@specverse/engines 6.42.3 → 6.60.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.
Files changed (143) hide show
  1. package/dist/ai/analyse-runner.d.ts.map +1 -1
  2. package/dist/ai/analyse-runner.js +53 -1
  3. package/dist/ai/analyse-runner.js.map +1 -1
  4. package/dist/ai/prompt-runner.d.ts +39 -1
  5. package/dist/ai/prompt-runner.d.ts.map +1 -1
  6. package/dist/ai/prompt-runner.js +44 -3
  7. package/dist/ai/prompt-runner.js.map +1 -1
  8. package/dist/ai/providers/claude-cli.d.ts.map +1 -1
  9. package/dist/ai/providers/claude-cli.js +8 -1
  10. package/dist/ai/providers/claude-cli.js.map +1 -1
  11. package/dist/ai/skill-loader.d.ts +50 -0
  12. package/dist/ai/skill-loader.d.ts.map +1 -0
  13. package/dist/ai/skill-loader.js +96 -0
  14. package/dist/ai/skill-loader.js.map +1 -0
  15. package/dist/analyse-prepass/adapters/index.d.ts +2 -0
  16. package/dist/analyse-prepass/adapters/index.d.ts.map +1 -1
  17. package/dist/analyse-prepass/adapters/index.js +2 -0
  18. package/dist/analyse-prepass/adapters/index.js.map +1 -1
  19. package/dist/analyse-prepass/adapters/module-functions.d.ts +95 -0
  20. package/dist/analyse-prepass/adapters/module-functions.d.ts.map +1 -0
  21. package/dist/analyse-prepass/adapters/module-functions.js +358 -0
  22. package/dist/analyse-prepass/adapters/module-functions.js.map +1 -0
  23. package/dist/analyse-prepass/adapters/naming-convention-fks.d.ts +90 -0
  24. package/dist/analyse-prepass/adapters/naming-convention-fks.d.ts.map +1 -0
  25. package/dist/analyse-prepass/adapters/naming-convention-fks.js +181 -0
  26. package/dist/analyse-prepass/adapters/naming-convention-fks.js.map +1 -0
  27. package/dist/analyse-prepass/index.d.ts +8 -0
  28. package/dist/analyse-prepass/index.d.ts.map +1 -1
  29. package/dist/analyse-prepass/index.js +130 -0
  30. package/dist/analyse-prepass/index.js.map +1 -1
  31. package/dist/libs/instance-factories/cli/templates/commander/cli-entry-generator.js +11 -12
  32. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +2 -2
  33. package/dist/libs/instance-factories/controllers/templates/fastify/routes-generator.js +29 -10
  34. package/dist/libs/instance-factories/services/templates/prisma/ai-behaviors-generator.js +10 -9
  35. package/dist/libs/instance-factories/services/templates/prisma/behavior-generator.js +24 -2
  36. package/dist/libs/instance-factories/services/templates/prisma/controller-generator.js +28 -20
  37. package/dist/normalise/index.d.ts +14 -0
  38. package/dist/normalise/index.d.ts.map +1 -0
  39. package/dist/normalise/index.js +14 -0
  40. package/dist/normalise/index.js.map +1 -0
  41. package/dist/normalise/load-overrides.d.ts +43 -0
  42. package/dist/normalise/load-overrides.d.ts.map +1 -0
  43. package/dist/normalise/load-overrides.js +121 -0
  44. package/dist/normalise/load-overrides.js.map +1 -0
  45. package/dist/normalise/normalise-rules.d.ts +181 -0
  46. package/dist/normalise/normalise-rules.d.ts.map +1 -0
  47. package/dist/normalise/normalise-rules.js +79 -0
  48. package/dist/normalise/normalise-rules.js.map +1 -0
  49. package/dist/normalise/rules/cluster-module-functions.d.ts +31 -0
  50. package/dist/normalise/rules/cluster-module-functions.d.ts.map +1 -0
  51. package/dist/normalise/rules/cluster-module-functions.js +238 -0
  52. package/dist/normalise/rules/cluster-module-functions.js.map +1 -0
  53. package/dist/normalise/rules/crud-into-curved.d.ts +117 -0
  54. package/dist/normalise/rules/crud-into-curved.d.ts.map +1 -0
  55. package/dist/normalise/rules/crud-into-curved.js +303 -0
  56. package/dist/normalise/rules/crud-into-curved.js.map +1 -0
  57. package/dist/normalise/rules/drop-trivial-passthrough.d.ts +92 -0
  58. package/dist/normalise/rules/drop-trivial-passthrough.d.ts.map +1 -0
  59. package/dist/normalise/rules/drop-trivial-passthrough.js +217 -0
  60. package/dist/normalise/rules/drop-trivial-passthrough.js.map +1 -0
  61. package/dist/normalise/runner.d.ts +58 -0
  62. package/dist/normalise/runner.d.ts.map +1 -0
  63. package/dist/normalise/runner.js +114 -0
  64. package/dist/normalise/runner.js.map +1 -0
  65. package/dist/parser/import-resolver/resolver.js +1 -1
  66. package/dist/parser/import-resolver/resolver.js.map +1 -1
  67. package/dist/realize/engines/typescript-engine.js +1 -1
  68. package/dist/realize/engines/typescript-engine.js.map +1 -1
  69. package/dist/realize/index.d.ts.map +1 -1
  70. package/dist/realize/index.js +221 -88
  71. package/dist/realize/index.js.map +1 -1
  72. package/dist/realize/library/library.js +1 -1
  73. package/dist/realize/library/library.js.map +1 -1
  74. package/dist/realize/library/resolver.d.ts.map +1 -1
  75. package/dist/realize/library/resolver.js +14 -1
  76. package/dist/realize/library/resolver.js.map +1 -1
  77. package/dist/realize/owner-emit-shared.d.ts +114 -0
  78. package/dist/realize/owner-emit-shared.d.ts.map +1 -0
  79. package/dist/realize/owner-emit-shared.js +227 -0
  80. package/dist/realize/owner-emit-shared.js.map +1 -0
  81. package/dist/realize/per-action-recovery.d.ts +74 -0
  82. package/dist/realize/per-action-recovery.d.ts.map +1 -0
  83. package/dist/realize/per-action-recovery.js +268 -0
  84. package/dist/realize/per-action-recovery.js.map +1 -0
  85. package/dist/realize/per-owner-emit.d.ts +7 -58
  86. package/dist/realize/per-owner-emit.d.ts.map +1 -1
  87. package/dist/realize/per-owner-emit.js +67 -215
  88. package/dist/realize/per-owner-emit.js.map +1 -1
  89. package/dist/realize/per-owner-runner.d.ts +24 -4
  90. package/dist/realize/per-owner-runner.d.ts.map +1 -1
  91. package/dist/realize/per-owner-runner.js +77 -19
  92. package/dist/realize/per-owner-runner.js.map +1 -1
  93. package/dist/realize/post-emit-verify/diagnostics.d.ts +107 -0
  94. package/dist/realize/post-emit-verify/diagnostics.d.ts.map +1 -0
  95. package/dist/realize/post-emit-verify/diagnostics.js +148 -0
  96. package/dist/realize/post-emit-verify/diagnostics.js.map +1 -0
  97. package/dist/realize/post-emit-verify/feedback-runner.d.ts +123 -0
  98. package/dist/realize/post-emit-verify/feedback-runner.d.ts.map +1 -0
  99. package/dist/realize/post-emit-verify/feedback-runner.js +232 -0
  100. package/dist/realize/post-emit-verify/feedback-runner.js.map +1 -0
  101. package/dist/realize/post-emit-verify/index.d.ts +19 -0
  102. package/dist/realize/post-emit-verify/index.d.ts.map +1 -0
  103. package/dist/realize/post-emit-verify/index.js +18 -0
  104. package/dist/realize/post-emit-verify/index.js.map +1 -0
  105. package/dist/realize/post-emit-verify/reemit.d.ts +82 -0
  106. package/dist/realize/post-emit-verify/reemit.d.ts.map +1 -0
  107. package/dist/realize/post-emit-verify/reemit.js +124 -0
  108. package/dist/realize/post-emit-verify/reemit.js.map +1 -0
  109. package/dist/realize/post-emit-verify/types.d.ts +187 -0
  110. package/dist/realize/post-emit-verify/types.d.ts.map +1 -0
  111. package/dist/realize/post-emit-verify/types.js +28 -0
  112. package/dist/realize/post-emit-verify/types.js.map +1 -0
  113. package/dist/realize/post-emit-verify/verifier-manifest.d.ts +29 -0
  114. package/dist/realize/post-emit-verify/verifier-manifest.d.ts.map +1 -0
  115. package/dist/realize/post-emit-verify/verifier-manifest.js +57 -0
  116. package/dist/realize/post-emit-verify/verifier-manifest.js.map +1 -0
  117. package/dist/realize/post-emit-verify/verifiers/stub-completeness.d.ts +85 -0
  118. package/dist/realize/post-emit-verify/verifiers/stub-completeness.d.ts.map +1 -0
  119. package/dist/realize/post-emit-verify/verifiers/stub-completeness.js +298 -0
  120. package/dist/realize/post-emit-verify/verifiers/stub-completeness.js.map +1 -0
  121. package/dist/realize/post-emit-verify/verifiers/tsc.d.ts +24 -0
  122. package/dist/realize/post-emit-verify/verifiers/tsc.d.ts.map +1 -0
  123. package/dist/realize/post-emit-verify/verifiers/tsc.js +148 -0
  124. package/dist/realize/post-emit-verify/verifiers/tsc.js.map +1 -0
  125. package/dist/realize/realize-context-snapshot.d.ts +70 -0
  126. package/dist/realize/realize-context-snapshot.d.ts.map +1 -0
  127. package/dist/realize/realize-context-snapshot.js +96 -0
  128. package/dist/realize/realize-context-snapshot.js.map +1 -0
  129. package/dist/realize/realize-rules.d.ts +113 -0
  130. package/dist/realize/realize-rules.d.ts.map +1 -0
  131. package/dist/realize/realize-rules.js +271 -0
  132. package/dist/realize/realize-rules.js.map +1 -0
  133. package/dist/realize/structural-validator.d.ts +36 -2
  134. package/dist/realize/structural-validator.d.ts.map +1 -1
  135. package/dist/realize/structural-validator.js +50 -7
  136. package/dist/realize/structural-validator.js.map +1 -1
  137. package/libs/instance-factories/cli/templates/commander/cli-entry-generator.ts +11 -12
  138. package/libs/instance-factories/cli/templates/commander/command-generator.ts +2 -2
  139. package/libs/instance-factories/controllers/templates/fastify/routes-generator.ts +49 -15
  140. package/libs/instance-factories/services/templates/prisma/ai-behaviors-generator.ts +19 -3
  141. package/libs/instance-factories/services/templates/prisma/behavior-generator.ts +62 -2
  142. package/libs/instance-factories/services/templates/prisma/controller-generator.ts +47 -20
  143. package/package.json +9 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-loader.js","sourceRoot":"","sources":["../../src/ai/skill-loader.ts"],"names":[],"mappings":"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"}
