pi-subagents 0.41.0 → 0.42.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/CHANGELOG.md +21 -0
- package/README.md +54 -1600
- package/inspector-runner.mjs +11 -0
- package/package.json +3 -3
- package/skills/pi-subagents/SKILL.md +5 -3
- package/skills/pi-subagents/references/constraints-and-recipes.md +5 -6
- package/skills/pi-subagents/references/execution-controls.md +6 -5
- package/skills/pi-subagents/references/prompting-and-roles.md +5 -3
- package/src/extension/schemas.ts +1 -1
- package/src/inspectors/herdr/actions.ts +2 -2
- package/src/missions/actions.ts +7 -5
- package/src/runs/background/async-execution.ts +12 -1
- package/src/runs/background/async-job-tracker.ts +17 -2
- package/src/runs/foreground/execution.ts +19 -7
- package/src/runs/foreground/subagent-executor.ts +16 -4
- package/src/runs/shared/acceptance.ts +2 -2
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +2 -0
- package/src/runs/shared/pi-args.ts +465 -116
- package/src/shared/artifacts.ts +125 -0
- package/src/tui/fleet.ts +1 -1
- package/src/tui/render.ts +77 -43
- package/src/types/pi-runtime-compat.d.ts +0 -6
|
@@ -3,41 +3,99 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
encodeNestedPathEnv,
|
|
8
|
+
parseNestedPathEnv,
|
|
9
|
+
type NestedPathEntry,
|
|
10
|
+
} from "./nested-path.ts";
|
|
11
|
+
import {
|
|
12
|
+
resolveMcpDirectToolSelections,
|
|
13
|
+
type ResolvedMcpDirectToolSelection,
|
|
14
|
+
} from "./mcp-direct-tool-allowlist.ts";
|
|
8
15
|
import { resolvePiPackageRoot } from "./pi-spawn.ts";
|
|
9
16
|
import { RUNTIME_EXTENSION_ACK_PATH_ENV } from "./runtime-acknowledged-extensions.ts";
|
|
10
|
-
import {
|
|
11
|
-
|
|
17
|
+
import {
|
|
18
|
+
STRUCTURED_OUTPUT_CAPTURE_ENV,
|
|
19
|
+
STRUCTURED_OUTPUT_SCHEMA_ENV,
|
|
20
|
+
} from "./structured-output.ts";
|
|
21
|
+
import {
|
|
22
|
+
TEMP_ROOT_DIR,
|
|
23
|
+
type JsonSchemaObject,
|
|
24
|
+
type LaunchResolvedChildExtensionsV1,
|
|
25
|
+
type ResolvedToolBudget,
|
|
26
|
+
} from "../../shared/types.ts";
|
|
12
27
|
import { THINKING_LEVELS } from "../../shared/model-info.ts";
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
28
|
+
import {
|
|
29
|
+
TOOL_BUDGET_ENV,
|
|
30
|
+
TOOL_BUDGET_ZERO_AUTH_ENV,
|
|
31
|
+
encodeToolBudgetEnv,
|
|
32
|
+
} from "./tool-budget.ts";
|
|
33
|
+
import {
|
|
34
|
+
CHILD_TOOL_DIAGNOSTIC_PATH_ENV,
|
|
35
|
+
MCP_DIRECT_CHILD_TOOLS_ENV,
|
|
36
|
+
REQUIRED_CHILD_TOOLS_ENV,
|
|
37
|
+
} from "./tool-availability.ts";
|
|
38
|
+
import {
|
|
39
|
+
CHILD_WATCHDOG_CONFIG_ENV,
|
|
40
|
+
encodeChildWatchdogConfig,
|
|
41
|
+
type ChildWatchdogConfig,
|
|
42
|
+
} from "../../watchdog/child-status.ts";
|
|
16
43
|
import { WAIT_TOOL_ENABLED_ENV } from "../background/wait-config.ts";
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
44
|
+
import {
|
|
45
|
+
PI_CODING_AGENT_PACKAGE_ROOT_ENV,
|
|
46
|
+
getAgentDir,
|
|
47
|
+
} from "../../shared/utils.ts";
|
|
48
|
+
import {
|
|
49
|
+
encodePermissionRules,
|
|
50
|
+
PERMISSION_AUDIT_PATH_ENV,
|
|
51
|
+
PERMISSION_POLICY_ENV,
|
|
52
|
+
type PermissionRules,
|
|
53
|
+
} from "./permissions.ts";
|
|
54
|
+
import {
|
|
55
|
+
SUBAGENT_CAPABILITY_CEILING_ENV,
|
|
56
|
+
capabilityCeilingAgentRestrictionSources,
|
|
57
|
+
decodeSubagentCapabilityCeiling,
|
|
58
|
+
encodeSubagentCapabilityCeiling,
|
|
59
|
+
intersectSubagentCapabilityCeilings,
|
|
60
|
+
isAgentAllowedByCapabilityCeiling,
|
|
61
|
+
type ResolvedSubagentCapabilityCeiling,
|
|
62
|
+
type SubagentCapabilityAudit,
|
|
63
|
+
} from "./capability-ceiling.ts";
|
|
20
64
|
|
|
21
65
|
const TASK_ARG_LIMIT = 8000;
|
|
22
66
|
const MAX_LAUNCH_RESOLVED_EXTENSION_IDS = 32;
|
|
23
|
-
const PROMPT_RUNTIME_EXTENSION_PATH = path.join(
|
|
24
|
-
|
|
67
|
+
const PROMPT_RUNTIME_EXTENSION_PATH = path.join(
|
|
68
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
69
|
+
"subagent-prompt-runtime.ts",
|
|
70
|
+
);
|
|
71
|
+
const FANOUT_CHILD_EXTENSION_PATH = path.join(
|
|
72
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
73
|
+
"..",
|
|
74
|
+
"..",
|
|
75
|
+
"extension",
|
|
76
|
+
"fanout-child.ts",
|
|
77
|
+
);
|
|
25
78
|
export const SUBAGENT_CHILD_ENV = "PI_SUBAGENT_CHILD";
|
|
26
|
-
export const SUBAGENT_ORCHESTRATOR_TARGET_ENV =
|
|
27
|
-
|
|
28
|
-
export const
|
|
79
|
+
export const SUBAGENT_ORCHESTRATOR_TARGET_ENV =
|
|
80
|
+
"PI_SUBAGENT_ORCHESTRATOR_TARGET";
|
|
81
|
+
export const SUBAGENT_ORCHESTRATOR_SESSION_ID_ENV =
|
|
82
|
+
"PI_SUBAGENT_ORCHESTRATOR_SESSION_ID";
|
|
83
|
+
export const SUBAGENT_SUPERVISOR_CHANNEL_DIR_ENV =
|
|
84
|
+
"PI_SUBAGENT_SUPERVISOR_CHANNEL_DIR";
|
|
29
85
|
export const SUBAGENT_RUN_ID_ENV = "PI_SUBAGENT_RUN_ID";
|
|
30
86
|
export const SUBAGENT_CHILD_AGENT_ENV = "PI_SUBAGENT_CHILD_AGENT";
|
|
31
87
|
export const SUBAGENT_CHILD_INDEX_ENV = "PI_SUBAGENT_CHILD_INDEX";
|
|
32
88
|
export const SUBAGENT_FANOUT_CHILD_ENV = "PI_SUBAGENT_FANOUT_CHILD";
|
|
33
89
|
export const SUBAGENT_PARENT_EVENT_SINK_ENV = "PI_SUBAGENT_PARENT_EVENT_SINK";
|
|
34
|
-
export const SUBAGENT_PARENT_CONTROL_INBOX_ENV =
|
|
90
|
+
export const SUBAGENT_PARENT_CONTROL_INBOX_ENV =
|
|
91
|
+
"PI_SUBAGENT_PARENT_CONTROL_INBOX";
|
|
35
92
|
export const SUBAGENT_PARENT_ROOT_RUN_ID_ENV = "PI_SUBAGENT_PARENT_ROOT_RUN_ID";
|
|
36
93
|
export const SUBAGENT_PARENT_RUN_ID_ENV = "PI_SUBAGENT_PARENT_RUN_ID";
|
|
37
94
|
export const SUBAGENT_PARENT_CHILD_INDEX_ENV = "PI_SUBAGENT_PARENT_CHILD_INDEX";
|
|
38
95
|
export const SUBAGENT_PARENT_DEPTH_ENV = "PI_SUBAGENT_PARENT_DEPTH";
|
|
39
96
|
export const SUBAGENT_PARENT_PATH_ENV = "PI_SUBAGENT_PARENT_PATH";
|
|
40
|
-
export const SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV =
|
|
97
|
+
export const SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV =
|
|
98
|
+
"PI_SUBAGENT_PARENT_CAPABILITY_TOKEN";
|
|
41
99
|
export const SUBAGENT_PARENT_SESSION_ENV = "PI_SUBAGENT_PARENT_SESSION";
|
|
42
100
|
export const SUBAGENT_STEER_INBOX_ENV = "PI_SUBAGENT_STEER_INBOX";
|
|
43
101
|
export const SUBAGENT_STEER_CAPABILITY_ENV = "PI_SUBAGENT_STEER_CAPABILITY";
|
|
@@ -105,17 +163,37 @@ export interface BuildPiArgsResult {
|
|
|
105
163
|
}
|
|
106
164
|
|
|
107
165
|
function sanitizeSupervisorChannelSegment(value: string): string {
|
|
108
|
-
return
|
|
166
|
+
return (
|
|
167
|
+
value
|
|
168
|
+
.trim()
|
|
169
|
+
.replace(/[^A-Za-z0-9._-]+/g, "-")
|
|
170
|
+
.replace(/^-+|-+$/g, "") || "unknown"
|
|
171
|
+
);
|
|
109
172
|
}
|
|
110
173
|
|
|
111
|
-
function supervisorChannelDir(
|
|
112
|
-
|
|
174
|
+
function supervisorChannelDir(
|
|
175
|
+
runId: string,
|
|
176
|
+
agent: string,
|
|
177
|
+
childIndex: number,
|
|
178
|
+
): string {
|
|
179
|
+
return path.join(
|
|
180
|
+
TEMP_ROOT_DIR,
|
|
181
|
+
"supervisor-channels",
|
|
182
|
+
`${sanitizeSupervisorChannelSegment(runId)}-${sanitizeSupervisorChannelSegment(agent)}-${childIndex}`,
|
|
183
|
+
);
|
|
113
184
|
}
|
|
114
185
|
|
|
115
|
-
export function applyThinkingSuffix(
|
|
186
|
+
export function applyThinkingSuffix(
|
|
187
|
+
model: string | undefined,
|
|
188
|
+
thinking: string | false | undefined,
|
|
189
|
+
replaceExisting = false,
|
|
190
|
+
): string | undefined {
|
|
116
191
|
if (!model || !thinking) return model;
|
|
117
192
|
const colonIdx = model.lastIndexOf(":");
|
|
118
|
-
if (
|
|
193
|
+
if (
|
|
194
|
+
colonIdx !== -1 &&
|
|
195
|
+
THINKING_LEVELS.some((level) => level === model.substring(colonIdx + 1))
|
|
196
|
+
) {
|
|
119
197
|
return replaceExisting ? `${model.slice(0, colonIdx)}:${thinking}` : model;
|
|
120
198
|
}
|
|
121
199
|
return `${model}:${thinking}`;
|
|
@@ -128,11 +206,13 @@ export interface ResolvePiLaunchToolPlanInput {
|
|
|
128
206
|
mcpDirectTools?: string[];
|
|
129
207
|
cwd?: string;
|
|
130
208
|
requireReadTool?: boolean;
|
|
131
|
-
structuredOutput?:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
209
|
+
structuredOutput?:
|
|
210
|
+
| boolean
|
|
211
|
+
| {
|
|
212
|
+
schema: JsonSchemaObject;
|
|
213
|
+
schemaPath: string;
|
|
214
|
+
outputPath: string;
|
|
215
|
+
};
|
|
136
216
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
137
217
|
inheritedCapabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
138
218
|
agentName?: string;
|
|
@@ -162,7 +242,10 @@ function extensionIdentifier(value: string): string {
|
|
|
162
242
|
return `sha256:${createHash("sha256").update(path.normalize(value.trim())).digest("hex").slice(0, 16)}`;
|
|
163
243
|
}
|
|
164
244
|
|
|
165
|
-
function boundedExtensionIdentifiers(values: string[]): {
|
|
245
|
+
function boundedExtensionIdentifiers(values: string[]): {
|
|
246
|
+
ids: string[];
|
|
247
|
+
omitted: number;
|
|
248
|
+
} {
|
|
166
249
|
const ids = [...new Set(values.map(extensionIdentifier))];
|
|
167
250
|
return {
|
|
168
251
|
ids: ids.slice(0, MAX_LAUNCH_RESOLVED_EXTENSION_IDS),
|
|
@@ -170,7 +253,15 @@ function boundedExtensionIdentifiers(values: string[]): { ids: string[]; omitted
|
|
|
170
253
|
};
|
|
171
254
|
}
|
|
172
255
|
|
|
173
|
-
export function projectLaunchResolvedChildExtensions(
|
|
256
|
+
export function projectLaunchResolvedChildExtensions(
|
|
257
|
+
toolPlan: Pick<
|
|
258
|
+
PiLaunchToolPlan,
|
|
259
|
+
| "runtimeExtensions"
|
|
260
|
+
| "configuredExtensions"
|
|
261
|
+
| "extensionArgs"
|
|
262
|
+
| "disableAmbientExtensions"
|
|
263
|
+
>,
|
|
264
|
+
): LaunchResolvedChildExtensionsV1 {
|
|
174
265
|
const runtime = boundedExtensionIdentifiers(toolPlan.runtimeExtensions);
|
|
175
266
|
const configured = boundedExtensionIdentifiers(toolPlan.configuredExtensions);
|
|
176
267
|
const effective = boundedExtensionIdentifiers(toolPlan.extensionArgs);
|
|
@@ -189,55 +280,207 @@ export function projectLaunchResolvedChildExtensions(toolPlan: Pick<PiLaunchTool
|
|
|
189
280
|
};
|
|
190
281
|
}
|
|
191
282
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
283
|
+
/**
|
|
284
|
+
* Resolve the permission-system extension entry point when installed.
|
|
285
|
+
* Returns the absolute path to the extension's main module, or undefined
|
|
286
|
+
* when the package is not installed. Callers can check `autoInject` config
|
|
287
|
+
* to decide whether to include it in child processes.
|
|
288
|
+
*/
|
|
289
|
+
export function resolvePermissionSystemExtension(): string | undefined {
|
|
290
|
+
const agentDir = getAgentDir();
|
|
291
|
+
const candidates = [
|
|
292
|
+
// npm-scoped package (most common)
|
|
293
|
+
path.join(
|
|
294
|
+
agentDir,
|
|
295
|
+
"npm",
|
|
296
|
+
"node_modules",
|
|
297
|
+
"@gotgenes",
|
|
298
|
+
"pi-permission-system",
|
|
299
|
+
),
|
|
300
|
+
// direct extension directory (some layouts)
|
|
301
|
+
path.join(agentDir, "extensions", "pi-permission-system"),
|
|
302
|
+
];
|
|
303
|
+
const errors: Error[] = [];
|
|
304
|
+
for (const extDir of candidates) {
|
|
305
|
+
if (!fs.existsSync(extDir)) continue;
|
|
306
|
+
const pkgPath = path.join(extDir, "package.json");
|
|
307
|
+
if (!fs.existsSync(pkgPath)) {
|
|
308
|
+
errors.push(new Error(`Permission-system package manifest is missing at ${pkgPath}.`));
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
let pkg: { pi?: { extensions?: string[] } };
|
|
313
|
+
const parsed: unknown = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
314
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
315
|
+
throw new Error("manifest root must be an object");
|
|
316
|
+
}
|
|
317
|
+
pkg = parsed as typeof pkg;
|
|
318
|
+
const extensions = pkg.pi?.extensions;
|
|
319
|
+
const entry = Array.isArray(extensions) ? extensions[0] : undefined;
|
|
320
|
+
if (typeof entry !== "string" || !entry.trim()) {
|
|
321
|
+
throw new Error(
|
|
322
|
+
`Permission-system package manifest at ${pkgPath} must declare pi.extensions[0] as a non-empty string.`,
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
const resolved = path.resolve(extDir, entry);
|
|
326
|
+
if (fs.existsSync(resolved)) return resolved;
|
|
327
|
+
throw new Error(
|
|
328
|
+
`Permission-system extension entry ${JSON.stringify(entry)} in ${pkgPath} does not exist at ${resolved}.`,
|
|
329
|
+
);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
332
|
+
errors.push(message.startsWith("Permission-system") ? new Error(message) : new Error(`Cannot read permission-system package manifest at ${pkgPath}: ${message}`));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (errors.length > 0) throw errors[0]!;
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export function resolvePiLaunchToolPlan(
|
|
340
|
+
input: ResolvePiLaunchToolPlanInput,
|
|
341
|
+
): PiLaunchToolPlan {
|
|
342
|
+
const capabilityCeiling = intersectSubagentCapabilityCeilings(
|
|
343
|
+
input.capabilityCeiling,
|
|
344
|
+
input.inheritedCapabilityCeiling,
|
|
345
|
+
);
|
|
346
|
+
const allowedToolSet =
|
|
347
|
+
capabilityCeiling?.allowedTools === undefined
|
|
348
|
+
? undefined
|
|
349
|
+
: new Set(capabilityCeiling.allowedTools);
|
|
350
|
+
const requestedBuiltinTools =
|
|
351
|
+
input.tools?.filter(
|
|
352
|
+
(tool) =>
|
|
353
|
+
!(tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js")),
|
|
354
|
+
) ?? [];
|
|
196
355
|
if (input.requireReadTool && allowedToolSet && !allowedToolSet.has("read")) {
|
|
197
|
-
throw new Error(
|
|
356
|
+
throw new Error(
|
|
357
|
+
`Capability ceiling from ${capabilityCeiling?.sources.join(", ") || "unknown source"} excludes required tool 'read' for lazy skill loading.`,
|
|
358
|
+
);
|
|
198
359
|
}
|
|
199
|
-
const declaredBuiltinTools =
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
360
|
+
const declaredBuiltinTools =
|
|
361
|
+
input.tools === undefined
|
|
362
|
+
? allowedToolSet
|
|
363
|
+
? [...allowedToolSet]
|
|
364
|
+
: []
|
|
365
|
+
: (input.requireReadTool &&
|
|
366
|
+
requestedBuiltinTools.length > 0 &&
|
|
367
|
+
!requestedBuiltinTools.includes("read") &&
|
|
368
|
+
!allowedToolSet
|
|
369
|
+
? ["read", ...requestedBuiltinTools]
|
|
370
|
+
: requestedBuiltinTools
|
|
371
|
+
).filter((tool) => !allowedToolSet || allowedToolSet.has(tool));
|
|
204
372
|
const fanoutAuthorized = declaredBuiltinTools.includes("subagent");
|
|
205
|
-
const toolExtensionPaths: string[] = capabilityCeiling?.denyExtensions
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
373
|
+
const toolExtensionPaths: string[] = capabilityCeiling?.denyExtensions
|
|
374
|
+
? []
|
|
375
|
+
: (input.tools ?? []).filter(
|
|
376
|
+
(tool) =>
|
|
377
|
+
!requestedBuiltinTools.includes(tool) &&
|
|
378
|
+
(tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js")),
|
|
379
|
+
);
|
|
380
|
+
const resolvedMcpSelections = capabilityCeiling?.denyExtensions
|
|
381
|
+
? []
|
|
382
|
+
: resolveMcpDirectToolSelections(input.mcpDirectTools, input.cwd);
|
|
383
|
+
const effectiveMcpSelections = resolvedMcpSelections.filter(
|
|
384
|
+
(selection) => !allowedToolSet || allowedToolSet.has(selection.name),
|
|
385
|
+
);
|
|
386
|
+
const effectiveMcpTools = effectiveMcpSelections.map(
|
|
387
|
+
(selection) => selection.name,
|
|
388
|
+
);
|
|
389
|
+
const explicitToolAllowlist =
|
|
390
|
+
input.tools !== undefined ||
|
|
391
|
+
(input.mcpDirectTools?.length ?? 0) > 0 ||
|
|
392
|
+
allowedToolSet !== undefined;
|
|
210
393
|
const internalTools = input.structuredOutput ? ["structured_output"] : [];
|
|
211
|
-
const effectiveToolAllowlist = [
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
394
|
+
const effectiveToolAllowlist = [
|
|
395
|
+
...new Set([
|
|
396
|
+
...declaredBuiltinTools,
|
|
397
|
+
...effectiveMcpTools,
|
|
398
|
+
...internalTools,
|
|
399
|
+
]),
|
|
400
|
+
];
|
|
401
|
+
const requiredChildTools = explicitToolAllowlist
|
|
402
|
+
? [
|
|
403
|
+
...new Set([
|
|
404
|
+
...(input.tools !== undefined ? declaredBuiltinTools : []),
|
|
405
|
+
...(input.mcpDirectTools?.length ? effectiveMcpTools : []),
|
|
406
|
+
...internalTools,
|
|
407
|
+
]),
|
|
408
|
+
]
|
|
409
|
+
: [];
|
|
410
|
+
const permSystemExt = capabilityCeiling?.denyExtensions
|
|
411
|
+
? undefined
|
|
412
|
+
: resolvePermissionSystemExtension();
|
|
413
|
+
const runtimeExtensions = [
|
|
414
|
+
PROMPT_RUNTIME_EXTENSION_PATH,
|
|
415
|
+
...(fanoutAuthorized ? [FANOUT_CHILD_EXTENSION_PATH] : []),
|
|
416
|
+
...(permSystemExt ? [permSystemExt] : []),
|
|
417
|
+
];
|
|
418
|
+
const disableAmbientExtensions =
|
|
419
|
+
capabilityCeiling?.denyExtensions === true ||
|
|
420
|
+
input.extensions !== undefined;
|
|
421
|
+
const configuredExtensions = capabilityCeiling?.denyExtensions
|
|
422
|
+
? []
|
|
423
|
+
: [
|
|
424
|
+
...toolExtensionPaths,
|
|
425
|
+
...(input.extensions ?? []),
|
|
426
|
+
...(input.subagentOnlyExtensions ?? []),
|
|
427
|
+
];
|
|
222
428
|
const extensionArgs = disableAmbientExtensions
|
|
223
429
|
? [...new Set([...runtimeExtensions, ...configuredExtensions])]
|
|
224
|
-
: [
|
|
225
|
-
|
|
226
|
-
|
|
430
|
+
: [
|
|
431
|
+
...new Set([
|
|
432
|
+
...runtimeExtensions,
|
|
433
|
+
...toolExtensionPaths,
|
|
434
|
+
...(input.subagentOnlyExtensions ?? []),
|
|
435
|
+
]),
|
|
436
|
+
];
|
|
437
|
+
const requestedToolNames =
|
|
438
|
+
input.tools !== undefined
|
|
439
|
+
? [
|
|
440
|
+
...new Set([
|
|
441
|
+
...requestedBuiltinTools,
|
|
442
|
+
...resolvedMcpSelections.map((selection) => selection.name),
|
|
443
|
+
]),
|
|
444
|
+
]
|
|
445
|
+
: undefined;
|
|
446
|
+
const capabilityAudit = capabilityCeiling
|
|
447
|
+
? ({
|
|
448
|
+
ceiling: capabilityCeiling,
|
|
449
|
+
...(requestedToolNames ? { requestedTools: requestedToolNames } : {}),
|
|
450
|
+
effectiveTools: effectiveToolAllowlist,
|
|
451
|
+
removedTools:
|
|
452
|
+
requestedToolNames?.filter(
|
|
453
|
+
(tool) => !effectiveToolAllowlist.includes(tool),
|
|
454
|
+
) ?? [],
|
|
455
|
+
internalTools,
|
|
456
|
+
extensionsDenied: capabilityCeiling.denyExtensions,
|
|
457
|
+
removedExtensionCount: capabilityCeiling.denyExtensions
|
|
458
|
+
? (input.extensions?.length ?? 0) +
|
|
459
|
+
(input.subagentOnlyExtensions?.length ?? 0) +
|
|
460
|
+
(input.tools ?? []).filter(
|
|
461
|
+
(tool) =>
|
|
462
|
+
tool.includes("/") ||
|
|
463
|
+
tool.endsWith(".ts") ||
|
|
464
|
+
tool.endsWith(".js"),
|
|
465
|
+
).length
|
|
466
|
+
: 0,
|
|
467
|
+
requestedMcpToolCount: input.mcpDirectTools?.length ?? 0,
|
|
468
|
+
effectiveMcpTools,
|
|
469
|
+
agentAllowed:
|
|
470
|
+
input.agentName === undefined
|
|
471
|
+
? true
|
|
472
|
+
: isAgentAllowedByCapabilityCeiling(
|
|
473
|
+
input.agentName,
|
|
474
|
+
capabilityCeiling,
|
|
475
|
+
),
|
|
476
|
+
...(capabilityCeilingAgentRestrictionSources(capabilityCeiling)
|
|
477
|
+
? {
|
|
478
|
+
agentRestrictionSources:
|
|
479
|
+
capabilityCeilingAgentRestrictionSources(capabilityCeiling),
|
|
480
|
+
}
|
|
481
|
+
: {}),
|
|
482
|
+
} satisfies SubagentCapabilityAudit)
|
|
227
483
|
: undefined;
|
|
228
|
-
const capabilityAudit = capabilityCeiling ? {
|
|
229
|
-
ceiling: capabilityCeiling,
|
|
230
|
-
...(requestedToolNames ? { requestedTools: requestedToolNames } : {}),
|
|
231
|
-
effectiveTools: effectiveToolAllowlist,
|
|
232
|
-
removedTools: requestedToolNames?.filter((tool) => !effectiveToolAllowlist.includes(tool)) ?? [],
|
|
233
|
-
internalTools,
|
|
234
|
-
extensionsDenied: capabilityCeiling.denyExtensions,
|
|
235
|
-
removedExtensionCount: capabilityCeiling.denyExtensions ? (input.extensions?.length ?? 0) + (input.subagentOnlyExtensions?.length ?? 0) + ((input.tools ?? []).filter((tool) => tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js")).length) : 0,
|
|
236
|
-
requestedMcpToolCount: input.mcpDirectTools?.length ?? 0,
|
|
237
|
-
effectiveMcpTools,
|
|
238
|
-
agentAllowed: input.agentName === undefined ? true : isAgentAllowedByCapabilityCeiling(input.agentName, capabilityCeiling),
|
|
239
|
-
...(capabilityCeilingAgentRestrictionSources(capabilityCeiling) ? { agentRestrictionSources: capabilityCeilingAgentRestrictionSources(capabilityCeiling) } : {}),
|
|
240
|
-
} satisfies SubagentCapabilityAudit : undefined;
|
|
241
484
|
return {
|
|
242
485
|
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
243
486
|
requestedBuiltinTools,
|
|
@@ -259,6 +502,15 @@ export function resolvePiLaunchToolPlan(input: ResolvePiLaunchToolPlanInput): Pi
|
|
|
259
502
|
};
|
|
260
503
|
}
|
|
261
504
|
|
|
505
|
+
/** Escape XML-significant characters in a string for safe attribute interpolation. */
|
|
506
|
+
function escapeXmlAttr(value: string): string {
|
|
507
|
+
return value
|
|
508
|
+
.replace(/&/g, "&")
|
|
509
|
+
.replace(/"/g, """)
|
|
510
|
+
.replace(/</g, "<")
|
|
511
|
+
.replace(/>/g, ">");
|
|
512
|
+
}
|
|
513
|
+
|
|
262
514
|
export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
263
515
|
const args = [...input.baseArgs];
|
|
264
516
|
|
|
@@ -289,17 +541,23 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
289
541
|
requireReadTool: input.requireReadTool,
|
|
290
542
|
structuredOutput: input.structuredOutput,
|
|
291
543
|
capabilityCeiling: input.capabilityCeiling,
|
|
292
|
-
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(
|
|
544
|
+
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(
|
|
545
|
+
process.env[SUBAGENT_CAPABILITY_CEILING_ENV],
|
|
546
|
+
),
|
|
293
547
|
agentName: input.childAgentName,
|
|
294
548
|
});
|
|
295
549
|
if (toolPlan.explicitToolAllowlist) {
|
|
296
|
-
args.push(
|
|
297
|
-
|
|
550
|
+
args.push(
|
|
551
|
+
toolPlan.effectiveToolAllowlist.length > 0 ? "--tools" : "--no-tools",
|
|
552
|
+
);
|
|
553
|
+
if (toolPlan.effectiveToolAllowlist.length > 0)
|
|
554
|
+
args.push(toolPlan.effectiveToolAllowlist.join(","));
|
|
298
555
|
}
|
|
299
556
|
if (toolPlan.disableAmbientExtensions) {
|
|
300
557
|
args.push("--no-extensions");
|
|
301
558
|
}
|
|
302
|
-
for (const extPath of toolPlan.extensionArgs)
|
|
559
|
+
for (const extPath of toolPlan.extensionArgs)
|
|
560
|
+
args.push("--extension", extPath);
|
|
303
561
|
|
|
304
562
|
if (!input.inheritProjectContext) {
|
|
305
563
|
args.push("--no-context-files");
|
|
@@ -313,8 +571,18 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
313
571
|
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-"));
|
|
314
572
|
const stem = (input.promptFileStem ?? "prompt").replace(/[^\w.-]/g, "_");
|
|
315
573
|
const promptPath = path.join(tempDir, `${stem}.md`);
|
|
316
|
-
|
|
317
|
-
|
|
574
|
+
// Inject <active_agent> tag so @gotgenes/pi-permission-system can
|
|
575
|
+
// resolve per-agent policy inside the child session.
|
|
576
|
+
const taggedPrompt = input.childAgentName
|
|
577
|
+
? `<active_agent name="${escapeXmlAttr(input.childAgentName)}"/>\n\n${input.systemPrompt}`
|
|
578
|
+
: input.systemPrompt;
|
|
579
|
+
fs.writeFileSync(promptPath, taggedPrompt, { mode: 0o600 });
|
|
580
|
+
args.push(
|
|
581
|
+
input.systemPromptMode === "replace"
|
|
582
|
+
? "--system-prompt"
|
|
583
|
+
: "--append-system-prompt",
|
|
584
|
+
promptPath,
|
|
585
|
+
);
|
|
318
586
|
}
|
|
319
587
|
|
|
320
588
|
if (input.task.length > TASK_ARG_LIMIT) {
|
|
@@ -329,58 +597,106 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
329
597
|
}
|
|
330
598
|
|
|
331
599
|
const env: Record<string, string | undefined> = {};
|
|
332
|
-
const piPackageRoot =
|
|
600
|
+
const piPackageRoot =
|
|
601
|
+
process.env[PI_CODING_AGENT_PACKAGE_ROOT_ENV] ?? resolvePiPackageRoot();
|
|
333
602
|
if (piPackageRoot) env[PI_CODING_AGENT_PACKAGE_ROOT_ENV] = piPackageRoot;
|
|
334
|
-
if (!tempDir)
|
|
335
|
-
|
|
603
|
+
if (!tempDir)
|
|
604
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-"));
|
|
605
|
+
const runtimeAcknowledgedExtensionsPath = path.join(
|
|
606
|
+
tempDir,
|
|
607
|
+
"runtime-acknowledged-extensions.json",
|
|
608
|
+
);
|
|
336
609
|
env[RUNTIME_EXTENSION_ACK_PATH_ENV] = runtimeAcknowledgedExtensionsPath;
|
|
337
610
|
let toolDiagnosticPath: string | undefined;
|
|
338
611
|
if (toolPlan.requiredChildTools.length > 0) {
|
|
339
|
-
if (!tempDir)
|
|
612
|
+
if (!tempDir)
|
|
613
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-"));
|
|
340
614
|
toolDiagnosticPath = path.join(tempDir, "tool-diagnostic.json");
|
|
341
615
|
env[REQUIRED_CHILD_TOOLS_ENV] = JSON.stringify(toolPlan.requiredChildTools);
|
|
342
616
|
env[CHILD_TOOL_DIAGNOSTIC_PATH_ENV] = toolDiagnosticPath;
|
|
343
617
|
}
|
|
344
|
-
env[MCP_DIRECT_CHILD_TOOLS_ENV] =
|
|
618
|
+
env[MCP_DIRECT_CHILD_TOOLS_ENV] =
|
|
619
|
+
toolPlan.effectiveMcpTools.length > 0
|
|
620
|
+
? JSON.stringify(toolPlan.effectiveMcpTools)
|
|
621
|
+
: undefined;
|
|
345
622
|
env[SUBAGENT_CHILD_ENV] = "1";
|
|
346
623
|
env[SUBAGENT_FANOUT_CHILD_ENV] = toolPlan.fanoutAuthorized ? "1" : "0";
|
|
347
624
|
if (input.waitToolEnabled !== undefined) {
|
|
348
625
|
env[WAIT_TOOL_ENABLED_ENV] = input.waitToolEnabled ? "true" : "false";
|
|
349
626
|
}
|
|
350
|
-
const inheritedNestedRoute = Boolean(
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
627
|
+
const inheritedNestedRoute = Boolean(
|
|
628
|
+
process.env[SUBAGENT_PARENT_EVENT_SINK_ENV] &&
|
|
629
|
+
process.env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] &&
|
|
630
|
+
process.env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV],
|
|
631
|
+
);
|
|
632
|
+
const parentRunId =
|
|
633
|
+
input.parentRunId ??
|
|
634
|
+
input.runId ??
|
|
635
|
+
(inheritedNestedRoute ? process.env[SUBAGENT_RUN_ID_ENV] : undefined) ??
|
|
636
|
+
process.env[SUBAGENT_PARENT_RUN_ID_ENV] ??
|
|
637
|
+
"";
|
|
638
|
+
const parentChildIndex =
|
|
639
|
+
input.parentChildIndex !== undefined
|
|
640
|
+
? String(input.parentChildIndex)
|
|
641
|
+
: input.childIndex !== undefined
|
|
642
|
+
? String(input.childIndex)
|
|
643
|
+
: (process.env[SUBAGENT_PARENT_CHILD_INDEX_ENV] ?? "");
|
|
357
644
|
const inheritedDepth = Number(process.env[SUBAGENT_PARENT_DEPTH_ENV]);
|
|
358
|
-
const parentDepth =
|
|
645
|
+
const parentDepth =
|
|
646
|
+
input.parentDepth ??
|
|
647
|
+
(inheritedNestedRoute && Number.isFinite(inheritedDepth)
|
|
648
|
+
? inheritedDepth + 1
|
|
649
|
+
: 1);
|
|
359
650
|
const parentPath = input.parentPath ?? [
|
|
360
651
|
...parseNestedPathEnv(process.env[SUBAGENT_PARENT_PATH_ENV]),
|
|
361
|
-
...(parentRunId
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
652
|
+
...(parentRunId
|
|
653
|
+
? [
|
|
654
|
+
{
|
|
655
|
+
runId: parentRunId,
|
|
656
|
+
...(parentChildIndex && /^\d+$/.test(parentChildIndex)
|
|
657
|
+
? { stepIndex: Number(parentChildIndex) }
|
|
658
|
+
: {}),
|
|
659
|
+
...(input.childAgentName ? { agent: input.childAgentName } : {}),
|
|
660
|
+
},
|
|
661
|
+
]
|
|
662
|
+
: []),
|
|
366
663
|
];
|
|
367
664
|
env[SUBAGENT_PARENT_EVENT_SINK_ENV] = toolPlan.fanoutAuthorized
|
|
368
|
-
? input.parentEventSink ??
|
|
665
|
+
? (input.parentEventSink ??
|
|
666
|
+
process.env[SUBAGENT_PARENT_EVENT_SINK_ENV] ??
|
|
667
|
+
"")
|
|
369
668
|
: "";
|
|
370
669
|
env[SUBAGENT_PARENT_CONTROL_INBOX_ENV] = toolPlan.fanoutAuthorized
|
|
371
|
-
? input.parentControlInbox ??
|
|
670
|
+
? (input.parentControlInbox ??
|
|
671
|
+
process.env[SUBAGENT_PARENT_CONTROL_INBOX_ENV] ??
|
|
672
|
+
"")
|
|
372
673
|
: "";
|
|
373
674
|
env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] = toolPlan.fanoutAuthorized
|
|
374
|
-
? input.parentRootRunId ??
|
|
675
|
+
? (input.parentRootRunId ??
|
|
676
|
+
process.env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] ??
|
|
677
|
+
input.runId ??
|
|
678
|
+
"")
|
|
679
|
+
: "";
|
|
680
|
+
env[SUBAGENT_PARENT_RUN_ID_ENV] = toolPlan.fanoutAuthorized
|
|
681
|
+
? parentRunId
|
|
682
|
+
: "";
|
|
683
|
+
env[SUBAGENT_PARENT_CHILD_INDEX_ENV] = toolPlan.fanoutAuthorized
|
|
684
|
+
? parentChildIndex
|
|
685
|
+
: "";
|
|
686
|
+
env[SUBAGENT_PARENT_DEPTH_ENV] = toolPlan.fanoutAuthorized
|
|
687
|
+
? String(parentDepth)
|
|
688
|
+
: "";
|
|
689
|
+
env[SUBAGENT_PARENT_PATH_ENV] = toolPlan.fanoutAuthorized
|
|
690
|
+
? encodeNestedPathEnv(parentPath)
|
|
375
691
|
: "";
|
|
376
|
-
env[SUBAGENT_PARENT_RUN_ID_ENV] = toolPlan.fanoutAuthorized ? parentRunId : "";
|
|
377
|
-
env[SUBAGENT_PARENT_CHILD_INDEX_ENV] = toolPlan.fanoutAuthorized ? parentChildIndex : "";
|
|
378
|
-
env[SUBAGENT_PARENT_DEPTH_ENV] = toolPlan.fanoutAuthorized ? String(parentDepth) : "";
|
|
379
|
-
env[SUBAGENT_PARENT_PATH_ENV] = toolPlan.fanoutAuthorized ? encodeNestedPathEnv(parentPath) : "";
|
|
380
692
|
env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] = toolPlan.fanoutAuthorized
|
|
381
|
-
? input.parentCapabilityToken ??
|
|
693
|
+
? (input.parentCapabilityToken ??
|
|
694
|
+
process.env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] ??
|
|
695
|
+
"")
|
|
382
696
|
: "";
|
|
383
|
-
env.PI_SUBAGENT_INHERIT_PROJECT_CONTEXT = input.inheritProjectContext
|
|
697
|
+
env.PI_SUBAGENT_INHERIT_PROJECT_CONTEXT = input.inheritProjectContext
|
|
698
|
+
? "1"
|
|
699
|
+
: "0";
|
|
384
700
|
env.PI_SUBAGENT_INHERIT_SKILLS = input.inheritSkills ? "1" : "0";
|
|
385
701
|
env[PI_INTERCOM_STABLE_ID_ENV] = input.intercomSessionName || undefined;
|
|
386
702
|
env[PI_INTERCOM_SESSION_ID_ENV] = undefined;
|
|
@@ -394,14 +710,25 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
394
710
|
env[SUBAGENT_ORCHESTRATOR_SESSION_ID_ENV] = input.parentSessionId;
|
|
395
711
|
}
|
|
396
712
|
const encodedPermissionRules = encodePermissionRules(input.permissionRules);
|
|
397
|
-
if (
|
|
713
|
+
if (
|
|
714
|
+
input.orchestratorIntercomTarget &&
|
|
715
|
+
input.parentSessionId &&
|
|
716
|
+
input.runId &&
|
|
717
|
+
input.childAgentName
|
|
718
|
+
) {
|
|
398
719
|
const childIndex = input.childIndex ?? 0;
|
|
399
|
-
const channelDir = supervisorChannelDir(
|
|
720
|
+
const channelDir = supervisorChannelDir(
|
|
721
|
+
input.runId,
|
|
722
|
+
input.childAgentName,
|
|
723
|
+
childIndex,
|
|
724
|
+
);
|
|
400
725
|
fs.mkdirSync(path.join(channelDir, "requests"), { recursive: true });
|
|
401
726
|
fs.mkdirSync(path.join(channelDir, "replies"), { recursive: true });
|
|
402
727
|
env[SUBAGENT_SUPERVISOR_CHANNEL_DIR_ENV] = channelDir;
|
|
403
728
|
}
|
|
404
|
-
if (encodedPermissionRules)
|
|
729
|
+
if (encodedPermissionRules)
|
|
730
|
+
env[PERMISSION_AUDIT_PATH_ENV] =
|
|
731
|
+
input.permissionAuditPath ?? path.join(tempDir, "permission-audit.jsonl");
|
|
405
732
|
if (input.runId) {
|
|
406
733
|
env[SUBAGENT_RUN_ID_ENV] = input.runId;
|
|
407
734
|
}
|
|
@@ -411,12 +738,24 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
411
738
|
if (input.childIndex !== undefined) {
|
|
412
739
|
env[SUBAGENT_CHILD_INDEX_ENV] = String(input.childIndex);
|
|
413
740
|
}
|
|
414
|
-
if (!toolPlan.capabilityCeiling && input.mcpDirectTools?.length)
|
|
415
|
-
|
|
741
|
+
if (!toolPlan.capabilityCeiling && input.mcpDirectTools?.length)
|
|
742
|
+
env.MCP_DIRECT_TOOLS = input.mcpDirectTools.join(",");
|
|
743
|
+
else if (
|
|
744
|
+
toolPlan.capabilityCeiling &&
|
|
745
|
+
toolPlan.effectiveMcpSelections.length &&
|
|
746
|
+
!toolPlan.capabilityCeiling.denyExtensions
|
|
747
|
+
)
|
|
748
|
+
env.MCP_DIRECT_TOOLS = toolPlan.effectiveMcpSelections
|
|
749
|
+
.map((selection) => selection.selector)
|
|
750
|
+
.join(",");
|
|
416
751
|
else env.MCP_DIRECT_TOOLS = "__none__";
|
|
417
|
-
const encodedCapabilityCeiling = encodeSubagentCapabilityCeiling(
|
|
418
|
-
|
|
419
|
-
|
|
752
|
+
const encodedCapabilityCeiling = encodeSubagentCapabilityCeiling(
|
|
753
|
+
toolPlan.capabilityCeiling,
|
|
754
|
+
);
|
|
755
|
+
if (encodedCapabilityCeiling)
|
|
756
|
+
env[SUBAGENT_CAPABILITY_CEILING_ENV] = encodedCapabilityCeiling;
|
|
757
|
+
if (encodedPermissionRules)
|
|
758
|
+
env[PERMISSION_POLICY_ENV] = encodedPermissionRules;
|
|
420
759
|
if (input.structuredOutput) {
|
|
421
760
|
env[STRUCTURED_OUTPUT_CAPTURE_ENV] = input.structuredOutput.outputPath;
|
|
422
761
|
env[STRUCTURED_OUTPUT_SCHEMA_ENV] = input.structuredOutput.schemaPath;
|
|
@@ -424,17 +763,27 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
424
763
|
if (input.steerInboxDir) {
|
|
425
764
|
env[SUBAGENT_STEER_INBOX_ENV] = input.steerInboxDir;
|
|
426
765
|
}
|
|
427
|
-
if (input.steerCapabilityPath)
|
|
766
|
+
if (input.steerCapabilityPath)
|
|
767
|
+
env[SUBAGENT_STEER_CAPABILITY_ENV] = input.steerCapabilityPath;
|
|
428
768
|
if (input.steerAckDir) env[SUBAGENT_STEER_ACK_DIR_ENV] = input.steerAckDir;
|
|
429
769
|
const encodedToolBudget = encodeToolBudgetEnv(input.toolBudget);
|
|
430
770
|
if (encodedToolBudget) env[TOOL_BUDGET_ENV] = encodedToolBudget;
|
|
431
771
|
env[TOOL_BUDGET_ZERO_AUTH_ENV] = input.allowZeroToolBudget ? "1" : undefined;
|
|
432
772
|
const encodedChildWatchdog = encodeChildWatchdogConfig(input.childWatchdog);
|
|
433
|
-
if (encodedChildWatchdog)
|
|
773
|
+
if (encodedChildWatchdog)
|
|
774
|
+
env[CHILD_WATCHDOG_CONFIG_ENV] = encodedChildWatchdog;
|
|
434
775
|
|
|
435
|
-
env[SUBAGENT_PARENT_SESSION_ENV] =
|
|
776
|
+
env[SUBAGENT_PARENT_SESSION_ENV] =
|
|
777
|
+
input.parentSessionId ?? process.env[SUBAGENT_PARENT_SESSION_ENV] ?? "";
|
|
436
778
|
|
|
437
|
-
return {
|
|
779
|
+
return {
|
|
780
|
+
args,
|
|
781
|
+
env,
|
|
782
|
+
tempDir,
|
|
783
|
+
toolDiagnosticPath,
|
|
784
|
+
runtimeAcknowledgedExtensionsPath,
|
|
785
|
+
capabilityAudit: toolPlan.capabilityAudit,
|
|
786
|
+
};
|
|
438
787
|
}
|
|
439
788
|
|
|
440
789
|
export const parseParentPathEnv = parseNestedPathEnv;
|