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,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSWD Specify Agents Module — Agent definitions, sequential-then-parallel orchestration
|
|
3
|
+
*
|
|
4
|
+
* Provides the 3 specify agents: journey-mapper (sequential), then
|
|
5
|
+
* architecture-drafter + integrations-checker (parallel).
|
|
6
|
+
*
|
|
7
|
+
* Follows the imagine-agents.ts pattern but with phased orchestration.
|
|
8
|
+
*
|
|
9
|
+
* Schema: GSWD_SPEC.md Section 8.3, Section 11.1
|
|
10
|
+
*/
|
|
11
|
+
import type { Journey, FunctionalRequirement } from './specify-journeys.js';
|
|
12
|
+
import type { OnAgentComplete } from './imagine-agents.js';
|
|
13
|
+
export interface SpecifyAgentDefinition {
|
|
14
|
+
/** Agent name matching file name (without .md) */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Path to agent definition file */
|
|
17
|
+
definitionPath: string;
|
|
18
|
+
/** Phase: 'sequential' runs first, 'parallel' runs after sequential completes */
|
|
19
|
+
phase: 'sequential' | 'parallel';
|
|
20
|
+
/** Minimum headings expected in agent output */
|
|
21
|
+
requiredHeadings: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface Integration {
|
|
24
|
+
/** Integration ID in I-001 format */
|
|
25
|
+
id: string;
|
|
26
|
+
/** Integration name */
|
|
27
|
+
name: string;
|
|
28
|
+
/** Steps to set up the integration */
|
|
29
|
+
setupSteps: string[];
|
|
30
|
+
/** Authentication method */
|
|
31
|
+
authMethod: string;
|
|
32
|
+
/** Monthly cost or quota description */
|
|
33
|
+
costQuota: string;
|
|
34
|
+
/** Fallback if integration unavailable */
|
|
35
|
+
fallback: string;
|
|
36
|
+
/** Approval status — MANDATORY field */
|
|
37
|
+
status: 'approved' | 'deferred with fallback' | 'rejected';
|
|
38
|
+
}
|
|
39
|
+
export interface ArchitectureComponent {
|
|
40
|
+
/** Component ID in C-001 format */
|
|
41
|
+
id: string;
|
|
42
|
+
/** Component name */
|
|
43
|
+
name: string;
|
|
44
|
+
/** What this component does */
|
|
45
|
+
responsibility: string;
|
|
46
|
+
/** Other C-XXX IDs this depends on */
|
|
47
|
+
dependencies: string[];
|
|
48
|
+
/** FR-XXX IDs this component implements */
|
|
49
|
+
linkedFRs: string[];
|
|
50
|
+
}
|
|
51
|
+
export interface AgentResult {
|
|
52
|
+
/** Agent name */
|
|
53
|
+
agent: string;
|
|
54
|
+
/** Agent output content */
|
|
55
|
+
content: string;
|
|
56
|
+
/** Completion status */
|
|
57
|
+
status: 'complete' | 'failed';
|
|
58
|
+
/** Error message if failed */
|
|
59
|
+
error?: string;
|
|
60
|
+
/** Execution time in milliseconds */
|
|
61
|
+
duration_ms?: number;
|
|
62
|
+
}
|
|
63
|
+
export type SpawnFn = (prompt: string) => Promise<string>;
|
|
64
|
+
/**
|
|
65
|
+
* The 3 specify agents from GSWD_SPEC Section 11.1.
|
|
66
|
+
* journey-mapper runs first (sequential); others run after (parallel).
|
|
67
|
+
*/
|
|
68
|
+
export declare const SPECIFY_AGENTS: SpecifyAgentDefinition[];
|
|
69
|
+
export interface SpecifyAgentContext {
|
|
70
|
+
/** DECISIONS.md content */
|
|
71
|
+
decisionsContent: string;
|
|
72
|
+
/** IMAGINE.md content (optional) */
|
|
73
|
+
imagineContent?: string;
|
|
74
|
+
/** Extracted journeys (available after journey-mapper) */
|
|
75
|
+
journeys?: Journey[];
|
|
76
|
+
/** Extracted FRs (available after FR extraction) */
|
|
77
|
+
frs?: FunctionalRequirement[];
|
|
78
|
+
/** Auto policy config content */
|
|
79
|
+
autoPolicy?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Build the prompt for a specify agent.
|
|
83
|
+
*
|
|
84
|
+
* - journey-mapper: gets DECISIONS.md + IMAGINE.md
|
|
85
|
+
* - architecture-drafter: gets journeys + FRs + DECISIONS.md
|
|
86
|
+
* - integrations-checker: gets journeys + FRs + DECISIONS.md + auto policy
|
|
87
|
+
*/
|
|
88
|
+
export declare function buildSpecifyAgentPrompt(agent: SpecifyAgentDefinition, context: SpecifyAgentContext): string;
|
|
89
|
+
/**
|
|
90
|
+
* Orchestrate specify agents with sequential-then-parallel pattern.
|
|
91
|
+
*
|
|
92
|
+
* Phase 1 (sequential): Run journey-mapper, wait for completion.
|
|
93
|
+
* Phase 2 (parallel): Run architecture-drafter + integrations-checker concurrently.
|
|
94
|
+
*
|
|
95
|
+
* Failed agents are marked with status: 'failed' but do not crash orchestration.
|
|
96
|
+
*
|
|
97
|
+
* @param agents - Agent definitions (defaults to SPECIFY_AGENTS)
|
|
98
|
+
* @param context - Shared context for prompt building
|
|
99
|
+
* @param spawnFn - Function that spawns an agent (Task() wrapper)
|
|
100
|
+
* @returns All agent results including failures
|
|
101
|
+
*/
|
|
102
|
+
export declare function orchestrateSpecifyAgents(agents: SpecifyAgentDefinition[], context: SpecifyAgentContext, spawnFn: SpawnFn, onComplete?: OnAgentComplete): Promise<AgentResult[]>;
|
|
103
|
+
/**
|
|
104
|
+
* Valid integration status values.
|
|
105
|
+
*/
|
|
106
|
+
export declare const VALID_INTEGRATION_STATUSES: readonly ["approved", "deferred with fallback", "rejected"];
|
|
107
|
+
/**
|
|
108
|
+
* Validate that an integration has all required fields including mandatory Status.
|
|
109
|
+
*/
|
|
110
|
+
export declare function validateIntegration(integration: Integration): {
|
|
111
|
+
valid: boolean;
|
|
112
|
+
errors: string[];
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Validate that a component has correct ID format and required fields.
|
|
116
|
+
*/
|
|
117
|
+
export declare function validateComponent(component: ArchitectureComponent): {
|
|
118
|
+
valid: boolean;
|
|
119
|
+
errors: string[];
|
|
120
|
+
};
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* GSWD Specify Agents Module — Agent definitions, sequential-then-parallel orchestration
|
|
4
|
+
*
|
|
5
|
+
* Provides the 3 specify agents: journey-mapper (sequential), then
|
|
6
|
+
* architecture-drafter + integrations-checker (parallel).
|
|
7
|
+
*
|
|
8
|
+
* Follows the imagine-agents.ts pattern but with phased orchestration.
|
|
9
|
+
*
|
|
10
|
+
* Schema: GSWD_SPEC.md Section 8.3, Section 11.1
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.VALID_INTEGRATION_STATUSES = exports.SPECIFY_AGENTS = void 0;
|
|
47
|
+
exports.buildSpecifyAgentPrompt = buildSpecifyAgentPrompt;
|
|
48
|
+
exports.orchestrateSpecifyAgents = orchestrateSpecifyAgents;
|
|
49
|
+
exports.validateIntegration = validateIntegration;
|
|
50
|
+
exports.validateComponent = validateComponent;
|
|
51
|
+
const fs = __importStar(require("node:fs"));
|
|
52
|
+
const render_js_1 = require("./render.js");
|
|
53
|
+
// ─── Agent Definitions ───────────────────────────────────────────────────────
|
|
54
|
+
/**
|
|
55
|
+
* The 3 specify agents from GSWD_SPEC Section 11.1.
|
|
56
|
+
* journey-mapper runs first (sequential); others run after (parallel).
|
|
57
|
+
*/
|
|
58
|
+
exports.SPECIFY_AGENTS = [
|
|
59
|
+
{
|
|
60
|
+
name: 'journey-mapper',
|
|
61
|
+
definitionPath: 'agents/gswd/journey-mapper.md',
|
|
62
|
+
phase: 'sequential',
|
|
63
|
+
requiredHeadings: ['### J-'],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'architecture-drafter',
|
|
67
|
+
definitionPath: 'agents/gswd/architecture-drafter.md',
|
|
68
|
+
phase: 'parallel',
|
|
69
|
+
requiredHeadings: ['### Components', '### Data Model'],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'integrations-checker',
|
|
73
|
+
definitionPath: 'agents/gswd/integrations-checker.md',
|
|
74
|
+
phase: 'parallel',
|
|
75
|
+
requiredHeadings: ['## Integrations'],
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
/**
|
|
79
|
+
* Build the prompt for a specify agent.
|
|
80
|
+
*
|
|
81
|
+
* - journey-mapper: gets DECISIONS.md + IMAGINE.md
|
|
82
|
+
* - architecture-drafter: gets journeys + FRs + DECISIONS.md
|
|
83
|
+
* - integrations-checker: gets journeys + FRs + DECISIONS.md + auto policy
|
|
84
|
+
*/
|
|
85
|
+
function buildSpecifyAgentPrompt(agent, context) {
|
|
86
|
+
let definition;
|
|
87
|
+
try {
|
|
88
|
+
definition = fs.readFileSync(agent.definitionPath, 'utf-8');
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
definition = `Agent: ${agent.name}\nRole: Specify agent`;
|
|
92
|
+
}
|
|
93
|
+
const sections = [definition];
|
|
94
|
+
// Always include decisions
|
|
95
|
+
if (context.decisionsContent) {
|
|
96
|
+
sections.push(`<decisions>\n${context.decisionsContent}\n</decisions>`);
|
|
97
|
+
}
|
|
98
|
+
switch (agent.name) {
|
|
99
|
+
case 'journey-mapper':
|
|
100
|
+
if (context.imagineContent) {
|
|
101
|
+
sections.push(`<imagine>\n${context.imagineContent}\n</imagine>`);
|
|
102
|
+
}
|
|
103
|
+
break;
|
|
104
|
+
case 'architecture-drafter':
|
|
105
|
+
if (context.frs && context.frs.length > 0) {
|
|
106
|
+
const frSummary = context.frs
|
|
107
|
+
.map((fr) => `- ${fr.id}: ${fr.description} [${fr.scope}/${fr.priority}]`)
|
|
108
|
+
.join('\n');
|
|
109
|
+
sections.push(`<functional_requirements>\n${frSummary}\n</functional_requirements>`);
|
|
110
|
+
}
|
|
111
|
+
if (context.journeys && context.journeys.length > 0) {
|
|
112
|
+
const journeySummary = context.journeys
|
|
113
|
+
.map((j) => `- ${j.id}: ${j.name} (${j.type}, ${j.steps.length} steps)`)
|
|
114
|
+
.join('\n');
|
|
115
|
+
sections.push(`<journeys>\n${journeySummary}\n</journeys>`);
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
case 'integrations-checker':
|
|
119
|
+
if (context.frs && context.frs.length > 0) {
|
|
120
|
+
const frSummary = context.frs
|
|
121
|
+
.map((fr) => `- ${fr.id}: ${fr.description} [${fr.scope}/${fr.priority}]`)
|
|
122
|
+
.join('\n');
|
|
123
|
+
sections.push(`<functional_requirements>\n${frSummary}\n</functional_requirements>`);
|
|
124
|
+
}
|
|
125
|
+
if (context.journeys && context.journeys.length > 0) {
|
|
126
|
+
const journeySummary = context.journeys
|
|
127
|
+
.map((j) => `- ${j.id}: ${j.name} (${j.type}, ${j.steps.length} steps)`)
|
|
128
|
+
.join('\n');
|
|
129
|
+
sections.push(`<journeys>\n${journeySummary}\n</journeys>`);
|
|
130
|
+
}
|
|
131
|
+
if (context.autoPolicy) {
|
|
132
|
+
sections.push(`<auto_policy>\n${context.autoPolicy}\n</auto_policy>`);
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
sections.push(`Produce your output now. Include all required headings: ${agent.requiredHeadings.join(', ')}.`);
|
|
137
|
+
return sections.join('\n\n');
|
|
138
|
+
}
|
|
139
|
+
// ─── Orchestration ───────────────────────────────────────────────────────────
|
|
140
|
+
/**
|
|
141
|
+
* Orchestrate specify agents with sequential-then-parallel pattern.
|
|
142
|
+
*
|
|
143
|
+
* Phase 1 (sequential): Run journey-mapper, wait for completion.
|
|
144
|
+
* Phase 2 (parallel): Run architecture-drafter + integrations-checker concurrently.
|
|
145
|
+
*
|
|
146
|
+
* Failed agents are marked with status: 'failed' but do not crash orchestration.
|
|
147
|
+
*
|
|
148
|
+
* @param agents - Agent definitions (defaults to SPECIFY_AGENTS)
|
|
149
|
+
* @param context - Shared context for prompt building
|
|
150
|
+
* @param spawnFn - Function that spawns an agent (Task() wrapper)
|
|
151
|
+
* @returns All agent results including failures
|
|
152
|
+
*/
|
|
153
|
+
async function orchestrateSpecifyAgents(agents, context, spawnFn, onComplete) {
|
|
154
|
+
const results = [];
|
|
155
|
+
// Phase 1: Sequential agents
|
|
156
|
+
const sequentialAgents = agents.filter((a) => a.phase === 'sequential');
|
|
157
|
+
for (const agent of sequentialAgents) {
|
|
158
|
+
const result = await runSingleAgent(agent, context, spawnFn);
|
|
159
|
+
results.push(result);
|
|
160
|
+
if (onComplete) {
|
|
161
|
+
onComplete({
|
|
162
|
+
agent: result.agent,
|
|
163
|
+
headline: result.status === 'complete'
|
|
164
|
+
? (0, render_js_1.extractHeadline)(result.content, result.agent)
|
|
165
|
+
: (result.error || 'Agent failed'),
|
|
166
|
+
status: result.status,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Phase 2: Parallel agents
|
|
171
|
+
const parallelAgents = agents.filter((a) => a.phase === 'parallel');
|
|
172
|
+
if (parallelAgents.length > 0) {
|
|
173
|
+
const parallelPromises = parallelAgents.map(async (agent) => {
|
|
174
|
+
const result = await runSingleAgent(agent, context, spawnFn);
|
|
175
|
+
if (onComplete) {
|
|
176
|
+
onComplete({
|
|
177
|
+
agent: result.agent,
|
|
178
|
+
headline: result.status === 'complete'
|
|
179
|
+
? (0, render_js_1.extractHeadline)(result.content, result.agent)
|
|
180
|
+
: (result.error || 'Agent failed'),
|
|
181
|
+
status: result.status,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
});
|
|
186
|
+
const parallelResults = await Promise.all(parallelPromises);
|
|
187
|
+
results.push(...parallelResults);
|
|
188
|
+
}
|
|
189
|
+
return results;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Run a single agent and return its result.
|
|
193
|
+
*/
|
|
194
|
+
async function runSingleAgent(agent, context, spawnFn) {
|
|
195
|
+
const start = Date.now();
|
|
196
|
+
try {
|
|
197
|
+
const prompt = buildSpecifyAgentPrompt(agent, context);
|
|
198
|
+
const content = await spawnFn(prompt);
|
|
199
|
+
return {
|
|
200
|
+
agent: agent.name,
|
|
201
|
+
content,
|
|
202
|
+
status: 'complete',
|
|
203
|
+
duration_ms: Date.now() - start,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
208
|
+
return {
|
|
209
|
+
agent: agent.name,
|
|
210
|
+
content: '',
|
|
211
|
+
status: 'failed',
|
|
212
|
+
error: message,
|
|
213
|
+
duration_ms: Date.now() - start,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// ─── Integration Validation ──────────────────────────────────────────────────
|
|
218
|
+
/**
|
|
219
|
+
* Valid integration status values.
|
|
220
|
+
*/
|
|
221
|
+
exports.VALID_INTEGRATION_STATUSES = [
|
|
222
|
+
'approved',
|
|
223
|
+
'deferred with fallback',
|
|
224
|
+
'rejected',
|
|
225
|
+
];
|
|
226
|
+
/**
|
|
227
|
+
* Validate that an integration has all required fields including mandatory Status.
|
|
228
|
+
*/
|
|
229
|
+
function validateIntegration(integration) {
|
|
230
|
+
const errors = [];
|
|
231
|
+
// ID format
|
|
232
|
+
if (!/^I-\d{3,}$/.test(integration.id)) {
|
|
233
|
+
errors.push(`Invalid integration ID format: ${integration.id} (expected I-XXX)`);
|
|
234
|
+
}
|
|
235
|
+
// Name non-empty
|
|
236
|
+
if (!integration.name || integration.name.trim() === '') {
|
|
237
|
+
errors.push(`Integration ${integration.id} has empty name`);
|
|
238
|
+
}
|
|
239
|
+
// Status is mandatory and must be a valid value
|
|
240
|
+
if (!exports.VALID_INTEGRATION_STATUSES.includes(integration.status)) {
|
|
241
|
+
errors.push(`Integration ${integration.id} has invalid status: "${integration.status}" (expected: ${exports.VALID_INTEGRATION_STATUSES.join(', ')})`);
|
|
242
|
+
}
|
|
243
|
+
// Deferred integrations must have a fallback
|
|
244
|
+
if (integration.status === 'deferred with fallback') {
|
|
245
|
+
if (!integration.fallback || integration.fallback.trim() === '') {
|
|
246
|
+
errors.push(`Integration ${integration.id} is deferred but has no fallback`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return { valid: errors.length === 0, errors };
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Validate that a component has correct ID format and required fields.
|
|
253
|
+
*/
|
|
254
|
+
function validateComponent(component) {
|
|
255
|
+
const errors = [];
|
|
256
|
+
// ID format
|
|
257
|
+
if (!/^C-\d{3,}$/.test(component.id)) {
|
|
258
|
+
errors.push(`Invalid component ID format: ${component.id} (expected C-XXX)`);
|
|
259
|
+
}
|
|
260
|
+
// Name non-empty
|
|
261
|
+
if (!component.name || component.name.trim() === '') {
|
|
262
|
+
errors.push(`Component ${component.id} has empty name`);
|
|
263
|
+
}
|
|
264
|
+
// Responsibility non-empty
|
|
265
|
+
if (!component.responsibility || component.responsibility.trim() === '') {
|
|
266
|
+
errors.push(`Component ${component.id} has empty responsibility`);
|
|
267
|
+
}
|
|
268
|
+
return { valid: errors.length === 0, errors };
|
|
269
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSWD Specify Journeys Module — Journey generation, FR extraction, cross-linking
|
|
3
|
+
*
|
|
4
|
+
* Produces journey structures and extracts functional requirements from journey steps.
|
|
5
|
+
* Bidirectional cross-linking: journeys reference FR IDs, FRs reference source journeys.
|
|
6
|
+
*
|
|
7
|
+
* Schema: GSWD_SPEC.md Section 6.1 (ID formats), 6.2 (scope tagging), 8.3 (specify workflow)
|
|
8
|
+
*/
|
|
9
|
+
export type JourneyType = 'onboarding' | 'core_action' | 'view_results' | 'settings' | 'error_states' | 'empty_states';
|
|
10
|
+
export interface FailureMode {
|
|
11
|
+
/** Concise scenario description (1-2 sentences max) */
|
|
12
|
+
scenario: string;
|
|
13
|
+
/** How the system handles this failure */
|
|
14
|
+
handling: string;
|
|
15
|
+
}
|
|
16
|
+
export interface JourneyStep {
|
|
17
|
+
/** Step number (1-based) */
|
|
18
|
+
number: number;
|
|
19
|
+
/** User action description */
|
|
20
|
+
action: string;
|
|
21
|
+
/** FR-XXX IDs derived from this step (populated during extraction) */
|
|
22
|
+
frIds: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface Journey {
|
|
25
|
+
/** Journey ID in J-001 format */
|
|
26
|
+
id: string;
|
|
27
|
+
/** Human-readable journey name */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Journey type category */
|
|
30
|
+
type: JourneyType;
|
|
31
|
+
/** Conditions that must be true before journey starts */
|
|
32
|
+
preconditions: string[];
|
|
33
|
+
/** Ordered user action steps (5-8 for main, 3+ for error/empty) */
|
|
34
|
+
steps: JourneyStep[];
|
|
35
|
+
/** Successful completion outcome */
|
|
36
|
+
success: string;
|
|
37
|
+
/** Failure scenarios (>= 2 required) */
|
|
38
|
+
failureModes: FailureMode[];
|
|
39
|
+
/** Single assertable test statements (>= 1 required) */
|
|
40
|
+
acceptanceTests: string[];
|
|
41
|
+
/** FR-XXX IDs linked to this journey (populated after extraction) */
|
|
42
|
+
linkedFRs: string[];
|
|
43
|
+
/** NFR-XXX IDs linked to this journey (populated later) */
|
|
44
|
+
linkedNFRs: string[];
|
|
45
|
+
}
|
|
46
|
+
export interface FunctionalRequirement {
|
|
47
|
+
/** FR ID in FR-001 format */
|
|
48
|
+
id: string;
|
|
49
|
+
/** What this requirement describes */
|
|
50
|
+
description: string;
|
|
51
|
+
/** Scope tag: v1/v2/out */
|
|
52
|
+
scope: 'v1' | 'v2' | 'out';
|
|
53
|
+
/** Priority: P0 (blocks core), P1 (required v1), P2 (enhances) */
|
|
54
|
+
priority: 'P0' | 'P1' | 'P2';
|
|
55
|
+
/** J-XXX IDs of source journeys */
|
|
56
|
+
sourceJourneys: string[];
|
|
57
|
+
/** "J-XXX step N" format references */
|
|
58
|
+
sourceSteps: string[];
|
|
59
|
+
}
|
|
60
|
+
export interface TraceabilityEntry {
|
|
61
|
+
/** FR ID */
|
|
62
|
+
frId: string;
|
|
63
|
+
/** FR description */
|
|
64
|
+
description: string;
|
|
65
|
+
/** Formatted journey references: "J-001 (step 3), J-002 (step 1)" */
|
|
66
|
+
journeyRefs: string[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* All 6 required journey types from GSWD_SPEC Section 8.3.
|
|
70
|
+
*/
|
|
71
|
+
export declare const JOURNEY_TYPES: {
|
|
72
|
+
type: JourneyType;
|
|
73
|
+
displayName: string;
|
|
74
|
+
}[];
|
|
75
|
+
/**
|
|
76
|
+
* Assign scope based on journey type.
|
|
77
|
+
* Heuristic from CONTEXT.md locked decisions:
|
|
78
|
+
* - core_action/onboarding → v1
|
|
79
|
+
* - error_states/empty_states → v1 (required for polish)
|
|
80
|
+
* - view_results → v1
|
|
81
|
+
* - settings → v1 (default; caller can override to v2 for non-essential)
|
|
82
|
+
*/
|
|
83
|
+
export declare function assignScope(journeyType: JourneyType): 'v1' | 'v2' | 'out';
|
|
84
|
+
/**
|
|
85
|
+
* Assign priority based on journey type.
|
|
86
|
+
* Heuristic from CONTEXT.md locked decisions:
|
|
87
|
+
* - core_action/onboarding → P0 (blocks core journey)
|
|
88
|
+
* - error_states/empty_states/view_results/settings → P1 (required for complete v1)
|
|
89
|
+
*/
|
|
90
|
+
export declare function assignPriority(journeyType: JourneyType): 'P0' | 'P1' | 'P2';
|
|
91
|
+
/**
|
|
92
|
+
* Create a journey skeleton with proper ID and empty arrays.
|
|
93
|
+
*/
|
|
94
|
+
export declare function generateJourneyStructure(type: JourneyType, journeyNumber: number): Journey;
|
|
95
|
+
/**
|
|
96
|
+
* Validate a journey meets all structural requirements.
|
|
97
|
+
*/
|
|
98
|
+
export declare function validateJourney(journey: Journey): {
|
|
99
|
+
valid: boolean;
|
|
100
|
+
errors: string[];
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Extract FRs from journeys. Each journey step maps to at least 1 FR.
|
|
104
|
+
* Populates bidirectional cross-links:
|
|
105
|
+
* - Each step.frIds gets the generated FR IDs
|
|
106
|
+
* - Each journey.linkedFRs gets all FR IDs from its steps
|
|
107
|
+
* - Each FR.sourceJourneys references the parent journey
|
|
108
|
+
* - Each FR.sourceSteps references "J-XXX step N"
|
|
109
|
+
*
|
|
110
|
+
* Duplicate step descriptions merge into a single FR with multiple sources.
|
|
111
|
+
*/
|
|
112
|
+
export declare function extractFRsFromJourneys(journeys: Journey[]): FunctionalRequirement[];
|
|
113
|
+
/**
|
|
114
|
+
* Build traceability map for SPEC.md traceability table.
|
|
115
|
+
* Each entry maps an FR to its source journeys.
|
|
116
|
+
*/
|
|
117
|
+
export declare function buildTraceabilityMap(frs: FunctionalRequirement[]): TraceabilityEntry[];
|
|
118
|
+
/**
|
|
119
|
+
* Validate FR coverage: every journey step has FRs, every FR has sources.
|
|
120
|
+
*/
|
|
121
|
+
export declare function validateFRCoverage(journeys: Journey[], frs: FunctionalRequirement[]): {
|
|
122
|
+
valid: boolean;
|
|
123
|
+
errors: string[];
|
|
124
|
+
};
|