@@ -7,4 +7,6 @@
7
7
  */
8
8
  export { extractTypeScriptPrisma, type PrismaFacts, type PrismaEntity, type PrismaField, type PrismaRelation, } from './typescript-prisma.js';
9
9
  export { extractTypeScriptDecorators, type DecoratorFacts, type DecoratorEntity, type DecoratorRelationship, } from './typescript-decorators.js';
10
+ export { inferNamingConventionFks, type NamingConventionFkFacts, type NamingConventionFkInferred, type NamingConventionFkOptions, type NamingConventionFkInputEntity, type NamingConventionFkInputRelationship, } from './naming-convention-fks.js';
11
+ export { parseFunctionTerminalId, groupTerminalsByFile, findExportedFunctionBody, synthesizeServiceClass, deriveServiceName, type ModuleFunctionTerminal, } from './module-functions.js';
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/analyse-prepass/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,uBAAuB,EACvB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,2BAA2B,EAC3B,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,qBAAqB,GAC3B,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/analyse-prepass/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,uBAAuB,EACvB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,2BAA2B,EAC3B,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,qBAAqB,GAC3B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,wBAAwB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,6BAA6B,EAClC,KAAK,mCAAmC,GACzC,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,wBAAwB,EACxB,sBAAsB,EACtB,iBAAiB,EACjB,KAAK,sBAAsB,GAC5B,MAAM,uBAAuB,CAAC"}
@@ -7,4 +7,6 @@
7
7
  */
