gsd-pi 2.81.0-dev.72a81bdf3 → 2.82.0-dev.2841a1e44

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 (243) hide show
  1. package/README.md +49 -30
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +3 -1
  4. package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
  5. package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
  6. package/dist/resources/extensions/cmux/index.js +5 -0
  7. package/dist/resources/extensions/gsd/auto/orchestrator.js +113 -6
  8. package/dist/resources/extensions/gsd/auto/phases.js +9 -0
  9. package/dist/resources/extensions/gsd/auto-post-unit.js +169 -124
  10. package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
  11. package/dist/resources/extensions/gsd/auto-verification.js +28 -22
  12. package/dist/resources/extensions/gsd/auto.js +128 -52
  13. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +5 -0
  14. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +16 -7
  15. package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
  16. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +3 -1
  17. package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
  18. package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
  19. package/dist/resources/extensions/gsd/commands/handlers/core.js +22 -1
  20. package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
  21. package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
  22. package/dist/resources/extensions/gsd/context-store.js +112 -0
  23. package/dist/resources/extensions/gsd/db-writer.js +150 -84
  24. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  25. package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
  26. package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
  27. package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
  28. package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
  29. package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
  30. package/dist/resources/extensions/gsd/markdown-renderer.js +6 -1
  31. package/dist/resources/extensions/gsd/md-importer.js +1 -1
  32. package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
  33. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
  34. package/dist/resources/extensions/gsd/migrate/command.js +5 -0
  35. package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
  36. package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
  37. package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
  38. package/dist/resources/extensions/gsd/prompts/system.md +2 -2
  39. package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
  40. package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
  41. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
  42. package/dist/resources/extensions/gsd/unit-context-manifest.js +25 -2
  43. package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
  44. package/dist/resources/extensions/gsd/worktree-lifecycle.js +21 -2
  45. package/dist/resources/extensions/subagent/index.js +448 -78
  46. package/dist/resources/extensions/subagent/launch.js +77 -0
  47. package/dist/resources/extensions/subagent/run-store.js +148 -0
  48. package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
  49. package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
  50. package/dist/resources/extensions/visual-brief/index.js +5 -0
  51. package/dist/resources/extensions/visual-brief/page-contract.js +122 -0
  52. package/dist/resources/extensions/visual-brief/prompts.js +111 -0
  53. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  54. package/dist/web/standalone/.next/BUILD_ID +1 -1
  55. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  56. package/dist/web/standalone/.next/build-manifest.json +3 -3
  57. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  58. package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
  59. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.rsc +2 -2
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  77. package/dist/web/standalone/.next/server/app/index.html +1 -1
  78. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  79. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  81. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  83. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  84. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  86. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  89. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  90. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  91. package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
  92. package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
  93. package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-6a95bc41e0f7ec89.js} +1 -1
  94. package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +1 -0
  95. package/package.json +5 -4
  96. package/packages/contracts/dist/rpc.test.js +7 -0
  97. package/packages/contracts/dist/rpc.test.js.map +1 -1
  98. package/packages/contracts/dist/workflow.d.ts +21 -0
  99. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  100. package/packages/contracts/dist/workflow.js +24 -0
  101. package/packages/contracts/dist/workflow.js.map +1 -1
  102. package/packages/contracts/src/rpc.test.ts +8 -0
  103. package/packages/contracts/src/workflow.ts +24 -0
  104. package/packages/daemon/package.json +2 -2
  105. package/packages/mcp-server/README.md +14 -3
  106. package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
  107. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  108. package/packages/mcp-server/dist/workflow-tools.js +80 -0
  109. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  110. package/packages/mcp-server/package.json +2 -2
  111. package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
  112. package/packages/mcp-server/src/workflow-tools.test.ts +22 -0
  113. package/packages/mcp-server/src/workflow-tools.ts +168 -0
  114. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  115. package/packages/native/package.json +1 -1
  116. package/packages/pi-agent-core/package.json +1 -1
  117. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  118. package/packages/pi-ai/dist/index.d.ts +2 -2
  119. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  120. package/packages/pi-ai/dist/index.js +1 -1
  121. package/packages/pi-ai/dist/index.js.map +1 -1
  122. package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
  123. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  124. package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
  125. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  126. package/packages/pi-ai/package.json +1 -1
  127. package/packages/pi-ai/src/index.ts +7 -2
  128. package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
  129. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  130. package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
  131. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  132. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
  133. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
  134. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
  135. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
  136. package/packages/pi-coding-agent/package.json +1 -1
  137. package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
  138. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  139. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  140. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  141. package/packages/pi-tui/dist/tui.js +5 -0
  142. package/packages/pi-tui/dist/tui.js.map +1 -1
  143. package/packages/pi-tui/package.json +1 -1
  144. package/packages/pi-tui/src/tui.ts +6 -0
  145. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  146. package/packages/rpc-client/package.json +1 -1
  147. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  148. package/pkg/package.json +1 -1
  149. package/src/resources/GSD-WORKFLOW.md +3 -1
  150. package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
  151. package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
  152. package/src/resources/extensions/cmux/index.ts +6 -0
  153. package/src/resources/extensions/gsd/auto/contracts.ts +46 -11
  154. package/src/resources/extensions/gsd/auto/orchestrator.ts +118 -6
  155. package/src/resources/extensions/gsd/auto/phases.ts +14 -0
  156. package/src/resources/extensions/gsd/auto-post-unit.ts +194 -137
  157. package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
  158. package/src/resources/extensions/gsd/auto-verification.ts +36 -34
  159. package/src/resources/extensions/gsd/auto.ts +136 -51
  160. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -0
  161. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +16 -6
  162. package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
  163. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +3 -2
  164. package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
  165. package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
  166. package/src/resources/extensions/gsd/commands/handlers/core.ts +25 -1
  167. package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
  168. package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
  169. package/src/resources/extensions/gsd/context-store.ts +120 -1
  170. package/src/resources/extensions/gsd/db-writer.ts +167 -84
  171. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  172. package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
  173. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  174. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  175. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  176. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  177. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  178. package/src/resources/extensions/gsd/markdown-renderer.ts +6 -1
  179. package/src/resources/extensions/gsd/md-importer.ts +1 -1
  180. package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
  181. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  182. package/src/resources/extensions/gsd/migrate/command.ts +5 -0
  183. package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
  184. package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
  185. package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
  186. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  187. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  188. package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
  189. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +75 -0
  190. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +408 -4
  191. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +6 -5
  192. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
  193. package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
  194. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  195. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
  196. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
  197. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  198. package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
  199. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  200. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  201. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
  202. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
  203. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
  204. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
  205. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
  206. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
  207. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  208. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  209. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
  210. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  211. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  212. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
  213. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
  214. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  215. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  216. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
  217. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  218. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
  219. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
  220. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +21 -0
  221. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
  222. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
  223. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +16 -0
  224. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
  225. package/src/resources/extensions/gsd/unit-context-manifest.ts +35 -2
  226. package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
  227. package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
  228. package/src/resources/extensions/gsd/worktree-lifecycle.ts +20 -2
  229. package/src/resources/extensions/subagent/index.ts +567 -103
  230. package/src/resources/extensions/subagent/launch.ts +131 -0
  231. package/src/resources/extensions/subagent/run-store.ts +218 -0
  232. package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
  233. package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
  234. package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
  235. package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
  236. package/src/resources/extensions/visual-brief/index.ts +8 -0
  237. package/src/resources/extensions/visual-brief/page-contract.ts +134 -0
  238. package/src/resources/extensions/visual-brief/prompts.ts +147 -0
  239. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +172 -0
  240. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
  241. package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
  242. /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → Qgr2B_MRhPxC0z8fwv4vT}/_buildManifest.js +0 -0
  243. /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → Qgr2B_MRhPxC0z8fwv4vT}/_ssgManifest.js +0 -0
