@lotagate/cli 0.1.25 → 0.1.27

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 (256) hide show
  1. package/README.md +5 -4
  2. package/bin/lotagate.mjs +50 -8
  3. package/dist/application/agent/agent-constants.d.ts +6 -0
  4. package/dist/application/agent/agent-constants.js +1 -0
  5. package/dist/application/agent/agent-session-store-registry.d.ts +16 -0
  6. package/dist/application/agent/agent-session-store-registry.js +1 -0
  7. package/dist/application/agent/agent-session-store.d.ts +4 -0
  8. package/dist/application/agent/agent-session-store.js +5 -5
  9. package/dist/application/agent/bounded-text-accumulator.d.ts +15 -0
  10. package/dist/application/agent/bounded-text-accumulator.js +1 -0
  11. package/dist/application/agent/capability-profile.d.ts +0 -38
  12. package/dist/application/agent/capability-profile.js +0 -1
  13. package/dist/application/agent/cli-agent-execution-service.d.ts +23 -13
  14. package/dist/application/agent/cli-agent-execution-service.js +1 -1
  15. package/dist/application/agent/cli-agent-preparation-cache.d.ts +39 -0
  16. package/dist/application/agent/cli-agent-preparation-cache.js +1 -0
  17. package/dist/application/agent/context-compaction.d.ts +1 -0
  18. package/dist/application/agent/context-compaction.js +7 -6
  19. package/dist/application/agent/context-token-cache.d.ts +21 -0
  20. package/dist/application/agent/context-token-cache.js +4 -0
  21. package/dist/application/agent/context-usage-service.d.ts +52 -0
  22. package/dist/application/agent/context-usage-service.js +1 -0
  23. package/dist/application/agent/continuation-checkpoint.d.ts +15 -0
  24. package/dist/application/agent/continuation-checkpoint.js +2 -0
  25. package/dist/application/agent/interactive-agent-guidance.d.ts +3 -3
  26. package/dist/application/agent/interactive-agent-guidance.js +2 -2
  27. package/dist/application/chat/pending-attachment-store.d.ts +5 -2
  28. package/dist/application/chat/pending-attachment-store.js +1 -1
  29. package/dist/application/commands/application-command-executor.js +2 -2
  30. package/dist/application/commands/cli-command-services.d.ts +1 -1
  31. package/dist/application/commands/cli-command-services.js +31 -31
  32. package/dist/application/commands/command-catalog.js +1 -1
  33. package/dist/application/commands/goal-command-handlers.js +6 -6
  34. package/dist/application/commands/media-command-handlers.js +7 -6
  35. package/dist/application/commands/memory-command-handler.d.ts +1 -1
  36. package/dist/application/commands/memory-command-handler.js +11 -11
  37. package/dist/application/commands/runtime-command-handlers.js +11 -11
  38. package/dist/application/extensions/plugin-contribution-registry.js +1 -1
  39. package/dist/application/intent/completion-gate.d.ts +2 -5
  40. package/dist/application/intent/completion-gate.js +1 -1
  41. package/dist/application/intent/evidence-ledger.d.ts +2 -1
  42. package/dist/application/intent/evidence-recording-tool-executor.js +1 -1
  43. package/dist/application/intent/intent-compiler.js +2 -2
  44. package/dist/application/lifecycle/operation-registry.d.ts +11 -0
  45. package/dist/application/lifecycle/operation-registry.js +1 -0
  46. package/dist/application/memory/memory-extractor.js +2 -2
  47. package/dist/application/model/cached-model-catalog.d.ts +7 -1
  48. package/dist/application/model/cached-model-catalog.js +1 -1
  49. package/dist/application/model/model-catalog-service.js +1 -1
  50. package/dist/application/model/model-context-window.js +1 -1
  51. package/dist/application/model/model-response-retry.d.ts +7 -1
  52. package/dist/application/model/model-response-retry.js +1 -1
  53. package/dist/application/orchestration/cli-subagent-service.d.ts +4 -0
  54. package/dist/application/orchestration/cli-subagent-service.js +3 -3
  55. package/dist/application/orchestration/cli-turn-event-projector.js +1 -1
  56. package/dist/application/orchestration/cli-turn-events.d.ts +0 -7
  57. package/dist/application/orchestration/goal-input.d.ts +1 -1
  58. package/dist/application/orchestration/goal-input.js +1 -1
  59. package/dist/application/orchestration/headless-agent-turn.d.ts +1 -0
  60. package/dist/application/orchestration/headless-agent-turn.js +3 -3
  61. package/dist/application/orchestration/orchestration-constants.d.ts +3 -0
  62. package/dist/application/orchestration/orchestration-constants.js +1 -0
  63. package/dist/application/orchestration/subagent-handoff.js +3 -3
  64. package/dist/application/project-intelligence/project-intelligence-constants.d.ts +56 -0
  65. package/dist/application/project-intelligence/project-intelligence-constants.js +1 -0
  66. package/dist/application/project-intelligence/project-intelligence-service.js +1 -1
  67. package/dist/application/protocol/browser-host-tool-executor.d.ts +13 -3
  68. package/dist/application/protocol/browser-host-tool-executor.js +2 -2
  69. package/dist/application/protocol/computer-host-tool-executor.d.ts +3 -0
  70. package/dist/application/protocol/computer-host-tool-executor.js +2 -2
  71. package/dist/application/protocol/desktop-agent-command.d.ts +2 -2
  72. package/dist/application/protocol/desktop-agent-command.js +1 -3
  73. package/dist/application/protocol/desktop-agent-contracts.d.ts +34 -0
  74. package/dist/application/protocol/desktop-agent-contracts.js +1 -0
  75. package/dist/application/protocol/desktop-agent-helpers.d.ts +5 -0
  76. package/dist/application/protocol/desktop-agent-helpers.js +1 -0
  77. package/dist/application/protocol/desktop-agent-request-parser.d.ts +31 -6
  78. package/dist/application/protocol/desktop-agent-request-parser.js +1 -1
  79. package/dist/application/protocol/desktop-approval-broker.d.ts +14 -4
  80. package/dist/application/protocol/desktop-approval-broker.js +1 -1
  81. package/dist/application/protocol/desktop-attachment-store.d.ts +19 -2
  82. package/dist/application/protocol/desktop-attachment-store.js +1 -1
  83. package/dist/application/protocol/desktop-execution-policy.d.ts +2 -0
  84. package/dist/application/protocol/desktop-execution-policy.js +1 -1
  85. package/dist/application/protocol/desktop-host-bridge.d.ts +33 -0
  86. package/dist/application/protocol/desktop-host-bridge.js +1 -0
  87. package/dist/application/protocol/desktop-host-capabilities.d.ts +12 -0
  88. package/dist/application/protocol/desktop-host-capabilities.js +1 -0
  89. package/dist/application/protocol/desktop-host-tool-executor.d.ts +15 -2
  90. package/dist/application/protocol/desktop-host-tool-executor.js +2 -2
  91. package/dist/application/protocol/desktop-intent-event-writer.js +1 -1
  92. package/dist/application/protocol/desktop-protocol-helpers.js +1 -1
  93. package/dist/application/protocol/desktop-title-generator.d.ts +5 -0
  94. package/dist/application/protocol/desktop-title-generator.js +3 -0
  95. package/dist/application/protocol/json-line-writer.d.ts +24 -2
  96. package/dist/application/protocol/json-line-writer.js +2 -2
  97. package/dist/application/protocol/jsonl-agent-command.d.ts +1 -1
  98. package/dist/application/protocol/jsonl-agent-command.js +2 -2
  99. package/dist/application/protocol/jsonl-protocol.d.ts +1 -1
  100. package/dist/application/protocol/jsonl-protocol.js +2 -2
  101. package/dist/application/security/desktop-tool-scope-policy.js +1 -1
  102. package/dist/application/security/tool-action-risk-analyzer.js +1 -1
  103. package/dist/application/security/tool-approval-service.d.ts +9 -3
  104. package/dist/application/security/tool-approval-service.js +1 -1
  105. package/dist/application/security/tool-policy-registry.d.ts +20 -0
  106. package/dist/application/security/tool-policy-registry.js +1 -0
  107. package/dist/application/security/tool-risk-classifier.d.ts +2 -1
  108. package/dist/application/security/tool-risk-classifier.js +1 -1
  109. package/dist/application/security/workspace-permission-policy.js +1 -1
  110. package/dist/application/workspace/session-execution-workspace.d.ts +2 -2
  111. package/dist/application/workspace/session-execution-workspace.js +3 -3
  112. package/dist/application/workspace/workspace-constants.d.ts +17 -0
  113. package/dist/application/workspace/workspace-constants.js +1 -0
  114. package/dist/application/workspace/workspace-file-index.d.ts +2 -3
  115. package/dist/application/workspace/workspace-file-index.js +1 -1
  116. package/dist/application/workspace/workspace-instruction-loader.js +1 -1
  117. package/dist/bootstrap/composition-root.d.ts +1 -0
  118. package/dist/bootstrap/runtime-factory.d.ts +5 -0
  119. package/dist/bootstrap/runtime-factory.js +1 -1
  120. package/dist/domain/auth/auth-profile.d.ts +1 -0
  121. package/dist/domain/auth/auth-profile.js +1 -1
  122. package/dist/domain/errors/cli-error.js +1 -1
  123. package/dist/domain/extensions/extension-constants.d.ts +1 -0
  124. package/dist/domain/extensions/extension-constants.js +1 -0
  125. package/dist/domain/extensions/host-tool-plugin-ids.d.ts +0 -4
  126. package/dist/domain/extensions/host-tool-plugin-ids.js +1 -1
  127. package/dist/domain/extensions/plugin-manifest.js +1 -1
  128. package/dist/domain/intent/intent-contract.d.ts +0 -8
  129. package/dist/domain/intent/intent-contract.js +1 -1
  130. package/dist/domain/media/gateway-media-contract.js +1 -1
  131. package/dist/domain/media/media-constants.d.ts +3 -0
  132. package/dist/domain/media/media-constants.js +1 -0
  133. package/dist/domain/media/media-execution-policy.js +1 -1
  134. package/dist/domain/memory/memory-constants.d.ts +3 -0
  135. package/dist/domain/memory/memory-constants.js +1 -0
  136. package/dist/domain/memory/memory-search.js +2 -2
  137. package/dist/domain/orchestration/goal.d.ts +0 -1
  138. package/dist/domain/orchestration/goal.js +1 -1
  139. package/dist/domain/orchestration/work-plan.d.ts +0 -62
  140. package/dist/domain/orchestration/work-plan.js +0 -1
  141. package/dist/domain/runtime/assistant-stream-text.d.ts +11 -0
  142. package/dist/domain/runtime/assistant-stream-text.js +1 -0
  143. package/dist/domain/runtime/gateway-request-budget.d.ts +19 -0
  144. package/dist/domain/runtime/gateway-request-budget.js +1 -0
  145. package/dist/domain/runtime/resource-limits.d.ts +26 -0
  146. package/dist/domain/runtime/resource-limits.js +1 -1
  147. package/dist/domain/session/attachment.d.ts +2 -0
  148. package/dist/domain/workspace/workspace-settings.d.ts +2 -0
  149. package/dist/domain/workspace/workspace-settings.js +1 -1
  150. package/dist/infrastructure/agent-sdk/model-response-metrics.d.ts +7 -0
  151. package/dist/infrastructure/agent-sdk/model-response-metrics.js +1 -0
  152. package/dist/infrastructure/agent-sdk/model-tool-name-mapper.js +1 -1
  153. package/dist/infrastructure/agent-sdk/sdk-constants.d.ts +2 -0
  154. package/dist/infrastructure/agent-sdk/sdk-constants.js +1 -0
  155. package/dist/infrastructure/agent-sdk/tool-calling-model-client.js +1 -1
  156. package/dist/infrastructure/cache/cache-policy.d.ts +2 -0
  157. package/dist/infrastructure/cache/cache-policy.js +1 -1
  158. package/dist/infrastructure/cache/file-cache-store.d.ts +13 -0
  159. package/dist/infrastructure/cache/file-cache-store.js +2 -2
  160. package/dist/infrastructure/clipboard/clipboard-adapter-factory.js +1 -1
  161. package/dist/infrastructure/clipboard/clipboard-constants.d.ts +1 -0
  162. package/dist/infrastructure/clipboard/clipboard-constants.js +1 -0
  163. package/dist/infrastructure/clipboard/clipboard-process.d.ts +20 -0
  164. package/dist/infrastructure/clipboard/clipboard-process.js +1 -0
  165. package/dist/infrastructure/clipboard/clipboard-text-adapter-factory.js +1 -1
  166. package/dist/infrastructure/clipboard/image-normalizer.js +1 -1
  167. package/dist/infrastructure/clipboard/windows-clipboard-adapter.js +1 -1
  168. package/dist/infrastructure/clipboard/windows-clipboard-text-adapter.js +1 -1
  169. package/dist/infrastructure/credentials/encrypted-file-credential-store.js +2 -2
  170. package/dist/infrastructure/credentials/secret-input.d.ts +1 -1
  171. package/dist/infrastructure/credentials/secret-input.js +3 -3
  172. package/dist/infrastructure/extensions/extensions-constants.d.ts +6 -0
  173. package/dist/infrastructure/extensions/extensions-constants.js +1 -0
  174. package/dist/infrastructure/extensions/mcp-runtime.d.ts +9 -0
  175. package/dist/infrastructure/extensions/mcp-runtime.js +1 -1
  176. package/dist/infrastructure/extensions/plugin-agent-discovery.d.ts +3 -1
  177. package/dist/infrastructure/extensions/plugin-agent-discovery.js +1 -1
  178. package/dist/infrastructure/extensions/plugin-manager.js +2 -2
  179. package/dist/infrastructure/extensions/skill-manager.js +2 -2
  180. package/dist/infrastructure/extensions/skill-tool-executor.d.ts +3 -1
  181. package/dist/infrastructure/extensions/skill-tool-executor.js +2 -2
  182. package/dist/infrastructure/filesystem/atomic-file-store.d.ts +11 -0
  183. package/dist/infrastructure/filesystem/atomic-file-store.js +1 -1
  184. package/dist/infrastructure/filesystem/filesystem-constants.d.ts +8 -0
  185. package/dist/infrastructure/filesystem/filesystem-constants.js +1 -0
  186. package/dist/infrastructure/filesystem/local-filesystem-tool-executor.d.ts +3 -0
  187. package/dist/infrastructure/filesystem/local-filesystem-tool-executor.js +3 -3
  188. package/dist/infrastructure/logging/daily-rotating-file-writer.d.ts +1 -1
  189. package/dist/infrastructure/logging/daily-rotating-file-writer.js +2 -2
  190. package/dist/infrastructure/logging/log-redactor.js +1 -1
  191. package/dist/infrastructure/logging/logging-constants.d.ts +3 -0
  192. package/dist/infrastructure/logging/logging-constants.js +1 -0
  193. package/dist/infrastructure/logging/structured-logger.d.ts +1 -1
  194. package/dist/infrastructure/logging/structured-logger.js +2 -2
  195. package/dist/infrastructure/observability/tool-execution-logger.d.ts +11 -0
  196. package/dist/infrastructure/observability/tool-execution-logger.js +1 -0
  197. package/dist/infrastructure/platform/host-platform.d.ts +2 -0
  198. package/dist/infrastructure/platform/host-platform.js +1 -1
  199. package/dist/infrastructure/platform/host-process.d.ts +3 -1
  200. package/dist/infrastructure/platform/host-process.js +1 -1
  201. package/dist/infrastructure/platform/platform-constants.d.ts +4 -0
  202. package/dist/infrastructure/platform/platform-constants.js +1 -0
  203. package/dist/infrastructure/platform/process-identity.d.ts +8 -0
  204. package/dist/infrastructure/platform/process-identity.js +1 -0
  205. package/dist/infrastructure/platform/read-only-executable.d.ts +2 -1
  206. package/dist/infrastructure/platform/read-only-executable.js +1 -1
  207. package/dist/infrastructure/sdk/lotagate-client-factory.js +1 -1
  208. package/dist/infrastructure/sdk/sdk-media-gateway-client.d.ts +4 -0
  209. package/dist/infrastructure/sdk/sdk-media-gateway-client.js +1 -1
  210. package/dist/infrastructure/sessions/file-session-store.d.ts +11 -0
  211. package/dist/infrastructure/sessions/file-session-store.js +4 -4
  212. package/dist/infrastructure/sessions/session-constants.d.ts +3 -0
  213. package/dist/infrastructure/sessions/session-constants.js +1 -0
  214. package/dist/infrastructure/sessions/session-index.js +3 -3
  215. package/dist/infrastructure/sessions/session-journal-health.d.ts +7 -0
  216. package/dist/infrastructure/sessions/session-journal-health.js +1 -0
  217. package/dist/infrastructure/shell/shell-tool-executor.d.ts +5 -1
  218. package/dist/infrastructure/shell/shell-tool-executor.js +2 -2
  219. package/dist/infrastructure/tokens/tiktoken-token-estimator.js +1 -1
  220. package/dist/infrastructure/tokens/token-constants.d.ts +1 -0
  221. package/dist/infrastructure/tokens/token-constants.js +1 -0
  222. package/dist/infrastructure/workspace/workspace-settings-store.d.ts +1 -0
  223. package/dist/infrastructure/workspace/workspace-settings-store.js +4 -4
  224. package/dist/main.js +3 -3
  225. package/dist/ports/media-gateway-client.d.ts +6 -0
  226. package/dist/ports/session-store.d.ts +1 -0
  227. package/dist/presentation/tui/ink/components/composer.js +4 -4
  228. package/dist/presentation/tui/ink/components/transcript.d.ts +1 -0
  229. package/dist/presentation/tui/ink/components/transcript.js +5 -5
  230. package/dist/presentation/tui/ink/tui-bridge.d.ts +2 -2
  231. package/dist/presentation/tui/ink/tui-bridge.js +1 -1
  232. package/dist/presentation/tui/tui-agent-turn-controller.d.ts +45 -0
  233. package/dist/presentation/tui/tui-agent-turn-controller.js +1 -0
  234. package/dist/presentation/tui/tui-application-contract.d.ts +1 -0
  235. package/dist/presentation/tui/tui-application.d.ts +3 -4
  236. package/dist/presentation/tui/tui-application.js +3 -3
  237. package/dist/presentation/tui/tui-clipboard-paste-handlers.d.ts +2 -2
  238. package/dist/presentation/tui/tui-clipboard-paste-handlers.js +1 -1
  239. package/dist/presentation/tui/tui-command-executor.js +3 -3
  240. package/dist/presentation/tui/tui-context-compaction.d.ts +4 -1
  241. package/dist/presentation/tui/tui-context-compaction.js +1 -1
  242. package/dist/presentation/tui/tui-context-service.d.ts +2 -34
  243. package/dist/presentation/tui/tui-context-service.js +1 -2
  244. package/dist/presentation/tui/tui-initial-model.js +1 -1
  245. package/dist/presentation/tui/tui-tool-approval.d.ts +1 -1
  246. package/dist/presentation/tui/tui-tool-approval.js +1 -1
  247. package/dist/version.d.ts +1 -1
  248. package/dist/version.js +1 -1
  249. package/native-targets.mjs +1 -1
  250. package/package.json +9 -10
  251. package/scripts/install-native.mjs +5 -13
  252. package/bin/lotagate.exe +0 -1
  253. package/dist/application/protocol/document-host-tool-definitions.d.ts +0 -4
  254. package/dist/application/protocol/document-host-tool-definitions.js +0 -1
  255. package/dist/application/protocol/document-host-tool-executor.d.ts +0 -49
  256. package/dist/application/protocol/document-host-tool-executor.js +0 -2
