@specverse/engines 6.21.4 → 6.27.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/analyse-runner.d.ts +16 -0
- package/dist/ai/analyse-runner.d.ts.map +1 -1
- package/dist/ai/analyse-runner.js +417 -53
- package/dist/ai/analyse-runner.js.map +1 -1
- package/dist/ai/microcall-orchestrator.d.ts +207 -0
- package/dist/ai/microcall-orchestrator.d.ts.map +1 -0
- package/dist/ai/microcall-orchestrator.js +753 -0
- package/dist/ai/microcall-orchestrator.js.map +1 -0
- package/dist/ai/skeleton-emitter.d.ts +94 -0
- package/dist/ai/skeleton-emitter.d.ts.map +1 -0
- package/dist/ai/skeleton-emitter.js +752 -0
- package/dist/ai/skeleton-emitter.js.map +1 -0
- package/dist/analyse-prepass/adapters/express-routes.d.ts +71 -0
- package/dist/analyse-prepass/adapters/express-routes.d.ts.map +1 -0
- package/dist/analyse-prepass/adapters/express-routes.js +329 -0
- package/dist/analyse-prepass/adapters/express-routes.js.map +1 -0
- package/dist/analyse-prepass/adapters/typescript-interfaces.d.ts +91 -0
- package/dist/analyse-prepass/adapters/typescript-interfaces.d.ts.map +1 -0
- package/dist/analyse-prepass/adapters/typescript-interfaces.js +411 -0
- package/dist/analyse-prepass/adapters/typescript-interfaces.js.map +1 -0
- package/dist/analyse-prepass/backends/gitnexus.d.ts.map +1 -1
- package/dist/analyse-prepass/backends/gitnexus.js +36 -8
- package/dist/analyse-prepass/backends/gitnexus.js.map +1 -1
- package/dist/analyse-prepass/backends/index.d.ts.map +1 -1
- package/dist/analyse-prepass/backends/index.js +3 -5
- package/dist/analyse-prepass/backends/index.js.map +1 -1
- package/dist/analyse-prepass/behavior-step-classifier.d.ts +3 -0
- package/dist/analyse-prepass/behavior-step-classifier.d.ts.map +1 -1
- package/dist/analyse-prepass/behavior-step-classifier.js +1 -0
- package/dist/analyse-prepass/behavior-step-classifier.js.map +1 -1
- package/dist/analyse-prepass/index.d.ts +69 -0
- package/dist/analyse-prepass/index.d.ts.map +1 -1
- package/dist/analyse-prepass/index.js +319 -37
- package/dist/analyse-prepass/index.js.map +1 -1
- package/dist/analyse-prepass/method-body-walker.d.ts +4 -0
- package/dist/analyse-prepass/method-body-walker.d.ts.map +1 -1
- package/dist/analyse-prepass/method-body-walker.js +14 -0
- package/dist/analyse-prepass/method-body-walker.js.map +1 -1
- package/dist/audit/realize-recorder.d.ts +164 -0
- package/dist/audit/realize-recorder.d.ts.map +1 -0
- package/dist/audit/realize-recorder.js +153 -0
- package/dist/audit/realize-recorder.js.map +1 -0
- package/dist/audit/verify-checks.d.ts +32 -0
- package/dist/audit/verify-checks.d.ts.map +1 -0
- package/dist/audit/verify-checks.js +202 -0
- package/dist/audit/verify-checks.js.map +1 -0
- package/dist/audit/verify-recorder.d.ts +84 -0
- package/dist/audit/verify-recorder.d.ts.map +1 -0
- package/dist/audit/verify-recorder.js +90 -0
- package/dist/audit/verify-recorder.js.map +1 -0
- package/dist/inference/core/specly-converter.d.ts.map +1 -1
- package/dist/inference/core/specly-converter.js +67 -36
- package/dist/inference/core/specly-converter.js.map +1 -1
- package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +1 -0
- package/dist/libs/instance-factories/services/templates/_shared/step-matching.js +39 -15
- package/dist/realize/index.d.ts.map +1 -1
- package/dist/realize/index.js +63 -0
- package/dist/realize/index.js.map +1 -1
- package/libs/instance-factories/cli/templates/commander/command-generator.ts +1 -0
- package/libs/instance-factories/services/templates/_shared/step-matching.ts +61 -16
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"behavior-step-classifier.js","sourceRoot":"","sources":["../../src/analyse-prepass/behavior-step-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,gBAAgB,EAAwB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"behavior-step-classifier.js","sourceRoot":"","sources":["../../src/analyse-prepass/behavior-step-classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -135,6 +135,45 @@ export interface SpecVerseFacts {
|
|
|
135
135
|
/** Per-method classified timelines. */
|
|
136
136
|
methods: import('./behavior-step-classifier.js').MethodCandidates[];
|
|
137
137
|
}>;
|
|
138
|
+
/**
|
|
139
|
+
* Audit-trail decision log — one entry per walker class, including
|
|
140
|
+
* methods that were filtered out + their drop reason. Populated when
|
|
141
|
+
* `recordAuditDecisions !== false` in options. Foundation for the
|
|
142
|
+
* `extract-decisions.json` sidecar (see
|
|
143
|
+
* specverse-self/docs/plans/2026-05-03-PIPELINE-AUDIT-TRAIL-INSTRUMENTATION.md).
|
|
144
|
+
*/
|
|
145
|
+
auditDecisions?: ExtractAuditDecisions;
|
|
146
|
+
}
|
|
147
|
+
export interface ExtractAuditDecisions {
|
|
148
|
+
schemaVersion: '1.0';
|
|
149
|
+
classes: Array<{
|
|
150
|
+
className: string;
|
|
151
|
+
filePath: string;
|
|
152
|
+
decision: {
|
|
153
|
+
walked: boolean;
|
|
154
|
+
reason: string;
|
|
155
|
+
};
|
|
156
|
+
methodCount: {
|
|
157
|
+
raw: number;
|
|
158
|
+
kept: number;
|
|
159
|
+
};
|
|
160
|
+
methods: Array<{
|
|
161
|
+
methodName: string;
|
|
162
|
+
isAsync: boolean;
|
|
163
|
+
sourceLineRange: [number, number];
|
|
164
|
+
candidateKindHistogram: Record<string, number>;
|
|
165
|
+
filter: MethodFilterDecision;
|
|
166
|
+
}>;
|
|
167
|
+
}>;
|
|
168
|
+
/** Aggregate counters across all classes. */
|
|
169
|
+
stats: {
|
|
170
|
+
classesWalked: number;
|
|
171
|
+
methodsRaw: number;
|
|
172
|
+
methodsKept: number;
|
|
173
|
+
methodsByDropReason: Record<string, number>;
|
|
174
|
+
candidateStepLines: number;
|
|
175
|
+
candidateStepKindHistogram: Record<string, number>;
|
|
176
|
+
};
|
|
138
177
|
}
|
|
139
178
|
export interface RunPrepassOptions {
|
|
140
179
|
/** Backend to use; defaults to 'auto' (CodeGraph if available, else grep-only). */
|
|
@@ -164,6 +203,27 @@ export interface RunPrepassOptions {
|
|
|
164
203
|
* (e.g. structure-only analysis, or to save time on huge codebases).
|
|
165
204
|
*/
|
|
166
205
|
extractCandidateSteps?: boolean;
|
|
206
|
+
/**
|
|
207
|
+
* When true (default), populates `facts.auditDecisions` with per-class
|
|
208
|
+
* walked/skipped + per-method drop-reason data for downstream
|
|
209
|
+
* `extract-decisions.json` emission. Add a small overhead during
|
|
210
|
+
* extraction (proportional to walker output size). See
|
|
211
|
+
* specverse-self/docs/plans/2026-05-03-PIPELINE-AUDIT-TRAIL-INSTRUMENTATION.md.
|
|
212
|
+
*/
|
|
213
|
+
recordAuditDecisions?: boolean;
|
|
214
|
+
/**
|
|
215
|
+
* When true (default), runs the typescript-interfaces walker (Phase C).
|
|
216
|
+
* Extracts entities from raw TS class/interface/type declarations for
|
|
217
|
+
* adapter-free codebases. Adapter-detected entities take precedence;
|
|
218
|
+
* TS walker fills the gap.
|
|
219
|
+
*/
|
|
220
|
+
extractInterfaces?: boolean;
|
|
221
|
+
/**
|
|
222
|
+
* Entity-shape heuristic for the typescript-interfaces walker.
|
|
223
|
+
* 'liberal' (default): a declared type with `id` field is an entity.
|
|
224
|
+
* 'conservative': also requires `createdAt`/`updatedAt` field.
|
|
225
|
+
*/
|
|
226
|
+
entityShapeHeuristic?: 'liberal' | 'conservative';
|
|
167
227
|
}
|
|
168
228
|
/**
|
|
169
229
|
* Run the structural pre-pass on a source directory.
|
|
@@ -176,6 +236,15 @@ export interface RunPrepassOptions {
|
|
|
176
236
|
* 5. Merge facts into a single SpecVerse-vocabulary `SpecVerseFacts` object
|
|
177
237
|
*/
|
|
178
238
|
export declare function runPrepass(sourceDir: string, options?: RunPrepassOptions): Promise<SpecVerseFacts>;
|
|
239
|
+
/**
|
|
240
|
+
* Drop reasons. Aligns with the audit-trail decision log
|
|
241
|
+
* (`extract-decisions.json` per the 2026-05-03 instrumentation plan).
|
|
242
|
+
*/
|
|
243
|
+
export type MethodFilterReason = 'no-candidates-classified' | 'level-0-accessor' | 'level-1-curved-retrieve' | 'level-1-curved-create-update-delete' | 'container-op-or-self-delegation-only' | 'kept-business-action-strong-signal' | 'kept-multi-step-composition' | 'kept-multiple-external-calls';
|
|
244
|
+
export interface MethodFilterDecision {
|
|
245
|
+
kept: boolean;
|
|
246
|
+
reason: MethodFilterReason;
|
|
247
|
+
}
|
|
179
248
|
/**
|
|
180
249
|
* Format a `SpecVerseFacts` object as a markdown block suitable for
|
|
181
250
|
* injection into the analyse prompt's user template (mirrors the format
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyse-prepass/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyse-prepass/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,9 +23,29 @@ export { extractCandidateSteps, } from './behavior-step-classifier.js';
|
|
|
23
23
|
*/
|
|
24
24
|
export async function runPrepass(sourceDir, options = {}) {
|
|
25
25
|
const start = Date.now();
|
|
26
|
-
|
|
26
|
+
let prepass = options.prepass ?? selectBackend(options.backend ?? 'auto');
|
|
27
27
|
await prepass.init(sourceDir);
|
|
28
28
|
await prepass.index();
|
|
29
|
+
// Auto-fallback: when 'auto' was used and the chosen backend (typically
|
|
30
|
+
// GitNexus) finds zero classes after indexing, swap to grep-only.
|
|
31
|
+
// GitNexus needs git working-tree state; small fixtures rsynced into
|
|
32
|
+
// run dirs without .git history produce empty results — but grep-only
|
|
33
|
+
// walks the filesystem directly and works.
|
|
34
|
+
const usedAuto = !options.prepass && (options.backend === 'auto' || options.backend === undefined);
|
|
35
|
+
if (usedAuto && prepass.constructor.name !== 'GrepOnlyBackend') {
|
|
36
|
+
try {
|
|
37
|
+
const probeClasses = await prepass.listClasses();
|
|
38
|
+
if (probeClasses.length === 0) {
|
|
39
|
+
const { GrepOnlyBackend } = await import('./backends/grep-only.js');
|
|
40
|
+
prepass = new GrepOnlyBackend();
|
|
41
|
+
await prepass.init(sourceDir);
|
|
42
|
+
await prepass.index();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// listClasses unsupported by this backend — leave it alone.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
29
49
|
const adaptersRun = [];
|
|
30
50
|
const facts = {
|
|
31
51
|
entities: [],
|
|
@@ -114,6 +134,76 @@ export async function runPrepass(sourceDir, options = {}) {
|
|
|
114
134
|
}
|
|
115
135
|
}
|
|
116
136
|
}
|
|
137
|
+
// ── TypeScript-interfaces walker (Phase C, plan: 2026-05-04
|
|
138
|
+
// ANALYSE-VIA-FAITHFUL-SKELETON-AND-MICROCALLS) — closes the adapter-
|
|
139
|
+
// free shape gap. Runs CORE per user direction (always, not gated on
|
|
140
|
+
// empty entities). Adapter-detected entities take precedence by name;
|
|
141
|
+
// the TS-interface walker fills in any entities that adapters missed.
|
|
142
|
+
// Non-entity declared types are recorded but NOT promoted to
|
|
143
|
+
// facts.entities (TODO #49 logs the future types: schema slot work).
|
|
144
|
+
if (options.extractInterfaces !== false) {
|
|
145
|
+
const { extractTypeScriptInterfaces } = await import('./adapters/typescript-interfaces.js');
|
|
146
|
+
try {
|
|
147
|
+
const tsi = await extractTypeScriptInterfaces(prepass, {
|
|
148
|
+
entityShapeHeuristic: options.entityShapeHeuristic ?? 'liberal',
|
|
149
|
+
});
|
|
150
|
+
if (tsi.entities.length > 0) {
|
|
151
|
+
// Merge: skip entities already present (adapter-detected names win).
|
|
152
|
+
const existingNames = new Set(facts.entities.map((e) => e.name));
|
|
153
|
+
let added = 0;
|
|
154
|
+
for (const ent of tsi.entities) {
|
|
155
|
+
if (existingNames.has(ent.name))
|
|
156
|
+
continue;
|
|
157
|
+
facts.entities.push({
|
|
158
|
+
name: ent.name,
|
|
159
|
+
filePath: ent.filePath,
|
|
160
|
+
sourceFramework: 'typescript-interfaces',
|
|
161
|
+
attributes: ent.fields.map((f) => ({
|
|
162
|
+
name: f.name,
|
|
163
|
+
declaredType: f.declaredType,
|
|
164
|
+
isPrimary: f.name === 'id' || f.name === '_id',
|
|
165
|
+
required: !f.isOptional,
|
|
166
|
+
})),
|
|
167
|
+
});
|
|
168
|
+
existingNames.add(ent.name);
|
|
169
|
+
added++;
|
|
170
|
+
}
|
|
171
|
+
if (added > 0)
|
|
172
|
+
adaptersRun.push('typescript-interfaces');
|
|
173
|
+
// Merge relationships (skip duplicates by from+to+type).
|
|
174
|
+
const seenRel = new Set(facts.relationships.map((r) => `${r.from}|${r.to}|${r.type}`));
|
|
175
|
+
for (const r of tsi.relationships) {
|
|
176
|
+
const key = `${r.from}|${r.to}|${r.type}`;
|
|
177
|
+
if (seenRel.has(key))
|
|
178
|
+
continue;
|
|
179
|
+
facts.relationships.push({ from: r.from, to: r.to, type: r.type });
|
|
180
|
+
seenRel.add(key);
|
|
181
|
+
}
|
|
182
|
+
// Merge lifecycles (engines 6.27.6+) — typescript-interfaces
|
|
183
|
+
// adapter now infers lifecycles from literal-union type aliases
|
|
184
|
+
// (`type Status = "a" | "b" | "c"`) referenced by entity
|
|
185
|
+
// fields. Skip if a decorator-adapter (or earlier walker)
|
|
186
|
+
// already produced a lifecycle for the same model — those are
|
|
187
|
+
// higher-fidelity signals (carry transitions from method bodies).
|
|
188
|
+
const seenLifecycles = new Set(facts.lifecycles.map((l) => l.model));
|
|
189
|
+
for (const lc of tsi.lifecycles) {
|
|
190
|
+
if (seenLifecycles.has(lc.model))
|
|
191
|
+
continue;
|
|
192
|
+
facts.lifecycles.push({
|
|
193
|
+
model: lc.model,
|
|
194
|
+
field: lc.field,
|
|
195
|
+
states: lc.states,
|
|
196
|
+
transitions: lc.transitions,
|
|
197
|
+
});
|
|
198
|
+
seenLifecycles.add(lc.model);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch (e) {
|
|
203
|
+
// TS-interfaces walker is best-effort; an error here doesn't
|
|
204
|
+
// stop the rest of the prepass.
|
|
205
|
+
}
|
|
206
|
+
}
|
|
117
207
|
// ── Candidate-step extraction (#27-B/C) — runs INDEPENDENTLY of
|
|
118
208
|
// entity detection. Pre-fix this block lived inside the
|
|
119
209
|
// typescript-decorators guard, which meant adapter-less codebases
|
|
@@ -127,6 +217,8 @@ export async function runPrepass(sourceDir, options = {}) {
|
|
|
127
217
|
const { extractCandidateSteps } = await import('./behavior-step-classifier.js');
|
|
128
218
|
const candidateMethods = [];
|
|
129
219
|
const fileSourceCache = new Map();
|
|
220
|
+
const recordAudit = options.recordAuditDecisions !== false;
|
|
221
|
+
const auditClasses = [];
|
|
130
222
|
const targets = [];
|
|
131
223
|
const seenTargetKeys = new Set();
|
|
132
224
|
const addTarget = (t) => {
|
|
@@ -181,9 +273,16 @@ export async function runPrepass(sourceDir, options = {}) {
|
|
|
181
273
|
? facts.lifecycles.find((lc) => lc.model === target.className)?.field
|
|
182
274
|
: undefined;
|
|
183
275
|
const methods = extractCandidateSteps(source, lifecycleField ? { lifecycleField } : {});
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
276
|
+
// Per-method audit record + filter pass with reason capture.
|
|
277
|
+
const perMethodDecisions = methods.map((m) => {
|
|
278
|
+
const filter = m.candidates.length === 0
|
|
279
|
+
? { kept: false, reason: 'no-candidates-classified' }
|
|
280
|
+
: evaluateMethodFilter(m);
|
|
281
|
+
return { method: m, filter };
|
|
282
|
+
});
|
|
283
|
+
const populated = perMethodDecisions
|
|
284
|
+
.filter((p) => p.filter.kept)
|
|
285
|
+
.map((p) => p.method);
|
|
187
286
|
if (populated.length > 0) {
|
|
188
287
|
candidateMethods.push({
|
|
189
288
|
filePath: target.filePath,
|
|
@@ -191,10 +290,163 @@ export async function runPrepass(sourceDir, options = {}) {
|
|
|
191
290
|
methods: populated,
|
|
192
291
|
});
|
|
193
292
|
}
|
|
293
|
+
if (recordAudit) {
|
|
294
|
+
const methodEntries = perMethodDecisions.map(({ method, filter }) => {
|
|
295
|
+
const histogram = {};
|
|
296
|
+
for (const c of method.candidates) {
|
|
297
|
+
histogram[c.kind] = (histogram[c.kind] ?? 0) + 1;
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
methodName: method.methodName,
|
|
301
|
+
isAsync: method.isAsync,
|
|
302
|
+
sourceLineRange: method.sourceLineRange,
|
|
303
|
+
candidateKindHistogram: histogram,
|
|
304
|
+
filter: filter,
|
|
305
|
+
};
|
|
306
|
+
});
|
|
307
|
+
auditClasses.push({
|
|
308
|
+
className: target.className,
|
|
309
|
+
filePath: target.filePath,
|
|
310
|
+
decision: { walked: true, reason: target.isEntity ? 'adapter-detected entity' : 'matches service-shaped name pattern' },
|
|
311
|
+
methodCount: { raw: methods.length, kept: populated.length },
|
|
312
|
+
methods: methodEntries,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// ── Express-routes adapter (engines 6.27.1+) ──
|
|
317
|
+
// Class-based walk above misses HTTP routing for codebases that use
|
|
318
|
+
// Express router files instead of `*Controller` classes (idle-meta:
|
|
319
|
+
// `routes/auth.ts` etc). Each route file becomes a synthetic
|
|
320
|
+
// controller; each `router.<verb>(path, handler)` call becomes one
|
|
321
|
+
// action.
|
|
322
|
+
try {
|
|
323
|
+
const { isExpressRouterFile, parseExpressRoutes, synthesizeControllerClass, deriveControllerName } = await import('./adapters/express-routes.js');
|
|
324
|
+
// listFiles' glob doesn't support brace-expansion ({ts,js,...}),
|
|
325
|
+
// so request `**/routes/**` then filter extensions in code.
|
|
326
|
+
const allRouteFiles = await prepass.listFiles({ glob: '**/routes/**' });
|
|
327
|
+
const candidateRouteFiles = allRouteFiles.filter((f) => /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(f));
|
|
328
|
+
for (const rf of candidateRouteFiles) {
|
|
329
|
+
let source;
|
|
330
|
+
try {
|
|
331
|
+
source = await prepass.fileSourceText(rf);
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (!source)
|
|
337
|
+
continue;
|
|
338
|
+
if (!isExpressRouterFile(source))
|
|
339
|
+
continue;
|
|
340
|
+
const handlers = parseExpressRoutes(source);
|
|
341
|
+
if (handlers.length === 0)
|
|
342
|
+
continue;
|
|
343
|
+
const controllerName = deriveControllerName(rf);
|
|
344
|
+
// Skip if a class with this name was already walked (avoids
|
|
345
|
+
// double emission when both a route file `auth.ts` and a class
|
|
346
|
+
// `AuthController` exist in source).
|
|
347
|
+
if (seenTargetKeys.has(`${rf}::${controllerName}`))
|
|
348
|
+
continue;
|
|
349
|
+
const synthClassBody = synthesizeControllerClass(controllerName, handlers);
|
|
350
|
+
const classifierMethods = extractCandidateSteps(synthClassBody);
|
|
351
|
+
const classifierByName = new Map(classifierMethods.map((m) => [m.methodName, m]));
|
|
352
|
+
// The class-body walker is `this.X`-oriented; HTTP route bodies
|
|
353
|
+
// typically have free-standing calls (`schema.parse(req.body)`,
|
|
354
|
+
// `res.json(...)`). When the classifier finds 0 candidates we
|
|
355
|
+
// still keep the handler — the per-action microcall LLM will
|
|
356
|
+
// author the body from the source-location pointer. Synthesize
|
|
357
|
+
// one minimal candidate so the method shape stays consistent
|
|
358
|
+
// and the filter doesn't drop it.
|
|
359
|
+
const remapped = handlers.map((h) => {
|
|
360
|
+
const c = classifierByName.get(h.methodName);
|
|
361
|
+
const candidates = c?.candidates ?? [];
|
|
362
|
+
const finalCandidates = candidates.length > 0 ? candidates : [{
|
|
363
|
+
kind: 'call',
|
|
364
|
+
position: 0,
|
|
365
|
+
summary: `HTTP ${h.httpVerb.toUpperCase()} ${h.routePath} (LLM-authored body via microcall)`,
|
|
366
|
+
}];
|
|
367
|
+
return {
|
|
368
|
+
methodName: h.methodName,
|
|
369
|
+
isAsync: h.isAsync,
|
|
370
|
+
body: c?.body ?? h.body,
|
|
371
|
+
sourceLineRange: h.sourceLineRange,
|
|
372
|
+
candidates: finalCandidates,
|
|
373
|
+
};
|
|
374
|
+
});
|
|
375
|
+
const perMethodDecisions = remapped.map((m) => {
|
|
376
|
+
// express-routes path always keeps handlers (HTTP routes are
|
|
377
|
+
// inherently real action surfaces). Skip the standard filter.
|
|
378
|
+
return { method: m, filter: { kept: true } };
|
|
379
|
+
});
|
|
380
|
+
const populated = perMethodDecisions
|
|
381
|
+
.filter((p) => p.filter.kept)
|
|
382
|
+
.map((p) => p.method);
|
|
383
|
+
if (populated.length > 0) {
|
|
384
|
+
candidateMethods.push({
|
|
385
|
+
filePath: rf,
|
|
386
|
+
entityName: controllerName,
|
|
387
|
+
methods: populated,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
if (recordAudit) {
|
|
391
|
+
const methodEntries = perMethodDecisions.map(({ method, filter }) => {
|
|
392
|
+
const histogram = {};
|
|
393
|
+
for (const c of method.candidates)
|
|
394
|
+
histogram[c.kind] = (histogram[c.kind] ?? 0) + 1;
|
|
395
|
+
return {
|
|
396
|
+
methodName: method.methodName,
|
|
397
|
+
isAsync: method.isAsync,
|
|
398
|
+
sourceLineRange: method.sourceLineRange,
|
|
399
|
+
candidateKindHistogram: histogram,
|
|
400
|
+
filter: filter,
|
|
401
|
+
};
|
|
402
|
+
});
|
|
403
|
+
auditClasses.push({
|
|
404
|
+
className: controllerName,
|
|
405
|
+
filePath: rf,
|
|
406
|
+
decision: { walked: true, reason: 'express-routes adapter (synthesized controller from Router())' },
|
|
407
|
+
methodCount: { raw: remapped.length, kept: populated.length },
|
|
408
|
+
methods: methodEntries,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
if (!adaptersRun.includes('express-routes'))
|
|
412
|
+
adaptersRun.push('express-routes');
|
|
413
|
+
}
|
|
194
414
|
}
|
|
415
|
+
catch { /* express-routes adapter is best-effort; continue */ }
|
|
195
416
|
if (candidateMethods.length > 0) {
|
|
196
417
|
facts.candidateMethods = candidateMethods;
|
|
197
418
|
}
|
|
419
|
+
if (recordAudit) {
|
|
420
|
+
// Aggregate stats across walker output.
|
|
421
|
+
const stats = {
|
|
422
|
+
classesWalked: auditClasses.length,
|
|
423
|
+
methodsRaw: 0,
|
|
424
|
+
methodsKept: 0,
|
|
425
|
+
methodsByDropReason: {},
|
|
426
|
+
candidateStepLines: 0,
|
|
427
|
+
candidateStepKindHistogram: {},
|
|
428
|
+
};
|
|
429
|
+
for (const cls of auditClasses) {
|
|
430
|
+
stats.methodsRaw += cls.methodCount.raw;
|
|
431
|
+
stats.methodsKept += cls.methodCount.kept;
|
|
432
|
+
for (const m of cls.methods) {
|
|
433
|
+
if (!m.filter.kept) {
|
|
434
|
+
stats.methodsByDropReason[m.filter.reason] =
|
|
435
|
+
(stats.methodsByDropReason[m.filter.reason] ?? 0) + 1;
|
|
436
|
+
}
|
|
437
|
+
for (const [kind, count] of Object.entries(m.candidateKindHistogram)) {
|
|
438
|
+
stats.candidateStepLines += count;
|
|
439
|
+
stats.candidateStepKindHistogram[kind] =
|
|
440
|
+
(stats.candidateStepKindHistogram[kind] ?? 0) + count;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
facts.auditDecisions = {
|
|
445
|
+
schemaVersion: '1.0',
|
|
446
|
+
classes: auditClasses,
|
|
447
|
+
stats,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
198
450
|
}
|
|
199
451
|
// Future framework-specific adapters slot in BEFORE the decorator
|
|
200
452
|
// fallback: typescript-typeorm, typescript-sequelize, typescript-drizzle.
|
|
@@ -202,27 +454,47 @@ export async function runPrepass(sourceDir, options = {}) {
|
|
|
202
454
|
// than the generic fallback.
|
|
203
455
|
facts.meta.adaptersRun = adaptersRun;
|
|
204
456
|
// ── Component suggestions ──
|
|
205
|
-
//
|
|
206
|
-
// 1.
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
457
|
+
// Three sources, ordered by AUTHOR-STATED-INTENT precedence:
|
|
458
|
+
// 1. Structural detector (HIGHEST signal) — author-stated boundaries
|
|
459
|
+
// from sub-package.json files OR apps/ services/ modules/ subdirs.
|
|
460
|
+
// idle-meta is a 168-file monorepo: apps/idle-clicker-mobile,
|
|
461
|
+
// apps/mythology-mobile, packages/idle-data, etc. — these dirs ARE
|
|
462
|
+
// the architectural decomposition.
|
|
463
|
+
// 2. Entity-graph Louvain — clusters the relationship graph when
|
|
464
|
+
// ORM adapters extracted ≥5 entities. Useful for single-package
|
|
465
|
+
// apps where structural signal is absent (cal-com, twenty).
|
|
466
|
+
// 3. Empty (LLM falls back to its own judgement).
|
|
212
467
|
//
|
|
213
|
-
//
|
|
214
|
-
//
|
|
468
|
+
// Prior versions (≤6.26.5) ran (1) only when entities < 5 — for
|
|
469
|
+
// monorepos with rich entity counts (idle-meta has 24), it skipped
|
|
470
|
+
// straight to (2) which collapsed everything to 2 generic-named
|
|
471
|
+
// buckets. Structural detection on monorepos is strictly better
|
|
472
|
+
// signal: package names like `idle-clicker-mobile` are author-chosen
|
|
473
|
+
// architectural identifiers; Louvain on a synthetic single-package
|
|
474
|
+
// graph is just clustering noise.
|
|
215
475
|
if (options.suggestComponents !== false) {
|
|
216
|
-
|
|
476
|
+
const { detectStructuralComponents } = await import('./structural-detector.js');
|
|
477
|
+
const structural = detectStructuralComponents(sourceDir);
|
|
478
|
+
if (structural.length >= 2) {
|
|
479
|
+
// Assign entities to structural buckets by filePath prefix.
|
|
480
|
+
// Each entity has filePath (from the walker); match against
|
|
481
|
+
// each component's structural.sourceDir. If no prefix matches,
|
|
482
|
+
// the entity falls through to the Unassigned bucket downstream.
|
|
483
|
+
const sortedByDirLen = [...structural].sort((a, b) => (b.structural?.sourceDir?.length ?? 0) - (a.structural?.sourceDir?.length ?? 0));
|
|
484
|
+
for (const ent of facts.entities) {
|
|
485
|
+
const home = sortedByDirLen.find((c) => c.structural?.sourceDir && ent.filePath.startsWith(c.structural.sourceDir));
|
|
486
|
+
if (home)
|
|
487
|
+
(home.entities ??= []).push(ent.name);
|
|
488
|
+
}
|
|
489
|
+
facts.suggestedComponents = structural;
|
|
490
|
+
}
|
|
491
|
+
else if (facts.entities.length >= 5) {
|
|
217
492
|
const { detectModelCommunities } = await import('./community-detection.js');
|
|
218
493
|
facts.suggestedComponents = detectModelCommunities(facts.entities, facts.relationships);
|
|
219
494
|
}
|
|
220
495
|
else {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (structural.length > 0) {
|
|
224
|
-
facts.suggestedComponents = structural;
|
|
225
|
-
}
|
|
496
|
+
// Fewer than 5 entities AND no structural signal — leave empty;
|
|
497
|
+
// the skeleton emitter uses the default-Application fallback.
|
|
226
498
|
}
|
|
227
499
|
}
|
|
228
500
|
// ── Per-method fact sheets (TODO #32) ──
|
|
@@ -295,19 +567,20 @@ export async function runPrepass(sourceDir, options = {}) {
|
|
|
295
567
|
*/
|
|
296
568
|
const CONTAINER_OP = /^this\.[a-zA-Z_$][\w$]*\.(get|set|has|delete|clear|size|values|keys|entries|push|pop|shift|unshift|add|remove|find|filter|map|forEach|some|every|reduce|includes|indexOf|sort|slice|splice|concat|join|length|of|from|isArray|fromEntries)$/;
|
|
297
569
|
const SELF_DELEGATION = /^this\.[a-zA-Z_$][\w$]*$/;
|
|
298
|
-
function
|
|
570
|
+
function evaluateMethodFilter(method) {
|
|
299
571
|
const c = method.candidates;
|
|
300
572
|
// Level-0: nothing but value returns (`getName() { return this.name }`).
|
|
301
|
-
if (c.length > 0 && c.every((s) => s.kind === 'return'))
|
|
302
|
-
return false;
|
|
573
|
+
if (c.length > 0 && c.every((s) => s.kind === 'return')) {
|
|
574
|
+
return { kept: false, reason: 'level-0-accessor' };
|
|
575
|
+
}
|
|
303
576
|
const nonReturn = c.filter((s) => s.kind !== 'return');
|
|
304
577
|
if (nonReturn.length === 0)
|
|
305
|
-
return false;
|
|
578
|
+
return { kept: false, reason: 'level-0-accessor' };
|
|
306
579
|
// Strong business signals — domain semantics that the realize stack
|
|
307
580
|
// can NOT auto-generate from CURVED conventions or attribute decls.
|
|
308
581
|
const hasStrong = nonReturn.some((s) => s.kind === 'validate' || s.kind === 'emit' || s.kind === 'transition');
|
|
309
582
|
if (hasStrong)
|
|
310
|
-
return true;
|
|
583
|
+
return { kept: true, reason: 'kept-business-action-strong-signal' };
|
|
311
584
|
// `[call]` candidates split into:
|
|
312
585
|
// - external — call to a non-self, non-container-op receiver. These
|
|
313
586
|
// are real cross-entity / cross-service coordination.
|
|
@@ -327,24 +600,33 @@ function isMethodWorthSurfacing(method) {
|
|
|
327
600
|
const findCount = nonReturn.filter((s) => s.kind === 'find' || s.kind === 'find-many').length;
|
|
328
601
|
// Single CURVED-shape (no externals): level-1 instance generator —
|
|
329
602
|
// use `cured: { retrieve|create|update|delete: {} }` shorthand.
|
|
330
|
-
if (writeKinds.size === 0 && findCount === 1 && externalCalls === 0)
|
|
331
|
-
return false;
|
|
332
|
-
|
|
333
|
-
|
|
603
|
+
if (writeKinds.size === 0 && findCount === 1 && externalCalls === 0) {
|
|
604
|
+
return { kept: false, reason: 'level-1-curved-retrieve' };
|
|
605
|
+
}
|
|
606
|
+
if (writeKinds.size === 1 && findCount <= 1 && externalCalls === 0) {
|
|
607
|
+
return { kept: false, reason: 'level-1-curved-create-update-delete' };
|
|
608
|
+
}
|
|
334
609
|
// Pure container/self-call wrapper (no CURVED, no external) — level-0.
|
|
335
|
-
if (writeKinds.size === 0 && findCount === 0 && externalCalls === 0)
|
|
336
|
-
return false;
|
|
610
|
+
if (writeKinds.size === 0 && findCount === 0 && externalCalls === 0) {
|
|
611
|
+
return { kept: false, reason: 'container-op-or-self-delegation-only' };
|
|
612
|
+
}
|
|
337
613
|
// Composite write ops or 2+ finds — multi-step action.
|
|
338
|
-
if (writeKinds.size >= 2 || findCount >= 2)
|
|
339
|
-
return true;
|
|
614
|
+
if (writeKinds.size >= 2 || findCount >= 2) {
|
|
615
|
+
return { kept: true, reason: 'kept-multi-step-composition' };
|
|
616
|
+
}
|
|
340
617
|
// Multiple distinct external calls — cross-entity coordination.
|
|
341
|
-
if (externalCalls >= 2)
|
|
342
|
-
return true;
|
|
618
|
+
if (externalCalls >= 2) {
|
|
619
|
+
return { kept: true, reason: 'kept-multiple-external-calls' };
|
|
620
|
+
}
|
|
343
621
|
// Single external call only counts as business if there's other shape
|
|
344
622
|
// to it (≥3 total non-return candidates). One-line delegations drop.
|
|
345
|
-
if (externalCalls === 1 && nonReturn.length >= 3)
|
|
346
|
-
return true;
|
|
347
|
-
|
|
623
|
+
if (externalCalls === 1 && nonReturn.length >= 3) {
|
|
624
|
+
return { kept: true, reason: 'kept-multi-step-composition' };
|
|
625
|
+
}
|
|
626
|
+
return { kept: false, reason: 'container-op-or-self-delegation-only' };
|
|
627
|
+
}
|
|
628
|
+
function isMethodWorthSurfacing(method) {
|
|
629
|
+
return evaluateMethodFilter(method).kept;
|
|
348
630
|
}
|
|
349
631
|
/**
|
|
350
632
|
* Format a `SpecVerseFacts` object as a markdown block suitable for
|