@vitos-pizza/vitos-pizza 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/AGENTS.md +158 -158
  2. package/CHANGELOG.md +42 -24
  3. package/LICENSE +21 -21
  4. package/README.md +237 -234
  5. package/assets/logo.svg +28 -28
  6. package/node_modules/@vitos-pizza/agent-mode/extensions/index.ts +138 -117
  7. package/node_modules/@vitos-pizza/agent-mode/package.json +3 -3
  8. package/node_modules/@vitos-pizza/agent-mode/src/apply-mode.ts +60 -60
  9. package/node_modules/@vitos-pizza/agent-mode/src/mode-events.ts +102 -102
  10. package/node_modules/@vitos-pizza/agent-mode/src/modes.ts +43 -43
  11. package/node_modules/@vitos-pizza/agent-mode/src/plan-instructions.ts +85 -44
  12. package/node_modules/@vitos-pizza/agent-mode/tests/apply-mode.test.ts +36 -36
  13. package/node_modules/@vitos-pizza/agent-mode/tests/mode-events.test.ts +22 -22
  14. package/node_modules/@vitos-pizza/agent-mode/tests/modes.test.ts +38 -38
  15. package/node_modules/@vitos-pizza/agent-mode/tests/plan-instructions.test.ts +68 -45
  16. package/node_modules/@vitos-pizza/agent-mode/tsconfig.json +13 -13
  17. package/node_modules/@vitos-pizza/agent-mode/vitest.config.ts +8 -8
  18. package/node_modules/@vitos-pizza/keybindings/extensions/index.ts +104 -104
  19. package/node_modules/@vitos-pizza/keybindings/package.json +1 -1
  20. package/node_modules/@vitos-pizza/keybindings/presets/shortcuts.json +3 -3
  21. package/node_modules/@vitos-pizza/keybindings/src/bind.ts +57 -57
  22. package/node_modules/@vitos-pizza/keybindings/src/config.ts +84 -84
  23. package/node_modules/@vitos-pizza/keybindings/src/registry.ts +43 -43
  24. package/node_modules/@vitos-pizza/keybindings/src/types.ts +54 -54
  25. package/node_modules/@vitos-pizza/keybindings/tests/config.test.ts +83 -83
  26. package/node_modules/@vitos-pizza/keybindings/tests/registry.test.ts +142 -142
  27. package/node_modules/@vitos-pizza/keybindings/tsconfig.json +13 -13
  28. package/node_modules/@vitos-pizza/keybindings/vitest.config.ts +8 -8
  29. package/node_modules/@vitos-pizza/permission-system/extensions/index.ts +162 -162
  30. package/node_modules/@vitos-pizza/permission-system/package.json +2 -2
  31. package/node_modules/@vitos-pizza/permission-system/src/bash/matcher.ts +54 -51
  32. package/node_modules/@vitos-pizza/permission-system/src/bash/parser.ts +40 -40
  33. package/node_modules/@vitos-pizza/permission-system/src/config-paths.ts +23 -23
  34. package/node_modules/@vitos-pizza/permission-system/src/detect-preset-mode.ts +61 -61
  35. package/node_modules/@vitos-pizza/permission-system/src/expand-home.ts +12 -12
  36. package/node_modules/@vitos-pizza/permission-system/src/forwarding/forwarder.ts +224 -224
  37. package/node_modules/@vitos-pizza/permission-system/src/forwarding/subagent-registry.ts +61 -61
  38. package/node_modules/@vitos-pizza/permission-system/src/gates/path-utils.ts +66 -66
  39. package/node_modules/@vitos-pizza/permission-system/src/gates/pipeline.ts +151 -155
  40. package/node_modules/@vitos-pizza/permission-system/src/handlers/before-agent-start.ts +86 -65
  41. package/node_modules/@vitos-pizza/permission-system/src/handlers/skill-input.ts +1 -1
  42. package/node_modules/@vitos-pizza/permission-system/src/handlers/tool-call-gate.ts +204 -199
  43. package/node_modules/@vitos-pizza/permission-system/src/mode-api.ts +44 -44
  44. package/node_modules/@vitos-pizza/permission-system/src/permission-evaluator.ts +233 -216
  45. package/node_modules/@vitos-pizza/permission-system/src/permission-session.ts +62 -62
  46. package/node_modules/@vitos-pizza/permission-system/src/policy-loader.ts +211 -211
  47. package/node_modules/@vitos-pizza/permission-system/src/sanitizers/skill-prompt.ts +99 -99
  48. package/node_modules/@vitos-pizza/permission-system/src/sanitizers/system-prompt.ts +221 -221
  49. package/node_modules/@vitos-pizza/permission-system/src/service.ts +66 -66
  50. package/node_modules/@vitos-pizza/permission-system/src/session-approvals.ts +4 -1
  51. package/node_modules/@vitos-pizza/permission-system/src/types.ts +80 -80
  52. package/node_modules/@vitos-pizza/permission-system/src/ui/approval-summary.ts +43 -43
  53. package/node_modules/@vitos-pizza/permission-system/src/ui/config-modal.ts +36 -36
  54. package/node_modules/@vitos-pizza/permission-system/src/ui/permission-dialog.ts +52 -52
  55. package/node_modules/@vitos-pizza/permission-system/src/wildcard-matcher.ts +81 -81
  56. package/node_modules/@vitos-pizza/permission-system/src/yaml-frontmatter.ts +84 -84
  57. package/node_modules/@vitos-pizza/permission-system/src/yolo/runtime-api.ts +49 -49
  58. package/node_modules/@vitos-pizza/permission-system/tests/bash-parser.test.ts +32 -32
  59. package/node_modules/@vitos-pizza/permission-system/tests/before-agent-start.test.ts +61 -0
  60. package/node_modules/@vitos-pizza/permission-system/tests/detect-preset-mode.test.ts +68 -68
  61. package/node_modules/@vitos-pizza/permission-system/tests/forwarder.test.ts +55 -55
  62. package/node_modules/@vitos-pizza/permission-system/tests/gates.test.ts +170 -61
  63. package/node_modules/@vitos-pizza/permission-system/tests/path-utils.test.ts +68 -68
  64. package/node_modules/@vitos-pizza/permission-system/tests/permission-evaluator.test.ts +82 -55
  65. package/node_modules/@vitos-pizza/permission-system/tests/policy-loader.test.ts +25 -25
  66. package/node_modules/@vitos-pizza/permission-system/tests/system-prompt-sanitizer.test.ts +22 -22
  67. package/node_modules/@vitos-pizza/permission-system/tests/wildcard-matcher.test.ts +27 -27
  68. package/node_modules/@vitos-pizza/permission-system/tsconfig.json +13 -13
  69. package/node_modules/@vitos-pizza/permission-system/vitest.config.ts +8 -8
  70. package/node_modules/@vitos-pizza/question/package.json +1 -1
  71. package/node_modules/@vitos-pizza/question/src/question-ui.ts +5 -1
  72. package/node_modules/@vitos-pizza/question/src/register-tool.ts +1 -4
  73. package/node_modules/@vitos-pizza/question/tests/question-ui-width-cache.test.ts +45 -0
  74. package/node_modules/@vitos-pizza/question/tests/register-tool-render.test.ts +48 -45
  75. package/node_modules/@vitos-pizza/session-title/extensions/index.ts +137 -137
  76. package/node_modules/@vitos-pizza/session-title/package.json +3 -3
  77. package/node_modules/@vitos-pizza/session-title/src/build-title-prompt.ts +16 -16
  78. package/node_modules/@vitos-pizza/session-title/src/extract-title-context.ts +55 -55
  79. package/node_modules/@vitos-pizza/session-title/src/fast-rules.ts +48 -48
  80. package/node_modules/@vitos-pizza/session-title/src/load-settings.ts +70 -70
  81. package/node_modules/@vitos-pizza/session-title/src/normalize-title.ts +20 -20
  82. package/node_modules/@vitos-pizza/session-title/src/parse-title-response.ts +6 -6
  83. package/node_modules/@vitos-pizza/session-title/src/resolve-title-model.ts +33 -33
  84. package/node_modules/@vitos-pizza/session-title/src/schedule-title-job.ts +53 -53
  85. package/node_modules/@vitos-pizza/session-title/src/should-schedule.ts +30 -30
  86. package/node_modules/@vitos-pizza/session-title/src/title-agent.ts +60 -60
  87. package/node_modules/@vitos-pizza/session-title/src/truncate-input.ts +10 -10
  88. package/node_modules/@vitos-pizza/session-title/src/types.ts +29 -29
  89. package/node_modules/@vitos-pizza/session-title/tests/build-title-prompt.test.ts +34 -34
  90. package/node_modules/@vitos-pizza/session-title/tests/extension.test.ts +198 -198
  91. package/node_modules/@vitos-pizza/session-title/tests/extract-title-context.test.ts +48 -48
  92. package/node_modules/@vitos-pizza/session-title/tests/fast-rules.test.ts +43 -43
  93. package/node_modules/@vitos-pizza/session-title/tests/parse-title-response.test.ts +34 -34
  94. package/node_modules/@vitos-pizza/session-title/tests/should-schedule.test.ts +30 -30
  95. package/node_modules/@vitos-pizza/session-title/tests/title-agent.test.ts +154 -154
  96. package/node_modules/@vitos-pizza/session-title/tests/truncate-input.test.ts +15 -15
  97. package/node_modules/@vitos-pizza/session-title/tsconfig.json +13 -13
  98. package/node_modules/@vitos-pizza/session-title/vitest.config.ts +8 -8
  99. package/node_modules/@vitos-pizza/subagents/agents/planner.md +46 -43
  100. package/node_modules/@vitos-pizza/subagents/agents/scout.md +40 -40
  101. package/node_modules/@vitos-pizza/subagents/agents/title.md +13 -13
  102. package/node_modules/@vitos-pizza/subagents/agents/worker.md +36 -36
  103. package/node_modules/@vitos-pizza/subagents/extensions/index.ts +164 -164
  104. package/node_modules/@vitos-pizza/subagents/package.json +1 -1
  105. package/node_modules/@vitos-pizza/subagents/skills/subagents/SKILL.md +86 -80
  106. package/node_modules/@vitos-pizza/subagents/src/agents.ts +166 -166
  107. package/node_modules/@vitos-pizza/subagents/src/async/job-tracker.ts +71 -71
  108. package/node_modules/@vitos-pizza/subagents/src/async/spawn-async.ts +220 -220
  109. package/node_modules/@vitos-pizza/subagents/src/async/storage.ts +57 -57
  110. package/node_modules/@vitos-pizza/subagents/src/env.ts +4 -4
  111. package/node_modules/@vitos-pizza/subagents/src/execute-subagent.ts +285 -285
  112. package/node_modules/@vitos-pizza/subagents/src/progress.ts +187 -187
  113. package/node_modules/@vitos-pizza/subagents/src/render-animation.ts +40 -40
  114. package/node_modules/@vitos-pizza/subagents/src/render.ts +428 -428
  115. package/node_modules/@vitos-pizza/subagents/src/rpc/channels.ts +21 -21
  116. package/node_modules/@vitos-pizza/subagents/src/rpc/client.ts +144 -144
  117. package/node_modules/@vitos-pizza/subagents/src/rpc/server.ts +11 -11
  118. package/node_modules/@vitos-pizza/subagents/src/run-agent.ts +313 -313
  119. package/node_modules/@vitos-pizza/subagents/src/runtime.ts +102 -102
  120. package/node_modules/@vitos-pizza/subagents/src/schema.ts +62 -62
  121. package/node_modules/@vitos-pizza/subagents/src/spawn.ts +104 -104
  122. package/node_modules/@vitos-pizza/subagents/src/types.ts +92 -92
  123. package/node_modules/@vitos-pizza/subagents/src/utils.ts +100 -100
  124. package/node_modules/@vitos-pizza/subagents/src/wait.ts +159 -159
  125. package/node_modules/@vitos-pizza/subagents/tests/agents.test.ts +19 -19
  126. package/node_modules/@vitos-pizza/subagents/tests/execute-subagent.test.ts +96 -96
  127. package/node_modules/@vitos-pizza/subagents/tests/extension.test.ts +42 -42
  128. package/node_modules/@vitos-pizza/subagents/tests/progress.test.ts +206 -206
  129. package/node_modules/@vitos-pizza/subagents/tests/rpc.test.ts +74 -74
  130. package/node_modules/@vitos-pizza/subagents/tsconfig.json +13 -13
  131. package/node_modules/@vitos-pizza/subagents/vitest.config.ts +8 -8
  132. package/node_modules/@vitos-pizza/ui-enhancements/package.json +1 -1
  133. package/node_modules/@vitos-pizza/ui-enhancements/src/chrome/agent-mode-badge.ts +60 -60
  134. package/node_modules/@vitos-pizza/ui-enhancements/src/chrome/border-status.ts +14 -1
  135. package/node_modules/@vitos-pizza/ui-enhancements/src/chrome/resize-recovery.ts +63 -0
  136. package/node_modules/@vitos-pizza/ui-enhancements/tests/agent-mode-badge.test.ts +35 -35
  137. package/node_modules/@vitos-pizza/ui-enhancements/tests/resize-recovery.test.ts +135 -0
  138. package/node_modules/@vitos-pizza/websearch/package.json +1 -1
  139. package/node_modules/node-addon-api/tools/conversion.js +0 -0
  140. package/node_modules/node-gyp-build/bin.js +0 -0
  141. package/node_modules/node-gyp-build/build-test.js +0 -0
  142. package/node_modules/node-gyp-build/optional.js +0 -0
  143. package/package.json +11 -9
  144. package/packages/agent-mode/extensions/index.ts +138 -117
  145. package/packages/agent-mode/package.json +3 -3
  146. package/packages/agent-mode/src/apply-mode.ts +60 -60
  147. package/packages/agent-mode/src/mode-events.ts +102 -102
  148. package/packages/agent-mode/src/modes.ts +43 -43
  149. package/packages/agent-mode/src/plan-instructions.ts +85 -44
  150. package/packages/agent-mode/tsconfig.json +13 -13
  151. package/packages/agent-mode/vitest.config.ts +8 -8
  152. package/packages/keybindings/extensions/index.ts +104 -104
  153. package/packages/keybindings/package.json +1 -1
  154. package/packages/keybindings/presets/shortcuts.json +3 -3
  155. package/packages/keybindings/src/bind.ts +57 -57
  156. package/packages/keybindings/src/config.ts +84 -84
  157. package/packages/keybindings/src/registry.ts +43 -43
  158. package/packages/keybindings/src/types.ts +54 -54
  159. package/packages/keybindings/tsconfig.json +13 -13
  160. package/packages/keybindings/vitest.config.ts +8 -8
  161. package/packages/permission-system/extensions/index.ts +162 -162
  162. package/packages/permission-system/node_modules/web-tree-sitter/debug/tree-sitter.wasm +0 -0
  163. package/packages/permission-system/node_modules/web-tree-sitter/tree-sitter.wasm +0 -0
  164. package/packages/permission-system/package.json +2 -2
  165. package/packages/permission-system/src/bash/matcher.ts +54 -51
  166. package/packages/permission-system/src/bash/parser.ts +40 -40
  167. package/packages/permission-system/src/config-paths.ts +23 -23
  168. package/packages/permission-system/src/detect-preset-mode.ts +61 -61
  169. package/packages/permission-system/src/expand-home.ts +12 -12
  170. package/packages/permission-system/src/forwarding/forwarder.ts +224 -224
  171. package/packages/permission-system/src/forwarding/subagent-registry.ts +61 -61
  172. package/packages/permission-system/src/gates/path-utils.ts +66 -66
  173. package/packages/permission-system/src/gates/pipeline.ts +151 -155
  174. package/packages/permission-system/src/handlers/before-agent-start.ts +86 -65
  175. package/packages/permission-system/src/handlers/skill-input.ts +1 -1
  176. package/packages/permission-system/src/handlers/tool-call-gate.ts +204 -199
  177. package/packages/permission-system/src/mode-api.ts +44 -44
  178. package/packages/permission-system/src/permission-evaluator.ts +233 -216
  179. package/packages/permission-system/src/permission-session.ts +62 -62
  180. package/packages/permission-system/src/policy-loader.ts +211 -211
  181. package/packages/permission-system/src/sanitizers/skill-prompt.ts +99 -99
  182. package/packages/permission-system/src/sanitizers/system-prompt.ts +221 -221
  183. package/packages/permission-system/src/service.ts +66 -66
  184. package/packages/permission-system/src/session-approvals.ts +4 -1
  185. package/packages/permission-system/src/types.ts +80 -80
  186. package/packages/permission-system/src/ui/approval-summary.ts +43 -43
  187. package/packages/permission-system/src/ui/config-modal.ts +36 -36
  188. package/packages/permission-system/src/ui/permission-dialog.ts +52 -52
  189. package/packages/permission-system/src/wildcard-matcher.ts +81 -81
  190. package/packages/permission-system/src/yaml-frontmatter.ts +84 -84
  191. package/packages/permission-system/src/yolo/runtime-api.ts +49 -49
  192. package/packages/permission-system/tsconfig.json +13 -13
  193. package/packages/permission-system/vitest.config.ts +8 -8
  194. package/packages/question/package.json +1 -1
  195. package/packages/question/src/question-ui.ts +5 -1
  196. package/packages/question/src/register-tool.ts +1 -4
  197. package/packages/session-title/extensions/index.ts +137 -137
  198. package/packages/session-title/package.json +3 -3
  199. package/packages/session-title/src/build-title-prompt.ts +16 -16
  200. package/packages/session-title/src/extract-title-context.ts +55 -55
  201. package/packages/session-title/src/fast-rules.ts +48 -48
  202. package/packages/session-title/src/load-settings.ts +70 -70
  203. package/packages/session-title/src/normalize-title.ts +20 -20
  204. package/packages/session-title/src/parse-title-response.ts +6 -6
  205. package/packages/session-title/src/resolve-title-model.ts +33 -33
  206. package/packages/session-title/src/schedule-title-job.ts +53 -53
  207. package/packages/session-title/src/should-schedule.ts +30 -30
  208. package/packages/session-title/src/title-agent.ts +60 -60
  209. package/packages/session-title/src/truncate-input.ts +10 -10
  210. package/packages/session-title/src/types.ts +29 -29
  211. package/packages/session-title/tsconfig.json +13 -13
  212. package/packages/session-title/vitest.config.ts +8 -8
  213. package/packages/subagents/agents/planner.md +46 -43
  214. package/packages/subagents/agents/scout.md +40 -40
  215. package/packages/subagents/agents/title.md +13 -13
  216. package/packages/subagents/agents/worker.md +36 -36
  217. package/packages/subagents/extensions/index.ts +164 -164
  218. package/packages/subagents/package.json +1 -1
  219. package/packages/subagents/skills/subagents/SKILL.md +86 -80
  220. package/packages/subagents/src/agents.ts +166 -166
  221. package/packages/subagents/src/async/job-tracker.ts +71 -71
  222. package/packages/subagents/src/async/spawn-async.ts +220 -220
  223. package/packages/subagents/src/async/storage.ts +57 -57
  224. package/packages/subagents/src/env.ts +4 -4
  225. package/packages/subagents/src/execute-subagent.ts +285 -285
  226. package/packages/subagents/src/progress.ts +187 -187
  227. package/packages/subagents/src/render-animation.ts +40 -40
  228. package/packages/subagents/src/render.ts +428 -428
  229. package/packages/subagents/src/rpc/channels.ts +21 -21
  230. package/packages/subagents/src/rpc/client.ts +144 -144
  231. package/packages/subagents/src/rpc/server.ts +11 -11
  232. package/packages/subagents/src/run-agent.ts +313 -313
  233. package/packages/subagents/src/runtime.ts +102 -102
  234. package/packages/subagents/src/schema.ts +62 -62
  235. package/packages/subagents/src/spawn.ts +104 -104
  236. package/packages/subagents/src/types.ts +92 -92
  237. package/packages/subagents/src/utils.ts +100 -100
  238. package/packages/subagents/src/wait.ts +159 -159
  239. package/packages/subagents/tsconfig.json +13 -13
  240. package/packages/subagents/vitest.config.ts +8 -8
  241. package/packages/todoist/extensions/index.ts +163 -0
  242. package/packages/todoist/package.json +34 -0
  243. package/packages/todoist/src/events.ts +7 -0
  244. package/packages/todoist/src/silent-render.ts +8 -0
  245. package/packages/todoist/src/state.ts +147 -0
  246. package/packages/todoist/src/tools.ts +175 -0
  247. package/packages/todoist/src/types.ts +34 -0
  248. package/packages/todoist/src/widget.ts +109 -0
  249. package/packages/todoist/tsconfig.json +13 -0
  250. package/packages/todoist/vitest.config.ts +8 -0
  251. package/packages/ui-enhancements/package.json +1 -1
  252. package/packages/ui-enhancements/src/chrome/agent-mode-badge.ts +60 -60
  253. package/packages/ui-enhancements/src/chrome/border-status.ts +14 -1
  254. package/packages/ui-enhancements/src/chrome/resize-recovery.ts +63 -0
  255. package/packages/websearch/package.json +1 -1
  256. package/scripts/sync-pi-manifest.mjs +1 -1
  257. package/packages/permission-system/node_modules/web-tree-sitter/lib/tree-sitter.cjs +0 -2988
  258. package/packages/permission-system/node_modules/web-tree-sitter/lib/tree-sitter.wasm +0 -0
  259. package/packages/permission-system/node_modules/web-tree-sitter/lib/tree-sitter.wasm.map +0 -1