@@ -1,4 +1,4 @@
1
- import{prepareCliAgent as m}from"../agent/cli-agent-execution-service.js";import{AgentRunTracker as h}from"../agent/agent-run-tracker.js";import{CliError as S}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as f}from"../../domain/errors/error-codes.js";import{writeStreamChunk as c}from"../commands/stream-output.js";import{CliTurnEventProjector as w}from"./cli-turn-event-projector.js";import{persistCliTurnEvent as p}from"./cli-turn-persistence.js";import{agentLimitNotice as C,classifyAgentLimit as I}from"../agent/agent-limit.js";import{buildUserMessage as y}from"../../infrastructure/clipboard/image-normalizer.js";async function k(e){const i=new h,d=await m({runtime:e.runtime,projectRoot:e.cwd,executionCwd:e.cwd,model:e.model,...e.reasoningEffort===void 0?{}:{reasoningEffort:e.reasoningEffort},client:e.client,profile:"headless-safe",approvalMode:"auto",...e.goal===void 0?{}:{goal:e.goal},...e.agentSessionStore===void 0?{}:{agentSessionStore:e.agentSessionStore},onModelComplete:n=>{n.usage!==void 0&&e.onUsage?.({usage:n.usage,modelCalls:1})},...e.onSubagentUsage===void 0?{}:{onSubagentModelComplete:n=>{n.usage!==void 0&&e.onSubagentUsage?.({usage:n.usage,modelCalls:1})}}}),r=[];let s;const g=new w;try{const n=await d.buildInput(e.prompt);if(e.agentSessionStore!==void 0&&e.sessionId!==void 0){const t=await e.runtime.sessionStore.readHistory(e.sessionId);e.agentSessionStore.hydrate(e.sessionId,t.transcript,t.events,n.input)}const u=e.attachments===void 0||e.attachments.length===0?void 0:y(n.input,e.attachments),l=u?.content===null?void 0:u?.content;for await(const t of d.run({input:n.input,userInput:n.userInput,...n.workspaceContext===void 0?{}:{workspaceContext:n.workspaceContext},...l===void 0?{}:{inputContent:l},model:e.model,...e.signal===void 0?{}:{signal:e.signal},...e.sessionId===void 0?{}:{sessionId:e.sessionId}})){i.observe(t);for(const a of g.observe(t)){if(e.sessionId!==void 0)try{await p(e.runtime.sessionStore,e.sessionId,a,{...e.turnId===void 0?{}:{turnId:e.turnId}})}catch(o){e.runtime.logger.warn("Unable to persist agent lifecycle event.",{eventType:a.type,reason:o instanceof Error?o.message:String(o)})}a.type==="assistant.delta"&&r.push(a.content),a.type==="assistant.replaced"&&r.splice(0,r.length,a.content)}if(e.output!==void 0&&e.json?await c(e.output,`${JSON.stringify(t)}
2
- `):t.type==="session.completed"&&r.length===0&&r.push(t.content),t.type==="session.failed"){if(s=I(t.error),s===void 0)throw t.error;break}}if(s!==void 0){const t=C(s);r.push(r.length===0?t:`
1
+ import{prepareCliAgent as w}from"../agent/cli-agent-execution-service.js";import{AgentRunTracker as S}from"../agent/agent-run-tracker.js";import{CliError as C}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as c}from"../../domain/errors/error-codes.js";import{writeStreamChunk as m}from"../commands/stream-output.js";import{CliTurnEventProjector as p}from"./cli-turn-event-projector.js";import{persistCliTurnEvent as h}from"./cli-turn-persistence.js";import{agentLimitNotice as y,classifyAgentLimit as I}from"../agent/agent-limit.js";import{buildUserMessage as E}from"../../infrastructure/clipboard/image-normalizer.js";import{createContextManagement as x}from"../agent/context-compaction.js";import{persistContextCompaction as M}from"../agent/context-compaction-persistence.js";import{resolveModelContextWindow as b}from"../model/model-context-window.js";import{formatContinuationCheckpoint as v}from"../agent/continuation-checkpoint.js";import{BoundedTextAccumulator as T}from"../agent/bounded-text-accumulator.js";async function Y(e){const s=new S,u=await b(e.runtime,e.model,e.profileName),i=await w({runtime:e.runtime,projectRoot:e.cwd,executionCwd:e.cwd,model:e.model,...e.reasoningEffort===void 0?{}:{reasoningEffort:e.reasoningEffort},client:e.client,profile:"headless-safe",approvalMode:"auto",...e.goal===void 0?{}:{goal:e.goal},...e.agentSessionStore===void 0?{}:{agentSessionStore:e.agentSessionStore},onModelComplete:t=>{s.observeModel(t),t.usage!==void 0&&e.onUsage?.({usage:t.usage,modelCalls:1})},...e.onSubagentUsage===void 0?{}:{onSubagentModelComplete:t=>{t.usage!==void 0&&e.onSubagentUsage?.({usage:t.usage,modelCalls:1})}},contextManagement:x({client:e.client,model:e.model,...u===void 0?{}:{contextWindow:u},onSummaryFailure:t=>e.runtime.logger.warn("Context summarization failed; using fallback summary.",{reason:t instanceof Error?t.message:String(t)}),continuationContext:()=>v({snapshot:s.snapshot(),...e.goal===void 0?{}:{goal:e.goal}})})}),r=new T;let d;const g=new p;try{const t=await i.buildInput(e.prompt);if(e.agentSessionStore!==void 0&&e.sessionId!==void 0){const n=await e.runtime.sessionStore.readHistory(e.sessionId);e.agentSessionStore.hydrate(e.sessionId,n.transcript,n.events,t.input)}const l=e.attachments===void 0||e.attachments.length===0?void 0:E(t.input,e.attachments),f=l?.content===null?void 0:l?.content;for await(const n of i.run({input:t.input,userInput:t.userInput,...t.workspaceContext===void 0?{}:{workspaceContext:t.workspaceContext},...f===void 0?{}:{inputContent:f},model:e.model,...e.signal===void 0?{}:{signal:e.signal},...e.sessionId===void 0?{}:{sessionId:e.sessionId}})){s.observe(n);for(const a of g.observe(n)){if(e.sessionId!==void 0)try{await h(e.runtime.sessionStore,e.sessionId,a,{...e.turnId===void 0?{}:{turnId:e.turnId}})}catch(o){e.runtime.logger.warn("Unable to persist agent lifecycle event.",{eventType:a.type,reason:o instanceof Error?o.message:String(o)})}a.type==="assistant.delta"&&r.append(a.content),a.type==="assistant.replaced"&&r.replace(a.content)}if(e.output!==void 0&&e.json?await m(e.output,`${JSON.stringify(n)}
2
+ `):n.type==="session.completed"&&r.isEmpty&&r.replace(n.content),n.type==="session.failed"){if(d=I(n.error),d===void 0)throw n.error;break}n.type==="context.compacted"&&e.sessionId!==void 0&&await M(e.runtime,i,e.sessionId,n.metrics,e.turnId)}if(d!==void 0){const n=y(d);r.append(r.isEmpty?n:`
3
3
 
4
- ${t}`),e.sessionId!==void 0&&e.agentSessionStore?.delete(e.sessionId)}if(r.join("").trim().length===0){const a=i.snapshot().toolCalls>0?f.MODEL_EMPTY_FINAL:f.MODEL_PROTOCOL_EMPTY_RESPONSE;throw new S(a,"Agent completed without a final text response.",{category:"model",userMessage:"The model completed without a final text response.",retryable:!0})}return e.output!==void 0&&!e.json&&await c(e.output,r.join("")),r.join("")}finally{e.onSnapshot?.(i.snapshot());try{await d.close()}catch(n){e.runtime.logger.warn("Agent cleanup failed after a completed turn.",{reason:n instanceof Error?n.message:String(n)})}}}export{k as runHeadlessAgentTurn};
4
+ ${n}`),e.sessionId!==void 0&&e.agentSessionStore?.delete(e.sessionId)}if(r.toString().trim().length===0){const a=s.snapshot().toolCalls>0?c.MODEL_EMPTY_FINAL:c.MODEL_PROTOCOL_EMPTY_RESPONSE;throw new C(a,"Agent completed without a final text response.",{category:"model",userMessage:"The model completed without a final text response.",retryable:!0})}return e.output!==void 0&&!e.json&&await m(e.output,r.toString()),r.toString()}finally{e.onSnapshot?.(s.snapshot());try{await i.close()}catch(t){e.runtime.logger.warn("Agent cleanup failed after a completed turn.",{reason:t instanceof Error?t.message:String(t)})}}}export{Y as runHeadlessAgentTurn};
@@ -0,0 +1,3 @@
1
+ export declare const MAX_HANDOFF_ITEMS = 32;
2
+ export declare const MAX_ITEM_BYTES = 1024;
3
+ export declare const HANDOFF_FIELDS: readonly ["summary", "filesInspected", "filesChanged", "commandsRun", "verification", "warnings"];
@@ -0,0 +1 @@
1
+ const n=32,e=1024,s=["summary","filesInspected","filesChanged","commandsRun","verification","warnings"];export{s as HANDOFF_FIELDS,n as MAX_HANDOFF_ITEMS,e as MAX_ITEM_BYTES};
@@ -1,3 +1,3 @@
1
- import{RESOURCE_LIMITS as m}from"../../domain/runtime/resource-limits.js";import{findUnexpectedRecordKey as l}from"../../domain/validation/record-schema.js";const y=32,u=1024,d=["summary","filesInspected","filesChanged","commandsRun","verification","warnings"],I=["## Handoff contract","When complete, return exactly one JSON object with only these fields: summary (string), filesInspected (string[]), filesChanged (string[]), commandsRun (string[]), verification (string[]), and warnings (string[]).","Return no markdown, code fences, or explanatory text outside the JSON object."].join(`
2
- `);function w(e){const n=x(e,m.subagentSummaryBytes),t=b(n);return t===void 0||!g(t)?h(n):p(t)}function g(e){return l(e,d)!==void 0||!d.every(n=>Object.prototype.hasOwnProperty.call(e,n))||o(e.summary)===void 0?!1:d.slice(1).every(n=>{const t=e[n];return Array.isArray(t)&&t.every(r=>typeof r=="string"&&o(r)!==void 0)})}function p(e){return{summary:o(e.summary)??"The subagent completed without a text summary.",filesInspected:s(e.filesInspected),filesChanged:s(e.filesChanged),commandsRun:s(e.commandsRun),verification:s(e.verification),warnings:s(e.warnings)}}function h(e){return{summary:e||"The subagent completed without a text summary.",filesInspected:[],filesChanged:[],commandsRun:[],verification:[],warnings:["The child returned an unstructured or invalid handoff; verify the result directly."]}}function b(e){const n=[e.trim(),...S(e)];for(const t of n)if(!(t===void 0||t.length===0))try{const r=JSON.parse(t);if(r!==null&&typeof r=="object"&&!Array.isArray(r))return r}catch{}}function S(e){const n=[];for(let t=e.indexOf("{");t>=0;t=e.indexOf("{",t+1)){let r=0,c=!1,a=!1;for(let f=t;f<e.length;f+=1){const i=e[f];if(c){a?a=!1:i==="\\"?a=!0:i==='"'&&(c=!1);continue}if(i==='"')c=!0;else if(i==="{")r+=1;else if(i==="}"&&--r===0){n.push(e.slice(t,f+1));break}}}return n}function s(e){return Array.isArray(e)?e.filter(n=>typeof n=="string").map(n=>o(n)).filter(n=>n!==void 0).slice(0,y):[]}function o(e){if(typeof e!="string")return;const n=e.trim();if(n.length!==0)return Buffer.byteLength(n,"utf8")<=u?n:`${Buffer.from(n,"utf8").subarray(0,u-3).toString("utf8")}...`}function x(e,n){const t=e.trim(),r=Buffer.from(t,"utf8");return r.byteLength<=n?t:`${r.subarray(0,n-16).toString("utf8")}
3
- [truncated]`}export{I as SUBAGENT_HANDOFF_GUIDANCE,w as parseSubagentHandoff};
1
+ import{RESOURCE_LIMITS as m}from"../../domain/runtime/resource-limits.js";import{findUnexpectedRecordKey as l}from"../../domain/validation/record-schema.js";import{HANDOFF_FIELDS as c,MAX_HANDOFF_ITEMS as y,MAX_ITEM_BYTES as u}from"./orchestration-constants.js";const w=["## Handoff contract","When complete, return exactly one JSON object with only these fields: summary (string), filesInspected (string[]), filesChanged (string[]), commandsRun (string[]), verification (string[]), and warnings (string[]).","Return no markdown, code fences, or explanatory text outside the JSON object."].join(`
2
+ `);function E(e){const n=x(e,m.subagentSummaryBytes),t=b(n);return t===void 0||!p(t)?h(n):g(t)}function p(e){return l(e,c)!==void 0||!c.every(n=>Object.prototype.hasOwnProperty.call(e,n))||o(e.summary)===void 0?!1:c.slice(1).every(n=>{const t=e[n];return Array.isArray(t)&&t.every(r=>typeof r=="string"&&o(r)!==void 0)})}function g(e){return{summary:o(e.summary)??"The subagent completed without a text summary.",filesInspected:f(e.filesInspected),filesChanged:f(e.filesChanged),commandsRun:f(e.commandsRun),verification:f(e.verification),warnings:f(e.warnings)}}function h(e){return{summary:e||"The subagent completed without a text summary.",filesInspected:[],filesChanged:[],commandsRun:[],verification:[],warnings:["The child returned an unstructured or invalid handoff; verify the result directly."]}}function b(e){const n=[e.trim(),...S(e)];for(const t of n)if(!(t===void 0||t.length===0))try{const r=JSON.parse(t);if(r!==null&&typeof r=="object"&&!Array.isArray(r))return r}catch{}}function S(e){const n=[];for(let t=e.indexOf("{");t>=0;t=e.indexOf("{",t+1)){let r=0,d=!1,a=!1;for(let s=t;s<e.length;s+=1){const i=e[s];if(d){a?a=!1:i==="\\"?a=!0:i==='"'&&(d=!1);continue}if(i==='"')d=!0;else if(i==="{")r+=1;else if(i==="}"&&--r===0){n.push(e.slice(t,s+1));break}}}return n}function f(e){return Array.isArray(e)?e.filter(n=>typeof n=="string").map(n=>o(n)).filter(n=>n!==void 0).slice(0,y):[]}function o(e){if(typeof e!="string")return;const n=e.trim();if(n.length!==0)return Buffer.byteLength(n,"utf8")<=u?n:`${Buffer.from(n,"utf8").subarray(0,u-3).toString("utf8")}...`}function x(e,n){const t=e.trim(),r=Buffer.from(t,"utf8");return r.byteLength<=n?t:`${r.subarray(0,n-16).toString("utf8")}
3
+ [truncated]`}export{w as SUBAGENT_HANDOFF_GUIDANCE,E as parseSubagentHandoff};
@@ -0,0 +1,56 @@
1
+ export type ProjectMarker = {
2
+ readonly name: string;
3
+ readonly markers: readonly string[];
4
+ readonly extensions: readonly string[];
5
+ };
6
+ export type FrameworkMarker = {
7
+ readonly label: string;
8
+ readonly packages?: readonly string[];
9
+ readonly files?: readonly string[];
10
+ };
11
+ export declare const CONFIG_FILE_NAMES: readonly ["package.json", "tsconfig.json", "jsconfig.json", "pyproject.toml", "setup.cfg", "setup.py", "requirements.txt", "Pipfile", "Cargo.toml", "go.mod", "pom.xml", "build.gradle", "build.gradle.kts", "Gemfile", "composer.json", "Makefile", "CMakeLists.txt", "Dockerfile", "vitest.config.ts", "vitest.config.js", "jest.config.ts", "jest.config.js", "playwright.config.ts", "playwright.config.js", "pytest.ini", "tox.ini", "eslint.config.mjs", "vite.config.ts", "electron.vite.config.ts", "pnpm-workspace.yaml", "turbo.json"];
12
+ export declare const PROJECT_MARKERS: readonly ProjectMarker[];
13
+ export declare const FRAMEWORK_MARKERS: readonly FrameworkMarker[];
14
+ export declare const PACKAGE_MANAGERS: readonly [readonly ["package-lock.json", "npm"], readonly ["pnpm-lock.yaml", "pnpm"], readonly ["yarn.lock", "Yarn"], readonly ["bun.lockb", "Bun"], readonly ["bun.lock", "Bun"], readonly ["uv.lock", "uv"], readonly ["poetry.lock", "Poetry"], readonly ["Pipfile.lock", "Pipenv"], readonly ["Cargo.lock", "Cargo"], readonly ["go.sum", "Go modules"], readonly ["Gemfile.lock", "Bundler"], readonly ["composer.lock", "Composer"]];
15
+ export declare const SOURCE_ROOT_NAMES: readonly ["src", "app", "lib", "test", "tests", "packages", "apps", "cmd", "internal", "pkg", "crates", "components"];
16
+ export declare const TEST_RUNNER_MARKERS: readonly [{
17
+ readonly label: "Vitest";
18
+ readonly packages: readonly ["vitest"];
19
+ readonly scriptTokens: readonly ["vitest"];
20
+ readonly files: readonly ["vitest.config.ts", "vitest.config.js"];
21
+ }, {
22
+ readonly label: "Jest";
23
+ readonly packages: readonly ["jest"];
24
+ readonly scriptTokens: readonly ["jest"];
25
+ readonly files: readonly ["jest.config.ts", "jest.config.js"];
26
+ }, {
27
+ readonly label: "Playwright";
28
+ readonly packages: readonly ["@playwright/test"];
29
+ readonly scriptTokens: readonly ["playwright"];
30
+ readonly files: readonly ["playwright.config.ts", "playwright.config.js"];
31
+ }, {
32
+ readonly label: "pytest";
33
+ readonly packages: readonly [];
34
+ readonly scriptTokens: readonly ["pytest"];
35
+ readonly files: readonly ["pytest.ini", "tox.ini"];
36
+ }, {
37
+ readonly label: "Cargo test";
38
+ readonly packages: readonly [];
39
+ readonly scriptTokens: readonly [];
40
+ readonly files: readonly ["Cargo.toml"];
41
+ }, {
42
+ readonly label: "Go test";
43
+ readonly packages: readonly [];
44
+ readonly scriptTokens: readonly [];
45
+ readonly files: readonly ["go.mod"];
46
+ }, {
47
+ readonly label: "Maven test";
48
+ readonly packages: readonly [];
49
+ readonly scriptTokens: readonly ["mvn", "maven"];
50
+ readonly files: readonly ["pom.xml"];
51
+ }, {
52
+ readonly label: "Gradle test";
53
+ readonly packages: readonly [];
54
+ readonly scriptTokens: readonly ["gradle"];
55
+ readonly files: readonly ["build.gradle", "build.gradle.kts"];
56
+ }];
@@ -0,0 +1 @@
1
+ const e=["package.json","tsconfig.json","jsconfig.json","pyproject.toml","setup.cfg","setup.py","requirements.txt","Pipfile","Cargo.toml","go.mod","pom.xml","build.gradle","build.gradle.kts","Gemfile","composer.json","Makefile","CMakeLists.txt","Dockerfile","vitest.config.ts","vitest.config.js","jest.config.ts","jest.config.js","playwright.config.ts","playwright.config.js","pytest.ini","tox.ini","eslint.config.mjs","vite.config.ts","electron.vite.config.ts","pnpm-workspace.yaml","turbo.json"],s=[{name:"TypeScript",markers:["tsconfig.json"],extensions:[".ts",".tsx"]},{name:"JavaScript/JSX",markers:["package.json"],extensions:[".js",".jsx",".mjs",".cjs"]},{name:"Python",markers:["pyproject.toml","setup.py","requirements.txt","Pipfile"],extensions:[".py"]},{name:"Rust",markers:["Cargo.toml"],extensions:[".rs"]},{name:"Go",markers:["go.mod"],extensions:[".go"]},{name:"Java/Kotlin",markers:["pom.xml","build.gradle","build.gradle.kts"],extensions:[".java",".kt",".kts"]},{name:"Ruby",markers:["Gemfile"],extensions:[".rb"]},{name:"PHP",markers:["composer.json"],extensions:[".php"]},{name:"C/C++",markers:["CMakeLists.txt"],extensions:[".c",".h",".cc",".cpp",".cxx",".hpp"]},{name:"C#",markers:[],extensions:[".cs",".csproj",".sln"]}],t=[{label:"React",packages:["react","react-dom"]},{label:"Electron",packages:["electron"]},{label:"Vite",packages:["vite"]},{label:"Next.js",packages:["next"]},{label:"Express",packages:["express"]},{label:"Angular",packages:["@angular/core"]},{label:"Vue",packages:["vue"]},{label:"Svelte",packages:["svelte"]},{label:"Django",files:["manage.py"]},{label:"FastAPI",packages:["fastapi"]},{label:"Flask",packages:["flask"]},{label:"Rails",files:["bin/rails"]}],a=[["package-lock.json","npm"],["pnpm-lock.yaml","pnpm"],["yarn.lock","Yarn"],["bun.lockb","Bun"],["bun.lock","Bun"],["uv.lock","uv"],["poetry.lock","Poetry"],["Pipfile.lock","Pipenv"],["Cargo.lock","Cargo"],["go.sum","Go modules"],["Gemfile.lock","Bundler"],["composer.lock","Composer"]],o=["src","app","lib","test","tests","packages","apps","cmd","internal","pkg","crates","components"],l=[{label:"Vitest",packages:["vitest"],scriptTokens:["vitest"],files:["vitest.config.ts","vitest.config.js"]},{label:"Jest",packages:["jest"],scriptTokens:["jest"],files:["jest.config.ts","jest.config.js"]},{label:"Playwright",packages:["@playwright/test"],scriptTokens:["playwright"],files:["playwright.config.ts","playwright.config.js"]},{label:"pytest",packages:[],scriptTokens:["pytest"],files:["pytest.ini","tox.ini"]},{label:"Cargo test",packages:[],scriptTokens:[],files:["Cargo.toml"]},{label:"Go test",packages:[],scriptTokens:[],files:["go.mod"]},{label:"Maven test",packages:[],scriptTokens:["mvn","maven"],files:["pom.xml"]},{label:"Gradle test",packages:[],scriptTokens:["gradle"],files:["build.gradle","build.gradle.kts"]}];export{e as CONFIG_FILE_NAMES,t as FRAMEWORK_MARKERS,a as PACKAGE_MANAGERS,s as PROJECT_MARKERS,o as SOURCE_ROOT_NAMES,l as TEST_RUNNER_MARKERS};
@@ -1 +1 @@
1
- import f from"node:fs/promises";import a from"node:path";const g=["package.json","tsconfig.json","vitest.config.ts","vitest.config.js","jest.config.ts","jest.config.js","playwright.config.ts","playwright.config.js","eslint.config.mjs","vite.config.ts","electron.vite.config.ts","pnpm-workspace.yaml","turbo.json"],j={react:"React",electron:"Electron",vite:"Vite",next:"Next.js",express:"Express","@angular/core":"Angular",vue:"Vue",svelte:"Svelte"};class b{async discover(e){const n=await y(a.join(e,"package.json")),s={...r(n?.dependencies),...r(n?.devDependencies)},c=r(n?.scripts),u=await v(e,n),p=(await Promise.all(g.map(async i=>await o(a.join(e,i))?i:void 0))).filter(i=>i!==void 0),d=await w(e),l=[...new Set([...c.test===void 0?[]:[c.test.includes("vitest")?"Vitest":c.test.includes("jest")?"Jest":c.test.includes("playwright")?"Playwright":"package test script"],...s.vitest===void 0?[]:["Vitest"],...s.jest===void 0?[]:["Jest"],...s["@playwright/test"]===void 0?[]:["Playwright"]])];return{...d===void 0?{}:{packageManager:d},...typeof n?.engines=="object"&&n.engines!==null&&typeof n.engines.node=="string"?{runtime:`Node ${n.engines.node}`}:{},languages:u,frameworks:Object.entries(j).filter(([i])=>s[i]!==void 0).map(([,i])=>i),scripts:c,testRunners:l,sourceRoots:await m(e),configFiles:p}}}async function y(t){try{const e=JSON.parse(await f.readFile(t,"utf8"));return typeof e=="object"&&e!==null?e:void 0}catch{return}}async function o(t){try{return await f.access(t),!0}catch{return!1}}async function w(t){for(const[e,n]of[["package-lock.json","npm"],["pnpm-lock.yaml","pnpm"],["yarn.lock","Yarn"],["bun.lockb","Bun"]])if(await o(a.join(t,e)))return n}async function m(t){return(await Promise.all(["src","app","lib","test","tests"].map(async e=>await o(a.join(t,e))?e:void 0))).filter(e=>e!==void 0)}async function v(t,e){const n={...r(e?.dependencies),...r(e?.devDependencies)},s=new Set;return(n.typescript!==void 0||await o(a.join(t,"tsconfig.json")))&&s.add("TypeScript"),Object.keys(n).some(c=>["react","react-dom","vue","svelte"].includes(c))&&s.add("JavaScript/JSX"),s.size===0&&s.add("JavaScript"),[...s]}function r(t){return typeof t!="object"||t===null?{}:Object.fromEntries(Object.entries(t).filter(e=>typeof e[1]=="string"))}export{b as ProjectIntelligenceService};
1
+ import f from"node:fs/promises";import c from"node:path";import{CONFIG_FILE_NAMES as h,FRAMEWORK_MARKERS as g,PACKAGE_MANAGERS as R,PROJECT_MARKERS as j,SOURCE_ROOT_NAMES as k,TEST_RUNNER_MARKERS as E}from"./project-intelligence-constants.js";class J{async discover(e){const t=await P(c.join(e,"package.json")),s={...o(t?.dependencies),...o(t?.devDependencies)},a=o(t?.scripts),i=await O(e),r=await A(e),u=_(t);return{...r===void 0?{}:{packageManager:r},...u===void 0?{}:{runtime:u},languages:await b(e,t,i),frameworks:await S(e,s),scripts:a,testRunners:await F(e,s,a),sourceRoots:i,configFiles:await M(e,h)}}}async function S(n,e){const t=[];for(const s of g)(s.packages?.some(a=>e[a]!==void 0)===!0||await l(n,s.files??[]))&&t.push(s.label);return t}async function F(n,e,t){const s=Object.values(t).join(" ").toLowerCase(),a=[];for(const i of E)(i.packages.some(r=>e[r]!==void 0)||i.scriptTokens.some(r=>s.includes(r))||await l(n,i.files))&&a.push(i.label);return a}async function M(n,e){return(await Promise.all(e.map(async t=>await d(c.join(n,t))?t:void 0))).filter(t=>t!==void 0)}async function A(n){for(const[e,t]of R)if(await d(c.join(n,e)))return t}async function O(n){const e=[];for(const t of k)await d(c.join(n,t))&&e.push(t);return e}async function b(n,e,t){const s={...o(e?.dependencies),...o(e?.devDependencies)},a=[],i=await T(n,t);for(const r of j){const u=await l(n,r.markers),p=r.name==="TypeScript"?s.typescript!==void 0:r.name==="JavaScript/JSX"?Object.keys(s).length>0:!1,m=i.some(y=>r.extensions.some(w=>y.toLowerCase().endsWith(w)));(u||p||m)&&a.push(r.name)}return a.length===0?["Unknown"]:a}async function T(n,e){const t=[];for(const s of[".",...e.slice(0,8)])try{const a=await f.readdir(c.join(n,s),{withFileTypes:!0});for(const i of a.slice(0,256))i.isFile()?t.push(i.name):i.isDirectory()&&s!=="."&&t.push(...await N(c.join(n,s,i.name)))}catch{}return t}async function N(n){try{return(await f.readdir(n,{withFileTypes:!0})).slice(0,256).filter(e=>e.isFile()).map(e=>e.name)}catch{return[]}}async function l(n,e){return(await Promise.all(e.map(s=>d(c.join(n,s))))).some(Boolean)}function _(n){const e=n?.engines;return typeof e=="object"&&e!==null&&typeof e.node=="string"?`Node ${e.node}`:void 0}async function P(n){try{const e=JSON.parse(await f.readFile(n,"utf8"));return typeof e=="object"&&e!==null?e:void 0}catch{return}}async function d(n){try{return await f.access(n),!0}catch{return!1}}function o(n){return typeof n!="object"||n===null?{}:Object.fromEntries(Object.entries(n).filter(e=>typeof e[1]=="string"))}export{J as ProjectIntelligenceService};
@@ -1,5 +1,5 @@
1
1
  import type { ToolDefinition } from '@lotagate/sdk';
