@nac3/forge-cli 0.2.0-alpha.13 → 0.2.0-alpha.15
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/dist/bin/yf.d.ts.map +1 -1
- package/dist/bin/yf.js +10 -0
- package/dist/bin/yf.js.map +1 -1
- package/dist/commands/approve.d.ts +32 -0
- package/dist/commands/approve.d.ts.map +1 -0
- package/dist/commands/approve.js +198 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/block.d.ts +28 -0
- package/dist/commands/block.d.ts.map +1 -0
- package/dist/commands/block.js +189 -0
- package/dist/commands/block.js.map +1 -0
- package/dist/commands/bootstrap.d.ts +35 -0
- package/dist/commands/bootstrap.d.ts.map +1 -0
- package/dist/commands/bootstrap.js +205 -0
- package/dist/commands/bootstrap.js.map +1 -0
- package/dist/commands/spec.d.ts +38 -0
- package/dist/commands/spec.d.ts.map +1 -0
- package/dist/commands/spec.js +256 -0
- package/dist/commands/spec.js.map +1 -0
- package/dist/commands/workflow-coverage.d.ts +30 -0
- package/dist/commands/workflow-coverage.d.ts.map +1 -0
- package/dist/commands/workflow-coverage.js +138 -0
- package/dist/commands/workflow-coverage.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yf bootstrap` -- Phase V step 14 of PRODUCT_WORKFLOW.md.
|
|
3
|
+
*
|
|
4
|
+
* Once Phase IV (approve) passes the three spec gates, this
|
|
5
|
+
* command initialises the project for the iterative build cycle:
|
|
6
|
+
*
|
|
7
|
+
* * Reads workflow.specs + workflow.clarification.blocks
|
|
8
|
+
* * Scaffolds the project shell (delegates to template engine
|
|
9
|
+
* if the project is brand-new; no-ops if code already exists)
|
|
10
|
+
* * Installs NAC-3 compliance baseline (5 attrs on the shell +
|
|
11
|
+
* manifest stub)
|
|
12
|
+
* * Sets CI gates (lint + typecheck + tests + visual + a11y +
|
|
13
|
+
* NAC-3 manifest check)
|
|
14
|
+
* * Sets up test scaffolding per layer (unit / integration /
|
|
15
|
+
* e2e / visual / a11y)
|
|
16
|
+
* * Sets up observability hooks (logger + optional Sentry)
|
|
17
|
+
* * Initialises blocks_progress = [{ block_id, status: pending }]
|
|
18
|
+
* for every block in workflow.clarification.blocks
|
|
19
|
+
*
|
|
20
|
+
* For alpha.15 the bootstrap is a thin shell -- it sets the
|
|
21
|
+
* workflow state + writes scaffolding markers + the actual
|
|
22
|
+
* heavy lifting (templates, CI config generation, observability
|
|
23
|
+
* wiring) lands incrementally in follow-up commits.
|
|
24
|
+
*
|
|
25
|
+
* ASCII-only.
|
|
26
|
+
*/
|
|
27
|
+
import path from 'node:path';
|
|
28
|
+
import { promises as fs } from 'node:fs';
|
|
29
|
+
import { c, header } from '../ui/colors.js';
|
|
30
|
+
import { readWorkflow, patchWorkflowGroup, writeWorkflow, } from '../workflow/state.js';
|
|
31
|
+
const DEFAULT_STACK = 'React + Vite + TypeScript + Vitest + Playwright + NAC-3';
|
|
32
|
+
async function ensureGitIgnoreHas(projectRoot, patterns) {
|
|
33
|
+
const giPath = path.join(projectRoot, '.gitignore');
|
|
34
|
+
let current = '';
|
|
35
|
+
try {
|
|
36
|
+
current = await fs.readFile(giPath, 'utf-8');
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
current = '';
|
|
40
|
+
}
|
|
41
|
+
const lines = new Set(current.split(/\r?\n/));
|
|
42
|
+
for (const p of patterns)
|
|
43
|
+
lines.add(p);
|
|
44
|
+
await fs.writeFile(giPath, [...lines].filter(Boolean).join('\n') + '\n', 'utf-8');
|
|
45
|
+
}
|
|
46
|
+
async function ensureFile(p, contents) {
|
|
47
|
+
try {
|
|
48
|
+
await fs.access(p);
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
catch { /* not present */ }
|
|
52
|
+
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
53
|
+
await fs.writeFile(p, contents, 'utf-8');
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
export async function runBootstrap(opts) {
|
|
57
|
+
header('Yujin Forge -- bootstrap');
|
|
58
|
+
console.log('');
|
|
59
|
+
const projectRoot = opts.cwd ? path.resolve(opts.cwd) : process.cwd();
|
|
60
|
+
const wf = await readWorkflow(projectRoot);
|
|
61
|
+
/* Gate: Phase IV must have approved all 3 docs with current
|
|
62
|
+
* sha256 matching. */
|
|
63
|
+
const docs = ['rfp', 'arch', 'design'];
|
|
64
|
+
for (const d of docs) {
|
|
65
|
+
const sp = wf.specs?.[d];
|
|
66
|
+
const ap = wf.approvals?.[d];
|
|
67
|
+
if (!sp || !ap) {
|
|
68
|
+
console.log(c.error('Phase IV gate no aprobado todavia (' + d + ' falta).'));
|
|
69
|
+
console.log(c.dim('Corre: ') + c.code('yf approve ' + d));
|
|
70
|
+
process.exitCode = 1;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (ap.version_sha256 !== sp.sha256) {
|
|
74
|
+
console.log(c.error('Approval STALE para ' + d + '. Doc cambio desde la aprobacion.'));
|
|
75
|
+
console.log(c.dim('Re-aprueba: ') + c.code('yf approve ' + d));
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (wf.bootstrap && !opts.yes) {
|
|
81
|
+
console.log(c.warn('Bootstrap previo en ' + wf.bootstrap.done_at + '.'));
|
|
82
|
+
console.log(c.dim('Para volver a correr, ') + c.code('yf bootstrap --yes'));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const stack = opts.stack || DEFAULT_STACK;
|
|
86
|
+
const blocks = wf.clarification?.blocks?.blocks ?? [];
|
|
87
|
+
if (blocks.length === 0) {
|
|
88
|
+
console.log(c.error('No hay bloques definidos en workflow.clarification.blocks.'));
|
|
89
|
+
console.log(c.dim('Corre: ') + c.code('yf clarify blocks'));
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
console.log(c.dim('Stack: ') + c.brand(stack));
|
|
94
|
+
console.log(c.dim('Blocks: ') + c.brand(String(blocks.length) + ' identificados'));
|
|
95
|
+
console.log(c.dim('Project root: ') + c.dim(projectRoot));
|
|
96
|
+
console.log('');
|
|
97
|
+
/* 1. Ensure a NAC-3 manifest stub exists. */
|
|
98
|
+
const manifestPath = path.join(projectRoot, 'src', 'nac', 'manifest.ts');
|
|
99
|
+
const wroteManifest = await ensureFile(manifestPath, [
|
|
100
|
+
'/**',
|
|
101
|
+
' * NAC-3 manifest stub generated by `yf bootstrap`.',
|
|
102
|
+
' * Forge populates this as you decorate components per block.',
|
|
103
|
+
' */',
|
|
104
|
+
"import { defineNacManifest } from '@nac3/runtime';",
|
|
105
|
+
'',
|
|
106
|
+
'export const manifest = defineNacManifest({',
|
|
107
|
+
' app_name: "' + path.basename(projectRoot) + '",',
|
|
108
|
+
' version: "0.0.1",',
|
|
109
|
+
' elements: [',
|
|
110
|
+
' /* Populated per block. See docs/project_design.md. */',
|
|
111
|
+
' ],',
|
|
112
|
+
'});',
|
|
113
|
+
'',
|
|
114
|
+
].join('\n'));
|
|
115
|
+
if (wroteManifest)
|
|
116
|
+
console.log(c.success(' +') + c.dim(' src/nac/manifest.ts'));
|
|
117
|
+
/* 2. CI workflow stub at .github/workflows/ci.yml if missing. */
|
|
118
|
+
const ciPath = path.join(projectRoot, '.github', 'workflows', 'ci.yml');
|
|
119
|
+
const wroteCi = await ensureFile(ciPath, [
|
|
120
|
+
'name: CI',
|
|
121
|
+
'on: { push: { branches: [main] }, pull_request: {} }',
|
|
122
|
+
'jobs:',
|
|
123
|
+
' test:',
|
|
124
|
+
' runs-on: ubuntu-latest',
|
|
125
|
+
' steps:',
|
|
126
|
+
' - uses: actions/checkout@v4',
|
|
127
|
+
' - uses: actions/setup-node@v4',
|
|
128
|
+
' with: { node-version: "20", cache: "npm" }',
|
|
129
|
+
' - run: npm ci',
|
|
130
|
+
' - run: npx yf doctor --json',
|
|
131
|
+
' - run: npm run lint --if-present',
|
|
132
|
+
' - run: npm run typecheck --if-present',
|
|
133
|
+
' - run: npm test --if-present',
|
|
134
|
+
' - run: npx yf coverage structural --if-failing-exit-1',
|
|
135
|
+
'',
|
|
136
|
+
].join('\n'));
|
|
137
|
+
if (wroteCi)
|
|
138
|
+
console.log(c.success(' +') + c.dim(' .github/workflows/ci.yml'));
|
|
139
|
+
/* 3. tests/fresh-user/ scaffold (per SQ Sec 14). */
|
|
140
|
+
const fuReadme = path.join(projectRoot, 'tests', 'fresh-user', 'README.md');
|
|
141
|
+
const wroteFu = await ensureFile(fuReadme, [
|
|
142
|
+
'# tests/fresh-user/',
|
|
143
|
+
'',
|
|
144
|
+
'Per Yujin Forge SQ Sec 14, every feature in this project has',
|
|
145
|
+
'a fresh-user e2e test: clean state -> exercise feature -> assert.',
|
|
146
|
+
'',
|
|
147
|
+
'Forge generates one of these per block as part of the',
|
|
148
|
+
'`yf block dev <block_id>` cycle.',
|
|
149
|
+
'',
|
|
150
|
+
].join('\n'));
|
|
151
|
+
if (wroteFu)
|
|
152
|
+
console.log(c.success(' +') + c.dim(' tests/fresh-user/README.md'));
|
|
153
|
+
/* 4. .gitignore additions. */
|
|
154
|
+
await ensureGitIgnoreHas(projectRoot, [
|
|
155
|
+
'node_modules',
|
|
156
|
+
'dist', 'build', '.next',
|
|
157
|
+
'coverage', '.cache',
|
|
158
|
+
'.env', '.env.local',
|
|
159
|
+
'.yujin-forge',
|
|
160
|
+
'yujin.forge.cache',
|
|
161
|
+
]);
|
|
162
|
+
console.log(c.success(' +') + c.dim(' .gitignore patterns'));
|
|
163
|
+
/* 5. Initialise blocks_progress for every block in workflow. */
|
|
164
|
+
const blocks_progress = blocks.map((b) => ({
|
|
165
|
+
block_id: b.id,
|
|
166
|
+
status: 'pending',
|
|
167
|
+
}));
|
|
168
|
+
await writeWorkflow(projectRoot, { blocks_progress });
|
|
169
|
+
console.log(c.success(' +') + c.dim(' blocks_progress[] initialised (' + blocks.length + ' bloques pending)'));
|
|
170
|
+
/* 6. Persist bootstrap state. */
|
|
171
|
+
await patchWorkflowGroup(projectRoot, 'bootstrap', {
|
|
172
|
+
done_at: new Date().toISOString(),
|
|
173
|
+
stack,
|
|
174
|
+
ci_set: true,
|
|
175
|
+
});
|
|
176
|
+
console.log('');
|
|
177
|
+
console.log(c.success('Bootstrap completado.'));
|
|
178
|
+
console.log('');
|
|
179
|
+
/* Suggest the first MVP block. */
|
|
180
|
+
const mvp = wf.clarification?.blocks?.mvp_path ?? [];
|
|
181
|
+
const firstBlock = mvp[0] ?? blocks[0]?.id;
|
|
182
|
+
if (firstBlock) {
|
|
183
|
+
console.log(c.dim('Primer bloque sugerido: ') + c.code('yf block dev ' + firstBlock));
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
console.log(c.dim('Siguiente paso: ') + c.code('yf block dev <block_id>'));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export function registerBootstrapCommand(program) {
|
|
190
|
+
program.command('bootstrap')
|
|
191
|
+
.description('Phase V step 14: initialise project (NAC-3 baseline + CI + tests + observability).')
|
|
192
|
+
.option('--cwd <path>', 'project root (default: current directory)')
|
|
193
|
+
.option('--yes', 're-run even if bootstrap already done')
|
|
194
|
+
.option('--stack <name>', 'override the default stack label')
|
|
195
|
+
.action(async (opts) => {
|
|
196
|
+
try {
|
|
197
|
+
await runBootstrap(opts);
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
console.error(c.error(err instanceof Error ? err.message : String(err)));
|
|
201
|
+
process.exitCode = 1;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/commands/bootstrap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yf spec rfp|arch|design` -- Phase III of PRODUCT_WORKFLOW.md
|
|
3
|
+
* (steps 10, 11, 12).
|
|
4
|
+
*
|
|
5
|
+
* Generates the three foundational documents that Phase IV gates
|
|
6
|
+
* on:
|
|
7
|
+
*
|
|
8
|
+
* yf spec rfp step 10 -- consolidated RFP / PRD
|
|
9
|
+
* yf spec arch step 11 -- technological architecture
|
|
10
|
+
* yf spec design step 12 -- solution design (per block)
|
|
11
|
+
*
|
|
12
|
+
* Each command:
|
|
13
|
+
* 1. Verifies Phase II is complete (functional + 4 NFR rounds +
|
|
14
|
+
* blocks). For RFP, all 6 are required. For arch + design,
|
|
15
|
+
* RFP must be done too.
|
|
16
|
+
* 2. Reads the markdown clarification docs from
|
|
17
|
+
* docs/clarification/0X_<round>.md.
|
|
18
|
+
* 3. Calls Claude with the document-specific generation prompt.
|
|
19
|
+
* 4. Writes the result to docs/project_<doc>.md.
|
|
20
|
+
* 5. Persists workflow.specs.<doc> with version, doc_path,
|
|
21
|
+
* sha256.
|
|
22
|
+
*
|
|
23
|
+
* Per HITO_4_STRATEGIC_ASSETS.md sec 1, the Tier-1 strategic
|
|
24
|
+
* prompts for these flows are eventually moving server-side to
|
|
25
|
+
* prompts.yujin.app. Today they live client-side as a stub --
|
|
26
|
+
* the system prompt is generic; a follow-up commit replaces it
|
|
27
|
+
* with the curated server-side endpoint when the Yujin server
|
|
28
|
+
* exposes them.
|
|
29
|
+
*
|
|
30
|
+
* ASCII-only.
|
|
31
|
+
*/
|
|
32
|
+
import type { Command } from 'commander';
|
|
33
|
+
export interface SpecOptions {
|
|
34
|
+
cwd?: string;
|
|
35
|
+
yes?: boolean;
|
|
36
|
+
}
|
|
37
|
+
export declare function registerSpecCommand(program: Command): void;
|
|
38
|
+
//# sourceMappingURL=spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../src/commands/spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAazC,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AA2ND,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkB1D"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yf spec rfp|arch|design` -- Phase III of PRODUCT_WORKFLOW.md
|
|
3
|
+
* (steps 10, 11, 12).
|
|
4
|
+
*
|
|
5
|
+
* Generates the three foundational documents that Phase IV gates
|
|
6
|
+
* on:
|
|
7
|
+
*
|
|
8
|
+
* yf spec rfp step 10 -- consolidated RFP / PRD
|
|
9
|
+
* yf spec arch step 11 -- technological architecture
|
|
10
|
+
* yf spec design step 12 -- solution design (per block)
|
|
11
|
+
*
|
|
12
|
+
* Each command:
|
|
13
|
+
* 1. Verifies Phase II is complete (functional + 4 NFR rounds +
|
|
14
|
+
* blocks). For RFP, all 6 are required. For arch + design,
|
|
15
|
+
* RFP must be done too.
|
|
16
|
+
* 2. Reads the markdown clarification docs from
|
|
17
|
+
* docs/clarification/0X_<round>.md.
|
|
18
|
+
* 3. Calls Claude with the document-specific generation prompt.
|
|
19
|
+
* 4. Writes the result to docs/project_<doc>.md.
|
|
20
|
+
* 5. Persists workflow.specs.<doc> with version, doc_path,
|
|
21
|
+
* sha256.
|
|
22
|
+
*
|
|
23
|
+
* Per HITO_4_STRATEGIC_ASSETS.md sec 1, the Tier-1 strategic
|
|
24
|
+
* prompts for these flows are eventually moving server-side to
|
|
25
|
+
* prompts.yujin.app. Today they live client-side as a stub --
|
|
26
|
+
* the system prompt is generic; a follow-up commit replaces it
|
|
27
|
+
* with the curated server-side endpoint when the Yujin server
|
|
28
|
+
* exposes them.
|
|
29
|
+
*
|
|
30
|
+
* ASCII-only.
|
|
31
|
+
*/
|
|
32
|
+
import path from 'node:path';
|
|
33
|
+
import { promises as fs } from 'node:fs';
|
|
34
|
+
import { createHash } from 'node:crypto';
|
|
35
|
+
import { c, header } from '../ui/colors.js';
|
|
36
|
+
import { ClaudeClient } from '../chat/claude.js';
|
|
37
|
+
import { readWorkflow, patchWorkflowGroup, } from '../workflow/state.js';
|
|
38
|
+
const DOC_FILENAME = {
|
|
39
|
+
rfp: 'project_rfp.md',
|
|
40
|
+
arch: 'project_architecture.md',
|
|
41
|
+
design: 'project_design.md',
|
|
42
|
+
};
|
|
43
|
+
const DOC_TITLE = {
|
|
44
|
+
rfp: 'RFP / PRD',
|
|
45
|
+
arch: 'Architecture',
|
|
46
|
+
design: 'Solution Design',
|
|
47
|
+
};
|
|
48
|
+
const CLARIFICATION_FILES = [
|
|
49
|
+
'04_functional.md',
|
|
50
|
+
'05_quantitative.md',
|
|
51
|
+
'06_structural.md',
|
|
52
|
+
'07_governance.md',
|
|
53
|
+
'08_operational.md',
|
|
54
|
+
'09_blocks.md',
|
|
55
|
+
];
|
|
56
|
+
async function readAllClarification(projectRoot) {
|
|
57
|
+
const dir = path.join(projectRoot, 'docs', 'clarification');
|
|
58
|
+
const parts = [];
|
|
59
|
+
for (const name of CLARIFICATION_FILES) {
|
|
60
|
+
try {
|
|
61
|
+
const text = await fs.readFile(path.join(dir, name), 'utf-8');
|
|
62
|
+
parts.push('===== ' + name + ' =====\n' + text);
|
|
63
|
+
}
|
|
64
|
+
catch { /* skip missing files */ }
|
|
65
|
+
}
|
|
66
|
+
return parts.join('\n\n');
|
|
67
|
+
}
|
|
68
|
+
function buildSystemPromptFor(kind) {
|
|
69
|
+
/* TODO(HITO-4): move these to prompts.yujin.app endpoints. */
|
|
70
|
+
const common = [
|
|
71
|
+
'You are Yujin Forge generating a foundational project document.',
|
|
72
|
+
'Read the supplied clarification rounds + workflow state and emit',
|
|
73
|
+
'a single, well-structured markdown document.',
|
|
74
|
+
'Output ASCII-only. Use sections + lists, NOT free prose.',
|
|
75
|
+
'Do not invent facts not present in the clarification rounds. If',
|
|
76
|
+
'something is missing, write "TBD: <what the user must define>".',
|
|
77
|
+
].join(' ');
|
|
78
|
+
switch (kind) {
|
|
79
|
+
case 'rfp':
|
|
80
|
+
return common + '\n\nDocument type: **RFP / PRD**. Structure:\n'
|
|
81
|
+
+ '1. Vision + objetivo del producto\n'
|
|
82
|
+
+ '2. Personas + user stories\n'
|
|
83
|
+
+ '3. Killer features + MVP slice\n'
|
|
84
|
+
+ '4. Bloques + orden\n'
|
|
85
|
+
+ '5. NFR cuantitativas (volumetria, paralelismo, complejidad)\n'
|
|
86
|
+
+ '6. NFR estructurales (persistencia, middleware, modelo objeto)\n'
|
|
87
|
+
+ '7. NFR de gobernanza (compliance, audit, retention)\n'
|
|
88
|
+
+ '8. NFR de operacion (i18n, a11y, monitoring, costos)\n'
|
|
89
|
+
+ '9. Acceptance criteria por bloque\n';
|
|
90
|
+
case 'arch':
|
|
91
|
+
return common + '\n\nDocument type: **Technological architecture**.\n'
|
|
92
|
+
+ 'Structure (driven by NFR decisions from clarification step 5+6+8):\n'
|
|
93
|
+
+ '1. Stack elegido + justificacion\n'
|
|
94
|
+
+ '2. Layering (frontend / backend / data / async)\n'
|
|
95
|
+
+ '3. Topologia de deployment (single instance / multi-region / serverless / edge)\n'
|
|
96
|
+
+ '4. Estrategia async (sync only / queue + workers / event bus / saga)\n'
|
|
97
|
+
+ '5. Persistence model + ERD inicial textual\n'
|
|
98
|
+
+ '6. Middleware stack (concretado del step 6)\n'
|
|
99
|
+
+ '7. Security model (auth, authz, encryption, secrets)\n'
|
|
100
|
+
+ '8. Observability (logs, metrics, traces, alertas del step 8)\n'
|
|
101
|
+
+ '9. Compliance hooks (per step 7 decisions)\n'
|
|
102
|
+
+ '10. Costos esperados (modelado de step 8)\n';
|
|
103
|
+
case 'design':
|
|
104
|
+
return common + '\n\nDocument type: **Solution design per block**.\n'
|
|
105
|
+
+ 'For each block in workflow.clarification.blocks, write a section with:\n'
|
|
106
|
+
+ '1. Data model (tables + relaciones + indices)\n'
|
|
107
|
+
+ '2. API contracts (endpoints + payloads + responses + errores)\n'
|
|
108
|
+
+ '3. Screens / pages (wireframes ascii o links a figma)\n'
|
|
109
|
+
+ '4. State machines (si aplica per step 5)\n'
|
|
110
|
+
+ '5. Sequence diagrams (las 2-3 secuencias mas complejas, textuales)\n'
|
|
111
|
+
+ '6. Edge cases identificados + estrategia\n'
|
|
112
|
+
+ '7. Test cases obligatorios (e2e + structural)\n'
|
|
113
|
+
+ '8. NAC-3 attributes (preview del manifest)\n';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function sha256(text) {
|
|
117
|
+
return createHash('sha256').update(text, 'utf-8').digest('hex');
|
|
118
|
+
}
|
|
119
|
+
async function runSpec(kind, opts) {
|
|
120
|
+
header('Yujin Forge -- spec ' + kind);
|
|
121
|
+
console.log('');
|
|
122
|
+
const projectRoot = opts.cwd ? path.resolve(opts.cwd) : process.cwd();
|
|
123
|
+
const wf = await readWorkflow(projectRoot);
|
|
124
|
+
/* Pre-requisites. */
|
|
125
|
+
const cl = wf.clarification;
|
|
126
|
+
if (!cl?.functional || !cl?.nfr_quantitative || !cl?.nfr_structural
|
|
127
|
+
|| !cl?.nfr_governance || !cl?.nfr_operational || !cl?.blocks) {
|
|
128
|
+
console.log(c.error('Clarification (Phase II) incompleta. Falta al menos una ronda.'));
|
|
129
|
+
console.log(c.dim('Corre: ') + c.code('yf clarify functional') + c.dim(' ... seguir hasta blocks.'));
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if ((kind === 'arch' || kind === 'design') && !wf.specs?.rfp) {
|
|
134
|
+
console.log(c.error('RFP debe estar generado primero.'));
|
|
135
|
+
console.log(c.dim('Corre: ') + c.code('yf spec rfp'));
|
|
136
|
+
process.exitCode = 1;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const existing = wf.specs?.[kind];
|
|
140
|
+
if (existing && !opts.yes) {
|
|
141
|
+
console.log(c.warn('Ya existe ') + c.brand(DOC_FILENAME[kind])
|
|
142
|
+
+ c.warn(' (version ' + existing.version + ').'));
|
|
143
|
+
console.log(c.dim('Para regenerar, corre con ') + c.code('--yes'));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
/* Build the context. */
|
|
147
|
+
const clarificationDump = await readAllClarification(projectRoot);
|
|
148
|
+
if (clarificationDump.trim() === '') {
|
|
149
|
+
console.log(c.error('No se encontraron docs en docs/clarification/. Re-corre las rondas.'));
|
|
150
|
+
process.exitCode = 1;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
/* If generating arch or design, also feed the RFP. */
|
|
154
|
+
let priorDocs = '';
|
|
155
|
+
if (kind === 'arch' || kind === 'design') {
|
|
156
|
+
try {
|
|
157
|
+
const rfpText = await fs.readFile(path.join(projectRoot, 'docs', wf.specs.rfp.doc_path.replace(/^docs\//, '')), 'utf-8');
|
|
158
|
+
priorDocs += '\n\n===== EXISTING RFP =====\n' + rfpText;
|
|
159
|
+
}
|
|
160
|
+
catch { /* may not exist if doc_path was relative differently */ }
|
|
161
|
+
}
|
|
162
|
+
if (kind === 'design' && wf.specs?.arch) {
|
|
163
|
+
try {
|
|
164
|
+
const archText = await fs.readFile(path.join(projectRoot, 'docs', wf.specs.arch.doc_path.replace(/^docs\//, '')), 'utf-8');
|
|
165
|
+
priorDocs += '\n\n===== EXISTING ARCHITECTURE =====\n' + archText;
|
|
166
|
+
}
|
|
167
|
+
catch { /* skip */ }
|
|
168
|
+
}
|
|
169
|
+
const userMessage = [
|
|
170
|
+
'Project root: ' + projectRoot,
|
|
171
|
+
'Tier: ' + (wf.tier ?? 'unknown'),
|
|
172
|
+
'Intent: ' + JSON.stringify(wf.intent ?? {}, null, 2),
|
|
173
|
+
'',
|
|
174
|
+
'===== CLARIFICATION ROUNDS =====',
|
|
175
|
+
clarificationDump,
|
|
176
|
+
priorDocs,
|
|
177
|
+
'',
|
|
178
|
+
'Generate the document now. Output the FULL markdown body only.',
|
|
179
|
+
'No preamble, no chatter, no closing remarks. Start with the first',
|
|
180
|
+
'H2 / heading and end with the last content line.',
|
|
181
|
+
].join('\n');
|
|
182
|
+
console.log(c.dim('Llamando Claude para generar ' + DOC_FILENAME[kind] + ' ...'));
|
|
183
|
+
console.log(c.dim('(prompt strategic asset; en HITO 4 esto se mueve a prompts.yujin.app)'));
|
|
184
|
+
console.log('');
|
|
185
|
+
const claude = new ClaudeClient();
|
|
186
|
+
let body;
|
|
187
|
+
try {
|
|
188
|
+
const resp = await claude.chat({
|
|
189
|
+
system: buildSystemPromptFor(kind),
|
|
190
|
+
messages: [{ role: 'user', content: userMessage }],
|
|
191
|
+
maxTokens: 8192,
|
|
192
|
+
});
|
|
193
|
+
body = resp.text.trim();
|
|
194
|
+
if (body === '')
|
|
195
|
+
throw new Error('Claude returned empty body');
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
console.error(c.error('Generacion fallo: ') + String(err instanceof Error ? err.message : err));
|
|
199
|
+
process.exitCode = 1;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const docsDir = path.join(projectRoot, 'docs');
|
|
203
|
+
await fs.mkdir(docsDir, { recursive: true });
|
|
204
|
+
const filePath = path.join(docsDir, DOC_FILENAME[kind]);
|
|
205
|
+
const previousVersion = existing?.version ?? 0;
|
|
206
|
+
const newVersion = previousVersion + 1;
|
|
207
|
+
const stamp = new Date().toISOString();
|
|
208
|
+
const header_md = '# ' + DOC_TITLE[kind] + ' -- ' + (wf.intent?.operation ?? 'project') + '\n\n'
|
|
209
|
+
+ '*Version ' + newVersion + ' generated by Yujin Forge on ' + stamp + '.*\n'
|
|
210
|
+
+ '*Tier: ' + wf.tier + '. To re-generate: `yf spec ' + kind + ' --yes`.*\n\n';
|
|
211
|
+
const full = header_md + body + '\n';
|
|
212
|
+
await fs.writeFile(filePath, full, 'utf-8');
|
|
213
|
+
const sha = sha256(full);
|
|
214
|
+
const relPath = path.relative(projectRoot, filePath);
|
|
215
|
+
await patchWorkflowGroup(projectRoot, 'specs', {
|
|
216
|
+
[kind]: {
|
|
217
|
+
done_at: stamp,
|
|
218
|
+
version: newVersion,
|
|
219
|
+
doc_path: relPath,
|
|
220
|
+
sha256: sha,
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
console.log(c.success('Generado: ') + c.brand(relPath) + c.dim(' (' + full.length + ' chars, sha256:' + sha.slice(0, 12) + '...)'));
|
|
224
|
+
console.log('');
|
|
225
|
+
switch (kind) {
|
|
226
|
+
case 'rfp':
|
|
227
|
+
console.log(c.dim('Siguiente: ') + c.code('yf spec arch'));
|
|
228
|
+
break;
|
|
229
|
+
case 'arch':
|
|
230
|
+
console.log(c.dim('Siguiente: ') + c.code('yf spec design'));
|
|
231
|
+
break;
|
|
232
|
+
case 'design':
|
|
233
|
+
console.log(c.dim('Phase III completa. Siguiente: ') + c.code('yf approve rfp arch design'));
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
export function registerSpecCommand(program) {
|
|
238
|
+
const spec = program.command('spec')
|
|
239
|
+
.description('Phase III steps 10-12: generate RFP + Architecture + Solution Design.');
|
|
240
|
+
for (const kind of ['rfp', 'arch', 'design']) {
|
|
241
|
+
spec.command(kind)
|
|
242
|
+
.description('Generate the ' + DOC_TITLE[kind] + ' doc into docs/' + DOC_FILENAME[kind])
|
|
243
|
+
.option('--cwd <path>', 'project root (default: current directory)')
|
|
244
|
+
.option('--yes', 'overwrite existing version')
|
|
245
|
+
.action(async (opts) => {
|
|
246
|
+
try {
|
|
247
|
+
await runSpec(kind, opts);
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
console.error(c.error(err instanceof Error ? err.message : String(err)));
|
|
251
|
+
process.exitCode = 1;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../../src/commands/spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yf coverage structural` -- Phase V step 15 acceptance gate.
|
|
3
|
+
*
|
|
4
|
+
* Checks that every NAC-3 manifest element is exercised by at
|
|
5
|
+
* least one e2e test. Required by SQ Sec 14 + PRODUCT_WORKFLOW
|
|
6
|
+
* step 15 for any block to enter "green" status.
|
|
7
|
+
*
|
|
8
|
+
* Strategy:
|
|
9
|
+
* 1. Read the manifest from src/nac/manifest.ts (parsed
|
|
10
|
+
* heuristically for element ids).
|
|
11
|
+
* 2. Scan tests/ for occurrences of each id (data-nac-id
|
|
12
|
+
* assertions, locator strings, etc).
|
|
13
|
+
* 3. Compute (covered ids) / (total ids) ratio.
|
|
14
|
+
* 4. Exit 0 iff coverage === 100%; exit 1 otherwise so CI
|
|
15
|
+
* can gate on it.
|
|
16
|
+
*
|
|
17
|
+
* Pure read-only. Output: counts + missing ids. Optional
|
|
18
|
+
* --if-failing-exit-1 flag so CI fails the job (default true).
|
|
19
|
+
*
|
|
20
|
+
* ASCII-only.
|
|
21
|
+
*/
|
|
22
|
+
import type { Command } from 'commander';
|
|
23
|
+
export interface CoverageOptions {
|
|
24
|
+
cwd?: string;
|
|
25
|
+
ifFailingExit1?: boolean;
|
|
26
|
+
manifest?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function runCoverage(opts: CoverageOptions): Promise<void>;
|
|
29
|
+
export declare function registerCoverageCommand(program: Command): void;
|
|
30
|
+
//# sourceMappingURL=workflow-coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-coverage.d.ts","sourceRoot":"","sources":["../../src/commands/workflow-coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAoCD,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAwDtE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAa9D"}
|