gswd 1.0.0 → 1.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.
- package/bin/gswd-tools.cjs +228 -0
- package/bin/install.js +8 -0
- package/commands/gswd/imagine.md +7 -1
- package/commands/gswd/start.md +507 -32
- package/dist/lib/audit.d.ts +205 -0
- package/dist/lib/audit.js +805 -0
- package/dist/lib/bootstrap.d.ts +103 -0
- package/dist/lib/bootstrap.js +563 -0
- package/dist/lib/compile.d.ts +239 -0
- package/dist/lib/compile.js +1152 -0
- package/dist/lib/config.d.ts +49 -0
- package/dist/lib/config.js +150 -0
- package/dist/lib/imagine-agents.d.ts +54 -0
- package/dist/lib/imagine-agents.js +185 -0
- package/dist/lib/imagine-gate.d.ts +47 -0
- package/dist/lib/imagine-gate.js +131 -0
- package/dist/lib/imagine-input.d.ts +46 -0
- package/dist/lib/imagine-input.js +233 -0
- package/dist/lib/imagine-synthesis.d.ts +90 -0
- package/dist/lib/imagine-synthesis.js +453 -0
- package/dist/lib/imagine.d.ts +56 -0
- package/dist/lib/imagine.js +413 -0
- package/dist/lib/intake.d.ts +27 -0
- package/dist/lib/intake.js +82 -0
- package/dist/lib/parse.d.ts +59 -0
- package/dist/lib/parse.js +171 -0
- package/dist/lib/render.d.ts +309 -0
- package/dist/lib/render.js +624 -0
- package/dist/lib/specify-agents.d.ts +120 -0
- package/dist/lib/specify-agents.js +269 -0
- package/dist/lib/specify-journeys.d.ts +124 -0
- package/dist/lib/specify-journeys.js +279 -0
- package/dist/lib/specify-nfr.d.ts +45 -0
- package/dist/lib/specify-nfr.js +159 -0
- package/dist/lib/specify-roles.d.ts +46 -0
- package/dist/lib/specify-roles.js +88 -0
- package/dist/lib/specify.d.ts +70 -0
- package/dist/lib/specify.js +676 -0
- package/dist/lib/state.d.ts +140 -0
- package/dist/lib/state.js +340 -0
- package/dist/tests/audit.test.d.ts +4 -0
- package/dist/tests/audit.test.js +1579 -0
- package/dist/tests/bootstrap.test.d.ts +5 -0
- package/dist/tests/bootstrap.test.js +611 -0
- package/dist/tests/compile.test.d.ts +4 -0
- package/dist/tests/compile.test.js +862 -0
- package/dist/tests/config.test.d.ts +4 -0
- package/dist/tests/config.test.js +191 -0
- package/dist/tests/imagine-agents.test.d.ts +6 -0
- package/dist/tests/imagine-agents.test.js +179 -0
- package/dist/tests/imagine-gate.test.d.ts +6 -0
- package/dist/tests/imagine-gate.test.js +264 -0
- package/dist/tests/imagine-input.test.d.ts +6 -0
- package/dist/tests/imagine-input.test.js +283 -0
- package/dist/tests/imagine-synthesis.test.d.ts +7 -0
- package/dist/tests/imagine-synthesis.test.js +380 -0
- package/dist/tests/imagine.test.d.ts +8 -0
- package/dist/tests/imagine.test.js +406 -0
- package/dist/tests/parse.test.d.ts +4 -0
- package/dist/tests/parse.test.js +285 -0
- package/dist/tests/render.test.d.ts +4 -0
- package/dist/tests/render.test.js +236 -0
- package/dist/tests/specify-agents.test.d.ts +4 -0
- package/dist/tests/specify-agents.test.js +352 -0
- package/dist/tests/specify-journeys.test.d.ts +5 -0
- package/dist/tests/specify-journeys.test.js +440 -0
- package/dist/tests/specify-nfr.test.d.ts +4 -0
- package/dist/tests/specify-nfr.test.js +205 -0
- package/dist/tests/specify-roles.test.d.ts +4 -0
- package/dist/tests/specify-roles.test.js +136 -0
- package/dist/tests/specify.test.d.ts +9 -0
- package/dist/tests/specify.test.js +544 -0
- package/dist/tests/state.test.d.ts +4 -0
- package/dist/tests/state.test.js +316 -0
- package/lib/bootstrap.ts +37 -11
- package/lib/compile.ts +426 -4
- package/lib/imagine-agents.ts +53 -7
- package/lib/imagine-synthesis.ts +170 -6
- package/lib/imagine.ts +59 -5
- package/lib/intake.ts +60 -0
- package/lib/parse.ts +2 -1
- package/lib/render.ts +566 -5
- package/lib/specify-agents.ts +25 -3
- package/lib/state.ts +115 -0
- package/package.json +4 -2
- package/templates/gswd/DECISIONS.template.md +3 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* GSWD Parse Module — ID extraction, heading validation, normalization
|
|
4
|
+
*
|
|
5
|
+
* Parses GSWD artifact files for IDs (J-NNN, FR-NNN, NFR-NNN, I-NNN, C-NNN),
|
|
6
|
+
* validates required heading structure, and normalizes malformed IDs.
|
|
7
|
+
*
|
|
8
|
+
* Schema: GSWD_SPEC.md Section 6.1-6.3
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.REQUIRED_HEADINGS = void 0;
|
|
12
|
+
exports.normalizeId = normalizeId;
|
|
13
|
+
exports.extractIds = extractIds;
|
|
14
|
+
exports.validateHeadings = validateHeadings;
|
|
15
|
+
exports.extractHeadingContent = extractHeadingContent;
|
|
16
|
+
// ─── Required Headings ──────────────────────────────────────────────────────
|
|
17
|
+
/**
|
|
18
|
+
* Required headings per artifact file type, from GSWD_SPEC Section 6.3.
|
|
19
|
+
* These are the stable anchors used by audit/compile parsers.
|
|
20
|
+
*/
|
|
21
|
+
exports.REQUIRED_HEADINGS = {
|
|
22
|
+
'JOURNEYS.md': ['## Journeys'],
|
|
23
|
+
'SPEC.md': ['## Roles & Permissions', '## Functional Requirements', '## Acceptance Criteria'],
|
|
24
|
+
'NFR.md': ['## Non-Functional Requirements'],
|
|
25
|
+
'INTEGRATIONS.md': ['## Integrations'],
|
|
26
|
+
'ARCHITECTURE.md': ['## Architecture', '### Components', '### Data Model'],
|
|
27
|
+
'DECISIONS.md': [
|
|
28
|
+
'## Vision',
|
|
29
|
+
'## Frozen Decisions',
|
|
30
|
+
'## Success Metrics',
|
|
31
|
+
'## Out of Scope',
|
|
32
|
+
'## Risks & Mitigations',
|
|
33
|
+
'## Open Questions',
|
|
34
|
+
],
|
|
35
|
+
'AUDIT.md': ['## Coverage Matrix', '## Check Results'],
|
|
36
|
+
'PROJECT.md': ['## What This Is', '## Target User', '## Problem Statement', '## Wedge / MVP Boundary', '## Success Metrics', '## Out of Scope', '## Context'],
|
|
37
|
+
'REQUIREMENTS.md': ['## Functional Requirements', '## Non-Functional Requirements', '## Traceability'],
|
|
38
|
+
'ROADMAP.md': ['## Overview', '## Phases'],
|
|
39
|
+
'STATE.md': ['## Frozen Decisions', '## Approvals', '## Open Questions', '## Risks'],
|
|
40
|
+
};
|
|
41
|
+
// ─── ID Normalization ────────────────────────────────────────────────────────
|
|
42
|
+
/** Valid ID prefixes */
|
|
43
|
+
const ID_PREFIXES = ['J', 'FR', 'NFR', 'I', 'C'];
|
|
44
|
+
/**
|
|
45
|
+
* Normalize an ID to canonical format: PREFIX-NNN (3-digit minimum, zero-padded).
|
|
46
|
+
*
|
|
47
|
+
* - FR-1 -> FR-001
|
|
48
|
+
* - FR-01 -> FR-001
|
|
49
|
+
* - FR-001 -> FR-001 (no change)
|
|
50
|
+
* - FR-1000 -> FR-1000 (4+ digits kept as-is)
|
|
51
|
+
* - INVALID -> INVALID (unrecognized format returned as-is)
|
|
52
|
+
*/
|
|
53
|
+
function normalizeId(rawId) {
|
|
54
|
+
if (!rawId)
|
|
55
|
+
return rawId;
|
|
56
|
+
const match = rawId.match(/^(J|FR|NFR|I|C)-(\d+)$/);
|
|
57
|
+
if (!match)
|
|
58
|
+
return rawId;
|
|
59
|
+
const prefix = match[1];
|
|
60
|
+
const num = parseInt(match[2], 10);
|
|
61
|
+
const padded = num.toString().padStart(3, '0');
|
|
62
|
+
return `${prefix}-${padded}`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Extract IDs from content using regex.
|
|
66
|
+
*
|
|
67
|
+
* Regex: /\b(J|FR|NFR|I|C)-(\d{1,4})\b/g
|
|
68
|
+
* - Word boundary prevents partial matches (e.g., INFRASTRUCTURE-001)
|
|
69
|
+
* - Returns deduplicated array sorted by normalized ID ascending
|
|
70
|
+
* - Optional filter by idType (e.g., 'FR')
|
|
71
|
+
*/
|
|
72
|
+
function extractIds(content, idType) {
|
|
73
|
+
const regex = /\b(J|FR|NFR|I|C)-(\d{1,4})\b/g;
|
|
74
|
+
const seen = new Map();
|
|
75
|
+
let match;
|
|
76
|
+
while ((match = regex.exec(content)) !== null) {
|
|
77
|
+
const raw = match[0];
|
|
78
|
+
const prefix = match[1];
|
|
79
|
+
// Filter by ID type if specified
|
|
80
|
+
if (idType && prefix !== idType)
|
|
81
|
+
continue;
|
|
82
|
+
const normalized = normalizeId(raw);
|
|
83
|
+
if (!seen.has(normalized)) {
|
|
84
|
+
seen.set(normalized, {
|
|
85
|
+
id: normalized,
|
|
86
|
+
raw,
|
|
87
|
+
normalized: raw !== normalized,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Sort by normalized ID ascending
|
|
92
|
+
return Array.from(seen.values()).sort((a, b) => {
|
|
93
|
+
// Split into prefix and number for proper sorting
|
|
94
|
+
const aParts = a.id.match(/^(.+)-(\d+)$/);
|
|
95
|
+
const bParts = b.id.match(/^(.+)-(\d+)$/);
|
|
96
|
+
if (!aParts || !bParts)
|
|
97
|
+
return a.id.localeCompare(b.id);
|
|
98
|
+
// Sort by prefix first, then by number
|
|
99
|
+
if (aParts[1] !== bParts[1])
|
|
100
|
+
return aParts[1].localeCompare(bParts[1]);
|
|
101
|
+
return parseInt(aParts[2], 10) - parseInt(bParts[2], 10);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Validate that a file contains all required headings for its type.
|
|
106
|
+
*
|
|
107
|
+
* - Looks up required headings from REQUIRED_HEADINGS[fileType]
|
|
108
|
+
* - Case-insensitive search as safety layer
|
|
109
|
+
* - Returns which headings are present and which are missing
|
|
110
|
+
* - Unknown file types are always valid (no required headings)
|
|
111
|
+
*/
|
|
112
|
+
function validateHeadings(content, fileType) {
|
|
113
|
+
const required = exports.REQUIRED_HEADINGS[fileType];
|
|
114
|
+
// Unknown file type — no required headings, always valid
|
|
115
|
+
if (!required) {
|
|
116
|
+
return { valid: true, missing: [], present: [] };
|
|
117
|
+
}
|
|
118
|
+
const contentLower = content.toLowerCase();
|
|
119
|
+
const missing = [];
|
|
120
|
+
const present = [];
|
|
121
|
+
for (const heading of required) {
|
|
122
|
+
if (contentLower.includes(heading.toLowerCase())) {
|
|
123
|
+
present.push(heading);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
missing.push(heading);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
valid: missing.length === 0,
|
|
131
|
+
missing,
|
|
132
|
+
present,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// ─── Heading Content Extraction ──────────────────────────────────────────────
|
|
136
|
+
/**
|
|
137
|
+
* Extract content between a heading and the next heading of same or higher level.
|
|
138
|
+
*
|
|
139
|
+
* @param content - Full file content
|
|
140
|
+
* @param heading - The heading to extract content from (e.g., "## Section A")
|
|
141
|
+
* @returns Content string (trimmed) or null if heading not found
|
|
142
|
+
*/
|
|
143
|
+
function extractHeadingContent(content, heading) {
|
|
144
|
+
const lines = content.split('\n');
|
|
145
|
+
const headingLevel = (heading.match(/^#+/) || [''])[0].length;
|
|
146
|
+
let capturing = false;
|
|
147
|
+
let startIdx = -1;
|
|
148
|
+
let endIdx = lines.length;
|
|
149
|
+
for (let i = 0; i < lines.length; i++) {
|
|
150
|
+
const line = lines[i];
|
|
151
|
+
if (!capturing) {
|
|
152
|
+
// Look for the target heading
|
|
153
|
+
if (line.trim().toLowerCase() === heading.toLowerCase()) {
|
|
154
|
+
capturing = true;
|
|
155
|
+
startIdx = i + 1;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
// Check if we hit another heading of same or higher level
|
|
160
|
+
const lineHeadingMatch = line.match(/^(#+)\s/);
|
|
161
|
+
if (lineHeadingMatch && lineHeadingMatch[1].length <= headingLevel) {
|
|
162
|
+
endIdx = i;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (startIdx === -1)
|
|
168
|
+
return null;
|
|
169
|
+
const extracted = lines.slice(startIdx, endIdx).join('\n').trim();
|
|
170
|
+
return extracted;
|
|
171
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSWD Render Module — Terminal UI rendering functions
|
|
3
|
+
*
|
|
4
|
+
* All functions return strings (not print to stdout).
|
|
5
|
+
* Zero external dependencies. Uses only string operations.
|
|
6
|
+
*
|
|
7
|
+
* Schema: GSWD_SPEC.md Section 7.1-7.3
|
|
8
|
+
*/
|
|
9
|
+
export declare const SYMBOLS: {
|
|
10
|
+
readonly complete: "✓";
|
|
11
|
+
readonly failed: "✗";
|
|
12
|
+
readonly inProgress: "◆";
|
|
13
|
+
readonly pending: "○";
|
|
14
|
+
readonly autoApproved: "⚡";
|
|
15
|
+
readonly warning: "⚠";
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* ANSI color codes for GSWD branding.
|
|
19
|
+
* Electric orange/amber is the brand color (per CONTEXT.md locked decision).
|
|
20
|
+
* 256-color code \x1b[38;5;208m; dim uses \x1b[2m.
|
|
21
|
+
*/
|
|
22
|
+
export declare const COLORS: {
|
|
23
|
+
readonly orange: "\u001B[38;5;208m";
|
|
24
|
+
readonly dim: "\u001B[2m";
|
|
25
|
+
readonly reset: "\u001B[0m";
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Wrap text in ANSI color. No-op when stdout is not a TTY (CI/Docker/pipe safety).
|
|
29
|
+
* Respects FORCE_COLOR env var to override TTY detection.
|
|
30
|
+
*/
|
|
31
|
+
export declare function colorize(text: string, color: keyof typeof COLORS): string;
|
|
32
|
+
/**
|
|
33
|
+
* Render the GSWD ASCII logo with catchphrase.
|
|
34
|
+
* Logo shape matches GSD's block-letter style from install.js.
|
|
35
|
+
* Static string — no figlet (STATE.md architectural decision).
|
|
36
|
+
*
|
|
37
|
+
* @param version - Optional version string (e.g., "1.0.1")
|
|
38
|
+
*/
|
|
39
|
+
export declare function renderLogo(version?: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Render the condensed first-run command guide.
|
|
42
|
+
* Per CONTEXT.md: primary commands only, no descriptions.
|
|
43
|
+
* Followed by automatic /gswd:start proposal for zero-friction onboarding.
|
|
44
|
+
*/
|
|
45
|
+
export declare function renderFirstRunGuide(): string;
|
|
46
|
+
/**
|
|
47
|
+
* Pad or truncate a string to exact width.
|
|
48
|
+
* If str exceeds width, truncate and append '...' (total = width).
|
|
49
|
+
*/
|
|
50
|
+
export declare function padRight(str: string, width: number): string;
|
|
51
|
+
/**
|
|
52
|
+
* Render a stage banner matching GSWD_SPEC Section 7.1.
|
|
53
|
+
*
|
|
54
|
+
* ```
|
|
55
|
+
* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
56
|
+
* GSWD ► {STAGE NAME}
|
|
57
|
+
* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* Banner width = 55 characters. Stage name is uppercased.
|
|
61
|
+
*/
|
|
62
|
+
export declare function renderBanner(stageName: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Render a checkpoint box matching GSWD_SPEC Section 7.2.
|
|
65
|
+
*
|
|
66
|
+
* Box total width: 56 characters (54 inner + 2 border characters).
|
|
67
|
+
* Uses single-line box-drawing characters.
|
|
68
|
+
*
|
|
69
|
+
* @param type - Header text (e.g., "Decision Required")
|
|
70
|
+
* @param context - Context paragraph
|
|
71
|
+
* @param options - Numbered options list
|
|
72
|
+
* @param actionPrompt - Action prompt (appears after → )
|
|
73
|
+
*/
|
|
74
|
+
export declare function renderCheckpoint(type: string, context: string, options: string[], actionPrompt: string): string;
|
|
75
|
+
/**
|
|
76
|
+
* Render a Next Up block matching GSWD_SPEC Section 7.3.
|
|
77
|
+
*
|
|
78
|
+
* ```
|
|
79
|
+
* ✓ Wrote: file1, file2, ...
|
|
80
|
+
*
|
|
81
|
+
* Next up:
|
|
82
|
+
* {nextCommand}
|
|
83
|
+
*
|
|
84
|
+
* Tip:
|
|
85
|
+
* If context is getting crowded, run /clear.
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare function renderNextUp(files: string[], nextCommand: string, alsoAvailable?: string[]): string;
|
|
89
|
+
/**
|
|
90
|
+
* Render a single status line with the appropriate symbol.
|
|
91
|
+
*
|
|
92
|
+
* Maps: done/pass -> ✓, fail -> ✗, in_progress -> ◆, not_started -> ○
|
|
93
|
+
*/
|
|
94
|
+
export declare function renderStatusLine(stage: string, status: string): string;
|
|
95
|
+
/**
|
|
96
|
+
* Render an ASCII progress bar.
|
|
97
|
+
*
|
|
98
|
+
* ```
|
|
99
|
+
* Progress: ████████░░ 80%
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @param current - Current value
|
|
103
|
+
* @param total - Total value
|
|
104
|
+
* @param width - Bar width in characters (default 10)
|
|
105
|
+
*/
|
|
106
|
+
export declare function renderProgressBar(current: number, total: number, width?: number): string;
|
|
107
|
+
/**
|
|
108
|
+
* Input for stage summary rendering.
|
|
109
|
+
* Used at manual-mode checkpoints to show what a stage produced.
|
|
110
|
+
*/
|
|
111
|
+
export interface StageSummarySection {
|
|
112
|
+
name: string;
|
|
113
|
+
summary: string;
|
|
114
|
+
}
|
|
115
|
+
export interface StageSummaryInput {
|
|
116
|
+
stageName: string;
|
|
117
|
+
headline: string;
|
|
118
|
+
sections: StageSummarySection[];
|
|
119
|
+
filesCreated: string[];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Render a structured stage summary for manual-mode checkpoints.
|
|
123
|
+
* Consistent template per CONTEXT.md locked decision:
|
|
124
|
+
* Headline -> section paragraphs -> file list
|
|
125
|
+
*
|
|
126
|
+
* ```
|
|
127
|
+
* ## Imagine Complete
|
|
128
|
+
*
|
|
129
|
+
* Imagine produced 3 product directions with ICP, GTM, and competition analysis.
|
|
130
|
+
*
|
|
131
|
+
* **Key outputs:**
|
|
132
|
+
* - ICP Analysis: Identified 2 primary personas with distinct pain points...
|
|
133
|
+
* - GTM Strategy: Recommended freemium launch with enterprise upgrade path...
|
|
134
|
+
*
|
|
135
|
+
* **Created:** IMAGINE.md, ICP.md, GTM.md, COMPETITION.md, DECISIONS.md
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
/**
|
|
139
|
+
* Research summary section for post-agent display.
|
|
140
|
+
* Mirrors ResearchSummarySection from imagine-synthesis.ts.
|
|
141
|
+
*/
|
|
142
|
+
export interface RenderResearchSection {
|
|
143
|
+
displayName: string;
|
|
144
|
+
takeaways: string[];
|
|
145
|
+
bridge: string;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Render structured research summary after agent completion.
|
|
149
|
+
* Product-contextualized: section intros reference user's product.
|
|
150
|
+
* Per CONTEXT.md: 3-5 takeaway bullets per section, bridging paragraph per section.
|
|
151
|
+
*
|
|
152
|
+
* @param sections - Research summary sections from buildResearchSummary
|
|
153
|
+
* @param productContext - Brief description of the product (from brief.vision)
|
|
154
|
+
* @param targetUser - Who the product is for (from brief.target_user)
|
|
155
|
+
*/
|
|
156
|
+
export declare function renderResearchSummary(sections: RenderResearchSection[], productContext: string, targetUser: string): string;
|
|
157
|
+
/**
|
|
158
|
+
* Direction card input for rendering.
|
|
159
|
+
*/
|
|
160
|
+
export interface RenderDirectionInput {
|
|
161
|
+
label: string;
|
|
162
|
+
rationale: string[];
|
|
163
|
+
icp_summary: string;
|
|
164
|
+
problem_framing: string;
|
|
165
|
+
wedge: string;
|
|
166
|
+
differentiator: string;
|
|
167
|
+
risks: string[];
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Render a direction card with "Why this makes sense" rationale section.
|
|
171
|
+
* Per CONTEXT.md: rationale section comes FIRST, before existing fields.
|
|
172
|
+
* Recommended direction gets a visual marker.
|
|
173
|
+
*
|
|
174
|
+
* @param direction - Direction data
|
|
175
|
+
* @param index - 0-based index for display numbering
|
|
176
|
+
* @param isRecommended - Whether this is the proposed/recommended direction
|
|
177
|
+
*/
|
|
178
|
+
export declare function renderDirectionCard(direction: RenderDirectionInput, index: number, isRecommended: boolean): string;
|
|
179
|
+
export declare function renderStageSummary(input: StageSummaryInput): string;
|
|
180
|
+
/**
|
|
181
|
+
* Minimal product context for contextual messaging throughout the pipeline.
|
|
182
|
+
* Extracted from INTAKE.json and DECISIONS.md with graceful fallbacks.
|
|
183
|
+
*/
|
|
184
|
+
export interface ProductContext {
|
|
185
|
+
/** Product domain (e.g., "spec-writing tool") */
|
|
186
|
+
domain: string;
|
|
187
|
+
/** Target user (e.g., "solo founders") */
|
|
188
|
+
targetUser: string;
|
|
189
|
+
/** Stage-specific context string */
|
|
190
|
+
stageContext: string;
|
|
191
|
+
/** Whether this is a re-run (changes banner messaging) */
|
|
192
|
+
isRerun: boolean;
|
|
193
|
+
/** Re-run feedback context (if re-run) */
|
|
194
|
+
rerunContext?: string;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Extract product context from DECISIONS.md and INTAKE.json.
|
|
198
|
+
* DECISIONS.md is preferred (more precise, available after Imagine).
|
|
199
|
+
* INTAKE.json is fallback (available from pipeline start).
|
|
200
|
+
* Returns safe defaults if neither file exists.
|
|
201
|
+
*
|
|
202
|
+
* @param planningDir - Path to .planning/ directory
|
|
203
|
+
* @param isRerun - Whether this is a re-run
|
|
204
|
+
*/
|
|
205
|
+
export declare function extractProductContext(planningDir: string, isRerun?: boolean): ProductContext;
|
|
206
|
+
/**
|
|
207
|
+
* Stage-specific context line generators for contextual banners.
|
|
208
|
+
* Each returns a product-contextualized one-liner for the banner.
|
|
209
|
+
* Compile is deliberately excluded (per CONTEXT.md: deterministic, no banner needed).
|
|
210
|
+
*/
|
|
211
|
+
export declare const STAGE_CONTEXT_TEMPLATES: Record<string, (ctx: ProductContext) => string>;
|
|
212
|
+
/**
|
|
213
|
+
* Product-contextualized one-liner descriptions for Imagine research agents.
|
|
214
|
+
* Each function receives ProductContext and returns a purpose string.
|
|
215
|
+
*/
|
|
216
|
+
export declare const IMAGINE_AGENT_BRIEFINGS: Record<string, (ctx: ProductContext) => string>;
|
|
217
|
+
/**
|
|
218
|
+
* Product-contextualized one-liner descriptions for Specify agents.
|
|
219
|
+
*/
|
|
220
|
+
export declare const SPECIFY_AGENT_BRIEFINGS: Record<string, (ctx: ProductContext) => string>;
|
|
221
|
+
/**
|
|
222
|
+
* Render a stage banner with a product-contextualized line below the title.
|
|
223
|
+
* Extension of renderBanner() for consultant-style messaging (Phase 16).
|
|
224
|
+
*
|
|
225
|
+
* ```
|
|
226
|
+
* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
227
|
+
* GSWD ► IMAGINE
|
|
228
|
+
* Validating product direction for a spec-writing tool targeting founders
|
|
229
|
+
* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
230
|
+
* ```
|
|
231
|
+
*
|
|
232
|
+
* @param stageName - Stage name (will be uppercased)
|
|
233
|
+
* @param contextLine - Product-contextualized one-liner
|
|
234
|
+
*/
|
|
235
|
+
export declare function renderContextBanner(stageName: string, contextLine: string): string;
|
|
236
|
+
/**
|
|
237
|
+
* Input for agent pre-briefing display.
|
|
238
|
+
*/
|
|
239
|
+
export interface AgentBriefingEntry {
|
|
240
|
+
name: string;
|
|
241
|
+
productPurpose: string;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Render agent pre-briefing block before spawning.
|
|
245
|
+
* Technical transparency: name each agent explicitly with product-specific purpose.
|
|
246
|
+
*
|
|
247
|
+
* ```
|
|
248
|
+
* ◆ Spawning 5 research agents:
|
|
249
|
+
* → market-researcher: mapping the spec-tooling landscape to find gaps
|
|
250
|
+
* → icp-persona: profiling founders who struggle with product specification
|
|
251
|
+
* ```
|
|
252
|
+
*
|
|
253
|
+
* @param agents - Array of agent names with product-contextualized purposes
|
|
254
|
+
* @param stageContext - Optional stage context description
|
|
255
|
+
*/
|
|
256
|
+
export declare function renderAgentBriefing(agents: AgentBriefingEntry[], stageContext?: string): string;
|
|
257
|
+
/**
|
|
258
|
+
* Render a single agent completion line with its key finding headline.
|
|
259
|
+
*
|
|
260
|
+
* ✓ market-researcher: 3 direct competitors in the spec-tooling space
|
|
261
|
+
* ✗ icp-persona: Agent failed — timeout
|
|
262
|
+
*
|
|
263
|
+
* @param agentName - Agent name
|
|
264
|
+
* @param headline - Key finding or error message
|
|
265
|
+
* @param status - Agent completion status
|
|
266
|
+
*/
|
|
267
|
+
export declare function renderAgentCompletion(agentName: string, headline: string, status: 'complete' | 'failed'): string;
|
|
268
|
+
/**
|
|
269
|
+
* Render full agent progress block showing pending and completed agents.
|
|
270
|
+
* Pending agents show ○, completed show ✓ with headline, failed show ✗.
|
|
271
|
+
*
|
|
272
|
+
* ✓ market-researcher: 3 direct competitors found
|
|
273
|
+
* ✓ icp-persona: primary persona is technical founder
|
|
274
|
+
* ○ positioning (pending)
|
|
275
|
+
* ○ brainstorm-alternatives (pending)
|
|
276
|
+
* ○ devils-advocate (pending)
|
|
277
|
+
*/
|
|
278
|
+
export declare function renderAgentProgress(agents: Array<{
|
|
279
|
+
name: string;
|
|
280
|
+
status: 'pending' | 'complete' | 'failed';
|
|
281
|
+
headline?: string;
|
|
282
|
+
}>): string;
|
|
283
|
+
/**
|
|
284
|
+
* Render a file inventory table listing all generated files with descriptions.
|
|
285
|
+
* Used at pipeline end to give users a deliverable checklist.
|
|
286
|
+
*
|
|
287
|
+
* @param files - Array of { path, description } objects
|
|
288
|
+
* @returns Markdown table string
|
|
289
|
+
*/
|
|
290
|
+
export declare function renderFileInventory(files: Array<{
|
|
291
|
+
path: string;
|
|
292
|
+
description: string;
|
|
293
|
+
}>): string;
|
|
294
|
+
/**
|
|
295
|
+
* Extract a one-line headline from agent output for completion display.
|
|
296
|
+
* Multi-strategy extraction with robust fallback.
|
|
297
|
+
*
|
|
298
|
+
* Strategy priority:
|
|
299
|
+
* 1. First sentence after "## Summary" heading
|
|
300
|
+
* 2. Text after "Key finding:" prefix
|
|
301
|
+
* 3. First non-heading, non-empty line
|
|
302
|
+
* 4. Fallback: "{agentName} analysis complete"
|
|
303
|
+
*
|
|
304
|
+
* Truncates to 80 chars. Never returns empty string.
|
|
305
|
+
*
|
|
306
|
+
* @param agentOutput - Raw agent output content
|
|
307
|
+
* @param agentName - Agent name (for fallback)
|
|
308
|
+
*/
|
|
309
|
+
export declare function extractHeadline(agentOutput: string, agentName: string): string;
|