@@ -1,61 +1,170 @@
1
- import { describe, expect, it } from "vitest";
2
- import { runGatePipeline } from "../src/gates/pipeline.ts";
3
- import { PermissionEvaluator } from "../src/permission-evaluator.ts";
4
-
5
- describe("gate pipeline", () => {
6
- const evaluator = new PermissionEvaluator();
7
- const permission = {
8
- "*": "allow" as const,
9
- path: {
10
- "*": "allow" as const,
11
- "*.env": "deny" as const,
12
- },
13
- bash: {
14
- "*": "ask" as const,
15
- "git status": "allow" as const,
16
- },
17
- external_directory: "ask" as const,
18
- };
19
-
20
- it("denies sensitive paths across tools", () => {
21
- const result = runGatePipeline(
22
- permission,
23
- evaluator,
24
- {
25
- toolName: "read",
26
- input: { path: ".env" },
27
- cwd: "/workspace/project",
28
- },
29
- { registeredTools: new Set(["read"]) },
30
- );
31
- expect(result.state).toBe("deny");
32
- });
33
-
34
- it("asks for external paths", () => {
35
- const result = runGatePipeline(
36
- permission,
37
- evaluator,
38
- {
39
- toolName: "read",
40
- input: { path: "/etc/hosts" },
41
- cwd: "/workspace/project",
42
- },
43
- { registeredTools: new Set(["read"]) },
44
- );
45
- expect(result.state).toBe("ask");
46
- });
47
-
48
- it("allows whitelisted bash commands", () => {
49
- const result = runGatePipeline(
50
- permission,
51
- evaluator,
52
- {
53
- toolName: "bash",
54
- input: { command: "git status" },
55
- cwd: "/workspace/project",
56
- },
57
- { registeredTools: new Set(["bash"]) },
58
- );
59
- expect(result.state).toBe("allow");
60
- });
61
- });
1
+ import { describe, expect, it } from "vitest";
2
+ import { runGatePipeline } from "../src/gates/pipeline.ts";
3
+ import { PermissionEvaluator } from "../src/permission-evaluator.ts";
4
+ import {
5
+ patternForSessionApproval,
6
+ SessionApprovals,
7
+ } from "../src/session-approvals.ts";
8
+
9
+ describe("gate pipeline", () => {
10
+ const evaluator = new PermissionEvaluator();
11
+ const permission = {
12
+ "*": "allow" as const,
13
+ path: {
14
+ "*": "allow" as const,
15
+ "*.env": "deny" as const,
16
+ },
17
+ bash: {
18
+ "*": "ask" as const,
19
+ "git status": "allow" as const,
20
+ },
21
+ external_directory: "ask" as const,
22
+ web_read: "ask" as const,
23
+ };
24
+
25
+ it("denies sensitive paths across tools", () => {
26
+ const result = runGatePipeline(
27
+ permission,
28
+ evaluator,
29
+ {
30
+ toolName: "read",
31
+ input: { path: ".env" },
32
+ cwd: "/workspace/project",
33
+ },
34
+ { registeredTools: new Set(["read"]) },
35
+ );
36
+ expect(result.state).toBe("deny");
37
+ });
38
+
39
+ it("asks for external paths", () => {
40
+ const result = runGatePipeline(
41
+ permission,
42
+ evaluator,
43
+ {
44
+ toolName: "read",
45
+ input: { path: "/etc/hosts" },
46
+ cwd: "/workspace/project",
47
+ },
48
+ { registeredTools: new Set(["read"]) },
49
+ );
50
+ expect(result.state).toBe("ask");
51
+ expect(result.surface).toBe("external_directory");
52
+ });
53
+
54
+ it("allows whitelisted bash commands", () => {
55
+ const result = runGatePipeline(
56
+ permission,
57
+ evaluator,
58
+ {
59
+ toolName: "bash",
60
+ input: { command: "git status" },
61
+ cwd: "/workspace/project",
62
+ },
63
+ { registeredTools: new Set(["bash"]) },
64
+ );
65
+ expect(result.state).toBe("allow");
66
+ });
67
+
68
+ it("honors session approval for web_read without re-asking", () => {
69
+ const approvals = new SessionApprovals();
70
+ const first = runGatePipeline(
71
+ permission,
72
+ evaluator,
73
+ {
74
+ toolName: "web_read",
75
+ input: { url: "https://example.com/a" },
76
+ cwd: "/workspace/project",
77
+ },
78
+ { registeredTools: new Set(["web_read"]) },
79
+ );
80
+ expect(first.state).toBe("ask");
81
+ approvals.add(
82
+ first.surface,
83
+ patternForSessionApproval(first.surface, first.matchedPattern ?? "*"),
84
+ );
85
+
86
+ const second = runGatePipeline(
87
+ permission,
88
+ evaluator,
89
+ {
90
+ toolName: "web_read",
91
+ input: { url: "https://other.example/b" },
92
+ cwd: "/workspace/project",
93
+ },
94
+ {
95
+ registeredTools: new Set(["web_read"]),
96
+ sessionApprovals: approvals,
97
+ },
98
+ );
99
+ expect(second.state).toBe("allow");
100
+ expect(second.origin).toBe("session");
101
+ });
102
+
103
+ it("honors session approval for external_directory across paths", () => {
104
+ const approvals = new SessionApprovals();
105
+ const first = runGatePipeline(
106
+ permission,
107
+ evaluator,
108
+ {
109
+ toolName: "read",
110
+ input: { path: "/etc/hosts" },
111
+ cwd: "/workspace/project",
112
+ },
113
+ { registeredTools: new Set(["read"]) },
114
+ );
115
+ expect(first.state).toBe("ask");
116
+ approvals.add(
117
+ first.surface,
118
+ patternForSessionApproval(first.surface, first.matchedPattern ?? "*"),
119
+ );
120
+
121
+ const second = runGatePipeline(
122
+ permission,
123
+ evaluator,
124
+ {
125
+ toolName: "read",
126
+ input: { path: "/tmp/other" },
127
+ cwd: "/workspace/project",
128
+ },
129
+ {
130
+ registeredTools: new Set(["read"]),
131
+ sessionApprovals: approvals,
132
+ },
133
+ );
134
+ expect(second.state).toBe("allow");
135
+ });
136
+
137
+ it("honors session approval for bash ask patterns", () => {
138
+ const approvals = new SessionApprovals();
139
+ const first = runGatePipeline(
140
+ permission,
141
+ evaluator,
142
+ {
143
+ toolName: "bash",
144
+ input: { command: "npm install" },
145
+ cwd: "/workspace/project",
146
+ },
147
+ { registeredTools: new Set(["bash"]) },
148
+ );
149
+ expect(first.state).toBe("ask");
150
+ approvals.add(
151
+ first.surface,
152
+ patternForSessionApproval(first.surface, first.matchedPattern ?? "*"),
153
+ );
154
+
155
+ const second = runGatePipeline(
156
+ permission,
157
+ evaluator,
158
+ {
159
+ toolName: "bash",
160
+ input: { command: "npm test" },
161
+ cwd: "/workspace/project",
162
+ },
163
+ {
164
+ registeredTools: new Set(["bash"]),
165
+ sessionApprovals: approvals,
166
+ },
167
+ );
168
+ expect(second.state).toBe("allow");
169
+ });
170
+ });
@@ -1,68 +1,68 @@
1
- import { mkdtempSync, mkdirSync, writeFileSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { describe, expect, it } from "vitest";
5
- import { runGatePipeline } from "../src/gates/pipeline.ts";
6
- import {
7
- findProjectRoot,
8
- isExternalPath,
9
- isPathWithinRoot,
10
- } from "../src/gates/path-utils.ts";
11
- import { PermissionEvaluator } from "../src/permission-evaluator.ts";
12
-
13
- describe("path-utils project root", () => {
14
- it("treats sibling packages inside the git repo as in-project", () => {
15
- const repo = mkdtempSync(join(tmpdir(), "perm-repo-"));
16
- mkdirSync(join(repo, ".git"));
17
- const pkgA = join(repo, "packages", "a");
18
- const pkgB = join(repo, "packages", "b", "file.ts");
19
- mkdirSync(pkgA, { recursive: true });
20
- mkdirSync(join(repo, "packages", "b"), { recursive: true });
21
- writeFileSync(pkgB, "export {}\n", "utf8");
22
-
23
- expect(findProjectRoot(pkgA)).toBe(repo);
24
- expect(isExternalPath(pkgB, pkgA)).toBe(false);
25
- expect(isPathWithinRoot(pkgB, repo)).toBe(true);
26
- });
27
-
28
- it("still treats paths outside the git repo as external", () => {
29
- const repo = mkdtempSync(join(tmpdir(), "perm-repo-"));
30
- mkdirSync(join(repo, ".git"));
31
- expect(isExternalPath("/etc/hosts", repo)).toBe(true);
32
- });
33
- });
34
-
35
- describe("gate pipeline in-project reads", () => {
36
- const evaluator = new PermissionEvaluator();
37
- const permission = {
38
- "*": "allow" as const,
39
- read: "allow" as const,
40
- path: {
41
- "*": "allow" as const,
42
- "*.env": "deny" as const,
43
- },
44
- external_directory: "ask" as const,
45
- };
46
-
47
- it("allows reading another package in the same repo without asking", () => {
48
- const repo = mkdtempSync(join(tmpdir(), "perm-gate-repo-"));
49
- mkdirSync(join(repo, ".git"));
50
- const cwd = join(repo, "packages", "a");
51
- const target = join(repo, "packages", "b", "file.ts");
52
- mkdirSync(cwd, { recursive: true });
53
- mkdirSync(join(repo, "packages", "b"), { recursive: true });
54
- writeFileSync(target, "export {}\n", "utf8");
55
-
56
- const result = runGatePipeline(
57
- permission,
58
- evaluator,
59
- {
60
- toolName: "read",
61
- input: { path: target },
62
- cwd,
63
- },
64
- { registeredTools: new Set(["read"]) },
65
- );
66
- expect(result.state).toBe("allow");
67
- });
68
- });
1
+ import { mkdtempSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { describe, expect, it } from "vitest";
5
+ import { runGatePipeline } from "../src/gates/pipeline.ts";
6
+ import {
7
+ findProjectRoot,
8
+ isExternalPath,
9
+ isPathWithinRoot,
10
+ } from "../src/gates/path-utils.ts";
11
+ import { PermissionEvaluator } from "../src/permission-evaluator.ts";
12
+
13
+ describe("path-utils project root", () => {
14
+ it("treats sibling packages inside the git repo as in-project", () => {
15
+ const repo = mkdtempSync(join(tmpdir(), "perm-repo-"));
16
+ mkdirSync(join(repo, ".git"));
17
+ const pkgA = join(repo, "packages", "a");
18
+ const pkgB = join(repo, "packages", "b", "file.ts");
19
+ mkdirSync(pkgA, { recursive: true });
20
+ mkdirSync(join(repo, "packages", "b"), { recursive: true });
21
+ writeFileSync(pkgB, "export {}\n", "utf8");
22
+
23
+ expect(findProjectRoot(pkgA)).toBe(repo);
24
+ expect(isExternalPath(pkgB, pkgA)).toBe(false);
25
+ expect(isPathWithinRoot(pkgB, repo)).toBe(true);
26
+ });
27
+
28
+ it("still treats paths outside the git repo as external", () => {
29
+ const repo = mkdtempSync(join(tmpdir(), "perm-repo-"));
30
+ mkdirSync(join(repo, ".git"));
31
+ expect(isExternalPath("/etc/hosts", repo)).toBe(true);
32
+ });
33
+ });
34
+
35
+ describe("gate pipeline in-project reads", () => {
36
+ const evaluator = new PermissionEvaluator();
37
+ const permission = {
38
+ "*": "allow" as const,
39
+ read: "allow" as const,
40
+ path: {
41
+ "*": "allow" as const,
42
+ "*.env": "deny" as const,
43
+ },
44
+ external_directory: "ask" as const,
45
+ };
46
+
47
+ it("allows reading another package in the same repo without asking", () => {
48
+ const repo = mkdtempSync(join(tmpdir(), "perm-gate-repo-"));
49
+ mkdirSync(join(repo, ".git"));
50
+ const cwd = join(repo, "packages", "a");
51
+ const target = join(repo, "packages", "b", "file.ts");
52
+ mkdirSync(cwd, { recursive: true });
53
+ mkdirSync(join(repo, "packages", "b"), { recursive: true });
54
+ writeFileSync(target, "export {}\n", "utf8");
55
+
56
+ const result = runGatePipeline(
57
+ permission,
58
+ evaluator,
59
+ {
60
+ toolName: "read",
61
+ input: { path: target },
62
+ cwd,
63
+ },
64
+ { registeredTools: new Set(["read"]) },
65
+ );
66
+ expect(result.state).toBe("allow");
67
+ });
68
+ });
@@ -1,55 +1,82 @@
1
- import { describe, expect, it } from "vitest";
2
- import { PermissionEvaluator } from "../src/permission-evaluator.ts";
3
- import { SessionApprovals } from "../src/session-approvals.ts";
4
-
5
- describe("permission-evaluator", () => {
6
- const evaluator = new PermissionEvaluator();
7
- const permission = {
8
- "*": "allow" as const,
9
- bash: {
10
- "*": "ask" as const,
11
- "git status": "allow" as const,
12
- "rm -rf *": "deny" as const,
13
- },
14
- };
15
-
16
- it("evaluates bash patterns with last-match-wins", () => {
17
- const allowed = evaluator.evaluateSurface(permission, "bash", "git status");
18
- const denied = evaluator.evaluateSurface(permission, "bash", "rm -rf /tmp");
19
- const asked = evaluator.evaluateSurface(permission, "bash", "npm install");
20
-
21
- expect(allowed.state).toBe("allow");
22
- expect(denied.state).toBe("deny");
23
- expect(asked.state).toBe("ask");
24
- });
25
-
26
- it("rewrites ask to allow in yolo mode", () => {
27
- const result = evaluator.evaluateSurface(
28
- permission,
29
- "bash",
30
- "npm install",
31
- "project",
32
- {
33
- yoloMode: true,
34
- },
35
- );
36
- expect(result.state).toBe("allow");
37
- expect(result.origin).toBe("yolo");
38
- });
39
-
40
- it("honors session approvals", () => {
41
- const approvals = new SessionApprovals();
42
- approvals.add("bash", "npm install");
43
- const result = evaluator.evaluateSurface(
44
- permission,
45
- "bash",
46
- "npm install",
47
- "project",
48
- {
49
- sessionApprovals: approvals,
50
- },
51
- );
52
- expect(result.state).toBe("allow");
53
- expect(result.origin).toBe("session");
54
- });
55
- });
1
+ import { describe, expect, it } from "vitest";
2
+ import { PermissionEvaluator } from "../src/permission-evaluator.ts";
3
+ import {
4
+ patternForSessionApproval,
5
+ SessionApprovals,
6
+ } from "../src/session-approvals.ts";
7
+
8
+ describe("permission-evaluator", () => {
9
+ const evaluator = new PermissionEvaluator();
10
+ const permission = {
11
+ "*": "allow" as const,
12
+ bash: {
13
+ "*": "ask" as const,
14
+ "git status": "allow" as const,
15
+ "rm -rf *": "deny" as const,
16
+ },
17
+ web_read: "ask" as const,
18
+ };
19
+
20
+ it("evaluates bash patterns with last-match-wins", () => {
21
+ const allowed = evaluator.evaluateSurface(permission, "bash", "git status");
22
+ const denied = evaluator.evaluateSurface(permission, "bash", "rm -rf /tmp");
23
+ const asked = evaluator.evaluateSurface(permission, "bash", "npm install");
24
+
25
+ expect(allowed.state).toBe("allow");
26
+ expect(denied.state).toBe("deny");
27
+ expect(asked.state).toBe("ask");
28
+ });
29
+
30
+ it("rewrites ask to allow in yolo mode", () => {
31
+ const result = evaluator.evaluateSurface(
32
+ permission,
33
+ "bash",
34
+ "npm install",
35
+ "project",
36
+ {
37
+ yoloMode: true,
38
+ },
39
+ );
40
+ expect(result.state).toBe("allow");
41
+ expect(result.origin).toBe("yolo");
42
+ });
43
+
44
+ it("honors session approvals", () => {
45
+ const approvals = new SessionApprovals();
46
+ approvals.add("bash", "npm install");
47
+ const result = evaluator.evaluateSurface(
48
+ permission,
49
+ "bash",
50
+ "npm install",
51
+ "project",
52
+ {
53
+ sessionApprovals: approvals,
54
+ },
55
+ );
56
+ expect(result.state).toBe("allow");
57
+ expect(result.origin).toBe("session");
58
+ });
59
+
60
+ it("getToolPermission honors session approvals for scalar tools", () => {
61
+ const approvals = new SessionApprovals();
62
+ const asked = evaluator.getToolPermission(permission, "web_read");
63
+ expect(asked).toBe("ask");
64
+
65
+ approvals.add(
66
+ "web_read",
67
+ patternForSessionApproval("web_read", "web_read"),
68
+ );
69
+ const allowed = evaluator.getToolPermission(permission, "web_read", {
70
+ sessionApprovals: approvals,
71
+ });
72
+ expect(allowed).toBe("allow");
73
+ });
74
+
75
+ it("patternForSessionApproval widens scalar surface matches to *", () => {
76
+ expect(patternForSessionApproval("web_read", "web_read")).toBe("*");
77
+ expect(patternForSessionApproval("bash", "*")).toBe("*");
78
+ expect(patternForSessionApproval("bash", "npm install")).toBe(
79
+ "npm install",
80
+ );
81
+ });
82
+ });
@@ -1,25 +1,25 @@
1
- import { describe, expect, it } from "vitest";
2
- import { mergePermissionMaps } from "../src/policy-loader.ts";
3
-
4
- describe("policy-loader merge", () => {
5
- it("merges nested maps and overrides scalars", () => {
6
- const merged = mergePermissionMaps(
7
- {
8
- "*": "allow",
9
- bash: { "*": "ask", "git status": "allow" },
10
- },
11
- {
12
- write: "ask",
13
- bash: { "npm install": "deny" },
14
- },
15
- );
16
-
17
- expect(merged["*"]).toBe("allow");
18
- expect(merged.write).toBe("ask");
19
- expect(merged.bash).toEqual({
20
- "*": "ask",
21
- "git status": "allow",
22
- "npm install": "deny",
23
- });
24
- });
25
- });
1
+ import { describe, expect, it } from "vitest";
2
+ import { mergePermissionMaps } from "../src/policy-loader.ts";
3
+
4
+ describe("policy-loader merge", () => {
5
+ it("merges nested maps and overrides scalars", () => {
6
+ const merged = mergePermissionMaps(
7
+ {
8
+ "*": "allow",
9
+ bash: { "*": "ask", "git status": "allow" },
10
+ },
11
+ {
12
+ write: "ask",
13
+ bash: { "npm install": "deny" },
14
+ },
15
+ );
16
+
17
+ expect(merged["*"]).toBe("allow");
18
+ expect(merged.write).toBe("ask");
19
+ expect(merged.bash).toEqual({
20
+ "*": "ask",
21
+ "git status": "allow",
22
+ "npm install": "deny",
23
+ });
24
+ });
25
+ });
@@ -1,22 +1,22 @@
1
- import { describe, expect, it } from "vitest";
2
- import { sanitizeAvailableToolsSection } from "../src/sanitizers/system-prompt.ts";
3
-
4
- describe("system-prompt sanitizer", () => {
5
- it("removes denied tools from Available tools section", () => {
6
- const prompt = [
7
- "Available tools:",
8
- "- read: read files",
9
- "- bash: run commands",
10
- "- write: write files",
11
- "",
12
- "Guidelines:",
13
- "- use bash for file operations like ls, rg, find",
14
- ].join("\n");
15
-
16
- const result = sanitizeAvailableToolsSection(prompt, ["read"]);
17
- expect(result.removed).toBe(true);
18
- expect(result.prompt).toContain("- read:");
19
- expect(result.prompt).not.toContain("- bash:");
20
- expect(result.prompt).not.toContain("use bash for file operations");
21
- });
22
- });
1
+ import { describe, expect, it } from "vitest";
2
+ import { sanitizeAvailableToolsSection } from "../src/sanitizers/system-prompt.ts";
3
+
4
+ describe("system-prompt sanitizer", () => {
5
+ it("removes denied tools from Available tools section", () => {
6
+ const prompt = [
7
+ "Available tools:",
8
+ "- read: read files",
9
+ "- bash: run commands",
10
+ "- write: write files",
11
+ "",
12
+ "Guidelines:",
13
+ "- use bash for file operations like ls, rg, find",
14
+ ].join("\n");
15
+
16
+ const result = sanitizeAvailableToolsSection(prompt, ["read"]);
17
+ expect(result.removed).toBe(true);
18
+ expect(result.prompt).toContain("- read:");
19
+ expect(result.prompt).not.toContain("- bash:");
20
+ expect(result.prompt).not.toContain("use bash for file operations");
21
+ });
22
+ });
@@ -1,27 +1,27 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- compileWildcardPattern,
4
- findCompiledWildcardMatch,
5
- wildcardMatch,
6
- } from "../src/wildcard-matcher.ts";
7
-
8
- describe("wildcard-matcher", () => {
9
- it("matches exact strings", () => {
10
- expect(wildcardMatch("git status", "git status")).toBe(true);
11
- expect(wildcardMatch("git status", "git diff")).toBe(false);
12
- });
13
-
14
- it("supports trailing optional args", () => {
15
- expect(wildcardMatch("git *", "git")).toBe(true);
16
- expect(wildcardMatch("git *", "git status")).toBe(true);
17
- });
18
-
19
- it("uses last-match-wins ordering", () => {
20
- const compiled = [
21
- compileWildcardPattern("*", "ask"),
22
- compileWildcardPattern("git status", "allow"),
23
- ];
24
- const match = findCompiledWildcardMatch(compiled, "git status");
25
- expect(match?.state).toBe("allow");
26
- });
27
- });
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ compileWildcardPattern,
4
+ findCompiledWildcardMatch,
5
+ wildcardMatch,
6
+ } from "../src/wildcard-matcher.ts";
7
+
8
+ describe("wildcard-matcher", () => {
9
+ it("matches exact strings", () => {
10
+ expect(wildcardMatch("git status", "git status")).toBe(true);
11
+ expect(wildcardMatch("git status", "git diff")).toBe(false);
12
+ });
13
+
14
+ it("supports trailing optional args", () => {
15
+ expect(wildcardMatch("git *", "git")).toBe(true);
16
+ expect(wildcardMatch("git *", "git status")).toBe(true);
17
+ });
18
+
19
+ it("uses last-match-wins ordering", () => {
20
+ const compiled = [
21
+ compileWildcardPattern("*", "ask"),
22
+ compileWildcardPattern("git status", "allow"),
23
+ ];
24
+ const match = findCompiledWildcardMatch(compiled, "git status");
25
+ expect(match?.state).toBe("allow");
26
+ });
27
+ });