@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
@@ -0,0 +1 @@
1
+ import{execFile as i}from"node:child_process";import{promisify as n}from"node:util";const s=n(i);function c(){return Math.floor(Date.now()-process.uptime()*1e3)}async function f(e){if(!(!Number.isSafeInteger(e)||e<1)){if(e===process.pid)return c();if(process.platform==="win32")try{const t=`$process = Get-Process -Id ${e} -ErrorAction Stop; ([DateTimeOffset]$process.StartTime.ToUniversalTime()).ToUnixTimeMilliseconds()`,o=await s("powershell.exe",["-NoLogo","-NoProfile","-NonInteractive","-Command",t],{windowsHide:!0,timeout:1e3,maxBuffer:4*1024}),r=Number(o.stdout.trim());return Number.isFinite(r)?r:void 0}catch{return}}}export{c as currentProcessStartTimeMs,f as readProcessStartTimeMs};
@@ -1,3 +1,4 @@
1
+ import type { HostPlatformContext } from './host-platform.js';
1
2
  /** Resolves user-installed host binaries from PATH, never from the workspace. */
2
- export declare function resolveReadOnlyExecutable(command: string, root: string): Promise<string | undefined>;
3
+ export declare function resolveReadOnlyExecutable(command: string, root: string, platform?: HostPlatformContext): Promise<string | undefined>;
3
4
  export declare function readOnlyArguments(command: string, args: readonly string[]): string[];
@@ -1 +1 @@
1
- import f from"node:fs/promises";import{constants as p}from"node:fs";import t from"node:path";async function m(o,e){if(/[\\/:]/u.test(o)||/\.(?:cmd|bat|ps1)$/iu.test(o))return;let n;try{n=await f.realpath(e)}catch{return}const s=process.platform==="win32"&&!/\.(?:exe|com)$/iu.test(o)?[".exe",".com"]:[""];for(const i of(process.env.PATH??process.env.Path??"").split(t.delimiter))if(t.isAbsolute(i))for(const l of s){const u=t.join(i,`${o}${l}`),r=t.relative(n,u);if(!(r===""||!r.startsWith(`..${t.sep}`)&&r!==".."&&!t.isAbsolute(r)))try{const c=await f.realpath(u),a=t.relative(n,c);if(a===""||!a.startsWith(`..${t.sep}`)&&a!==".."&&!t.isAbsolute(a)||!(await f.stat(c)).isFile())continue;return await f.access(c,process.platform==="win32"?p.F_OK:p.X_OK),c}catch{}}}function v(o,e){if(o.toLowerCase().replace(/\.exe$/u,"")!=="git")return[...e];const n=e.find(l=>!l.startsWith("-")),s=["--no-pager","--no-optional-locks","-c","core.fsmonitor=false",...["diff","log","show"].includes(n??"")?["--no-ext-diff","--no-textconv"]:[]],i=e.indexOf("--");return i<0?[...s,...e]:[...s,...e.slice(0,i),...e.slice(i)]}export{v as readOnlyArguments,m as resolveReadOnlyExecutable};
1
+ import l from"node:fs/promises";import{constants as p}from"node:fs";import t from"node:path";async function b(n,e,i){if(/[\\/:]/u.test(n)||/\.(?:cmd|bat|ps1)$/iu.test(n))return;if(i?.isWindows===!1)return n;let o;try{o=await l.realpath(e)}catch{return}const r=process.platform==="win32"&&!/\.(?:exe|com)$/iu.test(n)?[".exe",".com"]:[""];for(const s of(process.env.PATH??process.env.Path??"").split(t.delimiter))if(t.isAbsolute(s))for(const u of r){const d=t.join(s,`${n}${u}`),c=t.relative(o,d);if(!(c===""||!c.startsWith(`..${t.sep}`)&&c!==".."&&!t.isAbsolute(c)))try{const a=await l.realpath(d),f=t.relative(o,a);if(f===""||!f.startsWith(`..${t.sep}`)&&f!==".."&&!t.isAbsolute(f)||!(await l.stat(a)).isFile())continue;return await l.access(a,process.platform==="win32"?p.F_OK:p.X_OK),a}catch{}}}function w(n,e){if(n.toLowerCase().replace(/\.exe$/u,"")!=="git")return[...e];const i=e.findIndex(u=>!u.startsWith("-")),o=i<0?void 0:e[i],r=["--no-pager","--no-optional-locks","-c","core.fsmonitor=false"],s=["diff","log","show"].includes(o??"")?["--no-ext-diff","--no-textconv"]:[];return i<0||s.length===0?[...r,...e]:[...r,...e.slice(0,i+1),...s,...e.slice(i+1)]}export{w as readOnlyArguments,b as resolveReadOnlyExecutable};
@@ -1 +1 @@
1
- import{LotaGate as a}from"@lotagate/sdk";function r(t,e){const o={apiKey:e,baseURL:t.baseUrl};return new a(o)}export{r as createLotaGateClient};
1
+ import{LotaGate as a}from"@lotagate/sdk";function o(e,t){return new a({apiKey:t,baseURL:e.baseUrl})}export{o as createLotaGateClient};
@@ -1,4 +1,5 @@
1
1
  import type { LotaGate } from '@lotagate/sdk';
2
+ import type { AudioSpeechStreamEvent } from '@lotagate/sdk';
2
3
  import type { MediaGatewayClient, AudioUploadInput, ImageEditInput, ImageGenerationInput, MediaRequestOptions, SpeechInput } from '../../ports/media-gateway-client.js';
3
4
  import type { GeneratedImage, MediaBinary, VideoOperation } from '../../domain/media/media-contract.js';
4
5
  /** SDK boundary adapter. Application code only sees CLI-owned media contracts. */
