@lotagate/cli 0.1.25 → 0.1.26
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.
- package/README.md +5 -4
- package/bin/lotagate.mjs +50 -8
- package/dist/application/agent/agent-constants.d.ts +6 -0
- package/dist/application/agent/agent-constants.js +1 -0
- package/dist/application/agent/agent-session-store-registry.d.ts +16 -0
- package/dist/application/agent/agent-session-store-registry.js +1 -0
- package/dist/application/agent/agent-session-store.d.ts +4 -0
- package/dist/application/agent/agent-session-store.js +5 -5
- package/dist/application/agent/capability-profile.d.ts +0 -38
- package/dist/application/agent/capability-profile.js +0 -1
- package/dist/application/agent/cli-agent-execution-service.d.ts +22 -12
- package/dist/application/agent/cli-agent-execution-service.js +1 -1
- package/dist/application/agent/cli-agent-preparation-cache.d.ts +39 -0
- package/dist/application/agent/cli-agent-preparation-cache.js +1 -0
- package/dist/application/agent/context-compaction.d.ts +1 -0
- package/dist/application/agent/context-compaction.js +7 -6
- package/dist/application/agent/context-token-cache.d.ts +21 -0
- package/dist/application/agent/context-token-cache.js +4 -0
- package/dist/application/agent/context-usage-service.d.ts +52 -0
- package/dist/application/agent/context-usage-service.js +1 -0
- package/dist/application/agent/continuation-checkpoint.d.ts +15 -0
- package/dist/application/agent/continuation-checkpoint.js +2 -0
- package/dist/application/agent/interactive-agent-guidance.d.ts +3 -3
- package/dist/application/agent/interactive-agent-guidance.js +2 -2
- package/dist/application/chat/pending-attachment-store.d.ts +5 -2
- package/dist/application/chat/pending-attachment-store.js +1 -1
- package/dist/application/commands/application-command-executor.js +1 -1
- package/dist/application/commands/command-catalog.js +1 -1
- package/dist/application/commands/goal-command-handlers.js +6 -6
- package/dist/application/commands/media-command-handlers.js +7 -6
- package/dist/application/commands/runtime-command-handlers.js +9 -9
- package/dist/application/intent/completion-gate.d.ts +2 -5
- package/dist/application/intent/completion-gate.js +1 -1
- package/dist/application/intent/evidence-ledger.d.ts +2 -1
- package/dist/application/intent/evidence-recording-tool-executor.js +1 -1
- package/dist/application/intent/intent-compiler.js +2 -2
- package/dist/application/memory/memory-extractor.js +2 -2
- package/dist/application/model/cached-model-catalog.d.ts +7 -1
- package/dist/application/model/cached-model-catalog.js +1 -1
- package/dist/application/model/model-catalog-service.js +1 -1
- package/dist/application/model/model-context-window.js +1 -1
- package/dist/application/model/model-response-retry.d.ts +7 -1
- package/dist/application/model/model-response-retry.js +1 -1
- package/dist/application/orchestration/cli-subagent-service.d.ts +4 -0
- package/dist/application/orchestration/cli-subagent-service.js +3 -3
- package/dist/application/orchestration/cli-turn-event-projector.js +1 -1
- package/dist/application/orchestration/cli-turn-events.d.ts +0 -7
- package/dist/application/orchestration/goal-input.d.ts +1 -1
- package/dist/application/orchestration/goal-input.js +1 -1
- package/dist/application/orchestration/headless-agent-turn.d.ts +1 -0
- package/dist/application/orchestration/headless-agent-turn.js +3 -3
- package/dist/application/orchestration/orchestration-constants.d.ts +3 -0
- package/dist/application/orchestration/orchestration-constants.js +1 -0
- package/dist/application/orchestration/subagent-handoff.js +3 -3
- package/dist/application/project-intelligence/project-intelligence-constants.d.ts +56 -0
- package/dist/application/project-intelligence/project-intelligence-constants.js +1 -0
- package/dist/application/project-intelligence/project-intelligence-service.js +1 -1
- package/dist/application/protocol/browser-host-tool-executor.d.ts +13 -3
- package/dist/application/protocol/browser-host-tool-executor.js +2 -2
- package/dist/application/protocol/computer-host-tool-executor.d.ts +3 -0
- package/dist/application/protocol/computer-host-tool-executor.js +2 -2
- package/dist/application/protocol/desktop-agent-command.d.ts +2 -2
- package/dist/application/protocol/desktop-agent-command.js +2 -2
- package/dist/application/protocol/desktop-agent-contracts.d.ts +34 -0
- package/dist/application/protocol/desktop-agent-contracts.js +1 -0
- package/dist/application/protocol/desktop-agent-helpers.d.ts +5 -0
- package/dist/application/protocol/desktop-agent-helpers.js +1 -0
- package/dist/application/protocol/desktop-agent-request-parser.d.ts +31 -6
- package/dist/application/protocol/desktop-agent-request-parser.js +1 -1
- package/dist/application/protocol/desktop-approval-broker.d.ts +14 -4
- package/dist/application/protocol/desktop-approval-broker.js +1 -1
- package/dist/application/protocol/desktop-attachment-store.d.ts +19 -2
- package/dist/application/protocol/desktop-attachment-store.js +1 -1
- package/dist/application/protocol/desktop-execution-policy.d.ts +2 -0
- package/dist/application/protocol/desktop-execution-policy.js +1 -1
- package/dist/application/protocol/desktop-host-bridge.d.ts +33 -0
- package/dist/application/protocol/desktop-host-bridge.js +1 -0
- package/dist/application/protocol/desktop-host-capabilities.d.ts +12 -0
- package/dist/application/protocol/desktop-host-capabilities.js +1 -0
- package/dist/application/protocol/desktop-host-tool-executor.d.ts +15 -2
- package/dist/application/protocol/desktop-host-tool-executor.js +2 -2
- package/dist/application/protocol/desktop-intent-event-writer.js +1 -1
- package/dist/application/protocol/desktop-protocol-helpers.js +1 -1
- package/dist/application/protocol/json-line-writer.d.ts +24 -2
- package/dist/application/protocol/json-line-writer.js +2 -2
- package/dist/application/protocol/jsonl-agent-command.d.ts +1 -1
- package/dist/application/protocol/jsonl-agent-command.js +2 -2
- package/dist/application/protocol/jsonl-protocol.d.ts +1 -1
- package/dist/application/protocol/jsonl-protocol.js +2 -2
- package/dist/application/security/desktop-tool-scope-policy.js +1 -1
- package/dist/application/security/tool-action-risk-analyzer.js +1 -1
- package/dist/application/security/tool-approval-service.d.ts +9 -3
- package/dist/application/security/tool-approval-service.js +1 -1
- package/dist/application/security/tool-policy-registry.d.ts +20 -0
- package/dist/application/security/tool-policy-registry.js +1 -0
- package/dist/application/security/tool-risk-classifier.d.ts +2 -1
- package/dist/application/security/tool-risk-classifier.js +1 -1
- package/dist/application/security/workspace-permission-policy.js +1 -1
- package/dist/application/workspace/session-execution-workspace.d.ts +2 -2
- package/dist/application/workspace/session-execution-workspace.js +3 -3
- package/dist/application/workspace/workspace-constants.d.ts +17 -0
- package/dist/application/workspace/workspace-constants.js +1 -0
- package/dist/application/workspace/workspace-file-index.d.ts +0 -1
- package/dist/application/workspace/workspace-file-index.js +1 -1
- package/dist/application/workspace/workspace-instruction-loader.js +1 -1
- package/dist/bootstrap/composition-root.d.ts +1 -0
- package/dist/bootstrap/runtime-factory.d.ts +5 -0
- package/dist/bootstrap/runtime-factory.js +1 -1
- package/dist/domain/errors/cli-error.js +1 -1
- package/dist/domain/extensions/extension-constants.d.ts +1 -0
- package/dist/domain/extensions/extension-constants.js +1 -0
- package/dist/domain/extensions/host-tool-plugin-ids.d.ts +0 -4
- package/dist/domain/extensions/host-tool-plugin-ids.js +1 -1
- package/dist/domain/extensions/plugin-manifest.js +1 -1
- package/dist/domain/intent/intent-contract.d.ts +0 -8
- package/dist/domain/intent/intent-contract.js +1 -1
- package/dist/domain/media/gateway-media-contract.js +1 -1
- package/dist/domain/media/media-constants.d.ts +3 -0
- package/dist/domain/media/media-constants.js +1 -0
- package/dist/domain/media/media-execution-policy.js +1 -1
- package/dist/domain/memory/memory-constants.d.ts +3 -0
- package/dist/domain/memory/memory-constants.js +1 -0
- package/dist/domain/memory/memory-search.js +2 -2
- package/dist/domain/orchestration/goal.d.ts +0 -1
- package/dist/domain/orchestration/goal.js +1 -1
- package/dist/domain/orchestration/work-plan.d.ts +0 -62
- package/dist/domain/orchestration/work-plan.js +0 -1
- package/dist/domain/runtime/assistant-stream-text.d.ts +11 -0
- package/dist/domain/runtime/assistant-stream-text.js +1 -0
- package/dist/domain/runtime/gateway-request-budget.d.ts +19 -0
- package/dist/domain/runtime/gateway-request-budget.js +1 -0
- package/dist/domain/runtime/resource-limits.d.ts +17 -0
- package/dist/domain/runtime/resource-limits.js +1 -1
- package/dist/domain/session/attachment.d.ts +2 -0
- package/dist/domain/workspace/workspace-settings.d.ts +2 -0
- package/dist/domain/workspace/workspace-settings.js +1 -1
- package/dist/infrastructure/agent-sdk/model-response-metrics.d.ts +7 -0
- package/dist/infrastructure/agent-sdk/model-response-metrics.js +1 -0
- package/dist/infrastructure/agent-sdk/model-tool-name-mapper.js +1 -1
- package/dist/infrastructure/agent-sdk/sdk-constants.d.ts +2 -0
- package/dist/infrastructure/agent-sdk/sdk-constants.js +1 -0
- package/dist/infrastructure/agent-sdk/tool-calling-model-client.js +1 -1
- package/dist/infrastructure/cache/cache-policy.d.ts +2 -0
- package/dist/infrastructure/cache/cache-policy.js +1 -1
- package/dist/infrastructure/cache/file-cache-store.d.ts +8 -0
- package/dist/infrastructure/cache/file-cache-store.js +2 -2
- package/dist/infrastructure/clipboard/clipboard-constants.d.ts +1 -0
- package/dist/infrastructure/clipboard/clipboard-constants.js +1 -0
- package/dist/infrastructure/clipboard/image-normalizer.js +1 -1
- package/dist/infrastructure/extensions/extensions-constants.d.ts +6 -0
- package/dist/infrastructure/extensions/extensions-constants.js +1 -0
- package/dist/infrastructure/extensions/mcp-runtime.d.ts +7 -0
- package/dist/infrastructure/extensions/mcp-runtime.js +1 -1
- package/dist/infrastructure/extensions/plugin-manager.js +2 -2
- package/dist/infrastructure/extensions/skill-tool-executor.d.ts +3 -1
- package/dist/infrastructure/extensions/skill-tool-executor.js +2 -2
- package/dist/infrastructure/filesystem/atomic-file-store.d.ts +11 -0
- package/dist/infrastructure/filesystem/atomic-file-store.js +1 -1
- package/dist/infrastructure/filesystem/filesystem-constants.d.ts +8 -0
- package/dist/infrastructure/filesystem/filesystem-constants.js +1 -0
- package/dist/infrastructure/filesystem/local-filesystem-tool-executor.d.ts +3 -0
- package/dist/infrastructure/filesystem/local-filesystem-tool-executor.js +3 -3
- package/dist/infrastructure/logging/daily-rotating-file-writer.d.ts +1 -1
- package/dist/infrastructure/logging/daily-rotating-file-writer.js +2 -2
- package/dist/infrastructure/logging/log-redactor.js +1 -1
- package/dist/infrastructure/logging/logging-constants.d.ts +3 -0
- package/dist/infrastructure/logging/logging-constants.js +1 -0
- package/dist/infrastructure/logging/structured-logger.d.ts +1 -1
- package/dist/infrastructure/logging/structured-logger.js +2 -2
- package/dist/infrastructure/observability/tool-execution-logger.d.ts +11 -0
- package/dist/infrastructure/observability/tool-execution-logger.js +1 -0
- package/dist/infrastructure/platform/host-platform.d.ts +2 -0
- package/dist/infrastructure/platform/host-platform.js +1 -1
- package/dist/infrastructure/platform/host-process.d.ts +3 -1
- package/dist/infrastructure/platform/host-process.js +1 -1
- package/dist/infrastructure/platform/platform-constants.d.ts +4 -0
- package/dist/infrastructure/platform/platform-constants.js +1 -0
- package/dist/infrastructure/platform/process-identity.d.ts +8 -0
- package/dist/infrastructure/platform/process-identity.js +1 -0
- package/dist/infrastructure/platform/read-only-executable.d.ts +2 -1
- package/dist/infrastructure/platform/read-only-executable.js +1 -1
- package/dist/infrastructure/sdk/lotagate-client-factory.js +1 -1
- package/dist/infrastructure/sdk/sdk-media-gateway-client.d.ts +4 -0
- package/dist/infrastructure/sdk/sdk-media-gateway-client.js +1 -1
- package/dist/infrastructure/sessions/file-session-store.d.ts +3 -0
- package/dist/infrastructure/sessions/file-session-store.js +4 -4
- package/dist/infrastructure/sessions/session-constants.d.ts +3 -0
- package/dist/infrastructure/sessions/session-constants.js +1 -0
- package/dist/infrastructure/sessions/session-index.js +3 -3
- package/dist/infrastructure/sessions/session-journal-health.d.ts +7 -0
- package/dist/infrastructure/sessions/session-journal-health.js +1 -0
- package/dist/infrastructure/shell/shell-tool-executor.d.ts +5 -1
- package/dist/infrastructure/shell/shell-tool-executor.js +2 -2
- package/dist/infrastructure/tokens/tiktoken-token-estimator.js +1 -1
- package/dist/infrastructure/tokens/token-constants.d.ts +1 -0
- package/dist/infrastructure/tokens/token-constants.js +1 -0
- package/dist/infrastructure/workspace/workspace-settings-store.d.ts +1 -0
- package/dist/infrastructure/workspace/workspace-settings-store.js +4 -4
- package/dist/main.js +3 -3
- package/dist/ports/media-gateway-client.d.ts +6 -0
- package/dist/ports/session-store.d.ts +1 -0
- package/dist/presentation/tui/ink/components/composer.js +4 -4
- package/dist/presentation/tui/ink/components/transcript.d.ts +1 -0
- package/dist/presentation/tui/ink/components/transcript.js +5 -5
- package/dist/presentation/tui/ink/tui-bridge.d.ts +2 -2
- package/dist/presentation/tui/ink/tui-bridge.js +1 -1
- package/dist/presentation/tui/tui-agent-turn-controller.d.ts +45 -0
- package/dist/presentation/tui/tui-agent-turn-controller.js +1 -0
- package/dist/presentation/tui/tui-application-contract.d.ts +1 -0
- package/dist/presentation/tui/tui-application.d.ts +1 -4
- package/dist/presentation/tui/tui-application.js +3 -3
- package/dist/presentation/tui/tui-clipboard-paste-handlers.d.ts +2 -2
- package/dist/presentation/tui/tui-clipboard-paste-handlers.js +1 -1
- package/dist/presentation/tui/tui-command-executor.js +3 -3
- package/dist/presentation/tui/tui-context-compaction.d.ts +4 -1
- package/dist/presentation/tui/tui-context-compaction.js +1 -1
- package/dist/presentation/tui/tui-context-service.d.ts +2 -34
- package/dist/presentation/tui/tui-context-service.js +1 -2
- package/dist/presentation/tui/tui-initial-model.js +1 -1
- package/dist/presentation/tui/tui-tool-approval.d.ts +1 -1
- package/dist/presentation/tui/tui-tool-approval.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/native-targets.mjs +1 -1
- package/package.json +9 -10
- package/scripts/install-native.mjs +5 -13
- package/bin/lotagate.exe +0 -1
- package/dist/application/protocol/document-host-tool-definitions.d.ts +0 -4
- package/dist/application/protocol/document-host-tool-definitions.js +0 -1
- package/dist/application/protocol/document-host-tool-executor.d.ts +0 -49
- package/dist/application/protocol/document-host-tool-executor.js +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
${r}`,...e.turnId===void 0?{}:{turnId:e.turnId}}},{kind:"event",event:{type:"context.compacted",timestamp:n,sessionId:t,...e.turnId===void 0?{}:{turnId:e.turnId},data:{summary:r}}}])}async export(t){const a=await this.readSnapshot(t),e=[];for(const r of a.transcript)for(const n of r.attachmentIds??[]){if(e.some(
|
|
3
|
-
`),
|
|
4
|
-
`);for(const n of Object.values(a))await
|
|
1
|
+
import J from"node:crypto";import d from"node:fs/promises";import h from"node:path";import{CliError as u}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as l}from"../../domain/errors/error-codes.js";import{isRecord as x,isSessionEvent as I,isSessionMetadata as z,isTranscriptEntry as C}from"../../domain/session/session-schema.js";import{isGoalEventType as q,isPersistedGoalEventData as H}from"../../domain/orchestration/goal.js";import{isAlreadyExists as $,isFileNotFound as w}from"../filesystem/fs-errors.js";import{acquireAdvisoryFileLock as G,atomicWriteFile as O,isAdvisoryLockContention as V,recoverStaleAdvisoryLock as U,releaseAdvisoryFileLock as K}from"../filesystem/atomic-file-store.js";import{isSafeProjectKey as L,resolveProjectSessionPaths as W,resolveProjectSessionPathsForKey as v}from"./project-session-paths.js";import{appendJournalRecord as y,appendJournalRecords as Z,eventRecord as D,journalEvents as E,journalTranscript as P,latestMetadata as M,metadataRecord as T,readJournal as N,repairJournal as Q,transcriptRecord as B}from"./session-journal.js";import{indexProjectSession as j,readProjectSessionIndex as X,readSessionLocator as Y,removeIndexedSession as tt}from"./session-index.js";import{RESOURCE_LIMITS as f}from"../../domain/runtime/resource-limits.js";import{readJsonFileBounded as et}from"../filesystem/bounded-json-reader.js";import{SessionJournalHealth as at}from"./session-journal-health.js";import{ATTACHMENT_ID_PATTERN as S,SESSION_ID_PATTERN as _,SESSION_LOCK_STALE_MS as rt}from"./session-constants.js";class kt{paths;journalHealth=new at;constructor(t){this.paths=t}async create(t){const a=new Date().toISOString(),e={...t,id:J.randomUUID(),createdAt:a,updatedAt:a},r=W(this.paths,e.cwd,e.id);return await d.mkdir(r.attachmentsDirectory,{recursive:!0}),await y(r.journalFile,T(e)),await this.journalHealth.markValid(r.journalFile),await j(this.paths,e,r.projectKey),e}async get(t){const a=await this.locate(t);if(a===void 0)return;const e=(await this.readSessionJournal(t,a)).metadata;if(e===void 0)throw this.corrupt(t,new Error("Session metadata is missing."));return e}async list(t){const a=[];for(const e of await this.projectKeys()){const r=v(this.paths,e,"00000000-0000-4000-8000-000000000000"),n=await this.readOrRebuildIndex(r.projectIndexFile,e);for(const s of Object.values(n))(t===void 0||s.projectFingerprint===t)&&a.push(s)}return a.sort((e,r)=>r.updatedAt.localeCompare(e.updatedAt))}async updateStatus(t,a){return this.withLock(t,async()=>{const r={...await this.require(t),status:a,updatedAt:new Date().toISOString()},n=await this.requirePaths(t);return await y(n.journalFile,T(r)),await this.journalHealth.markValid(n.journalFile),await j(this.paths,r,n.projectKey),r})}async rename(t,a){const e=a.trim().replace(/\s+/gu," ");if(e.length===0||e.length>120||/[\r\n]/u.test(e)||e.includes("\0"))throw new u(l.INVALID_ARGUMENT,"Session name is invalid.",{category:"session",userMessage:"Session name must be between 1 and 120 printable characters."});return this.withLock(t,async()=>{const n={...await this.require(t),name:e,updatedAt:new Date().toISOString()},s=await this.requirePaths(t);return await y(s.journalFile,T(n)),await this.journalHealth.markValid(s.journalFile),await j(this.paths,n,s.projectKey),n})}async appendEvent(t,a={}){const e=[{kind:"event",event:t}];a.locked===!0?await this.appendJournalLocked(t.sessionId,e):await this.appendJournal(t.sessionId,e)}async appendTranscript(t,a){await this.appendJournal(t,[{kind:"transcript",entry:a}])}async appendJournal(t,a){a.length!==0&&await this.withLock(t,()=>this.appendJournalLocked(t,a))}async readEvents(t){const a=await this.readSessionJournal(t);if(a.metadata===void 0)throw this.corrupt(t,new Error("Session metadata is missing."));return E(a.records)}async readTranscript(t){const a=await this.readSessionJournal(t);if(a.metadata===void 0)throw this.corrupt(t,new Error("Session metadata is missing."));return P(a.records)}async readHistory(t){return this.withLock(t,async()=>{const a=await this.readSessionJournal(t);if(a.metadata===void 0)throw this.corrupt(t,new Error("Session metadata is missing."));const e=a.records;return{events:E(e),transcript:P(e)}})}async delete(t){const a=await this.get(t);return a===void 0?!1:(await this.withLock(t,async()=>{const e=await this.requirePaths(t);await d.rm(e.journalFile,{force:!0}),await d.rm(e.sessionDirectory,{recursive:!0,force:!0}),this.journalHealth.forget(e.journalFile),await tt(this.paths,a,e.projectKey)}),!0)}async fork(t,a={}){const e=await this.readSnapshot(t),r=e.metadata,n=await this.create({projectFingerprint:r.projectFingerprint,cwd:r.cwd,model:a.model??r.model,profile:a.profile??r.profile,status:"active"});try{return await this.withLock(n.id,async()=>{const s=await this.requirePaths(n.id);for(const o of e.events){const c=nt(o.data);await y(s.journalFile,D({...o,sessionId:n.id,...c===void 0?{}:{data:c}}))}for(const o of e.transcript)await y(s.journalFile,B(o));await this.journalHealth.markValid(s.journalFile);for(const[o,c]of e.attachments)c.attachment!==void 0&&await this.persistAttachment(n.id,{...c.attachment,id:o},c.bytes)}),n}catch(s){try{await this.delete(n.id)}catch(o){throw new AggregateError([s,o],"Session fork failed and cleanup was incomplete.")}throw s}}async compact(t,a,e={}){const r=a.trim();if(r.length===0)throw new u(l.SESSION_CORRUPTED,"Compaction summary cannot be empty.",{category:"session",userMessage:"Compaction summary cannot be empty."});const n=new Date().toISOString();await this.appendJournal(t,[{kind:"transcript",entry:{type:"system",timestamp:n,content:`[Compacted context]
|
|
2
|
+
${r}`,...e.turnId===void 0?{}:{turnId:e.turnId}}},{kind:"event",event:{type:"context.compacted",timestamp:n,sessionId:t,...e.turnId===void 0?{}:{turnId:e.turnId},data:{summary:r}}}])}async export(t){const a=await this.readSnapshot(t),e=[];for(const r of a.transcript)for(const n of r.attachmentIds??[]){if(e.some(c=>c.attachment.id===n))continue;const s=a.attachments.get(n);if(s===void 0)continue;const o=s.attachment??{id:n,name:n,mimeType:"application/octet-stream",sizeBytes:s.bytes.byteLength,source:"file"};e.push({attachment:o,dataBase64:Buffer.from(s.bytes).toString("base64")})}return{metadata:a.metadata,events:a.events,transcript:a.transcript,attachments:e}}async import(t,a,e){ot(t);const r=await this.create({projectFingerprint:a,cwd:e,model:t.metadata.model,profile:t.metadata.profile,status:"active"});try{for(const n of t.events){const s=st(n.data);await this.appendEvent({...n,sessionId:r.id,...s===void 0?{}:{data:s}})}for(const n of t.transcript)await this.appendTranscript(r.id,n);for(const n of t.attachments)await this.saveAttachment(r.id,n.attachment,Buffer.from(n.dataBase64,"base64"));return r}catch(n){try{await this.delete(r.id)}catch(s){throw new AggregateError([n,s],"Session import failed and cleanup was incomplete.")}throw n}}async saveAttachment(t,a,e){if(!S.test(a.id))throw new u(l.ATTACHMENT_INVALID_IMAGE,"Attachment id is invalid.",{category:"attachment",userMessage:"Attachment name is invalid."});if(a.sizeBytes<0||a.sizeBytes>f.maxAttachmentBytes)throw new u(l.ATTACHMENT_TOO_LARGE,"Attachment exceeds the allowed size.",{category:"attachment",userMessage:"Attachment exceeds the allowed size."});if(e.byteLength!==a.sizeBytes)throw new u(l.ATTACHMENT_INVALID_IMAGE,"Attachment size does not match metadata.",{category:"attachment",userMessage:"Attachment size does not match its metadata."});return this.withLock(t,()=>this.persistAttachment(t,a,e))}async persistAttachment(t,a,e){const r=await this.requirePaths(t);await this.require(t),await d.mkdir(r.attachmentsDirectory,{recursive:!0});const n=await this.readAttachmentMetadata(r,a.id),s=n?.storagePath===void 0?await it(r.attachmentsDirectory,a.storageName,a.id):h.basename(n.storagePath),o=h.join(r.attachmentsDirectory,s);await d.writeFile(o,e,{flag:"wx",mode:384}).catch(async p=>{if(!$(p))throw p;await d.writeFile(o,e,{mode:384})});const c={...a,storagePath:h.posix.join("attachments",s)};return await O(h.join(r.attachmentsDirectory,`${a.id}.json`),`${JSON.stringify(c,null,2)}
|
|
3
|
+
`),c}async readAttachment(t,a){const e=await this.requirePaths(t);if(await this.require(t),!S.test(a))return;const r=await this.readAttachmentMetadata(e,a),n=h.join(e.attachmentsDirectory,R(r,a));try{if((await d.stat(n)).size>f.maxAttachmentBytes)throw new u(l.ATTACHMENT_TOO_LARGE,"Stored attachment exceeds the allowed size.",{category:"attachment",userMessage:"Stored attachment exceeds the allowed size."});return await d.readFile(n)}catch(s){if(w(s))return;throw s}}async deleteAttachment(t,a){return S.test(a)?this.withLock(t,async()=>{const e=await this.requirePaths(t);await this.require(t);const r=await this.readAttachmentMetadata(e,a),n=h.join(e.attachmentsDirectory,R(r,a)),s=h.join(e.attachmentsDirectory,`${a}.json`);let o=!1;for(const c of[n,s])try{await d.unlink(c),o=!0}catch(p){if(!w(p))throw p}return o}):!1}async recoverStaleLock(t){const a=await this.locate(t);return a===void 0?!1:U(a.lockFile,rt)}async repair(t){const a=await this.requirePaths(t),e=await this.withLock(t,()=>Q(a.journalFile));return await this.journalHealth.markValid(a.journalFile),{eventsRemoved:e,transcriptRemoved:0}}async withLock(t,a){const e=await this.requirePaths(t);await d.mkdir(e.sessionDirectory,{recursive:!0});let r;try{r=await G(e.lockFile)}catch(n){const s=await V(n,e.lockFile);if(s&&await this.recoverStaleLock(t))return this.withLock(t,a);throw s?new u(l.SESSION_LOCKED,`Session is locked: ${t}`,{category:"session",userMessage:"The session is being used by another process. Try again later.",retryable:!0}):n}try{return await a()}finally{await K(r,e.lockFile)}}async require(t){const a=await this.get(t);if(a===void 0)throw new u(l.SESSION_NOT_FOUND,`Session not found: ${t}`,{category:"session",userMessage:`Session not found: ${t}.`});return a}async requirePaths(t){const a=await this.locate(t);if(a===void 0)throw new u(l.SESSION_NOT_FOUND,`Session not found: ${t}`,{category:"session",userMessage:`Session not found: ${t}.`});return a}async locate(t){if(!_.test(t))return;const e=(await Y(this.paths)).sessions[t];if(typeof e=="string"&&L(e)){const r=v(this.paths,e,t);if(await k(r.journalFile))return r}return this.locateByScan(t)}async locateByScan(t){for(const a of await this.projectKeys()){const e=v(this.paths,a,t);if(await k(e.journalFile))return e}}async projectKeys(){try{return(await d.readdir(this.paths.projectsDir,{withFileTypes:!0})).filter(t=>t.isDirectory()&&L(t.name)).map(t=>t.name)}catch(t){if(w(t))return[];throw t}}async readOrRebuildIndex(t,a){try{const e=(await X(t,a)).sessions;return await this.indexMatchesJournals(a,e)?e:this.rebuildProjectIndex(a)}catch{return this.rebuildProjectIndex(a)}}async indexMatchesJournals(t,a){const e=await this.projectJournalIds(t),r=Object.keys(a);return e.length===r.length&&e.every(n=>a[n]!==void 0)}async projectJournalIds(t){const a=h.join(this.paths.projectsDir,t);try{return(await d.readdir(a,{withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(".jsonl")).map(e=>e.name.slice(0,-6)).filter(e=>_.test(e))}catch(e){if(w(e))return[];throw e}}async rebuildProjectIndex(t){const a={},e=h.join(this.paths.projectsDir,t);for(const n of await d.readdir(e,{withFileTypes:!0}))if(!(!n.isFile()||!n.name.endsWith(".jsonl")))try{const s=M(await N(h.join(e,n.name)));s!==void 0&&(a[s.id]=s)}catch{}const r=h.join(e,"index.json");await d.mkdir(e,{recursive:!0}),await O(r,`${JSON.stringify({projectKey:t,sessions:a},null,2)}
|
|
4
|
+
`);for(const n of Object.values(a))await j(this.paths,n,t);return a}async readSnapshot(t){return this.withLock(t,async()=>{const a=await this.readSessionJournal(t),e=a.metadata;if(e===void 0)throw this.corrupt(t,new Error("Session metadata is missing."));const r=a.sessionPaths,n=a.records,s=E(n),o=P(n),c=new Map;for(const p of o)for(const g of p.attachmentIds??[]){if(c.has(g))continue;const F=await this.readAttachment(t,g);F!==void 0&&c.set(g,{bytes:F,attachment:await this.readAttachmentMetadata(r,g)})}return{metadata:e,events:s,transcript:o,attachments:c}})}async appendJournalLocked(t,a){const e=await this.requirePaths(t);try{if(!await this.journalHealth.ensureValid(e.journalFile))throw new Error("Session metadata is missing.")}catch(n){throw this.corrupt(t,n)}const r=a.map(n=>{if(n.kind==="event"&&n.event.sessionId!==t)throw new u(l.SESSION_CORRUPTED,"Cannot append an event to a different session.",{category:"session",userMessage:"Session event data is invalid."});return n.kind==="event"?D(n.event):B(n.entry)});await Z(e.journalFile,r),await this.journalHealth.markValid(e.journalFile)}async readSessionJournal(t,a){const e=a??await this.requirePaths(t);try{const r=await N(e.journalFile),n=M(r);return await this.journalHealth.markValid(e.journalFile,n!==void 0),{sessionPaths:e,records:r,metadata:n}}catch(r){throw this.corrupt(t,r)}}async readAttachmentMetadata(t,a){try{return ht(await et(h.join(t.attachmentsDirectory,`${a}.json`),f.configFileBytes))}catch(e){if(w(e))return;throw e}}corrupt(t,a){return new u(l.SESSION_CORRUPTED,`Session metadata is corrupted: ${t}`,{category:"session",userMessage:"Session is corrupted and its metadata cannot be read.",cause:a})}}function nt(i){return b(i)}function st(i){return b(i)}function b(i){if(i===void 0||typeof i.goal!="object"||i.goal===null)return i;const t=i.goal;return t.status!=="active"?i:{...i,goal:{...t,status:"paused",updatedAt:new Date().toISOString()},reason:"Explicit resume is required after fork or import."}}async function k(i){try{return await d.access(i),!0}catch(t){if(w(t))return!1;throw t}}function R(i,t){const a=i?.storagePath;if(typeof a=="string"&&a.startsWith("attachments/")){const e=h.basename(a);if(e.length>0&&e!=="."&&e!=="..")return e}return`${t}.bin`}async function it(i,t,a){if(t===void 0)return`${a}.bin`;const e=h.basename(t).replace(/[^A-Za-z0-9._-]/gu,"_").slice(0,120)||`${a}.bin`,r=h.extname(e),n=r.length===0?e:e.slice(0,-r.length);for(let s=0;s<1e4;s+=1){const o=s===0?e:`${n}-${s}${r}`;if(!await k(h.join(i,o)))return o}throw new u(l.ATTACHMENT_TOO_LARGE,"Too many attachments share the same filename.",{category:"attachment",userMessage:"Too many attachments share the same filename."})}function ot(i){if(!z(i.metadata)||!Array.isArray(i.events)||!Array.isArray(i.transcript)||!Array.isArray(i.attachments))throw m("Session export file is invalid.");if(i.events.length>f.sessionEvents||i.transcript.length>f.sessionTranscriptEntries||i.attachments.length>f.sessionAttachments)throw m("Session export exceeds the supported entry limits.");for(const e of i.events){if(!I(e))throw m("Session export contains an invalid event.");if(q(e.type)&&!H(e.data))throw m("Session export contains an invalid goal event.");if(A(e.type)>256||A(e.timestamp)>128||A(e.sessionId)>128)throw m("Session event metadata is too large.")}const t=new Set;let a=0;for(const e of i.transcript){if(!C(e)||A(e.content)>f.sessionTextBytes)throw m("Session export contains an invalid transcript entry.");if(e.attachmentIds!==void 0&&(!Array.isArray(e.attachmentIds)||e.attachmentIds.some(r=>typeof r!="string"||!S.test(r))))throw m("Session transcript contains invalid attachment references.")}for(const e of i.attachments){if(!ct(e))throw m("Session export contains an invalid attachment.");const r=e.attachment;if(typeof r.id!="string"||!S.test(r.id)||t.has(r.id)||typeof r.name!="string"||typeof r.mimeType!="string"||typeof r.sizeBytes!="number"||!Number.isSafeInteger(r.sizeBytes)||r.sizeBytes<0||r.sizeBytes>f.maxAttachmentBytes||r.source!=="clipboard"&&r.source!=="file")throw m("Session export contains invalid attachment metadata.");const n=Buffer.from(e.dataBase64,"base64");if(n.toString("base64")!==e.dataBase64||n.byteLength!==r.sizeBytes)throw m("Session export contains an invalid attachment payload.");if(a+=n.byteLength,a>f.sessionAttachmentTotalBytes)throw m("Session export exceeds the total attachment limit.");t.add(r.id)}}function ct(i){if(!x(i)||!x(i.attachment)||typeof i.dataBase64!="string")return!1;const t=i.attachment;return typeof t.id=="string"&&typeof t.name=="string"&&typeof t.mimeType=="string"&&typeof t.sizeBytes=="number"&&Number.isSafeInteger(t.sizeBytes)&&(t.source==="clipboard"||t.source==="file")}function A(i){return Buffer.byteLength(i,"utf8")}function m(i){return new u(l.SESSION_CORRUPTED,i,{category:"session",userMessage:i})}function ht(i){if(typeof i!="object"||i===null)throw new Error("Invalid attachment metadata.");const t=i;if(typeof t.id!="string"||typeof t.name!="string"||typeof t.mimeType!="string"||typeof t.sizeBytes!="number"||t.source!=="clipboard"&&t.source!=="file")throw new Error("Invalid attachment metadata.");return i}export{kt as FileSessionStore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const a=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,S=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,T=3e5;export{S as ATTACHMENT_ID_PATTERN,a as SESSION_ID_PATTERN,T as SESSION_LOCK_STALE_MS};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import c from"node:path";import{atomicWriteFile as
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import c from"node:path";import{atomicWriteFile as p,withFileLock as a}from"../filesystem/atomic-file-store.js";import{isFileNotFound as l}from"../filesystem/fs-errors.js";import{resolveProjectSessionPathsForKey as w}from"./project-session-paths.js";import{readJsonFileBounded as x}from"../filesystem/bounded-json-reader.js";import{RESOURCE_LIMITS as d}from"../../domain/runtime/resource-limits.js";async function j(o,s){try{return m(await x(o,d.sessionIndexBytes),s)}catch(t){if(l(t))return{projectKey:s,sessions:{}};throw t}}async function y(o,s,t){const e=`${JSON.stringify({projectKey:s,sessions:t},null,2)}
|
|
2
|
+
`;if(Buffer.byteLength(e,"utf8")>d.sessionIndexBytes)throw new Error("The project session index exceeds the supported size limit.");await p(o,e)}async function I(o){const s=c.join(o.projectsDir,"locator.json");try{return h(await x(s,d.sessionIndexBytes))}catch(t){if(l(t))return{sessions:{}};throw t}}function m(o,s){if(!r(o)||o.projectKey!==s||!r(o.sessions))throw new Error("Invalid project session index.");for(const t of Object.values(o.sessions))if(!F(t))throw new Error("Invalid project session metadata.");return{projectKey:s,sessions:o.sessions}}function h(o){if(!r(o)||!r(o.sessions)||Object.values(o.sessions).some(s=>typeof s!="string"))throw new Error("Invalid session locator index.");return{sessions:o.sessions}}function F(o){return r(o)?typeof o.id=="string"&&typeof o.projectFingerprint=="string"&&typeof o.cwd=="string"&&(typeof o.model=="string"||o.model===null)&&(typeof o.profile=="string"||o.profile===null)&&(o.status==="active"||o.status==="completed"||o.status==="failed"||o.status==="cancelled")&&typeof o.createdAt=="string"&&typeof o.updatedAt=="string":!1}function r(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}async function u(o,s){const t=`${JSON.stringify({sessions:s},null,2)}
|
|
3
|
+
`;if(Buffer.byteLength(t,"utf8")>d.sessionIndexBytes)throw new Error("The session locator exceeds the supported size limit.");await p(c.join(o.projectsDir,"locator.json"),t)}async function b(o,s,t){const e=w(o,t,s.id);await a(e.projectIndexFile,async()=>{const n=await j(e.projectIndexFile,t);await y(e.projectIndexFile,t,{...n.sessions,[s.id]:s})});const f=c.join(o.projectsDir,"locator.json");await a(f,async()=>{const n=await I(o);await u(o,{...n.sessions,[s.id]:t})})}async function O(o,s,t){const e=w(o,t,s.id);await a(e.projectIndexFile,async()=>{const i={...(await j(e.projectIndexFile,t)).sessions};delete i[s.id],await y(e.projectIndexFile,t,i)});const f=c.join(o.projectsDir,"locator.json");await a(f,async()=>{const i={...(await I(o)).sessions};delete i[s.id],await u(o,i)})}export{b as indexProjectSession,j as readProjectSessionIndex,I as readSessionLocator,O as removeIndexedSession,y as writeProjectSessionIndex,u as writeSessionLocator};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Avoids reparsing an unchanged journal on every append while detecting external writes. */
|
|
2
|
+
export declare class SessionJournalHealth {
|
|
3
|
+
private readonly entries;
|
|
4
|
+
ensureValid(filePath: string): Promise<boolean>;
|
|
5
|
+
markValid(filePath: string, hasMetadata?: boolean): Promise<void>;
|
|
6
|
+
forget(filePath: string): void;
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import c from"node:fs/promises";import{latestMetadata as m,readJournal as u}from"./session-journal.js";class g{entries=new Map;async ensureValid(e){const s=await n(e),a=this.entries.get(e);if(a!==void 0&&o(a.signature,s))return a.hasMetadata;const r=await u(e),i=m(r)!==void 0;return this.entries.set(e,{signature:await n(e),hasMetadata:i}),i}async markValid(e,s=!0){this.entries.set(e,{signature:await n(e),hasMetadata:s})}forget(e){this.entries.delete(e)}}async function n(t){const e=await c.stat(t);return{size:e.size,mtimeMs:e.mtimeMs,ctimeMs:e.ctimeMs}}function o(t,e){return t.size===e.size&&t.mtimeMs===e.mtimeMs&&t.ctimeMs===e.ctimeMs}export{g as SessionJournalHealth};
|
|
@@ -2,14 +2,18 @@ import type { ToolDefinition } from '@lotagate/sdk';
|
|
|
2
2
|
import type { ToolExecutionContext, ToolExecutor, ToolInfo, ToolResult } from '@lotagate/agent-sdk';
|
|
3
3
|
import type { ToolActivityObserver } from '../../ports/tool-activity.js';
|
|
4
4
|
import { type HostPlatformContext } from '../platform/host-platform.js';
|
|
5
|
+
import type { Logger } from '../../ports/logger.js';
|
|
6
|
+
export type ShellToolEnvironment = 'host' | 'linux-guest';
|
|
5
7
|
/** Exposes the same shell capability definitions to runtime and context accounting. */
|
|
6
|
-
export declare function shellToolDefinitions(): readonly ToolDefinition[];
|
|
8
|
+
export declare function shellToolDefinitions(environment?: ShellToolEnvironment): readonly ToolDefinition[];
|
|
7
9
|
export declare class ShellToolExecutor implements ToolExecutor {
|
|
8
10
|
private readonly options;
|
|
9
11
|
constructor(options?: {
|
|
10
12
|
onActivity?: ToolActivityObserver;
|
|
11
13
|
readOnly?: boolean;
|
|
12
14
|
platform?: HostPlatformContext;
|
|
15
|
+
logger?: Logger;
|
|
16
|
+
toolEnvironment?: ShellToolEnvironment;
|
|
13
17
|
});
|
|
14
18
|
listTools(): readonly ToolDefinition[];
|
|
15
19
|
getToolInfo(toolName: string): ToolInfo | undefined;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{resolveReadOnlyExecutable as
|
|
2
|
-
Process exited with code ${String(e.exitCode)}.`}`;return{content:
|
|
1
|
+
import{resolveReadOnlyExecutable as y,readOnlyArguments as E}from"../platform/read-only-executable.js";import{resolveWorkspacePath as p}from"../filesystem/path-resolver.js";import{isReadOnlyShellRequest as b}from"../../application/security/tool-risk-classifier.js";import{detectHostPlatform as S}from"../platform/host-platform.js";import{normalizePowerShellScriptInput as T,execPlatformCommand as v}from"../platform/host-process.js";import{formatShellCommandForDisplay as P}from"../../application/agent/tool-display.js";import{withToolExecutionLogging as C}from"../observability/tool-execution-logger.js";import{RESOURCE_LIMITS as c}from"../../domain/runtime/resource-limits.js";const h=[{type:"function",function:{name:"shell.exec",description:"Execute one program with structured arguments inside the trusted workspace. Shell interpretation is disabled. When the runtime platform is Windows, prefer powershell.exe with script for operating-system work; use direct command and args for project executables. On other platforms, follow the runtime shell and executable availability. Keep the executable in command and pass arguments separately in args (for example, git status --short means command git and args [status, --short]). The script field is a complete PowerShell script, is valid only with powershell.exe or pwsh.exe, and cannot be combined with args. Inspect stdout, stderr, exit code, and the resulting state before reporting success.",parameters:{type:"object",properties:{command:{type:"string",description:"Executable name or path."},args:{type:"array",items:{type:"string"},description:"Structured process arguments."},script:{type:"string",description:"Optional complete PowerShell script. Use only with powershell.exe or pwsh.exe; passed as one -Command argument."},cwd:{type:"string",description:"Optional workspace-relative working directory."},timeoutMs:{type:"number",description:"Timeout between 100 milliseconds and the configured runtime maximum."}},required:["command"],additionalProperties:!1}}}],k="Process completed successfully with no output.";function O(o="host"){return o==="host"?h:h.map(t=>"function"in t?{...t,function:{...t.function,description:'Execute one Linux program with structured arguments inside the isolated Desktop WSL2 guest. Use Linux executables and workspace-relative paths; never invoke powershell.exe, cmd.exe, wsl.exe, Windows paths, or host interop. Keep command and args separate. For multiple shell operations, use bash with args ["-lc", "..."] only when a shell script is necessary. Inspect stdout, stderr, exit code, and returned data before continuing.'}}:t)}class B{options;constructor(t={}){this.options=t}listTools(){return O(this.options.toolEnvironment)}getToolInfo(t){return t==="shell.exec"?{toolName:t,source:"shell",executorId:"local-shell"}:void 0}async execute(t,l,i){return t!=="shell.exec"?{content:`Unknown shell tool: ${t}`,isError:!0}:C(this.options.logger,{toolName:t,source:"shell",context:i},async()=>{if(typeof l.command!="string"||l.command.trim().length===0)return{content:"shell.exec requires a command.",isError:!0};const a=this.options.platform??S();let r;try{r=T(l,a,{allowNonWindows:this.options.toolEnvironment!=="linux-guest"})}catch(n){return{content:n instanceof Error?n.message:"Invalid shell.exec PowerShell script.",isError:!0}}const e=r.args===void 0?[]:r.args;if(!Array.isArray(e)||e.some(n=>typeof n!="string"))return{content:"shell.exec args must be an array of strings.",isError:!0};const s=await b(r.command,e,i,p,r.cwd,a);if(this.options.readOnly&&!s)return{content:"This subagent is limited to read-only shell commands inside the trusted workspace.",isError:!0};const g=this.options.toolEnvironment==="linux-guest"?c.guestShellTimeoutMs:c.hostShellTimeoutMs,w=typeof r.timeoutMs=="number"?Math.min(Math.max(r.timeoutMs,100),g):c.defaultShellTimeoutMs,u=await p(r.cwd??".",i),m=s?await y(r.command,i.workspaceRoot??u,a):void 0;if(s&&m===void 0)return{content:"Read-only executable is no longer available.",isError:!0};const x=P(r.command,e),d=this.options.onActivity?.start({key:`${i.runId}:shell.exec`,toolName:"shell.exec",source:"shell",label:x});try{const n=await M(m??r.command,s?E(r.command,e):e,u,w,i,a);return d?.complete(n.isError===!0),n}catch(n){throw d?.complete(!0),n}})}}async function M(o,t,l,i,a,r){try{const e=await v(o,t,r,{cwd:l,timeoutMs:i,maxBufferBytes:a.maxResultBytes,rejectOnNonZero:!1,...a.signal===void 0?{}:{signal:a.signal}}),s=`${e.stdout}${e.stderr}${e.exitCode===0?"":`
|
|
2
|
+
Process exited with code ${String(e.exitCode)}.`}`;return{content:f(s||k),isError:e.exitCode!==0,metadata:{exitCode:e.exitCode}}}catch(e){const s=e instanceof Error?e.message:"Process execution failed.";return{content:f(s),isError:!0,metadata:{errorCode:I(s)}}}}function I(o){return/timed out/iu.test(o)?"timeout":/cancelled/iu.test(o)?"cancelled":/output exceeded/iu.test(o)?"output_limit":"process_failure"}function f(o){return o.replace(/Bearer\s+[^\s]+/gi,"Bearer [REDACTED]").replace(/sk-[A-Za-z0-9_-]{8,}/g,"[REDACTED]")}export{B as ShellToolExecutor,O as shellToolDefinitions};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{encoding_for_model as c,get_encoding as
|
|
1
|
+
import{encoding_for_model as c,get_encoding as d}from"tiktoken";import{FALLBACK_ENCODING as f}from"./token-constants.js";function m(e){try{const t=o(e.model);try{const n=t.encode(e.prompt).length,r=t.encode(e.response).length;return{promptTokens:n,completionTokens:r,totalTokens:n+r,estimated:!0}}finally{t.free()}}catch{return}}function a(e){try{const t=o(e.model);try{return t.encode(e.text).length}finally{t.free()}}catch{return Math.ceil(Buffer.byteLength(e.text,"utf8")/4)}}function o(e){try{return c(e)}catch{return d(f)}}export{a as estimateTextTokens,m as estimateTurnUsage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const FALLBACK_ENCODING = "o200k_base";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o="o200k_base";export{o as FALLBACK_ENCODING};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
`)}async load(t){const i=
|
|
3
|
-
`)})}async readOptional(t){
|
|
4
|
-
`,{encoding:"utf8",mode:384,flag:"wx"})}catch(
|
|
1
|
+
import n from"node:fs/promises";import d from"node:path";import{DEFAULT_WORKSPACE_SETTINGS as l,normalizePermissionRule as f}from"../../domain/workspace/workspace-settings.js";import{permissionsFromSettings as u,validateSettingsDocument as g}from"../../domain/settings/settings-document.js";import{resolveProjectConfigPaths as c}from"../platform/platform-paths.js";import{atomicWriteFile as w,withFileLock as h}from"../filesystem/atomic-file-store.js";import{isAlreadyExists as y,isFileNotFound as S}from"../filesystem/fs-errors.js";import{readJsonFileBounded as k}from"../filesystem/bounded-json-reader.js";import{RESOURCE_LIMITS as O}from"../../domain/runtime/resource-limits.js";class T{async ensureInitialized(t){const i=c(t);await n.mkdir(i.directory,{recursive:!0}),await Promise.all([i.skillsDir,i.pluginsDir,i.hooksDir].map(e=>n.mkdir(e,{recursive:!0}))),await this.createIfMissing(i.settings,l),await this.createIfMissing(i.localSettings,l),await this.createIfMissing(d.join(i.directory,".gitignore"),`settings.local.json
|
|
2
|
+
`)}async load(t){const i=c(t),[e,r]=await Promise.all([this.readOptional(i.settings),this.readOptional(i.localSettings)]);return{schemaVersion:1,permissions:D(e?.permissions,r?.permissions)}}async rememberAllow(t,i){if(i.trim().length===0)return;const e=f(i),r=c(t);await n.mkdir(r.directory,{recursive:!0}),await h(r.localSettings,async()=>{const o=await this.readDocumentOptional(r.localSettings),a=o===void 0?l:{schemaVersion:1,permissions:u(o)};if(a.permissions.allow.includes(e))return;const p={...o?.config??{},permissions:{...a.permissions,allow:[...a.permissions.allow,e]}};await w(r.localSettings,`${JSON.stringify(p,null,2)}
|
|
3
|
+
`)})}async readOptional(t){const i=await this.readDocumentOptional(t);if(i!==void 0)return{schemaVersion:1,permissions:u(i)}}async readDocumentOptional(t){try{return g(await k(t,O.workspaceSettingsBytes))}catch(i){if(S(i))return;throw i}}async createIfMissing(t,i){try{await n.writeFile(t,typeof i=="string"?i:`${JSON.stringify(i,null,2)}
|
|
4
|
+
`,{encoding:"utf8",mode:384,flag:"wx"})}catch(e){if(!y(e))throw e}}}function D(s,t){return{allow:m(s?.allow,t?.allow),ask:m(s?.ask,t?.ask),deny:m(s?.deny,t?.deny)}}function m(...s){return[...new Set(s.flatMap(t=>t??[]))]}export{T as WorkspaceSettingsStore};
|
package/dist/main.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{asCliError as
|
|
2
|
-
`):r!==void 0?r.logger.error(
|
|
3
|
-
`),t.exitCode}finally{await r?.shutdown.shutdown()}}function
|
|
1
|
+
import{asCliError as S}from"./domain/errors/cli-error.js";import{createCompositionRoot as E}from"./bootstrap/composition-root.js";import{resolveStartupContext as x}from"./bootstrap/startup-sequence.js";import{parseGlobalCliOptions as O}from"./bootstrap/global-cli-options.js";import{TuiApplication as h}from"./presentation/tui/tui-application.js";import{formatCliErrorMessage as T}from"./application/commands/command-hints.js";import{COMMAND_REGISTRY as b}from"./application/commands/command-runtime.js";import{parseCommandInvocation as R}from"./application/commands/command-parser.js";import{executeApplicationCommand as v,executeInformationalCommand as G}from"./application/commands/application-command-executor.js";import{CLI_VERSION as B}from"./version.js";async function V(o,e={}){const y=e.stdin??process.stdin,n=e.stdout??process.stdout,u=e.stderr??process.stderr;let r;const i=new AbortController;let f=143;const p=()=>i.abort(new Error("Process termination requested."));let c;process.once("SIGTERM",p);try{const l=O(o),t=M(l.commandTokens);if(t.length===0){r=E({stderr:u,interactive:!0});const d=r.logger;d.info("Interactive session started.");const w=await new h(r,x(o).cwd,{output:n,signal:i.signal}).run();return d.info("Interactive session completed.",{exitCode:w}),w}const a=x(o).cwd,s=R(t,"direct",b),g=G(s,n);if(g!==void 0)return g;s.action.executor==="agent"&&(c=()=>{f=130,i.abort(new Error("Process interruption requested."))},process.once("SIGINT",c));const m=E({stderr:u});r=m;const C=m.logger;C.info("CLI command started.",{command:s.action.id,cwd:a});const I=await v(s,{runtime:m,cwd:a,output:n,stdin:y,writableOutput:n,signal:i.signal,resumeInteractive:async d=>new h(m,a,{output:n,sessionId:d,signal:i.signal}).run()});return C.info("CLI command completed.",{command:s.action.id,exitCode:I}),I}catch(l){if(i.signal.aborted)return f;const t=S(l);return r?.logger.error("CLI command failed.",{code:t.code,category:t.category}),N(o)?n.write(`${JSON.stringify({error:t.toJSON()})}
|
|
2
|
+
`):r!==void 0?r.logger.error(T(t,"direct"),{code:t.code,category:t.category}):u.write(`[error] ${T(t,"direct")}
|
|
3
|
+
`),t.exitCode}finally{process.off("SIGTERM",p),c!==void 0&&process.off("SIGINT",c),await r?.shutdown.shutdown()}}function N(o){return o.some(e=>e==="--json"||e.startsWith("--json="))}function M(o){return o.length===1&&(o[0]==="--help"||o[0]==="-h")?["help"]:o.length===1&&o[0]==="--version"?["version"]:o}export{B as CLI_VERSION,V as main};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { GeneratedImage, MediaBinary, VideoOperation } from '../domain/media/media-contract.js';
|
|
2
|
+
export type SpeechStreamFormat = 'audio' | 'sse';
|
|
3
|
+
export type SpeechStreamEvent = Readonly<Record<string, unknown>>;
|
|
2
4
|
export interface MediaRequestOptions {
|
|
3
5
|
readonly signal?: AbortSignal | undefined;
|
|
4
6
|
}
|
|
@@ -26,6 +28,7 @@ export interface SpeechInput {
|
|
|
26
28
|
readonly instructions?: string | undefined;
|
|
27
29
|
readonly responseFormat?: 'mp3' | 'opus' | 'aac' | 'flac' | 'wav' | 'pcm' | undefined;
|
|
28
30
|
readonly speed?: number | undefined;
|
|
31
|
+
readonly streamFormat?: SpeechStreamFormat | undefined;
|
|
29
32
|
}
|
|
30
33
|
export interface AudioUploadInput {
|
|
31
34
|
readonly model: string;
|
|
@@ -42,6 +45,9 @@ export interface MediaGatewayClient {
|
|
|
42
45
|
generateImage(input: ImageGenerationInput, options?: MediaRequestOptions): Promise<readonly GeneratedImage[]>;
|
|
43
46
|
editImage(input: ImageEditInput, options?: MediaRequestOptions): Promise<readonly GeneratedImage[]>;
|
|
44
47
|
createSpeech(input: SpeechInput, options?: MediaRequestOptions): Promise<MediaBinary>;
|
|
48
|
+
createSpeechStream(input: SpeechInput & {
|
|
49
|
+
readonly streamFormat: 'sse';
|
|
50
|
+
}, options?: MediaRequestOptions): AsyncIterable<SpeechStreamEvent>;
|
|
45
51
|
transcribe(input: AudioUploadInput, options?: MediaRequestOptions): Promise<string>;
|
|
46
52
|
translate(input: AudioUploadInput, options?: MediaRequestOptions): Promise<string>;
|
|
47
53
|
createVideo(input: {
|
|
@@ -51,6 +51,7 @@ export interface SessionStore {
|
|
|
51
51
|
export(sessionId: string): Promise<SessionBundle>;
|
|
52
52
|
import(bundle: SessionBundle, projectFingerprint: string, cwd: string): Promise<SessionMetadata>;
|
|
53
53
|
saveAttachment(sessionId: string, attachment: Attachment, bytes: Uint8Array): Promise<Attachment>;
|
|
54
|
+
deleteAttachment(sessionId: string, attachmentId: string): Promise<boolean>;
|
|
54
55
|
readAttachment(sessionId: string, attachmentId: string): Promise<Uint8Array | undefined>;
|
|
55
56
|
recoverStaleLock(sessionId: string): Promise<boolean>;
|
|
56
57
|
repair(sessionId: string): Promise<SessionRepairResult>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import{jsx as s,jsxs as R}from"react/jsx-runtime";import{useEffect as le,useLayoutEffect as U,useRef as S,useState as P}from"react";import{Box as g,Text as d,measureElement as de,useCursor as ae,useInput as fe,usePaste as me,useStdout as he}from"ink";import{formatContextUsage as pe,terminalTextWidth as H}from"../../formatters.js";import{DARK_THEME as r}from"../../../themes/theme.js";import{AttachmentChip as Ce}from"./transcript.js";import{isMouseSequence as ge}from"../../terminal-mouse.js";import{commandSuggestions as we}from"../../../../application/commands/command-presentation.js";import{parseCommandInvocation as xe,tokenizeCommandInput as Me}from"../../../../application/commands/command-parser.js";import{COMMAND_REGISTRY as k}from"../../../../application/commands/command-runtime.js";const q=4;function Ae({layout:o,value:c,cursor:i,terminalRows:u}){const a=c.slice(0,i).split(`
|
|
2
|
-
`),f=Math.max(1,o.width-(q+2)),w=a.slice(0,-1).reduce((W,l)=>W+Math.max(1,Math.ceil(H(l)/f)),0),p=H(a.at(-1)??""),E=o.y+1+w+Math.floor(p/f);if(!(u!==void 0&&(E<0||E>=u)))return{x:o.x+q+p%f,y:E}}function _e({bridge:o,enabled:c,activeRun:i,visible:u=!0,clearBlockedUntil:a,footerNotice:f,contextUsage:w,attachments:p,fileChoices:E,onLayoutRowsChange:W}){const[l,ee]=P(""),[N,L]=P(0),[$,
|
|
3
|
-
`)&&X.current!==l?we(l,k,"tui").slice(0,8):[],I=Se(l,N),Z=I===void 0?[]:E.filter(e=>e.value.slice(1).toLowerCase().includes(I.query.toLowerCase())).slice(0,8),h=b.length>0?b:Z,j=()=>{D.current=!1,F(void 0),m.current!==void 0&&clearTimeout(m.current),m.current=void 0},T=(e,t)=>{
|
|
4
|
-
`);if(t.length===0)return;j(),v();const n=
|
|
5
|
-
`);return}if(t.return){const n=h[$];if(b.length>0&&n!==void 0&&n.value!==l){K(n);return}if(Te(l)){y();return}n!==void 0&&Z.length>0?Y(n):y();return}if(t.tab&&h[$]!==void 0){const n=h[$];n!==void 0&&(b.length>0?K(n):Y(n));return}if(t.upArrow&&h.length>0){
|
|
2
|
+
`),f=Math.max(1,o.width-(q+2)),w=a.slice(0,-1).reduce((W,l)=>W+Math.max(1,Math.ceil(H(l)/f)),0),p=H(a.at(-1)??""),E=o.y+1+w+Math.floor(p/f);if(!(u!==void 0&&(E<0||E>=u)))return{x:o.x+q+p%f,y:E}}function _e({bridge:o,enabled:c,activeRun:i,visible:u=!0,clearBlockedUntil:a,footerNotice:f,contextUsage:w,attachments:p,fileChoices:E,onLayoutRowsChange:W}){const[l,ee]=P(""),[N,L]=P(0),[$,M]=P(0),[_,F]=P(),m=S(void 0),D=S(!1),x=S(""),C=S(0),X=S(void 0),O=S(null),[A,V]=P({left:0,top:0,width:0,hasMeasured:!1}),{setCursorPosition:te}=ae(),{stdout:G}=he(),b=l.startsWith("/")&&!l.includes(`
|
|
3
|
+
`)&&X.current!==l?we(l,k,"tui").slice(0,8):[],I=Se(l,N),Z=I===void 0?[]:E.filter(e=>e.value.slice(1).toLowerCase().includes(I.query.toLowerCase())).slice(0,8),h=b.length>0?b:Z,j=()=>{D.current=!1,F(void 0),m.current!==void 0&&clearTimeout(m.current),m.current=void 0},T=(e,t)=>{x.current=e,C.current=t,ee(e),L(t)},v=()=>{X.current=void 0},K=e=>{T(e.value,e.value.length),X.current=e.value,M(0)},B=e=>{const t=e.replace(/\r\n?/gu,`
|
|
4
|
+
`);if(t.length===0)return;j(),v();const n=x.current,z=C.current;T(`${n.slice(0,z)}${t}${n.slice(z)}`,z+t.length)},Y=e=>{if(I===void 0)return;v();const t=x.current;T(`${t.slice(0,I.start)}${e.value} ${t.slice(C.current)}`,I.start+e.value.length+1),M(0)},ne=()=>{const e=C.current;if(e===0)return;j(),v();const t=x.current;T(`${t.slice(0,e-1)}${t.slice(e)}`,e-1)},y=()=>{const e=x.current.trim();e.length>0&&(j(),v(),T("",0),M(0),o.submit(e))},re=()=>{j(),T("",0),M(0),o.clearAttachments()},oe=()=>{D.current=!0,F("Press Esc again to clear text and references."),m.current!==void 0&&clearTimeout(m.current),m.current=setTimeout(()=>{D.current=!1,F(void 0),m.current=void 0},1500)};fe((e,t)=>{if(c&&!ge(e)){if(t.escape||e==="\x1B"){if(i||a!==void 0&&a>Date.now()||l.length===0&&p.length===0)return;D.current?re():oe();return}if(t.meta&&e.toLowerCase()==="v"){o.pasteImage(x.current).catch(()=>{});return}if(t.ctrl&&e.toLowerCase()==="v"){o.pasteText().then(n=>{n!==void 0&&B(n)}).catch(()=>{});return}if(t.return&&t.shift){B(`
|
|
5
|
+
`);return}if(t.return){const n=h[$];if(b.length>0&&n!==void 0&&n.value!==l){K(n);return}if(Te(l)){y();return}n!==void 0&&Z.length>0?Y(n):y();return}if(t.tab&&h[$]!==void 0){const n=h[$];n!==void 0&&(b.length>0?K(n):Y(n));return}if(t.upArrow&&h.length>0){M(n=>Math.max(0,n-1));return}if(t.downArrow&&h.length>0){M(n=>Math.min(h.length-1,n+1));return}if(t.leftArrow){v();const n=Math.max(0,C.current-1);C.current=n,L(n);return}if(t.rightArrow){v();const n=Math.min(x.current.length,C.current+1);C.current=n,L(n);return}if(t.backspace||t.delete){ne();return}!t.ctrl&&!t.meta&&e.length>0&&B(e)}},{isActive:c}),me(e=>{c&&B(e)},{isActive:c}),le(()=>()=>{m.current!==void 0&&clearTimeout(m.current)},[]);const J=l.split(`
|
|
6
6
|
`),ie=A.hasMeasured?A.width:Math.max(40,G.columns??80),se=Math.max(1,ie-(q+2)),ue=J.reduce((e,t)=>e+Math.max(1,Math.ceil(H(t)/se)),0),Q=ve({attachmentCount:p.length,inputRows:ue,hasClearHint:_!==void 0,hasFooterNotice:f!==void 0,choiceCount:h.length});U(()=>{W?.(Q+1)},[Q,W]),U(()=>{const e=O.current;if(e===null){V(n=>n.hasMeasured?{left:0,top:0,width:0,hasMeasured:!1}:n);return}const t=de(e);V(n=>n.left===t.x&&n.top===t.y&&n.width===t.width&&n.hasMeasured?n:{left:t.x,top:t.y,width:t.width,hasMeasured:!0})});const ce=c&&u&&A.hasMeasured?Ae({layout:{x:A.left,y:A.top,width:A.width},value:l,cursor:N,terminalRows:G.rows}):void 0;return te(ce),u?R(g,{width:"100%",flexDirection:"column",marginTop:1,children:[p.map(e=>s(Ce,{attachment:e},e.id)),s(g,{ref:O,width:"100%",borderStyle:"round",borderColor:c?r.accent:r.border,flexDirection:"column",paddingX:1,children:R(g,{children:[s(d,{color:r.accent,children:"\u203A "}),s(d,{wrap:"wrap",color:l.length===0?r.muted:r.text,children:l.length===0?"Ask LotaGate to work on this project\u2026":Re(J.join(`
|
|
7
7
|
`))})]})}),R(g,{paddingX:1,justifyContent:"space-between",children:[s(d,{color:r.muted,dimColor:!0,children:"Enter send \xB7 Shift+Enter newline \xB7 / commands \xB7 @ files \xB7 Ctrl+V text \xB7 Alt+V image"}),w!==void 0&&s(d,{color:r.muted,dimColor:!0,children:pe(w.usedTokens,w.contextWindow)})]}),_!==void 0&&s(g,{paddingX:1,children:s(d,{color:r.muted,dimColor:!0,children:_})}),f!==void 0&&s(g,{paddingX:1,children:s(d,{color:r.muted,dimColor:!0,children:f})}),h.length>0&&s(g,{borderStyle:"round",borderColor:r.border,flexDirection:"column",paddingX:1,children:h.map((e,t)=>R(g,{...t===$?{backgroundColor:r.selection}:{},children:[s(d,{color:t===$?r.accent:r.muted,children:"\u203A "}),R(d,{color:e.kind==="directory"?r.warning:r.text,children:[e.kind==="directory"?"\u25B8 ":"",e.label]}),R(d,{color:r.muted,children:[" ",e.description]})]},e.value))})]}):null}function Te(o){if(!o.startsWith("/")||o.includes(`
|
|
8
8
|
`))return!1;try{return xe(Me(o.trimStart().slice(1)),"tui",k),!0}catch{return!1}}function ve({attachmentCount:o,inputRows:c,hasClearHint:i,hasFooterNotice:u,choiceCount:a}){const f=o*2,w=Math.max(1,c)+2,p=a>0?a+2:0;return f+w+1+(i?1:0)+(u?1:0)+p}function Re(o){return o.split(/(@[^\s@]+|https?:\/\/[^\s]+|\/[A-Za-z][\w-]*)/gu).filter(i=>i.length>0).map((i,u)=>i.startsWith("@")?s(d,{color:r.accent,children:i},u):/^https?:\/\//u.test(i)?s(d,{color:r.link,underline:!0,children:i},u):/^\/[A-Za-z][\w-]*$/u.test(i)?s(d,{color:r.accent,children:i},u):s(d,{children:i},u))}function Se(o,c){const i=o.slice(0,c),u=/(?:^|\s)@([^\s@]*)$/u.exec(i);if(u===null)return;const a=u[1]??"";return{start:c-a.length-1,query:a}}export{_e as Composer,Se as atFileReference,Ae as calculateComposerCursorPosition};
|
|
@@ -28,6 +28,7 @@ export interface TranscriptViewport {
|
|
|
28
28
|
messages: readonly TuiTranscriptEntry[];
|
|
29
29
|
firstMessage: number;
|
|
30
30
|
lastMessage: number;
|
|
31
|
+
totalRows?: number;
|
|
31
32
|
}
|
|
32
33
|
/** Returns a stable message window, measured from the newest transcript entry. */
|
|
33
34
|
export declare function transcriptViewport(messages: readonly TuiTranscriptEntry[], offset: number, maximumMessages: number): TranscriptViewport;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{jsx as e,jsxs as s}from"react/jsx-runtime";import{Box as f,Text as m}from"ink";import{DARK_THEME as
|
|
2
|
-
`).reduce((d,
|
|
3
|
-
`).reduce((
|
|
4
|
-
`)){const
|
|
5
|
-
`)}function
|
|
1
|
+
import{jsx as e,jsxs as s}from"react/jsx-runtime";import{Box as f,Text as m}from"ink";import{DARK_THEME as M}from"../../../themes/theme.js";import{MarkdownMessage as E}from"../markdown-message.js";import{FileDiff as W,fileDiffRowCount as _}from"./file-diff.js";import{terminalTextWidth as D,wrapTerminalText as G}from"../../formatters.js";import{ActivityEntry as I}from"./activity-entry.js";import{SubagentCreatedEntry as F}from"./subagent-activity.js";import{ActivityStatus as L}from"./activity-status.js";import{WelcomePanel as P,WELCOME_PANEL_ROWS as S}from"./welcome-panel.js";function rt({messages:t,showActionDetails:o=!1,fill:n=!1,height:i}){return e(f,{flexDirection:"column",...n?{flexGrow:1,overflow:"hidden"}:{},...i===void 0?{}:{height:i},children:t.map(r=>e(K,{message:r,showActionDetails:o},r.id))})}function ot(t,o,n){const i=Math.max(0,Math.min(o,Math.max(0,t.length-n))),r=t.length-i,a=Math.max(0,r-n);return{messages:t.slice(a,r),firstMessage:a+1,lastMessage:r}}function it(t,o,n,i){const r=t.map(l=>R(l,i)),a=[],c=r.reduce((l,h)=>l+h,0),d=Math.max(1,Math.floor(n)),p=Math.max(0,Math.min(Math.floor(o),Math.max(0,c-d))),x=c-p,T=Math.max(0,x-d);let k=0,u=t.length,C=0;for(let l=0;l<t.length;l+=1){const h=k;a[l]=h;const w=r[l]??1;k+=w,k>T&&h<x&&(u=Math.min(u,l),C=l+1)}return u===t.length?{messages:[],firstMessage:0,lastMessage:0,totalRows:c}:{messages:t.slice(u,C).flatMap((l,h)=>{const w=u+h,b=a[w]??0,O=b+(r[w]??1),v=Math.max(T,b),y=Math.min(x,O);return y<=v?[]:[z(l,v-b,y-v,i)]}),firstMessage:u+1,lastMessage:C,totalRows:c}}function et(t,o){return t.reduce((n,i)=>n+R(i,o),0)}const A=new WeakMap;function R(t,o){let n=A.get(t);if(n!==void 0){const r=n.get(o);if(r!==void 0)return r}else n=new Map,A.set(t,n);const i=V(t,o);return n.set(o,i),i}function V(t,o){if(t.kind==="welcome")return S;if(t.kind==="status")return 2;const n=Math.max(1,o-4),i=t.content.split(`
|
|
2
|
+
`).reduce((d,p)=>d+Math.max(1,Math.ceil(D(p)/n)),0),r=(t.attachments?.length??0)*2,a=t.fileChange===void 0?0:_(t.fileChange,o),c=t.subagent===void 0?0:2;return Math.max(1,i+r+a+c+1)}function z(t,o,n,i){if(t.kind==="welcome")return o<=0&&n>=S?t:{...t,visible:!1};if(t.kind==="status"||!H(t)||o<=0&&n>=R(t,i))return t;const r=Math.max(1,i-4),a=t.content.split(`
|
|
3
|
+
`).reduce((p,x)=>p+Math.max(1,Math.ceil(D(x)/r)),0),c=Math.max(0,o),d=Math.min(a,c+Math.max(0,n));return d<=c?{...t,content:B(t.content,Math.max(0,a-1),1,r)}:{...t,content:B(t.content,c,d-c,r)}}function H(t){return t.kind==="assistant"||t.kind==="user"||t.kind==="notice"||t.kind==="error"||t.kind==="command"}function B(t,o,n,i){const r=[];for(const a of t.split(`
|
|
4
|
+
`)){const c=G(a,i);r.push(...c)}return r.slice(o,o+n).join(`
|
|
5
|
+
`)}function K({message:t,showActionDetails:o}){if(t.kind==="welcome")return t.visible===!1?null:e(P,{welcome:t.welcome});if(t.kind==="status")return e(L,{...t.status});if(t.kind==="assistant")return s(f,{flexDirection:"row",alignItems:"flex-start",marginBottom:1,children:[e(j,{}),e(f,{flexGrow:1,children:e(E,{content:t.content||" "})})]});if(t.kind==="diff"&&t.fileChange!==void 0)return e(W,{change:t.fileChange});if(t.kind==="activity"&&t.activity!==void 0)return e(I,{activity:t.activity,showDetails:o});if(t.kind==="subagent"&&t.subagent!==void 0)return e(F,{subagent:t.subagent});if(t.kind==="user")return s(f,{backgroundColor:M.user,flexDirection:"column",marginBottom:1,children:[s(f,{flexDirection:"row",alignItems:"flex-start",children:[e(j,{}),e(f,{flexGrow:1,children:e(E,{content:t.content})})]}),t.attachments?.map(r=>e(N,{attachment:r},r.id))]});const n=t.kind==="error"?M.error:t.kind==="command"?M.accent:M.muted,i=t.kind==="error"?"!":t.kind==="command"?"\u203A":"\xB7";return s(f,{marginBottom:1,children:[s(m,{color:n,children:[i," "]}),e(m,{color:n,wrap:"wrap",children:t.content})]})}function j(){return e(m,{color:M.text,children:"\u25CF "})}function N({attachment:t}){return e(f,{marginTop:1,children:s(m,{color:M.muted,children:["\u25A3 ",t.name]})})}export{N as AttachmentChip,rt as Transcript,et as transcriptTotalRows,ot as transcriptViewport,it as transcriptViewportByRows};
|
|
@@ -115,13 +115,13 @@ export declare class InkTuiBridge {
|
|
|
115
115
|
snapshot(): TuiViewState;
|
|
116
116
|
subscribe(listener: Listener): () => void;
|
|
117
117
|
setSubmitHandler(handler: (value: string) => Promise<void>): void;
|
|
118
|
-
setImagePasteHandler(handler: () => Promise<void>): void;
|
|
118
|
+
setImagePasteHandler(handler: (prompt: string) => Promise<void>): void;
|
|
119
119
|
setTextPasteHandler(handler: () => Promise<string | undefined>): void;
|
|
120
120
|
setClearAttachmentsHandler(handler: () => void): void;
|
|
121
121
|
setInterruptHandler(handler: () => void): void;
|
|
122
122
|
setCancelHandler(handler: () => void): void;
|
|
123
123
|
submit(value: string): Promise<void>;
|
|
124
|
-
pasteImage(): Promise<void>;
|
|
124
|
+
pasteImage(prompt: string): Promise<void>;
|
|
125
125
|
pasteText(): Promise<string | undefined>;
|
|
126
126
|
interrupt(): void;
|
|
127
127
|
cancel(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RESOURCE_LIMITS as c}from"../../../domain/runtime/resource-limits.js";class A{listeners=new Set;initializationNotices=new Map;state={ready:!1,runActive:!1,messages:[],subagents:[],pendingAttachments:[],fileSuggestions:[],actionDetails:!1};resolveModal;exitResolvers=new Set;submitHandler;imagePasteHandler;textPasteHandler;clearAttachmentsHandler;interruptHandler;cancelHandler;sequence=0;noticeTimer;assistantRevealTimer;pendingAssistant;assistantSegmentPending=!1;pendingActivityTimers=new Map;snapshot(){return this.state}subscribe(t){return this.listeners.add(t),()=>this.listeners.delete(t)}setSubmitHandler(t){this.submitHandler=t}setImagePasteHandler(t){this.imagePasteHandler=t}setTextPasteHandler(t){this.textPasteHandler=t}setClearAttachmentsHandler(t){this.clearAttachmentsHandler=t}setInterruptHandler(t){this.interruptHandler=t}setCancelHandler(t){this.cancelHandler=t}async submit(t){await this.submitHandler?.(t)}async pasteImage(){await this.imagePasteHandler?.()}async pasteText(){return this.textPasteHandler?.()}interrupt(){this.interruptHandler?.()}cancel(){this.cancelHandler?.(),this.resolveActiveModal(void 0),this.update({clearBlockedUntil:Date.now()+1500})}clearAttachments(){this.clearAttachmentsHandler?.()}setReady(){this.update({ready:!0})}setRunActive(t){this.update({runActive:t})}setWelcome(t){this.update({welcome:t})}setPendingAttachments(t){this.update({pendingAttachments:t})}setContextUsage(t){this.update({contextUsage:t})}setFileSuggestions(t){this.update({fileSuggestions:t})}toggleActionDetails(){const t=!this.state.actionDetails;return this.update({actionDetails:t}),t}clearTranscript(){this.initializationNotices.clear(),this.assistantRevealTimer!==void 0&&clearTimeout(this.assistantRevealTimer),this.assistantRevealTimer=void 0,this.pendingAssistant=void 0,this.update({messages:[],subagents:[]})}exitCode;requestExit(t=0){this.exitCode??=t;for(const e of this.exitResolvers)e(this.exitCode);this.exitResolvers.clear()}waitForExit(){return this.exitCode===void 0?new Promise(t=>{this.exitResolvers.add(t)}):Promise.resolve(this.exitCode)}userPrompt(t,e=[]){this.append("user",t,e)}command(t){this.append("command",t)}commandOutput(t){this.append("notice",t)}transcriptNotice(t,e=!0){this.append("notice",t,void 0,void 0,void 0,void 0,e)}initializationNotice(t,e){this.initializationNotices.get(t)!==e&&(this.initializationNotices.set(t,e),this.transcriptNotice(e))}fileChange(t){this.append("diff",t.path,void 0,t)}notice(t){this.noticeTimer!==void 0&&clearTimeout(this.noticeTimer),this.update({footerNotice:t}),this.noticeTimer=setTimeout(()=>{this.noticeTimer=void 0,this.update({footerNotice:void 0})},4e3)}dispose(){this.noticeTimer!==void 0&&clearTimeout(this.noticeTimer),this.assistantRevealTimer!==void 0&&clearTimeout(this.assistantRevealTimer);for(const t of this.pendingActivityTimers.values())clearImmediate(t);this.pendingActivityTimers.clear(),this.noticeTimer=void 0,this.assistantRevealTimer=void 0,this.resolveActiveModal(void 0),this.initializationNotices.clear(),this.listeners.clear()}error(t){this.append("error",t)}subagentLifecycle(t){const e=this.state.modal?.kind==="subagent",i=this.state.subagents.find(n=>n.id===t.id),s={id:t.id,displayName:t.displayName,task:t.task,mode:t.mode,model:t.model,status:t.status,background:t.background,createdAt:i?.createdAt??t.timestamp,updatedAt:t.timestamp,...t.durationMs===void 0?{}:{durationMs:t.durationMs},...t.summary===void 0?{}:{summary:t.summary},...t.lastAction===void 0?i?.lastAction===void 0?{}:{lastAction:i.lastAction}:{lastAction:t.lastAction},...t.handoff===void 0?i?.handoff===void 0?{}:{handoff:i.handoff}:{handoff:t.handoff}},a=i===void 0?[...this.state.subagents,s]:this.state.subagents.map(n=>n.id===t.id?s:n);this.update({subagents:a},!e),t.type==="created"&&!this.state.messages.some(n=>n.kind==="subagent"&&n.subagent?.id===t.id)&&this.append("subagent",t.id,void 0,void 0,void 0,s,!e),(t.type==="completed"||t.type==="failed"||t.type==="cancelled")&&t.summary!==void 0&&this.transcriptNotice(`Agent ${t.displayName} ${t.status} \xB7 ${t.summary}`,!e)}startToolActivity(t,e,i){const s=this.state.messages.find(n=>n.kind==="activity"&&(n.activity?.state==="pending"||n.activity?.state==="running")&&n.content===t);let a=s?.id;if(s===void 0){const n=this.message("activity",t,void 0,void 0,{label:e,state:"running",startedAt:Date.now(),...i});a=n.id,this.update({messages:[...this.state.messages,n]})}else this.clearPendingActivityTimer(t),this.updateActivity(s.id,e,"running",i);return{complete:n=>this.completeToolActivity(a,n)}}toolActivityStarted(t,e,i){const s=this.state.messages.find(d=>d.kind==="activity"&&d.content===t&&(d.activity?.state==="pending"||d.activity?.state==="running"));if(s!==void 0){this.updateActivity(s.id,e,s.activity?.state==="pending"?"pending":"running",i);return}const a=this.message("activity",t,void 0,void 0,{label:e,state:"pending",startedAt:Date.now(),...i});this.update({messages:[...this.state.messages,a]});const n=setImmediate(()=>{this.pendingActivityTimers.delete(t);const d=this.state.messages.find(u=>u.kind==="activity"&&u.content===t&&u.activity?.state==="pending");d!==void 0&&this.updateActivity(d.id,e,"running",i)});this.pendingActivityTimers.set(t,n)}toolActivityCompleted(t,e){this.clearPendingActivityTimer(t);const i=this.state.messages.find(s=>s.kind==="activity"&&s.content===t&&(s.activity?.state==="pending"||s.activity?.state==="running"));i!==void 0&&this.completeToolActivity(i.id,e)}status(t){this.update({status:t,activityStartedAt:Date.now(),elapsedMs:void 0,usage:void 0})}activity(t,e,i){this.update({status:t,...this.state.activityStartedAt===void 0?{activityStartedAt:Date.now()-e}:{},elapsedMs:e,...i===void 0?{}:{usage:i}})}clearActivity(){this.update({status:void 0,activityStartedAt:void 0,elapsedMs:void 0,usage:void 0})}complete(t,e){this.update({status:"Done",elapsedMs:t,...e===void 0?{}:{usage:e}})}failed(){this.update({status:"Failed",elapsedMs:void 0,usage:void 0})}cancelled(){this.update({status:"Cancelled",elapsedMs:void 0,usage:void 0})}beginAssistant(){this.flushAssistant(),this.assistantSegmentPending=!1,this.appendAssistant("")}assistantActionBoundary(){this.flushAssistant(),this.assistantSegmentPending=!0}assistantDelta(t){if(this.assistantSegmentPending){this.assistantSegmentPending=!1,this.appendAssistant(t);return}const e=this.state.messages.at(-1);if(e?.kind!=="assistant"){this.flushAssistant(),this.appendAssistant(t);return}const i=this.pendingAssistant;this.pendingAssistant={id:e.id,content:`${i?.id===e.id?i.content:e.content}${t}`},this.revealAssistant()}replaceAssistant(t){this.assistantRevealTimer!==void 0&&clearTimeout(this.assistantRevealTimer),this.assistantRevealTimer=void 0,this.pendingAssistant=void 0,this.assistantSegmentPending=!1;let e=-1;for(let s=this.state.messages.length-1;s>=0;s-=1)if(this.state.messages[s]?.kind==="user"){e=s;break}const i=this.state.messages.filter((s,a)=>a<=e||s.kind!=="assistant");this.update({messages:o([...i,this.message("assistant",t)])})}finishAssistant(){this.revealAssistant(),this.assistantSegmentPending=!1}confirmTrust(){return this.request({kind:"trust"}).then(t=>t===!0)}confirmTool(t,e){return this.request({kind:"approval",toolName:t,...e===void 0?{}:{detail:e}}).then(i=>i==="allow"||i===!0)}openSubagentDetails(t){if(this.state.modal!==void 0)return;const e=this.state.subagents.find(i=>i.id===t);e!==void 0&&this.update({modal:{kind:"subagent",subagent:e}})}closeSubagentDetails(){this.state.modal?.kind==="subagent"&&this.update({modal:void 0})}selectModel(t,e,i){return this.selectChoice(t,e,i)}selectScope(t){return this.selectChoice(t,[{value:"user",label:"User",description:"Available across your projects"},{value:"project",label:"Project",description:"Stored in the trusted project"}]).then(e=>e==="user"||e==="project"?e:void 0)}requestSecret(t){return this.request({kind:"secret",label:t}).then(e=>typeof e=="string"?e:void 0)}resolveActiveModal(t){const e=this.resolveModal;e!==void 0&&(this.resolveModal=void 0,this.update({modal:void 0}),e?.(t))}request(t){if(this.resolveModal!==void 0)throw new Error("A TUI decision is already active.");return this.update({modal:t}),new Promise(e=>{this.resolveModal=e})}selectChoice(t,e,i){return this.request({kind:"choice",title:t,choices:e,...i===void 0?{}:{currentValue:i}}).then(s=>typeof s=="string"?s:void 0)}append(t,e,i,s,a,n,d=!0){this.update({messages:o([...this.state.messages,this.message(t,e,i,s,a,n)])},d)}appendAssistant(t){const e=this.message("assistant","");this.update({messages:o([...this.state.messages,e])}),this.pendingAssistant={id:e.id,content:t},this.revealAssistant()}message(t,e,i,s,a,n){return{id:`tui-${++this.sequence}`,kind:t,content:e,...i===void 0||i.length===0?{}:{attachments:i},...s===void 0?{}:{fileChange:s},...a===void 0?{}:{activity:a},...n===void 0?{}:{subagent:n}}}updateActivity(t,e,i,s){const a=this.state.messages.map(n=>n.id===t&&n.activity!==void 0?{...n,content:n.content,activity:{...n.activity,label:e,state:i,...s}}:n);this.update({messages:a})}completeToolActivity(t,e){const i=this.state.messages.find(s=>s.id===t&&s.activity!==void 0);i?.activity===void 0||i.activity.state!=="pending"&&i.activity.state!=="running"||this.update({messages:this.state.messages.map(s=>s.id===t&&s.activity!==void 0?{...s,activity:{...s.activity,state:e?"failed":"completed",elapsedMs:Date.now()-s.activity.startedAt}}:s)})}clearPendingActivityTimer(t){const e=this.pendingActivityTimers.get(t);e!==void 0&&(clearImmediate(e),this.pendingActivityTimers.delete(t))}update(t,e=!0){if(this.state={...this.state,...t},!!e)for(const i of this.listeners)i()}flushAssistant(){this.assistantRevealTimer!==void 0&&(clearTimeout(this.assistantRevealTimer),this.assistantRevealTimer=void 0);const t=this.pendingAssistant;if(t===void 0)return;this.pendingAssistant=void 0;const e=this.state.messages.findIndex(a=>a.id===t.id);if(e<0)return;const i=[...this.state.messages],s=i[e];s===void 0||s.kind!=="assistant"||(i[e]={...s,content:t.content},this.update({messages:i}))}revealAssistant(){const t=this.pendingAssistant;if(t===void 0)return;const e=this.state.messages.findIndex(l=>l.id===t.id);if(e<0){this.pendingAssistant=void 0;return}const i=this.state.messages[e];if(i===void 0||i.kind!=="assistant"){this.pendingAssistant=void 0;return}const s=Array.from(t.content),a=Array.from(i.content),n=a.length===0,d=Math.min(s.length,a.length+(n?p:m)),u=d>=s.length,h=[...this.state.messages];if(h[e]={...i,content:s.slice(0,d).join("")},this.update({messages:h}),u){this.pendingAssistant=void 0,this.assistantRevealTimer!==void 0&&(clearTimeout(this.assistantRevealTimer),this.assistantRevealTimer=void 0);return}this.assistantRevealTimer===void 0&&(this.assistantRevealTimer=setTimeout(()=>{this.assistantRevealTimer=void 0,this.revealAssistant()},f))}}const f=16,p=64,m=8;function o(r){if(r.length<=c.tuiTranscriptMessages)return r;const t=r.filter(s=>s.activity?.state==="pending"||s.activity?.state==="running"||s.subagent?.status==="queued"||s.subagent?.status==="running"),e=r.slice(-c.tuiTranscriptMessages);return[...t,...e.filter(s=>!t.some(a=>a.id===s.id))].slice(-c.tuiTranscriptMessages)}export{A as InkTuiBridge};
|
|
1
|
+
import{RESOURCE_LIMITS as h}from"../../../domain/runtime/resource-limits.js";class y{listeners=new Set;initializationNotices=new Map;state={ready:!1,runActive:!1,messages:[],subagents:[],pendingAttachments:[],fileSuggestions:[],actionDetails:!1};resolveModal;exitResolvers=new Set;submitHandler;imagePasteHandler;textPasteHandler;clearAttachmentsHandler;interruptHandler;cancelHandler;sequence=0;noticeTimer;assistantRevealTimer;pendingAssistant;assistantSegmentPending=!1;pendingActivityTimers=new Map;snapshot(){return this.state}subscribe(t){return this.listeners.add(t),()=>this.listeners.delete(t)}setSubmitHandler(t){this.submitHandler=t}setImagePasteHandler(t){this.imagePasteHandler=t}setTextPasteHandler(t){this.textPasteHandler=t}setClearAttachmentsHandler(t){this.clearAttachmentsHandler=t}setInterruptHandler(t){this.interruptHandler=t}setCancelHandler(t){this.cancelHandler=t}async submit(t){await this.submitHandler?.(t)}async pasteImage(t){await this.imagePasteHandler?.(t)}async pasteText(){return this.textPasteHandler?.()}interrupt(){this.interruptHandler?.()}cancel(){this.cancelHandler?.(),this.resolveActiveModal(void 0),this.update({clearBlockedUntil:Date.now()+1500})}clearAttachments(){this.clearAttachmentsHandler?.()}setReady(){this.update({ready:!0})}setRunActive(t){this.update({runActive:t})}setWelcome(t){this.update({welcome:t})}setPendingAttachments(t){this.update({pendingAttachments:t})}setContextUsage(t){this.update({contextUsage:t})}setFileSuggestions(t){this.update({fileSuggestions:t})}toggleActionDetails(){const t=!this.state.actionDetails;return this.update({actionDetails:t}),t}clearTranscript(){this.initializationNotices.clear(),this.assistantRevealTimer!==void 0&&clearTimeout(this.assistantRevealTimer),this.assistantRevealTimer=void 0,this.pendingAssistant=void 0,this.update({messages:[],subagents:[]})}exitCode;requestExit(t=0){this.exitCode??=t;for(const e of this.exitResolvers)e(this.exitCode);this.exitResolvers.clear()}waitForExit(){return this.exitCode===void 0?new Promise(t=>{this.exitResolvers.add(t)}):Promise.resolve(this.exitCode)}userPrompt(t,e=[]){this.append("user",t,e)}command(t){this.append("command",t)}commandOutput(t){this.append("notice",t)}transcriptNotice(t,e=!0){this.append("notice",t,void 0,void 0,void 0,void 0,e)}initializationNotice(t,e){this.initializationNotices.get(t)!==e&&(this.initializationNotices.set(t,e),this.transcriptNotice(e))}fileChange(t){this.append("diff",t.path,void 0,t)}notice(t){this.noticeTimer!==void 0&&clearTimeout(this.noticeTimer),this.update({footerNotice:t}),this.noticeTimer=setTimeout(()=>{this.noticeTimer=void 0,this.update({footerNotice:void 0})},4e3)}dispose(){this.noticeTimer!==void 0&&clearTimeout(this.noticeTimer),this.assistantRevealTimer!==void 0&&clearTimeout(this.assistantRevealTimer);for(const t of this.pendingActivityTimers.values())clearImmediate(t);this.pendingActivityTimers.clear(),this.noticeTimer=void 0,this.assistantRevealTimer=void 0,this.resolveActiveModal(void 0),this.initializationNotices.clear(),this.listeners.clear()}error(t){this.append("error",t)}subagentLifecycle(t){const e=this.state.modal?.kind==="subagent",i=this.state.subagents.find(n=>n.id===t.id),s={id:t.id,displayName:t.displayName,task:t.task,mode:t.mode,model:t.model,status:t.status,background:t.background,createdAt:i?.createdAt??t.timestamp,updatedAt:t.timestamp,...t.durationMs===void 0?{}:{durationMs:t.durationMs},...t.summary===void 0?{}:{summary:t.summary},...t.lastAction===void 0?i?.lastAction===void 0?{}:{lastAction:i.lastAction}:{lastAction:t.lastAction},...t.handoff===void 0?i?.handoff===void 0?{}:{handoff:i.handoff}:{handoff:t.handoff}},a=i===void 0?[...this.state.subagents,s]:this.state.subagents.map(n=>n.id===t.id?s:n);this.update({subagents:a},!e),t.type==="created"&&!this.state.messages.some(n=>n.kind==="subagent"&&n.subagent?.id===t.id)&&this.append("subagent",t.id,void 0,void 0,void 0,s,!e),(t.type==="completed"||t.type==="failed"||t.type==="cancelled")&&t.summary!==void 0&&this.transcriptNotice(`Agent ${t.displayName} ${t.status} \xB7 ${t.summary}`,!e)}startToolActivity(t,e,i){const s=this.state.messages.find(n=>n.kind==="activity"&&(n.activity?.state==="pending"||n.activity?.state==="running")&&n.content===t);let a=s?.id;if(s===void 0){const n=this.message("activity",t,void 0,void 0,{label:e,state:"running",startedAt:Date.now(),...i});a=n.id,this.update({messages:[...this.state.messages,n]})}else this.clearPendingActivityTimer(t),this.updateActivity(s.id,e,"running",i);return{complete:n=>this.completeToolActivity(a,n)}}toolActivityStarted(t,e,i){const s=this.state.messages.find(d=>d.kind==="activity"&&d.content===t&&(d.activity?.state==="pending"||d.activity?.state==="running"));if(s!==void 0){this.updateActivity(s.id,e,s.activity?.state==="pending"?"pending":"running",i);return}const a=this.message("activity",t,void 0,void 0,{label:e,state:"pending",startedAt:Date.now(),...i});this.update({messages:[...this.state.messages,a]});const n=setImmediate(()=>{this.pendingActivityTimers.delete(t);const d=this.state.messages.find(c=>c.kind==="activity"&&c.content===t&&c.activity?.state==="pending");d!==void 0&&this.updateActivity(d.id,e,"running",i)});this.pendingActivityTimers.set(t,n)}toolActivityCompleted(t,e){this.clearPendingActivityTimer(t);const i=this.state.messages.find(s=>s.kind==="activity"&&s.content===t&&(s.activity?.state==="pending"||s.activity?.state==="running"));i!==void 0&&this.completeToolActivity(i.id,e)}status(t){this.update({status:t,activityStartedAt:Date.now(),elapsedMs:void 0,usage:void 0})}activity(t,e,i){this.update({status:t,...this.state.activityStartedAt===void 0?{activityStartedAt:Date.now()-e}:{},elapsedMs:e,...i===void 0?{}:{usage:i}})}clearActivity(){this.update({status:void 0,activityStartedAt:void 0,elapsedMs:void 0,usage:void 0})}complete(t,e){this.update({status:"Done",elapsedMs:t,...e===void 0?{}:{usage:e}})}failed(){this.update({status:"Failed",elapsedMs:void 0,usage:void 0})}cancelled(){this.update({status:"Cancelled",elapsedMs:void 0,usage:void 0})}beginAssistant(){this.flushAssistant(),this.assistantSegmentPending=!1,this.appendAssistant("")}assistantActionBoundary(){this.flushAssistant(),this.assistantSegmentPending=!0}assistantDelta(t){if(this.assistantSegmentPending){this.assistantSegmentPending=!1,this.appendAssistant(t);return}const e=this.state.messages.at(-1);if(e?.kind!=="assistant"){this.flushAssistant(),this.appendAssistant(t);return}const i=this.pendingAssistant;this.pendingAssistant={id:e.id,content:`${i?.id===e.id?i.content:e.content}${t}`},this.assistantRevealTimer===void 0&&this.revealAssistant()}replaceAssistant(t){this.assistantRevealTimer!==void 0&&clearTimeout(this.assistantRevealTimer),this.assistantRevealTimer=void 0,this.pendingAssistant=void 0,this.assistantSegmentPending=!1;let e=-1;for(let s=this.state.messages.length-1;s>=0;s-=1)if(this.state.messages[s]?.kind==="user"){e=s;break}const i=this.state.messages.filter((s,a)=>a<=e||s.kind!=="assistant");this.update({messages:l([...i,this.message("assistant",t)])})}finishAssistant(){this.revealAssistant(),this.assistantSegmentPending=!1}confirmTrust(){return this.request({kind:"trust"}).then(t=>t===!0)}confirmTool(t,e){return this.request({kind:"approval",toolName:t,...e===void 0?{}:{detail:e}}).then(i=>i==="allow"||i===!0)}openSubagentDetails(t){if(this.state.modal!==void 0)return;const e=this.state.subagents.find(i=>i.id===t);e!==void 0&&this.update({modal:{kind:"subagent",subagent:e}})}closeSubagentDetails(){this.state.modal?.kind==="subagent"&&this.update({modal:void 0})}selectModel(t,e,i){return this.selectChoice(t,e,i)}selectScope(t){return this.selectChoice(t,[{value:"user",label:"User",description:"Available across your projects"},{value:"project",label:"Project",description:"Stored in the trusted project"}]).then(e=>e==="user"||e==="project"?e:void 0)}requestSecret(t){return this.request({kind:"secret",label:t}).then(e=>typeof e=="string"?e:void 0)}resolveActiveModal(t){const e=this.resolveModal;e!==void 0&&(this.resolveModal=void 0,this.update({modal:void 0}),e?.(t))}request(t){if(this.resolveModal!==void 0)throw new Error("A TUI decision is already active.");return this.update({modal:t}),new Promise(e=>{this.resolveModal=e})}selectChoice(t,e,i){return this.request({kind:"choice",title:t,choices:e,...i===void 0?{}:{currentValue:i}}).then(s=>typeof s=="string"?s:void 0)}append(t,e,i,s,a,n,d=!0){this.update({messages:l([...this.state.messages,this.message(t,e,i,s,a,n)])},d)}appendAssistant(t){const e=this.message("assistant","");this.update({messages:l([...this.state.messages,e])}),this.pendingAssistant={id:e.id,content:t},this.revealAssistant()}message(t,e,i,s,a,n){return{id:`tui-${++this.sequence}`,kind:t,content:e,...i===void 0||i.length===0?{}:{attachments:i},...s===void 0?{}:{fileChange:s},...a===void 0?{}:{activity:a},...n===void 0?{}:{subagent:n}}}updateActivity(t,e,i,s){const a=this.state.messages.map(n=>n.id===t&&n.activity!==void 0?{...n,content:n.content,activity:{...n.activity,label:e,state:i,...s}}:n);this.update({messages:a})}completeToolActivity(t,e){const i=this.state.messages.find(s=>s.id===t&&s.activity!==void 0);i?.activity===void 0||i.activity.state!=="pending"&&i.activity.state!=="running"||this.update({messages:this.state.messages.map(s=>s.id===t&&s.activity!==void 0?{...s,activity:{...s.activity,state:e?"failed":"completed",elapsedMs:Date.now()-s.activity.startedAt}}:s)})}clearPendingActivityTimer(t){const e=this.pendingActivityTimers.get(t);e!==void 0&&(clearImmediate(e),this.pendingActivityTimers.delete(t))}update(t,e=!0){if(this.state={...this.state,...t},!!e)for(const i of this.listeners)i()}flushAssistant(){this.assistantRevealTimer!==void 0&&(clearTimeout(this.assistantRevealTimer),this.assistantRevealTimer=void 0);const t=this.pendingAssistant;if(t===void 0)return;this.pendingAssistant=void 0;const e=this.state.messages.findIndex(a=>a.id===t.id);if(e<0)return;const i=[...this.state.messages],s=i[e];s===void 0||s.kind!=="assistant"||(i[e]={...s,content:t.content},this.update({messages:i}))}revealAssistant(){const t=this.pendingAssistant;if(t===void 0)return;const e=this.state.messages.findIndex(o=>o.id===t.id);if(e<0){this.pendingAssistant=void 0;return}const i=this.state.messages[e];if(i===void 0||i.kind!=="assistant"){this.pendingAssistant=void 0;return}const s=i.content.length,a=t.content.length,n=a-s;if(n<=0){this.pendingAssistant=void 0,this.assistantRevealTimer!==void 0&&(clearTimeout(this.assistantRevealTimer),this.assistantRevealTimer=void 0);return}const m=Math.max(s===0?A:v,Math.ceil(n/4));let u=Math.min(a,s+m);if(u<a){const o=t.content.charCodeAt(u-1);o>=55296&&o<=56319&&(u+=1)}const p=u>=a,f=[...this.state.messages];if(f[e]={...i,content:t.content.slice(0,u)},this.update({messages:f}),p){this.pendingAssistant=void 0,this.assistantRevealTimer!==void 0&&(clearTimeout(this.assistantRevealTimer),this.assistantRevealTimer=void 0);return}this.assistantRevealTimer===void 0&&(this.assistantRevealTimer=setTimeout(()=>{this.assistantRevealTimer=void 0,this.revealAssistant()},g))}}const g=16,A=64,v=8;function l(r){if(r.length<=h.tuiTranscriptMessages)return r;const t=r.filter(s=>s.activity?.state==="pending"||s.activity?.state==="running"||s.subagent?.status==="queued"||s.subagent?.status==="running"),e=r.slice(-h.tuiTranscriptMessages);return[...t,...e.filter(s=>!t.some(a=>a.id===s.id))].slice(-h.tuiTranscriptMessages)}export{y as InkTuiBridge};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { CliRuntime } from '../../bootstrap/runtime-factory.js';
|
|
2
|
+
import type { CliAgentSessionStore } from '../../application/agent/agent-session-store.js';
|
|
3
|
+
import type { SubagentJobRegistry } from '../../application/orchestration/cli-subagent-service.js';
|
|
4
|
+
import type { SessionExecutionWorkspaceService, SessionExecutionWorkspace } from '../../application/workspace/session-execution-workspace.js';
|
|
5
|
+
import type { SessionMetadata } from '../../domain/session/session.js';
|
|
6
|
+
import type { GoalTurnCallbacks } from '../../application/orchestration/goal-runner.js';
|
|
7
|
+
import type { SkillManifest } from '../../domain/extensions/skill-manifest.js';
|
|
8
|
+
import type { AttachmentPayload } from '../../domain/session/attachment.js';
|
|
9
|
+
import type { HookEvent } from '../../domain/extensions/hook-manifest.js';
|
|
10
|
+
import type { PendingAttachmentStore } from '../../application/chat/pending-attachment-store.js';
|
|
11
|
+
import type { InkTuiBridge } from './ink/tui-bridge.js';
|
|
12
|
+
import type { TuiToolApprovalCoordinator } from './tui-tool-approval.js';
|
|
13
|
+
import type { TuiContextService } from './tui-context-service.js';
|
|
14
|
+
export interface TuiAgentTurnControllerHost {
|
|
15
|
+
readonly runtime: CliRuntime;
|
|
16
|
+
readonly cwd: string;
|
|
17
|
+
readonly renderer: InkTuiBridge;
|
|
18
|
+
readonly pendingAttachments: PendingAttachmentStore;
|
|
19
|
+
readonly approvals: TuiToolApprovalCoordinator;
|
|
20
|
+
readonly contextService: TuiContextService;
|
|
21
|
+
readonly agentSessionStore: CliAgentSessionStore;
|
|
22
|
+
readonly executionWorkspaces: SessionExecutionWorkspaceService;
|
|
23
|
+
getSession(): SessionMetadata | undefined;
|
|
24
|
+
getActiveModel(): string | null;
|
|
25
|
+
getActiveProfile(): string | null;
|
|
26
|
+
getExecutionWorkspace(): SessionExecutionWorkspace;
|
|
27
|
+
setExecutionWorkspace(workspace: SessionExecutionWorkspace): void;
|
|
28
|
+
getSubagentJobs(): SubagentJobRegistry;
|
|
29
|
+
runHookEvent(event: HookEvent, sessionId: string): Promise<void>;
|
|
30
|
+
refreshContextUsage(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/** Owns interactive turn state and keeps prompt execution out of the TUI shell. */
|
|
33
|
+
export declare class TuiAgentTurnController {
|
|
34
|
+
private readonly host;
|
|
35
|
+
private activeAbortController;
|
|
36
|
+
private activePromptRun;
|
|
37
|
+
constructor(host: TuiAgentTurnControllerHost);
|
|
38
|
+
isRunning(): boolean;
|
|
39
|
+
getActiveAbortController(): AbortController | undefined;
|
|
40
|
+
setActiveAbortController(controller: AbortController | undefined): void;
|
|
41
|
+
abortActive(reason?: unknown): void;
|
|
42
|
+
runPrompt(prompt: string, initialSkill?: SkillManifest, goalCallbacks?: GoalTurnCallbacks): Promise<string>;
|
|
43
|
+
sendPrompt(prompt: string, attachments?: readonly AttachmentPayload[], initialSkill?: SkillManifest, goalCallbacks?: GoalTurnCallbacks): Promise<string>;
|
|
44
|
+
private executePrompt;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{AuthenticationService as O}from"../../application/auth/authentication-service.js";import{loadExecutionConfig as H}from"../../application/config/execution-config.js";import{CliError as q,asCliError as y}from"../../domain/errors/cli-error.js";import{CLI_ERROR_CODES as P}from"../../domain/errors/error-codes.js";import{buildUserMessage as B}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{createTurnId as Y,recordTurnCompletion as z,recordTurnFailure as K,recordTurnStart as Q}from"../../application/session/session-turn-lifecycle.js";import{createTuiContextManagement as X,createTuiContinuationContext as Z}from"./tui-context-compaction.js";import{isAbortError as ee,throwIfAborted as x}from"./tui-lifecycle-actions.js";import{runTuiAgentEvents as te}from"./tui-agent-event-runner.js";import{AUTH_LOGIN_HINT as oe,MODEL_SELECT_HINT as se,formatCliErrorMessage as M,formatCommandHint as I}from"../../application/commands/command-hints.js";class Ae{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=y(A);return this.host.renderer.error(M(w,"tui")),""}const c=this.host.getSession(),h=c===void 0?void 0:await this.host.executionWorkspaces.acquireTurn(c.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 c=await H(this.host.runtime,this.host.cwd),h=this.host.getActiveModel()??c.config.model;if(h===null)return this.host.renderer.error(`No model is selected. ${I(se,"tui")}`),"";const m=this.host.getActiveProfile()??c.config.profile??O.defaultProfileName(),A=await this.host.runtime.credentialStore.get(m);if(A===void 0)return this.host.renderer.error(`No API key is configured. ${I(oe,"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=Y();t!==void 0&&await Q(this.host.runtime.sessionStore,t.id,C,s,n.map(({attachment:e})=>e.id));const S=Date.now();let p,v=!1;this.host.renderer.status("Thinking");const f=new AbortController;this.activeAbortController=f;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&&(p=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:c.config.effort,client:T,profile:U?"interactive-trusted":"interactive-untrusted",approvalMode:c.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:X(T,h,W,e=>this.host.runtime.logger.warn("Context summarization failed; using fallback summary.",{reason:e instanceof Error?e.message:String(e)}),()=>Z(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}}}}),u=[];let b=!1;const D=e=>{x(f.signal),u.push(e),this.host.renderer.assistantDelta(e)},F=e=>{x(f.signal),u.splice(0,u.length,e),this.host.renderer.replaceAssistant(e)};try{x(f.signal);const e=await E.buildInput(s);this.host.pendingAttachments.assertPromptFits(e.input,n);const a=n.length===0?void 0:B(e.input,n),r=a?.content===null?void 0:a?.content;if(await te({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:f.signal,agentSessionStore:this.host.agentSessionStore,tracker:i,runtime:this.host.runtime,renderer:this.host.renderer,startedAt:S,getUsage:()=>p,appendAssistantDelta:D,replaceAssistantResponse:F,hasResponse:()=>u.length>0}),u.join("").trim().length===0){const l=i.snapshot();l.toolCalls>0&&i.markStuck();const j=l.toolCalls>0?P.MODEL_EMPTY_FINAL:P.MODEL_PROTOCOL_EMPTY_RESPONSE,R=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 q(j,R,{category:"model",userMessage:`${R} 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),b=!0),d?.onSnapshot(i.snapshot())}catch(e){const a=f.signal.aborted||ee(e);if(t!==void 0&&!b)try{const r=await this.host.executionWorkspaces.apply(t.id);b=!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 K(this.host.runtime.sessionStore,t.id,C,e,a),this.host.renderer.finishAssistant(),a)this.host.renderer.notice("Interrupted.");else{const r=y(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===f&&(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 z(this.host.runtime.sessionStore,t.id,C,u.join(""))}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&&p!==void 0&&d?.onUsage({usage:p,modelCalls:1});const k=p?.totalTokens===void 0?$({model:h,prompt:s,response:u.join("")}):p;return!v&&p===void 0&&k!==void 0&&d?.onUsage({usage:k,modelCalls:1}),this.host.renderer.complete(Date.now()-S,k),await this.host.refreshContextUsage(),u.join("")}}export{Ae as TuiAgentTurnController};
|
|
@@ -21,8 +21,6 @@ export declare class TuiApplication {
|
|
|
21
21
|
private skillRootScopes;
|
|
22
22
|
private enabledPluginNames;
|
|
23
23
|
private pluginMcpConfig;
|
|
24
|
-
private activeAbortController;
|
|
25
|
-
private activePromptRun;
|
|
26
24
|
private activeForegroundRun;
|
|
27
25
|
private exitArmedUntil;
|
|
28
26
|
private lastInterruptAt;
|
|
@@ -35,6 +33,7 @@ export declare class TuiApplication {
|
|
|
35
33
|
private subagentJobs;
|
|
36
34
|
private readonly executionWorkspaces;
|
|
37
35
|
private executionWorkspace;
|
|
36
|
+
private readonly turnController;
|
|
38
37
|
constructor(runtime: CliRuntime, cwd: string, options?: TuiApplicationOptions);
|
|
39
38
|
run(): Promise<number>;
|
|
40
39
|
private processPrompt;
|
|
@@ -42,8 +41,6 @@ export declare class TuiApplication {
|
|
|
42
41
|
runPrompt(prompt: string, initialSkill?: SkillManifest, goalCallbacks?: GoalTurnCallbacks): Promise<string>;
|
|
43
42
|
runGoal(objective: string, context: TuiCommandContext, limits?: Omit<CreateGoalInput, 'objective'>): Promise<void>;
|
|
44
43
|
resumeGoal(context: TuiCommandContext): Promise<void>;
|
|
45
|
-
private sendPrompt;
|
|
46
|
-
private executePrompt;
|
|
47
44
|
private commandContext;
|
|
48
45
|
getActiveModel(): string | null;
|
|
49
46
|
getActiveProfile(): string | null;
|