@mariozechner/pi-coding-agent 0.28.0 → 0.29.1
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/CHANGELOG.md +27 -0
- package/README.md +28 -13
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +5 -5
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/custom-tools/loader.d.ts +5 -0
- package/dist/core/custom-tools/loader.d.ts.map +1 -1
- package/dist/core/custom-tools/loader.js +58 -3
- package/dist/core/custom-tools/loader.js.map +1 -1
- package/dist/core/custom-tools/types.d.ts +2 -2
- package/dist/core/custom-tools/types.d.ts.map +1 -1
- package/dist/core/custom-tools/types.js.map +1 -1
- package/dist/core/hooks/loader.d.ts.map +1 -1
- package/dist/core/hooks/loader.js +8 -1
- package/dist/core/hooks/loader.js.map +1 -1
- package/dist/core/hooks/types.d.ts +3 -3
- package/dist/core/hooks/types.d.ts.map +1 -1
- package/dist/core/hooks/types.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +19 -2
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +33 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-selector.js +164 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -5
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +73 -119
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +1 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +9 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/docs/custom-tools.md +3 -3
- package/docs/hooks.md +9 -9
- package/examples/hooks/confirm-destructive.ts +1 -1
- package/examples/hooks/dirty-repo-guard.ts +2 -6
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/hooks/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoRH,mEAAmE;AACnE,MAAM,UAAU,gBAAgB,CAAC,CAAkB,EAA4B;IAC9E,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;AAAA,CAC7B;AACD,MAAM,UAAU,gBAAgB,CAAC,CAAkB,EAA4B;IAC9E,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;AAAA,CAC7B;AACD,MAAM,UAAU,gBAAgB,CAAC,CAAkB,EAA4B;IAC9E,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;AAAA,CAC7B;AACD,MAAM,UAAU,iBAAiB,CAAC,CAAkB,EAA6B;IAChF,OAAO,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC;AAAA,CAC9B;AACD,MAAM,UAAU,gBAAgB,CAAC,CAAkB,EAA4B;IAC9E,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;AAAA,CAC7B;AACD,MAAM,UAAU,gBAAgB,CAAC,CAAkB,EAA4B;IAC9E,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;AAAA,CAC7B;AACD,MAAM,UAAU,cAAc,CAAC,CAAkB,EAA0B;IAC1E,OAAO,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC;AAAA,CAC3B","sourcesContent":["/**\n * Hook system types.\n *\n * Hooks are TypeScript modules that can subscribe to agent lifecycle events\n * and interact with the user via UI primitives.\n */\n\nimport type { AppMessage, Attachment } from \"@mariozechner/pi-agent-core\";\nimport type { ImageContent, Model, TextContent, ToolResultMessage } from \"@mariozechner/pi-ai\";\nimport type { CutPointResult } from \"../compaction.js\";\nimport type { CompactionEntry, SessionEntry } from \"../session-manager.js\";\nimport type {\n\tBashToolDetails,\n\tFindToolDetails,\n\tGrepToolDetails,\n\tLsToolDetails,\n\tReadToolDetails,\n} from \"../tools/index.js\";\n\n// ============================================================================\n// Execution Context\n// ============================================================================\n\n/**\n * Result of executing a command via ctx.exec()\n */\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n\tcode: number;\n\t/** True if the process was killed due to signal or timeout */\n\tkilled?: boolean;\n}\n\nexport interface ExecOptions {\n\t/** AbortSignal to cancel the process */\n\tsignal?: AbortSignal;\n\t/** Timeout in milliseconds */\n\ttimeout?: number;\n}\n\n/**\n * UI context for hooks to request interactive UI from the harness.\n * Each mode (interactive, RPC, print) provides its own implementation.\n */\nexport interface HookUIContext {\n\t/**\n\t * Show a selector and return the user's choice.\n\t * @param title - Title to display\n\t * @param options - Array of string options\n\t * @returns Selected option string, or null if cancelled\n\t */\n\tselect(title: string, options: string[]): Promise<string | null>;\n\n\t/**\n\t * Show a confirmation dialog.\n\t * @returns true if confirmed, false if cancelled\n\t */\n\tconfirm(title: string, message: string): Promise<boolean>;\n\n\t/**\n\t * Show a text input dialog.\n\t * @returns User input, or null if cancelled\n\t */\n\tinput(title: string, placeholder?: string): Promise<string | null>;\n\n\t/**\n\t * Show a notification to the user.\n\t */\n\tnotify(message: string, type?: \"info\" | \"warning\" | \"error\"): void;\n}\n\n/**\n * Context passed to hook event handlers.\n */\nexport interface HookEventContext {\n\t/** Execute a command and return stdout/stderr/code */\n\texec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;\n\t/** UI methods for user interaction */\n\tui: HookUIContext;\n\t/** Whether UI is available (false in print mode) */\n\thasUI: boolean;\n\t/** Current working directory */\n\tcwd: string;\n\t/** Path to session file, or null if --no-session */\n\tsessionFile: string | null;\n}\n\n// ============================================================================\n// Events\n// ============================================================================\n\n/**\n * Base fields shared by all session events.\n */\ninterface SessionEventBase {\n\ttype: \"session\";\n\t/** All session entries (including pre-compaction history) */\n\tentries: SessionEntry[];\n\t/** Current session file path, or null in --no-session mode */\n\tsessionFile: string | null;\n\t/** Previous session file path, or null for \"start\" and \"clear\" */\n\tpreviousSessionFile: string | null;\n}\n\n/**\n * Event data for session events.\n * Discriminated union based on reason.\n *\n * Lifecycle:\n * - start: Initial session load\n * - before_switch / switch: Session switch (e.g., /resume command)\n * - before_clear / clear: Session clear (e.g., /clear command)\n * - before_branch / branch: Session branch (e.g., /branch command)\n * - before_compact / compact: Before/after context compaction\n * - shutdown: Process exit (SIGINT/SIGTERM)\n *\n * \"before_*\" events fire before the action and can be cancelled via SessionEventResult.\n * Other events fire after the action completes.\n */\nexport type SessionEvent =\n\t| (SessionEventBase & {\n\t\t\treason: \"start\" | \"switch\" | \"clear\" | \"before_switch\" | \"before_clear\" | \"shutdown\";\n\t })\n\t| (SessionEventBase & {\n\t\t\treason: \"branch\" | \"before_branch\";\n\t\t\t/** Index of the turn to branch from */\n\t\t\ttargetTurnIndex: number;\n\t })\n\t| (SessionEventBase & {\n\t\t\treason: \"before_compact\";\n\t\t\tcutPoint: CutPointResult;\n\t\t\t/** Summary from previous compaction, if any. Include this in your summary to preserve context. */\n\t\t\tpreviousSummary?: string;\n\t\t\t/** Messages that will be summarized and discarded */\n\t\t\tmessagesToSummarize: AppMessage[];\n\t\t\t/** Messages that will be kept after the summary (recent turns) */\n\t\t\tmessagesToKeep: AppMessage[];\n\t\t\ttokensBefore: number;\n\t\t\tcustomInstructions?: string;\n\t\t\tmodel: Model<any>;\n\t\t\t/** Resolve API key for any model (checks settings, OAuth, env vars) */\n\t\t\tresolveApiKey: (model: Model<any>) => Promise<string | undefined>;\n\t\t\t/** Abort signal - hooks should pass this to LLM calls and check it periodically */\n\t\t\tsignal: AbortSignal;\n\t })\n\t| (SessionEventBase & {\n\t\t\treason: \"compact\";\n\t\t\tcompactionEntry: CompactionEntry;\n\t\t\ttokensBefore: number;\n\t\t\t/** Whether the compaction entry was provided by a hook */\n\t\t\tfromHook: boolean;\n\t });\n\n/**\n * Event data for agent_start event.\n * Fired when an agent loop starts (once per user prompt).\n */\nexport interface AgentStartEvent {\n\ttype: \"agent_start\";\n}\n\n/**\n * Event data for agent_end event.\n */\nexport interface AgentEndEvent {\n\ttype: \"agent_end\";\n\tmessages: AppMessage[];\n}\n\n/**\n * Event data for turn_start event.\n */\nexport interface TurnStartEvent {\n\ttype: \"turn_start\";\n\tturnIndex: number;\n\ttimestamp: number;\n}\n\n/**\n * Event data for turn_end event.\n */\nexport interface TurnEndEvent {\n\ttype: \"turn_end\";\n\tturnIndex: number;\n\tmessage: AppMessage;\n\ttoolResults: ToolResultMessage[];\n}\n\n/**\n * Event data for tool_call event.\n * Fired before a tool is executed. Hooks can block execution.\n */\nexport interface ToolCallEvent {\n\ttype: \"tool_call\";\n\t/** Tool name (e.g., \"bash\", \"edit\", \"write\") */\n\ttoolName: string;\n\t/** Tool call ID */\n\ttoolCallId: string;\n\t/** Tool input parameters */\n\tinput: Record<string, unknown>;\n}\n\n/**\n * Base interface for tool_result events.\n */\ninterface ToolResultEventBase {\n\ttype: \"tool_result\";\n\t/** Tool call ID */\n\ttoolCallId: string;\n\t/** Tool input parameters */\n\tinput: Record<string, unknown>;\n\t/** Full content array (text and images) */\n\tcontent: (TextContent | ImageContent)[];\n\t/** Whether the tool execution was an error */\n\tisError: boolean;\n}\n\n/** Tool result event for bash tool */\nexport interface BashToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"bash\";\n\tdetails: BashToolDetails | undefined;\n}\n\n/** Tool result event for read tool */\nexport interface ReadToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"read\";\n\tdetails: ReadToolDetails | undefined;\n}\n\n/** Tool result event for edit tool */\nexport interface EditToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"edit\";\n\tdetails: undefined;\n}\n\n/** Tool result event for write tool */\nexport interface WriteToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"write\";\n\tdetails: undefined;\n}\n\n/** Tool result event for grep tool */\nexport interface GrepToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"grep\";\n\tdetails: GrepToolDetails | undefined;\n}\n\n/** Tool result event for find tool */\nexport interface FindToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"find\";\n\tdetails: FindToolDetails | undefined;\n}\n\n/** Tool result event for ls tool */\nexport interface LsToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"ls\";\n\tdetails: LsToolDetails | undefined;\n}\n\n/** Tool result event for custom/unknown tools */\nexport interface CustomToolResultEvent extends ToolResultEventBase {\n\ttoolName: string;\n\tdetails: unknown;\n}\n\n/**\n * Event data for tool_result event.\n * Fired after a tool is executed. Hooks can modify the result.\n * Use toolName to discriminate and get typed details.\n */\nexport type ToolResultEvent =\n\t| BashToolResultEvent\n\t| ReadToolResultEvent\n\t| EditToolResultEvent\n\t| WriteToolResultEvent\n\t| GrepToolResultEvent\n\t| FindToolResultEvent\n\t| LsToolResultEvent\n\t| CustomToolResultEvent;\n\n// Type guards for narrowing ToolResultEvent to specific tool types\nexport function isBashToolResult(e: ToolResultEvent): e is BashToolResultEvent {\n\treturn e.toolName === \"bash\";\n}\nexport function isReadToolResult(e: ToolResultEvent): e is ReadToolResultEvent {\n\treturn e.toolName === \"read\";\n}\nexport function isEditToolResult(e: ToolResultEvent): e is EditToolResultEvent {\n\treturn e.toolName === \"edit\";\n}\nexport function isWriteToolResult(e: ToolResultEvent): e is WriteToolResultEvent {\n\treturn e.toolName === \"write\";\n}\nexport function isGrepToolResult(e: ToolResultEvent): e is GrepToolResultEvent {\n\treturn e.toolName === \"grep\";\n}\nexport function isFindToolResult(e: ToolResultEvent): e is FindToolResultEvent {\n\treturn e.toolName === \"find\";\n}\nexport function isLsToolResult(e: ToolResultEvent): e is LsToolResultEvent {\n\treturn e.toolName === \"ls\";\n}\n\n/**\n * Union of all hook event types.\n */\nexport type HookEvent =\n\t| SessionEvent\n\t| AgentStartEvent\n\t| AgentEndEvent\n\t| TurnStartEvent\n\t| TurnEndEvent\n\t| ToolCallEvent\n\t| ToolResultEvent;\n\n// ============================================================================\n// Event Results\n// ============================================================================\n\n/**\n * Return type for tool_call event handlers.\n * Allows hooks to block tool execution.\n */\nexport interface ToolCallEventResult {\n\t/** If true, block the tool from executing */\n\tblock?: boolean;\n\t/** Reason for blocking (returned to LLM as error) */\n\treason?: string;\n}\n\n/**\n * Return type for tool_result event handlers.\n * Allows hooks to modify tool results.\n */\nexport interface ToolResultEventResult {\n\t/** Replacement content array (text and images) */\n\tcontent?: (TextContent | ImageContent)[];\n\t/** Replacement details */\n\tdetails?: unknown;\n\t/** Override isError flag */\n\tisError?: boolean;\n}\n\n/**\n * Return type for session event handlers.\n * Allows hooks to cancel \"before_*\" actions.\n */\nexport interface SessionEventResult {\n\t/** If true, cancel the pending action (switch, clear, or branch) */\n\tcancel?: boolean;\n\t/** If true (for before_branch only), skip restoring conversation to branch point while still creating the branched session file */\n\tskipConversationRestore?: boolean;\n\t/** Custom compaction entry (for before_compact event) */\n\tcompactionEntry?: CompactionEntry;\n}\n\n// ============================================================================\n// Hook API\n// ============================================================================\n\n/**\n * Handler function type for each event.\n */\nexport type HookHandler<E, R = void> = (event: E, ctx: HookEventContext) => Promise<R>;\n\n/**\n * HookAPI passed to hook factory functions.\n * Hooks use pi.on() to subscribe to events and pi.send() to inject messages.\n */\nexport interface HookAPI {\n\t// biome-ignore lint/suspicious/noConfusingVoidType: void allows handlers to not return anything\n\ton(event: \"session\", handler: HookHandler<SessionEvent, SessionEventResult | void>): void;\n\ton(event: \"agent_start\", handler: HookHandler<AgentStartEvent>): void;\n\ton(event: \"agent_end\", handler: HookHandler<AgentEndEvent>): void;\n\ton(event: \"turn_start\", handler: HookHandler<TurnStartEvent>): void;\n\ton(event: \"turn_end\", handler: HookHandler<TurnEndEvent>): void;\n\ton(event: \"tool_call\", handler: HookHandler<ToolCallEvent, ToolCallEventResult | undefined>): void;\n\ton(event: \"tool_result\", handler: HookHandler<ToolResultEvent, ToolResultEventResult | undefined>): void;\n\n\t/**\n\t * Send a message to the agent.\n\t * If the agent is streaming, the message is queued.\n\t * If the agent is idle, a new agent loop is started.\n\t */\n\tsend(text: string, attachments?: Attachment[]): void;\n}\n\n/**\n * Hook factory function type.\n * Hooks export a default function that receives the HookAPI.\n */\nexport type HookFactory = (pi: HookAPI) => void;\n\n// ============================================================================\n// Errors\n// ============================================================================\n\n/**\n * Error emitted when a hook fails.\n */\nexport interface HookError {\n\thookPath: string;\n\tevent: string;\n\terror: string;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/hooks/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoRH,mEAAmE;AACnE,MAAM,UAAU,gBAAgB,CAAC,CAAkB,EAA4B;IAC9E,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;AAAA,CAC7B;AACD,MAAM,UAAU,gBAAgB,CAAC,CAAkB,EAA4B;IAC9E,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;AAAA,CAC7B;AACD,MAAM,UAAU,gBAAgB,CAAC,CAAkB,EAA4B;IAC9E,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;AAAA,CAC7B;AACD,MAAM,UAAU,iBAAiB,CAAC,CAAkB,EAA6B;IAChF,OAAO,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC;AAAA,CAC9B;AACD,MAAM,UAAU,gBAAgB,CAAC,CAAkB,EAA4B;IAC9E,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;AAAA,CAC7B;AACD,MAAM,UAAU,gBAAgB,CAAC,CAAkB,EAA4B;IAC9E,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;AAAA,CAC7B;AACD,MAAM,UAAU,cAAc,CAAC,CAAkB,EAA0B;IAC1E,OAAO,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC;AAAA,CAC3B","sourcesContent":["/**\n * Hook system types.\n *\n * Hooks are TypeScript modules that can subscribe to agent lifecycle events\n * and interact with the user via UI primitives.\n */\n\nimport type { AppMessage, Attachment } from \"@mariozechner/pi-agent-core\";\nimport type { ImageContent, Model, TextContent, ToolResultMessage } from \"@mariozechner/pi-ai\";\nimport type { CutPointResult } from \"../compaction.js\";\nimport type { CompactionEntry, SessionEntry } from \"../session-manager.js\";\nimport type {\n\tBashToolDetails,\n\tFindToolDetails,\n\tGrepToolDetails,\n\tLsToolDetails,\n\tReadToolDetails,\n} from \"../tools/index.js\";\n\n// ============================================================================\n// Execution Context\n// ============================================================================\n\n/**\n * Result of executing a command via ctx.exec()\n */\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n\tcode: number;\n\t/** True if the process was killed due to signal or timeout */\n\tkilled?: boolean;\n}\n\nexport interface ExecOptions {\n\t/** AbortSignal to cancel the process */\n\tsignal?: AbortSignal;\n\t/** Timeout in milliseconds */\n\ttimeout?: number;\n}\n\n/**\n * UI context for hooks to request interactive UI from the harness.\n * Each mode (interactive, RPC, print) provides its own implementation.\n */\nexport interface HookUIContext {\n\t/**\n\t * Show a selector and return the user's choice.\n\t * @param title - Title to display\n\t * @param options - Array of string options\n\t * @returns Selected option string, or null if cancelled\n\t */\n\tselect(title: string, options: string[]): Promise<string | null>;\n\n\t/**\n\t * Show a confirmation dialog.\n\t * @returns true if confirmed, false if cancelled\n\t */\n\tconfirm(title: string, message: string): Promise<boolean>;\n\n\t/**\n\t * Show a text input dialog.\n\t * @returns User input, or null if cancelled\n\t */\n\tinput(title: string, placeholder?: string): Promise<string | null>;\n\n\t/**\n\t * Show a notification to the user.\n\t */\n\tnotify(message: string, type?: \"info\" | \"warning\" | \"error\"): void;\n}\n\n/**\n * Context passed to hook event handlers.\n */\nexport interface HookEventContext {\n\t/** Execute a command and return stdout/stderr/code */\n\texec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;\n\t/** UI methods for user interaction */\n\tui: HookUIContext;\n\t/** Whether UI is available (false in print mode) */\n\thasUI: boolean;\n\t/** Current working directory */\n\tcwd: string;\n\t/** Path to session file, or null if --no-session */\n\tsessionFile: string | null;\n}\n\n// ============================================================================\n// Events\n// ============================================================================\n\n/**\n * Base fields shared by all session events.\n */\ninterface SessionEventBase {\n\ttype: \"session\";\n\t/** All session entries (including pre-compaction history) */\n\tentries: SessionEntry[];\n\t/** Current session file path, or null in --no-session mode */\n\tsessionFile: string | null;\n\t/** Previous session file path, or null for \"start\" and \"new\" */\n\tpreviousSessionFile: string | null;\n}\n\n/**\n * Event data for session events.\n * Discriminated union based on reason.\n *\n * Lifecycle:\n * - start: Initial session load\n * - before_switch / switch: Session switch (e.g., /resume command)\n * - before_new / new: New session (e.g., /new command)\n * - before_branch / branch: Session branch (e.g., /branch command)\n * - before_compact / compact: Before/after context compaction\n * - shutdown: Process exit (SIGINT/SIGTERM)\n *\n * \"before_*\" events fire before the action and can be cancelled via SessionEventResult.\n * Other events fire after the action completes.\n */\nexport type SessionEvent =\n\t| (SessionEventBase & {\n\t\t\treason: \"start\" | \"switch\" | \"new\" | \"before_switch\" | \"before_new\" | \"shutdown\";\n\t })\n\t| (SessionEventBase & {\n\t\t\treason: \"branch\" | \"before_branch\";\n\t\t\t/** Index of the turn to branch from */\n\t\t\ttargetTurnIndex: number;\n\t })\n\t| (SessionEventBase & {\n\t\t\treason: \"before_compact\";\n\t\t\tcutPoint: CutPointResult;\n\t\t\t/** Summary from previous compaction, if any. Include this in your summary to preserve context. */\n\t\t\tpreviousSummary?: string;\n\t\t\t/** Messages that will be summarized and discarded */\n\t\t\tmessagesToSummarize: AppMessage[];\n\t\t\t/** Messages that will be kept after the summary (recent turns) */\n\t\t\tmessagesToKeep: AppMessage[];\n\t\t\ttokensBefore: number;\n\t\t\tcustomInstructions?: string;\n\t\t\tmodel: Model<any>;\n\t\t\t/** Resolve API key for any model (checks settings, OAuth, env vars) */\n\t\t\tresolveApiKey: (model: Model<any>) => Promise<string | undefined>;\n\t\t\t/** Abort signal - hooks should pass this to LLM calls and check it periodically */\n\t\t\tsignal: AbortSignal;\n\t })\n\t| (SessionEventBase & {\n\t\t\treason: \"compact\";\n\t\t\tcompactionEntry: CompactionEntry;\n\t\t\ttokensBefore: number;\n\t\t\t/** Whether the compaction entry was provided by a hook */\n\t\t\tfromHook: boolean;\n\t });\n\n/**\n * Event data for agent_start event.\n * Fired when an agent loop starts (once per user prompt).\n */\nexport interface AgentStartEvent {\n\ttype: \"agent_start\";\n}\n\n/**\n * Event data for agent_end event.\n */\nexport interface AgentEndEvent {\n\ttype: \"agent_end\";\n\tmessages: AppMessage[];\n}\n\n/**\n * Event data for turn_start event.\n */\nexport interface TurnStartEvent {\n\ttype: \"turn_start\";\n\tturnIndex: number;\n\ttimestamp: number;\n}\n\n/**\n * Event data for turn_end event.\n */\nexport interface TurnEndEvent {\n\ttype: \"turn_end\";\n\tturnIndex: number;\n\tmessage: AppMessage;\n\ttoolResults: ToolResultMessage[];\n}\n\n/**\n * Event data for tool_call event.\n * Fired before a tool is executed. Hooks can block execution.\n */\nexport interface ToolCallEvent {\n\ttype: \"tool_call\";\n\t/** Tool name (e.g., \"bash\", \"edit\", \"write\") */\n\ttoolName: string;\n\t/** Tool call ID */\n\ttoolCallId: string;\n\t/** Tool input parameters */\n\tinput: Record<string, unknown>;\n}\n\n/**\n * Base interface for tool_result events.\n */\ninterface ToolResultEventBase {\n\ttype: \"tool_result\";\n\t/** Tool call ID */\n\ttoolCallId: string;\n\t/** Tool input parameters */\n\tinput: Record<string, unknown>;\n\t/** Full content array (text and images) */\n\tcontent: (TextContent | ImageContent)[];\n\t/** Whether the tool execution was an error */\n\tisError: boolean;\n}\n\n/** Tool result event for bash tool */\nexport interface BashToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"bash\";\n\tdetails: BashToolDetails | undefined;\n}\n\n/** Tool result event for read tool */\nexport interface ReadToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"read\";\n\tdetails: ReadToolDetails | undefined;\n}\n\n/** Tool result event for edit tool */\nexport interface EditToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"edit\";\n\tdetails: undefined;\n}\n\n/** Tool result event for write tool */\nexport interface WriteToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"write\";\n\tdetails: undefined;\n}\n\n/** Tool result event for grep tool */\nexport interface GrepToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"grep\";\n\tdetails: GrepToolDetails | undefined;\n}\n\n/** Tool result event for find tool */\nexport interface FindToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"find\";\n\tdetails: FindToolDetails | undefined;\n}\n\n/** Tool result event for ls tool */\nexport interface LsToolResultEvent extends ToolResultEventBase {\n\ttoolName: \"ls\";\n\tdetails: LsToolDetails | undefined;\n}\n\n/** Tool result event for custom/unknown tools */\nexport interface CustomToolResultEvent extends ToolResultEventBase {\n\ttoolName: string;\n\tdetails: unknown;\n}\n\n/**\n * Event data for tool_result event.\n * Fired after a tool is executed. Hooks can modify the result.\n * Use toolName to discriminate and get typed details.\n */\nexport type ToolResultEvent =\n\t| BashToolResultEvent\n\t| ReadToolResultEvent\n\t| EditToolResultEvent\n\t| WriteToolResultEvent\n\t| GrepToolResultEvent\n\t| FindToolResultEvent\n\t| LsToolResultEvent\n\t| CustomToolResultEvent;\n\n// Type guards for narrowing ToolResultEvent to specific tool types\nexport function isBashToolResult(e: ToolResultEvent): e is BashToolResultEvent {\n\treturn e.toolName === \"bash\";\n}\nexport function isReadToolResult(e: ToolResultEvent): e is ReadToolResultEvent {\n\treturn e.toolName === \"read\";\n}\nexport function isEditToolResult(e: ToolResultEvent): e is EditToolResultEvent {\n\treturn e.toolName === \"edit\";\n}\nexport function isWriteToolResult(e: ToolResultEvent): e is WriteToolResultEvent {\n\treturn e.toolName === \"write\";\n}\nexport function isGrepToolResult(e: ToolResultEvent): e is GrepToolResultEvent {\n\treturn e.toolName === \"grep\";\n}\nexport function isFindToolResult(e: ToolResultEvent): e is FindToolResultEvent {\n\treturn e.toolName === \"find\";\n}\nexport function isLsToolResult(e: ToolResultEvent): e is LsToolResultEvent {\n\treturn e.toolName === \"ls\";\n}\n\n/**\n * Union of all hook event types.\n */\nexport type HookEvent =\n\t| SessionEvent\n\t| AgentStartEvent\n\t| AgentEndEvent\n\t| TurnStartEvent\n\t| TurnEndEvent\n\t| ToolCallEvent\n\t| ToolResultEvent;\n\n// ============================================================================\n// Event Results\n// ============================================================================\n\n/**\n * Return type for tool_call event handlers.\n * Allows hooks to block tool execution.\n */\nexport interface ToolCallEventResult {\n\t/** If true, block the tool from executing */\n\tblock?: boolean;\n\t/** Reason for blocking (returned to LLM as error) */\n\treason?: string;\n}\n\n/**\n * Return type for tool_result event handlers.\n * Allows hooks to modify tool results.\n */\nexport interface ToolResultEventResult {\n\t/** Replacement content array (text and images) */\n\tcontent?: (TextContent | ImageContent)[];\n\t/** Replacement details */\n\tdetails?: unknown;\n\t/** Override isError flag */\n\tisError?: boolean;\n}\n\n/**\n * Return type for session event handlers.\n * Allows hooks to cancel \"before_*\" actions.\n */\nexport interface SessionEventResult {\n\t/** If true, cancel the pending action (switch, clear, or branch) */\n\tcancel?: boolean;\n\t/** If true (for before_branch only), skip restoring conversation to branch point while still creating the branched session file */\n\tskipConversationRestore?: boolean;\n\t/** Custom compaction entry (for before_compact event) */\n\tcompactionEntry?: CompactionEntry;\n}\n\n// ============================================================================\n// Hook API\n// ============================================================================\n\n/**\n * Handler function type for each event.\n */\nexport type HookHandler<E, R = void> = (event: E, ctx: HookEventContext) => Promise<R>;\n\n/**\n * HookAPI passed to hook factory functions.\n * Hooks use pi.on() to subscribe to events and pi.send() to inject messages.\n */\nexport interface HookAPI {\n\t// biome-ignore lint/suspicious/noConfusingVoidType: void allows handlers to not return anything\n\ton(event: \"session\", handler: HookHandler<SessionEvent, SessionEventResult | void>): void;\n\ton(event: \"agent_start\", handler: HookHandler<AgentStartEvent>): void;\n\ton(event: \"agent_end\", handler: HookHandler<AgentEndEvent>): void;\n\ton(event: \"turn_start\", handler: HookHandler<TurnStartEvent>): void;\n\ton(event: \"turn_end\", handler: HookHandler<TurnEndEvent>): void;\n\ton(event: \"tool_call\", handler: HookHandler<ToolCallEvent, ToolCallEventResult | undefined>): void;\n\ton(event: \"tool_result\", handler: HookHandler<ToolResultEvent, ToolResultEventResult | undefined>): void;\n\n\t/**\n\t * Send a message to the agent.\n\t * If the agent is streaming, the message is queued.\n\t * If the agent is idle, a new agent loop is started.\n\t */\n\tsend(text: string, attachments?: Attachment[]): void;\n}\n\n/**\n * Hook factory function type.\n * Hooks export a default function that receives the HookAPI.\n */\nexport type HookFactory = (pi: HookAPI) => void;\n\n// ============================================================================\n// Errors\n// ============================================================================\n\n/**\n * Error emitted when a hook fails.\n */\nexport interface HookError {\n\thookPath: string;\n\tevent: string;\n\terror: string;\n}\n"]}
|
package/dist/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA6PH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,iBAwKxC","sourcesContent":["/**\n * Main entry point for the coding agent CLI.\n *\n * This file handles CLI argument parsing and translates them into\n * createAgentSession() options. The SDK does the heavy lifting.\n */\n\nimport type { Attachment } from \"@mariozechner/pi-agent-core\";\nimport { supportsXhigh } from \"@mariozechner/pi-ai\";\nimport chalk from \"chalk\";\nimport { join } from \"path\";\nimport { type Args, parseArgs, printHelp } from \"./cli/args.js\";\nimport { processFileArguments } from \"./cli/file-processor.js\";\nimport { listModels } from \"./cli/list-models.js\";\nimport { selectSession } from \"./cli/session-picker.js\";\nimport { getAgentDir, getModelsPath, VERSION } from \"./config.js\";\nimport type { AgentSession } from \"./core/agent-session.js\";\nimport { AuthStorage } from \"./core/auth-storage.js\";\nimport type { LoadedCustomTool } from \"./core/custom-tools/index.js\";\nimport { exportFromFile } from \"./core/export-html.js\";\nimport type { HookUIContext } from \"./core/index.js\";\nimport type { ModelRegistry } from \"./core/model-registry.js\";\nimport { resolveModelScope, type ScopedModel } from \"./core/model-resolver.js\";\nimport { type CreateAgentSessionOptions, createAgentSession, discoverAuthStorage, discoverModels } from \"./core/sdk.js\";\nimport { SessionManager } from \"./core/session-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\nimport { resolvePromptInput } from \"./core/system-prompt.js\";\nimport { printTimings, time } from \"./core/timings.js\";\nimport { allTools } from \"./core/tools/index.js\";\nimport { InteractiveMode, runPrintMode, runRpcMode } from \"./modes/index.js\";\nimport { initTheme, stopThemeWatcher } from \"./modes/interactive/theme/theme.js\";\nimport { getChangelogPath, getNewEntries, parseChangelog } from \"./utils/changelog.js\";\nimport { ensureTool } from \"./utils/tools-manager.js\";\n\nasync function checkForNewVersion(currentVersion: string): Promise<string | null> {\n\ttry {\n\t\tconst response = await fetch(\"https://registry.npmjs.org/@mariozechner/pi -coding-agent/latest\");\n\t\tif (!response.ok) return null;\n\n\t\tconst data = (await response.json()) as { version?: string };\n\t\tconst latestVersion = data.version;\n\n\t\tif (latestVersion && latestVersion !== currentVersion) {\n\t\t\treturn latestVersion;\n\t\t}\n\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function runInteractiveMode(\n\tsession: AgentSession,\n\tversion: string,\n\tchangelogMarkdown: string | null,\n\tmodelFallbackMessage: string | undefined,\n\tmodelsJsonError: string | null,\n\tmigratedProviders: string[],\n\tversionCheckPromise: Promise<string | null>,\n\tinitialMessages: string[],\n\tcustomTools: LoadedCustomTool[],\n\tsetToolUIContext: (uiContext: HookUIContext, hasUI: boolean) => void,\n\tinitialMessage?: string,\n\tinitialAttachments?: Attachment[],\n\tfdPath: string | null = null,\n): Promise<void> {\n\tconst mode = new InteractiveMode(session, version, changelogMarkdown, customTools, setToolUIContext, fdPath);\n\n\tawait mode.init();\n\n\tversionCheckPromise.then((newVersion) => {\n\t\tif (newVersion) {\n\t\t\tmode.showNewVersionNotification(newVersion);\n\t\t}\n\t});\n\n\tmode.renderInitialMessages(session.state);\n\n\tif (migratedProviders.length > 0) {\n\t\tmode.showWarning(`Migrated credentials to auth.json: ${migratedProviders.join(\", \")}`);\n\t}\n\n\tif (modelsJsonError) {\n\t\tmode.showError(`models.json error: ${modelsJsonError}`);\n\t}\n\n\tif (modelFallbackMessage) {\n\t\tmode.showWarning(modelFallbackMessage);\n\t}\n\n\tif (initialMessage) {\n\t\ttry {\n\t\t\tawait session.prompt(initialMessage, { attachments: initialAttachments });\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\tfor (const message of initialMessages) {\n\t\ttry {\n\t\t\tawait session.prompt(message);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\twhile (true) {\n\t\tconst userInput = await mode.getUserInput();\n\t\ttry {\n\t\t\tawait session.prompt(userInput);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n}\n\nasync function prepareInitialMessage(parsed: Args): Promise<{\n\tinitialMessage?: string;\n\tinitialAttachments?: Attachment[];\n}> {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn {};\n\t}\n\n\tconst { textContent, imageAttachments } = await processFileArguments(parsed.fileArgs);\n\n\tlet initialMessage: string;\n\tif (parsed.messages.length > 0) {\n\t\tinitialMessage = textContent + parsed.messages[0];\n\t\tparsed.messages.shift();\n\t} else {\n\t\tinitialMessage = textContent;\n\t}\n\n\treturn {\n\t\tinitialMessage,\n\t\tinitialAttachments: imageAttachments.length > 0 ? imageAttachments : undefined,\n\t};\n}\n\nfunction getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): string | null {\n\tif (parsed.continue || parsed.resume) {\n\t\treturn null;\n\t}\n\n\tconst lastVersion = settingsManager.getLastChangelogVersion();\n\tconst changelogPath = getChangelogPath();\n\tconst entries = parseChangelog(changelogPath);\n\n\tif (!lastVersion) {\n\t\tif (entries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn entries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t} else {\n\t\tconst newEntries = getNewEntries(entries, lastVersion);\n\t\tif (newEntries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn newEntries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t}\n\n\treturn null;\n}\n\nfunction createSessionManager(parsed: Args, cwd: string): SessionManager | null {\n\tif (parsed.noSession) {\n\t\treturn SessionManager.inMemory();\n\t}\n\tif (parsed.session) {\n\t\treturn SessionManager.open(parsed.session);\n\t}\n\tif (parsed.continue) {\n\t\treturn SessionManager.continueRecent(cwd);\n\t}\n\t// --resume is handled separately (needs picker UI)\n\t// Default case (new session) returns null, SDK will create one\n\treturn null;\n}\n\nfunction buildSessionOptions(\n\tparsed: Args,\n\tscopedModels: ScopedModel[],\n\tsessionManager: SessionManager | null,\n\tmodelRegistry: ModelRegistry,\n): CreateAgentSessionOptions {\n\tconst options: CreateAgentSessionOptions = {};\n\n\tconst resolvedSystemPrompt = resolvePromptInput(parsed.systemPrompt, \"system prompt\");\n\tconst resolvedAppendPrompt = resolvePromptInput(parsed.appendSystemPrompt, \"append system prompt\");\n\n\tif (sessionManager) {\n\t\toptions.sessionManager = sessionManager;\n\t}\n\n\t// Model from CLI\n\tif (parsed.provider && parsed.model) {\n\t\tconst model = modelRegistry.find(parsed.provider, parsed.model);\n\t\tif (!model) {\n\t\t\tconsole.error(chalk.red(`Model ${parsed.provider}/${parsed.model} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\toptions.model = model;\n\t} else if (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\toptions.model = scopedModels[0].model;\n\t}\n\n\t// Thinking level\n\tif (parsed.thinking) {\n\t\toptions.thinkingLevel = parsed.thinking;\n\t} else if (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\toptions.thinkingLevel = scopedModels[0].thinkingLevel;\n\t}\n\n\t// Scoped models for Ctrl+P cycling\n\tif (scopedModels.length > 0) {\n\t\toptions.scopedModels = scopedModels;\n\t}\n\n\t// API key from CLI - set in authStorage\n\t// (handled by caller before createAgentSession)\n\n\t// System prompt\n\tif (resolvedSystemPrompt && resolvedAppendPrompt) {\n\t\toptions.systemPrompt = `${resolvedSystemPrompt}\\n\\n${resolvedAppendPrompt}`;\n\t} else if (resolvedSystemPrompt) {\n\t\toptions.systemPrompt = resolvedSystemPrompt;\n\t} else if (resolvedAppendPrompt) {\n\t\toptions.systemPrompt = (defaultPrompt) => `${defaultPrompt}\\n\\n${resolvedAppendPrompt}`;\n\t}\n\n\t// Tools\n\tif (parsed.tools) {\n\t\toptions.tools = parsed.tools.map((name) => allTools[name]);\n\t}\n\n\t// Skills\n\tif (parsed.noSkills) {\n\t\toptions.skills = [];\n\t}\n\n\t// Additional hook paths from CLI\n\tif (parsed.hooks && parsed.hooks.length > 0) {\n\t\toptions.additionalHookPaths = parsed.hooks;\n\t}\n\n\t// Additional custom tool paths from CLI\n\tif (parsed.customTools && parsed.customTools.length > 0) {\n\t\toptions.additionalCustomToolPaths = parsed.customTools;\n\t}\n\n\treturn options;\n}\n\nexport async function main(args: string[]) {\n\ttime(\"start\");\n\n\t// Migrate legacy oauth.json and settings.json apiKeys to auth.json\n\tconst agentDir = getAgentDir();\n\tconst migratedProviders = AuthStorage.migrateLegacy(join(agentDir, \"auth.json\"), agentDir);\n\n\t// Create AuthStorage and ModelRegistry upfront\n\tconst authStorage = discoverAuthStorage();\n\tconst modelRegistry = discoverModels(authStorage);\n\ttime(\"discoverModels\");\n\n\tconst parsed = parseArgs(args);\n\ttime(\"parseArgs\");\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\tif (parsed.listModels !== undefined) {\n\t\tconst searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : undefined;\n\t\tawait listModels(modelRegistry, searchPattern);\n\t\treturn;\n\t}\n\n\tif (parsed.export) {\n\t\ttry {\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tconst result = exportFromFile(parsed.export, outputPath);\n\t\t\tconsole.log(`Exported to: ${result}`);\n\t\t\treturn;\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tconst cwd = process.cwd();\n\tconst { initialMessage, initialAttachments } = await prepareInitialMessage(parsed);\n\ttime(\"prepareInitialMessage\");\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\tconst mode = parsed.mode || \"text\";\n\n\tconst settingsManager = SettingsManager.create(cwd);\n\ttime(\"SettingsManager.create\");\n\tinitTheme(settingsManager.getTheme(), isInteractive);\n\ttime(\"initTheme\");\n\n\tlet scopedModels: ScopedModel[] = [];\n\tif (parsed.models && parsed.models.length > 0) {\n\t\tscopedModels = await resolveModelScope(parsed.models, modelRegistry);\n\t\ttime(\"resolveModelScope\");\n\t}\n\n\t// Create session manager based on CLI flags\n\tlet sessionManager = createSessionManager(parsed, cwd);\n\ttime(\"createSessionManager\");\n\n\t// Handle --resume: show session picker\n\tif (parsed.resume) {\n\t\tconst sessions = SessionManager.list(cwd);\n\t\ttime(\"SessionManager.list\");\n\t\tif (sessions.length === 0) {\n\t\t\tconsole.log(chalk.dim(\"No sessions found\"));\n\t\t\treturn;\n\t\t}\n\t\tconst selectedPath = await selectSession(sessions);\n\t\ttime(\"selectSession\");\n\t\tif (!selectedPath) {\n\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\treturn;\n\t\t}\n\t\tsessionManager = SessionManager.open(selectedPath);\n\t}\n\n\tconst sessionOptions = buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry);\n\tsessionOptions.authStorage = authStorage;\n\tsessionOptions.modelRegistry = modelRegistry;\n\n\t// Handle CLI --api-key as runtime override (not persisted)\n\tif (parsed.apiKey) {\n\t\tif (!sessionOptions.model) {\n\t\t\tconsole.error(chalk.red(\"--api-key requires a model to be specified via --provider/--model or -m/--models\"));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tauthStorage.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);\n\t}\n\n\ttime(\"buildSessionOptions\");\n\tconst { session, customToolsResult, modelFallbackMessage } = await createAgentSession(sessionOptions);\n\ttime(\"createAgentSession\");\n\n\tif (!isInteractive && !session.model) {\n\t\tconsole.error(chalk.red(\"No models available.\"));\n\t\tconsole.error(chalk.yellow(\"\\nSet an API key environment variable:\"));\n\t\tconsole.error(\" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\");\n\t\tconsole.error(chalk.yellow(`\\nOr create ${getModelsPath()}`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Clamp thinking level to model capabilities (for CLI override case)\n\tif (session.model && parsed.thinking) {\n\t\tlet effectiveThinking = parsed.thinking;\n\t\tif (!session.model.reasoning) {\n\t\t\teffectiveThinking = \"off\";\n\t\t} else if (effectiveThinking === \"xhigh\" && !supportsXhigh(session.model)) {\n\t\t\teffectiveThinking = \"high\";\n\t\t}\n\t\tif (effectiveThinking !== session.thinkingLevel) {\n\t\t\tsession.setThinkingLevel(effectiveThinking);\n\t\t}\n\t}\n\n\tif (mode === \"rpc\") {\n\t\tawait runRpcMode(session);\n\t} else if (isInteractive) {\n\t\tconst versionCheckPromise = checkForNewVersion(VERSION).catch(() => null);\n\t\tconst changelogMarkdown = getChangelogForDisplay(parsed, settingsManager);\n\n\t\tif (scopedModels.length > 0) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel !== \"off\" ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\tconst fdPath = await ensureTool(\"fd\");\n\t\ttime(\"ensureTool(fd)\");\n\n\t\tprintTimings();\n\t\tawait runInteractiveMode(\n\t\t\tsession,\n\t\t\tVERSION,\n\t\t\tchangelogMarkdown,\n\t\t\tmodelFallbackMessage,\n\t\t\tmodelRegistry.getError(),\n\t\t\tmigratedProviders,\n\t\t\tversionCheckPromise,\n\t\t\tparsed.messages,\n\t\t\tcustomToolsResult.tools,\n\t\t\tcustomToolsResult.setUIContext,\n\t\t\tinitialMessage,\n\t\t\tinitialAttachments,\n\t\t\tfdPath,\n\t\t);\n\t} else {\n\t\tawait runPrintMode(session, mode, parsed.messages, initialMessage, initialAttachments);\n\t\tstopThemeWatcher();\n\t\tif (process.stdout.writableLength > 0) {\n\t\t\tawait new Promise<void>((resolve) => process.stdout.once(\"drain\", resolve));\n\t\t}\n\t\tprocess.exit(0);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiRH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,iBAwKxC","sourcesContent":["/**\n * Main entry point for the coding agent CLI.\n *\n * This file handles CLI argument parsing and translates them into\n * createAgentSession() options. The SDK does the heavy lifting.\n */\n\nimport type { Attachment } from \"@mariozechner/pi-agent-core\";\nimport { supportsXhigh } from \"@mariozechner/pi-ai\";\nimport chalk from \"chalk\";\nimport { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport { type Args, parseArgs, printHelp } from \"./cli/args.js\";\nimport { processFileArguments } from \"./cli/file-processor.js\";\nimport { listModels } from \"./cli/list-models.js\";\nimport { selectSession } from \"./cli/session-picker.js\";\nimport { CONFIG_DIR_NAME, getAgentDir, getModelsPath, VERSION } from \"./config.js\";\nimport type { AgentSession } from \"./core/agent-session.js\";\nimport { AuthStorage } from \"./core/auth-storage.js\";\nimport type { LoadedCustomTool } from \"./core/custom-tools/index.js\";\nimport { exportFromFile } from \"./core/export-html.js\";\nimport type { HookUIContext } from \"./core/index.js\";\nimport type { ModelRegistry } from \"./core/model-registry.js\";\nimport { resolveModelScope, type ScopedModel } from \"./core/model-resolver.js\";\nimport { type CreateAgentSessionOptions, createAgentSession, discoverAuthStorage, discoverModels } from \"./core/sdk.js\";\nimport { SessionManager } from \"./core/session-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\nimport { resolvePromptInput } from \"./core/system-prompt.js\";\nimport { printTimings, time } from \"./core/timings.js\";\nimport { allTools } from \"./core/tools/index.js\";\nimport { InteractiveMode, runPrintMode, runRpcMode } from \"./modes/index.js\";\nimport { initTheme, stopThemeWatcher } from \"./modes/interactive/theme/theme.js\";\nimport { getChangelogPath, getNewEntries, parseChangelog } from \"./utils/changelog.js\";\nimport { ensureTool } from \"./utils/tools-manager.js\";\n\nasync function checkForNewVersion(currentVersion: string): Promise<string | null> {\n\ttry {\n\t\tconst response = await fetch(\"https://registry.npmjs.org/@mariozechner/pi -coding-agent/latest\");\n\t\tif (!response.ok) return null;\n\n\t\tconst data = (await response.json()) as { version?: string };\n\t\tconst latestVersion = data.version;\n\n\t\tif (latestVersion && latestVersion !== currentVersion) {\n\t\t\treturn latestVersion;\n\t\t}\n\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function runInteractiveMode(\n\tsession: AgentSession,\n\tversion: string,\n\tchangelogMarkdown: string | null,\n\tmodelFallbackMessage: string | undefined,\n\tmodelsJsonError: string | null,\n\tmigratedProviders: string[],\n\tversionCheckPromise: Promise<string | null>,\n\tinitialMessages: string[],\n\tcustomTools: LoadedCustomTool[],\n\tsetToolUIContext: (uiContext: HookUIContext, hasUI: boolean) => void,\n\tinitialMessage?: string,\n\tinitialAttachments?: Attachment[],\n\tfdPath: string | null = null,\n): Promise<void> {\n\tconst mode = new InteractiveMode(session, version, changelogMarkdown, customTools, setToolUIContext, fdPath);\n\n\tawait mode.init();\n\n\tversionCheckPromise.then((newVersion) => {\n\t\tif (newVersion) {\n\t\t\tmode.showNewVersionNotification(newVersion);\n\t\t}\n\t});\n\n\tmode.renderInitialMessages(session.state);\n\n\tif (migratedProviders.length > 0) {\n\t\tmode.showWarning(`Migrated credentials to auth.json: ${migratedProviders.join(\", \")}`);\n\t}\n\n\tif (modelsJsonError) {\n\t\tmode.showError(`models.json error: ${modelsJsonError}`);\n\t}\n\n\tif (modelFallbackMessage) {\n\t\tmode.showWarning(modelFallbackMessage);\n\t}\n\n\tif (initialMessage) {\n\t\ttry {\n\t\t\tawait session.prompt(initialMessage, { attachments: initialAttachments });\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\tfor (const message of initialMessages) {\n\t\ttry {\n\t\t\tawait session.prompt(message);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\twhile (true) {\n\t\tconst userInput = await mode.getUserInput();\n\t\ttry {\n\t\t\tawait session.prompt(userInput);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n}\n\nasync function prepareInitialMessage(parsed: Args): Promise<{\n\tinitialMessage?: string;\n\tinitialAttachments?: Attachment[];\n}> {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn {};\n\t}\n\n\tconst { textContent, imageAttachments } = await processFileArguments(parsed.fileArgs);\n\n\tlet initialMessage: string;\n\tif (parsed.messages.length > 0) {\n\t\tinitialMessage = textContent + parsed.messages[0];\n\t\tparsed.messages.shift();\n\t} else {\n\t\tinitialMessage = textContent;\n\t}\n\n\treturn {\n\t\tinitialMessage,\n\t\tinitialAttachments: imageAttachments.length > 0 ? imageAttachments : undefined,\n\t};\n}\n\nfunction getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): string | null {\n\tif (parsed.continue || parsed.resume) {\n\t\treturn null;\n\t}\n\n\tconst lastVersion = settingsManager.getLastChangelogVersion();\n\tconst changelogPath = getChangelogPath();\n\tconst entries = parseChangelog(changelogPath);\n\n\tif (!lastVersion) {\n\t\tif (entries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn entries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t} else {\n\t\tconst newEntries = getNewEntries(entries, lastVersion);\n\t\tif (newEntries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn newEntries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t}\n\n\treturn null;\n}\n\nfunction createSessionManager(parsed: Args, cwd: string): SessionManager | null {\n\tif (parsed.noSession) {\n\t\treturn SessionManager.inMemory();\n\t}\n\tif (parsed.session) {\n\t\treturn SessionManager.open(parsed.session);\n\t}\n\tif (parsed.continue) {\n\t\treturn SessionManager.continueRecent(cwd);\n\t}\n\t// --resume is handled separately (needs picker UI)\n\t// Default case (new session) returns null, SDK will create one\n\treturn null;\n}\n\n/** Discover SYSTEM.md file if no CLI system prompt was provided */\nfunction discoverSystemPromptFile(): string | undefined {\n\t// Check project-local first: .pi/SYSTEM.md\n\tconst projectPath = join(process.cwd(), CONFIG_DIR_NAME, \"SYSTEM.md\");\n\tif (existsSync(projectPath)) {\n\t\treturn projectPath;\n\t}\n\n\t// Fall back to global: ~/.pi/agent/SYSTEM.md\n\tconst globalPath = join(getAgentDir(), \"SYSTEM.md\");\n\tif (existsSync(globalPath)) {\n\t\treturn globalPath;\n\t}\n\n\treturn undefined;\n}\n\nfunction buildSessionOptions(\n\tparsed: Args,\n\tscopedModels: ScopedModel[],\n\tsessionManager: SessionManager | null,\n\tmodelRegistry: ModelRegistry,\n): CreateAgentSessionOptions {\n\tconst options: CreateAgentSessionOptions = {};\n\n\t// Auto-discover SYSTEM.md if no CLI system prompt provided\n\tconst systemPromptSource = parsed.systemPrompt ?? discoverSystemPromptFile();\n\tconst resolvedSystemPrompt = resolvePromptInput(systemPromptSource, \"system prompt\");\n\tconst resolvedAppendPrompt = resolvePromptInput(parsed.appendSystemPrompt, \"append system prompt\");\n\n\tif (sessionManager) {\n\t\toptions.sessionManager = sessionManager;\n\t}\n\n\t// Model from CLI\n\tif (parsed.provider && parsed.model) {\n\t\tconst model = modelRegistry.find(parsed.provider, parsed.model);\n\t\tif (!model) {\n\t\t\tconsole.error(chalk.red(`Model ${parsed.provider}/${parsed.model} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\toptions.model = model;\n\t} else if (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\toptions.model = scopedModels[0].model;\n\t}\n\n\t// Thinking level\n\tif (parsed.thinking) {\n\t\toptions.thinkingLevel = parsed.thinking;\n\t} else if (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\toptions.thinkingLevel = scopedModels[0].thinkingLevel;\n\t}\n\n\t// Scoped models for Ctrl+P cycling\n\tif (scopedModels.length > 0) {\n\t\toptions.scopedModels = scopedModels;\n\t}\n\n\t// API key from CLI - set in authStorage\n\t// (handled by caller before createAgentSession)\n\n\t// System prompt\n\tif (resolvedSystemPrompt && resolvedAppendPrompt) {\n\t\toptions.systemPrompt = `${resolvedSystemPrompt}\\n\\n${resolvedAppendPrompt}`;\n\t} else if (resolvedSystemPrompt) {\n\t\toptions.systemPrompt = resolvedSystemPrompt;\n\t} else if (resolvedAppendPrompt) {\n\t\toptions.systemPrompt = (defaultPrompt) => `${defaultPrompt}\\n\\n${resolvedAppendPrompt}`;\n\t}\n\n\t// Tools\n\tif (parsed.tools) {\n\t\toptions.tools = parsed.tools.map((name) => allTools[name]);\n\t}\n\n\t// Skills\n\tif (parsed.noSkills) {\n\t\toptions.skills = [];\n\t}\n\n\t// Additional hook paths from CLI\n\tif (parsed.hooks && parsed.hooks.length > 0) {\n\t\toptions.additionalHookPaths = parsed.hooks;\n\t}\n\n\t// Additional custom tool paths from CLI\n\tif (parsed.customTools && parsed.customTools.length > 0) {\n\t\toptions.additionalCustomToolPaths = parsed.customTools;\n\t}\n\n\treturn options;\n}\n\nexport async function main(args: string[]) {\n\ttime(\"start\");\n\n\t// Migrate legacy oauth.json and settings.json apiKeys to auth.json\n\tconst agentDir = getAgentDir();\n\tconst migratedProviders = AuthStorage.migrateLegacy(join(agentDir, \"auth.json\"), agentDir);\n\n\t// Create AuthStorage and ModelRegistry upfront\n\tconst authStorage = discoverAuthStorage();\n\tconst modelRegistry = discoverModels(authStorage);\n\ttime(\"discoverModels\");\n\n\tconst parsed = parseArgs(args);\n\ttime(\"parseArgs\");\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\tif (parsed.listModels !== undefined) {\n\t\tconst searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : undefined;\n\t\tawait listModels(modelRegistry, searchPattern);\n\t\treturn;\n\t}\n\n\tif (parsed.export) {\n\t\ttry {\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tconst result = exportFromFile(parsed.export, outputPath);\n\t\t\tconsole.log(`Exported to: ${result}`);\n\t\t\treturn;\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tconst cwd = process.cwd();\n\tconst { initialMessage, initialAttachments } = await prepareInitialMessage(parsed);\n\ttime(\"prepareInitialMessage\");\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\tconst mode = parsed.mode || \"text\";\n\n\tconst settingsManager = SettingsManager.create(cwd);\n\ttime(\"SettingsManager.create\");\n\tinitTheme(settingsManager.getTheme(), isInteractive);\n\ttime(\"initTheme\");\n\n\tlet scopedModels: ScopedModel[] = [];\n\tif (parsed.models && parsed.models.length > 0) {\n\t\tscopedModels = await resolveModelScope(parsed.models, modelRegistry);\n\t\ttime(\"resolveModelScope\");\n\t}\n\n\t// Create session manager based on CLI flags\n\tlet sessionManager = createSessionManager(parsed, cwd);\n\ttime(\"createSessionManager\");\n\n\t// Handle --resume: show session picker\n\tif (parsed.resume) {\n\t\tconst sessions = SessionManager.list(cwd);\n\t\ttime(\"SessionManager.list\");\n\t\tif (sessions.length === 0) {\n\t\t\tconsole.log(chalk.dim(\"No sessions found\"));\n\t\t\treturn;\n\t\t}\n\t\tconst selectedPath = await selectSession(sessions);\n\t\ttime(\"selectSession\");\n\t\tif (!selectedPath) {\n\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\treturn;\n\t\t}\n\t\tsessionManager = SessionManager.open(selectedPath);\n\t}\n\n\tconst sessionOptions = buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry);\n\tsessionOptions.authStorage = authStorage;\n\tsessionOptions.modelRegistry = modelRegistry;\n\n\t// Handle CLI --api-key as runtime override (not persisted)\n\tif (parsed.apiKey) {\n\t\tif (!sessionOptions.model) {\n\t\t\tconsole.error(chalk.red(\"--api-key requires a model to be specified via --provider/--model or -m/--models\"));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tauthStorage.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);\n\t}\n\n\ttime(\"buildSessionOptions\");\n\tconst { session, customToolsResult, modelFallbackMessage } = await createAgentSession(sessionOptions);\n\ttime(\"createAgentSession\");\n\n\tif (!isInteractive && !session.model) {\n\t\tconsole.error(chalk.red(\"No models available.\"));\n\t\tconsole.error(chalk.yellow(\"\\nSet an API key environment variable:\"));\n\t\tconsole.error(\" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\");\n\t\tconsole.error(chalk.yellow(`\\nOr create ${getModelsPath()}`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Clamp thinking level to model capabilities (for CLI override case)\n\tif (session.model && parsed.thinking) {\n\t\tlet effectiveThinking = parsed.thinking;\n\t\tif (!session.model.reasoning) {\n\t\t\teffectiveThinking = \"off\";\n\t\t} else if (effectiveThinking === \"xhigh\" && !supportsXhigh(session.model)) {\n\t\t\teffectiveThinking = \"high\";\n\t\t}\n\t\tif (effectiveThinking !== session.thinkingLevel) {\n\t\t\tsession.setThinkingLevel(effectiveThinking);\n\t\t}\n\t}\n\n\tif (mode === \"rpc\") {\n\t\tawait runRpcMode(session);\n\t} else if (isInteractive) {\n\t\tconst versionCheckPromise = checkForNewVersion(VERSION).catch(() => null);\n\t\tconst changelogMarkdown = getChangelogForDisplay(parsed, settingsManager);\n\n\t\tif (scopedModels.length > 0) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel !== \"off\" ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\tconst fdPath = await ensureTool(\"fd\");\n\t\ttime(\"ensureTool(fd)\");\n\n\t\tprintTimings();\n\t\tawait runInteractiveMode(\n\t\t\tsession,\n\t\t\tVERSION,\n\t\t\tchangelogMarkdown,\n\t\t\tmodelFallbackMessage,\n\t\t\tmodelRegistry.getError(),\n\t\t\tmigratedProviders,\n\t\t\tversionCheckPromise,\n\t\t\tparsed.messages,\n\t\t\tcustomToolsResult.tools,\n\t\t\tcustomToolsResult.setUIContext,\n\t\t\tinitialMessage,\n\t\t\tinitialAttachments,\n\t\t\tfdPath,\n\t\t);\n\t} else {\n\t\tawait runPrintMode(session, mode, parsed.messages, initialMessage, initialAttachments);\n\t\tstopThemeWatcher();\n\t\tif (process.stdout.writableLength > 0) {\n\t\t\tawait new Promise<void>((resolve) => process.stdout.once(\"drain\", resolve));\n\t\t}\n\t\tprocess.exit(0);\n\t}\n}\n"]}
|
package/dist/main.js
CHANGED
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { supportsXhigh } from "@mariozechner/pi-ai";
|
|
8
8
|
import chalk from "chalk";
|
|
9
|
+
import { existsSync } from "fs";
|
|
9
10
|
import { join } from "path";
|
|
10
11
|
import { parseArgs, printHelp } from "./cli/args.js";
|
|
11
12
|
import { processFileArguments } from "./cli/file-processor.js";
|
|
12
13
|
import { listModels } from "./cli/list-models.js";
|
|
13
14
|
import { selectSession } from "./cli/session-picker.js";
|
|
14
|
-
import { getAgentDir, getModelsPath, VERSION } from "./config.js";
|
|
15
|
+
import { CONFIG_DIR_NAME, getAgentDir, getModelsPath, VERSION } from "./config.js";
|
|
15
16
|
import { AuthStorage } from "./core/auth-storage.js";
|
|
16
17
|
import { exportFromFile } from "./core/export-html.js";
|
|
17
18
|
import { resolveModelScope } from "./core/model-resolver.js";
|
|
@@ -142,9 +143,25 @@ function createSessionManager(parsed, cwd) {
|
|
|
142
143
|
// Default case (new session) returns null, SDK will create one
|
|
143
144
|
return null;
|
|
144
145
|
}
|
|
146
|
+
/** Discover SYSTEM.md file if no CLI system prompt was provided */
|
|
147
|
+
function discoverSystemPromptFile() {
|
|
148
|
+
// Check project-local first: .pi/SYSTEM.md
|
|
149
|
+
const projectPath = join(process.cwd(), CONFIG_DIR_NAME, "SYSTEM.md");
|
|
150
|
+
if (existsSync(projectPath)) {
|
|
151
|
+
return projectPath;
|
|
152
|
+
}
|
|
153
|
+
// Fall back to global: ~/.pi/agent/SYSTEM.md
|
|
154
|
+
const globalPath = join(getAgentDir(), "SYSTEM.md");
|
|
155
|
+
if (existsSync(globalPath)) {
|
|
156
|
+
return globalPath;
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
145
160
|
function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry) {
|
|
146
161
|
const options = {};
|
|
147
|
-
|
|
162
|
+
// Auto-discover SYSTEM.md if no CLI system prompt provided
|
|
163
|
+
const systemPromptSource = parsed.systemPrompt ?? discoverSystemPromptFile();
|
|
164
|
+
const resolvedSystemPrompt = resolvePromptInput(systemPromptSource, "system prompt");
|
|
148
165
|
const resolvedAppendPrompt = resolvePromptInput(parsed.appendSystemPrompt, "append system prompt");
|
|
149
166
|
if (sessionManager) {
|
|
150
167
|
options.sessionManager = sessionManager;
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Main entry point for the coding agent CLI.\n *\n * This file handles CLI argument parsing and translates them into\n * createAgentSession() options. The SDK does the heavy lifting.\n */\n\nimport type { Attachment } from \"@mariozechner/pi-agent-core\";\nimport { supportsXhigh } from \"@mariozechner/pi-ai\";\nimport chalk from \"chalk\";\nimport { join } from \"path\";\nimport { type Args, parseArgs, printHelp } from \"./cli/args.js\";\nimport { processFileArguments } from \"./cli/file-processor.js\";\nimport { listModels } from \"./cli/list-models.js\";\nimport { selectSession } from \"./cli/session-picker.js\";\nimport { getAgentDir, getModelsPath, VERSION } from \"./config.js\";\nimport type { AgentSession } from \"./core/agent-session.js\";\nimport { AuthStorage } from \"./core/auth-storage.js\";\nimport type { LoadedCustomTool } from \"./core/custom-tools/index.js\";\nimport { exportFromFile } from \"./core/export-html.js\";\nimport type { HookUIContext } from \"./core/index.js\";\nimport type { ModelRegistry } from \"./core/model-registry.js\";\nimport { resolveModelScope, type ScopedModel } from \"./core/model-resolver.js\";\nimport { type CreateAgentSessionOptions, createAgentSession, discoverAuthStorage, discoverModels } from \"./core/sdk.js\";\nimport { SessionManager } from \"./core/session-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\nimport { resolvePromptInput } from \"./core/system-prompt.js\";\nimport { printTimings, time } from \"./core/timings.js\";\nimport { allTools } from \"./core/tools/index.js\";\nimport { InteractiveMode, runPrintMode, runRpcMode } from \"./modes/index.js\";\nimport { initTheme, stopThemeWatcher } from \"./modes/interactive/theme/theme.js\";\nimport { getChangelogPath, getNewEntries, parseChangelog } from \"./utils/changelog.js\";\nimport { ensureTool } from \"./utils/tools-manager.js\";\n\nasync function checkForNewVersion(currentVersion: string): Promise<string | null> {\n\ttry {\n\t\tconst response = await fetch(\"https://registry.npmjs.org/@mariozechner/pi -coding-agent/latest\");\n\t\tif (!response.ok) return null;\n\n\t\tconst data = (await response.json()) as { version?: string };\n\t\tconst latestVersion = data.version;\n\n\t\tif (latestVersion && latestVersion !== currentVersion) {\n\t\t\treturn latestVersion;\n\t\t}\n\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function runInteractiveMode(\n\tsession: AgentSession,\n\tversion: string,\n\tchangelogMarkdown: string | null,\n\tmodelFallbackMessage: string | undefined,\n\tmodelsJsonError: string | null,\n\tmigratedProviders: string[],\n\tversionCheckPromise: Promise<string | null>,\n\tinitialMessages: string[],\n\tcustomTools: LoadedCustomTool[],\n\tsetToolUIContext: (uiContext: HookUIContext, hasUI: boolean) => void,\n\tinitialMessage?: string,\n\tinitialAttachments?: Attachment[],\n\tfdPath: string | null = null,\n): Promise<void> {\n\tconst mode = new InteractiveMode(session, version, changelogMarkdown, customTools, setToolUIContext, fdPath);\n\n\tawait mode.init();\n\n\tversionCheckPromise.then((newVersion) => {\n\t\tif (newVersion) {\n\t\t\tmode.showNewVersionNotification(newVersion);\n\t\t}\n\t});\n\n\tmode.renderInitialMessages(session.state);\n\n\tif (migratedProviders.length > 0) {\n\t\tmode.showWarning(`Migrated credentials to auth.json: ${migratedProviders.join(\", \")}`);\n\t}\n\n\tif (modelsJsonError) {\n\t\tmode.showError(`models.json error: ${modelsJsonError}`);\n\t}\n\n\tif (modelFallbackMessage) {\n\t\tmode.showWarning(modelFallbackMessage);\n\t}\n\n\tif (initialMessage) {\n\t\ttry {\n\t\t\tawait session.prompt(initialMessage, { attachments: initialAttachments });\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\tfor (const message of initialMessages) {\n\t\ttry {\n\t\t\tawait session.prompt(message);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\twhile (true) {\n\t\tconst userInput = await mode.getUserInput();\n\t\ttry {\n\t\t\tawait session.prompt(userInput);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n}\n\nasync function prepareInitialMessage(parsed: Args): Promise<{\n\tinitialMessage?: string;\n\tinitialAttachments?: Attachment[];\n}> {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn {};\n\t}\n\n\tconst { textContent, imageAttachments } = await processFileArguments(parsed.fileArgs);\n\n\tlet initialMessage: string;\n\tif (parsed.messages.length > 0) {\n\t\tinitialMessage = textContent + parsed.messages[0];\n\t\tparsed.messages.shift();\n\t} else {\n\t\tinitialMessage = textContent;\n\t}\n\n\treturn {\n\t\tinitialMessage,\n\t\tinitialAttachments: imageAttachments.length > 0 ? imageAttachments : undefined,\n\t};\n}\n\nfunction getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): string | null {\n\tif (parsed.continue || parsed.resume) {\n\t\treturn null;\n\t}\n\n\tconst lastVersion = settingsManager.getLastChangelogVersion();\n\tconst changelogPath = getChangelogPath();\n\tconst entries = parseChangelog(changelogPath);\n\n\tif (!lastVersion) {\n\t\tif (entries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn entries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t} else {\n\t\tconst newEntries = getNewEntries(entries, lastVersion);\n\t\tif (newEntries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn newEntries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t}\n\n\treturn null;\n}\n\nfunction createSessionManager(parsed: Args, cwd: string): SessionManager | null {\n\tif (parsed.noSession) {\n\t\treturn SessionManager.inMemory();\n\t}\n\tif (parsed.session) {\n\t\treturn SessionManager.open(parsed.session);\n\t}\n\tif (parsed.continue) {\n\t\treturn SessionManager.continueRecent(cwd);\n\t}\n\t// --resume is handled separately (needs picker UI)\n\t// Default case (new session) returns null, SDK will create one\n\treturn null;\n}\n\nfunction buildSessionOptions(\n\tparsed: Args,\n\tscopedModels: ScopedModel[],\n\tsessionManager: SessionManager | null,\n\tmodelRegistry: ModelRegistry,\n): CreateAgentSessionOptions {\n\tconst options: CreateAgentSessionOptions = {};\n\n\tconst resolvedSystemPrompt = resolvePromptInput(parsed.systemPrompt, \"system prompt\");\n\tconst resolvedAppendPrompt = resolvePromptInput(parsed.appendSystemPrompt, \"append system prompt\");\n\n\tif (sessionManager) {\n\t\toptions.sessionManager = sessionManager;\n\t}\n\n\t// Model from CLI\n\tif (parsed.provider && parsed.model) {\n\t\tconst model = modelRegistry.find(parsed.provider, parsed.model);\n\t\tif (!model) {\n\t\t\tconsole.error(chalk.red(`Model ${parsed.provider}/${parsed.model} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\toptions.model = model;\n\t} else if (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\toptions.model = scopedModels[0].model;\n\t}\n\n\t// Thinking level\n\tif (parsed.thinking) {\n\t\toptions.thinkingLevel = parsed.thinking;\n\t} else if (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\toptions.thinkingLevel = scopedModels[0].thinkingLevel;\n\t}\n\n\t// Scoped models for Ctrl+P cycling\n\tif (scopedModels.length > 0) {\n\t\toptions.scopedModels = scopedModels;\n\t}\n\n\t// API key from CLI - set in authStorage\n\t// (handled by caller before createAgentSession)\n\n\t// System prompt\n\tif (resolvedSystemPrompt && resolvedAppendPrompt) {\n\t\toptions.systemPrompt = `${resolvedSystemPrompt}\\n\\n${resolvedAppendPrompt}`;\n\t} else if (resolvedSystemPrompt) {\n\t\toptions.systemPrompt = resolvedSystemPrompt;\n\t} else if (resolvedAppendPrompt) {\n\t\toptions.systemPrompt = (defaultPrompt) => `${defaultPrompt}\\n\\n${resolvedAppendPrompt}`;\n\t}\n\n\t// Tools\n\tif (parsed.tools) {\n\t\toptions.tools = parsed.tools.map((name) => allTools[name]);\n\t}\n\n\t// Skills\n\tif (parsed.noSkills) {\n\t\toptions.skills = [];\n\t}\n\n\t// Additional hook paths from CLI\n\tif (parsed.hooks && parsed.hooks.length > 0) {\n\t\toptions.additionalHookPaths = parsed.hooks;\n\t}\n\n\t// Additional custom tool paths from CLI\n\tif (parsed.customTools && parsed.customTools.length > 0) {\n\t\toptions.additionalCustomToolPaths = parsed.customTools;\n\t}\n\n\treturn options;\n}\n\nexport async function main(args: string[]) {\n\ttime(\"start\");\n\n\t// Migrate legacy oauth.json and settings.json apiKeys to auth.json\n\tconst agentDir = getAgentDir();\n\tconst migratedProviders = AuthStorage.migrateLegacy(join(agentDir, \"auth.json\"), agentDir);\n\n\t// Create AuthStorage and ModelRegistry upfront\n\tconst authStorage = discoverAuthStorage();\n\tconst modelRegistry = discoverModels(authStorage);\n\ttime(\"discoverModels\");\n\n\tconst parsed = parseArgs(args);\n\ttime(\"parseArgs\");\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\tif (parsed.listModels !== undefined) {\n\t\tconst searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : undefined;\n\t\tawait listModels(modelRegistry, searchPattern);\n\t\treturn;\n\t}\n\n\tif (parsed.export) {\n\t\ttry {\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tconst result = exportFromFile(parsed.export, outputPath);\n\t\t\tconsole.log(`Exported to: ${result}`);\n\t\t\treturn;\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tconst cwd = process.cwd();\n\tconst { initialMessage, initialAttachments } = await prepareInitialMessage(parsed);\n\ttime(\"prepareInitialMessage\");\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\tconst mode = parsed.mode || \"text\";\n\n\tconst settingsManager = SettingsManager.create(cwd);\n\ttime(\"SettingsManager.create\");\n\tinitTheme(settingsManager.getTheme(), isInteractive);\n\ttime(\"initTheme\");\n\n\tlet scopedModels: ScopedModel[] = [];\n\tif (parsed.models && parsed.models.length > 0) {\n\t\tscopedModels = await resolveModelScope(parsed.models, modelRegistry);\n\t\ttime(\"resolveModelScope\");\n\t}\n\n\t// Create session manager based on CLI flags\n\tlet sessionManager = createSessionManager(parsed, cwd);\n\ttime(\"createSessionManager\");\n\n\t// Handle --resume: show session picker\n\tif (parsed.resume) {\n\t\tconst sessions = SessionManager.list(cwd);\n\t\ttime(\"SessionManager.list\");\n\t\tif (sessions.length === 0) {\n\t\t\tconsole.log(chalk.dim(\"No sessions found\"));\n\t\t\treturn;\n\t\t}\n\t\tconst selectedPath = await selectSession(sessions);\n\t\ttime(\"selectSession\");\n\t\tif (!selectedPath) {\n\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\treturn;\n\t\t}\n\t\tsessionManager = SessionManager.open(selectedPath);\n\t}\n\n\tconst sessionOptions = buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry);\n\tsessionOptions.authStorage = authStorage;\n\tsessionOptions.modelRegistry = modelRegistry;\n\n\t// Handle CLI --api-key as runtime override (not persisted)\n\tif (parsed.apiKey) {\n\t\tif (!sessionOptions.model) {\n\t\t\tconsole.error(chalk.red(\"--api-key requires a model to be specified via --provider/--model or -m/--models\"));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tauthStorage.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);\n\t}\n\n\ttime(\"buildSessionOptions\");\n\tconst { session, customToolsResult, modelFallbackMessage } = await createAgentSession(sessionOptions);\n\ttime(\"createAgentSession\");\n\n\tif (!isInteractive && !session.model) {\n\t\tconsole.error(chalk.red(\"No models available.\"));\n\t\tconsole.error(chalk.yellow(\"\\nSet an API key environment variable:\"));\n\t\tconsole.error(\" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\");\n\t\tconsole.error(chalk.yellow(`\\nOr create ${getModelsPath()}`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Clamp thinking level to model capabilities (for CLI override case)\n\tif (session.model && parsed.thinking) {\n\t\tlet effectiveThinking = parsed.thinking;\n\t\tif (!session.model.reasoning) {\n\t\t\teffectiveThinking = \"off\";\n\t\t} else if (effectiveThinking === \"xhigh\" && !supportsXhigh(session.model)) {\n\t\t\teffectiveThinking = \"high\";\n\t\t}\n\t\tif (effectiveThinking !== session.thinkingLevel) {\n\t\t\tsession.setThinkingLevel(effectiveThinking);\n\t\t}\n\t}\n\n\tif (mode === \"rpc\") {\n\t\tawait runRpcMode(session);\n\t} else if (isInteractive) {\n\t\tconst versionCheckPromise = checkForNewVersion(VERSION).catch(() => null);\n\t\tconst changelogMarkdown = getChangelogForDisplay(parsed, settingsManager);\n\n\t\tif (scopedModels.length > 0) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel !== \"off\" ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\tconst fdPath = await ensureTool(\"fd\");\n\t\ttime(\"ensureTool(fd)\");\n\n\t\tprintTimings();\n\t\tawait runInteractiveMode(\n\t\t\tsession,\n\t\t\tVERSION,\n\t\t\tchangelogMarkdown,\n\t\t\tmodelFallbackMessage,\n\t\t\tmodelRegistry.getError(),\n\t\t\tmigratedProviders,\n\t\t\tversionCheckPromise,\n\t\t\tparsed.messages,\n\t\t\tcustomToolsResult.tools,\n\t\t\tcustomToolsResult.setUIContext,\n\t\t\tinitialMessage,\n\t\t\tinitialAttachments,\n\t\t\tfdPath,\n\t\t);\n\t} else {\n\t\tawait runPrintMode(session, mode, parsed.messages, initialMessage, initialAttachments);\n\t\tstopThemeWatcher();\n\t\tif (process.stdout.writableLength > 0) {\n\t\t\tawait new Promise<void>((resolve) => process.stdout.once(\"drain\", resolve));\n\t\t}\n\t\tprocess.exit(0);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAa,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEnF,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,EAAE,iBAAiB,EAAoB,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAkC,kBAAkB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACxH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,KAAK,UAAU,kBAAkB,CAAC,cAAsB,EAA0B;IACjF,IAAI,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kEAAkE,CAAC,CAAC;QACjG,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAE9B,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB,CAAC;QAC7D,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC;QAEnC,IAAI,aAAa,IAAI,aAAa,KAAK,cAAc,EAAE,CAAC;YACvD,OAAO,aAAa,CAAC;QACtB,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AAAA,CACD;AAED,KAAK,UAAU,kBAAkB,CAChC,OAAqB,EACrB,OAAe,EACf,iBAAgC,EAChC,oBAAwC,EACxC,eAA8B,EAC9B,iBAA2B,EAC3B,mBAA2C,EAC3C,eAAyB,EACzB,WAA+B,EAC/B,gBAAoE,EACpE,cAAuB,EACvB,kBAAiC,EACjC,MAAM,GAAkB,IAAI,EACZ;IAChB,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAE7G,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAElB,mBAAmB,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC;QACxC,IAAI,UAAU,EAAE,CAAC;YAChB,IAAI,CAAC,0BAA0B,CAAC,UAAU,CAAC,CAAC;QAC7C,CAAC;IAAA,CACD,CAAC,CAAC;IAEH,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAE1C,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,IAAI,CAAC,WAAW,CAAC,sCAAsC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IAED,IAAI,eAAe,EAAE,CAAC;QACrB,IAAI,CAAC,SAAS,CAAC,sBAAsB,eAAe,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,oBAAoB,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,cAAc,EAAE,CAAC;QACpB,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;YACvF,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC9B,CAAC;IACF,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACvC,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;YACvF,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC9B,CAAC;IACF,CAAC;IAED,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC5C,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;YACvF,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC9B,CAAC;IACF,CAAC;AAAA,CACD;AAED,KAAK,UAAU,qBAAqB,CAAC,MAAY,EAG9C;IACF,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,CAAC;IACX,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,MAAM,oBAAoB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEtF,IAAI,cAAsB,CAAC;IAC3B,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,cAAc,GAAG,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;SAAM,CAAC;QACP,cAAc,GAAG,WAAW,CAAC;IAC9B,CAAC;IAED,OAAO;QACN,cAAc;QACd,kBAAkB,EAAE,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS;KAC9E,CAAC;AAAA,CACF;AAED,SAAS,sBAAsB,CAAC,MAAY,EAAE,eAAgC,EAAiB;IAC9F,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,WAAW,GAAG,eAAe,CAAC,uBAAuB,EAAE,CAAC;IAC9D,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IAE9C,IAAI,CAAC,WAAW,EAAE,CAAC;QAClB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,eAAe,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;YACjD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnD,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACvD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,eAAe,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;YACjD,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtD,CAAC;IACF,CAAC;IAED,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,SAAS,oBAAoB,CAAC,MAAY,EAAE,GAAW,EAAyB;IAC/E,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,OAAO,cAAc,CAAC,QAAQ,EAAE,CAAC;IAClC,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,cAAc,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IACD,mDAAmD;IACnD,+DAA+D;IAC/D,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,mEAAmE;AACnE,SAAS,wBAAwB,GAAuB;IACvD,2CAA2C;IAC3C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC;IACtE,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,WAAW,CAAC;IACpB,CAAC;IAED,6CAA6C;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,EAAE,WAAW,CAAC,CAAC;IACpD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,UAAU,CAAC;IACnB,CAAC;IAED,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,mBAAmB,CAC3B,MAAY,EACZ,YAA2B,EAC3B,cAAqC,EACrC,aAA4B,EACA;IAC5B,MAAM,OAAO,GAA8B,EAAE,CAAC;IAE9C,2DAA2D;IAC3D,MAAM,kBAAkB,GAAG,MAAM,CAAC,YAAY,IAAI,wBAAwB,EAAE,CAAC;IAC7E,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;IACrF,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,MAAM,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC;IAEnG,IAAI,cAAc,EAAE,CAAC;QACpB,OAAO,CAAC,cAAc,GAAG,cAAc,CAAC;IACzC,CAAC;IAED,iBAAiB;IACjB,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAChE,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC;YAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;QACD,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;SAAM,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAC1E,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACvC,CAAC;IAED,iBAAiB;IACjB,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,CAAC,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC;IACzC,CAAC;SAAM,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAC1E,OAAO,CAAC,aAAa,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;IACvD,CAAC;IAED,mCAAmC;IACnC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,YAAY,GAAG,YAAY,CAAC;IACrC,CAAC;IAED,wCAAwC;IACxC,gDAAgD;IAEhD,gBAAgB;IAChB,IAAI,oBAAoB,IAAI,oBAAoB,EAAE,CAAC;QAClD,OAAO,CAAC,YAAY,GAAG,GAAG,oBAAoB,OAAO,oBAAoB,EAAE,CAAC;IAC7E,CAAC;SAAM,IAAI,oBAAoB,EAAE,CAAC;QACjC,OAAO,CAAC,YAAY,GAAG,oBAAoB,CAAC;IAC7C,CAAC;SAAM,IAAI,oBAAoB,EAAE,CAAC;QACjC,OAAO,CAAC,YAAY,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC,GAAG,aAAa,OAAO,oBAAoB,EAAE,CAAC;IACzF,CAAC;IAED,QAAQ;IACR,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,SAAS;IACT,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,iCAAiC;IACjC,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,OAAO,CAAC,mBAAmB,GAAG,MAAM,CAAC,KAAK,CAAC;IAC5C,CAAC;IAED,wCAAwC;IACxC,IAAI,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzD,OAAO,CAAC,yBAAyB,GAAG,MAAM,CAAC,WAAW,CAAC;IACxD,CAAC;IAED,OAAO,OAAO,CAAC;AAAA,CACf;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAc,EAAE;IAC1C,IAAI,CAAC,OAAO,CAAC,CAAC;IAEd,mEAAmE;IACnE,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,MAAM,iBAAiB,GAAG,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,QAAQ,CAAC,CAAC;IAE3F,+CAA+C;IAC/C,MAAM,WAAW,GAAG,mBAAmB,EAAE,CAAC;IAC1C,MAAM,aAAa,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAClD,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAEvB,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,WAAW,CAAC,CAAC;IAElB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO;IACR,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QACjB,SAAS,EAAE,CAAC;QACZ,OAAO;IACR,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,aAAa,GAAG,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5F,MAAM,UAAU,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;QAC/C,OAAO;IACR,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC/E,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;YACtC,OAAO;QACR,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC;YACpF,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC,CAAC;YAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;IACF,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC,CAAC;QACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACnF,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC9B,MAAM,aAAa,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;IACjE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC;IAEnC,MAAM,eAAe,GAAG,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACpD,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAC/B,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,EAAE,aAAa,CAAC,CAAC;IACrD,IAAI,CAAC,WAAW,CAAC,CAAC;IAElB,IAAI,YAAY,GAAkB,EAAE,CAAC;IACrC,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/C,YAAY,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QACrE,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC3B,CAAC;IAED,4CAA4C;IAC5C,IAAI,cAAc,GAAG,oBAAoB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACvD,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAE7B,uCAAuC;IACvC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC5B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;YAC5C,OAAO;QACR,CAAC;QACD,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,eAAe,CAAC,CAAC;QACtB,IAAI,CAAC,YAAY,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAC9C,OAAO;QACR,CAAC;QACD,cAAc,GAAG,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,cAAc,GAAG,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,CAAC,CAAC;IAChG,cAAc,CAAC,WAAW,GAAG,WAAW,CAAC;IACzC,cAAc,CAAC,aAAa,GAAG,aAAa,CAAC;IAE7C,2DAA2D;IAC3D,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,kFAAkF,CAAC,CAAC,CAAC;YAC7G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;QACD,WAAW,CAAC,gBAAgB,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAC5B,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,GAAG,MAAM,kBAAkB,CAAC,cAAc,CAAC,CAAC;IACtG,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAE3B,IAAI,CAAC,aAAa,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC;QACjD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,wCAAwC,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC3E,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IAED,qEAAqE;IACrE,IAAI,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,IAAI,iBAAiB,GAAG,MAAM,CAAC,QAAQ,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YAC9B,iBAAiB,GAAG,KAAK,CAAC;QAC3B,CAAC;aAAM,IAAI,iBAAiB,KAAK,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3E,iBAAiB,GAAG,MAAM,CAAC;QAC5B,CAAC;QACD,IAAI,iBAAiB,KAAK,OAAO,CAAC,aAAa,EAAE,CAAC;YACjD,OAAO,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;QAC7C,CAAC;IACF,CAAC;IAED,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACpB,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;SAAM,IAAI,aAAa,EAAE,CAAC;QAC1B,MAAM,mBAAmB,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1E,MAAM,iBAAiB,GAAG,sBAAsB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QAE1E,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,YAAY;iBAC5B,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC;gBACZ,MAAM,WAAW,GAAG,EAAE,CAAC,aAAa,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7E,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,WAAW,EAAE,CAAC;YAAA,CACtC,CAAC;iBACD,IAAI,CAAC,IAAI,CAAC,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAEvB,YAAY,EAAE,CAAC;QACf,MAAM,kBAAkB,CACvB,OAAO,EACP,OAAO,EACP,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,CAAC,QAAQ,EAAE,EACxB,iBAAiB,EACjB,mBAAmB,EACnB,MAAM,CAAC,QAAQ,EACf,iBAAiB,CAAC,KAAK,EACvB,iBAAiB,CAAC,YAAY,EAC9B,cAAc,EACd,kBAAkB,EAClB,MAAM,CACN,CAAC;IACH,CAAC;SAAM,CAAC;QACP,MAAM,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,kBAAkB,CAAC,CAAC;QACvF,gBAAgB,EAAE,CAAC;QACnB,IAAI,OAAO,CAAC,MAAM,CAAC,cAAc,GAAG,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;AAAA,CACD","sourcesContent":["/**\n * Main entry point for the coding agent CLI.\n *\n * This file handles CLI argument parsing and translates them into\n * createAgentSession() options. The SDK does the heavy lifting.\n */\n\nimport type { Attachment } from \"@mariozechner/pi-agent-core\";\nimport { supportsXhigh } from \"@mariozechner/pi-ai\";\nimport chalk from \"chalk\";\nimport { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport { type Args, parseArgs, printHelp } from \"./cli/args.js\";\nimport { processFileArguments } from \"./cli/file-processor.js\";\nimport { listModels } from \"./cli/list-models.js\";\nimport { selectSession } from \"./cli/session-picker.js\";\nimport { CONFIG_DIR_NAME, getAgentDir, getModelsPath, VERSION } from \"./config.js\";\nimport type { AgentSession } from \"./core/agent-session.js\";\nimport { AuthStorage } from \"./core/auth-storage.js\";\nimport type { LoadedCustomTool } from \"./core/custom-tools/index.js\";\nimport { exportFromFile } from \"./core/export-html.js\";\nimport type { HookUIContext } from \"./core/index.js\";\nimport type { ModelRegistry } from \"./core/model-registry.js\";\nimport { resolveModelScope, type ScopedModel } from \"./core/model-resolver.js\";\nimport { type CreateAgentSessionOptions, createAgentSession, discoverAuthStorage, discoverModels } from \"./core/sdk.js\";\nimport { SessionManager } from \"./core/session-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\nimport { resolvePromptInput } from \"./core/system-prompt.js\";\nimport { printTimings, time } from \"./core/timings.js\";\nimport { allTools } from \"./core/tools/index.js\";\nimport { InteractiveMode, runPrintMode, runRpcMode } from \"./modes/index.js\";\nimport { initTheme, stopThemeWatcher } from \"./modes/interactive/theme/theme.js\";\nimport { getChangelogPath, getNewEntries, parseChangelog } from \"./utils/changelog.js\";\nimport { ensureTool } from \"./utils/tools-manager.js\";\n\nasync function checkForNewVersion(currentVersion: string): Promise<string | null> {\n\ttry {\n\t\tconst response = await fetch(\"https://registry.npmjs.org/@mariozechner/pi -coding-agent/latest\");\n\t\tif (!response.ok) return null;\n\n\t\tconst data = (await response.json()) as { version?: string };\n\t\tconst latestVersion = data.version;\n\n\t\tif (latestVersion && latestVersion !== currentVersion) {\n\t\t\treturn latestVersion;\n\t\t}\n\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function runInteractiveMode(\n\tsession: AgentSession,\n\tversion: string,\n\tchangelogMarkdown: string | null,\n\tmodelFallbackMessage: string | undefined,\n\tmodelsJsonError: string | null,\n\tmigratedProviders: string[],\n\tversionCheckPromise: Promise<string | null>,\n\tinitialMessages: string[],\n\tcustomTools: LoadedCustomTool[],\n\tsetToolUIContext: (uiContext: HookUIContext, hasUI: boolean) => void,\n\tinitialMessage?: string,\n\tinitialAttachments?: Attachment[],\n\tfdPath: string | null = null,\n): Promise<void> {\n\tconst mode = new InteractiveMode(session, version, changelogMarkdown, customTools, setToolUIContext, fdPath);\n\n\tawait mode.init();\n\n\tversionCheckPromise.then((newVersion) => {\n\t\tif (newVersion) {\n\t\t\tmode.showNewVersionNotification(newVersion);\n\t\t}\n\t});\n\n\tmode.renderInitialMessages(session.state);\n\n\tif (migratedProviders.length > 0) {\n\t\tmode.showWarning(`Migrated credentials to auth.json: ${migratedProviders.join(\", \")}`);\n\t}\n\n\tif (modelsJsonError) {\n\t\tmode.showError(`models.json error: ${modelsJsonError}`);\n\t}\n\n\tif (modelFallbackMessage) {\n\t\tmode.showWarning(modelFallbackMessage);\n\t}\n\n\tif (initialMessage) {\n\t\ttry {\n\t\t\tawait session.prompt(initialMessage, { attachments: initialAttachments });\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\tfor (const message of initialMessages) {\n\t\ttry {\n\t\t\tawait session.prompt(message);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\twhile (true) {\n\t\tconst userInput = await mode.getUserInput();\n\t\ttry {\n\t\t\tawait session.prompt(userInput);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n}\n\nasync function prepareInitialMessage(parsed: Args): Promise<{\n\tinitialMessage?: string;\n\tinitialAttachments?: Attachment[];\n}> {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn {};\n\t}\n\n\tconst { textContent, imageAttachments } = await processFileArguments(parsed.fileArgs);\n\n\tlet initialMessage: string;\n\tif (parsed.messages.length > 0) {\n\t\tinitialMessage = textContent + parsed.messages[0];\n\t\tparsed.messages.shift();\n\t} else {\n\t\tinitialMessage = textContent;\n\t}\n\n\treturn {\n\t\tinitialMessage,\n\t\tinitialAttachments: imageAttachments.length > 0 ? imageAttachments : undefined,\n\t};\n}\n\nfunction getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): string | null {\n\tif (parsed.continue || parsed.resume) {\n\t\treturn null;\n\t}\n\n\tconst lastVersion = settingsManager.getLastChangelogVersion();\n\tconst changelogPath = getChangelogPath();\n\tconst entries = parseChangelog(changelogPath);\n\n\tif (!lastVersion) {\n\t\tif (entries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn entries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t} else {\n\t\tconst newEntries = getNewEntries(entries, lastVersion);\n\t\tif (newEntries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn newEntries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t}\n\n\treturn null;\n}\n\nfunction createSessionManager(parsed: Args, cwd: string): SessionManager | null {\n\tif (parsed.noSession) {\n\t\treturn SessionManager.inMemory();\n\t}\n\tif (parsed.session) {\n\t\treturn SessionManager.open(parsed.session);\n\t}\n\tif (parsed.continue) {\n\t\treturn SessionManager.continueRecent(cwd);\n\t}\n\t// --resume is handled separately (needs picker UI)\n\t// Default case (new session) returns null, SDK will create one\n\treturn null;\n}\n\n/** Discover SYSTEM.md file if no CLI system prompt was provided */\nfunction discoverSystemPromptFile(): string | undefined {\n\t// Check project-local first: .pi/SYSTEM.md\n\tconst projectPath = join(process.cwd(), CONFIG_DIR_NAME, \"SYSTEM.md\");\n\tif (existsSync(projectPath)) {\n\t\treturn projectPath;\n\t}\n\n\t// Fall back to global: ~/.pi/agent/SYSTEM.md\n\tconst globalPath = join(getAgentDir(), \"SYSTEM.md\");\n\tif (existsSync(globalPath)) {\n\t\treturn globalPath;\n\t}\n\n\treturn undefined;\n}\n\nfunction buildSessionOptions(\n\tparsed: Args,\n\tscopedModels: ScopedModel[],\n\tsessionManager: SessionManager | null,\n\tmodelRegistry: ModelRegistry,\n): CreateAgentSessionOptions {\n\tconst options: CreateAgentSessionOptions = {};\n\n\t// Auto-discover SYSTEM.md if no CLI system prompt provided\n\tconst systemPromptSource = parsed.systemPrompt ?? discoverSystemPromptFile();\n\tconst resolvedSystemPrompt = resolvePromptInput(systemPromptSource, \"system prompt\");\n\tconst resolvedAppendPrompt = resolvePromptInput(parsed.appendSystemPrompt, \"append system prompt\");\n\n\tif (sessionManager) {\n\t\toptions.sessionManager = sessionManager;\n\t}\n\n\t// Model from CLI\n\tif (parsed.provider && parsed.model) {\n\t\tconst model = modelRegistry.find(parsed.provider, parsed.model);\n\t\tif (!model) {\n\t\t\tconsole.error(chalk.red(`Model ${parsed.provider}/${parsed.model} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\toptions.model = model;\n\t} else if (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\toptions.model = scopedModels[0].model;\n\t}\n\n\t// Thinking level\n\tif (parsed.thinking) {\n\t\toptions.thinkingLevel = parsed.thinking;\n\t} else if (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\toptions.thinkingLevel = scopedModels[0].thinkingLevel;\n\t}\n\n\t// Scoped models for Ctrl+P cycling\n\tif (scopedModels.length > 0) {\n\t\toptions.scopedModels = scopedModels;\n\t}\n\n\t// API key from CLI - set in authStorage\n\t// (handled by caller before createAgentSession)\n\n\t// System prompt\n\tif (resolvedSystemPrompt && resolvedAppendPrompt) {\n\t\toptions.systemPrompt = `${resolvedSystemPrompt}\\n\\n${resolvedAppendPrompt}`;\n\t} else if (resolvedSystemPrompt) {\n\t\toptions.systemPrompt = resolvedSystemPrompt;\n\t} else if (resolvedAppendPrompt) {\n\t\toptions.systemPrompt = (defaultPrompt) => `${defaultPrompt}\\n\\n${resolvedAppendPrompt}`;\n\t}\n\n\t// Tools\n\tif (parsed.tools) {\n\t\toptions.tools = parsed.tools.map((name) => allTools[name]);\n\t}\n\n\t// Skills\n\tif (parsed.noSkills) {\n\t\toptions.skills = [];\n\t}\n\n\t// Additional hook paths from CLI\n\tif (parsed.hooks && parsed.hooks.length > 0) {\n\t\toptions.additionalHookPaths = parsed.hooks;\n\t}\n\n\t// Additional custom tool paths from CLI\n\tif (parsed.customTools && parsed.customTools.length > 0) {\n\t\toptions.additionalCustomToolPaths = parsed.customTools;\n\t}\n\n\treturn options;\n}\n\nexport async function main(args: string[]) {\n\ttime(\"start\");\n\n\t// Migrate legacy oauth.json and settings.json apiKeys to auth.json\n\tconst agentDir = getAgentDir();\n\tconst migratedProviders = AuthStorage.migrateLegacy(join(agentDir, \"auth.json\"), agentDir);\n\n\t// Create AuthStorage and ModelRegistry upfront\n\tconst authStorage = discoverAuthStorage();\n\tconst modelRegistry = discoverModels(authStorage);\n\ttime(\"discoverModels\");\n\n\tconst parsed = parseArgs(args);\n\ttime(\"parseArgs\");\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\tif (parsed.listModels !== undefined) {\n\t\tconst searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : undefined;\n\t\tawait listModels(modelRegistry, searchPattern);\n\t\treturn;\n\t}\n\n\tif (parsed.export) {\n\t\ttry {\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tconst result = exportFromFile(parsed.export, outputPath);\n\t\t\tconsole.log(`Exported to: ${result}`);\n\t\t\treturn;\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tconst cwd = process.cwd();\n\tconst { initialMessage, initialAttachments } = await prepareInitialMessage(parsed);\n\ttime(\"prepareInitialMessage\");\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\tconst mode = parsed.mode || \"text\";\n\n\tconst settingsManager = SettingsManager.create(cwd);\n\ttime(\"SettingsManager.create\");\n\tinitTheme(settingsManager.getTheme(), isInteractive);\n\ttime(\"initTheme\");\n\n\tlet scopedModels: ScopedModel[] = [];\n\tif (parsed.models && parsed.models.length > 0) {\n\t\tscopedModels = await resolveModelScope(parsed.models, modelRegistry);\n\t\ttime(\"resolveModelScope\");\n\t}\n\n\t// Create session manager based on CLI flags\n\tlet sessionManager = createSessionManager(parsed, cwd);\n\ttime(\"createSessionManager\");\n\n\t// Handle --resume: show session picker\n\tif (parsed.resume) {\n\t\tconst sessions = SessionManager.list(cwd);\n\t\ttime(\"SessionManager.list\");\n\t\tif (sessions.length === 0) {\n\t\t\tconsole.log(chalk.dim(\"No sessions found\"));\n\t\t\treturn;\n\t\t}\n\t\tconst selectedPath = await selectSession(sessions);\n\t\ttime(\"selectSession\");\n\t\tif (!selectedPath) {\n\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\treturn;\n\t\t}\n\t\tsessionManager = SessionManager.open(selectedPath);\n\t}\n\n\tconst sessionOptions = buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry);\n\tsessionOptions.authStorage = authStorage;\n\tsessionOptions.modelRegistry = modelRegistry;\n\n\t// Handle CLI --api-key as runtime override (not persisted)\n\tif (parsed.apiKey) {\n\t\tif (!sessionOptions.model) {\n\t\t\tconsole.error(chalk.red(\"--api-key requires a model to be specified via --provider/--model or -m/--models\"));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tauthStorage.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);\n\t}\n\n\ttime(\"buildSessionOptions\");\n\tconst { session, customToolsResult, modelFallbackMessage } = await createAgentSession(sessionOptions);\n\ttime(\"createAgentSession\");\n\n\tif (!isInteractive && !session.model) {\n\t\tconsole.error(chalk.red(\"No models available.\"));\n\t\tconsole.error(chalk.yellow(\"\\nSet an API key environment variable:\"));\n\t\tconsole.error(\" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\");\n\t\tconsole.error(chalk.yellow(`\\nOr create ${getModelsPath()}`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Clamp thinking level to model capabilities (for CLI override case)\n\tif (session.model && parsed.thinking) {\n\t\tlet effectiveThinking = parsed.thinking;\n\t\tif (!session.model.reasoning) {\n\t\t\teffectiveThinking = \"off\";\n\t\t} else if (effectiveThinking === \"xhigh\" && !supportsXhigh(session.model)) {\n\t\t\teffectiveThinking = \"high\";\n\t\t}\n\t\tif (effectiveThinking !== session.thinkingLevel) {\n\t\t\tsession.setThinkingLevel(effectiveThinking);\n\t\t}\n\t}\n\n\tif (mode === \"rpc\") {\n\t\tawait runRpcMode(session);\n\t} else if (isInteractive) {\n\t\tconst versionCheckPromise = checkForNewVersion(VERSION).catch(() => null);\n\t\tconst changelogMarkdown = getChangelogForDisplay(parsed, settingsManager);\n\n\t\tif (scopedModels.length > 0) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel !== \"off\" ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\tconst fdPath = await ensureTool(\"fd\");\n\t\ttime(\"ensureTool(fd)\");\n\n\t\tprintTimings();\n\t\tawait runInteractiveMode(\n\t\t\tsession,\n\t\t\tVERSION,\n\t\t\tchangelogMarkdown,\n\t\t\tmodelFallbackMessage,\n\t\t\tmodelRegistry.getError(),\n\t\t\tmigratedProviders,\n\t\t\tversionCheckPromise,\n\t\t\tparsed.messages,\n\t\t\tcustomToolsResult.tools,\n\t\t\tcustomToolsResult.setUIContext,\n\t\t\tinitialMessage,\n\t\t\tinitialAttachments,\n\t\t\tfdPath,\n\t\t);\n\t} else {\n\t\tawait runPrintMode(session, mode, parsed.messages, initialMessage, initialAttachments);\n\t\tstopThemeWatcher();\n\t\tif (process.stdout.writableLength > 0) {\n\t\t\tawait new Promise<void>((resolve) => process.stdout.once(\"drain\", resolve));\n\t\t}\n\t\tprocess.exit(0);\n\t}\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ThinkingLevel } from "@mariozechner/pi-agent-core";
|
|
2
|
+
import { Container, SettingsList } from "@mariozechner/pi-tui";
|
|
3
|
+
export interface SettingsConfig {
|
|
4
|
+
autoCompact: boolean;
|
|
5
|
+
showImages: boolean;
|
|
6
|
+
queueMode: "all" | "one-at-a-time";
|
|
7
|
+
thinkingLevel: ThinkingLevel;
|
|
8
|
+
availableThinkingLevels: ThinkingLevel[];
|
|
9
|
+
currentTheme: string;
|
|
10
|
+
availableThemes: string[];
|
|
11
|
+
hideThinkingBlock: boolean;
|
|
12
|
+
collapseChangelog: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface SettingsCallbacks {
|
|
15
|
+
onAutoCompactChange: (enabled: boolean) => void;
|
|
16
|
+
onShowImagesChange: (enabled: boolean) => void;
|
|
17
|
+
onQueueModeChange: (mode: "all" | "one-at-a-time") => void;
|
|
18
|
+
onThinkingLevelChange: (level: ThinkingLevel) => void;
|
|
19
|
+
onThemeChange: (theme: string) => void;
|
|
20
|
+
onThemePreview?: (theme: string) => void;
|
|
21
|
+
onHideThinkingBlockChange: (hidden: boolean) => void;
|
|
22
|
+
onCollapseChangelogChange: (collapsed: boolean) => void;
|
|
23
|
+
onCancel: () => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Main settings selector component.
|
|
27
|
+
*/
|
|
28
|
+
export declare class SettingsSelectorComponent extends Container {
|
|
29
|
+
private settingsList;
|
|
30
|
+
constructor(config: SettingsConfig, callbacks: SettingsCallbacks);
|
|
31
|
+
getSettingsList(): SettingsList;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=settings-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/settings-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EACN,SAAS,EAKT,YAAY,EAGZ,MAAM,sBAAsB,CAAC;AAa9B,MAAM,WAAW,cAAc;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,KAAK,GAAG,eAAe,CAAC;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,uBAAuB,EAAE,aAAa,EAAE,CAAC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C,iBAAiB,EAAE,CAAC,IAAI,EAAE,KAAK,GAAG,eAAe,KAAK,IAAI,CAAC;IAC3D,qBAAqB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,yBAAyB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,yBAAyB,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IACxD,QAAQ,EAAE,MAAM,IAAI,CAAC;CACrB;AAgED;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,YAAY,CAAe;IAEnC,YAAY,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,iBAAiB,EAkI/D;IAED,eAAe,IAAI,YAAY,CAE9B;CACD","sourcesContent":["import type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport {\n\tContainer,\n\tgetCapabilities,\n\ttype SelectItem,\n\tSelectList,\n\ttype SettingItem,\n\tSettingsList,\n\tSpacer,\n\tText,\n} from \"@mariozechner/pi-tui\";\nimport { getSelectListTheme, getSettingsListTheme, theme } from \"../theme/theme.js\";\nimport { DynamicBorder } from \"./dynamic-border.js\";\n\nconst THINKING_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Maximum reasoning (~32k tokens)\",\n};\n\nexport interface SettingsConfig {\n\tautoCompact: boolean;\n\tshowImages: boolean;\n\tqueueMode: \"all\" | \"one-at-a-time\";\n\tthinkingLevel: ThinkingLevel;\n\tavailableThinkingLevels: ThinkingLevel[];\n\tcurrentTheme: string;\n\tavailableThemes: string[];\n\thideThinkingBlock: boolean;\n\tcollapseChangelog: boolean;\n}\n\nexport interface SettingsCallbacks {\n\tonAutoCompactChange: (enabled: boolean) => void;\n\tonShowImagesChange: (enabled: boolean) => void;\n\tonQueueModeChange: (mode: \"all\" | \"one-at-a-time\") => void;\n\tonThinkingLevelChange: (level: ThinkingLevel) => void;\n\tonThemeChange: (theme: string) => void;\n\tonThemePreview?: (theme: string) => void;\n\tonHideThinkingBlockChange: (hidden: boolean) => void;\n\tonCollapseChangelogChange: (collapsed: boolean) => void;\n\tonCancel: () => void;\n}\n\n/**\n * A submenu component for selecting from a list of options.\n */\nclass SelectSubmenu extends Container {\n\tprivate selectList: SelectList;\n\n\tconstructor(\n\t\ttitle: string,\n\t\tdescription: string,\n\t\toptions: SelectItem[],\n\t\tcurrentValue: string,\n\t\tonSelect: (value: string) => void,\n\t\tonCancel: () => void,\n\t\tonSelectionChange?: (value: string) => void,\n\t) {\n\t\tsuper();\n\n\t\t// Title\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", title)), 0, 0));\n\n\t\t// Description\n\t\tif (description) {\n\t\t\tthis.addChild(new Spacer(1));\n\t\t\tthis.addChild(new Text(theme.fg(\"muted\", description), 0, 0));\n\t\t}\n\n\t\t// Spacer\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Select list\n\t\tthis.selectList = new SelectList(options, Math.min(options.length, 10), getSelectListTheme());\n\n\t\t// Pre-select current value\n\t\tconst currentIndex = options.findIndex((o) => o.value === currentValue);\n\t\tif (currentIndex !== -1) {\n\t\t\tthis.selectList.setSelectedIndex(currentIndex);\n\t\t}\n\n\t\tthis.selectList.onSelect = (item) => {\n\t\t\tonSelect(item.value);\n\t\t};\n\n\t\tthis.selectList.onCancel = onCancel;\n\n\t\tif (onSelectionChange) {\n\t\t\tthis.selectList.onSelectionChange = (item) => {\n\t\t\t\tonSelectionChange(item.value);\n\t\t\t};\n\t\t}\n\n\t\tthis.addChild(this.selectList);\n\n\t\t// Hint\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to select · Esc to go back\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.selectList.handleInput(data);\n\t}\n}\n\n/**\n * Main settings selector component.\n */\nexport class SettingsSelectorComponent extends Container {\n\tprivate settingsList: SettingsList;\n\n\tconstructor(config: SettingsConfig, callbacks: SettingsCallbacks) {\n\t\tsuper();\n\n\t\tconst supportsImages = getCapabilities().images;\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"autocompact\",\n\t\t\t\tlabel: \"Auto-compact\",\n\t\t\t\tdescription: \"Automatically compact context when it gets too large\",\n\t\t\t\tcurrentValue: config.autoCompact ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"queue-mode\",\n\t\t\t\tlabel: \"Queue mode\",\n\t\t\t\tdescription: \"How to process queued messages while agent is working\",\n\t\t\t\tcurrentValue: config.queueMode,\n\t\t\t\tvalues: [\"one-at-a-time\", \"all\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"hide-thinking\",\n\t\t\t\tlabel: \"Hide thinking\",\n\t\t\t\tdescription: \"Hide thinking blocks in assistant responses\",\n\t\t\t\tcurrentValue: config.hideThinkingBlock ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"collapse-changelog\",\n\t\t\t\tlabel: \"Collapse changelog\",\n\t\t\t\tdescription: \"Show condensed changelog after updates\",\n\t\t\t\tcurrentValue: config.collapseChangelog ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"thinking\",\n\t\t\t\tlabel: \"Thinking level\",\n\t\t\t\tdescription: \"Reasoning depth for thinking-capable models\",\n\t\t\t\tcurrentValue: config.thinkingLevel,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Thinking Level\",\n\t\t\t\t\t\t\"Select reasoning depth for thinking-capable models\",\n\t\t\t\t\t\tconfig.availableThinkingLevels.map((level) => ({\n\t\t\t\t\t\t\tvalue: level,\n\t\t\t\t\t\t\tlabel: level,\n\t\t\t\t\t\t\tdescription: THINKING_DESCRIPTIONS[level],\n\t\t\t\t\t\t})),\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tcallbacks.onThinkingLevelChange(value as ThinkingLevel);\n\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => done(),\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"theme\",\n\t\t\t\tlabel: \"Theme\",\n\t\t\t\tdescription: \"Color theme for the interface\",\n\t\t\t\tcurrentValue: config.currentTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Theme\",\n\t\t\t\t\t\t\"Select color theme\",\n\t\t\t\t\t\tconfig.availableThemes.map((t) => ({\n\t\t\t\t\t\t\tvalue: t,\n\t\t\t\t\t\t\tlabel: t,\n\t\t\t\t\t\t})),\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tcallbacks.onThemeChange(value);\n\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t// Restore original theme on cancel\n\t\t\t\t\t\t\tcallbacks.onThemePreview?.(currentValue);\n\t\t\t\t\t\t\tdone();\n\t\t\t\t\t\t},\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\t// Preview theme on selection change\n\t\t\t\t\t\t\tcallbacks.onThemePreview?.(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t},\n\t\t];\n\n\t\t// Only show image toggle if terminal supports it\n\t\tif (supportsImages) {\n\t\t\t// Insert after autocompact\n\t\t\titems.splice(1, 0, {\n\t\t\t\tid: \"show-images\",\n\t\t\t\tlabel: \"Show images\",\n\t\t\t\tdescription: \"Render images inline in terminal\",\n\t\t\t\tcurrentValue: config.showImages ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t});\n\t\t}\n\n\t\t// Add borders\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\t10,\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, newValue) => {\n\t\t\t\tswitch (id) {\n\t\t\t\t\tcase \"autocompact\":\n\t\t\t\t\t\tcallbacks.onAutoCompactChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"show-images\":\n\t\t\t\t\t\tcallbacks.onShowImagesChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"queue-mode\":\n\t\t\t\t\t\tcallbacks.onQueueModeChange(newValue as \"all\" | \"one-at-a-time\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"hide-thinking\":\n\t\t\t\t\t\tcallbacks.onHideThinkingBlockChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"collapse-changelog\":\n\t\t\t\t\t\tcallbacks.onCollapseChangelogChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\tcallbacks.onCancel,\n\t\t);\n\n\t\tthis.addChild(this.settingsList);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tgetSettingsList(): SettingsList {\n\t\treturn this.settingsList;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { Container, getCapabilities, SelectList, SettingsList, Spacer, Text, } from "@mariozechner/pi-tui";
|
|
2
|
+
import { getSelectListTheme, getSettingsListTheme, theme } from "../theme/theme.js";
|
|
3
|
+
import { DynamicBorder } from "./dynamic-border.js";
|
|
4
|
+
const THINKING_DESCRIPTIONS = {
|
|
5
|
+
off: "No reasoning",
|
|
6
|
+
minimal: "Very brief reasoning (~1k tokens)",
|
|
7
|
+
low: "Light reasoning (~2k tokens)",
|
|
8
|
+
medium: "Moderate reasoning (~8k tokens)",
|
|
9
|
+
high: "Deep reasoning (~16k tokens)",
|
|
10
|
+
xhigh: "Maximum reasoning (~32k tokens)",
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A submenu component for selecting from a list of options.
|
|
14
|
+
*/
|
|
15
|
+
class SelectSubmenu extends Container {
|
|
16
|
+
selectList;
|
|
17
|
+
constructor(title, description, options, currentValue, onSelect, onCancel, onSelectionChange) {
|
|
18
|
+
super();
|
|
19
|
+
// Title
|
|
20
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", title)), 0, 0));
|
|
21
|
+
// Description
|
|
22
|
+
if (description) {
|
|
23
|
+
this.addChild(new Spacer(1));
|
|
24
|
+
this.addChild(new Text(theme.fg("muted", description), 0, 0));
|
|
25
|
+
}
|
|
26
|
+
// Spacer
|
|
27
|
+
this.addChild(new Spacer(1));
|
|
28
|
+
// Select list
|
|
29
|
+
this.selectList = new SelectList(options, Math.min(options.length, 10), getSelectListTheme());
|
|
30
|
+
// Pre-select current value
|
|
31
|
+
const currentIndex = options.findIndex((o) => o.value === currentValue);
|
|
32
|
+
if (currentIndex !== -1) {
|
|
33
|
+
this.selectList.setSelectedIndex(currentIndex);
|
|
34
|
+
}
|
|
35
|
+
this.selectList.onSelect = (item) => {
|
|
36
|
+
onSelect(item.value);
|
|
37
|
+
};
|
|
38
|
+
this.selectList.onCancel = onCancel;
|
|
39
|
+
if (onSelectionChange) {
|
|
40
|
+
this.selectList.onSelectionChange = (item) => {
|
|
41
|
+
onSelectionChange(item.value);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
this.addChild(this.selectList);
|
|
45
|
+
// Hint
|
|
46
|
+
this.addChild(new Spacer(1));
|
|
47
|
+
this.addChild(new Text(theme.fg("dim", " Enter to select · Esc to go back"), 0, 0));
|
|
48
|
+
}
|
|
49
|
+
handleInput(data) {
|
|
50
|
+
this.selectList.handleInput(data);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Main settings selector component.
|
|
55
|
+
*/
|
|
56
|
+
export class SettingsSelectorComponent extends Container {
|
|
57
|
+
settingsList;
|
|
58
|
+
constructor(config, callbacks) {
|
|
59
|
+
super();
|
|
60
|
+
const supportsImages = getCapabilities().images;
|
|
61
|
+
const items = [
|
|
62
|
+
{
|
|
63
|
+
id: "autocompact",
|
|
64
|
+
label: "Auto-compact",
|
|
65
|
+
description: "Automatically compact context when it gets too large",
|
|
66
|
+
currentValue: config.autoCompact ? "true" : "false",
|
|
67
|
+
values: ["true", "false"],
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "queue-mode",
|
|
71
|
+
label: "Queue mode",
|
|
72
|
+
description: "How to process queued messages while agent is working",
|
|
73
|
+
currentValue: config.queueMode,
|
|
74
|
+
values: ["one-at-a-time", "all"],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "hide-thinking",
|
|
78
|
+
label: "Hide thinking",
|
|
79
|
+
description: "Hide thinking blocks in assistant responses",
|
|
80
|
+
currentValue: config.hideThinkingBlock ? "true" : "false",
|
|
81
|
+
values: ["true", "false"],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: "collapse-changelog",
|
|
85
|
+
label: "Collapse changelog",
|
|
86
|
+
description: "Show condensed changelog after updates",
|
|
87
|
+
currentValue: config.collapseChangelog ? "true" : "false",
|
|
88
|
+
values: ["true", "false"],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "thinking",
|
|
92
|
+
label: "Thinking level",
|
|
93
|
+
description: "Reasoning depth for thinking-capable models",
|
|
94
|
+
currentValue: config.thinkingLevel,
|
|
95
|
+
submenu: (currentValue, done) => new SelectSubmenu("Thinking Level", "Select reasoning depth for thinking-capable models", config.availableThinkingLevels.map((level) => ({
|
|
96
|
+
value: level,
|
|
97
|
+
label: level,
|
|
98
|
+
description: THINKING_DESCRIPTIONS[level],
|
|
99
|
+
})), currentValue, (value) => {
|
|
100
|
+
callbacks.onThinkingLevelChange(value);
|
|
101
|
+
done(value);
|
|
102
|
+
}, () => done()),
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "theme",
|
|
106
|
+
label: "Theme",
|
|
107
|
+
description: "Color theme for the interface",
|
|
108
|
+
currentValue: config.currentTheme,
|
|
109
|
+
submenu: (currentValue, done) => new SelectSubmenu("Theme", "Select color theme", config.availableThemes.map((t) => ({
|
|
110
|
+
value: t,
|
|
111
|
+
label: t,
|
|
112
|
+
})), currentValue, (value) => {
|
|
113
|
+
callbacks.onThemeChange(value);
|
|
114
|
+
done(value);
|
|
115
|
+
}, () => {
|
|
116
|
+
// Restore original theme on cancel
|
|
117
|
+
callbacks.onThemePreview?.(currentValue);
|
|
118
|
+
done();
|
|
119
|
+
}, (value) => {
|
|
120
|
+
// Preview theme on selection change
|
|
121
|
+
callbacks.onThemePreview?.(value);
|
|
122
|
+
}),
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
// Only show image toggle if terminal supports it
|
|
126
|
+
if (supportsImages) {
|
|
127
|
+
// Insert after autocompact
|
|
128
|
+
items.splice(1, 0, {
|
|
129
|
+
id: "show-images",
|
|
130
|
+
label: "Show images",
|
|
131
|
+
description: "Render images inline in terminal",
|
|
132
|
+
currentValue: config.showImages ? "true" : "false",
|
|
133
|
+
values: ["true", "false"],
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Add borders
|
|
137
|
+
this.addChild(new DynamicBorder());
|
|
138
|
+
this.settingsList = new SettingsList(items, 10, getSettingsListTheme(), (id, newValue) => {
|
|
139
|
+
switch (id) {
|
|
140
|
+
case "autocompact":
|
|
141
|
+
callbacks.onAutoCompactChange(newValue === "true");
|
|
142
|
+
break;
|
|
143
|
+
case "show-images":
|
|
144
|
+
callbacks.onShowImagesChange(newValue === "true");
|
|
145
|
+
break;
|
|
146
|
+
case "queue-mode":
|
|
147
|
+
callbacks.onQueueModeChange(newValue);
|
|
148
|
+
break;
|
|
149
|
+
case "hide-thinking":
|
|
150
|
+
callbacks.onHideThinkingBlockChange(newValue === "true");
|
|
151
|
+
break;
|
|
152
|
+
case "collapse-changelog":
|
|
153
|
+
callbacks.onCollapseChangelogChange(newValue === "true");
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}, callbacks.onCancel);
|
|
157
|
+
this.addChild(this.settingsList);
|
|
158
|
+
this.addChild(new DynamicBorder());
|
|
159
|
+
}
|
|
160
|
+
getSettingsList() {
|
|
161
|
+
return this.settingsList;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=settings-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/settings-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport {\n\tContainer,\n\tgetCapabilities,\n\ttype SelectItem,\n\tSelectList,\n\ttype SettingItem,\n\tSettingsList,\n\tSpacer,\n\tText,\n} from \"@mariozechner/pi-tui\";\nimport { getSelectListTheme, getSettingsListTheme, theme } from \"../theme/theme.js\";\nimport { DynamicBorder } from \"./dynamic-border.js\";\n\nconst THINKING_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Maximum reasoning (~32k tokens)\",\n};\n\nexport interface SettingsConfig {\n\tautoCompact: boolean;\n\tshowImages: boolean;\n\tqueueMode: \"all\" | \"one-at-a-time\";\n\tthinkingLevel: ThinkingLevel;\n\tavailableThinkingLevels: ThinkingLevel[];\n\tcurrentTheme: string;\n\tavailableThemes: string[];\n\thideThinkingBlock: boolean;\n\tcollapseChangelog: boolean;\n}\n\nexport interface SettingsCallbacks {\n\tonAutoCompactChange: (enabled: boolean) => void;\n\tonShowImagesChange: (enabled: boolean) => void;\n\tonQueueModeChange: (mode: \"all\" | \"one-at-a-time\") => void;\n\tonThinkingLevelChange: (level: ThinkingLevel) => void;\n\tonThemeChange: (theme: string) => void;\n\tonThemePreview?: (theme: string) => void;\n\tonHideThinkingBlockChange: (hidden: boolean) => void;\n\tonCollapseChangelogChange: (collapsed: boolean) => void;\n\tonCancel: () => void;\n}\n\n/**\n * A submenu component for selecting from a list of options.\n */\nclass SelectSubmenu extends Container {\n\tprivate selectList: SelectList;\n\n\tconstructor(\n\t\ttitle: string,\n\t\tdescription: string,\n\t\toptions: SelectItem[],\n\t\tcurrentValue: string,\n\t\tonSelect: (value: string) => void,\n\t\tonCancel: () => void,\n\t\tonSelectionChange?: (value: string) => void,\n\t) {\n\t\tsuper();\n\n\t\t// Title\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", title)), 0, 0));\n\n\t\t// Description\n\t\tif (description) {\n\t\t\tthis.addChild(new Spacer(1));\n\t\t\tthis.addChild(new Text(theme.fg(\"muted\", description), 0, 0));\n\t\t}\n\n\t\t// Spacer\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Select list\n\t\tthis.selectList = new SelectList(options, Math.min(options.length, 10), getSelectListTheme());\n\n\t\t// Pre-select current value\n\t\tconst currentIndex = options.findIndex((o) => o.value === currentValue);\n\t\tif (currentIndex !== -1) {\n\t\t\tthis.selectList.setSelectedIndex(currentIndex);\n\t\t}\n\n\t\tthis.selectList.onSelect = (item) => {\n\t\t\tonSelect(item.value);\n\t\t};\n\n\t\tthis.selectList.onCancel = onCancel;\n\n\t\tif (onSelectionChange) {\n\t\t\tthis.selectList.onSelectionChange = (item) => {\n\t\t\t\tonSelectionChange(item.value);\n\t\t\t};\n\t\t}\n\n\t\tthis.addChild(this.selectList);\n\n\t\t// Hint\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to select · Esc to go back\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.selectList.handleInput(data);\n\t}\n}\n\n/**\n * Main settings selector component.\n */\nexport class SettingsSelectorComponent extends Container {\n\tprivate settingsList: SettingsList;\n\n\tconstructor(config: SettingsConfig, callbacks: SettingsCallbacks) {\n\t\tsuper();\n\n\t\tconst supportsImages = getCapabilities().images;\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"autocompact\",\n\t\t\t\tlabel: \"Auto-compact\",\n\t\t\t\tdescription: \"Automatically compact context when it gets too large\",\n\t\t\t\tcurrentValue: config.autoCompact ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"queue-mode\",\n\t\t\t\tlabel: \"Queue mode\",\n\t\t\t\tdescription: \"How to process queued messages while agent is working\",\n\t\t\t\tcurrentValue: config.queueMode,\n\t\t\t\tvalues: [\"one-at-a-time\", \"all\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"hide-thinking\",\n\t\t\t\tlabel: \"Hide thinking\",\n\t\t\t\tdescription: \"Hide thinking blocks in assistant responses\",\n\t\t\t\tcurrentValue: config.hideThinkingBlock ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"collapse-changelog\",\n\t\t\t\tlabel: \"Collapse changelog\",\n\t\t\t\tdescription: \"Show condensed changelog after updates\",\n\t\t\t\tcurrentValue: config.collapseChangelog ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"thinking\",\n\t\t\t\tlabel: \"Thinking level\",\n\t\t\t\tdescription: \"Reasoning depth for thinking-capable models\",\n\t\t\t\tcurrentValue: config.thinkingLevel,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Thinking Level\",\n\t\t\t\t\t\t\"Select reasoning depth for thinking-capable models\",\n\t\t\t\t\t\tconfig.availableThinkingLevels.map((level) => ({\n\t\t\t\t\t\t\tvalue: level,\n\t\t\t\t\t\t\tlabel: level,\n\t\t\t\t\t\t\tdescription: THINKING_DESCRIPTIONS[level],\n\t\t\t\t\t\t})),\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tcallbacks.onThinkingLevelChange(value as ThinkingLevel);\n\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => done(),\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"theme\",\n\t\t\t\tlabel: \"Theme\",\n\t\t\t\tdescription: \"Color theme for the interface\",\n\t\t\t\tcurrentValue: config.currentTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Theme\",\n\t\t\t\t\t\t\"Select color theme\",\n\t\t\t\t\t\tconfig.availableThemes.map((t) => ({\n\t\t\t\t\t\t\tvalue: t,\n\t\t\t\t\t\t\tlabel: t,\n\t\t\t\t\t\t})),\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tcallbacks.onThemeChange(value);\n\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t// Restore original theme on cancel\n\t\t\t\t\t\t\tcallbacks.onThemePreview?.(currentValue);\n\t\t\t\t\t\t\tdone();\n\t\t\t\t\t\t},\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\t// Preview theme on selection change\n\t\t\t\t\t\t\tcallbacks.onThemePreview?.(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t},\n\t\t];\n\n\t\t// Only show image toggle if terminal supports it\n\t\tif (supportsImages) {\n\t\t\t// Insert after autocompact\n\t\t\titems.splice(1, 0, {\n\t\t\t\tid: \"show-images\",\n\t\t\t\tlabel: \"Show images\",\n\t\t\t\tdescription: \"Render images inline in terminal\",\n\t\t\t\tcurrentValue: config.showImages ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t});\n\t\t}\n\n\t\t// Add borders\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\t10,\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, newValue) => {\n\t\t\t\tswitch (id) {\n\t\t\t\t\tcase \"autocompact\":\n\t\t\t\t\t\tcallbacks.onAutoCompactChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"show-images\":\n\t\t\t\t\t\tcallbacks.onShowImagesChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"queue-mode\":\n\t\t\t\t\t\tcallbacks.onQueueModeChange(newValue as \"all\" | \"one-at-a-time\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"hide-thinking\":\n\t\t\t\t\t\tcallbacks.onHideThinkingBlockChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"collapse-changelog\":\n\t\t\t\t\t\tcallbacks.onCollapseChangelogChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\tcallbacks.onCancel,\n\t\t);\n\n\t\tthis.addChild(this.settingsList);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tgetSettingsList(): SettingsList {\n\t\treturn this.settingsList;\n\t}\n}\n"]}
|
|
@@ -125,9 +125,7 @@ export declare class InteractiveMode {
|
|
|
125
125
|
* @param create Factory that receives a `done` callback and returns the component and focus target
|
|
126
126
|
*/
|
|
127
127
|
private showSelector;
|
|
128
|
-
private
|
|
129
|
-
private showQueueModeSelector;
|
|
130
|
-
private showThemeSelector;
|
|
128
|
+
private showSettingsSelector;
|
|
131
129
|
private showModelSelector;
|
|
132
130
|
private showUserMessageSelector;
|
|
133
131
|
private showSessionSelector;
|
|
@@ -143,8 +141,6 @@ export declare class InteractiveMode {
|
|
|
143
141
|
private handleArminSaysHi;
|
|
144
142
|
private handleBashCommand;
|
|
145
143
|
private handleCompactCommand;
|
|
146
|
-
private handleAutocompactCommand;
|
|
147
|
-
private showShowImagesSelector;
|
|
148
144
|
private executeCompaction;
|
|
149
145
|
stop(): void;
|
|
150
146
|
}
|