@cryer/star-cli 0.3.11 → 0.3.13
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/dist/chunk-4IRY44TG.js +0 -0
- package/dist/{chunk-LSYGHLRU.js → chunk-6PLZ3FLG.js} +106 -63
- package/dist/chunk-6PLZ3FLG.js.map +1 -0
- package/dist/chunk-MVAMPVTA.js +0 -0
- package/dist/{chunk-GYXF6NPC.js → chunk-NMB3TNQU.js} +15 -5
- package/dist/chunk-NMB3TNQU.js.map +1 -0
- package/dist/{chunk-Q5FJN4LN.js → chunk-OF42OVM4.js} +11 -2
- package/dist/chunk-OF42OVM4.js.map +1 -0
- package/dist/{chunk-63CGUF3F.js → chunk-QELCMXQX.js} +98 -16
- package/dist/chunk-QELCMXQX.js.map +1 -0
- package/dist/{chunk-N4MIQSNZ.js → chunk-RD4S5LKM.js} +6 -5
- package/dist/chunk-RD4S5LKM.js.map +1 -0
- package/dist/{loop-AY4PXRVP.js → loop-DWQ5WTPD.js} +5 -5
- package/dist/main.js +6 -6
- package/dist/main.js.map +1 -1
- package/dist/provider-EWMUPBLH.js +0 -0
- package/dist/{repl-YBNTJOSB.js → repl-ZABBT33D.js} +44 -15
- package/dist/repl-ZABBT33D.js.map +1 -0
- package/dist/{tools-BH55BVIS.js → tools-4OLADVDR.js} +3 -3
- package/package.json +16 -25
- package/dist/chunk-63CGUF3F.js.map +0 -1
- package/dist/chunk-GYXF6NPC.js.map +0 -1
- package/dist/chunk-LSYGHLRU.js.map +0 -1
- package/dist/chunk-N4MIQSNZ.js.map +0 -1
- package/dist/chunk-Q5FJN4LN.js.map +0 -1
- package/dist/repl-YBNTJOSB.js.map +0 -1
- /package/dist/{loop-AY4PXRVP.js.map → loop-DWQ5WTPD.js.map} +0 -0
- /package/dist/{tools-BH55BVIS.js.map → tools-4OLADVDR.js.map} +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
gitTreesDir,
|
|
4
4
|
isSensitivePath
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-6PLZ3FLG.js";
|
|
6
6
|
|
|
7
7
|
// src/core/messages.ts
|
|
8
8
|
function toStarMessage(message) {
|
|
@@ -181,9 +181,10 @@ var ConfigSchema = z.object({
|
|
|
181
181
|
// retries and auto-continue nudges do not consume steps. Reaching the cap
|
|
182
182
|
// while tools still execute resets the budget with a notice; the turn stops
|
|
183
183
|
// only when no tool ran since the last checkpoint (the doom-loop
|
|
184
|
-
// signature). 0 disables the cap entirely
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
// signature). 0 disables the cap entirely and is the default
|
|
185
|
+
// (opencode/codex have none).
|
|
186
|
+
maxSteps: z.number().int().min(0).default(0),
|
|
187
|
+
contextMaxTokens: z.number().int().positive().default(2e5),
|
|
187
188
|
// Token threshold at which the agent loop auto-compacts the history.
|
|
188
189
|
// Defaults to the effective context window (compact only when full); set a
|
|
189
190
|
// lower value to compact earlier and keep headroom. Manual /compact ignores
|
|
@@ -501,4 +502,4 @@ export {
|
|
|
501
502
|
restoreTree,
|
|
502
503
|
diffTreeNames
|
|
503
504
|
};
|
|
504
|
-
//# sourceMappingURL=chunk-
|
|
505
|
+
//# sourceMappingURL=chunk-RD4S5LKM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/messages.ts","../src/config/schema.ts","../src/snapshot/git-tree.ts"],"sourcesContent":["import type { CoreMessage, ToolCallPart } from \"ai\";\n\nexport type { CoreMessage };\n\n// Side-band metadata the model never sees. It rides next to a persisted\n// message (the __starMeta jsonl key) so turn-boundary scans can tell a real\n// user turn from a loop-injected user message:\n// - \"nudge\": auto-continue / resume-after-cutoff steering injected mid-turn\n// - \"bg-report\": a finished background subagent's report, delivered mid-turn\n// - \"tool-image\": images a tool (read_image/screenshot) attached mid-turn\n// - \"steer\": a user prompt injected into the running turn (chosen at submit\n// time over queueing), delivered at the next step boundary\nexport interface MessageMeta {\n synthetic?: \"nudge\" | \"bg-report\" | \"tool-image\" | \"steer\";\n // Set by context/elision.ts when the message's bulky content (a stale tool\n // result, an old attached image) was replaced with a placeholder to free\n // the window — idempotency marker and debugging aid; the model never sees it.\n elided?: boolean;\n}\n\nexport interface StarMessage {\n message: CoreMessage;\n meta?: MessageMeta;\n}\n\nexport function toStarMessage(message: CoreMessage | StarMessage): StarMessage {\n return \"role\" in message ? { message } : message;\n}\n\nexport function toCoreMessages(messages: readonly StarMessage[]): CoreMessage[] {\n return messages.map((star) => star.message);\n}\n\n// A synthetic user message belongs to the turn that precedes it: it is never\n// a turn boundary for /undo, /rewind or compaction turn splitting.\nexport function isSyntheticUserMessage(star: StarMessage): boolean {\n return star.message.role === \"user\" && star.meta?.synthetic !== undefined;\n}\n\n// Plain-text content of a message: string content as-is; for array content,\n// the text parts joined with a space (tool calls, images and tool results\n// contribute nothing). Shared by the agent loop (/redo labels) and the CLI\n// (history rendering, conversation copy) so the extraction rule lives once.\nexport function coreMessageText(message: CoreMessage | undefined): string {\n if (!message) return \"\";\n const content = message.content;\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .filter((part) => part.type === \"text\")\n .map((part) => (\"text\" in part ? part.text : \"\"))\n .join(\" \");\n }\n return \"\";\n}\n\nexport interface ImageInput {\n path: string;\n mimeType: string;\n /** Base64-encoded image bytes. */\n data: string;\n}\n\nexport interface MultimodalInput {\n text: string;\n images: ImageInput[];\n}\n\nexport type ChatInput = string | MultimodalInput;\n\nexport interface ConversationState {\n messages: CoreMessage[];\n}\n\n// A tool call that has no real execution result must still be closed with a\n// synthetic tool message, or the stored history can no longer be sent to the\n// API. Three scenarios, three wordings:\n// - MISSING_TOOL_RESULT_TEXT: reconcileToolCalls/reconcileStarMessages repair\n// a persisted history whose session ended before the results were written\n// (crash, kill, older version) — the call may never have run at all.\n// - INTERRUPTED_TOOL_RESULT_TEXT: the user pressed Esc while the call was\n// still streaming in or executing (agent loop abort paths).\n// - UNFINISHED_TOOL_RESULT_TEXT: execution stopped for any other reason\n// (e.g. an error mid-batch) before the call produced a result.\nexport const MISSING_TOOL_RESULT_TEXT = \"tool result missing (session was interrupted)\";\nexport const INTERRUPTED_TOOL_RESULT_TEXT = \"Tool execution interrupted by user.\";\nexport const UNFINISHED_TOOL_RESULT_TEXT =\n \"Tool execution interrupted before a result was produced.\";\n\nexport function reconcileToolCalls(messages: CoreMessage[]): CoreMessage[] {\n const result: CoreMessage[] = [];\n let pending: { toolCallId: string; toolName: string }[] = [];\n // Non-tool messages that arrived while a tool-call batch was still open\n // (e.g. tool-attached image messages persisted by a version that\n // interleaved them between sibling tool results) are held back and emitted\n // once the batch closes: strict providers reject a user message sitting\n // inside the tool-result block (\"an assistant message with 'tool_calls'\n // must be followed by tool messages\"), and flushing synthetic fillers at\n // that point would also duplicate the real results that follow.\n let deferred: CoreMessage[] = [];\n\n const flushPending = () => {\n for (const call of pending) {\n result.push({\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n toolName: call.toolName,\n result: MISSING_TOOL_RESULT_TEXT,\n },\n ],\n });\n }\n pending = [];\n result.push(...deferred);\n deferred = [];\n };\n\n for (const message of messages) {\n if (message.role === \"assistant\" && Array.isArray(message.content)) {\n flushPending();\n pending = message.content\n .filter((part): part is ToolCallPart => part.type === \"tool-call\")\n .map((part) => ({ toolCallId: part.toolCallId, toolName: part.toolName }));\n result.push(message);\n } else if (message.role === \"tool\" && Array.isArray(message.content) && pending.length > 0) {\n const answered = new Set(message.content.map((part) => part.toolCallId));\n pending = pending.filter((call) => !answered.has(call.toolCallId));\n result.push(message);\n if (pending.length === 0) {\n result.push(...deferred);\n deferred = [];\n }\n } else if (pending.length > 0) {\n deferred.push(message);\n } else {\n result.push(message);\n }\n }\n flushPending();\n return result;\n}\n\n// StarMessage counterpart of reconcileToolCalls: same repair, preserving the\n// side-band meta of every surviving message. Synthetic filler results carry\n// no meta.\nexport function reconcileStarMessages(messages: readonly StarMessage[]): StarMessage[] {\n const result: StarMessage[] = [];\n let pending: { toolCallId: string; toolName: string }[] = [];\n let deferred: StarMessage[] = [];\n\n const flushPending = () => {\n for (const call of pending) {\n result.push({\n message: {\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n toolName: call.toolName,\n result: MISSING_TOOL_RESULT_TEXT,\n },\n ],\n },\n });\n }\n pending = [];\n result.push(...deferred);\n deferred = [];\n };\n\n for (const star of messages) {\n const message = star.message;\n if (message.role === \"assistant\" && Array.isArray(message.content)) {\n flushPending();\n pending = message.content\n .filter((part): part is ToolCallPart => part.type === \"tool-call\")\n .map((part) => ({ toolCallId: part.toolCallId, toolName: part.toolName }));\n result.push(star);\n } else if (message.role === \"tool\" && Array.isArray(message.content) && pending.length > 0) {\n const answered = new Set(message.content.map((part) => part.toolCallId));\n pending = pending.filter((call) => !answered.has(call.toolCallId));\n result.push(star);\n if (pending.length === 0) {\n result.push(...deferred);\n deferred = [];\n }\n } else if (pending.length > 0) {\n deferred.push(star);\n } else {\n result.push(star);\n }\n }\n flushPending();\n return result;\n}\n\n// Removes the last conversation turn: the final user message and everything\n// after it (assistant text, tool calls and results belonging to that turn).\n// Synthetic user messages (auto-continue nudges, background reports, tool\n// images) belong to the turn they sit in, so the scan skips them and the\n// boundary lands on the real user message that opened the turn. A leading\n// system message is never touched. Returns the trimmed list and how many\n// messages were dropped (0 = nothing to retract).\nexport function retractLastTurn(messages: StarMessage[]): {\n messages: StarMessage[];\n removed: number;\n} {\n for (let i = messages.length - 1; i >= 0; i--) {\n const star = messages[i];\n if (star && star.message.role === \"user\" && !isSyntheticUserMessage(star)) {\n return { messages: messages.slice(0, i), removed: messages.length - i };\n }\n }\n return { messages, removed: 0 };\n}\n","import { z } from \"zod\";\n\nexport const ProviderConfigSchema = z.object({\n name: z.string(),\n // openai-responses talks to the Responses API (/responses) instead of chat\n // completions — the wire format codex uses, and the native API of\n // reasoning-model relays that otherwise hide reasoning behind empty chat\n // completions. streamChat sends strictSchemas:false + store:false with it.\n protocol: z\n .enum([\"openai-compatible\", \"anthropic\", \"openai-responses\"])\n .default(\"openai-compatible\"),\n baseURL: z.string(),\n apiKeyEnv: z.string().optional(),\n apiKey: z.string().optional(),\n headers: z.record(z.string()).optional(),\n});\n\nexport const ModelConfigSchema = z.object({\n name: z.string(),\n provider: z.string(),\n model: z.string(),\n maxTokens: z.number().int().positive().optional(),\n // Per-model context window; overrides the top-level contextMaxTokens for\n // compaction and the status bar when set.\n contextMaxTokens: z.number().int().positive().optional(),\n // Reasoning intensity for thinking models, forwarded verbatim as\n // OpenAI-style reasoning_effort on every request (llm/provider.ts\n // reasoningEffortMetadata) — level naming varies by model/provider\n // (low|medium|high are common; some add minimal/max/xhigh/none), so any\n // non-empty string is accepted and the server validates it. Unset = the\n // request carries no effort field and the server-side default applies.\n // Anthropic maps effort to a thinking budget instead — ignored there.\n reasoningEffort: z.string().min(1).optional(),\n // Sampling temperature forwarded on every request. Unset = the AI SDK's\n // own default applies (ai@4 sends 0 — it does NOT omit the field). Some\n // endpoints reject anything but one explicit value (e.g. kimi-for-coding:\n // \"invalid temperature: only 1 is allowed\") — set it here. No upper\n // bound: ranges vary by provider and the server validates.\n temperature: z.number().min(0).optional(),\n // Per-model overrides of the top-level stream watchdog timeouts (unset =\n // the global values apply). Raise streamIdleTimeoutSec for relays that\n // buffer long generations and stall mid-stream between flushes.\n streamIdleTimeoutSec: z.number().positive().optional(),\n streamFirstChunkTimeoutSec: z.number().positive().optional(),\n // Text-only models: set false so image-producing tools (read_image,\n // screenshot) decline with a text error instead of attaching images the\n // endpoint would reject with an unrecoverable 4xx. Unset = images allowed.\n vision: z.boolean().optional(),\n // Cost estimation needs BOTH prices (USD per 1M tokens); with only one set\n // the model is treated as unpriced.\n promptPrice: z.number().nonnegative().optional(),\n completionPrice: z.number().nonnegative().optional(),\n // Optional price (USD per 1M tokens) for cache-read prompt tokens. When\n // unset, OpenAI-style cached tokens bill at promptPrice and Anthropic-style\n // cache reads are not billed — set this for accurate cache pricing.\n cacheReadPrice: z.number().nonnegative().optional(),\n});\n\nexport const PermissionsConfigSchema = z.object({\n allow: z.array(z.string()).default([]),\n deny: z.array(z.string()).default([]),\n // Rules that force a confirmation prompt in auto mode (same tool(glob)\n // syntax as allow/deny) — e.g. ask = [\"bash(git push *)\"]. Priority:\n // deny > ask > allow > mode default. Only meaningful in auto mode (ask\n // mode already prompts; readonly/plan are unaffected; yolo bypasses all).\n ask: z.array(z.string()).default([]),\n // Extra likely-secret file globs extending core/sensitive.ts's hardcoded\n // list (same single-* glob semantics as rules, matched case-insensitively\n // against the basename and the full normalized path). Global config only —\n // the project-config sandbox drops the whole [permissions] table.\n sensitive: z.array(z.string()).default([]),\n});\n\nexport const HookConfigSchema = z.object({\n event: z.enum([\"PreToolUse\", \"PostToolUse\", \"Stop\"]),\n matcher: z\n .string()\n .refine(\n (pattern) => {\n try {\n new RegExp(pattern);\n return true;\n } catch {\n return false;\n }\n },\n { message: \"invalid regular expression\" },\n )\n .optional(),\n command: z.string().min(1),\n timeoutSec: z.number().positive().default(30),\n});\n\nexport const ConfigSchema = z.object({\n defaultModel: z.string().default(\"\"),\n // Optional [[models]] name for cheap auxiliary LLM calls (compaction\n // summaries, session titles, turn completion checks) — Claude Code routes\n // these to a Haiku-class model. Unset = the active main model does them.\n smallModel: z.string().optional(),\n permissionMode: z.enum([\"auto\", \"ask\", \"readonly\", \"yolo\", \"plan\"]).default(\"ask\"),\n providers: z.array(ProviderConfigSchema).default([]),\n models: z.array(ModelConfigSchema).default([]),\n // Cap on model round-trips (\"steps\") per turn between progress checkpoints.\n // One step is a streamed reply plus every tool call it asked for — stream\n // retries and auto-continue nudges do not consume steps. Reaching the cap\n // while tools still execute resets the budget with a notice; the turn stops\n // only when no tool ran since the last checkpoint (the doom-loop\n // signature). 0 disables the cap entirely and is the default\n // (opencode/codex have none).\n maxSteps: z.number().int().min(0).default(0),\n contextMaxTokens: z.number().int().positive().default(200_000),\n // Token threshold at which the agent loop auto-compacts the history.\n // Defaults to the effective context window (compact only when full); set a\n // lower value to compact earlier and keep headroom. Manual /compact ignores\n // this — it always compacts.\n compactThresholdTokens: z.number().int().positive().optional(),\n // Seconds without any stream part before a stalled response is ended\n // gracefully (some relays never send the terminal chunks). Applies once\n // content has started streaming; the wait for the first content part gets\n // a longer allowance (control/metadata and reasoning parts don't count as\n // content).\n streamIdleTimeoutSec: z.number().positive().default(60),\n // Seconds to wait for the very first content part before giving up; slow\n // thinking-model endpoints can stay silent for minutes after accepting\n // the request.\n streamFirstChunkTimeoutSec: z.number().positive().default(300),\n // Extra attempts per model request when a stream fails transiently\n // (network error, 429/5xx, idle watchdog cutoff) or comes back empty, so a\n // relay hiccup does not silently end a half-finished turn. 0 disables.\n // The wait between attempts honors Retry-After headers and otherwise backs\n // off exponentially with jitter (llm/retry.ts); retries after a\n // timeout/empty failure also scale both stream timeouts up (attempt number\n // ×, capped at 3x) since the relay is likely overloaded. Default 5 matches\n // opencode/Codex retry budgets and rides out flaky relays (中转站) better\n // than a minimal budget.\n streamMaxRetries: z.number().int().min(0).default(5),\n // How many consecutive unproductive replies may be nudged before the turn\n // is handed back: a text-only reply that announces pending work (\"我将…\",\n // \"I will…\") or answers a nudge with more words, or an empty reply that\n // survived the stream retry budget (steered with a nudge — a changed\n // request — since identical resends already failed). Tool calls reset the\n // count, so a productive task keeps going; exhaustion surfaces a notice\n // instead of stopping silently. Never fires in plan mode. 0 disables.\n maxAutoContinues: z.number().int().min(0).default(2),\n contextCompaction: z.enum([\"summary\", \"truncate\"]).default(\"summary\"),\n // Optional per-session dollar budget; when set, the REPL stops the session\n // once the estimated cost for the session reaches this amount.\n sessionBudgetUsd: z.number().positive().optional(),\n // Terminal bell (REPL only): ring when a turn takes longer than\n // notifyBellThresholdSec, and when a background task finishes.\n // STAR_NO_NOTIFY=1 disables without touching the config.\n notifyBell: z.boolean().default(true),\n notifyBellThresholdSec: z.number().positive().default(10),\n permissions: PermissionsConfigSchema.default({ allow: [], deny: [] }),\n hooks: z.array(HookConfigSchema).default([]),\n // Consecutive identical tool calls (same tool + same arguments) allowed\n // before the loop refuses to execute the repeat and tells the model to\n // change approach — a guard against agents stuck retrying a failing call\n // (opencode's doom_loop). 0 disables.\n doomLoopThreshold: z.number().int().min(0).default(3),\n // Track the whole working tree with an internal git repo (outside the\n // user's .git) at every turn boundary, so /undo and /redo can restore\n // changes made by ANY tool (bash included), not just write_file/edit_file.\n // Falls back silently to per-file snapshots when git is unavailable.\n gitSnapshots: z.boolean().default(true),\n // web_fetch SSRF guard escape hatch: by default target hosts are resolved\n // before connecting and private/reserved ranges are refused (loopback,\n // RFC1918, link-local incl. the cloud metadata address 169.254.169.254,\n // ULA, and localhost/.local/.internal names; redirect hops re-checked).\n // true disables the guard for intranet use. Global config only — not in\n // the project-config sandbox whitelist.\n webFetchAllowPrivateHosts: z.boolean().default(false),\n});\n\nexport type ProviderConfig = z.infer<typeof ProviderConfigSchema>;\nexport type ModelConfig = z.infer<typeof ModelConfigSchema>;\nexport type PermissionsConfig = z.infer<typeof PermissionsConfigSchema>;\nexport type HookConfig = z.infer<typeof HookConfigSchema>;\nexport type StarConfig = z.infer<typeof ConfigSchema>;\n\n// Effective context window for a model: its own contextMaxTokens when set,\n// otherwise the top-level config.contextMaxTokens.\nexport function contextWindowTokens(config: StarConfig, modelName: string): number {\n return (\n config.models.find((m) => m.name === modelName)?.contextMaxTokens ?? config.contextMaxTokens\n );\n}\n\n// Token threshold that triggers automatic compaction in the agent loop:\n// config.compactThresholdTokens when set, clamped to the window so a stale\n// value (e.g. after switching to a smaller model) never pushes compaction\n// past it; otherwise the window itself (current behavior).\nexport function resolveCompactThreshold(config: StarConfig, windowTokens: number): number {\n return Math.min(config.compactThresholdTokens ?? windowTokens, windowTokens);\n}\n\nexport interface CliOverrides {\n model?: string;\n permissionMode?: \"auto\" | \"ask\" | \"readonly\" | \"yolo\" | \"plan\";\n}\n","import { execFile } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readdir, rm, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { gitTreesDir } from \"../config/paths\";\nimport { isSensitivePath } from \"../core/sensitive\";\n\nconst GIT_TIMEOUT_MS = 10_000;\n// gc repacks the object store and legitimately takes longer than the budget\n// every other git invocation gets; it runs rarely, so it can afford to wait.\nconst GC_TIMEOUT_MS = 60_000;\nconst GIT_MAX_BUFFER = 8 * 1024 * 1024;\n// `git gc --auto` runs after this many successful tree captures per repo\n// (each capture adds a tree plus blobs, and nothing else ever prunes them).\nconst GC_INTERVAL = 50;\n// The agent loop calls trackTree at the start of every turn; without a\n// negative cache a directory whose tracking fails (huge tree hitting the git\n// timeout, unreadable repo) would burn that timeout on every single turn.\nconst TRACK_FAILURE_TTL_MS = 5 * 60 * 1000;\n// Every captured tree is pinned under refs/star/<timestamp>-<random> so a\n// `gc --auto` prune (default gc.pruneExpire of two weeks) can never drop a\n// live /undo target. The namespace is trimmed to the newest this many refs,\n// matching the per-file snapshot stack cap.\nconst MAX_PINNED_REFS = 50;\nconst PINNED_REF_PREFIX = \"refs/star/\";\n\n// Likely-secret files that must never enter the internal snapshot repos,\n// pinned into each repo's info/exclude so `git add -A` skips them even in\n// projects with no .gitignore and `git clean -fd` on restore leaves them\n// alone. Mirrors isSensitivePath (src/core/sensitive.ts), including the\n// template exemptions.\nconst SENSITIVE_EXCLUDE_PATTERNS = [\n \".env\",\n \".env.*\",\n \"!.env.example\",\n \"!.env.sample\",\n \"!.env.template\",\n \"id_rsa\",\n \"id_dsa\",\n \"id_ecdsa\",\n \"id_ed25519\",\n \".npmrc\",\n \".netrc\",\n \".pgpass\",\n \"*.pem\",\n \"*.key\",\n \"*.p12\",\n \"*.pfx\",\n \"**/.aws/credentials\",\n \"**/.kube/config\",\n];\n\n// Forced config for every invocation: no CRLF translation (a file captured\n// with LF endings must restore byte-identically even on a machine whose\n// global config sets core.autocrlf=true) and no LFS filters rewriting blob\n// contents. Command-line -c beats repo/global/system config, so repos\n// created before this fix are covered too.\nconst GIT_CONFIG_ARGS = [\n \"-c\",\n \"core.autocrlf=false\",\n \"-c\",\n \"core.eol=native\",\n \"-c\",\n \"filter.lfs.process=\",\n \"-c\",\n \"filter.lfs.smudge=\",\n \"-c\",\n \"filter.lfs.clean=\",\n];\n\n// The child gets the parent environment minus every GIT_* variable (matched\n// case-insensitively: Windows env keys are). A star launched from a git hook\n// or rebase inherits GIT_DIR/GIT_INDEX_FILE pointing at the user's repo, and\n// GIT_INDEX_FILE redirects index writes even past an explicit --git-dir.\nfunction gitEnv(): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = {};\n for (const [key, value] of Object.entries(process.env)) {\n if (value !== undefined && !key.toUpperCase().startsWith(\"GIT_\")) env[key] = value;\n }\n return env;\n}\n\n// Every git invocation goes through here: array arguments (never a shell), a\n// per-call timeout, and any failure — git missing, repo corrupt, timeout —\n// resolves null so the snapshot feature degrades silently instead of breaking\n// the agent loop.\nfunction runGit(args: string[], timeoutMs = GIT_TIMEOUT_MS): Promise<string | null> {\n return new Promise((resolve) => {\n execFile(\n \"git\",\n [...GIT_CONFIG_ARGS, ...args],\n { timeout: timeoutMs, maxBuffer: GIT_MAX_BUFFER, encoding: \"utf8\", env: gitEnv() },\n (error, stdout) => {\n resolve(error ? null : stdout.trim());\n },\n );\n });\n}\n\nlet gitAvailable: boolean | null = null;\n\n// Expiry timestamps (Date.now) of the per-directory failure negative cache.\nconst trackFailureUntil = new Map<string, number>();\n// Successful captures per repo since process start, driving the periodic gc.\nconst trackCounts = new Map<string, number>();\n// Repos whose index was already scrubbed of excluded entries this process.\nconst scrubbedRepos = new Set<string>();\n\nexport async function isGitAvailable(): Promise<boolean> {\n if (gitAvailable === null) {\n gitAvailable = (await runGit([\"--version\"])) !== null;\n }\n return gitAvailable;\n}\n\n// Test hook: drop the cached availability probe so a mocked execFile takes\n// effect without reloading the module.\nexport function resetGitTreeAvailability(): void {\n gitAvailable = null;\n}\n\n// Test hook: drop every piece of cached state (availability probe, failure\n// negative cache, gc counters, scrub bookkeeping, capture chains).\nexport function resetGitTreeCaches(): void {\n gitAvailable = null;\n trackFailureUntil.clear();\n trackCounts.clear();\n scrubbedRepos.clear();\n trackChains.clear();\n}\n\n// One internal bare repo per project directory, named by the resolved path so\n// two directories never share a tree store.\nexport function treeRepoDir(cwd: string): string {\n const key = Buffer.from(path.resolve(cwd), \"utf8\").toString(\"base64url\");\n return path.join(gitTreesDir(), key);\n}\n\n// Removes a project's internal snapshot repo. Called when the project's last\n// session is cleared: the captured trees only make sense as /undo//redo\n// targets for session turns, and with no session left they are unreachable\n// disk usage. In-memory bookkeeping goes too, or a later session in the same\n// process would trust a failure cache / gc counter for a repo that no longer\n// exists.\nexport async function removeTreeRepo(cwd: string): Promise<void> {\n const dir = treeRepoDir(cwd);\n trackFailureUntil.delete(path.resolve(cwd));\n trackCounts.delete(dir);\n scrubbedRepos.delete(dir);\n await rm(dir, { recursive: true, force: true }).catch(() => {});\n}\n\n// Deletes every tree repo whose owning project has no surviving session.\n// remainingCwds are the cwd values of the sessions still on disk; repos are\n// keyed by resolved path (see treeRepoDir), so a basename compare keeps\n// exactly those.\nexport async function pruneTreeReposExcept(remainingCwds: Iterable<string>): Promise<void> {\n let entries: string[];\n try {\n entries = await readdir(gitTreesDir());\n } catch {\n return;\n }\n const keep = new Set<string>();\n for (const cwd of remainingCwds) keep.add(path.basename(treeRepoDir(cwd)));\n await Promise.all(\n entries\n .filter((entry) => !keep.has(entry))\n .map((entry) =>\n rm(path.join(gitTreesDir(), entry), { recursive: true, force: true }).catch(() => {}),\n ),\n );\n}\n\n// Snapshotting the home directory or a filesystem root would track an entire\n// machine — refuse rather than let a stray session there index everything.\nfunction isGuardedDir(cwd: string): boolean {\n const resolved = path.resolve(cwd);\n const home = path.resolve(os.homedir());\n const same = (a: string, b: string) =>\n process.platform === \"win32\" ? a.toLowerCase() === b.toLowerCase() : a === b;\n return same(resolved, home) || same(resolved, path.parse(resolved).root);\n}\n\nasync function ensureTreeRepo(cwd: string): Promise<string | null> {\n const dir = treeRepoDir(cwd);\n try {\n // Owner-only like the session directories: tree objects hold file\n // contents the user never committed anywhere else.\n await mkdir(dir, { recursive: true, mode: 0o700 });\n if (!existsSync(path.join(dir, \"HEAD\"))) {\n const out = await runGit([\"init\", \"--bare\", dir]);\n if (out === null) return null;\n // Belt and braces for fresh repos; runGit's forced -c flags already\n // cover repos created before the repo-local setting existed.\n await runGit([`--git-dir=${dir}`, \"config\", \"core.autocrlf\", \"false\"]);\n }\n // Rewritten on every call: repos created before the exclusion existed\n // pick it up here without any migration step.\n await mkdir(path.join(dir, \"info\"), { recursive: true });\n await writeFile(\n path.join(dir, \"info\", \"exclude\"),\n `${SENSITIVE_EXCLUDE_PATTERNS.join(\"\\n\")}\\n`,\n \"utf8\",\n );\n } catch {\n return null;\n }\n return dir;\n}\n\nfunction repoArgs(dir: string, cwd: string): string[] {\n return [`--git-dir=${dir}`, `--work-tree=${cwd}`];\n}\n\n// Drops index entries that match the exclude rules. Ignore patterns only keep\n// untracked files out of `git add`; a path already in the index — tracked by\n// a pre-exclusion star, or put back by read-tree of an old tree — stays until\n// explicitly removed, so both trackTree and restoreTree scrub it.\nasync function untrackExcluded(dir: string, cwd: string): Promise<boolean> {\n const base = repoArgs(dir, cwd);\n const listed = await runGit([...base, \"ls-files\", \"-z\", \"-c\", \"-i\", \"--exclude-standard\"]);\n if (listed === null) return false;\n const files = listed.split(\"\\0\").filter(Boolean);\n if (files.length === 0) return true;\n const removed = await runGit([\n ...base,\n \"rm\",\n \"--cached\",\n \"--ignore-unmatch\",\n \"-q\",\n \"--\",\n ...files.map((file) => `:(literal)${file}`),\n ]);\n return removed !== null;\n}\n\n// Captures the whole working tree (any change — write_file, edit_file, bash)\n// as a git tree object and returns its hash. The work tree's own .git is\n// skipped by git automatically; ignored files (node_modules) and excluded\n// likely-secret files never enter the tree, which is exactly what the restore\n// side relies on. A recent failure makes further attempts no-ops until\n// TRACK_FAILURE_TTL_MS has passed.\nexport function trackTree(cwd: string): Promise<string | null> {\n // Serialize captures per directory: the agent loop starts a turn's capture\n // concurrently and a quick second turn (or the /undo path) can arrive while\n // it still runs — two overlapping captures would race on the internal\n // repo's index.lock, and the loser's spurious failure would poison the\n // negative cache for five minutes. trackTreeUncached never rejects, so the\n // chain cannot wedge; each call still captures its own tree, in order.\n const key = path.resolve(cwd);\n const next = (trackChains.get(key) ?? Promise.resolve(null)).then(() => trackTreeGuarded(cwd));\n trackChains.set(key, next);\n return next;\n}\n\n// Per-cwd promise chains serializing trackTree (see above). Values stay\n// settled promises between captures; the map is keyed by directory, so it\n// stays tiny.\nconst trackChains = new Map<string, Promise<string | null>>();\n\nasync function trackTreeGuarded(cwd: string): Promise<string | null> {\n if (isGuardedDir(cwd)) return null;\n const key = path.resolve(cwd);\n const failedUntil = trackFailureUntil.get(key);\n if (failedUntil !== undefined && Date.now() < failedUntil) return null;\n const tree = await trackTreeUncached(cwd);\n if (tree === null) {\n trackFailureUntil.set(key, Date.now() + TRACK_FAILURE_TTL_MS);\n return null;\n }\n trackFailureUntil.delete(key);\n return tree;\n}\n\n// Pins a captured tree under refs/star/<timestamp>-<random> so gc --auto\n// never prunes a live /undo target, then trims the namespace to the newest\n// MAX_PINNED_REFS refs: for-each-ref sorts by refname, and equal-length\n// millisecond timestamps make that order chronological. Pure housekeeping —\n// a failure here never fails the capture.\nasync function pinTree(base: string[], tree: string): Promise<void> {\n const ref = `${PINNED_REF_PREFIX}${Date.now()}-${randomBytes(4).toString(\"hex\")}`;\n if ((await runGit([...base, \"update-ref\", ref, tree])) === null) return;\n const listed = await runGit([...base, \"for-each-ref\", \"--format=%(refname)\", PINNED_REF_PREFIX]);\n if (listed === null) return;\n const refs = listed.split(\"\\n\").filter(Boolean);\n const stale = refs.slice(0, Math.max(0, refs.length - MAX_PINNED_REFS));\n await Promise.all(stale.map((name) => runGit([...base, \"update-ref\", \"-d\", name])));\n}\n\nasync function trackTreeUncached(cwd: string): Promise<string | null> {\n if (!(await isGitAvailable())) return null;\n const dir = await ensureTreeRepo(cwd);\n if (!dir) return null;\n const base = repoArgs(dir, cwd);\n if (!scrubbedRepos.has(dir)) {\n if (!(await untrackExcluded(dir, cwd))) return null;\n scrubbedRepos.add(dir);\n }\n if ((await runGit([...base, \"add\", \"-A\"])) === null) return null;\n const tree = await runGit([...base, \"write-tree\"]);\n if (tree === null) return null;\n await pinTree(base, tree);\n const count = (trackCounts.get(dir) ?? 0) + 1;\n trackCounts.set(dir, count);\n if (count % GC_INTERVAL === 0) {\n // Pure housekeeping: the result is ignored so a gc failure never fails\n // the turn, matching the module's silent-degradation style.\n await runGit([`--git-dir=${dir}`, \"gc\", \"--auto\"], GC_TIMEOUT_MS);\n }\n return tree;\n}\n\n// Restores the working tree to a captured tree: index reset to the tree,\n// every index file checked out over the work tree, then untracked\n// (post-snapshot) files cleaned. `clean` keeps ignored files, so dependencies\n// and excluded secrets survive. checkout-index -a only writes paths present\n// in the index, so scrubbing excluded entries after read-tree guarantees a\n// tree captured before the exclusion existed still cannot overwrite the\n// user's current .env (or delete it via clean, which also skips it).\nexport async function restoreTree(cwd: string, hash: string): Promise<boolean> {\n if (isGuardedDir(cwd)) return false;\n if (!(await isGitAvailable())) return false;\n const dir = await ensureTreeRepo(cwd);\n if (!dir) return false;\n const base = repoArgs(dir, cwd);\n if ((await runGit([...base, \"read-tree\", hash])) === null) return false;\n if (!(await untrackExcluded(dir, cwd))) return false;\n if ((await runGit([...base, \"checkout-index\", \"-f\", \"-a\"])) === null) return false;\n if ((await runGit([...base, \"clean\", \"-fd\"])) === null) return false;\n return true;\n}\n\n// Read-only list of files restoring a tree would touch: tracked paths that\n// differ from the tree, plus untracked (non-ignored) paths the clean step\n// would remove. Backs the /undo and /redo previews.\nexport async function diffTreeNames(cwd: string, hash: string): Promise<string[] | null> {\n if (!(await isGitAvailable())) return null;\n const dir = treeRepoDir(cwd);\n if (!existsSync(path.join(dir, \"HEAD\"))) return null;\n const base = repoArgs(dir, cwd);\n const changed = await runGit([...base, \"diff\", \"--name-only\", hash]);\n const untracked = await runGit([...base, \"ls-files\", \"--others\", \"--exclude-standard\"]);\n if (changed === null || untracked === null) return null;\n const names = new Set<string>();\n for (const line of [...changed.split(\"\\n\"), ...untracked.split(\"\\n\")]) {\n // Restore never touches excluded likely-secret paths (trees captured\n // before the exclusion may still list them); keep the preview honest.\n if (line !== \"\" && !isSensitivePath(line)) names.add(line);\n }\n return [...names];\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
AgentLoop,
|
|
4
4
|
PLAN_MODE_PROMPT,
|
|
5
5
|
attachTurnContext
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-QELCMXQX.js";
|
|
7
|
+
import "./chunk-RD4S5LKM.js";
|
|
8
8
|
import "./chunk-MVAMPVTA.js";
|
|
9
9
|
import "./chunk-4IRY44TG.js";
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-OF42OVM4.js";
|
|
11
|
+
import "./chunk-6PLZ3FLG.js";
|
|
12
12
|
export {
|
|
13
13
|
AgentLoop,
|
|
14
14
|
PLAN_MODE_PROMPT,
|
|
15
15
|
attachTurnContext
|
|
16
16
|
};
|
|
17
|
-
//# sourceMappingURL=loop-
|
|
17
|
+
//# sourceMappingURL=loop-DWQ5WTPD.js.map
|
package/dist/main.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
resolveMentions,
|
|
17
17
|
resolveSessionId,
|
|
18
18
|
summarizeArgs
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-NMB3TNQU.js";
|
|
20
20
|
import {
|
|
21
21
|
ConfigSchema,
|
|
22
22
|
HookConfigSchema,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
ProviderConfigSchema,
|
|
26
26
|
contextWindowTokens,
|
|
27
27
|
reconcileStarMessages
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-RD4S5LKM.js";
|
|
29
29
|
import {
|
|
30
30
|
resolveModelConfig,
|
|
31
31
|
resolveStartupModel
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
registerSensitivePatterns,
|
|
42
42
|
setTodoSession,
|
|
43
43
|
setWebFetchAllowPrivateHosts
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-6PLZ3FLG.js";
|
|
45
45
|
|
|
46
46
|
// src/main.tsx
|
|
47
47
|
import { Command } from "commander";
|
|
@@ -352,7 +352,7 @@ function mergeProjectConfig(global, project, projectPath) {
|
|
|
352
352
|
merged.sessionBudgetUsd = Math.min(global.sessionBudgetUsd, project.sessionBudgetUsd);
|
|
353
353
|
}
|
|
354
354
|
if (project.maxSteps !== void 0) {
|
|
355
|
-
merged.maxSteps = protectiveMin(global.maxSteps ??
|
|
355
|
+
merged.maxSteps = protectiveMin(global.maxSteps ?? 0, project.maxSteps);
|
|
356
356
|
}
|
|
357
357
|
if (project.doomLoopThreshold !== void 0) {
|
|
358
358
|
merged.doomLoopThreshold = protectiveMin(
|
|
@@ -405,7 +405,7 @@ function wireRuntimeSettings(config) {
|
|
|
405
405
|
|
|
406
406
|
// src/main.tsx
|
|
407
407
|
async function createLoop(config, modelName, cwd, sessionStore) {
|
|
408
|
-
const [{ AgentLoop }, { createModel, reasoningEffortMetadata }, { createDefaultRegistry }] = await Promise.all([import("./loop-
|
|
408
|
+
const [{ AgentLoop }, { createModel, reasoningEffortMetadata }, { createDefaultRegistry }] = await Promise.all([import("./loop-DWQ5WTPD.js"), import("./provider-EWMUPBLH.js"), import("./tools-4OLADVDR.js")]);
|
|
409
409
|
const model = createModel(config, modelName);
|
|
410
410
|
const registry = createDefaultRegistry();
|
|
411
411
|
const modelConfig = resolveModelConfig(config, modelName);
|
|
@@ -658,7 +658,7 @@ program.name("star").description("Star CLI \u2014 an AI agent command-line inter
|
|
|
658
658
|
console.error(ttyError);
|
|
659
659
|
process.exit(1);
|
|
660
660
|
}
|
|
661
|
-
const { renderRepl } = await import("./repl-
|
|
661
|
+
const { renderRepl } = await import("./repl-ZABBT33D.js");
|
|
662
662
|
renderRepl(loop, {
|
|
663
663
|
model: modelName,
|
|
664
664
|
permissionMode: config.permissionMode,
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/main.tsx","../src/cli/print-human.ts","../src/cli/print-json.ts","../src/cli/startup.ts","../src/config/loader.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { defaultAgentTasks } from \"./agent/agent-tasks\";\nimport type { AgentLoop } from \"./agent/loop\";\nimport { formatTokens } from \"./cli/cost\";\nimport { formatStreamError } from \"./cli/format\";\nimport { MAX_IMAGE_BYTES, imageMimeType, readImageInput, resolveMentions } from \"./cli/mentions\";\nimport { printEventLine } from \"./cli/print-human\";\nimport { UsageTracker, eventToJsonLine } from \"./cli/print-json\";\nimport {\n imageRequiresPrintError,\n installStdoutEpipeGuard,\n interactiveRequiresTtyError,\n reportResumeSessions,\n} from \"./cli/startup\";\nimport { SYSTEM_PROMPT } from \"./cli/system-prompt\";\nimport { loadConfigSync } from \"./config/loader\";\nimport { type StarConfig, contextWindowTokens } from \"./config/schema\";\nimport { type ImageInput, type StarMessage, reconcileStarMessages } from \"./core/messages\";\nimport { resolveModelConfig, resolveStartupModel } from \"./llm/registry\";\nimport { loadSessionSnapshots } from \"./session/checkpoints\";\nimport { clearSessions } from \"./session/clear\";\nimport { findLatestSession, resolveSessionId } from \"./session/list\";\nimport { type SessionMeta, SessionStore } from \"./session/store\";\nimport { defaultTaskManager } from \"./tasks/manager\";\nimport { hydrateSnapshots } from \"./tools/fs/snapshots\";\nimport { loadTodos, setTodoSession } from \"./tools/todo\";\nimport { VERSION } from \"./version\";\n\nasync function createLoop(\n config: StarConfig,\n modelName: string,\n cwd: string,\n sessionStore: SessionStore | null,\n) {\n // Dynamic like the REPL import below: the agent loop pulls in the ai SDK\n // and every @ai-sdk provider (~100ms of module evaluation) that --version,\n // --help, session listing and --clear-sessions never need.\n const [{ AgentLoop }, { createModel, reasoningEffortMetadata }, { createDefaultRegistry }] =\n await Promise.all([import(\"./agent/loop\"), import(\"./llm/provider\"), import(\"./tools\")]);\n const model = createModel(config, modelName);\n const registry = createDefaultRegistry();\n const modelConfig = resolveModelConfig(config, modelName);\n return new AgentLoop({\n model,\n registry,\n config,\n cwd,\n system: SYSTEM_PROMPT,\n sessionStore,\n modelName,\n contextMaxTokens: contextWindowTokens(config, modelName),\n providerMetadata: reasoningEffortMetadata(config, modelName),\n temperature: modelConfig.temperature,\n streamIdleTimeoutSec: modelConfig.streamIdleTimeoutSec,\n streamFirstChunkTimeoutSec: modelConfig.streamFirstChunkTimeoutSec,\n vision: modelConfig.vision,\n });\n}\n\nasync function printMode(\n loop: AgentLoop,\n prompt: string,\n cwd: string,\n json: boolean,\n imagePaths: string[],\n sessionStore: SessionStore | null,\n): Promise<number> {\n const flagImages: ImageInput[] = [];\n for (const imagePath of imagePaths) {\n if (!imageMimeType(imagePath)) {\n process.stderr.write(\n `[error] unsupported image type: ${imagePath} (supported: png, jpg, jpeg, gif, webp)\\n`,\n );\n return 1;\n }\n const image = await readImageInput(imagePath, cwd);\n if (!image) {\n process.stderr.write(\n `[error] cannot read image: ${imagePath} (missing, unreadable, or larger than ${MAX_IMAGE_BYTES / (1024 * 1024)}MB)\\n`,\n );\n return 1;\n }\n flagImages.push(image);\n }\n const controller = new AbortController();\n process.on(\"SIGINT\", () => controller.abort());\n loop.onHookWarning = (message) => {\n process.stderr.write(`[hook] ${message}\\n`);\n };\n const resolved = await resolveMentions(prompt, cwd);\n if (resolved.attached.length > 0) {\n process.stderr.write(`[attached] ${resolved.attached.join(\", \")}\\n`);\n }\n for (const skip of resolved.skipped) {\n process.stderr.write(`[skipped] @${skip.path}: ${skip.reason}\\n`);\n }\n const images = [...flagImages, ...resolved.images];\n const input: string | { text: string; images: ImageInput[] } =\n images.length > 0 ? { text: resolved.input, images } : resolved.input;\n const usage = new UsageTracker();\n let exitCode = 0;\n try {\n for await (const event of loop.stream(input, controller.signal, {\n persistAs: prompt,\n })) {\n if (json) {\n const line = eventToJsonLine(event);\n if (line) process.stdout.write(`${line}\\n`);\n } else {\n // Human-readable path: tool args are the one-line summarizeArgs\n // digest (same as the REPL tool cards), never the full JSON.\n const line = printEventLine(event);\n if (line) {\n (line.stream === \"stdout\" ? process.stdout : process.stderr).write(line.text);\n }\n }\n switch (event.type) {\n case \"finish\":\n usage.add(event.usage);\n // A resumed session (-c/-r -p) must accumulate this turn's usage,\n // same as the REPL does; plain print runs have no store.\n if (event.usage) {\n sessionStore?.addUsage(event.usage).catch(() => {});\n }\n break;\n case \"error\":\n exitCode = 1;\n break;\n }\n if (exitCode !== 0) break;\n }\n } catch (error) {\n if (!(error instanceof DOMException && error.name === \"AbortError\")) {\n const message = error instanceof Error ? formatStreamError(error) : String(error);\n process.stderr.write(`\\n[error] ${message}\\n`);\n exitCode = 1;\n }\n }\n const usageLine = usage.toJsonLine();\n if (usageLine) {\n if (json) {\n process.stdout.write(`${usageLine}\\n`);\n } else {\n const t = usage.totals;\n process.stderr.write(\n `[usage] ${t.requests} requests, ${formatTokens(t.promptTokens)} prompt + ${formatTokens(t.completionTokens)} completion = ${formatTokens(t.totalTokens)} tokens\\n`,\n );\n }\n }\n if (!json) process.stdout.write(\"\\n\");\n const killedShells = defaultTaskManager.cleanup();\n const killedAgents = defaultAgentTasks.cleanup();\n const stopped = killedShells.length + killedAgents.length;\n if (stopped > 0) {\n process.stderr.write(\n `[info] ${stopped} background task(s) were still running and have been stopped.\\n`,\n );\n }\n return exitCode;\n}\n\nconst program = new Command();\n\nprogram\n .name(\"star\")\n .description(\"Star CLI — an AI agent command-line interface\")\n .version(VERSION)\n .option(\"-m, --model <model>\", \"model to use\")\n .option(\"--permission-mode <mode>\", \"permission mode: ask | auto | readonly | yolo | plan\")\n .option(\"-p, --print <prompt>\", \"non-interactive print mode\")\n .option(\"--json\", \"output NDJSON events on stdout (print mode only)\")\n .option(\n \"--image <path>\",\n \"attach an image file (png/jpg/jpeg/gif/webp, max 5MB); repeatable\",\n (value: string, previous: string[]) => [...previous, value],\n [] as string[],\n )\n .option(\"-r, --resume [sessionId]\", \"resume a previous session (lists sessions when no id given)\")\n .option(\"-c, --continue\", \"continue the most recent session for the current directory\")\n .option(\n \"--clear-sessions [scope]\",\n \"delete stored sessions for the current directory ('all' deletes every session) and exit\",\n )\n .action(async (opts) => {\n installStdoutEpipeGuard();\n const cwd = process.cwd();\n\n if (opts.json && opts.print === undefined) {\n console.error(\n '--json requires print mode: use star -p \"...\" --json (the interactive REPL does not support JSON output).',\n );\n process.exit(1);\n }\n\n const imageError = imageRequiresPrintError(opts.print, opts.image ?? []);\n if (imageError) {\n console.error(imageError);\n process.exit(1);\n }\n\n if (opts.resume !== undefined && opts.continue) {\n console.error(\"Options --resume and --continue are mutually exclusive: pick one.\");\n process.exit(1);\n }\n\n if (opts.resume === true) {\n process.exit(await reportResumeSessions(cwd));\n }\n\n if (opts.clearSessions !== undefined) {\n const scope = opts.clearSessions;\n if (scope !== true && scope !== \"all\") {\n console.error(`Invalid scope: ${scope}. Use --clear-sessions or --clear-sessions all.`);\n process.exit(1);\n }\n const all = scope === \"all\";\n const removed = await clearSessions(all ? undefined : cwd);\n console.log(\n all\n ? `Deleted ${removed} session(s) across all directories.`\n : `Deleted ${removed} session(s) for this directory.`,\n );\n process.exit(0);\n }\n\n let config: StarConfig;\n try {\n config = loadConfigSync(cwd, { model: opts.model, permissionMode: opts.permissionMode });\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n\n let sessionStore: SessionStore | null = null;\n let resumed: { meta: SessionMeta; messages: StarMessage[] } | null = null;\n let resumeId: string | null = null;\n if (typeof opts.resume === \"string\") {\n resumeId = await resolveSessionId(opts.resume);\n if (!resumeId) {\n console.error(`Session not found: ${opts.resume}`);\n process.exit(1);\n }\n } else if (opts.continue) {\n const latest = await findLatestSession(cwd);\n if (latest) {\n resumeId = latest.id;\n } else {\n process.stderr.write(\"No previous session for this directory — starting a new session.\\n\");\n }\n }\n\n if (resumeId) {\n // Open the store once and read through it: resumeSession() would open a\n // second SessionStore instance on the same directory whose independent\n // meta cache could race this instance's writes.\n sessionStore = await SessionStore.open(resumeId);\n if (!sessionStore) {\n console.error(`Session not found: ${resumeId}`);\n process.exit(1);\n }\n const [meta, loaded] = await Promise.all([sessionStore.meta(), sessionStore.starMessages()]);\n const messages = reconcileStarMessages(loaded);\n if (messages.length !== loaded.length) {\n await sessionStore.replaceMessages(messages);\n }\n resumed = { meta, messages };\n setTodoSession(resumeId);\n }\n\n // An explicit --model already landed in config.defaultModel (loader\n // override) and wins; otherwise a resumed session's recorded model is\n // restored when it still resolves in the config.\n const { name: modelName, notice: modelNotice } = resolveStartupModel(\n config,\n opts.model ? undefined : resumed?.meta.model,\n );\n if (modelNotice) {\n process.stderr.write(`${modelNotice}\\n`);\n }\n if (!modelName) {\n console.error(\n \"No model configured. Add one to ~/.star-cli/config.toml or pass --model.\\n\" +\n \"See README.md for configuration examples.\",\n );\n process.exit(1);\n }\n\n if (!resumeId && !opts.print) {\n sessionStore = await SessionStore.create(cwd, modelName);\n setTodoSession(sessionStore.id);\n }\n\n let loop: AgentLoop;\n try {\n loop = await createLoop(config, modelName, cwd, sessionStore);\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n if (resumed) {\n await loop.loadMessages(resumed.messages);\n // Resuming explicitly continues the project: rehydrate its todo list\n // (fresh sessions leave it alone even when .star/todos.json exists, and\n // a list owned by another session is not adopted).\n await loadTodos(cwd, resumeId ?? undefined);\n if (sessionStore) {\n hydrateSnapshots(await loadSessionSnapshots(sessionStore.dir));\n }\n }\n\n if (opts.print) {\n // Let the loop drain instead of process.exit(): force-exiting on Windows\n // can hit a libuv assertion while undici keep-alive handles are closing.\n process.exitCode = await printMode(\n loop,\n opts.print,\n cwd,\n Boolean(opts.json),\n opts.image ?? [],\n sessionStore,\n );\n return;\n }\n\n // The REPL needs a real terminal on both ends; check before paying for\n // the Ink import so a piped launch fails fast with a clear message.\n const ttyError = interactiveRequiresTtyError({\n stdinTTY: Boolean(process.stdin.isTTY),\n stdoutTTY: Boolean(process.stdout.isTTY),\n });\n if (ttyError) {\n console.error(ttyError);\n process.exit(1);\n }\n\n // The REPL pulls in Ink and every interactive component (~0.4s of module\n // evaluation): load it only on the interactive path so -p, --version,\n // --clear-sessions and session listing stay cheap.\n const { renderRepl } = await import(\"./cli/repl\");\n renderRepl(loop, {\n model: modelName,\n permissionMode: config.permissionMode,\n config,\n cwd,\n sessionStore,\n initialMessages: resumed ? resumed.messages : undefined,\n initialUsage: resumed?.meta.usage,\n });\n });\n\nprogram.parse(process.argv);\n","import type { StreamEvent } from \"../core/events\";\nimport { formatStreamError, summarizeArgs } from \"./format\";\n\nexport interface PrintLine {\n stream: \"stdout\" | \"stderr\";\n text: string;\n}\n\n// Human-readable (-p without --json) rendering of one stream event. Tool\n// args go through the same one-line summarizeArgs digest the REPL tool cards\n// use instead of the full JSON; print-json (machine consumption) keeps the\n// complete payload. Returns null for events this path ignores (reasoning,\n// tool-call progress) — finish is accounted separately via UsageTracker and\n// error additionally flips the exit code, both handled by the caller.\nexport function printEventLine(event: StreamEvent): PrintLine | null {\n switch (event.type) {\n case \"text-delta\":\n return { stream: \"stdout\", text: event.text };\n case \"tool-call\":\n return { stream: \"stderr\", text: `\\n[tool] ${event.name} ${summarizeArgs(event.args)}\\n` };\n case \"tool-result\": {\n const preview =\n event.content.length > 500\n ? `${event.content.slice(0, 500)}... (truncated)`\n : event.content;\n return {\n stream: \"stderr\",\n text: `[result] ${event.isError ? \"ERROR: \" : \"\"}${preview}\\n`,\n };\n }\n case \"retry\": {\n const wait =\n event.delayMs !== undefined && event.delayMs >= 1000\n ? ` in ${Math.round(event.delayMs / 1000)}s`\n : \"\";\n return {\n stream: \"stderr\",\n text: `\\n[retry ${event.attempt}/${event.maxAttempts}${wait}] ${event.reason}\\n`,\n };\n }\n case \"notice\":\n return { stream: \"stderr\", text: `\\n[notice] ${event.message}\\n` };\n case \"error\":\n return { stream: \"stderr\", text: `\\n[error] ${formatStreamError(event.error)}\\n` };\n default:\n return null;\n }\n}\n","import type { StreamEvent, TokenUsage } from \"../core/events\";\n\nexport function eventToJsonLine(event: StreamEvent): string | null {\n switch (event.type) {\n case \"finish\":\n return null;\n case \"error\":\n return JSON.stringify({ type: \"error\", error: { message: event.error.message } });\n default:\n return JSON.stringify(event);\n }\n}\n\nexport class UsageTracker {\n private requests = 0;\n private promptTokens = 0;\n private completionTokens = 0;\n private totalTokens = 0;\n\n add(usage?: TokenUsage): void {\n if (!usage) return;\n this.requests += 1;\n this.promptTokens += usage.promptTokens;\n this.completionTokens += usage.completionTokens;\n this.totalTokens += usage.totalTokens;\n }\n\n get totals(): TokenUsage & { requests: number } {\n return {\n requests: this.requests,\n promptTokens: this.promptTokens,\n completionTokens: this.completionTokens,\n totalTokens: this.totalTokens,\n };\n }\n\n toJsonLine(): string | null {\n if (this.requests === 0) return null;\n return JSON.stringify({\n type: \"usage\",\n requests: this.requests,\n promptTokens: this.promptTokens,\n completionTokens: this.completionTokens,\n totalTokens: this.totalTokens,\n });\n }\n}\n","import { formatSessionEntries, listSessionEntries } from \"../session/list\";\n\n// Guards for the CLI entry paths, kept out of main.tsx (which parses argv at\n// module scope) so tests can exercise them without launching commander.\n\nexport interface StartupStreams {\n stdinTTY: boolean;\n stdoutTTY: boolean;\n}\n\n// --image only has a consumer in print mode; without -p the file would be\n// silently dropped when the REPL starts, so fail at startup instead.\nexport function imageRequiresPrintError(\n print: string | undefined,\n images: readonly string[],\n): string | null {\n if (print !== undefined) return null;\n return images.length > 0 ? \"--image requires -p/--print\" : null;\n}\n\n// Ink needs a real terminal on both ends; piped stdin/stdout used to leave a\n// bare stack or a hung process.\nexport function interactiveRequiresTtyError(streams: StartupStreams): string | null {\n return streams.stdinTTY && streams.stdoutTTY\n ? null\n : \"interactive mode requires a TTY; use -p/--print\";\n}\n\n// A downstream pipe that closes early (star -p \"...\" | head -1) turns the next\n// stdout write into an EPIPE \"error\" event; exit quietly instead of dumping a\n// raw stack.\nexport function installStdoutEpipeGuard(stdout: NodeJS.WriteStream = process.stdout): void {\n stdout.on(\"error\", (error: NodeJS.ErrnoException) => {\n if (error?.code === \"EPIPE\") process.exit(0);\n else throw error;\n });\n}\n\n// `star -r` without an id prints the session picker list and leaves; a script\n// must be able to tell \"no sessions\" apart from a successful listing, hence\n// the non-zero code.\nexport async function reportResumeSessions(cwd: string): Promise<number> {\n const entries = await listSessionEntries(cwd);\n if (entries.length === 0) {\n console.error(\"No sessions found for this directory.\");\n return 1;\n }\n console.log(formatSessionEntries(entries));\n return 0;\n}\n","import fs from \"node:fs\";\nimport { parse } from \"smol-toml\";\nimport { registerSensitivePatterns } from \"../core/sensitive\";\nimport { setWebFetchAllowPrivateHosts } from \"../tools/web/fetch\";\nimport { loadEnvFile } from \"./env\";\nimport { globalConfigPath, projectConfigPath } from \"./paths\";\nimport {\n type CliOverrides,\n ConfigSchema,\n HookConfigSchema,\n type ModelConfig,\n ModelConfigSchema,\n PermissionsConfigSchema,\n ProviderConfigSchema,\n type StarConfig,\n} from \"./schema\";\n\nconst PartialConfigSchema = ConfigSchema.partial();\n\ntype PartialConfig = ReturnType<typeof PartialConfigSchema.parse>;\n\n// Which file a parsed config came from: project files warn differently —\n// schema-known keys the sandbox strips get sanitizeProjectConfig's \"project\n// config cannot set this key\", so the unknown-key diff only reports keys the\n// schema does not know at all.\ntype ConfigScope = \"global\" | \"project\";\n\nfunction parseTomlFile(content: string, filePath: string, scope: ConfigScope): PartialConfig {\n let raw: unknown;\n try {\n raw = parse(content);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to parse TOML in ${filePath}: ${message}`);\n }\n const result = PartialConfigSchema.safeParse(raw);\n if (!result.success) {\n // One readable line per issue instead of zod's single JSON blob.\n const details = result.error.issues\n .map((issue) => {\n const where = issue.path.length > 0 ? issue.path.join(\".\") : \"(root)\";\n return ` ${where}: ${issue.message}`;\n })\n .join(\"\\n\");\n throw new Error(`Invalid config in ${filePath}:\\n${details}`);\n }\n warnUnknownKeys(raw, filePath, scope);\n return result.data;\n}\n\n// Keys a project-level .star/config.toml may set. Anything else (providers,\n// permissionMode, permissions, hooks, ...) stays global-only: a checked-out\n// repo must not be able to plant shell hooks, force yolo mode, or redirect\n// provider traffic to a key-harvesting endpoint.\nconst PROJECT_ALLOWED_KEYS = new Set([\n \"defaultModel\",\n \"models\",\n \"maxSteps\",\n \"contextMaxTokens\",\n \"compactThresholdTokens\",\n \"streamIdleTimeoutSec\",\n \"streamFirstChunkTimeoutSec\",\n \"streamMaxRetries\",\n \"maxAutoContinues\",\n \"contextCompaction\",\n \"sessionBudgetUsd\",\n \"notifyBell\",\n \"notifyBellThresholdSec\",\n \"doomLoopThreshold\",\n \"gitSnapshots\",\n]);\n\n// Safe ranges for the project-provided streaming knobs: a repo must not set\n// pathological values (sub-second idle timeouts, thousands of retries).\nconst PROJECT_STREAM_RANGES = {\n streamIdleTimeoutSec: { min: 5, max: 120 },\n streamFirstChunkTimeoutSec: { min: 30, max: 900 },\n streamMaxRetries: { min: 0, max: 10 },\n} as const;\n\n// 0 disables these protections, so a project may only tighten them, never\n// turn them off (handled at merge time via min()).\nconst PROJECT_PROTECTIVE_MIN_KEYS = new Set([\"maxSteps\", \"doomLoopThreshold\"]);\n\n// Known keys per schema-defined section, for the unknown-key diff.\nconst TOP_LEVEL_KEYS = new Set(Object.keys(ConfigSchema.shape));\nconst SECTION_KEYS: Record<string, { keys: Set<string>; array: boolean }> = {\n permissions: { keys: new Set(Object.keys(PermissionsConfigSchema.shape)), array: false },\n providers: { keys: new Set(Object.keys(ProviderConfigSchema.shape)), array: true },\n models: { keys: new Set(Object.keys(ModelConfigSchema.shape)), array: true },\n hooks: { keys: new Set(Object.keys(HookConfigSchema.shape)), array: true },\n};\n\nfunction editDistance(a: string, b: string): number {\n let previous: number[] = Array.from({ length: b.length + 1 }, (_, i) => i);\n for (let i = 1; i <= a.length; i++) {\n const current: number[] = [i];\n for (let j = 1; j <= b.length; j++) {\n current[j] = Math.min(\n (previous[j] ?? 0) + 1,\n (current[j - 1] ?? 0) + 1,\n (previous[j - 1] ?? 0) + (a[i - 1] === b[j - 1] ? 0 : 1),\n );\n }\n previous = current;\n }\n return previous[b.length] ?? 0;\n}\n\n// Cheap \"did you mean\": case-insensitive Levenshtein against the known keys,\n// accepted when the distance is small relative to the key's length.\nfunction suggestKey(key: string, known: Set<string>): string | undefined {\n const needle = key.toLowerCase();\n let best: string | undefined;\n let bestDistance = Number.POSITIVE_INFINITY;\n for (const candidate of known) {\n const distance = editDistance(needle, candidate.toLowerCase());\n if (distance <= Math.max(1, Math.floor(candidate.length / 4)) && distance < bestDistance) {\n best = candidate;\n bestDistance = distance;\n }\n }\n return best;\n}\n\nfunction warnUnknownKey(keyPath: string, filePath: string, known: Set<string>): void {\n const leaf = keyPath.slice(keyPath.lastIndexOf(\".\") + 1);\n const suggestion = suggestKey(leaf, known);\n const hint = suggestion\n ? `possible typo of \"${suggestion}\"? the key is ignored`\n : \"possible typo? the key is ignored\";\n process.stderr.write(`[star] unknown config key \"${keyPath}\" in ${filePath}: ${hint}\\n`);\n}\n\n// zod object schemas strip unknown keys without a word, so a misspelled\n// option (\"streamMaxRetreis\") would otherwise vanish silently. Diff the raw\n// TOML against the schema shapes and warn once per unknown key — top level\n// plus inside the schema-defined sections ([permissions], [[providers]],\n// [[models]], [[hooks]]). Warnings never block loading. In project files,\n// schema-known sections the sandbox drops wholesale (everything but\n// [[models]]) already get sanitizeProjectConfig's own warning, so their\n// inner keys are not diffed.\nfunction warnUnknownKeys(raw: unknown, filePath: string, scope: ConfigScope): void {\n if (typeof raw !== \"object\" || raw === null) return;\n const table = raw as Record<string, unknown>;\n for (const key of Object.keys(table)) {\n if (!TOP_LEVEL_KEYS.has(key)) warnUnknownKey(key, filePath, TOP_LEVEL_KEYS);\n }\n for (const [section, { keys, array }] of Object.entries(SECTION_KEYS)) {\n if (scope === \"project\" && !PROJECT_ALLOWED_KEYS.has(section)) continue;\n const value = table[section];\n if (array) {\n if (!Array.isArray(value)) continue;\n value.forEach((entry, index) => {\n if (typeof entry !== \"object\" || entry === null) return;\n for (const key of Object.keys(entry)) {\n if (!keys.has(key)) warnUnknownKey(`${section}[${index}].${key}`, filePath, keys);\n }\n });\n continue;\n }\n if (typeof value !== \"object\" || value === null) continue;\n for (const key of Object.keys(value as Record<string, unknown>)) {\n if (!keys.has(key)) warnUnknownKey(`${section}.${key}`, filePath, keys);\n }\n }\n}\n\nfunction warnProject(filePath: string, message: string): void {\n process.stderr.write(`[star] ${message} in ${filePath}\\n`);\n}\n\n// Price fields are stripped from project models: a repo defining $0 prices\n// would silently zero out /cost and defeat sessionBudgetUsd.\nfunction stripModelPrices(models: ModelConfig[], filePath: string): ModelConfig[] {\n let stripped = false;\n const out = models.map((model) => {\n const { promptPrice, completionPrice, cacheReadPrice, ...rest } = model;\n if (\n promptPrice !== undefined ||\n completionPrice !== undefined ||\n cacheReadPrice !== undefined\n ) {\n stripped = true;\n }\n return rest;\n });\n if (stripped) {\n warnProject(filePath, \"ignoring price fields in project [[models]]: pricing stays global-only\");\n }\n return out;\n}\n\nfunction sanitizeProjectConfig(project: PartialConfig, filePath: string): PartialConfig {\n const sanitized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(project)) {\n if (value === undefined) continue;\n if (!PROJECT_ALLOWED_KEYS.has(key)) {\n process.stderr.write(\n `[star] ignoring \"${key}\" in ${filePath}: project config cannot set this key\\n`,\n );\n continue;\n }\n if (key === \"gitSnapshots\" && value === false) {\n // Snapshot tracking protects /undo and /redo; a repo may enable but\n // never disable it.\n warnProject(\n filePath,\n 'ignoring \"gitSnapshots = false\": project config cannot disable this protection',\n );\n continue;\n }\n if (PROJECT_PROTECTIVE_MIN_KEYS.has(key) && value === 0) {\n warnProject(filePath, `ignoring \"${key} = 0\": project config cannot disable this protection`);\n continue;\n }\n const range = PROJECT_STREAM_RANGES[key as keyof typeof PROJECT_STREAM_RANGES];\n if (range && typeof value === \"number\") {\n const clamped = Math.min(range.max, Math.max(range.min, value));\n if (clamped !== value) {\n warnProject(\n filePath,\n `clamping \"${key}\" from ${value} to ${clamped}: project config is limited to ${range.min}–${range.max}`,\n );\n }\n sanitized[key] = clamped;\n continue;\n }\n if (key === \"models\" && Array.isArray(value)) {\n sanitized[key] = stripModelPrices(value as ModelConfig[], filePath);\n continue;\n }\n sanitized[key] = value;\n }\n return sanitized as PartialConfig;\n}\n\n// Project [[models]] merge with the global table by name: a project entry\n// replaces the same-named global entry, every other global entry survives.\n// (Shallow-spreading the array would let a repo silently swap the user's\n// whole model table — and orphan a global defaultModel pointing into it.)\nfunction mergeModelsByName(\n globalModels: ModelConfig[],\n projectModels: ModelConfig[],\n): ModelConfig[] {\n const projectByName = new Map(projectModels.map((model) => [model.name, model]));\n const merged = globalModels.map((model) => projectByName.get(model.name) ?? model);\n const globalNames = new Set(globalModels.map((model) => model.name));\n for (const model of projectModels) {\n if (!globalNames.has(model.name)) merged.push(model);\n }\n return merged;\n}\n\n// 0 disables these protections (unlimited), so normalize it to +∞ before the\n// min: a project must be able to tighten a globally-disabled guard (global\n// maxSteps = 0, project 5 → 5), never to relax one.\nfunction protectiveMin(a: number, b: number): number {\n const result = Math.min(\n a === 0 ? Number.POSITIVE_INFINITY : a,\n b === 0 ? Number.POSITIVE_INFINITY : b,\n );\n return result === Number.POSITIVE_INFINITY ? 0 : result;\n}\n\n// Project values merge protectively: a repo can tighten safeguards but never\n// relax them. Budgets take the lower bound; guard thresholds take the lower\n// bound too (a project-side 0 = disabled was already filtered out above, and\n// a global 0 normalizes to +∞ via protectiveMin).\nfunction mergeProjectConfig(\n global: PartialConfig,\n project: PartialConfig,\n projectPath: string,\n): PartialConfig {\n const merged: PartialConfig = { ...global, ...project };\n if (project.models !== undefined) {\n merged.models = mergeModelsByName(global.models ?? [], project.models);\n warnProject(projectPath, `project config overrides ${project.models.length} model(s)`);\n }\n if (project.sessionBudgetUsd !== undefined && global.sessionBudgetUsd !== undefined) {\n merged.sessionBudgetUsd = Math.min(global.sessionBudgetUsd, project.sessionBudgetUsd);\n }\n if (project.maxSteps !== undefined) {\n merged.maxSteps = protectiveMin(global.maxSteps ?? 100, project.maxSteps);\n }\n if (project.doomLoopThreshold !== undefined) {\n merged.doomLoopThreshold = protectiveMin(\n global.doomLoopThreshold ?? 3,\n project.doomLoopThreshold,\n );\n }\n return merged;\n}\n\n// Plaintext keys still work, but config.toml is world-readable by default on\n// some setups and gets committed by accident — point users at apiKeyEnv.\nfunction warnPlaintextApiKey(config: PartialConfig): void {\n const offenders: string[] = [];\n for (const provider of config.providers ?? []) {\n if (provider.apiKey !== undefined) offenders.push(`provider \"${provider.name}\"`);\n }\n for (const model of config.models ?? []) {\n if (\"apiKey\" in model && model.apiKey !== undefined) offenders.push(`model \"${model.name}\"`);\n }\n if (offenders.length === 0) return;\n process.stderr.write(\n `[star] plaintext apiKey in config (${offenders.join(\", \")}) is deprecated: store keys in ~/.star-cli/.env and reference them with apiKeyEnv instead\\n`,\n );\n}\n\nfunction applyOverrides(config: PartialConfig, overrides?: CliOverrides): PartialConfig {\n if (!overrides) return config;\n const merged = { ...config };\n if (overrides.model !== undefined) merged.defaultModel = overrides.model;\n if (overrides.permissionMode !== undefined) merged.permissionMode = overrides.permissionMode;\n return merged;\n}\n\nasync function readTomlFile(filePath: string, scope: ConfigScope): Promise<PartialConfig> {\n let content: string;\n try {\n content = await fs.promises.readFile(filePath, \"utf8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {};\n throw error;\n }\n return parseTomlFile(content, filePath, scope);\n}\n\nfunction readTomlFileSync(filePath: string, scope: ConfigScope): PartialConfig {\n if (!fs.existsSync(filePath)) return {};\n const content = fs.readFileSync(filePath, \"utf8\");\n return parseTomlFile(content, filePath, scope);\n}\n\nexport async function loadConfig(cwd: string, overrides?: CliOverrides): Promise<StarConfig> {\n loadEnvFile();\n const global = await readTomlFile(globalConfigPath(), \"global\");\n const projectPath = projectConfigPath(cwd);\n const project = sanitizeProjectConfig(await readTomlFile(projectPath, \"project\"), projectPath);\n const merged = applyOverrides(mergeProjectConfig(global, project, projectPath), overrides);\n warnPlaintextApiKey(merged);\n return wireRuntimeSettings(ConfigSchema.parse(merged));\n}\n\nexport function loadConfigSync(cwd: string, overrides?: CliOverrides): StarConfig {\n loadEnvFile();\n const global = readTomlFileSync(globalConfigPath(), \"global\");\n const projectPath = projectConfigPath(cwd);\n const project = sanitizeProjectConfig(readTomlFileSync(projectPath, \"project\"), projectPath);\n const merged = applyOverrides(mergeProjectConfig(global, project, projectPath), overrides);\n warnPlaintextApiKey(merged);\n return wireRuntimeSettings(ConfigSchema.parse(merged));\n}\n\n// Pushes config-driven security settings into their runtime consumers. The\n// merged permissions table is global-only at this point (the project sandbox\n// dropped any project-side [permissions]), so these can never be planted by\n// a checked-out repo.\nfunction wireRuntimeSettings(config: StarConfig): StarConfig {\n registerSensitivePatterns(config.permissions.sensitive);\n setWebFetchAllowPrivateHosts(config.webFetchAllowPrivateHosts);\n return config;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/main.tsx","../src/cli/print-human.ts","../src/cli/print-json.ts","../src/cli/startup.ts","../src/config/loader.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { defaultAgentTasks } from \"./agent/agent-tasks\";\nimport type { AgentLoop } from \"./agent/loop\";\nimport { formatTokens } from \"./cli/cost\";\nimport { formatStreamError } from \"./cli/format\";\nimport { MAX_IMAGE_BYTES, imageMimeType, readImageInput, resolveMentions } from \"./cli/mentions\";\nimport { printEventLine } from \"./cli/print-human\";\nimport { UsageTracker, eventToJsonLine } from \"./cli/print-json\";\nimport {\n imageRequiresPrintError,\n installStdoutEpipeGuard,\n interactiveRequiresTtyError,\n reportResumeSessions,\n} from \"./cli/startup\";\nimport { SYSTEM_PROMPT } from \"./cli/system-prompt\";\nimport { loadConfigSync } from \"./config/loader\";\nimport { type StarConfig, contextWindowTokens } from \"./config/schema\";\nimport { type ImageInput, type StarMessage, reconcileStarMessages } from \"./core/messages\";\nimport { resolveModelConfig, resolveStartupModel } from \"./llm/registry\";\nimport { loadSessionSnapshots } from \"./session/checkpoints\";\nimport { clearSessions } from \"./session/clear\";\nimport { findLatestSession, resolveSessionId } from \"./session/list\";\nimport { type SessionMeta, SessionStore } from \"./session/store\";\nimport { defaultTaskManager } from \"./tasks/manager\";\nimport { hydrateSnapshots } from \"./tools/fs/snapshots\";\nimport { loadTodos, setTodoSession } from \"./tools/todo\";\nimport { VERSION } from \"./version\";\n\nasync function createLoop(\n config: StarConfig,\n modelName: string,\n cwd: string,\n sessionStore: SessionStore | null,\n) {\n // Dynamic like the REPL import below: the agent loop pulls in the ai SDK\n // and every @ai-sdk provider (~100ms of module evaluation) that --version,\n // --help, session listing and --clear-sessions never need.\n const [{ AgentLoop }, { createModel, reasoningEffortMetadata }, { createDefaultRegistry }] =\n await Promise.all([import(\"./agent/loop\"), import(\"./llm/provider\"), import(\"./tools\")]);\n const model = createModel(config, modelName);\n const registry = createDefaultRegistry();\n const modelConfig = resolveModelConfig(config, modelName);\n return new AgentLoop({\n model,\n registry,\n config,\n cwd,\n system: SYSTEM_PROMPT,\n sessionStore,\n modelName,\n contextMaxTokens: contextWindowTokens(config, modelName),\n providerMetadata: reasoningEffortMetadata(config, modelName),\n temperature: modelConfig.temperature,\n streamIdleTimeoutSec: modelConfig.streamIdleTimeoutSec,\n streamFirstChunkTimeoutSec: modelConfig.streamFirstChunkTimeoutSec,\n vision: modelConfig.vision,\n });\n}\n\nasync function printMode(\n loop: AgentLoop,\n prompt: string,\n cwd: string,\n json: boolean,\n imagePaths: string[],\n sessionStore: SessionStore | null,\n): Promise<number> {\n const flagImages: ImageInput[] = [];\n for (const imagePath of imagePaths) {\n if (!imageMimeType(imagePath)) {\n process.stderr.write(\n `[error] unsupported image type: ${imagePath} (supported: png, jpg, jpeg, gif, webp)\\n`,\n );\n return 1;\n }\n const image = await readImageInput(imagePath, cwd);\n if (!image) {\n process.stderr.write(\n `[error] cannot read image: ${imagePath} (missing, unreadable, or larger than ${MAX_IMAGE_BYTES / (1024 * 1024)}MB)\\n`,\n );\n return 1;\n }\n flagImages.push(image);\n }\n const controller = new AbortController();\n process.on(\"SIGINT\", () => controller.abort());\n loop.onHookWarning = (message) => {\n process.stderr.write(`[hook] ${message}\\n`);\n };\n const resolved = await resolveMentions(prompt, cwd);\n if (resolved.attached.length > 0) {\n process.stderr.write(`[attached] ${resolved.attached.join(\", \")}\\n`);\n }\n for (const skip of resolved.skipped) {\n process.stderr.write(`[skipped] @${skip.path}: ${skip.reason}\\n`);\n }\n const images = [...flagImages, ...resolved.images];\n const input: string | { text: string; images: ImageInput[] } =\n images.length > 0 ? { text: resolved.input, images } : resolved.input;\n const usage = new UsageTracker();\n let exitCode = 0;\n try {\n for await (const event of loop.stream(input, controller.signal, {\n persistAs: prompt,\n })) {\n if (json) {\n const line = eventToJsonLine(event);\n if (line) process.stdout.write(`${line}\\n`);\n } else {\n // Human-readable path: tool args are the one-line summarizeArgs\n // digest (same as the REPL tool cards), never the full JSON.\n const line = printEventLine(event);\n if (line) {\n (line.stream === \"stdout\" ? process.stdout : process.stderr).write(line.text);\n }\n }\n switch (event.type) {\n case \"finish\":\n usage.add(event.usage);\n // A resumed session (-c/-r -p) must accumulate this turn's usage,\n // same as the REPL does; plain print runs have no store.\n if (event.usage) {\n sessionStore?.addUsage(event.usage).catch(() => {});\n }\n break;\n case \"error\":\n exitCode = 1;\n break;\n }\n if (exitCode !== 0) break;\n }\n } catch (error) {\n if (!(error instanceof DOMException && error.name === \"AbortError\")) {\n const message = error instanceof Error ? formatStreamError(error) : String(error);\n process.stderr.write(`\\n[error] ${message}\\n`);\n exitCode = 1;\n }\n }\n const usageLine = usage.toJsonLine();\n if (usageLine) {\n if (json) {\n process.stdout.write(`${usageLine}\\n`);\n } else {\n const t = usage.totals;\n process.stderr.write(\n `[usage] ${t.requests} requests, ${formatTokens(t.promptTokens)} prompt + ${formatTokens(t.completionTokens)} completion = ${formatTokens(t.totalTokens)} tokens\\n`,\n );\n }\n }\n if (!json) process.stdout.write(\"\\n\");\n const killedShells = defaultTaskManager.cleanup();\n const killedAgents = defaultAgentTasks.cleanup();\n const stopped = killedShells.length + killedAgents.length;\n if (stopped > 0) {\n process.stderr.write(\n `[info] ${stopped} background task(s) were still running and have been stopped.\\n`,\n );\n }\n return exitCode;\n}\n\nconst program = new Command();\n\nprogram\n .name(\"star\")\n .description(\"Star CLI — an AI agent command-line interface\")\n .version(VERSION)\n .option(\"-m, --model <model>\", \"model to use\")\n .option(\"--permission-mode <mode>\", \"permission mode: ask | auto | readonly | yolo | plan\")\n .option(\"-p, --print <prompt>\", \"non-interactive print mode\")\n .option(\"--json\", \"output NDJSON events on stdout (print mode only)\")\n .option(\n \"--image <path>\",\n \"attach an image file (png/jpg/jpeg/gif/webp, max 5MB); repeatable\",\n (value: string, previous: string[]) => [...previous, value],\n [] as string[],\n )\n .option(\"-r, --resume [sessionId]\", \"resume a previous session (lists sessions when no id given)\")\n .option(\"-c, --continue\", \"continue the most recent session for the current directory\")\n .option(\n \"--clear-sessions [scope]\",\n \"delete stored sessions for the current directory ('all' deletes every session) and exit\",\n )\n .action(async (opts) => {\n installStdoutEpipeGuard();\n const cwd = process.cwd();\n\n if (opts.json && opts.print === undefined) {\n console.error(\n '--json requires print mode: use star -p \"...\" --json (the interactive REPL does not support JSON output).',\n );\n process.exit(1);\n }\n\n const imageError = imageRequiresPrintError(opts.print, opts.image ?? []);\n if (imageError) {\n console.error(imageError);\n process.exit(1);\n }\n\n if (opts.resume !== undefined && opts.continue) {\n console.error(\"Options --resume and --continue are mutually exclusive: pick one.\");\n process.exit(1);\n }\n\n if (opts.resume === true) {\n process.exit(await reportResumeSessions(cwd));\n }\n\n if (opts.clearSessions !== undefined) {\n const scope = opts.clearSessions;\n if (scope !== true && scope !== \"all\") {\n console.error(`Invalid scope: ${scope}. Use --clear-sessions or --clear-sessions all.`);\n process.exit(1);\n }\n const all = scope === \"all\";\n const removed = await clearSessions(all ? undefined : cwd);\n console.log(\n all\n ? `Deleted ${removed} session(s) across all directories.`\n : `Deleted ${removed} session(s) for this directory.`,\n );\n process.exit(0);\n }\n\n let config: StarConfig;\n try {\n config = loadConfigSync(cwd, { model: opts.model, permissionMode: opts.permissionMode });\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n\n let sessionStore: SessionStore | null = null;\n let resumed: { meta: SessionMeta; messages: StarMessage[] } | null = null;\n let resumeId: string | null = null;\n if (typeof opts.resume === \"string\") {\n resumeId = await resolveSessionId(opts.resume);\n if (!resumeId) {\n console.error(`Session not found: ${opts.resume}`);\n process.exit(1);\n }\n } else if (opts.continue) {\n const latest = await findLatestSession(cwd);\n if (latest) {\n resumeId = latest.id;\n } else {\n process.stderr.write(\"No previous session for this directory — starting a new session.\\n\");\n }\n }\n\n if (resumeId) {\n // Open the store once and read through it: resumeSession() would open a\n // second SessionStore instance on the same directory whose independent\n // meta cache could race this instance's writes.\n sessionStore = await SessionStore.open(resumeId);\n if (!sessionStore) {\n console.error(`Session not found: ${resumeId}`);\n process.exit(1);\n }\n const [meta, loaded] = await Promise.all([sessionStore.meta(), sessionStore.starMessages()]);\n const messages = reconcileStarMessages(loaded);\n if (messages.length !== loaded.length) {\n await sessionStore.replaceMessages(messages);\n }\n resumed = { meta, messages };\n setTodoSession(resumeId);\n }\n\n // An explicit --model already landed in config.defaultModel (loader\n // override) and wins; otherwise a resumed session's recorded model is\n // restored when it still resolves in the config.\n const { name: modelName, notice: modelNotice } = resolveStartupModel(\n config,\n opts.model ? undefined : resumed?.meta.model,\n );\n if (modelNotice) {\n process.stderr.write(`${modelNotice}\\n`);\n }\n if (!modelName) {\n console.error(\n \"No model configured. Add one to ~/.star-cli/config.toml or pass --model.\\n\" +\n \"See README.md for configuration examples.\",\n );\n process.exit(1);\n }\n\n if (!resumeId && !opts.print) {\n sessionStore = await SessionStore.create(cwd, modelName);\n setTodoSession(sessionStore.id);\n }\n\n let loop: AgentLoop;\n try {\n loop = await createLoop(config, modelName, cwd, sessionStore);\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n if (resumed) {\n await loop.loadMessages(resumed.messages);\n // Resuming explicitly continues the project: rehydrate its todo list\n // (fresh sessions leave it alone even when .star/todos.json exists, and\n // a list owned by another session is not adopted).\n await loadTodos(cwd, resumeId ?? undefined);\n if (sessionStore) {\n hydrateSnapshots(await loadSessionSnapshots(sessionStore.dir));\n }\n }\n\n if (opts.print) {\n // Let the loop drain instead of process.exit(): force-exiting on Windows\n // can hit a libuv assertion while undici keep-alive handles are closing.\n process.exitCode = await printMode(\n loop,\n opts.print,\n cwd,\n Boolean(opts.json),\n opts.image ?? [],\n sessionStore,\n );\n return;\n }\n\n // The REPL needs a real terminal on both ends; check before paying for\n // the Ink import so a piped launch fails fast with a clear message.\n const ttyError = interactiveRequiresTtyError({\n stdinTTY: Boolean(process.stdin.isTTY),\n stdoutTTY: Boolean(process.stdout.isTTY),\n });\n if (ttyError) {\n console.error(ttyError);\n process.exit(1);\n }\n\n // The REPL pulls in Ink and every interactive component (~0.4s of module\n // evaluation): load it only on the interactive path so -p, --version,\n // --clear-sessions and session listing stay cheap.\n const { renderRepl } = await import(\"./cli/repl\");\n renderRepl(loop, {\n model: modelName,\n permissionMode: config.permissionMode,\n config,\n cwd,\n sessionStore,\n initialMessages: resumed ? resumed.messages : undefined,\n initialUsage: resumed?.meta.usage,\n });\n });\n\nprogram.parse(process.argv);\n","import type { StreamEvent } from \"../core/events\";\nimport { formatStreamError, summarizeArgs } from \"./format\";\n\nexport interface PrintLine {\n stream: \"stdout\" | \"stderr\";\n text: string;\n}\n\n// Human-readable (-p without --json) rendering of one stream event. Tool\n// args go through the same one-line summarizeArgs digest the REPL tool cards\n// use instead of the full JSON; print-json (machine consumption) keeps the\n// complete payload. Returns null for events this path ignores (reasoning,\n// tool-call progress) — finish is accounted separately via UsageTracker and\n// error additionally flips the exit code, both handled by the caller.\nexport function printEventLine(event: StreamEvent): PrintLine | null {\n switch (event.type) {\n case \"text-delta\":\n return { stream: \"stdout\", text: event.text };\n case \"tool-call\":\n return { stream: \"stderr\", text: `\\n[tool] ${event.name} ${summarizeArgs(event.args)}\\n` };\n case \"tool-result\": {\n const preview =\n event.content.length > 500\n ? `${event.content.slice(0, 500)}... (truncated)`\n : event.content;\n return {\n stream: \"stderr\",\n text: `[result] ${event.isError ? \"ERROR: \" : \"\"}${preview}\\n`,\n };\n }\n case \"retry\": {\n const wait =\n event.delayMs !== undefined && event.delayMs >= 1000\n ? ` in ${Math.round(event.delayMs / 1000)}s`\n : \"\";\n return {\n stream: \"stderr\",\n text: `\\n[retry ${event.attempt}/${event.maxAttempts}${wait}] ${event.reason}\\n`,\n };\n }\n case \"notice\":\n return { stream: \"stderr\", text: `\\n[notice] ${event.message}\\n` };\n case \"error\":\n return { stream: \"stderr\", text: `\\n[error] ${formatStreamError(event.error)}\\n` };\n default:\n return null;\n }\n}\n","import type { StreamEvent, TokenUsage } from \"../core/events\";\n\nexport function eventToJsonLine(event: StreamEvent): string | null {\n switch (event.type) {\n case \"finish\":\n return null;\n case \"error\":\n return JSON.stringify({ type: \"error\", error: { message: event.error.message } });\n default:\n return JSON.stringify(event);\n }\n}\n\nexport class UsageTracker {\n private requests = 0;\n private promptTokens = 0;\n private completionTokens = 0;\n private totalTokens = 0;\n\n add(usage?: TokenUsage): void {\n if (!usage) return;\n this.requests += 1;\n this.promptTokens += usage.promptTokens;\n this.completionTokens += usage.completionTokens;\n this.totalTokens += usage.totalTokens;\n }\n\n get totals(): TokenUsage & { requests: number } {\n return {\n requests: this.requests,\n promptTokens: this.promptTokens,\n completionTokens: this.completionTokens,\n totalTokens: this.totalTokens,\n };\n }\n\n toJsonLine(): string | null {\n if (this.requests === 0) return null;\n return JSON.stringify({\n type: \"usage\",\n requests: this.requests,\n promptTokens: this.promptTokens,\n completionTokens: this.completionTokens,\n totalTokens: this.totalTokens,\n });\n }\n}\n","import { formatSessionEntries, listSessionEntries } from \"../session/list\";\n\n// Guards for the CLI entry paths, kept out of main.tsx (which parses argv at\n// module scope) so tests can exercise them without launching commander.\n\nexport interface StartupStreams {\n stdinTTY: boolean;\n stdoutTTY: boolean;\n}\n\n// --image only has a consumer in print mode; without -p the file would be\n// silently dropped when the REPL starts, so fail at startup instead.\nexport function imageRequiresPrintError(\n print: string | undefined,\n images: readonly string[],\n): string | null {\n if (print !== undefined) return null;\n return images.length > 0 ? \"--image requires -p/--print\" : null;\n}\n\n// Ink needs a real terminal on both ends; piped stdin/stdout used to leave a\n// bare stack or a hung process.\nexport function interactiveRequiresTtyError(streams: StartupStreams): string | null {\n return streams.stdinTTY && streams.stdoutTTY\n ? null\n : \"interactive mode requires a TTY; use -p/--print\";\n}\n\n// A downstream pipe that closes early (star -p \"...\" | head -1) turns the next\n// stdout write into an EPIPE \"error\" event; exit quietly instead of dumping a\n// raw stack.\nexport function installStdoutEpipeGuard(stdout: NodeJS.WriteStream = process.stdout): void {\n stdout.on(\"error\", (error: NodeJS.ErrnoException) => {\n if (error?.code === \"EPIPE\") process.exit(0);\n else throw error;\n });\n}\n\n// `star -r` without an id prints the session picker list and leaves; a script\n// must be able to tell \"no sessions\" apart from a successful listing, hence\n// the non-zero code.\nexport async function reportResumeSessions(cwd: string): Promise<number> {\n const entries = await listSessionEntries(cwd);\n if (entries.length === 0) {\n console.error(\"No sessions found for this directory.\");\n return 1;\n }\n console.log(formatSessionEntries(entries));\n return 0;\n}\n","import fs from \"node:fs\";\nimport { parse } from \"smol-toml\";\nimport { registerSensitivePatterns } from \"../core/sensitive\";\nimport { setWebFetchAllowPrivateHosts } from \"../tools/web/fetch\";\nimport { loadEnvFile } from \"./env\";\nimport { globalConfigPath, projectConfigPath } from \"./paths\";\nimport {\n type CliOverrides,\n ConfigSchema,\n HookConfigSchema,\n type ModelConfig,\n ModelConfigSchema,\n PermissionsConfigSchema,\n ProviderConfigSchema,\n type StarConfig,\n} from \"./schema\";\n\nconst PartialConfigSchema = ConfigSchema.partial();\n\ntype PartialConfig = ReturnType<typeof PartialConfigSchema.parse>;\n\n// Which file a parsed config came from: project files warn differently —\n// schema-known keys the sandbox strips get sanitizeProjectConfig's \"project\n// config cannot set this key\", so the unknown-key diff only reports keys the\n// schema does not know at all.\ntype ConfigScope = \"global\" | \"project\";\n\nfunction parseTomlFile(content: string, filePath: string, scope: ConfigScope): PartialConfig {\n let raw: unknown;\n try {\n raw = parse(content);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to parse TOML in ${filePath}: ${message}`);\n }\n const result = PartialConfigSchema.safeParse(raw);\n if (!result.success) {\n // One readable line per issue instead of zod's single JSON blob.\n const details = result.error.issues\n .map((issue) => {\n const where = issue.path.length > 0 ? issue.path.join(\".\") : \"(root)\";\n return ` ${where}: ${issue.message}`;\n })\n .join(\"\\n\");\n throw new Error(`Invalid config in ${filePath}:\\n${details}`);\n }\n warnUnknownKeys(raw, filePath, scope);\n return result.data;\n}\n\n// Keys a project-level .star/config.toml may set. Anything else (providers,\n// permissionMode, permissions, hooks, ...) stays global-only: a checked-out\n// repo must not be able to plant shell hooks, force yolo mode, or redirect\n// provider traffic to a key-harvesting endpoint.\nconst PROJECT_ALLOWED_KEYS = new Set([\n \"defaultModel\",\n \"models\",\n \"maxSteps\",\n \"contextMaxTokens\",\n \"compactThresholdTokens\",\n \"streamIdleTimeoutSec\",\n \"streamFirstChunkTimeoutSec\",\n \"streamMaxRetries\",\n \"maxAutoContinues\",\n \"contextCompaction\",\n \"sessionBudgetUsd\",\n \"notifyBell\",\n \"notifyBellThresholdSec\",\n \"doomLoopThreshold\",\n \"gitSnapshots\",\n]);\n\n// Safe ranges for the project-provided streaming knobs: a repo must not set\n// pathological values (sub-second idle timeouts, thousands of retries).\nconst PROJECT_STREAM_RANGES = {\n streamIdleTimeoutSec: { min: 5, max: 120 },\n streamFirstChunkTimeoutSec: { min: 30, max: 900 },\n streamMaxRetries: { min: 0, max: 10 },\n} as const;\n\n// 0 disables these protections, so a project may only tighten them, never\n// turn them off (handled at merge time via min()).\nconst PROJECT_PROTECTIVE_MIN_KEYS = new Set([\"maxSteps\", \"doomLoopThreshold\"]);\n\n// Known keys per schema-defined section, for the unknown-key diff.\nconst TOP_LEVEL_KEYS = new Set(Object.keys(ConfigSchema.shape));\nconst SECTION_KEYS: Record<string, { keys: Set<string>; array: boolean }> = {\n permissions: { keys: new Set(Object.keys(PermissionsConfigSchema.shape)), array: false },\n providers: { keys: new Set(Object.keys(ProviderConfigSchema.shape)), array: true },\n models: { keys: new Set(Object.keys(ModelConfigSchema.shape)), array: true },\n hooks: { keys: new Set(Object.keys(HookConfigSchema.shape)), array: true },\n};\n\nfunction editDistance(a: string, b: string): number {\n let previous: number[] = Array.from({ length: b.length + 1 }, (_, i) => i);\n for (let i = 1; i <= a.length; i++) {\n const current: number[] = [i];\n for (let j = 1; j <= b.length; j++) {\n current[j] = Math.min(\n (previous[j] ?? 0) + 1,\n (current[j - 1] ?? 0) + 1,\n (previous[j - 1] ?? 0) + (a[i - 1] === b[j - 1] ? 0 : 1),\n );\n }\n previous = current;\n }\n return previous[b.length] ?? 0;\n}\n\n// Cheap \"did you mean\": case-insensitive Levenshtein against the known keys,\n// accepted when the distance is small relative to the key's length.\nfunction suggestKey(key: string, known: Set<string>): string | undefined {\n const needle = key.toLowerCase();\n let best: string | undefined;\n let bestDistance = Number.POSITIVE_INFINITY;\n for (const candidate of known) {\n const distance = editDistance(needle, candidate.toLowerCase());\n if (distance <= Math.max(1, Math.floor(candidate.length / 4)) && distance < bestDistance) {\n best = candidate;\n bestDistance = distance;\n }\n }\n return best;\n}\n\nfunction warnUnknownKey(keyPath: string, filePath: string, known: Set<string>): void {\n const leaf = keyPath.slice(keyPath.lastIndexOf(\".\") + 1);\n const suggestion = suggestKey(leaf, known);\n const hint = suggestion\n ? `possible typo of \"${suggestion}\"? the key is ignored`\n : \"possible typo? the key is ignored\";\n process.stderr.write(`[star] unknown config key \"${keyPath}\" in ${filePath}: ${hint}\\n`);\n}\n\n// zod object schemas strip unknown keys without a word, so a misspelled\n// option (\"streamMaxRetreis\") would otherwise vanish silently. Diff the raw\n// TOML against the schema shapes and warn once per unknown key — top level\n// plus inside the schema-defined sections ([permissions], [[providers]],\n// [[models]], [[hooks]]). Warnings never block loading. In project files,\n// schema-known sections the sandbox drops wholesale (everything but\n// [[models]]) already get sanitizeProjectConfig's own warning, so their\n// inner keys are not diffed.\nfunction warnUnknownKeys(raw: unknown, filePath: string, scope: ConfigScope): void {\n if (typeof raw !== \"object\" || raw === null) return;\n const table = raw as Record<string, unknown>;\n for (const key of Object.keys(table)) {\n if (!TOP_LEVEL_KEYS.has(key)) warnUnknownKey(key, filePath, TOP_LEVEL_KEYS);\n }\n for (const [section, { keys, array }] of Object.entries(SECTION_KEYS)) {\n if (scope === \"project\" && !PROJECT_ALLOWED_KEYS.has(section)) continue;\n const value = table[section];\n if (array) {\n if (!Array.isArray(value)) continue;\n value.forEach((entry, index) => {\n if (typeof entry !== \"object\" || entry === null) return;\n for (const key of Object.keys(entry)) {\n if (!keys.has(key)) warnUnknownKey(`${section}[${index}].${key}`, filePath, keys);\n }\n });\n continue;\n }\n if (typeof value !== \"object\" || value === null) continue;\n for (const key of Object.keys(value as Record<string, unknown>)) {\n if (!keys.has(key)) warnUnknownKey(`${section}.${key}`, filePath, keys);\n }\n }\n}\n\nfunction warnProject(filePath: string, message: string): void {\n process.stderr.write(`[star] ${message} in ${filePath}\\n`);\n}\n\n// Price fields are stripped from project models: a repo defining $0 prices\n// would silently zero out /cost and defeat sessionBudgetUsd.\nfunction stripModelPrices(models: ModelConfig[], filePath: string): ModelConfig[] {\n let stripped = false;\n const out = models.map((model) => {\n const { promptPrice, completionPrice, cacheReadPrice, ...rest } = model;\n if (\n promptPrice !== undefined ||\n completionPrice !== undefined ||\n cacheReadPrice !== undefined\n ) {\n stripped = true;\n }\n return rest;\n });\n if (stripped) {\n warnProject(filePath, \"ignoring price fields in project [[models]]: pricing stays global-only\");\n }\n return out;\n}\n\nfunction sanitizeProjectConfig(project: PartialConfig, filePath: string): PartialConfig {\n const sanitized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(project)) {\n if (value === undefined) continue;\n if (!PROJECT_ALLOWED_KEYS.has(key)) {\n process.stderr.write(\n `[star] ignoring \"${key}\" in ${filePath}: project config cannot set this key\\n`,\n );\n continue;\n }\n if (key === \"gitSnapshots\" && value === false) {\n // Snapshot tracking protects /undo and /redo; a repo may enable but\n // never disable it.\n warnProject(\n filePath,\n 'ignoring \"gitSnapshots = false\": project config cannot disable this protection',\n );\n continue;\n }\n if (PROJECT_PROTECTIVE_MIN_KEYS.has(key) && value === 0) {\n warnProject(filePath, `ignoring \"${key} = 0\": project config cannot disable this protection`);\n continue;\n }\n const range = PROJECT_STREAM_RANGES[key as keyof typeof PROJECT_STREAM_RANGES];\n if (range && typeof value === \"number\") {\n const clamped = Math.min(range.max, Math.max(range.min, value));\n if (clamped !== value) {\n warnProject(\n filePath,\n `clamping \"${key}\" from ${value} to ${clamped}: project config is limited to ${range.min}–${range.max}`,\n );\n }\n sanitized[key] = clamped;\n continue;\n }\n if (key === \"models\" && Array.isArray(value)) {\n sanitized[key] = stripModelPrices(value as ModelConfig[], filePath);\n continue;\n }\n sanitized[key] = value;\n }\n return sanitized as PartialConfig;\n}\n\n// Project [[models]] merge with the global table by name: a project entry\n// replaces the same-named global entry, every other global entry survives.\n// (Shallow-spreading the array would let a repo silently swap the user's\n// whole model table — and orphan a global defaultModel pointing into it.)\nfunction mergeModelsByName(\n globalModels: ModelConfig[],\n projectModels: ModelConfig[],\n): ModelConfig[] {\n const projectByName = new Map(projectModels.map((model) => [model.name, model]));\n const merged = globalModels.map((model) => projectByName.get(model.name) ?? model);\n const globalNames = new Set(globalModels.map((model) => model.name));\n for (const model of projectModels) {\n if (!globalNames.has(model.name)) merged.push(model);\n }\n return merged;\n}\n\n// 0 disables these protections (unlimited), so normalize it to +∞ before the\n// min: a project must be able to tighten a globally-disabled guard (global\n// maxSteps = 0, project 5 → 5), never to relax one.\nfunction protectiveMin(a: number, b: number): number {\n const result = Math.min(\n a === 0 ? Number.POSITIVE_INFINITY : a,\n b === 0 ? Number.POSITIVE_INFINITY : b,\n );\n return result === Number.POSITIVE_INFINITY ? 0 : result;\n}\n\n// Project values merge protectively: a repo can tighten safeguards but never\n// relax them. Budgets take the lower bound; guard thresholds take the lower\n// bound too (a project-side 0 = disabled was already filtered out above, and\n// a global 0 normalizes to +∞ via protectiveMin).\nfunction mergeProjectConfig(\n global: PartialConfig,\n project: PartialConfig,\n projectPath: string,\n): PartialConfig {\n const merged: PartialConfig = { ...global, ...project };\n if (project.models !== undefined) {\n merged.models = mergeModelsByName(global.models ?? [], project.models);\n warnProject(projectPath, `project config overrides ${project.models.length} model(s)`);\n }\n if (project.sessionBudgetUsd !== undefined && global.sessionBudgetUsd !== undefined) {\n merged.sessionBudgetUsd = Math.min(global.sessionBudgetUsd, project.sessionBudgetUsd);\n }\n if (project.maxSteps !== undefined) {\n merged.maxSteps = protectiveMin(global.maxSteps ?? 0, project.maxSteps);\n }\n if (project.doomLoopThreshold !== undefined) {\n merged.doomLoopThreshold = protectiveMin(\n global.doomLoopThreshold ?? 3,\n project.doomLoopThreshold,\n );\n }\n return merged;\n}\n\n// Plaintext keys still work, but config.toml is world-readable by default on\n// some setups and gets committed by accident — point users at apiKeyEnv.\nfunction warnPlaintextApiKey(config: PartialConfig): void {\n const offenders: string[] = [];\n for (const provider of config.providers ?? []) {\n if (provider.apiKey !== undefined) offenders.push(`provider \"${provider.name}\"`);\n }\n for (const model of config.models ?? []) {\n if (\"apiKey\" in model && model.apiKey !== undefined) offenders.push(`model \"${model.name}\"`);\n }\n if (offenders.length === 0) return;\n process.stderr.write(\n `[star] plaintext apiKey in config (${offenders.join(\", \")}) is deprecated: store keys in ~/.star-cli/.env and reference them with apiKeyEnv instead\\n`,\n );\n}\n\nfunction applyOverrides(config: PartialConfig, overrides?: CliOverrides): PartialConfig {\n if (!overrides) return config;\n const merged = { ...config };\n if (overrides.model !== undefined) merged.defaultModel = overrides.model;\n if (overrides.permissionMode !== undefined) merged.permissionMode = overrides.permissionMode;\n return merged;\n}\n\nasync function readTomlFile(filePath: string, scope: ConfigScope): Promise<PartialConfig> {\n let content: string;\n try {\n content = await fs.promises.readFile(filePath, \"utf8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {};\n throw error;\n }\n return parseTomlFile(content, filePath, scope);\n}\n\nfunction readTomlFileSync(filePath: string, scope: ConfigScope): PartialConfig {\n if (!fs.existsSync(filePath)) return {};\n const content = fs.readFileSync(filePath, \"utf8\");\n return parseTomlFile(content, filePath, scope);\n}\n\nexport async function loadConfig(cwd: string, overrides?: CliOverrides): Promise<StarConfig> {\n loadEnvFile();\n const global = await readTomlFile(globalConfigPath(), \"global\");\n const projectPath = projectConfigPath(cwd);\n const project = sanitizeProjectConfig(await readTomlFile(projectPath, \"project\"), projectPath);\n const merged = applyOverrides(mergeProjectConfig(global, project, projectPath), overrides);\n warnPlaintextApiKey(merged);\n return wireRuntimeSettings(ConfigSchema.parse(merged));\n}\n\nexport function loadConfigSync(cwd: string, overrides?: CliOverrides): StarConfig {\n loadEnvFile();\n const global = readTomlFileSync(globalConfigPath(), \"global\");\n const projectPath = projectConfigPath(cwd);\n const project = sanitizeProjectConfig(readTomlFileSync(projectPath, \"project\"), projectPath);\n const merged = applyOverrides(mergeProjectConfig(global, project, projectPath), overrides);\n warnPlaintextApiKey(merged);\n return wireRuntimeSettings(ConfigSchema.parse(merged));\n}\n\n// Pushes config-driven security settings into their runtime consumers. The\n// merged permissions table is global-only at this point (the project sandbox\n// dropped any project-side [permissions]), so these can never be planted by\n// a checked-out repo.\nfunction wireRuntimeSettings(config: StarConfig): StarConfig {\n registerSensitivePatterns(config.permissions.sensitive);\n setWebFetchAllowPrivateHosts(config.webFetchAllowPrivateHosts);\n return config;\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|