@oh-my-pi/pi-coding-agent 15.4.2 → 15.5.0
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 +80 -4
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/auth-broker-cli.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +8 -0
- package/dist/types/config/settings-schema.d.ts +42 -1
- package/dist/types/edit/index.d.ts +2 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +8 -2
- package/dist/types/extensibility/hooks/types.d.ts +4 -0
- package/dist/types/lsp/index.d.ts +9 -1
- package/dist/types/mcp/client.d.ts +2 -1
- package/dist/types/mcp/oauth-discovery.d.ts +4 -3
- package/dist/types/mcp/timeout.d.ts +9 -0
- package/dist/types/mcp/types.d.ts +1 -1
- package/dist/types/sdk.d.ts +2 -0
- package/dist/types/session/streaming-output.d.ts +1 -1
- package/dist/types/task/index.d.ts +2 -0
- package/dist/types/task/types.d.ts +4 -0
- package/dist/types/tools/approval.d.ts +46 -0
- package/dist/types/tools/ask.d.ts +1 -0
- package/dist/types/tools/ast-edit.d.ts +2 -0
- package/dist/types/tools/ast-grep.d.ts +1 -0
- package/dist/types/tools/bash.d.ts +11 -1
- package/dist/types/tools/browser.d.ts +2 -0
- package/dist/types/tools/calculator.d.ts +1 -0
- package/dist/types/tools/checkpoint.d.ts +2 -0
- package/dist/types/tools/debug.d.ts +9 -1
- package/dist/types/tools/eval.d.ts +2 -0
- package/dist/types/tools/find.d.ts +10 -0
- package/dist/types/tools/gh.d.ts +2 -1
- package/dist/types/tools/hindsight-recall.d.ts +1 -0
- package/dist/types/tools/hindsight-reflect.d.ts +1 -0
- package/dist/types/tools/hindsight-retain.d.ts +1 -0
- package/dist/types/tools/inspect-image.d.ts +1 -0
- package/dist/types/tools/irc.d.ts +1 -0
- package/dist/types/tools/job.d.ts +1 -0
- package/dist/types/tools/read.d.ts +1 -0
- package/dist/types/tools/recipe/index.d.ts +1 -0
- package/dist/types/tools/render-mermaid.d.ts +1 -0
- package/dist/types/tools/resolve.d.ts +1 -0
- package/dist/types/tools/search-tool-bm25.d.ts +1 -0
- package/dist/types/tools/search.d.ts +1 -0
- package/dist/types/tools/ssh.d.ts +2 -0
- package/dist/types/tools/todo-write.d.ts +1 -0
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/tools/yield.d.ts +1 -0
- package/dist/types/web/search/index.d.ts +1 -0
- package/package.json +7 -7
- package/src/cli/args.ts +14 -0
- package/src/cli/auth-broker-cli.ts +171 -22
- package/src/commands/auth-broker.ts +3 -0
- package/src/commands/launch.ts +16 -0
- package/src/config/mcp-schema.json +2 -2
- package/src/config/model-registry.ts +49 -5
- package/src/config/settings-schema.ts +59 -1
- package/src/config/settings.ts +2 -1
- package/src/dap/session.ts +35 -2
- package/src/discovery/builtin.ts +2 -2
- package/src/discovery/mcp-json.ts +1 -1
- package/src/edit/index.ts +26 -0
- package/src/edit/modes/patch.ts +1 -1
- package/src/edit/streaming.ts +12 -2
- package/src/exec/bash-executor.ts +6 -2
- package/src/extensibility/custom-commands/bundled/review/index.ts +18 -14
- package/src/extensibility/custom-tools/types.ts +16 -2
- package/src/extensibility/extensions/wrapper.ts +36 -1
- package/src/extensibility/hooks/types.ts +8 -1
- package/src/hashline/apply.ts +47 -2
- package/src/internal-urls/docs-index.generated.ts +8 -7
- package/src/lsp/edits.ts +82 -29
- package/src/lsp/index.ts +38 -1
- package/src/lsp/utils.ts +1 -1
- package/src/main.ts +6 -0
- package/src/mcp/client.ts +8 -6
- package/src/mcp/oauth-discovery.ts +120 -32
- package/src/mcp/oauth-flow.ts +34 -6
- package/src/mcp/timeout.ts +59 -0
- package/src/mcp/transports/http.ts +42 -44
- package/src/mcp/transports/stdio.ts +8 -5
- package/src/mcp/types.ts +1 -1
- package/src/modes/components/hook-editor.ts +11 -3
- package/src/modes/components/mcp-add-wizard.ts +6 -2
- package/src/modes/components/model-selector.ts +33 -11
- package/src/modes/controllers/command-controller.ts +6 -4
- package/src/modes/controllers/mcp-command-controller.ts +8 -4
- package/src/prompts/review-custom-request.md +22 -0
- package/src/prompts/review-headless-request.md +16 -0
- package/src/prompts/review-request.md +2 -3
- package/src/prompts/system/project-prompt.md +4 -0
- package/src/prompts/tools/debug.md +1 -0
- package/src/prompts/tools/find.md +4 -2
- package/src/prompts/tools/hashline.md +1 -0
- package/src/sdk.ts +47 -73
- package/src/session/agent-session.ts +93 -27
- package/src/session/streaming-output.ts +1 -1
- package/src/slash-commands/helpers/usage-report.ts +3 -1
- package/src/task/executor.ts +11 -0
- package/src/task/index.ts +19 -0
- package/src/task/render.ts +12 -2
- package/src/task/types.ts +4 -0
- package/src/tools/approval.ts +185 -0
- package/src/tools/ask.ts +1 -0
- package/src/tools/ast-edit.ts +25 -1
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash.ts +69 -1
- package/src/tools/browser/tab-supervisor.ts +1 -1
- package/src/tools/browser.ts +15 -0
- package/src/tools/calculator.ts +1 -0
- package/src/tools/checkpoint.ts +2 -0
- package/src/tools/debug.ts +38 -0
- package/src/tools/eval.ts +15 -0
- package/src/tools/find.ts +17 -8
- package/src/tools/gh.ts +28 -5
- package/src/tools/hindsight-recall.ts +1 -0
- package/src/tools/hindsight-reflect.ts +1 -0
- package/src/tools/hindsight-retain.ts +1 -0
- package/src/tools/image-gen.ts +1 -0
- package/src/tools/inspect-image.ts +1 -0
- package/src/tools/irc.ts +1 -0
- package/src/tools/job.ts +1 -0
- package/src/tools/path-utils.ts +14 -1
- package/src/tools/read.ts +1 -0
- package/src/tools/recipe/index.ts +1 -0
- package/src/tools/render-mermaid.ts +1 -0
- package/src/tools/report-tool-issue.ts +1 -0
- package/src/tools/resolve.ts +1 -0
- package/src/tools/review.ts +1 -0
- package/src/tools/search-tool-bm25.ts +1 -0
- package/src/tools/search.ts +1 -0
- package/src/tools/ssh.ts +8 -0
- package/src/tools/todo-write.ts +1 -0
- package/src/tools/write.ts +12 -1
- package/src/tools/yield.ts +1 -0
- package/src/web/search/index.ts +2 -0
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback, RenderResultOptions } from "@oh-my-pi/pi-agent-core";
|
|
1
|
+
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback, RenderResultOptions, ToolApprovalDecision } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import { type Component } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import * as z from "zod/v4";
|
|
4
4
|
import { type DapBreakpointRecord, type DapContinueOutcome, type DapDataBreakpointInfoResponse, type DapDataBreakpointRecord, type DapDisassembledInstruction, type DapEvaluateResponse, type DapFunctionBreakpointRecord, type DapInstructionBreakpointRecord, type DapModule, type DapScope, type DapSessionSummary, type DapSource, type DapStackFrame, type DapThread, type DapVariable } from "../dap";
|
|
5
5
|
import type { Theme } from "../modes/theme/theme";
|
|
6
6
|
import type { ToolSession } from ".";
|
|
7
7
|
import type { OutputMeta } from "./output-meta";
|
|
8
|
+
/**
|
|
9
|
+
* DAP debug actions that only read program state (no mutation, no execution).
|
|
10
|
+
* Execution-side actions (`launch`, `attach`, `continue`, `step_*`, `pause`,
|
|
11
|
+
* `evaluate`, breakpoint mutations, memory writes) are exec-tier.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DEBUG_READONLY_ACTIONS: ReadonlySet<string>;
|
|
8
14
|
declare const debugSchema: z.ZodObject<{
|
|
9
15
|
action: z.ZodEnum<{
|
|
10
16
|
attach: "attach";
|
|
@@ -125,6 +131,8 @@ export declare const debugToolRenderer: {
|
|
|
125
131
|
export declare class DebugTool implements AgentTool<typeof debugSchema, DebugToolDetails> {
|
|
126
132
|
private readonly session;
|
|
127
133
|
readonly name = "debug";
|
|
134
|
+
readonly approval: (args: unknown) => ToolApprovalDecision;
|
|
135
|
+
readonly formatApprovalDetails: (args: unknown) => string[];
|
|
128
136
|
readonly label = "Debug";
|
|
129
137
|
readonly summary = "Debug a running process with DAP (debugger adapter protocol)";
|
|
130
138
|
readonly description: string;
|
|
@@ -54,6 +54,8 @@ export declare class EvalTool implements AgentTool<typeof evalSchema> {
|
|
|
54
54
|
#private;
|
|
55
55
|
private readonly session;
|
|
56
56
|
readonly name = "eval";
|
|
57
|
+
readonly approval: "exec";
|
|
58
|
+
readonly formatApprovalDetails: (args: unknown) => string[];
|
|
57
59
|
readonly summary = "Execute Python or JavaScript code in an in-process eval backend";
|
|
58
60
|
readonly loadMode = "discoverable";
|
|
59
61
|
readonly label = "Eval";
|
|
@@ -14,6 +14,15 @@ declare const findSchema: z.ZodObject<{
|
|
|
14
14
|
timeout: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
15
15
|
}, z.core.$strict>;
|
|
16
16
|
export type FindToolInput = z.infer<typeof findSchema>;
|
|
17
|
+
/**
|
|
18
|
+
* Reject comma-separated path lists packed into a single array element
|
|
19
|
+
* (`["a.py,b.py"]`). The schema is array-of-string; agents that pass a
|
|
20
|
+
* single comma-joined element get silent no-matches otherwise.
|
|
21
|
+
*
|
|
22
|
+
* Commas inside brace expansion (`{a,b}`) are legitimate glob syntax and
|
|
23
|
+
* must pass through.
|
|
24
|
+
*/
|
|
25
|
+
export declare function validateFindPathInputs(paths: readonly string[]): void;
|
|
17
26
|
export interface FindToolDetails {
|
|
18
27
|
truncation?: TruncationResult;
|
|
19
28
|
resultLimitReached?: number;
|
|
@@ -60,6 +69,7 @@ export declare class FindTool implements AgentTool<typeof findSchema, FindToolDe
|
|
|
60
69
|
#private;
|
|
61
70
|
private readonly session;
|
|
62
71
|
readonly name = "find";
|
|
72
|
+
readonly approval: "read";
|
|
63
73
|
readonly summary = "Find files and directories matching a glob pattern";
|
|
64
74
|
readonly loadMode = "discoverable";
|
|
65
75
|
readonly label = "Find";
|
package/dist/types/tools/gh.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
1
|
+
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback, ToolApprovalDecision } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import * as z from "zod/v4";
|
|
3
3
|
import type { Settings } from "../config/settings";
|
|
4
4
|
import type { ToolSession } from ".";
|
|
@@ -230,6 +230,7 @@ export declare function resolveDefaultRepoMemoized(cwd: string, signal?: AbortSi
|
|
|
230
230
|
export declare class GithubTool implements AgentTool<typeof githubSchema, GhToolDetails> {
|
|
231
231
|
private readonly session;
|
|
232
232
|
readonly name = "github";
|
|
233
|
+
readonly approval: (args: unknown) => ToolApprovalDecision;
|
|
233
234
|
readonly summary = "Interact with GitHub issues, pull requests, and repositories";
|
|
234
235
|
readonly loadMode = "discoverable";
|
|
235
236
|
readonly label = "GitHub";
|
|
@@ -8,6 +8,7 @@ export type HindsightRecallParams = z.infer<typeof hindsightRecallSchema>;
|
|
|
8
8
|
export declare class HindsightRecallTool implements AgentTool<typeof hindsightRecallSchema> {
|
|
9
9
|
private readonly session;
|
|
10
10
|
readonly name = "recall";
|
|
11
|
+
readonly approval: "read";
|
|
11
12
|
readonly label = "Recall";
|
|
12
13
|
readonly description: string;
|
|
13
14
|
readonly parameters: z.ZodObject<{
|
|
@@ -9,6 +9,7 @@ export type HindsightReflectParams = z.infer<typeof hindsightReflectSchema>;
|
|
|
9
9
|
export declare class HindsightReflectTool implements AgentTool<typeof hindsightReflectSchema> {
|
|
10
10
|
private readonly session;
|
|
11
11
|
readonly name = "reflect";
|
|
12
|
+
readonly approval: "read";
|
|
12
13
|
readonly label = "Reflect";
|
|
13
14
|
readonly description: string;
|
|
14
15
|
readonly parameters: z.ZodObject<{
|
|
@@ -11,6 +11,7 @@ export type HindsightRetainParams = z.infer<typeof hindsightRetainSchema>;
|
|
|
11
11
|
export declare class HindsightRetainTool implements AgentTool<typeof hindsightRetainSchema> {
|
|
12
12
|
private readonly session;
|
|
13
13
|
readonly name = "retain";
|
|
14
|
+
readonly approval: "read";
|
|
14
15
|
readonly label = "Retain";
|
|
15
16
|
readonly description: string;
|
|
16
17
|
readonly parameters: z.ZodObject<{
|
|
@@ -16,6 +16,7 @@ export declare class InspectImageTool implements AgentTool<typeof inspectImageSc
|
|
|
16
16
|
private readonly session;
|
|
17
17
|
private readonly completeImageRequest;
|
|
18
18
|
readonly name = "inspect_image";
|
|
19
|
+
readonly approval: "read";
|
|
19
20
|
readonly label = "InspectImage";
|
|
20
21
|
readonly loadMode = "discoverable";
|
|
21
22
|
readonly summary = "Describe or analyze an image file";
|
|
@@ -58,6 +58,7 @@ export declare class IrcTool implements AgentTool<typeof ircSchema, IrcDetails>
|
|
|
58
58
|
#private;
|
|
59
59
|
private readonly session;
|
|
60
60
|
readonly name = "irc";
|
|
61
|
+
readonly approval: "read";
|
|
61
62
|
readonly label = "IRC";
|
|
62
63
|
readonly summary = "Send and receive messages between agents over IRC-like channels";
|
|
63
64
|
readonly description: string;
|
|
@@ -31,6 +31,7 @@ export declare class JobTool implements AgentTool<typeof jobSchema, JobToolDetai
|
|
|
31
31
|
#private;
|
|
32
32
|
private readonly session;
|
|
33
33
|
readonly name = "job";
|
|
34
|
+
readonly approval: "read";
|
|
34
35
|
readonly label = "Job";
|
|
35
36
|
readonly summary = "Manage long-running background jobs (async bash/python)";
|
|
36
37
|
readonly description: string;
|
|
@@ -51,6 +51,7 @@ export declare class ReadTool implements AgentTool<typeof readSchema, ReadToolDe
|
|
|
51
51
|
#private;
|
|
52
52
|
private readonly session;
|
|
53
53
|
readonly name = "read";
|
|
54
|
+
readonly approval: "read";
|
|
54
55
|
readonly label = "Read";
|
|
55
56
|
readonly loadMode = "essential";
|
|
56
57
|
readonly description: string;
|
|
@@ -23,6 +23,7 @@ export declare class RecipeTool implements AgentTool<typeof recipeSchema, BashTo
|
|
|
23
23
|
#private;
|
|
24
24
|
readonly name = "recipe";
|
|
25
25
|
readonly label = "Run";
|
|
26
|
+
readonly approval: "exec";
|
|
26
27
|
readonly description: string;
|
|
27
28
|
readonly parameters: z.ZodObject<{
|
|
28
29
|
op: z.ZodString;
|
|
@@ -17,6 +17,7 @@ export interface RenderMermaidToolDetails {
|
|
|
17
17
|
export declare class RenderMermaidTool implements AgentTool<typeof renderMermaidSchema, RenderMermaidToolDetails> {
|
|
18
18
|
private readonly session;
|
|
19
19
|
readonly name = "render_mermaid";
|
|
20
|
+
readonly approval: "read";
|
|
20
21
|
readonly label = "RenderMermaid";
|
|
21
22
|
readonly summary = "Render a Mermaid diagram to an image";
|
|
22
23
|
readonly description: string;
|
|
@@ -58,6 +58,7 @@ export declare function runResolveInvocation(params: ResolveParams, options: {
|
|
|
58
58
|
export declare class ResolveTool implements AgentTool<typeof resolveSchema, ResolveToolDetails> {
|
|
59
59
|
private readonly session;
|
|
60
60
|
readonly name = "resolve";
|
|
61
|
+
readonly approval: "read";
|
|
61
62
|
readonly label = "Resolve";
|
|
62
63
|
readonly hidden = true;
|
|
63
64
|
readonly description: string;
|
|
@@ -37,6 +37,7 @@ export declare function renderSearchToolBm25Description(discoverableTools?: Disc
|
|
|
37
37
|
export declare class SearchToolBm25Tool implements AgentTool<typeof searchToolBm25Schema, SearchToolBm25Details> {
|
|
38
38
|
private readonly session;
|
|
39
39
|
readonly name = "search_tool_bm25";
|
|
40
|
+
readonly approval: "read";
|
|
40
41
|
readonly label = "SearchTools";
|
|
41
42
|
readonly loadMode = "essential";
|
|
42
43
|
get description(): string;
|
|
@@ -56,6 +56,7 @@ type SearchParams = z.infer<typeof searchSchema>;
|
|
|
56
56
|
export declare class SearchTool implements AgentTool<typeof searchSchema, SearchToolDetails> {
|
|
57
57
|
private readonly session;
|
|
58
58
|
readonly name = "search";
|
|
59
|
+
readonly approval: "read";
|
|
59
60
|
readonly label = "Search";
|
|
60
61
|
readonly loadMode = "discoverable";
|
|
61
62
|
readonly summary = "Search file contents using ripgrep (fast text search)";
|
|
@@ -23,6 +23,8 @@ export declare class SshTool implements AgentTool<typeof sshSchema, SSHToolDetai
|
|
|
23
23
|
private readonly hostsByName;
|
|
24
24
|
readonly description: string;
|
|
25
25
|
readonly name = "ssh";
|
|
26
|
+
readonly approval: "exec";
|
|
27
|
+
readonly formatApprovalDetails: (args: unknown) => string[];
|
|
26
28
|
readonly summary = "Execute a command on a remote host over SSH";
|
|
27
29
|
readonly loadMode = "discoverable";
|
|
28
30
|
readonly label = "SSH";
|
|
@@ -64,6 +64,7 @@ export declare function markdownToPhases(md: string): {
|
|
|
64
64
|
export declare class TodoWriteTool implements AgentTool<typeof todoWriteSchema, TodoWriteToolDetails> {
|
|
65
65
|
private readonly session;
|
|
66
66
|
readonly name = "todo_write";
|
|
67
|
+
readonly approval: "read";
|
|
67
68
|
readonly label = "Todo Write";
|
|
68
69
|
readonly summary = "Write a structured todo list to track progress within a session";
|
|
69
70
|
readonly description: string;
|
|
@@ -26,6 +26,8 @@ export declare class WriteTool implements AgentTool<typeof writeSchema, WriteToo
|
|
|
26
26
|
#private;
|
|
27
27
|
private readonly session;
|
|
28
28
|
readonly name = "write";
|
|
29
|
+
readonly approval: (args: unknown) => "read" | "write";
|
|
30
|
+
readonly formatApprovalDetails: (args: unknown) => string[];
|
|
29
31
|
readonly label = "Write";
|
|
30
32
|
readonly description: string;
|
|
31
33
|
readonly parameters: z.ZodObject<{
|
|
@@ -14,6 +14,7 @@ export interface YieldDetails {
|
|
|
14
14
|
export declare class YieldTool implements AgentTool<TSchema, YieldDetails> {
|
|
15
15
|
#private;
|
|
16
16
|
readonly name = "yield";
|
|
17
|
+
readonly approval: "read";
|
|
17
18
|
readonly label = "Submit Result";
|
|
18
19
|
readonly description: string;
|
|
19
20
|
readonly parameters: TSchema;
|
|
@@ -55,6 +55,7 @@ export declare function runSearchQuery(params: SearchQueryParams, options?: {
|
|
|
55
55
|
export declare class WebSearchTool implements AgentTool<typeof webSearchSchema, SearchRenderDetails> {
|
|
56
56
|
#private;
|
|
57
57
|
readonly name = "web_search";
|
|
58
|
+
readonly approval: "read";
|
|
58
59
|
readonly label = "Web Search";
|
|
59
60
|
readonly description: string;
|
|
60
61
|
readonly parameters: z.ZodObject<{
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.5.0",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
48
48
|
"@babel/parser": "^7.29.3",
|
|
49
49
|
"@mozilla/readability": "^0.6.0",
|
|
50
|
-
"@oh-my-pi/omp-stats": "15.
|
|
51
|
-
"@oh-my-pi/pi-agent-core": "15.
|
|
52
|
-
"@oh-my-pi/pi-ai": "15.
|
|
53
|
-
"@oh-my-pi/pi-natives": "15.
|
|
54
|
-
"@oh-my-pi/pi-tui": "15.
|
|
55
|
-
"@oh-my-pi/pi-utils": "15.
|
|
50
|
+
"@oh-my-pi/omp-stats": "15.5.0",
|
|
51
|
+
"@oh-my-pi/pi-agent-core": "15.5.0",
|
|
52
|
+
"@oh-my-pi/pi-ai": "15.5.0",
|
|
53
|
+
"@oh-my-pi/pi-natives": "15.5.0",
|
|
54
|
+
"@oh-my-pi/pi-tui": "15.5.0",
|
|
55
|
+
"@oh-my-pi/pi-utils": "15.5.0",
|
|
56
56
|
"@puppeteer/browsers": "^2.13.0",
|
|
57
57
|
"@types/turndown": "5.0.6",
|
|
58
58
|
"@xterm/headless": "^6.0.0",
|
package/src/cli/args.ts
CHANGED
|
@@ -46,6 +46,8 @@ export interface Args {
|
|
|
46
46
|
noRules?: boolean;
|
|
47
47
|
listModels?: string | true;
|
|
48
48
|
noTitle?: boolean;
|
|
49
|
+
autoApprove?: boolean;
|
|
50
|
+
approvalMode?: "always-ask" | "write" | "yolo";
|
|
49
51
|
messages: string[];
|
|
50
52
|
fileArgs: string[];
|
|
51
53
|
/** Unknown flags (potentially extension flags) - map of flag name to value */
|
|
@@ -172,6 +174,18 @@ export function parseArgs(args: string[], extensionFlags?: Map<string, { type: "
|
|
|
172
174
|
result.noRules = true;
|
|
173
175
|
} else if (arg === "--no-title") {
|
|
174
176
|
result.noTitle = true;
|
|
177
|
+
} else if (arg === "--auto-approve" || arg === "--yolo") {
|
|
178
|
+
result.autoApprove = true;
|
|
179
|
+
} else if (arg === "--approval-mode" && i + 1 < args.length) {
|
|
180
|
+
const mode = args[++i];
|
|
181
|
+
if (mode === "always-ask" || mode === "write" || mode === "yolo") {
|
|
182
|
+
result.approvalMode = mode;
|
|
183
|
+
} else {
|
|
184
|
+
logger.warn("Invalid value passed to --approval-mode", {
|
|
185
|
+
value: mode,
|
|
186
|
+
validValues: ["always-ask", "write", "yolo"],
|
|
187
|
+
});
|
|
188
|
+
}
|
|
175
189
|
} else if (arg === "--skills" && i + 1 < args.length) {
|
|
176
190
|
// Comma-separated glob patterns for skill filtering
|
|
177
191
|
result.skills = args[++i].split(",").map(s => s.trim());
|
|
@@ -17,6 +17,7 @@ import * as crypto from "node:crypto";
|
|
|
17
17
|
import * as fs from "node:fs/promises";
|
|
18
18
|
import * as os from "node:os";
|
|
19
19
|
import * as path from "node:path";
|
|
20
|
+
import * as readline from "node:readline";
|
|
20
21
|
import {
|
|
21
22
|
AuthBrokerClient,
|
|
22
23
|
type AuthCredential,
|
|
@@ -28,6 +29,7 @@ import {
|
|
|
28
29
|
listProvidersWithEnvKey,
|
|
29
30
|
type OAuthCredential,
|
|
30
31
|
type OAuthProvider,
|
|
32
|
+
type OAuthProviderInfo,
|
|
31
33
|
SqliteAuthCredentialStore,
|
|
32
34
|
startAuthBroker,
|
|
33
35
|
} from "@oh-my-pi/pi-ai";
|
|
@@ -36,7 +38,7 @@ import { $ } from "bun";
|
|
|
36
38
|
import chalk from "chalk";
|
|
37
39
|
import { resolveAuthBrokerConfig } from "../session/auth-broker-config";
|
|
38
40
|
|
|
39
|
-
export type AuthBrokerAction = "serve" | "token" | "login" | "logout" | "status" | "import" | "migrate";
|
|
41
|
+
export type AuthBrokerAction = "serve" | "token" | "login" | "logout" | "status" | "import" | "migrate" | "list";
|
|
40
42
|
|
|
41
43
|
export interface AuthBrokerCommandArgs {
|
|
42
44
|
action: AuthBrokerAction;
|
|
@@ -60,7 +62,16 @@ export interface AuthBrokerCommandArgs {
|
|
|
60
62
|
};
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
const ACTIONS: readonly AuthBrokerAction[] = [
|
|
65
|
+
const ACTIONS: readonly AuthBrokerAction[] = [
|
|
66
|
+
"serve",
|
|
67
|
+
"token",
|
|
68
|
+
"login",
|
|
69
|
+
"logout",
|
|
70
|
+
"import",
|
|
71
|
+
"migrate",
|
|
72
|
+
"status",
|
|
73
|
+
"list",
|
|
74
|
+
];
|
|
64
75
|
|
|
65
76
|
/** Callback ports baked from the per-provider OAuth flow modules. */
|
|
66
77
|
const CALLBACK_PORTS: Record<string, number> = {
|
|
@@ -168,13 +179,23 @@ async function runToken(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
|
|
|
168
179
|
}
|
|
169
180
|
|
|
170
181
|
async function runLogin(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
|
|
171
|
-
const
|
|
182
|
+
const providers = getOAuthProviders();
|
|
183
|
+
let providerArg = flags.provider;
|
|
172
184
|
if (!providerArg) {
|
|
173
|
-
|
|
185
|
+
if (flags.via) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
"Usage: omp auth-broker login <provider> --via=user@host (provider required for remote login)",
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
providerArg = await pickProviderInteractively(providers);
|
|
174
191
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
192
|
+
if (!providers.some(p => p.id === providerArg)) {
|
|
193
|
+
throw new Error(
|
|
194
|
+
`Unknown OAuth provider '${providerArg}'. Known: ${providers
|
|
195
|
+
.map(p => p.id)
|
|
196
|
+
.sort()
|
|
197
|
+
.join(", ")}`,
|
|
198
|
+
);
|
|
178
199
|
}
|
|
179
200
|
if (flags.via) {
|
|
180
201
|
await runRemoteLogin(providerArg, flags.via, flags.dryRun ?? false);
|
|
@@ -184,18 +205,107 @@ async function runLogin(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
|
|
|
184
205
|
}
|
|
185
206
|
|
|
186
207
|
async function runLocalLogin(provider: OAuthProvider): Promise<void> {
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
208
|
+
// Drive the per-provider OAuth dance in-process. Persists into the same
|
|
209
|
+
// SQLite store the broker uses.
|
|
210
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
211
|
+
const ask = (msg: string) => promptLine(rl, `${msg} `);
|
|
212
|
+
const store = await SqliteAuthCredentialStore.open(getAgentDbPath());
|
|
213
|
+
const storage = new AuthStorage(store);
|
|
214
|
+
await storage.reload();
|
|
215
|
+
try {
|
|
216
|
+
await storage.login(provider, {
|
|
217
|
+
onAuth({ url, instructions }) {
|
|
218
|
+
process.stdout.write(`\nOpen this URL in your browser:\n${url}\n`);
|
|
219
|
+
if (instructions) process.stdout.write(`${instructions}\n`);
|
|
220
|
+
process.stdout.write("\n");
|
|
221
|
+
},
|
|
222
|
+
onProgress(message) {
|
|
223
|
+
process.stdout.write(`${message}\n`);
|
|
224
|
+
},
|
|
225
|
+
onPrompt(p) {
|
|
226
|
+
return ask(`${p.message}${p.placeholder ? ` (${p.placeholder})` : ""}:`);
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
process.stdout.write(`\nCredentials saved to ${getAgentDbPath()}\n`);
|
|
230
|
+
} finally {
|
|
231
|
+
store.close();
|
|
232
|
+
rl.close();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Interactive `readline` prompt that cleanly tears down on Ctrl-C / Escape so
|
|
238
|
+
* cancelling a half-finished login flow doesn't leave the terminal in raw mode.
|
|
239
|
+
*/
|
|
240
|
+
function promptLine(rl: readline.Interface, question: string): Promise<string> {
|
|
241
|
+
const { promise, resolve, reject } = Promise.withResolvers<string>();
|
|
242
|
+
const input = process.stdin as NodeJS.ReadStream;
|
|
243
|
+
const supportsRawMode = input.isTTY && typeof input.setRawMode === "function";
|
|
244
|
+
const wasRaw = supportsRawMode ? input.isRaw : false;
|
|
245
|
+
let settled = false;
|
|
246
|
+
|
|
247
|
+
const cleanup = () => {
|
|
248
|
+
rl.off("SIGINT", onSigint);
|
|
249
|
+
if (supportsRawMode) {
|
|
250
|
+
input.off("keypress", onKeypress);
|
|
251
|
+
input.setRawMode?.(wasRaw);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const finish = (result: () => void) => {
|
|
256
|
+
if (settled) return;
|
|
257
|
+
settled = true;
|
|
258
|
+
cleanup();
|
|
259
|
+
result();
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const cancel = () => {
|
|
263
|
+
finish(() => reject(new Error("Login cancelled")));
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const onSigint = () => {
|
|
267
|
+
cancel();
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const onKeypress = (_str: string, key: readline.Key) => {
|
|
271
|
+
if (key.name === "escape" || (key.ctrl && key.name === "c")) {
|
|
272
|
+
cancel();
|
|
273
|
+
rl.close();
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
if (supportsRawMode) {
|
|
278
|
+
readline.emitKeypressEvents(input, rl);
|
|
279
|
+
input.setRawMode(true);
|
|
280
|
+
input.on("keypress", onKeypress);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
rl.once("SIGINT", onSigint);
|
|
284
|
+
rl.question(question, answer => {
|
|
285
|
+
finish(() => resolve(answer));
|
|
195
286
|
});
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
287
|
+
return promise;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async function pickProviderInteractively(providers: readonly OAuthProviderInfo[]): Promise<string> {
|
|
291
|
+
if (providers.length === 0) {
|
|
292
|
+
throw new Error("No OAuth providers registered");
|
|
293
|
+
}
|
|
294
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
295
|
+
try {
|
|
296
|
+
process.stdout.write("Select a provider:\n\n");
|
|
297
|
+
for (let i = 0; i < providers.length; i++) {
|
|
298
|
+
process.stdout.write(` ${i + 1}. ${providers[i].name}\n`);
|
|
299
|
+
}
|
|
300
|
+
process.stdout.write("\n");
|
|
301
|
+
const choice = await promptLine(rl, `Enter number (1-${providers.length}): `);
|
|
302
|
+
const index = Number.parseInt(choice, 10) - 1;
|
|
303
|
+
if (Number.isNaN(index) || index < 0 || index >= providers.length) {
|
|
304
|
+
throw new Error(`Invalid selection: ${choice}`);
|
|
305
|
+
}
|
|
306
|
+
return providers[index].id;
|
|
307
|
+
} finally {
|
|
308
|
+
rl.close();
|
|
199
309
|
}
|
|
200
310
|
}
|
|
201
311
|
|
|
@@ -235,12 +345,17 @@ async function runRemoteLogin(provider: string, via: string, dryRun: boolean): P
|
|
|
235
345
|
}
|
|
236
346
|
|
|
237
347
|
async function runLogout(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
|
|
238
|
-
|
|
239
|
-
if (!providerArg) {
|
|
240
|
-
throw new Error("Usage: omp auth-broker logout <provider>");
|
|
241
|
-
}
|
|
348
|
+
let providerArg = flags.provider;
|
|
242
349
|
const store = await SqliteAuthCredentialStore.open(getAgentDbPath());
|
|
243
350
|
try {
|
|
351
|
+
if (!providerArg) {
|
|
352
|
+
const stored = store.listProviders();
|
|
353
|
+
if (stored.length === 0) {
|
|
354
|
+
process.stdout.write("No credentials stored.\n");
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
providerArg = await pickStoredProviderInteractively(stored);
|
|
358
|
+
}
|
|
244
359
|
store.deleteAuthCredentialsForProvider(providerArg, "logged out by user");
|
|
245
360
|
process.stdout.write(`Logged out of ${providerArg}\n`);
|
|
246
361
|
} finally {
|
|
@@ -248,6 +363,37 @@ async function runLogout(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
|
|
|
248
363
|
}
|
|
249
364
|
}
|
|
250
365
|
|
|
366
|
+
async function pickStoredProviderInteractively(providers: string[]): Promise<string> {
|
|
367
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
368
|
+
try {
|
|
369
|
+
process.stdout.write("Select a provider to logout:\n\n");
|
|
370
|
+
for (let i = 0; i < providers.length; i++) {
|
|
371
|
+
process.stdout.write(` ${i + 1}. ${providers[i]}\n`);
|
|
372
|
+
}
|
|
373
|
+
process.stdout.write("\n");
|
|
374
|
+
const choice = await promptLine(rl, `Enter number (1-${providers.length}): `);
|
|
375
|
+
const index = Number.parseInt(choice, 10) - 1;
|
|
376
|
+
if (Number.isNaN(index) || index < 0 || index >= providers.length) {
|
|
377
|
+
throw new Error(`Invalid selection: ${choice}`);
|
|
378
|
+
}
|
|
379
|
+
return providers[index];
|
|
380
|
+
} finally {
|
|
381
|
+
rl.close();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async function runList(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
|
|
386
|
+
const providers = getOAuthProviders();
|
|
387
|
+
if (flags.json) {
|
|
388
|
+
process.stdout.write(`${JSON.stringify(providers.map(p => ({ id: p.id, name: p.name })))}\n`);
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
process.stdout.write("Available providers:\n\n");
|
|
392
|
+
for (const p of providers) {
|
|
393
|
+
process.stdout.write(` ${p.id.padEnd(20)} ${p.name}\n`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
251
397
|
// ─── CLIProxyAPI import ─────────────────────────────────────────────────
|
|
252
398
|
|
|
253
399
|
/**
|
|
@@ -732,6 +878,9 @@ export async function runAuthBrokerCommand(cmd: AuthBrokerCommandArgs): Promise<
|
|
|
732
878
|
case "status":
|
|
733
879
|
await runStatus(cmd.flags);
|
|
734
880
|
return;
|
|
881
|
+
case "list":
|
|
882
|
+
await runList(cmd.flags);
|
|
883
|
+
return;
|
|
735
884
|
default: {
|
|
736
885
|
// Exhaustive check.
|
|
737
886
|
const _exhaustive: never = cmd.action;
|
|
@@ -56,8 +56,11 @@ export default class AuthBroker extends Command {
|
|
|
56
56
|
"# Boot on a non-default port\n omp auth-broker serve --bind=127.0.0.1:9000",
|
|
57
57
|
"# Print the bearer token\n omp auth-broker token",
|
|
58
58
|
"# Rotate the bearer token\n omp auth-broker token --regenerate",
|
|
59
|
+
"# List supported OAuth providers\n omp auth-broker list",
|
|
59
60
|
"# Local login (run on the broker host)\n omp auth-broker login anthropic",
|
|
61
|
+
"# Interactive provider selection\n omp auth-broker login",
|
|
60
62
|
"# Remote login over SSH tunnel\n omp auth-broker login anthropic --via=user@broker",
|
|
63
|
+
"# Log out of a provider (interactive without provider arg)\n omp auth-broker logout anthropic",
|
|
61
64
|
"# Import a CLIProxyAPI auth dump\n omp auth-broker import ~/.cliproxy/auth",
|
|
62
65
|
"# Import a single CLIProxyAPI JSON, overriding the provider mapping\n omp auth-broker import ~/.cliproxy/auth/claude-foo.json --provider anthropic",
|
|
63
66
|
"# Preview a migration from local store + env vars to the configured broker\n omp auth-broker migrate --from-local --include-env --dry-run",
|
package/src/commands/launch.ts
CHANGED
|
@@ -120,6 +120,22 @@ export default class Index extends Command {
|
|
|
120
120
|
"no-title": Flags.boolean({
|
|
121
121
|
description: "Disable title auto-generation",
|
|
122
122
|
}),
|
|
123
|
+
// `--auto-approve` / `--yolo`: declared here so oclif's auto-generated `--help` lists it.
|
|
124
|
+
// Runtime parsing happens in `cli/args.ts parseArgs` (line 176 in that file) — `runRootCommand`
|
|
125
|
+
// consumes the manual-parser output, not these oclif flag values. If you rename or remove
|
|
126
|
+
// either form, update both call sites in lockstep.
|
|
127
|
+
"auto-approve": Flags.boolean({
|
|
128
|
+
aliases: ["yolo"],
|
|
129
|
+
description: "Auto-approve all tool calls (skip approval prompts)",
|
|
130
|
+
}),
|
|
131
|
+
// `--approval-mode`: declared here so oclif's auto-generated `--help` lists it; runtime parsing
|
|
132
|
+
// happens in `cli/args.ts parseArgs`. The value is applied via `Settings.override("tools.approvalMode", …)`
|
|
133
|
+
// in `main.ts` after the `Settings` instance is constructed, so every `settings.get("tools.approvalMode")`
|
|
134
|
+
// site (wrapper, `/settings` UI) observes the same value.
|
|
135
|
+
"approval-mode": Flags.string({
|
|
136
|
+
options: ["always-ask", "write", "yolo"],
|
|
137
|
+
description: "Override tools.approvalMode for this session (always-ask|write|yolo)",
|
|
138
|
+
}),
|
|
123
139
|
};
|
|
124
140
|
|
|
125
141
|
static examples = [
|
|
@@ -98,8 +98,8 @@
|
|
|
98
98
|
},
|
|
99
99
|
"timeout": {
|
|
100
100
|
"type": "number",
|
|
101
|
-
"
|
|
102
|
-
"description": "
|
|
101
|
+
"minimum": 0,
|
|
102
|
+
"description": "MCP request timeout in milliseconds. Set to 0 to disable client-side MCP timeouts."
|
|
103
103
|
},
|
|
104
104
|
"auth": {
|
|
105
105
|
"$ref": "#/$defs/authConfig"
|