@codexhost/cli-darwin-x64 0.9.1 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/app/codexhost-distribution.json +1 -1
- package/app/desktop-controller.mjs +255 -179
- package/app/host-runtime.mjs +392 -225
- package/app/plugins/antigravity/plugin.mjs +55 -0
- package/app/plugins/claude-code/plugin.mjs +232 -41
- package/app/plugins/codebuddy/plugin.mjs +56 -1
- package/app/plugins/cursor-cli/plugin.mjs +55 -0
- package/app/plugins/deepseek-harness/plugin.mjs +55 -0
- package/app/plugins/grok/plugin.mjs +178 -82
- package/app/plugins/hermes/plugin.mjs +55 -0
- package/app/plugins/kiro-cli/plugin.mjs +55 -0
- package/app/plugins/omp/plugin.mjs +55 -0
- package/app/plugins/opencode/plugin.mjs +55 -0
- package/app/plugins/pi/plugin.mjs +1920 -769
- package/app/plugins/qoder/plugin.mjs +55 -0
- package/app/plugins/qoder-cn/plugin.mjs +55 -0
- package/app/plugins/workbuddy/plugin.mjs +56 -1
- package/app/renderer-extension.js +4225 -2820
- package/bin/codexhost +0 -0
- package/libexec/codexhost-shim +0 -0
- package/libexec/codexhost-updater +0 -0
- package/package.json +1 -1
|
@@ -5,9 +5,15 @@ var __export = (target, all) => {
|
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
// dist/pi-
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
// dist/pi-credential-imports.js
|
|
9
|
+
import { randomUUID } from "node:crypto";
|
|
10
|
+
import { execFile } from "node:child_process";
|
|
11
|
+
import { promisify } from "node:util";
|
|
12
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync, lstatSync, renameSync, rmdirSync } from "node:fs";
|
|
13
|
+
import { realpath } from "node:fs/promises";
|
|
14
|
+
import os2 from "node:os";
|
|
15
|
+
import path3 from "node:path";
|
|
16
|
+
import { pathToFileURL } from "node:url";
|
|
11
17
|
|
|
12
18
|
// ../../../node_modules/zod/v4/classic/external.js
|
|
13
19
|
var external_exports = {};
|
|
@@ -731,9 +737,9 @@ function floatSafeRemainder(val, step) {
|
|
|
731
737
|
return ratio - roundedRatio;
|
|
732
738
|
}
|
|
733
739
|
var EVALUATING = /* @__PURE__ */ Symbol("evaluating");
|
|
734
|
-
function defineLazy(
|
|
740
|
+
function defineLazy(object3, key, getter) {
|
|
735
741
|
let value = void 0;
|
|
736
|
-
Object.defineProperty(
|
|
742
|
+
Object.defineProperty(object3, key, {
|
|
737
743
|
get() {
|
|
738
744
|
if (value === EVALUATING) {
|
|
739
745
|
return void 0;
|
|
@@ -745,7 +751,7 @@ function defineLazy(object2, key, getter) {
|
|
|
745
751
|
return value;
|
|
746
752
|
},
|
|
747
753
|
set(v) {
|
|
748
|
-
Object.defineProperty(
|
|
754
|
+
Object.defineProperty(object3, key, {
|
|
749
755
|
value: v
|
|
750
756
|
// configurable: true,
|
|
751
757
|
});
|
|
@@ -775,10 +781,10 @@ function mergeDefs(...defs) {
|
|
|
775
781
|
function cloneDef(schema) {
|
|
776
782
|
return mergeDefs(schema._zod.def);
|
|
777
783
|
}
|
|
778
|
-
function getElementAtPath(obj,
|
|
779
|
-
if (!
|
|
784
|
+
function getElementAtPath(obj, path10) {
|
|
785
|
+
if (!path10)
|
|
780
786
|
return obj;
|
|
781
|
-
return
|
|
787
|
+
return path10.reduce((acc, key) => acc?.[key], obj);
|
|
782
788
|
}
|
|
783
789
|
function promiseAllObject(promisesObj) {
|
|
784
790
|
const keys = Object.keys(promisesObj);
|
|
@@ -1187,11 +1193,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
1187
1193
|
}
|
|
1188
1194
|
return false;
|
|
1189
1195
|
}
|
|
1190
|
-
function prefixIssues(
|
|
1196
|
+
function prefixIssues(path10, issues) {
|
|
1191
1197
|
return issues.map((iss) => {
|
|
1192
1198
|
var _a3;
|
|
1193
1199
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
1194
|
-
iss.path.unshift(
|
|
1200
|
+
iss.path.unshift(path10);
|
|
1195
1201
|
return iss;
|
|
1196
1202
|
});
|
|
1197
1203
|
}
|
|
@@ -1338,16 +1344,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
1338
1344
|
}
|
|
1339
1345
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
1340
1346
|
const fieldErrors = { _errors: [] };
|
|
1341
|
-
const processError = (error52,
|
|
1347
|
+
const processError = (error52, path10 = []) => {
|
|
1342
1348
|
for (const issue2 of error52.issues) {
|
|
1343
1349
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
1344
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
1350
|
+
issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
|
|
1345
1351
|
} else if (issue2.code === "invalid_key") {
|
|
1346
|
-
processError({ issues: issue2.issues }, [...
|
|
1352
|
+
processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
|
|
1347
1353
|
} else if (issue2.code === "invalid_element") {
|
|
1348
|
-
processError({ issues: issue2.issues }, [...
|
|
1354
|
+
processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
|
|
1349
1355
|
} else {
|
|
1350
|
-
const fullpath = [...
|
|
1356
|
+
const fullpath = [...path10, ...issue2.path];
|
|
1351
1357
|
if (fullpath.length === 0) {
|
|
1352
1358
|
fieldErrors._errors.push(mapper(issue2));
|
|
1353
1359
|
} else {
|
|
@@ -1374,17 +1380,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
1374
1380
|
}
|
|
1375
1381
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
1376
1382
|
const result = { errors: [] };
|
|
1377
|
-
const processError = (error52,
|
|
1383
|
+
const processError = (error52, path10 = []) => {
|
|
1378
1384
|
var _a3, _b;
|
|
1379
1385
|
for (const issue2 of error52.issues) {
|
|
1380
1386
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
1381
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
1387
|
+
issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
|
|
1382
1388
|
} else if (issue2.code === "invalid_key") {
|
|
1383
|
-
processError({ issues: issue2.issues }, [...
|
|
1389
|
+
processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
|
|
1384
1390
|
} else if (issue2.code === "invalid_element") {
|
|
1385
|
-
processError({ issues: issue2.issues }, [...
|
|
1391
|
+
processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
|
|
1386
1392
|
} else {
|
|
1387
|
-
const fullpath = [...
|
|
1393
|
+
const fullpath = [...path10, ...issue2.path];
|
|
1388
1394
|
if (fullpath.length === 0) {
|
|
1389
1395
|
result.errors.push(mapper(issue2));
|
|
1390
1396
|
continue;
|
|
@@ -1416,8 +1422,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
1416
1422
|
}
|
|
1417
1423
|
function toDotPath(_path) {
|
|
1418
1424
|
const segs = [];
|
|
1419
|
-
const
|
|
1420
|
-
for (const seg of
|
|
1425
|
+
const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1426
|
+
for (const seg of path10) {
|
|
1421
1427
|
if (typeof seg === "number")
|
|
1422
1428
|
segs.push(`[${seg}]`);
|
|
1423
1429
|
else if (typeof seg === "symbol")
|
|
@@ -2670,9 +2676,9 @@ var $ZodE164 = /* @__PURE__ */ $constructor("$ZodE164", (inst, def) => {
|
|
|
2670
2676
|
def.pattern ?? (def.pattern = e164);
|
|
2671
2677
|
$ZodStringFormat.init(inst, def);
|
|
2672
2678
|
});
|
|
2673
|
-
function isValidJWT(
|
|
2679
|
+
function isValidJWT(token2, algorithm = null) {
|
|
2674
2680
|
try {
|
|
2675
|
-
const tokensParts =
|
|
2681
|
+
const tokensParts = token2.split(".");
|
|
2676
2682
|
if (tokensParts.length !== 3)
|
|
2677
2683
|
return false;
|
|
2678
2684
|
const [header] = tokensParts;
|
|
@@ -7647,8 +7653,8 @@ function ko_default() {
|
|
|
7647
7653
|
}
|
|
7648
7654
|
|
|
7649
7655
|
// ../../../node_modules/zod/v4/locales/lt.js
|
|
7650
|
-
var capitalizeFirstCharacter = (
|
|
7651
|
-
return
|
|
7656
|
+
var capitalizeFirstCharacter = (text2) => {
|
|
7657
|
+
return text2.charAt(0).toUpperCase() + text2.slice(1);
|
|
7652
7658
|
};
|
|
7653
7659
|
function getUnitTypeFromNumber(number4) {
|
|
7654
7660
|
const abs = Math.abs(number4);
|
|
@@ -14109,13 +14115,13 @@ function resolveRef(ref, ctx) {
|
|
|
14109
14115
|
if (!ref.startsWith("#")) {
|
|
14110
14116
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
14111
14117
|
}
|
|
14112
|
-
const
|
|
14113
|
-
if (
|
|
14118
|
+
const path10 = ref.slice(1).split("/").filter(Boolean);
|
|
14119
|
+
if (path10.length === 0) {
|
|
14114
14120
|
return ctx.rootSchema;
|
|
14115
14121
|
}
|
|
14116
14122
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
14117
|
-
if (
|
|
14118
|
-
const key =
|
|
14123
|
+
if (path10[0] === defsKey) {
|
|
14124
|
+
const key = path10[1];
|
|
14119
14125
|
if (!key || !ctx.defs[key]) {
|
|
14120
14126
|
throw new Error(`Reference not found: ${ref}`);
|
|
14121
14127
|
}
|
|
@@ -14523,6 +14529,61 @@ function date4(params) {
|
|
|
14523
14529
|
// ../../../node_modules/zod/v4/classic/external.js
|
|
14524
14530
|
config(en_default());
|
|
14525
14531
|
|
|
14532
|
+
// ../../shared-contracts/dist/credential-imports.js
|
|
14533
|
+
var credentialSourceSchema = external_exports.object({
|
|
14534
|
+
id: external_exports.string().min(1).max(256),
|
|
14535
|
+
harnessId: external_exports.string().min(1),
|
|
14536
|
+
label: external_exports.string().min(1).max(512),
|
|
14537
|
+
provider: external_exports.enum(["openai-codex", "xai"])
|
|
14538
|
+
}).strict();
|
|
14539
|
+
var credentialImportNameSchema = external_exports.string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
14540
|
+
var credentialImportRecordSchema = external_exports.object({
|
|
14541
|
+
name: credentialImportNameSchema,
|
|
14542
|
+
source: credentialSourceSchema,
|
|
14543
|
+
importedAt: external_exports.string()
|
|
14544
|
+
}).strict();
|
|
14545
|
+
var credentialImportsRequestSchema = external_exports.discriminatedUnion("action", [
|
|
14546
|
+
external_exports.object({ action: external_exports.literal("list") }).strict(),
|
|
14547
|
+
external_exports.object({
|
|
14548
|
+
action: external_exports.literal("import"),
|
|
14549
|
+
sourceId: external_exports.string().min(1).max(256),
|
|
14550
|
+
name: credentialImportNameSchema,
|
|
14551
|
+
confirmed: external_exports.literal(true)
|
|
14552
|
+
}).strict(),
|
|
14553
|
+
external_exports.object({
|
|
14554
|
+
action: external_exports.literal("reimport"),
|
|
14555
|
+
sourceId: external_exports.string().min(1).max(256),
|
|
14556
|
+
name: credentialImportNameSchema,
|
|
14557
|
+
confirmed: external_exports.literal(true)
|
|
14558
|
+
}).strict(),
|
|
14559
|
+
external_exports.object({
|
|
14560
|
+
action: external_exports.literal("remove"),
|
|
14561
|
+
name: credentialImportNameSchema,
|
|
14562
|
+
confirmed: external_exports.literal(true)
|
|
14563
|
+
}).strict()
|
|
14564
|
+
]);
|
|
14565
|
+
var credentialOtherLoginSchema = external_exports.object({
|
|
14566
|
+
provider: external_exports.string().min(1).max(128),
|
|
14567
|
+
type: external_exports.enum(["oauth", "api_key", "unknown"]),
|
|
14568
|
+
/** Best-effort account label (e.g. the email in a Codex token), derived locally when present. */
|
|
14569
|
+
label: external_exports.string().min(1).max(512).optional(),
|
|
14570
|
+
/** Recognized credential vendor, derived from the OAuth token issuer. Absent when unknown. */
|
|
14571
|
+
vendor: external_exports.enum(["openai-codex", "xai"]).optional()
|
|
14572
|
+
}).strict();
|
|
14573
|
+
var credentialImportsResultSchema = external_exports.object({
|
|
14574
|
+
sources: external_exports.array(credentialSourceSchema),
|
|
14575
|
+
targets: external_exports.array(external_exports.object({
|
|
14576
|
+
harnessId: external_exports.string(),
|
|
14577
|
+
providers: external_exports.array(external_exports.enum(["openai-codex", "xai"])),
|
|
14578
|
+
imports: external_exports.array(credentialImportRecordSchema),
|
|
14579
|
+
others: external_exports.array(credentialOtherLoginSchema).default([])
|
|
14580
|
+
}).strict())
|
|
14581
|
+
}).strict();
|
|
14582
|
+
var credentialImportsParamsSchema = external_exports.object({
|
|
14583
|
+
targetHarnessId: external_exports.string().min(1).max(128).optional(),
|
|
14584
|
+
request: credentialImportsRequestSchema
|
|
14585
|
+
}).strict();
|
|
14586
|
+
|
|
14526
14587
|
// ../../shared-contracts/dist/version.js
|
|
14527
14588
|
var WORKSPACE_CONTRACT_VERSION = 1;
|
|
14528
14589
|
|
|
@@ -14919,8 +14980,8 @@ var harnessConfigurationStateSchema = external_exports.object({
|
|
|
14919
14980
|
effectiveThinkingOptionId: harnessThinkingOptionIdSchema.optional(),
|
|
14920
14981
|
availableThinkingOptions: harnessThinkingOptionsSchema.optional(),
|
|
14921
14982
|
effectivePermissionModeId: harnessPermissionModeIdSchema.optional()
|
|
14922
|
-
}).strict().superRefine((
|
|
14923
|
-
if (
|
|
14983
|
+
}).strict().superRefine((state2, context) => {
|
|
14984
|
+
if (state2.effectiveThinkingOptionId && state2.availableThinkingOptions && !state2.availableThinkingOptions.some(({ id }) => id === state2.effectiveThinkingOptionId)) {
|
|
14924
14985
|
context.addIssue({
|
|
14925
14986
|
code: "custom",
|
|
14926
14987
|
message: "Effective Thinking option must be currently available",
|
|
@@ -15390,152 +15451,1106 @@ var updateStatusResultSchema = external_exports.strictObject({
|
|
|
15390
15451
|
// ../../shared-contracts/dist/index.js
|
|
15391
15452
|
var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
|
|
15392
15453
|
|
|
15393
|
-
// dist/
|
|
15394
|
-
import
|
|
15395
|
-
import { link, open as open2, rm } from "node:fs/promises";
|
|
15454
|
+
// ../../harness-discovery/dist/environment.js
|
|
15455
|
+
import fs from "node:fs";
|
|
15396
15456
|
import path from "node:path";
|
|
15397
|
-
|
|
15398
|
-
|
|
15399
|
-
var PI_MODEL_REF_PREFIX = "pi-model-v1.";
|
|
15400
|
-
var PI_DRAFT_THINKING_OPTION_IDS = [
|
|
15401
|
-
"off",
|
|
15402
|
-
"minimal",
|
|
15403
|
-
"low",
|
|
15404
|
-
"medium",
|
|
15405
|
-
"high",
|
|
15406
|
-
"xhigh",
|
|
15407
|
-
"max"
|
|
15408
|
-
].map((id) => harnessThinkingOptionIdSchema.parse(id));
|
|
15409
|
-
var PI_THINKING_LABELS = {
|
|
15410
|
-
off: "Off",
|
|
15411
|
-
minimal: "Minimal",
|
|
15412
|
-
low: "Low",
|
|
15413
|
-
medium: "Medium",
|
|
15414
|
-
high: "High",
|
|
15415
|
-
xhigh: "Extra High",
|
|
15416
|
-
max: "Max"
|
|
15417
|
-
};
|
|
15418
|
-
function compareText(left, right) {
|
|
15419
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
15457
|
+
function targetPath(platform) {
|
|
15458
|
+
return platform === "win32" ? path.win32 : path.posix;
|
|
15420
15459
|
}
|
|
15421
|
-
function
|
|
15422
|
-
|
|
15423
|
-
|
|
15460
|
+
function environmentValue(environment, name) {
|
|
15461
|
+
const lowered = name.toLowerCase();
|
|
15462
|
+
for (const [key, value] of Object.entries(environment)) {
|
|
15463
|
+
if (key.toLowerCase() === lowered)
|
|
15464
|
+
return value;
|
|
15465
|
+
}
|
|
15466
|
+
return void 0;
|
|
15424
15467
|
}
|
|
15425
|
-
function
|
|
15426
|
-
|
|
15427
|
-
assertNativePart(model.id, "Model id");
|
|
15428
|
-
const encoded = Buffer.from(JSON.stringify([model.provider, model.id]), "utf8").toString("base64url");
|
|
15429
|
-
return harnessModelRefSchema.parse({ id: `${PI_MODEL_REF_PREFIX}${encoded}` });
|
|
15468
|
+
function pathDelimiter(platform) {
|
|
15469
|
+
return platform === "win32" ? ";" : ":";
|
|
15430
15470
|
}
|
|
15431
|
-
function
|
|
15432
|
-
|
|
15433
|
-
|
|
15434
|
-
|
|
15435
|
-
|
|
15436
|
-
|
|
15437
|
-
|
|
15471
|
+
function pathDirectories(environment, platform) {
|
|
15472
|
+
return (environmentValue(environment, "PATH") ?? "").split(pathDelimiter(platform)).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean);
|
|
15473
|
+
}
|
|
15474
|
+
function executableExtensions(command, platform, environment) {
|
|
15475
|
+
if (platform !== "win32")
|
|
15476
|
+
return [""];
|
|
15477
|
+
if (targetPath(platform).extname(command) !== "")
|
|
15478
|
+
return [""];
|
|
15479
|
+
return (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean);
|
|
15480
|
+
}
|
|
15481
|
+
function isExecutableFile(filePath, platform) {
|
|
15438
15482
|
try {
|
|
15439
|
-
|
|
15483
|
+
fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
|
|
15484
|
+
return fs.statSync(filePath).isFile();
|
|
15440
15485
|
} catch {
|
|
15441
|
-
|
|
15442
|
-
}
|
|
15443
|
-
if (!Array.isArray(decoded) || decoded.length !== 2 || typeof decoded[0] !== "string" || typeof decoded[1] !== "string") {
|
|
15444
|
-
throw new Error("Pi Model Ref has an invalid native identity");
|
|
15445
|
-
}
|
|
15446
|
-
const native = { provider: decoded[0], id: decoded[1] };
|
|
15447
|
-
assertNativePart(native.provider, "Model provider");
|
|
15448
|
-
assertNativePart(native.id, "Model id");
|
|
15449
|
-
if (encodePiModelRef(native).id !== parsedRef.id) {
|
|
15450
|
-
throw new Error("Pi Model Ref is not canonical");
|
|
15486
|
+
return false;
|
|
15451
15487
|
}
|
|
15452
|
-
return native;
|
|
15453
15488
|
}
|
|
15454
|
-
function
|
|
15455
|
-
|
|
15489
|
+
function subdirectoryNames(directory) {
|
|
15490
|
+
try {
|
|
15491
|
+
return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
15492
|
+
} catch {
|
|
15493
|
+
return [];
|
|
15494
|
+
}
|
|
15456
15495
|
}
|
|
15457
|
-
function
|
|
15458
|
-
|
|
15459
|
-
return label || id;
|
|
15496
|
+
function newestFirst(names) {
|
|
15497
|
+
return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
|
|
15460
15498
|
}
|
|
15461
|
-
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
|
|
15499
|
+
|
|
15500
|
+
// ../../harness-discovery/dist/node-runtime.js
|
|
15501
|
+
import path2 from "node:path";
|
|
15502
|
+
function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
|
|
15503
|
+
const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
|
|
15504
|
+
const delimiter = platform === "win32" ? ";" : ":";
|
|
15505
|
+
const runtimeDirectory = path2.dirname(runtimeExecutable);
|
|
15506
|
+
const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
|
|
15507
|
+
const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
|
|
15508
|
+
if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
|
|
15509
|
+
directories.push(runtimeDirectory);
|
|
15510
|
+
}
|
|
15511
|
+
return { ...environment, [pathKey]: directories.join(delimiter) };
|
|
15466
15512
|
}
|
|
15467
|
-
|
|
15468
|
-
|
|
15469
|
-
|
|
15470
|
-
|
|
15471
|
-
|
|
15472
|
-
|
|
15473
|
-
|
|
15474
|
-
|
|
15475
|
-
|
|
15476
|
-
|
|
15513
|
+
|
|
15514
|
+
// ../../harness-discovery/dist/resolve.js
|
|
15515
|
+
import os from "node:os";
|
|
15516
|
+
|
|
15517
|
+
// ../../harness-discovery/dist/version-managers.js
|
|
15518
|
+
function versionManagerBinaryDirectories(context) {
|
|
15519
|
+
const { platform, environment, home } = context;
|
|
15520
|
+
const list = context.subdirectories ?? subdirectoryNames;
|
|
15521
|
+
const pathFlavor = targetPath(platform);
|
|
15522
|
+
const value = (name) => environmentValue(environment, name);
|
|
15523
|
+
const directories = [];
|
|
15524
|
+
const versioned = (root, ...tail) => {
|
|
15525
|
+
for (const version2 of newestFirst(list(root))) {
|
|
15526
|
+
directories.push(pathFlavor.join(root, version2, ...tail));
|
|
15477
15527
|
}
|
|
15478
|
-
|
|
15479
|
-
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15483
|
-
|
|
15484
|
-
|
|
15485
|
-
|
|
15486
|
-
|
|
15487
|
-
|
|
15488
|
-
|
|
15528
|
+
};
|
|
15529
|
+
if (platform === "win32") {
|
|
15530
|
+
const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
|
|
15531
|
+
const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
|
|
15532
|
+
versioned(pathFlavor.join(appData, "nvm"));
|
|
15533
|
+
versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
|
|
15534
|
+
directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
|
|
15535
|
+
directories.push(pathFlavor.join(home, ".bun", "bin"));
|
|
15536
|
+
const pnpmHome2 = value("PNPM_HOME");
|
|
15537
|
+
if (pnpmHome2)
|
|
15538
|
+
directories.push(pnpmHome2);
|
|
15539
|
+
directories.push(pathFlavor.join(localAppData, "pnpm"));
|
|
15540
|
+
return directories;
|
|
15489
15541
|
}
|
|
15490
|
-
|
|
15491
|
-
|
|
15542
|
+
versioned(pathFlavor.join(value("NVM_DIR") ?? pathFlavor.join(home, ".nvm"), "versions", "node"), "bin");
|
|
15543
|
+
const fnmRoots = [
|
|
15544
|
+
value("FNM_DIR"),
|
|
15545
|
+
pathFlavor.join(home, ".local", "share", "fnm"),
|
|
15546
|
+
pathFlavor.join(home, "Library", "Application Support", "fnm")
|
|
15547
|
+
].filter((root) => root !== void 0);
|
|
15548
|
+
for (const root of fnmRoots) {
|
|
15549
|
+
versioned(pathFlavor.join(root, "node-versions"), "installation", "bin");
|
|
15492
15550
|
}
|
|
15493
|
-
|
|
15494
|
-
|
|
15551
|
+
const voltaHome = value("VOLTA_HOME") ?? pathFlavor.join(home, ".volta");
|
|
15552
|
+
versioned(pathFlavor.join(voltaHome, "tools", "image", "node"), "bin");
|
|
15553
|
+
directories.push(pathFlavor.join(voltaHome, "bin"));
|
|
15554
|
+
const asdfHome = value("ASDF_DATA_DIR") ?? pathFlavor.join(home, ".asdf");
|
|
15555
|
+
versioned(pathFlavor.join(asdfHome, "installs", "nodejs"), "bin");
|
|
15556
|
+
directories.push(pathFlavor.join(asdfHome, "shims"));
|
|
15557
|
+
const nodenvHome = value("NODENV_ROOT") ?? pathFlavor.join(home, ".nodenv");
|
|
15558
|
+
versioned(pathFlavor.join(nodenvHome, "versions"), "bin");
|
|
15559
|
+
directories.push(pathFlavor.join(nodenvHome, "shims"));
|
|
15560
|
+
versioned(pathFlavor.join(value("N_PREFIX") ?? "/usr/local", "n", "versions", "node"), "bin");
|
|
15561
|
+
directories.push(pathFlavor.join(home, ".bun", "bin"));
|
|
15562
|
+
const pnpmHome = value("PNPM_HOME");
|
|
15563
|
+
if (pnpmHome)
|
|
15564
|
+
directories.push(pnpmHome);
|
|
15565
|
+
directories.push(pathFlavor.join(home, "Library", "pnpm"));
|
|
15566
|
+
directories.push(pathFlavor.join(home, ".local", "share", "pnpm"));
|
|
15567
|
+
for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
|
|
15568
|
+
for (const formula of newestFirst(list(prefix).filter((name) => name.startsWith("node@")))) {
|
|
15569
|
+
directories.push(pathFlavor.join(prefix, formula, "bin"));
|
|
15570
|
+
}
|
|
15495
15571
|
}
|
|
15496
|
-
|
|
15497
|
-
const allThinkingOptionIds = thinkingOptions.map(({ id }) => id);
|
|
15498
|
-
const offThinkingOptionId = thinkingOptions.find(({ id }) => id === "off")?.id;
|
|
15499
|
-
const models = [...byRef.values()].map(({ model, reasoning }) => ({
|
|
15500
|
-
...model,
|
|
15501
|
-
supportedThinkingOptionIds: reasoning ? allThinkingOptionIds : offThinkingOptionId ? [offThinkingOptionId] : []
|
|
15502
|
-
})).sort((left, right) => compareText(left.label, right.label) || compareText(left.ref.id, right.ref.id));
|
|
15503
|
-
const defaultThinkingOptionId = thinkingOptions.find(({ id }) => id === effectiveThinkingOptionId)?.id;
|
|
15504
|
-
return harnessModelCatalogSchema.parse({
|
|
15505
|
-
models,
|
|
15506
|
-
...defaultModel ? { defaultModel } : {},
|
|
15507
|
-
thinkingOptions,
|
|
15508
|
-
...defaultThinkingOptionId ? { defaultThinkingOptionId } : {}
|
|
15509
|
-
});
|
|
15572
|
+
return directories;
|
|
15510
15573
|
}
|
|
15511
15574
|
|
|
15512
|
-
// dist/
|
|
15513
|
-
var
|
|
15514
|
-
function
|
|
15515
|
-
return
|
|
15516
|
-
}
|
|
15517
|
-
function textContent(value) {
|
|
15518
|
-
if (typeof value === "string")
|
|
15519
|
-
return value;
|
|
15520
|
-
if (!Array.isArray(value))
|
|
15521
|
-
return "";
|
|
15522
|
-
return value.filter((part) => isRecord(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
|
|
15575
|
+
// ../../harness-discovery/dist/resolve.js
|
|
15576
|
+
var VERSION_MANAGER_ROOTS = "<version-managers>";
|
|
15577
|
+
function installRootExtensions(platform) {
|
|
15578
|
+
return platform === "win32" ? [".exe", ".cmd"] : [""];
|
|
15523
15579
|
}
|
|
15524
|
-
function
|
|
15525
|
-
|
|
15526
|
-
return "";
|
|
15527
|
-
return value.filter((part) => isRecord(part) && part.type === "thinking" && typeof part.thinking === "string").map((part) => part.thinking).join("");
|
|
15580
|
+
function resolveHomeDirectory(input) {
|
|
15581
|
+
return input.homeDirectory ?? environmentValue(input.environment, "HOME") ?? environmentValue(input.environment, "USERPROFILE") ?? os.homedir();
|
|
15528
15582
|
}
|
|
15529
|
-
function
|
|
15530
|
-
|
|
15531
|
-
|
|
15532
|
-
|
|
15533
|
-
|
|
15583
|
+
function templateVariables(environment, platform, home) {
|
|
15584
|
+
const pathFlavor = targetPath(platform);
|
|
15585
|
+
return {
|
|
15586
|
+
HOME: home,
|
|
15587
|
+
USERPROFILE: home,
|
|
15588
|
+
APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
|
|
15589
|
+
LOCALAPPDATA: environmentValue(environment, "LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local")
|
|
15590
|
+
};
|
|
15534
15591
|
}
|
|
15535
|
-
function
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
const
|
|
15592
|
+
function joinTemplate(platform, value) {
|
|
15593
|
+
const pathFlavor = targetPath(platform);
|
|
15594
|
+
const segments = value.split("/");
|
|
15595
|
+
const head = segments[0] ?? "";
|
|
15596
|
+
const tail = segments.slice(1);
|
|
15597
|
+
if (head === "")
|
|
15598
|
+
return pathFlavor.join(pathFlavor.sep, ...tail);
|
|
15599
|
+
return tail.length === 0 ? head : pathFlavor.join(head, ...tail);
|
|
15600
|
+
}
|
|
15601
|
+
function expandInstallRoot(template, environment, platform, home) {
|
|
15602
|
+
const variables = templateVariables(environment, platform, home);
|
|
15603
|
+
let unresolved = false;
|
|
15604
|
+
const substituted = template.replace(/^~(?=\/|$)/u, home).replace(/\$\{(\w+)\}/gu, (_match, name) => {
|
|
15605
|
+
const value = variables[name] ?? environmentValue(environment, name);
|
|
15606
|
+
if (value === void 0 || value === "") {
|
|
15607
|
+
unresolved = true;
|
|
15608
|
+
return "";
|
|
15609
|
+
}
|
|
15610
|
+
return value;
|
|
15611
|
+
});
|
|
15612
|
+
return unresolved ? void 0 : joinTemplate(platform, substituted);
|
|
15613
|
+
}
|
|
15614
|
+
function installRootDirectories(spec, input, dependencies, platform, home) {
|
|
15615
|
+
const templates = (platform === "win32" ? spec.installRoots?.windows : spec.installRoots?.posix) ?? [];
|
|
15616
|
+
const directories = [];
|
|
15617
|
+
for (const template of templates) {
|
|
15618
|
+
if (template === VERSION_MANAGER_ROOTS) {
|
|
15619
|
+
directories.push(...versionManagerBinaryDirectories({
|
|
15620
|
+
platform,
|
|
15621
|
+
environment: input.environment,
|
|
15622
|
+
home,
|
|
15623
|
+
...dependencies.subdirectories ? { subdirectories: dependencies.subdirectories } : {}
|
|
15624
|
+
}));
|
|
15625
|
+
continue;
|
|
15626
|
+
}
|
|
15627
|
+
const directory = expandInstallRoot(template, input.environment, platform, home);
|
|
15628
|
+
if (directory !== void 0)
|
|
15629
|
+
directories.push(directory);
|
|
15630
|
+
}
|
|
15631
|
+
return directories;
|
|
15632
|
+
}
|
|
15633
|
+
function harnessCandidates(spec, input, dependencies = {}) {
|
|
15634
|
+
const platform = input.platform ?? process.platform;
|
|
15635
|
+
const pathFlavor = targetPath(platform);
|
|
15636
|
+
const configured = input.command ?? (spec.commandEnvironmentVariable ? environmentValue(input.environment, spec.commandEnvironmentVariable) : void 0);
|
|
15637
|
+
const command = configured ?? spec.command;
|
|
15638
|
+
if (pathFlavor.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
|
|
15639
|
+
return [{ candidate: command, source: "configured" }];
|
|
15640
|
+
}
|
|
15641
|
+
const candidates = [];
|
|
15642
|
+
const extensions = executableExtensions(command, platform, input.environment);
|
|
15643
|
+
for (const directory of pathDirectories(input.environment, platform)) {
|
|
15644
|
+
for (const extension of extensions) {
|
|
15645
|
+
candidates.push({
|
|
15646
|
+
candidate: pathFlavor.join(directory, command + extension),
|
|
15647
|
+
source: "path"
|
|
15648
|
+
});
|
|
15649
|
+
}
|
|
15650
|
+
}
|
|
15651
|
+
if (configured !== void 0)
|
|
15652
|
+
return candidates;
|
|
15653
|
+
const home = resolveHomeDirectory(input);
|
|
15654
|
+
for (const directory of installRootDirectories(spec, input, dependencies, platform, home)) {
|
|
15655
|
+
for (const extension of installRootExtensions(platform)) {
|
|
15656
|
+
candidates.push({
|
|
15657
|
+
candidate: pathFlavor.join(directory, spec.command + extension),
|
|
15658
|
+
source: "install-root"
|
|
15659
|
+
});
|
|
15660
|
+
}
|
|
15661
|
+
}
|
|
15662
|
+
return candidates;
|
|
15663
|
+
}
|
|
15664
|
+
function resolveHarnessExecutable(spec, input, dependencies = {}) {
|
|
15665
|
+
const platform = input.platform ?? process.platform;
|
|
15666
|
+
const isExecutable = dependencies.isExecutable ?? ((candidate) => isExecutableFile(candidate, platform));
|
|
15667
|
+
const runnable = spec.runnableCandidate ?? ((candidate) => candidate);
|
|
15668
|
+
const context = { platform, isExecutable };
|
|
15669
|
+
for (const { candidate, source } of harnessCandidates(spec, input, dependencies)) {
|
|
15670
|
+
const executable = runnable(candidate, context);
|
|
15671
|
+
if (executable !== void 0 && isExecutable(executable))
|
|
15672
|
+
return { executable, source };
|
|
15673
|
+
}
|
|
15674
|
+
return void 0;
|
|
15675
|
+
}
|
|
15676
|
+
|
|
15677
|
+
// dist/command.js
|
|
15678
|
+
var piDiscoverySpec = {
|
|
15679
|
+
id: "pi",
|
|
15680
|
+
command: "pi",
|
|
15681
|
+
commandEnvironmentVariable: "PI_COMMAND",
|
|
15682
|
+
installRoots: {
|
|
15683
|
+
posix: [
|
|
15684
|
+
"~/.npm-global/bin",
|
|
15685
|
+
"~/.local/bin",
|
|
15686
|
+
VERSION_MANAGER_ROOTS,
|
|
15687
|
+
"/opt/homebrew/bin",
|
|
15688
|
+
"/usr/local/bin"
|
|
15689
|
+
],
|
|
15690
|
+
windows: ["${APPDATA}/npm", "~/.local/bin", VERSION_MANAGER_ROOTS]
|
|
15691
|
+
}
|
|
15692
|
+
};
|
|
15693
|
+
function resolvePiExecutable(input, dependencies = {}) {
|
|
15694
|
+
const resolution = resolveHarnessExecutable(piDiscoverySpec, {
|
|
15695
|
+
...input.command ? { command: input.command } : {},
|
|
15696
|
+
environment: input.environment,
|
|
15697
|
+
...dependencies.platform ? { platform: dependencies.platform } : {},
|
|
15698
|
+
...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {}
|
|
15699
|
+
}, { ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {} });
|
|
15700
|
+
return resolution?.executable ?? input.command ?? input.environment.PI_COMMAND ?? "pi";
|
|
15701
|
+
}
|
|
15702
|
+
|
|
15703
|
+
// dist/pi-credential-imports.js
|
|
15704
|
+
var PREFIX = "codexhost-account-";
|
|
15705
|
+
function object2(value) {
|
|
15706
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15707
|
+
}
|
|
15708
|
+
function parseAuth(raw) {
|
|
15709
|
+
const value = JSON.parse(raw ?? "{}");
|
|
15710
|
+
if (!object2(value))
|
|
15711
|
+
throw new Error("Invalid Pi auth store");
|
|
15712
|
+
return value;
|
|
15713
|
+
}
|
|
15714
|
+
var OAUTH_VENDORS = [
|
|
15715
|
+
{
|
|
15716
|
+
issuer: "https://auth.openai.com",
|
|
15717
|
+
client: "app_EMoamEEZ73f0CkXaXp7hrann",
|
|
15718
|
+
vendor: "openai-codex"
|
|
15719
|
+
},
|
|
15720
|
+
{ issuer: "https://auth.x.ai", client: "b1a00492-073a-47ea-816f-4c329264a828", vendor: "xai" }
|
|
15721
|
+
];
|
|
15722
|
+
function describeOauth(credential) {
|
|
15723
|
+
if (!object2(credential) || credential.type !== "oauth")
|
|
15724
|
+
return {};
|
|
15725
|
+
const token2 = credential.access;
|
|
15726
|
+
if (typeof token2 !== "string")
|
|
15727
|
+
return {};
|
|
15728
|
+
let claims;
|
|
15729
|
+
try {
|
|
15730
|
+
claims = JSON.parse(Buffer.from(token2.split(".")[1] ?? "", "base64url").toString("utf8"));
|
|
15731
|
+
} catch {
|
|
15732
|
+
return {};
|
|
15733
|
+
}
|
|
15734
|
+
if (!object2(claims))
|
|
15735
|
+
return {};
|
|
15736
|
+
const match = OAUTH_VENDORS.find((candidate) => claims.iss === candidate.issuer && claims.client_id === candidate.client);
|
|
15737
|
+
const profile = claims["https://api.openai.com/profile"];
|
|
15738
|
+
const email3 = object2(profile) ? profile.email : claims.email;
|
|
15739
|
+
return {
|
|
15740
|
+
...typeof email3 === "string" && email3.length > 0 && email3.length <= 512 ? { label: email3 } : {},
|
|
15741
|
+
...match ? { vendor: match.vendor } : {}
|
|
15742
|
+
};
|
|
15743
|
+
}
|
|
15744
|
+
function writeAuth(filename, content) {
|
|
15745
|
+
const temporary = `${filename}.${randomUUID()}.tmp`;
|
|
15746
|
+
try {
|
|
15747
|
+
writeFileSync(temporary, content, { flag: "wx", mode: 384 });
|
|
15748
|
+
renameSync(temporary, filename);
|
|
15749
|
+
} finally {
|
|
15750
|
+
rmSync(temporary, { force: true });
|
|
15751
|
+
}
|
|
15752
|
+
}
|
|
15753
|
+
function removeOwnedFiles(dir) {
|
|
15754
|
+
rmSync(path3.join(dir, "index.ts"), { force: true });
|
|
15755
|
+
rmSync(path3.join(dir, "import.json"), { force: true });
|
|
15756
|
+
try {
|
|
15757
|
+
rmdirSync(dir);
|
|
15758
|
+
} catch {
|
|
15759
|
+
}
|
|
15760
|
+
}
|
|
15761
|
+
async function installation(command, environment, authPath) {
|
|
15762
|
+
const executable = await realpath(resolvePiExecutable({ ...command ? { command } : {}, environment }));
|
|
15763
|
+
let directory = path3.dirname(executable);
|
|
15764
|
+
while (true) {
|
|
15765
|
+
const manifest = path3.join(directory, "package.json");
|
|
15766
|
+
if (existsSync(manifest)) {
|
|
15767
|
+
const pkg = JSON.parse(readFileSync(manifest, "utf8"));
|
|
15768
|
+
if (pkg.name === "@earendil-works/pi-coding-agent")
|
|
15769
|
+
break;
|
|
15770
|
+
}
|
|
15771
|
+
const parent = path3.dirname(directory);
|
|
15772
|
+
if (parent === directory)
|
|
15773
|
+
throw new Error("Pi credential import requires a supported npm Pi installation");
|
|
15774
|
+
directory = parent;
|
|
15775
|
+
}
|
|
15776
|
+
const storage = await import(pathToFileURL(path3.join(directory, "dist/core/auth-storage.js")).href);
|
|
15777
|
+
const ai = path3.join(directory, "node_modules/@earendil-works/pi-ai/dist");
|
|
15778
|
+
const all = await import(pathToFileURL(path3.join(ai, "providers/all.js")).href);
|
|
15779
|
+
const providers = all.getBuiltinProviders();
|
|
15780
|
+
const providerModules = {
|
|
15781
|
+
"openai-codex": pathToFileURL(path3.join(ai, "providers/openai-codex.js")).href,
|
|
15782
|
+
xai: pathToFileURL(path3.join(ai, "providers/xai.js")).href
|
|
15783
|
+
};
|
|
15784
|
+
for (const [id, url2] of Object.entries(providerModules)) {
|
|
15785
|
+
const module = await import(url2);
|
|
15786
|
+
const provider = id === "xai" ? module.xaiProvider() : module.openaiCodexProvider();
|
|
15787
|
+
if (!provider.auth?.oauth || !provider.getModels().length)
|
|
15788
|
+
throw new Error("Pi version does not support subscription imports");
|
|
15789
|
+
}
|
|
15790
|
+
return {
|
|
15791
|
+
backend: new storage.FileAuthStorageBackend(authPath),
|
|
15792
|
+
providerModules,
|
|
15793
|
+
reservedNames: providers.map((p) => typeof p === "string" ? p : p.id),
|
|
15794
|
+
async configuredProviderNames() {
|
|
15795
|
+
const { stdout } = await promisify(execFile)(process.execPath, [executable, "--offline", "--no-approve", "--list-models"], {
|
|
15796
|
+
cwd: existsSync(path3.dirname(authPath)) ? path3.dirname(authPath) : os2.homedir(),
|
|
15797
|
+
env: { ...environment, PI_CODING_AGENT_DIR: path3.dirname(authPath), PI_OFFLINE: "1" },
|
|
15798
|
+
timeout: 15e3,
|
|
15799
|
+
maxBuffer: 4 * 1024 * 1024
|
|
15800
|
+
});
|
|
15801
|
+
return stdout.split(/\r?\n/).map((line) => line.trim().split(/\s+/)[0] ?? "").filter(Boolean);
|
|
15802
|
+
}
|
|
15803
|
+
};
|
|
15804
|
+
}
|
|
15805
|
+
function extensionSource(moduleUrl, provider, name, owner) {
|
|
15806
|
+
return `// Managed by codexhost. Removing this file disables the imported Provider.
|
|
15807
|
+
export default async function (pi) {
|
|
15808
|
+
const moduleUrl = ${JSON.stringify(moduleUrl)};
|
|
15809
|
+
const nativeModule = await import(moduleUrl);
|
|
15810
|
+
const native = nativeModule.${provider === "xai" ? "xaiProvider" : "openaiCodexProvider"}();
|
|
15811
|
+
const oauth = native.auth.oauth;
|
|
15812
|
+
const models = native.getModels().map(model => ({ ...model, provider: ${JSON.stringify(name)} }));
|
|
15813
|
+
pi.registerProvider({
|
|
15814
|
+
...native, id: ${JSON.stringify(name)}, name: ${JSON.stringify(name)},
|
|
15815
|
+
auth: { oauth: { ...oauth,
|
|
15816
|
+
async refresh(credential, signal) {
|
|
15817
|
+
return { ...await oauth.refresh(credential, signal), codexhostImportId: ${JSON.stringify(owner)} };
|
|
15818
|
+
}
|
|
15819
|
+
} },
|
|
15820
|
+
getModels: () => models
|
|
15821
|
+
});
|
|
15822
|
+
}
|
|
15823
|
+
`;
|
|
15824
|
+
}
|
|
15825
|
+
function createPiCredentialImports(options = {}) {
|
|
15826
|
+
const env = { ...process.env, ...options.environment };
|
|
15827
|
+
const agentDir = env.PI_CODING_AGENT_DIR ?? path3.join(env.HOME ?? os2.homedir(), ".pi/agent");
|
|
15828
|
+
const authPath = path3.join(agentDir, "auth.json");
|
|
15829
|
+
const extensionsDir = path3.join(agentDir, "extensions");
|
|
15830
|
+
const saveAuth = (auth) => (options.writeAuth ?? writeAuth)(authPath, JSON.stringify(auth, null, 2) + "\n");
|
|
15831
|
+
const resolve = () => options.resolveInstallation?.(authPath) ?? installation(options.command, env, authPath);
|
|
15832
|
+
const location = (name) => path3.join(extensionsDir, `${PREFIX}${credentialImportNameSchema.parse(name)}`);
|
|
15833
|
+
const readRecord = (name) => {
|
|
15834
|
+
const dir = location(name);
|
|
15835
|
+
if (lstatSync(dir).isSymbolicLink())
|
|
15836
|
+
throw new Error("Imported configuration was changed; manage it in Pi");
|
|
15837
|
+
const value = JSON.parse(readFileSync(path3.join(dir, "import.json"), "utf8"));
|
|
15838
|
+
if (value.version !== 1 || typeof value.owner !== "string" || typeof value.extension !== "string")
|
|
15839
|
+
throw new Error("Invalid import metadata");
|
|
15840
|
+
const record6 = value.record;
|
|
15841
|
+
if (!object2(record6))
|
|
15842
|
+
throw new Error("Invalid import metadata");
|
|
15843
|
+
value.record = credentialImportRecordSchema.parse({
|
|
15844
|
+
name: record6.name,
|
|
15845
|
+
source: record6.source,
|
|
15846
|
+
importedAt: record6.importedAt
|
|
15847
|
+
});
|
|
15848
|
+
if (value.record.name !== name)
|
|
15849
|
+
throw new Error("Import identity mismatch");
|
|
15850
|
+
return value;
|
|
15851
|
+
};
|
|
15852
|
+
const owned = (meta3, auth) => {
|
|
15853
|
+
const credential = auth[meta3.record.name];
|
|
15854
|
+
const file2 = path3.join(location(meta3.record.name), "index.ts");
|
|
15855
|
+
return existsSync(file2) && !lstatSync(file2).isSymbolicLink() && readFileSync(file2, "utf8") === meta3.extension && object2(credential) && credential.type === "oauth" && credential.codexhostImportId === meta3.owner;
|
|
15856
|
+
};
|
|
15857
|
+
const readAuth = () => existsSync(authPath) ? parseAuth(readFileSync(authPath, "utf8")) : {};
|
|
15858
|
+
const ownedRecords = (auth) => {
|
|
15859
|
+
if (!existsSync(extensionsDir))
|
|
15860
|
+
return [];
|
|
15861
|
+
const result = [];
|
|
15862
|
+
for (const entry of readdirSync(extensionsDir)) {
|
|
15863
|
+
if (!entry.startsWith(PREFIX))
|
|
15864
|
+
continue;
|
|
15865
|
+
const name = entry.slice(PREFIX.length);
|
|
15866
|
+
if (!credentialImportNameSchema.safeParse(name).success)
|
|
15867
|
+
continue;
|
|
15868
|
+
if (!existsSync(path3.join(location(name), "import.json")))
|
|
15869
|
+
continue;
|
|
15870
|
+
try {
|
|
15871
|
+
const meta3 = readRecord(name);
|
|
15872
|
+
if (owned(meta3, auth))
|
|
15873
|
+
result.push(meta3.record);
|
|
15874
|
+
} catch {
|
|
15875
|
+
}
|
|
15876
|
+
}
|
|
15877
|
+
return result;
|
|
15878
|
+
};
|
|
15879
|
+
return {
|
|
15880
|
+
providers: ["openai-codex", "xai"],
|
|
15881
|
+
async list() {
|
|
15882
|
+
if (!existsSync(agentDir))
|
|
15883
|
+
throw new Error("Pi has no configuration directory");
|
|
15884
|
+
await resolve();
|
|
15885
|
+
return ownedRecords(readAuth());
|
|
15886
|
+
},
|
|
15887
|
+
async listOthers() {
|
|
15888
|
+
const auth = readAuth();
|
|
15889
|
+
const ours = new Set(ownedRecords(auth).map((record6) => record6.name));
|
|
15890
|
+
const result = /* @__PURE__ */ new Map();
|
|
15891
|
+
const usable = (provider) => Boolean(provider) && provider.length <= 128 && !ours.has(provider) && !result.has(provider);
|
|
15892
|
+
for (const [provider, credential] of Object.entries(auth)) {
|
|
15893
|
+
if (!usable(provider))
|
|
15894
|
+
continue;
|
|
15895
|
+
const type = object2(credential) ? credential.type : void 0;
|
|
15896
|
+
result.set(provider, {
|
|
15897
|
+
provider,
|
|
15898
|
+
type: type === "oauth" || type === "api_key" ? type : "unknown",
|
|
15899
|
+
...describeOauth(credential)
|
|
15900
|
+
});
|
|
15901
|
+
}
|
|
15902
|
+
const modelsPath = path3.join(agentDir, "models.json");
|
|
15903
|
+
if (existsSync(modelsPath)) {
|
|
15904
|
+
const models = JSON.parse(readFileSync(modelsPath, "utf8"));
|
|
15905
|
+
const providers = object2(models) && object2(models.providers) ? models.providers : {};
|
|
15906
|
+
for (const [provider, definition] of Object.entries(providers)) {
|
|
15907
|
+
if (!usable(provider) || !object2(definition) || !definition.apiKey)
|
|
15908
|
+
continue;
|
|
15909
|
+
const name = definition.name;
|
|
15910
|
+
const label = typeof name === "string" && name && name !== provider ? name : void 0;
|
|
15911
|
+
result.set(provider, { provider, type: "api_key", ...label ? { label } : {} });
|
|
15912
|
+
}
|
|
15913
|
+
}
|
|
15914
|
+
return [...result.values()].sort((a, b) => a.provider.localeCompare(b.provider));
|
|
15915
|
+
},
|
|
15916
|
+
async add(name, transfer) {
|
|
15917
|
+
credentialImportNameSchema.parse(name);
|
|
15918
|
+
const sdk = await resolve();
|
|
15919
|
+
if (!this.providers.includes(transfer.source.provider))
|
|
15920
|
+
throw new Error("Unsupported credential source");
|
|
15921
|
+
if (sdk.reservedNames.includes(name) || (await sdk.configuredProviderNames?.())?.includes(name))
|
|
15922
|
+
throw new Error("Provider name already exists; choose another name");
|
|
15923
|
+
const owner = randomUUID();
|
|
15924
|
+
const record6 = credentialImportRecordSchema.parse({
|
|
15925
|
+
name,
|
|
15926
|
+
source: transfer.source,
|
|
15927
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
15928
|
+
});
|
|
15929
|
+
const extension = extensionSource(sdk.providerModules[transfer.source.provider], transfer.source.provider, name, owner);
|
|
15930
|
+
const dir = location(name);
|
|
15931
|
+
let created = false;
|
|
15932
|
+
let committed = false;
|
|
15933
|
+
try {
|
|
15934
|
+
sdk.backend.withLock((current) => {
|
|
15935
|
+
const auth = parseAuth(current);
|
|
15936
|
+
const modelsPath = path3.join(agentDir, "models.json");
|
|
15937
|
+
const models = existsSync(modelsPath) ? JSON.parse(readFileSync(modelsPath, "utf8")) : {};
|
|
15938
|
+
if (Object.hasOwn(auth, name) || Object.hasOwn(models.providers ?? {}, name) || existsSync(dir) || existsSync(path3.join(extensionsDir, `${name}-provider.ts`)))
|
|
15939
|
+
throw new Error("Provider name already exists; choose another name");
|
|
15940
|
+
mkdirSync(extensionsDir, { recursive: true, mode: 448 });
|
|
15941
|
+
mkdirSync(dir, { mode: 448 });
|
|
15942
|
+
created = true;
|
|
15943
|
+
writeFileSync(path3.join(dir, "import.json"), JSON.stringify({ version: 1, owner, record: record6, extension }), { flag: "wx", mode: 384 });
|
|
15944
|
+
writeFileSync(path3.join(dir, "index.ts"), extension, { flag: "wx", mode: 384 });
|
|
15945
|
+
auth[name] = { type: "oauth", ...transfer.oauth, codexhostImportId: owner };
|
|
15946
|
+
saveAuth(auth);
|
|
15947
|
+
committed = true;
|
|
15948
|
+
return { result: void 0 };
|
|
15949
|
+
});
|
|
15950
|
+
} catch (error51) {
|
|
15951
|
+
if (created && !committed)
|
|
15952
|
+
removeOwnedFiles(dir);
|
|
15953
|
+
throw error51;
|
|
15954
|
+
}
|
|
15955
|
+
},
|
|
15956
|
+
async reimport(name, transfer) {
|
|
15957
|
+
const sdk = await resolve();
|
|
15958
|
+
sdk.backend.withLock((current) => {
|
|
15959
|
+
const meta3 = readRecord(name);
|
|
15960
|
+
const auth = parseAuth(current);
|
|
15961
|
+
if (!owned(meta3, auth) || meta3.record.source.id !== transfer.source.id || meta3.record.source.provider !== transfer.source.provider)
|
|
15962
|
+
throw new Error("Import ownership or source account changed; refusing replacement");
|
|
15963
|
+
const metadataPath = path3.join(location(name), "import.json");
|
|
15964
|
+
const previous = readFileSync(metadataPath, "utf8");
|
|
15965
|
+
const updated = {
|
|
15966
|
+
...meta3,
|
|
15967
|
+
record: { ...meta3.record, importedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
15968
|
+
};
|
|
15969
|
+
writeAuth(metadataPath, JSON.stringify(updated));
|
|
15970
|
+
try {
|
|
15971
|
+
saveAuth({
|
|
15972
|
+
...auth,
|
|
15973
|
+
[name]: { type: "oauth", ...transfer.oauth, codexhostImportId: meta3.owner }
|
|
15974
|
+
});
|
|
15975
|
+
} catch (error51) {
|
|
15976
|
+
writeAuth(metadataPath, previous);
|
|
15977
|
+
throw error51;
|
|
15978
|
+
}
|
|
15979
|
+
return { result: void 0 };
|
|
15980
|
+
});
|
|
15981
|
+
},
|
|
15982
|
+
async remove(name) {
|
|
15983
|
+
const sdk = await resolve();
|
|
15984
|
+
const meta3 = readRecord(name);
|
|
15985
|
+
sdk.backend.withLock((current) => {
|
|
15986
|
+
const auth = parseAuth(current);
|
|
15987
|
+
if (!owned(meta3, auth))
|
|
15988
|
+
throw new Error("Imported configuration was changed; manage it in Pi");
|
|
15989
|
+
saveAuth(Object.fromEntries(Object.entries(auth).filter(([key]) => key !== name)));
|
|
15990
|
+
removeOwnedFiles(location(name));
|
|
15991
|
+
return { result: void 0 };
|
|
15992
|
+
});
|
|
15993
|
+
}
|
|
15994
|
+
};
|
|
15995
|
+
}
|
|
15996
|
+
|
|
15997
|
+
// dist/pi-empty-session.js
|
|
15998
|
+
import { createReadStream } from "node:fs";
|
|
15999
|
+
import { createInterface } from "node:readline";
|
|
16000
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
16001
|
+
import { link, open as open2, rm } from "node:fs/promises";
|
|
16002
|
+
import path4 from "node:path";
|
|
16003
|
+
|
|
16004
|
+
// dist/pi-subagents.js
|
|
16005
|
+
import { createHash } from "node:crypto";
|
|
16006
|
+
|
|
16007
|
+
// dist/pi-subagent-workflow.js
|
|
16008
|
+
var PREFIX2 = "pi-subagents-workflow-v1:";
|
|
16009
|
+
var STATES = {
|
|
16010
|
+
pending: "pending",
|
|
16011
|
+
running: "running",
|
|
16012
|
+
completed: "completed",
|
|
16013
|
+
failed: "failed",
|
|
16014
|
+
paused: "interrupted",
|
|
16015
|
+
stopped: "interrupted",
|
|
16016
|
+
rejected: "failed",
|
|
16017
|
+
detached: "running"
|
|
16018
|
+
};
|
|
16019
|
+
function record2(value) {
|
|
16020
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16021
|
+
}
|
|
16022
|
+
function text(value, limit = 256) {
|
|
16023
|
+
return typeof value === "string" && value.length > 0 && value.length <= limit;
|
|
16024
|
+
}
|
|
16025
|
+
function piWorkflowSummary(result) {
|
|
16026
|
+
if (!record2(result) || !record2(result.details) || result.details.mode !== "workflow" || result.details.asyncId !== void 0)
|
|
16027
|
+
return null;
|
|
16028
|
+
const details = result.details;
|
|
16029
|
+
const summary = details.workflowChildren;
|
|
16030
|
+
if (!record2(summary) || summary.version !== 1 || !text(summary.workflowRunId) || summary.workflowRunId !== details.runId || !text(summary.parentToolCallId) || typeof summary.inventoryComplete !== "boolean" || !Array.isArray(summary.children) || summary.children.length > 256)
|
|
16031
|
+
return null;
|
|
16032
|
+
const children = [];
|
|
16033
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16034
|
+
for (const child of summary.children) {
|
|
16035
|
+
if (!record2(child) || !text(child.childId) || seen.has(child.childId) || typeof child.state !== "string" || !Object.hasOwn(STATES, child.state))
|
|
16036
|
+
return null;
|
|
16037
|
+
for (const key of ["agent", "sessionName", "model", "thinking"]) {
|
|
16038
|
+
if (child[key] !== void 0 && !text(child[key], 2048))
|
|
16039
|
+
return null;
|
|
16040
|
+
}
|
|
16041
|
+
const mappedState = STATES[child.state];
|
|
16042
|
+
if (!mappedState)
|
|
16043
|
+
return null;
|
|
16044
|
+
seen.add(child.childId);
|
|
16045
|
+
children.push({
|
|
16046
|
+
childId: child.childId,
|
|
16047
|
+
state: mappedState,
|
|
16048
|
+
background: child.state === "detached",
|
|
16049
|
+
...typeof child.agent === "string" ? { agent: child.agent } : {},
|
|
16050
|
+
...typeof child.sessionName === "string" ? { sessionName: child.sessionName } : {},
|
|
16051
|
+
...typeof child.model === "string" ? { model: child.model } : {},
|
|
16052
|
+
...typeof child.thinking === "string" ? { thinking: child.thinking } : {}
|
|
16053
|
+
});
|
|
16054
|
+
}
|
|
16055
|
+
return {
|
|
16056
|
+
workflowRunId: summary.workflowRunId,
|
|
16057
|
+
parentToolCallId: summary.parentToolCallId,
|
|
16058
|
+
children
|
|
16059
|
+
};
|
|
16060
|
+
}
|
|
16061
|
+
function piWorkflowSubagentId(address) {
|
|
16062
|
+
return PREFIX2 + Buffer.from(JSON.stringify([address.workflowRunId, address.childId])).toString("base64url");
|
|
16063
|
+
}
|
|
16064
|
+
function parsePiWorkflowSubagentId(id) {
|
|
16065
|
+
if (!id.startsWith(PREFIX2))
|
|
16066
|
+
return null;
|
|
16067
|
+
if (id.length > 3e3)
|
|
16068
|
+
throw new Error("Invalid Pi workflow child identity");
|
|
16069
|
+
const value = JSON.parse(Buffer.from(id.slice(PREFIX2.length), "base64url").toString("utf8"));
|
|
16070
|
+
if (!Array.isArray(value) || value.length !== 2 || !text(value[0]) || !text(value[1]))
|
|
16071
|
+
throw new Error("Invalid Pi workflow child identity");
|
|
16072
|
+
const address = { workflowRunId: value[0], childId: value[1] };
|
|
16073
|
+
if (piWorkflowSubagentId(address) !== id)
|
|
16074
|
+
throw new Error("Non-canonical Pi workflow child identity");
|
|
16075
|
+
return address;
|
|
16076
|
+
}
|
|
16077
|
+
function projectPiWorkflow(summary, itemId2) {
|
|
16078
|
+
if (!summary.children.length)
|
|
16079
|
+
return null;
|
|
16080
|
+
return {
|
|
16081
|
+
type: "subagentDelegation",
|
|
16082
|
+
itemId: itemId2,
|
|
16083
|
+
operation: "spawn",
|
|
16084
|
+
subagents: summary.children.map((child) => {
|
|
16085
|
+
const id = piWorkflowSubagentId({
|
|
16086
|
+
workflowRunId: summary.workflowRunId,
|
|
16087
|
+
childId: child.childId
|
|
16088
|
+
});
|
|
16089
|
+
return {
|
|
16090
|
+
subagentId: id,
|
|
16091
|
+
nativeSubagentId: id,
|
|
16092
|
+
description: child.sessionName ?? child.agent ?? child.childId,
|
|
16093
|
+
status: child.state,
|
|
16094
|
+
background: child.background,
|
|
16095
|
+
...child.agent ? { role: child.agent } : {},
|
|
16096
|
+
...child.model ? { model: child.model } : {},
|
|
16097
|
+
...child.thinking ? { reasoningEffort: child.thinking } : {}
|
|
16098
|
+
};
|
|
16099
|
+
})
|
|
16100
|
+
};
|
|
16101
|
+
}
|
|
16102
|
+
|
|
16103
|
+
// dist/pi-subagents.js
|
|
16104
|
+
var STATUS_PREFIX = "PI_SUBAGENT_ASYNC_JSON:";
|
|
16105
|
+
var INSPECT_PREFIX = "PI_SUBAGENT_INSPECT_JSON:";
|
|
16106
|
+
var ID_PREFIX = "pi-subagents-v1:";
|
|
16107
|
+
var MAX_BYTES = 64 * 1024;
|
|
16108
|
+
function record3(value) {
|
|
16109
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16110
|
+
}
|
|
16111
|
+
function token(value) {
|
|
16112
|
+
return typeof value === "string" && value.length > 0 && value.length <= 256 && !value.startsWith("--") && !/\s/u.test(value) && [...value].every((character) => character.charCodeAt(0) > 32 && character.charCodeAt(0) !== 127);
|
|
16113
|
+
}
|
|
16114
|
+
var statuses = {
|
|
16115
|
+
queued: "pending",
|
|
16116
|
+
running: "running",
|
|
16117
|
+
complete: "completed",
|
|
16118
|
+
failed: "failed",
|
|
16119
|
+
partial: "failed",
|
|
16120
|
+
paused: "interrupted",
|
|
16121
|
+
stopped: "interrupted",
|
|
16122
|
+
rejected: "failed"
|
|
16123
|
+
};
|
|
16124
|
+
function node(value, depth, budget) {
|
|
16125
|
+
if (!record3(value) || depth > 8 || ++budget.count > 256 || !token(value.id) || !["subagent", "workflow", "step", "host-step"].includes(String(value.kind)) || typeof value.label !== "string" || value.label.length > 2048 || typeof value.state !== "string" || !Object.hasOwn(statuses, value.state))
|
|
16126
|
+
return null;
|
|
16127
|
+
const children = [];
|
|
16128
|
+
if (value.children !== void 0) {
|
|
16129
|
+
if (!Array.isArray(value.children))
|
|
16130
|
+
return null;
|
|
16131
|
+
for (const child of value.children) {
|
|
16132
|
+
const parsed = node(child, depth + 1, budget);
|
|
16133
|
+
if (!parsed)
|
|
16134
|
+
return null;
|
|
16135
|
+
children.push(parsed);
|
|
16136
|
+
}
|
|
16137
|
+
}
|
|
16138
|
+
return {
|
|
16139
|
+
id: value.id,
|
|
16140
|
+
kind: value.kind,
|
|
16141
|
+
label: value.label,
|
|
16142
|
+
state: value.state,
|
|
16143
|
+
...children.length ? { children } : {}
|
|
16144
|
+
};
|
|
16145
|
+
}
|
|
16146
|
+
function widget(value, key, prefix) {
|
|
16147
|
+
if (!record3(value) || value.type !== "extension_ui_request" || value.method !== "setWidget" || value.widgetKey !== key || !Array.isArray(value.widgetLines))
|
|
16148
|
+
return null;
|
|
16149
|
+
const line = value.widgetLines.find((part) => typeof part === "string" && part.startsWith(prefix));
|
|
16150
|
+
if (!line || Buffer.byteLength(line) > MAX_BYTES + prefix.length)
|
|
16151
|
+
return null;
|
|
16152
|
+
try {
|
|
16153
|
+
const parsed = JSON.parse(line.slice(prefix.length));
|
|
16154
|
+
return record3(parsed) && parsed.version === 1 ? parsed : null;
|
|
16155
|
+
} catch {
|
|
16156
|
+
return null;
|
|
16157
|
+
}
|
|
16158
|
+
}
|
|
16159
|
+
function parsePiSubagentStatus(value) {
|
|
16160
|
+
const parsed = widget(value, "subagent-async", STATUS_PREFIX);
|
|
16161
|
+
if (!parsed || parsed.kind !== "pi-subagents.async-status-snapshot" || !Array.isArray(parsed.runs))
|
|
16162
|
+
return null;
|
|
16163
|
+
const runs = [];
|
|
16164
|
+
const budget = { count: 0 };
|
|
16165
|
+
for (const run of parsed.runs) {
|
|
16166
|
+
const parsedNode = node(run, 0, budget);
|
|
16167
|
+
if (!parsedNode)
|
|
16168
|
+
return null;
|
|
16169
|
+
runs.push(parsedNode);
|
|
16170
|
+
}
|
|
16171
|
+
return runs;
|
|
16172
|
+
}
|
|
16173
|
+
function piSubagentId(address) {
|
|
16174
|
+
return ID_PREFIX + Buffer.from(JSON.stringify([address.runId, address.childId ?? null])).toString("base64url");
|
|
16175
|
+
}
|
|
16176
|
+
function parsePiSubagentId(id) {
|
|
16177
|
+
if (!id.startsWith(ID_PREFIX) || id.length > 1500)
|
|
16178
|
+
throw new Error("Invalid Pi Subagent identity");
|
|
16179
|
+
const value = JSON.parse(Buffer.from(id.slice(ID_PREFIX.length), "base64url").toString("utf8"));
|
|
16180
|
+
if (!Array.isArray(value) || value.length !== 2 || !token(value[0]) || value[1] !== null && !token(value[1]))
|
|
16181
|
+
throw new Error("Invalid Pi Subagent identity");
|
|
16182
|
+
const address = { runId: value[0], ...value[1] === null ? {} : { childId: value[1] } };
|
|
16183
|
+
if (piSubagentId(address) !== id)
|
|
16184
|
+
throw new Error("Non-canonical Pi Subagent identity");
|
|
16185
|
+
return address;
|
|
16186
|
+
}
|
|
16187
|
+
function states(run) {
|
|
16188
|
+
const result = [];
|
|
16189
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16190
|
+
const visit = (entry, root) => {
|
|
16191
|
+
if (entry.kind === "host-step" || !root && entry.kind === "workflow")
|
|
16192
|
+
return;
|
|
16193
|
+
if (entry.kind !== "workflow") {
|
|
16194
|
+
const id = piSubagentId({ runId: run.id, ...!root ? { childId: entry.id } : {} });
|
|
16195
|
+
if (!seen.has(id)) {
|
|
16196
|
+
seen.add(id);
|
|
16197
|
+
result.push({
|
|
16198
|
+
subagentId: id,
|
|
16199
|
+
nativeSubagentId: id,
|
|
16200
|
+
description: entry.label,
|
|
16201
|
+
background: true,
|
|
16202
|
+
status: statuses[entry.state] ?? "running"
|
|
16203
|
+
});
|
|
16204
|
+
}
|
|
16205
|
+
}
|
|
16206
|
+
for (const child of entry.children ?? []) {
|
|
16207
|
+
if (entry.kind === "subagent" && child.kind === "step") {
|
|
16208
|
+
for (const nested of child.children ?? [])
|
|
16209
|
+
visit(nested, false);
|
|
16210
|
+
} else
|
|
16211
|
+
visit(child, false);
|
|
16212
|
+
}
|
|
16213
|
+
};
|
|
16214
|
+
visit(run, true);
|
|
16215
|
+
return result;
|
|
16216
|
+
}
|
|
16217
|
+
function asyncRunId(toolName, result) {
|
|
16218
|
+
if (toolName !== "subagent" || !record3(result) || !record3(result.details))
|
|
16219
|
+
return null;
|
|
16220
|
+
const details = result.details;
|
|
16221
|
+
return ["single", "parallel", "chain", "workflow"].includes(String(details.mode)) && token(details.asyncId) && typeof details.asyncDir === "string" ? details.asyncId : null;
|
|
16222
|
+
}
|
|
16223
|
+
var PiSubagents = class {
|
|
16224
|
+
emit;
|
|
16225
|
+
#children = /* @__PURE__ */ new Map();
|
|
16226
|
+
#active = /* @__PURE__ */ new Map();
|
|
16227
|
+
#waiting = /* @__PURE__ */ new Map();
|
|
16228
|
+
constructor(emit) {
|
|
16229
|
+
this.emit = emit;
|
|
16230
|
+
}
|
|
16231
|
+
observe(runs) {
|
|
16232
|
+
this.#apply(runs, true);
|
|
16233
|
+
}
|
|
16234
|
+
restore(runs) {
|
|
16235
|
+
this.#apply(runs, false);
|
|
16236
|
+
}
|
|
16237
|
+
#apply(runs, publish) {
|
|
16238
|
+
for (const run of runs) {
|
|
16239
|
+
const observed = states(run);
|
|
16240
|
+
const retained = this.#children.get(run.id) ?? /* @__PURE__ */ new Map();
|
|
16241
|
+
for (const child of observed)
|
|
16242
|
+
retained.set(child.subagentId, child);
|
|
16243
|
+
this.#children.set(run.id, retained);
|
|
16244
|
+
const children = [...retained.values()];
|
|
16245
|
+
if (!publish)
|
|
16246
|
+
continue;
|
|
16247
|
+
const waiting = this.#waiting.get(run.id);
|
|
16248
|
+
if (waiting && children.length) {
|
|
16249
|
+
const item = {
|
|
16250
|
+
type: "subagentDelegation",
|
|
16251
|
+
itemId: waiting.itemId,
|
|
16252
|
+
operation: "spawn",
|
|
16253
|
+
subagents: children
|
|
16254
|
+
};
|
|
16255
|
+
this.#waiting.delete(run.id);
|
|
16256
|
+
this.#active.set(run.id, { turnId: waiting.turnId, item });
|
|
16257
|
+
this.emit({ type: "item.started", turnId: waiting.turnId, item });
|
|
16258
|
+
}
|
|
16259
|
+
const active = this.#active.get(run.id);
|
|
16260
|
+
if (active && children.length) {
|
|
16261
|
+
const merged = new Map(active.item.subagents.map((child) => [child.nativeSubagentId, child]));
|
|
16262
|
+
for (const child of children)
|
|
16263
|
+
merged.set(child.nativeSubagentId, child);
|
|
16264
|
+
active.item = { ...active.item, subagents: [...merged.values()] };
|
|
16265
|
+
this.emit({
|
|
16266
|
+
type: "item.updated",
|
|
16267
|
+
turnId: active.turnId,
|
|
16268
|
+
itemId: active.item.itemId,
|
|
16269
|
+
update: { type: "subagents.replace", subagents: active.item.subagents }
|
|
16270
|
+
});
|
|
16271
|
+
}
|
|
16272
|
+
for (const child of observed) {
|
|
16273
|
+
this.emit({
|
|
16274
|
+
type: "subagent.state.changed",
|
|
16275
|
+
nativeSubagentId: child.subagentId,
|
|
16276
|
+
status: child.status
|
|
16277
|
+
});
|
|
16278
|
+
this.emit({ type: "subagent.transcript.changed", nativeSubagentId: child.subagentId });
|
|
16279
|
+
}
|
|
16280
|
+
}
|
|
16281
|
+
}
|
|
16282
|
+
project(toolName, result, itemId2, callId) {
|
|
16283
|
+
const workflow = toolName === "subagent" ? piWorkflowSummary(result) : null;
|
|
16284
|
+
if (workflow && (!callId || workflow.parentToolCallId === callId))
|
|
16285
|
+
return projectPiWorkflow(workflow, itemId2);
|
|
16286
|
+
const runId = asyncRunId(toolName, result);
|
|
16287
|
+
if (!runId || !this.#children.has(runId))
|
|
16288
|
+
return null;
|
|
16289
|
+
const children = [...this.#children.get(runId)?.values() ?? []];
|
|
16290
|
+
return children.length ? { type: "subagentDelegation", itemId: itemId2, operation: "spawn", subagents: children } : null;
|
|
16291
|
+
}
|
|
16292
|
+
start(turnId, toolName, result, itemId2, callId) {
|
|
16293
|
+
const workflow = toolName === "subagent" ? piWorkflowSummary(result) : null;
|
|
16294
|
+
if (workflow && (!callId || workflow.parentToolCallId === callId)) {
|
|
16295
|
+
const key = `workflow:${workflow.workflowRunId}`;
|
|
16296
|
+
const previous = this.#active.get(key);
|
|
16297
|
+
const item2 = projectPiWorkflow(workflow, previous?.item.itemId ?? itemId2);
|
|
16298
|
+
if (!item2)
|
|
16299
|
+
return;
|
|
16300
|
+
if (previous) {
|
|
16301
|
+
const children = new Map(previous.item.subagents.map((child) => [child.nativeSubagentId, child]));
|
|
16302
|
+
for (const child of item2.subagents)
|
|
16303
|
+
children.set(child.nativeSubagentId, child);
|
|
16304
|
+
item2.subagents = [...children.values()];
|
|
16305
|
+
previous.item = item2;
|
|
16306
|
+
this.emit({
|
|
16307
|
+
type: "item.updated",
|
|
16308
|
+
turnId: previous.turnId,
|
|
16309
|
+
itemId: item2.itemId,
|
|
16310
|
+
update: { type: "subagents.replace", subagents: item2.subagents }
|
|
16311
|
+
});
|
|
16312
|
+
} else {
|
|
16313
|
+
this.#active.set(key, { turnId, item: item2 });
|
|
16314
|
+
this.emit({ type: "item.started", turnId, item: item2 });
|
|
16315
|
+
}
|
|
16316
|
+
for (const child of item2.subagents) {
|
|
16317
|
+
this.emit({
|
|
16318
|
+
type: "subagent.state.changed",
|
|
16319
|
+
nativeSubagentId: child.subagentId,
|
|
16320
|
+
status: child.status
|
|
16321
|
+
});
|
|
16322
|
+
this.emit({ type: "subagent.transcript.changed", nativeSubagentId: child.subagentId });
|
|
16323
|
+
}
|
|
16324
|
+
return;
|
|
16325
|
+
}
|
|
16326
|
+
const runId = asyncRunId(toolName, result);
|
|
16327
|
+
const item = this.project(toolName, result, itemId2);
|
|
16328
|
+
if (!runId || this.#active.has(runId))
|
|
16329
|
+
return;
|
|
16330
|
+
if (!item) {
|
|
16331
|
+
this.#waiting.set(runId, { turnId, itemId: itemId2 });
|
|
16332
|
+
return;
|
|
16333
|
+
}
|
|
16334
|
+
this.#active.set(runId, { turnId, item });
|
|
16335
|
+
this.emit({ type: "item.started", turnId, item });
|
|
16336
|
+
}
|
|
16337
|
+
finish(turnId) {
|
|
16338
|
+
for (const [runId, waiting] of this.#waiting) {
|
|
16339
|
+
if (waiting.turnId === turnId)
|
|
16340
|
+
this.#waiting.delete(runId);
|
|
16341
|
+
}
|
|
16342
|
+
for (const [runId, active] of this.#active) {
|
|
16343
|
+
if (active.turnId !== turnId)
|
|
16344
|
+
continue;
|
|
16345
|
+
this.#active.delete(runId);
|
|
16346
|
+
this.emit({
|
|
16347
|
+
type: "item.completed",
|
|
16348
|
+
turnId,
|
|
16349
|
+
snapshot: { item: active.item, outcome: { status: "succeeded" } }
|
|
16350
|
+
});
|
|
16351
|
+
}
|
|
16352
|
+
}
|
|
16353
|
+
};
|
|
16354
|
+
function parsePiSubagentInspection(value) {
|
|
16355
|
+
const parsed = widget(value, "subagent-inspect", INSPECT_PREFIX);
|
|
16356
|
+
if (!parsed || parsed.kind !== "pi-subagents.inspect-reply" || !token(parsed.requestId))
|
|
16357
|
+
return null;
|
|
16358
|
+
if (parsed.error !== void 0 && (!record3(parsed.error) || typeof parsed.error.code !== "string" || typeof parsed.error.message !== "string"))
|
|
16359
|
+
return null;
|
|
16360
|
+
for (const field of ["asyncId", "childId", "status", "task", "finalOutput"]) {
|
|
16361
|
+
if (parsed[field] !== void 0 && typeof parsed[field] !== "string")
|
|
16362
|
+
return null;
|
|
16363
|
+
}
|
|
16364
|
+
if (parsed.messages !== void 0 && (!Array.isArray(parsed.messages) || parsed.messages.length > 200 || parsed.messages.some((entry) => !record3(entry) || typeof entry.role !== "string" || typeof entry.text !== "string" || !["text", "toolCall", "toolResult"].includes(String(entry.kind)) || entry.name !== void 0 && typeof entry.name !== "string")))
|
|
16365
|
+
return null;
|
|
16366
|
+
if (parsed.truncated !== void 0 && (!record3(parsed.truncated) || typeof parsed.truncated.task !== "boolean" || typeof parsed.truncated.finalOutput !== "boolean" || !Number.isSafeInteger(parsed.truncated.messages) || Number(parsed.truncated.messages) < 0))
|
|
16367
|
+
return null;
|
|
16368
|
+
return parsed;
|
|
16369
|
+
}
|
|
16370
|
+
function piSubagentSnapshot(parentSessionId, id, reply) {
|
|
16371
|
+
const messages = reply.messages ?? [];
|
|
16372
|
+
const texts = messages.map((entry) => entry.kind === "text" && entry.role === "assistant" ? entry.text : `[${entry.role}${entry.name ? `: ${entry.name}` : ""} / ${entry.kind}]
|
|
16373
|
+
${entry.text}`);
|
|
16374
|
+
if (!texts.length && reply.finalOutput)
|
|
16375
|
+
texts.push(reply.finalOutput);
|
|
16376
|
+
if (reply.truncated && (reply.truncated.task || reply.truncated.messages || reply.truncated.finalOutput)) {
|
|
16377
|
+
texts.push("[Pi subagent: native inspection returned a truncated transcript window.]");
|
|
16378
|
+
}
|
|
16379
|
+
return {
|
|
16380
|
+
turns: [
|
|
16381
|
+
{
|
|
16382
|
+
nativeTurnRef: nativeTurnRefSchema.parse({
|
|
16383
|
+
harnessId: "pi",
|
|
16384
|
+
nativeSessionId: parentSessionId,
|
|
16385
|
+
nativeTurnKey: `pi-subagent-${createHash("sha256").update(id).digest("hex")}`,
|
|
16386
|
+
formatVersion: 1
|
|
16387
|
+
}),
|
|
16388
|
+
input: reply.task ? [{ type: "text", text: reply.task }] : [],
|
|
16389
|
+
items: texts.map((text2, index) => ({
|
|
16390
|
+
item: {
|
|
16391
|
+
type: "agentMessage",
|
|
16392
|
+
text: text2,
|
|
16393
|
+
itemId: hostItemIdSchema.parse(`pi-subagent-${createHash("sha256").update(`${id}:${index}:${text2}`).digest("hex")}`)
|
|
16394
|
+
},
|
|
16395
|
+
outcome: { status: "succeeded" }
|
|
16396
|
+
})),
|
|
16397
|
+
outcome: reply.status === "complete" ? { status: "succeeded" } : reply.status === "stopped" ? { status: "cancelled", reason: "Pi subagent stopped" } : ["failed", "partial", "rejected"].includes(reply.status ?? "") ? {
|
|
16398
|
+
status: "failed",
|
|
16399
|
+
error: {
|
|
16400
|
+
code: "nativeFailure",
|
|
16401
|
+
message: `Pi subagent ${reply.status}`,
|
|
16402
|
+
retryable: false
|
|
16403
|
+
}
|
|
16404
|
+
} : {
|
|
16405
|
+
status: "unknown",
|
|
16406
|
+
reason: `Pi subagent ${reply.status ?? "status unavailable"}`
|
|
16407
|
+
}
|
|
16408
|
+
}
|
|
16409
|
+
]
|
|
16410
|
+
};
|
|
16411
|
+
}
|
|
16412
|
+
|
|
16413
|
+
// dist/pi-model-catalog.js
|
|
16414
|
+
var PI_MODEL_REF_PREFIX = "pi-model-v1.";
|
|
16415
|
+
var PI_DRAFT_THINKING_OPTION_IDS = [
|
|
16416
|
+
"off",
|
|
16417
|
+
"minimal",
|
|
16418
|
+
"low",
|
|
16419
|
+
"medium",
|
|
16420
|
+
"high",
|
|
16421
|
+
"xhigh",
|
|
16422
|
+
"max"
|
|
16423
|
+
].map((id) => harnessThinkingOptionIdSchema.parse(id));
|
|
16424
|
+
var PI_THINKING_LABELS = {
|
|
16425
|
+
off: "Off",
|
|
16426
|
+
minimal: "Minimal",
|
|
16427
|
+
low: "Low",
|
|
16428
|
+
medium: "Medium",
|
|
16429
|
+
high: "High",
|
|
16430
|
+
xhigh: "Extra High",
|
|
16431
|
+
max: "Max"
|
|
16432
|
+
};
|
|
16433
|
+
function compareText(left, right) {
|
|
16434
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
16435
|
+
}
|
|
16436
|
+
function assertNativePart(value, name) {
|
|
16437
|
+
if (value.trim().length === 0)
|
|
16438
|
+
throw new Error(`Pi ${name} must not be empty`);
|
|
16439
|
+
}
|
|
16440
|
+
function encodePiModelRef(model) {
|
|
16441
|
+
assertNativePart(model.provider, "Model provider");
|
|
16442
|
+
assertNativePart(model.id, "Model id");
|
|
16443
|
+
const encoded = Buffer.from(JSON.stringify([model.provider, model.id]), "utf8").toString("base64url");
|
|
16444
|
+
return harnessModelRefSchema.parse({ id: `${PI_MODEL_REF_PREFIX}${encoded}` });
|
|
16445
|
+
}
|
|
16446
|
+
function decodePiModelRef(ref) {
|
|
16447
|
+
const parsedRef = harnessModelRefSchema.parse(ref);
|
|
16448
|
+
if (!parsedRef.id.startsWith(PI_MODEL_REF_PREFIX)) {
|
|
16449
|
+
throw new Error("Model Ref does not belong to PiAdapter");
|
|
16450
|
+
}
|
|
16451
|
+
const encoded = parsedRef.id.slice(PI_MODEL_REF_PREFIX.length);
|
|
16452
|
+
let decoded;
|
|
16453
|
+
try {
|
|
16454
|
+
decoded = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
|
|
16455
|
+
} catch {
|
|
16456
|
+
throw new Error("Pi Model Ref is malformed");
|
|
16457
|
+
}
|
|
16458
|
+
if (!Array.isArray(decoded) || decoded.length !== 2 || typeof decoded[0] !== "string" || typeof decoded[1] !== "string") {
|
|
16459
|
+
throw new Error("Pi Model Ref has an invalid native identity");
|
|
16460
|
+
}
|
|
16461
|
+
const native = { provider: decoded[0], id: decoded[1] };
|
|
16462
|
+
assertNativePart(native.provider, "Model provider");
|
|
16463
|
+
assertNativePart(native.id, "Model id");
|
|
16464
|
+
if (encodePiModelRef(native).id !== parsedRef.id) {
|
|
16465
|
+
throw new Error("Pi Model Ref is not canonical");
|
|
16466
|
+
}
|
|
16467
|
+
return native;
|
|
16468
|
+
}
|
|
16469
|
+
function samePiModel(left, right) {
|
|
16470
|
+
return left === null ? right === null : right !== null && left.provider === right.provider && left.id === right.id;
|
|
16471
|
+
}
|
|
16472
|
+
function fallbackThinkingLabel(id) {
|
|
16473
|
+
const label = id.split(/[._~-]+/u).filter((part) => part.length > 0).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
16474
|
+
return label || id;
|
|
16475
|
+
}
|
|
16476
|
+
function normalizePiThinkingOptions(levels) {
|
|
16477
|
+
return levels.map((id) => harnessThinkingOptionSchema.parse({
|
|
16478
|
+
id,
|
|
16479
|
+
label: PI_THINKING_LABELS[id] ?? fallbackThinkingLabel(id)
|
|
16480
|
+
}));
|
|
16481
|
+
}
|
|
16482
|
+
function normalizePiModelCatalog(nativeModels, effectiveModel, thinkingLevels, effectiveThinkingOptionId) {
|
|
16483
|
+
const byRef = /* @__PURE__ */ new Map();
|
|
16484
|
+
for (const native of nativeModels) {
|
|
16485
|
+
const ref = encodePiModelRef(native);
|
|
16486
|
+
const existing = byRef.get(ref.id);
|
|
16487
|
+
if (existing) {
|
|
16488
|
+
if (existing.reasoning !== native.reasoning) {
|
|
16489
|
+
throw new Error("Pi duplicate Model entries disagree on reasoning capability");
|
|
16490
|
+
}
|
|
16491
|
+
continue;
|
|
16492
|
+
}
|
|
16493
|
+
byRef.set(ref.id, {
|
|
16494
|
+
model: {
|
|
16495
|
+
ref,
|
|
16496
|
+
label: `${native.provider} / ${native.id}`
|
|
16497
|
+
},
|
|
16498
|
+
reasoning: native.reasoning
|
|
16499
|
+
});
|
|
16500
|
+
}
|
|
16501
|
+
const defaultModel = effectiveModel ? encodePiModelRef(effectiveModel) : void 0;
|
|
16502
|
+
if (defaultModel && !byRef.has(defaultModel.id)) {
|
|
16503
|
+
throw new Error("Pi effective Model is absent from the available Model catalog");
|
|
16504
|
+
}
|
|
16505
|
+
if (thinkingLevels && effectiveThinkingOptionId && !thinkingLevels.includes(effectiveThinkingOptionId)) {
|
|
16506
|
+
throw new Error("Pi effective Thinking option is absent from the available option catalog");
|
|
16507
|
+
}
|
|
16508
|
+
if (thinkingLevels && !effectiveThinkingOptionId) {
|
|
16509
|
+
throw new Error("Pi did not report an effective Thinking option");
|
|
16510
|
+
}
|
|
16511
|
+
const thinkingOptions = thinkingLevels ? normalizePiThinkingOptions(PI_DRAFT_THINKING_OPTION_IDS) : [];
|
|
16512
|
+
const allThinkingOptionIds = thinkingOptions.map(({ id }) => id);
|
|
16513
|
+
const offThinkingOptionId = thinkingOptions.find(({ id }) => id === "off")?.id;
|
|
16514
|
+
const models = [...byRef.values()].map(({ model, reasoning }) => ({
|
|
16515
|
+
...model,
|
|
16516
|
+
supportedThinkingOptionIds: reasoning ? allThinkingOptionIds : offThinkingOptionId ? [offThinkingOptionId] : []
|
|
16517
|
+
})).sort((left, right) => compareText(left.label, right.label) || compareText(left.ref.id, right.ref.id));
|
|
16518
|
+
const defaultThinkingOptionId = thinkingOptions.find(({ id }) => id === effectiveThinkingOptionId)?.id;
|
|
16519
|
+
return harnessModelCatalogSchema.parse({
|
|
16520
|
+
models,
|
|
16521
|
+
...defaultModel ? { defaultModel } : {},
|
|
16522
|
+
thinkingOptions,
|
|
16523
|
+
...defaultThinkingOptionId ? { defaultThinkingOptionId } : {}
|
|
16524
|
+
});
|
|
16525
|
+
}
|
|
16526
|
+
|
|
16527
|
+
// dist/pi-history.js
|
|
16528
|
+
var piHarnessId = harnessIdSchema.parse("pi");
|
|
16529
|
+
function isRecord(value) {
|
|
16530
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16531
|
+
}
|
|
16532
|
+
function textContent(value) {
|
|
16533
|
+
if (typeof value === "string")
|
|
16534
|
+
return value;
|
|
16535
|
+
if (!Array.isArray(value))
|
|
16536
|
+
return "";
|
|
16537
|
+
return value.filter((part) => isRecord(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
|
|
16538
|
+
}
|
|
16539
|
+
function thinkingContent(value) {
|
|
16540
|
+
if (!Array.isArray(value))
|
|
16541
|
+
return "";
|
|
16542
|
+
return value.filter((part) => isRecord(part) && part.type === "thinking" && typeof part.thinking === "string").map((part) => part.thinking).join("");
|
|
16543
|
+
}
|
|
16544
|
+
function validatedEntry(value) {
|
|
16545
|
+
if (typeof value.id !== "string" || value.id.length === 0 || value.parentId !== null && typeof value.parentId !== "string" || typeof value.type !== "string") {
|
|
16546
|
+
throw new Error("Pi history contains an invalid Entry identity");
|
|
16547
|
+
}
|
|
16548
|
+
return value;
|
|
16549
|
+
}
|
|
16550
|
+
function activePiEntries(history) {
|
|
16551
|
+
if (history.leafId === null)
|
|
16552
|
+
return [];
|
|
16553
|
+
const byId = new Map(history.entries.map((value) => {
|
|
15539
16554
|
const entry = validatedEntry(value);
|
|
15540
16555
|
return [entry.id, entry];
|
|
15541
16556
|
}));
|
|
@@ -15600,10 +16615,10 @@ function itemOutcome(outcome) {
|
|
|
15600
16615
|
return { status: "succeeded" };
|
|
15601
16616
|
}
|
|
15602
16617
|
function toolOutput(value) {
|
|
15603
|
-
const
|
|
15604
|
-
return
|
|
16618
|
+
const text2 = textContent(value);
|
|
16619
|
+
return text2.length > 0 ? { content: [{ type: "text", text: text2 }] } : void 0;
|
|
15605
16620
|
}
|
|
15606
|
-
function snapshotItems(entries, outcome) {
|
|
16621
|
+
function snapshotItems(entries, outcome, subagents) {
|
|
15607
16622
|
const snapshots = [];
|
|
15608
16623
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
15609
16624
|
for (const entry of entries) {
|
|
@@ -15612,7 +16627,7 @@ function snapshotItems(entries, outcome) {
|
|
|
15612
16627
|
continue;
|
|
15613
16628
|
const content = Array.isArray(nativeMessage.content) ? nativeMessage.content : [];
|
|
15614
16629
|
if (nativeMessage.role === "assistant") {
|
|
15615
|
-
const
|
|
16630
|
+
const text2 = textContent(content);
|
|
15616
16631
|
const reasoning = thinkingContent(content);
|
|
15617
16632
|
let projectedText = false;
|
|
15618
16633
|
let projectedReasoning = false;
|
|
@@ -15629,11 +16644,11 @@ function snapshotItems(entries, outcome) {
|
|
|
15629
16644
|
projectedReasoning = true;
|
|
15630
16645
|
continue;
|
|
15631
16646
|
}
|
|
15632
|
-
if (part.type === "text" && !projectedText &&
|
|
16647
|
+
if (part.type === "text" && !projectedText && text2.length > 0) {
|
|
15633
16648
|
const item2 = {
|
|
15634
16649
|
type: "agentMessage",
|
|
15635
16650
|
itemId: itemId(entry.id, "assistant", 0),
|
|
15636
|
-
text
|
|
16651
|
+
text: text2
|
|
15637
16652
|
};
|
|
15638
16653
|
snapshots.push({ item: item2, outcome: itemOutcome(outcome) });
|
|
15639
16654
|
projectedText = true;
|
|
@@ -15669,6 +16684,7 @@ function snapshotItems(entries, outcome) {
|
|
|
15669
16684
|
...output ? { output } : {}
|
|
15670
16685
|
};
|
|
15671
16686
|
const toolSucceeded = nativeMessage.isError === false;
|
|
16687
|
+
const delegation = subagents?.project(call.name, nativeMessage, itemId(call.entryId, "subagent", call.ordinal), nativeMessage.toolCallId);
|
|
15672
16688
|
snapshots.push({
|
|
15673
16689
|
item,
|
|
15674
16690
|
outcome: toolSucceeded ? { status: "succeeded" } : {
|
|
@@ -15680,16 +16696,18 @@ function snapshotItems(entries, outcome) {
|
|
|
15680
16696
|
}
|
|
15681
16697
|
}
|
|
15682
16698
|
});
|
|
16699
|
+
if (delegation)
|
|
16700
|
+
snapshots.push({ item: delegation, outcome: { status: "succeeded" } });
|
|
15683
16701
|
}
|
|
15684
16702
|
return snapshots;
|
|
15685
16703
|
}
|
|
15686
16704
|
function modelChange(entry) {
|
|
15687
16705
|
return entry.type === "model_change" && typeof entry.provider === "string" && typeof entry.modelId === "string" ? { provider: entry.provider, id: entry.modelId } : null;
|
|
15688
16706
|
}
|
|
15689
|
-
function mapPiSnapshot(history,
|
|
16707
|
+
function mapPiSnapshot(history, state2, subagents = new PiSubagents(() => void 0)) {
|
|
15690
16708
|
const active = activePiEntries(history);
|
|
15691
16709
|
const turns = [];
|
|
15692
|
-
let effectiveModel =
|
|
16710
|
+
let effectiveModel = state2.model;
|
|
15693
16711
|
for (let index = 0; index < active.length; ) {
|
|
15694
16712
|
const model = modelChange(active[index]);
|
|
15695
16713
|
if (model) {
|
|
@@ -15710,13 +16728,13 @@ function mapPiSnapshot(history, state) {
|
|
|
15710
16728
|
const userText = textContent(message(user)?.content);
|
|
15711
16729
|
const nativeTurnRef = nativeTurnRefSchema.parse({
|
|
15712
16730
|
harnessId: piHarnessId,
|
|
15713
|
-
nativeSessionId:
|
|
16731
|
+
nativeSessionId: state2.sessionId,
|
|
15714
16732
|
nativeTurnKey: user.id,
|
|
15715
16733
|
formatVersion: 1
|
|
15716
16734
|
});
|
|
15717
16735
|
const checkpoint = nativeCheckpointRefSchema.parse({
|
|
15718
16736
|
harnessId: piHarnessId,
|
|
15719
|
-
nativeSessionId:
|
|
16737
|
+
nativeSessionId: state2.sessionId,
|
|
15720
16738
|
checkpointId: user.id,
|
|
15721
16739
|
formatVersion: 1
|
|
15722
16740
|
});
|
|
@@ -15724,7 +16742,7 @@ function mapPiSnapshot(history, state) {
|
|
|
15724
16742
|
nativeTurnRef,
|
|
15725
16743
|
checkpoint,
|
|
15726
16744
|
input: [{ type: "text", text: userText }],
|
|
15727
|
-
items: snapshotItems(entries, outcome),
|
|
16745
|
+
items: snapshotItems(entries, outcome, subagents),
|
|
15728
16746
|
outcome,
|
|
15729
16747
|
...effectiveModel ? { model: encodePiModelRef(effectiveModel) } : {}
|
|
15730
16748
|
});
|
|
@@ -15755,7 +16773,7 @@ function resolvePiForkBoundary(history, checkpointId) {
|
|
|
15755
16773
|
}
|
|
15756
16774
|
|
|
15757
16775
|
// dist/pi-session-file.js
|
|
15758
|
-
import { open, realpath } from "node:fs/promises";
|
|
16776
|
+
import { open, realpath as realpath2 } from "node:fs/promises";
|
|
15759
16777
|
var MAX_SESSION_HEADER_BYTES = 64 * 1024;
|
|
15760
16778
|
var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
15761
16779
|
function isRecord2(value) {
|
|
@@ -15799,8 +16817,8 @@ async function verifyPiSessionCwd(input) {
|
|
|
15799
16817
|
throw new Error("Pi Fork Session header identity does not match RPC state");
|
|
15800
16818
|
}
|
|
15801
16819
|
const [actualCwd, expectedCwd] = await Promise.all([
|
|
15802
|
-
|
|
15803
|
-
|
|
16820
|
+
realpath2(header.cwd),
|
|
16821
|
+
realpath2(input.expectedCwd)
|
|
15804
16822
|
]);
|
|
15805
16823
|
if (actualCwd !== expectedCwd) {
|
|
15806
16824
|
throw new Error("Pi Fork Session did not bind the requested cwd");
|
|
@@ -15809,9 +16827,9 @@ async function verifyPiSessionCwd(input) {
|
|
|
15809
16827
|
|
|
15810
16828
|
// dist/pi-empty-session.js
|
|
15811
16829
|
async function persistEmptyPiSession(input) {
|
|
15812
|
-
const { state, history, sourceSessionFile, sourceSessionId, cwd } = input;
|
|
15813
|
-
const destination =
|
|
15814
|
-
if (!destination || !
|
|
16830
|
+
const { state: state2, history, sourceSessionFile, sourceSessionId, cwd } = input;
|
|
16831
|
+
const destination = state2.sessionFile;
|
|
16832
|
+
if (!destination || !path4.isAbsolute(destination) || path4.resolve(destination) === path4.resolve(sourceSessionFile) || state2.sessionId === sourceSessionId || mapPiSnapshot(history, { sessionId: state2.sessionId, model: null }).turns.length !== 0)
|
|
15815
16833
|
throw new Error("Pi empty Session is not an independent empty native fork");
|
|
15816
16834
|
await verifyPiSessionCwd({
|
|
15817
16835
|
sessionFile: sourceSessionFile,
|
|
@@ -15830,12 +16848,12 @@ async function persistEmptyPiSession(input) {
|
|
|
15830
16848
|
const header = {
|
|
15831
16849
|
type: "session",
|
|
15832
16850
|
version: 3,
|
|
15833
|
-
id:
|
|
16851
|
+
id: state2.sessionId,
|
|
15834
16852
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15835
16853
|
cwd,
|
|
15836
16854
|
parentSession: sourceSessionFile
|
|
15837
16855
|
};
|
|
15838
|
-
const temporary =
|
|
16856
|
+
const temporary = path4.join(path4.dirname(destination), `.codexhost-${randomUUID2()}.tmp`);
|
|
15839
16857
|
try {
|
|
15840
16858
|
const file2 = await open2(temporary, "wx", 384);
|
|
15841
16859
|
try {
|
|
@@ -15846,7 +16864,7 @@ async function persistEmptyPiSession(input) {
|
|
|
15846
16864
|
}
|
|
15847
16865
|
await link(temporary, destination);
|
|
15848
16866
|
if (process.platform !== "win32") {
|
|
15849
|
-
const directory = await open2(
|
|
16867
|
+
const directory = await open2(path4.dirname(destination), "r");
|
|
15850
16868
|
try {
|
|
15851
16869
|
await directory.sync();
|
|
15852
16870
|
} finally {
|
|
@@ -16009,16 +17027,16 @@ var Diff = class {
|
|
|
16009
17027
|
}
|
|
16010
17028
|
}
|
|
16011
17029
|
}
|
|
16012
|
-
addToPath(
|
|
16013
|
-
const last =
|
|
17030
|
+
addToPath(path10, added, removed, oldPosInc, options) {
|
|
17031
|
+
const last = path10.lastComponent;
|
|
16014
17032
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
16015
17033
|
return {
|
|
16016
|
-
oldPos:
|
|
17034
|
+
oldPos: path10.oldPos + oldPosInc,
|
|
16017
17035
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
16018
17036
|
};
|
|
16019
17037
|
} else {
|
|
16020
17038
|
return {
|
|
16021
|
-
oldPos:
|
|
17039
|
+
oldPos: path10.oldPos + oldPosInc,
|
|
16022
17040
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
16023
17041
|
};
|
|
16024
17042
|
}
|
|
@@ -16418,9 +17436,9 @@ function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader
|
|
|
16418
17436
|
} }));
|
|
16419
17437
|
}
|
|
16420
17438
|
}
|
|
16421
|
-
function splitLines(
|
|
16422
|
-
const hasTrailingNl =
|
|
16423
|
-
const result =
|
|
17439
|
+
function splitLines(text2) {
|
|
17440
|
+
const hasTrailingNl = text2.endsWith("\n");
|
|
17441
|
+
const result = text2.split("\n").map((line) => line + "\n");
|
|
16424
17442
|
if (hasTrailingNl) {
|
|
16425
17443
|
result.pop();
|
|
16426
17444
|
} else {
|
|
@@ -16430,8 +17448,8 @@ function splitLines(text) {
|
|
|
16430
17448
|
}
|
|
16431
17449
|
|
|
16432
17450
|
// dist/pi-adapter.js
|
|
16433
|
-
import { randomUUID as
|
|
16434
|
-
import
|
|
17451
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
17452
|
+
import path9 from "node:path";
|
|
16435
17453
|
|
|
16436
17454
|
// ../../harness-adapter/dist/question.js
|
|
16437
17455
|
function invalidRequest(message3) {
|
|
@@ -16608,558 +17626,499 @@ function parseHostUsage(value) {
|
|
|
16608
17626
|
if (hasContextWindow && value.contextWindowTokens === 0) {
|
|
16609
17627
|
throw new Error("Harness Usage 'contextWindowTokens' must be greater than zero");
|
|
16610
17628
|
}
|
|
16611
|
-
if (value.planFiveHourResetsAtUnix !== void 0 && value.planFiveHourUsedPercent === void 0) {
|
|
16612
|
-
throw new Error("Harness Usage 'planFiveHourResetsAtUnix' must be provided with 'planFiveHourUsedPercent'");
|
|
16613
|
-
}
|
|
16614
|
-
if (value.planSevenDayResetsAtUnix !== void 0 && value.planSevenDayUsedPercent === void 0) {
|
|
16615
|
-
throw new Error("Harness Usage 'planSevenDayResetsAtUnix' must be provided with 'planSevenDayUsedPercent'");
|
|
16616
|
-
}
|
|
16617
|
-
return { ...value };
|
|
16618
|
-
}
|
|
16619
|
-
|
|
16620
|
-
// dist/pi-last-turn-rollback.js
|
|
16621
|
-
function modelFromState(state) {
|
|
16622
|
-
if (state.provider === null && state.modelId === null)
|
|
16623
|
-
return null;
|
|
16624
|
-
if (state.provider === null || state.modelId === null) {
|
|
16625
|
-
throw new Error("Pi state contains a partial Model identity");
|
|
16626
|
-
}
|
|
16627
|
-
return { provider: state.provider, id: state.modelId };
|
|
16628
|
-
}
|
|
16629
|
-
async function rollbackPiLastTurn(transport, sourceSessionId, cwd) {
|
|
16630
|
-
const startupState = transport.state;
|
|
16631
|
-
const startupSessionId = startupState.sessionId;
|
|
16632
|
-
const currentModel = modelFromState(startupState);
|
|
16633
|
-
const currentThinking = startupState.thinkingLevel;
|
|
16634
|
-
const copiedHistory = await transport.getEntries();
|
|
16635
|
-
const boundary = resolvePiLastTurnBoundary(copiedHistory);
|
|
16636
|
-
if (!boundary)
|
|
16637
|
-
return { ok: false, reason: "empty" };
|
|
16638
|
-
const sourceSnapshot = mapPiSnapshot(copiedHistory, {
|
|
16639
|
-
sessionId: startupSessionId,
|
|
16640
|
-
model: currentModel
|
|
16641
|
-
});
|
|
16642
|
-
let state = await transport.fork(boundary.lastUserEntryId);
|
|
16643
|
-
if (state.sessionId === sourceSessionId || state.sessionId === startupSessionId) {
|
|
16644
|
-
throw new Error("Pi last-Turn rollback did not create a distinct Native Session");
|
|
16645
|
-
}
|
|
16646
|
-
if (!samePiModel(modelFromState(state), currentModel)) {
|
|
16647
|
-
if (!currentModel)
|
|
16648
|
-
throw new Error("Pi last-Turn rollback changed the current Model");
|
|
16649
|
-
state = await transport.selectModel(currentModel);
|
|
16650
|
-
}
|
|
16651
|
-
if (state.thinkingLevel !== currentThinking) {
|
|
16652
|
-
if (!currentThinking)
|
|
16653
|
-
throw new Error("Pi last-Turn rollback changed current Thinking");
|
|
16654
|
-
state = await transport.selectThinkingOption(currentThinking);
|
|
16655
|
-
}
|
|
16656
|
-
if (!samePiModel(modelFromState(state), currentModel) || state.thinkingLevel !== currentThinking) {
|
|
16657
|
-
throw new Error("Pi last-Turn rollback could not restore current Model and Thinking");
|
|
16658
|
-
}
|
|
16659
|
-
const snapshot = mapPiSnapshot(await transport.getEntries(), {
|
|
16660
|
-
sessionId: state.sessionId,
|
|
16661
|
-
model: modelFromState(state)
|
|
16662
|
-
});
|
|
16663
|
-
const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
|
|
16664
|
-
const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
|
|
16665
|
-
if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
|
|
16666
|
-
throw new Error("Pi last-Turn rollback did not produce the exact retained history prefix");
|
|
16667
|
-
}
|
|
16668
|
-
try {
|
|
16669
|
-
await transport.verifySessionCwd(cwd);
|
|
16670
|
-
return { ok: true, unpersisted: false };
|
|
16671
|
-
} catch (error51) {
|
|
16672
|
-
if (snapshot.turns.length === 0 && error51?.code === "ENOENT") {
|
|
16673
|
-
return { ok: true, unpersisted: true };
|
|
16674
|
-
}
|
|
16675
|
-
throw error51;
|
|
17629
|
+
if (value.planFiveHourResetsAtUnix !== void 0 && value.planFiveHourUsedPercent === void 0) {
|
|
17630
|
+
throw new Error("Harness Usage 'planFiveHourResetsAtUnix' must be provided with 'planFiveHourUsedPercent'");
|
|
16676
17631
|
}
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
// dist/pi-session-import.js
|
|
16680
|
-
import { createReadStream as createReadStream2 } from "node:fs";
|
|
16681
|
-
import { opendir, realpath as realpath2, stat } from "node:fs/promises";
|
|
16682
|
-
import os from "node:os";
|
|
16683
|
-
import path2 from "node:path";
|
|
16684
|
-
import { createInterface as createInterface2 } from "node:readline";
|
|
16685
|
-
var PiSessionChangedError = class extends Error {
|
|
16686
|
-
constructor() {
|
|
16687
|
-
super("Pi Session changed during discovery; refresh and retry");
|
|
17632
|
+
if (value.planSevenDayResetsAtUnix !== void 0 && value.planSevenDayUsedPercent === void 0) {
|
|
17633
|
+
throw new Error("Harness Usage 'planSevenDayResetsAtUnix' must be provided with 'planSevenDayUsedPercent'");
|
|
16688
17634
|
}
|
|
16689
|
-
};
|
|
16690
|
-
function sameFile(left, right) {
|
|
16691
|
-
return left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs && left.ino === right.ino && left.dev === right.dev;
|
|
17635
|
+
return { ...value };
|
|
16692
17636
|
}
|
|
16693
|
-
|
|
17637
|
+
|
|
17638
|
+
// dist/pi-workflow-child-history.js
|
|
17639
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
17640
|
+
import { constants } from "node:fs";
|
|
17641
|
+
import { open as open3 } from "node:fs/promises";
|
|
17642
|
+
import path5 from "node:path";
|
|
17643
|
+
function record4(value) {
|
|
16694
17644
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16695
17645
|
}
|
|
16696
|
-
|
|
16697
|
-
|
|
16698
|
-
|
|
16699
|
-
|
|
16700
|
-
|
|
16701
|
-
}
|
|
16702
|
-
function piSessionImportDirectory(environment) {
|
|
16703
|
-
const home = (process.platform === "win32" ? environment.USERPROFILE : environment.HOME) || os.homedir();
|
|
16704
|
-
const custom2 = environment.PI_CODING_AGENT_SESSION_DIR;
|
|
16705
|
-
if (custom2)
|
|
16706
|
-
return { directory: expandDirectory(custom2, home), flat: true };
|
|
16707
|
-
const agent = environment.PI_CODING_AGENT_DIR;
|
|
16708
|
-
return {
|
|
16709
|
-
directory: path2.join(agent ? expandDirectory(agent, home) : path2.join(home, ".pi", "agent"), "sessions"),
|
|
16710
|
-
flat: false
|
|
16711
|
-
};
|
|
16712
|
-
}
|
|
16713
|
-
async function sessionFiles(directory, flat, signal) {
|
|
16714
|
-
const files = [];
|
|
16715
|
-
const visit = async (dir, projectLevel) => {
|
|
16716
|
-
signal.throwIfAborted();
|
|
16717
|
-
const entries = await opendir(dir).catch((error51) => {
|
|
16718
|
-
if (missing(error51))
|
|
16719
|
-
return null;
|
|
16720
|
-
throw error51;
|
|
16721
|
-
});
|
|
16722
|
-
if (!entries)
|
|
16723
|
-
return;
|
|
16724
|
-
for await (const entry of entries) {
|
|
16725
|
-
signal.throwIfAborted();
|
|
16726
|
-
if (projectLevel && entry.isDirectory())
|
|
16727
|
-
await visit(path2.join(dir, entry.name), false);
|
|
16728
|
-
else if (!projectLevel && entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
16729
|
-
files.push(path2.join(dir, entry.name));
|
|
16730
|
-
}
|
|
16731
|
-
}
|
|
16732
|
-
};
|
|
16733
|
-
await visit(directory, !flat);
|
|
16734
|
-
return files;
|
|
16735
|
-
}
|
|
16736
|
-
async function readCandidate(file2, signal) {
|
|
16737
|
-
const before = await stat(file2);
|
|
16738
|
-
if (!before.isFile() || before.size === 0)
|
|
16739
|
-
return null;
|
|
16740
|
-
const stream = createReadStream2(file2, { encoding: "utf8", signal, end: before.size - 1 });
|
|
16741
|
-
const lines = createInterface2({ input: stream, crlfDelay: Infinity });
|
|
16742
|
-
let header;
|
|
16743
|
-
let name = null;
|
|
16744
|
-
let firstMessage = null;
|
|
16745
|
-
let hasUser = false;
|
|
16746
|
-
let updatedAt = before.mtimeMs;
|
|
16747
|
-
const entries = /* @__PURE__ */ new Map();
|
|
17646
|
+
var MAX_SESSION_BYTES = 8 * 1024 * 1024;
|
|
17647
|
+
async function childHistory(file2, parentSessionId, identity) {
|
|
17648
|
+
if (!path5.isAbsolute(file2))
|
|
17649
|
+
throw new Error("Pi child Session path is not absolute");
|
|
17650
|
+
const handle = await open3(file2, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
|
|
16748
17651
|
try {
|
|
16749
|
-
|
|
16750
|
-
|
|
16751
|
-
|
|
16752
|
-
|
|
16753
|
-
|
|
16754
|
-
|
|
16755
|
-
|
|
16756
|
-
|
|
16757
|
-
|
|
16758
|
-
|
|
16759
|
-
|
|
16760
|
-
|
|
16761
|
-
|
|
16762
|
-
|
|
16763
|
-
|
|
16764
|
-
|
|
16765
|
-
|
|
16766
|
-
|
|
16767
|
-
|
|
16768
|
-
|
|
16769
|
-
|
|
16770
|
-
|
|
16771
|
-
|
|
16772
|
-
const
|
|
16773
|
-
|
|
16774
|
-
|
|
16775
|
-
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
16779
|
-
|
|
16780
|
-
|
|
16781
|
-
|
|
16782
|
-
|
|
16783
|
-
}
|
|
16784
|
-
}
|
|
17652
|
+
const stat2 = await handle.stat();
|
|
17653
|
+
if (!stat2.isFile() || stat2.size > MAX_SESSION_BYTES)
|
|
17654
|
+
throw new Error("Pi child Session exceeds read bounds");
|
|
17655
|
+
const buffer = Buffer.alloc(MAX_SESSION_BYTES + 1);
|
|
17656
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
|
|
17657
|
+
if (bytesRead > MAX_SESSION_BYTES)
|
|
17658
|
+
throw new Error("Pi child Session exceeds read bounds");
|
|
17659
|
+
const values = buffer.subarray(0, bytesRead).toString("utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
17660
|
+
const header = values[0];
|
|
17661
|
+
if (!record4(header) || header.type !== "session" || typeof header.id !== "string" || header.version !== 3)
|
|
17662
|
+
throw new Error("Unsupported Pi child Session header");
|
|
17663
|
+
const entries = [];
|
|
17664
|
+
for (const entry of values.slice(1)) {
|
|
17665
|
+
const parsed = jsonValueSchema.safeParse(entry);
|
|
17666
|
+
if (!parsed.success || !record4(parsed.data) || typeof parsed.data.id !== "string")
|
|
17667
|
+
throw new Error("Malformed Pi child Session entry");
|
|
17668
|
+
entries.push(parsed.data);
|
|
17669
|
+
}
|
|
17670
|
+
const history = { entries, leafId: String(entries.at(-1)?.id ?? "") || null };
|
|
17671
|
+
const snapshot = mapPiSnapshot(history, { sessionId: parentSessionId, model: null });
|
|
17672
|
+
const prefix = createHash2("sha256").update(identity).digest("hex");
|
|
17673
|
+
return {
|
|
17674
|
+
turns: snapshot.turns.map((turn) => {
|
|
17675
|
+
const readonlyTurn = {
|
|
17676
|
+
...turn,
|
|
17677
|
+
nativeTurnRef: {
|
|
17678
|
+
...turn.nativeTurnRef,
|
|
17679
|
+
nativeTurnKey: `${prefix}:${turn.nativeTurnRef.nativeTurnKey}`
|
|
17680
|
+
}
|
|
17681
|
+
};
|
|
17682
|
+
delete readonlyTurn.checkpoint;
|
|
17683
|
+
return readonlyTurn;
|
|
17684
|
+
})
|
|
17685
|
+
};
|
|
16785
17686
|
} finally {
|
|
16786
|
-
|
|
16787
|
-
stream.destroy();
|
|
17687
|
+
await handle.close();
|
|
16788
17688
|
}
|
|
16789
|
-
if (!header)
|
|
16790
|
-
return null;
|
|
16791
|
-
if (!hasUser)
|
|
16792
|
-
return null;
|
|
16793
|
-
const after = await stat(file2);
|
|
16794
|
-
if (!sameFile(before, after))
|
|
16795
|
-
throw new PiSessionChangedError();
|
|
16796
|
-
const cwd = await realpath2(String(header.cwd));
|
|
16797
|
-
if (!(await stat(cwd)).isDirectory())
|
|
16798
|
-
return null;
|
|
16799
|
-
const nativeRef = nativeSessionRefSchema.safeParse({
|
|
16800
|
-
harnessId: "pi",
|
|
16801
|
-
nativeSessionId: header.id,
|
|
16802
|
-
locator: { sessionFile: await realpath2(file2) },
|
|
16803
|
-
formatVersion: 1
|
|
16804
|
-
});
|
|
16805
|
-
const candidate = harnessSessionImportCandidateSchema.safeParse({
|
|
16806
|
-
nativeSessionId: header.id,
|
|
16807
|
-
cwd,
|
|
16808
|
-
title: name ?? firstMessage,
|
|
16809
|
-
updatedAt: Math.floor(updatedAt),
|
|
16810
|
-
running: null
|
|
16811
|
-
});
|
|
16812
|
-
return candidate.success && nativeRef.success ? { candidate: candidate.data, nativeRef: nativeRef.data } : null;
|
|
16813
17689
|
}
|
|
16814
|
-
async function
|
|
16815
|
-
const
|
|
16816
|
-
|
|
16817
|
-
|
|
16818
|
-
|
|
16819
|
-
|
|
16820
|
-
|
|
16821
|
-
|
|
16822
|
-
|
|
17690
|
+
async function readPiWorkflowChild(history, parentSessionId, address) {
|
|
17691
|
+
for (const entry of activePiEntries(history).reverse()) {
|
|
17692
|
+
const message3 = entry.message;
|
|
17693
|
+
if (!record4(message3) || message3.role !== "toolResult" || message3.toolName !== "subagent")
|
|
17694
|
+
continue;
|
|
17695
|
+
const summary = piWorkflowSummary(message3);
|
|
17696
|
+
if (!summary || summary.workflowRunId !== address.workflowRunId || summary.parentToolCallId !== message3.toolCallId)
|
|
17697
|
+
continue;
|
|
17698
|
+
const child = summary.children.find((candidate) => candidate.childId === address.childId);
|
|
17699
|
+
if (!child)
|
|
17700
|
+
break;
|
|
17701
|
+
const details = message3.details;
|
|
17702
|
+
if (!record4(details) || !Array.isArray(details.results))
|
|
17703
|
+
break;
|
|
17704
|
+
const result = details.results.findLast((candidate) => record4(candidate) && candidate.workflowKey === address.childId);
|
|
17705
|
+
if (!record4(result))
|
|
17706
|
+
break;
|
|
17707
|
+
const id = piWorkflowSubagentId(address);
|
|
17708
|
+
if (typeof result.sessionFile === "string") {
|
|
16823
17709
|
try {
|
|
16824
|
-
|
|
17710
|
+
const snapshot = await childHistory(result.sessionFile, parentSessionId, id);
|
|
17711
|
+
if (snapshot.turns.length)
|
|
17712
|
+
return { ok: true, value: snapshot };
|
|
16825
17713
|
} catch {
|
|
16826
|
-
return null;
|
|
16827
17714
|
}
|
|
16828
|
-
return isRecord4(header) && header.type === "session" && header.version === 3 && typeof header.id === "string" ? header.id : null;
|
|
16829
17715
|
}
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
|
|
16834
|
-
|
|
16835
|
-
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
16839
|
-
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
-
|
|
16843
|
-
|
|
16844
|
-
|
|
16845
|
-
|
|
16846
|
-
|
|
16847
|
-
|
|
16848
|
-
|
|
16849
|
-
async #scan(signal) {
|
|
16850
|
-
const { directory, flat } = this.#location;
|
|
16851
|
-
const files = await sessionFiles(directory, flat, signal);
|
|
16852
|
-
const next = /* @__PURE__ */ new Map();
|
|
16853
|
-
const identities = /* @__PURE__ */ new Set();
|
|
16854
|
-
const sources = [];
|
|
16855
|
-
for (const file2 of files) {
|
|
16856
|
-
signal.throwIfAborted();
|
|
16857
|
-
try {
|
|
16858
|
-
const fingerprint = await stat(file2);
|
|
16859
|
-
const cached2 = this.#cache.get(file2);
|
|
16860
|
-
const source = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source : await readCandidate(file2, signal);
|
|
16861
|
-
if (!source)
|
|
16862
|
-
continue;
|
|
16863
|
-
if (!(await stat(source.candidate.cwd)).isDirectory())
|
|
16864
|
-
continue;
|
|
16865
|
-
if (identities.has(source.nativeRef.nativeSessionId))
|
|
16866
|
-
throw new Error("Pi Session identity is ambiguous across files");
|
|
16867
|
-
identities.add(source.nativeRef.nativeSessionId);
|
|
16868
|
-
next.set(file2, { fingerprint, source });
|
|
16869
|
-
sources.push(source);
|
|
16870
|
-
} catch (error51) {
|
|
16871
|
-
if (!missing(error51) && !(error51 instanceof PiSessionChangedError))
|
|
16872
|
-
throw error51;
|
|
16873
|
-
}
|
|
17716
|
+
if (typeof result.finalOutput === "string" && result.finalOutput.length > 0) {
|
|
17717
|
+
const output = result.finalOutput.slice(0, 64 * 1024);
|
|
17718
|
+
return {
|
|
17719
|
+
ok: true,
|
|
17720
|
+
value: piSubagentSnapshot(parentSessionId, id, {
|
|
17721
|
+
kind: "pi-subagents.inspect-reply",
|
|
17722
|
+
version: 1,
|
|
17723
|
+
requestId: "native-workflow-result",
|
|
17724
|
+
status: child.state === "completed" ? "complete" : child.state === "failed" ? "failed" : child.state === "interrupted" ? "paused" : "running",
|
|
17725
|
+
...typeof result.task === "string" ? { task: result.task.slice(0, 4096) } : {},
|
|
17726
|
+
finalOutput: `[Pi subagent: saved native result; Session transcript unavailable.]
|
|
17727
|
+
${output}`,
|
|
17728
|
+
truncated: {
|
|
17729
|
+
task: typeof result.task === "string" && result.task.length > 4096,
|
|
17730
|
+
messages: 0,
|
|
17731
|
+
finalOutput: output.length < result.finalOutput.length
|
|
17732
|
+
}
|
|
17733
|
+
})
|
|
17734
|
+
};
|
|
16874
17735
|
}
|
|
16875
|
-
|
|
16876
|
-
return structuredClone(sources.sort((left, right) => right.candidate.updatedAt - left.candidate.updatedAt));
|
|
17736
|
+
break;
|
|
16877
17737
|
}
|
|
16878
|
-
|
|
16879
|
-
|
|
16880
|
-
|
|
16881
|
-
|
|
16882
|
-
|
|
16883
|
-
|
|
16884
|
-
const fingerprint = await stat(file2);
|
|
16885
|
-
const cached2 = this.#cache.get(file2);
|
|
16886
|
-
const id = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source.nativeRef.nativeSessionId : await readIdentity(file2, signal);
|
|
16887
|
-
if (id !== nativeSessionId)
|
|
16888
|
-
continue;
|
|
16889
|
-
if (selected)
|
|
16890
|
-
throw new Error("Pi Session identity is ambiguous across files");
|
|
16891
|
-
selected = file2;
|
|
16892
|
-
} catch (error51) {
|
|
16893
|
-
if (!missing(error51))
|
|
16894
|
-
throw error51;
|
|
16895
|
-
}
|
|
16896
|
-
}
|
|
16897
|
-
if (!selected)
|
|
16898
|
-
return null;
|
|
16899
|
-
try {
|
|
16900
|
-
const source = await readCandidate(selected, signal);
|
|
16901
|
-
return source?.nativeRef.nativeSessionId === nativeSessionId ? source : null;
|
|
16902
|
-
} catch (error51) {
|
|
16903
|
-
if (missing(error51))
|
|
16904
|
-
return null;
|
|
16905
|
-
throw error51;
|
|
17738
|
+
return {
|
|
17739
|
+
ok: false,
|
|
17740
|
+
error: {
|
|
17741
|
+
code: "sessionNotFound",
|
|
17742
|
+
message: "Pi workflow child has no published transcript/result in this parent's active history",
|
|
17743
|
+
retryable: true
|
|
16906
17744
|
}
|
|
16907
|
-
}
|
|
16908
|
-
};
|
|
16909
|
-
|
|
16910
|
-
// dist/pi-rpc-session.js
|
|
16911
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
16912
|
-
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
16913
|
-
import path5 from "node:path";
|
|
16914
|
-
|
|
16915
|
-
// ../../harness-discovery/dist/environment.js
|
|
16916
|
-
import fs from "node:fs";
|
|
16917
|
-
import path3 from "node:path";
|
|
16918
|
-
function targetPath(platform) {
|
|
16919
|
-
return platform === "win32" ? path3.win32 : path3.posix;
|
|
16920
|
-
}
|
|
16921
|
-
function environmentValue(environment, name) {
|
|
16922
|
-
const lowered = name.toLowerCase();
|
|
16923
|
-
for (const [key, value] of Object.entries(environment)) {
|
|
16924
|
-
if (key.toLowerCase() === lowered)
|
|
16925
|
-
return value;
|
|
16926
|
-
}
|
|
16927
|
-
return void 0;
|
|
16928
|
-
}
|
|
16929
|
-
function pathDelimiter(platform) {
|
|
16930
|
-
return platform === "win32" ? ";" : ":";
|
|
17745
|
+
};
|
|
16931
17746
|
}
|
|
16932
|
-
|
|
16933
|
-
|
|
17747
|
+
|
|
17748
|
+
// dist/pi-subagent-history.js
|
|
17749
|
+
import { constants as constants2 } from "node:fs";
|
|
17750
|
+
import { open as open4 } from "node:fs/promises";
|
|
17751
|
+
import path6 from "node:path";
|
|
17752
|
+
function record5(value) {
|
|
17753
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16934
17754
|
}
|
|
16935
|
-
function
|
|
16936
|
-
|
|
16937
|
-
return [""];
|
|
16938
|
-
if (targetPath(platform).extname(command) !== "")
|
|
16939
|
-
return [""];
|
|
16940
|
-
return (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean);
|
|
17755
|
+
function state(value) {
|
|
17756
|
+
return value === "pending" ? "queued" : value === "completed" ? "complete" : value;
|
|
16941
17757
|
}
|
|
16942
|
-
function
|
|
16943
|
-
|
|
16944
|
-
|
|
16945
|
-
|
|
16946
|
-
|
|
16947
|
-
|
|
17758
|
+
function piSubagentArtifact(value, runId, parentSessionId) {
|
|
17759
|
+
if (!record5(value) || value.lifecycleArtifactVersion !== 3 || value.runId !== runId || value.sessionId !== parentSessionId || !["single", "parallel", "chain", "workflow"].includes(String(value.mode)))
|
|
17760
|
+
return null;
|
|
17761
|
+
if (value.steps !== void 0 && (!Array.isArray(value.steps) || value.steps.length > 128))
|
|
17762
|
+
return null;
|
|
17763
|
+
const steps = Array.isArray(value.steps) ? value.steps : [];
|
|
17764
|
+
const children = [];
|
|
17765
|
+
for (const [index, step] of steps.entries()) {
|
|
17766
|
+
if (!record5(step) || typeof step.agent !== "string")
|
|
17767
|
+
return null;
|
|
17768
|
+
children.push({
|
|
17769
|
+
id: step.workflowKey ?? step.runId ?? `step:${index}`,
|
|
17770
|
+
kind: "step",
|
|
17771
|
+
label: step.label ?? step.agent,
|
|
17772
|
+
state: state(step.status)
|
|
17773
|
+
});
|
|
16948
17774
|
}
|
|
17775
|
+
return parsePiSubagentStatus({
|
|
17776
|
+
type: "extension_ui_request",
|
|
17777
|
+
method: "setWidget",
|
|
17778
|
+
widgetKey: "subagent-async",
|
|
17779
|
+
widgetLines: [
|
|
17780
|
+
"PI_SUBAGENT_ASYNC_JSON:" + JSON.stringify({
|
|
17781
|
+
kind: "pi-subagents.async-status-snapshot",
|
|
17782
|
+
version: 1,
|
|
17783
|
+
runs: [
|
|
17784
|
+
{
|
|
17785
|
+
id: runId,
|
|
17786
|
+
kind: value.mode === "single" ? "subagent" : "workflow",
|
|
17787
|
+
label: "Pi subagent",
|
|
17788
|
+
state: value.state,
|
|
17789
|
+
children
|
|
17790
|
+
}
|
|
17791
|
+
]
|
|
17792
|
+
})
|
|
17793
|
+
]
|
|
17794
|
+
});
|
|
16949
17795
|
}
|
|
16950
|
-
function
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
17796
|
+
async function restorePiSubagents(history, parentSessionId, observer) {
|
|
17797
|
+
const receipts = /* @__PURE__ */ new Map();
|
|
17798
|
+
for (const entry of activePiEntries(history)) {
|
|
17799
|
+
if (!record5(entry.message) || entry.message.role !== "toolResult" || entry.message.toolName !== "subagent" || entry.message.isError !== false || !record5(entry.message.details))
|
|
17800
|
+
continue;
|
|
17801
|
+
const details = entry.message.details;
|
|
17802
|
+
if (!["single", "parallel", "chain", "workflow"].includes(String(details.mode)) || typeof details.asyncId !== "string" || typeof details.asyncDir !== "string" || !path6.isAbsolute(details.asyncDir) || path6.basename(details.asyncDir) !== details.asyncId)
|
|
17803
|
+
continue;
|
|
17804
|
+
receipts.set(details.asyncId, details.asyncDir);
|
|
17805
|
+
}
|
|
17806
|
+
for (const [id, directory] of [...receipts].slice(-128)) {
|
|
17807
|
+
let file2;
|
|
17808
|
+
try {
|
|
17809
|
+
file2 = await open4(path6.join(directory, "status.json"), constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
|
|
17810
|
+
const stat2 = await file2.stat();
|
|
17811
|
+
if (!stat2.isFile() || stat2.size > 1024 * 1024)
|
|
17812
|
+
continue;
|
|
17813
|
+
const buffer = Buffer.alloc(1024 * 1024 + 1);
|
|
17814
|
+
const { bytesRead } = await file2.read(buffer, 0, buffer.length, 0);
|
|
17815
|
+
if (bytesRead > 1024 * 1024)
|
|
17816
|
+
continue;
|
|
17817
|
+
const value = JSON.parse(buffer.subarray(0, bytesRead).toString("utf8"));
|
|
17818
|
+
const runs = piSubagentArtifact(value, id, parentSessionId);
|
|
17819
|
+
if (runs)
|
|
17820
|
+
observer.restore(runs);
|
|
17821
|
+
} catch {
|
|
17822
|
+
} finally {
|
|
17823
|
+
await file2?.close();
|
|
17824
|
+
}
|
|
16955
17825
|
}
|
|
16956
|
-
}
|
|
16957
|
-
function newestFirst(names) {
|
|
16958
|
-
return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
|
|
16959
17826
|
}
|
|
16960
17827
|
|
|
16961
|
-
//
|
|
16962
|
-
|
|
16963
|
-
|
|
16964
|
-
|
|
16965
|
-
|
|
16966
|
-
|
|
16967
|
-
const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
|
|
16968
|
-
const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
|
|
16969
|
-
if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
|
|
16970
|
-
directories.push(runtimeDirectory);
|
|
17828
|
+
// dist/pi-last-turn-rollback.js
|
|
17829
|
+
function modelFromState(state2) {
|
|
17830
|
+
if (state2.provider === null && state2.modelId === null)
|
|
17831
|
+
return null;
|
|
17832
|
+
if (state2.provider === null || state2.modelId === null) {
|
|
17833
|
+
throw new Error("Pi state contains a partial Model identity");
|
|
16971
17834
|
}
|
|
16972
|
-
return {
|
|
17835
|
+
return { provider: state2.provider, id: state2.modelId };
|
|
16973
17836
|
}
|
|
16974
|
-
|
|
16975
|
-
|
|
16976
|
-
|
|
16977
|
-
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
const
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
const
|
|
16984
|
-
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
if (platform === "win32") {
|
|
16991
|
-
const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
|
|
16992
|
-
const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
|
|
16993
|
-
versioned(pathFlavor.join(appData, "nvm"));
|
|
16994
|
-
versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
|
|
16995
|
-
directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
|
|
16996
|
-
directories.push(pathFlavor.join(home, ".bun", "bin"));
|
|
16997
|
-
const pnpmHome2 = value("PNPM_HOME");
|
|
16998
|
-
if (pnpmHome2)
|
|
16999
|
-
directories.push(pnpmHome2);
|
|
17000
|
-
directories.push(pathFlavor.join(localAppData, "pnpm"));
|
|
17001
|
-
return directories;
|
|
17837
|
+
async function rollbackPiLastTurn(transport, sourceSessionId, cwd) {
|
|
17838
|
+
const startupState = transport.state;
|
|
17839
|
+
const startupSessionId = startupState.sessionId;
|
|
17840
|
+
const currentModel = modelFromState(startupState);
|
|
17841
|
+
const currentThinking = startupState.thinkingLevel;
|
|
17842
|
+
const copiedHistory = await transport.getEntries();
|
|
17843
|
+
const boundary = resolvePiLastTurnBoundary(copiedHistory);
|
|
17844
|
+
if (!boundary)
|
|
17845
|
+
return { ok: false, reason: "empty" };
|
|
17846
|
+
const sourceSnapshot = mapPiSnapshot(copiedHistory, {
|
|
17847
|
+
sessionId: startupSessionId,
|
|
17848
|
+
model: currentModel
|
|
17849
|
+
});
|
|
17850
|
+
let state2 = await transport.fork(boundary.lastUserEntryId);
|
|
17851
|
+
if (state2.sessionId === sourceSessionId || state2.sessionId === startupSessionId) {
|
|
17852
|
+
throw new Error("Pi last-Turn rollback did not create a distinct Native Session");
|
|
17002
17853
|
}
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
pathFlavor.join(home, "Library", "Application Support", "fnm")
|
|
17008
|
-
].filter((root) => root !== void 0);
|
|
17009
|
-
for (const root of fnmRoots) {
|
|
17010
|
-
versioned(pathFlavor.join(root, "node-versions"), "installation", "bin");
|
|
17854
|
+
if (!samePiModel(modelFromState(state2), currentModel)) {
|
|
17855
|
+
if (!currentModel)
|
|
17856
|
+
throw new Error("Pi last-Turn rollback changed the current Model");
|
|
17857
|
+
state2 = await transport.selectModel(currentModel);
|
|
17011
17858
|
}
|
|
17012
|
-
|
|
17013
|
-
|
|
17014
|
-
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
17025
|
-
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17859
|
+
if (state2.thinkingLevel !== currentThinking) {
|
|
17860
|
+
if (!currentThinking)
|
|
17861
|
+
throw new Error("Pi last-Turn rollback changed current Thinking");
|
|
17862
|
+
state2 = await transport.selectThinkingOption(currentThinking);
|
|
17863
|
+
}
|
|
17864
|
+
if (!samePiModel(modelFromState(state2), currentModel) || state2.thinkingLevel !== currentThinking) {
|
|
17865
|
+
throw new Error("Pi last-Turn rollback could not restore current Model and Thinking");
|
|
17866
|
+
}
|
|
17867
|
+
const snapshot = mapPiSnapshot(await transport.getEntries(), {
|
|
17868
|
+
sessionId: state2.sessionId,
|
|
17869
|
+
model: modelFromState(state2)
|
|
17870
|
+
});
|
|
17871
|
+
const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
|
|
17872
|
+
const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
|
|
17873
|
+
if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
|
|
17874
|
+
throw new Error("Pi last-Turn rollback did not produce the exact retained history prefix");
|
|
17875
|
+
}
|
|
17876
|
+
try {
|
|
17877
|
+
await transport.verifySessionCwd(cwd);
|
|
17878
|
+
return { ok: true, unpersisted: false };
|
|
17879
|
+
} catch (error51) {
|
|
17880
|
+
if (snapshot.turns.length === 0 && error51?.code === "ENOENT") {
|
|
17881
|
+
return { ok: true, unpersisted: true };
|
|
17031
17882
|
}
|
|
17883
|
+
throw error51;
|
|
17032
17884
|
}
|
|
17033
|
-
return directories;
|
|
17034
17885
|
}
|
|
17035
17886
|
|
|
17036
|
-
//
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17887
|
+
// dist/pi-session-import.js
|
|
17888
|
+
import { createReadStream as createReadStream2 } from "node:fs";
|
|
17889
|
+
import { opendir, realpath as realpath3, stat } from "node:fs/promises";
|
|
17890
|
+
import os3 from "node:os";
|
|
17891
|
+
import path7 from "node:path";
|
|
17892
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
17893
|
+
var PiSessionChangedError = class extends Error {
|
|
17894
|
+
constructor() {
|
|
17895
|
+
super("Pi Session changed during discovery; refresh and retry");
|
|
17896
|
+
}
|
|
17897
|
+
};
|
|
17898
|
+
function sameFile(left, right) {
|
|
17899
|
+
return left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs && left.ino === right.ino && left.dev === right.dev;
|
|
17040
17900
|
}
|
|
17041
|
-
function
|
|
17042
|
-
return
|
|
17901
|
+
function isRecord4(value) {
|
|
17902
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17043
17903
|
}
|
|
17044
|
-
function
|
|
17045
|
-
|
|
17904
|
+
function missing(error51) {
|
|
17905
|
+
return isRecord4(error51) && error51.code === "ENOENT";
|
|
17906
|
+
}
|
|
17907
|
+
function expandDirectory(value, home) {
|
|
17908
|
+
return path7.resolve(value === "~" ? home : value.startsWith(`~${path7.sep}`) || value.startsWith("~/") ? path7.join(home, value.slice(2)) : value);
|
|
17909
|
+
}
|
|
17910
|
+
function piSessionImportDirectory(environment) {
|
|
17911
|
+
const home = (process.platform === "win32" ? environment.USERPROFILE : environment.HOME) || os3.homedir();
|
|
17912
|
+
const custom2 = environment.PI_CODING_AGENT_SESSION_DIR;
|
|
17913
|
+
if (custom2)
|
|
17914
|
+
return { directory: expandDirectory(custom2, home), flat: true };
|
|
17915
|
+
const agent = environment.PI_CODING_AGENT_DIR;
|
|
17046
17916
|
return {
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
|
|
17050
|
-
LOCALAPPDATA: environmentValue(environment, "LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local")
|
|
17917
|
+
directory: path7.join(agent ? expandDirectory(agent, home) : path7.join(home, ".pi", "agent"), "sessions"),
|
|
17918
|
+
flat: false
|
|
17051
17919
|
};
|
|
17052
17920
|
}
|
|
17053
|
-
function
|
|
17054
|
-
const
|
|
17055
|
-
const
|
|
17056
|
-
|
|
17057
|
-
|
|
17058
|
-
|
|
17059
|
-
|
|
17060
|
-
|
|
17921
|
+
async function sessionFiles(directory, flat, signal) {
|
|
17922
|
+
const files = [];
|
|
17923
|
+
const visit = async (dir, projectLevel) => {
|
|
17924
|
+
signal.throwIfAborted();
|
|
17925
|
+
const entries = await opendir(dir).catch((error51) => {
|
|
17926
|
+
if (missing(error51))
|
|
17927
|
+
return null;
|
|
17928
|
+
throw error51;
|
|
17929
|
+
});
|
|
17930
|
+
if (!entries)
|
|
17931
|
+
return;
|
|
17932
|
+
for await (const entry of entries) {
|
|
17933
|
+
signal.throwIfAborted();
|
|
17934
|
+
if (projectLevel && entry.isDirectory())
|
|
17935
|
+
await visit(path7.join(dir, entry.name), false);
|
|
17936
|
+
else if (!projectLevel && entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
17937
|
+
files.push(path7.join(dir, entry.name));
|
|
17938
|
+
}
|
|
17939
|
+
}
|
|
17940
|
+
};
|
|
17941
|
+
await visit(directory, !flat);
|
|
17942
|
+
return files;
|
|
17061
17943
|
}
|
|
17062
|
-
function
|
|
17063
|
-
const
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17068
|
-
|
|
17069
|
-
|
|
17944
|
+
async function readCandidate(file2, signal) {
|
|
17945
|
+
const before = await stat(file2);
|
|
17946
|
+
if (!before.isFile() || before.size === 0)
|
|
17947
|
+
return null;
|
|
17948
|
+
const stream = createReadStream2(file2, { encoding: "utf8", signal, end: before.size - 1 });
|
|
17949
|
+
const lines = createInterface2({ input: stream, crlfDelay: Infinity });
|
|
17950
|
+
let header;
|
|
17951
|
+
let name = null;
|
|
17952
|
+
let firstMessage = null;
|
|
17953
|
+
let hasUser = false;
|
|
17954
|
+
let updatedAt = before.mtimeMs;
|
|
17955
|
+
const entries = /* @__PURE__ */ new Map();
|
|
17956
|
+
try {
|
|
17957
|
+
for await (const line of lines) {
|
|
17958
|
+
signal.throwIfAborted();
|
|
17959
|
+
if (!line.trim())
|
|
17960
|
+
continue;
|
|
17961
|
+
let entry;
|
|
17962
|
+
try {
|
|
17963
|
+
entry = JSON.parse(line);
|
|
17964
|
+
} catch {
|
|
17965
|
+
return null;
|
|
17966
|
+
}
|
|
17967
|
+
if (!isRecord4(entry))
|
|
17968
|
+
return null;
|
|
17969
|
+
if (!header) {
|
|
17970
|
+
if (entry.type !== "session" || entry.version !== 3 || typeof entry.id !== "string" || typeof entry.cwd !== "string" || !path7.isAbsolute(entry.cwd))
|
|
17971
|
+
return null;
|
|
17972
|
+
header = entry;
|
|
17973
|
+
continue;
|
|
17974
|
+
}
|
|
17975
|
+
if (typeof entry.id !== "string" || entry.id.length === 0 || entries.has(entry.id) || entry.parentId !== null && (typeof entry.parentId !== "string" || !entries.has(entry.parentId)))
|
|
17976
|
+
return null;
|
|
17977
|
+
const message3 = isRecord4(entry.message) ? entry.message : null;
|
|
17978
|
+
if (!firstMessage && entry.type === "message" && message3?.role === "user") {
|
|
17979
|
+
const content = message3.content;
|
|
17980
|
+
const text2 = typeof content === "string" ? content : Array.isArray(content) ? content.filter((block) => isRecord4(block) && block.type === "text" && typeof block.text === "string").map((block) => block.text).join(" ") : "";
|
|
17981
|
+
firstMessage = text2.replaceAll("\0", "").trim().slice(0, HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) || null;
|
|
17982
|
+
}
|
|
17983
|
+
hasUser = entry.type === "message" && message3?.role === "user" || typeof entry.parentId === "string" && entries.get(entry.parentId) === true;
|
|
17984
|
+
entries.set(entry.id, hasUser);
|
|
17985
|
+
if (entry.type === "session_info")
|
|
17986
|
+
name = typeof entry.name === "string" ? entry.name.trim() || null : null;
|
|
17987
|
+
if (entry.type === "message" && (message3?.role === "user" || message3?.role === "assistant")) {
|
|
17988
|
+
const time3 = typeof message3.timestamp === "number" ? message3.timestamp : typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : NaN;
|
|
17989
|
+
if (Number.isFinite(time3))
|
|
17990
|
+
updatedAt = time3;
|
|
17991
|
+
}
|
|
17070
17992
|
}
|
|
17071
|
-
|
|
17993
|
+
} finally {
|
|
17994
|
+
lines.close();
|
|
17995
|
+
stream.destroy();
|
|
17996
|
+
}
|
|
17997
|
+
if (!header)
|
|
17998
|
+
return null;
|
|
17999
|
+
if (!hasUser)
|
|
18000
|
+
return null;
|
|
18001
|
+
const after = await stat(file2);
|
|
18002
|
+
if (!sameFile(before, after))
|
|
18003
|
+
throw new PiSessionChangedError();
|
|
18004
|
+
const cwd = await realpath3(String(header.cwd));
|
|
18005
|
+
if (!(await stat(cwd)).isDirectory())
|
|
18006
|
+
return null;
|
|
18007
|
+
const nativeRef = nativeSessionRefSchema.safeParse({
|
|
18008
|
+
harnessId: "pi",
|
|
18009
|
+
nativeSessionId: header.id,
|
|
18010
|
+
locator: { sessionFile: await realpath3(file2) },
|
|
18011
|
+
formatVersion: 1
|
|
17072
18012
|
});
|
|
17073
|
-
|
|
18013
|
+
const candidate = harnessSessionImportCandidateSchema.safeParse({
|
|
18014
|
+
nativeSessionId: header.id,
|
|
18015
|
+
cwd,
|
|
18016
|
+
title: name ?? firstMessage,
|
|
18017
|
+
updatedAt: Math.floor(updatedAt),
|
|
18018
|
+
running: null
|
|
18019
|
+
});
|
|
18020
|
+
return candidate.success && nativeRef.success ? { candidate: candidate.data, nativeRef: nativeRef.data } : null;
|
|
17074
18021
|
}
|
|
17075
|
-
function
|
|
17076
|
-
const
|
|
17077
|
-
const
|
|
17078
|
-
|
|
17079
|
-
|
|
17080
|
-
|
|
17081
|
-
|
|
17082
|
-
|
|
17083
|
-
|
|
17084
|
-
|
|
17085
|
-
|
|
17086
|
-
|
|
18022
|
+
async function readIdentity(file2, signal) {
|
|
18023
|
+
const stream = createReadStream2(file2, { encoding: "utf8", signal });
|
|
18024
|
+
const lines = createInterface2({ input: stream, crlfDelay: Infinity });
|
|
18025
|
+
try {
|
|
18026
|
+
for await (const line of lines) {
|
|
18027
|
+
signal.throwIfAborted();
|
|
18028
|
+
if (!line.trim())
|
|
18029
|
+
continue;
|
|
18030
|
+
let header;
|
|
18031
|
+
try {
|
|
18032
|
+
header = JSON.parse(line);
|
|
18033
|
+
} catch {
|
|
18034
|
+
return null;
|
|
18035
|
+
}
|
|
18036
|
+
return isRecord4(header) && header.type === "session" && header.version === 3 && typeof header.id === "string" ? header.id : null;
|
|
17087
18037
|
}
|
|
17088
|
-
|
|
17089
|
-
|
|
17090
|
-
|
|
18038
|
+
return null;
|
|
18039
|
+
} finally {
|
|
18040
|
+
lines.close();
|
|
18041
|
+
stream.destroy();
|
|
17091
18042
|
}
|
|
17092
|
-
return directories;
|
|
17093
18043
|
}
|
|
17094
|
-
|
|
17095
|
-
|
|
17096
|
-
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
|
|
17100
|
-
return [{ candidate: command, source: "configured" }];
|
|
18044
|
+
var PiSessionImportIndex = class {
|
|
18045
|
+
#location;
|
|
18046
|
+
#cache = /* @__PURE__ */ new Map();
|
|
18047
|
+
#listing;
|
|
18048
|
+
constructor(environment) {
|
|
18049
|
+
this.#location = piSessionImportDirectory(environment);
|
|
17101
18050
|
}
|
|
17102
|
-
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
|
|
17106
|
-
|
|
17107
|
-
candidate: pathFlavor.join(directory, command + extension),
|
|
17108
|
-
source: "path"
|
|
17109
|
-
});
|
|
17110
|
-
}
|
|
18051
|
+
list(signal) {
|
|
18052
|
+
this.#listing ??= this.#scan(signal).finally(() => {
|
|
18053
|
+
this.#listing = void 0;
|
|
18054
|
+
});
|
|
18055
|
+
return this.#listing;
|
|
17111
18056
|
}
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
18057
|
+
async #scan(signal) {
|
|
18058
|
+
const { directory, flat } = this.#location;
|
|
18059
|
+
const files = await sessionFiles(directory, flat, signal);
|
|
18060
|
+
const next = /* @__PURE__ */ new Map();
|
|
18061
|
+
const identities = /* @__PURE__ */ new Set();
|
|
18062
|
+
const sources = [];
|
|
18063
|
+
for (const file2 of files) {
|
|
18064
|
+
signal.throwIfAborted();
|
|
18065
|
+
try {
|
|
18066
|
+
const fingerprint = await stat(file2);
|
|
18067
|
+
const cached2 = this.#cache.get(file2);
|
|
18068
|
+
const source = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source : await readCandidate(file2, signal);
|
|
18069
|
+
if (!source)
|
|
18070
|
+
continue;
|
|
18071
|
+
if (!(await stat(source.candidate.cwd)).isDirectory())
|
|
18072
|
+
continue;
|
|
18073
|
+
if (identities.has(source.nativeRef.nativeSessionId))
|
|
18074
|
+
throw new Error("Pi Session identity is ambiguous across files");
|
|
18075
|
+
identities.add(source.nativeRef.nativeSessionId);
|
|
18076
|
+
next.set(file2, { fingerprint, source });
|
|
18077
|
+
sources.push(source);
|
|
18078
|
+
} catch (error51) {
|
|
18079
|
+
if (!missing(error51) && !(error51 instanceof PiSessionChangedError))
|
|
18080
|
+
throw error51;
|
|
18081
|
+
}
|
|
17121
18082
|
}
|
|
18083
|
+
this.#cache = next;
|
|
18084
|
+
return structuredClone(sources.sort((left, right) => right.candidate.updatedAt - left.candidate.updatedAt));
|
|
17122
18085
|
}
|
|
17123
|
-
|
|
17124
|
-
}
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
|
|
17133
|
-
|
|
17134
|
-
|
|
17135
|
-
|
|
17136
|
-
|
|
17137
|
-
|
|
17138
|
-
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
|
|
17146
|
-
|
|
17147
|
-
|
|
17148
|
-
|
|
17149
|
-
|
|
17150
|
-
|
|
17151
|
-
|
|
18086
|
+
async resolve(nativeSessionId, signal) {
|
|
18087
|
+
const { directory, flat } = this.#location;
|
|
18088
|
+
let selected;
|
|
18089
|
+
for (const file2 of await sessionFiles(directory, flat, signal)) {
|
|
18090
|
+
signal.throwIfAborted();
|
|
18091
|
+
try {
|
|
18092
|
+
const fingerprint = await stat(file2);
|
|
18093
|
+
const cached2 = this.#cache.get(file2);
|
|
18094
|
+
const id = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source.nativeRef.nativeSessionId : await readIdentity(file2, signal);
|
|
18095
|
+
if (id !== nativeSessionId)
|
|
18096
|
+
continue;
|
|
18097
|
+
if (selected)
|
|
18098
|
+
throw new Error("Pi Session identity is ambiguous across files");
|
|
18099
|
+
selected = file2;
|
|
18100
|
+
} catch (error51) {
|
|
18101
|
+
if (!missing(error51))
|
|
18102
|
+
throw error51;
|
|
18103
|
+
}
|
|
18104
|
+
}
|
|
18105
|
+
if (!selected)
|
|
18106
|
+
return null;
|
|
18107
|
+
try {
|
|
18108
|
+
const source = await readCandidate(selected, signal);
|
|
18109
|
+
return source?.nativeRef.nativeSessionId === nativeSessionId ? source : null;
|
|
18110
|
+
} catch (error51) {
|
|
18111
|
+
if (missing(error51))
|
|
18112
|
+
return null;
|
|
18113
|
+
throw error51;
|
|
18114
|
+
}
|
|
17152
18115
|
}
|
|
17153
18116
|
};
|
|
17154
|
-
|
|
17155
|
-
|
|
17156
|
-
|
|
17157
|
-
|
|
17158
|
-
|
|
17159
|
-
...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {}
|
|
17160
|
-
}, { ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {} });
|
|
17161
|
-
return resolution?.executable ?? input.command ?? input.environment.PI_COMMAND ?? "pi";
|
|
17162
|
-
}
|
|
18117
|
+
|
|
18118
|
+
// dist/pi-rpc-session.js
|
|
18119
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
18120
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
18121
|
+
import path8 from "node:path";
|
|
17163
18122
|
|
|
17164
18123
|
// dist/pi-usage.js
|
|
17165
18124
|
function isRecord5(value) {
|
|
@@ -17232,6 +18191,82 @@ function optionalPiStateContextUsage(value) {
|
|
|
17232
18191
|
}
|
|
17233
18192
|
}
|
|
17234
18193
|
|
|
18194
|
+
// dist/pi-subagent-rpc.js
|
|
18195
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
18196
|
+
var PiSubagentRpc = class {
|
|
18197
|
+
send;
|
|
18198
|
+
timeoutMs;
|
|
18199
|
+
#handler;
|
|
18200
|
+
#latest;
|
|
18201
|
+
#pending = /* @__PURE__ */ new Map();
|
|
18202
|
+
constructor(send, timeoutMs) {
|
|
18203
|
+
this.send = send;
|
|
18204
|
+
this.timeoutMs = timeoutMs;
|
|
18205
|
+
}
|
|
18206
|
+
setHandler(handler) {
|
|
18207
|
+
this.#handler = handler;
|
|
18208
|
+
if (this.#latest)
|
|
18209
|
+
handler(this.#latest);
|
|
18210
|
+
}
|
|
18211
|
+
handle(value) {
|
|
18212
|
+
if (value.type !== "extension_ui_request" || value.method !== "setWidget" || value.widgetKey !== "subagent-async" && value.widgetKey !== "subagent-inspect")
|
|
18213
|
+
return false;
|
|
18214
|
+
const status = parsePiSubagentStatus(value);
|
|
18215
|
+
if (status) {
|
|
18216
|
+
this.#latest = status;
|
|
18217
|
+
this.#handler?.(status);
|
|
18218
|
+
}
|
|
18219
|
+
const reply = parsePiSubagentInspection(value);
|
|
18220
|
+
if (reply) {
|
|
18221
|
+
const pending = this.#pending.get(reply.requestId);
|
|
18222
|
+
if (pending) {
|
|
18223
|
+
this.#pending.delete(reply.requestId);
|
|
18224
|
+
clearTimeout(pending.timer);
|
|
18225
|
+
pending.resolve(reply);
|
|
18226
|
+
}
|
|
18227
|
+
}
|
|
18228
|
+
return true;
|
|
18229
|
+
}
|
|
18230
|
+
async inspect(nativeSubagentId) {
|
|
18231
|
+
const address = parsePiSubagentId(nativeSubagentId);
|
|
18232
|
+
const commands = await this.send("get_commands", {});
|
|
18233
|
+
const data = commands.data;
|
|
18234
|
+
if (!Array.isArray(data?.commands) || !data.commands.some((command) => command?.name === "subagents-inspect-rpc" && command.source === "extension")) {
|
|
18235
|
+
throw new Error("Installed Pi has no pi-subagents Host inspection command");
|
|
18236
|
+
}
|
|
18237
|
+
const requestId = randomUUID3();
|
|
18238
|
+
const reply = new Promise((resolve, reject) => {
|
|
18239
|
+
const timer = setTimeout(() => {
|
|
18240
|
+
this.#pending.delete(requestId);
|
|
18241
|
+
reject(new Error("Pi subagent inspection timed out"));
|
|
18242
|
+
}, this.timeoutMs);
|
|
18243
|
+
this.#pending.set(requestId, { resolve, reject, timer });
|
|
18244
|
+
});
|
|
18245
|
+
try {
|
|
18246
|
+
const message3 = `/subagents-inspect-rpc ${requestId} ${address.runId}${address.childId ? ` ${address.childId}` : ""} --lines 200`;
|
|
18247
|
+
const [, result] = await Promise.all([this.send("prompt", { message: message3 }), reply]);
|
|
18248
|
+
if (!result.error && (result.asyncId !== address.runId && result.asyncId !== address.childId || result.childId !== address.childId)) {
|
|
18249
|
+
throw new Error("Pi subagent inspection identity does not match the request");
|
|
18250
|
+
}
|
|
18251
|
+
return result;
|
|
18252
|
+
} finally {
|
|
18253
|
+
const pending = this.#pending.get(requestId);
|
|
18254
|
+
if (pending) {
|
|
18255
|
+
clearTimeout(pending.timer);
|
|
18256
|
+
this.#pending.delete(requestId);
|
|
18257
|
+
}
|
|
18258
|
+
}
|
|
18259
|
+
}
|
|
18260
|
+
close(error51 = new Error("Pi subagent inspection transport closed")) {
|
|
18261
|
+
for (const pending of this.#pending.values()) {
|
|
18262
|
+
clearTimeout(pending.timer);
|
|
18263
|
+
pending.reject(error51);
|
|
18264
|
+
}
|
|
18265
|
+
this.#pending.clear();
|
|
18266
|
+
this.#handler = void 0;
|
|
18267
|
+
}
|
|
18268
|
+
};
|
|
18269
|
+
|
|
17235
18270
|
// dist/pi-rpc-session.js
|
|
17236
18271
|
var PiRpcFaultError = class extends Error {
|
|
17237
18272
|
kind;
|
|
@@ -17363,15 +18398,15 @@ function extractReasoningText(content) {
|
|
|
17363
18398
|
return null;
|
|
17364
18399
|
const type = String(content.type ?? "");
|
|
17365
18400
|
if (type === "thinking" || type === "reasoning" || type === "thought") {
|
|
17366
|
-
const
|
|
17367
|
-
return typeof
|
|
18401
|
+
const text2 = content.thinking ?? content.reasoning ?? content.text ?? content.delta;
|
|
18402
|
+
return typeof text2 === "string" ? text2 : null;
|
|
17368
18403
|
}
|
|
17369
18404
|
return null;
|
|
17370
18405
|
}
|
|
17371
18406
|
function assistantReasoning(value) {
|
|
17372
18407
|
if (!isRecord6(value) || value.role !== "assistant" || !Array.isArray(value.content))
|
|
17373
18408
|
return null;
|
|
17374
|
-
return value.content.map(extractReasoningText).filter((
|
|
18409
|
+
return value.content.map(extractReasoningText).filter((text2) => typeof text2 === "string").join("");
|
|
17375
18410
|
}
|
|
17376
18411
|
function assistantFailure(value) {
|
|
17377
18412
|
if (!isRecord6(value) || value.role !== "assistant")
|
|
@@ -17436,7 +18471,7 @@ function piRpcProcessCommand(options, dependencies = {}) {
|
|
|
17436
18471
|
...thinkingArguments,
|
|
17437
18472
|
...sessionArguments
|
|
17438
18473
|
];
|
|
17439
|
-
const extension =
|
|
18474
|
+
const extension = path8.win32.extname(command).toLowerCase();
|
|
17440
18475
|
if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
|
|
17441
18476
|
return { command, arguments: arguments_, windowsVerbatimArguments: false };
|
|
17442
18477
|
}
|
|
@@ -17478,6 +18513,7 @@ var PiRpcSession = class {
|
|
|
17478
18513
|
#latestCacheHitRatePercent;
|
|
17479
18514
|
#manualCompaction = null;
|
|
17480
18515
|
#stderrTail = "";
|
|
18516
|
+
#subagents;
|
|
17481
18517
|
constructor(options, processAdapter = nodeProcessAdapter) {
|
|
17482
18518
|
if (options.sessionFile && options.forkSessionFile) {
|
|
17483
18519
|
throw new Error("Pi RPC cannot combine Session resume and Fork startup");
|
|
@@ -17492,6 +18528,7 @@ var PiRpcSession = class {
|
|
|
17492
18528
|
...options
|
|
17493
18529
|
};
|
|
17494
18530
|
this.#processAdapter = processAdapter;
|
|
18531
|
+
this.#subagents = new PiSubagentRpc((type, payload) => this.#send(type, payload), this.#options.commandTimeoutMs);
|
|
17495
18532
|
}
|
|
17496
18533
|
get state() {
|
|
17497
18534
|
if (!this.#state)
|
|
@@ -17501,6 +18538,12 @@ var PiRpcSession = class {
|
|
|
17501
18538
|
get stderrTail() {
|
|
17502
18539
|
return this.#stderrTail;
|
|
17503
18540
|
}
|
|
18541
|
+
setSubagentStatusHandler(handler) {
|
|
18542
|
+
this.#subagents.setHandler(handler);
|
|
18543
|
+
}
|
|
18544
|
+
inspectSubagent(id) {
|
|
18545
|
+
return this.#subagents.inspect(id);
|
|
18546
|
+
}
|
|
17504
18547
|
setAutonomousTurnHandler(handler) {
|
|
17505
18548
|
this.#autonomousTurnHandler = handler;
|
|
17506
18549
|
}
|
|
@@ -17670,13 +18713,13 @@ var PiRpcSession = class {
|
|
|
17670
18713
|
throw fault;
|
|
17671
18714
|
}
|
|
17672
18715
|
}
|
|
17673
|
-
async runTurn(
|
|
18716
|
+
async runTurn(text2, onEvent) {
|
|
17674
18717
|
if (!this.#child || !this.#state || this.#closed || this.#failed) {
|
|
17675
18718
|
throw new Error("Pi RPC Session is unavailable");
|
|
17676
18719
|
}
|
|
17677
18720
|
if (this.#activeTurn)
|
|
17678
18721
|
throw new Error("Pi RPC Session already has an active Turn");
|
|
17679
|
-
if (
|
|
18722
|
+
if (text2.length === 0)
|
|
17680
18723
|
throw new Error("Pi text Turn must not be empty");
|
|
17681
18724
|
const settled = new Promise((resolve, reject) => {
|
|
17682
18725
|
this.#activeTurn = {
|
|
@@ -17705,7 +18748,7 @@ var PiRpcSession = class {
|
|
|
17705
18748
|
};
|
|
17706
18749
|
});
|
|
17707
18750
|
try {
|
|
17708
|
-
await this.#send("prompt", { message:
|
|
18751
|
+
await this.#send("prompt", { message: text2 });
|
|
17709
18752
|
} catch (error51) {
|
|
17710
18753
|
this.#rejectActiveTurn(error51 instanceof Error ? error51 : new Error(message2(error51)));
|
|
17711
18754
|
}
|
|
@@ -17825,6 +18868,8 @@ var PiRpcSession = class {
|
|
|
17825
18868
|
this.#handleResponse(value);
|
|
17826
18869
|
return;
|
|
17827
18870
|
}
|
|
18871
|
+
if (this.#subagents.handle(value))
|
|
18872
|
+
return;
|
|
17828
18873
|
if (value.type === "compaction_start") {
|
|
17829
18874
|
this.#compactionActive = true;
|
|
17830
18875
|
this.#compactionTurn = this.#activeTurn;
|
|
@@ -17939,7 +18984,7 @@ var PiRpcSession = class {
|
|
|
17939
18984
|
const active = {
|
|
17940
18985
|
origin: "autonomous",
|
|
17941
18986
|
autonomousEvents: events,
|
|
17942
|
-
nativeTurnKey: assistantMessageId(value) ??
|
|
18987
|
+
nativeTurnKey: assistantMessageId(value) ?? randomUUID4(),
|
|
17943
18988
|
nativeCancellationObserved: false,
|
|
17944
18989
|
text: "",
|
|
17945
18990
|
assistantMessageId: null,
|
|
@@ -18121,13 +19166,13 @@ var PiRpcSession = class {
|
|
|
18121
19166
|
async #confirmSettledTurn(active) {
|
|
18122
19167
|
try {
|
|
18123
19168
|
const response = await this.#send("get_state", {});
|
|
18124
|
-
const
|
|
19169
|
+
const state2 = parseSessionState(response);
|
|
18125
19170
|
if (parseSessionStreaming(response)) {
|
|
18126
19171
|
throw new PiRpcFaultError("protocolError", "Pi RPC agent_settled state is still Streaming");
|
|
18127
19172
|
}
|
|
18128
19173
|
if (this.#activeTurn !== active)
|
|
18129
19174
|
return;
|
|
18130
|
-
this.#state =
|
|
19175
|
+
this.#state = state2;
|
|
18131
19176
|
active.settlement = "confirmed";
|
|
18132
19177
|
this.#finishSettledTurn(active);
|
|
18133
19178
|
} catch (error51) {
|
|
@@ -18182,7 +19227,7 @@ var PiRpcSession = class {
|
|
|
18182
19227
|
if (active.assistantMessageId !== null && active.reasoningMessageOpen) {
|
|
18183
19228
|
active.onEvent({ type: "reasoning.completed", messageId: active.assistantMessageId });
|
|
18184
19229
|
}
|
|
18185
|
-
const messageId = assistantMessageId(value) ??
|
|
19230
|
+
const messageId = assistantMessageId(value) ?? randomUUID4();
|
|
18186
19231
|
active.assistantMessageId = messageId;
|
|
18187
19232
|
active.sawStreamedMessageText = false;
|
|
18188
19233
|
active.sawStreamedMessageReasoning = false;
|
|
@@ -18243,7 +19288,7 @@ var PiRpcSession = class {
|
|
|
18243
19288
|
if (!child?.stdin.writable || this.#closed || this.#failed) {
|
|
18244
19289
|
return Promise.reject(new Error("Pi RPC stdin is unavailable"));
|
|
18245
19290
|
}
|
|
18246
|
-
const id = `codexhost-${
|
|
19291
|
+
const id = `codexhost-${randomUUID4()}`;
|
|
18247
19292
|
return new Promise((resolve, reject) => {
|
|
18248
19293
|
const pending = {
|
|
18249
19294
|
command: type,
|
|
@@ -18329,6 +19374,7 @@ var PiRpcSession = class {
|
|
|
18329
19374
|
}
|
|
18330
19375
|
}
|
|
18331
19376
|
#rejectAll(error51) {
|
|
19377
|
+
this.#subagents.close(error51);
|
|
18332
19378
|
for (const pending of this.#pending.values()) {
|
|
18333
19379
|
if (pending.timeout)
|
|
18334
19380
|
clearTimeout(pending.timeout);
|
|
@@ -18407,38 +19453,38 @@ function normalizedError(error51, fallbackCode) {
|
|
|
18407
19453
|
function invalidState(message3) {
|
|
18408
19454
|
return { code: "invalidState", message: message3, retryable: false };
|
|
18409
19455
|
}
|
|
18410
|
-
function nativeModelFromState(
|
|
18411
|
-
if (
|
|
19456
|
+
function nativeModelFromState(state2) {
|
|
19457
|
+
if (state2.provider === null && state2.modelId === null)
|
|
18412
19458
|
return null;
|
|
18413
|
-
if (
|
|
19459
|
+
if (state2.provider === null || state2.modelId === null) {
|
|
18414
19460
|
throw new PiRpcFaultError("protocolError", "Pi state contains a partial Model identity");
|
|
18415
19461
|
}
|
|
18416
|
-
return { provider:
|
|
19462
|
+
return { provider: state2.provider, id: state2.modelId };
|
|
18417
19463
|
}
|
|
18418
|
-
function effectiveModelFromState(
|
|
18419
|
-
const model = nativeModelFromState(
|
|
19464
|
+
function effectiveModelFromState(state2) {
|
|
19465
|
+
const model = nativeModelFromState(state2);
|
|
18420
19466
|
return model ? encodePiModelRef(model) : void 0;
|
|
18421
19467
|
}
|
|
18422
|
-
function harnessStateFromPi(
|
|
18423
|
-
const effectiveModel = effectiveModelFromState(
|
|
19468
|
+
function harnessStateFromPi(state2, thinkingLevels) {
|
|
19469
|
+
const effectiveModel = effectiveModelFromState(state2);
|
|
18424
19470
|
const availableThinkingOptions = thinkingLevels ? normalizePiThinkingOptions(thinkingLevels) : void 0;
|
|
18425
|
-
if (availableThinkingOptions && (!
|
|
19471
|
+
if (availableThinkingOptions && (!state2.thinkingLevel || !thinkingLevels?.includes(state2.thinkingLevel))) {
|
|
18426
19472
|
throw new PiRpcFaultError("protocolError", "Pi effective Thinking level is absent from its available levels");
|
|
18427
19473
|
}
|
|
18428
19474
|
return {
|
|
18429
19475
|
nativeRef: nativeSessionRefSchema.parse({
|
|
18430
19476
|
harnessId: piHarnessId2,
|
|
18431
|
-
nativeSessionId:
|
|
18432
|
-
...
|
|
19477
|
+
nativeSessionId: state2.sessionId,
|
|
19478
|
+
...state2.sessionFile ? { locator: { sessionFile: state2.sessionFile } } : {},
|
|
18433
19479
|
formatVersion: 1
|
|
18434
19480
|
}),
|
|
18435
19481
|
...effectiveModel ? { effectiveModel } : {},
|
|
18436
|
-
...
|
|
19482
|
+
...state2.thinkingLevel ? { effectiveThinkingOptionId: state2.thinkingLevel } : {},
|
|
18437
19483
|
...availableThinkingOptions ? { availableThinkingOptions } : {}
|
|
18438
19484
|
};
|
|
18439
19485
|
}
|
|
18440
|
-
function nativeModelForHistory(
|
|
18441
|
-
return nativeModelFromState(
|
|
19486
|
+
function nativeModelForHistory(state2) {
|
|
19487
|
+
return nativeModelFromState(state2);
|
|
18442
19488
|
}
|
|
18443
19489
|
function sessionFileFromRef(ref) {
|
|
18444
19490
|
if (ref.harnessId !== piHarnessId2 || !isRecord7(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
|
|
@@ -18458,20 +19504,20 @@ function nativeText(value) {
|
|
|
18458
19504
|
return value;
|
|
18459
19505
|
if (!isRecord7(value) || !Array.isArray(value.content))
|
|
18460
19506
|
return "";
|
|
18461
|
-
return value.content.filter((content) => isRecord7(content) && content.type === "text" && typeof content.text === "string").map(({ text }) =>
|
|
19507
|
+
return value.content.filter((content) => isRecord7(content) && content.type === "text" && typeof content.text === "string").map(({ text: text2 }) => text2).join("");
|
|
18462
19508
|
}
|
|
18463
19509
|
function boundedOutput(value, limit) {
|
|
18464
|
-
const
|
|
18465
|
-
if (
|
|
19510
|
+
const text2 = nativeText(value);
|
|
19511
|
+
if (text2.length === 0)
|
|
18466
19512
|
return void 0;
|
|
18467
|
-
const truncated =
|
|
19513
|
+
const truncated = text2.length > limit;
|
|
18468
19514
|
return {
|
|
18469
|
-
content: [{ type: "text", text: truncated ?
|
|
19515
|
+
content: [{ type: "text", text: truncated ? text2.slice(0, limit) : text2 }],
|
|
18470
19516
|
...truncated ? { truncated: true } : {}
|
|
18471
19517
|
};
|
|
18472
19518
|
}
|
|
18473
19519
|
function outputText(output) {
|
|
18474
|
-
return output?.content.filter((content) => content.type === "text").map(({ text }) =>
|
|
19520
|
+
return output?.content.filter((content) => content.type === "text").map(({ text: text2 }) => text2).join("") ?? "";
|
|
18475
19521
|
}
|
|
18476
19522
|
function stringField(value, key) {
|
|
18477
19523
|
if (!isRecord7(value))
|
|
@@ -18503,10 +19549,10 @@ function stripDiffPrefix(pathString) {
|
|
|
18503
19549
|
return pathString.startsWith("a/") || pathString.startsWith("b/") ? pathString.slice(2) : pathString;
|
|
18504
19550
|
}
|
|
18505
19551
|
function displayPath(nativePath, cwd) {
|
|
18506
|
-
const resolvedCwd =
|
|
18507
|
-
const resolvedPath =
|
|
18508
|
-
const relative =
|
|
18509
|
-
const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${
|
|
19552
|
+
const resolvedCwd = path9.resolve(cwd);
|
|
19553
|
+
const resolvedPath = path9.isAbsolute(nativePath) ? path9.resolve(nativePath) : path9.resolve(cwd, nativePath);
|
|
19554
|
+
const relative = path9.relative(resolvedCwd, resolvedPath);
|
|
19555
|
+
const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path9.sep}`);
|
|
18510
19556
|
const selected = inside ? relative : resolvedPath;
|
|
18511
19557
|
const normalized = selected.replaceAll("\\", "/");
|
|
18512
19558
|
if (normalized.length === 0 || normalized === ".")
|
|
@@ -18696,6 +19742,8 @@ var PiHarnessSession = class {
|
|
|
18696
19742
|
initialUsage;
|
|
18697
19743
|
outputs;
|
|
18698
19744
|
#channel = new HarnessOutputChannel();
|
|
19745
|
+
#subagents = new PiSubagents((event) => this.#event(event));
|
|
19746
|
+
#pendingSubagentStatus = null;
|
|
18699
19747
|
#closeTimeoutMs;
|
|
18700
19748
|
#createTransport;
|
|
18701
19749
|
#cwd;
|
|
@@ -18731,7 +19779,8 @@ var PiHarnessSession = class {
|
|
|
18731
19779
|
permissionModeScope: "live"
|
|
18732
19780
|
},
|
|
18733
19781
|
history: { fork: true, forkAcrossCwd: true, rollbackLastTurn: true },
|
|
18734
|
-
autonomousTurns: { observe: true }
|
|
19782
|
+
autonomousTurns: { observe: true },
|
|
19783
|
+
subagents: { observe: true, readTranscript: true }
|
|
18735
19784
|
};
|
|
18736
19785
|
this.commands = {
|
|
18737
19786
|
list: async () => ({ ok: true, value: piCommandCatalog }),
|
|
@@ -18746,6 +19795,24 @@ var PiHarnessSession = class {
|
|
|
18746
19795
|
if (this.#transport)
|
|
18747
19796
|
this.#bindAutonomousTurnHandler(this.#transport);
|
|
18748
19797
|
}
|
|
19798
|
+
ownsNativeSession(id) {
|
|
19799
|
+
return this.#transport?.state.sessionId === id;
|
|
19800
|
+
}
|
|
19801
|
+
async readSubagentHistory(cwd) {
|
|
19802
|
+
if (this.#phase !== "open" || path9.resolve(cwd) !== path9.resolve(this.#cwd)) {
|
|
19803
|
+
throw new Error("Pi Subagent parent workspace or Session is unavailable");
|
|
19804
|
+
}
|
|
19805
|
+
return (await this.#ensureTransport()).getEntries();
|
|
19806
|
+
}
|
|
19807
|
+
async inspectSubagent(id, cwd) {
|
|
19808
|
+
if (this.#phase !== "open" || path9.resolve(cwd) !== path9.resolve(this.#cwd)) {
|
|
19809
|
+
throw new Error("Pi Subagent parent workspace or Session is unavailable");
|
|
19810
|
+
}
|
|
19811
|
+
const transport = await this.#ensureTransport();
|
|
19812
|
+
if (!transport.inspectSubagent)
|
|
19813
|
+
throw new Error("Pi transport does not support Subagent inspection");
|
|
19814
|
+
return transport.inspectSubagent(id);
|
|
19815
|
+
}
|
|
18749
19816
|
handleTransportFault(error51) {
|
|
18750
19817
|
queueMicrotask(() => this.#fault(error51));
|
|
18751
19818
|
}
|
|
@@ -18766,13 +19833,14 @@ var PiHarnessSession = class {
|
|
|
18766
19833
|
try {
|
|
18767
19834
|
const transport = await this.#ensureTransport();
|
|
18768
19835
|
const history = await transport.getEntries();
|
|
19836
|
+
await restorePiSubagents(history, transport.state.sessionId, this.#subagents);
|
|
18769
19837
|
return {
|
|
18770
19838
|
ok: true,
|
|
18771
19839
|
value: {
|
|
18772
19840
|
...mapPiSnapshot(history, {
|
|
18773
19841
|
sessionId: transport.state.sessionId,
|
|
18774
19842
|
model: nativeModelForHistory(transport.state)
|
|
18775
|
-
}),
|
|
19843
|
+
}, this.#subagents),
|
|
18776
19844
|
state: this.#state
|
|
18777
19845
|
}
|
|
18778
19846
|
};
|
|
@@ -18812,8 +19880,8 @@ var PiHarnessSession = class {
|
|
|
18812
19880
|
}
|
|
18813
19881
|
};
|
|
18814
19882
|
}
|
|
18815
|
-
const
|
|
18816
|
-
if (
|
|
19883
|
+
const text2 = command.input.map((input) => input.text).join("\n");
|
|
19884
|
+
if (text2.length === 0) {
|
|
18817
19885
|
return {
|
|
18818
19886
|
ok: false,
|
|
18819
19887
|
error: {
|
|
@@ -18870,7 +19938,7 @@ var PiHarnessSession = class {
|
|
|
18870
19938
|
this.#active = active;
|
|
18871
19939
|
this.#event({ type: "turn.started", turnId: command.turnId });
|
|
18872
19940
|
this.#event({ type: "item.started", turnId: command.turnId, item });
|
|
18873
|
-
void transport.runTurn(
|
|
19941
|
+
void transport.runTurn(text2, (event) => this.#handleTurnEvent(active, event)).then(async (result) => {
|
|
18874
19942
|
try {
|
|
18875
19943
|
const identity = await this.#completedTurnIdentity(active, transport);
|
|
18876
19944
|
this.#completeTurn(active, result.cancelled ? {
|
|
@@ -18989,19 +20057,19 @@ var PiHarnessSession = class {
|
|
|
18989
20057
|
const previousModel = this.#state.effectiveModel;
|
|
18990
20058
|
this.#configuring = true;
|
|
18991
20059
|
try {
|
|
18992
|
-
let
|
|
20060
|
+
let state2;
|
|
18993
20061
|
let thinkingLevels;
|
|
18994
20062
|
try {
|
|
18995
|
-
|
|
20063
|
+
state2 = await transport.selectModel(requested);
|
|
18996
20064
|
thinkingLevels = await transport.getAvailableThinkingLevels();
|
|
18997
|
-
this.#publishTransportState(
|
|
20065
|
+
this.#publishTransportState(state2, thinkingLevels);
|
|
18998
20066
|
} catch (error51) {
|
|
18999
20067
|
if (error51 instanceof PiRpcFaultError)
|
|
19000
20068
|
this.#fault(error51);
|
|
19001
20069
|
return { ok: false, error: normalizedError(error51, "nativeFailure") };
|
|
19002
20070
|
}
|
|
19003
|
-
const actual = nativeModelFromState(
|
|
19004
|
-
const nextModel = effectiveModelFromState(
|
|
20071
|
+
const actual = nativeModelFromState(state2);
|
|
20072
|
+
const nextModel = effectiveModelFromState(state2);
|
|
19005
20073
|
if (previousModel?.id !== nextModel?.id) {
|
|
19006
20074
|
this.#invalidateUsage();
|
|
19007
20075
|
void this.#refreshUsage();
|
|
@@ -19063,10 +20131,10 @@ var PiHarnessSession = class {
|
|
|
19063
20131
|
const thinkingOptionId = parsedThinkingOptionId.data;
|
|
19064
20132
|
this.#configuring = true;
|
|
19065
20133
|
try {
|
|
19066
|
-
let
|
|
20134
|
+
let state2;
|
|
19067
20135
|
let thinkingLevels;
|
|
19068
20136
|
try {
|
|
19069
|
-
|
|
20137
|
+
state2 = await transport.selectThinkingOption(thinkingOptionId);
|
|
19070
20138
|
thinkingLevels = await transport.getAvailableThinkingLevels();
|
|
19071
20139
|
} catch (error51) {
|
|
19072
20140
|
if (error51 instanceof PiRpcFaultError)
|
|
@@ -19084,7 +20152,7 @@ var PiHarnessSession = class {
|
|
|
19084
20152
|
};
|
|
19085
20153
|
}
|
|
19086
20154
|
try {
|
|
19087
|
-
this.#publishTransportState(
|
|
20155
|
+
this.#publishTransportState(state2, thinkingLevels);
|
|
19088
20156
|
} catch (error51) {
|
|
19089
20157
|
if (error51 instanceof PiRpcFaultError)
|
|
19090
20158
|
this.#fault(error51);
|
|
@@ -19241,16 +20309,16 @@ var PiHarnessSession = class {
|
|
|
19241
20309
|
const starting = transport.start().then(async () => {
|
|
19242
20310
|
if (this.#phase !== "open")
|
|
19243
20311
|
throw new Error("Pi Session closed during startup");
|
|
19244
|
-
let
|
|
20312
|
+
let state2 = transport.state;
|
|
19245
20313
|
let thinkingLevels = await transport.getAvailableThinkingLevels();
|
|
19246
20314
|
if (this.#requestedModel) {
|
|
19247
20315
|
const requested = decodePiModelRef(this.#requestedModel);
|
|
19248
|
-
const current = nativeModelFromState(
|
|
20316
|
+
const current = nativeModelFromState(state2);
|
|
19249
20317
|
if (!samePiModel(current, requested))
|
|
19250
|
-
|
|
20318
|
+
state2 = await transport.selectModel(requested);
|
|
19251
20319
|
thinkingLevels = await transport.getAvailableThinkingLevels();
|
|
19252
|
-
if (!samePiModel(nativeModelFromState(
|
|
19253
|
-
this.#publishTransportState(
|
|
20320
|
+
if (!samePiModel(nativeModelFromState(state2), requested)) {
|
|
20321
|
+
this.#publishTransportState(state2, thinkingLevels);
|
|
19254
20322
|
throw new Error("Pi did not activate the requested create Model");
|
|
19255
20323
|
}
|
|
19256
20324
|
}
|
|
@@ -19262,11 +20330,11 @@ var PiHarnessSession = class {
|
|
|
19262
20330
|
retryable: false
|
|
19263
20331
|
});
|
|
19264
20332
|
}
|
|
19265
|
-
|
|
20333
|
+
state2 = await transport.selectThinkingOption(this.#requestedThinkingOptionId);
|
|
19266
20334
|
thinkingLevels = await transport.getAvailableThinkingLevels();
|
|
19267
20335
|
}
|
|
19268
20336
|
this.#transport = transport;
|
|
19269
|
-
this.#publishTransportState(
|
|
20337
|
+
this.#publishTransportState(state2, thinkingLevels);
|
|
19270
20338
|
this.#drainPendingAutonomousTurns(transport);
|
|
19271
20339
|
return transport;
|
|
19272
20340
|
}).catch(async (error51) => {
|
|
@@ -19283,6 +20351,14 @@ var PiHarnessSession = class {
|
|
|
19283
20351
|
return starting;
|
|
19284
20352
|
}
|
|
19285
20353
|
#bindAutonomousTurnHandler(transport) {
|
|
20354
|
+
transport.setSubagentStatusHandler?.((runs) => {
|
|
20355
|
+
if (this.#phase !== "open")
|
|
20356
|
+
return;
|
|
20357
|
+
if (this.#transport !== transport)
|
|
20358
|
+
this.#pendingSubagentStatus = runs;
|
|
20359
|
+
else
|
|
20360
|
+
this.#subagents.observe(runs);
|
|
20361
|
+
});
|
|
19286
20362
|
transport.setAutonomousTurnHandler((turn) => {
|
|
19287
20363
|
if (this.#phase !== "open")
|
|
19288
20364
|
return;
|
|
@@ -19294,6 +20370,10 @@ var PiHarnessSession = class {
|
|
|
19294
20370
|
});
|
|
19295
20371
|
}
|
|
19296
20372
|
#drainPendingAutonomousTurns(transport) {
|
|
20373
|
+
if (this.#pendingSubagentStatus) {
|
|
20374
|
+
this.#subagents.observe(this.#pendingSubagentStatus);
|
|
20375
|
+
this.#pendingSubagentStatus = null;
|
|
20376
|
+
}
|
|
19297
20377
|
const pending = this.#pendingAutonomousTurns.filter((candidate) => candidate.transport === transport);
|
|
19298
20378
|
this.#pendingAutonomousTurns = this.#pendingAutonomousTurns.filter((candidate) => candidate.transport !== transport);
|
|
19299
20379
|
for (const candidate of pending) {
|
|
@@ -19321,7 +20401,7 @@ var PiHarnessSession = class {
|
|
|
19321
20401
|
}));
|
|
19322
20402
|
return;
|
|
19323
20403
|
}
|
|
19324
|
-
const turnId = hostTurnIdSchema.parse(
|
|
20404
|
+
const turnId = hostTurnIdSchema.parse(randomUUID5());
|
|
19325
20405
|
let resolveCompletion = () => void 0;
|
|
19326
20406
|
const completion = new Promise((resolve) => {
|
|
19327
20407
|
resolveCompletion = resolve;
|
|
@@ -19374,8 +20454,8 @@ var PiHarnessSession = class {
|
|
|
19374
20454
|
this.#fault(new PiAdapterFaultError(normalized));
|
|
19375
20455
|
}
|
|
19376
20456
|
}
|
|
19377
|
-
#publishTransportState(
|
|
19378
|
-
this.#state = harnessStateFromPi(
|
|
20457
|
+
#publishTransportState(state2, thinkingLevels) {
|
|
20458
|
+
this.#state = harnessStateFromPi(state2, thinkingLevels);
|
|
19379
20459
|
this.#event({ type: "session.state.changed", state: this.#state });
|
|
19380
20460
|
}
|
|
19381
20461
|
#invalidateUsage() {
|
|
@@ -19483,7 +20563,7 @@ var PiHarnessSession = class {
|
|
|
19483
20563
|
if (active.interactionByNativeId.has(request.requestId)) {
|
|
19484
20564
|
throw new Error("Pi Interaction started more than once");
|
|
19485
20565
|
}
|
|
19486
|
-
const interactionId = hostInteractionIdSchema.parse(
|
|
20566
|
+
const interactionId = hostInteractionIdSchema.parse(randomUUID5());
|
|
19487
20567
|
const question = request.method === "select" ? {
|
|
19488
20568
|
id: "answer",
|
|
19489
20569
|
type: "choice",
|
|
@@ -19562,16 +20642,16 @@ var PiHarnessSession = class {
|
|
|
19562
20642
|
active.agentMessageId = messageId;
|
|
19563
20643
|
active.sawAssistantMessage = true;
|
|
19564
20644
|
}
|
|
19565
|
-
#appendText(active,
|
|
20645
|
+
#appendText(active, text2) {
|
|
19566
20646
|
if (active.agentMessageId === null || !active.agentItem) {
|
|
19567
20647
|
throw new Error("Pi Assistant text arrived outside an active message");
|
|
19568
20648
|
}
|
|
19569
|
-
active.agentItem = { ...active.agentItem, text: active.agentItem.text +
|
|
20649
|
+
active.agentItem = { ...active.agentItem, text: active.agentItem.text + text2 };
|
|
19570
20650
|
this.#event({
|
|
19571
20651
|
type: "item.updated",
|
|
19572
20652
|
turnId: active.command.turnId,
|
|
19573
20653
|
itemId: active.agentItem.itemId,
|
|
19574
|
-
update: { type: "text.append", text }
|
|
20654
|
+
update: { type: "text.append", text: text2 }
|
|
19575
20655
|
});
|
|
19576
20656
|
}
|
|
19577
20657
|
#completeAgentItem(active, outcome, completeEmpty) {
|
|
@@ -19582,8 +20662,8 @@ var PiHarnessSession = class {
|
|
|
19582
20662
|
active.agentItem = null;
|
|
19583
20663
|
this.#completeItem(active, item, outcome);
|
|
19584
20664
|
}
|
|
19585
|
-
#appendReasoning(active,
|
|
19586
|
-
if (
|
|
20665
|
+
#appendReasoning(active, text2) {
|
|
20666
|
+
if (text2.length === 0)
|
|
19587
20667
|
return;
|
|
19588
20668
|
if (!active.reasoningItem) {
|
|
19589
20669
|
active.reasoningItem = {
|
|
@@ -19599,13 +20679,13 @@ var PiHarnessSession = class {
|
|
|
19599
20679
|
}
|
|
19600
20680
|
active.reasoningItem = {
|
|
19601
20681
|
...active.reasoningItem,
|
|
19602
|
-
text: active.reasoningItem.text +
|
|
20682
|
+
text: active.reasoningItem.text + text2
|
|
19603
20683
|
};
|
|
19604
20684
|
this.#event({
|
|
19605
20685
|
type: "item.updated",
|
|
19606
20686
|
turnId: active.command.turnId,
|
|
19607
20687
|
itemId: active.reasoningItem.itemId,
|
|
19608
|
-
update: { type: "text.append", text }
|
|
20688
|
+
update: { type: "text.append", text: text2 }
|
|
19609
20689
|
});
|
|
19610
20690
|
}
|
|
19611
20691
|
#completeReasoning(active, outcome) {
|
|
@@ -19642,6 +20722,7 @@ var PiHarnessSession = class {
|
|
|
19642
20722
|
const tool = active.tools.get(event.callId);
|
|
19643
20723
|
if (!tool)
|
|
19644
20724
|
throw new Error("Pi Tool update references an unknown Tool Call");
|
|
20725
|
+
this.#subagents.start(active.command.turnId, tool.nativeName, event.output, this.#newItemId(), event.callId);
|
|
19645
20726
|
const output = boundedOutput(event.output, this.#toolOutputLimit);
|
|
19646
20727
|
if (!output)
|
|
19647
20728
|
return;
|
|
@@ -19698,6 +20779,7 @@ var PiHarnessSession = class {
|
|
|
19698
20779
|
}
|
|
19699
20780
|
const outcome = active.cancellationRequested ? { status: "cancelled", reason: "Cancelled by user" } : event.isError ? { status: "failed", error: toolFailure(event.toolName) } : { status: "succeeded" };
|
|
19700
20781
|
this.#completeItem(active, tool.item, outcome);
|
|
20782
|
+
this.#subagents.start(active.command.turnId, event.toolName, event.result, this.#newItemId(), event.callId);
|
|
19701
20783
|
if (!event.isError) {
|
|
19702
20784
|
try {
|
|
19703
20785
|
const kind = fileMutatingKind(event.toolName);
|
|
@@ -19767,6 +20849,7 @@ var PiHarnessSession = class {
|
|
|
19767
20849
|
for (const tool of active.tools.values())
|
|
19768
20850
|
this.#completeItem(active, tool.item, itemOutcome2);
|
|
19769
20851
|
active.tools.clear();
|
|
20852
|
+
this.#subagents.finish(active.command.turnId);
|
|
19770
20853
|
if (!active.sawAssistantMessage && finalText !== void 0 && active.agentItem) {
|
|
19771
20854
|
active.agentItem = { ...active.agentItem, text: finalText };
|
|
19772
20855
|
}
|
|
@@ -19827,12 +20910,66 @@ var PiHarnessSession = class {
|
|
|
19827
20910
|
this.#channel.emit({ kind: "event", event });
|
|
19828
20911
|
}
|
|
19829
20912
|
#newItemId() {
|
|
19830
|
-
return hostItemIdSchema.parse(
|
|
20913
|
+
return hostItemIdSchema.parse(randomUUID5());
|
|
19831
20914
|
}
|
|
19832
20915
|
};
|
|
19833
20916
|
var PiAdapter = class {
|
|
20917
|
+
credentialImports;
|
|
19834
20918
|
commandCatalog = piCommandCatalog;
|
|
19835
20919
|
harnessId = piHarnessId2;
|
|
20920
|
+
subagents = {
|
|
20921
|
+
readSnapshot: async ({ parent, nativeSubagentId, cwd }) => {
|
|
20922
|
+
let transport;
|
|
20923
|
+
try {
|
|
20924
|
+
if (this.#closePromise || parent.harnessId !== this.harnessId) {
|
|
20925
|
+
return { ok: false, error: invalidState("Pi Subagent parent is unavailable") };
|
|
20926
|
+
}
|
|
20927
|
+
const workflow = parsePiWorkflowSubagentId(nativeSubagentId);
|
|
20928
|
+
if (!workflow)
|
|
20929
|
+
parsePiSubagentId(nativeSubagentId);
|
|
20930
|
+
const live = [...this.#sessions].find((session) => session.ownsNativeSession(parent.nativeSessionId));
|
|
20931
|
+
let reply;
|
|
20932
|
+
if (live) {
|
|
20933
|
+
if (workflow)
|
|
20934
|
+
return await readPiWorkflowChild(await live.readSubagentHistory(cwd), parent.nativeSessionId, workflow);
|
|
20935
|
+
reply = await live.inspectSubagent(nativeSubagentId, cwd);
|
|
20936
|
+
} else {
|
|
20937
|
+
const sessionFile = sessionFileFromRef(parent);
|
|
20938
|
+
transport = this.#createTransport({ cwd, sessionFile });
|
|
20939
|
+
this.#inspections.add(transport);
|
|
20940
|
+
await transport.start();
|
|
20941
|
+
if (transport.state.sessionId !== parent.nativeSessionId)
|
|
20942
|
+
throw new Error("Pi Subagent parent identity mismatch");
|
|
20943
|
+
await transport.verifySessionCwd(cwd);
|
|
20944
|
+
if (workflow)
|
|
20945
|
+
return await readPiWorkflowChild(await transport.getEntries(), parent.nativeSessionId, workflow);
|
|
20946
|
+
if (!transport.inspectSubagent)
|
|
20947
|
+
throw new Error("Pi transport does not support Subagent inspection");
|
|
20948
|
+
reply = await transport.inspectSubagent(nativeSubagentId);
|
|
20949
|
+
}
|
|
20950
|
+
if (reply.error)
|
|
20951
|
+
return {
|
|
20952
|
+
ok: false,
|
|
20953
|
+
error: {
|
|
20954
|
+
code: reply.error.code === "foreign_session" ? "invalidRequest" : ["not_found", "stale"].includes(reply.error.code) ? "sessionNotFound" : "unavailable",
|
|
20955
|
+
message: reply.error.message,
|
|
20956
|
+
retryable: false
|
|
20957
|
+
}
|
|
20958
|
+
};
|
|
20959
|
+
return {
|
|
20960
|
+
ok: true,
|
|
20961
|
+
value: piSubagentSnapshot(parent.nativeSessionId, nativeSubagentId, reply)
|
|
20962
|
+
};
|
|
20963
|
+
} catch (error51) {
|
|
20964
|
+
return { ok: false, error: normalizedError(error51, "unavailable") };
|
|
20965
|
+
} finally {
|
|
20966
|
+
if (transport) {
|
|
20967
|
+
this.#inspections.delete(transport);
|
|
20968
|
+
await transport.close();
|
|
20969
|
+
}
|
|
20970
|
+
}
|
|
20971
|
+
}
|
|
20972
|
+
};
|
|
19836
20973
|
sessionImport = Object.freeze({
|
|
19837
20974
|
listCandidates: async () => {
|
|
19838
20975
|
const result = await this.#readImport((signal) => this.#importIndex.list(signal));
|
|
@@ -19868,6 +21005,19 @@ var PiAdapter = class {
|
|
|
19868
21005
|
constructor(options = {}, dependencies = {
|
|
19869
21006
|
createTransport: (sessionOptions) => new PiRpcSession({ ...options, ...sessionOptions })
|
|
19870
21007
|
}) {
|
|
21008
|
+
const imports = createPiCredentialImports(options);
|
|
21009
|
+
const updateCatalog = async (operation) => {
|
|
21010
|
+
await operation;
|
|
21011
|
+
this.#inspectionCache.clear();
|
|
21012
|
+
};
|
|
21013
|
+
this.credentialImports = {
|
|
21014
|
+
providers: imports.providers,
|
|
21015
|
+
list: () => imports.list(),
|
|
21016
|
+
listOthers: () => imports.listOthers?.() ?? Promise.resolve([]),
|
|
21017
|
+
add: (name, credential) => updateCatalog(imports.add(name, credential)),
|
|
21018
|
+
reimport: (name, credential) => updateCatalog(imports.reimport(name, credential)),
|
|
21019
|
+
remove: (name) => updateCatalog(imports.remove(name))
|
|
21020
|
+
};
|
|
19871
21021
|
this.#createTransport = dependencies.createTransport;
|
|
19872
21022
|
this.#importIndex = new PiSessionImportIndex({ ...process.env, ...options.environment });
|
|
19873
21023
|
this.#closeTimeoutMs = options.closeTimeoutMs ?? 2e3;
|
|
@@ -19945,7 +21095,8 @@ var PiAdapter = class {
|
|
|
19945
21095
|
permissionModeScope: "live"
|
|
19946
21096
|
},
|
|
19947
21097
|
history: { fork: true, forkAcrossCwd: true, rollbackLastTurn: true },
|
|
19948
|
-
autonomousTurns: { observe: true }
|
|
21098
|
+
autonomousTurns: { observe: true },
|
|
21099
|
+
subagents: { observe: true, readTranscript: true }
|
|
19949
21100
|
}
|
|
19950
21101
|
};
|
|
19951
21102
|
} catch (error51) {
|
|
@@ -20099,40 +21250,40 @@ var PiAdapter = class {
|
|
|
20099
21250
|
});
|
|
20100
21251
|
}
|
|
20101
21252
|
if (rolledBack.unpersisted) {
|
|
20102
|
-
const
|
|
21253
|
+
const state2 = transport.state;
|
|
20103
21254
|
const history = await transport.getEntries();
|
|
20104
21255
|
await transport.close();
|
|
20105
21256
|
await persistEmptyPiSession({
|
|
20106
|
-
state,
|
|
21257
|
+
state: state2,
|
|
20107
21258
|
history,
|
|
20108
21259
|
sourceSessionFile,
|
|
20109
21260
|
sourceSessionId: sourceRef.nativeSessionId,
|
|
20110
21261
|
cwd: input.cwd
|
|
20111
21262
|
});
|
|
20112
|
-
if (!
|
|
21263
|
+
if (!state2.sessionFile)
|
|
20113
21264
|
throw new Error("Pi empty fork has no Session file");
|
|
20114
|
-
const configuration = await readPiEmptySessionConfiguration(
|
|
21265
|
+
const configuration = await readPiEmptySessionConfiguration(state2.sessionFile);
|
|
20115
21266
|
if (!configuration)
|
|
20116
21267
|
throw new Error("Pi empty fork has no restorable configuration");
|
|
20117
21268
|
transport = this.#createTransport({
|
|
20118
21269
|
cwd: input.cwd,
|
|
20119
21270
|
...input.environment ? { environment: input.environment } : {},
|
|
20120
|
-
sessionFile:
|
|
21271
|
+
sessionFile: state2.sessionFile,
|
|
20121
21272
|
emptySessionConfiguration: configuration,
|
|
20122
21273
|
onFault: (error51) => session?.handleTransportFault(error51)
|
|
20123
21274
|
});
|
|
20124
21275
|
await transport.start();
|
|
20125
|
-
if (transport.state.sessionId !==
|
|
21276
|
+
if (transport.state.sessionId !== state2.sessionId) {
|
|
20126
21277
|
throw new Error("Pi empty fork resumed with a different identity");
|
|
20127
21278
|
}
|
|
20128
|
-
const model = nativeModelFromState(
|
|
21279
|
+
const model = nativeModelFromState(state2);
|
|
20129
21280
|
if (model && !samePiModel(nativeModelFromState(transport.state), model)) {
|
|
20130
21281
|
await transport.selectModel(model);
|
|
20131
21282
|
}
|
|
20132
|
-
if (
|
|
20133
|
-
await transport.selectThinkingOption(
|
|
21283
|
+
if (state2.thinkingLevel && transport.state.thinkingLevel !== state2.thinkingLevel) {
|
|
21284
|
+
await transport.selectThinkingOption(state2.thinkingLevel);
|
|
20134
21285
|
}
|
|
20135
|
-
if (!samePiModel(nativeModelFromState(transport.state), model) || transport.state.thinkingLevel !==
|
|
21286
|
+
if (!samePiModel(nativeModelFromState(transport.state), model) || transport.state.thinkingLevel !== state2.thinkingLevel) {
|
|
20136
21287
|
throw new Error("Pi empty fork could not restore its configuration");
|
|
20137
21288
|
}
|
|
20138
21289
|
await transport.verifySessionCwd(input.cwd);
|