@@ -8,12 +8,14 @@
8
8
  *
9
9
  * Design constraints (from Trek-e approval):
10
10
  * - Warn the user before stashing (no silent surprises)
11
- * - git stash push / git stash pop only no custom stash management layer
12
- * - Stash/pop errors are logged but MUST NOT block the merge itself
11
+ * - git stash push / git stash apply+drop for targeted restore
12
+ * - Stash/apply errors are logged but MUST NOT block the merge itself
13
13
  * - Fast-path status check — clean trees pay no extra cost
14
14
  */
15
15
 
16
16
  import { execFileSync } from "node:child_process";
17
+ import { existsSync, readFileSync } from "node:fs";
18
+ import { join } from "node:path";
17
19
  import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
18
20
  import { logWarning } from "./workflow-logger.js";
19
21
  import { nativeHasChanges } from "./native-git-bridge.js";
@@ -32,6 +34,148 @@ export interface PostflightResult {
32
34
  needsManualRecovery: boolean;
33
35
  message: string;
34
36
  stashRef?: string;
37
+ resolution?: "applied" | "already-present-dropped" | "already-present-preserved" | "manual-recovery";
38
+ collidedPaths?: string[];
39
+ }
40
+
41
+ function gitText(basePath: string, args: string[]): string {
42
+ return execFileSync("git", args, {
43
+ cwd: basePath,
44
+ stdio: ["ignore", "pipe", "pipe"],
45
+ encoding: "utf-8",
46
+ env: GIT_NO_PROMPT_ENV,
47
+ });
48
+ }
49
+
50
+ function gitBuffer(basePath: string, args: string[]): Buffer {
51
+ return execFileSync("git", args, {
52
+ cwd: basePath,
53
+ stdio: ["ignore", "pipe", "pipe"],
54
+ env: GIT_NO_PROMPT_ENV,
55
+ });
56
+ }
57
+
58
+ function errorText(err: unknown): string {
59
+ if (!err || typeof err !== "object") return String(err);
60
+ const parts: string[] = [];
61
+ const stderr = (err as { stderr?: unknown }).stderr;
62
+ const stdout = (err as { stdout?: unknown }).stdout;
63
+ for (const value of [stderr, stdout]) {
64
+ if (typeof value === "string") parts.push(value);
65
+ else if (value instanceof Uint8Array) parts.push(Buffer.from(value).toString("utf-8"));
66
+ }
67
+ parts.push(err instanceof Error ? err.message : String(err));
68
+ return parts.filter(Boolean).join("\n");
69
+ }
70
+
71
+ function parseAlreadyExistsNoCheckoutPaths(text: string): string[] {
72
+ const paths: string[] = [];
73
+ for (const line of text.split(/\r?\n/)) {
74
+ const match = /^(.+?) already exists, no checkout$/i.exec(line.trim());
75
+ if (match?.[1]) paths.push(match[1]);
76
+ }
77
+ return [...new Set(paths)];
78
+ }
79
+
80
+ function readZeroDelimitedPaths(output: string): string[] {
81
+ return output.split("\0").filter(Boolean);
82
+ }
83
+
84
+ function listStashUntrackedPaths(basePath: string, stashRef: string): string[] | null {
85
+ try {
86
+ const output = gitText(basePath, ["ls-tree", "-r", "-z", "--name-only", `${stashRef}^3`]);
87
+ return readZeroDelimitedPaths(output);
88
+ } catch {
89
+ return null;
90
+ }
91
+ }
92
+
93
+ function listStashTrackedPaths(basePath: string, stashRef: string): string[] | null {
94
+ try {
95
+ const output = gitText(basePath, ["diff", "--name-only", "-z", `${stashRef}^1`, stashRef]);
96
+ return readZeroDelimitedPaths(output);
97
+ } catch {
98
+ return null;
99
+ }
100
+ }
101
+
102
+ function isWorktreeClean(basePath: string): boolean | null {
103
+ try {
104
+ return gitText(basePath, ["status", "--porcelain"]).trim() === "";
105
+ } catch {
106
+ return null;
107
+ }
108
+ }
109
+
110
+ function stashBlobEqualsWorktreeFile(basePath: string, stashRef: string, path: string): boolean | null {
111
+ try {
112
+ const worktreePath = join(basePath, path);
113
+ if (!existsSync(worktreePath)) return false;
114
+ const worktreeContent = readFileSync(worktreePath);
115
+ const stashContent = gitBuffer(basePath, ["show", `${stashRef}^3:${path}`]);
116
+ return Buffer.compare(worktreeContent, stashContent) === 0;
117
+ } catch {
118
+ return null;
119
+ }
120
+ }
121
+
122
+ function reconcileAlreadyPresentUntrackedStash(
123
+ basePath: string,
124
+ milestoneId: string,
125
+ stashRef: string,
126
+ err: unknown,
127
+ ): PostflightResult | null {
128
+ const text = errorText(err);
129
+ const collidedPaths = parseAlreadyExistsNoCheckoutPaths(text);
130
+ if (collidedPaths.length === 0) return null;
131
+
132
+ const untrackedPaths = listStashUntrackedPaths(basePath, stashRef);
133
+ if (!untrackedPaths || untrackedPaths.length === 0) return null;
134
+
135
+ const trackedPaths = listStashTrackedPaths(basePath, stashRef);
136
+ if (trackedPaths === null || trackedPaths.length > 0) return null;
137
+
138
+ const untrackedPathSet = new Set(untrackedPaths);
139
+ if (!collidedPaths.every((path) => untrackedPathSet.has(path))) return null;
140
+ if (!untrackedPaths.every((path) => existsSync(join(basePath, path)))) return null;
141
+ if (isWorktreeClean(basePath) !== true) return null;
142
+
143
+ const blobComparisons = untrackedPaths.map((path) => stashBlobEqualsWorktreeFile(basePath, stashRef, path));
144
+ if (blobComparisons.some((result) => result === null)) return null;
145
+ const allIdentical = blobComparisons.every(Boolean);
146
+ if (allIdentical) {
147
+ let dropped = true;
148
+ try {
149
+ execFileSync("git", ["stash", "drop", stashRef], {
150
+ cwd: basePath,
151
+ stdio: ["ignore", "pipe", "pipe"],
152
+ encoding: "utf-8",
153
+ env: GIT_NO_PROMPT_ENV,
154
+ });
155
+ } catch (err) {
156
+ dropped = false;
157
+ logWarning("preflight", `git stash drop ${stashRef} failed after identical preflight stash reconciliation: ${err instanceof Error ? err.message : String(err)}`);
158
+ }
159
+ return {
160
+ restored: true,
161
+ needsManualRecovery: false,
162
+ message: dropped
163
+ ? `Preflight stash for milestone ${milestoneId} contained files already present after merge; identical stash dropped.`
164
+ : `Preflight stash for milestone ${milestoneId} contained files already present after merge, but ${stashRef} could not be dropped and remains as a backup.`,
165
+ stashRef,
166
+ resolution: dropped ? "already-present-dropped" : "already-present-preserved",
167
+ collidedPaths,
168
+ };
169
+ }
170
+
171
+ return {
172
+ restored: false,
173
+ needsManualRecovery: false,
174
+ message: `Preflight stash for milestone ${milestoneId} contained untracked files already present after merge. Keeping merged files and preserving ${stashRef} as a backup.`,
175
+ stashRef,
176
+ resolution: "already-present-preserved",
177
+ collidedPaths,
178
+ };
35
179
  }
