ai-whisper 0.12.0 → 0.12.1

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.
@@ -856,7 +856,7 @@ function listSessionAttachmentsByCollab(db, collabId2) {
856
856
 
857
857
  // ../broker/dist/storage/repositories/duo-assignment-repository.js
858
858
  import { z as z18 } from "zod";
859
- var duoRoleSchema = z18.enum(["reviewer", "implementer"]);
859
+ var duoRoleSchema = z18.enum(["body", "brain", "reviewer", "implementer"]).transform((value) => value === "reviewer" ? "brain" : value === "implementer" ? "body" : value);
860
860
  var duoRollSlotSchema = z18.object({
861
861
  characterId: z18.string().min(1),
862
862
  characterName: z18.string().min(1),
@@ -889,7 +889,7 @@ function listSessionAttachmentsByCollab(db, collabId) {
889
889
 
890
890
  // ../broker/dist/storage/repositories/duo-assignment-repository.js
891
891
  import { z as z18 } from "zod";
892
- var duoRoleSchema = z18.enum(["reviewer", "implementer"]);
892
+ var duoRoleSchema = z18.enum(["body", "brain", "reviewer", "implementer"]).transform((value) => value === "reviewer" ? "brain" : value === "implementer" ? "body" : value);
893
893
  var duoRollSlotSchema = z18.object({
894
894
  characterId: z18.string().min(1),
895
895
  characterName: z18.string().min(1),
@@ -859,7 +859,7 @@ function listSessionAttachmentsByCollab(db, collabId2) {
859
859
 
860
860
  // ../broker/dist/storage/repositories/duo-assignment-repository.js
861
861
  import { z as z18 } from "zod";
862
- var duoRoleSchema = z18.enum(["reviewer", "implementer"]);
862
+ var duoRoleSchema = z18.enum(["body", "brain", "reviewer", "implementer"]).transform((value) => value === "reviewer" ? "brain" : value === "implementer" ? "body" : value);
863
863
  var duoRollSlotSchema = z18.object({
864
864
  characterId: z18.string().min(1),
865
865
  characterName: z18.string().min(1),
@@ -1309,7 +1309,7 @@ var duoRoleSchema, duoRollSlotSchema, proposedDuoRollSchema;
1309
1309
  var init_duo_assignment_repository = __esm({
1310
1310
  "../broker/dist/storage/repositories/duo-assignment-repository.js"() {
1311
1311
  "use strict";
1312
- duoRoleSchema = z18.enum(["reviewer", "implementer"]);
1312
+ duoRoleSchema = z18.enum(["body", "brain", "reviewer", "implementer"]).transform((value) => value === "reviewer" ? "brain" : value === "implementer" ? "body" : value);
1313
1313
  duoRollSlotSchema = z18.object({
1314
1314
  characterId: z18.string().min(1),
1315
1315
  characterName: z18.string().min(1),
@@ -8883,6 +8883,7 @@ var DUOS = [
8883
8883
  characters: [
8884
8884
  {
8885
8885
  id: "sherlock",
8886
+ role: "brain",
8886
8887
  displayName: "Sherlock",
8887
8888
  summonName: "SHERLOCK",
8888
8889
  punchline: "Elementary, my dear Watson.",
@@ -8890,6 +8891,7 @@ var DUOS = [
8890
8891
  },
8891
8892
  {
8892
8893
  id: "watson",
8894
+ role: "body",
8893
8895
  displayName: "Watson",
8894
8896
  summonName: "WATSON",
8895
8897
  punchline: "By Jove, Holmes \u2014 it works!",
@@ -8902,6 +8904,7 @@ var DUOS = [
8902
8904
  characters: [
8903
8905
  {
8904
8906
  id: "frankenstein",
8907
+ role: "brain",
8905
8908
  displayName: "Frankenstein",
8906
8909
  summonName: "FRANKENSTEIN",
8907
8910
  punchline: "It's alive! IT'S ALIVE!",
@@ -8909,6 +8912,7 @@ var DUOS = [
8909
8912
  },
8910
8913
  {
8911
8914
  id: "igor",
8915
+ role: "body",
8912
8916
  displayName: "Igor",
8913
8917
  summonName: "IGOR",
8914
8918
  punchline: "It's pronounced 'eye-gor'.",
@@ -8921,6 +8925,7 @@ var DUOS = [
8921
8925
  characters: [
8922
8926
  {
8923
8927
  id: "quixote",
8928
+ role: "brain",
8924
8929
  displayName: "Don Quixote",
8925
8930
  summonName: "DON QUIXOTE",
8926
8931
  punchline: "Those are not windmills \u2014 they are giants!",
@@ -8928,6 +8933,7 @@ var DUOS = [
8928
8933
  },
8929
8934
  {
8930
8935
  id: "sancho",
8936
+ role: "body",
8931
8937
  displayName: "Sancho Panza",
8932
8938
  summonName: "SANCHO PANZA",
8933
8939
  punchline: "Se\xF1or... those are windmills.",
@@ -8940,6 +8946,7 @@ var DUOS = [
8940
8946
  characters: [
8941
8947
  {
8942
8948
  id: "c3po",
8949
+ role: "body",
8943
8950
  displayName: "C-3PO",
8944
8951
  summonName: "C-3PO",
8945
8952
  punchline: "We're doomed!",
@@ -8947,6 +8954,7 @@ var DUOS = [
8947
8954
  },
8948
8955
  {
8949
8956
  id: "r2d2",
8957
+ role: "brain",
8950
8958
  displayName: "R2-D2",
8951
8959
  summonName: "R2-D2",
8952
8960
  punchline: "Beep boop bee-boop.",
@@ -8959,6 +8967,7 @@ var DUOS = [
8959
8967
  characters: [
8960
8968
  {
8961
8969
  id: "batman",
8970
+ role: "brain",
8962
8971
  displayName: "Batman",
8963
8972
  summonName: "BATMAN",
8964
8973
  punchline: "I'm Batman.",
@@ -8966,6 +8975,7 @@ var DUOS = [
8966
8975
  },
8967
8976
  {
8968
8977
  id: "robin",
8978
+ role: "body",
8969
8979
  displayName: "Robin",
8970
8980
  summonName: "ROBIN",
8971
8981
  punchline: "Holy merge conflict, Batman!",
@@ -8978,6 +8988,7 @@ var DUOS = [
8978
8988
  characters: [
8979
8989
  {
8980
8990
  id: "rocket",
8991
+ role: "brain",
8981
8992
  displayName: "Rocket",
8982
8993
  summonName: "ROCKET",
8983
8994
  punchline: "Ain't no thing like me, 'cept me!",
@@ -8985,6 +8996,7 @@ var DUOS = [
8985
8996
  },
8986
8997
  {
8987
8998
  id: "groot",
8999
+ role: "body",
8988
9000
  displayName: "Groot",
8989
9001
  summonName: "GROOT",
8990
9002
  punchline: "I am Groot.",
@@ -8997,6 +9009,7 @@ var DUOS = [
8997
9009
  characters: [
8998
9010
  {
8999
9011
  id: "walter",
9012
+ role: "brain",
9000
9013
  displayName: "Walter White",
9001
9014
  summonName: "HEISENBERG",
9002
9015
  punchline: "I am the one who knocks.",
@@ -9004,6 +9017,7 @@ var DUOS = [
9004
9017
  },
9005
9018
  {
9006
9019
  id: "jesse",
9020
+ role: "body",
9007
9021
  displayName: "Jesse Pinkman",
9008
9022
  summonName: "JESSE",
9009
9023
  punchline: "That's science, b*tch!",
@@ -9012,6 +9026,9 @@ var DUOS = [
9012
9026
  ]
9013
9027
  }
9014
9028
  ];
9029
+ function duoRoleFlavor(role) {
9030
+ return role === "brain" ? "the brain of this operation" : "the body, the face, and the hair";
9031
+ }
9015
9032
  function getDuo(duoId) {
9016
9033
  return DUOS.find((duo) => duo.id === duoId);
9017
9034
  }
@@ -14477,8 +14494,8 @@ function compareSemver(a, b) {
14477
14494
  var EZIO_PROVENANCE = {
14478
14495
  ezioCliVersion: "0.4.0",
14479
14496
  ezioGitSha: "77a3b48",
14480
- builtAt: "2026-07-03T02:47:29.632Z",
14481
- whisperVersion: "0.12.0"
14497
+ builtAt: "2026-07-03T06:53:50.854Z",
14498
+ whisperVersion: "0.12.1"
14482
14499
  };
14483
14500
 
14484
14501
  // src/ezio-provenance-types.ts
@@ -16075,11 +16092,28 @@ function buildDuoHandoffFragment(input) {
16075
16092
  return `[duo] You are ${input.character} (${input.role}); teammate ${input.teammateAgentType} is ${teammateDisplay}. Character flavor in prose only; never alter code, commits, or workflow verdict labels.`;
16076
16093
  }
16077
16094
  function buildDuoPersonaBrief(duo) {
16078
- const otherRole = duo.role === "reviewer" ? "implementer" : "reviewer";
16095
+ const otherRole = duo.role === "brain" ? "body" : "brain";
16079
16096
  const teammateClause = duo.teammate === null ? " Your teammate has no character assigned yet." : duo.teammate.character === null ? ` Your teammate ${duo.teammate.agentType} has no character assigned.` : ` Your teammate ${duo.teammate.agentType} is ${duo.teammate.character}, the ${otherRole}.`;
16080
- return `[ai-whisper duo] For this collab session you are ${duo.character} \u2014 the ${duo.role} of this duo.${teammateClause}
16097
+ return `[ai-whisper duo] For this collab session you are ${duo.character} \u2014 ${duoRoleFlavor(duo.role)}.${teammateClause}
16081
16098
  Stay in character in conversational prose only \u2014 never in code, commit messages, PR text, or file contents, and never alter workflow verdict labels.`;
16082
16099
  }
16100
+ async function waitForProviderOutputSettle(input) {
16101
+ const now = input.now ?? Date.now;
16102
+ const sleep3 = input.sleep ?? ((ms) => new Promise((resolve5) => setTimeout(resolve5, ms)));
16103
+ const pollMs = input.pollMs ?? 50;
16104
+ const deadline = now() + input.maxWaitMs;
16105
+ for (; ; ) {
16106
+ const lastOutputAt = input.getLastOutputAt();
16107
+ const t = now();
16108
+ if (lastOutputAt !== null && t - lastOutputAt >= input.quietMs) {
16109
+ return "settled";
16110
+ }
16111
+ if (t >= deadline) {
16112
+ return "timeout";
16113
+ }
16114
+ await sleep3(Math.min(pollMs, deadline - t));
16115
+ }
16116
+ }
16083
16117
  function resolveTeammateCharacterFromAssignments(assignments, teammateAgentType) {
16084
16118
  const row = assignments.find((r) => r.agentType === teammateAgentType);
16085
16119
  if (!row) return null;
@@ -16269,6 +16303,7 @@ function createMountSessionRuntime(input) {
16269
16303
  Number(process.env.AI_WHISPER_IDLE_THRESHOLD_MS ?? "") || 3e4
16270
16304
  );
16271
16305
  let lastActivityAt = Date.now();
16306
+ let lastProviderOutputAt = null;
16272
16307
  let agyToolInFlight = false;
16273
16308
  try {
16274
16309
  const turnCapture = createAssistantTurnCapture();
@@ -16303,6 +16338,7 @@ function createMountSessionRuntime(input) {
16303
16338
  };
16304
16339
  interactiveSession.onProviderOutput?.((data) => {
16305
16340
  lastActivityAt = Date.now();
16341
+ lastProviderOutputAt = Date.now();
16306
16342
  turnCapture.recordProviderOutput(data);
16307
16343
  bracketedPaste.observe(data);
16308
16344
  });
@@ -16431,6 +16467,19 @@ function createMountSessionRuntime(input) {
16431
16467
  }
16432
16468
  if (input.duo) {
16433
16469
  try {
16470
+ if (input.target !== "ezio" && typeof interactiveSession.onProviderOutput === "function") {
16471
+ await waitForProviderOutputSettle({
16472
+ getLastOutputAt: () => lastProviderOutputAt,
16473
+ quietMs: Math.max(
16474
+ 0,
16475
+ Number(process.env.AI_WHISPER_DUO_BRIEF_QUIET_MS ?? "") || 500
16476
+ ),
16477
+ maxWaitMs: Math.max(
16478
+ 0,
16479
+ Number(process.env.AI_WHISPER_DUO_BRIEF_MAX_WAIT_MS ?? "") || 1e4
16480
+ )
16481
+ });
16482
+ }
16434
16483
  await submitInjectedInput2(buildDuoPersonaBrief(input.duo));
16435
16484
  } catch (err) {
16436
16485
  console.error(
@@ -17113,13 +17162,14 @@ function resolveDuoEnabled(duoFlag) {
17113
17162
  // src/duo/roll-duo.ts
17114
17163
  function rollDuo(rng = Math.random) {
17115
17164
  const duo = DUOS[Math.floor(rng() * DUOS.length)];
17116
- const reviewerIndex = Math.floor(rng() * 2);
17117
- const slots = duo.characters.map((character, index) => ({
17165
+ const body = duo.characters.find((character) => character.role === "body");
17166
+ const brain = duo.characters.find((character) => character.role === "brain");
17167
+ const toSlot = (character) => ({
17118
17168
  characterId: character.id,
17119
17169
  characterName: character.displayName,
17120
- role: index === reviewerIndex ? "reviewer" : "implementer"
17121
- }));
17122
- return { duoId: duo.id, slots };
17170
+ role: character.role
17171
+ });
17172
+ return { duoId: duo.id, slots: [toSlot(body), toSlot(brain)] };
17123
17173
  }
17124
17174
 
17125
17175
  // src/duo/art-assets.ts
@@ -17158,7 +17208,7 @@ init_agent_display();
17158
17208
  var RESET4 = "\x1B[0m";
17159
17209
  var PUNCHLINE_INDENT = " ";
17160
17210
  function renderDuoBanner(input) {
17161
- const summonLine = `\u26A1 Summoning ${input.summonName} as ${input.role}...`;
17211
+ const summonLine = `\u26A1 Summoning ${input.summonName} \u2014 ${duoRoleFlavor(input.role)}...`;
17162
17212
  const punchlineLine = `${PUNCHLINE_INDENT}"${input.punchline}"`;
17163
17213
  const showArt = input.columns >= maxDisplayWidth(input.art);
17164
17214
  const parts = showArt ? [summonLine, "", input.art, "", punchlineLine, RESET4] : [summonLine, punchlineLine, RESET4];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-whisper",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
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": {
@@ -55,10 +55,10 @@
55
55
  "@ai-whisper/adapter-ai-ezio": "0.0.0",
56
56
  "@ai-whisper/adapter-antigravity": "0.0.0",
57
57
  "@ai-whisper/adapter-codex": "0.0.0",
58
+ "@ai-whisper/companion-core": "0.0.0",
58
59
  "@ai-whisper/broker": "0.0.0",
59
60
  "@ai-whisper/adapter-claude": "0.0.0",
60
- "@ai-whisper/shared": "0.0.0",
61
- "@ai-whisper/companion-core": "0.0.0"
61
+ "@ai-whisper/shared": "0.0.0"
62
62
  },
63
63
  "files": [
64
64
  "dist",