2
- import type { ToolExecutionContext, ToolExecutor, ToolInfo, ToolResult } from '@lotagate/agent-sdk';
2
+ import type { ToolAuthorizationDecision, ToolApprovalRequest, ToolExecutionContext, ToolExecutor, ToolInfo, ToolResult } from '@lotagate/agent-sdk';
3
3
  import type { ToolActivityObserver } from '../../ports/tool-activity.js';
4
4
  export interface BrowserHostRequest {
5
5
  version: 1;
@@ -10,8 +10,11 @@ export interface BrowserHostRequest {
10
10
  runId: string;
11
11
  action: string;
12
12
  params: Record<string, unknown>;
13
- executionBoundary: 'host';
14
- hostFallback: 'deny';
13
+ executionBoundary: 'sandbox' | 'host';
14
+ hostFallback: 'ask' | 'deny' | 'allow';
15
+ projectRoot?: string;
16
+ executionCwd?: string;
17
+ executionWorkspaceId?: string;
15
18
  }
16
19
  export interface BrowserHostResponse {
17
20
  version: 1;
@@ -19,6 +22,7 @@ export interface BrowserHostResponse {
19
22
  requestId: string;
20
23
  tool: 'browser';
21
24
  ok: boolean;
25
+ environmentId?: string;
22
26
  result?: unknown;
23
27
  error?: {
24
28
  code: string;
@@ -26,6 +30,8 @@ export interface BrowserHostResponse {
26
30
  message: string;
27
31
  retryable: boolean;
28
32
  };
33
+ executionBoundary?: 'sandbox' | 'host';
34
+ fallbackReason?: string;
29
35
  }
30
36
  export type BrowserHostInvoker = (request: BrowserHostRequest, signal?: AbortSignal) => Promise<BrowserHostResponse>;
31
37
  export declare function browserToolDefinitions(): readonly ToolDefinition[];
@@ -33,9 +39,13 @@ export declare class BrowserHostToolExecutor implements ToolExecutor {
33
39
  private readonly options;
34
40
  constructor(options: {
35
41
  request: BrowserHostInvoker;
42
+ executionBoundary: 'sandbox' | 'host';
43
+ hostFallback: 'ask' | 'deny' | 'allow';
44
+ onFallbackApproval?: (request: ToolApprovalRequest, reason: string) => boolean | ToolAuthorizationDecision | Promise<boolean | ToolAuthorizationDecision>;
36
45
  onActivity?: ToolActivityObserver;
37
46
  });
38
47
  listTools(): readonly ToolDefinition[];
39
48
  getToolInfo(toolName: string): ToolInfo | undefined;
40
49
  execute(toolName: string, input: Record<string, unknown>, context: ToolExecutionContext): Promise<ToolResult>;
50
+ private request;
41
51
  }
@@ -1,2 +1,2 @@
1
- import{randomUUID as y}from"node:crypto";import{imageContentBlockFromDataUrl as v,omitImageData as k}from"./tool-image-content.js";const p=[e("browser.navigate","Open an HTTP(S) URL in the agent browser.",{url:t("Destination URL."),tabId:t("Optional browser tab id.")},["url"]),e("browser.newTab","Open a new blank tab in the agent browser.",{},[]),e("browser.closeTab","Close the active browser tab.",{tabId:t("Optional browser tab id.")},[]),e("browser.selectTab","Make a browser tab active.",{tabId:t("Browser tab id.")},["tabId"]),e("browser.inspect","Inspect the current page DOM summary, text, headings, links, and visible interactive elements.",{tabId:t("Optional browser tab id.")},[]),e("browser.inspectElement","Inspect a page element including its DOM, attributes, bounds, and computed CSS.",{target:s(),tabId:t("Optional browser tab id.")},["target"]),e("browser.extractTable","Extract a bounded HTML table from the current page.",{target:s(),maxRows:b("Maximum number of data rows to return.")},["target"]),e("browser.drag","Drag one visible page target onto another.",{from:s(),to:s()},["from","to"]),e("browser.listFrames","List frames embedded in the current browser page.",{tabId:t("Optional browser tab id.")},[]),e("browser.console","Read recent browser console messages and page errors.",{tabId:t("Optional browser tab id."),limit:b("Maximum number of entries to return.")},[]),e("browser.network","Read recent browser network requests, HTTP failures, and request errors.",{tabId:t("Optional browser tab id."),limit:b("Maximum number of entries to return.")},[]),e("browser.accessibility","Inspect the page accessibility tree without exposing control values.",{tabId:t("Optional browser tab id.")},[]),e("browser.setViewport","Emulate a responsive browser viewport for the current tab.",{width:b("Viewport width in CSS pixels."),height:b("Viewport height in CSS pixels."),mobile:l("Whether to emulate a mobile layout."),deviceScaleFactor:b("Optional device scale factor.")},["width","height"]),e("browser.resetViewport","Reset the browser tab to its normal viewport.",{tabId:t("Optional browser tab id.")},[]),e("browser.screenshot","Capture the current browser tab as evidence.",{tabId:t("Optional browser tab id.")},[]),e("browser.click","Click a visible page element using an accessibility target, text, CSS selector, or coordinates.",{target:s()},["target"]),e("browser.focus","Focus a visible page field or control.",{target:s()},["target"]),e("browser.clear","Clear a visible editable page field.",{target:s()},["target"]),e("browser.hover","Move the browser pointer over a visible page element.",{target:s()},["target"]),e("browser.check","Check or uncheck a checkbox or radio input.",{target:s(),checked:l("Whether the control should be checked.")},["target","checked"]),e("browser.select","Select an option in a native HTML select control.",{target:s(),value:t("Option value or visible label.")},["target","value"]),e("browser.readField","Read a visible non-password form field value.",{target:s()},["target"]),e("browser.type","Enter text into a visible page field.",{target:s(),value:t("Text to enter.")},["target","value"]),e("browser.upload","Upload a workspace file through a visible file input.",{target:s(),path:t("Workspace-relative or absolute file path.")},["target","path"]),e("browser.download","Download an HTTP(S) resource to the Desktop downloads folder.",{url:t("HTTP(S) resource URL."),tabId:t("Optional browser tab id.")},["url"]),e("browser.exportPdf","Export the current browser page to a workspace PDF file.",{outputPath:t("Workspace-relative or absolute output path."),overwrite:l("Whether an existing output file may be replaced."),printBackground:l("Whether CSS backgrounds should be printed."),landscape:l("Whether to use landscape orientation."),pageSize:w(["A4","Letter"],"PDF paper size.")},["outputPath"]),e("browser.dialog","Read or respond to the active alert, confirm, or prompt dialog.",{action:w(["read","accept","dismiss"],"Dialog operation."),promptText:t("Optional text for a prompt dialog."),tabId:t("Optional browser tab id.")},["action"]),e("browser.press","Press a keyboard key in the current browser tab.",{key:t("Key name, for example Enter or Tab."),modifiers:I("Optional modifiers: Alt, Control, Shift, or Meta."),tabId:t("Optional browser tab id.")},["key"]),e("browser.scroll","Scroll the current browser tab.",{deltaX:b("Horizontal scroll amount."),deltaY:b("Vertical scroll amount."),tabId:t("Optional browser tab id.")},[]),e("browser.back","Navigate the current browser tab back.",{tabId:t("Optional browser tab id.")},[]),e("browser.forward","Navigate the current browser tab forward.",{tabId:t("Optional browser tab id.")},[]),e("browser.reload","Reload the current browser tab.",{tabId:t("Optional browser tab id.")},[]),e("browser.waitFor","Wait until a URL, text fragment, or CSS selector appears.",{condition:x(),timeoutMs:b("Maximum wait time in milliseconds.")},["condition"]),e("browser.tabs","List tabs in the agent browser session.",{},[])];function O(){return p}class C{options;constructor(o){this.options=o}listTools(){return O()}getToolInfo(o){if(!p.some(i=>g(i)===o))return;const n=["browser.inspect","browser.inspectElement","browser.extractTable","browser.listFrames","browser.console","browser.network","browser.accessibility","browser.setViewport","browser.resetViewport","browser.screenshot","browser.tabs","browser.scroll","browser.focus","browser.hover","browser.waitFor"].includes(o);return{toolName:o,source:"custom",executorId:"desktop-browser-host",metadata:{risk:n?"read":"unknown"}}}async execute(o,n,i){if(!p.some(a=>g(a)===o))return{content:`Unknown browser tool: ${o}`,isError:!0};const u=this.options.onActivity?.start({key:`${i.runId}:${o}`,toolName:o,source:"browser",label:T(o,n)});try{const a=await this.options.request({version:1,type:"host.request",requestId:y(),tool:"browser",sessionId:i.sessionId,runId:i.runId,action:o,params:n,executionBoundary:"host",hostFallback:"deny"},i.signal);if(!a.ok){const m=a.error?.message??"Desktop rejected the browser action.";return u?.complete(!0),{content:m,isError:!0,metadata:{code:a.error?.code??"BROWSER_HOST_ERROR",retryable:a.error?.retryable??!1}}}const c=o==="browser.screenshot"&&R(a.result)?a.result:void 0,d=c===void 0?void 0:v(c.dataUrl);if(c!==void 0&&c.dataUrl!==void 0&&d===void 0)throw new Error("Desktop returned an invalid browser screenshot payload.");const f=o==="browser.screenshot"?k(a.result,"dataUrl"):a.result,h=S(f,i.maxResultBytes);return u?.complete(!1),{content:h,isError:!1,...d===void 0?{}:{contentBlocks:[d]},metadata:{browser:!0}}}catch(a){return u?.complete(!0),{content:a instanceof Error?a.message:"Browser host request failed.",isError:!0}}}}function e(r,o,n,i){return{type:"function",function:{name:r,description:o,parameters:{type:"object",properties:n,required:i,additionalProperties:!1}}}}function t(r){return{type:"string",description:r}}function b(r){return{type:"number",description:r}}function l(r){return{type:"boolean",description:r}}function w(r,o){return{type:"string",enum:[...r],description:o}}function I(r){return{type:"array",items:{type:"string"},description:r}}function s(){return{type:"object",properties:{type:{type:"string",enum:["accessibility","text","css","coordinates"]},role:{type:"string"},name:{type:"string"},value:{type:"string"},selector:{type:"string"},x:{type:"number"},y:{type:"number"}},required:["type"],additionalProperties:!1}}function x(){return{type:"object",properties:{type:{type:"string",enum:["selector","text","url"]},value:{type:"string"}},required:["type","value"],additionalProperties:!1}}function g(r){return"function"in r?r.function.name:void 0}function S(r,o){const n=JSON.stringify(r??null);return Buffer.byteLength(n,"utf8")<=o?n:`${n.slice(0,Math.max(0,o-12))}
2
- [truncated]`}function T(r,o){return r==="browser.navigate"?`Open ${typeof o.url=="string"?o.url:"URL"}`:r==="browser.type"?"Enter text in browser":r==="browser.click"?"Click page element":r.replace(/^browser\./u,"Browser ")}function R(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}export{C as BrowserHostToolExecutor,O as browserToolDefinitions};
1
+ import{randomUUID as k}from"node:crypto";import{imageContentBlockFromDataUrl as v,omitImageData as I}from"./tool-image-content.js";import{READ_ONLY_BROWSER_TOOLS as O}from"../security/tool-policy-registry.js";const f=[e("browser.navigate","Open an HTTP(S) URL in the agent browser.",{url:o("Destination URL."),tabId:o("Optional browser tab id.")},["url"]),e("browser.newTab","Open a new blank tab in the agent browser.",{},[]),e("browser.closeTab","Close the active browser tab.",{tabId:o("Optional browser tab id.")},[]),e("browser.selectTab","Make a browser tab active.",{tabId:o("Browser tab id.")},["tabId"]),e("browser.inspect","Inspect the current page DOM summary, text, headings, links, and visible interactive elements.",{tabId:o("Optional browser tab id.")},[]),e("browser.inspectElement","Inspect a page element including its DOM, attributes, bounds, and computed CSS.",{target:i(),tabId:o("Optional browser tab id.")},["target"]),e("browser.extractTable","Extract a bounded HTML table from the current page.",{target:i(),maxRows:l("Maximum number of data rows to return.")},["target"]),e("browser.drag","Drag one visible page target onto another.",{from:i(),to:i()},["from","to"]),e("browser.listFrames","List frames embedded in the current browser page.",{tabId:o("Optional browser tab id.")},[]),e("browser.console","Read recent browser console messages and page errors.",{tabId:o("Optional browser tab id."),limit:l("Maximum number of entries to return.")},[]),e("browser.network","Read recent browser network requests, HTTP failures, and request errors.",{tabId:o("Optional browser tab id."),limit:l("Maximum number of entries to return.")},[]),e("browser.accessibility","Inspect the page accessibility tree without exposing control values.",{tabId:o("Optional browser tab id.")},[]),e("browser.setViewport","Emulate a responsive browser viewport for the current tab.",{width:l("Viewport width in CSS pixels."),height:l("Viewport height in CSS pixels."),mobile:d("Whether to emulate a mobile layout."),deviceScaleFactor:l("Optional device scale factor.")},["width","height"]),e("browser.resetViewport","Reset the browser tab to its normal viewport.",{tabId:o("Optional browser tab id.")},[]),e("browser.screenshot","Capture the current browser tab as evidence.",{tabId:o("Optional browser tab id.")},[]),e("browser.click","Click a visible page element using an accessibility target, text, CSS selector, or coordinates.",{target:i()},["target"]),e("browser.focus","Focus a visible page field or control.",{target:i()},["target"]),e("browser.clear","Clear a visible editable page field.",{target:i()},["target"]),e("browser.hover","Move the browser pointer over a visible page element.",{target:i()},["target"]),e("browser.check","Check or uncheck a checkbox or radio input.",{target:i(),checked:d("Whether the control should be checked.")},["target","checked"]),e("browser.select","Select an option in a native HTML select control.",{target:i(),value:o("Option value or visible label.")},["target","value"]),e("browser.readField","Read a visible non-password form field value.",{target:i()},["target"]),e("browser.type","Enter text into a visible page field.",{target:i(),value:o("Text to enter.")},["target","value"]),e("browser.upload","Upload a workspace file through a visible file input.",{target:i(),path:o("Workspace-relative or absolute file path.")},["target","path"]),e("browser.download","Download an HTTP(S) resource to the Desktop downloads folder.",{url:o("HTTP(S) resource URL."),tabId:o("Optional browser tab id.")},["url"]),e("browser.exportPdf","Export the current browser page to a workspace PDF file.",{outputPath:o("Workspace-relative or absolute output path."),overwrite:d("Whether an existing output file may be replaced."),printBackground:d("Whether CSS backgrounds should be printed."),landscape:d("Whether to use landscape orientation."),pageSize:h(["A4","Letter"],"PDF paper size.")},["outputPath"]),e("browser.dialog","Read or respond to the active alert, confirm, or prompt dialog.",{action:h(["read","accept","dismiss"],"Dialog operation."),promptText:o("Optional text for a prompt dialog."),tabId:o("Optional browser tab id.")},["action"]),e("browser.press","Press a keyboard key in the current browser tab.",{key:o("Key name, for example Enter or Tab."),modifiers:S("Optional modifiers: Alt, Control, Shift, or Meta."),tabId:o("Optional browser tab id.")},["key"]),e("browser.scroll","Scroll the current browser tab.",{deltaX:l("Horizontal scroll amount."),deltaY:l("Vertical scroll amount."),tabId:o("Optional browser tab id.")},[]),e("browser.back","Navigate the current browser tab back.",{tabId:o("Optional browser tab id.")},[]),e("browser.forward","Navigate the current browser tab forward.",{tabId:o("Optional browser tab id.")},[]),e("browser.reload","Reload the current browser tab.",{tabId:o("Optional browser tab id.")},[]),e("browser.waitFor","Wait until a URL, text fragment, or CSS selector appears.",{condition:x(),timeoutMs:l("Maximum wait time in milliseconds.")},["condition"]),e("browser.tabs","List tabs in the agent browser session.",{},[])];function R(){return f}class U{options;constructor(r){this.options=r}listTools(){return R()}getToolInfo(r){if(!f.some(n=>g(n)===r))return;const s=O.has(r);return{toolName:r,source:"custom",executorId:"desktop-browser-host",metadata:{risk:s?"read":"unknown"}}}async execute(r,s,n){if(!f.some(a=>g(a)===r))return{content:`Unknown browser tool: ${r}`,isError:!0};const b=this.options.onActivity?.start({key:`${n.runId}:${r}`,toolName:r,source:"browser",label:E(r,s)});try{let a=await this.options.request(this.request(r,s,n),n.signal);if(!a.ok&&a.error?.code==="SANDBOX_FALLBACK_REQUIRED"&&this.options.hostFallback==="ask"){const p=this.getToolInfo(r),c=await this.options.onFallbackApproval?.({toolName:r,input:s,context:n,...p===void 0?{}:{toolInfo:p}},a.error.message)??!1;if(typeof c=="boolean"?c:c.decision==="allow")a=await this.options.request({...this.request(r,s,n),executionBoundary:"host",hostFallback:"deny"},n.signal);else if(typeof c!="boolean"&&c.decision==="redirect")return b?.complete(!0,{userRedirect:!0}),{content:c.message,isError:!0,metadata:{code:"USER_REDIRECTED_ACTION",boundary:this.options.executionBoundary}}}if(!a.ok){const p=a.error?.message??"Desktop rejected the browser action.";return b?.complete(!0),{content:p,isError:!0,metadata:{code:a.error?.code??"BROWSER_HOST_ERROR",retryable:a.error?.retryable??!1}}}const u=r==="browser.screenshot"&&B(a.result)?a.result:void 0,w=u===void 0?void 0:v(u.dataUrl);if(u!==void 0&&u.dataUrl!==void 0&&w===void 0)throw new Error("Desktop returned an invalid browser screenshot payload.");const m=r==="browser.screenshot"?I(a.result,"dataUrl"):a.result,y=T(m,n.maxResultBytes);return b?.complete(!1),{content:y,isError:!1,...w===void 0?{}:{contentBlocks:[w]},metadata:{browser:!0,boundary:a.executionBoundary??this.options.executionBoundary,...a.environmentId===void 0?{}:{environmentId:a.environmentId},...a.fallbackReason===void 0?{}:{fallbackReason:a.fallbackReason}}}}catch(a){return b?.complete(!0),{content:a instanceof Error?a.message:"Browser host request failed.",isError:!0}}}request(r,s,n){return{version:1,type:"host.request",requestId:k(),tool:"browser",sessionId:n.sessionId,runId:n.runId,action:r,params:s,executionBoundary:this.options.executionBoundary,hostFallback:this.options.hostFallback,...n.workspaceRoot===void 0?{}:{projectRoot:n.workspaceRoot},...n.cwd===void 0?{}:{executionCwd:n.cwd},...typeof n.metadata?.executionWorkspaceId=="string"?{executionWorkspaceId:n.metadata.executionWorkspaceId}:{}}}}function e(t,r,s,n){return{type:"function",function:{name:t,description:r,parameters:{type:"object",properties:s,required:n,additionalProperties:!1}}}}function o(t){return{type:"string",description:t}}function l(t){return{type:"number",description:t}}function d(t){return{type:"boolean",description:t}}function h(t,r){return{type:"string",enum:[...t],description:r}}function S(t){return{type:"array",items:{type:"string"},description:t}}function i(){return{type:"object",properties:{type:{type:"string",enum:["accessibility","text","css","coordinates"]},role:{type:"string"},name:{type:"string"},value:{type:"string"},selector:{type:"string"},x:{type:"number"},y:{type:"number"}},required:["type"],additionalProperties:!1}}function x(){return{type:"object",properties:{type:{type:"string",enum:["selector","text","url"]},value:{type:"string"}},required:["type","value"],additionalProperties:!1}}function g(t){return"function"in t?t.function.name:void 0}function T(t,r){const s=JSON.stringify(t??null);return Buffer.byteLength(s,"utf8")<=r?s:`${s.slice(0,Math.max(0,r-12))}
2
+ [truncated]`}function E(t,r){return t==="browser.navigate"?`Open ${typeof r.url=="string"?r.url:"URL"}`:t==="browser.type"?"Enter text in browser":t==="browser.click"?"Click page element":t.replace(/^browser\./u,"Browser ")}function B(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}export{U as BrowserHostToolExecutor,R as browserToolDefinitions};
@@ -30,10 +30,13 @@ export interface ComputerHostResponse {
30
30
  }
31
31
  export type ComputerHostInvoker = (request: ComputerHostRequest, signal?: AbortSignal) => Promise<ComputerHostResponse>;
32
32
  export declare function computerToolDefinitions(): readonly ToolDefinition[];
33
+ export declare function computerToolDefinitionsForOperations(operations: readonly string[]): readonly ToolDefinition[];
33
34
  export declare class ComputerHostToolExecutor implements ToolExecutor {
34
35
  private readonly options;
36
+ private readonly definitions;
35
37
  constructor(options: {
36
38
  request: ComputerHostInvoker;
39
+ operations?: readonly string[];
37
40
  onActivity?: ToolActivityObserver;
38
41
  });
39
42
  listTools(): readonly ToolDefinition[];
@@ -1,2 +1,2 @@
1
- import{randomUUID as g}from"node:crypto";import{imageContentBlockFromResult as h,omitImageData as y}from"./tool-image-content.js";const p=[t("computer.listWindows","List visible Windows application windows that can be targeted.",{includeMinimized:u("Whether minimized windows should be included.")},[]),t("computer.inspect","Inspect the accessible UI elements of a target Windows application window.",{windowId:e("Target window id."),query:T(),maxDepth:i("Maximum UI tree depth.")},["windowId"]),t("computer.screenshot","Capture the target Windows application window for visual verification.",{windowId:e("Target window id."),region:w()},["windowId"]),t("computer.readText","Read text or the current value from an inspected Windows UI element.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),scope:c(["value","document","selection"],"Text source to read.")},["windowId","elementId"]),t("computer.readSelection","Read selected items from a Windows selection control.",{windowId:e("Target window id."),elementId:e("Selection control element id.")},["windowId","elementId"]),t("computer.readGrid","Read a bounded rectangular region from a Windows grid control.",{windowId:e("Target window id."),elementId:e("Grid control element id."),rowStart:i("Zero-based first row."),rowCount:i("Maximum rows to read."),columnStart:i("Zero-based first column."),columnCount:i("Maximum columns to read.")},["windowId","elementId"]),t("computer.recognizeText","Recognize visible text in a Windows application screenshot.",{windowId:e("Target window id."),region:w(),language:e("Optional BCP-47 OCR language tag.")},["windowId"]),t("computer.focus","Bring a Windows application window or one of its inspected elements to the foreground.",{windowId:e("Target window id."),elementId:e("Optional element id from computer.inspect.")},["windowId"]),t("computer.click","Click a visible target window element or validated point.",{windowId:e("Target window id."),elementId:e("Optional element id from computer.inspect."),point:m(),button:c(["left","right","middle"],"Mouse button."),clickCount:i("Number of clicks, one or two.")},["windowId"]),t("computer.type","Type text into the focused Windows control.",{windowId:e("Target window id."),text:e("Text to type."),elementId:e("Optional editable element id from computer.inspect.")},["windowId","text"]),t("computer.keypress","Press a keyboard key with optional modifiers in the target window.",{windowId:e("Target window id."),key:e("Key name, for example Enter or Tab."),modifiers:b("Optional modifiers: Alt, Control, Shift, or Meta.")},["windowId","key"]),t("computer.scroll","Scroll the target Windows application.",{windowId:e("Target window id."),deltaX:i("Horizontal scroll amount."),deltaY:i("Vertical scroll amount."),point:m()},["windowId"]),t("computer.drag","Drag from one validated point or element to another within a target window.",{windowId:e("Target window id."),from:f(),to:f(),durationMs:i("Drag duration in milliseconds.")},["windowId","from","to"]),t("computer.selectText","Select an occurrence of text in an inspected Windows text control.",{windowId:e("Target window id."),elementId:e("Text control element id."),text:e("Text to select."),occurrence:i("One-based occurrence to select.")},["windowId","elementId","text"]),t("computer.listDisplays","List connected Windows displays and their work areas.",{},[]),t("computer.launch","Launch an allowlisted Windows application by app id.",{appId:e("Registered application id.")},["appId"]),t("computer.wait","Wait for a target window, UI element, text, or idle state.",{windowId:e("Optional target window id."),condition:c(["window","element","text","idle"],"Condition to wait for."),elementId:e("Optional element id."),text:e("Optional text to find."),timeoutMs:i("Maximum wait time in milliseconds."),idleMs:i("Minimum system idle time for the idle condition.")},["condition","timeoutMs"]),t("computer.move","Move the pointer to a target point or element, including hover interactions.",{windowId:e("Target window id."),elementId:e("Optional element id from computer.inspect."),point:m(),durationMs:i("Movement duration in milliseconds.")},["windowId"]),t("computer.setValue","Set the value of an editable or range UI Automation control.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),value:e("New control value.")},["windowId","elementId","value"]),t("computer.invoke","Invoke the default action of an inspected button or menu item.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect.")},["windowId","elementId"]),t("computer.select","Set the selection state of an inspected selectable UI element.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),mode:c(["replace","add","remove"],"Selection operation.")},["windowId","elementId"]),t("computer.setToggleState","Set an inspected toggle or checkbox to a specific state.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),state:c(["on","off","indeterminate"],"Desired toggle state.")},["windowId","elementId","state"]),t("computer.setExpandedState","Expand or collapse an inspected tree, menu, or group control.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),expanded:u("Whether the element should be expanded.")},["windowId","elementId","expanded"]),t("computer.scrollIntoView","Scroll an inspected element into the visible area of its container.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect.")},["windowId","elementId"]),t("computer.setWindowState","Set the target window visual state and optionally its screen bounds.",{windowId:e("Target window id."),state:c(["normal","minimized","maximized"],"Desired window state."),bounds:v()},["windowId","state"]),t("computer.closeWindow","Request a normal close of the target Windows application window.",{windowId:e("Target window id.")},["windowId"]),t("computer.readClipboard","Read the current Windows text clipboard contents.",{},[]),t("computer.writeClipboard","Replace the Windows text clipboard contents.",{text:e("Text to place on the clipboard.")},["text"]),t("computer.waitForState","Wait until an inspected Windows UI element exposes the requested property value.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),property:c(["name","value","isEnabled","isOffscreen","toggleState","expandCollapseState","selectionState"],"UI Automation property to observe."),expected:e("Expected property value."),timeoutMs:i("Maximum wait time in milliseconds."),intervalMs:i("Polling interval in milliseconds.")},["windowId","elementId","property","expected","timeoutMs"]),t("computer.manageFileDialog","Set, confirm, or cancel a standard Windows file dialog.",{windowId:e("File dialog window id."),action:c(["setPath","confirm","cancel"],"File dialog operation."),path:e("File path to enter when using setPath or confirm.")},["windowId","action"])];function x(){return p}class C{options;constructor(o){this.options=o}listTools(){return x()}getToolInfo(o){if(!p.some(a=>I(a)===o))return;const d=["computer.listWindows","computer.inspect","computer.screenshot","computer.readText","computer.readSelection","computer.readGrid","computer.recognizeText","computer.listDisplays","computer.wait","computer.readClipboard","computer.waitForState"].includes(o);return{toolName:o,source:"custom",executorId:"desktop-computer-host",metadata:{risk:d?"read":"unknown"}}}async execute(o,d,a){if(!p.some(r=>I(r)===o))return{content:`Unknown computer tool: ${o}`,isError:!0};const s=this.options.onActivity?.start({key:`${a.runId}:${o}`,toolName:o,source:"computer",label:W(o)});try{const r=await this.options.request({version:1,type:"host.request",requestId:g(),tool:"computer",sessionId:a.sessionId,runId:a.runId,action:o,params:d,executionBoundary:"host",hostFallback:"deny"},a.signal);if(!r.ok)return s?.complete(!0),{content:r.error?.message??"Desktop rejected the computer action.",isError:!0,metadata:{code:r.error?.code??"COMPUTER_HOST_ERROR",retryable:r.error?.retryable??!1}};s?.complete(!1);const l=o==="computer.screenshot"?h(r.result):void 0;return{content:S(l===void 0?r.result:y(r.result,"dataBase64"),a.maxResultBytes),isError:!1,...l===void 0?{}:{contentBlocks:[l]},metadata:{computer:!0}}}catch(r){return s?.complete(!0),{content:r instanceof Error?r.message:"Computer host request failed.",isError:!0}}}}function t(n,o,d,a){return{type:"function",function:{name:n,description:o,parameters:{type:"object",properties:d,required:a,additionalProperties:!1}}}}function e(n){return{type:"string",description:n}}function i(n){return{type:"number",description:n}}function u(n){return{type:"boolean",description:n}}function c(n,o){return{type:"string",enum:[...n],description:o}}function b(n){return{type:"array",items:{type:"string"},description:n}}function T(){return{type:"object",properties:{role:e("Exact UI Automation control type."),name:e("Case-insensitive text contained in the element name."),text:e("Case-insensitive text contained in the element name or help text.")},additionalProperties:!1,description:"Optional role, name, or text filter."}}function w(){return{type:"object",properties:{x:{type:"number",description:"Left offset within the window."},y:{type:"number",description:"Top offset within the window."},width:{type:"number",description:"Region width."},height:{type:"number",description:"Region height."}},required:["x","y","width","height"],additionalProperties:!1,description:"Optional region within the target window."}}function v(){return{type:"object",properties:{x:i("Screen left coordinate."),y:i("Screen top coordinate."),width:i("Window width."),height:i("Window height.")},required:["x","y","width","height"],additionalProperties:!1,description:"Optional screen bounds."}}function m(){return{type:"object",properties:{x:{type:"number"},y:{type:"number"}},required:["x","y"],additionalProperties:!1}}function f(){return{type:"object",properties:{elementId:{type:"string"},x:{type:"number"},y:{type:"number"}},additionalProperties:!1}}function I(n){return"function"in n?n.function.name:void 0}function S(n,o){const d=JSON.stringify(n??null);return Buffer.byteLength(d,"utf8")<=o?d:`${d.slice(0,Math.max(0,o-12))}
2
- [truncated]`}function W(n){return n.replace(/^computer\./u,"Computer ")}export{C as ComputerHostToolExecutor,x as computerToolDefinitions};
1
+ import{randomUUID as g}from"node:crypto";import{imageContentBlockFromResult as h,omitImageData as y}from"./tool-image-content.js";import{READ_ONLY_COMPUTER_TOOLS as x}from"../security/tool-policy-registry.js";const s=[t("computer.listWindows","List visible desktop application windows that can be targeted.",{includeMinimized:w("Whether minimized windows should be included.")},[]),t("computer.inspect","Inspect accessible UI elements of a target desktop application window.",{windowId:e("Target window id."),query:v(),maxDepth:i("Maximum UI tree depth.")},["windowId"]),t("computer.screenshot","Capture the target application window or screen for visual verification.",{windowId:e("Target window id."),region:f()},["windowId"]),t("computer.readText","Read text or the current value from an inspected UI element.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),scope:c(["value","document","selection"],"Text source to read.")},["windowId","elementId"]),t("computer.readSelection","Read selected items from a selection control.",{windowId:e("Target window id."),elementId:e("Selection control element id.")},["windowId","elementId"]),t("computer.readGrid","Read a bounded rectangular region from a grid control.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),rowStart:i("Zero-based first row."),rowCount:i("Maximum rows to read."),columnStart:i("Zero-based first column."),columnCount:i("Maximum columns to read.")},["windowId","elementId"]),t("computer.recognizeText","Recognize visible text in an application screenshot.",{windowId:e("Target window id."),region:f(),language:e("Optional BCP-47 OCR language tag.")},["windowId"]),t("computer.focus","Bring an application window or inspected element to the foreground.",{windowId:e("Target window id."),elementId:e("Optional element id from computer.inspect.")},["windowId"]),t("computer.click","Click a visible target window element or validated point.",{windowId:e("Target window id."),elementId:e("Optional element id from computer.inspect."),point:m(),button:c(["left","right","middle"],"Mouse button."),clickCount:i("Number of clicks, one or two.")},["windowId"]),t("computer.type","Type text into the focused application control.",{windowId:e("Target window id."),text:e("Text to type."),elementId:e("Optional editable element id from computer.inspect.")},["windowId","text"]),t("computer.keypress","Press a keyboard key with optional modifiers in the target window.",{windowId:e("Target window id."),key:e("Key name, for example Enter or Tab."),modifiers:T("Optional modifiers: Alt, Control, Shift, or Meta.")},["windowId","key"]),t("computer.scroll","Scroll the target application.",{windowId:e("Target window id."),deltaX:i("Horizontal scroll amount."),deltaY:i("Vertical scroll amount."),point:m()},["windowId"]),t("computer.drag","Drag from one validated point or element to another within a target window.",{windowId:e("Target window id."),from:I(),to:I(),durationMs:i("Drag duration in milliseconds.")},["windowId","from","to"]),t("computer.selectText","Select an occurrence of text in an inspected text control.",{windowId:e("Target window id."),elementId:e("Text control element id."),text:e("Text to select."),occurrence:i("One-based occurrence to select.")},["windowId","elementId","text"]),t("computer.listDisplays","List connected displays and their work areas.",{},[]),t("computer.launch","Launch an allowlisted desktop application by app id.",{appId:e("Registered application id.")},["appId"]),t("computer.wait","Wait for a target window, UI element, text, or idle state.",{windowId:e("Optional target window id."),condition:c(["window","element","text","idle"],"Condition to wait for."),elementId:e("Optional element id."),text:e("Optional text to find."),timeoutMs:i("Maximum wait time in milliseconds."),idleMs:i("Minimum system idle time for the idle condition.")},["condition","timeoutMs"]),t("computer.move","Move the pointer to a target point or element, including hover interactions.",{windowId:e("Target window id."),elementId:e("Optional element id from computer.inspect."),point:m(),durationMs:i("Movement duration in milliseconds.")},["windowId"]),t("computer.setValue","Set the value of an editable or range UI Automation control.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),value:e("New control value.")},["windowId","elementId","value"]),t("computer.invoke","Invoke the default action of an inspected button or menu item.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect.")},["windowId","elementId"]),t("computer.select","Set the selection state of an inspected selectable UI element.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),mode:c(["replace","add","remove"],"Selection operation.")},["windowId","elementId"]),t("computer.setToggleState","Set an inspected toggle or checkbox to a specific state.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),state:c(["on","off","indeterminate"],"Desired toggle state.")},["windowId","elementId","state"]),t("computer.setExpandedState","Expand or collapse an inspected tree, menu, or group control.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),expanded:w("Whether the element should be expanded.")},["windowId","elementId","expanded"]),t("computer.scrollIntoView","Scroll an inspected element into the visible area of its container.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect.")},["windowId","elementId"]),t("computer.setWindowState","Set the target window visual state and optionally its screen bounds.",{windowId:e("Target window id."),state:c(["normal","minimized","maximized"],"Desired window state."),bounds:S()},["windowId","state"]),t("computer.closeWindow","Request a normal close of the target application window.",{windowId:e("Target window id.")},["windowId"]),t("computer.readClipboard","Read the current text clipboard contents.",{},[]),t("computer.writeClipboard","Replace the text clipboard contents.",{text:e("Text to place on the clipboard.")},["text"]),t("computer.waitForState","Wait until an inspected UI element exposes the requested property value.",{windowId:e("Target window id."),elementId:e("Element id from computer.inspect."),property:c(["name","value","isEnabled","isOffscreen","toggleState","expandCollapseState","selectionState"],"UI property to observe."),expected:e("Expected property value."),timeoutMs:i("Maximum wait time in milliseconds."),intervalMs:i("Polling interval in milliseconds.")},["windowId","elementId","property","expected","timeoutMs"]),t("computer.manageFileDialog","Set, confirm, or cancel a standard file dialog.",{windowId:e("File dialog window id."),action:c(["setPath","confirm","cancel"],"File dialog operation."),path:e("File path to enter when using setPath or confirm.")},["windowId","action"])];function R(){return s}function b(n){if(n.includes("*"))return s;const o=new Set(n);return s.filter(a=>{const r=u(a);return r!==void 0&&o.has(r)})}class U{options;definitions;constructor(o){this.options=o,this.definitions=o.operations===void 0?s:b(o.operations)}listTools(){return this.definitions}getToolInfo(o){if(!this.definitions.some(r=>u(r)===o))return;const a=x.has(o);return{toolName:o,source:"custom",executorId:"desktop-computer-host",metadata:{risk:a?"read":"unknown"}}}async execute(o,a,r){if(!this.definitions.some(d=>u(d)===o))return{content:`Computer capability is unavailable for ${o}.`,isError:!0,metadata:{code:"COMPUTER_CAPABILITY_UNAVAILABLE"}};const l=this.options.onActivity?.start({key:`${r.runId}:${o}`,toolName:o,source:"computer",label:E(o)});try{const d=await this.options.request({version:1,type:"host.request",requestId:g(),tool:"computer",sessionId:r.sessionId,runId:r.runId,action:o,params:a,executionBoundary:"host",hostFallback:"deny"},r.signal);if(!d.ok)return l?.complete(!0),{content:d.error?.message??"Desktop rejected the computer action.",isError:!0,metadata:{code:d.error?.code??"COMPUTER_HOST_ERROR",retryable:d.error?.retryable??!1}};l?.complete(!1);const p=o==="computer.screenshot"?h(d.result):void 0;return{content:O(p===void 0?d.result:y(d.result,"dataBase64"),r.maxResultBytes),isError:!1,...p===void 0?{}:{contentBlocks:[p]},metadata:{computer:!0}}}catch(d){return l?.complete(!0),{content:d instanceof Error?d.message:"Computer host request failed.",isError:!0}}}}function t(n,o,a,r){return{type:"function",function:{name:n,description:o,parameters:{type:"object",properties:a,required:r,additionalProperties:!1}}}}function e(n){return{type:"string",description:n}}function i(n){return{type:"number",description:n}}function w(n){return{type:"boolean",description:n}}function c(n,o){return{type:"string",enum:[...n],description:o}}function T(n){return{type:"array",items:{type:"string"},description:n}}function v(){return{type:"object",properties:{role:e("Exact UI Automation control type."),name:e("Case-insensitive text contained in the element name."),text:e("Case-insensitive text contained in the element name or help text.")},additionalProperties:!1,description:"Optional role, name, or text filter."}}function f(){return{type:"object",properties:{x:{type:"number",description:"Left offset within the window."},y:{type:"number",description:"Top offset within the window."},width:{type:"number",description:"Region width."},height:{type:"number",description:"Region height."}},required:["x","y","width","height"],additionalProperties:!1,description:"Optional region within the target window."}}function S(){return{type:"object",properties:{x:i("Screen left coordinate."),y:i("Screen top coordinate."),width:i("Window width."),height:i("Window height.")},required:["x","y","width","height"],additionalProperties:!1,description:"Optional screen bounds."}}function m(){return{type:"object",properties:{x:{type:"number"},y:{type:"number"}},required:["x","y"],additionalProperties:!1}}function I(){return{type:"object",properties:{elementId:{type:"string"},x:{type:"number"},y:{type:"number"}},additionalProperties:!1}}function u(n){return"function"in n?n.function.name:void 0}function O(n,o){const a=JSON.stringify(n??null);return Buffer.byteLength(a,"utf8")<=o?a:`${a.slice(0,Math.max(0,o-12))}
2
+ [truncated]`}function E(n){return n.replace(/^computer\./u,"Computer ")}export{U as ComputerHostToolExecutor,R as computerToolDefinitions,b as computerToolDefinitionsForOperations};
@@ -1,9 +1,9 @@
1
1
  import type { Readable, Writable } from 'node:stream';
