@oh-my-pi/pi-coding-agent 16.3.4 → 16.3.6
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/CHANGELOG.md +36 -0
- package/dist/cli.js +3522 -3485
- package/dist/types/edit/file-snapshot-store.d.ts +4 -2
- package/dist/types/edit/renderer.d.ts +0 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -0
- package/dist/types/extensibility/shared-events.d.ts +8 -1
- package/dist/types/hindsight/content.d.ts +4 -0
- package/dist/types/internal-urls/artifact-protocol.d.ts +8 -0
- package/dist/types/internal-urls/types.d.ts +10 -0
- package/dist/types/lsp/config.d.ts +4 -0
- package/dist/types/lsp/edits.d.ts +2 -0
- package/dist/types/mcp/oauth-discovery.d.ts +30 -0
- package/dist/types/modes/components/assistant-message.d.ts +15 -10
- package/dist/types/modes/components/bash-execution.d.ts +6 -0
- package/dist/types/modes/components/eval-execution.d.ts +6 -0
- package/dist/types/modes/components/login-dialog.d.ts +10 -2
- package/dist/types/modes/components/tool-execution.d.ts +3 -13
- package/dist/types/modes/components/transcript-container.d.ts +26 -29
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +20 -3
- package/dist/types/modes/rpc/rpc-client.d.ts +7 -3
- package/dist/types/modes/rpc/rpc-types.d.ts +6 -0
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +15 -6
- package/dist/types/session/agent-session.d.ts +2 -0
- package/dist/types/subprocess/worker-runtime.d.ts +11 -0
- package/dist/types/tools/bash-skill-urls.d.ts +2 -2
- package/dist/types/tools/bash.d.ts +0 -2
- package/dist/types/tools/browser/tab-supervisor.d.ts +10 -0
- package/dist/types/tools/eval-render.d.ts +0 -2
- package/dist/types/tools/renderers.d.ts +0 -20
- package/dist/types/tools/ssh.d.ts +0 -2
- package/dist/types/tools/write.d.ts +1 -1
- package/dist/types/utils/git.d.ts +16 -0
- package/package.json +12 -12
- package/src/cli/auth-broker-cli.ts +13 -2
- package/src/cli/tiny-models-cli.ts +12 -5
- package/src/edit/file-snapshot-store.ts +5 -2
- package/src/edit/renderer.ts +0 -5
- package/src/extensibility/custom-tools/types.ts +2 -0
- package/src/extensibility/shared-events.ts +9 -1
- package/src/hindsight/content.ts +31 -0
- package/src/internal-urls/artifact-protocol.ts +97 -53
- package/src/internal-urls/types.ts +10 -0
- package/src/lsp/config.ts +15 -0
- package/src/lsp/edits.ts +28 -7
- package/src/lsp/index.ts +46 -4
- package/src/mcp/oauth-discovery.ts +88 -18
- package/src/mnemopi/state.ts +26 -2
- package/src/modes/components/assistant-message.ts +134 -82
- package/src/modes/components/bash-execution.ts +9 -0
- package/src/modes/components/chat-transcript-builder.ts +8 -4
- package/src/modes/components/eval-execution.ts +9 -0
- package/src/modes/components/login-dialog.ts +16 -2
- package/src/modes/components/mcp-add-wizard.ts +9 -1
- package/src/modes/components/tool-execution.ts +4 -50
- package/src/modes/components/transcript-container.ts +82 -458
- package/src/modes/components/tree-selector.ts +9 -3
- package/src/modes/controllers/command-controller.ts +0 -3
- package/src/modes/controllers/event-controller.ts +74 -14
- package/src/modes/controllers/extension-ui-controller.ts +0 -1
- package/src/modes/controllers/input-controller.ts +4 -10
- package/src/modes/controllers/mcp-command-controller.ts +106 -29
- package/src/modes/controllers/selector-controller.ts +9 -1
- package/src/modes/interactive-mode.ts +12 -8
- package/src/modes/rpc/rpc-client.ts +8 -4
- package/src/modes/rpc/rpc-mode.ts +1 -0
- package/src/modes/rpc/rpc-types.ts +13 -1
- package/src/modes/setup-wizard/scenes/sign-in.ts +18 -0
- package/src/modes/utils/transcript-render-helpers.ts +40 -13
- package/src/modes/utils/ui-helpers.ts +12 -7
- package/src/prompts/tools/read.md +1 -1
- package/src/sdk.ts +1 -0
- package/src/session/agent-session.ts +148 -1
- package/src/session/session-context.ts +7 -0
- package/src/subprocess/worker-runtime.ts +219 -2
- package/src/task/worktree.ts +28 -6
- package/src/tiny/worker.ts +14 -4
- package/src/tools/bash-skill-urls.ts +3 -3
- package/src/tools/bash.ts +0 -4
- package/src/tools/browser/tab-supervisor.ts +47 -3
- package/src/tools/eval-render.ts +0 -20
- package/src/tools/grep.ts +19 -2
- package/src/tools/path-utils.ts +4 -0
- package/src/tools/read.ts +261 -21
- package/src/tools/renderers.ts +0 -20
- package/src/tools/ssh.ts +0 -16
- package/src/tools/write.ts +13 -6
- package/src/utils/git.ts +20 -0
- package/src/utils/open.ts +51 -6
package/src/task/worktree.ts
CHANGED
|
@@ -855,18 +855,40 @@ export async function mergeTaskBranches(
|
|
|
855
855
|
try {
|
|
856
856
|
const target = baseSha ? `${baseSha}..${branchName}` : branchName;
|
|
857
857
|
await git.cherryPick(repoRoot, target);
|
|
858
|
-
} catch (
|
|
858
|
+
} catch (initialErr) {
|
|
859
|
+
// Empty cherry-picks are not conflicts: a commit whose net
|
|
860
|
+
// effect is already on HEAD (redundant change, or 3-way
|
|
861
|
+
// merge auto-resolved to HEAD) leaves the sequencer stopped
|
|
862
|
+
// with a "The previous cherry-pick is now empty" message.
|
|
863
|
+
// Advance past every consecutive empty with `--skip` so the
|
|
864
|
+
// remaining non-redundant commits in the range still land.
|
|
865
|
+
// A genuine conflict (unmerged files, no "now empty"
|
|
866
|
+
// message) falls through to the abort path below.
|
|
867
|
+
let cursor: unknown = initialErr;
|
|
868
|
+
while (git.cherryPick.isEmptyError(cursor)) {
|
|
869
|
+
try {
|
|
870
|
+
await git.cherryPick.skip(repoRoot);
|
|
871
|
+
cursor = undefined;
|
|
872
|
+
break;
|
|
873
|
+
} catch (skipErr) {
|
|
874
|
+
cursor = skipErr;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
if (cursor === undefined) {
|
|
878
|
+
merged.push(branchName);
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
859
881
|
try {
|
|
860
882
|
await git.cherryPick.abort(repoRoot);
|
|
861
883
|
} catch {
|
|
862
884
|
/* no state to abort */
|
|
863
885
|
}
|
|
864
886
|
const stderr =
|
|
865
|
-
|
|
866
|
-
?
|
|
867
|
-
:
|
|
868
|
-
?
|
|
869
|
-
: String(
|
|
887
|
+
cursor instanceof git.GitCommandError
|
|
888
|
+
? cursor.result.stderr.trim()
|
|
889
|
+
: cursor instanceof Error
|
|
890
|
+
? cursor.message
|
|
891
|
+
: String(cursor);
|
|
870
892
|
failed.push(branchName);
|
|
871
893
|
conflictResult = {
|
|
872
894
|
merged,
|
package/src/tiny/worker.ts
CHANGED
|
@@ -10,12 +10,14 @@ import tinyTitleSystemPrompt from "../prompts/system/tiny-title-system.md" with
|
|
|
10
10
|
import {
|
|
11
11
|
errorMessage,
|
|
12
12
|
errorText,
|
|
13
|
+
formatOnnxRuntimeCudaDiagnostics,
|
|
13
14
|
getTransformersVersionSpec,
|
|
14
15
|
loadTransformersRuntime,
|
|
15
16
|
MemoizedRuntime,
|
|
16
17
|
replayCachedReady,
|
|
17
18
|
sendLog,
|
|
18
19
|
sendProgress,
|
|
20
|
+
type TransformersRuntimeMetadata,
|
|
19
21
|
} from "../subprocess/worker-runtime";
|
|
20
22
|
import { resolveTinyModelDevicePreference, type TinyModelDevice, tinyModelDeviceLoadOrder } from "./device";
|
|
21
23
|
import { resolveTinyModelDtypeOverride, type TinyModelDtype } from "./dtype";
|
|
@@ -39,7 +41,7 @@ const TINY_TITLE_SYSTEM_PROMPT = prompt.render(tinyTitleSystemPrompt);
|
|
|
39
41
|
const tinyModelDevicePreference = resolveTinyModelDevicePreference();
|
|
40
42
|
const tinyModelDtypeOverride = resolveTinyModelDtypeOverride();
|
|
41
43
|
|
|
42
|
-
interface TransformersRuntime {
|
|
44
|
+
interface TransformersRuntime extends TransformersRuntimeMetadata {
|
|
43
45
|
env: {
|
|
44
46
|
cacheDir?: string;
|
|
45
47
|
allowLocalModels?: boolean;
|
|
@@ -136,6 +138,7 @@ async function loadPipelineWithDeviceFallback(
|
|
|
136
138
|
device: devices[0],
|
|
137
139
|
});
|
|
138
140
|
}
|
|
141
|
+
let cudaDiagnostics: string | null = null;
|
|
139
142
|
for (let i = 0; i < devices.length; i += 1) {
|
|
140
143
|
const device = devices[i]!;
|
|
141
144
|
try {
|
|
@@ -144,15 +147,22 @@ async function loadPipelineWithDeviceFallback(
|
|
|
144
147
|
device,
|
|
145
148
|
};
|
|
146
149
|
} catch (error) {
|
|
147
|
-
|
|
150
|
+
const deviceDiagnostics = await formatOnnxRuntimeCudaDiagnostics(transformers, device, error);
|
|
151
|
+
if (deviceDiagnostics) cudaDiagnostics = deviceDiagnostics;
|
|
152
|
+
if (i === devices.length - 1) {
|
|
153
|
+
if (cudaDiagnostics) throw new Error(`${errorText(error)}\n${cudaDiagnostics}`);
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
148
156
|
const fallbackDevice = devices[i + 1]!;
|
|
149
|
-
|
|
157
|
+
const meta: Record<string, unknown> = {
|
|
150
158
|
modelKey,
|
|
151
159
|
repo: spec.repo,
|
|
152
160
|
device,
|
|
153
161
|
fallbackDevice,
|
|
154
162
|
error: errorMessage(error),
|
|
155
|
-
}
|
|
163
|
+
};
|
|
164
|
+
if (deviceDiagnostics) meta.cudaDiagnostics = deviceDiagnostics;
|
|
165
|
+
sendLog(transport, "warn", "tiny-model: accelerated device failed; falling back", meta);
|
|
156
166
|
}
|
|
157
167
|
}
|
|
158
168
|
throw new Error("No tiny model devices configured");
|
|
@@ -3,7 +3,7 @@ import * as path from "node:path";
|
|
|
3
3
|
import type { Skill } from "../extensibility/skills";
|
|
4
4
|
import { type LocalProtocolOptions, resolveLocalUrlToPath } from "../internal-urls";
|
|
5
5
|
import { validateRelativePath } from "../internal-urls/skill-protocol";
|
|
6
|
-
import type { InternalResource } from "../internal-urls/types";
|
|
6
|
+
import type { InternalResource, ResolveContext } from "../internal-urls/types";
|
|
7
7
|
import { normalizeLocalScheme } from "./path-utils";
|
|
8
8
|
import { ToolError } from "./tool-errors";
|
|
9
9
|
|
|
@@ -19,7 +19,7 @@ type SupportedInternalScheme = (typeof SUPPORTED_INTERNAL_SCHEMES)[number];
|
|
|
19
19
|
|
|
20
20
|
interface InternalUrlResolver {
|
|
21
21
|
canHandle(input: string): boolean;
|
|
22
|
-
resolve(input: string): Promise<InternalResource>;
|
|
22
|
+
resolve(input: string, context?: ResolveContext): Promise<InternalResource>;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export interface InternalUrlExpansionOptions {
|
|
@@ -184,7 +184,7 @@ async function resolveInternalUrlToPath(
|
|
|
184
184
|
|
|
185
185
|
let resource: InternalResource;
|
|
186
186
|
try {
|
|
187
|
-
resource = await internalRouter.resolve(url);
|
|
187
|
+
resource = await internalRouter.resolve(url, { pathOnly: true });
|
|
188
188
|
} catch (error) {
|
|
189
189
|
const message = error instanceof Error ? error.message : String(error);
|
|
190
190
|
throw new ToolError(`Failed to resolve ${scheme}:// URL in bash command: ${url}\n${message}`);
|
package/src/tools/bash.ts
CHANGED
|
@@ -1409,10 +1409,6 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
|
|
|
1409
1409
|
},
|
|
1410
1410
|
mergeCallAndResult: true,
|
|
1411
1411
|
inline: true,
|
|
1412
|
-
// Collapsed pending preview caps the command to a viewport-sized tail
|
|
1413
|
-
// window that shifts while args stream. Expanded output is top-anchored
|
|
1414
|
-
// enough for the transcript to commit its settled prefix.
|
|
1415
|
-
provisionalPendingPreview: "collapsed",
|
|
1416
1412
|
};
|
|
1417
1413
|
}
|
|
1418
1414
|
|
|
@@ -48,6 +48,16 @@ export interface PendingRun {
|
|
|
48
48
|
session: ToolSession;
|
|
49
49
|
signal?: AbortSignal;
|
|
50
50
|
toolCalls: Map<string, AbortController>;
|
|
51
|
+
/**
|
|
52
|
+
* Fires when `releaseTab` closes the tab out from under an in-flight run
|
|
53
|
+
* (sibling `browser close --all`, session-scoped reap, etc.). Composed
|
|
54
|
+
* into the cmux run's signal so `wait(...)`, cmux socket calls, and the
|
|
55
|
+
* facade proxies unwind promptly instead of blocking to the run's
|
|
56
|
+
* timeout. `pending.reject` still fires first so the awaiting caller
|
|
57
|
+
* sees the tab-close error immediately; `closeAc` propagates the
|
|
58
|
+
* cancellation into the still-running `runCmuxCode` body (issue #4499).
|
|
59
|
+
*/
|
|
60
|
+
closeAc?: AbortController;
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
interface TabSessionBase<TBrowser extends BrowserHandle = BrowserHandle> {
|
|
@@ -380,23 +390,47 @@ async function runInTabWithSnapshot(
|
|
|
380
390
|
if (tab.pending.size > 0) throw new ToolError(`Tab ${JSON.stringify(name)} is busy`);
|
|
381
391
|
const id = Snowflake.next();
|
|
382
392
|
const { promise, resolve, reject } = Promise.withResolvers<RunResultOk>();
|
|
393
|
+
// `releaseTab` calls `pending.reject(closeError)` when the tab dies
|
|
394
|
+
// out from under an in-flight run (sibling `browser close --all`,
|
|
395
|
+
// session-scoped reap, etc.). Both backends below MUST end up awaiting
|
|
396
|
+
// this same `promise` so:
|
|
397
|
+
// 1. The caller sees `Tab ... was closed` immediately instead of
|
|
398
|
+
// blocking to the run's timeout, and
|
|
399
|
+
// 2. `reject(...)` always has an attached handler — a zero-consumer
|
|
400
|
+
// rejection would fire `unhandledRejection` and the CLI's
|
|
401
|
+
// top-level handler would tear the whole session down, killing
|
|
402
|
+
// every other tab and subagent sharing the process (issue #4499).
|
|
403
|
+
// The cmux branch also composes `closeAc.signal` into the run's abort
|
|
404
|
+
// signal so `wait(...)`, cmux socket calls, and the facade proxies
|
|
405
|
+
// unwind promptly when the tab is closed — otherwise a `wait(60_000)`
|
|
406
|
+
// with no in-flight socket request would keep `runCmuxCode` blocked
|
|
407
|
+
// until timeout even after the tab is gone.
|
|
408
|
+
const closeAc = new AbortController();
|
|
383
409
|
const pending: PendingRun = {
|
|
384
410
|
resolve,
|
|
385
411
|
reject,
|
|
386
412
|
session: opts.session ?? ({} as ToolSession),
|
|
387
413
|
signal: opts.signal,
|
|
388
414
|
toolCalls: new Map(),
|
|
415
|
+
closeAc,
|
|
389
416
|
};
|
|
390
417
|
tab.pending.set(id, pending);
|
|
391
418
|
if (tab.backend === "cmux") {
|
|
419
|
+
const runSignal = opts.signal ? AbortSignal.any([opts.signal, closeAc.signal]) : closeAc.signal;
|
|
392
420
|
try {
|
|
393
|
-
|
|
421
|
+
// `runCmuxCode.then(resolve, reject)` publishes the run's real
|
|
422
|
+
// outcome to `promise`, but `releaseTab` may have already
|
|
423
|
+
// rejected it — `Promise.withResolvers` settles on the first
|
|
424
|
+
// call and later resolve/reject are no-ops, so the tab-close
|
|
425
|
+
// error still wins the race.
|
|
426
|
+
runCmuxCode(tab.cmuxTab, {
|
|
394
427
|
code: opts.code,
|
|
395
428
|
timeoutMs: opts.timeoutMs,
|
|
396
|
-
signal:
|
|
429
|
+
signal: runSignal,
|
|
397
430
|
session: pending.session,
|
|
398
431
|
snapshot,
|
|
399
|
-
});
|
|
432
|
+
}).then(resolve, reject);
|
|
433
|
+
return await promise;
|
|
400
434
|
} finally {
|
|
401
435
|
tab.pending.delete(id);
|
|
402
436
|
}
|
|
@@ -460,6 +494,16 @@ export async function releaseTab(name: string, opts: ReleaseTabOptions = {}): Pr
|
|
|
460
494
|
} catch {}
|
|
461
495
|
}
|
|
462
496
|
for (const ctrl of pending.toolCalls.values()) ctrl.abort(closeError);
|
|
497
|
+
// Propagate the closure into the cmux run's abort signal so
|
|
498
|
+
// `wait(...)`, in-flight cmux socket calls, and the facade proxies
|
|
499
|
+
// unwind promptly. Firing this BEFORE `pending.reject` means
|
|
500
|
+
// `runCmuxCode` finishes with `ToolAbortError` and its `.then(reject)`
|
|
501
|
+
// is a no-op — `promise` still settles with the tab-close error via
|
|
502
|
+
// the `reject` call below. Without it, a run that isn't currently
|
|
503
|
+
// making a socket request (e.g. `await wait(60_000)`) would keep
|
|
504
|
+
// `runCmuxCode` blocked until timeout even after `pending.reject`
|
|
505
|
+
// unblocked the caller (issue #4499 review feedback).
|
|
506
|
+
pending.closeAc?.abort(closeError);
|
|
463
507
|
pending.reject(closeError);
|
|
464
508
|
}
|
|
465
509
|
tab.pending.clear();
|
package/src/tools/eval-render.ts
CHANGED
|
@@ -773,24 +773,4 @@ export const evalToolRenderer = {
|
|
|
773
773
|
|
|
774
774
|
mergeCallAndResult: true,
|
|
775
775
|
inline: true,
|
|
776
|
-
// Collapsed pending preview shows tail-window code cells; the result render
|
|
777
|
-
// interleaves each cell's output under its code, re-laying-out every row
|
|
778
|
-
// below the first cell. Expanded output is top-anchored enough for the
|
|
779
|
-
// transcript to commit its settled prefix.
|
|
780
|
-
provisionalPendingPreview: "collapsed",
|
|
781
|
-
// Partial-result chrome is NOT byte-stable: `renderAgentProgressEvents`
|
|
782
|
-
// inserts/removes each subagent's current-tool line as it starts/stops a
|
|
783
|
-
// tool, and ticks status icon/stats/duration on already-rendered rows,
|
|
784
|
-
// while `options.isPartial` holds for the whole eval() cell (agent
|
|
785
|
-
// progress ticks never carry an `async` completed/failed state, so
|
|
786
|
-
// `event-controller.ts` keeps `isPartial: true` throughout). If this
|
|
787
|
-
// block were commit-stable during that churn, `deriveLiveCommitState`'s
|
|
788
|
-
// stable-prefix ratchet would promote agent rows that keep mutating (a
|
|
789
|
-
// "slow ticker", see transcript-container.ts) into native scrollback,
|
|
790
|
-
// and the tui resync's "duplication, never loss" contract would
|
|
791
|
-
// repeatedly re-show the frame tail under a heavy concurrent
|
|
792
|
-
// `agent()`/`parallel()` fan-out — the overlapping/duplicated tree rows
|
|
793
|
-
// seen when many subagents run at once. Once the cell settles
|
|
794
|
-
// (`isPartial === false`) the block is commit-stable again.
|
|
795
|
-
provisionalPartialResult: true,
|
|
796
776
|
};
|
package/src/tools/grep.ts
CHANGED
|
@@ -750,6 +750,11 @@ async function resolveInternalSearchInputs(opts: {
|
|
|
750
750
|
localProtocolOptions: opts.localProtocolOptions,
|
|
751
751
|
skills: opts.skills,
|
|
752
752
|
skipDirectoryListing: true,
|
|
753
|
+
// Try path-only first so large artifacts (and any other handler that
|
|
754
|
+
// separates path from content) resolve without materializing bytes.
|
|
755
|
+
// Handlers that ignore the flag still return content, and virtual
|
|
756
|
+
// resources without a sourcePath fall through to a second resolve.
|
|
757
|
+
pathOnly: true,
|
|
753
758
|
};
|
|
754
759
|
|
|
755
760
|
for (let idx = 0; idx < paths.length; idx++) {
|
|
@@ -764,7 +769,7 @@ async function resolveInternalSearchInputs(opts: {
|
|
|
764
769
|
if (hasGlobPathChars(globTarget)) {
|
|
765
770
|
throw new ToolError(`Glob patterns are not supported for internal URLs: ${rawPath}`);
|
|
766
771
|
}
|
|
767
|
-
|
|
772
|
+
let resource = await internalRouter.resolve(rawPath, context);
|
|
768
773
|
// A directory listing with no backing local path (e.g. a remote ssh:// dir)
|
|
769
774
|
// has no real contents to grep — searching its listing text would be
|
|
770
775
|
// misleading. Local/skill/vault dir resources set `sourcePath` and skip this.
|
|
@@ -781,8 +786,20 @@ async function resolveInternalSearchInputs(opts: {
|
|
|
781
786
|
continue;
|
|
782
787
|
}
|
|
783
788
|
|
|
789
|
+
// No sourcePath: this handler needs its content materialized so the
|
|
790
|
+
// virtual expansion can search it. Re-resolve without pathOnly.
|
|
791
|
+
if (context.pathOnly) {
|
|
792
|
+
resource = await internalRouter.resolve(rawPath, { ...context, pathOnly: false });
|
|
793
|
+
}
|
|
794
|
+
|
|
784
795
|
const ranges = opts.pathSpecs[idx]?.ranges;
|
|
785
|
-
const expanded = await expandVirtualInternalResource(
|
|
796
|
+
const expanded = await expandVirtualInternalResource(
|
|
797
|
+
rawPath,
|
|
798
|
+
resource,
|
|
799
|
+
internalRouter,
|
|
800
|
+
{ ...context, pathOnly: false },
|
|
801
|
+
ranges,
|
|
802
|
+
);
|
|
786
803
|
virtualInputIndexes.add(idx);
|
|
787
804
|
for (const virtual of expanded) {
|
|
788
805
|
virtualResources.push(virtual);
|
package/src/tools/path-utils.ts
CHANGED
|
@@ -1201,6 +1201,10 @@ export async function resolveToolSearchScope(opts: ToolScopeOptions): Promise<To
|
|
|
1201
1201
|
signal: opts.signal,
|
|
1202
1202
|
localProtocolOptions: opts.localProtocolOptions,
|
|
1203
1203
|
skills: opts.skills,
|
|
1204
|
+
// Tool-scope resolution only needs `sourcePath`; skip content
|
|
1205
|
+
// materialization so large artifacts (or any handler that separates
|
|
1206
|
+
// path from content) stay searchable without OOM risk.
|
|
1207
|
+
pathOnly: true,
|
|
1204
1208
|
});
|
|
1205
1209
|
if (!resource.sourcePath) {
|
|
1206
1210
|
throw new ToolError(`Cannot ${internalUrlAction} internal URL without a backing file: ${rawPath}`);
|