@narumitw/pi-subagents 0.43.0 → 0.46.0
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/README.md +53 -13
- package/package.json +1 -1
- package/src/agents.ts +16 -0
- package/src/config-ui.ts +151 -20
- package/src/consult-render.ts +194 -0
- package/src/consult.ts +164 -37
- package/src/cwd-policy.ts +183 -0
- package/src/execution.ts +127 -64
- package/src/in-process-transport.ts +3 -3
- package/src/inspect-render.ts +234 -0
- package/src/inspect.ts +51 -3
- package/src/persistence.ts +29 -0
- package/src/pi-invocation.ts +168 -0
- package/src/registry.ts +12 -0
- package/src/render-common.ts +252 -0
- package/src/render.ts +134 -99
- package/src/runner.ts +19 -22
- package/src/settings.ts +111 -11
- package/src/stateful-guidance.ts +35 -0
- package/src/stateful-lifecycle.ts +31 -0
- package/src/stateful-render.ts +249 -0
- package/src/stateful-safety.ts +91 -0
- package/src/stateful.ts +235 -218
- package/src/subagents.ts +60 -18
- package/src/subprocess-transport.ts +19 -2
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { getAgentDir, ProjectTrustStore } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import type { ConsultationCwdPolicy, DelegationCwdPolicy } from "./agents.js";
|
|
5
|
+
import { safeTerminalLine } from "./safe-text.js";
|
|
6
|
+
|
|
7
|
+
export type TargetBoundary = "current-workspace" | "external";
|
|
8
|
+
export type TargetTrustKind =
|
|
9
|
+
| "session-trusted"
|
|
10
|
+
| "session-untrusted"
|
|
11
|
+
| "saved-trusted"
|
|
12
|
+
| "saved-denied"
|
|
13
|
+
| "unsaved"
|
|
14
|
+
| "trust-error";
|
|
15
|
+
|
|
16
|
+
export interface ResolvedTargetTrust {
|
|
17
|
+
kind: TargetTrustKind;
|
|
18
|
+
projectTrusted: boolean;
|
|
19
|
+
sourcePath?: string;
|
|
20
|
+
warning?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ResolvedSubagentTarget {
|
|
24
|
+
cwd: string;
|
|
25
|
+
workspace: string;
|
|
26
|
+
boundary: TargetBoundary;
|
|
27
|
+
trust: ResolvedTargetTrust;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface TargetPolicyAudit {
|
|
31
|
+
cwd: string;
|
|
32
|
+
boundary: TargetBoundary;
|
|
33
|
+
trust: {
|
|
34
|
+
kind: TargetTrustKind;
|
|
35
|
+
projectTrusted: boolean;
|
|
36
|
+
sourcePath?: string;
|
|
37
|
+
warning?: string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function targetPolicyAudit(target: ResolvedSubagentTarget): TargetPolicyAudit {
|
|
42
|
+
return {
|
|
43
|
+
cwd: safeTerminalLine(target.cwd),
|
|
44
|
+
boundary: target.boundary,
|
|
45
|
+
trust: {
|
|
46
|
+
...target.trust,
|
|
47
|
+
sourcePath: target.trust.sourcePath ? safeTerminalLine(target.trust.sourcePath) : undefined,
|
|
48
|
+
warning: target.trust.warning ? safeTerminalLine(target.trust.warning, 512) : undefined,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ResolveSubagentTargetOptions {
|
|
54
|
+
workspace: string;
|
|
55
|
+
requestedCwd?: string;
|
|
56
|
+
currentProjectTrusted: boolean;
|
|
57
|
+
agentDir?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function resolveSubagentTarget(
|
|
61
|
+
options: ResolveSubagentTargetOptions,
|
|
62
|
+
): ResolvedSubagentTarget {
|
|
63
|
+
const workspace = canonicalDirectory(options.workspace, "Current workspace");
|
|
64
|
+
const requested = path.resolve(options.workspace, options.requestedCwd ?? options.workspace);
|
|
65
|
+
const cwd = canonicalDirectory(requested, "Subagent working directory");
|
|
66
|
+
const boundary: TargetBoundary = isEqualOrDescendant(cwd, workspace)
|
|
67
|
+
? "current-workspace"
|
|
68
|
+
: "external";
|
|
69
|
+
if (boundary === "current-workspace") {
|
|
70
|
+
return {
|
|
71
|
+
cwd,
|
|
72
|
+
workspace,
|
|
73
|
+
boundary,
|
|
74
|
+
trust: {
|
|
75
|
+
kind: options.currentProjectTrusted ? "session-trusted" : "session-untrusted",
|
|
76
|
+
projectTrusted: options.currentProjectTrusted,
|
|
77
|
+
sourcePath: workspace,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const entry = new ProjectTrustStore(options.agentDir ?? getAgentDir()).getEntry(cwd);
|
|
83
|
+
if (!entry) {
|
|
84
|
+
return {
|
|
85
|
+
cwd,
|
|
86
|
+
workspace,
|
|
87
|
+
boundary,
|
|
88
|
+
trust: { kind: "unsaved", projectTrusted: false },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
cwd,
|
|
93
|
+
workspace,
|
|
94
|
+
boundary,
|
|
95
|
+
trust: {
|
|
96
|
+
kind: entry.decision ? "saved-trusted" : "saved-denied",
|
|
97
|
+
projectTrusted: entry.decision,
|
|
98
|
+
sourcePath: entry.path,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
} catch {
|
|
102
|
+
return {
|
|
103
|
+
cwd,
|
|
104
|
+
workspace,
|
|
105
|
+
boundary,
|
|
106
|
+
trust: {
|
|
107
|
+
kind: "trust-error",
|
|
108
|
+
projectTrusted: false,
|
|
109
|
+
warning: safeTerminalLine(
|
|
110
|
+
"Could not resolve Pi trust store; protected target resources were disabled. Repair trust with Pi /trust and restart Pi.",
|
|
111
|
+
512,
|
|
112
|
+
),
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function assertConsultationTargetAllowed(
|
|
119
|
+
target: ResolvedSubagentTarget,
|
|
120
|
+
policy: ConsultationCwdPolicy,
|
|
121
|
+
): void {
|
|
122
|
+
if (policy === "current-workspace" && target.boundary !== "current-workspace") {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`Read-only consultation target is outside the current workspace: ${safeTerminalLine(target.cwd)}`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function assertDelegationTargetAllowed(
|
|
130
|
+
target: ResolvedSubagentTarget,
|
|
131
|
+
policy: DelegationCwdPolicy,
|
|
132
|
+
): void {
|
|
133
|
+
if (target.boundary === "current-workspace" || policy === "anywhere") return;
|
|
134
|
+
if (policy === "trusted-targets" && target.trust.kind === "saved-trusted") return;
|
|
135
|
+
if (policy === "current-workspace") {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`General delegation target is outside the current workspace: ${safeTerminalLine(target.cwd)}`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
const reason =
|
|
141
|
+
target.trust.kind === "trust-error"
|
|
142
|
+
? target.trust.warning
|
|
143
|
+
: `Target trust is ${target.trust.kind}.`;
|
|
144
|
+
throw new Error(
|
|
145
|
+
[
|
|
146
|
+
`General delegation target is not a saved-trusted folder: ${safeTerminalLine(target.cwd)}`,
|
|
147
|
+
reason,
|
|
148
|
+
"Open Pi in that folder, manage trust with /trust, restart Pi, or choose Anywhere in /subagents settings.",
|
|
149
|
+
]
|
|
150
|
+
.filter(Boolean)
|
|
151
|
+
.join(" "),
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function canonicalDirectory(value: string, label: string): string {
|
|
156
|
+
let canonical: string;
|
|
157
|
+
try {
|
|
158
|
+
canonical = fs.realpathSync(value);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
161
|
+
throw new Error(`${label} does not exist: ${safeTerminalLine(value)}`);
|
|
162
|
+
}
|
|
163
|
+
throw new Error(
|
|
164
|
+
`${label} cannot be resolved: ${safeTerminalLine(value)}: ${formatError(error)}`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
if (!fs.statSync(canonical).isDirectory()) {
|
|
168
|
+
throw new Error(`${label} is not a directory: ${safeTerminalLine(canonical)}`);
|
|
169
|
+
}
|
|
170
|
+
return canonical;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function isEqualOrDescendant(candidate: string, workspace: string): boolean {
|
|
174
|
+
const relative = path.relative(workspace, candidate);
|
|
175
|
+
return (
|
|
176
|
+
relative === "" ||
|
|
177
|
+
(!relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative))
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function formatError(error: unknown): string {
|
|
182
|
+
return error instanceof Error ? error.message : String(error);
|
|
183
|
+
}
|
package/src/execution.ts
CHANGED
|
@@ -4,8 +4,15 @@ import {
|
|
|
4
4
|
type AgentConfig,
|
|
5
5
|
type AgentScope,
|
|
6
6
|
discoverAgents,
|
|
7
|
+
type SubagentSettings,
|
|
7
8
|
type SubagentThinkingLevel,
|
|
8
9
|
} from "./agents.js";
|
|
10
|
+
import {
|
|
11
|
+
assertDelegationTargetAllowed,
|
|
12
|
+
type ResolvedSubagentTarget,
|
|
13
|
+
resolveSubagentTarget,
|
|
14
|
+
targetPolicyAudit,
|
|
15
|
+
} from "./cwd-policy.js";
|
|
9
16
|
import { DEFAULT_MAX_CONTEXT_BYTES, truncateUtf8 } from "./limits.js";
|
|
10
17
|
import { hasUsableAggregator, type SubagentParams } from "./params.js";
|
|
11
18
|
import {
|
|
@@ -20,7 +27,11 @@ import {
|
|
|
20
27
|
type SubagentDetails,
|
|
21
28
|
} from "./runner.js";
|
|
22
29
|
import { safeTerminalLine } from "./safe-text.js";
|
|
23
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
DEFAULT_DELEGATION_CWD_POLICY,
|
|
32
|
+
readSubagentSettings,
|
|
33
|
+
resolveSubagentThinkingLevel,
|
|
34
|
+
} from "./settings.js";
|
|
24
35
|
|
|
25
36
|
const MAX_PARALLEL_TASKS = 8;
|
|
26
37
|
const MAX_CONCURRENCY = 4;
|
|
@@ -105,6 +116,7 @@ export async function executeSubagent(
|
|
|
105
116
|
signal: AbortSignal | undefined,
|
|
106
117
|
onUpdate: AgentToolUpdateCallback<SubagentDetails> | undefined,
|
|
107
118
|
ctx: ExtensionContext,
|
|
119
|
+
settingsOverride?: SubagentSettings,
|
|
108
120
|
): Promise<AgentToolResult<SubagentDetails> & { isError?: boolean }> {
|
|
109
121
|
assertSubagentDepthAllowed();
|
|
110
122
|
const agentScope: AgentScope = params.agentScope ?? "user";
|
|
@@ -112,7 +124,7 @@ export async function executeSubagent(
|
|
|
112
124
|
throw new Error("Project-local subagent definitions require a trusted project");
|
|
113
125
|
}
|
|
114
126
|
const aggregator = hasUsableAggregator(params.aggregator) ? params.aggregator : undefined;
|
|
115
|
-
const config = readSubagentSettings();
|
|
127
|
+
const config = settingsOverride ?? readSubagentSettings();
|
|
116
128
|
const discovery = discoverAgents(ctx.cwd, agentScope, config);
|
|
117
129
|
const agents = discovery.agents;
|
|
118
130
|
const confirmProjectAgents = params.confirmProjectAgents ?? true;
|
|
@@ -156,6 +168,28 @@ export async function executeSubagent(
|
|
|
156
168
|
};
|
|
157
169
|
}
|
|
158
170
|
|
|
171
|
+
const delegationPolicy = config?.cwdPolicy?.delegation ?? DEFAULT_DELEGATION_CWD_POLICY;
|
|
172
|
+
const resolveTarget = (cwd: string | undefined): ResolvedSubagentTarget => {
|
|
173
|
+
const target = resolveSubagentTarget({
|
|
174
|
+
workspace: ctx.cwd,
|
|
175
|
+
requestedCwd: cwd,
|
|
176
|
+
currentProjectTrusted: ctx.isProjectTrusted(),
|
|
177
|
+
});
|
|
178
|
+
assertDelegationTargetAllowed(target, delegationPolicy);
|
|
179
|
+
return target;
|
|
180
|
+
};
|
|
181
|
+
const singleTarget = hasSingle ? resolveTarget(params.cwd) : undefined;
|
|
182
|
+
const chainTargets = params.chain?.map((step) => resolveTarget(step.cwd)) ?? [];
|
|
183
|
+
const parallelTargets = params.tasks?.map((task) => resolveTarget(task.cwd)) ?? [];
|
|
184
|
+
const aggregatorTarget = aggregator ? resolveTarget(aggregator.cwd) : undefined;
|
|
185
|
+
const attachTarget = (result: SingleResult, target: ResolvedSubagentTarget): SingleResult => {
|
|
186
|
+
result.target = targetPolicyAudit(target);
|
|
187
|
+
return result;
|
|
188
|
+
};
|
|
189
|
+
const launchPolicy = (target: ResolvedSubagentTarget) => ({
|
|
190
|
+
projectTrust: target.trust.projectTrusted,
|
|
191
|
+
});
|
|
192
|
+
|
|
159
193
|
if (agentScope === "project" || agentScope === "both") {
|
|
160
194
|
const requestedAgentNames = new Set<string>();
|
|
161
195
|
if (params.chain) for (const step of params.chain) requestedAgentNames.add(step.agent);
|
|
@@ -180,6 +214,11 @@ export async function executeSubagent(
|
|
|
180
214
|
"Run project-local agents?",
|
|
181
215
|
`Agents: ${names}\nSource: ${dir}\n\nProject agents are repo-controlled. Only continue for trusted repositories.`,
|
|
182
216
|
);
|
|
217
|
+
if (signal?.aborted) {
|
|
218
|
+
const error = new Error("Subagent call was aborted during project-agent confirmation");
|
|
219
|
+
error.name = "AbortError";
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
183
222
|
if (!ok) {
|
|
184
223
|
return {
|
|
185
224
|
content: [{ type: "text", text: "Canceled: project-local agents not approved." }],
|
|
@@ -219,18 +258,24 @@ export async function executeSubagent(
|
|
|
219
258
|
}
|
|
220
259
|
: undefined;
|
|
221
260
|
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
261
|
+
const target = chainTargets[i];
|
|
262
|
+
const result = attachTarget(
|
|
263
|
+
await runSingleAgent(
|
|
264
|
+
ctx.cwd,
|
|
265
|
+
agents,
|
|
266
|
+
step.agent,
|
|
267
|
+
taskWithContext,
|
|
268
|
+
target.cwd,
|
|
269
|
+
i + 1,
|
|
270
|
+
signal,
|
|
271
|
+
resolveThinkingLevel(step.agent, step.thinkingLevel),
|
|
272
|
+
resolveTimeoutMs(step.agent, step.timeoutMs),
|
|
273
|
+
chainUpdate,
|
|
274
|
+
makeDetails("chain"),
|
|
275
|
+
undefined,
|
|
276
|
+
launchPolicy(target),
|
|
277
|
+
),
|
|
278
|
+
target,
|
|
234
279
|
);
|
|
235
280
|
results.push(result);
|
|
236
281
|
|
|
@@ -352,24 +397,30 @@ export async function executeSubagent(
|
|
|
352
397
|
params.tasks,
|
|
353
398
|
MAX_CONCURRENCY,
|
|
354
399
|
async (t, index) => {
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
400
|
+
const target = parallelTargets[index];
|
|
401
|
+
const result = attachTarget(
|
|
402
|
+
await runSingleAgent(
|
|
403
|
+
ctx.cwd,
|
|
404
|
+
agents,
|
|
405
|
+
t.agent,
|
|
406
|
+
t.task,
|
|
407
|
+
target.cwd,
|
|
408
|
+
undefined,
|
|
409
|
+
signal,
|
|
410
|
+
resolveThinkingLevel(t.agent, t.thinkingLevel),
|
|
411
|
+
resolveTimeoutMs(t.agent, t.timeoutMs),
|
|
412
|
+
// Per-task update callback
|
|
413
|
+
(partial) => {
|
|
414
|
+
if (partial.details?.results[0]) {
|
|
415
|
+
allResults[index] = { ...partial.details.results[0], exitCode: -1 };
|
|
416
|
+
emitParallelUpdate();
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
makeDetails("parallel"),
|
|
420
|
+
undefined,
|
|
421
|
+
launchPolicy(target),
|
|
422
|
+
),
|
|
423
|
+
target,
|
|
373
424
|
);
|
|
374
425
|
allResults[index] = result;
|
|
375
426
|
doneCount += 1;
|
|
@@ -405,26 +456,32 @@ export async function executeSubagent(
|
|
|
405
456
|
: `${aggregator.task}\n\nParallel task outputs:\n\n${fanInContext}`,
|
|
406
457
|
DEFAULT_MAX_CONTEXT_BYTES,
|
|
407
458
|
).text;
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
459
|
+
const target = aggregatorTarget as ResolvedSubagentTarget;
|
|
460
|
+
aggregatorResult = attachTarget(
|
|
461
|
+
await runSingleAgent(
|
|
462
|
+
ctx.cwd,
|
|
463
|
+
agents,
|
|
464
|
+
aggregator.agent,
|
|
465
|
+
aggregatorTask,
|
|
466
|
+
target.cwd,
|
|
467
|
+
undefined,
|
|
468
|
+
signal,
|
|
469
|
+
resolveThinkingLevel(aggregator.agent, aggregator.thinkingLevel),
|
|
470
|
+
resolveTimeoutMs(aggregator.agent, aggregator.timeoutMs),
|
|
471
|
+
(partial) => {
|
|
472
|
+
status.update(fanInStatus(aggregator.agent));
|
|
473
|
+
if (onUpdate && partial.details?.results[0]) {
|
|
474
|
+
onUpdate({
|
|
475
|
+
content: partial.content,
|
|
476
|
+
details: makeDetails("parallel")(results, partial.details.results[0]),
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
makeDetails("parallel"),
|
|
481
|
+
undefined,
|
|
482
|
+
launchPolicy(target),
|
|
483
|
+
),
|
|
484
|
+
target,
|
|
428
485
|
);
|
|
429
486
|
}
|
|
430
487
|
|
|
@@ -469,18 +526,24 @@ export async function executeSubagent(
|
|
|
469
526
|
const status = startSubagentStatus(ctx, toolCallId, singleStatus(params.agent));
|
|
470
527
|
|
|
471
528
|
try {
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
529
|
+
const target = singleTarget as ResolvedSubagentTarget;
|
|
530
|
+
const result = attachTarget(
|
|
531
|
+
await runSingleAgent(
|
|
532
|
+
ctx.cwd,
|
|
533
|
+
agents,
|
|
534
|
+
params.agent,
|
|
535
|
+
params.task,
|
|
536
|
+
target.cwd,
|
|
537
|
+
undefined,
|
|
538
|
+
signal,
|
|
539
|
+
resolveThinkingLevel(params.agent, params.thinkingLevel),
|
|
540
|
+
resolveTimeoutMs(params.agent, params.timeoutMs),
|
|
541
|
+
onUpdate,
|
|
542
|
+
makeDetails("single"),
|
|
543
|
+
undefined,
|
|
544
|
+
launchPolicy(target),
|
|
545
|
+
),
|
|
546
|
+
target,
|
|
484
547
|
);
|
|
485
548
|
const isError = isResultError(result);
|
|
486
549
|
if (isError) {
|
|
@@ -339,7 +339,8 @@ export async function createSdkChildSession(
|
|
|
339
339
|
options.agent.cwd,
|
|
340
340
|
agentDir,
|
|
341
341
|
options.agentConfig.systemPrompt,
|
|
342
|
-
options.agent.
|
|
342
|
+
options.agent.target?.trust.projectTrusted ??
|
|
343
|
+
(options.agent.agentScope === "project" || options.agent.agentScope === "both"),
|
|
343
344
|
);
|
|
344
345
|
const resolved = await resolveChildModel(options);
|
|
345
346
|
const modelRuntime = await createChildModelRuntime(
|
|
@@ -508,8 +509,7 @@ export async function createInProcessResourceLoader(
|
|
|
508
509
|
agentSystemPrompt: string,
|
|
509
510
|
projectTrusted = false,
|
|
510
511
|
): Promise<{ loader: DefaultResourceLoader; settingsManager: SettingsManager }> {
|
|
511
|
-
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
512
|
-
settingsManager.setProjectTrusted(projectTrusted);
|
|
512
|
+
const settingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted });
|
|
513
513
|
const loader = new DefaultResourceLoader({
|
|
514
514
|
cwd,
|
|
515
515
|
agentDir,
|