open-multi-agent-kit 0.96.0 → 0.96.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +24 -6
  3. package/dist/commands/doctor-provider.d.ts.map +1 -1
  4. package/dist/commands/doctor-provider.js +15 -20
  5. package/dist/commands/doctor-provider.js.map +1 -1
  6. package/dist/commands/sdk-session-cli.d.ts +24 -0
  7. package/dist/commands/sdk-session-cli.d.ts.map +1 -0
  8. package/dist/commands/sdk-session-cli.js +225 -0
  9. package/dist/commands/sdk-session-cli.js.map +1 -0
  10. package/dist/core/advisory-judge-model.d.ts +18 -0
  11. package/dist/core/advisory-judge-model.d.ts.map +1 -0
  12. package/dist/core/advisory-judge-model.js +168 -0
  13. package/dist/core/advisory-judge-model.js.map +1 -0
  14. package/dist/core/advisory-judge-response.d.ts +8 -0
  15. package/dist/core/advisory-judge-response.d.ts.map +1 -0
  16. package/dist/core/advisory-judge-response.js +61 -0
  17. package/dist/core/advisory-judge-response.js.map +1 -0
  18. package/dist/core/advisory-judge-types.d.ts +53 -0
  19. package/dist/core/advisory-judge-types.d.ts.map +1 -0
  20. package/dist/core/advisory-judge-types.js +2 -0
  21. package/dist/core/advisory-judge-types.js.map +1 -0
  22. package/dist/core/advisory-judge.d.ts +8 -0
  23. package/dist/core/advisory-judge.d.ts.map +1 -0
  24. package/dist/core/advisory-judge.js +178 -0
  25. package/dist/core/advisory-judge.js.map +1 -0
  26. package/dist/core/agent-session-services.d.ts +1 -0
  27. package/dist/core/agent-session-services.d.ts.map +1 -1
  28. package/dist/core/agent-session-services.js +1 -0
  29. package/dist/core/agent-session-services.js.map +1 -1
  30. package/dist/core/agent-session.d.ts +4 -1
  31. package/dist/core/agent-session.d.ts.map +1 -1
  32. package/dist/core/agent-session.js +107 -174
  33. package/dist/core/agent-session.js.map +1 -1
  34. package/dist/core/auth-storage.d.ts.map +1 -1
  35. package/dist/core/auth-storage.js +28 -4
  36. package/dist/core/auth-storage.js.map +1 -1
  37. package/dist/core/compaction-gate.d.ts +28 -0
  38. package/dist/core/compaction-gate.d.ts.map +1 -0
  39. package/dist/core/compaction-gate.js +34 -0
  40. package/dist/core/compaction-gate.js.map +1 -0
  41. package/dist/core/context-budget-system-prompt-items.d.ts.map +1 -1
  42. package/dist/core/context-budget-system-prompt-items.js +5 -3
  43. package/dist/core/context-budget-system-prompt-items.js.map +1 -1
  44. package/dist/core/domain-loadouts.d.ts.map +1 -1
  45. package/dist/core/domain-loadouts.js +2 -2
  46. package/dist/core/domain-loadouts.js.map +1 -1
  47. package/dist/core/durable-goal-checkpoint.d.ts +6 -0
  48. package/dist/core/durable-goal-checkpoint.d.ts.map +1 -0
  49. package/dist/core/durable-goal-checkpoint.js +195 -0
  50. package/dist/core/durable-goal-checkpoint.js.map +1 -0
  51. package/dist/core/durable-goal-parse.d.ts +3 -0
  52. package/dist/core/durable-goal-parse.d.ts.map +1 -0
  53. package/dist/core/durable-goal-parse.js +86 -0
  54. package/dist/core/durable-goal-parse.js.map +1 -0
  55. package/dist/core/durable-goal-reducer.d.ts +3 -0
  56. package/dist/core/durable-goal-reducer.d.ts.map +1 -0
  57. package/dist/core/durable-goal-reducer.js +175 -0
  58. package/dist/core/durable-goal-reducer.js.map +1 -0
  59. package/dist/core/durable-goal-store.d.ts +19 -0
  60. package/dist/core/durable-goal-store.d.ts.map +1 -0
  61. package/dist/core/durable-goal-store.js +126 -0
  62. package/dist/core/durable-goal-store.js.map +1 -0
  63. package/dist/core/durable-goal.d.ts +92 -0
  64. package/dist/core/durable-goal.d.ts.map +1 -0
  65. package/dist/core/durable-goal.js +62 -0
  66. package/dist/core/durable-goal.js.map +1 -0
  67. package/dist/core/extensions/builtin/goal-controller.d.ts +3 -0
  68. package/dist/core/extensions/builtin/goal-controller.d.ts.map +1 -0
  69. package/dist/core/extensions/builtin/goal-controller.js +125 -0
  70. package/dist/core/extensions/builtin/goal-controller.js.map +1 -0
  71. package/dist/core/extensions/builtin/identical-loop.d.ts +3 -0
  72. package/dist/core/extensions/builtin/identical-loop.d.ts.map +1 -0
  73. package/dist/core/extensions/builtin/identical-loop.js +31 -0
  74. package/dist/core/extensions/builtin/identical-loop.js.map +1 -0
  75. package/dist/core/extensions/builtin/prompt-preset.d.ts +3 -0
  76. package/dist/core/extensions/builtin/prompt-preset.d.ts.map +1 -0
  77. package/dist/core/extensions/builtin/prompt-preset.js +13 -0
  78. package/dist/core/extensions/builtin/prompt-preset.js.map +1 -0
  79. package/dist/core/extensions/builtin/tool-pair-repair.d.ts +3 -0
  80. package/dist/core/extensions/builtin/tool-pair-repair.d.ts.map +1 -0
  81. package/dist/core/extensions/builtin/tool-pair-repair.js +12 -0
  82. package/dist/core/extensions/builtin/tool-pair-repair.js.map +1 -0
  83. package/dist/core/extensions/types.d.ts +6 -2
  84. package/dist/core/extensions/types.d.ts.map +1 -1
  85. package/dist/core/extensions/types.js.map +1 -1
  86. package/dist/core/goal-continuation.d.ts +13 -0
  87. package/dist/core/goal-continuation.d.ts.map +1 -0
  88. package/dist/core/goal-continuation.js +10 -0
  89. package/dist/core/goal-continuation.js.map +1 -0
  90. package/dist/core/grok-harness.d.ts +1 -1
  91. package/dist/core/grok-harness.d.ts.map +1 -1
  92. package/dist/core/grok-harness.js +1 -1
  93. package/dist/core/grok-harness.js.map +1 -1
  94. package/dist/core/grok-playbook.d.ts +1 -1
  95. package/dist/core/grok-playbook.d.ts.map +1 -1
  96. package/dist/core/grok-playbook.js +1 -1
  97. package/dist/core/grok-playbook.js.map +1 -1
  98. package/dist/core/identical-loop.d.ts +15 -0
  99. package/dist/core/identical-loop.d.ts.map +1 -0
  100. package/dist/core/identical-loop.js +34 -0
  101. package/dist/core/identical-loop.js.map +1 -0
  102. package/dist/core/index.d.ts +1 -1
  103. package/dist/core/index.d.ts.map +1 -1
  104. package/dist/core/index.js +1 -1
  105. package/dist/core/index.js.map +1 -1
  106. package/dist/core/model-prompt-policy.d.ts +11 -0
  107. package/dist/core/model-prompt-policy.d.ts.map +1 -0
  108. package/dist/core/model-prompt-policy.js +17 -0
  109. package/dist/core/model-prompt-policy.js.map +1 -0
  110. package/dist/core/model-registry.d.ts.map +1 -1
  111. package/dist/core/model-registry.js +16 -4
  112. package/dist/core/model-registry.js.map +1 -1
  113. package/dist/core/model-resolver.d.ts.map +1 -1
  114. package/dist/core/model-resolver.js +2 -2
  115. package/dist/core/model-resolver.js.map +1 -1
  116. package/dist/core/prompt-budget.d.ts +21 -0
  117. package/dist/core/prompt-budget.d.ts.map +1 -0
  118. package/dist/core/prompt-budget.js +51 -0
  119. package/dist/core/prompt-budget.js.map +1 -0
  120. package/dist/core/prompt-cache.d.ts +14 -0
  121. package/dist/core/prompt-cache.d.ts.map +1 -0
  122. package/dist/core/prompt-cache.js +16 -0
  123. package/dist/core/prompt-cache.js.map +1 -0
  124. package/dist/core/prompt-preset.d.ts +8 -0
  125. package/dist/core/prompt-preset.d.ts.map +1 -0
  126. package/dist/core/prompt-preset.js +56 -0
  127. package/dist/core/prompt-preset.js.map +1 -0
  128. package/dist/core/provider-resilience.d.ts +16 -0
  129. package/dist/core/provider-resilience.d.ts.map +1 -1
  130. package/dist/core/provider-resilience.js +23 -1
  131. package/dist/core/provider-resilience.js.map +1 -1
  132. package/dist/core/provider-retry.d.ts +29 -0
  133. package/dist/core/provider-retry.d.ts.map +1 -0
  134. package/dist/core/provider-retry.js +49 -0
  135. package/dist/core/provider-retry.js.map +1 -0
  136. package/dist/core/provider-usage.d.ts +2 -1
  137. package/dist/core/provider-usage.d.ts.map +1 -1
  138. package/dist/core/provider-usage.js +40 -6
  139. package/dist/core/provider-usage.js.map +1 -1
  140. package/dist/core/resource-loader.d.ts.map +1 -1
  141. package/dist/core/resource-loader.js +32 -0
  142. package/dist/core/resource-loader.js.map +1 -1
  143. package/dist/core/sandbox/backend.d.ts +12 -0
  144. package/dist/core/sandbox/backend.d.ts.map +1 -1
  145. package/dist/core/sandbox/backend.js +52 -42
  146. package/dist/core/sandbox/backend.js.map +1 -1
  147. package/dist/core/sandbox/policy.d.ts +2 -0
  148. package/dist/core/sandbox/policy.d.ts.map +1 -1
  149. package/dist/core/sandbox/policy.js +2 -1
  150. package/dist/core/sandbox/policy.js.map +1 -1
  151. package/dist/core/sdk.d.ts +2 -0
  152. package/dist/core/sdk.d.ts.map +1 -1
  153. package/dist/core/sdk.js +1 -0
  154. package/dist/core/sdk.js.map +1 -1
  155. package/dist/core/session-system-prompt.d.ts +28 -0
  156. package/dist/core/session-system-prompt.d.ts.map +1 -0
  157. package/dist/core/session-system-prompt.js +37 -0
  158. package/dist/core/session-system-prompt.js.map +1 -0
  159. package/dist/core/strict-record.d.ts +2 -0
  160. package/dist/core/strict-record.d.ts.map +1 -0
  161. package/dist/core/strict-record.js +9 -0
  162. package/dist/core/strict-record.js.map +1 -0
  163. package/dist/core/tool-pair-repair.d.ts +11 -0
  164. package/dist/core/tool-pair-repair.d.ts.map +1 -0
  165. package/dist/core/tool-pair-repair.js +38 -0
  166. package/dist/core/tool-pair-repair.js.map +1 -0
  167. package/dist/core/tools/artifact-spill.d.ts +13 -0
  168. package/dist/core/tools/artifact-spill.d.ts.map +1 -0
  169. package/dist/core/tools/artifact-spill.js +26 -0
  170. package/dist/core/tools/artifact-spill.js.map +1 -0
  171. package/dist/core/tools/bash.d.ts +7 -4
  172. package/dist/core/tools/bash.d.ts.map +1 -1
  173. package/dist/core/tools/bash.js +8 -7
  174. package/dist/core/tools/bash.js.map +1 -1
  175. package/dist/core/tools/index.d.ts +1 -1
  176. package/dist/core/tools/index.d.ts.map +1 -1
  177. package/dist/core/tools/index.js.map +1 -1
  178. package/dist/core/tools/read.d.ts +1 -0
  179. package/dist/core/tools/read.d.ts.map +1 -1
  180. package/dist/core/tools/read.js +10 -1
  181. package/dist/core/tools/read.js.map +1 -1
  182. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  183. package/dist/core/tools/tool-definition-wrapper.js +2 -0
  184. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  185. package/dist/index.d.ts +18 -1
  186. package/dist/index.d.ts.map +1 -1
  187. package/dist/index.js +18 -0
  188. package/dist/index.js.map +1 -1
  189. package/dist/main.d.ts.map +1 -1
  190. package/dist/main.js +8 -0
  191. package/dist/main.js.map +1 -1
  192. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  193. package/dist/modes/interactive/theme/theme.js +14 -3
  194. package/dist/modes/interactive/theme/theme.js.map +1 -1
  195. package/docs/adaptorch-preview-spec.md +1 -1
  196. package/docs/adaptorch-preview.md +2 -2
  197. package/docs/book-to-skill.md +1 -1
  198. package/docs/containerization.md +9 -0
  199. package/docs/docs.json +11 -3
  200. package/docs/environment-variables.md +11 -4
  201. package/docs/extensions.md +14 -1
  202. package/docs/grok-harness.md +35 -12
  203. package/docs/index.md +7 -6
  204. package/docs/loadout-domains/grok-harness.md +2 -2
  205. package/docs/models.md +10 -9
  206. package/docs/provider-resilience.md +9 -3
  207. package/docs/providers.md +9 -4
  208. package/docs/run-protocol.md +32 -0
  209. package/docs/sdk.md +96 -3
  210. package/docs/security.md +22 -32
  211. package/docs/sessions.md +14 -0
  212. package/docs/usage.md +37 -15
  213. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  214. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  215. package/examples/extensions/custom-provider-gitlab-duo/index.ts +6 -1
  216. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  217. package/examples/extensions/gondolin/package-lock.json +2 -2
  218. package/examples/extensions/gondolin/package.json +1 -1
  219. package/examples/extensions/sandbox/package-lock.json +2 -2
  220. package/examples/extensions/sandbox/package.json +1 -1
  221. package/examples/extensions/with-deps/package-lock.json +2 -2
  222. package/examples/extensions/with-deps/package.json +1 -1
  223. package/npm-shrinkwrap.json +18 -18
  224. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport {\n\tAgent,\n\ttype AgentMessage,\n\tinspectTranscriptIntegrity,\n\trepairTranscriptIntegrity,\n\ttype ThinkingLevel,\n} from \"omk-agent-core\";\nimport { createNodeResourceKeyResolver } from \"omk-agent-core/node\";\nimport { clampThinkingLevel, type Message, type Model, streamSimple, type ToolResultMessage } from \"omk-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { ReplayLedgerManager } from \"../guardrails/evidence-system.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AgentSession, type SessionTranscriptRepair } from \"./agent-session.ts\";\nimport { resolveAgentToolSettings } from \"./agent-tool-settings.ts\";\nimport { formatNoModelsAvailableMessage } from \"./auth-guidance.ts\";\nimport { AuthStorage } from \"./auth-storage.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport { createDomainDispatchRuntimeSession, isDomainRoutingEnabled, tryDomainDispatch } from \"./domain-dispatch.ts\";\nimport type { ExtensionRunner, LoadExtensionsResult, SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport { tryGrokHarnessDispatch } from \"./grok-harness-dispatch.ts\";\nimport type { LoadoutAccessPolicy } from \"./loadout-access-policy.ts\";\nimport { convertToLlm } from \"./messages.ts\";\nimport { ModelRegistry } from \"./model-registry.ts\";\nimport { findInitialModel } from \"./model-resolver.ts\";\nimport { mergeProviderAttributionHeaders } from \"./provider-attribution.ts\";\nimport { recordClaudePassiveUsage, recordCodexPassiveUsage } from \"./provider-usage.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { DefaultResourceLoader } from \"./resource-loader.ts\";\nimport { getDefaultSessionDir, SessionManager } from \"./session-manager.ts\";\nimport { classifySessionTermination, SessionTerminationError } from \"./session-termination.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport { time } from \"./timings.ts\";\nimport type { BashSandboxPreflight } from \"./tools/bash.ts\";\nimport {\n\tallToolNames,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\ttype ToolName,\n\twithFileMutationQueue,\n} from \"./tools/index.ts\";\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.omk/agent */\n\tagentDir?: string;\n\n\t/** Auth storage for credentials. Default: AuthStorage.create(agentDir/auth.json) */\n\tauthStorage?: AuthStorage;\n\t/** Model registry. Default: ModelRegistry.create(authStorage, agentDir/models.json) */\n\tmodelRegistry?: ModelRegistry;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\n\t/**\n\t * Optional default tool suppression mode when no explicit allowlist is provided.\n\t *\n\t * - \"all\": start with no tools enabled\n\t * - \"builtin\": disable the default built-in tools (read, bash, edit, write)\n\t * but keep extension/custom tools enabled\n\t */\n\tnoTools?: \"all\" | \"builtin\";\n\t/**\n\t * Optional allowlist of tool names.\n\t *\n\t * When omitted, OMK enables the default built-in tools (read, bash, edit, write)\n\t * and leaves extension/custom tools enabled unless `noTools` changes that default.\n\t * When provided, only the listed tool names are enabled.\n\t */\n\ttools?: string[];\n\t/** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */\n\texcludeTools?: string[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n\t/** Session start event metadata for extension runtime startup. */\n\tsessionStartEvent?: SessionStartEvent;\n\t/**\n\t * Optional prompt hint used only for opt-in domain routing (`OMK_DOMAIN_ROUTING=1`).\n\t * This text only selects a loadout policy and is never sent to the model.\n\t */\n\tdomainRoutingPrompt?: string;\n\t/** Optional loadout enforcement policy for SDK-created sessions. */\n\tloadoutAccessPolicy?: LoadoutAccessPolicy;\n\t/** Trusted sandbox preflight used for built-in local bash execution. */\n\tbashSandboxPreflight?: BashSandboxPreflight;\n\t/** Optional replay ledger shared with VerifiedEvidenceExecutor freshness checks. */\n\treplayLedger?: ReplayLedgerManager;\n\t/** Goal binding for AgentSession replay events; defaults to replayLedger.goalId. */\n\treplayGoalId?: string;\n\t/** Optional lane binding for AgentSession replay events. */\n\treplayLaneId?: string;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport * from \"./agent-session-runtime.ts\";\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tSlashCommandInfo,\n\tSlashCommandSource,\n\tToolDefinition,\n} from \"./extensions/index.ts\";\nexport type { PromptTemplate } from \"./prompt-templates.ts\";\nexport type { Skill } from \"./skills.ts\";\nexport type { Tool } from \"./tools/index.ts\";\n\nexport {\n\twithFileMutationQueue,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\ninterface SessionTranscriptRecovery {\n\tmessages: AgentMessage[];\n\trepair?: SessionTranscriptRepair;\n}\n\n/**\n * ALG001-A: inspect the restored transcript on every live session open/resume.\n *\n * - A clean transcript passes through untouched.\n * - Unambiguous missing-only tail results are auto-repaired: synthetic\n * terminal results (tool-result/v2 envelope) are persisted to the session\n * so the repair is durable and idempotent, together with a durable\n * `transcript_repaired` audit entry.\n * - Any duplicate/orphan/duplicate-call/interleaved corruption marks the\n * session (`session_corrupt` entry, once) and fails closed.\n */\nfunction recoverSessionTranscriptOnOpen(\n\tsessionManager: SessionManager,\n\tmessages: AgentMessage[],\n): SessionTranscriptRecovery {\n\tconst report = inspectTranscriptIntegrity(messages);\n\tif (report.ok) {\n\t\treturn { messages };\n\t}\n\n\tlet repaired: AgentMessage[];\n\ttry {\n\t\trepaired = repairTranscriptIntegrity(messages, \"Tool result missing; synthesized during session resume recovery\");\n\t} catch {\n\t\tconst alreadyMarked = sessionManager\n\t\t\t.getBranch()\n\t\t\t.some((entry) => entry.type === \"custom\" && entry.customType === \"session_corrupt\");\n\t\tif (!alreadyMarked) {\n\t\t\tsessionManager.appendCustomEntry(\"session_corrupt\", {\n\t\t\t\tissues: report.issues.map((issue) => ({\n\t\t\t\t\tkind: issue.kind,\n\t\t\t\t\ttoolCallId: issue.toolCallId,\n\t\t\t\t\t...(issue.toolName === undefined ? {} : { toolName: issue.toolName }),\n\t\t\t\t})),\n\t\t\t});\n\t\t}\n\t\tconst summary = report.issues.map((issue) => `${issue.kind}:${issue.toolCallId}`).join(\", \");\n\t\tconst firstIssue = report.issues[0]?.kind ?? \"missing_result\";\n\t\tconst termination = classifySessionTermination({\n\t\t\tsessionId: sessionManager.getSessionId(),\n\t\t\trunId: `resume-${randomUUID()}`,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsource: \"inferred_on_resume\",\n\t\t\tmessage: \"Session transcript has ambiguous tool-result corruption.\",\n\t\t\tcause: { area: \"transcript\", code: firstIssue },\n\t\t\tsideEffects: \"possible\",\n\t\t});\n\t\tthrow new SessionTerminationError(\n\t\t\t`Cannot open session: corrupt tool transcript (${summary}). ` +\n\t\t\t\t\"The session has been marked corrupt; repair it explicitly before resuming.\",\n\t\t\ttermination,\n\t\t);\n\t}\n\n\tconst inserted = repaired.slice(messages.length) as ToolResultMessage[];\n\tif (inserted.length === 0) {\n\t\treturn { messages: repaired };\n\t}\n\tfor (const message of inserted) {\n\t\tsessionManager.appendMessage(message);\n\t}\n\tconst insertedToolCallIds = inserted.map((message) => message.toolCallId);\n\tsessionManager.appendCustomEntry(\"transcript_repaired\", { insertedToolCallIds, reason: \"resume\" });\n\treturn { messages: repaired, repair: { insertedToolCallIds, reason: \"resume\" } };\n}\n\nfunction getDomainDispatchBaseToolNames(options: CreateAgentSessionOptions): string[] {\n\tif (!options.tools && (options.noTools === \"all\" || options.noTools === \"builtin\")) {\n\t\treturn [];\n\t}\n\treturn [...allToolNames];\n}\n\nfunction getAllowedToolNamesForDomainDispatch(options: CreateAgentSessionOptions): string[] | undefined {\n\treturn options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n}\n\nfunction createEffectiveLoadoutAccessPolicy(\n\toptions: CreateAgentSessionOptions,\n\tresourceLoader: ResourceLoader,\n\tcwd: string,\n\tagentDir: string,\n\tprovider?: string,\n): LoadoutAccessPolicy | undefined {\n\tif (options.loadoutAccessPolicy) {\n\t\treturn options.loadoutAccessPolicy;\n\t}\n\n\tconst session = createDomainDispatchRuntimeSession({\n\t\tbaseToolNames: getDomainDispatchBaseToolNames(options),\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tallowedToolNames: getAllowedToolNamesForDomainDispatch(options),\n\t\texcludedToolNames: options.excludeTools,\n\t});\n\n\t// Grok OAuth: apply grok-harness domain loadout without requiring OMK_DOMAIN_ROUTING=1.\n\tif (provider) {\n\t\ttry {\n\t\t\tconst grokDispatch = tryGrokHarnessDispatch({\n\t\t\t\tprovider,\n\t\t\t\tsession,\n\t\t\t\tresourceLoader,\n\t\t\t\tcwd,\n\t\t\t\tagentDir,\n\t\t\t\tenv: process.env,\n\t\t\t});\n\t\t\tif (grokDispatch.loadoutAccessPolicy) {\n\t\t\t\treturn grokDispatch.loadoutAccessPolicy;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to opt-in domain routing.\n\t\t}\n\t}\n\n\tconst domainRoutingPrompt = options.domainRoutingPrompt?.trim();\n\tif (!domainRoutingPrompt || !isDomainRoutingEnabled(process.env)) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst dispatch = tryDomainDispatch({\n\t\t\trole: \"coder\",\n\t\t\tinitialPrompt: domainRoutingPrompt,\n\t\t\tsession,\n\t\t\tresourceLoader,\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tenv: process.env,\n\t\t});\n\t\treturn dispatch.loadoutAccessPolicy;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from 'omk-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [\"read\", \"bash\"],\n * resourceLoader: loader,\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n\tlet resourceLoader = options.resourceLoader;\n\n\t// Use provided or create AuthStorage and ModelRegistry\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst authStorage = options.authStorage ?? AuthStorage.create(authPath);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, modelsPath);\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst agentToolSettings = resolveAgentToolSettings(settingsManager);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n\tlet replayLedger = options.replayLedger;\n\tlet replayGoalId = options.replayGoalId;\n\tconst sessionFile = sessionManager.getSessionFile();\n\tif (!replayLedger && sessionManager.isPersisted() && sessionFile) {\n\t\treplayGoalId ??=\n\t\t\tsessionManager\n\t\t\t\t.getSessionId()\n\t\t\t\t.replace(/[^A-Za-z0-9._-]+/g, \"-\")\n\t\t\t\t.replace(/^[._-]+|[._-]+$/g, \"\") || \"session\";\n\t\treplayLedger = new ReplayLedgerManager(replayGoalId, `${sessionFile}.replay.jsonl`);\n\t}\n\n\tif (!resourceLoader) {\n\t\tresourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Check if session has existing data to restore. Live open/resume always\n\t// inspects the transcript and either auto-repairs missing-only tail results\n\t// or fails closed on ambiguous corruption (ALG001-A).\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst transcriptRecovery = recoverSessionTranscriptOnOpen(sessionManager, existingSession.messages);\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRegistry.hasConfiguredAuth(restoredModel)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRegistry,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\t// Loadout policy after model resolution so Grok OAuth can auto-apply grok-harness.\n\tconst effectiveLoadoutAccessPolicy = createEffectiveLoadoutAccessPolicy(\n\t\toptions,\n\t\tresourceLoader,\n\t\tcwd,\n\t\tagentDir,\n\t\tmodel?.provider,\n\t);\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = hasThinkingEntry\n\t\t\t? (existingSession.thinkingLevel as ThinkingLevel)\n\t\t\t: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model) {\n\t\tthinkingLevel = \"off\";\n\t} else {\n\t\tthinkingLevel = clampThinkingLevel(model, thinkingLevel) as ThinkingLevel;\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"diagnostics\"];\n\tconst allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n\tconst excludedToolNames = options.excludeTools;\n\tconst excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;\n\tconst initialActiveToolNames: string[] = (\n\t\toptions.tools ? [...options.tools] : options.noTools ? [] : defaultActiveToolNames\n\t).filter((name) => !excludedToolNameSet?.has(name));\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst extensionRunnerRef: { current?: ExtensionRunner } = {};\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tstreamFn: async (model, context, options) => {\n\t\t\tconst auth = await modelRegistry.getApiKeyAndHeaders(model);\n\t\t\tif (!auth.ok) {\n\t\t\t\tthrow new Error(auth.error);\n\t\t\t}\n\t\t\tconst providerRetrySettings = settingsManager.getProviderRetrySettings();\n\t\t\tconst httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n\t\t\t// SDKs treat timeout=0 as 0ms (immediate timeout), not \"no timeout\".\n\t\t\t// Use max int32 to effectively disable the timeout.\n\t\t\tconst effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n\t\t\tconst timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n\t\t\tconst websocketConnectTimeoutMs =\n\t\t\t\toptions?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n\t\t\treturn streamSimple(model, context, {\n\t\t\t\t...options,\n\t\t\t\tapiKey: auth.apiKey,\n\t\t\t\ttimeoutMs,\n\t\t\t\twebsocketConnectTimeoutMs,\n\t\t\t\tmaxRetries: options?.maxRetries ?? providerRetrySettings.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n\t\t\t\tonRateLimit: async (snapshot, responseModel) => {\n\t\t\t\t\tif (auth.apiKey && /^openai-codex(?:-|$)/.test(responseModel.provider)) {\n\t\t\t\t\t\trecordCodexPassiveUsage(auth.apiKey, snapshot);\n\t\t\t\t\t} else if (auth.apiKey && responseModel.provider === \"anthropic\") {\n\t\t\t\t\t\trecordClaudePassiveUsage(auth.apiKey, snapshot);\n\t\t\t\t\t}\n\t\t\t\t\tawait options?.onRateLimit?.(snapshot, responseModel);\n\t\t\t\t},\n\t\t\t\theaders: mergeProviderAttributionHeaders(\n\t\t\t\t\tmodel,\n\t\t\t\t\tsettingsManager,\n\t\t\t\t\toptions?.sessionId,\n\t\t\t\t\tauth.headers,\n\t\t\t\t\toptions?.headers,\n\t\t\t\t),\n\t\t\t});\n\t\t},\n\t\tonPayload: async (payload, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"before_provider_request\")) {\n\t\t\t\treturn payload;\n\t\t\t}\n\t\t\treturn runner.emitBeforeProviderRequest(payload);\n\t\t},\n\t\tonResponse: async (response, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"after_provider_response\")) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait runner.emit({\n\t\t\t\ttype: \"after_provider_response\",\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: response.headers,\n\t\t\t});\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner) return messages;\n\t\t\treturn runner.emitContext(messages);\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t\ttoolTimeoutMs: agentToolSettings.toolTimeoutMs,\n\t\ttoolTimeouts: agentToolSettings.toolTimeouts,\n\t\ttoolScheduler: agentToolSettings.toolScheduler,\n\t\tmaxToolConcurrency: agentToolSettings.maxToolConcurrency,\n\t\tstrictExtensionClaims: agentToolSettings.strictExtensionClaims,\n\t\tcwd,\n\t\t// §5.5 Node identity resolver: symlink/hardlink/drive/UNC path aliases\n\t\t// conflict in the dag-v2 scheduler instead of racing (ALG002-A).\n\t\tresourceKeyResolver: createNodeResourceKeyResolver(),\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.state.messages = transcriptRecovery.messages;\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRegistry,\n\t\tinitialActiveToolNames,\n\t\tallowedToolNames,\n\t\texcludedToolNames,\n\t\textensionRunnerRef,\n\t\tloadoutAccessPolicy: effectiveLoadoutAccessPolicy,\n\t\tbashSandboxPreflight: options.bashSandboxPreflight,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t\ttranscriptRepair: transcriptRecovery.repair,\n\t\treplayLedger,\n\t\treplayGoalId,\n\t\treplayLaneId: options.replayLaneId,\n\t});\n\tconst extensionsResult = resourceLoader.getExtensions();\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
