@mjasnikovs/pi-task 0.38.16 → 0.38.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/config/config.d.ts +26 -0
- package/dist/config/config.js +68 -17
- package/dist/task/accept-debt.js +2 -1
- package/dist/task/artifact-closure.js +18 -63
- package/dist/task/auto-orchestrator.js +205 -214
- package/dist/task/boot-probe.d.ts +46 -0
- package/dist/task/boot-probe.js +41 -21
- package/dist/task/coverage-loop.d.ts +11 -0
- package/dist/task/coverage-loop.js +16 -0
- package/dist/task/final-gate-fix.js +14 -24
- package/dist/task/final-gate.js +6 -1
- package/dist/task/fix-child.d.ts +64 -0
- package/dist/task/fix-child.js +66 -0
- package/dist/task/lint-fix.d.ts +7 -0
- package/dist/task/lint-fix.js +45 -9
- package/dist/task/orchestrator.js +9 -2
- package/dist/task/phases.d.ts +66 -4
- package/dist/task/phases.js +94 -34
- package/dist/task/plan-rounds.d.ts +86 -0
- package/dist/task/plan-rounds.js +105 -0
- package/dist/task/plan-session.d.ts +31 -21
- package/dist/task/plan-session.js +97 -120
- package/dist/task/qa-transcript.d.ts +100 -0
- package/dist/task/qa-transcript.js +99 -0
- package/dist/task/question-source.d.ts +117 -0
- package/dist/task/question-source.js +174 -0
- package/dist/task/serve-entry.js +6 -57
- package/dist/task/shipped-source.d.ts +67 -0
- package/dist/task/shipped-source.js +144 -0
- package/dist/task/task-gates.d.ts +1 -1
- package/dist/task/task-gates.js +4 -2
- package/dist/task/verify-work.d.ts +46 -0
- package/dist/task/verify-work.js +51 -3
- package/dist/workers/docs-core.d.ts +71 -1
- package/dist/workers/docs-core.js +131 -71
- package/dist/workers/pi-worker-core.js +23 -8
- package/package.json +1 -1
|
@@ -167,11 +167,81 @@ export declare function findDeclaredRange(parentPkg: string, cwd: string): strin
|
|
|
167
167
|
export declare function buildVersionBanner(pin: AutoInstallPin | undefined, resolved: string, version: string, cwd: string): string;
|
|
168
168
|
export declare function getDocsModulesDir(): string;
|
|
169
169
|
export declare function ensureDocsModulesDir(dir: string): void;
|
|
170
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Options rather than a positional tail: `signal` and `versionRange` sat adjacent,
|
|
172
|
+
* and reaching the range meant writing `undefined` into the signal slot — which is
|
|
173
|
+
* exactly how the primary acquisition path lost its abort signal while the hop path
|
|
174
|
+
* kept it.
|
|
175
|
+
*/
|
|
176
|
+
export interface AutoInstallOptions {
|
|
177
|
+
signal?: AbortSignal | undefined;
|
|
178
|
+
versionRange?: string | undefined;
|
|
179
|
+
}
|
|
180
|
+
export declare function runAutoInstall(spawn: SpawnFn, packageName: string, opts?: AutoInstallOptions): Promise<{
|
|
171
181
|
success: boolean;
|
|
172
182
|
installDir: string;
|
|
173
183
|
stderr: string;
|
|
174
184
|
}>;
|
|
185
|
+
/** What acquiring one package produced, or the stage at which it failed. */
|
|
186
|
+
export type AcquireOutcome = {
|
|
187
|
+
ok: true;
|
|
188
|
+
pkg: ResolvedPackage;
|
|
189
|
+
autoInstalled: boolean;
|
|
190
|
+
pin?: AutoInstallPin;
|
|
191
|
+
} | {
|
|
192
|
+
ok: false;
|
|
193
|
+
stage: 'resolve';
|
|
194
|
+
err: unknown;
|
|
195
|
+
} | {
|
|
196
|
+
ok: false;
|
|
197
|
+
stage: 'install';
|
|
198
|
+
stderr: string;
|
|
199
|
+
pin: AutoInstallPin;
|
|
200
|
+
asked: string;
|
|
201
|
+
} | {
|
|
202
|
+
ok: false;
|
|
203
|
+
stage: 'reresolve';
|
|
204
|
+
err: unknown;
|
|
205
|
+
pin: AutoInstallPin;
|
|
206
|
+
};
|
|
207
|
+
export interface AcquireInput {
|
|
208
|
+
/** The specifier to resolve. May be a subpath (`pkg/sub`) — the INSTALL always
|
|
209
|
+
* targets its parent package. */
|
|
210
|
+
name: string;
|
|
211
|
+
cwd: string;
|
|
212
|
+
spawn: SpawnFn;
|
|
213
|
+
resolvePackage: typeof defaultResolvePackage;
|
|
214
|
+
signal: AbortSignal | undefined;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Get a package onto disk and resolved: resolve from `cwd`, and on
|
|
218
|
+
* `not_installed` install it — at the range the PROJECT declares when it declares
|
|
219
|
+
* one — then resolve again from the install dir.
|
|
220
|
+
*
|
|
221
|
+
* One statement of the ladder, for both callers. It was written twice: inline in
|
|
222
|
+
* `docsRaw` for the requested package, and in `tryResolveOrInstall` for each hop
|
|
223
|
+
* of the type-redirect chain — and the copies had drifted on all three things
|
|
224
|
+
* that matter.
|
|
225
|
+
*
|
|
226
|
+
* - The abort signal. The hop copy passed it; the primary copy passed a bare
|
|
227
|
+
* `undefined` placeholder to reach the fourth positional, while
|
|
228
|
+
* `DocsRawInput.signal` was honoured on either side of that call. So a user
|
|
229
|
+
* cancel during the MAIN `npm install` of a model-chosen package was not
|
|
230
|
+
* delivered. `runAutoInstall` takes an options object now, so a hole like that
|
|
231
|
+
* cannot be typed.
|
|
232
|
+
* - The version pin. `findDeclaredRange` had exactly one call site — the primary
|
|
233
|
+
* copy. The hop copy installed `latest` unconditionally, on the hop most likely
|
|
234
|
+
* to be the declared one: `declarationChain` exists precisely because "a
|
|
235
|
+
* project that uses Bun declares `@types/bun`, not `bun`".
|
|
236
|
+
* - The provenance. `autoInstalled`/`autoInstallPin` were locals of `docsRaw`, so
|
|
237
|
+
* a package acquired only through a hop reported neither and got no version
|
|
238
|
+
* banner.
|
|
239
|
+
*
|
|
240
|
+
* CONTEXT.md records the redirect WALK as unified (`resolveTypeSource`) and its
|
|
241
|
+
* `resolveHop` seam as "the one thing its two call sites disagree about". They
|
|
242
|
+
* should disagree only about WHETHER to install, never about HOW.
|
|
243
|
+
*/
|
|
244
|
+
export declare function acquirePackage(input: AcquireInput): Promise<AcquireOutcome>;
|
|
175
245
|
export declare function docsRaw(input: DocsRawInput): Promise<DocsRawResult>;
|
|
176
246
|
export declare function docsFocused(input: DocsFocusedInput): Promise<DocsFocusedResult>;
|
|
177
247
|
export declare function buildPrompt(pkg: ResolvedPackage, query: string, content: string): string;
|
|
@@ -176,7 +176,8 @@ export function ensureDocsModulesDir(dir) {
|
|
|
176
176
|
fs.writeFileSync(pkgPath, '{"name":"pi-worker-docs-modules","private":true}\n', 'utf8');
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
|
-
export async function runAutoInstall(spawn, packageName,
|
|
179
|
+
export async function runAutoInstall(spawn, packageName, opts = {}) {
|
|
180
|
+
const { signal, versionRange } = opts;
|
|
180
181
|
const installDir = getDocsModulesDir();
|
|
181
182
|
ensureDocsModulesDir(installDir);
|
|
182
183
|
// `shell: false` in runChild, so a `^`/`~`/space in the range stays a single
|
|
@@ -203,31 +204,97 @@ export async function runAutoInstall(spawn, packageName, signal, versionRange) {
|
|
|
203
204
|
}, installDir, signal, { mode: 'text', discardStdout: true });
|
|
204
205
|
return { success: result.exitCode === 0 && !result.aborted, installDir, stderr: result.stderr };
|
|
205
206
|
}
|
|
206
|
-
/**
|
|
207
|
-
*
|
|
208
|
-
|
|
207
|
+
/**
|
|
208
|
+
* Get a package onto disk and resolved: resolve from `cwd`, and on
|
|
209
|
+
* `not_installed` install it — at the range the PROJECT declares when it declares
|
|
210
|
+
* one — then resolve again from the install dir.
|
|
211
|
+
*
|
|
212
|
+
* One statement of the ladder, for both callers. It was written twice: inline in
|
|
213
|
+
* `docsRaw` for the requested package, and in `tryResolveOrInstall` for each hop
|
|
214
|
+
* of the type-redirect chain — and the copies had drifted on all three things
|
|
215
|
+
* that matter.
|
|
216
|
+
*
|
|
217
|
+
* - The abort signal. The hop copy passed it; the primary copy passed a bare
|
|
218
|
+
* `undefined` placeholder to reach the fourth positional, while
|
|
219
|
+
* `DocsRawInput.signal` was honoured on either side of that call. So a user
|
|
220
|
+
* cancel during the MAIN `npm install` of a model-chosen package was not
|
|
221
|
+
* delivered. `runAutoInstall` takes an options object now, so a hole like that
|
|
222
|
+
* cannot be typed.
|
|
223
|
+
* - The version pin. `findDeclaredRange` had exactly one call site — the primary
|
|
224
|
+
* copy. The hop copy installed `latest` unconditionally, on the hop most likely
|
|
225
|
+
* to be the declared one: `declarationChain` exists precisely because "a
|
|
226
|
+
* project that uses Bun declares `@types/bun`, not `bun`".
|
|
227
|
+
* - The provenance. `autoInstalled`/`autoInstallPin` were locals of `docsRaw`, so
|
|
228
|
+
* a package acquired only through a hop reported neither and got no version
|
|
229
|
+
* banner.
|
|
230
|
+
*
|
|
231
|
+
* CONTEXT.md records the redirect WALK as unified (`resolveTypeSource`) and its
|
|
232
|
+
* `resolveHop` seam as "the one thing its two call sites disagree about". They
|
|
233
|
+
* should disagree only about WHETHER to install, never about HOW.
|
|
234
|
+
*/
|
|
235
|
+
export async function acquirePackage(input) {
|
|
236
|
+
const { name, cwd, spawn, resolvePackage, signal } = input;
|
|
209
237
|
try {
|
|
210
|
-
return resolvePackage(name, cwd);
|
|
238
|
+
return { ok: true, pkg: resolvePackage(name, cwd), autoInstalled: false };
|
|
211
239
|
}
|
|
212
|
-
catch (
|
|
213
|
-
if (!(
|
|
214
|
-
return
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
240
|
+
catch (firstErr) {
|
|
241
|
+
if (!(firstErr instanceof ResolveError) || firstErr.kind !== 'not_installed') {
|
|
242
|
+
return { ok: false, stage: 'resolve', err: firstErr };
|
|
243
|
+
}
|
|
244
|
+
// Auto-install — but FIRST honour the version the project intends. If the
|
|
245
|
+
// dep is declared in the project's package.json, install that range so a
|
|
246
|
+
// scaffolding answer is grounded in the project's major, not whatever npm
|
|
247
|
+
// currently tags `latest`.
|
|
248
|
+
const asked = extractParentPackage(name);
|
|
249
|
+
const declaredRange = findDeclaredRange(asked, cwd);
|
|
250
|
+
const pin = declaredRange ?
|
|
251
|
+
{ source: 'declared-range', range: declaredRange, asked }
|
|
252
|
+
: { source: 'npm-latest', asked };
|
|
253
|
+
const install = await runAutoInstall(spawn, asked, {
|
|
254
|
+
signal,
|
|
255
|
+
versionRange: declaredRange ?? undefined
|
|
256
|
+
});
|
|
257
|
+
if (!install.success) {
|
|
258
|
+
return { ok: false, stage: 'install', stderr: install.stderr, pin, asked };
|
|
259
|
+
}
|
|
218
260
|
try {
|
|
219
|
-
return
|
|
261
|
+
return {
|
|
262
|
+
ok: true,
|
|
263
|
+
pkg: resolvePackage(name, install.installDir),
|
|
264
|
+
autoInstalled: true,
|
|
265
|
+
pin
|
|
266
|
+
};
|
|
220
267
|
}
|
|
221
|
-
catch {
|
|
222
|
-
return
|
|
268
|
+
catch (retryErr) {
|
|
269
|
+
return { ok: false, stage: 'reresolve', err: retryErr, pin };
|
|
223
270
|
}
|
|
224
271
|
}
|
|
225
272
|
}
|
|
273
|
+
/** Resolve `name` from cwd; on `not_installed`, auto-install it and resolve from
|
|
274
|
+
* the install dir. Returns null on any failure (caller keeps its fallback). */
|
|
275
|
+
async function tryResolveOrInstall(name, cwd, spawn, resolvePackage, signal, onAcquired) {
|
|
276
|
+
const got = await acquirePackage({ name, cwd, spawn, resolvePackage, signal });
|
|
277
|
+
if (!got.ok)
|
|
278
|
+
return null;
|
|
279
|
+
if (got.autoInstalled)
|
|
280
|
+
onAcquired?.(got.pin);
|
|
281
|
+
return got.pkg;
|
|
282
|
+
}
|
|
226
283
|
/** The docs pipeline's adapter over the shared redirect walk (docs-resolve.ts):
|
|
227
284
|
* hops resolve through the auto-installing lookup, so a declaration package that is
|
|
228
285
|
* declared but not yet on disk is fetched rather than abandoned. */
|
|
229
|
-
function resolveTypeSourceForDocs(pkg, requested, cwd, spawn, resolvePackage, signal) {
|
|
230
|
-
|
|
286
|
+
async function resolveTypeSourceForDocs(pkg, requested, cwd, spawn, resolvePackage, signal) {
|
|
287
|
+
// A package acquired ONLY through a hop used to report neither `autoInstalled`
|
|
288
|
+
// nor a pin, so `pi-worker-docs` emitted no version banner for it — while the
|
|
289
|
+
// banner's own text ("only its types are, as `@types/bun` `^1.2`") claims a
|
|
290
|
+
// range as provenance. Report the last hop that actually installed.
|
|
291
|
+
let installed = false;
|
|
292
|
+
let pin;
|
|
293
|
+
const out = await resolveTypeSource(pkg, extractParentPackage(requested), next => tryResolveOrInstall(next, cwd, spawn, resolvePackage, signal, hopPin => {
|
|
294
|
+
installed = true;
|
|
295
|
+
pin = hopPin;
|
|
296
|
+
}));
|
|
297
|
+
return pin ? { pkg: out, installed, pin } : { pkg: out, installed };
|
|
231
298
|
}
|
|
232
299
|
export async function docsRaw(input) {
|
|
233
300
|
const resolvePackage = input.resolvePackage ?? defaultResolvePackage;
|
|
@@ -247,83 +314,76 @@ export async function docsRaw(input) {
|
|
|
247
314
|
const npmVersionPromise = npmVersionLookup(extractParentPackage(requested), {
|
|
248
315
|
signal: input.signal
|
|
249
316
|
}).catch(() => null);
|
|
250
|
-
// Step 1: resolve
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
resolveError: 'not_installed',
|
|
275
|
-
installError: installResult.stderr,
|
|
276
|
-
autoInstallPin,
|
|
277
|
-
npmVersion: await npmVersionPromise
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
autoInstalled = true;
|
|
281
|
-
try {
|
|
282
|
-
pkg = resolvePackage(requested, installResult.installDir);
|
|
283
|
-
}
|
|
284
|
-
catch (retryErr) {
|
|
285
|
-
if (retryErr instanceof ResolveError) {
|
|
286
|
-
return {
|
|
287
|
-
kind: 'error',
|
|
288
|
-
message: retryErr.message,
|
|
289
|
-
resolveError: retryErr.kind,
|
|
290
|
-
autoInstalled,
|
|
291
|
-
autoInstallPin,
|
|
292
|
-
npmVersion: await npmVersionPromise
|
|
293
|
-
};
|
|
294
|
-
}
|
|
317
|
+
// Step 1: acquire the package — resolve, or install-at-the-declared-range and
|
|
318
|
+
// resolve again. The ladder is `acquirePackage`; this maps its stages onto the
|
|
319
|
+
// rich error results the docs tool reports. `input.signal` now reaches the
|
|
320
|
+
// install, which it never did while the range was a fourth positional.
|
|
321
|
+
const got = await acquirePackage({
|
|
322
|
+
name: requested,
|
|
323
|
+
cwd: input.cwd,
|
|
324
|
+
spawn,
|
|
325
|
+
resolvePackage,
|
|
326
|
+
signal: input.signal
|
|
327
|
+
});
|
|
328
|
+
if (!got.ok) {
|
|
329
|
+
if (got.stage === 'install') {
|
|
330
|
+
return {
|
|
331
|
+
kind: 'error',
|
|
332
|
+
message: `Package "${got.asked}" is not installed and auto-install failed.\n${got.stderr}`,
|
|
333
|
+
resolveError: 'not_installed',
|
|
334
|
+
installError: got.stderr,
|
|
335
|
+
autoInstallPin: got.pin,
|
|
336
|
+
npmVersion: await npmVersionPromise
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
if (got.stage === 'reresolve') {
|
|
340
|
+
if (got.err instanceof ResolveError) {
|
|
295
341
|
return {
|
|
296
342
|
kind: 'error',
|
|
297
|
-
message:
|
|
298
|
-
|
|
299
|
-
|
|
343
|
+
message: got.err.message,
|
|
344
|
+
resolveError: got.err.kind,
|
|
345
|
+
autoInstalled: true,
|
|
346
|
+
autoInstallPin: got.pin,
|
|
300
347
|
npmVersion: await npmVersionPromise
|
|
301
348
|
};
|
|
302
349
|
}
|
|
303
|
-
}
|
|
304
|
-
else if (firstErr instanceof ResolveError) {
|
|
305
350
|
return {
|
|
306
351
|
kind: 'error',
|
|
307
|
-
message:
|
|
308
|
-
|
|
352
|
+
message: `Could not resolve "${input.pkg}" after install: ${got.err instanceof Error ? got.err.message : String(got.err)}`,
|
|
353
|
+
autoInstalled: true,
|
|
354
|
+
autoInstallPin: got.pin,
|
|
309
355
|
npmVersion: await npmVersionPromise
|
|
310
356
|
};
|
|
311
357
|
}
|
|
312
|
-
|
|
358
|
+
if (got.err instanceof ResolveError) {
|
|
313
359
|
return {
|
|
314
360
|
kind: 'error',
|
|
315
|
-
message:
|
|
361
|
+
message: got.err.message,
|
|
362
|
+
resolveError: got.err.kind,
|
|
316
363
|
npmVersion: await npmVersionPromise
|
|
317
364
|
};
|
|
318
365
|
}
|
|
366
|
+
return {
|
|
367
|
+
kind: 'error',
|
|
368
|
+
message: `Could not resolve "${input.pkg}": ${got.err instanceof Error ? got.err.message : String(got.err)}`,
|
|
369
|
+
npmVersion: await npmVersionPromise
|
|
370
|
+
};
|
|
319
371
|
}
|
|
372
|
+
let pkg = got.pkg;
|
|
373
|
+
let autoInstalled = got.autoInstalled;
|
|
374
|
+
let autoInstallPin = got.pin;
|
|
320
375
|
// Step 1b: if the resolved package ships no usable type declarations (e.g.
|
|
321
376
|
// the `bun` runtime launcher, which is just a binary + install README), or is
|
|
322
377
|
// a pure `@types/<name>` redirect stub, follow the conventional
|
|
323
378
|
// @types/<name> + triple-slash `<reference types>` chain to the package that
|
|
324
379
|
// actually holds the declarations (e.g. bun -> @types/bun -> bun-types).
|
|
325
380
|
// Best-effort: any failure leaves the original resolution untouched.
|
|
326
|
-
|
|
381
|
+
const viaTypes = await resolveTypeSourceForDocs(pkg, requested, input.cwd, spawn, resolvePackage, input.signal);
|
|
382
|
+
pkg = viaTypes.pkg;
|
|
383
|
+
if (viaTypes.installed) {
|
|
384
|
+
autoInstalled = true;
|
|
385
|
+
autoInstallPin ??= viaTypes.pin;
|
|
386
|
+
}
|
|
327
387
|
// Step 2: open cache
|
|
328
388
|
let cache = null;
|
|
329
389
|
let cacheError;
|
|
@@ -8,6 +8,7 @@ import { LOOP_WINDOW, LOOP_THRESHOLD, MAX_LOOP_RESTARTS, formatLoopHint, isConne
|
|
|
8
8
|
import { detectLeakedToolCall, leakedToolCallHint, MAX_LEAK_RETRIES } from '../shared/leaked-tool-call.js';
|
|
9
9
|
import { discoverModelEndpoints, probeModelEndpoints } from '../shared/model-endpoint.js';
|
|
10
10
|
import { streamStallHint } from '../shared/stream-watchdog.js';
|
|
11
|
+
import { classifyWorkerFailure } from './worker-failure.js';
|
|
11
12
|
// `--mode json` makes pi emit structured events as they happen instead of
|
|
12
13
|
// buffering the assistant text and flushing on exit. That matters for the
|
|
13
14
|
// wait/work timing split: in text mode the first stdout chunk only arrives at
|
|
@@ -647,14 +648,28 @@ export async function runWorker(input) {
|
|
|
647
648
|
// worker that finished cleanly has answered, and a short answer is a
|
|
648
649
|
// legitimate answer — length would let a long half-finished fragment
|
|
649
650
|
// override a concise correct one, which is the opposite of the fix.
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
651
|
+
// ASK THE LADDER — do not restate it. This was an eight-term disjunction,
|
|
652
|
+
// a fifth hand-written statement of the taxonomy `worker-failure.ts` exists
|
|
653
|
+
// to own, and it had already drifted: `leakedToolCall` and a plain non-zero
|
|
654
|
+
// `exitCode` are rows in FAILURE_RULES and were missing here. Both are cases
|
|
655
|
+
// where an attempt that produced nothing usable counted as NOT failed, so
|
|
656
|
+
// salvage was skipped and a good earlier partial was overwritten — the exact
|
|
657
|
+
// outcome the comment above forbids.
|
|
658
|
+
//
|
|
659
|
+
// The two non-kill terms stay explicit because `worker-failure.ts`
|
|
660
|
+
// deliberately excludes them as CONSUMER policy: an empty answer and a
|
|
661
|
+
// reported `modelError` on a run that still produced text are not kills.
|
|
662
|
+
const killCause = classifyWorkerFailure({
|
|
663
|
+
exitCode: result.exitCode,
|
|
664
|
+
aborted: result.aborted,
|
|
665
|
+
timedOut,
|
|
666
|
+
...(result.stalled === true ? { stalled: true } : {}),
|
|
667
|
+
...(loopHit ? { loopHit } : {}),
|
|
668
|
+
...(leaked ? { leakedToolCall: leaked } : {}),
|
|
669
|
+
...(commandKill ? { commandTimedOut: commandKill } : {}),
|
|
670
|
+
...(streamStalled ? { streamStalled } : {})
|
|
671
|
+
});
|
|
672
|
+
const finalAttemptFailed = killCause !== undefined || result.modelError !== undefined || text.trim().length === 0;
|
|
658
673
|
const answer = (finalAttemptFailed
|
|
659
674
|
&& salvage.text !== null
|
|
660
675
|
&& salvage.text.length > text.trim().length) ?
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.17",
|
|
4
4
|
"description": "Deterministic task planning and spec-orchestration for local models — crash-safe /task pipelines with verify/enforce gates, a real-time remote web view, and web/docs/fetch/worker subagent tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|