march-cli 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/march.mjs +13 -13
- package/package.json +49 -49
- package/src/agent/command-exec-tool.mjs +172 -172
- package/src/agent/context-stats-tool.mjs +57 -57
- package/src/agent/editing/diff-apply.mjs +28 -28
- package/src/agent/editing/diff-format.mjs +57 -57
- package/src/agent/editing/lsp-report.mjs +69 -69
- package/src/agent/file-edit-tool.mjs +250 -250
- package/src/agent/file-tools/read-file-tool.mjs +112 -112
- package/src/agent/file-tools/read-image-tool.mjs +76 -76
- package/src/agent/model-payload-dumper.mjs +208 -208
- package/src/agent/pi-session/pi-session-sidecar-failure.mjs +10 -10
- package/src/agent/provider/payload-messages.mjs +138 -138
- package/src/agent/runner/codex-large-context-guard.mjs +87 -87
- package/src/agent/runner/codex-transport-compression.mjs +180 -180
- package/src/agent/runner/codex-transport-debug.mjs +113 -113
- package/src/agent/runner/codex-websocket-event-debug.mjs +130 -130
- package/src/agent/runner/fast-model.mjs +36 -36
- package/src/agent/runner/runner-cleanup.mjs +12 -12
- package/src/agent/runner/runner-init.mjs +15 -15
- package/src/agent/runner/runner-session-state.mjs +40 -40
- package/src/agent/runner/runner-utils.mjs +24 -24
- package/src/agent/runner.mjs +299 -299
- package/src/agent/runtime/ipc/ipc-peer.mjs +99 -99
- package/src/agent/runtime/ipc/process-ipc-transport.mjs +16 -16
- package/src/agent/runtime/remote-runner-client.mjs +73 -73
- package/src/agent/runtime/remote-ui-client.mjs +20 -20
- package/src/agent/runtime/runner-ipc-target.mjs +125 -125
- package/src/agent/runtime/runner-process-client.mjs +47 -47
- package/src/agent/runtime/runner-process-entry.mjs +11 -11
- package/src/agent/runtime/runner-process-factory.mjs +111 -108
- package/src/agent/runtime/runner-runtime-host.mjs +79 -79
- package/src/agent/runtime/runtime-factory.mjs +42 -42
- package/src/agent/runtime/runtime-host.mjs +34 -34
- package/src/agent/runtime/ui-event-bridge.mjs +95 -95
- package/src/agent/screen-tools/list-windows-tool.mjs +39 -39
- package/src/agent/screen-tools/screen-tool.mjs +49 -49
- package/src/agent/screen-tools/windows-screen.mjs +133 -133
- package/src/agent/session/session-auto-name.mjs +41 -41
- package/src/agent/session/session-binding.mjs +12 -12
- package/src/agent/session/session-options.mjs +47 -47
- package/src/agent/tool-names.mjs +1 -1
- package/src/agent/tool-result.mjs +3 -3
- package/src/agent/tool-summary.mjs +112 -112
- package/src/agent/tools.mjs +58 -58
- package/src/agent/turn/turn-events.mjs +111 -111
- package/src/agent/turn/turn-logging.mjs +30 -30
- package/src/agent/turn/turn-runner.mjs +196 -196
- package/src/agent/vision-capability.mjs +14 -14
- package/src/auth/login-command.mjs +90 -90
- package/src/auth/storage.mjs +34 -34
- package/src/cli/args.mjs +96 -79
- package/src/cli/commands/copy-command.mjs +87 -87
- package/src/cli/commands/export-command.mjs +206 -206
- package/src/cli/commands/extensions-command.mjs +53 -53
- package/src/cli/commands/help-command.mjs +7 -7
- package/src/cli/commands/model-command.mjs +141 -141
- package/src/cli/commands/paste-image-command.mjs +43 -43
- package/src/cli/commands/provider-command.mjs +59 -59
- package/src/cli/commands/status-command.mjs +196 -194
- package/src/cli/commands/thinking-command.mjs +87 -87
- package/src/cli/fallback-ui.mjs +156 -156
- package/src/cli/input/attachment-tokens.mjs +20 -20
- package/src/cli/input/autocomplete.mjs +74 -74
- package/src/cli/input/external-editor.mjs +39 -39
- package/src/cli/input/file-search/index.mjs +160 -160
- package/src/cli/input/history-store.mjs +35 -35
- package/src/cli/input/image-clipboard.mjs +55 -55
- package/src/cli/input/keybinding-dispatch.mjs +76 -76
- package/src/cli/input/keybindings.mjs +96 -96
- package/src/cli/input/mode-state.mjs +43 -43
- package/src/cli/input/prompt-templates.mjs +84 -84
- package/src/cli/input/select-with-keyboard.mjs +86 -86
- package/src/cli/permissions.mjs +103 -103
- package/src/cli/repl-commands.mjs +86 -86
- package/src/cli/repl-loop.mjs +183 -183
- package/src/cli/selector-list.mjs +21 -21
- package/src/cli/session/pi-session-switch-command.mjs +41 -41
- package/src/cli/session/session-command.mjs +23 -23
- package/src/cli/session/session-list-command.mjs +68 -68
- package/src/cli/session/session-name-command.mjs +26 -26
- package/src/cli/session/session-source-command.mjs +89 -89
- package/src/cli/session/session-switch-command.mjs +1 -1
- package/src/cli/shell/shell-command.mjs +55 -55
- package/src/cli/shell/shell-drawer-controls.mjs +33 -33
- package/src/cli/shell/shell-drawer.mjs +192 -192
- package/src/cli/shell/shell-split-layout.mjs +70 -70
- package/src/cli/slash-commands.mjs +192 -192
- package/src/cli/startup/create-runtime-runner.mjs +61 -61
- package/src/cli/startup/runtime-close.mjs +23 -23
- package/src/cli/startup/startup-banner.mjs +71 -71
- package/src/cli/startup/startup-session.mjs +51 -51
- package/src/cli/status-line-updater.mjs +75 -75
- package/src/cli/tool-output.mjs +9 -9
- package/src/cli/tui/editor/external-editor-runner.mjs +24 -24
- package/src/cli/tui/input/mouse-selection-controller.mjs +91 -91
- package/src/cli/tui/input/mouse-tracking.mjs +20 -20
- package/src/cli/tui/layout/main-pane-layout.mjs +47 -47
- package/src/cli/tui/layout/safe-render-boundary.mjs +46 -46
- package/src/cli/tui/markdown-renderer.mjs +285 -285
- package/src/cli/tui/output/scroll-state.mjs +79 -79
- package/src/cli/tui/output/text-line-renderer.mjs +50 -50
- package/src/cli/tui/output/tool-card-renderer.mjs +59 -59
- package/src/cli/tui/output/visible-lines.mjs +8 -8
- package/src/cli/tui/output-buffer.mjs +293 -293
- package/src/cli/tui/permission-request-ui.mjs +18 -18
- package/src/cli/tui/recall-rendering.mjs +28 -25
- package/src/cli/tui/render/render-scheduler.mjs +26 -26
- package/src/cli/tui/render/stream-delta-buffer.mjs +46 -46
- package/src/cli/tui/select/editor-select-list.mjs +111 -111
- package/src/cli/tui/selection-screen.mjs +269 -269
- package/src/cli/tui/status/retry-status.mjs +72 -72
- package/src/cli/tui/status/spinner-status.mjs +42 -42
- package/src/cli/tui/status/status-bar.mjs +225 -225
- package/src/cli/tui/syntax/highlighting.mjs +260 -260
- package/src/cli/tui/syntax/languages.mjs +91 -91
- package/src/cli/tui/syntax/tree-sitter/bash.highlights.scm +261 -261
- package/src/cli/tui/syntax/tree-sitter/c.highlights.scm +341 -341
- package/src/cli/tui/syntax/tree-sitter/cpp.highlights.scm +268 -268
- package/src/cli/tui/syntax/tree-sitter/csharp.highlights.scm +577 -577
- package/src/cli/tui/syntax/tree-sitter/css.highlights.scm +109 -109
- package/src/cli/tui/syntax/tree-sitter/diff.highlights.scm +49 -49
- package/src/cli/tui/syntax/tree-sitter/go.highlights.scm +254 -254
- package/src/cli/tui/syntax/tree-sitter/html.highlights.scm +13 -13
- package/src/cli/tui/syntax/tree-sitter/java.highlights.scm +330 -330
- package/src/cli/tui/syntax/tree-sitter/json.highlights.scm +38 -38
- package/src/cli/tui/syntax/tree-sitter/php.highlights.scm +203 -203
- package/src/cli/tui/syntax/tree-sitter/python.highlights.scm +137 -137
- package/src/cli/tui/syntax/tree-sitter/ruby.highlights.scm +309 -309
- package/src/cli/tui/syntax/tree-sitter/rust.highlights.scm +531 -531
- package/src/cli/tui/syntax/tree-sitter/toml.highlights.scm +39 -39
- package/src/cli/tui/syntax/tree-sitter/tsx.highlights.scm +35 -35
- package/src/cli/tui/syntax/tree-sitter/typescript.highlights.scm +35 -35
- package/src/cli/tui/syntax/tree-sitter/yaml.highlights.scm +99 -99
- package/src/cli/tui/tool-rendering.mjs +87 -87
- package/src/cli/tui/tui-diff-rendering.mjs +157 -157
- package/src/cli/tui/tui-handlers.mjs +111 -111
- package/src/cli/tui/tui-input-controller.mjs +61 -61
- package/src/cli/tui/ui-theme.mjs +157 -157
- package/src/cli/ui.mjs +297 -297
- package/src/config/config-json.mjs +108 -84
- package/src/config/dotenv.mjs +20 -20
- package/src/config/features.mjs +75 -75
- package/src/config/loader.mjs +156 -143
- package/src/config/settings-command.mjs +97 -97
- package/src/context/engine.mjs +199 -198
- package/src/context/injections.mjs +26 -26
- package/src/context/profiles.mjs +39 -39
- package/src/context/project-context.mjs +20 -20
- package/src/context/session-status.mjs +25 -17
- package/src/context/shell-layers.mjs +23 -23
- package/src/context/system-core/base.md +51 -50
- package/src/context/system-core/prompts/deepseek-v4-pro.md +3 -3
- package/src/context/system-core/prompts/default.md +3 -3
- package/src/context/system-core.mjs +35 -35
- package/src/debug/logger.mjs +141 -141
- package/src/debug/model-context-dumper.mjs +52 -52
- package/src/extensions/discovery.mjs +40 -40
- package/src/extensions/lifecycle-adapter.mjs +210 -210
- package/src/extensions/lifecycle-manifest.mjs +69 -69
- package/src/image-gen/index.mjs +7 -7
- package/src/image-gen/provider.mjs +231 -231
- package/src/image-gen/tool.mjs +84 -84
- package/src/lsp/client.mjs +257 -257
- package/src/lsp/diagnostic-store.mjs +42 -42
- package/src/lsp/diagnostics-format.mjs +72 -72
- package/src/lsp/managed-node-server.mjs +99 -99
- package/src/lsp/path-match.mjs +10 -10
- package/src/lsp/server-definitions.mjs +188 -188
- package/src/lsp/servers.mjs +165 -165
- package/src/lsp/service.mjs +110 -110
- package/src/lsp/status-message.mjs +9 -9
- package/src/lsp/typescript-project-resolver.mjs +186 -186
- package/src/main.mjs +294 -299
- package/src/mcp/client.mjs +195 -195
- package/src/mcp/config.mjs +130 -130
- package/src/mcp/index.mjs +48 -48
- package/src/mcp/tools.mjs +98 -98
- package/src/memory/command.mjs +120 -0
- package/src/memory/markdown/markdown-delete.mjs +23 -23
- package/src/memory/markdown/markdown-format.mjs +128 -128
- package/src/memory/markdown/markdown-recall.mjs +28 -28
- package/src/memory/markdown/ripgrep.mjs +16 -16
- package/src/memory/markdown/sqlite-index.mjs +87 -87
- package/src/memory/markdown-store.mjs +272 -286
- package/src/memory/markdown-tools.mjs +174 -103
- package/src/memory/remote/client.mjs +68 -0
- package/src/memory/remote/config.mjs +52 -0
- package/src/memory/remote/server.mjs +99 -0
- package/src/memory/search.mjs +183 -0
- package/src/network/environment.mjs +131 -131
- package/src/notification/desktop-notifier.mjs +262 -262
- package/src/platform/open-file.mjs +28 -28
- package/src/platform/spawn-command.mjs +27 -27
- package/src/provider/accept-command.mjs +89 -89
- package/src/provider/command.mjs +21 -21
- package/src/provider/config-command.mjs +129 -129
- package/src/provider/custom-provider.mjs +113 -113
- package/src/provider/hosted-tools.mjs +111 -111
- package/src/provider/presets.mjs +72 -72
- package/src/provider/share-command.mjs +79 -79
- package/src/provider/share-payload.mjs +52 -52
- package/src/session/attachment-display.mjs +16 -16
- package/src/session/attachment-references.mjs +65 -65
- package/src/session/attachments.mjs +140 -140
- package/src/session/persist.mjs +1 -1
- package/src/session/pi-manager.mjs +34 -34
- package/src/session/session-utils.mjs +16 -16
- package/src/session/sidecar-sync.mjs +19 -19
- package/src/session/sidecar.mjs +69 -69
- package/src/session/transcript.mjs +83 -83
- package/src/session/tree.mjs +42 -42
- package/src/shell/cli-runtime.mjs +11 -11
- package/src/shell/hints.mjs +12 -12
- package/src/shell/node-pty-adapter.mjs +81 -81
- package/src/shell/runtime-state.mjs +126 -126
- package/src/shell/runtime.mjs +252 -252
- package/src/shell/screen-buffer.mjs +136 -136
- package/src/shell/tool-read.mjs +74 -74
- package/src/shell/tools.mjs +299 -299
- package/src/supergrok/actions/image-generate.mjs +60 -60
- package/src/supergrok/actions/search.mjs +78 -78
- package/src/supergrok/auth.mjs +36 -36
- package/src/supergrok/constants.mjs +18 -18
- package/src/supergrok/oauth-provider.mjs +278 -278
- package/src/supergrok/provider.mjs +35 -35
- package/src/supergrok/response.mjs +76 -76
- package/src/supergrok/tool.mjs +61 -61
- package/src/text/ansi.mjs +3 -3
- package/src/web/config-command.mjs +43 -43
- package/src/web/fetch.mjs +78 -78
- package/src/web/presets.mjs +16 -16
- package/src/web/search.mjs +83 -83
- package/src/web/tools.mjs +107 -107
package/src/cli/permissions.mjs
CHANGED
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
// ── Permission categories ──────────────────────────────────────────────
|
|
2
|
-
export const PERM = Object.freeze({
|
|
3
|
-
READ_ONLY: "read_only",
|
|
4
|
-
FILE_WRITE: "file_write",
|
|
5
|
-
COMMAND_EXEC: "command_exec",
|
|
6
|
-
NETWORK_EXTERNAL: "network_external",
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
const CATEGORY_LABEL = {
|
|
10
|
-
[PERM.READ_ONLY]: "read-only",
|
|
11
|
-
[PERM.FILE_WRITE]: "file write",
|
|
12
|
-
[PERM.COMMAND_EXEC]: "command exec",
|
|
13
|
-
[PERM.NETWORK_EXTERNAL]: "network",
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export function permissionLabel(cat) {
|
|
17
|
-
return CATEGORY_LABEL[cat] ?? cat;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// ── Permitted modes ────────────────────────────────────────────────────
|
|
21
|
-
export const MODE = Object.freeze({
|
|
22
|
-
DEFAULT: "default",
|
|
23
|
-
DONT_ASK: "dontAsk",
|
|
24
|
-
BYPASS: "bypassPermissions",
|
|
25
|
-
ACCEPT_EDITS: "acceptEdits",
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// ── Default tool → category mapping ────────────────────────────────────
|
|
29
|
-
const DEFAULT_CATEGORIES = {
|
|
30
|
-
context_stats: PERM.READ_ONLY,
|
|
31
|
-
find: PERM.READ_ONLY,
|
|
32
|
-
edit_file: PERM.FILE_WRITE,
|
|
33
|
-
command_exec: PERM.COMMAND_EXEC,
|
|
34
|
-
terminal_spawn: PERM.COMMAND_EXEC,
|
|
35
|
-
terminal_send: PERM.COMMAND_EXEC,
|
|
36
|
-
terminal_list: PERM.COMMAND_EXEC,
|
|
37
|
-
terminal_kill: PERM.COMMAND_EXEC,
|
|
38
|
-
terminal_resize: PERM.COMMAND_EXEC,
|
|
39
|
-
terminal_clear: PERM.COMMAND_EXEC,
|
|
40
|
-
terminal_search: PERM.COMMAND_EXEC,
|
|
41
|
-
terminal_read: PERM.COMMAND_EXEC,
|
|
42
|
-
terminal_snapshot: PERM.COMMAND_EXEC,
|
|
43
|
-
external_web_search: PERM.NETWORK_EXTERNAL,
|
|
44
|
-
web_fetch: PERM.NETWORK_EXTERNAL,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export function createPermissionController({
|
|
48
|
-
mode = MODE.DEFAULT,
|
|
49
|
-
toolCategories = {},
|
|
50
|
-
onRequestApproval = null,
|
|
51
|
-
} = {}) {
|
|
52
|
-
const sessionApprovals = new Map();
|
|
53
|
-
const categories = { ...DEFAULT_CATEGORIES, ...toolCategories };
|
|
54
|
-
|
|
55
|
-
function getCategory(toolName) {
|
|
56
|
-
if (categories[toolName] !== undefined) return categories[toolName];
|
|
57
|
-
// MCP and unknown tools: default to most restrictive
|
|
58
|
-
if (toolName.startsWith("mcp__")) return PERM.NETWORK_EXTERNAL;
|
|
59
|
-
return PERM.COMMAND_EXEC;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function setCategory(toolName, category) {
|
|
63
|
-
categories[toolName] = category;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function check(toolName) {
|
|
67
|
-
const category = getCategory(toolName);
|
|
68
|
-
|
|
69
|
-
if (category === PERM.READ_ONLY) return { behavior: "allow" };
|
|
70
|
-
if (mode === MODE.BYPASS) return { behavior: "allow" };
|
|
71
|
-
if (mode === MODE.DONT_ASK) {
|
|
72
|
-
return { behavior: "deny", message: `Tool '${toolName}' requires ${permissionLabel(category)} permission, but permission mode is 'dontAsk'.` };
|
|
73
|
-
}
|
|
74
|
-
if (sessionApprovals.has(toolName)) return { behavior: "allow" };
|
|
75
|
-
|
|
76
|
-
return { behavior: "ask", category, toolName };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function approve(toolName) {
|
|
80
|
-
sessionApprovals.set(toolName, true);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function isApproved(toolName) {
|
|
84
|
-
return sessionApprovals.has(toolName);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async function requestApproval(toolName, params, requestFn) {
|
|
88
|
-
const decision = check(toolName);
|
|
89
|
-
if (decision.behavior !== "ask") return decision;
|
|
90
|
-
if (!requestFn) return decision;
|
|
91
|
-
const ok = await requestFn({ toolName, params, category: decision.category });
|
|
92
|
-
if (ok) {
|
|
93
|
-
approve(toolName);
|
|
94
|
-
return { behavior: "allow" };
|
|
95
|
-
}
|
|
96
|
-
return {
|
|
97
|
-
behavior: "deny",
|
|
98
|
-
message: `User denied ${toolName} (requires ${permissionLabel(decision.category)} permission).`,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return { check, approve, isApproved, getCategory, setCategory, requestApproval, get mode() { return mode; } };
|
|
103
|
-
}
|
|
1
|
+
// ── Permission categories ──────────────────────────────────────────────
|
|
2
|
+
export const PERM = Object.freeze({
|
|
3
|
+
READ_ONLY: "read_only",
|
|
4
|
+
FILE_WRITE: "file_write",
|
|
5
|
+
COMMAND_EXEC: "command_exec",
|
|
6
|
+
NETWORK_EXTERNAL: "network_external",
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const CATEGORY_LABEL = {
|
|
10
|
+
[PERM.READ_ONLY]: "read-only",
|
|
11
|
+
[PERM.FILE_WRITE]: "file write",
|
|
12
|
+
[PERM.COMMAND_EXEC]: "command exec",
|
|
13
|
+
[PERM.NETWORK_EXTERNAL]: "network",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function permissionLabel(cat) {
|
|
17
|
+
return CATEGORY_LABEL[cat] ?? cat;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ── Permitted modes ────────────────────────────────────────────────────
|
|
21
|
+
export const MODE = Object.freeze({
|
|
22
|
+
DEFAULT: "default",
|
|
23
|
+
DONT_ASK: "dontAsk",
|
|
24
|
+
BYPASS: "bypassPermissions",
|
|
25
|
+
ACCEPT_EDITS: "acceptEdits",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// ── Default tool → category mapping ────────────────────────────────────
|
|
29
|
+
const DEFAULT_CATEGORIES = {
|
|
30
|
+
context_stats: PERM.READ_ONLY,
|
|
31
|
+
find: PERM.READ_ONLY,
|
|
32
|
+
edit_file: PERM.FILE_WRITE,
|
|
33
|
+
command_exec: PERM.COMMAND_EXEC,
|
|
34
|
+
terminal_spawn: PERM.COMMAND_EXEC,
|
|
35
|
+
terminal_send: PERM.COMMAND_EXEC,
|
|
36
|
+
terminal_list: PERM.COMMAND_EXEC,
|
|
37
|
+
terminal_kill: PERM.COMMAND_EXEC,
|
|
38
|
+
terminal_resize: PERM.COMMAND_EXEC,
|
|
39
|
+
terminal_clear: PERM.COMMAND_EXEC,
|
|
40
|
+
terminal_search: PERM.COMMAND_EXEC,
|
|
41
|
+
terminal_read: PERM.COMMAND_EXEC,
|
|
42
|
+
terminal_snapshot: PERM.COMMAND_EXEC,
|
|
43
|
+
external_web_search: PERM.NETWORK_EXTERNAL,
|
|
44
|
+
web_fetch: PERM.NETWORK_EXTERNAL,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export function createPermissionController({
|
|
48
|
+
mode = MODE.DEFAULT,
|
|
49
|
+
toolCategories = {},
|
|
50
|
+
onRequestApproval = null,
|
|
51
|
+
} = {}) {
|
|
52
|
+
const sessionApprovals = new Map();
|
|
53
|
+
const categories = { ...DEFAULT_CATEGORIES, ...toolCategories };
|
|
54
|
+
|
|
55
|
+
function getCategory(toolName) {
|
|
56
|
+
if (categories[toolName] !== undefined) return categories[toolName];
|
|
57
|
+
// MCP and unknown tools: default to most restrictive
|
|
58
|
+
if (toolName.startsWith("mcp__")) return PERM.NETWORK_EXTERNAL;
|
|
59
|
+
return PERM.COMMAND_EXEC;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function setCategory(toolName, category) {
|
|
63
|
+
categories[toolName] = category;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function check(toolName) {
|
|
67
|
+
const category = getCategory(toolName);
|
|
68
|
+
|
|
69
|
+
if (category === PERM.READ_ONLY) return { behavior: "allow" };
|
|
70
|
+
if (mode === MODE.BYPASS) return { behavior: "allow" };
|
|
71
|
+
if (mode === MODE.DONT_ASK) {
|
|
72
|
+
return { behavior: "deny", message: `Tool '${toolName}' requires ${permissionLabel(category)} permission, but permission mode is 'dontAsk'.` };
|
|
73
|
+
}
|
|
74
|
+
if (sessionApprovals.has(toolName)) return { behavior: "allow" };
|
|
75
|
+
|
|
76
|
+
return { behavior: "ask", category, toolName };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function approve(toolName) {
|
|
80
|
+
sessionApprovals.set(toolName, true);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isApproved(toolName) {
|
|
84
|
+
return sessionApprovals.has(toolName);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function requestApproval(toolName, params, requestFn) {
|
|
88
|
+
const decision = check(toolName);
|
|
89
|
+
if (decision.behavior !== "ask") return decision;
|
|
90
|
+
if (!requestFn) return decision;
|
|
91
|
+
const ok = await requestFn({ toolName, params, category: decision.category });
|
|
92
|
+
if (ok) {
|
|
93
|
+
approve(toolName);
|
|
94
|
+
return { behavior: "allow" };
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
behavior: "deny",
|
|
98
|
+
message: `User denied ${toolName} (requires ${permissionLabel(decision.category)} permission).`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return { check, approve, isApproved, getCategory, setCategory, requestApproval, get mode() { return mode; } };
|
|
103
|
+
}
|
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { DEFAULT_KEYBINDINGS, KEYBINDING_ACTIONS } from "./input/keybindings.mjs";
|
|
3
|
-
import { dim, red } from "./tui/ui-theme.mjs";
|
|
4
|
-
|
|
5
|
-
const HOTKEY_GROUPS = Object.freeze([
|
|
6
|
-
["Turn control", ["abort", "interrupt"]],
|
|
7
|
-
["Model and thinking", ["cycleThinking", "thinkingSelector", "modelSelector"]],
|
|
8
|
-
["Editor and output", ["externalEditor", "toggleToolOutput", "pasteImage"]],
|
|
9
|
-
["Shell pane", ["toggleShellDrawer", "nextShell", "shellScrollUp", "shellScrollDown"]],
|
|
10
|
-
["Output scroll", ["outputScrollUp", "outputScrollDown"]],
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
export function parseInlineShellInput(input, lastCommand = "") {
|
|
14
|
-
if (input === "!!") {
|
|
15
|
-
if (!lastCommand) return { type: "error", message: "No previous inline shell command." };
|
|
16
|
-
return { type: "command", command: lastCommand, repeated: true };
|
|
17
|
-
}
|
|
18
|
-
if (!input.startsWith("!")) return { type: "none" };
|
|
19
|
-
const command = input.slice(1).trim();
|
|
20
|
-
if (!command) return { type: "error", message: "Usage: ! <command>" };
|
|
21
|
-
return { type: "command", command, repeated: false };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function runInlineShellCommand(command, { cwd = process.cwd(), ui } = {}) {
|
|
25
|
-
const shell = process.platform === "win32"
|
|
26
|
-
? { bin: "powershell.exe", args: ["-NoProfile", "-Command", command] }
|
|
27
|
-
: { bin: "bash", args: ["-lc", command] };
|
|
28
|
-
ui?.writeln(dim(`$ ${command}`));
|
|
29
|
-
const result = spawnSync(shell.bin, shell.args, {
|
|
30
|
-
cwd,
|
|
31
|
-
encoding: "utf8",
|
|
32
|
-
windowsHide: true,
|
|
33
|
-
maxBuffer: 1024 * 1024,
|
|
34
|
-
});
|
|
35
|
-
if (result.stdout) {
|
|
36
|
-
for (const line of result.stdout.replace(/\s+$/, "").split("\n")) {
|
|
37
|
-
if (line) ui?.writeln(line);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (result.stderr) {
|
|
41
|
-
for (const line of result.stderr.replace(/\s+$/, "").split("\n")) {
|
|
42
|
-
if (line) ui?.writeln(red(line));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (result.error) {
|
|
46
|
-
ui?.writeln(red(`Error: ${result.error.message}`));
|
|
47
|
-
} else if (result.status !== 0) {
|
|
48
|
-
ui?.writeln(red(`exit ${result.status}`));
|
|
49
|
-
}
|
|
50
|
-
return result;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function formatHotkeysPanel(keybindings = DEFAULT_KEYBINDINGS, diagnostics = []) {
|
|
54
|
-
return [
|
|
55
|
-
"Keyboard shortcuts:",
|
|
56
|
-
...formatGroupedKeybindingLines(keybindings),
|
|
57
|
-
...formatKeybindingDiagnostics(diagnostics),
|
|
58
|
-
"Input prefixes:",
|
|
59
|
-
" / Slash command autocomplete",
|
|
60
|
-
" /session Restore a previous session",
|
|
61
|
-
" /thinking Choose or list/set thinking level",
|
|
62
|
-
" @ File path autocomplete",
|
|
63
|
-
" ! cmd Run local shell command without sending to the model",
|
|
64
|
-
" !! Repeat previous local shell command",
|
|
65
|
-
];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function formatGroupedKeybindingLines(keybindings = DEFAULT_KEYBINDINGS) {
|
|
69
|
-
return HOTKEY_GROUPS.flatMap(([label, actions]) => [
|
|
70
|
-
` ${label}:`,
|
|
71
|
-
...actions.map((action) => formatKeybindingLine(action, keybindings)),
|
|
72
|
-
]);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function formatKeybindingLine(action, keybindings) {
|
|
76
|
-
const key = keybindings[action] ?? DEFAULT_KEYBINDINGS[action];
|
|
77
|
-
return ` ${key.padEnd(10, " ")} ${KEYBINDING_ACTIONS[action]}`;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function formatKeybindingDiagnostics(diagnostics) {
|
|
81
|
-
if (!diagnostics || diagnostics.length === 0) return [];
|
|
82
|
-
return [
|
|
83
|
-
"Keybinding diagnostics:",
|
|
84
|
-
...diagnostics.map((diagnostic) => ` - ${diagnostic.type ?? "warning"}: ${diagnostic.message}`),
|
|
85
|
-
];
|
|
86
|
-
}
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { DEFAULT_KEYBINDINGS, KEYBINDING_ACTIONS } from "./input/keybindings.mjs";
|
|
3
|
+
import { dim, red } from "./tui/ui-theme.mjs";
|
|
4
|
+
|
|
5
|
+
const HOTKEY_GROUPS = Object.freeze([
|
|
6
|
+
["Turn control", ["abort", "interrupt"]],
|
|
7
|
+
["Model and thinking", ["cycleThinking", "thinkingSelector", "modelSelector"]],
|
|
8
|
+
["Editor and output", ["externalEditor", "toggleToolOutput", "pasteImage"]],
|
|
9
|
+
["Shell pane", ["toggleShellDrawer", "nextShell", "shellScrollUp", "shellScrollDown"]],
|
|
10
|
+
["Output scroll", ["outputScrollUp", "outputScrollDown"]],
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
export function parseInlineShellInput(input, lastCommand = "") {
|
|
14
|
+
if (input === "!!") {
|
|
15
|
+
if (!lastCommand) return { type: "error", message: "No previous inline shell command." };
|
|
16
|
+
return { type: "command", command: lastCommand, repeated: true };
|
|
17
|
+
}
|
|
18
|
+
if (!input.startsWith("!")) return { type: "none" };
|
|
19
|
+
const command = input.slice(1).trim();
|
|
20
|
+
if (!command) return { type: "error", message: "Usage: ! <command>" };
|
|
21
|
+
return { type: "command", command, repeated: false };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function runInlineShellCommand(command, { cwd = process.cwd(), ui } = {}) {
|
|
25
|
+
const shell = process.platform === "win32"
|
|
26
|
+
? { bin: "powershell.exe", args: ["-NoProfile", "-Command", command] }
|
|
27
|
+
: { bin: "bash", args: ["-lc", command] };
|
|
28
|
+
ui?.writeln(dim(`$ ${command}`));
|
|
29
|
+
const result = spawnSync(shell.bin, shell.args, {
|
|
30
|
+
cwd,
|
|
31
|
+
encoding: "utf8",
|
|
32
|
+
windowsHide: true,
|
|
33
|
+
maxBuffer: 1024 * 1024,
|
|
34
|
+
});
|
|
35
|
+
if (result.stdout) {
|
|
36
|
+
for (const line of result.stdout.replace(/\s+$/, "").split("\n")) {
|
|
37
|
+
if (line) ui?.writeln(line);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (result.stderr) {
|
|
41
|
+
for (const line of result.stderr.replace(/\s+$/, "").split("\n")) {
|
|
42
|
+
if (line) ui?.writeln(red(line));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (result.error) {
|
|
46
|
+
ui?.writeln(red(`Error: ${result.error.message}`));
|
|
47
|
+
} else if (result.status !== 0) {
|
|
48
|
+
ui?.writeln(red(`exit ${result.status}`));
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function formatHotkeysPanel(keybindings = DEFAULT_KEYBINDINGS, diagnostics = []) {
|
|
54
|
+
return [
|
|
55
|
+
"Keyboard shortcuts:",
|
|
56
|
+
...formatGroupedKeybindingLines(keybindings),
|
|
57
|
+
...formatKeybindingDiagnostics(diagnostics),
|
|
58
|
+
"Input prefixes:",
|
|
59
|
+
" / Slash command autocomplete",
|
|
60
|
+
" /session Restore a previous session",
|
|
61
|
+
" /thinking Choose or list/set thinking level",
|
|
62
|
+
" @ File path autocomplete",
|
|
63
|
+
" ! cmd Run local shell command without sending to the model",
|
|
64
|
+
" !! Repeat previous local shell command",
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function formatGroupedKeybindingLines(keybindings = DEFAULT_KEYBINDINGS) {
|
|
69
|
+
return HOTKEY_GROUPS.flatMap(([label, actions]) => [
|
|
70
|
+
` ${label}:`,
|
|
71
|
+
...actions.map((action) => formatKeybindingLine(action, keybindings)),
|
|
72
|
+
]);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function formatKeybindingLine(action, keybindings) {
|
|
76
|
+
const key = keybindings[action] ?? DEFAULT_KEYBINDINGS[action];
|
|
77
|
+
return ` ${key.padEnd(10, " ")} ${KEYBINDING_ACTIONS[action]}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function formatKeybindingDiagnostics(diagnostics) {
|
|
81
|
+
if (!diagnostics || diagnostics.length === 0) return [];
|
|
82
|
+
return [
|
|
83
|
+
"Keybinding diagnostics:",
|
|
84
|
+
...diagnostics.map((diagnostic) => ` - ${diagnostic.type ?? "warning"}: ${diagnostic.message}`),
|
|
85
|
+
];
|
|
86
|
+
}
|