@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.
@@ -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-empty-session.js
9
- import { createReadStream } from "node:fs";
10
- import { createInterface } from "node:readline";
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(object2, key, getter) {
740
+ function defineLazy(object3, key, getter) {
735
741
  let value = void 0;
736
- Object.defineProperty(object2, key, {
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(object2, key, {
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, path7) {
779
- if (!path7)
784
+ function getElementAtPath(obj, path10) {
785
+ if (!path10)
780
786
  return obj;
781
- return path7.reduce((acc, key) => acc?.[key], obj);
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(path7, issues) {
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(path7);
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, path7 = []) => {
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 }, [...path7, ...issue2.path]));
1350
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1345
1351
  } else if (issue2.code === "invalid_key") {
1346
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
1352
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1347
1353
  } else if (issue2.code === "invalid_element") {
1348
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
1354
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1349
1355
  } else {
1350
- const fullpath = [...path7, ...issue2.path];
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, path7 = []) => {
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 }, [...path7, ...issue2.path]));
1387
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1382
1388
  } else if (issue2.code === "invalid_key") {
1383
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
1389
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1384
1390
  } else if (issue2.code === "invalid_element") {
1385
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
1391
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1386
1392
  } else {
1387
- const fullpath = [...path7, ...issue2.path];
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 path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1420
- for (const seg of path7) {
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(token, algorithm = null) {
2679
+ function isValidJWT(token2, algorithm = null) {
2674
2680
  try {
2675
- const tokensParts = token.split(".");
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 = (text) => {
7651
- return text.charAt(0).toUpperCase() + text.slice(1);
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 path7 = ref.slice(1).split("/").filter(Boolean);
14113
- if (path7.length === 0) {
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 (path7[0] === defsKey) {
14118
- const key = path7[1];
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((state, context) => {
14923
- if (state.effectiveThinkingOptionId && state.availableThinkingOptions && !state.availableThinkingOptions.some(({ id }) => id === state.effectiveThinkingOptionId)) {
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/pi-empty-session.js
15379
- import { randomUUID } from "node:crypto";
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
- // dist/pi-model-catalog.js
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 assertNativePart(value, name) {
15407
- if (value.trim().length === 0)
15408
- throw new Error(`Pi ${name} must not be empty`);
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 encodePiModelRef(model) {
15411
- assertNativePart(model.provider, "Model provider");
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 decodePiModelRef(ref) {
15417
- const parsedRef = harnessModelRefSchema.parse(ref);
15418
- if (!parsedRef.id.startsWith(PI_MODEL_REF_PREFIX)) {
15419
- throw new Error("Model Ref does not belong to PiAdapter");
15420
- }
15421
- const encoded = parsedRef.id.slice(PI_MODEL_REF_PREFIX.length);
15422
- let decoded;
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
- decoded = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
15483
+ fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
15484
+ return fs.statSync(filePath).isFile();
15425
15485
  } catch {
15426
- throw new Error("Pi Model Ref is malformed");
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 samePiModel(left, right) {
15440
- return left === null ? right === null : right !== null && left.provider === right.provider && left.id === right.id;
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 fallbackThinkingLabel(id) {
15443
- const label = id.split(/[._~-]+/u).filter((part) => part.length > 0).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
15444
- return label || id;
15496
+ function newestFirst(names) {
15497
+ return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
15445
15498
  }
15446
- function normalizePiThinkingOptions(levels) {
15447
- return levels.map((id) => harnessThinkingOptionSchema.parse({
15448
- id,
15449
- label: PI_THINKING_LABELS[id] ?? fallbackThinkingLabel(id)
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
- function normalizePiModelCatalog(nativeModels, effectiveModel, thinkingLevels, effectiveThinkingOptionId) {
15453
- const byRef = /* @__PURE__ */ new Map();
15454
- for (const native of nativeModels) {
15455
- const ref = encodePiModelRef(native);
15456
- const existing = byRef.get(ref.id);
15457
- if (existing) {
15458
- if (existing.reasoning !== native.reasoning) {
15459
- throw new Error("Pi duplicate Model entries disagree on reasoning capability");
15460
- }
15461
- continue;
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
- byRef.set(ref.id, {
15464
- model: {
15465
- ref,
15466
- label: `${native.provider} / ${native.id}`
15467
- },
15468
- reasoning: native.reasoning
15469
- });
15470
- }
15471
- const defaultModel = effectiveModel ? encodePiModelRef(effectiveModel) : void 0;
15472
- if (defaultModel && !byRef.has(defaultModel.id)) {
15473
- throw new Error("Pi effective Model is absent from the available Model catalog");
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
- if (thinkingLevels && effectiveThinkingOptionId && !thinkingLevels.includes(effectiveThinkingOptionId)) {
15476
- throw new Error("Pi effective Thinking option is absent from the available option catalog");
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
- if (thinkingLevels && !effectiveThinkingOptionId) {
15479
- throw new Error("Pi did not report an effective Thinking option");
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
- const thinkingOptions = thinkingLevels ? normalizePiThinkingOptions(PI_DRAFT_THINKING_OPTION_IDS) : [];
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/pi-history.js
15498
- var piHarnessId = harnessIdSchema.parse("pi");
15499
- function isRecord(value) {
15500
- return typeof value === "object" && value !== null && !Array.isArray(value);
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 thinkingContent(value) {
15510
- if (!Array.isArray(value))
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 validatedEntry(value) {
15515
- if (typeof value.id !== "string" || value.id.length === 0 || value.parentId !== null && typeof value.parentId !== "string" || typeof value.type !== "string") {
15516
- throw new Error("Pi history contains an invalid Entry identity");
15517
- }
15518
- return value;
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 activePiEntries(history) {
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 text = textContent(value);
15589
- return text.length > 0 ? { content: [{ type: "text", text }] } : void 0;
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 text = textContent(content);
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 && text.length > 0) {
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, state) {
16707
+ function mapPiSnapshot(history, state2, subagents = new PiSubagents(() => void 0)) {
15675
16708
  const active = activePiEntries(history);
15676
16709
  const turns = [];
15677
- let effectiveModel = state.model;
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: state.sessionId,
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: state.sessionId,
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
- realpath(header.cwd),
15788
- realpath(input.expectedCwd)
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 = state.sessionFile;
15799
- if (!destination || !path.isAbsolute(destination) || path.resolve(destination) === path.resolve(sourceSessionFile) || state.sessionId === sourceSessionId || mapPiSnapshot(history, { sessionId: state.sessionId, model: null }).turns.length !== 0)
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: state.sessionId,
16851
+ id: state2.sessionId,
15819
16852
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
15820
16853
  cwd,
15821
16854
  parentSession: sourceSessionFile
15822
16855
  };
15823
- const temporary = path.join(path.dirname(destination), `.codexhost-${randomUUID()}.tmp`);
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(path.dirname(destination), "r");
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(path7, added, removed, oldPosInc, options) {
15998
- const last = path7.lastComponent;
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: path7.oldPos + oldPosInc,
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: path7.oldPos + oldPosInc,
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(text) {
16407
- const hasTrailingNl = text.endsWith("\n");
16408
- const result = text.split("\n").map((line) => line + "\n");
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 randomUUID3 } from "node:crypto";
16419
- import path6 from "node:path";
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
- function sameFile(left, right) {
16676
- return left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs && left.ino === right.ino && left.dev === right.dev;
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
- function isRecord4(value) {
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
- function missing(error51) {
16682
- return isRecord4(error51) && error51.code === "ENOENT";
16683
- }
16684
- function expandDirectory(value, home) {
16685
- return path2.resolve(value === "~" ? home : value.startsWith(`~${path2.sep}`) || value.startsWith("~/") ? path2.join(home, value.slice(2)) : value);
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
- for await (const line of lines) {
16735
- signal.throwIfAborted();
16736
- if (!line.trim())
16737
- continue;
16738
- let entry;
16739
- try {
16740
- entry = JSON.parse(line);
16741
- } catch {
16742
- return null;
16743
- }
16744
- if (!isRecord4(entry))
16745
- return null;
16746
- if (!header) {
16747
- if (entry.type !== "session" || entry.version !== 3 || typeof entry.id !== "string" || typeof entry.cwd !== "string" || !path2.isAbsolute(entry.cwd))
16748
- return null;
16749
- header = entry;
16750
- continue;
16751
- }
16752
- if (typeof entry.id !== "string" || entry.id.length === 0 || entries.has(entry.id) || entry.parentId !== null && (typeof entry.parentId !== "string" || !entries.has(entry.parentId)))
16753
- return null;
16754
- const message3 = isRecord4(entry.message) ? entry.message : null;
16755
- if (!firstMessage && entry.type === "message" && message3?.role === "user") {
16756
- const content = message3.content;
16757
- const text = typeof content === "string" ? content : Array.isArray(content) ? content.filter((block) => isRecord4(block) && block.type === "text" && typeof block.text === "string").map((block) => block.text).join(" ") : "";
16758
- firstMessage = text.replaceAll("\0", "").trim().slice(0, HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) || null;
16759
- }
16760
- hasUser = entry.type === "message" && message3?.role === "user" || typeof entry.parentId === "string" && entries.get(entry.parentId) === true;
16761
- entries.set(entry.id, hasUser);
16762
- if (entry.type === "session_info")
16763
- name = typeof entry.name === "string" ? entry.name.trim() || null : null;
16764
- if (entry.type === "message" && (message3?.role === "user" || message3?.role === "assistant")) {
16765
- const time3 = typeof message3.timestamp === "number" ? message3.timestamp : typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : NaN;
16766
- if (Number.isFinite(time3))
16767
- updatedAt = time3;
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
- lines.close();
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 readIdentity(file2, signal) {
16800
- const stream = createReadStream2(file2, { encoding: "utf8", signal });
16801
- const lines = createInterface2({ input: stream, crlfDelay: Infinity });
16802
- try {
16803
- for await (const line of lines) {
16804
- signal.throwIfAborted();
16805
- if (!line.trim())
16806
- continue;
16807
- let header;
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
- header = JSON.parse(line);
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
- return null;
16816
- } finally {
16817
- lines.close();
16818
- stream.destroy();
16819
- }
16820
- }
16821
- var PiSessionImportIndex = class {
16822
- #location;
16823
- #cache = /* @__PURE__ */ new Map();
16824
- #listing;
16825
- constructor(environment) {
16826
- this.#location = piSessionImportDirectory(environment);
16827
- }
16828
- list(signal) {
16829
- this.#listing ??= this.#scan(signal).finally(() => {
16830
- this.#listing = void 0;
16831
- });
16832
- return this.#listing;
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
- this.#cache = next;
16861
- return structuredClone(sources.sort((left, right) => right.candidate.updatedAt - left.candidate.updatedAt));
17736
+ break;
16862
17737
  }
16863
- async resolve(nativeSessionId, signal) {
16864
- const { directory, flat } = this.#location;
16865
- let selected;
16866
- for (const file2 of await sessionFiles(directory, flat, signal)) {
16867
- signal.throwIfAborted();
16868
- try {
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
- function pathDirectories(environment, platform) {
16918
- return (environmentValue(environment, "PATH") ?? "").split(pathDelimiter(platform)).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean);
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 executableExtensions(command, platform, environment) {
16921
- if (platform !== "win32")
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 isExecutableFile(filePath, platform) {
16928
- try {
16929
- fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
16930
- return fs.statSync(filePath).isFile();
16931
- } catch {
16932
- return false;
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 subdirectoryNames(directory) {
16936
- try {
16937
- return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
16938
- } catch {
16939
- return [];
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
- // ../../harness-discovery/dist/node-runtime.js
16947
- import path4 from "node:path";
16948
- function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
16949
- const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
16950
- const delimiter = platform === "win32" ? ";" : ":";
16951
- const runtimeDirectory = path4.dirname(runtimeExecutable);
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 { ...environment, [pathKey]: directories.join(delimiter) };
17835
+ return { provider: state2.provider, id: state2.modelId };
16958
17836
  }
16959
-
16960
- // ../../harness-discovery/dist/resolve.js
16961
- import os2 from "node:os";
16962
-
16963
- // ../../harness-discovery/dist/version-managers.js
16964
- function versionManagerBinaryDirectories(context) {
16965
- const { platform, environment, home } = context;
16966
- const list = context.subdirectories ?? subdirectoryNames;
16967
- const pathFlavor = targetPath(platform);
16968
- const value = (name) => environmentValue(environment, name);
16969
- const directories = [];
16970
- const versioned = (root, ...tail) => {
16971
- for (const version2 of newestFirst(list(root))) {
16972
- directories.push(pathFlavor.join(root, version2, ...tail));
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
- versioned(pathFlavor.join(value("NVM_DIR") ?? pathFlavor.join(home, ".nvm"), "versions", "node"), "bin");
16989
- const fnmRoots = [
16990
- value("FNM_DIR"),
16991
- pathFlavor.join(home, ".local", "share", "fnm"),
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
- const voltaHome = value("VOLTA_HOME") ?? pathFlavor.join(home, ".volta");
16998
- versioned(pathFlavor.join(voltaHome, "tools", "image", "node"), "bin");
16999
- directories.push(pathFlavor.join(voltaHome, "bin"));
17000
- const asdfHome = value("ASDF_DATA_DIR") ?? pathFlavor.join(home, ".asdf");
17001
- versioned(pathFlavor.join(asdfHome, "installs", "nodejs"), "bin");
17002
- directories.push(pathFlavor.join(asdfHome, "shims"));
17003
- const nodenvHome = value("NODENV_ROOT") ?? pathFlavor.join(home, ".nodenv");
17004
- versioned(pathFlavor.join(nodenvHome, "versions"), "bin");
17005
- directories.push(pathFlavor.join(nodenvHome, "shims"));
17006
- versioned(pathFlavor.join(value("N_PREFIX") ?? "/usr/local", "n", "versions", "node"), "bin");
17007
- directories.push(pathFlavor.join(home, ".bun", "bin"));
17008
- const pnpmHome = value("PNPM_HOME");
17009
- if (pnpmHome)
17010
- directories.push(pnpmHome);
17011
- directories.push(pathFlavor.join(home, "Library", "pnpm"));
17012
- directories.push(pathFlavor.join(home, ".local", "share", "pnpm"));
17013
- for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
17014
- for (const formula of newestFirst(list(prefix).filter((name) => name.startsWith("node@")))) {
17015
- directories.push(pathFlavor.join(prefix, formula, "bin"));
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
- // ../../harness-discovery/dist/resolve.js
17022
- var VERSION_MANAGER_ROOTS = "<version-managers>";
17023
- function installRootExtensions(platform) {
17024
- return platform === "win32" ? [".exe", ".cmd"] : [""];
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 resolveHomeDirectory(input) {
17027
- return input.homeDirectory ?? environmentValue(input.environment, "HOME") ?? environmentValue(input.environment, "USERPROFILE") ?? os2.homedir();
17901
+ function isRecord4(value) {
17902
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17028
17903
  }
17029
- function templateVariables(environment, platform, home) {
17030
- const pathFlavor = targetPath(platform);
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
- HOME: home,
17033
- USERPROFILE: home,
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 joinTemplate(platform, value) {
17039
- const pathFlavor = targetPath(platform);
17040
- const segments = value.split("/");
17041
- const head = segments[0] ?? "";
17042
- const tail = segments.slice(1);
17043
- if (head === "")
17044
- return pathFlavor.join(pathFlavor.sep, ...tail);
17045
- return tail.length === 0 ? head : pathFlavor.join(head, ...tail);
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 expandInstallRoot(template, environment, platform, home) {
17048
- const variables = templateVariables(environment, platform, home);
17049
- let unresolved = false;
17050
- const substituted = template.replace(/^~(?=\/|$)/u, home).replace(/\$\{(\w+)\}/gu, (_match, name) => {
17051
- const value = variables[name] ?? environmentValue(environment, name);
17052
- if (value === void 0 || value === "") {
17053
- unresolved = true;
17054
- return "";
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
- return value;
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
- return unresolved ? void 0 : joinTemplate(platform, substituted);
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 installRootDirectories(spec, input, dependencies, platform, home) {
17061
- const templates = (platform === "win32" ? spec.installRoots?.windows : spec.installRoots?.posix) ?? [];
17062
- const directories = [];
17063
- for (const template of templates) {
17064
- if (template === VERSION_MANAGER_ROOTS) {
17065
- directories.push(...versionManagerBinaryDirectories({
17066
- platform,
17067
- environment: input.environment,
17068
- home,
17069
- ...dependencies.subdirectories ? { subdirectories: dependencies.subdirectories } : {}
17070
- }));
17071
- continue;
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
- const directory = expandInstallRoot(template, input.environment, platform, home);
17074
- if (directory !== void 0)
17075
- directories.push(directory);
18038
+ return null;
18039
+ } finally {
18040
+ lines.close();
18041
+ stream.destroy();
17076
18042
  }
17077
- return directories;
17078
18043
  }
17079
- function harnessCandidates(spec, input, dependencies = {}) {
17080
- const platform = input.platform ?? process.platform;
17081
- const pathFlavor = targetPath(platform);
17082
- const configured = input.command ?? (spec.commandEnvironmentVariable ? environmentValue(input.environment, spec.commandEnvironmentVariable) : void 0);
17083
- const command = configured ?? spec.command;
17084
- if (pathFlavor.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
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
- const candidates = [];
17088
- const extensions = executableExtensions(command, platform, input.environment);
17089
- for (const directory of pathDirectories(input.environment, platform)) {
17090
- for (const extension of extensions) {
17091
- candidates.push({
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
- if (configured !== void 0)
17098
- return candidates;
17099
- const home = resolveHomeDirectory(input);
17100
- for (const directory of installRootDirectories(spec, input, dependencies, platform, home)) {
17101
- for (const extension of installRootExtensions(platform)) {
17102
- candidates.push({
17103
- candidate: pathFlavor.join(directory, spec.command + extension),
17104
- source: "install-root"
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
- return candidates;
17109
- }
17110
- function resolveHarnessExecutable(spec, input, dependencies = {}) {
17111
- const platform = input.platform ?? process.platform;
17112
- const isExecutable = dependencies.isExecutable ?? ((candidate) => isExecutableFile(candidate, platform));
17113
- const runnable = spec.runnableCandidate ?? ((candidate) => candidate);
17114
- const context = { platform, isExecutable };
17115
- for (const { candidate, source } of harnessCandidates(spec, input, dependencies)) {
17116
- const executable = runnable(candidate, context);
17117
- if (executable !== void 0 && isExecutable(executable))
17118
- return { executable, source };
17119
- }
17120
- return void 0;
17121
- }
17122
-
17123
- // dist/command.js
17124
- var piDiscoverySpec = {
17125
- id: "pi",
17126
- command: "pi",
17127
- commandEnvironmentVariable: "PI_COMMAND",
17128
- installRoots: {
17129
- posix: [
17130
- "~/.npm-global/bin",
17131
- "~/.local/bin",
17132
- VERSION_MANAGER_ROOTS,
17133
- "/opt/homebrew/bin",
17134
- "/usr/local/bin"
17135
- ],
17136
- windows: ["${APPDATA}/npm", "~/.local/bin", VERSION_MANAGER_ROOTS]
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
- function resolvePiExecutable(input, dependencies = {}) {
17140
- const resolution = resolveHarnessExecutable(piDiscoverySpec, {
17141
- ...input.command ? { command: input.command } : {},
17142
- environment: input.environment,
17143
- ...dependencies.platform ? { platform: dependencies.platform } : {},
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 text = content.thinking ?? content.reasoning ?? content.text ?? content.delta;
17352
- return typeof text === "string" ? text : null;
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((text) => typeof text === "string").join("");
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 = path5.win32.extname(command).toLowerCase();
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(text, onEvent) {
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 (text.length === 0)
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: text });
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) ?? randomUUID2(),
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 state = parseSessionState(response);
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 = 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) ?? randomUUID2();
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-${randomUUID2()}`;
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(state) {
18396
- if (state.provider === null && state.modelId === null)
19456
+ function nativeModelFromState(state2) {
19457
+ if (state2.provider === null && state2.modelId === null)
18397
19458
  return null;
18398
- if (state.provider === null || state.modelId === null) {
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: state.provider, id: state.modelId };
19462
+ return { provider: state2.provider, id: state2.modelId };
18402
19463
  }
18403
- function effectiveModelFromState(state) {
18404
- const model = nativeModelFromState(state);
19464
+ function effectiveModelFromState(state2) {
19465
+ const model = nativeModelFromState(state2);
18405
19466
  return model ? encodePiModelRef(model) : void 0;
18406
19467
  }
18407
- function harnessStateFromPi(state, thinkingLevels) {
18408
- const effectiveModel = effectiveModelFromState(state);
19468
+ function harnessStateFromPi(state2, thinkingLevels) {
19469
+ const effectiveModel = effectiveModelFromState(state2);
18409
19470
  const availableThinkingOptions = thinkingLevels ? normalizePiThinkingOptions(thinkingLevels) : void 0;
18410
- if (availableThinkingOptions && (!state.thinkingLevel || !thinkingLevels?.includes(state.thinkingLevel))) {
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: state.sessionId,
18417
- ...state.sessionFile ? { locator: { sessionFile: state.sessionFile } } : {},
19477
+ nativeSessionId: state2.sessionId,
19478
+ ...state2.sessionFile ? { locator: { sessionFile: state2.sessionFile } } : {},
18418
19479
  formatVersion: 1
18419
19480
  }),
18420
19481
  ...effectiveModel ? { effectiveModel } : {},
18421
- ...state.thinkingLevel ? { effectiveThinkingOptionId: state.thinkingLevel } : {},
19482
+ ...state2.thinkingLevel ? { effectiveThinkingOptionId: state2.thinkingLevel } : {},
18422
19483
  ...availableThinkingOptions ? { availableThinkingOptions } : {}
18423
19484
  };
18424
19485
  }
18425
- function nativeModelForHistory(state) {
18426
- return nativeModelFromState(state);
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 }) => text).join("");
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 text = nativeText(value);
18450
- if (text.length === 0)
19510
+ const text2 = nativeText(value);
19511
+ if (text2.length === 0)
18451
19512
  return void 0;
18452
- const truncated = text.length > limit;
19513
+ const truncated = text2.length > limit;
18453
19514
  return {
18454
- content: [{ type: "text", text: truncated ? text.slice(0, limit) : text }],
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 }) => text).join("") ?? "";
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 = path6.resolve(cwd);
18492
- const resolvedPath = path6.isAbsolute(nativePath) ? path6.resolve(nativePath) : path6.resolve(cwd, nativePath);
18493
- const relative = path6.relative(resolvedCwd, resolvedPath);
18494
- const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path6.sep}`);
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 text = command.input.map((input) => input.text).join("\n");
18801
- if (text.length === 0) {
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(text, (event) => this.#handleTurnEvent(active, event)).then(async (result) => {
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 state;
20060
+ let state2;
18978
20061
  let thinkingLevels;
18979
20062
  try {
18980
- state = await transport.selectModel(requested);
20063
+ state2 = await transport.selectModel(requested);
18981
20064
  thinkingLevels = await transport.getAvailableThinkingLevels();
18982
- this.#publishTransportState(state, thinkingLevels);
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(state);
18989
- const nextModel = effectiveModelFromState(state);
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 state;
20134
+ let state2;
19052
20135
  let thinkingLevels;
19053
20136
  try {
19054
- state = await transport.selectThinkingOption(thinkingOptionId);
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(state, thinkingLevels);
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 state = transport.state;
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(state);
20316
+ const current = nativeModelFromState(state2);
19234
20317
  if (!samePiModel(current, requested))
19235
- state = await transport.selectModel(requested);
20318
+ state2 = await transport.selectModel(requested);
19236
20319
  thinkingLevels = await transport.getAvailableThinkingLevels();
19237
- if (!samePiModel(nativeModelFromState(state), requested)) {
19238
- this.#publishTransportState(state, thinkingLevels);
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
- state = await transport.selectThinkingOption(this.#requestedThinkingOptionId);
20333
+ state2 = await transport.selectThinkingOption(this.#requestedThinkingOptionId);
19251
20334
  thinkingLevels = await transport.getAvailableThinkingLevels();
19252
20335
  }
19253
20336
  this.#transport = transport;
19254
- this.#publishTransportState(state, thinkingLevels);
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(randomUUID3());
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(state, thinkingLevels) {
19363
- this.#state = harnessStateFromPi(state, thinkingLevels);
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(randomUUID3());
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, text) {
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 + 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, text) {
19571
- if (text.length === 0)
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 + 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(randomUUID3());
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 state = transport.state;
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 (!state.sessionFile)
21263
+ if (!state2.sessionFile)
20098
21264
  throw new Error("Pi empty fork has no Session file");
20099
- const configuration = await readPiEmptySessionConfiguration(state.sessionFile);
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: state.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 !== 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(state);
21279
+ const model = nativeModelFromState(state2);
20114
21280
  if (model && !samePiModel(nativeModelFromState(transport.state), model)) {
20115
21281
  await transport.selectModel(model);
20116
21282
  }
20117
- if (state.thinkingLevel && transport.state.thinkingLevel !== state.thinkingLevel) {
20118
- await transport.selectThinkingOption(state.thinkingLevel);
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 !== 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);