@nexrall/code-core 1.4.31 → 1.4.32

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.
@@ -1,5 +1,7 @@
1
1
  import type { Message, ToolResult, AgentLoopOptions, EnvContext } from '../types';
2
2
  import { type AgentMemoryScope } from './agentTypes';
3
+ import { bashNeedsRepoLock } from '../permissions/bashClassify';
4
+ export { bashNeedsRepoLock };
3
5
  /**
4
6
  * Fingerprint one round's tool failures, for the repeated-failure runaway guard.
5
7
  *
@@ -85,17 +87,6 @@ export declare function stopReasonNotice(reason: StopReason, ctx?: {
85
87
  repeatError?: string | null;
86
88
  }): string | null;
87
89
  export declare function resolveMaxIterations(optionValue: number | undefined, settingsRaw: Record<string, unknown>): number;
88
- /**
89
- * Whether a bash command should take the repo-state lock.
90
- *
91
- * Exported for tests: the failure mode (two concurrent `git commit`) is timing-dependent
92
- * and painful to reproduce through the real loop.
93
- *
94
- * Scans EVERY segment, not just the first word, because the mutating verb is routinely
95
- * not leading: `cd packages/core && npm publish`, `FOO=1 git push`, `ls && git commit`.
96
- * Checking only the first token would miss most real commands.
97
- */
98
- export declare function bashNeedsRepoLock(command: string): boolean;
99
90
  /**
100
91
  * Every path a tool call will touch, so all of them can be locked.
101
92
  *
@@ -1 +1 @@
1
- {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
@@ -33,12 +33,11 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.VERIFY_CMD_RE = exports.WRITE_TOOL_NAMES = exports.ToolNotAllowedError = exports.AGENT_MEMORY_TOOL_SCHEMA = exports.AGENT_MEMORY_TOOL = exports._stallLimits = void 0;
36
+ exports.VERIFY_CMD_RE = exports.WRITE_TOOL_NAMES = exports.ToolNotAllowedError = exports.AGENT_MEMORY_TOOL_SCHEMA = exports.AGENT_MEMORY_TOOL = exports._stallLimits = exports.bashNeedsRepoLock = void 0;
37
37
  exports.errorRoundSignature = errorRoundSignature;
38
38
  exports.executeAgentMemoryWrite = executeAgentMemoryWrite;
39
39
  exports.stopReasonNotice = stopReasonNotice;
40
40
  exports.resolveMaxIterations = resolveMaxIterations;
41
- exports.bashNeedsRepoLock = bashNeedsRepoLock;
42
41
  exports.lockPathsFor = lockPathsFor;
43
42
  exports.resolveMaxConcurrentSubtasks = resolveMaxConcurrentSubtasks;
44
43
  exports.createLimiter = createLimiter;
@@ -68,6 +67,11 @@ const executor_1 = require("../tools/executor");
68
67
  const agentTypes_1 = require("./agentTypes");
69
68
  const skills_1 = require("./skills");
70
69
  const rules_1 = require("../permissions/rules");
70
+ // bashNeedsRepoLock lives in permissions/bashClassify.ts, not here: the permission
71
+ // gate needs the same "does this command mutate shared state?" answer, and importing
72
+ // it from loop.ts would make permissions depend on the agent loop (a cycle).
73
+ const bashClassify_1 = require("../permissions/bashClassify");
74
+ Object.defineProperty(exports, "bashNeedsRepoLock", { enumerable: true, get: function () { return bashClassify_1.bashNeedsRepoLock; } });
71
75
  const planMode_1 = require("./planMode");
72
76
  const agentRegistry_1 = require("./agentRegistry");
73
77
  const sandbox_1 = require("../tools/sandbox");
@@ -422,62 +426,6 @@ const WRITE_TOOLS = new Set([
422
426
  * they serialise against each other while everything else stays parallel.
423
427
  */
424
428
  const REPO_STATE_LOCK = '\u0000repo-state';
