@henryqw/pi-subagent 27.10.0 → 27.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/composition.js +3 -6
- package/dist/direct-herdr.js +2 -2
- package/dist/git-runtime.js +3 -6
- package/dist/herdr-runtime.js +2 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/launch-runtime.js +2 -8
- package/dist/process-lease.d.ts +1 -0
- package/dist/process-lease.js +1 -0
- package/dist/schema.d.ts +0 -38
- package/dist/store.js +2 -8
- package/dist/worktree.d.ts +2 -0
- package/dist/worktree.js +8 -1
- package/extensions/config.ts +1 -3
- package/extensions/isolated.ts +5 -5
- package/extensions/result-transport.ts +2 -2
- package/extensions/subagent.ts +5 -5
- package/package.json +1 -1
package/dist/composition.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { lstat, realpath } from "node:fs/promises";
|
|
2
|
-
import { isAbsolute, normalize
|
|
2
|
+
import { isAbsolute, normalize } from "node:path";
|
|
3
3
|
import { runProcess as defaultRunProcess } from "./process.js";
|
|
4
|
+
import { isWithin } from "./worktree.js";
|
|
4
5
|
const GIT_ROOT_TIMEOUT_CAP_MS = 30_000;
|
|
5
6
|
const REVIEW_PROMPT_MAX_BYTES = 64 * 1024;
|
|
6
|
-
function within(root, candidate) {
|
|
7
|
-
const fromRoot = relative(root, candidate);
|
|
8
|
-
return fromRoot === "" || (fromRoot !== ".." && !fromRoot.startsWith(`..${sep}`) && !isAbsolute(fromRoot));
|
|
9
|
-
}
|
|
10
7
|
function processFailure(result) {
|
|
11
8
|
const detail = (result.stderr || result.stdout).trim().slice(0, 1_000);
|
|
12
9
|
return new Error(`git rev-parse --show-toplevel failed with exit ${result.code}${detail ? `: ${detail}` : ""}`);
|
|
@@ -45,7 +42,7 @@ export function createCanonicalGitRootResolver(options = {}) {
|
|
|
45
42
|
if (canonicalRoot !== root || !rootInfo.isDirectory()) {
|
|
46
43
|
throw new Error("Git returned a non-canonical repository root.");
|
|
47
44
|
}
|
|
48
|
-
if (!
|
|
45
|
+
if (!isWithin(root, canonicalCwd)) {
|
|
49
46
|
throw new Error("Git repository root does not identify the requested working directory.");
|
|
50
47
|
}
|
|
51
48
|
return root;
|
package/dist/direct-herdr.js
CHANGED
|
@@ -5,7 +5,7 @@ import { tmpdir } from "node:os";
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
7
7
|
import { createHerdrClient, hasHerdrErrorCode, herdrCommandFailure, startPiAgent } from "@henryqw/pi-herdr";
|
|
8
|
-
import { assertPrivateLease, scanProcessLease } from "./process-lease.js";
|
|
8
|
+
import { assertPrivateLease, PI_SUBAGENT_PROCESS_LEASE, scanProcessLease } from "./process-lease.js";
|
|
9
9
|
const OPERATION_MS = 30_000;
|
|
10
10
|
const SESSION_LIMIT = 16 * 1024 * 1024;
|
|
11
11
|
const ANSWER_LIMIT = 50 * 1024;
|
|
@@ -384,7 +384,7 @@ export function createDirectHerdr(pi, cwd, idleMs) {
|
|
|
384
384
|
let tabId;
|
|
385
385
|
let paneId;
|
|
386
386
|
try {
|
|
387
|
-
const response = await herdr.json(["tab", "create", "--workspace", workspaceId, "--cwd", workingDir, "--label", label, "--env",
|
|
387
|
+
const response = await herdr.json(["tab", "create", "--workspace", workspaceId, "--cwd", workingDir, "--label", label, "--env", `${PI_SUBAGENT_PROCESS_LEASE}=${leasePath}`, "--no-focus"], options());
|
|
388
388
|
const created = object(response.result, "tab allocation result");
|
|
389
389
|
// Capture every returned ID before validation can fail. These are evidence,
|
|
390
390
|
// not owned tabs; the caller retains this intent even without either ID.
|
package/dist/git-runtime.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { lstat, realpath } from "node:fs/promises";
|
|
2
|
-
import { createChildWorktree, inspectIndexFlags, inspectWorktreeDirty, WorktreeSetupError, } from "./worktree.js";
|
|
2
|
+
import { createChildWorktree, inspectIndexFlags, inspectWorktreeDirty, isMissing, WorktreeSetupError, } from "./worktree.js";
|
|
3
3
|
import { prepareExactReviewEvidence } from "./review-evidence.js";
|
|
4
4
|
import { sameIdentity, } from "./schema.js";
|
|
5
5
|
import { withTransientLaunch, } from "./runner.js";
|
|
@@ -41,16 +41,13 @@ function cloneWorktree(info) {
|
|
|
41
41
|
baseCommit: info.baseCommit.toLowerCase(),
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
-
function pathMissing(error) {
|
|
45
|
-
return Boolean(error && typeof error === "object" && error.code === "ENOENT");
|
|
46
|
-
}
|
|
47
44
|
async function pathExists(path) {
|
|
48
45
|
try {
|
|
49
46
|
await lstat(path);
|
|
50
47
|
return true;
|
|
51
48
|
}
|
|
52
49
|
catch (error) {
|
|
53
|
-
if (
|
|
50
|
+
if (isMissing(error))
|
|
54
51
|
return false;
|
|
55
52
|
throw error;
|
|
56
53
|
}
|
|
@@ -457,7 +454,7 @@ export class CheckedGitRuntime {
|
|
|
457
454
|
return await realpath(path);
|
|
458
455
|
}
|
|
459
456
|
catch (error) {
|
|
460
|
-
if (
|
|
457
|
+
if (isMissing(error))
|
|
461
458
|
return path;
|
|
462
459
|
throw error;
|
|
463
460
|
}
|
package/dist/herdr-runtime.js
CHANGED
|
@@ -9,7 +9,7 @@ import { isCleanCommitted, } from "./schema.js";
|
|
|
9
9
|
import { buildChangesetTaskPrompt, withTransientLaunch, } from "./runner.js";
|
|
10
10
|
import { runProcess as defaultRunProcess } from "./process.js";
|
|
11
11
|
import { EXECUTION_BUDGET_ENV } from "./ephemeral.js";
|
|
12
|
-
import { assertPrivateLease, scanProcessLease } from "./process-lease.js";
|
|
12
|
+
import { assertPrivateLease, PI_SUBAGENT_PROCESS_LEASE, scanProcessLease } from "./process-lease.js";
|
|
13
13
|
import { exactDirectTerminalTurn } from "./direct-herdr.js";
|
|
14
14
|
import { READABLE_BRANCH_PATTERN } from "./worktree.js";
|
|
15
15
|
const MIN_HERDR_VERSION = [0, 9, 3];
|
|
@@ -25,7 +25,6 @@ const DIAGNOSTIC_LIMIT = 8 * 1024;
|
|
|
25
25
|
const SESSION_LIMIT = 16 * 1024 * 1024;
|
|
26
26
|
const LEASE_MODE = 0o600;
|
|
27
27
|
const DIRECTORY_MODE = 0o700;
|
|
28
|
-
const PROCESS_LEASE_ENV = "PI_SUBAGENT_PROCESS_LEASE";
|
|
29
28
|
const CORRELATION_TOKEN_PATTERN = /^[A-Za-z0-9_-]{16,128}$/;
|
|
30
29
|
const HERDR_AGENT_NAME_PATTERN = /^[a-z][a-z0-9_-]{0,31}$/;
|
|
31
30
|
const SETTLED_AGENT_STATES = new Set(["idle", "done"]);
|
|
@@ -803,7 +802,7 @@ export class HerdrHostRuntime {
|
|
|
803
802
|
const budget = this.executionBudget?.();
|
|
804
803
|
const args = [
|
|
805
804
|
"tab", "create", "--workspace", allocation.workspaceId, "--cwd", allocation.worktreeCwd,
|
|
806
|
-
"--label", allocation.label, "--env", `${
|
|
805
|
+
"--label", allocation.label, "--env", `${PI_SUBAGENT_PROCESS_LEASE}=${allocation.leasePath}`,
|
|
807
806
|
...(budget ? ["--env", `${EXECUTION_BUDGET_ENV}=${JSON.stringify({ ...budget, startedAt: this.now() })}`] : []),
|
|
808
807
|
"--no-focus",
|
|
809
808
|
];
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { loadRoleMcpConfig, parseRoleMcpAllowlist } from "./mcp-role.ts";
|
|
|
5
5
|
export { addUsage, capEphemeralSubagentOutput, createEphemeralSubagentExecutor, DEFAULT_MAX_TURNS, EphemeralSubagentError, EXECUTION_BUDGET_ENV, formatDuration, type EphemeralSubagentActivityEvent, type EphemeralSubagentErrorCode, type EphemeralSubagentExecutionBudget, type EphemeralSubagentExecutor, type EphemeralSubagentExecutorOptions, type EphemeralSubagentResult, type EphemeralSubagentRunInput, type EphemeralSubagentTimeout, } from "./ephemeral.ts";
|
|
6
6
|
export { createChildWorktree, finalizeChildWorktree, inspectIndexFlags, inspectWorktreeDirty, WorktreeSetupError, type WorktreeDirtyInspection, type WorktreeInfo, type WorktreePayload, } from "./worktree.ts";
|
|
7
7
|
export { prepareExactReviewEvidence, REVIEW_MAX_PATCH_BYTES, REVIEW_MAX_PATHS, type PreparedReviewEvidence, type PrepareExactReviewEvidenceInput, } from "./review-evidence.ts";
|
|
8
|
-
export
|
|
8
|
+
export { PI_SUBAGENT_PROCESS_LEASE } from "./process-lease.ts";
|
|
9
9
|
export declare const ROLE_MCP_POLICY_FLAG = "pi-subagent-role-mcps";
|
|
10
10
|
export declare const ROLE_TOOL_POLICY_FLAG = "pi-subagent-role-tools";
|
|
11
11
|
/** Read child MCP policy before Pi binds registered extension flag values. */
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ const MULTI_CODEX_EXTENSION = fileURLToPath(import.meta.resolve("@henryqw/pi-mul
|
|
|
17
17
|
const ROLE_MCP_EXTENSION = fileURLToPath(new URL("../extensions/role-mcp.ts", import.meta.url));
|
|
18
18
|
const ROLE_TOOLS_EXTENSION = fileURLToPath(new URL("../extensions/role-tools.ts", import.meta.url));
|
|
19
19
|
const GIT_READ_EXTENSION = fileURLToPath(new URL("../extensions/git-read.ts", import.meta.url));
|
|
20
|
-
export
|
|
20
|
+
export { PI_SUBAGENT_PROCESS_LEASE } from "./process-lease.js";
|
|
21
21
|
export const ROLE_MCP_POLICY_FLAG = "pi-subagent-role-mcps";
|
|
22
22
|
export const ROLE_TOOL_POLICY_FLAG = "pi-subagent-role-tools";
|
|
23
23
|
const CODEMODE_TOOL = "codemode";
|
package/dist/launch-runtime.js
CHANGED
|
@@ -2,9 +2,10 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
3
|
import { chmod, lstat, mkdtemp, open, realpath, rmdir, unlink } from "node:fs/promises";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
|
-
import { isAbsolute, join, normalize
|
|
5
|
+
import { isAbsolute, join, normalize } from "node:path";
|
|
6
6
|
import { resolveConfiguredRoleLaunch } from "./index.js";
|
|
7
7
|
import { registerModelTask } from "@henryqw/pi-task-models";
|
|
8
|
+
import { isMissing, isWithin } from "./worktree.js";
|
|
8
9
|
const PROMPT_FLAG = "--append-system-prompt";
|
|
9
10
|
const DIRECTORY_MODE = 0o700;
|
|
10
11
|
const PROMPT_MODE = 0o600;
|
|
@@ -14,13 +15,6 @@ export const ISOLATED_MODEL_TASK = {
|
|
|
14
15
|
purpose: "Resolve one task-scoped isolated Role launch.",
|
|
15
16
|
defaultProfile: "balanced",
|
|
16
17
|
};
|
|
17
|
-
function isMissing(error) {
|
|
18
|
-
return Boolean(error && typeof error === "object" && error.code === "ENOENT");
|
|
19
|
-
}
|
|
20
|
-
function isWithin(root, candidate) {
|
|
21
|
-
const fromRoot = relative(root, candidate);
|
|
22
|
-
return fromRoot === "" || (fromRoot !== ".." && !fromRoot.startsWith(`..${sep}`) && !isAbsolute(fromRoot));
|
|
23
|
-
}
|
|
24
18
|
async function removeTransientLaunch(directory, promptPath, promptRequired) {
|
|
25
19
|
const failures = [];
|
|
26
20
|
try {
|
package/dist/process-lease.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { HerdrExecResult } from "@henryqw/pi-herdr";
|
|
2
|
+
export declare const PI_SUBAGENT_PROCESS_LEASE = "PI_SUBAGENT_PROCESS_LEASE";
|
|
2
3
|
export declare function assertPrivateLease(path: string, allowMissing: boolean): Promise<boolean>;
|
|
3
4
|
/** Shared exact process-lease evidence for direct and isolated workers. */
|
|
4
5
|
export declare function scanProcessLease(path: string, execute: (args: string[]) => Promise<HerdrExecResult>, pid?: number, allowMissing?: boolean): Promise<number[]>;
|
package/dist/process-lease.js
CHANGED
package/dist/schema.d.ts
CHANGED
|
@@ -298,7 +298,6 @@ export type CommandEvidence = Static<typeof CommandEvidenceSchema>;
|
|
|
298
298
|
export type CheckBatchEvidence = Static<typeof CheckBatchEvidenceSchema>;
|
|
299
299
|
export type ReusedCheckSource = NonNullable<CommandEvidence["reusedFrom"]>;
|
|
300
300
|
export type ReviewEvidence = Static<typeof ReviewEvidenceSchema>;
|
|
301
|
-
export type WorkerTermination = Static<typeof WorkerTerminationSchema>;
|
|
302
301
|
export declare const CLEANUP_KINDS: readonly ["worker_tab", "workspace", "worktree", "branch"];
|
|
303
302
|
export type CleanupStep = Static<typeof CleanupStepSchema>;
|
|
304
303
|
export type CleanupKind = CleanupStep["kind"];
|
|
@@ -507,18 +506,6 @@ declare const ReviewEvidenceSchema: Type.TObject<{
|
|
|
507
506
|
passed: Type.TBoolean;
|
|
508
507
|
at: Type.TInteger;
|
|
509
508
|
}>;
|
|
510
|
-
declare const WorkerTerminationSchema: Type.TObject<{
|
|
511
|
-
status: Type.TUnion<[Type.TLiteral<"terminating">, Type.TLiteral<"terminated">, Type.TLiteral<"unknown">]>;
|
|
512
|
-
workerId: Type.TString;
|
|
513
|
-
candidate: Type.TObject<{
|
|
514
|
-
branch: Type.TString;
|
|
515
|
-
head: Type.TString;
|
|
516
|
-
index: Type.TString;
|
|
517
|
-
tree: Type.TString;
|
|
518
|
-
}>;
|
|
519
|
-
at: Type.TOptional<Type.TInteger>;
|
|
520
|
-
failure: Type.TOptional<Type.TString>;
|
|
521
|
-
}>;
|
|
522
509
|
declare const CleanupStepSchema: Type.TObject<{
|
|
523
510
|
kind: Type.TUnion<[Type.TLiteral<"worker_tab">, Type.TLiteral<"workspace">, Type.TLiteral<"worktree">, Type.TLiteral<"branch">]>;
|
|
524
511
|
status: Type.TUnion<[Type.TLiteral<"pending">, Type.TLiteral<"running">, Type.TLiteral<"completed">]>;
|
|
@@ -1304,30 +1291,6 @@ declare const IntegrationCandidateSchema: Type.TObject<{
|
|
|
1304
1291
|
worker: Type.TUnion<[Type.TLiteral<"retained">, Type.TLiteral<"release_pending">, Type.TLiteral<"released">]>;
|
|
1305
1292
|
decision: Type.TOptional<Type.TLiteral<"rejected">>;
|
|
1306
1293
|
}>;
|
|
1307
|
-
declare const IntegrationStageSchema: Type.TObject<{
|
|
1308
|
-
taskId: Type.TString;
|
|
1309
|
-
attempt: Type.TInteger;
|
|
1310
|
-
source: Type.TObject<{
|
|
1311
|
-
branch: Type.TString;
|
|
1312
|
-
head: Type.TString;
|
|
1313
|
-
index: Type.TString;
|
|
1314
|
-
tree: Type.TString;
|
|
1315
|
-
}>;
|
|
1316
|
-
onto: Type.TObject<{
|
|
1317
|
-
branch: Type.TString;
|
|
1318
|
-
head: Type.TString;
|
|
1319
|
-
index: Type.TString;
|
|
1320
|
-
tree: Type.TString;
|
|
1321
|
-
}>;
|
|
1322
|
-
status: Type.TUnion<[Type.TLiteral<"pending">, Type.TLiteral<"staging">, Type.TLiteral<"staged">, Type.TLiteral<"conflict">]>;
|
|
1323
|
-
tip: Type.TOptional<Type.TObject<{
|
|
1324
|
-
branch: Type.TString;
|
|
1325
|
-
head: Type.TString;
|
|
1326
|
-
index: Type.TString;
|
|
1327
|
-
tree: Type.TString;
|
|
1328
|
-
}>>;
|
|
1329
|
-
failure: Type.TOptional<Type.TString>;
|
|
1330
|
-
}>;
|
|
1331
1294
|
declare const IntegrationGenerationSchema: Type.TObject<{
|
|
1332
1295
|
number: Type.TInteger;
|
|
1333
1296
|
status: Type.TUnion<[Type.TLiteral<"staging">, Type.TLiteral<"conflict">, Type.TLiteral<"validating">, Type.TLiteral<"validation_failed">, Type.TLiteral<"ready">, Type.TLiteral<"promoting">, Type.TLiteral<"promoted">, Type.TLiteral<"promotion_unknown">, Type.TLiteral<"promotion_failed">, Type.TLiteral<"superseded">]>;
|
|
@@ -1788,7 +1751,6 @@ export declare const IntegrationStateSchema: Type.TObject<{
|
|
|
1788
1751
|
}>>;
|
|
1789
1752
|
}>;
|
|
1790
1753
|
export type IntegrationCandidate = Static<typeof IntegrationCandidateSchema>;
|
|
1791
|
-
export type IntegrationStage = Static<typeof IntegrationStageSchema>;
|
|
1792
1754
|
export type IntegrationGeneration = Static<typeof IntegrationGenerationSchema>;
|
|
1793
1755
|
export type IntegrationState = Static<typeof IntegrationStateSchema>;
|
|
1794
1756
|
declare const TerminalRunStatusSchema: Type.TUnion<[Type.TLiteral<"completed">, Type.TLiteral<"final_failed">, Type.TLiteral<"superseded">, Type.TLiteral<"aborted">]>;
|
package/dist/store.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { realpathSync } from "node:fs";
|
|
3
3
|
import { lstat, mkdir, open, readdir, realpath } from "node:fs/promises";
|
|
4
|
-
import { basename, dirname, isAbsolute, join,
|
|
4
|
+
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
5
|
import { extensionConfigDir, readTextFileBounded, writePrivateTextFileAtomically } from "@henryqw/pi-config-store";
|
|
6
6
|
import { check, lock } from "proper-lockfile";
|
|
7
7
|
import { parseRunState, RUN_STATE_VERSION } from "./schema.js";
|
|
8
8
|
import { discardResources } from "./discard.js";
|
|
9
|
+
import { isMissing, isWithin } from "./worktree.js";
|
|
9
10
|
const INITIAL_STATE_MAX_BYTES = 2 * 1024 * 1024;
|
|
10
11
|
/*
|
|
11
12
|
* create() caps the complete initial serialization at 2 MiB. Loaded requests
|
|
@@ -30,19 +31,12 @@ export class ProductiveRunLeaseBusyError extends Error {
|
|
|
30
31
|
super("Another Pi Subagent productive request is active in this repository.");
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
|
-
function isMissing(error) {
|
|
34
|
-
return Boolean(error && typeof error === "object" && error.code === "ENOENT");
|
|
35
|
-
}
|
|
36
34
|
function isAlreadyPresent(error) {
|
|
37
35
|
return Boolean(error && typeof error === "object" && error.code === "EEXIST");
|
|
38
36
|
}
|
|
39
37
|
function isLocked(error) {
|
|
40
38
|
return Boolean(error && typeof error === "object" && error.code === "ELOCKED");
|
|
41
39
|
}
|
|
42
|
-
function isWithin(root, candidate) {
|
|
43
|
-
const fromRoot = relative(root, candidate);
|
|
44
|
-
return fromRoot === "" || (fromRoot !== ".." && !fromRoot.startsWith(`..${sep}`) && !isAbsolute(fromRoot));
|
|
45
|
-
}
|
|
46
40
|
async function canonicalPlannedPath(path) {
|
|
47
41
|
let ancestor = resolve(path);
|
|
48
42
|
const suffix = [];
|
package/dist/worktree.d.ts
CHANGED
package/dist/worktree.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { existsSync, lstatSync } from "node:fs";
|
|
3
3
|
import { appendFile, mkdir, readFile } from "node:fs/promises";
|
|
4
|
-
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { runGit } from "./git-process.js";
|
|
6
|
+
export function isMissing(error) {
|
|
7
|
+
return Boolean(error && typeof error === "object" && error.code === "ENOENT");
|
|
8
|
+
}
|
|
9
|
+
export function isWithin(root, candidate) {
|
|
10
|
+
const fromRoot = relative(root, candidate);
|
|
11
|
+
return fromRoot === "" || (fromRoot !== ".." && !fromRoot.startsWith(`..${sep}`) && !isAbsolute(fromRoot));
|
|
12
|
+
}
|
|
6
13
|
export const WORKTREES_DIRNAME = ".worktrees";
|
|
7
14
|
const BRANCH_NAMESPACE = "pi-subagent";
|
|
8
15
|
const NAME_COMPONENT_LIMIT = 24;
|
package/extensions/config.ts
CHANGED
|
@@ -2,10 +2,8 @@ import { formatConfigIssues, type ConfigLoad } from "@henryqw/pi-config-store";
|
|
|
2
2
|
import type { ExecutionPolicySnapshot } from "../dist/schema.js";
|
|
3
3
|
import type { SubagentConfig } from "@henryqw/pi-subagent";
|
|
4
4
|
|
|
5
|
-
export type EffectiveExecutionPolicy = ExecutionPolicySnapshot;
|
|
6
|
-
|
|
7
5
|
/** Resolve one immutable policy. A disabled config blocks delegation. */
|
|
8
|
-
export function resolveExecutionPolicy(path: string, loaded: ConfigLoad<SubagentConfig>):
|
|
6
|
+
export function resolveExecutionPolicy(path: string, loaded: ConfigLoad<SubagentConfig>): ExecutionPolicySnapshot {
|
|
9
7
|
if (loaded.status === "disabled") {
|
|
10
8
|
throw new Error(`${path}: ${formatConfigIssues(loaded.issues)}; delegation is blocked until this file is corrected.`);
|
|
11
9
|
}
|
package/extensions/isolated.ts
CHANGED
|
@@ -3,7 +3,6 @@ import type { JsonValue } from "@earendil-works/pi-ai";
|
|
|
3
3
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import { truncateToWidth } from "@earendil-works/pi-tui";
|
|
5
5
|
import { capEphemeralSubagentOutput, utf8Prefix, type EphemeralSubagentExecutor } from "../dist/ephemeral.js";
|
|
6
|
-
import type { EffectiveExecutionPolicy } from "./config.ts";
|
|
7
6
|
import {
|
|
8
7
|
createCanonicalGitRootResolver,
|
|
9
8
|
createExactJudgmentExecutor,
|
|
@@ -31,6 +30,7 @@ import {
|
|
|
31
30
|
StatusOutputSchema,
|
|
32
31
|
type CheckBatchEvidence,
|
|
33
32
|
type ExecuteRequest,
|
|
33
|
+
type ExecutionPolicySnapshot,
|
|
34
34
|
type ModelClass,
|
|
35
35
|
type ReviewEvidence,
|
|
36
36
|
type RunState,
|
|
@@ -59,8 +59,8 @@ export type CreateIsolatedComponents = (options: {
|
|
|
59
59
|
pi: ExtensionAPI;
|
|
60
60
|
context(): ExtensionContext;
|
|
61
61
|
executor: EphemeralSubagentExecutor;
|
|
62
|
-
policy:
|
|
63
|
-
currentPolicy():
|
|
62
|
+
policy: ExecutionPolicySnapshot;
|
|
63
|
+
currentPolicy(): ExecutionPolicySnapshot;
|
|
64
64
|
onStateSaved(state: RunState): void;
|
|
65
65
|
}) => IsolatedExtensionComponents;
|
|
66
66
|
|
|
@@ -531,8 +531,8 @@ export interface IsolatedSurface {
|
|
|
531
531
|
|
|
532
532
|
export interface RegisterIsolatedOptions {
|
|
533
533
|
executor: EphemeralSubagentExecutor;
|
|
534
|
-
policy:
|
|
535
|
-
currentPolicy():
|
|
534
|
+
policy: ExecutionPolicySnapshot;
|
|
535
|
+
currentPolicy(): ExecutionPolicySnapshot;
|
|
536
536
|
/** Report new config issues, and throw when the config now blocks delegation, before each deferred Role launch. */
|
|
537
537
|
beforeRoleLaunch?(ctx: ExtensionContext): void;
|
|
538
538
|
componentsFactory?: CreateIsolatedComponents;
|
|
@@ -149,12 +149,12 @@ function sourceFor(entry: WorkflowTransportEntry): string | undefined {
|
|
|
149
149
|
if (entry.status === "rejected") {
|
|
150
150
|
return entry.partialOutput ? `${entry.failure}\nPartial output before failure (incomplete; not a success):\n${entry.partialOutput}` : entry.failure;
|
|
151
151
|
}
|
|
152
|
-
if (entry.status === "
|
|
152
|
+
if (entry.status === "succeeded") return entry.assistantOutput;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
function evidenceFor(entry: WorkflowTransportEntry, position: number, total: number): Evidence | undefined {
|
|
156
156
|
const source = sourceFor(entry);
|
|
157
|
-
if (
|
|
157
|
+
if (!source) return;
|
|
158
158
|
const [preview, remainder] = splitEvidence(source);
|
|
159
159
|
return {
|
|
160
160
|
heading: `- [${position}/${total}] ${entry.name} · ${entry.role} · ${entry.status === "rejected" ? "failure" : "result"}:`,
|
package/extensions/subagent.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type { ExtensionAPI, ExtensionContext, Theme } from "@earendil-works/pi-c
|
|
|
3
3
|
import { type Component, Text, type TUI, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
4
4
|
import { availableTaskModels, loadTaskModelsConfig, modelReference, type ProfileName, registerModelTask, registerTaskModelsConfigReporting, resolveAvailableModel, resolveConfiguredTaskRoute, type ResolvedTaskRoute, taskThinkingLevels } from "@henryqw/pi-task-models";
|
|
5
5
|
import { registerConfigReporting } from "@henryqw/pi-config-store";
|
|
6
|
-
import { capEphemeralSubagentOutput as capOutput, createEphemeralSubagentExecutor, createSubagentConfigStore, DEFAULT_SUBAGENT_CONFIG, DELEGATE_TASK, findRole, formatDuration, loadRoleCatalog, prepareRoleLaunch, resolveRolePackageResources, resolveTaskRoute, ROLE_TOOL_POLICY_FLAG, type Role } from "@henryqw/pi-subagent";
|
|
7
|
-
import { resolveExecutionPolicy
|
|
6
|
+
import { capEphemeralSubagentOutput as capOutput, createEphemeralSubagentExecutor, createSubagentConfigStore, DEFAULT_SUBAGENT_CONFIG, DELEGATE_TASK, findRole, formatDuration, loadRoleCatalog, prepareRoleLaunch, resolveRolePackageResources, resolveTaskRoute, ROLE_TOOL_POLICY_FLAG, type ExecutionPolicySnapshot, type Role } from "@henryqw/pi-subagent";
|
|
7
|
+
import { resolveExecutionPolicy } from "./config.ts";
|
|
8
8
|
import { registerCheckoutAdmission } from "./admission.ts";
|
|
9
9
|
import { registerIsolatedExtension } from "./isolated.ts";
|
|
10
10
|
import { directRef, registerSubagentCommand, type DirectDisplay, type DirectTask } from "./subagent-command.ts";
|
|
@@ -204,7 +204,7 @@ export default function subagentExtension(pi: ExtensionAPI): void {
|
|
|
204
204
|
});
|
|
205
205
|
// The isolated runner reads the policy lazily without a context, so each read reports through the session's.
|
|
206
206
|
let latestCtx: ExtensionContext | undefined;
|
|
207
|
-
const currentPolicy = ():
|
|
207
|
+
const currentPolicy = (): ExecutionPolicySnapshot => {
|
|
208
208
|
const loaded = configStore.loadSync();
|
|
209
209
|
if (latestCtx) configReporter.report(latestCtx, configStore, loaded);
|
|
210
210
|
const policy = resolveExecutionPolicy(configStore.path, loaded);
|
|
@@ -407,8 +407,8 @@ export default function subagentExtension(pi: ExtensionAPI): void {
|
|
|
407
407
|
const resolved = role.modelClass === undefined ? resolveConfiguredTaskRoute(ctx, DELEGATE_TASK) : resolveTaskRoute(ctx, role.modelClass);
|
|
408
408
|
route = { model: modelReference(resolved.model), thinking: resolved.thinkingLevel };
|
|
409
409
|
} catch (error) { route = { error: message(error) }; }
|
|
410
|
-
return { name: role.name, source: catalog.sources.get(role.name)
|
|
411
|
-
tools: role.tools
|
|
410
|
+
return { name: role.name, source: catalog.sources.get(role.name)!, modelClass: role.modelClass, route,
|
|
411
|
+
tools: role.tools, extensions: role.extensions, skills: role.skills, mcps: role.mcps ?? [] };
|
|
412
412
|
});
|
|
413
413
|
return { roles, errors: catalog.errors.map((error) => error.message) };
|
|
414
414
|
},
|