ai-whisper 0.1.1 → 0.1.2

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.
package/README.md CHANGED
@@ -21,7 +21,7 @@ Run spec-driven-development using docs/spec.md
21
21
 
22
22
  From there ai-whisper runs the workflow autonomously:
23
23
 
24
- - **Implementer / reviewer assignment** — one agent is the implementer, the other the reviewer (for `spec-driven-development` the default is implementer = Claude, reviewer = Codex). The baton passes between them; only one owns the turn at a time.
24
+ - **Implementer / reviewer assignment** — the agent you trigger the workflow from becomes the implementer and the other agent becomes the reviewer; pass `--implementer` / `--reviewer` to choose explicitly. (Started outside a mounted session with no flags, it falls back to a default pairing and warns.) The baton passes between them; only one owns the turn at a time.
25
25
  - **Autonomous execution** — the implementer does each step in its real session and hands the result back. An LLM evaluator judges whether the deliverable meets the request.
26
26
  - **Review loops** — when work isn't good enough yet, the reviewer's findings are composed into a follow-up handoff and the implementer iterates. The loop repeats until the work is approved or the round budget is exhausted.
27
27
  - **Resumability** — workflow and chain state is durable. If the broker restarts or you stop for the day, you recover and reconnect rather than starting over.
@@ -100,6 +100,7 @@ For the full mental model, read [Concepts](docs/concepts.md).
100
100
 
101
101
  ## Learn more
102
102
 
103
+ - [Workflows](docs/workflows.md) — how to use the workflows well: choosing between `spec-driven-development` and `ralph-loop`, and authoring the spec or goal that drives the run.
103
104
  - [Concepts](docs/concepts.md) — the mental model: baton handoff, real mounted sessions, supervised autonomy, workflow-first execution.
104
105
  - [Relay & handoff flows](docs/relay-handoff-flows.md) — the complete handoff state machine, capture-status table, hotkey reference, per-step verdicts, and troubleshooting.
105
106
  - [Evaluator configuration](docs/evaluator-configuration.md) — required credentials and options for the LLM evaluator that gates workflows.
@@ -5866,12 +5866,16 @@ function createNodePty(input) {
5866
5866
  ensureNodePtySpawnHelperExecutable({
5867
5867
  unixTerminalPath: nodePtyUnixTerminalPath
5868
5868
  });
5869
- return spawn2(input.config.executable, input.config.execArgs, {
5870
- name: "xterm-256color",
5871
- cols: input.cols,
5872
- rows: input.rows,
5873
- cwd: input.cwd
5874
- });
5869
+ return spawn2(input.config.executable, input.config.execArgs, buildClaudePtySpawnOptions({ cols: input.cols, rows: input.rows, cwd: input.cwd }));
5870
+ }
5871
+ function buildClaudePtySpawnOptions(input) {
5872
+ const env = {};
5873
+ for (const [key, value] of Object.entries(input.baseEnv ?? process.env)) {
5874
+ if (typeof value === "string")
5875
+ env[key] = value;
5876
+ }
5877
+ env.AI_WHISPER_AGENT = "claude";
5878
+ return { name: "xterm-256color", cols: input.cols, rows: input.rows, cwd: input.cwd, env };
5875
5879
  }
