gsd-pi 2.41.0-dev.cac69f9 → 2.42.0-dev.1df898f
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 +23 -0
- package/dist/cli.js +18 -3
- package/dist/loader.js +3 -1
- package/dist/resource-loader.js +39 -6
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +52 -4
- package/dist/resources/extensions/async-jobs/await-tool.js +5 -0
- package/dist/resources/extensions/async-jobs/index.js +2 -0
- package/dist/resources/extensions/gsd/auto/loop.js +80 -0
- package/dist/resources/extensions/gsd/auto/phases.js +3 -5
- package/dist/resources/extensions/gsd/auto/session.js +6 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +2 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +3 -16
- package/dist/resources/extensions/gsd/auto-start.js +8 -11
- package/dist/resources/extensions/gsd/auto.js +28 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -5
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +7 -2
- package/dist/resources/extensions/gsd/commands/catalog.js +32 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +146 -0
- package/dist/resources/extensions/gsd/context-injector.js +74 -0
- package/dist/resources/extensions/gsd/custom-execution-policy.js +47 -0
- package/dist/resources/extensions/gsd/custom-verification.js +145 -0
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +164 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -0
- package/dist/resources/extensions/gsd/definition-loader.js +352 -0
- package/dist/resources/extensions/gsd/detection.js +19 -0
- package/dist/resources/extensions/gsd/dev-execution-policy.js +24 -0
- package/dist/resources/extensions/gsd/dev-workflow-engine.js +82 -0
- package/dist/resources/extensions/gsd/doctor-checks.js +31 -1
- package/dist/resources/extensions/gsd/doctor-providers.js +10 -0
- package/dist/resources/extensions/gsd/engine-resolver.js +40 -0
- package/dist/resources/extensions/gsd/engine-types.js +8 -0
- package/dist/resources/extensions/gsd/execution-policy.js +8 -0
- package/dist/resources/extensions/gsd/forensics.js +84 -0
- package/dist/resources/extensions/gsd/git-constants.js +1 -0
- package/dist/resources/extensions/gsd/git-service.js +1 -1
- package/dist/resources/extensions/gsd/graph.js +225 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +1 -0
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences.js +59 -8
- package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/dist/resources/extensions/gsd/repo-identity.js +46 -5
- package/dist/resources/extensions/gsd/run-manager.js +134 -0
- package/dist/resources/extensions/gsd/service-tier.js +13 -4
- package/dist/resources/extensions/gsd/session-lock.js +2 -2
- package/dist/resources/extensions/gsd/workflow-engine.js +7 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +2 -2
- package/dist/resources/extensions/gsd/worktree.js +2 -2
- package/dist/resources/extensions/mcp-client/index.js +2 -1
- package/dist/resources/extensions/search-the-web/tool-search.js +3 -3
- package/dist/resources/skills/create-workflow/SKILL.md +103 -0
- package/dist/resources/skills/create-workflow/references/feature-patterns.md +128 -0
- package/dist/resources/skills/create-workflow/references/verification-policies.md +76 -0
- package/dist/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
- package/dist/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
- package/dist/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
- package/dist/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
- package/dist/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
- package/dist/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
- package/dist/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
- 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 +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/git/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 +15 -15
- package/dist/web/standalone/.next/server/chunks/229.js +2 -2
- 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-mode.d.ts +2 -0
- package/dist/web-mode.js +40 -4
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +6 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent.test.ts +53 -0
- package/packages/pi-agent-core/src/agent.ts +3 -0
- package/packages/pi-agent-core/src/types.ts +6 -0
- package/packages/pi-agent-core/tsconfig.json +1 -1
- package/packages/pi-ai/dist/models.d.ts +5 -3
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +801 -1468
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +1135 -1588
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js +60 -2
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +1543 -0
- package/packages/pi-ai/src/models.generated.ts +1140 -1593
- package/packages/pi-ai/src/models.ts +7 -4
- package/packages/pi-ai/src/utils/oauth/github-copilot.ts +74 -2
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +29 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +60 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +18 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +23 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +63 -11
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +20 -6
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +6 -5
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +9 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +30 -10
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +7 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +68 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +30 -2
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +18 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +29 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +3 -0
- package/packages/pi-coding-agent/src/core/package-manager.ts +99 -58
- package/packages/pi-coding-agent/src/core/resource-loader.ts +24 -6
- package/packages/pi-coding-agent/src/core/system-prompt.ts +6 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-editor.ts +3 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +10 -6
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +31 -11
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/async-bash-timeout.test.ts +122 -0
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +40 -4
- package/src/resources/extensions/async-jobs/await-tool.test.ts +47 -0
- package/src/resources/extensions/async-jobs/await-tool.ts +5 -0
- package/src/resources/extensions/async-jobs/index.ts +1 -0
- package/src/resources/extensions/async-jobs/job-manager.ts +2 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -1
- package/src/resources/extensions/gsd/auto/loop.ts +91 -0
- package/src/resources/extensions/gsd/auto/phases.ts +3 -5
- package/src/resources/extensions/gsd/auto/session.ts +6 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +2 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +2 -18
- package/src/resources/extensions/gsd/auto-start.ts +7 -10
- package/src/resources/extensions/gsd/auto.ts +31 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +13 -5
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +9 -2
- package/src/resources/extensions/gsd/commands/catalog.ts +32 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +164 -0
- package/src/resources/extensions/gsd/context-injector.ts +100 -0
- package/src/resources/extensions/gsd/custom-execution-policy.ts +73 -0
- package/src/resources/extensions/gsd/custom-verification.ts +180 -0
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +216 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -0
- package/src/resources/extensions/gsd/definition-loader.ts +462 -0
- package/src/resources/extensions/gsd/detection.ts +19 -0
- package/src/resources/extensions/gsd/dev-execution-policy.ts +51 -0
- package/src/resources/extensions/gsd/dev-workflow-engine.ts +110 -0
- package/src/resources/extensions/gsd/doctor-checks.ts +32 -1
- package/src/resources/extensions/gsd/doctor-providers.ts +13 -0
- package/src/resources/extensions/gsd/doctor-types.ts +1 -0
- package/src/resources/extensions/gsd/engine-resolver.ts +57 -0
- package/src/resources/extensions/gsd/engine-types.ts +71 -0
- package/src/resources/extensions/gsd/execution-policy.ts +43 -0
- package/src/resources/extensions/gsd/forensics.ts +92 -0
- package/src/resources/extensions/gsd/git-constants.ts +1 -0
- package/src/resources/extensions/gsd/git-service.ts +0 -1
- package/src/resources/extensions/gsd/gitignore.ts +1 -1
- package/src/resources/extensions/gsd/graph.ts +312 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +1 -0
- package/src/resources/extensions/gsd/preferences-types.ts +3 -0
- package/src/resources/extensions/gsd/preferences.ts +62 -6
- package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/src/resources/extensions/gsd/repo-identity.ts +48 -5
- package/src/resources/extensions/gsd/run-manager.ts +180 -0
- package/src/resources/extensions/gsd/service-tier.ts +17 -4
- package/src/resources/extensions/gsd/session-lock.ts +2 -2
- package/src/resources/extensions/gsd/tests/activity-log.test.ts +31 -69
- package/src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +283 -0
- package/src/resources/extensions/gsd/tests/context-injector.test.ts +313 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +540 -0
- package/src/resources/extensions/gsd/tests/custom-verification.test.ts +382 -0
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +339 -0
- package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +778 -0
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +318 -0
- package/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts +476 -0
- package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +271 -0
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +599 -0
- package/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts +429 -0
- package/src/resources/extensions/gsd/tests/journal.test.ts +82 -127
- package/src/resources/extensions/gsd/tests/manifest-status.test.ts +73 -82
- package/src/resources/extensions/gsd/tests/run-manager.test.ts +229 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +30 -1
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +56 -3
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +156 -263
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +35 -78
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +81 -74
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +1 -2
- package/src/resources/extensions/gsd/workflow-engine.ts +38 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +2 -3
- package/src/resources/extensions/gsd/worktree.ts +2 -2
- package/src/resources/extensions/mcp-client/index.ts +5 -1
- package/src/resources/extensions/search-the-web/tool-search.ts +3 -3
- package/src/resources/skills/create-workflow/SKILL.md +103 -0
- package/src/resources/skills/create-workflow/references/feature-patterns.md +128 -0
- package/src/resources/skills/create-workflow/references/verification-policies.md +76 -0
- package/src/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
- package/src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
- package/src/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
- package/src/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
- package/src/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
- package/src/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
- package/src/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
- /package/dist/web/standalone/.next/static/{EnGUNqHeGbE0tuuUkTJVA → qw8qDHXOTLUXBq1vEknSz}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{EnGUNqHeGbE0tuuUkTJVA → qw8qDHXOTLUXBq1vEknSz}/_ssgManifest.js +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import test from "node:test";
|
|
1
|
+
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
import {
|
|
4
4
|
mkdirSync,
|
|
@@ -46,9 +46,12 @@ function makeEntry(overrides: Partial<JournalEntry> = {}): JournalEntry {
|
|
|
46
46
|
|
|
47
47
|
// ─── emitJournalEvent ─────────────────────────────────────────────────────────
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
describe("emitJournalEvent", () => {
|
|
50
|
+
let base: string;
|
|
51
|
+
beforeEach(() => { base = makeTmpBase(); });
|
|
52
|
+
afterEach(() => { cleanup(base); });
|
|
53
|
+
|
|
54
|
+
test("creates journal directory and JSONL file", () => {
|
|
52
55
|
const entry = makeEntry();
|
|
53
56
|
emitJournalEvent(base, entry);
|
|
54
57
|
|
|
@@ -61,14 +64,9 @@ test("emitJournalEvent creates journal directory and JSONL file", () => {
|
|
|
61
64
|
assert.equal(parsed.flowId, entry.flowId);
|
|
62
65
|
assert.equal(parsed.seq, entry.seq);
|
|
63
66
|
assert.equal(parsed.eventType, entry.eventType);
|
|
64
|
-
}
|
|
65
|
-
cleanup(base);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
67
|
+
});
|
|
68
68
|
|
|
69
|
-
test("
|
|
70
|
-
const base = makeTmpBase();
|
|
71
|
-
try {
|
|
69
|
+
test("appends multiple lines to the same file", () => {
|
|
72
70
|
emitJournalEvent(base, makeEntry({ seq: 0 }));
|
|
73
71
|
emitJournalEvent(base, makeEntry({ seq: 1, eventType: "dispatch-match" }));
|
|
74
72
|
emitJournalEvent(base, makeEntry({ seq: 2, eventType: "unit-start" }));
|
|
@@ -82,26 +80,9 @@ test("emitJournalEvent appends multiple lines to the same file", () => {
|
|
|
82
80
|
assert.equal(parsed[1].seq, 1);
|
|
83
81
|
assert.equal(parsed[2].seq, 2);
|
|
84
82
|
assert.equal(parsed[1].eventType, "dispatch-match");
|
|
85
|
-
}
|
|
86
|
-
cleanup(base);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test("emitJournalEvent auto-creates nonexistent parent directory", () => {
|
|
91
|
-
const base = join(tmpdir(), `gsd-journal-test-${randomUUID()}`);
|
|
92
|
-
// Don't create .gsd/ — emitJournalEvent should handle it via mkdirSync recursive
|
|
93
|
-
try {
|
|
94
|
-
emitJournalEvent(base, makeEntry());
|
|
95
|
-
const filePath = join(base, ".gsd", "journal", "2025-03-21.jsonl");
|
|
96
|
-
assert.ok(existsSync(filePath), "File should exist even when parent dirs did not");
|
|
97
|
-
} finally {
|
|
98
|
-
cleanup(base);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
83
|
+
});
|
|
101
84
|
|
|
102
|
-
test("
|
|
103
|
-
const base = makeTmpBase();
|
|
104
|
-
try {
|
|
85
|
+
test("preserves optional fields (rule, causedBy, data)", () => {
|
|
105
86
|
const entry = makeEntry({
|
|
106
87
|
rule: "my-dispatch-rule",
|
|
107
88
|
causedBy: { flowId: "flow-prior", seq: 3 },
|
|
@@ -115,24 +96,12 @@ test("emitJournalEvent preserves optional fields (rule, causedBy, data)", () =>
|
|
|
115
96
|
assert.deepEqual(parsed.causedBy, { flowId: "flow-prior", seq: 3 });
|
|
116
97
|
assert.equal(parsed.data.unitId, "M001/S01/T01");
|
|
117
98
|
assert.equal(parsed.data.status, "ok");
|
|
118
|
-
} finally {
|
|
119
|
-
cleanup(base);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test("emitJournalEvent silently catches write errors (no throw)", () => {
|
|
124
|
-
// Use a path that can't be created — null bytes in path
|
|
125
|
-
assert.doesNotThrow(() => {
|
|
126
|
-
emitJournalEvent("/dev/null/impossible\0path", makeEntry());
|
|
127
99
|
});
|
|
128
|
-
});
|
|
129
100
|
|
|
130
|
-
test("
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
mkdirSync(journalDir, { recursive: true });
|
|
101
|
+
test("silently catches read-only directory errors", () => {
|
|
102
|
+
const journalDir = join(base, ".gsd", "journal");
|
|
103
|
+
mkdirSync(journalDir, { recursive: true });
|
|
134
104
|
|
|
135
|
-
try {
|
|
136
105
|
// Make the journal directory read-only
|
|
137
106
|
chmodSync(journalDir, 0o444);
|
|
138
107
|
|
|
@@ -140,22 +109,46 @@ test("emitJournalEvent silently catches read-only directory errors", () => {
|
|
|
140
109
|
assert.doesNotThrow(() => {
|
|
141
110
|
emitJournalEvent(base, makeEntry());
|
|
142
111
|
});
|
|
143
|
-
|
|
112
|
+
|
|
144
113
|
// Restore permissions for cleanup
|
|
145
114
|
try {
|
|
146
115
|
chmodSync(journalDir, 0o755);
|
|
147
116
|
} catch {
|
|
148
117
|
/* */
|
|
149
118
|
}
|
|
150
|
-
|
|
151
|
-
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe("emitJournalEvent — auto-creates parent directory", () => {
|
|
123
|
+
let base: string;
|
|
124
|
+
beforeEach(() => {
|
|
125
|
+
base = join(tmpdir(), `gsd-journal-test-${randomUUID()}`);
|
|
126
|
+
// Don't create .gsd/ — emitJournalEvent should handle it via mkdirSync recursive
|
|
127
|
+
});
|
|
128
|
+
afterEach(() => { cleanup(base); });
|
|
129
|
+
|
|
130
|
+
test("auto-creates nonexistent parent directory", () => {
|
|
131
|
+
emitJournalEvent(base, makeEntry());
|
|
132
|
+
const filePath = join(base, ".gsd", "journal", "2025-03-21.jsonl");
|
|
133
|
+
assert.ok(existsSync(filePath), "File should exist even when parent dirs did not");
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("emitJournalEvent silently catches write errors (no throw)", () => {
|
|
138
|
+
// Use a path that can't be created — null bytes in path
|
|
139
|
+
assert.doesNotThrow(() => {
|
|
140
|
+
emitJournalEvent("/dev/null/impossible\0path", makeEntry());
|
|
141
|
+
});
|
|
152
142
|
});
|
|
153
143
|
|
|
154
144
|
// ─── Daily Rotation ───────────────────────────────────────────────────────────
|
|
155
145
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
146
|
+
describe("daily rotation", () => {
|
|
147
|
+
let base: string;
|
|
148
|
+
beforeEach(() => { base = makeTmpBase(); });
|
|
149
|
+
afterEach(() => { cleanup(base); });
|
|
150
|
+
|
|
151
|
+
test("events with different dates go to different files", () => {
|
|
159
152
|
emitJournalEvent(base, makeEntry({ ts: "2025-03-20T23:59:59.000Z" }));
|
|
160
153
|
emitJournalEvent(base, makeEntry({ ts: "2025-03-21T00:00:01.000Z" }));
|
|
161
154
|
emitJournalEvent(base, makeEntry({ ts: "2025-03-22T12:00:00.000Z" }));
|
|
@@ -172,16 +165,17 @@ test("daily rotation: events with different dates go to different files", () =>
|
|
|
172
165
|
.split("\n");
|
|
173
166
|
assert.equal(lines.length, 1, `${date}.jsonl should have 1 line`);
|
|
174
167
|
}
|
|
175
|
-
}
|
|
176
|
-
cleanup(base);
|
|
177
|
-
}
|
|
168
|
+
});
|
|
178
169
|
});
|
|
179
170
|
|
|
180
171
|
// ─── queryJournal ─────────────────────────────────────────────────────────────
|
|
181
172
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
173
|
+
describe("queryJournal", () => {
|
|
174
|
+
let base: string;
|
|
175
|
+
beforeEach(() => { base = makeTmpBase(); });
|
|
176
|
+
afterEach(() => { cleanup(base); });
|
|
177
|
+
|
|
178
|
+
test("returns all entries when no filters provided", () => {
|
|
185
179
|
emitJournalEvent(base, makeEntry({ seq: 0 }));
|
|
186
180
|
emitJournalEvent(base, makeEntry({ seq: 1, eventType: "dispatch-match" }));
|
|
187
181
|
|
|
@@ -189,14 +183,9 @@ test("queryJournal returns all entries when no filters provided", () => {
|
|
|
189
183
|
assert.equal(results.length, 2);
|
|
190
184
|
assert.equal(results[0].seq, 0);
|
|
191
185
|
assert.equal(results[1].seq, 1);
|
|
192
|
-
}
|
|
193
|
-
cleanup(base);
|
|
194
|
-
}
|
|
195
|
-
});
|
|
186
|
+
});
|
|
196
187
|
|
|
197
|
-
test("
|
|
198
|
-
const base = makeTmpBase();
|
|
199
|
-
try {
|
|
188
|
+
test("filters by flowId", () => {
|
|
200
189
|
emitJournalEvent(base, makeEntry({ flowId: "flow-aaa", seq: 0 }));
|
|
201
190
|
emitJournalEvent(base, makeEntry({ flowId: "flow-bbb", seq: 1 }));
|
|
202
191
|
emitJournalEvent(base, makeEntry({ flowId: "flow-aaa", seq: 2 }));
|
|
@@ -204,14 +193,9 @@ test("queryJournal filters by flowId", () => {
|
|
|
204
193
|
const results = queryJournal(base, { flowId: "flow-aaa" });
|
|
205
194
|
assert.equal(results.length, 2);
|
|
206
195
|
assert.ok(results.every(e => e.flowId === "flow-aaa"));
|
|
207
|
-
}
|
|
208
|
-
cleanup(base);
|
|
209
|
-
}
|
|
210
|
-
});
|
|
196
|
+
});
|
|
211
197
|
|
|
212
|
-
test("
|
|
213
|
-
const base = makeTmpBase();
|
|
214
|
-
try {
|
|
198
|
+
test("filters by eventType", () => {
|
|
215
199
|
emitJournalEvent(base, makeEntry({ eventType: "iteration-start", seq: 0 }));
|
|
216
200
|
emitJournalEvent(base, makeEntry({ eventType: "dispatch-match", seq: 1 }));
|
|
217
201
|
emitJournalEvent(base, makeEntry({ eventType: "unit-start", seq: 2 }));
|
|
@@ -220,14 +204,9 @@ test("queryJournal filters by eventType", () => {
|
|
|
220
204
|
const results = queryJournal(base, { eventType: "dispatch-match" });
|
|
221
205
|
assert.equal(results.length, 2);
|
|
222
206
|
assert.ok(results.every(e => e.eventType === "dispatch-match"));
|
|
223
|
-
}
|
|
224
|
-
cleanup(base);
|
|
225
|
-
}
|
|
226
|
-
});
|
|
207
|
+
});
|
|
227
208
|
|
|
228
|
-
test("
|
|
229
|
-
const base = makeTmpBase();
|
|
230
|
-
try {
|
|
209
|
+
test("filters by unitId (from data.unitId)", () => {
|
|
231
210
|
emitJournalEvent(
|
|
232
211
|
base,
|
|
233
212
|
makeEntry({ seq: 0, data: { unitId: "M001/S01/T01" } }),
|
|
@@ -249,14 +228,9 @@ test("queryJournal filters by unitId (from data.unitId)", () => {
|
|
|
249
228
|
e => (e.data as Record<string, unknown>)?.unitId === "M001/S01/T01",
|
|
250
229
|
),
|
|
251
230
|
);
|
|
252
|
-
}
|
|
253
|
-
cleanup(base);
|
|
254
|
-
}
|
|
255
|
-
});
|
|
231
|
+
});
|
|
256
232
|
|
|
257
|
-
test("
|
|
258
|
-
const base = makeTmpBase();
|
|
259
|
-
try {
|
|
233
|
+
test("filters by time range (after/before)", () => {
|
|
260
234
|
emitJournalEvent(base, makeEntry({ ts: "2025-03-20T08:00:00.000Z", seq: 0 }));
|
|
261
235
|
emitJournalEvent(base, makeEntry({ ts: "2025-03-21T10:00:00.000Z", seq: 1 }));
|
|
262
236
|
emitJournalEvent(base, makeEntry({ ts: "2025-03-21T15:00:00.000Z", seq: 2 }));
|
|
@@ -276,14 +250,9 @@ test("queryJournal filters by time range (after/before)", () => {
|
|
|
276
250
|
before: "2025-03-21T23:59:59.000Z",
|
|
277
251
|
});
|
|
278
252
|
assert.equal(rangeResults.length, 2, "2 entries within 2025-03-21");
|
|
279
|
-
}
|
|
280
|
-
cleanup(base);
|
|
281
|
-
}
|
|
282
|
-
});
|
|
253
|
+
});
|
|
283
254
|
|
|
284
|
-
test("
|
|
285
|
-
const base = makeTmpBase();
|
|
286
|
-
try {
|
|
255
|
+
test("combines multiple filters", () => {
|
|
287
256
|
emitJournalEvent(
|
|
288
257
|
base,
|
|
289
258
|
makeEntry({ flowId: "flow-aaa", eventType: "unit-start", seq: 0 }),
|
|
@@ -304,25 +273,9 @@ test("queryJournal combines multiple filters", () => {
|
|
|
304
273
|
assert.equal(results.length, 1);
|
|
305
274
|
assert.equal(results[0].flowId, "flow-aaa");
|
|
306
275
|
assert.equal(results[0].eventType, "unit-start");
|
|
307
|
-
}
|
|
308
|
-
cleanup(base);
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
test("queryJournal on nonexistent directory returns empty array", () => {
|
|
313
|
-
const base = join(tmpdir(), `gsd-journal-test-${randomUUID()}`);
|
|
314
|
-
// Don't create anything
|
|
315
|
-
try {
|
|
316
|
-
const results = queryJournal(base);
|
|
317
|
-
assert.deepEqual(results, []);
|
|
318
|
-
} finally {
|
|
319
|
-
cleanup(base);
|
|
320
|
-
}
|
|
321
|
-
});
|
|
276
|
+
});
|
|
322
277
|
|
|
323
|
-
test("
|
|
324
|
-
const base = makeTmpBase();
|
|
325
|
-
try {
|
|
278
|
+
test("skips malformed JSON lines gracefully", () => {
|
|
326
279
|
const journalDir = join(base, ".gsd", "journal");
|
|
327
280
|
mkdirSync(journalDir, { recursive: true });
|
|
328
281
|
|
|
@@ -335,14 +288,9 @@ test("queryJournal skips malformed JSON lines gracefully", () => {
|
|
|
335
288
|
assert.equal(results.length, 2, "Should skip the malformed line");
|
|
336
289
|
assert.equal(results[0].seq, 0);
|
|
337
290
|
assert.equal(results[1].seq, 1);
|
|
338
|
-
}
|
|
339
|
-
cleanup(base);
|
|
340
|
-
}
|
|
341
|
-
});
|
|
291
|
+
});
|
|
342
292
|
|
|
343
|
-
test("
|
|
344
|
-
const base = makeTmpBase();
|
|
345
|
-
try {
|
|
293
|
+
test("reads across multiple daily files", () => {
|
|
346
294
|
emitJournalEvent(base, makeEntry({ ts: "2025-03-20T12:00:00.000Z", seq: 0 }));
|
|
347
295
|
emitJournalEvent(base, makeEntry({ ts: "2025-03-21T12:00:00.000Z", seq: 1 }));
|
|
348
296
|
emitJournalEvent(base, makeEntry({ ts: "2025-03-22T12:00:00.000Z", seq: 2 }));
|
|
@@ -353,14 +301,9 @@ test("queryJournal reads across multiple daily files", () => {
|
|
|
353
301
|
assert.equal(results[0].ts, "2025-03-20T12:00:00.000Z");
|
|
354
302
|
assert.equal(results[1].ts, "2025-03-21T12:00:00.000Z");
|
|
355
303
|
assert.equal(results[2].ts, "2025-03-22T12:00:00.000Z");
|
|
356
|
-
}
|
|
357
|
-
cleanup(base);
|
|
358
|
-
}
|
|
359
|
-
});
|
|
304
|
+
});
|
|
360
305
|
|
|
361
|
-
test("
|
|
362
|
-
const base = makeTmpBase();
|
|
363
|
-
try {
|
|
306
|
+
test("filters by rule", () => {
|
|
364
307
|
emitJournalEvent(
|
|
365
308
|
base,
|
|
366
309
|
makeEntry({ seq: 0, eventType: "dispatch-match", rule: "dispatch-task" }),
|
|
@@ -380,7 +323,19 @@ test("queryJournal filters by rule", () => {
|
|
|
380
323
|
results.every(e => e.rule === "dispatch-task"),
|
|
381
324
|
"All results should have rule === 'dispatch-task'",
|
|
382
325
|
);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
describe("queryJournal — nonexistent directory", () => {
|
|
330
|
+
let base: string;
|
|
331
|
+
beforeEach(() => {
|
|
332
|
+
base = join(tmpdir(), `gsd-journal-test-${randomUUID()}`);
|
|
333
|
+
// Don't create anything
|
|
334
|
+
});
|
|
335
|
+
afterEach(() => { cleanup(base); });
|
|
336
|
+
|
|
337
|
+
test("on nonexistent directory returns empty array", () => {
|
|
338
|
+
const results = queryJournal(base);
|
|
339
|
+
assert.deepEqual(results, []);
|
|
340
|
+
});
|
|
386
341
|
});
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Uses temp directories with real .gsd/milestones/M001/ structure.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import test from 'node:test';
|
|
11
|
+
import { describe, test, beforeEach, afterEach } from 'node:test';
|
|
12
12
|
import assert from 'node:assert/strict';
|
|
13
13
|
import { mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
14
14
|
import { join } from 'node:path';
|
|
@@ -30,12 +30,21 @@ function writeManifest(base: string, content: string): void {
|
|
|
30
30
|
|
|
31
31
|
// ─── Mixed statuses ──────────────────────────────────────────────────────────
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
describe('getManifestStatus: mixed statuses', () => {
|
|
34
|
+
let tmp: string;
|
|
35
|
+
let savedVal: string | undefined;
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
tmp = makeTempDir('manifest-mixed');
|
|
38
|
+
savedVal = process.env.GSD_TEST_EXISTING_KEY_001;
|
|
37
39
|
process.env.GSD_TEST_EXISTING_KEY_001 = 'some-value';
|
|
40
|
+
});
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
delete process.env.GSD_TEST_EXISTING_KEY_001;
|
|
43
|
+
if (savedVal !== undefined) process.env.GSD_TEST_EXISTING_KEY_001 = savedVal;
|
|
44
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
45
|
+
});
|
|
38
46
|
|
|
47
|
+
test('categorizes entries correctly', async () => {
|
|
39
48
|
writeManifest(tmp, `# Secrets Manifest
|
|
40
49
|
|
|
41
50
|
**Milestone:** M001
|
|
@@ -80,18 +89,17 @@ test('getManifestStatus: mixed statuses — categorizes entries correctly', asyn
|
|
|
80
89
|
assert.deepStrictEqual(result!.collected, ['COLLECTED_KEY']);
|
|
81
90
|
assert.deepStrictEqual(result!.skipped, ['SKIPPED_KEY']);
|
|
82
91
|
assert.deepStrictEqual(result!.existing, ['GSD_TEST_EXISTING_KEY_001']);
|
|
83
|
-
}
|
|
84
|
-
delete process.env.GSD_TEST_EXISTING_KEY_001;
|
|
85
|
-
if (savedVal !== undefined) process.env.GSD_TEST_EXISTING_KEY_001 = savedVal;
|
|
86
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
87
|
-
}
|
|
92
|
+
});
|
|
88
93
|
});
|
|
89
94
|
|
|
90
95
|
// ─── All pending ─────────────────────────────────────────────────────────────
|
|
91
96
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
describe('getManifestStatus: simple temp dir tests', () => {
|
|
98
|
+
let tmp: string;
|
|
99
|
+
beforeEach(() => { tmp = makeTempDir('manifest-test'); });
|
|
100
|
+
afterEach(() => { rmSync(tmp, { recursive: true, force: true }); });
|
|
101
|
+
|
|
102
|
+
test('all pending — 3 pending entries, none in env', async () => {
|
|
95
103
|
// Ensure none of these are in process.env
|
|
96
104
|
delete process.env.PEND_A;
|
|
97
105
|
delete process.env.PEND_B;
|
|
@@ -133,16 +141,11 @@ test('getManifestStatus: all pending — 3 pending entries, none in env', async
|
|
|
133
141
|
assert.deepStrictEqual(result!.collected, []);
|
|
134
142
|
assert.deepStrictEqual(result!.skipped, []);
|
|
135
143
|
assert.deepStrictEqual(result!.existing, []);
|
|
136
|
-
}
|
|
137
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
138
|
-
}
|
|
139
|
-
});
|
|
144
|
+
});
|
|
140
145
|
|
|
141
|
-
// ─── All collected ───────────────────────────────────────────────────────────
|
|
146
|
+
// ─── All collected ───────────────────────────────────────────────────────────
|
|
142
147
|
|
|
143
|
-
test('
|
|
144
|
-
const tmp = makeTempDir('manifest-collected');
|
|
145
|
-
try {
|
|
148
|
+
test('all collected — 2 collected entries, none in env', async () => {
|
|
146
149
|
delete process.env.COLL_X;
|
|
147
150
|
delete process.env.COLL_Y;
|
|
148
151
|
|
|
@@ -174,64 +177,19 @@ test('getManifestStatus: all collected — 2 collected entries, none in env', as
|
|
|
174
177
|
assert.deepStrictEqual(result!.collected, ['COLL_X', 'COLL_Y']);
|
|
175
178
|
assert.deepStrictEqual(result!.skipped, []);
|
|
176
179
|
assert.deepStrictEqual(result!.existing, []);
|
|
177
|
-
}
|
|
178
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
// ─── Key in env overrides manifest status ────────────────────────────────────
|
|
183
|
-
|
|
184
|
-
test('getManifestStatus: key in env overrides manifest status — collected key in env goes to existing', async () => {
|
|
185
|
-
const tmp = makeTempDir('manifest-override');
|
|
186
|
-
const savedVal = process.env.GSD_TEST_OVERRIDE_KEY;
|
|
187
|
-
try {
|
|
188
|
-
process.env.GSD_TEST_OVERRIDE_KEY = 'already-here';
|
|
189
|
-
|
|
190
|
-
writeManifest(tmp, `# Secrets Manifest
|
|
191
|
-
|
|
192
|
-
**Milestone:** M001
|
|
193
|
-
**Generated:** 2025-06-20T10:00:00Z
|
|
194
|
-
|
|
195
|
-
### GSD_TEST_OVERRIDE_KEY
|
|
196
|
-
|
|
197
|
-
**Service:** Override
|
|
198
|
-
**Status:** collected
|
|
199
|
-
**Destination:** dotenv
|
|
200
|
-
|
|
201
|
-
1. Was collected but now in env
|
|
202
|
-
`);
|
|
203
|
-
|
|
204
|
-
const result = await getManifestStatus(tmp, 'M001');
|
|
205
|
-
assert.notStrictEqual(result, null);
|
|
206
|
-
assert.deepStrictEqual(result!.pending, []);
|
|
207
|
-
assert.deepStrictEqual(result!.collected, []);
|
|
208
|
-
assert.deepStrictEqual(result!.skipped, []);
|
|
209
|
-
assert.deepStrictEqual(result!.existing, ['GSD_TEST_OVERRIDE_KEY']);
|
|
210
|
-
} finally {
|
|
211
|
-
delete process.env.GSD_TEST_OVERRIDE_KEY;
|
|
212
|
-
if (savedVal !== undefined) process.env.GSD_TEST_OVERRIDE_KEY = savedVal;
|
|
213
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
214
|
-
}
|
|
215
|
-
});
|
|
180
|
+
});
|
|
216
181
|
|
|
217
|
-
// ─── Missing manifest ────────────────────────────────────────────────────────
|
|
182
|
+
// ─── Missing manifest ────────────────────────────────────────────────────────
|
|
218
183
|
|
|
219
|
-
test('
|
|
220
|
-
const tmp = makeTempDir('manifest-missing');
|
|
221
|
-
try {
|
|
184
|
+
test('missing manifest — returns null', async () => {
|
|
222
185
|
// No .gsd directory at all
|
|
223
186
|
const result = await getManifestStatus(tmp, 'M001');
|
|
224
187
|
assert.strictEqual(result, null);
|
|
225
|
-
}
|
|
226
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
227
|
-
}
|
|
228
|
-
});
|
|
188
|
+
});
|
|
229
189
|
|
|
230
|
-
// ─── Empty manifest (no entries) ─────────────────────────────────────────────
|
|
190
|
+
// ─── Empty manifest (no entries) ─────────────────────────────────────────────
|
|
231
191
|
|
|
232
|
-
test('
|
|
233
|
-
const tmp = makeTempDir('manifest-empty');
|
|
234
|
-
try {
|
|
192
|
+
test('empty manifest — exists but no H3 sections', async () => {
|
|
235
193
|
writeManifest(tmp, `# Secrets Manifest
|
|
236
194
|
|
|
237
195
|
**Milestone:** M001
|
|
@@ -244,16 +202,11 @@ test('getManifestStatus: empty manifest — exists but no H3 sections', async ()
|
|
|
244
202
|
assert.deepStrictEqual(result!.collected, []);
|
|
245
203
|
assert.deepStrictEqual(result!.skipped, []);
|
|
246
204
|
assert.deepStrictEqual(result!.existing, []);
|
|
247
|
-
}
|
|
248
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
249
|
-
}
|
|
250
|
-
});
|
|
205
|
+
});
|
|
251
206
|
|
|
252
|
-
// ─── Env via .env file (not just process.env) ────────────────────────────────
|
|
207
|
+
// ─── Env via .env file (not just process.env) ────────────────────────────────
|
|
253
208
|
|
|
254
|
-
test('
|
|
255
|
-
const tmp = makeTempDir('manifest-dotenv');
|
|
256
|
-
try {
|
|
209
|
+
test('key in .env file counts as existing', async () => {
|
|
257
210
|
delete process.env.DOTENV_ONLY_KEY;
|
|
258
211
|
|
|
259
212
|
writeManifest(tmp, `# Secrets Manifest
|
|
@@ -277,7 +230,45 @@ test('getManifestStatus: key in .env file counts as existing', async () => {
|
|
|
277
230
|
assert.notStrictEqual(result, null);
|
|
278
231
|
assert.deepStrictEqual(result!.existing, ['DOTENV_ONLY_KEY']);
|
|
279
232
|
assert.deepStrictEqual(result!.pending, []);
|
|
280
|
-
}
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// ─── Key in env overrides manifest status ────────────────────────────────────
|
|
237
|
+
|
|
238
|
+
describe('getManifestStatus: key in env overrides manifest status', () => {
|
|
239
|
+
let tmp: string;
|
|
240
|
+
let savedVal: string | undefined;
|
|
241
|
+
beforeEach(() => {
|
|
242
|
+
tmp = makeTempDir('manifest-override');
|
|
243
|
+
savedVal = process.env.GSD_TEST_OVERRIDE_KEY;
|
|
244
|
+
process.env.GSD_TEST_OVERRIDE_KEY = 'already-here';
|
|
245
|
+
});
|
|
246
|
+
afterEach(() => {
|
|
247
|
+
delete process.env.GSD_TEST_OVERRIDE_KEY;
|
|
248
|
+
if (savedVal !== undefined) process.env.GSD_TEST_OVERRIDE_KEY = savedVal;
|
|
281
249
|
rmSync(tmp, { recursive: true, force: true });
|
|
282
|
-
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test('collected key in env goes to existing', async () => {
|
|
253
|
+
writeManifest(tmp, `# Secrets Manifest
|
|
254
|
+
|
|
255
|
+
**Milestone:** M001
|
|
256
|
+
**Generated:** 2025-06-20T10:00:00Z
|
|
257
|
+
|
|
258
|
+
### GSD_TEST_OVERRIDE_KEY
|
|
259
|
+
|
|
260
|
+
**Service:** Override
|
|
261
|
+
**Status:** collected
|
|
262
|
+
**Destination:** dotenv
|
|
263
|
+
|
|
264
|
+
1. Was collected but now in env
|
|
265
|
+
`);
|
|
266
|
+
|
|
267
|
+
const result = await getManifestStatus(tmp, 'M001');
|
|
268
|
+
assert.notStrictEqual(result, null);
|
|
269
|
+
assert.deepStrictEqual(result!.pending, []);
|
|
270
|
+
assert.deepStrictEqual(result!.collected, []);
|
|
271
|
+
assert.deepStrictEqual(result!.skipped, []);
|
|
272
|
+
assert.deepStrictEqual(result!.existing, ['GSD_TEST_OVERRIDE_KEY']);
|
|
273
|
+
});
|
|
283
274
|
});
|