@mjasnikovs/pi-task 0.14.8 → 0.14.9
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/task/phases.js
CHANGED
|
@@ -6,7 +6,7 @@ import { docsFocused } from '../workers/docs-core.js';
|
|
|
6
6
|
import { fetchFocused } from '../workers/fetch-core.js';
|
|
7
7
|
import { formatNpmVersionSection } from '../workers/npm-version.js';
|
|
8
8
|
import { runWorker } from '../workers/pi-worker-core.js';
|
|
9
|
-
import { findPhantomImports, formatApiCorrections } from '../workers/phantom-imports.js';
|
|
9
|
+
import { findPhantomImports, formatApiCorrections, rewritePhantomSpecifiers } from '../workers/phantom-imports.js';
|
|
10
10
|
import { search as defaultSearch } from '../workers/search-core.js';
|
|
11
11
|
import { extractEnrichTargets } from './enrichment.js';
|
|
12
12
|
import { getFileInventory } from './file-inventory.js';
|
|
@@ -651,7 +651,21 @@ export const PHASES = [
|
|
|
651
651
|
name: 'refine',
|
|
652
652
|
section: 'refined prompt',
|
|
653
653
|
field: 'refined',
|
|
654
|
-
run: (d, p) =>
|
|
654
|
+
run: async (d, p) => {
|
|
655
|
+
const refined = await phaseRefine(d, p.rawPrompt, p.planContext);
|
|
656
|
+
// Subtractively strike any phantom runtime specifier (`bun:sql`) the
|
|
657
|
+
// refine carried up verbatim from the spec doc, BEFORE it flows to
|
|
658
|
+
// research/grill/compose. An appended correction alone loses: the
|
|
659
|
+
// affirmative survives into the composed GOAL and on to the implementer
|
|
660
|
+
// (proven: compose re-leaks it 4/4). Rewriting the source so compose has
|
|
661
|
+
// nothing to contradict is the fix. Silent + no-op when nothing is wrong
|
|
662
|
+
// or the runtime's types aren't installed.
|
|
663
|
+
const phantoms = findPhantomImports(refined, d.cwd);
|
|
664
|
+
if (phantoms.length === 0)
|
|
665
|
+
return refined;
|
|
666
|
+
d.logDebug?.(`phantom specifiers rewritten in refined: ${phantoms.map(x => x.spec).join(', ')}`);
|
|
667
|
+
return rewritePhantomSpecifiers(refined, phantoms);
|
|
668
|
+
}
|
|
655
669
|
},
|
|
656
670
|
{
|
|
657
671
|
name: 'research',
|
|
@@ -5,6 +5,9 @@ export interface PhantomImport {
|
|
|
5
5
|
realModules: string[];
|
|
6
6
|
/** Corrective guidance to inject into the spec. */
|
|
7
7
|
suggestion: string;
|
|
8
|
+
/** Base-module symbol the submodule leaf maps to (`bun:sql` → `SQL`), or null
|
|
9
|
+
* when the types declare no matching symbol. Drives the canonical-import rewrite. */
|
|
10
|
+
baseSymbol: string | null;
|
|
8
11
|
}
|
|
9
12
|
/** Every distinct runtime-namespace specifier mentioned in the text, in first-seen order. */
|
|
10
13
|
export declare function extractRuntimeSpecifiers(text: string): string[];
|
|
@@ -33,3 +36,19 @@ export declare function loadRuntimeTypeText(runtime: string, cwd: string): strin
|
|
|
33
36
|
export declare function findPhantomImports(text: string, cwd: string, loadText?: (runtime: string, cwd: string) => string | null): PhantomImport[];
|
|
34
37
|
/** Render flagged phantoms as an authoritative research section, or '' if none. */
|
|
35
38
|
export declare function formatApiCorrections(phantoms: PhantomImport[]): string;
|
|
39
|
+
/**
|
|
40
|
+
* Subtractively rewrite every flagged phantom specifier in `text` to the canonical
|
|
41
|
+
* import the installed types prove, so NO affirmative occurrence of the non-existent
|
|
42
|
+
* specifier survives downstream. This is the half an appended correction can't do:
|
|
43
|
+
* REFINE preserves identifiers verbatim, so `bun:sql` otherwise rides into the
|
|
44
|
+
* composed GOAL (proven: compose re-leaks it 4/4) and on to the implementer. Strike
|
|
45
|
+
* it at the source and compose has nothing to contradict.
|
|
46
|
+
*
|
|
47
|
+
* Deterministic, no LLM. Idempotent on healthy input: once a specifier is replaced
|
|
48
|
+
* the literal is gone, so a second pass is a no-op (the only residue is a `declare
|
|
49
|
+
* module` comment that quotes the spec inside a slash-star, which the bare-word rule
|
|
50
|
+
* skips via its lookbehind). Handles the four forms a phantom takes: an import/require
|
|
51
|
+
* `from "<spec>"`, a fabricated `declare module "<spec>"`, a backticked prose mention
|
|
52
|
+
* `` `<spec>` ``, and a bare word `<spec>`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function rewritePhantomSpecifiers(text: string, phantoms: PhantomImport[]): string;
|
|
@@ -173,7 +173,8 @@ export function findPhantomImports(text, cwd, loadText = loadRuntimeTypeText) {
|
|
|
173
173
|
out.push({
|
|
174
174
|
spec,
|
|
175
175
|
realModules: verdict.realModules,
|
|
176
|
-
suggestion: suggestionFor(verdict, ns.runtime)
|
|
176
|
+
suggestion: suggestionFor(verdict, ns.runtime),
|
|
177
|
+
baseSymbol: verdict.baseSymbol
|
|
177
178
|
});
|
|
178
179
|
}
|
|
179
180
|
return out;
|
|
@@ -185,3 +186,43 @@ export function formatApiCorrections(phantoms) {
|
|
|
185
186
|
const lines = phantoms.map(p => ` - ${p.suggestion}`);
|
|
186
187
|
return `API CORRECTIONS\n${lines.join('\n')}`;
|
|
187
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Subtractively rewrite every flagged phantom specifier in `text` to the canonical
|
|
191
|
+
* import the installed types prove, so NO affirmative occurrence of the non-existent
|
|
192
|
+
* specifier survives downstream. This is the half an appended correction can't do:
|
|
193
|
+
* REFINE preserves identifiers verbatim, so `bun:sql` otherwise rides into the
|
|
194
|
+
* composed GOAL (proven: compose re-leaks it 4/4) and on to the implementer. Strike
|
|
195
|
+
* it at the source and compose has nothing to contradict.
|
|
196
|
+
*
|
|
197
|
+
* Deterministic, no LLM. Idempotent on healthy input: once a specifier is replaced
|
|
198
|
+
* the literal is gone, so a second pass is a no-op (the only residue is a `declare
|
|
199
|
+
* module` comment that quotes the spec inside a slash-star, which the bare-word rule
|
|
200
|
+
* skips via its lookbehind). Handles the four forms a phantom takes: an import/require
|
|
201
|
+
* `from "<spec>"`, a fabricated `declare module "<spec>"`, a backticked prose mention
|
|
202
|
+
* `` `<spec>` ``, and a bare word `<spec>`.
|
|
203
|
+
*/
|
|
204
|
+
export function rewritePhantomSpecifiers(text, phantoms) {
|
|
205
|
+
let out = text;
|
|
206
|
+
for (const p of phantoms) {
|
|
207
|
+
const ns = splitRuntimeNamespace(p.spec);
|
|
208
|
+
if (!ns)
|
|
209
|
+
continue;
|
|
210
|
+
const runtime = ns.runtime;
|
|
211
|
+
const canonical = p.baseSymbol ?
|
|
212
|
+
`import { ${p.baseSymbol} } from "${runtime}"`
|
|
213
|
+
: `the "${runtime}" module`;
|
|
214
|
+
const spec = escapeRe(p.spec);
|
|
215
|
+
out = out
|
|
216
|
+
// `from "bun:sql"` / `require("bun:sql")` → point at the base runtime module
|
|
217
|
+
.replace(new RegExp(`((?:from\\s+|require\\(\\s*)["'])${spec}(["'])`, 'g'), `$1${runtime}$2`)
|
|
218
|
+
// a fabricated `declare module "bun:sql"` → a comment naming the real import.
|
|
219
|
+
// Deliberately does NOT echo the spec literal, so the bare-word pass below
|
|
220
|
+
// can't re-corrupt this comment (keeps the rewrite idempotent).
|
|
221
|
+
.replace(new RegExp(`declare\\s+module\\s+["']${spec}["']`, 'g'), `/* not a module — use ${canonical} */`)
|
|
222
|
+
// backticked prose mention → the canonical import
|
|
223
|
+
.replace(new RegExp('`' + spec + '`', 'g'), '`' + canonical + '`')
|
|
224
|
+
// bare word, not already inside quotes/backticks/a path or our own comment
|
|
225
|
+
.replace(new RegExp(`(?<![\`"'/])\\b${spec}\\b(?![\`"'])`, 'g'), canonical);
|
|
226
|
+
}
|
|
227
|
+
return out;
|
|
228
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.9",
|
|
4
4
|
"description": "Deterministic spec-orchestration for local models, with a bundled real-time remote web view and web/docs/fetch/worker subagent tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|