@lotagate/cli 0.1.28 → 0.1.29

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 (77) hide show
  1. package/LICENSE.md +79 -21
  2. package/README.md +31 -2
  3. package/dist/application/agent/cli-agent-execution-service.d.ts +2 -0
  4. package/dist/application/agent/cli-agent-execution-service.js +1 -1
  5. package/dist/application/agent/context-compaction.d.ts +2 -0
  6. package/dist/application/agent/context-compaction.js +7 -7
  7. package/dist/application/agent/interactive-agent-guidance.js +1 -1
  8. package/dist/application/commands/cli-command-services.js +33 -33
  9. package/dist/application/extensions/extension-list-scope-policy.d.ts +9 -0
  10. package/dist/application/extensions/extension-list-scope-policy.js +1 -0
  11. package/dist/application/intent/completion-gate.js +1 -1
  12. package/dist/application/intent/evidence-ledger.d.ts +6 -3
  13. package/dist/application/intent/evidence-recording-tool-executor.d.ts +5 -2
  14. package/dist/application/intent/evidence-recording-tool-executor.js +1 -1
  15. package/dist/application/intent/intent-compiler.d.ts +15 -2
  16. package/dist/application/intent/intent-compiler.js +3 -2
  17. package/dist/application/intent/intent-execution-gate.d.ts +4 -1
  18. package/dist/application/intent/intent-execution-gate.js +1 -1
  19. package/dist/application/intent/intent-run-controller.d.ts +2 -1
  20. package/dist/application/intent/intent-run-controller.js +2 -2
  21. package/dist/application/model/model-response-retry.d.ts +21 -0
  22. package/dist/application/model/model-response-retry.js +1 -1
  23. package/dist/application/orchestration/cli-turn-event-projector.d.ts +1 -1
  24. package/dist/application/orchestration/cli-turn-event-projector.js +1 -1
  25. package/dist/application/orchestration/cli-turn-events.d.ts +7 -0
  26. package/dist/application/orchestration/cli-turn-events.js +1 -1
  27. package/dist/application/protocol/computer-host-tool-executor.d.ts +8 -0
  28. package/dist/application/protocol/computer-host-tool-executor.js +2 -2
  29. package/dist/application/protocol/desktop-agent-command.js +1 -1
  30. package/dist/application/protocol/desktop-command-runner.d.ts +19 -0
  31. package/dist/application/protocol/desktop-command-runner.js +1 -0
  32. package/dist/application/protocol/desktop-intent-event-writer.js +1 -1
  33. package/dist/application/protocol/desktop-turn-execution-service.d.ts +43 -0
  34. package/dist/application/protocol/desktop-turn-execution-service.js +1 -0
  35. package/dist/application/protocol/jsonl-agent-command.js +2 -2
  36. package/dist/application/security/tool-approval-service.js +1 -1
  37. package/dist/application/workspace/session-execution-workspace.d.ts +10 -1
  38. package/dist/application/workspace/session-execution-workspace.js +3 -3
  39. package/dist/application/workspace/session-worktree.d.ts +6 -0
  40. package/dist/application/workspace/session-worktree.js +1 -0
  41. package/dist/application/workspace/workspace-constants.d.ts +0 -1
  42. package/dist/application/workspace/workspace-constants.js +1 -1
  43. package/dist/bootstrap/runtime-factory.js +1 -1
  44. package/dist/domain/errors/error-codes.d.ts +1 -0
  45. package/dist/domain/errors/error-codes.js +1 -1
  46. package/dist/domain/intent/intent-contract.d.ts +0 -1
  47. package/dist/domain/intent/intent-contract.js +1 -1
  48. package/dist/domain/runtime/resource-limits.d.ts +4 -0
  49. package/dist/domain/runtime/resource-limits.js +1 -1
  50. package/dist/domain/workspace/workspace-materialization-policy.d.ts +6 -0
  51. package/dist/domain/workspace/workspace-materialization-policy.js +1 -0
  52. package/dist/infrastructure/agent-sdk/agent-instance-factory.d.ts +3 -0
  53. package/dist/infrastructure/agent-sdk/agent-instance-factory.js +1 -1
  54. package/dist/infrastructure/agent-sdk/tool-calling-completion-client.d.ts +2 -1
  55. package/dist/infrastructure/agent-sdk/tool-calling-completion-client.js +1 -1
  56. package/dist/infrastructure/agent-sdk/tool-calling-model-client.d.ts +2 -1
  57. package/dist/infrastructure/agent-sdk/tool-calling-model-client.js +1 -1
  58. package/dist/infrastructure/agent-sdk/tool-calling-model-normalization.d.ts +7 -0
  59. package/dist/infrastructure/agent-sdk/tool-calling-model-normalization.js +1 -0
  60. package/dist/infrastructure/clipboard/windows-clipboard-adapter.js +1 -1
  61. package/dist/infrastructure/credentials/composite-credential-store.js +1 -1
  62. package/dist/infrastructure/extensions/skill-tool-executor.js +4 -2
  63. package/dist/infrastructure/observability/tool-execution-logger.js +1 -1
  64. package/dist/infrastructure/platform/host-process.js +1 -1
  65. package/dist/infrastructure/platform/platform-constants.d.ts +1 -0
  66. package/dist/infrastructure/platform/platform-constants.js +1 -1
  67. package/dist/infrastructure/platform/process-termination.js +1 -1
  68. package/dist/infrastructure/workspace/workspace-materializer.d.ts +26 -0
  69. package/dist/infrastructure/workspace/workspace-materializer.js +2 -0
  70. package/dist/presentation/tui/tui-agent-event-runner.js +1 -1
  71. package/dist/presentation/tui/tui-agent-turn-controller.js +1 -1
  72. package/dist/presentation/tui/tui-application.js +2 -2
  73. package/dist/presentation/tui/tui-context-compaction.d.ts +2 -1
  74. package/dist/presentation/tui/tui-context-compaction.js +1 -1
  75. package/dist/version.d.ts +1 -1
  76. package/dist/version.js +1 -1
  77. package/package.json +10 -10
