@bastani/atomic 0.6.4-0 → 0.6.5-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/.agents/skills/create-spec/SKILL.md +6 -3
  2. package/.agents/skills/tdd/SKILL.md +107 -0
  3. package/.agents/skills/tdd/deep-modules.md +33 -0
  4. package/.agents/skills/tdd/interface-design.md +31 -0
  5. package/.agents/skills/tdd/mocking.md +59 -0
  6. package/.agents/skills/tdd/refactoring.md +10 -0
  7. package/.agents/skills/tdd/tests.md +61 -0
  8. package/.agents/skills/workflow-creator/SKILL.md +550 -0
  9. package/.agents/skills/workflow-creator/references/agent-sessions.md +891 -0
  10. package/.agents/skills/workflow-creator/references/agent-setup-recipe.md +266 -0
  11. package/.agents/skills/workflow-creator/references/computation-and-validation.md +201 -0
  12. package/.agents/skills/workflow-creator/references/control-flow.md +470 -0
  13. package/.agents/skills/workflow-creator/references/failure-modes.md +1014 -0
  14. package/.agents/skills/workflow-creator/references/getting-started.md +392 -0
  15. package/.agents/skills/workflow-creator/references/registry-and-validation.md +141 -0
  16. package/.agents/skills/workflow-creator/references/running-workflows.md +418 -0
  17. package/.agents/skills/workflow-creator/references/session-config.md +384 -0
  18. package/.agents/skills/workflow-creator/references/state-and-data-flow.md +356 -0
  19. package/.agents/skills/workflow-creator/references/user-input.md +234 -0
  20. package/.agents/skills/workflow-creator/references/workflow-inputs.md +392 -0
  21. package/.claude/agents/debugger.md +2 -2
  22. package/.claude/agents/reviewer.md +1 -1
  23. package/.claude/agents/worker.md +2 -2
  24. package/.github/agents/debugger.md +1 -1
  25. package/.github/agents/worker.md +1 -1
  26. package/.mcp.json +5 -1
  27. package/.opencode/agents/debugger.md +1 -1
  28. package/.opencode/agents/worker.md +1 -1
  29. package/README.md +236 -201
  30. package/dist/sdk/define-workflow.d.ts +11 -6
  31. package/dist/sdk/define-workflow.d.ts.map +1 -1
  32. package/dist/sdk/errors.d.ts +10 -0
  33. package/dist/sdk/errors.d.ts.map +1 -1
  34. package/dist/sdk/index.d.ts +21 -9
  35. package/dist/sdk/index.d.ts.map +1 -1
  36. package/dist/sdk/primitives/inputs.d.ts +36 -0
  37. package/dist/sdk/primitives/inputs.d.ts.map +1 -0
  38. package/dist/sdk/primitives/metadata.d.ts +40 -0
  39. package/dist/sdk/primitives/metadata.d.ts.map +1 -0
  40. package/dist/sdk/primitives/run.d.ts +57 -0
  41. package/dist/sdk/primitives/run.d.ts.map +1 -0
  42. package/dist/sdk/primitives/sessions.d.ts +128 -0
  43. package/dist/sdk/primitives/sessions.d.ts.map +1 -0
  44. package/dist/sdk/runtime/executor.d.ts +24 -56
  45. package/dist/sdk/runtime/executor.d.ts.map +1 -1
  46. package/dist/sdk/runtime/orchestrator-entry.d.ts +26 -0
  47. package/dist/sdk/runtime/orchestrator-entry.d.ts.map +1 -0
  48. package/dist/sdk/runtime/tmux.d.ts +20 -0
  49. package/dist/sdk/runtime/tmux.d.ts.map +1 -1
  50. package/dist/sdk/types.d.ts +26 -86
  51. package/dist/sdk/types.d.ts.map +1 -1
  52. package/dist/sdk/workflows/builtin/deep-research-codebase/claude/index.d.ts.map +1 -1
  53. package/dist/sdk/workflows/builtin/deep-research-codebase/copilot/index.d.ts.map +1 -1
  54. package/dist/sdk/workflows/builtin/deep-research-codebase/opencode/index.d.ts.map +1 -1
  55. package/dist/sdk/workflows/builtin/open-claude-design/claude/index.d.ts.map +1 -1
  56. package/dist/sdk/workflows/builtin/open-claude-design/copilot/index.d.ts.map +1 -1
  57. package/dist/sdk/workflows/builtin/open-claude-design/opencode/index.d.ts.map +1 -1
  58. package/dist/sdk/workflows/builtin/ralph/claude/index.d.ts.map +1 -1
  59. package/dist/sdk/workflows/builtin/ralph/copilot/index.d.ts.map +1 -1
  60. package/dist/sdk/workflows/builtin/ralph/opencode/index.d.ts.map +1 -1
  61. package/dist/sdk/workflows/index.d.ts +20 -12
  62. package/dist/sdk/workflows/index.d.ts.map +1 -1
  63. package/dist/services/config/additional-instructions.d.ts +1 -1
  64. package/dist/services/config/additional-instructions.d.ts.map +1 -1
  65. package/package.json +4 -4
  66. package/src/cli.ts +39 -56
  67. package/src/commands/builtin-registry.ts +37 -0
  68. package/src/commands/cli/chat/index.ts +1 -3
  69. package/src/{sdk → commands/cli}/management-commands.ts +15 -55
  70. package/src/commands/cli/session.ts +1 -1
  71. package/src/commands/cli/workflow-command.test.ts +250 -16
  72. package/src/commands/cli/workflow-inputs.test.ts +1 -0
  73. package/src/commands/cli/workflow-inputs.ts +13 -3
  74. package/src/commands/cli/workflow-list.test.ts +1 -0
  75. package/src/commands/cli/workflow-list.ts +0 -0
  76. package/src/commands/cli/workflow-status.ts +1 -1
  77. package/src/commands/cli/workflow.ts +191 -11
  78. package/src/sdk/define-workflow.test.ts +47 -16
  79. package/src/sdk/define-workflow.ts +24 -6
  80. package/src/sdk/errors.test.ts +11 -0
  81. package/src/sdk/errors.ts +13 -0
  82. package/src/sdk/index.test.ts +92 -0
  83. package/src/sdk/index.ts +71 -15
  84. package/src/sdk/primitives/inputs.ts +48 -0
  85. package/src/sdk/primitives/metadata.ts +63 -0
  86. package/src/sdk/primitives/run.ts +81 -0
  87. package/src/sdk/primitives/sessions.test.ts +594 -0
  88. package/src/sdk/primitives/sessions.ts +328 -0
  89. package/src/sdk/runtime/executor.ts +36 -115
  90. package/src/sdk/runtime/orchestrator-entry.ts +110 -0
  91. package/src/sdk/runtime/tmux.ts +33 -0
  92. package/src/sdk/types.ts +26 -91
  93. package/src/sdk/workflows/builtin/deep-research-codebase/claude/index.ts +1 -0
  94. package/src/sdk/workflows/builtin/deep-research-codebase/copilot/index.ts +1 -0
  95. package/src/sdk/workflows/builtin/deep-research-codebase/opencode/index.ts +1 -0
  96. package/src/sdk/workflows/builtin/open-claude-design/claude/index.ts +1 -0
  97. package/src/sdk/workflows/builtin/open-claude-design/copilot/index.ts +1 -0
  98. package/src/sdk/workflows/builtin/open-claude-design/opencode/index.ts +1 -0
  99. package/src/sdk/workflows/builtin/ralph/claude/index.ts +1 -0
  100. package/src/sdk/workflows/builtin/ralph/copilot/index.ts +1 -0
  101. package/src/sdk/workflows/builtin/ralph/opencode/index.ts +1 -0
  102. package/src/sdk/workflows/index.ts +68 -51
  103. package/src/services/config/additional-instructions.ts +1 -1
  104. package/.agents/skills/test-driven-development/SKILL.md +0 -371
  105. package/.agents/skills/test-driven-development/testing-anti-patterns.md +0 -299
  106. package/dist/commands/cli/session.d.ts +0 -67
  107. package/dist/commands/cli/session.d.ts.map +0 -1
  108. package/dist/commands/cli/workflow-status.d.ts +0 -63
  109. package/dist/commands/cli/workflow-status.d.ts.map +0 -1
  110. package/dist/sdk/commander.d.ts +0 -74
  111. package/dist/sdk/commander.d.ts.map +0 -1
  112. package/dist/sdk/management-commands.d.ts +0 -42
  113. package/dist/sdk/management-commands.d.ts.map +0 -1
  114. package/dist/sdk/workflow-cli.d.ts +0 -103
  115. package/dist/sdk/workflow-cli.d.ts.map +0 -1
  116. package/dist/sdk/workflows/builtin-registry.d.ts +0 -113
  117. package/dist/sdk/workflows/builtin-registry.d.ts.map +0 -1
  118. package/src/sdk/commander.ts +0 -161
  119. package/src/sdk/workflow-cli.ts +0 -409
  120. package/src/sdk/workflows/builtin-registry.ts +0 -23
