pi-cohort 7.5.0 → 7.6.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 +5 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/agents/agents.ts +50 -12
- package/src/execution-backend/configured-selection.ts +1 -3
- package/src/extension/fanout-child.ts +2 -7
- package/src/extension/index.ts +21 -13
- package/src/runs/background/subagent-runner.ts +46 -8
- package/src/runs/foreground/chain-execution.ts +16 -7
- package/src/runs/foreground/subagent-executor.ts +26 -21
- package/src/runs/shared/chain-outputs.ts +0 -3
- package/src/shared/types.ts +1 -0
- package/src/extension/config.ts +0 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [7.6.0] - 2026-10-26
|
|
4
|
+
|
|
5
|
+
### Breaking
|
|
6
|
+
- All extension settings now come only from `settings.json#subagents`: the profile is below project levels, and the nearest defined value wins. Move the legacy configuration object's keys under `subagents` in the profile's `settings.json` or project `.pi/settings.json`; the old file is ignored and triggers one top-level session-start migration warning. Hooks and backend selection follow each execution unit's effective cwd, including detached runs. (#29)
|
|
7
|
+
|
|
3
8
|
## [7.5.0] - 2026-10-26
|
|
4
9
|
|
|
5
10
|
### Added
|
package/README.md
CHANGED
|
@@ -186,7 +186,7 @@ Full reference: agent/chain authoring in [doc/agents-and-chains.md](doc/agents-a
|
|
|
186
186
|
|
|
187
187
|
## Configuration
|
|
188
188
|
|
|
189
|
-
Most installs need zero configuration.
|
|
189
|
+
Most installs need zero configuration. Set options under `subagents` in the profile's `settings.json` or project `.pi/settings.json`; project levels override the profile, nearest wins. See the [settings reference and migration guide](doc/configuration.md) for defaults, whole-object replacement, and moving legacy configuration.
|
|
190
190
|
|
|
191
191
|
Run history lives under the pinned profile's `pi-cohort/` root and has no automatic age expiry. Status listings can grow without bound as history accumulates. To remove history manually, delete only a terminal top-level run directory after confirming its entire subtree has stopped; never delete queued or running state, individual nested records, or shared route files. This removes that directory's status and resume lookup, not separately stored session files or shared routes. Keep those sessions if you need their context; deleting a run directory is not a complete session purge. Storage details: [doc/observability.md](doc/observability.md#files-logs-and-observability).
|
|
192
192
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-cohort",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.6.0",
|
|
4
4
|
"description": "Delegate Pi work to focused child agents: code review, scouting, implementation, parallel audits, saved chains, and background jobs.",
|
|
5
5
|
"author": "Jacek Juraszek",
|
|
6
6
|
"license": "MIT",
|
package/src/agents/agents.ts
CHANGED
|
@@ -6,7 +6,7 @@ import * as fs from "node:fs";
|
|
|
6
6
|
import * as os from "node:os";
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
-
import type { AcceptanceInput, OutputMode, StopCondition } from "../shared/types.ts";
|
|
9
|
+
import type { AcceptanceInput, ExtensionConfig, OutputMode, StopCondition } from "../shared/types.ts";
|
|
10
10
|
import { getAgentDir } from "../shared/utils.ts";
|
|
11
11
|
import { KNOWN_FIELDS } from "./agent-serializer.ts";
|
|
12
12
|
import { parseChain, parseJsonChain } from "./chain-serializer.ts";
|
|
@@ -114,12 +114,29 @@ export interface AgentConfig {
|
|
|
114
114
|
override?: BuiltinAgentOverrideInfo;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
interface SubagentSettings {
|
|
117
|
+
interface SubagentSettings extends ExtensionConfig {
|
|
118
118
|
overrides: Record<string, BuiltinAgentOverrideConfig>;
|
|
119
119
|
disableBuiltins?: boolean;
|
|
120
120
|
executionBackend?: string;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
const EXTENSION_SETTING_TYPES = {
|
|
124
|
+
asyncByDefault: "boolean",
|
|
125
|
+
forceTopLevelAsync: "boolean",
|
|
126
|
+
defaultSessionDir: "string",
|
|
127
|
+
maxSubagentDepth: "depth",
|
|
128
|
+
control: "object",
|
|
129
|
+
parallel: "object",
|
|
130
|
+
chain: "object",
|
|
131
|
+
worktreeSetupHook: "string",
|
|
132
|
+
worktreeSetupHookTimeoutMs: "timeout",
|
|
133
|
+
worktreeTeardownHook: "string",
|
|
134
|
+
worktreeTeardownHookTimeoutMs: "timeout",
|
|
135
|
+
showRosterOnStart: "boolean",
|
|
136
|
+
forwardParentFlags: "boolean",
|
|
137
|
+
executionBackend: "backend",
|
|
138
|
+
} as const;
|
|
139
|
+
|
|
123
140
|
const EMPTY_SUBAGENT_SETTINGS: SubagentSettings = { overrides: {} };
|
|
124
141
|
|
|
125
142
|
export interface ChainStepConfig {
|
|
@@ -475,16 +492,28 @@ function readSubagentSettings(filePath: string | null): SubagentSettings {
|
|
|
475
492
|
executionBackend = trimmed;
|
|
476
493
|
}
|
|
477
494
|
|
|
495
|
+
const extension: Record<string, unknown> = {};
|
|
496
|
+
for (const [key, type] of Object.entries(EXTENSION_SETTING_TYPES)) {
|
|
497
|
+
if (type === "backend" || !(key in subagentsObject)) continue;
|
|
498
|
+
const value = subagentsObject[key];
|
|
499
|
+
const valid = type === "timeout"
|
|
500
|
+
|| (type === "depth" ? typeof value === "number" && Number.isInteger(value) && value >= 0
|
|
501
|
+
: type === "object" ? value !== null && typeof value === "object" && !Array.isArray(value)
|
|
502
|
+
: typeof value === type);
|
|
503
|
+
if (valid) extension[key] = value;
|
|
504
|
+
else console.warn(`Subagent settings in '${filePath}' have invalid '${key}'; expected ${type}.`);
|
|
505
|
+
}
|
|
506
|
+
|
|
478
507
|
const parsed: Record<string, BuiltinAgentOverrideConfig> = {};
|
|
479
508
|
const agentOverrides = subagentsObject.agentOverrides;
|
|
480
509
|
if (!agentOverrides || typeof agentOverrides !== "object" || Array.isArray(agentOverrides)) {
|
|
481
|
-
return { overrides: parsed, disableBuiltins, executionBackend };
|
|
510
|
+
return { ...extension, overrides: parsed, disableBuiltins, executionBackend };
|
|
482
511
|
}
|
|
483
512
|
for (const [name, value] of Object.entries(agentOverrides)) {
|
|
484
513
|
const override = parseBuiltinOverrideEntry(name, value, filePath);
|
|
485
514
|
if (override) parsed[name] = override;
|
|
486
515
|
}
|
|
487
|
-
return { overrides: parsed, disableBuiltins, executionBackend };
|
|
516
|
+
return { ...extension, overrides: parsed, disableBuiltins, executionBackend };
|
|
488
517
|
}
|
|
489
518
|
|
|
490
519
|
// Merge project .pi/settings.json across every enumerated level, farthest-first
|
|
@@ -498,7 +527,7 @@ function readMergedProjectSubagentSettings(cwd: string): SubagentSettings {
|
|
|
498
527
|
|
|
499
528
|
const overrides: Record<string, BuiltinAgentOverrideConfig> = {};
|
|
500
529
|
let disableBuiltins: boolean | undefined;
|
|
501
|
-
|
|
530
|
+
const extension: ExtensionConfig = {};
|
|
502
531
|
for (const level of levels) {
|
|
503
532
|
const settingsPath = path.join(level, ".pi", "settings.json");
|
|
504
533
|
let levelSettings: SubagentSettings;
|
|
@@ -519,16 +548,25 @@ function readMergedProjectSubagentSettings(cwd: string): SubagentSettings {
|
|
|
519
548
|
if (levelSettings.disableBuiltins !== undefined) {
|
|
520
549
|
disableBuiltins = levelSettings.disableBuiltins;
|
|
521
550
|
}
|
|
522
|
-
|
|
523
|
-
executionBackend = levelSettings.executionBackend;
|
|
524
|
-
}
|
|
551
|
+
Object.assign(extension, projectExtensionSettings(levelSettings));
|
|
525
552
|
}
|
|
526
|
-
return { overrides, disableBuiltins
|
|
553
|
+
return { ...extension, overrides, disableBuiltins };
|
|
527
554
|
}
|
|
528
555
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
556
|
+
function projectExtensionSettings(settings: SubagentSettings): ExtensionConfig {
|
|
557
|
+
return Object.fromEntries(
|
|
558
|
+
Object.keys(EXTENSION_SETTING_TYPES)
|
|
559
|
+
.filter((key) => settings[key as keyof ExtensionConfig] !== undefined)
|
|
560
|
+
.map((key) => [key, settings[key as keyof ExtensionConfig]]),
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
export function resolveExtensionConfig(cwd: string): ExtensionConfig {
|
|
565
|
+
const profile = readSubagentSettings(getUserAgentSettingsPath());
|
|
566
|
+
return {
|
|
567
|
+
...projectExtensionSettings(profile),
|
|
568
|
+
...projectExtensionSettings(readMergedProjectSubagentSettings(cwd)),
|
|
569
|
+
};
|
|
532
570
|
}
|
|
533
571
|
|
|
534
572
|
function composeOverrideTools(
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { selectExecutionBackend } from "./selection.ts";
|
|
2
|
-
import { readProjectExecutionBackend } from "../agents/agents.ts";
|
|
3
2
|
import type { ExtensionConfig } from "../shared/types.ts";
|
|
4
3
|
import type { ExecutionBackendPreparation, ExecutionBackendSelectionResult } from "./selection.ts";
|
|
5
4
|
|
|
@@ -13,7 +12,6 @@ export interface ConfiguredSelectionInput {
|
|
|
13
12
|
export async function selectConfiguredExecutionBackend(
|
|
14
13
|
input: ConfiguredSelectionInput,
|
|
15
14
|
): Promise<ExecutionBackendSelectionResult> {
|
|
16
|
-
const
|
|
17
|
-
const preference = projectPreference ?? input.userConfig.executionBackend ?? "auto";
|
|
15
|
+
const preference = input.userConfig.executionBackend ?? "auto";
|
|
18
16
|
return selectExecutionBackend(preference, input.preparation);
|
|
19
17
|
}
|
|
@@ -2,14 +2,12 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
5
|
-
import { discoverAgents } from "../agents/agents.ts";
|
|
5
|
+
import { resolveExtensionConfig, discoverAgents } from "../agents/agents.ts";
|
|
6
6
|
import { getArtifactsDir } from "../shared/artifacts.ts";
|
|
7
7
|
import { createSubagentExecutor, type SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
|
|
8
8
|
import { SUBAGENT_CHILD_ENV, SUBAGENT_FANOUT_CHILD_ENV } from "../runs/shared/pi-args.ts";
|
|
9
9
|
import { readNestedControlRequests, resolveNestedRouteFromEnv, writeNestedControlResult } from "../runs/shared/nested-events.ts";
|
|
10
10
|
import { SubagentParams } from "./schemas.ts";
|
|
11
|
-
import { loadConfig } from "./config.ts";
|
|
12
|
-
import { deriveForwardedFlags } from "../runs/shared/forward-flags.ts";
|
|
13
11
|
import { RUN_STATE_ROOT_DIR, type Details, type SubagentState } from "../shared/types.ts";
|
|
14
12
|
import { emptyGrandTotal } from "./grand-total.ts";
|
|
15
13
|
|
|
@@ -126,18 +124,15 @@ export default function registerFanoutChildSubagentExtension(pi: ExtensionAPI):
|
|
|
126
124
|
if (registeredApis.has(pi)) return;
|
|
127
125
|
registeredApis.add(pi);
|
|
128
126
|
|
|
129
|
-
const config = loadConfig();
|
|
130
127
|
const state = createChildSafeState();
|
|
131
128
|
const executor = createSubagentExecutor({
|
|
132
129
|
pi,
|
|
133
130
|
state,
|
|
134
|
-
|
|
135
|
-
asyncByDefault: config.asyncByDefault === true,
|
|
131
|
+
resolveConfig: resolveExtensionConfig,
|
|
136
132
|
tempArtifactsDir: getArtifactsDir(null),
|
|
137
133
|
getSubagentSessionRoot,
|
|
138
134
|
expandTilde,
|
|
139
135
|
discoverAgents,
|
|
140
|
-
forwardedFlags: deriveForwardedFlags(process.argv, config),
|
|
141
136
|
allowMutatingManagementActions: false,
|
|
142
137
|
});
|
|
143
138
|
|
package/src/extension/index.ts
CHANGED
|
@@ -6,10 +6,18 @@
|
|
|
6
6
|
* - Async: Background execution, emits events when done
|
|
7
7
|
*
|
|
8
8
|
* Modes: single (agent + task), parallel (tasks[]), chain (chain[] with {previous})
|
|
9
|
-
* Toggle: async parameter (default: false, configurable via
|
|
9
|
+
* Toggle: async parameter (default: false, configurable via settings.json#subagents)
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* { "
|
|
11
|
+
* Settings: settings.json#subagents (profile or project .pi/settings.json)
|
|
12
|
+
* { "subagents": {
|
|
13
|
+
* "asyncByDefault": true, "forceTopLevelAsync": true,
|
|
14
|
+
* "defaultSessionDir": "./sessions", "maxSubagentDepth": 1,
|
|
15
|
+
* "control": {}, "parallel": { "maxTasks": 8 },
|
|
16
|
+
* "chain": { "dynamicFanout": { "maxItems": 8 } },
|
|
17
|
+
* "worktreeSetupHook": "./scripts/setup-worktree.mjs", "worktreeSetupHookTimeoutMs": 30000,
|
|
18
|
+
* "worktreeTeardownHook": "./scripts/teardown-worktree.mjs", "worktreeTeardownHookTimeoutMs": 30000,
|
|
19
|
+
* "showRosterOnStart": true, "forwardParentFlags": true, "executionBackend": "auto"
|
|
20
|
+
* } }
|
|
13
21
|
*/
|
|
14
22
|
|
|
15
23
|
import * as fs from "node:fs";
|
|
@@ -18,7 +26,7 @@ import * as path from "node:path";
|
|
|
18
26
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
19
27
|
import type { ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
20
28
|
import { Box, Container, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, type Component } from "@earendil-works/pi-tui";
|
|
21
|
-
import { discoverAgents, discoverAgentsAll } from "../agents/agents.ts";
|
|
29
|
+
import { resolveExtensionConfig, discoverAgents, discoverAgentsAll } from "../agents/agents.ts";
|
|
22
30
|
import { cleanupAllArtifactDirs, cleanupOldArtifacts, getArtifactsDir } from "../shared/artifacts.ts";
|
|
23
31
|
import { resolveCurrentSessionId } from "../shared/session-identity.ts";
|
|
24
32
|
import { cleanupOldChainDirs } from "../shared/settings.ts";
|
|
@@ -36,8 +44,7 @@ import { inspectSubagentStatus } from "../runs/background/run-status.ts";
|
|
|
36
44
|
import registerSubagentNotify, { type SubagentNotifyDetails } from "../runs/background/notify.ts";
|
|
37
45
|
import { SUBAGENT_CHILD_ENV } from "../runs/shared/pi-args.ts";
|
|
38
46
|
import { formatDuration, shortenPath } from "../shared/formatters.ts";
|
|
39
|
-
import {
|
|
40
|
-
import { deriveForwardedFlags } from "../runs/shared/forward-flags.ts";
|
|
47
|
+
import { getAgentDir } from "../shared/utils.ts";
|
|
41
48
|
import {
|
|
42
49
|
type Details,
|
|
43
50
|
type SubagentState,
|
|
@@ -61,8 +68,6 @@ import {
|
|
|
61
68
|
type SubagentControlMessageDetails,
|
|
62
69
|
} from "./control-notices.ts";
|
|
63
70
|
|
|
64
|
-
export { loadConfig } from "./config.ts";
|
|
65
|
-
|
|
66
71
|
/**
|
|
67
72
|
* Derive subagent session base directory from parent session file.
|
|
68
73
|
* If parent session is ~/.pi/agent/sessions/abc123.jsonl,
|
|
@@ -250,8 +255,6 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
250
255
|
ensureAccessibleDir(ASYNC_DIR, true);
|
|
251
256
|
cleanupOldChainDirs();
|
|
252
257
|
|
|
253
|
-
const config = loadConfig();
|
|
254
|
-
const asyncByDefault = config.asyncByDefault === true;
|
|
255
258
|
const tempArtifactsDir = getArtifactsDir(null);
|
|
256
259
|
cleanupAllArtifactDirs(DEFAULT_ARTIFACT_CONFIG.cleanupDays);
|
|
257
260
|
|
|
@@ -290,13 +293,11 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
290
293
|
const executor = createSubagentExecutor({
|
|
291
294
|
pi,
|
|
292
295
|
state,
|
|
293
|
-
|
|
294
|
-
asyncByDefault,
|
|
296
|
+
resolveConfig: resolveExtensionConfig,
|
|
295
297
|
tempArtifactsDir,
|
|
296
298
|
getSubagentSessionRoot,
|
|
297
299
|
expandTilde,
|
|
298
300
|
discoverAgents,
|
|
299
|
-
forwardedFlags: deriveForwardedFlags(process.argv, config),
|
|
300
301
|
});
|
|
301
302
|
|
|
302
303
|
pi.registerMessageRenderer<SlashMessageDetails>(SLASH_RESULT_TYPE, (message, options, theme) => {
|
|
@@ -542,6 +543,13 @@ DIAGNOSTICS:
|
|
|
542
543
|
|
|
543
544
|
pi.on("session_start", (_event, ctx) => {
|
|
544
545
|
resetSessionState(ctx);
|
|
546
|
+
const config = resolveExtensionConfig(ctx.cwd);
|
|
547
|
+
const legacyConfigPath = path.join(getAgentDir(), "extensions", "pi-cohort", "config.json");
|
|
548
|
+
if (fs.existsSync(legacyConfigPath)) {
|
|
549
|
+
const message = `${legacyConfigPath}: pi-cohort no longer reads this file; move its keys under \`subagents\` in \`settings.json\`.`;
|
|
550
|
+
if (ctx.hasUI) ctx.ui.notify(message, "warning");
|
|
551
|
+
else console.warn(message);
|
|
552
|
+
}
|
|
545
553
|
if (ctx.hasUI && config.showRosterOnStart !== false) {
|
|
546
554
|
const roster = formatSubagentRoster(ctx.cwd);
|
|
547
555
|
// Posted to scrollback at start (alongside [Skills]/[Extensions]). Safe to
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn, spawnSync } from "node:child_process";
|
|
2
2
|
import { PINNED_AGENT_DIR_OVERRIDE } from "../../shared/agent-dir.ts";
|
|
3
|
+
import { resolveExtensionConfig } from "../../agents/agents.ts";
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as path from "node:path";
|
|
5
6
|
import { pathToFileURL } from "node:url";
|
|
@@ -608,6 +609,7 @@ function writeRunLog(
|
|
|
608
609
|
|
|
609
610
|
/** Internal context for one detached-runner leaf. */
|
|
610
611
|
export interface SingleStepContext {
|
|
612
|
+
jobCwd?: string;
|
|
611
613
|
previousOutput: string;
|
|
612
614
|
outputs?: ChainOutputMap;
|
|
613
615
|
trees?: TreeRegistry;
|
|
@@ -666,9 +668,13 @@ export async function runSingleStep(
|
|
|
666
668
|
}
|
|
667
669
|
let backendSelection: import("../../execution-backend/selection.ts").ExecutionBackendSelectionResult;
|
|
668
670
|
try {
|
|
671
|
+
const unitConfig = resolveExtensionConfig(childCwd);
|
|
672
|
+
const jobPreference = path.resolve(childCwd) === path.resolve(ctx.jobCwd ?? ctx.cwd)
|
|
673
|
+
? ctx.executionBackendConfig?.userPreference
|
|
674
|
+
: undefined;
|
|
669
675
|
backendSelection = await selectConfiguredExecutionBackend({
|
|
670
676
|
cwd: childCwd,
|
|
671
|
-
userConfig: { executionBackend:
|
|
677
|
+
userConfig: { executionBackend: unitConfig.executionBackend ?? jobPreference },
|
|
672
678
|
preparation: ctx.executionBackendCoordinator,
|
|
673
679
|
});
|
|
674
680
|
} catch (error) {
|
|
@@ -1961,6 +1967,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1961
1967
|
writeStatusPayload();
|
|
1962
1968
|
appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.started", ts: taskStartTime, runId: id, stepIndex: fi, agent: task.agent }));
|
|
1963
1969
|
const singleResult = await runSingleStep(task, {
|
|
1970
|
+
jobCwd: config.cwd,
|
|
1964
1971
|
previousOutput, placeholder, cwd, sessionEnabled,
|
|
1965
1972
|
outputs,
|
|
1966
1973
|
trees,
|
|
@@ -2102,8 +2109,37 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2102
2109
|
}
|
|
2103
2110
|
|
|
2104
2111
|
if (isParallelGroup(step)) {
|
|
2105
|
-
|
|
2106
|
-
|
|
2112
|
+
let group = step;
|
|
2113
|
+
let groupCwd = group.cwd?.includes("{outputs.") ? group.cwd : resolveChildCwd(cwd, group.cwd);
|
|
2114
|
+
let groupConfig: ReturnType<typeof resolveExtensionConfig> = {};
|
|
2115
|
+
if (group.worktree) {
|
|
2116
|
+
try {
|
|
2117
|
+
groupCwd = resolveChildCwd(cwd, resolveOutputReferences(group.cwd ?? cwd, outputs, trees));
|
|
2118
|
+
group = {
|
|
2119
|
+
...group,
|
|
2120
|
+
parallel: group.parallel.map((task) => ({
|
|
2121
|
+
...task,
|
|
2122
|
+
cwd: task.cwd === undefined ? undefined : resolveChildCwd(cwd, resolveOutputReferences(task.cwd, outputs, trees)),
|
|
2123
|
+
})),
|
|
2124
|
+
};
|
|
2125
|
+
const resolved = resolveExtensionConfig(groupCwd);
|
|
2126
|
+
const fallback = path.resolve(groupCwd) === path.resolve(config.cwd) ? config : {};
|
|
2127
|
+
groupConfig = {
|
|
2128
|
+
worktreeSetupHook: resolved.worktreeSetupHook ?? fallback.worktreeSetupHook,
|
|
2129
|
+
worktreeSetupHookTimeoutMs: resolved.worktreeSetupHookTimeoutMs === undefined ? fallback.worktreeSetupHookTimeoutMs : resolved.worktreeSetupHookTimeoutMs,
|
|
2130
|
+
worktreeTeardownHook: resolved.worktreeTeardownHook ?? fallback.worktreeTeardownHook,
|
|
2131
|
+
worktreeTeardownHookTimeoutMs: resolved.worktreeTeardownHookTimeoutMs === undefined ? fallback.worktreeTeardownHookTimeoutMs : resolved.worktreeTeardownHookTimeoutMs,
|
|
2132
|
+
};
|
|
2133
|
+
} catch (error) {
|
|
2134
|
+
markParallelGroupSetupFailure({
|
|
2135
|
+
statusPayload, results, group, groupStartFlatIndex: flatIndex,
|
|
2136
|
+
setupError: error instanceof Error ? error.message : String(error), failedAt: Date.now(),
|
|
2137
|
+
statusPath, eventsPath, asyncDir, runId: id, stepIndex,
|
|
2138
|
+
});
|
|
2139
|
+
flatIndex += group.parallel.length;
|
|
2140
|
+
break;
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2107
2143
|
const concurrency = group.concurrency ?? MAX_PARALLEL_CONCURRENCY;
|
|
2108
2144
|
const failFast = group.failFast ?? false;
|
|
2109
2145
|
const groupStartFlatIndex = flatIndex;
|
|
@@ -2132,11 +2168,11 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2132
2168
|
try {
|
|
2133
2169
|
worktreeSetup = createWorktrees(groupCwd, `${id}-s${stepIndex}`, group.parallel.length, {
|
|
2134
2170
|
agents: group.parallel.map((task) => task.agent),
|
|
2135
|
-
setupHook:
|
|
2136
|
-
? { hookPath:
|
|
2171
|
+
setupHook: groupConfig.worktreeSetupHook
|
|
2172
|
+
? { hookPath: groupConfig.worktreeSetupHook, timeoutMs: groupConfig.worktreeSetupHookTimeoutMs }
|
|
2137
2173
|
: undefined,
|
|
2138
|
-
teardownHook:
|
|
2139
|
-
? { hookPath:
|
|
2174
|
+
teardownHook: groupConfig.worktreeTeardownHook
|
|
2175
|
+
? { hookPath: groupConfig.worktreeTeardownHook, timeoutMs: groupConfig.worktreeTeardownHookTimeoutMs }
|
|
2140
2176
|
: undefined,
|
|
2141
2177
|
});
|
|
2142
2178
|
} catch (error) {
|
|
@@ -2218,9 +2254,10 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2218
2254
|
const taskSessionDir = config.sessionDir
|
|
2219
2255
|
? path.join(config.sessionDir, `parallel-${fi}`)
|
|
2220
2256
|
: undefined;
|
|
2221
|
-
const { taskForRun, taskCwd } = prepareParallelTaskRun(task, cwd, worktreeSetup, taskIdx,
|
|
2257
|
+
const { taskForRun, taskCwd } = prepareParallelTaskRun(task, cwd, worktreeSetup, taskIdx, groupCwd);
|
|
2222
2258
|
|
|
2223
2259
|
const singleResult = await runSingleStep(taskForRun, {
|
|
2260
|
+
jobCwd: config.cwd,
|
|
2224
2261
|
previousOutput, placeholder, cwd: taskCwd, sessionEnabled,
|
|
2225
2262
|
outputs,
|
|
2226
2263
|
trees,
|
|
@@ -2400,6 +2437,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2400
2437
|
}));
|
|
2401
2438
|
|
|
2402
2439
|
const singleResult = await runSingleStep(seqStep, {
|
|
2440
|
+
jobCwd: config.cwd,
|
|
2403
2441
|
previousOutput, placeholder, cwd, sessionEnabled,
|
|
2404
2442
|
outputs,
|
|
2405
2443
|
trees,
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
type ResolvedTemplates,
|
|
32
32
|
} from "../../shared/settings.ts";
|
|
33
33
|
import { discoverAvailableSkills, normalizeSkillInput } from "../../agents/skills.ts";
|
|
34
|
+
import type { ExtensionConfig } from "../../shared/types.ts";
|
|
34
35
|
import { runSync } from "./execution.ts";
|
|
35
36
|
import type { PiRuntimeIdentity } from "../shared/pi-spawn.ts";
|
|
36
37
|
import { buildChainSummary, buildChainOutputsSection, buildChainStopSection, type ChainSummaryOptions } from "../../shared/formatters.ts";
|
|
@@ -142,6 +143,7 @@ interface ParallelChainRunInput {
|
|
|
142
143
|
maxSubagentDepth: number;
|
|
143
144
|
nestedRoute?: NestedRouteInfo;
|
|
144
145
|
forwardedFlags?: string[];
|
|
146
|
+
resolveConfig?: (cwd: string) => ExtensionConfig;
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
function buildChainExecutionDetails(input: ChainExecutionDetailsInput): Details {
|
|
@@ -295,6 +297,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
295
297
|
const result = await runSync(input.ctx.cwd, input.agents, task.agent, taskStr, {
|
|
296
298
|
runtime: input.runtime,
|
|
297
299
|
cwd: taskCwd,
|
|
300
|
+
executionBackend: input.resolveConfig?.(taskCwd).executionBackend,
|
|
298
301
|
signal: input.signal,
|
|
299
302
|
interruptSignal: interruptController.signal,
|
|
300
303
|
runId: input.runId,
|
|
@@ -423,6 +426,7 @@ interface ChainExecutionParams {
|
|
|
423
426
|
worktreeTeardownHook?: string;
|
|
424
427
|
worktreeTeardownHookTimeoutMs?: number;
|
|
425
428
|
forwardedFlags?: string[];
|
|
429
|
+
resolveConfig?: (cwd: string) => ExtensionConfig;
|
|
426
430
|
}
|
|
427
431
|
|
|
428
432
|
interface ChainExecutionResult {
|
|
@@ -645,10 +649,12 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
645
649
|
|
|
646
650
|
if (isParallelStep(step)) {
|
|
647
651
|
const parallelTemplates = stepTemplates as string[];
|
|
648
|
-
const parallelCwd = resolveChildCwd(cwd ?? ctx.cwd, step.cwd);
|
|
652
|
+
const parallelCwd = resolveChildCwd(cwd ?? ctx.cwd, step.cwd === undefined ? undefined : resolveOutputReferences(step.cwd, outputs, trees));
|
|
649
653
|
let worktreeSetup: WorktreeSetup | undefined;
|
|
650
654
|
if (step.worktree) {
|
|
651
|
-
const
|
|
655
|
+
const groupConfig = params.resolveConfig?.(parallelCwd) ?? params;
|
|
656
|
+
const resolvedTasks = step.parallel.map((task) => ({ ...task, cwd: task.cwd === undefined ? undefined : resolveOutputReferences(task.cwd, outputs, trees) }));
|
|
657
|
+
const worktreeTaskCwdConflict = findWorktreeTaskCwdConflict(resolvedTasks, parallelCwd);
|
|
652
658
|
if (worktreeTaskCwdConflict) {
|
|
653
659
|
return buildChainExecutionErrorResult(
|
|
654
660
|
`parallel chain step ${stepIndex + 1}: ${formatWorktreeTaskCwdConflict(worktreeTaskCwdConflict, parallelCwd)}`,
|
|
@@ -659,11 +665,11 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
659
665
|
try {
|
|
660
666
|
worktreeSetup = createWorktrees(parallelCwd, `${runId}-s${stepIndex}`, step.parallel.length, {
|
|
661
667
|
agents: step.parallel.map((task) => task.agent),
|
|
662
|
-
setupHook:
|
|
663
|
-
? { hookPath:
|
|
668
|
+
setupHook: groupConfig.worktreeSetupHook
|
|
669
|
+
? { hookPath: groupConfig.worktreeSetupHook, timeoutMs: groupConfig.worktreeSetupHookTimeoutMs }
|
|
664
670
|
: undefined,
|
|
665
|
-
teardownHook:
|
|
666
|
-
? { hookPath:
|
|
671
|
+
teardownHook: groupConfig.worktreeTeardownHook
|
|
672
|
+
? { hookPath: groupConfig.worktreeTeardownHook, timeoutMs: groupConfig.worktreeTeardownHookTimeoutMs }
|
|
667
673
|
: undefined,
|
|
668
674
|
});
|
|
669
675
|
} catch (error) {
|
|
@@ -703,6 +709,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
703
709
|
runId,
|
|
704
710
|
globalTaskIndex,
|
|
705
711
|
forwardedFlags: params.forwardedFlags,
|
|
712
|
+
resolveConfig: params.resolveConfig,
|
|
706
713
|
sessionDirForIndex,
|
|
707
714
|
sessionFileForIndex,
|
|
708
715
|
shareEnabled,
|
|
@@ -714,7 +721,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
714
721
|
allProgress,
|
|
715
722
|
outputs,
|
|
716
723
|
trees,
|
|
717
|
-
stepCwd:
|
|
724
|
+
stepCwd: parallelCwd,
|
|
718
725
|
chainAgents,
|
|
719
726
|
chainSteps,
|
|
720
727
|
totalSteps,
|
|
@@ -912,6 +919,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
912
919
|
runId,
|
|
913
920
|
globalTaskIndex,
|
|
914
921
|
forwardedFlags: params.forwardedFlags,
|
|
922
|
+
resolveConfig: params.resolveConfig,
|
|
915
923
|
sessionDirForIndex,
|
|
916
924
|
sessionFileForIndex,
|
|
917
925
|
shareEnabled,
|
|
@@ -1131,6 +1139,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1131
1139
|
const r = await runSync(ctx.cwd, agents, seqStep.agent, stepTask, {
|
|
1132
1140
|
runtime: params.runtime,
|
|
1133
1141
|
cwd: stepCwd,
|
|
1142
|
+
executionBackend: params.resolveConfig?.(stepCwd).executionBackend,
|
|
1134
1143
|
signal,
|
|
1135
1144
|
interruptSignal: interruptController.signal,
|
|
1136
1145
|
runId,
|
|
@@ -8,6 +8,7 @@ import type { AgentConfig, AgentScope } from "../../agents/agents.ts";
|
|
|
8
8
|
import { getArtifactsDir } from "../../shared/artifacts.ts";
|
|
9
9
|
import { ChainClarifyComponent, type ChainClarifyResult } from "./chain-clarify.ts";
|
|
10
10
|
import { parentModelFullId, toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
|
|
11
|
+
import { deriveForwardedFlags } from "../shared/forward-flags.ts";
|
|
11
12
|
import { executeChain } from "./chain-execution.ts";
|
|
12
13
|
import { resolveExecutionAgentScope } from "../../agents/agent-scope.ts";
|
|
13
14
|
import { handleManagementAction } from "../../agents/agent-management.ts";
|
|
@@ -137,9 +138,7 @@ interface ExecutorDeps {
|
|
|
137
138
|
captureRuntime?: () => PiRuntimeIdentity;
|
|
138
139
|
pi: ExtensionAPI;
|
|
139
140
|
state: SubagentState;
|
|
140
|
-
|
|
141
|
-
forwardedFlags: string[];
|
|
142
|
-
asyncByDefault: boolean;
|
|
141
|
+
resolveConfig: (cwd: string) => ExtensionConfig;
|
|
143
142
|
tempArtifactsDir: string;
|
|
144
143
|
getSubagentSessionRoot: (parentSessionFile: string | null) => string;
|
|
145
144
|
expandTilde: (p: string) => string;
|
|
@@ -147,6 +146,8 @@ interface ExecutorDeps {
|
|
|
147
146
|
allowMutatingManagementActions?: boolean;
|
|
148
147
|
}
|
|
149
148
|
|
|
149
|
+
type CallExecutorDeps = ExecutorDeps & { config: ExtensionConfig; forwardedFlags: string[]; asyncByDefault: boolean };
|
|
150
|
+
|
|
150
151
|
interface ExecutionContextData {
|
|
151
152
|
runtime: PiRuntimeIdentity;
|
|
152
153
|
params: SubagentParamsLike;
|
|
@@ -205,7 +206,7 @@ function formatForegroundActivity(control: SubagentState["foregroundControls"] e
|
|
|
205
206
|
return [`active ${seconds}s ago`, ...facts].join(" | ");
|
|
206
207
|
}
|
|
207
208
|
|
|
208
|
-
function nestedResolutionScopeForExecutor(deps:
|
|
209
|
+
function nestedResolutionScopeForExecutor(deps: CallExecutorDeps): NestedRunResolutionScope | undefined {
|
|
209
210
|
if (deps.allowMutatingManagementActions !== false) return undefined;
|
|
210
211
|
const route = resolveInheritedNestedRouteFromEnv();
|
|
211
212
|
const address = route ? resolveNestedParentAddressFromEnv() : undefined;
|
|
@@ -215,7 +216,7 @@ function nestedResolutionScopeForExecutor(deps: ExecutorDeps): NestedRunResoluti
|
|
|
215
216
|
};
|
|
216
217
|
}
|
|
217
218
|
|
|
218
|
-
function buildAsyncContext(ctx: ExtensionContext, deps:
|
|
219
|
+
function buildAsyncContext(ctx: ExtensionContext, deps: CallExecutorDeps, cwd: string, runtime: PiRuntimeIdentity) {
|
|
219
220
|
return {
|
|
220
221
|
runtime,
|
|
221
222
|
pi: deps.pi,
|
|
@@ -581,7 +582,7 @@ async function resumeAsyncRun(input: {
|
|
|
581
582
|
params: SubagentParamsLike;
|
|
582
583
|
requestCwd: string;
|
|
583
584
|
ctx: ExtensionContext;
|
|
584
|
-
deps:
|
|
585
|
+
deps: CallExecutorDeps;
|
|
585
586
|
}): Promise<AgentToolResult<Details>> {
|
|
586
587
|
const followUp = (input.params.message ?? input.params.task ?? "").trim();
|
|
587
588
|
if (!followUp) {
|
|
@@ -627,6 +628,7 @@ async function resumeAsyncRun(input: {
|
|
|
627
628
|
|
|
628
629
|
input.deps.state.currentSessionId = resolveCurrentSessionId(input.ctx.sessionManager);
|
|
629
630
|
const effectiveCwd = target.cwd ?? input.requestCwd;
|
|
631
|
+
const unitConfig = effectiveCwd === input.requestCwd ? input.deps.config : input.deps.resolveConfig(effectiveCwd);
|
|
630
632
|
const scope: AgentScope = resolveExecutionAgentScope(input.params.agentScope);
|
|
631
633
|
const discoveredAgents = input.deps.discoverAgents(effectiveCwd, scope).agents;
|
|
632
634
|
const agentConfig = discoveredAgents.find((agent) => agent.name === target.agent);
|
|
@@ -649,7 +651,7 @@ async function resumeAsyncRun(input: {
|
|
|
649
651
|
agent: target.agent,
|
|
650
652
|
task: buildRevivedAsyncTask(target, followUp),
|
|
651
653
|
agentConfig,
|
|
652
|
-
ctx: buildAsyncContext(input.ctx, input.deps, input.requestCwd, target.runtime),
|
|
654
|
+
ctx: { ...buildAsyncContext(input.ctx, input.deps, input.requestCwd, target.runtime), executionBackend: unitConfig.executionBackend },
|
|
653
655
|
cwd: effectiveCwd,
|
|
654
656
|
maxOutput: input.params.maxOutput,
|
|
655
657
|
artifactsDir: input.deps.tempArtifactsDir,
|
|
@@ -663,10 +665,10 @@ async function resumeAsyncRun(input: {
|
|
|
663
665
|
originSessionRoot: originalRoot,
|
|
664
666
|
sessionFile: target.sessionFile,
|
|
665
667
|
maxSubagentDepth: resolveCurrentMaxSubagentDepth(input.deps.config.maxSubagentDepth),
|
|
666
|
-
worktreeSetupHook:
|
|
667
|
-
worktreeSetupHookTimeoutMs:
|
|
668
|
-
worktreeTeardownHook:
|
|
669
|
-
worktreeTeardownHookTimeoutMs:
|
|
668
|
+
worktreeSetupHook: unitConfig.worktreeSetupHook,
|
|
669
|
+
worktreeSetupHookTimeoutMs: unitConfig.worktreeSetupHookTimeoutMs,
|
|
670
|
+
worktreeTeardownHook: unitConfig.worktreeTeardownHook,
|
|
671
|
+
worktreeTeardownHookTimeoutMs: unitConfig.worktreeTeardownHookTimeoutMs,
|
|
670
672
|
controlConfig: resolveControlConfig(input.deps.config.control, input.params.control),
|
|
671
673
|
availableModels,
|
|
672
674
|
forwardedFlags: input.deps.forwardedFlags,
|
|
@@ -980,7 +982,7 @@ function wrapChainTasksForFork(chain: ChainStep[], context: SubagentParamsLike["
|
|
|
980
982
|
});
|
|
981
983
|
}
|
|
982
984
|
|
|
983
|
-
function runAsyncPath(data: ExecutionContextData, deps:
|
|
985
|
+
function runAsyncPath(data: ExecutionContextData, deps: CallExecutorDeps): AgentToolResult<Details> | null {
|
|
984
986
|
const {
|
|
985
987
|
params,
|
|
986
988
|
effectiveCwd,
|
|
@@ -1162,7 +1164,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1162
1164
|
return null;
|
|
1163
1165
|
}
|
|
1164
1166
|
|
|
1165
|
-
async function runChainPath(data: ExecutionContextData, deps:
|
|
1167
|
+
async function runChainPath(data: ExecutionContextData, deps: CallExecutorDeps): Promise<AgentToolResult<Details>> {
|
|
1166
1168
|
const {
|
|
1167
1169
|
params,
|
|
1168
1170
|
effectiveCwd,
|
|
@@ -1208,6 +1210,7 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
1208
1210
|
nestedRoute: foregroundControl?.nestedRoute,
|
|
1209
1211
|
chainSkills,
|
|
1210
1212
|
chainDir: params.chainDir,
|
|
1213
|
+
resolveConfig: deps.resolveConfig,
|
|
1211
1214
|
dynamicFanoutMaxItems: deps.config.chain?.dynamicFanout?.maxItems,
|
|
1212
1215
|
maxSubagentDepth: currentMaxSubagentDepth,
|
|
1213
1216
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
@@ -1288,7 +1291,7 @@ interface ForegroundParallelRunInput {
|
|
|
1288
1291
|
onControlEvent?: (event: ControlEvent) => void;
|
|
1289
1292
|
foregroundControl?: SubagentState["foregroundControls"] extends Map<string, infer T> ? T : never;
|
|
1290
1293
|
concurrencyLimit: number;
|
|
1291
|
-
|
|
1294
|
+
resolveConfig: (cwd: string) => ExtensionConfig;
|
|
1292
1295
|
liveResults: (SingleResult | undefined)[];
|
|
1293
1296
|
liveProgress: (AgentProgress | undefined)[];
|
|
1294
1297
|
onUpdate?: (r: AgentToolResult<Details>) => void;
|
|
@@ -1481,7 +1484,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
1481
1484
|
signal: input.signal,
|
|
1482
1485
|
interruptSignal: interruptController.signal,
|
|
1483
1486
|
runId: input.runId,
|
|
1484
|
-
executionBackend: input.executionBackend,
|
|
1487
|
+
executionBackend: input.resolveConfig(taskCwd).executionBackend,
|
|
1485
1488
|
index,
|
|
1486
1489
|
sessionDir: input.sessionDirForIndex(index),
|
|
1487
1490
|
sessionFile: input.sessionFileForIndex(index),
|
|
@@ -1547,7 +1550,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
1547
1550
|
});
|
|
1548
1551
|
}
|
|
1549
1552
|
|
|
1550
|
-
async function runParallelPath(data: ExecutionContextData, deps:
|
|
1553
|
+
async function runParallelPath(data: ExecutionContextData, deps: CallExecutorDeps): Promise<AgentToolResult<Details>> {
|
|
1551
1554
|
const {
|
|
1552
1555
|
params,
|
|
1553
1556
|
effectiveCwd,
|
|
@@ -1807,7 +1810,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1807
1810
|
onUpdate: onUpdateWithCost,
|
|
1808
1811
|
worktreeSetup,
|
|
1809
1812
|
forwardedFlags: deps.forwardedFlags,
|
|
1810
|
-
|
|
1813
|
+
resolveConfig: deps.resolveConfig,
|
|
1811
1814
|
});
|
|
1812
1815
|
if (foregroundControl) updateForegroundNestedProjection(foregroundControl);
|
|
1813
1816
|
recordSyncCost(deps.state.grandTotal, runId, results.reduce((sum, r) => sum + r.usage.cost, 0) + sumNestedCost(foregroundControl?.nestedChildren));
|
|
@@ -1867,7 +1870,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1867
1870
|
}
|
|
1868
1871
|
}
|
|
1869
1872
|
|
|
1870
|
-
async function runSinglePath(data: ExecutionContextData, deps:
|
|
1873
|
+
async function runSinglePath(data: ExecutionContextData, deps: CallExecutorDeps): Promise<AgentToolResult<Details>> {
|
|
1871
1874
|
const {
|
|
1872
1875
|
params,
|
|
1873
1876
|
effectiveCwd,
|
|
@@ -2132,7 +2135,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
2132
2135
|
};
|
|
2133
2136
|
}
|
|
2134
2137
|
|
|
2135
|
-
export function createSubagentExecutor(
|
|
2138
|
+
export function createSubagentExecutor(services: ExecutorDeps): {
|
|
2136
2139
|
execute: (
|
|
2137
2140
|
id: string,
|
|
2138
2141
|
params: SubagentParamsLike,
|
|
@@ -2145,7 +2148,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
2145
2148
|
let runtimeError: unknown;
|
|
2146
2149
|
try {
|
|
2147
2150
|
// SDK hosts are not launched through Pi's CLI; the installation this extension was loaded from is the fallback.
|
|
2148
|
-
runtime = (
|
|
2151
|
+
runtime = (services.captureRuntime ?? (() => capturePiRuntime({ installRoot: getPackageDir() })))();
|
|
2149
2152
|
} catch (error) {
|
|
2150
2153
|
runtimeError = error;
|
|
2151
2154
|
}
|
|
@@ -2156,11 +2159,13 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
2156
2159
|
onUpdate: ((r: AgentToolResult<Details>) => void) | undefined,
|
|
2157
2160
|
ctx: ExtensionContext,
|
|
2158
2161
|
): Promise<AgentToolResult<Details>> => {
|
|
2162
|
+
const requestCwd = resolveRequestedCwd(ctx.cwd, params.cwd);
|
|
2163
|
+
const config = services.resolveConfig(requestCwd);
|
|
2164
|
+
const deps: CallExecutorDeps = { ...services, config, forwardedFlags: deriveForwardedFlags(process.argv, config), asyncByDefault: config.asyncByDefault === true };
|
|
2159
2165
|
deps.state.baseCwd = ctx.cwd;
|
|
2160
2166
|
deps.state.foregroundRuns ??= new Map();
|
|
2161
2167
|
deps.state.foregroundControls ??= new Map();
|
|
2162
2168
|
deps.state.lastForegroundControlId ??= null;
|
|
2163
|
-
const requestCwd = resolveRequestedCwd(ctx.cwd, params.cwd);
|
|
2164
2169
|
const paramsWithResolvedCwd = params.cwd === undefined ? params : { ...params, cwd: requestCwd };
|
|
2165
2170
|
if (params.action) {
|
|
2166
2171
|
if (params.action === "doctor") {
|
|
@@ -81,9 +81,6 @@ export function validateChainOutputBindings(steps: ChainStep[], dynamicFanoutCon
|
|
|
81
81
|
}
|
|
82
82
|
for (const { template, cwd } of taskTemplatesForStep(step)) {
|
|
83
83
|
for (const match of template.matchAll(OUTPUT_REF_PATTERN)) {
|
|
84
|
-
if (cwd && isParallelStep(step) && step.worktree) {
|
|
85
|
-
throw new ChainOutputValidationError(`Chain step ${stepIndex + 1}: cwd output references cannot be combined with worktree: true.`);
|
|
86
|
-
}
|
|
87
84
|
const rawReference = match[0];
|
|
88
85
|
const parsed = parseOutputReference(match[1]!);
|
|
89
86
|
if (!parsed) {
|
package/src/shared/types.ts
CHANGED
package/src/extension/config.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import type { ExtensionConfig } from "../shared/types.ts";
|
|
4
|
-
import { getAgentDir } from "../shared/utils.ts";
|
|
5
|
-
|
|
6
|
-
export function loadConfig(): ExtensionConfig {
|
|
7
|
-
const configPath = path.join(getAgentDir(), "extensions", "pi-cohort", "config.json");
|
|
8
|
-
try {
|
|
9
|
-
if (fs.existsSync(configPath)) {
|
|
10
|
-
return JSON.parse(fs.readFileSync(configPath, "utf-8")) as ExtensionConfig;
|
|
11
|
-
}
|
|
12
|
-
} catch (error) {
|
|
13
|
-
console.error(`Failed to load pi-cohort config from '${configPath}':`, error);
|
|
14
|
-
}
|
|
15
|
-
return {};
|
|
16
|
-
}
|