@ilya-lesikov/pi-pi 0.1.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 (271) hide show
  1. package/3p/pi-ask-user/index.ts +1835 -0
  2. package/3p/pi-ask-user/package.json +50 -0
  3. package/3p/pi-ask-user/single-select-layout.ts +203 -0
  4. package/3p/pi-lsp/extensions/lsp/client.ts +542 -0
  5. package/3p/pi-lsp/extensions/lsp/config.ts +135 -0
  6. package/3p/pi-lsp/extensions/lsp/effects/command.ts +42 -0
  7. package/3p/pi-lsp/extensions/lsp/effects/filesystem.ts +50 -0
  8. package/3p/pi-lsp/extensions/lsp/effects/runtime.ts +21 -0
  9. package/3p/pi-lsp/extensions/lsp/errors.ts +113 -0
  10. package/3p/pi-lsp/extensions/lsp/formatting.ts +315 -0
  11. package/3p/pi-lsp/extensions/lsp/index.ts +231 -0
  12. package/3p/pi-lsp/extensions/lsp/protocol.ts +209 -0
  13. package/3p/pi-lsp/extensions/lsp/retry.ts +39 -0
  14. package/3p/pi-lsp/extensions/lsp/tools/programs.ts +293 -0
  15. package/3p/pi-lsp/extensions/lsp/tools.ts +89 -0
  16. package/3p/pi-lsp/extensions/lsp/types.ts +243 -0
  17. package/3p/pi-lsp/package.json +54 -0
  18. package/3p/pi-plannotator/AGENTS.md +583 -0
  19. package/3p/pi-plannotator/apps/pi-extension/README.md +228 -0
  20. package/3p/pi-plannotator/apps/pi-extension/assistant-message.ts +128 -0
  21. package/3p/pi-plannotator/apps/pi-extension/config.test.ts +166 -0
  22. package/3p/pi-plannotator/apps/pi-extension/config.ts +318 -0
  23. package/3p/pi-plannotator/apps/pi-extension/current-pi-session.ts +147 -0
  24. package/3p/pi-plannotator/apps/pi-extension/index.ts +1279 -0
  25. package/3p/pi-plannotator/apps/pi-extension/package.json +56 -0
  26. package/3p/pi-plannotator/apps/pi-extension/plannotator-browser.test.ts +13 -0
  27. package/3p/pi-plannotator/apps/pi-extension/plannotator-browser.ts +616 -0
  28. package/3p/pi-plannotator/apps/pi-extension/plannotator-events.ts +342 -0
  29. package/3p/pi-plannotator/apps/pi-extension/plannotator.json +12 -0
  30. package/3p/pi-plannotator/apps/pi-extension/server/agent-jobs.ts +515 -0
  31. package/3p/pi-plannotator/apps/pi-extension/server/ai-runtime.ts +169 -0
  32. package/3p/pi-plannotator/apps/pi-extension/server/annotations.ts +85 -0
  33. package/3p/pi-plannotator/apps/pi-extension/server/external-annotations.ts +189 -0
  34. package/3p/pi-plannotator/apps/pi-extension/server/handlers.ts +210 -0
  35. package/3p/pi-plannotator/apps/pi-extension/server/helpers.ts +78 -0
  36. package/3p/pi-plannotator/apps/pi-extension/server/ide.ts +46 -0
  37. package/3p/pi-plannotator/apps/pi-extension/server/integrations.ts +195 -0
  38. package/3p/pi-plannotator/apps/pi-extension/server/network.test.ts +158 -0
  39. package/3p/pi-plannotator/apps/pi-extension/server/network.ts +268 -0
  40. package/3p/pi-plannotator/apps/pi-extension/server/pr.ts +126 -0
  41. package/3p/pi-plannotator/apps/pi-extension/server/project.ts +64 -0
  42. package/3p/pi-plannotator/apps/pi-extension/server/reference.ts +362 -0
  43. package/3p/pi-plannotator/apps/pi-extension/server/serverAnnotate.ts +199 -0
  44. package/3p/pi-plannotator/apps/pi-extension/server/serverPlan.ts +505 -0
  45. package/3p/pi-plannotator/apps/pi-extension/server/serverReview.ts +1229 -0
  46. package/3p/pi-plannotator/apps/pi-extension/server/vcs.ts +121 -0
  47. package/3p/pi-plannotator/apps/pi-extension/server.test.ts +966 -0
  48. package/3p/pi-plannotator/apps/pi-extension/server.ts +44 -0
  49. package/3p/pi-plannotator/apps/pi-extension/tool-scope.test.ts +88 -0
  50. package/3p/pi-plannotator/apps/pi-extension/tool-scope.ts +39 -0
  51. package/3p/pi-plannotator/apps/pi-extension/tsconfig.json +16 -0
  52. package/3p/pi-plannotator/apps/pi-extension/vendor.sh +48 -0
  53. package/3p/pi-plannotator/package.json +53 -0
  54. package/3p/pi-plannotator/packages/ai/ai.test.ts +1407 -0
  55. package/3p/pi-plannotator/packages/ai/base-session.ts +94 -0
  56. package/3p/pi-plannotator/packages/ai/context.ts +250 -0
  57. package/3p/pi-plannotator/packages/ai/endpoints.ts +326 -0
  58. package/3p/pi-plannotator/packages/ai/index.ts +105 -0
  59. package/3p/pi-plannotator/packages/ai/package.json +21 -0
  60. package/3p/pi-plannotator/packages/ai/provider.ts +103 -0
  61. package/3p/pi-plannotator/packages/ai/providers/claude-agent-sdk.ts +447 -0
  62. package/3p/pi-plannotator/packages/ai/providers/codex-sdk.ts +430 -0
  63. package/3p/pi-plannotator/packages/ai/providers/command-path.ts +115 -0
  64. package/3p/pi-plannotator/packages/ai/providers/opencode-sdk.ts +546 -0
  65. package/3p/pi-plannotator/packages/ai/providers/pi-events.ts +110 -0
  66. package/3p/pi-plannotator/packages/ai/providers/pi-sdk-node.ts +425 -0
  67. package/3p/pi-plannotator/packages/ai/providers/pi-sdk.ts +469 -0
  68. package/3p/pi-plannotator/packages/ai/session-manager.ts +195 -0
  69. package/3p/pi-plannotator/packages/ai/tsconfig.json +15 -0
  70. package/3p/pi-plannotator/packages/ai/types.ts +379 -0
  71. package/3p/pi-plannotator/packages/server/agent-jobs.ts +538 -0
  72. package/3p/pi-plannotator/packages/server/agent-review-message.test.ts +135 -0
  73. package/3p/pi-plannotator/packages/server/agent-review-message.ts +243 -0
  74. package/3p/pi-plannotator/packages/server/ai-runtime.ts +108 -0
  75. package/3p/pi-plannotator/packages/server/annotate.ts +401 -0
  76. package/3p/pi-plannotator/packages/server/browser.test.ts +87 -0
  77. package/3p/pi-plannotator/packages/server/browser.ts +245 -0
  78. package/3p/pi-plannotator/packages/server/claude-review.ts +352 -0
  79. package/3p/pi-plannotator/packages/server/code-nav.ts +73 -0
  80. package/3p/pi-plannotator/packages/server/codex-review-schema.json +41 -0
  81. package/3p/pi-plannotator/packages/server/codex-review.ts +330 -0
  82. package/3p/pi-plannotator/packages/server/config.ts +8 -0
  83. package/3p/pi-plannotator/packages/server/draft.ts +1 -0
  84. package/3p/pi-plannotator/packages/server/editor-annotations.ts +76 -0
  85. package/3p/pi-plannotator/packages/server/external-annotations.test.ts +18 -0
  86. package/3p/pi-plannotator/packages/server/external-annotations.ts +207 -0
  87. package/3p/pi-plannotator/packages/server/git.ts +141 -0
  88. package/3p/pi-plannotator/packages/server/goal-setup.test.ts +55 -0
  89. package/3p/pi-plannotator/packages/server/goal-setup.ts +248 -0
  90. package/3p/pi-plannotator/packages/server/ide.ts +43 -0
  91. package/3p/pi-plannotator/packages/server/image.test.ts +63 -0
  92. package/3p/pi-plannotator/packages/server/image.ts +66 -0
  93. package/3p/pi-plannotator/packages/server/index.ts +648 -0
  94. package/3p/pi-plannotator/packages/server/integrations.test.ts +172 -0
  95. package/3p/pi-plannotator/packages/server/integrations.ts +214 -0
  96. package/3p/pi-plannotator/packages/server/jj.test.ts +69 -0
  97. package/3p/pi-plannotator/packages/server/jj.ts +86 -0
  98. package/3p/pi-plannotator/packages/server/p4.ts +417 -0
  99. package/3p/pi-plannotator/packages/server/package.json +40 -0
  100. package/3p/pi-plannotator/packages/server/path-utils.ts +18 -0
  101. package/3p/pi-plannotator/packages/server/pr.ts +146 -0
  102. package/3p/pi-plannotator/packages/server/project.test.ts +115 -0
  103. package/3p/pi-plannotator/packages/server/project.ts +45 -0
  104. package/3p/pi-plannotator/packages/server/reference-handlers.ts +404 -0
  105. package/3p/pi-plannotator/packages/server/remote.test.ts +150 -0
  106. package/3p/pi-plannotator/packages/server/remote.ts +74 -0
  107. package/3p/pi-plannotator/packages/server/repo.ts +80 -0
  108. package/3p/pi-plannotator/packages/server/resolve-file.test.ts +310 -0
  109. package/3p/pi-plannotator/packages/server/review-workspace.test.ts +1032 -0
  110. package/3p/pi-plannotator/packages/server/review-workspace.ts +48 -0
  111. package/3p/pi-plannotator/packages/server/review.ts +1318 -0
  112. package/3p/pi-plannotator/packages/server/sessions.ts +111 -0
  113. package/3p/pi-plannotator/packages/server/share-url.ts +53 -0
  114. package/3p/pi-plannotator/packages/server/shared-handlers.test.ts +43 -0
  115. package/3p/pi-plannotator/packages/server/shared-handlers.ts +177 -0
  116. package/3p/pi-plannotator/packages/server/storage.test.ts +176 -0
  117. package/3p/pi-plannotator/packages/server/storage.ts +17 -0
  118. package/3p/pi-plannotator/packages/server/tour/tour-review.test.ts +146 -0
  119. package/3p/pi-plannotator/packages/server/tour/tour-review.ts +604 -0
  120. package/3p/pi-plannotator/packages/server/tsconfig.json +15 -0
  121. package/3p/pi-plannotator/packages/server/vcs.test.ts +48 -0
  122. package/3p/pi-plannotator/packages/server/vcs.ts +80 -0
  123. package/3p/pi-plannotator/packages/shared/agent-jobs.ts +132 -0
  124. package/3p/pi-plannotator/packages/shared/agents.ts +53 -0
  125. package/3p/pi-plannotator/packages/shared/annotate-args.test.ts +386 -0
  126. package/3p/pi-plannotator/packages/shared/annotate-args.ts +107 -0
  127. package/3p/pi-plannotator/packages/shared/at-reference.test.ts +99 -0
  128. package/3p/pi-plannotator/packages/shared/at-reference.ts +52 -0
  129. package/3p/pi-plannotator/packages/shared/checklist.ts +52 -0
  130. package/3p/pi-plannotator/packages/shared/code-file.test.ts +112 -0
  131. package/3p/pi-plannotator/packages/shared/code-file.ts +41 -0
  132. package/3p/pi-plannotator/packages/shared/code-nav.test.ts +515 -0
  133. package/3p/pi-plannotator/packages/shared/code-nav.ts +436 -0
  134. package/3p/pi-plannotator/packages/shared/compress.ts +51 -0
  135. package/3p/pi-plannotator/packages/shared/config.ts +262 -0
  136. package/3p/pi-plannotator/packages/shared/crypto.test.ts +172 -0
  137. package/3p/pi-plannotator/packages/shared/crypto.ts +97 -0
  138. package/3p/pi-plannotator/packages/shared/data-dir.ts +42 -0
  139. package/3p/pi-plannotator/packages/shared/diff-paths.test.ts +30 -0
  140. package/3p/pi-plannotator/packages/shared/diff-paths.ts +137 -0
  141. package/3p/pi-plannotator/packages/shared/draft.ts +64 -0
  142. package/3p/pi-plannotator/packages/shared/external-annotation.ts +397 -0
  143. package/3p/pi-plannotator/packages/shared/extract-code-paths.test.ts +59 -0
  144. package/3p/pi-plannotator/packages/shared/extract-code-paths.ts +66 -0
  145. package/3p/pi-plannotator/packages/shared/favicon.ts +5 -0
  146. package/3p/pi-plannotator/packages/shared/feedback-templates.test.ts +65 -0
  147. package/3p/pi-plannotator/packages/shared/feedback-templates.ts +29 -0
  148. package/3p/pi-plannotator/packages/shared/goal-setup.test.ts +231 -0
  149. package/3p/pi-plannotator/packages/shared/goal-setup.ts +336 -0
  150. package/3p/pi-plannotator/packages/shared/html-to-markdown.test.ts +62 -0
  151. package/3p/pi-plannotator/packages/shared/html-to-markdown.ts +32 -0
  152. package/3p/pi-plannotator/packages/shared/improvement-hooks.test.ts +135 -0
  153. package/3p/pi-plannotator/packages/shared/improvement-hooks.ts +115 -0
  154. package/3p/pi-plannotator/packages/shared/integrations-common.ts +243 -0
  155. package/3p/pi-plannotator/packages/shared/jj-core.test.ts +236 -0
  156. package/3p/pi-plannotator/packages/shared/jj-core.ts +433 -0
  157. package/3p/pi-plannotator/packages/shared/package.json +55 -0
  158. package/3p/pi-plannotator/packages/shared/pfm-reminder.test.ts +88 -0
  159. package/3p/pi-plannotator/packages/shared/pfm-reminder.ts +80 -0
  160. package/3p/pi-plannotator/packages/shared/pr-github.ts +661 -0
  161. package/3p/pi-plannotator/packages/shared/pr-gitlab.test.ts +202 -0
  162. package/3p/pi-plannotator/packages/shared/pr-gitlab.ts +620 -0
  163. package/3p/pi-plannotator/packages/shared/pr-provider.test.ts +266 -0
  164. package/3p/pi-plannotator/packages/shared/pr-provider.ts +123 -0
  165. package/3p/pi-plannotator/packages/shared/pr-stack.test.ts +104 -0
  166. package/3p/pi-plannotator/packages/shared/pr-stack.ts +194 -0
  167. package/3p/pi-plannotator/packages/shared/pr-types.ts +326 -0
  168. package/3p/pi-plannotator/packages/shared/project.ts +71 -0
  169. package/3p/pi-plannotator/packages/shared/prompts-integration.test.ts +421 -0
  170. package/3p/pi-plannotator/packages/shared/prompts.test.ts +504 -0
  171. package/3p/pi-plannotator/packages/shared/prompts.ts +247 -0
  172. package/3p/pi-plannotator/packages/shared/reference-common.ts +87 -0
  173. package/3p/pi-plannotator/packages/shared/repo.ts +71 -0
  174. package/3p/pi-plannotator/packages/shared/resolve-file.test.ts +113 -0
  175. package/3p/pi-plannotator/packages/shared/resolve-file.ts +509 -0
  176. package/3p/pi-plannotator/packages/shared/review-args.test.ts +64 -0
  177. package/3p/pi-plannotator/packages/shared/review-args.ts +85 -0
  178. package/3p/pi-plannotator/packages/shared/review-core.test.ts +286 -0
  179. package/3p/pi-plannotator/packages/shared/review-core.ts +895 -0
  180. package/3p/pi-plannotator/packages/shared/review-workspace-node.ts +230 -0
  181. package/3p/pi-plannotator/packages/shared/review-workspace.ts +436 -0
  182. package/3p/pi-plannotator/packages/shared/semantic-diff-types.ts +76 -0
  183. package/3p/pi-plannotator/packages/shared/semantic-diff.test.ts +322 -0
  184. package/3p/pi-plannotator/packages/shared/semantic-diff.ts +520 -0
  185. package/3p/pi-plannotator/packages/shared/storage.ts +378 -0
  186. package/3p/pi-plannotator/packages/shared/tour.ts +61 -0
  187. package/3p/pi-plannotator/packages/shared/tsconfig.json +15 -0
  188. package/3p/pi-plannotator/packages/shared/types.ts +29 -0
  189. package/3p/pi-plannotator/packages/shared/url-to-markdown.test.ts +177 -0
  190. package/3p/pi-plannotator/packages/shared/url-to-markdown.ts +351 -0
  191. package/3p/pi-plannotator/packages/shared/vcs-core.test.ts +332 -0
  192. package/3p/pi-plannotator/packages/shared/vcs-core.ts +482 -0
  193. package/3p/pi-plannotator/packages/shared/worktree-pool.test.ts +162 -0
  194. package/3p/pi-plannotator/packages/shared/worktree-pool.ts +103 -0
  195. package/3p/pi-plannotator/packages/shared/worktree.ts +119 -0
  196. package/3p/pi-subagents/package.json +50 -0
  197. package/3p/pi-subagents/src/agent-manager.ts +413 -0
  198. package/3p/pi-subagents/src/agent-runner.ts +502 -0
  199. package/3p/pi-subagents/src/agent-types.ts +248 -0
  200. package/3p/pi-subagents/src/context.ts +58 -0
  201. package/3p/pi-subagents/src/cross-extension-rpc.ts +135 -0
  202. package/3p/pi-subagents/src/custom-agents.ts +137 -0
  203. package/3p/pi-subagents/src/default-agents.ts +144 -0
  204. package/3p/pi-subagents/src/env.ts +33 -0
  205. package/3p/pi-subagents/src/group-join.ts +141 -0
  206. package/3p/pi-subagents/src/index.ts +1811 -0
  207. package/3p/pi-subagents/src/invocation-config.ts +40 -0
  208. package/3p/pi-subagents/src/memory.ts +165 -0
  209. package/3p/pi-subagents/src/model-resolver.ts +81 -0
  210. package/3p/pi-subagents/src/output-file.ts +77 -0
  211. package/3p/pi-subagents/src/prompts.ts +85 -0
  212. package/3p/pi-subagents/src/skill-loader.ts +79 -0
  213. package/3p/pi-subagents/src/types.ts +111 -0
  214. package/3p/pi-subagents/src/ui/agent-widget.ts +496 -0
  215. package/3p/pi-subagents/src/ui/conversation-viewer.ts +250 -0
  216. package/3p/pi-subagents/src/worktree.ts +162 -0
  217. package/3p/pi-tasks/package.json +52 -0
  218. package/3p/pi-tasks/src/auto-clear.ts +91 -0
  219. package/3p/pi-tasks/src/index.ts +1150 -0
  220. package/3p/pi-tasks/src/process-tracker.ts +140 -0
  221. package/3p/pi-tasks/src/reminder-cadence.ts +90 -0
  222. package/3p/pi-tasks/src/task-store.ts +324 -0
  223. package/3p/pi-tasks/src/tasks-config.ts +27 -0
  224. package/3p/pi-tasks/src/types.ts +40 -0
  225. package/3p/pi-tasks/src/ui/settings-menu.ts +152 -0
  226. package/3p/pi-tasks/src/ui/task-widget.ts +296 -0
  227. package/AGENTS.md +28 -0
  228. package/LICENSE +201 -0
  229. package/extensions/orchestrator/agents/brainstorm-reviewer.ts +77 -0
  230. package/extensions/orchestrator/agents/code-reviewer.ts +89 -0
  231. package/extensions/orchestrator/agents/explore.ts +33 -0
  232. package/extensions/orchestrator/agents/librarian.ts +43 -0
  233. package/extensions/orchestrator/agents/plan-reviewer.ts +75 -0
  234. package/extensions/orchestrator/agents/planner.ts +61 -0
  235. package/extensions/orchestrator/agents/registry.ts +156 -0
  236. package/extensions/orchestrator/agents/task.ts +50 -0
  237. package/extensions/orchestrator/agents/tool-routing.ts +84 -0
  238. package/extensions/orchestrator/ast-search.ts +85 -0
  239. package/extensions/orchestrator/cbm.ts +330 -0
  240. package/extensions/orchestrator/command-handlers.test.ts +163 -0
  241. package/extensions/orchestrator/command-handlers.ts +116 -0
  242. package/extensions/orchestrator/commands.test.ts +81 -0
  243. package/extensions/orchestrator/commands.ts +75 -0
  244. package/extensions/orchestrator/config.test.ts +221 -0
  245. package/extensions/orchestrator/config.ts +230 -0
  246. package/extensions/orchestrator/context.test.ts +293 -0
  247. package/extensions/orchestrator/context.ts +206 -0
  248. package/extensions/orchestrator/event-handlers.test.ts +190 -0
  249. package/extensions/orchestrator/event-handlers.ts +1416 -0
  250. package/extensions/orchestrator/exa.ts +104 -0
  251. package/extensions/orchestrator/flant-infra.ts +486 -0
  252. package/extensions/orchestrator/index.ts +80 -0
  253. package/extensions/orchestrator/integration.test.ts +1214 -0
  254. package/extensions/orchestrator/orchestrator.test.ts +252 -0
  255. package/extensions/orchestrator/orchestrator.ts +538 -0
  256. package/extensions/orchestrator/phases/brainstorm.test.ts +15 -0
  257. package/extensions/orchestrator/phases/brainstorm.ts +273 -0
  258. package/extensions/orchestrator/phases/implementation.ts +40 -0
  259. package/extensions/orchestrator/phases/machine.test.ts +293 -0
  260. package/extensions/orchestrator/phases/machine.ts +209 -0
  261. package/extensions/orchestrator/phases/planning.ts +255 -0
  262. package/extensions/orchestrator/phases/review.ts +193 -0
  263. package/extensions/orchestrator/plannotator.ts +56 -0
  264. package/extensions/orchestrator/pp-menu.ts +866 -0
  265. package/extensions/orchestrator/state.test.ts +343 -0
  266. package/extensions/orchestrator/state.ts +237 -0
  267. package/extensions/orchestrator/validate-artifacts.test.ts +88 -0
  268. package/extensions/orchestrator/validate-artifacts.ts +272 -0
  269. package/extensions/orchestrator/vendor.d.ts +26 -0
  270. package/package.json +73 -0
  271. package/scripts/postinstall.sh +18 -0