8
8
  export { extractTypeScriptPrisma, } from './typescript-prisma.js';
9
9
  export { extractTypeScriptDecorators, } from './typescript-decorators.js';
10
+ export { inferNamingConventionFks, } from './naming-convention-fks.js';
11
+ export { parseFunctionTerminalId, groupTerminalsByFile, findExportedFunctionBody, synthesizeServiceClass, deriveServiceName, } from './module-functions.js';
10
12
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyse-prepass/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,uBAAuB,GAKxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,2BAA2B,GAI5B,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyse-prepass/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,uBAAuB,GAKxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,2BAA2B,GAI5B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,wBAAwB,GAMzB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,wBAAwB,EACxB,sBAAsB,EACtB,iBAAiB,GAElB,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * `module-functions` adapter — surfaces module-level exported functions
3
+ * as synthetic service classes via the candidate-step pipeline.
4
+ *
5
+ * Why this exists: PowerSync / hand-rolled Drizzle / Supabase-queries
6
+ * style codebases keep their business logic in modules of exported
7
+ * async functions:
8
+ *
9
+ * // db/queries/smc-rounds.ts
10
+ * export async function smcCreateRound(db, params) { ... }
11
+ * export async function smcGetRound(db, id) { ... }
12
+ * export async function smcUpdateRoundStatus(db, id, status) { ... }
13
+ *
14
+ * The class walker only sees classes — module functions are invisible
15
+ * to it. But GitNexus traces cross-method call flows AND captures
16
+ * function terminals as `Process` nodes (`Function:<filePath>:<fnName>`).
17
+ * That signal is already in `facts.processes` at the point the
18
+ * orchestrator finishes structural extraction.
19
+ *
20
+ * This adapter consumes the process terminals, groups them by file,
21
+ * and synthesizes one service class per file — exactly mirroring the
22
+ * `express-routes` pattern. The synthetic class body feeds into the
23
+ * existing `extractCandidateSteps` classifier, so module-function
24
+ * services get pre-classified timelines just like real class methods.
25
+ *
26
+ * Phase 0 of `2026-05-13-NORMALISE-PHASE.md`.
27
+ *
28
+ * Filed in proposal section §3.
29
+ */
30
+ export interface ModuleFunctionTerminal {
31
+ /** Function name (suitable as a yaml key — preserved verbatim from source). */
32
+ methodName: string;
33
+ /** Whether the function is declared async. */
34
+ isAsync: boolean;
35
+ /** Function body between matching braces, no wrapping. */
36
+ body: string;
37
+ /** Source line range of the full declaration (export keyword → closing brace). */
38
+ sourceLineRange: [number, number];
39
+ }
40
+ /**
41
+ * Parse a `Function:<filePath>:<fnName>` terminalId. Returns null if
42
+ * the ID doesn't match (e.g. it's a class method).
43
+ *
44
+ * Examples:
45
+ * "Function:db/queries/smc-rounds.ts:smcCreateRound" → { filePath, functionName }
46
+ * "Method:UserController:create" → null
47
+ */
48
+ export declare function parseFunctionTerminalId(id: string): {
49
+ filePath: string;
50
+ functionName: string;
51
+ } | null;
52
+ /**
53
+ * Walk `facts.processes`-shaped input for function terminals. Returns a
54
+ * map: filePath → Set<functionName>. Skips:
55
+ * - Non-Function: terminals (class methods, etc.)
56
+ * - Files outside common source extensions
57
+ * - Files in node_modules / dist / build output
58
+ */
59
+ export declare function groupTerminalsByFile(processes: Array<{
60
+ terminalId: string;
61
+ }>): Map<string, Set<string>>;
62
+ /**
63
+ * Find an exported top-level function in source. Handles four common
64
+ * declaration shapes:
65
+ *
66
+ * export async function <name>(...) { ... }
67
+ * export function <name>(...) { ... }
68
+ * export const <name> = async (...) => { ... }
69
+ * export const <name> = (...) => { ... }
70
+ *
71
+ * Returns null if not found or if the declaration's body can't be
72
+ * isolated (single-expression arrow `=> expr` without a brace block).
73
+ */
74
+ export declare function findExportedFunctionBody(source: string, fnName: string): ModuleFunctionTerminal | null;
75
+ /**
76
+ * Wrap a list of module functions in a synthetic class body. The output
77
+ * is suitable for `walkMethodBodies` / `extractCandidateSteps` to
78
+ * consume. Each function becomes a `<methodName>(...) { <body> }` member.
79
+ *
80
+ * Mirrors `synthesizeControllerClass` in `express-routes.ts`.
81
+ */
82
+ export declare function synthesizeServiceClass(serviceName: string, functions: ModuleFunctionTerminal[]): string;
83
+ /**
84
+ * Derive a service class name from a file path.
85
+ *
86
+ * "db/queries/smc-rounds.ts" → "SmcRoundsService"
87
+ * "lib/round-guards.ts" → "RoundGuardsService"
88
+ * "providers/AuthProvider.tsx" → "AuthProviderService"
89
+ *
90
+ * The file basename (no extension) is split on `-`, `_`, `.`, `/` and
91
+ * each segment is PascalCased. `Service` suffix is appended unless the
92
+ * derived name already ends in `Service` / `Controller`.
93
+ */
94
+ export declare function deriveServiceName(filePath: string): string;
95
+ //# sourceMappingURL=module-functions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-functions.d.ts","sourceRoot":"","sources":["../../../src/analyse-prepass/adapters/module-functions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,MAAM,WAAW,sBAAsB;IACrC,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,MAAM,GACT;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAanD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,GACvC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAqB1B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,sBAAsB,GAAG,IAAI,CA4C/B;AAqED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,sBAAsB,EAAE,GAClC,MAAM,CAYR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAU1D"}
@@ -0,0 +1,358 @@
1
+ /**
2
+ * `module-functions` adapter — surfaces module-level exported functions
3
+ * as synthetic service classes via the candidate-step pipeline.
4
+ *
5
+ * Why this exists: PowerSync / hand-rolled Drizzle / Supabase-queries
6
+ * style codebases keep their business logic in modules of exported
7
+ * async functions:
8
+ *
9
+ * // db/queries/smc-rounds.ts
10
+ * export async function smcCreateRound(db, params) { ... }
11
+ * export async function smcGetRound(db, id) { ... }
12
+ * export async function smcUpdateRoundStatus(db, id, status) { ... }
13
+ *
14
+ * The class walker only sees classes — module functions are invisible
15
+ * to it. But GitNexus traces cross-method call flows AND captures
16
+ * function terminals as `Process` nodes (`Function:<filePath>:<fnName>`).
17
+ * That signal is already in `facts.processes` at the point the
18
+ * orchestrator finishes structural extraction.
19
+ *
20
+ * This adapter consumes the process terminals, groups them by file,
21
+ * and synthesizes one service class per file — exactly mirroring the
22
+ * `express-routes` pattern. The synthetic class body feeds into the
23
+ * existing `extractCandidateSteps` classifier, so module-function
24
+ * services get pre-classified timelines just like real class methods.
25
+ *
26
+ * Phase 0 of `2026-05-13-NORMALISE-PHASE.md`.
27
+ *
28
+ * Filed in proposal section §3.
29
+ */
30
+ /**
31
+ * Parse a `Function:<filePath>:<fnName>` terminalId. Returns null if
32
+ * the ID doesn't match (e.g. it's a class method).
33
+ *
34
+ * Examples:
35
+ * "Function:db/queries/smc-rounds.ts:smcCreateRound" → { filePath, functionName }
36
+ * "Method:UserController:create" → null
37
+ */
38
+ export function parseFunctionTerminalId(id) {
39
+ // Format: Function:<filePath>:<functionName>. The filePath may contain
40
+ // colons (drive letters on Windows, ports in URLs — rare in practice
41
+ // but defensive). The functionName is always the LAST `:`-separated
42
+ // segment. Anchor on `Function:` prefix.
43
+ if (!id.startsWith('Function:'))
44
+ return null;
45
+ const rest = id.slice('Function:'.length);
46
+ const lastColon = rest.lastIndexOf(':');
47
+ if (lastColon < 0)
48
+ return null;
49
+ const filePath = rest.slice(0, lastColon);
50
+ const functionName = rest.slice(lastColon + 1);
51
+ if (!filePath || !functionName)
52
+ return null;
53
+ return { filePath, functionName };
54
+ }
55
+ /**
56
+ * Walk `facts.processes`-shaped input for function terminals. Returns a
57
+ * map: filePath → Set<functionName>. Skips:
58
+ * - Non-Function: terminals (class methods, etc.)
59
+ * - Files outside common source extensions
60
+ * - Files in node_modules / dist / build output
61
+ */
62
+ export function groupTerminalsByFile(processes) {
63
+ const out = new Map();
64
+ for (const p of processes) {
65
+ const parsed = parseFunctionTerminalId(p.terminalId);
66
+ if (!parsed)
67
+ continue;
68
+ // Skip files that look like generated / vendored output.
69
+ if (/node_modules|\.d\.ts$|dist\/|build\//.test(parsed.filePath))
70
+ continue;
71
+ // Stick to backend source extensions. `.tsx`/`.jsx` are React/JSX
72
+ // files — those are frontend components + hooks, NOT backend
73
+ // service modules. The react-views adapter handles them; this
74
+ // adapter must not double-claim them as services.
75
+ if (!/\.(ts|js|mjs|cjs)$/.test(parsed.filePath))
76
+ continue;
77
+ if (/\.d\.ts$/.test(parsed.filePath))
78
+ continue;
79
+ let set = out.get(parsed.filePath);
80
+ if (!set) {
81
+ set = new Set();
82
+ out.set(parsed.filePath, set);
83
+ }
84
+ set.add(parsed.functionName);
85
+ }
86
+ return out;
87
+ }
88
+ /**
89
+ * Find an exported top-level function in source. Handles four common
90
+ * declaration shapes:
91
+ *
92
+ * export async function <name>(...) { ... }
93
+ * export function <name>(...) { ... }
94
+ * export const <name> = async (...) => { ... }
95
+ * export const <name> = (...) => { ... }
96
+ *
97
+ * Returns null if not found or if the declaration's body can't be
98
+ * isolated (single-expression arrow `=> expr` without a brace block).
99
+ */
100
+ export function findExportedFunctionBody(source, fnName) {
101
+ // Shape A: `export (async )? function <fnName>(...) { ... }`
102
+ // The space-or-newline between `function` and the name allows for
103
+ // multiline declarations with intervening whitespace.
104
+ const funcRe = new RegExp(`\\bexport\\s+(async\\s+)?function\\s+${escapeRegex(fnName)}\\s*\\(`, 'm');
105
+ const funcMatch = funcRe.exec(source);
106
+ if (funcMatch) {
107
+ const openParenIdx = funcMatch.index + funcMatch[0].length - 1;
108
+ const closeParenIdx = findMatchingParen(source, openParenIdx);
109
+ if (closeParenIdx < 0)
110
+ return null;
111
+ // Body opening brace = first `{` after `)` at angle-bracket depth 0
112
+ // (skips `{` inside a return type generic like `Promise<{ ... }>`).
113
+ const braceIdx = findBodyBrace(source, closeParenIdx + 1);
114
+ if (braceIdx < 0)
115
+ return null;
116
+ return extractBody(source, funcMatch.index, braceIdx, !!funcMatch[1]);
117
+ }
118
+ // Shape B: `export const <fnName> = (async )? (...) [: Type]? => { ... }`
119
+ const constRe = new RegExp(`\\bexport\\s+const\\s+${escapeRegex(fnName)}\\s*=\\s*(async\\s+)?\\(`, 'm');
120
+ const constMatch = constRe.exec(source);
121
+ if (constMatch) {
122
+ const openParenIdx = constMatch.index + constMatch[0].length - 1;
123
+ const closeParenIdx = findMatchingParen(source, openParenIdx);
124
+ if (closeParenIdx < 0)
125
+ return null;
126
+ // After the `)`, expect optionally `: <ReturnType>` then `=>` then `{`.
127
+ // The return type can contain `>`, `<`, `,`, generics, etc., so we
128
+ // can't use a simple regex. Walk forward through angle-bracket-aware
129
+ // chars until we hit `=>`.
130
+ const arrowIdx = findArrowAfterParen(source, closeParenIdx + 1);
131
+ if (arrowIdx < 0)
132
+ return null;
133
+ // After `=>`, skip whitespace, expect `{`.
134
+ let i = arrowIdx + 2;
135
+ while (i < source.length && /\s/.test(source[i]))
136
+ i++;
137
+ if (source[i] !== '{')
138
+ return null;
139
+ return extractBody(source, constMatch.index, i, !!constMatch[1]);
140
+ }
141
+ return null;
142
+ }
143
+ /**
144
+ * Find the first `{` after `fromIdx` that's at angle-bracket depth 0.
145
+ * This skips over generic-parameter braces like `Promise<{rows: Row[]}>`
146
+ * which would otherwise be mistakenly identified as the function body.
147
+ */
148
+ function findBodyBrace(source, fromIdx) {
149
+ let angleDepth = 0;
150
+ let strChar = null;
151
+ for (let i = fromIdx; i < source.length; i++) {
152
+ const c = source[i];
153
+ if (strChar) {
154
+ if (c === '\\') {
155
+ i++;
156
+ continue;
157
+ }
158
+ if (c === strChar)
159
+ strChar = null;
160
+ continue;
161
+ }
162
+ if (c === '"' || c === "'" || c === '`') {
163
+ strChar = c;
164
+ continue;
165
+ }
166
+ if (c === '<')
167
+ angleDepth++;
168
+ else if (c === '>')
169
+ angleDepth = Math.max(0, angleDepth - 1);
170
+ else if (c === '{' && angleDepth === 0)
171
+ return i;
172
+ }
173
+ return -1;
174
+ }
175
+ /**
176
+ * Find the `=>` after `fromIdx` at angle-bracket depth 0. Lets us walk
177
+ * past a `: Type<...>` return-type annotation on a const arrow form.
178
+ */
179
+ function findArrowAfterParen(source, fromIdx) {
180
+ let angleDepth = 0;
181
+ let strChar = null;
182
+ for (let i = fromIdx; i < source.length - 1; i++) {
183
+ const c = source[i];
184
+ const next = source[i + 1];
185
+ if (strChar) {
186
+ if (c === '\\') {
187
+ i++;
188
+ continue;
189
+ }
190
+ if (c === strChar)
191
+ strChar = null;
192
+ continue;
193
+ }
194
+ if (c === '"' || c === "'" || c === '`') {
195
+ strChar = c;
196
+ continue;
197
+ }
198
+ if (c === '<')
199
+ angleDepth++;
200
+ else if (c === '>')
201
+ angleDepth = Math.max(0, angleDepth - 1);
202
+ else if (c === '=' && next === '>' && angleDepth === 0)
203
+ return i;
204
+ // Bail if we hit `{` or `;` at depth 0 without seeing `=>` — not an arrow form.
205
+ else if ((c === '{' || c === ';') && angleDepth === 0)
206
+ return -1;
207
+ }
208
+ return -1;
209
+ }
210
+ function extractBody(source, declStartIdx, openBraceIdx, isAsync) {
211
+ const closeBraceIdx = findMatchingBrace(source, openBraceIdx);
212
+ if (closeBraceIdx < 0)
213
+ return null;
214
+ const body = source.slice(openBraceIdx + 1, closeBraceIdx);
215
+ const startLine = source.slice(0, declStartIdx).split('\n').length;
216
+ const endLine = source.slice(0, closeBraceIdx + 1).split('\n').length;
217
+ return {
218
+ methodName: '', // filled by caller; we don't have the name here
219
+ isAsync,
220
+ body,
221
+ sourceLineRange: [startLine, endLine],
222
+ };
223
+ }
224
+ /**
225
+ * Wrap a list of module functions in a synthetic class body. The output
226
+ * is suitable for `walkMethodBodies` / `extractCandidateSteps` to
227
+ * consume. Each function becomes a `<methodName>(...) { <body> }` member.
228
+ *
229
+ * Mirrors `synthesizeControllerClass` in `express-routes.ts`.
230
+ */
231
+ export function synthesizeServiceClass(serviceName, functions) {
232
+ const lines = [];
233
+ lines.push(`class ${serviceName} {`);
234
+ for (const f of functions) {
235
+ const asyncWord = f.isAsync ? 'async ' : '';
236
+ lines.push(` ${asyncWord}${f.methodName}() {`);
237
+ const bodyLines = f.body.split('\n').map((l) => ' ' + l);
238
+ lines.push(...bodyLines);
239
+ lines.push(' }');
240
+ }
241
+ lines.push('}');
242
+ return lines.join('\n');
243
+ }
244
+ /**
245
+ * Derive a service class name from a file path.
246
+ *
247
+ * "db/queries/smc-rounds.ts" → "SmcRoundsService"
248
+ * "lib/round-guards.ts" → "RoundGuardsService"
249
+ * "providers/AuthProvider.tsx" → "AuthProviderService"
250
+ *
251
+ * The file basename (no extension) is split on `-`, `_`, `.`, `/` and
252
+ * each segment is PascalCased. `Service` suffix is appended unless the
253
+ * derived name already ends in `Service` / `Controller`.
254
+ */
255
+ export function deriveServiceName(filePath) {
256
+ const basename = filePath.split('/').pop() ?? filePath;
257
+ const noExt = basename.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, '');
258
+ const pascal = noExt
259
+ .split(/[-_./]+/)
260
+ .filter((p) => p.length > 0)
261
+ .map((p) => p.charAt(0).toUpperCase() + p.slice(1))
262
+ .join('');
263
+ if (/Service$/.test(pascal) || /Controller$/.test(pascal))
264
+ return pascal;
265
+ return `${pascal}Service`;
266
+ }
267
+ // ── Brace / paren matching helpers ───────────────────────────────────
268
+ // Inlined (not imported from express-routes) to keep this adapter
269
+ // self-contained. Same logic, same edge cases.
270
+ function findMatchingParen(source, openIdx) {
271
+ if (source[openIdx] !== '(')
272
+ return -1;
273
+ let depth = 0;
274
+ let strChar = null;
275
+ for (let i = openIdx; i < source.length; i++) {
276
+ const c = source[i];
277
+ if (strChar) {
278
+ if (c === '\\') {
279
+ i++;
280
+ continue;
281
+ }
282
+ if (c === strChar)
283
+ strChar = null;
284
+ continue;
285
+ }
286
+ if (c === '"' || c === "'" || c === '`') {
287
+ strChar = c;
288
+ continue;
289
+ }
290
+ if (c === '(')
291
+ depth++;
292
+ else if (c === ')') {
293
+ depth--;
294
+ if (depth === 0)
295
+ return i;
296
+ }
297
+ }
298
+ return -1;
299
+ }
300
+ function findMatchingBrace(source, openIdx) {
301
+ if (source[openIdx] !== '{')
302
+ return -1;
303
+ let depth = 0;
304
+ let strChar = null;
305
+ let inLineComment = false;
306
+ let inBlockComment = false;
307
+ for (let i = openIdx; i < source.length; i++) {
308
+ const c = source[i];
309
+ const next = source[i + 1];
310
+ if (inLineComment) {
311
+ if (c === '\n')
312
+ inLineComment = false;
313
+ continue;
314
+ }
315
+ if (inBlockComment) {
316
+ if (c === '*' && next === '/') {
317
+ inBlockComment = false;
318
+ i++;
319
+ }
320
+ continue;
321
+ }
322
+ if (strChar) {
323
+ if (c === '\\') {
324
+ i++;
325
+ continue;
326
+ }
327
+ if (c === strChar)
328
+ strChar = null;
329
+ continue;
330
+ }
331
+ if (c === '/' && next === '/') {
332
+ inLineComment = true;
333
+ i++;
334
+ continue;
335
+ }
336
+ if (c === '/' && next === '*') {
337
+ inBlockComment = true;
338
+ i++;
339
+ continue;
340
+ }
341
+ if (c === '"' || c === "'" || c === '`') {
342
+ strChar = c;
343
+ continue;
344
+ }
345
+ if (c === '{')
346
+ depth++;
347
+ else if (c === '}') {
348
+ depth--;
349
+ if (depth === 0)
350
+ return i;
351
+ }
352
+ }
353
+ return -1;
354
+ }
355
+ function escapeRegex(s) {
356
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
357
+ }
358
+ //# sourceMappingURL=module-functions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-functions.js","sourceRoot":"","sources":["../../../src/analyse-prepass/adapters/module-functions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * `naming-convention-fks` adapter — convention-FK relationship inference.
3
+ *
4
+ * Some codebases carry no explicit FK metadata: PowerSync (`column.text`
5
+ * without `.references()`), hand-rolled Drizzle without relations, plain
6
+ * SQL migrations without REFERENCES clauses. The relationship lives in the
7
+ * column NAME (`club_id`, `userId`) by convention only. None of the
8
+ * structural adapters (typescript-prisma / typescript-decorators /
9
+ * typescript-interfaces / express-routes / react-views) catches this
10
+ * pattern — typescript-interfaces sees `club_id: string` as a plain string
11
+ * field, not a relationship.
12
+ *
13
+ * This adapter is a POST-EXTRACTION inference pass. It runs after all
14
+ * structural adapters have populated `facts.entities[].attributes[]` and
15
+ * walks those attributes for the `*_id` / `*Id` pattern, resolving the
16
+ * prefix against the entity name set (singular OR plural form). When a
17
+ * match resolves cleanly to a known entity, it emits a belongsTo
18
+ * relationship from the owning entity to the target plus a reverse hasMany.
19
+ *
20
+ * Surfaced as a gap by the scoremyclays full-pipeline run 2026-05-12: 10
21
+ * entities extracted, 0 relationships, because Supabase + PowerSync uses
22
+ * convention FKs throughout (`club_id: column.text`).
23
+ *
24
+ * Cut 1 patterns:
25
+ * - `<entity>_id` (snake_case) or `<entity>Id` (camelCase), where the
26
+ * prefix maps to a known entity name (case-insensitive, singular OR
27
+ * plural via a small english heuristic).
28
+ *
29
+ * Out of scope (deferred to follow-up):
30
+ * - `created_by` / `assigned_to` / `owner_id` — target entity not named
31
+ * in the column (needs a curated semantic map OR LLM inference).
32
+ * - Composite FKs — same shape produces independent belongsTos; downstream
33
+ * can combine if it cares.
34
+ *
35
+ * Cardinality: forward `belongsTo` for every matched `*_id`. The reverse
36
+ * `hasMany` is emitted ONLY when this adapter discovered the forward edge
37
+ * itself — i.e. when a prior adapter hadn't already declared that
38
+ * belongsTo. Rationale: rich-metadata codebases (TypeORM with explicit
39
+ * @ManyToOne) decline to declare the inverse @OneToMany when they don't
40
+ * navigate that way, and we shouldn't second-guess that omission. For
41
+ * convention-only codebases (PowerSync) where no prior adapter saw the
42
+ * relationship, BOTH directions are emitted so downstream gets a complete
43
+ * cardinality view.
44
+ *
45
+ * Self-references (`parent_id` on Category → Category) emit only the
46
+ * belongsTo regardless — `Category hasMany Category` is legal but rarely
47
+ * the intended shape.
48
+ *
49
+ * Dedup: skip a candidate when the same `from|to|type` already exists in
50
+ * the input relationships list (a higher-fidelity adapter wins).
51
+ */
52
+ export interface NamingConventionFkInputEntity {
53
+ name: string;
54
+ attributes?: Array<{
55
+ name: string;
56
+ isPrimary?: boolean;
57
+ }>;
58
+ }
59
+ export interface NamingConventionFkInputRelationship {
60
+ from: string;
61
+ to: string;
62
+ type: 'belongsTo' | 'hasMany' | 'hasOne' | 'manyToMany';
63
+ }
64
+ export interface NamingConventionFkInferred {
65
+ from: string;
66
+ to: string;
67
+ type: 'belongsTo' | 'hasMany';
68
+ /** Source attribute that triggered the inference. Kept for downstream
69
+ * attribution + tests; the orchestrator drops this before merging into
70
+ * facts.relationships (which has no `fieldName` field on its canonical
71
+ * shape). */
72
+ fieldName: string;
73
+ }
74
+ export interface NamingConventionFkFacts {
75
+ relationships: NamingConventionFkInferred[];
76
+ /** How many attributes matched the `*_id` / `*Id` pattern. */
77
+ matchedAttributes: number;
78
+ /** Matches that were skipped because the attribute is the entity's PK. */
79
+ ignoredPrimaryKeys: number;
80
+ /** Matches that resolved to no entity name. */
81
+ unresolvedTargets: number;
82
+ }
83
+ export interface NamingConventionFkOptions {
84
+ /** Override pluralization. Default: simple english heuristic. */
85
+ pluralize?: (singular: string) => string;
86
+ /** Override singularization. Default: simple english heuristic. */
87
+ singularize?: (plural: string) => string;
88
+ }
89
+ export declare function inferNamingConventionFks(entities: NamingConventionFkInputEntity[], existingRelationships: NamingConventionFkInputRelationship[], options?: NamingConventionFkOptions): NamingConventionFkFacts;
90
+ //# sourceMappingURL=naming-convention-fks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naming-convention-fks.d.ts","sourceRoot":"","sources":["../../../src/analyse-prepass/adapters/naming-convention-fks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,mCAAmC;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,YAAY,CAAC;CACzD;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;IAC9B;;;kBAGc;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,0BAA0B,EAAE,CAAC;IAC5C,8DAA8D;IAC9D,iBAAiB,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,kBAAkB,EAAE,MAAM,CAAC;IAC3B,+CAA+C;IAC/C,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,yBAAyB;IACxC,iEAAiE;IACjE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,mEAAmE;IACnE,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;CAC1C;AAID,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,6BAA6B,EAAE,EACzC,qBAAqB,EAAE,mCAAmC,EAAE,EAC5D,OAAO,GAAE,yBAA8B,GACtC,uBAAuB,CA6EzB"}