@@ -1,67 +0,0 @@
1
- /**
2
- * Session CLI commands — shared between `atomic chat session` and
3
- * `atomic workflow session`, and the top-level `atomic session` picker.
4
- *
5
- * Wraps tmux -L atomic list-sessions / attach-session so users can
6
- * inspect and reconnect to running atomic sessions without touching
7
- * tmux directly.
8
- */
9
- import { select, confirm, isCancel } from "@clack/prompts";
10
- import type { TmuxSession } from "../../sdk/runtime/tmux.ts";
11
- import type { Subprocess } from "bun";
12
- /** Scope controls which session types a command shows. */
13
- export type SessionScope = "chat" | "workflow" | "all";
14
- /** Injectable tmux dependencies for command functions. */
15
- export interface SessionDeps {
16
- isTmuxInstalled: () => boolean;
17
- sessionExists: (name: string) => boolean;
18
- listSessions: () => TmuxSession[];
19
- isInsideAtomicSocket: () => boolean;
20
- isInsideTmux: () => boolean;
21
- switchClient: (name: string) => void;
22
- spawnMuxAttach: (name: string) => Subprocess;
23
- detachAndAttachAtomic: (name: string) => void;
24
- killSession: (name: string) => void;
25
- /** Prompt function for the session picker — defaults to @clack/prompts select. */
26
- select: typeof select;
27
- /** Prompt function for yes/no confirmations — defaults to @clack/prompts confirm. */
28
- confirm: typeof confirm;
29
- isCancel: typeof isCancel;
30
- }
31
- /**
32
- * Render the session list as a printable string.
33
- *
34
- * Layout mirrors the workflow list style — data-first count header,
35
- * session rows with metadata, dim footer hint.
36
- */
37
- export declare function renderSessionList(sessions: TmuxSession[]): string;
38
- /** Filter sessions by scope (chat-only, workflow-only, or all). */
39
- export declare function filterByScope(sessions: TmuxSession[], scope: SessionScope): TmuxSession[];
40
- /** Filter sessions to only those matching at least one of the given agents. */
41
- export declare function filterByAgent(sessions: TmuxSession[], agents: string[]): TmuxSession[];
42
- export declare function sessionListCommand(agents?: string[], scope?: SessionScope, deps?: SessionDeps): Promise<number>;
43
- /**
44
- * Connect to a named session. Handles the three tmux contexts:
45
- * already on atomic socket → switch-client, inside other tmux → detach+attach,
46
- * outside tmux → spawn attach.
47
- */
48
- export declare function sessionConnectCommand(sessionName: string, deps?: SessionDeps): Promise<number>;
49
- /**
50
- * Show an fzf-style interactive picker for all running atomic sessions.
51
- * Used by `atomic session connect` (no args).
52
- */
53
- export declare function sessionPickerCommand(agents?: string[], scope?: SessionScope, deps?: SessionDeps): Promise<number>;
54
- /**
55
- * Kill a named session or all sessions matching the given scope and agents.
56
- *
57
- * - If `sessionId` is provided: confirm and kill that one session.
58
- * - If `sessionId` is omitted: confirm and kill all sessions in scope.
59
- *
60
- * Pass `yes: true` (the `-y/--yes` flag on the CLI) to skip the
61
- * confirmation prompt — useful for orchestrating agents that need to
62
- * tear down a workflow session non-interactively.
63
- */
64
- export declare function sessionKillCommand(sessionId: string | undefined, agents?: string[], scope?: SessionScope, deps?: SessionDeps, options?: {
65
- yes?: boolean;
66
- }): Promise<number>;
67
- //# sourceMappingURL=session.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/commands/cli/session.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAU,MAAM,gBAAgB,CAAC;AAcnE,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,2BAA2B,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEtC,0DAA0D;AAC1D,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;AAEvD,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,eAAe,EAAE,MAAM,OAAO,CAAC;IAC/B,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,YAAY,EAAE,MAAM,WAAW,EAAE,CAAC;IAClC,oBAAoB,EAAE,MAAM,OAAO,CAAC;IACpC,YAAY,EAAE,MAAM,OAAO,CAAC;IAC5B,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,UAAU,CAAC;IAC7C,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,kFAAkF;IAClF,MAAM,EAAE,OAAO,MAAM,CAAC;IACtB,qFAAqF;IACrF,OAAO,EAAE,OAAO,OAAO,CAAC;IACxB,QAAQ,EAAE,OAAO,QAAQ,CAAC;CAC3B;AAoBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,CA6CjE;AA+BD,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,YAAY,GAAG,WAAW,EAAE,CAIzF;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAItF;AAID,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,MAAM,EAAO,EAAE,KAAK,GAAE,YAAoB,EAAE,IAAI,GAAE,WAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAa7I;AAID;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,GAAE,WAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyCjH;AAID;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,GAAE,MAAM,EAAO,EAAE,KAAK,GAAE,YAAoB,EAAE,IAAI,GAAE,WAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoC/I;AAID;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,GAAE,MAAM,EAAO,EACrB,KAAK,GAAE,YAAoB,EAC3B,IAAI,GAAE,WAAyB,EAC/B,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B,OAAO,CAAC,MAAM,CAAC,CAoGjB"}
@@ -1,63 +0,0 @@
1
- /**
2
- * `atomic workflow status [<id>]` — query the current state of one or
3
- * all running workflows so an orchestrating agent can decide whether
4
- * to keep waiting, surface a HIL prompt to the user, or move on.
5
- *
6
- * Status sources, in priority order:
7
- * 1. <sessionDir>/status.json — written by the orchestrator on every
8
- * panel-store mutation. Provides per-stage detail and the
9
- * derived overall state (in_progress | error | completed |
10
- * needs_review).
11
- * 2. tmux liveness fallback — when status.json is missing or stale
12
- * we still report whether the tmux session is alive so
13
- * script-driven workflows aren't blind during the brief window
14
- * before the orchestrator first writes its snapshot.
15
- */
16
- import { readSnapshot, type WorkflowOverallStatus, type WorkflowStatusSnapshot } from "../../sdk/runtime/status-writer.ts";
17
- import type { TmuxSession } from "../../sdk/runtime/tmux.ts";
18
- export type StatusFormat = "json" | "text";
19
- /** A single workflow's resolved status, as returned to the caller. */
20
- export interface WorkflowStatusReport {
21
- /** Tmux session name (e.g. `atomic-wf-claude-ralph-a1b2c3d4`). */
22
- id: string;
23
- /** Workflow run id (the trailing 8-hex segment of the tmux name). */
24
- workflowRunId: string;
25
- /** Workflow name pulled from the snapshot. Empty when no snapshot exists. */
26
- workflowName: string;
27
- /** Agent backend (claude / copilot / opencode). */
28
- agent: string;
29
- overall: WorkflowOverallStatus;
30
- /** True when the tmux session is currently alive on the atomic socket. */
31
- alive: boolean;
32
- /** ISO timestamp of the last snapshot, or null when none exists. */
33
- updatedAt: string | null;
34
- /** Sessions/stages, mirrored from the snapshot. Empty when no snapshot exists. */
35
- sessions: WorkflowStatusSnapshot["sessions"];
36
- /** Fatal-error message, if any. */
37
- fatalError: string | null;
38
- }
39
- export interface StatusDeps {
40
- isTmuxInstalled: () => boolean;
41
- sessionExists: (name: string) => boolean;
42
- listSessions: () => TmuxSession[];
43
- /**
44
- * Read a snapshot from disk. Defaults to the real reader; tests
45
- * inject a fake to control the snapshot data without touching the
46
- * filesystem.
47
- */
48
- readSnapshot: typeof readSnapshot;
49
- /** Base directory for session dirs. Defaults to `~/.atomic/sessions`. */
50
- sessionsBaseDir: string;
51
- }
52
- export interface WorkflowStatusOptions {
53
- /** Filter to a specific workflow by tmux session name. */
54
- id?: string;
55
- format?: StatusFormat;
56
- }
57
- /**
58
- * Top-level command. Prints either a single report (when `id` is
59
- * provided) or the list of all workflow sessions on the atomic
60
- * socket. Returns 1 when a requested id can't be found, 0 otherwise.
61
- */
62
- export declare function workflowStatusCommand(options: WorkflowStatusOptions, deps?: StatusDeps): Promise<number>;
63
- //# sourceMappingURL=workflow-status.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"workflow-status.d.ts","sourceRoot":"","sources":["../../../src/commands/cli/workflow-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAUH,OAAO,EACL,YAAY,EAEZ,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;AAE3C,sEAAsE;AACtE,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,qEAAqE;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,qBAAqB,CAAC;IAC/B,0EAA0E;IAC1E,KAAK,EAAE,OAAO,CAAC;IACf,oEAAoE;IACpE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kFAAkF;IAClF,QAAQ,EAAE,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAC7C,mCAAmC;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,OAAO,CAAC;IAC/B,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,YAAY,EAAE,MAAM,WAAW,EAAE,CAAC;IAClC;;;;OAIG;IACH,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,yEAAyE;IACzE,eAAe,EAAE,MAAM,CAAC;CACzB;AAiED,MAAM,WAAW,qBAAqB;IACpC,0DAA0D;IAC1D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,qBAAqB,EAC9B,IAAI,GAAE,UAAwB,GAC7B,OAAO,CAAC,MAAM,CAAC,CAiDjB"}
@@ -1,74 +0,0 @@
1
- /**
2
- * Commander adapter for embedding a WorkflowCli under a parent Commander CLI.
3
- *
4
- * ```ts
5
- * import { createWorkflowCli } from "@bastani/atomic/workflows";
6
- * import { toCommand, runCli } from "@bastani/atomic/workflows/commander";
7
- *
8
- * const cli = createWorkflowCli(workflow);
9
- * const program = new Command("my-app");
10
- * program.addCommand(toCommand(cli, "workflow"));
11
- *
12
- * await runCli(cli, () => program.parseAsync());
13
- * ```
14
- *
15
- * `WorkflowCli` itself is framework-agnostic — this module is the only place
16
- * that imports Commander on the adapter side of the API. A future
17
- * yargs/citty adapter would be a sibling module with the same shape.
18
- *
19
- * `runCli` handles orchestrator re-entry transparently — parent CLIs never
20
- * see env vars or guards. PyTorch-distributed style: the framework owns
21
- * rank-zero dispatch; the developer writes one line.
22
- */
23
- import type { Command } from "@commander-js/extra-typings";
24
- import type { WorkflowCli, WorkflowDefinition } from "./types.ts";
25
- /**
26
- * Build a Commander `Command` bound to a WorkflowCli for embedding under
27
- * a parent CLI. The returned Command declares `-n/--name`, `-a/--agent`,
28
- * `-d/--detach`, plus the per-input union across the registry. Picker
29
- * behaviour (agent without name in a TTY) is preserved.
30
- *
31
- * @param cli - WorkflowCli returned by `createWorkflowCli()`.
32
- * @param name - Mount name (default: `"workflow"`).
33
- */
34
- export declare function toCommand<T extends Record<string, WorkflowDefinition>>(cli: WorkflowCli<T>, name?: string): Command;
35
- /**
36
- * Bootstrap an embedded Commander CLI. Use this in place of
37
- * `program.parseAsync()` when you've mounted an atomic WorkflowCli under
38
- * a parent program.
39
- *
40
- * Inspired by PyTorch's `init_process_group()`: the framework handles
41
- * rank-zero dispatch (here: orchestrator vs CLI) transparently, so the
42
- * developer writes the same code whether this process is a fresh CLI
43
- * invocation or a tmux-spawned orchestrator re-exec.
44
- *
45
- * - On a fresh invocation, invokes `cliFn()` (your `program.parseAsync()`
46
- * call, plus any bootstrap you want before it).
47
- * - When the process is a detached orchestrator re-exec
48
- * (`ATOMIC_ORCHESTRATOR_MODE=1` is set by the runtime), resolves the
49
- * workflow identified by `ATOMIC_WF_KEY` against the supplied CLI
50
- * (or the first match across CLIs) and drives it via
51
- * `runOrchestrator`. `cliFn` is not called.
52
- *
53
- * Accepts a single WorkflowCli or an array — use an array when your
54
- * parent CLI embeds multiple atomic WorkflowClis (rare, but supported).
55
- *
56
- * @example
57
- * ```ts
58
- * const program = new Command("my-app");
59
- * program.addCommand(toCommand(cli));
60
- *
61
- * await runCli(cli, () => program.parseAsync());
62
- * ```
63
- *
64
- * @example With pre-parse bootstrap:
65
- * ```ts
66
- * await runCli(builtinCli, async () => {
67
- * await ensureGlobalAtomicSettings();
68
- * await autoSyncIfStale();
69
- * await program.parseAsync();
70
- * });
71
- * ```
72
- */
73
- export declare function runCli(target: WorkflowCli | ReadonlyArray<WorkflowCli>, cliFn: () => void | Promise<void>): Promise<void>;
74
- //# sourceMappingURL=commander.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"commander.d.ts","sourceRoot":"","sources":["../../src/sdk/commander.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,KAAK,EAEV,WAAW,EACX,kBAAkB,EACnB,MAAM,YAAY,CAAC;AASpB;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACpE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,EACnB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAyCT;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,MAAM,CAC1B,MAAM,EAAE,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC,EAChD,KAAK,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CAyBf"}
@@ -1,42 +0,0 @@
1
- /**
2
- * Session + status management subcommands for workflow CLIs.
3
- *
4
- * Shared by the atomic CLI root (`atomic session *`, `atomic workflow status`)
5
- * and by SDK-built CLIs (`createWorkflowCli(...)`). Factoring this out means a
6
- * user running `bun run src/claude-worker.ts session list` gets the identical
7
- * command surface as `atomic session list`, without the SDK embedding its own
8
- * diverging implementation. All queries go through the shared atomic tmux
9
- * socket, so sessions spawned by SDK-built CLIs and by `atomic workflow -n …`
10
- * show up interchangeably.
11
- *
12
- * Commander options are declared with the same names, descriptions, and
13
- * behaviour as the atomic root CLI — keep them in sync when the root CLI
14
- * grows a new option.
15
- */
16
- import type { Command } from "@commander-js/extra-typings";
17
- import type { SessionScope } from "../commands/cli/session.ts";
18
- /**
19
- * Attach the `session` subcommand group (`list` / `connect` / `kill`) to a
20
- * parent Commander command. Returns the created `session` group so callers
21
- * can attach additional children if they need to.
22
- *
23
- * @param parent The Commander command to mount `session` under.
24
- * @param scope Which session set the list/kill commands operate on. SDK CLIs
25
- * typically pass `"workflow"` to scope the picker to
26
- * `atomic-wf-*` sessions only; the atomic root uses `"all"`.
27
- */
28
- export declare function addSessionSubcommand(parent: Command, scope?: SessionScope): Command;
29
- /**
30
- * Attach a top-level `status` subcommand for querying workflow status.
31
- * Mirrors `atomic workflow status` — same overall-state contract
32
- * (`in_progress` / `error` / `completed` / `needs_review`) and same JSON
33
- * shape. Omit the id to list every running workflow on the socket.
34
- */
35
- export declare function addStatusSubcommand(parent: Command): void;
36
- /**
37
- * Convenience: attach both `session` and `status` subcommands in the order
38
- * the SDK defaults use. Called by `createWorkflowCli` when
39
- * `includeManagementCommands` is `true` (the default).
40
- */
41
- export declare function addManagementCommands(parent: Command, scope?: SessionScope): void;
42
- //# sourceMappingURL=management-commands.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"management-commands.d.ts","sourceRoot":"","sources":["../../src/sdk/management-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAO/D;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,EACf,KAAK,GAAE,YAAoB,GAC1B,OAAO,CA0ET;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAkBzD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,EACf,KAAK,GAAE,YAAyB,GAC/B,IAAI,CAGN"}
@@ -1,103 +0,0 @@
1
- /**
2
- * WorkflowCli — the single entry-point factory for workflow CLIs.
3
- *
4
- * Parses `-n/--name` + `-a/--agent` from argv, exposes a union of flags
5
- * across every workflow in the registry, opens an interactive picker when
6
- * agent is given without a name in a TTY, and handles orchestrator
7
- * re-entry from detached runs.
8
- *
9
- * Framework-agnostic: the returned `WorkflowCli` type has no direct
10
- * Commander dependency. To embed under a parent Commander CLI, use
11
- * `toCommand(cli)` from `@bastani/atomic/workflows/commander`.
12
- *
13
- * Used by the internal `atomic workflow` command. Per-workflow CLI
14
- * files call `createWorkflowCli(workflow)` — the same factory supports
15
- * a lone workflow, an array, or a full `Registry`.
16
- */
17
- import { Command } from "@commander-js/extra-typings";
18
- import type { AgentType, Registry, RegistrableWorkflow, WorkflowCli, WorkflowDefinition, WorkflowInput, CreateWorkflowCliOptions } from "./types.ts";
19
- /**
20
- * Resolve the workflow definition, merge inputs (with precedence), validate,
21
- * and hand off to the executor.
22
- *
23
- * Input precedence (highest → lowest):
24
- * cliInputs > runInputs > dispatcherInputs > defineWorkflow defaults
25
- *
26
- * Exported for `./commander.ts` — not part of the public API.
27
- */
28
- export declare function resolveAndStart(registry: Registry, name: string, agent: AgentType, opts: {
29
- cliInputs?: Record<string, string>;
30
- runInputs?: Record<string, string>;
31
- dispatcherInputs?: Record<string, string>;
32
- detach?: boolean;
33
- entry: string;
34
- }): Promise<void>;
35
- /**
36
- * Build the Commander Command that drives the workflow CLI. Used by both
37
- * the standalone `run()` path and the `toCommand` adapter.
38
- *
39
- * Exported for `./commander.ts` — not part of the public API.
40
- */
41
- export declare function buildCliCommand(registry: Registry, unionInputs: Map<string, WorkflowInput>, onAction: (params: {
42
- name: string | undefined;
43
- agent: AgentType | undefined;
44
- cliInputs: Record<string, string>;
45
- detach: boolean;
46
- }) => Promise<void>, mountName?: string): Command;
47
- /**
48
- * Interactive-picker path used by both `run()` and the Commander adapter.
49
- * Depends on `process.stdout.isTTY`; returns without side effects when
50
- * the user cancels or no terminal is attached.
51
- *
52
- * Exported for `./commander.ts` — not part of the public API.
53
- */
54
- export declare function runPicker(registry: Registry, agent: AgentType, detach: boolean, entry: string, dispatcherInputs: Record<string, string> | undefined): Promise<void>;
55
- /**
56
- * Create a workflow CLI that resolves `--name` + `--agent` from argv and
57
- * runs the matching workflow from the registry.
58
- *
59
- * Accepts three input shapes — pick whichever is cleanest:
60
- *
61
- * - **A single workflow.** `createWorkflowCli(workflow).run()`.
62
- * - **An array of workflows.** `createWorkflowCli([claude, copilot]).run()`.
63
- * - **A `Registry`.** For programmatic/dynamic composition, or sharing a
64
- * registry across multiple CLIs. Build with `createRegistry().register(...)`.
65
- *
66
- * @example
67
- * ```ts
68
- * // Single workflow — ~70% of use cases
69
- * const cli = createWorkflowCli(workflow);
70
- * await cli.run();
71
- *
72
- * // Multi-workflow, multi-agent — by far the most common multi-case
73
- * await createWorkflowCli([claude, copilot, opencode]).run();
74
- *
75
- * // Dynamic composition
76
- * const registry = workflowFiles.reduce(
77
- * (r, wf) => r.register(wf),
78
- * createRegistry(),
79
- * );
80
- * await createWorkflowCli(registry).run();
81
- * ```
82
- *
83
- * To embed under a parent Commander CLI:
84
- *
85
- * ```ts
86
- * import { toCommand, runCli } from "@bastani/atomic/workflows/commander";
87
- * parent.addCommand(toCommand(cli));
88
- * await runCli(cli, () => parent.parseAsync());
89
- * ```
90
- *
91
- * The single/array overloads use generic constraints (`W extends
92
- * RegistrableWorkflow`) rather than a plain parameter type. This matters
93
- * under `--strictFunctionTypes`: a `WorkflowDefinition<"claude", ...>`
94
- * will not assign to a property-typed parameter because its narrow
95
- * `run(ctx: WorkflowContext<"claude">)` is contravariant against the
96
- * broader target. Routing through a generic `W` lets TS check bivariantly
97
- * via `extends`, which matches how `Registry.register` already accepts
98
- * the same inputs.
99
- */
100
- export declare function createWorkflowCli<W extends RegistrableWorkflow>(target: W, options?: CreateWorkflowCliOptions): WorkflowCli;
101
- export declare function createWorkflowCli<W extends RegistrableWorkflow>(target: readonly W[], options?: CreateWorkflowCliOptions): WorkflowCli;
102
- export declare function createWorkflowCli<T extends Record<string, WorkflowDefinition>>(target: Registry<T>, options?: CreateWorkflowCliOptions): WorkflowCli<T>;
103
- //# sourceMappingURL=workflow-cli.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"workflow-cli.d.ts","sourceRoot":"","sources":["../../src/sdk/workflow-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,KAAK,EACV,SAAS,EACT,QAAQ,EACR,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAsDpB;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE;IACJ,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf,GACA,OAAO,CAAC,IAAI,CAAC,CAmCf;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EACvC,QAAQ,EAAE,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,MAAM,EAAE,OAAO,CAAC;CACjB,KAAK,OAAO,CAAC,IAAI,CAAC,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAwET;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,MAAM,EACb,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GACnD,OAAO,CAAC,IAAI,CAAC,CAef;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,mBAAmB,EAC7D,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,wBAAwB,GACjC,WAAW,CAAC;AACf,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,mBAAmB,EAC7D,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,OAAO,CAAC,EAAE,wBAAwB,GACjC,WAAW,CAAC;AACf,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAC5E,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EACnB,OAAO,CAAC,EAAE,wBAAwB,GACjC,WAAW,CAAC,CAAC,CAAC,CAAC"}
@@ -1,113 +0,0 @@
1
- export declare function createBuiltinRegistry(): import(".").Registry<Record<string, never> & Record<`claude/${string}`, import(".").WorkflowDefinition<"claude", readonly [{
2
- readonly name: "prompt";
3
- readonly type: "text";
4
- readonly required: true;
5
- readonly description: "task prompt";
6
- }, {
7
- readonly name: "max_loops";
8
- readonly type: "integer";
9
- readonly description: "maximum number of plan/orchestrate/review iterations";
10
- readonly default: 10;
11
- }]>> & Record<`copilot/${string}`, import(".").WorkflowDefinition<"copilot", readonly [{
12
- readonly name: "prompt";
13
- readonly type: "text";
14
- readonly required: true;
15
- readonly description: "task prompt";
16
- }, {
17
- readonly name: "max_loops";
18
- readonly type: "integer";
19
- readonly description: "maximum number of plan/orchestrate/review iterations";
20
- readonly default: 10;
21
- }]>> & Record<`opencode/${string}`, import(".").WorkflowDefinition<"opencode", readonly [{
22
- readonly name: "prompt";
23
- readonly type: "text";
24
- readonly required: true;
25
- readonly description: "task prompt";
26
- }, {
27
- readonly name: "max_loops";
28
- readonly type: "integer";
29
- readonly description: "maximum number of plan/orchestrate/review iterations";
30
- readonly default: 10;
31
- }]>> & Record<`claude/${string}`, import(".").WorkflowDefinition<"claude", readonly [{
32
- readonly name: "prompt";
33
- readonly type: "text";
34
- readonly required: true;
35
- readonly description: "research question";
36
- }]>> & Record<`copilot/${string}`, import(".").WorkflowDefinition<"copilot", readonly [{
37
- readonly name: "prompt";
38
- readonly type: "text";
39
- readonly required: true;
40
- readonly description: "research question";
41
- }]>> & Record<`opencode/${string}`, import(".").WorkflowDefinition<"opencode", readonly [{
42
- readonly name: "prompt";
43
- readonly type: "text";
44
- readonly required: true;
45
- readonly description: "research question";
46
- }]>> & Record<`claude/${string}`, import(".").WorkflowDefinition<"claude", readonly [{
47
- readonly name: "prompt";
48
- readonly type: "text";
49
- readonly required: true;
50
- readonly description: "What to design (e.g., 'a dashboard for monitoring API latency')";
51
- }, {
52
- readonly name: "reference";
53
- readonly type: "text";
54
- readonly required: false;
55
- readonly description: "URL, file path, or codebase path to import as design reference";
56
- }, {
57
- readonly name: "output-type";
58
- readonly type: "enum";
59
- readonly required: false;
60
- readonly values: readonly ["prototype", "wireframe", "page", "component"];
61
- readonly default: "prototype";
62
- readonly description: "Type of design output to generate";
63
- }, {
64
- readonly name: "design-system";
65
- readonly type: "text";
66
- readonly required: false;
67
- readonly description: "Path to existing Design.md (skips onboarding if provided)";
68
- }]>> & Record<`copilot/${string}`, import(".").WorkflowDefinition<"copilot", readonly [{
69
- readonly name: "prompt";
70
- readonly type: "text";
71
- readonly required: true;
72
- readonly description: "What to design (e.g., 'a dashboard for monitoring API latency')";
73
- }, {
74
- readonly name: "reference";
75
- readonly type: "text";
76
- readonly required: false;
77
- readonly description: "URL, file path, or codebase path to import as design reference";
78
- }, {
79
- readonly name: "output-type";
80
- readonly type: "enum";
81
- readonly required: false;
82
- readonly values: readonly ["prototype", "wireframe", "page", "component"];
83
- readonly default: "prototype";
84
- readonly description: "Type of design output to generate";
85
- }, {
86
- readonly name: "design-system";
87
- readonly type: "text";
88
- readonly required: false;
89
- readonly description: "Path to existing Design.md (skips onboarding if provided)";
90
- }]>> & Record<`opencode/${string}`, import(".").WorkflowDefinition<"opencode", readonly [{
91
- readonly name: "prompt";
92
- readonly type: "text";
93
- readonly required: true;
94
- readonly description: "What to design (e.g., 'a dashboard for monitoring API latency')";
95
- }, {
96
- readonly name: "reference";
97
- readonly type: "text";
98
- readonly required: false;
99
- readonly description: "URL, file path, or codebase path to import as design reference";
100
- }, {
101
- readonly name: "output-type";
102
- readonly type: "enum";
103
- readonly required: false;
104
- readonly values: readonly ["prototype", "wireframe", "page", "component"];
105
- readonly default: "prototype";
106
- readonly description: "Type of design output to generate";
107
- }, {
108
- readonly name: "design-system";
109
- readonly type: "text";
110
- readonly required: false;
111
- readonly description: "Path to existing Design.md (skips onboarding if provided)";
112
- }]>>>;
113
- //# sourceMappingURL=builtin-registry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"builtin-registry.d.ts","sourceRoot":"","sources":["../../../src/sdk/workflows/builtin-registry.ts"],"names":[],"mappings":"AAiBA,wBAAgB,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAKpC"}
@@ -1,161 +0,0 @@
1
- /**
2
- * Commander adapter for embedding a WorkflowCli under a parent Commander CLI.
3
- *
4
- * ```ts
5
- * import { createWorkflowCli } from "@bastani/atomic/workflows";
6
- * import { toCommand, runCli } from "@bastani/atomic/workflows/commander";
7
- *
8
- * const cli = createWorkflowCli(workflow);
9
- * const program = new Command("my-app");
10
- * program.addCommand(toCommand(cli, "workflow"));
11
- *
12
- * await runCli(cli, () => program.parseAsync());
13
- * ```
14
- *
15
- * `WorkflowCli` itself is framework-agnostic — this module is the only place
16
- * that imports Commander on the adapter side of the API. A future
17
- * yargs/citty adapter would be a sibling module with the same shape.
18
- *
19
- * `runCli` handles orchestrator re-entry transparently — parent CLIs never
20
- * see env vars or guards. PyTorch-distributed style: the framework owns
21
- * rank-zero dispatch; the developer writes one line.
22
- */
23
-
24
- import type { Command } from "@commander-js/extra-typings";
25
- import type {
26
- AgentType,
27
- WorkflowCli,
28
- WorkflowDefinition,
29
- } from "./types.ts";
30
- import {
31
- buildCliCommand,
32
- resolveAndStart,
33
- runPicker,
34
- } from "./workflow-cli.ts";
35
- import { buildInputUnion } from "./worker-shared.ts";
36
- import { runOrchestrator } from "./runtime/executor.ts";
37
-
38
- /**
39
- * Build a Commander `Command` bound to a WorkflowCli for embedding under
40
- * a parent CLI. The returned Command declares `-n/--name`, `-a/--agent`,
41
- * `-d/--detach`, plus the per-input union across the registry. Picker
42
- * behaviour (agent without name in a TTY) is preserved.
43
- *
44
- * @param cli - WorkflowCli returned by `createWorkflowCli()`.
45
- * @param name - Mount name (default: `"workflow"`).
46
- */
47
- export function toCommand<T extends Record<string, WorkflowDefinition>>(
48
- cli: WorkflowCli<T>,
49
- name?: string,
50
- ): Command {
51
- const registry = cli.registry;
52
- const entry = cli.entry;
53
- const defaultInputs = cli.defaults;
54
-
55
- const unionInputs = buildInputUnion(registry.list());
56
-
57
- let cmd!: Command;
58
- cmd = buildCliCommand(
59
- registry,
60
- unionInputs,
61
- async (params) => {
62
- const { name: parsedName, agent: parsedAgent, cliInputs, detach } = params;
63
-
64
- // Interactive picker: agent given, name omitted, running in a TTY.
65
- if (!parsedName && parsedAgent && process.stdout.isTTY) {
66
- await runPicker(registry, parsedAgent, detach, entry, defaultInputs);
67
- return;
68
- }
69
-
70
- if (!parsedName || !parsedAgent) {
71
- // Commander's `help()` calls `process.exit()` and is typed `never`.
72
- cmd.help();
73
- }
74
-
75
- await resolveAndStart(
76
- registry,
77
- parsedName,
78
- parsedAgent as AgentType,
79
- {
80
- cliInputs,
81
- dispatcherInputs: defaultInputs,
82
- detach,
83
- entry,
84
- },
85
- );
86
- },
87
- name ?? "workflow",
88
- );
89
-
90
- return cmd;
91
- }
92
-
93
- // ─── runCli — embed bootstrap ──────────────────────────────────────────────
94
-
95
- /**
96
- * Bootstrap an embedded Commander CLI. Use this in place of
97
- * `program.parseAsync()` when you've mounted an atomic WorkflowCli under
98
- * a parent program.
99
- *
100
- * Inspired by PyTorch's `init_process_group()`: the framework handles
101
- * rank-zero dispatch (here: orchestrator vs CLI) transparently, so the
102
- * developer writes the same code whether this process is a fresh CLI
103
- * invocation or a tmux-spawned orchestrator re-exec.
104
- *
105
- * - On a fresh invocation, invokes `cliFn()` (your `program.parseAsync()`
106
- * call, plus any bootstrap you want before it).
107
- * - When the process is a detached orchestrator re-exec
108
- * (`ATOMIC_ORCHESTRATOR_MODE=1` is set by the runtime), resolves the
109
- * workflow identified by `ATOMIC_WF_KEY` against the supplied CLI
110
- * (or the first match across CLIs) and drives it via
111
- * `runOrchestrator`. `cliFn` is not called.
112
- *
113
- * Accepts a single WorkflowCli or an array — use an array when your
114
- * parent CLI embeds multiple atomic WorkflowClis (rare, but supported).
115
- *
116
- * @example
117
- * ```ts
118
- * const program = new Command("my-app");
119
- * program.addCommand(toCommand(cli));
120
- *
121
- * await runCli(cli, () => program.parseAsync());
122
- * ```
123
- *
124
- * @example With pre-parse bootstrap:
125
- * ```ts
126
- * await runCli(builtinCli, async () => {
127
- * await ensureGlobalAtomicSettings();
128
- * await autoSyncIfStale();
129
- * await program.parseAsync();
130
- * });
131
- * ```
132
- */
133
- export async function runCli(
134
- target: WorkflowCli | ReadonlyArray<WorkflowCli>,
135
- cliFn: () => void | Promise<void>,
136
- ): Promise<void> {
137
- if (process.env.ATOMIC_ORCHESTRATOR_MODE === "1") {
138
- const key = process.env.ATOMIC_WF_KEY ?? "";
139
- const slashIdx = key.indexOf("/");
140
- if (slashIdx < 0) {
141
- throw new Error(
142
- `ATOMIC_ORCHESTRATOR_MODE=1 but ATOMIC_WF_KEY "${key}" is malformed — expected "<agent>/<name>"`,
143
- );
144
- }
145
- const agent = key.slice(0, slashIdx) as AgentType;
146
- const name = key.slice(slashIdx + 1);
147
-
148
- const clis = Array.isArray(target) ? target : [target];
149
- for (const cli of clis) {
150
- const def = cli.registry.resolve(name, agent);
151
- if (def) {
152
- await runOrchestrator(def);
153
- return;
154
- }
155
- }
156
-
157
- throw new Error(`ATOMIC_WF_KEY "${key}" not found in any provided WorkflowCli`);
158
- }
159
-
160
- await cliFn();
161
- }