@mjasnikovs/pi-task 0.17.7 → 0.17.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/shared/child-process.d.ts +9 -1
- package/dist/shared/child-process.js +12 -1
- package/dist/shared/fs-text.d.ts +18 -0
- package/dist/shared/fs-text.js +23 -0
- package/dist/shared/pi-invocation.d.ts +8 -2
- package/dist/shared/pi-invocation.js +11 -6
- package/dist/task/auto-io.js +2 -1
- package/dist/task/auto-orchestrator.js +4 -1
- package/dist/task/child-runner.d.ts +1 -1
- package/dist/task/child-runner.js +7 -3
- package/dist/task/orchestrator.js +3 -2
- package/dist/task/task-io.js +6 -2
- package/dist/task/task-parsers.js +9 -3
- package/dist/workers/docs-core.js +1 -1
- package/dist/workers/fetch-core.js +1 -1
- package/dist/workers/pi-worker-core.js +1 -1
- package/dist/workers/pi-worker-docs.js +2 -2
- package/package.json +1 -1
|
@@ -3,7 +3,14 @@ import type { EventEmitter } from 'node:events';
|
|
|
3
3
|
export declare const KILL_GRACE_MS = 5000;
|
|
4
4
|
/** Base flags shared by all child pi invocations. */
|
|
5
5
|
export declare const CHILD_BASE_ARGS: readonly ["--print", "--no-skills", "--no-extensions", "--no-prompt-templates", "--no-context-files", "--no-session"];
|
|
6
|
+
/** The subset of a child's stdin we use: write the prompt, then close it. */
|
|
7
|
+
export interface WritableLike {
|
|
8
|
+
write(chunk: string): boolean;
|
|
9
|
+
end(): void;
|
|
10
|
+
}
|
|
6
11
|
export interface ProcLike extends EventEmitter {
|
|
12
|
+
/** Present only when the child was spawned with stdin 'pipe' (prompt delivery). */
|
|
13
|
+
stdin: WritableLike | null;
|
|
7
14
|
stdout: EventEmitter | null;
|
|
8
15
|
stderr: EventEmitter | null;
|
|
9
16
|
killed: boolean;
|
|
@@ -12,7 +19,7 @@ export interface ProcLike extends EventEmitter {
|
|
|
12
19
|
export type SpawnFn = (command: string, args: ReadonlyArray<string>, options: {
|
|
13
20
|
cwd: string;
|
|
14
21
|
shell: boolean;
|
|
15
|
-
stdio: ['ignore', 'pipe', 'pipe'];
|
|
22
|
+
stdio: ['ignore' | 'pipe', 'pipe', 'pipe'];
|
|
16
23
|
}) => ProcLike;
|
|
17
24
|
export interface ChildResult {
|
|
18
25
|
stdout: string;
|
|
@@ -105,6 +112,7 @@ export declare class JsonEventSink {
|
|
|
105
112
|
export declare function runChild(spawn: SpawnFn, invocation: {
|
|
106
113
|
command: string;
|
|
107
114
|
args: ReadonlyArray<string>;
|
|
115
|
+
stdin?: string;
|
|
108
116
|
}, cwd: string, signal: AbortSignal | undefined, opts?: RunChildOptions): Promise<ChildResult>;
|
|
109
117
|
export declare function runChildDefault(invocation: {
|
|
110
118
|
command: string;
|
|
@@ -169,11 +169,22 @@ export function runChild(spawn, invocation, cwd, signal, opts) {
|
|
|
169
169
|
let stderr = '';
|
|
170
170
|
let aborted = false;
|
|
171
171
|
const discardStdout = opts?.mode === 'text' && opts.discardStdout === true;
|
|
172
|
+
// Deliver the prompt on stdin, not argv: a large prompt (e.g. an inlined
|
|
173
|
+
// design doc) blows past the OS command-line limit — Windows CreateProcessW
|
|
174
|
+
// caps it at 32767 chars and Node throws `spawn ENAMETOOLONG`. When a
|
|
175
|
+
// prompt is present we open stdin as a pipe; otherwise keep it 'ignore'
|
|
176
|
+
// (git and other arg-only spawns are unaffected). See GitHub issue #1.
|
|
177
|
+
const usesStdin = invocation.stdin !== undefined;
|
|
172
178
|
const proc = spawn(invocation.command, invocation.args, {
|
|
173
179
|
cwd,
|
|
174
180
|
shell: false,
|
|
175
|
-
stdio: ['ignore', 'pipe', 'pipe']
|
|
181
|
+
stdio: [usesStdin ? 'pipe' : 'ignore', 'pipe', 'pipe']
|
|
176
182
|
});
|
|
183
|
+
if (usesStdin) {
|
|
184
|
+
// pi reads the prompt from stdin and waits for EOF, so write then end.
|
|
185
|
+
proc.stdin?.write(invocation.stdin);
|
|
186
|
+
proc.stdin?.end();
|
|
187
|
+
}
|
|
177
188
|
// One kill path, shared by user-abort and loop-kill: SIGTERM, then
|
|
178
189
|
// SIGKILL after a grace period if the child ignored the term.
|
|
179
190
|
const killProc = () => {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-file reads with line endings normalized to LF.
|
|
3
|
+
*
|
|
4
|
+
* Every task-file parser in pi-task assumes `\n` line endings: the front-matter
|
|
5
|
+
* regex (`^---\n`), the body-delimiter strip, `sectionRegex` (`## h[ \t]*\n`),
|
|
6
|
+
* the checkbox/VERIFY-token line splits. On Windows a task file can carry CRLF
|
|
7
|
+
* (an editor save, or a `git` checkout with `core.autocrlf=true`), and classic
|
|
8
|
+
* Mac tooling can emit lone CR. Any of those makes `parseFrontMatter` return
|
|
9
|
+
* null ("malformed front matter") and every `extractSection` miss.
|
|
10
|
+
*
|
|
11
|
+
* Rather than teach each parser about `\r`, we normalize ONCE at the read
|
|
12
|
+
* boundary — the single place file bytes enter the task layer — so everything
|
|
13
|
+
* downstream sees LF. See GitHub issue #1.
|
|
14
|
+
*/
|
|
15
|
+
/** Collapse CRLF and lone CR to LF. `\r\n?` matches Windows CRLF and classic-Mac CR. */
|
|
16
|
+
export declare function normalizeNewlines(text: string): string;
|
|
17
|
+
/** Read a UTF-8 text file with line endings normalized to LF. */
|
|
18
|
+
export declare function readTextFile(filePath: string): Promise<string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-file reads with line endings normalized to LF.
|
|
3
|
+
*
|
|
4
|
+
* Every task-file parser in pi-task assumes `\n` line endings: the front-matter
|
|
5
|
+
* regex (`^---\n`), the body-delimiter strip, `sectionRegex` (`## h[ \t]*\n`),
|
|
6
|
+
* the checkbox/VERIFY-token line splits. On Windows a task file can carry CRLF
|
|
7
|
+
* (an editor save, or a `git` checkout with `core.autocrlf=true`), and classic
|
|
8
|
+
* Mac tooling can emit lone CR. Any of those makes `parseFrontMatter` return
|
|
9
|
+
* null ("malformed front matter") and every `extractSection` miss.
|
|
10
|
+
*
|
|
11
|
+
* Rather than teach each parser about `\r`, we normalize ONCE at the read
|
|
12
|
+
* boundary — the single place file bytes enter the task layer — so everything
|
|
13
|
+
* downstream sees LF. See GitHub issue #1.
|
|
14
|
+
*/
|
|
15
|
+
import * as fsp from 'node:fs/promises';
|
|
16
|
+
/** Collapse CRLF and lone CR to LF. `\r\n?` matches Windows CRLF and classic-Mac CR. */
|
|
17
|
+
export function normalizeNewlines(text) {
|
|
18
|
+
return text.replace(/\r\n?/g, '\n');
|
|
19
|
+
}
|
|
20
|
+
/** Read a UTF-8 text file with line endings normalized to LF. */
|
|
21
|
+
export async function readTextFile(filePath) {
|
|
22
|
+
return normalizeNewlines(await fsp.readFile(filePath, 'utf8'));
|
|
23
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
/** Pick the right way to re-invoke pi: prefer the current pi script under the
|
|
2
2
|
* current node/bun runtime; fall back to the `pi` shim on PATH. Mirrors the
|
|
3
|
-
* pattern from pi-coding-agent's official subagent example.
|
|
4
|
-
|
|
3
|
+
* pattern from pi-coding-agent's official subagent example.
|
|
4
|
+
*
|
|
5
|
+
* `stdin`, when given, is the prompt to feed the child over stdin instead of as
|
|
6
|
+
* an argv element — pi reads its prompt from stdin when no positional message
|
|
7
|
+
* is passed, which keeps a large prompt off the length-limited command line
|
|
8
|
+
* (see runChild / GitHub issue #1). It is threaded through unchanged. */
|
|
9
|
+
export declare function getPiInvocation(args: string[], stdin?: string): {
|
|
5
10
|
command: string;
|
|
6
11
|
args: string[];
|
|
12
|
+
stdin?: string;
|
|
7
13
|
};
|
|
@@ -2,23 +2,28 @@ import * as fs from 'node:fs';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
/** Pick the right way to re-invoke pi: prefer the current pi script under the
|
|
4
4
|
* current node/bun runtime; fall back to the `pi` shim on PATH. Mirrors the
|
|
5
|
-
* pattern from pi-coding-agent's official subagent example.
|
|
6
|
-
|
|
5
|
+
* pattern from pi-coding-agent's official subagent example.
|
|
6
|
+
*
|
|
7
|
+
* `stdin`, when given, is the prompt to feed the child over stdin instead of as
|
|
8
|
+
* an argv element — pi reads its prompt from stdin when no positional message
|
|
9
|
+
* is passed, which keeps a large prompt off the length-limited command line
|
|
10
|
+
* (see runChild / GitHub issue #1). It is threaded through unchanged. */
|
|
11
|
+
export function getPiInvocation(args, stdin) {
|
|
7
12
|
// Test/dev override: point at a specific pi binary directly. Bypasses the
|
|
8
13
|
// re-invoke-current-script heuristic, which goes wrong under `bun test`
|
|
9
14
|
// (currentScript is the .test.ts file, not a pi entrypoint).
|
|
10
15
|
if (process.env.PI_BIN) {
|
|
11
|
-
return { command: process.env.PI_BIN, args };
|
|
16
|
+
return { command: process.env.PI_BIN, args, stdin };
|
|
12
17
|
}
|
|
13
18
|
const currentScript = process.argv[1];
|
|
14
19
|
const isBunVirtualScript = currentScript?.startsWith('/$bunfs/root/');
|
|
15
20
|
if (currentScript && !isBunVirtualScript && fs.existsSync(currentScript)) {
|
|
16
|
-
return { command: process.execPath, args: [currentScript, ...args] };
|
|
21
|
+
return { command: process.execPath, args: [currentScript, ...args], stdin };
|
|
17
22
|
}
|
|
18
23
|
const execName = path.basename(process.execPath).toLowerCase();
|
|
19
24
|
const isGenericRuntime = /^(node|bun)(\.exe)?$/.test(execName);
|
|
20
25
|
if (!isGenericRuntime) {
|
|
21
|
-
return { command: process.execPath, args };
|
|
26
|
+
return { command: process.execPath, args, stdin };
|
|
22
27
|
}
|
|
23
|
-
return { command: 'pi', args };
|
|
28
|
+
return { command: 'pi', args, stdin };
|
|
24
29
|
}
|
package/dist/task/auto-io.js
CHANGED
|
@@ -9,6 +9,7 @@ import * as fsp from 'node:fs/promises';
|
|
|
9
9
|
import * as path from 'node:path';
|
|
10
10
|
import { tasksDir, ensureTasksDir, readTaskFile, setTaskSection } from './task-io.js';
|
|
11
11
|
import { extractSection, parseFrontMatter } from './task-parsers.js';
|
|
12
|
+
import { readTextFile } from '../shared/fs-text.js';
|
|
12
13
|
import { RESUMABLE_STATES } from './task-types.js';
|
|
13
14
|
const AUTO_FILE_RE = /^(TASK_AUTO_\d{4,})\.md$/;
|
|
14
15
|
const MAX_TASKS = 30;
|
|
@@ -117,7 +118,7 @@ export async function findResumableAuto(cwd) {
|
|
|
117
118
|
if (!m)
|
|
118
119
|
continue;
|
|
119
120
|
try {
|
|
120
|
-
const raw = await
|
|
121
|
+
const raw = await readTextFile(path.join(tasksDir(cwd), f));
|
|
121
122
|
const fm = parseFrontMatter(raw);
|
|
122
123
|
if (!fm)
|
|
123
124
|
continue;
|
|
@@ -15,6 +15,7 @@ import { GRILL_AUTO_ANSWER_PROMPT, GRILL_AUTO_FORMAT_HINT } from './prompts.js';
|
|
|
15
15
|
import { isDuplicateQuestion, MAX_DUP_STRIKES, DUP_REPROMPT_HINT } from './question-dedup.js';
|
|
16
16
|
import { allocateAutoId, buildAutoBody, parseDecomposeList, parseTaskList, checkOffTask, stampTaskInProgress, findResumableAuto } from './auto-io.js';
|
|
17
17
|
import { writeTaskFile, readTaskFile, updateTaskFrontMatter, taskFilePath, tasksDir } from './task-io.js';
|
|
18
|
+
import { readTextFile } from '../shared/fs-text.js';
|
|
18
19
|
import { findPhantomImports, rewritePhantomSpecifiers } from '../workers/phantom-imports.js';
|
|
19
20
|
import { runPhaseChild, prependHint, USER_CANCELLED } from './child-runner.js';
|
|
20
21
|
import { refineExistingFilesBlock } from './phases.js';
|
|
@@ -134,7 +135,9 @@ export async function expandFeatureMentions(cwd, feature) {
|
|
|
134
135
|
continue;
|
|
135
136
|
seen.add(rel);
|
|
136
137
|
try {
|
|
137
|
-
|
|
138
|
+
// Normalize CRLF/CR so an @-mentioned design doc saved on Windows
|
|
139
|
+
// inlines with LF endings the downstream phase parsers expect.
|
|
140
|
+
const body = await readTextFile(path.resolve(cwd, rel));
|
|
138
141
|
if (body.trim().length > 0) {
|
|
139
142
|
blocks.push(`--- contents of ${rel} ---\n${body.trim()}`);
|
|
140
143
|
}
|
|
@@ -23,7 +23,7 @@ export interface PhaseRunResult {
|
|
|
23
23
|
/** Set when the child's final turn failed with stopReason "error" (model/provider failure). */
|
|
24
24
|
modelError?: string;
|
|
25
25
|
}
|
|
26
|
-
export declare function childArgs(tools: string
|
|
26
|
+
export declare function childArgs(tools: string): string[];
|
|
27
27
|
export declare const USER_CANCELLED = "__user_cancelled__";
|
|
28
28
|
/**
|
|
29
29
|
* Run a child pi process with JSON event-stream output, loop detection, and
|
|
@@ -44,7 +44,7 @@ export function connectionRetryBackoffMs(attempt) {
|
|
|
44
44
|
}
|
|
45
45
|
const defaultSleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
46
46
|
// ─── Spawn helpers ───────────────────────────────────────────────────────────
|
|
47
|
-
export function childArgs(tools
|
|
47
|
+
export function childArgs(tools) {
|
|
48
48
|
// `--mode json` puts the child into the structured event stream the
|
|
49
49
|
// unified runner parses in `mode: 'json-events'`. Without it the child
|
|
50
50
|
// emits plain text, every line fails JSON.parse, finalText stays empty,
|
|
@@ -55,8 +55,12 @@ export function childArgs(tools, prompt) {
|
|
|
55
55
|
// instead of `--tools ''` (which pi would reject). Used by pure-judgment
|
|
56
56
|
// phases like critique-triage that should reason only over the text we
|
|
57
57
|
// hand them, never spend time reading the repo.
|
|
58
|
+
//
|
|
59
|
+
// The prompt is NOT an argv element: it goes to the child over stdin (see
|
|
60
|
+
// runChild below / getPiInvocation), so a large inlined-design prompt can't
|
|
61
|
+
// overflow the OS command-line limit (Windows `spawn ENAMETOOLONG`).
|
|
58
62
|
const toolFlags = tools === '' ? ['--no-tools'] : ['--tools', tools];
|
|
59
|
-
return [...CHILD_BASE_ARGS, '--mode', 'json', ...toolFlags
|
|
63
|
+
return [...CHILD_BASE_ARGS, '--mode', 'json', ...toolFlags];
|
|
60
64
|
}
|
|
61
65
|
// Sentinel error thrown when the user dismisses a grill-me dialog.
|
|
62
66
|
// Defined here (not in failure-classifier.ts) to avoid circular dependency.
|
|
@@ -68,7 +72,7 @@ export const USER_CANCELLED = '__user_cancelled__';
|
|
|
68
72
|
* phase-level code.
|
|
69
73
|
*/
|
|
70
74
|
export async function runChild(cwd, tools, prompt, signal, onLine, onContextUsage, onToolCall, spawnFn) {
|
|
71
|
-
const invocation = getPiInvocation(childArgs(tools, prompt)
|
|
75
|
+
const invocation = getPiInvocation(childArgs(tools), prompt);
|
|
72
76
|
let loopHit;
|
|
73
77
|
const result = await runChildUnified(spawnFn ?? spawn, invocation, cwd, signal, {
|
|
74
78
|
mode: 'json-events',
|
|
@@ -21,6 +21,7 @@ import { PHASES, postCommitPhase } from './phases.js';
|
|
|
21
21
|
import { handleFailure } from './failure-classifier.js';
|
|
22
22
|
import { PHASE_INDEX, PHASE_ORDER, RESUMABLE_STATES } from './task-types.js';
|
|
23
23
|
import { normaliseTaskId, parseFrontMatter, extractSection } from './task-parsers.js';
|
|
24
|
+
import { readTextFile } from '../shared/fs-text.js';
|
|
24
25
|
import { allocateTaskId, ensureTasksDir, readSection, readTaskFile, setTaskSection, taskFilePath, tasksDir, updateTaskFrontMatter, writeTaskFile } from './task-io.js';
|
|
25
26
|
import { startWidget } from './widget.js';
|
|
26
27
|
import { armImplWidget, disarmImplWidget, setupImplWidget } from './impl-widget.js';
|
|
@@ -705,7 +706,7 @@ async function handleTaskList(_args, ctx) {
|
|
|
705
706
|
const rows = [];
|
|
706
707
|
for (const f of taskFiles) {
|
|
707
708
|
try {
|
|
708
|
-
const raw = await
|
|
709
|
+
const raw = await readTextFile(path.join(tasksDir(cwd), f));
|
|
709
710
|
const fm = parseFrontMatter(raw);
|
|
710
711
|
if (!fm)
|
|
711
712
|
continue;
|
|
@@ -754,7 +755,7 @@ async function handleTaskResume(args, ctx) {
|
|
|
754
755
|
if (!m)
|
|
755
756
|
continue;
|
|
756
757
|
try {
|
|
757
|
-
const raw = await
|
|
758
|
+
const raw = await readTextFile(path.join(tasksDir(cwd), f));
|
|
758
759
|
const fm = parseFrontMatter(raw);
|
|
759
760
|
if (!fm)
|
|
760
761
|
continue;
|
package/dist/task/task-io.js
CHANGED
|
@@ -8,6 +8,7 @@ import * as fsp from 'node:fs/promises';
|
|
|
8
8
|
import * as path from 'node:path';
|
|
9
9
|
import { TASKS_DIR_NAME } from './task-types.js';
|
|
10
10
|
import { emitFrontMatter, parseFrontMatter, sectionRegex } from './task-parsers.js';
|
|
11
|
+
import { readTextFile } from '../shared/fs-text.js';
|
|
11
12
|
// ─── Directory & path helpers ────────────────────────────────────────────────
|
|
12
13
|
export function tasksDir(cwd) {
|
|
13
14
|
return path.join(cwd, TASKS_DIR_NAME);
|
|
@@ -58,11 +59,14 @@ export async function allocateTaskId(cwd) {
|
|
|
58
59
|
}
|
|
59
60
|
// ─── File read/write ─────────────────────────────────────────────────────────
|
|
60
61
|
export async function readTaskFile(cwd, id) {
|
|
61
|
-
|
|
62
|
+
// Normalize CRLF/CR → LF at the read boundary: every parser below (front
|
|
63
|
+
// matter, body strip, sectionRegex) assumes '\n'. A Windows/autocrlf file
|
|
64
|
+
// would otherwise fail as "malformed front matter". See shared/fs-text.ts.
|
|
65
|
+
const raw = await readTextFile(taskFilePath(cwd, id));
|
|
62
66
|
const fm = parseFrontMatter(raw);
|
|
63
67
|
if (!fm)
|
|
64
68
|
throw new Error(`malformed front matter in ${id}.md`);
|
|
65
|
-
const body = raw.replace(/^---\n[\s\S]*?\n---\n?/, '');
|
|
69
|
+
const body = raw.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '');
|
|
66
70
|
return { frontMatter: fm, body };
|
|
67
71
|
}
|
|
68
72
|
export async function writeTaskFile(cwd, fm, body) {
|
|
@@ -32,11 +32,15 @@ export function emitFrontMatter(fm) {
|
|
|
32
32
|
return lines.join('\n');
|
|
33
33
|
}
|
|
34
34
|
export function parseFrontMatter(content) {
|
|
35
|
-
|
|
35
|
+
// `\r?\n` throughout so a CRLF/Windows task file parses too. Reads normally
|
|
36
|
+
// pass through readTextFile (which normalizes to LF), but tolerating CRLF at
|
|
37
|
+
// the parser itself is the safety net for any read site that forgets to —
|
|
38
|
+
// exactly the class of miss that shipped in 0.17.8. See shared/fs-text.ts.
|
|
39
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(content);
|
|
36
40
|
if (!m)
|
|
37
41
|
return null;
|
|
38
42
|
const obj = {};
|
|
39
|
-
for (const line of m[1].split(
|
|
43
|
+
for (const line of m[1].split(/\r?\n/)) {
|
|
40
44
|
const kv = /^([a-z_]+):\s*(.*)$/.exec(line);
|
|
41
45
|
if (kv)
|
|
42
46
|
obj[kv[1]] = kv[2];
|
|
@@ -69,7 +73,9 @@ export function sectionRegex(heading) {
|
|
|
69
73
|
// after a long /task-auto run). Keeping blanks in group 2 lets the `.trim()`
|
|
70
74
|
// every reader already applies collapse them, which also self-heals files
|
|
71
75
|
// that already accumulated the gap.
|
|
72
|
-
|
|
76
|
+
// `[ \t]*\r?\n` on the heading line so a CRLF file still matches the section
|
|
77
|
+
// (belt-and-suspenders alongside read-boundary normalization; see fs-text.ts).
|
|
78
|
+
return new RegExp(`(^## ${escapeRegex(heading)}[ \\t]*\\r?\\n)([\\s\\S]*?)(?=^## |$(?![\\s\\S]))`, 'm');
|
|
73
79
|
}
|
|
74
80
|
export function extractSection(body, heading) {
|
|
75
81
|
const m = sectionRegex(heading).exec(body);
|
|
@@ -423,7 +423,7 @@ export async function docsFocused(input) {
|
|
|
423
423
|
const { pkg, chunks, hitCache, indexingMs } = rawResult;
|
|
424
424
|
const concatenated = chunks.map(c => c.content).join('\n\n');
|
|
425
425
|
const prompt = buildPrompt(pkg, input.query, concatenated);
|
|
426
|
-
const invocation = getPiInvocation([...CHILD_ARGS, prompt
|
|
426
|
+
const invocation = getPiInvocation([...CHILD_ARGS], prompt);
|
|
427
427
|
const child = await runChild(spawn, invocation, input.cwd, input.signal);
|
|
428
428
|
const parsed = parseChildOutput(child.stdout);
|
|
429
429
|
const excerptVerified = parsed.excerpt ? isExcerptInContent(parsed.excerpt, concatenated) : undefined;
|
|
@@ -24,7 +24,7 @@ export async function fetchFocused(input) {
|
|
|
24
24
|
title: cleaned.title,
|
|
25
25
|
content: truncated
|
|
26
26
|
});
|
|
27
|
-
const invocation = getPiInvocation([...CHILD_ARGS, prompt
|
|
27
|
+
const invocation = getPiInvocation([...CHILD_ARGS], prompt);
|
|
28
28
|
const childResult = await runChild(spawnFn, invocation, input.cwd, input.signal);
|
|
29
29
|
if (childResult.aborted) {
|
|
30
30
|
return {
|
|
@@ -72,7 +72,7 @@ export async function runWorker(input) {
|
|
|
72
72
|
let leakRetries = 0;
|
|
73
73
|
for (;;) {
|
|
74
74
|
const prompt = hint === null ? input.prompt : `${hint}\n\n${input.prompt}`;
|
|
75
|
-
const invocation = getPiInvocation([...baseArgs, prompt
|
|
75
|
+
const invocation = getPiInvocation([...baseArgs], prompt);
|
|
76
76
|
const tStart = Date.now();
|
|
77
77
|
let tFirstByte = null;
|
|
78
78
|
// loop === false turns the guard off entirely (detector is null and no
|
|
@@ -104,7 +104,7 @@ export function registerPiWorkerDocs(pi, internals = {}) {
|
|
|
104
104
|
};
|
|
105
105
|
const concatenated = chunks.map(c => c.content).join('\n\n');
|
|
106
106
|
const prompt = buildProjectPrompt(projectName, params.query, concatenated);
|
|
107
|
-
const invocation = getPiInvocation([...CHILD_ARGS, prompt
|
|
107
|
+
const invocation = getPiInvocation([...CHILD_ARGS], prompt);
|
|
108
108
|
const child = await runChild(spawn, invocation, ctx.cwd, signal);
|
|
109
109
|
const failure = formatChildFailure(child, 'Project docs lookup aborted.');
|
|
110
110
|
if (failure !== null) {
|
|
@@ -206,7 +206,7 @@ export function registerPiWorkerDocs(pi, internals = {}) {
|
|
|
206
206
|
};
|
|
207
207
|
const concatenated = chunks.map(c => c.content).join('\n\n');
|
|
208
208
|
const prompt = buildPrompt(pkg, params.query, concatenated);
|
|
209
|
-
const invocation = getPiInvocation([...CHILD_ARGS, prompt
|
|
209
|
+
const invocation = getPiInvocation([...CHILD_ARGS], prompt);
|
|
210
210
|
const child = await runChild(spawn, invocation, ctx.cwd, signal);
|
|
211
211
|
const failure = formatChildFailure(child, 'Docs lookup aborted.');
|
|
212
212
|
if (failure !== null) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.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",
|