gswd 0.1.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.
Files changed (42) hide show
  1. package/agents/gswd/architecture-drafter.md +70 -0
  2. package/agents/gswd/brainstorm-alternatives.md +60 -0
  3. package/agents/gswd/devils-advocate.md +57 -0
  4. package/agents/gswd/icp-persona.md +58 -0
  5. package/agents/gswd/integrations-checker.md +68 -0
  6. package/agents/gswd/journey-mapper.md +69 -0
  7. package/agents/gswd/market-researcher.md +54 -0
  8. package/agents/gswd/positioning.md +54 -0
  9. package/bin/gswd-tools.cjs +716 -0
  10. package/lib/audit.ts +959 -0
  11. package/lib/bootstrap.ts +617 -0
  12. package/lib/compile.ts +940 -0
  13. package/lib/config.ts +164 -0
  14. package/lib/imagine-agents.ts +154 -0
  15. package/lib/imagine-gate.ts +156 -0
  16. package/lib/imagine-input.ts +242 -0
  17. package/lib/imagine-synthesis.ts +402 -0
  18. package/lib/imagine.ts +433 -0
  19. package/lib/parse.ts +196 -0
  20. package/lib/render.ts +200 -0
  21. package/lib/specify-agents.ts +332 -0
  22. package/lib/specify-journeys.ts +410 -0
  23. package/lib/specify-nfr.ts +208 -0
  24. package/lib/specify-roles.ts +122 -0
  25. package/lib/specify.ts +773 -0
  26. package/lib/state.ts +305 -0
  27. package/package.json +26 -0
  28. package/templates/gswd/ARCHITECTURE.template.md +17 -0
  29. package/templates/gswd/AUDIT.template.md +31 -0
  30. package/templates/gswd/COMPETITION.template.md +18 -0
  31. package/templates/gswd/DECISIONS.template.md +18 -0
  32. package/templates/gswd/GTM.template.md +18 -0
  33. package/templates/gswd/ICP.template.md +18 -0
  34. package/templates/gswd/IMAGINE.template.md +24 -0
  35. package/templates/gswd/INTEGRATIONS.template.md +7 -0
  36. package/templates/gswd/JOURNEYS.template.md +7 -0
  37. package/templates/gswd/NFR.template.md +7 -0
  38. package/templates/gswd/PROJECT.template.md +21 -0
  39. package/templates/gswd/REQUIREMENTS.template.md +31 -0
  40. package/templates/gswd/ROADMAP.template.md +21 -0
  41. package/templates/gswd/SPEC.template.md +19 -0
  42. package/templates/gswd/STATE.template.md +15 -0
