Summary
A Toolcraft command tree exported from a published package loses usable SDK member/result types in a strict TypeScript consumer.
With toolcraft@0.0.93, the runtime SDK works, but a clean consumer compiling with strict, module: NodeNext, and moduleResolution: NodeNext sees generated SDK members as unknown. In less strict declaration probes, command results can instead collapse to HumanInLoopPending even though no human-in-loop mode is configured.
Reproduction
Package code:
import { defineCommand, defineGroup, S } from "toolcraft";
const lint = defineCommand({
name: "lint",
params: S.Object({ root: S.Optional(S.String()) }),
handler: async () => ({ files: 1 }),
});
export const root = defineGroup({
name: "example",
scope: ["cli", "mcp", "sdk"],
children: [lint] as const,
});
Build declarations, pack and install that package into a clean consumer, then compile:
import { createSDK } from "toolcraft/sdk";
import { root } from "example-package";
const sdk = createSDK(root);
const result = await sdk.lint({ root: "." });
const files: number = result.files;
tsc --noEmit --strict --target ES2022 --module NodeNext --moduleResolution NodeNext consumer.ts
Observed error:
TS18046: 'sdk.lint' is of type 'unknown'.
A declaration-emission probe without strict checking can expose lint, but its return type becomes Promise<HumanInLoopPending> rather than the handler result.
Expected behavior
A command tree imported from a published package should preserve the same generated SDK parameter and result types as an in-repository tree:
sdk.lint({ root: 42 }); // type error
const result = await sdk.lint({ root: "." });
result.files; // number
A command with no human-in-loop configuration should resolve to its handler result, not HumanInLoopPending.
Acceptance criteria
- A packed two-package fixture compiles under strict NodeNext settings.
- Generated command members remain callable and preserve parameter types.
- Generated command results preserve the handler/result-schema type.
- Commands without human-in-loop configuration do not infer
HumanInLoopPending.
- Toolcraft has a regression test that builds declarations, installs the tarball into a clean consumer, and runs
tsc there.
Summary
A Toolcraft command tree exported from a published package loses usable SDK member/result types in a strict TypeScript consumer.
With
toolcraft@0.0.93, the runtime SDK works, but a clean consumer compiling withstrict,module: NodeNext, andmoduleResolution: NodeNextsees generated SDK members asunknown. In less strict declaration probes, command results can instead collapse toHumanInLoopPendingeven though no human-in-loop mode is configured.Reproduction
Package code:
Build declarations, pack and install that package into a clean consumer, then compile:
Observed error:
A declaration-emission probe without strict checking can expose
lint, but its return type becomesPromise<HumanInLoopPending>rather than the handler result.Expected behavior
A command tree imported from a published package should preserve the same generated SDK parameter and result types as an in-repository tree:
A command with no human-in-loop configuration should resolve to its handler result, not
HumanInLoopPending.Acceptance criteria
HumanInLoopPending.tscthere.