36
180
 
37
181
  function findPreflightStashRef(basePath: string, milestoneId: string, stashMarker?: string): string | null {
@@ -141,27 +285,48 @@ export function postflightPopStash(
141
285
  message: msg,
142
286
  };
143
287
  }
144
- execFileSync("git", ["stash", "pop", stashRef], {
288
+ execFileSync("git", ["stash", "apply", stashRef], {
145
289
  cwd: basePath,
146
290
  stdio: ["ignore", "pipe", "pipe"],
147
291
  encoding: "utf-8",
148
292
  env: GIT_NO_PROMPT_ENV,
149
293
  });
294
+ let dropWarning: string | null = null;
295
+ try {
296
+ execFileSync("git", ["stash", "drop", stashRef], {
297
+ cwd: basePath,
298
+ stdio: ["ignore", "pipe", "pipe"],
299
+ encoding: "utf-8",
300
+ env: GIT_NO_PROMPT_ENV,
301
+ });
302
+ } catch (err) {
303
+ dropWarning = ` Stash was restored, but git stash drop ${stashRef} failed: ${err instanceof Error ? err.message : String(err)}.`;
304
+ logWarning("preflight", dropWarning.trim());
305
+ }
150
306
  const msg = `Restored stashed changes after milestone ${milestoneId} merge.`;
151
- notify(msg, "info");
307
+ notify(`${msg}${dropWarning ?? ""}`, dropWarning ? "warning" : "info");
152
308
  return {
153
309
  restored: true,
154
310
  needsManualRecovery: false,
155
- message: msg,
311
+ message: `${msg}${dropWarning ?? ""}`,
156
312
  stashRef,
313
+ resolution: "applied",
157
314
  };
158
315
  } catch (err) {
159
- // Pop conflicts mean the merged code collides with the stashed changes.
316
+ if (stashRef) {
317
+ const reconciled = reconcileAlreadyPresentUntrackedStash(basePath, milestoneId, stashRef, err);
318
+ if (reconciled) {
319
+ logWarning("preflight", reconciled.message);
320
+ notify(reconciled.message, reconciled.resolution === "already-present-preserved" ? "warning" : "info");
321
+ return reconciled;
322
+ }
323
+ }
324
+ // Apply conflicts mean the merged code collides with the stashed changes.
160
325
  // Log a warning — the user needs to resolve manually, but the merge succeeded.
161
326
  const restoreHint = stashRef
162
- ? `Run "git stash pop ${stashRef}" or "git stash apply ${stashRef}" manually to restore the correct stash.`
327
+ ? `Run "git stash apply ${stashRef}" manually to restore the correct stash, then "git stash drop ${stashRef}" after recovery.`
163
328
  : `Run "git stash list" to find the matching GSD preflight stash before restoring manually.`;
164
- const msg = `git stash pop ${stashRef ?? ""}`.trim() + ` failed after merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. ${restoreHint}`;
329
+ const msg = `git stash apply ${stashRef ?? ""}`.trim() + ` failed after merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. ${restoreHint}`;
165
330
  logWarning("preflight", msg);
166
331
  notify(msg, "warning");
167
332
  return {
@@ -169,6 +334,7 @@ export function postflightPopStash(
169
334
  needsManualRecovery: true,
170
335
  message: msg,
171
336
  ...(stashRef ? { stashRef } : {}),
337
+ resolution: "manual-recovery",
172
338
  };
173
339
  }
174
340
  }
@@ -3,6 +3,7 @@ import { join, resolve } from "node:path";
3
3
 
4
4
  import { loadRegistry } from "../workflow-templates.js";
5
5
  import { gsdHome } from "../gsd-home.js";
6
+ import { VISUAL_BRIEF_MODES } from "../../visual-brief/prompts.js";
6
7
 
7
8
 
8
9
  export interface GsdCommandDefinition {
@@ -13,7 +14,7 @@ export interface GsdCommandDefinition {
13
14
  type CompletionMap = Record<string, readonly GsdCommandDefinition[]>;
14
15
 
15
16
  export const GSD_COMMAND_DESCRIPTION =
16
- "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|new-project|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|fast|mcp|rethink|workflow|codebase|notifications|ship|do|session-report|backlog|pr-branch|add-tests|scan|language|worktree|eval-review";
17
+ "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|brief|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|new-project|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|fast|mcp|rethink|workflow|codebase|notifications|ship|do|session-report|backlog|pr-branch|add-tests|scan|language|worktree|eval-review";
17
18
 
18
19
  export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
19
20
  { cmd: "help", desc: "Categorized command reference with descriptions" },
@@ -24,6 +25,7 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
24
25
  { cmd: "status", desc: "Progress dashboard" },
25
26
  { cmd: "widget", desc: "Cycle widget: full → small → min → off" },
26
27
  { cmd: "visualize", desc: "Open 10-tab workflow visualizer (progress, timeline, deps, metrics, health, agent, changes, knowledge, captures, export)" },
28
+ { cmd: "brief", desc: "Generate a visual HTML brief: diagram, plan, diff review, recap, table, or slides" },
27
29
  { cmd: "queue", desc: "Queue and reorder future milestones" },
28
30
  { cmd: "quick", desc: "Execute a quick task without full planning overhead" },
29
31
  { cmd: "discuss", desc: "Discuss architecture and decisions" },
@@ -88,6 +90,7 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
88
90
  ];
89
91
 
90
92
  const NESTED_COMPLETIONS: CompletionMap = {
93
+ brief: VISUAL_BRIEF_MODES.map((mode) => ({ cmd: mode.mode, desc: mode.description })),
91
94
  auto: [
92
95
  { cmd: "--verbose", desc: "Show detailed execution output" },
93
96
  { cmd: "--debug", desc: "Enable debug logging" },
@@ -11,6 +11,8 @@ import { handleCmux } from "../../commands-cmux.js";
11
11
  import { setSessionModelOverride } from "../../session-model-override.js";
12
12
  import { projectRoot } from "../context.js";
13
13
  import { formattedShortcutPair } from "../../shortcut-defs.js";
14
+ import { getVisualBriefOutputDir } from "../../../visual-brief/artifact-policy.js";
15
+ import { buildVisualBriefPrompt, parseVisualBriefArgs, VISUAL_BRIEF_USAGE } from "../../../visual-brief/prompts.js";
14
16
 
15
17
  export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
16
18
  const summaryLines = [
@@ -27,6 +29,7 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
27
29
  ` /gsd parallel watch Parallel monitor (${formattedShortcutPair("parallel")})`,
28
30
  ` /gsd notifications Notification history (${formattedShortcutPair("notifications")})`,
29
31
  " /gsd visualize Interactive 10-tab TUI",
32
+ " /gsd brief <mode> Visual HTML brief (diagram, plan, diff, recap, table, slides)",
30
33
  " /gsd queue Show queued/dispatched units",
31
34
  "",
32
35
  "COURSE CORRECTION",
@@ -75,6 +78,7 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
75
78
  ` /gsd parallel watch Open parallel worker monitor (${formattedShortcutPair("parallel")})`,
76
79
  " /gsd widget Cycle status widget [full|small|min|off]",
77
80
  " /gsd visualize Interactive 10-tab TUI (progress, timeline, deps, metrics, health, agent, changes, knowledge, captures, export)",
81
+ " /gsd brief <mode> Generate a visual HTML brief [diagram|plan|diff|recap|table|slides] [topic] [--slides]",
78
82
  " /gsd queue Show queued/dispatched units and execution order",
79
83
  " /gsd history View execution history [--cost] [--phase] [--model] [N]",
80
84
  " /gsd changelog Show categorized release notes [version]",
@@ -96,7 +100,7 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
96
100
  " /gsd unpark [id] Reactivate a parked milestone",
97
101
  "",
98
102
  "PROJECT KNOWLEDGE",
99
- " /gsd knowledge <type> <text> Add rule, pattern, or lesson to KNOWLEDGE.md",
103
+ " /gsd knowledge <type> <text> Add a rule to KNOWLEDGE.md or capture a pattern/lesson to memories",
100
104
  " /gsd codebase [generate|update|stats] Manage the CODEBASE.md cache used in prompt context",
101
105
  "",
102
106
  "SHIPPING & BACKLOG",
@@ -203,6 +207,22 @@ export async function handleVisualize(ctx: ExtensionCommandContext): Promise<voi
203
207
  }
204
208
  }
205
209
 
210
+ export async function handleBrief(args: string, ctx: ExtensionCommandContext, pi?: ExtensionAPI): Promise<void> {
211
+ const request = parseVisualBriefArgs(args);
212
+ if (!request) {
213
+ ctx.ui.notify(VISUAL_BRIEF_USAGE, "info");
214
+ return;
215
+ }
216
+
217
+ if (!pi?.sendUserMessage) {
218
+ ctx.ui.notify("Visual brief generation is unavailable in this context.", "warning");
219
+ return;
220
+ }
221
+
222
+ const outputDir = getVisualBriefOutputDir();
223
+ pi.sendUserMessage(buildVisualBriefPrompt(request, { outputDir }));
224
+ }
225
+
206
226
  export async function handleSetup(args: string, ctx: ExtensionCommandContext, pi?: ExtensionAPI): Promise<void> {
207
227
  const { detectProjectState, hasGlobalSetup } = await import("../../detection.js");
208
228
  const { isOnboardingComplete, readOnboardingRecord } = await import("../../onboarding-state.js");
@@ -429,6 +449,10 @@ export async function handleCoreCommand(
429
449
  await handleVisualize(ctx);
430
450
  return true;
431
451
  }
452
+ if (trimmed === "brief" || trimmed.startsWith("brief ")) {
453
+ await handleBrief(trimmed.replace(/^brief\s*/, "").trim(), ctx, pi);
454
+ return true;
455
+ }
432
456
  if (trimmed === "widget" || trimmed.startsWith("widget ")) {
433
457
  const { cycleWidgetMode, setWidgetMode, getWidgetMode } = await import("../../auto-dashboard.js");
434
458
  const arg = trimmed.replace(/^widget\s*/, "").trim();
@@ -1,4 +1,5 @@
1
1
  import { importExtensionModule, type ExtensionAPI, type ExtensionCommandContext } from "@gsd/pi-coding-agent";
2
+ import { VISUAL_BRIEF_MODES } from "../visual-brief/prompts.js";
2
3
 
3
4
  const TOP_LEVEL_SUBCOMMANDS = [
4
5
  { cmd: "help", desc: "Categorized command reference with descriptions" },
@@ -8,6 +9,7 @@ const TOP_LEVEL_SUBCOMMANDS = [
8
9
  { cmd: "pause", desc: "Pause auto-mode (preserves state, /gsd auto to resume)" },
9
10
  { cmd: "status", desc: "Progress dashboard" },
10
11
  { cmd: "visualize", desc: "Open workflow visualizer" },
12
+ { cmd: "brief", desc: "Generate a visual HTML brief" },
11
13
  { cmd: "queue", desc: "Queue and reorder future milestones" },
12
14
  { cmd: "quick", desc: "Execute a quick task without full planning overhead" },
13
15
  { cmd: "discuss", desc: "Discuss architecture and decisions" },
@@ -87,6 +89,14 @@ function getGsdArgumentCompletions(prefix: string) {
87
89
  ], "next");
88
90
  }
89
91
 
92
+ if (parts[0] === "brief" && parts.length <= 2) {
93
+ return filterStartsWith(
94
+ partial,
95
+ VISUAL_BRIEF_MODES.map((mode) => ({ cmd: mode.mode, desc: mode.description })),
96
+ "brief",
97
+ );
98
+ }
99
+
90
100
  if ((parts[0] === "new-project" || parts[0] === "new-milestone") && parts.length <= 2) {
91
101
  return filterStartsWith(partial, [
92
102
  { cmd: "--deep", desc: "Enable deep planning mode (staged project-level discovery)" },
@@ -368,8 +368,25 @@ export async function handleKnowledge(args: string, ctx: ExtensionCommandContext
368
368
  ? `${state.activeMilestone.id}${state.activeSlice ? `/${state.activeSlice.id}` : ""}`
369
369
  : "global";
370
370
 
371
- await appendKnowledge(basePath, type, entryText, scope);
372
- ctx.ui.notify(`Added ${type} to KNOWLEDGE.md: "${entryText}"`, "success");
371
+ // ADR-013 Stage 2c: Patterns and Lessons land in the memories table; the
372
+ // next session-start projection render emits them back into KNOWLEDGE.md.
373
+ // Rules stay file-canonical per ADR-013 line 39 — Rules are not migrated.
374
+ if (type === "rule") {
375
+ await appendKnowledge(basePath, type, entryText, scope);
376
+ ctx.ui.notify(`Added rule to KNOWLEDGE.md: "${entryText}"`, "success");
377
+ return;
378
+ }
379
+
380
+ const { captureKnowledgeEntry } = await import("./knowledge-capture.js");
381
+ const { id, written } = captureKnowledgeEntry(basePath, type, entryText, scope);
382
+ if (!written) {
383
+ ctx.ui.notify(`Could not persist ${type} — see logs for details.`, "error");
384
+ return;
385
+ }
386
+ ctx.ui.notify(
387
+ `Captured ${type} ${id} to memories; KNOWLEDGE.md will render it on next session start.`,
388
+ "success",
389
+ );
373
390
  }
374
391
 
375
392
  export async function handleRunHook(args: string, ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
@@ -5,7 +5,7 @@
5
5
  // All functions degrade gracefully: return empty results when DB unavailable, never throw.
6
6
 
7
7
  import { isDbAvailable, _getAdapter } from './gsd-db.js';
8
- import type { Decision, Requirement } from './types.js';
8
+ import type { Decision, DecisionMadeBy, Requirement } from './types.js';
9
9
 
10
10
  // ─── Query Functions ───────────────────────────────────────────────────────
11
11
 
@@ -66,6 +66,125 @@ export function queryDecisions(opts?: DecisionQueryOpts): Decision[] {
66
66
  }
67
67
  }
68
68
 
69
+ /**
70
+ * Internal: shared core for the two memory-sourced decision queries. Reads
71
+ * memory rows tagged with `sourceDecisionId` and reconstructs `Decision[]`
72
+ * from their `structured_fields` JSON.
73
+ *
74
+ * @param includeSuperseded — when false, drops rows whose
75
+ * `structured_fields.superseded_by` is non-null. The supersedes-chain is
76
+ * captured by the backfill (`memory-backfill.ts`) and kept in sync by
77
+ * the backfill's drift auto-heal pass.
78
+ */
79
+ function readDecisionsFromMemories(
80
+ opts: DecisionQueryOpts | undefined,
81
+ includeSuperseded: boolean,
82
+ ): Decision[] {
83
+ if (!isDbAvailable()) return [];
84
+ const adapter = _getAdapter();
85
+ if (!adapter) return [];
86
+
87
+ try {
88
+ const clauses: string[] = [
89
+ "category = 'architecture'",
90
+ "structured_fields LIKE '%\"sourceDecisionId\":\"%'",
91
+ ];
92
+ const params: Record<string, unknown> = {};
93
+
94
+ if (opts?.milestoneId) {
95
+ // when_context is a free-text JSON value; substring match preserves the
96
+ // semantics of `when_context LIKE '%milestoneId%'` on the legacy table.
97
+ clauses.push("json_extract(structured_fields, '$.when_context') LIKE :milestone_pattern");
98
+ params[':milestone_pattern'] = `%${opts.milestoneId}%`;
99
+ }
100
+
101
+ if (opts?.scope) {
102
+ // Stage 1 used `json_extract` in main (post-merge); preserve that
103
+ // style here. Exact equality on the JSON value avoids the prefix
104
+ // collision risk LIKE patterns had (scope=M001 vs scope=M001-S01).
105
+ clauses.push("json_extract(structured_fields, '$.scope') = :scope");
106
+ params[':scope'] = opts.scope;
107
+ }
108
+
109
+ const sql = `SELECT seq, structured_fields FROM memories WHERE ${clauses.join(' AND ')} ORDER BY seq`;
110
+ const rows = adapter.prepare(sql).all(params) as Array<Record<string, unknown>>;
111
+
112
+ const decisions: Decision[] = [];
113
+ for (const row of rows) {
114
+ const seq = row['seq'] as number;
115
+ const sfRaw = row['structured_fields'] as string | null;
116
+ if (!sfRaw) continue;
117
+ let sf: Record<string, unknown>;
118
+ try {
119
+ sf = JSON.parse(sfRaw) as Record<string, unknown>;
120
+ } catch {
121
+ continue;
122
+ }
123
+ const sourceId = sf['sourceDecisionId'];
124
+ if (typeof sourceId !== 'string' || sourceId.length === 0) continue;
125
+
126
+ // Decision-level superseded status lives in structured_fields.superseded_by
127
+ // (written by mirrorDecisionToMemory / memory-backfill.ts). The top-level
128
+ // memories.superseded_by column is intentionally never set for decision mirrors,
129
+ // so active-only filtering must be done here in the JS loop.
130
+ const supersededBy = typeof sf['superseded_by'] === 'string' ? (sf['superseded_by'] as string) : null;
131
+ if (!includeSuperseded && supersededBy) continue;
132
+
133
+ decisions.push({
134
+ seq,
135
+ id: sourceId,
136
+ when_context: typeof sf['when_context'] === 'string' ? (sf['when_context'] as string) : '',
137
+ scope: typeof sf['scope'] === 'string' ? (sf['scope'] as string) : '',
138
+ decision: typeof sf['decision'] === 'string' ? (sf['decision'] as string) : '',
139
+ choice: typeof sf['choice'] === 'string' ? (sf['choice'] as string) : '',
140
+ rationale: typeof sf['rationale'] === 'string' ? (sf['rationale'] as string) : '',
141
+ revisable: typeof sf['revisable'] === 'string' ? (sf['revisable'] as string) : '',
142
+ made_by: ((typeof sf['made_by'] === 'string' ? sf['made_by'] : 'agent') as DecisionMadeBy),
143
+ superseded_by: supersededBy,
144
+ });
145
+ }
146
+
147
+ return decisions;
148
+ } catch {
149
+ return [];
150
+ }
151
+ }
152
+
153
+ /**
154
+ * ADR-013 Phase 6 cutover (Stage 1): read **active** decisions from the
155
+ * `memories` table instead of the legacy `decisions` table. Returns the
156
+ * same `Decision[]` shape as `queryDecisions` so downstream formatters
157
+ * work unchanged.
158
+ *
159
+ * Filter semantics match `queryDecisions` exactly:
160
+ * - active only (skips rows where `structured_fields.superseded_by` is set)
161
+ * - `milestoneId`: substring match on `structured_fields.when_context`
162
+ * - `scope`: exact match on `structured_fields.scope`
163
+ *
164
+ * Used by the prompt-inline path (`inlineDecisionsFromDb` in
165
+ * `auto-prompts.ts`). For the projection regen (which renders superseded
166
+ * rows too), see `getAllDecisionsFromMemories`.
167
+ */
168
+ export function queryDecisionsFromMemories(opts?: DecisionQueryOpts): Decision[] {
169
+ return readDecisionsFromMemories(opts, /* includeSuperseded */ false);
170
+ }
171
+
172
+ /**
173
+ * ADR-013 Phase 6 cutover (Stage 2a): read **all** decisions (active +
174
+ * superseded) from the `memories` table. Used by the DECISIONS.md
175
+ * projection regen in `saveDecisionToDb`, which must render the full
176
+ * supersedes-chain for the canonical register format.
177
+ *
178
+ * Equivalent to `SELECT * FROM decisions ORDER BY seq` over the legacy
179
+ * table — but sourced from memories so the legacy table can be retired
180
+ * in Stage 3. Includes `superseded_by` reconstructed from
181
+ * `structured_fields.superseded_by` (populated by the backfill's drift
182
+ * auto-heal pass).
183
+ */
184
+ export function getAllDecisionsFromMemories(): Decision[] {
185
+ return readDecisionsFromMemories(undefined, /* includeSuperseded */ true);
186
+ }
187
+
69
188
  /**
70
189
  * Query active (non-superseded) requirements with optional filters.
71
190
  * - milestoneId: combined with sliceId for precise filtering (e.g. %M005/S01%)