@codexhost/cli-darwin-x64 0.9.1-test.2 → 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 +256 -179
- package/app/host-runtime.mjs +594 -298
- package/app/plugins/antigravity/plugin.mjs +123 -1
- package/app/plugins/claude-code/plugin.mjs +248 -42
- package/app/plugins/codebuddy/plugin.mjs +2166 -758
- package/app/plugins/cursor-cli/plugin.mjs +35942 -10942
- package/app/plugins/deepseek-harness/plugin.mjs +70 -0
- package/app/plugins/enabled.json +1 -0
- package/app/plugins/grok/plugin.mjs +193 -82
- package/app/plugins/hermes/plugin.mjs +2444 -94
- package/app/plugins/kiro-cli/plugin.mjs +70 -0
- package/app/plugins/omp/plugin.mjs +106 -8
- package/app/plugins/opencode/plugin.mjs +70 -0
- package/app/plugins/pi/plugin.mjs +1933 -767
- package/app/plugins/qoder/plugin.mjs +71 -9
- package/app/plugins/qoder-cn/plugin.mjs +71 -9
- package/app/plugins/workbuddy/assets/icon.svg +29 -0
- package/app/plugins/workbuddy/manifest.json +14 -0
- package/app/plugins/workbuddy/plugin.mjs +24873 -0
- package/app/renderer-extension.js +5290 -3642
- 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",
|
|
@@ -15051,6 +15112,8 @@ var pluginPresentationShape = {
|
|
|
15051
15112
|
id: harnessPluginIdSchema,
|
|
15052
15113
|
name: external_exports.string().trim().min(1).max(128),
|
|
15053
15114
|
version: external_exports.string().min(1).max(128),
|
|
15115
|
+
/** The factory accepts a persisted local entrypoint through its construction context. */
|
|
15116
|
+
launchCommand: external_exports.literal(true).optional(),
|
|
15054
15117
|
links: external_exports.object({
|
|
15055
15118
|
documentation: documentationUrlSchema.optional(),
|
|
15056
15119
|
installation: documentationUrlSchema.optional()
|
|
@@ -15088,6 +15151,19 @@ var harnessPluginRouteSchema = external_exports.object({
|
|
|
15088
15151
|
permissionModeId: harnessPermissionModeIdSchema.optional()
|
|
15089
15152
|
}).strict();
|
|
15090
15153
|
|
|
15154
|
+
// ../../shared-contracts/dist/harness-launch-settings.js
|
|
15155
|
+
var harnessLaunchPathSchema = external_exports.string().trim().min(1).max(4096).refine((value) => !/[\u0000\r\n]/u.test(value), "Invalid entrypoint path");
|
|
15156
|
+
var harnessLaunchSettingsGetSchema = external_exports.object({
|
|
15157
|
+
harnessId: harnessPluginIdSchema
|
|
15158
|
+
}).strict();
|
|
15159
|
+
var harnessLaunchSettingsSetSchema = harnessLaunchSettingsGetSchema.extend({
|
|
15160
|
+
path: harnessLaunchPathSchema.nullable()
|
|
15161
|
+
});
|
|
15162
|
+
var harnessLaunchSettingsSchema = external_exports.object({
|
|
15163
|
+
path: harnessLaunchPathSchema.nullable(),
|
|
15164
|
+
restartRequired: external_exports.boolean()
|
|
15165
|
+
}).strict();
|
|
15166
|
+
|
|
15091
15167
|
// ../../shared-contracts/dist/codex-accounts.js
|
|
15092
15168
|
var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
|
|
15093
15169
|
var nonBlankTextSchema3 = external_exports.string().trim().min(1);
|
|
@@ -15375,149 +15451,1103 @@ var updateStatusResultSchema = external_exports.strictObject({
|
|
|
15375
15451
|
// ../../shared-contracts/dist/index.js
|
|
15376
15452
|
var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
|
|
15377
15453
|
|
|
15378
|
-
// dist/
|
|
15379
|
-
import
|
|
15380
|
-
import { link, open as open2, rm } from "node:fs/promises";
|
|
15454
|
+
// ../../harness-discovery/dist/environment.js
|
|
15455
|
+
import fs from "node:fs";
|
|
15381
15456
|
import path from "node:path";
|
|
15382
|
-
|
|
15383
|
-
|
|
15384
|
-
var PI_MODEL_REF_PREFIX = "pi-model-v1.";
|
|
15385
|
-
var PI_DRAFT_THINKING_OPTION_IDS = [
|
|
15386
|
-
"off",
|
|
15387
|
-
"minimal",
|
|
15388
|
-
"low",
|
|
15389
|
-
"medium",
|
|
15390
|
-
"high",
|
|
15391
|
-
"xhigh",
|
|
15392
|
-
"max"
|
|
15393
|
-
].map((id) => harnessThinkingOptionIdSchema.parse(id));
|
|
15394
|
-
var PI_THINKING_LABELS = {
|
|
15395
|
-
off: "Off",
|
|
15396
|
-
minimal: "Minimal",
|
|
15397
|
-
low: "Low",
|
|
15398
|
-
medium: "Medium",
|
|
15399
|
-
high: "High",
|
|
15400
|
-
xhigh: "Extra High",
|
|
15401
|
-
max: "Max"
|
|
15402
|
-
};
|
|
15403
|
-
function compareText(left, right) {
|
|
15404
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
15457
|
+
function targetPath(platform) {
|
|
15458
|
+
return platform === "win32" ? path.win32 : path.posix;
|
|
15405
15459
|
}
|
|
15406
|
-
function
|
|
15407
|
-
|
|
15408
|
-
|
|
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;
|
|
15409
15467
|
}
|
|
15410
|
-
function
|
|
15411
|
-
|
|
15412
|
-
assertNativePart(model.id, "Model id");
|
|
15413
|
-
const encoded = Buffer.from(JSON.stringify([model.provider, model.id]), "utf8").toString("base64url");
|
|
15414
|
-
return harnessModelRefSchema.parse({ id: `${PI_MODEL_REF_PREFIX}${encoded}` });
|
|
15468
|
+
function pathDelimiter(platform) {
|
|
15469
|
+
return platform === "win32" ? ";" : ":";
|
|
15415
15470
|
}
|
|
15416
|
-
function
|
|
15417
|
-
|
|
15418
|
-
|
|
15419
|
-
|
|
15420
|
-
|
|
15421
|
-
|
|
15422
|
-
|
|
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) {
|
|
15423
15482
|
try {
|
|
15424
|
-
|
|
15483
|
+
fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
|
|
15484
|
+
return fs.statSync(filePath).isFile();
|
|
15425
15485
|
} catch {
|
|
15426
|
-
|
|
15427
|
-
}
|
|
15428
|
-
if (!Array.isArray(decoded) || decoded.length !== 2 || typeof decoded[0] !== "string" || typeof decoded[1] !== "string") {
|
|
15429
|
-
throw new Error("Pi Model Ref has an invalid native identity");
|
|
15430
|
-
}
|
|
15431
|
-
const native = { provider: decoded[0], id: decoded[1] };
|
|
15432
|
-
assertNativePart(native.provider, "Model provider");
|
|
15433
|
-
assertNativePart(native.id, "Model id");
|
|
15434
|
-
if (encodePiModelRef(native).id !== parsedRef.id) {
|
|
15435
|
-
throw new Error("Pi Model Ref is not canonical");
|
|
15486
|
+
return false;
|
|
15436
15487
|
}
|
|
15437
|
-
return native;
|
|
15438
15488
|
}
|
|
15439
|
-
function
|
|
15440
|
-
|
|
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
|
+
}
|
|
15441
15495
|
}
|
|
15442
|
-
function
|
|
15443
|
-
|
|
15444
|
-
return label || id;
|
|
15496
|
+
function newestFirst(names) {
|
|
15497
|
+
return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
|
|
15445
15498
|
}
|
|
15446
|
-
|
|
15447
|
-
|
|
15448
|
-
|
|
15449
|
-
|
|
15450
|
-
|
|
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) };
|
|
15451
15512
|
}
|
|
15452
|
-
|
|
15453
|
-
|
|
15454
|
-
|
|
15455
|
-
|
|
15456
|
-
|
|
15457
|
-
|
|
15458
|
-
|
|
15459
|
-
|
|
15460
|
-
|
|
15461
|
-
|
|
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));
|
|
15462
15527
|
}
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
|
|
15466
|
-
|
|
15467
|
-
|
|
15468
|
-
|
|
15469
|
-
|
|
15470
|
-
|
|
15471
|
-
|
|
15472
|
-
|
|
15473
|
-
|
|
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;
|
|
15474
15541
|
}
|
|
15475
|
-
|
|
15476
|
-
|
|
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");
|
|
15477
15550
|
}
|
|
15478
|
-
|
|
15479
|
-
|
|
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
|
+
}
|
|
15480
15571
|
}
|
|
15481
|
-
|
|
15482
|
-
const allThinkingOptionIds = thinkingOptions.map(({ id }) => id);
|
|
15483
|
-
const offThinkingOptionId = thinkingOptions.find(({ id }) => id === "off")?.id;
|
|
15484
|
-
const models = [...byRef.values()].map(({ model, reasoning }) => ({
|
|
15485
|
-
...model,
|
|
15486
|
-
supportedThinkingOptionIds: reasoning ? allThinkingOptionIds : offThinkingOptionId ? [offThinkingOptionId] : []
|
|
15487
|
-
})).sort((left, right) => compareText(left.label, right.label) || compareText(left.ref.id, right.ref.id));
|
|
15488
|
-
const defaultThinkingOptionId = thinkingOptions.find(({ id }) => id === effectiveThinkingOptionId)?.id;
|
|
15489
|
-
return harnessModelCatalogSchema.parse({
|
|
15490
|
-
models,
|
|
15491
|
-
...defaultModel ? { defaultModel } : {},
|
|
15492
|
-
thinkingOptions,
|
|
15493
|
-
...defaultThinkingOptionId ? { defaultThinkingOptionId } : {}
|
|
15494
|
-
});
|
|
15572
|
+
return directories;
|
|
15495
15573
|
}
|
|
15496
15574
|
|
|
15497
|
-
// dist/
|
|
15498
|
-
var
|
|
15499
|
-
function
|
|
15500
|
-
return
|
|
15501
|
-
}
|
|
15502
|
-
function textContent(value) {
|
|
15503
|
-
if (typeof value === "string")
|
|
15504
|
-
return value;
|
|
15505
|
-
if (!Array.isArray(value))
|
|
15506
|
-
return "";
|
|
15507
|
-
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"] : [""];
|
|
15508
15579
|
}
|
|
15509
|
-
function
|
|
15510
|
-
|
|
15511
|
-
return "";
|
|
15512
|
-
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();
|
|
15513
15582
|
}
|
|
15514
|
-
function
|
|
15515
|
-
|
|
15516
|
-
|
|
15517
|
-
|
|
15518
|
-
|
|
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
|
+
};
|
|
15519
15591
|
}
|
|
15520
|
-
function
|
|
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) {
|
|
15521
16551
|
if (history.leafId === null)
|
|
15522
16552
|
return [];
|
|
15523
16553
|
const byId = new Map(history.entries.map((value) => {
|
|
@@ -15585,10 +16615,10 @@ function itemOutcome(outcome) {
|
|
|
15585
16615
|
return { status: "succeeded" };
|
|
15586
16616
|
}
|
|
15587
16617
|
function toolOutput(value) {
|
|
15588
|
-
const
|
|
15589
|
-
return
|
|
16618
|
+
const text2 = textContent(value);
|
|
16619
|
+
return text2.length > 0 ? { content: [{ type: "text", text: text2 }] } : void 0;
|
|
15590
16620
|
}
|
|
15591
|
-
function snapshotItems(entries, outcome) {
|
|
16621
|
+
function snapshotItems(entries, outcome, subagents) {
|
|
15592
16622
|
const snapshots = [];
|
|
15593
16623
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
15594
16624
|
for (const entry of entries) {
|
|
@@ -15597,7 +16627,7 @@ function snapshotItems(entries, outcome) {
|
|
|
15597
16627
|
continue;
|
|
15598
16628
|
const content = Array.isArray(nativeMessage.content) ? nativeMessage.content : [];
|
|
15599
16629
|
if (nativeMessage.role === "assistant") {
|
|
15600
|
-
const
|
|
16630
|
+
const text2 = textContent(content);
|
|
15601
16631
|
const reasoning = thinkingContent(content);
|
|
15602
16632
|
let projectedText = false;
|
|
15603
16633
|
let projectedReasoning = false;
|
|
@@ -15614,11 +16644,11 @@ function snapshotItems(entries, outcome) {
|
|
|
15614
16644
|
projectedReasoning = true;
|
|
15615
16645
|
continue;
|
|
15616
16646
|
}
|
|
15617
|
-
if (part.type === "text" && !projectedText &&
|
|
16647
|
+
if (part.type === "text" && !projectedText && text2.length > 0) {
|
|
15618
16648
|
const item2 = {
|
|
15619
16649
|
type: "agentMessage",
|
|
15620
16650
|
itemId: itemId(entry.id, "assistant", 0),
|
|
15621
|
-
text
|
|
16651
|
+
text: text2
|
|
15622
16652
|
};
|
|
15623
16653
|
snapshots.push({ item: item2, outcome: itemOutcome(outcome) });
|
|
15624
16654
|
projectedText = true;
|
|
@@ -15654,6 +16684,7 @@ function snapshotItems(entries, outcome) {
|
|
|
15654
16684
|
...output ? { output } : {}
|
|
15655
16685
|
};
|
|
15656
16686
|
const toolSucceeded = nativeMessage.isError === false;
|
|
16687
|
+
const delegation = subagents?.project(call.name, nativeMessage, itemId(call.entryId, "subagent", call.ordinal), nativeMessage.toolCallId);
|
|
15657
16688
|
snapshots.push({
|
|
15658
16689
|
item,
|
|
15659
16690
|
outcome: toolSucceeded ? { status: "succeeded" } : {
|
|
@@ -15665,16 +16696,18 @@ function snapshotItems(entries, outcome) {
|
|
|
15665
16696
|
}
|
|
15666
16697
|
}
|
|
15667
16698
|
});
|
|
16699
|
+
if (delegation)
|
|
16700
|
+
snapshots.push({ item: delegation, outcome: { status: "succeeded" } });
|
|
15668
16701
|
}
|
|
15669
16702
|
return snapshots;
|
|
15670
16703
|
}
|
|
15671
16704
|
function modelChange(entry) {
|
|
15672
16705
|
return entry.type === "model_change" && typeof entry.provider === "string" && typeof entry.modelId === "string" ? { provider: entry.provider, id: entry.modelId } : null;
|
|
15673
16706
|
}
|
|
15674
|
-
function mapPiSnapshot(history,
|
|
16707
|
+
function mapPiSnapshot(history, state2, subagents = new PiSubagents(() => void 0)) {
|
|
15675
16708
|
const active = activePiEntries(history);
|
|
15676
16709
|
const turns = [];
|
|
15677
|
-
let effectiveModel =
|
|
16710
|
+
let effectiveModel = state2.model;
|
|
15678
16711
|
for (let index = 0; index < active.length; ) {
|
|
15679
16712
|
const model = modelChange(active[index]);
|
|
15680
16713
|
if (model) {
|
|
@@ -15695,13 +16728,13 @@ function mapPiSnapshot(history, state) {
|
|
|
15695
16728
|
const userText = textContent(message(user)?.content);
|
|
15696
16729
|
const nativeTurnRef = nativeTurnRefSchema.parse({
|
|
15697
16730
|
harnessId: piHarnessId,
|
|
15698
|
-
nativeSessionId:
|
|
16731
|
+
nativeSessionId: state2.sessionId,
|
|
15699
16732
|
nativeTurnKey: user.id,
|
|
15700
16733
|
formatVersion: 1
|
|
15701
16734
|
});
|
|
15702
16735
|
const checkpoint = nativeCheckpointRefSchema.parse({
|
|
15703
16736
|
harnessId: piHarnessId,
|
|
15704
|
-
nativeSessionId:
|
|
16737
|
+
nativeSessionId: state2.sessionId,
|
|
15705
16738
|
checkpointId: user.id,
|
|
15706
16739
|
formatVersion: 1
|
|
15707
16740
|
});
|
|
@@ -15709,7 +16742,7 @@ function mapPiSnapshot(history, state) {
|
|
|
15709
16742
|
nativeTurnRef,
|
|
15710
16743
|
checkpoint,
|
|
15711
16744
|
input: [{ type: "text", text: userText }],
|
|
15712
|
-
items: snapshotItems(entries, outcome),
|
|
16745
|
+
items: snapshotItems(entries, outcome, subagents),
|
|
15713
16746
|
outcome,
|
|
15714
16747
|
...effectiveModel ? { model: encodePiModelRef(effectiveModel) } : {}
|
|
15715
16748
|
});
|
|
@@ -15740,7 +16773,7 @@ function resolvePiForkBoundary(history, checkpointId) {
|
|
|
15740
16773
|
}
|
|
15741
16774
|
|
|
15742
16775
|
// dist/pi-session-file.js
|
|
15743
|
-
import { open, realpath } from "node:fs/promises";
|
|
16776
|
+
import { open, realpath as realpath2 } from "node:fs/promises";
|
|
15744
16777
|
var MAX_SESSION_HEADER_BYTES = 64 * 1024;
|
|
15745
16778
|
var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
15746
16779
|
function isRecord2(value) {
|
|
@@ -15784,8 +16817,8 @@ async function verifyPiSessionCwd(input) {
|
|
|
15784
16817
|
throw new Error("Pi Fork Session header identity does not match RPC state");
|
|
15785
16818
|
}
|
|
15786
16819
|
const [actualCwd, expectedCwd] = await Promise.all([
|
|
15787
|
-
|
|
15788
|
-
|
|
16820
|
+
realpath2(header.cwd),
|
|
16821
|
+
realpath2(input.expectedCwd)
|
|
15789
16822
|
]);
|
|
15790
16823
|
if (actualCwd !== expectedCwd) {
|
|
15791
16824
|
throw new Error("Pi Fork Session did not bind the requested cwd");
|
|
@@ -15794,9 +16827,9 @@ async function verifyPiSessionCwd(input) {
|
|
|
15794
16827
|
|
|
15795
16828
|
// dist/pi-empty-session.js
|
|
15796
16829
|
async function persistEmptyPiSession(input) {
|
|
15797
|
-
const { state, history, sourceSessionFile, sourceSessionId, cwd } = input;
|
|
15798
|
-
const destination =
|
|
15799
|
-
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)
|
|
15800
16833
|
throw new Error("Pi empty Session is not an independent empty native fork");
|
|
15801
16834
|
await verifyPiSessionCwd({
|
|
15802
16835
|
sessionFile: sourceSessionFile,
|
|
@@ -15815,12 +16848,12 @@ async function persistEmptyPiSession(input) {
|
|
|
15815
16848
|
const header = {
|
|
15816
16849
|
type: "session",
|
|
15817
16850
|
version: 3,
|
|
15818
|
-
id:
|
|
16851
|
+
id: state2.sessionId,
|
|
15819
16852
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15820
16853
|
cwd,
|
|
15821
16854
|
parentSession: sourceSessionFile
|
|
15822
16855
|
};
|
|
15823
|
-
const temporary =
|
|
16856
|
+
const temporary = path4.join(path4.dirname(destination), `.codexhost-${randomUUID2()}.tmp`);
|
|
15824
16857
|
try {
|
|
15825
16858
|
const file2 = await open2(temporary, "wx", 384);
|
|
15826
16859
|
try {
|
|
@@ -15831,7 +16864,7 @@ async function persistEmptyPiSession(input) {
|
|
|
15831
16864
|
}
|
|
15832
16865
|
await link(temporary, destination);
|
|
15833
16866
|
if (process.platform !== "win32") {
|
|
15834
|
-
const directory = await open2(
|
|
16867
|
+
const directory = await open2(path4.dirname(destination), "r");
|
|
15835
16868
|
try {
|
|
15836
16869
|
await directory.sync();
|
|
15837
16870
|
} finally {
|
|
@@ -15994,16 +17027,16 @@ var Diff = class {
|
|
|
15994
17027
|
}
|
|
15995
17028
|
}
|
|
15996
17029
|
}
|
|
15997
|
-
addToPath(
|
|
15998
|
-
const last =
|
|
17030
|
+
addToPath(path10, added, removed, oldPosInc, options) {
|
|
17031
|
+
const last = path10.lastComponent;
|
|
15999
17032
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
16000
17033
|
return {
|
|
16001
|
-
oldPos:
|
|
17034
|
+
oldPos: path10.oldPos + oldPosInc,
|
|
16002
17035
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
16003
17036
|
};
|
|
16004
17037
|
} else {
|
|
16005
17038
|
return {
|
|
16006
|
-
oldPos:
|
|
17039
|
+
oldPos: path10.oldPos + oldPosInc,
|
|
16007
17040
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
16008
17041
|
};
|
|
16009
17042
|
}
|
|
@@ -16403,9 +17436,9 @@ function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader
|
|
|
16403
17436
|
} }));
|
|
16404
17437
|
}
|
|
16405
17438
|
}
|
|
16406
|
-
function splitLines(
|
|
16407
|
-
const hasTrailingNl =
|
|
16408
|
-
const result =
|
|
17439
|
+
function splitLines(text2) {
|
|
17440
|
+
const hasTrailingNl = text2.endsWith("\n");
|
|
17441
|
+
const result = text2.split("\n").map((line) => line + "\n");
|
|
16409
17442
|
if (hasTrailingNl) {
|
|
16410
17443
|
result.pop();
|
|
16411
17444
|
} else {
|
|
@@ -16415,8 +17448,8 @@ function splitLines(text) {
|
|
|
16415
17448
|
}
|
|
16416
17449
|
|
|
16417
17450
|
// dist/pi-adapter.js
|
|
16418
|
-
import { randomUUID as
|
|
16419
|
-
import
|
|
17451
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
17452
|
+
import path9 from "node:path";
|
|
16420
17453
|
|
|
16421
17454
|
// ../../harness-adapter/dist/question.js
|
|
16422
17455
|
function invalidRequest(message3) {
|
|
@@ -16593,558 +17626,499 @@ function parseHostUsage(value) {
|
|
|
16593
17626
|
if (hasContextWindow && value.contextWindowTokens === 0) {
|
|
16594
17627
|
throw new Error("Harness Usage 'contextWindowTokens' must be greater than zero");
|
|
16595
17628
|
}
|
|
16596
|
-
if (value.planFiveHourResetsAtUnix !== void 0 && value.planFiveHourUsedPercent === void 0) {
|
|
16597
|
-
throw new Error("Harness Usage 'planFiveHourResetsAtUnix' must be provided with 'planFiveHourUsedPercent'");
|
|
16598
|
-
}
|
|
16599
|
-
if (value.planSevenDayResetsAtUnix !== void 0 && value.planSevenDayUsedPercent === void 0) {
|
|
16600
|
-
throw new Error("Harness Usage 'planSevenDayResetsAtUnix' must be provided with 'planSevenDayUsedPercent'");
|
|
16601
|
-
}
|
|
16602
|
-
return { ...value };
|
|
16603
|
-
}
|
|
16604
|
-
|
|
16605
|
-
// dist/pi-last-turn-rollback.js
|
|
16606
|
-
function modelFromState(state) {
|
|
16607
|
-
if (state.provider === null && state.modelId === null)
|
|
16608
|
-
return null;
|
|
16609
|
-
if (state.provider === null || state.modelId === null) {
|
|
16610
|
-
throw new Error("Pi state contains a partial Model identity");
|
|
16611
|
-
}
|
|
16612
|
-
return { provider: state.provider, id: state.modelId };
|
|
16613
|
-
}
|
|
16614
|
-
async function rollbackPiLastTurn(transport, sourceSessionId, cwd) {
|
|
16615
|
-
const startupState = transport.state;
|
|
16616
|
-
const startupSessionId = startupState.sessionId;
|
|
16617
|
-
const currentModel = modelFromState(startupState);
|
|
16618
|
-
const currentThinking = startupState.thinkingLevel;
|
|
16619
|
-
const copiedHistory = await transport.getEntries();
|
|
16620
|
-
const boundary = resolvePiLastTurnBoundary(copiedHistory);
|
|
16621
|
-
if (!boundary)
|
|
16622
|
-
return { ok: false, reason: "empty" };
|
|
16623
|
-
const sourceSnapshot = mapPiSnapshot(copiedHistory, {
|
|
16624
|
-
sessionId: startupSessionId,
|
|
16625
|
-
model: currentModel
|
|
16626
|
-
});
|
|
16627
|
-
let state = await transport.fork(boundary.lastUserEntryId);
|
|
16628
|
-
if (state.sessionId === sourceSessionId || state.sessionId === startupSessionId) {
|
|
16629
|
-
throw new Error("Pi last-Turn rollback did not create a distinct Native Session");
|
|
16630
|
-
}
|
|
16631
|
-
if (!samePiModel(modelFromState(state), currentModel)) {
|
|
16632
|
-
if (!currentModel)
|
|
16633
|
-
throw new Error("Pi last-Turn rollback changed the current Model");
|
|
16634
|
-
state = await transport.selectModel(currentModel);
|
|
16635
|
-
}
|
|
16636
|
-
if (state.thinkingLevel !== currentThinking) {
|
|
16637
|
-
if (!currentThinking)
|
|
16638
|
-
throw new Error("Pi last-Turn rollback changed current Thinking");
|
|
16639
|
-
state = await transport.selectThinkingOption(currentThinking);
|
|
16640
|
-
}
|
|
16641
|
-
if (!samePiModel(modelFromState(state), currentModel) || state.thinkingLevel !== currentThinking) {
|
|
16642
|
-
throw new Error("Pi last-Turn rollback could not restore current Model and Thinking");
|
|
16643
|
-
}
|
|
16644
|
-
const snapshot = mapPiSnapshot(await transport.getEntries(), {
|
|
16645
|
-
sessionId: state.sessionId,
|
|
16646
|
-
model: modelFromState(state)
|
|
16647
|
-
});
|
|
16648
|
-
const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
|
|
16649
|
-
const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
|
|
16650
|
-
if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
|
|
16651
|
-
throw new Error("Pi last-Turn rollback did not produce the exact retained history prefix");
|
|
16652
|
-
}
|
|
16653
|
-
try {
|
|
16654
|
-
await transport.verifySessionCwd(cwd);
|
|
16655
|
-
return { ok: true, unpersisted: false };
|
|
16656
|
-
} catch (error51) {
|
|
16657
|
-
if (snapshot.turns.length === 0 && error51?.code === "ENOENT") {
|
|
16658
|
-
return { ok: true, unpersisted: true };
|
|
16659
|
-
}
|
|
16660
|
-
throw error51;
|
|
16661
|
-
}
|
|
16662
|
-
}
|
|
16663
|
-
|
|
16664
|
-
// dist/pi-session-import.js
|
|
16665
|
-
import { createReadStream as createReadStream2 } from "node:fs";
|
|
16666
|
-
import { opendir, realpath as realpath2, stat } from "node:fs/promises";
|
|
16667
|
-
import os from "node:os";
|
|
16668
|
-
import path2 from "node:path";
|
|
16669
|
-
import { createInterface as createInterface2 } from "node:readline";
|
|
16670
|
-
var PiSessionChangedError = class extends Error {
|
|
16671
|
-
constructor() {
|
|
16672
|
-
super("Pi Session changed during discovery; refresh and retry");
|
|
17629
|
+
if (value.planFiveHourResetsAtUnix !== void 0 && value.planFiveHourUsedPercent === void 0) {
|
|
17630
|
+
throw new Error("Harness Usage 'planFiveHourResetsAtUnix' must be provided with 'planFiveHourUsedPercent'");
|
|
16673
17631
|
}
|
|
16674
|
-
|
|
16675
|
-
|
|
16676
|
-
|
|
17632
|
+
if (value.planSevenDayResetsAtUnix !== void 0 && value.planSevenDayUsedPercent === void 0) {
|
|
17633
|
+
throw new Error("Harness Usage 'planSevenDayResetsAtUnix' must be provided with 'planSevenDayUsedPercent'");
|
|
17634
|
+
}
|
|
17635
|
+
return { ...value };
|
|
16677
17636
|
}
|
|
16678
|
-
|
|
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) {
|
|
16679
17644
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16680
17645
|
}
|
|
16681
|
-
|
|
16682
|
-
|
|
16683
|
-
|
|
16684
|
-
|
|
16685
|
-
|
|
16686
|
-
}
|
|
16687
|
-
function piSessionImportDirectory(environment) {
|
|
16688
|
-
const home = (process.platform === "win32" ? environment.USERPROFILE : environment.HOME) || os.homedir();
|
|
16689
|
-
const custom2 = environment.PI_CODING_AGENT_SESSION_DIR;
|
|
16690
|
-
if (custom2)
|
|
16691
|
-
return { directory: expandDirectory(custom2, home), flat: true };
|
|
16692
|
-
const agent = environment.PI_CODING_AGENT_DIR;
|
|
16693
|
-
return {
|
|
16694
|
-
directory: path2.join(agent ? expandDirectory(agent, home) : path2.join(home, ".pi", "agent"), "sessions"),
|
|
16695
|
-
flat: false
|
|
16696
|
-
};
|
|
16697
|
-
}
|
|
16698
|
-
async function sessionFiles(directory, flat, signal) {
|
|
16699
|
-
const files = [];
|
|
16700
|
-
const visit = async (dir, projectLevel) => {
|
|
16701
|
-
signal.throwIfAborted();
|
|
16702
|
-
const entries = await opendir(dir).catch((error51) => {
|
|
16703
|
-
if (missing(error51))
|
|
16704
|
-
return null;
|
|
16705
|
-
throw error51;
|
|
16706
|
-
});
|
|
16707
|
-
if (!entries)
|
|
16708
|
-
return;
|
|
16709
|
-
for await (const entry of entries) {
|
|
16710
|
-
signal.throwIfAborted();
|
|
16711
|
-
if (projectLevel && entry.isDirectory())
|
|
16712
|
-
await visit(path2.join(dir, entry.name), false);
|
|
16713
|
-
else if (!projectLevel && entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
16714
|
-
files.push(path2.join(dir, entry.name));
|
|
16715
|
-
}
|
|
16716
|
-
}
|
|
16717
|
-
};
|
|
16718
|
-
await visit(directory, !flat);
|
|
16719
|
-
return files;
|
|
16720
|
-
}
|
|
16721
|
-
async function readCandidate(file2, signal) {
|
|
16722
|
-
const before = await stat(file2);
|
|
16723
|
-
if (!before.isFile() || before.size === 0)
|
|
16724
|
-
return null;
|
|
16725
|
-
const stream = createReadStream2(file2, { encoding: "utf8", signal, end: before.size - 1 });
|
|
16726
|
-
const lines = createInterface2({ input: stream, crlfDelay: Infinity });
|
|
16727
|
-
let header;
|
|
16728
|
-
let name = null;
|
|
16729
|
-
let firstMessage = null;
|
|
16730
|
-
let hasUser = false;
|
|
16731
|
-
let updatedAt = before.mtimeMs;
|
|
16732
|
-
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));
|
|
16733
17651
|
try {
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
|
|
16737
|
-
|
|
16738
|
-
|
|
16739
|
-
|
|
16740
|
-
|
|
16741
|
-
|
|
16742
|
-
|
|
16743
|
-
|
|
16744
|
-
|
|
16745
|
-
|
|
16746
|
-
|
|
16747
|
-
|
|
16748
|
-
|
|
16749
|
-
|
|
16750
|
-
|
|
16751
|
-
|
|
16752
|
-
|
|
16753
|
-
|
|
16754
|
-
|
|
16755
|
-
|
|
16756
|
-
|
|
16757
|
-
const
|
|
16758
|
-
|
|
16759
|
-
|
|
16760
|
-
|
|
16761
|
-
|
|
16762
|
-
|
|
16763
|
-
|
|
16764
|
-
|
|
16765
|
-
|
|
16766
|
-
|
|
16767
|
-
|
|
16768
|
-
}
|
|
16769
|
-
}
|
|
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
|
+
};
|
|
16770
17686
|
} finally {
|
|
16771
|
-
|
|
16772
|
-
stream.destroy();
|
|
17687
|
+
await handle.close();
|
|
16773
17688
|
}
|
|
16774
|
-
if (!header)
|
|
16775
|
-
return null;
|
|
16776
|
-
if (!hasUser)
|
|
16777
|
-
return null;
|
|
16778
|
-
const after = await stat(file2);
|
|
16779
|
-
if (!sameFile(before, after))
|
|
16780
|
-
throw new PiSessionChangedError();
|
|
16781
|
-
const cwd = await realpath2(String(header.cwd));
|
|
16782
|
-
if (!(await stat(cwd)).isDirectory())
|
|
16783
|
-
return null;
|
|
16784
|
-
const nativeRef = nativeSessionRefSchema.safeParse({
|
|
16785
|
-
harnessId: "pi",
|
|
16786
|
-
nativeSessionId: header.id,
|
|
16787
|
-
locator: { sessionFile: await realpath2(file2) },
|
|
16788
|
-
formatVersion: 1
|
|
16789
|
-
});
|
|
16790
|
-
const candidate = harnessSessionImportCandidateSchema.safeParse({
|
|
16791
|
-
nativeSessionId: header.id,
|
|
16792
|
-
cwd,
|
|
16793
|
-
title: name ?? firstMessage,
|
|
16794
|
-
updatedAt: Math.floor(updatedAt),
|
|
16795
|
-
running: null
|
|
16796
|
-
});
|
|
16797
|
-
return candidate.success && nativeRef.success ? { candidate: candidate.data, nativeRef: nativeRef.data } : null;
|
|
16798
17689
|
}
|
|
16799
|
-
async function
|
|
16800
|
-
const
|
|
16801
|
-
|
|
16802
|
-
|
|
16803
|
-
|
|
16804
|
-
|
|
16805
|
-
|
|
16806
|
-
|
|
16807
|
-
|
|
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") {
|
|
16808
17709
|
try {
|
|
16809
|
-
|
|
17710
|
+
const snapshot = await childHistory(result.sessionFile, parentSessionId, id);
|
|
17711
|
+
if (snapshot.turns.length)
|
|
17712
|
+
return { ok: true, value: snapshot };
|
|
16810
17713
|
} catch {
|
|
16811
|
-
return null;
|
|
16812
17714
|
}
|
|
16813
|
-
return isRecord4(header) && header.type === "session" && header.version === 3 && typeof header.id === "string" ? header.id : null;
|
|
16814
17715
|
}
|
|
16815
|
-
|
|
16816
|
-
|
|
16817
|
-
|
|
16818
|
-
|
|
16819
|
-
|
|
16820
|
-
|
|
16821
|
-
|
|
16822
|
-
|
|
16823
|
-
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
|
|
16834
|
-
async #scan(signal) {
|
|
16835
|
-
const { directory, flat } = this.#location;
|
|
16836
|
-
const files = await sessionFiles(directory, flat, signal);
|
|
16837
|
-
const next = /* @__PURE__ */ new Map();
|
|
16838
|
-
const identities = /* @__PURE__ */ new Set();
|
|
16839
|
-
const sources = [];
|
|
16840
|
-
for (const file2 of files) {
|
|
16841
|
-
signal.throwIfAborted();
|
|
16842
|
-
try {
|
|
16843
|
-
const fingerprint = await stat(file2);
|
|
16844
|
-
const cached2 = this.#cache.get(file2);
|
|
16845
|
-
const source = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source : await readCandidate(file2, signal);
|
|
16846
|
-
if (!source)
|
|
16847
|
-
continue;
|
|
16848
|
-
if (!(await stat(source.candidate.cwd)).isDirectory())
|
|
16849
|
-
continue;
|
|
16850
|
-
if (identities.has(source.nativeRef.nativeSessionId))
|
|
16851
|
-
throw new Error("Pi Session identity is ambiguous across files");
|
|
16852
|
-
identities.add(source.nativeRef.nativeSessionId);
|
|
16853
|
-
next.set(file2, { fingerprint, source });
|
|
16854
|
-
sources.push(source);
|
|
16855
|
-
} catch (error51) {
|
|
16856
|
-
if (!missing(error51) && !(error51 instanceof PiSessionChangedError))
|
|
16857
|
-
throw error51;
|
|
16858
|
-
}
|
|
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
|
+
};
|
|
16859
17735
|
}
|
|
16860
|
-
|
|
16861
|
-
return structuredClone(sources.sort((left, right) => right.candidate.updatedAt - left.candidate.updatedAt));
|
|
17736
|
+
break;
|
|
16862
17737
|
}
|
|
16863
|
-
|
|
16864
|
-
|
|
16865
|
-
|
|
16866
|
-
|
|
16867
|
-
|
|
16868
|
-
|
|
16869
|
-
const fingerprint = await stat(file2);
|
|
16870
|
-
const cached2 = this.#cache.get(file2);
|
|
16871
|
-
const id = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source.nativeRef.nativeSessionId : await readIdentity(file2, signal);
|
|
16872
|
-
if (id !== nativeSessionId)
|
|
16873
|
-
continue;
|
|
16874
|
-
if (selected)
|
|
16875
|
-
throw new Error("Pi Session identity is ambiguous across files");
|
|
16876
|
-
selected = file2;
|
|
16877
|
-
} catch (error51) {
|
|
16878
|
-
if (!missing(error51))
|
|
16879
|
-
throw error51;
|
|
16880
|
-
}
|
|
16881
|
-
}
|
|
16882
|
-
if (!selected)
|
|
16883
|
-
return null;
|
|
16884
|
-
try {
|
|
16885
|
-
const source = await readCandidate(selected, signal);
|
|
16886
|
-
return source?.nativeRef.nativeSessionId === nativeSessionId ? source : null;
|
|
16887
|
-
} catch (error51) {
|
|
16888
|
-
if (missing(error51))
|
|
16889
|
-
return null;
|
|
16890
|
-
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
|
|
16891
17744
|
}
|
|
16892
|
-
}
|
|
16893
|
-
};
|
|
16894
|
-
|
|
16895
|
-
// dist/pi-rpc-session.js
|
|
16896
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
16897
|
-
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
16898
|
-
import path5 from "node:path";
|
|
16899
|
-
|
|
16900
|
-
// ../../harness-discovery/dist/environment.js
|
|
16901
|
-
import fs from "node:fs";
|
|
16902
|
-
import path3 from "node:path";
|
|
16903
|
-
function targetPath(platform) {
|
|
16904
|
-
return platform === "win32" ? path3.win32 : path3.posix;
|
|
16905
|
-
}
|
|
16906
|
-
function environmentValue(environment, name) {
|
|
16907
|
-
const lowered = name.toLowerCase();
|
|
16908
|
-
for (const [key, value] of Object.entries(environment)) {
|
|
16909
|
-
if (key.toLowerCase() === lowered)
|
|
16910
|
-
return value;
|
|
16911
|
-
}
|
|
16912
|
-
return void 0;
|
|
16913
|
-
}
|
|
16914
|
-
function pathDelimiter(platform) {
|
|
16915
|
-
return platform === "win32" ? ";" : ":";
|
|
17745
|
+
};
|
|
16916
17746
|
}
|
|
16917
|
-
|
|
16918
|
-
|
|
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);
|
|
16919
17754
|
}
|
|
16920
|
-
function
|
|
16921
|
-
|
|
16922
|
-
return [""];
|
|
16923
|
-
if (targetPath(platform).extname(command) !== "")
|
|
16924
|
-
return [""];
|
|
16925
|
-
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;
|
|
16926
17757
|
}
|
|
16927
|
-
function
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
|
|
16931
|
-
|
|
16932
|
-
|
|
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
|
+
});
|
|
16933
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
|
+
});
|
|
16934
17795
|
}
|
|
16935
|
-
function
|
|
16936
|
-
|
|
16937
|
-
|
|
16938
|
-
|
|
16939
|
-
|
|
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
|
+
}
|
|
16940
17825
|
}
|
|
16941
|
-
}
|
|
16942
|
-
function newestFirst(names) {
|
|
16943
|
-
return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
|
|
16944
17826
|
}
|
|
16945
17827
|
|
|
16946
|
-
//
|
|
16947
|
-
|
|
16948
|
-
|
|
16949
|
-
|
|
16950
|
-
|
|
16951
|
-
|
|
16952
|
-
const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
|
|
16953
|
-
const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
|
|
16954
|
-
if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
|
|
16955
|
-
directories.unshift(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");
|
|
16956
17834
|
}
|
|
16957
|
-
return {
|
|
17835
|
+
return { provider: state2.provider, id: state2.modelId };
|
|
16958
17836
|
}
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
|
|
16963
|
-
|
|
16964
|
-
|
|
16965
|
-
const
|
|
16966
|
-
|
|
16967
|
-
|
|
16968
|
-
const
|
|
16969
|
-
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
if (platform === "win32") {
|
|
16976
|
-
const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
|
|
16977
|
-
const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
|
|
16978
|
-
versioned(pathFlavor.join(appData, "nvm"));
|
|
16979
|
-
versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
|
|
16980
|
-
directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
|
|
16981
|
-
directories.push(pathFlavor.join(home, ".bun", "bin"));
|
|
16982
|
-
const pnpmHome2 = value("PNPM_HOME");
|
|
16983
|
-
if (pnpmHome2)
|
|
16984
|
-
directories.push(pnpmHome2);
|
|
16985
|
-
directories.push(pathFlavor.join(localAppData, "pnpm"));
|
|
16986
|
-
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");
|
|
16987
17853
|
}
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
pathFlavor.join(home, "Library", "Application Support", "fnm")
|
|
16993
|
-
].filter((root) => root !== void 0);
|
|
16994
|
-
for (const root of fnmRoots) {
|
|
16995
|
-
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);
|
|
16996
17858
|
}
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
|
|
17009
|
-
|
|
17010
|
-
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
|
|
17014
|
-
|
|
17015
|
-
|
|
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 };
|
|
17016
17882
|
}
|
|
17883
|
+
throw error51;
|
|
17017
17884
|
}
|
|
17018
|
-
return directories;
|
|
17019
17885
|
}
|
|
17020
17886
|
|
|
17021
|
-
//
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
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;
|
|
17025
17900
|
}
|
|
17026
|
-
function
|
|
17027
|
-
return
|
|
17901
|
+
function isRecord4(value) {
|
|
17902
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17028
17903
|
}
|
|
17029
|
-
function
|
|
17030
|
-
|
|
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;
|
|
17031
17916
|
return {
|
|
17032
|
-
|
|
17033
|
-
|
|
17034
|
-
APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
|
|
17035
|
-
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
|
|
17036
17919
|
};
|
|
17037
17920
|
}
|
|
17038
|
-
function
|
|
17039
|
-
const
|
|
17040
|
-
const
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
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;
|
|
17046
17943
|
}
|
|
17047
|
-
function
|
|
17048
|
-
const
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17053
|
-
|
|
17054
|
-
|
|
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
|
+
}
|
|
17055
17992
|
}
|
|
17056
|
-
|
|
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
|
|
17057
18012
|
});
|
|
17058
|
-
|
|
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;
|
|
17059
18021
|
}
|
|
17060
|
-
function
|
|
17061
|
-
const
|
|
17062
|
-
const
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17068
|
-
|
|
17069
|
-
|
|
17070
|
-
|
|
17071
|
-
|
|
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;
|
|
17072
18037
|
}
|
|
17073
|
-
|
|
17074
|
-
|
|
17075
|
-
|
|
18038
|
+
return null;
|
|
18039
|
+
} finally {
|
|
18040
|
+
lines.close();
|
|
18041
|
+
stream.destroy();
|
|
17076
18042
|
}
|
|
17077
|
-
return directories;
|
|
17078
18043
|
}
|
|
17079
|
-
|
|
17080
|
-
|
|
17081
|
-
|
|
17082
|
-
|
|
17083
|
-
|
|
17084
|
-
|
|
17085
|
-
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);
|
|
17086
18050
|
}
|
|
17087
|
-
|
|
17088
|
-
|
|
17089
|
-
|
|
17090
|
-
|
|
17091
|
-
|
|
17092
|
-
candidate: pathFlavor.join(directory, command + extension),
|
|
17093
|
-
source: "path"
|
|
17094
|
-
});
|
|
17095
|
-
}
|
|
18051
|
+
list(signal) {
|
|
18052
|
+
this.#listing ??= this.#scan(signal).finally(() => {
|
|
18053
|
+
this.#listing = void 0;
|
|
18054
|
+
});
|
|
18055
|
+
return this.#listing;
|
|
17096
18056
|
}
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
|
|
17100
|
-
|
|
17101
|
-
|
|
17102
|
-
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
|
|
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
|
+
}
|
|
17106
18082
|
}
|
|
18083
|
+
this.#cache = next;
|
|
18084
|
+
return structuredClone(sources.sort((left, right) => right.candidate.updatedAt - left.candidate.updatedAt));
|
|
17107
18085
|
}
|
|
17108
|
-
|
|
17109
|
-
}
|
|
17110
|
-
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
|
|
17133
|
-
|
|
17134
|
-
|
|
17135
|
-
|
|
17136
|
-
|
|
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
|
+
}
|
|
17137
18115
|
}
|
|
17138
18116
|
};
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {}
|
|
17145
|
-
}, { ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {} });
|
|
17146
|
-
return resolution?.executable ?? input.command ?? input.environment.PI_COMMAND ?? "pi";
|
|
17147
|
-
}
|
|
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";
|
|
17148
18122
|
|
|
17149
18123
|
// dist/pi-usage.js
|
|
17150
18124
|
function isRecord5(value) {
|
|
@@ -17217,6 +18191,82 @@ function optionalPiStateContextUsage(value) {
|
|
|
17217
18191
|
}
|
|
17218
18192
|
}
|
|
17219
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
|
+
|
|
17220
18270
|
// dist/pi-rpc-session.js
|
|
17221
18271
|
var PiRpcFaultError = class extends Error {
|
|
17222
18272
|
kind;
|
|
@@ -17348,15 +18398,15 @@ function extractReasoningText(content) {
|
|
|
17348
18398
|
return null;
|
|
17349
18399
|
const type = String(content.type ?? "");
|
|
17350
18400
|
if (type === "thinking" || type === "reasoning" || type === "thought") {
|
|
17351
|
-
const
|
|
17352
|
-
return typeof
|
|
18401
|
+
const text2 = content.thinking ?? content.reasoning ?? content.text ?? content.delta;
|
|
18402
|
+
return typeof text2 === "string" ? text2 : null;
|
|
17353
18403
|
}
|
|
17354
18404
|
return null;
|
|
17355
18405
|
}
|
|
17356
18406
|
function assistantReasoning(value) {
|
|
17357
18407
|
if (!isRecord6(value) || value.role !== "assistant" || !Array.isArray(value.content))
|
|
17358
18408
|
return null;
|
|
17359
|
-
return value.content.map(extractReasoningText).filter((
|
|
18409
|
+
return value.content.map(extractReasoningText).filter((text2) => typeof text2 === "string").join("");
|
|
17360
18410
|
}
|
|
17361
18411
|
function assistantFailure(value) {
|
|
17362
18412
|
if (!isRecord6(value) || value.role !== "assistant")
|
|
@@ -17421,7 +18471,7 @@ function piRpcProcessCommand(options, dependencies = {}) {
|
|
|
17421
18471
|
...thinkingArguments,
|
|
17422
18472
|
...sessionArguments
|
|
17423
18473
|
];
|
|
17424
|
-
const extension =
|
|
18474
|
+
const extension = path8.win32.extname(command).toLowerCase();
|
|
17425
18475
|
if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
|
|
17426
18476
|
return { command, arguments: arguments_, windowsVerbatimArguments: false };
|
|
17427
18477
|
}
|
|
@@ -17463,6 +18513,7 @@ var PiRpcSession = class {
|
|
|
17463
18513
|
#latestCacheHitRatePercent;
|
|
17464
18514
|
#manualCompaction = null;
|
|
17465
18515
|
#stderrTail = "";
|
|
18516
|
+
#subagents;
|
|
17466
18517
|
constructor(options, processAdapter = nodeProcessAdapter) {
|
|
17467
18518
|
if (options.sessionFile && options.forkSessionFile) {
|
|
17468
18519
|
throw new Error("Pi RPC cannot combine Session resume and Fork startup");
|
|
@@ -17477,6 +18528,7 @@ var PiRpcSession = class {
|
|
|
17477
18528
|
...options
|
|
17478
18529
|
};
|
|
17479
18530
|
this.#processAdapter = processAdapter;
|
|
18531
|
+
this.#subagents = new PiSubagentRpc((type, payload) => this.#send(type, payload), this.#options.commandTimeoutMs);
|
|
17480
18532
|
}
|
|
17481
18533
|
get state() {
|
|
17482
18534
|
if (!this.#state)
|
|
@@ -17486,6 +18538,12 @@ var PiRpcSession = class {
|
|
|
17486
18538
|
get stderrTail() {
|
|
17487
18539
|
return this.#stderrTail;
|
|
17488
18540
|
}
|
|
18541
|
+
setSubagentStatusHandler(handler) {
|
|
18542
|
+
this.#subagents.setHandler(handler);
|
|
18543
|
+
}
|
|
18544
|
+
inspectSubagent(id) {
|
|
18545
|
+
return this.#subagents.inspect(id);
|
|
18546
|
+
}
|
|
17489
18547
|
setAutonomousTurnHandler(handler) {
|
|
17490
18548
|
this.#autonomousTurnHandler = handler;
|
|
17491
18549
|
}
|
|
@@ -17655,13 +18713,13 @@ var PiRpcSession = class {
|
|
|
17655
18713
|
throw fault;
|
|
17656
18714
|
}
|
|
17657
18715
|
}
|
|
17658
|
-
async runTurn(
|
|
18716
|
+
async runTurn(text2, onEvent) {
|
|
17659
18717
|
if (!this.#child || !this.#state || this.#closed || this.#failed) {
|
|
17660
18718
|
throw new Error("Pi RPC Session is unavailable");
|
|
17661
18719
|
}
|
|
17662
18720
|
if (this.#activeTurn)
|
|
17663
18721
|
throw new Error("Pi RPC Session already has an active Turn");
|
|
17664
|
-
if (
|
|
18722
|
+
if (text2.length === 0)
|
|
17665
18723
|
throw new Error("Pi text Turn must not be empty");
|
|
17666
18724
|
const settled = new Promise((resolve, reject) => {
|
|
17667
18725
|
this.#activeTurn = {
|
|
@@ -17690,7 +18748,7 @@ var PiRpcSession = class {
|
|
|
17690
18748
|
};
|
|
17691
18749
|
});
|
|
17692
18750
|
try {
|
|
17693
|
-
await this.#send("prompt", { message:
|
|
18751
|
+
await this.#send("prompt", { message: text2 });
|
|
17694
18752
|
} catch (error51) {
|
|
17695
18753
|
this.#rejectActiveTurn(error51 instanceof Error ? error51 : new Error(message2(error51)));
|
|
17696
18754
|
}
|
|
@@ -17810,6 +18868,8 @@ var PiRpcSession = class {
|
|
|
17810
18868
|
this.#handleResponse(value);
|
|
17811
18869
|
return;
|
|
17812
18870
|
}
|
|
18871
|
+
if (this.#subagents.handle(value))
|
|
18872
|
+
return;
|
|
17813
18873
|
if (value.type === "compaction_start") {
|
|
17814
18874
|
this.#compactionActive = true;
|
|
17815
18875
|
this.#compactionTurn = this.#activeTurn;
|
|
@@ -17924,7 +18984,7 @@ var PiRpcSession = class {
|
|
|
17924
18984
|
const active = {
|
|
17925
18985
|
origin: "autonomous",
|
|
17926
18986
|
autonomousEvents: events,
|
|
17927
|
-
nativeTurnKey: assistantMessageId(value) ??
|
|
18987
|
+
nativeTurnKey: assistantMessageId(value) ?? randomUUID4(),
|
|
17928
18988
|
nativeCancellationObserved: false,
|
|
17929
18989
|
text: "",
|
|
17930
18990
|
assistantMessageId: null,
|
|
@@ -18106,13 +19166,13 @@ var PiRpcSession = class {
|
|
|
18106
19166
|
async #confirmSettledTurn(active) {
|
|
18107
19167
|
try {
|
|
18108
19168
|
const response = await this.#send("get_state", {});
|
|
18109
|
-
const
|
|
19169
|
+
const state2 = parseSessionState(response);
|
|
18110
19170
|
if (parseSessionStreaming(response)) {
|
|
18111
19171
|
throw new PiRpcFaultError("protocolError", "Pi RPC agent_settled state is still Streaming");
|
|
18112
19172
|
}
|
|
18113
19173
|
if (this.#activeTurn !== active)
|
|
18114
19174
|
return;
|
|
18115
|
-
this.#state =
|
|
19175
|
+
this.#state = state2;
|
|
18116
19176
|
active.settlement = "confirmed";
|
|
18117
19177
|
this.#finishSettledTurn(active);
|
|
18118
19178
|
} catch (error51) {
|
|
@@ -18167,7 +19227,7 @@ var PiRpcSession = class {
|
|
|
18167
19227
|
if (active.assistantMessageId !== null && active.reasoningMessageOpen) {
|
|
18168
19228
|
active.onEvent({ type: "reasoning.completed", messageId: active.assistantMessageId });
|
|
18169
19229
|
}
|
|
18170
|
-
const messageId = assistantMessageId(value) ??
|
|
19230
|
+
const messageId = assistantMessageId(value) ?? randomUUID4();
|
|
18171
19231
|
active.assistantMessageId = messageId;
|
|
18172
19232
|
active.sawStreamedMessageText = false;
|
|
18173
19233
|
active.sawStreamedMessageReasoning = false;
|
|
@@ -18228,7 +19288,7 @@ var PiRpcSession = class {
|
|
|
18228
19288
|
if (!child?.stdin.writable || this.#closed || this.#failed) {
|
|
18229
19289
|
return Promise.reject(new Error("Pi RPC stdin is unavailable"));
|
|
18230
19290
|
}
|
|
18231
|
-
const id = `codexhost-${
|
|
19291
|
+
const id = `codexhost-${randomUUID4()}`;
|
|
18232
19292
|
return new Promise((resolve, reject) => {
|
|
18233
19293
|
const pending = {
|
|
18234
19294
|
command: type,
|
|
@@ -18314,6 +19374,7 @@ var PiRpcSession = class {
|
|
|
18314
19374
|
}
|
|
18315
19375
|
}
|
|
18316
19376
|
#rejectAll(error51) {
|
|
19377
|
+
this.#subagents.close(error51);
|
|
18317
19378
|
for (const pending of this.#pending.values()) {
|
|
18318
19379
|
if (pending.timeout)
|
|
18319
19380
|
clearTimeout(pending.timeout);
|
|
@@ -18392,38 +19453,38 @@ function normalizedError(error51, fallbackCode) {
|
|
|
18392
19453
|
function invalidState(message3) {
|
|
18393
19454
|
return { code: "invalidState", message: message3, retryable: false };
|
|
18394
19455
|
}
|
|
18395
|
-
function nativeModelFromState(
|
|
18396
|
-
if (
|
|
19456
|
+
function nativeModelFromState(state2) {
|
|
19457
|
+
if (state2.provider === null && state2.modelId === null)
|
|
18397
19458
|
return null;
|
|
18398
|
-
if (
|
|
19459
|
+
if (state2.provider === null || state2.modelId === null) {
|
|
18399
19460
|
throw new PiRpcFaultError("protocolError", "Pi state contains a partial Model identity");
|
|
18400
19461
|
}
|
|
18401
|
-
return { provider:
|
|
19462
|
+
return { provider: state2.provider, id: state2.modelId };
|
|
18402
19463
|
}
|
|
18403
|
-
function effectiveModelFromState(
|
|
18404
|
-
const model = nativeModelFromState(
|
|
19464
|
+
function effectiveModelFromState(state2) {
|
|
19465
|
+
const model = nativeModelFromState(state2);
|
|
18405
19466
|
return model ? encodePiModelRef(model) : void 0;
|
|
18406
19467
|
}
|
|
18407
|
-
function harnessStateFromPi(
|
|
18408
|
-
const effectiveModel = effectiveModelFromState(
|
|
19468
|
+
function harnessStateFromPi(state2, thinkingLevels) {
|
|
19469
|
+
const effectiveModel = effectiveModelFromState(state2);
|
|
18409
19470
|
const availableThinkingOptions = thinkingLevels ? normalizePiThinkingOptions(thinkingLevels) : void 0;
|
|
18410
|
-
if (availableThinkingOptions && (!
|
|
19471
|
+
if (availableThinkingOptions && (!state2.thinkingLevel || !thinkingLevels?.includes(state2.thinkingLevel))) {
|
|
18411
19472
|
throw new PiRpcFaultError("protocolError", "Pi effective Thinking level is absent from its available levels");
|
|
18412
19473
|
}
|
|
18413
19474
|
return {
|
|
18414
19475
|
nativeRef: nativeSessionRefSchema.parse({
|
|
18415
19476
|
harnessId: piHarnessId2,
|
|
18416
|
-
nativeSessionId:
|
|
18417
|
-
...
|
|
19477
|
+
nativeSessionId: state2.sessionId,
|
|
19478
|
+
...state2.sessionFile ? { locator: { sessionFile: state2.sessionFile } } : {},
|
|
18418
19479
|
formatVersion: 1
|
|
18419
19480
|
}),
|
|
18420
19481
|
...effectiveModel ? { effectiveModel } : {},
|
|
18421
|
-
...
|
|
19482
|
+
...state2.thinkingLevel ? { effectiveThinkingOptionId: state2.thinkingLevel } : {},
|
|
18422
19483
|
...availableThinkingOptions ? { availableThinkingOptions } : {}
|
|
18423
19484
|
};
|
|
18424
19485
|
}
|
|
18425
|
-
function nativeModelForHistory(
|
|
18426
|
-
return nativeModelFromState(
|
|
19486
|
+
function nativeModelForHistory(state2) {
|
|
19487
|
+
return nativeModelFromState(state2);
|
|
18427
19488
|
}
|
|
18428
19489
|
function sessionFileFromRef(ref) {
|
|
18429
19490
|
if (ref.harnessId !== piHarnessId2 || !isRecord7(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
|
|
@@ -18443,20 +19504,20 @@ function nativeText(value) {
|
|
|
18443
19504
|
return value;
|
|
18444
19505
|
if (!isRecord7(value) || !Array.isArray(value.content))
|
|
18445
19506
|
return "";
|
|
18446
|
-
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("");
|
|
18447
19508
|
}
|
|
18448
19509
|
function boundedOutput(value, limit) {
|
|
18449
|
-
const
|
|
18450
|
-
if (
|
|
19510
|
+
const text2 = nativeText(value);
|
|
19511
|
+
if (text2.length === 0)
|
|
18451
19512
|
return void 0;
|
|
18452
|
-
const truncated =
|
|
19513
|
+
const truncated = text2.length > limit;
|
|
18453
19514
|
return {
|
|
18454
|
-
content: [{ type: "text", text: truncated ?
|
|
19515
|
+
content: [{ type: "text", text: truncated ? text2.slice(0, limit) : text2 }],
|
|
18455
19516
|
...truncated ? { truncated: true } : {}
|
|
18456
19517
|
};
|
|
18457
19518
|
}
|
|
18458
19519
|
function outputText(output) {
|
|
18459
|
-
return output?.content.filter((content) => content.type === "text").map(({ text }) =>
|
|
19520
|
+
return output?.content.filter((content) => content.type === "text").map(({ text: text2 }) => text2).join("") ?? "";
|
|
18460
19521
|
}
|
|
18461
19522
|
function stringField(value, key) {
|
|
18462
19523
|
if (!isRecord7(value))
|
|
@@ -18488,10 +19549,10 @@ function stripDiffPrefix(pathString) {
|
|
|
18488
19549
|
return pathString.startsWith("a/") || pathString.startsWith("b/") ? pathString.slice(2) : pathString;
|
|
18489
19550
|
}
|
|
18490
19551
|
function displayPath(nativePath, cwd) {
|
|
18491
|
-
const resolvedCwd =
|
|
18492
|
-
const resolvedPath =
|
|
18493
|
-
const relative =
|
|
18494
|
-
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}`);
|
|
18495
19556
|
const selected = inside ? relative : resolvedPath;
|
|
18496
19557
|
const normalized = selected.replaceAll("\\", "/");
|
|
18497
19558
|
if (normalized.length === 0 || normalized === ".")
|
|
@@ -18681,6 +19742,8 @@ var PiHarnessSession = class {
|
|
|
18681
19742
|
initialUsage;
|
|
18682
19743
|
outputs;
|
|
18683
19744
|
#channel = new HarnessOutputChannel();
|
|
19745
|
+
#subagents = new PiSubagents((event) => this.#event(event));
|
|
19746
|
+
#pendingSubagentStatus = null;
|
|
18684
19747
|
#closeTimeoutMs;
|
|
18685
19748
|
#createTransport;
|
|
18686
19749
|
#cwd;
|
|
@@ -18716,7 +19779,8 @@ var PiHarnessSession = class {
|
|
|
18716
19779
|
permissionModeScope: "live"
|
|
18717
19780
|
},
|
|
18718
19781
|
history: { fork: true, forkAcrossCwd: true, rollbackLastTurn: true },
|
|
18719
|
-
autonomousTurns: { observe: true }
|
|
19782
|
+
autonomousTurns: { observe: true },
|
|
19783
|
+
subagents: { observe: true, readTranscript: true }
|
|
18720
19784
|
};
|
|
18721
19785
|
this.commands = {
|
|
18722
19786
|
list: async () => ({ ok: true, value: piCommandCatalog }),
|
|
@@ -18731,6 +19795,24 @@ var PiHarnessSession = class {
|
|
|
18731
19795
|
if (this.#transport)
|
|
18732
19796
|
this.#bindAutonomousTurnHandler(this.#transport);
|
|
18733
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
|
+
}
|
|
18734
19816
|
handleTransportFault(error51) {
|
|
18735
19817
|
queueMicrotask(() => this.#fault(error51));
|
|
18736
19818
|
}
|
|
@@ -18751,13 +19833,14 @@ var PiHarnessSession = class {
|
|
|
18751
19833
|
try {
|
|
18752
19834
|
const transport = await this.#ensureTransport();
|
|
18753
19835
|
const history = await transport.getEntries();
|
|
19836
|
+
await restorePiSubagents(history, transport.state.sessionId, this.#subagents);
|
|
18754
19837
|
return {
|
|
18755
19838
|
ok: true,
|
|
18756
19839
|
value: {
|
|
18757
19840
|
...mapPiSnapshot(history, {
|
|
18758
19841
|
sessionId: transport.state.sessionId,
|
|
18759
19842
|
model: nativeModelForHistory(transport.state)
|
|
18760
|
-
}),
|
|
19843
|
+
}, this.#subagents),
|
|
18761
19844
|
state: this.#state
|
|
18762
19845
|
}
|
|
18763
19846
|
};
|
|
@@ -18797,8 +19880,8 @@ var PiHarnessSession = class {
|
|
|
18797
19880
|
}
|
|
18798
19881
|
};
|
|
18799
19882
|
}
|
|
18800
|
-
const
|
|
18801
|
-
if (
|
|
19883
|
+
const text2 = command.input.map((input) => input.text).join("\n");
|
|
19884
|
+
if (text2.length === 0) {
|
|
18802
19885
|
return {
|
|
18803
19886
|
ok: false,
|
|
18804
19887
|
error: {
|
|
@@ -18855,7 +19938,7 @@ var PiHarnessSession = class {
|
|
|
18855
19938
|
this.#active = active;
|
|
18856
19939
|
this.#event({ type: "turn.started", turnId: command.turnId });
|
|
18857
19940
|
this.#event({ type: "item.started", turnId: command.turnId, item });
|
|
18858
|
-
void transport.runTurn(
|
|
19941
|
+
void transport.runTurn(text2, (event) => this.#handleTurnEvent(active, event)).then(async (result) => {
|
|
18859
19942
|
try {
|
|
18860
19943
|
const identity = await this.#completedTurnIdentity(active, transport);
|
|
18861
19944
|
this.#completeTurn(active, result.cancelled ? {
|
|
@@ -18974,19 +20057,19 @@ var PiHarnessSession = class {
|
|
|
18974
20057
|
const previousModel = this.#state.effectiveModel;
|
|
18975
20058
|
this.#configuring = true;
|
|
18976
20059
|
try {
|
|
18977
|
-
let
|
|
20060
|
+
let state2;
|
|
18978
20061
|
let thinkingLevels;
|
|
18979
20062
|
try {
|
|
18980
|
-
|
|
20063
|
+
state2 = await transport.selectModel(requested);
|
|
18981
20064
|
thinkingLevels = await transport.getAvailableThinkingLevels();
|
|
18982
|
-
this.#publishTransportState(
|
|
20065
|
+
this.#publishTransportState(state2, thinkingLevels);
|
|
18983
20066
|
} catch (error51) {
|
|
18984
20067
|
if (error51 instanceof PiRpcFaultError)
|
|
18985
20068
|
this.#fault(error51);
|
|
18986
20069
|
return { ok: false, error: normalizedError(error51, "nativeFailure") };
|
|
18987
20070
|
}
|
|
18988
|
-
const actual = nativeModelFromState(
|
|
18989
|
-
const nextModel = effectiveModelFromState(
|
|
20071
|
+
const actual = nativeModelFromState(state2);
|
|
20072
|
+
const nextModel = effectiveModelFromState(state2);
|
|
18990
20073
|
if (previousModel?.id !== nextModel?.id) {
|
|
18991
20074
|
this.#invalidateUsage();
|
|
18992
20075
|
void this.#refreshUsage();
|
|
@@ -19048,10 +20131,10 @@ var PiHarnessSession = class {
|
|
|
19048
20131
|
const thinkingOptionId = parsedThinkingOptionId.data;
|
|
19049
20132
|
this.#configuring = true;
|
|
19050
20133
|
try {
|
|
19051
|
-
let
|
|
20134
|
+
let state2;
|
|
19052
20135
|
let thinkingLevels;
|
|
19053
20136
|
try {
|
|
19054
|
-
|
|
20137
|
+
state2 = await transport.selectThinkingOption(thinkingOptionId);
|
|
19055
20138
|
thinkingLevels = await transport.getAvailableThinkingLevels();
|
|
19056
20139
|
} catch (error51) {
|
|
19057
20140
|
if (error51 instanceof PiRpcFaultError)
|
|
@@ -19069,7 +20152,7 @@ var PiHarnessSession = class {
|
|
|
19069
20152
|
};
|
|
19070
20153
|
}
|
|
19071
20154
|
try {
|
|
19072
|
-
this.#publishTransportState(
|
|
20155
|
+
this.#publishTransportState(state2, thinkingLevels);
|
|
19073
20156
|
} catch (error51) {
|
|
19074
20157
|
if (error51 instanceof PiRpcFaultError)
|
|
19075
20158
|
this.#fault(error51);
|
|
@@ -19226,16 +20309,16 @@ var PiHarnessSession = class {
|
|
|
19226
20309
|
const starting = transport.start().then(async () => {
|
|
19227
20310
|
if (this.#phase !== "open")
|
|
19228
20311
|
throw new Error("Pi Session closed during startup");
|
|
19229
|
-
let
|
|
20312
|
+
let state2 = transport.state;
|
|
19230
20313
|
let thinkingLevels = await transport.getAvailableThinkingLevels();
|
|
19231
20314
|
if (this.#requestedModel) {
|
|
19232
20315
|
const requested = decodePiModelRef(this.#requestedModel);
|
|
19233
|
-
const current = nativeModelFromState(
|
|
20316
|
+
const current = nativeModelFromState(state2);
|
|
19234
20317
|
if (!samePiModel(current, requested))
|
|
19235
|
-
|
|
20318
|
+
state2 = await transport.selectModel(requested);
|
|
19236
20319
|
thinkingLevels = await transport.getAvailableThinkingLevels();
|
|
19237
|
-
if (!samePiModel(nativeModelFromState(
|
|
19238
|
-
this.#publishTransportState(
|
|
20320
|
+
if (!samePiModel(nativeModelFromState(state2), requested)) {
|
|
20321
|
+
this.#publishTransportState(state2, thinkingLevels);
|
|
19239
20322
|
throw new Error("Pi did not activate the requested create Model");
|
|
19240
20323
|
}
|
|
19241
20324
|
}
|
|
@@ -19247,11 +20330,11 @@ var PiHarnessSession = class {
|
|
|
19247
20330
|
retryable: false
|
|
19248
20331
|
});
|
|
19249
20332
|
}
|
|
19250
|
-
|
|
20333
|
+
state2 = await transport.selectThinkingOption(this.#requestedThinkingOptionId);
|
|
19251
20334
|
thinkingLevels = await transport.getAvailableThinkingLevels();
|
|
19252
20335
|
}
|
|
19253
20336
|
this.#transport = transport;
|
|
19254
|
-
this.#publishTransportState(
|
|
20337
|
+
this.#publishTransportState(state2, thinkingLevels);
|
|
19255
20338
|
this.#drainPendingAutonomousTurns(transport);
|
|
19256
20339
|
return transport;
|
|
19257
20340
|
}).catch(async (error51) => {
|
|
@@ -19268,6 +20351,14 @@ var PiHarnessSession = class {
|
|
|
19268
20351
|
return starting;
|
|
19269
20352
|
}
|
|
19270
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
|
+
});
|
|
19271
20362
|
transport.setAutonomousTurnHandler((turn) => {
|
|
19272
20363
|
if (this.#phase !== "open")
|
|
19273
20364
|
return;
|
|
@@ -19279,6 +20370,10 @@ var PiHarnessSession = class {
|
|
|
19279
20370
|
});
|
|
19280
20371
|
}
|
|
19281
20372
|
#drainPendingAutonomousTurns(transport) {
|
|
20373
|
+
if (this.#pendingSubagentStatus) {
|
|
20374
|
+
this.#subagents.observe(this.#pendingSubagentStatus);
|
|
20375
|
+
this.#pendingSubagentStatus = null;
|
|
20376
|
+
}
|
|
19282
20377
|
const pending = this.#pendingAutonomousTurns.filter((candidate) => candidate.transport === transport);
|
|
19283
20378
|
this.#pendingAutonomousTurns = this.#pendingAutonomousTurns.filter((candidate) => candidate.transport !== transport);
|
|
19284
20379
|
for (const candidate of pending) {
|
|
@@ -19306,7 +20401,7 @@ var PiHarnessSession = class {
|
|
|
19306
20401
|
}));
|
|
19307
20402
|
return;
|
|
19308
20403
|
}
|
|
19309
|
-
const turnId = hostTurnIdSchema.parse(
|
|
20404
|
+
const turnId = hostTurnIdSchema.parse(randomUUID5());
|
|
19310
20405
|
let resolveCompletion = () => void 0;
|
|
19311
20406
|
const completion = new Promise((resolve) => {
|
|
19312
20407
|
resolveCompletion = resolve;
|
|
@@ -19359,8 +20454,8 @@ var PiHarnessSession = class {
|
|
|
19359
20454
|
this.#fault(new PiAdapterFaultError(normalized));
|
|
19360
20455
|
}
|
|
19361
20456
|
}
|
|
19362
|
-
#publishTransportState(
|
|
19363
|
-
this.#state = harnessStateFromPi(
|
|
20457
|
+
#publishTransportState(state2, thinkingLevels) {
|
|
20458
|
+
this.#state = harnessStateFromPi(state2, thinkingLevels);
|
|
19364
20459
|
this.#event({ type: "session.state.changed", state: this.#state });
|
|
19365
20460
|
}
|
|
19366
20461
|
#invalidateUsage() {
|
|
@@ -19468,7 +20563,7 @@ var PiHarnessSession = class {
|
|
|
19468
20563
|
if (active.interactionByNativeId.has(request.requestId)) {
|
|
19469
20564
|
throw new Error("Pi Interaction started more than once");
|
|
19470
20565
|
}
|
|
19471
|
-
const interactionId = hostInteractionIdSchema.parse(
|
|
20566
|
+
const interactionId = hostInteractionIdSchema.parse(randomUUID5());
|
|
19472
20567
|
const question = request.method === "select" ? {
|
|
19473
20568
|
id: "answer",
|
|
19474
20569
|
type: "choice",
|
|
@@ -19547,16 +20642,16 @@ var PiHarnessSession = class {
|
|
|
19547
20642
|
active.agentMessageId = messageId;
|
|
19548
20643
|
active.sawAssistantMessage = true;
|
|
19549
20644
|
}
|
|
19550
|
-
#appendText(active,
|
|
20645
|
+
#appendText(active, text2) {
|
|
19551
20646
|
if (active.agentMessageId === null || !active.agentItem) {
|
|
19552
20647
|
throw new Error("Pi Assistant text arrived outside an active message");
|
|
19553
20648
|
}
|
|
19554
|
-
active.agentItem = { ...active.agentItem, text: active.agentItem.text +
|
|
20649
|
+
active.agentItem = { ...active.agentItem, text: active.agentItem.text + text2 };
|
|
19555
20650
|
this.#event({
|
|
19556
20651
|
type: "item.updated",
|
|
19557
20652
|
turnId: active.command.turnId,
|
|
19558
20653
|
itemId: active.agentItem.itemId,
|
|
19559
|
-
update: { type: "text.append", text }
|
|
20654
|
+
update: { type: "text.append", text: text2 }
|
|
19560
20655
|
});
|
|
19561
20656
|
}
|
|
19562
20657
|
#completeAgentItem(active, outcome, completeEmpty) {
|
|
@@ -19567,8 +20662,8 @@ var PiHarnessSession = class {
|
|
|
19567
20662
|
active.agentItem = null;
|
|
19568
20663
|
this.#completeItem(active, item, outcome);
|
|
19569
20664
|
}
|
|
19570
|
-
#appendReasoning(active,
|
|
19571
|
-
if (
|
|
20665
|
+
#appendReasoning(active, text2) {
|
|
20666
|
+
if (text2.length === 0)
|
|
19572
20667
|
return;
|
|
19573
20668
|
if (!active.reasoningItem) {
|
|
19574
20669
|
active.reasoningItem = {
|
|
@@ -19584,13 +20679,13 @@ var PiHarnessSession = class {
|
|
|
19584
20679
|
}
|
|
19585
20680
|
active.reasoningItem = {
|
|
19586
20681
|
...active.reasoningItem,
|
|
19587
|
-
text: active.reasoningItem.text +
|
|
20682
|
+
text: active.reasoningItem.text + text2
|
|
19588
20683
|
};
|
|
19589
20684
|
this.#event({
|
|
19590
20685
|
type: "item.updated",
|
|
19591
20686
|
turnId: active.command.turnId,
|
|
19592
20687
|
itemId: active.reasoningItem.itemId,
|
|
19593
|
-
update: { type: "text.append", text }
|
|
20688
|
+
update: { type: "text.append", text: text2 }
|
|
19594
20689
|
});
|
|
19595
20690
|
}
|
|
19596
20691
|
#completeReasoning(active, outcome) {
|
|
@@ -19627,6 +20722,7 @@ var PiHarnessSession = class {
|
|
|
19627
20722
|
const tool = active.tools.get(event.callId);
|
|
19628
20723
|
if (!tool)
|
|
19629
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);
|
|
19630
20726
|
const output = boundedOutput(event.output, this.#toolOutputLimit);
|
|
19631
20727
|
if (!output)
|
|
19632
20728
|
return;
|
|
@@ -19683,6 +20779,7 @@ var PiHarnessSession = class {
|
|
|
19683
20779
|
}
|
|
19684
20780
|
const outcome = active.cancellationRequested ? { status: "cancelled", reason: "Cancelled by user" } : event.isError ? { status: "failed", error: toolFailure(event.toolName) } : { status: "succeeded" };
|
|
19685
20781
|
this.#completeItem(active, tool.item, outcome);
|
|
20782
|
+
this.#subagents.start(active.command.turnId, event.toolName, event.result, this.#newItemId(), event.callId);
|
|
19686
20783
|
if (!event.isError) {
|
|
19687
20784
|
try {
|
|
19688
20785
|
const kind = fileMutatingKind(event.toolName);
|
|
@@ -19752,6 +20849,7 @@ var PiHarnessSession = class {
|
|
|
19752
20849
|
for (const tool of active.tools.values())
|
|
19753
20850
|
this.#completeItem(active, tool.item, itemOutcome2);
|
|
19754
20851
|
active.tools.clear();
|
|
20852
|
+
this.#subagents.finish(active.command.turnId);
|
|
19755
20853
|
if (!active.sawAssistantMessage && finalText !== void 0 && active.agentItem) {
|
|
19756
20854
|
active.agentItem = { ...active.agentItem, text: finalText };
|
|
19757
20855
|
}
|
|
@@ -19812,12 +20910,66 @@ var PiHarnessSession = class {
|
|
|
19812
20910
|
this.#channel.emit({ kind: "event", event });
|
|
19813
20911
|
}
|
|
19814
20912
|
#newItemId() {
|
|
19815
|
-
return hostItemIdSchema.parse(
|
|
20913
|
+
return hostItemIdSchema.parse(randomUUID5());
|
|
19816
20914
|
}
|
|
19817
20915
|
};
|
|
19818
20916
|
var PiAdapter = class {
|
|
20917
|
+
credentialImports;
|
|
19819
20918
|
commandCatalog = piCommandCatalog;
|
|
19820
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
|
+
};
|
|
19821
20973
|
sessionImport = Object.freeze({
|
|
19822
20974
|
listCandidates: async () => {
|
|
19823
20975
|
const result = await this.#readImport((signal) => this.#importIndex.list(signal));
|
|
@@ -19853,6 +21005,19 @@ var PiAdapter = class {
|
|
|
19853
21005
|
constructor(options = {}, dependencies = {
|
|
19854
21006
|
createTransport: (sessionOptions) => new PiRpcSession({ ...options, ...sessionOptions })
|
|
19855
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
|
+
};
|
|
19856
21021
|
this.#createTransport = dependencies.createTransport;
|
|
19857
21022
|
this.#importIndex = new PiSessionImportIndex({ ...process.env, ...options.environment });
|
|
19858
21023
|
this.#closeTimeoutMs = options.closeTimeoutMs ?? 2e3;
|
|
@@ -19930,7 +21095,8 @@ var PiAdapter = class {
|
|
|
19930
21095
|
permissionModeScope: "live"
|
|
19931
21096
|
},
|
|
19932
21097
|
history: { fork: true, forkAcrossCwd: true, rollbackLastTurn: true },
|
|
19933
|
-
autonomousTurns: { observe: true }
|
|
21098
|
+
autonomousTurns: { observe: true },
|
|
21099
|
+
subagents: { observe: true, readTranscript: true }
|
|
19934
21100
|
}
|
|
19935
21101
|
};
|
|
19936
21102
|
} catch (error51) {
|
|
@@ -20084,40 +21250,40 @@ var PiAdapter = class {
|
|
|
20084
21250
|
});
|
|
20085
21251
|
}
|
|
20086
21252
|
if (rolledBack.unpersisted) {
|
|
20087
|
-
const
|
|
21253
|
+
const state2 = transport.state;
|
|
20088
21254
|
const history = await transport.getEntries();
|
|
20089
21255
|
await transport.close();
|
|
20090
21256
|
await persistEmptyPiSession({
|
|
20091
|
-
state,
|
|
21257
|
+
state: state2,
|
|
20092
21258
|
history,
|
|
20093
21259
|
sourceSessionFile,
|
|
20094
21260
|
sourceSessionId: sourceRef.nativeSessionId,
|
|
20095
21261
|
cwd: input.cwd
|
|
20096
21262
|
});
|
|
20097
|
-
if (!
|
|
21263
|
+
if (!state2.sessionFile)
|
|
20098
21264
|
throw new Error("Pi empty fork has no Session file");
|
|
20099
|
-
const configuration = await readPiEmptySessionConfiguration(
|
|
21265
|
+
const configuration = await readPiEmptySessionConfiguration(state2.sessionFile);
|
|
20100
21266
|
if (!configuration)
|
|
20101
21267
|
throw new Error("Pi empty fork has no restorable configuration");
|
|
20102
21268
|
transport = this.#createTransport({
|
|
20103
21269
|
cwd: input.cwd,
|
|
20104
21270
|
...input.environment ? { environment: input.environment } : {},
|
|
20105
|
-
sessionFile:
|
|
21271
|
+
sessionFile: state2.sessionFile,
|
|
20106
21272
|
emptySessionConfiguration: configuration,
|
|
20107
21273
|
onFault: (error51) => session?.handleTransportFault(error51)
|
|
20108
21274
|
});
|
|
20109
21275
|
await transport.start();
|
|
20110
|
-
if (transport.state.sessionId !==
|
|
21276
|
+
if (transport.state.sessionId !== state2.sessionId) {
|
|
20111
21277
|
throw new Error("Pi empty fork resumed with a different identity");
|
|
20112
21278
|
}
|
|
20113
|
-
const model = nativeModelFromState(
|
|
21279
|
+
const model = nativeModelFromState(state2);
|
|
20114
21280
|
if (model && !samePiModel(nativeModelFromState(transport.state), model)) {
|
|
20115
21281
|
await transport.selectModel(model);
|
|
20116
21282
|
}
|
|
20117
|
-
if (
|
|
20118
|
-
await transport.selectThinkingOption(
|
|
21283
|
+
if (state2.thinkingLevel && transport.state.thinkingLevel !== state2.thinkingLevel) {
|
|
21284
|
+
await transport.selectThinkingOption(state2.thinkingLevel);
|
|
20119
21285
|
}
|
|
20120
|
-
if (!samePiModel(nativeModelFromState(transport.state), model) || transport.state.thinkingLevel !==
|
|
21286
|
+
if (!samePiModel(nativeModelFromState(transport.state), model) || transport.state.thinkingLevel !== state2.thinkingLevel) {
|
|
20121
21287
|
throw new Error("Pi empty fork could not restore its configuration");
|
|
20122
21288
|
}
|
|
20123
21289
|
await transport.verifySessionCwd(input.cwd);
|