chatroom-cli 1.77.0 → 1.77.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/dist/index.js CHANGED
@@ -77610,9 +77610,6 @@ ${getUnresolvedDecisionsSectionBlock()}
77610
77610
 
77611
77611
  ## Notes
77612
77612
  <anything the user should know — context, caveats, or observations not covered above. Omit if none.>
77613
-
77614
- ## Next steps
77615
- <follow-up actions for the user or team. Omit if none.>
77616
77613
  \`\`\``;
77617
77614
  }
77618
77615
  var init_planner_to_user = __esm(() => {
@@ -77715,9 +77712,6 @@ ${getUnresolvedDecisionsSectionBlock()}
77715
77712
 
77716
77713
  ## Notes
77717
77714
  <anything the user should know — context, caveats, or observations not covered above. Omit if none.>
77718
-
77719
- ## Next steps
77720
- <follow-up actions for the user or team. Omit if none.>
77721
77715
  \`\`\``;
77722
77716
  }
77723
77717
  var init_solo_to_user = __esm(() => {
@@ -78896,7 +78890,9 @@ flowchart TD
78896
78890
  **Review loop:**
78897
78891
  - Review completed work before moving to the next slice.
78898
78892
  - Send back with specific feedback if requirements aren't met.
78899
- - ${feedingNote}.`;
78893
+ - ${feedingNote}.
78894
+
78895
+ **When enhancement is enabled:** See \`<handoff-enhancer>\` in task delivery — one check-in per delegation before builder.`;
78900
78896
  }
78901
78897
  function getDelegationGuidelinesSection(config3, options) {
78902
78898
  const feedingNote = config3.hasBuilder ? "Feed slices to the builder incrementally — one at a time, not all at once" : "When implementing yourself, tackle one layer at a time — avoid large monolithic changes";
@@ -78914,9 +78910,10 @@ function getDelegationGuidelinesSection(config3, options) {
78914
78910
  function buildHandoffRuleLines(config3) {
78915
78911
  return [
78916
78912
  config3.hasBuilder ? "- **To delegate implementation** → Hand off to `builder` with clear requirements" : "- **To implement** → Work on the chatroom task directly (you are acting as implementer)",
78913
+ config3.hasBuilder ? "- **When enhancement is enabled** → See `<handoff-enhancer>` in task delivery before each builder delegation" : null,
78917
78914
  "- **To deliver to user** → Hand off to `user` with a complete, standalone summary\n ⚠️ The user can ONLY see the handoff-to-user message — progress reports and all other messages are invisible to them. Write the handoff as a self-contained document: include all relevant context, results, and next steps without assuming the user read any prior conversation.",
78918
78915
  config3.hasBuilder ? "- **For rework** → Hand off back to `builder` with specific feedback on what needs to change" : "- **For rework** → Revise your implementation directly and re-validate"
78919
- ].join(`
78916
+ ].filter((line) => line !== null).join(`
78920
78917
  `);
78921
78918
  }
78922
78919
  function getHandoffRulesSection(config3, nativeIntegration) {
@@ -103884,7 +103881,7 @@ var init_start_subscriptions2 = __esm(() => {
103884
103881
  });
103885
103882
 
103886
103883
  // src/commands/machine/daemon-start/enhancer/constants.ts
103887
- var ENHANCER_AGENT_ROLE = "enhancer";
103884
+ var ENHANCER_AGENT_ROLE = "enhancer", ENHANCER_AGENT_END_GRACE_MS = 3000, ENHANCER_JOB_POLL_INTERVAL_MS = 500, ENHANCER_SILENCE_TIMEOUT_MS = 120000;
103888
103885
 
103889
103886
  // src/commands/machine/daemon-start/enhancer/enhancer-log.ts
103890
103887
  function formatEnhancerLogLine(message) {
@@ -103899,6 +103896,114 @@ function writeEnhancerLog(message) {
103899
103896
  }
103900
103897
  var ENHANCER_LOG_PREFIX = "[enhancer]";
103901
103898
 
103899
+ // src/commands/machine/daemon-start/enhancer/wait-for-enhancer-job.ts
103900
+ async function waitForEnhancerJobResolution(params) {
103901
+ const { sessionId, chatroomId, jobId, backend: backend2, onFailure, onSalvageComplete } = params;
103902
+ let outcome = null;
103903
+ let lastActivityAt = Date.now();
103904
+ let salvagedText = "";
103905
+ const pollInterval = setInterval(async () => {
103906
+ if (outcome)
103907
+ return;
103908
+ try {
103909
+ const status3 = await backend2.query(api.web.enhancer.index.getJob, {
103910
+ sessionId,
103911
+ chatroomId,
103912
+ jobId
103913
+ });
103914
+ if (status3?.status === "complete") {
103915
+ outcome = "complete";
103916
+ writeEnhancerLog(`completed job=${jobId}`);
103917
+ }
103918
+ } catch {}
103919
+ }, ENHANCER_JOB_POLL_INTERVAL_MS);
103920
+ const silenceInterval = setInterval(() => {
103921
+ if (outcome)
103922
+ return;
103923
+ if (Date.now() - lastActivityAt >= ENHANCER_SILENCE_TIMEOUT_MS) {
103924
+ outcome = "failed";
103925
+ writeEnhancerLog(`silence timeout — no activity for ${ENHANCER_SILENCE_TIMEOUT_MS}ms`);
103926
+ onFailure("Enhancer silence timeout — no output received", false);
103927
+ }
103928
+ }, ENHANCER_JOB_POLL_INTERVAL_MS);
103929
+ params.onAssistantText?.((text) => {
103930
+ lastActivityAt = Date.now();
103931
+ salvagedText += text;
103932
+ });
103933
+ params.onAgentEnd?.(() => {
103934
+ if (outcome)
103935
+ return;
103936
+ const check4 = () => {
103937
+ if (outcome)
103938
+ return;
103939
+ backend2.query(api.web.enhancer.index.getJob, {
103940
+ sessionId,
103941
+ chatroomId,
103942
+ jobId
103943
+ }).then((status3) => {
103944
+ if (outcome)
103945
+ return;
103946
+ if (status3?.status === "complete") {
103947
+ outcome = "complete";
103948
+ return;
103949
+ }
103950
+ if (status3?.status === "running") {
103951
+ const trimmed = salvagedText.trim();
103952
+ if (trimmed && onSalvageComplete) {
103953
+ onSalvageComplete(trimmed).then(() => {
103954
+ if (outcome)
103955
+ return;
103956
+ backend2.query(api.web.enhancer.index.getJob, {
103957
+ sessionId,
103958
+ chatroomId,
103959
+ jobId
103960
+ }).then((afterSalvage) => {
103961
+ if (afterSalvage?.status === "complete") {
103962
+ outcome = "complete";
103963
+ writeEnhancerLog("agent_end: salvaged assistant text via complete");
103964
+ return;
103965
+ }
103966
+ outcome = "failed";
103967
+ writeEnhancerLog("agent_end: turn ended without complete — failing terminal");
103968
+ onFailure("Agent exited without completing enhancer job", true);
103969
+ });
103970
+ }).catch(() => {
103971
+ outcome = "failed";
103972
+ writeEnhancerLog("agent_end: turn ended without complete — failing terminal");
103973
+ onFailure("Agent exited without completing enhancer job", true);
103974
+ });
103975
+ } else {
103976
+ outcome = "failed";
103977
+ writeEnhancerLog("agent_end: turn ended without complete — failing terminal");
103978
+ onFailure("Agent exited without completing enhancer job", true);
103979
+ }
103980
+ }
103981
+ });
103982
+ };
103983
+ setTimeout(check4, ENHANCER_AGENT_END_GRACE_MS);
103984
+ });
103985
+ params.onExit(() => {
103986
+ if (outcome)
103987
+ return;
103988
+ outcome = "failed";
103989
+ onFailure("Agent process exited without completing enhancer job", false);
103990
+ });
103991
+ await new Promise((resolve4) => {
103992
+ const check4 = setInterval(() => {
103993
+ if (outcome) {
103994
+ clearInterval(check4);
103995
+ resolve4();
103996
+ }
103997
+ }, 100);
103998
+ });
103999
+ clearInterval(pollInterval);
104000
+ clearInterval(silenceInterval);
104001
+ return outcome ?? "failed";
104002
+ }
104003
+ var init_wait_for_enhancer_job = __esm(() => {
104004
+ init_api3();
104005
+ });
104006
+
103902
104007
  // src/commands/machine/daemon-start/enhancer/job-subscriber.ts
103903
104008
  function startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, wsClient2, agentServices) {
103904
104009
  const inFlight = new Set;
@@ -103911,6 +104016,8 @@ function startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, w
103911
104016
  let claimed = false;
103912
104017
  let chatroomId = job.chatroomId;
103913
104018
  let jobId = job.jobId;
104019
+ let spawnResult = null;
104020
+ let service3 = null;
103914
104021
  try {
103915
104022
  const claim = await backend2.mutation(api.daemon.enhancer.index.claimForSpawn, {
103916
104023
  sessionId,
@@ -103928,7 +104035,7 @@ function startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, w
103928
104035
  chatroomId = payload.chatroomId;
103929
104036
  jobId = payload.jobId;
103930
104037
  writeEnhancerLog(`spawning harness=${payload.agentHarness} model=${payload.model} job=${payload.jobId}`);
103931
- const service3 = agentServices.get(payload.agentHarness);
104038
+ service3 = agentServices.get(payload.agentHarness) ?? null;
103932
104039
  if (!service3) {
103933
104040
  await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
103934
104041
  sessionId,
@@ -103938,7 +104045,7 @@ function startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, w
103938
104045
  });
103939
104046
  return;
103940
104047
  }
103941
- const spawnResult = await service3.spawn({
104048
+ spawnResult = await service3.spawn({
103942
104049
  workingDir: payload.workingDir,
103943
104050
  prompt: createSpawnPrompt(payload.taskEnvelope),
103944
104051
  systemPrompt: payload.systemPrompt,
@@ -103953,29 +104060,34 @@ function startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, w
103953
104060
  spawnResult.onLogLine?.((line) => {
103954
104061
  writeEnhancerLog(line);
103955
104062
  });
103956
- spawnResult.onAssistantText?.((text) => {
103957
- if (text)
103958
- writeEnhancerLog(`text] ${text}`);
103959
- });
103960
- await new Promise((resolve4) => {
103961
- spawnResult.onExit(() => resolve4());
103962
- });
103963
- const status3 = await backend2.query(api.web.enhancer.index.getJob, {
104063
+ const sr = spawnResult;
104064
+ const outcome = await waitForEnhancerJobResolution({
103964
104065
  sessionId,
103965
104066
  chatroomId: payload.chatroomId,
103966
- jobId: payload.jobId
104067
+ jobId: payload.jobId,
104068
+ backend: backend2,
104069
+ onAssistantText: sr.onAssistantText ? (cb) => sr.onAssistantText(cb) : undefined,
104070
+ onAgentEnd: sr.onAgentEnd ? (cb) => sr.onAgentEnd(cb) : undefined,
104071
+ onExit: (cb) => sr.onExit(() => cb()),
104072
+ onSalvageComplete: async (content) => {
104073
+ await backend2.mutation(api.web.enhancer.index.complete, {
104074
+ sessionId,
104075
+ chatroomId: payload.chatroomId,
104076
+ jobId: payload.jobId,
104077
+ enhancedContent: content
104078
+ });
104079
+ },
104080
+ onFailure: async (error51, forceTerminal) => {
104081
+ await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
104082
+ sessionId,
104083
+ chatroomId: payload.chatroomId,
104084
+ jobId: payload.jobId,
104085
+ error: error51,
104086
+ ...forceTerminal ? { forceTerminal: true } : {}
104087
+ });
104088
+ }
103967
104089
  });
103968
- if (status3?.status === "complete") {
103969
- writeEnhancerLog(`completed job=${payload.jobId}`);
103970
- }
103971
- if (status3?.status === "running") {
103972
- await backend2.mutation(api.web.enhancer.index.recordAttemptFailure, {
103973
- sessionId,
103974
- chatroomId: payload.chatroomId,
103975
- jobId: payload.jobId,
103976
- error: "Agent exited without completing enhancer job"
103977
- });
103978
- }
104090
+ writeEnhancerLog(`completed job=${jobId}`);
103979
104091
  } catch (err) {
103980
104092
  writeEnhancerLog(`error: ${err instanceof Error ? err.message : String(err)}`);
103981
104093
  if (claimed) {
@@ -103988,6 +104100,11 @@ function startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, w
103988
104100
  }
103989
104101
  } finally {
103990
104102
  inFlight.delete(job.jobId);
104103
+ if (spawnResult && service3) {
104104
+ try {
104105
+ await service3.stop(spawnResult.pid);
104106
+ } catch {}
104107
+ }
103991
104108
  }
103992
104109
  })();
103993
104110
  }
@@ -103995,6 +104112,7 @@ function startEnhancerJobSubscriber(sessionId, machineId, convexUrl, backend2, w
103995
104112
  return { stop: unsub };
103996
104113
  }
103997
104114
  var init_job_subscriber = __esm(() => {
104115
+ init_wait_for_enhancer_job();
103998
104116
  init_api3();
103999
104117
  });
104000
104118
 
@@ -104112,11 +104230,11 @@ async function getWorkspacesForMachine(deps) {
104112
104230
  return store.workspaces;
104113
104231
  }
104114
104232
  try {
104115
- const workspaces = await deps.backend.query(api.workspaces.listRecentlyObservedWorkspacesForMachine, {
104233
+ const workingDirs = await deps.backend.query(api.workspaces.listRecentlyObservedWorkspacesForMachine, {
104116
104234
  sessionId: deps.sessionId,
104117
104235
  machineId: deps.machineId
104118
104236
  });
104119
- const mapped = workspaces.map((ws) => ({ workingDir: ws.workingDir }));
104237
+ const mapped = (workingDirs ?? []).map((workingDir) => ({ workingDir }));
104120
104238
  if (store) {
104121
104239
  store.workspaces = mapped;
104122
104240
  store.updatedAt = Date.now();
@@ -107837,18 +107955,18 @@ async function syncScannedFileTree(session2, normalizedWorkingDir, tree, dataHas
107837
107955
  function toDeltaOperations(delta) {
107838
107956
  return [
107839
107957
  ...delta.added.map((entry) => ({
107840
- operation: "add",
107841
- path: entry.path,
107842
- entryType: entry.type
107958
+ o: "a",
107959
+ p: entry.path,
107960
+ e: entry.type === "directory" ? "d" : "f"
107843
107961
  })),
107844
107962
  ...delta.removed.map((entryPath) => ({
107845
- operation: "remove",
107846
- path: entryPath
107963
+ o: "r",
107964
+ p: entryPath
107847
107965
  })),
107848
107966
  ...delta.typeChanged.map((entry) => ({
107849
- operation: "type-change",
107850
- path: entry.path,
107851
- entryType: entry.type
107967
+ o: "t",
107968
+ p: entry.path,
107969
+ e: entry.type === "directory" ? "d" : "f"
107852
107970
  }))
107853
107971
  ];
107854
107972
  }
@@ -113276,9 +113394,9 @@ var startObservedSyncSubscriptionEffect = (wsClient2) => exports_Effect.gen(func
113276
113394
  sessionId: session2.sessionId,
113277
113395
  machineId: session2.machineId
113278
113396
  }, (observed) => {
113279
- if (stopped)
113397
+ if (stopped || observed == null)
113280
113398
  return;
113281
- handleObservedChange(observed ?? []);
113399
+ handleObservedChange(observed);
113282
113400
  }, (err) => {
113283
113401
  console.warn(`[${formatTimestamp()}] ⚠️ Observed-sync subscription error: ${getErrorMessage(err)}`);
113284
113402
  });
@@ -113291,8 +113409,8 @@ var startObservedSyncSubscriptionEffect = (wsClient2) => exports_Effect.gen(func
113291
113409
  sessionId: session2.sessionId,
113292
113410
  machineId: session2.machineId
113293
113411
  }).then((observed) => {
113294
- if (!stopped)
113295
- handleObservedChange(observed ?? []);
113412
+ if (!stopped && observed != null)
113413
+ handleObservedChange(observed);
113296
113414
  }).catch((err) => {
113297
113415
  console.warn(`[${formatTimestamp()}] ⚠️ Observed-sync reconcile query failed: ${getErrorMessage(err)}`);
113298
113416
  }).finally(() => {
@@ -114501,8 +114619,8 @@ var init_task_monitor = __esm(() => {
114501
114619
  });
114502
114620
 
114503
114621
  // src/commands/machine/daemon-start/workspace-list-subscription.ts
114504
- function toSyncWorkspaces(workspaces) {
114505
- return workspaces.map((ws) => ({ workingDir: ws.workingDir }));
114622
+ function toSyncWorkspaces(workingDirs) {
114623
+ return workingDirs.map((workingDir) => ({ workingDir }));
114506
114624
  }
114507
114625
  var startWorkspaceListSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
114508
114626
  const session2 = yield* DaemonSessionService;
@@ -114514,16 +114632,16 @@ var startWorkspaceListSubscriptionEffect = (wsClient2) => exports_Effect.gen(fun
114514
114632
  };
114515
114633
  let stopped = false;
114516
114634
  let reconcileInFlight = false;
114517
- const applyList = (workspaces) => {
114635
+ const applyList = (workingDirs) => {
114518
114636
  if (!session2.workspaceListStore)
114519
114637
  return;
114520
- session2.workspaceListStore.workspaces = toSyncWorkspaces(workspaces);
114638
+ session2.workspaceListStore.workspaces = toSyncWorkspaces(workingDirs);
114521
114639
  session2.workspaceListStore.updatedAt = Date.now();
114522
114640
  };
114523
114641
  const unsubscribe = wsClient2.onUpdate(api.workspaces.listRecentlyObservedWorkspacesForMachine, queryArgs, (workspaces) => {
114524
- if (stopped)
114642
+ if (stopped || workspaces == null)
114525
114643
  return;
114526
- applyList(workspaces ?? []);
114644
+ applyList(workspaces);
114527
114645
  }, (err) => {
114528
114646
  console.warn(`[${formatTimestamp()}] ⚠️ Workspace-list subscription error: ${getErrorMessage(err)}`);
114529
114647
  });
@@ -114532,8 +114650,8 @@ var startWorkspaceListSubscriptionEffect = (wsClient2) => exports_Effect.gen(fun
114532
114650
  return;
114533
114651
  reconcileInFlight = true;
114534
114652
  session2.backend.query(api.workspaces.listRecentlyObservedWorkspacesForMachine, queryArgs).then((workspaces) => {
114535
- if (!stopped)
114536
- applyList(workspaces ?? []);
114653
+ if (!stopped && workspaces != null)
114654
+ applyList(workspaces);
114537
114655
  }).catch((err) => {
114538
114656
  console.warn(`[${formatTimestamp()}] ⚠️ Workspace-list reconcile failed: ${getErrorMessage(err)}`);
114539
114657
  }).finally(() => {
@@ -116147,4 +116265,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
116147
116265
  });
116148
116266
  program2.parse();
116149
116267
 
116150
- //# debugId=94A8E14D18276BBD64756E2164756E21
116268
+ //# debugId=E0C7F128710614BD64756E2164756E21