@@ -0,0 +1,421 @@
1
+ /**
2
+ * Integration tests for the prompt pipeline.
3
+ *
4
+ * Each test writes a real ~/.plannotator/config.json (in a temp HOME),
5
+ * then calls prompt functions WITHOUT passing a config parameter —
6
+ * forcing loadConfig() to read from disk. This proves the full path:
7
+ * config.json on disk → loadConfig() → getConfiguredPrompt() → output
8
+ *
9
+ * Uses the same subprocess isolation pattern as improvement-hooks.test.ts.
10
+ *
11
+ * Run: bun test packages/shared/prompts-integration.test.ts
12
+ */
13
+
14
+ import { describe, expect, test, beforeEach, afterEach } from "bun:test";
15
+ import { mkdirSync, writeFileSync, rmSync, existsSync } from "fs";
16
+ import { join } from "path";
17
+ import { tmpdir } from "os";
18
+
19
+ const TEST_HOME = join(tmpdir(), `prompts-integration-test-${Date.now()}`);
20
+ const CONFIG_DIR = join(TEST_HOME, ".plannotator");
21
+ const CONFIG_PATH = join(CONFIG_DIR, "config.json");
22
+ const PROJECT_ROOT = join(import.meta.dir, "../..");
23
+
24
+ function writeConfig(config: Record<string, unknown>) {
25
+ mkdirSync(CONFIG_DIR, { recursive: true });
26
+ writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
27
+ }
28
+
29
+ function cleanTestHome() {
30
+ if (existsSync(TEST_HOME)) {
31
+ rmSync(TEST_HOME, { recursive: true, force: true });
32
+ }
33
+ }
34
+
35
+ async function runScript(script: string): Promise<string> {
36
+ const proc = Bun.spawn(["bun", "-e", script], {
37
+ env: { ...process.env, HOME: TEST_HOME },
38
+ cwd: PROJECT_ROOT,
39
+ stdout: "pipe",
40
+ stderr: "pipe",
41
+ });
42
+
43
+ const stdout = await new Response(proc.stdout).text();
44
+ const exitCode = await proc.exited;
45
+
46
+ if (exitCode !== 0) {
47
+ const stderr = await new Response(proc.stderr).text();
48
+ throw new Error(`Subprocess failed (exit ${exitCode}): ${stderr}`);
49
+ }
50
+
51
+ return stdout.trim();
52
+ }
53
+
54
+ describe("prompts integration (config from disk)", () => {
55
+ beforeEach(() => {
56
+ cleanTestHome();
57
+ mkdirSync(CONFIG_DIR, { recursive: true });
58
+ });
59
+ afterEach(cleanTestHome);
60
+
61
+ // ── Plan denied ──────────────────────────────────────────────────────
62
+
63
+ test("plan denied reads generic override from config.json", async () => {
64
+ writeConfig({
65
+ prompts: {
66
+ plan: {
67
+ denied: "NOPE.\n\n{{feedback}}",
68
+ },
69
+ },
70
+ });
71
+
72
+ const result = await runScript(`
73
+ import { getPlanDeniedPrompt } from "./packages/shared/prompts";
74
+ console.log(getPlanDeniedPrompt("claude-code", undefined, {
75
+ toolName: "ExitPlanMode",
76
+ planFileRule: "",
77
+ feedback: "Fix the auth",
78
+ }));
79
+ `);
80
+
81
+ expect(result).toBe("NOPE.\n\nFix the auth");
82
+ expect(result).not.toContain("YOUR PLAN WAS NOT APPROVED");
83
+ });
84
+
85
+ test("plan denied reads runtime-specific override from config.json", async () => {
86
+ writeConfig({
87
+ prompts: {
88
+ plan: {
89
+ denied: "Generic: {{feedback}}",
90
+ runtimes: {
91
+ opencode: { denied: "OpenCode: {{feedback}}" },
92
+ },
93
+ },
94
+ },
95
+ });
96
+
97
+ const oc = await runScript(`
98
+ import { getPlanDeniedPrompt, getPlanToolName } from "./packages/shared/prompts";
99
+ console.log(getPlanDeniedPrompt("opencode", undefined, {
100
+ toolName: getPlanToolName("opencode"),
101
+ planFileRule: "",
102
+ feedback: "Fix it",
103
+ }));
104
+ `);
105
+ expect(oc).toBe("OpenCode: Fix it");
106
+
107
+ const cc = await runScript(`
108
+ import { getPlanDeniedPrompt, getPlanToolName } from "./packages/shared/prompts";
109
+ console.log(getPlanDeniedPrompt("claude-code", undefined, {
110
+ toolName: getPlanToolName("claude-code"),
111
+ planFileRule: "",
112
+ feedback: "Fix it",
113
+ }));
114
+ `);
115
+ expect(cc).toBe("Generic: Fix it");
116
+ });
117
+
118
+ test("plan denied falls back to hardcoded default when config.json missing", async () => {
119
+ // No config file written — CONFIG_DIR exists but no config.json
120
+ rmSync(CONFIG_PATH, { force: true });
121
+
122
+ const result = await runScript(`
123
+ import { getPlanDeniedPrompt } from "./packages/shared/prompts";
124
+ console.log(getPlanDeniedPrompt("claude-code", undefined, {
125
+ toolName: "ExitPlanMode",
126
+ planFileRule: "",
127
+ feedback: "Some feedback",
128
+ }));
129
+ `);
130
+
131
+ expect(result).toContain("YOUR PLAN WAS NOT APPROVED");
132
+ expect(result).toContain("Some feedback");
133
+ });
134
+
135
+ test("plan denied falls through blank config values to default", async () => {
136
+ writeConfig({
137
+ prompts: {
138
+ plan: {
139
+ denied: " ",
140
+ runtimes: { "claude-code": { denied: "" } },
141
+ },
142
+ },
143
+ });
144
+
145
+ const result = await runScript(`
146
+ import { getPlanDeniedPrompt } from "./packages/shared/prompts";
147
+ console.log(getPlanDeniedPrompt("claude-code", undefined, {
148
+ toolName: "ExitPlanMode",
149
+ planFileRule: "",
150
+ feedback: "fb",
151
+ }));
152
+ `);
153
+
154
+ expect(result).toContain("YOUR PLAN WAS NOT APPROVED");
155
+ });
156
+
157
+ // ── Plan approved ────────────────────────────────────────────────────
158
+
159
+ test("plan approved reads override from config.json", async () => {
160
+ writeConfig({
161
+ prompts: {
162
+ plan: {
163
+ approved: "Go build it.",
164
+ },
165
+ },
166
+ });
167
+
168
+ const result = await runScript(`
169
+ import { getPlanApprovedPrompt } from "./packages/shared/prompts";
170
+ console.log(getPlanApprovedPrompt("pi"));
171
+ `);
172
+
173
+ expect(result).toBe("Go build it.");
174
+ expect(result).not.toContain("full tool access");
175
+ });
176
+
177
+ test("plan approved uses runtime built-in default when no config", async () => {
178
+ // No config — opencode should get its built-in "Plan approved!{{doneMsg}}"
179
+ const oc = await runScript(`
180
+ import { getPlanApprovedPrompt } from "./packages/shared/prompts";
181
+ console.log(getPlanApprovedPrompt("opencode", undefined, { doneMsg: " Done." }));
182
+ `);
183
+ expect(oc).toBe("Plan approved! Done.");
184
+
185
+ // Pi should get the verbose default
186
+ const pi = await runScript(`
187
+ import { getPlanApprovedPrompt } from "./packages/shared/prompts";
188
+ console.log(getPlanApprovedPrompt("pi", undefined, {
189
+ planFilePath: "plan.md", doneMsg: "",
190
+ }));
191
+ `);
192
+ expect(pi).toContain("full tool access");
193
+ expect(pi).toContain("plan.md");
194
+ });
195
+
196
+ // ── Plan approved with notes ─────────────────────────────────────────
197
+
198
+ test("plan approved with notes reads override from config.json", async () => {
199
+ writeConfig({
200
+ prompts: {
201
+ plan: {
202
+ approvedWithNotes: "Approved. User says: {{feedback}}",
203
+ },
204
+ },
205
+ });
206
+
207
+ const result = await runScript(`
208
+ import { getPlanApprovedWithNotesPrompt } from "./packages/shared/prompts";
209
+ console.log(getPlanApprovedWithNotesPrompt("pi", undefined, {
210
+ feedback: "Watch the edge case",
211
+ }));
212
+ `);
213
+
214
+ expect(result).toBe("Approved. User says: Watch the edge case");
215
+ });
216
+
217
+ test("plan approved with notes uses opencode runtime default when no config", async () => {
218
+ const result = await runScript(`
219
+ import { getPlanApprovedWithNotesPrompt } from "./packages/shared/prompts";
220
+ console.log(getPlanApprovedWithNotesPrompt("opencode", undefined, {
221
+ doneMsg: "",
222
+ feedback: "Be careful",
223
+ }));
224
+ `);
225
+
226
+ expect(result).toContain("Plan approved with notes!");
227
+ expect(result).toContain("Be careful");
228
+ expect(result).not.toContain("full tool access");
229
+ expect(result).not.toContain("Execute the plan in");
230
+ });
231
+
232
+ // ── Plan auto-approved ───────────────────────────────────────────────
233
+
234
+ test("plan auto-approved reads override from config.json", async () => {
235
+ writeConfig({
236
+ prompts: { plan: { autoApproved: "Auto-OK. Proceed." } },
237
+ });
238
+
239
+ const result = await runScript(`
240
+ import { getPlanAutoApprovedPrompt } from "./packages/shared/prompts";
241
+ console.log(getPlanAutoApprovedPrompt("pi"));
242
+ `);
243
+
244
+ expect(result).toBe("Auto-OK. Proceed.");
245
+ });
246
+
247
+ // ── Annotate file feedback ───────────────────────────────────────────
248
+
249
+ test("annotate file feedback reads override from config.json", async () => {
250
+ writeConfig({
251
+ prompts: {
252
+ annotate: {
253
+ fileFeedback: "# Notes\n\n{{filePath}}: {{feedback}}",
254
+ },
255
+ },
256
+ });
257
+
258
+ const result = await runScript(`
259
+ import { getAnnotateFileFeedbackPrompt } from "./packages/shared/prompts";
260
+ console.log(getAnnotateFileFeedbackPrompt("opencode", undefined, {
261
+ fileHeader: "File",
262
+ filePath: "src/app.ts",
263
+ feedback: "Fix line 10",
264
+ }));
265
+ `);
266
+
267
+ expect(result).toBe("# Notes\n\nsrc/app.ts: Fix line 10");
268
+ });
269
+
270
+ test("annotate file feedback reads runtime-specific override", async () => {
271
+ writeConfig({
272
+ prompts: {
273
+ annotate: {
274
+ fileFeedback: "Generic: {{feedback}}",
275
+ runtimes: {
276
+ pi: { fileFeedback: "Pi: {{filePath}} — {{feedback}}" },
277
+ },
278
+ },
279
+ },
280
+ });
281
+
282
+ const pi = await runScript(`
283
+ import { getAnnotateFileFeedbackPrompt } from "./packages/shared/prompts";
284
+ console.log(getAnnotateFileFeedbackPrompt("pi", undefined, {
285
+ fileHeader: "File", filePath: "x.ts", feedback: "fix",
286
+ }));
287
+ `);
288
+ expect(pi).toBe("Pi: x.ts — fix");
289
+
290
+ const oc = await runScript(`
291
+ import { getAnnotateFileFeedbackPrompt } from "./packages/shared/prompts";
292
+ console.log(getAnnotateFileFeedbackPrompt("opencode", undefined, {
293
+ fileHeader: "File", filePath: "x.ts", feedback: "fix",
294
+ }));
295
+ `);
296
+ expect(oc).toBe("Generic: fix");
297
+ });
298
+
299
+ // ── Annotate message feedback ────────────────────────────────────────
300
+
301
+ test("annotate message feedback reads override from config.json", async () => {
302
+ writeConfig({
303
+ prompts: {
304
+ annotate: {
305
+ messageFeedback: "Message review:\n\n{{feedback}}",
306
+ },
307
+ },
308
+ });
309
+
310
+ const result = await runScript(`
311
+ import { getAnnotateMessageFeedbackPrompt } from "./packages/shared/prompts";
312
+ console.log(getAnnotateMessageFeedbackPrompt("pi", undefined, {
313
+ feedback: "Wrong output",
314
+ }));
315
+ `);
316
+
317
+ expect(result).toBe("Message review:\n\nWrong output");
318
+ });
319
+
320
+ // ── Annotate approved ────────────────────────────────────────────────
321
+
322
+ test("annotate approved reads override from config.json", async () => {
323
+ writeConfig({
324
+ prompts: { annotate: { approved: "LGTM" } },
325
+ });
326
+
327
+ const result = await runScript(`
328
+ import { getAnnotateApprovedPrompt } from "./packages/shared/prompts";
329
+ console.log(getAnnotateApprovedPrompt("claude-code"));
330
+ `);
331
+
332
+ expect(result).toBe("LGTM");
333
+ });
334
+
335
+ // ── Review denied suffix ─────────────────────────────────────────────
336
+
337
+ test("review denied suffix reads override from config.json", async () => {
338
+ writeConfig({
339
+ prompts: { review: { denied: "\n\nFix everything now." } },
340
+ });
341
+
342
+ const result = await runScript(`
343
+ import { getReviewDeniedSuffix } from "./packages/shared/prompts";
344
+ console.log(JSON.stringify(getReviewDeniedSuffix("claude-code")));
345
+ `);
346
+
347
+ expect(JSON.parse(result)).toBe("\n\nFix everything now.");
348
+ });
349
+
350
+ // ── Cross-section isolation ──────────────────────────────────────────
351
+
352
+ test("config sections don't bleed into each other", async () => {
353
+ writeConfig({
354
+ prompts: {
355
+ plan: { denied: "Custom plan denial: {{feedback}}" },
356
+ annotate: { approved: "Custom annotate approved" },
357
+ },
358
+ });
359
+
360
+ // Plan denied should use custom
361
+ const planDenied = await runScript(`
362
+ import { getPlanDeniedPrompt } from "./packages/shared/prompts";
363
+ console.log(getPlanDeniedPrompt("claude-code", undefined, {
364
+ toolName: "ExitPlanMode", planFileRule: "", feedback: "fb",
365
+ }));
366
+ `);
367
+ expect(planDenied).toBe("Custom plan denial: fb");
368
+
369
+ // Annotate approved should use custom
370
+ const annotateApproved = await runScript(`
371
+ import { getAnnotateApprovedPrompt } from "./packages/shared/prompts";
372
+ console.log(getAnnotateApprovedPrompt("claude-code"));
373
+ `);
374
+ expect(annotateApproved).toBe("Custom annotate approved");
375
+
376
+ // Plan approved should still be the default (not set in config)
377
+ const planApproved = await runScript(`
378
+ import { getPlanApprovedPrompt } from "./packages/shared/prompts";
379
+ console.log(getPlanApprovedPrompt("pi", undefined, {
380
+ planFilePath: "p.md", doneMsg: "",
381
+ }));
382
+ `);
383
+ expect(planApproved).toContain("full tool access");
384
+ });
385
+
386
+ // ── Malformed config resilience ──────────────────────────────────────
387
+
388
+ test("malformed config.json falls back to defaults gracefully", async () => {
389
+ writeFileSync(CONFIG_PATH, "not valid json {{{");
390
+
391
+ const result = await runScript(`
392
+ import { getPlanDeniedPrompt } from "./packages/shared/prompts";
393
+ console.log(getPlanDeniedPrompt("claude-code", undefined, {
394
+ toolName: "ExitPlanMode", planFileRule: "", feedback: "fb",
395
+ }));
396
+ `);
397
+
398
+ expect(result).toContain("YOUR PLAN WAS NOT APPROVED");
399
+ });
400
+
401
+ // ── planDenyFeedback is browser-safe (no Node imports) ────────────────
402
+
403
+ test("planDenyFeedback() always uses hardcoded default (not config)", async () => {
404
+ writeConfig({
405
+ prompts: {
406
+ plan: { denied: "CUSTOM.\n\n{{feedback}}" },
407
+ },
408
+ });
409
+
410
+ const result = await runScript(`
411
+ import { planDenyFeedback } from "./packages/shared/feedback-templates";
412
+ console.log(planDenyFeedback("Fix auth", "ExitPlanMode"));
413
+ `);
414
+
415
+ // planDenyFeedback is self-contained — it does NOT read config.json.
416
+ // This is intentional: it's imported by the browser SPA bundle, which
417
+ // cannot access Node APIs. Config-aware denials use getPlanDeniedPrompt().
418
+ expect(result).toContain("YOUR PLAN WAS NOT APPROVED");
419
+ expect(result).toContain("Fix auth");
420
+ });
421
+ });