@codeyam/codeyam-cli 0.1.18 → 0.1.19
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/analyzer-template/.build-info.json +6 -6
- package/analyzer-template/log.txt +3 -3
- package/codeyam-cli/src/cli.js +15 -0
- package/codeyam-cli/src/cli.js.map +1 -1
- package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js +9 -9
- package/codeyam-cli/src/commands/editor.js +334 -254
- package/codeyam-cli/src/commands/editor.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorGuardMiddleware.test.js +67 -0
- package/codeyam-cli/src/utils/__tests__/editorGuardMiddleware.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js +16 -1
- package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js.map +1 -1
- package/codeyam-cli/src/utils/editorGuard.js +36 -0
- package/codeyam-cli/src/utils/editorGuard.js.map +1 -0
- package/codeyam-cli/src/utils/editorScenarios.js +1 -1
- package/codeyam-cli/src/utils/simulationGateMiddleware.js +9 -0
- package/codeyam-cli/src/utils/simulationGateMiddleware.js.map +1 -1
- package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js +17 -6
- package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js.map +1 -1
- package/codeyam-cli/src/webserver/__tests__/stripClaudeCommand.test.js +79 -0
- package/codeyam-cli/src/webserver/__tests__/stripClaudeCommand.test.js.map +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{editor.entity.(_sha)-Bnx7yUP0.js → editor.entity.(_sha)-CGzKlIHg.js} +13 -13
- package/codeyam-cli/src/webserver/build/client/assets/globals-Yn9W3zp3.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{manifest-b9d4d267.js → manifest-2ef99f38.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{root-DB3O9_9j.js → root-BxUQigda.js} +5 -5
- package/codeyam-cli/src/webserver/build/server/assets/{analysisRunner-CGwTN3V2.js → analysisRunner-BPmOG9bE.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{index-D4meMKy3.js → index-Cd-ufawF.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{init-odGJ_c2-.js → init-CzeBGOto.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{server-build-TmPfF7pT.js → server-build-Dht7CKXY.js} +102 -102
- package/codeyam-cli/src/webserver/build/server/index.js +1 -1
- package/codeyam-cli/src/webserver/build-info.json +5 -5
- package/codeyam-cli/src/webserver/terminalServer.js +85 -19
- package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
- package/codeyam-cli/templates/__tests__/editor-step-hook.prompt-capture.test.ts +118 -0
- package/codeyam-cli/templates/codeyam-editor-claude.md +2 -0
- package/codeyam-cli/templates/codeyam-editor-reference.md +1 -1
- package/codeyam-cli/templates/editor-step-hook.py +72 -46
- package/package.json +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-fAqOD9ex.css +0 -1
|
@@ -16,7 +16,7 @@ import { APP_FORMATS, TECH_STACKS } from "../data/techStacks.js";
|
|
|
16
16
|
import { getProjectRoot as getStateProjectRoot } from "../state.js";
|
|
17
17
|
import initCommand from "./init.js";
|
|
18
18
|
import { scanScenarioFiles, syncScenarioFilesToDatabase, backfillScenarioMetadata, migrateScenarioFormats, } from "../utils/scenariosManifest.js";
|
|
19
|
-
import { clearEditorState,
|
|
19
|
+
import { clearEditorState, validateStepTransition, backfillEntityShaOnScenarios, } from "../utils/editorScenarios.js";
|
|
20
20
|
import { validateSeedData, detectSeedAdapter, validateSeedKeysAgainstPrisma, } from "../utils/editorSeedAdapter.js";
|
|
21
21
|
import { deleteScenarioViaCli } from "../utils/editorDeleteScenario.js";
|
|
22
22
|
import { buildEditorApiRequest, callEditorApi, EDITOR_API_SUBCOMMANDS, } from "../utils/editorApi.js";
|
|
@@ -27,21 +27,23 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
27
27
|
const __dirname = path.dirname(__filename);
|
|
28
28
|
const STEP_LABELS = {
|
|
29
29
|
1: 'Plan',
|
|
30
|
-
2: '
|
|
31
|
-
3: '
|
|
32
|
-
4: '
|
|
33
|
-
5: '
|
|
34
|
-
6: '
|
|
35
|
-
7: '
|
|
36
|
-
8: '
|
|
37
|
-
9: '
|
|
38
|
-
10: '
|
|
39
|
-
11: '
|
|
40
|
-
12: '
|
|
41
|
-
13: '
|
|
42
|
-
14: '
|
|
43
|
-
15: '
|
|
44
|
-
16: '
|
|
30
|
+
2: 'Prepare',
|
|
31
|
+
3: 'Prototype',
|
|
32
|
+
4: 'Verify Prototype',
|
|
33
|
+
5: 'Confirm',
|
|
34
|
+
6: 'Deconstruct',
|
|
35
|
+
7: 'Extract',
|
|
36
|
+
8: 'Glossary',
|
|
37
|
+
9: 'Analyze',
|
|
38
|
+
10: 'App Scenarios',
|
|
39
|
+
11: 'User Scenarios',
|
|
40
|
+
12: 'Verify',
|
|
41
|
+
13: 'Journal',
|
|
42
|
+
14: 'Review',
|
|
43
|
+
15: 'Present',
|
|
44
|
+
16: 'Commit',
|
|
45
|
+
17: 'Finalize',
|
|
46
|
+
18: 'Push',
|
|
45
47
|
};
|
|
46
48
|
const MIGRATION_STEP_LABELS = {
|
|
47
49
|
1: 'Survey',
|
|
@@ -122,8 +124,9 @@ function writeState(root, state) {
|
|
|
122
124
|
}
|
|
123
125
|
/**
|
|
124
126
|
* Clear the editor state (for starting a new feature).
|
|
125
|
-
* Does NOT clear the user prompt file —
|
|
126
|
-
*
|
|
127
|
+
* Does NOT clear the user prompt file — the prompt is cleared
|
|
128
|
+
* by the journal API after recording, and the hook captures
|
|
129
|
+
* a fresh prompt for the next feature on UserPromptSubmit.
|
|
127
130
|
*/
|
|
128
131
|
function clearState(root) {
|
|
129
132
|
clearEditorState(root);
|
|
@@ -208,8 +211,9 @@ function printAppScenarioInstructions(pageName, route) {
|
|
|
208
211
|
const root = process.cwd();
|
|
209
212
|
const hasSeedAdapter = !!detectSeedAdapter(root);
|
|
210
213
|
checkbox('Check existing scenarios: `codeyam editor scenarios`');
|
|
211
|
-
console.log(chalk.dim(' Review existing scenarios —
|
|
212
|
-
console.log(chalk.dim('
|
|
214
|
+
console.log(chalk.dim(' Review existing scenarios — enhance their seed data to exercise new features.'));
|
|
215
|
+
console.log(chalk.dim(' A rich scenario that exercises 5 features is better than 5 thin scenarios with one feature each.'));
|
|
216
|
+
console.log(chalk.dim(' Rename scenarios if their data scope has grown beyond the original name.'));
|
|
213
217
|
console.log();
|
|
214
218
|
console.log(chalk.bold.yellow('App scenarios vs component scenarios — these are DIFFERENT:'));
|
|
215
219
|
console.log(chalk.yellow(' App scenarios: show the FULL PAGE with seeded data at a real route (/, /library, etc.)'));
|
|
@@ -305,7 +309,7 @@ function printExtractionPlanInstructions() {
|
|
|
305
309
|
console.log(chalk.yellow(' — Where it currently lives (source file + approximate lines)'));
|
|
306
310
|
console.log(chalk.yellow(' — Where it will go (new file path)'));
|
|
307
311
|
console.log();
|
|
308
|
-
console.log(chalk.dim('Present the numbered plan, then proceed to step
|
|
312
|
+
console.log(chalk.dim('Present the numbered plan, then proceed to step 7 to execute it.'));
|
|
309
313
|
}
|
|
310
314
|
/**
|
|
311
315
|
* Shared component capture instructions used by editor Step 7 and migration Steps 3/8.
|
|
@@ -362,13 +366,13 @@ function stepHeader(step, title, feature) {
|
|
|
362
366
|
console.log();
|
|
363
367
|
}
|
|
364
368
|
/**
|
|
365
|
-
* Print a colored progress tracker showing all
|
|
369
|
+
* Print a colored progress tracker showing all 18 steps.
|
|
366
370
|
* Steps before `current` are green ✓, `current` is bold cyan →, future steps are dim ○.
|
|
367
371
|
*/
|
|
368
372
|
function printProgressTracker(current) {
|
|
369
373
|
console.log();
|
|
370
374
|
console.log(chalk.dim(' ┌─────────────────────────────────────┐'));
|
|
371
|
-
for (let i = 1; i <=
|
|
375
|
+
for (let i = 1; i <= 18; i++) {
|
|
372
376
|
const label = STEP_LABELS[i];
|
|
373
377
|
const num = i < 10 ? ` ${i}` : `${i}`;
|
|
374
378
|
const content = `${num}. ${label.padEnd(28)}`;
|
|
@@ -406,13 +410,13 @@ function stopGate(current, opts) {
|
|
|
406
410
|
console.log(chalk.yellow('For the CURRENT step (→), show each checklist item with ✓ (done) or ✗ (skipped + reason).'));
|
|
407
411
|
console.log(chalk.yellow('If any items are ✗, explain why and ask if the user wants to address them.'));
|
|
408
412
|
console.log();
|
|
409
|
-
if (current <
|
|
413
|
+
if (current < 18) {
|
|
410
414
|
console.log(chalk.green('When done, run: ') +
|
|
411
415
|
chalk.bold(`codeyam editor ${current + 1}`));
|
|
412
416
|
}
|
|
413
417
|
else {
|
|
414
418
|
console.log(chalk.green('Feature complete! Run: ') +
|
|
415
|
-
chalk.bold('codeyam editor
|
|
419
|
+
chalk.bold('codeyam editor steps') +
|
|
416
420
|
chalk.green(' to start the next feature'));
|
|
417
421
|
}
|
|
418
422
|
console.log();
|
|
@@ -428,34 +432,36 @@ function printResumptionHeader(step) {
|
|
|
428
432
|
'Check if plan was already written to context file:\n `cat .codeyam/editor-mode-context.md`',
|
|
429
433
|
],
|
|
430
434
|
2: ['Check if project files already exist:\n `ls package.json src/`'],
|
|
431
|
-
3: ['
|
|
432
|
-
4: [
|
|
435
|
+
3: ['Re-check is safe — just re-run the step'],
|
|
436
|
+
4: ['Re-verify is safe to repeat — just re-run the checks'],
|
|
437
|
+
5: ['This is a confirmation step — just re-present to user'],
|
|
438
|
+
6: [
|
|
433
439
|
'Check if extraction plan already exists in context file:\n `cat .codeyam/editor-mode-context.md`',
|
|
434
440
|
],
|
|
435
|
-
|
|
441
|
+
7: [
|
|
436
442
|
'Check if components/functions already extracted:\n `ls src/components/ src/lib/`',
|
|
437
443
|
],
|
|
438
|
-
|
|
444
|
+
8: [
|
|
439
445
|
'Check if glossary already populated:\n `cat .codeyam/glossary.json`',
|
|
440
446
|
],
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
447
|
+
9: ['Check if isolation routes and registered scenarios already exist'],
|
|
448
|
+
10: ['Check existing scenarios:\n `codeyam editor scenarios`'],
|
|
449
|
+
11: [
|
|
444
450
|
'Check existing user-persona scenarios:\n `codeyam editor scenarios`',
|
|
445
451
|
],
|
|
446
|
-
|
|
447
|
-
|
|
452
|
+
12: ['Re-verify is safe to repeat — just re-run the checks'],
|
|
453
|
+
13: [
|
|
448
454
|
'Check if a journal entry already exists for this feature:\n `codeyam editor journal-list`',
|
|
449
455
|
'If an entry exists, use PATCH to update it — do NOT create a new one',
|
|
450
456
|
],
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
457
|
+
14: ['Re-verify is safe to repeat — just re-run the checks'],
|
|
458
|
+
15: ['Check if commit already made:\n `git log --oneline -3`'],
|
|
459
|
+
16: ['Check if commit already made:\n `git log --oneline -3`'],
|
|
460
|
+
17: [
|
|
455
461
|
'Check if journal was already updated with commit SHA:\n `codeyam editor journal-list`',
|
|
456
462
|
'Check if commit was already amended:\n `git log --oneline -3`',
|
|
457
463
|
],
|
|
458
|
-
|
|
464
|
+
18: [
|
|
459
465
|
'Check if already pushed:\n `git remote -v && git log --oneline origin/HEAD..HEAD 2>/dev/null`',
|
|
460
466
|
],
|
|
461
467
|
};
|
|
@@ -562,7 +568,7 @@ function parseDebugTargets(target) {
|
|
|
562
568
|
}
|
|
563
569
|
if (entry.startsWith('step-')) {
|
|
564
570
|
const num = parseInt(entry.replace('step-', ''), 10);
|
|
565
|
-
if (!isNaN(num) && num >= 1 && num <=
|
|
571
|
+
if (!isNaN(num) && num >= 1 && num <= 18) {
|
|
566
572
|
valid.add(`step-${num}`);
|
|
567
573
|
continue;
|
|
568
574
|
}
|
|
@@ -788,24 +794,26 @@ function printCycleOverview(root, state) {
|
|
|
788
794
|
console.log(chalk.yellow('This applies even after committing — always use the change workflow.'));
|
|
789
795
|
}
|
|
790
796
|
else {
|
|
791
|
-
console.log('Each feature follows
|
|
797
|
+
console.log('Each feature follows 18 steps. You MUST run each command in order:');
|
|
792
798
|
console.log();
|
|
793
|
-
console.log(` ${chalk.bold.yellow(' 1')} ${chalk.bold('Plan')}
|
|
794
|
-
console.log(` ${chalk.bold.yellow(' 2')} ${chalk.bold('
|
|
795
|
-
console.log(` ${chalk.bold.yellow(' 3')} ${chalk.bold('
|
|
796
|
-
console.log(` ${chalk.bold.yellow(' 4')} ${chalk.bold('
|
|
797
|
-
console.log(` ${chalk.bold.yellow(' 5')} ${chalk.bold('
|
|
798
|
-
console.log(` ${chalk.bold.yellow(' 6')} ${chalk.bold('
|
|
799
|
-
console.log(` ${chalk.bold.yellow(' 7')} ${chalk.bold('
|
|
800
|
-
console.log(` ${chalk.bold.yellow(' 8')} ${chalk.bold('
|
|
801
|
-
console.log(` ${chalk.bold.yellow(' 9')} ${chalk.bold('
|
|
802
|
-
console.log(` ${chalk.bold.yellow('10')} ${chalk.bold('
|
|
803
|
-
console.log(` ${chalk.bold.yellow('11')} ${chalk.bold('
|
|
804
|
-
console.log(` ${chalk.bold.yellow('12')} ${chalk.bold('
|
|
805
|
-
console.log(` ${chalk.bold.yellow('13')} ${chalk.bold('
|
|
806
|
-
console.log(` ${chalk.bold.yellow('14')} ${chalk.bold('
|
|
807
|
-
console.log(` ${chalk.bold.yellow('15')} ${chalk.bold('
|
|
808
|
-
console.log(` ${chalk.bold.yellow('16')} ${chalk.bold('
|
|
799
|
+
console.log(` ${chalk.bold.yellow(' 1')} ${chalk.bold('Plan')} — Plan the feature, confirm with user`);
|
|
800
|
+
console.log(` ${chalk.bold.yellow(' 2')} ${chalk.bold('Prepare')} — Set up project and dependencies`);
|
|
801
|
+
console.log(` ${chalk.bold.yellow(' 3')} ${chalk.bold('Prototype')} — Build a working prototype fast`);
|
|
802
|
+
console.log(` ${chalk.bold.yellow(' 4')} ${chalk.bold('Verify Prototype')} — Verify prototype works correctly`);
|
|
803
|
+
console.log(` ${chalk.bold.yellow(' 5')} ${chalk.bold('Confirm')} — Confirm prototype with user`);
|
|
804
|
+
console.log(` ${chalk.bold.yellow(' 6')} ${chalk.bold('Deconstruct')} — Read code, plan all extractions`);
|
|
805
|
+
console.log(` ${chalk.bold.yellow(' 7')} ${chalk.bold('Extract')} — TDD extraction of functions + components`);
|
|
806
|
+
console.log(` ${chalk.bold.yellow(' 8')} ${chalk.bold('Glossary')} — Record functions in glossary`);
|
|
807
|
+
console.log(` ${chalk.bold.yellow(' 9')} ${chalk.bold('Analyze')} — Analyze and verify components`);
|
|
808
|
+
console.log(` ${chalk.bold.yellow('10')} ${chalk.bold('App Scenarios')} — Create app-level scenarios`);
|
|
809
|
+
console.log(` ${chalk.bold.yellow('11')} ${chalk.bold('User Scenarios')} — Create user-persona scenarios`);
|
|
810
|
+
console.log(` ${chalk.bold.yellow('12')} ${chalk.bold('Verify')} — Review screenshots, check for errors`);
|
|
811
|
+
console.log(` ${chalk.bold.yellow('13')} ${chalk.bold('Journal')} — Create/update journal entry`);
|
|
812
|
+
console.log(` ${chalk.bold.yellow('14')} ${chalk.bold('Review')} — Verify screenshots and audit`);
|
|
813
|
+
console.log(` ${chalk.bold.yellow('15')} ${chalk.bold('Present')} — Present summary, get approval`);
|
|
814
|
+
console.log(` ${chalk.bold.yellow('16')} ${chalk.bold('Commit')} — Commit all changes`);
|
|
815
|
+
console.log(` ${chalk.bold.yellow('17')} ${chalk.bold('Finalize')} — Journal update + amend commit`);
|
|
816
|
+
console.log(` ${chalk.bold.yellow('18')} ${chalk.bold('Push')} — Push to remote`);
|
|
809
817
|
console.log();
|
|
810
818
|
console.log(chalk.green('Start now: ') + chalk.bold('codeyam editor 1'));
|
|
811
819
|
console.log(chalk.dim(' If the user already described what they want, pass it: codeyam editor 1 --prompt "their message"'));
|
|
@@ -897,7 +905,7 @@ function printStep1(root, feature, options, userPrompt) {
|
|
|
897
905
|
console.log(chalk.dim(' Replace "Feature Name" with a short title for what you just described.'));
|
|
898
906
|
console.log();
|
|
899
907
|
}
|
|
900
|
-
// ─── Step 2:
|
|
908
|
+
// ─── Step 2: Prepare ──────────────────────────────────────────────────
|
|
901
909
|
function printStep2(root, feature) {
|
|
902
910
|
const port = getServerPort();
|
|
903
911
|
const { defaultName: dim, names: dimNames } = getProjectDimensions(root);
|
|
@@ -914,12 +922,19 @@ function printStep2(root, feature) {
|
|
|
914
922
|
appFormats: prevState?.appFormats,
|
|
915
923
|
techStackId: prevState?.techStackId,
|
|
916
924
|
});
|
|
917
|
-
logEvent(root, 'step', { step: 2, label: '
|
|
918
|
-
stepHeader(2, '
|
|
925
|
+
logEvent(root, 'step', { step: 2, label: 'Prepare', feature });
|
|
926
|
+
stepHeader(2, 'Prepare', feature);
|
|
919
927
|
if (isResuming) {
|
|
920
928
|
printResumptionHeader(2);
|
|
921
929
|
}
|
|
922
|
-
console.log('
|
|
930
|
+
console.log(chalk.bold.red('━━━ MANDATORY: CREATE TASK NOW ━━━'));
|
|
931
|
+
console.log();
|
|
932
|
+
console.log(chalk.red(`Run TaskCreate with title: "Use \`codeyam editor\` to work on ${feature}"`));
|
|
933
|
+
console.log(chalk.red('DO NOT read files, scaffold, write code, or do ANYTHING else until this task exists.'));
|
|
934
|
+
console.log(chalk.red('This is not optional. Create the task, then continue below.'));
|
|
935
|
+
console.log(chalk.bold.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
936
|
+
console.log();
|
|
937
|
+
console.log('Get the project ready to build.');
|
|
923
938
|
console.log();
|
|
924
939
|
// If no project exists yet, include scaffolding instructions first
|
|
925
940
|
if (!projectExists) {
|
|
@@ -948,7 +963,6 @@ function printStep2(root, feature) {
|
|
|
948
963
|
console.log(chalk.dim(' Key: import { prisma } from "@/app/lib/prisma" in API routes.'));
|
|
949
964
|
console.log(chalk.dim(' Key: Seed scripts must use the adapter pattern (see prisma/seed.ts).'));
|
|
950
965
|
console.log();
|
|
951
|
-
console.log(chalk.bold('Build the feature:'));
|
|
952
966
|
}
|
|
953
967
|
else {
|
|
954
968
|
console.log(chalk.bold('Prepare the database for this feature:'));
|
|
@@ -964,6 +978,32 @@ function printStep2(root, feature) {
|
|
|
964
978
|
console.log(chalk.dim(' If no existing scenario fits, use the default seed: npm run db:seed'));
|
|
965
979
|
console.log();
|
|
966
980
|
}
|
|
981
|
+
stopGate(2);
|
|
982
|
+
}
|
|
983
|
+
// ─── Step 3: Prototype ────────────────────────────────────────────────
|
|
984
|
+
function printStep3(root, feature) {
|
|
985
|
+
const port = getServerPort();
|
|
986
|
+
const { defaultName: dim, names: dimNames } = getProjectDimensions(root);
|
|
987
|
+
const projectExists = hasProject(root);
|
|
988
|
+
const prevState = readState(root);
|
|
989
|
+
const isResuming = prevState?.step === 3;
|
|
990
|
+
const now = new Date().toISOString();
|
|
991
|
+
writeState(root, {
|
|
992
|
+
feature,
|
|
993
|
+
step: 3,
|
|
994
|
+
label: STEP_LABELS[3],
|
|
995
|
+
startedAt: isResuming ? prevState.startedAt : now,
|
|
996
|
+
featureStartedAt: prevState?.featureStartedAt || now,
|
|
997
|
+
appFormats: prevState?.appFormats,
|
|
998
|
+
techStackId: prevState?.techStackId,
|
|
999
|
+
});
|
|
1000
|
+
logEvent(root, 'step', { step: 3, label: 'Prototype', feature });
|
|
1001
|
+
stepHeader(3, 'Prototype', feature);
|
|
1002
|
+
if (isResuming) {
|
|
1003
|
+
printResumptionHeader(3);
|
|
1004
|
+
}
|
|
1005
|
+
console.log('Build fast with real data. Prioritize speed over quality.');
|
|
1006
|
+
console.log();
|
|
967
1007
|
console.log(chalk.bold('Checklist:'));
|
|
968
1008
|
checkbox('Create API routes that read from the database via Prisma');
|
|
969
1009
|
if (!projectExists) {
|
|
@@ -1012,6 +1052,28 @@ function printStep2(root, feature) {
|
|
|
1012
1052
|
console.log(chalk.cyan(` codeyam editor preview '{"path":"/drinks/1","dimension":"${dim}"}'`));
|
|
1013
1053
|
printDimensionGuidance(dim, dimNames);
|
|
1014
1054
|
console.log();
|
|
1055
|
+
stopGate(3);
|
|
1056
|
+
}
|
|
1057
|
+
// ─── Step 4: Verify Prototype ─────────────────────────────────────────
|
|
1058
|
+
function printStep4(root, feature) {
|
|
1059
|
+
const { defaultName: dim, names: dimNames } = getProjectDimensions(root);
|
|
1060
|
+
const prevState = readState(root);
|
|
1061
|
+
const isResuming = prevState?.step === 4;
|
|
1062
|
+
const now = new Date().toISOString();
|
|
1063
|
+
writeState(root, {
|
|
1064
|
+
feature,
|
|
1065
|
+
step: 4,
|
|
1066
|
+
label: STEP_LABELS[4],
|
|
1067
|
+
startedAt: isResuming ? prevState.startedAt : now,
|
|
1068
|
+
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1069
|
+
});
|
|
1070
|
+
logEvent(root, 'step', { step: 4, label: 'Verify Prototype', feature });
|
|
1071
|
+
stepHeader(4, 'Verify Prototype', feature);
|
|
1072
|
+
if (isResuming) {
|
|
1073
|
+
printResumptionHeader(4);
|
|
1074
|
+
}
|
|
1075
|
+
console.log('Verify everything works before presenting the prototype.');
|
|
1076
|
+
console.log();
|
|
1015
1077
|
console.log(chalk.bold('Verify the dev server:'));
|
|
1016
1078
|
console.log(chalk.dim(` # Get dev server URL: codeyam editor dev-server`));
|
|
1017
1079
|
console.log(chalk.dim(' # Check page loads: curl -s -o /dev/null -w "%{http_code}" http://localhost:<dev-port>'));
|
|
@@ -1038,26 +1100,26 @@ function printStep2(root, feature) {
|
|
|
1038
1100
|
console.log(chalk.dim(' A new clone should work with just: git clone → npm run setup → npm run dev'));
|
|
1039
1101
|
console.log();
|
|
1040
1102
|
console.log(chalk.dim('Focus on building the prototype. Scenarios and refactoring happen in later steps.'));
|
|
1041
|
-
stopGate(
|
|
1103
|
+
stopGate(4);
|
|
1042
1104
|
}
|
|
1043
|
-
// ─── Step
|
|
1044
|
-
function
|
|
1105
|
+
// ─── Step 5: Confirm ──────────────────────────────────────────────────
|
|
1106
|
+
function printStep5(root, feature) {
|
|
1045
1107
|
const port = getServerPort();
|
|
1046
1108
|
const { defaultName: dim, names: dimNames } = getProjectDimensions(root);
|
|
1047
1109
|
const prevState = readState(root);
|
|
1048
|
-
const isResuming = prevState?.step ===
|
|
1110
|
+
const isResuming = prevState?.step === 5;
|
|
1049
1111
|
const now = new Date().toISOString();
|
|
1050
1112
|
writeState(root, {
|
|
1051
1113
|
feature,
|
|
1052
|
-
step:
|
|
1053
|
-
label: STEP_LABELS[
|
|
1114
|
+
step: 5,
|
|
1115
|
+
label: STEP_LABELS[5],
|
|
1054
1116
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1055
1117
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1056
1118
|
});
|
|
1057
|
-
logEvent(root, 'step', { step:
|
|
1058
|
-
stepHeader(
|
|
1119
|
+
logEvent(root, 'step', { step: 5, label: 'Confirm', feature });
|
|
1120
|
+
stepHeader(5, 'Confirm', feature);
|
|
1059
1121
|
if (isResuming) {
|
|
1060
|
-
printResumptionHeader(
|
|
1122
|
+
printResumptionHeader(5);
|
|
1061
1123
|
}
|
|
1062
1124
|
console.log('Summarize what was built and get user confirmation.');
|
|
1063
1125
|
console.log();
|
|
@@ -1074,6 +1136,11 @@ function printStep3(root, feature) {
|
|
|
1074
1136
|
console.log(chalk.dim(' If there are errors, fix the underlying issue before presenting.'));
|
|
1075
1137
|
checkbox('Verify `hasContent=true` and `liveErrors=0` — do NOT ask the user to confirm if the preview is broken');
|
|
1076
1138
|
console.log();
|
|
1139
|
+
console.log(chalk.bold('Verify the captured user prompt:'));
|
|
1140
|
+
checkbox("Read `.codeyam/editor-user-prompt.txt` — this is the user's original feature request");
|
|
1141
|
+
checkbox('If the file is missing or does not match what the user actually asked for, write the correct prompt text to `.codeyam/editor-user-prompt.txt`');
|
|
1142
|
+
console.log(chalk.dim(" This must be the user's exact words, not a summary. It gets recorded in the journal."));
|
|
1143
|
+
console.log();
|
|
1077
1144
|
console.log(chalk.bold('Then present to the user:'));
|
|
1078
1145
|
checkbox('Summarize what was built (routes, components, data)');
|
|
1079
1146
|
checkbox(`Navigate the preview to the feature's primary page: \`codeyam editor preview '{"path":"/your-page","dimension":"${dim}"}'\``);
|
|
@@ -1087,62 +1154,62 @@ function printStep3(root, feature) {
|
|
|
1087
1154
|
checkbox('Ask the user: "Does everything work as expected?"');
|
|
1088
1155
|
console.log();
|
|
1089
1156
|
console.log(chalk.bold('Present a selection menu to the user (use AskUserQuestion with these EXACT option labels):'));
|
|
1090
|
-
console.log(chalk.green(' Option 1 label: "The live preview is displaying what I expected"') + chalk.dim(' — proceed to step
|
|
1157
|
+
console.log(chalk.green(' Option 1 label: "The live preview is displaying what I expected"') + chalk.dim(' — proceed to step 6'));
|
|
1091
1158
|
console.log(chalk.yellow(' Option 2 label: "I\'d like some changes"') +
|
|
1092
|
-
chalk.dim(' — make changes, refresh preview, re-run `codeyam editor
|
|
1159
|
+
chalk.dim(' — make changes, refresh preview, re-run `codeyam editor 5`'));
|
|
1093
1160
|
console.log();
|
|
1094
1161
|
console.log(chalk.dim('Wait for user approval before moving on. Refactoring and scenarios happen in later steps.'));
|
|
1095
|
-
stopGate(
|
|
1162
|
+
stopGate(5, { confirm: true });
|
|
1096
1163
|
}
|
|
1097
|
-
// ─── Step
|
|
1098
|
-
function
|
|
1164
|
+
// ─── Step 6: Deconstruct ──────────────────────────────────────────────
|
|
1165
|
+
function printStep6(root, feature) {
|
|
1099
1166
|
const prevState = readState(root);
|
|
1100
|
-
const isResuming = prevState?.step ===
|
|
1167
|
+
const isResuming = prevState?.step === 6;
|
|
1101
1168
|
const now = new Date().toISOString();
|
|
1102
1169
|
writeState(root, {
|
|
1103
1170
|
feature,
|
|
1104
|
-
step:
|
|
1105
|
-
label: STEP_LABELS[
|
|
1171
|
+
step: 6,
|
|
1172
|
+
label: STEP_LABELS[6],
|
|
1106
1173
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1107
1174
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1108
1175
|
});
|
|
1109
|
-
logEvent(root, 'step', { step:
|
|
1110
|
-
stepHeader(
|
|
1176
|
+
logEvent(root, 'step', { step: 6, label: 'Deconstruct', feature });
|
|
1177
|
+
stepHeader(6, 'Deconstruct', feature);
|
|
1111
1178
|
if (isResuming) {
|
|
1112
|
-
printResumptionHeader(
|
|
1179
|
+
printResumptionHeader(6);
|
|
1113
1180
|
}
|
|
1114
1181
|
console.log(chalk.bold('Goal: pages contain ONLY components. Components contain ONLY sub-components.'));
|
|
1115
|
-
console.log(chalk.yellow('This step is read and plan only. Code extraction happens in step
|
|
1182
|
+
console.log(chalk.yellow('This step is read and plan only. Code extraction happens in step 7.'));
|
|
1116
1183
|
console.log();
|
|
1117
1184
|
printExtractionPlanInstructions();
|
|
1118
|
-
stopGate(
|
|
1185
|
+
stopGate(6);
|
|
1119
1186
|
}
|
|
1120
|
-
// ─── Step
|
|
1121
|
-
function
|
|
1187
|
+
// ─── Step 7: Extract ──────────────────────────────────────────────────
|
|
1188
|
+
function printStep7(root, feature) {
|
|
1122
1189
|
const port = getServerPort();
|
|
1123
1190
|
const { defaultName: dim, names: dimNames } = getProjectDimensions(root);
|
|
1124
1191
|
const prevState = readState(root);
|
|
1125
|
-
const isResuming = prevState?.step ===
|
|
1192
|
+
const isResuming = prevState?.step === 7;
|
|
1126
1193
|
const now = new Date().toISOString();
|
|
1127
1194
|
writeState(root, {
|
|
1128
1195
|
feature,
|
|
1129
|
-
step:
|
|
1130
|
-
label: STEP_LABELS[
|
|
1196
|
+
step: 7,
|
|
1197
|
+
label: STEP_LABELS[7],
|
|
1131
1198
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1132
1199
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1133
1200
|
});
|
|
1134
|
-
logEvent(root, 'step', { step:
|
|
1135
|
-
stepHeader(
|
|
1201
|
+
logEvent(root, 'step', { step: 7, label: 'Extract', feature });
|
|
1202
|
+
stepHeader(7, 'Extract', feature);
|
|
1136
1203
|
if (isResuming) {
|
|
1137
|
-
printResumptionHeader(
|
|
1204
|
+
printResumptionHeader(7);
|
|
1138
1205
|
}
|
|
1139
|
-
console.log('Execute your extraction plan from step
|
|
1206
|
+
console.log('Execute your extraction plan from step 6.');
|
|
1140
1207
|
console.log();
|
|
1141
1208
|
console.log(chalk.bold('Components:'));
|
|
1142
1209
|
checkbox('Extract each component from your plan into its own file');
|
|
1143
1210
|
checkbox('Page/route files must contain ZERO direct JSX — only imported components');
|
|
1144
1211
|
checkbox('Every component that renders multiple sections must be split into sub-components');
|
|
1145
|
-
console.log(chalk.dim(' No tests needed — visual verification happens in step
|
|
1212
|
+
console.log(chalk.dim(' No tests needed — visual verification happens in step 9'));
|
|
1146
1213
|
console.log();
|
|
1147
1214
|
console.log(chalk.bold('Library functions AND hooks (TDD):'));
|
|
1148
1215
|
checkbox('For each function/hook: write MULTIPLE failing tests FIRST, then extract to make them pass');
|
|
@@ -1150,7 +1217,7 @@ function printStep5(root, feature) {
|
|
|
1150
1217
|
console.log(chalk.dim(' Aim for 3-8 test cases per function depending on complexity'));
|
|
1151
1218
|
console.log(chalk.dim(' Hooks count as functions — useDrinks, useAuth, etc. all need test files'));
|
|
1152
1219
|
checkbox('Place test files next to source: `app/lib/drinks.ts` → `app/lib/drinks.test.ts`');
|
|
1153
|
-
console.log(chalk.yellow(' Tests ARE the only coverage for library functions/hooks — step
|
|
1220
|
+
console.log(chalk.yellow(' Tests ARE the only coverage for library functions/hooks — step 9 only captures component screenshots.'));
|
|
1154
1221
|
console.log();
|
|
1155
1222
|
console.log(chalk.bold('Recursive pass:'));
|
|
1156
1223
|
checkbox('Re-read EVERY new file you just created — extract components from components, functions from functions');
|
|
@@ -1168,55 +1235,55 @@ function printStep5(root, feature) {
|
|
|
1168
1235
|
console.log(chalk.dim('Reuse glossary functions when they fit naturally. Extract a new function when the use case diverges.'));
|
|
1169
1236
|
console.log();
|
|
1170
1237
|
console.log(chalk.dim('Focus on TDD for functions and extraction for components. Scenarios come in later steps.'));
|
|
1171
|
-
stopGate(
|
|
1238
|
+
stopGate(7);
|
|
1172
1239
|
}
|
|
1173
|
-
// ─── Step
|
|
1174
|
-
function
|
|
1240
|
+
// ─── Step 8: Glossary ─────────────────────────────────────────────────
|
|
1241
|
+
function printStep8(root, feature) {
|
|
1175
1242
|
const prevState = readState(root);
|
|
1176
|
-
const isResuming = prevState?.step ===
|
|
1243
|
+
const isResuming = prevState?.step === 8;
|
|
1177
1244
|
const now = new Date().toISOString();
|
|
1178
1245
|
writeState(root, {
|
|
1179
1246
|
feature,
|
|
1180
|
-
step:
|
|
1181
|
-
label: STEP_LABELS[
|
|
1247
|
+
step: 8,
|
|
1248
|
+
label: STEP_LABELS[8],
|
|
1182
1249
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1183
1250
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1184
1251
|
});
|
|
1185
|
-
logEvent(root, 'step', { step:
|
|
1186
|
-
stepHeader(
|
|
1252
|
+
logEvent(root, 'step', { step: 8, label: 'Glossary', feature });
|
|
1253
|
+
stepHeader(8, 'Glossary', feature);
|
|
1187
1254
|
if (isResuming) {
|
|
1188
|
-
printResumptionHeader(
|
|
1255
|
+
printResumptionHeader(8);
|
|
1189
1256
|
}
|
|
1190
1257
|
console.log('Record all new functions/components in `.codeyam/glossary.json`.');
|
|
1191
1258
|
console.log();
|
|
1192
1259
|
printGlossaryInstructions(feature);
|
|
1193
1260
|
console.log();
|
|
1194
1261
|
console.log(chalk.dim('Focus on updating the glossary. Application code and scenarios come in later steps.'));
|
|
1195
|
-
stopGate(
|
|
1262
|
+
stopGate(8);
|
|
1196
1263
|
}
|
|
1197
|
-
// ─── Step
|
|
1198
|
-
function
|
|
1264
|
+
// ─── Step 9: Analyze ──────────────────────────────────────────────────
|
|
1265
|
+
function printStep9(root, feature) {
|
|
1199
1266
|
const port = getServerPort();
|
|
1200
1267
|
const { defaultName: dim, names: dimNames } = getProjectDimensions(root);
|
|
1201
1268
|
const prevState = readState(root);
|
|
1202
|
-
const isResuming = prevState?.step ===
|
|
1269
|
+
const isResuming = prevState?.step === 9;
|
|
1203
1270
|
const now = new Date().toISOString();
|
|
1204
1271
|
writeState(root, {
|
|
1205
1272
|
feature,
|
|
1206
|
-
step:
|
|
1207
|
-
label: STEP_LABELS[
|
|
1273
|
+
step: 9,
|
|
1274
|
+
label: STEP_LABELS[9],
|
|
1208
1275
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1209
1276
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1210
1277
|
});
|
|
1211
|
-
logEvent(root, 'step', { step:
|
|
1212
|
-
stepHeader(
|
|
1278
|
+
logEvent(root, 'step', { step: 9, label: 'Analyze', feature });
|
|
1279
|
+
stepHeader(9, 'Analyze and Verify', feature);
|
|
1213
1280
|
if (isResuming) {
|
|
1214
|
-
printResumptionHeader(
|
|
1281
|
+
printResumptionHeader(9);
|
|
1215
1282
|
}
|
|
1216
1283
|
console.log('Verify visual components (via isolation routes) and library functions (via tests).');
|
|
1217
1284
|
console.log();
|
|
1218
1285
|
console.log(chalk.bold('Visual Components — Component Isolation:'));
|
|
1219
|
-
checkbox('List all files with new/modified visual components from step
|
|
1286
|
+
checkbox('List all files with new/modified visual components from step 7');
|
|
1220
1287
|
checkbox('Check existing scenarios: `codeyam editor scenarios`');
|
|
1221
1288
|
console.log(chalk.dim(' Reuse and improve existing scenarios where possible — update mock data'));
|
|
1222
1289
|
console.log(chalk.dim(' to reflect current changes. Add new scenarios only for genuinely new states.'));
|
|
@@ -1224,7 +1291,7 @@ function printStep7(root, feature) {
|
|
|
1224
1291
|
printComponentCaptureInstructions();
|
|
1225
1292
|
console.log();
|
|
1226
1293
|
console.log(chalk.bold('Library Functions — run tests:'));
|
|
1227
|
-
checkbox('Run ALL test files created in step
|
|
1294
|
+
checkbox('Run ALL test files created in step 7');
|
|
1228
1295
|
console.log(chalk.dim(' Example: npx vitest run app/lib/drinks.test.ts'));
|
|
1229
1296
|
checkbox('Verify every test passes');
|
|
1230
1297
|
checkbox('If any test fails, fix the source code and re-run');
|
|
@@ -1232,29 +1299,29 @@ function printStep7(root, feature) {
|
|
|
1232
1299
|
console.log(chalk.dim('Do not proceed until both component isolations and library tests pass.'));
|
|
1233
1300
|
console.log();
|
|
1234
1301
|
checkbox('Run `codeyam editor audit` to verify all components have scenarios and all functions/hooks have tests');
|
|
1235
|
-
console.log(chalk.red.bold(' The audit is a HARD GATE — step
|
|
1302
|
+
console.log(chalk.red.bold(' The audit is a HARD GATE — step 10 will refuse to run until the audit passes.'));
|
|
1236
1303
|
console.log(chalk.dim(' When audit passes, the import graph is built automatically for change tracking.'));
|
|
1237
1304
|
console.log();
|
|
1238
|
-
stopGate(
|
|
1305
|
+
stopGate(9);
|
|
1239
1306
|
}
|
|
1240
|
-
// ─── Step
|
|
1241
|
-
function
|
|
1307
|
+
// ─── Step 10: App Scenarios ────────────────────────────────────────────
|
|
1308
|
+
function printStep10(root, feature) {
|
|
1242
1309
|
const port = getServerPort();
|
|
1243
1310
|
const { defaultName: dim, names: dimNames } = getProjectDimensions(root);
|
|
1244
1311
|
const prevState = readState(root);
|
|
1245
|
-
const isResuming = prevState?.step ===
|
|
1312
|
+
const isResuming = prevState?.step === 10;
|
|
1246
1313
|
const now = new Date().toISOString();
|
|
1247
1314
|
writeState(root, {
|
|
1248
1315
|
feature,
|
|
1249
|
-
step:
|
|
1250
|
-
label: STEP_LABELS[
|
|
1316
|
+
step: 10,
|
|
1317
|
+
label: STEP_LABELS[10],
|
|
1251
1318
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1252
1319
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1253
1320
|
});
|
|
1254
|
-
logEvent(root, 'step', { step:
|
|
1255
|
-
stepHeader(
|
|
1321
|
+
logEvent(root, 'step', { step: 10, label: 'App Scenarios', feature });
|
|
1322
|
+
stepHeader(10, 'App Scenarios', feature);
|
|
1256
1323
|
if (isResuming) {
|
|
1257
|
-
printResumptionHeader(
|
|
1324
|
+
printResumptionHeader(10);
|
|
1258
1325
|
}
|
|
1259
1326
|
console.log('Create app-level scenarios with rich data that robustly demonstrates this feature.');
|
|
1260
1327
|
console.log();
|
|
@@ -1276,13 +1343,19 @@ function printStep8(root, feature) {
|
|
|
1276
1343
|
console.log(chalk.cyan(" • New data states that can't coexist in one scenario (empty vs rich, error vs success) → new scenario"));
|
|
1277
1344
|
console.log(chalk.cyan(" • Don't duplicate — if an existing scenario can cover a state with richer data, enhance it instead"));
|
|
1278
1345
|
console.log();
|
|
1346
|
+
console.log(chalk.bold.cyan('Scenario naming — describe data states, not features:'));
|
|
1347
|
+
console.log(chalk.cyan(' • Name scenarios by what they represent: "Rich Data", "Empty", "Mobile", "Minimal"'));
|
|
1348
|
+
console.log(chalk.cyan(' • When enhancing a scenario with new feature data, update the name if it has grown beyond its original scope'));
|
|
1349
|
+
console.log(chalk.cyan(' • A single rich scenario exercising multiple features is more valuable than separate thin scenarios per feature'));
|
|
1350
|
+
console.log(chalk.cyan(' • Re-register with the same name to update; to rename, register with the new name'));
|
|
1351
|
+
console.log();
|
|
1279
1352
|
checkbox('Ensure scenarios clearly demonstrate what changed in this session');
|
|
1280
1353
|
console.log(chalk.dim(' If data models changed: update existing scenarios seed data to match'));
|
|
1281
1354
|
console.log(chalk.dim(' If UI changed: re-register existing scenarios so screenshots reflect the update'));
|
|
1282
1355
|
console.log(chalk.dim(' Add new scenarios only for genuinely new data states not covered by existing ones'));
|
|
1283
1356
|
printAppScenarioInstructions();
|
|
1284
1357
|
console.log();
|
|
1285
|
-
console.log(chalk.dim('Focus on creating and registering app-level scenarios. Code fixes happen in step
|
|
1358
|
+
console.log(chalk.dim('Focus on creating and registering app-level scenarios. Code fixes happen in step 12 if needed.'));
|
|
1286
1359
|
console.log();
|
|
1287
1360
|
console.log(chalk.bold.cyan("Verify your work — screenshots don't lie:"));
|
|
1288
1361
|
console.log(chalk.cyan(' • View every captured screenshot. Does it show what the scenario name promises?'));
|
|
@@ -1293,43 +1366,43 @@ function printStep8(root, feature) {
|
|
|
1293
1366
|
console.log(chalk.bold.yellow('GATE: Before proceeding, run `codeyam editor scenario-coverage`'));
|
|
1294
1367
|
console.log(chalk.yellow(' This checks which existing scenarios have stale screenshots.'));
|
|
1295
1368
|
console.log(chalk.yellow(' Re-register every stale scenario listed until the check passes.'));
|
|
1296
|
-
stopGate(
|
|
1369
|
+
stopGate(10);
|
|
1297
1370
|
}
|
|
1298
|
-
// ─── Step
|
|
1299
|
-
function
|
|
1371
|
+
// ─── Step 11: User Scenarios ───────────────────────────────────────────
|
|
1372
|
+
function printStep11(root, feature) {
|
|
1300
1373
|
const port = getServerPort();
|
|
1301
1374
|
const prevState = readState(root);
|
|
1302
|
-
const isResuming = prevState?.step ===
|
|
1375
|
+
const isResuming = prevState?.step === 11;
|
|
1303
1376
|
const now = new Date().toISOString();
|
|
1304
1377
|
writeState(root, {
|
|
1305
1378
|
feature,
|
|
1306
|
-
step:
|
|
1307
|
-
label: STEP_LABELS[
|
|
1379
|
+
step: 11,
|
|
1380
|
+
label: STEP_LABELS[11],
|
|
1308
1381
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1309
1382
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1310
1383
|
});
|
|
1311
|
-
logEvent(root, 'step', { step:
|
|
1312
|
-
stepHeader(
|
|
1384
|
+
logEvent(root, 'step', { step: 11, label: 'User Scenarios', feature });
|
|
1385
|
+
stepHeader(11, 'User Scenarios', feature);
|
|
1313
1386
|
if (isResuming) {
|
|
1314
|
-
printResumptionHeader(
|
|
1387
|
+
printResumptionHeader(11);
|
|
1315
1388
|
}
|
|
1316
|
-
console.log('Create per-persona variations of existing scenarios. Skip to step
|
|
1389
|
+
console.log('Create per-persona variations of existing scenarios. Skip to step 12 if no users.');
|
|
1317
1390
|
console.log();
|
|
1318
1391
|
console.log(chalk.bold('If the app has NO users/auth:'));
|
|
1319
|
-
console.log(chalk.dim(' Skip this step and proceed to step
|
|
1392
|
+
console.log(chalk.dim(' Skip this step and proceed to step 12 (Verify).'));
|
|
1320
1393
|
console.log();
|
|
1321
1394
|
console.log(chalk.bold('If the app has users/auth:'));
|
|
1322
1395
|
console.log();
|
|
1323
1396
|
console.log(chalk.bold('Goal: Create persona variations of EXISTING app scenarios.'));
|
|
1324
1397
|
console.log(chalk.dim(' Do NOT create standalone persona scenarios. Each user-persona scenario should be'));
|
|
1325
|
-
console.log(chalk.dim(' a variation of an existing app scenario from step
|
|
1398
|
+
console.log(chalk.dim(' a variation of an existing app scenario from step 10, with user-specific state layered on.'));
|
|
1326
1399
|
console.log();
|
|
1327
1400
|
console.log(chalk.bold('Checklist:'));
|
|
1328
1401
|
checkbox('Run `codeyam editor scenarios` — list all existing app scenarios');
|
|
1329
1402
|
checkbox('For EACH existing app scenario, create a logged-in variation:');
|
|
1330
1403
|
console.log(chalk.dim(' Copy the scenario seed data and add "session":{"cookieValue":"sess_alice"} + user seed'));
|
|
1331
1404
|
console.log(chalk.dim(' Name: "<Original Name> - Logged In" (e.g. "Full Catalog - Logged In")'));
|
|
1332
|
-
console.log(chalk.dim(' Step
|
|
1405
|
+
console.log(chalk.dim(' Step 10 scenarios already serve as logged-out versions (no session cookie)'));
|
|
1333
1406
|
checkbox('If there are multiple user roles (admin, regular, etc.), create role-specific variations too');
|
|
1334
1407
|
console.log(chalk.dim(' Each persona scenario layers user-specific seed data on top of an app scenario'));
|
|
1335
1408
|
checkbox('Include "dimensions" — inherit from the base app scenario, or override if the persona implies a different device');
|
|
@@ -1338,26 +1411,26 @@ function printStep9(root, feature) {
|
|
|
1338
1411
|
console.log(chalk.yellow(' If clientErrors is non-empty → fix the issue and re-register the scenario'));
|
|
1339
1412
|
console.log();
|
|
1340
1413
|
console.log(chalk.dim('See FEATURE_PATTERNS.md and AUTH_PATTERNS.md for auth scenario guidance.'));
|
|
1341
|
-
stopGate(
|
|
1414
|
+
stopGate(11);
|
|
1342
1415
|
}
|
|
1343
|
-
// ─── Step
|
|
1344
|
-
function
|
|
1416
|
+
// ─── Step 12: Verify ──────────────────────────────────────────────────
|
|
1417
|
+
function printStep12(root, feature) {
|
|
1345
1418
|
const port = getServerPort();
|
|
1346
1419
|
const { defaultName: dim, names: dimNames } = getProjectDimensions(root);
|
|
1347
1420
|
const prevState = readState(root);
|
|
1348
|
-
const isResuming = prevState?.step ===
|
|
1421
|
+
const isResuming = prevState?.step === 12;
|
|
1349
1422
|
const now = new Date().toISOString();
|
|
1350
1423
|
writeState(root, {
|
|
1351
1424
|
feature,
|
|
1352
|
-
step:
|
|
1353
|
-
label: STEP_LABELS[
|
|
1425
|
+
step: 12,
|
|
1426
|
+
label: STEP_LABELS[12],
|
|
1354
1427
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1355
1428
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1356
1429
|
});
|
|
1357
|
-
logEvent(root, 'step', { step:
|
|
1358
|
-
stepHeader(
|
|
1430
|
+
logEvent(root, 'step', { step: 12, label: 'Verify', feature });
|
|
1431
|
+
stepHeader(12, 'Verify', feature);
|
|
1359
1432
|
if (isResuming) {
|
|
1360
|
-
printResumptionHeader(
|
|
1433
|
+
printResumptionHeader(12);
|
|
1361
1434
|
}
|
|
1362
1435
|
console.log('Verify component isolation screenshots, editor scenarios, and library tests.');
|
|
1363
1436
|
console.log();
|
|
@@ -1380,63 +1453,63 @@ function printStep10(root, feature) {
|
|
|
1380
1453
|
checkbox('Verify no broken images: `codeyam editor verify-images \'{"paths":["/"], "imageUrls":["url1"]}\'` with all page paths and image URLs');
|
|
1381
1454
|
console.log();
|
|
1382
1455
|
console.log(chalk.bold('Library functions — test check:'));
|
|
1383
|
-
checkbox('Re-run all test files from step
|
|
1456
|
+
checkbox('Re-run all test files from step 7 to confirm they still pass');
|
|
1384
1457
|
console.log(chalk.dim(' Example: npx vitest run app/lib/drinks.test.ts'));
|
|
1385
1458
|
checkbox('If any test fails, fix the source code and re-run');
|
|
1386
1459
|
console.log();
|
|
1387
1460
|
console.log(chalk.dim('Focus on fixing issues. All component screenshots, scenarios, and tests must be clean before proceeding.'));
|
|
1388
|
-
stopGate(
|
|
1461
|
+
stopGate(12);
|
|
1389
1462
|
}
|
|
1390
|
-
// ─── Step
|
|
1391
|
-
function
|
|
1463
|
+
// ─── Step 13: Journal ─────────────────────────────────────────────────
|
|
1464
|
+
function printStep13(root, feature) {
|
|
1392
1465
|
const port = getServerPort();
|
|
1393
1466
|
const prevState = readState(root);
|
|
1394
|
-
const isResuming = prevState?.step ===
|
|
1467
|
+
const isResuming = prevState?.step === 13;
|
|
1395
1468
|
const now = new Date().toISOString();
|
|
1396
1469
|
writeState(root, {
|
|
1397
1470
|
feature,
|
|
1398
|
-
step:
|
|
1399
|
-
label: STEP_LABELS[
|
|
1471
|
+
step: 13,
|
|
1472
|
+
label: STEP_LABELS[13],
|
|
1400
1473
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1401
1474
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1402
1475
|
});
|
|
1403
|
-
logEvent(root, 'step', { step:
|
|
1404
|
-
stepHeader(
|
|
1476
|
+
logEvent(root, 'step', { step: 13, label: 'Journal', feature });
|
|
1477
|
+
stepHeader(13, 'Journal', feature);
|
|
1405
1478
|
if (isResuming) {
|
|
1406
|
-
printResumptionHeader(
|
|
1479
|
+
printResumptionHeader(13);
|
|
1407
1480
|
}
|
|
1408
1481
|
console.log('Create or update the journal entry for this feature.');
|
|
1409
1482
|
console.log();
|
|
1410
1483
|
console.log(chalk.bold('Checklist:'));
|
|
1411
1484
|
checkbox('Write a concise description of what was built (2-3 sentences)');
|
|
1412
|
-
checkbox(`First time at step
|
|
1485
|
+
checkbox(`First time at step 13 — create journal entry with ALL session screenshots:`);
|
|
1413
1486
|
console.log(chalk.dim(` codeyam editor journal '{"title":"...","type":"feature","description":"...","includeSessionScenarios":true}'`));
|
|
1414
1487
|
console.log(chalk.dim(' includeSessionScenarios auto-discovers component + app + user persona screenshots'));
|
|
1415
|
-
checkbox(`Returning to step
|
|
1488
|
+
checkbox(`Returning to step 13 (before commit) — update the existing journal entry:`);
|
|
1416
1489
|
console.log(chalk.dim(` codeyam editor journal-update '{"time":"<journal entry time>","description":"<updated>","includeSessionScenarios":true}'`));
|
|
1417
1490
|
console.log(chalk.dim(' Note: PATCH only works before the entry is committed. After commit, use POST to create a new entry.'));
|
|
1418
1491
|
console.log();
|
|
1419
|
-
console.log(chalk.dim('Focus on creating or updating the journal entry. Summary and presentation happen in step
|
|
1420
|
-
stopGate(
|
|
1492
|
+
console.log(chalk.dim('Focus on creating or updating the journal entry. Summary and presentation happen in step 15.'));
|
|
1493
|
+
stopGate(13);
|
|
1421
1494
|
}
|
|
1422
|
-
// ─── Step
|
|
1423
|
-
function
|
|
1495
|
+
// ─── Step 14: Review ──────────────────────────────────────────────────
|
|
1496
|
+
function printStep14(root, feature) {
|
|
1424
1497
|
const port = getServerPort();
|
|
1425
1498
|
const { defaultName: dim, names: dimNames } = getProjectDimensions(root);
|
|
1426
1499
|
const prevState = readState(root);
|
|
1427
|
-
const isResuming = prevState?.step ===
|
|
1500
|
+
const isResuming = prevState?.step === 14;
|
|
1428
1501
|
const now = new Date().toISOString();
|
|
1429
1502
|
writeState(root, {
|
|
1430
1503
|
feature,
|
|
1431
|
-
step:
|
|
1432
|
-
label: STEP_LABELS[
|
|
1504
|
+
step: 14,
|
|
1505
|
+
label: STEP_LABELS[14],
|
|
1433
1506
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1434
1507
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1435
1508
|
});
|
|
1436
|
-
logEvent(root, 'step', { step:
|
|
1437
|
-
stepHeader(
|
|
1509
|
+
logEvent(root, 'step', { step: 14, label: 'Review', feature });
|
|
1510
|
+
stepHeader(14, 'Review', feature);
|
|
1438
1511
|
if (isResuming) {
|
|
1439
|
-
printResumptionHeader(
|
|
1512
|
+
printResumptionHeader(14);
|
|
1440
1513
|
}
|
|
1441
1514
|
console.log('Verify all screenshots and checks pass before presenting to the user.');
|
|
1442
1515
|
console.log();
|
|
@@ -1452,24 +1525,24 @@ function printStep12(root, feature) {
|
|
|
1452
1525
|
checkbox('Recapture stale scenarios: `codeyam editor recapture-stale`');
|
|
1453
1526
|
checkbox('Run `codeyam editor audit` to verify completeness of scenarios and tests');
|
|
1454
1527
|
checkbox('Do not proceed until all checks pass');
|
|
1455
|
-
stopGate(
|
|
1528
|
+
stopGate(14);
|
|
1456
1529
|
}
|
|
1457
|
-
// ─── Step
|
|
1458
|
-
function
|
|
1530
|
+
// ─── Step 15: Present ─────────────────────────────────────────────────
|
|
1531
|
+
function printStep15(root, feature) {
|
|
1459
1532
|
const prevState = readState(root);
|
|
1460
|
-
const isResuming = prevState?.step ===
|
|
1533
|
+
const isResuming = prevState?.step === 15;
|
|
1461
1534
|
const now = new Date().toISOString();
|
|
1462
1535
|
writeState(root, {
|
|
1463
1536
|
feature,
|
|
1464
|
-
step:
|
|
1465
|
-
label: STEP_LABELS[
|
|
1537
|
+
step: 15,
|
|
1538
|
+
label: STEP_LABELS[15],
|
|
1466
1539
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
1467
1540
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
1468
1541
|
});
|
|
1469
|
-
logEvent(root, 'step', { step:
|
|
1470
|
-
stepHeader(
|
|
1542
|
+
logEvent(root, 'step', { step: 15, label: 'Present', feature });
|
|
1543
|
+
stepHeader(15, 'Present', feature);
|
|
1471
1544
|
if (isResuming) {
|
|
1472
|
-
printResumptionHeader(
|
|
1545
|
+
printResumptionHeader(15);
|
|
1473
1546
|
}
|
|
1474
1547
|
console.log('Present the results to the user and get their approval.');
|
|
1475
1548
|
console.log();
|
|
@@ -1488,7 +1561,7 @@ function printStep13(root, feature) {
|
|
|
1488
1561
|
chalk.dim(' — describe changes, then re-verify'));
|
|
1489
1562
|
console.log();
|
|
1490
1563
|
console.log(chalk.bold('If the user chooses "Save & commit":'));
|
|
1491
|
-
checkbox('Advance to the commit step: `codeyam editor
|
|
1564
|
+
checkbox('Advance to the commit step: `codeyam editor 16`');
|
|
1492
1565
|
console.log();
|
|
1493
1566
|
console.log(chalk.bold('If the user chooses "Make changes" (or asks for ANY change, even as a question):'));
|
|
1494
1567
|
checkbox(`Hide the results panel: \`codeyam editor hide-results\``);
|
|
@@ -1496,7 +1569,7 @@ function printStep13(root, feature) {
|
|
|
1496
1569
|
checkbox(`Run: \`codeyam editor change "${feature}"\` — this gives you the change checklist`);
|
|
1497
1570
|
checkbox('THEN make the requested changes and follow the checklist');
|
|
1498
1571
|
console.log(chalk.red.bold(' IMPORTANT: Always run the change command BEFORE writing any code.'));
|
|
1499
|
-
stopGate(
|
|
1572
|
+
stopGate(15, { confirm: true });
|
|
1500
1573
|
}
|
|
1501
1574
|
// ─── Migration Mode ──────────────────────────────────────────────────
|
|
1502
1575
|
/**
|
|
@@ -2103,22 +2176,22 @@ function handleMigrateCommand(root, subArg) {
|
|
|
2103
2176
|
};
|
|
2104
2177
|
stepFns[step](root);
|
|
2105
2178
|
}
|
|
2106
|
-
// ─── Step
|
|
2107
|
-
function
|
|
2179
|
+
// ─── Step 16: Commit ─────────────────────────────────────────────────
|
|
2180
|
+
function printStep16(root, feature) {
|
|
2108
2181
|
const prevState = readState(root);
|
|
2109
|
-
const isResuming = prevState?.step ===
|
|
2182
|
+
const isResuming = prevState?.step === 16;
|
|
2110
2183
|
const now = new Date().toISOString();
|
|
2111
2184
|
writeState(root, {
|
|
2112
2185
|
feature,
|
|
2113
|
-
step:
|
|
2114
|
-
label: STEP_LABELS[
|
|
2186
|
+
step: 16,
|
|
2187
|
+
label: STEP_LABELS[16],
|
|
2115
2188
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
2116
2189
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
2117
2190
|
});
|
|
2118
|
-
logEvent(root, 'step', { step:
|
|
2119
|
-
stepHeader(
|
|
2191
|
+
logEvent(root, 'step', { step: 16, label: 'Commit', feature });
|
|
2192
|
+
stepHeader(16, 'Commit', feature);
|
|
2120
2193
|
if (isResuming) {
|
|
2121
|
-
printResumptionHeader(
|
|
2194
|
+
printResumptionHeader(16);
|
|
2122
2195
|
}
|
|
2123
2196
|
console.log('Commit all changes for this feature.');
|
|
2124
2197
|
console.log();
|
|
@@ -2127,24 +2200,24 @@ function printStep14(root, feature) {
|
|
|
2127
2200
|
checkbox(`Hide the results panel: \`codeyam editor hide-results\``);
|
|
2128
2201
|
checkbox(`Git commit using the journal description: \`codeyam editor commit '{"message":"feat: <title>\\n\\n<journal description>"}'\``);
|
|
2129
2202
|
console.log(chalk.dim(' The commit message body MUST match the journal description exactly'));
|
|
2130
|
-
stopGate(
|
|
2203
|
+
stopGate(16);
|
|
2131
2204
|
}
|
|
2132
|
-
// ─── Step
|
|
2133
|
-
function
|
|
2205
|
+
// ─── Step 17: Finalize ───────────────────────────────────────────────
|
|
2206
|
+
function printStep17(root, feature) {
|
|
2134
2207
|
const prevState = readState(root);
|
|
2135
|
-
const isResuming = prevState?.step ===
|
|
2208
|
+
const isResuming = prevState?.step === 17;
|
|
2136
2209
|
const now = new Date().toISOString();
|
|
2137
2210
|
writeState(root, {
|
|
2138
2211
|
feature,
|
|
2139
|
-
step:
|
|
2140
|
-
label: STEP_LABELS[
|
|
2212
|
+
step: 17,
|
|
2213
|
+
label: STEP_LABELS[17],
|
|
2141
2214
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
2142
2215
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
2143
2216
|
});
|
|
2144
|
-
logEvent(root, 'step', { step:
|
|
2145
|
-
stepHeader(
|
|
2217
|
+
logEvent(root, 'step', { step: 17, label: 'Finalize', feature });
|
|
2218
|
+
stepHeader(17, 'Finalize', feature);
|
|
2146
2219
|
if (isResuming) {
|
|
2147
|
-
printResumptionHeader(
|
|
2220
|
+
printResumptionHeader(17);
|
|
2148
2221
|
}
|
|
2149
2222
|
console.log('Update the journal with the commit SHA and amend the commit.');
|
|
2150
2223
|
console.log();
|
|
@@ -2152,24 +2225,24 @@ function printStep15(root, feature) {
|
|
|
2152
2225
|
checkbox(`Update journal with commit SHA: \`codeyam editor journal-update '{"time":"<journal entry time>","commitSha":"<sha>","commitMessage":"feat: <title>"}'\``);
|
|
2153
2226
|
checkbox('Amend the commit to include the journal update: `git add .codeyam/journal/ && git commit --amend --no-edit`');
|
|
2154
2227
|
console.log(chalk.dim(' The journal-update modifies journal files after the commit — amend to keep the tree clean.'));
|
|
2155
|
-
stopGate(
|
|
2228
|
+
stopGate(17);
|
|
2156
2229
|
}
|
|
2157
|
-
// ─── Step
|
|
2158
|
-
function
|
|
2230
|
+
// ─── Step 18: Push ───────────────────────────────────────────────────
|
|
2231
|
+
function printStep18(root, feature) {
|
|
2159
2232
|
const prevState = readState(root);
|
|
2160
|
-
const isResuming = prevState?.step ===
|
|
2233
|
+
const isResuming = prevState?.step === 18;
|
|
2161
2234
|
const now = new Date().toISOString();
|
|
2162
2235
|
writeState(root, {
|
|
2163
2236
|
feature,
|
|
2164
|
-
step:
|
|
2165
|
-
label: STEP_LABELS[
|
|
2237
|
+
step: 18,
|
|
2238
|
+
label: STEP_LABELS[18],
|
|
2166
2239
|
startedAt: isResuming ? prevState.startedAt : now,
|
|
2167
2240
|
featureStartedAt: prevState?.featureStartedAt || now,
|
|
2168
2241
|
});
|
|
2169
|
-
logEvent(root, 'step', { step:
|
|
2170
|
-
stepHeader(
|
|
2242
|
+
logEvent(root, 'step', { step: 18, label: 'Push', feature });
|
|
2243
|
+
stepHeader(18, 'Push', feature);
|
|
2171
2244
|
if (isResuming) {
|
|
2172
|
-
printResumptionHeader(
|
|
2245
|
+
printResumptionHeader(18);
|
|
2173
2246
|
}
|
|
2174
2247
|
console.log('Push the commit to the remote repository.');
|
|
2175
2248
|
console.log();
|
|
@@ -2180,12 +2253,17 @@ function printStep16(root, feature) {
|
|
|
2180
2253
|
console.log(chalk.dim(' If the user says yes, run: `git push`'));
|
|
2181
2254
|
console.log(chalk.dim(' If NO remote exists, ask (AskUserQuestion): "This project doesn\'t have a git remote yet. Would you like help setting one up? I can walk you through creating a GitHub repository." with options "Yes, set up remote" and "No, skip"'));
|
|
2182
2255
|
console.log(chalk.dim(' If the user wants help, guide them through `gh repo create` or manual GitHub setup, then push.'));
|
|
2183
|
-
checkbox('
|
|
2184
|
-
|
|
2185
|
-
console.log(chalk.
|
|
2186
|
-
console.log(chalk.
|
|
2187
|
-
console.log(
|
|
2188
|
-
|
|
2256
|
+
checkbox('Mark the current build task as complete');
|
|
2257
|
+
checkbox('Create a new task with EXACTLY this title: "Ask the user what to build next, then run `codeyam editor 1` to start the next feature"');
|
|
2258
|
+
console.log(chalk.dim(' There must ALWAYS be an active task. Never leave the task list empty.'));
|
|
2259
|
+
console.log(chalk.dim(' This task reminds you to use the editor workflow for the next feature.'));
|
|
2260
|
+
console.log();
|
|
2261
|
+
console.log(chalk.bold.yellow('IMPORTANT: After this step, the current feature is DONE.'));
|
|
2262
|
+
console.log(chalk.yellow(' Any new user request — even if it sounds related — is a NEW feature.'));
|
|
2263
|
+
console.log(chalk.yellow(' Do NOT use `codeyam editor change` or start building directly.'));
|
|
2264
|
+
console.log(chalk.yellow(' The next feature MUST start with `codeyam editor 1`.'));
|
|
2265
|
+
console.log(chalk.yellow(' The change workflow is ONLY for modifications during steps 1-15, not after commit.'));
|
|
2266
|
+
stopGate(18, { confirm: true });
|
|
2189
2267
|
}
|
|
2190
2268
|
// ─── Command definition ───────────────────────────────────────────────
|
|
2191
2269
|
// ─── Analyze-imports subcommand ────────────────────────────────────────
|
|
@@ -2205,7 +2283,7 @@ async function handleAnalyzeImports(options = {}) {
|
|
|
2205
2283
|
return;
|
|
2206
2284
|
}
|
|
2207
2285
|
console.error(chalk.red('Error: .codeyam/glossary.json not found.'));
|
|
2208
|
-
console.error(chalk.dim(' Run codeyam editor
|
|
2286
|
+
console.error(chalk.dim(' Run codeyam editor 8 to create the glossary first.'));
|
|
2209
2287
|
process.exit(1);
|
|
2210
2288
|
}
|
|
2211
2289
|
let glossaryEntries;
|
|
@@ -2659,8 +2737,14 @@ async function handleRegister(jsonArg) {
|
|
|
2659
2737
|
else {
|
|
2660
2738
|
parts.push(`errors=0`);
|
|
2661
2739
|
}
|
|
2662
|
-
if (data.seedResult)
|
|
2663
|
-
|
|
2740
|
+
if (data.seedResult) {
|
|
2741
|
+
if (data.seedResult.success) {
|
|
2742
|
+
parts.push(`seed=ok`);
|
|
2743
|
+
}
|
|
2744
|
+
else {
|
|
2745
|
+
parts.push(chalk.red(`seed=FAILED${data.seedResult.error ? ` (${data.seedResult.error})` : ''}`));
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2664
2748
|
if (data.captureError)
|
|
2665
2749
|
parts.push(chalk.yellow(`captureError="${data.captureError}"`));
|
|
2666
2750
|
console.log(prefix + parts.join(' '));
|
|
@@ -2879,7 +2963,7 @@ async function handleDependents(entityName) {
|
|
|
2879
2963
|
*
|
|
2880
2964
|
* Prints a condensed post-change checklist that guides Claude through
|
|
2881
2965
|
* re-verifying after user-requested modifications. When called from
|
|
2882
|
-
* step
|
|
2966
|
+
* step 15+, this loops back to step 15 (present). When called from an
|
|
2883
2967
|
* earlier step, it returns to that step so the normal flow continues.
|
|
2884
2968
|
*/
|
|
2885
2969
|
function handleChange(feature) {
|
|
@@ -2897,7 +2981,7 @@ function handleChange(feature) {
|
|
|
2897
2981
|
process.exit(1);
|
|
2898
2982
|
}
|
|
2899
2983
|
}
|
|
2900
|
-
const currentStep = state?.step ??
|
|
2984
|
+
const currentStep = state?.step ?? 15;
|
|
2901
2985
|
const port = getServerPort();
|
|
2902
2986
|
console.log();
|
|
2903
2987
|
console.log(chalk.bold.cyan('━━━ Change Loop ━━━'));
|
|
@@ -2945,6 +3029,7 @@ function handleChange(feature) {
|
|
|
2945
3029
|
console.log(chalk.dim(' re-register "Home - Default", "Catalog - Full", "Detail - WithReviews", etc.'));
|
|
2946
3030
|
checkbox("Enrich existing scenario data to exercise the change — don't just re-register unchanged data");
|
|
2947
3031
|
console.log(chalk.dim(' Add data that demonstrates what changed: new fields, relationships, states, content variety.'));
|
|
3032
|
+
console.log(chalk.dim(' If the enriched data makes the scenario name too narrow, rename it to reflect its broader coverage.'));
|
|
2948
3033
|
checkbox('After each re-registration, view the screenshot to verify data is visible');
|
|
2949
3034
|
console.log(chalk.dim(" If the screenshot doesn't show the data you put in, the scenario is broken."));
|
|
2950
3035
|
console.log();
|
|
@@ -2968,10 +3053,10 @@ function handleChange(feature) {
|
|
|
2968
3053
|
console.log(chalk.dim(' Always update the existing uncommitted entry — do NOT create a new one.'));
|
|
2969
3054
|
console.log(chalk.dim(' Only create a new entry (POST) if no uncommitted entry exists for this feature.'));
|
|
2970
3055
|
console.log();
|
|
2971
|
-
// If the change was initiated from a step before
|
|
2972
|
-
// instead of jumping to step
|
|
2973
|
-
// step
|
|
2974
|
-
if (currentStep <
|
|
3056
|
+
// If the change was initiated from a step before 15, return to that step
|
|
3057
|
+
// instead of jumping to step 15. The change workflow should only loop to
|
|
3058
|
+
// step 15 when changes are requested FROM step 15.
|
|
3059
|
+
if (currentStep < 15) {
|
|
2975
3060
|
console.log(chalk.red(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
2976
3061
|
console.log(chalk.red.bold(' REQUIRED: Return to current step'));
|
|
2977
3062
|
console.log(chalk.red.bold(' When all checks pass, you MUST run: ') +
|
|
@@ -2982,7 +3067,7 @@ function handleChange(feature) {
|
|
|
2982
3067
|
console.log(chalk.red(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
2983
3068
|
console.log(chalk.red.bold(' REQUIRED: Show Results'));
|
|
2984
3069
|
console.log(chalk.red.bold(' When all checks pass, you MUST run: ') +
|
|
2985
|
-
chalk.bold(`codeyam editor
|
|
3070
|
+
chalk.bold(`codeyam editor 15`));
|
|
2986
3071
|
console.log(chalk.red.bold(' The user ALWAYS expects to see results after changes. DO NOT skip this step.'));
|
|
2987
3072
|
console.log(chalk.red(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
2988
3073
|
}
|
|
@@ -3129,8 +3214,6 @@ function printAuditGateFailures(data) {
|
|
|
3129
3214
|
}
|
|
3130
3215
|
}
|
|
3131
3216
|
console.error(chalk.yellow('\nFix: Fix the code errors above, then re-capture the affected scenarios.'));
|
|
3132
|
-
console.error(chalk.yellow('If errors reference browser APIs (localStorage, sessionStorage, window, document),'));
|
|
3133
|
-
console.error(chalk.yellow('create a universal mock: codeyam detect-universal-mocks'));
|
|
3134
3217
|
}
|
|
3135
3218
|
}
|
|
3136
3219
|
console.error(chalk.dim('\nRun `codeyam editor audit` for full details.\n'));
|
|
@@ -3219,14 +3302,6 @@ async function handleAudit() {
|
|
|
3219
3302
|
if (c.clientErrors.length > 3) {
|
|
3220
3303
|
console.log(chalk.dim(` … and ${c.clientErrors.length - 3} more`));
|
|
3221
3304
|
}
|
|
3222
|
-
// Detect browser API errors and provide actionable guidance
|
|
3223
|
-
const browserApiPattern = /\b(localStorage|sessionStorage|window\.|document\.|navigator\.|indexedDB|matchMedia|ResizeObserver|IntersectionObserver|MutationObserver)\b/;
|
|
3224
|
-
const hasBrowserApiErrors = c.clientErrors.some((err) => browserApiPattern.test(err));
|
|
3225
|
-
if (hasBrowserApiErrors) {
|
|
3226
|
-
console.log(chalk.yellow(` ⚠ These errors are caused by browser APIs that don't exist during server-side analysis.`));
|
|
3227
|
-
console.log(chalk.yellow(` Fix: Create a universal mock to stub the missing API. Run: codeyam detect-universal-mocks`));
|
|
3228
|
-
console.log(chalk.yellow(` DO NOT re-run the audit or analyze-imports — the error will persist until a mock is created.`));
|
|
3229
|
-
}
|
|
3230
3305
|
}
|
|
3231
3306
|
}
|
|
3232
3307
|
console.log();
|
|
@@ -3287,11 +3362,9 @@ async function handleAudit() {
|
|
|
3287
3362
|
console.log(chalk.red(' analyze-imports was run automatically but these entities are STILL incomplete.'));
|
|
3288
3363
|
console.log(chalk.red(' DO NOT re-run analyze-imports or the audit in a loop — the result will be the same.'));
|
|
3289
3364
|
console.log(chalk.yellow(' This means the analysis failed for these entities. Common causes:'));
|
|
3290
|
-
console.log(chalk.yellow(' • Entity code uses browser APIs (localStorage, window, document) — create a universal mock'));
|
|
3291
3365
|
console.log(chalk.yellow(' • Source file was renamed/deleted but glossary still references the old path'));
|
|
3292
3366
|
console.log(chalk.yellow(' • Entity has import errors that prevent analysis'));
|
|
3293
3367
|
console.log(chalk.yellow(' To investigate: run `codeyam editor analyze-imports` (without --silent) to see the full error.'));
|
|
3294
|
-
console.log(chalk.yellow(' To fix browser API issues: run `codeyam detect-universal-mocks`'));
|
|
3295
3368
|
}
|
|
3296
3369
|
else {
|
|
3297
3370
|
console.log(chalk.yellow(' Run `codeyam editor analyze-imports` to analyze these entities'));
|
|
@@ -3745,7 +3818,7 @@ async function handleTemplate() {
|
|
|
3745
3818
|
console.log(chalk.green(' Git initialized.'));
|
|
3746
3819
|
}
|
|
3747
3820
|
// 4. Run codeyam init
|
|
3748
|
-
console.log(chalk.bold('
|
|
3821
|
+
console.log(chalk.bold('Initializing project...'));
|
|
3749
3822
|
await initCommand.handler({
|
|
3750
3823
|
force: true,
|
|
3751
3824
|
'keep-server': true,
|
|
@@ -3824,7 +3897,7 @@ async function handleSync() {
|
|
|
3824
3897
|
// fall through
|
|
3825
3898
|
}
|
|
3826
3899
|
if (!projectSlug) {
|
|
3827
|
-
console.error(chalk.red('Error: No project slug found. Run codeyam
|
|
3900
|
+
console.error(chalk.red('Error: No project slug found. Run `codeyam editor template` to initialize the project.'));
|
|
3828
3901
|
process.exit(1);
|
|
3829
3902
|
}
|
|
3830
3903
|
const connectionOk = await withoutSpinner(() => testEnvironment());
|
|
@@ -4008,7 +4081,7 @@ function handleEditorDebug(args) {
|
|
|
4008
4081
|
scenarios.push({
|
|
4009
4082
|
id: 'overview-with-state',
|
|
4010
4083
|
title: 'Cycle overview (project, with state)',
|
|
4011
|
-
render: () => withTempRoot(true, (tempRoot) => captureOutput(() => printCycleOverview(tempRoot, makeState(
|
|
4084
|
+
render: () => withTempRoot(true, (tempRoot) => captureOutput(() => printCycleOverview(tempRoot, makeState(6, feature)))),
|
|
4012
4085
|
});
|
|
4013
4086
|
}
|
|
4014
4087
|
const stepFns = {
|
|
@@ -4028,8 +4101,10 @@ function handleEditorDebug(args) {
|
|
|
4028
4101
|
14: printStep14,
|
|
4029
4102
|
15: printStep15,
|
|
4030
4103
|
16: printStep16,
|
|
4104
|
+
17: printStep17,
|
|
4105
|
+
18: printStep18,
|
|
4031
4106
|
};
|
|
4032
|
-
for (let step = 1; step <=
|
|
4107
|
+
for (let step = 1; step <= 18; step++) {
|
|
4033
4108
|
const stepId = `step-${step}`;
|
|
4034
4109
|
if (!wants(stepId))
|
|
4035
4110
|
continue;
|
|
@@ -4049,7 +4124,7 @@ function handleEditorDebug(args) {
|
|
|
4049
4124
|
if (step === 2) {
|
|
4050
4125
|
scenarios.push({
|
|
4051
4126
|
id: 'step-2-scaffold',
|
|
4052
|
-
title: 'Step 2 (
|
|
4127
|
+
title: 'Step 2 (Prepare) — scaffold flow (no project)',
|
|
4053
4128
|
render: () => withTempRoot(false, (tempRoot) => captureOutput(() => printStep2(tempRoot, feature))),
|
|
4054
4129
|
});
|
|
4055
4130
|
}
|
|
@@ -4108,8 +4183,8 @@ const editorCommand = {
|
|
|
4108
4183
|
describe: 'Editor mode guided workflow',
|
|
4109
4184
|
builder: (yargs) => {
|
|
4110
4185
|
const stepDescription = IS_INTERNAL_BUILD
|
|
4111
|
-
? 'Step number (1-
|
|
4112
|
-
: 'Step number (1-
|
|
4186
|
+
? 'Step number (1-18) or subcommand (template, register, isolate, analyze-imports, dependents, audit, scenarios, scenario-coverage, recapture-stale, change, sync, debug, preview, show-results, hide-results, commit, journal, journal-list, journal-update, dev-server, client-errors)'
|
|
4187
|
+
: 'Step number (1-18) or subcommand (template, register, isolate, analyze-imports, dependents, audit, scenarios, scenario-coverage, recapture-stale, change, sync, preview, show-results, hide-results, commit, journal, journal-list, journal-update, dev-server, client-errors)';
|
|
4113
4188
|
let builder = yargs
|
|
4114
4189
|
.positional('step', {
|
|
4115
4190
|
type: 'string',
|
|
@@ -4145,7 +4220,7 @@ const editorCommand = {
|
|
|
4145
4220
|
builder = builder
|
|
4146
4221
|
.option('target', {
|
|
4147
4222
|
type: 'string',
|
|
4148
|
-
describe: 'Debug target (setup, overview, overview-with-state, step-1..step-
|
|
4223
|
+
describe: 'Debug target (setup, overview, overview-with-state, step-1..step-18, or comma-separated list)',
|
|
4149
4224
|
})
|
|
4150
4225
|
.option('resume', {
|
|
4151
4226
|
type: 'boolean',
|
|
@@ -4189,6 +4264,12 @@ const editorCommand = {
|
|
|
4189
4264
|
console.log(JSON.stringify(result.data, null, 2));
|
|
4190
4265
|
}
|
|
4191
4266
|
}
|
|
4267
|
+
// After a successful commit, remind Claude to continue to step 17
|
|
4268
|
+
if (argv.step === 'commit' && result.ok) {
|
|
4269
|
+
console.log();
|
|
4270
|
+
console.log(chalk.green('Commit done. Now run: ') +
|
|
4271
|
+
chalk.bold('codeyam editor 17'));
|
|
4272
|
+
}
|
|
4192
4273
|
}
|
|
4193
4274
|
catch (err) {
|
|
4194
4275
|
console.error(chalk.red('Error: Could not reach the CodeYam server. Is it running?'));
|
|
@@ -4296,18 +4377,13 @@ const editorCommand = {
|
|
|
4296
4377
|
}
|
|
4297
4378
|
else {
|
|
4298
4379
|
const state = readState(root);
|
|
4299
|
-
// Clear prompt file when feature is done (step 16) so the hook
|
|
4300
|
-
// can capture the next feature request from the user.
|
|
4301
|
-
if (state?.step === 16) {
|
|
4302
|
-
clearEditorUserPrompt(root);
|
|
4303
|
-
}
|
|
4304
4380
|
printCycleOverview(root, state);
|
|
4305
4381
|
}
|
|
4306
4382
|
return;
|
|
4307
4383
|
}
|
|
4308
4384
|
const step = argv.step ? parseInt(argv.step, 10) : undefined;
|
|
4309
|
-
if (step != null && (isNaN(step) || step < 1 || step >
|
|
4310
|
-
console.error(chalk.red(`Error: Invalid step "${argv.step}". Must be 1-
|
|
4385
|
+
if (step != null && (isNaN(step) || step < 1 || step > 18)) {
|
|
4386
|
+
console.error(chalk.red(`Error: Invalid step "${argv.step}". Must be 1-18.`));
|
|
4311
4387
|
process.exit(1);
|
|
4312
4388
|
}
|
|
4313
4389
|
if (step == null) {
|
|
@@ -4331,7 +4407,7 @@ const editorCommand = {
|
|
|
4331
4407
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
4332
4408
|
const { projectSlug } = config;
|
|
4333
4409
|
if (!projectSlug) {
|
|
4334
|
-
errorLog('Missing project slug. Try reinitializing with: codeyam
|
|
4410
|
+
errorLog('Missing project slug. Try reinitializing with: `codeyam editor template`');
|
|
4335
4411
|
return;
|
|
4336
4412
|
}
|
|
4337
4413
|
const connectionOk = await withoutSpinner(() => testEnvironment());
|
|
@@ -4768,14 +4844,16 @@ const editorCommand = {
|
|
|
4768
4844
|
case 13:
|
|
4769
4845
|
case 14:
|
|
4770
4846
|
case 15:
|
|
4771
|
-
case 16:
|
|
4847
|
+
case 16:
|
|
4848
|
+
case 17:
|
|
4849
|
+
case 18: {
|
|
4772
4850
|
const feature = argv.feature || state?.feature;
|
|
4773
4851
|
if (!feature) {
|
|
4774
4852
|
console.error(chalk.red('Error: No feature in progress. Run codeyam editor 1 first.'));
|
|
4775
4853
|
process.exit(1);
|
|
4776
4854
|
}
|
|
4777
|
-
// Hard gate: steps
|
|
4778
|
-
if (step >=
|
|
4855
|
+
// Hard gate: steps 10+ require audit to have passed
|
|
4856
|
+
if (step >= 10) {
|
|
4779
4857
|
const auditOk = await checkAuditGate();
|
|
4780
4858
|
if (!auditOk) {
|
|
4781
4859
|
// checkAuditGate() already printed specific failure details above
|
|
@@ -4799,6 +4877,8 @@ const editorCommand = {
|
|
|
4799
4877
|
14: printStep14,
|
|
4800
4878
|
15: printStep15,
|
|
4801
4879
|
16: printStep16,
|
|
4880
|
+
17: printStep17,
|
|
4881
|
+
18: printStep18,
|
|
4802
4882
|
};
|
|
4803
4883
|
stepFns[step](root, feature);
|
|
4804
4884
|
break;
|