package/lib/state.ts ADDED
@@ -0,0 +1,305 @@
1
+ /**
2
+ * GSWD State Module — STATE.json CRUD with atomic writes
3
+ *
4
+ * All file writes use the atomic pattern: write to .tmp -> verify -> rename.
5
+ * STATE.json is updated only AFTER artifact writes complete.
6
+ *
7
+ * Schema: GSWD_SPEC.md Section 5.1
8
+ */
9
+
10
+ import * as fs from 'node:fs';
11
+ import * as path from 'node:path';
12
+
13
+ // ─── Types ───────────────────────────────────────────────────────────────────
14
+
15
+ export interface StageStatus {
16
+ imagine: 'not_started' | 'in_progress' | 'done';
17
+ specify: 'not_started' | 'in_progress' | 'done';
18
+ audit: 'not_started' | 'in_progress' | 'pass' | 'fail';
19
+ compile: 'not_started' | 'in_progress' | 'done';
20
+ }
21
+
22
+ export interface Checkpoint {
23
+ workflow: string;
24
+ checkpoint_id: string;
25
+ timestamp: string;
26
+ }
27
+
28
+ export interface PaidIntegration {
29
+ integration_id: string;
30
+ name: string;
31
+ monthly_cost_usd: number;
32
+ status: 'approved' | 'rejected';
33
+ approved_at: string;
34
+ }
35
+
36
+ export interface IdRange {
37
+ agent: string;
38
+ start: number;
39
+ end: number;
40
+ }
41
+
42
+ export interface IdRegistry {
43
+ allocated_ranges: Record<string, IdRange[]>;
44
+ }
45
+
46
+ export interface GswdState {
47
+ version: number;
48
+ project_slug: string;
49
+ created_at: string;
50
+ updated_at: string;
51
+ stage: 'init' | 'imagine' | 'specify' | 'audit' | 'compile' | 'done';
52
+ stage_status: StageStatus;
53
+ last_checkpoint: Checkpoint | null;
54
+ auto: {
55
+ enabled: boolean;
56
+ policy: 'strict' | 'balanced' | 'aggressive';
57
+ interrupt_reasons: string[];
58
+ decisions?: Array<{ type: string; chosen: string; rationale: string; score?: number; recorded_at: string }>;
59
+ };
60
+ approvals: {
61
+ auth_model: string;
62
+ data_store: string;
63
+ paid_integrations: PaidIntegration[];
64
+ };
65
+ id_registry?: IdRegistry;
66
+ }
67
+
68
+ // ─── Atomic File I/O ─────────────────────────────────────────────────────────
69
+
70
+ /**
71
+ * Atomically write a file: write to .tmp, verify, rename.
72
+ * Cleans up .tmp on any failure.
73
+ */
74
+ export function safeWriteFile(filePath: string, content: string): void {
75
+ const tmpPath = filePath + '.tmp';
76
+ const dir = path.dirname(filePath);
77
+
78
+ // Ensure parent directory exists
79
+ fs.mkdirSync(dir, { recursive: true });
80
+
81
+ try {
82
+ // Write to temp file
83
+ fs.writeFileSync(tmpPath, content, 'utf-8');
84
+
85
+ // Verify temp file was written correctly
86
+ const written = fs.readFileSync(tmpPath, 'utf-8');
87
+ if (written !== content) {
88
+ throw new Error(`Write verification failed for ${filePath}: content mismatch`);
89
+ }
90
+
91
+ // Atomic rename (atomic on Unix/macOS)
92
+ fs.renameSync(tmpPath, filePath);
93
+ } catch (err) {
94
+ // Clean up .tmp on any failure
95
+ try {
96
+ if (fs.existsSync(tmpPath)) {
97
+ fs.unlinkSync(tmpPath);
98
+ }
99
+ } catch {
100
+ // Ignore cleanup errors
101
+ }
102
+ throw err;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Atomically write JSON: pretty-print, atomic write, then verify round-trip.
108
+ */
109
+ export function safeWriteJson(filePath: string, data: unknown): void {
110
+ const content = JSON.stringify(data, null, 2) + '\n';
111
+ safeWriteFile(filePath, content);
112
+
113
+ // Post-rename verification: re-read and parse
114
+ const verify = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
115
+ if (JSON.stringify(verify) !== JSON.stringify(data)) {
116
+ throw new Error(`JSON round-trip verification failed for ${filePath}`);
117
+ }
118
+ }
119
+
120
+ // ─── State CRUD ──────────────────────────────────────────────────────────────
121
+
122
+ /**
123
+ * Create a default STATE.json object matching GSWD_SPEC Section 5.1.
124
+ */
125
+ export function createDefaultState(projectSlug: string): GswdState {
126
+ const now = new Date().toISOString();
127
+ return {
128
+ version: 1,
129
+ project_slug: projectSlug,
130
+ created_at: now,
131
+ updated_at: now,
132
+ stage: 'init',
133
+ stage_status: {
134
+ imagine: 'not_started',
135
+ specify: 'not_started',
136
+ audit: 'not_started',
137
+ compile: 'not_started',
138
+ },
139
+ last_checkpoint: null,
140
+ auto: {
141
+ enabled: false,
142
+ policy: 'balanced',
143
+ interrupt_reasons: [],
144
+ decisions: [],
145
+ },
146
+ approvals: {
147
+ auth_model: 'unapproved',
148
+ data_store: 'unapproved',
149
+ paid_integrations: [],
150
+ },
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Read STATE.json. Returns null if file doesn't exist or is invalid JSON.
156
+ */
157
+ export function readState(statePath: string): GswdState | null {
158
+ try {
159
+ const content = fs.readFileSync(statePath, 'utf-8');
160
+ const parsed = JSON.parse(content);
161
+ // Basic validation: check required top-level fields
162
+ if (typeof parsed.version !== 'number' || typeof parsed.project_slug !== 'string') {
163
+ return null;
164
+ }
165
+ return parsed as GswdState;
166
+ } catch {
167
+ return null;
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Write STATE.json atomically. Updates updated_at timestamp.
173
+ */
174
+ export function writeState(statePath: string, state: GswdState): void {
175
+ state.updated_at = new Date().toISOString();
176
+ safeWriteJson(statePath, state);
177
+ }
178
+
179
+ /**
180
+ * Idempotent init: create STATE.json only if missing or corrupt.
181
+ * If valid state exists, returns it unchanged (no timestamp update).
182
+ */
183
+ export function initState(stateDir: string, projectSlug: string): GswdState {
184
+ const statePath = path.join(stateDir, 'STATE.json');
185
+
186
+ // Try reading existing state
187
+ const existing = readState(statePath);
188
+ if (existing !== null) {
189
+ return existing;
190
+ }
191
+
192
+ // Create new state
193
+ const state = createDefaultState(projectSlug);
194
+ safeWriteJson(statePath, state);
195
+ return state;
196
+ }
197
+
198
+ /**
199
+ * Update a specific stage status. Read-modify-write pattern.
200
+ */
201
+ export function updateStageStatus(
202
+ statePath: string,
203
+ stage: keyof StageStatus,
204
+ status: string
205
+ ): void {
206
+ const state = readState(statePath);
207
+ if (!state) {
208
+ throw new Error(`Cannot read STATE.json at ${statePath}`);
209
+ }
210
+ (state.stage_status as Record<string, string>)[stage] = status;
211
+ writeState(statePath, state);
212
+ }
213
+
214
+ /**
215
+ * Write a checkpoint to STATE.json.
216
+ */
217
+ export function writeCheckpoint(
218
+ statePath: string,
219
+ workflow: string,
220
+ checkpointId: string
221
+ ): void {
222
+ const state = readState(statePath);
223
+ if (!state) {
224
+ throw new Error(`Cannot read STATE.json at ${statePath}`);
225
+ }
226
+ state.last_checkpoint = {
227
+ workflow,
228
+ checkpoint_id: checkpointId,
229
+ timestamp: new Date().toISOString(),
230
+ };
231
+ writeState(statePath, state);
232
+ }
233
+
234
+ // ─── ID Registry ─────────────────────────────────────────────────────────────
235
+
236
+ /**
237
+ * Allocate an ID range for an agent. Ranges are non-overlapping per ID type.
238
+ */
239
+ export function allocateIdRange(
240
+ statePath: string,
241
+ idType: string,
242
+ agentName: string,
243
+ rangeSize: number = 50
244
+ ): { start: number; end: number } {
245
+ const state = readState(statePath);
246
+ if (!state) {
247
+ throw new Error(`Cannot read STATE.json at ${statePath}`);
248
+ }
249
+
250
+ if (!state.id_registry) {
251
+ state.id_registry = { allocated_ranges: {} };
252
+ }
253
+ if (!state.id_registry.allocated_ranges[idType]) {
254
+ state.id_registry.allocated_ranges[idType] = [];
255
+ }
256
+
257
+ const ranges = state.id_registry.allocated_ranges[idType];
258
+ const lastEnd = ranges.length > 0
259
+ ? Math.max(...ranges.map(r => r.end))
260
+ : 0;
261
+
262
+ const newRange: IdRange = {
263
+ agent: agentName,
264
+ start: lastEnd + 1,
265
+ end: lastEnd + rangeSize,
266
+ };
267
+
268
+ ranges.push(newRange);
269
+ writeState(statePath, state);
270
+
271
+ return { start: newRange.start, end: newRange.end };
272
+ }
273
+
274
+ /**
275
+ * Get allocated ID ranges, optionally filtered by type.
276
+ */
277
+ export function getIdRanges(
278
+ statePath: string,
279
+ idType?: string
280
+ ): Record<string, IdRange[]> {
281
+ const state = readState(statePath);
282
+ if (!state || !state.id_registry) {
283
+ return {};
284
+ }
285
+
286
+ if (idType) {
287
+ const ranges = state.id_registry.allocated_ranges[idType];
288
+ return ranges ? { [idType]: ranges } : {};
289
+ }
290
+
291
+ return state.id_registry.allocated_ranges;
292
+ }
293
+
294
+ /**
295
+ * Reset all allocated ID ranges.
296
+ */
297
+ export function resetIdRegistry(statePath: string): void {
298
+ const state = readState(statePath);
299
+ if (!state) {
300
+ throw new Error(`Cannot read STATE.json at ${statePath}`);
301
+ }
302
+
303
+ state.id_registry = { allocated_ranges: {} };
304
+ writeState(statePath, state);
305
+ }
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "gswd",
3
+ "version": "0.1.0",
4
+ "type": "commonjs",
5
+ "description": "Get Shit Well Done — CLI meta-prompting and spec-generation system",
6
+ "bin": {
7
+ "gswd": "./bin/gswd-tools.cjs",
8
+ "gswd-tools": "./bin/gswd-tools.cjs"
9
+ },
10
+ "files": [
11
+ "bin/",
12
+ "lib/",
13
+ "templates/",
14
+ "agents/"
15
+ ],
16
+ "scripts": {
17
+ "test": "node --import tsx --test tests/*.test.ts",
18
+ "test:cjs": "node --test tests/*.test.cjs",
19
+ "build": "tsc"
20
+ },
21
+ "devDependencies": {
22
+ "typescript": "^5.7.0",
23
+ "@types/node": "^22.0.0",
24
+ "tsx": "^4.19.0"
25
+ }
26
+ }
@@ -0,0 +1,17 @@
1
+ # Architecture
2
+
3
+ ## Architecture
4
+
5
+ ### Components
6
+
7
+ <!-- GSWD:CONTENT:COMPONENTS -->
8
+
9
+ ### Data Model
10
+
11
+ <!-- GSWD:CONTENT:DATA_MODEL -->
12
+
13
+ ### Ownership Boundaries
14
+
15
+ <!-- GSWD:CONTENT:OWNERSHIP -->
16
+
17
+ <!-- GSWD:COMPLETE -->
@@ -0,0 +1,31 @@
1
+ # Audit Report
2
+
3
+ **Date:** {date}
4
+ **Result:** {PASS|FAIL}
5
+ **Summary:** {passed}/{total} checks passed, {findings} issue(s) found
6
+
7
+ ## Coverage Matrix
8
+
9
+ | Journey | Linked FRs | Linked NFRs | Acceptance Tests | Integrations | Status |
10
+ |---------|------------|-------------|------------------|--------------|--------|
11
+
12
+ ## Coverage Statistics
13
+
14
+ | Metric | Count |
15
+ |--------|-------|
16
+ | Journeys | {N} |
17
+ | Functional Requirements | {N} |
18
+ | Non-Functional Requirements | {N} |
19
+ | Integrations | {N} |
20
+
21
+ ## Check Results
22
+
23
+ ### Journey FR Coverage
24
+ ### Journey Test Coverage
25
+ ### Orphan v1 FRs
26
+ ### Integration Approval
27
+ ### Required Headings
28
+
29
+ ## Actionable Checklist
30
+
31
+ {Only present on FAIL}
@@ -0,0 +1,18 @@
1
+ # Competition
2
+
3
+ ## Market Overview
4
+ <!-- GSWD:CONTENT market_overview -->
5
+
6
+ ## Competitors
7
+ <!-- GSWD:CONTENT competitors -->
8
+
9
+ ## Market Gaps
10
+ <!-- GSWD:CONTENT gaps -->
11
+
12
+ ## Opportunities
13
+ <!-- GSWD:CONTENT opportunities -->
14
+
15
+ ## Competitive Positioning
16
+ <!-- GSWD:CONTENT competitive_positioning -->
17
+
18
+ <!-- GSWD:COMPLETE -->
@@ -0,0 +1,18 @@
1
+ # Decisions
2
+
3
+ ## Frozen Decisions
4
+ <!-- GSWD:CONTENT - Minimum 8 frozen decisions required -->
5
+
6
+ ## Success Metrics
7
+ <!-- GSWD:CONTENT - 1-3 measurable success metrics -->
8
+
9
+ ## Out of Scope
10
+ <!-- GSWD:CONTENT - Explicit exclusions -->
11
+
12
+ ## Risks & Mitigations
13
+ <!-- GSWD:CONTENT - Minimum 5 risks with mitigations -->
14
+
15
+ ## Open Questions
16
+ <!-- GSWD:CONTENT - Unresolved questions for future resolution -->
17
+
18
+ <!-- GSWD:COMPLETE -->
@@ -0,0 +1,18 @@
1
+ # Go-to-Market
2
+
3
+ ## Value Proposition
4
+ <!-- GSWD:CONTENT value_prop -->
5
+
6
+ ## Positioning Statement
7
+ <!-- GSWD:CONTENT positioning -->
8
+
9
+ ## Key Differentiators
10
+ <!-- GSWD:CONTENT differentiators -->
11
+
12
+ ## Go-to-Market Angle
13
+ <!-- GSWD:CONTENT gtm_angle -->
14
+
15
+ ## Early Traction Strategy
16
+ <!-- GSWD:CONTENT traction -->
17
+
18
+ <!-- GSWD:COMPLETE -->
@@ -0,0 +1,18 @@
1
+ # Ideal Customer Profile
2
+
3
+ ## ICP Profile
4
+ <!-- GSWD:CONTENT icp_profile -->
5
+
6
+ ## Pain Points
7
+ <!-- GSWD:CONTENT pain_points -->
8
+
9
+ ## Willingness to Pay
10
+ <!-- GSWD:CONTENT wtp -->
11
+
12
+ ## Reachability
13
+ <!-- GSWD:CONTENT reachability -->
14
+
15
+ ## Behavioral Traits
16
+ <!-- GSWD:CONTENT traits -->
17
+
18
+ <!-- GSWD:COMPLETE -->
@@ -0,0 +1,24 @@
1
+ # Imagine
2
+
3
+ ## Vision
4
+ <!-- GSWD:CONTENT vision -->
5
+
6
+ ## Target User
7
+ <!-- GSWD:CONTENT target_user -->
8
+
9
+ ## Problem Statement
10
+ <!-- GSWD:CONTENT problem -->
11
+
12
+ ## Product Direction
13
+ <!-- GSWD:CONTENT direction -->
14
+
15
+ ## Alternatives
16
+ <!-- GSWD:CONTENT alternatives -->
17
+
18
+ ## Wedge / MVP Boundary
19
+ <!-- GSWD:CONTENT wedge -->
20
+
21
+ ## Success Metrics
22
+ <!-- GSWD:CONTENT metrics -->
23
+
24
+ <!-- GSWD:COMPLETE -->
@@ -0,0 +1,7 @@
1
+ # External Integrations
2
+
3
+ ## Integrations
4
+
5
+ <!-- GSWD:CONTENT:INTEGRATIONS -->
6
+
7
+ <!-- GSWD:COMPLETE -->
@@ -0,0 +1,7 @@
1
+ # User Journeys
2
+
3
+ ## Journeys
4
+
5
+ <!-- GSWD:CONTENT:JOURNEYS -->
6
+
7
+ <!-- GSWD:COMPLETE -->
@@ -0,0 +1,7 @@
1
+ # Non-Functional Requirements
2
+
3
+ ## Non-Functional Requirements
4
+
5
+ <!-- GSWD:CONTENT:NFRS -->
6
+
7
+ <!-- GSWD:COMPLETE -->
@@ -0,0 +1,21 @@
1
+ # {project_slug}
2
+
3
+ ## What This Is
4
+ <!-- Compiled from IMAGINE.md vision -->
5
+
6
+ ## Target User
7
+ <!-- Compiled from IMAGINE.md target user / ICP -->
8
+
9
+ ## Problem Statement
10
+ <!-- Compiled from IMAGINE.md product direction -->
11
+
12
+ ## Wedge / MVP Boundary
13
+ <!-- Compiled from IMAGINE.md wedge -->
14
+
15
+ ## Success Metrics
16
+ <!-- Compiled from DECISIONS.md success metrics -->
17
+
18
+ ## Out of Scope
19
+ <!-- Compiled from DECISIONS.md out of scope -->
20
+
21
+ <!-- GSWD:COMPILED -->
@@ -0,0 +1,31 @@
1
+ # Requirements
2
+
3
+ ## Functional Requirements
4
+
5
+ ### v1 (In Scope)
6
+ <!-- FRs with Scope: v1, sorted by Priority then ID -->
7
+
8
+ ### v2 (Future)
9
+ <!-- FRs with Scope: v2, sorted by Priority then ID -->
10
+
11
+ ## Non-Functional Requirements
12
+
13
+ ### Security
14
+ <!-- NFRs in security category -->
15
+
16
+ ### Privacy
17
+ <!-- NFRs in privacy category -->
18
+
19
+ ### Performance
20
+ <!-- NFRs in performance category -->
21
+
22
+ ### Observability
23
+ <!-- NFRs in observability category -->
24
+
25
+ ## Traceability
26
+
27
+ <!-- FR-to-Journey mapping table for v1 FRs -->
28
+ | FR | Description | Journeys |
29
+ |----|-------------|----------|
30
+
31
+ <!-- GSWD:COMPILED -->
@@ -0,0 +1,21 @@
1
+ # Roadmap
2
+
3
+ ## Overview
4
+
5
+ v1 journeys assigned to 4 phases following deterministic rules.
6
+
7
+ ## Phases
8
+
9
+ ### Phase 1: Skeleton & Core Loop
10
+ <!-- onboarding + core_action journeys -->
11
+
12
+ ### Phase 2: Persistence & History
13
+ <!-- view_results journeys -->
14
+
15
+ ### Phase 3: Polish: errors, empty states, settings
16
+ <!-- error_states + empty_states + settings journeys -->
17
+
18
+ ### Phase 4: Observability & Hardening
19
+ <!-- Observability + security NFRs (no journeys) -->
20
+
21
+ <!-- GSWD:COMPILED -->
@@ -0,0 +1,19 @@
1
+ # Specification
2
+
3
+ ## Roles & Permissions
4
+
5
+ <!-- GSWD:CONTENT:ROLES -->
6
+
7
+ ## Functional Requirements
8
+
9
+ <!-- GSWD:CONTENT:FRS -->
10
+
11
+ ## Acceptance Criteria
12
+
13
+ <!-- GSWD:CONTENT:ACCEPTANCE -->
14
+
15
+ ## Traceability
16
+
17
+ <!-- GSWD:CONTENT:TRACEABILITY -->
18
+
19
+ <!-- GSWD:COMPLETE -->
@@ -0,0 +1,15 @@
1
+ # Project State
2
+
3
+ ## Frozen Decisions
4
+ <!-- Numbered list from DECISIONS.md -->
5
+
6
+ ## Approvals
7
+ <!-- Auth model, data store, paid integrations from STATE.json -->
8
+
9
+ ## Open Questions
10
+ <!-- Bulleted list from DECISIONS.md -->
11
+
12
+ ## Risks
13
+ <!-- Bulleted list from DECISIONS.md risks & mitigations -->
14
+
15
+ <!-- GSWD:COMPILED -->