@ponythewhite/base-context 1.0.13 → 1.0.15

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 (83) hide show
  1. package/CHANGELOG.md +18 -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-URKVA3UB.js → bundled-modules-O67MEO74.js} +5 -5
  9. package/dist/bundle/{chunk-FOGKLC7V.js → chunk-72LSQYUV.js} +1 -1
  10. package/dist/bundle/{chunk-TXVF6Q5H.js → chunk-DGO66I3L.js} +87 -51
  11. package/dist/bundle/{chunk-MUFZODP5.js → chunk-EGFIZABJ.js} +1 -1
  12. package/dist/bundle/{chunk-AEMRBMI2.js → chunk-IEM74GZ5.js} +9 -9
  13. package/dist/bundle/{chunk-25VYRAC6.js → chunk-JKKXN6JE.js} +72 -0
  14. package/dist/bundle/{chunk-TKOBEJ5E.js → chunk-RQFC34FM.js} +151 -51
  15. package/dist/bundle/{chunk-Q6UAHLII.js → chunk-V6LOBH6X.js} +2 -2
  16. package/dist/bundle/{cli-main-ZTJM5EEH.js → cli-main-2RER6PBE.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-53I74INO.js → main-YERLD3T4.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 +42 -25
  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 +1 -1
  36. package/dist/core/compaction/compaction.d.ts.map +1 -1
  37. package/dist/core/compaction/compaction.js +11 -9
  38. package/dist/core/compaction/compaction.js.map +1 -1
  39. package/dist/core/inference-coordinator.d.ts.map +1 -1
  40. package/dist/core/inference-coordinator.js +13 -2
  41. package/dist/core/inference-coordinator.js.map +1 -1
  42. package/dist/core/kernel/repl-manager.d.ts.map +1 -1
  43. package/dist/core/kernel/repl-manager.js +5 -0
  44. package/dist/core/kernel/repl-manager.js.map +1 -1
  45. package/dist/core/public-context.d.ts.map +1 -1
  46. package/dist/core/public-context.js +2 -0
  47. package/dist/core/public-context.js.map +1 -1
  48. package/dist/core/session-manager.d.ts +8 -0
  49. package/dist/core/session-manager.d.ts.map +1 -1
  50. package/dist/core/session-manager.js +57 -0
  51. package/dist/core/session-manager.js.map +1 -1
  52. package/dist/core/view-units.d.ts.map +1 -1
  53. package/dist/core/view-units.js +3 -0
  54. package/dist/core/view-units.js.map +1 -1
  55. package/dist/main.d.ts.map +1 -1
  56. package/dist/main.js +1 -1
  57. package/dist/main.js.map +1 -1
  58. package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
  59. package/dist/modes/daemon/daemon-mode.js +21 -20
  60. package/dist/modes/daemon/daemon-mode.js.map +1 -1
  61. package/dist/modes/daemon/daemon-supervisor.d.ts.map +1 -1
  62. package/dist/modes/daemon/daemon-supervisor.js +11 -5
  63. package/dist/modes/daemon/daemon-supervisor.js.map +1 -1
  64. package/dist/modes/daemon/daemon-worker-client.d.ts +1 -0
  65. package/dist/modes/daemon/daemon-worker-client.d.ts.map +1 -1
  66. package/dist/modes/daemon/daemon-worker-client.js +8 -0
  67. package/dist/modes/daemon/daemon-worker-client.js.map +1 -1
  68. package/dist/modes/daemon/daemon-worker-protocol.d.ts +3 -0
  69. package/dist/modes/daemon/daemon-worker-protocol.d.ts.map +1 -1
  70. package/dist/modes/daemon/daemon-worker-protocol.js +2 -0
  71. package/dist/modes/daemon/daemon-worker-protocol.js.map +1 -1
  72. package/dist/modes/interactive/interactive-mode.d.ts +2 -0
  73. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  74. package/dist/modes/interactive/interactive-mode.js +29 -4
  75. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  76. package/dist/modes/print-mode.d.ts.map +1 -1
  77. package/dist/modes/print-mode.js +24 -21
  78. package/dist/modes/print-mode.js.map +1 -1
  79. package/docs/json.md +14 -1
  80. package/docs/long-running-agents.md +23 -2
  81. package/docs/providers.md +17 -0
  82. package/docs/upstream-1.0.15.md +83 -0
  83. package/package.json +4 -4
@@ -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":"AAAA;;;;;;GAMG;AAIH,OAAO,EAA0D,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACtH,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mDAAmD,CAAC;AAE7F,OAAO,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAgBrG,SAAS,uBAAuB,CAAC,MAA6B,EAAE,MAA6B,EAAU;IACtG,IAAI,MAAM,KAAK,kBAAkB,EAAE,CAAC;QACnC,OAAO,6BAA6B,MAAM,CAAC,iBAAiB,IAAI,MAAM,CAAC,MAAM,CAAC,gBAAgB,GAAG,CAAC;IACnG,CAAC;IACD,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;QAC3B,OAAO,qBAAqB,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC;IAC3E,CAAC;IACD,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QAC5B,OAAO,sBAAsB,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC;IAC9E,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAChG,OAAO,sBAAsB,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC;AAAA,CACnE;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,WAAgC,EAAE,OAAyB,EAAmB;IAChH,MAAM,UAAU,GAAG,IAAI,wBAAwB,CAAC,WAAW,CAAC,CAAC;IAC7D,OAAO,kCAAkC,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,sBAAsB,EAAE,CAAC,CAAC;AAAA,CAC1G;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC/C,UAA2B,EAC3B,OAAyB,EACP;IAClB,OAAO,kCAAkC,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAAA,CAC/D;AAED,KAAK,UAAU,kCAAkC,CAChD,UAA2B,EAC3B,OAAyB,EACzB,sBAA4C,EAC1B;IAClB,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,EAAE,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IACvE,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,WAAqC,CAAC;IAC1C,MAAM,qBAAqB,GAAsB,EAAE,CAAC;IAEpD,MAAM,iBAAiB,GAAG,KAAK,IAAmB,EAAE,CAAC;QACpD,IAAI,QAAQ;YAAE,OAAO;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,WAAW,EAAE,EAAE,CAAC;QAChB,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC;IAAA,CAC3B,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI;QACpB,QAAQ;QACR,SAAS;QACT,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;KAC/B,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC;YACrB,2BAA2B,EAAE,CAAC;YAC9B,KAAK,iBAAiB,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;gBACtC,MAAM,QAAQ,GAAG,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;gBAC7E,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAAA,CACvB,CAAC,CAAC;QAAA,CACH,CAAC;QACF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC5B,qBAAqB,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,CAAC;QACJ,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,gBAAgB,EAAE,CAAC;YACnD,IAAI,MAAM,EAAE,CAAC;gBACZ,cAAc,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC/C,CAAC;QACF,CAAC;QAED,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;YAC7C,IAAI,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;gBACvD,cAAc,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACpD,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;gBACtC,OAAO,CAAC,KAAK,CAAC,oBAAoB,KAAK,CAAC,aAAa,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YAC3E,CAAC;QAAA,CACD,CAAC,CAAC;QACH,MAAM,sBAAsB,EAAE,EAAE,CAAC;QAEjC,IAAI,cAAc,EAAE,CAAC;YACpB,MAAM,UAAU,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;QAC3E,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAChC,MAAM,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,gBAAgB,GAAG,MAAM,UAAU,CAAC,yBAAyB,EAAE,CAAC;QACtE,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,4BAA4B,CAAC,MAAM,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;QACrG,IAAI,OAAO,EAAE,IAAI,KAAK,WAAW,EAAE,CAAC;YACnC,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACxE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,IAAI,WAAW,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;gBACvE,QAAQ,GAAG,CAAC,CAAC;YACd,CAAC;iBAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC5B,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;oBACvC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;wBAC7B,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;oBACrC,CAAC;gBACF,CAAC;YACF,CAAC;QACF,CAAC;aAAM,IAAI,OAAO,EAAE,CAAC;YACpB,IAAI,IAAI,KAAK,MAAM;gBAAE,cAAc,CAAC,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;YAC5D,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;gBAAE,QAAQ,GAAG,CAAC,CAAC;QACpF,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;YAC1C,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,KAAK,QAAQ;gBAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC5F,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,KAAK,QAAQ;gBAAE,QAAQ,GAAG,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,eAAe,GAAG,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;QAChE,IAAI,gBAAgB,CAAC,OAAO,IAAI,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,gBAAgB,CAAC,eAAe,EAAE,CAAC;YAChH,MAAM,SAAS,GAAG,eAAe;gBAChC,CAAC,CAAC,+BAA+B,uBAAuB,CAAC,gBAAgB,EAAE,eAAe,CAAC,EAAE;gBAC7F,CAAC,CAAC,EAAE,CAAC;YACN,OAAO,CAAC,KAAK,CACZ,uDAAuD,2BAA2B,CAAC,gBAAgB,CAAC,IAAI,gBAAgB,CAAC,KAAK,CAAC,UAAU,KAAK,gBAAgB,CAAC,eAAe,CAAC,QAAQ,GAAG,SAAS,EAAE,CACrM,CAAC;YACF,QAAQ,GAAG,CAAC,CAAC;QACd,CAAC;aAAM,IACN,gBAAgB,CAAC,OAAO;YACxB,eAAe;YACf,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAC5C,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,gBAAgB,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAChG,CAAC;YACF,OAAO,CAAC,KAAK,CACZ,oDAAoD,uBAAuB,CAAC,gBAAgB,EAAE,eAAe,CAAC,EAAE,CAChH,CAAC;YACF,QAAQ,GAAG,CAAC,CAAC;QACd,CAAC;QAED,OAAO,QAAQ,CAAC;IACjB,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,CAAC;IACV,CAAC;YAAS,CAAC;QACV,KAAK,MAAM,OAAO,IAAI,qBAAqB,EAAE,CAAC;YAC7C,OAAO,EAAE,CAAC;QACX,CAAC;QACD,MAAM,iBAAiB,EAAE,CAAC;QAC1B,MAAM,cAAc,EAAE,CAAC;IACxB,CAAC;AAAA,CACD","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"]}
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
  ```
@@ -46,7 +46,9 @@ The client can detach at any point. The resident worker continues to own the que
46
46
 
47
47
  Normal interactive sessions run in resident worker processes managed by a local supervisor. The worker owns the root session, its Python kernel, scheduled jobs, and RLM descendants.
48
48
 
49
- Closing the terminal UI detaches the client; it does not stop the worker. List and reconnect to active agents with:
49
+ Closing the terminal UI detaches the client; it does not stop the resident worker. Print/JSON and RPC sessions are client-owned instead: losing their client connection triggers worker cleanup. ACP sessions are resident unless `--no-session` is used. A separate launcher or monitoring process can fail while its CLI child remains connected; that is not a client disconnect.
50
+
51
+ List and reconnect to active agents with:
50
52
 
51
53
  ```bash
52
54
  base-context list
@@ -64,12 +66,16 @@ base-context doctor [--fix] # Diagnose or repair service state
64
66
  base-context shutdown [--force] # Stop all agents and services
65
67
  ```
66
68
 
69
+ Use the session ID from the JSON stream header or the IDs in `base-context list --json` to track a run. Several sessions can share one cwd. The process title `base-context` identifies the program, not an individual session. `stop` reports an error for an unknown or ambiguous target; do not suppress all stop failures or infer worker death from a separate launcher's exit.
70
+
67
71
  Workers persist native-framed journals and use derived indexes. The default flat paths are `~/.base-context/sessions/<session-id>.jsonl` and `~/.base-context/session-artifacts/<session-id>/`. `BASE_CONTEXT_HOME` selects the product root; `BASE_CONTEXT_SESSION_DIR` can select a different absolute sessions directory, with artifacts under its parent's `session-artifacts/` directory.
68
72
 
69
73
  The `.jsonl` extension does not make a native journal an editable transcript. Use the asynchronous, bounded SessionManager APIs described in [Sessions](sessions.md#session-format), not `jq`, manual appends or text edits. Recovery uses the native owners and supported artifacts. Copying a journal alone does not restore a worker, Python process, live children or pending dispatch authority.
70
74
 
71
75
  Daemon workers are process-isolated for lifecycle and failure containment, not security-sandboxed. They normally run with the same operating-system permissions as the client.
72
76
 
77
+ If a run must not create subagents, use the existing `/agents 0` control or the `rlmMaxSubagents: 0` setting. This blocks new admissions; it does not stop existing children. A prompt instruction alone is not a capability limit. Parent `message_end` usage describes parent responses, not all delegated work; inspect child usage separately. See [RLM](rlm.md) and [Settings](settings.md).
78
+
73
79
  ## Agent-to-Agent Communication
74
80
 
75
81
  The daemon routes direct messages between active sessions and retained daemon-backed subagents. From a shell:
@@ -228,6 +234,15 @@ await goal.complete()
228
234
 
229
235
  Goal state records token usage, elapsed time, continuation count, and an optional explicit token budget. The harness keeps prompting an active goal after ordinary assistant turns; only `goal.complete()` marks successful completion. Creating a persistent goal is an explicit user or host action, not something the agent should infer from every task. Imported historical goal entries remain retained data; importing them does not reactivate the goal.
230
236
 
237
+ Goal objectives are limited to 4,000 characters because they remain part of the ongoing task context. Keep the objective short and pass a longer brief as prompt input, for example:
238
+
239
+ ```bash
240
+ base-context -p --goal "Complete the change described in BRIEF.md" \
241
+ --goal-token-budget 200000 @BRIEF.md
242
+ ```
243
+
244
+ `--goal-token-budget` accompanies `--goal`; resuming a session alone restores the saved goal budget and usage. `/goal resume` does not reset an exhausted budget. To authorize more work after exhaustion, explicitly start a new goal with a new budget. Goal token usage counts `input + output`, not cached reads.
245
+
231
246
  ## Autonomous Mode
232
247
 
233
248
  Autonomous mode is a bounded host policy for runs where no human input is expected. Base Context adds follow-up continuations until configured quality gates pass or a continuation, turn, token, or wall-clock limit is reached.
@@ -250,7 +265,13 @@ base-context \
250
265
  "Implement and verify the requested change"
251
266
  ```
252
267
 
253
- Autonomous mode supports limits for continuations, assistant turns, tokens, and wall-clock duration. Gate commands run before the session may finish; a failed gate returns its bounded output to the agent for another attempt. Base Context avoids rerunning the same failed gate when the workspace has not changed.
268
+ Autonomous mode supports limits for continuations, assistant turns, tokens, and wall-clock duration. Defaults are 3 continuations, 12 turns, 80,000 tokens, and 30 minutes. Set explicit limits for longer jobs rather than relying on unbounded execution.
269
+
270
+ The autonomous token counter is `input + output + cacheWrite`. It excludes `cacheRead`; provider `totalTokens` includes cached reads and is not the same budget or a monetary cost. An external launcher that sums `totalTokens` therefore applies a different limit.
271
+
272
+ Turn, token, and time limits are checked at completed native tool-turn boundaries before another main-loop request. A running response or tool is allowed to finish, so usage or elapsed time can exceed the exact cap by that work. These limits are not process-kill timers and do not cancel every auxiliary lifecycle operation. `maxContinuations` counts host-injected prompts separately; the final permitted prompt can still execute its tool turns.
273
+
274
+ Gate commands run before successful autonomous completion; a failed gate returns its bounded output to the agent for another attempt. Base Context avoids rerunning the same failed gate when the workspace has not changed. A work limit can stop a run before its gates execute. Headless mode returns nonzero in that case, rather than treating an unrun gate as success.
254
275
 
255
276
  Goals and autonomous mode are complementary but different:
256
277
 
package/docs/providers.md CHANGED
@@ -35,6 +35,23 @@ An OpenAI API key belongs to the separate `openai` provider; it is not required
35
35
 
36
36
  The SDK also offers an optional, explicitly injected read-only Codex backend for existing credentials. Only that mode disables login, refresh, credential writes, and API-key fallback. It does not restrict normal interactive subscription login. See [SDK authentication](sdk.md#api-keys-and-oauth).
37
37
 
38
+ ### GPT-6 Sol and Luna
39
+
40
+ Both `gpt-6-sol` and `gpt-6-luna` are listed under these separate providers:
41
+
42
+ | Provider | Authentication | Route | Catalog context capacity |
43
+ |----------|----------------|-------|--------------------------|
44
+ | `openai` | OpenAI API key | `openai-responses`, `https://api.openai.com/v1/responses` | 1,050,000 tokens |
45
+ | `openai-codex` | ChatGPT/Codex subscription OAuth | `openai-codex-responses`, `https://chatgpt.com/backend-api/codex/responses` | 872,000 tokens |
46
+
47
+ The official Codex catalog specifies a 272,000-token **client default** and an 872,000-token **maximum configuration override** for both models. Base Context uses that documented maximum as catalog capacity, without importing Codex's compaction percentages. The API model cards specify 1,050,000 context tokens, 922,000 maximum input tokens, and 128,000 maximum output tokens. All four catalog entries use the nominal 128,000 output ceiling; a separate Codex account/backend output limit has not been verified. Both accept text and images and produce text.
48
+
49
+ API reasoning levels are `off` (sent as `none`), `low`, `medium`, `high`, `xhigh`, and `max`. The Codex entries expose `low` through `max`, without `off` or `minimal`. Codex's Ultra option is client-side task delegation, not an additional Base Context reasoning level.
50
+
51
+ Catalog costs are flat Standard API-rate estimates. Long-context and service-tier premiums are not modeled by these entries. Codex costs are API-equivalent estimates, not subscription charges or invoices. Model availability depends on account, workspace, client, and rollout; live account access has not been verified.
52
+
53
+ Official sources: [Sol model card](https://developers.openai.com/api/docs/models/gpt-6-sol), [Luna model card](https://developers.openai.com/api/docs/models/gpt-6-luna), [API pricing](https://developers.openai.com/api/docs/pricing), [Codex models](https://developers.openai.com/codex/models), [Codex catalog](https://github.com/openai/codex/blob/main/codex-rs/models-manager/models.json), and [context-field definitions](https://github.com/openai/codex/blob/main/codex-rs/protocol/src/openai_models.rs).
54
+
38
55
  ## API Keys
39
56
 
40
57
  ### Environment Variables or Auth File
@@ -0,0 +1,83 @@
1
+ # Prime Agent selection for Base Context 1.0.15
2
+
3
+ This is a selective adaptation, not an upstream merge.
4
+
5
+ Base Context forked Prime Agent 0.9.3 at
6
+ `915c78f42c248b08238dd27fcd4bcab32c60beab`. This review screened all 222
7
+ subsequent commits through `2d24ad4e6b2d1ee8e6919af6f108e980a14d550e`
8
+ (2026-09-27): 10 through 0.9.4, the 113 commits covered by the prior
9
+ [0.9.5 selection](upstream-0.9.5.md), and 99 after 0.9.5. Relevant runtime,
10
+ compaction, goal, and workflow changes received focused source comparison;
11
+ this is not a full audit of every changed function.
12
+
13
+ The latest stable release in this review was Prime Agent 0.9.6,
14
+ `e260085dd8f742e0def3d871860c9a888b114851`, published 2026-09-24. Six later
15
+ main commits were also screened. A commit can be absent from fork ancestry
16
+ while its selected behavior is already implemented locally.
17
+
18
+ ## Selected small fixes
19
+
20
+ | Exact upstream commit | Adaptation |
21
+ |---|---|
22
+ | `a0660bb5f823bcd9490a83ca3e822d7d53f36e24` | Clear a failed direct daemon-worker connection's socket and channel references, so the same client can retry after a connection error or timeout. Keep Base Context's native-owner, compatibility, and probe-timeout handling. Do not refactor the already-correct daemon-client connection path merely to share a helper. |
23
+ | `b6b94c78a7747997e0ec6c690c0e8f2a563dbe14` | Add the missing kernel stderr stream error listener, matching the existing stdin/stdout listeners. Record the diagnostic without taking cleanup ownership from pending writes and child exit. |
24
+
25
+ These changes add no provider, model, daemon command, wire shape, or protocol
26
+ version. Focused coverage belongs in the existing `daemon-client.test.ts` and
27
+ `repl-kernel-pipe-errors.test.ts` files. Test outcomes belong to the change's
28
+ validation record, not to this upstream-selection rationale.
29
+
30
+ ## Relevant decisions
31
+
32
+ Upstream commits can be viewed at
33
+ `https://github.com/PrimeIntellect-ai/prime-agent/commit/<commit>`.
34
+
35
+ | Exact upstream commit | Decision | Reason |
36
+ |---|---|---|
37
+ | `90ca4a457e0fef0bd925215d4c973abd6264f067` | Already adapted | Kernel stdin/stdout pipe errors are already handled. Keep that behavior; only stderr was missing. |
38
+ | `55ade48b73f636d992855b7cab797d71dc1f6f1c` | Already adapted | LiteLLM overflow recognition and rate-limit exclusions already match upstream. A local history-source limit is not a provider context overflow. |
39
+ | `8eaa00c37385c6b25fed9d46584b50ffc2e87f9c` | Already adapted | Blocked input-pump idle waits already yield, with additional native settlement/admission guards. |
40
+ | `b3e04b58b358ae9adc02387e6d01937ef9f8064f` | Defer native adaptation | Restoring non-durable next-turn prefixes from every cancelled turn is relevant, but must preserve the native action/source owner. Not part of the two isolated runtime patches. |
41
+ | `c4afa57352e71a8532f04ef04a09ce14720ddeca` | Defer | Deriving displayed activity from actual session activity rather than summary freshness is useful, but is a separate UI/state change. |
42
+ | `bcdcd6e65e10959c9904ec4467747528303493b0` | Defer native adaptation | Manual-compaction goal resume must use Base Context's captured-owner continuation lifecycle, not upstream queue scheduling. |
43
+ | `215e7a7409b2931b49d3aad62d29fa8e94345973` | Defer native adaptation | Same-goal accounting should remain monotonic across summary moves, without applying maxima across unrelated goals or deliberate branch navigation. The upstream reload helper has been replaced locally. |
44
+ | `9bd6a9bc0fbc1e4072cfd7162f855a305c39efb0` | Defer native adaptation | Refresh queued goal accounting at a native admission/capture boundary; do not copy upstream in-place mutation of accepted message content. |
45
+ | `2e43ebca3753c82ed0ef2064cb14081588ebd4d3`, `b08f08efad6830856318e994447162ba3fd4c6ee` | Reject as-is | Blanket continuation pauses while children or background shells run prevent independent work. A running resource does not establish a dependency. |
46
+ | `5fb3d9acbafa06ae9228c49a4b8a4eca9abc0997` | Defer summary adaptation | Tool name, error status, and matching call indices improve summary input, but change prompt representation and need to fit native context budgets. |
47
+ | `27f32ddb7e99803555c4654c9ce38edad3e90e22` | Defer summary adaptation | Strip repeated mechanical file lists if adopted. Kept-tail recency must not promote assistant statements over user constraints or TaskFrame authority. Silent list caps are not acceptable substitutes for visible limits. |
48
+ | `6be5d4f297f112df8b57b6807de9405c5444fc0f`, `f31c440c788499a4ba49736acbf1504a25e3ad4c` | Retain prior deferral | Head/tail excerpts and kernel-reported file paths change summary selection. Retain recoverable original evidence; do not silently cap file lists or promote tool observations to task authority. |
49
+ | `4f6df9d14385368a148c22e65dfc6050fbb984f1` | Reject routing policy | Automatic auxiliary-model fallback and suppressed reasoning would override explicit compaction model/effort selection. Native request budgeting remains authoritative. |
50
+ | `c91e6e991fc006098ea21c3640eed3bdd268c222`, `0e3c900225f8beea4ecd57180902d437cd394117`, `2d24ad4e6b2d1ee8e6919af6f108e980a14d550e` | Defer larger runtime change | Bounded frames/payloads and linear protocol reading are a coherent later adaptation, not part of the stderr listener fix. They do not fix full-parent history hydration. |
51
+ | `8ee46be35b6fcc4ab28aa6d524aeed1fff69ffe4` | Defer larger runtime change | Restored functions need live namespace globals, but the revival change must preserve native staged restore and interrupt behavior. No dill/restore rewrite is included here. |
52
+ | `561401b273b5affa3877aae51e3b44ce201cc2d5` | Defer | Bound attached cell-source metadata separately from complete execution/canonical source. The upstream cap is characters plus a marker, not a byte limit. |
53
+ | `d73349d508075cb4d6c3d9d6eec677f029e294c8` | Defer legacy-only adaptation | The retained opt-in owned-worker frontend differs from normal daemon startup. Its cleanup may throw on corrupt tracking; copying upstream's error callback would bypass native cleanup reporting. |
54
+ | `ecd60e3cd4313643dede3cb2fcf13b4e2e9a2a75`, `66df06fc12d721c919d61c5ce4d6fb3ef0da479f` | Defer together | Consumed shell-notice withdrawal and its ordering fix form one optional workflow change. Preserve native action/source semantics. |
55
+ | `e2fb7bfa1372552d81c33e9b3261d6a9cf82d30f` | Defer product decision | Interrupt-and-send-queued changes user controls and adds a capability-gated command. It requires explicit selection and compatibility coverage, not a protocol-version transplant. |
56
+
57
+ ## Native context and command boundaries
58
+
59
+ Upstream does not implement Base Context's framed source/indexed working-view
60
+ architecture. Full-transcript branch caches and JSONL parse optimizations are
61
+ not repairs for a native source-byte refusal. Compaction must select required
62
+ source-backed views before hydrating unrelated old payloads. Captured owners,
63
+ replay groups, accepted epochs, recovery authorization, and acknowledged writes
64
+ must remain intact. A `baseContextEpoch` record is not necessarily a model-written
65
+ summary.
66
+
67
+ The `/goal` text parser is unchanged from upstream at the reviewed revisions.
68
+ Single-line objectives are supported; session slash commands reject multiline
69
+ input, and the command name must start at column zero. Changing that grammar is
70
+ a local product decision, not an upstream bug-fix transplant. Historical goal
71
+ regressions added by the commits above were removed in upstream
72
+ `cf07c5a3f5eca98e7744f2df83050044c920252a`; they are useful test vectors, not
73
+ claims about current upstream test coverage.
74
+
75
+ ## What stays out
76
+
77
+ All PrimeRL/Prime product provider, subscription, model, account, team, and
78
+ catalog integrations remain excluded. No implicit backup models, credential
79
+ migration, compiled installer migration, `rlm.spawn`/`collect` API replacement,
80
+ new ledger/audit system, or benchmark pipeline is introduced. Base Context keeps
81
+ explicit provider/auth/model/effort selection, its package and state roots,
82
+ callable `await rlm(...)`, native context authority, and independent-work policy.
83
+ Lawful upstream copyright and MIT attribution remain intact.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponythewhite/base-context",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Synerise base-context: a coding and research agent with durable context and a persistent Python REPL",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,9 +42,9 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@agentclientprotocol/sdk": "^1.3.0",
45
- "@ponythewhite/base-context-agent": "1.0.13",
46
- "@ponythewhite/base-context-ai": "1.0.13",
47
- "@ponythewhite/base-context-tui": "1.0.13",
45
+ "@ponythewhite/base-context-agent": "1.0.15",
46
+ "@ponythewhite/base-context-ai": "1.0.15",
47
+ "@ponythewhite/base-context-tui": "1.0.15",
48
48
  "@silvia-odwyer/photon-node": "^0.3.4",
49
49
  "chalk": "^5.5.0",
50
50
  "cli-highlight": "^2.1.11",