@pattern-stack/codegen 0.6.4 → 0.6.5

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +2 -0
  3. package/dist/runtime/subsystems/auth/auth-oauth-state.schema.d.ts +81 -0
  4. package/dist/runtime/subsystems/auth/auth-oauth-state.schema.js +12 -0
  5. package/dist/runtime/subsystems/auth/auth-oauth-state.schema.js.map +1 -0
  6. package/dist/runtime/subsystems/auth/auth.module.d.ts +39 -24
  7. package/dist/runtime/subsystems/auth/auth.module.js +246 -13
  8. package/dist/runtime/subsystems/auth/auth.module.js.map +1 -1
  9. package/dist/runtime/subsystems/auth/auth.tokens.d.ts +15 -2
  10. package/dist/runtime/subsystems/auth/auth.tokens.js +9 -1
  11. package/dist/runtime/subsystems/auth/auth.tokens.js.map +1 -1
  12. package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.d.ts +23 -0
  13. package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.js +68 -0
  14. package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.js.map +1 -0
  15. package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.d.ts +21 -0
  16. package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.js +51 -0
  17. package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.js.map +1 -0
  18. package/dist/runtime/subsystems/auth/controllers/auth.controller.d.ts +31 -0
  19. package/dist/runtime/subsystems/auth/controllers/auth.controller.js +137 -0
  20. package/dist/runtime/subsystems/auth/controllers/auth.controller.js.map +1 -0
  21. package/dist/runtime/subsystems/auth/index.d.ts +13 -4
  22. package/dist/runtime/subsystems/auth/index.js +253 -14
  23. package/dist/runtime/subsystems/auth/index.js.map +1 -1
  24. package/dist/runtime/subsystems/auth/protocols/integration-store.d.ts +36 -1
  25. package/dist/runtime/subsystems/auth/protocols/oauth-state-store.d.ts +33 -7
  26. package/dist/runtime/subsystems/auth/protocols/oauth-state-store.js +12 -0
  27. package/dist/runtime/subsystems/auth/protocols/oauth-state-store.js.map +1 -1
  28. package/dist/runtime/subsystems/auth/protocols/provider-strategy.d.ts +47 -0
  29. package/dist/runtime/subsystems/auth/protocols/provider-strategy.js +1 -0
  30. package/dist/runtime/subsystems/auth/protocols/provider-strategy.js.map +1 -0
  31. package/dist/runtime/subsystems/auth/protocols/user-context.d.ts +24 -0
  32. package/dist/runtime/subsystems/auth/protocols/user-context.js +1 -0
  33. package/dist/runtime/subsystems/auth/protocols/user-context.js.map +1 -0
  34. package/dist/runtime/subsystems/index.d.ts +9 -4
  35. package/dist/runtime/subsystems/index.js +247 -14
  36. package/dist/runtime/subsystems/index.js.map +1 -1
  37. package/dist/src/cli/index.js +574 -142
  38. package/dist/src/cli/index.js.map +1 -1
  39. package/package.json +1 -1
  40. package/runtime/subsystems/auth/auth-oauth-state.schema.ts +30 -0
  41. package/runtime/subsystems/auth/auth.module.ts +89 -32
  42. package/runtime/subsystems/auth/auth.tokens.ts +14 -1
  43. package/runtime/subsystems/auth/backends/state-store.drizzle-backend.ts +83 -0
  44. package/runtime/subsystems/auth/backends/state-store.memory-backend.ts +76 -0
  45. package/runtime/subsystems/auth/controllers/auth.controller.ts +155 -0
  46. package/runtime/subsystems/auth/index.ts +43 -4
  47. package/runtime/subsystems/auth/protocols/integration-store.ts +37 -0
  48. package/runtime/subsystems/auth/protocols/oauth-state-store.ts +38 -6
  49. package/runtime/subsystems/auth/protocols/provider-strategy.ts +41 -0
  50. package/runtime/subsystems/auth/protocols/user-context.ts +22 -0
  51. package/runtime/subsystems/index.ts +17 -2
  52. package/templates/subsystem/auth/app-module-hook.ejs.t +21 -0
  53. package/templates/subsystem/auth/auth-oauth-state.schema.ejs.t +35 -0
  54. package/templates/subsystem/auth/env-config.ejs.t +20 -0
  55. package/templates/subsystem/auth/prompt.js +46 -0
  56. package/templates/subsystem/auth-config/codegen-config-auth-block.ejs.t +20 -0
  57. package/templates/subsystem/auth-config/prompt.js +20 -0
  58. package/templates/subsystem/auth-integrations/app-module-hook.ejs.t +16 -0
  59. package/templates/subsystem/auth-integrations/prompt.js +23 -0
  60. package/dist/runtime/subsystems/auth/backends/oauth-state-store/in-memory.d.ts +0 -24
  61. package/dist/runtime/subsystems/auth/backends/oauth-state-store/in-memory.js +0 -24
  62. package/dist/runtime/subsystems/auth/backends/oauth-state-store/in-memory.js.map +0 -1
  63. package/runtime/subsystems/auth/backends/oauth-state-store/in-memory.ts +0 -42
@@ -2839,8 +2839,8 @@ function loadEntityFromYaml(filePath) {
2839
2839
  }
2840
2840
  function formatZodErrors(error) {
2841
2841
  return error.errors.map((err) => {
2842
- const path27 = err.path.join(".");
2843
- const location = path27 ? `at '${path27}'` : "at root";
2842
+ const path29 = err.path.join(".");
2843
+ const location = path29 ? `at '${path29}'` : "at root";
2844
2844
  return `${err.message} ${location}`;
2845
2845
  });
2846
2846
  }
