@liberseek/boft-cli-win32-arm64 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
 
@@ -14938,8 +14999,8 @@ var harnessConfigurationStateSchema = external_exports.object({
14938
14999
  effectiveThinkingOptionId: harnessThinkingOptionIdSchema.optional(),
14939
15000
  availableThinkingOptions: harnessThinkingOptionsSchema.optional(),
14940
15001
  effectivePermissionModeId: harnessPermissionModeIdSchema.optional()
14941
- }).strict().superRefine((state, context) => {
14942
- if (state.effectiveThinkingOptionId && state.availableThinkingOptions && !state.availableThinkingOptions.some(({ id }) => id === state.effectiveThinkingOptionId)) {
15002
+ }).strict().superRefine((state2, context) => {
15003
+ if (state2.effectiveThinkingOptionId && state2.availableThinkingOptions && !state2.availableThinkingOptions.some(({ id }) => id === state2.effectiveThinkingOptionId)) {
14943
15004
  context.addIssue({
14944
15005
  code: "custom",
14945
15006
  message: "Effective Thinking option must be currently available",
@@ -15072,6 +15133,8 @@ var pluginPresentationShape = {
15072
15133
  id: harnessPluginIdSchema,
15073
15134
  name: external_exports.string().trim().min(1).max(128),
15074
15135
  version: external_exports.string().min(1).max(128),
15136
+ /** The factory accepts a persisted local entrypoint through its construction context. */
15137
+ launchCommand: external_exports.literal(true).optional(),
15075
15138
  links: external_exports.object({
15076
15139
  documentation: documentationUrlSchema.optional(),
15077
15140
  installation: documentationUrlSchema.optional()
@@ -15109,6 +15172,19 @@ var harnessPluginRouteSchema = external_exports.object({
15109
15172
  permissionModeId: harnessPermissionModeIdSchema.optional()
15110
15173
  }).strict();
15111
15174
 
15175
+ // ../../shared-contracts/dist/harness-launch-settings.js
15176
+ var harnessLaunchPathSchema = external_exports.string().trim().min(1).max(4096).refine((value) => !/[\u0000\r\n]/u.test(value), "Invalid entrypoint path");
15177
+ var harnessLaunchSettingsGetSchema = external_exports.object({
15178
+ harnessId: harnessPluginIdSchema
15179
+ }).strict();
15180
+ var harnessLaunchSettingsSetSchema = harnessLaunchSettingsGetSchema.extend({
15181
+ path: harnessLaunchPathSchema.nullable()
15182
+ });
15183
+ var harnessLaunchSettingsSchema = external_exports.object({
15184
+ path: harnessLaunchPathSchema.nullable(),
15185
+ restartRequired: external_exports.boolean()
15186
+ }).strict();
15187
+
15112
15188
  // ../../shared-contracts/dist/codex-accounts.js
15113
15189
  var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
15114
15190
  var nonBlankTextSchema3 = external_exports.string().trim().min(1);
@@ -15399,149 +15475,1103 @@ var updateStatusResultSchema = external_exports.strictObject({
15399
15475
  // ../../shared-contracts/dist/index.js
15400
15476
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
15401
15477
 
15402
- // dist/pi-empty-session.js
15403
- import { randomUUID } from "node:crypto";
15404
- import { link, open as open2, rm } from "node:fs/promises";
15478
+ // ../../harness-discovery/dist/environment.js
15479
+ import fs from "node:fs";
15405
15480
  import path from "node:path";
15406
-
15407
- // dist/pi-model-catalog.js
15408
- var PI_MODEL_REF_PREFIX = "pi-model-v1.";
15409
- var PI_DRAFT_THINKING_OPTION_IDS = [
15410
- "off",
15411
- "minimal",
15412
- "low",
15413
- "medium",
15414
- "high",
15415
- "xhigh",
15416
- "max"
15417
- ].map((id) => harnessThinkingOptionIdSchema.parse(id));
15418
- var PI_THINKING_LABELS = {
15419
- off: "Off",
15420
- minimal: "Minimal",
15421
- low: "Low",
15422
- medium: "Medium",
15423
- high: "High",
15424
- xhigh: "Extra High",
15425
- max: "Max"
15426
- };
15427
- function compareText(left, right) {
15428
- return left < right ? -1 : left > right ? 1 : 0;
15481
+ function targetPath(platform) {
15482
+ return platform === "win32" ? path.win32 : path.posix;
15429
15483
  }
15430
- function assertNativePart(value, name) {
15431
- if (value.trim().length === 0)
15432
- throw new Error(`Pi ${name} must not be empty`);
15484
+ function environmentValue(environment, name) {
15485
+ const lowered = name.toLowerCase();
15486
+ for (const [key, value] of Object.entries(environment)) {
15487
+ if (key.toLowerCase() === lowered)
15488
+ return value;
15489
+ }
15490
+ return void 0;
15433
15491
  }
15434
- function encodePiModelRef(model) {
15435
- assertNativePart(model.provider, "Model provider");
15436
- assertNativePart(model.id, "Model id");
15437
- const encoded = Buffer.from(JSON.stringify([model.provider, model.id]), "utf8").toString("base64url");
15438
- return harnessModelRefSchema.parse({ id: `${PI_MODEL_REF_PREFIX}${encoded}` });
15492
+ function pathDelimiter(platform) {
15493
+ return platform === "win32" ? ";" : ":";
15439
15494
  }
15440
- function decodePiModelRef(ref) {
15441
- const parsedRef = harnessModelRefSchema.parse(ref);
15442
- if (!parsedRef.id.startsWith(PI_MODEL_REF_PREFIX)) {
15443
- throw new Error("Model Ref does not belong to PiAdapter");
15444
- }
15445
- const encoded = parsedRef.id.slice(PI_MODEL_REF_PREFIX.length);
15446
- let decoded;
15495
+ function pathDirectories(environment, platform) {
15496
+ return (environmentValue(environment, "PATH") ?? "").split(pathDelimiter(platform)).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean);
15497
+ }
15498
+ function executableExtensions(command, platform, environment) {
15499
+ if (platform !== "win32")
15500
+ return [""];
15501
+ if (targetPath(platform).extname(command) !== "")
15502
+ return [""];
15503
+ return (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean);
15504
+ }
15505
+ function isExecutableFile(filePath, platform) {
15447
15506
  try {
15448
- decoded = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
15507
+ fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
15508
+ return fs.statSync(filePath).isFile();
15449
15509
  } catch {
15450
- throw new Error("Pi Model Ref is malformed");
15451
- }
15452
- if (!Array.isArray(decoded) || decoded.length !== 2 || typeof decoded[0] !== "string" || typeof decoded[1] !== "string") {
15453
- throw new Error("Pi Model Ref has an invalid native identity");
15454
- }
15455
- const native = { provider: decoded[0], id: decoded[1] };
15456
- assertNativePart(native.provider, "Model provider");
15457
- assertNativePart(native.id, "Model id");
15458
- if (encodePiModelRef(native).id !== parsedRef.id) {
15459
- throw new Error("Pi Model Ref is not canonical");
15510
+ return false;
15460
15511
  }
15461
- return native;
15462
15512
  }
15463
- function samePiModel(left, right) {
15464
- return left === null ? right === null : right !== null && left.provider === right.provider && left.id === right.id;
15513
+ function subdirectoryNames(directory) {
15514
+ try {
15515
+ return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
15516
+ } catch {
15517
+ return [];
15518
+ }
15465
15519
  }
15466
- function fallbackThinkingLabel(id) {
15467
- const label = id.split(/[._~-]+/u).filter((part) => part.length > 0).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
15468
- return label || id;
15520
+ function newestFirst(names) {
15521
+ return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
15469
15522
  }
15470
- function normalizePiThinkingOptions(levels) {
15471
- return levels.map((id) => harnessThinkingOptionSchema.parse({
15472
- id,
15473
- label: PI_THINKING_LABELS[id] ?? fallbackThinkingLabel(id)
15474
- }));
15523
+
15524
+ // ../../harness-discovery/dist/node-runtime.js
15525
+ import path2 from "node:path";
15526
+ function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
15527
+ const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
15528
+ const delimiter = platform === "win32" ? ";" : ":";
15529
+ const runtimeDirectory = path2.dirname(runtimeExecutable);
15530
+ const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
15531
+ const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
15532
+ if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
15533
+ directories.push(runtimeDirectory);
15534
+ }
15535
+ return { ...environment, [pathKey]: directories.join(delimiter) };
15475
15536
  }
15476
- function normalizePiModelCatalog(nativeModels, effectiveModel, thinkingLevels, effectiveThinkingOptionId) {
15477
- const byRef = /* @__PURE__ */ new Map();
15478
- for (const native of nativeModels) {
15479
- const ref = encodePiModelRef(native);
15480
- const existing = byRef.get(ref.id);
15481
- if (existing) {
15482
- if (existing.reasoning !== native.reasoning) {
15483
- throw new Error("Pi duplicate Model entries disagree on reasoning capability");
15484
- }
15485
- continue;
15537
+
15538
+ // ../../harness-discovery/dist/resolve.js
15539
+ import os from "node:os";
15540
+
15541
+ // ../../harness-discovery/dist/version-managers.js
15542
+ function versionManagerBinaryDirectories(context) {
15543
+ const { platform, environment, home } = context;
15544
+ const list = context.subdirectories ?? subdirectoryNames;
15545
+ const pathFlavor = targetPath(platform);
15546
+ const value = (name) => environmentValue(environment, name);
15547
+ const directories = [];
15548
+ const versioned = (root, ...tail) => {
15549
+ for (const version2 of newestFirst(list(root))) {
15550
+ directories.push(pathFlavor.join(root, version2, ...tail));
15486
15551
  }
15487
- byRef.set(ref.id, {
15488
- model: {
15489
- ref,
15490
- label: `${native.provider} / ${native.id}`
15491
- },
15492
- reasoning: native.reasoning
15493
- });
15494
- }
15495
- const defaultModel = effectiveModel ? encodePiModelRef(effectiveModel) : void 0;
15496
- if (defaultModel && !byRef.has(defaultModel.id)) {
15497
- throw new Error("Pi effective Model is absent from the available Model catalog");
15552
+ };
15553
+ if (platform === "win32") {
15554
+ const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
15555
+ const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
15556
+ versioned(pathFlavor.join(appData, "nvm"));
15557
+ versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
15558
+ directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
15559
+ directories.push(pathFlavor.join(home, ".bun", "bin"));
15560
+ const pnpmHome2 = value("PNPM_HOME");
15561
+ if (pnpmHome2)
15562
+ directories.push(pnpmHome2);
15563
+ directories.push(pathFlavor.join(localAppData, "pnpm"));
15564
+ return directories;
15498
15565
  }
15499
- if (thinkingLevels && effectiveThinkingOptionId && !thinkingLevels.includes(effectiveThinkingOptionId)) {
15500
- throw new Error("Pi effective Thinking option is absent from the available option catalog");
15566
+ versioned(pathFlavor.join(value("NVM_DIR") ?? pathFlavor.join(home, ".nvm"), "versions", "node"), "bin");
15567
+ const fnmRoots = [
15568
+ value("FNM_DIR"),
15569
+ pathFlavor.join(home, ".local", "share", "fnm"),
15570
+ pathFlavor.join(home, "Library", "Application Support", "fnm")
15571
+ ].filter((root) => root !== void 0);
15572
+ for (const root of fnmRoots) {
15573
+ versioned(pathFlavor.join(root, "node-versions"), "installation", "bin");
15501
15574
  }
15502
- if (thinkingLevels && !effectiveThinkingOptionId) {
15503
- throw new Error("Pi did not report an effective Thinking option");
15575
+ const voltaHome = value("VOLTA_HOME") ?? pathFlavor.join(home, ".volta");
15576
+ versioned(pathFlavor.join(voltaHome, "tools", "image", "node"), "bin");
15577
+ directories.push(pathFlavor.join(voltaHome, "bin"));
15578
+ const asdfHome = value("ASDF_DATA_DIR") ?? pathFlavor.join(home, ".asdf");
15579
+ versioned(pathFlavor.join(asdfHome, "installs", "nodejs"), "bin");
15580
+ directories.push(pathFlavor.join(asdfHome, "shims"));
15581
+ const nodenvHome = value("NODENV_ROOT") ?? pathFlavor.join(home, ".nodenv");
15582
+ versioned(pathFlavor.join(nodenvHome, "versions"), "bin");
15583
+ directories.push(pathFlavor.join(nodenvHome, "shims"));
15584
+ versioned(pathFlavor.join(value("N_PREFIX") ?? "/usr/local", "n", "versions", "node"), "bin");
15585
+ directories.push(pathFlavor.join(home, ".bun", "bin"));
15586
+ const pnpmHome = value("PNPM_HOME");
15587
+ if (pnpmHome)
15588
+ directories.push(pnpmHome);
15589
+ directories.push(pathFlavor.join(home, "Library", "pnpm"));
15590
+ directories.push(pathFlavor.join(home, ".local", "share", "pnpm"));
15591
+ for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
15592
+ for (const formula of newestFirst(list(prefix).filter((name) => name.startsWith("node@")))) {
15593
+ directories.push(pathFlavor.join(prefix, formula, "bin"));
15594
+ }
15504
15595
  }
15505
- const thinkingOptions = thinkingLevels ? normalizePiThinkingOptions(PI_DRAFT_THINKING_OPTION_IDS) : [];
15506
- const allThinkingOptionIds = thinkingOptions.map(({ id }) => id);
15507
- const offThinkingOptionId = thinkingOptions.find(({ id }) => id === "off")?.id;
15508
- const models = [...byRef.values()].map(({ model, reasoning }) => ({
15509
- ...model,
15510
- supportedThinkingOptionIds: reasoning ? allThinkingOptionIds : offThinkingOptionId ? [offThinkingOptionId] : []
15511
- })).sort((left, right) => compareText(left.label, right.label) || compareText(left.ref.id, right.ref.id));
15512
- const defaultThinkingOptionId = thinkingOptions.find(({ id }) => id === effectiveThinkingOptionId)?.id;
15513
- return harnessModelCatalogSchema.parse({
15514
- models,
15515
- ...defaultModel ? { defaultModel } : {},
15516
- thinkingOptions,
15517
- ...defaultThinkingOptionId ? { defaultThinkingOptionId } : {}
15518
- });
15596
+ return directories;
15519
15597
  }
15520
15598
 
15521
- // dist/pi-history.js
15522
- var piHarnessId = harnessIdSchema.parse("pi");
15523
- function isRecord(value) {
15524
- return typeof value === "object" && value !== null && !Array.isArray(value);
15525
- }
15526
- function textContent(value) {
15527
- if (typeof value === "string")
15528
- return value;
15529
- if (!Array.isArray(value))
15530
- return "";
15531
- return value.filter((part) => isRecord(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
15599
+ // ../../harness-discovery/dist/resolve.js
15600
+ var VERSION_MANAGER_ROOTS = "<version-managers>";
15601
+ function installRootExtensions(platform) {
15602
+ return platform === "win32" ? [".exe", ".cmd"] : [""];
15532
15603
  }
15533
- function thinkingContent(value) {
15534
- if (!Array.isArray(value))
15535
- return "";
15536
- return value.filter((part) => isRecord(part) && part.type === "thinking" && typeof part.thinking === "string").map((part) => part.thinking).join("");
15604
+ function resolveHomeDirectory(input) {
15605
+ return input.homeDirectory ?? environmentValue(input.environment, "HOME") ?? environmentValue(input.environment, "USERPROFILE") ?? os.homedir();
15537
15606
  }
15538
- function validatedEntry(value) {
15539
- if (typeof value.id !== "string" || value.id.length === 0 || value.parentId !== null && typeof value.parentId !== "string" || typeof value.type !== "string") {
15540
- throw new Error("Pi history contains an invalid Entry identity");
15541
- }
15542
- return value;
15607
+ function templateVariables(environment, platform, home) {
15608
+ const pathFlavor = targetPath(platform);
15609
+ return {
15610
+ HOME: home,
15611
+ USERPROFILE: home,
15612
+ APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
15613
+ LOCALAPPDATA: environmentValue(environment, "LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local")
15614
+ };
15543
15615
  }
15544
- function activePiEntries(history) {
15616
+ function joinTemplate(platform, value) {
15617
+ const pathFlavor = targetPath(platform);
15618
+ const segments = value.split("/");
15619
+ const head = segments[0] ?? "";
15620
+ const tail = segments.slice(1);
15621
+ if (head === "")
15622
+ return pathFlavor.join(pathFlavor.sep, ...tail);
15623
+ return tail.length === 0 ? head : pathFlavor.join(head, ...tail);
15624
+ }
15625
+ function expandInstallRoot(template, environment, platform, home) {
15626
+ const variables = templateVariables(environment, platform, home);
15627
+ let unresolved = false;
15628
+ const substituted = template.replace(/^~(?=\/|$)/u, home).replace(/\$\{(\w+)\}/gu, (_match, name) => {
15629
+ const value = variables[name] ?? environmentValue(environment, name);
15630
+ if (value === void 0 || value === "") {
15631
+ unresolved = true;
15632
+ return "";
15633
+ }
15634
+ return value;
15635
+ });
15636
+ return unresolved ? void 0 : joinTemplate(platform, substituted);
15637
+ }
15638
+ function installRootDirectories(spec, input, dependencies, platform, home) {
15639
+ const templates = (platform === "win32" ? spec.installRoots?.windows : spec.installRoots?.posix) ?? [];
15640
+ const directories = [];
15641
+ for (const template of templates) {
15642
+ if (template === VERSION_MANAGER_ROOTS) {
15643
+ directories.push(...versionManagerBinaryDirectories({
15644
+ platform,
15645
+ environment: input.environment,
15646
+ home,
15647
+ ...dependencies.subdirectories ? { subdirectories: dependencies.subdirectories } : {}
15648
+ }));
15649
+ continue;
15650
+ }
15651
+ const directory = expandInstallRoot(template, input.environment, platform, home);
15652
+ if (directory !== void 0)
15653
+ directories.push(directory);
15654
+ }
15655
+ return directories;
15656
+ }
15657
+ function harnessCandidates(spec, input, dependencies = {}) {
15658
+ const platform = input.platform ?? process.platform;
15659
+ const pathFlavor = targetPath(platform);
15660
+ const configured = input.command ?? (spec.commandEnvironmentVariable ? environmentValue(input.environment, spec.commandEnvironmentVariable) : void 0);
15661
+ const command = configured ?? spec.command;
15662
+ if (pathFlavor.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
15663
+ return [{ candidate: command, source: "configured" }];
15664
+ }
15665
+ const candidates = [];
15666
+ const extensions = executableExtensions(command, platform, input.environment);
15667
+ for (const directory of pathDirectories(input.environment, platform)) {
15668
+ for (const extension of extensions) {
15669
+ candidates.push({
15670
+ candidate: pathFlavor.join(directory, command + extension),
15671
+ source: "path"
15672
+ });
15673
+ }
15674
+ }
15675
+ if (configured !== void 0)
15676
+ return candidates;
15677
+ const home = resolveHomeDirectory(input);
15678
+ for (const directory of installRootDirectories(spec, input, dependencies, platform, home)) {
15679
+ for (const extension of installRootExtensions(platform)) {
15680
+ candidates.push({
15681
+ candidate: pathFlavor.join(directory, spec.command + extension),
15682
+ source: "install-root"
15683
+ });
15684
+ }
15685
+ }
15686
+ return candidates;
15687
+ }
15688
+ function resolveHarnessExecutable(spec, input, dependencies = {}) {
15689
+ const platform = input.platform ?? process.platform;
15690
+ const isExecutable = dependencies.isExecutable ?? ((candidate) => isExecutableFile(candidate, platform));
15691
+ const runnable = spec.runnableCandidate ?? ((candidate) => candidate);
15692
+ const context = { platform, isExecutable };
15693
+ for (const { candidate, source } of harnessCandidates(spec, input, dependencies)) {
15694
+ const executable = runnable(candidate, context);
15695
+ if (executable !== void 0 && isExecutable(executable))
15696
+ return { executable, source };
15697
+ }
15698
+ return void 0;
15699
+ }
15700
+
15701
+ // dist/command.js
15702
+ var piDiscoverySpec = {
15703
+ id: "pi",
15704
+ command: "pi",
15705
+ commandEnvironmentVariable: "PI_COMMAND",
15706
+ installRoots: {
15707
+ posix: [
15708
+ "~/.npm-global/bin",
15709
+ "~/.local/bin",
15710
+ VERSION_MANAGER_ROOTS,
15711
+ "/opt/homebrew/bin",
15712
+ "/usr/local/bin"
15713
+ ],
15714
+ windows: ["${APPDATA}/npm", "~/.local/bin", VERSION_MANAGER_ROOTS]
15715
+ }
15716
+ };
15717
+ function resolvePiExecutable(input, dependencies = {}) {
15718
+ const resolution = resolveHarnessExecutable(piDiscoverySpec, {
15719
+ ...input.command ? { command: input.command } : {},
15720
+ environment: input.environment,
15721
+ ...dependencies.platform ? { platform: dependencies.platform } : {},
15722
+ ...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {}
15723
+ }, { ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {} });
15724
+ return resolution?.executable ?? input.command ?? input.environment.PI_COMMAND ?? "pi";
15725
+ }
15726
+
15727
+ // dist/pi-credential-imports.js
15728
+ var PREFIX = "codexhost-account-";
15729
+ function object2(value) {
15730
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15731
+ }
15732
+ function parseAuth(raw) {
15733
+ const value = JSON.parse(raw ?? "{}");
15734
+ if (!object2(value))
15735
+ throw new Error("Invalid Pi auth store");
15736
+ return value;
15737
+ }
15738
+ var OAUTH_VENDORS = [
15739
+ {
15740
+ issuer: "https://auth.openai.com",
15741
+ client: "app_EMoamEEZ73f0CkXaXp7hrann",
15742
+ vendor: "openai-codex"
15743
+ },
15744
+ { issuer: "https://auth.x.ai", client: "b1a00492-073a-47ea-816f-4c329264a828", vendor: "xai" }
15745
+ ];
15746
+ function describeOauth(credential) {
15747
+ if (!object2(credential) || credential.type !== "oauth")
15748
+ return {};
15749
+ const token2 = credential.access;
15750
+ if (typeof token2 !== "string")
15751
+ return {};
15752
+ let claims;
15753
+ try {
15754
+ claims = JSON.parse(Buffer.from(token2.split(".")[1] ?? "", "base64url").toString("utf8"));
15755
+ } catch {
15756
+ return {};
15757
+ }
15758
+ if (!object2(claims))
15759
+ return {};
15760
+ const match = OAUTH_VENDORS.find((candidate) => claims.iss === candidate.issuer && claims.client_id === candidate.client);
15761
+ const profile = claims["https://api.openai.com/profile"];
15762
+ const email3 = object2(profile) ? profile.email : claims.email;
15763
+ return {
15764
+ ...typeof email3 === "string" && email3.length > 0 && email3.length <= 512 ? { label: email3 } : {},
15765
+ ...match ? { vendor: match.vendor } : {}
15766
+ };
15767
+ }
15768
+ function writeAuth(filename, content) {
15769
+ const temporary = `${filename}.${randomUUID()}.tmp`;
15770
+ try {
15771
+ writeFileSync(temporary, content, { flag: "wx", mode: 384 });
15772
+ renameSync(temporary, filename);
15773
+ } finally {
15774
+ rmSync(temporary, { force: true });
15775
+ }
15776
+ }
15777
+ function removeOwnedFiles(dir) {
15778
+ rmSync(path3.join(dir, "index.ts"), { force: true });
15779
+ rmSync(path3.join(dir, "import.json"), { force: true });
15780
+ try {
15781
+ rmdirSync(dir);
15782
+ } catch {
15783
+ }
15784
+ }
15785
+ async function installation(command, environment, authPath) {
15786
+ const executable = await realpath(resolvePiExecutable({ ...command ? { command } : {}, environment }));
15787
+ let directory = path3.dirname(executable);
15788
+ while (true) {
15789
+ const manifest = path3.join(directory, "package.json");
15790
+ if (existsSync(manifest)) {
15791
+ const pkg = JSON.parse(readFileSync(manifest, "utf8"));
15792
+ if (pkg.name === "@earendil-works/pi-coding-agent")
15793
+ break;
15794
+ }
15795
+ const parent = path3.dirname(directory);
15796
+ if (parent === directory)
15797
+ throw new Error("Pi credential import requires a supported npm Pi installation");
15798
+ directory = parent;
15799
+ }
15800
+ const storage = await import(pathToFileURL(path3.join(directory, "dist/core/auth-storage.js")).href);
15801
+ const ai = path3.join(directory, "node_modules/@earendil-works/pi-ai/dist");
15802
+ const all = await import(pathToFileURL(path3.join(ai, "providers/all.js")).href);
15803
+ const providers = all.getBuiltinProviders();
15804
+ const providerModules = {
15805
+ "openai-codex": pathToFileURL(path3.join(ai, "providers/openai-codex.js")).href,
15806
+ xai: pathToFileURL(path3.join(ai, "providers/xai.js")).href
15807
+ };
15808
+ for (const [id, url2] of Object.entries(providerModules)) {
15809
+ const module = await import(url2);
15810
+ const provider = id === "xai" ? module.xaiProvider() : module.openaiCodexProvider();
15811
+ if (!provider.auth?.oauth || !provider.getModels().length)
15812
+ throw new Error("Pi version does not support subscription imports");
15813
+ }
15814
+ return {
15815
+ backend: new storage.FileAuthStorageBackend(authPath),
15816
+ providerModules,
15817
+ reservedNames: providers.map((p) => typeof p === "string" ? p : p.id),
15818
+ async configuredProviderNames() {
15819
+ const { stdout } = await promisify(execFile)(process.execPath, [executable, "--offline", "--no-approve", "--list-models"], {
15820
+ cwd: existsSync(path3.dirname(authPath)) ? path3.dirname(authPath) : os2.homedir(),
15821
+ env: { ...environment, PI_CODING_AGENT_DIR: path3.dirname(authPath), PI_OFFLINE: "1" },
15822
+ timeout: 15e3,
15823
+ maxBuffer: 4 * 1024 * 1024
15824
+ });
15825
+ return stdout.split(/\r?\n/).map((line) => line.trim().split(/\s+/)[0] ?? "").filter(Boolean);
15826
+ }
15827
+ };
15828
+ }
15829
+ function extensionSource(moduleUrl, provider, name, owner) {
15830
+ return `// Managed by codexhost. Removing this file disables the imported Provider.
15831
+ export default async function (pi) {
15832
+ const moduleUrl = ${JSON.stringify(moduleUrl)};
15833
+ const nativeModule = await import(moduleUrl);
15834
+ const native = nativeModule.${provider === "xai" ? "xaiProvider" : "openaiCodexProvider"}();
15835
+ const oauth = native.auth.oauth;
15836
+ const models = native.getModels().map(model => ({ ...model, provider: ${JSON.stringify(name)} }));
15837
+ pi.registerProvider({
15838
+ ...native, id: ${JSON.stringify(name)}, name: ${JSON.stringify(name)},
15839
+ auth: { oauth: { ...oauth,
15840
+ async refresh(credential, signal) {
15841
+ return { ...await oauth.refresh(credential, signal), codexhostImportId: ${JSON.stringify(owner)} };
15842
+ }
15843
+ } },
15844
+ getModels: () => models
15845
+ });
15846
+ }
15847
+ `;
15848
+ }
15849
+ function createPiCredentialImports(options = {}) {
15850
+ const env = { ...process.env, ...options.environment };
15851
+ const agentDir = env.PI_CODING_AGENT_DIR ?? path3.join(env.HOME ?? os2.homedir(), ".pi/agent");
15852
+ const authPath = path3.join(agentDir, "auth.json");
15853
+ const extensionsDir = path3.join(agentDir, "extensions");
15854
+ const saveAuth = (auth) => (options.writeAuth ?? writeAuth)(authPath, JSON.stringify(auth, null, 2) + "\n");
15855
+ const resolve = () => options.resolveInstallation?.(authPath) ?? installation(options.command, env, authPath);
15856
+ const location = (name) => path3.join(extensionsDir, `${PREFIX}${credentialImportNameSchema.parse(name)}`);
15857
+ const readRecord = (name) => {
15858
+ const dir = location(name);
15859
+ if (lstatSync(dir).isSymbolicLink())
15860
+ throw new Error("Imported configuration was changed; manage it in Pi");
15861
+ const value = JSON.parse(readFileSync(path3.join(dir, "import.json"), "utf8"));
15862
+ if (value.version !== 1 || typeof value.owner !== "string" || typeof value.extension !== "string")
15863
+ throw new Error("Invalid import metadata");
15864
+ const record6 = value.record;
15865
+ if (!object2(record6))
15866
+ throw new Error("Invalid import metadata");
15867
+ value.record = credentialImportRecordSchema.parse({
15868
+ name: record6.name,
15869
+ source: record6.source,
15870
+ importedAt: record6.importedAt
15871
+ });
15872
+ if (value.record.name !== name)
15873
+ throw new Error("Import identity mismatch");
15874
+ return value;
15875
+ };
15876
+ const owned = (meta3, auth) => {
15877
+ const credential = auth[meta3.record.name];
15878
+ const file2 = path3.join(location(meta3.record.name), "index.ts");
15879
+ return existsSync(file2) && !lstatSync(file2).isSymbolicLink() && readFileSync(file2, "utf8") === meta3.extension && object2(credential) && credential.type === "oauth" && credential.codexhostImportId === meta3.owner;
15880
+ };
15881
+ const readAuth = () => existsSync(authPath) ? parseAuth(readFileSync(authPath, "utf8")) : {};
15882
+ const ownedRecords = (auth) => {
15883
+ if (!existsSync(extensionsDir))
15884
+ return [];
15885
+ const result = [];
15886
+ for (const entry of readdirSync(extensionsDir)) {
15887
+ if (!entry.startsWith(PREFIX))
15888
+ continue;
15889
+ const name = entry.slice(PREFIX.length);
15890
+ if (!credentialImportNameSchema.safeParse(name).success)
15891
+ continue;
15892
+ if (!existsSync(path3.join(location(name), "import.json")))
15893
+ continue;
15894
+ try {
15895
+ const meta3 = readRecord(name);
15896
+ if (owned(meta3, auth))
15897
+ result.push(meta3.record);
15898
+ } catch {
15899
+ }
15900
+ }
15901
+ return result;
15902
+ };
15903
+ return {
15904
+ providers: ["openai-codex", "xai"],
15905
+ async list() {
15906
+ if (!existsSync(agentDir))
15907
+ throw new Error("Pi has no configuration directory");
15908
+ await resolve();
15909
+ return ownedRecords(readAuth());
15910
+ },
15911
+ async listOthers() {
15912
+ const auth = readAuth();
15913
+ const ours = new Set(ownedRecords(auth).map((record6) => record6.name));
15914
+ const result = /* @__PURE__ */ new Map();
15915
+ const usable = (provider) => Boolean(provider) && provider.length <= 128 && !ours.has(provider) && !result.has(provider);
15916
+ for (const [provider, credential] of Object.entries(auth)) {
15917
+ if (!usable(provider))
15918
+ continue;
15919
+ const type = object2(credential) ? credential.type : void 0;
15920
+ result.set(provider, {
15921
+ provider,
15922
+ type: type === "oauth" || type === "api_key" ? type : "unknown",
15923
+ ...describeOauth(credential)
15924
+ });
15925
+ }
15926
+ const modelsPath = path3.join(agentDir, "models.json");
15927
+ if (existsSync(modelsPath)) {
15928
+ const models = JSON.parse(readFileSync(modelsPath, "utf8"));
15929
+ const providers = object2(models) && object2(models.providers) ? models.providers : {};
15930
+ for (const [provider, definition] of Object.entries(providers)) {
15931
+ if (!usable(provider) || !object2(definition) || !definition.apiKey)
15932
+ continue;
15933
+ const name = definition.name;
15934
+ const label = typeof name === "string" && name && name !== provider ? name : void 0;
15935
+ result.set(provider, { provider, type: "api_key", ...label ? { label } : {} });
15936
+ }
15937
+ }
15938
+ return [...result.values()].sort((a, b) => a.provider.localeCompare(b.provider));
15939
+ },
15940
+ async add(name, transfer) {
15941
+ credentialImportNameSchema.parse(name);
15942
+ const sdk = await resolve();
15943
+ if (!this.providers.includes(transfer.source.provider))
15944
+ throw new Error("Unsupported credential source");
15945
+ if (sdk.reservedNames.includes(name) || (await sdk.configuredProviderNames?.())?.includes(name))
15946
+ throw new Error("Provider name already exists; choose another name");
15947
+ const owner = randomUUID();
15948
+ const record6 = credentialImportRecordSchema.parse({
15949
+ name,
15950
+ source: transfer.source,
15951
+ importedAt: (/* @__PURE__ */ new Date()).toISOString()
15952
+ });
15953
+ const extension = extensionSource(sdk.providerModules[transfer.source.provider], transfer.source.provider, name, owner);
15954
+ const dir = location(name);
15955
+ let created = false;
15956
+ let committed = false;
15957
+ try {
15958
+ sdk.backend.withLock((current) => {
15959
+ const auth = parseAuth(current);
15960
+ const modelsPath = path3.join(agentDir, "models.json");
15961
+ const models = existsSync(modelsPath) ? JSON.parse(readFileSync(modelsPath, "utf8")) : {};
15962
+ if (Object.hasOwn(auth, name) || Object.hasOwn(models.providers ?? {}, name) || existsSync(dir) || existsSync(path3.join(extensionsDir, `${name}-provider.ts`)))
15963
+ throw new Error("Provider name already exists; choose another name");
15964
+ mkdirSync(extensionsDir, { recursive: true, mode: 448 });
15965
+ mkdirSync(dir, { mode: 448 });
15966
+ created = true;
15967
+ writeFileSync(path3.join(dir, "import.json"), JSON.stringify({ version: 1, owner, record: record6, extension }), { flag: "wx", mode: 384 });
15968
+ writeFileSync(path3.join(dir, "index.ts"), extension, { flag: "wx", mode: 384 });
15969
+ auth[name] = { type: "oauth", ...transfer.oauth, codexhostImportId: owner };
15970
+ saveAuth(auth);
15971
+ committed = true;
15972
+ return { result: void 0 };
15973
+ });
15974
+ } catch (error51) {
15975
+ if (created && !committed)
15976
+ removeOwnedFiles(dir);
15977
+ throw error51;
15978
+ }
15979
+ },
15980
+ async reimport(name, transfer) {
15981
+ const sdk = await resolve();
15982
+ sdk.backend.withLock((current) => {
15983
+ const meta3 = readRecord(name);
15984
+ const auth = parseAuth(current);
15985
+ if (!owned(meta3, auth) || meta3.record.source.id !== transfer.source.id || meta3.record.source.provider !== transfer.source.provider)
15986
+ throw new Error("Import ownership or source account changed; refusing replacement");
15987
+ const metadataPath = path3.join(location(name), "import.json");
15988
+ const previous = readFileSync(metadataPath, "utf8");
15989
+ const updated = {
15990
+ ...meta3,
15991
+ record: { ...meta3.record, importedAt: (/* @__PURE__ */ new Date()).toISOString() }
15992
+ };
15993
+ writeAuth(metadataPath, JSON.stringify(updated));
15994
+ try {
15995
+ saveAuth({
15996
+ ...auth,
15997
+ [name]: { type: "oauth", ...transfer.oauth, codexhostImportId: meta3.owner }
15998
+ });
15999
+ } catch (error51) {
16000
+ writeAuth(metadataPath, previous);
16001
+ throw error51;
16002
+ }
16003
+ return { result: void 0 };
16004
+ });
16005
+ },
16006
+ async remove(name) {
16007
+ const sdk = await resolve();
16008
+ const meta3 = readRecord(name);
16009
+ sdk.backend.withLock((current) => {
16010
+ const auth = parseAuth(current);
16011
+ if (!owned(meta3, auth))
16012
+ throw new Error("Imported configuration was changed; manage it in Pi");
16013
+ saveAuth(Object.fromEntries(Object.entries(auth).filter(([key]) => key !== name)));
16014
+ removeOwnedFiles(location(name));
16015
+ return { result: void 0 };
16016
+ });
16017
+ }
16018
+ };
16019
+ }
16020
+
16021
+ // dist/pi-empty-session.js
16022
+ import { createReadStream } from "node:fs";
16023
+ import { createInterface } from "node:readline";
16024
+ import { randomUUID as randomUUID2 } from "node:crypto";
16025
+ import { link, open as open2, rm } from "node:fs/promises";
16026
+ import path4 from "node:path";
16027
+
16028
+ // dist/pi-subagents.js
16029
+ import { createHash } from "node:crypto";
16030
+
16031
+ // dist/pi-subagent-workflow.js
16032
+ var PREFIX2 = "pi-subagents-workflow-v1:";
16033
+ var STATES = {
16034
+ pending: "pending",
16035
+ running: "running",
16036
+ completed: "completed",
16037
+ failed: "failed",
16038
+ paused: "interrupted",
16039
+ stopped: "interrupted",
16040
+ rejected: "failed",
16041
+ detached: "running"
16042
+ };
16043
+ function record2(value) {
16044
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16045
+ }
16046
+ function text(value, limit = 256) {
16047
+ return typeof value === "string" && value.length > 0 && value.length <= limit;
16048
+ }
16049
+ function piWorkflowSummary(result) {
16050
+ if (!record2(result) || !record2(result.details) || result.details.mode !== "workflow" || result.details.asyncId !== void 0)
16051
+ return null;
16052
+ const details = result.details;
16053
+ const summary = details.workflowChildren;
16054
+ 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)
16055
+ return null;
16056
+ const children = [];
16057
+ const seen = /* @__PURE__ */ new Set();
16058
+ for (const child of summary.children) {
16059
+ if (!record2(child) || !text(child.childId) || seen.has(child.childId) || typeof child.state !== "string" || !Object.hasOwn(STATES, child.state))
16060
+ return null;
16061
+ for (const key of ["agent", "sessionName", "model", "thinking"]) {
16062
+ if (child[key] !== void 0 && !text(child[key], 2048))
16063
+ return null;
16064
+ }
16065
+ const mappedState = STATES[child.state];
16066
+ if (!mappedState)
16067
+ return null;
16068
+ seen.add(child.childId);
16069
+ children.push({
16070
+ childId: child.childId,
16071
+ state: mappedState,
16072
+ background: child.state === "detached",
16073
+ ...typeof child.agent === "string" ? { agent: child.agent } : {},
16074
+ ...typeof child.sessionName === "string" ? { sessionName: child.sessionName } : {},
16075
+ ...typeof child.model === "string" ? { model: child.model } : {},
16076
+ ...typeof child.thinking === "string" ? { thinking: child.thinking } : {}
16077
+ });
16078
+ }
16079
+ return {
16080
+ workflowRunId: summary.workflowRunId,
16081
+ parentToolCallId: summary.parentToolCallId,
16082
+ children
16083
+ };
16084
+ }
16085
+ function piWorkflowSubagentId(address) {
16086
+ return PREFIX2 + Buffer.from(JSON.stringify([address.workflowRunId, address.childId])).toString("base64url");
16087
+ }
16088
+ function parsePiWorkflowSubagentId(id) {
16089
+ if (!id.startsWith(PREFIX2))
16090
+ return null;
16091
+ if (id.length > 3e3)
16092
+ throw new Error("Invalid Pi workflow child identity");
16093
+ const value = JSON.parse(Buffer.from(id.slice(PREFIX2.length), "base64url").toString("utf8"));
16094
+ if (!Array.isArray(value) || value.length !== 2 || !text(value[0]) || !text(value[1]))
16095
+ throw new Error("Invalid Pi workflow child identity");
16096
+ const address = { workflowRunId: value[0], childId: value[1] };
16097
+ if (piWorkflowSubagentId(address) !== id)
16098
+ throw new Error("Non-canonical Pi workflow child identity");
16099
+ return address;
16100
+ }
16101
+ function projectPiWorkflow(summary, itemId2) {
16102
+ if (!summary.children.length)
16103
+ return null;
16104
+ return {
16105
+ type: "subagentDelegation",
16106
+ itemId: itemId2,
16107
+ operation: "spawn",
16108
+ subagents: summary.children.map((child) => {
16109
+ const id = piWorkflowSubagentId({
16110
+ workflowRunId: summary.workflowRunId,
16111
+ childId: child.childId
16112
+ });
16113
+ return {
16114
+ subagentId: id,
16115
+ nativeSubagentId: id,
16116
+ description: child.sessionName ?? child.agent ?? child.childId,
16117
+ status: child.state,
16118
+ background: child.background,
16119
+ ...child.agent ? { role: child.agent } : {},
16120
+ ...child.model ? { model: child.model } : {},
16121
+ ...child.thinking ? { reasoningEffort: child.thinking } : {}
16122
+ };
16123
+ })
16124
+ };
16125
+ }
16126
+
16127
+ // dist/pi-subagents.js
16128
+ var STATUS_PREFIX = "PI_SUBAGENT_ASYNC_JSON:";
16129
+ var INSPECT_PREFIX = "PI_SUBAGENT_INSPECT_JSON:";
16130
+ var ID_PREFIX = "pi-subagents-v1:";
16131
+ var MAX_BYTES = 64 * 1024;
16132
+ function record3(value) {
16133
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16134
+ }
16135
+ function token(value) {
16136
+ 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);
16137
+ }
16138
+ var statuses = {
16139
+ queued: "pending",
16140
+ running: "running",
16141
+ complete: "completed",
16142
+ failed: "failed",
16143
+ partial: "failed",
16144
+ paused: "interrupted",
16145
+ stopped: "interrupted",
16146
+ rejected: "failed"
16147
+ };
16148
+ function node(value, depth, budget) {
16149
+ 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))
16150
+ return null;
16151
+ const children = [];
16152
+ if (value.children !== void 0) {
16153
+ if (!Array.isArray(value.children))
16154
+ return null;
16155
+ for (const child of value.children) {
16156
+ const parsed = node(child, depth + 1, budget);
16157
+ if (!parsed)
16158
+ return null;
16159
+ children.push(parsed);
16160
+ }
16161
+ }
16162
+ return {
16163
+ id: value.id,
16164
+ kind: value.kind,
16165
+ label: value.label,
16166
+ state: value.state,
16167
+ ...children.length ? { children } : {}
16168
+ };
16169
+ }
16170
+ function widget(value, key, prefix) {
16171
+ if (!record3(value) || value.type !== "extension_ui_request" || value.method !== "setWidget" || value.widgetKey !== key || !Array.isArray(value.widgetLines))
16172
+ return null;
16173
+ const line = value.widgetLines.find((part) => typeof part === "string" && part.startsWith(prefix));
16174
+ if (!line || Buffer.byteLength(line) > MAX_BYTES + prefix.length)
16175
+ return null;
16176
+ try {
16177
+ const parsed = JSON.parse(line.slice(prefix.length));
16178
+ return record3(parsed) && parsed.version === 1 ? parsed : null;
16179
+ } catch {
16180
+ return null;
16181
+ }
16182
+ }
16183
+ function parsePiSubagentStatus(value) {
16184
+ const parsed = widget(value, "subagent-async", STATUS_PREFIX);
16185
+ if (!parsed || parsed.kind !== "pi-subagents.async-status-snapshot" || !Array.isArray(parsed.runs))
16186
+ return null;
16187
+ const runs = [];
16188
+ const budget = { count: 0 };
16189
+ for (const run of parsed.runs) {
16190
+ const parsedNode = node(run, 0, budget);
16191
+ if (!parsedNode)
16192
+ return null;
16193
+ runs.push(parsedNode);
16194
+ }
16195
+ return runs;
16196
+ }
16197
+ function piSubagentId(address) {
16198
+ return ID_PREFIX + Buffer.from(JSON.stringify([address.runId, address.childId ?? null])).toString("base64url");
16199
+ }
16200
+ function parsePiSubagentId(id) {
16201
+ if (!id.startsWith(ID_PREFIX) || id.length > 1500)
16202
+ throw new Error("Invalid Pi Subagent identity");
16203
+ const value = JSON.parse(Buffer.from(id.slice(ID_PREFIX.length), "base64url").toString("utf8"));
16204
+ if (!Array.isArray(value) || value.length !== 2 || !token(value[0]) || value[1] !== null && !token(value[1]))
16205
+ throw new Error("Invalid Pi Subagent identity");
16206
+ const address = { runId: value[0], ...value[1] === null ? {} : { childId: value[1] } };
16207
+ if (piSubagentId(address) !== id)
16208
+ throw new Error("Non-canonical Pi Subagent identity");
16209
+ return address;
16210
+ }
16211
+ function states(run) {
16212
+ const result = [];
16213
+ const seen = /* @__PURE__ */ new Set();
16214
+ const visit = (entry, root) => {
16215
+ if (entry.kind === "host-step" || !root && entry.kind === "workflow")
16216
+ return;
16217
+ if (entry.kind !== "workflow") {
16218
+ const id = piSubagentId({ runId: run.id, ...!root ? { childId: entry.id } : {} });
16219
+ if (!seen.has(id)) {
16220
+ seen.add(id);
16221
+ result.push({
16222
+ subagentId: id,
16223
+ nativeSubagentId: id,
16224
+ description: entry.label,
16225
+ background: true,
16226
+ status: statuses[entry.state] ?? "running"
16227
+ });
16228
+ }
16229
+ }
16230
+ for (const child of entry.children ?? []) {
16231
+ if (entry.kind === "subagent" && child.kind === "step") {
16232
+ for (const nested of child.children ?? [])
16233
+ visit(nested, false);
16234
+ } else
16235
+ visit(child, false);
16236
+ }
16237
+ };
16238
+ visit(run, true);
16239
+ return result;
16240
+ }
16241
+ function asyncRunId(toolName, result) {
16242
+ if (toolName !== "subagent" || !record3(result) || !record3(result.details))
16243
+ return null;
16244
+ const details = result.details;
16245
+ return ["single", "parallel", "chain", "workflow"].includes(String(details.mode)) && token(details.asyncId) && typeof details.asyncDir === "string" ? details.asyncId : null;
16246
+ }
16247
+ var PiSubagents = class {
16248
+ emit;
16249
+ #children = /* @__PURE__ */ new Map();
16250
+ #active = /* @__PURE__ */ new Map();
16251
+ #waiting = /* @__PURE__ */ new Map();
16252
+ constructor(emit) {
16253
+ this.emit = emit;
16254
+ }
16255
+ observe(runs) {
16256
+ this.#apply(runs, true);
16257
+ }
16258
+ restore(runs) {
16259
+ this.#apply(runs, false);
16260
+ }
16261
+ #apply(runs, publish) {
16262
+ for (const run of runs) {
16263
+ const observed = states(run);
16264
+ const retained = this.#children.get(run.id) ?? /* @__PURE__ */ new Map();
16265
+ for (const child of observed)
16266
+ retained.set(child.subagentId, child);
16267
+ this.#children.set(run.id, retained);
16268
+ const children = [...retained.values()];
16269
+ if (!publish)
16270
+ continue;
16271
+ const waiting = this.#waiting.get(run.id);
16272
+ if (waiting && children.length) {
16273
+ const item = {
16274
+ type: "subagentDelegation",
16275
+ itemId: waiting.itemId,
16276
+ operation: "spawn",
16277
+ subagents: children
16278
+ };
16279
+ this.#waiting.delete(run.id);
16280
+ this.#active.set(run.id, { turnId: waiting.turnId, item });
16281
+ this.emit({ type: "item.started", turnId: waiting.turnId, item });
16282
+ }
16283
+ const active = this.#active.get(run.id);
16284
+ if (active && children.length) {
16285
+ const merged = new Map(active.item.subagents.map((child) => [child.nativeSubagentId, child]));
16286
+ for (const child of children)
16287
+ merged.set(child.nativeSubagentId, child);
16288
+ active.item = { ...active.item, subagents: [...merged.values()] };
16289
+ this.emit({
16290
+ type: "item.updated",
16291
+ turnId: active.turnId,
16292
+ itemId: active.item.itemId,
16293
+ update: { type: "subagents.replace", subagents: active.item.subagents }
16294
+ });
16295
+ }
16296
+ for (const child of observed) {
16297
+ this.emit({
16298
+ type: "subagent.state.changed",
16299
+ nativeSubagentId: child.subagentId,
16300
+ status: child.status
16301
+ });
16302
+ this.emit({ type: "subagent.transcript.changed", nativeSubagentId: child.subagentId });
16303
+ }
16304
+ }
16305
+ }
16306
+ project(toolName, result, itemId2, callId) {
16307
+ const workflow = toolName === "subagent" ? piWorkflowSummary(result) : null;
16308
+ if (workflow && (!callId || workflow.parentToolCallId === callId))
16309
+ return projectPiWorkflow(workflow, itemId2);
16310
+ const runId = asyncRunId(toolName, result);
16311
+ if (!runId || !this.#children.has(runId))
16312
+ return null;
16313
+ const children = [...this.#children.get(runId)?.values() ?? []];
16314
+ return children.length ? { type: "subagentDelegation", itemId: itemId2, operation: "spawn", subagents: children } : null;
16315
+ }
16316
+ start(turnId, toolName, result, itemId2, callId) {
16317
+ const workflow = toolName === "subagent" ? piWorkflowSummary(result) : null;
16318
+ if (workflow && (!callId || workflow.parentToolCallId === callId)) {
16319
+ const key = `workflow:${workflow.workflowRunId}`;
16320
+ const previous = this.#active.get(key);
16321
+ const item2 = projectPiWorkflow(workflow, previous?.item.itemId ?? itemId2);
16322
+ if (!item2)
16323
+ return;
16324
+ if (previous) {
16325
+ const children = new Map(previous.item.subagents.map((child) => [child.nativeSubagentId, child]));
16326
+ for (const child of item2.subagents)
16327
+ children.set(child.nativeSubagentId, child);
16328
+ item2.subagents = [...children.values()];
16329
+ previous.item = item2;
16330
+ this.emit({
16331
+ type: "item.updated",
16332
+ turnId: previous.turnId,
16333
+ itemId: item2.itemId,
16334
+ update: { type: "subagents.replace", subagents: item2.subagents }
16335
+ });
16336
+ } else {
16337
+ this.#active.set(key, { turnId, item: item2 });
16338
+ this.emit({ type: "item.started", turnId, item: item2 });
16339
+ }
16340
+ for (const child of item2.subagents) {
16341
+ this.emit({
16342
+ type: "subagent.state.changed",
16343
+ nativeSubagentId: child.subagentId,
16344
+ status: child.status
16345
+ });
16346
+ this.emit({ type: "subagent.transcript.changed", nativeSubagentId: child.subagentId });
16347
+ }
16348
+ return;
16349
+ }
16350
+ const runId = asyncRunId(toolName, result);
16351
+ const item = this.project(toolName, result, itemId2);
16352
+ if (!runId || this.#active.has(runId))
16353
+ return;
16354
+ if (!item) {
16355
+ this.#waiting.set(runId, { turnId, itemId: itemId2 });
16356
+ return;
16357
+ }
16358
+ this.#active.set(runId, { turnId, item });
16359
+ this.emit({ type: "item.started", turnId, item });
16360
+ }
16361
+ finish(turnId) {
16362
+ for (const [runId, waiting] of this.#waiting) {
16363
+ if (waiting.turnId === turnId)
16364
+ this.#waiting.delete(runId);
16365
+ }
16366
+ for (const [runId, active] of this.#active) {
16367
+ if (active.turnId !== turnId)
16368
+ continue;
16369
+ this.#active.delete(runId);
16370
+ this.emit({
16371
+ type: "item.completed",
16372
+ turnId,
16373
+ snapshot: { item: active.item, outcome: { status: "succeeded" } }
16374
+ });
16375
+ }
16376
+ }
16377
+ };
16378
+ function parsePiSubagentInspection(value) {
16379
+ const parsed = widget(value, "subagent-inspect", INSPECT_PREFIX);
16380
+ if (!parsed || parsed.kind !== "pi-subagents.inspect-reply" || !token(parsed.requestId))
16381
+ return null;
16382
+ if (parsed.error !== void 0 && (!record3(parsed.error) || typeof parsed.error.code !== "string" || typeof parsed.error.message !== "string"))
16383
+ return null;
16384
+ for (const field of ["asyncId", "childId", "status", "task", "finalOutput"]) {
16385
+ if (parsed[field] !== void 0 && typeof parsed[field] !== "string")
16386
+ return null;
16387
+ }
16388
+ 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")))
16389
+ return null;
16390
+ 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))
16391
+ return null;
16392
+ return parsed;
16393
+ }
16394
+ function piSubagentSnapshot(parentSessionId, id, reply) {
16395
+ const messages = reply.messages ?? [];
16396
+ const texts = messages.map((entry) => entry.kind === "text" && entry.role === "assistant" ? entry.text : `[${entry.role}${entry.name ? `: ${entry.name}` : ""} / ${entry.kind}]
16397
+ ${entry.text}`);
16398
+ if (!texts.length && reply.finalOutput)
16399
+ texts.push(reply.finalOutput);
16400
+ if (reply.truncated && (reply.truncated.task || reply.truncated.messages || reply.truncated.finalOutput)) {
16401
+ texts.push("[Pi subagent: native inspection returned a truncated transcript window.]");
16402
+ }
16403
+ return {
16404
+ turns: [
16405
+ {
16406
+ nativeTurnRef: nativeTurnRefSchema.parse({
16407
+ harnessId: "pi",
16408
+ nativeSessionId: parentSessionId,
16409
+ nativeTurnKey: `pi-subagent-${createHash("sha256").update(id).digest("hex")}`,
16410
+ formatVersion: 1
16411
+ }),
16412
+ input: reply.task ? [{ type: "text", text: reply.task }] : [],
16413
+ items: texts.map((text2, index) => ({
16414
+ item: {
16415
+ type: "agentMessage",
16416
+ text: text2,
16417
+ itemId: hostItemIdSchema.parse(`pi-subagent-${createHash("sha256").update(`${id}:${index}:${text2}`).digest("hex")}`)
16418
+ },
16419
+ outcome: { status: "succeeded" }
16420
+ })),
16421
+ outcome: reply.status === "complete" ? { status: "succeeded" } : reply.status === "stopped" ? { status: "cancelled", reason: "Pi subagent stopped" } : ["failed", "partial", "rejected"].includes(reply.status ?? "") ? {
16422
+ status: "failed",
16423
+ error: {
16424
+ code: "nativeFailure",
16425
+ message: `Pi subagent ${reply.status}`,
16426
+ retryable: false
16427
+ }
16428
+ } : {
16429
+ status: "unknown",
16430
+ reason: `Pi subagent ${reply.status ?? "status unavailable"}`
16431
+ }
16432
+ }
16433
+ ]
16434
+ };
16435
+ }
16436
+
16437
+ // dist/pi-model-catalog.js
16438
+ var PI_MODEL_REF_PREFIX = "pi-model-v1.";
16439
+ var PI_DRAFT_THINKING_OPTION_IDS = [
16440
+ "off",
16441
+ "minimal",
16442
+ "low",
16443
+ "medium",
16444
+ "high",
16445
+ "xhigh",
16446
+ "max"
16447
+ ].map((id) => harnessThinkingOptionIdSchema.parse(id));
16448
+ var PI_THINKING_LABELS = {
16449
+ off: "Off",
16450
+ minimal: "Minimal",
16451
+ low: "Low",
16452
+ medium: "Medium",
16453
+ high: "High",
16454
+ xhigh: "Extra High",
16455
+ max: "Max"
16456
+ };
16457
+ function compareText(left, right) {
16458
+ return left < right ? -1 : left > right ? 1 : 0;
16459
+ }
16460
+ function assertNativePart(value, name) {
16461
+ if (value.trim().length === 0)
16462
+ throw new Error(`Pi ${name} must not be empty`);
16463
+ }
16464
+ function encodePiModelRef(model) {
16465
+ assertNativePart(model.provider, "Model provider");
16466
+ assertNativePart(model.id, "Model id");
16467
+ const encoded = Buffer.from(JSON.stringify([model.provider, model.id]), "utf8").toString("base64url");
16468
+ return harnessModelRefSchema.parse({ id: `${PI_MODEL_REF_PREFIX}${encoded}` });
16469
+ }
16470
+ function decodePiModelRef(ref) {
16471
+ const parsedRef = harnessModelRefSchema.parse(ref);
16472
+ if (!parsedRef.id.startsWith(PI_MODEL_REF_PREFIX)) {
16473
+ throw new Error("Model Ref does not belong to PiAdapter");
16474
+ }
16475
+ const encoded = parsedRef.id.slice(PI_MODEL_REF_PREFIX.length);
16476
+ let decoded;
16477
+ try {
16478
+ decoded = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
16479
+ } catch {
16480
+ throw new Error("Pi Model Ref is malformed");
16481
+ }
16482
+ if (!Array.isArray(decoded) || decoded.length !== 2 || typeof decoded[0] !== "string" || typeof decoded[1] !== "string") {
16483
+ throw new Error("Pi Model Ref has an invalid native identity");
16484
+ }
16485
+ const native = { provider: decoded[0], id: decoded[1] };
16486
+ assertNativePart(native.provider, "Model provider");
16487
+ assertNativePart(native.id, "Model id");
16488
+ if (encodePiModelRef(native).id !== parsedRef.id) {
16489
+ throw new Error("Pi Model Ref is not canonical");
16490
+ }
16491
+ return native;
16492
+ }
16493
+ function samePiModel(left, right) {
16494
+ return left === null ? right === null : right !== null && left.provider === right.provider && left.id === right.id;
16495
+ }
16496
+ function fallbackThinkingLabel(id) {
16497
+ const label = id.split(/[._~-]+/u).filter((part) => part.length > 0).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
16498
+ return label || id;
16499
+ }
16500
+ function normalizePiThinkingOptions(levels) {
16501
+ return levels.map((id) => harnessThinkingOptionSchema.parse({
16502
+ id,
16503
+ label: PI_THINKING_LABELS[id] ?? fallbackThinkingLabel(id)
16504
+ }));
16505
+ }
16506
+ function normalizePiModelCatalog(nativeModels, effectiveModel, thinkingLevels, effectiveThinkingOptionId) {
16507
+ const byRef = /* @__PURE__ */ new Map();
16508
+ for (const native of nativeModels) {
16509
+ const ref = encodePiModelRef(native);
16510
+ const existing = byRef.get(ref.id);
16511
+ if (existing) {
16512
+ if (existing.reasoning !== native.reasoning) {
16513
+ throw new Error("Pi duplicate Model entries disagree on reasoning capability");
16514
+ }
16515
+ continue;
16516
+ }
16517
+ byRef.set(ref.id, {
16518
+ model: {
16519
+ ref,
16520
+ label: `${native.provider} / ${native.id}`
16521
+ },
16522
+ reasoning: native.reasoning
16523
+ });
16524
+ }
16525
+ const defaultModel = effectiveModel ? encodePiModelRef(effectiveModel) : void 0;
16526
+ if (defaultModel && !byRef.has(defaultModel.id)) {
16527
+ throw new Error("Pi effective Model is absent from the available Model catalog");
16528
+ }
16529
+ if (thinkingLevels && effectiveThinkingOptionId && !thinkingLevels.includes(effectiveThinkingOptionId)) {
16530
+ throw new Error("Pi effective Thinking option is absent from the available option catalog");
16531
+ }
16532
+ if (thinkingLevels && !effectiveThinkingOptionId) {
16533
+ throw new Error("Pi did not report an effective Thinking option");
16534
+ }
16535
+ const thinkingOptions = thinkingLevels ? normalizePiThinkingOptions(PI_DRAFT_THINKING_OPTION_IDS) : [];
16536
+ const allThinkingOptionIds = thinkingOptions.map(({ id }) => id);
16537
+ const offThinkingOptionId = thinkingOptions.find(({ id }) => id === "off")?.id;
16538
+ const models = [...byRef.values()].map(({ model, reasoning }) => ({
16539
+ ...model,
16540
+ supportedThinkingOptionIds: reasoning ? allThinkingOptionIds : offThinkingOptionId ? [offThinkingOptionId] : []
16541
+ })).sort((left, right) => compareText(left.label, right.label) || compareText(left.ref.id, right.ref.id));
16542
+ const defaultThinkingOptionId = thinkingOptions.find(({ id }) => id === effectiveThinkingOptionId)?.id;
16543
+ return harnessModelCatalogSchema.parse({
16544
+ models,
16545
+ ...defaultModel ? { defaultModel } : {},
16546
+ thinkingOptions,
16547
+ ...defaultThinkingOptionId ? { defaultThinkingOptionId } : {}
16548
+ });
16549
+ }
16550
+
16551
+ // dist/pi-history.js
16552
+ var piHarnessId = harnessIdSchema.parse("pi");
16553
+ function isRecord(value) {
16554
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16555
+ }
16556
+ function textContent(value) {
16557
+ if (typeof value === "string")
16558
+ return value;
16559
+ if (!Array.isArray(value))
16560
+ return "";
16561
+ return value.filter((part) => isRecord(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
16562
+ }
16563
+ function thinkingContent(value) {
16564
+ if (!Array.isArray(value))
16565
+ return "";
16566
+ return value.filter((part) => isRecord(part) && part.type === "thinking" && typeof part.thinking === "string").map((part) => part.thinking).join("");
16567
+ }
16568
+ function validatedEntry(value) {
16569
+ if (typeof value.id !== "string" || value.id.length === 0 || value.parentId !== null && typeof value.parentId !== "string" || typeof value.type !== "string") {
16570
+ throw new Error("Pi history contains an invalid Entry identity");
16571
+ }
16572
+ return value;
16573
+ }
16574
+ function activePiEntries(history) {
15545
16575
  if (history.leafId === null)
15546
16576
  return [];
15547
16577
  const byId = new Map(history.entries.map((value) => {
@@ -15609,10 +16639,10 @@ function itemOutcome(outcome) {
15609
16639
  return { status: "succeeded" };
15610
16640
  }
15611
16641
  function toolOutput(value) {
15612
- const text = textContent(value);
15613
- return text.length > 0 ? { content: [{ type: "text", text }] } : void 0;
16642
+ const text2 = textContent(value);
16643
+ return text2.length > 0 ? { content: [{ type: "text", text: text2 }] } : void 0;
15614
16644
  }
15615
- function snapshotItems(entries, outcome) {
16645
+ function snapshotItems(entries, outcome, subagents) {
15616
16646
  const snapshots = [];
15617
16647
  const toolCalls = /* @__PURE__ */ new Map();
15618
16648
  for (const entry of entries) {
@@ -15621,7 +16651,7 @@ function snapshotItems(entries, outcome) {
15621
16651
  continue;
15622
16652
  const content = Array.isArray(nativeMessage.content) ? nativeMessage.content : [];
15623
16653
  if (nativeMessage.role === "assistant") {
15624
- const text = textContent(content);
16654
+ const text2 = textContent(content);
15625
16655
  const reasoning = thinkingContent(content);
15626
16656
  let projectedText = false;
15627
16657
  let projectedReasoning = false;
@@ -15638,11 +16668,11 @@ function snapshotItems(entries, outcome) {
15638
16668
  projectedReasoning = true;
15639
16669
  continue;
15640
16670
  }
15641
- if (part.type === "text" && !projectedText && text.length > 0) {
16671
+ if (part.type === "text" && !projectedText && text2.length > 0) {
15642
16672
  const item2 = {
15643
16673
  type: "agentMessage",
15644
16674
  itemId: itemId(entry.id, "assistant", 0),
15645
- text
16675
+ text: text2
15646
16676
  };
15647
16677
  snapshots.push({ item: item2, outcome: itemOutcome(outcome) });
15648
16678
  projectedText = true;
@@ -15678,6 +16708,7 @@ function snapshotItems(entries, outcome) {
15678
16708
  ...output ? { output } : {}
15679
16709
  };
15680
16710
  const toolFailed = nativeMessage.isError === true;
16711
+ const delegation = subagents?.project(call.name, nativeMessage, itemId(call.entryId, "subagent", call.ordinal), nativeMessage.toolCallId);
15681
16712
  snapshots.push({
15682
16713
  item,
15683
16714
  outcome: toolFailed ? {
@@ -15689,16 +16720,18 @@ function snapshotItems(entries, outcome) {
15689
16720
  }
15690
16721
  } : { status: "succeeded" }
15691
16722
  });
16723
+ if (delegation)
16724
+ snapshots.push({ item: delegation, outcome: { status: "succeeded" } });
15692
16725
  }
15693
16726
  return snapshots;
15694
16727
  }
15695
16728
  function modelChange(entry) {
15696
16729
  return entry.type === "model_change" && typeof entry.provider === "string" && typeof entry.modelId === "string" ? { provider: entry.provider, id: entry.modelId } : null;
15697
16730
  }
15698
- function mapPiSnapshot(history, state) {
16731
+ function mapPiSnapshot(history, state2, subagents = new PiSubagents(() => void 0)) {
15699
16732
  const active = activePiEntries(history);
15700
16733
  const turns = [];
15701
- let effectiveModel = state.model;
16734
+ let effectiveModel = state2.model;
15702
16735
  for (let index = 0; index < active.length; ) {
15703
16736
  const model = modelChange(active[index]);
15704
16737
  if (model) {
@@ -15719,13 +16752,13 @@ function mapPiSnapshot(history, state) {
15719
16752
  const userText = textContent(message(user)?.content);
15720
16753
  const nativeTurnRef = nativeTurnRefSchema.parse({
15721
16754
  harnessId: piHarnessId,
15722
- nativeSessionId: state.sessionId,
16755
+ nativeSessionId: state2.sessionId,
15723
16756
  nativeTurnKey: user.id,
15724
16757
  formatVersion: 1
15725
16758
  });
15726
16759
  const checkpoint = nativeCheckpointRefSchema.parse({
15727
16760
  harnessId: piHarnessId,
15728
- nativeSessionId: state.sessionId,
16761
+ nativeSessionId: state2.sessionId,
15729
16762
  checkpointId: user.id,
15730
16763
  formatVersion: 1
15731
16764
  });
@@ -15733,7 +16766,7 @@ function mapPiSnapshot(history, state) {
15733
16766
  nativeTurnRef,
15734
16767
  checkpoint,
15735
16768
  input: [{ type: "text", text: userText }],
15736
- items: snapshotItems(entries, outcome),
16769
+ items: snapshotItems(entries, outcome, subagents),
15737
16770
  outcome,
15738
16771
  ...effectiveModel ? { model: encodePiModelRef(effectiveModel) } : {}
15739
16772
  });
@@ -15764,7 +16797,7 @@ function resolvePiForkBoundary(history, checkpointId) {
15764
16797
  }
15765
16798
 
15766
16799
  // dist/pi-session-file.js
15767
- import { open, realpath } from "node:fs/promises";
16800
+ import { open, realpath as realpath2 } from "node:fs/promises";
15768
16801
  var MAX_SESSION_HEADER_BYTES = 64 * 1024;
15769
16802
  var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
15770
16803
  function isRecord2(value) {
@@ -15808,8 +16841,8 @@ async function verifyPiSessionCwd(input) {
15808
16841
  throw new Error("Pi Fork Session header identity does not match RPC state");
15809
16842
  }
15810
16843
  const [actualCwd, expectedCwd] = await Promise.all([
15811
- realpath(header.cwd),
15812
- realpath(input.expectedCwd)
16844
+ realpath2(header.cwd),
16845
+ realpath2(input.expectedCwd)
15813
16846
  ]);
15814
16847
  if (actualCwd !== expectedCwd) {
15815
16848
  throw new Error("Pi Fork Session did not bind the requested cwd");
@@ -15818,9 +16851,9 @@ async function verifyPiSessionCwd(input) {
15818
16851
 
15819
16852
  // dist/pi-empty-session.js
15820
16853
  async function persistEmptyPiSession(input) {
15821
- const { state, history, sourceSessionFile, sourceSessionId, cwd } = input;
15822
- const destination = state.sessionFile;
15823
- if (!destination || !path.isAbsolute(destination) || path.resolve(destination) === path.resolve(sourceSessionFile) || state.sessionId === sourceSessionId || mapPiSnapshot(history, { sessionId: state.sessionId, model: null }).turns.length !== 0)
16854
+ const { state: state2, history, sourceSessionFile, sourceSessionId, cwd } = input;
16855
+ const destination = state2.sessionFile;
16856
+ if (!destination || !path4.isAbsolute(destination) || path4.resolve(destination) === path4.resolve(sourceSessionFile) || state2.sessionId === sourceSessionId || mapPiSnapshot(history, { sessionId: state2.sessionId, model: null }).turns.length !== 0)
15824
16857
  throw new Error("Pi empty Session is not an independent empty native fork");
15825
16858
  await verifyPiSessionCwd({
15826
16859
  sessionFile: sourceSessionFile,
@@ -15839,12 +16872,12 @@ async function persistEmptyPiSession(input) {
15839
16872
  const header = {
15840
16873
  type: "session",
15841
16874
  version: 3,
15842
- id: state.sessionId,
16875
+ id: state2.sessionId,
15843
16876
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
15844
16877
  cwd,
15845
16878
  parentSession: sourceSessionFile
15846
16879
  };
15847
- const temporary = path.join(path.dirname(destination), `.codexhost-${randomUUID()}.tmp`);
16880
+ const temporary = path4.join(path4.dirname(destination), `.codexhost-${randomUUID2()}.tmp`);
15848
16881
  try {
15849
16882
  const file2 = await open2(temporary, "wx", 384);
15850
16883
  try {
@@ -15855,7 +16888,7 @@ async function persistEmptyPiSession(input) {
15855
16888
  }
15856
16889
  await link(temporary, destination);
15857
16890
  if (process.platform !== "win32") {
15858
- const directory = await open2(path.dirname(destination), "r");
16891
+ const directory = await open2(path4.dirname(destination), "r");
15859
16892
  try {
15860
16893
  await directory.sync();
15861
16894
  } finally {
@@ -16018,16 +17051,16 @@ var Diff = class {
16018
17051
  }
16019
17052
  }
16020
17053
  }
16021
- addToPath(path7, added, removed, oldPosInc, options) {
16022
- const last = path7.lastComponent;
17054
+ addToPath(path10, added, removed, oldPosInc, options) {
17055
+ const last = path10.lastComponent;
16023
17056
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
16024
17057
  return {
16025
- oldPos: path7.oldPos + oldPosInc,
17058
+ oldPos: path10.oldPos + oldPosInc,
16026
17059
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
16027
17060
  };
16028
17061
  } else {
16029
17062
  return {
16030
- oldPos: path7.oldPos + oldPosInc,
17063
+ oldPos: path10.oldPos + oldPosInc,
16031
17064
  lastComponent: { count: 1, added, removed, previousComponent: last }
16032
17065
  };
16033
17066
  }
@@ -16393,788 +17426,729 @@ function formatPatch(patch) {
16393
17426
  ret.push("+++ " + patch.newFileName + (typeof patch.newHeader === "undefined" ? "" : " " + patch.newHeader));
16394
17427
  for (let i = 0; i < patch.hunks.length; i++) {
16395
17428
  const hunk = patch.hunks[i];
16396
- if (hunk.oldLines === 0) {
16397
- hunk.oldStart -= 1;
16398
- }
16399
- if (hunk.newLines === 0) {
16400
- hunk.newStart -= 1;
16401
- }
16402
- ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
16403
- for (const line of hunk.lines) {
16404
- ret.push(line);
16405
- }
16406
- }
16407
- return ret.join("\n") + "\n";
16408
- }
16409
- function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
16410
- if (typeof options === "function") {
16411
- options = { callback: options };
16412
- }
16413
- if (!(options === null || options === void 0 ? void 0 : options.callback)) {
16414
- const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
16415
- if (!patchObj) {
16416
- return;
16417
- }
16418
- return formatPatch(patchObj);
16419
- } else {
16420
- const { callback } = options;
16421
- structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: (patchObj) => {
16422
- if (!patchObj) {
16423
- callback(void 0);
16424
- } else {
16425
- callback(formatPatch(patchObj));
16426
- }
16427
- } }));
16428
- }
16429
- }
16430
- function splitLines(text) {
16431
- const hasTrailingNl = text.endsWith("\n");
16432
- const result = text.split("\n").map((line) => line + "\n");
16433
- if (hasTrailingNl) {
16434
- result.pop();
16435
- } else {
16436
- result.push(result.pop().slice(0, -1));
16437
- }
16438
- return result;
16439
- }
16440
-
16441
- // dist/pi-adapter.js
16442
- import { randomUUID as randomUUID3 } from "node:crypto";
16443
- import path6 from "node:path";
16444
-
16445
- // ../../harness-adapter/dist/question.js
16446
- function invalidRequest(message3) {
16447
- return { code: "invalidRequest", message: message3, retryable: false };
16448
- }
16449
- function validateHostQuestionResponse(interaction, response) {
16450
- const questionIds = new Set(interaction.questions.map(({ id }) => id));
16451
- if (response.cancelled) {
16452
- return Object.keys(response.answers).length === 0 ? null : invalidRequest("Cancelled Question Response must not contain answers");
16453
- }
16454
- for (const answerId of Object.keys(response.answers)) {
16455
- if (!questionIds.has(answerId)) {
16456
- return invalidRequest("Question Response contains an unknown Question ID");
16457
- }
16458
- }
16459
- for (const question of interaction.questions) {
16460
- const answers = response.answers[question.id] ?? [];
16461
- if (!question.optional && answers.length === 0) {
16462
- return invalidRequest("Question Response omits a required answer");
16463
- }
16464
- if (question.type === "text") {
16465
- if (answers.length > 1) {
16466
- return invalidRequest("Text Question accepts at most one answer");
16467
- }
16468
- continue;
16469
- }
16470
- if (!question.multiple && answers.length > 1) {
16471
- return invalidRequest("Single-choice Question accepts at most one answer");
16472
- }
16473
- const declared = new Set(question.options.map(({ value }) => value));
16474
- if (!question.allowOther && answers.some((answer) => !declared.has(answer))) {
16475
- return invalidRequest("Question Response contains an undeclared choice");
16476
- }
16477
- }
16478
- return null;
16479
- }
16480
-
16481
- // ../../harness-adapter/dist/output-channel.js
16482
- var HarnessOutputChannel = class {
16483
- outputs;
16484
- #consumerCreated = false;
16485
- #ended = false;
16486
- #pending = [];
16487
- #values = [];
16488
- constructor() {
16489
- this.outputs = {
16490
- [Symbol.asyncIterator]: () => {
16491
- if (this.#consumerCreated) {
16492
- throw new Error("Harness outputs allow only one consumer");
16493
- }
16494
- this.#consumerCreated = true;
16495
- return {
16496
- next: () => this.#next()
16497
- };
16498
- }
16499
- };
16500
- }
16501
- emit(value) {
16502
- if (this.#ended)
16503
- return false;
16504
- const resolve = this.#pending.shift();
16505
- if (resolve)
16506
- resolve({ done: false, value });
16507
- else
16508
- this.#values.push(value);
16509
- return true;
16510
- }
16511
- end() {
16512
- if (this.#ended)
16513
- return;
16514
- this.#ended = true;
16515
- if (this.#values.length !== 0)
16516
- return;
16517
- for (const resolve of this.#pending.splice(0))
16518
- resolve({ done: true, value: void 0 });
16519
- }
16520
- #next() {
16521
- const value = this.#values.shift();
16522
- if (value !== void 0)
16523
- return Promise.resolve({ done: false, value });
16524
- if (this.#ended)
16525
- return Promise.resolve({ done: true, value: void 0 });
16526
- return new Promise((resolve) => this.#pending.push(resolve));
16527
- }
16528
- };
16529
-
16530
- // ../../harness-adapter/dist/diagnostics.js
16531
- var DIAGNOSTIC_TAIL_MAX_LENGTH = 8e3;
16532
- var SENSITIVE_VALUE_PATTERN = /(api[_-]?key|access[_-]?token|auth(?:orization)?|password|secret)(\s*[:=]\s*)([^\s,;]+)/giu;
16533
- var BEARER_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]+/giu;
16534
- function sanitizeDiagnosticTail(value) {
16535
- const redacted = value.replace(BEARER_PATTERN, "Bearer [redacted]").replace(SENSITIVE_VALUE_PATTERN, "$1$2[redacted]");
16536
- return redacted.length <= DIAGNOSTIC_TAIL_MAX_LENGTH ? redacted : redacted.slice(-DIAGNOSTIC_TAIL_MAX_LENGTH);
16537
- }
16538
-
16539
- // ../../harness-adapter/dist/usage.js
16540
- var tokenFields = [
16541
- "inputTokens",
16542
- "cachedInputTokens",
16543
- "cacheWriteInputTokens",
16544
- "outputTokens",
16545
- "outputTokensPerSecond",
16546
- "reasoningOutputTokens",
16547
- "totalTokens",
16548
- "contextWindowTokens",
16549
- "contextUsedTokens"
16550
- ];
16551
- var safeIntegerFields = [
16552
- "planFiveHourResetsAtUnix",
16553
- "planSevenDayResetsAtUnix"
16554
- ];
16555
- var percentFields = [
16556
- "cacheHitRatePercent",
16557
- "planFiveHourUsedPercent",
16558
- "planSevenDayUsedPercent"
16559
- ];
16560
- var usageFields = /* @__PURE__ */ new Set([
16561
- ...tokenFields,
16562
- ...safeIntegerFields,
16563
- ...percentFields,
16564
- "totalCostUsd",
16565
- "totalCredits",
16566
- "contextUsagePercent"
16567
- ]);
16568
- function isRecord3(value) {
16569
- return typeof value === "object" && value !== null && !Array.isArray(value);
16570
- }
16571
- function parseHostUsage(value) {
16572
- if (!isRecord3(value))
16573
- throw new Error("Harness Usage must be an object");
16574
- const keys = Object.keys(value);
16575
- if (keys.length === 0)
16576
- throw new Error("Harness Usage must contain a reliable field");
16577
- for (const key of keys) {
16578
- if (!usageFields.has(key)) {
16579
- throw new Error(`Harness Usage contains unknown field '${key}'`);
16580
- }
16581
- }
16582
- for (const field of ["totalCredits", "contextUsagePercent"]) {
16583
- const candidate = value[field];
16584
- if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
16585
- throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
16586
- }
16587
- }
16588
- for (const field of tokenFields) {
16589
- const candidate = value[field];
16590
- if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
16591
- throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
16592
- }
16593
- }
16594
- for (const field of safeIntegerFields) {
16595
- const candidate = value[field];
16596
- if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
16597
- throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
16598
- }
16599
- }
16600
- if (value.outputTokensPerSecond !== void 0 && (typeof value.outputTokensPerSecond !== "number" || !Number.isFinite(value.outputTokensPerSecond) || value.outputTokensPerSecond < 0)) {
16601
- throw new Error("Harness Usage 'outputTokensPerSecond' must be a finite non-negative number");
16602
- }
16603
- if (value.totalCostUsd !== void 0 && (typeof value.totalCostUsd !== "number" || !Number.isFinite(value.totalCostUsd) || value.totalCostUsd < 0)) {
16604
- throw new Error("Harness Usage 'totalCostUsd' must be a finite non-negative number");
16605
- }
16606
- for (const field of ["totalCredits", "contextUsagePercent"]) {
16607
- const candidate = value[field];
16608
- if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
16609
- throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
17429
+ if (hunk.oldLines === 0) {
17430
+ hunk.oldStart -= 1;
16610
17431
  }
16611
- }
16612
- for (const field of percentFields) {
16613
- const candidate = value[field];
16614
- if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0 || candidate > 100)) {
16615
- throw new Error(`Harness Usage '${field}' must be between 0 and 100`);
17432
+ if (hunk.newLines === 0) {
17433
+ hunk.newStart -= 1;
17434
+ }
17435
+ ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
17436
+ for (const line of hunk.lines) {
17437
+ ret.push(line);
16616
17438
  }
16617
17439
  }
16618
- const hasContextUsed = value.contextUsedTokens !== void 0;
16619
- const hasContextWindow = value.contextWindowTokens !== void 0;
16620
- if (hasContextUsed !== hasContextWindow) {
16621
- throw new Error("Harness Usage context fields must be provided together");
16622
- }
16623
- if (hasContextWindow && value.contextWindowTokens === 0) {
16624
- throw new Error("Harness Usage 'contextWindowTokens' must be greater than zero");
17440
+ return ret.join("\n") + "\n";
17441
+ }
17442
+ function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
17443
+ if (typeof options === "function") {
17444
+ options = { callback: options };
16625
17445
  }
16626
- if (value.planFiveHourResetsAtUnix !== void 0 && value.planFiveHourUsedPercent === void 0) {
16627
- throw new Error("Harness Usage 'planFiveHourResetsAtUnix' must be provided with 'planFiveHourUsedPercent'");
17446
+ if (!(options === null || options === void 0 ? void 0 : options.callback)) {
17447
+ const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
17448
+ if (!patchObj) {
17449
+ return;
17450
+ }
17451
+ return formatPatch(patchObj);
17452
+ } else {
17453
+ const { callback } = options;
17454
+ structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: (patchObj) => {
17455
+ if (!patchObj) {
17456
+ callback(void 0);
17457
+ } else {
17458
+ callback(formatPatch(patchObj));
17459
+ }
17460
+ } }));
16628
17461
  }
16629
- if (value.planSevenDayResetsAtUnix !== void 0 && value.planSevenDayUsedPercent === void 0) {
16630
- throw new Error("Harness Usage 'planSevenDayResetsAtUnix' must be provided with 'planSevenDayUsedPercent'");
17462
+ }
17463
+ function splitLines(text2) {
17464
+ const hasTrailingNl = text2.endsWith("\n");
17465
+ const result = text2.split("\n").map((line) => line + "\n");
17466
+ if (hasTrailingNl) {
17467
+ result.pop();
17468
+ } else {
17469
+ result.push(result.pop().slice(0, -1));
16631
17470
  }
16632
- return { ...value };
17471
+ return result;
16633
17472
  }
16634
17473
 
16635
- // dist/pi-last-turn-rollback.js
16636
- function modelFromState(state) {
16637
- if (state.provider === null && state.modelId === null)
16638
- return null;
16639
- if (state.provider === null || state.modelId === null) {
16640
- throw new Error("Pi state contains a partial Model identity");
16641
- }
16642
- return { provider: state.provider, id: state.modelId };
17474
+ // dist/pi-adapter.js
17475
+ import { randomUUID as randomUUID5 } from "node:crypto";
17476
+ import path9 from "node:path";
17477
+
17478
+ // ../../harness-adapter/dist/question.js
17479
+ function invalidRequest(message3) {
17480
+ return { code: "invalidRequest", message: message3, retryable: false };
16643
17481
  }
16644
- async function rollbackPiLastTurn(transport, sourceSessionId, cwd) {
16645
- const startupState = transport.state;
16646
- const startupSessionId = startupState.sessionId;
16647
- const currentModel = modelFromState(startupState);
16648
- const currentThinking = startupState.thinkingLevel;
16649
- const copiedHistory = await transport.getEntries();
16650
- const boundary = resolvePiLastTurnBoundary(copiedHistory);
16651
- if (!boundary)
16652
- return { ok: false, reason: "empty" };
16653
- const sourceSnapshot = mapPiSnapshot(copiedHistory, {
16654
- sessionId: startupSessionId,
16655
- model: currentModel
16656
- });
16657
- let state = await transport.fork(boundary.lastUserEntryId);
16658
- if (state.sessionId === sourceSessionId || state.sessionId === startupSessionId) {
16659
- throw new Error("Pi last-Turn rollback did not create a distinct Native Session");
16660
- }
16661
- if (!samePiModel(modelFromState(state), currentModel)) {
16662
- if (!currentModel)
16663
- throw new Error("Pi last-Turn rollback changed the current Model");
16664
- state = await transport.selectModel(currentModel);
16665
- }
16666
- if (state.thinkingLevel !== currentThinking) {
16667
- if (!currentThinking)
16668
- throw new Error("Pi last-Turn rollback changed current Thinking");
16669
- state = await transport.selectThinkingOption(currentThinking);
16670
- }
16671
- if (!samePiModel(modelFromState(state), currentModel) || state.thinkingLevel !== currentThinking) {
16672
- throw new Error("Pi last-Turn rollback could not restore current Model and Thinking");
17482
+ function validateHostQuestionResponse(interaction, response) {
17483
+ const questionIds = new Set(interaction.questions.map(({ id }) => id));
17484
+ if (response.cancelled) {
17485
+ return Object.keys(response.answers).length === 0 ? null : invalidRequest("Cancelled Question Response must not contain answers");
16673
17486
  }
16674
- const snapshot = mapPiSnapshot(await transport.getEntries(), {
16675
- sessionId: state.sessionId,
16676
- model: modelFromState(state)
16677
- });
16678
- const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
16679
- const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
16680
- if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
16681
- throw new Error("Pi last-Turn rollback did not produce the exact retained history prefix");
17487
+ for (const answerId of Object.keys(response.answers)) {
17488
+ if (!questionIds.has(answerId)) {
17489
+ return invalidRequest("Question Response contains an unknown Question ID");
17490
+ }
16682
17491
  }
16683
- try {
16684
- await transport.verifySessionCwd(cwd);
16685
- return { ok: true, unpersisted: false };
16686
- } catch (error51) {
16687
- if (snapshot.turns.length === 0 && error51?.code === "ENOENT") {
16688
- return { ok: true, unpersisted: true };
17492
+ for (const question of interaction.questions) {
17493
+ const answers = response.answers[question.id] ?? [];
17494
+ if (!question.optional && answers.length === 0) {
17495
+ return invalidRequest("Question Response omits a required answer");
17496
+ }
17497
+ if (question.type === "text") {
17498
+ if (answers.length > 1) {
17499
+ return invalidRequest("Text Question accepts at most one answer");
17500
+ }
17501
+ continue;
17502
+ }
17503
+ if (!question.multiple && answers.length > 1) {
17504
+ return invalidRequest("Single-choice Question accepts at most one answer");
17505
+ }
17506
+ const declared = new Set(question.options.map(({ value }) => value));
17507
+ if (!question.allowOther && answers.some((answer) => !declared.has(answer))) {
17508
+ return invalidRequest("Question Response contains an undeclared choice");
16689
17509
  }
16690
- throw error51;
16691
17510
  }
17511
+ return null;
16692
17512
  }
16693
17513
 
16694
- // dist/pi-session-import.js
16695
- import { createReadStream as createReadStream2 } from "node:fs";
16696
- import { opendir, realpath as realpath2, stat } from "node:fs/promises";
16697
- import os from "node:os";
16698
- import path2 from "node:path";
16699
- import { createInterface as createInterface2 } from "node:readline";
16700
- var PiSessionChangedError = class extends Error {
17514
+ // ../../harness-adapter/dist/output-channel.js
17515
+ var HarnessOutputChannel = class {
17516
+ outputs;
17517
+ #consumerCreated = false;
17518
+ #ended = false;
17519
+ #pending = [];
17520
+ #values = [];
16701
17521
  constructor() {
16702
- super("Pi Session changed during discovery; refresh and retry");
17522
+ this.outputs = {
17523
+ [Symbol.asyncIterator]: () => {
17524
+ if (this.#consumerCreated) {
17525
+ throw new Error("Harness outputs allow only one consumer");
17526
+ }
17527
+ this.#consumerCreated = true;
17528
+ return {
17529
+ next: () => this.#next()
17530
+ };
17531
+ }
17532
+ };
16703
17533
  }
16704
- };
16705
- function sameFile(left, right) {
16706
- return left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs && left.ino === right.ino && left.dev === right.dev;
16707
- }
16708
- function isRecord4(value) {
16709
- return typeof value === "object" && value !== null && !Array.isArray(value);
16710
- }
16711
- function missing(error51) {
16712
- return isRecord4(error51) && error51.code === "ENOENT";
16713
- }
16714
- function expandDirectory(value, home) {
16715
- return path2.resolve(value === "~" ? home : value.startsWith(`~${path2.sep}`) || value.startsWith("~/") ? path2.join(home, value.slice(2)) : value);
16716
- }
16717
- function piSessionImportDirectory(environment) {
16718
- const home = (process.platform === "win32" ? environment.USERPROFILE : environment.HOME) || os.homedir();
16719
- const custom2 = environment.PI_CODING_AGENT_SESSION_DIR;
16720
- if (custom2)
16721
- return { directory: expandDirectory(custom2, home), flat: true };
16722
- const agent = environment.PI_CODING_AGENT_DIR;
16723
- return {
16724
- directory: path2.join(agent ? expandDirectory(agent, home) : path2.join(home, ".pi", "agent"), "sessions"),
16725
- flat: false
16726
- };
16727
- }
16728
- async function sessionFiles(directory, flat, signal) {
16729
- const files = [];
16730
- const visit = async (dir, projectLevel) => {
16731
- signal.throwIfAborted();
16732
- const entries = await opendir(dir).catch((error51) => {
16733
- if (missing(error51))
16734
- return null;
16735
- throw error51;
16736
- });
16737
- if (!entries)
17534
+ emit(value) {
17535
+ if (this.#ended)
17536
+ return false;
17537
+ const resolve = this.#pending.shift();
17538
+ if (resolve)
17539
+ resolve({ done: false, value });
17540
+ else
17541
+ this.#values.push(value);
17542
+ return true;
17543
+ }
17544
+ end() {
17545
+ if (this.#ended)
16738
17546
  return;
16739
- for await (const entry of entries) {
16740
- signal.throwIfAborted();
16741
- if (projectLevel && entry.isDirectory())
16742
- await visit(path2.join(dir, entry.name), false);
16743
- else if (!projectLevel && entry.isFile() && entry.name.endsWith(".jsonl")) {
16744
- files.push(path2.join(dir, entry.name));
16745
- }
16746
- }
16747
- };
16748
- await visit(directory, !flat);
16749
- return files;
16750
- }
16751
- async function readCandidate(file2, signal) {
16752
- const before = await stat(file2);
16753
- if (!before.isFile() || before.size === 0)
16754
- return null;
16755
- const stream = createReadStream2(file2, { encoding: "utf8", signal, end: before.size - 1 });
16756
- const lines = createInterface2({ input: stream, crlfDelay: Infinity });
16757
- let header;
16758
- let name = null;
16759
- let firstMessage = null;
16760
- let hasUser = false;
16761
- let updatedAt = before.mtimeMs;
16762
- const entries = /* @__PURE__ */ new Map();
16763
- try {
16764
- for await (const line of lines) {
16765
- signal.throwIfAborted();
16766
- if (!line.trim())
16767
- continue;
16768
- let entry;
16769
- try {
16770
- entry = JSON.parse(line);
16771
- } catch {
16772
- return null;
16773
- }
16774
- if (!isRecord4(entry))
16775
- return null;
16776
- if (!header) {
16777
- if (entry.type !== "session" || entry.version !== 3 || typeof entry.id !== "string" || typeof entry.cwd !== "string" || !path2.isAbsolute(entry.cwd))
16778
- return null;
16779
- header = entry;
16780
- continue;
16781
- }
16782
- if (typeof entry.id !== "string" || entry.id.length === 0 || entries.has(entry.id) || entry.parentId !== null && (typeof entry.parentId !== "string" || !entries.has(entry.parentId)))
16783
- return null;
16784
- const message3 = isRecord4(entry.message) ? entry.message : null;
16785
- if (!firstMessage && entry.type === "message" && message3?.role === "user") {
16786
- const content = message3.content;
16787
- 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(" ") : "";
16788
- firstMessage = text.replaceAll("\0", "").trim().slice(0, HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) || null;
16789
- }
16790
- hasUser = entry.type === "message" && message3?.role === "user" || typeof entry.parentId === "string" && entries.get(entry.parentId) === true;
16791
- entries.set(entry.id, hasUser);
16792
- if (entry.type === "session_info")
16793
- name = typeof entry.name === "string" ? entry.name.trim() || null : null;
16794
- if (entry.type === "message" && (message3?.role === "user" || message3?.role === "assistant")) {
16795
- const time3 = typeof message3.timestamp === "number" ? message3.timestamp : typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : NaN;
16796
- if (Number.isFinite(time3))
16797
- updatedAt = time3;
16798
- }
16799
- }
16800
- } finally {
16801
- lines.close();
16802
- stream.destroy();
17547
+ this.#ended = true;
17548
+ if (this.#values.length !== 0)
17549
+ return;
17550
+ for (const resolve of this.#pending.splice(0))
17551
+ resolve({ done: true, value: void 0 });
17552
+ }
17553
+ #next() {
17554
+ const value = this.#values.shift();
17555
+ if (value !== void 0)
17556
+ return Promise.resolve({ done: false, value });
17557
+ if (this.#ended)
17558
+ return Promise.resolve({ done: true, value: void 0 });
17559
+ return new Promise((resolve) => this.#pending.push(resolve));
16803
17560
  }
16804
- if (!header)
16805
- return null;
16806
- if (!hasUser)
16807
- return null;
16808
- const after = await stat(file2);
16809
- if (!sameFile(before, after))
16810
- throw new PiSessionChangedError();
16811
- const cwd = await realpath2(String(header.cwd));
16812
- if (!(await stat(cwd)).isDirectory())
16813
- return null;
16814
- const nativeRef = nativeSessionRefSchema.safeParse({
16815
- harnessId: "pi",
16816
- nativeSessionId: header.id,
16817
- locator: { sessionFile: await realpath2(file2) },
16818
- formatVersion: 1
16819
- });
16820
- const candidate = harnessSessionImportCandidateSchema.safeParse({
16821
- nativeSessionId: header.id,
16822
- cwd,
16823
- title: name ?? firstMessage,
16824
- updatedAt: Math.floor(updatedAt),
16825
- running: null
16826
- });
16827
- return candidate.success && nativeRef.success ? { candidate: candidate.data, nativeRef: nativeRef.data } : null;
17561
+ };
17562
+
17563
+ // ../../harness-adapter/dist/diagnostics.js
17564
+ var DIAGNOSTIC_TAIL_MAX_LENGTH = 8e3;
17565
+ var SENSITIVE_VALUE_PATTERN = /(api[_-]?key|access[_-]?token|auth(?:orization)?|password|secret)(\s*[:=]\s*)([^\s,;]+)/giu;
17566
+ var BEARER_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]+/giu;
17567
+ function sanitizeDiagnosticTail(value) {
17568
+ const redacted = value.replace(BEARER_PATTERN, "Bearer [redacted]").replace(SENSITIVE_VALUE_PATTERN, "$1$2[redacted]");
17569
+ return redacted.length <= DIAGNOSTIC_TAIL_MAX_LENGTH ? redacted : redacted.slice(-DIAGNOSTIC_TAIL_MAX_LENGTH);
16828
17570
  }
16829
- async function readIdentity(file2, signal) {
16830
- const stream = createReadStream2(file2, { encoding: "utf8", signal });
16831
- const lines = createInterface2({ input: stream, crlfDelay: Infinity });
16832
- try {
16833
- for await (const line of lines) {
16834
- signal.throwIfAborted();
16835
- if (!line.trim())
16836
- continue;
16837
- let header;
16838
- try {
16839
- header = JSON.parse(line);
16840
- } catch {
16841
- return null;
16842
- }
16843
- return isRecord4(header) && header.type === "session" && header.version === 3 && typeof header.id === "string" ? header.id : null;
17571
+
17572
+ // ../../harness-adapter/dist/usage.js
17573
+ var tokenFields = [
17574
+ "inputTokens",
17575
+ "cachedInputTokens",
17576
+ "cacheWriteInputTokens",
17577
+ "outputTokens",
17578
+ "outputTokensPerSecond",
17579
+ "reasoningOutputTokens",
17580
+ "totalTokens",
17581
+ "contextWindowTokens",
17582
+ "contextUsedTokens"
17583
+ ];
17584
+ var safeIntegerFields = [
17585
+ "planFiveHourResetsAtUnix",
17586
+ "planSevenDayResetsAtUnix"
17587
+ ];
17588
+ var percentFields = [
17589
+ "cacheHitRatePercent",
17590
+ "planFiveHourUsedPercent",
17591
+ "planSevenDayUsedPercent"
17592
+ ];
17593
+ var usageFields = /* @__PURE__ */ new Set([
17594
+ ...tokenFields,
17595
+ ...safeIntegerFields,
17596
+ ...percentFields,
17597
+ "totalCostUsd",
17598
+ "totalCredits",
17599
+ "contextUsagePercent"
17600
+ ]);
17601
+ function isRecord3(value) {
17602
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17603
+ }
17604
+ function parseHostUsage(value) {
17605
+ if (!isRecord3(value))
17606
+ throw new Error("Harness Usage must be an object");
17607
+ const keys = Object.keys(value);
17608
+ if (keys.length === 0)
17609
+ throw new Error("Harness Usage must contain a reliable field");
17610
+ for (const key of keys) {
17611
+ if (!usageFields.has(key)) {
17612
+ throw new Error(`Harness Usage contains unknown field '${key}'`);
16844
17613
  }
16845
- return null;
16846
- } finally {
16847
- lines.close();
16848
- stream.destroy();
16849
17614
  }
16850
- }
16851
- var PiSessionImportIndex = class {
16852
- #location;
16853
- #cache = /* @__PURE__ */ new Map();
16854
- #listing;
16855
- constructor(environment) {
16856
- this.#location = piSessionImportDirectory(environment);
17615
+ for (const field of ["totalCredits", "contextUsagePercent"]) {
17616
+ const candidate = value[field];
17617
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
17618
+ throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
17619
+ }
16857
17620
  }
16858
- list(signal) {
16859
- this.#listing ??= this.#scan(signal).finally(() => {
16860
- this.#listing = void 0;
16861
- });
16862
- return this.#listing;
17621
+ for (const field of tokenFields) {
17622
+ const candidate = value[field];
17623
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
17624
+ throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
17625
+ }
16863
17626
  }
16864
- async #scan(signal) {
16865
- const { directory, flat } = this.#location;
16866
- const files = await sessionFiles(directory, flat, signal);
16867
- const next = /* @__PURE__ */ new Map();
16868
- const identities = /* @__PURE__ */ new Set();
16869
- const sources = [];
16870
- for (const file2 of files) {
16871
- signal.throwIfAborted();
16872
- try {
16873
- const fingerprint = await stat(file2);
16874
- const cached2 = this.#cache.get(file2);
16875
- const source = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source : await readCandidate(file2, signal);
16876
- if (!source)
16877
- continue;
16878
- if (!(await stat(source.candidate.cwd)).isDirectory())
16879
- continue;
16880
- if (identities.has(source.nativeRef.nativeSessionId))
16881
- throw new Error("Pi Session identity is ambiguous across files");
16882
- identities.add(source.nativeRef.nativeSessionId);
16883
- next.set(file2, { fingerprint, source });
16884
- sources.push(source);
16885
- } catch (error51) {
16886
- if (!missing(error51) && !(error51 instanceof PiSessionChangedError))
16887
- throw error51;
16888
- }
17627
+ for (const field of safeIntegerFields) {
17628
+ const candidate = value[field];
17629
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
17630
+ throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
16889
17631
  }
16890
- this.#cache = next;
16891
- return structuredClone(sources.sort((left, right) => right.candidate.updatedAt - left.candidate.updatedAt));
16892
17632
  }
16893
- async resolve(nativeSessionId, signal) {
16894
- const { directory, flat } = this.#location;
16895
- let selected;
16896
- for (const file2 of await sessionFiles(directory, flat, signal)) {
16897
- signal.throwIfAborted();
16898
- try {
16899
- const fingerprint = await stat(file2);
16900
- const cached2 = this.#cache.get(file2);
16901
- const id = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source.nativeRef.nativeSessionId : await readIdentity(file2, signal);
16902
- if (id !== nativeSessionId)
16903
- continue;
16904
- if (selected)
16905
- throw new Error("Pi Session identity is ambiguous across files");
16906
- selected = file2;
16907
- } catch (error51) {
16908
- if (!missing(error51))
16909
- throw error51;
16910
- }
17633
+ if (value.outputTokensPerSecond !== void 0 && (typeof value.outputTokensPerSecond !== "number" || !Number.isFinite(value.outputTokensPerSecond) || value.outputTokensPerSecond < 0)) {
17634
+ throw new Error("Harness Usage 'outputTokensPerSecond' must be a finite non-negative number");
17635
+ }
17636
+ if (value.totalCostUsd !== void 0 && (typeof value.totalCostUsd !== "number" || !Number.isFinite(value.totalCostUsd) || value.totalCostUsd < 0)) {
17637
+ throw new Error("Harness Usage 'totalCostUsd' must be a finite non-negative number");
17638
+ }
17639
+ for (const field of ["totalCredits", "contextUsagePercent"]) {
17640
+ const candidate = value[field];
17641
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
17642
+ throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
16911
17643
  }
16912
- if (!selected)
16913
- return null;
16914
- try {
16915
- const source = await readCandidate(selected, signal);
16916
- return source?.nativeRef.nativeSessionId === nativeSessionId ? source : null;
16917
- } catch (error51) {
16918
- if (missing(error51))
16919
- return null;
16920
- throw error51;
17644
+ }
17645
+ for (const field of percentFields) {
17646
+ const candidate = value[field];
17647
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0 || candidate > 100)) {
17648
+ throw new Error(`Harness Usage '${field}' must be between 0 and 100`);
16921
17649
  }
16922
17650
  }
16923
- };
17651
+ const hasContextUsed = value.contextUsedTokens !== void 0;
17652
+ const hasContextWindow = value.contextWindowTokens !== void 0;
17653
+ if (hasContextUsed !== hasContextWindow) {
17654
+ throw new Error("Harness Usage context fields must be provided together");
17655
+ }
17656
+ if (hasContextWindow && value.contextWindowTokens === 0) {
17657
+ throw new Error("Harness Usage 'contextWindowTokens' must be greater than zero");
17658
+ }
17659
+ if (value.planFiveHourResetsAtUnix !== void 0 && value.planFiveHourUsedPercent === void 0) {
17660
+ throw new Error("Harness Usage 'planFiveHourResetsAtUnix' must be provided with 'planFiveHourUsedPercent'");
17661
+ }
17662
+ if (value.planSevenDayResetsAtUnix !== void 0 && value.planSevenDayUsedPercent === void 0) {
17663
+ throw new Error("Harness Usage 'planSevenDayResetsAtUnix' must be provided with 'planSevenDayUsedPercent'");
17664
+ }
17665
+ return { ...value };
17666
+ }
16924
17667
 
16925
- // dist/pi-rpc-session.js
16926
- import { spawn, spawnSync } from "node:child_process";
16927
- import { randomUUID as randomUUID2 } from "node:crypto";
17668
+ // dist/pi-workflow-child-history.js
17669
+ import { createHash as createHash2 } from "node:crypto";
17670
+ import { constants } from "node:fs";
17671
+ import { open as open3 } from "node:fs/promises";
16928
17672
  import path5 from "node:path";
16929
-
16930
- // ../../harness-discovery/dist/environment.js
16931
- import fs from "node:fs";
16932
- import path3 from "node:path";
16933
- function targetPath(platform) {
16934
- return platform === "win32" ? path3.win32 : path3.posix;
17673
+ function record4(value) {
17674
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16935
17675
  }
16936
- function environmentValue(environment, name) {
16937
- const lowered = name.toLowerCase();
16938
- for (const [key, value] of Object.entries(environment)) {
16939
- if (key.toLowerCase() === lowered)
16940
- return value;
17676
+ var MAX_SESSION_BYTES = 8 * 1024 * 1024;
17677
+ async function childHistory(file2, parentSessionId, identity) {
17678
+ if (!path5.isAbsolute(file2))
17679
+ throw new Error("Pi child Session path is not absolute");
17680
+ const handle = await open3(file2, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
17681
+ try {
17682
+ const stat2 = await handle.stat();
17683
+ if (!stat2.isFile() || stat2.size > MAX_SESSION_BYTES)
17684
+ throw new Error("Pi child Session exceeds read bounds");
17685
+ const buffer = Buffer.alloc(MAX_SESSION_BYTES + 1);
17686
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
17687
+ if (bytesRead > MAX_SESSION_BYTES)
17688
+ throw new Error("Pi child Session exceeds read bounds");
17689
+ const values = buffer.subarray(0, bytesRead).toString("utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
17690
+ const header = values[0];
17691
+ if (!record4(header) || header.type !== "session" || typeof header.id !== "string" || header.version !== 3)
17692
+ throw new Error("Unsupported Pi child Session header");
17693
+ const entries = [];
17694
+ for (const entry of values.slice(1)) {
17695
+ const parsed = jsonValueSchema.safeParse(entry);
17696
+ if (!parsed.success || !record4(parsed.data) || typeof parsed.data.id !== "string")
17697
+ throw new Error("Malformed Pi child Session entry");
17698
+ entries.push(parsed.data);
17699
+ }
17700
+ const history = { entries, leafId: String(entries.at(-1)?.id ?? "") || null };
17701
+ const snapshot = mapPiSnapshot(history, { sessionId: parentSessionId, model: null });
17702
+ const prefix = createHash2("sha256").update(identity).digest("hex");
17703
+ return {
17704
+ turns: snapshot.turns.map((turn) => {
17705
+ const readonlyTurn = {
17706
+ ...turn,
17707
+ nativeTurnRef: {
17708
+ ...turn.nativeTurnRef,
17709
+ nativeTurnKey: `${prefix}:${turn.nativeTurnRef.nativeTurnKey}`
17710
+ }
17711
+ };
17712
+ delete readonlyTurn.checkpoint;
17713
+ return readonlyTurn;
17714
+ })
17715
+ };
17716
+ } finally {
17717
+ await handle.close();
16941
17718
  }
16942
- return void 0;
16943
17719
  }
16944
- function pathDelimiter(platform) {
16945
- return platform === "win32" ? ";" : ":";
17720
+ async function readPiWorkflowChild(history, parentSessionId, address) {
17721
+ for (const entry of activePiEntries(history).reverse()) {
17722
+ const message3 = entry.message;
17723
+ if (!record4(message3) || message3.role !== "toolResult" || message3.toolName !== "subagent")
17724
+ continue;
17725
+ const summary = piWorkflowSummary(message3);
17726
+ if (!summary || summary.workflowRunId !== address.workflowRunId || summary.parentToolCallId !== message3.toolCallId)
17727
+ continue;
17728
+ const child = summary.children.find((candidate) => candidate.childId === address.childId);
17729
+ if (!child)
17730
+ break;
17731
+ const details = message3.details;
17732
+ if (!record4(details) || !Array.isArray(details.results))
17733
+ break;
17734
+ const result = details.results.findLast((candidate) => record4(candidate) && candidate.workflowKey === address.childId);
17735
+ if (!record4(result))
17736
+ break;
17737
+ const id = piWorkflowSubagentId(address);
17738
+ if (typeof result.sessionFile === "string") {
17739
+ try {
17740
+ const snapshot = await childHistory(result.sessionFile, parentSessionId, id);
17741
+ if (snapshot.turns.length)
17742
+ return { ok: true, value: snapshot };
17743
+ } catch {
17744
+ }
17745
+ }
17746
+ if (typeof result.finalOutput === "string" && result.finalOutput.length > 0) {
17747
+ const output = result.finalOutput.slice(0, 64 * 1024);
17748
+ return {
17749
+ ok: true,
17750
+ value: piSubagentSnapshot(parentSessionId, id, {
17751
+ kind: "pi-subagents.inspect-reply",
17752
+ version: 1,
17753
+ requestId: "native-workflow-result",
17754
+ status: child.state === "completed" ? "complete" : child.state === "failed" ? "failed" : child.state === "interrupted" ? "paused" : "running",
17755
+ ...typeof result.task === "string" ? { task: result.task.slice(0, 4096) } : {},
17756
+ finalOutput: `[Pi subagent: saved native result; Session transcript unavailable.]
17757
+ ${output}`,
17758
+ truncated: {
17759
+ task: typeof result.task === "string" && result.task.length > 4096,
17760
+ messages: 0,
17761
+ finalOutput: output.length < result.finalOutput.length
17762
+ }
17763
+ })
17764
+ };
17765
+ }
17766
+ break;
17767
+ }
17768
+ return {
17769
+ ok: false,
17770
+ error: {
17771
+ code: "sessionNotFound",
17772
+ message: "Pi workflow child has no published transcript/result in this parent's active history",
17773
+ retryable: true
17774
+ }
17775
+ };
16946
17776
  }
16947
- function pathDirectories(environment, platform) {
16948
- return (environmentValue(environment, "PATH") ?? "").split(pathDelimiter(platform)).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean);
17777
+
17778
+ // dist/pi-subagent-history.js
17779
+ import { constants as constants2 } from "node:fs";
17780
+ import { open as open4 } from "node:fs/promises";
17781
+ import path6 from "node:path";
17782
+ function record5(value) {
17783
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16949
17784
  }
16950
- function executableExtensions(command, platform, environment) {
16951
- if (platform !== "win32")
16952
- return [""];
16953
- if (targetPath(platform).extname(command) !== "")
16954
- return [""];
16955
- return (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean);
17785
+ function state(value) {
17786
+ return value === "pending" ? "queued" : value === "completed" ? "complete" : value;
16956
17787
  }
16957
- function isExecutableFile(filePath, platform) {
16958
- try {
16959
- fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
16960
- return fs.statSync(filePath).isFile();
16961
- } catch {
16962
- return false;
17788
+ function piSubagentArtifact(value, runId, parentSessionId) {
17789
+ if (!record5(value) || value.lifecycleArtifactVersion !== 3 || value.runId !== runId || value.sessionId !== parentSessionId || !["single", "parallel", "chain", "workflow"].includes(String(value.mode)))
17790
+ return null;
17791
+ if (value.steps !== void 0 && (!Array.isArray(value.steps) || value.steps.length > 128))
17792
+ return null;
17793
+ const steps = Array.isArray(value.steps) ? value.steps : [];
17794
+ const children = [];
17795
+ for (const [index, step] of steps.entries()) {
17796
+ if (!record5(step) || typeof step.agent !== "string")
17797
+ return null;
17798
+ children.push({
17799
+ id: step.workflowKey ?? step.runId ?? `step:${index}`,
17800
+ kind: "step",
17801
+ label: step.label ?? step.agent,
17802
+ state: state(step.status)
17803
+ });
16963
17804
  }
17805
+ return parsePiSubagentStatus({
17806
+ type: "extension_ui_request",
17807
+ method: "setWidget",
17808
+ widgetKey: "subagent-async",
17809
+ widgetLines: [
17810
+ "PI_SUBAGENT_ASYNC_JSON:" + JSON.stringify({
17811
+ kind: "pi-subagents.async-status-snapshot",
17812
+ version: 1,
17813
+ runs: [
17814
+ {
17815
+ id: runId,
17816
+ kind: value.mode === "single" ? "subagent" : "workflow",
17817
+ label: "Pi subagent",
17818
+ state: value.state,
17819
+ children
17820
+ }
17821
+ ]
17822
+ })
17823
+ ]
17824
+ });
16964
17825
  }
16965
- function subdirectoryNames(directory) {
16966
- try {
16967
- return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
16968
- } catch {
16969
- return [];
17826
+ async function restorePiSubagents(history, parentSessionId, observer) {
17827
+ const receipts = /* @__PURE__ */ new Map();
17828
+ for (const entry of activePiEntries(history)) {
17829
+ if (!record5(entry.message) || entry.message.role !== "toolResult" || entry.message.toolName !== "subagent" || entry.message.isError !== false || !record5(entry.message.details))
17830
+ continue;
17831
+ const details = entry.message.details;
17832
+ 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)
17833
+ continue;
17834
+ receipts.set(details.asyncId, details.asyncDir);
17835
+ }
17836
+ for (const [id, directory] of [...receipts].slice(-128)) {
17837
+ let file2;
17838
+ try {
17839
+ file2 = await open4(path6.join(directory, "status.json"), constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
17840
+ const stat2 = await file2.stat();
17841
+ if (!stat2.isFile() || stat2.size > 1024 * 1024)
17842
+ continue;
17843
+ const buffer = Buffer.alloc(1024 * 1024 + 1);
17844
+ const { bytesRead } = await file2.read(buffer, 0, buffer.length, 0);
17845
+ if (bytesRead > 1024 * 1024)
17846
+ continue;
17847
+ const value = JSON.parse(buffer.subarray(0, bytesRead).toString("utf8"));
17848
+ const runs = piSubagentArtifact(value, id, parentSessionId);
17849
+ if (runs)
17850
+ observer.restore(runs);
17851
+ } catch {
17852
+ } finally {
17853
+ await file2?.close();
17854
+ }
16970
17855
  }
16971
- }
16972
- function newestFirst(names) {
16973
- return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
16974
17856
  }
16975
17857
 
16976
- // ../../harness-discovery/dist/node-runtime.js
16977
- import path4 from "node:path";
16978
- function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
16979
- const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
16980
- const delimiter = platform === "win32" ? ";" : ":";
16981
- const runtimeDirectory = path4.dirname(runtimeExecutable);
16982
- const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
16983
- const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
16984
- if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
16985
- directories.unshift(runtimeDirectory);
17858
+ // dist/pi-last-turn-rollback.js
17859
+ function modelFromState(state2) {
17860
+ if (state2.provider === null && state2.modelId === null)
17861
+ return null;
17862
+ if (state2.provider === null || state2.modelId === null) {
17863
+ throw new Error("Pi state contains a partial Model identity");
16986
17864
  }
16987
- return { ...environment, [pathKey]: directories.join(delimiter) };
17865
+ return { provider: state2.provider, id: state2.modelId };
16988
17866
  }
16989
-
16990
- // ../../harness-discovery/dist/resolve.js
16991
- import os2 from "node:os";
16992
-
16993
- // ../../harness-discovery/dist/version-managers.js
16994
- function versionManagerBinaryDirectories(context) {
16995
- const { platform, environment, home } = context;
16996
- const list = context.subdirectories ?? subdirectoryNames;
16997
- const pathFlavor = targetPath(platform);
16998
- const value = (name) => environmentValue(environment, name);
16999
- const directories = [];
17000
- const versioned = (root, ...tail) => {
17001
- for (const version2 of newestFirst(list(root))) {
17002
- directories.push(pathFlavor.join(root, version2, ...tail));
17003
- }
17004
- };
17005
- if (platform === "win32") {
17006
- const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
17007
- const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
17008
- versioned(pathFlavor.join(appData, "nvm"));
17009
- versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
17010
- directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
17011
- directories.push(pathFlavor.join(home, ".bun", "bin"));
17012
- const pnpmHome2 = value("PNPM_HOME");
17013
- if (pnpmHome2)
17014
- directories.push(pnpmHome2);
17015
- directories.push(pathFlavor.join(localAppData, "pnpm"));
17016
- return directories;
17867
+ async function rollbackPiLastTurn(transport, sourceSessionId, cwd) {
17868
+ const startupState = transport.state;
17869
+ const startupSessionId = startupState.sessionId;
17870
+ const currentModel = modelFromState(startupState);
17871
+ const currentThinking = startupState.thinkingLevel;
17872
+ const copiedHistory = await transport.getEntries();
17873
+ const boundary = resolvePiLastTurnBoundary(copiedHistory);
17874
+ if (!boundary)
17875
+ return { ok: false, reason: "empty" };
17876
+ const sourceSnapshot = mapPiSnapshot(copiedHistory, {
17877
+ sessionId: startupSessionId,
17878
+ model: currentModel
17879
+ });
17880
+ let state2 = await transport.fork(boundary.lastUserEntryId);
17881
+ if (state2.sessionId === sourceSessionId || state2.sessionId === startupSessionId) {
17882
+ throw new Error("Pi last-Turn rollback did not create a distinct Native Session");
17017
17883
  }
17018
- versioned(pathFlavor.join(value("NVM_DIR") ?? pathFlavor.join(home, ".nvm"), "versions", "node"), "bin");
17019
- const fnmRoots = [
17020
- value("FNM_DIR"),
17021
- pathFlavor.join(home, ".local", "share", "fnm"),
17022
- pathFlavor.join(home, "Library", "Application Support", "fnm")
17023
- ].filter((root) => root !== void 0);
17024
- for (const root of fnmRoots) {
17025
- versioned(pathFlavor.join(root, "node-versions"), "installation", "bin");
17884
+ if (!samePiModel(modelFromState(state2), currentModel)) {
17885
+ if (!currentModel)
17886
+ throw new Error("Pi last-Turn rollback changed the current Model");
17887
+ state2 = await transport.selectModel(currentModel);
17026
17888
  }
17027
- const voltaHome = value("VOLTA_HOME") ?? pathFlavor.join(home, ".volta");
17028
- versioned(pathFlavor.join(voltaHome, "tools", "image", "node"), "bin");
17029
- directories.push(pathFlavor.join(voltaHome, "bin"));
17030
- const asdfHome = value("ASDF_DATA_DIR") ?? pathFlavor.join(home, ".asdf");
17031
- versioned(pathFlavor.join(asdfHome, "installs", "nodejs"), "bin");
17032
- directories.push(pathFlavor.join(asdfHome, "shims"));
17033
- const nodenvHome = value("NODENV_ROOT") ?? pathFlavor.join(home, ".nodenv");
17034
- versioned(pathFlavor.join(nodenvHome, "versions"), "bin");
17035
- directories.push(pathFlavor.join(nodenvHome, "shims"));
17036
- versioned(pathFlavor.join(value("N_PREFIX") ?? "/usr/local", "n", "versions", "node"), "bin");
17037
- directories.push(pathFlavor.join(home, ".bun", "bin"));
17038
- const pnpmHome = value("PNPM_HOME");
17039
- if (pnpmHome)
17040
- directories.push(pnpmHome);
17041
- directories.push(pathFlavor.join(home, "Library", "pnpm"));
17042
- directories.push(pathFlavor.join(home, ".local", "share", "pnpm"));
17043
- for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
17044
- for (const formula of newestFirst(list(prefix).filter((name) => name.startsWith("node@")))) {
17045
- directories.push(pathFlavor.join(prefix, formula, "bin"));
17889
+ if (state2.thinkingLevel !== currentThinking) {
17890
+ if (!currentThinking)
17891
+ throw new Error("Pi last-Turn rollback changed current Thinking");
17892
+ state2 = await transport.selectThinkingOption(currentThinking);
17893
+ }
17894
+ if (!samePiModel(modelFromState(state2), currentModel) || state2.thinkingLevel !== currentThinking) {
17895
+ throw new Error("Pi last-Turn rollback could not restore current Model and Thinking");
17896
+ }
17897
+ const snapshot = mapPiSnapshot(await transport.getEntries(), {
17898
+ sessionId: state2.sessionId,
17899
+ model: modelFromState(state2)
17900
+ });
17901
+ const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
17902
+ const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
17903
+ if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
17904
+ throw new Error("Pi last-Turn rollback did not produce the exact retained history prefix");
17905
+ }
17906
+ try {
17907
+ await transport.verifySessionCwd(cwd);
17908
+ return { ok: true, unpersisted: false };
17909
+ } catch (error51) {
17910
+ if (snapshot.turns.length === 0 && error51?.code === "ENOENT") {
17911
+ return { ok: true, unpersisted: true };
17046
17912
  }
17913
+ throw error51;
17047
17914
  }
17048
- return directories;
17049
17915
  }
17050
17916
 
17051
- // ../../harness-discovery/dist/resolve.js
17052
- var VERSION_MANAGER_ROOTS = "<version-managers>";
17053
- function installRootExtensions(platform) {
17054
- return platform === "win32" ? [".exe", ".cmd"] : [""];
17917
+ // dist/pi-session-import.js
17918
+ import { createReadStream as createReadStream2 } from "node:fs";
17919
+ import { opendir, realpath as realpath3, stat } from "node:fs/promises";
17920
+ import os3 from "node:os";
17921
+ import path7 from "node:path";
17922
+ import { createInterface as createInterface2 } from "node:readline";
17923
+ var PiSessionChangedError = class extends Error {
17924
+ constructor() {
17925
+ super("Pi Session changed during discovery; refresh and retry");
17926
+ }
17927
+ };
17928
+ function sameFile(left, right) {
17929
+ return left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs && left.ino === right.ino && left.dev === right.dev;
17055
17930
  }
17056
- function resolveHomeDirectory(input) {
17057
- return input.homeDirectory ?? environmentValue(input.environment, "HOME") ?? environmentValue(input.environment, "USERPROFILE") ?? os2.homedir();
17931
+ function isRecord4(value) {
17932
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17058
17933
  }
17059
- function templateVariables(environment, platform, home) {
17060
- const pathFlavor = targetPath(platform);
17934
+ function missing(error51) {
17935
+ return isRecord4(error51) && error51.code === "ENOENT";
17936
+ }
17937
+ function expandDirectory(value, home) {
17938
+ return path7.resolve(value === "~" ? home : value.startsWith(`~${path7.sep}`) || value.startsWith("~/") ? path7.join(home, value.slice(2)) : value);
17939
+ }
17940
+ function piSessionImportDirectory(environment) {
17941
+ const home = (process.platform === "win32" ? environment.USERPROFILE : environment.HOME) || os3.homedir();
17942
+ const custom2 = environment.PI_CODING_AGENT_SESSION_DIR;
17943
+ if (custom2)
17944
+ return { directory: expandDirectory(custom2, home), flat: true };
17945
+ const agent = environment.PI_CODING_AGENT_DIR;
17061
17946
  return {
17062
- HOME: home,
17063
- USERPROFILE: home,
17064
- APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
17065
- LOCALAPPDATA: environmentValue(environment, "LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local")
17947
+ directory: path7.join(agent ? expandDirectory(agent, home) : path7.join(home, ".pi", "agent"), "sessions"),
17948
+ flat: false
17066
17949
  };
17067
17950
  }
17068
- function joinTemplate(platform, value) {
17069
- const pathFlavor = targetPath(platform);
17070
- const segments = value.split("/");
17071
- const head = segments[0] ?? "";
17072
- const tail = segments.slice(1);
17073
- if (head === "")
17074
- return pathFlavor.join(pathFlavor.sep, ...tail);
17075
- return tail.length === 0 ? head : pathFlavor.join(head, ...tail);
17951
+ async function sessionFiles(directory, flat, signal) {
17952
+ const files = [];
17953
+ const visit = async (dir, projectLevel) => {
17954
+ signal.throwIfAborted();
17955
+ const entries = await opendir(dir).catch((error51) => {
17956
+ if (missing(error51))
17957
+ return null;
17958
+ throw error51;
17959
+ });
17960
+ if (!entries)
17961
+ return;
17962
+ for await (const entry of entries) {
17963
+ signal.throwIfAborted();
17964
+ if (projectLevel && entry.isDirectory())
17965
+ await visit(path7.join(dir, entry.name), false);
17966
+ else if (!projectLevel && entry.isFile() && entry.name.endsWith(".jsonl")) {
17967
+ files.push(path7.join(dir, entry.name));
17968
+ }
17969
+ }
17970
+ };
17971
+ await visit(directory, !flat);
17972
+ return files;
17076
17973
  }
17077
- function expandInstallRoot(template, environment, platform, home) {
17078
- const variables = templateVariables(environment, platform, home);
17079
- let unresolved = false;
17080
- const substituted = template.replace(/^~(?=\/|$)/u, home).replace(/\$\{(\w+)\}/gu, (_match, name) => {
17081
- const value = variables[name] ?? environmentValue(environment, name);
17082
- if (value === void 0 || value === "") {
17083
- unresolved = true;
17084
- return "";
17974
+ async function readCandidate(file2, signal) {
17975
+ const before = await stat(file2);
17976
+ if (!before.isFile() || before.size === 0)
17977
+ return null;
17978
+ const stream = createReadStream2(file2, { encoding: "utf8", signal, end: before.size - 1 });
17979
+ const lines = createInterface2({ input: stream, crlfDelay: Infinity });
17980
+ let header;
17981
+ let name = null;
17982
+ let firstMessage = null;
17983
+ let hasUser = false;
17984
+ let updatedAt = before.mtimeMs;
17985
+ const entries = /* @__PURE__ */ new Map();
17986
+ try {
17987
+ for await (const line of lines) {
17988
+ signal.throwIfAborted();
17989
+ if (!line.trim())
17990
+ continue;
17991
+ let entry;
17992
+ try {
17993
+ entry = JSON.parse(line);
17994
+ } catch {
17995
+ return null;
17996
+ }
17997
+ if (!isRecord4(entry))
17998
+ return null;
17999
+ if (!header) {
18000
+ if (entry.type !== "session" || entry.version !== 3 || typeof entry.id !== "string" || typeof entry.cwd !== "string" || !path7.isAbsolute(entry.cwd))
18001
+ return null;
18002
+ header = entry;
18003
+ continue;
18004
+ }
18005
+ if (typeof entry.id !== "string" || entry.id.length === 0 || entries.has(entry.id) || entry.parentId !== null && (typeof entry.parentId !== "string" || !entries.has(entry.parentId)))
18006
+ return null;
18007
+ const message3 = isRecord4(entry.message) ? entry.message : null;
18008
+ if (!firstMessage && entry.type === "message" && message3?.role === "user") {
18009
+ const content = message3.content;
18010
+ 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(" ") : "";
18011
+ firstMessage = text2.replaceAll("\0", "").trim().slice(0, HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) || null;
18012
+ }
18013
+ hasUser = entry.type === "message" && message3?.role === "user" || typeof entry.parentId === "string" && entries.get(entry.parentId) === true;
18014
+ entries.set(entry.id, hasUser);
18015
+ if (entry.type === "session_info")
18016
+ name = typeof entry.name === "string" ? entry.name.trim() || null : null;
18017
+ if (entry.type === "message" && (message3?.role === "user" || message3?.role === "assistant")) {
18018
+ const time3 = typeof message3.timestamp === "number" ? message3.timestamp : typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : NaN;
18019
+ if (Number.isFinite(time3))
18020
+ updatedAt = time3;
18021
+ }
17085
18022
  }
17086
- return value;
18023
+ } finally {
18024
+ lines.close();
18025
+ stream.destroy();
18026
+ }
18027
+ if (!header)
18028
+ return null;
18029
+ if (!hasUser)
18030
+ return null;
18031
+ const after = await stat(file2);
18032
+ if (!sameFile(before, after))
18033
+ throw new PiSessionChangedError();
18034
+ const cwd = await realpath3(String(header.cwd));
18035
+ if (!(await stat(cwd)).isDirectory())
18036
+ return null;
18037
+ const nativeRef = nativeSessionRefSchema.safeParse({
18038
+ harnessId: "pi",
18039
+ nativeSessionId: header.id,
18040
+ locator: { sessionFile: await realpath3(file2) },
18041
+ formatVersion: 1
17087
18042
  });
17088
- return unresolved ? void 0 : joinTemplate(platform, substituted);
18043
+ const candidate = harnessSessionImportCandidateSchema.safeParse({
18044
+ nativeSessionId: header.id,
18045
+ cwd,
18046
+ title: name ?? firstMessage,
18047
+ updatedAt: Math.floor(updatedAt),
18048
+ running: null
18049
+ });
18050
+ return candidate.success && nativeRef.success ? { candidate: candidate.data, nativeRef: nativeRef.data } : null;
17089
18051
  }
17090
- function installRootDirectories(spec, input, dependencies, platform, home) {
17091
- const templates = (platform === "win32" ? spec.installRoots?.windows : spec.installRoots?.posix) ?? [];
17092
- const directories = [];
17093
- for (const template of templates) {
17094
- if (template === VERSION_MANAGER_ROOTS) {
17095
- directories.push(...versionManagerBinaryDirectories({
17096
- platform,
17097
- environment: input.environment,
17098
- home,
17099
- ...dependencies.subdirectories ? { subdirectories: dependencies.subdirectories } : {}
17100
- }));
17101
- continue;
18052
+ async function readIdentity(file2, signal) {
18053
+ const stream = createReadStream2(file2, { encoding: "utf8", signal });
18054
+ const lines = createInterface2({ input: stream, crlfDelay: Infinity });
18055
+ try {
18056
+ for await (const line of lines) {
18057
+ signal.throwIfAborted();
18058
+ if (!line.trim())
18059
+ continue;
18060
+ let header;
18061
+ try {
18062
+ header = JSON.parse(line);
18063
+ } catch {
18064
+ return null;
18065
+ }
18066
+ return isRecord4(header) && header.type === "session" && header.version === 3 && typeof header.id === "string" ? header.id : null;
17102
18067
  }
17103
- const directory = expandInstallRoot(template, input.environment, platform, home);
17104
- if (directory !== void 0)
17105
- directories.push(directory);
18068
+ return null;
18069
+ } finally {
18070
+ lines.close();
18071
+ stream.destroy();
17106
18072
  }
17107
- return directories;
17108
18073
  }
17109
- function harnessCandidates(spec, input, dependencies = {}) {
17110
- const platform = input.platform ?? process.platform;
17111
- const pathFlavor = targetPath(platform);
17112
- const configured = input.command ?? (spec.commandEnvironmentVariable ? environmentValue(input.environment, spec.commandEnvironmentVariable) : void 0);
17113
- const command = configured ?? spec.command;
17114
- if (pathFlavor.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
17115
- return [{ candidate: command, source: "configured" }];
18074
+ var PiSessionImportIndex = class {
18075
+ #location;
18076
+ #cache = /* @__PURE__ */ new Map();
18077
+ #listing;
18078
+ constructor(environment) {
18079
+ this.#location = piSessionImportDirectory(environment);
17116
18080
  }
17117
- const candidates = [];
17118
- const extensions = executableExtensions(command, platform, input.environment);
17119
- for (const directory of pathDirectories(input.environment, platform)) {
17120
- for (const extension of extensions) {
17121
- candidates.push({
17122
- candidate: pathFlavor.join(directory, command + extension),
17123
- source: "path"
17124
- });
17125
- }
18081
+ list(signal) {
18082
+ this.#listing ??= this.#scan(signal).finally(() => {
18083
+ this.#listing = void 0;
18084
+ });
18085
+ return this.#listing;
17126
18086
  }
17127
- if (configured !== void 0)
17128
- return candidates;
17129
- const home = resolveHomeDirectory(input);
17130
- for (const directory of installRootDirectories(spec, input, dependencies, platform, home)) {
17131
- for (const extension of installRootExtensions(platform)) {
17132
- candidates.push({
17133
- candidate: pathFlavor.join(directory, spec.command + extension),
17134
- source: "install-root"
17135
- });
18087
+ async #scan(signal) {
18088
+ const { directory, flat } = this.#location;
18089
+ const files = await sessionFiles(directory, flat, signal);
18090
+ const next = /* @__PURE__ */ new Map();
18091
+ const identities = /* @__PURE__ */ new Set();
18092
+ const sources = [];
18093
+ for (const file2 of files) {
18094
+ signal.throwIfAborted();
18095
+ try {
18096
+ const fingerprint = await stat(file2);
18097
+ const cached2 = this.#cache.get(file2);
18098
+ const source = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source : await readCandidate(file2, signal);
18099
+ if (!source)
18100
+ continue;
18101
+ if (!(await stat(source.candidate.cwd)).isDirectory())
18102
+ continue;
18103
+ if (identities.has(source.nativeRef.nativeSessionId))
18104
+ throw new Error("Pi Session identity is ambiguous across files");
18105
+ identities.add(source.nativeRef.nativeSessionId);
18106
+ next.set(file2, { fingerprint, source });
18107
+ sources.push(source);
18108
+ } catch (error51) {
18109
+ if (!missing(error51) && !(error51 instanceof PiSessionChangedError))
18110
+ throw error51;
18111
+ }
17136
18112
  }
18113
+ this.#cache = next;
18114
+ return structuredClone(sources.sort((left, right) => right.candidate.updatedAt - left.candidate.updatedAt));
17137
18115
  }
17138
- return candidates;
17139
- }
17140
- function resolveHarnessExecutable(spec, input, dependencies = {}) {
17141
- const platform = input.platform ?? process.platform;
17142
- const isExecutable = dependencies.isExecutable ?? ((candidate) => isExecutableFile(candidate, platform));
17143
- const runnable = spec.runnableCandidate ?? ((candidate) => candidate);
17144
- const context = { platform, isExecutable };
17145
- for (const { candidate, source } of harnessCandidates(spec, input, dependencies)) {
17146
- const executable = runnable(candidate, context);
17147
- if (executable !== void 0 && isExecutable(executable))
17148
- return { executable, source };
17149
- }
17150
- return void 0;
17151
- }
17152
-
17153
- // dist/command.js
17154
- var piDiscoverySpec = {
17155
- id: "pi",
17156
- command: "pi",
17157
- commandEnvironmentVariable: "PI_COMMAND",
17158
- installRoots: {
17159
- posix: [
17160
- "~/.npm-global/bin",
17161
- "~/.local/bin",
17162
- VERSION_MANAGER_ROOTS,
17163
- "/opt/homebrew/bin",
17164
- "/usr/local/bin"
17165
- ],
17166
- windows: ["${APPDATA}/npm", "~/.local/bin", VERSION_MANAGER_ROOTS]
18116
+ async resolve(nativeSessionId, signal) {
18117
+ const { directory, flat } = this.#location;
18118
+ let selected;
18119
+ for (const file2 of await sessionFiles(directory, flat, signal)) {
18120
+ signal.throwIfAborted();
18121
+ try {
18122
+ const fingerprint = await stat(file2);
18123
+ const cached2 = this.#cache.get(file2);
18124
+ const id = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source.nativeRef.nativeSessionId : await readIdentity(file2, signal);
18125
+ if (id !== nativeSessionId)
18126
+ continue;
18127
+ if (selected)
18128
+ throw new Error("Pi Session identity is ambiguous across files");
18129
+ selected = file2;
18130
+ } catch (error51) {
18131
+ if (!missing(error51))
18132
+ throw error51;
18133
+ }
18134
+ }
18135
+ if (!selected)
18136
+ return null;
18137
+ try {
18138
+ const source = await readCandidate(selected, signal);
18139
+ return source?.nativeRef.nativeSessionId === nativeSessionId ? source : null;
18140
+ } catch (error51) {
18141
+ if (missing(error51))
18142
+ return null;
18143
+ throw error51;
18144
+ }
17167
18145
  }
17168
18146
  };
17169
- function resolvePiExecutable(input, dependencies = {}) {
17170
- const resolution = resolveHarnessExecutable(piDiscoverySpec, {
17171
- ...input.command ? { command: input.command } : {},
17172
- environment: input.environment,
17173
- ...dependencies.platform ? { platform: dependencies.platform } : {},
17174
- ...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {}
17175
- }, { ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {} });
17176
- return resolution?.executable ?? input.command ?? input.environment.PI_COMMAND ?? "pi";
17177
- }
18147
+
18148
+ // dist/pi-rpc-session.js
18149
+ import { spawn, spawnSync } from "node:child_process";
18150
+ import { randomUUID as randomUUID4 } from "node:crypto";
18151
+ import path8 from "node:path";
17178
18152
 
17179
18153
  // dist/pi-usage.js
17180
18154
  function isRecord5(value) {
@@ -17247,6 +18221,82 @@ function optionalPiStateContextUsage(value) {
17247
18221
  }
17248
18222
  }
17249
18223
 
18224
+ // dist/pi-subagent-rpc.js
18225
+ import { randomUUID as randomUUID3 } from "node:crypto";
18226
+ var PiSubagentRpc = class {
18227
+ send;
18228
+ timeoutMs;
18229
+ #handler;
18230
+ #latest;
18231
+ #pending = /* @__PURE__ */ new Map();
18232
+ constructor(send, timeoutMs) {
18233
+ this.send = send;
18234
+ this.timeoutMs = timeoutMs;
18235
+ }
18236
+ setHandler(handler) {
18237
+ this.#handler = handler;
18238
+ if (this.#latest)
18239
+ handler(this.#latest);
18240
+ }
18241
+ handle(value) {
18242
+ if (value.type !== "extension_ui_request" || value.method !== "setWidget" || value.widgetKey !== "subagent-async" && value.widgetKey !== "subagent-inspect")
18243
+ return false;
18244
+ const status = parsePiSubagentStatus(value);
18245
+ if (status) {
18246
+ this.#latest = status;
18247
+ this.#handler?.(status);
18248
+ }
18249
+ const reply = parsePiSubagentInspection(value);
18250
+ if (reply) {
18251
+ const pending = this.#pending.get(reply.requestId);
18252
+ if (pending) {
18253
+ this.#pending.delete(reply.requestId);
18254
+ clearTimeout(pending.timer);
18255
+ pending.resolve(reply);
18256
+ }
18257
+ }
18258
+ return true;
18259
+ }
18260
+ async inspect(nativeSubagentId) {
18261
+ const address = parsePiSubagentId(nativeSubagentId);
18262
+ const commands = await this.send("get_commands", {});
18263
+ const data = commands.data;
18264
+ if (!Array.isArray(data?.commands) || !data.commands.some((command) => command?.name === "subagents-inspect-rpc" && command.source === "extension")) {
18265
+ throw new Error("Installed Pi has no pi-subagents Host inspection command");
18266
+ }
18267
+ const requestId = randomUUID3();
18268
+ const reply = new Promise((resolve, reject) => {
18269
+ const timer = setTimeout(() => {
18270
+ this.#pending.delete(requestId);
18271
+ reject(new Error("Pi subagent inspection timed out"));
18272
+ }, this.timeoutMs);
18273
+ this.#pending.set(requestId, { resolve, reject, timer });
18274
+ });
18275
+ try {
18276
+ const message3 = `/subagents-inspect-rpc ${requestId} ${address.runId}${address.childId ? ` ${address.childId}` : ""} --lines 200`;
18277
+ const [, result] = await Promise.all([this.send("prompt", { message: message3 }), reply]);
18278
+ if (!result.error && (result.asyncId !== address.runId && result.asyncId !== address.childId || result.childId !== address.childId)) {
18279
+ throw new Error("Pi subagent inspection identity does not match the request");
18280
+ }
18281
+ return result;
18282
+ } finally {
18283
+ const pending = this.#pending.get(requestId);
18284
+ if (pending) {
18285
+ clearTimeout(pending.timer);
18286
+ this.#pending.delete(requestId);
18287
+ }
18288
+ }
18289
+ }
18290
+ close(error51 = new Error("Pi subagent inspection transport closed")) {
18291
+ for (const pending of this.#pending.values()) {
18292
+ clearTimeout(pending.timer);
18293
+ pending.reject(error51);
18294
+ }
18295
+ this.#pending.clear();
18296
+ this.#handler = void 0;
18297
+ }
18298
+ };
18299
+
17250
18300
  // dist/pi-rpc-session.js
17251
18301
  var PiRpcFaultError = class extends Error {
17252
18302
  kind;
@@ -17378,15 +18428,15 @@ function extractReasoningText(content) {
17378
18428
  return null;
17379
18429
  const type = String(content.type ?? "");
17380
18430
  if (type === "thinking" || type === "reasoning" || type === "thought") {
17381
- const text = content.thinking ?? content.reasoning ?? content.text ?? content.delta;
17382
- return typeof text === "string" ? text : null;
18431
+ const text2 = content.thinking ?? content.reasoning ?? content.text ?? content.delta;
18432
+ return typeof text2 === "string" ? text2 : null;
17383
18433
  }
17384
18434
  return null;
17385
18435
  }
17386
18436
  function assistantReasoning(value) {
17387
18437
  if (!isRecord6(value) || value.role !== "assistant" || !Array.isArray(value.content))
17388
18438
  return null;
17389
- return value.content.map(extractReasoningText).filter((text) => typeof text === "string").join("");
18439
+ return value.content.map(extractReasoningText).filter((text2) => typeof text2 === "string").join("");
17390
18440
  }
17391
18441
  function assistantFailure(value) {
17392
18442
  if (!isRecord6(value) || value.role !== "assistant")
@@ -17451,7 +18501,7 @@ function piRpcProcessCommand(options, dependencies = {}) {
17451
18501
  ...thinkingArguments,
17452
18502
  ...sessionArguments
17453
18503
  ];
17454
- const extension = path5.win32.extname(command).toLowerCase();
18504
+ const extension = path8.win32.extname(command).toLowerCase();
17455
18505
  if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
17456
18506
  return { command, arguments: arguments_, windowsVerbatimArguments: false };
17457
18507
  }
@@ -17493,6 +18543,7 @@ var PiRpcSession = class {
17493
18543
  #latestCacheHitRatePercent;
17494
18544
  #manualCompaction = null;
17495
18545
  #stderrTail = "";
18546
+ #subagents;
17496
18547
  constructor(options, processAdapter = nodeProcessAdapter) {
17497
18548
  if (options.sessionFile && options.forkSessionFile) {
17498
18549
  throw new Error("Pi RPC cannot combine Session resume and Fork startup");
@@ -17507,6 +18558,7 @@ var PiRpcSession = class {
17507
18558
  ...options
17508
18559
  };
17509
18560
  this.#processAdapter = processAdapter;
18561
+ this.#subagents = new PiSubagentRpc((type, payload) => this.#send(type, payload), this.#options.commandTimeoutMs);
17510
18562
  }
17511
18563
  get state() {
17512
18564
  if (!this.#state)
@@ -17516,6 +18568,12 @@ var PiRpcSession = class {
17516
18568
  get stderrTail() {
17517
18569
  return this.#stderrTail;
17518
18570
  }
18571
+ setSubagentStatusHandler(handler) {
18572
+ this.#subagents.setHandler(handler);
18573
+ }
18574
+ inspectSubagent(id) {
18575
+ return this.#subagents.inspect(id);
18576
+ }
17519
18577
  setAutonomousTurnHandler(handler) {
17520
18578
  this.#autonomousTurnHandler = handler;
17521
18579
  }
@@ -17685,13 +18743,13 @@ var PiRpcSession = class {
17685
18743
  throw fault;
17686
18744
  }
17687
18745
  }
17688
- async runTurn(text, onEvent) {
18746
+ async runTurn(text2, onEvent) {
17689
18747
  if (!this.#child || !this.#state || this.#closed || this.#failed) {
17690
18748
  throw new Error("Pi RPC Session is unavailable");
17691
18749
  }
17692
18750
  if (this.#activeTurn)
17693
18751
  throw new Error("Pi RPC Session already has an active Turn");
17694
- if (text.length === 0)
18752
+ if (text2.length === 0)
17695
18753
  throw new Error("Pi text Turn must not be empty");
17696
18754
  const settled = new Promise((resolve, reject) => {
17697
18755
  this.#activeTurn = {
@@ -17720,7 +18778,7 @@ var PiRpcSession = class {
17720
18778
  };
17721
18779
  });
17722
18780
  try {
17723
- await this.#send("prompt", { message: text });
18781
+ await this.#send("prompt", { message: text2 });
17724
18782
  } catch (error51) {
17725
18783
  this.#rejectActiveTurn(error51 instanceof Error ? error51 : new Error(message2(error51)));
17726
18784
  }
@@ -17840,6 +18898,8 @@ var PiRpcSession = class {
17840
18898
  this.#handleResponse(value);
17841
18899
  return;
17842
18900
  }
18901
+ if (this.#subagents.handle(value))
18902
+ return;
17843
18903
  if (value.type === "compaction_start") {
17844
18904
  this.#compactionActive = true;
17845
18905
  this.#compactionTurn = this.#activeTurn;
@@ -17954,7 +19014,7 @@ var PiRpcSession = class {
17954
19014
  const active = {
17955
19015
  origin: "autonomous",
17956
19016
  autonomousEvents: events,
17957
- nativeTurnKey: assistantMessageId(value) ?? randomUUID2(),
19017
+ nativeTurnKey: assistantMessageId(value) ?? randomUUID4(),
17958
19018
  nativeCancellationObserved: false,
17959
19019
  text: "",
17960
19020
  assistantMessageId: null,
@@ -18156,13 +19216,13 @@ var PiRpcSession = class {
18156
19216
  async #confirmSettledTurn(active) {
18157
19217
  try {
18158
19218
  const response = await this.#send("get_state", {});
18159
- const state = parseSessionState(response);
19219
+ const state2 = parseSessionState(response);
18160
19220
  if (parseSessionStreaming(response)) {
18161
19221
  throw new PiRpcFaultError("protocolError", "Pi RPC agent_settled state is still Streaming");
18162
19222
  }
18163
19223
  if (this.#activeTurn !== active)
18164
19224
  return;
18165
- this.#state = state;
19225
+ this.#state = state2;
18166
19226
  active.settlement = "confirmed";
18167
19227
  this.#finishSettledTurn(active);
18168
19228
  } catch (error51) {
@@ -18217,7 +19277,7 @@ var PiRpcSession = class {
18217
19277
  if (active.assistantMessageId !== null && active.reasoningMessageOpen) {
18218
19278
  active.onEvent({ type: "reasoning.completed", messageId: active.assistantMessageId });
18219
19279
  }
18220
- const messageId = assistantMessageId(value) ?? randomUUID2();
19280
+ const messageId = assistantMessageId(value) ?? randomUUID4();
18221
19281
  active.assistantMessageId = messageId;
18222
19282
  active.sawStreamedMessageText = false;
18223
19283
  active.sawStreamedMessageReasoning = false;
@@ -18278,7 +19338,7 @@ var PiRpcSession = class {
18278
19338
  if (!child?.stdin.writable || this.#closed || this.#failed) {
18279
19339
  return Promise.reject(new Error("Pi RPC stdin is unavailable"));
18280
19340
  }
18281
- const id = `codexhost-${randomUUID2()}`;
19341
+ const id = `codexhost-${randomUUID4()}`;
18282
19342
  return new Promise((resolve, reject) => {
18283
19343
  const pending = {
18284
19344
  command: type,
@@ -18364,6 +19424,7 @@ var PiRpcSession = class {
18364
19424
  }
18365
19425
  }
18366
19426
  #rejectAll(error51) {
19427
+ this.#subagents.close(error51);
18367
19428
  for (const pending of this.#pending.values()) {
18368
19429
  if (pending.timeout)
18369
19430
  clearTimeout(pending.timeout);
@@ -18442,38 +19503,38 @@ function normalizedError(error51, fallbackCode) {
18442
19503
  function invalidState(message3) {
18443
19504
  return { code: "invalidState", message: message3, retryable: false };
18444
19505
  }
18445
- function nativeModelFromState(state) {
18446
- if (state.provider === null && state.modelId === null)
19506
+ function nativeModelFromState(state2) {
19507
+ if (state2.provider === null && state2.modelId === null)
18447
19508
  return null;
18448
- if (state.provider === null || state.modelId === null) {
19509
+ if (state2.provider === null || state2.modelId === null) {
18449
19510
  throw new PiRpcFaultError("protocolError", "Pi state contains a partial Model identity");
18450
19511
  }
18451
- return { provider: state.provider, id: state.modelId };
19512
+ return { provider: state2.provider, id: state2.modelId };
18452
19513
  }
18453
- function effectiveModelFromState(state) {
18454
- const model = nativeModelFromState(state);
19514
+ function effectiveModelFromState(state2) {
19515
+ const model = nativeModelFromState(state2);
18455
19516
  return model ? encodePiModelRef(model) : void 0;
18456
19517
  }
18457
- function harnessStateFromPi(state, thinkingLevels) {
18458
- const effectiveModel = effectiveModelFromState(state);
19518
+ function harnessStateFromPi(state2, thinkingLevels) {
19519
+ const effectiveModel = effectiveModelFromState(state2);
18459
19520
  const availableThinkingOptions = thinkingLevels ? normalizePiThinkingOptions(thinkingLevels) : void 0;
18460
- if (availableThinkingOptions && (!state.thinkingLevel || !thinkingLevels?.includes(state.thinkingLevel))) {
19521
+ if (availableThinkingOptions && (!state2.thinkingLevel || !thinkingLevels?.includes(state2.thinkingLevel))) {
18461
19522
  throw new PiRpcFaultError("protocolError", "Pi effective Thinking level is absent from its available levels");
18462
19523
  }
18463
19524
  return {
18464
19525
  nativeRef: nativeSessionRefSchema.parse({
18465
19526
  harnessId: piHarnessId2,
18466
- nativeSessionId: state.sessionId,
18467
- ...state.sessionFile ? { locator: { sessionFile: state.sessionFile } } : {},
19527
+ nativeSessionId: state2.sessionId,
19528
+ ...state2.sessionFile ? { locator: { sessionFile: state2.sessionFile } } : {},
18468
19529
  formatVersion: 1
18469
19530
  }),
18470
19531
  ...effectiveModel ? { effectiveModel } : {},
18471
- ...state.thinkingLevel ? { effectiveThinkingOptionId: state.thinkingLevel } : {},
19532
+ ...state2.thinkingLevel ? { effectiveThinkingOptionId: state2.thinkingLevel } : {},
18472
19533
  ...availableThinkingOptions ? { availableThinkingOptions } : {}
18473
19534
  };
18474
19535
  }
18475
- function nativeModelForHistory(state) {
18476
- return nativeModelFromState(state);
19536
+ function nativeModelForHistory(state2) {
19537
+ return nativeModelFromState(state2);
18477
19538
  }
18478
19539
  function sessionFileFromRef(ref) {
18479
19540
  if (ref.harnessId !== piHarnessId2 || !isRecord7(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
@@ -18493,20 +19554,20 @@ function nativeText(value) {
18493
19554
  return value;
18494
19555
  if (!isRecord7(value) || !Array.isArray(value.content))
18495
19556
  return "";
18496
- return value.content.filter((content) => isRecord7(content) && content.type === "text" && typeof content.text === "string").map(({ text }) => text).join("");
19557
+ return value.content.filter((content) => isRecord7(content) && content.type === "text" && typeof content.text === "string").map(({ text: text2 }) => text2).join("");
18497
19558
  }
18498
19559
  function boundedOutput(value, limit) {
18499
- const text = nativeText(value);
18500
- if (text.length === 0)
19560
+ const text2 = nativeText(value);
19561
+ if (text2.length === 0)
18501
19562
  return void 0;
18502
- const truncated = text.length > limit;
19563
+ const truncated = text2.length > limit;
18503
19564
  return {
18504
- content: [{ type: "text", text: truncated ? text.slice(0, limit) : text }],
19565
+ content: [{ type: "text", text: truncated ? text2.slice(0, limit) : text2 }],
18505
19566
  ...truncated ? { truncated: true } : {}
18506
19567
  };
18507
19568
  }
18508
19569
  function outputText(output) {
18509
- return output?.content.filter((content) => content.type === "text").map(({ text }) => text).join("") ?? "";
19570
+ return output?.content.filter((content) => content.type === "text").map(({ text: text2 }) => text2).join("") ?? "";
18510
19571
  }
18511
19572
  function stringField(value, key) {
18512
19573
  if (!isRecord7(value))
@@ -18538,10 +19599,10 @@ function stripDiffPrefix(pathString) {
18538
19599
  return pathString.startsWith("a/") || pathString.startsWith("b/") ? pathString.slice(2) : pathString;
18539
19600
  }
18540
19601
  function displayPath(nativePath, cwd) {
18541
- const resolvedCwd = path6.resolve(cwd);
18542
- const resolvedPath = path6.isAbsolute(nativePath) ? path6.resolve(nativePath) : path6.resolve(cwd, nativePath);
18543
- const relative = path6.relative(resolvedCwd, resolvedPath);
18544
- const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path6.sep}`);
19602
+ const resolvedCwd = path9.resolve(cwd);
19603
+ const resolvedPath = path9.isAbsolute(nativePath) ? path9.resolve(nativePath) : path9.resolve(cwd, nativePath);
19604
+ const relative = path9.relative(resolvedCwd, resolvedPath);
19605
+ const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path9.sep}`);
18545
19606
  const selected = inside ? relative : resolvedPath;
18546
19607
  const normalized = selected.replaceAll("\\", "/");
18547
19608
  if (normalized.length === 0 || normalized === ".")
@@ -18731,6 +19792,8 @@ var PiHarnessSession = class {
18731
19792
  initialUsage;
18732
19793
  outputs;
18733
19794
  #channel = new HarnessOutputChannel();
19795
+ #subagents = new PiSubagents((event) => this.#event(event));
19796
+ #pendingSubagentStatus = null;
18734
19797
  #closeTimeoutMs;
18735
19798
  #createTransport;
18736
19799
  #cwd;
@@ -18766,7 +19829,8 @@ var PiHarnessSession = class {
18766
19829
  permissionModeScope: "live"
18767
19830
  },
18768
19831
  history: { fork: true, forkAcrossCwd: true, rollbackLastTurn: true },
18769
- autonomousTurns: { observe: true }
19832
+ autonomousTurns: { observe: true },
19833
+ subagents: { observe: true, readTranscript: true }
18770
19834
  };
18771
19835
  this.commands = {
18772
19836
  list: async () => ({ ok: true, value: piCommandCatalog }),
@@ -18781,6 +19845,24 @@ var PiHarnessSession = class {
18781
19845
  if (this.#transport)
18782
19846
  this.#bindAutonomousTurnHandler(this.#transport);
18783
19847
  }
19848
+ ownsNativeSession(id) {
19849
+ return this.#transport?.state.sessionId === id;
19850
+ }
19851
+ async readSubagentHistory(cwd) {
19852
+ if (this.#phase !== "open" || path9.resolve(cwd) !== path9.resolve(this.#cwd)) {
19853
+ throw new Error("Pi Subagent parent workspace or Session is unavailable");
19854
+ }
19855
+ return (await this.#ensureTransport()).getEntries();
19856
+ }
19857
+ async inspectSubagent(id, cwd) {
19858
+ if (this.#phase !== "open" || path9.resolve(cwd) !== path9.resolve(this.#cwd)) {
19859
+ throw new Error("Pi Subagent parent workspace or Session is unavailable");
19860
+ }
19861
+ const transport = await this.#ensureTransport();
19862
+ if (!transport.inspectSubagent)
19863
+ throw new Error("Pi transport does not support Subagent inspection");
19864
+ return transport.inspectSubagent(id);
19865
+ }
18784
19866
  handleTransportFault(error51) {
18785
19867
  queueMicrotask(() => this.#fault(error51));
18786
19868
  }
@@ -18801,13 +19883,14 @@ var PiHarnessSession = class {
18801
19883
  try {
18802
19884
  const transport = await this.#ensureTransport();
18803
19885
  const history = await transport.getEntries();
19886
+ await restorePiSubagents(history, transport.state.sessionId, this.#subagents);
18804
19887
  return {
18805
19888
  ok: true,
18806
19889
  value: {
18807
19890
  ...mapPiSnapshot(history, {
18808
19891
  sessionId: transport.state.sessionId,
18809
19892
  model: nativeModelForHistory(transport.state)
18810
- }),
19893
+ }, this.#subagents),
18811
19894
  state: this.#state
18812
19895
  }
18813
19896
  };
@@ -18850,8 +19933,8 @@ var PiHarnessSession = class {
18850
19933
  }
18851
19934
  };
18852
19935
  }
18853
- const text = command.input.filter((input) => input.type === "text").map((input) => input.text).join("\n");
18854
- if (text.length === 0) {
19936
+ const text2 = command.input.filter((input) => input.type === "text").map((input) => input.text).join("\n");
19937
+ if (text2.length === 0) {
18855
19938
  return {
18856
19939
  ok: false,
18857
19940
  error: {
@@ -18908,7 +19991,7 @@ var PiHarnessSession = class {
18908
19991
  this.#active = active;
18909
19992
  this.#event({ type: "turn.started", turnId: command.turnId });
18910
19993
  this.#event({ type: "item.started", turnId: command.turnId, item });
18911
- void transport.runTurn(text, (event) => this.#handleTurnEvent(active, event)).then(async (result) => {
19994
+ void transport.runTurn(text2, (event) => this.#handleTurnEvent(active, event)).then(async (result) => {
18912
19995
  try {
18913
19996
  const identity = await this.#completedTurnIdentity(active, transport);
18914
19997
  this.#completeTurn(active, result.cancelled ? {
@@ -19027,19 +20110,19 @@ var PiHarnessSession = class {
19027
20110
  const previousModel = this.#state.effectiveModel;
19028
20111
  this.#configuring = true;
19029
20112
  try {
19030
- let state;
20113
+ let state2;
19031
20114
  let thinkingLevels;
19032
20115
  try {
19033
- state = await transport.selectModel(requested);
20116
+ state2 = await transport.selectModel(requested);
19034
20117
  thinkingLevels = await transport.getAvailableThinkingLevels();
19035
- this.#publishTransportState(state, thinkingLevels);
20118
+ this.#publishTransportState(state2, thinkingLevels);
19036
20119
  } catch (error51) {
19037
20120
  if (error51 instanceof PiRpcFaultError)
19038
20121
  this.#fault(error51);
19039
20122
  return { ok: false, error: normalizedError(error51, "nativeFailure") };
19040
20123
  }
19041
- const actual = nativeModelFromState(state);
19042
- const nextModel = effectiveModelFromState(state);
20124
+ const actual = nativeModelFromState(state2);
20125
+ const nextModel = effectiveModelFromState(state2);
19043
20126
  if (previousModel?.id !== nextModel?.id) {
19044
20127
  this.#invalidateUsage();
19045
20128
  void this.#refreshUsage();
@@ -19101,10 +20184,10 @@ var PiHarnessSession = class {
19101
20184
  const thinkingOptionId = parsedThinkingOptionId.data;
19102
20185
  this.#configuring = true;
19103
20186
  try {
19104
- let state;
20187
+ let state2;
19105
20188
  let thinkingLevels;
19106
20189
  try {
19107
- state = await transport.selectThinkingOption(thinkingOptionId);
20190
+ state2 = await transport.selectThinkingOption(thinkingOptionId);
19108
20191
  thinkingLevels = await transport.getAvailableThinkingLevels();
19109
20192
  } catch (error51) {
19110
20193
  if (error51 instanceof PiRpcFaultError)
@@ -19122,7 +20205,7 @@ var PiHarnessSession = class {
19122
20205
  };
19123
20206
  }
19124
20207
  try {
19125
- this.#publishTransportState(state, thinkingLevels);
20208
+ this.#publishTransportState(state2, thinkingLevels);
19126
20209
  } catch (error51) {
19127
20210
  if (error51 instanceof PiRpcFaultError)
19128
20211
  this.#fault(error51);
@@ -19279,16 +20362,16 @@ var PiHarnessSession = class {
19279
20362
  const starting = transport.start().then(async () => {
19280
20363
  if (this.#phase !== "open")
19281
20364
  throw new Error("Pi Session closed during startup");
19282
- let state = transport.state;
20365
+ let state2 = transport.state;
19283
20366
  let thinkingLevels = await transport.getAvailableThinkingLevels();
19284
20367
  if (this.#requestedModel) {
19285
20368
  const requested = decodePiModelRef(this.#requestedModel);
19286
- const current = nativeModelFromState(state);
20369
+ const current = nativeModelFromState(state2);
19287
20370
  if (!samePiModel(current, requested))
19288
- state = await transport.selectModel(requested);
20371
+ state2 = await transport.selectModel(requested);
19289
20372
  thinkingLevels = await transport.getAvailableThinkingLevels();
19290
- if (!samePiModel(nativeModelFromState(state), requested)) {
19291
- this.#publishTransportState(state, thinkingLevels);
20373
+ if (!samePiModel(nativeModelFromState(state2), requested)) {
20374
+ this.#publishTransportState(state2, thinkingLevels);
19292
20375
  throw new Error("Pi did not activate the requested create Model");
19293
20376
  }
19294
20377
  }
@@ -19300,11 +20383,11 @@ var PiHarnessSession = class {
19300
20383
  retryable: false
19301
20384
  });
19302
20385
  }
19303
- state = await transport.selectThinkingOption(this.#requestedThinkingOptionId);
20386
+ state2 = await transport.selectThinkingOption(this.#requestedThinkingOptionId);
19304
20387
  thinkingLevels = await transport.getAvailableThinkingLevels();
19305
20388
  }
19306
20389
  this.#transport = transport;
19307
- this.#publishTransportState(state, thinkingLevels);
20390
+ this.#publishTransportState(state2, thinkingLevels);
19308
20391
  this.#drainPendingAutonomousTurns(transport);
19309
20392
  return transport;
19310
20393
  }).catch(async (error51) => {
@@ -19321,6 +20404,14 @@ var PiHarnessSession = class {
19321
20404
  return starting;
19322
20405
  }
19323
20406
  #bindAutonomousTurnHandler(transport) {
20407
+ transport.setSubagentStatusHandler?.((runs) => {
20408
+ if (this.#phase !== "open")
20409
+ return;
20410
+ if (this.#transport !== transport)
20411
+ this.#pendingSubagentStatus = runs;
20412
+ else
20413
+ this.#subagents.observe(runs);
20414
+ });
19324
20415
  transport.setAutonomousTurnHandler((turn) => {
19325
20416
  if (this.#phase !== "open")
19326
20417
  return;
@@ -19332,6 +20423,10 @@ var PiHarnessSession = class {
19332
20423
  });
19333
20424
  }
19334
20425
  #drainPendingAutonomousTurns(transport) {
20426
+ if (this.#pendingSubagentStatus) {
20427
+ this.#subagents.observe(this.#pendingSubagentStatus);
20428
+ this.#pendingSubagentStatus = null;
20429
+ }
19335
20430
  const pending = this.#pendingAutonomousTurns.filter((candidate) => candidate.transport === transport);
19336
20431
  this.#pendingAutonomousTurns = this.#pendingAutonomousTurns.filter((candidate) => candidate.transport !== transport);
19337
20432
  for (const candidate of pending) {
@@ -19359,7 +20454,7 @@ var PiHarnessSession = class {
19359
20454
  }));
19360
20455
  return;
19361
20456
  }
19362
- const turnId = hostTurnIdSchema.parse(randomUUID3());
20457
+ const turnId = hostTurnIdSchema.parse(randomUUID5());
19363
20458
  let resolveCompletion = () => void 0;
19364
20459
  const completion = new Promise((resolve) => {
19365
20460
  resolveCompletion = resolve;
@@ -19412,8 +20507,8 @@ var PiHarnessSession = class {
19412
20507
  this.#fault(new PiAdapterFaultError(normalized));
19413
20508
  }
19414
20509
  }
19415
- #publishTransportState(state, thinkingLevels) {
19416
- this.#state = harnessStateFromPi(state, thinkingLevels);
20510
+ #publishTransportState(state2, thinkingLevels) {
20511
+ this.#state = harnessStateFromPi(state2, thinkingLevels);
19417
20512
  this.#event({ type: "session.state.changed", state: this.#state });
19418
20513
  }
19419
20514
  #invalidateUsage() {
@@ -19521,7 +20616,7 @@ var PiHarnessSession = class {
19521
20616
  if (active.interactionByNativeId.has(request.requestId)) {
19522
20617
  throw new Error("Pi Interaction started more than once");
19523
20618
  }
19524
- const interactionId = hostInteractionIdSchema.parse(randomUUID3());
20619
+ const interactionId = hostInteractionIdSchema.parse(randomUUID5());
19525
20620
  const question = request.method === "select" ? {
19526
20621
  id: "answer",
19527
20622
  type: "choice",
@@ -19600,16 +20695,16 @@ var PiHarnessSession = class {
19600
20695
  active.agentMessageId = messageId;
19601
20696
  active.sawAssistantMessage = true;
19602
20697
  }
19603
- #appendText(active, text) {
20698
+ #appendText(active, text2) {
19604
20699
  if (active.agentMessageId === null || !active.agentItem) {
19605
20700
  throw new Error("Pi Assistant text arrived outside an active message");
19606
20701
  }
19607
- active.agentItem = { ...active.agentItem, text: active.agentItem.text + text };
20702
+ active.agentItem = { ...active.agentItem, text: active.agentItem.text + text2 };
19608
20703
  this.#event({
19609
20704
  type: "item.updated",
19610
20705
  turnId: active.command.turnId,
19611
20706
  itemId: active.agentItem.itemId,
19612
- update: { type: "text.append", text }
20707
+ update: { type: "text.append", text: text2 }
19613
20708
  });
19614
20709
  }
19615
20710
  #completeAgentItem(active, outcome, completeEmpty) {
@@ -19620,8 +20715,8 @@ var PiHarnessSession = class {
19620
20715
  active.agentItem = null;
19621
20716
  this.#completeItem(active, item, outcome);
19622
20717
  }
19623
- #appendReasoning(active, text) {
19624
- if (text.length === 0)
20718
+ #appendReasoning(active, text2) {
20719
+ if (text2.length === 0)
19625
20720
  return;
19626
20721
  if (!active.reasoningItem) {
19627
20722
  active.reasoningItem = {
@@ -19637,13 +20732,13 @@ var PiHarnessSession = class {
19637
20732
  }
19638
20733
  active.reasoningItem = {
19639
20734
  ...active.reasoningItem,
19640
- text: active.reasoningItem.text + text
20735
+ text: active.reasoningItem.text + text2
19641
20736
  };
19642
20737
  this.#event({
19643
20738
  type: "item.updated",
19644
20739
  turnId: active.command.turnId,
19645
20740
  itemId: active.reasoningItem.itemId,
19646
- update: { type: "text.append", text }
20741
+ update: { type: "text.append", text: text2 }
19647
20742
  });
19648
20743
  }
19649
20744
  #completeReasoning(active, outcome) {
@@ -19680,6 +20775,7 @@ var PiHarnessSession = class {
19680
20775
  const tool = active.tools.get(event.callId);
19681
20776
  if (!tool)
19682
20777
  throw new Error("Pi Tool update references an unknown Tool Call");
20778
+ this.#subagents.start(active.command.turnId, tool.nativeName, event.output, this.#newItemId(), event.callId);
19683
20779
  const output = boundedOutput(event.output, this.#toolOutputLimit);
19684
20780
  if (!output)
19685
20781
  return;
@@ -19736,6 +20832,7 @@ var PiHarnessSession = class {
19736
20832
  }
19737
20833
  const outcome = active.cancellationRequested ? { status: "cancelled", reason: "Cancelled by user" } : event.isError ? { status: "failed", error: toolFailure(event.toolName) } : { status: "succeeded" };
19738
20834
  this.#completeItem(active, tool.item, outcome);
20835
+ this.#subagents.start(active.command.turnId, event.toolName, event.result, this.#newItemId(), event.callId);
19739
20836
  if (!event.isError) {
19740
20837
  try {
19741
20838
  const kind = fileMutatingKind(event.toolName);
@@ -19805,6 +20902,7 @@ var PiHarnessSession = class {
19805
20902
  for (const tool of active.tools.values())
19806
20903
  this.#completeItem(active, tool.item, itemOutcome2);
19807
20904
  active.tools.clear();
20905
+ this.#subagents.finish(active.command.turnId);
19808
20906
  if (!active.sawAssistantMessage && finalText !== void 0 && active.agentItem) {
19809
20907
  active.agentItem = { ...active.agentItem, text: finalText };
19810
20908
  }
@@ -19865,12 +20963,66 @@ var PiHarnessSession = class {
19865
20963
  this.#channel.emit({ kind: "event", event });
19866
20964
  }
19867
20965
  #newItemId() {
19868
- return hostItemIdSchema.parse(randomUUID3());
20966
+ return hostItemIdSchema.parse(randomUUID5());
19869
20967
  }
19870
20968
  };
19871
20969
  var PiAdapter = class {
20970
+ credentialImports;
19872
20971
  commandCatalog = piCommandCatalog;
19873
20972
  harnessId = piHarnessId2;
20973
+ subagents = {
20974
+ readSnapshot: async ({ parent, nativeSubagentId, cwd }) => {
20975
+ let transport;
20976
+ try {
20977
+ if (this.#closePromise || parent.harnessId !== this.harnessId) {
20978
+ return { ok: false, error: invalidState("Pi Subagent parent is unavailable") };
20979
+ }
20980
+ const workflow = parsePiWorkflowSubagentId(nativeSubagentId);
20981
+ if (!workflow)
20982
+ parsePiSubagentId(nativeSubagentId);
20983
+ const live = [...this.#sessions].find((session) => session.ownsNativeSession(parent.nativeSessionId));
20984
+ let reply;
20985
+ if (live) {
20986
+ if (workflow)
20987
+ return await readPiWorkflowChild(await live.readSubagentHistory(cwd), parent.nativeSessionId, workflow);
20988
+ reply = await live.inspectSubagent(nativeSubagentId, cwd);
20989
+ } else {
20990
+ const sessionFile = sessionFileFromRef(parent);
20991
+ transport = this.#createTransport({ cwd, sessionFile });
20992
+ this.#inspections.add(transport);
20993
+ await transport.start();
20994
+ if (transport.state.sessionId !== parent.nativeSessionId)
20995
+ throw new Error("Pi Subagent parent identity mismatch");
20996
+ await transport.verifySessionCwd(cwd);
20997
+ if (workflow)
20998
+ return await readPiWorkflowChild(await transport.getEntries(), parent.nativeSessionId, workflow);
20999
+ if (!transport.inspectSubagent)
21000
+ throw new Error("Pi transport does not support Subagent inspection");
21001
+ reply = await transport.inspectSubagent(nativeSubagentId);
21002
+ }
21003
+ if (reply.error)
21004
+ return {
21005
+ ok: false,
21006
+ error: {
21007
+ code: reply.error.code === "foreign_session" ? "invalidRequest" : ["not_found", "stale"].includes(reply.error.code) ? "sessionNotFound" : "unavailable",
21008
+ message: reply.error.message,
21009
+ retryable: false
21010
+ }
21011
+ };
21012
+ return {
21013
+ ok: true,
21014
+ value: piSubagentSnapshot(parent.nativeSessionId, nativeSubagentId, reply)
21015
+ };
21016
+ } catch (error51) {
21017
+ return { ok: false, error: normalizedError(error51, "unavailable") };
21018
+ } finally {
21019
+ if (transport) {
21020
+ this.#inspections.delete(transport);
21021
+ await transport.close();
21022
+ }
21023
+ }
21024
+ }
21025
+ };
19874
21026
  sessionImport = Object.freeze({
19875
21027
  listCandidates: async () => {
19876
21028
  const result = await this.#readImport((signal) => this.#importIndex.list(signal));
@@ -19906,6 +21058,19 @@ var PiAdapter = class {
19906
21058
  constructor(options = {}, dependencies = {
19907
21059
  createTransport: (sessionOptions) => new PiRpcSession({ ...options, ...sessionOptions })
19908
21060
  }) {
21061
+ const imports = createPiCredentialImports(options);
21062
+ const updateCatalog = async (operation) => {
21063
+ await operation;
21064
+ this.#inspectionCache.clear();
21065
+ };
21066
+ this.credentialImports = {
21067
+ providers: imports.providers,
21068
+ list: () => imports.list(),
21069
+ listOthers: () => imports.listOthers?.() ?? Promise.resolve([]),
21070
+ add: (name, credential) => updateCatalog(imports.add(name, credential)),
21071
+ reimport: (name, credential) => updateCatalog(imports.reimport(name, credential)),
21072
+ remove: (name) => updateCatalog(imports.remove(name))
21073
+ };
19909
21074
  this.#createTransport = dependencies.createTransport;
19910
21075
  this.#importIndex = new PiSessionImportIndex({ ...process.env, ...options.environment });
19911
21076
  this.#closeTimeoutMs = options.closeTimeoutMs ?? 2e3;
@@ -19983,7 +21148,8 @@ var PiAdapter = class {
19983
21148
  permissionModeScope: "live"
19984
21149
  },
19985
21150
  history: { fork: true, forkAcrossCwd: true, rollbackLastTurn: true },
19986
- autonomousTurns: { observe: true }
21151
+ autonomousTurns: { observe: true },
21152
+ subagents: { observe: true, readTranscript: true }
19987
21153
  }
19988
21154
  };
19989
21155
  } catch (error51) {
@@ -20137,40 +21303,40 @@ var PiAdapter = class {
20137
21303
  });
20138
21304
  }
20139
21305
  if (rolledBack.unpersisted) {
20140
- const state = transport.state;
21306
+ const state2 = transport.state;
20141
21307
  const history = await transport.getEntries();
20142
21308
  await transport.close();
20143
21309
  await persistEmptyPiSession({
20144
- state,
21310
+ state: state2,
20145
21311
  history,
20146
21312
  sourceSessionFile,
20147
21313
  sourceSessionId: sourceRef.nativeSessionId,
20148
21314
  cwd: input.cwd
20149
21315
  });
20150
- if (!state.sessionFile)
21316
+ if (!state2.sessionFile)
20151
21317
  throw new Error("Pi empty fork has no Session file");
20152
- const configuration = await readPiEmptySessionConfiguration(state.sessionFile);
21318
+ const configuration = await readPiEmptySessionConfiguration(state2.sessionFile);
20153
21319
  if (!configuration)
20154
21320
  throw new Error("Pi empty fork has no restorable configuration");
20155
21321
  transport = this.#createTransport({
20156
21322
  cwd: input.cwd,
20157
21323
  ...input.environment ? { environment: input.environment } : {},
20158
- sessionFile: state.sessionFile,
21324
+ sessionFile: state2.sessionFile,
20159
21325
  emptySessionConfiguration: configuration,
20160
21326
  onFault: (error51) => session?.handleTransportFault(error51)
20161
21327
  });
20162
21328
  await transport.start();
20163
- if (transport.state.sessionId !== state.sessionId) {
21329
+ if (transport.state.sessionId !== state2.sessionId) {
20164
21330
  throw new Error("Pi empty fork resumed with a different identity");
20165
21331
  }
20166
- const model = nativeModelFromState(state);
21332
+ const model = nativeModelFromState(state2);
20167
21333
  if (model && !samePiModel(nativeModelFromState(transport.state), model)) {
20168
21334
  await transport.selectModel(model);
20169
21335
  }
20170
- if (state.thinkingLevel && transport.state.thinkingLevel !== state.thinkingLevel) {
20171
- await transport.selectThinkingOption(state.thinkingLevel);
21336
+ if (state2.thinkingLevel && transport.state.thinkingLevel !== state2.thinkingLevel) {
21337
+ await transport.selectThinkingOption(state2.thinkingLevel);
20172
21338
  }
20173
- if (!samePiModel(nativeModelFromState(transport.state), model) || transport.state.thinkingLevel !== state.thinkingLevel) {
21339
+ if (!samePiModel(nativeModelFromState(transport.state), model) || transport.state.thinkingLevel !== state2.thinkingLevel) {
20174
21340
  throw new Error("Pi empty fork could not restore its configuration");
20175
21341
  }
20176
21342
  await transport.verifySessionCwd(input.cwd);