2
2
  import type { CliRuntime } from '../../bootstrap/runtime-factory.js';
3
- export declare const DESKTOP_PROTOCOL_VERSION: 1;
3
+ export { DESKTOP_PROTOCOL_VERSION } from './desktop-agent-contracts.js';
4
4
  /**
5
5
  * Local JSONL bridge for the Desktop application. It is deliberately kept in
6
6
  * the CLI application layer: Desktop reuses CLI policy and runtime, while the
7
7
  * public SDK packages remain independent libraries.
8
8
  */
9
- export declare function runDesktopAgentCommand(runtime: CliRuntime, cwd: string, input: Readable, output: Writable): Promise<number>;
9
+ export declare function runDesktopAgentCommand(runtime: CliRuntime, cwd: string, input: Readable, output: Writable, signal?: AbortSignal): Promise<number>;
@@ -1,3 +1 @@
1
- import{randomUUID as U}from"node:crypto";import{AuthenticationService as k}from"../auth/authentication-service.js";import{createLotaGateClient as N}from"../../infrastructure/sdk/lotagate-client-factory.js";import{ModelCatalogAdapter as q}from"../../infrastructure/sdk/model-catalog-adapter.js";import{loadExecutionConfig as T}from"../config/execution-config.js";import{prepareCliAgent as F,warmMcpRuntime as z}from"../agent/cli-agent-execution-service.js";import{createContextManagement as Q}from"../agent/context-compaction.js";import{persistContextCompaction as X}from"../agent/context-compaction-persistence.js";import{CliAgentSessionStore as Z}from"../agent/agent-session-store.js";import{CliTurnEventProjector as tt}from"../orchestration/cli-turn-event-projector.js";import{persistCliTurnEvent as et}from"../orchestration/cli-turn-persistence.js";import{createTurnId as ot,recordTurnCompletion as st,recordTurnFailure as it,recordTurnStart as nt}from"../session/session-turn-lifecycle.js";import{ProjectSessionAccess as G}from"../session/project-session-access.js";import{permissionRuleForRequest as at}from"../security/workspace-permission-policy.js";import{agentLimitNotice as rt,classifyAgentLimit as ct}from"../agent/agent-limit.js";import{CliError as f}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as g}from"../../domain/errors/error-codes.js";import{readLinesBounded as dt}from"./jsonl-protocol.js";import{RESOURCE_LIMITS as lt}from"../../domain/runtime/resource-limits.js";import{getDesktopCommandCatalog as mt}from"./desktop-command-catalog.js";import{COMMAND_REGISTRY as pt}from"../commands/command-runtime.js";import{executeDesktopCommand as ut}from"./desktop-command-executor.js";import{DesktopAttachmentStore as ht}from"./desktop-attachment-store.js";import{SubagentJobRegistry as wt}from"../orchestration/cli-subagent-service.js";import{subagentDesktopPayload as ft}from"./desktop-orchestration-events.js";import{DesktopIntentEventWriter as gt}from"./desktop-intent-event-writer.js";import{resolveModelContextWindow as bt}from"../model/model-context-window.js";import{JsonLineWriter as Et}from"./json-line-writer.js";import{desktopApprovalMode as vt,sessionResult as J,toDesktopError as E}from"./desktop-protocol-helpers.js";import{DesktopApprovalBroker as yt}from"./desktop-approval-broker.js";import{SessionExecutionWorkspaceService as It}from"../workspace/session-execution-workspace.js";import{buildUserMessage as kt}from"../../infrastructure/clipboard/image-normalizer.js";import{isBrowserHostResponse as Rt,isComputerHostResponse as xt,isDesktopHostResponse as Tt,isDocumentHostResponse as St,parseDesktopRequest as Ct}from"./desktop-agent-request-parser.js";import{desktopMcpEvent as K}from"./desktop-mcp-events.js";import{DesktopExtensionService as At}from"./desktop-extension-service.js";import{DesktopExtensionRequestHandler as Dt}from"./desktop-extension-request-handler.js";const S=1,Mt=25e3;async function we(P,t,e,o){return new Nt(P,t,o).run(e)}class Nt{runtime;cwd;writer;turns=new Map;activeTurnBySession=new Map;subagentJobs=new wt;sessionStores=new Map;turnContexts=new Map;attachments=new ht;approvalBroker=new yt((t,e)=>this.writeEvent(t,e));commands=new Map;browserRequests=new Map;hostRequests=new Map;computerRequests=new Map;documentRequests=new Map;extensions=new At;extensionRequests;intentEvents;fallbackExecutionWorkspaces;browserHostEnabled=!1;computerHostEnabled=!1;documentHostEnabled=!1;stopping=!1;constructor(t,e,o){this.runtime=t,this.cwd=e,this.writer=new Et(o),this.extensionRequests=new Dt(this.extensions,(s,i)=>this.respond(s,i),this.cwd),this.intentEvents=new gt({writeEvent:(s,i)=>this.writeEvent(s,i),log:(s,i)=>this.logInfo(s,i)})}async run(t){let e=0;try{for await(const o of dt(t,lt.jsonlLineBytes)){if(o.trim().length===0)continue;let s;try{s=JSON.parse(o)}catch(a){e+=1,await this.writeError("unknown","protocol",E(a));continue}if(Rt(s)){this.resolveBrowserRequest(s);continue}if(Tt(s)){this.resolveDesktopHostRequest(s);continue}if(xt(s)){this.resolveComputerHostRequest(s);continue}if(St(s)){this.resolveDocumentHostRequest(s);continue}let i;try{i=Ct(s)}catch(a){e+=1,await this.writeError("unknown","protocol",E(a));continue}try{await this.handle(i)}catch(a){e+=1,await this.writeError(i.id,i.method,E(a))}if(this.stopping)break}}catch(o){e+=1,await this.writeError("unknown","protocol",E(o))}finally{for(const o of this.turns.values())o.controller.abort();await Promise.allSettled([...this.turns.values()].map(o=>o.operation));for(const o of this.commands.values())o.controller.abort();await Promise.allSettled([...this.commands.values()].map(o=>o.operation)),await this.subagentJobs.close(),this.approvalBroker.close();for(const o of this.browserRequests.values())o.onAbort!==void 0&&o.signal?.removeEventListener("abort",o.onAbort),o.reject(new Error("The Desktop browser bridge was closed."));this.browserRequests.clear();for(const o of this.hostRequests.values())o.onAbort!==void 0&&o.signal?.removeEventListener("abort",o.onAbort),o.reject(new Error("The Desktop execution bridge was closed."));this.hostRequests.clear();for(const o of this.computerRequests.values())o.onAbort!==void 0&&o.signal?.removeEventListener("abort",o.onAbort),o.reject(new Error("The Desktop computer bridge was closed."));this.computerRequests.clear();for(const o of this.documentRequests.values())o.onAbort!==void 0&&o.signal?.removeEventListener("abort",o.onAbort),o.reject(new Error("The Desktop document bridge was closed."));this.documentRequests.clear(),this.attachments.clear(),await this.writer.flush()}return e===0?0:1}async handle(t){switch(t.method){case"initialize":return this.browserHostEnabled=t.params.browserHost===!0,this.computerHostEnabled=t.params.computerHost===!0,this.documentHostEnabled=t.params.documentHost===!0,this.respond(t,{protocol:"lotagate.desktop",version:S,capabilities:["sessions","streaming","tool-approval","project-trust","models","auth","commands","image-attachments","file-attachments","execution-context","tool-allowlist","approval-reviews","lifecycle-controls","execution-broker","intent-runtime","host-evidence","conversational-progress","local-memory-commands","extensions",...this.browserHostEnabled?["browser-host"]:[],...this.computerHostEnabled?["computer-host"]:[],...this.documentHostEnabled?["document-host"]:[]]});case"session.create":return this.createSession(t);case"title.generate":return this.generateTitle(t);case"session.list":return this.listSessions(t);case"session.resume":return this.resumeSession(t);case"extension.listPublicPlugins":case"extension.resolvePublicPluginSource":case"extension.readPublicPluginContribution":case"extension.readDetail":case"extension.readPluginIcon":return this.extensionRequests.handle(t);case"attachment.begin":return this.attachments.begin({id:t.params.attachmentId,name:t.params.name,mimeType:t.params.mimeType,sizeBytes:t.params.sizeBytes}),this.respond(t,{accepted:!0,attachmentId:t.params.attachmentId});case"attachment.chunk":return this.attachments.appendChunk(t.params.attachmentId,t.params.index,t.params.dataBase64),this.respond(t,{accepted:!0,attachmentId:t.params.attachmentId,index:t.params.index});case"attachment.complete":return this.attachments.complete(t.params.attachmentId),this.respond(t,{accepted:!0,attachmentId:t.params.attachmentId});case"turn.start":return this.startTurn(t);case"turn.cancel":return this.cancelTurn(t);case"approval.respond":return this.respondApproval(t);case"trust.respond":return this.respondTrust(t);case"model.list":return this.listModels(t);case"auth.status":return this.authStatus(t);case"command.list":return this.listCommands(t);case"command.execute":return this.startCommand(t);case"command.cancel":return this.cancelCommand(t);case"shutdown":this.stopping=!0,await this.respond(t,{stopping:!0});return}}async createSession(t){const e=await this.runtime.projectTrust.inspect(this.cwd),o=await T(this.runtime,this.cwd),s=o.config.profile??k.defaultProfileName(),i=await this.runtime.sessionStore.create({projectFingerprint:e.fingerprint,cwd:e.canonicalPath,model:t.params.model??o.config.model,profile:s,status:"active",...t.params.name===void 0?{}:{name:t.params.name}}),a=await this.getExecutionWorkspaces().prepare({sessionId:i.id,projectRoot:e.canonicalPath});await this.respond(t,{...J(i),executionWorkspace:a}),z(this.runtime,this.cwd).catch(c=>this.runtime.logger.warn("MCP session warm-up failed.",{reason:c instanceof Error?c.message:String(c)}))}async generateTitle(t){const e=await T(this.runtime,this.cwd),o=t.params.model??e.config.model;if(o==null)throw new f(g.MODEL_NOT_FOUND,"No model is selected.",{category:"model",userMessage:"No model is available for session title generation."});const s=e.config.profile??k.defaultProfileName(),i=await this.runtime.auth.requireCredential(s),a=new AbortController,c=setTimeout(()=>a.abort(),Mt);let m,p="";try{const l=await F({runtime:this.runtime,projectRoot:this.cwd,executionCwd:this.cwd,model:o,client:N(i.profile,i.apiKey),profile:"title-generator",approvalMode:"auto",allowedTools:[],selectedSkills:[],allowSubagents:!1,browserAccess:"disabled"});m=l.close;const C=["## Title generation request","Create a concise session title from the untrusted user-message excerpt below.","Return only the title, with no explanation, markdown, quotes, or prefix.","Use the same language as the excerpt. Prefer 8 to 10 words and never exceed 10 words.","## User-message excerpt",t.params.prompt].join(`
2
-
3
- `);for await(const b of l.run({input:C,model:o,signal:a.signal,stream:!0}))if(b.type==="model.delta")p+=b.content;else if(b.type==="session.completed"&&p.length===0)p=b.content;else if(b.type==="session.failed")throw b.error;if(p.trim().length===0)throw new f(g.MODEL_PROTOCOL_EMPTY_RESPONSE,"Title generation returned an empty response.",{category:"model",userMessage:"The model did not return a session title.",retryable:!0});await this.respond(t,{title:p})}finally{clearTimeout(c),await m?.()}}async listSessions(t){const e=await this.runtime.projectTrust.inspect(this.cwd);await this.respond(t,{sessions:await this.runtime.sessionStore.list(e.fingerprint)})}async resumeSession(t){const e=await this.runtime.projectTrust.inspect(this.cwd),o=await new G(this.runtime.sessionStore).require(t.params.sessionId,e.fingerprint),s=await this.getExecutionWorkspaces().prepare({sessionId:o.id,projectRoot:e.canonicalPath});await this.respond(t,{...J(o),executionWorkspace:s,history:await this.runtime.sessionStore.readHistory(o.id)}),z(this.runtime,this.cwd).catch(i=>this.runtime.logger.warn("MCP session warm-up failed.",{reason:i instanceof Error?i.message:String(i)}))}async startTurn(t){const{sessionId:e}=t.params;if(this.runtime.logger.info("CLI Desktop turn request received.",{requestId:t.id,sessionId:e,promptLength:t.params.prompt.length,requestedModel:t.params.model}),[...this.turns.values()].some(l=>l.sessionId===e))throw new f(g.INVALID_ARGUMENT,"A turn is already active for this session.",{category:"session",userMessage:"This session already has an active turn."});const o=await this.runtime.projectTrust.inspect(this.cwd),s=await new G(this.runtime.sessionStore).require(e,o.fingerprint),i=await this.getExecutionWorkspaces().prepare({sessionId:e,projectRoot:o.canonicalPath}),a=this.attachments.take(t.params.attachmentIds??[]),c=ot(),m=new AbortController;this.turnContexts.set(c,{...i,...t.params.taskId===void 0?{}:{taskId:t.params.taskId}}),this.activeTurnBySession.set(e,c);const p=this.executeTurn(t,s,o,i,c,m,a).catch(async l=>{await this.writeEvent(m.signal.aborted?"turn.cancelled":"turn.failed",{turnId:c,sessionId:e,...m.signal.aborted?{}:{error:E(l)}})}).finally(()=>{this.turns.delete(c),this.turnContexts.delete(c),this.activeTurnBySession.get(e)===c&&this.activeTurnBySession.delete(e)});this.turns.set(c,{sessionId:e,controller:m,operation:p}),await this.respond(t,{accepted:!0,turnId:c,sessionId:e})}async executeTurn(t,e,o,s,i,a,c){const m=await T(this.runtime,this.cwd);if(!await this.runtime.projectTrust.isTrusted(o)){const r=U();if(await this.writeEvent("trust.requested",{trustRequestId:r,sessionId:e.id,path:o.canonicalPath}),!await this.approvalBroker.waitForTrust(r,a.signal))throw new f(g.PROJECT_TRUST_REQUIRED,"Project trust was not granted.",{category:"project",userMessage:"Trust this project in the Desktop application before running tools."});await this.runtime.projectTrust.grant(o),await this.runtime.workspaceSettings.ensureInitialized(o.canonicalPath)}const l=t.params.model??e.model??m.config.model;if(l==null)throw new f(g.MODEL_NOT_FOUND,"No model is selected.",{category:"model",userMessage:"Select a model before starting a turn."});const C=t.params.reasoningEffort??m.config.effort;this.runtime.logger.info("CLI Desktop turn model resolved.",{sessionId:e.id,turnId:i,requestedModel:t.params.model,sessionModel:e.model,resolvedModel:l});const b=e.profile??m.config.profile??k.defaultProfileName(),L=await this.runtime.auth.requireCredential(b),H=N(L.profile,L.apiKey),O=await bt(this.runtime,l,b),A=this.sessionStores.get(e.id)??new Z;this.sessionStores.set(e.id,A);const I=[],R=[];for(const r of c)R.push({...r,attachment:await this.runtime.sessionStore.saveAttachment(e.id,r.attachment,r.bytes)});await nt(this.runtime.sessionStore,e.id,i,t.params.prompt,R.map(r=>r.attachment.id)),await this.runtime.sessionStore.updateStatus(e.id,"active"),await this.writeEvent("turn.started",{turnId:i,sessionId:e.id,model:l});const V={onSubagentLifecycle:r=>this.writeEvent(`subagent.${r.type}`,ft(r,this.activeTurnBySession.get(r.sessionId)))},Y={start:r=>{if(r.source!=="shell"&&r.source!=="computer"&&r.source!=="custom"&&r.toolName!=="filesystem.read"&&r.toolName!=="filesystem.write"&&r.toolName!=="filesystem.exists")return;const h={turnId:i,sessionId:e.id,actionId:r.key,toolName:r.toolName,displayName:r.label,...r.source==="shell"?{command:r.label}:{},kind:r.source??"tool",source:r.source},w=(u,v)=>{this.writeEvent(u,v).catch(y=>this.runtime.logger.warn("Desktop tool activity event failed.",{event:u,reason:y instanceof Error?y.message:String(y)}))};return w("tool.activity.started",{...h,status:"running"}),{complete:(u,v)=>w("tool.activity.completed",{...h,...v??{},status:u?"failed":"completed",isError:u})}}};let D,M=!1;const j=setTimeout(()=>a.abort(),t.params.execution.timeoutMs);try{const r=t.params.execution,h=await F({runtime:this.runtime,projectRoot:o.canonicalPath,executionCwd:s.executionCwd,model:l,client:H,reasoningEffort:C,profile:"interactive-trusted",approvalMode:vt(r.permissionPolicy),...r.allowedTools===void 0?{}:{allowedTools:r.allowedTools},...t.params.skills===void 0?{}:{selectedSkills:t.params.skills},browserAccess:r.browserAccess,subagentLifecycle:V,subagentJobs:this.subagentJobs,...this.browserHostEnabled?{browserHost:(n,d)=>this.requestBrowserHost(n,d)}:{},...this.browserHostEnabled?{desktopHost:((n,d)=>this.requestDesktopHost(n,d))}:{},...this.computerHostEnabled?{computerHost:((n,d)=>this.requestComputerHost(n,d))}:{},...this.documentHostEnabled?{documentHost:((n,d)=>this.requestDocumentHost(n,d))}:{},executionBoundary:r.isolation,hostFallback:r.hostFallback,...this.browserHostEnabled?{onExecutionFallbackApproval:(n,d)=>this.approvalBroker.waitForApproval(n,e.id,i,a.signal,"host",d)}:{},toolActivity:Y,onIntentLifecycle:n=>this.intentEvents.write(n,e.id,i),contextManagement:Q({client:H,model:l,...O===void 0?{}:{contextWindow:O},onCompactionStart:()=>this.writeEvent("context.compacting",{turnId:i,sessionId:e.id}),onSummaryFailure:n=>this.runtime.logger.warn("Context summarization failed; using fallback summary.",{reason:n instanceof Error?n.message:String(n)})}),agentSessionStore:A,prompt:n=>this.approvalBroker.waitForApproval(n,e.id,i,a.signal,r.isolation),rememberApproval:n=>this.runtime.workspaceSettings.rememberAllow(o.canonicalPath,at(n.toolName,n.input)),audit:async n=>{this.runtime.logger.info("Tool authorization decision.",{toolName:n.toolName,decision:n.decision,reason:n.reason}),await this.runtime.sessionStore.appendEvent({type:"tool.approval",timestamp:new Date().toISOString(),sessionId:e.id,turnId:i,data:{toolName:n.toolName,decision:n.decision,reason:n.reason}})},onModelComplete:n=>{n.usage!==void 0&&this.writeEvent("usage.updated",{turnId:i,sessionId:e.id,usage:n.usage}).catch(d=>this.runtime.logger.warn("Desktop usage event failed.",{reason:d instanceof Error?d.message:String(d)}))},onWrite:n=>{this.writeEvent("file.changed",{turnId:i,sessionId:e.id,change:n}).catch(d=>this.runtime.logger.warn("Desktop file event failed.",{reason:d instanceof Error?d.message:String(d)}))},mcpLifecycle:n=>this.writeMcpRuntimeEvent(n,e.id,i)});D=h.close;const w=new tt,u=await h.buildInput(t.params.prompt),v=await this.runtime.sessionStore.readHistory(e.id);A.hydrate(e.id,v.transcript,v.events,u.input);const y=R.length===0?void 0:kt(u.input,R),_=y?.content===null?void 0:y?.content,$=await h.agent.initialize();for(const n of $)(n.type==="mcp.server.status"||n.type==="mcp.tool.catalog.updated")&&await this.writeMcpEvent(n,e.id,i);for await(const n of h.run({input:u.input,userInput:u.userInput,...u.workspaceContext===void 0?{}:{workspaceContext:u.workspaceContext},..._===void 0?{}:{inputContent:_},model:l,sessionId:e.id,stream:!0,signal:a.signal})){(n.type==="mcp.server.status"||n.type==="mcp.tool.catalog.updated")&&await this.writeMcpEvent(n,e.id,i),n.type==="context.compacted"&&await X(this.runtime,h,e.id,n.metrics,i);const d=w.observe(n);for(const x of d)await this.emitProjected(x,e.id,i,I);if(n.type==="session.failed"){const x=ct(n.error);if(x===void 0)throw n.error;const B=rt(x);I.push(B);const W=`${i}:final`;await this.writeEvent("assistant.delta",{turnId:i,sessionId:e.id,segmentId:W,iteration:0,content:B}),await this.writeEvent("assistant.segment.completed",{turnId:i,sessionId:e.id,segmentId:W,iteration:0,phase:"final"});break}}if(I.join("").trim().length===0)throw new f(g.MODEL_PROTOCOL_EMPTY_RESPONSE,"Agent completed without a final text response.",{category:"model",userMessage:"The model completed without a final text response.",retryable:!0});await this.getExecutionWorkspaces().apply(e.id),M=!0,await st(this.runtime.sessionStore,e.id,i,I.join("")),await this.runtime.sessionStore.updateStatus(e.id,"completed"),await this.writeEvent("turn.completed",{turnId:i,sessionId:e.id,content:I.join("")})}catch(r){if(!M)try{const w=await this.getExecutionWorkspaces().apply(e.id);M=!0,w.appliedPaths.length>0&&this.runtime.logger.info("Applied session workspace changes after turn failure.",{sessionId:e.id,turnId:i,appliedPaths:w.appliedPaths})}catch(w){this.runtime.logger.error("Failed to apply session workspace changes after turn failure.",{sessionId:e.id,turnId:i,reason:w instanceof Error?w.message:String(w)})}const h=a.signal.aborted;throw await it(this.runtime.sessionStore,e.id,i,r,h),await this.runtime.sessionStore.updateStatus(e.id,h?"cancelled":"failed"),r}finally{if(this.intentEvents.clear(i),j!==void 0&&clearTimeout(j),D!==void 0)try{await D()}catch(r){this.runtime.logger.warn("Desktop agent cleanup failed.",{reason:r instanceof Error?r.message:String(r)})}await this.getExecutionWorkspaces().markReady(e.id)}}async emitProjected(t,e,o,s){t.type==="assistant.delta"?(s.push(t.content),await this.writeEvent("assistant.delta",{turnId:o,sessionId:e,segmentId:t.segmentId,iteration:t.iteration,content:t.content})):t.type==="assistant.replaced"?(s.splice(0,s.length,t.content),await this.writeEvent("assistant.replaced",{turnId:o,sessionId:e,segmentId:t.segmentId,iteration:t.iteration,content:t.content})):t.type==="assistant.segment.completed"?await this.writeEvent("assistant.segment.completed",{turnId:o,sessionId:e,segmentId:t.segmentId,iteration:t.iteration,phase:t.phase}):t.type==="action.started"?await this.writeEvent("tool.started",{turnId:o,sessionId:e,actionId:t.actionId,toolName:t.toolName,displayName:t.displayName,kind:t.kind,...t.source===void 0?{}:{source:t.source}}):t.type==="action.completed"?await this.writeEvent("tool.completed",{turnId:o,sessionId:e,actionId:t.actionId,toolName:t.toolName,displayName:t.displayName,kind:t.kind,status:t.status,isError:t.isError}):t.type==="context.compacted"&&await this.writeEvent("context.compacted",{turnId:o,sessionId:e}),await et(this.runtime.sessionStore,e,t,{turnId:o})}async writeMcpEvent(t,e,o){const s=K(t,e,o);await this.writeEvent(s.name,s.data)}async writeMcpRuntimeEvent(t,e,o){const s=K(t,e,o);await this.writeEvent(s.name,s.data)}async cancelTurn(t){const e=this.turns.get(t.params.turnId);if(e===void 0)throw new f(g.INVALID_ARGUMENT,"Turn is not active.",{category:"session",userMessage:"The requested turn is not active."});e.controller.abort(),await this.respond(t,{cancelled:!0,turnId:t.params.turnId}),await e.operation.catch(o=>this.runtime.logger.warn("Cancelled Desktop turn cleanup reported an error.",{turnId:t.params.turnId,reason:o instanceof Error?o.message:String(o)}))}async respondApproval(t){if(!this.approvalBroker.respondApproval(t.params.approvalId,t.params.approved))throw new f(g.INVALID_ARGUMENT,"Approval request is no longer active.",{category:"arguments",userMessage:"This approval request is no longer active."});await this.respond(t,{accepted:!0})}async respondTrust(t){if(!this.approvalBroker.respondTrust(t.params.trustRequestId,t.params.trusted))throw new f(g.INVALID_ARGUMENT,"Trust request is no longer active.",{category:"arguments",userMessage:"This trust request is no longer active."});await this.respond(t,{accepted:!0})}async listModels(t){const o=(await T(this.runtime,this.cwd)).config.profile??k.defaultProfileName(),s=await this.runtime.auth.requireCredential(o),i=await new q(N(s.profile,s.apiKey)).listModels();await this.respond(t,{models:i.data})}async authStatus(t){const o=(await this.runtime.configLoader.load(this.cwd,{includeProject:!1})).config.profile??k.defaultProfileName(),s=await this.runtime.credentialStore.get(o);await this.respond(t,{authenticated:s!==void 0,profile:o,...s===void 0?{}:{baseUrl:s.profile.baseUrl,credentialRef:s.profile.credentialRef}})}async listCommands(t){await this.respond(t,mt())}async startCommand(t){const o=pt.get(t.params.actionId)?.desktop?.mutationKey;if(o!==void 0&&(this.turns.size>0||[...this.commands.values()].some(p=>p.mutationKey===o)))throw new f(g.INVALID_ARGUMENT,`Desktop command conflicts with an active ${o} operation.`,{category:"command",userMessage:"Wait for the active operation to finish before changing this resource."});const s=U(),i=new AbortController,a=typeof t.params.options.scope=="string"?t.params.options.scope:void 0;this.logInfo("CLI Desktop command started.",{commandId:s,actionId:t.params.actionId,...a===void 0?{}:{scope:a}});const c=Promise.resolve().then(()=>this.executeCommand(t,s,i)).catch(async p=>{if(i.signal.aborted){this.logWarn("CLI Desktop command cancelled.",{commandId:s,actionId:t.params.actionId}),await this.writeEvent("command.cancelled",{commandId:s,actionId:t.params.actionId});return}this.logError("CLI Desktop command failed.",{commandId:s,actionId:t.params.actionId,code:E(p).code}),await this.writeEvent("command.failed",{commandId:s,actionId:t.params.actionId,error:E(p)})}).finally(()=>this.commands.delete(s));this.commands.set(s,{controller:i,operation:c,...o===void 0?{}:{mutationKey:o}});const m={accepted:!0,commandId:s,actionId:t.params.actionId};await this.respond(t,m)}async executeCommand(t,e,o){await this.writeEvent("command.started",{commandId:e,actionId:t.params.actionId});const s=await ut({runtime:this.runtime,cwd:this.cwd,invocation:t.params,signal:o.signal,output:{write:(i,a)=>this.writeEvent("command.output",{commandId:e,actionId:t.params.actionId,content:i,...a===void 0?{}:{structured:a}})},activity:{started:(i,a)=>this.writeEvent("command.activity.started",{commandId:e,actionId:t.params.actionId,key:i,label:a}),completed:(i,a)=>this.writeEvent("command.activity.completed",{commandId:e,actionId:t.params.actionId,key:i,isError:a})},onActivityError:i=>this.runtime.logger.warn("Desktop command activity event failed.",{commandId:e,reason:i instanceof Error?i.message:String(i)})});await this.writeEvent("command.completed",{commandId:e,actionId:t.params.actionId,exitCode:s,success:s===0}),this.logInfo("CLI Desktop command completed.",{commandId:e,actionId:t.params.actionId,exitCode:s,success:s===0})}logInfo(t,e){this.runtime.logger?.info(t,e)}logWarn(t,e){this.runtime.logger?.warn(t,e)}logError(t,e){this.runtime.logger?.error(t,e)}async cancelCommand(t){const e=this.commands.get(t.params.commandId);if(e===void 0)throw new f(g.INVALID_ARGUMENT,"Command is not active.",{category:"command",userMessage:"The requested command is not active."});e.controller.abort(),await this.respond(t,{accepted:!0,commandId:t.params.commandId})}async requestBrowserHost(t,e){if(this.stopping)throw new Error("The Desktop browser bridge is stopping.");const o=new Promise((s,i)=>{const a={resolve:s,reject:i,...e===void 0?{}:{signal:e}};if(e!==void 0){if(e.aborted){i(new Error("Browser action was cancelled."));return}a.onAbort=()=>{this.browserRequests.delete(t.requestId),this.sendHostCancel(t),i(new Error("Browser action was cancelled."))},e.addEventListener("abort",a.onAbort,{once:!0})}this.browserRequests.set(t.requestId,a)});try{return await this.writer.write(t),await o}finally{const s=this.browserRequests.get(t.requestId);s!==void 0&&(s.onAbort!==void 0&&s.signal?.removeEventListener("abort",s.onAbort),this.browserRequests.delete(t.requestId))}}async requestDesktopHost(t,e){if(this.stopping)throw new Error("The Desktop execution bridge is stopping.");const o=new Promise((s,i)=>{const a={resolve:s,reject:i,...e===void 0?{}:{signal:e}};if(e!==void 0){if(e.aborted){i(new Error("Host execution was cancelled."));return}a.onAbort=()=>{this.hostRequests.delete(t.requestId),this.sendHostCancel(t),i(new Error("Host execution was cancelled."))},e.addEventListener("abort",a.onAbort,{once:!0})}this.hostRequests.set(t.requestId,a)});try{return await this.writer.write(t),await o}finally{const s=this.hostRequests.get(t.requestId);s!==void 0&&(s.onAbort!==void 0&&s.signal?.removeEventListener("abort",s.onAbort),this.hostRequests.delete(t.requestId))}}resolveBrowserRequest(t){const e=this.browserRequests.get(t.requestId);e!==void 0&&(e.onAbort!==void 0&&e.signal?.removeEventListener("abort",e.onAbort),this.browserRequests.delete(t.requestId),e.resolve(t))}resolveDesktopHostRequest(t){const e=this.hostRequests.get(t.requestId);e!==void 0&&(e.onAbort!==void 0&&e.signal?.removeEventListener("abort",e.onAbort),this.hostRequests.delete(t.requestId),e.resolve(t))}async requestComputerHost(t,e){if(this.stopping)throw new Error("The Desktop computer bridge is stopping.");const o=new Promise((s,i)=>{const a={resolve:s,reject:i,...e===void 0?{}:{signal:e}};if(e!==void 0){if(e.aborted){i(new Error("Computer action was cancelled."));return}a.onAbort=()=>{this.computerRequests.delete(t.requestId),this.sendHostCancel(t),i(new Error("Computer action was cancelled."))},e.addEventListener("abort",a.onAbort,{once:!0})}this.computerRequests.set(t.requestId,a)});try{return await this.writer.write(t),await o}finally{const s=this.computerRequests.get(t.requestId);s!==void 0&&(s.onAbort!==void 0&&s.signal?.removeEventListener("abort",s.onAbort),this.computerRequests.delete(t.requestId))}}resolveComputerHostRequest(t){const e=this.computerRequests.get(t.requestId);e!==void 0&&(e.onAbort!==void 0&&e.signal?.removeEventListener("abort",e.onAbort),this.computerRequests.delete(t.requestId),e.resolve(t))}async requestDocumentHost(t,e){if(this.stopping)throw new Error("The Desktop document bridge is stopping.");const o=new Promise((s,i)=>{const a={resolve:s,reject:i,...e===void 0?{}:{signal:e}};if(e!==void 0){if(e.aborted){i(new Error("Document action was cancelled."));return}a.onAbort=()=>{this.documentRequests.delete(t.requestId),this.sendHostCancel(t),i(new Error("Document action was cancelled."))},e.addEventListener("abort",a.onAbort,{once:!0})}this.documentRequests.set(t.requestId,a)});try{return await this.writer.write(t),await o}finally{const s=this.documentRequests.get(t.requestId);s!==void 0&&(s.onAbort!==void 0&&s.signal?.removeEventListener("abort",s.onAbort),this.documentRequests.delete(t.requestId))}}resolveDocumentHostRequest(t){const e=this.documentRequests.get(t.requestId);e!==void 0&&(e.onAbort!==void 0&&e.signal?.removeEventListener("abort",e.onAbort),this.documentRequests.delete(t.requestId),e.resolve(t))}async sendHostCancel(t){this.stopping||await this.writer.write({version:1,type:"host.cancel",requestId:t.requestId,tool:t.tool,sessionId:t.sessionId})}async respond(t,e){await this.writer.write({version:S,id:t.id,type:"response",method:t.method,ok:!0,result:e})}async writeError(t,e,o){await this.writer.write({version:S,id:t,type:"response",method:e,ok:!1,error:o})}async writeEvent(t,e){const o=typeof e.turnId=="string"?e.turnId:void 0,s=o===void 0?void 0:this.turnContexts.get(o),i=s===void 0?{}:{projectRoot:s.projectRoot,executionCwd:s.executionCwd,executionWorkspaceId:s.id,...s.taskId===void 0?{}:{taskId:s.taskId}};await this.writer.write({version:S,type:"event",scope:typeof e.sessionId=="string"?"session":"control",event:t,data:{...i,...e}})}getExecutionWorkspaces(){return this.fallbackExecutionWorkspaces??=this.runtime.executionWorkspaces??new It(this.runtime.paths.globalConfigDir,this.runtime.platform),this.fallbackExecutionWorkspaces}}export{S as DESKTOP_PROTOCOL_VERSION,we as runDesktopAgentCommand};
1
+ import{randomUUID as K}from"node:crypto";import{AuthenticationService as D}from"../auth/authentication-service.js";import{createLotaGateClient as V}from"../../infrastructure/sdk/lotagate-client-factory.js";import{loadExecutionConfig as L}from"../config/execution-config.js";import{prepareCliAgent as ot,warmMcpRuntime as it}from"../agent/cli-agent-execution-service.js";import{createContextManagement as nt}from"../agent/context-compaction.js";import{persistContextCompaction as rt}from"../agent/context-compaction-persistence.js";import{CliAgentSessionStoreRegistry as ct}from"../agent/agent-session-store-registry.js";import{AgentRunTracker as dt}from"../agent/agent-run-tracker.js";import{formatContinuationCheckpoint as pt}from"../agent/continuation-checkpoint.js";import{CliTurnEventProjector as mt}from"../orchestration/cli-turn-event-projector.js";import{persistCliTurnEvent as lt}from"../orchestration/cli-turn-persistence.js";import{createTurnId as ht,recordTurnCompletion as ut,recordTurnFailure as ft,recordTurnStart as wt}from"../session/session-turn-lifecycle.js";import{ProjectSessionAccess as Y}from"../session/project-session-access.js";import{permissionRuleForRequest as gt}from"../security/workspace-permission-policy.js";import{agentLimitNotice as yt,classifyAgentLimit as kt}from"../agent/agent-limit.js";import{CliError as g}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as y}from"../../domain/errors/error-codes.js";import{readLinesBounded as Et}from"./jsonl-protocol.js";import{RESOURCE_LIMITS as _}from"../../domain/runtime/resource-limits.js";import{getDesktopCommandCatalog as bt}from"./desktop-command-catalog.js";import{COMMAND_REGISTRY as $}from"../commands/command-runtime.js";import{executeDesktopCommand as It}from"./desktop-command-executor.js";import{DesktopAttachmentStore as vt}from"./desktop-attachment-store.js";import{SubagentJobRegistry as St}from"../orchestration/cli-subagent-service.js";import{subagentDesktopPayload as xt}from"./desktop-orchestration-events.js";import{DesktopIntentEventWriter as Tt}from"./desktop-intent-event-writer.js";import{resolveModelContextWindow as Ct}from"../model/model-context-window.js";import{ContextUsageService as Rt}from"../agent/context-usage-service.js";import{isCliAgentPreparationMutation as Mt}from"../agent/cli-agent-preparation-cache.js";import{JsonLineWriter as Dt}from"./json-line-writer.js";import{desktopApprovalMode as Pt,sessionResult as Q,toDesktopError as I}from"./desktop-protocol-helpers.js";import{DesktopApprovalBroker as At}from"./desktop-approval-broker.js";import{SessionExecutionWorkspaceService as Nt}from"../workspace/session-execution-workspace.js";import{buildUserMessage as Ot}from"../../infrastructure/clipboard/image-normalizer.js";import{isBrowserHostResponse as Bt,isComputerHostResponse as Lt,isDesktopHostResponse as _t,parseDesktopRequest as jt}from"./desktop-agent-request-parser.js";import{desktopMcpEvent as X}from"./desktop-mcp-events.js";import{DesktopExtensionService as Ht}from"./desktop-extension-service.js";import{DesktopExtensionRequestHandler as Wt}from"./desktop-extension-request-handler.js";import{DesktopHostBridge as Ut}from"./desktop-host-bridge.js";import{normalizeDesktopHostCapabilities as Ft}from"./desktop-host-capabilities.js";import{loadModelCatalog as Z}from"../model/model-catalog-service.js";import{SdkMediaGatewayClient as Gt}from"../../infrastructure/sdk/sdk-media-gateway-client.js";import{artifactIdsData as j,resolveSpeechModel as zt}from"./desktop-agent-helpers.js";import{DESKTOP_PROTOCOL_VERSION as P,DESKTOP_SPEECH_MAX_BYTES as Jt,DESKTOP_SPEECH_SYNTHESIS_TIMEOUT_MS as Kt}from"./desktop-agent-contracts.js";import{createIsolatedGuestPlatform as Vt}from"../../infrastructure/platform/host-platform.js";import{evaluateGatewayRequestBudget as Yt}from"../../domain/runtime/gateway-request-budget.js";import{OperationRegistry as q}from"../lifecycle/operation-registry.js";import{BoundedTextAccumulator as $t}from"../agent/bounded-text-accumulator.js";import{generateDesktopTitle as Qt}from"./desktop-title-generator.js";import{DESKTOP_PROTOCOL_VERSION as Ze}from"./desktop-agent-contracts.js";async function $e(k,t,e,s,o){return new Xt(k,t,s).run(e,o)}class Xt{runtime;cwd;writer;turns=new Map;activeTurnBySession=new Map;subagentJobs=new St;sessionStores=new ct(_.desktopSessionStoreMaxEntries);turnContexts=new Map;attachments=new vt;approvalBroker=new At((t,e)=>this.writeEvent(t,e));commands=new Map;speechRequests=new Map;titleOperations=new q;backgroundOperations=new q;activeRequests=new Set;hostBridge;extensions=new Ht;extensionRequests;intentEvents;executionWorkspaces;browserHostEnabled=!1;computerHostEnabled=!1;desktopHostEnabled=!1;hostCapabilities;stopping=!1;constructor(t,e,s){this.runtime=t,this.cwd=e,this.writer=new Dt(s),this.executionWorkspaces=t.executionWorkspaces??new Nt(t.paths.globalConfigDir,t.platform),this.hostBridge=new Ut(this.writer,()=>this.stopping),this.extensionRequests=new Wt(this.extensions,(o,a)=>this.respond(o,a),this.cwd),this.intentEvents=new Tt({writeEvent:(o,a)=>this.writeEvent(o,a),log:(o,a)=>this.logInfo(o,a)})}async run(t,e){let s=0;const o=()=>{this.stopping=!0,this.backgroundOperations.abort(e?.reason);for(const a of this.turns.values())a.controller.abort(e?.reason);for(const a of this.commands.values())a.controller.abort(e?.reason);for(const a of this.speechRequests.values())a.abort(e?.reason);this.titleOperations.abort(e?.reason),t.destroy()};e?.addEventListener("abort",o,{once:!0});try{for await(const a of Et(t,_.desktopJsonlLineBytes)){if(a.trim().length===0)continue;let r;try{r=JSON.parse(a)}catch(p){s+=1,await this.writeError("unknown","protocol",I(p));continue}if(Bt(r)){this.hostBridge.resolveBrowser(r);continue}if(_t(r)){this.hostBridge.resolveDesktop(r);continue}if(Lt(r)){this.hostBridge.resolveComputer(r);continue}let d;try{d=jt(r)}catch(p){s+=1,await this.writeError("unknown","protocol",I(p));continue}if(this.activeRequests.size>=_.jsonlMaxInFlight&&!Zt(d)?(s+=1,await this.writeError(d.id,d.method,{code:"CLI_PROTOCOL_OVERLOADED",category:"protocol",message:"The CLI Desktop protocol is busy. Retry the request later.",retryable:!0})):this.dispatch(d,()=>{s+=1}),this.stopping)break}}catch(a){s+=1,await this.writeError("unknown","protocol",I(a))}finally{e?.removeEventListener("abort",o),this.backgroundOperations.abort(),this.titleOperations.abort();for(const a of this.turns.values())a.controller.abort();for(const a of this.commands.values())a.controller.abort();for(const a of this.speechRequests.values())a.abort();await Promise.allSettled(this.activeRequests),await Promise.allSettled([...this.turns.values()].map(a=>a.operation)),await Promise.allSettled([...this.commands.values()].map(a=>a.operation)),await this.titleOperations.close(),await this.backgroundOperations.close(),await this.subagentJobs.close(),this.sessionStores.clear(),this.approvalBroker.close(),this.hostBridge.close(),this.attachments.clear(),await this.writer.flush(),this.writer.close()}return s===0?0:1}dispatch(t,e){let s;s=this.handle(t).catch(o=>(this.runtime.logger.error("CLI Desktop request failed.",{method:t.method,requestId:t.id,reason:o instanceof Error?o.message:String(o)}),e(),this.writeError(t.id,t.method,I(o)))).finally(()=>{this.activeRequests.delete(s)}),this.activeRequests.add(s)}async handle(t){switch(t.method){case"initialize":return this.browserHostEnabled=t.params.browserHost===!0,this.computerHostEnabled=t.params.computerHost===!0,this.desktopHostEnabled=t.params.executionBroker===!0,this.hostCapabilities=Ft(t.params.hostCapabilities),this.respond(t,{protocol:"lotagate.desktop",version:P,capabilities:["sessions","streaming","tool-approval","project-trust","models","auth","commands","image-attachments","file-attachments","execution-context","tool-allowlist","approval-reviews","lifecycle-controls",...this.desktopHostEnabled?["execution-broker"]:[],"intent-runtime","host-evidence","conversational-progress","local-memory-commands","extensions","speech-synthesis",...this.browserHostEnabled?["browser-host"]:[],...this.computerHostEnabled?["computer-host"]:[]]});case"session.create":return this.createSession(t);case"title.generate":return this.generateTitle(t);case"session.list":return this.listSessions(t);case"session.resume":return this.resumeSession(t);case"extension.listPublicPlugins":case"extension.resolvePublicPluginSource":case"extension.readPublicPluginContribution":case"extension.readDetail":case"extension.readPluginIcon":return this.extensionRequests.handle(t);case"attachment.begin":return this.attachments.begin({id:t.params.attachmentId,...t.params.sessionId===void 0?{}:{sessionId:t.params.sessionId},name:t.params.name,mimeType:t.params.mimeType,sizeBytes:t.params.sizeBytes,...t.params.storageName===void 0?{}:{storageName:t.params.storageName}}),this.respond(t,{accepted:!0,attachmentId:t.params.attachmentId});case"attachment.chunk":return this.attachments.appendChunk(t.params.attachmentId,t.params.index,t.params.dataBase64),this.respond(t,{accepted:!0,attachmentId:t.params.attachmentId,index:t.params.index});case"attachment.complete":{const e=this.attachments.complete(t.params.attachmentId);if(e.sessionId.length===0)return this.respond(t,{accepted:!0,attachmentId:t.params.attachmentId});const s=await this.runtime.sessionStore.saveAttachment(e.sessionId,e.attachment,e.bytes);return this.attachments.replace(t.params.attachmentId,{...e,attachment:s}),this.respond(t,{accepted:!0,attachmentId:t.params.attachmentId,storagePath:s.storagePath})}case"attachment.delete":{this.attachments.delete(t.params.attachmentId,t.params.sessionId);const e=await this.runtime.sessionStore.deleteAttachment(t.params.sessionId,t.params.attachmentId);return this.respond(t,{accepted:!0,attachmentId:t.params.attachmentId,deleted:e})}case"turn.start":return this.startTurn(t);case"turn.cancel":return this.cancelTurn(t);case"approval.respond":return this.respondApproval(t);case"trust.respond":return this.respondTrust(t);case"model.list":return this.listModels(t);case"auth.status":return this.authStatus(t);case"speech.synthesize":return this.synthesizeSpeech(t);case"command.list":return this.listCommands(t);case"command.execute":return this.startCommand(t);case"command.cancel":return this.cancelCommand(t);case"shutdown":this.stopping=!0,await this.respond(t,{stopping:!0});return}}async createSession(t){const e=await this.runtime.projectTrust.inspect(this.cwd),s=await L(this.runtime,this.cwd),o=s.config.profile??D.defaultProfileName(),a=await this.runtime.sessionStore.create({projectFingerprint:e.fingerprint,cwd:e.canonicalPath,model:t.params.model??s.config.model,profile:o,status:"active",...t.params.name===void 0?{}:{name:t.params.name}}),r=await this.executionWorkspaces.prepare({sessionId:a.id,projectRoot:e.canonicalPath});await this.respond(t,{...Q(a),executionWorkspace:r}),this.startBackgroundMcpWarmup()}async generateTitle(t){const e=await this.titleOperations.start(s=>Qt(this.runtime,this.cwd,t,s));await this.respond(t,{title:e})}async listSessions(t){const e=await this.runtime.projectTrust.inspect(this.cwd);await this.respond(t,{sessions:await this.runtime.sessionStore.list(e.fingerprint)})}async resumeSession(t){const e=await this.runtime.projectTrust.inspect(this.cwd),s=await new Y(this.runtime.sessionStore).require(t.params.sessionId,e.fingerprint),o=await this.executionWorkspaces.prepare({sessionId:s.id,projectRoot:e.canonicalPath});await this.respond(t,{...Q(s),executionWorkspace:o,history:await this.runtime.sessionStore.readHistory(s.id)}),this.startBackgroundMcpWarmup()}async startTurn(t){const{sessionId:e}=t.params;if(this.runtime.logger.info("CLI Desktop turn request received.",{requestId:t.id,sessionId:e,promptLength:t.params.prompt.length,requestedModel:t.params.model}),[...this.turns.values()].some(m=>m.sessionId===e))throw new g(y.INVALID_ARGUMENT,"A turn is already active for this session.",{category:"session",userMessage:"This session already has an active turn."});const s=await this.runtime.projectTrust.inspect(this.cwd);let o=await new Y(this.runtime.sessionStore).require(e,s.fingerprint);t.params.sessionName!==void 0&&t.params.sessionName.trim()!==o.name&&(o=await this.runtime.sessionStore.rename(e,t.params.sessionName));const a=await this.executionWorkspaces.acquireTurn(e);let r=!1;const d=async()=>{r||(r=!0,await a())};let p=!1;try{const m=await this.executionWorkspaces.prepare({sessionId:e,projectRoot:s.canonicalPath}),l=this.attachments.take(t.params.attachmentIds??[],e),f=ht(),E=new AbortController;this.turnContexts.set(f,{...m,...t.params.taskId===void 0?{}:{taskId:t.params.taskId}}),this.activeTurnBySession.set(e,f);const T=this.executeTurn(t,o,s,m,f,E,l,d).catch(async C=>{await this.writeEvent(E.signal.aborted?"turn.cancelled":"turn.failed",{turnId:f,sessionId:e,...E.signal.aborted?{}:{error:I(C)}})}).finally(()=>{this.turns.delete(f),this.turnContexts.delete(f),this.activeTurnBySession.get(e)===f&&this.activeTurnBySession.delete(e),this.sessionStores.prune(this.activeTurnBySession.keys())});this.turns.set(f,{sessionId:e,controller:E,operation:T}),p=!0,await this.respond(t,{accepted:!0,turnId:f,sessionId:e})}finally{p||await d()}}async executeTurn(t,e,s,o,a,r,d,p){try{await this.executeTurnBody(t,e,s,o,a,r,d)}finally{await p()}}async executeTurnBody(t,e,s,o,a,r,d){const p=await L(this.runtime,this.cwd);if(!await this.runtime.projectTrust.isTrusted(s)){const n=K();if(await this.writeEvent("trust.requested",{trustRequestId:n,sessionId:e.id,path:s.canonicalPath}),!await this.approvalBroker.waitForTrust(n,r.signal))throw new g(y.PROJECT_TRUST_REQUIRED,"Project trust was not granted.",{category:"project",userMessage:"Trust this project in the Desktop application before running tools."});await this.runtime.projectTrust.grant(s),this.runtime.agentPreparation?.clear(s.canonicalPath),await this.runtime.workspaceSettings.ensureInitialized(s.canonicalPath)}const l=t.params.model??e.model??p.config.model;if(l==null)throw new g(y.MODEL_NOT_FOUND,"No model is selected.",{category:"model",userMessage:"Select a model before starting a turn."});const f=t.params.reasoningEffort??p.config.effort;this.runtime.logger.info("CLI Desktop turn model resolved.",{sessionId:e.id,turnId:a,requestedModel:t.params.model,sessionModel:e.model,resolvedModel:l});const E=e.profile??p.config.profile??D.defaultProfileName(),T=await this.runtime.auth.requireCredential(E),C=V(T.profile,T.apiKey),H=await Ct(this.runtime,l,E),A=new dt,N=this.sessionStores.getOrCreate(e.id,this.activeTurnBySession.keys()),R=new Set,tt=new Rt(this.runtime,s.canonicalPath),W=async()=>{try{const n=await tt.buildForProject({sessionId:e.id,model:l,profileName:E,pluginNames:[],pendingAttachments:0,agentSessionStore:N});await this.writeEvent("usage.updated",{turnId:a,sessionId:e.id,model:l,...n.contextWindow===void 0?{}:{contextWindow:n.contextWindow},usage:{promptTokens:n.usedTokens,estimated:!0}})}catch(n){this.runtime.logger.warn("Desktop context usage update failed.",{sessionId:e.id,turnId:a,reason:n instanceof Error?n.message:String(n)})}},S=new $t,x=[];for(const n of d){const h=n.attachment.storagePath===void 0?await this.runtime.sessionStore.saveAttachment(e.id,n.attachment,n.bytes):n.attachment;x.push({...n,attachment:h})}await wt(this.runtime.sessionStore,e.id,a,t.params.prompt,x.map(n=>n.attachment.id)),await this.runtime.sessionStore.updateStatus(e.id,"active"),await this.writeEvent("turn.started",{turnId:a,sessionId:e.id,model:l});const et={onSubagentLifecycle:n=>this.writeEvent(`subagent.${n.type}`,xt(n,a),{delivery:"best-effort"})},at={start:n=>{if(n.source!=="shell"&&n.source!=="computer"&&n.source!=="custom"&&n.toolName!=="filesystem.read"&&n.toolName!=="filesystem.write"&&n.toolName!=="filesystem.exists")return;const h={turnId:a,sessionId:e.id,actionId:n.key,toolName:n.toolName,displayName:n.label,...n.source==="shell"?{command:n.label}:{},kind:n.source??"tool",source:n.source},w=(u,v)=>{this.writeEvent(u,v,{delivery:"best-effort"}).catch(b=>this.runtime.logger.warn("Desktop tool activity event failed.",{event:u,reason:b instanceof Error?b.message:String(b)}))};return w("tool.activity.started",{...h,status:"running"}),{complete:(u,v)=>w("tool.activity.completed",{...h,...v??{},status:u?"failed":"completed",isError:u})}}};let O,B=!1;const U=setTimeout(()=>r.abort(),t.params.execution.timeoutMs);try{const n=t.params.execution,h=await ot({runtime:this.runtime,projectRoot:s.canonicalPath,executionCwd:o.executionCwd,executionWorkspaceId:o.id,model:l,client:C,reasoningEffort:f,profile:"interactive-trusted",approvalMode:Pt(n.permissionPolicy),...n.allowedTools===void 0?{}:{allowedTools:n.allowedTools},...t.params.skills===void 0?{}:{selectedSkills:t.params.skills},browserAccess:n.browserAccess,subagentLifecycle:et,subagentJobs:this.subagentJobs,...this.browserHostEnabled?{browserHost:(i,c)=>this.hostBridge.requestBrowser(i,c)}:{},...this.desktopHostEnabled?{desktopHost:((i,c)=>this.hostBridge.requestDesktop(i,c))}:{},...this.computerHostEnabled?{computerHost:((i,c)=>this.hostBridge.requestComputer(i,c))}:{},onArtifacts:i=>{for(const c of i)R.add(c.id)},...this.hostCapabilities===void 0?{}:{hostCapabilities:this.hostCapabilities},executionBoundary:n.isolation,executionPlatform:n.isolation==="sandbox"?Vt():this.runtime.platform,browserExecution:n.browserExecution,hostFallback:n.hostFallback,...this.browserHostEnabled||this.desktopHostEnabled?{onExecutionFallbackApproval:(i,c)=>this.approvalBroker.waitForApproval(i,e.id,a,r.signal,"host",c)}:{},toolActivity:at,onIntentLifecycle:i=>this.intentEvents.write(i,e.id,a),contextManagement:nt({client:C,model:l,...H===void 0?{}:{contextWindow:H},onCompactionStart:()=>this.writeEvent("context.compacting",{turnId:a,sessionId:e.id}),onSummaryFailure:i=>this.runtime.logger.warn("Context summarization failed; using fallback summary.",{reason:i instanceof Error?i.message:String(i)}),continuationContext:()=>pt({snapshot:A.snapshot()})}),agentSessionStore:N,prompt:(i,c)=>this.approvalBroker.waitForApproval(i,e.id,a,c??r.signal,n.isolation),rememberApproval:i=>this.runtime.workspaceSettings.rememberAllow(s.canonicalPath,gt(i.toolName,i.input)),audit:async i=>{const c={toolName:i.toolName,stage:i.stage,sessionId:i.sessionId,runId:i.runId,decision:i.decision,reason:i.reason,...i.source===void 0?{}:{source:i.source},...i.executorId===void 0?{}:{executorId:i.executorId},...i.ruleId===void 0?{}:{ruleId:i.ruleId},...i.skillName===void 0?{}:{skillName:i.skillName},...i.riskCategory===void 0?{}:{riskCategory:i.riskCategory}};this.runtime.logger.info("Tool authorization decision.",c),await this.runtime.sessionStore.appendEvent({type:"tool.approval",timestamp:new Date().toISOString(),sessionId:e.id,turnId:a,data:c})},onModelComplete:i=>{A.observeModel(i),i.usage!==void 0&&this.writeEvent("usage.updated",{turnId:a,sessionId:e.id,model:l,usage:i.usage},{delivery:"best-effort"}).catch(c=>this.runtime.logger.warn("Desktop usage event failed.",{reason:c instanceof Error?c.message:String(c)}))},onWrite:i=>{this.writeEvent("file.changed",{turnId:a,sessionId:e.id,change:i},{delivery:"best-effort"}).catch(c=>this.runtime.logger.warn("Desktop file event failed.",{reason:c instanceof Error?c.message:String(c)}))},mcpLifecycle:i=>this.writeMcpRuntimeEvent(i,e.id,a)});O=h.close;const w=new mt,u=await h.buildInput(t.params.prompt),v=await this.runtime.sessionStore.readHistory(e.id);N.hydrate(e.id,v.transcript,v.events,u.input);const b=Yt(u.input,x.map(({attachment:i,bytes:c})=>({byteLength:c.byteLength,mimeType:i.mimeType,name:i.name})));if(!b.isWithinLimit)throw new g(y.ATTACHMENT_TOO_LARGE,"The prompt and attachments exceed the Gateway JSON body limit.",{category:"attachment",userMessage:`The prompt and attachments exceed the ${b.limitBytes/1e6} MB decimal Gateway JSON limit. Remove an attachment or shorten the prompt and retry.`,details:{kind:"gateway-json-body",maxBytes:b.limitBytes,projectedBytes:b.projectedBytes}});const F=x.length===0?void 0:Ot(u.input,x),G=F?.content===null?void 0:F?.content,st=await h.agent.initialize();for(const i of st)(i.type==="mcp.server.status"||i.type==="mcp.tool.catalog.updated")&&await this.writeMcpEvent(i,e.id,a);for await(const i of h.run({input:u.input,userInput:u.userInput,...u.workspaceContext===void 0?{}:{workspaceContext:u.workspaceContext},...G===void 0?{}:{inputContent:G},model:l,sessionId:e.id,stream:!0,signal:r.signal,metadata:{taskId:t.params.taskId,turnId:a}})){A.observe(i),(i.type==="mcp.server.status"||i.type==="mcp.tool.catalog.updated")&&await this.writeMcpEvent(i,e.id,a),i.type==="context.compacted"&&(await rt(this.runtime,h,e.id,i.metrics,a),await W());const c=w.observe(i);for(const M of c)await this.emitProjected(M,e.id,a,S,R);if(i.type==="session.failed"){const M=kt(i.error);if(M===void 0)throw i.error;const z=yt(M);S.append(z);const J=`${a}:final`;await this.writeEvent("assistant.delta",{turnId:a,sessionId:e.id,segmentId:J,iteration:0,content:z}),await this.writeEvent("assistant.segment.completed",{turnId:a,sessionId:e.id,segmentId:J,iteration:0,phase:"final",...j(R)});break}}if(S.toString().trim().length===0)throw new g(y.MODEL_PROTOCOL_EMPTY_RESPONSE,"Agent completed without a final text response.",{category:"model",userMessage:"The model completed without a final text response.",retryable:!0});await this.executionWorkspaces.apply(e.id),B=!0,await ut(this.runtime.sessionStore,e.id,a,S.toString()),await this.runtime.sessionStore.updateStatus(e.id,"completed"),await W(),await this.writeEvent("turn.completed",{turnId:a,sessionId:e.id,content:S.toString(),...j(R)})}catch(n){if(!B)try{const w=await this.executionWorkspaces.apply(e.id);B=!0,w.appliedPaths.length>0&&this.runtime.logger.info("Applied session workspace changes after turn failure.",{sessionId:e.id,turnId:a,appliedPaths:w.appliedPaths})}catch(w){this.runtime.logger.error("Failed to apply session workspace changes after turn failure.",{sessionId:e.id,turnId:a,reason:w instanceof Error?w.message:String(w)})}const h=r.signal.aborted;throw await ft(this.runtime.sessionStore,e.id,a,n,h),await this.runtime.sessionStore.updateStatus(e.id,h?"cancelled":"failed"),n}finally{if(this.intentEvents.clear(a),U!==void 0&&clearTimeout(U),O!==void 0)try{await O()}catch(n){this.runtime.logger.warn("Desktop agent cleanup failed.",{reason:n instanceof Error?n.message:String(n)})}await this.executionWorkspaces.markReady(e.id)}}async emitProjected(t,e,s,o,a){t.type==="assistant.delta"?(o.append(t.content),await this.writeEvent("assistant.delta",{turnId:s,sessionId:e,segmentId:t.segmentId,iteration:t.iteration,content:t.content})):t.type==="assistant.replaced"?(o.replace(t.content),await this.writeEvent("assistant.replaced",{turnId:s,sessionId:e,segmentId:t.segmentId,iteration:t.iteration,content:t.content})):t.type==="assistant.segment.completed"?await this.writeEvent("assistant.segment.completed",{turnId:s,sessionId:e,segmentId:t.segmentId,iteration:t.iteration,phase:t.phase,...t.phase==="final"?j(a):{}}):t.type==="action.started"?await this.writeEvent("tool.started",{turnId:s,sessionId:e,actionId:t.actionId,toolName:t.toolName,displayName:t.displayName,kind:t.kind,...t.source===void 0?{}:{source:t.source}}):t.type==="action.completed"?await this.writeEvent("tool.completed",{turnId:s,sessionId:e,actionId:t.actionId,toolName:t.toolName,displayName:t.displayName,kind:t.kind,status:t.status,isError:t.isError}):t.type==="context.compacted"&&await this.writeEvent("context.compacted",{turnId:s,sessionId:e}),await lt(this.runtime.sessionStore,e,t,{turnId:s})}async writeMcpEvent(t,e,s){const o=X(t,e,s);await this.writeEvent(o.name,o.data)}async writeMcpRuntimeEvent(t,e,s){const o=X(t,e,s);await this.writeEvent(o.name,o.data)}async cancelTurn(t){const e=this.turns.get(t.params.turnId);if(e===void 0)throw new g(y.INVALID_ARGUMENT,"Turn is not active.",{category:"session",userMessage:"The requested turn is not active."});e.controller.abort(),await this.respond(t,{cancelled:!0,turnId:t.params.turnId}),await e.operation.catch(s=>this.runtime.logger.warn("Cancelled Desktop turn cleanup reported an error.",{turnId:t.params.turnId,reason:s instanceof Error?s.message:String(s)}))}async respondApproval(t){const e=t.params.decision==="redirect"?{decision:"redirect",message:t.params.message}:{decision:t.params.decision};if(!this.approvalBroker.respondApproval(t.params.approvalId,e))throw new g(y.INVALID_ARGUMENT,"Approval request is no longer active.",{category:"arguments",userMessage:"This approval request is no longer active."});await this.respond(t,{accepted:!0})}async respondTrust(t){if(!this.approvalBroker.respondTrust(t.params.trustRequestId,t.params.trusted))throw new g(y.INVALID_ARGUMENT,"Trust request is no longer active.",{category:"arguments",userMessage:"This trust request is no longer active."});await this.respond(t,{accepted:!0})}async listModels(t){const e=await Z(this.runtime,this.cwd);await this.respond(t,{models:e.data})}async authStatus(t){const s=(await this.runtime.configLoader.load(this.cwd,{includeProject:!1})).config.profile??D.defaultProfileName(),o=await this.runtime.credentialStore.get(s);await this.respond(t,{authenticated:o!==void 0,profile:s,...o===void 0?{}:{baseUrl:o.profile.baseUrl,credentialRef:o.profile.credentialRef}})}async synthesizeSpeech(t){const s=(await L(this.runtime,this.cwd)).config.profile??D.defaultProfileName(),o=await this.runtime.auth.requireCredential(s),a=await Z(this.runtime,this.cwd),r=zt(t.params.model,a.data),d=new AbortController;this.speechRequests.set(t.id,d);const p=setTimeout(()=>d.abort(new Error("Desktop speech synthesis timed out.")),Kt);try{const m=await new Gt(V(o.profile,o.apiKey)).createSpeech({model:r,input:t.params.input,voice:t.params.voice,responseFormat:t.params.responseFormat??"mp3"},{signal:d.signal});if(m.bytes.byteLength===0||m.bytes.byteLength>Jt)throw new g(y.MEDIA_RESPONSE_TOO_LARGE,"Generated speech exceeds the Desktop playback limit.",{category:"media",userMessage:"The generated speech is too large to play in the Desktop app."});await this.respond(t,{contentType:m.contentType??"audio/mpeg",bytesBase64:Buffer.from(m.bytes).toString("base64")})}finally{clearTimeout(p),this.speechRequests.get(t.id)===d&&this.speechRequests.delete(t.id)}}async listCommands(t){await this.respond(t,bt())}async startCommand(t){const s=$.get(t.params.actionId)?.desktop?.mutationKey;if(s!==void 0&&(this.turns.size>0||[...this.commands.values()].some(m=>m.mutationKey===s)))throw new g(y.INVALID_ARGUMENT,`Desktop command conflicts with an active ${s} operation.`,{category:"command",userMessage:"Wait for the active operation to finish before changing this resource."});const o=K(),a=new AbortController,r=typeof t.params.options.scope=="string"?t.params.options.scope:void 0;this.logInfo("CLI Desktop command started.",{commandId:o,actionId:t.params.actionId,...r===void 0?{}:{scope:r}});const d=Promise.resolve().then(()=>this.executeCommand(t,o,a)).catch(async m=>{if(a.signal.aborted){this.logWarn("CLI Desktop command cancelled.",{commandId:o,actionId:t.params.actionId}),await this.writeEvent("command.cancelled",{commandId:o,actionId:t.params.actionId});return}this.logError("CLI Desktop command failed.",{commandId:o,actionId:t.params.actionId,code:I(m).code}),await this.writeEvent("command.failed",{commandId:o,actionId:t.params.actionId,error:I(m)})}).finally(()=>this.commands.delete(o));this.commands.set(o,{controller:a,operation:d,...s===void 0?{}:{mutationKey:s}});const p={accepted:!0,commandId:o,actionId:t.params.actionId};await this.respond(t,p)}async executeCommand(t,e,s){await this.writeEvent("command.started",{commandId:e,actionId:t.params.actionId});const o=await It({runtime:this.runtime,cwd:this.cwd,invocation:t.params,signal:s.signal,output:{write:(a,r)=>this.writeEvent("command.output",{commandId:e,actionId:t.params.actionId,content:a,...r===void 0?{}:{structured:r}})},activity:{started:(a,r)=>this.writeEvent("command.activity.started",{commandId:e,actionId:t.params.actionId,key:a,label:r}),completed:(a,r)=>this.writeEvent("command.activity.completed",{commandId:e,actionId:t.params.actionId,key:a,isError:r})},onActivityError:a=>this.runtime.logger.warn("Desktop command activity event failed.",{commandId:e,reason:a instanceof Error?a.message:String(a)})});if(o===0&&t.params.actionId==="session.delete"){const a=t.params.positionals[1];a!==void 0&&(await this.subagentJobs.closeSession(a),this.sessionStores.delete(a))}o===0&&Mt(t.params.actionId,$.get(t.params.actionId)?.desktop?.mutationKey)&&this.runtime.agentPreparation?.clear(),await this.writeEvent("command.completed",{commandId:e,actionId:t.params.actionId,exitCode:o,success:o===0}),this.logInfo("CLI Desktop command completed.",{commandId:e,actionId:t.params.actionId,exitCode:o,success:o===0})}logInfo(t,e){this.runtime.logger?.info(t,e)}startBackgroundMcpWarmup(){this.backgroundOperations.start(t=>it(this.runtime,this.cwd,t)).catch(t=>this.runtime.logger.warn("MCP session warm-up failed.",{reason:t instanceof Error?t.message:String(t)}))}logWarn(t,e){this.runtime.logger?.warn(t,e)}logError(t,e){this.runtime.logger?.error(t,e)}async cancelCommand(t){const e=this.commands.get(t.params.commandId);if(e===void 0)throw new g(y.INVALID_ARGUMENT,"Command is not active.",{category:"command",userMessage:"The requested command is not active."});e.controller.abort(),await this.respond(t,{accepted:!0,commandId:t.params.commandId})}async respond(t,e){await this.writer.write({version:P,id:t.id,type:"response",method:t.method,ok:!0,result:e})}async writeError(t,e,s){await this.writer.write({version:P,id:t,type:"response",method:e,ok:!1,error:s})}async writeEvent(t,e,s={}){const o=typeof e.turnId=="string"?e.turnId:void 0,a=o===void 0?void 0:this.turnContexts.get(o),r=a===void 0?{}:{projectRoot:a.projectRoot,executionCwd:a.executionCwd,executionWorkspaceId:a.id,...a.taskId===void 0?{}:{taskId:a.taskId}};await this.writer.write({version:P,type:"event",scope:typeof e.sessionId=="string"?"session":"control",event:t,data:{...r,...e}},s)}}function Zt(k){return k.method==="turn.cancel"||k.method==="command.cancel"||k.method==="approval.respond"||k.method==="trust.respond"||k.method==="shutdown"}export{Ze as DESKTOP_PROTOCOL_VERSION,$e as runDesktopAgentCommand};
@@ -0,0 +1,34 @@
1
+ import type { DesktopHostWireMessage } from './desktop-host-bridge.js';
2
+ export declare const DESKTOP_PROTOCOL_VERSION: 1;
3
+ export declare const TITLE_GENERATION_TIMEOUT_MS = 25000;
4
+ export declare const DESKTOP_SPEECH_SYNTHESIS_TIMEOUT_MS = 60000;
5
+ export declare const DESKTOP_SPEECH_MAX_BYTES = 2500000;
6
+ export type DesktopResponse = {
7
+ version: 1;
8
+ id: string;
9
+ type: 'response';
10
+ method: string;
11
+ ok: true;
12
+ result?: unknown;
13
+ } | {
14
+ version: 1;
15
+ id: string;
16
+ type: 'response';
17
+ method: string;
18
+ ok: false;
19
+ error: DesktopError;
20
+ };
21
+ export type DesktopEvent = {
22
+ version: 1;
23
+ type: 'event';
24
+ scope: 'session' | 'control';
25
+ event: string;
26
+ data: Record<string, unknown>;
27
+ };
28
+ export type DesktopError = {
29
+ code: string;
30
+ category: string;
31
+ message: string;
32
+ retryable: boolean;
33
+ };
34
+ export type DesktopWireMessage = DesktopResponse | DesktopEvent | DesktopHostWireMessage;
@@ -0,0 +1 @@
1
+ const _=1,E=25e3,T=6e4,S=25e5;export{_ as DESKTOP_PROTOCOL_VERSION,S as DESKTOP_SPEECH_MAX_BYTES,T as DESKTOP_SPEECH_SYNTHESIS_TIMEOUT_MS,E as TITLE_GENERATION_TIMEOUT_MS};
@@ -0,0 +1,5 @@
1
+ export declare function artifactIdsData(artifactIds: ReadonlySet<string>): Record<string, unknown>;
2
+ export declare function resolveSpeechModel(requested: string | undefined, models: readonly {
3
+ id: string;
4
+ [key: string]: unknown;
5
+ }[]): string;
@@ -0,0 +1 @@
1
+ import{CliError as i}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as a}from"../../domain/errors/error-codes.js";function d(e){return e.size===0?{}:{artifactIds:[...e]}}function s(e,n){if(e!==void 0){const o=n.find(r=>r.id===e);if(o===void 0)throw new i(a.MODEL_NOT_FOUND,`Speech model is not available: ${e}`,{category:"model",userMessage:`Speech model is not available: ${e}.`});if(o.model_category!==void 0&&o.model_category!=="speech")throw new i(a.MODEL_NOT_FOUND,`Model is not a speech model: ${e}`,{category:"model",userMessage:`Model ${e} cannot synthesize speech.`});return e}const l=n.find(o=>o.model_category==="speech")?.id;if(l!==void 0)return l;throw new i(a.MODEL_NOT_FOUND,"No speech model is available.",{category:"model",userMessage:"No speech model is available for Live Chat."})}export{d as artifactIdsData,s as resolveSpeechModel};