@@ -8,6 +9,9 @@ export declare class SdkMediaGatewayClient implements MediaGatewayClient {
8
9
  generateImage(input: ImageGenerationInput, options?: MediaRequestOptions): Promise<readonly GeneratedImage[]>;
9
10
  editImage(input: ImageEditInput, options?: MediaRequestOptions): Promise<readonly GeneratedImage[]>;
10
11
  createSpeech(input: SpeechInput, options?: MediaRequestOptions): Promise<MediaBinary>;
12
+ createSpeechStream(input: SpeechInput & {
13
+ readonly streamFormat: 'sse';
14
+ }, options?: MediaRequestOptions): AsyncIterable<AudioSpeechStreamEvent>;
11
15
  transcribe(input: AudioUploadInput, options?: MediaRequestOptions): Promise<string>;
12
16
  translate(input: AudioUploadInput, options?: MediaRequestOptions): Promise<string>;
13
17
  createVideo(input: {
@@ -1 +1 @@
1
- class f{client;constructor(r){this.client=r}async generateImage(r,t){return(await this.client.images.generations.create(a(r),t)).data.map(n=>({...typeof n.b64_json=="string"?{base64:n.b64_json}:{},...typeof n.url=="string"?{url:n.url}:{},...typeof n.revised_prompt=="string"?{revisedPrompt:n.revised_prompt}:{}}))}async editImage(r,t){const s={...a(r),image:r.images,...r.mask===void 0?{}:{mask:r.mask},...r.inputFidelity===void 0?{}:{input_fidelity:r.inputFidelity}};return(await this.client.images.edits.create(s,t)).data.map(o=>({...typeof o.b64_json=="string"?{base64:o.b64_json}:{},...typeof o.url=="string"?{url:o.url}:{},...typeof o.revised_prompt=="string"?{revisedPrompt:o.revised_prompt}:{}}))}async createSpeech(r,t){const s=await this.client.audio.speech.create({model:r.model,input:r.input,voice:r.voice,...r.instructions===void 0?{}:{instructions:r.instructions},...r.responseFormat===void 0?{}:{response_format:r.responseFormat},...r.speed===void 0?{}:{speed:r.speed}},t);return d(s)}async transcribe(r,t){return(await this.client.audio.transcriptions.create(m(r),t)).text}async translate(r,t){return(await this.client.audio.translations.create(c(r),t)).text}async createVideo(r,t){const s={model:r.model,instances:[{prompt:r.prompt}],...r.parameters===void 0?{}:{parameters:r.parameters}};return i(await this.client.video.generations.create(s,t))}async getVideoOperation(r,t){return i(await this.client.video.operations.retrieve(r,t))}async downloadVideo(r,t){return d(await this.client.video.operations.download(r,t))}}function a(e){return{model:e.model,prompt:e.prompt,...e.n===void 0?{}:{n:e.n},...e.size===void 0?{}:{size:e.size},...e.quality===void 0?{}:{quality:e.quality},...e.background===void 0?{}:{background:e.background},...e.outputFormat===void 0?{}:{output_format:e.outputFormat},...e.outputCompression===void 0?{}:{output_compression:e.outputCompression},...e.moderation===void 0?{}:{moderation:e.moderation},...e.user===void 0?{}:{user:e.user}}}function m(e){const r={model:e.model,file:e.file,filename:e.filename};return e.prompt!==void 0&&(r.prompt=e.prompt),e.temperature!==void 0&&(r.temperature=e.temperature),e.responseFormat!==void 0&&(r.response_format=e.responseFormat),e.language!==void 0&&(r.language=e.language),e.timestampGranularities!==void 0&&(r.timestamp_granularities=[...e.timestampGranularities]),e.include!==void 0&&(r.include=[...e.include]),r}function c(e){const r={model:e.model,file:e.file,filename:e.filename};return e.prompt!==void 0&&(r.prompt=e.prompt),e.temperature!==void 0&&(r.temperature=e.temperature),e.responseFormat!==void 0&&(r.response_format=e.responseFormat),r}function d(e){const r=e.headers.get("content-type")?.split(";",1)[0]?.trim();return{bytes:new Uint8Array(e.data),...r===void 0||r.length===0?{}:{contentType:r}}}function i(e){return{id:e.name,done:e.done===!0,...typeof e.error?.message=="string"?{errorMessage:e.error.message}:{}}}export{f as SdkMediaGatewayClient};
1
+ class f{client;constructor(e){this.client=e}async generateImage(e,s){return(await this.client.images.generations.create(a(e),s)).data.map(t=>({...typeof t.b64_json=="string"?{base64:t.b64_json}:{},...typeof t.url=="string"?{url:t.url}:{},...typeof t.revised_prompt=="string"?{revisedPrompt:t.revised_prompt}:{}}))}async editImage(e,s){const o={...a(e),image:e.images,...e.mask===void 0?{}:{mask:e.mask},...e.inputFidelity===void 0?{}:{input_fidelity:e.inputFidelity}};return(await this.client.images.edits.create(o,s)).data.map(n=>({...typeof n.b64_json=="string"?{base64:n.b64_json}:{},...typeof n.url=="string"?{url:n.url}:{},...typeof n.revised_prompt=="string"?{revisedPrompt:n.revised_prompt}:{}}))}async createSpeech(e,s){if(e.streamFormat==="sse")throw new Error("Use createSpeechStream for SSE speech responses.");const o=e.streamFormat??"audio",t=await this.client.audio.speech.create({model:e.model,input:e.input,voice:e.voice,...e.instructions===void 0?{}:{instructions:e.instructions},...e.responseFormat===void 0?{}:{response_format:e.responseFormat},...e.speed===void 0?{}:{speed:e.speed},stream_format:o},s);return d(t)}createSpeechStream(e,s){return this.client.audio.speech.create({model:e.model,input:e.input,voice:e.voice,...e.instructions===void 0?{}:{instructions:e.instructions},...e.responseFormat===void 0?{}:{response_format:e.responseFormat},...e.speed===void 0?{}:{speed:e.speed},stream_format:"sse"},s)}async transcribe(e,s){return(await this.client.audio.transcriptions.create(m(e),s)).text}async translate(e,s){return(await this.client.audio.translations.create(c(e),s)).text}async createVideo(e,s){const o={model:e.model,instances:[{prompt:e.prompt}],...e.parameters===void 0?{}:{parameters:e.parameters}};return i(await this.client.video.generations.create(o,s))}async getVideoOperation(e,s){return i(await this.client.video.operations.retrieve(e,s))}async downloadVideo(e,s){return d(await this.client.video.operations.download(e,s))}}function a(r){return{model:r.model,prompt:r.prompt,...r.n===void 0?{}:{n:r.n},...r.size===void 0?{}:{size:r.size},...r.quality===void 0?{}:{quality:r.quality},...r.background===void 0?{}:{background:r.background},...r.outputFormat===void 0?{}:{output_format:r.outputFormat},...r.outputCompression===void 0?{}:{output_compression:r.outputCompression},...r.moderation===void 0?{}:{moderation:r.moderation},...r.user===void 0?{}:{user:r.user}}}function m(r){const e={model:r.model,file:r.file,filename:r.filename};return r.prompt!==void 0&&(e.prompt=r.prompt),r.temperature!==void 0&&(e.temperature=r.temperature),r.responseFormat!==void 0&&(e.response_format=r.responseFormat),r.language!==void 0&&(e.language=r.language),r.timestampGranularities!==void 0&&(e.timestamp_granularities=[...r.timestampGranularities]),r.include!==void 0&&(e.include=[...r.include]),e}function c(r){const e={model:r.model,file:r.file,filename:r.filename};return r.prompt!==void 0&&(e.prompt=r.prompt),r.temperature!==void 0&&(e.temperature=r.temperature),r.responseFormat!==void 0&&(e.response_format=r.responseFormat),e}function d(r){const e=r.headers.get("content-type")?.split(";",1)[0]?.trim();return{bytes:new Uint8Array(r.data),...e===void 0||e.length===0?{}:{contentType:e}}}function i(r){return{id:r.name,done:r.done===!0,...typeof r.error?.message=="string"?{errorMessage:r.error.message}:{}}}export{f as SdkMediaGatewayClient};
@@ -4,8 +4,12 @@ import type { SessionStore, SessionBundle, SessionHistory, SessionJournalAppend,
4
4
  import type { PlatformPaths } from '../platform/platform-paths.js';
5
5
  export declare class FileSessionStore implements SessionStore {
6
6
  private readonly paths;
7
+ private readonly journalHealth;
8
+ private readonly journalSnapshotCache;
9
+ private journalSnapshotCacheBytes;
7
10
  constructor(paths: PlatformPaths);
8
11
  create(input: Omit<SessionMetadata, 'id' | 'createdAt' | 'updatedAt'>): Promise<SessionMetadata>;
12
+ private createUnpublished;
9
13
  get(sessionId: string): Promise<SessionMetadata | undefined>;
10
14
  list(projectFingerprint?: string): Promise<readonly SessionMetadata[]>;
11
15
  updateStatus(sessionId: string, status: SessionMetadata['status']): Promise<SessionMetadata>;
@@ -28,9 +32,11 @@ export declare class FileSessionStore implements SessionStore {
28
32
  saveAttachment(sessionId: string, attachment: Attachment, bytes: Uint8Array): Promise<Attachment>;
29
33
  private persistAttachment;
30
34
  readAttachment(sessionId: string, attachmentId: string): Promise<Uint8Array | undefined>;
35
+ deleteAttachment(sessionId: string, attachmentId: string): Promise<boolean>;
31
36
  recoverStaleLock(sessionId: string): Promise<boolean>;
32
37
  repair(sessionId: string): Promise<SessionRepairResult>;
33
38
  withLock<T>(sessionId: string, action: () => Promise<T>): Promise<T>;
39
+ private withSessionPathsLock;
34
40
  private require;
35
41
  private requirePaths;
36
42
  private locate;
@@ -42,6 +48,11 @@ export declare class FileSessionStore implements SessionStore {
42
48
  private rebuildProjectIndex;
43
49
  private readSnapshot;
44
50
  private appendJournalLocked;
51
+ private removeUnpublishedSession;
52
+ private readSessionJournal;
53
+ private readJournalVersion;
54
+ private cacheJournalSnapshot;
55
+ private forgetJournalSnapshot;
45
56
  private readAttachmentMetadata;
46
57
  private corrupt;
47
58
  }
@@ -1,4 +1,4 @@
1
- import R from"node:crypto";import o from"node:fs/promises";import m from"node:path";import{CliError as h}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as d}from"../../domain/errors/error-codes.js";import{isRecord as F,isSessionEvent as _,isSessionMetadata as q,isTranscriptEntry as z}from"../../domain/session/session-schema.js";import{isGoalEventType as C,isPersistedGoalEventData as J}from"../../domain/orchestration/goal.js";import{isAlreadyExists as $,isFileNotFound as p}from"../filesystem/fs-errors.js";import{acquireAdvisoryFileLock as G,atomicWriteFile as x,isAdvisoryLockContention as U,releaseAdvisoryFileLock as K}from"../filesystem/atomic-file-store.js";import{isSafeProjectKey as O,resolveProjectSessionPaths as H,resolveProjectSessionPathsForKey as j}from"./project-session-paths.js";import{appendJournalRecord as y,appendJournalRecords as V,eventRecord as L,journalEvents as E,journalTranscript as P,latestMetadata as D,metadataRecord as T,readJournal as w,repairJournal as W,transcriptRecord as B}from"./session-journal.js";import{indexProjectSession as g,readProjectSessionIndex as Z,readSessionLocator as Q,removeIndexedSession as X}from"./session-index.js";import{RESOURCE_LIMITS as l}from"../../domain/runtime/resource-limits.js";import{readJsonFileBounded as I}from"../filesystem/bounded-json-reader.js";const b=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,v=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,Y=300*1e3;class vt{paths;constructor(t){this.paths=t}async create(t){const a=new Date().toISOString(),e={...t,id:R.randomUUID(),createdAt:a,updatedAt:a},r=H(this.paths,e.cwd,e.id);return await o.mkdir(r.attachmentsDirectory,{recursive:!0}),await y(r.journalFile,T(e)),await g(this.paths,e,r.projectKey),e}async get(t){const a=await this.locate(t);if(a!==void 0)try{const e=D(await w(a.journalFile));if(e===void 0)throw new Error("Session metadata is missing.");return e}catch(e){throw this.corrupt(t,e)}}async list(t){const a=[];for(const e of await this.projectKeys()){const r=j(this.paths,e,"00000000-0000-4000-8000-000000000000"),n=await this.readOrRebuildIndex(r.projectIndexFile,e);for(const i of Object.values(n))(t===void 0||i.projectFingerprint===t)&&a.push(i)}return a.sort((e,r)=>r.updatedAt.localeCompare(e.updatedAt))}async updateStatus(t,a){return this.withLock(t,async()=>{const r={...await this.require(t),status:a,updatedAt:new Date().toISOString()},n=await this.requirePaths(t);return await y(n.journalFile,T(r)),await g(this.paths,r,n.projectKey),r})}async rename(t,a){const e=a.trim().replace(/\s+/gu," ");if(e.length===0||e.length>120||/[\r\n]/u.test(e)||e.includes("\0"))throw new h(d.INVALID_ARGUMENT,"Session name is invalid.",{category:"session",userMessage:"Session name must be between 1 and 120 printable characters."});return this.withLock(t,async()=>{const n={...await this.require(t),name:e,updatedAt:new Date().toISOString()},i=await this.requirePaths(t);return await y(i.journalFile,T(n)),await g(this.paths,n,i.projectKey),n})}async appendEvent(t,a={}){const e=[{kind:"event",event:t}];a.locked===!0?await this.appendJournalLocked(t.sessionId,e):await this.appendJournal(t.sessionId,e)}async appendTranscript(t,a){await this.appendJournal(t,[{kind:"transcript",entry:a}])}async appendJournal(t,a){a.length!==0&&await this.withLock(t,()=>this.appendJournalLocked(t,a))}async readEvents(t){const a=await this.requirePaths(t);return await this.require(t),E(await w(a.journalFile))}async readTranscript(t){const a=await this.requirePaths(t);return await this.require(t),P(await w(a.journalFile))}async readHistory(t){return this.withLock(t,async()=>{const a=await this.requirePaths(t);await this.require(t);const e=await w(a.journalFile);return{events:E(e),transcript:P(e)}})}async delete(t){const a=await this.get(t);return a===void 0?!1:(await this.withLock(t,async()=>{const e=await this.requirePaths(t);await o.rm(e.journalFile,{force:!0}),await o.rm(e.sessionDirectory,{recursive:!0,force:!0}),await X(this.paths,a,e.projectKey)}),!0)}async fork(t,a={}){const e=await this.readSnapshot(t),r=e.metadata,n=await this.create({projectFingerprint:r.projectFingerprint,cwd:r.cwd,model:a.model??r.model,profile:a.profile??r.profile,status:"active"});try{return await this.withLock(n.id,async()=>{const i=await this.requirePaths(n.id);for(const c of e.events){const f=tt(c.data);await y(i.journalFile,L({...c,sessionId:n.id,...f===void 0?{}:{data:f}}))}for(const c of e.transcript)await y(i.journalFile,B(c));for(const[c,f]of e.attachments)f.attachment!==void 0&&await this.persistAttachment(n.id,{...f.attachment,id:c},f.bytes)}),n}catch(i){try{await this.delete(n.id)}catch(c){throw new AggregateError([i,c],"Session fork failed and cleanup was incomplete.")}throw i}}async compact(t,a,e={}){const r=a.trim();if(r.length===0)throw new h(d.SESSION_CORRUPTED,"Compaction summary cannot be empty.",{category:"session",userMessage:"Compaction summary cannot be empty."});const n=new Date().toISOString();await this.appendJournal(t,[{kind:"transcript",entry:{type:"system",timestamp:n,content:`[Compacted context]
2
- ${r}`,...e.turnId===void 0?{}:{turnId:e.turnId}}},{kind:"event",event:{type:"context.compacted",timestamp:n,sessionId:t,...e.turnId===void 0?{}:{turnId:e.turnId},data:{summary:r}}}])}async export(t){const a=await this.readSnapshot(t),e=[];for(const r of a.transcript)for(const n of r.attachmentIds??[]){if(e.some(f=>f.attachment.id===n))continue;const i=a.attachments.get(n);if(i===void 0)continue;const c=i.attachment??{id:n,name:n,mimeType:"application/octet-stream",sizeBytes:i.bytes.byteLength,source:"file"};e.push({attachment:c,dataBase64:Buffer.from(i.bytes).toString("base64")})}return{metadata:a.metadata,events:a.events,transcript:a.transcript,attachments:e}}async import(t,a,e){rt(t);const r=await this.create({projectFingerprint:a,cwd:e,model:t.metadata.model,profile:t.metadata.profile,status:"active"});try{for(const n of t.events){const i=et(n.data);await this.appendEvent({...n,sessionId:r.id,...i===void 0?{}:{data:i}})}for(const n of t.transcript)await this.appendTranscript(r.id,n);for(const n of t.attachments)await this.saveAttachment(r.id,n.attachment,Buffer.from(n.dataBase64,"base64"));return r}catch(n){try{await this.delete(r.id)}catch(i){throw new AggregateError([n,i],"Session import failed and cleanup was incomplete.")}throw n}}async saveAttachment(t,a,e){if(!v.test(a.id))throw new h(d.ATTACHMENT_INVALID_IMAGE,"Attachment id is invalid.",{category:"attachment",userMessage:"Attachment name is invalid."});if(a.sizeBytes<0||a.sizeBytes>l.maxAttachmentBytes)throw new h(d.ATTACHMENT_TOO_LARGE,"Attachment exceeds the allowed size.",{category:"attachment",userMessage:"Attachment exceeds the allowed size."});if(e.byteLength!==a.sizeBytes)throw new h(d.ATTACHMENT_INVALID_IMAGE,"Attachment size does not match metadata.",{category:"attachment",userMessage:"Attachment size does not match its metadata."});return this.withLock(t,()=>this.persistAttachment(t,a,e))}async persistAttachment(t,a,e){const r=await this.requirePaths(t);await this.require(t),await o.mkdir(r.attachmentsDirectory,{recursive:!0});const n=m.join(r.attachmentsDirectory,`${a.id}.bin`);return await o.writeFile(n,e,{flag:"wx",mode:384}).catch(async i=>{if(!$(i))throw i;await o.writeFile(n,e,{mode:384})}),await x(m.join(r.attachmentsDirectory,`${a.id}.json`),`${JSON.stringify(a,null,2)}
3
- `),{...a,storagePath:m.posix.join("attachments",`${a.id}.bin`)}}async readAttachment(t,a){const e=await this.requirePaths(t);if(await this.require(t),!v.test(a))return;const r=m.join(e.attachmentsDirectory,`${a}.bin`);try{if((await o.stat(r)).size>l.maxAttachmentBytes)throw new h(d.ATTACHMENT_TOO_LARGE,"Stored attachment exceeds the allowed size.",{category:"attachment",userMessage:"Stored attachment exceeds the allowed size."});return await o.readFile(r)}catch(n){if(p(n))return;throw n}}async recoverStaleLock(t){const a=await this.locate(t);if(a===void 0)return!1;let e;try{e=await o.stat(a.lockFile)}catch(n){if(p(n))return!1;throw n}if(Date.now()-e.mtimeMs<Y)return!1;let r={};try{r=await I(a.lockFile,4*1024)}catch{}return typeof r.pid=="number"&&at(r.pid)?!1:(await o.rm(a.lockFile,{force:!0}),!0)}async repair(t){const a=await this.requirePaths(t);return{eventsRemoved:await this.withLock(t,()=>W(a.journalFile)),transcriptRemoved:0}}async withLock(t,a){const e=await this.requirePaths(t);await o.mkdir(e.sessionDirectory,{recursive:!0});let r;try{r=await G(e.lockFile)}catch(n){const i=await U(n,e.lockFile);if(i&&await this.recoverStaleLock(t))return this.withLock(t,a);throw i?new h(d.SESSION_LOCKED,`Session is locked: ${t}`,{category:"session",userMessage:"The session is being used by another process. Try again later.",retryable:!0}):n}try{return await a()}finally{await K(r,e.lockFile)}}async require(t){const a=await this.get(t);if(a===void 0)throw new h(d.SESSION_NOT_FOUND,`Session not found: ${t}`,{category:"session",userMessage:`Session not found: ${t}.`});return a}async requirePaths(t){const a=await this.locate(t);if(a===void 0)throw new h(d.SESSION_NOT_FOUND,`Session not found: ${t}`,{category:"session",userMessage:`Session not found: ${t}.`});return a}async locate(t){if(!b.test(t))return;const e=(await Q(this.paths)).sessions[t];if(typeof e=="string"&&O(e)){const r=j(this.paths,e,t);if(await N(r.journalFile))return r}return this.locateByScan(t)}async locateByScan(t){for(const a of await this.projectKeys()){const e=j(this.paths,a,t);if(await N(e.journalFile))return e}}async projectKeys(){try{return(await o.readdir(this.paths.projectsDir,{withFileTypes:!0})).filter(t=>t.isDirectory()&&O(t.name)).map(t=>t.name)}catch(t){if(p(t))return[];throw t}}async readOrRebuildIndex(t,a){try{const e=(await Z(t,a)).sessions;return await this.indexMatchesJournals(a,e)?e:this.rebuildProjectIndex(a)}catch{return this.rebuildProjectIndex(a)}}async indexMatchesJournals(t,a){const e=await this.projectJournalIds(t),r=Object.keys(a);return e.length===r.length&&e.every(n=>a[n]!==void 0)}async projectJournalIds(t){const a=m.join(this.paths.projectsDir,t);try{return(await o.readdir(a,{withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(".jsonl")).map(e=>e.name.slice(0,-6)).filter(e=>b.test(e))}catch(e){if(p(e))return[];throw e}}async rebuildProjectIndex(t){const a={},e=m.join(this.paths.projectsDir,t);for(const n of await o.readdir(e,{withFileTypes:!0}))if(!(!n.isFile()||!n.name.endsWith(".jsonl")))try{const i=D(await w(m.join(e,n.name)));i!==void 0&&(a[i.id]=i)}catch{}const r=m.join(e,"index.json");await o.mkdir(e,{recursive:!0}),await x(r,`${JSON.stringify({projectKey:t,sessions:a},null,2)}
4
- `);for(const n of Object.values(a))await g(this.paths,n,t);return a}async readSnapshot(t){return this.withLock(t,async()=>{const a=await this.require(t),e=await this.requirePaths(t),r=await w(e.journalFile),n=E(r),i=P(r),c=new Map;for(const f of i)for(const S of f.attachmentIds??[]){if(c.has(S))continue;const k=await this.readAttachment(t,S);k!==void 0&&c.set(S,{bytes:k,attachment:await this.readAttachmentMetadata(e,S)})}return{metadata:a,events:n,transcript:i,attachments:c}})}async appendJournalLocked(t,a){const e=await this.requirePaths(t);await this.require(t);const r=a.map(n=>{if(n.kind==="event"&&n.event.sessionId!==t)throw new h(d.SESSION_CORRUPTED,"Cannot append an event to a different session.",{category:"session",userMessage:"Session event data is invalid."});return n.kind==="event"?L(n.event):B(n.entry)});await V(e.journalFile,r)}async readAttachmentMetadata(t,a){try{return st(await I(m.join(t.attachmentsDirectory,`${a}.json`),l.configFileBytes))}catch(e){if(p(e))return;throw e}}corrupt(t,a){return new h(d.SESSION_CORRUPTED,`Session metadata is corrupted: ${t}`,{category:"session",userMessage:"Session is corrupted and its metadata cannot be read.",cause:a})}}function tt(s){return M(s)}function et(s){return M(s)}function M(s){if(s===void 0||typeof s.goal!="object"||s.goal===null)return s;const t=s.goal;return t.status!=="active"?s:{...s,goal:{...t,status:"paused",updatedAt:new Date().toISOString()},reason:"Explicit resume is required after fork or import."}}async function N(s){try{return await o.access(s),!0}catch(t){if(p(t))return!1;throw t}}function at(s){if(s===process.pid)return!0;try{return process.kill(s,0),!0}catch{return!1}}function rt(s){if(!q(s.metadata)||!Array.isArray(s.events)||!Array.isArray(s.transcript)||!Array.isArray(s.attachments))throw u("Session export file is invalid.");if(s.events.length>l.sessionEvents||s.transcript.length>l.sessionTranscriptEntries||s.attachments.length>l.sessionAttachments)throw u("Session export exceeds the supported entry limits.");for(const e of s.events){if(!_(e))throw u("Session export contains an invalid event.");if(C(e.type)&&!J(e.data))throw u("Session export contains an invalid goal event.");if(A(e.type)>256||A(e.timestamp)>128||A(e.sessionId)>128)throw u("Session event metadata is too large.")}const t=new Set;let a=0;for(const e of s.transcript){if(!z(e)||A(e.content)>l.sessionTextBytes)throw u("Session export contains an invalid transcript entry.");if(e.attachmentIds!==void 0&&(!Array.isArray(e.attachmentIds)||e.attachmentIds.some(r=>typeof r!="string"||!v.test(r))))throw u("Session transcript contains invalid attachment references.")}for(const e of s.attachments){if(!nt(e))throw u("Session export contains an invalid attachment.");const r=e.attachment;if(typeof r.id!="string"||!v.test(r.id)||t.has(r.id)||typeof r.name!="string"||typeof r.mimeType!="string"||typeof r.sizeBytes!="number"||!Number.isSafeInteger(r.sizeBytes)||r.sizeBytes<0||r.sizeBytes>l.maxAttachmentBytes||r.source!=="clipboard"&&r.source!=="file")throw u("Session export contains invalid attachment metadata.");const n=Buffer.from(e.dataBase64,"base64");if(n.toString("base64")!==e.dataBase64||n.byteLength!==r.sizeBytes)throw u("Session export contains an invalid attachment payload.");if(a+=n.byteLength,a>l.sessionAttachmentTotalBytes)throw u("Session export exceeds the total attachment limit.");t.add(r.id)}}function nt(s){if(!F(s)||!F(s.attachment)||typeof s.dataBase64!="string")return!1;const t=s.attachment;return typeof t.id=="string"&&typeof t.name=="string"&&typeof t.mimeType=="string"&&typeof t.sizeBytes=="number"&&Number.isSafeInteger(t.sizeBytes)&&(t.source==="clipboard"||t.source==="file")}function A(s){return Buffer.byteLength(s,"utf8")}function u(s){return new h(d.SESSION_CORRUPTED,s,{category:"session",userMessage:s})}function st(s){if(typeof s!="object"||s===null)throw new Error("Invalid attachment metadata.");const t=s;if(typeof t.id!="string"||typeof t.name!="string"||typeof t.mimeType!="string"||typeof t.sizeBytes!="number"||t.source!=="clipboard"&&t.source!=="file")throw new Error("Invalid attachment metadata.");return s}export{vt as FileSessionStore};
1
+ import R from"node:crypto";import h from"node:fs/promises";import d from"node:path";import{CliError as u}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as l}from"../../domain/errors/error-codes.js";import{isRecord as T,isSessionEvent as I,isSessionMetadata as q,isTranscriptEntry as H}from"../../domain/session/session-schema.js";import{isGoalEventType as $,isPersistedGoalEventData as V}from"../../domain/orchestration/goal.js";import{isAlreadyExists as U,isFileNotFound as y}from"../filesystem/fs-errors.js";import{acquireAdvisoryFileLock as G,atomicWriteFile as M,isAdvisoryLockContention as K,recoverStaleAdvisoryLock as J,releaseAdvisoryFileLock as W}from"../filesystem/atomic-file-store.js";import{isSafeProjectKey as L,resolveProjectSessionPaths as Z,resolveProjectSessionPathsForKey as v}from"./project-session-paths.js";import{appendJournalRecord as S,appendJournalRecords as Q,eventRecord as b,journalEvents as F,journalTranscript as E,latestMetadata as O,metadataRecord as k,readJournal as B,repairJournal as X,transcriptRecord as C}from"./session-journal.js";import{indexProjectSession as g,readProjectSessionIndex as Y,readSessionLocator as tt,removeIndexedSession as et}from"./session-index.js";import{RESOURCE_LIMITS as m}from"../../domain/runtime/resource-limits.js";import{readJsonFileBounded as at}from"../filesystem/bounded-json-reader.js";import{SessionJournalHealth as nt}from"./session-journal-health.js";import{ATTACHMENT_ID_PATTERN as j,SESSION_ID_PATTERN as D,SESSION_LOCK_STALE_MS as N}from"./session-constants.js";class xt{paths;journalHealth=new nt;journalSnapshotCache=new Map;journalSnapshotCacheBytes=0;constructor(t){this.paths=t}async create(t){const e=await this.createUnpublished(t);return await g(this.paths,e.metadata,e.sessionPaths.projectKey),e.metadata}async createUnpublished(t){const e=new Date().toISOString(),a={...t,id:R.randomUUID(),createdAt:e,updatedAt:e},n=Z(this.paths,a.cwd,a.id);return await h.mkdir(n.attachmentsDirectory,{recursive:!0}),await S(n.journalFile,k(a)),await this.journalHealth.markValid(n.journalFile),{metadata:a,sessionPaths:n}}async get(t){const e=await this.locate(t);if(e===void 0)return;const a=(await this.readSessionJournal(t,e)).metadata;if(a===void 0)throw this.corrupt(t,new Error("Session metadata is missing."));return a}async list(t){const e=[];for(const a of await this.projectKeys()){const n=v(this.paths,a,"00000000-0000-4000-8000-000000000000"),r=await this.readOrRebuildIndex(n.projectIndexFile,a);for(const s of Object.values(r))(t===void 0||s.projectFingerprint===t)&&e.push(s)}return e.sort((a,n)=>n.updatedAt.localeCompare(a.updatedAt))}async updateStatus(t,e){return this.withLock(t,async()=>{const n={...await this.require(t),status:e,updatedAt:new Date().toISOString()},r=await this.requirePaths(t);return await S(r.journalFile,k(n)),await this.journalHealth.markValid(r.journalFile),await g(this.paths,n,r.projectKey),n})}async rename(t,e){const a=e.trim().replace(/\s+/gu," ");if(a.length===0||a.length>120||/[\r\n]/u.test(a)||a.includes("\0"))throw new u(l.INVALID_ARGUMENT,"Session name is invalid.",{category:"session",userMessage:"Session name must be between 1 and 120 printable characters."});return this.withLock(t,async()=>{const r={...await this.require(t),name:a,updatedAt:new Date().toISOString()},s=await this.requirePaths(t);return await S(s.journalFile,k(r)),await this.journalHealth.markValid(s.journalFile),await g(this.paths,r,s.projectKey),r})}async appendEvent(t,e={}){const a=[{kind:"event",event:t}];e.locked===!0?await this.appendJournalLocked(t.sessionId,a):await this.appendJournal(t.sessionId,a)}async appendTranscript(t,e){await this.appendJournal(t,[{kind:"transcript",entry:e}])}async appendJournal(t,e){e.length!==0&&await this.withLock(t,()=>this.appendJournalLocked(t,e))}async readEvents(t){const e=await this.readSessionJournal(t);if(e.metadata===void 0)throw this.corrupt(t,new Error("Session metadata is missing."));return F(e.records)}async readTranscript(t){const e=await this.readSessionJournal(t);if(e.metadata===void 0)throw this.corrupt(t,new Error("Session metadata is missing."));return E(e.records)}async readHistory(t){return this.withLock(t,async()=>{const e=await this.readSessionJournal(t);if(e.metadata===void 0)throw this.corrupt(t,new Error("Session metadata is missing."));const a=e.records;return{events:F(a),transcript:E(a)}})}async delete(t){const e=await this.get(t);return e===void 0?!1:(await this.withLock(t,async()=>{const a=await this.requirePaths(t);await h.rm(a.journalFile,{force:!0}),await h.rm(a.sessionDirectory,{recursive:!0,force:!0}),this.forgetJournalSnapshot(a.journalFile),this.journalHealth.forget(a.journalFile),await et(this.paths,e,a.projectKey)}),!0)}async fork(t,e={}){const a=await this.readSnapshot(t),n=a.metadata,r=await this.create({projectFingerprint:n.projectFingerprint,cwd:n.cwd,model:e.model??n.model,profile:e.profile??n.profile,status:"active"});try{return await this.withLock(r.id,async()=>{const s=await this.requirePaths(r.id);for(const o of a.events){const c=rt(o.data);await S(s.journalFile,b({...o,sessionId:r.id,...c===void 0?{}:{data:c}}))}for(const o of a.transcript)await S(s.journalFile,C(o));await this.journalHealth.markValid(s.journalFile);for(const[o,c]of a.attachments)c.attachment!==void 0&&await this.persistAttachment(r.id,{...c.attachment,id:o},c.bytes)}),r}catch(s){try{await this.delete(r.id)}catch(o){throw new AggregateError([s,o],"Session fork failed and cleanup was incomplete.")}throw s}}async compact(t,e,a={}){const n=e.trim();if(n.length===0)throw new u(l.SESSION_CORRUPTED,"Compaction summary cannot be empty.",{category:"session",userMessage:"Compaction summary cannot be empty."});const r=new Date().toISOString();await this.appendJournal(t,[{kind:"transcript",entry:{type:"system",timestamp:r,content:`[Compacted context]
2
+ ${n}`,...a.turnId===void 0?{}:{turnId:a.turnId}}},{kind:"event",event:{type:"context.compacted",timestamp:r,sessionId:t,...a.turnId===void 0?{}:{turnId:a.turnId},data:{summary:n}}}])}async export(t){const e=await this.readSnapshot(t),a=[];for(const n of e.transcript)for(const r of n.attachmentIds??[]){if(a.some(c=>c.attachment.id===r))continue;const s=e.attachments.get(r);if(s===void 0)continue;const o=s.attachment??{id:r,name:r,mimeType:"application/octet-stream",sizeBytes:s.bytes.byteLength,source:"file"};a.push({attachment:o,dataBase64:Buffer.from(s.bytes).toString("base64")})}return{metadata:e.metadata,events:e.events,transcript:e.transcript,attachments:a}}async import(t,e,a){ct(t);const n=await this.createUnpublished({projectFingerprint:e,cwd:a,model:t.metadata.model,profile:t.metadata.profile,status:"active"}),{metadata:r,sessionPaths:s}=n;try{return await this.withSessionPathsLock(r.id,s,async()=>{const o=[...t.events.map(c=>{const p=st(c.data);return{kind:"event",event:{...c,sessionId:r.id,...p===void 0?{}:{data:p}}}}),...t.transcript.map(c=>({kind:"transcript",entry:c}))];await this.appendJournalLocked(r.id,o,s);for(const c of t.attachments)await this.persistAttachment(r.id,c.attachment,Buffer.from(c.dataBase64,"base64"),{sessionPaths:s,requirePublished:!1})}),await g(this.paths,r,s.projectKey),r}catch(o){try{await this.removeUnpublishedSession(s)}catch(c){throw new AggregateError([o,c],"Session import failed and cleanup was incomplete.")}throw o}}async saveAttachment(t,e,a){if(!j.test(e.id))throw new u(l.ATTACHMENT_INVALID_IMAGE,"Attachment id is invalid.",{category:"attachment",userMessage:"Attachment name is invalid."});if(e.sizeBytes<0||e.sizeBytes>m.maxAttachmentBytes)throw new u(l.ATTACHMENT_TOO_LARGE,"Attachment exceeds the allowed size.",{category:"attachment",userMessage:"Attachment exceeds the allowed size."});if(a.byteLength!==e.sizeBytes)throw new u(l.ATTACHMENT_INVALID_IMAGE,"Attachment size does not match metadata.",{category:"attachment",userMessage:"Attachment size does not match its metadata."});return this.withLock(t,()=>this.persistAttachment(t,e,a))}async persistAttachment(t,e,a,n={}){const r=n.sessionPaths??await this.requirePaths(t);n.requirePublished!==!1&&await this.require(t),await h.mkdir(r.attachmentsDirectory,{recursive:!0});const s=await this.readAttachmentMetadata(r,e.id),o=s?.storagePath===void 0?await ot(r.attachmentsDirectory,e.storageName,e.id):d.basename(s.storagePath),c=d.join(r.attachmentsDirectory,o);await h.writeFile(c,a,{flag:"wx",mode:384}).catch(async w=>{if(!U(w))throw w;await h.writeFile(c,a,{mode:384})});const p={...e,storagePath:d.posix.join("attachments",o)};return await M(d.join(r.attachmentsDirectory,`${e.id}.json`),`${JSON.stringify(p,null,2)}
3
+ `),p}async readAttachment(t,e){const a=await this.requirePaths(t);if(await this.require(t),!j.test(e))return;const n=await this.readAttachmentMetadata(a,e),r=d.join(a.attachmentsDirectory,z(n,e));try{if((await h.stat(r)).size>m.maxAttachmentBytes)throw new u(l.ATTACHMENT_TOO_LARGE,"Stored attachment exceeds the allowed size.",{category:"attachment",userMessage:"Stored attachment exceeds the allowed size."});return await h.readFile(r)}catch(s){if(y(s))return;throw s}}async deleteAttachment(t,e){return j.test(e)?this.withLock(t,async()=>{const a=await this.requirePaths(t);await this.require(t);const n=await this.readAttachmentMetadata(a,e),r=d.join(a.attachmentsDirectory,z(n,e)),s=d.join(a.attachmentsDirectory,`${e}.json`);let o=!1;for(const c of[r,s])try{await h.unlink(c),o=!0}catch(p){if(!y(p))throw p}return o}):!1}async recoverStaleLock(t){const e=await this.locate(t);return e===void 0?!1:J(e.lockFile,N)}async repair(t){const e=await this.requirePaths(t),a=await this.withLock(t,()=>X(e.journalFile));return this.forgetJournalSnapshot(e.journalFile),await this.journalHealth.markValid(e.journalFile),{eventsRemoved:a,transcriptRemoved:0}}async withLock(t,e){const a=await this.requirePaths(t);return this.withSessionPathsLock(t,a,e)}async withSessionPathsLock(t,e,a){await h.mkdir(e.sessionDirectory,{recursive:!0});let n;try{n=await G(e.lockFile)}catch(r){const s=await K(r,e.lockFile);if(s&&await J(e.lockFile,N))return this.withSessionPathsLock(t,e,a);throw s?new u(l.SESSION_LOCKED,`Session is locked: ${t}`,{category:"session",userMessage:"The session is being used by another process. Try again later.",retryable:!0}):r}try{return await a()}finally{await W(n,e.lockFile)}}async require(t){const e=await this.get(t);if(e===void 0)throw new u(l.SESSION_NOT_FOUND,`Session not found: ${t}`,{category:"session",userMessage:`Session not found: ${t}.`});return e}async requirePaths(t){const e=await this.locate(t);if(e===void 0)throw new u(l.SESSION_NOT_FOUND,`Session not found: ${t}`,{category:"session",userMessage:`Session not found: ${t}.`});return e}async locate(t){if(!D.test(t))return;const a=(await tt(this.paths)).sessions[t];if(typeof a=="string"&&L(a)){const n=v(this.paths,a,t);if(await P(n.journalFile))return n}return this.locateByScan(t)}async locateByScan(t){for(const e of await this.projectKeys()){const a=v(this.paths,e,t);if(await P(a.journalFile))return a}}async projectKeys(){try{return(await h.readdir(this.paths.projectsDir,{withFileTypes:!0})).filter(t=>t.isDirectory()&&L(t.name)).map(t=>t.name)}catch(t){if(y(t))return[];throw t}}async readOrRebuildIndex(t,e){try{const a=(await Y(t,e)).sessions;return await this.indexMatchesJournals(e,a)?a:this.rebuildProjectIndex(e)}catch{return this.rebuildProjectIndex(e)}}async indexMatchesJournals(t,e){const a=await this.projectJournalIds(t),n=Object.keys(e);return a.length===n.length&&a.every(r=>e[r]!==void 0)}async projectJournalIds(t){const e=d.join(this.paths.projectsDir,t);try{return(await h.readdir(e,{withFileTypes:!0})).filter(a=>a.isFile()&&a.name.endsWith(".jsonl")).map(a=>a.name.slice(0,-6)).filter(a=>D.test(a))}catch(a){if(y(a))return[];throw a}}async rebuildProjectIndex(t){const e={},a=d.join(this.paths.projectsDir,t);for(const r of await h.readdir(a,{withFileTypes:!0}))if(!(!r.isFile()||!r.name.endsWith(".jsonl")))try{const s=O(await B(d.join(a,r.name)));s!==void 0&&(e[s.id]=s)}catch{}const n=d.join(a,"index.json");await h.mkdir(a,{recursive:!0}),await M(n,`${JSON.stringify({projectKey:t,sessions:e},null,2)}
4
+ `);for(const r of Object.values(e))await g(this.paths,r,t);return e}async readSnapshot(t){return this.withLock(t,async()=>{const e=await this.readSessionJournal(t),a=e.metadata;if(a===void 0)throw this.corrupt(t,new Error("Session metadata is missing."));const n=e.sessionPaths,r=e.records,s=F(r),o=E(r),c=new Map;for(const p of o)for(const w of p.attachmentIds??[]){if(c.has(w))continue;const x=await this.readAttachment(t,w);x!==void 0&&c.set(w,{bytes:x,attachment:await this.readAttachmentMetadata(n,w)})}return{metadata:a,events:s,transcript:o,attachments:c}})}async appendJournalLocked(t,e,a){const n=a??await this.requirePaths(t);try{if(!await this.journalHealth.ensureValid(n.journalFile))throw new Error("Session metadata is missing.")}catch(s){throw this.corrupt(t,s)}const r=e.map(s=>{if(s.kind==="event"&&s.event.sessionId!==t)throw new u(l.SESSION_CORRUPTED,"Cannot append an event to a different session.",{category:"session",userMessage:"Session event data is invalid."});return s.kind==="event"?b(s.event):C(s.entry)});await Q(n.journalFile,r),this.forgetJournalSnapshot(n.journalFile),await this.journalHealth.markValid(n.journalFile)}async removeUnpublishedSession(t){await h.rm(t.journalFile,{force:!0}),await h.rm(t.sessionDirectory,{recursive:!0,force:!0}),this.forgetJournalSnapshot(t.journalFile),this.journalHealth.forget(t.journalFile)}async readSessionJournal(t,e){const a=e??await this.requirePaths(t);try{const n=await this.readJournalVersion(a.journalFile),r=n===void 0?void 0:this.journalSnapshotCache.get(a.journalFile);if(n!==void 0&&r!==void 0&&it(r,n))return this.journalSnapshotCache.delete(a.journalFile),this.journalSnapshotCache.set(a.journalFile,r),await this.journalHealth.markValid(a.journalFile,r.metadata!==void 0),{sessionPaths:a,records:r.records,metadata:r.metadata};const s=await B(a.journalFile),o=O(s),c=await this.readJournalVersion(a.journalFile);return c!==void 0&&this.cacheJournalSnapshot(a.journalFile,c,s,o),await this.journalHealth.markValid(a.journalFile,o!==void 0),{sessionPaths:a,records:s,metadata:o}}catch(n){throw this.corrupt(t,n)}}async readJournalVersion(t){try{const e=await h.stat(t);return{size:e.size,mtimeMs:e.mtimeMs,ctimeMs:e.ctimeMs}}catch(e){if(y(e))return;throw e}}cacheJournalSnapshot(t,e,a,n){if(this.forgetJournalSnapshot(t),e.size>m.sessionJournalCacheMaxBytes)return;const r={...e,records:a,metadata:n};for(this.journalSnapshotCache.set(t,r),this.journalSnapshotCacheBytes+=e.size;this.journalSnapshotCache.size>m.sessionJournalCacheMaxEntries||this.journalSnapshotCacheBytes>m.sessionJournalCacheMaxBytes;){const s=this.journalSnapshotCache.keys().next().value;if(s===void 0)break;this.forgetJournalSnapshot(s)}}forgetJournalSnapshot(t){const e=this.journalSnapshotCache.get(t);e!==void 0&&(this.journalSnapshotCacheBytes-=e.size),this.journalSnapshotCache.delete(t)}async readAttachmentMetadata(t,e){try{return dt(await at(d.join(t.attachmentsDirectory,`${e}.json`),m.configFileBytes))}catch(a){if(y(a))return;throw a}}corrupt(t,e){return new u(l.SESSION_CORRUPTED,`Session metadata is corrupted: ${t}`,{category:"session",userMessage:"Session is corrupted and its metadata cannot be read.",cause:e})}}function rt(i){return _(i)}function st(i){return _(i)}function _(i){if(i===void 0||typeof i.goal!="object"||i.goal===null)return i;const t=i.goal;return t.status!=="active"?i:{...i,goal:{...t,status:"paused",updatedAt:new Date().toISOString()},reason:"Explicit resume is required after fork or import."}}async function P(i){try{return await h.access(i),!0}catch(t){if(y(t))return!1;throw t}}function z(i,t){const e=i?.storagePath;if(typeof e=="string"&&e.startsWith("attachments/")){const a=d.basename(e);if(a.length>0&&a!=="."&&a!=="..")return a}return`${t}.bin`}function it(i,t){return i.size===t.size&&i.mtimeMs===t.mtimeMs&&i.ctimeMs===t.ctimeMs}async function ot(i,t,e){if(t===void 0)return`${e}.bin`;const a=d.basename(t).replace(/[^A-Za-z0-9._-]/gu,"_").slice(0,120)||`${e}.bin`,n=d.extname(a),r=n.length===0?a:a.slice(0,-n.length);for(let s=0;s<1e4;s+=1){const o=s===0?a:`${r}-${s}${n}`;if(!await P(d.join(i,o)))return o}throw new u(l.ATTACHMENT_TOO_LARGE,"Too many attachments share the same filename.",{category:"attachment",userMessage:"Too many attachments share the same filename."})}function ct(i){if(!q(i.metadata)||!Array.isArray(i.events)||!Array.isArray(i.transcript)||!Array.isArray(i.attachments))throw f("Session export file is invalid.");if(i.events.length>m.sessionEvents||i.transcript.length>m.sessionTranscriptEntries||i.attachments.length>m.sessionAttachments)throw f("Session export exceeds the supported entry limits.");for(const a of i.events){if(!I(a))throw f("Session export contains an invalid event.");if($(a.type)&&!V(a.data))throw f("Session export contains an invalid goal event.");if(A(a.type)>256||A(a.timestamp)>128||A(a.sessionId)>128)throw f("Session event metadata is too large.")}const t=new Set;let e=0;for(const a of i.transcript){if(!H(a)||A(a.content)>m.sessionTextBytes)throw f("Session export contains an invalid transcript entry.");if(a.attachmentIds!==void 0&&(!Array.isArray(a.attachmentIds)||a.attachmentIds.some(n=>typeof n!="string"||!j.test(n))))throw f("Session transcript contains invalid attachment references.")}for(const a of i.attachments){if(!ht(a))throw f("Session export contains an invalid attachment.");const n=a.attachment;if(typeof n.id!="string"||!j.test(n.id)||t.has(n.id)||typeof n.name!="string"||typeof n.mimeType!="string"||typeof n.sizeBytes!="number"||!Number.isSafeInteger(n.sizeBytes)||n.sizeBytes<0||n.sizeBytes>m.maxAttachmentBytes||n.source!=="clipboard"&&n.source!=="file")throw f("Session export contains invalid attachment metadata.");const r=Buffer.from(a.dataBase64,"base64");if(r.toString("base64")!==a.dataBase64||r.byteLength!==n.sizeBytes)throw f("Session export contains an invalid attachment payload.");if(e+=r.byteLength,e>m.sessionAttachmentTotalBytes)throw f("Session export exceeds the total attachment limit.");t.add(n.id)}}function ht(i){if(!T(i)||!T(i.attachment)||typeof i.dataBase64!="string")return!1;const t=i.attachment;return typeof t.id=="string"&&typeof t.name=="string"&&typeof t.mimeType=="string"&&typeof t.sizeBytes=="number"&&Number.isSafeInteger(t.sizeBytes)&&(t.source==="clipboard"||t.source==="file")}function A(i){return Buffer.byteLength(i,"utf8")}function f(i){return new u(l.SESSION_CORRUPTED,i,{category:"session",userMessage:i})}function dt(i){if(typeof i!="object"||i===null)throw new Error("Invalid attachment metadata.");const t=i;if(typeof t.id!="string"||typeof t.name!="string"||typeof t.mimeType!="string"||typeof t.sizeBytes!="number"||t.source!=="clipboard"&&t.source!=="file")throw new Error("Invalid attachment metadata.");return i}export{xt as FileSessionStore};
@@ -0,0 +1,3 @@
1
+ export declare const SESSION_ID_PATTERN: RegExp;
2
+ export declare const ATTACHMENT_ID_PATTERN: RegExp;
3
+ export declare const SESSION_LOCK_STALE_MS: number;
@@ -0,0 +1 @@
1
+ const a=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,S=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,T=3e5;export{S as ATTACHMENT_ID_PATTERN,a as SESSION_ID_PATTERN,T as SESSION_LOCK_STALE_MS};
@@ -1,3 +1,3 @@
1
- import c from"node:path";import{atomicWriteFile as f,withFileLock as a}from"../filesystem/atomic-file-store.js";import{isFileNotFound as l}from"../filesystem/fs-errors.js";import{resolveProjectSessionPathsForKey as p}from"./project-session-paths.js";import{readJsonFileBounded as j}from"../filesystem/bounded-json-reader.js";import{RESOURCE_LIMITS as w}from"../../domain/runtime/resource-limits.js";async function x(o,s){try{return m(await j(o,w.configFileBytes),s)}catch(t){if(l(t))return{projectKey:s,sessions:{}};throw t}}async function y(o,s,t){await f(o,`${JSON.stringify({projectKey:s,sessions:t},null,2)}
2
- `)}async function I(o){const s=c.join(o.projectsDir,"locator.json");try{return g(await j(s,w.configFileBytes))}catch(t){if(l(t))return{sessions:{}};throw t}}function m(o,s){if(!e(o)||o.projectKey!==s||!e(o.sessions))throw new Error("Invalid project session index.");for(const t of Object.values(o.sessions))if(!u(t))throw new Error("Invalid project session metadata.");return{projectKey:s,sessions:o.sessions}}function g(o){if(!e(o)||!e(o.sessions)||Object.values(o.sessions).some(s=>typeof s!="string"))throw new Error("Invalid session locator index.");return{sessions:o.sessions}}function u(o){return e(o)?typeof o.id=="string"&&typeof o.projectFingerprint=="string"&&typeof o.cwd=="string"&&(typeof o.model=="string"||o.model===null)&&(typeof o.profile=="string"||o.profile===null)&&(o.status==="active"||o.status==="completed"||o.status==="failed"||o.status==="cancelled")&&typeof o.createdAt=="string"&&typeof o.updatedAt=="string":!1}function e(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}async function F(o,s){await f(c.join(o.projectsDir,"locator.json"),`${JSON.stringify({sessions:s},null,2)}
3
- `)}async function A(o,s,t){const n=p(o,t,s.id);await a(n.projectIndexFile,async()=>{const i=await x(n.projectIndexFile,t);await y(n.projectIndexFile,t,{...i.sessions,[s.id]:s})});const d=c.join(o.projectsDir,"locator.json");await a(d,async()=>{const i=await I(o);await F(o,{...i.sessions,[s.id]:t})})}async function D(o,s,t){const n=p(o,t,s.id);await a(n.projectIndexFile,async()=>{const r={...(await x(n.projectIndexFile,t)).sessions};delete r[s.id],await y(n.projectIndexFile,t,r)});const d=c.join(o.projectsDir,"locator.json");await a(d,async()=>{const r={...(await I(o)).sessions};delete r[s.id],await F(o,r)})}export{A as indexProjectSession,x as readProjectSessionIndex,I as readSessionLocator,D as removeIndexedSession,y as writeProjectSessionIndex,F as writeSessionLocator};
1
+ import c from"node:path";import{atomicWriteFile as p,withFileLock as a}from"../filesystem/atomic-file-store.js";import{isFileNotFound as l}from"../filesystem/fs-errors.js";import{resolveProjectSessionPathsForKey as w}from"./project-session-paths.js";import{readJsonFileBounded as x}from"../filesystem/bounded-json-reader.js";import{RESOURCE_LIMITS as d}from"../../domain/runtime/resource-limits.js";async function j(o,s){try{return m(await x(o,d.sessionIndexBytes),s)}catch(t){if(l(t))return{projectKey:s,sessions:{}};throw t}}async function y(o,s,t){const e=`${JSON.stringify({projectKey:s,sessions:t},null,2)}
2
+ `;if(Buffer.byteLength(e,"utf8")>d.sessionIndexBytes)throw new Error("The project session index exceeds the supported size limit.");await p(o,e)}async function I(o){const s=c.join(o.projectsDir,"locator.json");try{return h(await x(s,d.sessionIndexBytes))}catch(t){if(l(t))return{sessions:{}};throw t}}function m(o,s){if(!r(o)||o.projectKey!==s||!r(o.sessions))throw new Error("Invalid project session index.");for(const t of Object.values(o.sessions))if(!F(t))throw new Error("Invalid project session metadata.");return{projectKey:s,sessions:o.sessions}}function h(o){if(!r(o)||!r(o.sessions)||Object.values(o.sessions).some(s=>typeof s!="string"))throw new Error("Invalid session locator index.");return{sessions:o.sessions}}function F(o){return r(o)?typeof o.id=="string"&&typeof o.projectFingerprint=="string"&&typeof o.cwd=="string"&&(typeof o.model=="string"||o.model===null)&&(typeof o.profile=="string"||o.profile===null)&&(o.status==="active"||o.status==="completed"||o.status==="failed"||o.status==="cancelled")&&typeof o.createdAt=="string"&&typeof o.updatedAt=="string":!1}function r(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}async function u(o,s){const t=`${JSON.stringify({sessions:s},null,2)}
3
+ `;if(Buffer.byteLength(t,"utf8")>d.sessionIndexBytes)throw new Error("The session locator exceeds the supported size limit.");await p(c.join(o.projectsDir,"locator.json"),t)}async function b(o,s,t){const e=w(o,t,s.id);await a(e.projectIndexFile,async()=>{const n=await j(e.projectIndexFile,t);await y(e.projectIndexFile,t,{...n.sessions,[s.id]:s})});const f=c.join(o.projectsDir,"locator.json");await a(f,async()=>{const n=await I(o);await u(o,{...n.sessions,[s.id]:t})})}async function O(o,s,t){const e=w(o,t,s.id);await a(e.projectIndexFile,async()=>{const i={...(await j(e.projectIndexFile,t)).sessions};delete i[s.id],await y(e.projectIndexFile,t,i)});const f=c.join(o.projectsDir,"locator.json");await a(f,async()=>{const i={...(await I(o)).sessions};delete i[s.id],await u(o,i)})}export{b as indexProjectSession,j as readProjectSessionIndex,I as readSessionLocator,O as removeIndexedSession,y as writeProjectSessionIndex,u as writeSessionLocator};
@@ -0,0 +1,7 @@
1
+ /** Avoids reparsing an unchanged journal on every append while detecting external writes. */
2
+ export declare class SessionJournalHealth {
3
+ private readonly entries;
4
+ ensureValid(filePath: string): Promise<boolean>;
5
+ markValid(filePath: string, hasMetadata?: boolean): Promise<void>;
6
+ forget(filePath: string): void;
7
+ }
@@ -0,0 +1 @@
1
+ import c from"node:fs/promises";import{latestMetadata as m,readJournal as u}from"./session-journal.js";class g{entries=new Map;async ensureValid(e){const s=await n(e),a=this.entries.get(e);if(a!==void 0&&o(a.signature,s))return a.hasMetadata;const r=await u(e),i=m(r)!==void 0;return this.entries.set(e,{signature:await n(e),hasMetadata:i}),i}async markValid(e,s=!0){this.entries.set(e,{signature:await n(e),hasMetadata:s})}forget(e){this.entries.delete(e)}}async function n(t){const e=await c.stat(t);return{size:e.size,mtimeMs:e.mtimeMs,ctimeMs:e.ctimeMs}}function o(t,e){return t.size===e.size&&t.mtimeMs===e.mtimeMs&&t.ctimeMs===e.ctimeMs}export{g as SessionJournalHealth};
@@ -2,14 +2,18 @@ import type { ToolDefinition } from '@lotagate/sdk';
2
2
  import type { ToolExecutionContext, ToolExecutor, ToolInfo, ToolResult } from '@lotagate/agent-sdk';
3
3
  import type { ToolActivityObserver } from '../../ports/tool-activity.js';
4
4
  import { type HostPlatformContext } from '../platform/host-platform.js';
5
+ import type { Logger } from '../../ports/logger.js';
6
+ export type ShellToolEnvironment = 'host' | 'linux-guest';
5
7
  /** Exposes the same shell capability definitions to runtime and context accounting. */
6
- export declare function shellToolDefinitions(): readonly ToolDefinition[];
8
+ export declare function shellToolDefinitions(environment?: ShellToolEnvironment): readonly ToolDefinition[];
7
9
  export declare class ShellToolExecutor implements ToolExecutor {
8
10
  private readonly options;
9
11
  constructor(options?: {
10
12
  onActivity?: ToolActivityObserver;
11
13
  readOnly?: boolean;
12
14
  platform?: HostPlatformContext;
15
+ logger?: Logger;
16
+ toolEnvironment?: ShellToolEnvironment;
13
17
  });
14
18
  listTools(): readonly ToolDefinition[];
15
19
  getToolInfo(toolName: string): ToolInfo | undefined;
@@ -1,2 +1,2 @@
1
- import{resolveReadOnlyExecutable as g,readOnlyArguments as y}from"../platform/read-only-executable.js";import{resolveWorkspacePath as u}from"../filesystem/path-resolver.js";import{isReadOnlyShellRequest as w}from"../../application/security/tool-risk-classifier.js";import{detectHostPlatform as x}from"../platform/host-platform.js";import{normalizePowerShellScriptInput as E,execPlatformCommand as b}from"../platform/host-process.js";import{formatShellCommandForDisplay as S}from"../../application/agent/tool-display.js";const P=[{type:"function",function:{name:"shell.exec",description:"Execute one program with structured arguments inside the trusted workspace. Shell interpretation is disabled. On Windows, prefer powershell.exe with script for operating-system work; use direct command and args for node, npm, npx, pnpm, yarn, git, rg, and other project executables. Keep the executable in command and pass arguments separately in args (for example, git status --short means command git and args [status, --short]).",parameters:{type:"object",properties:{command:{type:"string",description:"Executable name or path."},args:{type:"array",items:{type:"string"},description:"Structured process arguments."},script:{type:"string",description:"Optional complete PowerShell script. Use only with powershell.exe or pwsh.exe; passed as one -Command argument."},cwd:{type:"string",description:"Optional workspace-relative working directory."},timeoutMs:{type:"number",description:"Timeout between 100 and 120000 milliseconds."}},required:["command"],additionalProperties:!1}}}],O="Process completed successfully with no output.";function T(){return P}class I{options;constructor(t={}){this.options=t}listTools(){return T()}getToolInfo(t){return t==="shell.exec"?{toolName:t,source:"shell",executorId:"local-shell"}:void 0}async execute(t,a,o){if(t!=="shell.exec")return{content:`Unknown shell tool: ${t}`,isError:!0};if(typeof a.command!="string"||a.command.trim().length===0)return{content:"shell.exec requires a command.",isError:!0};const n=this.options.platform??x();let r;try{r=E(a,n)}catch(s){return{content:s instanceof Error?s.message:"Invalid shell.exec PowerShell script.",isError:!0}}const e=r.args===void 0?[]:r.args;if(!Array.isArray(e)||e.some(s=>typeof s!="string"))return{content:"shell.exec args must be an array of strings.",isError:!0};const i=await w(r.command,e,o,u,r.cwd);if(this.options.readOnly&&!i)return{content:"This subagent is limited to read-only shell commands inside the trusted workspace.",isError:!0};const p=typeof r.timeoutMs=="number"?Math.min(Math.max(r.timeoutMs,100),12e4):3e4,l=await u(r.cwd??".",o),m=i?await g(r.command,o.workspaceRoot??l):void 0;if(i&&m===void 0)return{content:"Read-only executable is no longer available.",isError:!0};const h=S(r.command,e),f=this.options.onActivity?.start({key:`${o.runId}:shell.exec`,toolName:"shell.exec",source:"shell",label:h});return k(m??r.command,i?y(r.command,e):e,l,p,o,n).then(s=>(f?.complete(s.isError===!0),s))}}async function k(c,t,a,o,n,r){try{const e=await b(c,t,r,{cwd:a,timeoutMs:o,maxBufferBytes:n.maxResultBytes,rejectOnNonZero:!1,...n.signal===void 0?{}:{signal:n.signal}}),i=`${e.stdout}${e.stderr}${e.exitCode===0?"":`
2
- Process exited with code ${String(e.exitCode)}.`}`;return{content:d(i||O),isError:e.exitCode!==0}}catch(e){return{content:d(e instanceof Error?e.message:"Process execution failed."),isError:!0}}}function d(c){return c.replace(/Bearer\s+[^\s]+/gi,"Bearer [REDACTED]").replace(/sk-[A-Za-z0-9_-]{8,}/g,"[REDACTED]")}export{I as ShellToolExecutor,T as shellToolDefinitions};
1
+ import{resolveReadOnlyExecutable as y,readOnlyArguments as E}from"../platform/read-only-executable.js";import{resolveWorkspacePath as p}from"../filesystem/path-resolver.js";import{isReadOnlyShellRequest as b}from"../../application/security/tool-risk-classifier.js";import{detectHostPlatform as S}from"../platform/host-platform.js";import{normalizePowerShellScriptInput as T,execPlatformCommand as v}from"../platform/host-process.js";import{formatShellCommandForDisplay as P}from"../../application/agent/tool-display.js";import{withToolExecutionLogging as C}from"../observability/tool-execution-logger.js";import{RESOURCE_LIMITS as c}from"../../domain/runtime/resource-limits.js";const h=[{type:"function",function:{name:"shell.exec",description:"Execute one program with structured arguments inside the trusted workspace. Shell interpretation is disabled. When the runtime platform is Windows, prefer powershell.exe with script for operating-system work; use direct command and args for project executables. On other platforms, follow the runtime shell and executable availability. Keep the executable in command and pass arguments separately in args (for example, git status --short means command git and args [status, --short]). The script field is a complete PowerShell script, is valid only with powershell.exe or pwsh.exe, and cannot be combined with args. Inspect stdout, stderr, exit code, and the resulting state before reporting success.",parameters:{type:"object",properties:{command:{type:"string",description:"Executable name or path."},args:{type:"array",items:{type:"string"},description:"Structured process arguments."},script:{type:"string",description:"Optional complete PowerShell script. Use only with powershell.exe or pwsh.exe; passed as one -Command argument."},cwd:{type:"string",description:"Optional workspace-relative working directory."},timeoutMs:{type:"number",description:"Timeout between 100 milliseconds and the configured runtime maximum."}},required:["command"],additionalProperties:!1}}}],k="Process completed successfully with no output.";function O(o="host"){return o==="host"?h:h.map(t=>"function"in t?{...t,function:{...t.function,description:'Execute one Linux program with structured arguments inside the isolated Desktop WSL2 guest. Use Linux executables and workspace-relative paths; never invoke powershell.exe, cmd.exe, wsl.exe, Windows paths, or host interop. Keep command and args separate. For multiple shell operations, use bash with args ["-lc", "..."] only when a shell script is necessary. Inspect stdout, stderr, exit code, and returned data before continuing.'}}:t)}class B{options;constructor(t={}){this.options=t}listTools(){return O(this.options.toolEnvironment)}getToolInfo(t){return t==="shell.exec"?{toolName:t,source:"shell",executorId:"local-shell"}:void 0}async execute(t,l,i){return t!=="shell.exec"?{content:`Unknown shell tool: ${t}`,isError:!0}:C(this.options.logger,{toolName:t,source:"shell",context:i},async()=>{if(typeof l.command!="string"||l.command.trim().length===0)return{content:"shell.exec requires a command.",isError:!0};const a=this.options.platform??S();let r;try{r=T(l,a,{allowNonWindows:this.options.toolEnvironment!=="linux-guest"})}catch(n){return{content:n instanceof Error?n.message:"Invalid shell.exec PowerShell script.",isError:!0}}const e=r.args===void 0?[]:r.args;if(!Array.isArray(e)||e.some(n=>typeof n!="string"))return{content:"shell.exec args must be an array of strings.",isError:!0};const s=await b(r.command,e,i,p,r.cwd,a);if(this.options.readOnly&&!s)return{content:"This subagent is limited to read-only shell commands inside the trusted workspace.",isError:!0};const g=this.options.toolEnvironment==="linux-guest"?c.guestShellTimeoutMs:c.hostShellTimeoutMs,w=typeof r.timeoutMs=="number"?Math.min(Math.max(r.timeoutMs,100),g):c.defaultShellTimeoutMs,u=await p(r.cwd??".",i),m=s?await y(r.command,i.workspaceRoot??u,a):void 0;if(s&&m===void 0)return{content:"Read-only executable is no longer available.",isError:!0};const x=P(r.command,e),d=this.options.onActivity?.start({key:`${i.runId}:shell.exec`,toolName:"shell.exec",source:"shell",label:x});try{const n=await M(m??r.command,s?E(r.command,e):e,u,w,i,a);return d?.complete(n.isError===!0),n}catch(n){throw d?.complete(!0),n}})}}async function M(o,t,l,i,a,r){try{const e=await v(o,t,r,{cwd:l,timeoutMs:i,maxBufferBytes:a.maxResultBytes,rejectOnNonZero:!1,...a.signal===void 0?{}:{signal:a.signal}}),s=`${e.stdout}${e.stderr}${e.exitCode===0?"":`
2
+ Process exited with code ${String(e.exitCode)}.`}`;return{content:f(s||k),isError:e.exitCode!==0,metadata:{exitCode:e.exitCode}}}catch(e){const s=e instanceof Error?e.message:"Process execution failed.";return{content:f(s),isError:!0,metadata:{errorCode:I(s)}}}}function I(o){return/timed out/iu.test(o)?"timeout":/cancelled/iu.test(o)?"cancelled":/output exceeded/iu.test(o)?"output_limit":"process_failure"}function f(o){return o.replace(/Bearer\s+[^\s]+/gi,"Bearer [REDACTED]").replace(/sk-[A-Za-z0-9_-]{8,}/g,"[REDACTED]")}export{B as ShellToolExecutor,O as shellToolDefinitions};
@@ -1 +1 @@
1
- import{encoding_for_model as c,get_encoding as s}from"tiktoken";const d="o200k_base";function f(e){try{const t=r(e.model);try{const n=t.encode(e.prompt).length,o=t.encode(e.response).length;return{promptTokens:n,completionTokens:o,totalTokens:n+o,estimated:!0}}finally{t.free()}}catch{return}}function l(e){try{const t=r(e.model);try{return t.encode(e.text).length}finally{t.free()}}catch{return Math.ceil(Buffer.byteLength(e.text,"utf8")/4)}}function r(e){try{return c(e)}catch{return s(d)}}export{l as estimateTextTokens,f as estimateTurnUsage};
1
+ import{encoding_for_model as c,get_encoding as d}from"tiktoken";import{FALLBACK_ENCODING as f}from"./token-constants.js";function m(e){try{const t=o(e.model);try{const n=t.encode(e.prompt).length,r=t.encode(e.response).length;return{promptTokens:n,completionTokens:r,totalTokens:n+r,estimated:!0}}finally{t.free()}}catch{return}}function a(e){try{const t=o(e.model);try{return t.encode(e.text).length}finally{t.free()}}catch{return Math.ceil(Buffer.byteLength(e.text,"utf8")/4)}}function o(e){try{return c(e)}catch{return d(f)}}export{a as estimateTextTokens,m as estimateTurnUsage};
@@ -0,0 +1 @@
1
+ export declare const FALLBACK_ENCODING = "o200k_base";
@@ -0,0 +1 @@
1
+ const o="o200k_base";export{o as FALLBACK_ENCODING};
@@ -5,5 +5,6 @@ export declare class WorkspaceSettingsStore {
5
5
  /** Persist a user-approved rule in the ignored local project policy. */
6
6
  rememberAllow(cwd: string, rule: string): Promise<void>;
7
7
  private readOptional;
8
+ private readDocumentOptional;
8
9
  private createIfMissing;
9
10
  }
@@ -1,4 +1,4 @@
1
- import o from"node:fs/promises";import p from"node:path";import{DEFAULT_WORKSPACE_SETTINGS as a}from"../../domain/workspace/workspace-settings.js";import{permissionsFromSettings as f,validateSettingsDocument as g}from"../../domain/settings/settings-document.js";import{resolveProjectConfigPaths as l}from"../platform/platform-paths.js";import{atomicWriteFile as d,withFileLock as u}from"../filesystem/atomic-file-store.js";import{isAlreadyExists as w,isFileNotFound as h}from"../filesystem/fs-errors.js";import{readJsonFileBounded as y}from"../filesystem/bounded-json-reader.js";import{RESOURCE_LIMITS as S}from"../../domain/runtime/resource-limits.js";class A{async ensureInitialized(t){const i=l(t);await o.mkdir(i.directory,{recursive:!0}),await Promise.all([i.skillsDir,i.pluginsDir,i.hooksDir].map(s=>o.mkdir(s,{recursive:!0}))),await this.createIfMissing(i.settings,a),await this.createIfMissing(i.localSettings,a),await this.createIfMissing(p.join(i.directory,".gitignore"),`settings.local.json
2
- `)}async load(t){const i=l(t),[s,r]=await Promise.all([this.readOptional(i.settings),this.readOptional(i.localSettings)]);return{schemaVersion:1,permissions:k(s?.permissions,r?.permissions)}}async rememberAllow(t,i){const s=i.trim();if(s.length===0)return;const r=l(t);await o.mkdir(r.directory,{recursive:!0}),await u(r.localSettings,async()=>{const n=await this.readOptional(r.localSettings)??a;if(n.permissions.allow.includes(s))return;const m={schemaVersion:1,permissions:{...n.permissions,allow:[...n.permissions.allow,s]}};await d(r.localSettings,`${JSON.stringify(m,null,2)}
3
- `)})}async readOptional(t){try{const i=g(await y(t,S.workspaceSettingsBytes));return{schemaVersion:1,permissions:f(i)}}catch(i){if(h(i))return;throw i}}async createIfMissing(t,i){try{await o.writeFile(t,typeof i=="string"?i:`${JSON.stringify(i,null,2)}
4
- `,{encoding:"utf8",mode:384,flag:"wx"})}catch(s){if(!w(s))throw s}}}function k(e,t){return{allow:c(e?.allow,t?.allow),ask:c(e?.ask,t?.ask),deny:c(e?.deny,t?.deny)}}function c(...e){return[...new Set(e.flatMap(t=>t??[]))]}export{A as WorkspaceSettingsStore};
1
+ import n from"node:fs/promises";import d from"node:path";import{DEFAULT_WORKSPACE_SETTINGS as l,normalizePermissionRule as f}from"../../domain/workspace/workspace-settings.js";import{permissionsFromSettings as u,validateSettingsDocument as g}from"../../domain/settings/settings-document.js";import{resolveProjectConfigPaths as c}from"../platform/platform-paths.js";import{atomicWriteFile as w,withFileLock as h}from"../filesystem/atomic-file-store.js";import{isAlreadyExists as y,isFileNotFound as S}from"../filesystem/fs-errors.js";import{readJsonFileBounded as k}from"../filesystem/bounded-json-reader.js";import{RESOURCE_LIMITS as O}from"../../domain/runtime/resource-limits.js";class T{async ensureInitialized(t){const i=c(t);await n.mkdir(i.directory,{recursive:!0}),await Promise.all([i.skillsDir,i.pluginsDir,i.hooksDir].map(e=>n.mkdir(e,{recursive:!0}))),await this.createIfMissing(i.settings,l),await this.createIfMissing(i.localSettings,l),await this.createIfMissing(d.join(i.directory,".gitignore"),`settings.local.json
2
+ `)}async load(t){const i=c(t),[e,r]=await Promise.all([this.readOptional(i.settings),this.readOptional(i.localSettings)]);return{schemaVersion:1,permissions:D(e?.permissions,r?.permissions)}}async rememberAllow(t,i){if(i.trim().length===0)return;const e=f(i),r=c(t);await n.mkdir(r.directory,{recursive:!0}),await h(r.localSettings,async()=>{const o=await this.readDocumentOptional(r.localSettings),a=o===void 0?l:{schemaVersion:1,permissions:u(o)};if(a.permissions.allow.includes(e))return;const p={...o?.config??{},permissions:{...a.permissions,allow:[...a.permissions.allow,e]}};await w(r.localSettings,`${JSON.stringify(p,null,2)}
3
+ `)})}async readOptional(t){const i=await this.readDocumentOptional(t);if(i!==void 0)return{schemaVersion:1,permissions:u(i)}}async readDocumentOptional(t){try{return g(await k(t,O.workspaceSettingsBytes))}catch(i){if(S(i))return;throw i}}async createIfMissing(t,i){try{await n.writeFile(t,typeof i=="string"?i:`${JSON.stringify(i,null,2)}
4
+ `,{encoding:"utf8",mode:384,flag:"wx"})}catch(e){if(!y(e))throw e}}}function D(s,t){return{allow:m(s?.allow,t?.allow),ask:m(s?.ask,t?.ask),deny:m(s?.deny,t?.deny)}}function m(...s){return[...new Set(s.flatMap(t=>t??[]))]}export{T as WorkspaceSettingsStore};
package/dist/main.js CHANGED
@@ -1,3 +1,3 @@
1
- import{asCliError as x}from"./domain/errors/cli-error.js";import{createCompositionRoot as g}from"./bootstrap/composition-root.js";import{resolveStartupContext as C}from"./bootstrap/startup-sequence.js";import{parseGlobalCliOptions as y}from"./bootstrap/global-cli-options.js";import{TuiApplication as w}from"./presentation/tui/tui-application.js";import{formatCliErrorMessage as I}from"./application/commands/command-hints.js";import{COMMAND_REGISTRY as O}from"./application/commands/command-runtime.js";import{parseCommandInvocation as E}from"./application/commands/command-parser.js";import{executeApplicationCommand as v,executeInformationalCommand as R}from"./application/commands/application-command-executor.js";import{CLI_VERSION as W}from"./version.js";async function _(o,e={}){const h=e.stdin??process.stdin,n=e.stdout??process.stdout,a=e.stderr??process.stderr;let r;try{const d=y(o),t=T(d.commandTokens);if(t.length===0){r=g({stderr:a});const m=r.logger;m.info("Interactive session started.");const f=await new w(r,C(o).cwd,{output:n}).run();return m.info("Interactive session completed.",{exitCode:f}),f}const i=C(o).cwd,s=E(t,"direct",O),u=R(s,n);if(u!==void 0)return u;const c=g({stderr:a});r=c;const l=c.logger;l.info("CLI command started.",{command:s.action.id,cwd:i});const p=await v(s,{runtime:c,cwd:i,output:n,stdin:h,writableOutput:n,resumeInteractive:async m=>new w(c,i,{output:n,sessionId:m}).run()});return l.info("CLI command completed.",{command:s.action.id,exitCode:p}),p}catch(d){const t=x(d);return r?.logger.error("CLI command failed.",{code:t.code,category:t.category}),S(o)?n.write(`${JSON.stringify({error:t.toJSON()})}
2
- `):r!==void 0?r.logger.error(I(t,"direct"),{code:t.code,category:t.category}):a.write(`[error] ${I(t,"direct")}
3
- `),t.exitCode}finally{await r?.shutdown.shutdown()}}function S(o){return o.some(e=>e==="--json"||e.startsWith("--json="))}function T(o){return o.length===1&&(o[0]==="--help"||o[0]==="-h")?["help"]:o.length===1&&o[0]==="--version"?["version"]:o}export{W as CLI_VERSION,_ as main};
1
+ import{asCliError as S}from"./domain/errors/cli-error.js";import{createCompositionRoot as E}from"./bootstrap/composition-root.js";import{resolveStartupContext as h}from"./bootstrap/startup-sequence.js";import{parseGlobalCliOptions as O}from"./bootstrap/global-cli-options.js";import{TuiApplication as x}from"./presentation/tui/tui-application.js";import{formatCliErrorMessage as T}from"./application/commands/command-hints.js";import{COMMAND_REGISTRY as b}from"./application/commands/command-runtime.js";import{parseCommandInvocation as R}from"./application/commands/command-parser.js";import{executeApplicationCommand as v,executeInformationalCommand as G}from"./application/commands/application-command-executor.js";import{CLI_VERSION as B}from"./version.js";async function V(o,e={}){const y=e.stdin??process.stdin,n=e.stdout??process.stdout,u=e.stderr??process.stderr;let r;const i=new AbortController;let p=143;const f=()=>i.abort(new Error("Process termination requested."));let s;process.once("SIGTERM",f);try{const l=O(o),t=M(l.commandTokens);if(t.length===0){r=E({stderr:u,interactive:!0});const d=r.logger;d.info("Interactive session started.");const w=await new x(r,h(o).cwd,{output:n,signal:i.signal}).run();return d.info("Interactive session completed.",{exitCode:w}),w}const c=h(o).cwd,a=R(t,"direct",b),g=G(a,n);if(g!==void 0)return g;s=()=>{p=130,i.abort(new Error("Process interruption requested."))},process.once("SIGINT",s);const m=E({stderr:u});r=m;const C=m.logger;C.info("CLI command started.",{command:a.action.id,cwd:c});const I=await v(a,{runtime:m,cwd:c,output:n,stdin:y,writableOutput:n,signal:i.signal,resumeInteractive:async d=>new x(m,c,{output:n,sessionId:d,signal:i.signal}).run()});return C.info("CLI command completed.",{command:a.action.id,exitCode:I}),I}catch(l){if(i.signal.aborted)return p;const t=S(l);return r?.logger.error("CLI command failed.",{code:t.code,category:t.category}),N(o)?n.write(`${JSON.stringify({error:t.toJSON()})}
2
+ `):r!==void 0?r.logger.error(T(t,"direct"),{code:t.code,category:t.category}):u.write(`[error] ${T(t,"direct")}
3
+ `),t.exitCode}finally{process.off("SIGTERM",f),s!==void 0&&process.off("SIGINT",s),await r?.shutdown.shutdown()}}function N(o){return o.some(e=>e==="--json"||e.startsWith("--json="))}function M(o){return o.length===1&&(o[0]==="--help"||o[0]==="-h")?["help"]:o.length===1&&o[0]==="--version"?["version"]:o}export{B as CLI_VERSION,V as main};
@@ -1,4 +1,6 @@
1
1
  import type { GeneratedImage, MediaBinary, VideoOperation } from '../domain/media/media-contract.js';
2
+ export type SpeechStreamFormat = 'audio' | 'sse';
3
+ export type SpeechStreamEvent = Readonly<Record<string, unknown>>;
2
4
  export interface MediaRequestOptions {
3
5
  readonly signal?: AbortSignal | undefined;
4
6
  }
@@ -26,6 +28,7 @@ export interface SpeechInput {
26
28
  readonly instructions?: string | undefined;
27
29
  readonly responseFormat?: 'mp3' | 'opus' | 'aac' | 'flac' | 'wav' | 'pcm' | undefined;
28
30
  readonly speed?: number | undefined;
31
+ readonly streamFormat?: SpeechStreamFormat | undefined;
29
32
  }
30
33
  export interface AudioUploadInput {
31
34
  readonly model: string;
@@ -42,6 +45,9 @@ export interface MediaGatewayClient {
42
45
  generateImage(input: ImageGenerationInput, options?: MediaRequestOptions): Promise<readonly GeneratedImage[]>;
43
46
  editImage(input: ImageEditInput, options?: MediaRequestOptions): Promise<readonly GeneratedImage[]>;
44
47
  createSpeech(input: SpeechInput, options?: MediaRequestOptions): Promise<MediaBinary>;
48
+ createSpeechStream(input: SpeechInput & {
49
+ readonly streamFormat: 'sse';
50
+ }, options?: MediaRequestOptions): AsyncIterable<SpeechStreamEvent>;
45
51
  transcribe(input: AudioUploadInput, options?: MediaRequestOptions): Promise<string>;
46
52
  translate(input: AudioUploadInput, options?: MediaRequestOptions): Promise<string>;
47
53
  createVideo(input: {
@@ -51,6 +51,7 @@ export interface SessionStore {
51
51
  export(sessionId: string): Promise<SessionBundle>;
52
52
  import(bundle: SessionBundle, projectFingerprint: string, cwd: string): Promise<SessionMetadata>;
53
53
  saveAttachment(sessionId: string, attachment: Attachment, bytes: Uint8Array): Promise<Attachment>;
54
+ deleteAttachment(sessionId: string, attachmentId: string): Promise<boolean>;
54
55
  readAttachment(sessionId: string, attachmentId: string): Promise<Uint8Array | undefined>;
55
56
  recoverStaleLock(sessionId: string): Promise<boolean>;
56
57
  repair(sessionId: string): Promise<SessionRepairResult>;
@@ -1,8 +1,8 @@
1
1
  import{jsx as s,jsxs as R}from"react/jsx-runtime";import{useEffect as le,useLayoutEffect as U,useRef as S,useState as P}from"react";import{Box as g,Text as d,measureElement as de,useCursor as ae,useInput as fe,usePaste as me,useStdout as he}from"ink";import{formatContextUsage as pe,terminalTextWidth as H}from"../../formatters.js";import{DARK_THEME as r}from"../../../themes/theme.js";import{AttachmentChip as Ce}from"./transcript.js";import{isMouseSequence as ge}from"../../terminal-mouse.js";import{commandSuggestions as we}from"../../../../application/commands/command-presentation.js";import{parseCommandInvocation as xe,tokenizeCommandInput as Me}from"../../../../application/commands/command-parser.js";import{COMMAND_REGISTRY as k}from"../../../../application/commands/command-runtime.js";const q=4;function Ae({layout:o,value:c,cursor:i,terminalRows:u}){const a=c.slice(0,i).split(`
2
- `),f=Math.max(1,o.width-(q+2)),w=a.slice(0,-1).reduce((W,l)=>W+Math.max(1,Math.ceil(H(l)/f)),0),p=H(a.at(-1)??""),E=o.y+1+w+Math.floor(p/f);if(!(u!==void 0&&(E<0||E>=u)))return{x:o.x+q+p%f,y:E}}function _e({bridge:o,enabled:c,activeRun:i,visible:u=!0,clearBlockedUntil:a,footerNotice:f,contextUsage:w,attachments:p,fileChoices:E,onLayoutRowsChange:W}){const[l,ee]=P(""),[N,L]=P(0),[$,x]=P(0),[_,F]=P(),m=S(void 0),D=S(!1),M=S(""),C=S(0),X=S(void 0),O=S(null),[A,V]=P({left:0,top:0,width:0,hasMeasured:!1}),{setCursorPosition:te}=ae(),{stdout:G}=he(),b=l.startsWith("/")&&!l.includes(`
3
- `)&&X.current!==l?we(l,k,"tui").slice(0,8):[],I=Se(l,N),Z=I===void 0?[]:E.filter(e=>e.value.slice(1).toLowerCase().includes(I.query.toLowerCase())).slice(0,8),h=b.length>0?b:Z,j=()=>{D.current=!1,F(void 0),m.current!==void 0&&clearTimeout(m.current),m.current=void 0},T=(e,t)=>{M.current=e,C.current=t,ee(e),L(t)},v=()=>{X.current=void 0},K=e=>{T(e.value,e.value.length),X.current=e.value,x(0)},B=e=>{const t=e.replace(/\r\n?/gu,`
4
- `);if(t.length===0)return;j(),v();const n=M.current,z=C.current;T(`${n.slice(0,z)}${t}${n.slice(z)}`,z+t.length)},Y=e=>{if(I===void 0)return;v();const t=M.current;T(`${t.slice(0,I.start)}${e.value} ${t.slice(C.current)}`,I.start+e.value.length+1),x(0)},ne=()=>{const e=C.current;if(e===0)return;j(),v();const t=M.current;T(`${t.slice(0,e-1)}${t.slice(e)}`,e-1)},y=()=>{const e=M.current.trim();e.length>0&&(j(),v(),T("",0),x(0),o.submit(e))},re=()=>{j(),T("",0),x(0),o.clearAttachments()},oe=()=>{D.current=!0,F("Press Esc again to clear text and references."),m.current!==void 0&&clearTimeout(m.current),m.current=setTimeout(()=>{D.current=!1,F(void 0),m.current=void 0},1500)};fe((e,t)=>{if(c&&!ge(e)){if(t.escape||e==="\x1B"){if(i||a!==void 0&&a>Date.now()||l.length===0&&p.length===0)return;D.current?re():oe();return}if(t.meta&&e.toLowerCase()==="v"){o.pasteImage().catch(()=>{});return}if(t.ctrl&&e.toLowerCase()==="v"){o.pasteText().then(n=>{n!==void 0&&B(n)}).catch(()=>{});return}if(t.return&&t.shift){B(`
5
- `);return}if(t.return){const n=h[$];if(b.length>0&&n!==void 0&&n.value!==l){K(n);return}if(Te(l)){y();return}n!==void 0&&Z.length>0?Y(n):y();return}if(t.tab&&h[$]!==void 0){const n=h[$];n!==void 0&&(b.length>0?K(n):Y(n));return}if(t.upArrow&&h.length>0){x(n=>Math.max(0,n-1));return}if(t.downArrow&&h.length>0){x(n=>Math.min(h.length-1,n+1));return}if(t.leftArrow){v();const n=Math.max(0,C.current-1);C.current=n,L(n);return}if(t.rightArrow){v();const n=Math.min(M.current.length,C.current+1);C.current=n,L(n);return}if(t.backspace||t.delete){ne();return}!t.ctrl&&!t.meta&&e.length>0&&B(e)}},{isActive:c}),me(e=>{c&&B(e)},{isActive:c}),le(()=>()=>{m.current!==void 0&&clearTimeout(m.current)},[]);const J=l.split(`
2
+ `),f=Math.max(1,o.width-(q+2)),w=a.slice(0,-1).reduce((W,l)=>W+Math.max(1,Math.ceil(H(l)/f)),0),p=H(a.at(-1)??""),E=o.y+1+w+Math.floor(p/f);if(!(u!==void 0&&(E<0||E>=u)))return{x:o.x+q+p%f,y:E}}function _e({bridge:o,enabled:c,activeRun:i,visible:u=!0,clearBlockedUntil:a,footerNotice:f,contextUsage:w,attachments:p,fileChoices:E,onLayoutRowsChange:W}){const[l,ee]=P(""),[N,L]=P(0),[$,M]=P(0),[_,F]=P(),m=S(void 0),D=S(!1),x=S(""),C=S(0),X=S(void 0),O=S(null),[A,V]=P({left:0,top:0,width:0,hasMeasured:!1}),{setCursorPosition:te}=ae(),{stdout:G}=he(),b=l.startsWith("/")&&!l.includes(`
3
+ `)&&X.current!==l?we(l,k,"tui").slice(0,8):[],I=Se(l,N),Z=I===void 0?[]:E.filter(e=>e.value.slice(1).toLowerCase().includes(I.query.toLowerCase())).slice(0,8),h=b.length>0?b:Z,j=()=>{D.current=!1,F(void 0),m.current!==void 0&&clearTimeout(m.current),m.current=void 0},T=(e,t)=>{x.current=e,C.current=t,ee(e),L(t)},v=()=>{X.current=void 0},K=e=>{T(e.value,e.value.length),X.current=e.value,M(0)},B=e=>{const t=e.replace(/\r\n?/gu,`
4
+ `);if(t.length===0)return;j(),v();const n=x.current,z=C.current;T(`${n.slice(0,z)}${t}${n.slice(z)}`,z+t.length)},Y=e=>{if(I===void 0)return;v();const t=x.current;T(`${t.slice(0,I.start)}${e.value} ${t.slice(C.current)}`,I.start+e.value.length+1),M(0)},ne=()=>{const e=C.current;if(e===0)return;j(),v();const t=x.current;T(`${t.slice(0,e-1)}${t.slice(e)}`,e-1)},y=()=>{const e=x.current.trim();e.length>0&&(j(),v(),T("",0),M(0),o.submit(e))},re=()=>{j(),T("",0),M(0),o.clearAttachments()},oe=()=>{D.current=!0,F("Press Esc again to clear text and references."),m.current!==void 0&&clearTimeout(m.current),m.current=setTimeout(()=>{D.current=!1,F(void 0),m.current=void 0},1500)};fe((e,t)=>{if(c&&!ge(e)){if(t.escape||e==="\x1B"){if(i||a!==void 0&&a>Date.now()||l.length===0&&p.length===0)return;D.current?re():oe();return}if(t.meta&&e.toLowerCase()==="v"){o.pasteImage(x.current).catch(()=>{});return}if(t.ctrl&&e.toLowerCase()==="v"){o.pasteText().then(n=>{n!==void 0&&B(n)}).catch(()=>{});return}if(t.return&&t.shift){B(`
5
+ `);return}if(t.return){const n=h[$];if(b.length>0&&n!==void 0&&n.value!==l){K(n);return}if(Te(l)){y();return}n!==void 0&&Z.length>0?Y(n):y();return}if(t.tab&&h[$]!==void 0){const n=h[$];n!==void 0&&(b.length>0?K(n):Y(n));return}if(t.upArrow&&h.length>0){M(n=>Math.max(0,n-1));return}if(t.downArrow&&h.length>0){M(n=>Math.min(h.length-1,n+1));return}if(t.leftArrow){v();const n=Math.max(0,C.current-1);C.current=n,L(n);return}if(t.rightArrow){v();const n=Math.min(x.current.length,C.current+1);C.current=n,L(n);return}if(t.backspace||t.delete){ne();return}!t.ctrl&&!t.meta&&e.length>0&&B(e)}},{isActive:c}),me(e=>{c&&B(e)},{isActive:c}),le(()=>()=>{m.current!==void 0&&clearTimeout(m.current)},[]);const J=l.split(`
6
6
  `),ie=A.hasMeasured?A.width:Math.max(40,G.columns??80),se=Math.max(1,ie-(q+2)),ue=J.reduce((e,t)=>e+Math.max(1,Math.ceil(H(t)/se)),0),Q=ve({attachmentCount:p.length,inputRows:ue,hasClearHint:_!==void 0,hasFooterNotice:f!==void 0,choiceCount:h.length});U(()=>{W?.(Q+1)},[Q,W]),U(()=>{const e=O.current;if(e===null){V(n=>n.hasMeasured?{left:0,top:0,width:0,hasMeasured:!1}:n);return}const t=de(e);V(n=>n.left===t.x&&n.top===t.y&&n.width===t.width&&n.hasMeasured?n:{left:t.x,top:t.y,width:t.width,hasMeasured:!0})});const ce=c&&u&&A.hasMeasured?Ae({layout:{x:A.left,y:A.top,width:A.width},value:l,cursor:N,terminalRows:G.rows}):void 0;return te(ce),u?R(g,{width:"100%",flexDirection:"column",marginTop:1,children:[p.map(e=>s(Ce,{attachment:e},e.id)),s(g,{ref:O,width:"100%",borderStyle:"round",borderColor:c?r.accent:r.border,flexDirection:"column",paddingX:1,children:R(g,{children:[s(d,{color:r.accent,children:"\u203A "}),s(d,{wrap:"wrap",color:l.length===0?r.muted:r.text,children:l.length===0?"Ask LotaGate to work on this project\u2026":Re(J.join(`
7
7
  `))})]})}),R(g,{paddingX:1,justifyContent:"space-between",children:[s(d,{color:r.muted,dimColor:!0,children:"Enter send \xB7 Shift+Enter newline \xB7 / commands \xB7 @ files \xB7 Ctrl+V text \xB7 Alt+V image"}),w!==void 0&&s(d,{color:r.muted,dimColor:!0,children:pe(w.usedTokens,w.contextWindow)})]}),_!==void 0&&s(g,{paddingX:1,children:s(d,{color:r.muted,dimColor:!0,children:_})}),f!==void 0&&s(g,{paddingX:1,children:s(d,{color:r.muted,dimColor:!0,children:f})}),h.length>0&&s(g,{borderStyle:"round",borderColor:r.border,flexDirection:"column",paddingX:1,children:h.map((e,t)=>R(g,{...t===$?{backgroundColor:r.selection}:{},children:[s(d,{color:t===$?r.accent:r.muted,children:"\u203A "}),R(d,{color:e.kind==="directory"?r.warning:r.text,children:[e.kind==="directory"?"\u25B8 ":"",e.label]}),R(d,{color:r.muted,children:[" ",e.description]})]},e.value))})]}):null}function Te(o){if(!o.startsWith("/")||o.includes(`
8
8
  `))return!1;try{return xe(Me(o.trimStart().slice(1)),"tui",k),!0}catch{return!1}}function ve({attachmentCount:o,inputRows:c,hasClearHint:i,hasFooterNotice:u,choiceCount:a}){const f=o*2,w=Math.max(1,c)+2,p=a>0?a+2:0;return f+w+1+(i?1:0)+(u?1:0)+p}function Re(o){return o.split(/(@[^\s@]+|https?:\/\/[^\s]+|\/[A-Za-z][\w-]*)/gu).filter(i=>i.length>0).map((i,u)=>i.startsWith("@")?s(d,{color:r.accent,children:i},u):/^https?:\/\//u.test(i)?s(d,{color:r.link,underline:!0,children:i},u):/^\/[A-Za-z][\w-]*$/u.test(i)?s(d,{color:r.accent,children:i},u):s(d,{children:i},u))}function Se(o,c){const i=o.slice(0,c),u=/(?:^|\s)@([^\s@]*)$/u.exec(i);if(u===null)return;const a=u[1]??"";return{start:c-a.length-1,query:a}}export{_e as Composer,Se as atFileReference,Ae as calculateComposerCursorPosition};
@@ -28,6 +28,7 @@ export interface TranscriptViewport {
28
28
  messages: readonly TuiTranscriptEntry[];
29
29
  firstMessage: number;
30
30
  lastMessage: number;
31
+ totalRows?: number;
31
32
  }
32
33
  /** Returns a stable message window, measured from the newest transcript entry. */
33
34
  export declare function transcriptViewport(messages: readonly TuiTranscriptEntry[], offset: number, maximumMessages: number): TranscriptViewport;
@@ -1,5 +1,5 @@
1
- import{jsx as e,jsxs as s}from"react/jsx-runtime";import{Box as f,Text as m}from"ink";import{DARK_THEME as x}from"../../../themes/theme.js";import{MarkdownMessage as y}from"../markdown-message.js";import{FileDiff as O,fileDiffRowCount as _}from"./file-diff.js";import{terminalTextWidth as D,wrapTerminalText as W}from"../../formatters.js";import{ActivityEntry as G}from"./activity-entry.js";import{SubagentCreatedEntry as I}from"./subagent-activity.js";import{ActivityStatus as F}from"./activity-status.js";import{WelcomePanel as L,WELCOME_PANEL_ROWS as S}from"./welcome-panel.js";function tt({messages:t,showActionDetails:r=!1,fill:i=!1,height:o}){return e(f,{flexDirection:"column",...i?{flexGrow:1,overflow:"hidden"}:{},...o===void 0?{}:{height:o},children:t.map(n=>e(z,{message:n,showActionDetails:r},n.id))})}function nt(t,r,i){const o=Math.max(0,Math.min(r,Math.max(0,t.length-i))),n=t.length-o,c=Math.max(0,n-i);return{messages:t.slice(c,n),firstMessage:c+1,lastMessage:n}}function rt(t,r,i,o){const n=t.map(a=>T(a,o)),c=[],l=n.reduce((a,h)=>a+h,0),d=Math.max(1,Math.floor(i)),M=Math.max(0,Math.min(Math.floor(r),Math.max(0,l-d))),p=l-M,E=Math.max(0,p-d);let k=0,u=t.length,b=0;for(let a=0;a<t.length;a+=1){const h=k;c[a]=h;const w=n[a]??1;k+=w,k>E&&h<p&&(u=Math.min(u,a),b=a+1)}return u===t.length?{messages:[],firstMessage:0,lastMessage:0}:{messages:t.slice(u,b).flatMap((a,h)=>{const w=u+h,v=c[w]??0,j=v+(n[w]??1),C=Math.max(E,v),R=Math.min(p,j);return R<=C?[]:[P(a,C-v,R-C,o)]}),firstMessage:u+1,lastMessage:b}}function it(t,r){return t.reduce((i,o)=>i+T(o,r),0)}function T(t,r){if(t.kind==="welcome")return S;if(t.kind==="status")return 2;const i=Math.max(1,r-4),o=t.content.split(`
2
- `).reduce((d,M)=>d+Math.max(1,Math.ceil(D(M)/i)),0),n=(t.attachments?.length??0)*2,c=t.fileChange===void 0?0:_(t.fileChange,r),l=t.subagent===void 0?0:2;return Math.max(1,o+n+c+l+1)}function P(t,r,i,o){if(t.kind==="welcome")return r<=0&&i>=S?t:{...t,visible:!1};if(t.kind==="status"||!V(t)||r<=0&&i>=T(t,o))return t;const n=Math.max(1,o-4),c=t.content.split(`
3
- `).reduce((M,p)=>M+Math.max(1,Math.ceil(D(p)/n)),0),l=Math.max(0,r),d=Math.min(c,l+Math.max(0,i));return d<=l?{...t,content:A(t.content,Math.max(0,c-1),1,n)}:{...t,content:A(t.content,l,d-l,n)}}function V(t){return t.kind==="assistant"||t.kind==="user"||t.kind==="notice"||t.kind==="error"||t.kind==="command"}function A(t,r,i,o){const n=[];for(const c of t.split(`
4
- `)){const l=W(c,o);n.push(...l)}return n.slice(r,r+i).join(`
5
- `)}function z({message:t,showActionDetails:r}){if(t.kind==="welcome")return t.visible===!1?null:e(L,{welcome:t.welcome});if(t.kind==="status")return e(F,{...t.status});if(t.kind==="assistant")return s(f,{flexDirection:"row",alignItems:"flex-start",marginBottom:1,children:[e(B,{}),e(f,{flexGrow:1,children:e(y,{content:t.content||" "})})]});if(t.kind==="diff"&&t.fileChange!==void 0)return e(O,{change:t.fileChange});if(t.kind==="activity"&&t.activity!==void 0)return e(G,{activity:t.activity,showDetails:r});if(t.kind==="subagent"&&t.subagent!==void 0)return e(I,{subagent:t.subagent});if(t.kind==="user")return s(f,{backgroundColor:x.user,flexDirection:"column",marginBottom:1,children:[s(f,{flexDirection:"row",alignItems:"flex-start",children:[e(B,{}),e(f,{flexGrow:1,children:e(y,{content:t.content})})]}),t.attachments?.map(n=>e(H,{attachment:n},n.id))]});const i=t.kind==="error"?x.error:t.kind==="command"?x.accent:x.muted,o=t.kind==="error"?"!":t.kind==="command"?"\u203A":"\xB7";return s(f,{marginBottom:1,children:[s(m,{color:i,children:[o," "]}),e(m,{color:i,wrap:"wrap",children:t.content})]})}function B(){return e(m,{color:x.text,children:"\u25CF "})}function H({attachment:t}){return e(f,{marginTop:1,children:s(m,{color:x.muted,children:["\u25A3 ",t.name]})})}export{H as AttachmentChip,tt as Transcript,it as transcriptTotalRows,nt as transcriptViewport,rt as transcriptViewportByRows};
1
+ import{jsx as e,jsxs as s}from"react/jsx-runtime";import{Box as f,Text as m}from"ink";import{DARK_THEME as M}from"../../../themes/theme.js";import{MarkdownMessage as E}from"../markdown-message.js";import{FileDiff as W,fileDiffRowCount as _}from"./file-diff.js";import{terminalTextWidth as D,wrapTerminalText as G}from"../../formatters.js";import{ActivityEntry as I}from"./activity-entry.js";import{SubagentCreatedEntry as F}from"./subagent-activity.js";import{ActivityStatus as L}from"./activity-status.js";import{WelcomePanel as P,WELCOME_PANEL_ROWS as S}from"./welcome-panel.js";function rt({messages:t,showActionDetails:o=!1,fill:n=!1,height:i}){return e(f,{flexDirection:"column",...n?{flexGrow:1,overflow:"hidden"}:{},...i===void 0?{}:{height:i},children:t.map(r=>e(K,{message:r,showActionDetails:o},r.id))})}function ot(t,o,n){const i=Math.max(0,Math.min(o,Math.max(0,t.length-n))),r=t.length-i,a=Math.max(0,r-n);return{messages:t.slice(a,r),firstMessage:a+1,lastMessage:r}}function it(t,o,n,i){const r=t.map(l=>R(l,i)),a=[],c=r.reduce((l,h)=>l+h,0),d=Math.max(1,Math.floor(n)),p=Math.max(0,Math.min(Math.floor(o),Math.max(0,c-d))),x=c-p,T=Math.max(0,x-d);let k=0,u=t.length,C=0;for(let l=0;l<t.length;l+=1){const h=k;a[l]=h;const w=r[l]??1;k+=w,k>T&&h<x&&(u=Math.min(u,l),C=l+1)}return u===t.length?{messages:[],firstMessage:0,lastMessage:0,totalRows:c}:{messages:t.slice(u,C).flatMap((l,h)=>{const w=u+h,b=a[w]??0,O=b+(r[w]??1),v=Math.max(T,b),y=Math.min(x,O);return y<=v?[]:[z(l,v-b,y-v,i)]}),firstMessage:u+1,lastMessage:C,totalRows:c}}function et(t,o){return t.reduce((n,i)=>n+R(i,o),0)}const A=new WeakMap;function R(t,o){let n=A.get(t);if(n!==void 0){const r=n.get(o);if(r!==void 0)return r}else n=new Map,A.set(t,n);const i=V(t,o);return n.set(o,i),i}function V(t,o){if(t.kind==="welcome")return S;if(t.kind==="status")return 2;const n=Math.max(1,o-4),i=t.content.split(`
2
+ `).reduce((d,p)=>d+Math.max(1,Math.ceil(D(p)/n)),0),r=(t.attachments?.length??0)*2,a=t.fileChange===void 0?0:_(t.fileChange,o),c=t.subagent===void 0?0:2;return Math.max(1,i+r+a+c+1)}function z(t,o,n,i){if(t.kind==="welcome")return o<=0&&n>=S?t:{...t,visible:!1};if(t.kind==="status"||!H(t)||o<=0&&n>=R(t,i))return t;const r=Math.max(1,i-4),a=t.content.split(`
3
+ `).reduce((p,x)=>p+Math.max(1,Math.ceil(D(x)/r)),0),c=Math.max(0,o),d=Math.min(a,c+Math.max(0,n));return d<=c?{...t,content:B(t.content,Math.max(0,a-1),1,r)}:{...t,content:B(t.content,c,d-c,r)}}function H(t){return t.kind==="assistant"||t.kind==="user"||t.kind==="notice"||t.kind==="error"||t.kind==="command"}function B(t,o,n,i){const r=[];for(const a of t.split(`
4
+ `)){const c=G(a,i);r.push(...c)}return r.slice(o,o+n).join(`
5
+ `)}function K({message:t,showActionDetails:o}){if(t.kind==="welcome")return t.visible===!1?null:e(P,{welcome:t.welcome});if(t.kind==="status")return e(L,{...t.status});if(t.kind==="assistant")return s(f,{flexDirection:"row",alignItems:"flex-start",marginBottom:1,children:[e(j,{}),e(f,{flexGrow:1,children:e(E,{content:t.content||" "})})]});if(t.kind==="diff"&&t.fileChange!==void 0)return e(W,{change:t.fileChange});if(t.kind==="activity"&&t.activity!==void 0)return e(I,{activity:t.activity,showDetails:o});if(t.kind==="subagent"&&t.subagent!==void 0)return e(F,{subagent:t.subagent});if(t.kind==="user")return s(f,{backgroundColor:M.user,flexDirection:"column",marginBottom:1,children:[s(f,{flexDirection:"row",alignItems:"flex-start",children:[e(j,{}),e(f,{flexGrow:1,children:e(E,{content:t.content})})]}),t.attachments?.map(r=>e(N,{attachment:r},r.id))]});const n=t.kind==="error"?M.error:t.kind==="command"?M.accent:M.muted,i=t.kind==="error"?"!":t.kind==="command"?"\u203A":"\xB7";return s(f,{marginBottom:1,children:[s(m,{color:n,children:[i," "]}),e(m,{color:n,wrap:"wrap",children:t.content})]})}function j(){return e(m,{color:M.text,children:"\u25CF "})}function N({attachment:t}){return e(f,{marginTop:1,children:s(m,{color:M.muted,children:["\u25A3 ",t.name]})})}export{N as AttachmentChip,rt as Transcript,et as transcriptTotalRows,ot as transcriptViewport,it as transcriptViewportByRows};
@@ -115,13 +115,13 @@ export declare class InkTuiBridge {
115
115
  snapshot(): TuiViewState;
116
116
  subscribe(listener: Listener): () => void;
117
117
  setSubmitHandler(handler: (value: string) => Promise<void>): void;
118
- setImagePasteHandler(handler: () => Promise<void>): void;
118
+ setImagePasteHandler(handler: (prompt: string) => Promise<void>): void;
119
119
  setTextPasteHandler(handler: () => Promise<string | undefined>): void;
120
120
  setClearAttachmentsHandler(handler: () => void): void;
121
121
  setInterruptHandler(handler: () => void): void;
122
122
  setCancelHandler(handler: () => void): void;
123
123
  submit(value: string): Promise<void>;
124
- pasteImage(): Promise<void>;
124
+ pasteImage(prompt: string): Promise<void>;
125
125
  pasteText(): Promise<string | undefined>;
126
126
  interrupt(): void;
127
127
  cancel(): void;