@ponythewhite/base-context 1.0.12 → 1.0.14

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 (66) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/base-context-runtime/pyproject.toml +1 -1
  3. package/dist/base-context-runtime/uv.lock +1 -1
  4. package/dist/build-info.json +1 -1
  5. package/dist/bundle/amazon-bedrock.js +3 -3
  6. package/dist/bundle/{anthropic-BJVPUMPB.js → anthropic-AXUXEET7.js} +1 -1
  7. package/dist/bundle/{azure-openai-responses-ERRMAXK6.js → azure-openai-responses-J3NTJKEO.js} +2 -2
  8. package/dist/bundle/{bundled-modules-WCGPZI2H.js → bundled-modules-UODO7ZR7.js} +5 -5
  9. package/dist/bundle/{chunk-FOGKLC7V.js → chunk-72LSQYUV.js} +1 -1
  10. package/dist/bundle/{chunk-MUFZODP5.js → chunk-EGFIZABJ.js} +1 -1
  11. package/dist/bundle/{chunk-AEMRBMI2.js → chunk-IEM74GZ5.js} +9 -9
  12. package/dist/bundle/{chunk-25VYRAC6.js → chunk-JKKXN6JE.js} +72 -0
  13. package/dist/bundle/{chunk-IAKHCQA2.js → chunk-NLRWERWA.js} +37 -32
  14. package/dist/bundle/{chunk-YGV3Y4AD.js → chunk-SX7CAXWU.js} +23 -5
  15. package/dist/bundle/{chunk-Q6UAHLII.js → chunk-V6LOBH6X.js} +2 -2
  16. package/dist/bundle/{cli-main-CTYDQHFE.js → cli-main-6GXXIMQQ.js} +4 -4
  17. package/dist/bundle/cli.js +1 -1
  18. package/dist/bundle/{google-4GA4YMUX.js → google-QLKV2ZLC.js} +2 -2
  19. package/dist/bundle/{google-vertex-7AMALD7D.js → google-vertex-UGLUZV6B.js} +2 -2
  20. package/dist/bundle/{main-GVGK354K.js → main-HF64B4HM.js} +5 -5
  21. package/dist/bundle/{mistral-74BXMNRM.js → mistral-2ITSLHYF.js} +1 -1
  22. package/dist/bundle/{openai-codex-responses-COXNC4IH.js → openai-codex-responses-FRREQXS3.js} +5 -4
  23. package/dist/bundle/{openai-completions-BCSA5Q6S.js → openai-completions-HF6UPPLW.js} +1 -1
  24. package/dist/bundle/{openai-responses-ONCIZSJS.js → openai-responses-LRTMBDFW.js} +2 -2
  25. package/dist/core/agent-session.d.ts.map +1 -1
  26. package/dist/core/agent-session.js +6 -1
  27. package/dist/core/agent-session.js.map +1 -1
  28. package/dist/core/autonomous.d.ts +2 -0
  29. package/dist/core/autonomous.d.ts.map +1 -1
  30. package/dist/core/autonomous.js +4 -0
  31. package/dist/core/autonomous.js.map +1 -1
  32. package/dist/core/canonical-context.d.ts.map +1 -1
  33. package/dist/core/canonical-context.js +7 -0
  34. package/dist/core/canonical-context.js.map +1 -1
  35. package/dist/core/compaction/compaction.d.ts.map +1 -1
  36. package/dist/core/compaction/compaction.js +1 -1
  37. package/dist/core/compaction/compaction.js.map +1 -1
  38. package/dist/core/public-context.d.ts.map +1 -1
  39. package/dist/core/public-context.js +2 -0
  40. package/dist/core/public-context.js.map +1 -1
  41. package/dist/core/view-units.d.ts.map +1 -1
  42. package/dist/core/view-units.js +3 -0
  43. package/dist/core/view-units.js.map +1 -1
  44. package/dist/main.d.ts.map +1 -1
  45. package/dist/main.js +1 -1
  46. package/dist/main.js.map +1 -1
  47. package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
  48. package/dist/modes/daemon/daemon-mode.js +4 -3
  49. package/dist/modes/daemon/daemon-mode.js.map +1 -1
  50. package/dist/modes/daemon/daemon-supervisor.d.ts.map +1 -1
  51. package/dist/modes/daemon/daemon-supervisor.js +11 -5
  52. package/dist/modes/daemon/daemon-supervisor.js.map +1 -1
  53. package/dist/modes/daemon/daemon-worker-protocol.d.ts +3 -0
  54. package/dist/modes/daemon/daemon-worker-protocol.d.ts.map +1 -1
  55. package/dist/modes/daemon/daemon-worker-protocol.js +2 -0
  56. package/dist/modes/daemon/daemon-worker-protocol.js.map +1 -1
  57. package/dist/modes/print-mode.d.ts.map +1 -1
  58. package/dist/modes/print-mode.js +24 -21
  59. package/dist/modes/print-mode.js.map +1 -1
  60. package/docs/compaction.md +36 -7
  61. package/docs/context-management.md +16 -10
  62. package/docs/json.md +14 -1
  63. package/docs/long-running-agents.md +23 -2
  64. package/docs/providers.md +17 -0
  65. package/docs/settings.md +20 -11
  66. package/package.json +4 -4
@@ -9,6 +9,7 @@ export declare const DAEMON_WORKER_INSTANCE_ID_ENV = "BASE_CONTEXT_INTERNAL_DAEM
9
9
  export declare const DAEMON_WORKER_ACTIVE_SESSION_ID_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_WORKER_ACTIVE_SESSION_ID";
10
10
  export declare const DAEMON_WORKER_SUPERVISOR_SOCKET_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_SUPERVISOR_SOCKET";
11
11
  export declare const DAEMON_WORKER_RECOVERY_JOURNAL_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RECOVERY_JOURNAL";
12
+ export declare const DAEMON_WORKER_RLM_LEDGER_SESSION_DIR_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RLM_LEDGER_SESSION_DIR";
12
13
  export declare const DAEMON_WORKER_STARTUP_GATE_FD_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_WORKER_STARTUP_GATE_FD";
13
14
  export declare const DAEMON_WORKER_STARTUP_GATE_COMMIT = "start\n";
14
15
  export type DaemonWorkerLifecycle = "starting" | "ready" | "recovering" | "stopping" | "failed";