@@ -1 +1 @@
1
- import $ from"node:path";import{spawn as B}from"node:child_process";import{RESOURCE_LIMITS as A}from"../../domain/runtime/resource-limits.js";import{terminatePlatformProcess as T}from"./process-termination.js";import{terminatePlatformProcess as Y}from"./process-termination.js";import{DEFAULT_EXEC_BUFFER_BYTES as v,WINDOWS_CMD_SHIM as y,WINDOWS_DIRECT_EXECUTABLE as W,WINDOWS_META_CHARS as P}from"./platform-constants.js";function F(e,r,t={}){const n=e.script;if(n===void 0)return e;if(typeof n!="string"||n.trim().length===0)throw new Error("shell.exec script must be a non-empty string.");if(Buffer.byteLength(n,"utf8")>A.sessionTextBytes)throw new Error("shell.exec script exceeds the configured limit.");if(!r.isWindows&&t.allowNonWindows!==!0)throw new Error("shell.exec PowerShell scripts are unavailable in the isolated guest sandbox; use the supported host command with structured args.");const o=e.command;if(typeof o!="string"||!I(o))throw new Error("shell.exec script requires powershell.exe or pwsh.exe as the command.");const c=e.args;if(c!==void 0&&(!Array.isArray(c)||c.length>0||c.some(u=>typeof u!="string")))throw new Error("shell.exec script cannot be combined with args.");const d=_(o,n),i={...e};return delete i.script,{...i,command:d.command,args:[...d.args]}}function _(e,r){return{command:e,args:["-NoProfile","-NonInteractive","-Command",r],windowsVerbatimArguments:!1}}function I(e){const r=e.replace(/^.*[\\/]/u,"").toLowerCase();return r==="powershell"||r==="powershell.exe"||r==="pwsh"||r==="pwsh.exe"}function O(e,r,t,n={}){const o=M(e,r,t);return B(o.command,[...o.args],{...n,shell:!1,windowsHide:!0,...o.windowsVerbatimArguments?{windowsVerbatimArguments:!0}:{}})}function X(e,r,t,n={}){if(n.signal?.aborted)return Promise.reject(new Error("Process cancelled."));const o=n.maxBufferBytes??v,c=n.timeoutMs??A.internalProcessTimeoutMs;return new Promise((d,i)=>{const u=O(e,r,t,{...n.cwd===void 0?{}:{cwd:n.cwd},env:n.env??L(t),detached:t.supportsProcessGroups,stdio:["ignore","pipe","pipe"]}),x=[],p=[];let w=0,a=!1,l=!1,b=!1,S=!1,h;const m=()=>{h!==void 0&&clearTimeout(h),n.signal?.removeEventListener("abort",g)},g=()=>{S=!0,E(new Error("Process cancelled."))},E=s=>{l||a||(l=!0,T(u,t).then(()=>{a||(a=!0,m(),i(s))},f=>{a||(a=!0,m(),i(new AggregateError([s,f],`${s.message} Termination could not be confirmed.`)))}))},C=(s,f)=>{if(!(a||l)){if(w+=f.byteLength,w>o){E(new Error("Process output exceeded the configured limit."));return}s.push(f)}};u.stdout?.on("data",s=>C(x,s)),u.stderr?.on("data",s=>C(p,s)),u.once("error",s=>{a||l||(a=!0,m(),i(s))}),u.once("close",s=>{a||(a=!0,m(),S?i(new Error("Process cancelled.")):b?i(new Error(`Process timed out after ${c}ms.`)):w>o?i(new Error("Process output exceeded the configured limit.")):s===0||n.rejectOnNonZero===!1?d({stdout:Buffer.concat(x).toString("utf8"),stderr:Buffer.concat(p).toString("utf8"),exitCode:s}):i(new Error(Buffer.concat(p).toString("utf8").trim()||`Process exited with code ${String(s)}.`)))}),h=setTimeout(()=>{b=!0,E(new Error(`Process timed out after ${c}ms.`))},c),n.signal?.aborted===!0?g():n.signal?.addEventListener("abort",g,{once:!0})})}function L(e){const r=Object.fromEntries(Object.entries(e.env).filter(t=>t[1]!==void 0));if(e.isWindows){const t=r.Path??r.PATH;t!==void 0&&(delete r.Path,delete r.PATH,r.Path=t)}return r}function M(e,r,t){if(!t.isWindows||W.test(e))return{command:e,args:r,windowsVerbatimArguments:!1};const n=$.win32.normalize(e),o=y.test(n),c=N(n),d=r.map(i=>D(i,o));return{command:t.env.ComSpec??t.env.COMSPEC??"cmd.exe",args:["/d","/s","/c",`"${[c,...d].join(" ")}"`],windowsVerbatimArguments:!0}}function N(e){return e.replace(P,"^$1")}function D(e,r){let t=e.replace(/(?=(\\+?)?)\1"/gu,'$1$1\\"').replace(/(?=(\\+?)?)\1$/gu,"$1$1");return t=`"${t}"`.replace(P,"^$1"),r?t.replace(P,"^$1"):t}export{L as createSafeChildEnvironment,X as execPlatformCommand,I as isPowerShellExecutable,F as normalizePowerShellScriptInput,M as preparePlatformCommand,_ as preparePowerShellScript,O as spawnPlatformProcess,Y as terminatePlatformProcess};
1
+ import v from"node:path";import{spawn as B}from"node:child_process";import{RESOURCE_LIMITS as A}from"../../domain/runtime/resource-limits.js";import{terminatePlatformProcess as I}from"./process-termination.js";import{terminatePlatformProcess as Z}from"./process-termination.js";import{DEFAULT_EXEC_BUFFER_BYTES as $,SENSITIVE_CHILD_ENVIRONMENT_VARIABLE as _,WINDOWS_CMD_SHIM as W,WINDOWS_DIRECT_EXECUTABLE as y,WINDOWS_META_CHARS as P}from"./platform-constants.js";function X(e,r,t={}){const n=e.script;if(n===void 0)return e;if(typeof n!="string"||n.trim().length===0)throw new Error("shell.exec script must be a non-empty string.");if(Buffer.byteLength(n,"utf8")>A.sessionTextBytes)throw new Error("shell.exec script exceeds the configured limit.");if(!r.isWindows&&t.allowNonWindows!==!0)throw new Error("shell.exec PowerShell scripts are unavailable in the isolated guest sandbox; use the supported host command with structured args.");const o=e.command;if(typeof o!="string"||!L(o))throw new Error("shell.exec script requires powershell.exe or pwsh.exe as the command.");const c=e.args;if(c!==void 0&&(!Array.isArray(c)||c.length>0||c.some(u=>typeof u!="string")))throw new Error("shell.exec script cannot be combined with args.");const d=N(o,n),i={...e};return delete i.script,{...i,command:d.command,args:[...d.args]}}function N(e,r){return{command:e,args:["-NoProfile","-NonInteractive","-Command",r],windowsVerbatimArguments:!1}}function L(e){const r=e.replace(/^.*[\\/]/u,"").toLowerCase();return r==="powershell"||r==="powershell.exe"||r==="pwsh"||r==="pwsh.exe"}function O(e,r,t,n={}){const o=M(e,r,t);return B(o.command,[...o.args],{...n,env:n.env??T(t),shell:!1,windowsHide:!0,...o.windowsVerbatimArguments?{windowsVerbatimArguments:!0}:{}})}function q(e,r,t,n={}){if(n.signal?.aborted)return Promise.reject(new Error("Process cancelled."));const o=n.maxBufferBytes??$,c=n.timeoutMs??A.internalProcessTimeoutMs;return new Promise((d,i)=>{const u=O(e,r,t,{...n.cwd===void 0?{}:{cwd:n.cwd},env:n.env??T(t),detached:t.supportsProcessGroups,stdio:["ignore","pipe","pipe"]}),x=[],w=[];let p=0,a=!1,l=!1,b=!1,S=!1,h;const m=()=>{h!==void 0&&clearTimeout(h),n.signal?.removeEventListener("abort",g)},g=()=>{S=!0,E(new Error("Process cancelled."))},E=s=>{l||a||(l=!0,I(u,t).then(()=>{a||(a=!0,m(),i(s))},f=>{a||(a=!0,m(),i(new AggregateError([s,f],`${s.message} Termination could not be confirmed.`)))}))},C=(s,f)=>{if(!(a||l)){if(p+=f.byteLength,p>o){E(new Error("Process output exceeded the configured limit."));return}s.push(f)}};u.stdout?.on("data",s=>C(x,s)),u.stderr?.on("data",s=>C(w,s)),u.once("error",s=>{a||l||(a=!0,m(),i(s))}),u.once("close",s=>{a||(a=!0,m(),S?i(new Error("Process cancelled.")):b?i(new Error(`Process timed out after ${c}ms.`)):p>o?i(new Error("Process output exceeded the configured limit.")):s===0||n.rejectOnNonZero===!1?d({stdout:Buffer.concat(x).toString("utf8"),stderr:Buffer.concat(w).toString("utf8"),exitCode:s}):i(new Error(Buffer.concat(w).toString("utf8").trim()||`Process exited with code ${String(s)}.`)))}),h=setTimeout(()=>{b=!0,E(new Error(`Process timed out after ${c}ms.`))},c),n.signal?.aborted===!0?g():n.signal?.addEventListener("abort",g,{once:!0})})}function T(e){const r=Object.fromEntries(Object.entries(e.env).filter(t=>t[1]!==void 0&&!_.test(t[0])));if(e.isWindows){const t=r.Path??r.PATH;t!==void 0&&(delete r.Path,delete r.PATH,r.Path=t)}return r}function M(e,r,t){if(!t.isWindows||y.test(e))return{command:e,args:r,windowsVerbatimArguments:!1};const n=v.win32.normalize(e),o=W.test(n),c=V(n),d=r.map(i=>D(i,o));return{command:t.env.ComSpec??t.env.COMSPEC??"cmd.exe",args:["/d","/s","/c",`"${[c,...d].join(" ")}"`],windowsVerbatimArguments:!0}}function V(e){return e.replace(P,"^$1")}function D(e,r){let t=e.replace(/(?=(\\+?)?)\1"/gu,'$1$1\\"').replace(/(?=(\\+?)?)\1$/gu,"$1$1");return t=`"${t}"`.replace(P,"^$1"),r?t.replace(P,"^$1"):t}export{T as createSafeChildEnvironment,q as execPlatformCommand,L as isPowerShellExecutable,X as normalizePowerShellScriptInput,M as preparePlatformCommand,N as preparePowerShellScript,O as spawnPlatformProcess,Z as terminatePlatformProcess};
@@ -2,3 +2,4 @@ export declare const DEFAULT_EXEC_BUFFER_BYTES: number;
2
2
  export declare const WINDOWS_META_CHARS: RegExp;
3
3
  export declare const WINDOWS_DIRECT_EXECUTABLE: RegExp;
4
4
  export declare const WINDOWS_CMD_SHIM: RegExp;
5
+ export declare const SENSITIVE_CHILD_ENVIRONMENT_VARIABLE: RegExp;
@@ -1 +1 @@
1
- const o=2097152,E=/([()\][%!^"`<>&|;, *?])/gu,_=/\.(?:com|exe)$/iu,e=/node_modules[\\/]\.bin[\\/][^\\/]+\.cmd$/iu;export{o as DEFAULT_EXEC_BUFFER_BYTES,e as WINDOWS_CMD_SHIM,_ as WINDOWS_DIRECT_EXECUTABLE,E as WINDOWS_META_CHARS};
1
+ const E=2097152,_=/([()\][%!^"`<>&|;, *?])/gu,S=/\.(?:com|exe)$/iu,I=/node_modules[\\/]\.bin[\\/][^\\/]+\.cmd$/iu,A=/(?:^|_)(?:API[_-]?KEY|ACCESS[_-]?KEY|AUTH(?:ORIZATION)?|CREDENTIALS?|PASSWORD|PASSWD|PRIVATE[_-]?KEY|SECRET|TOKEN)(?:$|_)/iu;export{E as DEFAULT_EXEC_BUFFER_BYTES,A as SENSITIVE_CHILD_ENVIRONMENT_VARIABLE,I as WINDOWS_CMD_SHIM,S as WINDOWS_DIRECT_EXECUTABLE,_ as WINDOWS_META_CHARS};
@@ -1 +1 @@
1
- import{spawn as T}from"node:child_process";import{RESOURCE_LIMITS as p}from"../../domain/runtime/resource-limits.js";const d=new WeakMap;function k(e,s){const u=d.get(e);if(u!==void 0)return u;if(e.pid===void 0||e.exitCode!==null||e.signalCode!==null)return Promise.resolve();const a=new Promise((f,l)=>{let t,r;const i=()=>{if(clearTimeout(g),t!==void 0&&clearTimeout(t),e.removeListener("close",c),e.removeListener("error",m),r!==void 0&&r.exitCode===null&&r.signalCode===null)try{r.kill()}catch{}},c=()=>{i(),f()},m=n=>{i(),l(n)},o=n=>{if(s.supportsProcessGroups)try{process.kill(-e.pid,n?"SIGKILL":"SIGTERM");return}catch{}try{e.kill(n?"SIGKILL":"SIGTERM")}catch{}},g=setTimeout(()=>{o(!0),i(),l(new Error(`Process ${String(e.pid)} did not close after forced termination.`))},p.processTerminationTimeoutMs);e.once("close",c),e.once("error",m),s.isWindows?(r=T("taskkill",["/pid",String(e.pid),"/t","/f"],{windowsHide:!0,stdio:"ignore"}),r.once("error",()=>o(!0)),r.once("exit",n=>{n!==0&&o(!0)})):(o(!1),t=setTimeout(()=>o(!0),p.processTerminationGraceMs))});return d.set(e,a),a}export{k as terminatePlatformProcess};
1
+ import{spawn as P}from"node:child_process";import{RESOURCE_LIMITS as p}from"../../domain/runtime/resource-limits.js";const f=new WeakMap;function R(e,t){const u=f.get(e);if(u!==void 0)return u;if(e.pid===void 0||e.exitCode!==null||e.signalCode!==null)return Promise.resolve();const a=new Promise((T,c)=>{let s,n;const i=()=>{if(clearTimeout(S),s!==void 0&&clearTimeout(s),e.removeListener("close",d),e.removeListener("error",l),n!==void 0&&n.exitCode===null&&n.signalCode===null)try{n.kill()}catch{}},d=()=>{i(),T()},l=o=>{i(),c(o)},r=o=>{if(t.supportsProcessGroups)try{process.kill(-e.pid,o?"SIGKILL":"SIGTERM");return}catch{}try{e.kill(o?"SIGKILL":"SIGTERM")}catch{}},S=setTimeout(()=>{r(!0),i(),c(new Error(`Process ${String(e.pid)} did not close after forced termination.`))},p.processTerminationTimeoutMs);if(e.once("close",d),e.once("error",l),t.isWindows){const o=t.env.Path??t.env.PATH??"",m=t.env.SystemRoot??t.env.SYSTEMROOT;n=P("taskkill",["/pid",String(e.pid),"/t","/f"],{env:{Path:o,...m===void 0?{}:{SystemRoot:m}},windowsHide:!0,stdio:"ignore"}),n.once("error",()=>r(!0)),n.once("exit",g=>{g!==0&&r(!0)})}else r(!1),s=setTimeout(()=>r(!0),p.processTerminationGraceMs)});return f.set(e,a),a}export{R as terminatePlatformProcess};
@@ -0,0 +1,26 @@
1
+ import { type PlatformExecOptions, type PlatformExecResult } from '../platform/host-process.js';
2
+ import type { HostPlatformContext } from '../platform/host-platform.js';
3
+ import type { Logger } from '../../ports/logger.js';
4
+ export type WorkspaceMaterializerKind = 'native-cow' | 'copy';
5
+ export type WorkspaceMaterializerFailureClass = 'unsupported' | 'transient' | 'error';
6
+ export type WorkspaceMaterializerCommandRunner = (command: string, args: readonly string[], platform: HostPlatformContext, options?: PlatformExecOptions) => Promise<PlatformExecResult>;
7
+ export interface WorkspaceMaterializerOptions {
8
+ readonly logger?: Logger;
9
+ readonly signal?: AbortSignal;
10
+ readonly sessionId?: string;
11
+ readonly commandRunner?: WorkspaceMaterializerCommandRunner;
12
+ readonly timeoutMs?: number;
13
+ readonly retryAttempts?: number;
14
+ readonly retryBackoffMs?: number;
15
+ }
16
+ export interface WorkspaceMaterializationResult {
17
+ readonly kind: WorkspaceMaterializerKind;
18
+ }
19
+ /**
20
+ * Materializes a session view without changing the source project. Native
21
+ * clone support is opportunistic; correctness always falls back to the
22
+ * existing filtered copy behavior when the host filesystem rejects cloning.
23
+ */
24
+ export declare function materializeWorkspace(source: string, destination: string, platform: HostPlatformContext, options?: WorkspaceMaterializerOptions): Promise<WorkspaceMaterializationResult>;
25
+ export declare function classifyNativeCloneFailure(error: unknown): WorkspaceMaterializerFailureClass;
26
+ export declare function copyWorkingTree(source: string, destination: string, signal?: AbortSignal): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import c from"node:fs/promises";import o from"node:path";import{COPY_EXCLUDED as v}from"../../domain/workspace/workspace-materialization-policy.js";import{RESOURCE_LIMITS as p}from"../../domain/runtime/resource-limits.js";import{execPlatformCommand as P}from"../platform/host-process.js";async function V(e,r,a,t={}){const i=Date.now();await T(e,r),await g(r);const n=C(t);try{const s=await B(e,r,a,n);return s.supported?(await M(r,n.signal),await F(e,r,a,n),t.logger?.info("workspace.materialization.completed",{...t.sessionId===void 0?{}:{sessionId:t.sessionId},materializer:"native-cow",durationMs:Date.now()-i}),{kind:"native-cow"}):(t.logger?.info("workspace.materialization.native_skipped",{...t.sessionId===void 0?{}:{sessionId:t.sessionId},materializer:"native-cow",reason:s.reason,...s.detail===void 0?{}:{detail:s.detail}}),await E(e,r,n,t,i,s.reason))}catch(s){f(n);const u=R(s);return t.logger?.warn("workspace.materialization.native_failed",{...t.sessionId===void 0?{}:{sessionId:t.sessionId},materializer:"native-cow",failureClass:u,retryAttempts:t.retryAttempts??p.workspaceMaterializationRetryAttempts,reason:h(s)}),await E(e,r,n,t,i)}finally{n.dispose()}}async function E(e,r,a,t,i,n){try{await M(r,a.signal),await S(e,r,a.signal)}catch(s){throw t.logger?.error("workspace.materialization.failed",{...t.sessionId===void 0?{}:{sessionId:t.sessionId},materializer:"copy",fallbackFrom:"native-cow",...n===void 0?{}:{fallbackReason:n},reason:h(s)}),s}return t.logger?.info("workspace.materialization.completed",{...t.sessionId===void 0?{}:{sessionId:t.sessionId},materializer:"copy",fallbackFrom:"native-cow",...n===void 0?{}:{fallbackReason:n},durationMs:Date.now()-i}),{kind:"copy"}}function C(e){const r=new AbortController,a=e.timeoutMs??p.workspaceMaterializationTimeoutMs,t=e.retryAttempts??p.workspaceMaterializationRetryAttempts,i=e.retryBackoffMs??p.workspaceMaterializationRetryBackoffMs,n=setTimeout(()=>r.abort(new Error("Workspace materialization timed out.")),a),s=()=>r.abort(e.signal?.reason??new Error("Workspace materialization was cancelled."));return e.signal?.aborted===!0?s():e.signal?.addEventListener("abort",s,{once:!0}),{signal:r.signal,retryAttempts:Math.max(0,Math.floor(t)),retryBackoffMs:Math.max(0,i),commandRunner:e.commandRunner??P,...e.logger===void 0?{}:{logger:e.logger},...e.sessionId===void 0?{}:{sessionId:e.sessionId},dispose:()=>{clearTimeout(n),e.signal?.removeEventListener("abort",s)}}}function f(e){if(!e.signal.aborted)return;const r=e.signal.reason;throw r instanceof Error?r:new Error("Workspace materialization was cancelled.")}async function B(e,r,a,t){if(f(t),a.id==="bsd"||a.id==="unsupported")return{supported:!1,reason:"platform-unsupported"};if(a.id!=="windows")return{supported:!0};const i=b(e),n=b(r);if(i.length===0||i!==n)return{supported:!1,reason:"cross-volume"};try{const s=await t.commandRunner("fsutil.exe",["fsinfo","volumeinfo",i],a,{cwd:i,maxBufferBytes:p.internalProcessOutputBytes,timeoutMs:p.internalProcessTimeoutMs,signal:t.signal});f(t);const u=`${s.stdout}
2
+ ${s.stderr}`;return/\bReFS\b/iu.test(u)?{supported:!0}:{supported:!1,reason:"filesystem-unsupported"}}catch(s){return f(t),{supported:!1,reason:"probe-failed",detail:h(s)}}}function b(e){return o.win32.parse(o.win32.resolve(e)).root.toLowerCase()}async function F(e,r,a,t){await c.mkdir(r,{recursive:!0}),await i(e,"");async function i(n,s){for(const u of await c.readdir(n,{withFileTypes:!0})){if(f(t),v.has(u.name))continue;const l=s.length===0?u.name:o.join(s,u.name),m=o.join(e,l),d=o.join(r,l);if(u.isDirectory())await c.mkdir(d,{recursive:!0}),await i(m,l);else if(u.isSymbolicLink())await c.mkdir(o.dirname(d),{recursive:!0}),await c.symlink(await c.readlink(m),d);else if(u.isFile())await c.mkdir(o.dirname(d),{recursive:!0}),await W(m,d,a,t);else throw new Error(`Unsupported source entry type: ${l}`)}}}async function W(e,r,a,t){for(let i=0;;i+=1){f(t);try{if(a.id==="linux"){await k("cp",["--reflink=always","--preserve=mode,timestamps",e,r],e,a,t),f(t);return}if(a.id==="macos"){await k("cp",["-c","-p",e,r],e,a,t),f(t);return}if(a.id==="windows"){await k("fsutil.exe",["file","clone",e,r],e,a,t),f(t);return}throw new Error("Native workspace cloning is unavailable on this platform.")}catch(n){if(i>=t.retryAttempts||!z(n))throw n;t.logger?.debug("workspace.materialization.native_retry",{...t.sessionId===void 0?{}:{sessionId:t.sessionId},attempt:i+1,maxAttempts:t.retryAttempts}),await j(t.retryBackoffMs*(i+1),t.signal)}}}async function k(e,r,a,t,i){await i.commandRunner(e,r,t,{cwd:o.dirname(a),maxBufferBytes:p.internalProcessOutputBytes,timeoutMs:p.internalProcessTimeoutMs,signal:i.signal})}async function j(e,r){if(e<=0){y(r);return}await new Promise((a,t)=>{let i;const n=u=>{i!==void 0&&clearTimeout(i),r.removeEventListener("abort",s),u===void 0?a():t(u)},s=()=>n(r.reason instanceof Error?r.reason:new Error("Workspace materialization was cancelled."));i=setTimeout(()=>n(),e),r.aborted?s():r.addEventListener("abort",s,{once:!0})}),y(r)}function y(e){if(e?.aborted===!0)throw e.reason instanceof Error?e.reason:new Error("Workspace materialization was cancelled.")}function z(e){const r=h(e);return/(busy|temporarily unavailable|resource unavailable|sharing violation|timed out|try again)/iu.test(r)}function R(e){if(z(e))return"transient";const r=h(e);return/(not supported|operation not permitted|invalid argument|not found|unavailable)/iu.test(r)?"unsupported":"error"}function h(e){return e instanceof Error?e.message:String(e)}async function S(e,r,a){y(a),await T(e,r),await g(r),await c.mkdir(r,{recursive:!0}),await n(e,""),y(a);const[t,i]=await Promise.all([I(e),I(r)]);for(const s of[...i].filter(u=>!t.has(u)).sort((u,l)=>l.split(o.sep).length-u.split(o.sep).length))await L(r,s);async function n(s,u){for(const l of await c.readdir(s,{withFileTypes:!0})){if(y(a),v.has(l.name))continue;const m=u.length===0?l.name:o.join(u,l.name),d=o.join(e,m),w=o.join(r,m);if(l.isDirectory())await c.mkdir(w,{recursive:!0}),await n(d,m);else if(l.isSymbolicLink())await c.mkdir(o.dirname(w),{recursive:!0}),await c.rm(w,{recursive:!0,force:!0}),await c.symlink(await c.readlink(d),w);else if(l.isFile()){await c.mkdir(o.dirname(w),{recursive:!0}),await c.rm(w,{recursive:!0,force:!0}),await c.copyFile(d,w);const A=await c.stat(d);await c.chmod(w,A.mode&4095)}else throw new Error(`Unsupported source entry type: ${m}`)}}}async function M(e,r){await g(e);for(const a of await c.readdir(e,{withFileTypes:!0}))y(r),!v.has(a.name)&&await c.rm(o.join(e,a.name),{recursive:!0,force:!0})}async function I(e){const r=new Set;return await a(e,""),r;async function a(t,i){for(const n of await c.readdir(t,{withFileTypes:!0})){if(v.has(n.name))continue;const s=i.length===0?n.name:o.join(i,n.name);r.add(s),n.isDirectory()&&await a(o.join(t,n.name),s)}}}async function L(e,r){const a=o.resolve(e,r),t=o.relative(o.resolve(e),a);if(t===".."||t.startsWith(`..${o.sep}`)||o.isAbsolute(t))throw new Error("The materialized workspace path escapes its root.");await c.rm(a,{recursive:!0,force:!0})}async function g(e){const r=await c.lstat(e).catch(a=>{if(!(a instanceof Error&&a.code==="ENOENT"))throw a});if(r?.isSymbolicLink())throw new Error("The execution workspace root cannot be a symbolic link.");if(r!==void 0&&!r.isDirectory())throw new Error("The execution workspace root is not a directory.");r===void 0&&await c.mkdir(e,{recursive:!0})}async function T(e,r){const a=await c.realpath(e),t=await N(r),i=o.relative(a,t);if(i.length===0||!i.startsWith(`..${o.sep}`)&&i!==".."&&!o.isAbsolute(i))throw new Error("The execution workspace destination must be outside the source project.")}async function N(e){const r=[];let a=o.resolve(e);for(;;){if(await c.lstat(a).catch(n=>{if(!(n instanceof Error&&n.code==="ENOENT"))throw n})!==void 0)return o.join(await c.realpath(a),...r.reverse());const i=o.dirname(a);if(i===a)return a;r.push(o.basename(a)),a=i}}export{R as classifyNativeCloneFailure,S as copyWorkingTree,V as materializeWorkspace};
@@ -1 +1 @@
1
- import{CliTurnEventProjector as i}from"../../application/orchestration/cli-turn-event-projector.js";import{persistCliTurnEvent as d}from"../../application/orchestration/cli-turn-persistence.js";import{persistContextCompaction as s}from"../../application/agent/context-compaction-persistence.js";import{renderAgentInitialization as c}from"./agent-initialization-renderer.js";import{throwIfAborted as l}from"./tui-lifecycle-actions.js";import{agentLimitNotice as f,classifyAgentLimit as m}from"../../application/agent/agent-limit.js";async function w(e){const a=new i;if(c(e.renderer,await e.prepared.agent.initialize()),e.sessionId!==void 0){const r=await e.runtime.sessionStore.readHistory(e.sessionId);e.agentSessionStore.hydrate(e.sessionId,r.transcript,r.events,e.input)}for await(const r of e.prepared.run({input:e.input,...e.userInput===void 0?{}:{userInput:e.userInput},...e.workspaceContext===void 0?{}:{workspaceContext:e.workspaceContext},...e.inputContent===void 0?{}:{inputContent:e.inputContent},model:e.model,...e.sessionId===void 0?{}:{sessionId:e.sessionId},signal:e.signal})){l(e.signal),e.tracker.observe(r);for(const t of a.observe(r)){if(e.sessionId!==void 0)try{await d(e.runtime.sessionStore,e.sessionId,t,{...e.turnId===void 0?{}:{turnId:e.turnId}})}catch(n){e.runtime.logger.warn("Unable to persist agent lifecycle event.",{eventType:t.type,reason:n instanceof Error?n.message:String(n)})}t.type==="assistant.delta"&&e.appendAssistantDelta(t.content),t.type==="assistant.replaced"&&e.replaceAssistantResponse(t.content),t.type==="assistant.segment.completed"&&(e.renderer.assistantActionBoundary(),t.phase==="final"&&e.renderer.complete(Date.now()-e.startedAt,e.getUsage())),t.type==="action.approval_requested"&&(e.renderer.assistantActionBoundary(),e.renderer.status("Waiting for approval")),t.type==="action.started"&&(e.renderer.assistantActionBoundary(),e.runtime.logger.info("Agent tool called.",{toolName:t.toolName,actionId:t.actionId}),t.toolName!=="agent.spawn"&&e.renderer.toolActivityStarted(t.actionId,t.displayName,{toolName:t.toolName,kind:t.kind})),t.type==="action.completed"&&(e.runtime.logger.info("Agent tool completed.",{toolName:t.toolName,actionId:t.actionId,isError:t.isError}),e.renderer.toolActivityCompleted(t.actionId,t.isError))}if(r.type==="context.compacted"&&(e.sessionId!==void 0&&await s(e.runtime,e.prepared,e.sessionId,r.metrics,e.turnId),e.renderer.transcriptNotice("Context compacted automatically."),e.renderer.activity("Thinking",Date.now()-e.startedAt,e.getUsage())),r.type==="session.failed"){const t=m(r.error);if(t===void 0)throw r.error;e.tracker.markStuck(),e.sessionId!==void 0&&e.agentSessionStore.delete(e.sessionId);const n=f(t);e.hasResponse()?e.renderer.notice(n):e.appendAssistantDelta(n);return}r.type==="session.completed"&&!e.hasResponse()&&e.appendAssistantDelta(r.content)}}export{w as runTuiAgentEvents};
1
+ import{CliTurnEventProjector as s}from"../../application/orchestration/cli-turn-event-projector.js";import{persistCliTurnEvent as i}from"../../application/orchestration/cli-turn-persistence.js";import{persistContextCompaction as d}from"../../application/agent/context-compaction-persistence.js";import{renderAgentInitialization as c}from"./agent-initialization-renderer.js";import{throwIfAborted as f}from"./tui-lifecycle-actions.js";import{agentLimitNotice as u,classifyAgentLimit as l}from"../../application/agent/agent-limit.js";async function w(e){const a=new s;if(c(e.renderer,await e.prepared.agent.initialize()),e.sessionId!==void 0){const r=await e.runtime.sessionStore.readHistory(e.sessionId);e.agentSessionStore.hydrate(e.sessionId,r.transcript,r.events,e.input)}for await(const r of e.prepared.run({input:e.input,...e.userInput===void 0?{}:{userInput:e.userInput},...e.workspaceContext===void 0?{}:{workspaceContext:e.workspaceContext},...e.inputContent===void 0?{}:{inputContent:e.inputContent},model:e.model,...e.sessionId===void 0?{}:{sessionId:e.sessionId},signal:e.signal})){f(e.signal),e.tracker.observe(r);for(const t of a.observe(r)){if(e.sessionId!==void 0)try{await i(e.runtime.sessionStore,e.sessionId,t,{...e.turnId===void 0?{}:{turnId:e.turnId}})}catch(n){e.runtime.logger.warn("Unable to persist agent lifecycle event.",{eventType:t.type,reason:n instanceof Error?n.message:String(n)})}t.type==="assistant.delta"&&e.appendAssistantDelta(t.content),t.type==="assistant.replaced"&&e.replaceAssistantResponse(t.content),t.type==="assistant.segment.started"&&t.phase==="final"&&e.renderer.assistantActionBoundary(),t.type==="assistant.segment.completed"&&(e.renderer.assistantActionBoundary(),t.phase==="final"&&e.renderer.complete(Date.now()-e.startedAt,e.getUsage())),t.type==="action.approval_requested"&&(e.renderer.assistantActionBoundary(),e.renderer.status("Waiting for approval")),t.type==="action.started"&&(e.renderer.assistantActionBoundary(),t.toolName!=="agent.spawn"&&e.renderer.toolActivityStarted(t.actionId,t.displayName,{toolName:t.toolName,kind:t.kind})),t.type==="action.completed"&&e.renderer.toolActivityCompleted(t.actionId,t.isError)}if(r.type==="context.compacted"&&(e.sessionId!==void 0&&await d(e.runtime,e.prepared,e.sessionId,r.metrics,e.turnId),e.renderer.transcriptNotice("Context compacted automatically."),e.renderer.activity("Thinking",Date.now()-e.startedAt,e.getUsage())),r.type==="session.failed"){const t=l(r.error);if(t===void 0)throw r.error;e.tracker.markStuck(),e.sessionId!==void 0&&e.agentSessionStore.delete(e.sessionId);const n=u(t);e.hasResponse()?e.renderer.notice(n):e.appendAssistantDelta(n);return}r.type==="session.completed"&&!e.hasResponse()&&e.appendAssistantDelta(r.content)}}export{w as runTuiAgentEvents};
@@ -1 +1 @@
1
- import{AuthenticationService as j}from"../../application/auth/authentication-service.js";import{loadExecutionConfig as H}from"../../application/config/execution-config.js";import{CliError as B,asCliError as R}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as P}from"../../domain/errors/error-codes.js";import{buildUserMessage as q}from"../../infrastructure/clipboard/image-normalizer.js";import{createLotaGateClient as G}from"../../infrastructure/sdk/lotagate-client-factory.js";import{estimateTurnUsage as $}from"../../infrastructure/tokens/tiktoken-token-estimator.js";import{AgentRunTracker as J}from"../../application/agent/agent-run-tracker.js";import{prepareCliAgent as V}from"../../application/agent/cli-agent-execution-service.js";import{BoundedTextAccumulator as Y}from"../../application/agent/bounded-text-accumulator.js";import{createTurnId as z,recordTurnCompletion as K,recordTurnFailure as Q,recordTurnStart as X}from"../../application/session/session-turn-lifecycle.js";import{createTuiContextManagement as Z,createTuiContinuationContext as ee}from"./tui-context-compaction.js";import{isAbortError as te,throwIfAborted as k}from"./tui-lifecycle-actions.js";import{runTuiAgentEvents as oe}from"./tui-agent-event-runner.js";import{AUTH_LOGIN_HINT as se,MODEL_SELECT_HINT as re,formatCliErrorMessage as M,formatCommandHint as I}from"../../application/commands/command-hints.js";class Ee{host;activeAbortController;activePromptRun;constructor(s){this.host=s}isRunning(){return this.activePromptRun!==void 0}getActiveAbortController(){return this.activeAbortController}setActiveAbortController(s){this.activeAbortController=s}abortActive(s){this.activeAbortController?.abort(s)}async runPrompt(s,n,g){return this.sendPrompt(s,this.host.pendingAttachments.list(),n,g)}async sendPrompt(s,n=[],g,d){if(this.activePromptRun!==void 0)return this.host.renderer.notice("A response is already running. Stop it before sending another prompt."),"";try{this.host.pendingAttachments.assertPromptFits(s,n)}catch(A){const w=R(A);return this.host.renderer.error(M(w,"tui")),""}const u=this.host.getSession(),h=u===void 0?void 0:await this.host.executionWorkspaces.acquireTurn(u.id),m=this.executePrompt(s,n,g,d);this.activePromptRun=m,this.host.renderer.setRunActive(!0);try{return await m}finally{this.activePromptRun===m&&(this.activePromptRun=void 0),this.host.renderer.setRunActive(!1),await h?.()}}async executePrompt(s,n,g,d){const u=await H(this.host.runtime,this.host.cwd),h=this.host.getActiveModel()??u.config.model;if(h===null)return this.host.renderer.error(`No model is selected. ${I(re,"tui")}`),"";const m=this.host.getActiveProfile()??u.config.profile??j.defaultProfileName(),A=await this.host.runtime.credentialStore.get(m);if(A===void 0)return this.host.renderer.error(`No API key is configured. ${I(se,"tui")}`),"";const w=await this.host.runtime.projectTrust.inspect(this.host.cwd),t=this.host.getSession();t!==void 0&&this.host.setExecutionWorkspace(await this.host.executionWorkspaces.prepare({sessionId:t.id,projectRoot:w.canonicalPath})),await this.host.runHookEvent("prompt.before",t?.id??"tui"),this.host.renderer.userPrompt(s,n.map(({attachment:e})=>e));const C=z();t!==void 0&&await X(this.host.runtime.sessionStore,t.id,C,s,n.map(({attachment:e})=>e.id));const x=Date.now();let c,v=!1;this.host.renderer.status("Thinking");const p=new AbortController;this.activeAbortController=p;const T=G(A.profile,A.apiKey),U=await this.host.runtime.projectTrust.isTrusted(w),o=t===void 0?void 0:await this.host.runtime.goalStore.get(t.id),i=new J,L={start:e=>this.host.renderer.startToolActivity(e.key,e.label)},N={onSubagentLifecycle:e=>{e.sessionId===t?.id&&this.host.renderer.subagentLifecycle(e)}},W=await this.host.contextService.getModelContextWindow(h,m),_=e=>{i.observeModel(e),e.usage!==void 0&&(c=e.usage,v=!0,d?.onUsage({usage:e.usage,modelCalls:1})),this.host.runtime.logger.debug("Model turn completed.",{model:e.model,stream:e.stream,contentLength:e.contentLength,toolCallCount:e.toolCallCount,toolNames:e.toolNames,finishReason:e.finishReason})},E=await V({runtime:this.host.runtime,projectRoot:w.canonicalPath,executionCwd:this.host.getExecutionWorkspace().executionCwd,executionWorkspaceId:this.host.getExecutionWorkspace().id,model:h,reasoningEffort:u.config.effort,client:T,profile:U?"interactive-trusted":"interactive-untrusted",approvalMode:u.config.approvalMode,subagentJobs:this.host.getSubagentJobs(),...g===void 0?{}:{initialSkill:g},onWrite:e=>this.host.renderer.fileChange(e),prompt:(e,a)=>this.host.approvals.ask(e,a),rememberApproval:e=>this.host.approvals.remember(w.canonicalPath,e),onApprovalPersistenceFailure:(e,a)=>this.host.approvals.rememberFailure(a),audit:e=>this.host.approvals.audit(e),onModelComplete:_,onSubagentModelComplete:e=>{e.usage!==void 0&&d?.onUsage({usage:e.usage,modelCalls:1})},contextManagement:Z(T,h,W,e=>this.host.runtime.logger.warn("Context summarization failed; using fallback summary.",{reason:e instanceof Error?e.message:String(e)}),()=>ee(i.snapshot(),o)),agentSessionStore:this.host.agentSessionStore,toolActivity:L,onIntentLifecycle:e=>{e.type==="intent.compiled"?this.host.renderer.status("Understanding the task"):e.type==="intent.verification.required"?this.host.renderer.status("Verifying the result"):e.type==="intent.blocked"&&this.host.renderer.status("Verification is incomplete")},subagentLifecycle:N,...o===void 0?{}:{goal:{objective:o.objective,status:o.status,turns:o.turns,evaluatorRuns:o.evaluatorRuns,tokensUsed:o.usage.totalTokens,...o.tokenBudget===void 0?{}:{tokenBudget:o.tokenBudget},...o.maxTurns===void 0?{}:{maxTurns:o.maxTurns},...o.maxDurationMs===void 0?{}:{maxDurationMs:o.maxDurationMs},...o.lastError===void 0?{}:{lastError:o.lastError},...o.lastEvaluation===void 0?{}:{lastEvaluation:o.lastEvaluation.reason}}}}),f=new Y;let S=!1;const D=e=>{k(p.signal),f.append(e),this.host.renderer.assistantDelta(e)},F=e=>{k(p.signal),f.replace(e),this.host.renderer.replaceAssistant(e)};try{k(p.signal);const e=await E.buildInput(s);this.host.pendingAttachments.assertPromptFits(e.input,n);const a=n.length===0?void 0:q(e.input,n),r=a?.content===null?void 0:a?.content;if(await oe({prepared:E,input:e.input,userInput:e.userInput,...e.workspaceContext===void 0?{}:{workspaceContext:e.workspaceContext},...r===void 0?{}:{inputContent:r},model:h,...t===void 0?{}:{sessionId:t.id},turnId:C,signal:p.signal,agentSessionStore:this.host.agentSessionStore,tracker:i,runtime:this.host.runtime,renderer:this.host.renderer,startedAt:x,getUsage:()=>c,appendAssistantDelta:D,replaceAssistantResponse:F,hasResponse:()=>!f.isEmpty}),f.toString().trim().length===0){const l=i.snapshot();l.toolCalls>0&&i.markStuck();const O=l.toolCalls>0?P.MODEL_EMPTY_FINAL:P.MODEL_PROTOCOL_EMPTY_RESPONSE,y=l.toolCalls>0?"The model completed its tool work without a final text response.":"The model returned neither text nor a tool call.";throw new B(O,y,{category:"model",userMessage:`${y} Check the selected model and gateway tool-calling support, then try again.`,retryable:!0,details:{modelTurns:l.modelTurns,toolCalls:l.toolCalls,toolCompletions:l.toolCompletions,toolFailures:l.toolFailures,toolNames:l.toolNames,finishReason:l.lastFinishReason}})}t!==void 0&&(await this.host.executionWorkspaces.apply(t.id),S=!0),d?.onSnapshot(i.snapshot())}catch(e){const a=p.signal.aborted||te(e);if(t!==void 0&&!S)try{const r=await this.host.executionWorkspaces.apply(t.id);S=!0,r.appliedPaths.length>0&&this.host.runtime.logger.info("Applied session workspace changes after turn failure.",{sessionId:t.id,turnId:C,appliedPaths:r.appliedPaths})}catch(r){this.host.runtime.logger.error("Failed to apply session workspace changes after turn failure.",{sessionId:t.id,turnId:C,reason:r instanceof Error?r.message:String(r)})}if(t!==void 0&&this.host.agentSessionStore.delete(t.id),a?i.markCancelled():i.snapshot().state!=="stuck"&&i.markFailed(),t!==void 0&&await Q(this.host.runtime.sessionStore,t.id,C,e,a),this.host.renderer.finishAssistant(),a)this.host.renderer.notice("Interrupted.");else{const r=R(e);this.host.renderer.failed(),this.host.runtime.logger.error("Agent run failed.",{code:r.code,category:r.category,...r.details??{}}),this.host.renderer.error(M(r,"tui"))}return d?.onError(e),d?.onSnapshot(i.snapshot()),""}finally{this.activeAbortController===p&&(this.activeAbortController=void 0);try{await E.close()}catch(e){this.host.runtime.logger.warn("Agent cleanup failed after a completed turn.",{reason:e instanceof Error?e.message:String(e)})}if(t!==void 0)try{await this.host.executionWorkspaces.markReady(t.id)}catch(e){this.host.runtime.logger.warn("Unable to release TUI execution workspace after turn.",{sessionId:t.id,reason:e instanceof Error?e.message:String(e)})}}this.host.renderer.finishAssistant();try{t!==void 0&&await K(this.host.runtime.sessionStore,t.id,C,f.toString())}catch(e){this.host.runtime.logger.warn("Unable to persist the completed turn.",{reason:e instanceof Error?e.message:String(e)}),this.host.renderer.notice("Response completed, but the session state could not be saved.")}try{await this.host.runHookEvent("response.after",t?.id??"tui")}catch(e){this.host.runtime.logger.warn("Response hook failed after a completed turn.",{reason:e instanceof Error?e.message:String(e)}),this.host.renderer.notice("Response completed, but the response hook failed.")}this.host.pendingAttachments.clear(),this.host.renderer.setPendingAttachments([]),!v&&c!==void 0&&d?.onUsage({usage:c,modelCalls:1});const b=c?.totalTokens===void 0?$({model:h,prompt:s,response:f.toString()}):c;return!v&&c===void 0&&b!==void 0&&d?.onUsage({usage:b,modelCalls:1}),this.host.renderer.complete(Date.now()-x,b),await this.host.refreshContextUsage(),f.toString()}}export{Ee as TuiAgentTurnController};
1
+ import{AuthenticationService as H}from"../../application/auth/authentication-service.js";import{loadExecutionConfig as $}from"../../application/config/execution-config.js";import{CliError as B,asCliError as P}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as M}from"../../domain/errors/error-codes.js";import{buildUserMessage as q}from"../../infrastructure/clipboard/image-normalizer.js";import{createLotaGateClient as G}from"../../infrastructure/sdk/lotagate-client-factory.js";import{estimateTurnUsage as J}from"../../infrastructure/tokens/tiktoken-token-estimator.js";import{AgentRunTracker as V}from"../../application/agent/agent-run-tracker.js";import{prepareCliAgent as Y}from"../../application/agent/cli-agent-execution-service.js";import{BoundedTextAccumulator as z}from"../../application/agent/bounded-text-accumulator.js";import{createTurnId as K,recordTurnCompletion as Q,recordTurnFailure as X,recordTurnStart as Z}from"../../application/session/session-turn-lifecycle.js";import{createTuiContextManagement as ee,createTuiContinuationContext as te}from"./tui-context-compaction.js";import{isAbortError as oe,throwIfAborted as x}from"./tui-lifecycle-actions.js";import{runTuiAgentEvents as se}from"./tui-agent-event-runner.js";import{AUTH_LOGIN_HINT as ne,MODEL_SELECT_HINT as re,formatCliErrorMessage as I,formatCommandHint as U}from"../../application/commands/command-hints.js";class Se{host;activeAbortController;activePromptRun;constructor(s){this.host=s}isRunning(){return this.activePromptRun!==void 0}getActiveAbortController(){return this.activeAbortController}setActiveAbortController(s){this.activeAbortController=s}abortActive(s){this.activeAbortController?.abort(s)}async runPrompt(s,i,g){return this.sendPrompt(s,this.host.pendingAttachments.list(),i,g)}async sendPrompt(s,i=[],g,d){if(this.activePromptRun!==void 0)return this.host.renderer.notice("A response is already running. Stop it before sending another prompt."),"";try{this.host.pendingAttachments.assertPromptFits(s,i)}catch(A){const w=P(A);return this.host.renderer.error(I(w,"tui")),""}const u=this.host.getSession(),c=u===void 0?void 0:await this.host.executionWorkspaces.acquireTurn(u.id),m=this.executePrompt(s,i,g,d);this.activePromptRun=m,this.host.renderer.setRunActive(!0);try{return await m}finally{this.activePromptRun===m&&(this.activePromptRun=void 0),this.host.renderer.setRunActive(!1),await c?.()}}async executePrompt(s,i,g,d){const u=await $(this.host.runtime,this.host.cwd),c=this.host.getActiveModel()??u.config.model;if(c===null)return this.host.renderer.error(`No model is selected. ${U(re,"tui")}`),"";const m=this.host.getActiveProfile()??u.config.profile??H.defaultProfileName(),A=await this.host.runtime.credentialStore.get(m);if(A===void 0)return this.host.renderer.error(`No API key is configured. ${U(ne,"tui")}`),"";const w=await this.host.runtime.projectTrust.inspect(this.host.cwd),t=this.host.getSession();t!==void 0&&this.host.setExecutionWorkspace(await this.host.executionWorkspaces.prepare({sessionId:t.id,projectRoot:w.canonicalPath})),await this.host.runHookEvent("prompt.before",t?.id??"tui"),this.host.renderer.userPrompt(s,i.map(({attachment:e})=>e));const C=K();t!==void 0&&await Z(this.host.runtime.sessionStore,t.id,C,s,i.map(({attachment:e})=>e.id));const v=Date.now();let l,E=!1;this.host.renderer.status("Thinking");const p=new AbortController;this.activeAbortController=p;const T=G(A.profile,A.apiKey),L=await this.host.runtime.projectTrust.isTrusted(w),o=t===void 0?void 0:await this.host.runtime.goalStore.get(t.id),a=new V,D={start:e=>this.host.renderer.startToolActivity(e.key,e.label)},N={onSubagentLifecycle:e=>{e.sessionId===t?.id&&this.host.renderer.subagentLifecycle(e)}},W=await this.host.contextService.getModelContextWindow(c,m),_=e=>{a.observeModel(e),e.usage!==void 0&&(l=e.usage,E=!0,d?.onUsage({usage:e.usage,modelCalls:1})),this.host.runtime.logger.debug("Model turn completed.",{model:e.model,stream:e.stream,contentLength:e.contentLength,toolCallCount:e.toolCallCount,toolNames:e.toolNames,finishReason:e.finishReason})},R={onReconnect:({attempt:e,maxAttempts:r})=>this.host.renderer.activity(`Reconnecting ${e}/${r}`,Date.now()-v,l),onReconnected:()=>this.host.renderer.activity("Thinking",Date.now()-v,l)},S=await Y({runtime:this.host.runtime,projectRoot:w.canonicalPath,executionCwd:this.host.getExecutionWorkspace().executionCwd,executionWorkspaceId:this.host.getExecutionWorkspace().id,model:c,reasoningEffort:u.config.effort,client:T,profile:L?"interactive-trusted":"interactive-untrusted",approvalMode:u.config.approvalMode,subagentJobs:this.host.getSubagentJobs(),...g===void 0?{}:{initialSkill:g},onWrite:e=>this.host.renderer.fileChange(e),prompt:(e,r)=>this.host.approvals.ask(e,r),rememberApproval:e=>this.host.approvals.remember(w.canonicalPath,e),onApprovalPersistenceFailure:(e,r)=>this.host.approvals.rememberFailure(r),audit:e=>this.host.approvals.audit(e),onModelComplete:_,networkRecovery:R,onSubagentModelComplete:e=>{e.usage!==void 0&&d?.onUsage({usage:e.usage,modelCalls:1})},contextManagement:ee(T,c,W,e=>this.host.runtime.logger.warn("Context summarization failed; using fallback summary.",{reason:e instanceof Error?e.message:String(e)}),()=>te(a.snapshot(),o),R),agentSessionStore:this.host.agentSessionStore,toolActivity:D,onIntentLifecycle:e=>{e.type==="intent.compiled"?this.host.renderer.status("Understanding the task"):e.type==="intent.verification.required"?this.host.renderer.status("Verifying the result"):e.type==="intent.blocked"&&this.host.renderer.status("Verification is incomplete")},subagentLifecycle:N,...o===void 0?{}:{goal:{objective:o.objective,status:o.status,turns:o.turns,evaluatorRuns:o.evaluatorRuns,tokensUsed:o.usage.totalTokens,...o.tokenBudget===void 0?{}:{tokenBudget:o.tokenBudget},...o.maxTurns===void 0?{}:{maxTurns:o.maxTurns},...o.maxDurationMs===void 0?{}:{maxDurationMs:o.maxDurationMs},...o.lastError===void 0?{}:{lastError:o.lastError},...o.lastEvaluation===void 0?{}:{lastEvaluation:o.lastEvaluation.reason}}}}),f=new z;let k=!1;const F=e=>{x(p.signal),f.append(e),this.host.renderer.assistantDelta(e)},O=e=>{x(p.signal),f.replace(e),this.host.renderer.replaceAssistant(e)};try{x(p.signal);const e=await S.buildInput(s);this.host.pendingAttachments.assertPromptFits(e.input,i);const r=i.length===0?void 0:q(e.input,i),n=r?.content===null?void 0:r?.content;if(await se({prepared:S,input:e.input,userInput:e.userInput,...e.workspaceContext===void 0?{}:{workspaceContext:e.workspaceContext},...n===void 0?{}:{inputContent:n},model:c,...t===void 0?{}:{sessionId:t.id},turnId:C,signal:p.signal,agentSessionStore:this.host.agentSessionStore,tracker:a,runtime:this.host.runtime,renderer:this.host.renderer,startedAt:v,getUsage:()=>l,appendAssistantDelta:F,replaceAssistantResponse:O,hasResponse:()=>!f.isEmpty}),f.toString().trim().length===0){const h=a.snapshot();h.toolCalls>0&&a.markStuck();const j=h.toolCalls>0?M.MODEL_EMPTY_FINAL:M.MODEL_PROTOCOL_EMPTY_RESPONSE,y=h.toolCalls>0?"The model completed its tool work without a final text response.":"The model returned neither text nor a tool call.";throw new B(j,y,{category:"model",userMessage:`${y} Check the selected model and gateway tool-calling support, then try again.`,retryable:!0,details:{modelTurns:h.modelTurns,toolCalls:h.toolCalls,toolCompletions:h.toolCompletions,toolFailures:h.toolFailures,toolNames:h.toolNames,finishReason:h.lastFinishReason}})}t!==void 0&&(await this.host.executionWorkspaces.apply(t.id),k=!0),d?.onSnapshot(a.snapshot())}catch(e){const r=p.signal.aborted||oe(e);if(t!==void 0&&!k)try{const n=await this.host.executionWorkspaces.apply(t.id);k=!0,n.appliedPaths.length>0&&this.host.runtime.logger.info("Applied session workspace changes after turn failure.",{sessionId:t.id,turnId:C,appliedPaths:n.appliedPaths})}catch(n){this.host.runtime.logger.error("Failed to apply session workspace changes after turn failure.",{sessionId:t.id,turnId:C,reason:n instanceof Error?n.message:String(n)})}if(t!==void 0&&this.host.agentSessionStore.delete(t.id),r?a.markCancelled():a.snapshot().state!=="stuck"&&a.markFailed(),t!==void 0&&await X(this.host.runtime.sessionStore,t.id,C,e,r),this.host.renderer.finishAssistant(),r)this.host.renderer.notice("Interrupted.");else{const n=P(e);this.host.renderer.failed(),this.host.runtime.logger.error("Agent run failed.",{code:n.code,category:n.category,...n.details??{}}),this.host.renderer.error(I(n,"tui"))}return d?.onError(e),d?.onSnapshot(a.snapshot()),""}finally{this.activeAbortController===p&&(this.activeAbortController=void 0);try{await S.close()}catch(e){this.host.runtime.logger.warn("Agent cleanup failed after a completed turn.",{reason:e instanceof Error?e.message:String(e)})}if(t!==void 0)try{await this.host.executionWorkspaces.markReady(t.id)}catch(e){this.host.runtime.logger.warn("Unable to release TUI execution workspace after turn.",{sessionId:t.id,reason:e instanceof Error?e.message:String(e)})}}this.host.renderer.finishAssistant();try{t!==void 0&&await Q(this.host.runtime.sessionStore,t.id,C,f.toString())}catch(e){this.host.runtime.logger.warn("Unable to persist the completed turn.",{reason:e instanceof Error?e.message:String(e)}),this.host.renderer.notice("Response completed, but the session state could not be saved.")}try{await this.host.runHookEvent("response.after",t?.id??"tui")}catch(e){this.host.runtime.logger.warn("Response hook failed after a completed turn.",{reason:e instanceof Error?e.message:String(e)}),this.host.renderer.notice("Response completed, but the response hook failed.")}this.host.pendingAttachments.clear(),this.host.renderer.setPendingAttachments([]),!E&&l!==void 0&&d?.onUsage({usage:l,modelCalls:1});const b=l?.totalTokens===void 0?J({model:c,prompt:s,response:f.toString()}):l;return!E&&l===void 0&&b!==void 0&&d?.onUsage({usage:b,modelCalls:1}),this.host.renderer.complete(Date.now()-v,b),await this.host.refreshContextUsage(),f.toString()}}export{Se as TuiAgentTurnController};
@@ -1,3 +1,3 @@
1
- import{createElement as f}from"react";import{render as w}from"ink";import{detectTerminalCapabilities as v}from"./terminal-capabilities.js";import{enterInteractiveScreen as S,exitInteractiveScreen as b}from"./terminal-screen.js";import{createImageAttachment as x,normalizeImage as C}from"../../infrastructure/clipboard/image-normalizer.js";import{PendingAttachmentStore as A}from"../../application/chat/pending-attachment-store.js";import{CLI_VERSION as u}from"../../version.js";import{InkTuiBridge as k}from"./ink/tui-bridge.js";import{LotaGateTui as P}from"./ink/lotagate-tui.js";import{WorkspaceFileIndex as y}from"../../application/workspace/workspace-file-index.js";import{ProjectSessionAccess as T}from"../../application/session/project-session-access.js";import{createTuiCommandHost as I}from"./tui-command-host-factory.js";import{workspaceFileSuggestions as E}from"./tui-file-suggestions.js";import{warmMcpRuntime as R}from"../../application/agent/cli-agent-execution-service.js";import{TuiToolApprovalCoordinator as M}from"./tui-tool-approval.js";import{TuiContextService as W}from"./tui-context-service.js";import{createTuiClipboardPasteHandlers as U}from"./tui-clipboard-paste-handlers.js";import{dispatchTuiPrompt as j}from"./tui-prompt-dispatcher.js";import{CliAgentSessionStore as H,retainLatestCompaction as m}from"../../application/agent/agent-session-store.js";import{compactManualTuiSession as F}from"./tui-manual-compaction.js";import{resolveInitialModel as p}from"./tui-initial-model.js";import{cancelTuiResponse as O,handleTuiInterrupt as G,isAbortError as L,runTuiHookEvent as N}from"./tui-lifecycle-actions.js";import{loadExecutionConfig as B}from"../../application/config/execution-config.js";import{resumeTuiGoal as D,runTuiGoal as $}from"./tui-goal-controller.js";import{runTuiSkill as J}from"./tui-skill-controller.js";import{SubagentJobRegistry as g}from"../../application/orchestration/cli-subagent-service.js";import{formatResumeCommand as z}from"./tui-application-contract.js";import{SessionExecutionWorkspaceService as q}from"../../application/workspace/session-execution-workspace.js";import{loadTuiExtensions as V}from"./tui-extension-loader.js";import{TuiAgentTurnController as _}from"./tui-agent-turn-controller.js";import{OperationRegistry as K}from"../../application/lifecycle/operation-registry.js";class It{runtime;cwd;options;input;output;renderer;pendingAttachments=new A;session;hookRuntime;hooks=[];skillRootScopes=[];enabledPluginNames=[];pluginMcpConfig={};activeForegroundRun;exitArmedUntil=0;lastInterruptAt=0;printResumeCommandOnExit=!1;activeModel=null;activeProfile=null;approvals;contextService;agentSessionStore=new H;backgroundOperations=new K;subagentJobs=new g;executionWorkspaces;executionWorkspace;turnController;constructor(i,t,e={}){this.runtime=i,this.cwd=t,this.options=e,this.input=e.input??process.stdin,this.output=e.output??process.stdout,this.renderer=new k,this.executionWorkspaces=this.runtime.executionWorkspaces??new q(this.runtime.paths.globalConfigDir,this.runtime.platform),this.contextService=new W(this.runtime,this.cwd),this.approvals=new M({renderer:this.renderer,runtime:this.runtime,getSessionId:()=>this.session?.id,getActiveSignal:()=>this.turnController.getActiveAbortController()?.signal}),this.turnController=new _({runtime:this.runtime,cwd:this.cwd,renderer:this.renderer,pendingAttachments:this.pendingAttachments,approvals:this.approvals,contextService:this.contextService,agentSessionStore:this.agentSessionStore,executionWorkspaces:this.executionWorkspaces,getSession:()=>this.session,getActiveModel:()=>this.activeModel,getActiveProfile:()=>this.activeProfile,getExecutionWorkspace:()=>this.executionWorkspace,setExecutionWorkspace:r=>{this.executionWorkspace=r},getSubagentJobs:()=>this.subagentJobs,runHookEvent:(r,s)=>this.runHookEvent(r,s),refreshContextUsage:()=>this.refreshContextUsage()}),this.renderer.setInterruptHandler(()=>this.handleInterrupt()),this.renderer.setCancelHandler(()=>O(this.turnController.getActiveAbortController(),this.renderer));const n=U({platform:this.runtime.platform,notify:r=>this.renderer.notice(r),attachImage:(r,s)=>this.attachClipboardImage(r,!1,s)});this.renderer.setImagePasteHandler(n.image),this.renderer.setTextPasteHandler(n.text),this.renderer.setClearAttachmentsHandler(()=>{this.pendingAttachments.clear(),this.renderer.setPendingAttachments([])})}async run(){if(!v(this.input,this.output).isInteractive)return this.output.write('Interactive TUI requires a terminal. Use `lotagate chat "prompt"` for non-interactive streaming.\n'),2;S(this.output);const t=w(f(P,{bridge:this.renderer}),{stdin:this.input,stdout:this.output,exitOnCtrlC:!1}),e=()=>this.handleInterrupt(),n=()=>{const s=new Error("Interactive session is shutting down.");this.backgroundOperations.abort(s),this.turnController.abortActive(s),this.renderer.requestExit(143)};process.on("SIGINT",e),this.options.signal?.addEventListener("abort",n,{once:!0});let r="completed";try{const s=await this.runtime.projectTrust.inspect(this.cwd);let o=await this.runtime.projectTrust.isTrusted(s),h=await this.runtime.configLoader.load(this.cwd,{includeProject:o}),l=await p(this.runtime,h.config),c={...h,config:{...h.config,model:l}};if(this.activeModel=c.config.model,this.activeProfile=c.config.profile,this.renderer.setWelcome({version:u,cwd:s.canonicalPath,model:c.config.model,profile:c.config.profile,trusted:o}),this.renderer.setFileSuggestions([]),o||(o=await this.renderer.confirmTrust(),o?(await this.runtime.projectTrust.grant(s),h=await this.runtime.configLoader.load(this.cwd),l=await p(this.runtime,h.config),c={...h,config:{...h.config,model:l}},this.activeModel=c.config.model,this.activeProfile=c.config.profile,this.renderer.setWelcome({version:u,cwd:s.canonicalPath,model:this.activeModel,profile:this.activeProfile,trusted:!0}),this.renderer.notice("Project trusted.")):this.renderer.notice("Project remains untrusted; local tools and extensions stay disabled.")),o&&await this.runtime.workspaceSettings.ensureInitialized(s.canonicalPath),await this.reloadExtensions(o,c.config.approvalMode,s.canonicalPath),this.options.sessionId!==void 0){const a=await this.runtime.sessionStore.get(this.options.sessionId);if(a===void 0)throw new Error(`Session not found: ${this.options.sessionId}`);if(a.projectFingerprint!==s.fingerprint)throw new Error("Session belongs to another project.");this.session=a,this.renderer.status(`Resuming session ${a.id}`);for(const d of m(await this.runtime.sessionStore.readTranscript(a.id)))d.type==="user"?this.renderer.userPrompt(d.content):d.type==="assistant"&&(this.renderer.beginAssistant(),this.renderer.assistantDelta(d.content),this.renderer.finishAssistant())}else this.session=await this.runtime.sessionStore.create({projectFingerprint:s.fingerprint,cwd:s.canonicalPath,model:c.config.model,profile:c.config.profile,status:"active"});return this.executionWorkspace=await this.executionWorkspaces.prepare({sessionId:this.session.id,projectRoot:s.canonicalPath}),await this.refreshContextUsage(),await this.runHookEvent("session.start",this.session.id),this.startBackgroundMcpWarmup(),this.renderer.setSubmitHandler(async a=>{await this.processPrompt(a)&&this.renderer.requestExit()}),this.renderer.clearActivity(),this.renderer.setReady(),this.backgroundOperations.start(a=>new y(s.canonicalPath).listEntries(a)).then(a=>this.renderer.setFileSuggestions(E(a))).catch(a=>this.runtime.logger.debug("Unable to load workspace file suggestions.",{reason:a instanceof Error?a.message:String(a)})),await this.renderer.waitForExit()}catch(s){throw r=L(s)?"cancelled":"failed",s}finally{this.turnController.abortActive(new Error("Interactive session is closing.")),await this.backgroundOperations.close(),this.renderer.resolveActiveModal(void 0),await this.awaitActiveForegroundRun();try{await this.subagentJobs.close()}catch(s){this.runtime.logger.warn("Unable to close subagent jobs during TUI shutdown.",{reason:s instanceof Error?s.message:String(s)})}if(this.agentSessionStore.clear(),this.session!==void 0){try{await this.runHookEvent("session.end",this.session.id)}catch(s){this.runtime.logger.warn("Session end hook failed during TUI shutdown.",{sessionId:this.session.id,reason:s instanceof Error?s.message:String(s)})}try{await this.runtime.sessionStore.updateStatus(this.session.id,r)}catch(s){this.runtime.logger.warn("Unable to update TUI session status during shutdown.",{sessionId:this.session.id,reason:s instanceof Error?s.message:String(s)})}try{await this.executionWorkspaces.markReady(this.session.id)}catch(s){this.runtime.logger.warn("Unable to release TUI execution workspace.",{sessionId:this.session.id,reason:s instanceof Error?s.message:String(s)})}}process.off("SIGINT",e),this.options.signal?.removeEventListener("abort",n),this.renderer.dispose(),t.unmount(),b(this.output),this.printResumeCommandOnExit&&this.session!==void 0&&this.output.write(`
1
+ import{createElement as f}from"react";import{render as w}from"ink";import{detectTerminalCapabilities as v}from"./terminal-capabilities.js";import{enterInteractiveScreen as S,exitInteractiveScreen as b}from"./terminal-screen.js";import{createImageAttachment as x,normalizeImage as C}from"../../infrastructure/clipboard/image-normalizer.js";import{PendingAttachmentStore as A}from"../../application/chat/pending-attachment-store.js";import{CLI_VERSION as u}from"../../version.js";import{InkTuiBridge as k}from"./ink/tui-bridge.js";import{LotaGateTui as P}from"./ink/lotagate-tui.js";import{WorkspaceFileIndex as y}from"../../application/workspace/workspace-file-index.js";import{ProjectSessionAccess as T}from"../../application/session/project-session-access.js";import{createTuiCommandHost as I}from"./tui-command-host-factory.js";import{workspaceFileSuggestions as E}from"./tui-file-suggestions.js";import{warmMcpRuntime as R}from"../../application/agent/cli-agent-execution-service.js";import{TuiToolApprovalCoordinator as M}from"./tui-tool-approval.js";import{TuiContextService as W}from"./tui-context-service.js";import{createTuiClipboardPasteHandlers as U}from"./tui-clipboard-paste-handlers.js";import{dispatchTuiPrompt as j}from"./tui-prompt-dispatcher.js";import{CliAgentSessionStore as H,retainLatestCompaction as m}from"../../application/agent/agent-session-store.js";import{compactManualTuiSession as F}from"./tui-manual-compaction.js";import{resolveInitialModel as p}from"./tui-initial-model.js";import{cancelTuiResponse as O,handleTuiInterrupt as G,isAbortError as L,runTuiHookEvent as D}from"./tui-lifecycle-actions.js";import{loadExecutionConfig as N}from"../../application/config/execution-config.js";import{resumeTuiGoal as B,runTuiGoal as $}from"./tui-goal-controller.js";import{runTuiSkill as J}from"./tui-skill-controller.js";import{SubagentJobRegistry as g}from"../../application/orchestration/cli-subagent-service.js";import{formatResumeCommand as z}from"./tui-application-contract.js";import{SessionExecutionWorkspaceService as q}from"../../application/workspace/session-execution-workspace.js";import{loadTuiExtensions as V}from"./tui-extension-loader.js";import{TuiAgentTurnController as _}from"./tui-agent-turn-controller.js";import{OperationRegistry as K}from"../../application/lifecycle/operation-registry.js";class It{runtime;cwd;options;input;output;renderer;pendingAttachments=new A;session;hookRuntime;hooks=[];skillRootScopes=[];enabledPluginNames=[];pluginMcpConfig={};activeForegroundRun;exitArmedUntil=0;lastInterruptAt=0;printResumeCommandOnExit=!1;activeModel=null;activeProfile=null;approvals;contextService;agentSessionStore=new H;backgroundOperations=new K;subagentJobs=new g;executionWorkspaces;executionWorkspace;turnController;constructor(i,t,e={}){this.runtime=i,this.cwd=t,this.options=e,this.input=e.input??process.stdin,this.output=e.output??process.stdout,this.renderer=new k,this.executionWorkspaces=this.runtime.executionWorkspaces??new q(this.runtime.paths.globalConfigDir,this.runtime.platform,Date.now,this.runtime.logger),this.contextService=new W(this.runtime,this.cwd),this.approvals=new M({renderer:this.renderer,runtime:this.runtime,getSessionId:()=>this.session?.id,getActiveSignal:()=>this.turnController.getActiveAbortController()?.signal}),this.turnController=new _({runtime:this.runtime,cwd:this.cwd,renderer:this.renderer,pendingAttachments:this.pendingAttachments,approvals:this.approvals,contextService:this.contextService,agentSessionStore:this.agentSessionStore,executionWorkspaces:this.executionWorkspaces,getSession:()=>this.session,getActiveModel:()=>this.activeModel,getActiveProfile:()=>this.activeProfile,getExecutionWorkspace:()=>this.executionWorkspace,setExecutionWorkspace:r=>{this.executionWorkspace=r},getSubagentJobs:()=>this.subagentJobs,runHookEvent:(r,s)=>this.runHookEvent(r,s),refreshContextUsage:()=>this.refreshContextUsage()}),this.renderer.setInterruptHandler(()=>this.handleInterrupt()),this.renderer.setCancelHandler(()=>O(this.turnController.getActiveAbortController(),this.renderer));const n=U({platform:this.runtime.platform,notify:r=>this.renderer.notice(r),attachImage:(r,s)=>this.attachClipboardImage(r,!1,s)});this.renderer.setImagePasteHandler(n.image),this.renderer.setTextPasteHandler(n.text),this.renderer.setClearAttachmentsHandler(()=>{this.pendingAttachments.clear(),this.renderer.setPendingAttachments([])})}async run(){if(!v(this.input,this.output).isInteractive)return this.output.write('Interactive TUI requires a terminal. Use `lotagate chat "prompt"` for non-interactive streaming.\n'),2;S(this.output);const t=w(f(P,{bridge:this.renderer}),{stdin:this.input,stdout:this.output,exitOnCtrlC:!1}),e=()=>this.handleInterrupt(),n=()=>{const s=new Error("Interactive session is shutting down.");this.backgroundOperations.abort(s),this.turnController.abortActive(s),this.renderer.requestExit(143)};process.on("SIGINT",e),this.options.signal?.addEventListener("abort",n,{once:!0});let r="completed";try{const s=await this.runtime.projectTrust.inspect(this.cwd);let o=await this.runtime.projectTrust.isTrusted(s),h=await this.runtime.configLoader.load(this.cwd,{includeProject:o}),l=await p(this.runtime,h.config),c={...h,config:{...h.config,model:l}};if(this.activeModel=c.config.model,this.activeProfile=c.config.profile,this.renderer.setWelcome({version:u,cwd:s.canonicalPath,model:c.config.model,profile:c.config.profile,trusted:o}),this.renderer.setFileSuggestions([]),o||(o=await this.renderer.confirmTrust(),o?(await this.runtime.projectTrust.grant(s),h=await this.runtime.configLoader.load(this.cwd),l=await p(this.runtime,h.config),c={...h,config:{...h.config,model:l}},this.activeModel=c.config.model,this.activeProfile=c.config.profile,this.renderer.setWelcome({version:u,cwd:s.canonicalPath,model:this.activeModel,profile:this.activeProfile,trusted:!0}),this.renderer.notice("Project trusted.")):this.renderer.notice("Project remains untrusted; local tools and extensions stay disabled.")),o&&await this.runtime.workspaceSettings.ensureInitialized(s.canonicalPath),await this.reloadExtensions(o,c.config.approvalMode,s.canonicalPath),this.options.sessionId!==void 0){const a=await this.runtime.sessionStore.get(this.options.sessionId);if(a===void 0)throw new Error(`Session not found: ${this.options.sessionId}`);if(a.projectFingerprint!==s.fingerprint)throw new Error("Session belongs to another project.");this.session=a,this.renderer.status(`Resuming session ${a.id}`);for(const d of m(await this.runtime.sessionStore.readTranscript(a.id)))d.type==="user"?this.renderer.userPrompt(d.content):d.type==="assistant"&&(this.renderer.beginAssistant(),this.renderer.assistantDelta(d.content),this.renderer.finishAssistant())}else this.session=await this.runtime.sessionStore.create({projectFingerprint:s.fingerprint,cwd:s.canonicalPath,model:c.config.model,profile:c.config.profile,status:"active"});return this.executionWorkspace=await this.executionWorkspaces.prepare({sessionId:this.session.id,projectRoot:s.canonicalPath}),await this.refreshContextUsage(),await this.runHookEvent("session.start",this.session.id),this.startBackgroundMcpWarmup(),this.renderer.setSubmitHandler(async a=>{await this.processPrompt(a)&&this.renderer.requestExit()}),this.renderer.clearActivity(),this.renderer.setReady(),this.backgroundOperations.start(a=>new y(s.canonicalPath).listEntries(a)).then(a=>this.renderer.setFileSuggestions(E(a))).catch(a=>this.runtime.logger.debug("Unable to load workspace file suggestions.",{reason:a instanceof Error?a.message:String(a)})),await this.renderer.waitForExit()}catch(s){throw r=L(s)?"cancelled":"failed",s}finally{this.turnController.abortActive(new Error("Interactive session is closing.")),await this.backgroundOperations.close(),this.renderer.resolveActiveModal(void 0),await this.awaitActiveForegroundRun();try{await this.subagentJobs.close()}catch(s){this.runtime.logger.warn("Unable to close subagent jobs during TUI shutdown.",{reason:s instanceof Error?s.message:String(s)})}if(this.agentSessionStore.clear(),this.session!==void 0){try{await this.runHookEvent("session.end",this.session.id)}catch(s){this.runtime.logger.warn("Session end hook failed during TUI shutdown.",{sessionId:this.session.id,reason:s instanceof Error?s.message:String(s)})}try{await this.runtime.sessionStore.updateStatus(this.session.id,r)}catch(s){this.runtime.logger.warn("Unable to update TUI session status during shutdown.",{sessionId:this.session.id,reason:s instanceof Error?s.message:String(s)})}try{await this.executionWorkspaces.markReady(this.session.id)}catch(s){this.runtime.logger.warn("Unable to release TUI execution workspace.",{sessionId:this.session.id,reason:s instanceof Error?s.message:String(s)})}}process.off("SIGINT",e),this.options.signal?.removeEventListener("abort",n),this.renderer.dispose(),t.unmount(),b(this.output),this.printResumeCommandOnExit&&this.session!==void 0&&this.output.write(`
2
2
  ${z(this.session.id)}
3
- `)}}async processPrompt(i){if(this.activeForegroundRun!==void 0)return this.renderer.notice("An operation is already running. Stop it before starting another one."),!1;const t=j(i,{renderer:this.renderer,logger:this.runtime.logger,commandHost:I({runtime:this.runtime,cwd:this.cwd,renderer:this.renderer,pendingAttachments:this.pendingAttachments,getHooks:()=>this.hooks,getSession:()=>this.session,getActiveAbortController:()=>this.turnController.getActiveAbortController(),setActiveAbortController:e=>{this.turnController.setActiveAbortController(e)},attachClipboardImage:e=>this.attachClipboardImage(e),runPrompt:(e,n)=>this.turnController.runPrompt(e,n),runGoal:(e,n,r)=>this.runGoal(e,n,r),resumeGoal:e=>this.resumeGoal(e),runSkill:(e,n,r,s,o)=>this.runSkill(e,n,r,s,o),refreshExtensions:()=>this.refreshExtensions(),compactSession:()=>this.compactSession(),refreshWelcome:e=>this.refreshWelcome(e),getContextSnapshot:()=>this.getContextSnapshot(),resumeSession:e=>this.resumeSession(e)}),pendingAttachments:this.pendingAttachments,commandContext:()=>this.commandContext(),sendPrompt:(e,n)=>this.turnController.sendPrompt(e,n),resetActiveAbortController:()=>{this.turnController.isRunning()||this.turnController.setActiveAbortController(void 0)}});this.activeForegroundRun=t;try{return await t}finally{this.activeForegroundRun===t&&(this.activeForegroundRun=void 0)}}async attachClipboardImage(i,t=!0,e=""){if(i===void 0){t&&this.renderer.notice("Clipboard does not contain an image.");return}const n=C(i.bytes,i.mimeType);this.pendingAttachments.assertCanAdd(n.bytes.byteLength,e,{byteLength:n.bytes.byteLength,mimeType:n.mimeType});const r=this.pendingAttachments.nextId(),s=x(n,"clipboard",r),o=this.session===void 0?s:await this.runtime.sessionStore.saveAttachment(this.session.id,s,n.bytes);this.pendingAttachments.add({attachment:o,bytes:n.bytes},e),this.renderer.setPendingAttachments(this.pendingAttachments.list().map(({attachment:h})=>h)),t&&this.renderer.notice(`Attached ${s.name} \xB7 ${s.mimeType} \xB7 ${s.sizeBytes} bytes`)}async runPrompt(i,t,e){return this.turnController.runPrompt(i,t,e)}async runGoal(i,t,e={}){if(this.turnController.isRunning()){t.write("Stop the active response before starting a goal.");return}await $({runtime:this.runtime,cwd:this.cwd,sessionId:this.session?.id,model:this.activeModel??this.session?.model??null,profile:this.activeProfile??this.session?.profile??null,runPrompt:(n,r)=>this.runPrompt(n,void 0,r),write:n=>t.write(n)},i,e)}async resumeGoal(i){if(this.turnController.isRunning()){i.write("Stop the active response before resuming a goal.");return}await D({runtime:this.runtime,cwd:this.cwd,sessionId:this.session?.id,model:this.activeModel??this.session?.model??null,profile:this.activeProfile??this.session?.profile??null,runPrompt:(t,e)=>this.runPrompt(t,void 0,e),write:t=>i.write(t)})}commandContext(){return{write:i=>this.renderer.commandOutput(i)}}getActiveModel(){return this.activeModel}getActiveProfile(){return this.activeProfile}async refreshExtensions(){const i=await this.runtime.projectTrust.inspect(this.cwd);this.runtime.agentPreparation?.clear(i.canonicalPath);const t=await this.runtime.projectTrust.isTrusted(i),e=await this.runtime.configLoader.load(this.cwd,{includeProject:t});await this.reloadExtensions(t,e.config.approvalMode,i.canonicalPath),await this.refreshContextUsage()}async refreshWelcome(i={}){const t=await this.runtime.projectTrust.inspect(this.cwd);this.runtime.agentPreparation?.clear(t.canonicalPath);const e=await this.runtime.projectTrust.isTrusted(t),n=await this.runtime.configLoader.load(this.cwd,{includeProject:e});this.activeModel=i.model===void 0?this.activeModel??n.config.model:i.model,this.activeProfile=i.profile===void 0?this.activeProfile??n.config.profile:i.profile,this.renderer.setWelcome({version:u,cwd:t.canonicalPath,model:this.activeModel,profile:this.activeProfile,trusted:e}),await this.refreshContextUsage()}async getContextSnapshot(){const i=this.activeModel??this.session?.model??null,t=this.session===void 0?void 0:await this.runtime.goalStore.get(this.session.id),e=await this.contextService.buildForProject({...this.session===void 0?{}:{sessionId:this.session.id},model:i,profileName:this.activeProfile??this.session?.profile??null,pluginNames:this.enabledPluginNames,pluginMcpConfig:this.pluginMcpConfig,pendingAttachments:this.pendingAttachments.size,skillRootScopes:this.skillRootScopes,agentSessionStore:this.agentSessionStore,...t===void 0?{}:{goal:{objective:t.objective,status:t.status,turns:t.turns,evaluatorRuns:t.evaluatorRuns,tokensUsed:t.usage.totalTokens,...t.tokenBudget===void 0?{}:{tokenBudget:t.tokenBudget},...t.maxTurns===void 0?{}:{maxTurns:t.maxTurns},...t.maxDurationMs===void 0?{}:{maxDurationMs:t.maxDurationMs},...t.lastError===void 0?{}:{lastError:t.lastError},...t.lastEvaluation===void 0?{}:{lastEvaluation:t.lastEvaluation.reason}}}});return this.renderer.setContextUsage({usedTokens:e.usedTokens,...e.contextWindow===void 0?{}:{contextWindow:e.contextWindow}}),e}async refreshContextUsage(){try{await this.getContextSnapshot()}catch(i){this.runtime.logger.debug("Unable to refresh context usage.",{reason:i instanceof Error?i.message:String(i)})}}async runSkill(i,t,e,n,r){await J({globalConfigDir:this.runtime.paths.globalConfigDir,skillRootScopes:this.skillRootScopes,runPrompt:(s,o)=>this.turnController.sendPrompt(s,this.pendingAttachments.list(),o)},i,t,e,r,n)}async reloadExtensions(i,t,e){const n=await V({runtime:this.runtime,cwd:this.cwd,trusted:i,approvalMode:t,workspaceRoot:e,approvals:this.approvals});this.hookRuntime=n.hookRuntime,this.skillRootScopes=n.skillRootScopes,this.enabledPluginNames=n.enabledPluginNames,this.pluginMcpConfig=n.pluginMcpConfig,this.hooks=n.hooks}async compactSession(){await F({runtime:this.runtime,cwd:this.cwd,session:this.session,activeModel:this.activeModel,activeProfile:this.activeProfile,activeResponse:this.turnController.getActiveAbortController()!==void 0,renderer:this.renderer,contextService:this.contextService,agentSessionStore:this.agentSessionStore,refreshContextUsage:()=>this.refreshContextUsage()})}async resumeSession(i){if(this.turnController.isRunning())throw new Error("Stop the active response before resuming another session.");const t=await this.runtime.projectTrust.inspect(this.cwd),e=await new T(this.runtime.sessionStore).require(i,t.fingerprint);if(e.id===this.session?.id){this.renderer.notice(`Already using session: ${e.id}`);return}const n=await this.runtime.sessionStore.readTranscript(e.id),r=this.session;r!==void 0&&(await this.subagentJobs.close(),this.subagentJobs=new g,await this.runHookEvent("session.end",r.id),await this.runtime.sessionStore.updateStatus(r.id,"completed"),this.agentSessionStore.delete(r.id)),this.session=await this.runtime.sessionStore.updateStatus(e.id,"active"),this.executionWorkspace=await this.executionWorkspaces.prepare({sessionId:e.id,projectRoot:t.canonicalPath});const s=await B(this.runtime,this.cwd);this.activeModel=e.model??s.config.model,this.activeProfile=e.profile??s.config.profile,this.renderer.setWelcome({version:u,cwd:t.canonicalPath,model:this.activeModel,profile:this.activeProfile,trusted:await this.runtime.projectTrust.isTrusted(t)}),this.renderer.clearTranscript();for(const o of m(n))o.type==="user"?this.renderer.userPrompt(o.content):o.type==="assistant"&&(this.renderer.beginAssistant(),this.renderer.assistantDelta(o.content),this.renderer.finishAssistant());await this.refreshContextUsage(),await this.runHookEvent("session.start",e.id),this.pendingAttachments.clear(),this.renderer.setPendingAttachments([]),this.startBackgroundMcpWarmup(),this.renderer.notice(`Resumed session: ${e.id}`)}handleInterrupt(){const i=G({lastInterruptAt:this.lastInterruptAt,exitArmedUntil:this.exitArmedUntil,printResumeCommandOnExit:this.printResumeCommandOnExit},this.turnController.getActiveAbortController(),this.renderer);this.lastInterruptAt=i.lastInterruptAt,this.exitArmedUntil=i.exitArmedUntil,this.printResumeCommandOnExit=i.printResumeCommandOnExit}startBackgroundMcpWarmup(){this.backgroundOperations.start(i=>R(this.runtime,this.cwd,i)).catch(i=>this.runtime.logger.warn("MCP session warm-up failed.",{reason:i instanceof Error?i.message:String(i)}))}async awaitActiveForegroundRun(){const i=this.activeForegroundRun;if(i!==void 0)try{await i}catch(t){this.runtime.logger.warn("Foreground TUI operation failed during shutdown.",{reason:t instanceof Error?t.message:String(t)})}}async runHookEvent(i,t){await N(this.hookRuntime,this.hooks,i,this.executionWorkspace?.executionCwd??this.cwd,t)}}export{It as TuiApplication};
3
+ `)}}async processPrompt(i){if(this.activeForegroundRun!==void 0)return this.renderer.notice("An operation is already running. Stop it before starting another one."),!1;const t=j(i,{renderer:this.renderer,logger:this.runtime.logger,commandHost:I({runtime:this.runtime,cwd:this.cwd,renderer:this.renderer,pendingAttachments:this.pendingAttachments,getHooks:()=>this.hooks,getSession:()=>this.session,getActiveAbortController:()=>this.turnController.getActiveAbortController(),setActiveAbortController:e=>{this.turnController.setActiveAbortController(e)},attachClipboardImage:e=>this.attachClipboardImage(e),runPrompt:(e,n)=>this.turnController.runPrompt(e,n),runGoal:(e,n,r)=>this.runGoal(e,n,r),resumeGoal:e=>this.resumeGoal(e),runSkill:(e,n,r,s,o)=>this.runSkill(e,n,r,s,o),refreshExtensions:()=>this.refreshExtensions(),compactSession:()=>this.compactSession(),refreshWelcome:e=>this.refreshWelcome(e),getContextSnapshot:()=>this.getContextSnapshot(),resumeSession:e=>this.resumeSession(e)}),pendingAttachments:this.pendingAttachments,commandContext:()=>this.commandContext(),sendPrompt:(e,n)=>this.turnController.sendPrompt(e,n),resetActiveAbortController:()=>{this.turnController.isRunning()||this.turnController.setActiveAbortController(void 0)}});this.activeForegroundRun=t;try{return await t}finally{this.activeForegroundRun===t&&(this.activeForegroundRun=void 0)}}async attachClipboardImage(i,t=!0,e=""){if(i===void 0){t&&this.renderer.notice("Clipboard does not contain an image.");return}const n=C(i.bytes,i.mimeType);this.pendingAttachments.assertCanAdd(n.bytes.byteLength,e,{byteLength:n.bytes.byteLength,mimeType:n.mimeType});const r=this.pendingAttachments.nextId(),s=x(n,"clipboard",r),o=this.session===void 0?s:await this.runtime.sessionStore.saveAttachment(this.session.id,s,n.bytes);this.pendingAttachments.add({attachment:o,bytes:n.bytes},e),this.renderer.setPendingAttachments(this.pendingAttachments.list().map(({attachment:h})=>h)),t&&this.renderer.notice(`Attached ${s.name} \xB7 ${s.mimeType} \xB7 ${s.sizeBytes} bytes`)}async runPrompt(i,t,e){return this.turnController.runPrompt(i,t,e)}async runGoal(i,t,e={}){if(this.turnController.isRunning()){t.write("Stop the active response before starting a goal.");return}await $({runtime:this.runtime,cwd:this.cwd,sessionId:this.session?.id,model:this.activeModel??this.session?.model??null,profile:this.activeProfile??this.session?.profile??null,runPrompt:(n,r)=>this.runPrompt(n,void 0,r),write:n=>t.write(n)},i,e)}async resumeGoal(i){if(this.turnController.isRunning()){i.write("Stop the active response before resuming a goal.");return}await B({runtime:this.runtime,cwd:this.cwd,sessionId:this.session?.id,model:this.activeModel??this.session?.model??null,profile:this.activeProfile??this.session?.profile??null,runPrompt:(t,e)=>this.runPrompt(t,void 0,e),write:t=>i.write(t)})}commandContext(){return{write:i=>this.renderer.commandOutput(i)}}getActiveModel(){return this.activeModel}getActiveProfile(){return this.activeProfile}async refreshExtensions(){const i=await this.runtime.projectTrust.inspect(this.cwd);this.runtime.agentPreparation?.clear(i.canonicalPath);const t=await this.runtime.projectTrust.isTrusted(i),e=await this.runtime.configLoader.load(this.cwd,{includeProject:t});await this.reloadExtensions(t,e.config.approvalMode,i.canonicalPath),await this.refreshContextUsage()}async refreshWelcome(i={}){const t=await this.runtime.projectTrust.inspect(this.cwd);this.runtime.agentPreparation?.clear(t.canonicalPath);const e=await this.runtime.projectTrust.isTrusted(t),n=await this.runtime.configLoader.load(this.cwd,{includeProject:e});this.activeModel=i.model===void 0?this.activeModel??n.config.model:i.model,this.activeProfile=i.profile===void 0?this.activeProfile??n.config.profile:i.profile,this.renderer.setWelcome({version:u,cwd:t.canonicalPath,model:this.activeModel,profile:this.activeProfile,trusted:e}),await this.refreshContextUsage()}async getContextSnapshot(){const i=this.activeModel??this.session?.model??null,t=this.session===void 0?void 0:await this.runtime.goalStore.get(this.session.id),e=await this.contextService.buildForProject({...this.session===void 0?{}:{sessionId:this.session.id},model:i,profileName:this.activeProfile??this.session?.profile??null,pluginNames:this.enabledPluginNames,pluginMcpConfig:this.pluginMcpConfig,pendingAttachments:this.pendingAttachments.size,skillRootScopes:this.skillRootScopes,agentSessionStore:this.agentSessionStore,...t===void 0?{}:{goal:{objective:t.objective,status:t.status,turns:t.turns,evaluatorRuns:t.evaluatorRuns,tokensUsed:t.usage.totalTokens,...t.tokenBudget===void 0?{}:{tokenBudget:t.tokenBudget},...t.maxTurns===void 0?{}:{maxTurns:t.maxTurns},...t.maxDurationMs===void 0?{}:{maxDurationMs:t.maxDurationMs},...t.lastError===void 0?{}:{lastError:t.lastError},...t.lastEvaluation===void 0?{}:{lastEvaluation:t.lastEvaluation.reason}}}});return this.renderer.setContextUsage({usedTokens:e.usedTokens,...e.contextWindow===void 0?{}:{contextWindow:e.contextWindow}}),e}async refreshContextUsage(){try{await this.getContextSnapshot()}catch(i){this.runtime.logger.debug("Unable to refresh context usage.",{reason:i instanceof Error?i.message:String(i)})}}async runSkill(i,t,e,n,r){await J({globalConfigDir:this.runtime.paths.globalConfigDir,skillRootScopes:this.skillRootScopes,runPrompt:(s,o)=>this.turnController.sendPrompt(s,this.pendingAttachments.list(),o)},i,t,e,r,n)}async reloadExtensions(i,t,e){const n=await V({runtime:this.runtime,cwd:this.cwd,trusted:i,approvalMode:t,workspaceRoot:e,approvals:this.approvals});this.hookRuntime=n.hookRuntime,this.skillRootScopes=n.skillRootScopes,this.enabledPluginNames=n.enabledPluginNames,this.pluginMcpConfig=n.pluginMcpConfig,this.hooks=n.hooks}async compactSession(){await F({runtime:this.runtime,cwd:this.cwd,session:this.session,activeModel:this.activeModel,activeProfile:this.activeProfile,activeResponse:this.turnController.getActiveAbortController()!==void 0,renderer:this.renderer,contextService:this.contextService,agentSessionStore:this.agentSessionStore,refreshContextUsage:()=>this.refreshContextUsage()})}async resumeSession(i){if(this.turnController.isRunning())throw new Error("Stop the active response before resuming another session.");const t=await this.runtime.projectTrust.inspect(this.cwd),e=await new T(this.runtime.sessionStore).require(i,t.fingerprint);if(e.id===this.session?.id){this.renderer.notice(`Already using session: ${e.id}`);return}const n=await this.runtime.sessionStore.readTranscript(e.id),r=this.session;r!==void 0&&(await this.subagentJobs.close(),this.subagentJobs=new g,await this.runHookEvent("session.end",r.id),await this.runtime.sessionStore.updateStatus(r.id,"completed"),this.agentSessionStore.delete(r.id)),this.session=await this.runtime.sessionStore.updateStatus(e.id,"active"),this.executionWorkspace=await this.executionWorkspaces.prepare({sessionId:e.id,projectRoot:t.canonicalPath});const s=await N(this.runtime,this.cwd);this.activeModel=e.model??s.config.model,this.activeProfile=e.profile??s.config.profile,this.renderer.setWelcome({version:u,cwd:t.canonicalPath,model:this.activeModel,profile:this.activeProfile,trusted:await this.runtime.projectTrust.isTrusted(t)}),this.renderer.clearTranscript();for(const o of m(n))o.type==="user"?this.renderer.userPrompt(o.content):o.type==="assistant"&&(this.renderer.beginAssistant(),this.renderer.assistantDelta(o.content),this.renderer.finishAssistant());await this.refreshContextUsage(),await this.runHookEvent("session.start",e.id),this.pendingAttachments.clear(),this.renderer.setPendingAttachments([]),this.startBackgroundMcpWarmup(),this.renderer.notice(`Resumed session: ${e.id}`)}handleInterrupt(){const i=G({lastInterruptAt:this.lastInterruptAt,exitArmedUntil:this.exitArmedUntil,printResumeCommandOnExit:this.printResumeCommandOnExit},this.turnController.getActiveAbortController(),this.renderer);this.lastInterruptAt=i.lastInterruptAt,this.exitArmedUntil=i.exitArmedUntil,this.printResumeCommandOnExit=i.printResumeCommandOnExit}startBackgroundMcpWarmup(){this.backgroundOperations.start(i=>R(this.runtime,this.cwd,i)).catch(i=>this.runtime.logger.warn("MCP session warm-up failed.",{reason:i instanceof Error?i.message:String(i)}))}async awaitActiveForegroundRun(){const i=this.activeForegroundRun;if(i!==void 0)try{await i}catch(t){this.runtime.logger.warn("Foreground TUI operation failed during shutdown.",{reason:t instanceof Error?t.message:String(t)})}}async runHookEvent(i,t){await D(this.hookRuntime,this.hooks,i,this.executionWorkspace?.executionCwd??this.cwd,t)}}export{It as TuiApplication};
@@ -3,6 +3,7 @@ import type { LotaGate } from '@lotagate/sdk';
3
3
  import type { CliRuntime } from '../../bootstrap/runtime-factory.js';
4
4
  import type { AgentRunSnapshot } from '../../application/agent/agent-run-tracker.js';
5
5
  import { type ContinuationGoal } from '../../application/agent/continuation-checkpoint.js';
6
- export declare function createTuiContextManagement(client: LotaGate, model: string, contextWindow: number | undefined, onSummaryFailure: (error: unknown) => void, continuationContext?: () => string | undefined): import("@lotagate/agent-sdk").ContextManagementOptions;
6
+ import type { ModelNetworkRecoveryObserver } from '../../application/model/model-response-retry.js';
7
+ export declare function createTuiContextManagement(client: LotaGate, model: string, contextWindow: number | undefined, onSummaryFailure: (error: unknown) => void, continuationContext?: () => string | undefined, networkRecovery?: ModelNetworkRecoveryObserver): import("@lotagate/agent-sdk").ContextManagementOptions;
7
8
  export declare function createTuiContinuationContext(snapshot: AgentRunSnapshot, goal?: ContinuationGoal): string;
8
9
  export declare function compactTuiSession(runtime: CliRuntime, agentSessions: AgentSessionStore, sessionId: string, client: LotaGate, model: string, contextWindow?: number, onSummaryFailure?: (error: unknown) => void): Promise<boolean>;
@@ -1 +1 @@
1
- import{createContextManagement as c,redactCompactionSummary as f}from"../../application/agent/context-compaction.js";import{retainLatestCompaction as p,toAgentMessage as d}from"../../application/agent/agent-session-store.js";import{buildAgentHistory as g}from"../../application/agent/agent-history.js";import{compactSessionMessages as y}from"../../application/session/session-compaction-service.js";import{formatContinuationCheckpoint as C}from"../../application/agent/continuation-checkpoint.js";function T(a,e,t,r,n){return c({client:a,model:e,...t===void 0?{}:{contextWindow:t},onSummaryFailure:r,...n===void 0?{}:{continuationContext:n}})}function h(a,e){return C({snapshot:a,...e===void 0?{}:{goal:e}})}async function H(a,e,t,r,n,i,m){const s=await e.get(t),u=s?.messages??await w(a,t),o=await y(u,r,n,i,m);return o.summary===void 0?!1:(s!==void 0&&await e.update(t,{messages:o.messages,status:"completed"}),await a.sessionStore.compact(t,f(o.summary)),!0)}async function w(a,e){const t=await a.sessionStore.readHistory(e);return p(g(t.transcript,t.events)).map(d)}export{H as compactTuiSession,T as createTuiContextManagement,h as createTuiContinuationContext};
1
+ import{createContextManagement as c,redactCompactionSummary as f}from"../../application/agent/context-compaction.js";import{retainLatestCompaction as p,toAgentMessage as d}from"../../application/agent/agent-session-store.js";import{buildAgentHistory as g}from"../../application/agent/agent-history.js";import{compactSessionMessages as y}from"../../application/session/session-compaction-service.js";import{formatContinuationCheckpoint as C}from"../../application/agent/continuation-checkpoint.js";function T(a,e,t,o,n,r){return c({client:a,model:e,...t===void 0?{}:{contextWindow:t},onSummaryFailure:o,...n===void 0?{}:{continuationContext:n},...r===void 0?{}:{networkRecovery:r}})}function h(a,e){return C({snapshot:a,...e===void 0?{}:{goal:e}})}async function H(a,e,t,o,n,r,m){const i=await e.get(t),u=i?.messages??await M(a,t),s=await y(u,o,n,r,m);return s.summary===void 0?!1:(i!==void 0&&await e.update(t,{messages:s.messages,status:"completed"}),await a.sessionStore.compact(t,f(s.summary)),!0)}async function M(a,e){const t=await a.sessionStore.readHistory(e);return p(g(t.transcript,t.events)).map(d)}export{H as compactTuiSession,T as createTuiContextManagement,h as createTuiContinuationContext};
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const CLI_VERSION = "0.1.28";
1
+ export declare const CLI_VERSION = "0.1.29";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- const o="0.1.28";export{o as CLI_VERSION};
1
+ const o="0.1.29";export{o as CLI_VERSION};
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@lotagate/cli",
3
- "version": "0.1.28",
3
+ "version": "0.1.29",
4
4
  "description": "Enterprise-grade terminal client for LotaGate AI agents.",
5
5
  "type": "module",
6
- "license": "MIT",
6
+ "license": "SEE LICENSE IN LICENSE.md",
7
7
  "author": "LotaGate",
8
8
  "homepage": "https://lotagate.com",
9
9
  "repository": {
@@ -64,19 +64,19 @@
64
64
  "prepack": "npm run build"
65
65
  },
66
66
  "dependencies": {
67
- "@lotagate/agent-sdk": "^0.1.9",
68
- "@lotagate/sdk": "^0.1.3",
67
+ "@lotagate/agent-sdk": "^0.1.10",
68
+ "@lotagate/sdk": "^0.1.5",
69
69
  "ink": "^7.1.1",
70
70
  "react": "^19.2.4",
71
71
  "tiktoken": "^1.0.22"
72
72
  },
73
73
  "optionalDependencies": {
74
- "@lotagate/cli-native-linux-arm64-gnu": "0.1.28",
75
- "@lotagate/cli-native-linux-x64-gnu": "0.1.28",
76
- "@lotagate/cli-native-macos-arm64": "0.1.28",
77
- "@lotagate/cli-native-macos-x64": "0.1.28",
78
- "@lotagate/cli-native-windows-arm64": "0.1.28",
79
- "@lotagate/cli-native-windows-x64": "0.1.28"
74
+ "@lotagate/cli-native-linux-arm64-gnu": "0.1.29",
75
+ "@lotagate/cli-native-linux-x64-gnu": "0.1.29",
76
+ "@lotagate/cli-native-macos-arm64": "0.1.29",
77
+ "@lotagate/cli-native-macos-x64": "0.1.29",
78
+ "@lotagate/cli-native-windows-arm64": "0.1.29",
79
+ "@lotagate/cli-native-windows-x64": "0.1.29"
80
80
  },
81
81
  "devDependencies": {
82
82
  "@eslint/js": "9.39.5",