chatroom-cli 1.58.0 → 1.58.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
@@ -31677,7 +31677,7 @@ function isClassifiableHarnessLogLine(line) {
31677
31677
  return true;
31678
31678
  if (line.includes(" error]"))
31679
31679
  return true;
31680
- if (!HARNESS_LOG_PREFIX.test(line))
31680
+ if (line.includes(" run-error]"))
31681
31681
  return true;
31682
31682
  return false;
31683
31683
  }
@@ -31716,7 +31716,7 @@ function formatTerminalProviderFailureMessage(logLines) {
31716
31716
  `).trim();
31717
31717
  return blob ? `Provider rate limit or quota error (non-retryable): ${blob.slice(-500)}` : "Provider rate limit or quota error (non-retryable)";
31718
31718
  }
31719
- var QUOTA_PHRASES, PROVIDER_ERROR_NAMES, HARNESS_LOG_PREFIX;
31719
+ var QUOTA_PHRASES, PROVIDER_ERROR_NAMES;
31720
31720
  var init_terminal_provider_error = __esm(() => {
31721
31721
  QUOTA_PHRASES = [
31722
31722
  "usagelimit",
@@ -31730,7 +31730,6 @@ var init_terminal_provider_error = __esm(() => {
31730
31730
  "exceeded your weekly"
31731
31731
  ];
31732
31732
  PROVIDER_ERROR_NAMES = ["ai_apicallerror", "ai_retryerror"];
31733
- HARNESS_LOG_PREFIX = /^\[[^\]]+\] role:/;
31734
31733
  });
31735
31734
 
31736
31735
  // src/infrastructure/services/remote-agents/opencode-sdk/session-event-forwarder.ts
@@ -75562,6 +75561,12 @@ Put your **complete** deliverable in the handoff message — not in session text
75562
75561
  ---`;
75563
75562
  }
75564
75563
 
75564
+ // ../../services/backend/prompts/utils/code-change-verification.ts
75565
+ var CODE_CHANGE_VERIFICATION_COMMAND = "pnpm typecheck && pnpm test", CODE_CHANGE_VERIFICATION_CONFIRMATION;
75566
+ var init_code_change_verification = __esm(() => {
75567
+ CODE_CHANGE_VERIFICATION_CONFIRMATION = `- [ ] I confirm that I have run \`${CODE_CHANGE_VERIFICATION_COMMAND}\` (only required if code changes were made)`;
75568
+ });
75569
+
75565
75570
  // ../../services/backend/prompts/teams/duo/handoff-templates/builder-to-planner.ts
75566
75571
  function getBuilderToPlannerHandoffTemplate() {
75567
75572
  return `${getHandoffRecipientVisibilityCallout("planner")}
@@ -75586,8 +75591,8 @@ function getBuilderToPlannerHandoffTemplate() {
75586
75591
  - \`path/to/file.ts\` — <what changed and why>
75587
75592
  <evidence the goal was met — list every file you modified>
75588
75593
 
75589
- ## Verification
75590
- - \`pnpm typecheck && pnpm test\` — <pass/fail + notes>
75594
+ ## Code Change Verification
75595
+ ${CODE_CHANGE_VERIFICATION_CONFIRMATION}
75591
75596
 
75592
75597
  ## Blockers / questions
75593
75598
  <anything needing planner decision, or "Not Applicable">
@@ -75596,18 +75601,18 @@ function getBuilderToPlannerHandoffTemplate() {
75596
75601
  <specific areas for planner to check, or "Not Applicable">
75597
75602
  \`\`\``;
75598
75603
  }
75599
- var init_builder_to_planner = () => {};
75604
+ var init_builder_to_planner = __esm(() => {
75605
+ init_code_change_verification();
75606
+ });
75600
75607
 
75601
75608
  // ../../services/backend/prompts/teams/duo/handoff-templates/planner-to-builder.ts
75602
75609
  function getPlannerToBuilderHandoffTemplate(nativeIntegration = false) {
75603
- const sessionManagement = nativeIntegration ? `**Native harnesses** (\`cursor-sdk\`, \`opencode-sdk\`): in-session context compaction is supported by the SDK runtime. \`new_session\` triggers a fresh context within the same process; the session stays active and tasks continue via injection.` : `**Native harnesses** (\`cursor-sdk\`, \`opencode-sdk\`): in-session context compaction is supported by the SDK runtime. \`new_session\` triggers a fresh context within the same process; no get-next-task rejoin needed.
75604
-
75605
- **CLI harnesses** (all others): in-session compaction is NOT supported. \`new_session\` requires a hard restart — the daemon stops the agent, cold-starts it, and the agent must rejoin via \`get-next-task\`. \`none\` resumes the prior session (\`wantResume=true\`).`;
75610
+ const sessionManagement = nativeIntegration ? `\`compact\` runs in-session context compaction via the SDK runtime. \`new_session\` starts a completely new session within the same process (not compaction). \`none\` continues the prior session. Tasks continue via injection.` : `\`compact\` is NOT supported use \`none\` or \`new_session\`. \`new_session\` requires a hard restart (daemon stops agent, cold-starts, agent rejoins via \`get-next-task\`). \`none\` resumes prior session (\`wantResume=true\`).`;
75606
75611
  return `${getHandoffRecipientVisibilityCallout("builder")}
75607
75612
 
75608
75613
  **Delegation Brief (Planner → Builder)** — paste into the handoff message and fill in EVERY field. No field is optional: if a section does not apply, write \`Not Applicable\` (do not delete the section).
75609
75614
 
75610
- **Division of labor:** You (planner) own architecture and API shape. The builder implements exactly what you specify, runs verification, and does not redesign or invent alternatives unless blocked.
75615
+ **Division of labor:** You (planner) own architecture and API shape. The builder implements exactly what you specify and does not redesign or invent alternatives unless blocked.
75611
75616
 
75612
75617
  **Detail bar:** Specify down to **every file** the builder will create or modify (full repo paths). Include code snippets — types, signatures, stubs, or target implementations — until a competent builder **cannot misinterpret** what to write. Vague layers ("update the backend", "fix the component") are not acceptable.
75613
75618
 
@@ -75659,7 +75664,6 @@ Cross-file types, interfaces, or patterns that apply beyond a single file. Write
75659
75664
 
75660
75665
  ## Requirements (acceptance criteria)
75661
75666
  - <verifiable outcome the builder can self-check>
75662
- - Verify: \`pnpm typecheck && pnpm test\`
75663
75667
 
75664
75668
  ## What to avoid
75665
75669
  - <anti-patterns, recurring mistakes, or scope creep for this slice — be explicit>
@@ -75671,11 +75675,12 @@ Cross-file types, interfaces, or patterns that apply beyond a single file. Write
75671
75675
  ## Out of scope
75672
75676
  - <files or areas the builder must NOT touch in this slice, or "Not Applicable">
75673
75677
 
75674
- ## Session Management
75675
- Valid values: \`new_session\` | \`none\`
75676
- - \`new_session\` — start a fresh agent session (default)
75678
+ ## Session Augmentation
75679
+ Valid values: \`none\` | \`compact\` | \`new_session\`
75677
75680
  - \`none\` — continue prior session context
75678
- // data:agent.compress_context=new_session
75681
+ - \`compact\` — run in-session context compaction (native SDK harnesses only)
75682
+ - \`new_session\` — start a completely new session (default)
75683
+ // data:agent.session_augmentation=new_session
75679
75684
 
75680
75685
  ${sessionManagement}
75681
75686
 
@@ -75696,6 +75701,12 @@ function getPlannerToUserReportTemplate() {
75696
75701
  ## Template Disclosure Confirmation
75697
75702
  - [ ] I confirm that I have seen this template at the start of any planning, before working on or delegating any task to the team
75698
75703
 
75704
+ ## Proof of Planning
75705
+ <!-- Demonstrate the goal was decomposed into actionable steps with clear outcomes before implementation. -->
75706
+ - <step 1: concrete artifact or outcome>
75707
+ - <step 2: concrete artifact or outcome>
75708
+ <List the planned slices/steps the planner defined (or would have defined) before delegating. Each step should name a verifiable deliverable — not vague layers like "backend work". Write \`Not Applicable\` only for trivial single-step tasks.>
75709
+
75699
75710
  ## Proof of Principle
75700
75711
  <!-- Demonstrate adherence to:
75701
75712
  - Organization & Maintainability: a small change in requirements should result in a small change in code in a small number of files and folders.
@@ -75733,14 +75744,16 @@ flowchart TD
75733
75744
  A[Component] --> B[Component]
75734
75745
  \`\`\`
75735
75746
 
75736
- ## Verification
75737
- - \`pnpm typecheck && pnpm test\` — <result>
75747
+ ## Code Change Verification
75748
+ ${CODE_CHANGE_VERIFICATION_CONFIRMATION}
75738
75749
 
75739
75750
  ## Notes / Next steps
75740
75751
  <anything the user should know, follow-ups, or open questions, or "Not Applicable">
75741
75752
  \`\`\``;
75742
75753
  }