5876
5880
  function createClaudeLiveSession(input) {
5877
5881
  let pty = null;
@@ -6169,12 +6173,16 @@ function createNodePty2(input) {
6169
6173
  ensureNodePtySpawnHelperExecutable({
6170
6174
  unixTerminalPath: nodePtyUnixTerminalPath2
6171
6175
  });
6172
- return spawn4(input.config.executable, input.config.execArgs, {
6173
- name: "xterm-256color",
6174
- cols: input.cols,
6175
- rows: input.rows,
6176
- cwd: input.cwd
6177
- });
6176
+ return spawn4(input.config.executable, input.config.execArgs, buildCodexPtySpawnOptions({ cols: input.cols, rows: input.rows, cwd: input.cwd }));
6177
+ }
6178
+ function buildCodexPtySpawnOptions(input) {
6179
+ const env = {};
6180
+ for (const [key, value] of Object.entries(input.baseEnv ?? process.env)) {
6181
+ if (typeof value === "string")
6182
+ env[key] = value;
6183
+ }
6184
+ env.AI_WHISPER_AGENT = "codex";
6185
+ return { name: "xterm-256color", cols: input.cols, rows: input.rows, cwd: input.cwd, env };
6178
6186
  }
6179
6187
  function createCodexLiveSession(input) {
6180
6188
  let pty = null;
@@ -6168,12 +6168,16 @@ function createNodePty(input) {
6168
6168
  ensureNodePtySpawnHelperExecutable({
6169
6169
  unixTerminalPath: nodePtyUnixTerminalPath
6170
6170
  });
6171
- return spawn3(input.config.executable, input.config.execArgs, {
6172
- name: "xterm-256color",
6173
- cols: input.cols,
6174
- rows: input.rows,
6175
- cwd: input.cwd
6176
- });
6171
+ return spawn3(input.config.executable, input.config.execArgs, buildClaudePtySpawnOptions({ cols: input.cols, rows: input.rows, cwd: input.cwd }));
6172
+ }
6173
+ function buildClaudePtySpawnOptions(input) {
6174
+ const env = {};
6175
+ for (const [key, value] of Object.entries(input.baseEnv ?? process.env)) {
6176
+ if (typeof value === "string")
6177
+ env[key] = value;
6178
+ }
6179
+ env.AI_WHISPER_AGENT = "claude";
6180
+ return { name: "xterm-256color", cols: input.cols, rows: input.rows, cwd: input.cwd, env };
6177
6181
  }
6178
6182
  function createClaudeLiveSession(input) {
6179
6183
  let pty = null;
@@ -6471,12 +6475,16 @@ function createNodePty2(input) {
6471
6475
  ensureNodePtySpawnHelperExecutable({
6472
6476
  unixTerminalPath: nodePtyUnixTerminalPath2
6473
6477
  });
6474
- return spawn5(input.config.executable, input.config.execArgs, {
6475
- name: "xterm-256color",
6476
- cols: input.cols,
6477
- rows: input.rows,
6478
- cwd: input.cwd
6479
- });
6478
+ return spawn5(input.config.executable, input.config.execArgs, buildCodexPtySpawnOptions({ cols: input.cols, rows: input.rows, cwd: input.cwd }));
6479
+ }
6480
+ function buildCodexPtySpawnOptions(input) {
6481
+ const env = {};
6482
+ for (const [key, value] of Object.entries(input.baseEnv ?? process.env)) {
6483
+ if (typeof value === "string")
6484
+ env[key] = value;
6485
+ }
6486
+ env.AI_WHISPER_AGENT = "codex";
6487
+ return { name: "xterm-256color", cols: input.cols, rows: input.rows, cwd: input.cwd, env };
6480
6488
  }
6481
6489
  function createCodexLiveSession(input) {
6482
6490
  let pty = null;
@@ -10802,21 +10810,62 @@ async function runWorkflowStart(deps) {
10802
10810
  }
10803
10811
  }
10804
10812
  const def = getWorkflowDefinition(deps.workflowType);
10805
- const implementer = deps.implementer ?? def?.defaultImplementer;
10806
- const reviewer = deps.reviewer ?? def?.defaultReviewer;
10807
- if (!implementer || !reviewer) {
10808
- throw new Error(
10809
- `Workflow type "${deps.workflowType}" has no default role bindings. Pass --implementer and --reviewer explicitly.`
10810
- );
10813
+ let resolved;
10814
+ try {
10815
+ resolved = resolveRoleBindings({
10816
+ explicitImplementer: deps.implementer,
10817
+ explicitReviewer: deps.reviewer,
10818
+ callerAgent: deps.callerAgent ?? null,
10819
+ def
10820
+ });
10821
+ } catch (e) {
10822
+ if (e instanceof Error && /no default role bindings/.test(e.message)) {
10823
+ throw new Error(
10824
+ `Workflow type "${deps.workflowType}" has no default role bindings. Pass --implementer and --reviewer explicitly.`
10825
+ );
10826
+ }
10827
+ throw e;
10811
10828
  }
10812
- return deps.broker.control.createWorkflow({
10829
+ const { workflowId } = deps.broker.control.createWorkflow({
10813
10830
  collabId: deps.collabId,
10814
10831
  workflowType: deps.workflowType,
10815
10832
  specPath: deps.specPath,
10816
- roleBindings: { implementer, reviewer },
10833
+ roleBindings: { implementer: resolved.implementer, reviewer: resolved.reviewer },
10817
10834
  ...deps.name ? { name: deps.name } : {},
10818
10835
  now: deps.now
10819
10836
  });
10837
+ return { workflowId, ...resolved.warning ? { roleWarning: resolved.warning } : {} };
10838
+ }
10839
+ var otherAgent = (a) => a === "claude" ? "codex" : "claude";
10840
+ function resolveRoleBindings(input) {
10841
+ const { explicitImplementer, explicitReviewer, callerAgent, def } = input;
10842
+ if (explicitImplementer || explicitReviewer) {
10843
+ const implementer2 = explicitImplementer ?? (explicitReviewer ? otherAgent(explicitReviewer) : void 0);
10844
+ const reviewer2 = explicitReviewer ?? (explicitImplementer ? otherAgent(explicitImplementer) : void 0);
10845
+ if (implementer2 && reviewer2) {
10846
+ if (implementer2 === reviewer2) {
10847
+ throw new Error("implementer and reviewer cannot be the same agent");
10848
+ }
10849
+ return { implementer: implementer2, reviewer: reviewer2, source: "explicit" };
10850
+ }
10851
+ }
10852
+ if (callerAgent) {
10853
+ return { implementer: callerAgent, reviewer: otherAgent(callerAgent), source: "caller" };
10854
+ }
10855
+ const implementer = def?.defaultImplementer;
10856
+ const reviewer = def?.defaultReviewer;
10857
+ if (!implementer || !reviewer) {
10858
+ throw new Error("no default role bindings");
10859
+ }
10860
+ return {
10861
+ implementer,
10862
+ reviewer,
10863
+ source: "default",
10864
+ warning: `No triggering agent detected; defaulted to implementer=${implementer} / reviewer=${reviewer}. Pass --implementer / --reviewer to choose explicitly.`
10865
+ };
10866
+ }
10867
+ function parseCallerAgent(raw) {
10868
+ return raw === "claude" || raw === "codex" ? raw : null;
10820
10869
  }
10821
10870
 
10822
10871
  // src/commands/workflow/list.ts
@@ -11184,8 +11233,10 @@ Not attached (stdin/stdout is not a TTY). To view the tmux session, run:
11184
11233
  ...opts.implementer ? { implementer: opts.implementer } : {},
11185
11234
  ...opts.reviewer ? { reviewer: opts.reviewer } : {},
11186
11235
  ...opts.name ? { name: opts.name } : {},
11236
+ callerAgent: parseCallerAgent(process.env.AI_WHISPER_AGENT),
11187
11237
  now: (/* @__PURE__ */ new Date()).toISOString()
11188
11238
  });
11239
+ if (result.roleWarning) console.error(result.roleWarning);
11189
11240
  console.log(`Workflow started: ${result.workflowId}`);
11190
11241
  } finally {
11191
11242
  await broker.stop();
@@ -97,7 +97,7 @@ Run:
97
97
  whisper workflow start --type=ralph-loop --spec=<resolved-absolute-path>
98
98
  ```
99
99
 
100
- (No `--implementer` / `--reviewer` — the CLI fills ralph defaults: implementer=claude, reviewer=codex. `--spec` names the goal file.)
100
+ (No `--implementer` / `--reviewer` needed — the agent triggering this skill becomes the implementer and the other agent the reviewer. Pass `--implementer <agent> --reviewer <agent>` only to override. `--spec` names the goal file.)
101
101
 
102
102
  Parse the workflowId from stdout (format: `Workflow started: <workflowId>`).
103
103
 
@@ -94,7 +94,7 @@ Run:
94
94
  whisper workflow start --type=spec-driven-development --spec=<resolved-absolute-path>
95
95
  ```
96
96
 
97
- (No `--implementer` / `--reviewer` — the CLI fills SDD defaults: implementer=claude, reviewer=codex.)
97
+ (No `--implementer` / `--reviewer` needed — the agent triggering this skill becomes the implementer and the other agent the reviewer. Pass `--implementer <agent> --reviewer <agent>` only to override.)
98
98
 
99
99
  Parse the workflowId from stdout (format: `Workflow started: <workflowId>`).
100
100
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-whisper",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Terminal-first relay for paired AI coding agents (Claude + Codex), driven by structured workflows.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -29,11 +29,11 @@
29
29
  "@types/better-sqlite3": "^7.6.12",
30
30
  "@types/react": "^19.2.14",
31
31
  "ink-testing-library": "^4.0.0",
32
- "@ai-whisper/adapter-codex": "0.0.0",
32
+ "@ai-whisper/adapter-claude": "0.0.0",
33
33
  "@ai-whisper/broker": "0.0.0",
34
+ "@ai-whisper/companion-core": "0.0.0",
34
35
  "@ai-whisper/shared": "0.0.0",
35
- "@ai-whisper/adapter-claude": "0.0.0",
36
- "@ai-whisper/companion-core": "0.0.0"
36
+ "@ai-whisper/adapter-codex": "0.0.0"
37
37
  },
38
38
  "files": [
39
39
  "dist",
@@ -97,7 +97,7 @@ Run:
97
97
  whisper workflow start --type=ralph-loop --spec=<resolved-absolute-path>
98
98
  ```
99
99
 
100
- (No `--implementer` / `--reviewer` — the CLI fills ralph defaults: implementer=claude, reviewer=codex. `--spec` names the goal file.)
100
+ (No `--implementer` / `--reviewer` needed — the agent triggering this skill becomes the implementer and the other agent the reviewer. Pass `--implementer <agent> --reviewer <agent>` only to override. `--spec` names the goal file.)
101
101
 
102
102
  Parse the workflowId from stdout (format: `Workflow started: <workflowId>`).
103
103
 
@@ -94,7 +94,7 @@ Run:
94
94
  whisper workflow start --type=spec-driven-development --spec=<resolved-absolute-path>
95
95
  ```
96
96
 
97
- (No `--implementer` / `--reviewer` — the CLI fills SDD defaults: implementer=claude, reviewer=codex.)
97
+ (No `--implementer` / `--reviewer` needed — the agent triggering this skill becomes the implementer and the other agent the reviewer. Pass `--implementer <agent> --reviewer <agent>` only to override.)
98
98
 
99
99
  Parse the workflowId from stdout (format: `Workflow started: <workflowId>`).
100
100