1
+ {"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport {\n\tAgent,\n\ttype AgentMessage,\n\tinspectTranscriptIntegrity,\n\trepairTranscriptIntegrity,\n\ttype ThinkingLevel,\n} from \"omk-agent-core\";\nimport { createNodeResourceKeyResolver } from \"omk-agent-core/node\";\nimport { clampThinkingLevel, type Message, type Model, streamSimple, type ToolResultMessage } from \"omk-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { ReplayLedgerManager } from \"../guardrails/evidence-system.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AgentSession, type SessionTranscriptRepair } from \"./agent-session.ts\";\nimport { resolveAgentToolSettings } from \"./agent-tool-settings.ts\";\nimport { formatNoModelsAvailableMessage } from \"./auth-guidance.ts\";\nimport { AuthStorage } from \"./auth-storage.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport { createDomainDispatchRuntimeSession, isDomainRoutingEnabled, tryDomainDispatch } from \"./domain-dispatch.ts\";\nimport type { ExtensionRunner, LoadExtensionsResult, SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport { tryGrokHarnessDispatch } from \"./grok-harness-dispatch.ts\";\nimport type { LoadoutAccessPolicy } from \"./loadout-access-policy.ts\";\nimport { convertToLlm } from \"./messages.ts\";\nimport { ModelRegistry } from \"./model-registry.ts\";\nimport { findInitialModel } from \"./model-resolver.ts\";\nimport { mergeProviderAttributionHeaders } from \"./provider-attribution.ts\";\nimport { recordClaudePassiveUsage, recordCodexPassiveUsage } from \"./provider-usage.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { DefaultResourceLoader } from \"./resource-loader.ts\";\nimport { getDefaultSessionDir, SessionManager } from \"./session-manager.ts\";\nimport { classifySessionTermination, SessionTerminationError } from \"./session-termination.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport { time } from \"./timings.ts\";\nimport type { BashSandboxPreflight } from \"./tools/bash.ts\";\nimport {\n\tallToolNames,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\ttype ToolName,\n\twithFileMutationQueue,\n} from \"./tools/index.ts\";\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.omk/agent */\n\tagentDir?: string;\n\n\t/** Auth storage for credentials. Default: AuthStorage.create(agentDir/auth.json) */\n\tauthStorage?: AuthStorage;\n\t/** Model registry. Default: ModelRegistry.create(authStorage, agentDir/models.json) */\n\tmodelRegistry?: ModelRegistry;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\t/** True when the user pinned `--model` / `--provider` for this process. */\n\tmodelPinned?: boolean;\n\n\t/**\n\t * Optional default tool suppression mode when no explicit allowlist is provided.\n\t *\n\t * - \"all\": start with no tools enabled\n\t * - \"builtin\": disable the default built-in tools (read, bash, edit, write)\n\t * but keep extension/custom tools enabled\n\t */\n\tnoTools?: \"all\" | \"builtin\";\n\t/**\n\t * Optional allowlist of tool names.\n\t *\n\t * When omitted, OMK enables the default built-in tools (read, bash, edit, write)\n\t * and leaves extension/custom tools enabled unless `noTools` changes that default.\n\t * When provided, only the listed tool names are enabled.\n\t */\n\ttools?: string[];\n\t/** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */\n\texcludeTools?: string[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n\t/** Session start event metadata for extension runtime startup. */\n\tsessionStartEvent?: SessionStartEvent;\n\t/**\n\t * Optional prompt hint used only for opt-in domain routing (`OMK_DOMAIN_ROUTING=1`).\n\t * This text only selects a loadout policy and is never sent to the model.\n\t */\n\tdomainRoutingPrompt?: string;\n\t/** Optional loadout enforcement policy for SDK-created sessions. */\n\tloadoutAccessPolicy?: LoadoutAccessPolicy;\n\t/** Trusted sandbox preflight used for built-in local bash execution. */\n\tbashSandboxPreflight?: BashSandboxPreflight;\n\t/** Optional replay ledger shared with VerifiedEvidenceExecutor freshness checks. */\n\treplayLedger?: ReplayLedgerManager;\n\t/** Goal binding for AgentSession replay events; defaults to replayLedger.goalId. */\n\treplayGoalId?: string;\n\t/** Optional lane binding for AgentSession replay events. */\n\treplayLaneId?: string;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport * from \"./agent-session-runtime.ts\";\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tSlashCommandInfo,\n\tSlashCommandSource,\n\tToolDefinition,\n} from \"./extensions/index.ts\";\nexport type { PromptTemplate } from \"./prompt-templates.ts\";\nexport type { Skill } from \"./skills.ts\";\nexport type { Tool } from \"./tools/index.ts\";\n\nexport {\n\twithFileMutationQueue,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\ninterface SessionTranscriptRecovery {\n\tmessages: AgentMessage[];\n\trepair?: SessionTranscriptRepair;\n}\n\n/**\n * ALG001-A: inspect the restored transcript on every live session open/resume.\n *\n * - A clean transcript passes through untouched.\n * - Unambiguous missing-only tail results are auto-repaired: synthetic\n * terminal results (tool-result/v2 envelope) are persisted to the session\n * so the repair is durable and idempotent, together with a durable\n * `transcript_repaired` audit entry.\n * - Any duplicate/orphan/duplicate-call/interleaved corruption marks the\n * session (`session_corrupt` entry, once) and fails closed.\n */\nfunction recoverSessionTranscriptOnOpen(\n\tsessionManager: SessionManager,\n\tmessages: AgentMessage[],\n): SessionTranscriptRecovery {\n\tconst report = inspectTranscriptIntegrity(messages);\n\tif (report.ok) {\n\t\treturn { messages };\n\t}\n\n\tlet repaired: AgentMessage[];\n\ttry {\n\t\trepaired = repairTranscriptIntegrity(messages, \"Tool result missing; synthesized during session resume recovery\");\n\t} catch {\n\t\tconst alreadyMarked = sessionManager\n\t\t\t.getBranch()\n\t\t\t.some((entry) => entry.type === \"custom\" && entry.customType === \"session_corrupt\");\n\t\tif (!alreadyMarked) {\n\t\t\tsessionManager.appendCustomEntry(\"session_corrupt\", {\n\t\t\t\tissues: report.issues.map((issue) => ({\n\t\t\t\t\tkind: issue.kind,\n\t\t\t\t\ttoolCallId: issue.toolCallId,\n\t\t\t\t\t...(issue.toolName === undefined ? {} : { toolName: issue.toolName }),\n\t\t\t\t})),\n\t\t\t});\n\t\t}\n\t\tconst summary = report.issues.map((issue) => `${issue.kind}:${issue.toolCallId}`).join(\", \");\n\t\tconst firstIssue = report.issues[0]?.kind ?? \"missing_result\";\n\t\tconst termination = classifySessionTermination({\n\t\t\tsessionId: sessionManager.getSessionId(),\n\t\t\trunId: `resume-${randomUUID()}`,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsource: \"inferred_on_resume\",\n\t\t\tmessage: \"Session transcript has ambiguous tool-result corruption.\",\n\t\t\tcause: { area: \"transcript\", code: firstIssue },\n\t\t\tsideEffects: \"possible\",\n\t\t});\n\t\tthrow new SessionTerminationError(\n\t\t\t`Cannot open session: corrupt tool transcript (${summary}). ` +\n\t\t\t\t\"The session has been marked corrupt; repair it explicitly before resuming.\",\n\t\t\ttermination,\n\t\t);\n\t}\n\n\tconst inserted = repaired.slice(messages.length) as ToolResultMessage[];\n\tif (inserted.length === 0) {\n\t\treturn { messages: repaired };\n\t}\n\tfor (const message of inserted) {\n\t\tsessionManager.appendMessage(message);\n\t}\n\tconst insertedToolCallIds = inserted.map((message) => message.toolCallId);\n\tsessionManager.appendCustomEntry(\"transcript_repaired\", { insertedToolCallIds, reason: \"resume\" });\n\treturn { messages: repaired, repair: { insertedToolCallIds, reason: \"resume\" } };\n}\n\nfunction getDomainDispatchBaseToolNames(options: CreateAgentSessionOptions): string[] {\n\tif (!options.tools && (options.noTools === \"all\" || options.noTools === \"builtin\")) {\n\t\treturn [];\n\t}\n\treturn [...allToolNames];\n}\n\nfunction getAllowedToolNamesForDomainDispatch(options: CreateAgentSessionOptions): string[] | undefined {\n\treturn options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n}\n\nfunction createEffectiveLoadoutAccessPolicy(\n\toptions: CreateAgentSessionOptions,\n\tresourceLoader: ResourceLoader,\n\tcwd: string,\n\tagentDir: string,\n\tprovider?: string,\n): LoadoutAccessPolicy | undefined {\n\tif (options.loadoutAccessPolicy) {\n\t\treturn options.loadoutAccessPolicy;\n\t}\n\n\tconst session = createDomainDispatchRuntimeSession({\n\t\tbaseToolNames: getDomainDispatchBaseToolNames(options),\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tallowedToolNames: getAllowedToolNamesForDomainDispatch(options),\n\t\texcludedToolNames: options.excludeTools,\n\t});\n\n\t// Grok OAuth: apply grok-harness domain loadout without requiring OMK_DOMAIN_ROUTING=1.\n\tif (provider) {\n\t\ttry {\n\t\t\tconst grokDispatch = tryGrokHarnessDispatch({\n\t\t\t\tprovider,\n\t\t\t\tsession,\n\t\t\t\tresourceLoader,\n\t\t\t\tcwd,\n\t\t\t\tagentDir,\n\t\t\t\tenv: process.env,\n\t\t\t});\n\t\t\tif (grokDispatch.loadoutAccessPolicy) {\n\t\t\t\treturn grokDispatch.loadoutAccessPolicy;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to opt-in domain routing.\n\t\t}\n\t}\n\n\tconst domainRoutingPrompt = options.domainRoutingPrompt?.trim();\n\tif (!domainRoutingPrompt || !isDomainRoutingEnabled(process.env)) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst dispatch = tryDomainDispatch({\n\t\t\trole: \"coder\",\n\t\t\tinitialPrompt: domainRoutingPrompt,\n\t\t\tsession,\n\t\t\tresourceLoader,\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tenv: process.env,\n\t\t});\n\t\treturn dispatch.loadoutAccessPolicy;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from 'omk-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [\"read\", \"bash\"],\n * resourceLoader: loader,\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n\tlet resourceLoader = options.resourceLoader;\n\n\t// Use provided or create AuthStorage and ModelRegistry\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst authStorage = options.authStorage ?? AuthStorage.create(authPath);\n\tconst modelRegistry = options.modelRegistry ?? ModelRegistry.create(authStorage, modelsPath);\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst agentToolSettings = resolveAgentToolSettings(settingsManager);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n\tlet replayLedger = options.replayLedger;\n\tlet replayGoalId = options.replayGoalId;\n\tconst sessionFile = sessionManager.getSessionFile();\n\tif (!replayLedger && sessionManager.isPersisted() && sessionFile) {\n\t\treplayGoalId ??=\n\t\t\tsessionManager\n\t\t\t\t.getSessionId()\n\t\t\t\t.replace(/[^A-Za-z0-9._-]+/g, \"-\")\n\t\t\t\t.replace(/^[._-]+|[._-]+$/g, \"\") || \"session\";\n\t\treplayLedger = new ReplayLedgerManager(replayGoalId, `${sessionFile}.replay.jsonl`);\n\t}\n\n\tif (!resourceLoader) {\n\t\tresourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Check if session has existing data to restore. Live open/resume always\n\t// inspects the transcript and either auto-repairs missing-only tail results\n\t// or fails closed on ambiguous corruption (ALG001-A).\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst transcriptRecovery = recoverSessionTranscriptOnOpen(sessionManager, existingSession.messages);\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRegistry.hasConfiguredAuth(restoredModel)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRegistry,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\t// Loadout policy after model resolution so Grok OAuth can auto-apply grok-harness.\n\tconst effectiveLoadoutAccessPolicy = createEffectiveLoadoutAccessPolicy(\n\t\toptions,\n\t\tresourceLoader,\n\t\tcwd,\n\t\tagentDir,\n\t\tmodel?.provider,\n\t);\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = hasThinkingEntry\n\t\t\t? (existingSession.thinkingLevel as ThinkingLevel)\n\t\t\t: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model) {\n\t\tthinkingLevel = \"off\";\n\t} else {\n\t\tthinkingLevel = clampThinkingLevel(model, thinkingLevel) as ThinkingLevel;\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"diagnostics\"];\n\tconst allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n\tconst excludedToolNames = options.excludeTools;\n\tconst excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;\n\tconst initialActiveToolNames: string[] = (\n\t\toptions.tools ? [...options.tools] : options.noTools ? [] : defaultActiveToolNames\n\t).filter((name) => !excludedToolNameSet?.has(name));\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst extensionRunnerRef: { current?: ExtensionRunner } = {};\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tstreamFn: async (model, context, options) => {\n\t\t\tconst auth = await modelRegistry.getApiKeyAndHeaders(model);\n\t\t\tif (!auth.ok) {\n\t\t\t\tthrow new Error(auth.error);\n\t\t\t}\n\t\t\tconst providerRetrySettings = settingsManager.getProviderRetrySettings();\n\t\t\tconst httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n\t\t\t// SDKs treat timeout=0 as 0ms (immediate timeout), not \"no timeout\".\n\t\t\t// Use max int32 to effectively disable the timeout.\n\t\t\tconst effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n\t\t\tconst timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n\t\t\tconst websocketConnectTimeoutMs =\n\t\t\t\toptions?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n\t\t\treturn streamSimple(model, context, {\n\t\t\t\t...options,\n\t\t\t\tapiKey: auth.apiKey,\n\t\t\t\ttimeoutMs,\n\t\t\t\twebsocketConnectTimeoutMs,\n\t\t\t\tmaxRetries: options?.maxRetries ?? providerRetrySettings.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n\t\t\t\tonRateLimit: async (snapshot, responseModel) => {\n\t\t\t\t\tif (auth.apiKey && /^openai-codex(?:-|$)/.test(responseModel.provider)) {\n\t\t\t\t\t\trecordCodexPassiveUsage(auth.apiKey, snapshot);\n\t\t\t\t\t} else if (auth.apiKey && responseModel.provider === \"anthropic\") {\n\t\t\t\t\t\trecordClaudePassiveUsage(auth.apiKey, snapshot);\n\t\t\t\t\t}\n\t\t\t\t\tawait options?.onRateLimit?.(snapshot, responseModel);\n\t\t\t\t},\n\t\t\t\theaders: mergeProviderAttributionHeaders(\n\t\t\t\t\tmodel,\n\t\t\t\t\tsettingsManager,\n\t\t\t\t\toptions?.sessionId,\n\t\t\t\t\tauth.headers,\n\t\t\t\t\toptions?.headers,\n\t\t\t\t),\n\t\t\t});\n\t\t},\n\t\tonPayload: async (payload, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"before_provider_request\")) {\n\t\t\t\treturn payload;\n\t\t\t}\n\t\t\treturn runner.emitBeforeProviderRequest(payload);\n\t\t},\n\t\tonResponse: async (response, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"after_provider_response\")) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait runner.emit({\n\t\t\t\ttype: \"after_provider_response\",\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: response.headers,\n\t\t\t});\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner) return messages;\n\t\t\treturn runner.emitContext(messages);\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t\ttoolTimeoutMs: agentToolSettings.toolTimeoutMs,\n\t\ttoolTimeouts: agentToolSettings.toolTimeouts,\n\t\ttoolScheduler: agentToolSettings.toolScheduler,\n\t\tmaxToolConcurrency: agentToolSettings.maxToolConcurrency,\n\t\tstrictExtensionClaims: agentToolSettings.strictExtensionClaims,\n\t\tcwd,\n\t\t// §5.5 Node identity resolver: symlink/hardlink/drive/UNC path aliases\n\t\t// conflict in the dag-v2 scheduler instead of racing (ALG002-A).\n\t\tresourceKeyResolver: createNodeResourceKeyResolver(),\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.state.messages = transcriptRecovery.messages;\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRegistry,\n\t\tinitialActiveToolNames,\n\t\tallowedToolNames,\n\t\texcludedToolNames,\n\t\textensionRunnerRef,\n\t\tloadoutAccessPolicy: effectiveLoadoutAccessPolicy,\n\t\tbashSandboxPreflight: options.bashSandboxPreflight,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t\tmodelPinned: options.modelPinned,\n\t\ttranscriptRepair: transcriptRecovery.repair,\n\t\treplayLedger,\n\t\treplayGoalId,\n\t\treplayLaneId: options.replayLaneId,\n\t});\n\tconst extensionsResult = resourceLoader.getExtensions();\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import type { ContextFile } from "./resource-loader.ts";
2
+ import type { Skill } from "./skills.ts";
3
+ import { type BuildSystemPromptOptions } from "./system-prompt.ts";
4
+ export interface SessionSystemPromptInput {
5
+ readonly cwd: string;
6
+ readonly toolNames: readonly string[];
7
+ readonly hasTool: (name: string) => boolean;
8
+ readonly toolPromptSnippets: ReadonlyMap<string, string>;
9
+ readonly toolPromptGuidelines: ReadonlyMap<string, readonly string[]>;
10
+ readonly customPrompt?: string;
11
+ readonly appendSystemPrompt?: readonly string[];
12
+ readonly providerAppend?: string;
13
+ readonly skills: readonly Skill[];
14
+ readonly contextFiles: readonly ContextFile[];
15
+ readonly contextBudget?: BuildSystemPromptOptions["contextBudget"];
16
+ }
17
+ export interface SessionSystemPromptAssembly {
18
+ readonly options: BuildSystemPromptOptions;
19
+ readonly prompt: string;
20
+ readonly cacheBoundary: number;
21
+ }
22
+ /**
23
+ * Pure assembly of the session system-prompt plan: tool filtering, snippet and
24
+ * guideline collection, and append-section joining. Callers resolve side effects
25
+ * (resource loader reads, provider playbook files) and pass them in.
26
+ */
27
+ export declare function assembleSessionSystemPrompt(input: SessionSystemPromptInput): SessionSystemPromptAssembly;
28
+ //# sourceMappingURL=session-system-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/session-system-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,wBAAwB,EAAiD,MAAM,oBAAoB,CAAC;AAElH,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5C,QAAQ,CAAC,kBAAkB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzD,QAAQ,CAAC,oBAAoB,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IACtE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9C,QAAQ,CAAC,aAAa,CAAC,EAAE,wBAAwB,CAAC,eAAe,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,wBAAwB,GAAG,2BAA2B,CA4BxG","sourcesContent":["import type { ContextFile } from \"./resource-loader.ts\";\nimport type { Skill } from \"./skills.ts\";\nimport { type BuildSystemPromptOptions, type BuiltSystemPrompt, buildSystemPromptPlan } from \"./system-prompt.ts\";\n\nexport interface SessionSystemPromptInput {\n\treadonly cwd: string;\n\treadonly toolNames: readonly string[];\n\treadonly hasTool: (name: string) => boolean;\n\treadonly toolPromptSnippets: ReadonlyMap<string, string>;\n\treadonly toolPromptGuidelines: ReadonlyMap<string, readonly string[]>;\n\treadonly customPrompt?: string;\n\treadonly appendSystemPrompt?: readonly string[];\n\treadonly providerAppend?: string;\n\treadonly skills: readonly Skill[];\n\treadonly contextFiles: readonly ContextFile[];\n\treadonly contextBudget?: BuildSystemPromptOptions[\"contextBudget\"];\n}\n\nexport interface SessionSystemPromptAssembly {\n\treadonly options: BuildSystemPromptOptions;\n\treadonly prompt: string;\n\treadonly cacheBoundary: number;\n}\n\n/**\n * Pure assembly of the session system-prompt plan: tool filtering, snippet and\n * guideline collection, and append-section joining. Callers resolve side effects\n * (resource loader reads, provider playbook files) and pass them in.\n */\nexport function assembleSessionSystemPrompt(input: SessionSystemPromptInput): SessionSystemPromptAssembly {\n\tconst validToolNames = input.toolNames.filter((name) => input.hasTool(name));\n\tconst toolSnippets: Record<string, string> = {};\n\tconst promptGuidelines: string[] = [];\n\tfor (const name of validToolNames) {\n\t\tconst snippet = input.toolPromptSnippets.get(name);\n\t\tif (snippet) toolSnippets[name] = snippet;\n\t\tconst toolGuidelines = input.toolPromptGuidelines.get(name);\n\t\tif (toolGuidelines) promptGuidelines.push(...toolGuidelines);\n\t}\n\n\tconst appendParts = [...(input.appendSystemPrompt ?? [])];\n\tif (input.providerAppend) appendParts.push(input.providerAppend);\n\tconst appendSystemPrompt = appendParts.length > 0 ? appendParts.join(\"\\n\\n\") : undefined;\n\n\tconst options: BuildSystemPromptOptions = {\n\t\tcwd: input.cwd,\n\t\tskills: [...input.skills],\n\t\tcontextFiles: [...input.contextFiles],\n\t\tcustomPrompt: input.customPrompt,\n\t\tappendSystemPrompt,\n\t\tselectedTools: validToolNames,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tcontextBudget: input.contextBudget,\n\t};\n\tconst built: BuiltSystemPrompt = buildSystemPromptPlan(options);\n\treturn { options, prompt: built.prompt, cacheBoundary: built.cacheBoundary };\n}\n"]}
@@ -0,0 +1,37 @@
1
+ import { buildSystemPromptPlan } from "./system-prompt.js";
2
+ /**
3
+ * Pure assembly of the session system-prompt plan: tool filtering, snippet and
4
+ * guideline collection, and append-section joining. Callers resolve side effects
5
+ * (resource loader reads, provider playbook files) and pass them in.
6
+ */
7
+ export function assembleSessionSystemPrompt(input) {
8
+ const validToolNames = input.toolNames.filter((name) => input.hasTool(name));
9
+ const toolSnippets = {};
10
+ const promptGuidelines = [];
11
+ for (const name of validToolNames) {
12
+ const snippet = input.toolPromptSnippets.get(name);
13
+ if (snippet)
14
+ toolSnippets[name] = snippet;
15
+ const toolGuidelines = input.toolPromptGuidelines.get(name);
16
+ if (toolGuidelines)
17
+ promptGuidelines.push(...toolGuidelines);
18
+ }
19
+ const appendParts = [...(input.appendSystemPrompt ?? [])];
20
+ if (input.providerAppend)
21
+ appendParts.push(input.providerAppend);
22
+ const appendSystemPrompt = appendParts.length > 0 ? appendParts.join("\n\n") : undefined;
23
+ const options = {
24
+ cwd: input.cwd,
25
+ skills: [...input.skills],
26
+ contextFiles: [...input.contextFiles],
27
+ customPrompt: input.customPrompt,
28
+ appendSystemPrompt,
29
+ selectedTools: validToolNames,
30
+ toolSnippets,
31
+ promptGuidelines,
32
+ contextBudget: input.contextBudget,
33
+ };
34
+ const built = buildSystemPromptPlan(options);
35
+ return { options, prompt: built.prompt, cacheBoundary: built.cacheBoundary };
36
+ }
37
+ //# sourceMappingURL=session-system-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-system-prompt.js","sourceRoot":"","sources":["../../src/core/session-system-prompt.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyD,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAsBlH;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CAAC,KAA+B,EAA+B;IACzG,MAAM,cAAc,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7E,MAAM,YAAY,GAA2B,EAAE,CAAC;IAChD,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,OAAO;YAAE,YAAY,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;QAC1C,MAAM,cAAc,GAAG,KAAK,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5D,IAAI,cAAc;YAAE,gBAAgB,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1D,IAAI,KAAK,CAAC,cAAc;QAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACjE,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEzF,MAAM,OAAO,GAA6B;QACzC,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QACzB,YAAY,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC;QACrC,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,kBAAkB;QAClB,aAAa,EAAE,cAAc;QAC7B,YAAY;QACZ,gBAAgB;QAChB,aAAa,EAAE,KAAK,CAAC,aAAa;KAClC,CAAC;IACF,MAAM,KAAK,GAAsB,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAChE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC;AAAA,CAC7E","sourcesContent":["import type { ContextFile } from \"./resource-loader.ts\";\nimport type { Skill } from \"./skills.ts\";\nimport { type BuildSystemPromptOptions, type BuiltSystemPrompt, buildSystemPromptPlan } from \"./system-prompt.ts\";\n\nexport interface SessionSystemPromptInput {\n\treadonly cwd: string;\n\treadonly toolNames: readonly string[];\n\treadonly hasTool: (name: string) => boolean;\n\treadonly toolPromptSnippets: ReadonlyMap<string, string>;\n\treadonly toolPromptGuidelines: ReadonlyMap<string, readonly string[]>;\n\treadonly customPrompt?: string;\n\treadonly appendSystemPrompt?: readonly string[];\n\treadonly providerAppend?: string;\n\treadonly skills: readonly Skill[];\n\treadonly contextFiles: readonly ContextFile[];\n\treadonly contextBudget?: BuildSystemPromptOptions[\"contextBudget\"];\n}\n\nexport interface SessionSystemPromptAssembly {\n\treadonly options: BuildSystemPromptOptions;\n\treadonly prompt: string;\n\treadonly cacheBoundary: number;\n}\n\n/**\n * Pure assembly of the session system-prompt plan: tool filtering, snippet and\n * guideline collection, and append-section joining. Callers resolve side effects\n * (resource loader reads, provider playbook files) and pass them in.\n */\nexport function assembleSessionSystemPrompt(input: SessionSystemPromptInput): SessionSystemPromptAssembly {\n\tconst validToolNames = input.toolNames.filter((name) => input.hasTool(name));\n\tconst toolSnippets: Record<string, string> = {};\n\tconst promptGuidelines: string[] = [];\n\tfor (const name of validToolNames) {\n\t\tconst snippet = input.toolPromptSnippets.get(name);\n\t\tif (snippet) toolSnippets[name] = snippet;\n\t\tconst toolGuidelines = input.toolPromptGuidelines.get(name);\n\t\tif (toolGuidelines) promptGuidelines.push(...toolGuidelines);\n\t}\n\n\tconst appendParts = [...(input.appendSystemPrompt ?? [])];\n\tif (input.providerAppend) appendParts.push(input.providerAppend);\n\tconst appendSystemPrompt = appendParts.length > 0 ? appendParts.join(\"\\n\\n\") : undefined;\n\n\tconst options: BuildSystemPromptOptions = {\n\t\tcwd: input.cwd,\n\t\tskills: [...input.skills],\n\t\tcontextFiles: [...input.contextFiles],\n\t\tcustomPrompt: input.customPrompt,\n\t\tappendSystemPrompt,\n\t\tselectedTools: validToolNames,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tcontextBudget: input.contextBudget,\n\t};\n\tconst built: BuiltSystemPrompt = buildSystemPromptPlan(options);\n\treturn { options, prompt: built.prompt, cacheBoundary: built.cacheBoundary };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function isExactRecord(value: unknown, keys: readonly string[]): value is Record<string, unknown>;
2
+ //# sourceMappingURL=strict-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strict-record.d.ts","sourceRoot":"","sources":["../../src/core/strict-record.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMvG","sourcesContent":["export function isExactRecord(value: unknown, keys: readonly string[]): value is Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n\tconst compare = (left: string, right: string): number => left.localeCompare(right);\n\tconst actual = Object.keys(value).sort(compare);\n\tconst expected = [...keys].sort(compare);\n\treturn actual.length === expected.length && actual.every((key, index) => key === expected[index]);\n}\n"]}
@@ -0,0 +1,9 @@
1
+ export function isExactRecord(value, keys) {
2
+ if (typeof value !== "object" || value === null || Array.isArray(value))
3
+ return false;
4
+ const compare = (left, right) => left.localeCompare(right);
5
+ const actual = Object.keys(value).sort(compare);
6
+ const expected = [...keys].sort(compare);
7
+ return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
8
+ }
9
+ //# sourceMappingURL=strict-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strict-record.js","sourceRoot":"","sources":["../../src/core/strict-record.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,IAAuB,EAAoC;IACxG,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtF,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,KAAa,EAAU,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAAA,CAClG","sourcesContent":["export function isExactRecord(value: unknown, keys: readonly string[]): value is Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n\tconst compare = (left: string, right: string): number => left.localeCompare(right);\n\tconst actual = Object.keys(value).sort(compare);\n\tconst expected = [...keys].sort(compare);\n\treturn actual.length === expected.length && actual.every((key, index) => key === expected[index]);\n}\n"]}
@@ -0,0 +1,11 @@
1
+ export interface ToolContentBlock {
2
+ readonly type: string;
3
+ readonly id?: string;
4
+ }
5
+ export interface ToolPairMessage {
6
+ readonly role: string;
7
+ readonly content?: readonly ToolContentBlock[] | string;
8
+ readonly toolCallId?: string;
9
+ }
10
+ export declare function applyToolPairRepair<T extends ToolPairMessage>(messages: readonly T[]): T[];
11
+ //# sourceMappingURL=tool-pair-repair.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-pair-repair.d.ts","sourceRoot":"","sources":["../../src/core/tool-pair-repair.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,CAAC;IACxD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAMD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,eAAe,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,CA8B1F","sourcesContent":["export interface ToolContentBlock {\n\treadonly type: string;\n\treadonly id?: string;\n}\n\nexport interface ToolPairMessage {\n\treadonly role: string;\n\treadonly content?: readonly ToolContentBlock[] | string;\n\treadonly toolCallId?: string;\n}\n\nfunction asBlocks(content: ToolPairMessage[\"content\"]): readonly ToolContentBlock[] {\n\treturn Array.isArray(content) ? content : [];\n}\n\nexport function applyToolPairRepair<T extends ToolPairMessage>(messages: readonly T[]): T[] {\n\tconst resultIds = new Set<string>();\n\tfor (const message of messages) {\n\t\tif (message.role === \"toolResult\" && typeof message.toolCallId === \"string\") {\n\t\t\tresultIds.add(message.toolCallId);\n\t\t}\n\t}\n\n\tconst keptIds = new Set<string>();\n\tconst repaired: T[] = [];\n\tfor (const message of messages) {\n\t\tif (message.role === \"assistant\") {\n\t\t\tconst original = asBlocks(message.content);\n\t\t\tconst content = original.filter((block) => {\n\t\t\t\tif (block.type !== \"toolCall\") return true;\n\t\t\t\tif (typeof block.id !== \"string\" || !resultIds.has(block.id)) return false;\n\t\t\t\tkeptIds.add(block.id);\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tif (content.length === 0) continue;\n\t\t\trepaired.push(content.length === original.length ? message : { ...message, content });\n\t\t\tcontinue;\n\t\t}\n\t\tif (message.role === \"toolResult\") {\n\t\t\tif (typeof message.toolCallId === \"string\" && keptIds.has(message.toolCallId)) repaired.push(message);\n\t\t\tcontinue;\n\t\t}\n\t\trepaired.push(message);\n\t}\n\treturn repaired;\n}\n"]}
@@ -0,0 +1,38 @@
1
+ function asBlocks(content) {
2
+ return Array.isArray(content) ? content : [];
3
+ }
4
+ export function applyToolPairRepair(messages) {
5
+ const resultIds = new Set();
6
+ for (const message of messages) {
7
+ if (message.role === "toolResult" && typeof message.toolCallId === "string") {
8
+ resultIds.add(message.toolCallId);
9
+ }
10
+ }
11
+ const keptIds = new Set();
12
+ const repaired = [];
13
+ for (const message of messages) {
14
+ if (message.role === "assistant") {
15
+ const original = asBlocks(message.content);
16
+ const content = original.filter((block) => {
17
+ if (block.type !== "toolCall")
18
+ return true;
19
+ if (typeof block.id !== "string" || !resultIds.has(block.id))
20
+ return false;
21
+ keptIds.add(block.id);
22
+ return true;
23
+ });
24
+ if (content.length === 0)
25
+ continue;
26
+ repaired.push(content.length === original.length ? message : { ...message, content });
27
+ continue;
28
+ }
29
+ if (message.role === "toolResult") {
30
+ if (typeof message.toolCallId === "string" && keptIds.has(message.toolCallId))
31
+ repaired.push(message);
32
+ continue;
33
+ }
34
+ repaired.push(message);
35
+ }
36
+ return repaired;
37
+ }
38
+ //# sourceMappingURL=tool-pair-repair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-pair-repair.js","sourceRoot":"","sources":["../../src/core/tool-pair-repair.ts"],"names":[],"mappings":"AAWA,SAAS,QAAQ,CAAC,OAAmC,EAA+B;IACnF,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AAAA,CAC7C;AAED,MAAM,UAAU,mBAAmB,CAA4B,QAAsB,EAAO;IAC3F,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAChC,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YAC7E,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;IACF,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,QAAQ,GAAQ,EAAE,CAAC;IACzB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAChC,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAClC,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;gBAC1C,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;oBAAE,OAAO,IAAI,CAAC;gBAC3C,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBAAE,OAAO,KAAK,CAAC;gBAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACtB,OAAO,IAAI,CAAC;YAAA,CACZ,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACnC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YACtF,SAAS;QACV,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACnC,IAAI,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtG,SAAS;QACV,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,QAAQ,CAAC;AAAA,CAChB","sourcesContent":["export interface ToolContentBlock {\n\treadonly type: string;\n\treadonly id?: string;\n}\n\nexport interface ToolPairMessage {\n\treadonly role: string;\n\treadonly content?: readonly ToolContentBlock[] | string;\n\treadonly toolCallId?: string;\n}\n\nfunction asBlocks(content: ToolPairMessage[\"content\"]): readonly ToolContentBlock[] {\n\treturn Array.isArray(content) ? content : [];\n}\n\nexport function applyToolPairRepair<T extends ToolPairMessage>(messages: readonly T[]): T[] {\n\tconst resultIds = new Set<string>();\n\tfor (const message of messages) {\n\t\tif (message.role === \"toolResult\" && typeof message.toolCallId === \"string\") {\n\t\t\tresultIds.add(message.toolCallId);\n\t\t}\n\t}\n\n\tconst keptIds = new Set<string>();\n\tconst repaired: T[] = [];\n\tfor (const message of messages) {\n\t\tif (message.role === \"assistant\") {\n\t\t\tconst original = asBlocks(message.content);\n\t\t\tconst content = original.filter((block) => {\n\t\t\t\tif (block.type !== \"toolCall\") return true;\n\t\t\t\tif (typeof block.id !== \"string\" || !resultIds.has(block.id)) return false;\n\t\t\t\tkeptIds.add(block.id);\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tif (content.length === 0) continue;\n\t\t\trepaired.push(content.length === original.length ? message : { ...message, content });\n\t\t\tcontinue;\n\t\t}\n\t\tif (message.role === \"toolResult\") {\n\t\t\tif (typeof message.toolCallId === \"string\" && keptIds.has(message.toolCallId)) repaired.push(message);\n\t\t\tcontinue;\n\t\t}\n\t\trepaired.push(message);\n\t}\n\treturn repaired;\n}\n"]}
@@ -0,0 +1,13 @@
1
+ export interface SpillInput {
2
+ readonly kind: "read" | "bash";
3
+ readonly preview: string;
4
+ readonly full: string;
5
+ readonly truncated: boolean;
6
+ readonly path: string;
7
+ }
8
+ export interface SpillResult {
9
+ readonly preview: string;
10
+ readonly path: string;
11
+ }
12
+ export declare function spillTruncatedOutput(input: SpillInput): SpillResult;
13
+ //# sourceMappingURL=artifact-spill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-spill.d.ts","sourceRoot":"","sources":["../../../src/core/tools/artifact-spill.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAiBnE","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { chmodSync, mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { formatSize } from \"./truncate.ts\";\n\nexport interface SpillInput {\n\treadonly kind: \"read\" | \"bash\";\n\treadonly preview: string;\n\treadonly full: string;\n\treadonly truncated: boolean;\n\treadonly path: string;\n}\n\nexport interface SpillResult {\n\treadonly preview: string;\n\treadonly path: string;\n}\n\nexport function spillTruncatedOutput(input: SpillInput): SpillResult {\n\tif (!input.truncated) return { preview: input.preview, path: input.path };\n\tconst directory = mkdtempSync(join(tmpdir(), \"omk-spill-\"));\n\tchmodSync(directory, 0o700);\n\tconst sourceDigest = createHash(\"sha256\").update(input.path).digest(\"hex\").slice(0, 16);\n\tconst spillPath = join(directory, `${input.kind}-${sourceDigest}.txt`);\n\ttry {\n\t\twriteFileSync(spillPath, input.full, { encoding: \"utf8\", flag: \"wx\", mode: 0o600 });\n\t} catch (error) {\n\t\trmSync(directory, { recursive: true, force: true });\n\t\tthrow error;\n\t}\n\tconst size = formatSize(Buffer.byteLength(input.full, \"utf-8\"));\n\treturn {\n\t\tpreview: `${input.preview}\\n\\n[Full ${input.kind} output spilled to ${spillPath} (${size}).]`,\n\t\tpath: spillPath,\n\t};\n}\n"]}
@@ -0,0 +1,26 @@
1
+ import { createHash } from "node:crypto";
2
+ import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { formatSize } from "./truncate.js";
6
+ export function spillTruncatedOutput(input) {
7
+ if (!input.truncated)
8
+ return { preview: input.preview, path: input.path };
9
+ const directory = mkdtempSync(join(tmpdir(), "omk-spill-"));
10
+ chmodSync(directory, 0o700);
11
+ const sourceDigest = createHash("sha256").update(input.path).digest("hex").slice(0, 16);
12
+ const spillPath = join(directory, `${input.kind}-${sourceDigest}.txt`);
13
+ try {
14
+ writeFileSync(spillPath, input.full, { encoding: "utf8", flag: "wx", mode: 0o600 });
15
+ }
16
+ catch (error) {
17
+ rmSync(directory, { recursive: true, force: true });
18
+ throw error;
19
+ }
20
+ const size = formatSize(Buffer.byteLength(input.full, "utf-8"));
21
+ return {
22
+ preview: `${input.preview}\n\n[Full ${input.kind} output spilled to ${spillPath} (${size}).]`,
23
+ path: spillPath,
24
+ };
25
+ }
26
+ //# sourceMappingURL=artifact-spill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-spill.js","sourceRoot":"","sources":["../../../src/core/tools/artifact-spill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAe3C,MAAM,UAAU,oBAAoB,CAAC,KAAiB,EAAe;IACpE,IAAI,CAAC,KAAK,CAAC,SAAS;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1E,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC;IAC5D,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC5B,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxF,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,KAAK,CAAC,IAAI,IAAI,YAAY,MAAM,CAAC,CAAC;IACvE,IAAI,CAAC;QACJ,aAAa,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,MAAM,KAAK,CAAC;IACb,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAChE,OAAO;QACN,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,aAAa,KAAK,CAAC,IAAI,sBAAsB,SAAS,KAAK,IAAI,KAAK;QAC7F,IAAI,EAAE,SAAS;KACf,CAAC;AAAA,CACF","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { chmodSync, mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { formatSize } from \"./truncate.ts\";\n\nexport interface SpillInput {\n\treadonly kind: \"read\" | \"bash\";\n\treadonly preview: string;\n\treadonly full: string;\n\treadonly truncated: boolean;\n\treadonly path: string;\n}\n\nexport interface SpillResult {\n\treadonly preview: string;\n\treadonly path: string;\n}\n\nexport function spillTruncatedOutput(input: SpillInput): SpillResult {\n\tif (!input.truncated) return { preview: input.preview, path: input.path };\n\tconst directory = mkdtempSync(join(tmpdir(), \"omk-spill-\"));\n\tchmodSync(directory, 0o700);\n\tconst sourceDigest = createHash(\"sha256\").update(input.path).digest(\"hex\").slice(0, 16);\n\tconst spillPath = join(directory, `${input.kind}-${sourceDigest}.txt`);\n\ttry {\n\t\twriteFileSync(spillPath, input.full, { encoding: \"utf8\", flag: \"wx\", mode: 0o600 });\n\t} catch (error) {\n\t\trmSync(directory, { recursive: true, force: true });\n\t\tthrow error;\n\t}\n\tconst size = formatSize(Buffer.byteLength(input.full, \"utf-8\"));\n\treturn {\n\t\tpreview: `${input.preview}\\n\\n[Full ${input.kind} output spilled to ${spillPath} (${size}).]`,\n\t\tpath: spillPath,\n\t};\n}\n"]}
@@ -41,10 +41,13 @@ export interface BashOperations {
41
41
  * This is useful for extensions that intercept user_bash and still want OMK's
42
42
  * standard local shell behavior while wrapping, sandboxing, or rewriting commands.
43
43
  */
44
- export declare function createLocalBashOperations(options?: {
45
- shellPath?: string;
46
- sandboxPolicy?: BashSandboxPreflight;
47
- }): BashOperations;
44
+ export interface LocalBashOperationsOptions {
45
+ readonly shellPath?: string;
46
+ readonly sandboxPolicy?: BashSandboxPreflight;
47
+ /** Override backend probing for embedders and deterministic tests. */
48
+ readonly detectSandboxBackend?: () => SandboxBackendStatus;
49
+ }
50
+ export declare function createLocalBashOperations(options?: LocalBashOperationsOptions): BashOperations;
48
51
  /**
49
52
  * Sandbox preflight inputs for local bash operations. When provided to
50
53
  * {@link createLocalBashOperations}, every spawn is gated by the sandbox spawn
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAa5C,OAAO,KAAK,EAAoB,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACxG,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAE3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAA8B,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAI7F,OAAO,EAAoD,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAExG,QAAA,MAAM,UAAU;;;EAGd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B;;;;;;OAMG;IACH,IAAI,EAAE,CACL,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;KACxB,KACG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,oBAAoB,CAAC;CACrC,GAAG,cAAc,CAqFjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACpC,0DAA0D;IAC1D,MAAM,EAAE,aAAa,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAC/B,iFAAiF;IACjF,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC5D;AAMD,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;AA6B5E,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,uDAAuD;IACvD,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,2DAA2D;IAC3D,SAAS,CAAC,EAAE,aAAa,CAAC;CAC1B;AAKD,KAAK,eAAe,GAAG;IACtB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;CACrC,CAAC;AA8GF,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CAsMjF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport type { AgentTool } from \"omk-agent-core\";\nimport { Container, Text, truncateToWidth } from \"omk-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport { classifyShellCommand } from \"../command-safety.ts\";\nimport type { ExtensionContext, ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { assertLoadoutAccess, type LoadoutAccessGuard } from \"../loadout-access-policy.ts\";\nimport { detectSandboxBackend } from \"../sandbox/backend.ts\";\nimport type { SandboxBackendStatus, SandboxPathResolver, SandboxPolicy } from \"../sandbox/policy.ts\";\nimport { buildSandboxedSpawnRequest, type SandboxedSpawnRequest } from \"../sandbox/spawn.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { getTextOutput, invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\n/**\n * Create bash operations using OMK's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want OMK's\n * standard local shell behavior while wrapping, sandboxing, or rewriting commands.\n */\nexport function createLocalBashOperations(options?: {\n\tshellPath?: string;\n\tsandboxPolicy?: BashSandboxPreflight;\n}): BashOperations {\n\tconst sandbox = options?.sandboxPolicy;\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst { shell, args } = getShellConfig(options?.shellPath);\n\t\t\tlet spawnCommand = shell;\n\t\t\tlet spawnArgs = [...args, command];\n\t\t\tlet spawnCwd = cwd;\n\t\t\tlet spawnEnv: NodeJS.ProcessEnv = env ?? getShellEnv();\n\t\t\tif (sandbox) {\n\t\t\t\tconst backend = sandbox.backend ?? defaultBashSandboxBackend();\n\t\t\t\tconst request = buildSandboxedSpawnRequest({\n\t\t\t\t\targv: [shell, ...args, command],\n\t\t\t\t\tcwd,\n\t\t\t\t\tenv: spawnEnv,\n\t\t\t\t\tpolicy: sandbox.policy,\n\t\t\t\t\tbackend,\n\t\t\t\t\tresolver: sandbox.resolver,\n\t\t\t\t});\n\t\t\t\tsandbox.onSpawnDecision?.(request);\n\t\t\t\tif (!request.allowed) {\n\t\t\t\t\tthrow new Error(`sandbox: shell denied\\n[${request.rule}] ${request.reason}`);\n\t\t\t\t}\n\t\t\t\tspawnCommand = request.argv[0];\n\t\t\t\tspawnArgs = [...request.argv.slice(1)];\n\t\t\t\tspawnCwd = request.cwd;\n\t\t\t\tspawnEnv = request.env;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait fsAccess(spawnCwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${spawnCwd}\\nCannot execute bash commands.`);\n\t\t\t}\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\n\t\t\t// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process -- argv-array spawn; sandbox policy is applied above and shell mode is not used.\n\t\t\tconst child = spawn(spawnCommand, spawnArgs, {\n\t\t\t\tcwd: spawnCwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: spawnEnv,\n\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeout !== undefined && timeout > 0) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeout * 1000);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn { exitCode };\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t};\n}\n\n/**\n * Sandbox preflight inputs for local bash operations. When provided to\n * {@link createLocalBashOperations}, every spawn is gated by the sandbox spawn\n * builder: shell is denied when an OS sandbox backend is missing under enforce\n * mode, the environment is filtered, and available backends wrap the spawned\n * command. When omitted, local bash behavior is unchanged.\n */\nexport interface BashSandboxPreflight {\n\t/** Policy that decides whether this spawn may proceed. */\n\tpolicy: SandboxPolicy;\n\t/**\n\t * Availability of an OS-level sandbox backend. Local operations auto-detect\n\t * macOS sandbox-exec or Linux bubblewrap when this is omitted.\n\t */\n\tbackend?: SandboxBackendStatus;\n\t/** Optional resolver used to canonicalize the working directory before the root check. */\n\tresolver?: SandboxPathResolver;\n\t/** Observer for each sandbox spawn decision (audit/enforce ledger recording). */\n\tonSpawnDecision?: (decision: SandboxedSpawnRequest) => void;\n}\n\nfunction defaultBashSandboxBackend(): SandboxBackendStatus {\n\treturn detectSandboxBackend();\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nconst SESSION_ENV_KEYS = [\"PI_SESSION_ID\", \"PI_SESSION_FILE\", \"PI_PROVIDER\", \"PI_MODEL\", \"PI_REASONING_LEVEL\"] as const;\n\nfunction resolveSpawnContext(\n\tcommand: string,\n\tcwd: string,\n\tspawnHook: BashSpawnHook | undefined,\n\texposeSessionEnvironment: boolean,\n\tctx: ExtensionContext | undefined,\n): BashSpawnContext {\n\tconst env = { ...getShellEnv() };\n\t// Anti-spoof: never inherit PI_* session metadata from the parent environment.\n\tfor (const key of SESSION_ENV_KEYS) delete env[key];\n\tif (exposeSessionEnvironment && ctx?.sessionManager) {\n\t\tconst model = ctx.model;\n\t\tenv.PI_SESSION_ID = ctx.sessionManager.getSessionId();\n\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\tif (sessionFile) env.PI_SESSION_FILE = sessionFile;\n\t\tif (model) {\n\t\t\tenv.PI_PROVIDER = model.provider;\n\t\t\tenv.PI_MODEL = model.id;\n\t\t}\n\t\tif (ctx.thinkingLevel) env.PI_REASONING_LEVEL = ctx.thinkingLevel;\n\t}\n\tconst baseContext: BashSpawnContext = { command, cwd, env };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Expose current session metadata as PI_* environment variables. Default: true */\n\texposeSessionEnvironment?: boolean;\n\t/** Trusted sandbox policy for local shell execution */\n\tsandboxPolicy?: BashSandboxPreflight;\n\tloadoutAccessGuard?: LoadoutAccessGuard;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\ntype BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction formatBashCall(args: { command?: string; timeout?: number } | undefined): string {\n\tconst command = str(args?.command);\n\tconst timeout = args?.timeout as number | undefined;\n\tconst timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tconst commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\treturn theme.fg(\"toolTitle\", theme.bold(`$ ${commandDisplay}`)) + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tlet output = getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines;\n\t\t\t\t\t\tstate.cachedSkipped = preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops =\n\t\toptions?.operations ??\n\t\tcreateLocalBashOperations({ shellPath: options?.shellPath, sandboxPolicy: options?.sandboxPolicy });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\treturn {\n\t\tname: \"bash\",\n\t\tlabel: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\t\tpromptGuidelines: exposeSessionEnvironment\n\t\t\t? [\"Inspect PI_* environment variables for current model and session details.\"]\n\t\t\t: undefined,\n\t\tparameters: bashSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ command, timeout }: { command: string; timeout?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\tonUpdate?,\n\t\t\tctx?,\n\t\t) {\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook, exposeSessionEnvironment, ctx);\n\t\t\tassertLoadoutAccess(options?.loadoutAccessGuard, {\n\t\t\t\toperation: \"execute\",\n\t\t\t\ttoolName: \"bash\",\n\t\t\t\tcommand: spawnContext.command,\n\t\t\t});\n\n\t\t\t// Safety floor: re-classify the EFFECTIVE command after commandPrefix/spawnHook.\n\t\t\t// Skipped entirely in YOLO mode (OMK_YOLO=1 / OMK_COMMAND_SAFETY=0).\n\t\t\tconst yolo =\n\t\t\t\tprocess.env.OMK_YOLO === \"1\" ||\n\t\t\t\tprocess.env.OMK_YOLO === \"true\" ||\n\t\t\t\tprocess.env.OMK_DISABLE_COMMAND_SAFETY === \"1\" ||\n\t\t\t\tprocess.env.OMK_DISABLE_COMMAND_SAFETY === \"true\" ||\n\t\t\t\t[\"0\", \"false\", \"off\", \"disable\", \"disabled\"].includes(\n\t\t\t\t\tString(process.env.OMK_COMMAND_SAFETY ?? \"\").toLowerCase(),\n\t\t\t\t);\n\t\t\tif (!yolo) {\n\t\t\t\tconst effectiveVerdict = classifyShellCommand(spawnContext.command);\n\t\t\t\tif (effectiveVerdict.risk === \"block\") {\n\t\t\t\t\tthrow new Error(`command-safety: blocked\\n[${effectiveVerdict.rule}] ${effectiveVerdict.reason}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: \"omk-bash\" });\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: snapshot.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\treturn snapshot;\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new Error(appendStatus(text, \"Command aborted\"));\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new Error(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`));\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${exitCode}`));\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBashCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\treturn wrapToolDefinition(createBashToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport type { AgentTool } from \"omk-agent-core\";\nimport { Container, Text, truncateToWidth } from \"omk-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport { classifyShellCommand } from \"../command-safety.ts\";\nimport type { ExtensionContext, ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { assertLoadoutAccess, type LoadoutAccessGuard } from \"../loadout-access-policy.ts\";\nimport { detectSandboxBackend } from \"../sandbox/backend.ts\";\nimport type { SandboxBackendStatus, SandboxPathResolver, SandboxPolicy } from \"../sandbox/policy.ts\";\nimport { buildSandboxedSpawnRequest, type SandboxedSpawnRequest } from \"../sandbox/spawn.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { getTextOutput, invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\n/**\n * Create bash operations using OMK's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want OMK's\n * standard local shell behavior while wrapping, sandboxing, or rewriting commands.\n */\nexport interface LocalBashOperationsOptions {\n\treadonly shellPath?: string;\n\treadonly sandboxPolicy?: BashSandboxPreflight;\n\t/** Override backend probing for embedders and deterministic tests. */\n\treadonly detectSandboxBackend?: () => SandboxBackendStatus;\n}\n\nexport function createLocalBashOperations(options?: LocalBashOperationsOptions): BashOperations {\n\tconst sandbox = options?.sandboxPolicy;\n\tlet detectedBackend: SandboxBackendStatus | undefined;\n\tconst resolveBackend = (): SandboxBackendStatus => {\n\t\tif (sandbox?.backend) return sandbox.backend;\n\t\tdetectedBackend ??= (options?.detectSandboxBackend ?? defaultBashSandboxBackend)();\n\t\treturn detectedBackend;\n\t};\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst { shell, args } = getShellConfig(options?.shellPath);\n\t\t\tlet spawnCommand = shell;\n\t\t\tlet spawnArgs = [...args, command];\n\t\t\tlet spawnCwd = cwd;\n\t\t\tlet spawnEnv: NodeJS.ProcessEnv = env ?? getShellEnv();\n\t\t\tif (sandbox) {\n\t\t\t\tconst backend = resolveBackend();\n\t\t\t\tconst request = buildSandboxedSpawnRequest({\n\t\t\t\t\targv: [shell, ...args, command],\n\t\t\t\t\tcwd,\n\t\t\t\t\tenv: spawnEnv,\n\t\t\t\t\tpolicy: sandbox.policy,\n\t\t\t\t\tbackend,\n\t\t\t\t\tresolver: sandbox.resolver,\n\t\t\t\t});\n\t\t\t\tsandbox.onSpawnDecision?.(request);\n\t\t\t\tif (!request.allowed) {\n\t\t\t\t\tthrow new Error(`sandbox: shell denied\\n[${request.rule}] ${request.reason}`);\n\t\t\t\t}\n\t\t\t\tspawnCommand = request.argv[0];\n\t\t\t\tspawnArgs = [...request.argv.slice(1)];\n\t\t\t\tspawnCwd = request.cwd;\n\t\t\t\tspawnEnv = request.env;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait fsAccess(spawnCwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${spawnCwd}\\nCannot execute bash commands.`);\n\t\t\t}\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\n\t\t\t// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process -- argv-array spawn; sandbox policy is applied above and shell mode is not used.\n\t\t\tconst child = spawn(spawnCommand, spawnArgs, {\n\t\t\t\tcwd: spawnCwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: spawnEnv,\n\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeout !== undefined && timeout > 0) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeout * 1000);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn { exitCode };\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t};\n}\n\n/**\n * Sandbox preflight inputs for local bash operations. When provided to\n * {@link createLocalBashOperations}, every spawn is gated by the sandbox spawn\n * builder: shell is denied when an OS sandbox backend is missing under enforce\n * mode, the environment is filtered, and available backends wrap the spawned\n * command. When omitted, local bash behavior is unchanged.\n */\nexport interface BashSandboxPreflight {\n\t/** Policy that decides whether this spawn may proceed. */\n\tpolicy: SandboxPolicy;\n\t/**\n\t * Availability of an OS-level sandbox backend. Local operations auto-detect\n\t * macOS sandbox-exec or Linux bubblewrap when this is omitted.\n\t */\n\tbackend?: SandboxBackendStatus;\n\t/** Optional resolver used to canonicalize the working directory before the root check. */\n\tresolver?: SandboxPathResolver;\n\t/** Observer for each sandbox spawn decision (audit/enforce ledger recording). */\n\tonSpawnDecision?: (decision: SandboxedSpawnRequest) => void;\n}\n\nfunction defaultBashSandboxBackend(): SandboxBackendStatus {\n\treturn detectSandboxBackend();\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nconst SESSION_ENV_KEYS = [\"PI_SESSION_ID\", \"PI_SESSION_FILE\", \"PI_PROVIDER\", \"PI_MODEL\", \"PI_REASONING_LEVEL\"] as const;\n\nfunction resolveSpawnContext(\n\tcommand: string,\n\tcwd: string,\n\tspawnHook: BashSpawnHook | undefined,\n\texposeSessionEnvironment: boolean,\n\tctx: ExtensionContext | undefined,\n): BashSpawnContext {\n\tconst env = { ...getShellEnv() };\n\t// Anti-spoof: never inherit PI_* session metadata from the parent environment.\n\tfor (const key of SESSION_ENV_KEYS) delete env[key];\n\tif (exposeSessionEnvironment && ctx?.sessionManager) {\n\t\tconst model = ctx.model;\n\t\tenv.PI_SESSION_ID = ctx.sessionManager.getSessionId();\n\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\tif (sessionFile) env.PI_SESSION_FILE = sessionFile;\n\t\tif (model) {\n\t\t\tenv.PI_PROVIDER = model.provider;\n\t\t\tenv.PI_MODEL = model.id;\n\t\t}\n\t\tif (ctx.thinkingLevel) env.PI_REASONING_LEVEL = ctx.thinkingLevel;\n\t}\n\tconst baseContext: BashSpawnContext = { command, cwd, env };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Expose current session metadata as PI_* environment variables. Default: true */\n\texposeSessionEnvironment?: boolean;\n\t/** Trusted sandbox policy for local shell execution */\n\tsandboxPolicy?: BashSandboxPreflight;\n\tloadoutAccessGuard?: LoadoutAccessGuard;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\ntype BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction formatBashCall(args: { command?: string; timeout?: number } | undefined): string {\n\tconst command = str(args?.command);\n\tconst timeout = args?.timeout as number | undefined;\n\tconst timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tconst commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\treturn theme.fg(\"toolTitle\", theme.bold(`$ ${commandDisplay}`)) + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tlet output = getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines;\n\t\t\t\t\t\tstate.cachedSkipped = preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops =\n\t\toptions?.operations ??\n\t\tcreateLocalBashOperations({ shellPath: options?.shellPath, sandboxPolicy: options?.sandboxPolicy });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\treturn {\n\t\tname: \"bash\",\n\t\tlabel: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\t\tpromptGuidelines: exposeSessionEnvironment\n\t\t\t? [\"Inspect PI_* environment variables for current model and session details.\"]\n\t\t\t: undefined,\n\t\tparameters: bashSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ command, timeout }: { command: string; timeout?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\tonUpdate?,\n\t\t\tctx?,\n\t\t) {\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook, exposeSessionEnvironment, ctx);\n\t\t\tassertLoadoutAccess(options?.loadoutAccessGuard, {\n\t\t\t\toperation: \"execute\",\n\t\t\t\ttoolName: \"bash\",\n\t\t\t\tcommand: spawnContext.command,\n\t\t\t});\n\n\t\t\t// Safety floor: re-classify the EFFECTIVE command after commandPrefix/spawnHook.\n\t\t\t// Skipped entirely in YOLO mode (OMK_YOLO=1 / OMK_COMMAND_SAFETY=0).\n\t\t\tconst yolo =\n\t\t\t\tprocess.env.OMK_YOLO === \"1\" ||\n\t\t\t\tprocess.env.OMK_YOLO === \"true\" ||\n\t\t\t\tprocess.env.OMK_DISABLE_COMMAND_SAFETY === \"1\" ||\n\t\t\t\tprocess.env.OMK_DISABLE_COMMAND_SAFETY === \"true\" ||\n\t\t\t\t[\"0\", \"false\", \"off\", \"disable\", \"disabled\"].includes(\n\t\t\t\t\tString(process.env.OMK_COMMAND_SAFETY ?? \"\").toLowerCase(),\n\t\t\t\t);\n\t\t\tif (!yolo) {\n\t\t\t\tconst effectiveVerdict = classifyShellCommand(spawnContext.command);\n\t\t\t\tif (effectiveVerdict.risk === \"block\") {\n\t\t\t\t\tthrow new Error(`command-safety: blocked\\n[${effectiveVerdict.rule}] ${effectiveVerdict.reason}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: \"omk-bash\" });\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: snapshot.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\treturn snapshot;\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new Error(appendStatus(text, \"Command aborted\"));\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new Error(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`));\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${exitCode}`));\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBashCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\treturn wrapToolDefinition(createBashToolDefinition(cwd, options));\n}\n"]}
@@ -20,14 +20,15 @@ const bashSchema = Type.Object({
20
20
  command: Type.String({ description: "Bash command to execute" }),
21
21
  timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })),
22
22
  });