@@ -179,6 +180,8 @@ export interface DaemonWorkerDescriptor {
179
180
  rootSessionId?: string;
180
181
  sessionFile?: string;
181
182
  sessionDir?: string;
183
+ /** Supervisor-assigned journal scope, independent of transcript storage. */
184
+ rlmLedgerSessionDir?: string;
182
185
  createdAt: string;
183
186
  updatedAt: string;
184
187
  lifecycle: DaemonWorkerLifecycle;
@@ -1 +1 @@
1
- {"version":3,"file":"daemon-worker-protocol.d.ts","sourceRoot":"","sources":["../../../src/modes/daemon/daemon-worker-protocol.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,+BAA+B,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAC/G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAE9E,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAErG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAElG,eAAO,MAAM,sBAAsB,wCAAwC,CAAC;AAC5E,eAAO,MAAM,uBAAuB,8CAA8C,CAAC;AACnF,eAAO,MAAM,6BAA6B,oDAAoD,CAAC;AAC/F,eAAO,MAAM,mCAAmC,0DAA0D,CAAC;AAC3G,eAAO,MAAM,mCAAmC,mDAAmD,CAAC;AACpG,eAAO,MAAM,kCAAkC,yDAAyD,CAAC;AACzG,eAAO,MAAM,iCAAiC,wDAAwD,CAAC;AACvG,eAAO,MAAM,iCAAiC,YAAY,CAAC;AAC3D,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,CAAC;AAGhG,MAAM,MAAM,0BAA0B,GACnC;IACA,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,IAAI,CAAC;CACf,GACD;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAEhC,uFAAuF;AACvF,eAAO,MAAM,+BAA+B,iBAAiB,CAAC;AAE9D,2FAA2F;AAC3F,eAAO,MAAM,uCAAuC,mBAAmB,CAAC;AAExE,uHAAuH;AACvH,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD,MAAM,MAAM,uBAAuB,GAChC;IACA,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACnB,GACD;IACA,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,cAAc,CAAC,MAAM,CAAC,GAAG,0BAA0B,CAAC,MAAM,CAAC,CAAC;IAC1E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IAC9C,eAAe,CAAC,EAAE,QAAQ,GAAG,aAAa,GAAG,SAAS,CAAC;CACtD,CAAC;AAEL,MAAM,WAAW,uBAAuB;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,0BAA0B,GACnC,CAAC,uBAAuB,GAAG;IAAE,EAAE,EAAE,QAAQ,CAAA;CAAE,CAAC,GAC5C,CAAC,uBAAuB,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,GAC/D,CAAC,uBAAuB,GAAG;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC,GACzF;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C,MAAM,WAAW,4BAA6B,SAAQ,uBAAuB;IAC5E,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACzC,YAAY,EAAE,4BAA4B,EAAE,CAAC;CAC7C;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,yBAAyB,CAoB9F;AAED,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAC;AAE7E,MAAM,WAAW,0BAA0B;IAC1C,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,mBAAmB,GAAG,0BAA0B,CAMnG;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CACzB;AAED,qFAAqF;AACrF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,gBAAgB,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;AAElE,MAAM,MAAM,mBAAmB,GAC5B;IACA,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,oBAAoB,EAAE,MAAM,CAAC;CAC5B,GACD;IACA,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,kBAAkB,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,SAAS,sBAAsB,EAAE,CAAC;IACjD,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC7B,GACD;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,oBAAoB,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,gCAAgC,CAAC;IAAC,KAAK,EAAE,qBAAqB,CAAA;CAAE,GACrF;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,6BAA6B,CAAA;CAAE,GACpD;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,yBAAyB,CAAA;CAAE,GAChD;IACA,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,gCAAgC,CAAC;IACvC,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACb,GACD;IACA,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,wBAAwB,CAAC;IAC/B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,yBAAyB,CAAC;IAClC,YAAY,CAAC,EAAE,+BAA+B,CAAC;CAC9C,GACD;IACA,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,uBAAuB,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,yBAAyB,CAAC;IAClC,YAAY,CAAC,EAAE,+BAA+B,CAAC;CAC9C,GACD;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,uBAAuB,CAAA;CAAE,GAC9C;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,sBAAsB,CAAA;CAAE,GAC7C;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAEjD,MAAM,MAAM,uBAAuB,GAAG,mBAAmB,SAAS,MAAM,QAAQ,GAC7E,QAAQ,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/B,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,GACpB,KAAK,GACN,KAAK,CAAC;AAET,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,qBAAqB,CAAC;IACjC,aAAa,EAAE,0BAA0B,CAAC;IAC1C,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kGAAkG;IAClG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kFAAkF;IAClF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,sBAAsB,GAAG,sBAAsB,CAuCxG;AAED,wBAAgB,qBAAqB,CAAC,WAAW,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE3F;AAED,wBAAgB,8BAA8B,CAAC,WAAW,GAAE,MAAM,CAAC,UAAwB,GAAG,IAAI,CAmBjG;AAED,wBAAgB,sBAAsB,CAAC,WAAW,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAEvG;AAED,wBAAgB,sCAAsC,CAAC,WAAW,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAM3G;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,uBAAuB,CAuB1F","sourcesContent":["import { closeSync, readFileSync } from \"node:fs\";\nimport type { AgentSessionMessageDeliveryMode, AgentSessionMessageSender } from \"../../core/agent-messages.js\";\nimport type { IdleEvictionMinutes } from \"../../core/session-action-store.js\";\n\nexport { SESSION_LEASE_OWNER_ID_ENV, SESSION_LEASES_ENABLED_ENV } from \"../../core/session-lease.js\";\n\nimport type { WorkerRosterEntry } from \"./agent-roster.js\";\nimport type { DaemonClientCapability, DaemonCommand, DaemonOutbound } from \"./daemon-protocol.js\";\n\nexport const DAEMON_WORKER_ROLE_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER\";\nexport const DAEMON_WORKER_TOKEN_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_TOKEN\";\nexport const DAEMON_WORKER_INSTANCE_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_INSTANCE_ID\";\nexport const DAEMON_WORKER_ACTIVE_SESSION_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_ACTIVE_SESSION_ID\";\nexport const DAEMON_WORKER_SUPERVISOR_SOCKET_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_SUPERVISOR_SOCKET\";\nexport const DAEMON_WORKER_RECOVERY_JOURNAL_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RECOVERY_JOURNAL\";\nexport const DAEMON_WORKER_STARTUP_GATE_FD_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_STARTUP_GATE_FD\";\nexport const DAEMON_WORKER_STARTUP_GATE_COMMIT = \"start\\n\";\nexport type DaemonWorkerLifecycle = \"starting\" | \"ready\" | \"recovering\" | \"stopping\" | \"failed\";\n\n// Worker->supervisor roster frames live outside the client-facing DaemonOutbound schema.\nexport type DaemonWorkerRosterOutbound =\n\t| {\n\t\t\ttype: \"roster_delta\";\n\t\t\tentries: WorkerRosterEntry[];\n\t\t\tremovedAgentIds?: string[];\n\t\t\tsnapshot?: true;\n\t }\n\t| { type: \"roster_heartbeat\" };\n\n/** Advertised by new workers in the worker_auth response; absent on legacy workers. */\nexport const DAEMON_WORKER_ROSTER_CAPABILITY = \"agent_roster\";\n\n/** Advertised in the worker_auth response by workers that accept peer transport grants. */\nexport const DAEMON_WORKER_PEER_TRANSPORT_CAPABILITY = \"peer_transport\";\n\n/** Idle keepalive cadence for worker->supervisor roster frames; the supervisor staleness threshold derives from it. */\nexport const ROSTER_HEARTBEAT_INTERVAL_MS = 15_000;\n\nexport type DaemonWorkerFrameHeader =\n\t| {\n\t\t\tkind: \"command\";\n\t\t\trequestId: string;\n\t\t\tcommandType: string;\n\t }\n\t| {\n\t\t\tkind: \"outbound\";\n\t\t\trequestId?: string;\n\t\t\toutboundType: DaemonOutbound[\"type\"] | DaemonWorkerRosterOutbound[\"type\"];\n\t\t\tactiveSessionId?: string;\n\t\t\tsnapshotId?: string;\n\t\t\tsessionEventType?: string;\n\t\t\tpayloadEncoding?: \"jsonl\" | \"assistant-delta\";\n\t\t\tsnapshotPurpose?: \"attach\" | \"replacement\" | \"catchup\";\n\t };\n\nexport interface DaemonRlmCapacityOrigin {\n\tsessionFile?: string;\n\tsessionId: string;\n}\n\nexport type DaemonRlmCapacityOperation =\n\t| (DaemonRlmCapacityOrigin & { op: \"status\" })\n\t| (DaemonRlmCapacityOrigin & { op: \"set\"; maxSubagents: number })\n\t| (DaemonRlmCapacityOrigin & { op: \"reserve\"; reservationId: string; residentRoot?: true })\n\t| { op: \"release\"; reservationId: string };\n\nexport interface DaemonRlmCapacityReservation extends DaemonRlmCapacityOrigin {\n\treservationId: string;\n\tresidentRoot?: true;\n}\n\nexport interface DaemonRlmCapacitySnapshot {\n\treservations: DaemonRlmCapacityReservation[];\n}\n\nexport function isDaemonRlmCapacitySnapshot(value: unknown): value is DaemonRlmCapacitySnapshot {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"reservations\" in value &&\n\t\tArray.isArray(value.reservations) &&\n\t\tvalue.reservations.every(\n\t\t\t(entry: unknown) =>\n\t\t\t\ttypeof entry === \"object\" &&\n\t\t\t\tentry !== null &&\n\t\t\t\t\"reservationId\" in entry &&\n\t\t\t\ttypeof entry.reservationId === \"string\" &&\n\t\t\t\tentry.reservationId.length > 0 &&\n\t\t\t\t\"sessionId\" in entry &&\n\t\t\t\ttypeof entry.sessionId === \"string\" &&\n\t\t\t\tentry.sessionId.length > 0 &&\n\t\t\t\t(!(\"sessionFile\" in entry) || entry.sessionFile === undefined || typeof entry.sessionFile === \"string\") &&\n\t\t\t\t(!(\"residentRoot\" in entry) || entry.residentRoot === undefined || entry.residentRoot === true),\n\t\t)\n\t);\n}\n\nexport type DaemonCreateCommand = Extract<DaemonCommand, { type: \"create\" }>;\n\nexport interface DurableDaemonCreateCommand {\n\ttype: \"create\";\n\tsessionPath?: string;\n\tnoSession?: boolean;\n}\n\nexport function durableDaemonCreateCommand(command: DaemonCreateCommand): DurableDaemonCreateCommand {\n\treturn {\n\t\ttype: \"create\",\n\t\t...(command.sessionPath !== undefined ? { sessionPath: command.sessionPath } : {}),\n\t\t...(command.noSession !== undefined ? { noSession: command.noSession } : {}),\n\t};\n}\n\n/**\n * A single-use, worker-memory-only admission for one direct peer, scoped to one active-session\n * slot (stable across switch_session/new_session/fork) of one worker incarnation. The session pin\n * is a routing/accident guard, not a privilege boundary: ticket holders already hold supervisor\n * access, which can attach to, switch, or kill any session.\n */\nexport interface DaemonWorkerPeerGrant {\n\tgrantId: string;\n\ttoken: string;\n\texpiresAt: string;\n\tpurpose: \"session_client\";\n\tworkerInstanceId: string;\n\tactiveSessionId: string;\n\tissuerGeneration: string;\n}\n\n/** Commands a direct peer may send before it holds an authenticated session role. */\nexport type DaemonPeerCommand = {\n\tid?: string;\n\ttype: \"peer_auth\";\n\tgrantId: string;\n\ttoken: string;\n\tworkerInstanceId: string;\n\tpurpose: \"session_client\";\n};\n\nexport type DaemonPeerCommandBody = Omit<DaemonPeerCommand, \"id\">;\n\nexport type DaemonWorkerCommand =\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_auth\";\n\t\t\ttoken: string;\n\t\t\tworkerInstanceId?: string;\n\t\t\tsupervisorGeneration: string;\n\t\t\tsupervisorPid: number;\n\t\t\tsupervisorProcessStartId?: string;\n\t\t\tsupervisorSocketPath: string;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_subscribe\";\n\t\t\tactiveSessionId: string;\n\t\t\tcapabilities?: readonly DaemonClientCapability[];\n\t\t\tsupportsExtensionUi?: boolean;\n\t }\n\t| { id?: string; type: \"worker_unsubscribe\"; activeSessionId: string }\n\t| { id?: string; type: \"worker_register_peer_transport\"; grant: DaemonWorkerPeerGrant }\n\t| { id?: string; type: \"worker_archive_and_shutdown\" }\n\t| { id?: string; type: \"worker_get_rlm_capacity\" }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_passivate_idle_children\";\n\t\t\tidleEvictionMinutes: IdleEvictionMinutes;\n\t\t\tnow: number;\n\t\t\tlimit: number;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_message\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tmessage: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_result\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tsummary: string;\n\t\t\tfindings: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| { id?: string; type: \"worker_prepare_update\" }\n\t| { id?: string; type: \"worker_commit_update\" }\n\t| { id?: string; type: \"worker_cancel_update\" };\n\nexport type DaemonWorkerCommandBody = DaemonWorkerCommand extends infer TCommand\n\t? TCommand extends { id?: string }\n\t\t? Omit<TCommand, \"id\">\n\t\t: never\n\t: never;\n\nexport interface DaemonWorkerDescriptor {\n\tversion: 1 | 2;\n\tworkerId: string;\n\tpid: number;\n\tprocessStartId?: string;\n\tsocketPath: string;\n\trecoveryJournalPath: string;\n\torphanProcessJournalPath?: string;\n\tsupervisorSocketPath: string;\n\tauthenticationToken: string;\n\tworkerInstanceId?: string;\n\trootActiveSessionId: string;\n\t/** Stable protocol client that owns this worker. Omitted for resident sessions. */\n\townerClientId?: string;\n\trootSessionId?: string;\n\tsessionFile?: string;\n\tsessionDir?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tlifecycle: DaemonWorkerLifecycle;\n\tcreateCommand: DurableDaemonCreateCommand;\n\tconsecutiveFailures: number;\n\t/** Durable intent written before root termination so replacement supervisors never recover it. */\n\tstopRequestedAt?: string;\n\t/** Complete the root's archived lifecycle state after its process has stopped. */\n\tarchiveOnStop?: boolean;\n\tlastFailureAt?: string;\n\tlastError?: string;\n}\n\nexport function durableDaemonWorkerDescriptor(descriptor: DaemonWorkerDescriptor): DaemonWorkerDescriptor {\n\tconst versionOneCreateCommand = descriptor.createCommand as unknown as { config?: unknown };\n\tconst versionOneConfig =\n\t\tdescriptor.version === 1 &&\n\t\ttypeof versionOneCreateCommand.config === \"object\" &&\n\t\tversionOneCreateCommand.config !== null\n\t\t\t? (versionOneCreateCommand.config as Record<string, unknown>)\n\t\t\t: undefined;\n\tconst sessionDir =\n\t\tdescriptor.sessionDir ??\n\t\t(typeof versionOneConfig?.sessionDir === \"string\" ? versionOneConfig.sessionDir : undefined);\n\treturn {\n\t\tversion: 2,\n\t\tworkerId: descriptor.workerId,\n\t\tpid: descriptor.pid,\n\t\t...(descriptor.processStartId !== undefined ? { processStartId: descriptor.processStartId } : {}),\n\t\tsocketPath: descriptor.socketPath,\n\t\trecoveryJournalPath: descriptor.recoveryJournalPath,\n\t\t...(descriptor.orphanProcessJournalPath !== undefined\n\t\t\t? { orphanProcessJournalPath: descriptor.orphanProcessJournalPath }\n\t\t\t: {}),\n\t\tsupervisorSocketPath: descriptor.supervisorSocketPath,\n\t\tauthenticationToken: descriptor.authenticationToken,\n\t\t...(descriptor.workerInstanceId !== undefined ? { workerInstanceId: descriptor.workerInstanceId } : {}),\n\t\trootActiveSessionId: descriptor.rootActiveSessionId,\n\t\t...(descriptor.ownerClientId !== undefined ? { ownerClientId: descriptor.ownerClientId } : {}),\n\t\t...(descriptor.rootSessionId !== undefined ? { rootSessionId: descriptor.rootSessionId } : {}),\n\t\t...(descriptor.sessionFile !== undefined ? { sessionFile: descriptor.sessionFile } : {}),\n\t\t...(sessionDir !== undefined ? { sessionDir } : {}),\n\t\tcreatedAt: descriptor.createdAt,\n\t\tupdatedAt: descriptor.updatedAt,\n\t\tlifecycle: descriptor.lifecycle,\n\t\tcreateCommand: durableDaemonCreateCommand(descriptor.createCommand),\n\t\tconsecutiveFailures: descriptor.consecutiveFailures,\n\t\t...(descriptor.stopRequestedAt !== undefined ? { stopRequestedAt: descriptor.stopRequestedAt } : {}),\n\t\t...(descriptor.archiveOnStop !== undefined ? { archiveOnStop: descriptor.archiveOnStop } : {}),\n\t\t...(descriptor.lastFailureAt !== undefined ? { lastFailureAt: descriptor.lastFailureAt } : {}),\n\t\t...(descriptor.lifecycle === \"failed\" ? { lastError: \"Waiting for a client with fresh runtime context\" } : {}),\n\t};\n}\n\nexport function isDaemonWorkerProcess(environment: NodeJS.ProcessEnv = process.env): boolean {\n\treturn environment[DAEMON_WORKER_ROLE_ENV] === \"1\";\n}\n\nexport function waitForDaemonWorkerStartupGate(environment: NodeJS.ProcessEnv = process.env): void {\n\tconst rawFd = environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tif (rawFd === undefined) {\n\t\treturn;\n\t}\n\tdelete environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tconst fd = Number(rawFd);\n\tif (!Number.isInteger(fd) || fd < 3) {\n\t\tthrow new Error(\"Daemon session worker has an invalid startup gate\");\n\t}\n\tlet marker: string;\n\ttry {\n\t\tmarker = readFileSync(fd, \"utf8\");\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\tif (marker !== DAEMON_WORKER_STARTUP_GATE_COMMIT) {\n\t\tthrow new Error(\"Daemon session worker startup was cancelled\");\n\t}\n}\n\nexport function daemonWorkerInstanceId(environment: NodeJS.ProcessEnv = process.env): string | undefined {\n\treturn environment[DAEMON_WORKER_INSTANCE_ID_ENV] || undefined;\n}\n\nexport function requireDaemonWorkerAuthenticationToken(environment: NodeJS.ProcessEnv = process.env): string {\n\tconst token = environment[DAEMON_WORKER_TOKEN_ENV];\n\tif (!token) {\n\t\tthrow new Error(\"Daemon session worker is missing its authentication token\");\n\t}\n\treturn token;\n}\n\nexport function isDaemonWorkerFrameHeader(value: unknown): value is DaemonWorkerFrameHeader {\n\tif (!value || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tif (candidate.kind === \"command\") {\n\t\treturn typeof candidate.requestId === \"string\" && typeof candidate.commandType === \"string\";\n\t}\n\treturn (\n\t\tcandidate.kind === \"outbound\" &&\n\t\ttypeof candidate.outboundType === \"string\" &&\n\t\t(candidate.requestId === undefined || typeof candidate.requestId === \"string\") &&\n\t\t(candidate.activeSessionId === undefined || typeof candidate.activeSessionId === \"string\") &&\n\t\t(candidate.snapshotId === undefined || typeof candidate.snapshotId === \"string\") &&\n\t\t(candidate.sessionEventType === undefined || typeof candidate.sessionEventType === \"string\") &&\n\t\t(candidate.snapshotPurpose === undefined ||\n\t\t\tcandidate.snapshotPurpose === \"attach\" ||\n\t\t\tcandidate.snapshotPurpose === \"replacement\" ||\n\t\t\tcandidate.snapshotPurpose === \"catchup\") &&\n\t\t(candidate.payloadEncoding === undefined ||\n\t\t\tcandidate.payloadEncoding === \"jsonl\" ||\n\t\t\tcandidate.payloadEncoding === \"assistant-delta\")\n\t);\n}\n"]}
1
+ {"version":3,"file":"daemon-worker-protocol.d.ts","sourceRoot":"","sources":["../../../src/modes/daemon/daemon-worker-protocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { closeSync, readFileSync } from \"node:fs\";\nimport type { AgentSessionMessageDeliveryMode, AgentSessionMessageSender } from \"../../core/agent-messages.js\";\nimport type { IdleEvictionMinutes } from \"../../core/session-action-store.js\";\n\nexport { SESSION_LEASE_OWNER_ID_ENV, SESSION_LEASES_ENABLED_ENV } from \"../../core/session-lease.js\";\n\nimport type { WorkerRosterEntry } from \"./agent-roster.js\";\nimport type { DaemonClientCapability, DaemonCommand, DaemonOutbound } from \"./daemon-protocol.js\";\n\nexport const DAEMON_WORKER_ROLE_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER\";\nexport const DAEMON_WORKER_TOKEN_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_TOKEN\";\nexport const DAEMON_WORKER_INSTANCE_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_INSTANCE_ID\";\nexport const DAEMON_WORKER_ACTIVE_SESSION_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_ACTIVE_SESSION_ID\";\nexport const DAEMON_WORKER_SUPERVISOR_SOCKET_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_SUPERVISOR_SOCKET\";\nexport const DAEMON_WORKER_RECOVERY_JOURNAL_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RECOVERY_JOURNAL\";\nexport const DAEMON_WORKER_RLM_LEDGER_SESSION_DIR_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RLM_LEDGER_SESSION_DIR\";\nexport const DAEMON_WORKER_STARTUP_GATE_FD_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_STARTUP_GATE_FD\";\nexport const DAEMON_WORKER_STARTUP_GATE_COMMIT = \"start\\n\";\nexport type DaemonWorkerLifecycle = \"starting\" | \"ready\" | \"recovering\" | \"stopping\" | \"failed\";\n\n// Worker->supervisor roster frames live outside the client-facing DaemonOutbound schema.\nexport type DaemonWorkerRosterOutbound =\n\t| {\n\t\t\ttype: \"roster_delta\";\n\t\t\tentries: WorkerRosterEntry[];\n\t\t\tremovedAgentIds?: string[];\n\t\t\tsnapshot?: true;\n\t }\n\t| { type: \"roster_heartbeat\" };\n\n/** Advertised by new workers in the worker_auth response; absent on legacy workers. */\nexport const DAEMON_WORKER_ROSTER_CAPABILITY = \"agent_roster\";\n\n/** Advertised in the worker_auth response by workers that accept peer transport grants. */\nexport const DAEMON_WORKER_PEER_TRANSPORT_CAPABILITY = \"peer_transport\";\n\n/** Idle keepalive cadence for worker->supervisor roster frames; the supervisor staleness threshold derives from it. */\nexport const ROSTER_HEARTBEAT_INTERVAL_MS = 15_000;\n\nexport type DaemonWorkerFrameHeader =\n\t| {\n\t\t\tkind: \"command\";\n\t\t\trequestId: string;\n\t\t\tcommandType: string;\n\t }\n\t| {\n\t\t\tkind: \"outbound\";\n\t\t\trequestId?: string;\n\t\t\toutboundType: DaemonOutbound[\"type\"] | DaemonWorkerRosterOutbound[\"type\"];\n\t\t\tactiveSessionId?: string;\n\t\t\tsnapshotId?: string;\n\t\t\tsessionEventType?: string;\n\t\t\tpayloadEncoding?: \"jsonl\" | \"assistant-delta\";\n\t\t\tsnapshotPurpose?: \"attach\" | \"replacement\" | \"catchup\";\n\t };\n\nexport interface DaemonRlmCapacityOrigin {\n\tsessionFile?: string;\n\tsessionId: string;\n}\n\nexport type DaemonRlmCapacityOperation =\n\t| (DaemonRlmCapacityOrigin & { op: \"status\" })\n\t| (DaemonRlmCapacityOrigin & { op: \"set\"; maxSubagents: number })\n\t| (DaemonRlmCapacityOrigin & { op: \"reserve\"; reservationId: string; residentRoot?: true })\n\t| { op: \"release\"; reservationId: string };\n\nexport interface DaemonRlmCapacityReservation extends DaemonRlmCapacityOrigin {\n\treservationId: string;\n\tresidentRoot?: true;\n}\n\nexport interface DaemonRlmCapacitySnapshot {\n\treservations: DaemonRlmCapacityReservation[];\n}\n\nexport function isDaemonRlmCapacitySnapshot(value: unknown): value is DaemonRlmCapacitySnapshot {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"reservations\" in value &&\n\t\tArray.isArray(value.reservations) &&\n\t\tvalue.reservations.every(\n\t\t\t(entry: unknown) =>\n\t\t\t\ttypeof entry === \"object\" &&\n\t\t\t\tentry !== null &&\n\t\t\t\t\"reservationId\" in entry &&\n\t\t\t\ttypeof entry.reservationId === \"string\" &&\n\t\t\t\tentry.reservationId.length > 0 &&\n\t\t\t\t\"sessionId\" in entry &&\n\t\t\t\ttypeof entry.sessionId === \"string\" &&\n\t\t\t\tentry.sessionId.length > 0 &&\n\t\t\t\t(!(\"sessionFile\" in entry) || entry.sessionFile === undefined || typeof entry.sessionFile === \"string\") &&\n\t\t\t\t(!(\"residentRoot\" in entry) || entry.residentRoot === undefined || entry.residentRoot === true),\n\t\t)\n\t);\n}\n\nexport type DaemonCreateCommand = Extract<DaemonCommand, { type: \"create\" }>;\n\nexport interface DurableDaemonCreateCommand {\n\ttype: \"create\";\n\tsessionPath?: string;\n\tnoSession?: boolean;\n}\n\nexport function durableDaemonCreateCommand(command: DaemonCreateCommand): DurableDaemonCreateCommand {\n\treturn {\n\t\ttype: \"create\",\n\t\t...(command.sessionPath !== undefined ? { sessionPath: command.sessionPath } : {}),\n\t\t...(command.noSession !== undefined ? { noSession: command.noSession } : {}),\n\t};\n}\n\n/**\n * A single-use, worker-memory-only admission for one direct peer, scoped to one active-session\n * slot (stable across switch_session/new_session/fork) of one worker incarnation. The session pin\n * is a routing/accident guard, not a privilege boundary: ticket holders already hold supervisor\n * access, which can attach to, switch, or kill any session.\n */\nexport interface DaemonWorkerPeerGrant {\n\tgrantId: string;\n\ttoken: string;\n\texpiresAt: string;\n\tpurpose: \"session_client\";\n\tworkerInstanceId: string;\n\tactiveSessionId: string;\n\tissuerGeneration: string;\n}\n\n/** Commands a direct peer may send before it holds an authenticated session role. */\nexport type DaemonPeerCommand = {\n\tid?: string;\n\ttype: \"peer_auth\";\n\tgrantId: string;\n\ttoken: string;\n\tworkerInstanceId: string;\n\tpurpose: \"session_client\";\n};\n\nexport type DaemonPeerCommandBody = Omit<DaemonPeerCommand, \"id\">;\n\nexport type DaemonWorkerCommand =\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_auth\";\n\t\t\ttoken: string;\n\t\t\tworkerInstanceId?: string;\n\t\t\tsupervisorGeneration: string;\n\t\t\tsupervisorPid: number;\n\t\t\tsupervisorProcessStartId?: string;\n\t\t\tsupervisorSocketPath: string;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_subscribe\";\n\t\t\tactiveSessionId: string;\n\t\t\tcapabilities?: readonly DaemonClientCapability[];\n\t\t\tsupportsExtensionUi?: boolean;\n\t }\n\t| { id?: string; type: \"worker_unsubscribe\"; activeSessionId: string }\n\t| { id?: string; type: \"worker_register_peer_transport\"; grant: DaemonWorkerPeerGrant }\n\t| { id?: string; type: \"worker_archive_and_shutdown\" }\n\t| { id?: string; type: \"worker_get_rlm_capacity\" }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_passivate_idle_children\";\n\t\t\tidleEvictionMinutes: IdleEvictionMinutes;\n\t\t\tnow: number;\n\t\t\tlimit: number;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_message\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tmessage: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_result\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tsummary: string;\n\t\t\tfindings: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| { id?: string; type: \"worker_prepare_update\" }\n\t| { id?: string; type: \"worker_commit_update\" }\n\t| { id?: string; type: \"worker_cancel_update\" };\n\nexport type DaemonWorkerCommandBody = DaemonWorkerCommand extends infer TCommand\n\t? TCommand extends { id?: string }\n\t\t? Omit<TCommand, \"id\">\n\t\t: never\n\t: never;\n\nexport interface DaemonWorkerDescriptor {\n\tversion: 1 | 2;\n\tworkerId: string;\n\tpid: number;\n\tprocessStartId?: string;\n\tsocketPath: string;\n\trecoveryJournalPath: string;\n\torphanProcessJournalPath?: string;\n\tsupervisorSocketPath: string;\n\tauthenticationToken: string;\n\tworkerInstanceId?: string;\n\trootActiveSessionId: string;\n\t/** Stable protocol client that owns this worker. Omitted for resident sessions. */\n\townerClientId?: string;\n\trootSessionId?: string;\n\tsessionFile?: string;\n\tsessionDir?: string;\n\t/** Supervisor-assigned journal scope, independent of transcript storage. */\n\trlmLedgerSessionDir?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tlifecycle: DaemonWorkerLifecycle;\n\tcreateCommand: DurableDaemonCreateCommand;\n\tconsecutiveFailures: number;\n\t/** Durable intent written before root termination so replacement supervisors never recover it. */\n\tstopRequestedAt?: string;\n\t/** Complete the root's archived lifecycle state after its process has stopped. */\n\tarchiveOnStop?: boolean;\n\tlastFailureAt?: string;\n\tlastError?: string;\n}\n\nexport function durableDaemonWorkerDescriptor(descriptor: DaemonWorkerDescriptor): DaemonWorkerDescriptor {\n\tconst versionOneCreateCommand = descriptor.createCommand as unknown as { config?: unknown };\n\tconst versionOneConfig =\n\t\tdescriptor.version === 1 &&\n\t\ttypeof versionOneCreateCommand.config === \"object\" &&\n\t\tversionOneCreateCommand.config !== null\n\t\t\t? (versionOneCreateCommand.config as Record<string, unknown>)\n\t\t\t: undefined;\n\tconst sessionDir =\n\t\tdescriptor.sessionDir ??\n\t\t(typeof versionOneConfig?.sessionDir === \"string\" ? versionOneConfig.sessionDir : undefined);\n\treturn {\n\t\tversion: 2,\n\t\tworkerId: descriptor.workerId,\n\t\tpid: descriptor.pid,\n\t\t...(descriptor.processStartId !== undefined ? { processStartId: descriptor.processStartId } : {}),\n\t\tsocketPath: descriptor.socketPath,\n\t\trecoveryJournalPath: descriptor.recoveryJournalPath,\n\t\t...(descriptor.orphanProcessJournalPath !== undefined\n\t\t\t? { orphanProcessJournalPath: descriptor.orphanProcessJournalPath }\n\t\t\t: {}),\n\t\tsupervisorSocketPath: descriptor.supervisorSocketPath,\n\t\tauthenticationToken: descriptor.authenticationToken,\n\t\t...(descriptor.workerInstanceId !== undefined ? { workerInstanceId: descriptor.workerInstanceId } : {}),\n\t\trootActiveSessionId: descriptor.rootActiveSessionId,\n\t\t...(descriptor.ownerClientId !== undefined ? { ownerClientId: descriptor.ownerClientId } : {}),\n\t\t...(descriptor.rootSessionId !== undefined ? { rootSessionId: descriptor.rootSessionId } : {}),\n\t\t...(descriptor.sessionFile !== undefined ? { sessionFile: descriptor.sessionFile } : {}),\n\t\t...(sessionDir !== undefined ? { sessionDir } : {}),\n\t\t...(descriptor.rlmLedgerSessionDir !== undefined ? { rlmLedgerSessionDir: descriptor.rlmLedgerSessionDir } : {}),\n\t\tcreatedAt: descriptor.createdAt,\n\t\tupdatedAt: descriptor.updatedAt,\n\t\tlifecycle: descriptor.lifecycle,\n\t\tcreateCommand: durableDaemonCreateCommand(descriptor.createCommand),\n\t\tconsecutiveFailures: descriptor.consecutiveFailures,\n\t\t...(descriptor.stopRequestedAt !== undefined ? { stopRequestedAt: descriptor.stopRequestedAt } : {}),\n\t\t...(descriptor.archiveOnStop !== undefined ? { archiveOnStop: descriptor.archiveOnStop } : {}),\n\t\t...(descriptor.lastFailureAt !== undefined ? { lastFailureAt: descriptor.lastFailureAt } : {}),\n\t\t...(descriptor.lifecycle === \"failed\" ? { lastError: \"Waiting for a client with fresh runtime context\" } : {}),\n\t};\n}\n\nexport function isDaemonWorkerProcess(environment: NodeJS.ProcessEnv = process.env): boolean {\n\treturn environment[DAEMON_WORKER_ROLE_ENV] === \"1\";\n}\n\nexport function waitForDaemonWorkerStartupGate(environment: NodeJS.ProcessEnv = process.env): void {\n\tconst rawFd = environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tif (rawFd === undefined) {\n\t\treturn;\n\t}\n\tdelete environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tconst fd = Number(rawFd);\n\tif (!Number.isInteger(fd) || fd < 3) {\n\t\tthrow new Error(\"Daemon session worker has an invalid startup gate\");\n\t}\n\tlet marker: string;\n\ttry {\n\t\tmarker = readFileSync(fd, \"utf8\");\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\tif (marker !== DAEMON_WORKER_STARTUP_GATE_COMMIT) {\n\t\tthrow new Error(\"Daemon session worker startup was cancelled\");\n\t}\n}\n\nexport function daemonWorkerInstanceId(environment: NodeJS.ProcessEnv = process.env): string | undefined {\n\treturn environment[DAEMON_WORKER_INSTANCE_ID_ENV] || undefined;\n}\n\nexport function requireDaemonWorkerAuthenticationToken(environment: NodeJS.ProcessEnv = process.env): string {\n\tconst token = environment[DAEMON_WORKER_TOKEN_ENV];\n\tif (!token) {\n\t\tthrow new Error(\"Daemon session worker is missing its authentication token\");\n\t}\n\treturn token;\n}\n\nexport function isDaemonWorkerFrameHeader(value: unknown): value is DaemonWorkerFrameHeader {\n\tif (!value || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tif (candidate.kind === \"command\") {\n\t\treturn typeof candidate.requestId === \"string\" && typeof candidate.commandType === \"string\";\n\t}\n\treturn (\n\t\tcandidate.kind === \"outbound\" &&\n\t\ttypeof candidate.outboundType === \"string\" &&\n\t\t(candidate.requestId === undefined || typeof candidate.requestId === \"string\") &&\n\t\t(candidate.activeSessionId === undefined || typeof candidate.activeSessionId === \"string\") &&\n\t\t(candidate.snapshotId === undefined || typeof candidate.snapshotId === \"string\") &&\n\t\t(candidate.sessionEventType === undefined || typeof candidate.sessionEventType === \"string\") &&\n\t\t(candidate.snapshotPurpose === undefined ||\n\t\t\tcandidate.snapshotPurpose === \"attach\" ||\n\t\t\tcandidate.snapshotPurpose === \"replacement\" ||\n\t\t\tcandidate.snapshotPurpose === \"catchup\") &&\n\t\t(candidate.payloadEncoding === undefined ||\n\t\t\tcandidate.payloadEncoding === \"jsonl\" ||\n\t\t\tcandidate.payloadEncoding === \"assistant-delta\")\n\t);\n}\n"]}
@@ -6,6 +6,7 @@ export const DAEMON_WORKER_INSTANCE_ID_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_WORKE
6
6
  export const DAEMON_WORKER_ACTIVE_SESSION_ID_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_WORKER_ACTIVE_SESSION_ID";
7
7
  export const DAEMON_WORKER_SUPERVISOR_SOCKET_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_SUPERVISOR_SOCKET";
8
8
  export const DAEMON_WORKER_RECOVERY_JOURNAL_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RECOVERY_JOURNAL";
9
+ export const DAEMON_WORKER_RLM_LEDGER_SESSION_DIR_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RLM_LEDGER_SESSION_DIR";
9
10
  export const DAEMON_WORKER_STARTUP_GATE_FD_ENV = "BASE_CONTEXT_INTERNAL_DAEMON_WORKER_STARTUP_GATE_FD";
10
11
  export const DAEMON_WORKER_STARTUP_GATE_COMMIT = "start\n";
11
12
  /** Advertised by new workers in the worker_auth response; absent on legacy workers. */
@@ -64,6 +65,7 @@ export function durableDaemonWorkerDescriptor(descriptor) {
64
65
  ...(descriptor.rootSessionId !== undefined ? { rootSessionId: descriptor.rootSessionId } : {}),
65
66
  ...(descriptor.sessionFile !== undefined ? { sessionFile: descriptor.sessionFile } : {}),
66
67
  ...(sessionDir !== undefined ? { sessionDir } : {}),
68
+ ...(descriptor.rlmLedgerSessionDir !== undefined ? { rlmLedgerSessionDir: descriptor.rlmLedgerSessionDir } : {}),
67
69
  createdAt: descriptor.createdAt,
68
70
  updatedAt: descriptor.updatedAt,
69
71
  lifecycle: descriptor.lifecycle,
@@ -1 +1 @@
1
- {"version":3,"file":"daemon-worker-protocol.js","sourceRoot":"","sources":["../../../src/modes/daemon/daemon-worker-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAIlD,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAKrG,MAAM,CAAC,MAAM,sBAAsB,GAAG,qCAAqC,CAAC;AAC5E,MAAM,CAAC,MAAM,uBAAuB,GAAG,2CAA2C,CAAC;AACnF,MAAM,CAAC,MAAM,6BAA6B,GAAG,iDAAiD,CAAC;AAC/F,MAAM,CAAC,MAAM,mCAAmC,GAAG,uDAAuD,CAAC;AAC3G,MAAM,CAAC,MAAM,mCAAmC,GAAG,gDAAgD,CAAC;AACpG,MAAM,CAAC,MAAM,kCAAkC,GAAG,sDAAsD,CAAC;AACzG,MAAM,CAAC,MAAM,iCAAiC,GAAG,qDAAqD,CAAC;AACvG,MAAM,CAAC,MAAM,iCAAiC,GAAG,SAAS,CAAC;AAa3D,uFAAuF;AACvF,MAAM,CAAC,MAAM,+BAA+B,GAAG,cAAc,CAAC;AAE9D,2FAA2F;AAC3F,MAAM,CAAC,MAAM,uCAAuC,GAAG,gBAAgB,CAAC;AAExE,uHAAuH;AACvH,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC;AAuCnD,MAAM,UAAU,2BAA2B,CAAC,KAAc,EAAsC;IAC/F,OAAO,CACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,cAAc,IAAI,KAAK;QACvB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC;QACjC,KAAK,CAAC,YAAY,CAAC,KAAK,CACvB,CAAC,KAAc,EAAE,EAAE,CAClB,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,KAAK,IAAI;YACd,eAAe,IAAI,KAAK;YACxB,OAAO,KAAK,CAAC,aAAa,KAAK,QAAQ;YACvC,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC;YAC9B,WAAW,IAAI,KAAK;YACpB,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ;YACnC,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YAC1B,CAAC,CAAC,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,CAAC;YACvG,CAAC,CAAC,CAAC,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC,CAChG,CACD,CAAC;AAAA,CACF;AAUD,MAAM,UAAU,0BAA0B,CAAC,OAA4B,EAA8B;IACpG,OAAO;QACN,IAAI,EAAE,QAAQ;QACd,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAC;AAAA,CACF;AAoHD,MAAM,UAAU,6BAA6B,CAAC,UAAkC,EAA0B;IACzG,MAAM,uBAAuB,GAAG,UAAU,CAAC,aAAgD,CAAC;IAC5F,MAAM,gBAAgB,GACrB,UAAU,CAAC,OAAO,KAAK,CAAC;QACxB,OAAO,uBAAuB,CAAC,MAAM,KAAK,QAAQ;QAClD,uBAAuB,CAAC,MAAM,KAAK,IAAI;QACtC,CAAC,CAAE,uBAAuB,CAAC,MAAkC;QAC7D,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,UAAU,GACf,UAAU,CAAC,UAAU;QACrB,CAAC,OAAO,gBAAgB,EAAE,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC9F,OAAO;QACN,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,GAAG,EAAE,UAAU,CAAC,GAAG;QACnB,GAAG,CAAC,UAAU,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,UAAU,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjG,UAAU,EAAE,UAAU,CAAC,UAAU;QACjC,mBAAmB,EAAE,UAAU,CAAC,mBAAmB;QACnD,GAAG,CAAC,UAAU,CAAC,wBAAwB,KAAK,SAAS;YACpD,CAAC,CAAC,EAAE,wBAAwB,EAAE,UAAU,CAAC,wBAAwB,EAAE;YACnE,CAAC,CAAC,EAAE,CAAC;QACN,oBAAoB,EAAE,UAAU,CAAC,oBAAoB;QACrD,mBAAmB,EAAE,UAAU,CAAC,mBAAmB;QACnD,GAAG,CAAC,UAAU,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,UAAU,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvG,mBAAmB,EAAE,UAAU,CAAC,mBAAmB;QACnD,GAAG,CAAC,UAAU,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9F,GAAG,CAAC,UAAU,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9F,GAAG,CAAC,UAAU,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxF,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,SAAS,EAAE,UAAU,CAAC,SAAS;QAC/B,SAAS,EAAE,UAAU,CAAC,SAAS;QAC/B,SAAS,EAAE,UAAU,CAAC,SAAS;QAC/B,aAAa,EAAE,0BAA0B,CAAC,UAAU,CAAC,aAAa,CAAC;QACnE,mBAAmB,EAAE,UAAU,CAAC,mBAAmB;QACnD,GAAG,CAAC,UAAU,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,UAAU,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpG,GAAG,CAAC,UAAU,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9F,GAAG,CAAC,UAAU,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9F,GAAG,CAAC,UAAU,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,iDAAiD,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9G,CAAC;AAAA,CACF;AAED,MAAM,UAAU,qBAAqB,CAAC,WAAW,GAAsB,OAAO,CAAC,GAAG,EAAW;IAC5F,OAAO,WAAW,CAAC,sBAAsB,CAAC,KAAK,GAAG,CAAC;AAAA,CACnD;AAED,MAAM,UAAU,8BAA8B,CAAC,WAAW,GAAsB,OAAO,CAAC,GAAG,EAAQ;IAClG,MAAM,KAAK,GAAG,WAAW,CAAC,iCAAiC,CAAC,CAAC;IAC7D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO;IACR,CAAC;IACD,OAAO,WAAW,CAAC,iCAAiC,CAAC,CAAC;IACtD,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACzB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACJ,MAAM,GAAG,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;YAAS,CAAC;QACV,SAAS,CAAC,EAAE,CAAC,CAAC;IACf,CAAC;IACD,IAAI,MAAM,KAAK,iCAAiC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAChE,CAAC;AAAA,CACD;AAED,MAAM,UAAU,sBAAsB,CAAC,WAAW,GAAsB,OAAO,CAAC,GAAG,EAAsB;IACxG,OAAO,WAAW,CAAC,6BAA6B,CAAC,IAAI,SAAS,CAAC;AAAA,CAC/D;AAED,MAAM,UAAU,sCAAsC,CAAC,WAAW,GAAsB,OAAO,CAAC,GAAG,EAAU;IAC5G,MAAM,KAAK,GAAG,WAAW,CAAC,uBAAuB,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAc,EAAoC;IAC3F,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACzC,OAAO,KAAK,CAAC;IACd,CAAC;IACD,MAAM,SAAS,GAAG,KAAgC,CAAC;IACnD,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,OAAO,SAAS,CAAC,SAAS,KAAK,QAAQ,IAAI,OAAO,SAAS,CAAC,WAAW,KAAK,QAAQ,CAAC;IAC7F,CAAC;IACD,OAAO,CACN,SAAS,CAAC,IAAI,KAAK,UAAU;QAC7B,OAAO,SAAS,CAAC,YAAY,KAAK,QAAQ;QAC1C,CAAC,SAAS,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,SAAS,CAAC,SAAS,KAAK,QAAQ,CAAC;QAC9E,CAAC,SAAS,CAAC,eAAe,KAAK,SAAS,IAAI,OAAO,SAAS,CAAC,eAAe,KAAK,QAAQ,CAAC;QAC1F,CAAC,SAAS,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,SAAS,CAAC,UAAU,KAAK,QAAQ,CAAC;QAChF,CAAC,SAAS,CAAC,gBAAgB,KAAK,SAAS,IAAI,OAAO,SAAS,CAAC,gBAAgB,KAAK,QAAQ,CAAC;QAC5F,CAAC,SAAS,CAAC,eAAe,KAAK,SAAS;YACvC,SAAS,CAAC,eAAe,KAAK,QAAQ;YACtC,SAAS,CAAC,eAAe,KAAK,aAAa;YAC3C,SAAS,CAAC,eAAe,KAAK,SAAS,CAAC;QACzC,CAAC,SAAS,CAAC,eAAe,KAAK,SAAS;YACvC,SAAS,CAAC,eAAe,KAAK,OAAO;YACrC,SAAS,CAAC,eAAe,KAAK,iBAAiB,CAAC,CACjD,CAAC;AAAA,CACF","sourcesContent":["import { closeSync, readFileSync } from \"node:fs\";\nimport type { AgentSessionMessageDeliveryMode, AgentSessionMessageSender } from \"../../core/agent-messages.js\";\nimport type { IdleEvictionMinutes } from \"../../core/session-action-store.js\";\n\nexport { SESSION_LEASE_OWNER_ID_ENV, SESSION_LEASES_ENABLED_ENV } from \"../../core/session-lease.js\";\n\nimport type { WorkerRosterEntry } from \"./agent-roster.js\";\nimport type { DaemonClientCapability, DaemonCommand, DaemonOutbound } from \"./daemon-protocol.js\";\n\nexport const DAEMON_WORKER_ROLE_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER\";\nexport const DAEMON_WORKER_TOKEN_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_TOKEN\";\nexport const DAEMON_WORKER_INSTANCE_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_INSTANCE_ID\";\nexport const DAEMON_WORKER_ACTIVE_SESSION_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_ACTIVE_SESSION_ID\";\nexport const DAEMON_WORKER_SUPERVISOR_SOCKET_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_SUPERVISOR_SOCKET\";\nexport const DAEMON_WORKER_RECOVERY_JOURNAL_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RECOVERY_JOURNAL\";\nexport const DAEMON_WORKER_STARTUP_GATE_FD_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_STARTUP_GATE_FD\";\nexport const DAEMON_WORKER_STARTUP_GATE_COMMIT = \"start\\n\";\nexport type DaemonWorkerLifecycle = \"starting\" | \"ready\" | \"recovering\" | \"stopping\" | \"failed\";\n\n// Worker->supervisor roster frames live outside the client-facing DaemonOutbound schema.\nexport type DaemonWorkerRosterOutbound =\n\t| {\n\t\t\ttype: \"roster_delta\";\n\t\t\tentries: WorkerRosterEntry[];\n\t\t\tremovedAgentIds?: string[];\n\t\t\tsnapshot?: true;\n\t }\n\t| { type: \"roster_heartbeat\" };\n\n/** Advertised by new workers in the worker_auth response; absent on legacy workers. */\nexport const DAEMON_WORKER_ROSTER_CAPABILITY = \"agent_roster\";\n\n/** Advertised in the worker_auth response by workers that accept peer transport grants. */\nexport const DAEMON_WORKER_PEER_TRANSPORT_CAPABILITY = \"peer_transport\";\n\n/** Idle keepalive cadence for worker->supervisor roster frames; the supervisor staleness threshold derives from it. */\nexport const ROSTER_HEARTBEAT_INTERVAL_MS = 15_000;\n\nexport type DaemonWorkerFrameHeader =\n\t| {\n\t\t\tkind: \"command\";\n\t\t\trequestId: string;\n\t\t\tcommandType: string;\n\t }\n\t| {\n\t\t\tkind: \"outbound\";\n\t\t\trequestId?: string;\n\t\t\toutboundType: DaemonOutbound[\"type\"] | DaemonWorkerRosterOutbound[\"type\"];\n\t\t\tactiveSessionId?: string;\n\t\t\tsnapshotId?: string;\n\t\t\tsessionEventType?: string;\n\t\t\tpayloadEncoding?: \"jsonl\" | \"assistant-delta\";\n\t\t\tsnapshotPurpose?: \"attach\" | \"replacement\" | \"catchup\";\n\t };\n\nexport interface DaemonRlmCapacityOrigin {\n\tsessionFile?: string;\n\tsessionId: string;\n}\n\nexport type DaemonRlmCapacityOperation =\n\t| (DaemonRlmCapacityOrigin & { op: \"status\" })\n\t| (DaemonRlmCapacityOrigin & { op: \"set\"; maxSubagents: number })\n\t| (DaemonRlmCapacityOrigin & { op: \"reserve\"; reservationId: string; residentRoot?: true })\n\t| { op: \"release\"; reservationId: string };\n\nexport interface DaemonRlmCapacityReservation extends DaemonRlmCapacityOrigin {\n\treservationId: string;\n\tresidentRoot?: true;\n}\n\nexport interface DaemonRlmCapacitySnapshot {\n\treservations: DaemonRlmCapacityReservation[];\n}\n\nexport function isDaemonRlmCapacitySnapshot(value: unknown): value is DaemonRlmCapacitySnapshot {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"reservations\" in value &&\n\t\tArray.isArray(value.reservations) &&\n\t\tvalue.reservations.every(\n\t\t\t(entry: unknown) =>\n\t\t\t\ttypeof entry === \"object\" &&\n\t\t\t\tentry !== null &&\n\t\t\t\t\"reservationId\" in entry &&\n\t\t\t\ttypeof entry.reservationId === \"string\" &&\n\t\t\t\tentry.reservationId.length > 0 &&\n\t\t\t\t\"sessionId\" in entry &&\n\t\t\t\ttypeof entry.sessionId === \"string\" &&\n\t\t\t\tentry.sessionId.length > 0 &&\n\t\t\t\t(!(\"sessionFile\" in entry) || entry.sessionFile === undefined || typeof entry.sessionFile === \"string\") &&\n\t\t\t\t(!(\"residentRoot\" in entry) || entry.residentRoot === undefined || entry.residentRoot === true),\n\t\t)\n\t);\n}\n\nexport type DaemonCreateCommand = Extract<DaemonCommand, { type: \"create\" }>;\n\nexport interface DurableDaemonCreateCommand {\n\ttype: \"create\";\n\tsessionPath?: string;\n\tnoSession?: boolean;\n}\n\nexport function durableDaemonCreateCommand(command: DaemonCreateCommand): DurableDaemonCreateCommand {\n\treturn {\n\t\ttype: \"create\",\n\t\t...(command.sessionPath !== undefined ? { sessionPath: command.sessionPath } : {}),\n\t\t...(command.noSession !== undefined ? { noSession: command.noSession } : {}),\n\t};\n}\n\n/**\n * A single-use, worker-memory-only admission for one direct peer, scoped to one active-session\n * slot (stable across switch_session/new_session/fork) of one worker incarnation. The session pin\n * is a routing/accident guard, not a privilege boundary: ticket holders already hold supervisor\n * access, which can attach to, switch, or kill any session.\n */\nexport interface DaemonWorkerPeerGrant {\n\tgrantId: string;\n\ttoken: string;\n\texpiresAt: string;\n\tpurpose: \"session_client\";\n\tworkerInstanceId: string;\n\tactiveSessionId: string;\n\tissuerGeneration: string;\n}\n\n/** Commands a direct peer may send before it holds an authenticated session role. */\nexport type DaemonPeerCommand = {\n\tid?: string;\n\ttype: \"peer_auth\";\n\tgrantId: string;\n\ttoken: string;\n\tworkerInstanceId: string;\n\tpurpose: \"session_client\";\n};\n\nexport type DaemonPeerCommandBody = Omit<DaemonPeerCommand, \"id\">;\n\nexport type DaemonWorkerCommand =\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_auth\";\n\t\t\ttoken: string;\n\t\t\tworkerInstanceId?: string;\n\t\t\tsupervisorGeneration: string;\n\t\t\tsupervisorPid: number;\n\t\t\tsupervisorProcessStartId?: string;\n\t\t\tsupervisorSocketPath: string;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_subscribe\";\n\t\t\tactiveSessionId: string;\n\t\t\tcapabilities?: readonly DaemonClientCapability[];\n\t\t\tsupportsExtensionUi?: boolean;\n\t }\n\t| { id?: string; type: \"worker_unsubscribe\"; activeSessionId: string }\n\t| { id?: string; type: \"worker_register_peer_transport\"; grant: DaemonWorkerPeerGrant }\n\t| { id?: string; type: \"worker_archive_and_shutdown\" }\n\t| { id?: string; type: \"worker_get_rlm_capacity\" }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_passivate_idle_children\";\n\t\t\tidleEvictionMinutes: IdleEvictionMinutes;\n\t\t\tnow: number;\n\t\t\tlimit: number;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_message\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tmessage: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_result\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tsummary: string;\n\t\t\tfindings: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| { id?: string; type: \"worker_prepare_update\" }\n\t| { id?: string; type: \"worker_commit_update\" }\n\t| { id?: string; type: \"worker_cancel_update\" };\n\nexport type DaemonWorkerCommandBody = DaemonWorkerCommand extends infer TCommand\n\t? TCommand extends { id?: string }\n\t\t? Omit<TCommand, \"id\">\n\t\t: never\n\t: never;\n\nexport interface DaemonWorkerDescriptor {\n\tversion: 1 | 2;\n\tworkerId: string;\n\tpid: number;\n\tprocessStartId?: string;\n\tsocketPath: string;\n\trecoveryJournalPath: string;\n\torphanProcessJournalPath?: string;\n\tsupervisorSocketPath: string;\n\tauthenticationToken: string;\n\tworkerInstanceId?: string;\n\trootActiveSessionId: string;\n\t/** Stable protocol client that owns this worker. Omitted for resident sessions. */\n\townerClientId?: string;\n\trootSessionId?: string;\n\tsessionFile?: string;\n\tsessionDir?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tlifecycle: DaemonWorkerLifecycle;\n\tcreateCommand: DurableDaemonCreateCommand;\n\tconsecutiveFailures: number;\n\t/** Durable intent written before root termination so replacement supervisors never recover it. */\n\tstopRequestedAt?: string;\n\t/** Complete the root's archived lifecycle state after its process has stopped. */\n\tarchiveOnStop?: boolean;\n\tlastFailureAt?: string;\n\tlastError?: string;\n}\n\nexport function durableDaemonWorkerDescriptor(descriptor: DaemonWorkerDescriptor): DaemonWorkerDescriptor {\n\tconst versionOneCreateCommand = descriptor.createCommand as unknown as { config?: unknown };\n\tconst versionOneConfig =\n\t\tdescriptor.version === 1 &&\n\t\ttypeof versionOneCreateCommand.config === \"object\" &&\n\t\tversionOneCreateCommand.config !== null\n\t\t\t? (versionOneCreateCommand.config as Record<string, unknown>)\n\t\t\t: undefined;\n\tconst sessionDir =\n\t\tdescriptor.sessionDir ??\n\t\t(typeof versionOneConfig?.sessionDir === \"string\" ? versionOneConfig.sessionDir : undefined);\n\treturn {\n\t\tversion: 2,\n\t\tworkerId: descriptor.workerId,\n\t\tpid: descriptor.pid,\n\t\t...(descriptor.processStartId !== undefined ? { processStartId: descriptor.processStartId } : {}),\n\t\tsocketPath: descriptor.socketPath,\n\t\trecoveryJournalPath: descriptor.recoveryJournalPath,\n\t\t...(descriptor.orphanProcessJournalPath !== undefined\n\t\t\t? { orphanProcessJournalPath: descriptor.orphanProcessJournalPath }\n\t\t\t: {}),\n\t\tsupervisorSocketPath: descriptor.supervisorSocketPath,\n\t\tauthenticationToken: descriptor.authenticationToken,\n\t\t...(descriptor.workerInstanceId !== undefined ? { workerInstanceId: descriptor.workerInstanceId } : {}),\n\t\trootActiveSessionId: descriptor.rootActiveSessionId,\n\t\t...(descriptor.ownerClientId !== undefined ? { ownerClientId: descriptor.ownerClientId } : {}),\n\t\t...(descriptor.rootSessionId !== undefined ? { rootSessionId: descriptor.rootSessionId } : {}),\n\t\t...(descriptor.sessionFile !== undefined ? { sessionFile: descriptor.sessionFile } : {}),\n\t\t...(sessionDir !== undefined ? { sessionDir } : {}),\n\t\tcreatedAt: descriptor.createdAt,\n\t\tupdatedAt: descriptor.updatedAt,\n\t\tlifecycle: descriptor.lifecycle,\n\t\tcreateCommand: durableDaemonCreateCommand(descriptor.createCommand),\n\t\tconsecutiveFailures: descriptor.consecutiveFailures,\n\t\t...(descriptor.stopRequestedAt !== undefined ? { stopRequestedAt: descriptor.stopRequestedAt } : {}),\n\t\t...(descriptor.archiveOnStop !== undefined ? { archiveOnStop: descriptor.archiveOnStop } : {}),\n\t\t...(descriptor.lastFailureAt !== undefined ? { lastFailureAt: descriptor.lastFailureAt } : {}),\n\t\t...(descriptor.lifecycle === \"failed\" ? { lastError: \"Waiting for a client with fresh runtime context\" } : {}),\n\t};\n}\n\nexport function isDaemonWorkerProcess(environment: NodeJS.ProcessEnv = process.env): boolean {\n\treturn environment[DAEMON_WORKER_ROLE_ENV] === \"1\";\n}\n\nexport function waitForDaemonWorkerStartupGate(environment: NodeJS.ProcessEnv = process.env): void {\n\tconst rawFd = environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tif (rawFd === undefined) {\n\t\treturn;\n\t}\n\tdelete environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tconst fd = Number(rawFd);\n\tif (!Number.isInteger(fd) || fd < 3) {\n\t\tthrow new Error(\"Daemon session worker has an invalid startup gate\");\n\t}\n\tlet marker: string;\n\ttry {\n\t\tmarker = readFileSync(fd, \"utf8\");\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\tif (marker !== DAEMON_WORKER_STARTUP_GATE_COMMIT) {\n\t\tthrow new Error(\"Daemon session worker startup was cancelled\");\n\t}\n}\n\nexport function daemonWorkerInstanceId(environment: NodeJS.ProcessEnv = process.env): string | undefined {\n\treturn environment[DAEMON_WORKER_INSTANCE_ID_ENV] || undefined;\n}\n\nexport function requireDaemonWorkerAuthenticationToken(environment: NodeJS.ProcessEnv = process.env): string {\n\tconst token = environment[DAEMON_WORKER_TOKEN_ENV];\n\tif (!token) {\n\t\tthrow new Error(\"Daemon session worker is missing its authentication token\");\n\t}\n\treturn token;\n}\n\nexport function isDaemonWorkerFrameHeader(value: unknown): value is DaemonWorkerFrameHeader {\n\tif (!value || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tif (candidate.kind === \"command\") {\n\t\treturn typeof candidate.requestId === \"string\" && typeof candidate.commandType === \"string\";\n\t}\n\treturn (\n\t\tcandidate.kind === \"outbound\" &&\n\t\ttypeof candidate.outboundType === \"string\" &&\n\t\t(candidate.requestId === undefined || typeof candidate.requestId === \"string\") &&\n\t\t(candidate.activeSessionId === undefined || typeof candidate.activeSessionId === \"string\") &&\n\t\t(candidate.snapshotId === undefined || typeof candidate.snapshotId === \"string\") &&\n\t\t(candidate.sessionEventType === undefined || typeof candidate.sessionEventType === \"string\") &&\n\t\t(candidate.snapshotPurpose === undefined ||\n\t\t\tcandidate.snapshotPurpose === \"attach\" ||\n\t\t\tcandidate.snapshotPurpose === \"replacement\" ||\n\t\t\tcandidate.snapshotPurpose === \"catchup\") &&\n\t\t(candidate.payloadEncoding === undefined ||\n\t\t\tcandidate.payloadEncoding === \"jsonl\" ||\n\t\t\tcandidate.payloadEncoding === \"assistant-delta\")\n\t);\n}\n"]}
1
+ {"version":3,"file":"daemon-worker-protocol.js","sourceRoot":"","sources":["../../../src/modes/daemon/daemon-worker-protocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { closeSync, readFileSync } from \"node:fs\";\nimport type { AgentSessionMessageDeliveryMode, AgentSessionMessageSender } from \"../../core/agent-messages.js\";\nimport type { IdleEvictionMinutes } from \"../../core/session-action-store.js\";\n\nexport { SESSION_LEASE_OWNER_ID_ENV, SESSION_LEASES_ENABLED_ENV } from \"../../core/session-lease.js\";\n\nimport type { WorkerRosterEntry } from \"./agent-roster.js\";\nimport type { DaemonClientCapability, DaemonCommand, DaemonOutbound } from \"./daemon-protocol.js\";\n\nexport const DAEMON_WORKER_ROLE_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER\";\nexport const DAEMON_WORKER_TOKEN_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_TOKEN\";\nexport const DAEMON_WORKER_INSTANCE_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_INSTANCE_ID\";\nexport const DAEMON_WORKER_ACTIVE_SESSION_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_ACTIVE_SESSION_ID\";\nexport const DAEMON_WORKER_SUPERVISOR_SOCKET_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_SUPERVISOR_SOCKET\";\nexport const DAEMON_WORKER_RECOVERY_JOURNAL_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RECOVERY_JOURNAL\";\nexport const DAEMON_WORKER_RLM_LEDGER_SESSION_DIR_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RLM_LEDGER_SESSION_DIR\";\nexport const DAEMON_WORKER_STARTUP_GATE_FD_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_STARTUP_GATE_FD\";\nexport const DAEMON_WORKER_STARTUP_GATE_COMMIT = \"start\\n\";\nexport type DaemonWorkerLifecycle = \"starting\" | \"ready\" | \"recovering\" | \"stopping\" | \"failed\";\n\n// Worker->supervisor roster frames live outside the client-facing DaemonOutbound schema.\nexport type DaemonWorkerRosterOutbound =\n\t| {\n\t\t\ttype: \"roster_delta\";\n\t\t\tentries: WorkerRosterEntry[];\n\t\t\tremovedAgentIds?: string[];\n\t\t\tsnapshot?: true;\n\t }\n\t| { type: \"roster_heartbeat\" };\n\n/** Advertised by new workers in the worker_auth response; absent on legacy workers. */\nexport const DAEMON_WORKER_ROSTER_CAPABILITY = \"agent_roster\";\n\n/** Advertised in the worker_auth response by workers that accept peer transport grants. */\nexport const DAEMON_WORKER_PEER_TRANSPORT_CAPABILITY = \"peer_transport\";\n\n/** Idle keepalive cadence for worker->supervisor roster frames; the supervisor staleness threshold derives from it. */\nexport const ROSTER_HEARTBEAT_INTERVAL_MS = 15_000;\n\nexport type DaemonWorkerFrameHeader =\n\t| {\n\t\t\tkind: \"command\";\n\t\t\trequestId: string;\n\t\t\tcommandType: string;\n\t }\n\t| {\n\t\t\tkind: \"outbound\";\n\t\t\trequestId?: string;\n\t\t\toutboundType: DaemonOutbound[\"type\"] | DaemonWorkerRosterOutbound[\"type\"];\n\t\t\tactiveSessionId?: string;\n\t\t\tsnapshotId?: string;\n\t\t\tsessionEventType?: string;\n\t\t\tpayloadEncoding?: \"jsonl\" | \"assistant-delta\";\n\t\t\tsnapshotPurpose?: \"attach\" | \"replacement\" | \"catchup\";\n\t };\n\nexport interface DaemonRlmCapacityOrigin {\n\tsessionFile?: string;\n\tsessionId: string;\n}\n\nexport type DaemonRlmCapacityOperation =\n\t| (DaemonRlmCapacityOrigin & { op: \"status\" })\n\t| (DaemonRlmCapacityOrigin & { op: \"set\"; maxSubagents: number })\n\t| (DaemonRlmCapacityOrigin & { op: \"reserve\"; reservationId: string; residentRoot?: true })\n\t| { op: \"release\"; reservationId: string };\n\nexport interface DaemonRlmCapacityReservation extends DaemonRlmCapacityOrigin {\n\treservationId: string;\n\tresidentRoot?: true;\n}\n\nexport interface DaemonRlmCapacitySnapshot {\n\treservations: DaemonRlmCapacityReservation[];\n}\n\nexport function isDaemonRlmCapacitySnapshot(value: unknown): value is DaemonRlmCapacitySnapshot {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"reservations\" in value &&\n\t\tArray.isArray(value.reservations) &&\n\t\tvalue.reservations.every(\n\t\t\t(entry: unknown) =>\n\t\t\t\ttypeof entry === \"object\" &&\n\t\t\t\tentry !== null &&\n\t\t\t\t\"reservationId\" in entry &&\n\t\t\t\ttypeof entry.reservationId === \"string\" &&\n\t\t\t\tentry.reservationId.length > 0 &&\n\t\t\t\t\"sessionId\" in entry &&\n\t\t\t\ttypeof entry.sessionId === \"string\" &&\n\t\t\t\tentry.sessionId.length > 0 &&\n\t\t\t\t(!(\"sessionFile\" in entry) || entry.sessionFile === undefined || typeof entry.sessionFile === \"string\") &&\n\t\t\t\t(!(\"residentRoot\" in entry) || entry.residentRoot === undefined || entry.residentRoot === true),\n\t\t)\n\t);\n}\n\nexport type DaemonCreateCommand = Extract<DaemonCommand, { type: \"create\" }>;\n\nexport interface DurableDaemonCreateCommand {\n\ttype: \"create\";\n\tsessionPath?: string;\n\tnoSession?: boolean;\n}\n\nexport function durableDaemonCreateCommand(command: DaemonCreateCommand): DurableDaemonCreateCommand {\n\treturn {\n\t\ttype: \"create\",\n\t\t...(command.sessionPath !== undefined ? { sessionPath: command.sessionPath } : {}),\n\t\t...(command.noSession !== undefined ? { noSession: command.noSession } : {}),\n\t};\n}\n\n/**\n * A single-use, worker-memory-only admission for one direct peer, scoped to one active-session\n * slot (stable across switch_session/new_session/fork) of one worker incarnation. The session pin\n * is a routing/accident guard, not a privilege boundary: ticket holders already hold supervisor\n * access, which can attach to, switch, or kill any session.\n */\nexport interface DaemonWorkerPeerGrant {\n\tgrantId: string;\n\ttoken: string;\n\texpiresAt: string;\n\tpurpose: \"session_client\";\n\tworkerInstanceId: string;\n\tactiveSessionId: string;\n\tissuerGeneration: string;\n}\n\n/** Commands a direct peer may send before it holds an authenticated session role. */\nexport type DaemonPeerCommand = {\n\tid?: string;\n\ttype: \"peer_auth\";\n\tgrantId: string;\n\ttoken: string;\n\tworkerInstanceId: string;\n\tpurpose: \"session_client\";\n};\n\nexport type DaemonPeerCommandBody = Omit<DaemonPeerCommand, \"id\">;\n\nexport type DaemonWorkerCommand =\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_auth\";\n\t\t\ttoken: string;\n\t\t\tworkerInstanceId?: string;\n\t\t\tsupervisorGeneration: string;\n\t\t\tsupervisorPid: number;\n\t\t\tsupervisorProcessStartId?: string;\n\t\t\tsupervisorSocketPath: string;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_subscribe\";\n\t\t\tactiveSessionId: string;\n\t\t\tcapabilities?: readonly DaemonClientCapability[];\n\t\t\tsupportsExtensionUi?: boolean;\n\t }\n\t| { id?: string; type: \"worker_unsubscribe\"; activeSessionId: string }\n\t| { id?: string; type: \"worker_register_peer_transport\"; grant: DaemonWorkerPeerGrant }\n\t| { id?: string; type: \"worker_archive_and_shutdown\" }\n\t| { id?: string; type: \"worker_get_rlm_capacity\" }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_passivate_idle_children\";\n\t\t\tidleEvictionMinutes: IdleEvictionMinutes;\n\t\t\tnow: number;\n\t\t\tlimit: number;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_message\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tmessage: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_result\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tsummary: string;\n\t\t\tfindings: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| { id?: string; type: \"worker_prepare_update\" }\n\t| { id?: string; type: \"worker_commit_update\" }\n\t| { id?: string; type: \"worker_cancel_update\" };\n\nexport type DaemonWorkerCommandBody = DaemonWorkerCommand extends infer TCommand\n\t? TCommand extends { id?: string }\n\t\t? Omit<TCommand, \"id\">\n\t\t: never\n\t: never;\n\nexport interface DaemonWorkerDescriptor {\n\tversion: 1 | 2;\n\tworkerId: string;\n\tpid: number;\n\tprocessStartId?: string;\n\tsocketPath: string;\n\trecoveryJournalPath: string;\n\torphanProcessJournalPath?: string;\n\tsupervisorSocketPath: string;\n\tauthenticationToken: string;\n\tworkerInstanceId?: string;\n\trootActiveSessionId: string;\n\t/** Stable protocol client that owns this worker. Omitted for resident sessions. */\n\townerClientId?: string;\n\trootSessionId?: string;\n\tsessionFile?: string;\n\tsessionDir?: string;\n\t/** Supervisor-assigned journal scope, independent of transcript storage. */\n\trlmLedgerSessionDir?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tlifecycle: DaemonWorkerLifecycle;\n\tcreateCommand: DurableDaemonCreateCommand;\n\tconsecutiveFailures: number;\n\t/** Durable intent written before root termination so replacement supervisors never recover it. */\n\tstopRequestedAt?: string;\n\t/** Complete the root's archived lifecycle state after its process has stopped. */\n\tarchiveOnStop?: boolean;\n\tlastFailureAt?: string;\n\tlastError?: string;\n}\n\nexport function durableDaemonWorkerDescriptor(descriptor: DaemonWorkerDescriptor): DaemonWorkerDescriptor {\n\tconst versionOneCreateCommand = descriptor.createCommand as unknown as { config?: unknown };\n\tconst versionOneConfig =\n\t\tdescriptor.version === 1 &&\n\t\ttypeof versionOneCreateCommand.config === \"object\" &&\n\t\tversionOneCreateCommand.config !== null\n\t\t\t? (versionOneCreateCommand.config as Record<string, unknown>)\n\t\t\t: undefined;\n\tconst sessionDir =\n\t\tdescriptor.sessionDir ??\n\t\t(typeof versionOneConfig?.sessionDir === \"string\" ? versionOneConfig.sessionDir : undefined);\n\treturn {\n\t\tversion: 2,\n\t\tworkerId: descriptor.workerId,\n\t\tpid: descriptor.pid,\n\t\t...(descriptor.processStartId !== undefined ? { processStartId: descriptor.processStartId } : {}),\n\t\tsocketPath: descriptor.socketPath,\n\t\trecoveryJournalPath: descriptor.recoveryJournalPath,\n\t\t...(descriptor.orphanProcessJournalPath !== undefined\n\t\t\t? { orphanProcessJournalPath: descriptor.orphanProcessJournalPath }\n\t\t\t: {}),\n\t\tsupervisorSocketPath: descriptor.supervisorSocketPath,\n\t\tauthenticationToken: descriptor.authenticationToken,\n\t\t...(descriptor.workerInstanceId !== undefined ? { workerInstanceId: descriptor.workerInstanceId } : {}),\n\t\trootActiveSessionId: descriptor.rootActiveSessionId,\n\t\t...(descriptor.ownerClientId !== undefined ? { ownerClientId: descriptor.ownerClientId } : {}),\n\t\t...(descriptor.rootSessionId !== undefined ? { rootSessionId: descriptor.rootSessionId } : {}),\n\t\t...(descriptor.sessionFile !== undefined ? { sessionFile: descriptor.sessionFile } : {}),\n\t\t...(sessionDir !== undefined ? { sessionDir } : {}),\n\t\t...(descriptor.rlmLedgerSessionDir !== undefined ? { rlmLedgerSessionDir: descriptor.rlmLedgerSessionDir } : {}),\n\t\tcreatedAt: descriptor.createdAt,\n\t\tupdatedAt: descriptor.updatedAt,\n\t\tlifecycle: descriptor.lifecycle,\n\t\tcreateCommand: durableDaemonCreateCommand(descriptor.createCommand),\n\t\tconsecutiveFailures: descriptor.consecutiveFailures,\n\t\t...(descriptor.stopRequestedAt !== undefined ? { stopRequestedAt: descriptor.stopRequestedAt } : {}),\n\t\t...(descriptor.archiveOnStop !== undefined ? { archiveOnStop: descriptor.archiveOnStop } : {}),\n\t\t...(descriptor.lastFailureAt !== undefined ? { lastFailureAt: descriptor.lastFailureAt } : {}),\n\t\t...(descriptor.lifecycle === \"failed\" ? { lastError: \"Waiting for a client with fresh runtime context\" } : {}),\n\t};\n}\n\nexport function isDaemonWorkerProcess(environment: NodeJS.ProcessEnv = process.env): boolean {\n\treturn environment[DAEMON_WORKER_ROLE_ENV] === \"1\";\n}\n\nexport function waitForDaemonWorkerStartupGate(environment: NodeJS.ProcessEnv = process.env): void {\n\tconst rawFd = environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tif (rawFd === undefined) {\n\t\treturn;\n\t}\n\tdelete environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tconst fd = Number(rawFd);\n\tif (!Number.isInteger(fd) || fd < 3) {\n\t\tthrow new Error(\"Daemon session worker has an invalid startup gate\");\n\t}\n\tlet marker: string;\n\ttry {\n\t\tmarker = readFileSync(fd, \"utf8\");\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\tif (marker !== DAEMON_WORKER_STARTUP_GATE_COMMIT) {\n\t\tthrow new Error(\"Daemon session worker startup was cancelled\");\n\t}\n}\n\nexport function daemonWorkerInstanceId(environment: NodeJS.ProcessEnv = process.env): string | undefined {\n\treturn environment[DAEMON_WORKER_INSTANCE_ID_ENV] || undefined;\n}\n\nexport function requireDaemonWorkerAuthenticationToken(environment: NodeJS.ProcessEnv = process.env): string {\n\tconst token = environment[DAEMON_WORKER_TOKEN_ENV];\n\tif (!token) {\n\t\tthrow new Error(\"Daemon session worker is missing its authentication token\");\n\t}\n\treturn token;\n}\n\nexport function isDaemonWorkerFrameHeader(value: unknown): value is DaemonWorkerFrameHeader {\n\tif (!value || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tif (candidate.kind === \"command\") {\n\t\treturn typeof candidate.requestId === \"string\" && typeof candidate.commandType === \"string\";\n\t}\n\treturn (\n\t\tcandidate.kind === \"outbound\" &&\n\t\ttypeof candidate.outboundType === \"string\" &&\n\t\t(candidate.requestId === undefined || typeof candidate.requestId === \"string\") &&\n\t\t(candidate.activeSessionId === undefined || typeof candidate.activeSessionId === \"string\") &&\n\t\t(candidate.snapshotId === undefined || typeof candidate.snapshotId === \"string\") &&\n\t\t(candidate.sessionEventType === undefined || typeof candidate.sessionEventType === \"string\") &&\n\t\t(candidate.snapshotPurpose === undefined ||\n\t\t\tcandidate.snapshotPurpose === \"attach\" ||\n\t\t\tcandidate.snapshotPurpose === \"replacement\" ||\n\t\t\tcandidate.snapshotPurpose === \"catchup\") &&\n\t\t(candidate.payloadEncoding === undefined ||\n\t\t\tcandidate.payloadEncoding === \"jsonl\" ||\n\t\t\tcandidate.payloadEncoding === \"assistant-delta\")\n\t);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"print-mode.d.ts","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAK5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAGnE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;CAC/B;AAgBD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/G;AAED,wBAAsB,0BAA0B,CAC/C,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE,gBAAgB,GACvB,OAAO,CAAC,MAAM,CAAC,CAEjB","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `pi -p \"prompt\"` - text output\n * - `pi --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { ImageContent } from \"@ponythewhite/base-context-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.js\";\nimport { type AgentAutonomousStatus, type AutonomousLimitReason, autonomousLimitReason } from \"../core/autonomous.js\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.js\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.js\";\nimport { InProcessAgentConnection } from \"./agent-connection/in-process-agent-connection.js\";\nimport type { AgentConnection } from \"./agent-connection/types.js\";\nimport { latestAutonomousGateAttempt, selectHeadlessTerminalResult } from \"./headless-completion.js\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\nfunction describeAutonomousLimit(status: AgentAutonomousStatus, reason: AutonomousLimitReason): string {\n\tif (reason === \"maxContinuations\") {\n\t\treturn `maxContinuations reached (${status.continuationsUsed}/${status.limits.maxContinuations})`;\n\t}\n\tif (reason === \"maxTurns\") {\n\t\treturn `maxTurns reached (${status.turnsUsed}/${status.limits.maxTurns})`;\n\t}\n\tif (reason === \"maxTokens\") {\n\t\treturn `maxTokens reached (${status.tokensUsed}/${status.limits.maxTokens})`;\n\t}\n\tconst elapsed = status.startedAt === undefined ? 0 : Math.max(0, Date.now() - status.startedAt);\n\treturn `timeoutMs reached (${elapsed}/${status.limits.timeoutMs})`;\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst connection = new InProcessAgentConnection(runtimeHost);\n\treturn runPrintModeWithConnectionInternal(connection, options, () => connection.bindHeadlessExtensions());\n}\n\nexport async function runPrintModeWithConnection(\n\tconnection: AgentConnection,\n\toptions: PrintModeOptions,\n): Promise<number> {\n\treturn runPrintModeWithConnectionInternal(connection, options);\n}\n\nasync function runPrintModeWithConnectionInternal(\n\tconnection: AgentConnection,\n\toptions: PrintModeOptions,\n\tbindHeadlessExtensions?: () => Promise<void>,\n): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet disposed = false;\n\tlet unsubscribe: (() => void) | undefined;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst disposeConnection = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tawait connection.dispose();\n\t};\n\n\tfor (const signal of [\n\t\t\"SIGINT\",\n\t\t\"SIGTERM\",\n\t\t...(process.platform === \"win32\" ? [] : [\"SIGHUP\"]),\n\t] as NodeJS.Signals[]) {\n\t\tconst handler = () => {\n\t\t\tkillTrackedDetachedChildren();\n\t\t\tvoid disposeConnection().finally(() => {\n\t\t\t\tconst exitCode = signal === \"SIGINT\" ? 130 : signal === \"SIGHUP\" ? 129 : 143;\n\t\t\t\tprocess.exit(exitCode);\n\t\t\t});\n\t\t};\n\t\tprocess.on(signal, handler);\n\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t}\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = await connection.getSessionHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tunsubscribe = connection.subscribe((event) => {\n\t\t\tif (mode === \"json\" && event.type === \"session_event\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event.event)}\\n`);\n\t\t\t}\n\t\t\tif (event.type === \"extension_error\") {\n\t\t\t\tconsole.error(`Extension error (${event.extensionPath}): ${event.error}`);\n\t\t\t}\n\t\t});\n\t\tawait bindHeadlessExtensions?.();\n\n\t\tif (initialMessage) {\n\t\t\tawait connection.promptAndWait(initialMessage, { images: initialImages });\n\t\t}\n\t\tfor (const message of messages) {\n\t\t\tawait connection.promptAndWait(message);\n\t\t}\n\n\t\tconst autonomousStatus = await connection.waitForHeadlessCompletion();\n\t\tif (mode === \"text\") {\n\t\t\tconst { primary, compactionOutcomes } = selectHeadlessTerminalResult(await connection.getMessages());\n\t\t\tif (primary?.role === \"assistant\") {\n\t\t\t\tif (primary.stopReason === \"error\" || primary.stopReason === \"aborted\") {\n\t\t\t\t\tconsole.error(primary.errorMessage || `Request ${primary.stopReason}`);\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\tfor (const content of primary.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (primary) {\n\t\t\t\twriteRawStdout(`${primary.content}\\n`);\n\t\t\t\tif (!primary.details.success || primary.details.severity === \"error\") exitCode = 1;\n\t\t\t}\n\t\t\tfor (const outcome of compactionOutcomes) {\n\t\t\t\tconsole.error(outcome.content);\n\t\t\t\tif (outcome.details.outcome === \"failed\") exitCode = 1;\n\t\t\t}\n\t\t}\n\n\t\tconst autonomousLimit = autonomousLimitReason(autonomousStatus);\n\t\tif (autonomousStatus.enabled && autonomousStatus.gates.commands.length > 0 && autonomousStatus.lastGateFailure) {\n\t\t\tconst limitText = autonomousLimit\n\t\t\t\t? `; autonomous limit reached: ${describeAutonomousLimit(autonomousStatus, autonomousLimit)}`\n\t\t\t\t: \"\";\n\t\t\tconsole.error(\n\t\t\t\t`Autonomous quality gate still failing after attempt ${latestAutonomousGateAttempt(autonomousStatus)}/${autonomousStatus.gates.maxRetries}: ${autonomousStatus.lastGateFailure.exitText}${limitText}`,\n\t\t\t);\n\t\t\texitCode = 1;\n\t\t} else if (autonomousStatus.enabled && autonomousStatus.gates.commands.length === 0 && autonomousLimit) {\n\t\t\tconsole.error(\n\t\t\t\t`Autonomous run stopped before terminal evidence; ${describeAutonomousLimit(autonomousStatus, autonomousLimit)}`,\n\t\t\t);\n\t\t\texitCode = 1;\n\t\t}\n\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\tconsole.error(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeConnection();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
1
+ {"version":3,"file":"print-mode.d.ts","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAK5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAGnE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;CAC/B;AAgBD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/G;AAED,wBAAsB,0BAA0B,CAC/C,UAAU,EAAE,eAAe,EAC3B,OAAO,EAAE,gBAAgB,GACvB,OAAO,CAAC,MAAM,CAAC,CAEjB","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `pi -p \"prompt\"` - text output\n * - `pi --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { ImageContent } from \"@ponythewhite/base-context-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.js\";\nimport { type AgentAutonomousStatus, type AutonomousLimitReason, autonomousLimitReason } from \"../core/autonomous.js\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.js\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.js\";\nimport { InProcessAgentConnection } from \"./agent-connection/in-process-agent-connection.js\";\nimport type { AgentConnection } from \"./agent-connection/types.js\";\nimport { latestAutonomousGateAttempt, selectHeadlessTerminalResult } from \"./headless-completion.js\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\nfunction describeAutonomousLimit(status: AgentAutonomousStatus, reason: AutonomousLimitReason): string {\n\tif (reason === \"maxContinuations\") {\n\t\treturn `maxContinuations reached (${status.continuationsUsed}/${status.limits.maxContinuations})`;\n\t}\n\tif (reason === \"maxTurns\") {\n\t\treturn `maxTurns reached (${status.turnsUsed}/${status.limits.maxTurns})`;\n\t}\n\tif (reason === \"maxTokens\") {\n\t\treturn `maxTokens reached (${status.tokensUsed}/${status.limits.maxTokens})`;\n\t}\n\tconst elapsed = status.startedAt === undefined ? 0 : Math.max(0, Date.now() - status.startedAt);\n\treturn `timeoutMs reached (${elapsed}/${status.limits.timeoutMs})`;\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst connection = new InProcessAgentConnection(runtimeHost);\n\treturn runPrintModeWithConnectionInternal(connection, options, () => connection.bindHeadlessExtensions());\n}\n\nexport async function runPrintModeWithConnection(\n\tconnection: AgentConnection,\n\toptions: PrintModeOptions,\n): Promise<number> {\n\treturn runPrintModeWithConnectionInternal(connection, options);\n}\n\nasync function runPrintModeWithConnectionInternal(\n\tconnection: AgentConnection,\n\toptions: PrintModeOptions,\n\tbindHeadlessExtensions?: () => Promise<void>,\n): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet disposed = false;\n\tlet unsubscribe: (() => void) | undefined;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst disposeConnection = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tawait connection.dispose();\n\t};\n\n\tfor (const signal of [\n\t\t\"SIGINT\",\n\t\t\"SIGTERM\",\n\t\t...(process.platform === \"win32\" ? [] : [\"SIGHUP\"]),\n\t] as NodeJS.Signals[]) {\n\t\tconst handler = () => {\n\t\t\tkillTrackedDetachedChildren();\n\t\t\tvoid disposeConnection().finally(() => {\n\t\t\t\tconst exitCode = signal === \"SIGINT\" ? 130 : signal === \"SIGHUP\" ? 129 : 143;\n\t\t\t\tprocess.exit(exitCode);\n\t\t\t});\n\t\t};\n\t\tprocess.on(signal, handler);\n\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t}\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = await connection.getSessionHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tunsubscribe = connection.subscribe((event) => {\n\t\t\tif (mode === \"json\" && event.type === \"session_event\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event.event)}\\n`);\n\t\t\t}\n\t\t\tif (event.type === \"extension_error\") {\n\t\t\t\tconsole.error(`Extension error (${event.extensionPath}): ${event.error}`);\n\t\t\t}\n\t\t});\n\t\tawait bindHeadlessExtensions?.();\n\n\t\tif (initialMessage) {\n\t\t\tawait connection.promptAndWait(initialMessage, { images: initialImages });\n\t\t}\n\t\tfor (const message of messages) {\n\t\t\tawait connection.promptAndWait(message);\n\t\t}\n\n\t\tconst autonomousStatus = await connection.waitForHeadlessCompletion();\n\t\tconst { primary, compactionOutcomes } = selectHeadlessTerminalResult(await connection.getMessages());\n\t\tif (primary?.role === \"assistant\") {\n\t\t\tif (primary.stopReason === \"error\" || primary.stopReason === \"aborted\") {\n\t\t\t\tconsole.error(primary.errorMessage || `Request ${primary.stopReason}`);\n\t\t\t\texitCode = 1;\n\t\t\t} else if (mode === \"text\") {\n\t\t\t\tfor (const content of primary.content) {\n\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (primary) {\n\t\t\tif (mode === \"text\") writeRawStdout(`${primary.content}\\n`);\n\t\t\tif (!primary.details.success || primary.details.severity === \"error\") exitCode = 1;\n\t\t}\n\t\tfor (const outcome of compactionOutcomes) {\n\t\t\tif (mode === \"text\" || outcome.details.outcome === \"failed\") console.error(outcome.content);\n\t\t\tif (outcome.details.outcome === \"failed\") exitCode = 1;\n\t\t}\n\n\t\tconst autonomousLimit = autonomousLimitReason(autonomousStatus);\n\t\tif (autonomousStatus.enabled && autonomousStatus.gates.commands.length > 0 && autonomousStatus.lastGateFailure) {\n\t\t\tconst limitText = autonomousLimit\n\t\t\t\t? `; autonomous limit reached: ${describeAutonomousLimit(autonomousStatus, autonomousLimit)}`\n\t\t\t\t: \"\";\n\t\t\tconsole.error(\n\t\t\t\t`Autonomous quality gate still failing after attempt ${latestAutonomousGateAttempt(autonomousStatus)}/${autonomousStatus.gates.maxRetries}: ${autonomousStatus.lastGateFailure.exitText}${limitText}`,\n\t\t\t);\n\t\t\texitCode = 1;\n\t\t} else if (\n\t\t\tautonomousStatus.enabled &&\n\t\t\tautonomousLimit &&\n\t\t\t(autonomousStatus.gates.commands.length === 0 ||\n\t\t\t\tautonomousStatus.gates.commands.some((command) => autonomousStatus.gateAttempts[command] !== 0))\n\t\t) {\n\t\t\tconsole.error(\n\t\t\t\t`Autonomous run stopped before terminal evidence; ${describeAutonomousLimit(autonomousStatus, autonomousLimit)}`,\n\t\t\t);\n\t\t\texitCode = 1;\n\t\t}\n\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\tconsole.error(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeConnection();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
@@ -85,31 +85,31 @@ async function runPrintModeWithConnectionInternal(connection, options, bindHeadl
85
85
  await connection.promptAndWait(message);
86
86
  }
87
87
  const autonomousStatus = await connection.waitForHeadlessCompletion();
88
- if (mode === "text") {
89
- const { primary, compactionOutcomes } = selectHeadlessTerminalResult(await connection.getMessages());
90
- if (primary?.role === "assistant") {
91
- if (primary.stopReason === "error" || primary.stopReason === "aborted") {
92
- console.error(primary.errorMessage || `Request ${primary.stopReason}`);
93
- exitCode = 1;
94
- }
95
- else {
96
- for (const content of primary.content) {
97
- if (content.type === "text") {
98
- writeRawStdout(`${content.text}\n`);
99
- }
88
+ const { primary, compactionOutcomes } = selectHeadlessTerminalResult(await connection.getMessages());
89
+ if (primary?.role === "assistant") {
90
+ if (primary.stopReason === "error" || primary.stopReason === "aborted") {
91
+ console.error(primary.errorMessage || `Request ${primary.stopReason}`);
92
+ exitCode = 1;
93
+ }
94
+ else if (mode === "text") {
95
+ for (const content of primary.content) {
96
+ if (content.type === "text") {
97
+ writeRawStdout(`${content.text}\n`);
100
98
  }
101
99
  }
102
100
  }
103
- else if (primary) {
101
+ }
102
+ else if (primary) {
103
+ if (mode === "text")
104
104
  writeRawStdout(`${primary.content}\n`);
105
- if (!primary.details.success || primary.details.severity === "error")
106
- exitCode = 1;
107
- }
108
- for (const outcome of compactionOutcomes) {
105
+ if (!primary.details.success || primary.details.severity === "error")
106
+ exitCode = 1;
107
+ }
108
+ for (const outcome of compactionOutcomes) {
109
+ if (mode === "text" || outcome.details.outcome === "failed")
109
110
  console.error(outcome.content);
110
- if (outcome.details.outcome === "failed")
111
- exitCode = 1;
112
- }
111
+ if (outcome.details.outcome === "failed")
112
+ exitCode = 1;
113
113
  }
114
114
  const autonomousLimit = autonomousLimitReason(autonomousStatus);
115
115
  if (autonomousStatus.enabled && autonomousStatus.gates.commands.length > 0 && autonomousStatus.lastGateFailure) {
@@ -119,7 +119,10 @@ async function runPrintModeWithConnectionInternal(connection, options, bindHeadl
119
119
  console.error(`Autonomous quality gate still failing after attempt ${latestAutonomousGateAttempt(autonomousStatus)}/${autonomousStatus.gates.maxRetries}: ${autonomousStatus.lastGateFailure.exitText}${limitText}`);
120
120
  exitCode = 1;
121
121
  }
122
- else if (autonomousStatus.enabled && autonomousStatus.gates.commands.length === 0 && autonomousLimit) {
122
+ else if (autonomousStatus.enabled &&
123
+ autonomousLimit &&
124
+ (autonomousStatus.gates.commands.length === 0 ||
125
+ autonomousStatus.gates.commands.some((command) => autonomousStatus.gateAttempts[command] !== 0))) {
123
126
  console.error(`Autonomous run stopped before terminal evidence; ${describeAutonomousLimit(autonomousStatus, autonomousLimit)}`);
124
127
  exitCode = 1;
125
128
  }
@@ -1 +1 @@
1
- {"version":3,"file":"print-mode.js","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `pi -p \"prompt\"` - text output\n * - `pi --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { ImageContent } from \"@ponythewhite/base-context-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.js\";\nimport { type AgentAutonomousStatus, type AutonomousLimitReason, autonomousLimitReason } from \"../core/autonomous.js\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.js\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.js\";\nimport { InProcessAgentConnection } from \"./agent-connection/in-process-agent-connection.js\";\nimport type { AgentConnection } from \"./agent-connection/types.js\";\nimport { latestAutonomousGateAttempt, selectHeadlessTerminalResult } from \"./headless-completion.js\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\nfunction describeAutonomousLimit(status: AgentAutonomousStatus, reason: AutonomousLimitReason): string {\n\tif (reason === \"maxContinuations\") {\n\t\treturn `maxContinuations reached (${status.continuationsUsed}/${status.limits.maxContinuations})`;\n\t}\n\tif (reason === \"maxTurns\") {\n\t\treturn `maxTurns reached (${status.turnsUsed}/${status.limits.maxTurns})`;\n\t}\n\tif (reason === \"maxTokens\") {\n\t\treturn `maxTokens reached (${status.tokensUsed}/${status.limits.maxTokens})`;\n\t}\n\tconst elapsed = status.startedAt === undefined ? 0 : Math.max(0, Date.now() - status.startedAt);\n\treturn `timeoutMs reached (${elapsed}/${status.limits.timeoutMs})`;\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst connection = new InProcessAgentConnection(runtimeHost);\n\treturn runPrintModeWithConnectionInternal(connection, options, () => connection.bindHeadlessExtensions());\n}\n\nexport async function runPrintModeWithConnection(\n\tconnection: AgentConnection,\n\toptions: PrintModeOptions,\n): Promise<number> {\n\treturn runPrintModeWithConnectionInternal(connection, options);\n}\n\nasync function runPrintModeWithConnectionInternal(\n\tconnection: AgentConnection,\n\toptions: PrintModeOptions,\n\tbindHeadlessExtensions?: () => Promise<void>,\n): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet disposed = false;\n\tlet unsubscribe: (() => void) | undefined;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst disposeConnection = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tawait connection.dispose();\n\t};\n\n\tfor (const signal of [\n\t\t\"SIGINT\",\n\t\t\"SIGTERM\",\n\t\t...(process.platform === \"win32\" ? [] : [\"SIGHUP\"]),\n\t] as NodeJS.Signals[]) {\n\t\tconst handler = () => {\n\t\t\tkillTrackedDetachedChildren();\n\t\t\tvoid disposeConnection().finally(() => {\n\t\t\t\tconst exitCode = signal === \"SIGINT\" ? 130 : signal === \"SIGHUP\" ? 129 : 143;\n\t\t\t\tprocess.exit(exitCode);\n\t\t\t});\n\t\t};\n\t\tprocess.on(signal, handler);\n\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t}\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = await connection.getSessionHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tunsubscribe = connection.subscribe((event) => {\n\t\t\tif (mode === \"json\" && event.type === \"session_event\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event.event)}\\n`);\n\t\t\t}\n\t\t\tif (event.type === \"extension_error\") {\n\t\t\t\tconsole.error(`Extension error (${event.extensionPath}): ${event.error}`);\n\t\t\t}\n\t\t});\n\t\tawait bindHeadlessExtensions?.();\n\n\t\tif (initialMessage) {\n\t\t\tawait connection.promptAndWait(initialMessage, { images: initialImages });\n\t\t}\n\t\tfor (const message of messages) {\n\t\t\tawait connection.promptAndWait(message);\n\t\t}\n\n\t\tconst autonomousStatus = await connection.waitForHeadlessCompletion();\n\t\tif (mode === \"text\") {\n\t\t\tconst { primary, compactionOutcomes } = selectHeadlessTerminalResult(await connection.getMessages());\n\t\t\tif (primary?.role === \"assistant\") {\n\t\t\t\tif (primary.stopReason === \"error\" || primary.stopReason === \"aborted\") {\n\t\t\t\t\tconsole.error(primary.errorMessage || `Request ${primary.stopReason}`);\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\tfor (const content of primary.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (primary) {\n\t\t\t\twriteRawStdout(`${primary.content}\\n`);\n\t\t\t\tif (!primary.details.success || primary.details.severity === \"error\") exitCode = 1;\n\t\t\t}\n\t\t\tfor (const outcome of compactionOutcomes) {\n\t\t\t\tconsole.error(outcome.content);\n\t\t\t\tif (outcome.details.outcome === \"failed\") exitCode = 1;\n\t\t\t}\n\t\t}\n\n\t\tconst autonomousLimit = autonomousLimitReason(autonomousStatus);\n\t\tif (autonomousStatus.enabled && autonomousStatus.gates.commands.length > 0 && autonomousStatus.lastGateFailure) {\n\t\t\tconst limitText = autonomousLimit\n\t\t\t\t? `; autonomous limit reached: ${describeAutonomousLimit(autonomousStatus, autonomousLimit)}`\n\t\t\t\t: \"\";\n\t\t\tconsole.error(\n\t\t\t\t`Autonomous quality gate still failing after attempt ${latestAutonomousGateAttempt(autonomousStatus)}/${autonomousStatus.gates.maxRetries}: ${autonomousStatus.lastGateFailure.exitText}${limitText}`,\n\t\t\t);\n\t\t\texitCode = 1;\n\t\t} else if (autonomousStatus.enabled && autonomousStatus.gates.commands.length === 0 && autonomousLimit) {\n\t\t\tconsole.error(\n\t\t\t\t`Autonomous run stopped before terminal evidence; ${describeAutonomousLimit(autonomousStatus, autonomousLimit)}`,\n\t\t\t);\n\t\t\texitCode = 1;\n\t\t}\n\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\tconsole.error(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeConnection();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
1
+ {"version":3,"file":"print-mode.js","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `pi -p \"prompt\"` - text output\n * - `pi --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { ImageContent } from \"@ponythewhite/base-context-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.js\";\nimport { type AgentAutonomousStatus, type AutonomousLimitReason, autonomousLimitReason } from \"../core/autonomous.js\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.js\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.js\";\nimport { InProcessAgentConnection } from \"./agent-connection/in-process-agent-connection.js\";\nimport type { AgentConnection } from \"./agent-connection/types.js\";\nimport { latestAutonomousGateAttempt, selectHeadlessTerminalResult } from \"./headless-completion.js\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\nfunction describeAutonomousLimit(status: AgentAutonomousStatus, reason: AutonomousLimitReason): string {\n\tif (reason === \"maxContinuations\") {\n\t\treturn `maxContinuations reached (${status.continuationsUsed}/${status.limits.maxContinuations})`;\n\t}\n\tif (reason === \"maxTurns\") {\n\t\treturn `maxTurns reached (${status.turnsUsed}/${status.limits.maxTurns})`;\n\t}\n\tif (reason === \"maxTokens\") {\n\t\treturn `maxTokens reached (${status.tokensUsed}/${status.limits.maxTokens})`;\n\t}\n\tconst elapsed = status.startedAt === undefined ? 0 : Math.max(0, Date.now() - status.startedAt);\n\treturn `timeoutMs reached (${elapsed}/${status.limits.timeoutMs})`;\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst connection = new InProcessAgentConnection(runtimeHost);\n\treturn runPrintModeWithConnectionInternal(connection, options, () => connection.bindHeadlessExtensions());\n}\n\nexport async function runPrintModeWithConnection(\n\tconnection: AgentConnection,\n\toptions: PrintModeOptions,\n): Promise<number> {\n\treturn runPrintModeWithConnectionInternal(connection, options);\n}\n\nasync function runPrintModeWithConnectionInternal(\n\tconnection: AgentConnection,\n\toptions: PrintModeOptions,\n\tbindHeadlessExtensions?: () => Promise<void>,\n): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet disposed = false;\n\tlet unsubscribe: (() => void) | undefined;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst disposeConnection = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tawait connection.dispose();\n\t};\n\n\tfor (const signal of [\n\t\t\"SIGINT\",\n\t\t\"SIGTERM\",\n\t\t...(process.platform === \"win32\" ? [] : [\"SIGHUP\"]),\n\t] as NodeJS.Signals[]) {\n\t\tconst handler = () => {\n\t\t\tkillTrackedDetachedChildren();\n\t\t\tvoid disposeConnection().finally(() => {\n\t\t\t\tconst exitCode = signal === \"SIGINT\" ? 130 : signal === \"SIGHUP\" ? 129 : 143;\n\t\t\t\tprocess.exit(exitCode);\n\t\t\t});\n\t\t};\n\t\tprocess.on(signal, handler);\n\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t}\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = await connection.getSessionHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tunsubscribe = connection.subscribe((event) => {\n\t\t\tif (mode === \"json\" && event.type === \"session_event\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event.event)}\\n`);\n\t\t\t}\n\t\t\tif (event.type === \"extension_error\") {\n\t\t\t\tconsole.error(`Extension error (${event.extensionPath}): ${event.error}`);\n\t\t\t}\n\t\t});\n\t\tawait bindHeadlessExtensions?.();\n\n\t\tif (initialMessage) {\n\t\t\tawait connection.promptAndWait(initialMessage, { images: initialImages });\n\t\t}\n\t\tfor (const message of messages) {\n\t\t\tawait connection.promptAndWait(message);\n\t\t}\n\n\t\tconst autonomousStatus = await connection.waitForHeadlessCompletion();\n\t\tconst { primary, compactionOutcomes } = selectHeadlessTerminalResult(await connection.getMessages());\n\t\tif (primary?.role === \"assistant\") {\n\t\t\tif (primary.stopReason === \"error\" || primary.stopReason === \"aborted\") {\n\t\t\t\tconsole.error(primary.errorMessage || `Request ${primary.stopReason}`);\n\t\t\t\texitCode = 1;\n\t\t\t} else if (mode === \"text\") {\n\t\t\t\tfor (const content of primary.content) {\n\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (primary) {\n\t\t\tif (mode === \"text\") writeRawStdout(`${primary.content}\\n`);\n\t\t\tif (!primary.details.success || primary.details.severity === \"error\") exitCode = 1;\n\t\t}\n\t\tfor (const outcome of compactionOutcomes) {\n\t\t\tif (mode === \"text\" || outcome.details.outcome === \"failed\") console.error(outcome.content);\n\t\t\tif (outcome.details.outcome === \"failed\") exitCode = 1;\n\t\t}\n\n\t\tconst autonomousLimit = autonomousLimitReason(autonomousStatus);\n\t\tif (autonomousStatus.enabled && autonomousStatus.gates.commands.length > 0 && autonomousStatus.lastGateFailure) {\n\t\t\tconst limitText = autonomousLimit\n\t\t\t\t? `; autonomous limit reached: ${describeAutonomousLimit(autonomousStatus, autonomousLimit)}`\n\t\t\t\t: \"\";\n\t\t\tconsole.error(\n\t\t\t\t`Autonomous quality gate still failing after attempt ${latestAutonomousGateAttempt(autonomousStatus)}/${autonomousStatus.gates.maxRetries}: ${autonomousStatus.lastGateFailure.exitText}${limitText}`,\n\t\t\t);\n\t\t\texitCode = 1;\n\t\t} else if (\n\t\t\tautonomousStatus.enabled &&\n\t\t\tautonomousLimit &&\n\t\t\t(autonomousStatus.gates.commands.length === 0 ||\n\t\t\t\tautonomousStatus.gates.commands.some((command) => autonomousStatus.gateAttempts[command] !== 0))\n\t\t) {\n\t\t\tconsole.error(\n\t\t\t\t`Autonomous run stopped before terminal evidence; ${describeAutonomousLimit(autonomousStatus, autonomousLimit)}`,\n\t\t\t);\n\t\t\texitCode = 1;\n\t\t}\n\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\tconsole.error(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeConnection();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
@@ -35,18 +35,19 @@ or loss from a summary alone.
35
35
 
36
36
  ### When It Triggers
37
37
 
38
- Auto-compaction uses an earlier, model-aware soft target by default:
38
+ Auto-compaction uses 90% of the model context window as its default soft target:
39
39
 
40
40
  ```
41
- softTarget = max(4 * keepRecentTokens, min(96000, contextWindow / 2))
41
+ softTarget = floor(0.9 * contextWindow)
42
42
  threshold = min(contextWindow - reserveTokens, max(softTarget, fixedContextTokens + 4 * keepRecentTokens))
43
43
  contextTokens > threshold
44
44
  ```
45
45
 
46
46
  With default `keepRecentTokens` of 20000 and `reserveTokens` of 16384, before
47
- fixed-context headroom raises the target, the thresholds are 96000 for a
48
- 272000-token model, 80000 for a 128000-token model, and 47616 for a 64000-token
49
- model. The model-window ceiling always applies.
47
+ fixed-context headroom raises the target, the thresholds are 244800 for a
48
+ 272000-token model, 111616 for a 128000-token model, and 47616 for a 64000-token
49
+ model. The model-window reserve can therefore trigger compaction before 90%.
50
+ The model-window ceiling always applies.
50
51
 
51
52
  `fixedContextTokens` estimates current system instructions, tool schemas, the
52
53
  current TaskFrame and latest harness snapshot. It does not count all historical
@@ -68,6 +69,33 @@ budgets remain separate; see [context management](context-management.md#model-aw
68
69
 
69
70
  You can also trigger manually with `/compact [instructions]`, where optional instructions focus the summary — for example `/compact focus on the auth refactor, remember the exact migration command`. The instructions are passed to the summarization prompt with high priority, persisted on the `CompactionEntry`, and shown on the `[compaction]` message in the TUI.
70
71
 
72
+ ### Agent-Requested Compaction
73
+
74
+ The agent can request compaction before the automatic threshold, including when
75
+ using Astra. The bundled `compact` skill is enabled by default and runs from the
76
+ Python REPL:
77
+
78
+ ```python
79
+ await compact.status()
80
+ await compact.run("keep the remaining plan and exact test names")
81
+ ```
82
+
83
+ `status()` reports `tokens`, `context_window`, `percent`, and `scheduled`. Usage
84
+ can be unknown immediately after compaction. `run()` schedules compaction at the
85
+ next turn boundary, not in the middle of the Python cell. It returns
86
+ `{"scheduled": True}` when accepted, or `{"scheduled": False, "reason": ...}`
87
+ when no turn is active or there is nothing to compact yet. Optional instructions
88
+ focus the summary. Repeating the request before the boundary updates them.
89
+ Interrupted tool work can continue after the checkpoint; this does not start new
90
+ work after an otherwise completed turn.
91
+
92
+ This request does not depend on the automatic threshold or `compaction.enabled`.
93
+ It requires context optimization to be on. `compaction.agentCallable: false`
94
+ disables the skill, and disabling Python or bundled skills can remove its normal
95
+ entry point. Each recursive agent uses its own session's compaction path; children
96
+ inherit the parent's compact-skill availability. There is no Astra-specific gate.
97
+ A request compacts the requesting session, not the whole agent tree.
98
+
71
99
  ### How It Works
72
100
 
73
101
  1. **Find cut point**: Walk backwards from newest message, accumulating token estimates until `keepRecentTokens` (default 20k, configurable in `~/.base-context/settings.json` or `<project-dir>/.base-context/settings.json`) is reached
@@ -455,10 +483,11 @@ Configure compaction in `~/.base-context/settings.json` or `<project-dir>/.base-
455
483
  | `enabled` | `true` | Enable auto-compaction |
456
484
  | `reserveTokens` | `16384` | Headroom used by the compaction threshold |
457
485
  | `keepRecentTokens` | `20000` | Estimated recent-token target for the retained tail |
458
- | `targetTokens` | Model-aware soft target | Positive safe integer to override the soft target, or `"model-limit"` for the model-window threshold |
486
+ | `targetTokens` | 90% of the model context window | Positive safe integer to override the soft target, or `"model-limit"` for the model-window threshold; fixed-context headroom and the model reserve still apply as described above |
487
+ | `agentCallable` | `true` | Expose the `compact` skill so the agent can request earlier compaction |
459
488
 
460
489
  Disable automatic compaction with `"compaction": { "enabled": false }`. Manual
461
- `/compact` remains available while `context.mode` is `"on"`. Setting `context.mode`
490
+ `/compact` and agent-requested compaction remain available while `context.mode` is `"on"`. Setting `context.mode`
462
491
  to `"off"` disables context optimization, including manual compaction; logging,
463
492
  recovery, limits and other non-optimization ownership remain active.
464
493
 
@@ -84,22 +84,28 @@ In supported native Responses/Codex selection paths, historical assistant litera
84
84
 
85
85
  See [SDK request-token profiles](sdk.md#explicit-request-token-budget-profiles) for the exact scope and configuration.
86
86
 
87
- Ordinary [compaction](compaction.md) uses a separate model-aware soft target:
88
- `max(4 * keepRecentTokens, min(96000, contextWindow / 2))`. The actual trigger also
89
- leaves `4 * keepRecentTokens` above estimated fixed context, then caps the result
90
- at `contextWindow - reserveTokens`. Fixed context includes current system
87
+ Ordinary [compaction](compaction.md) uses a separate soft target of 90% of the
88
+ model context window: `floor(0.9 * contextWindow)`. The actual trigger also leaves
89
+ `4 * keepRecentTokens` above estimated fixed context, then caps the result at
90
+ `contextWindow - reserveTokens`. Fixed context includes current system
91
91
  instructions, tool schemas, the current TaskFrame and latest harness snapshot,
92
92
  not every historical message. This avoids repeated ineffective summaries of
93
93
  noncompactable instructions.
94
94
 
95
- With small fixed context, default settings trigger earlier at 96000 estimated
96
- tokens for a 272000-token model. Set `compaction.targetTokens` to a positive safe
97
- integer to replace the soft target (still subject to fixed-context headroom), or
98
- `"model-limit"` to use exactly the full-window threshold.
99
- This policy reduces repeated large-history requests without clipping required
100
- replay groups. It can add summary calls and rereads; it is not a strict request
95
+ With small fixed context, default thresholds are 244800 estimated tokens for a
96
+ 272000-token model, 111616 for a 128000-token model, and 47616 for a 64000-token
97
+ model. The model-window reserve can trigger compaction before 90%. Set
98
+ `compaction.targetTokens` to a positive safe integer to replace the soft target
99
+ (still subject to fixed-context headroom), or `"model-limit"` to use exactly
100
+ `contextWindow - reserveTokens`. Required replay groups are not clipped to meet
101
+ this target. Summaries can add calls and rereads; this is not a strict request
101
102
  cap, an optimality guarantee, or evidence of a deployment's actual limit.
102
103
 
104
+ The agent can request an earlier checkpoint from the Python REPL with
105
+ `await compact.run()`, independently of the automatic threshold. It can inspect
106
+ usage with `await compact.status()`. This is enabled by default for all models,
107
+ including Astra; see [agent-requested compaction](compaction.md#agent-requested-compaction).
108
+
103
109
  ## Stable context epochs
104
110
 
105
111
  An epoch is a committed context choice: selected source recipes, task-frame text, and the accepted request contract. Within an epoch, unchanged context stays stable. A new selection or relevant resource change requires an accepted boundary rather than an unrecorded rewrite of the prefix.
package/docs/json.md CHANGED
@@ -75,8 +75,21 @@ Followed by events as they occur:
75
75
  {"type":"agent_end","messages":[...]}
76
76
  ```
77
77
 
78
+ ## Completion and Errors
79
+
80
+ JSON mode has the same exit-status rules as text print mode. Terminal assistant errors or aborts, failed session commands, failed compaction, and unfinished autonomous runs stopped by a limit return a nonzero exit status. A configured gate that has not run is not a passed gate. Error diagnostics go to stderr; stdout remains a JSON event stream. Recovered intermediate errors do not by themselves make the final result fail.
81
+
82
+ An unknown explicit `--model` fails startup instead of falling back to the saved model. Startup failures can occur before the session header is emitted.
83
+
84
+ Keep stderr and check the process exit status. An `agent_end` event means the agent loop ended, not that the task succeeded: inspect the terminal assistant's `stopReason` and `errorMessage`, and any gate or compaction failure. Codex error diagnostics retain supplied flat or nested error messages and codes; an empty provider error cannot reveal a cause the provider did not send.
85
+
86
+ Record the first session header's `id` when launching a run. Use that session ID with lifecycle commands; neither cwd nor an operating-system process title uniquely identifies a session. See [Long-Running Agents](long-running-agents.md#daemon-backed-sessions) for client-owned versus resident lifetimes.
87
+
78
88
  ## Example
79
89
 
90
+ Use `pipefail` so the filter does not hide a failing CLI exit status:
91
+
80
92
  ```bash
81
- base-context --mode json "List files" 2>/dev/null | jq -c 'select(.type == "message_end")'
93
+ set -o pipefail
94
+ base-context --mode json "List files" 2>run.err | jq -c 'select(.type == "message_end")'
82
95
  ```