@@ -3392,19 +3392,19 @@ function findCircularDependencies(graph) {
3392
3392
  const cycles = [];
3393
3393
  const visited = /* @__PURE__ */ new Set();
3394
3394
  const recursionStack = /* @__PURE__ */ new Set();
3395
- function dfs(node, path27) {
3395
+ function dfs(node, path29) {
3396
3396
  visited.add(node);
3397
3397
  recursionStack.add(node);
3398
3398
  const outgoingEdges = graph.edges.filter((e) => e.from === node);
3399
3399
  for (const edge of outgoingEdges) {
3400
3400
  if (!visited.has(edge.to)) {
3401
- dfs(edge.to, [...path27, edge.to]);
3401
+ dfs(edge.to, [...path29, edge.to]);
3402
3402
  } else if (recursionStack.has(edge.to)) {
3403
- const cycleStart = path27.indexOf(edge.to);
3403
+ const cycleStart = path29.indexOf(edge.to);
3404
3404
  if (cycleStart !== -1) {
3405
- cycles.push([...path27.slice(cycleStart), edge.to]);
3405
+ cycles.push([...path29.slice(cycleStart), edge.to]);
3406
3406
  } else {
3407
- cycles.push([...path27, edge.to]);
3407
+ cycles.push([...path29, edge.to]);
3408
3408
  }
3409
3409
  }
3410
3410
  }
@@ -4001,8 +4001,8 @@ function suggestTransitiveRelationships(graph, options) {
4001
4001
  for (const [entityName, entity] of graph.entities) {
4002
4002
  if (shouldExcludeEntity(entityName, opts)) continue;
4003
4003
  const paths = findTransitivePaths(graph, entityName, opts);
4004
- for (const path27 of paths) {
4005
- suggestions.push(createSuggestion(path27));
4004
+ for (const path29 of paths) {
4005
+ suggestions.push(createSuggestion(path29));
4006
4006
  }
4007
4007
  }
4008
4008
  return suggestions;
@@ -4033,7 +4033,7 @@ function findTransitivePaths(graph, sourceEntity, opts) {
4033
4033
  while (queue.length > 0) {
4034
4034
  const current = queue.shift();
4035
4035
  if (!current) continue;
4036
- const { entity, depth, path: path27, visited } = current;
4036
+ const { entity, depth, path: path29, visited } = current;
4037
4037
  if (depth >= opts.maxDepth) continue;
4038
4038
  const currentEntity = graph.entities.get(entity);
4039
4039
  if (!currentEntity) continue;
@@ -4044,7 +4044,7 @@ function findTransitivePaths(graph, sourceEntity, opts) {
4044
4044
  if (shouldExcludeEntity(target, opts)) continue;
4045
4045
  if (visited.has(target)) continue;
4046
4046
  const newPath = [
4047
- ...path27,
4047
+ ...path29,
4048
4048
  {
4049
4049
  via: entity,
4050
4050
  relationship: relName,
@@ -4112,15 +4112,15 @@ function generateYamlSnippet(name, target, throughPath) {
4112
4112
  target: ${target}
4113
4113
  through: "${throughPath}"`;
4114
4114
  }
4115
- function createSuggestion(path27) {
4116
- const pathDescription = [path27.source, ...path27.hops.map((h) => h.via), path27.target].join(" -> ");
4115
+ function createSuggestion(path29) {
4116
+ const pathDescription = [path29.source, ...path29.hops.map((h) => h.via), path29.target].join(" -> ");
4117
4117
  return {
4118
4118
  severity: "info",
4119
4119
  type: "transitive_suggestion",
4120
- entity: path27.source,
4120
+ entity: path29.source,
4121
4121
  message: `Potential transitive relationship: ${pathDescription}`,
4122
- suggestion: `Add "${path27.suggestedName}" relationship via "${path27.throughPath}"`,
4123
- path: path27
4122
+ suggestion: `Add "${path29.suggestedName}" relationship via "${path29.throughPath}"`,
4123
+ path: path29
4124
4124
  };
4125
4125
  }
4126
4126
 
@@ -7902,7 +7902,7 @@ var entity_default = entityNoun;
7902
7902
 
7903
7903
  // src/cli/commands/subsystem.ts
7904
7904
  import fs10 from "fs";
7905
- import path19 from "path";
7905
+ import path21 from "path";
7906
7906
  import { Command as Command3, Option as Option3 } from "clipanion";
7907
7907
 
7908
7908
  // src/cli/shared/config-block-detect.ts
@@ -8146,9 +8146,90 @@ function localsToHygenArgs5(locals) {
8146
8146
  ];
8147
8147
  }
8148
8148
 
8149
+ // src/cli/shared/auth-scaffold-locals.ts
8150
+ import crypto2 from "crypto";
8151
+ import path17 from "path";
8152
+ var FALLBACK_BACKEND_SRC3 = "src";
8153
+ var DEFAULT_REDIRECT_URI_BASE = "http://localhost:3000";
8154
+ function resolveAuthScaffoldLocals(input) {
8155
+ const { cwd, config } = input;
8156
+ const backendSrc = typeof config?.paths?.backend_src === "string" && config.paths.backend_src.length > 0 ? config.paths.backend_src : FALLBACK_BACKEND_SRC3;
8157
+ const subsystemsRoot = resolveSubsystemsRootFromConfig(cwd, config);
8158
+ const authBlock = config?.auth ?? {};
8159
+ const redirectRaw = authBlock.redirect_uri_base;
8160
+ const redirectUriBase = typeof redirectRaw === "string" && redirectRaw.length > 0 ? redirectRaw : DEFAULT_REDIRECT_URI_BASE;
8161
+ const tokenEncryptionKey = crypto2.randomBytes(32).toString("base64");
8162
+ return {
8163
+ appName: path17.basename(cwd),
8164
+ configPath: path17.resolve(cwd, "codegen.config.yaml"),
8165
+ schemaPath: path17.resolve(
8166
+ subsystemsRoot,
8167
+ "auth",
8168
+ "auth-oauth-state.schema.ts"
8169
+ ),
8170
+ appModulePath: path17.resolve(cwd, backendSrc, "app.module.ts"),
8171
+ envConfigPath: path17.resolve(cwd, ".env.config"),
8172
+ redirectUriBase,
8173
+ tokenEncryptionKey
8174
+ };
8175
+ }
8176
+ function localsToHygenArgs6(locals) {
8177
+ return [
8178
+ "--appName",
8179
+ locals.appName,
8180
+ "--configPath",
8181
+ locals.configPath,
8182
+ "--schemaPath",
8183
+ locals.schemaPath,
8184
+ "--appModulePath",
8185
+ locals.appModulePath,
8186
+ "--envConfigPath",
8187
+ locals.envConfigPath,
8188
+ "--redirectUriBase",
8189
+ locals.redirectUriBase,
8190
+ "--tokenEncryptionKey",
8191
+ locals.tokenEncryptionKey
8192
+ ];
8193
+ }
8194
+
8195
+ // src/cli/shared/auth-integrations-scaffold-locals.ts
8196
+ import path18 from "path";
8197
+ var FALLBACK_BACKEND_SRC4 = "src";
8198
+ var SHARED_DIR_NAME = "shared";
8199
+ var DEFAULT_DEFINITIONS_DIR = "definitions/entities";
8200
+ function resolveAuthIntegrationsScaffoldLocals(input) {
8201
+ const { cwd, config } = input;
8202
+ const backendSrc = typeof config?.paths?.backend_src === "string" && config.paths.backend_src.length > 0 ? config.paths.backend_src : FALLBACK_BACKEND_SRC4;
8203
+ const sharedConfigured = config?.paths?.shared;
8204
+ const sharedRoot = typeof sharedConfigured === "string" && sharedConfigured.length > 0 ? path18.resolve(cwd, sharedConfigured) : path18.resolve(cwd, backendSrc, SHARED_DIR_NAME);
8205
+ const definitionsConfigured = config?.paths?.definitions;
8206
+ const definitionsPath = typeof definitionsConfigured === "string" && definitionsConfigured.length > 0 ? path18.resolve(cwd, definitionsConfigured, "integration.yaml") : path18.resolve(cwd, DEFAULT_DEFINITIONS_DIR, "integration.yaml");
8207
+ const appModulePath = path18.resolve(cwd, backendSrc, "app.module.ts");
8208
+ let authModuleRegistered = false;
8209
+ const appModuleSource = input.readFile(appModulePath);
8210
+ if (appModuleSource && appModuleSource.includes("AuthModule.forRoot")) {
8211
+ authModuleRegistered = true;
8212
+ }
8213
+ return {
8214
+ appName: path18.basename(cwd),
8215
+ appModulePath,
8216
+ sharedRoot,
8217
+ definitionsPath,
8218
+ authModuleRegistered
8219
+ };
8220
+ }
8221
+ function localsToHygenArgs7(locals) {
8222
+ return [
8223
+ "--appName",
8224
+ locals.appName,
8225
+ "--appModulePath",
8226
+ locals.appModulePath
8227
+ ];
8228
+ }
8229
+
8149
8230
  // src/cli/shared/runtime-copier.ts
8150
8231
  import fs8 from "fs";
8151
- import path17 from "path";
8232
+ import path19 from "path";
8152
8233
  function readIfExists(p) {
8153
8234
  try {
8154
8235
  return fs8.readFileSync(p, "utf-8");
@@ -8159,7 +8240,7 @@ function readIfExists(p) {
8159
8240
  function writeFile(target, content) {
8160
8241
  const existing = readIfExists(target);
8161
8242
  if (existing === content) return "unchanged";
8162
- fs8.mkdirSync(path17.dirname(target), { recursive: true });
8243
+ fs8.mkdirSync(path19.dirname(target), { recursive: true });
8163
8244
  fs8.writeFileSync(target, content);
8164
8245
  return existing === null ? "written" : "updated";
8165
8246
  }
@@ -8173,8 +8254,8 @@ function extractRelativeImports(source) {
8173
8254
  return out;
8174
8255
  }
8175
8256
  function resolveSourceImport(sourceFile, specifier) {
8176
- const base = path17.resolve(path17.dirname(sourceFile), specifier);
8177
- const candidates = [base + ".ts", base + ".tsx", path17.join(base, "index.ts")];
8257
+ const base = path19.resolve(path19.dirname(sourceFile), specifier);
8258
+ const candidates = [base + ".ts", base + ".tsx", path19.join(base, "index.ts")];
8178
8259
  for (const c of candidates) {
8179
8260
  if (fs8.existsSync(c)) return c;
8180
8261
  }
@@ -8185,8 +8266,8 @@ async function copyRuntime(opts) {
8185
8266
  if (!fs8.existsSync(sourceDir) || !fs8.statSync(sourceDir).isDirectory()) {
8186
8267
  throw new Error(`runtime source directory not found: ${sourceDir}`);
8187
8268
  }
8188
- const runtimeRoot4 = opts.runtimeRoot ? path17.resolve(opts.runtimeRoot) : path17.resolve(sourceDir, "..", "..");
8189
- const depsTargetRoot = opts.depsTargetRoot ?? path17.resolve(targetDir, "..");
8269
+ const runtimeRoot4 = opts.runtimeRoot ? path19.resolve(opts.runtimeRoot) : path19.resolve(sourceDir, "..", "..");
8270
+ const depsTargetRoot = opts.depsTargetRoot ?? path19.resolve(targetDir, "..");
8190
8271
  const result = {
8191
8272
  written: [],
8192
8273
  updated: [],
@@ -8197,7 +8278,7 @@ async function copyRuntime(opts) {
8197
8278
  const queue = [];
8198
8279
  function walk(dir) {
8199
8280
  for (const entry of fs8.readdirSync(dir)) {
8200
- const src = path17.join(dir, entry);
8281
+ const src = path19.join(dir, entry);
8201
8282
  const stat = fs8.statSync(src);
8202
8283
  if (stat.isDirectory()) {
8203
8284
  if (entry === "generated") continue;
@@ -8206,9 +8287,9 @@ async function copyRuntime(opts) {
8206
8287
  }
8207
8288
  if (!stat.isFile()) continue;
8208
8289
  if (!entry.endsWith(".ts") && !entry.endsWith(".tsx")) continue;
8209
- const rel = path17.relative(sourceDir, src);
8290
+ const rel = path19.relative(sourceDir, src);
8210
8291
  if (filter && !filter(rel) && !filter(entry)) continue;
8211
- queue.push({ src, dest: path17.join(targetDir, rel), isDep: false });
8292
+ queue.push({ src, dest: path19.join(targetDir, rel), isDep: false });
8212
8293
  }
8213
8294
  }
8214
8295
  walk(sourceDir);
@@ -8230,11 +8311,11 @@ async function copyRuntime(opts) {
8230
8311
  for (const spec of extractRelativeImports(content)) {
8231
8312
  const resolvedSrc = resolveSourceImport(next.src, spec);
8232
8313
  if (!resolvedSrc) continue;
8233
- const relToRuntime = path17.relative(runtimeRoot4, resolvedSrc);
8234
- if (relToRuntime.startsWith("..") || path17.isAbsolute(relToRuntime)) continue;
8235
- const relToSource = path17.relative(sourceDir, resolvedSrc);
8236
- if (!relToSource.startsWith("..") && !path17.isAbsolute(relToSource)) continue;
8237
- const depDest = path17.join(depsTargetRoot, relToRuntime);
8314
+ const relToRuntime = path19.relative(runtimeRoot4, resolvedSrc);
8315
+ if (relToRuntime.startsWith("..") || path19.isAbsolute(relToRuntime)) continue;
8316
+ const relToSource = path19.relative(sourceDir, resolvedSrc);
8317
+ if (!relToSource.startsWith("..") && !path19.isAbsolute(relToSource)) continue;
8318
+ const depDest = path19.join(depsTargetRoot, relToRuntime);
8238
8319
  queue.push({ src: resolvedSrc, dest: depDest, isDep: true });
8239
8320
  }
8240
8321
  }
@@ -8244,7 +8325,7 @@ async function copyRuntime(opts) {
8244
8325
 
8245
8326
  // src/cli/shared/subsystem-detect.ts
8246
8327
  import fs9 from "fs";
8247
- import path18 from "path";
8328
+ import path20 from "path";
8248
8329
  var SUBSYSTEMS = [
8249
8330
  {
8250
8331
  name: "events",
@@ -8301,21 +8382,49 @@ var SUBSYSTEMS = [
8301
8382
  description: "Observability combiner \u2014 composes sibling read ports via @Optional() DI (ADR-025)",
8302
8383
  backends: ["combiner"],
8303
8384
  defaultBackend: "combiner"
8385
+ },
8386
+ {
8387
+ // #287. Auth subsystem (PR #289) — AuthModule + ports + OAuth state
8388
+ // store + AuthController. Backends: drizzle (prod, persists OAuth
8389
+ // state in `auth_oauth_state`) or memory (dev/tests). Detection in
8390
+ // `detectInstalledSubsystems` is a special case: auth's protocols
8391
+ // live under `protocols/`, not at the subsystem root, so we look
8392
+ // for `auth.module.ts` instead of `*.protocol.ts`.
8393
+ name: "auth",
8394
+ description: "OAuth integration auth (AuthModule + ports + state store)",
8395
+ backends: ["drizzle", "memory"],
8396
+ defaultBackend: "drizzle"
8397
+ },
8398
+ {
8399
+ // #287. Auth-integrations starter (PR #290) — vendored from
8400
+ // `examples/auth-integrations/`, NOT from `runtime/subsystems/`.
8401
+ // Bundles a canonical `integration` entity yaml + the three
8402
+ // integration-store-port adapters + the `IntegrationsService`
8403
+ // facade. Single-backend (drizzle); the runtime adapters call
8404
+ // directly into the codegen-emitted `IntegrationService` from the
8405
+ // entity layer. Detection: presence of
8406
+ // `<sharedRoot>/integrations/integrations-auth.module.ts`.
8407
+ name: "auth-integrations",
8408
+ description: "Vendored integrations entity + adapters (consumes auth subsystem)",
8409
+ backends: ["drizzle"],
8410
+ defaultBackend: "drizzle"
8304
8411
  }
8305
8412
  ];
8306
8413
  var KNOWN_NAMES = SUBSYSTEMS.map((s) => s.name);
8307
8414
  function candidateRoots(cwd, configured) {
8308
8415
  const roots = [
8309
- ...configured ? [path18.resolve(cwd, configured)] : [],
8310
- path18.resolve(cwd, "src/shared/subsystems"),
8311
- path18.resolve(cwd, "src/subsystems"),
8312
- path18.resolve(cwd, "shared/subsystems")
8416
+ ...configured ? [path20.resolve(cwd, configured)] : [],
8417
+ path20.resolve(cwd, "src/shared/subsystems"),
8418
+ path20.resolve(cwd, "src/subsystems"),
8419
+ path20.resolve(cwd, "shared/subsystems")
8313
8420
  ];
8314
8421
  return Array.from(new Set(roots));
8315
8422
  }
8316
8423
  function inferBackend(dir, name) {
8317
8424
  if (name === "observability") return "combiner";
8318
- const hasDrizzle = fs9.existsSync(path18.join(dir, `${name.replace(/s$/, "")}-bus.drizzle-backend.ts`)) || fs9.readdirSync(dir).some((f) => f.endsWith(".drizzle-backend.ts"));
8425
+ if (name === "auth") return "drizzle";
8426
+ if (name === "auth-integrations") return "drizzle";
8427
+ const hasDrizzle = fs9.existsSync(path20.join(dir, `${name.replace(/s$/, "")}-bus.drizzle-backend.ts`)) || fs9.readdirSync(dir).some((f) => f.endsWith(".drizzle-backend.ts"));
8319
8428
  const hasMemory = fs9.readdirSync(dir).some((f) => f.endsWith(".memory-backend.ts"));
8320
8429
  const hasLocal = fs9.readdirSync(dir).some((f) => f.includes("local"));
8321
8430
  if (hasDrizzle && hasMemory) return "drizzle";
@@ -8334,10 +8443,14 @@ async function detectInstalledSubsystems(ctx) {
8334
8443
  for (const name of KNOWN_NAMES) {
8335
8444
  if (seen.has(name)) continue;
8336
8445
  if (name === "openapi-config") continue;
8337
- const dir = path18.join(root, name);
8446
+ if (name === "auth-integrations") continue;
8447
+ const dir = path20.join(root, name);
8338
8448
  if (!fs9.existsSync(dir) || !fs9.statSync(dir).isDirectory()) continue;
8339
8449
  const files = fs9.readdirSync(dir);
8340
- const hasProtocol = files.some((f) => f.endsWith(".protocol.ts"));
8450
+ let hasProtocol = files.some((f) => f.endsWith(".protocol.ts"));
8451
+ if (name === "auth") {
8452
+ hasProtocol = files.includes("auth.module.ts");
8453
+ }
8341
8454
  if (!hasProtocol) continue;
8342
8455
  seen.add(name);
8343
8456
  found.push({
@@ -8348,7 +8461,7 @@ async function detectInstalledSubsystems(ctx) {
8348
8461
  }
8349
8462
  }
8350
8463
  if (!seen.has("openapi-config")) {
8351
- const configPath = path18.resolve(
8464
+ const configPath = path20.resolve(
8352
8465
  ctx.cwd,
8353
8466
  ctx.config ? "codegen.config.yaml" : "codegen.config.yaml"
8354
8467
  );
@@ -8366,18 +8479,35 @@ async function detectInstalledSubsystems(ctx) {
8366
8479
  }
8367
8480
  }
8368
8481
  }
8482
+ if (!seen.has("auth-integrations")) {
8483
+ const backendSrc = ctx.config?.paths?.backend_src ?? "src";
8484
+ const sharedConfigured = ctx.config?.paths?.shared;
8485
+ const sharedRoot = typeof sharedConfigured === "string" && sharedConfigured.length > 0 ? path20.resolve(ctx.cwd, sharedConfigured) : path20.resolve(ctx.cwd, backendSrc, "shared");
8486
+ const moduleFile = path20.join(
8487
+ sharedRoot,
8488
+ "integrations",
8489
+ "integrations-auth.module.ts"
8490
+ );
8491
+ if (fs9.existsSync(moduleFile)) {
8492
+ found.push({
8493
+ name: "auth-integrations",
8494
+ path: path20.dirname(moduleFile),
8495
+ backend: "drizzle"
8496
+ });
8497
+ }
8498
+ }
8369
8499
  return found;
8370
8500
  }
8371
8501
 
8372
8502
  // src/cli/commands/subsystem.ts
8373
8503
  function runtimeRoot() {
8374
- const pkgRoot = path19.resolve(import.meta.dirname, "..", "..", "..");
8375
- const topLevel = path19.join(pkgRoot, "runtime");
8504
+ const pkgRoot = path21.resolve(import.meta.dirname, "..", "..", "..");
8505
+ const topLevel = path21.join(pkgRoot, "runtime");
8376
8506
  if (fs10.existsSync(topLevel)) return topLevel;
8377
- return path19.join(pkgRoot, "dist", "runtime");
8507
+ return path21.join(pkgRoot, "dist", "runtime");
8378
8508
  }
8379
8509
  function subsystemSource(name) {
8380
- return path19.join(runtimeRoot(), "subsystems", name);
8510
+ return path21.join(runtimeRoot(), "subsystems", name);
8381
8511
  }
8382
8512
  function describeSubsystem(name) {
8383
8513
  return SUBSYSTEMS.find((s) => s.name === name) ?? null;
@@ -8404,7 +8534,7 @@ async function summary2(ctx) {
8404
8534
  }
8405
8535
  body.push(theme.muted("Installed:"));
8406
8536
  for (const i of installed) {
8407
- const rel = path19.relative(ctx.cwd, i.path) || i.path;
8537
+ const rel = path21.relative(ctx.cwd, i.path) || i.path;
8408
8538
  body.push(
8409
8539
  ` ${theme.success(icons.check)} ${i.name.padEnd(10)} ${theme.muted(
8410
8540
  `${i.backend} backend`
@@ -8461,6 +8591,9 @@ function backendFileFilter(backend, subsystemName) {
8461
8591
  if (subsystemName === "sync" && file === "sync-audit.schema.ts") {
8462
8592
  return false;
8463
8593
  }
8594
+ if (subsystemName === "auth" && file === "auth-oauth-state.schema.ts") {
8595
+ return false;
8596
+ }
8464
8597
  if (backend === "memory") {
8465
8598
  if (file.endsWith(".drizzle-backend.ts")) return false;
8466
8599
  if (file.endsWith(".schema.ts")) return false;
@@ -8519,6 +8652,9 @@ var SubsystemInstallCommand = class extends Command3 {
8519
8652
  if (desc3.name === "openapi-config") {
8520
8653
  return this.executeOpenApiConfig(ctx);
8521
8654
  }
8655
+ if (desc3.name === "auth-integrations") {
8656
+ return this.executeAuthIntegrations(ctx);
8657
+ }
8522
8658
  const installed = await detectInstalledSubsystems(ctx);
8523
8659
  const already = installed.find((i) => i.name === desc3.name);
8524
8660
  if (already && !this.force) {
@@ -8536,14 +8672,14 @@ var SubsystemInstallCommand = class extends Command3 {
8536
8672
  return 0;
8537
8673
  }
8538
8674
  const targetRoot = resolveSubsystemsRoot(ctx, this.target);
8539
- const subsystemTarget = path19.join(targetRoot, desc3.name);
8675
+ const subsystemTarget = path21.join(targetRoot, desc3.name);
8540
8676
  const source = subsystemSource(desc3.name);
8541
8677
  if (!fs10.existsSync(source)) {
8542
8678
  printError(`Runtime subsystem source missing: ${source}`);
8543
8679
  return 1;
8544
8680
  }
8545
8681
  if (!this.force) {
8546
- const gitCheck = checkGitSafety([path19.relative(ctx.cwd, subsystemTarget) || subsystemTarget], ctx.cwd);
8682
+ const gitCheck = checkGitSafety([path21.relative(ctx.cwd, subsystemTarget) || subsystemTarget], ctx.cwd);
8547
8683
  if (gitCheck.inRepo && !gitCheck.clean) {
8548
8684
  printWarning(
8549
8685
  `Uncommitted changes under ${subsystemTarget}. Pass --force to overwrite.`
@@ -8552,7 +8688,7 @@ var SubsystemInstallCommand = class extends Command3 {
8552
8688
  }
8553
8689
  }
8554
8690
  if (!isJsonMode()) {
8555
- printInfo(`target = ${path19.relative(ctx.cwd, subsystemTarget) || subsystemTarget}`);
8691
+ printInfo(`target = ${path21.relative(ctx.cwd, subsystemTarget) || subsystemTarget}`);
8556
8692
  printInfo(`backend = ${backend}`);
8557
8693
  }
8558
8694
  const result = await copyRuntime({
@@ -8561,7 +8697,7 @@ var SubsystemInstallCommand = class extends Command3 {
8561
8697
  filter: backendFileFilter(backend, desc3.name),
8562
8698
  resolveDeps: true,
8563
8699
  runtimeRoot: runtimeRoot(),
8564
- depsTargetRoot: path19.resolve(targetRoot, ".."),
8700
+ depsTargetRoot: path21.resolve(targetRoot, ".."),
8565
8701
  dryRun: this.dryRun
8566
8702
  });
8567
8703
  const jobsScaffold = desc3.name === "jobs" ? runJobsScaffold(ctx.cwd, ctx.config, {
@@ -8589,6 +8725,11 @@ var SubsystemInstallCommand = class extends Command3 {
8589
8725
  json: isJsonMode(),
8590
8726
  forceConfig: this.forceConfig
8591
8727
  }) : null;
8728
+ const authScaffold = desc3.name === "auth" ? runAuthScaffold(ctx.cwd, ctx.config, {
8729
+ dryRun: this.dryRun,
8730
+ json: isJsonMode(),
8731
+ forceConfig: this.forceConfig
8732
+ }) : null;
8592
8733
  if (jobsScaffold?.configBlockOutcome === "parse-error") {
8593
8734
  printError(
8594
8735
  "codegen.config.yaml is not valid YAML: refusing to inject jobs config block. Fix the YAML and re-run."
@@ -8619,6 +8760,12 @@ var SubsystemInstallCommand = class extends Command3 {
8619
8760
  );
8620
8761
  return 1;
8621
8762
  }
8763
+ if (authScaffold?.configBlockOutcome === "parse-error") {
8764
+ printError(
8765
+ "codegen.config.yaml is not valid YAML: refusing to inject auth config block. Fix the YAML and re-run."
8766
+ );
8767
+ return 1;
8768
+ }
8622
8769
  if (isJsonMode()) {
8623
8770
  printJson({
8624
8771
  command: "subsystem install",
@@ -8637,21 +8784,22 @@ var SubsystemInstallCommand = class extends Command3 {
8637
8784
  ...eventsScaffold ? { scaffold: eventsScaffold } : {},
8638
8785
  ...syncScaffold ? { scaffold: syncScaffold } : {},
8639
8786
  ...bridgeScaffold ? { scaffold: bridgeScaffold } : {},
8640
- ...observabilityScaffold ? { scaffold: observabilityScaffold } : {}
8787
+ ...observabilityScaffold ? { scaffold: observabilityScaffold } : {},
8788
+ ...authScaffold ? { scaffold: authScaffold } : {}
8641
8789
  });
8642
8790
  return 0;
8643
8791
  }
8644
8792
  if (this.dryRun) {
8645
8793
  printInfo(`Dry run \u2014 ${result.planned.length} files would be written`);
8646
8794
  for (const p of result.planned) {
8647
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8795
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8648
8796
  }
8649
8797
  if (jobsScaffold?.planned?.length) {
8650
8798
  printInfo(
8651
8799
  `Jobs scaffold \u2014 ${jobsScaffold.planned.length} template targets`
8652
8800
  );
8653
8801
  for (const p of jobsScaffold.planned) {
8654
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8802
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8655
8803
  }
8656
8804
  }
8657
8805
  if (eventsScaffold?.planned?.length) {
@@ -8659,7 +8807,7 @@ var SubsystemInstallCommand = class extends Command3 {
8659
8807
  `Events scaffold \u2014 ${eventsScaffold.planned.length} template targets`
8660
8808
  );
8661
8809
  for (const p of eventsScaffold.planned) {
8662
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8810
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8663
8811
  }
8664
8812
  }
8665
8813
  if (syncScaffold?.planned?.length) {
@@ -8667,7 +8815,7 @@ var SubsystemInstallCommand = class extends Command3 {
8667
8815
  `Sync scaffold \u2014 ${syncScaffold.planned.length} template targets`
8668
8816
  );
8669
8817
  for (const p of syncScaffold.planned) {
8670
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8818
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8671
8819
  }
8672
8820
  }
8673
8821
  if (bridgeScaffold?.planned?.length) {
@@ -8675,7 +8823,7 @@ var SubsystemInstallCommand = class extends Command3 {
8675
8823
  `Bridge scaffold \u2014 ${bridgeScaffold.planned.length} template targets`
8676
8824
  );
8677
8825
  for (const p of bridgeScaffold.planned) {
8678
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8826
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8679
8827
  }
8680
8828
  }
8681
8829
  if (observabilityScaffold?.planned?.length) {
@@ -8683,7 +8831,15 @@ var SubsystemInstallCommand = class extends Command3 {
8683
8831
  `Observability scaffold \u2014 ${observabilityScaffold.planned.length} template targets`
8684
8832
  );
8685
8833
  for (const p of observabilityScaffold.planned) {
8686
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8834
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8835
+ }
8836
+ }
8837
+ if (authScaffold?.planned?.length) {
8838
+ printInfo(
8839
+ `Auth scaffold \u2014 ${authScaffold.planned.length} template targets`
8840
+ );
8841
+ for (const p of authScaffold.planned) {
8842
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8687
8843
  }
8688
8844
  }
8689
8845
  return 0;
@@ -8750,11 +8906,29 @@ var SubsystemInstallCommand = class extends Command3 {
8750
8906
  );
8751
8907
  }
8752
8908
  }
8909
+ if (authScaffold) {
8910
+ if (authScaffold.ok) {
8911
+ printSuccess(
8912
+ `auth scaffold applied (schema, config block, app.module.ts hint, .env.config key)`
8913
+ );
8914
+ } else {
8915
+ printWarning(
8916
+ `auth scaffold (Hygen) failed \u2014 runtime files were written; re-run after fixing: ${authScaffold.error ?? "unknown error"}`
8917
+ );
8918
+ }
8919
+ }
8753
8920
  printSuccess(`${desc3.name} subsystem installed with ${backend} backend.`);
8754
8921
  if (desc3.name === "observability") {
8755
8922
  printInfo(
8756
8923
  "Register `ObservabilityModule.forRoot()` AFTER Events/Jobs/Bridge/Sync in app.module.ts"
8757
8924
  );
8925
+ } else if (desc3.name === "auth") {
8926
+ printInfo("auth subsystem installed.");
8927
+ printInfo("Next steps:");
8928
+ printInfo(" 1. Provide an IUserContext adapter (your app's session/JWT scheme \u2014 req is typed `unknown`, narrow to your framework's Request inside the adapter).");
8929
+ printInfo(" 2. Install the auth-integrations starter: cdp subsystem install auth-integrations");
8930
+ printInfo(" 3. Bind per-provider strategies into STRATEGY_REGISTRY (HubSpot, SFDC, Google, ...).");
8931
+ printInfo(" 4. Configure provider client_id/client_secret in secrets/secrets.yaml.");
8758
8932
  } else {
8759
8933
  printInfo(
8760
8934
  `Register ${capitalize(desc3.name)}Module.forRoot({ backend: '${backend}' }) in your app.module.ts`
@@ -8778,7 +8952,7 @@ var SubsystemInstallCommand = class extends Command3 {
8778
8952
  * semantics as jobs/events/sync/bridge.
8779
8953
  */
8780
8954
  async executeOpenApiConfig(ctx) {
8781
- const configPath = path19.join(ctx.cwd, "codegen.config.yaml");
8955
+ const configPath = path21.join(ctx.cwd, "codegen.config.yaml");
8782
8956
  const outcome = planConfigBlockAction(configPath, "openapi", this.forceConfig);
8783
8957
  if (outcome === "parse-error") {
8784
8958
  printError(
@@ -8797,7 +8971,7 @@ var SubsystemInstallCommand = class extends Command3 {
8797
8971
  });
8798
8972
  } else {
8799
8973
  printInfo(`Dry run \u2014 openapi config block would be ${outcome}`);
8800
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, configPath) || configPath}`);
8974
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, configPath) || configPath}`);
8801
8975
  }
8802
8976
  return 0;
8803
8977
  }
@@ -8833,6 +9007,87 @@ var SubsystemInstallCommand = class extends Command3 {
8833
9007
  );
8834
9008
  return 0;
8835
9009
  }
9010
+ /**
9011
+ * #287: install flow for the `auth-integrations` starter.
9012
+ *
9013
+ * Source is `examples/auth-integrations/`, NOT `runtime/subsystems/`,
9014
+ * so this method short-circuits the `copyRuntime` flow. It vendors the
9015
+ * adapters tree + the canonical `integration.yaml`, then invokes the
9016
+ * `subsystem auth-integrations` Hygen action to append the
9017
+ * `IntegrationsAuthModule` TODO to `app.module.ts`.
9018
+ *
9019
+ * Idempotent: pre-existing files are skipped unless `--force` is set.
9020
+ */
9021
+ async executeAuthIntegrations(ctx) {
9022
+ const installed = await detectInstalledSubsystems(ctx);
9023
+ const already = installed.find((i) => i.name === "auth-integrations");
9024
+ if (already && !this.force) {
9025
+ if (isJsonMode()) {
9026
+ printJson({
9027
+ command: "subsystem install",
9028
+ subsystem: "auth-integrations",
9029
+ status: "already-installed",
9030
+ path: already.path,
9031
+ backend: already.backend
9032
+ });
9033
+ } else {
9034
+ printInfo(
9035
+ `auth-integrations is already installed at ${already.path} (pass --force to reinstall)`
9036
+ );
9037
+ }
9038
+ return 0;
9039
+ }
9040
+ const scaffold = runAuthIntegrationsScaffold(ctx.cwd, ctx.config, {
9041
+ dryRun: this.dryRun,
9042
+ json: isJsonMode(),
9043
+ force: this.force
9044
+ });
9045
+ if (!scaffold.ok) {
9046
+ printError(
9047
+ `auth-integrations install failed: ${scaffold.error ?? "unknown error"}`
9048
+ );
9049
+ return 1;
9050
+ }
9051
+ if (isJsonMode()) {
9052
+ printJson({
9053
+ command: "subsystem install",
9054
+ subsystem: "auth-integrations",
9055
+ dryRun: this.dryRun,
9056
+ planned: scaffold.planned,
9057
+ written: scaffold.written ?? [],
9058
+ skipped: scaffold.skipped ?? [],
9059
+ authModuleRegistered: scaffold.authModuleRegistered ?? false
9060
+ });
9061
+ return 0;
9062
+ }
9063
+ if (this.dryRun) {
9064
+ printInfo(
9065
+ `Dry run \u2014 auth-integrations would vendor adapters + integration.yaml + append TODO`
9066
+ );
9067
+ for (const p of scaffold.planned) {
9068
+ console.log(
9069
+ ` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`
9070
+ );
9071
+ }
9072
+ return 0;
9073
+ }
9074
+ const writtenCount = scaffold.written?.length ?? 0;
9075
+ const skippedCount = scaffold.skipped?.length ?? 0;
9076
+ printSuccess(
9077
+ `auth-integrations starter vendored (${writtenCount} files written, ${skippedCount} skipped).`
9078
+ );
9079
+ if (scaffold.authModuleRegistered === false) {
9080
+ printWarning(
9081
+ "AuthModule.forRoot(...) not detected in app.module.ts. Run `cdp subsystem install auth` first \u2014 IntegrationsAuthModule requires ENCRYPTION_KEY from it."
9082
+ );
9083
+ }
9084
+ printInfo("auth-integrations starter vendored.");
9085
+ printInfo("Next steps:");
9086
+ printInfo(" 1. Run `cdp entity new integration` to scaffold the codegen layer (apps/api/src/modules/integrations/integration.service) the adapters import.");
9087
+ printInfo(" 2. Ensure AuthModule.forRoot(...) is registered in AppModule (run `cdp subsystem install auth` if not).");
9088
+ printInfo(" 3. Wire IntegrationsAuthModule into AppModule (see TODO appended to app.module.ts).");
9089
+ return 0;
9090
+ }
8836
9091
  };
8837
9092
  function planConfigBlockAction(configPath, subsystem, forceConfig) {
8838
9093
  if (!fs10.existsSync(configPath)) {
@@ -9171,6 +9426,183 @@ function runObservabilityScaffold(cwd, config, opts) {
9171
9426
  }
9172
9427
  return { ok: true, planned, configBlockOutcome };
9173
9428
  }
9429
+ function runAuthScaffold(cwd, config, opts) {
9430
+ const locals = resolveAuthScaffoldLocals({
9431
+ cwd,
9432
+ config
9433
+ });
9434
+ const planned = [
9435
+ locals.schemaPath,
9436
+ locals.configPath,
9437
+ locals.appModulePath,
9438
+ locals.envConfigPath
9439
+ ];
9440
+ const configBlockOutcome = planConfigBlockAction(
9441
+ locals.configPath,
9442
+ "auth",
9443
+ opts.forceConfig
9444
+ );
9445
+ if (configBlockOutcome === "parse-error") {
9446
+ return { ok: false, planned, configBlockOutcome };
9447
+ }
9448
+ if (opts.dryRun) {
9449
+ return { ok: true, planned, configBlockOutcome };
9450
+ }
9451
+ if (!fs10.existsSync(locals.envConfigPath)) {
9452
+ fs10.mkdirSync(path21.dirname(locals.envConfigPath), { recursive: true });
9453
+ fs10.writeFileSync(locals.envConfigPath, "", "utf-8");
9454
+ }
9455
+ const result = invokeHygen({
9456
+ generator: "subsystem",
9457
+ action: "auth",
9458
+ cwd,
9459
+ args: localsToHygenArgs6(locals),
9460
+ inherit: !opts.json
9461
+ });
9462
+ if (!result.ok) {
9463
+ return {
9464
+ ok: false,
9465
+ planned,
9466
+ error: result.stderr?.trim() || "hygen exited non-zero",
9467
+ configBlockOutcome
9468
+ };
9469
+ }
9470
+ const configResult = runConfigBlockAction({
9471
+ cwd,
9472
+ actionFolder: "auth-config",
9473
+ configPath: locals.configPath,
9474
+ subsystem: "auth",
9475
+ outcome: configBlockOutcome,
9476
+ json: opts.json
9477
+ });
9478
+ if (!configResult.ok) {
9479
+ return {
9480
+ ok: false,
9481
+ planned,
9482
+ error: configResult.error,
9483
+ configBlockOutcome
9484
+ };
9485
+ }
9486
+ return { ok: true, planned, configBlockOutcome };
9487
+ }
9488
+ function authIntegrationsExamplesRoot() {
9489
+ const pkgRoot = path21.resolve(import.meta.dirname, "..", "..", "..");
9490
+ const topLevel = path21.join(pkgRoot, "examples", "auth-integrations");
9491
+ if (fs10.existsSync(topLevel)) return topLevel;
9492
+ return path21.join(pkgRoot, "dist", "examples", "auth-integrations");
9493
+ }
9494
+ function copyTreeIdempotent(srcDir, destDir, force) {
9495
+ const written = [];
9496
+ const skipped = [];
9497
+ const walk = (src, dest) => {
9498
+ const entries = fs10.readdirSync(src, { withFileTypes: true });
9499
+ for (const entry of entries) {
9500
+ const srcPath = path21.join(src, entry.name);
9501
+ const destPath = path21.join(dest, entry.name);
9502
+ if (entry.isDirectory()) {
9503
+ fs10.mkdirSync(destPath, { recursive: true });
9504
+ walk(srcPath, destPath);
9505
+ continue;
9506
+ }
9507
+ if (!entry.isFile()) continue;
9508
+ if (fs10.existsSync(destPath) && !force) {
9509
+ skipped.push(destPath);
9510
+ continue;
9511
+ }
9512
+ fs10.mkdirSync(path21.dirname(destPath), { recursive: true });
9513
+ fs10.copyFileSync(srcPath, destPath);
9514
+ written.push(destPath);
9515
+ }
9516
+ };
9517
+ if (!fs10.existsSync(srcDir)) return { written, skipped };
9518
+ fs10.mkdirSync(destDir, { recursive: true });
9519
+ walk(srcDir, destDir);
9520
+ return { written, skipped };
9521
+ }
9522
+ function runAuthIntegrationsScaffold(cwd, config, opts) {
9523
+ const locals = resolveAuthIntegrationsScaffoldLocals({
9524
+ cwd,
9525
+ config,
9526
+ fileExists: (p) => fs10.existsSync(p),
9527
+ readFile: (p) => fs10.existsSync(p) ? fs10.readFileSync(p, "utf-8") : null
9528
+ });
9529
+ const examplesRoot = authIntegrationsExamplesRoot();
9530
+ if (!fs10.existsSync(examplesRoot)) {
9531
+ return {
9532
+ ok: false,
9533
+ planned: [],
9534
+ error: `auth-integrations starter source missing: ${examplesRoot}`
9535
+ };
9536
+ }
9537
+ const adaptersSrc = path21.join(examplesRoot, "runtime", "integrations");
9538
+ const adaptersDest = path21.join(locals.sharedRoot, "integrations");
9539
+ const integrationYamlSrc = path21.join(
9540
+ examplesRoot,
9541
+ "definitions",
9542
+ "entities",
9543
+ "integration.yaml"
9544
+ );
9545
+ const integrationYamlDest = locals.definitionsPath;
9546
+ const planned = [
9547
+ adaptersDest,
9548
+ integrationYamlDest,
9549
+ locals.appModulePath
9550
+ ];
9551
+ if (opts.dryRun) {
9552
+ return {
9553
+ ok: true,
9554
+ planned,
9555
+ authModuleRegistered: locals.authModuleRegistered
9556
+ };
9557
+ }
9558
+ const adapterCopy = copyTreeIdempotent(
9559
+ adaptersSrc,
9560
+ adaptersDest,
9561
+ opts.force
9562
+ );
9563
+ let yamlWritten = false;
9564
+ let yamlSkipped = false;
9565
+ try {
9566
+ if (fs10.existsSync(integrationYamlDest) && !opts.force) {
9567
+ yamlSkipped = true;
9568
+ } else if (fs10.existsSync(integrationYamlSrc)) {
9569
+ fs10.mkdirSync(path21.dirname(integrationYamlDest), { recursive: true });
9570
+ fs10.copyFileSync(integrationYamlSrc, integrationYamlDest);
9571
+ yamlWritten = true;
9572
+ }
9573
+ } catch (err) {
9574
+ return {
9575
+ ok: false,
9576
+ planned,
9577
+ error: `failed to vendor integration.yaml: ${err instanceof Error ? err.message : String(err)}`,
9578
+ authModuleRegistered: locals.authModuleRegistered
9579
+ };
9580
+ }
9581
+ const result = invokeHygen({
9582
+ generator: "subsystem",
9583
+ action: "auth-integrations",
9584
+ cwd,
9585
+ args: localsToHygenArgs7(locals),
9586
+ inherit: !opts.json
9587
+ });
9588
+ if (!result.ok) {
9589
+ return {
9590
+ ok: false,
9591
+ planned,
9592
+ error: result.stderr?.trim() || "hygen exited non-zero",
9593
+ written: adapterCopy.written.concat(yamlWritten ? [integrationYamlDest] : []),
9594
+ skipped: adapterCopy.skipped.concat(yamlSkipped ? [integrationYamlDest] : []),
9595
+ authModuleRegistered: locals.authModuleRegistered
9596
+ };
9597
+ }
9598
+ return {
9599
+ ok: true,
9600
+ planned,
9601
+ written: adapterCopy.written.concat(yamlWritten ? [integrationYamlDest] : []),
9602
+ skipped: adapterCopy.skipped.concat(yamlSkipped ? [integrationYamlDest] : []),
9603
+ authModuleRegistered: locals.authModuleRegistered
9604
+ };
9605
+ }
9174
9606
  function capitalize(s) {
9175
9607
  return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
9176
9608
  }
@@ -9200,7 +9632,7 @@ var SubsystemListCommand = class extends Command3 {
9200
9632
  name: s.name,
9201
9633
  status: inst ? "installed" : "available",
9202
9634
  backend: inst ? inst.backend : null,
9203
- path: inst ? path19.relative(ctx.cwd, inst.path) || inst.path : null
9635
+ path: inst ? path21.relative(ctx.cwd, inst.path) || inst.path : null
9204
9636
  };
9205
9637
  });
9206
9638
  if (isJsonMode()) {
@@ -9261,27 +9693,27 @@ var subsystem_default = subsystemNoun;
9261
9693
 
9262
9694
  // src/cli/commands/project.ts
9263
9695
  import fs13 from "fs";
9264
- import path22 from "path";
9696
+ import path24 from "path";
9265
9697
  import readline from "readline";
9266
9698
  import { Command as Command5, Option as Option5 } from "clipanion";
9267
9699
  import { stringify as stringifyYaml2 } from "yaml";
9268
9700
 
9269
9701
  // src/cli/shared/init-scaffold.ts
9270
9702
  import fs11 from "fs";
9271
- import path20 from "path";
9703
+ import path22 from "path";
9272
9704
  import { stringify as stringifyYaml } from "yaml";
9273
9705
  function runtimeRoot2() {
9274
- const pkgRoot = path20.resolve(import.meta.dirname, "..", "..", "..");
9275
- const topLevel = path20.join(pkgRoot, "runtime");
9706
+ const pkgRoot = path22.resolve(import.meta.dirname, "..", "..", "..");
9707
+ const topLevel = path22.join(pkgRoot, "runtime");
9276
9708
  if (fs11.existsSync(topLevel)) return topLevel;
9277
- return path20.join(pkgRoot, "dist", "runtime");
9709
+ return path22.join(pkgRoot, "dist", "runtime");
9278
9710
  }
9279
9711
  function resolveRuntimePath(cwd) {
9280
- const shimDir = path20.join(cwd, "src", "shared", "base-classes");
9281
- return path20.relative(shimDir, runtimeRoot2());
9712
+ const shimDir = path22.join(cwd, "src", "shared", "base-classes");
9713
+ return path22.relative(shimDir, runtimeRoot2());
9282
9714
  }
9283
9715
  function loadRuntimeFile(relPath2) {
9284
- return fs11.readFileSync(path20.join(runtimeRoot2(), relPath2), "utf-8");
9716
+ return fs11.readFileSync(path22.join(runtimeRoot2(), relPath2), "utf-8");
9285
9717
  }
9286
9718
  var VENDORED_RUNTIME_FILES = [
9287
9719
  // base-classes — consumer-facing inheritance targets
@@ -9678,7 +10110,7 @@ function mergeTsconfig(raw) {
9678
10110
  };
9679
10111
  }
9680
10112
  function relOf(cwd, abs) {
9681
- return path20.relative(cwd, abs) || abs;
10113
+ return path22.relative(cwd, abs) || abs;
9682
10114
  }
9683
10115
  function fileEntry(cwd, absPath, content, opts) {
9684
10116
  const exists = fs11.existsSync(absPath);
@@ -9728,7 +10160,7 @@ async function buildInitPlan(ctx, options) {
9728
10160
  const runtimePath = options.runtimePath ?? resolveRuntimePath(cwd);
9729
10161
  const entries = [];
9730
10162
  {
9731
- const configPath = path20.join(cwd, "codegen.config.yaml");
10163
+ const configPath = path22.join(cwd, "codegen.config.yaml");
9732
10164
  const config = {
9733
10165
  paths: {
9734
10166
  backend_src: "src",
@@ -9758,7 +10190,7 @@ async function buildInitPlan(ctx, options) {
9758
10190
  entries.push(fileEntry(cwd, configPath, content, { force }));
9759
10191
  }
9760
10192
  {
9761
- const tsconfigPath = path20.join(cwd, "tsconfig.json");
10193
+ const tsconfigPath = path22.join(cwd, "tsconfig.json");
9762
10194
  if (fs11.existsSync(tsconfigPath)) {
9763
10195
  const raw = fs11.readFileSync(tsconfigPath, "utf-8");
9764
10196
  const merged = mergeTsconfig(raw);
@@ -9805,20 +10237,20 @@ async function buildInitPlan(ctx, options) {
9805
10237
  entries.push(
9806
10238
  fileEntry(
9807
10239
  cwd,
9808
- path20.join(cwd, "src", "shared", "database", "database.module.ts"),
10240
+ path22.join(cwd, "src", "shared", "database", "database.module.ts"),
9809
10241
  databaseModuleContent(),
9810
10242
  { force }
9811
10243
  )
9812
10244
  );
9813
10245
  for (const v of VENDORED_RUNTIME_FILES) {
9814
10246
  entries.push(
9815
- fileEntry(cwd, path20.join(cwd, v.target), loadRuntimeFile(v.runtime), { force })
10247
+ fileEntry(cwd, path22.join(cwd, v.target), loadRuntimeFile(v.runtime), { force })
9816
10248
  );
9817
10249
  }
9818
10250
  entries.push(
9819
10251
  fileEntry(
9820
10252
  cwd,
9821
- path20.join(cwd, "src", "generated", "modules.ts"),
10253
+ path22.join(cwd, "src", "generated", "modules.ts"),
9822
10254
  emptyModulesBarrel(),
9823
10255
  { force }
9824
10256
  )
@@ -9826,13 +10258,13 @@ async function buildInitPlan(ctx, options) {
9826
10258
  entries.push(
9827
10259
  fileEntry(
9828
10260
  cwd,
9829
- path20.join(cwd, "src", "generated", "schema.ts"),
10261
+ path22.join(cwd, "src", "generated", "schema.ts"),
9830
10262
  emptySchemaBarrel(),
9831
10263
  { force }
9832
10264
  )
9833
10265
  );
9834
10266
  {
9835
- const appModulePath = path20.join(cwd, "src", "app.module.ts");
10267
+ const appModulePath = path22.join(cwd, "src", "app.module.ts");
9836
10268
  if (!fs11.existsSync(appModulePath)) {
9837
10269
  entries.push({
9838
10270
  path: appModulePath,
@@ -9850,7 +10282,7 @@ async function buildInitPlan(ctx, options) {
9850
10282
  }
9851
10283
  }
9852
10284
  {
9853
- const mainPath = path20.join(cwd, "src", "main.ts");
10285
+ const mainPath = path22.join(cwd, "src", "main.ts");
9854
10286
  if (!fs11.existsSync(mainPath)) {
9855
10287
  entries.push({
9856
10288
  path: mainPath,
@@ -9868,7 +10300,7 @@ async function buildInitPlan(ctx, options) {
9868
10300
  }
9869
10301
  }
9870
10302
  {
9871
- const schemaPath = path20.join(cwd, "src", "schema.ts");
10303
+ const schemaPath = path22.join(cwd, "src", "schema.ts");
9872
10304
  if (!fs11.existsSync(schemaPath)) {
9873
10305
  entries.push({
9874
10306
  path: schemaPath,
@@ -9885,10 +10317,10 @@ async function buildInitPlan(ctx, options) {
9885
10317
  });
9886
10318
  }
9887
10319
  }
9888
- entries.push(dirEntry(cwd, path20.join(cwd, "entities")));
10320
+ entries.push(dirEntry(cwd, path22.join(cwd, "entities")));
9889
10321
  {
9890
- const entitiesDir = path20.join(cwd, "entities");
9891
- const examplePath = path20.join(entitiesDir, "example.yaml");
10322
+ const entitiesDir = path22.join(cwd, "entities");
10323
+ const examplePath = path22.join(entitiesDir, "example.yaml");
9892
10324
  const hasOtherYamls = fs11.existsSync(entitiesDir) && fs11.readdirSync(entitiesDir).some(
9893
10325
  (f) => (f.endsWith(".yaml") || f.endsWith(".yml")) && f !== "example.yaml"
9894
10326
  );
@@ -9946,7 +10378,7 @@ function writePlan(plan) {
9946
10378
  skipped.push(e);
9947
10379
  continue;
9948
10380
  }
9949
- fs11.mkdirSync(path20.dirname(e.path), { recursive: true });
10381
+ fs11.mkdirSync(path22.dirname(e.path), { recursive: true });
9950
10382
  fs11.writeFileSync(e.path, e.content, "utf-8");
9951
10383
  if (e.action === "create") created.push(e);
9952
10384
  else if (e.action === "merge") merged.push(e);
@@ -9957,7 +10389,7 @@ function writePlan(plan) {
9957
10389
 
9958
10390
  // src/cli/commands/project-upgrade-openapi.ts
9959
10391
  import fs12 from "fs";
9960
- import path21 from "path";
10392
+ import path23 from "path";
9961
10393
  import { Command as Command4, Option as Option4 } from "clipanion";
9962
10394
  import { Project, IndentationText, QuoteKind, NewLineKind } from "ts-morph";
9963
10395
 
@@ -10196,31 +10628,31 @@ var MAIN_SWAGGER_IMPORTS = [
10196
10628
  "import { OPENAPI_REGISTRY, OpenApiRegistry } from './shared/openapi';"
10197
10629
  ];
10198
10630
  function runtimeRoot3() {
10199
- const pkgRoot = path21.resolve(import.meta.dirname, "..", "..", "..");
10200
- const topLevel = path21.join(pkgRoot, "runtime");
10631
+ const pkgRoot = path23.resolve(import.meta.dirname, "..", "..", "..");
10632
+ const topLevel = path23.join(pkgRoot, "runtime");
10201
10633
  if (fs12.existsSync(topLevel)) return topLevel;
10202
- return path21.join(pkgRoot, "dist", "runtime");
10634
+ return path23.join(pkgRoot, "dist", "runtime");
10203
10635
  }
10204
10636
  function loadRuntimeFile2(rel) {
10205
- return fs12.readFileSync(path21.join(runtimeRoot3(), rel), "utf-8");
10637
+ return fs12.readFileSync(path23.join(runtimeRoot3(), rel), "utf-8");
10206
10638
  }
10207
10639
  function resolveProjectRoot(startDir) {
10208
- let dir = path21.resolve(startDir);
10640
+ let dir = path23.resolve(startDir);
10209
10641
  for (let i = 0; i < 16; i++) {
10210
- if (fs12.existsSync(path21.join(dir, "codegen.config.yaml")) || fs12.existsSync(path21.join(dir, "package.json"))) {
10642
+ if (fs12.existsSync(path23.join(dir, "codegen.config.yaml")) || fs12.existsSync(path23.join(dir, "package.json"))) {
10211
10643
  return dir;
10212
10644
  }
10213
- const parent = path21.dirname(dir);
10645
+ const parent = path23.dirname(dir);
10214
10646
  if (parent === dir) break;
10215
10647
  dir = parent;
10216
10648
  }
10217
- return path21.resolve(startDir);
10649
+ return path23.resolve(startDir);
10218
10650
  }
10219
10651
  async function runUpgradeOpenapi(opts) {
10220
10652
  const { projectRoot, dryRun, force } = opts;
10221
10653
  const changes = [];
10222
10654
  for (const v of OPENAPI_VENDORED_FILES) {
10223
- const target = path21.join(projectRoot, v.target);
10655
+ const target = path23.join(projectRoot, v.target);
10224
10656
  const exists = fs12.existsSync(target);
10225
10657
  const newContent = loadRuntimeFile2(v.runtime);
10226
10658
  if (exists && !force) {
@@ -10236,7 +10668,7 @@ async function runUpgradeOpenapi(opts) {
10236
10668
  }
10237
10669
  } else {
10238
10670
  if (!dryRun) {
10239
- fs12.mkdirSync(path21.dirname(target), { recursive: true });
10671
+ fs12.mkdirSync(path23.dirname(target), { recursive: true });
10240
10672
  fs12.writeFileSync(target, newContent);
10241
10673
  }
10242
10674
  changes.push({
@@ -10245,7 +10677,7 @@ async function runUpgradeOpenapi(opts) {
10245
10677
  });
10246
10678
  }
10247
10679
  }
10248
- const appModulePath = path21.join(projectRoot, "src", "app.module.ts");
10680
+ const appModulePath = path23.join(projectRoot, "src", "app.module.ts");
10249
10681
  if (!fs12.existsSync(appModulePath)) {
10250
10682
  return {
10251
10683
  projectRoot,
@@ -10329,7 +10761,7 @@ async function runUpgradeOpenapi(opts) {
10329
10761
  } else {
10330
10762
  changes.push({ path: "src/app.module.ts", action: "unchanged" });
10331
10763
  }
10332
- const mainPath = path21.join(projectRoot, "src", "main.ts");
10764
+ const mainPath = path23.join(projectRoot, "src", "main.ts");
10333
10765
  if (fs12.existsSync(mainPath)) {
10334
10766
  const mainSource = project.addSourceFileAtPath(mainPath);
10335
10767
  const mainBefore = mainSource.getFullText();
@@ -10410,7 +10842,7 @@ var ProjectUpgradeOpenapiCommand = class extends Command4 {
10410
10842
  json = Option4.Boolean("--json", false);
10411
10843
  async execute() {
10412
10844
  if (this.json) setJsonMode(true);
10413
- const startDir = this.pathOpt ? path21.resolve(this.pathOpt) : process.cwd();
10845
+ const startDir = this.pathOpt ? path23.resolve(this.pathOpt) : process.cwd();
10414
10846
  if (!fs12.existsSync(startDir)) {
10415
10847
  printError(`Directory not found: ${startDir}`);
10416
10848
  return 1;
@@ -10695,8 +11127,8 @@ var ProjectScanCommand = class extends Command5 {
10695
11127
  cwd = Option5.String("--cwd", { required: false });
10696
11128
  async execute() {
10697
11129
  if (this.json) setJsonMode(true);
10698
- const baseCwd = this.cwd ? path22.resolve(this.cwd) : process.cwd();
10699
- const target = this.directory ? path22.resolve(baseCwd, this.directory) : baseCwd;
11130
+ const baseCwd = this.cwd ? path24.resolve(this.cwd) : process.cwd();
11131
+ const target = this.directory ? path24.resolve(baseCwd, this.directory) : baseCwd;
10700
11132
  if (!fs13.existsSync(target)) {
10701
11133
  printError(`Directory not found: ${target}`);
10702
11134
  return 1;
@@ -10747,7 +11179,7 @@ var ProjectScanCommand = class extends Command5 {
10747
11179
  `architecture: ${profile.architecture.evidence.join(", ") || "\u2014"}`
10748
11180
  ]);
10749
11181
  }
10750
- const outPath = path22.join(target, "codegen.config.yaml");
11182
+ const outPath = path24.join(target, "codegen.config.yaml");
10751
11183
  const existsNow = fs13.existsSync(outPath);
10752
11184
  if (this.dryRun) {
10753
11185
  console.log("");
@@ -10868,8 +11300,8 @@ var ProjectInspectCommand = class extends Command5 {
10868
11300
  return 2;
10869
11301
  }
10870
11302
  resolveEntitiesDir(ctx) {
10871
- if (this.dir) return path22.resolve(ctx.cwd, this.dir);
10872
- return ctx.entitiesDir ?? path22.resolve(ctx.cwd, "entities");
11303
+ if (this.dir) return path24.resolve(ctx.cwd, this.dir);
11304
+ return ctx.entitiesDir ?? path24.resolve(ctx.cwd, "entities");
10873
11305
  }
10874
11306
  async runAnalysis(ctx, kind) {
10875
11307
  const entitiesDir = this.resolveEntitiesDir(ctx);
@@ -11072,15 +11504,15 @@ var ProjectGraphCommand = class extends Command5 {
11072
11504
  json: this.json,
11073
11505
  skipDetection: true
11074
11506
  });
11075
- const entitiesDir = this.dir ? path22.resolve(ctx.cwd, this.dir) : ctx.entitiesDir ?? path22.resolve(ctx.cwd, "entities");
11507
+ const entitiesDir = this.dir ? path24.resolve(ctx.cwd, this.dir) : ctx.entitiesDir ?? path24.resolve(ctx.cwd, "entities");
11076
11508
  if (!fs13.existsSync(entitiesDir)) {
11077
11509
  printError(`Entity directory not found: ${entitiesDir}`);
11078
11510
  return 1;
11079
11511
  }
11080
11512
  const relCandidates = [
11081
- path22.resolve(path22.dirname(entitiesDir), "relationships"),
11082
- path22.resolve(entitiesDir, "relationships"),
11083
- path22.resolve(ctx.cwd, "relationships")
11513
+ path24.resolve(path24.dirname(entitiesDir), "relationships"),
11514
+ path24.resolve(entitiesDir, "relationships"),
11515
+ path24.resolve(ctx.cwd, "relationships")
11084
11516
  ];
11085
11517
  const relationshipsDir = relCandidates.find((d) => fs13.existsSync(d));
11086
11518
  const result = await analyzeDomain(entitiesDir, relationshipsDir);
@@ -11096,20 +11528,20 @@ var ProjectGraphCommand = class extends Command5 {
11096
11528
  return 0;
11097
11529
  }
11098
11530
  if (this.output) {
11099
- const outPath = path22.resolve(ctx.cwd, this.output);
11531
+ const outPath = path24.resolve(ctx.cwd, this.output);
11100
11532
  fs13.writeFileSync(outPath, JSON.stringify(serialized, null, 2));
11101
11533
  printSuccess(`Graph written to ${outPath}`);
11102
11534
  printInfo(`${result.entities.length} entities, ${result.relationshipDefinitions.length} relationships, ${result.graph.edges.length} edges`);
11103
11535
  return 0;
11104
11536
  }
11105
11537
  const os = await import("os");
11106
- const tmpDir = fs13.mkdtempSync(path22.join(os.default.tmpdir(), "codegen-graph-"));
11107
- const graphPath = path22.join(tmpDir, "graph.json");
11538
+ const tmpDir = fs13.mkdtempSync(path24.join(os.default.tmpdir(), "codegen-graph-"));
11539
+ const graphPath = path24.join(tmpDir, "graph.json");
11108
11540
  fs13.writeFileSync(graphPath, JSON.stringify(serialized, null, 2));
11109
- const viewerDir = path22.resolve(import.meta.dirname, "..", "..", "..", "tools", "schema-graph-viewer");
11110
- const viewerDist = path22.join(viewerDir, "dist", "index.html");
11541
+ const viewerDir = path24.resolve(import.meta.dirname, "..", "..", "..", "tools", "schema-graph-viewer");
11542
+ const viewerDist = path24.join(viewerDir, "dist", "index.html");
11111
11543
  if (fs13.existsSync(viewerDist)) {
11112
- fs13.copyFileSync(graphPath, path22.join(viewerDir, "dist", "graph.json"));
11544
+ fs13.copyFileSync(graphPath, path24.join(viewerDir, "dist", "graph.json"));
11113
11545
  printSuccess("Graph exported");
11114
11546
  printInfo(`${result.entities.length} entities, ${result.relationshipDefinitions.length} relationships, ${result.graph.edges.length} edges`);
11115
11547
  printInfo(`Graph JSON: ${graphPath}`);
@@ -11140,7 +11572,7 @@ var project_default = projectNoun;
11140
11572
 
11141
11573
  // src/cli/commands/dev.ts
11142
11574
  import fs14 from "fs";
11143
- import path23 from "path";
11575
+ import path25 from "path";
11144
11576
  import { execSync as execSync3, spawn, spawnSync } from "child_process";
11145
11577
  import { Command as Command6, Option as Option6 } from "clipanion";
11146
11578
  var DEFAULT_APP_PORT = 3e3;
@@ -11173,14 +11605,14 @@ function getRedisPort(_ctx) {
11173
11605
  return Number(process.env.DEV_REDIS_PORT ?? DEFAULT_REDIS_PORT);
11174
11606
  }
11175
11607
  function composeFilePath(cwd) {
11176
- const devPath = path23.join(cwd, COMPOSE_FILE);
11608
+ const devPath = path25.join(cwd, COMPOSE_FILE);
11177
11609
  if (fs14.existsSync(devPath)) return devPath;
11178
- const rootPath = path23.join(cwd, "docker-compose.yml");
11610
+ const rootPath = path25.join(cwd, "docker-compose.yml");
11179
11611
  if (fs14.existsSync(rootPath)) return rootPath;
11180
11612
  return devPath;
11181
11613
  }
11182
11614
  function pidFilePath(cwd) {
11183
- return path23.join(cwd, PID_FILE);
11615
+ return path25.join(cwd, PID_FILE);
11184
11616
  }
11185
11617
  function readAppPid(cwd) {
11186
11618
  const p = pidFilePath(cwd);
@@ -11249,7 +11681,7 @@ function formatServiceLine(svc) {
11249
11681
  return `${icon} ${svc.name.padEnd(12)} ${theme.muted(`${svc.host}:${svc.port}`)} ${status}${pidStr}`;
11250
11682
  }
11251
11683
  function ensureComposeFile(cwd, pgPort, redisPort) {
11252
- const composePath = path23.join(cwd, COMPOSE_FILE);
11684
+ const composePath = path25.join(cwd, COMPOSE_FILE);
11253
11685
  if (fs14.existsSync(composePath)) return composePath;
11254
11686
  const content = `# Auto-generated by codegen dev
11255
11687
  # Ports offset from defaults to avoid conflicts with other local services.
@@ -11334,7 +11766,7 @@ var DevUpCommand = class extends Command6 {
11334
11766
  if (!pgReady) printWarning("postgres did not become healthy in time");
11335
11767
  if (!redisReady) printWarning("redis did not become healthy in time");
11336
11768
  const drizzleConfig = ["drizzle.config.ts", "drizzle.config.js"].find(
11337
- (f) => fs14.existsSync(path23.join(ctx.cwd, f))
11769
+ (f) => fs14.existsSync(path25.join(ctx.cwd, f))
11338
11770
  );
11339
11771
  if (drizzleConfig) {
11340
11772
  if (!isJsonMode()) printInfo("pushing database schema...");
@@ -11354,7 +11786,7 @@ var DevUpCommand = class extends Command6 {
11354
11786
  if (!isJsonMode()) printInfo("starting NestJS app...");
11355
11787
  const dbUrl = `postgres://postgres:postgres@localhost:${pgPort}/codegen_dev`;
11356
11788
  const redisUrl = `redis://localhost:${redisPort}`;
11357
- const logFile = path23.join(ctx.cwd, ".dev-app.log");
11789
+ const logFile = path25.join(ctx.cwd, ".dev-app.log");
11358
11790
  const logFd = fs14.openSync(logFile, "a");
11359
11791
  const child = spawn("bun", ["src/main.ts"], {
11360
11792
  cwd: ctx.cwd,
@@ -11512,7 +11944,7 @@ var DevLogsCommand = class extends Command6 {
11512
11944
  }
11513
11945
  return 0;
11514
11946
  }
11515
- const logFile = path23.join(ctx.cwd, ".dev-app.log");
11947
+ const logFile = path25.join(ctx.cwd, ".dev-app.log");
11516
11948
  if (!fs14.existsSync(logFile)) {
11517
11949
  printInfo("no app logs found \u2014 is the app running?");
11518
11950
  return 0;
@@ -11556,7 +11988,7 @@ var DevRestartCommand = class extends Command6 {
11556
11988
  spawnSync("sleep", ["1"]);
11557
11989
  const dbUrl = `postgres://postgres:postgres@localhost:${pgPort}/codegen_dev`;
11558
11990
  const redisUrl = `redis://localhost:${redisPort}`;
11559
- const logFile = path23.join(ctx.cwd, ".dev-app.log");
11991
+ const logFile = path25.join(ctx.cwd, ".dev-app.log");
11560
11992
  const logFd = fs14.openSync(logFile, "a");
11561
11993
  const child = spawn("bun", ["src/main.ts"], {
11562
11994
  cwd: ctx.cwd,
@@ -11686,14 +12118,14 @@ var dev_default = devNoun;
11686
12118
 
11687
12119
  // src/cli/commands/relationship.ts
11688
12120
  import fs15 from "fs";
11689
- import path24 from "path";
12121
+ import path26 from "path";
11690
12122
  import { Command as Command7, Option as Option7 } from "clipanion";
11691
12123
  function listRelationshipYamls2(dir) {
11692
12124
  if (!fs15.existsSync(dir)) return [];
11693
12125
  return fs15.readdirSync(dir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml")).filter((f) => {
11694
- const fullPath = path24.join(dir, f);
12126
+ const fullPath = path26.join(dir, f);
11695
12127
  return detectYamlType(fullPath) === "relationship";
11696
- }).map((f) => path24.join(dir, f));
12128
+ }).map((f) => path26.join(dir, f));
11697
12129
  }
11698
12130
  function summarizeRelationshipFile(filePath) {
11699
12131
  const result = loadRelationshipFromYaml(filePath);
@@ -11714,7 +12146,7 @@ function padRight2(s, n) {
11714
12146
  return s.length >= n ? s : s + " ".repeat(n - s.length);
11715
12147
  }
11716
12148
  async function summary5(ctx) {
11717
- const relDir = path24.resolve(ctx.cwd, "relationships");
12149
+ const relDir = path26.resolve(ctx.cwd, "relationships");
11718
12150
  const files = listRelationshipYamls2(relDir);
11719
12151
  if (files.length === 0) {
11720
12152
  return {
@@ -11784,14 +12216,14 @@ var RelationshipNewCommand = class extends Command7 {
11784
12216
  }
11785
12217
  let targets = [];
11786
12218
  if (this.all) {
11787
- const dir = path24.resolve(ctx.cwd, "relationships");
12219
+ const dir = path26.resolve(ctx.cwd, "relationships");
11788
12220
  targets = listRelationshipYamls2(dir);
11789
12221
  if (targets.length === 0) {
11790
12222
  printError(`No relationship YAML files found in ${dir}`);
11791
12223
  return 1;
11792
12224
  }
11793
12225
  } else if (this.yaml) {
11794
- targets = [path24.resolve(ctx.cwd, this.yaml)];
12226
+ targets = [path26.resolve(ctx.cwd, this.yaml)];
11795
12227
  } else {
11796
12228
  printError("Missing YAML path. Pass a file or --all.");
11797
12229
  return 2;
@@ -11808,7 +12240,7 @@ var RelationshipNewCommand = class extends Command7 {
11808
12240
  }
11809
12241
  if (invalid.length > 0) {
11810
12242
  for (const i of invalid) {
11811
- printError(`${path24.basename(i.file)} \u2014 ${i.message}`);
12243
+ printError(`${path26.basename(i.file)} \u2014 ${i.message}`);
11812
12244
  }
11813
12245
  if (!isJsonMode()) return 1;
11814
12246
  }
@@ -11839,7 +12271,7 @@ var RelationshipNewCommand = class extends Command7 {
11839
12271
  }
11840
12272
  const succeeded = [];
11841
12273
  const failed = [
11842
- ...invalid.map((i) => ({ name: path24.basename(i.file), file: i.file, message: i.message }))
12274
+ ...invalid.map((i) => ({ name: path26.basename(i.file), file: i.file, message: i.message }))
11843
12275
  ];
11844
12276
  for (const v of validated) {
11845
12277
  if (!isJsonMode()) {
@@ -11858,8 +12290,8 @@ var RelationshipNewCommand = class extends Command7 {
11858
12290
  if (!isJsonMode()) printError(`${v.name} \u2014 ${res.stderr ?? "failed"}`);
11859
12291
  }
11860
12292
  }
11861
- const entitiesDir = ctx.entitiesDir ?? path24.resolve(ctx.cwd, "entities");
11862
- const relationshipsDir = path24.resolve(ctx.cwd, "relationships");
12293
+ const entitiesDir = ctx.entitiesDir ?? path26.resolve(ctx.cwd, "entities");
12294
+ const relationshipsDir = path26.resolve(ctx.cwd, "relationships");
11863
12295
  const generatedDir = resolveGeneratedDir(ctx);
11864
12296
  const architecture = resolveArchitecture(ctx);
11865
12297
  let barrelResult = null;
@@ -11904,7 +12336,7 @@ var RelationshipNewCommand = class extends Command7 {
11904
12336
  }
11905
12337
  if (barrelResult) {
11906
12338
  printInfo(
11907
- `barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${path24.relative(ctx.cwd, barrelResult.modulesBarrel)}, ${path24.relative(ctx.cwd, barrelResult.schemaBarrel)}`
12339
+ `barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${path26.relative(ctx.cwd, barrelResult.modulesBarrel)}, ${path26.relative(ctx.cwd, barrelResult.schemaBarrel)}`
11908
12340
  );
11909
12341
  }
11910
12342
  }
@@ -11927,7 +12359,7 @@ var RelationshipListCommand = class extends Command7 {
11927
12359
  json: this.json,
11928
12360
  skipDetection: true
11929
12361
  });
11930
- const relDir = path24.resolve(ctx.cwd, "relationships");
12362
+ const relDir = path26.resolve(ctx.cwd, "relationships");
11931
12363
  const files = listRelationshipYamls2(relDir);
11932
12364
  if (files.length === 0) {
11933
12365
  printInfo("No relationship definitions found.");
@@ -11968,7 +12400,7 @@ var relationship_default = relationshipNoun;
11968
12400
 
11969
12401
  // src/cli/commands/events.ts
11970
12402
  import fs16 from "fs";
11971
- import path25 from "path";
12403
+ import path27 from "path";
11972
12404
  import ts2 from "typescript";
11973
12405
  import { Command as Command8, Option as Option8 } from "clipanion";
11974
12406
  function scanSourceFileForConsumers(sourceFile, filePath, eventType) {
@@ -12104,7 +12536,7 @@ function suggestEventTypes(target, known, limit = 3) {
12104
12536
  return known.map((t) => ({ t, d: levenshtein(target, t) })).sort((a, b) => a.d - b.d).slice(0, limit).map((x) => x.t);
12105
12537
  }
12106
12538
  function renderConsumerReport(result, cwd) {
12107
- const rel = (p) => path25.relative(cwd, p) || p;
12539
+ const rel = (p) => path27.relative(cwd, p) || p;
12108
12540
  const lines = [];
12109
12541
  const total = result.tier3.length + result.tier2.length + result.tier1.length;
12110
12542
  lines.push(`Event: ${result.eventType}`);
@@ -12140,7 +12572,7 @@ function renderConsumerReport(result, cwd) {
12140
12572
  return lines;
12141
12573
  }
12142
12574
  function runConsumersScan(opts) {
12143
- const scanRoot = opts.scanRoot ?? path25.join(opts.cwd, "src");
12575
+ const scanRoot = opts.scanRoot ?? path27.join(opts.cwd, "src");
12144
12576
  const handlersDir = opts.handlersDir ?? scanRoot;
12145
12577
  const allTriggers = scanHandlerFiles(handlersDir);
12146
12578
  const tier3 = allTriggers.filter((t) => t.event === opts.eventType).map((t) => ({
@@ -12150,7 +12582,7 @@ function runConsumersScan(opts) {
12150
12582
  sourceLine: t.sourceLine
12151
12583
  }));
12152
12584
  const tier21 = fs16.existsSync(scanRoot) ? scanDirectoryForConsumers(scanRoot, opts.eventType) : { tier2: [], tier1: [], hasEventFlowImport: false };
12153
- const eventsGeneratedDir = opts.eventsGeneratedDir ?? path25.join(
12585
+ const eventsGeneratedDir = opts.eventsGeneratedDir ?? path27.join(
12154
12586
  resolveSubsystemsRootFromContext(opts.cwd, opts.config),
12155
12587
  "events",
12156
12588
  "generated"
@@ -12171,11 +12603,11 @@ function runConsumersScan(opts) {
12171
12603
  function resolveSubsystemsRootFromContext(cwd, config) {
12172
12604
  const configured = config?.paths?.subsystems;
12173
12605
  if (typeof configured === "string" && configured.length > 0) {
12174
- return path25.resolve(cwd, configured);
12606
+ return path27.resolve(cwd, configured);
12175
12607
  }
12176
12608
  const backendSrc = config?.paths?.backend_src;
12177
12609
  const base = typeof backendSrc === "string" && backendSrc.length > 0 ? backendSrc : "src";
12178
- return path25.resolve(cwd, base, "shared", "subsystems");
12610
+ return path27.resolve(cwd, base, "shared", "subsystems");
12179
12611
  }
12180
12612
  var EventsConsumersCommand = class extends Command8 {
12181
12613
  static paths = [["events", "consumers"]];
@@ -12264,7 +12696,7 @@ var eventsNoun = {
12264
12696
  var events_default = eventsNoun;
12265
12697
 
12266
12698
  // src/cli/commands/orchestration.ts
12267
- import path26 from "path";
12699
+ import path28 from "path";
12268
12700
  import { Command as Command9, Option as Option9 } from "clipanion";
12269
12701
  var DEFAULT_PATTERN_GLOBS = ["src/patterns/*.pattern.ts"];
12270
12702
  function resolvePatternGlobs(ctx) {
@@ -12278,10 +12710,10 @@ function resolveOrchestrationOutputRoot(ctx) {
12278
12710
  const paths = ctx.config?.paths;
12279
12711
  const explicit = paths?.orchestration_src;
12280
12712
  if (typeof explicit === "string" && explicit.length > 0) {
12281
- return path26.resolve(ctx.cwd, explicit);
12713
+ return path28.resolve(ctx.cwd, explicit);
12282
12714
  }
12283
12715
  const backendSrc = typeof paths?.backend_src === "string" && paths.backend_src.length > 0 ? paths.backend_src : "app/backend/src";
12284
- return path26.resolve(ctx.cwd, backendSrc, "orchestration");
12716
+ return path28.resolve(ctx.cwd, backendSrc, "orchestration");
12285
12717
  }
12286
12718
  async function reloadRegistry(ctx) {
12287
12719
  _resetRegistryForTests({ includeLibrary: false });
@@ -12370,12 +12802,12 @@ var OrchestrationGenCommand = class extends Command9 {
12370
12802
  );
12371
12803
  for (const f of result.files) {
12372
12804
  console.log(
12373
- ` ${theme.muted(icons.arrow)} ${path26.relative(ctx.cwd, f.outputPath)}`
12805
+ ` ${theme.muted(icons.arrow)} ${path28.relative(ctx.cwd, f.outputPath)}`
12374
12806
  );
12375
12807
  }
12376
12808
  } else {
12377
12809
  printSuccess(
12378
- `Emitted ${result.files.length} file(s) across ${targets.length} pattern(s) \u2192 ${path26.relative(ctx.cwd, outputRoot)}`
12810
+ `Emitted ${result.files.length} file(s) across ${targets.length} pattern(s) \u2192 ${path28.relative(ctx.cwd, outputRoot)}`
12379
12811
  );
12380
12812
  }
12381
12813
  return 0;