@namzu/cli 2.0.0 → 2.1.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.
Files changed (176) hide show
  1. package/dist/tui/App.d.ts.map +1 -1
  2. package/dist/tui/App.js +8 -0
  3. package/dist/tui/App.js.map +1 -1
  4. package/dist/tui/agent.d.ts +10 -0
  5. package/dist/tui/agent.d.ts.map +1 -1
  6. package/dist/tui/agent.js +10 -0
  7. package/dist/tui/agent.js.map +1 -1
  8. package/dist/tui/slashCommands.d.ts +46 -0
  9. package/dist/tui/slashCommands.d.ts.map +1 -1
  10. package/dist/tui/slashCommands.js +96 -0
  11. package/dist/tui/slashCommands.js.map +1 -1
  12. package/package.json +11 -6
  13. package/dist/__tests__/environment-reaches-the-turn.test.d.ts +0 -17
  14. package/dist/__tests__/environment-reaches-the-turn.test.d.ts.map +0 -1
  15. package/dist/__tests__/environment-reaches-the-turn.test.js +0 -128
  16. package/dist/__tests__/environment-reaches-the-turn.test.js.map +0 -1
  17. package/dist/__tests__/headless-trust-gate.test.d.ts +0 -23
  18. package/dist/__tests__/headless-trust-gate.test.d.ts.map +0 -1
  19. package/dist/__tests__/headless-trust-gate.test.js +0 -227
  20. package/dist/__tests__/headless-trust-gate.test.js.map +0 -1
  21. package/dist/__tests__/mcp-servers-reach-the-session.test.d.ts +0 -17
  22. package/dist/__tests__/mcp-servers-reach-the-session.test.d.ts.map +0 -1
  23. package/dist/__tests__/mcp-servers-reach-the-session.test.js +0 -171
  24. package/dist/__tests__/mcp-servers-reach-the-session.test.js.map +0 -1
  25. package/dist/__tests__/permission-rules-reach-the-turn.test.d.ts +0 -31
  26. package/dist/__tests__/permission-rules-reach-the-turn.test.d.ts.map +0 -1
  27. package/dist/__tests__/permission-rules-reach-the-turn.test.js +0 -132
  28. package/dist/__tests__/permission-rules-reach-the-turn.test.js.map +0 -1
  29. package/dist/__tests__/project-instructions-reach-the-turn.test.d.ts +0 -24
  30. package/dist/__tests__/project-instructions-reach-the-turn.test.d.ts.map +0 -1
  31. package/dist/__tests__/project-instructions-reach-the-turn.test.js +0 -153
  32. package/dist/__tests__/project-instructions-reach-the-turn.test.js.map +0 -1
  33. package/dist/cli.test.d.ts +0 -2
  34. package/dist/cli.test.d.ts.map +0 -1
  35. package/dist/cli.test.js +0 -108
  36. package/dist/cli.test.js.map +0 -1
  37. package/dist/commands/__tests__/eval.test.d.ts +0 -2
  38. package/dist/commands/__tests__/eval.test.d.ts.map +0 -1
  39. package/dist/commands/__tests__/eval.test.js +0 -165
  40. package/dist/commands/__tests__/eval.test.js.map +0 -1
  41. package/dist/commands/__tests__/passthrough-help.test.d.ts +0 -2
  42. package/dist/commands/__tests__/passthrough-help.test.d.ts.map +0 -1
  43. package/dist/commands/__tests__/passthrough-help.test.js +0 -96
  44. package/dist/commands/__tests__/passthrough-help.test.js.map +0 -1
  45. package/dist/commands/__tests__/resume.test.d.ts +0 -15
  46. package/dist/commands/__tests__/resume.test.d.ts.map +0 -1
  47. package/dist/commands/__tests__/resume.test.js +0 -116
  48. package/dist/commands/__tests__/resume.test.js.map +0 -1
  49. package/dist/commands/__tests__/run-exit-code.test.d.ts +0 -2
  50. package/dist/commands/__tests__/run-exit-code.test.d.ts.map +0 -1
  51. package/dist/commands/__tests__/run-exit-code.test.js +0 -100
  52. package/dist/commands/__tests__/run-exit-code.test.js.map +0 -1
  53. package/dist/commands/__tests__/run-flags.test.d.ts +0 -11
  54. package/dist/commands/__tests__/run-flags.test.d.ts.map +0 -1
  55. package/dist/commands/__tests__/run-flags.test.js +0 -238
  56. package/dist/commands/__tests__/run-flags.test.js.map +0 -1
  57. package/dist/commands/__tests__/run-stream-flags.test.d.ts +0 -2
  58. package/dist/commands/__tests__/run-stream-flags.test.d.ts.map +0 -1
  59. package/dist/commands/__tests__/run-stream-flags.test.js +0 -295
  60. package/dist/commands/__tests__/run-stream-flags.test.js.map +0 -1
  61. package/dist/commands/doctor.test.d.ts +0 -2
  62. package/dist/commands/doctor.test.d.ts.map +0 -1
  63. package/dist/commands/doctor.test.js +0 -82
  64. package/dist/commands/doctor.test.js.map +0 -1
  65. package/dist/config/load.test.d.ts +0 -2
  66. package/dist/config/load.test.d.ts.map +0 -1
  67. package/dist/config/load.test.js +0 -57
  68. package/dist/config/load.test.js.map +0 -1
  69. package/dist/context/__tests__/environment.test.d.ts +0 -10
  70. package/dist/context/__tests__/environment.test.d.ts.map +0 -1
  71. package/dist/context/__tests__/environment.test.js +0 -84
  72. package/dist/context/__tests__/environment.test.js.map +0 -1
  73. package/dist/context/__tests__/project.test.d.ts +0 -12
  74. package/dist/context/__tests__/project.test.d.ts.map +0 -1
  75. package/dist/context/__tests__/project.test.js +0 -201
  76. package/dist/context/__tests__/project.test.js.map +0 -1
  77. package/dist/doctor/checks/credentials.test.d.ts +0 -10
  78. package/dist/doctor/checks/credentials.test.d.ts.map +0 -1
  79. package/dist/doctor/checks/credentials.test.js +0 -47
  80. package/dist/doctor/checks/credentials.test.js.map +0 -1
  81. package/dist/doctor/checks/sandbox.test.d.ts +0 -2
  82. package/dist/doctor/checks/sandbox.test.d.ts.map +0 -1
  83. package/dist/doctor/checks/sandbox.test.js +0 -59
  84. package/dist/doctor/checks/sandbox.test.js.map +0 -1
  85. package/dist/doctor/registry.test.d.ts +0 -7
  86. package/dist/doctor/registry.test.d.ts.map +0 -1
  87. package/dist/doctor/registry.test.js +0 -379
  88. package/dist/doctor/registry.test.js.map +0 -1
  89. package/dist/integrations/mcp/__tests__/connect.test.d.ts +0 -11
  90. package/dist/integrations/mcp/__tests__/connect.test.d.ts.map +0 -1
  91. package/dist/integrations/mcp/__tests__/connect.test.js +0 -231
  92. package/dist/integrations/mcp/__tests__/connect.test.js.map +0 -1
  93. package/dist/integrations/providers/discover.test.d.ts +0 -2
  94. package/dist/integrations/providers/discover.test.d.ts.map +0 -1
  95. package/dist/integrations/providers/discover.test.js +0 -93
  96. package/dist/integrations/providers/discover.test.js.map +0 -1
  97. package/dist/integrations/providers/keychain.test.d.ts +0 -2
  98. package/dist/integrations/providers/keychain.test.d.ts.map +0 -1
  99. package/dist/integrations/providers/keychain.test.js +0 -21
  100. package/dist/integrations/providers/keychain.test.js.map +0 -1
  101. package/dist/integrations/providers/oauth.test.d.ts +0 -2
  102. package/dist/integrations/providers/oauth.test.d.ts.map +0 -1
  103. package/dist/integrations/providers/oauth.test.js +0 -86
  104. package/dist/integrations/providers/oauth.test.js.map +0 -1
  105. package/dist/integrations/providers/preferences.test.d.ts +0 -2
  106. package/dist/integrations/providers/preferences.test.d.ts.map +0 -1
  107. package/dist/integrations/providers/preferences.test.js +0 -76
  108. package/dist/integrations/providers/preferences.test.js.map +0 -1
  109. package/dist/integrations/sessions/__tests__/archived-workspace.test.d.ts +0 -21
  110. package/dist/integrations/sessions/__tests__/archived-workspace.test.d.ts.map +0 -1
  111. package/dist/integrations/sessions/__tests__/archived-workspace.test.js +0 -62
  112. package/dist/integrations/sessions/__tests__/archived-workspace.test.js.map +0 -1
  113. package/dist/integrations/subagents/__tests__/delegation-trace.test.d.ts +0 -2
  114. package/dist/integrations/subagents/__tests__/delegation-trace.test.d.ts.map +0 -1
  115. package/dist/integrations/subagents/__tests__/delegation-trace.test.js +0 -114
  116. package/dist/integrations/subagents/__tests__/delegation-trace.test.js.map +0 -1
  117. package/dist/integrations/trust/store.test.d.ts +0 -2
  118. package/dist/integrations/trust/store.test.d.ts.map +0 -1
  119. package/dist/integrations/trust/store.test.js +0 -50
  120. package/dist/integrations/trust/store.test.js.map +0 -1
  121. package/dist/memory/store.test.d.ts +0 -2
  122. package/dist/memory/store.test.d.ts.map +0 -1
  123. package/dist/memory/store.test.js +0 -63
  124. package/dist/memory/store.test.js.map +0 -1
  125. package/dist/output/formatter.test.d.ts +0 -2
  126. package/dist/output/formatter.test.d.ts.map +0 -1
  127. package/dist/output/formatter.test.js +0 -88
  128. package/dist/output/formatter.test.js.map +0 -1
  129. package/dist/output/rendered-payload.test.d.ts +0 -2
  130. package/dist/output/rendered-payload.test.d.ts.map +0 -1
  131. package/dist/output/rendered-payload.test.js +0 -61
  132. package/dist/output/rendered-payload.test.js.map +0 -1
  133. package/dist/permissions/__tests__/mode.test.d.ts +0 -10
  134. package/dist/permissions/__tests__/mode.test.d.ts.map +0 -1
  135. package/dist/permissions/__tests__/mode.test.js +0 -115
  136. package/dist/permissions/__tests__/mode.test.js.map +0 -1
  137. package/dist/permissions/__tests__/rules.test.d.ts +0 -10
  138. package/dist/permissions/__tests__/rules.test.d.ts.map +0 -1
  139. package/dist/permissions/__tests__/rules.test.js +0 -196
  140. package/dist/permissions/__tests__/rules.test.js.map +0 -1
  141. package/dist/skills/store.test.d.ts +0 -2
  142. package/dist/skills/store.test.d.ts.map +0 -1
  143. package/dist/skills/store.test.js +0 -80
  144. package/dist/skills/store.test.js.map +0 -1
  145. package/dist/tui/__tests__/context-gauge.test.d.ts +0 -2
  146. package/dist/tui/__tests__/context-gauge.test.d.ts.map +0 -1
  147. package/dist/tui/__tests__/context-gauge.test.js +0 -83
  148. package/dist/tui/__tests__/context-gauge.test.js.map +0 -1
  149. package/dist/tui/__tests__/deferred-tool-discovery.test.d.ts +0 -24
  150. package/dist/tui/__tests__/deferred-tool-discovery.test.d.ts.map +0 -1
  151. package/dist/tui/__tests__/deferred-tool-discovery.test.js +0 -111
  152. package/dist/tui/__tests__/deferred-tool-discovery.test.js.map +0 -1
  153. package/dist/tui/__tests__/to-agent-event.test.d.ts +0 -2
  154. package/dist/tui/__tests__/to-agent-event.test.d.ts.map +0 -1
  155. package/dist/tui/__tests__/to-agent-event.test.js +0 -230
  156. package/dist/tui/__tests__/to-agent-event.test.js.map +0 -1
  157. package/dist/tui/__tests__/working-directory.test.d.ts +0 -13
  158. package/dist/tui/__tests__/working-directory.test.d.ts.map +0 -1
  159. package/dist/tui/__tests__/working-directory.test.js +0 -109
  160. package/dist/tui/__tests__/working-directory.test.js.map +0 -1
  161. package/dist/tui/agent.test.d.ts +0 -2
  162. package/dist/tui/agent.test.d.ts.map +0 -1
  163. package/dist/tui/agent.test.js +0 -225
  164. package/dist/tui/agent.test.js.map +0 -1
  165. package/dist/tui/markdownParser.test.d.ts +0 -2
  166. package/dist/tui/markdownParser.test.d.ts.map +0 -1
  167. package/dist/tui/markdownParser.test.js +0 -90
  168. package/dist/tui/markdownParser.test.js.map +0 -1
  169. package/dist/tui/mentions.test.d.ts +0 -2
  170. package/dist/tui/mentions.test.d.ts.map +0 -1
  171. package/dist/tui/mentions.test.js +0 -35
  172. package/dist/tui/mentions.test.js.map +0 -1
  173. package/dist/tui/slashCommands.test.d.ts +0 -2
  174. package/dist/tui/slashCommands.test.d.ts.map +0 -1
  175. package/dist/tui/slashCommands.test.js +0 -114
  176. package/dist/tui/slashCommands.test.js.map +0 -1