425
- /**
426
- * Commands that must not run concurrently with another instance of themselves.
427
- *
428
- * `bash` was excluded from the write-tool lock entirely, which was the largest hole in
429
- * the concurrency story: it is the most mutating tool there is, and with 4 sub-agents
430
- * fanned out two of them could run `git commit` simultaneously (one dies on
431
- * `.git/index.lock`), or two `npm install` (corrupted node_modules / lockfile), or two
432
- * `npm test` writing the same coverage and snapshot files (wrong results, not an error).
433
- * The comment above withFileLock explains carefully why two edit_file calls must be
434
- * sequenced, then a `bash -c 'echo x > file'` did exactly that with nothing holding it.
435
- *
436
- * Deliberately a VERB ALLOWLIST rather than serialising all of bash: an explorer's
437
- * `grep`/`rg`/`ls`/`cat` are read-only and are precisely the calls that benefit most
438
- * from running in parallel. Serialising those would trade a real correctness bug for a
439
- * real performance regression. These verbs are the ones that take a global lock, write
440
- * a lockfile, or mutate a shared build/dependency directory.
441
- */
442
- const MUTATING_BASH_VERBS = new Set([
443
- 'git', 'npm', 'pnpm', 'yarn', 'bun', 'cargo', 'go', 'pip', 'pip3', 'poetry', 'uv',
444
- 'bundle', 'composer', 'gradle', 'mvn', 'make', 'terraform', 'helm', 'docker',
445
- 'vsce', 'tsc', 'pytest', 'dotnet', 'swift', 'gem',
446
- ]);
447
- /**
448
- * Whether a bash command should take the repo-state lock.
449
- *
450
- * Exported for tests: the failure mode (two concurrent `git commit`) is timing-dependent
451
- * and painful to reproduce through the real loop.
452
- *
453
- * Scans EVERY segment, not just the first word, because the mutating verb is routinely
454
- * not leading: `cd packages/core && npm publish`, `FOO=1 git push`, `ls && git commit`.
455
- * Checking only the first token would miss most real commands.
456
- */
457
- function bashNeedsRepoLock(command) {
458
- if (!command)
459
- return false;
460
- // Split on shell separators, then take the first bare word of each segment, skipping
461
- // env-var assignments (FOO=bar git push) and `sudo`/`time`-style prefixes.
462
- const segments = command.split(/\|\||&&|[;|&\n()]|\$\(/);
463
- for (const seg of segments) {
464
- for (const tokenRaw of seg.trim().split(/\s+/)) {
465
- const token = tokenRaw.replace(/^["']|["']$/g, '');
466
- if (!token)
467
- continue;
468
- if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(token))
469
- continue; // env assignment
470
- if (token === 'sudo' || token === 'time' || token === 'nice' || token === 'env')
471
- continue;
472
- // Use the basename so `/usr/bin/git` and `./node_modules/.bin/tsc` still match.
473
- const verb = token.split('/').pop() ?? token;
474
- if (MUTATING_BASH_VERBS.has(verb))
475
- return true;
476
- break; // only the command word of each segment matters
477
- }
478
- }
479
- return false;
480
- }
481
429
  /**
482
430
  * Every path a tool call will touch, so all of them can be locked.
483
431
  *
@@ -2650,7 +2598,7 @@ async function runAgentLoop(initialMessages, options) {
2650
2598
  // This matters far more with sub-agents than without: up to 4 run
2651
2599
  // concurrently, each issuing its own tool calls into this same process.
2652
2600
  const locks = name === 'bash'
2653
- ? (bashNeedsRepoLock(String(input.command ?? '')) ? [REPO_STATE_LOCK] : [])
2601
+ ? ((0, bashClassify_1.bashNeedsRepoLock)(String(input.command ?? '')) ? [REPO_STATE_LOCK] : [])
2654
2602
  : lockPathsFor(name, input, options.workDir);
2655
2603
  result = locks.length ? await withFileLocks(locks, run) : await run();
2656
2604
  }
package/dist/index.d.ts CHANGED
@@ -20,6 +20,8 @@ export * from './agent/agentTypes';
20
20
  export * from './agent/planMode';
21
21
  export * from './agent/agentRegistry';
22
22
  export * from './permissions/rules';
23
+ export * from './permissions/modePolicy';
24
+ export * from './permissions/bashClassify';
23
25
  export * from './permissions/destructive';
24
26
  export * from './plugins/index';
25
27
  export * from './plugins/installer';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -36,6 +36,8 @@ __exportStar(require("./agent/agentTypes"), exports);
36
36
  __exportStar(require("./agent/planMode"), exports);
37
37
  __exportStar(require("./agent/agentRegistry"), exports);
38
38
  __exportStar(require("./permissions/rules"), exports);
39
+ __exportStar(require("./permissions/modePolicy"), exports);
40
+ __exportStar(require("./permissions/bashClassify"), exports);
39
41
  __exportStar(require("./permissions/destructive"), exports);
40
42
  __exportStar(require("./plugins/index"), exports);
41
43
  __exportStar(require("./plugins/installer"), exports);
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Whether a bash command should take the repo-state lock.
3
+ *
4
+ * Exported for tests: the failure mode (two concurrent `git commit`) is timing-dependent
5
+ * and painful to reproduce through the real loop.
6
+ *
7
+ * Scans EVERY segment, not just the first word, because the mutating verb is routinely
8
+ * not leading: `cd packages/core && npm publish`, `FOO=1 git push`, `ls && git commit`.
9
+ * Checking only the first token would miss most real commands.
10
+ */
11
+ export declare function bashNeedsRepoLock(command: string): boolean;
12
+ //# sourceMappingURL=bashClassify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bashClassify.d.ts","sourceRoot":"","sources":["../../src/permissions/bashClassify.ts"],"names":[],"mappings":"AAqCA;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAkB1D"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ // ─── Classifying shell commands ───────────────────────────────────────────────
3
+ //
4
+ // Lives in permissions/ rather than agent/loop.ts because TWO subsystems need the same
5
+ // answer to "does this command mutate shared state?":
6
+ //
7
+ // • the concurrency locks — two `git commit` must not interleave;
8
+ // • the permission gate — `auto` mode runs `npm test` without asking but must still
9
+ // prompt for anything with wider side effects.
10
+ //
11
+ // Keeping one classifier means those can never disagree. Two copies would be a second
12
+ // source of truth that has to stay in sync forever, which is the exact class of bug this
13
+ // codebase keeps turning up (a prompt promising what the gate didn't enforce; a mode the
14
+ // gate never read).
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.bashNeedsRepoLock = bashNeedsRepoLock;
17
+ /**
18
+ * Commands that must not run concurrently with another instance of themselves.
19
+ *
20
+ * `bash` was excluded from the write-tool lock entirely, which was the largest hole in
21
+ * the concurrency story: it is the most mutating tool there is, and with 4 sub-agents
22
+ * fanned out two of them could run `git commit` simultaneously (one dies on
23
+ * `.git/index.lock`), or two `npm install` (corrupted node_modules / lockfile), or two
24
+ * `npm test` writing the same coverage and snapshot files (wrong results, not an error).
25
+ * The comment above withFileLock explains carefully why two edit_file calls must be
26
+ * sequenced, then a `bash -c 'echo x > file'` did exactly that with nothing holding it.
27
+ *
28
+ * Deliberately a VERB ALLOWLIST rather than serialising all of bash: an explorer's
29
+ * `grep`/`rg`/`ls`/`cat` are read-only and are precisely the calls that benefit most
30
+ * from running in parallel. Serialising those would trade a real correctness bug for a
31
+ * real performance regression. These verbs are the ones that take a global lock, write
32
+ * a lockfile, or mutate a shared build/dependency directory.
33
+ */
34
+ const MUTATING_BASH_VERBS = new Set([
35
+ 'git', 'npm', 'pnpm', 'yarn', 'bun', 'cargo', 'go', 'pip', 'pip3', 'poetry', 'uv',
36
+ 'bundle', 'composer', 'gradle', 'mvn', 'make', 'terraform', 'helm', 'docker',
37
+ 'vsce', 'tsc', 'pytest', 'dotnet', 'swift', 'gem',
38
+ ]);
39
+ /**
40
+ * Whether a bash command should take the repo-state lock.
41
+ *
42
+ * Exported for tests: the failure mode (two concurrent `git commit`) is timing-dependent
43
+ * and painful to reproduce through the real loop.
44
+ *
45
+ * Scans EVERY segment, not just the first word, because the mutating verb is routinely
46
+ * not leading: `cd packages/core && npm publish`, `FOO=1 git push`, `ls && git commit`.
47
+ * Checking only the first token would miss most real commands.
48
+ */
49
+ function bashNeedsRepoLock(command) {
50
+ if (!command)
51
+ return false;
52
+ // Split on shell separators, then take the first bare word of each segment, skipping
53
+ // env-var assignments (FOO=bar git push) and `sudo`/`time`-style prefixes.
54
+ const segments = command.split(/\|\||&&|[;|&\n()]|\$\(/);
55
+ for (const seg of segments) {
56
+ for (const tokenRaw of seg.trim().split(/\s+/)) {
57
+ const token = tokenRaw.replace(/^["']|["']$/g, '');
58
+ if (!token)
59
+ continue;
60
+ if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(token))
61
+ continue; // env assignment
62
+ if (token === 'sudo' || token === 'time' || token === 'nice' || token === 'env')
63
+ continue;
64
+ // Use the basename so `/usr/bin/git` and `./node_modules/.bin/tsc` still match.
65
+ const verb = token.split('/').pop() ?? token;
66
+ if (MUTATING_BASH_VERBS.has(verb))
67
+ return true;
68
+ break; // only the command word of each segment matters
69
+ }
70
+ }
71
+ return false;
72
+ }
73
+ //# sourceMappingURL=bashClassify.js.map
@@ -0,0 +1,55 @@
1
+ /** Permission modes, in increasing order of autonomy. */
2
+ export type PermissionMode = 'plan' | 'ask' | 'edit' | 'auto';
3
+ /** What the gate should do with one tool call. */
4
+ export type PolicyDecision = 'allow' | 'ask' | 'deny' | 'confirm';
5
+ export interface PolicyInput {
6
+ tool: string;
7
+ input: Record<string, unknown>;
8
+ mode: PermissionMode;
9
+ /** True when the user has already opted into blanket approval (--yolo / bypass). */
10
+ bypass?: boolean;
11
+ /** True when this call is irreversible (DB drop, force-push, rm -rf …). */
12
+ destructive?: boolean;
13
+ }
14
+ /**
15
+ * Tools that only ever READ. Always allowed, in every mode including plan.
16
+ *
17
+ * Kept here rather than in each client so "read-only" cannot mean two different things
18
+ * in two windows. Note `memory_write` is NOT here even though the CLI's old list had it
19
+ * — it mutates durable cross-session state, and listing it under "read-only / safe"
20
+ * meant it silently bypassed plan mode's read-only guarantee.
21
+ */
22
+ export declare const READ_ONLY_TOOLS: Set<string>;
23
+ /** Tools that write to the filesystem. */
24
+ export declare const FILE_WRITE_TOOLS: Set<string>;
25
+ /** Tools that move/delete files — riskier than an in-place edit. */
26
+ export declare const FILE_MUTATE_TOOLS: Set<string>;
27
+ /** Tools that run a shell command. */
28
+ export declare const BASH_TOOLS: Set<string>;
29
+ /**
30
+ * Is this bash command read-only?
31
+ *
32
+ * Deliberately delegates to `bashNeedsRepoLock`, the classifier written for the
33
+ * concurrency work: it already distinguishes commands that mutate shared state
34
+ * (`git`, `npm`, `cargo`, `make` …) from ones that only read (`grep`, `ls`, `cat`,
35
+ * `rg`), scanning every shell segment so `cd x && npm publish` is caught.
36
+ *
37
+ * Reusing it is the point. Writing a second classifier here would create two
38
+ * definitions of "mutating" that must agree forever — the exact failure this whole
39
+ * audit keeps finding. If the lock treats a command as mutating, so does the gate.
40
+ */
41
+ export declare function isReadOnlyBash(command: string): boolean;
42
+ /**
43
+ * The single source of truth for "should we prompt?".
44
+ *
45
+ * Order matters and mirrors Claude Code's: destructive actions are checked BEFORE any
46
+ * blanket approval, so an irreversible command can never ride `--yolo` or `auto`
47
+ * straight to execution. That ordering has a body count in the industry (dropped
48
+ * production databases), and it is the one rule no convenience setting may override.
49
+ */
50
+ export declare function decide(req: PolicyInput): PolicyDecision;
51
+ /** Human-readable one-liner for the footer / status bar. */
52
+ export declare function describeMode(mode: PermissionMode): string;
53
+ /** Normalise arbitrary input to a known mode, defaulting to the safe middle. */
54
+ export declare function parseMode(raw: unknown): PermissionMode;
55
+ //# sourceMappingURL=modePolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modePolicy.d.ts","sourceRoot":"","sources":["../../src/permissions/modePolicy.ts"],"names":[],"mappings":"AAsBA,yDAAyD;AACzD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAE9D,kDAAkD;AAClD,MAAM,MAAM,cAAc,GACtB,OAAO,GACP,KAAK,GACL,MAAM,GACN,SAAS,CAAC;AAEd,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,oFAAoF;IACpF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,aAU1B,CAAC;AAEH,0CAA0C;AAC1C,eAAO,MAAM,gBAAgB,aAE3B,CAAC;AAEH,oEAAoE;AACpE,eAAO,MAAM,iBAAiB,aAE5B,CAAC;AAEH,sCAAsC;AACtC,eAAO,MAAM,UAAU,aAAsD,CAAC;AAE9E;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,WAAW,GAAG,cAAc,CAmDvD;AAED,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAOzD;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAGtD"}
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BASH_TOOLS = exports.FILE_MUTATE_TOOLS = exports.FILE_WRITE_TOOLS = exports.READ_ONLY_TOOLS = void 0;
4
+ exports.isReadOnlyBash = isReadOnlyBash;
5
+ exports.decide = decide;
6
+ exports.describeMode = describeMode;
7
+ exports.parseMode = parseMode;
8
+ const bashClassify_1 = require("./bashClassify");
9
+ /**
10
+ * Tools that only ever READ. Always allowed, in every mode including plan.
11
+ *
12
+ * Kept here rather than in each client so "read-only" cannot mean two different things
13
+ * in two windows. Note `memory_write` is NOT here even though the CLI's old list had it
14
+ * — it mutates durable cross-session state, and listing it under "read-only / safe"
15
+ * meant it silently bypassed plan mode's read-only guarantee.
16
+ */
17
+ exports.READ_ONLY_TOOLS = new Set([
18
+ 'read_file', 'list_directory', 'search_files', 'glob', 'grep',
19
+ 'fetch_url', 'web_search',
20
+ 'bash_output', 'kill_shell',
21
+ 'todo_read', 'todo_write',
22
+ 'memory_read',
23
+ 'use_skill',
24
+ 'notebook_read',
25
+ 'get_diagnostics', 'go_to_definition', 'find_references',
26
+ 'get_symbols', 'get_workspace_symbols', 'get_hover',
27
+ ]);
28
+ /** Tools that write to the filesystem. */
29
+ exports.FILE_WRITE_TOOLS = new Set([
30
+ 'write_file', 'create_file', 'edit_file', 'multi_edit', 'notebook_edit',
31
+ ]);
32
+ /** Tools that move/delete files — riskier than an in-place edit. */
33
+ exports.FILE_MUTATE_TOOLS = new Set([
34
+ 'delete_file', 'move_file', 'copy_file',
35
+ ]);
36
+ /** Tools that run a shell command. */
37
+ exports.BASH_TOOLS = new Set(['bash', 'run_command', 'execute_command']);
38
+ /**
39
+ * Is this bash command read-only?
40
+ *
41
+ * Deliberately delegates to `bashNeedsRepoLock`, the classifier written for the
42
+ * concurrency work: it already distinguishes commands that mutate shared state
43
+ * (`git`, `npm`, `cargo`, `make` …) from ones that only read (`grep`, `ls`, `cat`,
44
+ * `rg`), scanning every shell segment so `cd x && npm publish` is caught.
45
+ *
46
+ * Reusing it is the point. Writing a second classifier here would create two
47
+ * definitions of "mutating" that must agree forever — the exact failure this whole
48
+ * audit keeps finding. If the lock treats a command as mutating, so does the gate.
49
+ */
50
+ function isReadOnlyBash(command) {
51
+ return !(0, bashClassify_1.bashNeedsRepoLock)(command);
52
+ }
53
+ /**
54
+ * The single source of truth for "should we prompt?".
55
+ *
56
+ * Order matters and mirrors Claude Code's: destructive actions are checked BEFORE any
57
+ * blanket approval, so an irreversible command can never ride `--yolo` or `auto`
58
+ * straight to execution. That ordering has a body count in the industry (dropped
59
+ * production databases), and it is the one rule no convenience setting may override.
60
+ */
61
+ function decide(req) {
62
+ const { tool, mode } = req;
63
+ const command = String(req.input.command ?? req.input.cmd ?? '');
64
+ // 1. Reads are always fine — an agent that cannot read cannot help.
65
+ // Checked before plan mode too: plan mode is read-ONLY, not read-nothing.
66
+ if (exports.READ_ONLY_TOOLS.has(tool))
67
+ return 'allow';
68
+ if (exports.BASH_TOOLS.has(tool) && isReadOnlyBash(command) && !req.destructive)
69
+ return 'allow';
70
+ // 2. Irreversible actions ALWAYS need an explicit human "yes".
71
+ // Before bypass, before mode. `rm -rf`, `git push --force`, `DROP TABLE` are not
72
+ // things any mode should silently perform, and the strong confirm treatment (type
73
+ // the word "yes", no "approve all") is what makes it a real speed bump.
74
+ if (req.destructive)
75
+ return 'confirm';
76
+ // 3. Plan mode: refuse every remaining (i.e. mutating) tool outright.
77
+ // A refusal, not a prompt — the guarantee is "nothing changes until I approve the
78
+ // plan", and a prompt would let one distracted keypress break it.
79
+ if (mode === 'plan')
80
+ return 'deny';
81
+ // 4. Explicit blanket approval (--yolo / bypassPermissions). Deliberately after the
82
+ // destructive check above.
83
+ if (req.bypass)
84
+ return 'allow';
85
+ // 5. Mode policy for the mutating tools that remain.
86
+ if (exports.FILE_WRITE_TOOLS.has(tool) || exports.FILE_MUTATE_TOOLS.has(tool)) {
87
+ // `edit` and `auto` both pre-authorise ordinary file edits — that is the whole
88
+ // reason to leave `ask`.
89
+ return mode === 'ask' ? 'ask' : 'allow';
90
+ }
91
+ if (exports.BASH_TOOLS.has(tool)) {
92
+ // A mutating-but-recoverable command: `npm test`, `npm install`, `git commit`,
93
+ // `cargo build`. `auto` runs these, which is the behaviour its own prompt block
94
+ // already advertises. `edit` still asks, matching Claude Code's acceptEdits —
95
+ // "file changes flow, anything with side effects beyond the working directory
96
+ // still prompts" — because shell commands reach the network, global caches and
97
+ // other checkouts, not just this repo.
98
+ return mode === 'auto' ? 'allow' : 'ask';
99
+ }
100
+ // 6. Anything unrecognised — a newly added tool, an MCP tool, a plugin tool — asks,
101
+ // in EVERY mode including `auto`.
102
+ //
103
+ // Fail-CLOSED on permission, deliberately: a tool nobody has classified must not
104
+ // inherit autonomy merely because the user chose a permissive mode. An MCP server
105
+ // is third-party code whose blast radius this policy cannot see, so `auto` meaning
106
+ // "run anything, including things I've never heard of" would make the mode
107
+ // unauditable. Same principle as forcing an unparseable agent definition to
108
+ // read-only: the less we know, the less it gets.
109
+ return 'ask';
110
+ }
111
+ /** Human-readable one-liner for the footer / status bar. */
112
+ function describeMode(mode) {
113
+ switch (mode) {
114
+ case 'plan': return 'plan — read-only, produces a plan for approval';
115
+ case 'ask': return 'ask — approves reads; asks before edits and commands';
116
+ case 'edit': return 'edit — edits files freely; asks before shell commands';
117
+ case 'auto': return 'auto — edits and runs commands; still confirms irreversible actions';
118
+ }
119
+ }
120
+ /** Normalise arbitrary input to a known mode, defaulting to the safe middle. */
121
+ function parseMode(raw) {
122
+ const s = String(raw ?? '').trim().toLowerCase();
123
+ return s === 'plan' || s === 'ask' || s === 'edit' || s === 'auto' ? s : 'ask';
124
+ }
125
+ //# sourceMappingURL=modePolicy.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexrall/code-core",
3
- "version": "1.4.31",
3
+ "version": "1.4.32",
4
4
  "description": "Core agent loop, tools, and extension primitives for Nexrall Code — embed an AI coding agent in any Node.js application.",
5
5
  "license": "MIT",
6
6
  "author": "Nexrall <support@nexrall.com> (https://nexrall.com)",