@cleocode/core 2026.6.14 → 2026.6.17
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/check/pr-gate.d.ts +6 -2
- package/dist/check/pr-gate.d.ts.map +1 -1
- package/dist/check/pr-gate.js +14 -32
- package/dist/check/pr-gate.js.map +1 -1
- package/dist/config/config-repair.d.ts +70 -0
- package/dist/config/config-repair.d.ts.map +1 -0
- package/dist/config/config-repair.js +248 -0
- package/dist/config/config-repair.js.map +1 -0
- package/dist/config/registry.d.ts.map +1 -1
- package/dist/config/registry.js +4 -4
- package/dist/config/registry.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -10
- package/dist/config.js.map +1 -1
- package/dist/docs/export-document.js +58 -16
- package/dist/docs/export-document.js.map +2 -2
- package/dist/gc/cleanup.d.ts +23 -8
- package/dist/gc/cleanup.d.ts.map +1 -1
- package/dist/gc/cleanup.js +287 -22
- package/dist/gc/cleanup.js.map +1 -1
- package/dist/gc/janitor.d.ts +149 -0
- package/dist/gc/janitor.d.ts.map +1 -0
- package/dist/gc/janitor.js +760 -0
- package/dist/gc/janitor.js.map +1 -0
- package/dist/internal.d.ts +1 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +3 -0
- package/dist/internal.js.map +1 -1
- package/dist/llm/cli-ops.d.ts +31 -4
- package/dist/llm/cli-ops.d.ts.map +1 -1
- package/dist/llm/cli-ops.js +110 -26
- package/dist/llm/cli-ops.js.map +1 -1
- package/dist/llm/credential-pool.d.ts +62 -0
- package/dist/llm/credential-pool.d.ts.map +1 -1
- package/dist/llm/credential-pool.js +161 -0
- package/dist/llm/credential-pool.js.map +1 -1
- package/dist/llm/cross-provider-selector.d.ts +254 -0
- package/dist/llm/cross-provider-selector.d.ts.map +1 -0
- package/dist/llm/cross-provider-selector.js +635 -0
- package/dist/llm/cross-provider-selector.js.map +1 -0
- package/dist/llm/index.d.ts +2 -0
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +1 -0
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/local-model-fit.d.ts +260 -0
- package/dist/llm/local-model-fit.d.ts.map +1 -0
- package/dist/llm/local-model-fit.js +563 -0
- package/dist/llm/local-model-fit.js.map +1 -0
- package/dist/llm/plugin-facade.js +883 -231
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/llm/provider-registry/builtin/ollama.d.ts +18 -0
- package/dist/llm/provider-registry/builtin/ollama.d.ts.map +1 -1
- package/dist/llm/provider-registry/builtin/ollama.js +20 -2
- package/dist/llm/provider-registry/builtin/ollama.js.map +1 -1
- package/dist/llm/role-resolver.d.ts.map +1 -1
- package/dist/llm/role-resolver.js +45 -10
- package/dist/llm/role-resolver.js.map +1 -1
- package/dist/llm/transports/codex-responses.d.ts +111 -88
- package/dist/llm/transports/codex-responses.d.ts.map +1 -1
- package/dist/llm/transports/codex-responses.js +456 -258
- package/dist/llm/transports/codex-responses.js.map +1 -1
- package/dist/release/index.d.ts +2 -2
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +1 -1
- package/dist/release/index.js.map +1 -1
- package/dist/release/reconcile.d.ts +97 -0
- package/dist/release/reconcile.d.ts.map +1 -1
- package/dist/release/reconcile.js +412 -5
- package/dist/release/reconcile.js.map +1 -1
- package/dist/resources/backend.d.ts +155 -0
- package/dist/resources/backend.d.ts.map +1 -0
- package/dist/resources/backend.js +23 -0
- package/dist/resources/backend.js.map +1 -0
- package/dist/resources/linux-backend.d.ts +167 -0
- package/dist/resources/linux-backend.d.ts.map +1 -0
- package/dist/resources/linux-backend.js +259 -0
- package/dist/resources/linux-backend.js.map +1 -0
- package/dist/resources/monitor.d.ts +230 -0
- package/dist/resources/monitor.d.ts.map +1 -0
- package/dist/resources/monitor.js +255 -0
- package/dist/resources/monitor.js.map +1 -0
- package/dist/resources/spawn-wrapper.d.ts +265 -0
- package/dist/resources/spawn-wrapper.d.ts.map +1 -0
- package/dist/resources/spawn-wrapper.js +304 -0
- package/dist/resources/spawn-wrapper.js.map +1 -0
- package/dist/selfimprove/budget.d.ts +11 -2
- package/dist/selfimprove/budget.d.ts.map +1 -1
- package/dist/selfimprove/budget.js +11 -2
- package/dist/selfimprove/budget.js.map +1 -1
- package/dist/selfimprove/fix-gen-context.d.ts +172 -0
- package/dist/selfimprove/fix-gen-context.d.ts.map +1 -0
- package/dist/selfimprove/fix-gen-context.js +218 -0
- package/dist/selfimprove/fix-gen-context.js.map +1 -0
- package/dist/selfimprove/fix-gen.d.ts +285 -0
- package/dist/selfimprove/fix-gen.d.ts.map +1 -0
- package/dist/selfimprove/fix-gen.js +346 -0
- package/dist/selfimprove/fix-gen.js.map +1 -0
- package/dist/selfimprove/op-source-map.d.ts +92 -0
- package/dist/selfimprove/op-source-map.d.ts.map +1 -0
- package/dist/selfimprove/op-source-map.js +187 -0
- package/dist/selfimprove/op-source-map.js.map +1 -0
- package/dist/selfimprove/probe-helper.d.ts +61 -0
- package/dist/selfimprove/probe-helper.d.ts.map +1 -0
- package/dist/selfimprove/probe-helper.js +64 -0
- package/dist/selfimprove/probe-helper.js.map +1 -0
- package/dist/selfimprove/run-loop.d.ts +44 -4
- package/dist/selfimprove/run-loop.d.ts.map +1 -1
- package/dist/selfimprove/run-loop.js +73 -6
- package/dist/selfimprove/run-loop.js.map +1 -1
- package/dist/selfimprove/scenarios/seeded-code-regression/golden.json +18 -0
- package/dist/selfimprove/scenarios/seeded-code-regression/scenario.json +12 -0
- package/dist/sentient/cross-project-hygiene.d.ts +11 -2
- package/dist/sentient/cross-project-hygiene.d.ts.map +1 -1
- package/dist/sentient/cross-project-hygiene.js +73 -10
- package/dist/sentient/cross-project-hygiene.js.map +1 -1
- package/dist/sentient/daemon.d.ts.map +1 -1
- package/dist/sentient/daemon.js +7 -2
- package/dist/sentient/daemon.js.map +1 -1
- package/dist/sentient/worktree-dispatch.d.ts.map +1 -1
- package/dist/sentient/worktree-dispatch.js +8 -1
- package/dist/sentient/worktree-dispatch.js.map +1 -1
- package/dist/setup/index.d.ts +1 -0
- package/dist/setup/index.d.ts.map +1 -1
- package/dist/setup/index.js +1 -0
- package/dist/setup/index.js.map +1 -1
- package/dist/setup/sections/models-roles.d.ts +32 -1
- package/dist/setup/sections/models-roles.d.ts.map +1 -1
- package/dist/setup/sections/models-roles.js +118 -19
- package/dist/setup/sections/models-roles.js.map +1 -1
- package/dist/setup/whoami-summary.d.ts +34 -0
- package/dist/setup/whoami-summary.d.ts.map +1 -0
- package/dist/setup/whoami-summary.js +106 -0
- package/dist/setup/whoami-summary.js.map +1 -0
- package/dist/spawn/branch-lock.d.ts.map +1 -1
- package/dist/spawn/branch-lock.js +7 -1
- package/dist/spawn/branch-lock.js.map +1 -1
- package/dist/store/attachment-repair.d.ts +110 -0
- package/dist/store/attachment-repair.d.ts.map +1 -0
- package/dist/store/attachment-repair.js +326 -0
- package/dist/store/attachment-repair.js.map +1 -0
- package/dist/store/attachment-store.d.ts.map +1 -1
- package/dist/store/attachment-store.js +24 -7
- package/dist/store/attachment-store.js.map +1 -1
- package/dist/tasks/evidence.d.ts +34 -2
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js +293 -35
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/verification/verify-tools.d.ts.map +1 -1
- package/dist/verification/verify-tools.js +5 -6
- package/dist/verification/verify-tools.js.map +1 -1
- package/package.json +22 -12
- package/templates/workflows/release-prepare.yml.tmpl +48 -2
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fix-generation stage for the self-improvement loop (T11889 · T11975).
|
|
3
|
+
*
|
|
4
|
+
* This is the missing autonomous link the v1 loop explicitly stubbed out
|
|
5
|
+
* ("NO autonomous fix-gen in v1", see {@link "./run-loop.js"}): given a detected
|
|
6
|
+
* regression (an open `selfimprove_dhq` + its envelope-diff) plus minimal repo
|
|
7
|
+
* context, it asks the LLM to PROPOSE a unified-diff patch and writes that patch
|
|
8
|
+
* to the path the draft-PR egress ({@link "./draft-pr.js".openDraftPr}) already
|
|
9
|
+
* `existsSync`-checks: `<cwd>/selfimprove-<scenario>.patch`. Once the patch is on
|
|
10
|
+
* disk the existing egress guard opens ONE DRAFT PR — closing the
|
|
11
|
+
* DHQ → fix → draft-PR pipeline end-to-end.
|
|
12
|
+
*
|
|
13
|
+
* ## Hard safety posture (unchanged from v1 — P5 spec §B.7)
|
|
14
|
+
*
|
|
15
|
+
* - **LLM ONLY via the E9 chokepoint.** The real generator
|
|
16
|
+
* ({@link createLlmFixGenerator}) resolves its model strictly through
|
|
17
|
+
* {@link "../llm/system-resolver.js".resolveLLMForSystem} → {@link ModelRunner}
|
|
18
|
+
* (Gate-13). It constructs NO raw provider client, reads NO `*_API_KEY` env,
|
|
19
|
+
* and hardcodes no model id — the resolver/registry is the SSoT. The
|
|
20
|
+
* plaintext token is materialized only at the wire boundary (E10).
|
|
21
|
+
* - **Draft-PR-ONLY, never auto-merge.** This module produces a PATCH FILE only;
|
|
22
|
+
* the egress that consumes it always opens a `--draft` PR against a feature
|
|
23
|
+
* branch (never `main`). This module performs NO git/gh action.
|
|
24
|
+
* - **Graceful degrade, never a rogue mutation.** Every failure (no credential,
|
|
25
|
+
* LLM error, empty / non-unified-diff output) returns a typed
|
|
26
|
+
* {@link FixGenResult} of kind `'skipped'` and writes NO patch file — so the
|
|
27
|
+
* existing egress guard (`existsSync` on the patch path) simply skips the PR.
|
|
28
|
+
* This function NEVER throws.
|
|
29
|
+
* - **Injectable seam.** The LLM dependency is the {@link FixGenerator} port;
|
|
30
|
+
* unit tests inject a deterministic fake that returns a canned patch, so NO
|
|
31
|
+
* real LLM is reached in tests.
|
|
32
|
+
*
|
|
33
|
+
* CORE-first: this engine lives in `core` and owns the `FixGenerator` port TYPE.
|
|
34
|
+
* Import-time side-effect-free.
|
|
35
|
+
*
|
|
36
|
+
* @module @cleocode/core/selfimprove/fix-gen
|
|
37
|
+
* @epic T11889
|
|
38
|
+
* @task T11975
|
|
39
|
+
*/
|
|
40
|
+
import { writeFileSync } from 'node:fs';
|
|
41
|
+
import { resolve as resolvePath } from 'node:path';
|
|
42
|
+
import { cwd as processCwd } from 'node:process';
|
|
43
|
+
import { redact } from '@cleocode/utils';
|
|
44
|
+
import { loadFileContext, renderFileContextSection, } from './fix-gen-context.js';
|
|
45
|
+
/**
|
|
46
|
+
* Maximum byte length of a model-reply excerpt stored in DHQ evidence or logs.
|
|
47
|
+
* Replies beyond this threshold are truncated with a marker so logs stay bounded
|
|
48
|
+
* while preserving enough context for diagnosis.
|
|
49
|
+
*/
|
|
50
|
+
const REPLY_EXCERPT_MAX_BYTES = 3072;
|
|
51
|
+
/**
|
|
52
|
+
* The E9 system-of-use label the fix-generator resolves its model under. Maps to
|
|
53
|
+
* the `judgement` role (see `SYSTEM_ROLE_MAP`) — the closest standing role for
|
|
54
|
+
* "reason about a regression and propose a code change".
|
|
55
|
+
*/
|
|
56
|
+
const FIXGEN_SYSTEM = 'task-executor';
|
|
57
|
+
/** A leading marker every unified-diff hunk header / file header carries. */
|
|
58
|
+
const UNIFIED_DIFF_MARKERS = ['diff --git ', '--- ', '+++ ', '@@ '];
|
|
59
|
+
/**
|
|
60
|
+
* Compute the patch path the draft-PR egress expects for a scenario:
|
|
61
|
+
* `<cwd>/selfimprove-<scenario>.patch`. The scenario is sanitized to a safe file
|
|
62
|
+
* stem so a hostile scenario name cannot escape the cwd.
|
|
63
|
+
*
|
|
64
|
+
* @param scenario - The scenario name.
|
|
65
|
+
* @param cwd - The working directory to resolve against (defaults to `process.cwd`).
|
|
66
|
+
* @returns The absolute patch path.
|
|
67
|
+
*/
|
|
68
|
+
export function fixPatchPath(scenario, cwd) {
|
|
69
|
+
const safeScenario = scenario.replace(/[^a-z0-9-]/gi, '-');
|
|
70
|
+
return resolvePath(cwd ?? processCwd(), `selfimprove-${safeScenario}.patch`);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Is `text` a plausible unified diff?
|
|
74
|
+
*
|
|
75
|
+
* A real `git apply`-able patch always carries at least one of the canonical
|
|
76
|
+
* unified-diff markers ({@link UNIFIED_DIFF_MARKERS}). An LLM that returns prose,
|
|
77
|
+
* an apology, or an empty string fails this guard, so the loop degrades to "no
|
|
78
|
+
* patch" rather than writing junk the egress would then fail to `git apply`.
|
|
79
|
+
*
|
|
80
|
+
* This is a cheap structural sniff, NOT a full parse — the authoritative
|
|
81
|
+
* applicability check is `git apply` inside the egress (which fails the PR cut on
|
|
82
|
+
* a bad patch, never `main`).
|
|
83
|
+
*
|
|
84
|
+
* @param text - Candidate patch text.
|
|
85
|
+
* @returns `true` when the text looks like a unified diff.
|
|
86
|
+
*/
|
|
87
|
+
export function looksLikeUnifiedDiff(text) {
|
|
88
|
+
if (text.trim().length === 0)
|
|
89
|
+
return false;
|
|
90
|
+
return UNIFIED_DIFF_MARKERS.some((marker) => text.includes(marker));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Build the system + user prompt the real generator sends to the LLM. Pure
|
|
94
|
+
* (no IO) so it is unit-testable in isolation when an explicit `fileContext` is
|
|
95
|
+
* passed; the default path calls {@link loadFileContext} to resolve the relevant
|
|
96
|
+
* source files for each regressing op-coordinate (IO-bearing path used in
|
|
97
|
+
* production).
|
|
98
|
+
*
|
|
99
|
+
* The prompt is deliberately strict: "respond with ONLY a unified diff" — anything
|
|
100
|
+
* else fails {@link looksLikeUnifiedDiff} downstream and degrades to "no patch".
|
|
101
|
+
* When file context is available it is embedded between the regression description
|
|
102
|
+
* and the "produce the diff" instruction so the model can locate the responsible
|
|
103
|
+
* code. When context is absent (unmapped op or budget exhausted) the model is
|
|
104
|
+
* explicitly told it may respond `NO_PATCH` — this keeps the prompt honest.
|
|
105
|
+
*
|
|
106
|
+
* @param request - The fix-generation request.
|
|
107
|
+
* @param fileContext - Optional pre-loaded file context (injected for pure unit
|
|
108
|
+
* tests). When absent, {@link loadFileContext} is called with the request's
|
|
109
|
+
* `repoContext.projectRoot` and the op-coordinates from `regressions`.
|
|
110
|
+
* @returns The `{ system, user }` prompt pair.
|
|
111
|
+
*
|
|
112
|
+
* @task T11988
|
|
113
|
+
*/
|
|
114
|
+
export function buildFixGenPrompt(request, fileContext) {
|
|
115
|
+
const system = 'You are an autonomous software-maintenance agent. You are given a detected ' +
|
|
116
|
+
'regression in a TypeScript monorepo (a divergence between a replayed scenario ' +
|
|
117
|
+
'and its golden expected output). Produce a MINIMAL fix as a single unified diff ' +
|
|
118
|
+
'(`git diff` format, with `diff --git`, `---`, `+++`, and `@@` hunk headers). ' +
|
|
119
|
+
'Respond with ONLY the unified diff and NOTHING else — no prose, no code fences, ' +
|
|
120
|
+
'no explanation. If you cannot propose a safe fix, respond with the single token ' +
|
|
121
|
+
'NO_PATCH.';
|
|
122
|
+
const lines = request.regressions.map((r) => `- op ${r.opCoord} (#${r.opIndex}) at path \`${r.path}\`: ` +
|
|
123
|
+
`actual=${JSON.stringify(r.actual)} expected=${JSON.stringify(r.expected)}`);
|
|
124
|
+
// Resolve file context: use the pre-loaded context (pure test path) or load it
|
|
125
|
+
// now from disk (production path). Either way we render the same section string.
|
|
126
|
+
const ctx = fileContext ??
|
|
127
|
+
loadFileContext({
|
|
128
|
+
projectRoot: request.repoContext.projectRoot,
|
|
129
|
+
opCoords: request.regressions.map((r) => r.opCoord),
|
|
130
|
+
...request.repoContext.contextBudget,
|
|
131
|
+
});
|
|
132
|
+
const fileSection = renderFileContextSection(ctx);
|
|
133
|
+
const user = `Regression ${request.dhqId} in scenario \`${request.scenario}\` ` +
|
|
134
|
+
`(${request.regressions.length} diverging path(s)).\n` +
|
|
135
|
+
(request.repoContext.summary ? `Scenario summary: ${request.repoContext.summary}\n` : '') +
|
|
136
|
+
`Project root: ${request.repoContext.projectRoot}\n\n` +
|
|
137
|
+
`Diverging paths:\n${lines.join('\n')}\n` +
|
|
138
|
+
(fileSection
|
|
139
|
+
? `\n${fileSection}\n`
|
|
140
|
+
: '\n[No source file context available — respond NO_PATCH if you cannot locate the fix.]\n') +
|
|
141
|
+
'\nProduce the unified diff that resolves these divergences.';
|
|
142
|
+
return { system, user };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Produce a credential-redacted, byte-bounded excerpt of a raw model reply for
|
|
146
|
+
* safe logging and DHQ evidence attachment.
|
|
147
|
+
*
|
|
148
|
+
* The excerpt is at most {@link REPLY_EXCERPT_MAX_BYTES} UTF-8 bytes. When the
|
|
149
|
+
* reply is longer a `…[truncated <N> bytes]` marker replaces the tail so the
|
|
150
|
+
* caller can distinguish a genuinely-short reply from a truncated one. The
|
|
151
|
+
* returned string is already passed through {@link redact} so no downstream
|
|
152
|
+
* scrubbing is needed.
|
|
153
|
+
*
|
|
154
|
+
* @param reply - The raw model reply text.
|
|
155
|
+
* @returns A scrubbed, bounded excerpt string.
|
|
156
|
+
*/
|
|
157
|
+
export function truncateReply(reply) {
|
|
158
|
+
const scrubbed = redact(reply);
|
|
159
|
+
const buf = Buffer.from(scrubbed, 'utf8');
|
|
160
|
+
if (buf.byteLength <= REPLY_EXCERPT_MAX_BYTES)
|
|
161
|
+
return scrubbed;
|
|
162
|
+
const truncated = buf.subarray(0, REPLY_EXCERPT_MAX_BYTES).toString('utf8');
|
|
163
|
+
const overflow = buf.byteLength - REPLY_EXCERPT_MAX_BYTES;
|
|
164
|
+
return `${truncated}…[truncated ${overflow} bytes]`;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Lazily-resolved module logger (import-time side-effect-free).
|
|
168
|
+
*/
|
|
169
|
+
let cachedLogger;
|
|
170
|
+
async function getModuleLogger() {
|
|
171
|
+
if (cachedLogger === undefined) {
|
|
172
|
+
const { getLogger } = await import('../logger.js');
|
|
173
|
+
cachedLogger = getLogger('selfimprove-fix-gen');
|
|
174
|
+
}
|
|
175
|
+
return cachedLogger;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Run the fix-generation stage: ask the injected {@link FixGenerator} for a patch,
|
|
179
|
+
* validate it as a unified diff, and write it to the egress-expected patch path.
|
|
180
|
+
*
|
|
181
|
+
* This function NEVER throws and NEVER mutates anything but the single patch file.
|
|
182
|
+
* On ANY degrade path — generator returns `'none'`, the generator throws, or the
|
|
183
|
+
* returned text is not a unified diff — it writes NO file and returns
|
|
184
|
+
* `{ kind: 'skipped', reason }`, so the downstream `existsSync` egress guard
|
|
185
|
+
* simply skips the PR. The caller records the `reason` on the DHQ evidence.
|
|
186
|
+
*
|
|
187
|
+
* @param opts - See {@link GenerateFixPatchOptions}.
|
|
188
|
+
* @returns A {@link FixGenResult}.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* const res = await generateFixPatch({
|
|
193
|
+
* request: { dhqId: 'DHQ-abcd1234', scenario, questionHash, regressions, repoContext },
|
|
194
|
+
* generator: createLlmFixGenerator(),
|
|
195
|
+
* cwd: projectRoot,
|
|
196
|
+
* });
|
|
197
|
+
* if (res.kind === 'written') { // openDraftPr will now find selfimprove-<scenario>.patch }
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
export async function generateFixPatch(opts) {
|
|
201
|
+
const logger = opts.logger ?? (await getModuleLogger());
|
|
202
|
+
const { request, generator } = opts;
|
|
203
|
+
const patchPath = fixPatchPath(request.scenario, opts.cwd);
|
|
204
|
+
let output;
|
|
205
|
+
try {
|
|
206
|
+
output = await generator.propose(request);
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
const reason = `fixgen-threw:${err instanceof Error ? err.message : String(err)}`;
|
|
210
|
+
logger.warn({ dhqId: request.dhqId, scenario: request.scenario, reason }, 'fix-gen degraded');
|
|
211
|
+
return { kind: 'skipped', reason };
|
|
212
|
+
}
|
|
213
|
+
if (output.kind === 'none') {
|
|
214
|
+
// For model-declined the generator already pre-sanitized the rawReply field;
|
|
215
|
+
// log it at debug so the reply is visible without noise on green runs.
|
|
216
|
+
const replyExcerpt = output.rawReply;
|
|
217
|
+
if (replyExcerpt !== undefined) {
|
|
218
|
+
logger.debug({ dhqId: request.dhqId, scenario: request.scenario, reason: output.reason, replyExcerpt }, 'fix-gen model declined — raw reply excerpt (redacted, truncated) attached to DHQ evidence');
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
logger.info({ dhqId: request.dhqId, scenario: request.scenario, reason: output.reason }, 'fix-gen produced no patch (graceful skip — no PR)');
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
kind: 'skipped',
|
|
225
|
+
reason: `fixgen-none:${output.reason}`,
|
|
226
|
+
...(replyExcerpt !== undefined ? { replyExcerpt } : {}),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
if (!looksLikeUnifiedDiff(output.diff)) {
|
|
230
|
+
// The model returned something but it is not a unified diff. Log the reply
|
|
231
|
+
// excerpt at warn (actionable — the model may need a prompt tweak) and
|
|
232
|
+
// attach it to the DHQ evidence row for the operator.
|
|
233
|
+
const replyExcerpt = truncateReply(output.diff);
|
|
234
|
+
logger.warn({ dhqId: request.dhqId, scenario: request.scenario, replyExcerpt }, 'fix-gen output is not a unified diff (graceful skip — no PR); raw reply attached to DHQ evidence');
|
|
235
|
+
return { kind: 'skipped', reason: 'fixgen-not-a-diff', replyExcerpt };
|
|
236
|
+
}
|
|
237
|
+
// Normalize a trailing newline so `git apply` accepts the hunk.
|
|
238
|
+
const diff = output.diff.endsWith('\n') ? output.diff : `${output.diff}\n`;
|
|
239
|
+
writeFileSync(patchPath, diff, 'utf8');
|
|
240
|
+
const bytes = Buffer.byteLength(diff, 'utf8');
|
|
241
|
+
logger.info({ dhqId: request.dhqId, scenario: request.scenario, patchPath, bytes, model: output.model }, 'fix-gen wrote candidate patch — egress will open a DRAFT PR');
|
|
242
|
+
return { kind: 'written', patchPath, bytes, model: output.model };
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Construct the REAL fix generator — the one that drives the E9 LLM chokepoint.
|
|
246
|
+
*
|
|
247
|
+
* Resolution funnels through {@link resolveLLMForSystem}(`'task-executor'`) →
|
|
248
|
+
* {@link ModelRunner.build} → `session.send` (ONE non-streaming completion).
|
|
249
|
+
* It constructs NO raw provider client, reads NO API-key env, and hardcodes no
|
|
250
|
+
* model id (Gate-13). The plaintext credential is materialized ONLY at the
|
|
251
|
+
* `ModelRunner` wire boundary (E10) via the sealed handle. When no credential is
|
|
252
|
+
* reachable it returns `{ kind: 'none' }` — the loop degrades to "no patch", no
|
|
253
|
+
* PR. This function constructs nothing at call time (lazy dynamic imports keep the
|
|
254
|
+
* module import-time side-effect-free + the E9 deps off the hot import path).
|
|
255
|
+
*
|
|
256
|
+
* @param opts - Optional project root threaded into the resolver.
|
|
257
|
+
* @returns A {@link FixGenerator} backed by the E9 chokepoint.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```ts
|
|
261
|
+
* const gen = createLlmFixGenerator({ projectRoot });
|
|
262
|
+
* const out = await gen.propose(request); // resolves model via E9, never raw client
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
export function createLlmFixGenerator(opts = {}) {
|
|
266
|
+
return {
|
|
267
|
+
async propose(request) {
|
|
268
|
+
const logger = await getModuleLogger();
|
|
269
|
+
// Lazy imports: keep E9 deps off the module import path + side-effect-free.
|
|
270
|
+
const { resolveLLMForSystem } = await import('../llm/system-resolver.js');
|
|
271
|
+
const { ModelRunner } = await import('../llm/model-runner.js');
|
|
272
|
+
// 1. E9 resolution chokepoint. Never throws (resolver contract).
|
|
273
|
+
const projectRoot = opts.projectRoot ?? request.repoContext.projectRoot;
|
|
274
|
+
const resolved = await resolveLLMForSystem(FIXGEN_SYSTEM, { projectRoot });
|
|
275
|
+
if (!resolved.sealedCredential && resolved.authType !== 'aws_sdk') {
|
|
276
|
+
return { kind: 'none', reason: 'no-credential-resolved' };
|
|
277
|
+
}
|
|
278
|
+
// 2. Materialize the plaintext ONLY at the wire boundary (E10), build a
|
|
279
|
+
// clean descriptor, and construct the transport inside ModelRunner.
|
|
280
|
+
const apiKey = resolved.sealedCredential
|
|
281
|
+
? (await resolved.sealedCredential.fetch()).value
|
|
282
|
+
: null;
|
|
283
|
+
const built = await ModelRunner.build({
|
|
284
|
+
provider: resolved.provider,
|
|
285
|
+
model: resolved.model,
|
|
286
|
+
credential: resolved.credential
|
|
287
|
+
? {
|
|
288
|
+
provider: resolved.credential.provider,
|
|
289
|
+
apiKey,
|
|
290
|
+
source: resolved.credential.source,
|
|
291
|
+
authType: resolved.credential.authType,
|
|
292
|
+
}
|
|
293
|
+
: null,
|
|
294
|
+
source: resolved.source,
|
|
295
|
+
...(resolved.credentialLabel !== undefined
|
|
296
|
+
? { credentialLabel: resolved.credentialLabel }
|
|
297
|
+
: {}),
|
|
298
|
+
apiMode: resolved.apiMode,
|
|
299
|
+
baseUrl: resolved.baseUrl,
|
|
300
|
+
authType: resolved.authType,
|
|
301
|
+
...(resolved.capabilities !== undefined ? { capabilities: resolved.capabilities } : {}),
|
|
302
|
+
});
|
|
303
|
+
// 3. ONE non-streaming completion. The system prompt is threaded onto the
|
|
304
|
+
// request via `systemSuffix` (ConcreteSession maps it to
|
|
305
|
+
// `TransportRequest.system`); the user turn carries the regression detail.
|
|
306
|
+
const { system, user } = buildFixGenPrompt(request);
|
|
307
|
+
try {
|
|
308
|
+
const response = await built.session.send([{ role: 'user', content: user }], {
|
|
309
|
+
systemSuffix: system,
|
|
310
|
+
});
|
|
311
|
+
const text = (response.content ?? '').trim();
|
|
312
|
+
if (text.length === 0 || text === 'NO_PATCH') {
|
|
313
|
+
// Attach a redacted, bounded excerpt so the caller can log it onto
|
|
314
|
+
// the DHQ evidence row without having to re-run. The empty-reply case
|
|
315
|
+
// carries no useful excerpt; only the non-empty case (e.g. prose like
|
|
316
|
+
// "I cannot fix this") is worth capturing.
|
|
317
|
+
const rawReply = text.length > 0 ? truncateReply(text) : undefined;
|
|
318
|
+
return {
|
|
319
|
+
kind: 'none',
|
|
320
|
+
reason: 'model-declined',
|
|
321
|
+
...(rawReply !== undefined ? { rawReply } : {}),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
return { kind: 'patch', diff: stripCodeFences(text), model: response.model };
|
|
325
|
+
}
|
|
326
|
+
catch (err) {
|
|
327
|
+
logger.warn({ system: FIXGEN_SYSTEM, err: err instanceof Error ? err.message : String(err) }, 'fix-gen LLM call failed — degrading to no-patch');
|
|
328
|
+
return { kind: 'none', reason: 'llm-call-failed' };
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Strip a single surrounding markdown code fence (```diff … ```), if present, so a
|
|
335
|
+
* model that wraps its diff still yields an applyable patch. A bare diff passes
|
|
336
|
+
* through untouched.
|
|
337
|
+
*
|
|
338
|
+
* @param text - Candidate patch text (already trimmed).
|
|
339
|
+
* @returns The fence-stripped text.
|
|
340
|
+
*/
|
|
341
|
+
export function stripCodeFences(text) {
|
|
342
|
+
const fence = /^```[a-z]*\n([\s\S]*?)\n```$/i;
|
|
343
|
+
const m = text.match(fence);
|
|
344
|
+
return m?.[1] !== undefined ? m[1].trim() : text;
|
|
345
|
+
}
|
|
346
|
+
//# sourceMappingURL=fix-gen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix-gen.js","sourceRoot":"","sources":["../../src/selfimprove/fix-gen.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static op-coordinate → source-file map for the self-improvement fix-gen stage.
|
|
3
|
+
*
|
|
4
|
+
* Given a regression's `opCoord` (the `domain.operation` string produced by
|
|
5
|
+
* {@link "../selfimprove/envelope-diff.js".DiffEntry.opCoord}, e.g. `tasks.show`),
|
|
6
|
+
* this module resolves the **repo-relative** paths of the CLI handler and the
|
|
7
|
+
* core module(s) most likely to contain the regression. The file list is fed into
|
|
8
|
+
* the fix-gen prompt builder ({@link "./fix-gen-context.js"}) so the LLM receives
|
|
9
|
+
* bounded, targeted code context rather than zero context or an unbounded repo
|
|
10
|
+
* dump.
|
|
11
|
+
*
|
|
12
|
+
* ## Design: static map, not a registry query
|
|
13
|
+
*
|
|
14
|
+
* The ops catalog (the `OPERATIONS` array in `@cleocode/contracts`) encodes
|
|
15
|
+
* `{ gateway, domain, operation }` but does NOT track source-file provenance.
|
|
16
|
+
* Runtime nexus queries (`cleo nexus query`) would work but introduce an
|
|
17
|
+
* in-process dependency on the nexus subsystem (an expensive side-effectful
|
|
18
|
+
* import in the fix-gen hot path). A **static map keyed by `domain.operation`**
|
|
19
|
+
* is the cost-free alternative: it is derived once (by reading the repo's known
|
|
20
|
+
* handler layout), is small enough to inline, and carries zero import-time cost.
|
|
21
|
+
*
|
|
22
|
+
* The map covers the common `tasks` domain operations exercised by the canonical
|
|
23
|
+
* scenarios. The entry for an unregistered `opCoord` returns an empty file list
|
|
24
|
+
* (`{ handlerFiles: [], coreFiles: [] }`) — the fix-gen stage degrades gracefully
|
|
25
|
+
* to "no context" (the model still receives the regression diff and may emit
|
|
26
|
+
* `NO_PATCH`, which is the honest outcome when context is absent).
|
|
27
|
+
*
|
|
28
|
+
* ## File path convention
|
|
29
|
+
*
|
|
30
|
+
* Every path is **repo-relative** (no leading `/`). The file content loader
|
|
31
|
+
* ({@link "./fix-gen-context.js"}) resolves them against `repoContext.projectRoot`
|
|
32
|
+
* before reading.
|
|
33
|
+
*
|
|
34
|
+
* Import-time side-effect-free: no IO, no dynamic imports.
|
|
35
|
+
*
|
|
36
|
+
* @module @cleocode/core/selfimprove/op-source-map
|
|
37
|
+
* @epic T11889
|
|
38
|
+
* @task T11988
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* Resolved source files for one op-coordinate.
|
|
42
|
+
*
|
|
43
|
+
* - `handlerFiles`: the CLI dispatch handler(s) in `packages/cleo/src/dispatch/domains/`
|
|
44
|
+
* - `coreFiles`: the core-logic module(s) in `packages/core/src/` (the file most
|
|
45
|
+
* likely to contain the regression for this operation)
|
|
46
|
+
*
|
|
47
|
+
* Both lists are repo-relative. Either may be empty when not applicable.
|
|
48
|
+
*/
|
|
49
|
+
export interface OpSourceEntry {
|
|
50
|
+
/** CLI dispatch handler files (repo-relative). */
|
|
51
|
+
readonly handlerFiles: readonly string[];
|
|
52
|
+
/** Core module files that implement the operation logic (repo-relative). */
|
|
53
|
+
readonly coreFiles: readonly string[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the handler + core source files for a given op-coordinate.
|
|
57
|
+
*
|
|
58
|
+
* Returns the {@link OpSourceEntry} from the static map when the `opCoord` is
|
|
59
|
+
* registered, or {@link EMPTY_ENTRY} when it is not. NEVER throws. The returned
|
|
60
|
+
* lists contain repo-relative paths; callers resolve them against the project root
|
|
61
|
+
* before reading.
|
|
62
|
+
*
|
|
63
|
+
* @param opCoord - The op coordinate to resolve (e.g. `'tasks.show'`).
|
|
64
|
+
* @returns The resolved {@link OpSourceEntry} (may be empty for unknown ops).
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const { handlerFiles, coreFiles } = resolveOpSourceFiles('tasks.show');
|
|
69
|
+
* // handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts']
|
|
70
|
+
* // coreFiles: ['packages/core/src/tasks/show.ts']
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveOpSourceFiles(opCoord: string): OpSourceEntry;
|
|
74
|
+
/**
|
|
75
|
+
* Collect the unique set of source files for a list of op-coordinates.
|
|
76
|
+
*
|
|
77
|
+
* Deduplicates across entries so a scenario with two ops from the same handler
|
|
78
|
+
* does not include the handler twice. Returns the merged `{ handlerFiles, coreFiles }`
|
|
79
|
+
* with order preserved (first-seen wins for dedup).
|
|
80
|
+
*
|
|
81
|
+
* @param opCoords - The op-coordinate strings to collect files for.
|
|
82
|
+
* @returns The merged, deduplicated {@link OpSourceEntry}.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* const entry = collectOpSourceFiles(['tasks.find', 'tasks.show']);
|
|
87
|
+
* // entry.handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts']
|
|
88
|
+
* // entry.coreFiles: ['packages/core/src/tasks/find.ts', 'packages/core/src/tasks/show.ts']
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function collectOpSourceFiles(opCoords: readonly string[]): OpSourceEntry;
|
|
92
|
+
//# sourceMappingURL=op-source-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"op-source-map.d.ts","sourceRoot":"","sources":["../../src/selfimprove/op-source-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AA2FD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAEnE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,aAAa,CAuB/E"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static op-coordinate → source-file map for the self-improvement fix-gen stage.
|
|
3
|
+
*
|
|
4
|
+
* Given a regression's `opCoord` (the `domain.operation` string produced by
|
|
5
|
+
* {@link "../selfimprove/envelope-diff.js".DiffEntry.opCoord}, e.g. `tasks.show`),
|
|
6
|
+
* this module resolves the **repo-relative** paths of the CLI handler and the
|
|
7
|
+
* core module(s) most likely to contain the regression. The file list is fed into
|
|
8
|
+
* the fix-gen prompt builder ({@link "./fix-gen-context.js"}) so the LLM receives
|
|
9
|
+
* bounded, targeted code context rather than zero context or an unbounded repo
|
|
10
|
+
* dump.
|
|
11
|
+
*
|
|
12
|
+
* ## Design: static map, not a registry query
|
|
13
|
+
*
|
|
14
|
+
* The ops catalog (the `OPERATIONS` array in `@cleocode/contracts`) encodes
|
|
15
|
+
* `{ gateway, domain, operation }` but does NOT track source-file provenance.
|
|
16
|
+
* Runtime nexus queries (`cleo nexus query`) would work but introduce an
|
|
17
|
+
* in-process dependency on the nexus subsystem (an expensive side-effectful
|
|
18
|
+
* import in the fix-gen hot path). A **static map keyed by `domain.operation`**
|
|
19
|
+
* is the cost-free alternative: it is derived once (by reading the repo's known
|
|
20
|
+
* handler layout), is small enough to inline, and carries zero import-time cost.
|
|
21
|
+
*
|
|
22
|
+
* The map covers the common `tasks` domain operations exercised by the canonical
|
|
23
|
+
* scenarios. The entry for an unregistered `opCoord` returns an empty file list
|
|
24
|
+
* (`{ handlerFiles: [], coreFiles: [] }`) — the fix-gen stage degrades gracefully
|
|
25
|
+
* to "no context" (the model still receives the regression diff and may emit
|
|
26
|
+
* `NO_PATCH`, which is the honest outcome when context is absent).
|
|
27
|
+
*
|
|
28
|
+
* ## File path convention
|
|
29
|
+
*
|
|
30
|
+
* Every path is **repo-relative** (no leading `/`). The file content loader
|
|
31
|
+
* ({@link "./fix-gen-context.js"}) resolves them against `repoContext.projectRoot`
|
|
32
|
+
* before reading.
|
|
33
|
+
*
|
|
34
|
+
* Import-time side-effect-free: no IO, no dynamic imports.
|
|
35
|
+
*
|
|
36
|
+
* @module @cleocode/core/selfimprove/op-source-map
|
|
37
|
+
* @epic T11889
|
|
38
|
+
* @task T11988
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* The static `opCoord → source files` map.
|
|
42
|
+
*
|
|
43
|
+
* Keys are `domain.operation` strings (lowercase, e.g. `'tasks.show'`). Values
|
|
44
|
+
* are {@link OpSourceEntry} objects with repo-relative paths.
|
|
45
|
+
*
|
|
46
|
+
* Coverage: the `tasks` domain operations exercised by the built-in scenarios
|
|
47
|
+
* (T11988: `seeded-code-regression`) plus the pre-existing `dhq-replay-find`
|
|
48
|
+
* scenario (`tasks.find`, `tasks.show`).
|
|
49
|
+
*
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
52
|
+
const OP_SOURCE_MAP = {
|
|
53
|
+
'tasks.show': {
|
|
54
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
55
|
+
coreFiles: ['packages/core/src/tasks/show.ts'],
|
|
56
|
+
},
|
|
57
|
+
'tasks.find': {
|
|
58
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
59
|
+
coreFiles: ['packages/core/src/tasks/find.ts'],
|
|
60
|
+
},
|
|
61
|
+
'tasks.list': {
|
|
62
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
63
|
+
coreFiles: ['packages/core/src/tasks/list.ts'],
|
|
64
|
+
},
|
|
65
|
+
'tasks.add': {
|
|
66
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
67
|
+
coreFiles: ['packages/core/src/tasks/add.ts'],
|
|
68
|
+
},
|
|
69
|
+
'tasks.update': {
|
|
70
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
71
|
+
coreFiles: ['packages/core/src/tasks/update.ts'],
|
|
72
|
+
},
|
|
73
|
+
'tasks.complete': {
|
|
74
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
75
|
+
coreFiles: ['packages/core/src/tasks/complete.ts'],
|
|
76
|
+
},
|
|
77
|
+
'tasks.delete': {
|
|
78
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
79
|
+
coreFiles: ['packages/core/src/tasks/delete.ts'],
|
|
80
|
+
},
|
|
81
|
+
'tasks.next': {
|
|
82
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
83
|
+
coreFiles: ['packages/core/src/tasks/next.ts'],
|
|
84
|
+
},
|
|
85
|
+
'tasks.current': {
|
|
86
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
87
|
+
coreFiles: ['packages/core/src/tasks/current.ts'],
|
|
88
|
+
},
|
|
89
|
+
'tasks.tree': {
|
|
90
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
91
|
+
coreFiles: ['packages/core/src/tasks/generic-tree.ts'],
|
|
92
|
+
},
|
|
93
|
+
'tasks.analyze': {
|
|
94
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts'],
|
|
95
|
+
coreFiles: ['packages/core/src/tasks/analyze.ts'],
|
|
96
|
+
},
|
|
97
|
+
'memory.find': {
|
|
98
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/memory.ts'],
|
|
99
|
+
coreFiles: [],
|
|
100
|
+
},
|
|
101
|
+
'memory.fetch': {
|
|
102
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/memory.ts'],
|
|
103
|
+
coreFiles: [],
|
|
104
|
+
},
|
|
105
|
+
'selfimprove.run': {
|
|
106
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/selfimprove.ts'],
|
|
107
|
+
coreFiles: ['packages/core/src/selfimprove/run-loop.ts'],
|
|
108
|
+
},
|
|
109
|
+
/**
|
|
110
|
+
* `selfimprove.probe` — the seeded-code-regression scenario target (T11988).
|
|
111
|
+
* The probe-helper is intentionally broken (`probeVersion()` returns `2`
|
|
112
|
+
* instead of `1`); the fix is a single-line change in this file.
|
|
113
|
+
*/
|
|
114
|
+
'selfimprove.probe': {
|
|
115
|
+
handlerFiles: ['packages/cleo/src/dispatch/domains/selfimprove.ts'],
|
|
116
|
+
coreFiles: ['packages/core/src/selfimprove/probe-helper.ts'],
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* An empty source entry returned for unknown or unmapped op-coordinates.
|
|
121
|
+
*
|
|
122
|
+
* The fix-gen stage treats an empty file list as "no context available" and
|
|
123
|
+
* degrades the prompt to the regression-only view. The model may still produce
|
|
124
|
+
* a patch (or `NO_PATCH`) without file context.
|
|
125
|
+
*/
|
|
126
|
+
const EMPTY_ENTRY = { handlerFiles: [], coreFiles: [] };
|
|
127
|
+
/**
|
|
128
|
+
* Resolve the handler + core source files for a given op-coordinate.
|
|
129
|
+
*
|
|
130
|
+
* Returns the {@link OpSourceEntry} from the static map when the `opCoord` is
|
|
131
|
+
* registered, or {@link EMPTY_ENTRY} when it is not. NEVER throws. The returned
|
|
132
|
+
* lists contain repo-relative paths; callers resolve them against the project root
|
|
133
|
+
* before reading.
|
|
134
|
+
*
|
|
135
|
+
* @param opCoord - The op coordinate to resolve (e.g. `'tasks.show'`).
|
|
136
|
+
* @returns The resolved {@link OpSourceEntry} (may be empty for unknown ops).
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* const { handlerFiles, coreFiles } = resolveOpSourceFiles('tasks.show');
|
|
141
|
+
* // handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts']
|
|
142
|
+
* // coreFiles: ['packages/core/src/tasks/show.ts']
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
export function resolveOpSourceFiles(opCoord) {
|
|
146
|
+
return OP_SOURCE_MAP[opCoord] ?? EMPTY_ENTRY;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Collect the unique set of source files for a list of op-coordinates.
|
|
150
|
+
*
|
|
151
|
+
* Deduplicates across entries so a scenario with two ops from the same handler
|
|
152
|
+
* does not include the handler twice. Returns the merged `{ handlerFiles, coreFiles }`
|
|
153
|
+
* with order preserved (first-seen wins for dedup).
|
|
154
|
+
*
|
|
155
|
+
* @param opCoords - The op-coordinate strings to collect files for.
|
|
156
|
+
* @returns The merged, deduplicated {@link OpSourceEntry}.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* const entry = collectOpSourceFiles(['tasks.find', 'tasks.show']);
|
|
161
|
+
* // entry.handlerFiles: ['packages/cleo/src/dispatch/domains/tasks.ts']
|
|
162
|
+
* // entry.coreFiles: ['packages/core/src/tasks/find.ts', 'packages/core/src/tasks/show.ts']
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export function collectOpSourceFiles(opCoords) {
|
|
166
|
+
const seenHandler = new Set();
|
|
167
|
+
const seenCore = new Set();
|
|
168
|
+
const handlerFiles = [];
|
|
169
|
+
const coreFiles = [];
|
|
170
|
+
for (const coord of opCoords) {
|
|
171
|
+
const entry = resolveOpSourceFiles(coord);
|
|
172
|
+
for (const f of entry.handlerFiles) {
|
|
173
|
+
if (!seenHandler.has(f)) {
|
|
174
|
+
seenHandler.add(f);
|
|
175
|
+
handlerFiles.push(f);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
for (const f of entry.coreFiles) {
|
|
179
|
+
if (!seenCore.has(f)) {
|
|
180
|
+
seenCore.add(f);
|
|
181
|
+
coreFiles.push(f);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return { handlerFiles, coreFiles };
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=op-source-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"op-source-map.js","sourceRoot":"","sources":["../../src/selfimprove/op-source-map.ts"],"names":[],"mappings":"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"}
|