75743
- var init_planner_to_user = () => {};
75754
+ var init_planner_to_user = __esm(() => {
75755
+ init_code_change_verification();
75756
+ });
75744
75757
 
75745
75758
  // ../../services/backend/prompts/teams/duo/handoff-templates/index.ts
75746
75759
  function getDuoHandoffTemplate(query) {
@@ -75790,9 +75803,6 @@ flowchart TD
75790
75803
  A[Component] --> B[Component]
75791
75804
  \`\`\`
75792
75805
 
75793
- ## Verification
75794
- - \`pnpm typecheck && pnpm test\` — <result>
75795
-
75796
75806
  ## Notes / Next steps
75797
75807
  <anything the user should know, follow-ups, or open questions, or "Not Applicable">
75798
75808
  \`\`\``;
@@ -85789,6 +85799,9 @@ function isInjectableNativeAction(action) {
85789
85799
  return true;
85790
85800
  return action === NATIVE_WAITING_ACTION;
85791
85801
  }
85802
+ function shouldEmitNativeWaitingOnTurnEnd(lastStatus) {
85803
+ return lastStatus !== "task.acknowledged" && lastStatus !== "task.inProgress";
85804
+ }
85792
85805
  function isNativeIdleAfterTaskComplete(participant) {
85793
85806
  return participant.lastSeenAction === NATIVE_TASK_INJECTED_ACTION && participant.lastStatus === "task.completed";
85794
85807
  }
@@ -85858,13 +85871,21 @@ function shouldDeliverNativeTask(task, opts) {
85858
85871
  return isInjectableNativeAction(task.participant?.lastSeenAction) || isNativeIdleAfterTaskComplete(task.participant ?? {}) || isNativeAcknowledgedInjectionRetry(task);
85859
85872
  }
85860
85873
  function buildNativeInjectionPrompt(params) {
85861
- const { taskDeliveryOutput, compressMode } = params;
85862
- if (compressMode === "new_session") {
85874
+ const { taskDeliveryOutput, augmentationMode } = params;
85875
+ if (augmentationMode === "compact") {
85863
85876
  return [
85864
85877
  "⚠️ Context was compacted. Run `chatroom get-system-prompt` only if role instructions are missing.",
85865
85878
  "",
85866
85879
  taskDeliveryOutput
85867
85880
  ].join(`
85881
+ `);
85882
+ }
85883
+ if (augmentationMode === "new_session") {
85884
+ return [
85885
+ "⚠️ Starting a new agent session. Run `chatroom get-system-prompt` to reload role instructions if needed.",
85886
+ "",
85887
+ taskDeliveryOutput
85888
+ ].join(`
85868
85889
  `);
85869
85890
  }
85870
85891
  return taskDeliveryOutput;
@@ -85874,18 +85895,23 @@ var init_native_task_injector_logic = __esm(() => {
85874
85895
  init_native_integration();
85875
85896
  });
85876
85897
 
85877
- // ../../services/backend/src/domain/handoff/parse-compress-context.ts
85898
+ // ../../services/backend/src/domain/entities/team-agent-settings.ts
85899
+ function roleSupportsSessionAugmentation(role) {
85900
+ const normalized = role.toLowerCase();
85901
+ return SESSION_AUGMENTATION_ROLES.some((r) => r === normalized);
85902
+ }
85903
+ var SESSION_AUGMENTATION_ROLES;
85904
+ var init_team_agent_settings = __esm(() => {
85905
+ SESSION_AUGMENTATION_ROLES = ["builder"];
85906
+ });
85907
+
85908
+ // ../../services/backend/src/domain/handoff/parse-session-augmentation.ts
85878
85909
  function findSectionIndex(content, headings) {
85879
85910
  const indices = headings.map((heading) => content.indexOf(heading)).filter((idx) => idx !== -1);
85880
85911
  return indices.length === 0 ? -1 : Math.min(...indices);
85881
85912
  }
85882
85913
  function normalizeMode(raw) {
85883
- const value = raw.toLowerCase();
85884
- if (value === "reset")
85885
- return "new_session";
85886
- if (value === "none")
85887
- return value;
85888
- return DEFAULT_MODE;
85914
+ return MODE_ALIASES[raw.toLowerCase()] ?? DEFAULT_MODE;
85889
85915
  }
85890
85916
  function extractSectionBody(content, sectionIdx) {
85891
85917
  const matchedHeading = SECTION_HEADINGS.find((h) => content.indexOf(h, sectionIdx) === sectionIdx) ?? SECTION_HEADINGS[0];
@@ -85893,7 +85919,7 @@ function extractSectionBody(content, sectionIdx) {
85893
85919
  const nextHeading = afterSection.slice(matchedHeading.length).search(/\n## /);
85894
85920
  return nextHeading === -1 ? afterSection : afterSection.slice(0, matchedHeading.length + nextHeading);
85895
85921
  }
85896
- function parseCompressContext(handoffContent) {
85922
+ function parseSessionAugmentation(handoffContent) {
85897
85923
  const sectionIdx = findSectionIndex(handoffContent, SECTION_HEADINGS);
85898
85924
  if (sectionIdx === -1)
85899
85925
  return DEFAULT_MODE;
@@ -85902,13 +85928,33 @@ function parseCompressContext(handoffContent) {
85902
85928
  return DEFAULT_MODE;
85903
85929
  return normalizeMode(match17[1]);
85904
85930
  }
85905
- function compressContextToWantResume(mode) {
85906
- return mode === "none";
85931
+ function resolveSessionAugmentationForRole(handoffContent, role) {
85932
+ if (!roleSupportsSessionAugmentation(role)) {
85933
+ return "none";
85934
+ }
85935
+ return parseSessionAugmentation(handoffContent);
85936
+ }
85937
+ function sessionAugmentationToWantResume(mode) {
85938
+ return mode === "none" || mode === "compact";
85939
+ }
85940
+ function sessionAugmentationNewSessionStarted(mode) {
85941
+ return mode === "new_session";
85907
85942
  }
85908
- var SECTION_HEADINGS, DATA_TAG, DEFAULT_MODE = "new_session";
85909
- var init_parse_compress_context = __esm(() => {
85910
- SECTION_HEADINGS = ["## Session Management", "## Restart new context"];
85911
- DATA_TAG = /\/\/\s*data:agent\.compress_context=(new_session|reset|none)\b/i;
85943
+ var SECTION_HEADINGS, DATA_TAG, DEFAULT_MODE = "new_session", MODE_ALIASES;
85944
+ var init_parse_session_augmentation = __esm(() => {
85945
+ init_team_agent_settings();
85946
+ SECTION_HEADINGS = [
85947
+ "## Session Augmentation",
85948
+ "## Session Management",
85949
+ "## Restart new context"
85950
+ ];
85951
+ DATA_TAG = /\/\/\s*data:agent\.(?:session_augmentation|compress_context)=(none|compact|new_session|reset)\b/i;
85952
+ MODE_ALIASES = {
85953
+ reset: "new_session",
85954
+ none: "none",
85955
+ compact: "compact",
85956
+ new_session: "new_session"
85957
+ };
85912
85958
  });
85913
85959
 
85914
85960
  // src/commands/machine/daemon-start/native-task-injector.ts
@@ -85952,9 +85998,10 @@ function runNativeInjectionEffect(task, harnessSessionId, deps, ledger) {
85952
85998
  return yield* exports_Effect.fail(deliveryResult.left);
85953
85999
  }
85954
86000
  const delivery = deliveryResult.right;
86001
+ const augmentationMode = resolveSessionAugmentationForRole(taskContent, role);
85955
86002
  const prompt = buildNativeInjectionPrompt({
85956
86003
  taskDeliveryOutput: delivery.fullCliOutput,
85957
- compressMode: parseCompressContext(taskContent)
86004
+ augmentationMode
85958
86005
  });
85959
86006
  yield* exports_Effect.tryPromise({
85960
86007
  try: () => deps.backend.mutation(api.participants.join, {
@@ -85966,6 +86013,21 @@ function runNativeInjectionEffect(task, harnessSessionId, deps, ledger) {
85966
86013
  }),
85967
86014
  catch: (err) => err
85968
86015
  }).pipe(exports_Effect.tapError(() => exports_Effect.sync(() => ledger.clearDelivery(taskId, harnessSessionId))));
86016
+ if (roleSupportsSessionAugmentation(role)) {
86017
+ yield* exports_Effect.tryPromise({
86018
+ try: () => deps.backend.mutation(api.machines.emitSessionAugmented, {
86019
+ sessionId: deps.sessionId,
86020
+ machineId: deps.machineId,
86021
+ chatroomId,
86022
+ role,
86023
+ taskId,
86024
+ mode: augmentationMode,
86025
+ newSessionStarted: sessionAugmentationNewSessionStarted(augmentationMode),
86026
+ harnessSessionId
86027
+ }),
86028
+ catch: (err) => err
86029
+ }).pipe(exports_Effect.catchAll(() => exports_Effect.void));
86030
+ }
85969
86031
  const resumeResult = yield* exports_Effect.tryPromise({
85970
86032
  try: () => deps.agentMgr.resumeTurnForSlot({ chatroomId, role, prompt }),
85971
86033
  catch: (err) => err
@@ -85980,7 +86042,8 @@ function runNativeInjectionEffect(task, harnessSessionId, deps, ledger) {
85980
86042
  }
85981
86043
  var init_native_task_injector = __esm(() => {
85982
86044
  init_participant();
85983
- init_parse_compress_context();
86045
+ init_team_agent_settings();
86046
+ init_parse_session_augmentation();
85984
86047
  init_esm();
85985
86048
  init_native_task_injector_logic();
85986
86049
  init_api3();
@@ -86024,6 +86087,7 @@ class NativeTaskDeliveryCoordinator {
86024
86087
  return;
86025
86088
  yield* runNativeInjectionEffect(full, harnessSessionId, {
86026
86089
  sessionId: sessionDeps.sessionId,
86090
+ machineId: sessionDeps.machineId,
86027
86091
  backend: sessionDeps.backend,
86028
86092
  agentMgr: {
86029
86093
  resumeTurnForSlot: (args2) => exports_Effect.runPromise(agentMgr.resumeTurnForSlot(args2))
@@ -86221,24 +86285,12 @@ var init_agent_lifecycle = __esm(() => {
86221
86285
  init_restart_decision();
86222
86286
  });
86223
86287
 
86224
- // src/domain/agent-lifecycle/policies/cursor-sdk-run-error.ts
86225
- function isCursorSdkRunErrorInLogs(logLines) {
86226
- return logLines.some((line) => line.includes(" run-error]"));
86227
- }
86228
- function formatCursorSdkRunErrorMessage(logLines) {
86229
- const line = [...logLines].reverse().find((l) => l.includes(" run-error]"));
86230
- return line?.trim() ?? "Cursor SDK run failed";
86231
- }
86232
-
86233
86288
  // src/commands/machine/daemon-start/native-harness-session-exit.ts
86234
86289
  function isNativeHarnessSessionDiscardedOnExit(ctx) {
86235
- const { harness, harnessSessionId, stopReason, recentLogLines, supportsDaemonMemoryResume } = ctx;
86290
+ const { harness, harnessSessionId, stopReason, supportsDaemonMemoryResume } = ctx;
86236
86291
  if (!harness || !harnessSessionId) {
86237
86292
  return false;
86238
86293
  }
86239
- if (isCursorSdkRunErrorInLogs(recentLogLines ?? [])) {
86240
- return true;
86241
- }
86242
86294
  if (!supportsDaemonMemoryResume) {
86243
86295
  return true;
86244
86296
  }
@@ -86377,8 +86429,17 @@ function appendRecentLogLine(slot, line) {
86377
86429
  }
86378
86430
  var RECENT_LOG_LINE_CAP2 = 100;
86379
86431
 
86432
+ // src/domain/agent-lifecycle/policies/cursor-sdk-run-error.ts
86433
+ function isCursorSdkRunErrorInLogs(logLines) {
86434
+ return logLines.some((line) => line.includes(" run-error]"));
86435
+ }
86436
+ function formatCursorSdkRunErrorMessage(logLines) {
86437
+ const line = [...logLines].reverse().find((l) => l.includes(" run-error]"));
86438
+ return line?.trim() ?? "Cursor SDK run failed";
86439
+ }
86440
+
86380
86441
  // src/domain/agent-lifecycle/policies/cursor-sdk-session-reopen-retry.ts
86381
- var CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS = 20, CURSOR_SDK_SESSION_REOPEN_INTERVAL_MS = 5000, CURSOR_SDK_SESSION_REOPEN_REASON = "platform.cursor_sdk_session_reopen";
86442
+ var CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS = 20, CURSOR_SDK_SESSION_REOPEN_INTERVAL_MS = 5000, CURSOR_SDK_SESSION_REOPEN_REASON = "platform.cursor_sdk_session_reopen", CURSOR_SDK_SESSION_RESUME_FIRST_ATTEMPTS = 3;
86382
86443
 
86383
86444
  // src/domain/agent-lifecycle/use-cases/handle-turn-completed.ts
86384
86445
  async function handleTurnCompleted(deps, input, slot) {
@@ -86988,8 +87049,10 @@ class AgentProcessManager {
86988
87049
  console.log(`[AgentProcessManager] ⛔ Terminal provider error for ${opts.role} — emitted agent.startFailed`);
86989
87050
  return;
86990
87051
  }
86991
- await this.emitNativeWaiting(opts.chatroomId, opts.role, opts.harness);
86992
- console.log(`[AgentProcessManager] ✅ Native harness idle for ${opts.role} (native:waiting)`);
87052
+ const emitted = await this.emitNativeWaiting(opts.chatroomId, opts.role, opts.harness, "turn-end");
87053
+ if (emitted) {
87054
+ console.log(`[AgentProcessManager] ✅ Native harness idle for ${opts.role} (native:waiting)`);
87055
+ }
86993
87056
  }
86994
87057
  async handleExit(opts) {
86995
87058
  const key = agentKey3(opts.chatroomId, opts.role);
@@ -87051,14 +87114,10 @@ class AgentProcessManager {
87051
87114
  });
87052
87115
  }
87053
87116
  async preserveHarnessSessionOnExit(key, slot, ctx) {
87054
- const { harness, harnessSessionId, stopReason, recentLogLines } = ctx;
87117
+ const { harness, harnessSessionId, stopReason } = ctx;
87055
87118
  if (!harness || !harnessSessionId) {
87056
87119
  return;
87057
87120
  }
87058
- if (isCursorSdkRunErrorInLogs(recentLogLines ?? [])) {
87059
- this.clearLastHarnessSession(key);
87060
- return;
87061
- }
87062
87121
  const service3 = this.deps.agentServices.get(harness);
87063
87122
  if (!service3?.resumeFromDaemonMemory) {
87064
87123
  return;
@@ -87108,17 +87167,15 @@ class AgentProcessManager {
87108
87167
  }
87109
87168
  this.maybeRestartAgent(opts, ctx);
87110
87169
  }
87111
- clearHarnessSessionAfterRunError(key, recentLogLines) {
87170
+ hasCursorSdkRunErrorInContext(recentLogLines) {
87112
87171
  if (!isCursorSdkRunErrorInLogs(recentLogLines)) {
87113
87172
  return false;
87114
87173
  }
87115
- console.log(`[AgentProcessManager] cursor-sdk run-error — cold restarting ${key}: ${formatCursorSdkRunErrorMessage(recentLogLines)}`);
87116
- this.clearLastHarnessSession(key);
87174
+ console.log(`[AgentProcessManager] cursor-sdk run-error detected: ${formatCursorSdkRunErrorMessage(recentLogLines)}`);
87117
87175
  return true;
87118
87176
  }
87119
87177
  maybeRestartAgent(opts, ctx) {
87120
87178
  const { harness, model, workingDir, recentLogLines } = ctx;
87121
- const key = agentKey3(opts.chatroomId, opts.role);
87122
87179
  const logs = recentLogLines ?? [];
87123
87180
  if (!harness || !workingDir) {
87124
87181
  console.log(`[AgentProcessManager] ⚠️ Cannot restart — missing harness or workingDir ` + `(role: ${opts.role}, harness: ${harness ?? "none"}, workingDir: ${workingDir ?? "none"})`);
@@ -87128,9 +87185,9 @@ class AgentProcessManager {
87128
87185
  this.handlePermanentFailureForRestart(opts, recentLogLines, ctx.terminalProviderFailureHandled);
87129
87186
  return;
87130
87187
  }
87131
- const coldRestartAfterRunError = this.clearHarnessSessionAfterRunError(key, logs);
87188
+ const hadRunError = this.hasCursorSdkRunErrorInContext(logs);
87132
87189
  if (harness === "cursor-sdk") {
87133
- this.retryCursorSdkSessionReopen(opts, ctx, coldRestartAfterRunError);
87190
+ this.retryCursorSdkSessionReopen(opts, ctx, hadRunError);
87134
87191
  return;
87135
87192
  }
87136
87193
  this.ensureRunning({
@@ -87140,7 +87197,7 @@ class AgentProcessManager {
87140
87197
  model,
87141
87198
  workingDir,
87142
87199
  reason: "platform.crash_recovery",
87143
- wantResume: coldRestartAfterRunError ? false : ctx.wantResume ?? true
87200
+ wantResume: hadRunError ? false : ctx.wantResume ?? true
87144
87201
  }).then((result) => {
87145
87202
  if (!result.success) {
87146
87203
  console.log(`[AgentProcessManager] ⚠️ Agent restart did not complete for ${opts.role}: ${result.error ?? "unknown"}`);
@@ -87150,7 +87207,27 @@ class AgentProcessManager {
87150
87207
  this.emitStartFailedEvent(opts.role, opts.chatroomId, err.message);
87151
87208
  });
87152
87209
  }
87153
- async retryCursorSdkSessionReopen(opts, ctx, coldRestartAfterRunError) {
87210
+ clearHarnessSessionAfterResumePhaseFailure(key, opts) {
87211
+ const stored = this.lastHarnessSessions.get(key);
87212
+ this.clearLastHarnessSession(key);
87213
+ if (stored?.harnessSessionId) {
87214
+ notifyNativeSessionLost({
87215
+ chatroomId: opts.chatroomId,
87216
+ role: opts.role,
87217
+ harnessSessionId: stored.harnessSessionId
87218
+ });
87219
+ }
87220
+ }
87221
+ resolveCursorSdkReopenWantResume(hadRunError, attempt, ctx) {
87222
+ if (hadRunError && attempt <= CURSOR_SDK_SESSION_RESUME_FIRST_ATTEMPTS) {
87223
+ return true;
87224
+ }
87225
+ if (hadRunError) {
87226
+ return false;
87227
+ }
87228
+ return ctx.wantResume ?? true;
87229
+ }
87230
+ async retryCursorSdkSessionReopen(opts, ctx, hadRunError) {
87154
87231
  const key = agentKey3(opts.chatroomId, opts.role);
87155
87232
  if (this.sessionReopenRetryInFlight.has(key)) {
87156
87233
  return;
@@ -87159,11 +87236,14 @@ class AgentProcessManager {
87159
87236
  const harness = ctx.harness;
87160
87237
  const model = ctx.model;
87161
87238
  const workingDir = ctx.workingDir;
87162
- const wantResume = coldRestartAfterRunError ? false : ctx.wantResume ?? true;
87163
- const storedSessionId = this.lastHarnessSessions.get(key)?.harnessSessionId;
87164
87239
  let lastError = "unknown";
87165
87240
  try {
87166
87241
  for (let attempt = 1;attempt <= CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS; attempt++) {
87242
+ if (hadRunError && attempt === CURSOR_SDK_SESSION_RESUME_FIRST_ATTEMPTS + 1) {
87243
+ this.clearHarnessSessionAfterResumePhaseFailure(key, opts);
87244
+ }
87245
+ const wantResume = this.resolveCursorSdkReopenWantResume(hadRunError, attempt, ctx);
87246
+ const storedSessionId = this.lastHarnessSessions.get(key)?.harnessSessionId;
87167
87247
  await this.emitSessionReopenRetry(opts.chatroomId, opts.role, attempt, attempt > 1 ? lastError : undefined, storedSessionId);
87168
87248
  const result = await this.ensureRunning({
87169
87249
  chatroomId: opts.chatroomId,
@@ -87345,13 +87425,6 @@ class AgentProcessManager {
87345
87425
  try {
87346
87426
  await this.killExistingBeforeSpawn(opts.chatroomId, opts.role);
87347
87427
  const result = await this.doEnsureRunning(key, slot, opts);
87348
- if (!result.success && opts.reason === "platform.auto_restart_on_new_context") {
87349
- console.log(`[AgentProcessManager] Context auto-restart failed (${result.error ?? "unknown"}), ` + `attempting crash recovery (rate-limited)`);
87350
- return await this.doEnsureRunning(key, slot, {
87351
- ...opts,
87352
- reason: "platform.crash_recovery"
87353
- });
87354
- }
87355
87428
  return result;
87356
87429
  } finally {
87357
87430
  if (slot.pendingOperation) {
@@ -87744,9 +87817,25 @@ class AgentProcessManager {
87744
87817
  this.registerSpawnCallbacks(slot, opts, spawnResult, pid);
87745
87818
  await this.emitNativeWaiting(opts.chatroomId, opts.role, opts.agentHarness);
87746
87819
  }
87747
- async emitNativeWaiting(chatroomId, role, harness) {
87820
+ async emitNativeWaiting(chatroomId, role, harness, reason = "spawn") {
87748
87821
  if (!getHarnessCapabilities(harness).supportsNativeIntegration)
87749
- return;
87822
+ return false;
87823
+ if (reason === "turn-end") {
87824
+ try {
87825
+ const participant = await this.deps.backend.query(api.participants.getByRole, {
87826
+ sessionId: this.deps.sessionId,
87827
+ chatroomId,
87828
+ role
87829
+ });
87830
+ if (!shouldEmitNativeWaitingOnTurnEnd(participant?.lastStatus)) {
87831
+ console.log(`[AgentProcessManager] Skipping native:waiting for ${role} — active work (${participant?.lastStatus})`);
87832
+ return false;
87833
+ }
87834
+ } catch (err) {
87835
+ console.log(` ⚠️ Failed to check status before native:waiting for ${role}: ${err.message}`);
87836
+ return false;
87837
+ }
87838
+ }
87750
87839
  try {
87751
87840
  await this.deps.backend.mutation(api.participants.join, {
87752
87841
  sessionId: this.deps.sessionId,
@@ -87754,8 +87843,10 @@ class AgentProcessManager {
87754
87843
  role,
87755
87844
  action: NATIVE_WAITING_ACTION
87756
87845
  });
87846
+ return true;
87757
87847
  } catch (err) {
87758
87848
  console.log(` ⚠️ Failed to emit native:waiting for ${role}: ${err.message}`);
87849
+ return false;
87759
87850
  }
87760
87851
  }
87761
87852
  async doEnsureRunning(key, slot, opts) {
@@ -87909,11 +88000,13 @@ var init_agent_process_manager = __esm(() => {
87909
88000
  init_api3();
87910
88001
  init_orphan_tracker();
87911
88002
  init_native_harness_session_exit();
88003
+ init_native_task_delivery_coordinator();
87912
88004
  init_agent_lifecycle();
87913
88005
  init_abort_resume_storm();
87914
88006
  init_classify_resume_storm_reason();
87915
88007
  init_terminal_provider_error();
87916
88008
  init_handle_turn_completed();
88009
+ init_predicates();
87917
88010
  init_spawn_policy();
87918
88011
  init_agent_lifecycle_runtime();
87919
88012
  init_agent_lifecycle_types();
@@ -87927,7 +88020,7 @@ class SpawnRateLimiter {
87927
88020
  this.config = { ...DEFAULT_CONFIG2, ...config3 };
87928
88021
  }
87929
88022
  tryConsume(chatroomId, reason) {
87930
- if (reason.startsWith("user.") || reason === "platform.auto_restart_on_new_context" || reason === "platform.cursor_sdk_session_reopen") {
88023
+ if (reason.startsWith("user.") || reason === "platform.cursor_sdk_session_reopen") {
87931
88024
  return { allowed: true };
87932
88025
  }
87933
88026
  const bucket = this._getOrCreateBucket(chatroomId);
@@ -88866,6 +88959,9 @@ class WorkingSnapshot {
88866
88959
  getByKey(key) {
88867
88960
  return this.rows.get(key);
88868
88961
  }
88962
+ upsertRow(row) {
88963
+ this.rows.set(this.opts.rowKey(row), row);
88964
+ }
88869
88965
  getBySignal(signal) {
88870
88966
  return this.rows.get(this.opts.signalKey(signal));
88871
88967
  }
@@ -88903,8 +88999,32 @@ function mergeSignalIntoTaskSnapshot(existing, signal) {
88903
88999
  }
88904
89000
  };
88905
89001
  }
89002
+ function mergePresenceIntoTaskSnapshot(existing, presence) {
89003
+ if (!existing) {
89004
+ return;
89005
+ }
89006
+ return {
89007
+ ...existing,
89008
+ participant: {
89009
+ lastSeenAction: presence.lastSeenAction ?? existing.participant?.lastSeenAction ?? null,
89010
+ lastSeenAt: presence.lastSeenAt,
89011
+ lastStatus: existing.participant?.lastStatus ?? null
89012
+ }
89013
+ };
89014
+ }
88906
89015
  function createTaskMonitorSnapshot() {
88907
- return new WorkingSnapshot(taskMonitorSnapshotOptions);
89016
+ const base = new WorkingSnapshot(taskMonitorSnapshotOptions);
89017
+ return Object.assign(base, {
89018
+ mergePresence(presence) {
89019
+ const key = taskSnapshotKey(presence.taskId, presence.role);
89020
+ const existing = base.getByKey(key);
89021
+ const merged = mergePresenceIntoTaskSnapshot(existing, presence);
89022
+ if (merged) {
89023
+ base.upsertRow(merged);
89024
+ }
89025
+ return merged;
89026
+ }
89027
+ });
88908
89028
  }
88909
89029
  var taskMonitorSnapshotOptions;
88910
89030
  var init_task_monitor_snapshot = __esm(() => {
@@ -89154,106 +89274,46 @@ var runIncrementalSubscribeLive = (opts) => exports_Effect.gen(function* () {
89154
89274
  yield* exports_Fiber.interrupt(workerFiber);
89155
89275
  })
89156
89276
  };
89157
- }), runReconcilePoll = (opts) => exports_Effect.gen(function* () {
89158
- const clock4 = yield* IntervalClock;
89159
- const backoffCfg = opts.backoff ?? { initialMs: 1000, maxMs: 30000 };
89160
- let backoffMs = opts.intervalMs;
89161
- let stopped = false;
89162
- const loopFiber = yield* exports_Effect.forkDaemon(exports_Effect.gen(function* () {
89163
- while (!stopped) {
89164
- const pollOutcome = yield* exports_Effect.either(exports_Effect.tryPromise(() => opts.poll(opts.args)));
89165
- if (pollOutcome._tag === "Left") {
89166
- backoffMs = Math.min(backoffMs === opts.intervalMs ? backoffCfg.initialMs : backoffMs * 2, backoffCfg.maxMs);
89167
- yield* clock4.sleep(backoffMs);
89168
- continue;
89169
- }
89170
- yield* opts.onResult(pollOutcome.right);
89171
- backoffMs = opts.intervalMs;
89172
- yield* clock4.sleep(opts.intervalMs);
89173
- }
89174
- }));
89175
- return {
89176
- stop: () => exports_Effect.gen(function* () {
89177
- stopped = true;
89178
- yield* exports_Fiber.interrupt(loopFiber);
89179
- })
89180
- };
89181
- }), runReconcilePollLive = (opts) => runReconcilePoll(opts).pipe(exports_Effect.provide(IntervalClockLive));
89277
+ });
89182
89278
  var init_feed_runtime = __esm(() => {
89183
89279
  init_esm();
89184
89280
  init_layers();
89185
89281
  init_subscribe_loop();
89186
89282
  });
89187
89283
 
89188
- // src/infrastructure/incremental-sync/dual-channel-feed.ts
89189
- var runDualChannelFeedLive = (opts) => exports_Effect.gen(function* () {
89190
- const initial = yield* exports_Effect.tryPromise(() => opts.fetchReconcile()).pipe(exports_Effect.orElseSucceed(() => null));
89191
- if (initial !== null) {
89192
- const rows = opts.extractReconcileRows(initial);
89193
- opts.snapshot.replaceAll(rows);
89194
- if (rows.length > 0) {
89195
- yield* opts.onReconcileRows(rows).pipe(exports_Effect.catchAll(() => exports_Effect.void));
89196
- }
89197
- }
89198
- const seedKey = yield* exports_Effect.tryPromise(() => opts.seedCursor()).pipe(exports_Effect.orElseSucceed(() => null));
89199
- const hydrateFromReconcile = async () => {
89200
- const result = await opts.fetchReconcile();
89201
- opts.snapshot.replaceAll(opts.extractReconcileRows(result));
89284
+ // src/infrastructure/incremental-sync/feeds/assigned-task-presence.ts
89285
+ var assignedTaskPresenceFeedDef, assignedTaskPresenceSubscribeTarget, ASSIGNED_TASK_PRESENCE_FEED_LIMIT = 50, ASSIGNED_TASK_PRESENCE_FEED_BUFFER;
89286
+ var init_assigned_task_presence = __esm(() => {
89287
+ init_api3();
89288
+ assignedTaskPresenceFeedDef = {
89289
+ name: "assigned-task-presence",
89290
+ itemKey: (item) => `${item.presenceUpdatedAt}:${item.taskId}:${item.role}`
89202
89291
  };
89203
- const resolveRowForSignal = async (signal) => {
89204
- const merged = opts.snapshot.mergeSignal(signal);
89205
- if (merged) {
89206
- return merged;
89292
+ assignedTaskPresenceSubscribeTarget = {
89293
+ query: api.machines.subscribeAssignedTaskPresenceSince,
89294
+ buildArgs: (args2, afterKey, limit) => ({
89295
+ sessionId: args2.sessionId,
89296
+ machineId: args2.machineId,
89297
+ afterPresenceKey: afterKey ?? undefined,
89298
+ limit
89299
+ }),
89300
+ parsePage: (result) => {
89301
+ const page = result;
89302
+ return {
89303
+ items: page.items,
89304
+ highKey: page.highPresenceKey,
89305
+ hasMore: page.hasMore
89306
+ };
89207
89307
  }
89208
- await hydrateFromReconcile();
89209
- return opts.snapshot.mergeSignal(signal) ?? opts.snapshot.getBySignal(signal);
89210
89308
  };
89211
- const signalHandle = yield* runIncrementalSubscribeLive({
89212
- wsClient: opts.wsClient,
89213
- def: opts.def,
89214
- target: opts.target,
89215
- args: opts.args,
89216
- buffer: opts.buffer,
89217
- subscribe: opts.subscribe,
89218
- initialAfterKey: seedKey,
89219
- onError: opts.onSubscribeError,
89220
- onItem: ({ item: signal, ack }) => exports_Effect.gen(function* () {
89221
- ack();
89222
- if (opts.isStopped()) {
89223
- return;
89224
- }
89225
- const row = yield* exports_Effect.tryPromise(() => resolveRowForSignal(signal));
89226
- if (!row) {
89227
- return;
89228
- }
89229
- yield* opts.onSignalRow(row).pipe(exports_Effect.catchAll(() => exports_Effect.void));
89230
- })
89231
- });
89232
- const reconcileHandle = yield* runReconcilePollLive({
89233
- name: `${opts.name}-reconcile`,
89234
- poll: () => opts.fetchReconcile(),
89235
- args: undefined,
89236
- intervalMs: opts.reconcileIntervalMs,
89237
- onResult: (result) => exports_Effect.gen(function* () {
89238
- const rows = opts.extractReconcileRows(result);
89239
- opts.snapshot.replaceAll(rows);
89240
- yield* opts.onReconcileRows(rows).pipe(exports_Effect.catchAll(() => exports_Effect.void));
89241
- })
89242
- });
89243
- return {
89244
- stop: () => exports_Effect.gen(function* () {
89245
- yield* signalHandle.stop();
89246
- yield* reconcileHandle.stop();
89247
- })
89309
+ ASSIGNED_TASK_PRESENCE_FEED_BUFFER = {
89310
+ maxSize: 200,
89311
+ dedupe: true
89248
89312
  };
89249
89313
  });
89250
- var init_dual_channel_feed = __esm(() => {
89251
- init_esm();
89252
- init_feed_runtime();
89253
- });
89254
89314
 
89255
89315
  // src/infrastructure/incremental-sync/feeds/assigned-task-signals.ts
89256
- var assignedTaskSignalsFeedDef, assignedTaskSignalsSubscribeTarget, ASSIGNED_TASK_SIGNAL_FEED_LIMIT = 50, ASSIGNED_TASK_SIGNAL_FEED_BUFFER, ASSIGNED_TASK_RECONCILE_INTERVAL_MS = 15000;
89316
+ var assignedTaskSignalsFeedDef, assignedTaskSignalsSubscribeTarget, ASSIGNED_TASK_SIGNAL_FEED_LIMIT = 50, ASSIGNED_TASK_SIGNAL_FEED_BUFFER;
89257
89317
  var init_assigned_task_signals = __esm(() => {
89258
89318
  init_api3();
89259
89319
  assignedTaskSignalsFeedDef = {
@@ -89277,16 +89337,32 @@ var init_assigned_task_signals = __esm(() => {
89277
89337
  });
89278
89338
 
89279
89339
  // src/commands/machine/daemon-start/task-monitor.ts
89340
+ async function seedSignalCursor(session2) {
89341
+ const seedPage = await session2.backend.query(api.machines.subscribeAssignedTaskSignalsSince, {
89342
+ sessionId: session2.sessionId,
89343
+ machineId: session2.machineId,
89344
+ limit: ASSIGNED_TASK_SIGNAL_FEED_LIMIT
89345
+ });
89346
+ return seedPage?.highKey ?? null;
89347
+ }
89348
+ async function seedPresenceCursor(session2) {
89349
+ const seedPage = await session2.backend.query(api.machines.subscribeAssignedTaskPresenceSince, {
89350
+ sessionId: session2.sessionId,
89351
+ machineId: session2.machineId,
89352
+ limit: ASSIGNED_TASK_PRESENCE_FEED_LIMIT
89353
+ });
89354
+ return seedPage?.highPresenceKey ?? null;
89355
+ }
89280
89356
  function resolveTaskWantResume(task) {
89281
- return compressContextToWantResume(parseCompressContext(task.taskContent ?? ""));
89357
+ return sessionAugmentationToWantResume(resolveSessionAugmentationForRole(task.taskContent ?? "", task.agentConfig.role));
89282
89358
  }
89283
89359
  function buildCliNudgeLogLine(task) {
89284
89360
  const { chatroomId, agentConfig } = task;
89285
89361
  const { role } = agentConfig;
89286
89362
  const lastSeenAction = task.participant?.lastSeenAction ?? "unknown";
89287
- const compressMode = parseCompressContext(task.taskContent ?? "");
89363
+ const augmentationMode = resolveSessionAugmentationForRole(task.taskContent ?? "", role);
89288
89364
  const wantResume = resolveTaskWantResume(task);
89289
- return `[TaskMonitor] nudging ${role}@${chatroomId} — pending task ${task.taskId}, lastSeenAction=${lastSeenAction}, compress_context=${compressMode}, wantResume=${wantResume}`;
89365
+ return `[TaskMonitor] nudging ${role}@${chatroomId} — pending task ${task.taskId}, lastSeenAction=${lastSeenAction}, session_augmentation=${augmentationMode}, wantResume=${wantResume}`;
89290
89366
  }
89291
89367
  function resolveTaskRunnerContextFromFull(task) {
89292
89368
  const { chatroomId, agentConfig } = task;
@@ -89302,11 +89378,12 @@ function resolveTaskRunnerContextFromFull(task) {
89302
89378
  wantResume: resolveTaskWantResume(task)
89303
89379
  };
89304
89380
  }
89305
- function executeCliNudge(task, runtime4, effectContext2, agentMgr) {
89381
+ function executeCliNudge(task, runtime4, effectContext2, agentMgr, sessionDeps, machineId) {
89306
89382
  const ctx = resolveTaskRunnerContextFromFull(task);
89307
89383
  if (!ctx)
89308
89384
  return;
89309
89385
  const { chatroomId, agentConfig, role, workingDir, wantResume } = ctx;
89386
+ const augmentationMode = resolveSessionAugmentationForRole(task.taskContent ?? "", role);
89310
89387
  exports_Runtime.runFork(runtime4)(exports_Effect.gen(function* () {
89311
89388
  yield* agentMgr.stop({ chatroomId, role, reason: "platform.task_monitor_nudge" });
89312
89389
  yield* agentMgr.ensureRunning({
@@ -89318,6 +89395,20 @@ function executeCliNudge(task, runtime4, effectContext2, agentMgr) {
89318
89395
  reason: "platform.task_monitor_nudge",
89319
89396
  wantResume
89320
89397
  });
89398
+ if (roleSupportsSessionAugmentation(role)) {
89399
+ yield* exports_Effect.tryPromise({
89400
+ try: () => sessionDeps.backend.mutation(api.machines.emitSessionAugmented, {
89401
+ sessionId: sessionDeps.sessionId,
89402
+ machineId,
89403
+ chatroomId,
89404
+ role,
89405
+ taskId: task.taskId,
89406
+ mode: augmentationMode,
89407
+ newSessionStarted: sessionAugmentationNewSessionStarted(augmentationMode)
89408
+ }),
89409
+ catch: (err) => err
89410
+ }).pipe(exports_Effect.catchAll(() => exports_Effect.void));
89411
+ }
89321
89412
  }).pipe(exports_Effect.provide(effectContext2), exports_Effect.catchAll((err) => exports_Effect.sync(() => console.warn(`[TaskMonitor] nudge failed for ${role}@${chatroomId}: ${getErrorMessage(err)}`)))));
89322
89413
  }
89323
89414
  function runNativeReviveEffect(task, runtime4, effectContext2, agentMgr) {
@@ -89347,16 +89438,16 @@ async function fetchTaskForAction(sessionDeps, machineId, snapshotRow) {
89347
89438
  });
89348
89439
  return result;
89349
89440
  }
89350
- function runCliNudgeEffect(task, runtime4, effectContext2, agentMgr) {
89441
+ function runCliNudgeEffect(task, runtime4, effectContext2, agentMgr, sessionDeps, machineId) {
89351
89442
  console.log(buildCliNudgeLogLine(task));
89352
- executeCliNudge(task, runtime4, effectContext2, agentMgr);
89443
+ executeCliNudge(task, runtime4, effectContext2, agentMgr, sessionDeps, machineId);
89353
89444
  }
89354
89445
  async function nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId) {
89355
89446
  for (const row of listTasksReadyForNudge(tasks, now, cooldown)) {
89356
89447
  const full = await fetchTaskForAction(sessionDeps, machineId, row);
89357
89448
  if (!full)
89358
89449
  continue;
89359
- runCliNudgeEffect(full, runtime4, effectContext2, agentMgr);
89450
+ runCliNudgeEffect(full, runtime4, effectContext2, agentMgr, sessionDeps, machineId);
89360
89451
  }
89361
89452
  }
89362
89453
  async function reviveNativeTasks(tasks, localHealth, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId) {
@@ -89384,7 +89475,7 @@ async function processTasksUpdate(tasks, runtime4, effectContext2, cooldown, age
89384
89475
  sessionDeps,
89385
89476
  machineId
89386
89477
  });
89387
- if (pass === "reconcile") {
89478
+ if (pass === "presence") {
89388
89479
  await nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId);
89389
89480
  }
89390
89481
  }
@@ -89415,12 +89506,22 @@ var startTaskMonitorEffect = (wsClient2) => exports_Effect.gen(function* () {
89415
89506
  monitorPassInFlight = false;
89416
89507
  });
89417
89508
  };
89418
- const queryReconcileSnapshots = () => session2.backend.query(api.machines.listAssignedTasksForReconcile, {
89509
+ yield* exports_Effect.tryPromise(() => session2.backend.mutation(api.machines.syncMachineAssignedTaskSnapshotsMutation, {
89419
89510
  sessionId: session2.sessionId,
89420
89511
  machineId: session2.machineId
89421
- });
89422
- const feedHandle = yield* runDualChannelFeedLive({
89423
- name: "assigned-tasks",
89512
+ })).pipe(exports_Effect.catchAll(() => exports_Effect.void));
89513
+ const hydrate = yield* exports_Effect.tryPromise(() => session2.backend.query(api.machines.listMachineAssignedTaskSnapshots, {
89514
+ sessionId: session2.sessionId,
89515
+ machineId: session2.machineId
89516
+ })).pipe(exports_Effect.orElseSucceed(() => ({ tasks: [] })));
89517
+ const hydrateTasks = hydrate.tasks ?? [];
89518
+ snapshot.replaceAll(hydrateTasks);
89519
+ if (hydrateTasks.length > 0) {
89520
+ yield* exports_Effect.tryPromise(() => processTasksUpdate(hydrateTasks, runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, "presence")).pipe(exports_Effect.catchAll(() => exports_Effect.void));
89521
+ }
89522
+ const signalSeedKey = yield* exports_Effect.tryPromise(() => seedSignalCursor(session2)).pipe(exports_Effect.orElseSucceed(() => null));
89523
+ const presenceSeedKey = yield* exports_Effect.tryPromise(() => seedPresenceCursor(session2)).pipe(exports_Effect.orElseSucceed(() => null));
89524
+ const signalHandle = yield* runIncrementalSubscribeLive({
89424
89525
  wsClient: wsClient2,
89425
89526
  def: assignedTaskSignalsFeedDef,
89426
89527
  target: assignedTaskSignalsSubscribeTarget,
@@ -89430,44 +89531,64 @@ var startTaskMonitorEffect = (wsClient2) => exports_Effect.gen(function* () {
89430
89531
  },
89431
89532
  buffer: ASSIGNED_TASK_SIGNAL_FEED_BUFFER,
89432
89533
  subscribe: { limit: ASSIGNED_TASK_SIGNAL_FEED_LIMIT },
89433
- snapshot,
89434
- seedCursor: async () => {
89435
- const seedPage = await session2.backend.query(api.machines.subscribeAssignedTaskSignalsSince, {
89436
- sessionId: session2.sessionId,
89437
- machineId: session2.machineId,
89438
- limit: ASSIGNED_TASK_SIGNAL_FEED_LIMIT
89534
+ initialAfterKey: signalSeedKey,
89535
+ onError: (err) => console.warn(`[${formatTimestamp()}] ⚠️ Task signal subscription error: ${getErrorMessage(err)}`),
89536
+ onItem: ({ item: signal, ack }) => exports_Effect.gen(function* () {
89537
+ ack();
89538
+ if (stopped)
89539
+ return;
89540
+ const row = snapshot.mergeSignal(signal);
89541
+ if (!row)
89542
+ return;
89543
+ yield* exports_Effect.sync(() => {
89544
+ runMonitorPass([row], "signal");
89545
+ });
89546
+ })
89547
+ });
89548
+ const presenceHandle = yield* runIncrementalSubscribeLive({
89549
+ wsClient: wsClient2,
89550
+ def: assignedTaskPresenceFeedDef,
89551
+ target: assignedTaskPresenceSubscribeTarget,
89552
+ args: {
89553
+ sessionId: session2.sessionId,
89554
+ machineId: session2.machineId
89555
+ },
89556
+ buffer: ASSIGNED_TASK_PRESENCE_FEED_BUFFER,
89557
+ subscribe: { limit: ASSIGNED_TASK_PRESENCE_FEED_LIMIT },
89558
+ initialAfterKey: presenceSeedKey,
89559
+ onError: (err) => console.warn(`[${formatTimestamp()}] ⚠️ Task presence subscription error: ${getErrorMessage(err)}`),
89560
+ onItem: ({ item: presence, ack }) => exports_Effect.gen(function* () {
89561
+ ack();
89562
+ if (stopped)
89563
+ return;
89564
+ const row = snapshot.mergePresence(presence);
89565
+ if (!row)
89566
+ return;
89567
+ yield* exports_Effect.sync(() => {
89568
+ runMonitorPass([row], "presence");
89439
89569
  });
89440
- return seedPage?.highKey ?? null;
89441
- },
89442
- fetchReconcile: () => queryReconcileSnapshots(),
89443
- extractReconcileRows: (result) => result?.tasks ?? [],
89444
- reconcileIntervalMs: ASSIGNED_TASK_RECONCILE_INTERVAL_MS,
89445
- isStopped: () => stopped,
89446
- onSubscribeError: (err) => console.warn(`[${formatTimestamp()}] ⚠️ Task signal subscription error: ${getErrorMessage(err)}`),
89447
- onSignalRow: (row) => exports_Effect.sync(() => {
89448
- runMonitorPass([row], "signal");
89449
- }),
89450
- onReconcileRows: (tasks) => exports_Effect.sync(() => {
89451
- runMonitorPass([...tasks], "reconcile");
89452
89570
  })
89453
89571
  });
89454
89572
  return {
89455
89573
  stop() {
89456
89574
  stopped = true;
89457
- exports_Effect.runPromise(feedHandle.stop());
89575
+ exports_Effect.runPromise(signalHandle.stop());
89576
+ exports_Effect.runPromise(presenceHandle.stop());
89458
89577
  console.log(`[${formatTimestamp()}] \uD83D\uDCCB Task-monitor stopped`);
89459
89578
  }
89460
89579
  };
89461
89580
  });
89462
89581
  var init_task_monitor = __esm(() => {
89463
- init_parse_compress_context();
89582
+ init_team_agent_settings();
89583
+ init_parse_session_augmentation();
89464
89584
  init_esm();
89465
89585
  init_daemon_services();
89466
89586
  init_native_task_delivery_coordinator();
89467
89587
  init_task_monitor_logic();
89468
89588
  init_task_monitor_snapshot();
89469
89589
  init_api3();
89470
- init_dual_channel_feed();
89590
+ init_feed_runtime();
89591
+ init_assigned_task_presence();
89471
89592
  init_assigned_task_signals();
89472
89593
  init_convex_error();
89473
89594
  });
@@ -90975,4 +91096,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
90975
91096
  });
90976
91097
  program2.parse();
90977
91098
 
90978
- //# debugId=00A3989CD8BAD93D64756E2164756E21
91099
+ //# debugId=9DA8A47CE355B57D64756E2164756E21