@codeyam/codeyam-cli 0.1.20 → 0.1.21
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 +7 -7
- package/analyzer-template/log.txt +3 -3
- package/analyzer-template/package.json +1 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +5 -1
- package/analyzer-template/packages/analyze/src/lib/files/analyze/findOrCreateEntity.ts +1 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyzeChange.ts +4 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyzeInitial.ts +4 -0
- package/analyzer-template/packages/aws/package.json +1 -1
- package/analyzer-template/packages/database/src/lib/loadEntity.ts +11 -4
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.d.ts +4 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.js +4 -4
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.js.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts +3 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js +22 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js.map +1 -1
- package/analyzer-template/packages/utils/src/lib/fs/rsyncCopy.ts +27 -0
- package/codeyam-cli/src/commands/editor.js +185 -59
- package/codeyam-cli/src/commands/editor.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +630 -23
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/registerScenarioResult.test.js +127 -0
- package/codeyam-cli/src/utils/__tests__/registerScenarioResult.test.js.map +1 -0
- package/codeyam-cli/src/utils/analyzer.js +8 -0
- package/codeyam-cli/src/utils/analyzer.js.map +1 -1
- package/codeyam-cli/src/utils/editorAudit.js +113 -12
- package/codeyam-cli/src/utils/editorAudit.js.map +1 -1
- package/codeyam-cli/src/utils/registerScenarioResult.js +52 -0
- package/codeyam-cli/src/utils/registerScenarioResult.js.map +1 -0
- package/codeyam-cli/src/webserver/app/lib/clientErrors.js +3 -0
- package/codeyam-cli/src/webserver/app/lib/clientErrors.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-save-scenario-data-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-schema-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{cy-logo-cli-CCKUIm0S.svg → cy-logo-cli-CJzc4vOH.svg} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-DODLxLcw.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-Dx-h1rJK.js +130 -0
- package/codeyam-cli/src/webserver/build/client/assets/editorPreview-NTuLi4Xg.js +41 -0
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.dev-KTQuL0aj.js → entity._sha.scenarios._scenarioId.dev-BA5L8bU-.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-C6eeL24i.js → entity._sha.scenarios._scenarioId.fullscreen-D4dmRgvO.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-BrPXT1iR.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/manifest-5025e428.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{root-BxUQigda.js → root-BCx1S8Z3.js} +26 -13
- package/codeyam-cli/src/webserver/build/server/assets/{analysisRunner-B_PsTAb1.js → analysisRunner-C1kjC9UJ.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{index-CjLhfz6Z.js → index-C91yWWCI.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{init-BEqlbI84.js → init-Dkas-RUS.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-pulXLTrG.js +640 -0
- 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 +10 -3
- package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
- package/package.json +1 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +4 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js +1 -0
- package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js.map +1 -1
- package/packages/analyze/src/lib/files/analyzeChange.js +1 -0
- package/packages/analyze/src/lib/files/analyzeChange.js.map +1 -1
- package/packages/analyze/src/lib/files/analyzeInitial.js +1 -0
- package/packages/analyze/src/lib/files/analyzeInitial.js.map +1 -1
- package/packages/database/src/lib/loadEntity.js +4 -4
- package/packages/database/src/lib/loadEntity.js.map +1 -1
- package/packages/utils/src/lib/fs/rsyncCopy.js +22 -1
- package/packages/utils/src/lib/fs/rsyncCopy.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-DcX-ZS3p.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-DII1pg_z.js +0 -58
- package/codeyam-cli/src/webserver/build/client/assets/editorPreview-oepecPae.js +0 -41
- package/codeyam-cli/src/webserver/build/client/assets/globals-Yn9W3zp3.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-cdf2c0a7.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-YI63xTu4.js +0 -553
|
@@ -21,6 +21,7 @@ import { validateSeedData, detectSeedAdapter, validateSeedKeysAgainstPrisma, } f
|
|
|
21
21
|
import { deleteScenarioViaCli } from "../utils/editorDeleteScenario.js";
|
|
22
22
|
import { buildEditorApiRequest, callEditorApi, EDITOR_API_SUBCOMMANDS, } from "../utils/editorApi.js";
|
|
23
23
|
import { parseRegisterArg } from "../utils/parseRegisterArg.js";
|
|
24
|
+
import { classifyRegistrationResult } from "../utils/registerScenarioResult.js";
|
|
24
25
|
import { sanitizeGlossaryEntries } from "../utils/editorLoaderHelpers.js";
|
|
25
26
|
import { readMigrationState, writeMigrationState, advanceToNextPage, completePage, getMigrationResumeInfo, } from "../utils/editorMigration.js";
|
|
26
27
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -210,6 +211,34 @@ function checkbox(text) {
|
|
|
210
211
|
const highlighted = text.replace(/`([^`]+)`/g, (_m, code) => chalk.cyan(code));
|
|
211
212
|
console.log(` ${chalk.dim('[ ]')} ${highlighted}`);
|
|
212
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* Instructions for creating/updating .codeyam/data-structure.json.
|
|
216
|
+
* Only prints creation instructions if the file doesn't exist yet.
|
|
217
|
+
* If it exists, reminds Claude to update it if data models changed.
|
|
218
|
+
*/
|
|
219
|
+
function printDataStructureInstructions() {
|
|
220
|
+
const root = getProjectRoot();
|
|
221
|
+
const dsPath = path.join(root, '.codeyam', 'data-structure.json');
|
|
222
|
+
const exists = fs.existsSync(dsPath);
|
|
223
|
+
if (!exists) {
|
|
224
|
+
console.log(chalk.bold('Create the data structure config:'));
|
|
225
|
+
checkbox('Create `.codeyam/data-structure.json` describing all data sources');
|
|
226
|
+
console.log(chalk.dim(" This file tells the editor what data the app uses and how it's stored."));
|
|
227
|
+
console.log(chalk.dim(' The file is a JSON array. Each entry describes one data source:'));
|
|
228
|
+
console.log(chalk.dim(' { "name": "Drink", "description": "...", "category": "datastore", "order": 1,'));
|
|
229
|
+
console.log(chalk.dim(' "fields": [{ "name": "id", "type": "number", "isId": true, "required": true }, ...] }'));
|
|
230
|
+
console.log();
|
|
231
|
+
console.log(chalk.dim(' category: "datastore" for persisted data (DB, localStorage)'));
|
|
232
|
+
console.log(chalk.dim(' "mock-api" for mocked external API responses'));
|
|
233
|
+
console.log(chalk.dim(' order: 1 = primary data store, 2 = secondary, etc.'));
|
|
234
|
+
console.log(chalk.dim(' Do NOT include types only used as component props.'));
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
checkbox('If this feature changes data models, update `.codeyam/data-structure.json`');
|
|
238
|
+
console.log(chalk.dim(' Add new tables, update fields, or change descriptions to match.'));
|
|
239
|
+
}
|
|
240
|
+
console.log();
|
|
241
|
+
}
|
|
213
242
|
/**
|
|
214
243
|
* Shared app scenario registration instructions used by editor Step 8 and migration Steps 1/6.
|
|
215
244
|
* Prints seed-based scenarios, mock-based fallback, @ file prefix, externalApis, url requirement, and error checking.
|
|
@@ -978,6 +1007,7 @@ function printStep2(root, feature) {
|
|
|
978
1007
|
console.log(chalk.dim(' Key: import { prisma } from "@/app/lib/prisma" in API routes.'));
|
|
979
1008
|
console.log(chalk.dim(' Key: Seed scripts must use the adapter pattern (see prisma/seed.ts).'));
|
|
980
1009
|
console.log();
|
|
1010
|
+
printDataStructureInstructions();
|
|
981
1011
|
}
|
|
982
1012
|
else {
|
|
983
1013
|
console.log(chalk.bold('Prepare the database for this feature:'));
|
|
@@ -992,6 +1022,7 @@ function printStep2(root, feature) {
|
|
|
992
1022
|
console.log(chalk.dim(' This switches the active scenario, runs the seed adapter, and refreshes the preview.'));
|
|
993
1023
|
console.log(chalk.dim(' If no existing scenario fits, use the default seed: npm run db:seed'));
|
|
994
1024
|
console.log();
|
|
1025
|
+
printDataStructureInstructions();
|
|
995
1026
|
}
|
|
996
1027
|
stopGate(2);
|
|
997
1028
|
}
|
|
@@ -1326,7 +1357,10 @@ function printStep9(root, feature) {
|
|
|
1326
1357
|
console.log();
|
|
1327
1358
|
checkbox('Run `codeyam editor audit` to verify all components have scenarios and all functions/hooks have tests');
|
|
1328
1359
|
console.log(chalk.red.bold(' The audit is a HARD GATE — step 10 will refuse to run until the audit passes.'));
|
|
1329
|
-
console.log(chalk.dim('
|
|
1360
|
+
console.log(chalk.dim(' The audit auto-fixes incomplete entities by running targeted analysis on just the affected files.'));
|
|
1361
|
+
console.log(chalk.dim(' If the audit reports issues (including pre-existing ones), fix ALL of them — do not skip.'));
|
|
1362
|
+
console.log(chalk.dim(' Re-run `codeyam editor audit` until all checks pass. Do NOT run `codeyam editor analyze-imports`'));
|
|
1363
|
+
console.log(chalk.dim(' — the audit runs targeted analysis automatically and is much faster.'));
|
|
1330
1364
|
console.log();
|
|
1331
1365
|
stopGate(9);
|
|
1332
1366
|
}
|
|
@@ -2362,25 +2396,54 @@ async function handleAnalyzeImports(options = {}) {
|
|
|
2362
2396
|
// Non-fatal — scenario file paths just won't be included
|
|
2363
2397
|
}
|
|
2364
2398
|
const progress = new ProgressReporter();
|
|
2365
|
-
//
|
|
2366
|
-
//
|
|
2367
|
-
|
|
2368
|
-
progress.start('Running import analysis for all entities...');
|
|
2399
|
+
// Filter to only files that actually need analysis — avoids re-analyzing
|
|
2400
|
+
// ~120 files when only 2 are incomplete.
|
|
2401
|
+
let targetFilePaths = filePaths;
|
|
2369
2402
|
try {
|
|
2370
|
-
await
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2403
|
+
const { getDatabase } = await import('../../../packages/database/index.js');
|
|
2404
|
+
const db = getDatabase();
|
|
2405
|
+
const { requireBranchAndProject: rbp } = await import('../utils/database.js');
|
|
2406
|
+
const { project } = await rbp(JSON.parse(fs.readFileSync(path.join(root, '.codeyam', 'config.json'), 'utf8')).projectSlug);
|
|
2407
|
+
const { filterToIncompleteFilePaths } = await import('../utils/editorAudit.js');
|
|
2408
|
+
const incomplete = await filterToIncompleteFilePaths(db, project.id, filePaths);
|
|
2409
|
+
if (incomplete.length < filePaths.length && incomplete.length > 0) {
|
|
2410
|
+
if (!options.silent) {
|
|
2411
|
+
console.log(chalk.dim(`Skipping ${filePaths.length - incomplete.length} already-analyzed files, analyzing ${incomplete.length} remaining...`));
|
|
2412
|
+
}
|
|
2413
|
+
targetFilePaths = incomplete;
|
|
2414
|
+
}
|
|
2415
|
+
else if (incomplete.length === 0) {
|
|
2416
|
+
if (!options.silent) {
|
|
2417
|
+
console.log(chalk.green('All entities already have analyses — nothing to do.'));
|
|
2418
|
+
}
|
|
2419
|
+
// Still need to run the import graph + backfill below
|
|
2420
|
+
targetFilePaths = [];
|
|
2421
|
+
}
|
|
2376
2422
|
}
|
|
2377
|
-
catch
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2423
|
+
catch {
|
|
2424
|
+
// Non-fatal — fall back to analyzing all files
|
|
2425
|
+
}
|
|
2426
|
+
// Run data-structure-only analysis for entities that need it.
|
|
2427
|
+
// Don't pass entityNames — entities may not exist yet (fresh clone).
|
|
2428
|
+
// The analyzer will discover and create them from file paths.
|
|
2429
|
+
if (targetFilePaths.length > 0) {
|
|
2430
|
+
progress.start(`Running import analysis for ${targetFilePaths.length} entit${targetFilePaths.length !== 1 ? 'ies' : 'y'}...`);
|
|
2431
|
+
try {
|
|
2432
|
+
await runAnalysisForEntities({
|
|
2433
|
+
projectRoot: root,
|
|
2434
|
+
filePaths: targetFilePaths,
|
|
2435
|
+
progress,
|
|
2436
|
+
onlyDataStructure: true,
|
|
2437
|
+
});
|
|
2438
|
+
}
|
|
2439
|
+
catch (err) {
|
|
2440
|
+
progress.fail('Analysis failed');
|
|
2441
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2442
|
+
console.error(chalk.red(`Error: ${msg}`));
|
|
2443
|
+
process.exit(1);
|
|
2444
|
+
}
|
|
2445
|
+
progress.succeed('Analysis complete');
|
|
2382
2446
|
}
|
|
2383
|
-
progress.succeed('Analysis complete');
|
|
2384
2447
|
// Load entities WITH metadata from database
|
|
2385
2448
|
progress.start('Loading entity metadata...');
|
|
2386
2449
|
await initializeEnvironment();
|
|
@@ -2736,6 +2799,8 @@ async function handleRegister(jsonArg) {
|
|
|
2736
2799
|
const isBatch = items.length > 1;
|
|
2737
2800
|
let succeeded = 0;
|
|
2738
2801
|
let failed = 0;
|
|
2802
|
+
let warnings = 0;
|
|
2803
|
+
const issues = [];
|
|
2739
2804
|
const screenshotEntries = [];
|
|
2740
2805
|
for (let i = 0; i < items.length; i++) {
|
|
2741
2806
|
const body = items[i];
|
|
@@ -2805,11 +2870,14 @@ async function handleRegister(jsonArg) {
|
|
|
2805
2870
|
}
|
|
2806
2871
|
console.log(chalk.yellow(' Fix the issue and re-register this scenario.'));
|
|
2807
2872
|
}
|
|
2873
|
+
const resultIssues = classifyRegistrationResult(res.ok, res.status, data, String(body.name || `item ${i + 1}`));
|
|
2808
2874
|
if (!res.ok) {
|
|
2809
2875
|
console.error(chalk.dim(JSON.stringify(data, null, 2)));
|
|
2810
2876
|
failed++;
|
|
2811
2877
|
}
|
|
2812
2878
|
else {
|
|
2879
|
+
if (resultIssues.length > 0)
|
|
2880
|
+
warnings++;
|
|
2813
2881
|
succeeded++;
|
|
2814
2882
|
// Collect screenshot paths for duplicate detection
|
|
2815
2883
|
if (data.screenshotCaptured &&
|
|
@@ -2822,6 +2890,10 @@ async function handleRegister(jsonArg) {
|
|
|
2822
2890
|
});
|
|
2823
2891
|
}
|
|
2824
2892
|
}
|
|
2893
|
+
// Collect issues from this registration
|
|
2894
|
+
for (const issue of resultIssues) {
|
|
2895
|
+
issues.push(`"${issue.scenarioName}": ${issue.message}`);
|
|
2896
|
+
}
|
|
2825
2897
|
}
|
|
2826
2898
|
catch (error) {
|
|
2827
2899
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -2859,9 +2931,22 @@ async function handleRegister(jsonArg) {
|
|
|
2859
2931
|
}
|
|
2860
2932
|
}
|
|
2861
2933
|
if (isBatch) {
|
|
2862
|
-
console.log(
|
|
2934
|
+
console.log('');
|
|
2935
|
+
if (failed > 0 || warnings > 0) {
|
|
2936
|
+
console.log(chalk.red.bold(`ERROR: ${failed} failed, ${warnings} with warnings out of ${items.length} scenarios`));
|
|
2937
|
+
console.log('');
|
|
2938
|
+
console.log(chalk.red.bold('Issues that MUST be fixed:'));
|
|
2939
|
+
for (const issue of issues) {
|
|
2940
|
+
console.log(chalk.red(` ✗ ${issue}`));
|
|
2941
|
+
}
|
|
2942
|
+
console.log('');
|
|
2943
|
+
console.log(chalk.red('Do NOT skip these errors. Fix each issue and re-register the affected scenarios.'));
|
|
2944
|
+
}
|
|
2945
|
+
else {
|
|
2946
|
+
console.log(chalk.green(`✓ Batch complete: ${succeeded}/${items.length} succeeded with no issues`));
|
|
2947
|
+
}
|
|
2863
2948
|
}
|
|
2864
|
-
if (failed > 0) {
|
|
2949
|
+
if (failed > 0 || warnings > 0) {
|
|
2865
2950
|
process.exit(1);
|
|
2866
2951
|
}
|
|
2867
2952
|
}
|
|
@@ -3176,17 +3261,15 @@ async function checkAuditGate() {
|
|
|
3176
3261
|
return true; // Server unreachable — don't block
|
|
3177
3262
|
if (data.summary?.allPassing === true)
|
|
3178
3263
|
return true;
|
|
3179
|
-
//
|
|
3180
|
-
//
|
|
3181
|
-
const {
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
}
|
|
3189
|
-
// Backfill entity_sha on scenarios registered before entities existed
|
|
3264
|
+
// Lightweight auto-fix: backfill entity_sha (DB-only, fast).
|
|
3265
|
+
// Never run handleAnalyzeImports here — it takes minutes on large projects.
|
|
3266
|
+
const { isOnlyIncompleteEntities, isOnlyPreExistingIncomplete } = await import('../utils/editorAudit.js');
|
|
3267
|
+
// If the only failures are pre-existing incomplete entities (not caused by
|
|
3268
|
+
// this session), don't block — the audit text already calls these "non-blocking".
|
|
3269
|
+
if (isOnlyPreExistingIncomplete(data.summary, data.incompleteEntities)) {
|
|
3270
|
+
return true;
|
|
3271
|
+
}
|
|
3272
|
+
if (isOnlyIncompleteEntities(data.summary)) {
|
|
3190
3273
|
try {
|
|
3191
3274
|
const entities = await loadEntities({});
|
|
3192
3275
|
if (entities && entities.length > 0) {
|
|
@@ -3204,7 +3287,7 @@ async function checkAuditGate() {
|
|
|
3204
3287
|
catch {
|
|
3205
3288
|
// Fall through
|
|
3206
3289
|
}
|
|
3207
|
-
// Re-check after
|
|
3290
|
+
// Re-check after backfill
|
|
3208
3291
|
const retry = await fetchAuditResult();
|
|
3209
3292
|
if (retry?.summary?.allPassing === true)
|
|
3210
3293
|
return true;
|
|
@@ -3228,6 +3311,8 @@ function printAuditGateFailures(data) {
|
|
|
3228
3311
|
const missing = (data.components || []).filter((c) => c.status === 'missing');
|
|
3229
3312
|
for (const c of missing) {
|
|
3230
3313
|
issues.push(` → ${c.name}${c.filePath ? ` (${c.filePath})` : ''}`);
|
|
3314
|
+
if (c.hint)
|
|
3315
|
+
issues.push(` Fix: ${c.hint}`);
|
|
3231
3316
|
}
|
|
3232
3317
|
}
|
|
3233
3318
|
if (s.componentsWithErrors > 0) {
|
|
@@ -3241,7 +3326,15 @@ function printAuditGateFailures(data) {
|
|
|
3241
3326
|
issues.push(`${s.functionsMissing} function(s) missing test files`);
|
|
3242
3327
|
const missing = (data.functions || []).filter((f) => f.status === 'missing');
|
|
3243
3328
|
for (const f of missing) {
|
|
3244
|
-
|
|
3329
|
+
if (f.testFile) {
|
|
3330
|
+
issues.push(` → ${f.name} — test file missing: ${f.testFile}`);
|
|
3331
|
+
}
|
|
3332
|
+
else {
|
|
3333
|
+
issues.push(` → ${f.name} (${f.filePath}) — no testFile in glossary`);
|
|
3334
|
+
if (f.suggestedTestFile) {
|
|
3335
|
+
issues.push(` Fix: Create ${f.suggestedTestFile} or add "testFile": "${f.suggestedTestFile}" to .codeyam/glossary.json`);
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3245
3338
|
}
|
|
3246
3339
|
}
|
|
3247
3340
|
if (s.functionsFailing > 0) {
|
|
@@ -3330,22 +3423,16 @@ async function handleAudit() {
|
|
|
3330
3423
|
console.error(chalk.red('Error: Could not reach the CodeYam server. Is it running?'));
|
|
3331
3424
|
process.exit(1);
|
|
3332
3425
|
}
|
|
3333
|
-
//
|
|
3334
|
-
//
|
|
3335
|
-
//
|
|
3336
|
-
//
|
|
3426
|
+
// Lightweight auto-fix: backfill entity_sha on scenarios that were
|
|
3427
|
+
// registered before entity records existed. This is fast (DB-only).
|
|
3428
|
+
// We do NOT run handleAnalyzeImports here — it scans all files and takes
|
|
3429
|
+
// minutes on large projects. Users should run it separately if needed.
|
|
3337
3430
|
const incompleteBeforeFix = data.incompleteEntities || [];
|
|
3338
3431
|
const unassociatedBeforeFix = data.unassociatedScenarios || [];
|
|
3339
3432
|
let autoRemediationFailed = false;
|
|
3340
3433
|
if (incompleteBeforeFix.length > 0 || unassociatedBeforeFix.length > 0) {
|
|
3341
3434
|
const issueCount = incompleteBeforeFix.length + unassociatedBeforeFix.length;
|
|
3342
|
-
console.log(chalk.dim(`
|
|
3343
|
-
try {
|
|
3344
|
-
await handleAnalyzeImports({ silent: true });
|
|
3345
|
-
}
|
|
3346
|
-
catch {
|
|
3347
|
-
// Fall through — the audit will still report them
|
|
3348
|
-
}
|
|
3435
|
+
console.log(chalk.dim(`Backfilling ${issueCount} entity association issue${issueCount !== 1 ? 's' : ''}...`));
|
|
3349
3436
|
// Backfill entity_sha on scenarios that were registered before entities existed
|
|
3350
3437
|
try {
|
|
3351
3438
|
const entities = await loadEntities({});
|
|
@@ -3364,13 +3451,13 @@ async function handleAudit() {
|
|
|
3364
3451
|
catch {
|
|
3365
3452
|
// Fall through — re-fetch will show remaining issues
|
|
3366
3453
|
}
|
|
3367
|
-
// Re-fetch audit results after the
|
|
3454
|
+
// Re-fetch audit results after the backfill
|
|
3368
3455
|
data = await fetchAuditResult();
|
|
3369
3456
|
if (!data) {
|
|
3370
|
-
console.error(chalk.red('Error: Could not reach the CodeYam server after
|
|
3457
|
+
console.error(chalk.red('Error: Could not reach the CodeYam server after backfill.'));
|
|
3371
3458
|
process.exit(1);
|
|
3372
3459
|
}
|
|
3373
|
-
// If issues persist after
|
|
3460
|
+
// If issues persist after backfill, flag it so we show clear guidance
|
|
3374
3461
|
const incompleteAfterFix = data.incompleteEntities || [];
|
|
3375
3462
|
const unassociatedAfterFix = data.unassociatedScenarios || [];
|
|
3376
3463
|
if (incompleteAfterFix.length > 0 || unassociatedAfterFix.length > 0) {
|
|
@@ -3407,6 +3494,9 @@ async function handleAudit() {
|
|
|
3407
3494
|
}
|
|
3408
3495
|
else {
|
|
3409
3496
|
detail = chalk.red(' — no scenarios registered');
|
|
3497
|
+
if (c.hint) {
|
|
3498
|
+
detail += `\n ${chalk.yellow('Fix: ' + c.hint)}`;
|
|
3499
|
+
}
|
|
3410
3500
|
}
|
|
3411
3501
|
// Show file path for failing components always, for OK only when name is ambiguous
|
|
3412
3502
|
const isDuplicate = (componentNameCounts.get(c.name) || 0) > 1;
|
|
@@ -3450,9 +3540,16 @@ async function handleAudit() {
|
|
|
3450
3540
|
break;
|
|
3451
3541
|
case 'missing':
|
|
3452
3542
|
default:
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3543
|
+
if (f.testFile) {
|
|
3544
|
+
detail = chalk.red(` — test file missing: ${f.testFile}`);
|
|
3545
|
+
}
|
|
3546
|
+
else {
|
|
3547
|
+
detail = chalk.red(` — no test file specified in glossary`);
|
|
3548
|
+
detail += chalk.dim(` (source: ${f.filePath})`);
|
|
3549
|
+
if (f.suggestedTestFile) {
|
|
3550
|
+
detail += `\n ${chalk.yellow(`Fix: Either create ${f.suggestedTestFile} or add "testFile": "${f.suggestedTestFile}" to this entry in .codeyam/glossary.json`)}`;
|
|
3551
|
+
}
|
|
3552
|
+
}
|
|
3456
3553
|
break;
|
|
3457
3554
|
}
|
|
3458
3555
|
console.log(` ${icon} ${f.name}${detail}`);
|
|
@@ -3469,19 +3566,48 @@ async function handleAudit() {
|
|
|
3469
3566
|
console.log(chalk.yellow(' Add these to .codeyam/glossary.json and run `codeyam editor analyze-imports`'));
|
|
3470
3567
|
console.log();
|
|
3471
3568
|
}
|
|
3472
|
-
// Incomplete entities (scenarios without analyses)
|
|
3473
|
-
|
|
3569
|
+
// Incomplete entities (scenarios without analyses) — auto-fix by running
|
|
3570
|
+
// targeted analysis on just the affected files (fast: 2 files vs 117+).
|
|
3571
|
+
let incompleteEntities = data.incompleteEntities || [];
|
|
3474
3572
|
if (incompleteEntities.length > 0) {
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3573
|
+
const { getIncompleteEntityFilePaths } = await import('../utils/editorAudit.js');
|
|
3574
|
+
try {
|
|
3575
|
+
const { getDatabase } = await import('../../../packages/database/index.js');
|
|
3576
|
+
const db = getDatabase();
|
|
3577
|
+
const filePaths = await getIncompleteEntityFilePaths(db, incompleteEntities);
|
|
3578
|
+
if (filePaths.length > 0) {
|
|
3579
|
+
console.log(chalk.dim(`Running targeted import analysis for ${filePaths.length} incomplete entit${filePaths.length !== 1 ? 'ies' : 'y'}...`));
|
|
3580
|
+
const root = getProjectRoot();
|
|
3581
|
+
try {
|
|
3582
|
+
const { runAnalysisForEntities } = await import('../utils/analysisRunner.js');
|
|
3583
|
+
await runAnalysisForEntities({
|
|
3584
|
+
projectRoot: root,
|
|
3585
|
+
filePaths,
|
|
3586
|
+
progress: new ProgressReporter(),
|
|
3587
|
+
onlyDataStructure: true,
|
|
3588
|
+
});
|
|
3589
|
+
// Re-fetch audit results after targeted fix
|
|
3590
|
+
const refreshed = await fetchAuditResult();
|
|
3591
|
+
if (refreshed) {
|
|
3592
|
+
data = refreshed;
|
|
3593
|
+
incompleteEntities = data.incompleteEntities || [];
|
|
3594
|
+
}
|
|
3595
|
+
}
|
|
3596
|
+
catch {
|
|
3597
|
+
// Fall through — report remaining incomplete entities below
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3478
3600
|
}
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
console.log(chalk.yellow(' Run `codeyam editor analyze-imports` to see the full error output.'));
|
|
3601
|
+
catch {
|
|
3602
|
+
// DB not available — fall through to reporting
|
|
3482
3603
|
}
|
|
3483
|
-
|
|
3484
|
-
|
|
3604
|
+
}
|
|
3605
|
+
if (incompleteEntities.length > 0) {
|
|
3606
|
+
const { formatIncompleteEntityGuidance } = await import('../utils/editorAudit.js');
|
|
3607
|
+
console.log(chalk.bold('Incomplete entities (need import analysis):'));
|
|
3608
|
+
for (const e of incompleteEntities) {
|
|
3609
|
+
const guidance = formatIncompleteEntityGuidance(e);
|
|
3610
|
+
console.log(` ${chalk.red('✗')} ${guidance}`);
|
|
3485
3611
|
}
|
|
3486
3612
|
console.log();
|
|
3487
3613
|
}
|