gsd-pi 2.81.0-dev.72a81bdf3 → 2.82.0-dev.725028083
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.
- package/README.md +46 -28
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/gsd/auto/phases.js +9 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +11 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +5 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +6 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +3 -2
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +2 -0
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/gsd/auto/phases.ts +14 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +6 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → KDRTXR-22LPCsa80X9dey}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → KDRTXR-22LPCsa80X9dey}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -27,38 +27,46 @@ One command. Walk away. Come back to a built project with clean git history.
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
## What's New in v2.
|
|
30
|
+
## What's New in v2.82
|
|
31
31
|
|
|
32
|
-
###
|
|
32
|
+
### State Reconciliation & Drift Detection (ADR-017)
|
|
33
33
|
|
|
34
|
-
- **
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
38
|
-
- **
|
|
34
|
+
- **Unified drift-detection framework** — a new state-reconciliation layer replaces ad-hoc recovery checks. Each drift kind (stale worker, unregistered milestone, roadmap divergence, missing completion timestamp, merge-state, stale render) is owned by a focused detector + idempotent repair handler registered in a single registry, with a cap=2 retry contract that ensures repair-then-retry settles cleanly.
|
|
35
|
+
- **Stale session locks no longer block resume** — when a `/gsd auto` process is SIGKILL'd, sleep-killed, or otherwise crashes, the `auto.lock` file is left behind with a dead PID. Previously you had to wait out a 30-minute stale window before `/gsd` would resume. The new `stale-worker` drift handler verifies the PID is alive and clears orphaned locks proactively on startup.
|
|
36
|
+
- **Unregistered milestones get imported automatically** — if you scaffold a milestone directory (with `ROADMAP.md`/`CONTEXT.md`/`SUMMARY.md`) but never re-imported, dispatch couldn't see it. The `unregistered-milestone` handler now imports those rows idempotently before dispatch.
|
|
37
|
+
- **ROADMAP and DB stay in sync** — divergence between `ROADMAP.md` (parsed slice sequence + `depends` declarations) and the corresponding DB slice rows is detected per-milestone and reconciled via importer upserts plus an explicit `syncSliceDependencies` pass.
|
|
38
|
+
- **Missing completion timestamps backfill from disk** — entities marked complete in the DB but with a null `completed_at` are now backfilled from `SUMMARY.md` mtime, deterministically and idempotently. Tasks are checked independently of their parent slice status (a bug in the first cut nested task iteration behind slice completion).
|
|
39
|
+
- **Parallel spawns reconcile before fanning out** — `/gsd parallel start` and slice-parallel-dispatch now run reconciliation at the parent before spawning auto-loop workers, so workers don't independently race on shared drift. Gate failures surface a typed exit reason (`slice-parallel-reconciliation-failed`) and a user-visible message instead of a confused hang.
|
|
39
40
|
|
|
40
|
-
###
|
|
41
|
+
### Worktree Lifecycle Refactor (ADR-016 — final phases)
|
|
41
42
|
|
|
42
|
-
- **
|
|
43
|
-
- **
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
43
|
+
- **Phase 2 complete** — the worktree-manager module finished absorbing fs primitives, git-CLI primitives, worktree-manager helpers, cache/preferences/paths, and the final `gitServiceFactory`. Lifecycle verbs are now first-class: `adoptOrphanWorktree`, `adoptSessionRoot`, `resumeFromPausedSession`, and `restoreToProjectRoot` are explicit entry points, and the stop-path routes through `restoreToProjectRoot` instead of ad-hoc cleanup. `mergeMilestoneStandalone` was extracted and `mergeMilestoneToMain` was privatized.
|
|
44
|
+
- **Phase 3 closes strict-closure residuals** — dead defensive `s.basePath = s.originalBasePath` fallbacks were removed from both auto.ts stop-path catch blocks (the verb assigns `basePath` before any throwable work, so the fallback was unreachable). The public `WorktreeLifecycleDeps` interface dropped 15 `@deprecated` optional fields; the active dep bag is now three fields (`gitServiceFactory`, `worktreeProjection`, `mergeMilestoneToMain`). Test fixtures move to a dedicated `WorktreeLifecycleTestOverrides` type.
|
|
45
|
+
|
|
46
|
+
### Auto-Mode Reliability
|
|
47
|
+
|
|
48
|
+
- **`complete-slice` closeout is read-only** — the closeout prompt is no longer allowed to write project files, removing a class of races where closeout edits could fight with the next slice's setup. Write-gate planning and prompt contracts were updated to enforce this.
|
|
49
|
+
- **Verification retries back off properly** — a new `verification-retry-policy.ts` adds bounded exponential backoff and runs stuck detection between attempts, so transient verification failures (slow tools, flaky LLM calls) no longer spin in tight retry loops.
|
|
50
|
+
- **Auto-loop exit paths are journaled end-to-end** — post-unit finalize stops, all unit-end iteration exits, and the run-unit failsafe now journal cleanly. Auto-timeout recovery journaling completes its handoff record. The run-unit failsafe also defers when a recovery is already in flight to avoid double-firing.
|
|
51
|
+
- **Ghost completions and stale telemetry are guarded** — auto-mode no longer stops on ghost completions before a milestone stop has actually fired, and unmerged-exit telemetry is gated on active worktrees so closed sessions don't generate noise.
|
|
52
|
+
- **Session-switch hygiene** — completed-content aborts that fire while the session is switching are ignored instead of being misclassified as user aborts. Auto-commit skips `.gitignore`d task key files so the working tree stays clean across slices.
|
|
48
53
|
|
|
49
54
|
### TUI & Operator Experience
|
|
50
55
|
|
|
51
|
-
- **
|
|
52
|
-
- **
|
|
53
|
-
- **Auto-mode stays anchored** — bottom anchoring, direct tool execution rollups, and lifecycle hook shutdown behavior were tightened.
|
|
56
|
+
- **Operations console redesign** — the auto-mode dashboard, notification overlay, parallel-monitor overlay, health widget, header renderer, and welcome screen were all rebuilt against a new shared `render-kit`. The result is a more consistent visual language across overlays, with refreshed reference designs (`docs/dev/tui-recommended-design.html`, `tui-render-options.html`) and expanded test coverage for the new components.
|
|
57
|
+
- **Milestone completion rollup** — at the boundary between milestones, auto-mode now renders a `CompletionDashboardSnapshot` summarizing success criteria results, definition-of-done results, requirement outcomes, deviations, follow-ups, key decisions, key files, lessons learned, total cost, total tokens, cache hit rate, and slice progress. You no longer have to scroll back through the transcript to see what a milestone actually delivered.
|
|
54
58
|
|
|
55
|
-
|
|
59
|
+
See the full [Changelog](./CHANGELOG.md) for the complete v2.82 entry and prior releases.
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
- **CI is faster and less noisy** — merge/build gates were simplified, expensive PR jobs are gated, and merge-conflict PRs skip heavy jobs.
|
|
61
|
+
<details>
|
|
62
|
+
<summary>v2.81 highlights</summary>
|
|
60
63
|
|
|
61
|
-
|
|
64
|
+
- **Worktree safety is fail-closed** — write/edit operations enforce the worktree-isolation contract; lifecycle and projection split into dedicated modules; milestone merge closeout is harder to wedge.
|
|
65
|
+
- **Memory, context, and token control** — artifact integrity fingerprints, time-decay memory ranking, safer FTS5 fallback, request-time tool scoping, leaner workflow prompts, and more accurate session/context token accounting.
|
|
66
|
+
- **TUI polish** — compact tool output with targets, refreshed chat/tool cards, adaptive refresher layouts, stable welcome/header lifecycle, and bottom-anchored auto-mode rendering.
|
|
67
|
+
- **Reliability, tests, and CI** — auto-mode recovery and session handoff hardened, broad E2E coverage expansion (real-process MCP, fake LLM, native ABI, Docker, Windows), and a faster, less-noisy CI gate setup.
|
|
68
|
+
|
|
69
|
+
</details>
|
|
62
70
|
|
|
63
71
|
<details>
|
|
64
72
|
<summary>v2.80 highlights</summary>
|
|
@@ -108,7 +116,7 @@ See the full [Changelog](./CHANGELOG.md) for the complete v2.81 entry and prior
|
|
|
108
116
|
|
|
109
117
|
- **Context Mode** — dispatch builds task-ready context automatically (artifacts, prior session, milestone/slice signals, execution metadata); enabled by default for new projects
|
|
110
118
|
- **Sandboxed execution tools** — `gsd_exec_search`, `gsd_resume`, and sandboxed tool-output paths for context-mode flows
|
|
111
|
-
- **Memory architecture (ADR-013)** — `memories` table is now authoritative; `structured_fields` adds typed metadata;
|
|
119
|
+
- **Memory architecture (ADR-013)** — `memories` table is now authoritative; `structured_fields` adds typed metadata; decisions and KNOWLEDGE patterns/lessons are memory-backed projections after the cutover
|
|
112
120
|
- **Skill coverage** — 9 gap-closing skills landed plus 6 planning/design skills surfaced
|
|
113
121
|
- **Hook stack** — Layer 0 shell hooks and additional Layer 2 lifecycle events
|
|
114
122
|
- **TUI polish** — dedicated chat-frame style for skill invocations; active-row overflow fixes
|
|
@@ -330,6 +338,8 @@ Plan (with integrated research) → Execute (per task) → Complete → Reassess
|
|
|
330
338
|
|
|
331
339
|
**Plan** scouts the codebase, researches relevant docs, and decomposes the slice into tasks with must-haves (mechanically verifiable outcomes). **Execute** runs each task in a fresh context window with only the relevant files pre-loaded — then runs configured verification commands (lint, test, etc.) with auto-fix retries. **Complete** writes the summary, UAT script, marks the roadmap, and commits with meaningful messages derived from task summaries. **Reassess** checks if the roadmap still makes sense given what was learned. **Validate Milestone** runs a reconciliation gate after all slices complete — comparing roadmap success criteria against actual results before sealing the milestone.
|
|
332
340
|
|
|
341
|
+
When progressive planning is enabled, the first slice is fully planned up front while later slices may appear in `M###-ROADMAP.md` with a `` `[sketch]` `` badge. A sketch slice has an approved title, dependency shape, demo line, and scope boundary, but it has not yet been expanded into task plans; auto mode runs `refine-slice` just before execution to turn the sketch into a full slice plan using the latest prior-slice summaries.
|
|
342
|
+
|
|
333
343
|
### `/gsd auto` — The Main Event
|
|
334
344
|
|
|
335
345
|
This is what makes GSD different. Run it, walk away, come back to built software.
|
|
@@ -340,7 +350,9 @@ This is what makes GSD different. Run it, walk away, come back to built software
|
|
|
340
350
|
|
|
341
351
|
Auto mode is a state machine driven by the GSD database at the project root. It derives the next unit of work from authoritative SQLite state, creates a fresh agent session, injects a focused prompt with all relevant context pre-inlined, and lets the LLM execute. When the LLM finishes, auto mode persists the result to the database, refreshes markdown projections such as `STATE.md`, and dispatches the next unit.
|
|
342
352
|
|
|
343
|
-
The database is authoritative for milestones, slices, tasks, requirements,
|
|
353
|
+
The database is authoritative for milestones, slices, tasks, requirements, summaries, and completion status. Durable decisions and project knowledge are stored in the `memories` table: decisions are `architecture` memories, and KNOWLEDGE patterns/lessons are `pattern`/`gotcha` memories. Markdown under `.gsd/` is a rendered projection for review, prompts, and git-friendly history; it is not a runtime fallback unless you explicitly run a recovery/import command. In worktree mode, project-root DB state remains authoritative and worktree markdown projections are not synced back as state.
|
|
354
|
+
|
|
355
|
+
`KNOWLEDGE.md` is hybrid: rules remain file-canonical, while patterns and lessons are stored in the `memories` table and rendered back into `KNOWLEDGE.md` on the next session-start projection. Existing pattern and lesson rows are backfilled into memories before projection, so newly captured patterns and lessons may appear in memory-backed prompt context before the file view refreshes.
|
|
344
356
|
|
|
345
357
|
**What happens under the hood:**
|
|
346
358
|
|
|
@@ -534,13 +546,13 @@ Every dispatch is carefully constructed. The LLM never wastes tool calls on orie
|
|
|
534
546
|
| `gsd.db` | Authoritative runtime state for hierarchy and completion |
|
|
535
547
|
| `PROJECT.md` | Living doc — what the project is right now |
|
|
536
548
|
| `REQUIREMENTS.md` | Project-level capability contract and out-of-scope list |
|
|
537
|
-
| `DECISIONS.md` |
|
|
538
|
-
| `KNOWLEDGE.md` |
|
|
549
|
+
| `DECISIONS.md` | Projected register of memory-backed architectural decisions |
|
|
550
|
+
| `KNOWLEDGE.md` | Hybrid knowledge projection: manual Rules plus memory-backed Patterns/Lessons |
|
|
539
551
|
| `RUNTIME.md` | Runtime context — API endpoints, env vars, services (v2.39) |
|
|
540
552
|
| `runtime/research-decision.json` | Deep-mode marker for project research vs skip |
|
|
541
553
|
| `research/*.md` | Optional deep-mode project research: stack, features, architecture, pitfalls |
|
|
542
554
|
| `STATE.md` | Quick-glance dashboard rendered from the database |
|
|
543
|
-
| `M001-ROADMAP.md` | Milestone plan with slice checkboxes, risk levels, dependencies |
|
|
555
|
+
| `M001-ROADMAP.md` | Milestone plan with slice checkboxes, risk levels, dependencies, and `` `[sketch]` `` badges for slices awaiting `refine-slice` |
|
|
544
556
|
| `M001-CONTEXT.md` | User decisions from the discuss phase |
|
|
545
557
|
| `M001-RESEARCH.md` | Codebase and ecosystem research |
|
|
546
558
|
| `S01-PLAN.md` | Slice task decomposition with must-haves |
|
|
@@ -577,6 +589,12 @@ Every task has must-haves — mechanically checkable outcomes:
|
|
|
577
589
|
|
|
578
590
|
The verification ladder: static checks → command execution → behavioral testing → human review (only when the agent genuinely can't verify itself).
|
|
579
591
|
|
|
592
|
+
### Project Knowledge
|
|
593
|
+
|
|
594
|
+
`.gsd/KNOWLEDGE.md` remains the human-readable register for durable project knowledge, but the memory store is now authoritative for generated Patterns and Lessons. On startup, GSD backfills existing `## Patterns` and `## Lessons Learned` rows into `gsd.db` memories, then rewrites `KNOWLEDGE.md` as a hybrid projection: the manual `## Rules` section is preserved from the file, while Patterns and Lessons are rendered from the backfilled memory rows.
|
|
595
|
+
|
|
596
|
+
Keep hand-authored operating rules in `## Rules` or add them with `/gsd knowledge rule`. Patterns and Lessons that agents discover are retrieved through the memory system for prompts and projected back into `KNOWLEDGE.md` for review, reports, and git history.
|
|
597
|
+
|
|
580
598
|
### Dashboard
|
|
581
599
|
|
|
582
600
|
`Ctrl+Alt+G` or `/gsd status` opens a real-time overlay showing:
|
|
@@ -821,7 +839,7 @@ gsd (CLI binary)
|
|
|
821
839
|
- **`pkg/` shim directory** — `PI_PACKAGE_DIR` points here (not project root) to avoid Pi's theme resolution collision with our `src/` directory. Contains only `piConfig` and theme assets.
|
|
822
840
|
- **Two-file loader pattern** — `loader.ts` sets all env vars with zero SDK imports, then dynamic-imports `cli.ts` which does static SDK imports. This ensures `PI_PACKAGE_DIR` is set before any SDK code evaluates.
|
|
823
841
|
- **Always-overwrite sync** — `npm update -g` takes effect immediately. Bundled extensions and agents are synced to `~/.gsd/agent/` on every launch, not just first run.
|
|
824
|
-
- **DB-authoritative state** — the project-root GSD database is the runtime source of truth. `.gsd/` markdown files are rendered projections for review, prompt context, and git history. No in-memory state survives across sessions.
|
|
842
|
+
- **DB-authoritative state** — the project-root GSD database is the runtime source of truth. `.gsd/` markdown files are rendered projections for review, prompt context, and git history. `KNOWLEDGE.md` keeps rules file-canonical and projects patterns/lessons from `memories` at session start. No in-memory state survives across sessions.
|
|
825
843
|
|
|
826
844
|
---
|
|
827
845
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
5c6d4acc2e1d8c2b
|
|
@@ -5,6 +5,7 @@ export function registerScreenshotTools(pi, deps) {
|
|
|
5
5
|
name: "browser_screenshot",
|
|
6
6
|
label: "Browser Screenshot",
|
|
7
7
|
description: "Take a screenshot of the current browser page and return it as an inline image. Uses JPEG for viewport/fullpage (smaller, configurable quality) and PNG for element crops (preserves transparency). Optionally crop to a specific element by CSS selector.",
|
|
8
|
+
compatibility: { producesImages: true },
|
|
8
9
|
parameters: Type.Object({
|
|
9
10
|
fullPage: Type.Optional(Type.Boolean({ description: "Capture the full scrollable page (default: false)" })),
|
|
10
11
|
selector: Type.Optional(Type.String({
|
|
@@ -9,6 +9,7 @@ export function registerZoomTools(pi, deps) {
|
|
|
9
9
|
description: "Capture and optionally upscale a specific rectangular region of the page for detailed inspection. " +
|
|
10
10
|
"Useful for dense UIs where full-page screenshots have text too small to read. " +
|
|
11
11
|
"Returns the region as an inline image, same as browser_screenshot.",
|
|
12
|
+
compatibility: { producesImages: true },
|
|
12
13
|
parameters: Type.Object({
|
|
13
14
|
x: Type.Number({ description: "Left coordinate of the region in CSS pixels." }),
|
|
14
15
|
y: Type.Number({ description: "Top coordinate of the region in CSS pixels." }),
|
|
@@ -1656,6 +1656,15 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1656
1656
|
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1657
1657
|
return { action: "break", reason: "session-timeout" };
|
|
1658
1658
|
}
|
|
1659
|
+
if (unitResult.errorContext?.isTransient &&
|
|
1660
|
+
errorCategory === "aborted") {
|
|
1661
|
+
ctx.ui.notify(`Unit ${unitType} ${unitId} was aborted by the user. Pausing auto-mode (recoverable).`, "warning");
|
|
1662
|
+
debugLog("autoLoop", { phase: "unit-aborted-transient-pause", unitType, unitId, category: errorCategory });
|
|
1663
|
+
await deps.pauseAuto(ctx, pi);
|
|
1664
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
1665
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
1666
|
+
return { action: "break", reason: "unit-aborted-pause" };
|
|
1667
|
+
}
|
|
1659
1668
|
// All other cancelled states (structural errors, non-transient failures): hard stop
|
|
1660
1669
|
if (s.currentUnit) {
|
|
1661
1670
|
await deps.closeoutUnit(ctx, s.basePath, unitType, unitId, s.currentUnit.startedAt, deps.buildSnapshotOpts(unitType, unitId));
|
|
@@ -728,12 +728,20 @@ export async function inlineDecisionsFromDb(base, milestoneId, scope, level) {
|
|
|
728
728
|
try {
|
|
729
729
|
const { isDbAvailable } = await import("./gsd-db.js");
|
|
730
730
|
if (isDbAvailable()) {
|
|
731
|
-
|
|
731
|
+
// ADR-013 Phase 6 cutover (Stage 1): read decisions from the `memories`
|
|
732
|
+
// table. Both `queryDecisions` (legacy) and `queryDecisionsFromMemories`
|
|
733
|
+
// return identical Decision[] for active rows once Phase 5 dual-write is
|
|
734
|
+
// caught up. Switching the read here lets the destructive Phase 6 step
|
|
735
|
+
// (#5755) retire the legacy `decisions` table without changing prompt
|
|
736
|
+
// contents. Projection regen (`DECISIONS.md`) still sources from the
|
|
737
|
+
// legacy table — that switch lands separately to handle superseded
|
|
738
|
+
// history cleanly.
|
|
739
|
+
const { queryDecisionsFromMemories, formatDecisionsForPrompt } = await import("./context-store.js");
|
|
732
740
|
// First query: try with both milestoneId and scope (if scope provided)
|
|
733
|
-
let decisions =
|
|
741
|
+
let decisions = queryDecisionsFromMemories({ milestoneId, scope });
|
|
734
742
|
// Cascade: if empty AND scope was provided, retry without scope
|
|
735
743
|
if (decisions.length === 0 && scope) {
|
|
736
|
-
decisions =
|
|
744
|
+
decisions = queryDecisionsFromMemories({ milestoneId });
|
|
737
745
|
}
|
|
738
746
|
if (decisions.length > 0) {
|
|
739
747
|
// Use compact format for non-full levels to save ~35% tokens
|
|
@@ -355,6 +355,9 @@ async function writeContextModeCompactionSnapshot(basePath) {
|
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
357
|
export function registerHooks(pi, ecosystemHandlers) {
|
|
358
|
+
// ADR-005 Phase 3b: surface pi-ai ProviderSwitchReport via audit, notification, and counter.
|
|
359
|
+
// Idempotent — only the first registerHooks call installs.
|
|
360
|
+
void import("../provider-switch-observer.js").then((m) => m.installProviderSwitchObserver());
|
|
358
361
|
pi.on("session_start", async (_event, ctx) => {
|
|
359
362
|
const basePath = contextBasePath(ctx);
|
|
360
363
|
initSessionNotifications(ctx);
|
|
@@ -411,6 +414,8 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
411
414
|
}
|
|
412
415
|
await loadToolApiKeysForSession();
|
|
413
416
|
if (!isAutoActive()) {
|
|
417
|
+
ctx.ui.setWidget("gsd-progress", undefined);
|
|
418
|
+
ctx.ui.setWidget("gsd-outcome", undefined);
|
|
414
419
|
const { initHealthWidget } = await import("../health-widget.js");
|
|
415
420
|
initHealthWidget(ctx);
|
|
416
421
|
}
|
|
@@ -10,6 +10,7 @@ import { resolveAllSkillReferences, renderPreferencesForSystemPrompt, loadEffect
|
|
|
10
10
|
import { resolveModelWithFallbacksForUnit } from "../preferences-models.js";
|
|
11
11
|
import { resolveSkillReference } from "../preferences-skills.js";
|
|
12
12
|
import { resolveGsdRootFile, resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTaskFiles, resolveTasksDir, relSliceFile, relSlicePath, relTaskFile } from "../paths.js";
|
|
13
|
+
import { extractIntroAndRules } from "../knowledge-parser.js";
|
|
13
14
|
import { ensureCodebaseMapFresh, readCodebaseMap } from "../codebase-generator.js";
|
|
14
15
|
import { hasSkillSnapshot, detectNewSkills, formatSkillsXml } from "../skill-discovery.js";
|
|
15
16
|
import { getActiveAutoWorktreeContext } from "../auto-worktree.js";
|
|
@@ -116,19 +117,19 @@ export async function buildBeforeAgentStartResult(event, ctx) {
|
|
|
116
117
|
catch (e) {
|
|
117
118
|
logWarning("bootstrap", `cmux prompt setup skipped: ${e.message}`);
|
|
118
119
|
}
|
|
120
|
+
const ctxProjectRoot = ctx.projectRoot;
|
|
121
|
+
const basePath = typeof ctxProjectRoot === "string" && ctxProjectRoot.length > 0
|
|
122
|
+
? ctxProjectRoot
|
|
123
|
+
: process.cwd();
|
|
119
124
|
let preferenceBlock = "";
|
|
120
125
|
if (loadedPreferences) {
|
|
121
|
-
const cwd =
|
|
126
|
+
const cwd = basePath;
|
|
122
127
|
const report = resolveAllSkillReferences(loadedPreferences.preferences, cwd);
|
|
123
128
|
preferenceBlock = `\n\n${renderPreferencesForSystemPrompt(loadedPreferences.preferences, report.resolutions)}`;
|
|
124
129
|
if (report.warnings.length > 0) {
|
|
125
130
|
ctx.ui.notify(`GSD skill preferences: ${report.warnings.length} unresolved skill${report.warnings.length === 1 ? "" : "s"}: ${report.warnings.join(", ")}`, "warning");
|
|
126
131
|
}
|
|
127
132
|
}
|
|
128
|
-
const { block: knowledgeBlock, globalSizeKb } = loadKnowledgeBlock(gsdHome(), process.cwd());
|
|
129
|
-
if (globalSizeKb > 4) {
|
|
130
|
-
ctx.ui.notify(`GSD: ~/.gsd/agent/KNOWLEDGE.md is ${globalSizeKb.toFixed(1)}KB — consider trimming to keep system prompt lean.`, "warning");
|
|
131
|
-
}
|
|
132
133
|
// ADR-013 step 5: opportunistic decisions->memories backfill. Idempotent
|
|
133
134
|
// and best-effort — first run absorbs the existing decisions table into
|
|
134
135
|
// the memory store; subsequent runs are a single sentinel SELECT.
|
|
@@ -136,12 +137,47 @@ export async function buildBeforeAgentStartResult(event, ctx) {
|
|
|
136
137
|
const { backfillDecisionsToMemories } = await import("../memory-backfill.js");
|
|
137
138
|
const written = backfillDecisionsToMemories();
|
|
138
139
|
if (written > 0) {
|
|
139
|
-
ctx.ui.notify(`GSD: backfilled ${written} decision${written === 1 ? "" : "s"} into the memory store
|
|
140
|
+
ctx.ui.notify(`GSD: backfilled ${written} decision${written === 1 ? "" : "s"} into the memory store.`, "info");
|
|
140
141
|
}
|
|
141
142
|
}
|
|
142
143
|
catch (e) {
|
|
143
144
|
logWarning("bootstrap", `decisions backfill failed: ${e.message}`);
|
|
144
145
|
}
|
|
146
|
+
// ADR-013 Stage 2b: KNOWLEDGE.md Patterns + Lessons backfill, then
|
|
147
|
+
// re-render the hybrid projection (manual Rules + projected Patterns +
|
|
148
|
+
// projected Lessons). Both are idempotent and best-effort — failures here
|
|
149
|
+
// can't block agent startup.
|
|
150
|
+
try {
|
|
151
|
+
const { backfillKnowledgeToMemories } = await import("../knowledge-backfill.js");
|
|
152
|
+
const writtenK = backfillKnowledgeToMemories(basePath);
|
|
153
|
+
if (writtenK > 0) {
|
|
154
|
+
ctx.ui.notify(`GSD: backfilled ${writtenK} KNOWLEDGE.md row${writtenK === 1 ? "" : "s"} into the memory store.`, "info");
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
logWarning("bootstrap", `KNOWLEDGE.md backfill failed: ${e.message}`);
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const { renderKnowledgeProjection } = await import("../knowledge-projection.js");
|
|
162
|
+
renderKnowledgeProjection(basePath);
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
logWarning("bootstrap", `KNOWLEDGE.md projection render failed: ${e.message}`);
|
|
166
|
+
}
|
|
167
|
+
// ADR-013 step 6 preflight: warn when decisions / KNOWLEDGE.md rows are not
|
|
168
|
+
// yet in the memories table. Read-only; never throws. Runs after the two
|
|
169
|
+
// backfills above so the gap report reflects post-backfill state.
|
|
170
|
+
try {
|
|
171
|
+
const { reportConsolidationGaps } = await import("../memory-consolidation-scanner.js");
|
|
172
|
+
reportConsolidationGaps(basePath);
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
logWarning("bootstrap", `memory consolidation scan failed: ${e.message}`);
|
|
176
|
+
}
|
|
177
|
+
const { block: knowledgeBlock, globalSizeKb } = loadKnowledgeBlock(gsdHome(), basePath);
|
|
178
|
+
if (globalSizeKb > 4) {
|
|
179
|
+
ctx.ui.notify(`GSD: ~/.gsd/agent/KNOWLEDGE.md is ${globalSizeKb.toFixed(1)}KB — consider trimming to keep system prompt lean.`, "warning");
|
|
180
|
+
}
|
|
145
181
|
let newSkillsBlock = "";
|
|
146
182
|
if (hasSkillSnapshot()) {
|
|
147
183
|
const newSkills = detectNewSkills();
|
|
@@ -320,7 +356,9 @@ export async function loadMemoryBlock(userPrompt, opts = {}) {
|
|
|
320
356
|
}
|
|
321
357
|
}
|
|
322
358
|
export function loadKnowledgeBlock(gsdHomeDir, cwd) {
|
|
323
|
-
// 1. Global knowledge (~/.gsd/agent/KNOWLEDGE.md) — cross-project,
|
|
359
|
+
// 1. Global knowledge (~/.gsd/agent/KNOWLEDGE.md) — cross-project,
|
|
360
|
+
// user-maintained. NOT migrated to memories (which are project-scoped),
|
|
361
|
+
// so the full file is injected unchanged.
|
|
324
362
|
let globalKnowledge = "";
|
|
325
363
|
let globalSizeKb = 0;
|
|
326
364
|
const globalKnowledgePath = join(gsdHomeDir, "agent", "KNOWLEDGE.md");
|
|
@@ -336,14 +374,19 @@ export function loadKnowledgeBlock(gsdHomeDir, cwd) {
|
|
|
336
374
|
logWarning("bootstrap", `global knowledge file read failed: ${e.message}`);
|
|
337
375
|
}
|
|
338
376
|
}
|
|
339
|
-
// 2. Project knowledge (.gsd/KNOWLEDGE.md) — project-specific
|
|
377
|
+
// 2. Project knowledge (.gsd/KNOWLEDGE.md) — project-specific.
|
|
378
|
+
// ADR-013 Stage 2b: Patterns and Lessons are projected from the
|
|
379
|
+
// memories table and already reach the LLM via loadMemoryBlock. Inject
|
|
380
|
+
// only the intro prose + `## Rules` section here to avoid duplicating
|
|
381
|
+
// Patterns/Lessons content in the prompt. Rules stay manual per
|
|
382
|
+
// ADR-013 line 39 and have no memory equivalent.
|
|
340
383
|
let projectKnowledge = "";
|
|
341
384
|
const knowledgePath = resolveGsdRootFile(cwd, "KNOWLEDGE");
|
|
342
385
|
if (existsSync(knowledgePath)) {
|
|
343
386
|
try {
|
|
344
|
-
const
|
|
345
|
-
if (
|
|
346
|
-
projectKnowledge =
|
|
387
|
+
const raw = readFileSync(knowledgePath, "utf-8").trim();
|
|
388
|
+
if (raw)
|
|
389
|
+
projectKnowledge = extractIntroAndRules(raw).trim();
|
|
347
390
|
}
|
|
348
391
|
catch (e) {
|
|
349
392
|
logWarning("bootstrap", `project knowledge file read failed: ${e.message}`);
|
|
@@ -361,7 +404,7 @@ export function loadKnowledgeBlock(gsdHomeDir, cwd) {
|
|
|
361
404
|
}
|
|
362
405
|
const body = limitKnowledgeBlock(parts.join("\n\n"), getKnowledgeCharLimit());
|
|
363
406
|
return {
|
|
364
|
-
block: `\n\n[KNOWLEDGE — Rules
|
|
407
|
+
block: `\n\n[KNOWLEDGE — Rules from KNOWLEDGE.md (Patterns and Lessons reach the LLM via the memory block)]\n\n${body}`,
|
|
365
408
|
globalSizeKb,
|
|
366
409
|
};
|
|
367
410
|
}
|
|
@@ -90,7 +90,7 @@ export function showHelp(ctx, args = "") {
|
|
|
90
90
|
" /gsd unpark [id] Reactivate a parked milestone",
|
|
91
91
|
"",
|
|
92
92
|
"PROJECT KNOWLEDGE",
|
|
93
|
-
" /gsd knowledge <type> <text> Add rule
|
|
93
|
+
" /gsd knowledge <type> <text> Add a rule to KNOWLEDGE.md or capture a pattern/lesson to memories",
|
|
94
94
|
" /gsd codebase [generate|update|stats] Manage the CODEBASE.md cache used in prompt context",
|
|
95
95
|
"",
|
|
96
96
|
"SHIPPING & BACKLOG",
|
|
@@ -303,8 +303,21 @@ export async function handleKnowledge(args, ctx) {
|
|
|
303
303
|
const scope = state.activeMilestone?.id
|
|
304
304
|
? `${state.activeMilestone.id}${state.activeSlice ? `/${state.activeSlice.id}` : ""}`
|
|
305
305
|
: "global";
|
|
306
|
-
|
|
307
|
-
|
|
306
|
+
// ADR-013 Stage 2c: Patterns and Lessons land in the memories table; the
|
|
307
|
+
// next session-start projection render emits them back into KNOWLEDGE.md.
|
|
308
|
+
// Rules stay file-canonical per ADR-013 line 39 — Rules are not migrated.
|
|
309
|
+
if (type === "rule") {
|
|
310
|
+
await appendKnowledge(basePath, type, entryText, scope);
|
|
311
|
+
ctx.ui.notify(`Added rule to KNOWLEDGE.md: "${entryText}"`, "success");
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const { captureKnowledgeEntry } = await import("./knowledge-capture.js");
|
|
315
|
+
const { id, written } = captureKnowledgeEntry(basePath, type, entryText, scope);
|
|
316
|
+
if (!written) {
|
|
317
|
+
ctx.ui.notify(`Could not persist ${type} — see logs for details.`, "error");
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
ctx.ui.notify(`Captured ${type} ${id} to memories; KNOWLEDGE.md will render it on next session start.`, "success");
|
|
308
321
|
}
|
|
309
322
|
export async function handleRunHook(args, ctx, pi) {
|
|
310
323
|
const parts = args.trim().split(/\s+/);
|
|
@@ -47,6 +47,118 @@ export function queryDecisions(opts) {
|
|
|
47
47
|
return [];
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Internal: shared core for the two memory-sourced decision queries. Reads
|
|
52
|
+
* memory rows tagged with `sourceDecisionId` and reconstructs `Decision[]`
|
|
53
|
+
* from their `structured_fields` JSON.
|
|
54
|
+
*
|
|
55
|
+
* @param includeSuperseded — when false, drops rows whose
|
|
56
|
+
* `structured_fields.superseded_by` is non-null. The supersedes-chain is
|
|
57
|
+
* captured by the backfill (`memory-backfill.ts`) and kept in sync by
|
|
58
|
+
* the backfill's drift auto-heal pass.
|
|
59
|
+
*/
|
|
60
|
+
function readDecisionsFromMemories(opts, includeSuperseded) {
|
|
61
|
+
if (!isDbAvailable())
|
|
62
|
+
return [];
|
|
63
|
+
const adapter = _getAdapter();
|
|
64
|
+
if (!adapter)
|
|
65
|
+
return [];
|
|
66
|
+
try {
|
|
67
|
+
const clauses = [
|
|
68
|
+
"category = 'architecture'",
|
|
69
|
+
"structured_fields LIKE '%\"sourceDecisionId\":\"%'",
|
|
70
|
+
];
|
|
71
|
+
const params = {};
|
|
72
|
+
if (opts?.milestoneId) {
|
|
73
|
+
// when_context is a free-text JSON value; substring match preserves the
|
|
74
|
+
// semantics of `when_context LIKE '%milestoneId%'` on the legacy table.
|
|
75
|
+
clauses.push("json_extract(structured_fields, '$.when_context') LIKE :milestone_pattern");
|
|
76
|
+
params[':milestone_pattern'] = `%${opts.milestoneId}%`;
|
|
77
|
+
}
|
|
78
|
+
if (opts?.scope) {
|
|
79
|
+
// Stage 1 used `json_extract` in main (post-merge); preserve that
|
|
80
|
+
// style here. Exact equality on the JSON value avoids the prefix
|
|
81
|
+
// collision risk LIKE patterns had (scope=M001 vs scope=M001-S01).
|
|
82
|
+
clauses.push("json_extract(structured_fields, '$.scope') = :scope");
|
|
83
|
+
params[':scope'] = opts.scope;
|
|
84
|
+
}
|
|
85
|
+
const sql = `SELECT seq, structured_fields FROM memories WHERE ${clauses.join(' AND ')} ORDER BY seq`;
|
|
86
|
+
const rows = adapter.prepare(sql).all(params);
|
|
87
|
+
const decisions = [];
|
|
88
|
+
for (const row of rows) {
|
|
89
|
+
const seq = row['seq'];
|
|
90
|
+
const sfRaw = row['structured_fields'];
|
|
91
|
+
if (!sfRaw)
|
|
92
|
+
continue;
|
|
93
|
+
let sf;
|
|
94
|
+
try {
|
|
95
|
+
sf = JSON.parse(sfRaw);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const sourceId = sf['sourceDecisionId'];
|
|
101
|
+
if (typeof sourceId !== 'string' || sourceId.length === 0)
|
|
102
|
+
continue;
|
|
103
|
+
// Decision-level superseded status lives in structured_fields.superseded_by
|
|
104
|
+
// (written by mirrorDecisionToMemory / memory-backfill.ts). The top-level
|
|
105
|
+
// memories.superseded_by column is intentionally never set for decision mirrors,
|
|
106
|
+
// so active-only filtering must be done here in the JS loop.
|
|
107
|
+
const supersededBy = typeof sf['superseded_by'] === 'string' ? sf['superseded_by'] : null;
|
|
108
|
+
if (!includeSuperseded && supersededBy)
|
|
109
|
+
continue;
|
|
110
|
+
decisions.push({
|
|
111
|
+
seq,
|
|
112
|
+
id: sourceId,
|
|
113
|
+
when_context: typeof sf['when_context'] === 'string' ? sf['when_context'] : '',
|
|
114
|
+
scope: typeof sf['scope'] === 'string' ? sf['scope'] : '',
|
|
115
|
+
decision: typeof sf['decision'] === 'string' ? sf['decision'] : '',
|
|
116
|
+
choice: typeof sf['choice'] === 'string' ? sf['choice'] : '',
|
|
117
|
+
rationale: typeof sf['rationale'] === 'string' ? sf['rationale'] : '',
|
|
118
|
+
revisable: typeof sf['revisable'] === 'string' ? sf['revisable'] : '',
|
|
119
|
+
made_by: (typeof sf['made_by'] === 'string' ? sf['made_by'] : 'agent'),
|
|
120
|
+
superseded_by: supersededBy,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return decisions;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* ADR-013 Phase 6 cutover (Stage 1): read **active** decisions from the
|
|
131
|
+
* `memories` table instead of the legacy `decisions` table. Returns the
|
|
132
|
+
* same `Decision[]` shape as `queryDecisions` so downstream formatters
|
|
133
|
+
* work unchanged.
|
|
134
|
+
*
|
|
135
|
+
* Filter semantics match `queryDecisions` exactly:
|
|
136
|
+
* - active only (skips rows where `structured_fields.superseded_by` is set)
|
|
137
|
+
* - `milestoneId`: substring match on `structured_fields.when_context`
|
|
138
|
+
* - `scope`: exact match on `structured_fields.scope`
|
|
139
|
+
*
|
|
140
|
+
* Used by the prompt-inline path (`inlineDecisionsFromDb` in
|
|
141
|
+
* `auto-prompts.ts`). For the projection regen (which renders superseded
|
|
142
|
+
* rows too), see `getAllDecisionsFromMemories`.
|
|
143
|
+
*/
|
|
144
|
+
export function queryDecisionsFromMemories(opts) {
|
|
145
|
+
return readDecisionsFromMemories(opts, /* includeSuperseded */ false);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* ADR-013 Phase 6 cutover (Stage 2a): read **all** decisions (active +
|
|
149
|
+
* superseded) from the `memories` table. Used by the DECISIONS.md
|
|
150
|
+
* projection regen in `saveDecisionToDb`, which must render the full
|
|
151
|
+
* supersedes-chain for the canonical register format.
|
|
152
|
+
*
|
|
153
|
+
* Equivalent to `SELECT * FROM decisions ORDER BY seq` over the legacy
|
|
154
|
+
* table — but sourced from memories so the legacy table can be retired
|
|
155
|
+
* in Stage 3. Includes `superseded_by` reconstructed from
|
|
156
|
+
* `structured_fields.superseded_by` (populated by the backfill's drift
|
|
157
|
+
* auto-heal pass).
|
|
158
|
+
*/
|
|
159
|
+
export function getAllDecisionsFromMemories() {
|
|
160
|
+
return readDecisionsFromMemories(undefined, /* includeSuperseded */ true);
|
|
161
|
+
}
|
|
50
162
|
/**
|
|
51
163
|
* Query active (non-superseded) requirements with optional filters.
|
|
52
164
|
* - milestoneId: combined with sliceId for precise filtering (e.g. %M005/S01%)
|