@codeyam/codeyam-cli 0.1.12 → 0.1.13
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 +9 -0
- package/codeyam-cli/src/cli.js.map +1 -1
- package/codeyam-cli/src/commands/__tests__/editor.isolateArgs.test.js +51 -0
- package/codeyam-cli/src/commands/__tests__/editor.isolateArgs.test.js.map +1 -0
- package/codeyam-cli/src/commands/editor.js +180 -18
- package/codeyam-cli/src/commands/editor.js.map +1 -1
- package/codeyam-cli/src/commands/editorIsolateArgs.js +25 -0
- package/codeyam-cli/src/commands/editorIsolateArgs.js.map +1 -0
- package/codeyam-cli/src/commands/telemetry.js +37 -0
- package/codeyam-cli/src/commands/telemetry.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js +70 -0
- package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/telemetry.test.js +159 -0
- package/codeyam-cli/src/utils/__tests__/telemetry.test.js.map +1 -0
- package/codeyam-cli/src/utils/editorEntityChangeStatus.js +13 -7
- package/codeyam-cli/src/utils/editorEntityChangeStatus.js.map +1 -1
- package/codeyam-cli/src/utils/telemetry.js +106 -0
- package/codeyam-cli/src/utils/telemetry.js.map +1 -0
- package/codeyam-cli/src/utils/telemetryMiddleware.js +22 -0
- package/codeyam-cli/src/utils/telemetryMiddleware.js.map +1 -0
- package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +28 -0
- package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-CjC3_6JI.js +58 -0
- package/codeyam-cli/src/webserver/build/client/assets/globals-DRvOjyO3.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{manifest-b3f77062.js → manifest-75b1b319.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{root-D5Zi3U2Z.js → root-F-k2uYj5.js} +15 -15
- package/codeyam-cli/src/webserver/build/server/assets/{analysisRunner-yTyb36j3.js → analysisRunner-lv2ooewK.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{index-Cr7d_IsG.js → index-Im3Smyei.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{init-M_wqNAfu.js → init-BjuAFKGM.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{server-build-_ybRgrlc.js → server-build-CNjF0B9B.js} +116 -116
- 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/editorProxy.js +19 -2
- package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
- package/codeyam-cli/src/webserver/server.js +32 -0
- package/codeyam-cli/src/webserver/server.js.map +1 -1
- package/package.json +2 -1
- package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-DmBK1JBK.js +0 -58
- package/codeyam-cli/src/webserver/build/client/assets/globals-CGrDAxj0.css +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"buildTimestamp": "2026-03-
|
|
3
|
-
"buildTime":
|
|
4
|
-
"gitCommit": "
|
|
2
|
+
"buildTimestamp": "2026-03-17T22:42:54.370Z",
|
|
3
|
+
"buildTime": 1773787374370,
|
|
4
|
+
"gitCommit": "6af1ab46096de2c86af4f0947046703a16ac9786",
|
|
5
5
|
"nodeVersion": "v20.20.1",
|
|
6
6
|
"contentHash": "b046e014847d5b02d10d6795839ccd0d5117627cbd0be413260824610596a63d",
|
|
7
|
-
"buildNumber":
|
|
8
|
-
"semanticVersion": "0.1.
|
|
9
|
-
"version": "0.1.
|
|
7
|
+
"buildNumber": 1087,
|
|
8
|
+
"semanticVersion": "0.1.1087",
|
|
9
|
+
"version": "0.1.1087 (2026-03-17T22:42+b046e01)"
|
|
10
10
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
[3/17/2026,
|
|
3
|
-
[3/17/2026,
|
|
2
|
+
[3/17/2026, 10:42:54 PM] > codeyam-combo@1.0.0 mergeDependencies
|
|
3
|
+
[3/17/2026, 10:42:54 PM] > node ./scripts/mergePackageJsonFiles.cjs
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
[3/17/2026,
|
|
6
|
+
[3/17/2026, 10:42:54 PM] Merged dependencies into root package.json
|
|
7
7
|
|
package/codeyam-cli/src/cli.js
CHANGED
|
@@ -27,8 +27,11 @@ import memoryCommand from "./commands/memory.js";
|
|
|
27
27
|
import editorCommand from "./commands/editor.js";
|
|
28
28
|
import setupSimulationsCommand from "./commands/setup-simulations.js";
|
|
29
29
|
import { syncMocksMiddleware } from "./utils/syncMocksMiddleware.js";
|
|
30
|
+
import { telemetryMiddleware } from "./utils/telemetryMiddleware.js";
|
|
31
|
+
import { captureEvent } from "./utils/telemetry.js";
|
|
30
32
|
import { getDisplayVersion } from "./utils/versionInfo.js";
|
|
31
33
|
import { simulationGateMiddleware, buildSimulationEpilogue, } from "./utils/simulationGateMiddleware.js";
|
|
34
|
+
import telemetryCommand from "./commands/telemetry.js";
|
|
32
35
|
// Install global signal handlers for automatic process cleanup
|
|
33
36
|
// This ensures all child processes (analyzer, capture, etc.) are cleaned up on:
|
|
34
37
|
// - Ctrl+C (SIGINT)
|
|
@@ -49,11 +52,13 @@ yargs(hideBin(process.argv))
|
|
|
49
52
|
.usage('CodeYam local development CLI')
|
|
50
53
|
.middleware(simulationGateMiddleware)
|
|
51
54
|
.middleware(syncMocksMiddleware)
|
|
55
|
+
.middleware(telemetryMiddleware)
|
|
52
56
|
// Core commands (always visible in help)
|
|
53
57
|
.command(defaultCommand)
|
|
54
58
|
.command(startCommand)
|
|
55
59
|
.command(stopCommand)
|
|
56
60
|
.command(memoryCommand)
|
|
61
|
+
.command(telemetryCommand)
|
|
57
62
|
// Hidden commands (shown in epilogue when simulations are enabled)
|
|
58
63
|
.command(withoutDescribe(initCommand))
|
|
59
64
|
.command(withoutDescribe(updateConfigCommand))
|
|
@@ -81,6 +86,10 @@ yargs(hideBin(process.argv))
|
|
|
81
86
|
.strict()
|
|
82
87
|
.parseAsync()
|
|
83
88
|
.catch((error) => {
|
|
89
|
+
captureEvent('cli_error', {
|
|
90
|
+
command: process.argv[2] ?? 'unknown',
|
|
91
|
+
error_type: error?.constructor?.name ?? 'Error',
|
|
92
|
+
});
|
|
84
93
|
console.error('CLI Error:', error.message);
|
|
85
94
|
process.exit(1);
|
|
86
95
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,0BAA0B;AAC1B,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAC1C,OAAO,cAAc,MAAM,oBAAoB,CAAC;AAChD,OAAO,aAAa,MAAM,mBAAmB,CAAC;AAC9C,OAAO,eAAe,MAAM,qBAAqB,CAAC;AAClD,OAAO,cAAc,MAAM,oBAAoB,CAAC;AAChD,OAAO,kBAAkB,MAAM,yBAAyB,CAAC;AACzD,OAAO,YAAY,MAAM,kBAAkB,CAAC;AAC5C,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAC1C,OAAO,cAAc,MAAM,oBAAoB,CAAC;AAChD,OAAO,mBAAmB,MAAM,0BAA0B,CAAC;AAC3D,OAAO,aAAa,MAAM,mBAAmB,CAAC;AAC9C,OAAO,oBAAoB,MAAM,oCAAoC,CAAC;AACtE,OAAO,YAAY,MAAM,kBAAkB,CAAC;AAC5C,OAAO,mBAAmB,MAAM,0BAA0B,CAAC;AAC3D,OAAO,aAAa,MAAM,mBAAmB,CAAC;AAC9C,OAAO,YAAY,MAAM,kBAAkB,CAAC;AAC5C,OAAO,gBAAgB,MAAM,sBAAsB,CAAC;AACpD,OAAO,mBAAmB,MAAM,0BAA0B,CAAC;AAC3D,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAC1C,OAAO,eAAe,MAAM,qBAAqB,CAAC;AAClD,OAAO,aAAa,MAAM,mBAAmB,CAAC;AAC9C,OAAO,aAAa,MAAM,mBAAmB,CAAC;AAC9C,OAAO,uBAAuB,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACL,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests that `codeyam editor isolate` correctly parses multiple component
|
|
3
|
+
* names whether passed as separate args or a single quoted string.
|
|
4
|
+
*
|
|
5
|
+
* Bug: `codeyam editor isolate A B C` failed because yargs .strict()
|
|
6
|
+
* rejected extra positionals beyond the two declared (step, json).
|
|
7
|
+
* Claude would then try one at a time, wasting time and tokens.
|
|
8
|
+
*/
|
|
9
|
+
import { parseIsolateArgs } from "../editorIsolateArgs.js";
|
|
10
|
+
describe('parseIsolateArgs', () => {
|
|
11
|
+
it('should parse a single component name from json arg', () => {
|
|
12
|
+
expect(parseIsolateArgs('LogoMark', [])).toEqual(['LogoMark']);
|
|
13
|
+
});
|
|
14
|
+
it('should parse space-separated names from a single quoted json arg', () => {
|
|
15
|
+
// codeyam editor isolate "LogoMark AppHeader Button"
|
|
16
|
+
expect(parseIsolateArgs('LogoMark AppHeader Button', [])).toEqual([
|
|
17
|
+
'LogoMark',
|
|
18
|
+
'AppHeader',
|
|
19
|
+
'Button',
|
|
20
|
+
]);
|
|
21
|
+
});
|
|
22
|
+
it('should parse comma-separated names from json arg', () => {
|
|
23
|
+
expect(parseIsolateArgs('LogoMark,AppHeader,Button', [])).toEqual([
|
|
24
|
+
'LogoMark',
|
|
25
|
+
'AppHeader',
|
|
26
|
+
'Button',
|
|
27
|
+
]);
|
|
28
|
+
});
|
|
29
|
+
it('should collect extra positional args from argv._', () => {
|
|
30
|
+
// codeyam editor isolate LogoMark AppHeader Button
|
|
31
|
+
// yargs: json="LogoMark", argv._=["editor", "AppHeader", "Button"]
|
|
32
|
+
expect(parseIsolateArgs('LogoMark', ['editor', 'AppHeader', 'Button'])).toEqual(['LogoMark', 'AppHeader', 'Button']);
|
|
33
|
+
});
|
|
34
|
+
it('should deduplicate names from json and extras', () => {
|
|
35
|
+
expect(parseIsolateArgs('LogoMark', ['editor', 'LogoMark', 'AppHeader'])).toEqual(['LogoMark', 'AppHeader']);
|
|
36
|
+
});
|
|
37
|
+
it('should filter out empty strings', () => {
|
|
38
|
+
expect(parseIsolateArgs('LogoMark AppHeader', [])).toEqual([
|
|
39
|
+
'LogoMark',
|
|
40
|
+
'AppHeader',
|
|
41
|
+
]);
|
|
42
|
+
});
|
|
43
|
+
it('should return empty array when no names provided', () => {
|
|
44
|
+
expect(parseIsolateArgs(undefined, [])).toEqual([]);
|
|
45
|
+
expect(parseIsolateArgs('', [])).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
it('should filter out "editor" from argv._', () => {
|
|
48
|
+
expect(parseIsolateArgs(undefined, ['editor', 'LogoMark', 'AppHeader'])).toEqual(['LogoMark', 'AppHeader']);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=editor.isolateArgs.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.isolateArgs.test.js","sourceRoot":"","sources":["../../../../../src/commands/__tests__/editor.isolateArgs.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,qDAAqD;QACrD,MAAM,CAAC,gBAAgB,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAChE,UAAU;YACV,WAAW;YACX,QAAQ;SACT,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,gBAAgB,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAChE,UAAU;YACV,WAAW;YACX,QAAQ;SACT,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,mDAAmD;QACnD,mEAAmE;QACnE,MAAM,CACJ,gBAAgB,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAChE,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,CACJ,gBAAgB,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAClE,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAC1D,UAAU;YACV,WAAW;SACZ,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CACJ,gBAAgB,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CACjE,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -939,13 +939,29 @@ function printStep2(root, feature) {
|
|
|
939
939
|
console.log();
|
|
940
940
|
console.log(chalk.bold('Build the feature:'));
|
|
941
941
|
}
|
|
942
|
+
else {
|
|
943
|
+
console.log(chalk.bold('Prepare the database for this feature:'));
|
|
944
|
+
checkbox('List existing scenarios: `codeyam editor scenarios`');
|
|
945
|
+
console.log(chalk.dim(' Review existing scenarios to find seed data that best demonstrates the feature.'));
|
|
946
|
+
console.log(chalk.dim(" Don't create throwaway seed data — use what's already been curated."));
|
|
947
|
+
checkbox('Pick the scenario with seed data most relevant to this feature');
|
|
948
|
+
console.log(chalk.dim(" Think: which existing data state best exercises the feature you're building?"));
|
|
949
|
+
console.log(chalk.dim(' A scenario with diverse, realistic data is usually the best starting point.'));
|
|
950
|
+
checkbox('Load that scenario to seed the database and preview it:');
|
|
951
|
+
console.log(chalk.dim(` codeyam editor preview '{"scenarioId":"<id>","dimension":"${dim}"}'`));
|
|
952
|
+
console.log(chalk.dim(' This switches the active scenario, runs the seed adapter, and refreshes the preview.'));
|
|
953
|
+
console.log(chalk.dim(' If no existing scenario fits, use the default seed: npm run db:seed'));
|
|
954
|
+
console.log();
|
|
955
|
+
}
|
|
942
956
|
console.log(chalk.bold('Checklist:'));
|
|
943
957
|
checkbox('Create API routes that read from the database via Prisma');
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
958
|
+
if (!projectExists) {
|
|
959
|
+
checkbox('Seed the database with demo data');
|
|
960
|
+
checkbox('Create `.codeyam/seed-adapter.ts` so CodeYam can seed the database for scenarios');
|
|
961
|
+
console.log(chalk.dim(' The seed adapter reads a JSON file (path passed as CLI arg), wipes tables, inserts rows.'));
|
|
962
|
+
console.log(chalk.dim(" Use the project's own ORM (Prisma, Drizzle, etc.). See template for example."));
|
|
963
|
+
console.log(chalk.dim(' Run with: npx tsx .codeyam/seed-adapter.ts <path-to-seed-data.json>'));
|
|
964
|
+
}
|
|
949
965
|
checkbox('Verify the dev server shows the changes');
|
|
950
966
|
checkbox('If the feature involves auth, email, payments, or other common patterns: read FEATURE_PATTERNS.md');
|
|
951
967
|
// Responsive design guidance when building a mobile-responsive web app
|
|
@@ -2955,10 +2971,67 @@ async function checkAuditGate() {
|
|
|
2955
2971
|
}
|
|
2956
2972
|
// Re-check after fix
|
|
2957
2973
|
const retry = await fetchAuditResult();
|
|
2958
|
-
|
|
2974
|
+
if (retry?.summary?.allPassing === true)
|
|
2975
|
+
return true;
|
|
2959
2976
|
}
|
|
2977
|
+
// Print specific failures so Claude knows what to fix without running audit separately
|
|
2978
|
+
printAuditGateFailures(data);
|
|
2960
2979
|
return false;
|
|
2961
2980
|
}
|
|
2981
|
+
/**
|
|
2982
|
+
* Print a concise summary of audit failures for the gate block message.
|
|
2983
|
+
* This gives Claude immediate context about what to fix without needing
|
|
2984
|
+
* to run `codeyam editor audit` as a separate step.
|
|
2985
|
+
*/
|
|
2986
|
+
function printAuditGateFailures(data) {
|
|
2987
|
+
const s = data.summary;
|
|
2988
|
+
if (!s)
|
|
2989
|
+
return;
|
|
2990
|
+
const issues = [];
|
|
2991
|
+
if (s.componentsMissing > 0)
|
|
2992
|
+
issues.push(`${s.componentsMissing} component(s) missing scenarios`);
|
|
2993
|
+
if (s.componentsWithErrors > 0)
|
|
2994
|
+
issues.push(`${s.componentsWithErrors} component(s) with client errors (browser API or runtime errors in captured scenarios)`);
|
|
2995
|
+
if (s.functionsMissing > 0)
|
|
2996
|
+
issues.push(`${s.functionsMissing} function(s) missing test files`);
|
|
2997
|
+
if (s.functionsFailing > 0)
|
|
2998
|
+
issues.push(`${s.functionsFailing} function(s) with failing tests`);
|
|
2999
|
+
if (s.functionsNameMismatch > 0)
|
|
3000
|
+
issues.push(`${s.functionsNameMismatch} function(s) with test name mismatch`);
|
|
3001
|
+
if (s.missingFromGlossary > 0)
|
|
3002
|
+
issues.push(`${s.missingFromGlossary} file(s) with scenarios not in glossary`);
|
|
3003
|
+
if (s.incompleteEntities > 0)
|
|
3004
|
+
issues.push(`${s.incompleteEntities} entity/entities need import analysis`);
|
|
3005
|
+
if (s.miscategorizedScenarios > 0)
|
|
3006
|
+
issues.push(`${s.miscategorizedScenarios} component(s) using page URLs instead of isolation routes`);
|
|
3007
|
+
if (issues.length > 0) {
|
|
3008
|
+
console.error(chalk.yellow('\nAudit failures:'));
|
|
3009
|
+
for (const issue of issues) {
|
|
3010
|
+
console.error(chalk.yellow(` • ${issue}`));
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
// Surface client error details inline — these are the most common cause of
|
|
3014
|
+
// Claude looping because the errors require code fixes, not audit re-runs.
|
|
3015
|
+
if (data.components) {
|
|
3016
|
+
const withErrors = data.components.filter((c) => c.status === 'has_errors' && c.clientErrors?.length > 0);
|
|
3017
|
+
if (withErrors.length > 0) {
|
|
3018
|
+
console.error(chalk.yellow('\nClient errors found:'));
|
|
3019
|
+
for (const c of withErrors) {
|
|
3020
|
+
console.error(chalk.red(` ${c.name}:`));
|
|
3021
|
+
for (const err of c.clientErrors.slice(0, 3)) {
|
|
3022
|
+
console.error(chalk.red(` → ${err}`));
|
|
3023
|
+
}
|
|
3024
|
+
if (c.clientErrors.length > 3) {
|
|
3025
|
+
console.error(chalk.dim(` … and ${c.clientErrors.length - 3} more`));
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
console.error(chalk.yellow('\nFix: Fix the code errors above, then re-capture the affected scenarios.'));
|
|
3029
|
+
console.error(chalk.yellow('If errors reference browser APIs (localStorage, sessionStorage, window, document),'));
|
|
3030
|
+
console.error(chalk.yellow('create a universal mock: codeyam detect-universal-mocks'));
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
console.error(chalk.dim('\nRun `codeyam editor audit` for full details.\n'));
|
|
3034
|
+
}
|
|
2962
3035
|
// ─── Audit subcommand ────────────────────────────────────────────────
|
|
2963
3036
|
/**
|
|
2964
3037
|
* `codeyam editor audit`
|
|
@@ -3027,6 +3100,14 @@ async function handleAudit() {
|
|
|
3027
3100
|
if (c.clientErrors.length > 3) {
|
|
3028
3101
|
console.log(chalk.dim(` … and ${c.clientErrors.length - 3} more`));
|
|
3029
3102
|
}
|
|
3103
|
+
// Detect browser API errors and provide actionable guidance
|
|
3104
|
+
const browserApiPattern = /\b(localStorage|sessionStorage|window\.|document\.|navigator\.|indexedDB|matchMedia|ResizeObserver|IntersectionObserver|MutationObserver)\b/;
|
|
3105
|
+
const hasBrowserApiErrors = c.clientErrors.some((err) => browserApiPattern.test(err));
|
|
3106
|
+
if (hasBrowserApiErrors) {
|
|
3107
|
+
console.log(chalk.yellow(` ⚠ These errors are caused by browser APIs that don't exist during server-side analysis.`));
|
|
3108
|
+
console.log(chalk.yellow(` Fix: Create a universal mock to stub the missing API. Run: codeyam detect-universal-mocks`));
|
|
3109
|
+
console.log(chalk.yellow(` DO NOT re-run the audit or analyze-imports — the error will persist until a mock is created.`));
|
|
3110
|
+
}
|
|
3030
3111
|
}
|
|
3031
3112
|
}
|
|
3032
3113
|
console.log();
|
|
@@ -3077,9 +3158,13 @@ async function handleAudit() {
|
|
|
3077
3158
|
}
|
|
3078
3159
|
if (autoRemediationFailed) {
|
|
3079
3160
|
console.log(chalk.red(' analyze-imports was run automatically but these entities are STILL incomplete.'));
|
|
3080
|
-
console.log(chalk.red('
|
|
3081
|
-
console.log(chalk.yellow('
|
|
3082
|
-
console.log(chalk.yellow('
|
|
3161
|
+
console.log(chalk.red(' DO NOT re-run analyze-imports or the audit in a loop — the result will be the same.'));
|
|
3162
|
+
console.log(chalk.yellow(' This means the analysis failed for these entities. Common causes:'));
|
|
3163
|
+
console.log(chalk.yellow(' • Entity code uses browser APIs (localStorage, window, document) — create a universal mock'));
|
|
3164
|
+
console.log(chalk.yellow(' • Source file was renamed/deleted but glossary still references the old path'));
|
|
3165
|
+
console.log(chalk.yellow(' • Entity has import errors that prevent analysis'));
|
|
3166
|
+
console.log(chalk.yellow(' To investigate: run `codeyam editor analyze-imports` (without --silent) to see the full error.'));
|
|
3167
|
+
console.log(chalk.yellow(' To fix browser API issues: run `codeyam detect-universal-mocks`'));
|
|
3083
3168
|
}
|
|
3084
3169
|
else {
|
|
3085
3170
|
console.log(chalk.yellow(' Run `codeyam editor analyze-imports` to analyze these entities'));
|
|
@@ -3812,7 +3897,9 @@ const editorCommand = {
|
|
|
3812
3897
|
describe: 'Debug: output directory for the bundle',
|
|
3813
3898
|
});
|
|
3814
3899
|
}
|
|
3815
|
-
|
|
3900
|
+
// Allow extra positional args for subcommands like `isolate A B C`
|
|
3901
|
+
// without yargs rejecting them as unknown.
|
|
3902
|
+
return builder.strict(false);
|
|
3816
3903
|
},
|
|
3817
3904
|
handler: async (argv) => {
|
|
3818
3905
|
const root = getProjectRoot();
|
|
@@ -3897,13 +3984,10 @@ const editorCommand = {
|
|
|
3897
3984
|
return;
|
|
3898
3985
|
}
|
|
3899
3986
|
// Subcommand: codeyam editor isolate "StarRating CategoryBadge DrinkCard"
|
|
3987
|
+
// Also supports: codeyam editor isolate StarRating CategoryBadge DrinkCard
|
|
3900
3988
|
if (argv.step === 'isolate') {
|
|
3901
|
-
const
|
|
3902
|
-
|
|
3903
|
-
names.push(...argv.json.split(/[\s,]+/).filter(Boolean));
|
|
3904
|
-
// Collect any extra positional args (yargs puts them in argv._)
|
|
3905
|
-
const extras = argv._.filter((a) => typeof a === 'string' && a !== 'editor');
|
|
3906
|
-
names.push(...extras);
|
|
3989
|
+
const { parseIsolateArgs } = await import('./editorIsolateArgs.js');
|
|
3990
|
+
const names = parseIsolateArgs(argv.json, argv._);
|
|
3907
3991
|
handleIsolate(names);
|
|
3908
3992
|
return;
|
|
3909
3993
|
}
|
|
@@ -4091,6 +4175,41 @@ const editorCommand = {
|
|
|
4091
4175
|
catch {
|
|
4092
4176
|
// Non-fatal — migration failure shouldn't block editor startup
|
|
4093
4177
|
}
|
|
4178
|
+
// Auto-seed on fresh clone: if no scenario has ever been activated
|
|
4179
|
+
// (active-scenario.json doesn't exist), seed the application database
|
|
4180
|
+
// with the first application scenario that has seed data.
|
|
4181
|
+
const activeScenarioPath = path.join(projectRoot, '.codeyam', 'active-scenario.json');
|
|
4182
|
+
if (!fs.existsSync(activeScenarioPath)) {
|
|
4183
|
+
try {
|
|
4184
|
+
const { getDatabase: getDb } = await import('../../../packages/database/index.js');
|
|
4185
|
+
const seedDb = getDb();
|
|
4186
|
+
const appScenario = await seedDb
|
|
4187
|
+
.selectFrom('editor_scenarios')
|
|
4188
|
+
.select(['id', 'name', 'type'])
|
|
4189
|
+
.where('project_id', '=', project.id)
|
|
4190
|
+
.where('type', '=', 'application')
|
|
4191
|
+
.orderBy('created_at', 'asc')
|
|
4192
|
+
.executeTakeFirst();
|
|
4193
|
+
if (appScenario) {
|
|
4194
|
+
const seedFile = path.join(projectRoot, '.codeyam', 'editor-scenarios', `${appScenario.id}.seed.json`);
|
|
4195
|
+
if (fs.existsSync(seedFile)) {
|
|
4196
|
+
const { switchActiveScenario } = await import('../utils/editorScenarioSwitch.js');
|
|
4197
|
+
const seedResult = await switchActiveScenario({
|
|
4198
|
+
scenarioId: appScenario.id,
|
|
4199
|
+
scenarioName: appScenario.name || undefined,
|
|
4200
|
+
scenarioType: appScenario.type || undefined,
|
|
4201
|
+
projectRoot,
|
|
4202
|
+
});
|
|
4203
|
+
if (seedResult.seedResult?.success) {
|
|
4204
|
+
console.log(chalk.green(` Auto-seeded database with scenario: ${appScenario.name || appScenario.id}`));
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4209
|
+
catch {
|
|
4210
|
+
// Non-fatal — auto-seed is best-effort
|
|
4211
|
+
}
|
|
4212
|
+
}
|
|
4094
4213
|
// `codeyam editor` (no step) always implies editor mode.
|
|
4095
4214
|
// The empty-folder heuristic is no longer needed here — running this
|
|
4096
4215
|
// command IS the signal. We still detect empty folders so that
|
|
@@ -4235,6 +4354,48 @@ const editorCommand = {
|
|
|
4235
4354
|
}
|
|
4236
4355
|
}
|
|
4237
4356
|
}
|
|
4357
|
+
// Backfill page_file_path for application scenarios that have a URL but
|
|
4358
|
+
// no page_file_path. This resolves the file from the URL using Next.js
|
|
4359
|
+
// routing conventions, enabling syncScenarioEntityShas to link them to
|
|
4360
|
+
// entities. Covers fresh clones where JSON files lack pageFilePath.
|
|
4361
|
+
try {
|
|
4362
|
+
const { getDatabase: getDb } = await import('../../../packages/database/index.js');
|
|
4363
|
+
const pfpDb = getDb();
|
|
4364
|
+
const unresolved = await pfpDb
|
|
4365
|
+
.selectFrom('editor_scenarios')
|
|
4366
|
+
.select(['id', 'url'])
|
|
4367
|
+
.where('project_id', '=', project.id)
|
|
4368
|
+
.where('component_name', 'is', null)
|
|
4369
|
+
.where('page_file_path', 'is', null)
|
|
4370
|
+
.where('url', 'is not', null)
|
|
4371
|
+
.execute();
|
|
4372
|
+
if (unresolved.length > 0) {
|
|
4373
|
+
const { scanPageFilePaths: scanPfp } = await import('../utils/entityChangeStatus.server.js');
|
|
4374
|
+
const { matchUrlToPageFile } = await import('../utils/routePatternMatching');
|
|
4375
|
+
const { allFiles: pfpFiles } = scanPfp(projectRoot);
|
|
4376
|
+
let pfpResolved = 0;
|
|
4377
|
+
for (const row of unresolved) {
|
|
4378
|
+
const r = row;
|
|
4379
|
+
if (!r.url)
|
|
4380
|
+
continue;
|
|
4381
|
+
const matched = matchUrlToPageFile(r.url, pfpFiles);
|
|
4382
|
+
if (matched) {
|
|
4383
|
+
await pfpDb
|
|
4384
|
+
.updateTable('editor_scenarios')
|
|
4385
|
+
.set({ page_file_path: matched })
|
|
4386
|
+
.where('id', '=', r.id)
|
|
4387
|
+
.execute();
|
|
4388
|
+
pfpResolved++;
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
4391
|
+
if (pfpResolved > 0) {
|
|
4392
|
+
console.log(chalk.green(` Resolved page_file_path for ${pfpResolved} scenario(s) from URL`));
|
|
4393
|
+
}
|
|
4394
|
+
}
|
|
4395
|
+
}
|
|
4396
|
+
catch {
|
|
4397
|
+
/* Non-fatal — page_file_path backfill from URL */
|
|
4398
|
+
}
|
|
4238
4399
|
// Backfill entity_sha on scenarios that were synced before entities existed.
|
|
4239
4400
|
// This runs independently of analyze-imports so fresh clones and file-synced
|
|
4240
4401
|
// scenarios get linked to their entities even when auto-analyze doesn't trigger.
|
|
@@ -4341,8 +4502,9 @@ const editorCommand = {
|
|
|
4341
4502
|
if (step >= 8) {
|
|
4342
4503
|
const auditOk = await checkAuditGate();
|
|
4343
4504
|
if (!auditOk) {
|
|
4344
|
-
|
|
4345
|
-
console.error(chalk.
|
|
4505
|
+
// checkAuditGate() already printed specific failure details above
|
|
4506
|
+
console.error(chalk.red.bold('BLOCKED: The audit has not passed. Fix the issues listed above before proceeding.'));
|
|
4507
|
+
console.error(chalk.yellow('DO NOT re-run the audit in a loop — fix the underlying issues first.'));
|
|
4346
4508
|
process.exit(1);
|
|
4347
4509
|
}
|
|
4348
4510
|
}
|