@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
@@ -3,7 +3,14 @@ import { type DesktopExecutionPolicy } from './desktop-execution-policy.js';
3
3
  import type { BrowserHostResponse } from './browser-host-tool-executor.js';
4
4
  import type { DesktopHostExecutionResponse } from './desktop-host-tool-executor.js';
5
5
  import type { ComputerHostResponse } from './computer-host-tool-executor.js';
6
- import type { DocumentHostResponse } from './document-host-tool-executor.js';
6
+ type DesktopApprovalRequestDecision = {
7
+ approvalId: string;
8
+ decision: 'allow' | 'deny';
9
+ } | {
10
+ approvalId: string;
11
+ decision: 'redirect';
12
+ message: string;
13
+ };
7
14
  export type DesktopRequest = {
8
15
  version: 1;
9
16
  id: string;
@@ -82,15 +89,27 @@ export type DesktopRequest = {
82
89
  prompt: string;
83
90
  model?: string;
84
91
  };
92
+ } | {
93
+ version: 1;
94
+ id: string;
95
+ method: 'speech.synthesize';
96
+ params: {
97
+ input: string;
98
+ voice: string;
99
+ model?: string;
100
+ responseFormat?: 'mp3' | 'opus' | 'aac' | 'flac' | 'wav' | 'pcm';
101
+ };
85
102
  } | {
86
103
  version: 1;
87
104
  id: string;
88
105
  method: 'attachment.begin';
89
106
  params: {
90
107
  attachmentId: string;
108
+ sessionId?: string;
91
109
  name: string;
92
110
  mimeType: string;
93
111
  sizeBytes: number;
112
+ storageName?: string;
94
113
  };
95
114
  } | {
96
115
  version: 1;
@@ -108,6 +127,14 @@ export type DesktopRequest = {
108
127
  params: {
109
128
  attachmentId: string;
110
129
  };
130
+ } | {
131
+ version: 1;
132
+ id: string;
133
+ method: 'attachment.delete';
134
+ params: {
135
+ sessionId: string;
136
+ attachmentId: string;
137
+ };
111
138
  } | {
112
139
  version: 1;
113
140
  id: string;
@@ -119,6 +146,7 @@ export type DesktopRequest = {
119
146
  reasoningEffort?: string;
120
147
  runId?: string;
121
148
  taskId?: string;
149
+ sessionName?: string;
122
150
  attachmentIds?: string[];
123
151
  skills?: string[];
124
152
  execution: DesktopExecutionPolicy;
@@ -134,10 +162,7 @@ export type DesktopRequest = {
134
162
  version: 1;
135
163
  id: string;
136
164
  method: 'approval.respond';
137
- params: {
138
- approvalId: string;
139
- approved: boolean;
140
- };
165
+ params: DesktopApprovalRequestDecision;
141
166
  } | {
142
167
  version: 1;
143
168
  id: string;
@@ -183,4 +208,4 @@ export declare function parseDesktopRequest(value: unknown): DesktopRequest;
183
208
  export declare function isBrowserHostResponse(value: unknown): value is BrowserHostResponse;
184
209
  export declare function isDesktopHostResponse(value: unknown): value is DesktopHostExecutionResponse;
185
210
  export declare function isComputerHostResponse(value: unknown): value is ComputerHostResponse;
186
- export declare function isDocumentHostResponse(value: unknown): value is DocumentHostResponse;
211
+ export {};
@@ -1 +1 @@
1
- import{parseDesktopExecutionPolicy as y}from"./desktop-execution-policy.js";import{RESOURCE_LIMITS as s}from"../../domain/runtime/resource-limits.js";function L(e){if(!i(e)||e.version!==1||!u(e.id)||!i(e.params)||typeof e.method!="string")throw o("Invalid Desktop protocol request.");const t=e.id,n=e.method,r=e.params;if(n==="initialize"||n==="session.list"||n==="model.list"||n==="auth.status"||n==="command.list"||n==="shutdown")return{version:1,id:t,method:n,params:r};if(n==="session.create")return{version:1,id:t,method:n,params:{...d(r,"model"),...d(r,"name")}};if(n==="session.resume")return{version:1,id:t,method:n,params:{sessionId:a(r,"sessionId")}};if(n==="extension.listPublicPlugins")return{version:1,id:t,method:n,params:{root:l(r,"root")}};if(n==="extension.resolvePublicPluginSource")return{version:1,id:t,method:n,params:{root:l(r,"root"),name:m(r,"name","public plugin")}};if(n==="extension.readPublicPluginContribution")return{version:1,id:t,method:n,params:{root:l(r,"root"),pluginName:m(r,"pluginName","plugin"),kind:v(r),sourceName:m(r,"sourceName","extension")}};if(n==="extension.readDetail")return{version:1,id:t,method:n,params:B(r)};if(n==="extension.readPluginIcon")return{version:1,id:t,method:n,params:{name:m(r,"name","plugin"),scope:x(r,"scope")}};if(n==="title.generate")return{version:1,id:t,method:n,params:{prompt:I(r),...d(r,"model")}};if(n==="attachment.begin")return{version:1,id:t,method:n,params:{attachmentId:a(r,"attachmentId"),name:q(r),mimeType:A(r),sizeBytes:z(r)}};if(n==="attachment.chunk")return{version:1,id:t,method:n,params:{attachmentId:a(r,"attachmentId"),index:P(r),dataBase64:j(r)}};if(n==="attachment.complete")return{version:1,id:t,method:n,params:{attachmentId:a(r,"attachmentId")}};if(n==="turn.start")return{version:1,id:t,method:n,params:{sessionId:a(r,"sessionId"),prompt:I(r),...d(r,"model"),...d(r,"reasoningEffort"),...d(r,"runId"),...d(r,"taskId"),...S(r),...$(r),execution:N(r)}};if(n==="turn.cancel")return{version:1,id:t,method:n,params:{turnId:a(r,"turnId")}};if(n==="approval.respond")return{version:1,id:t,method:n,params:{approvalId:a(r,"approvalId"),approved:g(r,"approved")}};if(n==="trust.respond")return{version:1,id:t,method:n,params:{trustRequestId:a(r,"trustRequestId"),trusted:g(r,"trusted")}};if(n==="command.execute")return{version:1,id:t,method:n,params:w(r)};if(n==="command.cancel")return{version:1,id:t,method:n,params:{commandId:a(r,"commandId")}};throw o("Unsupported Desktop protocol method.")}function R(e){return!i(e)||e.version!==1||e.type!=="host.response"||e.tool!=="browser"||!u(e.requestId)||typeof e.ok!="boolean"?!1:e.error===void 0||i(e.error)}function C(e){return!i(e)||e.version!==1||e.type!=="host.response"||!["filesystem","shell","git","artifact"].includes(String(e.tool))||!u(e.requestId)||typeof e.ok!="boolean"?!1:e.error===void 0||i(e.error)}function K(e){return!i(e)||e.version!==1||e.type!=="host.response"||e.tool!=="computer"||!u(e.requestId)||typeof e.ok!="boolean"?!1:e.error===void 0||i(e.error)}function M(e){return!i(e)||e.version!==1||e.type!=="host.response"||e.tool!=="document"||!u(e.requestId)||typeof e.ok!="boolean"?!1:e.error===void 0||i(e.error)}function w(e){const t=a(e,"actionId"),n=e.positionals;if(!Array.isArray(n)||n.some(c=>typeof c!="string"||Buffer.byteLength(c,"utf8")>s.jsonlPromptBytes))throw o("Invalid command positionals.");const r=e.options;if(!i(r)||Object.entries(r).some(([c,p])=>!u(c)||typeof p!="string"&&typeof p!="boolean"||typeof p=="string"&&Buffer.byteLength(p,"utf8")>s.jsonlPromptBytes))throw o("Invalid command options.");const f=e.secrets;if(f===void 0)return{actionId:t,positionals:n,options:r};if(t!=="auth.login.direct"||!i(f)||Object.keys(f).some(c=>c!=="apiKey")||typeof f.apiKey!="string"||f.apiKey.length===0||Buffer.byteLength(f.apiKey,"utf8")>s.jsonlPromptBytes)throw o("Invalid command secrets.");return{actionId:t,positionals:n,options:r,secrets:{apiKey:f.apiKey}}}function a(e,t){const n=e[t];if(!u(n))throw o(`Invalid ${t}.`);return n}function l(e,t){const n=e[t];if(typeof n!="string"||n.trim().length===0||n.includes("\0")||Buffer.byteLength(n,"utf8")>s.jsonlPathBytes)throw o(`Invalid ${t}.`);return n}function m(e,t,n){const r=e[t];if(typeof r!="string"||!/^[a-z0-9][a-z0-9-]{0,63}$/u.test(r))throw o(`Invalid ${n} name.`);return r}function b(e,t){const n=e[t];if(typeof n!="string"||n.length===0||n.length>256||n.includes("\0")||!/^[a-z0-9][a-z0-9:_-]*$/u.test(n))throw o("Invalid extension name.");return n}function v(e){const t=e.kind;if(t!=="skill"&&t!=="mcp"&&t!=="hook")throw o("Invalid extension kind.");return t}function x(e,t){const n=e[t];if(n!=="user"&&n!=="project")throw o(`Invalid ${t}.`);return n}function B(e){const t=e.kind;if(t!=="hook"&&t!=="skill"&&t!=="plugin"&&t!=="mcp")throw o("Invalid extension kind.");const n=e.scope;if(n!==void 0&&n!=="user"&&n!=="project"&&n!=="plugin"&&n!=="builtin")throw o("Invalid extension scope.");const r=b(e,"name");return{kind:t,name:r,...n===void 0?{}:{scope:n},...h(e,"pluginName"),...k(e,"pluginScope"),...h(e,"sourceName")}}function h(e,t){const n=e[t];if(n===void 0)return{};if(typeof n!="string"||!/^[a-z0-9][a-z0-9-]{0,63}$/u.test(n))throw o(`Invalid ${t}.`);return{[t]:n}}function k(e,t){const n=e[t];if(n===void 0)return{};if(n!=="user"&&n!=="project")throw o(`Invalid ${t}.`);return{[t]:n}}function I(e){const t=e.prompt;if(typeof t!="string"||t.trim().length===0||Buffer.byteLength(t,"utf8")>s.jsonlPromptBytes)throw o("Invalid prompt.");return t}function g(e,t){if(typeof e[t]!="boolean")throw o(`Invalid ${t}.`);return e[t]}function d(e,t){const n=e[t];if(n===void 0)return{};if(typeof n!="string"||n.length===0||Buffer.byteLength(n,"utf8")>s.jsonlIdBytes)throw o(`Invalid ${t}.`);return{[t]:n}}function q(e){const t=e.name;if(typeof t!="string"||t.length===0||t.length>200||t.includes("\0"))throw o("Invalid attachment name.");return t}function A(e){const t=e.mimeType;if(typeof t!="string"||!/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*$/u.test(t)||Buffer.byteLength(t,"utf8")>s.jsonlIdBytes)throw o("Invalid attachment MIME type.");return t}function z(e){const t=e.sizeBytes;if(typeof t!="number"||!Number.isSafeInteger(t)||t<=0||t>s.maxAttachmentBytes)throw o("Invalid attachment size.");return t}function P(e){const t=e.index;if(typeof t!="number"||!Number.isSafeInteger(t)||t<0)throw o("Invalid attachment chunk index.");return t}function j(e){const t=e.dataBase64;if(typeof t!="string"||t.length===0||Buffer.byteLength(t,"utf8")>Math.ceil(s.desktopAttachmentChunkBytes/3)*4+4)throw o("Invalid attachment chunk.");return t}function S(e){const t=e.attachmentIds;if(t===void 0)return{};if(!Array.isArray(t)||t.length>s.pendingAttachments||t.some(n=>!u(n))||new Set(t).size!==t.length)throw o("Invalid attachment ids.");return{attachmentIds:t}}function $(e){const t=e.skills;if(t===void 0)return{};if(!Array.isArray(t)||t.length>32||t.some(n=>!u(n))||new Set(t).size!==t.length)throw o("Invalid skills.");return{skills:t}}function N(e){return y(e.execution)}function u(e){return typeof e=="string"&&e.length>0&&Buffer.byteLength(e,"utf8")<=s.jsonlIdBytes}function i(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function o(e){return new Error(e)}export{R as isBrowserHostResponse,K as isComputerHostResponse,C as isDesktopHostResponse,M as isDocumentHostResponse,L as parseDesktopRequest};
1
+ import{parseDesktopExecutionPolicy as y}from"./desktop-execution-policy.js";import{RESOURCE_LIMITS as i}from"../../domain/runtime/resource-limits.js";import{GATEWAY_MEDIA_LIMITS as h}from"../../domain/media/gateway-media-contract.js";function F(n){if(!a(n)||n.version!==1||!c(n.id)||!a(n.params)||typeof n.method!="string")throw o("Invalid Desktop protocol request.");const e=n.id,t=n.method,r=n.params;if(t==="initialize"||t==="session.list"||t==="model.list"||t==="auth.status"||t==="command.list"||t==="shutdown")return{version:1,id:e,method:t,params:r};if(t==="session.create")return{version:1,id:e,method:t,params:{...u(r,"model"),...u(r,"name")}};if(t==="session.resume")return{version:1,id:e,method:t,params:{sessionId:s(r,"sessionId")}};if(t==="extension.listPublicPlugins")return{version:1,id:e,method:t,params:{root:m(r,"root")}};if(t==="extension.resolvePublicPluginSource")return{version:1,id:e,method:t,params:{root:m(r,"root"),name:l(r,"name","public plugin")}};if(t==="extension.readPublicPluginContribution")return{version:1,id:e,method:t,params:{root:m(r,"root"),pluginName:l(r,"pluginName","plugin"),kind:b(r),sourceName:l(r,"sourceName","extension")}};if(t==="extension.readDetail")return{version:1,id:e,method:t,params:x(r)};if(t==="extension.readPluginIcon")return{version:1,id:e,method:t,params:{name:l(r,"name","plugin"),scope:B(r,"scope")}};if(t==="title.generate")return{version:1,id:e,method:t,params:{prompt:I(r),...u(r,"model")}};if(t==="speech.synthesize")return{version:1,id:e,method:t,params:{input:q(r),voice:k(r),...u(r,"model"),...S(r)}};if(t==="attachment.begin")return{version:1,id:e,method:t,params:{attachmentId:s(r,"attachmentId"),...N(r,"sessionId"),name:j(r),mimeType:$(r),sizeBytes:E(r),...L(r)}};if(t==="attachment.chunk")return{version:1,id:e,method:t,params:{attachmentId:s(r,"attachmentId"),index:R(r),dataBase64:D(r)}};if(t==="attachment.complete")return{version:1,id:e,method:t,params:{attachmentId:s(r,"attachmentId")}};if(t==="attachment.delete")return{version:1,id:e,method:t,params:{sessionId:s(r,"sessionId"),attachmentId:s(r,"attachmentId")}};if(t==="turn.start")return{version:1,id:e,method:t,params:{sessionId:s(r,"sessionId"),prompt:I(r),...u(r,"model"),...u(r,"reasoningEffort"),...u(r,"runId"),...u(r,"taskId"),...u(r,"sessionName"),...C(r),...K(r),execution:M(r)}};if(t==="turn.cancel")return{version:1,id:e,method:t,params:{turnId:s(r,"turnId")}};if(t==="approval.respond")return{version:1,id:e,method:t,params:P(r)};if(t==="trust.respond")return{version:1,id:e,method:t,params:{trustRequestId:s(r,"trustRequestId"),trusted:z(r,"trusted")}};if(t==="command.execute")return{version:1,id:e,method:t,params:v(r)};if(t==="command.cancel")return{version:1,id:e,method:t,params:{commandId:s(r,"commandId")}};throw o("Unsupported Desktop protocol method.")}function H(n){return!a(n)||n.version!==1||n.type!=="host.response"||n.tool!=="browser"||!c(n.requestId)||typeof n.ok!="boolean"?!1:n.error===void 0||a(n.error)}function O(n){return!a(n)||n.version!==1||n.type!=="host.response"||!["filesystem","shell","git","artifact"].includes(String(n.tool))||!c(n.requestId)||typeof n.ok!="boolean"?!1:n.error===void 0||a(n.error)}function U(n){return!a(n)||n.version!==1||n.type!=="host.response"||n.tool!=="computer"||!c(n.requestId)||typeof n.ok!="boolean"?!1:n.error===void 0||a(n.error)}function v(n){const e=s(n,"actionId"),t=n.positionals;if(!Array.isArray(t)||t.some(f=>typeof f!="string"||Buffer.byteLength(f,"utf8")>i.jsonlPromptBytes))throw o("Invalid command positionals.");const r=n.options;if(!a(r)||Object.entries(r).some(([f,p])=>!c(f)||typeof p!="string"&&typeof p!="boolean"||typeof p=="string"&&Buffer.byteLength(p,"utf8")>i.jsonlPromptBytes))throw o("Invalid command options.");const d=n.secrets;if(d===void 0)return{actionId:e,positionals:t,options:r};if(e!=="auth.login.direct"||!a(d)||Object.keys(d).some(f=>f!=="apiKey")||typeof d.apiKey!="string"||d.apiKey.length===0||Buffer.byteLength(d.apiKey,"utf8")>i.jsonlPromptBytes)throw o("Invalid command secrets.");return{actionId:e,positionals:t,options:r,secrets:{apiKey:d.apiKey}}}function s(n,e){const t=n[e];if(!c(t))throw o(`Invalid ${e}.`);return t}function m(n,e){const t=n[e];if(typeof t!="string"||t.trim().length===0||t.includes("\0")||Buffer.byteLength(t,"utf8")>i.jsonlPathBytes)throw o(`Invalid ${e}.`);return t}function l(n,e,t){const r=n[e];if(typeof r!="string"||!/^[a-z0-9][a-z0-9-]{0,63}$/u.test(r))throw o(`Invalid ${t} name.`);return r}function w(n,e){const t=n[e];if(typeof t!="string"||t.length===0||t.length>256||t.includes("\0")||!/^[a-z0-9][a-z0-9:_-]*$/u.test(t))throw o("Invalid extension name.");return t}function b(n){const e=n.kind;if(e!=="skill"&&e!=="mcp"&&e!=="hook")throw o("Invalid extension kind.");return e}function B(n,e){const t=n[e];if(t!=="user"&&t!=="project")throw o(`Invalid ${e}.`);return t}function x(n){const e=n.kind;if(e!=="hook"&&e!=="skill"&&e!=="plugin"&&e!=="mcp")throw o("Invalid extension kind.");const t=n.scope;if(t!==void 0&&t!=="user"&&t!=="project"&&t!=="plugin"&&t!=="builtin")throw o("Invalid extension scope.");const r=w(n,"name");return{kind:e,name:r,...t===void 0?{}:{scope:t},...g(n,"pluginName"),...A(n,"pluginScope"),...g(n,"sourceName")}}function g(n,e){const t=n[e];if(t===void 0)return{};if(typeof t!="string"||!/^[a-z0-9][a-z0-9-]{0,63}$/u.test(t))throw o(`Invalid ${e}.`);return{[e]:t}}function A(n,e){const t=n[e];if(t===void 0)return{};if(t!=="user"&&t!=="project")throw o(`Invalid ${e}.`);return{[e]:t}}function I(n){const e=n.prompt;if(typeof e!="string"||e.trim().length===0||Buffer.byteLength(e,"utf8")>i.jsonlPromptBytes)throw o("Invalid prompt.");return e}function q(n){const e=n.input;if(typeof e!="string"||e.trim().length===0||[...e].length>h.speechInputCharacters)throw o("Invalid speech input.");return e}function k(n){const e=n.voice;if(typeof e!="string"||e.trim().length===0||[...e].length>h.speechVoiceCharacters)throw o("Invalid speech voice.");return e}function S(n){const e=n.responseFormat;if(e===void 0)return{};if(e!=="mp3"&&e!=="opus"&&e!=="aac"&&e!=="flac"&&e!=="wav"&&e!=="pcm")throw o("Invalid speech response format.");return{responseFormat:e}}function z(n,e){if(typeof n[e]!="boolean")throw o(`Invalid ${e}.`);return n[e]}function P(n){const e=s(n,"approvalId"),t=n.decision;if(t!=="allow"&&t!=="deny"&&t!=="redirect")throw o("Invalid approval decision.");const r=n.message;if(r!==void 0&&(typeof r!="string"||r.trim().length===0||Buffer.byteLength(r,"utf8")>i.jsonlPromptBytes))throw o("Invalid approval message.");if(t==="redirect"&&r===void 0)throw o("Approval redirect requires a message.");if(t!=="redirect"&&r!==void 0)throw o("Approval message is only valid for redirect decisions.");return t==="redirect"?{approvalId:e,decision:t,message:r}:{approvalId:e,decision:t}}function u(n,e){const t=n[e];if(t===void 0)return{};if(typeof t!="string"||t.length===0||Buffer.byteLength(t,"utf8")>i.jsonlIdBytes)throw o(`Invalid ${e}.`);return{[e]:t}}function N(n,e){const t=n[e];if(t===void 0)return{};if(!c(t))throw o(`Invalid ${e}.`);return{[e]:t}}function j(n){const e=n.name;if(typeof e!="string"||e.length===0||e.length>200||e.includes("\0"))throw o("Invalid attachment name.");return e}function $(n){const e=n.mimeType;if(typeof e!="string"||!/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*$/u.test(e)||Buffer.byteLength(e,"utf8")>i.jsonlIdBytes)throw o("Invalid attachment MIME type.");return e}function E(n){const e=n.sizeBytes;if(typeof e!="number"||!Number.isSafeInteger(e)||e<=0||e>i.maxAttachmentBytes)throw o("Invalid attachment size.");return e}function L(n){const e=n.storageName;if(e===void 0)return{};if(typeof e!="string"||e.length===0||e.length>200||e.includes("\0")||/[\\/]/u.test(e))throw o("Invalid attachment storage name.");return{storageName:e}}function R(n){const e=n.index;if(typeof e!="number"||!Number.isSafeInteger(e)||e<0)throw o("Invalid attachment chunk index.");return e}function D(n){const e=n.dataBase64;if(typeof e!="string"||e.length===0||Buffer.byteLength(e,"utf8")>Math.ceil(i.desktopAttachmentChunkBytes/3)*4+4)throw o("Invalid attachment chunk.");return e}function C(n){const e=n.attachmentIds;if(e===void 0)return{};if(!Array.isArray(e)||e.length>i.pendingAttachments||e.some(t=>!c(t))||new Set(e).size!==e.length)throw o("Invalid attachment ids.");return{attachmentIds:e}}function K(n){const e=n.skills;if(e===void 0)return{};if(!Array.isArray(e)||e.length>32||e.some(t=>!c(t))||new Set(e).size!==e.length)throw o("Invalid skills.");return{skills:e}}function M(n){return y(n.execution)}function c(n){return typeof n=="string"&&n.length>0&&Buffer.byteLength(n,"utf8")<=i.jsonlIdBytes}function a(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function o(n){return new Error(n)}export{H as isBrowserHostResponse,U as isComputerHostResponse,O as isDesktopHostResponse,F as parseDesktopRequest};
@@ -1,16 +1,26 @@
1
1
  import type { ToolApprovalRequest } from '@lotagate/agent-sdk';
2
2
  import type { DesktopExecutionPolicy } from './desktop-execution-policy.js';
3
+ export type DesktopApprovalDecision = {
4
+ decision: 'allow';
5
+ } | {
6
+ decision: 'deny';
7
+ } | {
8
+ decision: 'redirect';
9
+ message: string;
10
+ };
3
11
  /** Owns Desktop approval/trust waiters and their AbortSignal lifecycle. */
4
12
  export declare class DesktopApprovalBroker {
5
13
  private readonly writeEvent;
6
14
  private readonly approvals;
7
15
  private readonly trusts;
8
16
  constructor(writeEvent: (event: string, data: Record<string, unknown>) => Promise<void>);
9
- waitForApproval(request: ToolApprovalRequest, sessionId: string, turnId: string, signal: AbortSignal, executionBoundary: DesktopExecutionPolicy['isolation'], fallbackReason?: string): Promise<boolean>;
17
+ waitForApproval(request: ToolApprovalRequest, sessionId: string, turnId: string, signal: AbortSignal, executionBoundary: DesktopExecutionPolicy['isolation'], fallbackReason?: string): Promise<DesktopApprovalDecision>;
10
18
  waitForTrust(trustRequestId: string, signal: AbortSignal): Promise<boolean>;
11
- respondApproval(approvalId: string, approved: boolean): boolean;
19
+ respondApproval(approvalId: string, decision: DesktopApprovalDecision | boolean): boolean;
12
20
  respondTrust(trustRequestId: string, trusted: boolean): boolean;
13
21
  close(): void;
14
- private wait;
15
- private respond;
22
+ private waitApproval;
23
+ private waitTrust;
24
+ private respondApprovalDecision;
25
+ private respondTrustDecision;
16
26
  }
@@ -1 +1 @@
1
- import{randomUUID as n}from"node:crypto";import{actionDisplayName as p,actionKind as l}from"../orchestration/cli-turn-events.js";import{describeApproval as v}from"./desktop-protocol-helpers.js";class m{writeEvent;approvals=new Map;trusts=new Map;constructor(t){this.writeEvent=t}async waitForApproval(t,r,e,o,a,s){const i=n();return await this.writeEvent("approval.requested",{approvalId:i,turnId:e,sessionId:r,toolName:t.toolName,displayName:p(t.toolName),kind:l(t.toolName,t.toolInfo?.source),detail:v(t),executionBoundary:a,...s===void 0?{}:{fallbackReason:s}}),this.wait(this.approvals,i,o)}waitForTrust(t,r){return this.wait(this.trusts,t,r)}respondApproval(t,r){return this.respond(this.approvals,t,r)}respondTrust(t,r){return this.respond(this.trusts,t,r)}close(){for(const t of[...this.approvals.values(),...this.trusts.values()])t.resolve(!1);this.approvals.clear(),this.trusts.clear()}wait(t,r,e){return new Promise(o=>{const a=()=>s(!1),s=i=>{t.delete(r),e.removeEventListener("abort",a),o(i)};if(e.aborted){s(!1);return}e.addEventListener("abort",a,{once:!0}),t.set(r,{resolve:s,signal:e,onAbort:a})})}respond(t,r,e){const o=t.get(r);return o===void 0?!1:(o.resolve(e),!0)}}export{m as DesktopApprovalBroker};
1
+ import{randomUUID as l}from"node:crypto";import{actionDisplayName as d,actionKind as v}from"../orchestration/cli-turn-events.js";import{describeApproval as u}from"./desktop-protocol-helpers.js";class m{writeEvent;approvals=new Map;trusts=new Map;constructor(e){this.writeEvent=e}async waitForApproval(e,t,r,o,s,n){const i=l(),a=this.waitApproval(i,o);try{await this.writeEvent("approval.requested",{approvalId:i,turnId:r,sessionId:t,toolName:e.toolName,displayName:d(e.toolName),kind:v(e.toolName,e.toolInfo?.source),detail:u(e),executionBoundary:s,...n===void 0?{}:{fallbackReason:n}})}catch(p){throw this.respondApproval(i,{decision:"deny"}),p}return a}waitForTrust(e,t){return this.waitTrust(e,t)}respondApproval(e,t){return this.respondApprovalDecision(e,t)}respondTrust(e,t){return this.respondTrustDecision(e,t)}close(){for(const e of this.approvals.values())e.resolve({decision:"deny"});for(const e of this.trusts.values())e.resolve(!1);this.approvals.clear(),this.trusts.clear()}waitApproval(e,t){return new Promise(r=>{const o=()=>s({decision:"deny"}),s=n=>{this.approvals.delete(e),t.removeEventListener("abort",o),r(n)};if(t.aborted){s({decision:"deny"});return}t.addEventListener("abort",o,{once:!0}),this.approvals.set(e,{resolve:s,signal:t,onAbort:o})})}waitTrust(e,t){return new Promise(r=>{const o=()=>s(!1),s=n=>{this.trusts.delete(e),t.removeEventListener("abort",o),r(n)};if(t.aborted){s(!1);return}t.addEventListener("abort",o,{once:!0}),this.trusts.set(e,{resolve:s,signal:t,onAbort:o})})}respondApprovalDecision(e,t){const r=this.approvals.get(e);return r===void 0?!1:(r.resolve(typeof t=="boolean"?{decision:t?"allow":"deny"}:t),!0)}respondTrustDecision(e,t){const r=this.trusts.get(e);return r===void 0?!1:(r.resolve(t),!0)}}export{m as DesktopApprovalBroker};
@@ -1,16 +1,33 @@
1
1
  import type { AttachmentPayload } from '../../domain/session/attachment.js';
2
+ export interface DesktopAttachmentStoreOptions {
3
+ readonly ttlMs?: number;
4
+ }
2
5
  export declare class DesktopAttachmentStore {
3
6
  private readonly pending;
4
7
  private readonly completed;
8
+ private readonly ttlMs;
9
+ constructor(options?: DesktopAttachmentStoreOptions);
5
10
  begin(input: {
6
11
  id: string;
12
+ sessionId?: string;
7
13
  name: string;
8
14
  mimeType: string;
9
15
  sizeBytes: number;
16
+ storageName?: string;
10
17
  }): void;
11
18
  appendChunk(id: string, index: number, encoded: string): void;
12
- complete(id: string): void;
13
- take(ids: readonly string[]): AttachmentPayload[];
19
+ complete(id: string): AttachmentUpload;
20
+ take(ids: readonly string[], sessionId?: string): AttachmentPayload[];
21
+ replace(id: string, upload: AttachmentUpload): void;
22
+ delete(id: string, sessionId?: string): void;
14
23
  clear(): void;
15
24
  private totalReservedBytes;
25
+ private schedulePendingExpiry;
26
+ private createRetainedAttachment;
27
+ private removePending;
28
+ private removeCompleted;
29
+ private clearExpiryTimer;
30
+ }
31
+ export interface AttachmentUpload extends AttachmentPayload {
32
+ sessionId: string;
16
33
  }
@@ -1 +1 @@
1
- import{CLI_ERROR_CODES as s}from"../../domain/errors/error-codes.js";import{CliError as c}from"../../domain/errors/cli-error.js";import{createImageAttachment as d,normalizeImage as r}from"../../infrastructure/clipboard/image-normalizer.js";import{RESOURCE_LIMITS as m}from"../../domain/runtime/resource-limits.js";class u{pending=new Map;completed=new Map;begin(e){if(!p(e.id)||!A(e.name)||!T(e.mimeType))throw i(s.ATTACHMENT_INVALID_IMAGE,"Invalid desktop attachment metadata.","The attachment metadata is invalid.");if(!Number.isSafeInteger(e.sizeBytes)||e.sizeBytes<=0||e.sizeBytes>m.maxAttachmentBytes)throw i(s.ATTACHMENT_TOO_LARGE,"Desktop attachment size is outside the allowed range.","The attachment exceeds the maximum allowed size.",!0);if(this.pending.has(e.id)||this.completed.has(e.id))throw i(s.ATTACHMENT_INVALID_IMAGE,"Desktop attachment id is already in use.","This attachment has already been uploaded.");if(this.totalReservedBytes()+e.sizeBytes>m.pendingAttachmentTotalBytes||this.pending.size+this.completed.size>=m.pendingAttachments)throw i(s.ATTACHMENT_TOO_LARGE,"Desktop attachment limits exceeded.","Too many or too-large attachments are pending.",!0);this.pending.set(e.id,{id:e.id,name:e.name,mimeType:e.mimeType,sizeBytes:e.sizeBytes,nextIndex:0,receivedBytes:0,chunks:[]})}appendChunk(e,t,o){const n=this.pending.get(e);if(n===void 0)throw i(s.ATTACHMENT_INVALID_IMAGE,"Desktop attachment upload was not started.","The attachment upload is not active.");if(!Number.isSafeInteger(t)||t!==n.nextIndex)throw i(s.ATTACHMENT_INVALID_IMAGE,"Desktop attachment chunk order is invalid.","The attachment upload is out of order.");const h=l(o);if(h.byteLength===0||h.byteLength>m.desktopAttachmentChunkBytes||n.receivedBytes+h.byteLength>n.sizeBytes)throw i(s.ATTACHMENT_TOO_LARGE,"Desktop attachment chunk exceeds its declared size.","The attachment upload is invalid or too large.",!0);n.chunks.push(h),n.receivedBytes+=h.byteLength,n.nextIndex+=1}complete(e){const t=this.pending.get(e);if(t===void 0)throw i(s.ATTACHMENT_INVALID_IMAGE,"Desktop attachment upload was not started.","The attachment upload is not active.");if(t.receivedBytes!==t.sizeBytes)throw i(s.ATTACHMENT_INVALID_IMAGE,"Desktop attachment upload is incomplete.","The attachment upload did not finish.");const o=Buffer.concat(t.chunks);if(t.mimeType.startsWith("image/")){const n=r(o,t.mimeType),h=d(n,"file",t.id);this.completed.set(e,{attachment:{...h,name:t.name},bytes:n.bytes})}else this.completed.set(e,{attachment:{id:t.id,name:t.name,mimeType:t.mimeType,sizeBytes:o.byteLength,source:"file"},bytes:o});this.pending.delete(e)}take(e){if(new Set(e).size!==e.length)throw i(s.ATTACHMENT_INVALID_IMAGE,"Desktop attachment ids must be unique.","An attachment was referenced more than once.");const t=e.map(o=>{const n=this.completed.get(o);if(n===void 0)throw i(s.ATTACHMENT_INVALID_IMAGE,"Desktop attachment is not complete.","Complete the attachment upload before sending the prompt.");return n});return e.forEach(o=>this.completed.delete(o)),t}clear(){this.pending.clear(),this.completed.clear()}totalReservedBytes(){let e=0;for(const t of this.pending.values())e+=t.sizeBytes;for(const t of this.completed.values())e+=t.bytes.byteLength;return e}}function l(a){if(!/^[A-Za-z0-9+/]*={0,2}$/u.test(a)||a.length===0||a.length%4!==0)throw i(s.ATTACHMENT_INVALID_IMAGE,"Desktop attachment chunk is not valid Base64.","The attachment upload is invalid.");return Buffer.from(a,"base64")}function p(a){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(a)}function A(a){return a.length>0&&a.length<=200&&!a.includes("\0")}function T(a){return a.length<=m.jsonlIdBytes&&/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*$/u.test(a)}function i(a,e,t,o=!1){return new c(a,e,{category:"attachment",userMessage:t,retryable:o})}export{u as DesktopAttachmentStore};
1
+ import{CLI_ERROR_CODES as i}from"../../domain/errors/error-codes.js";import{CliError as d}from"../../domain/errors/cli-error.js";import{createImageAttachment as c,normalizeImage as l}from"../../infrastructure/clipboard/image-normalizer.js";import{RESOURCE_LIMITS as h}from"../../domain/runtime/resource-limits.js";class E{pending=new Map;completed=new Map;ttlMs;constructor(e={}){if(this.ttlMs=e.ttlMs??h.desktopAttachmentTtlMs,!Number.isSafeInteger(this.ttlMs)||this.ttlMs<=0)throw new RangeError("Desktop attachment TTL must be a positive safe integer.")}begin(e){if(!T(e.id)||!A(e.name)||!g(e.mimeType))throw o(i.ATTACHMENT_INVALID_IMAGE,"Invalid desktop attachment metadata.","The attachment metadata is invalid.");if(!Number.isSafeInteger(e.sizeBytes)||e.sizeBytes<=0||e.sizeBytes>h.maxAttachmentBytes)throw o(i.ATTACHMENT_TOO_LARGE,"Desktop attachment size is outside the allowed range.","The attachment exceeds the maximum allowed size.",!0);if(this.pending.has(e.id)||this.completed.has(e.id))throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment id is already in use.","This attachment has already been uploaded.");if(this.totalReservedBytes()+e.sizeBytes>h.pendingAttachmentTotalBytes||this.pending.size+this.completed.size>=h.pendingAttachments)throw o(i.ATTACHMENT_TOO_LARGE,"Desktop attachment limits exceeded.","Too many or too-large attachments are pending.",!0);const t={id:e.id,sessionId:e.sessionId??"",name:e.name,mimeType:e.mimeType,sizeBytes:e.sizeBytes,...e.storageName===void 0?{}:{storageName:e.storageName},nextIndex:0,receivedBytes:0,chunks:[]};this.pending.set(e.id,t),this.schedulePendingExpiry(t)}appendChunk(e,t,r){const s=this.pending.get(e);if(s===void 0)throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment upload was not started.","The attachment upload is not active.");if(!Number.isSafeInteger(t)||t!==s.nextIndex)throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment chunk order is invalid.","The attachment upload is out of order.");const n=p(r);if(n.byteLength===0||n.byteLength>h.desktopAttachmentChunkBytes||s.receivedBytes+n.byteLength>s.sizeBytes)throw o(i.ATTACHMENT_TOO_LARGE,"Desktop attachment chunk exceeds its declared size.","The attachment upload is invalid or too large.",!0);s.chunks.push(n),s.receivedBytes+=n.byteLength,s.nextIndex+=1,this.schedulePendingExpiry(s)}complete(e){const t=this.pending.get(e);if(t===void 0)throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment upload was not started.","The attachment upload is not active.");if(t.receivedBytes!==t.sizeBytes)throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment upload is incomplete.","The attachment upload did not finish.");const r=Buffer.concat(t.chunks),s=t.mimeType.startsWith("image/")?(()=>{const n=l(r,t.mimeType),m=c(n,"file",t.id);return{sessionId:t.sessionId,attachment:{...m,name:t.name,...t.storageName===void 0?{}:{storageName:t.storageName}},bytes:n.bytes}})():{sessionId:t.sessionId,attachment:{id:t.id,name:t.name,mimeType:t.mimeType,sizeBytes:r.byteLength,source:"file",...t.storageName===void 0?{}:{storageName:t.storageName}},bytes:r};return this.removePending(e),this.completed.set(e,this.createRetainedAttachment(s)),s}take(e,t){if(new Set(e).size!==e.length)throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment ids must be unique.","An attachment was referenced more than once.");const r=e.map(s=>{const n=this.completed.get(s);if(n===void 0)throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment is not complete.","Complete the attachment upload before sending the prompt.");if(t!==void 0&&n.upload.sessionId.length>0&&n.upload.sessionId!==t)throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment belongs to another session.","The attachment is not available in this session.");return{attachment:n.upload.attachment,bytes:n.upload.bytes}});return e.forEach(s=>this.removeCompleted(s)),r}replace(e,t){if(!this.completed.has(e))throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment upload was not retained.","The attachment upload is not available.");this.removeCompleted(e),this.completed.set(e,this.createRetainedAttachment(t))}delete(e,t){const r=this.pending.get(e),s=this.completed.get(e),n=r?.sessionId??s?.upload.sessionId;if(t!==void 0&&n!==void 0&&n.length>0&&n!==t)throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment belongs to another session.","The attachment is not available in this session.");this.removePending(e),this.removeCompleted(e)}clear(){for(const e of this.pending.values())this.clearExpiryTimer(e.expiryTimer);for(const e of this.completed.values())this.clearExpiryTimer(e.expiryTimer);this.pending.clear(),this.completed.clear()}totalReservedBytes(){let e=0;for(const t of this.pending.values())e+=t.sizeBytes;for(const t of this.completed.values())e+=t.upload.bytes.byteLength;return e}schedulePendingExpiry(e){this.clearExpiryTimer(e.expiryTimer);const t=setTimeout(()=>{this.pending.get(e.id)===e&&this.pending.delete(e.id)},this.ttlMs);t.unref?.(),e.expiryTimer=t}createRetainedAttachment(e){const t={upload:e},r=setTimeout(()=>{this.completed.get(e.attachment.id)===t&&this.completed.delete(e.attachment.id)},this.ttlMs);return r.unref?.(),t.expiryTimer=r,t}removePending(e){const t=this.pending.get(e);t!==void 0&&(this.clearExpiryTimer(t.expiryTimer),this.pending.delete(e))}removeCompleted(e){const t=this.completed.get(e);t!==void 0&&(this.clearExpiryTimer(t.expiryTimer),this.completed.delete(e))}clearExpiryTimer(e){e!==void 0&&clearTimeout(e)}}function p(a){if(!/^[A-Za-z0-9+/]*={0,2}$/u.test(a)||a.length===0||a.length%4!==0)throw o(i.ATTACHMENT_INVALID_IMAGE,"Desktop attachment chunk is not valid Base64.","The attachment upload is invalid.");return Buffer.from(a,"base64")}function T(a){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(a)}function A(a){return a.length>0&&a.length<=200&&!a.includes("\0")}function g(a){return a.length<=h.jsonlIdBytes&&/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*$/u.test(a)}function o(a,e,t,r=!1){return new d(a,e,{category:"attachment",userMessage:t,retryable:r})}export{E as DesktopAttachmentStore};
@@ -1,9 +1,11 @@
1
1
  export type DesktopPermissionPolicy = 'ask' | 'allowlist' | 'review' | 'autonomous';
2
2
  export type DesktopBrowserAccess = 'disabled' | 'read-only' | 'interactive' | 'autonomous';
3
+ export type DesktopBrowserExecution = 'isolated' | 'interactive';
3
4
  export interface DesktopExecutionPolicy {
4
5
  readonly permissionPolicy: DesktopPermissionPolicy;
5
6
  readonly allowedTools?: readonly string[];
6
7
  readonly browserAccess: DesktopBrowserAccess;
8
+ readonly browserExecution: DesktopBrowserExecution;
7
9
  readonly isolation: 'sandbox' | 'host';
8
10
  readonly hostFallback: 'ask' | 'deny' | 'allow';
9
11
  readonly timeoutMs: number;
@@ -1 +1 @@
1
- import{RESOURCE_LIMITS as f}from"../../domain/runtime/resource-limits.js";function y(o){if(!w(o))throw new Error("Invalid Desktop execution policy.");const r=e(o.permissionPolicy,["ask","allowlist","review","autonomous"],"permissionPolicy"),t=e(o.browserAccess,["disabled","read-only","interactive","autonomous"],"browserAccess"),n=e(o.isolation,["sandbox","host"],"isolation"),d=e(o.hostFallback,["ask","deny","allow"],"hostFallback"),s=o.allowedTools===void 0?void 0:p(o.allowedTools),l=c(o.timeoutMs,1e4,7200*1e3,"timeoutMs"),i=o.retryAttempt===void 0?void 0:c(o.retryAttempt,0,3,"retryAttempt");return{permissionPolicy:r,...s===void 0?{}:{allowedTools:s},browserAccess:t,isolation:n,hostFallback:d,timeoutMs:l,...i===void 0?{}:{retryAttempt:i}}}function p(o){if(!Array.isArray(o)||o.length>128)throw new Error("Invalid Desktop allowedTools.");const r=o.map(t=>{if(typeof t!="string"||t.trim().length===0||Buffer.byteLength(t,"utf8")>f.jsonlIdBytes)throw new Error("Invalid Desktop allowedTools entry.");return t.trim()});if(new Set(r).size!==r.length)throw new Error("Desktop allowedTools must not contain duplicates.");return r}function e(o,r,t){if(typeof o!="string"||!r.includes(o))throw new Error(`Invalid Desktop ${t}.`);return o}function c(o,r,t,n){if(typeof o!="number"||!Number.isSafeInteger(o)||o<r||o>t)throw new Error(`Invalid Desktop ${n}.`);return o}function w(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}export{y as parseDesktopExecutionPolicy};
1
+ import{RESOURCE_LIMITS as f}from"../../domain/runtime/resource-limits.js";function m(o){if(!a(o))throw new Error("Invalid Desktop execution policy.");const r=e(o.permissionPolicy,["ask","allowlist","review","autonomous"],"permissionPolicy"),t=e(o.browserAccess,["disabled","read-only","interactive","autonomous"],"browserAccess"),n=e(o.browserExecution,["isolated","interactive"],"browserExecution"),d=e(o.isolation,["sandbox","host"],"isolation"),l=e(o.hostFallback,["ask","deny","allow"],"hostFallback"),s=o.allowedTools===void 0?void 0:p(o.allowedTools),w=c(o.timeoutMs,1e4,7200*1e3,"timeoutMs"),i=o.retryAttempt===void 0?void 0:c(o.retryAttempt,0,3,"retryAttempt");return{permissionPolicy:r,...s===void 0?{}:{allowedTools:s},browserAccess:t,browserExecution:n,isolation:d,hostFallback:l,timeoutMs:w,...i===void 0?{}:{retryAttempt:i}}}function p(o){if(!Array.isArray(o)||o.length>128)throw new Error("Invalid Desktop allowedTools.");const r=o.map(t=>{if(typeof t!="string"||t.trim().length===0||Buffer.byteLength(t,"utf8")>f.jsonlIdBytes)throw new Error("Invalid Desktop allowedTools entry.");return t.trim()});if(new Set(r).size!==r.length)throw new Error("Desktop allowedTools must not contain duplicates.");return r}function e(o,r,t){if(typeof o!="string"||!r.includes(o))throw new Error(`Invalid Desktop ${t}.`);return o}function c(o,r,t,n){if(typeof o!="number"||!Number.isSafeInteger(o)||o<r||o>t)throw new Error(`Invalid Desktop ${n}.`);return o}function a(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}export{m as parseDesktopExecutionPolicy};
@@ -0,0 +1,33 @@
1
+ import type { BrowserHostRequest, BrowserHostResponse } from './browser-host-tool-executor.js';
2
+ import type { DesktopHostExecutionRequest, DesktopHostExecutionResponse } from './desktop-host-tool-executor.js';
3
+ import type { ComputerHostRequest, ComputerHostResponse } from './computer-host-tool-executor.js';
4
+ import type { JsonLineWriter } from './json-line-writer.js';
5
+ type HostCancel = {
6
+ version: 1;
7
+ type: 'host.cancel';
8
+ requestId: string;
9
+ tool: 'browser' | 'computer' | 'filesystem' | 'shell' | 'git' | 'artifact';
10
+ sessionId: string;
11
+ };
12
+ export type DesktopHostWireMessage = BrowserHostRequest | BrowserHostResponse | DesktopHostExecutionRequest | DesktopHostExecutionResponse | ComputerHostRequest | ComputerHostResponse | HostCancel;
13
+ /** Owns the request/response lifecycle for Desktop-hosted capabilities. */
14
+ export declare class DesktopHostBridge {
15
+ private readonly writer;
16
+ private readonly isStopping;
17
+ private readonly browserRequests;
18
+ private readonly desktopRequests;
19
+ private readonly computerRequests;
20
+ constructor(writer: JsonLineWriter<DesktopHostWireMessage>, isStopping: () => boolean);
21
+ requestBrowser(request: BrowserHostRequest, signal?: AbortSignal): Promise<BrowserHostResponse>;
22
+ requestDesktop(request: DesktopHostExecutionRequest, signal?: AbortSignal): Promise<DesktopHostExecutionResponse>;
23
+ requestComputer(request: ComputerHostRequest, signal?: AbortSignal): Promise<ComputerHostResponse>;
24
+ resolveBrowser(response: BrowserHostResponse): void;
25
+ resolveDesktop(response: DesktopHostExecutionResponse): void;
26
+ resolveComputer(response: ComputerHostResponse): void;
27
+ close(): void;
28
+ private request;
29
+ private resolve;
30
+ private rejectAll;
31
+ private sendCancel;
32
+ }
33
+ export {};
@@ -0,0 +1 @@
1
+ class c{writer;isStopping;browserRequests=new Map;desktopRequests=new Map;computerRequests=new Map;constructor(e,t){this.writer=e,this.isStopping=t}requestBrowser(e,t){return this.request(e,t,this.browserRequests,"Browser action was cancelled.")}requestDesktop(e,t){return this.request(e,t,this.desktopRequests,"Host execution was cancelled.")}requestComputer(e,t){return this.request(e,t,this.computerRequests,"Computer action was cancelled.")}resolveBrowser(e){this.resolve(this.browserRequests,e)}resolveDesktop(e){this.resolve(this.desktopRequests,e)}resolveComputer(e){this.resolve(this.computerRequests,e)}close(){this.rejectAll(this.browserRequests,"The Desktop browser bridge was closed."),this.rejectAll(this.desktopRequests,"The Desktop execution bridge was closed."),this.rejectAll(this.computerRequests,"The Desktop computer bridge was closed.")}request(e,t,s,i){if(this.isStopping())return Promise.reject(new Error("The Desktop host bridge is stopping."));if(t?.aborted===!0)return Promise.reject(new Error(i));const n=new Promise((r,d)=>{const o={resolve:r,reject:d,...t===void 0?{}:{signal:t}};t!==void 0&&(o.onAbort=()=>{s.delete(e.requestId),this.sendCancel(e),d(new Error(i))},t.addEventListener("abort",o.onAbort,{once:!0})),s.set(e.requestId,o)});return n.catch(()=>{}),this.writer.write(e).then(()=>n).finally(()=>{const r=s.get(e.requestId);r!==void 0&&(r.onAbort!==void 0&&r.signal?.removeEventListener("abort",r.onAbort),s.delete(e.requestId))})}resolve(e,t){const s=e.get(t.requestId);s!==void 0&&(s.onAbort!==void 0&&s.signal?.removeEventListener("abort",s.onAbort),e.delete(t.requestId),s.resolve(t))}rejectAll(e,t){for(const s of e.values())s.onAbort!==void 0&&s.signal?.removeEventListener("abort",s.onAbort),s.reject(new Error(t));e.clear()}async sendCancel(e){this.isStopping()||await this.writer.write({version:1,type:"host.cancel",requestId:e.requestId,tool:e.tool,sessionId:e.sessionId}).catch(()=>{})}}export{c as DesktopHostBridge};
@@ -0,0 +1,12 @@
1
+ /** Capability metadata supplied by the Desktop native host during handshake. */
2
+ export interface DesktopHostCapability {
3
+ readonly available: boolean;
4
+ readonly provider: string;
5
+ readonly operations: readonly string[];
6
+ readonly reason?: string;
7
+ }
8
+ export interface DesktopHostCapabilities {
9
+ readonly computer?: DesktopHostCapability;
10
+ }
11
+ export declare function hostCapabilityAvailable(capabilities: DesktopHostCapabilities | undefined, capability: DesktopHostCapability | undefined): boolean;
12
+ export declare function normalizeDesktopHostCapabilities(value: unknown): DesktopHostCapabilities | undefined;
@@ -0,0 +1 @@
1
+ function a(r,n){return r===void 0?n?.available!==!1:n?.available===!0}function s(r){if(!i(r))return;const n=o(r.computer);return{...n===void 0?{}:{computer:n}}}function o(r){if(!i(r)||typeof r.available!="boolean"||typeof r.provider!="string"||r.provider.trim().length===0||!Array.isArray(r.operations))return;const n=r.operations.filter(t=>typeof t=="string"&&t.length>0),e=typeof r.reason=="string"&&r.reason.length>0?r.reason:void 0;return{available:r.available,provider:r.provider,operations:n,...e===void 0?{}:{reason:e}}}function i(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}export{a as hostCapabilityAvailable,s as normalizeDesktopHostCapabilities};
@@ -1,8 +1,9 @@
1
1
  import type { ToolDefinition } from '@lotagate/sdk';
2
- import type { ToolExecutionContext, ToolExecutor, ToolInfo, ToolResult } from '@lotagate/agent-sdk';
2
+ import type { ToolAuthorizationDecision, ToolExecutionContext, ToolExecutor, ToolInfo, ToolResult } from '@lotagate/agent-sdk';
3
3
  import type { ToolActivityObserver } from '../../ports/tool-activity.js';
4
4
  import type { ToolApprovalRequest } from '@lotagate/agent-sdk';
5
5
  import type { FileChangeDiff } from '../../domain/filesystem/file-change-diff.js';
6
+ import { type HostPlatformContext } from '../../infrastructure/platform/host-platform.js';
6
7
  export type DesktopHostExecutionTool = 'filesystem' | 'shell' | 'git' | 'artifact';
7
8
  export interface DesktopHostExecutionRequest {
8
9
  version: 1;
@@ -13,6 +14,7 @@ export interface DesktopHostExecutionRequest {
13
14
  runId: string;
14
15
  action: string;
15
16
  params: Record<string, unknown>;
17
+ taskId?: string;
16
18
  executionBoundary: 'sandbox' | 'host';
17
19
  hostFallback: 'ask' | 'deny' | 'allow';
18
20
  projectRoot?: string;
@@ -25,6 +27,7 @@ export interface DesktopHostExecutionResponse {
25
27
  requestId: string;
26
28
  tool: DesktopHostExecutionTool;
27
29
  ok: boolean;
30
+ environmentId?: string;
28
31
  result?: unknown;
29
32
  error?: {
30
33
  code: string;
@@ -35,6 +38,13 @@ export interface DesktopHostExecutionResponse {
35
38
  executionBoundary?: 'sandbox' | 'host';
36
39
  fallbackReason?: string;
37
40
  fileChange?: FileChangeDiff;
41
+ artifacts?: readonly DesktopArtifactDescriptor[];
42
+ }
43
+ export interface DesktopArtifactDescriptor {
44
+ readonly id: string;
45
+ readonly name: string;
46
+ readonly kind: string;
47
+ readonly sizeBytes: number;
38
48
  }
39
49
  export type DesktopHostInvoker = (request: DesktopHostExecutionRequest, signal?: AbortSignal) => Promise<DesktopHostExecutionResponse>;
40
50
  /**
@@ -52,8 +62,11 @@ export declare class DesktopHostToolExecutor implements ToolExecutor {
52
62
  projectRoot?: string;
53
63
  executionCwd?: string;
54
64
  executionWorkspaceId?: string;
65
+ executionPlatform?: HostPlatformContext;
66
+ readOnly?: boolean;
55
67
  onWrite?: (change: FileChangeDiff) => void | Promise<void>;
56
- onFallbackApproval?: (request: ToolApprovalRequest, reason: string) => boolean | Promise<boolean>;
68
+ onArtifacts?: (artifacts: readonly DesktopArtifactDescriptor[], context: ToolExecutionContext) => void | Promise<void>;
69
+ onFallbackApproval?: (request: ToolApprovalRequest, reason: string) => boolean | ToolAuthorizationDecision | Promise<boolean | ToolAuthorizationDecision>;
57
70
  onActivity?: ToolActivityObserver;
58
71
  });
59
72
  listTools(): readonly ToolDefinition[];
@@ -1,2 +1,2 @@
1
- import{randomUUID as f}from"node:crypto";import{isReadOnlyShellRequest as p}from"../security/tool-risk-classifier.js";import{resolveWorkspacePath as h}from"../../infrastructure/filesystem/path-resolver.js";import{readOnlyArguments as m,resolveReadOnlyExecutable as y}from"../../infrastructure/platform/read-only-executable.js";import{filesystemToolDefinitions as g}from"../../infrastructure/filesystem/local-filesystem-tool-executor.js";import{shellToolDefinitions as x}from"../../infrastructure/shell/shell-tool-executor.js";import{formatFilesystemActivityName as b,formatShellCommandForDisplay as C}from"../agent/tool-display.js";import{normalizePowerShellScriptInput as E}from"../../infrastructure/platform/host-process.js";import{detectHostPlatform as k}from"../../infrastructure/platform/host-platform.js";class q{options;definitions=[...g(),...x()];constructor(t){this.options=t}listTools(){return this.definitions}getToolInfo(t){if(this.definitions.some(o=>c(o)===t))return{toolName:t,source:t==="shell.exec"?"shell":"filesystem",executorId:"desktop-host-execution",metadata:{boundary:this.options.executionBoundary}}}async execute(t,o,n){if(!this.definitions.some(e=>c(e)===t))return{content:`Unknown Desktop host tool: ${t}`,isError:!0};const i=t==="shell.exec"?"shell":"filesystem";let r;try{r=t==="shell.exec"?E(o,k()):o}catch(e){return{content:e instanceof Error?e.message:"Invalid shell.exec PowerShell script.",isError:!0}}if(t==="shell.exec"&&await p(r.command,r.args,n,h,r.cwd)){const e=r.command,a=await y(e,n.workspaceRoot??n.cwd??process.cwd());if(a===void 0)return{content:"Read-only executable is no longer available.",isError:!0};r={...r,command:a,args:m(e,r.args)}}const l=t==="shell.exec"&&typeof r.command=="string"?C(r.command,Array.isArray(r.args)?r.args.filter(e=>typeof e=="string"):[]):b(t,r.path),u=this.options.onActivity?.start({key:`${n.runId}:${t}`,toolName:t,source:i,label:l});try{let e=await this.options.request(this.request(i,t,r,n),n.signal);if(!e.ok&&e.error?.code==="SANDBOX_FALLBACK_REQUIRED"&&this.options.hostFallback==="ask"){const d=this.getToolInfo(t);(await this.options.onFallbackApproval?.({toolName:t,input:r,context:n,...d===void 0?{}:{toolInfo:d}},e.error.message)??!1)&&(e=await this.options.request({...this.request(i,t,r,n),executionBoundary:"host",hostFallback:"deny"},n.signal))}if(!e.ok)return u?.complete(!0),{content:e.error?.message??"Desktop rejected the execution request.",isError:!0,metadata:{code:e.error?.code??"HOST_EXECUTION_ERROR",boundary:e.executionBoundary??this.options.executionBoundary,retryable:e.error?.retryable??!1}};const a=O(i,e.result);if(a!==void 0){const d={code:a.code,boundary:e.executionBoundary??this.options.executionBoundary,retryable:a.retryable,...a.exitCode===void 0?{}:{exitCode:a.exitCode}};return u?.complete(!0,d),{content:a.message,isError:!0,metadata:d}}return u?.complete(!1,e.fileChange===void 0?void 0:{fileChange:{path:e.fileChange.path,additions:e.fileChange.additions,deletions:e.fileChange.deletions}}),e.fileChange!==void 0&&await this.options.onWrite?.(e.fileChange),{content:I(e.result,n.maxResultBytes),isError:!1,metadata:{boundary:e.executionBoundary??this.options.executionBoundary,...e.fallbackReason===void 0?{}:{fallbackReason:e.fallbackReason}}}}catch(e){return u?.complete(!0),{content:e instanceof Error?e.message:"Desktop execution failed.",isError:!0,metadata:{boundary:this.options.executionBoundary}}}}request(t,o,n,i){return{version:1,type:"host.request",requestId:f(),tool:t,sessionId:i.sessionId,runId:i.runId,action:o,params:n,executionBoundary:this.options.executionBoundary,hostFallback:this.options.hostFallback,...this.options.projectRoot===void 0?{}:{projectRoot:this.options.projectRoot},...this.options.executionCwd===void 0?{}:{executionCwd:this.options.executionCwd},...this.options.executionWorkspaceId===void 0?{}:{executionWorkspaceId:this.options.executionWorkspaceId}}}}function c(s){return"function"in s?s.function.name:void 0}function I(s,t){const o=typeof s=="string"?s:JSON.stringify(s??null);return Buffer.byteLength(o,"utf8")<=t?o:`${o.slice(0,Math.max(0,t-12))}
2
- [truncated]`}function O(s,t){if(s!=="shell"||typeof t!="object"||t===null||Array.isArray(t))return;const o=t,n=typeof o.stderr=="string"?o.stderr.trim():"",i=typeof o.stdout=="string"?o.stdout.trim():"";if(o.cancelled===!0)return{code:"HOST_EXECUTION_CANCELLED",message:n||"Desktop host execution was cancelled.",retryable:!1};if(o.timedOut===!0)return{code:"HOST_EXECUTION_TIMEOUT",message:n||"Desktop host execution timed out.",retryable:!0};if(o.error===!0)return{code:"HOST_EXECUTION_PROCESS_ERROR",message:n||"Desktop host process failed to start or communicate.",retryable:!0};if(Object.hasOwn(o,"exitCode")&&o.exitCode!==0){const r=typeof o.exitCode=="number"?o.exitCode:null;return{code:"HOST_COMMAND_FAILED",message:n||i||`Desktop host command exited with code ${String(r)}.`,retryable:!1,exitCode:r}}}export{q as DesktopHostToolExecutor};
1
+ import{randomUUID as y}from"node:crypto";import{isReadOnlyShellRequest as b}from"../security/tool-risk-classifier.js";import{resolveWorkspacePath as x}from"../../infrastructure/filesystem/path-resolver.js";import{readOnlyArguments as g,resolveReadOnlyExecutable as E}from"../../infrastructure/platform/read-only-executable.js";import{filesystemToolDefinitions as k,filesystemToolRisk as I}from"../../infrastructure/filesystem/local-filesystem-tool-executor.js";import{shellToolDefinitions as w}from"../../infrastructure/shell/shell-tool-executor.js";import{formatFilesystemActivityName as C,formatShellCommandForDisplay as O}from"../agent/tool-display.js";import{normalizePowerShellScriptInput as R}from"../../infrastructure/platform/host-process.js";import{detectHostPlatform as T}from"../../infrastructure/platform/host-platform.js";class W{options;definitions;constructor(t){this.options=t,this.definitions=[...k(),...w(t.executionBoundary==="sandbox"?"linux-guest":"host"),_()]}listTools(){return this.definitions}getToolInfo(t){if(!this.definitions.some(i=>h(i)===t))return;const o=t==="artifact.publish"?"write":I(t);return{toolName:t,source:t==="shell.exec"?"shell":t==="artifact.publish"?"custom":"filesystem",executorId:t==="artifact.publish"?"desktop-artifact-publisher":"desktop-host-execution",metadata:{boundary:this.options.executionBoundary,...o===void 0?{}:{risk:o}}}}async execute(t,o,r){if(!this.definitions.some(e=>h(e)===t))return{content:`Unknown Desktop host tool: ${t}`,isError:!0};const i=t==="shell.exec"?"shell":t==="artifact.publish"?"artifact":"filesystem";let s;const f=this.options.executionPlatform??T();try{s=t==="shell.exec"?R(o,f,{allowNonWindows:this.options.executionBoundary!=="sandbox"}):o}catch(e){return{content:e instanceof Error?e.message:"Invalid shell.exec PowerShell script.",isError:!0}}const p=t==="shell.exec"?await b(s.command,s.args,r,x,s.cwd,f):!1;if(t==="shell.exec"&&this.options.readOnly&&!p)return{content:"This subagent is limited to read-only shell commands inside the trusted workspace.",isError:!0,metadata:{code:"READ_ONLY_SHELL_REQUIRED"}};if(t==="shell.exec"&&p){const e=s.command,a=this.options.executionBoundary==="sandbox"?e:await E(e,r.workspaceRoot??r.cwd??process.cwd(),f);if(a===void 0)return{content:"Read-only executable is no longer available.",isError:!0};s={...s,command:a,args:g(e,s.args)}}const m=t==="shell.exec"&&typeof s.command=="string"?O(s.command,Array.isArray(s.args)?s.args.filter(e=>typeof e=="string"):[]):C(t,s.path),u=this.options.onActivity?.start({key:`${r.runId}:${t}`,toolName:t,source:i==="artifact"?"custom":i,label:m});try{let e=await this.options.request(this.request(i,t,s,r),r.signal);if(!e.ok&&e.error?.code==="SANDBOX_FALLBACK_REQUIRED"&&this.options.hostFallback==="ask"){const d=this.getToolInfo(t),c=await this.options.onFallbackApproval?.({toolName:t,input:s,context:r,...d===void 0?{}:{toolInfo:d}},e.error.message)??!1;if(typeof c=="boolean"?c:c.decision==="allow")e=await this.options.request({...this.request(i,t,s,r),executionBoundary:"host",hostFallback:"deny"},r.signal);else if(typeof c!="boolean"&&c.decision==="redirect")return u?.complete(!0,{userRedirect:!0}),{content:c.message,isError:!0,metadata:{code:"USER_REDIRECTED_ACTION",boundary:this.options.executionBoundary,userRedirect:!0}}}if(!e.ok)return u?.complete(!0),{content:e.error?.message??"Desktop rejected the execution request.",isError:!0,metadata:{code:e.error?.code??"HOST_EXECUTION_ERROR",boundary:e.executionBoundary??this.options.executionBoundary,retryable:e.error?.retryable??!1}};const a=S(i,e.result);if(a!==void 0){const d={code:a.code,boundary:e.executionBoundary??this.options.executionBoundary,retryable:a.retryable,...a.exitCode===void 0?{}:{exitCode:a.exitCode}};return u?.complete(!0,d),{content:a.message,isError:!0,metadata:d}}const l=e.artifacts??[];return l.length>0&&await this.options.onArtifacts?.(l,r),u?.complete(!1,e.fileChange===void 0?void 0:{fileChange:{path:e.fileChange.path,additions:e.fileChange.additions,deletions:e.fileChange.deletions}}),e.fileChange!==void 0&&await this.options.onWrite?.(e.fileChange),{content:D(e.result,r.maxResultBytes),isError:!1,metadata:{boundary:e.executionBoundary??this.options.executionBoundary,...e.environmentId===void 0?{}:{environmentId:e.environmentId},...e.fallbackReason===void 0?{}:{fallbackReason:e.fallbackReason},...l.length===0?{}:{artifactIds:l.map(d=>d.id)}}}}catch(e){return u?.complete(!0),{content:e instanceof Error?e.message:"Desktop execution failed.",isError:!0,metadata:{boundary:this.options.executionBoundary}}}}request(t,o,r,i){return{version:1,type:"host.request",requestId:y(),tool:t,sessionId:i.sessionId,runId:i.runId,action:o,params:r,executionBoundary:this.options.executionBoundary,hostFallback:this.options.hostFallback,...this.options.projectRoot===void 0?{}:{projectRoot:this.options.projectRoot},...this.options.executionCwd===void 0?{}:{executionCwd:this.options.executionCwd},...this.options.executionWorkspaceId===void 0?{}:{executionWorkspaceId:this.options.executionWorkspaceId},...typeof i.metadata?.taskId=="string"?{taskId:i.metadata.taskId}:{}}}}function _(){return{type:"function",function:{name:"artifact.publish",description:"Publish one completed output file from the execution workspace to the current task artifacts. The path must be workspace-relative and the file must already exist.",parameters:{type:"object",properties:{path:{type:"string",description:"Workspace-relative path of the completed output file."}},required:["path"],additionalProperties:!1}}}}function h(n){return"function"in n?n.function.name:void 0}function D(n,t){const o=typeof n=="string"?n:JSON.stringify(n??null);return Buffer.byteLength(o,"utf8")<=t?o:`${o.slice(0,Math.max(0,t-12))}
2
+ [truncated]`}function S(n,t){if(n!=="shell"||typeof t!="object"||t===null||Array.isArray(t))return;const o=t,r=typeof o.stderr=="string"?o.stderr.trim():"",i=typeof o.stdout=="string"?o.stdout.trim():"";if(o.diskLimitExceeded===!0)return{code:"HOST_EXECUTION_DISK_LIMIT",message:r||"The sandbox workspace disk limit was exceeded while the command was running.",retryable:!1};if(o.processLimitExceeded===!0)return{code:"HOST_EXECUTION_PROCESS_LIMIT",message:r||"The sandbox process limit was exceeded while the command was running.",retryable:!1};if(o.cancelled===!0)return{code:"HOST_EXECUTION_CANCELLED",message:r||"Desktop host execution was cancelled.",retryable:!1};if(o.timedOut===!0)return{code:"HOST_EXECUTION_TIMEOUT",message:r||"Desktop host execution timed out.",retryable:!0};if(o.error===!0)return{code:"HOST_EXECUTION_PROCESS_ERROR",message:r||"Desktop host process failed to start or communicate.",retryable:!0};if(Object.hasOwn(o,"exitCode")&&o.exitCode!==0){const s=typeof o.exitCode=="number"?o.exitCode:null;return{code:"HOST_COMMAND_FAILED",message:r||i||`Desktop host command exited with code ${String(s)}.`,retryable:!1,exitCode:s}}}export{W as DesktopHostToolExecutor};
@@ -1 +1 @@
1
- class o{options;progress=new Map;constructor(i){this.options=i}clear(i){this.progress.delete(i)}async write(i,t,e){if(this.options.log("Intent lifecycle updated.",{lifecycle:i.type,intentId:i.contract.id,sessionId:t,turnId:e,...i.type==="intent.evidence"?{evidenceKind:i.evidence.kind,evidenceStatus:i.evidence.status}:{},...i.type==="intent.verification.required"||i.type==="intent.blocked"?{missingCount:i.missing.length}:{}}),i.type==="intent.compiled")return this.writeCompiled(i,t,e);if(i.type==="intent.evidence")return this.writeEvidence(i,t,e);if(i.type==="intent.verification.required")return this.writeVerificationRequired(i,t,e);if(i.type==="intent.blocked")return this.writeBlocked(i,t,e);await this.options.writeEvent("intent.completed",{turnId:e,sessionId:t,intentId:i.contract.id});for(const n of i.contract.steps)await this.options.writeEvent("work.task.completed",{turnId:e,sessionId:t,planId:i.contract.id,version:this.nextVersion(e),stepId:n.id});await this.options.writeEvent("work.plan.completed",{turnId:e,sessionId:t,planId:i.contract.id,version:this.nextVersion(e)}),this.clear(e)}async writeCompiled(i,t,e){const n=i.contract.steps[0]?.id;n!==void 0&&(this.progress.set(e,{version:1,activeStepId:n}),await this.options.writeEvent("intent.compiled",{turnId:e,sessionId:t,contract:i.contract}),await this.options.writeEvent("work.plan.created",{turnId:e,sessionId:t,planId:i.contract.id,version:1,goal:i.contract.objective,language:"und",totalSteps:i.contract.steps.length,steps:i.contract.steps.map((c,r)=>({index:r,id:c.id,title:c.title,description:c.title,dependencies:[],scope:[],acceptanceCriteria:c.acceptanceCriteria,verificationHints:c.requiresVerification?["Host-observed verification required"]:[],evidenceIds:[],status:r===0?"active":"queued"}))}))}async writeEvidence(i,t,e){const n=this.evidenceStep(e,i.contract,i.evidence.kind);await this.options.writeEvent("intent.evidence.recorded",{turnId:e,sessionId:t,intentId:i.contract.id,evidence:i.evidence}),await this.options.writeEvent("work.evidence.recorded",{turnId:e,sessionId:t,planId:i.contract.id,version:this.nextVersion(e),evidence:{id:i.evidence.id,stepId:n,kind:i.evidence.kind==="tool"?"runtime":i.evidence.kind,summary:i.evidence.summary,status:i.evidence.status,...i.evidence.command===void 0?{}:{command:i.evidence.command},...i.evidence.paths===void 0?{}:{paths:i.evidence.paths},...i.evidence.exitCode===void 0?{}:{exitCode:i.evidence.exitCode},createdAt:i.evidence.timestamp}})}async writeVerificationRequired(i,t,e){await this.options.writeEvent("intent.verification.required",{turnId:e,sessionId:t,intentId:i.contract.id,missing:i.missing});const n=i.contract.steps.find(c=>c.requiresVerification);n!==void 0&&(this.setActiveStep(e,n.id),await this.options.writeEvent("work.task.started",{turnId:e,sessionId:t,planId:i.contract.id,version:this.nextVersion(e),stepId:n.id}))}async writeBlocked(i,t,e){await this.options.writeEvent("intent.blocked",{turnId:e,sessionId:t,intentId:i.contract.id,missing:i.missing}),await this.options.writeEvent("work.plan.blocked",{turnId:e,sessionId:t,planId:i.contract.id,version:this.nextVersion(e),reason:i.missing.join(", ")}),this.clear(e)}nextVersion(i){const t=this.progress.get(i);return t===void 0?1:(t.version+=1,t.version)}setActiveStep(i,t){const e=this.progress.get(i);e!==void 0&&(e.activeStepId=t)}evidenceStep(i,t,e){return e==="test"||e==="typecheck"||e==="lint"||e==="build"||e==="runtime"?t.steps.find(n=>n.requiresVerification)?.id??t.steps.at(-1)?.id??t.steps[0].id:this.progress.get(i)?.activeStepId??t.steps[0].id}}export{o as DesktopIntentEventWriter};
1
+ class o{options;progress=new Map;constructor(i){this.options=i}clear(i){this.progress.delete(i)}async write(i,t,e){if(this.options.log("Intent lifecycle updated.",{lifecycle:i.type,intentId:i.contract.id,sessionId:t,turnId:e,...i.type==="intent.evidence"?{evidenceKind:i.evidence.kind,evidenceStatus:i.evidence.status}:{},...i.type==="intent.verification.required"||i.type==="intent.blocked"?{missingCount:i.missing.length}:{}}),i.type==="intent.compiled")return this.writeCompiled(i,t,e);if(i.type==="intent.evidence")return this.writeEvidence(i,t,e);if(i.type==="intent.verification.required")return this.writeVerificationRequired(i,t,e);if(i.type==="intent.blocked")return this.writeBlocked(i,t,e);await this.options.writeEvent("intent.completed",{turnId:e,sessionId:t,intentId:i.contract.id});for(const n of i.contract.steps)await this.options.writeEvent("work.task.completed",{turnId:e,sessionId:t,planId:i.contract.id,version:this.nextVersion(e),stepId:n.id});await this.options.writeEvent("work.plan.completed",{turnId:e,sessionId:t,planId:i.contract.id,version:this.nextVersion(e)}),this.clear(e)}async writeCompiled(i,t,e){const n=i.contract.steps[0]?.id;n!==void 0&&(this.progress.set(e,{version:1,activeStepId:n}),await this.options.writeEvent("intent.compiled",{turnId:e,sessionId:t,contract:i.contract}),await this.options.writeEvent("work.plan.created",{turnId:e,sessionId:t,planId:i.contract.id,version:1,goal:i.contract.objective,language:"und",totalSteps:i.contract.steps.length,steps:i.contract.steps.map((c,r)=>({index:r,id:c.id,title:c.title,description:c.title,dependencies:[],scope:[],acceptanceCriteria:c.acceptanceCriteria,verificationHints:c.requiresVerification?["Host-observed verification required"]:[],evidenceIds:[],status:r===0?"active":"queued"}))}))}async writeEvidence(i,t,e){const n=this.evidenceStep(e,i.contract,i.evidence.kind);await this.options.writeEvent("intent.evidence.recorded",{turnId:e,sessionId:t,intentId:i.contract.id,evidence:i.evidence}),await this.options.writeEvent("work.evidence.recorded",{turnId:e,sessionId:t,planId:i.contract.id,version:this.nextVersion(e),evidence:{id:i.evidence.id,stepId:n,kind:i.evidence.kind,summary:i.evidence.summary,status:i.evidence.status,...i.evidence.command===void 0?{}:{command:i.evidence.command},...i.evidence.paths===void 0?{}:{paths:i.evidence.paths},...i.evidence.exitCode===void 0?{}:{exitCode:i.evidence.exitCode},createdAt:i.evidence.timestamp}})}async writeVerificationRequired(i,t,e){await this.options.writeEvent("intent.verification.required",{turnId:e,sessionId:t,intentId:i.contract.id,missing:i.missing});const n=i.contract.steps.find(c=>c.requiresVerification);n!==void 0&&(this.setActiveStep(e,n.id),await this.options.writeEvent("work.task.started",{turnId:e,sessionId:t,planId:i.contract.id,version:this.nextVersion(e),stepId:n.id}))}async writeBlocked(i,t,e){await this.options.writeEvent("intent.blocked",{turnId:e,sessionId:t,intentId:i.contract.id,missing:i.missing}),await this.options.writeEvent("work.plan.blocked",{turnId:e,sessionId:t,planId:i.contract.id,version:this.nextVersion(e),reason:i.missing.join(", ")}),this.clear(e)}nextVersion(i){const t=this.progress.get(i);return t===void 0?1:(t.version+=1,t.version)}setActiveStep(i,t){const e=this.progress.get(i);e!==void 0&&(e.activeStepId=t)}evidenceStep(i,t,e){return e!=="read"?t.steps.find(n=>n.requiresVerification)?.id??t.steps.at(-1)?.id??t.steps[0].id:this.progress.get(i)?.activeStepId??t.steps[0].id}}export{o as DesktopIntentEventWriter};
@@ -1 +1 @@
1
- import{asCliError as n}from"../../domain/errors/cli-error.js";import{formatShellCommandForDisplay as s,formatToolActivityName as i}from"../agent/tool-display.js";function p(e){return e==="allowlist"?"auto":e==="review"?"review":e==="autonomous"?"autonomous":"ask"}function l(e){if(typeof e=="object"&&e!==null){const r=e;if(typeof r.code=="string"&&typeof r.category=="string"&&typeof r.userMessage=="string"&&typeof r.retryable=="boolean")return{code:r.code,category:r.category,message:r.userMessage,retryable:r.retryable}}const t=n(e);return{code:t.code,category:t.category,message:t.userMessage,retryable:t.retryable}}function u(e){return{session:e}}function f(e){if(e.toolName==="filesystem.write")return{summary:`Write workspace file: ${o(e.input.path)}`,path:o(e.input.path)};if(e.toolName==="shell.exec"){const t=typeof e.input.command=="string"?e.input.command:"",r=Array.isArray(e.input.args)?e.input.args.filter(a=>typeof a=="string"):[];return{summary:`Run command: ${s(t,r,240)}`,command:t,args:r}}return{summary:`This ${i(e.toolName)} operation may change workspace or external state.`}}function o(e){return String(e??"").replace(/Bearer\s+[^\s]+/giu,"Bearer [REDACTED]").replace(/sk-[A-Za-z0-9_-]{8,}/gu,"[REDACTED]").slice(0,240)}export{f as describeApproval,p as desktopApprovalMode,u as sessionResult,l as toDesktopError};
1
+ import{asCliError as s}from"../../domain/errors/cli-error.js";import{formatShellCommandForDisplay as p,formatToolActivityName as c}from"../agent/tool-display.js";function l(e){return e==="allowlist"?"auto":e==="review"?"review":e==="autonomous"?"autonomous":"ask"}function f(e){if(typeof e=="object"&&e!==null){const t=e;if(typeof t.code=="string"&&typeof t.category=="string"&&typeof t.userMessage=="string"&&typeof t.retryable=="boolean")return{code:t.code,category:t.category,message:t.userMessage,retryable:t.retryable}}const r=s(e);return{code:r.code,category:r.category,message:r.userMessage,retryable:r.retryable}}function y(e){return{session:e}}function g(e){if(e.toolName==="filesystem.write")return{summary:`Write workspace file: ${a(e.input.path)}`,path:a(e.input.path)};if(e.toolName==="shell.exec"){const r=typeof e.input.command=="string"?e.input.command:"",t=Array.isArray(e.input.args)?e.input.args.filter(i=>typeof i=="string"):[],o=typeof e.input.script=="string"?a(e.input.script):void 0,n=o===void 0?t:[...t,"-Command",o];return{summary:`Run command: ${p(r,n,240)}`,command:r,args:t,...o===void 0?{}:{script:o}}}return{summary:`This ${c(e.toolName)} operation may change workspace or external state.`}}function a(e){return String(e??"").replace(/Bearer\s+[^\s]+/giu,"Bearer [REDACTED]").replace(/sk-[A-Za-z0-9_-]{8,}/gu,"[REDACTED]").slice(0,240)}export{g as describeApproval,l as desktopApprovalMode,y as sessionResult,f as toDesktopError};
@@ -0,0 +1,5 @@
1
+ import type { DesktopRequest } from './desktop-agent-request-parser.js';
2
+ import type { CliRuntime } from '../../bootstrap/runtime-factory.js';
3
+ export declare function generateDesktopTitle(runtime: CliRuntime, cwd: string, request: Extract<DesktopRequest, {
4
+ method: 'title.generate';
5
+ }>, signal: AbortSignal): Promise<string>;
@@ -0,0 +1,3 @@
1
+ import{TITLE_GENERATION_TIMEOUT_MS as y}from"./desktop-agent-contracts.js";import{AuthenticationService as b}from"../auth/authentication-service.js";import{createLotaGateClient as h}from"../../infrastructure/sdk/lotagate-client-factory.js";import{loadExecutionConfig as O}from"../config/execution-config.js";import{prepareCliAgent as C}from"../agent/cli-agent-execution-service.js";import{BoundedTextAccumulator as x}from"../agent/bounded-text-accumulator.js";import{CliError as u}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as w}from"../../domain/errors/error-codes.js";async function P(a,i,s,t){t.throwIfAborted();const l=await O(a,i),o=s.params.model??l.config.model;if(o==null)throw new u(w.MODEL_NOT_FOUND,"No model is selected.",{category:"model",userMessage:"No model is available for session title generation."});const g=l.config.profile??b.defaultProfileName(),c=await a.auth.requireCredential(g),r=new AbortController,m=()=>r.abort(t.reason);t.addEventListener("abort",m,{once:!0});const E=setTimeout(()=>r.abort(),y);let p;const n=new x;try{const d=await C({runtime:a,projectRoot:i,executionCwd:i,model:o,client:h(c.profile,c.apiKey),profile:"title-generator",approvalMode:"auto",allowedTools:[],selectedSkills:[],allowSubagents:!1,browserAccess:"disabled"});p=d.close;const T=["## 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",s.params.prompt].join(`
2
+
3
+ `);for await(const e of d.run({input:T,model:o,signal:r.signal,stream:!0}))if(e.type==="model.delta")n.append(e.content);else if(e.type==="session.completed"&&n.isEmpty)n.replace(e.content);else if(e.type==="session.failed")throw e.error;const f=n.toString();if(f.trim().length===0)throw new u(w.MODEL_PROTOCOL_EMPTY_RESPONSE,"Title generation returned an empty response.",{category:"model",userMessage:"The model did not return a session title.",retryable:!0});return f}finally{clearTimeout(E),t.removeEventListener("abort",m);try{await p?.()}finally{r.abort()}}}export{P as generateDesktopTitle};
@@ -1,9 +1,31 @@
1
1
  import type { Writable } from 'node:stream';
2
+ export type JsonLineDelivery = 'reliable' | 'best-effort';
3
+ export interface JsonLineWriteOptions {
4
+ readonly delivery?: JsonLineDelivery;
5
+ }
6
+ export interface JsonLineWriterOptions {
7
+ readonly maxQueuedEntries?: number;
8
+ readonly maxQueuedBytes?: number;
9
+ }
10
+ export declare function waitForWritableDrain(output: Writable): Promise<void>;
2
11
  /** Serializes protocol messages in order and applies Writable backpressure. */
3
12
  export declare class JsonLineWriter<T> {
4
13
  private readonly output;
5
14
  private tail;
6
- constructor(output: Writable);
7
- write(value: T): Promise<void>;
15
+ private activeEntries;
16
+ private activeBytes;
17
+ private waitingBytes;
18
+ private readonly waiting;
19
+ private closed;
20
+ private readonly maxQueuedEntries;
21
+ private readonly maxQueuedBytes;
22
+ constructor(output: Writable, options?: JsonLineWriterOptions);
23
+ write(value: T, options?: JsonLineWriteOptions): Promise<void>;
8
24
  flush(): Promise<void>;
25
+ close(error?: Error): void;
26
+ private schedule;
27
+ private readonly complete;
28
+ private admitWaiting;
29
+ private canSchedule;
30
+ private canWait;
9
31
  }
@@ -1,2 +1,2 @@
1
- import{once as r}from"node:events";class o{output;tail=Promise.resolve();constructor(t){this.output=t}write(t){const i=this.tail.then(async()=>{this.output.write(`${JSON.stringify(t)}
2
- `)||await r(this.output,"drain")});return this.tail=i.catch(()=>{}),i}async flush(){await this.tail}}export{o as JsonLineWriter};
1
+ import{RESOURCE_LIMITS as c}from"../../domain/runtime/resource-limits.js";function h(i){return i.destroyed||i.writableEnded?Promise.reject(new Error("The protocol output is closed.")):new Promise((e,t)=>{const s=()=>{i.removeListener("drain",r),i.removeListener("error",o),i.removeListener("close",n),i.removeListener("finish",n)},r=()=>{s(),e()},o=a=>{s(),t(a)},n=()=>{s(),t(new Error("The protocol output is closed."))};i.once("drain",r),i.once("error",o),i.once("close",n),i.once("finish",n),(i.destroyed||i.writableEnded)&&n()})}class u{output;tail=Promise.resolve();activeEntries=0;activeBytes=0;waitingBytes=0;waiting=[];closed=!1;maxQueuedEntries;maxQueuedBytes;constructor(e,t={}){this.output=e,this.maxQueuedEntries=t.maxQueuedEntries??c.protocolWriteQueueEntries,this.maxQueuedBytes=t.maxQueuedBytes??c.protocolWriteQueueBytes}write(e,t={}){const s=`${JSON.stringify(e)}
2
+ `,r=Buffer.byteLength(s,"utf8"),o=t.delivery??"reliable";return this.closed?Promise.reject(new Error("The protocol writer is closed.")):this.waiting.length>0||!this.canSchedule(r)?o==="best-effort"?Promise.reject(new Error("The protocol output queue is full.")):this.canWait(r)?new Promise((n,a)=>{this.waiting.push({serialized:s,bytes:r,resolve:n,reject:a}),this.waitingBytes+=r}):Promise.reject(new Error("The protocol output queue limit was exceeded.")):this.schedule(s,r)}async flush(){for(;;){const e=this.tail;if(await e,await new Promise(t=>setImmediate(t)),e===this.tail&&this.activeEntries===0&&this.waiting.length===0)return}}close(e=new Error("The protocol writer is closed.")){this.closed=!0;const t=this.waiting.splice(0);this.waitingBytes=0;for(const s of t)s.reject(e)}schedule(e,t){this.activeEntries+=1,this.activeBytes+=t;const s=this.tail.then(async()=>{this.output.write(e)||await h(this.output)});return this.tail=s.catch(()=>{}),s.then(()=>this.complete(t),()=>this.complete(t)),s}complete=e=>{this.activeEntries-=1,this.activeBytes-=e,this.admitWaiting()};admitWaiting(){for(;this.waiting.length>0;){const e=this.waiting[0];if(!this.canSchedule(e.bytes))return;this.waiting.shift(),this.waitingBytes-=e.bytes,this.schedule(e.serialized,e.bytes).then(e.resolve,e.reject)}}canSchedule(e){return this.activeEntries<this.maxQueuedEntries&&this.activeBytes+e<=this.maxQueuedBytes}canWait(e){return this.activeEntries+this.waiting.length<this.maxQueuedEntries&&this.activeBytes+this.waitingBytes+e<=this.maxQueuedBytes}}export{u as JsonLineWriter,h as waitForWritableDrain};
@@ -1,3 +1,3 @@
1
1
  import type { Readable, Writable } from 'node:stream';
2
2
  import type { createCompositionRoot } from '../../bootstrap/composition-root.js';
3
- export declare function runAgentCommand(positionals: readonly string[], runtime: ReturnType<typeof createCompositionRoot>, cwd: string, stdin: Readable, stdout: Writable): Promise<number>;
3
+ export declare function runAgentCommand(positionals: readonly string[], runtime: ReturnType<typeof createCompositionRoot>, cwd: string, stdin: Readable, stdout: Writable, signal?: AbortSignal): Promise<number>;
@@ -1,3 +1,3 @@
1
- import{AuthenticationService as A}from"../auth/authentication-service.js";import{JsonlProtocolRunner as k}from"./jsonl-protocol.js";import{createLotaGateClient as O}from"../../infrastructure/sdk/lotagate-client-factory.js";import{CliError as C}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as d}from"../../domain/errors/error-codes.js";import{prepareCliAgent as _}from"../agent/cli-agent-execution-service.js";import{AgentRunTracker as x}from"../agent/agent-run-tracker.js";import{loadExecutionConfig as P}from"../config/execution-config.js";import{agentLimitNotice as T,classifyAgentLimit as b}from"../agent/agent-limit.js";import{runDesktopAgentCommand as v}from"./desktop-agent-command.js";async function $(E,t,r,h,w){const N=E[0]??"stdio";if(N==="desktop")return v(t,r,h,w);if(N!=="stdio")throw new C(d.INVALID_ARGUMENT,"Unsupported agent action.",{category:"arguments",userMessage:"Use `lotagate agent stdio` or `lotagate agent desktop`."});const a=await P(t,r);if(a.config.model===null)throw new C(d.MODEL_NOT_FOUND,"No model is selected.",{category:"model",userMessage:"Select a model before running the stdio agent."});const M=a.config.profile??A.defaultProfileName(),y=await t.auth.requireCredential(M);return(await new k(async function*(f,R){const i=f.params.model??a.config.model;t.logger.info("Protocol agent request started.",{model:i,promptLength:f.params.prompt.length});const s=new x,L=o=>{s.observeModel(o),t.logger.debug("Model turn completed.",{model:o.model,stream:o.stream,contentLength:o.contentLength,toolCallCount:o.toolCallCount,toolNames:o.toolNames,finishReason:o.finishReason})},m=await _({runtime:t,projectRoot:r,executionCwd:r,model:i,client:O(y.profile,y.apiKey),profile:"protocol-safe",approvalMode:a.config.approvalMode,onModelComplete:L});let g=!1,n="",l,c;try{const o=await m.buildInput(f.params.prompt);for await(const e of m.run({input:o.input,userInput:o.userInput,...o.workspaceContext===void 0?{}:{workspaceContext:o.workspaceContext},model:i,signal:R}))if(s.observe(e),e.type==="tool.called"&&t.logger.info("Agent tool called.",{toolName:e.toolName}),e.type==="tool.completed"&&t.logger.info("Agent tool completed.",{toolName:e.toolName,isError:e.isError}),e.type==="model.delta"&&e.content.length>0?(g=!0,n+=e.content,yield{type:"delta",content:e.content}):e.type==="session.completed"&&(l=e.content),e.type==="session.failed"){const p=b(e.error);if(p===void 0)throw e.error;c=T(p);break}if(c!==void 0){const e=n.length===0?c:`
1
+ import{AuthenticationService as L}from"../auth/authentication-service.js";import{JsonlProtocolRunner as O}from"./jsonl-protocol.js";import{createLotaGateClient as _}from"../../infrastructure/sdk/lotagate-client-factory.js";import{CliError as u}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as c}from"../../domain/errors/error-codes.js";import{prepareCliAgent as S}from"../agent/cli-agent-execution-service.js";import{AgentRunTracker as T}from"../agent/agent-run-tracker.js";import{loadExecutionConfig as b}from"../config/execution-config.js";import{agentLimitNotice as v,classifyAgentLimit as P}from"../agent/agent-limit.js";import{runDesktopAgentCommand as D}from"./desktop-agent-command.js";import{createContextManagement as I}from"../agent/context-compaction.js";import{formatContinuationCheckpoint as F}from"../agent/continuation-checkpoint.js";import{resolveModelContextWindow as U}from"../model/model-context-window.js";import{BoundedTextAccumulator as G}from"../agent/bounded-text-accumulator.js";async function to(R,t,l,C,h,w){const y=R[0]??"stdio";if(y==="desktop")return D(t,l,C,h,w);if(y!=="stdio")throw new u(c.INVALID_ARGUMENT,"Unsupported agent action.",{category:"arguments",userMessage:"Use `lotagate agent stdio` or `lotagate agent desktop`."});const i=await b(t,l);if(i.config.model===null)throw new u(c.MODEL_NOT_FOUND,"No model is selected.",{category:"model",userMessage:"Select a model before running the stdio agent."});const N=i.config.profile??L.defaultProfileName(),M=await t.auth.requireCredential(N);return(await new O(async function*(d,k){const n=d.params.model??i.config.model;t.logger.info("Protocol agent request started.",{model:n,promptLength:d.params.prompt.length});const a=new T,x=_(M.profile,M.apiKey),E=await U(t,n,N),A=e=>{a.observeModel(e),t.logger.debug("Model turn completed.",{model:e.model,stream:e.stream,contentLength:e.contentLength,toolCallCount:e.toolCallCount,toolNames:e.toolNames,finishReason:e.finishReason})},m=await S({runtime:t,projectRoot:l,executionCwd:l,model:n,client:x,profile:"protocol-safe",approvalMode:i.config.approvalMode,onModelComplete:A,contextManagement:I({client:x,model:n,...E===void 0?{}:{contextWindow:E},onSummaryFailure:e=>t.logger.warn("Context summarization failed; using fallback summary.",{reason:e instanceof Error?e.message:String(e)}),continuationContext:()=>F({snapshot:a.snapshot()})})});let f=!1;const r=new G;let s;try{const e=await m.buildInput(d.params.prompt);for await(const o of m.run({input:e.input,userInput:e.userInput,...e.workspaceContext===void 0?{}:{workspaceContext:e.workspaceContext},model:n,signal:k}))if(a.observe(o),o.type==="tool.called"&&t.logger.info("Agent tool called.",{toolName:o.toolName}),o.type==="tool.completed"&&t.logger.info("Agent tool completed.",{toolName:o.toolName,isError:o.isError}),o.type==="model.delta"&&o.content.length>0?(f=!0,r.append(o.content),yield{type:"delta",content:o.content}):o.type==="session.completed"&&r.replace(o.content),o.type==="session.failed"){const p=P(o.error);if(p===void 0)throw o.error;s=v(p);break}if(s!==void 0){const o=r.isEmpty?s:`
2
2
 
3
- ${c}`;g=!0,n+=e,l=n,yield{type:"delta",content:e}}const u=l===void 0||l.trim().length===0?n:l;if(u.trim().length===0){const e=s.snapshot();e.toolCalls>0&&s.markStuck();const p=e.toolCalls>0?d.MODEL_EMPTY_FINAL:d.MODEL_PROTOCOL_EMPTY_RESPONSE;throw new C(p,"Agent completed without a final text response.",{category:"model",userMessage:"The model completed without a final text response.",retryable:!0,details:{toolCalls:e.toolCalls,toolCompletions:e.toolCompletions,toolNames:e.toolNames,finishReason:e.lastFinishReason}})}g||(yield{type:"delta",content:u}),yield{type:"completed",content:u},t.logger.info("Protocol agent request completed.",{model:i})}finally{await m.close()}}).run(h,w)).errorCount===0?0:1}export{$ as runAgentCommand};
3
+ ${s}`;f=!0,r.append(o),yield{type:"delta",content:o}}const g=r.toString();if(g.trim().length===0){const o=a.snapshot();o.toolCalls>0&&a.markStuck();const p=o.toolCalls>0?c.MODEL_EMPTY_FINAL:c.MODEL_PROTOCOL_EMPTY_RESPONSE;throw new u(p,"Agent completed without a final text response.",{category:"model",userMessage:"The model completed without a final text response.",retryable:!0,details:{toolCalls:o.toolCalls,toolCompletions:o.toolCompletions,toolNames:o.toolNames,finishReason:o.lastFinishReason}})}f||(yield{type:"delta",content:g}),yield{type:"completed",content:g},t.logger.info("Protocol agent request completed.",{model:n})}finally{await m.close()}}).run(C,h,w)).errorCount===0?0:1}export{to as runAgentCommand};
@@ -76,7 +76,7 @@ export declare class JsonlProtocolRunner {
76
76
  private readonly executor;
77
77
  private readonly options;
78
78
  constructor(executor: JsonlExecutor, options?: JsonlProtocolOptions);
79
- run(input: Readable, output: Writable): Promise<JsonlProtocolResult>;
79
+ run(input: Readable, output: Writable, signal?: AbortSignal): Promise<JsonlProtocolResult>;
80
80
  private executeOne;
81
81
  }
82
82
  export declare function readLinesBounded(input: Readable, maxBytes: number): AsyncGenerator<string>;