@@ -1,115 +0,0 @@
1
- /**
2
- * The mode, and its precedence against the config file.
3
- *
4
- * The rule being protected is one sentence: a mode governs only the calls no
5
- * rule decided, so it can never reopen what a rule closed. The tests that
6
- * matter are the ones that would catch a future change making
7
- * `--permission-mode auto` able to run something the operator wrote `deny` for.
8
- */
9
- import { VerificationGate, configureLogger, getRootLogger } from '@namzu/sdk';
10
- import { describe, expect, it } from 'vitest';
11
- import { makeResumeHandler } from '../../tui/agent.js';
12
- import { PERMISSION_MODES, isPermissionMode, resolvePermissionMode } from '../mode.js';
13
- import { compilePermissions } from '../rules.js';
14
- configureLogger({ level: 'silent' });
15
- describe('resolving the mode from flag, alias and terminal', () => {
16
- it('takes an explicit flag over everything else', () => {
17
- expect(resolvePermissionMode({ flag: 'strict', interactive: true })).toEqual({ mode: 'strict' });
18
- expect(resolvePermissionMode({ flag: 'prompt', skipPermissions: true, interactive: false })).toEqual({ mode: 'prompt' });
19
- });
20
- it('refuses a mode it does not know, and names the ones it does', () => {
21
- const result = resolvePermissionMode({ flag: 'yolo', interactive: false });
22
- expect('error' in result && result.error).toContain('prompt, auto, strict');
23
- });
24
- it('maps the bypass aliases to auto', () => {
25
- expect(resolvePermissionMode({ skipPermissions: true, interactive: true })).toEqual({
26
- mode: 'auto',
27
- });
28
- });
29
- it('asks when there is someone to ask, and does not when there is not', () => {
30
- // `prompt` without a terminal would silently become `auto` anyway;
31
- // resolving it as `auto` makes the resolved mode honest in a log.
32
- expect(resolvePermissionMode({ interactive: true })).toEqual({ mode: 'prompt' });
33
- expect(resolvePermissionMode({ interactive: false })).toEqual({ mode: 'auto' });
34
- });
35
- it('exposes exactly the modes it accepts', () => {
36
- expect(PERMISSION_MODES.every(isPermissionMode)).toBe(true);
37
- expect(isPermissionMode('trusted')).toBe(false);
38
- });
39
- });
40
- describe('a mode decides only what no rule decided', () => {
41
- function gate(config) {
42
- const { rules } = compilePermissions(config);
43
- return new VerificationGate({
44
- enabled: true,
45
- rules: [...rules],
46
- allowReadOnlyTools: false,
47
- denyDangerousPatterns: false,
48
- logDecisions: false,
49
- }, getRootLogger());
50
- }
51
- it('a denied call never reaches the mode at all', async () => {
52
- // THE precedence test. `deny` is settled by the gate, so no mode — not
53
- // even the one spelled --yolo — is ever consulted about it. If this ever
54
- // fails, a flag has become able to lift a prohibition someone wrote down.
55
- const decision = gate({ bash: 'deny' }).evaluate({
56
- toolName: 'bash',
57
- toolInput: { command: 'rm -rf /tmp/x' },
58
- toolDef: undefined,
59
- });
60
- expect(decision.decision).toBe('deny');
61
- });
62
- it('an allowed call never reaches the mode either', () => {
63
- const decision = gate({ bash: { 'git status*': 'allow' } }).evaluate({
64
- toolName: 'bash',
65
- toolInput: { command: 'git status' },
66
- toolDef: undefined,
67
- });
68
- expect(decision.decision).toBe('allow');
69
- });
70
- });
71
- describe('what each mode does with an undecided call', () => {
72
- const destructive = [
73
- { id: '1', name: 'write', input: { path: 'a.txt' }, isDestructive: true },
74
- ];
75
- it('auto approves it', async () => {
76
- const handler = makeResumeHandler({ all: false }, undefined, 'auto');
77
- const decision = await handler({ type: 'tool_review', toolCalls: destructive });
78
- expect(decision).toEqual({ action: 'approve_tools' });
79
- });
80
- it('strict refuses it, and says asking again will not help', async () => {
81
- // The mode that did not exist: an unattended run could only be `auto`, so
82
- // a CI job either trusted the agent with everything or could not use it.
83
- const handler = makeResumeHandler({ all: false }, undefined, 'strict');
84
- const decision = (await handler({
85
- type: 'tool_review',
86
- toolCalls: destructive,
87
- }));
88
- expect(decision.action).toBe('reject_tools');
89
- expect(decision.feedback).toContain('Asking again will not change it');
90
- });
91
- it('prompt asks the human, and honours the answer', async () => {
92
- let asked = false;
93
- const handler = makeResumeHandler({ all: false }, async () => {
94
- asked = true;
95
- return { kind: 'reject', feedback: 'not that one' };
96
- }, 'prompt');
97
- const decision = (await handler({
98
- type: 'tool_review',
99
- toolCalls: destructive,
100
- }));
101
- expect(asked).toBe(true);
102
- expect(decision.action).toBe('reject_tools');
103
- expect(decision.feedback).toBe('not that one');
104
- });
105
- it('read-only batches run under every mode, including strict', async () => {
106
- // `strict` refuses what needs asking, and a read never needed asking.
107
- // Refusing reads would make the mode unusable rather than strict.
108
- const readOnly = [{ id: '1', name: 'read', input: {}, isDestructive: false }];
109
- const handler = makeResumeHandler({ all: false }, undefined, 'strict');
110
- expect(await handler({ type: 'tool_review', toolCalls: readOnly })).toEqual({
111
- action: 'approve_tools',
112
- });
113
- });
114
- });
115
- //# sourceMappingURL=mode.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mode.test.js","sourceRoot":"","sources":["../../../src/permissions/__tests__/mode.test.ts"],"names":[],"mappings":"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"}
@@ -1,10 +0,0 @@
1
- /**
2
- * The rule compiler.
3
- *
4
- * The load-bearing case is the LAST one: a tool nobody wrote a rule for must
5
- * still be asked about. A declarative permission model that quietly widened the
6
- * default would be a security downgrade wearing a feature's clothes, and it
7
- * would look exactly like this change from the outside.
8
- */
9
- export {};
10
- //# sourceMappingURL=rules.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rules.test.d.ts","sourceRoot":"","sources":["../../../src/permissions/__tests__/rules.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -1,196 +0,0 @@
1
- /**
2
- * The rule compiler.
3
- *
4
- * The load-bearing case is the LAST one: a tool nobody wrote a rule for must
5
- * still be asked about. A declarative permission model that quietly widened the
6
- * default would be a security downgrade wearing a feature's clothes, and it
7
- * would look exactly like this change from the outside.
8
- */
9
- import { VerificationGate, configureLogger, getRootLogger } from '@namzu/sdk';
10
- import { describe, expect, it } from 'vitest';
11
- import { bySpecificity, compilePermissions, matchesPattern, patternToRegExpSource, } from '../rules.js';
12
- describe('pattern matching', () => {
13
- it('matches a literal command exactly', () => {
14
- expect(matchesPattern('git status', 'git status')).toBe(true);
15
- expect(matchesPattern('git statuses', 'git status')).toBe(false);
16
- });
17
- it('lets * stand for any run of characters and ? for one', () => {
18
- expect(matchesPattern('git push --force', 'git push*')).toBe(true);
19
- expect(matchesPattern('cat a.ts', 'cat ?.ts')).toBe(true);
20
- expect(matchesPattern('cat ab.ts', 'cat ?.ts')).toBe(false);
21
- });
22
- it('matches the bare command for a trailing " *"', () => {
23
- // `git push *` is the obvious way to write "any git push". Without this
24
- // the rule silently misses the exact invocation it was written for.
25
- expect(matchesPattern('git push', 'git push *')).toBe(true);
26
- expect(matchesPattern('git push origin main', 'git push *')).toBe(true);
27
- });
28
- it('treats a backslash path as its forward-slash self, both sides', () => {
29
- // One rule has to work on every platform; an operator should not have to
30
- // write the same path twice.
31
- expect(matchesPattern('src\\index.ts', 'src/*.ts')).toBe(true);
32
- expect(matchesPattern('src/index.ts', 'src\\*.ts')).toBe(true);
33
- });
34
- it('does not let a pattern character smuggle in a regex', () => {
35
- // `.` is a literal dot, not "any character", or a rule meant to allow
36
- // `a.ts` would also allow `axts`.
37
- expect(matchesPattern('axts', 'a.ts')).toBe(false);
38
- expect(matchesPattern('a.ts', 'a.ts')).toBe(true);
39
- expect(patternToRegExpSource('a+b')).toBe('^a\\+b$');
40
- });
41
- it('anchors, so a pattern is not a substring search', () => {
42
- expect(matchesPattern('sudo git status', 'git status')).toBe(false);
43
- });
44
- });
45
- describe('specificity ordering', () => {
46
- // The kernel evaluates first-match-wins, so order decides meaning: a bare
47
- // `*` sorted first would make every rule after it dead config.
48
- it('puts a bare star last', () => {
49
- expect(['*', 'git push*', 'git status'].sort(bySpecificity)).toEqual([
50
- 'git status',
51
- 'git push*',
52
- '*',
53
- ]);
54
- });
55
- it('puts a longer literal prefix first', () => {
56
- expect(['git*', 'git push*'].sort(bySpecificity)).toEqual(['git push*', 'git*']);
57
- });
58
- it('is stable for two patterns of equal specificity', () => {
59
- expect(['b*', 'a*'].sort(bySpecificity)).toEqual(['a*', 'b*']);
60
- });
61
- });
62
- describe('compiling a permissions table', () => {
63
- it('turns a bare allow and deny into by-name rules', () => {
64
- const { rules } = compilePermissions({ read: 'allow', bash: 'deny' });
65
- expect(rules).toEqual([
66
- { type: 'allow_by_name', toolNames: ['read'] },
67
- { type: 'deny_by_name', toolNames: ['bash'] },
68
- ]);
69
- });
70
- it('emits pattern rules most-specific-first', () => {
71
- const { rules } = compilePermissions({ bash: { '*': 'deny', 'git status*': 'allow' } });
72
- expect(rules.map((r) => ('decision' in r ? r.decision : r.type))).toEqual(['allow', 'deny']);
73
- });
74
- it('emits nothing for ask, because the gate already asks by default', () => {
75
- // If "ask" emitted a rule it would have to mean something different from
76
- // the absence of a rule, and it does not.
77
- const { rules } = compilePermissions({ edit: 'ask', bash: { 'rm *': 'ask' } });
78
- expect(rules).toEqual([]);
79
- });
80
- it('reports a bad effect instead of dropping it in silence', () => {
81
- // A permission someone believes is in force and which was quietly
82
- // discarded is the worst outcome here — worse than refusing to start.
83
- const { rules, diagnostics } = compilePermissions({
84
- bash: { 'git push*': 'maybe' },
85
- });
86
- expect(rules).toEqual([]);
87
- expect(diagnostics).toHaveLength(1);
88
- expect(diagnostics[0]?.tool).toBe('bash');
89
- expect(diagnostics[0]?.pattern).toBe('git push*');
90
- });
91
- it('keeps the other rules when one line is unreadable', () => {
92
- const { rules, diagnostics } = compilePermissions({
93
- read: 'allow',
94
- bash: 7,
95
- glob: 'allow',
96
- });
97
- expect(rules).toHaveLength(2);
98
- expect(diagnostics).toHaveLength(1);
99
- });
100
- it('a tool nobody wrote a rule for produces no rule, so the gate asks', () => {
101
- // THE case. The kernel's fallback for an unmatched call is `review`, so
102
- // emitting nothing is what makes an unconfigured or newly bridged tool
103
- // prompt. There is deliberately no way to spell "allow by omission":
104
- // widening the default has to be something an operator typed.
105
- const { rules } = compilePermissions({ read: 'allow' });
106
- expect(rules.some((r) => 'toolNames' in r && r.toolNames.includes('some_new_tool'))).toBe(false);
107
- expect(rules).toHaveLength(1);
108
- });
109
- it('is empty for absent config, which is the same as asking about everything', () => {
110
- expect(compilePermissions(undefined)).toEqual({ rules: [], diagnostics: [] });
111
- });
112
- });
113
- configureLogger({ level: 'silent' });
114
- describe('the rules actually decide a real call', () => {
115
- // The compiler tests above assert the SHAPE of the emitted rules. Shape is
116
- // not behaviour: the first version of this compiler emitted `target: 'args'`
117
- // with an anchored pattern, which matches `JSON.stringify(input)` — so
118
- // `^git push.*$` could never match `{"command":"git push origin main"}` and
119
- // every pattern rule decided nothing at all. It looked correct in every
120
- // shape assertion. These drive the kernel's own gate instead.
121
- function decide(config, tool, input) {
122
- const { rules } = compilePermissions(config);
123
- const gate = new VerificationGate({
124
- enabled: true,
125
- rules: [...rules],
126
- allowReadOnlyTools: false,
127
- denyDangerousPatterns: false,
128
- logDecisions: false,
129
- }, getRootLogger());
130
- return gate.evaluate({ toolName: tool, toolInput: input, toolDef: undefined });
131
- }
132
- it('allows the command an operator allowed', () => {
133
- expect(decide({ bash: { 'git status*': 'allow' } }, 'bash', { command: 'git status' }).decision).toBe('allow');
134
- });
135
- it('denies the command an operator denied', () => {
136
- const result = decide({ bash: { 'git push*': 'deny' } }, 'bash', {
137
- command: 'git push origin main',
138
- });
139
- expect(result.decision).toBe('deny');
140
- });
141
- it('does not let one tool rule decide another tool call', () => {
142
- // A rule written under `bash` must not decide an `edit` call whose
143
- // arguments happen to contain the same text. The kernel's pattern rules
144
- // carry no tool scope, so this is the CLI's job and it is easy to lose.
145
- const result = decide({ bash: { 'git push*': 'deny' } }, 'edit', {
146
- content: 'run git push to deploy',
147
- });
148
- expect(result.decision).toBe('review');
149
- });
150
- it('asks about a tool nobody wrote a rule for', () => {
151
- // The load-bearing case, driven end to end rather than inferred.
152
- expect(decide({ read: 'allow' }, 'some_new_bridged_tool', { x: 1 }).decision).toBe('review');
153
- });
154
- it('prefers the specific rule over the catch-all, whatever the config order', () => {
155
- const config = { bash: { '*': 'allow', 'git push*': 'deny' } };
156
- expect(decide(config, 'bash', { command: 'git push --force' }).decision).toBe('deny');
157
- expect(decide(config, 'bash', { command: 'ls' }).decision).toBe('allow');
158
- });
159
- });
160
- describe('what a denial actually says to the model', () => {
161
- // The decision was never the part that was broken. A model told only
162
- // "denied" rewords the command and tries again; a model told WHICH rule
163
- // stopped it, and whether a different input could ever pass, can stop and
164
- // say so. These assert the sentence, not the verdict.
165
- function reasonFor(config, tool, input) {
166
- const { rules } = compilePermissions(config);
167
- const gate = new VerificationGate({
168
- enabled: true,
169
- rules: [...rules],
170
- allowReadOnlyTools: false,
171
- denyDangerousPatterns: false,
172
- logDecisions: false,
173
- }, getRootLogger());
174
- return gate.evaluate({ toolName: tool, toolInput: input, toolDef: undefined }).reason;
175
- }
176
- it('a by-name denial says the tool is refused, so a reworded input will not help', () => {
177
- const reason = reasonFor({ bash: 'deny' }, 'bash', { command: 'ls' });
178
- expect(reason).toContain('bash');
179
- // The part that stops the retry loop.
180
- expect(reason).toContain('a different input will not change it');
181
- });
182
- it('a pattern denial quotes the rule that matched', () => {
183
- const reason = reasonFor({ bash: { 'git push*': 'deny' } }, 'bash', {
184
- command: 'git push --force',
185
- });
186
- expect(reason).toContain('pattern rule');
187
- // The model is shown the rule itself, not the name of its category, so
188
- // it can tell which of its options are closed and which are not.
189
- expect(reason).toContain('git push');
190
- });
191
- it('an unmatched call says nothing matched, rather than naming a rule', () => {
192
- const reason = reasonFor({ read: 'allow' }, 'some_new_tool', {});
193
- expect(reason).toBe('No matching rule found');
194
- });
195
- });
196
- //# sourceMappingURL=rules.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rules.test.js","sourceRoot":"","sources":["../../../src/permissions/__tests__/rules.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=store.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"store.test.d.ts","sourceRoot":"","sources":["../../src/skills/store.test.ts"],"names":[],"mappings":""}
@@ -1,80 +0,0 @@
1
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
- import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
4
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
- import { composeSkillsPrompt, discoverSkills, loadSkillBody, parseSkillMarkdown } from './store.js';
6
- let home;
7
- let cwd;
8
- function writeSkill(root, dir, contents) {
9
- const skillDir = join(root, 'skills', dir);
10
- mkdirSync(skillDir, { recursive: true });
11
- writeFileSync(join(skillDir, 'SKILL.md'), contents);
12
- }
13
- beforeEach(() => {
14
- home = mkdtempSync(join(tmpdir(), 'namzu-skh-'));
15
- cwd = mkdtempSync(join(tmpdir(), 'namzu-skc-'));
16
- mkdirSync(join(home, '.namzu'), { recursive: true });
17
- });
18
- afterEach(() => {
19
- rmSync(home, { recursive: true, force: true });
20
- rmSync(cwd, { recursive: true, force: true });
21
- });
22
- describe('parseSkillMarkdown', () => {
23
- it('splits frontmatter from body', () => {
24
- const parsed = parseSkillMarkdown('---\nname: Pirate\ndescription: talk like a pirate\n---\nArr matey.');
25
- expect(parsed.name).toBe('Pirate');
26
- expect(parsed.description).toBe('talk like a pirate');
27
- expect(parsed.body).toBe('Arr matey.');
28
- });
29
- it('treats a file with no frontmatter as all body', () => {
30
- const parsed = parseSkillMarkdown('just a body');
31
- expect(parsed.name).toBeUndefined();
32
- expect(parsed.body).toBe('just a body');
33
- });
34
- it('tolerates malformed frontmatter', () => {
35
- const parsed = parseSkillMarkdown('---\n: : bad yaml :\n---\nbody here');
36
- expect(parsed.body).toBe('body here');
37
- });
38
- });
39
- describe('discoverSkills', () => {
40
- it('returns empty when no skill dirs exist', () => {
41
- expect(discoverSkills({ home, cwd })).toEqual([]);
42
- });
43
- it('discovers user + project skills, falling back to dir name', () => {
44
- writeSkill(join(home, '.namzu'), 'greet', '---\ndescription: greets\n---\nSay hi.');
45
- writeSkill(cwd, 'lint', 'no frontmatter body');
46
- const skills = discoverSkills({ home, cwd });
47
- expect(skills.map((s) => s.name).sort()).toEqual(['greet', 'lint']);
48
- const greet = skills.find((s) => s.name === 'greet');
49
- expect(greet?.source).toBe('user');
50
- expect(greet?.description).toBe('greets');
51
- expect(skills.find((s) => s.name === 'lint')?.description).toBe('(no description)');
52
- });
53
- it('lets a project skill shadow a user skill of the same name', () => {
54
- writeSkill(join(home, '.namzu'), 'dup', '---\nname: dup\ndescription: user version\n---\nU');
55
- writeSkill(cwd, 'dup', '---\nname: dup\ndescription: project version\n---\nP');
56
- const skills = discoverSkills({ home, cwd });
57
- const dup = skills.filter((s) => s.name === 'dup');
58
- expect(dup).toHaveLength(1);
59
- expect(dup[0]?.source).toBe('project');
60
- expect(dup[0]?.description).toBe('project version');
61
- });
62
- });
63
- describe('loadSkillBody', () => {
64
- it('returns the body of a discovered skill', () => {
65
- writeSkill(cwd, 'greet', '---\nname: greet\n---\nAlways greet warmly.');
66
- const info = discoverSkills({ home, cwd }).find((s) => s.name === 'greet');
67
- expect(info && loadSkillBody(info)).toBe('Always greet warmly.');
68
- });
69
- });
70
- describe('composeSkillsPrompt', () => {
71
- it('returns null when nothing is active', () => {
72
- expect(composeSkillsPrompt([])).toBeNull();
73
- });
74
- it('frames each active skill', () => {
75
- const prompt = composeSkillsPrompt([{ name: 'greet', body: 'Say hi.' }]);
76
- expect(prompt).toContain('### Skill: greet');
77
- expect(prompt).toContain('Say hi.');
78
- });
79
- });
80
- //# sourceMappingURL=store.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"store.test.js","sourceRoot":"","sources":["../../src/skills/store.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=context-gauge.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-gauge.test.d.ts","sourceRoot":"","sources":["../../../src/tui/__tests__/context-gauge.test.ts"],"names":[],"mappings":""}
@@ -1,83 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { buildGauge } from '../StatusBar.js';
3
- /**
4
- * What the footer's context bar may honestly claim.
5
- *
6
- * Two rules, and the second is the one with a history. The gauge must show no
7
- * proportion it cannot ground — it previously grounded one on a two-branch
8
- * guess at the window and a counter that measured something else entirely. And
9
- * when it does show one, the reader must be able to tell a measurement from an
10
- * inference, because a bar that looks measured and is not is the same defect
11
- * in miniature.
12
- */
13
- describe('buildGauge grounds the ratio or shows nothing', () => {
14
- const measured = { measuredBy: 'provider', windowSource: 'model-table' };
15
- it('divides context by window, not spend by a guess', () => {
16
- const gauge = buildGauge({ tokens: 50_000, windowTokens: 200_000, ...measured });
17
- expect(gauge?.pct).toBe(25);
18
- });
19
- it('shows nothing when the window is missing', () => {
20
- expect(buildGauge({ tokens: 50_000, ...measured })).toBeNull();
21
- });
22
- it('shows nothing when the measurement is missing', () => {
23
- expect(buildGauge({ windowTokens: 200_000, ...measured })).toBeNull();
24
- });
25
- it('shows nothing at all rather than a partial gauge', () => {
26
- expect(buildGauge(null)).toBeNull();
27
- expect(buildGauge(undefined)).toBeNull();
28
- expect(buildGauge({})).toBeNull();
29
- });
30
- it('refuses a zero window instead of dividing by it', () => {
31
- // Not reachable from today's kernel, which always resolves a positive
32
- // window when it reports one — but Infinity rendered as a bar is a
33
- // worse outcome than silence, and the guard costs one comparison.
34
- expect(buildGauge({ tokens: 10, windowTokens: 0, ...measured })).toBeNull();
35
- });
36
- it('clamps rather than reporting over 100 percent', () => {
37
- const gauge = buildGauge({ tokens: 400_000, windowTokens: 200_000, ...measured });
38
- expect(gauge?.pct).toBe(100);
39
- expect(gauge?.bar).not.toContain('░');
40
- });
41
- });
42
- describe('buildGauge marks a ratio no stronger than its weaker term', () => {
43
- it('presents a provider count against a known window as measured', () => {
44
- const gauge = buildGauge({
45
- tokens: 50_000,
46
- windowTokens: 200_000,
47
- measuredBy: 'provider',
48
- windowSource: 'model-table',
49
- });
50
- expect(gauge?.approximate).toBe(false);
51
- });
52
- it('marks an estimated numerator', () => {
53
- const gauge = buildGauge({
54
- tokens: 50_000,
55
- windowTokens: 200_000,
56
- measuredBy: 'estimate',
57
- windowSource: 'model-table',
58
- });
59
- expect(gauge?.approximate).toBe(true);
60
- });
61
- it('marks an assumed window even when the count is exact', () => {
62
- // The case that makes this rule more than a rename of `measuredBy`.
63
- // `windowSource: 'default'` is the kernel falling back to an assumed
64
- // 128k because it recognised neither a configured window nor the
65
- // model. An exact numerator over an invented denominator is a guess
66
- // wearing a precise-looking figure, and marking only the numerator
67
- // would repeat one level down the error this whole change fixes.
68
- const gauge = buildGauge({
69
- tokens: 50_000,
70
- windowTokens: 128_000,
71
- measuredBy: 'provider',
72
- windowSource: 'default',
73
- });
74
- expect(gauge?.approximate).toBe(true);
75
- });
76
- it('treats an unstated provenance as not measured', () => {
77
- // Silence is not a claim of accuracy. Defaulting the other way would
78
- // let any future producer that forgets the field render as exact.
79
- const gauge = buildGauge({ tokens: 50_000, windowTokens: 200_000 });
80
- expect(gauge?.approximate).toBe(true);
81
- });
82
- });
83
- //# sourceMappingURL=context-gauge.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-gauge.test.js","sourceRoot":"","sources":["../../../src/tui/__tests__/context-gauge.test.ts"],"names":[],"mappings":"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"}
@@ -1,24 +0,0 @@
1
- /**
2
- * `search_tools` is mounted where there is something to find, and not where
3
- * there is not.
4
- *
5
- * The two registries come from the same builder, so "does the CLI register
6
- * search_tools" has one answer from one call site and a different correct
7
- * answer from the other — the shape that hides behind a green suite. The
8
- * session passes a `taskStore`, so `query()` registers the task tools deferred
9
- * and the search has a roster of three. A sub-agent is built with no task
10
- * store, so nothing in its registry is deferred and the tool could only ever
11
- * answer "no deferred tools matching X" — a capability advertised every turn
12
- * that costs a turn to discover it is unusable.
13
- *
14
- * Removing the peer-daemon catalog is what created the asymmetry: that catalog
15
- * used to supply BOTH registries, so both were justified in mounting the tool.
16
- * Only one lost its supplier, and from the side that still works the loss is
17
- * invisible.
18
- *
19
- * So this asserts the CONTRAST, not either half: a test that only checked the
20
- * session would pass with the tool wrongly mounted on the sub-agent, which is
21
- * exactly the state this file was written against.
22
- */
23
- export {};
24
- //# sourceMappingURL=deferred-tool-discovery.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deferred-tool-discovery.test.d.ts","sourceRoot":"","sources":["../../../src/tui/__tests__/deferred-tool-discovery.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG"}