gsd-pi 2.41.0-dev.9446b20 → 2.41.0-dev.b832948
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 +69 -29
- package/dist/cli-web-branch.d.ts +6 -0
- package/dist/cli-web-branch.js +17 -0
- package/dist/onboarding.js +2 -1
- package/dist/resources/extensions/gsd/auto/loop.js +9 -1
- package/dist/resources/extensions/gsd/auto/phases.js +26 -8
- package/dist/resources/extensions/gsd/auto-dashboard.js +6 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +19 -2
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +12 -4
- package/dist/resources/extensions/gsd/auto-start.js +8 -3
- package/dist/resources/extensions/gsd/auto-worktree.js +147 -13
- package/dist/resources/extensions/gsd/auto.js +36 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +199 -164
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +62 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +16 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +8 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/context-store.js +4 -3
- package/dist/resources/extensions/gsd/db-writer.js +5 -2
- package/dist/resources/extensions/gsd/detection.js +1 -1
- package/dist/resources/extensions/gsd/doctor.js +11 -1
- package/dist/resources/extensions/gsd/exit-command.js +12 -2
- package/dist/resources/extensions/gsd/export.js +9 -13
- package/dist/resources/extensions/gsd/extension-manifest.json +2 -2
- package/dist/resources/extensions/gsd/files.js +28 -11
- package/dist/resources/extensions/gsd/forensics.js +10 -3
- package/dist/resources/extensions/gsd/git-service.js +5 -1
- package/dist/resources/extensions/gsd/gsd-db.js +25 -8
- package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
- package/dist/resources/extensions/gsd/guided-flow.js +7 -3
- package/dist/resources/extensions/gsd/journal.js +85 -0
- package/dist/resources/extensions/gsd/md-importer.js +5 -0
- package/dist/resources/extensions/gsd/milestone-ids.js +1 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +2 -2
- package/dist/resources/extensions/gsd/post-unit-hooks.js +24 -412
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences.js +1 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +34 -4
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +1 -1
- package/dist/resources/extensions/gsd/repo-identity.js +46 -2
- package/dist/resources/extensions/gsd/rule-registry.js +489 -0
- package/dist/resources/extensions/gsd/rule-types.js +6 -0
- package/dist/resources/extensions/gsd/service-tier.js +138 -0
- package/dist/resources/extensions/gsd/structured-data-formatter.js +2 -1
- package/dist/resources/extensions/gsd/templates/decisions.md +2 -2
- package/dist/resources/extensions/gsd/workflow-templates.js +13 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +20 -6
- package/dist/resources/extensions/gsd/worktree-resolver.js +19 -2
- package/dist/resources/extensions/subagent/index.js +7 -3
- package/dist/resources/extensions/voice/index.js +4 -4
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- 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/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +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 +17 -17
- package/dist/web/standalone/.next/server/chunks/229.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.c195dc1fdd2adbea.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-9afaaebf6042a1d7.js → webpack-fa307370fcf9fb2c.js} +1 -1
- package/dist/web-mode.d.ts +2 -0
- package/dist/web-mode.js +29 -7
- package/package.json +1 -1
- package/packages/native/src/__tests__/text.test.mjs +33 -0
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +3 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +10 -7
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +4 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +11 -7
- package/src/resources/extensions/gsd/auto/loop-deps.ts +5 -1
- package/src/resources/extensions/gsd/auto/loop.ts +10 -1
- package/src/resources/extensions/gsd/auto/phases.ts +28 -8
- package/src/resources/extensions/gsd/auto/types.ts +4 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +7 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +25 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +8 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +12 -4
- package/src/resources/extensions/gsd/auto-start.ts +8 -3
- package/src/resources/extensions/gsd/auto-worktree.ts +162 -18
- package/src/resources/extensions/gsd/auto.ts +40 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +209 -162
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +62 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +13 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +8 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/context-store.ts +4 -3
- package/src/resources/extensions/gsd/db-writer.ts +6 -2
- package/src/resources/extensions/gsd/detection.ts +1 -1
- package/src/resources/extensions/gsd/doctor.ts +12 -1
- package/src/resources/extensions/gsd/exit-command.ts +14 -2
- package/src/resources/extensions/gsd/export.ts +8 -15
- package/src/resources/extensions/gsd/extension-manifest.json +2 -2
- package/src/resources/extensions/gsd/files.ts +29 -12
- package/src/resources/extensions/gsd/forensics.ts +9 -3
- package/src/resources/extensions/gsd/git-service.ts +5 -4
- package/src/resources/extensions/gsd/gsd-db.ts +37 -8
- package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
- package/src/resources/extensions/gsd/guided-flow.ts +7 -3
- package/src/resources/extensions/gsd/journal.ts +134 -0
- package/src/resources/extensions/gsd/md-importer.ts +6 -0
- package/src/resources/extensions/gsd/milestone-ids.ts +1 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +2 -2
- package/src/resources/extensions/gsd/post-unit-hooks.ts +24 -462
- package/src/resources/extensions/gsd/preferences-types.ts +3 -0
- package/src/resources/extensions/gsd/preferences.ts +1 -0
- package/src/resources/extensions/gsd/prompt-loader.ts +35 -4
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
- package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +1 -1
- package/src/resources/extensions/gsd/repo-identity.ts +47 -2
- package/src/resources/extensions/gsd/rule-registry.ts +599 -0
- package/src/resources/extensions/gsd/rule-types.ts +68 -0
- package/src/resources/extensions/gsd/service-tier.ts +171 -0
- package/src/resources/extensions/gsd/structured-data-formatter.ts +3 -1
- package/src/resources/extensions/gsd/templates/decisions.md +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +202 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +10 -5
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +15 -10
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +5 -4
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +174 -0
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +513 -0
- package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/journal.test.ts +386 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/milestone-id-reservation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parsers.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -25
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/routing-history.test.ts +11 -22
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +413 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +178 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -3
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +74 -0
- package/src/resources/extensions/gsd/types.ts +3 -0
- package/src/resources/extensions/gsd/workflow-templates.ts +12 -1
- package/src/resources/extensions/gsd/worktree-manager.ts +21 -6
- package/src/resources/extensions/gsd/worktree-resolver.ts +30 -9
- package/src/resources/extensions/subagent/index.ts +7 -3
- package/src/resources/extensions/voice/index.ts +4 -4
- package/dist/web/standalone/.next/static/chunks/4024.279c423e4661ece1.js +0 -9
- /package/dist/web/standalone/.next/static/{02cti5IXH7FycOqkbAkWL → 43Aw72Fdw8k1aAHQOYOXr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{02cti5IXH7FycOqkbAkWL → 43Aw72Fdw8k1aAHQOYOXr}/_ssgManifest.js +0 -0
|
@@ -11,7 +11,7 @@ import { homedir } from "node:os";
|
|
|
11
11
|
import { gsdRoot } from "./paths.js";
|
|
12
12
|
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
13
13
|
// ─── Project File Markers ───────────────────────────────────────────────────────
|
|
14
|
-
const PROJECT_FILES = [
|
|
14
|
+
export const PROJECT_FILES = [
|
|
15
15
|
"package.json",
|
|
16
16
|
"Cargo.toml",
|
|
17
17
|
"go.mod",
|
|
@@ -745,6 +745,7 @@ export async function runGSDDoctor(basePath, options) {
|
|
|
745
745
|
}
|
|
746
746
|
catch { /* non-fatal */ }
|
|
747
747
|
let allTasksDone = plan.tasks.length > 0;
|
|
748
|
+
let taskUncheckedByDoctor = false;
|
|
748
749
|
for (const task of plan.tasks) {
|
|
749
750
|
const taskUnitId = `${unitId}/${task.id}`;
|
|
750
751
|
const summaryPath = resolveTaskFile(basePath, milestoneId, slice.id, task.id, "SUMMARY");
|
|
@@ -762,6 +763,7 @@ export async function runGSDDoctor(basePath, options) {
|
|
|
762
763
|
dryRunCanFix("task_done_missing_summary", `uncheck ${task.id} in plan for ${taskUnitId}`);
|
|
763
764
|
if (shouldFix("task_done_missing_summary")) {
|
|
764
765
|
await markTaskUndoneInPlan(basePath, milestoneId, slice.id, task.id, fixesApplied);
|
|
766
|
+
taskUncheckedByDoctor = true;
|
|
765
767
|
}
|
|
766
768
|
}
|
|
767
769
|
if (!task.done && hasSummary) {
|
|
@@ -822,6 +824,14 @@ export async function runGSDDoctor(basePath, options) {
|
|
|
822
824
|
}
|
|
823
825
|
allTasksDone = allTasksDone && task.done;
|
|
824
826
|
}
|
|
827
|
+
// ── #1850: cascade slice uncheck when task_done_missing_summary fires ──
|
|
828
|
+
// When doctor unchecks tasks inside a done slice, the slice must also be
|
|
829
|
+
// unchecked so the state machine re-enters the executing phase. Without
|
|
830
|
+
// this, state.ts skips done slices and the unchecked tasks never run,
|
|
831
|
+
// causing doctor to fire again on every start (infinite loop).
|
|
832
|
+
if (taskUncheckedByDoctor && slice.done) {
|
|
833
|
+
await markSliceUndoneInRoadmap(basePath, milestoneId, slice.id, fixesApplied);
|
|
834
|
+
}
|
|
825
835
|
// Blocker-without-replan detection
|
|
826
836
|
const replanPath = resolveSliceFile(basePath, milestoneId, slice.id, "REPLAN");
|
|
827
837
|
if (!replanPath) {
|
|
@@ -898,7 +908,7 @@ export async function runGSDDoctor(basePath, options) {
|
|
|
898
908
|
fixable: true,
|
|
899
909
|
});
|
|
900
910
|
dryRunCanFix("all_tasks_done_roadmap_not_checked", `mark ${slice.id} done in roadmap`);
|
|
901
|
-
if (shouldFix("all_tasks_done_roadmap_not_checked") && (hasSliceSummary ||
|
|
911
|
+
if (shouldFix("all_tasks_done_roadmap_not_checked") && (hasSliceSummary || existsSync(join(slicePath, `${slice.id}-SUMMARY.md`)))) {
|
|
902
912
|
await markSliceDoneInRoadmap(basePath, milestoneId, slice.id, fixesApplied);
|
|
903
913
|
}
|
|
904
914
|
}
|
|
@@ -4,8 +4,18 @@ export function registerExitCommand(pi, deps = {}) {
|
|
|
4
4
|
description: "Exit GSD gracefully",
|
|
5
5
|
handler: async (_args, ctx) => {
|
|
6
6
|
// Stop auto-mode first so locks and activity state are cleaned up before shutdown.
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
// Wrapped in try/catch: if gsd-pi was updated on disk mid-session, the dynamic
|
|
8
|
+
// import may resolve a new auto-worktree.js whose static imports reference
|
|
9
|
+
// exports absent from the process-cached native-git-bridge.js (ESM cache is
|
|
10
|
+
// immutable). The user's work is already saved — this is cleanup only.
|
|
11
|
+
try {
|
|
12
|
+
const stopAuto = deps.stopAuto ?? (await importExtensionModule(import.meta.url, "./auto.js")).stopAuto;
|
|
13
|
+
await stopAuto(ctx, pi, "Graceful exit");
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
17
|
+
ctx.ui?.notify?.(`Auto-mode cleanup skipped (module version mismatch): ${msg}`, "warning");
|
|
18
|
+
}
|
|
9
19
|
ctx.shutdown();
|
|
10
20
|
},
|
|
11
21
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Generate shareable reports of milestone work in JSON or markdown format.
|
|
3
3
|
import { writeFileSync, mkdirSync } from "node:fs";
|
|
4
4
|
import { join, basename } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { execFile } from "node:child_process";
|
|
6
6
|
import { getLedger, getProjectTotals, aggregateByPhase, aggregateBySlice, aggregateByModel, formatCost, formatTokenCount, loadLedgerFromDisk, } from "./metrics.js";
|
|
7
7
|
import { gsdRoot } from "./paths.js";
|
|
8
8
|
import { formatDuration, fileLink } from "../shared/format-utils.js";
|
|
@@ -13,18 +13,14 @@ import { getErrorMessage } from "./error-utils.js";
|
|
|
13
13
|
* Non-blocking, non-fatal — failures are silently ignored.
|
|
14
14
|
*/
|
|
15
15
|
export function openInBrowser(filePath) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
?
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// Non-fatal — if the browser can't be opened, the file path is still shown
|
|
25
|
-
if (err)
|
|
26
|
-
void err;
|
|
27
|
-
});
|
|
16
|
+
if (process.platform === "win32") {
|
|
17
|
+
// PowerShell's Start-Process handles paths with '&' and spaces safely.
|
|
18
|
+
execFile("powershell", ["-c", `Start-Process '${filePath.replace(/'/g, "''")}'`], () => { });
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const cmd = process.platform === "darwin" ? "open" : "xdg-open";
|
|
22
|
+
execFile(cmd, [filePath], () => { });
|
|
23
|
+
}
|
|
28
24
|
}
|
|
29
25
|
/**
|
|
30
26
|
* Write an export file directly, without requiring an ExtensionCommandContext.
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"provides": {
|
|
9
9
|
"tools": [
|
|
10
10
|
"bash", "write", "read", "edit",
|
|
11
|
-
"
|
|
12
|
-
"
|
|
11
|
+
"gsd_decision_save", "gsd_summary_save",
|
|
12
|
+
"gsd_requirement_update", "gsd_milestone_generate_id"
|
|
13
13
|
],
|
|
14
14
|
"commands": ["gsd", "kill", "worktree", "exit"],
|
|
15
15
|
"hooks": ["session_start"],
|
|
@@ -309,19 +309,36 @@ function _parsePlanImpl(content) {
|
|
|
309
309
|
let currentTask = null;
|
|
310
310
|
for (const line of taskLines) {
|
|
311
311
|
const cbMatch = line.match(/^-\s+\[([ xX])\]\s+\*\*([\w.]+):\s+(.+?)\*\*\s*(.*)/);
|
|
312
|
-
|
|
312
|
+
// Heading-style: ### T01 -- Title, ### T01: Title, ### T01 — Title
|
|
313
|
+
const hdMatch = !cbMatch ? line.match(/^#{2,4}\s+([\w.]+)\s*(?:--|—|:)\s*(.+)/) : null;
|
|
314
|
+
if (cbMatch || hdMatch) {
|
|
313
315
|
if (currentTask)
|
|
314
316
|
tasks.push(currentTask);
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
317
|
+
if (cbMatch) {
|
|
318
|
+
const rest = cbMatch[4] || '';
|
|
319
|
+
const estMatch = rest.match(/`est:([^`]+)`/);
|
|
320
|
+
const estimate = estMatch ? estMatch[1] : '';
|
|
321
|
+
currentTask = {
|
|
322
|
+
id: cbMatch[2],
|
|
323
|
+
title: cbMatch[3],
|
|
324
|
+
description: '',
|
|
325
|
+
done: cbMatch[1].toLowerCase() === 'x',
|
|
326
|
+
estimate,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
const rest = hdMatch[2] || '';
|
|
331
|
+
const titleEstMatch = rest.match(/^(.+?)\s*`est:([^`]+)`\s*$/);
|
|
332
|
+
const title = titleEstMatch ? titleEstMatch[1].trim() : rest.trim();
|
|
333
|
+
const estimate = titleEstMatch ? titleEstMatch[2] : '';
|
|
334
|
+
currentTask = {
|
|
335
|
+
id: hdMatch[1],
|
|
336
|
+
title,
|
|
337
|
+
description: '',
|
|
338
|
+
done: false,
|
|
339
|
+
estimate,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
325
342
|
}
|
|
326
343
|
else if (currentTask && line.match(/^\s*-\s+Files:\s*(.*)/)) {
|
|
327
344
|
const filesMatch = line.match(/^\s*-\s+Files:\s*(.*)/);
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { join, dirname, relative } from "node:path";
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
|
+
import { homedir } from "node:os";
|
|
13
14
|
import { extractTrace } from "./session-forensics.js";
|
|
14
15
|
import { nativeParseJsonlTail } from "./native-parser-bridge.js";
|
|
15
16
|
import { MAX_JSONL_BYTES, parseJSONL } from "./jsonl-utils.js";
|
|
@@ -46,9 +47,15 @@ export async function handleForensics(args, ctx, pi) {
|
|
|
46
47
|
ctx.ui.notify("Building forensic report...", "info");
|
|
47
48
|
const report = await buildForensicReport(basePath);
|
|
48
49
|
const savedPath = saveForensicReport(basePath, report, problemDescription);
|
|
49
|
-
// Derive GSD source dir for prompt
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
// Derive GSD source dir for prompt — fall back to ~/.gsd/agent/extensions/gsd/
|
|
51
|
+
// when import.meta.url resolves to the npm-global install path (Windows).
|
|
52
|
+
let gsdSourceDir = dirname(fileURLToPath(import.meta.url));
|
|
53
|
+
if (!existsSync(join(gsdSourceDir, "prompts"))) {
|
|
54
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
55
|
+
const fallback = join(gsdHome, "agent", "extensions", "gsd");
|
|
56
|
+
if (existsSync(join(fallback, "prompts")))
|
|
57
|
+
gsdSourceDir = fallback;
|
|
58
|
+
}
|
|
52
59
|
const forensicData = formatReportForPrompt(report);
|
|
53
60
|
const content = loadPrompt("forensics", {
|
|
54
61
|
problemDescription,
|
|
@@ -508,7 +508,11 @@ export class GitServiceImpl {
|
|
|
508
508
|
*/
|
|
509
509
|
export function createDraftPR(basePath, milestoneId, title, body) {
|
|
510
510
|
try {
|
|
511
|
-
const result =
|
|
511
|
+
const result = execFileSync("gh", [
|
|
512
|
+
"pr", "create", "--draft",
|
|
513
|
+
"--title", title,
|
|
514
|
+
"--body", body,
|
|
515
|
+
], { cwd: basePath, encoding: "utf8", timeout: 30000, env: GIT_NO_PROMPT_ENV });
|
|
512
516
|
return result.trim();
|
|
513
517
|
}
|
|
514
518
|
catch {
|
|
@@ -118,7 +118,7 @@ function openRawDb(path) {
|
|
|
118
118
|
return new Database(path);
|
|
119
119
|
}
|
|
120
120
|
// ─── Schema ────────────────────────────────────────────────────────────────
|
|
121
|
-
const SCHEMA_VERSION =
|
|
121
|
+
const SCHEMA_VERSION = 4;
|
|
122
122
|
function initSchema(db, fileBacked) {
|
|
123
123
|
// WAL mode for file-backed databases (must be outside transaction)
|
|
124
124
|
if (fileBacked) {
|
|
@@ -142,6 +142,7 @@ function initSchema(db, fileBacked) {
|
|
|
142
142
|
choice TEXT NOT NULL DEFAULT '',
|
|
143
143
|
rationale TEXT NOT NULL DEFAULT '',
|
|
144
144
|
revisable TEXT NOT NULL DEFAULT '',
|
|
145
|
+
made_by TEXT NOT NULL DEFAULT 'agent',
|
|
145
146
|
superseded_by TEXT DEFAULT NULL
|
|
146
147
|
)
|
|
147
148
|
`);
|
|
@@ -273,6 +274,15 @@ function migrateSchema(db) {
|
|
|
273
274
|
db.exec("CREATE VIEW active_memories AS SELECT * FROM memories WHERE superseded_by IS NULL");
|
|
274
275
|
db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({ ":version": 3, ":applied_at": new Date().toISOString() });
|
|
275
276
|
}
|
|
277
|
+
// v3 → v4: add made_by column to decisions table
|
|
278
|
+
if (currentVersion < 4) {
|
|
279
|
+
// Add made_by column — default 'agent' for existing rows (pre-attribution decisions)
|
|
280
|
+
db.exec(`ALTER TABLE decisions ADD COLUMN made_by TEXT NOT NULL DEFAULT 'agent'`);
|
|
281
|
+
// Recreate views to pick up new columns (SQLite expands SELECT * at view creation time)
|
|
282
|
+
db.exec("DROP VIEW IF EXISTS active_decisions");
|
|
283
|
+
db.exec("CREATE VIEW active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL");
|
|
284
|
+
db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({ ":version": 4, ":applied_at": new Date().toISOString() });
|
|
285
|
+
}
|
|
276
286
|
db.exec("COMMIT");
|
|
277
287
|
}
|
|
278
288
|
catch (err) {
|
|
@@ -375,8 +385,8 @@ export function insertDecision(d) {
|
|
|
375
385
|
if (!currentDb)
|
|
376
386
|
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
377
387
|
currentDb
|
|
378
|
-
.prepare(`INSERT INTO decisions (id, when_context, scope, decision, choice, rationale, revisable, superseded_by)
|
|
379
|
-
VALUES (:id, :when_context, :scope, :decision, :choice, :rationale, :revisable, :superseded_by)`)
|
|
388
|
+
.prepare(`INSERT INTO decisions (id, when_context, scope, decision, choice, rationale, revisable, made_by, superseded_by)
|
|
389
|
+
VALUES (:id, :when_context, :scope, :decision, :choice, :rationale, :revisable, :made_by, :superseded_by)`)
|
|
380
390
|
.run({
|
|
381
391
|
":id": d.id,
|
|
382
392
|
":when_context": d.when_context,
|
|
@@ -385,6 +395,7 @@ export function insertDecision(d) {
|
|
|
385
395
|
":choice": d.choice,
|
|
386
396
|
":rationale": d.rationale,
|
|
387
397
|
":revisable": d.revisable,
|
|
398
|
+
":made_by": d.made_by ?? "agent",
|
|
388
399
|
":superseded_by": d.superseded_by,
|
|
389
400
|
});
|
|
390
401
|
}
|
|
@@ -406,6 +417,7 @@ export function getDecisionById(id) {
|
|
|
406
417
|
choice: row["choice"],
|
|
407
418
|
rationale: row["rationale"],
|
|
408
419
|
revisable: row["revisable"],
|
|
420
|
+
made_by: row["made_by"] ?? "agent",
|
|
409
421
|
superseded_by: row["superseded_by"] ?? null,
|
|
410
422
|
};
|
|
411
423
|
}
|
|
@@ -425,6 +437,7 @@ export function getActiveDecisions() {
|
|
|
425
437
|
choice: row["choice"],
|
|
426
438
|
rationale: row["rationale"],
|
|
427
439
|
revisable: row["revisable"],
|
|
440
|
+
made_by: row["made_by"] ?? "agent",
|
|
428
441
|
superseded_by: null,
|
|
429
442
|
}));
|
|
430
443
|
}
|
|
@@ -537,8 +550,8 @@ export function upsertDecision(d) {
|
|
|
537
550
|
if (!currentDb)
|
|
538
551
|
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
539
552
|
currentDb
|
|
540
|
-
.prepare(`INSERT OR REPLACE INTO decisions (id, when_context, scope, decision, choice, rationale, revisable, superseded_by)
|
|
541
|
-
VALUES (:id, :when_context, :scope, :decision, :choice, :rationale, :revisable, :superseded_by)`)
|
|
553
|
+
.prepare(`INSERT OR REPLACE INTO decisions (id, when_context, scope, decision, choice, rationale, revisable, made_by, superseded_by)
|
|
554
|
+
VALUES (:id, :when_context, :scope, :decision, :choice, :rationale, :revisable, :made_by, :superseded_by)`)
|
|
542
555
|
.run({
|
|
543
556
|
":id": d.id,
|
|
544
557
|
":when_context": d.when_context,
|
|
@@ -547,6 +560,7 @@ export function upsertDecision(d) {
|
|
|
547
560
|
":choice": d.choice,
|
|
548
561
|
":rationale": d.rationale,
|
|
549
562
|
":revisable": d.revisable,
|
|
563
|
+
":made_by": d.made_by ?? "agent",
|
|
550
564
|
":superseded_by": d.superseded_by ?? null,
|
|
551
565
|
});
|
|
552
566
|
}
|
|
@@ -649,8 +663,11 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
|
|
|
649
663
|
try {
|
|
650
664
|
adapter.exec(`ATTACH DATABASE '${worktreeDbPath}' AS wt`);
|
|
651
665
|
try {
|
|
666
|
+
// Check if attached wt database has the made_by column (legacy v3 worktrees won't)
|
|
667
|
+
const wtInfo = adapter.prepare("PRAGMA wt.table_info('decisions')").all();
|
|
668
|
+
const hasMadeBy = wtInfo.some((col) => col["name"] === "made_by");
|
|
652
669
|
const decConf = adapter
|
|
653
|
-
.prepare(`SELECT m.id FROM decisions m INNER JOIN wt.decisions w ON m.id = w.id WHERE m.decision != w.decision OR m.choice != w.choice OR m.rationale != w.rationale OR m.superseded_by IS NOT w.superseded_by`)
|
|
670
|
+
.prepare(`SELECT m.id FROM decisions m INNER JOIN wt.decisions w ON m.id = w.id WHERE m.decision != w.decision OR m.choice != w.choice OR m.rationale != w.rationale OR ${hasMadeBy ? "m.made_by != w.made_by" : "'agent' != 'agent'"} OR m.superseded_by IS NOT w.superseded_by`)
|
|
654
671
|
.all();
|
|
655
672
|
for (const row of decConf)
|
|
656
673
|
conflicts.push(`decision ${row["id"]}: modified in both`);
|
|
@@ -665,10 +682,10 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
|
|
|
665
682
|
const dR = adapter
|
|
666
683
|
.prepare(`
|
|
667
684
|
INSERT OR REPLACE INTO decisions (
|
|
668
|
-
id, when_context, scope, decision, choice, rationale, revisable, superseded_by
|
|
685
|
+
id, when_context, scope, decision, choice, rationale, revisable, made_by, superseded_by
|
|
669
686
|
)
|
|
670
687
|
SELECT
|
|
671
|
-
id, when_context, scope, decision, choice, rationale, revisable, superseded_by
|
|
688
|
+
id, when_context, scope, decision, choice, rationale, revisable, ${hasMadeBy ? "made_by" : "'agent'"}, superseded_by
|
|
672
689
|
FROM wt.decisions
|
|
673
690
|
`)
|
|
674
691
|
.run();
|
|
@@ -130,7 +130,7 @@ export async function showQueueAdd(ctx, pi, basePath, state) {
|
|
|
130
130
|
// ── Build existing milestones context for the prompt ────────────────
|
|
131
131
|
const existingContext = await buildExistingMilestonesContext(basePath, milestoneIds, state);
|
|
132
132
|
// ── Determine next milestone ID ─────────────────────────────────────
|
|
133
|
-
// Note: the LLM will use the
|
|
133
|
+
// Note: the LLM will use the gsd_milestone_generate_id tool to get IDs
|
|
134
134
|
// at creation time, but we still mention the next ID in the preamble
|
|
135
135
|
// for context about where the sequence is.
|
|
136
136
|
const uniqueEnabled = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
@@ -20,6 +20,7 @@ import { join } from "node:path";
|
|
|
20
20
|
import { readFileSync, existsSync, mkdirSync, readdirSync, unlinkSync } from "node:fs";
|
|
21
21
|
import { readSessionLockData, isSessionLockProcessAlive } from "./session-lock.js";
|
|
22
22
|
import { nativeIsRepo, nativeInit } from "./native-git-bridge.js";
|
|
23
|
+
import { isInheritedRepo } from "./repo-identity.js";
|
|
23
24
|
import { ensureGitignore, ensurePreferences, untrackRuntimeFiles } from "./gitignore.js";
|
|
24
25
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
25
26
|
import { detectProjectState } from "./detection.js";
|
|
@@ -37,7 +38,7 @@ import { getErrorMessage } from "./error-utils.js";
|
|
|
37
38
|
// ─── ID Generation with Reservation ─────────────────────────────────────────
|
|
38
39
|
/**
|
|
39
40
|
* Generate the next milestone ID, accounting for reserved IDs, and reserve it.
|
|
40
|
-
* Ensures any preview ID shown in the UI matches what `
|
|
41
|
+
* Ensures any preview ID shown in the UI matches what `gsd_milestone_generate_id`
|
|
41
42
|
* will later return.
|
|
42
43
|
*/
|
|
43
44
|
function nextMilestoneIdReserved(existingIds, uniqueEnabled) {
|
|
@@ -277,7 +278,7 @@ function buildHeadlessDiscussPrompt(nextId, seedContext, _basePath) {
|
|
|
277
278
|
* Ensures git repo, .gsd/ structure, gitignore, and preferences all exist.
|
|
278
279
|
*/
|
|
279
280
|
function bootstrapGsdProject(basePath) {
|
|
280
|
-
if (!nativeIsRepo(basePath)) {
|
|
281
|
+
if (!nativeIsRepo(basePath) || isInheritedRepo(basePath)) {
|
|
281
282
|
const mainBranch = loadEffectiveGSDPreferences()?.preferences?.git?.main_branch || "main";
|
|
282
283
|
nativeInit(basePath, mainBranch);
|
|
283
284
|
}
|
|
@@ -721,7 +722,10 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
721
722
|
// which will detect "no milestones" and start the discuss prompt
|
|
722
723
|
}
|
|
723
724
|
// ── Ensure git repo exists — GSD needs it for worktree isolation ──────
|
|
724
|
-
if
|
|
725
|
+
// Also handle inherited repos: if basePath is a subdirectory of another
|
|
726
|
+
// git repo that has no .gsd, create a fresh repo to prevent cross-project
|
|
727
|
+
// state leaks (#1639).
|
|
728
|
+
if (!nativeIsRepo(basePath) || isInheritedRepo(basePath)) {
|
|
725
729
|
const mainBranch = loadEffectiveGSDPreferences()?.preferences?.git?.main_branch || "main";
|
|
726
730
|
nativeInit(basePath, mainBranch);
|
|
727
731
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSD Event Journal — structured JSONL event log for auto-mode iterations.
|
|
3
|
+
*
|
|
4
|
+
* Writes daily-rotated JSONL files to `.gsd/journal/YYYY-MM-DD.jsonl`.
|
|
5
|
+
* Zero imports from `auto/` — depends only on node:fs, node:path, and paths.ts.
|
|
6
|
+
*
|
|
7
|
+
* Observability:
|
|
8
|
+
* - Each line in the JSONL file is a self-contained JournalEntry
|
|
9
|
+
* - Events are grouped by flowId (one per iteration) with monotonic seq numbers
|
|
10
|
+
* - causedBy references enable causal chain reconstruction
|
|
11
|
+
* - queryJournal() enables programmatic filtering by flowId, eventType, unitId, time range
|
|
12
|
+
* - Silent failure: journal writes never throw — absence of events is the failure signal
|
|
13
|
+
*/
|
|
14
|
+
import { appendFileSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { gsdRoot } from "./paths.js";
|
|
17
|
+
// ─── Emit ─────────────────────────────────────────────────────────────────────
|
|
18
|
+
/**
|
|
19
|
+
* Append a journal event to the daily JSONL file.
|
|
20
|
+
*
|
|
21
|
+
* File path: `<gsdRoot>/journal/<YYYY-MM-DD>.jsonl`
|
|
22
|
+
* where the date is extracted from `entry.ts.slice(0, 10)`.
|
|
23
|
+
*
|
|
24
|
+
* Never throws — all errors are silently caught.
|
|
25
|
+
*/
|
|
26
|
+
export function emitJournalEvent(basePath, entry) {
|
|
27
|
+
try {
|
|
28
|
+
const journalDir = join(gsdRoot(basePath), "journal");
|
|
29
|
+
mkdirSync(journalDir, { recursive: true });
|
|
30
|
+
const dateStr = entry.ts.slice(0, 10);
|
|
31
|
+
const filePath = join(journalDir, `${dateStr}.jsonl`);
|
|
32
|
+
appendFileSync(filePath, JSON.stringify(entry) + "\n");
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Silent failure — journal must never break auto-mode
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// ─── Query ────────────────────────────────────────────────────────────────────
|
|
39
|
+
/**
|
|
40
|
+
* Read and filter journal entries from all daily JSONL files.
|
|
41
|
+
*
|
|
42
|
+
* Returns an empty array on any error (missing directory, corrupt files, etc.).
|
|
43
|
+
*/
|
|
44
|
+
export function queryJournal(basePath, filters) {
|
|
45
|
+
try {
|
|
46
|
+
const journalDir = join(gsdRoot(basePath), "journal");
|
|
47
|
+
const files = readdirSync(journalDir).filter(f => f.endsWith(".jsonl")).sort();
|
|
48
|
+
const entries = [];
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
const raw = readFileSync(join(journalDir, file), "utf-8");
|
|
51
|
+
for (const line of raw.split("\n")) {
|
|
52
|
+
if (!line.trim())
|
|
53
|
+
continue;
|
|
54
|
+
try {
|
|
55
|
+
const entry = JSON.parse(line);
|
|
56
|
+
entries.push(entry);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Skip malformed lines
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!filters)
|
|
64
|
+
return entries;
|
|
65
|
+
return entries.filter(e => {
|
|
66
|
+
if (filters.flowId && e.flowId !== filters.flowId)
|
|
67
|
+
return false;
|
|
68
|
+
if (filters.eventType && e.eventType !== filters.eventType)
|
|
69
|
+
return false;
|
|
70
|
+
if (filters.rule && e.rule !== filters.rule)
|
|
71
|
+
return false;
|
|
72
|
+
if (filters.unitId && e.data?.unitId !== filters.unitId)
|
|
73
|
+
return false;
|
|
74
|
+
if (filters.after && e.ts < filters.after)
|
|
75
|
+
return false;
|
|
76
|
+
if (filters.before && e.ts > filters.before)
|
|
77
|
+
return false;
|
|
78
|
+
return true;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Missing directory, permission errors, etc. — return empty
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -9,6 +9,7 @@ import { upsertDecision, upsertRequirement, insertArtifact, openDatabase, transa
|
|
|
9
9
|
import { resolveGsdRootFile, milestonesDir, gsdRoot, resolveTaskFiles, } from './paths.js';
|
|
10
10
|
import { findMilestoneIds } from './guided-flow.js';
|
|
11
11
|
// ─── DECISIONS.md Parser ───────────────────────────────────────────────────
|
|
12
|
+
const VALID_MADE_BY = new Set(['human', 'agent', 'collaborative']);
|
|
12
13
|
/**
|
|
13
14
|
* Parse a DECISIONS.md markdown table into Decision objects (without seq).
|
|
14
15
|
* Detects `(amends DXXX)` in the Decision column to build supersession info.
|
|
@@ -49,6 +50,9 @@ export function parseDecisionsTable(content) {
|
|
|
49
50
|
const choice = cells[4].trim();
|
|
50
51
|
const rationale = cells[5].trim();
|
|
51
52
|
const revisable = cells[6].trim();
|
|
53
|
+
// Made By column is optional for backward compatibility — defaults to 'agent'
|
|
54
|
+
const rawMadeBy = cells.length >= 8 ? cells[7].trim().toLowerCase() : 'agent';
|
|
55
|
+
const made_by = (VALID_MADE_BY.has(rawMadeBy) ? rawMadeBy : 'agent');
|
|
52
56
|
// Detect (amends DXXX) in the Decision column
|
|
53
57
|
const amendsMatch = decisionText.match(/\(amends\s+(D\d+)\)/i);
|
|
54
58
|
if (amendsMatch) {
|
|
@@ -62,6 +66,7 @@ export function parseDecisionsTable(content) {
|
|
|
62
66
|
choice,
|
|
63
67
|
rationale,
|
|
64
68
|
revisable,
|
|
69
|
+
made_by,
|
|
65
70
|
superseded_by: null,
|
|
66
71
|
});
|
|
67
72
|
}
|
|
@@ -62,7 +62,7 @@ export function nextMilestoneId(milestoneIds, uniqueEnabled) {
|
|
|
62
62
|
/**
|
|
63
63
|
* Module-level set of milestone IDs that have been previewed/promised to the
|
|
64
64
|
* user but not yet materialised on disk. Both guided-flow (preview) and
|
|
65
|
-
*
|
|
65
|
+
* gsd_milestone_generate_id (tool) share this set so the ID shown in the UI
|
|
66
66
|
* matches the one the tool returns.
|
|
67
67
|
*/
|
|
68
68
|
const reservedMilestoneIds = new Set();
|
|
@@ -647,7 +647,7 @@ export function nativeCheckoutBranch(basePath, branch) {
|
|
|
647
647
|
native.gitCheckoutBranch(basePath, branch);
|
|
648
648
|
return;
|
|
649
649
|
}
|
|
650
|
-
|
|
650
|
+
execFileSync("git", ["checkout", branch], {
|
|
651
651
|
cwd: basePath,
|
|
652
652
|
stdio: ["ignore", "pipe", "pipe"],
|
|
653
653
|
encoding: "utf-8",
|
|
@@ -679,7 +679,7 @@ export function nativeMergeSquash(basePath, branch) {
|
|
|
679
679
|
return native.gitMergeSquash(basePath, branch);
|
|
680
680
|
}
|
|
681
681
|
try {
|
|
682
|
-
|
|
682
|
+
execFileSync("git", ["merge", "--squash", branch], {
|
|
683
683
|
cwd: basePath,
|
|
684
684
|
stdio: ["ignore", "pipe", "pipe"],
|
|
685
685
|
encoding: "utf-8",
|