@pattern-stack/codegen 0.9.2 → 0.10.1
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/CHANGELOG.md +73 -0
- package/README.md +5 -0
- package/consumer-skills/bridge/SKILL.md +265 -0
- package/consumer-skills/codegen/SKILL.md +115 -0
- package/consumer-skills/entities/SKILL.md +111 -0
- package/consumer-skills/entities/families-and-queries.md +82 -0
- package/consumer-skills/entities/yaml-reference.md +118 -0
- package/consumer-skills/events/SKILL.md +71 -0
- package/consumer-skills/events/authoring-events.md +164 -0
- package/consumer-skills/events/typed-bus-and-outbox.md +163 -0
- package/consumer-skills/jobs/SKILL.md +66 -0
- package/consumer-skills/jobs/handler-authoring.md +236 -0
- package/consumer-skills/jobs/pools-and-ordering.md +161 -0
- package/consumer-skills/subsystems/SKILL.md +161 -0
- package/consumer-skills/subsystems/wiring-and-order.md +120 -0
- package/consumer-skills/sync/SKILL.md +134 -0
- package/consumer-skills/sync/audit-and-detection.md +302 -0
- package/consumer-skills/sync/change-sources-and-sinks.md +442 -0
- package/dist/runtime/subsystems/bridge/bridge.module.d.ts +0 -1
- package/dist/runtime/subsystems/bridge/bridge.module.js +294 -710
- package/dist/runtime/subsystems/bridge/bridge.module.js.map +1 -1
- package/dist/runtime/subsystems/bridge/index.d.ts +0 -1
- package/dist/runtime/subsystems/bridge/index.js +248 -664
- package/dist/runtime/subsystems/bridge/index.js.map +1 -1
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +18 -10
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/events/events.module.js +43 -244
- package/dist/runtime/subsystems/events/events.module.js.map +1 -1
- package/dist/runtime/subsystems/events/index.d.ts +0 -1
- package/dist/runtime/subsystems/events/index.js +39 -241
- package/dist/runtime/subsystems/events/index.js.map +1 -1
- package/dist/runtime/subsystems/index.js +174 -791
- package/dist/runtime/subsystems/index.js.map +1 -1
- package/dist/runtime/subsystems/jobs/bullmq.config.d.ts +22 -3
- package/dist/runtime/subsystems/jobs/bullmq.config.js.map +1 -1
- package/dist/runtime/subsystems/jobs/index.d.ts +1 -4
- package/dist/runtime/subsystems/jobs/index.js +87 -506
- package/dist/runtime/subsystems/jobs/index.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js +3 -0
- package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-worker.module.d.ts +11 -4
- package/dist/runtime/subsystems/jobs/job-worker.module.js +248 -664
- package/dist/runtime/subsystems/jobs/job-worker.module.js.map +1 -1
- package/dist/runtime/subsystems/jobs/jobs-domain.module.d.ts +0 -1
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js +89 -391
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js.map +1 -1
- package/dist/src/cli/index.js +1065 -440
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.js +26 -4
- package/dist/src/index.js.map +1 -1
- package/package.json +2 -1
- package/runtime/subsystems/events/event-bus.drizzle-backend.ts +32 -10
- package/runtime/subsystems/events/events.module.ts +38 -6
- package/runtime/subsystems/events/index.ts +7 -1
- package/runtime/subsystems/jobs/bullmq.config.ts +23 -3
- package/runtime/subsystems/jobs/index.ts +13 -8
- package/runtime/subsystems/jobs/job-worker.bullmq-backend.ts +5 -2
- package/runtime/subsystems/jobs/job-worker.module.ts +27 -7
- package/runtime/subsystems/jobs/jobs-domain.module.ts +27 -2
- package/templates/subsystem/events/domain-events.schema.ejs.t +43 -2
package/dist/src/cli/index.js
CHANGED
|
@@ -13,8 +13,8 @@ var __decorateParam = (index2, decorator) => (target, key) => decorator(target,
|
|
|
13
13
|
|
|
14
14
|
// src/cli/index.ts
|
|
15
15
|
import { readFileSync as readFileSync6 } from "fs";
|
|
16
|
-
import { join as
|
|
17
|
-
import { Builtins, Cli, Command as
|
|
16
|
+
import { join as join10 } from "path";
|
|
17
|
+
import { Builtins, Cli, Command as Command13 } from "clipanion";
|
|
18
18
|
|
|
19
19
|
// src/cli/noun-module.ts
|
|
20
20
|
import { Command, Option } from "clipanion";
|
|
@@ -24,13 +24,36 @@ import fs from "fs";
|
|
|
24
24
|
import path from "path";
|
|
25
25
|
import yaml from "yaml";
|
|
26
26
|
|
|
27
|
+
// src/utils/find-yaml-files.ts
|
|
28
|
+
import { readdirSync } from "fs";
|
|
29
|
+
import { join, resolve } from "path";
|
|
30
|
+
function isYaml(name) {
|
|
31
|
+
return name.endsWith(".yaml") || name.endsWith(".yml");
|
|
32
|
+
}
|
|
33
|
+
function findYamlFiles(dir) {
|
|
34
|
+
const root = resolve(dir);
|
|
35
|
+
const out = [];
|
|
36
|
+
const walk = (current) => {
|
|
37
|
+
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
38
|
+
if (entry.isDirectory()) {
|
|
39
|
+
if (entry.name.startsWith(".")) continue;
|
|
40
|
+
walk(join(current, entry.name));
|
|
41
|
+
} else if (isYaml(entry.name)) {
|
|
42
|
+
out.push(join(current, entry.name));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
walk(root);
|
|
47
|
+
return out.sort();
|
|
48
|
+
}
|
|
49
|
+
|
|
27
50
|
// src/scanner/index.ts
|
|
28
51
|
import { existsSync as existsSync5, statSync as statSync2 } from "fs";
|
|
29
|
-
import { join as
|
|
52
|
+
import { join as join7 } from "path";
|
|
30
53
|
|
|
31
54
|
// src/scanner/framework-detector.ts
|
|
32
|
-
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
33
|
-
import { join } from "path";
|
|
55
|
+
import { existsSync, readdirSync as readdirSync2, readFileSync } from "fs";
|
|
56
|
+
import { join as join2 } from "path";
|
|
34
57
|
var FRAMEWORK_MARKERS = {
|
|
35
58
|
nestjs: {
|
|
36
59
|
imports: [
|
|
@@ -87,12 +110,12 @@ var FRAMEWORK_MARKERS = {
|
|
|
87
110
|
function getAllTsFiles(dir, files = []) {
|
|
88
111
|
if (!existsSync(dir)) return files;
|
|
89
112
|
try {
|
|
90
|
-
const entries =
|
|
113
|
+
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
91
114
|
for (const entry of entries) {
|
|
92
115
|
if (entry.name === "node_modules" || entry.name.startsWith(".")) {
|
|
93
116
|
continue;
|
|
94
117
|
}
|
|
95
|
-
const fullPath =
|
|
118
|
+
const fullPath = join2(dir, entry.name);
|
|
96
119
|
if (entry.isDirectory()) {
|
|
97
120
|
getAllTsFiles(fullPath, files);
|
|
98
121
|
} else if (entry.isFile() && entry.name.endsWith(".ts")) {
|
|
@@ -177,15 +200,15 @@ async function detectFramework(projectPath) {
|
|
|
177
200
|
}
|
|
178
201
|
|
|
179
202
|
// src/scanner/orm-detector.ts
|
|
180
|
-
import { existsSync as existsSync2, readdirSync as
|
|
181
|
-
import { join as
|
|
203
|
+
import { existsSync as existsSync2, readdirSync as readdirSync3, readFileSync as readFileSync2 } from "fs";
|
|
204
|
+
import { join as join3 } from "path";
|
|
182
205
|
async function detectORM(projectPath) {
|
|
183
206
|
const markers = {
|
|
184
207
|
drizzle: [],
|
|
185
208
|
prisma: [],
|
|
186
209
|
typeorm: []
|
|
187
210
|
};
|
|
188
|
-
const prismaSchemaPath =
|
|
211
|
+
const prismaSchemaPath = join3(projectPath, "prisma", "schema.prisma");
|
|
189
212
|
if (existsSync2(prismaSchemaPath)) {
|
|
190
213
|
markers.prisma.push("prisma/schema.prisma");
|
|
191
214
|
}
|
|
@@ -265,12 +288,12 @@ function findTypeScriptFiles(dir, files = []) {
|
|
|
265
288
|
return files;
|
|
266
289
|
}
|
|
267
290
|
try {
|
|
268
|
-
const entries =
|
|
291
|
+
const entries = readdirSync3(dir, { withFileTypes: true });
|
|
269
292
|
for (const entry of entries) {
|
|
270
293
|
if (shouldSkip(entry.name)) {
|
|
271
294
|
continue;
|
|
272
295
|
}
|
|
273
|
-
const fullPath =
|
|
296
|
+
const fullPath = join3(dir, entry.name);
|
|
274
297
|
if (entry.isDirectory()) {
|
|
275
298
|
findTypeScriptFiles(fullPath, files);
|
|
276
299
|
} else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx"))) {
|
|
@@ -298,8 +321,8 @@ function shouldSkip(name) {
|
|
|
298
321
|
}
|
|
299
322
|
|
|
300
323
|
// src/scanner/architecture-detector.ts
|
|
301
|
-
import { readdirSync as
|
|
302
|
-
import { join as
|
|
324
|
+
import { readdirSync as readdirSync4, statSync } from "fs";
|
|
325
|
+
import { join as join4 } from "path";
|
|
303
326
|
async function detectArchitecture(projectPath) {
|
|
304
327
|
const scores = [
|
|
305
328
|
detectCleanArchitecture(projectPath),
|
|
@@ -356,7 +379,7 @@ function detectFeatureArchitecture(projectPath) {
|
|
|
356
379
|
const basePath = findFolder(projectPath, baseFolder);
|
|
357
380
|
if (basePath) {
|
|
358
381
|
try {
|
|
359
|
-
const subfolders =
|
|
382
|
+
const subfolders = readdirSync4(basePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => `${baseFolder}/${dirent.name}`);
|
|
360
383
|
if (subfolders.length > 0) {
|
|
361
384
|
matchedFolders.push(baseFolder);
|
|
362
385
|
matchedFolders.push(...subfolders.slice(0, 3));
|
|
@@ -406,8 +429,8 @@ function findMatchingFolders(projectPath, folderNames) {
|
|
|
406
429
|
}
|
|
407
430
|
function findFolder(projectPath, folderName) {
|
|
408
431
|
const candidates = [
|
|
409
|
-
|
|
410
|
-
|
|
432
|
+
join4(projectPath, folderName),
|
|
433
|
+
join4(projectPath, "src", folderName)
|
|
411
434
|
];
|
|
412
435
|
for (const candidate of candidates) {
|
|
413
436
|
try {
|
|
@@ -422,8 +445,8 @@ function findFolder(projectPath, folderName) {
|
|
|
422
445
|
}
|
|
423
446
|
|
|
424
447
|
// src/scanner/naming-detector.ts
|
|
425
|
-
import { existsSync as existsSync3, readdirSync as
|
|
426
|
-
import { basename, join as
|
|
448
|
+
import { existsSync as existsSync3, readdirSync as readdirSync5, readFileSync as readFileSync3 } from "fs";
|
|
449
|
+
import { basename, join as join5 } from "path";
|
|
427
450
|
var CASE_PATTERNS = {
|
|
428
451
|
"kebab-case": /^[a-z]+(-[a-z0-9]+)*$/,
|
|
429
452
|
"camelCase": /^[a-z]+([A-Z][a-z0-9]*)*$/,
|
|
@@ -452,12 +475,12 @@ var COMMON_SUFFIXES = [
|
|
|
452
475
|
function getAllTsFiles2(dir, files = []) {
|
|
453
476
|
if (!existsSync3(dir)) return files;
|
|
454
477
|
try {
|
|
455
|
-
const entries =
|
|
478
|
+
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
456
479
|
for (const entry of entries) {
|
|
457
480
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage" || entry.name.startsWith(".")) {
|
|
458
481
|
continue;
|
|
459
482
|
}
|
|
460
|
-
const fullPath =
|
|
483
|
+
const fullPath = join5(dir, entry.name);
|
|
461
484
|
if (entry.isDirectory()) {
|
|
462
485
|
getAllTsFiles2(fullPath, files);
|
|
463
486
|
} else if (entry.isFile() && entry.name.endsWith(".ts")) {
|
|
@@ -617,7 +640,7 @@ async function detectNaming(projectPath) {
|
|
|
617
640
|
|
|
618
641
|
// src/scanner/config-generator.ts
|
|
619
642
|
import { existsSync as existsSync4 } from "fs";
|
|
620
|
-
import { join as
|
|
643
|
+
import { join as join6 } from "path";
|
|
621
644
|
function generateConfig(profile) {
|
|
622
645
|
const framework = profile.framework.detected;
|
|
623
646
|
const orm = profile.orm.detected;
|
|
@@ -640,7 +663,7 @@ function generateConfig(profile) {
|
|
|
640
663
|
}
|
|
641
664
|
function buildGenerateConfig(profile, paths) {
|
|
642
665
|
const explicitFrontendSrc = typeof paths.frontend_src === "string" && paths.frontend_src.length > 0;
|
|
643
|
-
const appsFrontendExists = existsSync4(
|
|
666
|
+
const appsFrontendExists = existsSync4(join6(profile.paths.root, "apps", "frontend"));
|
|
644
667
|
return {
|
|
645
668
|
architecture: "clean",
|
|
646
669
|
frontend: explicitFrontendSrc || appsFrontendExists
|
|
@@ -806,7 +829,7 @@ function calculateConfidence(profile) {
|
|
|
806
829
|
function findSrcDirectory(projectPath) {
|
|
807
830
|
const candidates = ["src", "app", "lib"];
|
|
808
831
|
for (const candidate of candidates) {
|
|
809
|
-
const fullPath =
|
|
832
|
+
const fullPath = join7(projectPath, candidate);
|
|
810
833
|
try {
|
|
811
834
|
const stats = statSync2(fullPath);
|
|
812
835
|
if (stats.isDirectory()) {
|
|
@@ -878,7 +901,7 @@ function resolveEntitiesDir(cwd, config) {
|
|
|
878
901
|
function countEntityYamls(entitiesDir) {
|
|
879
902
|
if (!entitiesDir || !fs.existsSync(entitiesDir)) return 0;
|
|
880
903
|
try {
|
|
881
|
-
return
|
|
904
|
+
return findYamlFiles(entitiesDir).length;
|
|
882
905
|
} catch {
|
|
883
906
|
return 0;
|
|
884
907
|
}
|
|
@@ -986,13 +1009,13 @@ function renderPane(pane) {
|
|
|
986
1009
|
}
|
|
987
1010
|
|
|
988
1011
|
// src/cli/ui/hints.ts
|
|
989
|
-
function renderHints(
|
|
1012
|
+
function renderHints(hints10) {
|
|
990
1013
|
if (isJsonMode()) return;
|
|
991
|
-
if (
|
|
1014
|
+
if (hints10.length === 0) return;
|
|
992
1015
|
console.log("");
|
|
993
1016
|
console.log(theme.muted(" Next:"));
|
|
994
|
-
const maxCmd = Math.max(...
|
|
995
|
-
for (const h of
|
|
1017
|
+
const maxCmd = Math.max(...hints10.map((h) => h.command.length));
|
|
1018
|
+
for (const h of hints10) {
|
|
996
1019
|
const pad = " ".repeat(maxCmd - h.command.length + 2);
|
|
997
1020
|
console.log(` ${theme.system(h.command)}${pad}${theme.muted(h.description)}`);
|
|
998
1021
|
}
|
|
@@ -1017,13 +1040,13 @@ function buildNounSummaryCommand(noun) {
|
|
|
1017
1040
|
json: this.json,
|
|
1018
1041
|
verbose: this.verbose
|
|
1019
1042
|
});
|
|
1020
|
-
const [pane,
|
|
1043
|
+
const [pane, hints10] = await Promise.all([noun.summary(ctx), noun.hints(ctx)]);
|
|
1021
1044
|
if (isJsonMode()) {
|
|
1022
|
-
printJson({ noun: noun.name, summary: pane, hints:
|
|
1045
|
+
printJson({ noun: noun.name, summary: pane, hints: hints10 });
|
|
1023
1046
|
return 0;
|
|
1024
1047
|
}
|
|
1025
1048
|
renderPane(pane);
|
|
1026
|
-
renderHints(
|
|
1049
|
+
renderHints(hints10);
|
|
1027
1050
|
return 0;
|
|
1028
1051
|
}
|
|
1029
1052
|
}
|
|
@@ -2935,8 +2958,8 @@ function loadEntityFromYaml(filePath) {
|
|
|
2935
2958
|
}
|
|
2936
2959
|
function formatZodErrors(error) {
|
|
2937
2960
|
return error.errors.map((err) => {
|
|
2938
|
-
const
|
|
2939
|
-
const location =
|
|
2961
|
+
const path34 = err.path.join(".");
|
|
2962
|
+
const location = path34 ? `at '${path34}'` : "at root";
|
|
2940
2963
|
return `${err.message} ${location}`;
|
|
2941
2964
|
});
|
|
2942
2965
|
}
|
|
@@ -3091,8 +3114,7 @@ function detectYamlType(filePath) {
|
|
|
3091
3114
|
}
|
|
3092
3115
|
|
|
3093
3116
|
// src/parser/load-entities.ts
|
|
3094
|
-
import {
|
|
3095
|
-
import { join as join7, resolve } from "path";
|
|
3117
|
+
import { resolve as resolve2 } from "path";
|
|
3096
3118
|
function transformToEntity(result) {
|
|
3097
3119
|
const { definition, filePath } = result;
|
|
3098
3120
|
const queries = definition.queries?.filter((q) => "by" in q).map((q) => ({
|
|
@@ -3224,10 +3246,10 @@ function loadErrorToIssue(error) {
|
|
|
3224
3246
|
function loadEntities(entitiesDir) {
|
|
3225
3247
|
const entities = [];
|
|
3226
3248
|
const issues = [];
|
|
3227
|
-
const resolvedDir =
|
|
3249
|
+
const resolvedDir = resolve2(entitiesDir);
|
|
3228
3250
|
let files;
|
|
3229
3251
|
try {
|
|
3230
|
-
files =
|
|
3252
|
+
files = findYamlFiles(resolvedDir);
|
|
3231
3253
|
} catch (err) {
|
|
3232
3254
|
issues.push({
|
|
3233
3255
|
severity: "error",
|
|
@@ -3272,19 +3294,19 @@ function resolveReferences(entities) {
|
|
|
3272
3294
|
entityMap.set(entity.name, entity);
|
|
3273
3295
|
}
|
|
3274
3296
|
for (const entity of entities) {
|
|
3275
|
-
for (const [relName,
|
|
3276
|
-
const targetEntity = entityMap.get(
|
|
3297
|
+
for (const [relName, rel2] of entity.relationships) {
|
|
3298
|
+
const targetEntity = entityMap.get(rel2.target);
|
|
3277
3299
|
if (targetEntity) {
|
|
3278
|
-
|
|
3300
|
+
rel2.resolved = true;
|
|
3279
3301
|
} else {
|
|
3280
3302
|
issues.push({
|
|
3281
3303
|
severity: "error",
|
|
3282
3304
|
type: "missing_target",
|
|
3283
3305
|
entity: entity.name,
|
|
3284
3306
|
field: relName,
|
|
3285
|
-
message: `Relationship '${relName}' references unknown entity '${
|
|
3307
|
+
message: `Relationship '${relName}' references unknown entity '${rel2.target}'`,
|
|
3286
3308
|
path: entity.sourcePath,
|
|
3287
|
-
suggestion: `Define entity '${
|
|
3309
|
+
suggestion: `Define entity '${rel2.target}' or fix the target name`
|
|
3288
3310
|
});
|
|
3289
3311
|
}
|
|
3290
3312
|
}
|
|
@@ -3397,10 +3419,10 @@ function resolveTypeDirections(types) {
|
|
|
3397
3419
|
function loadRelationships(relationshipsDir) {
|
|
3398
3420
|
const relationships = [];
|
|
3399
3421
|
const issues = [];
|
|
3400
|
-
const resolvedDir =
|
|
3422
|
+
const resolvedDir = resolve2(relationshipsDir);
|
|
3401
3423
|
let files;
|
|
3402
3424
|
try {
|
|
3403
|
-
files =
|
|
3425
|
+
files = findYamlFiles(resolvedDir);
|
|
3404
3426
|
} catch {
|
|
3405
3427
|
return { relationships, issues };
|
|
3406
3428
|
}
|
|
@@ -3482,14 +3504,14 @@ function buildDomainGraph(entities, relationshipDefinitions = []) {
|
|
|
3482
3504
|
relDefMap.set(relDef.name, relDef);
|
|
3483
3505
|
}
|
|
3484
3506
|
for (const entity of entities) {
|
|
3485
|
-
for (const [relName,
|
|
3486
|
-
if (!
|
|
3487
|
-
const reverseEdge = hasReverseEdge(edges, entity.name,
|
|
3507
|
+
for (const [relName, rel2] of entity.relationships) {
|
|
3508
|
+
if (!rel2.resolved) continue;
|
|
3509
|
+
const reverseEdge = hasReverseEdge(edges, entity.name, rel2.target);
|
|
3488
3510
|
const edge = {
|
|
3489
3511
|
from: entity.name,
|
|
3490
|
-
to:
|
|
3491
|
-
relationship:
|
|
3492
|
-
cardinality: inferCardinality(
|
|
3512
|
+
to: rel2.target,
|
|
3513
|
+
relationship: rel2,
|
|
3514
|
+
cardinality: inferCardinality(rel2.type),
|
|
3493
3515
|
bidirectional: reverseEdge !== void 0
|
|
3494
3516
|
};
|
|
3495
3517
|
if (reverseEdge) {
|
|
@@ -3534,19 +3556,19 @@ function findCircularDependencies(graph) {
|
|
|
3534
3556
|
const cycles = [];
|
|
3535
3557
|
const visited = /* @__PURE__ */ new Set();
|
|
3536
3558
|
const recursionStack = /* @__PURE__ */ new Set();
|
|
3537
|
-
function dfs(node,
|
|
3559
|
+
function dfs(node, path34) {
|
|
3538
3560
|
visited.add(node);
|
|
3539
3561
|
recursionStack.add(node);
|
|
3540
3562
|
const outgoingEdges = graph.edges.filter((e) => e.from === node);
|
|
3541
3563
|
for (const edge of outgoingEdges) {
|
|
3542
3564
|
if (!visited.has(edge.to)) {
|
|
3543
|
-
dfs(edge.to, [...
|
|
3565
|
+
dfs(edge.to, [...path34, edge.to]);
|
|
3544
3566
|
} else if (recursionStack.has(edge.to)) {
|
|
3545
|
-
const cycleStart =
|
|
3567
|
+
const cycleStart = path34.indexOf(edge.to);
|
|
3546
3568
|
if (cycleStart !== -1) {
|
|
3547
|
-
cycles.push([...
|
|
3569
|
+
cycles.push([...path34.slice(cycleStart), edge.to]);
|
|
3548
3570
|
} else {
|
|
3549
|
-
cycles.push([...
|
|
3571
|
+
cycles.push([...path34, edge.to]);
|
|
3550
3572
|
}
|
|
3551
3573
|
}
|
|
3552
3574
|
}
|
|
@@ -3847,32 +3869,32 @@ function checkEntityConsistency(entity) {
|
|
|
3847
3869
|
}
|
|
3848
3870
|
function checkRelationshipConsistency(entity, graph) {
|
|
3849
3871
|
const issues = [];
|
|
3850
|
-
for (const [relName,
|
|
3851
|
-
if (
|
|
3852
|
-
const fkField = entity.fields.get(
|
|
3872
|
+
for (const [relName, rel2] of entity.relationships) {
|
|
3873
|
+
if (rel2.type === "belongs_to") {
|
|
3874
|
+
const fkField = entity.fields.get(rel2.foreignKey);
|
|
3853
3875
|
if (!fkField) {
|
|
3854
3876
|
issues.push({
|
|
3855
3877
|
severity: "warning",
|
|
3856
3878
|
type: "missing_fk_field",
|
|
3857
3879
|
entity: entity.name,
|
|
3858
3880
|
field: relName,
|
|
3859
|
-
message: `Relationship "${relName}" references foreign key "${
|
|
3860
|
-
suggestion: `Add field "${
|
|
3881
|
+
message: `Relationship "${relName}" references foreign key "${rel2.foreignKey}" but field doesn't exist`,
|
|
3882
|
+
suggestion: `Add field "${rel2.foreignKey}" with foreign_key reference`
|
|
3861
3883
|
});
|
|
3862
3884
|
}
|
|
3863
3885
|
}
|
|
3864
|
-
if (
|
|
3865
|
-
const targetEntity = graph.entities.get(
|
|
3886
|
+
if (rel2.type === "has_many" || rel2.type === "has_one") {
|
|
3887
|
+
const targetEntity = graph.entities.get(rel2.target);
|
|
3866
3888
|
if (targetEntity) {
|
|
3867
|
-
const targetFkField = targetEntity.fields.get(
|
|
3889
|
+
const targetFkField = targetEntity.fields.get(rel2.foreignKey);
|
|
3868
3890
|
if (!targetFkField) {
|
|
3869
3891
|
issues.push({
|
|
3870
3892
|
severity: "warning",
|
|
3871
3893
|
type: "missing_target_fk",
|
|
3872
3894
|
entity: entity.name,
|
|
3873
3895
|
field: relName,
|
|
3874
|
-
message: `Relationship "${relName}" expects foreign key "${
|
|
3875
|
-
suggestion: `Add field "${
|
|
3896
|
+
message: `Relationship "${relName}" expects foreign key "${rel2.foreignKey}" on "${rel2.target}" but field doesn't exist`,
|
|
3897
|
+
suggestion: `Add field "${rel2.foreignKey}" to "${rel2.target}" entity`
|
|
3876
3898
|
});
|
|
3877
3899
|
}
|
|
3878
3900
|
}
|
|
@@ -3989,7 +4011,7 @@ function checkMissingInverses(graph) {
|
|
|
3989
4011
|
const targetEntity = graph.entities.get(to);
|
|
3990
4012
|
if (!targetEntity) continue;
|
|
3991
4013
|
const hasInverse = Array.from(targetEntity.relationships.values()).some(
|
|
3992
|
-
(
|
|
4014
|
+
(rel2) => rel2.target === from
|
|
3993
4015
|
);
|
|
3994
4016
|
if (!hasInverse && relationship.type !== "belongs_to") {
|
|
3995
4017
|
issues.push({
|
|
@@ -4009,9 +4031,9 @@ function getAvailableFieldNames(entity) {
|
|
|
4009
4031
|
const behaviorFields = resolveBehaviorFields(entity.behaviors);
|
|
4010
4032
|
const behaviorFieldNames = behaviorFields.map((f) => f.name);
|
|
4011
4033
|
const belongsToFkNames = [];
|
|
4012
|
-
for (const
|
|
4013
|
-
if (
|
|
4014
|
-
belongsToFkNames.push(
|
|
4034
|
+
for (const rel2 of entity.relationships.values()) {
|
|
4035
|
+
if (rel2.type === "belongs_to" && rel2.foreignKey) {
|
|
4036
|
+
belongsToFkNames.push(rel2.foreignKey);
|
|
4015
4037
|
}
|
|
4016
4038
|
}
|
|
4017
4039
|
return [.../* @__PURE__ */ new Set([...entityFieldNames, ...behaviorFieldNames, ...belongsToFkNames])];
|
|
@@ -4116,8 +4138,8 @@ function computeStatistics(graph) {
|
|
|
4116
4138
|
for (const field of entity.fields.values()) {
|
|
4117
4139
|
fieldsByType[field.type] = (fieldsByType[field.type] ?? 0) + 1;
|
|
4118
4140
|
}
|
|
4119
|
-
for (const
|
|
4120
|
-
relationshipsByType[
|
|
4141
|
+
for (const rel2 of entity.relationships.values()) {
|
|
4142
|
+
relationshipsByType[rel2.type] = (relationshipsByType[rel2.type] ?? 0) + 1;
|
|
4121
4143
|
}
|
|
4122
4144
|
}
|
|
4123
4145
|
return {
|
|
@@ -4143,8 +4165,8 @@ function suggestTransitiveRelationships(graph, options) {
|
|
|
4143
4165
|
for (const [entityName, entity] of graph.entities) {
|
|
4144
4166
|
if (shouldExcludeEntity(entityName, opts)) continue;
|
|
4145
4167
|
const paths = findTransitivePaths(graph, entityName, opts);
|
|
4146
|
-
for (const
|
|
4147
|
-
suggestions.push(createSuggestion(
|
|
4168
|
+
for (const path34 of paths) {
|
|
4169
|
+
suggestions.push(createSuggestion(path34));
|
|
4148
4170
|
}
|
|
4149
4171
|
}
|
|
4150
4172
|
return suggestions;
|
|
@@ -4175,22 +4197,22 @@ function findTransitivePaths(graph, sourceEntity, opts) {
|
|
|
4175
4197
|
while (queue.length > 0) {
|
|
4176
4198
|
const current = queue.shift();
|
|
4177
4199
|
if (!current) continue;
|
|
4178
|
-
const { entity, depth, path:
|
|
4200
|
+
const { entity, depth, path: path34, visited } = current;
|
|
4179
4201
|
if (depth >= opts.maxDepth) continue;
|
|
4180
4202
|
const currentEntity = graph.entities.get(entity);
|
|
4181
4203
|
if (!currentEntity) continue;
|
|
4182
|
-
for (const [relName,
|
|
4183
|
-
if (
|
|
4184
|
-
if (
|
|
4185
|
-
const target =
|
|
4204
|
+
for (const [relName, rel2] of currentEntity.relationships) {
|
|
4205
|
+
if (rel2.through) continue;
|
|
4206
|
+
if (rel2.type !== "has_many" && rel2.type !== "has_one") continue;
|
|
4207
|
+
const target = rel2.target;
|
|
4186
4208
|
if (shouldExcludeEntity(target, opts)) continue;
|
|
4187
4209
|
if (visited.has(target)) continue;
|
|
4188
4210
|
const newPath = [
|
|
4189
|
-
...
|
|
4211
|
+
...path34,
|
|
4190
4212
|
{
|
|
4191
4213
|
via: entity,
|
|
4192
4214
|
relationship: relName,
|
|
4193
|
-
foreignKey:
|
|
4215
|
+
foreignKey: rel2.foreignKey
|
|
4194
4216
|
}
|
|
4195
4217
|
];
|
|
4196
4218
|
if (depth >= 1) {
|
|
@@ -4218,8 +4240,8 @@ function findTransitivePaths(graph, sourceEntity, opts) {
|
|
|
4218
4240
|
return paths;
|
|
4219
4241
|
}
|
|
4220
4242
|
function hasDirectRelationship(sourceEntity, targetName) {
|
|
4221
|
-
for (const
|
|
4222
|
-
if (
|
|
4243
|
+
for (const rel2 of sourceEntity.relationships.values()) {
|
|
4244
|
+
if (rel2.target === targetName && !rel2.through) {
|
|
4223
4245
|
return true;
|
|
4224
4246
|
}
|
|
4225
4247
|
}
|
|
@@ -4254,15 +4276,15 @@ function generateYamlSnippet(name, target, throughPath) {
|
|
|
4254
4276
|
target: ${target}
|
|
4255
4277
|
through: "${throughPath}"`;
|
|
4256
4278
|
}
|
|
4257
|
-
function createSuggestion(
|
|
4258
|
-
const pathDescription = [
|
|
4279
|
+
function createSuggestion(path34) {
|
|
4280
|
+
const pathDescription = [path34.source, ...path34.hops.map((h) => h.via), path34.target].join(" -> ");
|
|
4259
4281
|
return {
|
|
4260
4282
|
severity: "info",
|
|
4261
4283
|
type: "transitive_suggestion",
|
|
4262
|
-
entity:
|
|
4284
|
+
entity: path34.source,
|
|
4263
4285
|
message: `Potential transitive relationship: ${pathDescription}`,
|
|
4264
|
-
suggestion: `Add "${
|
|
4265
|
-
path:
|
|
4286
|
+
suggestion: `Add "${path34.suggestedName}" relationship via "${path34.throughPath}"`,
|
|
4287
|
+
path: path34
|
|
4266
4288
|
};
|
|
4267
4289
|
}
|
|
4268
4290
|
|
|
@@ -4354,13 +4376,13 @@ function toManifestEntity(entity) {
|
|
|
4354
4376
|
};
|
|
4355
4377
|
}
|
|
4356
4378
|
const relationships = {};
|
|
4357
|
-
for (const [name,
|
|
4379
|
+
for (const [name, rel2] of entity.relationships) {
|
|
4358
4380
|
relationships[name] = {
|
|
4359
|
-
type:
|
|
4360
|
-
target:
|
|
4361
|
-
foreignKey:
|
|
4362
|
-
through:
|
|
4363
|
-
inverse:
|
|
4381
|
+
type: rel2.type,
|
|
4382
|
+
target: rel2.target,
|
|
4383
|
+
foreignKey: rel2.foreignKey,
|
|
4384
|
+
through: rel2.through,
|
|
4385
|
+
inverse: rel2.inverse
|
|
4364
4386
|
};
|
|
4365
4387
|
}
|
|
4366
4388
|
return {
|
|
@@ -5332,8 +5354,8 @@ function formatEntitySection(entity) {
|
|
|
5332
5354
|
lines.push("");
|
|
5333
5355
|
lines.push("| Name | Type | Target | Foreign Key |");
|
|
5334
5356
|
lines.push("|------|------|--------|-------------|");
|
|
5335
|
-
for (const [name,
|
|
5336
|
-
lines.push(`| ${name} | ${
|
|
5357
|
+
for (const [name, rel2] of entity.relationships) {
|
|
5358
|
+
lines.push(`| ${name} | ${rel2.type} | ${rel2.target} | ${rel2.foreignKey} |`);
|
|
5337
5359
|
}
|
|
5338
5360
|
lines.push("");
|
|
5339
5361
|
}
|
|
@@ -5665,7 +5687,7 @@ function toKebabCase(input) {
|
|
|
5665
5687
|
}
|
|
5666
5688
|
function listEntityYamls(entitiesDir) {
|
|
5667
5689
|
if (!fs2.existsSync(entitiesDir)) return [];
|
|
5668
|
-
return
|
|
5690
|
+
return findYamlFiles(entitiesDir);
|
|
5669
5691
|
}
|
|
5670
5692
|
function collectEntities(entitiesDir) {
|
|
5671
5693
|
const files = listEntityYamls(entitiesDir);
|
|
@@ -5684,7 +5706,9 @@ function collectEntities(entitiesDir) {
|
|
|
5684
5706
|
}
|
|
5685
5707
|
function listRelationshipYamls(relationshipsDir) {
|
|
5686
5708
|
if (!fs2.existsSync(relationshipsDir)) return [];
|
|
5687
|
-
return
|
|
5709
|
+
return findYamlFiles(relationshipsDir).filter(
|
|
5710
|
+
(full) => detectYamlType(full) === "relationship"
|
|
5711
|
+
);
|
|
5688
5712
|
}
|
|
5689
5713
|
function collectRelationships(relationshipsDir) {
|
|
5690
5714
|
const files = listRelationshipYamls(relationshipsDir);
|
|
@@ -5692,9 +5716,9 @@ function collectRelationships(relationshipsDir) {
|
|
|
5692
5716
|
for (const file of files) {
|
|
5693
5717
|
const result = loadRelationshipFromYaml(file);
|
|
5694
5718
|
if (!result.success) continue;
|
|
5695
|
-
const
|
|
5696
|
-
const name =
|
|
5697
|
-
const plural =
|
|
5719
|
+
const rel2 = result.definition.relationship;
|
|
5720
|
+
const name = rel2.name;
|
|
5721
|
+
const plural = rel2.table ?? pluralize(name);
|
|
5698
5722
|
junctions.push({ name, plural });
|
|
5699
5723
|
}
|
|
5700
5724
|
junctions.sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -5702,7 +5726,9 @@ function collectRelationships(relationshipsDir) {
|
|
|
5702
5726
|
}
|
|
5703
5727
|
function listJunctionYamls(junctionsDir) {
|
|
5704
5728
|
if (!fs2.existsSync(junctionsDir)) return [];
|
|
5705
|
-
return
|
|
5729
|
+
return findYamlFiles(junctionsDir).filter(
|
|
5730
|
+
(full) => detectYamlType(full) === "junction"
|
|
5731
|
+
);
|
|
5706
5732
|
}
|
|
5707
5733
|
function deriveJunctionName(def) {
|
|
5708
5734
|
return def.name ?? `${def.between[0]}_${def.between[1]}`;
|
|
@@ -5747,9 +5773,9 @@ var HEADER = `// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.
|
|
|
5747
5773
|
`;
|
|
5748
5774
|
function relativeImport(fromFile, toFile) {
|
|
5749
5775
|
const fromDir = path4.posix.dirname(fromFile);
|
|
5750
|
-
let
|
|
5751
|
-
if (!
|
|
5752
|
-
return
|
|
5776
|
+
let rel2 = path4.posix.relative(fromDir, toFile);
|
|
5777
|
+
if (!rel2.startsWith(".")) rel2 = `./${rel2}`;
|
|
5778
|
+
return rel2.replace(/\.ts$/, "");
|
|
5753
5779
|
}
|
|
5754
5780
|
function buildModulesBarrel(entities, barrelFile, architecture, backendSrc = "app/backend/src") {
|
|
5755
5781
|
const imports = [];
|
|
@@ -5836,8 +5862,8 @@ function resolveArchitecture(ctx) {
|
|
|
5836
5862
|
}
|
|
5837
5863
|
function resolveGeneratedDir(ctx) {
|
|
5838
5864
|
const fromConfig = ctx.config?.paths?.generated;
|
|
5839
|
-
const
|
|
5840
|
-
return path4.resolve(ctx.cwd,
|
|
5865
|
+
const rel2 = typeof fromConfig === "string" && fromConfig.length > 0 ? fromConfig : "src/generated";
|
|
5866
|
+
return path4.resolve(ctx.cwd, rel2);
|
|
5841
5867
|
}
|
|
5842
5868
|
function resolveBackendSrc(ctx) {
|
|
5843
5869
|
const fromConfig = ctx.config?.paths?.backend_src;
|
|
@@ -5852,7 +5878,7 @@ var HEADER2 = `// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.
|
|
|
5852
5878
|
`;
|
|
5853
5879
|
function collectScopeableNames(entitiesDir) {
|
|
5854
5880
|
if (!fs3.existsSync(entitiesDir)) return [];
|
|
5855
|
-
const files =
|
|
5881
|
+
const files = findYamlFiles(entitiesDir);
|
|
5856
5882
|
const names = [];
|
|
5857
5883
|
for (const file of files) {
|
|
5858
5884
|
const result = loadEntityFromYaml(file);
|
|
@@ -5986,6 +6012,19 @@ var SUBSYSTEMS = [
|
|
|
5986
6012
|
}
|
|
5987
6013
|
];
|
|
5988
6014
|
var KNOWN_NAMES = SUBSYSTEMS.map((s) => s.name);
|
|
6015
|
+
var SUBSYSTEM_MODULE_FILE = {
|
|
6016
|
+
events: "events.module.ts",
|
|
6017
|
+
jobs: "jobs-domain.module.ts",
|
|
6018
|
+
cache: "cache.module.ts",
|
|
6019
|
+
storage: "storage.module.ts",
|
|
6020
|
+
sync: "sync.module.ts",
|
|
6021
|
+
bridge: "bridge.module.ts",
|
|
6022
|
+
observability: "observability.module.ts",
|
|
6023
|
+
auth: "auth.module.ts"
|
|
6024
|
+
};
|
|
6025
|
+
function subsystemModuleFile(name) {
|
|
6026
|
+
return SUBSYSTEM_MODULE_FILE[name] ?? null;
|
|
6027
|
+
}
|
|
5989
6028
|
function candidateRoots(cwd, configured) {
|
|
5990
6029
|
const roots = [
|
|
5991
6030
|
...configured ? [path6.resolve(cwd, configured)] : [],
|
|
@@ -6008,7 +6047,7 @@ function inferBackend(dir, name) {
|
|
|
6008
6047
|
if (hasMemory) return "memory";
|
|
6009
6048
|
return "unknown";
|
|
6010
6049
|
}
|
|
6011
|
-
async function
|
|
6050
|
+
async function detectSubsystemStatesImpl(ctx) {
|
|
6012
6051
|
const configured = ctx.config?.paths?.subsystems;
|
|
6013
6052
|
const roots = candidateRoots(ctx.cwd, configured);
|
|
6014
6053
|
const found = [];
|
|
@@ -6022,16 +6061,16 @@ async function detectInstalledSubsystems(ctx) {
|
|
|
6022
6061
|
const dir = path6.join(root, name);
|
|
6023
6062
|
if (!fs4.existsSync(dir) || !fs4.statSync(dir).isDirectory()) continue;
|
|
6024
6063
|
const files = fs4.readdirSync(dir);
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
if (!hasProtocol) continue;
|
|
6064
|
+
const moduleFile = subsystemModuleFile(name);
|
|
6065
|
+
const hasModule = moduleFile ? files.includes(moduleFile) : false;
|
|
6066
|
+
const present = name === "auth" ? hasModule : files.some((f) => f.endsWith(".protocol.ts")) || hasModule;
|
|
6067
|
+
if (!present) continue;
|
|
6030
6068
|
seen.add(name);
|
|
6031
6069
|
found.push({
|
|
6032
6070
|
name,
|
|
6033
6071
|
path: dir,
|
|
6034
|
-
backend: inferBackend(dir, name)
|
|
6072
|
+
backend: inferBackend(dir, name),
|
|
6073
|
+
status: hasModule ? "installed" : "incomplete"
|
|
6035
6074
|
});
|
|
6036
6075
|
}
|
|
6037
6076
|
}
|
|
@@ -6047,7 +6086,8 @@ async function detectInstalledSubsystems(ctx) {
|
|
|
6047
6086
|
found.push({
|
|
6048
6087
|
name: "openapi-config",
|
|
6049
6088
|
path: configPath,
|
|
6050
|
-
backend: "config-only"
|
|
6089
|
+
backend: "config-only",
|
|
6090
|
+
status: "installed"
|
|
6051
6091
|
});
|
|
6052
6092
|
}
|
|
6053
6093
|
} catch {
|
|
@@ -6070,7 +6110,8 @@ async function detectInstalledSubsystems(ctx) {
|
|
|
6070
6110
|
found.push({
|
|
6071
6111
|
name: "auth-integrations",
|
|
6072
6112
|
path: path6.dirname(moduleFile),
|
|
6073
|
-
backend: "drizzle"
|
|
6113
|
+
backend: "drizzle",
|
|
6114
|
+
status: "installed"
|
|
6074
6115
|
});
|
|
6075
6116
|
break;
|
|
6076
6117
|
}
|
|
@@ -6078,6 +6119,13 @@ async function detectInstalledSubsystems(ctx) {
|
|
|
6078
6119
|
}
|
|
6079
6120
|
return found;
|
|
6080
6121
|
}
|
|
6122
|
+
async function detectSubsystemStates(ctx) {
|
|
6123
|
+
return detectSubsystemStatesImpl(ctx);
|
|
6124
|
+
}
|
|
6125
|
+
async function detectInstalledSubsystems(ctx) {
|
|
6126
|
+
const states = await detectSubsystemStatesImpl(ctx);
|
|
6127
|
+
return states.filter((s) => s.status === "installed");
|
|
6128
|
+
}
|
|
6081
6129
|
|
|
6082
6130
|
// src/cli/shared/subsystems-path.ts
|
|
6083
6131
|
import path7 from "path";
|
|
@@ -6197,7 +6245,8 @@ var HEADER3 = `// AUTO-GENERATED by @pattern-stack/codegen. DO NOT EDIT.
|
|
|
6197
6245
|
|
|
6198
6246
|
`;
|
|
6199
6247
|
function buildSubsystemBarrel(installed, config, subsystemsRel) {
|
|
6200
|
-
const
|
|
6248
|
+
const actable = installed.filter((i) => i.status !== "incomplete");
|
|
6249
|
+
const installedNames = new Set(actable.map((i) => i.name));
|
|
6201
6250
|
const emitted = [];
|
|
6202
6251
|
const skipped = [];
|
|
6203
6252
|
const allImports = [`import type { DynamicModule } from '@nestjs/common';`];
|
|
@@ -6215,25 +6264,17 @@ function buildSubsystemBarrel(installed, config, subsystemsRel) {
|
|
|
6215
6264
|
allCalls.push(...out.calls);
|
|
6216
6265
|
emitted.push(name);
|
|
6217
6266
|
}
|
|
6218
|
-
for (const inst of
|
|
6267
|
+
for (const inst of actable) {
|
|
6219
6268
|
if (!COMPOSABLE_ORDER.includes(inst.name) && !COMPOSERS[inst.name]) {
|
|
6220
6269
|
skipped.push(inst.name);
|
|
6221
6270
|
}
|
|
6222
6271
|
}
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
content: HEADER3 + `export const SUBSYSTEM_MODULES: DynamicModule[] = [];
|
|
6226
|
-
`,
|
|
6227
|
-
emitted,
|
|
6228
|
-
skipped
|
|
6229
|
-
};
|
|
6230
|
-
}
|
|
6231
|
-
const body = allImports.join("\n") + `
|
|
6232
|
-
|
|
6233
|
-
export const SUBSYSTEM_MODULES: DynamicModule[] = [
|
|
6272
|
+
const exportLine = allCalls.length === 0 ? `export const SUBSYSTEM_MODULES: DynamicModule[] = [];
|
|
6273
|
+
` : `export const SUBSYSTEM_MODULES: DynamicModule[] = [
|
|
6234
6274
|
${allCalls.join("\n")}
|
|
6235
6275
|
];
|
|
6236
6276
|
`;
|
|
6277
|
+
const body = allImports.join("\n") + "\n\n" + exportLine;
|
|
6237
6278
|
return { content: HEADER3 + body, emitted, skipped };
|
|
6238
6279
|
}
|
|
6239
6280
|
async function regenerateSubsystemBarrel(opts) {
|
|
@@ -7042,8 +7083,7 @@ import fs8 from "fs";
|
|
|
7042
7083
|
import path11 from "path";
|
|
7043
7084
|
|
|
7044
7085
|
// src/parser/load-events.ts
|
|
7045
|
-
import {
|
|
7046
|
-
import { basename as basename2, join as join10, resolve as resolve2 } from "path";
|
|
7086
|
+
import { basename as basename2, resolve as resolve3 } from "path";
|
|
7047
7087
|
function loadErrorToIssue2(error) {
|
|
7048
7088
|
const issues = [];
|
|
7049
7089
|
issues.push({
|
|
@@ -7073,10 +7113,10 @@ function stripYamlExt(file) {
|
|
|
7073
7113
|
function loadEvents(eventsDir, entityNames) {
|
|
7074
7114
|
const events = [];
|
|
7075
7115
|
const issues = [];
|
|
7076
|
-
const resolvedDir =
|
|
7116
|
+
const resolvedDir = resolve3(eventsDir);
|
|
7077
7117
|
let files;
|
|
7078
7118
|
try {
|
|
7079
|
-
files =
|
|
7119
|
+
files = findYamlFiles(resolvedDir);
|
|
7080
7120
|
} catch {
|
|
7081
7121
|
issues.push({
|
|
7082
7122
|
severity: "warning",
|
|
@@ -7227,7 +7267,7 @@ function collectEntityEvents(entitiesDir) {
|
|
|
7227
7267
|
if (!fs8.existsSync(entitiesDir)) {
|
|
7228
7268
|
return { events, issues };
|
|
7229
7269
|
}
|
|
7230
|
-
const files =
|
|
7270
|
+
const files = findYamlFiles(entitiesDir);
|
|
7231
7271
|
for (const filePath of files) {
|
|
7232
7272
|
const result = loadEntityFromYaml(filePath);
|
|
7233
7273
|
if (!result.success) continue;
|
|
@@ -7269,7 +7309,7 @@ function collectMergedEvents(opts) {
|
|
|
7269
7309
|
const { entitiesDir, eventsDir } = opts;
|
|
7270
7310
|
const entityNames = [];
|
|
7271
7311
|
if (fs8.existsSync(entitiesDir)) {
|
|
7272
|
-
const entityFiles =
|
|
7312
|
+
const entityFiles = findYamlFiles(entitiesDir);
|
|
7273
7313
|
for (const f of entityFiles) {
|
|
7274
7314
|
const result = loadEntityFromYaml(f);
|
|
7275
7315
|
if (result.success) entityNames.push(result.definition.entity.name);
|
|
@@ -7752,7 +7792,7 @@ function printInfo(msg) {
|
|
|
7752
7792
|
// src/cli/commands/entity.ts
|
|
7753
7793
|
function listEntityYamls2(dir) {
|
|
7754
7794
|
if (!fs9.existsSync(dir)) return [];
|
|
7755
|
-
return
|
|
7795
|
+
return findYamlFiles(dir);
|
|
7756
7796
|
}
|
|
7757
7797
|
function summarizePatternLabel(entity) {
|
|
7758
7798
|
if (typeof entity.pattern === "string" && entity.pattern.length > 0) {
|
|
@@ -8788,13 +8828,6 @@ function readIfExists(p) {
|
|
|
8788
8828
|
return null;
|
|
8789
8829
|
}
|
|
8790
8830
|
}
|
|
8791
|
-
function writeFile(target, content) {
|
|
8792
|
-
const existing = readIfExists(target);
|
|
8793
|
-
if (existing === content) return "unchanged";
|
|
8794
|
-
fs10.mkdirSync(path21.dirname(target), { recursive: true });
|
|
8795
|
-
fs10.writeFileSync(target, content);
|
|
8796
|
-
return existing === null ? "written" : "updated";
|
|
8797
|
-
}
|
|
8798
8831
|
function extractRelativeImports(source) {
|
|
8799
8832
|
const out = [];
|
|
8800
8833
|
const re = /(?:import|export)\s+(?:[^'"`;]*?\s+from\s+)?['"`](\.{1,2}\/[^'"`]+)['"`]/g;
|
|
@@ -8813,7 +8846,7 @@ function resolveSourceImport(sourceFile, specifier) {
|
|
|
8813
8846
|
return null;
|
|
8814
8847
|
}
|
|
8815
8848
|
async function copyRuntime(opts) {
|
|
8816
|
-
const { sourceDir, targetDir, filter, resolveDeps, dryRun } = opts;
|
|
8849
|
+
const { sourceDir, targetDir, filter, resolveDeps, dryRun, onlyExisting } = opts;
|
|
8817
8850
|
if (!fs10.existsSync(sourceDir) || !fs10.statSync(sourceDir).isDirectory()) {
|
|
8818
8851
|
throw new Error(`runtime source directory not found: ${sourceDir}`);
|
|
8819
8852
|
}
|
|
@@ -8838,9 +8871,9 @@ async function copyRuntime(opts) {
|
|
|
8838
8871
|
}
|
|
8839
8872
|
if (!stat.isFile()) continue;
|
|
8840
8873
|
if (!entry.endsWith(".ts") && !entry.endsWith(".tsx")) continue;
|
|
8841
|
-
const
|
|
8842
|
-
if (filter && !filter(
|
|
8843
|
-
queue.push({ src, dest: path21.join(targetDir,
|
|
8874
|
+
const rel2 = path21.relative(sourceDir, src);
|
|
8875
|
+
if (filter && !filter(rel2) && !filter(entry)) continue;
|
|
8876
|
+
queue.push({ src, dest: path21.join(targetDir, rel2), isDep: false });
|
|
8844
8877
|
}
|
|
8845
8878
|
}
|
|
8846
8879
|
walk(sourceDir);
|
|
@@ -8849,14 +8882,20 @@ async function copyRuntime(opts) {
|
|
|
8849
8882
|
const next = queue.shift();
|
|
8850
8883
|
if (visited.has(next.src)) continue;
|
|
8851
8884
|
visited.add(next.src);
|
|
8885
|
+
if (onlyExisting && !fs10.existsSync(next.dest)) {
|
|
8886
|
+
continue;
|
|
8887
|
+
}
|
|
8852
8888
|
const content = fs10.readFileSync(next.src, "utf-8");
|
|
8853
8889
|
result.planned.push(next.dest);
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8890
|
+
const existing = readIfExists(next.dest);
|
|
8891
|
+
const status = existing === content ? "unchanged" : existing === null ? "written" : "updated";
|
|
8892
|
+
if (status === "written") result.written.push(next.dest);
|
|
8893
|
+
else if (status === "updated") result.updated.push(next.dest);
|
|
8894
|
+
else result.unchanged.push(next.dest);
|
|
8895
|
+
if (next.isDep) result.dependenciesCopied.push(next.dest);
|
|
8896
|
+
if (!dryRun && status !== "unchanged") {
|
|
8897
|
+
fs10.mkdirSync(path21.dirname(next.dest), { recursive: true });
|
|
8898
|
+
fs10.writeFileSync(next.dest, content);
|
|
8860
8899
|
}
|
|
8861
8900
|
if (resolveDeps) {
|
|
8862
8901
|
for (const spec of extractRelativeImports(content)) {
|
|
@@ -8909,11 +8948,11 @@ async function summary2(ctx) {
|
|
|
8909
8948
|
}
|
|
8910
8949
|
body.push(theme.muted("Installed:"));
|
|
8911
8950
|
for (const i of installed) {
|
|
8912
|
-
const
|
|
8951
|
+
const rel2 = path22.relative(ctx.cwd, i.path) || i.path;
|
|
8913
8952
|
body.push(
|
|
8914
8953
|
` ${theme.success(icons.check)} ${i.name.padEnd(10)} ${theme.muted(
|
|
8915
8954
|
`${i.backend} backend`
|
|
8916
|
-
)} ${theme.muted(
|
|
8955
|
+
)} ${theme.muted(rel2)}`
|
|
8917
8956
|
);
|
|
8918
8957
|
}
|
|
8919
8958
|
if (missing.length > 0) {
|
|
@@ -8969,6 +9008,8 @@ function backendFileFilter(backend, subsystemName) {
|
|
|
8969
9008
|
if (subsystemName === "auth" && file === "auth-oauth-state.schema.ts") {
|
|
8970
9009
|
return false;
|
|
8971
9010
|
}
|
|
9011
|
+
if (file.endsWith(".redis-backend.ts") && backend !== "redis") return false;
|
|
9012
|
+
if (file.endsWith(".bullmq-backend.ts") && backend !== "bullmq") return false;
|
|
8972
9013
|
if (backend === "memory") {
|
|
8973
9014
|
if (file.endsWith(".drizzle-backend.ts")) return false;
|
|
8974
9015
|
if (file.endsWith(".schema.ts")) return false;
|
|
@@ -9916,9 +9957,9 @@ function buildAuthImportRewriter(subsystemsRoot) {
|
|
|
9916
9957
|
return content;
|
|
9917
9958
|
}
|
|
9918
9959
|
AUTH_BARE_IMPORT_RE.lastIndex = 0;
|
|
9919
|
-
let
|
|
9920
|
-
if (!
|
|
9921
|
-
const relPosix =
|
|
9960
|
+
let rel2 = path22.relative(path22.dirname(destPath), authRoot);
|
|
9961
|
+
if (!rel2.startsWith(".")) rel2 = `./${rel2}`;
|
|
9962
|
+
const relPosix = rel2.split(path22.sep).join("/");
|
|
9922
9963
|
return content.replace(
|
|
9923
9964
|
AUTH_BARE_IMPORT_RE,
|
|
9924
9965
|
(_match, quote) => `${quote}${relPosix}${quote}`
|
|
@@ -10031,14 +10072,14 @@ var SubsystemListCommand = class extends Command3 {
|
|
|
10031
10072
|
json: this.json,
|
|
10032
10073
|
skipDetection: true
|
|
10033
10074
|
});
|
|
10034
|
-
const
|
|
10075
|
+
const states = await detectSubsystemStates(ctx);
|
|
10035
10076
|
const byName = /* @__PURE__ */ new Map();
|
|
10036
|
-
for (const i of
|
|
10077
|
+
for (const i of states) byName.set(i.name, i);
|
|
10037
10078
|
const rows = SUBSYSTEMS.map((s) => {
|
|
10038
10079
|
const inst = byName.get(s.name);
|
|
10039
10080
|
return {
|
|
10040
10081
|
name: s.name,
|
|
10041
|
-
status: inst ?
|
|
10082
|
+
status: inst ? inst.status : "available",
|
|
10042
10083
|
backend: inst ? inst.backend : null,
|
|
10043
10084
|
path: inst ? path22.relative(ctx.cwd, inst.path) || inst.path : null
|
|
10044
10085
|
};
|
|
@@ -10062,29 +10103,129 @@ var SubsystemListCommand = class extends Command3 {
|
|
|
10062
10103
|
var SubsystemRemoveCommand = class extends Command3 {
|
|
10063
10104
|
static paths = [["subsystem", "remove"]];
|
|
10064
10105
|
static usage = Command3.Usage({
|
|
10065
|
-
description: "Remove a subsystem
|
|
10106
|
+
description: "Remove a vendored subsystem",
|
|
10107
|
+
examples: [
|
|
10108
|
+
["Remove the jobs subsystem", "codegen subsystem remove jobs"],
|
|
10109
|
+
[
|
|
10110
|
+
"Skip the git-safety check (uncommitted edits will be lost)",
|
|
10111
|
+
"codegen subsystem remove jobs --force"
|
|
10112
|
+
],
|
|
10113
|
+
["Non-interactive parity with install", "codegen subsystem remove jobs --yes"]
|
|
10114
|
+
]
|
|
10066
10115
|
});
|
|
10067
10116
|
name = Option3.String({ required: true });
|
|
10117
|
+
// #7: parity with `subsystem install` so a non-interactive caller can pass
|
|
10118
|
+
// the same flag set across install/remove. Accepted but currently a no-op
|
|
10119
|
+
// (remove has no interactive prompt yet); kept for forward-compatibility.
|
|
10120
|
+
yes = Option3.Boolean("--yes,-y", false);
|
|
10121
|
+
force = Option3.Boolean("--force", false);
|
|
10068
10122
|
json = Option3.Boolean("--json", false);
|
|
10069
10123
|
cwd = Option3.String("--cwd", { required: false });
|
|
10070
10124
|
configPath = Option3.String("--config", { required: false });
|
|
10071
10125
|
async execute() {
|
|
10072
10126
|
if (this.json) setJsonMode(true);
|
|
10127
|
+
const ctx = await loadContext({
|
|
10128
|
+
cwd: this.cwd,
|
|
10129
|
+
configPath: this.configPath,
|
|
10130
|
+
json: this.json,
|
|
10131
|
+
skipDetection: true
|
|
10132
|
+
});
|
|
10133
|
+
const desc3 = describeSubsystem(this.name);
|
|
10134
|
+
if (!desc3) {
|
|
10135
|
+
printError(
|
|
10136
|
+
`Unknown subsystem '${this.name}'. Known: ${SUBSYSTEMS.map((s) => s.name).join(", ")}`
|
|
10137
|
+
);
|
|
10138
|
+
return 2;
|
|
10139
|
+
}
|
|
10140
|
+
if (desc3.name === "openapi-config") {
|
|
10141
|
+
printError(
|
|
10142
|
+
"openapi-config has no vendored runtime to remove \u2014 it's a config-only pseudo-subsystem."
|
|
10143
|
+
);
|
|
10144
|
+
printInfo(
|
|
10145
|
+
"To uninstall: delete the `openapi:` block from codegen.config.yaml and uninstall the @nestjs/swagger / @anatine/zod-openapi peer deps."
|
|
10146
|
+
);
|
|
10147
|
+
return 1;
|
|
10148
|
+
}
|
|
10149
|
+
if (desc3.name === "auth-integrations") {
|
|
10150
|
+
printError(
|
|
10151
|
+
"auth-integrations is vendored under <modules>/integrations/ alongside the codegen-emitted entity layer \u2014 not auto-removable here."
|
|
10152
|
+
);
|
|
10153
|
+
printInfo(
|
|
10154
|
+
"To uninstall: remove the integrations/ directory and the IntegrationsAuthModule registration from app.module.ts by hand."
|
|
10155
|
+
);
|
|
10156
|
+
return 1;
|
|
10157
|
+
}
|
|
10158
|
+
const installed = await detectInstalledSubsystems(ctx);
|
|
10159
|
+
const target = installed.find((i) => i.name === desc3.name);
|
|
10160
|
+
if (!target) {
|
|
10161
|
+
if (isJsonMode()) {
|
|
10162
|
+
printJson({
|
|
10163
|
+
command: "subsystem remove",
|
|
10164
|
+
subsystem: desc3.name,
|
|
10165
|
+
status: "not-installed"
|
|
10166
|
+
});
|
|
10167
|
+
} else {
|
|
10168
|
+
printError(`${desc3.name} is not installed \u2014 nothing to remove.`);
|
|
10169
|
+
}
|
|
10170
|
+
return 1;
|
|
10171
|
+
}
|
|
10172
|
+
const subsystemDir = target.path;
|
|
10173
|
+
if (!fs11.existsSync(subsystemDir)) {
|
|
10174
|
+
printError(
|
|
10175
|
+
`Detected install at ${subsystemDir} but the directory is gone \u2014 refusing to act.`
|
|
10176
|
+
);
|
|
10177
|
+
return 1;
|
|
10178
|
+
}
|
|
10179
|
+
if (!this.force) {
|
|
10180
|
+
const rel2 = path22.relative(ctx.cwd, subsystemDir) || subsystemDir;
|
|
10181
|
+
const gitCheck = checkGitSafety([rel2], ctx.cwd);
|
|
10182
|
+
if (gitCheck.inRepo && !gitCheck.clean) {
|
|
10183
|
+
printWarning(
|
|
10184
|
+
`Uncommitted changes under ${subsystemDir}. Pass --force to delete anyway.`
|
|
10185
|
+
);
|
|
10186
|
+
if (!isJsonMode()) return 1;
|
|
10187
|
+
}
|
|
10188
|
+
}
|
|
10189
|
+
try {
|
|
10190
|
+
fs11.rmSync(subsystemDir, { recursive: true, force: true });
|
|
10191
|
+
} catch (err) {
|
|
10192
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
10193
|
+
printError(`Failed to remove ${subsystemDir}: ${message}`);
|
|
10194
|
+
return 1;
|
|
10195
|
+
}
|
|
10196
|
+
let barrelRegenerated = false;
|
|
10197
|
+
try {
|
|
10198
|
+
const generatedDir = resolveGeneratedDir(ctx);
|
|
10199
|
+
await regenerateSubsystemBarrel({ ctx, generatedDir });
|
|
10200
|
+
barrelRegenerated = true;
|
|
10201
|
+
} catch (err) {
|
|
10202
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10203
|
+
printWarning(`subsystem barrel regeneration failed \u2014 ${msg}`);
|
|
10204
|
+
}
|
|
10073
10205
|
if (isJsonMode()) {
|
|
10074
10206
|
printJson({
|
|
10075
10207
|
command: "subsystem remove",
|
|
10076
|
-
|
|
10077
|
-
|
|
10208
|
+
subsystem: desc3.name,
|
|
10209
|
+
status: "removed",
|
|
10210
|
+
path: subsystemDir,
|
|
10211
|
+
barrelRegenerated
|
|
10078
10212
|
});
|
|
10079
|
-
return
|
|
10213
|
+
return 0;
|
|
10080
10214
|
}
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
)
|
|
10215
|
+
printSuccess(
|
|
10216
|
+
`${desc3.name} subsystem removed (${path22.relative(ctx.cwd, subsystemDir) || subsystemDir}).`
|
|
10217
|
+
);
|
|
10218
|
+
if (barrelRegenerated) {
|
|
10219
|
+
printInfo("Regenerated <generated>/subsystems.ts barrel.");
|
|
10220
|
+
}
|
|
10221
|
+
printInfo("Next steps (manual):");
|
|
10222
|
+
printInfo(
|
|
10223
|
+
` 1. Remove the \`${capitalize(desc3.name)}Module.forRoot(...)\` registration from app.module.ts.`
|
|
10086
10224
|
);
|
|
10087
|
-
|
|
10225
|
+
printInfo(
|
|
10226
|
+
` 2. Remove the \`${desc3.name}:\` block from codegen.config.yaml (if you no longer want it).`
|
|
10227
|
+
);
|
|
10228
|
+
return 0;
|
|
10088
10229
|
}
|
|
10089
10230
|
};
|
|
10090
10231
|
var subsystemNoun = {
|
|
@@ -10100,10 +10241,10 @@ var subsystemNoun = {
|
|
|
10100
10241
|
var subsystem_default = subsystemNoun;
|
|
10101
10242
|
|
|
10102
10243
|
// src/cli/commands/project.ts
|
|
10103
|
-
import
|
|
10104
|
-
import
|
|
10244
|
+
import fs17 from "fs";
|
|
10245
|
+
import path28 from "path";
|
|
10105
10246
|
import readline from "readline";
|
|
10106
|
-
import { Command as
|
|
10247
|
+
import { Command as Command7, Option as Option7 } from "clipanion";
|
|
10107
10248
|
import { stringify as stringifyYaml2 } from "yaml";
|
|
10108
10249
|
|
|
10109
10250
|
// src/cli/shared/init-scaffold.ts
|
|
@@ -10746,8 +10887,8 @@ async function buildInitPlan(ctx, options) {
|
|
|
10746
10887
|
{
|
|
10747
10888
|
const entitiesDir = path23.join(cwd, "entities");
|
|
10748
10889
|
const examplePath = path23.join(entitiesDir, "example.yaml");
|
|
10749
|
-
const hasOtherYamls = fs12.existsSync(entitiesDir) &&
|
|
10750
|
-
(f) =>
|
|
10890
|
+
const hasOtherYamls = fs12.existsSync(entitiesDir) && findYamlFiles(entitiesDir).some(
|
|
10891
|
+
(f) => path23.basename(f) !== "example.yaml"
|
|
10751
10892
|
);
|
|
10752
10893
|
if (fs12.existsSync(examplePath)) {
|
|
10753
10894
|
entries.push({
|
|
@@ -11058,8 +11199,8 @@ function runtimeRoot3() {
|
|
|
11058
11199
|
if (fs13.existsSync(topLevel)) return topLevel;
|
|
11059
11200
|
return path24.join(pkgRoot, "dist", "runtime");
|
|
11060
11201
|
}
|
|
11061
|
-
function loadRuntimeFile2(
|
|
11062
|
-
return fs13.readFileSync(path24.join(runtimeRoot3(),
|
|
11202
|
+
function loadRuntimeFile2(rel2) {
|
|
11203
|
+
return fs13.readFileSync(path24.join(runtimeRoot3(), rel2), "utf-8");
|
|
11063
11204
|
}
|
|
11064
11205
|
function resolveProjectRoot(startDir) {
|
|
11065
11206
|
let dir = path24.resolve(startDir);
|
|
@@ -11342,8 +11483,457 @@ ${CONSUMER_SETUP_POINTER}
|
|
|
11342
11483
|
}
|
|
11343
11484
|
};
|
|
11344
11485
|
|
|
11345
|
-
// src/cli/commands/project.ts
|
|
11486
|
+
// src/cli/commands/project-update.ts
|
|
11487
|
+
import fs16 from "fs";
|
|
11488
|
+
import path27 from "path";
|
|
11489
|
+
import { Command as Command6, Option as Option6 } from "clipanion";
|
|
11490
|
+
|
|
11491
|
+
// src/cli/commands/skills.ts
|
|
11492
|
+
import fs15 from "fs";
|
|
11493
|
+
import path26 from "path";
|
|
11494
|
+
import { Command as Command5, Option as Option5 } from "clipanion";
|
|
11495
|
+
|
|
11496
|
+
// src/cli/shared/tree-copier.ts
|
|
11497
|
+
import fs14 from "fs";
|
|
11498
|
+
import path25 from "path";
|
|
11499
|
+
var TEXT_EXTENSIONS = [".ts", ".tsx", ".md", ".mdx", ".yaml", ".yml", ".json"];
|
|
11500
|
+
function isTextFile(name) {
|
|
11501
|
+
return TEXT_EXTENSIONS.some((ext) => name.endsWith(ext));
|
|
11502
|
+
}
|
|
11503
|
+
function copyTreeWithReport(opts) {
|
|
11504
|
+
const { srcDir, destDir, dryRun = false, transform, include } = opts;
|
|
11505
|
+
const report = {
|
|
11506
|
+
entries: [],
|
|
11507
|
+
created: [],
|
|
11508
|
+
updated: [],
|
|
11509
|
+
unchanged: []
|
|
11510
|
+
};
|
|
11511
|
+
if (!fs14.existsSync(srcDir) || !fs14.statSync(srcDir).isDirectory()) {
|
|
11512
|
+
throw new Error(`tree-copier source directory not found: ${srcDir}`);
|
|
11513
|
+
}
|
|
11514
|
+
const walk = (relDir) => {
|
|
11515
|
+
const absSrcDir = path25.join(srcDir, relDir);
|
|
11516
|
+
for (const entry of fs14.readdirSync(absSrcDir, { withFileTypes: true })) {
|
|
11517
|
+
const relPath2 = relDir ? path25.posix.join(relDir, entry.name) : entry.name;
|
|
11518
|
+
const absSrc = path25.join(srcDir, relPath2);
|
|
11519
|
+
if (entry.isDirectory()) {
|
|
11520
|
+
walk(relPath2);
|
|
11521
|
+
continue;
|
|
11522
|
+
}
|
|
11523
|
+
if (!entry.isFile()) continue;
|
|
11524
|
+
if (include && !include(relPath2)) continue;
|
|
11525
|
+
const dest = path25.join(destDir, relPath2);
|
|
11526
|
+
let content = fs14.readFileSync(absSrc, "utf-8");
|
|
11527
|
+
if (transform && isTextFile(entry.name)) {
|
|
11528
|
+
content = transform(content, dest);
|
|
11529
|
+
}
|
|
11530
|
+
const existing = fs14.existsSync(dest) ? fs14.readFileSync(dest, "utf-8") : null;
|
|
11531
|
+
let action;
|
|
11532
|
+
if (existing === null) {
|
|
11533
|
+
action = "created";
|
|
11534
|
+
} else if (existing === content) {
|
|
11535
|
+
action = "unchanged";
|
|
11536
|
+
} else {
|
|
11537
|
+
action = "updated";
|
|
11538
|
+
}
|
|
11539
|
+
if (!dryRun && action !== "unchanged") {
|
|
11540
|
+
fs14.mkdirSync(path25.dirname(dest), { recursive: true });
|
|
11541
|
+
fs14.writeFileSync(dest, content, "utf-8");
|
|
11542
|
+
}
|
|
11543
|
+
const record = { relPath: relPath2, dest, action };
|
|
11544
|
+
report.entries.push(record);
|
|
11545
|
+
report[action].push(record);
|
|
11546
|
+
}
|
|
11547
|
+
};
|
|
11548
|
+
walk("");
|
|
11549
|
+
return report;
|
|
11550
|
+
}
|
|
11551
|
+
|
|
11552
|
+
// src/cli/commands/skills.ts
|
|
11553
|
+
function consumerSkillsRoot() {
|
|
11554
|
+
const pkgRoot = path26.resolve(import.meta.dirname, "..", "..", "..");
|
|
11555
|
+
const topLevel = path26.join(pkgRoot, "consumer-skills");
|
|
11556
|
+
if (fs15.existsSync(topLevel)) return topLevel;
|
|
11557
|
+
return path26.join(pkgRoot, "dist", "consumer-skills");
|
|
11558
|
+
}
|
|
11559
|
+
function skillsTargetDir(cwd) {
|
|
11560
|
+
return path26.join(cwd, ".claude", "skills");
|
|
11561
|
+
}
|
|
11562
|
+
function availableSkills() {
|
|
11563
|
+
const root = consumerSkillsRoot();
|
|
11564
|
+
if (!fs15.existsSync(root)) return [];
|
|
11565
|
+
return fs15.readdirSync(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
11566
|
+
}
|
|
11567
|
+
function runSkillsInstall(opts) {
|
|
11568
|
+
const sourceRoot = consumerSkillsRoot();
|
|
11569
|
+
const targetDir = skillsTargetDir(opts.cwd);
|
|
11570
|
+
if (!fs15.existsSync(sourceRoot)) {
|
|
11571
|
+
return {
|
|
11572
|
+
ok: false,
|
|
11573
|
+
sourceRoot,
|
|
11574
|
+
targetDir,
|
|
11575
|
+
error: `consumer skills source missing: ${sourceRoot}`
|
|
11576
|
+
};
|
|
11577
|
+
}
|
|
11578
|
+
const report = copyTreeWithReport({
|
|
11579
|
+
srcDir: sourceRoot,
|
|
11580
|
+
destDir: targetDir,
|
|
11581
|
+
dryRun: Boolean(opts.dryRun)
|
|
11582
|
+
});
|
|
11583
|
+
return { ok: true, sourceRoot, targetDir, report };
|
|
11584
|
+
}
|
|
11346
11585
|
async function summary3(ctx) {
|
|
11586
|
+
const skills = availableSkills();
|
|
11587
|
+
const targetDir = skillsTargetDir(ctx.cwd);
|
|
11588
|
+
const installedDirs = fs15.existsSync(targetDir) ? new Set(
|
|
11589
|
+
fs15.readdirSync(targetDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name)
|
|
11590
|
+
) : /* @__PURE__ */ new Set();
|
|
11591
|
+
const body = [];
|
|
11592
|
+
if (skills.length === 0) {
|
|
11593
|
+
body.push(theme.muted("No consumer skills bundled with this package build."));
|
|
11594
|
+
return { title: "skills", body, footer: "" };
|
|
11595
|
+
}
|
|
11596
|
+
body.push(theme.muted("Consumer skills:"));
|
|
11597
|
+
for (const name of skills) {
|
|
11598
|
+
const present = installedDirs.has(name);
|
|
11599
|
+
const icon = present ? theme.success(icons.check) : theme.muted(icons.dash);
|
|
11600
|
+
const status = present ? "" : theme.muted("not installed");
|
|
11601
|
+
body.push(` ${icon} ${name.padEnd(12)} ${status}`);
|
|
11602
|
+
}
|
|
11603
|
+
const installedCount = skills.filter((s) => installedDirs.has(s)).length;
|
|
11604
|
+
return {
|
|
11605
|
+
title: "skills",
|
|
11606
|
+
body,
|
|
11607
|
+
footer: `${installedCount} of ${skills.length} skills installed \u2192 ${path26.relative(ctx.cwd, targetDir) || targetDir}`
|
|
11608
|
+
};
|
|
11609
|
+
}
|
|
11610
|
+
async function hints3(ctx) {
|
|
11611
|
+
const skills = availableSkills();
|
|
11612
|
+
const targetDir = skillsTargetDir(ctx.cwd);
|
|
11613
|
+
const allPresent = skills.length > 0 && fs15.existsSync(targetDir) && skills.every((s) => fs15.existsSync(path26.join(targetDir, s)));
|
|
11614
|
+
if (allPresent) {
|
|
11615
|
+
return [
|
|
11616
|
+
{ command: "codegen update", description: "Re-sync skills + runtime after a package bump" }
|
|
11617
|
+
];
|
|
11618
|
+
}
|
|
11619
|
+
return [
|
|
11620
|
+
{ command: "codegen skills install", description: "Vendor consumer skills into .claude/skills" }
|
|
11621
|
+
];
|
|
11622
|
+
}
|
|
11623
|
+
function renderTreeReport(report) {
|
|
11624
|
+
const show = (entry) => {
|
|
11625
|
+
const icon = theme.success(icons.check);
|
|
11626
|
+
console.log(` ${icon} ${theme.muted(entry.action.padEnd(10))} ${entry.relPath}`);
|
|
11627
|
+
};
|
|
11628
|
+
for (const e of [...report.created, ...report.updated]) show(e);
|
|
11629
|
+
if (report.unchanged.length > 0) {
|
|
11630
|
+
console.log(
|
|
11631
|
+
` ${theme.muted(icons.dash)} ${theme.muted("unchanged".padEnd(10))} ${theme.muted(
|
|
11632
|
+
`${report.unchanged.length} file${report.unchanged.length === 1 ? "" : "s"} already current`
|
|
11633
|
+
)}`
|
|
11634
|
+
);
|
|
11635
|
+
}
|
|
11636
|
+
}
|
|
11637
|
+
var SkillsInstallCommand = class extends Command5 {
|
|
11638
|
+
static paths = [["skills", "install"]];
|
|
11639
|
+
static usage = Command5.Usage({
|
|
11640
|
+
description: "Vendor consumer-facing skills into the project .claude/skills",
|
|
11641
|
+
examples: [
|
|
11642
|
+
["Install all consumer skills", "codegen skills install"],
|
|
11643
|
+
["Preview without writing", "codegen skills install --dry-run"],
|
|
11644
|
+
["Overwrite locally-edited skill files", "codegen skills install --force"]
|
|
11645
|
+
]
|
|
11646
|
+
});
|
|
11647
|
+
force = Option5.Boolean("--force", false);
|
|
11648
|
+
dryRun = Option5.Boolean("--dry-run", false);
|
|
11649
|
+
json = Option5.Boolean("--json", false);
|
|
11650
|
+
cwd = Option5.String("--cwd", { required: false });
|
|
11651
|
+
async execute() {
|
|
11652
|
+
if (this.json) setJsonMode(true);
|
|
11653
|
+
const ctx = await loadContext({ cwd: this.cwd, json: this.json, skipDetection: true });
|
|
11654
|
+
const preview = runSkillsInstall({ cwd: ctx.cwd, dryRun: true });
|
|
11655
|
+
if (!preview.ok) {
|
|
11656
|
+
if (isJsonMode()) {
|
|
11657
|
+
printJson({ command: "skills install", status: "error", error: preview.error });
|
|
11658
|
+
} else {
|
|
11659
|
+
printError(preview.error ?? "skills install failed");
|
|
11660
|
+
}
|
|
11661
|
+
return 1;
|
|
11662
|
+
}
|
|
11663
|
+
if (!this.dryRun && !this.force) {
|
|
11664
|
+
const updatedPaths = preview.report.updated.map((e) => e.dest);
|
|
11665
|
+
const gate = checkGitSafety(updatedPaths, ctx.cwd);
|
|
11666
|
+
if (gate.inRepo && !gate.clean) {
|
|
11667
|
+
printWarning(
|
|
11668
|
+
`Uncommitted changes in ${gate.dirty.length} skill file(s). Commit them or pass --force to overwrite.`
|
|
11669
|
+
);
|
|
11670
|
+
if (!isJsonMode()) return 1;
|
|
11671
|
+
}
|
|
11672
|
+
}
|
|
11673
|
+
const result = runSkillsInstall({ cwd: ctx.cwd, dryRun: this.dryRun });
|
|
11674
|
+
const report = result.report;
|
|
11675
|
+
if (isJsonMode()) {
|
|
11676
|
+
printJson({
|
|
11677
|
+
command: "skills install",
|
|
11678
|
+
dryRun: this.dryRun,
|
|
11679
|
+
target: result.targetDir,
|
|
11680
|
+
files: {
|
|
11681
|
+
created: report.created.map((e) => e.relPath),
|
|
11682
|
+
updated: report.updated.map((e) => e.relPath),
|
|
11683
|
+
unchanged: report.unchanged.map((e) => e.relPath)
|
|
11684
|
+
}
|
|
11685
|
+
});
|
|
11686
|
+
return 0;
|
|
11687
|
+
}
|
|
11688
|
+
printInfo(`target = ${path26.relative(ctx.cwd, result.targetDir) || result.targetDir}`);
|
|
11689
|
+
console.log("");
|
|
11690
|
+
renderTreeReport(report);
|
|
11691
|
+
console.log("");
|
|
11692
|
+
if (this.dryRun) {
|
|
11693
|
+
printWarning("dry-run \u2014 no files written");
|
|
11694
|
+
return 0;
|
|
11695
|
+
}
|
|
11696
|
+
printSuccess(
|
|
11697
|
+
`skills installed (${report.created.length} new, ${report.updated.length} updated, ${report.unchanged.length} unchanged)`
|
|
11698
|
+
);
|
|
11699
|
+
printInfo("Skills are auto-discovered by Claude Code from .claude/skills/.");
|
|
11700
|
+
return 0;
|
|
11701
|
+
}
|
|
11702
|
+
};
|
|
11703
|
+
var SkillsListCommand = class extends Command5 {
|
|
11704
|
+
static paths = [["skills", "list"]];
|
|
11705
|
+
static usage = Command5.Usage({
|
|
11706
|
+
description: "List available consumer skills and their installed status"
|
|
11707
|
+
});
|
|
11708
|
+
json = Option5.Boolean("--json", false);
|
|
11709
|
+
cwd = Option5.String("--cwd", { required: false });
|
|
11710
|
+
async execute() {
|
|
11711
|
+
if (this.json) setJsonMode(true);
|
|
11712
|
+
const ctx = await loadContext({ cwd: this.cwd, json: this.json, skipDetection: true });
|
|
11713
|
+
const skills = availableSkills();
|
|
11714
|
+
const targetDir = skillsTargetDir(ctx.cwd);
|
|
11715
|
+
const rows = skills.map((name) => {
|
|
11716
|
+
const dir = path26.join(targetDir, name);
|
|
11717
|
+
return { name, status: fs15.existsSync(dir) ? "installed" : "available" };
|
|
11718
|
+
});
|
|
11719
|
+
if (isJsonMode()) {
|
|
11720
|
+
printJson({ command: "skills list", target: targetDir, skills: rows });
|
|
11721
|
+
return 0;
|
|
11722
|
+
}
|
|
11723
|
+
if (rows.length === 0) {
|
|
11724
|
+
printWarning("No consumer skills bundled with this package build.");
|
|
11725
|
+
return 0;
|
|
11726
|
+
}
|
|
11727
|
+
const pad = (s, n) => s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
11728
|
+
console.log(theme.muted(`${pad("NAME", 14)}STATUS`));
|
|
11729
|
+
for (const r of rows) console.log(`${pad(r.name, 14)}${r.status}`);
|
|
11730
|
+
return 0;
|
|
11731
|
+
}
|
|
11732
|
+
};
|
|
11733
|
+
var skillsNoun = {
|
|
11734
|
+
name: "skills",
|
|
11735
|
+
commandClasses: [SkillsInstallCommand, SkillsListCommand],
|
|
11736
|
+
summary: summary3,
|
|
11737
|
+
hints: hints3
|
|
11738
|
+
};
|
|
11739
|
+
var skills_default = skillsNoun;
|
|
11740
|
+
|
|
11741
|
+
// src/cli/commands/project-update.ts
|
|
11742
|
+
var NON_RUNTIME_SUBSYSTEMS = /* @__PURE__ */ new Set(["openapi-config", "auth-integrations"]);
|
|
11743
|
+
function syncVendoredRuntime(cwd, write) {
|
|
11744
|
+
const changes = [];
|
|
11745
|
+
for (const v of VENDORED_RUNTIME_FILES) {
|
|
11746
|
+
const dest = path27.join(cwd, v.target);
|
|
11747
|
+
const content = loadRuntimeFile(v.runtime);
|
|
11748
|
+
const existing = fs16.existsSync(dest) ? fs16.readFileSync(dest, "utf-8") : null;
|
|
11749
|
+
let action;
|
|
11750
|
+
if (existing === null) action = "created";
|
|
11751
|
+
else if (existing === content) action = "unchanged";
|
|
11752
|
+
else action = "updated";
|
|
11753
|
+
if (write && action !== "unchanged") {
|
|
11754
|
+
fs16.mkdirSync(path27.dirname(dest), { recursive: true });
|
|
11755
|
+
fs16.writeFileSync(dest, content, "utf-8");
|
|
11756
|
+
}
|
|
11757
|
+
changes.push({ path: v.target, action });
|
|
11758
|
+
}
|
|
11759
|
+
return changes;
|
|
11760
|
+
}
|
|
11761
|
+
async function syncSubsystemRuntime(cwd, inst, write) {
|
|
11762
|
+
if (NON_RUNTIME_SUBSYSTEMS.has(inst.name)) {
|
|
11763
|
+
return { name: inst.name, changes: [], skippedReason: "config-only / vendored elsewhere" };
|
|
11764
|
+
}
|
|
11765
|
+
const source = subsystemSource(inst.name);
|
|
11766
|
+
if (!fs16.existsSync(source)) {
|
|
11767
|
+
return { name: inst.name, changes: [], skippedReason: "no runtime source in package" };
|
|
11768
|
+
}
|
|
11769
|
+
const subsystemsRoot = path27.dirname(inst.path);
|
|
11770
|
+
const result = await copyRuntime({
|
|
11771
|
+
sourceDir: source,
|
|
11772
|
+
targetDir: inst.path,
|
|
11773
|
+
filter: backendFileFilter(inst.backend, inst.name),
|
|
11774
|
+
resolveDeps: true,
|
|
11775
|
+
runtimeRoot: runtimeRoot2(),
|
|
11776
|
+
depsTargetRoot: path27.resolve(subsystemsRoot, ".."),
|
|
11777
|
+
dryRun: !write,
|
|
11778
|
+
// Refresh files already vendored for this subsystem; never install new
|
|
11779
|
+
// ones (that's `subsystem install`). copyRuntime classifies accurately
|
|
11780
|
+
// in dry-run too, so this report is correct either way.
|
|
11781
|
+
onlyExisting: true
|
|
11782
|
+
});
|
|
11783
|
+
const changes = [];
|
|
11784
|
+
for (const p of result.written) changes.push({ path: rel(cwd, p), action: "created" });
|
|
11785
|
+
for (const p of result.updated) changes.push({ path: rel(cwd, p), action: "updated" });
|
|
11786
|
+
for (const p of result.unchanged) changes.push({ path: rel(cwd, p), action: "unchanged" });
|
|
11787
|
+
return { name: inst.name, changes };
|
|
11788
|
+
}
|
|
11789
|
+
function rel(cwd, abs) {
|
|
11790
|
+
return path27.relative(cwd, abs) || abs;
|
|
11791
|
+
}
|
|
11792
|
+
var ProjectUpdateCommand = class extends Command6 {
|
|
11793
|
+
static paths = [["project", "update"]];
|
|
11794
|
+
static usage = Command6.Usage({
|
|
11795
|
+
description: "Re-sync vendored runtime, installed subsystems, and consumer skills to the installed package version",
|
|
11796
|
+
examples: [
|
|
11797
|
+
["Re-sync everything after a package bump", "codegen update"],
|
|
11798
|
+
["Preview without writing", "codegen update --dry-run"],
|
|
11799
|
+
["Overwrite even with uncommitted changes", "codegen update --force"],
|
|
11800
|
+
["Skip the skills re-sync", "codegen update --skip-skills"]
|
|
11801
|
+
]
|
|
11802
|
+
});
|
|
11803
|
+
dryRun = Option6.Boolean("--dry-run", false);
|
|
11804
|
+
force = Option6.Boolean("--force", false);
|
|
11805
|
+
skipSkills = Option6.Boolean("--skip-skills", false);
|
|
11806
|
+
skipSubsystems = Option6.Boolean("--skip-subsystems", false);
|
|
11807
|
+
json = Option6.Boolean("--json", false);
|
|
11808
|
+
cwd = Option6.String("--cwd", { required: false });
|
|
11809
|
+
configPath = Option6.String("--config", { required: false });
|
|
11810
|
+
async execute() {
|
|
11811
|
+
if (this.json) setJsonMode(true);
|
|
11812
|
+
const ctx = await loadContext({
|
|
11813
|
+
cwd: this.cwd,
|
|
11814
|
+
configPath: this.configPath,
|
|
11815
|
+
json: this.json,
|
|
11816
|
+
skipDetection: true
|
|
11817
|
+
});
|
|
11818
|
+
if (!ctx.isInitialized) {
|
|
11819
|
+
if (isJsonMode()) {
|
|
11820
|
+
printJson({ command: "project update", status: "not-initialized" });
|
|
11821
|
+
} else {
|
|
11822
|
+
printWarning("project is not initialized \u2014 run `codegen init` first");
|
|
11823
|
+
}
|
|
11824
|
+
return 1;
|
|
11825
|
+
}
|
|
11826
|
+
const installed = this.skipSubsystems ? [] : await detectInstalledSubsystems(ctx);
|
|
11827
|
+
if (!this.dryRun && !this.force) {
|
|
11828
|
+
const vendoredDry = syncVendoredRuntime(ctx.cwd, false);
|
|
11829
|
+
const vendoredDirtyCandidates = vendoredDry.filter((c) => c.action === "updated").map((c) => path27.join(ctx.cwd, c.path));
|
|
11830
|
+
const skillDirtyCandidates = this.skipSkills ? [] : runSkillsInstall({ cwd: ctx.cwd, dryRun: true }).report?.updated.map((e) => e.dest) ?? [];
|
|
11831
|
+
const subsystemDirs = installed.filter((i) => !NON_RUNTIME_SUBSYSTEMS.has(i.name)).map((i) => i.path);
|
|
11832
|
+
const gate = checkGitSafety(
|
|
11833
|
+
[...vendoredDirtyCandidates, ...skillDirtyCandidates, ...subsystemDirs],
|
|
11834
|
+
ctx.cwd
|
|
11835
|
+
);
|
|
11836
|
+
if (gate.inRepo && !gate.clean) {
|
|
11837
|
+
if (isJsonMode()) {
|
|
11838
|
+
printJson({
|
|
11839
|
+
command: "project update",
|
|
11840
|
+
status: "dirty-tree",
|
|
11841
|
+
dirty: gate.dirty
|
|
11842
|
+
});
|
|
11843
|
+
} else {
|
|
11844
|
+
printWarning(
|
|
11845
|
+
`Uncommitted changes in ${gate.dirty.length} file(s) that update would overwrite. Commit them or pass --force.`
|
|
11846
|
+
);
|
|
11847
|
+
for (const d of gate.dirty.slice(0, 10)) {
|
|
11848
|
+
console.log(` ${theme.muted(icons.dash)} ${d}`);
|
|
11849
|
+
}
|
|
11850
|
+
}
|
|
11851
|
+
return 1;
|
|
11852
|
+
}
|
|
11853
|
+
}
|
|
11854
|
+
const write = !this.dryRun;
|
|
11855
|
+
const vendored = syncVendoredRuntime(ctx.cwd, write);
|
|
11856
|
+
const subsystemResults = [];
|
|
11857
|
+
for (const inst of installed) {
|
|
11858
|
+
subsystemResults.push(await syncSubsystemRuntime(ctx.cwd, inst, write));
|
|
11859
|
+
}
|
|
11860
|
+
const skills = this.skipSkills ? null : runSkillsInstall({ cwd: ctx.cwd, dryRun: this.dryRun });
|
|
11861
|
+
const tally = (changes) => ({
|
|
11862
|
+
created: changes.filter((c) => c.action === "created").length,
|
|
11863
|
+
updated: changes.filter((c) => c.action === "updated").length,
|
|
11864
|
+
unchanged: changes.filter((c) => c.action === "unchanged").length
|
|
11865
|
+
});
|
|
11866
|
+
if (isJsonMode()) {
|
|
11867
|
+
printJson({
|
|
11868
|
+
command: "project update",
|
|
11869
|
+
dryRun: this.dryRun,
|
|
11870
|
+
runtime: vendored,
|
|
11871
|
+
subsystems: subsystemResults.map((s) => ({
|
|
11872
|
+
name: s.name,
|
|
11873
|
+
skipped: s.skippedReason ?? null,
|
|
11874
|
+
...tally(s.changes)
|
|
11875
|
+
})),
|
|
11876
|
+
skills: skills && skills.report ? {
|
|
11877
|
+
created: skills.report.created.length,
|
|
11878
|
+
updated: skills.report.updated.length,
|
|
11879
|
+
unchanged: skills.report.unchanged.length
|
|
11880
|
+
} : null
|
|
11881
|
+
});
|
|
11882
|
+
return 0;
|
|
11883
|
+
}
|
|
11884
|
+
printInfo(`Updating ${ctx.cwd} to the installed @pattern-stack/codegen version`);
|
|
11885
|
+
console.log("");
|
|
11886
|
+
renderSection("shared runtime", vendored);
|
|
11887
|
+
for (const s of subsystemResults) {
|
|
11888
|
+
if (s.skippedReason) {
|
|
11889
|
+
console.log(
|
|
11890
|
+
` ${theme.muted(icons.dash)} ${theme.muted(`subsystem ${s.name} skipped (${s.skippedReason})`)}`
|
|
11891
|
+
);
|
|
11892
|
+
continue;
|
|
11893
|
+
}
|
|
11894
|
+
renderSection(`subsystem ${s.name}`, s.changes);
|
|
11895
|
+
}
|
|
11896
|
+
if (skills?.report) {
|
|
11897
|
+
renderSection(
|
|
11898
|
+
"skills",
|
|
11899
|
+
[
|
|
11900
|
+
...skills.report.created.map((e) => ({ path: e.relPath, action: "created" })),
|
|
11901
|
+
...skills.report.updated.map((e) => ({ path: e.relPath, action: "updated" })),
|
|
11902
|
+
...skills.report.unchanged.map((e) => ({
|
|
11903
|
+
path: e.relPath,
|
|
11904
|
+
action: "unchanged"
|
|
11905
|
+
}))
|
|
11906
|
+
]
|
|
11907
|
+
);
|
|
11908
|
+
} else if (this.skipSkills) {
|
|
11909
|
+
console.log(` ${theme.muted(icons.dash)} ${theme.muted("skills skipped (--skip-skills)")}`);
|
|
11910
|
+
}
|
|
11911
|
+
console.log("");
|
|
11912
|
+
if (this.dryRun) {
|
|
11913
|
+
printWarning("dry-run \u2014 no files written");
|
|
11914
|
+
return 0;
|
|
11915
|
+
}
|
|
11916
|
+
printSuccess("update complete");
|
|
11917
|
+
printInfo(
|
|
11918
|
+
"Schema shape changes are NOT re-synced \u2014 if a subsystem schema changed across versions, run `codegen subsystem install <name> --force --force-config`."
|
|
11919
|
+
);
|
|
11920
|
+
return 0;
|
|
11921
|
+
}
|
|
11922
|
+
};
|
|
11923
|
+
function renderSection(label, changes) {
|
|
11924
|
+
const created = changes.filter((c) => c.action === "created");
|
|
11925
|
+
const updated = changes.filter((c) => c.action === "updated");
|
|
11926
|
+
const unchanged = changes.filter((c) => c.action === "unchanged");
|
|
11927
|
+
if (created.length === 0 && updated.length === 0 && unchanged.length === 0) return;
|
|
11928
|
+
const head = created.length + updated.length === 0 ? theme.muted(`${label} \u2014 up to date (${unchanged.length})`) : `${theme.system(label)} \u2014 ${created.length} new, ${updated.length} updated`;
|
|
11929
|
+
console.log(` ${head}`);
|
|
11930
|
+
for (const c of [...created, ...updated]) {
|
|
11931
|
+
console.log(` ${theme.success(icons.check)} ${theme.muted(c.action.padEnd(8))} ${c.path}`);
|
|
11932
|
+
}
|
|
11933
|
+
}
|
|
11934
|
+
|
|
11935
|
+
// src/cli/commands/project.ts
|
|
11936
|
+
async function summary4(ctx) {
|
|
11347
11937
|
if (!ctx.isInitialized) {
|
|
11348
11938
|
return {
|
|
11349
11939
|
title: "project",
|
|
@@ -11368,7 +11958,7 @@ async function summary3(ctx) {
|
|
|
11368
11958
|
body.push(` orm: ${orm}`);
|
|
11369
11959
|
body.push(` architecture: ${arch}`);
|
|
11370
11960
|
body.push(` entities: ${ctx.entityCount}`);
|
|
11371
|
-
body.push(` subsystems: ${ctx.installedSubsystems.length}
|
|
11961
|
+
body.push(` subsystems: ${ctx.installedSubsystems.length}/${SUBSYSTEMS.length} installed`);
|
|
11372
11962
|
body.push(` generated: ${generated}`);
|
|
11373
11963
|
return {
|
|
11374
11964
|
title: "project",
|
|
@@ -11376,7 +11966,7 @@ async function summary3(ctx) {
|
|
|
11376
11966
|
footer: `cwd: ${ctx.cwd}`
|
|
11377
11967
|
};
|
|
11378
11968
|
}
|
|
11379
|
-
async function
|
|
11969
|
+
async function hints4(ctx) {
|
|
11380
11970
|
if (!ctx.isInitialized) {
|
|
11381
11971
|
return [
|
|
11382
11972
|
{ command: "codegen init", description: "Scaffold consumer project" },
|
|
@@ -11394,17 +11984,17 @@ async function hints3(ctx) {
|
|
|
11394
11984
|
} else {
|
|
11395
11985
|
out.push({ command: "codegen entity", description: "Entity summary + hints" });
|
|
11396
11986
|
}
|
|
11397
|
-
if (ctx.installedSubsystems.length <
|
|
11987
|
+
if (ctx.installedSubsystems.length < SUBSYSTEMS.length) {
|
|
11398
11988
|
out.push({
|
|
11399
11989
|
command: "codegen subsystem",
|
|
11400
|
-
description: "Install events/jobs/cache/storage"
|
|
11990
|
+
description: "Install events/jobs/cache/storage/\u2026"
|
|
11401
11991
|
});
|
|
11402
11992
|
}
|
|
11403
11993
|
return out;
|
|
11404
11994
|
}
|
|
11405
|
-
var ProjectInitCommand = class extends
|
|
11995
|
+
var ProjectInitCommand = class extends Command7 {
|
|
11406
11996
|
static paths = [["project", "init"]];
|
|
11407
|
-
static usage =
|
|
11997
|
+
static usage = Command7.Usage({
|
|
11408
11998
|
description: "Scaffold a consumer project (config, shims, barrels, app.module)",
|
|
11409
11999
|
examples: [
|
|
11410
12000
|
["Initialize with defaults", "codegen project init --yes"],
|
|
@@ -11413,12 +12003,14 @@ var ProjectInitCommand = class extends Command5 {
|
|
|
11413
12003
|
["Overwrite existing shims", "codegen project init --force"]
|
|
11414
12004
|
]
|
|
11415
12005
|
});
|
|
11416
|
-
yes =
|
|
11417
|
-
dryRun =
|
|
11418
|
-
force =
|
|
11419
|
-
withTsconfig =
|
|
11420
|
-
|
|
11421
|
-
|
|
12006
|
+
yes = Option7.Boolean("--yes,-y", false);
|
|
12007
|
+
dryRun = Option7.Boolean("--dry-run", false);
|
|
12008
|
+
force = Option7.Boolean("--force", false);
|
|
12009
|
+
withTsconfig = Option7.Boolean("--with-tsconfig", false);
|
|
12010
|
+
// Vendor consumer skills into .claude/skills by default; opt out with --no-skills.
|
|
12011
|
+
skills = Option7.Boolean("--skills", true);
|
|
12012
|
+
json = Option7.Boolean("--json", false);
|
|
12013
|
+
cwd = Option7.String("--cwd", { required: false });
|
|
11422
12014
|
async execute() {
|
|
11423
12015
|
if (this.json) setJsonMode(true);
|
|
11424
12016
|
const ctx = await loadContext({
|
|
@@ -11449,6 +12041,7 @@ var ProjectInitCommand = class extends Command5 {
|
|
|
11449
12041
|
console.log("");
|
|
11450
12042
|
}
|
|
11451
12043
|
const result = writePlan(plan);
|
|
12044
|
+
const skillsResult = this.skills ? runSkillsInstall({ cwd: ctx.cwd, dryRun: false }) : null;
|
|
11452
12045
|
if (isJsonMode()) {
|
|
11453
12046
|
printJson({
|
|
11454
12047
|
command: "project init",
|
|
@@ -11457,7 +12050,12 @@ var ProjectInitCommand = class extends Command5 {
|
|
|
11457
12050
|
created: result.created.map((e) => e.relPath),
|
|
11458
12051
|
merged: result.merged.map((e) => e.relPath),
|
|
11459
12052
|
overwritten: result.overwritten.map((e) => e.relPath),
|
|
11460
|
-
skipped: result.skipped.map((e) => ({ path: e.relPath, reason: e.reason }))
|
|
12053
|
+
skipped: result.skipped.map((e) => ({ path: e.relPath, reason: e.reason })),
|
|
12054
|
+
skills: skillsResult && skillsResult.report ? {
|
|
12055
|
+
created: skillsResult.report.created.length,
|
|
12056
|
+
updated: skillsResult.report.updated.length,
|
|
12057
|
+
unchanged: skillsResult.report.unchanged.length
|
|
12058
|
+
} : null
|
|
11461
12059
|
});
|
|
11462
12060
|
return 0;
|
|
11463
12061
|
}
|
|
@@ -11486,6 +12084,22 @@ var ProjectInitCommand = class extends Command5 {
|
|
|
11486
12084
|
` ${theme.muted(icons.dash)} ${theme.muted("skip ")} ${e.relPath}${e.reason ? theme.muted(" (" + e.reason + ")") : ""}`
|
|
11487
12085
|
);
|
|
11488
12086
|
}
|
|
12087
|
+
if (skillsResult?.report) {
|
|
12088
|
+
const r = skillsResult.report;
|
|
12089
|
+
console.log(
|
|
12090
|
+
` ${theme.success(icons.check)} ${theme.muted("skills ")} .claude/skills/ ${theme.muted(
|
|
12091
|
+
`(${r.created.length} new, ${r.updated.length} updated, ${r.unchanged.length} unchanged)`
|
|
12092
|
+
)}`
|
|
12093
|
+
);
|
|
12094
|
+
} else if (!this.skills) {
|
|
12095
|
+
console.log(
|
|
12096
|
+
` ${theme.muted(icons.dash)} ${theme.muted("skip ")} .claude/skills/ ${theme.muted("(--no-skills)")}`
|
|
12097
|
+
);
|
|
12098
|
+
} else if (skillsResult && !skillsResult.ok) {
|
|
12099
|
+
console.log(
|
|
12100
|
+
` ${theme.warning(icons.warning)} ${theme.muted("skills ")} ${theme.muted(skillsResult.error ?? "skills install failed")}`
|
|
12101
|
+
);
|
|
12102
|
+
}
|
|
11489
12103
|
console.log("");
|
|
11490
12104
|
printInfo("Next steps:");
|
|
11491
12105
|
console.log(` 1. ${theme.system("bun add")} the peer deps (see docs/CONSUMER-SETUP.md)`);
|
|
@@ -11498,10 +12112,10 @@ var ProjectInitCommand = class extends Command5 {
|
|
|
11498
12112
|
};
|
|
11499
12113
|
function askConfirm(question) {
|
|
11500
12114
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
11501
|
-
return new Promise((
|
|
12115
|
+
return new Promise((resolve4) => {
|
|
11502
12116
|
rl.question(`${question} [Y/n] `, (answer) => {
|
|
11503
12117
|
rl.close();
|
|
11504
|
-
|
|
12118
|
+
resolve4(answer.trim().toLowerCase() !== "n");
|
|
11505
12119
|
});
|
|
11506
12120
|
});
|
|
11507
12121
|
}
|
|
@@ -11534,9 +12148,9 @@ function renderPlanOnly(plan, opts) {
|
|
|
11534
12148
|
}
|
|
11535
12149
|
return 0;
|
|
11536
12150
|
}
|
|
11537
|
-
var ProjectScanCommand = class extends
|
|
12151
|
+
var ProjectScanCommand = class extends Command7 {
|
|
11538
12152
|
static paths = [["project", "scan"]];
|
|
11539
|
-
static usage =
|
|
12153
|
+
static usage = Command7.Usage({
|
|
11540
12154
|
description: "Detect framework/ORM/architecture and propose a codegen.config.yaml",
|
|
11541
12155
|
examples: [
|
|
11542
12156
|
["Scan the current directory", "codegen project scan"],
|
|
@@ -11544,17 +12158,17 @@ var ProjectScanCommand = class extends Command5 {
|
|
|
11544
12158
|
["Preview only", "codegen project scan --dry-run"]
|
|
11545
12159
|
]
|
|
11546
12160
|
});
|
|
11547
|
-
directory =
|
|
11548
|
-
write =
|
|
11549
|
-
dryRun =
|
|
11550
|
-
verbose =
|
|
11551
|
-
json =
|
|
11552
|
-
cwd =
|
|
12161
|
+
directory = Option7.String({ required: false });
|
|
12162
|
+
write = Option7.Boolean("--write", false);
|
|
12163
|
+
dryRun = Option7.Boolean("--dry-run", false);
|
|
12164
|
+
verbose = Option7.Boolean("--verbose,-v", false);
|
|
12165
|
+
json = Option7.Boolean("--json", false);
|
|
12166
|
+
cwd = Option7.String("--cwd", { required: false });
|
|
11553
12167
|
async execute() {
|
|
11554
12168
|
if (this.json) setJsonMode(true);
|
|
11555
|
-
const baseCwd = this.cwd ?
|
|
11556
|
-
const target = this.directory ?
|
|
11557
|
-
if (!
|
|
12169
|
+
const baseCwd = this.cwd ? path28.resolve(this.cwd) : process.cwd();
|
|
12170
|
+
const target = this.directory ? path28.resolve(baseCwd, this.directory) : baseCwd;
|
|
12171
|
+
if (!fs17.existsSync(target)) {
|
|
11558
12172
|
printError(`Directory not found: ${target}`);
|
|
11559
12173
|
return 1;
|
|
11560
12174
|
}
|
|
@@ -11604,8 +12218,8 @@ var ProjectScanCommand = class extends Command5 {
|
|
|
11604
12218
|
`architecture: ${profile.architecture.evidence.join(", ") || "\u2014"}`
|
|
11605
12219
|
]);
|
|
11606
12220
|
}
|
|
11607
|
-
const outPath =
|
|
11608
|
-
const existsNow =
|
|
12221
|
+
const outPath = path28.join(target, "codegen.config.yaml");
|
|
12222
|
+
const existsNow = fs17.existsSync(outPath);
|
|
11609
12223
|
if (this.dryRun) {
|
|
11610
12224
|
console.log("");
|
|
11611
12225
|
printInfo("Dry run \u2014 proposed codegen.config.yaml:");
|
|
@@ -11618,7 +12232,7 @@ var ProjectScanCommand = class extends Command5 {
|
|
|
11618
12232
|
printWarning(`${outPath} already exists \u2014 pass --force via edit; skipping.`);
|
|
11619
12233
|
return 0;
|
|
11620
12234
|
}
|
|
11621
|
-
|
|
12235
|
+
fs17.writeFileSync(outPath, yamlText);
|
|
11622
12236
|
printSuccess(`wrote ${outPath}`);
|
|
11623
12237
|
return 0;
|
|
11624
12238
|
}
|
|
@@ -11636,14 +12250,14 @@ function printMutedBlock(title, lines) {
|
|
|
11636
12250
|
console.log(theme.muted(title + ":"));
|
|
11637
12251
|
for (const l of lines) console.log(theme.muted(" " + l));
|
|
11638
12252
|
}
|
|
11639
|
-
var ProjectConfigCommand = class extends
|
|
12253
|
+
var ProjectConfigCommand = class extends Command7 {
|
|
11640
12254
|
static paths = [["project", "config"]];
|
|
11641
|
-
static usage =
|
|
12255
|
+
static usage = Command7.Usage({
|
|
11642
12256
|
description: "Print the resolved codegen config (YAML or JSON)"
|
|
11643
12257
|
});
|
|
11644
|
-
json =
|
|
11645
|
-
cwd =
|
|
11646
|
-
configPath =
|
|
12258
|
+
json = Option7.Boolean("--json", false);
|
|
12259
|
+
cwd = Option7.String("--cwd", { required: false });
|
|
12260
|
+
configPath = Option7.String("--config", { required: false });
|
|
11647
12261
|
async execute() {
|
|
11648
12262
|
if (this.json) setJsonMode(true);
|
|
11649
12263
|
const ctx = await loadContext({
|
|
@@ -11675,9 +12289,9 @@ var ProjectConfigCommand = class extends Command5 {
|
|
|
11675
12289
|
return 0;
|
|
11676
12290
|
}
|
|
11677
12291
|
};
|
|
11678
|
-
var ProjectInspectCommand = class extends
|
|
12292
|
+
var ProjectInspectCommand = class extends Command7 {
|
|
11679
12293
|
static paths = [["project", "inspect"]];
|
|
11680
|
-
static usage =
|
|
12294
|
+
static usage = Command7.Usage({
|
|
11681
12295
|
description: "Domain analysis, statistics, documentation, and manifest operations",
|
|
11682
12296
|
examples: [
|
|
11683
12297
|
["Full analysis", "codegen project inspect --kind analyze"],
|
|
@@ -11687,20 +12301,20 @@ var ProjectInspectCommand = class extends Command5 {
|
|
|
11687
12301
|
["Review suggestions", "codegen project inspect --kind suggestions"]
|
|
11688
12302
|
]
|
|
11689
12303
|
});
|
|
11690
|
-
kind =
|
|
11691
|
-
dir =
|
|
11692
|
-
format =
|
|
11693
|
-
output =
|
|
11694
|
-
strict =
|
|
11695
|
-
entity =
|
|
11696
|
-
force =
|
|
11697
|
-
accept =
|
|
11698
|
-
skip =
|
|
11699
|
-
acceptAll =
|
|
11700
|
-
skipAll =
|
|
11701
|
-
json =
|
|
11702
|
-
cwd =
|
|
11703
|
-
configPath =
|
|
12304
|
+
kind = Option7.String("--kind", { required: true });
|
|
12305
|
+
dir = Option7.String({ required: false });
|
|
12306
|
+
format = Option7.String("--format", "console");
|
|
12307
|
+
output = Option7.String("--output,-o", { required: false });
|
|
12308
|
+
strict = Option7.Boolean("--strict", false);
|
|
12309
|
+
entity = Option7.String("--entity", { required: false });
|
|
12310
|
+
force = Option7.Boolean("--force", false);
|
|
12311
|
+
accept = Option7.String("--accept", { required: false });
|
|
12312
|
+
skip = Option7.String("--skip", { required: false });
|
|
12313
|
+
acceptAll = Option7.Boolean("--accept-all", false);
|
|
12314
|
+
skipAll = Option7.Boolean("--skip-all", false);
|
|
12315
|
+
json = Option7.Boolean("--json", false);
|
|
12316
|
+
cwd = Option7.String("--cwd", { required: false });
|
|
12317
|
+
configPath = Option7.String("--config", { required: false });
|
|
11704
12318
|
async execute() {
|
|
11705
12319
|
if (this.json || this.format === "json") setJsonMode(true);
|
|
11706
12320
|
const ctx = await loadContext({
|
|
@@ -11725,12 +12339,12 @@ var ProjectInspectCommand = class extends Command5 {
|
|
|
11725
12339
|
return 2;
|
|
11726
12340
|
}
|
|
11727
12341
|
resolveEntitiesDir(ctx) {
|
|
11728
|
-
if (this.dir) return
|
|
11729
|
-
return ctx.entitiesDir ??
|
|
12342
|
+
if (this.dir) return path28.resolve(ctx.cwd, this.dir);
|
|
12343
|
+
return ctx.entitiesDir ?? path28.resolve(ctx.cwd, "entities");
|
|
11730
12344
|
}
|
|
11731
12345
|
async runAnalysis(ctx, kind) {
|
|
11732
12346
|
const entitiesDir = this.resolveEntitiesDir(ctx);
|
|
11733
|
-
if (!entitiesDir || !
|
|
12347
|
+
if (!entitiesDir || !fs17.existsSync(entitiesDir)) {
|
|
11734
12348
|
printError(`Directory not found: ${entitiesDir ?? "(no entities/ dir)"}`);
|
|
11735
12349
|
return 1;
|
|
11736
12350
|
}
|
|
@@ -11760,7 +12374,7 @@ var ProjectInspectCommand = class extends Command5 {
|
|
|
11760
12374
|
out = formatConsole(filtered);
|
|
11761
12375
|
}
|
|
11762
12376
|
if (this.output) {
|
|
11763
|
-
|
|
12377
|
+
fs17.writeFileSync(this.output, out);
|
|
11764
12378
|
if (!isJsonMode()) printSuccess(`wrote ${this.output}`);
|
|
11765
12379
|
} else {
|
|
11766
12380
|
console.log(out);
|
|
@@ -11773,7 +12387,7 @@ var ProjectInspectCommand = class extends Command5 {
|
|
|
11773
12387
|
}
|
|
11774
12388
|
async runManifest(ctx) {
|
|
11775
12389
|
const entitiesDir = this.resolveEntitiesDir(ctx);
|
|
11776
|
-
if (!entitiesDir || !
|
|
12390
|
+
if (!entitiesDir || !fs17.existsSync(entitiesDir)) {
|
|
11777
12391
|
printError(`Directory not found: ${entitiesDir ?? "(no entities/ dir)"}`);
|
|
11778
12392
|
return 1;
|
|
11779
12393
|
}
|
|
@@ -11906,9 +12520,9 @@ function formatStatsConsole(result) {
|
|
|
11906
12520
|
lines.push("");
|
|
11907
12521
|
return lines.join("\n");
|
|
11908
12522
|
}
|
|
11909
|
-
var ProjectGraphCommand = class extends
|
|
12523
|
+
var ProjectGraphCommand = class extends Command7 {
|
|
11910
12524
|
static paths = [["project", "graph"]];
|
|
11911
|
-
static usage =
|
|
12525
|
+
static usage = Command7.Usage({
|
|
11912
12526
|
description: "Visualize the entity-relationship graph in a browser",
|
|
11913
12527
|
examples: [
|
|
11914
12528
|
["Open interactive graph viewer", "codegen project graph"],
|
|
@@ -11916,11 +12530,11 @@ var ProjectGraphCommand = class extends Command5 {
|
|
|
11916
12530
|
["Write graph JSON to file", "codegen project graph --output graph.json"]
|
|
11917
12531
|
]
|
|
11918
12532
|
});
|
|
11919
|
-
dir =
|
|
11920
|
-
output =
|
|
11921
|
-
json =
|
|
11922
|
-
cwd =
|
|
11923
|
-
configPath =
|
|
12533
|
+
dir = Option7.String({ required: false });
|
|
12534
|
+
output = Option7.String("--output,-o", { required: false });
|
|
12535
|
+
json = Option7.Boolean("--json", false);
|
|
12536
|
+
cwd = Option7.String("--cwd", { required: false });
|
|
12537
|
+
configPath = Option7.String("--config", { required: false });
|
|
11924
12538
|
async execute() {
|
|
11925
12539
|
if (this.json) setJsonMode(true);
|
|
11926
12540
|
const ctx = await loadContext({
|
|
@@ -11929,17 +12543,17 @@ var ProjectGraphCommand = class extends Command5 {
|
|
|
11929
12543
|
json: this.json,
|
|
11930
12544
|
skipDetection: true
|
|
11931
12545
|
});
|
|
11932
|
-
const entitiesDir = this.dir ?
|
|
11933
|
-
if (!
|
|
12546
|
+
const entitiesDir = this.dir ? path28.resolve(ctx.cwd, this.dir) : ctx.entitiesDir ?? path28.resolve(ctx.cwd, "entities");
|
|
12547
|
+
if (!fs17.existsSync(entitiesDir)) {
|
|
11934
12548
|
printError(`Entity directory not found: ${entitiesDir}`);
|
|
11935
12549
|
return 1;
|
|
11936
12550
|
}
|
|
11937
12551
|
const relCandidates = [
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
12552
|
+
path28.resolve(path28.dirname(entitiesDir), "relationships"),
|
|
12553
|
+
path28.resolve(entitiesDir, "relationships"),
|
|
12554
|
+
path28.resolve(ctx.cwd, "relationships")
|
|
11941
12555
|
];
|
|
11942
|
-
const relationshipsDir = relCandidates.find((d) =>
|
|
12556
|
+
const relationshipsDir = relCandidates.find((d) => fs17.existsSync(d));
|
|
11943
12557
|
const result = await analyzeDomain(entitiesDir, relationshipsDir);
|
|
11944
12558
|
const serialized = serializeDomainGraph(result.graph);
|
|
11945
12559
|
if (isJsonMode()) {
|
|
@@ -11953,20 +12567,20 @@ var ProjectGraphCommand = class extends Command5 {
|
|
|
11953
12567
|
return 0;
|
|
11954
12568
|
}
|
|
11955
12569
|
if (this.output) {
|
|
11956
|
-
const outPath =
|
|
11957
|
-
|
|
12570
|
+
const outPath = path28.resolve(ctx.cwd, this.output);
|
|
12571
|
+
fs17.writeFileSync(outPath, JSON.stringify(serialized, null, 2));
|
|
11958
12572
|
printSuccess(`Graph written to ${outPath}`);
|
|
11959
12573
|
printInfo(`${result.entities.length} entities, ${result.relationshipDefinitions.length} relationships, ${result.graph.edges.length} edges`);
|
|
11960
12574
|
return 0;
|
|
11961
12575
|
}
|
|
11962
12576
|
const os = await import("os");
|
|
11963
|
-
const tmpDir =
|
|
11964
|
-
const graphPath =
|
|
11965
|
-
|
|
11966
|
-
const viewerDir =
|
|
11967
|
-
const viewerDist =
|
|
11968
|
-
if (
|
|
11969
|
-
|
|
12577
|
+
const tmpDir = fs17.mkdtempSync(path28.join(os.default.tmpdir(), "codegen-graph-"));
|
|
12578
|
+
const graphPath = path28.join(tmpDir, "graph.json");
|
|
12579
|
+
fs17.writeFileSync(graphPath, JSON.stringify(serialized, null, 2));
|
|
12580
|
+
const viewerDir = path28.resolve(import.meta.dirname, "..", "..", "..", "tools", "schema-graph-viewer");
|
|
12581
|
+
const viewerDist = path28.join(viewerDir, "dist", "index.html");
|
|
12582
|
+
if (fs17.existsSync(viewerDist)) {
|
|
12583
|
+
fs17.copyFileSync(graphPath, path28.join(viewerDir, "dist", "graph.json"));
|
|
11970
12584
|
printSuccess("Graph exported");
|
|
11971
12585
|
printInfo(`${result.entities.length} entities, ${result.relationshipDefinitions.length} relationships, ${result.graph.edges.length} edges`);
|
|
11972
12586
|
printInfo(`Graph JSON: ${graphPath}`);
|
|
@@ -11988,18 +12602,19 @@ var projectNoun = {
|
|
|
11988
12602
|
ProjectConfigCommand,
|
|
11989
12603
|
ProjectInspectCommand,
|
|
11990
12604
|
ProjectGraphCommand,
|
|
11991
|
-
ProjectUpgradeOpenapiCommand
|
|
12605
|
+
ProjectUpgradeOpenapiCommand,
|
|
12606
|
+
ProjectUpdateCommand
|
|
11992
12607
|
],
|
|
11993
|
-
summary:
|
|
11994
|
-
hints:
|
|
12608
|
+
summary: summary4,
|
|
12609
|
+
hints: hints4
|
|
11995
12610
|
};
|
|
11996
12611
|
var project_default = projectNoun;
|
|
11997
12612
|
|
|
11998
12613
|
// src/cli/commands/dev.ts
|
|
11999
|
-
import
|
|
12000
|
-
import
|
|
12614
|
+
import fs18 from "fs";
|
|
12615
|
+
import path29 from "path";
|
|
12001
12616
|
import { execSync as execSync3, spawn, spawnSync } from "child_process";
|
|
12002
|
-
import { Command as
|
|
12617
|
+
import { Command as Command8, Option as Option8 } from "clipanion";
|
|
12003
12618
|
var DEFAULT_APP_PORT = 3e3;
|
|
12004
12619
|
var DEFAULT_PG_PORT = 5433;
|
|
12005
12620
|
var DEFAULT_REDIS_PORT = 6380;
|
|
@@ -12030,33 +12645,33 @@ function getRedisPort(_ctx) {
|
|
|
12030
12645
|
return Number(process.env.DEV_REDIS_PORT ?? DEFAULT_REDIS_PORT);
|
|
12031
12646
|
}
|
|
12032
12647
|
function composeFilePath(cwd) {
|
|
12033
|
-
const devPath =
|
|
12034
|
-
if (
|
|
12035
|
-
const rootPath =
|
|
12036
|
-
if (
|
|
12648
|
+
const devPath = path29.join(cwd, COMPOSE_FILE);
|
|
12649
|
+
if (fs18.existsSync(devPath)) return devPath;
|
|
12650
|
+
const rootPath = path29.join(cwd, "docker-compose.yml");
|
|
12651
|
+
if (fs18.existsSync(rootPath)) return rootPath;
|
|
12037
12652
|
return devPath;
|
|
12038
12653
|
}
|
|
12039
12654
|
function pidFilePath(cwd) {
|
|
12040
|
-
return
|
|
12655
|
+
return path29.join(cwd, PID_FILE);
|
|
12041
12656
|
}
|
|
12042
12657
|
function readAppPid(cwd) {
|
|
12043
12658
|
const p = pidFilePath(cwd);
|
|
12044
|
-
if (!
|
|
12045
|
-
const pid = parseInt(
|
|
12659
|
+
if (!fs18.existsSync(p)) return null;
|
|
12660
|
+
const pid = parseInt(fs18.readFileSync(p, "utf-8").trim(), 10);
|
|
12046
12661
|
if (isNaN(pid)) return null;
|
|
12047
12662
|
try {
|
|
12048
12663
|
process.kill(pid, 0);
|
|
12049
12664
|
return pid;
|
|
12050
12665
|
} catch {
|
|
12051
|
-
|
|
12666
|
+
fs18.rmSync(p, { force: true });
|
|
12052
12667
|
return null;
|
|
12053
12668
|
}
|
|
12054
12669
|
}
|
|
12055
12670
|
function writeAppPid(cwd, pid) {
|
|
12056
|
-
|
|
12671
|
+
fs18.writeFileSync(pidFilePath(cwd), String(pid));
|
|
12057
12672
|
}
|
|
12058
12673
|
function clearAppPid(cwd) {
|
|
12059
|
-
|
|
12674
|
+
fs18.rmSync(pidFilePath(cwd), { force: true });
|
|
12060
12675
|
}
|
|
12061
12676
|
function checkPostgres(cwd, port) {
|
|
12062
12677
|
const r = runCmd(`docker exec codegen-dev-postgres pg_isready -U postgres`, cwd, {
|
|
@@ -12096,8 +12711,10 @@ function checkApp(cwd, port) {
|
|
|
12096
12711
|
};
|
|
12097
12712
|
}
|
|
12098
12713
|
function listEntityNames(ctx) {
|
|
12099
|
-
if (!ctx.entitiesDir || !
|
|
12100
|
-
return
|
|
12714
|
+
if (!ctx.entitiesDir || !fs18.existsSync(ctx.entitiesDir)) return [];
|
|
12715
|
+
return findYamlFiles(ctx.entitiesDir).map(
|
|
12716
|
+
(f) => path29.basename(f).replace(/\.ya?ml$/, "")
|
|
12717
|
+
);
|
|
12101
12718
|
}
|
|
12102
12719
|
function formatServiceLine(svc) {
|
|
12103
12720
|
const icon = svc.healthy ? theme.success(icons.check) : theme.error(icons.error);
|
|
@@ -12106,8 +12723,8 @@ function formatServiceLine(svc) {
|
|
|
12106
12723
|
return `${icon} ${svc.name.padEnd(12)} ${theme.muted(`${svc.host}:${svc.port}`)} ${status}${pidStr}`;
|
|
12107
12724
|
}
|
|
12108
12725
|
function ensureComposeFile(cwd, pgPort, redisPort) {
|
|
12109
|
-
const composePath =
|
|
12110
|
-
if (
|
|
12726
|
+
const composePath = path29.join(cwd, COMPOSE_FILE);
|
|
12727
|
+
if (fs18.existsSync(composePath)) return composePath;
|
|
12111
12728
|
const content = `# Auto-generated by codegen dev
|
|
12112
12729
|
# Ports offset from defaults to avoid conflicts with other local services.
|
|
12113
12730
|
services:
|
|
@@ -12142,22 +12759,22 @@ services:
|
|
|
12142
12759
|
volumes:
|
|
12143
12760
|
codegen-dev-pgdata:
|
|
12144
12761
|
`;
|
|
12145
|
-
|
|
12762
|
+
fs18.writeFileSync(composePath, content);
|
|
12146
12763
|
return composePath;
|
|
12147
12764
|
}
|
|
12148
|
-
var DevUpCommand = class extends
|
|
12765
|
+
var DevUpCommand = class extends Command8 {
|
|
12149
12766
|
static paths = [["dev", "up"]];
|
|
12150
|
-
static usage =
|
|
12767
|
+
static usage = Command8.Usage({
|
|
12151
12768
|
description: "Start Docker services (Postgres + Redis), run migrations, start the NestJS app",
|
|
12152
12769
|
examples: [
|
|
12153
12770
|
["Start everything", "codegen dev up"],
|
|
12154
12771
|
["Skip app start (services only)", "codegen dev up --no-app"]
|
|
12155
12772
|
]
|
|
12156
12773
|
});
|
|
12157
|
-
noApp =
|
|
12158
|
-
json =
|
|
12159
|
-
cwd =
|
|
12160
|
-
configPath =
|
|
12774
|
+
noApp = Option8.Boolean("--no-app", false);
|
|
12775
|
+
json = Option8.Boolean("--json", false);
|
|
12776
|
+
cwd = Option8.String("--cwd", { required: false });
|
|
12777
|
+
configPath = Option8.String("--config", { required: false });
|
|
12161
12778
|
async execute() {
|
|
12162
12779
|
if (this.json) setJsonMode(true);
|
|
12163
12780
|
const ctx = await loadContext({
|
|
@@ -12191,7 +12808,7 @@ var DevUpCommand = class extends Command6 {
|
|
|
12191
12808
|
if (!pgReady) printWarning("postgres did not become healthy in time");
|
|
12192
12809
|
if (!redisReady) printWarning("redis did not become healthy in time");
|
|
12193
12810
|
const drizzleConfig = ["drizzle.config.ts", "drizzle.config.js"].find(
|
|
12194
|
-
(f) =>
|
|
12811
|
+
(f) => fs18.existsSync(path29.join(ctx.cwd, f))
|
|
12195
12812
|
);
|
|
12196
12813
|
if (drizzleConfig) {
|
|
12197
12814
|
if (!isJsonMode()) printInfo("pushing database schema...");
|
|
@@ -12211,8 +12828,8 @@ var DevUpCommand = class extends Command6 {
|
|
|
12211
12828
|
if (!isJsonMode()) printInfo("starting NestJS app...");
|
|
12212
12829
|
const dbUrl = `postgres://postgres:postgres@localhost:${pgPort}/codegen_dev`;
|
|
12213
12830
|
const redisUrl = `redis://localhost:${redisPort}`;
|
|
12214
|
-
const logFile =
|
|
12215
|
-
const logFd =
|
|
12831
|
+
const logFile = path29.join(ctx.cwd, ".dev-app.log");
|
|
12832
|
+
const logFd = fs18.openSync(logFile, "a");
|
|
12216
12833
|
const child = spawn("bun", ["src/main.ts"], {
|
|
12217
12834
|
cwd: ctx.cwd,
|
|
12218
12835
|
detached: true,
|
|
@@ -12225,7 +12842,7 @@ var DevUpCommand = class extends Command6 {
|
|
|
12225
12842
|
}
|
|
12226
12843
|
});
|
|
12227
12844
|
child.unref();
|
|
12228
|
-
|
|
12845
|
+
fs18.closeSync(logFd);
|
|
12229
12846
|
if (child.pid) {
|
|
12230
12847
|
writeAppPid(ctx.cwd, child.pid);
|
|
12231
12848
|
spawnSync("sleep", ["2"]);
|
|
@@ -12255,15 +12872,15 @@ var DevUpCommand = class extends Command6 {
|
|
|
12255
12872
|
return 0;
|
|
12256
12873
|
}
|
|
12257
12874
|
};
|
|
12258
|
-
var DevDownCommand = class extends
|
|
12875
|
+
var DevDownCommand = class extends Command8 {
|
|
12259
12876
|
static paths = [["dev", "down"]];
|
|
12260
|
-
static usage =
|
|
12877
|
+
static usage = Command8.Usage({
|
|
12261
12878
|
description: "Stop Docker services and the NestJS app"
|
|
12262
12879
|
});
|
|
12263
|
-
volumes =
|
|
12264
|
-
json =
|
|
12265
|
-
cwd =
|
|
12266
|
-
configPath =
|
|
12880
|
+
volumes = Option8.Boolean("--volumes,-v", false);
|
|
12881
|
+
json = Option8.Boolean("--json", false);
|
|
12882
|
+
cwd = Option8.String("--cwd", { required: false });
|
|
12883
|
+
configPath = Option8.String("--config", { required: false });
|
|
12267
12884
|
async execute() {
|
|
12268
12885
|
if (this.json) setJsonMode(true);
|
|
12269
12886
|
const ctx = await loadContext({
|
|
@@ -12299,14 +12916,14 @@ var DevDownCommand = class extends Command6 {
|
|
|
12299
12916
|
return 0;
|
|
12300
12917
|
}
|
|
12301
12918
|
};
|
|
12302
|
-
var DevStatusCommand = class extends
|
|
12919
|
+
var DevStatusCommand = class extends Command8 {
|
|
12303
12920
|
static paths = [["dev", "status"]];
|
|
12304
|
-
static usage =
|
|
12921
|
+
static usage = Command8.Usage({
|
|
12305
12922
|
description: "Show status of Docker services and the NestJS app"
|
|
12306
12923
|
});
|
|
12307
|
-
json =
|
|
12308
|
-
cwd =
|
|
12309
|
-
configPath =
|
|
12924
|
+
json = Option8.Boolean("--json", false);
|
|
12925
|
+
cwd = Option8.String("--cwd", { required: false });
|
|
12926
|
+
configPath = Option8.String("--config", { required: false });
|
|
12310
12927
|
async execute() {
|
|
12311
12928
|
if (this.json) setJsonMode(true);
|
|
12312
12929
|
const ctx = await loadContext({
|
|
@@ -12334,9 +12951,9 @@ var DevStatusCommand = class extends Command6 {
|
|
|
12334
12951
|
return 0;
|
|
12335
12952
|
}
|
|
12336
12953
|
};
|
|
12337
|
-
var DevLogsCommand = class extends
|
|
12954
|
+
var DevLogsCommand = class extends Command8 {
|
|
12338
12955
|
static paths = [["dev", "logs"]];
|
|
12339
|
-
static usage =
|
|
12956
|
+
static usage = Command8.Usage({
|
|
12340
12957
|
description: "Tail application and Docker service logs",
|
|
12341
12958
|
examples: [
|
|
12342
12959
|
["Tail app logs", "codegen dev logs"],
|
|
@@ -12344,11 +12961,11 @@ var DevLogsCommand = class extends Command6 {
|
|
|
12344
12961
|
["Show last N lines", "codegen dev logs --tail 50"]
|
|
12345
12962
|
]
|
|
12346
12963
|
});
|
|
12347
|
-
docker =
|
|
12348
|
-
tail =
|
|
12349
|
-
json =
|
|
12350
|
-
cwd =
|
|
12351
|
-
configPath =
|
|
12964
|
+
docker = Option8.Boolean("--docker", false);
|
|
12965
|
+
tail = Option8.String("--tail", "30");
|
|
12966
|
+
json = Option8.Boolean("--json", false);
|
|
12967
|
+
cwd = Option8.String("--cwd", { required: false });
|
|
12968
|
+
configPath = Option8.String("--config", { required: false });
|
|
12352
12969
|
async execute() {
|
|
12353
12970
|
if (this.json) setJsonMode(true);
|
|
12354
12971
|
const ctx = await loadContext({
|
|
@@ -12369,8 +12986,8 @@ var DevLogsCommand = class extends Command6 {
|
|
|
12369
12986
|
}
|
|
12370
12987
|
return 0;
|
|
12371
12988
|
}
|
|
12372
|
-
const logFile =
|
|
12373
|
-
if (!
|
|
12989
|
+
const logFile = path29.join(ctx.cwd, ".dev-app.log");
|
|
12990
|
+
if (!fs18.existsSync(logFile)) {
|
|
12374
12991
|
printInfo("no app logs found \u2014 is the app running?");
|
|
12375
12992
|
return 0;
|
|
12376
12993
|
}
|
|
@@ -12382,14 +12999,14 @@ var DevLogsCommand = class extends Command6 {
|
|
|
12382
12999
|
return 0;
|
|
12383
13000
|
}
|
|
12384
13001
|
};
|
|
12385
|
-
var DevRestartCommand = class extends
|
|
13002
|
+
var DevRestartCommand = class extends Command8 {
|
|
12386
13003
|
static paths = [["dev", "restart"]];
|
|
12387
|
-
static usage =
|
|
13004
|
+
static usage = Command8.Usage({
|
|
12388
13005
|
description: "Restart the NestJS app (keep Docker services running)"
|
|
12389
13006
|
});
|
|
12390
|
-
json =
|
|
12391
|
-
cwd =
|
|
12392
|
-
configPath =
|
|
13007
|
+
json = Option8.Boolean("--json", false);
|
|
13008
|
+
cwd = Option8.String("--cwd", { required: false });
|
|
13009
|
+
configPath = Option8.String("--config", { required: false });
|
|
12393
13010
|
async execute() {
|
|
12394
13011
|
if (this.json) setJsonMode(true);
|
|
12395
13012
|
const ctx = await loadContext({
|
|
@@ -12413,8 +13030,8 @@ var DevRestartCommand = class extends Command6 {
|
|
|
12413
13030
|
spawnSync("sleep", ["1"]);
|
|
12414
13031
|
const dbUrl = `postgres://postgres:postgres@localhost:${pgPort}/codegen_dev`;
|
|
12415
13032
|
const redisUrl = `redis://localhost:${redisPort}`;
|
|
12416
|
-
const logFile =
|
|
12417
|
-
const logFd =
|
|
13033
|
+
const logFile = path29.join(ctx.cwd, ".dev-app.log");
|
|
13034
|
+
const logFd = fs18.openSync(logFile, "a");
|
|
12418
13035
|
const child = spawn("bun", ["src/main.ts"], {
|
|
12419
13036
|
cwd: ctx.cwd,
|
|
12420
13037
|
detached: true,
|
|
@@ -12427,7 +13044,7 @@ var DevRestartCommand = class extends Command6 {
|
|
|
12427
13044
|
}
|
|
12428
13045
|
});
|
|
12429
13046
|
child.unref();
|
|
12430
|
-
|
|
13047
|
+
fs18.closeSync(logFd);
|
|
12431
13048
|
if (child.pid) {
|
|
12432
13049
|
writeAppPid(ctx.cwd, child.pid);
|
|
12433
13050
|
spawnSync("sleep", ["2"]);
|
|
@@ -12489,7 +13106,7 @@ function renderDevStatus(ctx) {
|
|
|
12489
13106
|
{ command: "/dev-test", description: "Run test suite + endpoint verification" }
|
|
12490
13107
|
]);
|
|
12491
13108
|
}
|
|
12492
|
-
async function
|
|
13109
|
+
async function summary5(ctx) {
|
|
12493
13110
|
const pgPort = getPgPort(ctx);
|
|
12494
13111
|
const redisPort = getRedisPort(ctx);
|
|
12495
13112
|
const appPort = getAppPort(ctx);
|
|
@@ -12513,7 +13130,7 @@ async function summary4(ctx) {
|
|
|
12513
13130
|
footer: `${running}/${total} services healthy`
|
|
12514
13131
|
};
|
|
12515
13132
|
}
|
|
12516
|
-
async function
|
|
13133
|
+
async function hints5(ctx) {
|
|
12517
13134
|
const app = checkApp(ctx.cwd, getAppPort(ctx));
|
|
12518
13135
|
if (!app.healthy) {
|
|
12519
13136
|
return [
|
|
@@ -12536,21 +13153,20 @@ var devNoun = {
|
|
|
12536
13153
|
DevLogsCommand,
|
|
12537
13154
|
DevRestartCommand
|
|
12538
13155
|
],
|
|
12539
|
-
summary:
|
|
12540
|
-
hints:
|
|
13156
|
+
summary: summary5,
|
|
13157
|
+
hints: hints5
|
|
12541
13158
|
};
|
|
12542
13159
|
var dev_default = devNoun;
|
|
12543
13160
|
|
|
12544
13161
|
// src/cli/commands/relationship.ts
|
|
12545
|
-
import
|
|
12546
|
-
import
|
|
12547
|
-
import { Command as
|
|
13162
|
+
import fs19 from "fs";
|
|
13163
|
+
import path30 from "path";
|
|
13164
|
+
import { Command as Command9, Option as Option9 } from "clipanion";
|
|
12548
13165
|
function listRelationshipYamls2(dir) {
|
|
12549
|
-
if (!
|
|
12550
|
-
return
|
|
12551
|
-
|
|
12552
|
-
|
|
12553
|
-
}).map((f) => path27.join(dir, f));
|
|
13166
|
+
if (!fs19.existsSync(dir)) return [];
|
|
13167
|
+
return findYamlFiles(dir).filter(
|
|
13168
|
+
(full) => detectYamlType(full) === "relationship"
|
|
13169
|
+
);
|
|
12554
13170
|
}
|
|
12555
13171
|
function summarizeRelationshipFile(filePath) {
|
|
12556
13172
|
const result = loadRelationshipFromYaml(filePath);
|
|
@@ -12570,8 +13186,8 @@ function summarizeRelationshipFile(filePath) {
|
|
|
12570
13186
|
function padRight2(s, n) {
|
|
12571
13187
|
return s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
12572
13188
|
}
|
|
12573
|
-
async function
|
|
12574
|
-
const relDir =
|
|
13189
|
+
async function summary6(ctx) {
|
|
13190
|
+
const relDir = path30.resolve(ctx.cwd, "relationships");
|
|
12575
13191
|
const files = listRelationshipYamls2(relDir);
|
|
12576
13192
|
if (files.length === 0) {
|
|
12577
13193
|
return {
|
|
@@ -12603,16 +13219,16 @@ async function summary5(ctx) {
|
|
|
12603
13219
|
footer: `${rows.length} relationships`
|
|
12604
13220
|
};
|
|
12605
13221
|
}
|
|
12606
|
-
async function
|
|
13222
|
+
async function hints6(_ctx) {
|
|
12607
13223
|
return [
|
|
12608
13224
|
{ command: "codegen relationship new <file>", description: "Generate one relationship" },
|
|
12609
13225
|
{ command: "codegen relationship new --all", description: "Generate all relationships" },
|
|
12610
13226
|
{ command: "codegen relationship list", description: "List relationship definitions" }
|
|
12611
13227
|
];
|
|
12612
13228
|
}
|
|
12613
|
-
var RelationshipNewCommand = class extends
|
|
13229
|
+
var RelationshipNewCommand = class extends Command9 {
|
|
12614
13230
|
static paths = [["relationship", "new"]];
|
|
12615
|
-
static usage =
|
|
13231
|
+
static usage = Command9.Usage({
|
|
12616
13232
|
description: "Generate code for one or more relationships from YAML",
|
|
12617
13233
|
examples: [
|
|
12618
13234
|
["Generate a single relationship", "codegen relationship new relationships/person_organization.yaml"],
|
|
@@ -12620,13 +13236,13 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
12620
13236
|
["Preview without writing", "codegen relationship new relationships/person_organization.yaml --dry-run"]
|
|
12621
13237
|
]
|
|
12622
13238
|
});
|
|
12623
|
-
yaml =
|
|
12624
|
-
all =
|
|
12625
|
-
dryRun =
|
|
12626
|
-
force =
|
|
12627
|
-
json =
|
|
12628
|
-
cwd =
|
|
12629
|
-
configPath =
|
|
13239
|
+
yaml = Option9.String({ required: false });
|
|
13240
|
+
all = Option9.Boolean("--all", false);
|
|
13241
|
+
dryRun = Option9.Boolean("--dry-run", false);
|
|
13242
|
+
force = Option9.Boolean("--force", false);
|
|
13243
|
+
json = Option9.Boolean("--json", false);
|
|
13244
|
+
cwd = Option9.String("--cwd", { required: false });
|
|
13245
|
+
configPath = Option9.String("--config", { required: false });
|
|
12630
13246
|
async execute() {
|
|
12631
13247
|
if (this.json) setJsonMode(true);
|
|
12632
13248
|
const ctx = await loadContext({
|
|
@@ -12641,14 +13257,14 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
12641
13257
|
}
|
|
12642
13258
|
let targets = [];
|
|
12643
13259
|
if (this.all) {
|
|
12644
|
-
const dir =
|
|
13260
|
+
const dir = path30.resolve(ctx.cwd, "relationships");
|
|
12645
13261
|
targets = listRelationshipYamls2(dir);
|
|
12646
13262
|
if (targets.length === 0) {
|
|
12647
13263
|
printError(`No relationship YAML files found in ${dir}`);
|
|
12648
13264
|
return 1;
|
|
12649
13265
|
}
|
|
12650
13266
|
} else if (this.yaml) {
|
|
12651
|
-
targets = [
|
|
13267
|
+
targets = [path30.resolve(ctx.cwd, this.yaml)];
|
|
12652
13268
|
} else {
|
|
12653
13269
|
printError("Missing YAML path. Pass a file or --all.");
|
|
12654
13270
|
return 2;
|
|
@@ -12665,7 +13281,7 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
12665
13281
|
}
|
|
12666
13282
|
if (invalid.length > 0) {
|
|
12667
13283
|
for (const i of invalid) {
|
|
12668
|
-
printError(`${
|
|
13284
|
+
printError(`${path30.basename(i.file)} \u2014 ${i.message}`);
|
|
12669
13285
|
}
|
|
12670
13286
|
if (!isJsonMode()) return 1;
|
|
12671
13287
|
}
|
|
@@ -12696,7 +13312,7 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
12696
13312
|
}
|
|
12697
13313
|
const succeeded = [];
|
|
12698
13314
|
const failed = [
|
|
12699
|
-
...invalid.map((i) => ({ name:
|
|
13315
|
+
...invalid.map((i) => ({ name: path30.basename(i.file), file: i.file, message: i.message }))
|
|
12700
13316
|
];
|
|
12701
13317
|
for (const v of validated) {
|
|
12702
13318
|
if (!isJsonMode()) {
|
|
@@ -12715,8 +13331,8 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
12715
13331
|
if (!isJsonMode()) printError(`${v.name} \u2014 ${res.stderr ?? "failed"}`);
|
|
12716
13332
|
}
|
|
12717
13333
|
}
|
|
12718
|
-
const entitiesDir = ctx.entitiesDir ??
|
|
12719
|
-
const relationshipsDir =
|
|
13334
|
+
const entitiesDir = ctx.entitiesDir ?? path30.resolve(ctx.cwd, "entities");
|
|
13335
|
+
const relationshipsDir = path30.resolve(ctx.cwd, "relationships");
|
|
12720
13336
|
const generatedDir = resolveGeneratedDir(ctx);
|
|
12721
13337
|
const architecture = resolveArchitecture(ctx);
|
|
12722
13338
|
let barrelResult = null;
|
|
@@ -12761,21 +13377,21 @@ var RelationshipNewCommand = class extends Command7 {
|
|
|
12761
13377
|
}
|
|
12762
13378
|
if (barrelResult) {
|
|
12763
13379
|
printInfo(
|
|
12764
|
-
`barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${
|
|
13380
|
+
`barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${path30.relative(ctx.cwd, barrelResult.modulesBarrel)}, ${path30.relative(ctx.cwd, barrelResult.schemaBarrel)}`
|
|
12765
13381
|
);
|
|
12766
13382
|
}
|
|
12767
13383
|
}
|
|
12768
13384
|
return failed.length === 0 ? 0 : 1;
|
|
12769
13385
|
}
|
|
12770
13386
|
};
|
|
12771
|
-
var RelationshipListCommand = class extends
|
|
13387
|
+
var RelationshipListCommand = class extends Command9 {
|
|
12772
13388
|
static paths = [["relationship", "list"]];
|
|
12773
|
-
static usage =
|
|
13389
|
+
static usage = Command9.Usage({
|
|
12774
13390
|
description: "List defined relationships as a table"
|
|
12775
13391
|
});
|
|
12776
|
-
json =
|
|
12777
|
-
cwd =
|
|
12778
|
-
configPath =
|
|
13392
|
+
json = Option9.Boolean("--json", false);
|
|
13393
|
+
cwd = Option9.String("--cwd", { required: false });
|
|
13394
|
+
configPath = Option9.String("--config", { required: false });
|
|
12779
13395
|
async execute() {
|
|
12780
13396
|
if (this.json) setJsonMode(true);
|
|
12781
13397
|
const ctx = await loadContext({
|
|
@@ -12784,7 +13400,7 @@ var RelationshipListCommand = class extends Command7 {
|
|
|
12784
13400
|
json: this.json,
|
|
12785
13401
|
skipDetection: true
|
|
12786
13402
|
});
|
|
12787
|
-
const relDir =
|
|
13403
|
+
const relDir = path30.resolve(ctx.cwd, "relationships");
|
|
12788
13404
|
const files = listRelationshipYamls2(relDir);
|
|
12789
13405
|
if (files.length === 0) {
|
|
12790
13406
|
printInfo("No relationship definitions found.");
|
|
@@ -12818,14 +13434,14 @@ var RelationshipListCommand = class extends Command7 {
|
|
|
12818
13434
|
var relationshipNoun = {
|
|
12819
13435
|
name: "relationship",
|
|
12820
13436
|
commandClasses: [RelationshipNewCommand, RelationshipListCommand],
|
|
12821
|
-
summary:
|
|
12822
|
-
hints:
|
|
13437
|
+
summary: summary6,
|
|
13438
|
+
hints: hints6
|
|
12823
13439
|
};
|
|
12824
13440
|
var relationship_default = relationshipNoun;
|
|
12825
13441
|
|
|
12826
13442
|
// src/cli/commands/junction.ts
|
|
12827
|
-
import
|
|
12828
|
-
import { Command as
|
|
13443
|
+
import path31 from "path";
|
|
13444
|
+
import { Command as Command10, Option as Option10 } from "clipanion";
|
|
12829
13445
|
function summarizeJunctionFile(filePath) {
|
|
12830
13446
|
const result = loadJunctionFromYaml(filePath);
|
|
12831
13447
|
if (!result.success) return null;
|
|
@@ -12846,8 +13462,8 @@ function summarizeJunctionFile(filePath) {
|
|
|
12846
13462
|
function padRight3(s, n) {
|
|
12847
13463
|
return s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
12848
13464
|
}
|
|
12849
|
-
async function
|
|
12850
|
-
const junctionDir =
|
|
13465
|
+
async function summary7(ctx) {
|
|
13466
|
+
const junctionDir = path31.resolve(ctx.cwd, "junctions");
|
|
12851
13467
|
const files = listJunctionYamls(junctionDir);
|
|
12852
13468
|
if (files.length === 0) {
|
|
12853
13469
|
return {
|
|
@@ -12879,16 +13495,16 @@ async function summary6(ctx) {
|
|
|
12879
13495
|
footer: `${rows.length} junctions`
|
|
12880
13496
|
};
|
|
12881
13497
|
}
|
|
12882
|
-
async function
|
|
13498
|
+
async function hints7(_ctx) {
|
|
12883
13499
|
return [
|
|
12884
13500
|
{ command: "codegen junction new <file>", description: "Generate one junction" },
|
|
12885
13501
|
{ command: "codegen junction new --all", description: "Generate all junctions" },
|
|
12886
13502
|
{ command: "codegen junction list", description: "List junction definitions" }
|
|
12887
13503
|
];
|
|
12888
13504
|
}
|
|
12889
|
-
var JunctionNewCommand = class extends
|
|
13505
|
+
var JunctionNewCommand = class extends Command10 {
|
|
12890
13506
|
static paths = [["junction", "new"]];
|
|
12891
|
-
static usage =
|
|
13507
|
+
static usage = Command10.Usage({
|
|
12892
13508
|
description: "Generate code for one or more junctions from YAML",
|
|
12893
13509
|
examples: [
|
|
12894
13510
|
["Generate a single junction", "codegen junction new junctions/opportunity_contact.yaml"],
|
|
@@ -12896,13 +13512,13 @@ var JunctionNewCommand = class extends Command8 {
|
|
|
12896
13512
|
["Preview without writing", "codegen junction new junctions/opportunity_contact.yaml --dry-run"]
|
|
12897
13513
|
]
|
|
12898
13514
|
});
|
|
12899
|
-
yaml =
|
|
12900
|
-
all =
|
|
12901
|
-
dryRun =
|
|
12902
|
-
force =
|
|
12903
|
-
json =
|
|
12904
|
-
cwd =
|
|
12905
|
-
configPath =
|
|
13515
|
+
yaml = Option10.String({ required: false });
|
|
13516
|
+
all = Option10.Boolean("--all", false);
|
|
13517
|
+
dryRun = Option10.Boolean("--dry-run", false);
|
|
13518
|
+
force = Option10.Boolean("--force", false);
|
|
13519
|
+
json = Option10.Boolean("--json", false);
|
|
13520
|
+
cwd = Option10.String("--cwd", { required: false });
|
|
13521
|
+
configPath = Option10.String("--config", { required: false });
|
|
12906
13522
|
async execute() {
|
|
12907
13523
|
if (this.json) setJsonMode(true);
|
|
12908
13524
|
const ctx = await loadContext({
|
|
@@ -12917,14 +13533,14 @@ var JunctionNewCommand = class extends Command8 {
|
|
|
12917
13533
|
}
|
|
12918
13534
|
let targets = [];
|
|
12919
13535
|
if (this.all) {
|
|
12920
|
-
const dir =
|
|
13536
|
+
const dir = path31.resolve(ctx.cwd, "junctions");
|
|
12921
13537
|
targets = listJunctionYamls(dir);
|
|
12922
13538
|
if (targets.length === 0) {
|
|
12923
13539
|
printError(`No junction YAML files found in ${dir}`);
|
|
12924
13540
|
return 1;
|
|
12925
13541
|
}
|
|
12926
13542
|
} else if (this.yaml) {
|
|
12927
|
-
targets = [
|
|
13543
|
+
targets = [path31.resolve(ctx.cwd, this.yaml)];
|
|
12928
13544
|
} else {
|
|
12929
13545
|
printError("Missing YAML path. Pass a file or --all.");
|
|
12930
13546
|
return 2;
|
|
@@ -12943,7 +13559,7 @@ var JunctionNewCommand = class extends Command8 {
|
|
|
12943
13559
|
}
|
|
12944
13560
|
if (invalid.length > 0) {
|
|
12945
13561
|
for (const i of invalid) {
|
|
12946
|
-
printError(`${
|
|
13562
|
+
printError(`${path31.basename(i.file)} \u2014 ${i.message}`);
|
|
12947
13563
|
}
|
|
12948
13564
|
if (!isJsonMode()) return 1;
|
|
12949
13565
|
}
|
|
@@ -12974,7 +13590,7 @@ var JunctionNewCommand = class extends Command8 {
|
|
|
12974
13590
|
}
|
|
12975
13591
|
const succeeded = [];
|
|
12976
13592
|
const failed = [
|
|
12977
|
-
...invalid.map((i) => ({ name:
|
|
13593
|
+
...invalid.map((i) => ({ name: path31.basename(i.file), file: i.file, message: i.message }))
|
|
12978
13594
|
];
|
|
12979
13595
|
for (const v of validated) {
|
|
12980
13596
|
if (!isJsonMode()) {
|
|
@@ -12993,9 +13609,9 @@ var JunctionNewCommand = class extends Command8 {
|
|
|
12993
13609
|
if (!isJsonMode()) printError(`${v.name} \u2014 ${res.stderr ?? "failed"}`);
|
|
12994
13610
|
}
|
|
12995
13611
|
}
|
|
12996
|
-
const entitiesDir = ctx.entitiesDir ??
|
|
12997
|
-
const relationshipsDir =
|
|
12998
|
-
const junctionsDir =
|
|
13612
|
+
const entitiesDir = ctx.entitiesDir ?? path31.resolve(ctx.cwd, "entities");
|
|
13613
|
+
const relationshipsDir = path31.resolve(ctx.cwd, "relationships");
|
|
13614
|
+
const junctionsDir = path31.resolve(ctx.cwd, "junctions");
|
|
12999
13615
|
const generatedDir = resolveGeneratedDir(ctx);
|
|
13000
13616
|
const architecture = resolveArchitecture(ctx);
|
|
13001
13617
|
let barrelResult = null;
|
|
@@ -13041,21 +13657,21 @@ var JunctionNewCommand = class extends Command8 {
|
|
|
13041
13657
|
}
|
|
13042
13658
|
if (barrelResult) {
|
|
13043
13659
|
printInfo(
|
|
13044
|
-
`barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${
|
|
13660
|
+
`barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${path31.relative(ctx.cwd, barrelResult.modulesBarrel)}, ${path31.relative(ctx.cwd, barrelResult.schemaBarrel)}`
|
|
13045
13661
|
);
|
|
13046
13662
|
}
|
|
13047
13663
|
}
|
|
13048
13664
|
return failed.length === 0 ? 0 : 1;
|
|
13049
13665
|
}
|
|
13050
13666
|
};
|
|
13051
|
-
var JunctionListCommand = class extends
|
|
13667
|
+
var JunctionListCommand = class extends Command10 {
|
|
13052
13668
|
static paths = [["junction", "list"]];
|
|
13053
|
-
static usage =
|
|
13669
|
+
static usage = Command10.Usage({
|
|
13054
13670
|
description: "List defined junctions as a table"
|
|
13055
13671
|
});
|
|
13056
|
-
json =
|
|
13057
|
-
cwd =
|
|
13058
|
-
configPath =
|
|
13672
|
+
json = Option10.Boolean("--json", false);
|
|
13673
|
+
cwd = Option10.String("--cwd", { required: false });
|
|
13674
|
+
configPath = Option10.String("--config", { required: false });
|
|
13059
13675
|
async execute() {
|
|
13060
13676
|
if (this.json) setJsonMode(true);
|
|
13061
13677
|
const ctx = await loadContext({
|
|
@@ -13064,7 +13680,7 @@ var JunctionListCommand = class extends Command8 {
|
|
|
13064
13680
|
json: this.json,
|
|
13065
13681
|
skipDetection: true
|
|
13066
13682
|
});
|
|
13067
|
-
const junctionDir =
|
|
13683
|
+
const junctionDir = path31.resolve(ctx.cwd, "junctions");
|
|
13068
13684
|
const files = listJunctionYamls(junctionDir);
|
|
13069
13685
|
if (files.length === 0) {
|
|
13070
13686
|
printInfo("No junction definitions found.");
|
|
@@ -13098,16 +13714,16 @@ var JunctionListCommand = class extends Command8 {
|
|
|
13098
13714
|
var junctionNoun = {
|
|
13099
13715
|
name: "junction",
|
|
13100
13716
|
commandClasses: [JunctionNewCommand, JunctionListCommand],
|
|
13101
|
-
summary:
|
|
13102
|
-
hints:
|
|
13717
|
+
summary: summary7,
|
|
13718
|
+
hints: hints7
|
|
13103
13719
|
};
|
|
13104
13720
|
var junction_default = junctionNoun;
|
|
13105
13721
|
|
|
13106
13722
|
// src/cli/commands/events.ts
|
|
13107
|
-
import
|
|
13108
|
-
import
|
|
13723
|
+
import fs20 from "fs";
|
|
13724
|
+
import path32 from "path";
|
|
13109
13725
|
import ts2 from "typescript";
|
|
13110
|
-
import { Command as
|
|
13726
|
+
import { Command as Command11, Option as Option11 } from "clipanion";
|
|
13111
13727
|
function scanSourceFileForConsumers(sourceFile, filePath, eventType) {
|
|
13112
13728
|
const tier2 = [];
|
|
13113
13729
|
const tier1 = [];
|
|
@@ -13204,7 +13820,7 @@ function scanDirectoryForConsumers(rootDir, eventType) {
|
|
|
13204
13820
|
const tier1 = [];
|
|
13205
13821
|
let hasEventFlowImport = false;
|
|
13206
13822
|
for (const filePath of files) {
|
|
13207
|
-
const text2 =
|
|
13823
|
+
const text2 = fs20.readFileSync(filePath, "utf8");
|
|
13208
13824
|
const sourceFile = ts2.createSourceFile(
|
|
13209
13825
|
filePath,
|
|
13210
13826
|
text2,
|
|
@@ -13241,7 +13857,7 @@ function suggestEventTypes(target, known, limit = 3) {
|
|
|
13241
13857
|
return known.map((t) => ({ t, d: levenshtein(target, t) })).sort((a, b) => a.d - b.d).slice(0, limit).map((x) => x.t);
|
|
13242
13858
|
}
|
|
13243
13859
|
function renderConsumerReport(result, cwd) {
|
|
13244
|
-
const
|
|
13860
|
+
const rel2 = (p) => path32.relative(cwd, p) || p;
|
|
13245
13861
|
const lines = [];
|
|
13246
13862
|
const total = result.tier3.length + result.tier2.length + result.tier1.length;
|
|
13247
13863
|
lines.push(`Event: ${result.eventType}`);
|
|
@@ -13255,7 +13871,7 @@ function renderConsumerReport(result, cwd) {
|
|
|
13255
13871
|
const labelWidth = Math.max(...result.tier3.map((h) => h.triggerId.length)) + 2;
|
|
13256
13872
|
for (const h of result.tier3) {
|
|
13257
13873
|
const padded = h.triggerId.padEnd(labelWidth);
|
|
13258
|
-
lines.push(` - ${padded}(${
|
|
13874
|
+
lines.push(` - ${padded}(${rel2(h.sourceFile)}:${h.sourceLine})`);
|
|
13259
13875
|
}
|
|
13260
13876
|
}
|
|
13261
13877
|
lines.push(`Tier 2 \u2014 Direct invoke via publishAndStart (${result.tier2.length}):`);
|
|
@@ -13263,7 +13879,7 @@ function renderConsumerReport(result, cwd) {
|
|
|
13263
13879
|
lines.push(" - (none)");
|
|
13264
13880
|
} else {
|
|
13265
13881
|
for (const h of result.tier2) {
|
|
13266
|
-
lines.push(` - ${
|
|
13882
|
+
lines.push(` - ${rel2(h.sourceFile)}:${h.sourceLine}`);
|
|
13267
13883
|
}
|
|
13268
13884
|
}
|
|
13269
13885
|
lines.push(`Tier 1 \u2014 Subscribers (${result.tier1.length}):`);
|
|
@@ -13271,13 +13887,13 @@ function renderConsumerReport(result, cwd) {
|
|
|
13271
13887
|
lines.push(" - (none)");
|
|
13272
13888
|
} else {
|
|
13273
13889
|
for (const h of result.tier1) {
|
|
13274
|
-
lines.push(` - ${h.siteLabel} at ${
|
|
13890
|
+
lines.push(` - ${h.siteLabel} at ${rel2(h.sourceFile)}:${h.sourceLine}`);
|
|
13275
13891
|
}
|
|
13276
13892
|
}
|
|
13277
13893
|
return lines;
|
|
13278
13894
|
}
|
|
13279
13895
|
function runConsumersScan(opts) {
|
|
13280
|
-
const scanRoot = opts.scanRoot ??
|
|
13896
|
+
const scanRoot = opts.scanRoot ?? path32.join(opts.cwd, "src");
|
|
13281
13897
|
const handlersDir = opts.handlersDir ?? scanRoot;
|
|
13282
13898
|
const allTriggers = scanHandlerFiles(handlersDir);
|
|
13283
13899
|
const tier3 = allTriggers.filter((t) => t.event === opts.eventType).map((t) => ({
|
|
@@ -13286,8 +13902,8 @@ function runConsumersScan(opts) {
|
|
|
13286
13902
|
sourceFile: t.sourceFile,
|
|
13287
13903
|
sourceLine: t.sourceLine
|
|
13288
13904
|
}));
|
|
13289
|
-
const tier21 =
|
|
13290
|
-
const eventsGeneratedDir = opts.eventsGeneratedDir ??
|
|
13905
|
+
const tier21 = fs20.existsSync(scanRoot) ? scanDirectoryForConsumers(scanRoot, opts.eventType) : { tier2: [], tier1: [], hasEventFlowImport: false };
|
|
13906
|
+
const eventsGeneratedDir = opts.eventsGeneratedDir ?? path32.join(
|
|
13291
13907
|
resolveSubsystemsRootFromContext(opts.cwd, opts.config),
|
|
13292
13908
|
"events",
|
|
13293
13909
|
"generated"
|
|
@@ -13308,15 +13924,15 @@ function runConsumersScan(opts) {
|
|
|
13308
13924
|
function resolveSubsystemsRootFromContext(cwd, config) {
|
|
13309
13925
|
const configured = config?.paths?.subsystems;
|
|
13310
13926
|
if (typeof configured === "string" && configured.length > 0) {
|
|
13311
|
-
return
|
|
13927
|
+
return path32.resolve(cwd, configured);
|
|
13312
13928
|
}
|
|
13313
13929
|
const backendSrc = config?.paths?.backend_src;
|
|
13314
13930
|
const base = typeof backendSrc === "string" && backendSrc.length > 0 ? backendSrc : "src";
|
|
13315
|
-
return
|
|
13931
|
+
return path32.resolve(cwd, base, "shared", "subsystems");
|
|
13316
13932
|
}
|
|
13317
|
-
var EventsConsumersCommand = class extends
|
|
13933
|
+
var EventsConsumersCommand = class extends Command11 {
|
|
13318
13934
|
static paths = [["events", "consumers"]];
|
|
13319
|
-
static usage =
|
|
13935
|
+
static usage = Command11.Usage({
|
|
13320
13936
|
description: "List all consumers of an event across the three tiers",
|
|
13321
13937
|
examples: [
|
|
13322
13938
|
[
|
|
@@ -13325,10 +13941,10 @@ var EventsConsumersCommand = class extends Command9 {
|
|
|
13325
13941
|
]
|
|
13326
13942
|
]
|
|
13327
13943
|
});
|
|
13328
|
-
eventType =
|
|
13329
|
-
json =
|
|
13330
|
-
cwd =
|
|
13331
|
-
configPath =
|
|
13944
|
+
eventType = Option11.String({ required: true });
|
|
13945
|
+
json = Option11.Boolean("--json", false);
|
|
13946
|
+
cwd = Option11.String("--cwd", { required: false });
|
|
13947
|
+
configPath = Option11.String("--config", { required: false });
|
|
13332
13948
|
async execute() {
|
|
13333
13949
|
if (this.json) setJsonMode(true);
|
|
13334
13950
|
const ctx = await loadContext({
|
|
@@ -13373,7 +13989,7 @@ var EventsConsumersCommand = class extends Command9 {
|
|
|
13373
13989
|
return 0;
|
|
13374
13990
|
}
|
|
13375
13991
|
};
|
|
13376
|
-
async function
|
|
13992
|
+
async function summary8(_ctx) {
|
|
13377
13993
|
return {
|
|
13378
13994
|
title: "events",
|
|
13379
13995
|
body: [
|
|
@@ -13384,7 +14000,7 @@ async function summary7(_ctx) {
|
|
|
13384
14000
|
]
|
|
13385
14001
|
};
|
|
13386
14002
|
}
|
|
13387
|
-
async function
|
|
14003
|
+
async function hints8(_ctx) {
|
|
13388
14004
|
return [
|
|
13389
14005
|
{
|
|
13390
14006
|
command: "codegen events consumers <type>",
|
|
@@ -13395,14 +14011,14 @@ async function hints7(_ctx) {
|
|
|
13395
14011
|
var eventsNoun = {
|
|
13396
14012
|
name: "events",
|
|
13397
14013
|
commandClasses: [EventsConsumersCommand],
|
|
13398
|
-
summary:
|
|
13399
|
-
hints:
|
|
14014
|
+
summary: summary8,
|
|
14015
|
+
hints: hints8
|
|
13400
14016
|
};
|
|
13401
14017
|
var events_default = eventsNoun;
|
|
13402
14018
|
|
|
13403
14019
|
// src/cli/commands/orchestration.ts
|
|
13404
|
-
import
|
|
13405
|
-
import { Command as
|
|
14020
|
+
import path33 from "path";
|
|
14021
|
+
import { Command as Command12, Option as Option12 } from "clipanion";
|
|
13406
14022
|
var DEFAULT_PATTERN_GLOBS = ["src/patterns/*.pattern.ts"];
|
|
13407
14023
|
function resolvePatternGlobs(ctx) {
|
|
13408
14024
|
const fromConfig = ctx.config?.patterns;
|
|
@@ -13415,26 +14031,26 @@ function resolveOrchestrationOutputRoot(ctx) {
|
|
|
13415
14031
|
const paths = ctx.config?.paths;
|
|
13416
14032
|
const explicit = paths?.orchestration_src;
|
|
13417
14033
|
if (typeof explicit === "string" && explicit.length > 0) {
|
|
13418
|
-
return
|
|
14034
|
+
return path33.resolve(ctx.cwd, explicit);
|
|
13419
14035
|
}
|
|
13420
14036
|
const backendSrc = typeof paths?.backend_src === "string" && paths.backend_src.length > 0 ? paths.backend_src : "app/backend/src";
|
|
13421
|
-
return
|
|
14037
|
+
return path33.resolve(ctx.cwd, backendSrc, "orchestration");
|
|
13422
14038
|
}
|
|
13423
14039
|
async function reloadRegistry(ctx) {
|
|
13424
14040
|
_resetRegistryForTests({ includeLibrary: false });
|
|
13425
14041
|
return loadAppPatterns(resolvePatternGlobs(ctx), ctx.cwd);
|
|
13426
14042
|
}
|
|
13427
|
-
var OrchestrationGenCommand = class extends
|
|
14043
|
+
var OrchestrationGenCommand = class extends Command12 {
|
|
13428
14044
|
static paths = [["orchestration", "gen"]];
|
|
13429
|
-
static usage =
|
|
14045
|
+
static usage = Command12.Usage({
|
|
13430
14046
|
description: "Emit token / providers / dispatcher / module files per orchestration pattern (ADR-032 Phase 3-2/3)."
|
|
13431
14047
|
});
|
|
13432
|
-
pattern =
|
|
13433
|
-
all =
|
|
13434
|
-
dryRun =
|
|
13435
|
-
json =
|
|
13436
|
-
cwd =
|
|
13437
|
-
configPath =
|
|
14048
|
+
pattern = Option12.String("--pattern", { required: false });
|
|
14049
|
+
all = Option12.Boolean("--all", false);
|
|
14050
|
+
dryRun = Option12.Boolean("--dry-run", false);
|
|
14051
|
+
json = Option12.Boolean("--json", false);
|
|
14052
|
+
cwd = Option12.String("--cwd", { required: false });
|
|
14053
|
+
configPath = Option12.String("--config", { required: false });
|
|
13438
14054
|
async execute() {
|
|
13439
14055
|
if (this.json) setJsonMode(true);
|
|
13440
14056
|
const ctx = await loadContext({
|
|
@@ -13507,12 +14123,12 @@ var OrchestrationGenCommand = class extends Command10 {
|
|
|
13507
14123
|
);
|
|
13508
14124
|
for (const f of result.files) {
|
|
13509
14125
|
console.log(
|
|
13510
|
-
` ${theme.muted(icons.arrow)} ${
|
|
14126
|
+
` ${theme.muted(icons.arrow)} ${path33.relative(ctx.cwd, f.outputPath)}`
|
|
13511
14127
|
);
|
|
13512
14128
|
}
|
|
13513
14129
|
} else {
|
|
13514
14130
|
printSuccess(
|
|
13515
|
-
`Emitted ${result.files.length} file(s) across ${targets.length} pattern(s) \u2192 ${
|
|
14131
|
+
`Emitted ${result.files.length} file(s) across ${targets.length} pattern(s) \u2192 ${path33.relative(ctx.cwd, outputRoot)}`
|
|
13516
14132
|
);
|
|
13517
14133
|
}
|
|
13518
14134
|
return 0;
|
|
@@ -13525,14 +14141,14 @@ var OrchestrationGenCommand = class extends Command10 {
|
|
|
13525
14141
|
}
|
|
13526
14142
|
}
|
|
13527
14143
|
};
|
|
13528
|
-
var OrchestrationListCommand = class extends
|
|
14144
|
+
var OrchestrationListCommand = class extends Command12 {
|
|
13529
14145
|
static paths = [["orchestration", "list"]];
|
|
13530
|
-
static usage =
|
|
14146
|
+
static usage = Command12.Usage({
|
|
13531
14147
|
description: "List registered orchestration patterns"
|
|
13532
14148
|
});
|
|
13533
|
-
json =
|
|
13534
|
-
cwd =
|
|
13535
|
-
configPath =
|
|
14149
|
+
json = Option12.Boolean("--json", false);
|
|
14150
|
+
cwd = Option12.String("--cwd", { required: false });
|
|
14151
|
+
configPath = Option12.String("--config", { required: false });
|
|
13536
14152
|
async execute() {
|
|
13537
14153
|
if (this.json) setJsonMode(true);
|
|
13538
14154
|
const ctx = await loadContext({
|
|
@@ -13576,14 +14192,14 @@ var OrchestrationListCommand = class extends Command10 {
|
|
|
13576
14192
|
return 0;
|
|
13577
14193
|
}
|
|
13578
14194
|
};
|
|
13579
|
-
var OrchestrationValidateCommand = class extends
|
|
14195
|
+
var OrchestrationValidateCommand = class extends Command12 {
|
|
13580
14196
|
static paths = [["orchestration", "validate"]];
|
|
13581
|
-
static usage =
|
|
14197
|
+
static usage = Command12.Usage({
|
|
13582
14198
|
description: "Run the Phase 3-1 project-level orchestration validator (ADR-032)"
|
|
13583
14199
|
});
|
|
13584
|
-
json =
|
|
13585
|
-
cwd =
|
|
13586
|
-
configPath =
|
|
14200
|
+
json = Option12.Boolean("--json", false);
|
|
14201
|
+
cwd = Option12.String("--cwd", { required: false });
|
|
14202
|
+
configPath = Option12.String("--config", { required: false });
|
|
13587
14203
|
async execute() {
|
|
13588
14204
|
if (this.json) setJsonMode(true);
|
|
13589
14205
|
const ctx = await loadContext({
|
|
@@ -13619,7 +14235,7 @@ var OrchestrationValidateCommand = class extends Command10 {
|
|
|
13619
14235
|
return errors.length === 0 && loadResult.errors.length === 0 ? 0 : 1;
|
|
13620
14236
|
}
|
|
13621
14237
|
};
|
|
13622
|
-
async function
|
|
14238
|
+
async function summary9(ctx) {
|
|
13623
14239
|
try {
|
|
13624
14240
|
await reloadRegistry(ctx);
|
|
13625
14241
|
} catch {
|
|
@@ -13633,7 +14249,7 @@ async function summary8(ctx) {
|
|
|
13633
14249
|
]
|
|
13634
14250
|
};
|
|
13635
14251
|
}
|
|
13636
|
-
async function
|
|
14252
|
+
async function hints9(_ctx) {
|
|
13637
14253
|
return [
|
|
13638
14254
|
{
|
|
13639
14255
|
command: "codegen orchestration gen",
|
|
@@ -13656,8 +14272,8 @@ var orchestrationNoun = {
|
|
|
13656
14272
|
OrchestrationListCommand,
|
|
13657
14273
|
OrchestrationValidateCommand
|
|
13658
14274
|
],
|
|
13659
|
-
summary:
|
|
13660
|
-
hints:
|
|
14275
|
+
summary: summary9,
|
|
14276
|
+
hints: hints9
|
|
13661
14277
|
};
|
|
13662
14278
|
var orchestration_default = orchestrationNoun;
|
|
13663
14279
|
|
|
@@ -13668,19 +14284,26 @@ var InitShortcut = class extends ProjectInitCommand {
|
|
|
13668
14284
|
};
|
|
13669
14285
|
var init_default = InitShortcut;
|
|
13670
14286
|
|
|
14287
|
+
// src/cli/shortcuts/update.ts
|
|
14288
|
+
var UpdateShortcut = class extends ProjectUpdateCommand {
|
|
14289
|
+
static paths = [["update"]];
|
|
14290
|
+
static usage = ProjectUpdateCommand.usage;
|
|
14291
|
+
};
|
|
14292
|
+
var update_default = UpdateShortcut;
|
|
14293
|
+
|
|
13671
14294
|
// src/cli/index.ts
|
|
13672
14295
|
function readVersion() {
|
|
13673
14296
|
try {
|
|
13674
|
-
const pkgPath =
|
|
14297
|
+
const pkgPath = join10(import.meta.dirname, "..", "..", "package.json");
|
|
13675
14298
|
const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
|
|
13676
14299
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
13677
14300
|
} catch {
|
|
13678
14301
|
return "0.0.0";
|
|
13679
14302
|
}
|
|
13680
14303
|
}
|
|
13681
|
-
var RootSummaryCommand = class extends
|
|
13682
|
-
static paths = [
|
|
13683
|
-
static usage =
|
|
14304
|
+
var RootSummaryCommand = class extends Command13 {
|
|
14305
|
+
static paths = [Command13.Default];
|
|
14306
|
+
static usage = Command13.Usage({
|
|
13684
14307
|
description: "Show project status and available noun commands"
|
|
13685
14308
|
});
|
|
13686
14309
|
async execute() {
|
|
@@ -13722,6 +14345,7 @@ var nouns = [
|
|
|
13722
14345
|
entity_default,
|
|
13723
14346
|
subsystem_default,
|
|
13724
14347
|
project_default,
|
|
14348
|
+
skills_default,
|
|
13725
14349
|
dev_default,
|
|
13726
14350
|
relationship_default,
|
|
13727
14351
|
junction_default,
|
|
@@ -13740,6 +14364,7 @@ async function main() {
|
|
|
13740
14364
|
cli.register(Builtins.VersionCommand);
|
|
13741
14365
|
cli.register(RootSummaryCommand);
|
|
13742
14366
|
cli.register(init_default);
|
|
14367
|
+
cli.register(update_default);
|
|
13743
14368
|
for (const noun of nouns) {
|
|
13744
14369
|
for (const CommandClass of noun.commandClasses) {
|
|
13745
14370
|
cli.register(CommandClass);
|