codebyplan 1.13.65 → 1.13.67

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 (300) hide show
  1. package/README.md +118 -75
  2. package/dist/__tests__/helpers.d.ts +22 -0
  3. package/dist/__tests__/helpers.d.ts.map +1 -0
  4. package/dist/ci-public.d.ts +20 -0
  5. package/dist/ci-public.d.ts.map +1 -0
  6. package/dist/ci.js +11 -2
  7. package/dist/cli/arch-map.d.ts +33 -0
  8. package/dist/cli/arch-map.d.ts.map +1 -0
  9. package/dist/cli/branch.d.ts +10 -0
  10. package/dist/cli/branch.d.ts.map +1 -0
  11. package/dist/cli/bump.d.ts +12 -0
  12. package/dist/cli/bump.d.ts.map +1 -0
  13. package/dist/cli/cd.d.ts +20 -0
  14. package/dist/cli/cd.d.ts.map +1 -0
  15. package/dist/cli/check.d.ts +30 -0
  16. package/dist/cli/check.d.ts.map +1 -0
  17. package/dist/cli/checkpoint.d.ts +17 -0
  18. package/dist/cli/checkpoint.d.ts.map +1 -0
  19. package/dist/cli/ci.d.ts +31 -0
  20. package/dist/cli/ci.d.ts.map +1 -0
  21. package/dist/cli/claude/__test-helpers__/expect-manifest.d.ts +7 -0
  22. package/dist/cli/claude/__test-helpers__/expect-manifest.d.ts.map +1 -0
  23. package/dist/cli/claude/__test-helpers__/tmp-fixture.d.ts +64 -0
  24. package/dist/cli/claude/__test-helpers__/tmp-fixture.d.ts.map +1 -0
  25. package/dist/cli/claude/audit-mode.d.ts +16 -0
  26. package/dist/cli/claude/audit-mode.d.ts.map +1 -0
  27. package/dist/cli/claude/generate.d.ts +23 -0
  28. package/dist/cli/claude/generate.d.ts.map +1 -0
  29. package/dist/cli/claude/install.d.ts +55 -0
  30. package/dist/cli/claude/install.d.ts.map +1 -0
  31. package/dist/cli/claude/migrate-memory.d.ts +117 -0
  32. package/dist/cli/claude/migrate-memory.d.ts.map +1 -0
  33. package/dist/cli/claude/readme.d.ts +28 -0
  34. package/dist/cli/claude/readme.d.ts.map +1 -0
  35. package/dist/cli/claude/status.d.ts +41 -0
  36. package/dist/cli/claude/status.d.ts.map +1 -0
  37. package/dist/cli/claude/uninstall.d.ts +21 -0
  38. package/dist/cli/claude/uninstall.d.ts.map +1 -0
  39. package/dist/cli/claude/update.d.ts +25 -0
  40. package/dist/cli/claude/update.d.ts.map +1 -0
  41. package/dist/cli/claude/verify-parity.d.ts +25 -0
  42. package/dist/cli/claude/verify-parity.d.ts.map +1 -0
  43. package/dist/cli/cleanup-plan-folders.d.ts +21 -0
  44. package/dist/cli/cleanup-plan-folders.d.ts.map +1 -0
  45. package/dist/cli/commit.d.ts +25 -0
  46. package/dist/cli/commit.d.ts.map +1 -0
  47. package/dist/cli/config.d.ts +50 -0
  48. package/dist/cli/config.d.ts.map +1 -0
  49. package/dist/cli/confirm.d.ts +9 -0
  50. package/dist/cli/confirm.d.ts.map +1 -0
  51. package/dist/cli/create-org.d.ts +9 -0
  52. package/dist/cli/create-org.d.ts.map +1 -0
  53. package/dist/cli/create-project.d.ts +10 -0
  54. package/dist/cli/create-project.d.ts.map +1 -0
  55. package/dist/cli/create-repo.d.ts +14 -0
  56. package/dist/cli/create-repo.d.ts.map +1 -0
  57. package/dist/cli/docs.d.ts +41 -0
  58. package/dist/cli/docs.d.ts.map +1 -0
  59. package/dist/cli/doctor.d.ts +17 -0
  60. package/dist/cli/doctor.d.ts.map +1 -0
  61. package/dist/cli/e2e/verify-round.d.ts +46 -0
  62. package/dist/cli/e2e/verify-round.d.ts.map +1 -0
  63. package/dist/cli/e2e.d.ts +11 -0
  64. package/dist/cli/e2e.d.ts.map +1 -0
  65. package/dist/cli/eslint.d.ts +20 -0
  66. package/dist/cli/eslint.d.ts.map +1 -0
  67. package/dist/cli/export-writer.d.ts +99 -0
  68. package/dist/cli/export-writer.d.ts.map +1 -0
  69. package/dist/cli/handoff.d.ts +13 -0
  70. package/dist/cli/handoff.d.ts.map +1 -0
  71. package/dist/cli/login.d.ts +10 -0
  72. package/dist/cli/login.d.ts.map +1 -0
  73. package/dist/cli/logout.d.ts +2 -0
  74. package/dist/cli/logout.d.ts.map +1 -0
  75. package/dist/cli/lsp.d.ts +16 -0
  76. package/dist/cli/lsp.d.ts.map +1 -0
  77. package/dist/cli/migration-collisions.d.ts +10 -0
  78. package/dist/cli/migration-collisions.d.ts.map +1 -0
  79. package/dist/cli/ports.d.ts +29 -0
  80. package/dist/cli/ports.d.ts.map +1 -0
  81. package/dist/cli/process-exit-signal.d.ts +24 -0
  82. package/dist/cli/process-exit-signal.d.ts.map +1 -0
  83. package/dist/cli/round.d.ts +79 -0
  84. package/dist/cli/round.d.ts.map +1 -0
  85. package/dist/cli/scaffold-publish-workflow.d.ts +16 -0
  86. package/dist/cli/scaffold-publish-workflow.d.ts.map +1 -0
  87. package/dist/cli/session/freshness-gate.d.ts +21 -0
  88. package/dist/cli/session/freshness-gate.d.ts.map +1 -0
  89. package/dist/cli/session/home-ff.d.ts +16 -0
  90. package/dist/cli/session/home-ff.d.ts.map +1 -0
  91. package/dist/cli/session/infra-files.d.ts +21 -0
  92. package/dist/cli/session/infra-files.d.ts.map +1 -0
  93. package/dist/cli/session/start.d.ts +70 -0
  94. package/dist/cli/session/start.d.ts.map +1 -0
  95. package/dist/cli/session.d.ts +17 -0
  96. package/dist/cli/session.d.ts.map +1 -0
  97. package/dist/cli/setup.d.ts +2 -0
  98. package/dist/cli/setup.d.ts.map +1 -0
  99. package/dist/cli/ship.d.ts +16 -0
  100. package/dist/cli/ship.d.ts.map +1 -0
  101. package/dist/cli/slug.d.ts +10 -0
  102. package/dist/cli/slug.d.ts.map +1 -0
  103. package/dist/cli/standalone-task.d.ts +31 -0
  104. package/dist/cli/standalone-task.d.ts.map +1 -0
  105. package/dist/cli/statusline.d.ts +10 -0
  106. package/dist/cli/statusline.d.ts.map +1 -0
  107. package/dist/cli/supabase/new-migration.d.ts +24 -0
  108. package/dist/cli/supabase/new-migration.d.ts.map +1 -0
  109. package/dist/cli/supabase/preview-check.d.ts +30 -0
  110. package/dist/cli/supabase/preview-check.d.ts.map +1 -0
  111. package/dist/cli/supabase/resolve-preview.d.ts +19 -0
  112. package/dist/cli/supabase/resolve-preview.d.ts.map +1 -0
  113. package/dist/cli/supabase/teardown-preview.d.ts +22 -0
  114. package/dist/cli/supabase/teardown-preview.d.ts.map +1 -0
  115. package/dist/cli/sync.d.ts +13 -0
  116. package/dist/cli/sync.d.ts.map +1 -0
  117. package/dist/cli/task.d.ts +17 -0
  118. package/dist/cli/task.d.ts.map +1 -0
  119. package/dist/cli/tech-stack.d.ts +11 -0
  120. package/dist/cli/tech-stack.d.ts.map +1 -0
  121. package/dist/cli/upgrade-auth.d.ts +2 -0
  122. package/dist/cli/upgrade-auth.d.ts.map +1 -0
  123. package/dist/cli/upload-e2e-images.d.ts +18 -0
  124. package/dist/cli/upload-e2e-images.d.ts.map +1 -0
  125. package/dist/cli/validate-waves.d.ts +22 -0
  126. package/dist/cli/validate-waves.d.ts.map +1 -0
  127. package/dist/cli/version-status.d.ts +42 -0
  128. package/dist/cli/version-status.d.ts.map +1 -0
  129. package/dist/cli/watch.d.ts +18 -0
  130. package/dist/cli/watch.d.ts.map +1 -0
  131. package/dist/cli/whoami.d.ts +5 -0
  132. package/dist/cli/whoami.d.ts.map +1 -0
  133. package/dist/cli/worktree/add.d.ts +81 -0
  134. package/dist/cli/worktree/add.d.ts.map +1 -0
  135. package/dist/cli/worktree/create.d.ts +46 -0
  136. package/dist/cli/worktree/create.d.ts.map +1 -0
  137. package/dist/cli/worktree/path.d.ts +19 -0
  138. package/dist/cli/worktree/path.d.ts.map +1 -0
  139. package/dist/cli/worktree/remove.d.ts +92 -0
  140. package/dist/cli/worktree/remove.d.ts.map +1 -0
  141. package/dist/cli/worktree.d.ts +15 -0
  142. package/dist/cli/worktree.d.ts.map +1 -0
  143. package/dist/cli.js +5697 -5322
  144. package/dist/dispatch.d.ts +64 -0
  145. package/dist/dispatch.d.ts.map +1 -0
  146. package/dist/index.d.ts +2 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/lib/agents-generator.d.ts +42 -0
  149. package/dist/lib/agents-generator.d.ts.map +1 -0
  150. package/dist/lib/api.d.ts +54 -0
  151. package/dist/lib/api.d.ts.map +1 -0
  152. package/dist/lib/atomic-write.d.ts +27 -0
  153. package/dist/lib/atomic-write.d.ts.map +1 -0
  154. package/dist/lib/branch-checkout.d.ts +47 -0
  155. package/dist/lib/branch-checkout.d.ts.map +1 -0
  156. package/dist/lib/branch-port-resolver.d.ts +58 -0
  157. package/dist/lib/branch-port-resolver.d.ts.map +1 -0
  158. package/dist/lib/bump.d.ts +97 -0
  159. package/dist/lib/bump.d.ts.map +1 -0
  160. package/dist/lib/cd-init.d.ts +86 -0
  161. package/dist/lib/cd-init.d.ts.map +1 -0
  162. package/dist/lib/check-baseline.d.ts +91 -0
  163. package/dist/lib/check-baseline.d.ts.map +1 -0
  164. package/dist/lib/check.d.ts +178 -0
  165. package/dist/lib/check.d.ts.map +1 -0
  166. package/dist/lib/ci-init.d.ts +106 -0
  167. package/dist/lib/ci-init.d.ts.map +1 -0
  168. package/dist/lib/ci-resolve.d.ts +60 -0
  169. package/dist/lib/ci-resolve.d.ts.map +1 -0
  170. package/dist/lib/claude-mode-audit.d.ts +41 -0
  171. package/dist/lib/claude-mode-audit.d.ts.map +1 -0
  172. package/dist/lib/claude-plan.d.ts +34 -0
  173. package/dist/lib/claude-plan.d.ts.map +1 -0
  174. package/dist/lib/commit-scope.d.ts +21 -0
  175. package/dist/lib/commit-scope.d.ts.map +1 -0
  176. package/dist/lib/e2e.d.ts +157 -0
  177. package/dist/lib/e2e.d.ts.map +1 -0
  178. package/dist/lib/eslint-generator.d.ts +86 -0
  179. package/dist/lib/eslint-generator.d.ts.map +1 -0
  180. package/dist/lib/file-lock.d.ts +44 -0
  181. package/dist/lib/file-lock.d.ts.map +1 -0
  182. package/dist/lib/flags.d.ts +115 -0
  183. package/dist/lib/flags.d.ts.map +1 -0
  184. package/dist/lib/gh-required-checks.d.ts +76 -0
  185. package/dist/lib/gh-required-checks.d.ts.map +1 -0
  186. package/dist/lib/git-utils.d.ts +46 -0
  187. package/dist/lib/git-utils.d.ts.map +1 -0
  188. package/dist/lib/gitignore-block.d.ts +32 -0
  189. package/dist/lib/gitignore-block.d.ts.map +1 -0
  190. package/dist/lib/gitignore-detect.d.ts +117 -0
  191. package/dist/lib/gitignore-detect.d.ts.map +1 -0
  192. package/dist/lib/handoff-file.d.ts +63 -0
  193. package/dist/lib/handoff-file.d.ts.map +1 -0
  194. package/dist/lib/hash.d.ts +9 -0
  195. package/dist/lib/hash.d.ts.map +1 -0
  196. package/dist/lib/lsp-detect.d.ts +42 -0
  197. package/dist/lib/lsp-detect.d.ts.map +1 -0
  198. package/dist/lib/manifest.d.ts +88 -0
  199. package/dist/lib/manifest.d.ts.map +1 -0
  200. package/dist/lib/mcp-client.d.ts +39 -0
  201. package/dist/lib/mcp-client.d.ts.map +1 -0
  202. package/dist/lib/migrate-branch-model.d.ts +34 -0
  203. package/dist/lib/migrate-branch-model.d.ts.map +1 -0
  204. package/dist/lib/migrate-local-config.d.ts +39 -0
  205. package/dist/lib/migrate-local-config.d.ts.map +1 -0
  206. package/dist/lib/migration-collisions.d.ts +61 -0
  207. package/dist/lib/migration-collisions.d.ts.map +1 -0
  208. package/dist/lib/port-verify.d.ts +73 -0
  209. package/dist/lib/port-verify.d.ts.map +1 -0
  210. package/dist/lib/prompt.d.ts +41 -0
  211. package/dist/lib/prompt.d.ts.map +1 -0
  212. package/dist/lib/readme-generator.d.ts +108 -0
  213. package/dist/lib/readme-generator.d.ts.map +1 -0
  214. package/dist/lib/repo-reader.d.ts +59 -0
  215. package/dist/lib/repo-reader.d.ts.map +1 -0
  216. package/dist/lib/scaffold-cd-workflow.d.ts +48 -0
  217. package/dist/lib/scaffold-cd-workflow.d.ts.map +1 -0
  218. package/dist/lib/scaffold-ci-workflow.d.ts +83 -0
  219. package/dist/lib/scaffold-ci-workflow.d.ts.map +1 -0
  220. package/dist/lib/scaffold-publish-workflow.d.ts +48 -0
  221. package/dist/lib/scaffold-publish-workflow.d.ts.map +1 -0
  222. package/dist/lib/server-detect.d.ts +20 -0
  223. package/dist/lib/server-detect.d.ts.map +1 -0
  224. package/dist/lib/session.d.ts +371 -0
  225. package/dist/lib/session.d.ts.map +1 -0
  226. package/dist/lib/settings-merge.d.ts +268 -0
  227. package/dist/lib/settings-merge.d.ts.map +1 -0
  228. package/dist/lib/ship.d.ts +84 -0
  229. package/dist/lib/ship.d.ts.map +1 -0
  230. package/dist/lib/slug.d.ts +26 -0
  231. package/dist/lib/slug.d.ts.map +1 -0
  232. package/dist/lib/spawn.d.ts +12 -0
  233. package/dist/lib/spawn.d.ts.map +1 -0
  234. package/dist/lib/state-client.d.ts +54 -0
  235. package/dist/lib/state-client.d.ts.map +1 -0
  236. package/dist/lib/state-store.d.ts +153 -0
  237. package/dist/lib/state-store.d.ts.map +1 -0
  238. package/dist/lib/state-sync.d.ts +101 -0
  239. package/dist/lib/state-sync.d.ts.map +1 -0
  240. package/dist/lib/statusline-config.d.ts +55 -0
  241. package/dist/lib/statusline-config.d.ts.map +1 -0
  242. package/dist/lib/structure-generator.d.ts +63 -0
  243. package/dist/lib/structure-generator.d.ts.map +1 -0
  244. package/dist/lib/supabase.d.ts +87 -0
  245. package/dist/lib/supabase.d.ts.map +1 -0
  246. package/dist/lib/sync-approvals.d.ts +108 -0
  247. package/dist/lib/sync-approvals.d.ts.map +1 -0
  248. package/dist/lib/tech-detect.d.ts +77 -0
  249. package/dist/lib/tech-detect.d.ts.map +1 -0
  250. package/dist/lib/template-walker.d.ts +26 -0
  251. package/dist/lib/template-walker.d.ts.map +1 -0
  252. package/dist/lib/templates-dir.d.ts +25 -0
  253. package/dist/lib/templates-dir.d.ts.map +1 -0
  254. package/dist/lib/types.d.ts +843 -0
  255. package/dist/lib/types.d.ts.map +1 -0
  256. package/dist/lib/validate-waves.d.ts +38 -0
  257. package/dist/lib/validate-waves.d.ts.map +1 -0
  258. package/dist/lib/verify-parity.d.ts +154 -0
  259. package/dist/lib/verify-parity.d.ts.map +1 -0
  260. package/dist/lib/version.d.ts +3 -0
  261. package/dist/lib/version.d.ts.map +1 -0
  262. package/dist/lib/watch-daemon.d.ts +114 -0
  263. package/dist/lib/watch-daemon.d.ts.map +1 -0
  264. package/dist/lib/worktree.d.ts +56 -0
  265. package/dist/lib/worktree.d.ts.map +1 -0
  266. package/dist/oauth/browser.d.ts +8 -0
  267. package/dist/oauth/browser.d.ts.map +1 -0
  268. package/dist/oauth/client-registration.d.ts +16 -0
  269. package/dist/oauth/client-registration.d.ts.map +1 -0
  270. package/dist/oauth/device-flow.d.ts +40 -0
  271. package/dist/oauth/device-flow.d.ts.map +1 -0
  272. package/dist/oauth/jwt-decode.d.ts +10 -0
  273. package/dist/oauth/jwt-decode.d.ts.map +1 -0
  274. package/dist/oauth/keychain.d.ts +17 -0
  275. package/dist/oauth/keychain.d.ts.map +1 -0
  276. package/dist/oauth/token-refresh.d.ts +7 -0
  277. package/dist/oauth/token-refresh.d.ts.map +1 -0
  278. package/dist/oauth/types.d.ts +28 -0
  279. package/dist/oauth/types.d.ts.map +1 -0
  280. package/dist/oauth/urls.d.ts +16 -0
  281. package/dist/oauth/urls.d.ts.map +1 -0
  282. package/package.json +5 -6
  283. package/templates/agents/cbp-security-agent.md +0 -1
  284. package/templates/agents/cbp-stripe-agent.md +0 -1
  285. package/templates/agents/cbp-testing-qa-agent.md +0 -1
  286. package/templates/hooks/cbp-skill-context-guard.sh +0 -1
  287. package/templates/hooks/cbp-test-hooks.sh +0 -81
  288. package/templates/hooks/validate-structure-lib.sh +36 -9
  289. package/templates/rules/cbp-operating-gotchas.md +8 -10
  290. package/templates/rules/todo-backend.md +4 -2
  291. package/templates/skills/cbp-build-cc-settings/reference/cbp-permission-policy.md +3 -3
  292. package/templates/skills/cbp-checkpoint-check/SKILL.md +0 -1
  293. package/templates/skills/cbp-checkpoint-end/SKILL.md +11 -5
  294. package/templates/skills/cbp-clear-continue/SKILL.md +0 -1
  295. package/templates/skills/cbp-clear-prep/SKILL.md +0 -1
  296. package/templates/skills/cbp-finalize/SKILL.md +2 -2
  297. package/templates/skills/cbp-setup-cd/SKILL.md +0 -1
  298. package/templates/skills/cbp-setup-ci/SKILL.md +0 -1
  299. package/templates/skills/cbp-standalone-task-complete/SKILL.md +40 -0
  300. package/templates/skills/cbp-stripe/SKILL.md +0 -1
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Settings.json hook-merge engine.
3
+ *
4
+ * The source-of-truth is `templates/hooks/hooks.json` — the nested
5
+ * Claude Code spec shape (`hooks.<event>[].matcher`, each containing a
6
+ * `hooks[]` of `{type, command}` command-entries with no provenance fields).
7
+ *
8
+ * On install:
9
+ * - Walk every command-entry across every event/matcher block
10
+ * - Tag each entry with `_owner: "codebyplan-claude"` + a `_hook_id`
11
+ * derived from the script filename in the command string
12
+ * - Rewrite the `${CLAUDE_PLUGIN_ROOT}/hooks/<file>` placeholder to the
13
+ * repo-local `./.claude/hooks/<file>` path
14
+ * - Upsert into the user's `.claude/settings.json` by `_hook_id` within
15
+ * the SAME matcher block, preserving every non-owned entry byte-for-byte
16
+ *
17
+ * On uninstall: strip every entry whose `_owner === "codebyplan-claude"`,
18
+ * collapse now-empty matcher blocks and event arrays, drop a now-empty
19
+ * `hooks` key.
20
+ *
21
+ * Crucially, the SOURCE `hooks.json` is never mutated — placeholder rewrite
22
+ * and tagging happen at merge time on a structural clone of each command-entry.
23
+ */
24
+ export declare const OWNER = "codebyplan-claude";
25
+ /**
26
+ * Marks monorepo-internal hook registrations (e.g. cbp-canonical-templates-nudge.sh
27
+ * PreToolUse, verify-parity.sh SessionStart) that live ONLY in the canonical monorepo's
28
+ * .claude/settings.json and are intentionally absent from templates/hooks/hooks.json.
29
+ *
30
+ * Because stripOwnedHooksFromSettings strips `_owner === OWNER` and
31
+ * pruneMissingManagedHooks prunes `_owner === OWNER`, a distinct owner string is
32
+ * preserved through every managed-hook pass — so these internal registrations survive
33
+ * a strip+remerge cycle.
34
+ *
35
+ * Do NOT add INTERNAL_OWNER to any strip/prune allow-list — its distinctness IS the
36
+ * mechanism.
37
+ */
38
+ export declare const INTERNAL_OWNER = "codebyplan-monorepo-internal";
39
+ /**
40
+ * A single command-entry inside the nested Claude Code hook shape.
41
+ * Source entries (from templates/hooks/hooks.json) carry only `type` and
42
+ * `command`; entries written into settings.json by this merger ALSO carry
43
+ * `_owner` + `_hook_id` so uninstall can distinguish them from user-authored
44
+ * entries.
45
+ */
46
+ export interface InnerHookCommand {
47
+ _owner?: string;
48
+ _hook_id?: string;
49
+ type: string;
50
+ command: string;
51
+ [extra: string]: unknown;
52
+ }
53
+ export interface MatcherBlock {
54
+ /** Optional: absent for event-level hooks e.g. UserPromptSubmit */
55
+ matcher?: string;
56
+ hooks: InnerHookCommand[];
57
+ }
58
+ export type HooksByEvent = Record<string, MatcherBlock[]>;
59
+ /**
60
+ * Shape of a `statusLine` or `subagentStatusLine` entry. Both use the same
61
+ * structure — a command renderer invoked by Claude Code outside the hook
62
+ * lifecycle. Optional fields (`padding`, `refreshInterval`,
63
+ * `hideVimModeIndicator`) are preserved when present in user settings.
64
+ */
65
+ export interface StatusLineSetting {
66
+ type: string;
67
+ command: string;
68
+ padding?: number;
69
+ refreshInterval?: number;
70
+ hideVimModeIndicator?: boolean;
71
+ }
72
+ export interface Settings {
73
+ hooks?: HooksByEvent;
74
+ statusLine?: StatusLineSetting;
75
+ subagentStatusLine?: StatusLineSetting;
76
+ enabledPlugins?: Record<string, boolean>;
77
+ [otherKey: string]: unknown;
78
+ }
79
+ export interface HooksJson {
80
+ hooks: HooksByEvent;
81
+ }
82
+ /**
83
+ * Shape of `templates/settings.project.base.json` — the top-level (non-hooks)
84
+ * settings the package owns. Every field is optional so the template can grow
85
+ * without forcing churn in this type.
86
+ *
87
+ * Scope comments:
88
+ * // common — appears in settings.project.base.json AND available for user settings
89
+ * // project-only — appears in settings.project.base.json only (CBP project conventions)
90
+ * // user-only — NOT in settings.project.base.json; populated by user settings (e.g. TASK-3)
91
+ */
92
+ export interface BaseSettings {
93
+ alwaysThinkingEnabled?: boolean;
94
+ autoUpdatesChannel?: string;
95
+ awaySummaryEnabled?: boolean;
96
+ disableAgentView?: boolean;
97
+ editorMode?: string;
98
+ outputStyle?: string;
99
+ preferredNotifChannel?: string;
100
+ prefersReducedMotion?: boolean;
101
+ respectGitignore?: boolean;
102
+ showTurnDuration?: boolean;
103
+ spinnerTipsEnabled?: boolean;
104
+ terminalProgressBarEnabled?: boolean;
105
+ viewMode?: string;
106
+ worktree?: {
107
+ baseRef?: string;
108
+ [k: string]: unknown;
109
+ };
110
+ autoScrollEnabled?: boolean;
111
+ cleanupPeriodDays?: number;
112
+ includeGitInstructions?: boolean;
113
+ showThinkingSummaries?: boolean;
114
+ disableSkillShellExecution?: boolean;
115
+ skipWebFetchPreflight?: boolean;
116
+ fastModePerSessionOptIn?: boolean;
117
+ autoMemoryEnabled?: boolean;
118
+ effortLevel?: string;
119
+ statusLine?: StatusLineSetting;
120
+ subagentStatusLine?: StatusLineSetting;
121
+ permissions?: {
122
+ defaultMode?: string;
123
+ deny?: string[];
124
+ ask?: string[];
125
+ allow?: string[];
126
+ skipDangerousModePermissionPrompt?: boolean;
127
+ };
128
+ attribution?: {
129
+ commit?: string;
130
+ pr?: string;
131
+ };
132
+ showClearContextOnPlanAccept?: boolean;
133
+ syntaxHighlightingDisabled?: boolean;
134
+ }
135
+ /**
136
+ * Merge the hook entries from `hooksJson` into `settings.hooks`, tagging each
137
+ * with the codebyplan-claude owner marker and rewriting the path placeholder.
138
+ *
139
+ * Returns the same `settings` reference (mutated in place) for caller
140
+ * convenience. The source `hooksJson` is NOT mutated — each command-entry is
141
+ * cloned before being tagged.
142
+ *
143
+ * Upsert semantics: within a single matcher block (same event, same matcher
144
+ * string), entries are keyed by `_hook_id`. An owned entry with a matching
145
+ * `_hook_id` is replaced in place (preserving its index); otherwise the new
146
+ * owned entry is appended. Non-owned entries (`_owner !== OWNER`) are NEVER
147
+ * touched — they stay at their original index.
148
+ */
149
+ export declare function mergeHooksIntoSettings(settings: Settings, hooksJson: HooksJson): Settings;
150
+ /**
151
+ * Merge top-level non-hook settings from `base` into `settings`. Semantics are
152
+ * conservative — the install must never clobber a user-customised value:
153
+ *
154
+ * - Scalar fields (21 scalar-common + 3 project-only) in SCALAR_BASE_KEYS: set
155
+ * only if absent. `worktree` is the 22nd common field and is handled
156
+ * separately below via per-sub-key filling.
157
+ * - `statusLine`: set only if absent (object, deep-set as a unit)
158
+ * - `subagentStatusLine`: set only if absent (object, deep-set as a unit)
159
+ * - `attribution`: set only if absent (object, deep-set as a unit)
160
+ * - `worktree`: if absent, deep-clone base.worktree; if present, fill each
161
+ * sub-key individually iff absent in settings.worktree
162
+ * - `permissions.defaultMode`: set only if absent
163
+ * - `permissions.skipDangerousModePermissionPrompt`: set only if absent
164
+ * - `permissions.deny` / `permissions.ask` / `permissions.allow`: cross-tier
165
+ * reconciliation followed by union (see scoped exception below).
166
+ *
167
+ * Cross-tier reconciliation (scoped exception to the otherwise union-only contract):
168
+ * Before the union loop, a map is built from every entry in base.permissions.*
169
+ * to its canonical tier. Any entry in the user's existing array that appears
170
+ * in the map AND is sitting in the WRONG tier is removed from that array. The
171
+ * subsequent union loop then places it in the correct (canonical) tier. This
172
+ * enables both promotion (allow→ask) and demotion (ask→allow) for base-owned
173
+ * entries. The removal is STRICTLY SCOPED: entries that are NOT present in any
174
+ * base array (user-authored entries and legacy specifics such as
175
+ * `Bash(git add .:*)` / `Bash(git add -A:*)`) are NEVER removed — the
176
+ * union-only behavior is preserved for all non-base entries.
177
+ *
178
+ * Returns the same `settings` reference (mutated in place). Source `base` is
179
+ * NOT mutated — each StatusLineSetting is shallow-cloned before assignment,
180
+ * and the `permissions.deny` / `ask` / `allow` arrays are read-only iterated
181
+ * into a fresh `merged` array (never pushed into), so later mutations to
182
+ * `settings.statusLine` / `settings.subagentStatusLine` / `settings.permissions.*`
183
+ * do not bleed back into the template. Mirrors the clone-source guarantee
184
+ * documented on `mergeHooksIntoSettings`.
185
+ */
186
+ export declare function mergeBaseSettingsIntoSettings(settings: Settings, base: BaseSettings): Settings;
187
+ /**
188
+ * Strip package-owned top-level settings from `settings`, given the same `base`
189
+ * template the installer merged in. Conservative — only removes a field when
190
+ * it byte-equals the package default, so any user customisation is preserved:
191
+ *
192
+ * - Scalar fields (21 scalar-common + 3 project-only) in SCALAR_BASE_KEYS:
193
+ * deleted iff byte-equal to base value. `worktree` is the 22nd common field
194
+ * and is handled separately below.
195
+ * - `statusLine`: deleted iff deep-equal to `base.statusLine`
196
+ * - `subagentStatusLine`: deleted iff deep-equal to `base.subagentStatusLine`
197
+ * - `attribution`: deleted iff deep-equal to `base.attribution`
198
+ * - `worktree`: each sub-key deleted iff equal to base sub-key; if worktree
199
+ * becomes `{}` the key itself is deleted
200
+ * - `permissions.defaultMode`: deleted iff equal to `base.permissions.defaultMode`
201
+ * - `permissions.skipDangerousModePermissionPrompt`: deleted iff byte-equal
202
+ * - `permissions.deny` / `permissions.ask` / `permissions.allow`: cross-tier
203
+ * strip — every base-owned entry (present in ANY base array) is filtered out
204
+ * of EVERY consumer array, regardless of which tier it currently sits in, so
205
+ * a base entry that drifted into the wrong tier is still removed on uninstall
206
+ * (mirrors the cross-tier reconciliation in mergeBaseSettingsIntoSettings).
207
+ * User-added entries (absent from all base arrays) are preserved. An empty
208
+ * array post-filter is dropped entirely.
209
+ * - `permissions`: dropped entirely once it has no remaining keys.
210
+ *
211
+ * Returns the same `settings` reference (mutated in place).
212
+ */
213
+ export declare function stripBaseSettingsFromSettings(settings: Settings, base: BaseSettings): Settings;
214
+ /**
215
+ * Merge LSP plugin IDs into `settings.enabledPlugins`.
216
+ *
217
+ * For each plugin id in `plugins`, computes the settings key as
218
+ * `${plugin}@claude-plugins-official` and sets it to `true` ONLY when the key
219
+ * is absent from settings.enabledPlugins. Existing entries (true OR false) are
220
+ * never clobbered — a user who explicitly disabled a plugin (false) keeps that.
221
+ *
222
+ * Initializes `settings.enabledPlugins` to `{}` if undefined.
223
+ *
224
+ * NOTE: the uninstall strip path in `stripBaseSettingsFromSettings` does NOT
225
+ * touch `enabledPlugins` — LSP entries are intentionally left in place after
226
+ * uninstall. The user opted in by running `codebyplan lsp`; stripping the
227
+ * plugins on uninstall would silently degrade their editor experience.
228
+ *
229
+ * Returns the same `settings` reference (mutated in place).
230
+ */
231
+ export declare function mergeEnabledPluginsIntoSettings(settings: Settings, plugins: string[]): Settings;
232
+ /**
233
+ * Strip every command-entry whose `_owner === OWNER` from `settings.hooks`.
234
+ * Empty matcher blocks, empty event arrays, and a now-empty `hooks` object
235
+ * are pruned so the resulting settings.json is shaped like an unmodified
236
+ * user-only file.
237
+ *
238
+ * Returns the same `settings` reference (mutated in place).
239
+ */
240
+ export declare function stripOwnedHooksFromSettings(settings: Settings): Settings;
241
+ /**
242
+ * Remove managed hook entries whose `_hook_id` is no longer present in the
243
+ * current `hooksJson` template. Called immediately after `mergeHooksIntoSettings`
244
+ * on install and update so that hooks removed from the package template do not
245
+ * persist forever in consuming repos' settings.json.
246
+ *
247
+ * Semantics:
248
+ * - Builds a per-event map of live `_hook_id` values by iterating every
249
+ * event/matcher/command in `hooksJson` using the same `extractHookId`
250
+ * the merge uses. Per-event keying ensures a hook id that moved from
251
+ * one event to another is correctly pruned from the OLD event.
252
+ * - In each event/matcher block, removes an entry ONLY when ALL of these
253
+ * hold: `e._owner === OWNER`, `e._hook_id !== undefined`, and the id is
254
+ * NOT in the per-event live set (events absent from the template get an
255
+ * empty set, so all their owned entries are pruned).
256
+ * - Calls `onPruned(hookId)` for each removed entry (optional callback —
257
+ * used for verbose logging in install/update callers).
258
+ * - Collapses now-empty blocks and event keys via `collapseEmptyHookBlocks`.
259
+ *
260
+ * Guarantees:
261
+ * - NEVER removes a non-owned entry or an owned entry with undefined `_hook_id`.
262
+ * - NEVER mutates `hooksJson`.
263
+ * - Idempotent: a second call with the same arguments produces no further changes.
264
+ *
265
+ * Returns the same `settings` reference (mutated in place).
266
+ */
267
+ export declare function pruneMissingManagedHooks(settings: Settings, hooksJson: HooksJson, onPruned?: (hookId: string) => void): Settings;
268
+ //# sourceMappingURL=settings-merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-merge.d.ts","sourceRoot":"","sources":["../../src/lib/settings-merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Pure library: ship a feat branch to production via PR.
3
+ *
4
+ * Reads branch_config from .codebyplan/git.json to determine the base/production
5
+ * branch. Handles all git/gh mechanics: push, PR create-or-reuse, checks poll,
6
+ * merge, verify, cleanup.
7
+ *
8
+ * dryRun: true short-circuits BEFORE any mutating call (no push/create/merge/delete).
9
+ * Read-only operations (fetch, pr list, pr checks) may still run in dry-run for
10
+ * representative output.
11
+ */
12
+ import { type BumpEntry } from "./bump.js";
13
+ export type ShipOptions = {
14
+ /** Skip all mutating operations; return a representative dry-run result. */
15
+ dryRun?: boolean;
16
+ /** Write JSON to stdout. */
17
+ json?: boolean;
18
+ /** Do not delete the feat branch after merge. */
19
+ keepFeat?: boolean;
20
+ /**
21
+ * Path to a file containing the PR body markdown.
22
+ * If omitted, a default body is generated from the branch name.
23
+ */
24
+ bodyFile?: string;
25
+ /**
26
+ * Maximum seconds to poll gh pr checks before aborting. Default: 600.
27
+ */
28
+ timeoutSeconds?: number;
29
+ /** Override cwd for testing. */
30
+ cwd?: string;
31
+ /**
32
+ * Injectable sleep function for testing (avoids real timer waits).
33
+ * Defaults to real setTimeout-based sleep in production.
34
+ * @internal
35
+ */
36
+ _sleepMs?: (ms: number) => Promise<void>;
37
+ /** Patch-bump changed packages before push. Default: true. */
38
+ bump?: boolean;
39
+ };
40
+ export type ShipResult = {
41
+ pr_url: string;
42
+ merge_commit: string | null;
43
+ branch_deleted: boolean;
44
+ /** Present when dryRun=true. */
45
+ dry_run?: boolean;
46
+ /** Present when required checks failed. */
47
+ checks_failed?: boolean;
48
+ checks_failure_reason?: string;
49
+ feat_branch?: string;
50
+ base_branch?: string;
51
+ /** Bump entries from runBump (present when bump was attempted). */
52
+ bumps?: BumpEntry[];
53
+ };
54
+ type CheckEntry = {
55
+ name: string;
56
+ state: string;
57
+ bucket: string;
58
+ };
59
+ /**
60
+ * Evaluate a set of gh pr checks entries using the gh bucket model.
61
+ *
62
+ * gh pr checks returns a `bucket` field per check with one of:
63
+ * pass | fail | pending | skipping | cancel
64
+ *
65
+ * Decision table (fail-safe):
66
+ * - fail / cancel → block merge (returned in `failed[]`)
67
+ * - pass / skipping → do NOT block (treated as passing)
68
+ * - pending → wait for completion
69
+ * - unknown / unrecognized / empty bucket → block merge (fail-safe; returned in `failed[]`)
70
+ * A check is non-blocking ONLY when its bucket is explicitly "pass" or "skipping".
71
+ * Any bucket value that is not in {pass, skipping, pending} — including future gh
72
+ * bucket values and empty strings — is treated as blocking to prevent a fail-open merge.
73
+ *
74
+ * This is the canonical evaluator for pollChecks and is mirrored by the
75
+ * cbp-supabase-branch-check skill.
76
+ */
77
+ export declare function evaluateChecks(checks: CheckEntry[]): {
78
+ passed: boolean;
79
+ pending: number;
80
+ failed: string[];
81
+ };
82
+ export declare function runShip(opts?: ShipOptions): Promise<ShipResult>;
83
+ export {};
84
+ //# sourceMappingURL=ship.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ship.d.ts","sourceRoot":"","sources":["../../src/lib/ship.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAMpD,MAAM,MAAM,WAAW,GAAG;IACxB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4BAA4B;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iDAAiD;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,8DAA8D;IAC9D,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,gCAAgC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB,CAAC;AA0BF,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG;IACpD,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CASA;AA2HD,wBAAsB,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAySrE"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Canonical branch slug helper.
3
+ *
4
+ * Replicates the slug rules from cbp-task-start Step 3.1:
5
+ * lowercase → split on whitespace/punctuation → drop non-alphanumerics →
6
+ * dash-join → truncate to 40 chars (no trailing dash after truncate).
7
+ *
8
+ * Handles bash-glob footgun titles safely: "[param] routes", "(group) layout",
9
+ * titles with slashes, quotes, unicode, and consecutive separators.
10
+ *
11
+ * No I/O — pure transform.
12
+ */
13
+ /**
14
+ * Convert a human title to a git-safe branch slug.
15
+ *
16
+ * - Lowercase
17
+ * - Non-alphanumeric characters (including brackets, parens, slashes, quotes,
18
+ * unicode combining marks, etc.) are treated as separators and replaced with
19
+ * a single dash in the output
20
+ * - Consecutive separators collapse to a single dash
21
+ * - Leading/trailing dashes are stripped
22
+ * - Truncated to MAX_LENGTH characters with no trailing dash
23
+ * - Empty input → ""
24
+ */
25
+ export declare function slugify(title: string): string;
26
+ //# sourceMappingURL=slug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../src/lib/slug.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAwB7C"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `spawnSyncOrThrow` — run a command with an argv array (NO shell, so no
3
+ * command-injection surface) while preserving execSync-like ergonomics:
4
+ * throw on a spawn error or a non-zero exit, otherwise return stdout as a string.
5
+ *
6
+ * Use this anywhere a `git`/`gh`/etc. invocation previously used
7
+ * `execSync(`cmd ${interpolated}`)` — the interpolated value can no longer reach
8
+ * a shell. The no-restricted-syntax lint rule enforces this package-wide.
9
+ */
10
+ import { type SpawnSyncOptions } from "node:child_process";
11
+ export declare function spawnSyncOrThrow(file: string, args: string[], opts?: SpawnSyncOptions): string;
12
+ //# sourceMappingURL=spawn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../src/lib/spawn.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtE,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,GAAE,gBAAqB,GAC1B,MAAM,CAaR"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Backend write HTTP client for the local-first state layer.
3
+ *
4
+ * Provides `apiBackendPost` and `apiBackendPatch` for the NestJS backend at
5
+ * `getBackendBase()` (CODEBYPLAN_BACKEND_URL ?? "https://api.codebyplan.com").
6
+ * Auth is via `getAuthHeaders()` (OAuth bearer or legacy API key).
7
+ *
8
+ * Throws `BackendError` on non-2xx responses so callers can distinguish
9
+ * 4xx (reject-reconcile: revert local) from 5xx (keep local + write _pending/).
10
+ *
11
+ * 409 Conflict is surfaced distinctly via `isConflict` so callers implementing
12
+ * OCC retry loops can detect it without inspecting the raw status code.
13
+ */
14
+ /**
15
+ * Thrown by `apiBackendPost` / `apiBackendPatch` on non-2xx responses.
16
+ * Callers should inspect `status` to decide reconciliation strategy:
17
+ * - 4xx → reject: revert the optimistic local write
18
+ * - 5xx → degrade: keep local, write `_pending/<id>.json` marker
19
+ * - 409 specifically → OCC conflict: re-read row and retry (use isConflict)
20
+ */
21
+ export declare class BackendError extends Error {
22
+ status: number;
23
+ constructor(message: string, status: number);
24
+ }
25
+ /**
26
+ * Returns true when the thrown error is a BackendError with status 409.
27
+ *
28
+ * Use in OCC retry loops:
29
+ *
30
+ * ```ts
31
+ * try {
32
+ * await apiBackendPatch(path, body);
33
+ * } catch (err) {
34
+ * if (isConflict(err)) {
35
+ * // re-read the row, merge intent, retry
36
+ * }
37
+ * throw err;
38
+ * }
39
+ * ```
40
+ */
41
+ export declare function isConflict(err: unknown): err is BackendError;
42
+ /**
43
+ * POST to the NestJS backend.
44
+ * @throws {BackendError} on non-2xx response
45
+ * @throws {Error} on network / timeout failure
46
+ */
47
+ export declare function apiBackendPost<T>(path: string, body: unknown): Promise<T>;
48
+ /**
49
+ * PATCH to the NestJS backend.
50
+ * @throws {BackendError} on non-2xx response (including 409 Conflict — use isConflict())
51
+ * @throws {Error} on network / timeout failure
52
+ */
53
+ export declare function apiBackendPatch<T>(path: string, body: unknown): Promise<T>;
54
+ //# sourceMappingURL=state-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-client.d.ts","sourceRoot":"","sources":["../../src/lib/state-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAWH;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,MAAM,EAAE,MAAM,CAAC;gBAEH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAK5C;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,YAAY,CAE5D;AAkDD;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,CAAC,CAAC,CAEZ"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * @module state-store
3
+ *
4
+ * Core read/write layer for the `.codebyplan/state/` local mirror.
5
+ *
6
+ * ## Directory layout
7
+ *
8
+ * ```
9
+ * .codebyplan/state/
10
+ * _cursor.json — sync cursor (seq + hash map)
11
+ * checkpoints/<checkpointId>.json — checkpoint row
12
+ * checkpoints/<checkpointId>/
13
+ * tasks/<taskId>.json — task row
14
+ * tasks/<taskId>/
15
+ * rounds/<roundId>.json — round row
16
+ * standalone_tasks/<taskId>.json — standalone task row (FLAT,
17
+ * no checkpoint partitioning;
18
+ * write-through only — not
19
+ * hydrated by runSync)
20
+ * session/
21
+ * current.json — active session_log row
22
+ * state.json — session_state row (write-through-only;
23
+ * populated by `codebyplan session update-state`;
24
+ * never written by runSync — session_state is
25
+ * not a sync_seq table and is absent from /sync)
26
+ * todos.json — todos snapshot
27
+ * _pending/
28
+ * <entityId>.json — pending-write marker (5xx path)
29
+ * ```
30
+ *
31
+ * ## Server-side deletion propagation
32
+ *
33
+ * `pruneEntityTree` runs on full hydrate (`since=0`) to drop entities absent
34
+ * from the server response. Delta syncs (warm path) propagate server-side
35
+ * removals via tombstones: the backend `/sync` endpoint returns a `deleted[]`
36
+ * array (sourced from the `sync_tombstones` table + after-delete triggers), and
37
+ * `runSync` prunes the matching local per-id files on every delta — not only on
38
+ * `--full` (CHK-222 TASK-4).
39
+ *
40
+ * ## Write-through-only fields
41
+ *
42
+ * `session/state.json` is WRITE-THROUGH-ONLY: it is populated solely by
43
+ * `codebyplan session update-state` (which PATCHes the backend and overwrites
44
+ * the local file with the server response). `runSync` never hydrates it — the
45
+ * `/sync` endpoint does not return session_state because it is not a sync_seq
46
+ * table. A future local-first `get_session_state` reader (TASK-7/8) must not
47
+ * assume `sync --full` populates `session/state.json`.
48
+ *
49
+ * `port_allocations` is present in every `/sync` payload (it IS a sync_seq table)
50
+ * but `runSync` intentionally does NOT mirror it to `.codebyplan/state/`. Port
51
+ * allocations are managed by `codebyplan ports` and persisted to
52
+ * `server.json`/`server.local.json`. Persisting them a second time under
53
+ * `state/` would create a second source of truth for port data.
54
+ *
55
+ * ## Advisory / non-fatal contract
56
+ *
57
+ * All functions swallow errors and warn to stderr. A state-store failure
58
+ * must never abort the caller's primary work (MCP write, sync invocation, etc.).
59
+ */
60
+ /**
61
+ * Sync cursor stored at `.codebyplan/state/_cursor.json`.
62
+ * Tracks the last successfully synced sequence number and per-entity
63
+ * content hashes (sha256 of JSON.stringify(row)) for change detection.
64
+ */
65
+ export interface Cursor {
66
+ /** Last `max_seq` value returned by the backend `/sync` endpoint. */
67
+ sync_seq: number;
68
+ /** ISO-8601 timestamp of the last successful sync. */
69
+ synced_at: string;
70
+ /**
71
+ * Map of entity_id → sha256(JSON.stringify(row)).
72
+ * Used to detect whether a local file is up-to-date without re-reading
73
+ * every file on every delta sync.
74
+ */
75
+ entity_hashes: Record<string, string>;
76
+ /** `synced` = all pages complete; `partial` = interrupted mid-sync. */
77
+ sync_status: "synced" | "partial";
78
+ }
79
+ export declare function checkpointPath(repoRoot: string, checkpointId: string): string;
80
+ export declare function taskPath(repoRoot: string, checkpointId: string, taskId: string): string;
81
+ export declare function roundPath(repoRoot: string, checkpointId: string, taskId: string, roundId: string): string;
82
+ export declare function standaloneTaskPath(repoRoot: string, taskId: string): string;
83
+ export declare function sessionLogPath(repoRoot: string): string;
84
+ export declare function todosPath(repoRoot: string): string;
85
+ /**
86
+ * Absolute path to the `_pending/` outbox directory under `.codebyplan/state/`.
87
+ * Pending-write markers (5xx path) are stored here as `<entityId>.json`.
88
+ * Use `listEntityFiles(pendingDir(repoRoot))` to scan for markers to replay.
89
+ */
90
+ export declare function pendingDir(repoRoot: string): string;
91
+ export declare function pendingMarkerPath(repoRoot: string, entityId: string): string;
92
+ /**
93
+ * Compute sha256(serializeEntity(row)) for entity_hashes tracking.
94
+ * Uses the same pretty-printed + trailing-newline form as writeEntityFile
95
+ * so hashes are byte-identical whether produced by the sync path or the
96
+ * CLI-verb path.
97
+ */
98
+ export declare function hashEntity(row: unknown): string;
99
+ /**
100
+ * Read the sync cursor from `.codebyplan/state/_cursor.json`.
101
+ * Returns `null` (silently) when absent or corrupt.
102
+ * Never throws.
103
+ */
104
+ export declare function readCursor(repoRoot: string): Promise<Cursor | null>;
105
+ /**
106
+ * Write the sync cursor to `.codebyplan/state/_cursor.json`.
107
+ * Creates the state directory recursively if absent.
108
+ * Never throws; errors are swallowed with a stderr warning.
109
+ */
110
+ export declare function writeCursor(repoRoot: string, cursor: Cursor): Promise<void>;
111
+ /**
112
+ * Read an entity file at the given absolute path.
113
+ * Returns `null` when absent (ENOENT) or when JSON parse fails.
114
+ * Never throws.
115
+ */
116
+ export declare function readEntityFile<T = unknown>(filePath: string): Promise<T | null>;
117
+ /**
118
+ * Write an entity row to `filePath`, creating parent directories recursively.
119
+ * Also computes and returns the sha256 hash of the serialized row.
120
+ * Never throws; errors are swallowed with a stderr warning.
121
+ */
122
+ export declare function writeEntityFile(filePath: string, row: unknown): Promise<string>;
123
+ /**
124
+ * Delete an entity file at `filePath`.
125
+ * Silently ignores ENOENT. Never throws.
126
+ */
127
+ export declare function deleteEntityFile(filePath: string): Promise<void>;
128
+ /**
129
+ * List all `.json` files recursively under `dirPath`.
130
+ * Returns an empty array when the directory does not exist.
131
+ * Never throws.
132
+ */
133
+ export declare function listEntityFiles(dirPath: string): Promise<string[]>;
134
+ /**
135
+ * Tables tracked in the local state mirror.
136
+ */
137
+ export type StateTable = "checkpoints" | "tasks" | "rounds" | "session_logs" | "todos";
138
+ /**
139
+ * Remove local entity files whose IDs are absent from the server's hydrate
140
+ * response. Only called on full hydrate (since=0); delta syncs never prune.
141
+ *
142
+ * `knownIdsByTable` maps each table name to the set of IDs the backend returned.
143
+ * Any local file whose basename (without `.json`) is not in the known set is
144
+ * deleted. The `_cursor.json`, `_pending/`, and top-level collection files
145
+ * (`todos.json`) are handled separately and are NOT pruned
146
+ * by per-table ID matching.
147
+ *
148
+ * Never throws.
149
+ */
150
+ export declare function pruneEntityTree(repoRoot: string, knownIdsByTable: Partial<Record<StateTable, Set<string>>>): Promise<{
151
+ pruned: string[];
152
+ }>;
153
+ //# sourceMappingURL=state-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-store.d.ts","sourceRoot":"","sources":["../../src/lib/state-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAkBH;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACrB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,uEAAuE;IACvE,WAAW,EAAE,QAAQ,GAAG,SAAS,CAAC;CACnC;AAcD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,MAAM,CAQR;AAED,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,MAAM,CAUR;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5E;AAkBD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE/C;AAMD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAczE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAUf;AAMD;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,CAAC,GAAG,OAAO,EAC9C,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAanB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWtE;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAaxE;AA8BD;;GAEG;AACH,MAAM,MAAM,UAAU,GAClB,aAAa,GACb,OAAO,GACP,QAAQ,GACR,cAAc,GACd,OAAO,CAAC;AAEZ;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GACxD,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAmE/B"}