@tuan_son.dinh/gsd 2.6.0
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/LICENSE +21 -0
- package/README.md +453 -0
- package/dist/app-paths.d.ts +4 -0
- package/dist/app-paths.js +6 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +269 -0
- package/dist/loader.d.ts +2 -0
- package/dist/loader.js +70 -0
- package/dist/logo.d.ts +16 -0
- package/dist/logo.js +25 -0
- package/dist/onboarding.d.ts +43 -0
- package/dist/onboarding.js +418 -0
- package/dist/pi-migration.d.ts +14 -0
- package/dist/pi-migration.js +57 -0
- package/dist/resource-loader.d.ts +22 -0
- package/dist/resource-loader.js +60 -0
- package/dist/tool-bootstrap.d.ts +4 -0
- package/dist/tool-bootstrap.js +74 -0
- package/dist/wizard.d.ts +7 -0
- package/dist/wizard.js +25 -0
- package/package.json +60 -0
- package/patches/@mariozechner+pi-coding-agent+0.57.1.patch +108 -0
- package/patches/@mariozechner+pi-tui+0.57.1.patch +47 -0
- package/pkg/dist/modes/interactive/theme/dark.json +85 -0
- package/pkg/dist/modes/interactive/theme/light.json +84 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts +78 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme.js +949 -0
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -0
- package/pkg/package.json +8 -0
- package/scripts/postinstall.js +127 -0
- package/src/resources/GSD-WORKFLOW.md +661 -0
- package/src/resources/agents/researcher.md +29 -0
- package/src/resources/agents/scout.md +56 -0
- package/src/resources/agents/worker.md +31 -0
- package/src/resources/extensions/ask-user-questions.ts +249 -0
- package/src/resources/extensions/bg-shell/index.ts +2808 -0
- package/src/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
- package/src/resources/extensions/browser-tools/core.js +1057 -0
- package/src/resources/extensions/browser-tools/index.ts +4989 -0
- package/src/resources/extensions/browser-tools/package.json +20 -0
- package/src/resources/extensions/context7/index.ts +428 -0
- package/src/resources/extensions/context7/package.json +11 -0
- package/src/resources/extensions/get-secrets-from-user.ts +352 -0
- package/src/resources/extensions/google-search/index.ts +323 -0
- package/src/resources/extensions/google-search/package.json +9 -0
- package/src/resources/extensions/gsd/activity-log.ts +69 -0
- package/src/resources/extensions/gsd/auto.ts +2744 -0
- package/src/resources/extensions/gsd/commands.ts +313 -0
- package/src/resources/extensions/gsd/crash-recovery.ts +85 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +521 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +176 -0
- package/src/resources/extensions/gsd/doctor.ts +690 -0
- package/src/resources/extensions/gsd/files.ts +732 -0
- package/src/resources/extensions/gsd/git-service.ts +597 -0
- package/src/resources/extensions/gsd/gitignore.ts +168 -0
- package/src/resources/extensions/gsd/guided-flow.ts +817 -0
- package/src/resources/extensions/gsd/index.ts +558 -0
- package/src/resources/extensions/gsd/metrics.ts +374 -0
- package/src/resources/extensions/gsd/migrate/command.ts +218 -0
- package/src/resources/extensions/gsd/migrate/index.ts +42 -0
- package/src/resources/extensions/gsd/migrate/parser.ts +323 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +624 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +48 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +346 -0
- package/src/resources/extensions/gsd/migrate/types.ts +370 -0
- package/src/resources/extensions/gsd/migrate/validator.ts +55 -0
- package/src/resources/extensions/gsd/migrate/writer.ts +539 -0
- package/src/resources/extensions/gsd/observability-validator.ts +408 -0
- package/src/resources/extensions/gsd/package.json +11 -0
- package/src/resources/extensions/gsd/paths.ts +308 -0
- package/src/resources/extensions/gsd/preferences.ts +757 -0
- package/src/resources/extensions/gsd/prompt-loader.ts +50 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +25 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +29 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +189 -0
- package/src/resources/extensions/gsd/prompts/doctor-heal.md +29 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +61 -0
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +59 -0
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -0
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +23 -0
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +11 -0
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -0
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +65 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +51 -0
- package/src/resources/extensions/gsd/prompts/queue.md +85 -0
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +48 -0
- package/src/resources/extensions/gsd/prompts/replan-slice.md +39 -0
- package/src/resources/extensions/gsd/prompts/research-milestone.md +37 -0
- package/src/resources/extensions/gsd/prompts/research-slice.md +28 -0
- package/src/resources/extensions/gsd/prompts/review-migration.md +66 -0
- package/src/resources/extensions/gsd/prompts/run-uat.md +109 -0
- package/src/resources/extensions/gsd/prompts/system.md +187 -0
- package/src/resources/extensions/gsd/prompts/worktree-merge.md +123 -0
- package/src/resources/extensions/gsd/session-forensics.ts +487 -0
- package/src/resources/extensions/gsd/skill-discovery.ts +137 -0
- package/src/resources/extensions/gsd/state.ts +460 -0
- package/src/resources/extensions/gsd/templates/context.md +76 -0
- package/src/resources/extensions/gsd/templates/decisions.md +8 -0
- package/src/resources/extensions/gsd/templates/milestone-summary.md +73 -0
- package/src/resources/extensions/gsd/templates/plan.md +131 -0
- package/src/resources/extensions/gsd/templates/preferences.md +24 -0
- package/src/resources/extensions/gsd/templates/project.md +31 -0
- package/src/resources/extensions/gsd/templates/reassessment.md +28 -0
- package/src/resources/extensions/gsd/templates/requirements.md +81 -0
- package/src/resources/extensions/gsd/templates/research.md +46 -0
- package/src/resources/extensions/gsd/templates/roadmap.md +118 -0
- package/src/resources/extensions/gsd/templates/slice-context.md +58 -0
- package/src/resources/extensions/gsd/templates/slice-summary.md +99 -0
- package/src/resources/extensions/gsd/templates/state.md +19 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +52 -0
- package/src/resources/extensions/gsd/templates/task-summary.md +57 -0
- package/src/resources/extensions/gsd/templates/uat.md +54 -0
- package/src/resources/extensions/gsd/tests/activity-log-prune.test.ts +327 -0
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +53 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +225 -0
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +160 -0
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +341 -0
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +689 -0
- package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/doctor.test.ts +505 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +1313 -0
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +308 -0
- package/src/resources/extensions/gsd/tests/metrics-io.test.ts +201 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +217 -0
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +390 -0
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +786 -0
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +657 -0
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +443 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +318 -0
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +420 -0
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +309 -0
- package/src/resources/extensions/gsd/tests/parsers.test.ts +1351 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +163 -0
- package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +386 -0
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +171 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +155 -0
- package/src/resources/extensions/gsd/tests/remote-status.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +521 -0
- package/src/resources/extensions/gsd/tests/requirements.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +34 -0
- package/src/resources/extensions/gsd/tests/resolve-ts.mjs +11 -0
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +247 -0
- package/src/resources/extensions/gsd/tests/workflow-config.test.mjs +53 -0
- package/src/resources/extensions/gsd/tests/workspace-index.test.ts +94 -0
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +253 -0
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +160 -0
- package/src/resources/extensions/gsd/tests/worktree.test.ts +264 -0
- package/src/resources/extensions/gsd/types.ts +159 -0
- package/src/resources/extensions/gsd/unit-runtime.ts +184 -0
- package/src/resources/extensions/gsd/workspace-index.ts +203 -0
- package/src/resources/extensions/gsd/worktree-command.ts +845 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +392 -0
- package/src/resources/extensions/gsd/worktree.ts +183 -0
- package/src/resources/extensions/mac-tools/index.ts +852 -0
- package/src/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
- package/src/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
- package/src/resources/extensions/mcporter/index.ts +429 -0
- package/src/resources/extensions/remote-questions/config.ts +81 -0
- package/src/resources/extensions/remote-questions/discord-adapter.ts +128 -0
- package/src/resources/extensions/remote-questions/format.ts +163 -0
- package/src/resources/extensions/remote-questions/manager.ts +192 -0
- package/src/resources/extensions/remote-questions/remote-command.ts +307 -0
- package/src/resources/extensions/remote-questions/slack-adapter.ts +92 -0
- package/src/resources/extensions/remote-questions/status.ts +31 -0
- package/src/resources/extensions/remote-questions/store.ts +77 -0
- package/src/resources/extensions/remote-questions/types.ts +75 -0
- package/src/resources/extensions/search-the-web/cache.ts +78 -0
- package/src/resources/extensions/search-the-web/command-search-provider.ts +95 -0
- package/src/resources/extensions/search-the-web/format.ts +258 -0
- package/src/resources/extensions/search-the-web/http.ts +238 -0
- package/src/resources/extensions/search-the-web/index.ts +65 -0
- package/src/resources/extensions/search-the-web/native-search.ts +157 -0
- package/src/resources/extensions/search-the-web/provider.ts +118 -0
- package/src/resources/extensions/search-the-web/tavily.ts +116 -0
- package/src/resources/extensions/search-the-web/tool-fetch-page.ts +519 -0
- package/src/resources/extensions/search-the-web/tool-llm-context.ts +561 -0
- package/src/resources/extensions/search-the-web/tool-search.ts +576 -0
- package/src/resources/extensions/search-the-web/url-utils.ts +91 -0
- package/src/resources/extensions/shared/confirm-ui.ts +126 -0
- package/src/resources/extensions/shared/interview-ui.ts +613 -0
- package/src/resources/extensions/shared/next-action-ui.ts +197 -0
- package/src/resources/extensions/shared/progress-widget.ts +282 -0
- package/src/resources/extensions/shared/terminal.ts +23 -0
- package/src/resources/extensions/shared/thinking-widget.ts +107 -0
- package/src/resources/extensions/shared/ui.ts +400 -0
- package/src/resources/extensions/shared/wizard-ui.ts +551 -0
- package/src/resources/extensions/slash-commands/audit.ts +88 -0
- package/src/resources/extensions/slash-commands/clear.ts +10 -0
- package/src/resources/extensions/slash-commands/create-extension.ts +297 -0
- package/src/resources/extensions/slash-commands/create-slash-command.ts +234 -0
- package/src/resources/extensions/slash-commands/index.ts +12 -0
- package/src/resources/extensions/subagent/agents.ts +126 -0
- package/src/resources/extensions/subagent/index.ts +1020 -0
- package/src/resources/extensions/voice/index.ts +195 -0
- package/src/resources/extensions/voice/speech-recognizer.swift +154 -0
- package/src/resources/skills/debug-like-expert/SKILL.md +231 -0
- package/src/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
- package/src/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
- package/src/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
- package/src/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
- package/src/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
- package/src/resources/skills/frontend-design/SKILL.md +45 -0
- package/src/resources/skills/swiftui/SKILL.md +208 -0
- package/src/resources/skills/swiftui/references/animations.md +921 -0
- package/src/resources/skills/swiftui/references/architecture.md +1561 -0
- package/src/resources/skills/swiftui/references/layout-system.md +1186 -0
- package/src/resources/skills/swiftui/references/navigation.md +1492 -0
- package/src/resources/skills/swiftui/references/networking-async.md +214 -0
- package/src/resources/skills/swiftui/references/performance.md +1706 -0
- package/src/resources/skills/swiftui/references/platform-integration.md +204 -0
- package/src/resources/skills/swiftui/references/state-management.md +1443 -0
- package/src/resources/skills/swiftui/references/swiftdata.md +297 -0
- package/src/resources/skills/swiftui/references/testing-debugging.md +247 -0
- package/src/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
- package/src/resources/skills/swiftui/workflows/add-feature.md +191 -0
- package/src/resources/skills/swiftui/workflows/build-new-app.md +311 -0
- package/src/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
- package/src/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
- package/src/resources/skills/swiftui/workflows/ship-app.md +203 -0
- package/src/resources/skills/swiftui/workflows/write-tests.md +235 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
// Unit tests for T02: validator and per-file parsers
|
|
2
|
+
// Tests these independently of the T03 orchestrator (parsePlanningDirectory).
|
|
3
|
+
|
|
4
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
|
|
8
|
+
import { validatePlanningDirectory } from '../migrate/validator.ts';
|
|
9
|
+
import {
|
|
10
|
+
parseOldRoadmap,
|
|
11
|
+
parseOldPlan,
|
|
12
|
+
parseOldSummary,
|
|
13
|
+
parseOldRequirements,
|
|
14
|
+
parseOldProject,
|
|
15
|
+
parseOldState,
|
|
16
|
+
parseOldConfig,
|
|
17
|
+
} from '../migrate/parsers.ts';
|
|
18
|
+
|
|
19
|
+
let passed = 0;
|
|
20
|
+
let failed = 0;
|
|
21
|
+
|
|
22
|
+
function assert(condition: boolean, message: string): void {
|
|
23
|
+
if (condition) {
|
|
24
|
+
passed++;
|
|
25
|
+
} else {
|
|
26
|
+
failed++;
|
|
27
|
+
console.error(` FAIL: ${message}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function assertEq<T>(actual: T, expected: T, message: string): void {
|
|
32
|
+
if (JSON.stringify(actual) === JSON.stringify(expected)) {
|
|
33
|
+
passed++;
|
|
34
|
+
} else {
|
|
35
|
+
failed++;
|
|
36
|
+
console.error(` FAIL: ${message} — expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function createFixtureBase(): string {
|
|
41
|
+
return mkdtempSync(join(tmpdir(), 'gsd-migrate-t02-'));
|
|
42
|
+
}
|
|
43
|
+
function createPlanningDir(base: string): string {
|
|
44
|
+
const dir = join(base, '.planning');
|
|
45
|
+
mkdirSync(dir, { recursive: true });
|
|
46
|
+
return dir;
|
|
47
|
+
}
|
|
48
|
+
function cleanup(base: string): void {
|
|
49
|
+
rmSync(base, { recursive: true, force: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ─── Sample Fixtures ───────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
const SAMPLE_ROADMAP = `# Project Roadmap
|
|
55
|
+
|
|
56
|
+
## Phases
|
|
57
|
+
|
|
58
|
+
- [x] 29 — Auth System
|
|
59
|
+
- [ ] 30 — Dashboard
|
|
60
|
+
- [ ] 31 — Notifications
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
const SAMPLE_PROJECT = `# My Project
|
|
64
|
+
|
|
65
|
+
A sample project for testing the migration parser.
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const SAMPLE_MILESTONE_SECTIONED_ROADMAP = `# Project Roadmap
|
|
69
|
+
|
|
70
|
+
## v2.0 — Foundation
|
|
71
|
+
|
|
72
|
+
<details>
|
|
73
|
+
<summary>Completed</summary>
|
|
74
|
+
|
|
75
|
+
- [x] 01 — Project Setup
|
|
76
|
+
- [x] 02 — Database Schema
|
|
77
|
+
|
|
78
|
+
</details>
|
|
79
|
+
|
|
80
|
+
## v2.5 — Features
|
|
81
|
+
|
|
82
|
+
- [x] 29 — Auth System
|
|
83
|
+
- [ ] 30 — Dashboard
|
|
84
|
+
- [ ] 31 — Notifications
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
const SAMPLE_PLAN_XML = `---
|
|
88
|
+
phase: "29-auth-system"
|
|
89
|
+
plan: "01"
|
|
90
|
+
type: "implementation"
|
|
91
|
+
wave: 1
|
|
92
|
+
depends_on: []
|
|
93
|
+
files_modified: [src/auth.ts, src/login.ts]
|
|
94
|
+
autonomous: true
|
|
95
|
+
must_haves:
|
|
96
|
+
truths:
|
|
97
|
+
- Users can log in
|
|
98
|
+
artifacts:
|
|
99
|
+
- src/auth.ts
|
|
100
|
+
key_links: []
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
# 29-01: Implement Auth
|
|
104
|
+
|
|
105
|
+
<objective>
|
|
106
|
+
Build the authentication system with JWT tokens and session management.
|
|
107
|
+
</objective>
|
|
108
|
+
|
|
109
|
+
<tasks>
|
|
110
|
+
<task>Create auth middleware</task>
|
|
111
|
+
<task>Add login endpoint</task>
|
|
112
|
+
<task>Add logout endpoint</task>
|
|
113
|
+
</tasks>
|
|
114
|
+
|
|
115
|
+
<context>
|
|
116
|
+
The project needs authentication before any other features can be built.
|
|
117
|
+
Auth tokens use JWT with RS256 signing.
|
|
118
|
+
</context>
|
|
119
|
+
|
|
120
|
+
<verification>
|
|
121
|
+
- Login returns valid JWT
|
|
122
|
+
- Middleware rejects invalid tokens
|
|
123
|
+
- Logout invalidates session
|
|
124
|
+
</verification>
|
|
125
|
+
|
|
126
|
+
<success_criteria>
|
|
127
|
+
All auth endpoints respond correctly and tokens are validated.
|
|
128
|
+
</success_criteria>
|
|
129
|
+
`;
|
|
130
|
+
|
|
131
|
+
const SAMPLE_SUMMARY = `---
|
|
132
|
+
phase: "29-auth-system"
|
|
133
|
+
plan: "01"
|
|
134
|
+
subsystem: "auth"
|
|
135
|
+
tags:
|
|
136
|
+
- authentication
|
|
137
|
+
- security
|
|
138
|
+
requires: []
|
|
139
|
+
provides:
|
|
140
|
+
- auth-middleware
|
|
141
|
+
- jwt-validation
|
|
142
|
+
affects:
|
|
143
|
+
- api-routes
|
|
144
|
+
tech-stack:
|
|
145
|
+
- jsonwebtoken
|
|
146
|
+
- express
|
|
147
|
+
key-files:
|
|
148
|
+
- src/auth.ts
|
|
149
|
+
- src/middleware/auth.ts
|
|
150
|
+
key-decisions:
|
|
151
|
+
- Use RS256 for JWT signing
|
|
152
|
+
- Store refresh tokens in DB
|
|
153
|
+
patterns-established:
|
|
154
|
+
- Middleware-based auth
|
|
155
|
+
duration: "2h"
|
|
156
|
+
completed: "2026-01-15"
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
# 29-01: Auth Implementation Summary
|
|
160
|
+
|
|
161
|
+
Authentication system implemented with JWT tokens.
|
|
162
|
+
`;
|
|
163
|
+
|
|
164
|
+
const SAMPLE_REQUIREMENTS = `# Requirements
|
|
165
|
+
|
|
166
|
+
## Active
|
|
167
|
+
|
|
168
|
+
### R001 — User Authentication
|
|
169
|
+
- Status: active
|
|
170
|
+
- Description: Users must be able to log in.
|
|
171
|
+
|
|
172
|
+
### R002 — Dashboard View
|
|
173
|
+
- Status: active
|
|
174
|
+
- Description: Main dashboard page.
|
|
175
|
+
|
|
176
|
+
## Validated
|
|
177
|
+
|
|
178
|
+
### R003 — Session Management
|
|
179
|
+
- Status: validated
|
|
180
|
+
- Description: Sessions expire after 24h.
|
|
181
|
+
|
|
182
|
+
## Deferred
|
|
183
|
+
|
|
184
|
+
### R004 — OAuth Support
|
|
185
|
+
- Status: deferred
|
|
186
|
+
- Description: Third-party login.
|
|
187
|
+
`;
|
|
188
|
+
|
|
189
|
+
const SAMPLE_STATE = `# State
|
|
190
|
+
|
|
191
|
+
**Current Phase:** 30-dashboard
|
|
192
|
+
**Status:** in-progress
|
|
193
|
+
`;
|
|
194
|
+
|
|
195
|
+
async function main(): Promise<void> {
|
|
196
|
+
|
|
197
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
198
|
+
// Validator Tests
|
|
199
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
200
|
+
|
|
201
|
+
console.log('\n=== Validator: missing directory → fatal ===');
|
|
202
|
+
{
|
|
203
|
+
const base = createFixtureBase();
|
|
204
|
+
try {
|
|
205
|
+
const result = await validatePlanningDirectory(join(base, 'nonexistent'));
|
|
206
|
+
assertEq(result.valid, false, 'missing dir: validation fails');
|
|
207
|
+
assert(result.issues.length > 0, 'missing dir: has issues');
|
|
208
|
+
assert(result.issues.some(i => i.severity === 'fatal'), 'missing dir: has fatal issue');
|
|
209
|
+
} finally {
|
|
210
|
+
cleanup(base);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
console.log('\n=== Validator: missing ROADMAP.md → warning (not fatal) ===');
|
|
215
|
+
{
|
|
216
|
+
const base = createFixtureBase();
|
|
217
|
+
try {
|
|
218
|
+
const planning = createPlanningDir(base);
|
|
219
|
+
writeFileSync(join(planning, 'PROJECT.md'), SAMPLE_PROJECT);
|
|
220
|
+
const result = await validatePlanningDirectory(planning);
|
|
221
|
+
assertEq(result.valid, true, 'no roadmap: validation still passes');
|
|
222
|
+
assert(result.issues.some(i => i.severity === 'warning' && i.file.includes('ROADMAP')), 'no roadmap: warning issue mentions ROADMAP');
|
|
223
|
+
} finally {
|
|
224
|
+
cleanup(base);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
console.log('\n=== Validator: missing PROJECT.md → warning ===');
|
|
229
|
+
{
|
|
230
|
+
const base = createFixtureBase();
|
|
231
|
+
try {
|
|
232
|
+
const planning = createPlanningDir(base);
|
|
233
|
+
writeFileSync(join(planning, 'ROADMAP.md'), SAMPLE_ROADMAP);
|
|
234
|
+
const result = await validatePlanningDirectory(planning);
|
|
235
|
+
assertEq(result.valid, true, 'no project: validation passes (warning only)');
|
|
236
|
+
assert(result.issues.some(i => i.severity === 'warning' && i.file.includes('PROJECT')), 'no project: warning issue mentions PROJECT');
|
|
237
|
+
} finally {
|
|
238
|
+
cleanup(base);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.log('\n=== Validator: complete directory → valid with no issues ===');
|
|
243
|
+
{
|
|
244
|
+
const base = createFixtureBase();
|
|
245
|
+
try {
|
|
246
|
+
const planning = createPlanningDir(base);
|
|
247
|
+
writeFileSync(join(planning, 'ROADMAP.md'), SAMPLE_ROADMAP);
|
|
248
|
+
writeFileSync(join(planning, 'PROJECT.md'), SAMPLE_PROJECT);
|
|
249
|
+
writeFileSync(join(planning, 'REQUIREMENTS.md'), SAMPLE_REQUIREMENTS);
|
|
250
|
+
writeFileSync(join(planning, 'STATE.md'), SAMPLE_STATE);
|
|
251
|
+
mkdirSync(join(planning, 'phases'), { recursive: true });
|
|
252
|
+
const result = await validatePlanningDirectory(planning);
|
|
253
|
+
assertEq(result.valid, true, 'complete dir: validation passes');
|
|
254
|
+
assertEq(result.issues.length, 0, 'complete dir: no issues');
|
|
255
|
+
} finally {
|
|
256
|
+
cleanup(base);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
261
|
+
// Roadmap Parser Tests
|
|
262
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
263
|
+
|
|
264
|
+
console.log('\n=== parseOldRoadmap: flat format ===');
|
|
265
|
+
{
|
|
266
|
+
const roadmap = parseOldRoadmap(SAMPLE_ROADMAP);
|
|
267
|
+
assertEq(roadmap.milestones.length, 0, 'flat roadmap: no milestone sections');
|
|
268
|
+
assertEq(roadmap.phases.length, 3, 'flat roadmap: 3 phases');
|
|
269
|
+
assertEq(roadmap.phases[0].number, 29, 'flat roadmap: first phase number');
|
|
270
|
+
assertEq(roadmap.phases[0].title, 'Auth System', 'flat roadmap: first phase title');
|
|
271
|
+
assertEq(roadmap.phases[0].done, true, 'flat roadmap: first phase done');
|
|
272
|
+
assertEq(roadmap.phases[1].done, false, 'flat roadmap: second phase not done');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
console.log('\n=== parseOldRoadmap: milestone-sectioned with <details> ===');
|
|
276
|
+
{
|
|
277
|
+
const roadmap = parseOldRoadmap(SAMPLE_MILESTONE_SECTIONED_ROADMAP);
|
|
278
|
+
assert(roadmap.milestones.length >= 2, 'ms roadmap: has milestone sections');
|
|
279
|
+
|
|
280
|
+
const v20 = roadmap.milestones.find(m => m.id.includes('2.0'));
|
|
281
|
+
assert(v20 !== undefined, 'ms roadmap: v2.0 found');
|
|
282
|
+
assertEq(v20?.collapsed, true, 'ms roadmap: v2.0 collapsed');
|
|
283
|
+
assert((v20?.phases.length ?? 0) >= 2, 'ms roadmap: v2.0 has phases');
|
|
284
|
+
assert(v20?.phases.every(p => p.done) ?? false, 'ms roadmap: v2.0 all done');
|
|
285
|
+
|
|
286
|
+
const v25 = roadmap.milestones.find(m => m.id.includes('2.5'));
|
|
287
|
+
assert(v25 !== undefined, 'ms roadmap: v2.5 found');
|
|
288
|
+
assertEq(v25?.collapsed, false, 'ms roadmap: v2.5 not collapsed');
|
|
289
|
+
assert((v25?.phases.length ?? 0) >= 3, 'ms roadmap: v2.5 has 3 phases');
|
|
290
|
+
|
|
291
|
+
const p29 = v25?.phases.find(p => p.number === 29);
|
|
292
|
+
assertEq(p29?.done, true, 'ms roadmap: phase 29 done');
|
|
293
|
+
const p30 = v25?.phases.find(p => p.number === 30);
|
|
294
|
+
assertEq(p30?.done, false, 'ms roadmap: phase 30 not done');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
298
|
+
// Plan Parser Tests
|
|
299
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
300
|
+
|
|
301
|
+
console.log('\n=== parseOldPlan: XML-in-markdown ===');
|
|
302
|
+
{
|
|
303
|
+
const plan = parseOldPlan(SAMPLE_PLAN_XML, '29-01-PLAN.md', '01');
|
|
304
|
+
assert(plan.objective.includes('authentication'), 'plan: objective extracted');
|
|
305
|
+
assertEq(plan.tasks.length, 3, 'plan: 3 tasks');
|
|
306
|
+
assert(plan.tasks[0].includes('auth middleware'), 'plan: first task content');
|
|
307
|
+
assert(plan.context.includes('JWT'), 'plan: context extracted');
|
|
308
|
+
assert(plan.verification.includes('Login returns'), 'plan: verification extracted');
|
|
309
|
+
assert(plan.successCriteria.includes('endpoints respond'), 'plan: success criteria extracted');
|
|
310
|
+
|
|
311
|
+
// Frontmatter
|
|
312
|
+
assertEq(plan.frontmatter.phase, '29-auth-system', 'plan fm: phase');
|
|
313
|
+
assertEq(plan.frontmatter.plan, '01', 'plan fm: plan');
|
|
314
|
+
assertEq(plan.frontmatter.type, 'implementation', 'plan fm: type');
|
|
315
|
+
assertEq(plan.frontmatter.wave, 1, 'plan fm: wave');
|
|
316
|
+
assertEq(plan.frontmatter.autonomous, true, 'plan fm: autonomous');
|
|
317
|
+
assert(plan.frontmatter.files_modified.length >= 2, 'plan fm: files_modified');
|
|
318
|
+
assert(plan.frontmatter.must_haves !== null, 'plan fm: must_haves parsed');
|
|
319
|
+
assert((plan.frontmatter.must_haves?.truths.length ?? 0) >= 1, 'plan fm: must_haves truths');
|
|
320
|
+
assert((plan.frontmatter.must_haves?.artifacts.length ?? 0) >= 1, 'plan fm: must_haves artifacts');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
console.log('\n=== parseOldPlan: plain markdown (no XML tags) ===');
|
|
324
|
+
{
|
|
325
|
+
const plainPlan = `# 001: Fix Login Bug
|
|
326
|
+
|
|
327
|
+
## Description
|
|
328
|
+
|
|
329
|
+
Fix the login button not responding on mobile.
|
|
330
|
+
|
|
331
|
+
## Steps
|
|
332
|
+
|
|
333
|
+
1. Debug click handler
|
|
334
|
+
2. Fix event propagation
|
|
335
|
+
`;
|
|
336
|
+
const plan = parseOldPlan(plainPlan, '001-PLAN.md', '001');
|
|
337
|
+
assertEq(plan.objective, '', 'plain plan: no objective (no XML)');
|
|
338
|
+
assertEq(plan.tasks.length, 0, 'plain plan: no tasks (no XML)');
|
|
339
|
+
assertEq(plan.frontmatter.phase, '', 'plain plan: no frontmatter phase');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
343
|
+
// Summary Parser Tests
|
|
344
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
345
|
+
|
|
346
|
+
console.log('\n=== parseOldSummary: YAML frontmatter ===');
|
|
347
|
+
{
|
|
348
|
+
const summary = parseOldSummary(SAMPLE_SUMMARY, '29-01-SUMMARY.md', '01');
|
|
349
|
+
assertEq(summary.frontmatter.phase, '29-auth-system', 'summary fm: phase');
|
|
350
|
+
assertEq(summary.frontmatter.plan, '01', 'summary fm: plan');
|
|
351
|
+
assertEq(summary.frontmatter.subsystem, 'auth', 'summary fm: subsystem');
|
|
352
|
+
assertEq(summary.frontmatter.tags, ['authentication', 'security'], 'summary fm: tags');
|
|
353
|
+
assertEq(summary.frontmatter.provides, ['auth-middleware', 'jwt-validation'], 'summary fm: provides');
|
|
354
|
+
assertEq(summary.frontmatter.affects, ['api-routes'], 'summary fm: affects');
|
|
355
|
+
assertEq(summary.frontmatter['tech-stack'], ['jsonwebtoken', 'express'], 'summary fm: tech-stack');
|
|
356
|
+
assertEq(summary.frontmatter['key-files'], ['src/auth.ts', 'src/middleware/auth.ts'], 'summary fm: key-files');
|
|
357
|
+
assertEq(summary.frontmatter['key-decisions'], ['Use RS256 for JWT signing', 'Store refresh tokens in DB'], 'summary fm: key-decisions');
|
|
358
|
+
assertEq(summary.frontmatter['patterns-established'], ['Middleware-based auth'], 'summary fm: patterns-established');
|
|
359
|
+
assertEq(summary.frontmatter.duration, '2h', 'summary fm: duration');
|
|
360
|
+
assertEq(summary.frontmatter.completed, '2026-01-15', 'summary fm: completed');
|
|
361
|
+
assert(summary.body.includes('Auth Implementation Summary'), 'summary: body content present');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
365
|
+
// Requirements Parser Tests
|
|
366
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
367
|
+
|
|
368
|
+
console.log('\n=== parseOldRequirements ===');
|
|
369
|
+
{
|
|
370
|
+
const reqs = parseOldRequirements(SAMPLE_REQUIREMENTS);
|
|
371
|
+
assertEq(reqs.length, 4, 'requirements: 4 entries');
|
|
372
|
+
assertEq(reqs[0].id, 'R001', 'req 0: id');
|
|
373
|
+
assertEq(reqs[0].title, 'User Authentication', 'req 0: title');
|
|
374
|
+
assertEq(reqs[0].status, 'active', 'req 0: status');
|
|
375
|
+
assert(reqs[0].description.includes('log in'), 'req 0: description');
|
|
376
|
+
assertEq(reqs[2].id, 'R003', 'req 2: id');
|
|
377
|
+
assertEq(reqs[2].status, 'validated', 'req 2: status');
|
|
378
|
+
assertEq(reqs[3].id, 'R004', 'req 3: id');
|
|
379
|
+
assertEq(reqs[3].status, 'deferred', 'req 3: status');
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
383
|
+
// State Parser Tests
|
|
384
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
385
|
+
|
|
386
|
+
console.log('\n=== parseOldState ===');
|
|
387
|
+
{
|
|
388
|
+
const state = parseOldState(SAMPLE_STATE);
|
|
389
|
+
assert(state.currentPhase?.includes('30') ?? false, 'state: current phase includes 30');
|
|
390
|
+
assertEq(state.status, 'in-progress', 'state: status');
|
|
391
|
+
assert(state.raw === SAMPLE_STATE, 'state: raw preserved');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
395
|
+
// Config Parser Tests
|
|
396
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
397
|
+
|
|
398
|
+
console.log('\n=== parseOldConfig: valid JSON ===');
|
|
399
|
+
{
|
|
400
|
+
const config = parseOldConfig('{"projectName":"test","version":"1.0"}');
|
|
401
|
+
assert(config !== null, 'config: parsed');
|
|
402
|
+
assertEq(config?.projectName, 'test', 'config: projectName');
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
console.log('\n=== parseOldConfig: invalid JSON → null ===');
|
|
406
|
+
{
|
|
407
|
+
const config = parseOldConfig('not json at all {{{');
|
|
408
|
+
assertEq(config, null, 'config: invalid JSON returns null');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
console.log('\n=== parseOldConfig: non-object JSON → null ===');
|
|
412
|
+
{
|
|
413
|
+
const config = parseOldConfig('"just a string"');
|
|
414
|
+
assertEq(config, null, 'config: non-object returns null');
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
418
|
+
// Project Parser Tests
|
|
419
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
420
|
+
|
|
421
|
+
console.log('\n=== parseOldProject ===');
|
|
422
|
+
{
|
|
423
|
+
const project = parseOldProject(SAMPLE_PROJECT);
|
|
424
|
+
assertEq(project, SAMPLE_PROJECT, 'project: returns raw content');
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
428
|
+
// Results
|
|
429
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
430
|
+
|
|
431
|
+
console.log(`\n${'='.repeat(40)}`);
|
|
432
|
+
console.log(`Results: ${passed} passed, ${failed} failed`);
|
|
433
|
+
if (failed > 0) {
|
|
434
|
+
process.exit(1);
|
|
435
|
+
} else {
|
|
436
|
+
console.log('All tests passed ✓');
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
main().catch((error) => {
|
|
441
|
+
console.error(error);
|
|
442
|
+
process.exit(1);
|
|
443
|
+
});
|