@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,221 +1,221 @@
1
- export interface SanitizeSystemPromptResult {
2
- prompt: string;
3
- removed: boolean;
4
- }
5
-
6
- type LineSection = { start: number; end: number };
7
-
8
- type GuidelineRule = {
9
- matches: (guideline: string) => boolean;
10
- shouldKeep: (allowedTools: ReadonlySet<string>) => boolean;
11
- };
12
-
13
- const AVAILABLE_TOOLS_SECTION_HEADER = "Available tools:";
14
- const GUIDELINES_SECTION_HEADER = "Guidelines:";
15
-
16
- const TOOL_GUIDELINE_RULES: readonly GuidelineRule[] = [
17
- {
18
- matches: (g) => g === "use bash for file operations like ls, rg, find",
19
- shouldKeep: (tools) => tools.has("bash"),
20
- },
21
- {
22
- matches: (g) =>
23
- g ===
24
- "prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)",
25
- shouldKeep: (tools) =>
26
- tools.has("bash") &&
27
- (tools.has("grep") || tools.has("find") || tools.has("ls")),
28
- },
29
- {
30
- matches: (g) =>
31
- g ===
32
- "use read to examine files before editing. you must use this tool instead of cat or sed." ||
33
- g === "use read to examine files instead of cat or sed.",
34
- shouldKeep: (tools) => tools.has("read"),
35
- },
36
- {
37
- matches: (g) =>
38
- g === "use edit for precise changes (old text must match exactly)",
39
- shouldKeep: (tools) => tools.has("edit"),
40
- },
41
- {
42
- matches: (g) => g === "use write only for new files or complete rewrites",
43
- shouldKeep: (tools) => tools.has("write"),
44
- },
45
- {
46
- matches: (g) =>
47
- g ===
48
- "when summarizing your actions, output plain text directly - do not use cat or bash to display what you did",
49
- shouldKeep: (tools) => tools.has("edit") || tools.has("write"),
50
- },
51
- {
52
- matches: (g) =>
53
- g ===
54
- "use task when work should be delegated to one or more specialized agents instead of handled entirely in the current session.",
55
- shouldKeep: (tools) => tools.has("task"),
56
- },
57
- {
58
- matches: (g) =>
59
- g ===
60
- "use mcp for mcp discovery first: search by capability, describe one exact tool name, then call it.",
61
- shouldKeep: (tools) => tools.has("mcp"),
62
- },
63
- ];
64
-
65
- function normalizePrompt(prompt: string): string {
66
- return (prompt || "").replace(/\r\n/g, "\n");
67
- }
68
-
69
- function collapseExtraBlankLines(text: string): string {
70
- return text.replace(/\n{3,}/g, "\n\n").trimEnd();
71
- }
72
-
73
- function normalizeGuidelineText(line: string): string {
74
- return line
75
- .trim()
76
- .replace(/^[-*]\s+/, "")
77
- .replace(/\s+/g, " ")
78
- .toLowerCase();
79
- }
80
-
81
- function isTopLevelSectionHeader(line: string): boolean {
82
- const trimmed = line.trim();
83
- return (
84
- trimmed.length > 0 && trimmed.endsWith(":") && !trimmed.startsWith("-")
85
- );
86
- }
87
-
88
- function isSectionBodyLine(line: string): boolean {
89
- const trimmed = line.trim();
90
- if (!trimmed) return true;
91
- if (trimmed.startsWith("- ")) return true;
92
- return line !== line.trimStart();
93
- }
94
-
95
- function findSection(
96
- lines: readonly string[],
97
- header: string,
98
- ): LineSection | null {
99
- const start = lines.findIndex((line) => line.trim() === header);
100
- if (start === -1) return null;
101
-
102
- for (let index = start + 1; index < lines.length; index += 1) {
103
- if (isTopLevelSectionHeader(lines[index])) {
104
- return { start, end: index };
105
- }
106
- }
107
-
108
- let end = start + 1;
109
- for (let index = start + 1; index < lines.length; index += 1) {
110
- if (!isSectionBodyLine(lines[index])) {
111
- end = index;
112
- break;
113
- }
114
- end = index + 1;
115
- }
116
- return { start, end };
117
- }
118
-
119
- function extractToolBulletName(line: string): string | null {
120
- const match = /^\s*-\s+([A-Za-z0-9_-]+)/.exec(line);
121
- return match ? match[1] : null;
122
- }
123
-
124
- function narrowAvailableToolsSection(
125
- lines: readonly string[],
126
- allowedTools: ReadonlySet<string>,
127
- ): { lines: string[]; removed: boolean } {
128
- const section = findSection(lines, AVAILABLE_TOOLS_SECTION_HEADER);
129
- if (!section) return { lines: [...lines], removed: false };
130
-
131
- const before = lines.slice(0, section.start);
132
- const header = lines[section.start];
133
- const body = lines.slice(section.start + 1, section.end);
134
- const after = lines.slice(section.end);
135
-
136
- const filteredBody = body.filter((line) => {
137
- const toolName = extractToolBulletName(line);
138
- if (!toolName) return true;
139
- return allowedTools.has(toolName);
140
- });
141
-
142
- const removed = filteredBody.length !== body.length;
143
- if (!removed) return { lines: [...lines], removed: false };
144
-
145
- const hasToolBullet = filteredBody.some(
146
- (line) => extractToolBulletName(line) !== null,
147
- );
148
- if (!hasToolBullet) return { lines: [...before, ...after], removed: true };
149
-
150
- return {
151
- lines: [...before, header, ...filteredBody, ...after],
152
- removed: true,
153
- };
154
- }
155
-
156
- function shouldKeepGuideline(
157
- line: string,
158
- allowedTools: ReadonlySet<string>,
159
- ): boolean {
160
- const normalized = normalizeGuidelineText(line);
161
- for (const rule of TOOL_GUIDELINE_RULES) {
162
- if (rule.matches(normalized)) return rule.shouldKeep(allowedTools);
163
- }
164
- return true;
165
- }
166
-
167
- function sanitizeGuidelinesSection(
168
- lines: readonly string[],
169
- allowedTools: ReadonlySet<string>,
170
- ): { lines: string[]; removed: boolean } {
171
- const section = findSection(lines, GUIDELINES_SECTION_HEADER);
172
- if (!section) return { lines: [...lines], removed: false };
173
-
174
- const before = lines.slice(0, section.start + 1);
175
- const after = lines.slice(section.end);
176
- const body = lines.slice(section.start + 1, section.end);
177
- const filteredBody = body.filter((line) => {
178
- const trimmed = line.trim();
179
- if (!trimmed.startsWith("- ")) return true;
180
- return shouldKeepGuideline(line, allowedTools);
181
- });
182
-
183
- const removed = filteredBody.length !== body.length;
184
- if (!removed) return { lines: [...lines], removed: false };
185
-
186
- const hasBullet = filteredBody.some((line) => line.trim().startsWith("- "));
187
- if (!hasBullet) {
188
- return {
189
- lines: [...lines.slice(0, section.start), ...after],
190
- removed: true,
191
- };
192
- }
193
-
194
- return { lines: [...before, ...filteredBody, ...after], removed: true };
195
- }
196
-
197
- export function sanitizeAvailableToolsSection(
198
- systemPrompt: string,
199
- allowedToolNames: readonly string[],
200
- ): SanitizeSystemPromptResult {
201
- const allowedTools = new Set(
202
- allowedToolNames.map((toolName) => toolName.trim()).filter(Boolean),
203
- );
204
- const normalizedLines = normalizePrompt(systemPrompt).split("\n");
205
- const narrowedToolsSection = narrowAvailableToolsSection(
206
- normalizedLines,
207
- allowedTools,
208
- );
209
- const sanitizedGuidelines = sanitizeGuidelinesSection(
210
- narrowedToolsSection.lines,
211
- allowedTools,
212
- );
213
- const removed = narrowedToolsSection.removed || sanitizedGuidelines.removed;
214
-
215
- return {
216
- prompt: removed
217
- ? collapseExtraBlankLines(sanitizedGuidelines.lines.join("\n"))
218
- : systemPrompt,
219
- removed,
220
- };
221
- }
1
+ export interface SanitizeSystemPromptResult {
2
+ prompt: string;
3
+ removed: boolean;
4
+ }
5
+
6
+ type LineSection = { start: number; end: number };
7
+
8
+ type GuidelineRule = {
9
+ matches: (guideline: string) => boolean;
10
+ shouldKeep: (allowedTools: ReadonlySet<string>) => boolean;
11
+ };
12
+
13
+ const AVAILABLE_TOOLS_SECTION_HEADER = "Available tools:";
14
+ const GUIDELINES_SECTION_HEADER = "Guidelines:";
15
+
16
+ const TOOL_GUIDELINE_RULES: readonly GuidelineRule[] = [
17
+ {
18
+ matches: (g) => g === "use bash for file operations like ls, rg, find",
19
+ shouldKeep: (tools) => tools.has("bash"),
20
+ },
21
+ {
22
+ matches: (g) =>
23
+ g ===
24
+ "prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)",
25
+ shouldKeep: (tools) =>
26
+ tools.has("bash") &&
27
+ (tools.has("grep") || tools.has("find") || tools.has("ls")),
28
+ },
29
+ {
30
+ matches: (g) =>
31
+ g ===
32
+ "use read to examine files before editing. you must use this tool instead of cat or sed." ||
33
+ g === "use read to examine files instead of cat or sed.",
34
+ shouldKeep: (tools) => tools.has("read"),
35
+ },
36
+ {
37
+ matches: (g) =>
38
+ g === "use edit for precise changes (old text must match exactly)",
39
+ shouldKeep: (tools) => tools.has("edit"),
40
+ },
41
+ {
42
+ matches: (g) => g === "use write only for new files or complete rewrites",
43
+ shouldKeep: (tools) => tools.has("write"),
44
+ },
45
+ {
46
+ matches: (g) =>
47
+ g ===
48
+ "when summarizing your actions, output plain text directly - do not use cat or bash to display what you did",
49
+ shouldKeep: (tools) => tools.has("edit") || tools.has("write"),
50
+ },
51
+ {
52
+ matches: (g) =>
53
+ g ===
54
+ "use task when work should be delegated to one or more specialized agents instead of handled entirely in the current session.",
55
+ shouldKeep: (tools) => tools.has("task"),
56
+ },
57
+ {
58
+ matches: (g) =>
59
+ g ===
60
+ "use mcp for mcp discovery first: search by capability, describe one exact tool name, then call it.",
61
+ shouldKeep: (tools) => tools.has("mcp"),
62
+ },
63
+ ];
64
+
65
+ function normalizePrompt(prompt: string): string {
66
+ return (prompt || "").replace(/\r\n/g, "\n");
67
+ }
68
+
69
+ function collapseExtraBlankLines(text: string): string {
70
+ return text.replace(/\n{3,}/g, "\n\n").trimEnd();
71
+ }
72
+
73
+ function normalizeGuidelineText(line: string): string {
74
+ return line
75
+ .trim()
76
+ .replace(/^[-*]\s+/, "")
77
+ .replace(/\s+/g, " ")
78
+ .toLowerCase();
79
+ }
80
+
81
+ function isTopLevelSectionHeader(line: string): boolean {
82
+ const trimmed = line.trim();
83
+ return (
84
+ trimmed.length > 0 && trimmed.endsWith(":") && !trimmed.startsWith("-")
85
+ );
86
+ }
87
+
88
+ function isSectionBodyLine(line: string): boolean {
89
+ const trimmed = line.trim();
90
+ if (!trimmed) return true;
91
+ if (trimmed.startsWith("- ")) return true;
92
+ return line !== line.trimStart();
93
+ }
94
+
95
+ function findSection(
96
+ lines: readonly string[],
97
+ header: string,
98
+ ): LineSection | null {
99
+ const start = lines.findIndex((line) => line.trim() === header);
100
+ if (start === -1) return null;
101
+
102
+ for (let index = start + 1; index < lines.length; index += 1) {
103
+ if (isTopLevelSectionHeader(lines[index])) {
104
+ return { start, end: index };
105
+ }
106
+ }
107
+
108
+ let end = start + 1;
109
+ for (let index = start + 1; index < lines.length; index += 1) {
110
+ if (!isSectionBodyLine(lines[index])) {
111
+ end = index;
112
+ break;
113
+ }
114
+ end = index + 1;
115
+ }
116
+ return { start, end };
117
+ }
118
+
119
+ function extractToolBulletName(line: string): string | null {
120
+ const match = /^\s*-\s+([A-Za-z0-9_-]+)/.exec(line);
121
+ return match ? match[1] : null;
122
+ }
123
+
124
+ function narrowAvailableToolsSection(
125
+ lines: readonly string[],
126
+ allowedTools: ReadonlySet<string>,
127
+ ): { lines: string[]; removed: boolean } {
128
+ const section = findSection(lines, AVAILABLE_TOOLS_SECTION_HEADER);
129
+ if (!section) return { lines: [...lines], removed: false };
130
+
131
+ const before = lines.slice(0, section.start);
132
+ const header = lines[section.start];
133
+ const body = lines.slice(section.start + 1, section.end);
134
+ const after = lines.slice(section.end);
135
+
136
+ const filteredBody = body.filter((line) => {
137
+ const toolName = extractToolBulletName(line);
138
+ if (!toolName) return true;
139
+ return allowedTools.has(toolName);
140
+ });
141
+
142
+ const removed = filteredBody.length !== body.length;
143
+ if (!removed) return { lines: [...lines], removed: false };
144
+
145
+ const hasToolBullet = filteredBody.some(
146
+ (line) => extractToolBulletName(line) !== null,
147
+ );
148
+ if (!hasToolBullet) return { lines: [...before, ...after], removed: true };
149
+
150
+ return {
151
+ lines: [...before, header, ...filteredBody, ...after],
152
+ removed: true,
153
+ };
154
+ }
155
+
156
+ function shouldKeepGuideline(
157
+ line: string,
158
+ allowedTools: ReadonlySet<string>,
159
+ ): boolean {
160
+ const normalized = normalizeGuidelineText(line);
161
+ for (const rule of TOOL_GUIDELINE_RULES) {
162
+ if (rule.matches(normalized)) return rule.shouldKeep(allowedTools);
163
+ }
164
+ return true;
165
+ }
166
+
167
+ function sanitizeGuidelinesSection(
168
+ lines: readonly string[],
169
+ allowedTools: ReadonlySet<string>,
170
+ ): { lines: string[]; removed: boolean } {
171
+ const section = findSection(lines, GUIDELINES_SECTION_HEADER);
172
+ if (!section) return { lines: [...lines], removed: false };
173
+
174
+ const before = lines.slice(0, section.start + 1);
175
+ const after = lines.slice(section.end);
176
+ const body = lines.slice(section.start + 1, section.end);
177
+ const filteredBody = body.filter((line) => {
178
+ const trimmed = line.trim();
179
+ if (!trimmed.startsWith("- ")) return true;
180
+ return shouldKeepGuideline(line, allowedTools);
181
+ });
182
+
183
+ const removed = filteredBody.length !== body.length;
184
+ if (!removed) return { lines: [...lines], removed: false };
185
+
186
+ const hasBullet = filteredBody.some((line) => line.trim().startsWith("- "));
187
+ if (!hasBullet) {
188
+ return {
189
+ lines: [...lines.slice(0, section.start), ...after],
190
+ removed: true,
191
+ };
192
+ }
193
+
194
+ return { lines: [...before, ...filteredBody, ...after], removed: true };
195
+ }
196
+
197
+ export function sanitizeAvailableToolsSection(
198
+ systemPrompt: string,
199
+ allowedToolNames: readonly string[],
200
+ ): SanitizeSystemPromptResult {
201
+ const allowedTools = new Set(
202
+ allowedToolNames.map((toolName) => toolName.trim()).filter(Boolean),
203
+ );
204
+ const normalizedLines = normalizePrompt(systemPrompt).split("\n");
205
+ const narrowedToolsSection = narrowAvailableToolsSection(
206
+ normalizedLines,
207
+ allowedTools,
208
+ );
209
+ const sanitizedGuidelines = sanitizeGuidelinesSection(
210
+ narrowedToolsSection.lines,
211
+ allowedTools,
212
+ );
213
+ const removed = narrowedToolsSection.removed || sanitizedGuidelines.removed;
214
+
215
+ return {
216
+ prompt: removed
217
+ ? collapseExtraBlankLines(sanitizedGuidelines.lines.join("\n"))
218
+ : systemPrompt,
219
+ removed,
220
+ };
221
+ }
@@ -1,66 +1,66 @@
1
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
- import type { PermissionEvaluator } from "./permission-evaluator.ts";
3
- import type { SessionApprovals } from "./session-approvals.ts";
4
- import type { ExtensionConfig, PermissionCheckResult } from "./types.ts";
5
-
6
- export interface PermissionsService {
7
- checkPermission(surface: string, value: string): PermissionCheckResult;
8
- getToolPermission(toolName: string): "allow" | "ask" | "deny";
9
- }
10
-
11
- let serviceInstance: PermissionsService | null = null;
12
-
13
- export function setPermissionsService(
14
- service: PermissionsService | null,
15
- ): void {
16
- serviceInstance = service;
17
- }
18
-
19
- export function getPermissionsService(): PermissionsService | null {
20
- return serviceInstance;
21
- }
22
-
23
- export function createPermissionsService(deps: {
24
- getConfig: () => ExtensionConfig;
25
- evaluator: PermissionEvaluator;
26
- sessionApprovals: SessionApprovals;
27
- getAgentName: () => string | undefined;
28
- }): PermissionsService {
29
- return {
30
- checkPermission(surface, value) {
31
- const config = deps.getConfig();
32
- return deps.evaluator.evaluateSurface(
33
- config.permission ?? {},
34
- surface,
35
- value,
36
- "project",
37
- {
38
- yoloMode: config.yoloMode,
39
- sessionApprovals: deps.sessionApprovals,
40
- },
41
- );
42
- },
43
- getToolPermission(toolName) {
44
- const config = deps.getConfig();
45
- return deps.evaluator.getToolPermission(
46
- config.permission ?? {},
47
- toolName,
48
- {
49
- yoloMode: config.yoloMode,
50
- sessionApprovals: deps.sessionApprovals,
51
- },
52
- );
53
- },
54
- };
55
- }
56
-
57
- export function emitPermissionEvent(
58
- pi: ExtensionAPI,
59
- channel:
60
- | "permissions:ready"
61
- | "permissions:decision"
62
- | "permissions:ui_prompt",
63
- payload: unknown,
64
- ): void {
65
- pi.events.emit(channel, payload);
66
- }
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import type { PermissionEvaluator } from "./permission-evaluator.ts";
3
+ import type { SessionApprovals } from "./session-approvals.ts";
4
+ import type { ExtensionConfig, PermissionCheckResult } from "./types.ts";
5
+
6
+ export interface PermissionsService {
7
+ checkPermission(surface: string, value: string): PermissionCheckResult;
8
+ getToolPermission(toolName: string): "allow" | "ask" | "deny";
9
+ }
10
+
11
+ let serviceInstance: PermissionsService | null = null;
12
+
13
+ export function setPermissionsService(
14
+ service: PermissionsService | null,
15
+ ): void {
16
+ serviceInstance = service;
17
+ }
18
+
19
+ export function getPermissionsService(): PermissionsService | null {
20
+ return serviceInstance;
21
+ }
22
+
23
+ export function createPermissionsService(deps: {
24
+ getConfig: () => ExtensionConfig;
25
+ evaluator: PermissionEvaluator;
26
+ sessionApprovals: SessionApprovals;
27
+ getAgentName: () => string | undefined;
28
+ }): PermissionsService {
29
+ return {
30
+ checkPermission(surface, value) {
31
+ const config = deps.getConfig();
32
+ return deps.evaluator.evaluateSurface(
33
+ config.permission ?? {},
34
+ surface,
35
+ value,
36
+ "project",
37
+ {
38
+ yoloMode: config.yoloMode,
39
+ sessionApprovals: deps.sessionApprovals,
40
+ },
41
+ );
42
+ },
43
+ getToolPermission(toolName) {
44
+ const config = deps.getConfig();
45
+ return deps.evaluator.getToolPermission(
46
+ config.permission ?? {},
47
+ toolName,
48
+ {
49
+ yoloMode: config.yoloMode,
50
+ sessionApprovals: deps.sessionApprovals,
51
+ },
52
+ );
53
+ },
54
+ };
55
+ }
56
+
57
+ export function emitPermissionEvent(
58
+ pi: ExtensionAPI,
59
+ channel:
60
+ | "permissions:ready"
61
+ | "permissions:decision"
62
+ | "permissions:ui_prompt",
63
+ payload: unknown,
64
+ ): void {
65
+ pi.events.emit(channel, payload);
66
+ }
@@ -1 +1,4 @@
1
- export { SessionApprovals } from "./permission-evaluator.ts";
1
+ export {
2
+ patternForSessionApproval,
3
+ SessionApprovals,
4
+ } from "./permission-evaluator.ts";