23
- /**
24
- * Create bash operations using OMK's built-in local shell execution backend.
25
- *
26
- * This is useful for extensions that intercept user_bash and still want OMK's
27
- * standard local shell behavior while wrapping, sandboxing, or rewriting commands.
28
- */
29
23
  export function createLocalBashOperations(options) {
30
24
  const sandbox = options?.sandboxPolicy;
25
+ let detectedBackend;
26
+ const resolveBackend = () => {
27
+ if (sandbox?.backend)
28
+ return sandbox.backend;
29
+ detectedBackend ??= (options?.detectSandboxBackend ?? defaultBashSandboxBackend)();
30
+ return detectedBackend;
31
+ };
31
32
  return {
32
33
  exec: async (command, cwd, { onData, signal, timeout, env }) => {
33
34
  const { shell, args } = getShellConfig(options?.shellPath);
@@ -36,7 +37,7 @@ export function createLocalBashOperations(options) {
36
37
  let spawnCwd = cwd;
37
38
  let spawnEnv = env ?? getShellEnv();
38
39
  if (sandbox) {
39
- const backend = sandbox.backend ?? defaultBashSandboxBackend();
40
+ const backend = resolveBackend();
40
41
  const request = buildSandboxedSpawnRequest({
41
42
  argv: [shell, ...args, command],
42
43
  cwd,