@codexhost/cli-darwin-x64 0.10.1 → 0.11.0

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,15 +5,10 @@ var __export = (target, all) => {
5
5
  __defProp(target, name, { get: all[name], enumerable: true });
6
6
  };
7
7
 
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";
8
+ // dist/account-balance.js
9
+ import { readFile } from "node:fs/promises";
10
+ import { homedir } from "node:os";
11
+ import path from "node:path";
17
12
 
18
13
  // ../../../node_modules/zod/v4/classic/external.js
19
14
  var external_exports = {};
@@ -781,10 +776,10 @@ function mergeDefs(...defs) {
781
776
  function cloneDef(schema) {
782
777
  return mergeDefs(schema._zod.def);
783
778
  }
784
- function getElementAtPath(obj, path10) {
785
- if (!path10)
779
+ function getElementAtPath(obj, path13) {
780
+ if (!path13)
786
781
  return obj;
787
- return path10.reduce((acc, key) => acc?.[key], obj);
782
+ return path13.reduce((acc, key) => acc?.[key], obj);
788
783
  }
789
784
  function promiseAllObject(promisesObj) {
790
785
  const keys = Object.keys(promisesObj);
@@ -1193,11 +1188,11 @@ function explicitlyAborted(x, startIndex = 0) {
1193
1188
  }
1194
1189
  return false;
1195
1190
  }
1196
- function prefixIssues(path10, issues) {
1191
+ function prefixIssues(path13, issues) {
1197
1192
  return issues.map((iss) => {
1198
1193
  var _a3;
1199
1194
  (_a3 = iss).path ?? (_a3.path = []);
1200
- iss.path.unshift(path10);
1195
+ iss.path.unshift(path13);
1201
1196
  return iss;
1202
1197
  });
1203
1198
  }
@@ -1344,16 +1339,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1344
1339
  }
1345
1340
  function formatError(error51, mapper = (issue2) => issue2.message) {
1346
1341
  const fieldErrors = { _errors: [] };
1347
- const processError = (error52, path10 = []) => {
1342
+ const processError = (error52, path13 = []) => {
1348
1343
  for (const issue2 of error52.issues) {
1349
1344
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1350
- issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1345
+ issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
1351
1346
  } else if (issue2.code === "invalid_key") {
1352
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1347
+ processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
1353
1348
  } else if (issue2.code === "invalid_element") {
1354
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1349
+ processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
1355
1350
  } else {
1356
- const fullpath = [...path10, ...issue2.path];
1351
+ const fullpath = [...path13, ...issue2.path];
1357
1352
  if (fullpath.length === 0) {
1358
1353
  fieldErrors._errors.push(mapper(issue2));
1359
1354
  } else {
@@ -1380,17 +1375,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1380
1375
  }
1381
1376
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1382
1377
  const result = { errors: [] };
1383
- const processError = (error52, path10 = []) => {
1378
+ const processError = (error52, path13 = []) => {
1384
1379
  var _a3, _b;
1385
1380
  for (const issue2 of error52.issues) {
1386
1381
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1387
- issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1382
+ issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
1388
1383
  } else if (issue2.code === "invalid_key") {
1389
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1384
+ processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
1390
1385
  } else if (issue2.code === "invalid_element") {
1391
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1386
+ processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
1392
1387
  } else {
1393
- const fullpath = [...path10, ...issue2.path];
1388
+ const fullpath = [...path13, ...issue2.path];
1394
1389
  if (fullpath.length === 0) {
1395
1390
  result.errors.push(mapper(issue2));
1396
1391
  continue;
@@ -1422,8 +1417,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1422
1417
  }
1423
1418
  function toDotPath(_path) {
1424
1419
  const segs = [];
1425
- const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1426
- for (const seg of path10) {
1420
+ const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1421
+ for (const seg of path13) {
1427
1422
  if (typeof seg === "number")
1428
1423
  segs.push(`[${seg}]`);
1429
1424
  else if (typeof seg === "symbol")
@@ -14115,13 +14110,13 @@ function resolveRef(ref, ctx) {
14115
14110
  if (!ref.startsWith("#")) {
14116
14111
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14117
14112
  }
14118
- const path10 = ref.slice(1).split("/").filter(Boolean);
14119
- if (path10.length === 0) {
14113
+ const path13 = ref.slice(1).split("/").filter(Boolean);
14114
+ if (path13.length === 0) {
14120
14115
  return ctx.rootSchema;
14121
14116
  }
14122
14117
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14123
- if (path10[0] === defsKey) {
14124
- const key = path10[1];
14118
+ if (path13[0] === defsKey) {
14119
+ const key = path13[1];
14125
14120
  if (!key || !ctx.defs[key]) {
14126
14121
  throw new Error(`Reference not found: ${ref}`);
14127
14122
  }
@@ -14584,6 +14579,55 @@ var credentialImportsParamsSchema = external_exports.object({
14584
14579
  request: credentialImportsRequestSchema
14585
14580
  }).strict();
14586
14581
 
14582
+ // ../../shared-contracts/dist/harness-display-settings.js
14583
+ var harnessDisplayEntriesSchema = external_exports.array(external_exports.strictObject({
14584
+ agent: external_exports.string().min(1).max(128),
14585
+ section: external_exports.enum(["main", "more", "auto"])
14586
+ })).max(256).refine((entries) => new Set(entries.map((entry) => entry.agent)).size === entries.length, "Duplicate Harness IDs");
14587
+ var harnessDisplaySettingsSchema = external_exports.strictObject({
14588
+ entries: harnessDisplayEntriesSchema.nullable()
14589
+ });
14590
+ var harnessDisplayGetSchema = external_exports.strictObject({});
14591
+ var harnessDisplaySetSchema = external_exports.strictObject({
14592
+ entries: harnessDisplayEntriesSchema,
14593
+ /** Import legacy Desktop preferences only if no shared settings exist yet. */
14594
+ initializeOnly: external_exports.boolean().optional()
14595
+ });
14596
+
14597
+ // ../../shared-contracts/dist/console.js
14598
+ var consoleAnnouncementSchema = external_exports.strictObject({
14599
+ title: external_exports.string().trim().min(1).max(200),
14600
+ type: external_exports.enum(["info", "warning", "danger"]),
14601
+ body: external_exports.string().trim().min(1).max(16 * 1024)
14602
+ });
14603
+ var consoleOpenParamsSchema = external_exports.strictObject({});
14604
+ var consoleOpenResultSchema = external_exports.strictObject({
14605
+ /** The console address. */
14606
+ url: external_exports.string().max(2048).regex(/^http:\/\/(?:127\.0\.0\.1|localhost):\d{1,5}\/(?:\?.*)?$/u)
14607
+ });
14608
+ var CONSOLE_HOST_METHODS = Object.freeze([
14609
+ "codexhost/harness/plugins/list",
14610
+ "codexhost/harness/display-settings/get",
14611
+ "codexhost/harness/display-settings/set",
14612
+ "codexhost/harness/inspect",
14613
+ "codexhost/harness/launch-settings/get",
14614
+ "codexhost/harness/launch-settings/set",
14615
+ "codexhost/harness/web-ui/open",
14616
+ "codexhost/harness/accounts/sources",
14617
+ "codexhost/harness/accounts/list",
14618
+ "codexhost/harness/accounts/inspect",
14619
+ "codexhost/harness/credential-imports",
14620
+ "codexhost/harness/session-import/sources",
14621
+ "codexhost/harness/session-import/list",
14622
+ "codexhost/harness/session-import/import",
14623
+ "codexhost/account/list",
14624
+ "codexhost/account/refresh",
14625
+ "codexhost/account/usage/inspect",
14626
+ "codexhost/update/check",
14627
+ "codexhost/update/start",
14628
+ "codexhost/update/status"
14629
+ ]);
14630
+
14587
14631
  // ../../shared-contracts/dist/version.js
14588
14632
  var WORKSPACE_CONTRACT_VERSION = 1;
14589
14633
 
@@ -14637,6 +14681,12 @@ var hostTurnIdSchema = opaqueIdSchema.brand();
14637
14681
  var hostItemIdSchema = opaqueIdSchema.brand();
14638
14682
  var hostInteractionIdSchema = opaqueIdSchema.brand();
14639
14683
 
14684
+ // ../../shared-contracts/dist/manual-compaction.js
14685
+ var threadManualCompactionStartedSchema = external_exports.strictObject({
14686
+ threadId: hostThreadIdSchema,
14687
+ turnId: hostTurnIdSchema
14688
+ });
14689
+
14640
14690
  // ../../shared-contracts/dist/thread-usage.js
14641
14691
  var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
14642
14692
  var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
@@ -14697,6 +14747,10 @@ var threadUsageSnapshotSchema = external_exports.object({
14697
14747
  var usagePercentSchema = external_exports.number().finite().min(0).max(100);
14698
14748
  var accountCreditsProductUsageSchema = external_exports.object({
14699
14749
  product: external_exports.string().min(1),
14750
+ used: external_exports.number().finite().nonnegative().optional(),
14751
+ // Zero is a real empty cap, not an absent field.
14752
+ limit: external_exports.number().finite().nonnegative().optional(),
14753
+ unit: external_exports.string().min(1).max(32).optional(),
14700
14754
  usagePercent: usagePercentSchema,
14701
14755
  resetsAt: external_exports.string().min(1).optional()
14702
14756
  }).strict();
@@ -14706,6 +14760,10 @@ var accountResetCreditsSchema = external_exports.object({
14706
14760
  expiresAt: external_exports.array(external_exports.string().min(1)).min(1).max(32).optional()
14707
14761
  }).strict();
14708
14762
  var accountCreditsSnapshotSchema = external_exports.object({
14763
+ used: external_exports.number().finite().nonnegative().optional(),
14764
+ // Zero is a real empty cap, not an absent field.
14765
+ limit: external_exports.number().finite().nonnegative().optional(),
14766
+ unit: external_exports.string().min(1).max(32).optional(),
14709
14767
  /** Native label when the primary limit is scoped to a model or product group. */
14710
14768
  label: external_exports.string().min(1).optional(),
14711
14769
  usedPercent: usagePercentSchema,
@@ -14725,12 +14783,27 @@ var threadUsageInspectionSchema = external_exports.object({
14725
14783
  }).strict();
14726
14784
 
14727
14785
  // ../../shared-contracts/dist/harness-accounts.js
14728
- var harnessAccountSnapshotSchema = external_exports.object({
14786
+ var accountBalanceSnapshotSchema = external_exports.object({
14787
+ amount: external_exports.number().finite().nonnegative(),
14788
+ /** ISO 4217 code as reported by the Provider, for example `CNY`. */
14789
+ currency: external_exports.string().trim().min(1).max(8),
14790
+ /** Native label when the Harness exposes several Billing Sources. */
14791
+ label: external_exports.string().trim().min(1).max(128).optional()
14792
+ }).strict();
14793
+ var harnessAccountSnapshotObject = external_exports.object({
14729
14794
  email: external_exports.string().trim().min(1).max(320).optional(),
14730
14795
  label: external_exports.string().trim().min(1).max(256).optional(),
14731
14796
  plan: external_exports.string().trim().min(1).max(128).optional(),
14732
- credits: accountCreditsSnapshotSchema
14797
+ credits: accountCreditsSnapshotSchema.optional(),
14798
+ balance: accountBalanceSnapshotSchema.optional()
14733
14799
  }).strict();
14800
+ function requireReportedQuota(schema) {
14801
+ return schema.refine((value) => {
14802
+ const reported = value;
14803
+ return reported.credits !== void 0 || reported.balance !== void 0;
14804
+ }, { message: "Account must report either credits or a balance" });
14805
+ }
14806
+ var harnessAccountSnapshotSchema = requireReportedQuota(harnessAccountSnapshotObject);
14734
14807
  var harnessAccountIdentityShape = {
14735
14808
  harnessId: harnessIdSchema,
14736
14809
  harnessName: external_exports.string().trim().min(1).max(128)
@@ -14741,11 +14814,13 @@ var harnessAccountSourceListResultSchema = external_exports.object({ sources: ex
14741
14814
  var harnessAccountInspectParamsSchema = external_exports.object({ harnessId: harnessIdSchema, refresh: external_exports.boolean().optional() }).strict();
14742
14815
  var harnessAccountInspectResultSchema = external_exports.object({
14743
14816
  ...harnessAccountIdentityShape,
14744
- account: harnessAccountSnapshotSchema.nullable()
14817
+ account: harnessAccountSnapshotSchema.nullable(),
14818
+ /** Every Billing Source from one Harness; `account` remains the first for older clients. */
14819
+ accounts: external_exports.array(harnessAccountSnapshotSchema).max(8).optional()
14745
14820
  }).strict();
14746
14821
  var harnessAccountListParamsSchema = external_exports.object({ refresh: external_exports.boolean().optional() }).strict();
14747
14822
  var harnessAccountListResultSchema = external_exports.object({
14748
- accounts: external_exports.array(harnessAccountSnapshotSchema.extend(harnessAccountIdentityShape)).max(128)
14823
+ accounts: external_exports.array(requireReportedQuota(harnessAccountSnapshotObject.extend(harnessAccountIdentityShape))).max(128)
14749
14824
  }).strict();
14750
14825
 
14751
14826
  // ../../shared-contracts/dist/json-value.js
@@ -14883,6 +14958,8 @@ var harnessModelSchema = external_exports.object({
14883
14958
  ref: harnessModelRefSchema,
14884
14959
  label: nonBlankTextSchema2.max(HARNESS_MODEL_LABEL_MAX_LENGTH),
14885
14960
  resolvedModelLabel: harnessResolvedModelLabelSchema.optional(),
14961
+ /** Optional opaque selection for this same Model with priority processing enabled. */
14962
+ fastModel: harnessModelRefSchema.optional(),
14886
14963
  supportedThinkingOptionIds: external_exports.array(harnessThinkingOptionIdSchema).optional()
14887
14964
  }).strict();
14888
14965
  var harnessThinkingOptionsSchema = external_exports.array(harnessThinkingOptionSchema).superRefine((options, context) => {
@@ -14915,6 +14992,16 @@ var harnessModelCatalogSchema = external_exports.object({
14915
14992
  });
14916
14993
  }
14917
14994
  refs.add(model.ref.id);
14995
+ if (model.fastModel) {
14996
+ if (refs.has(model.fastModel.id) || catalog.models.some((entry) => entry.ref.id === model.fastModel?.id)) {
14997
+ context.addIssue({
14998
+ code: "custom",
14999
+ message: "Fast Model refs must be distinct and unique",
15000
+ path: ["models", index, "fastModel"]
15001
+ });
15002
+ }
15003
+ refs.add(model.fastModel.id);
15004
+ }
14918
15005
  const supportedThinkingIds = /* @__PURE__ */ new Set();
14919
15006
  for (const [optionIndex, optionId] of (model.supportedThinkingOptionIds ?? []).entries()) {
14920
15007
  if (supportedThinkingIds.has(optionId)) {
@@ -15034,11 +15121,13 @@ var threadThinkingSelectParamsSchema = external_exports.object({
15034
15121
  thinkingOptionId: harnessThinkingOptionIdSchema
15035
15122
  }).strict();
15036
15123
  var threadInspectionParamsSchema = external_exports.object({
15037
- threadId: hostThreadIdSchema
15124
+ threadId: hostThreadIdSchema,
15125
+ includeReferenceCapability: external_exports.boolean().optional()
15038
15126
  }).strict();
15039
15127
  var codexThreadInspectionSchema = external_exports.object({
15040
15128
  owner: external_exports.literal("codex"),
15041
- locked: external_exports.literal(true)
15129
+ locked: external_exports.literal(true),
15130
+ supportsThreadReferences: external_exports.literal(true).optional()
15042
15131
  }).strict();
15043
15132
  var externalThreadInspectionSchema = external_exports.object({
15044
15133
  owner: external_exports.literal("external"),
@@ -15164,6 +15253,19 @@ var harnessLaunchSettingsSchema = external_exports.object({
15164
15253
  restartRequired: external_exports.boolean()
15165
15254
  }).strict();
15166
15255
 
15256
+ // ../../shared-contracts/dist/harness-installation.js
15257
+ var harnessInstallationParamsSchema = external_exports.object({
15258
+ harnessId: harnessIdSchema,
15259
+ action: external_exports.enum(["check", "update"])
15260
+ }).strict();
15261
+ var harnessInstallationStateSchema = external_exports.object({
15262
+ currentVersion: external_exports.string().min(1).max(128),
15263
+ latestVersion: external_exports.string().min(1).max(128),
15264
+ updateAvailable: external_exports.boolean(),
15265
+ canUpdate: external_exports.boolean(),
15266
+ message: external_exports.string().max(2048).optional()
15267
+ }).strict();
15268
+
15167
15269
  // ../../shared-contracts/dist/codex-accounts.js
15168
15270
  var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
15169
15271
  var nonBlankTextSchema3 = external_exports.string().trim().min(1);
@@ -15466,11 +15568,164 @@ var updateStatusResultSchema = external_exports.strictObject({
15466
15568
  // ../../shared-contracts/dist/index.js
15467
15569
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
15468
15570
 
15571
+ // dist/account-balance.js
15572
+ var DEEPSEEK_BALANCE_ENDPOINT = "https://api.deepseek.com/user/balance";
15573
+ var SUB2API_USAGE_PATH = "/v1/usage";
15574
+ var REQUEST_TIMEOUT_MS = 1e4;
15575
+ var MAX_PI_ACCOUNTS = 8;
15576
+ function agentDirectory(environment) {
15577
+ const configured = environment.PI_CODING_AGENT_DIR?.trim();
15578
+ if (configured)
15579
+ return configured;
15580
+ return path.join(environment.HOME ?? environment.USERPROFILE ?? homedir(), ".pi", "agent");
15581
+ }
15582
+ var record2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
15583
+ async function deepSeekApiKey(environment) {
15584
+ const auth = record2(JSON.parse(await readFile(path.join(agentDirectory(environment), "auth.json"), "utf8")));
15585
+ const deepseek = record2(auth.deepseek);
15586
+ if (deepseek.type !== "api_key")
15587
+ return void 0;
15588
+ return typeof deepseek.key === "string" && deepseek.key.trim() ? deepseek.key : void 0;
15589
+ }
15590
+ function projectSub2ApiUsage(payload, providerId) {
15591
+ const data = record2(payload);
15592
+ if (data.isValid === false)
15593
+ return null;
15594
+ if (data.mode !== "unrestricted" && data.mode !== "quota_limited")
15595
+ return null;
15596
+ const currency = typeof data.unit === "string" ? data.unit.trim() : "";
15597
+ if (!/^[A-Z]{3}$/u.test(currency))
15598
+ return null;
15599
+ const wallet = finiteAmount(data.balance);
15600
+ const remaining = finiteAmount(data.remaining);
15601
+ const quotaRemaining = finiteAmount(record2(data.quota).remaining);
15602
+ const amount = wallet ?? remaining ?? quotaRemaining;
15603
+ if (amount === null)
15604
+ return null;
15605
+ const planName = typeof data.planName === "string" ? data.planName.trim() : "";
15606
+ const label = providerId.trim();
15607
+ if (!label || label.length > 128)
15608
+ return null;
15609
+ const parsed = harnessAccountSnapshotSchema.safeParse({
15610
+ label,
15611
+ ...planName ? { plan: planName.slice(0, 128) } : {},
15612
+ balance: { amount, currency, label: planName || label }
15613
+ });
15614
+ return parsed.success ? parsed.data : null;
15615
+ }
15616
+ function finiteAmount(value) {
15617
+ const amount = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
15618
+ return Number.isFinite(amount) && amount >= 0 ? amount : null;
15619
+ }
15620
+ function projectDeepSeekBalance(payload) {
15621
+ const data = record2(payload);
15622
+ if (!Array.isArray(data.balance_infos))
15623
+ return null;
15624
+ const first = record2(data.balance_infos[0]);
15625
+ const amount = finiteAmount(first.total_balance);
15626
+ const currency = typeof first.currency === "string" ? first.currency.trim() : "";
15627
+ if (amount === null || !currency)
15628
+ return null;
15629
+ const parsed = harnessAccountSnapshotSchema.safeParse({
15630
+ label: "DeepSeek",
15631
+ balance: { amount, currency, label: "DeepSeek API" }
15632
+ });
15633
+ return parsed.success ? parsed.data : null;
15634
+ }
15635
+ function usageEndpoint(baseUrl) {
15636
+ let url2;
15637
+ try {
15638
+ url2 = new URL(baseUrl);
15639
+ } catch {
15640
+ return null;
15641
+ }
15642
+ if (url2.protocol !== "https:" && url2.protocol !== "http:" || !url2.hostname)
15643
+ return null;
15644
+ url2.username = "";
15645
+ url2.password = "";
15646
+ url2.pathname = SUB2API_USAGE_PATH;
15647
+ url2.search = "";
15648
+ url2.hash = "";
15649
+ return url2.toString();
15650
+ }
15651
+ async function configuredSub2ApiProviders(environment) {
15652
+ try {
15653
+ const models = record2(JSON.parse(await readFile(path.join(agentDirectory(environment), "models.json"), "utf8")));
15654
+ const providers = record2(models.providers);
15655
+ const found = [];
15656
+ for (const [id, definition] of Object.entries(providers)) {
15657
+ const provider = record2(definition);
15658
+ const apiKey = typeof provider.apiKey === "string" ? provider.apiKey.trim() : "";
15659
+ const baseUrl = typeof provider.baseUrl === "string" ? provider.baseUrl.trim() : "";
15660
+ if (!id.trim() || id.length > 128 || !apiKey || !usageEndpoint(baseUrl))
15661
+ continue;
15662
+ found.push({ id, apiKey, baseUrl });
15663
+ }
15664
+ return found.sort((left, right) => left.id.localeCompare(right.id));
15665
+ } catch {
15666
+ return [];
15667
+ }
15668
+ }
15669
+ async function fetchSub2ApiBalance(provider, fetchImpl, signal) {
15670
+ const endpoint = usageEndpoint(provider.baseUrl);
15671
+ if (!endpoint)
15672
+ return null;
15673
+ const response = await fetchImpl(endpoint, {
15674
+ headers: { Authorization: `Bearer ${provider.apiKey}`, Accept: "application/json" },
15675
+ redirect: "error",
15676
+ signal
15677
+ });
15678
+ if (!response.ok)
15679
+ return null;
15680
+ return projectSub2ApiUsage(await response.json(), provider.id);
15681
+ }
15682
+ async function fetchPiAccounts(input = {}) {
15683
+ try {
15684
+ const environment = input.environment ?? process.env;
15685
+ const fetchImpl = input.fetch ?? fetch;
15686
+ const signal = input.signal ? AbortSignal.any([input.signal, AbortSignal.timeout(REQUEST_TIMEOUT_MS)]) : AbortSignal.timeout(REQUEST_TIMEOUT_MS);
15687
+ const [providers, deepseek] = await Promise.all([
15688
+ input.readProviders ? input.readProviders() : configuredSub2ApiProviders(environment),
15689
+ fetchPiAccountBalance({ ...input, environment, fetch: fetchImpl, signal })
15690
+ ]);
15691
+ const wallets = await Promise.all(providers.filter((provider) => provider.apiKey.trim() && usageEndpoint(provider.baseUrl)).map((provider) => fetchSub2ApiBalance(provider, fetchImpl, signal).catch(() => null)));
15692
+ return [...wallets, deepseek].filter((account) => account !== null).slice(0, MAX_PI_ACCOUNTS);
15693
+ } catch {
15694
+ return [];
15695
+ }
15696
+ }
15697
+ async function fetchPiAccountBalance(input) {
15698
+ try {
15699
+ const key = await (input.readApiKey ? input.readApiKey() : deepSeekApiKey(input.environment));
15700
+ if (!key)
15701
+ return null;
15702
+ const response = await input.fetch(DEEPSEEK_BALANCE_ENDPOINT, {
15703
+ headers: { Authorization: `Bearer ${key}`, Accept: "application/json" },
15704
+ signal: input.signal
15705
+ });
15706
+ if (!response.ok)
15707
+ return null;
15708
+ return projectDeepSeekBalance(await response.json());
15709
+ } catch {
15710
+ return null;
15711
+ }
15712
+ }
15713
+
15714
+ // dist/pi-credential-imports.js
15715
+ import { randomUUID } from "node:crypto";
15716
+ import { execFile as execFile2 } from "node:child_process";
15717
+ import { promisify } from "node:util";
15718
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync, lstatSync, renameSync, rmdirSync } from "node:fs";
15719
+ import { realpath } from "node:fs/promises";
15720
+ import os2 from "node:os";
15721
+ import path5 from "node:path";
15722
+ import { pathToFileURL } from "node:url";
15723
+
15469
15724
  // ../../harness-discovery/dist/environment.js
15470
15725
  import fs from "node:fs";
15471
- import path from "node:path";
15726
+ import path2 from "node:path";
15472
15727
  function targetPath(platform) {
15473
- return platform === "win32" ? path.win32 : path.posix;
15728
+ return platform === "win32" ? path2.win32 : path2.posix;
15474
15729
  }
15475
15730
  function environmentValue(environment, name) {
15476
15731
  const lowered = name.toLowerCase();
@@ -15512,12 +15767,28 @@ function newestFirst(names) {
15512
15767
  return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
15513
15768
  }
15514
15769
 
15770
+ // ../../harness-discovery/dist/invocation.js
15771
+ import path3 from "node:path";
15772
+ function commandInvocation(command, arguments_, environment, platform = process.platform) {
15773
+ const extension = path3.win32.extname(command).toLowerCase();
15774
+ if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
15775
+ return { command, arguments: [...arguments_], windowsVerbatimArguments: false };
15776
+ }
15777
+ const quote = (value) => `"${value.replaceAll("%", "%%").replaceAll('"', '""')}"`;
15778
+ const commandLine = [command, ...arguments_].map(quote).join(" ");
15779
+ return {
15780
+ command: environmentValue(environment, "ComSpec") ?? "cmd.exe",
15781
+ arguments: ["/d", "/v:off", "/s", "/c", `"${commandLine}"`],
15782
+ windowsVerbatimArguments: true
15783
+ };
15784
+ }
15785
+
15515
15786
  // ../../harness-discovery/dist/node-runtime.js
15516
- import path2 from "node:path";
15787
+ import path4 from "node:path";
15517
15788
  function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
15518
15789
  const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
15519
15790
  const delimiter = platform === "win32" ? ";" : ":";
15520
- const runtimeDirectory = path2.dirname(runtimeExecutable);
15791
+ const runtimeDirectory = path4.dirname(runtimeExecutable);
15521
15792
  const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
15522
15793
  const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
15523
15794
  if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
@@ -15689,6 +15960,116 @@ function resolveHarnessExecutable(spec, input, dependencies = {}) {
15689
15960
  return void 0;
15690
15961
  }
15691
15962
 
15963
+ // ../../harness-discovery/dist/installation.js
15964
+ import { execFile } from "node:child_process";
15965
+ import { homedir as homedir2 } from "node:os";
15966
+ function runInstallationCommand(command, args, environment, timeout = 3e4) {
15967
+ const env = withNodeRuntimeOnPath(environment);
15968
+ const invocation = /\.[cm]?js$/i.test(command) ? commandInvocation(process.execPath, [command, ...args], env) : commandInvocation(command, args, env);
15969
+ return new Promise((resolve, reject) => {
15970
+ const child = execFile(invocation.command, invocation.arguments, {
15971
+ env,
15972
+ cwd: env.HOME ?? env.USERPROFILE ?? homedir2(),
15973
+ encoding: "utf8",
15974
+ timeout,
15975
+ killSignal: "SIGKILL",
15976
+ maxBuffer: 1024 * 1024,
15977
+ windowsHide: true,
15978
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments
15979
+ }, (error51, stdout, stderr) => {
15980
+ if (error51)
15981
+ reject(new Error(error51.killed ? "Harness command timed out" : "Harness command failed; check the native installation and retry"));
15982
+ else
15983
+ resolve((stdout || stderr).trim());
15984
+ });
15985
+ child.stdin?.end();
15986
+ });
15987
+ }
15988
+ function installationVersion(value) {
15989
+ if (typeof value !== "string" || !/^v?\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(value.trim()))
15990
+ throw new Error("Harness returned an invalid version");
15991
+ return value.trim().replace(/^v/, "");
15992
+ }
15993
+ function versionFromOutput(output) {
15994
+ return installationVersion(output.match(/\b\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?\b/)?.[0]);
15995
+ }
15996
+ function newerInstallationVersion(current, latest) {
15997
+ const a = installationVersion(current).replace(/\+.*/, "");
15998
+ const b = installationVersion(latest).replace(/\+.*/, "");
15999
+ const coreA = a.replace(/-.*/, "").split(".").map(BigInt);
16000
+ const coreB = b.replace(/-.*/, "").split(".").map(BigInt);
16001
+ for (let i = 0; i < Math.max(coreA.length, coreB.length); i++) {
16002
+ if ((coreA[i] ?? 0n) !== (coreB[i] ?? 0n))
16003
+ return (coreB[i] ?? 0n) > (coreA[i] ?? 0n);
16004
+ }
16005
+ const preA = a.includes("-") ? a.slice(a.indexOf("-") + 1).split(".") : [];
16006
+ const preB = b.includes("-") ? b.slice(b.indexOf("-") + 1).split(".") : [];
16007
+ if (!preA.length || !preB.length)
16008
+ return !!preA.length && !preB.length;
16009
+ for (let i = 0; i < Math.max(preA.length, preB.length); i++) {
16010
+ const x = preA[i];
16011
+ const y = preB[i];
16012
+ if (x === y)
16013
+ continue;
16014
+ if (x === void 0 || y === void 0)
16015
+ return x === void 0;
16016
+ const numericX = /^\d+$/.test(x);
16017
+ const numericY = /^\d+$/.test(y);
16018
+ if (numericX && numericY) {
16019
+ if (BigInt(x) === BigInt(y))
16020
+ continue;
16021
+ return BigInt(y) > BigInt(x);
16022
+ }
16023
+ if (numericX !== numericY)
16024
+ return numericX;
16025
+ return y > x;
16026
+ }
16027
+ return false;
16028
+ }
16029
+ function createInstallationManager(options) {
16030
+ let checking;
16031
+ let updating;
16032
+ const check2 = () => checking ??= options.check().finally(() => {
16033
+ checking = void 0;
16034
+ });
16035
+ return (action) => {
16036
+ if (updating)
16037
+ return updating;
16038
+ if (action === "check")
16039
+ return check2();
16040
+ updating = (async () => {
16041
+ const before = await check2();
16042
+ if (!before.updateAvailable)
16043
+ return before;
16044
+ if (!before.canUpdate)
16045
+ throw new Error(before.message ?? "This installation cannot be updated automatically");
16046
+ await options.update(before);
16047
+ const after = await check2();
16048
+ if (after.currentVersion === before.currentVersion)
16049
+ throw new Error("The Harness version did not change; check the native updater and retry");
16050
+ return after;
16051
+ })().finally(() => {
16052
+ updating = void 0;
16053
+ });
16054
+ return updating;
16055
+ };
16056
+ }
16057
+ async function fetchInstallationText(url2) {
16058
+ const request = async () => {
16059
+ const response = await fetch(url2, { signal: AbortSignal.timeout(15e3) });
16060
+ if (!response.ok)
16061
+ throw new Error("Could not check the latest Harness version");
16062
+ return response.text();
16063
+ };
16064
+ try {
16065
+ return await request();
16066
+ } catch (error51) {
16067
+ if (error51 instanceof DOMException && (error51.name === "AbortError" || error51.name === "TimeoutError"))
16068
+ throw error51;
16069
+ return request();
16070
+ }
16071
+ }
16072
+
15692
16073
  // dist/command.js
15693
16074
  var piDiscoverySpec = {
15694
16075
  id: "pi",
@@ -15756,6 +16137,15 @@ function describeOauth(credential) {
15756
16137
  ...match ? { vendor: match.vendor } : {}
15757
16138
  };
15758
16139
  }
16140
+ function readPiCodexProviderNames(environment) {
16141
+ const agentDir = environment.PI_CODING_AGENT_DIR ?? path5.join(environment.HOME ?? environment.USERPROFILE ?? os2.homedir(), ".pi/agent");
16142
+ try {
16143
+ const auth = parseAuth(readFileSync(path5.join(agentDir, "auth.json"), "utf8"));
16144
+ return Object.entries(auth).filter(([, credential]) => describeOauth(credential).vendor === "openai-codex").map(([provider]) => provider);
16145
+ } catch {
16146
+ return [];
16147
+ }
16148
+ }
15759
16149
  function writeAuth(filename, content) {
15760
16150
  const temporary = `${filename}.${randomUUID()}.tmp`;
15761
16151
  try {
@@ -15766,8 +16156,8 @@ function writeAuth(filename, content) {
15766
16156
  }
15767
16157
  }
15768
16158
  function removeOwnedFiles(dir) {
15769
- rmSync(path3.join(dir, "index.ts"), { force: true });
15770
- rmSync(path3.join(dir, "import.json"), { force: true });
16159
+ rmSync(path5.join(dir, "index.ts"), { force: true });
16160
+ rmSync(path5.join(dir, "import.json"), { force: true });
15771
16161
  try {
15772
16162
  rmdirSync(dir);
15773
16163
  } catch {
@@ -15775,26 +16165,26 @@ function removeOwnedFiles(dir) {
15775
16165
  }
15776
16166
  async function installation(command, environment, authPath) {
15777
16167
  const executable = await realpath(resolvePiExecutable({ ...command ? { command } : {}, environment }));
15778
- let directory = path3.dirname(executable);
16168
+ let directory = path5.dirname(executable);
15779
16169
  while (true) {
15780
- const manifest = path3.join(directory, "package.json");
16170
+ const manifest = path5.join(directory, "package.json");
15781
16171
  if (existsSync(manifest)) {
15782
16172
  const pkg = JSON.parse(readFileSync(manifest, "utf8"));
15783
16173
  if (pkg.name === "@earendil-works/pi-coding-agent")
15784
16174
  break;
15785
16175
  }
15786
- const parent = path3.dirname(directory);
16176
+ const parent = path5.dirname(directory);
15787
16177
  if (parent === directory)
15788
16178
  throw new Error("Pi credential import requires a supported npm Pi installation");
15789
16179
  directory = parent;
15790
16180
  }
15791
- const storage = await import(pathToFileURL(path3.join(directory, "dist/core/auth-storage.js")).href);
15792
- const ai = path3.join(directory, "node_modules/@earendil-works/pi-ai/dist");
15793
- const all = await import(pathToFileURL(path3.join(ai, "providers/all.js")).href);
16181
+ const storage = await import(pathToFileURL(path5.join(directory, "dist/core/auth-storage.js")).href);
16182
+ const ai = path5.join(directory, "node_modules/@earendil-works/pi-ai/dist");
16183
+ const all = await import(pathToFileURL(path5.join(ai, "providers/all.js")).href);
15794
16184
  const providers = all.getBuiltinProviders();
15795
16185
  const providerModules = {
15796
- "openai-codex": pathToFileURL(path3.join(ai, "providers/openai-codex.js")).href,
15797
- xai: pathToFileURL(path3.join(ai, "providers/xai.js")).href
16186
+ "openai-codex": pathToFileURL(path5.join(ai, "providers/openai-codex.js")).href,
16187
+ xai: pathToFileURL(path5.join(ai, "providers/xai.js")).href
15798
16188
  };
15799
16189
  for (const [id, url2] of Object.entries(providerModules)) {
15800
16190
  const module = await import(url2);
@@ -15807,9 +16197,9 @@ async function installation(command, environment, authPath) {
15807
16197
  providerModules,
15808
16198
  reservedNames: providers.map((p) => typeof p === "string" ? p : p.id),
15809
16199
  async configuredProviderNames() {
15810
- const { stdout } = await promisify(execFile)(process.execPath, [executable, "--offline", "--no-approve", "--list-models"], {
15811
- cwd: existsSync(path3.dirname(authPath)) ? path3.dirname(authPath) : os2.homedir(),
15812
- env: { ...environment, PI_CODING_AGENT_DIR: path3.dirname(authPath), PI_OFFLINE: "1" },
16200
+ const { stdout } = await promisify(execFile2)(process.execPath, [executable, "--offline", "--no-approve", "--list-models"], {
16201
+ cwd: existsSync(path5.dirname(authPath)) ? path5.dirname(authPath) : os2.homedir(),
16202
+ env: { ...environment, PI_CODING_AGENT_DIR: path5.dirname(authPath), PI_OFFLINE: "1" },
15813
16203
  timeout: 15e3,
15814
16204
  maxBuffer: 4 * 1024 * 1024
15815
16205
  });
@@ -15839,26 +16229,26 @@ export default async function (pi) {
15839
16229
  }
15840
16230
  function createPiCredentialImports(options = {}) {
15841
16231
  const env = { ...process.env, ...options.environment };
15842
- const agentDir = env.PI_CODING_AGENT_DIR ?? path3.join(env.HOME ?? os2.homedir(), ".pi/agent");
15843
- const authPath = path3.join(agentDir, "auth.json");
15844
- const extensionsDir = path3.join(agentDir, "extensions");
16232
+ const agentDir = env.PI_CODING_AGENT_DIR ?? path5.join(env.HOME ?? os2.homedir(), ".pi/agent");
16233
+ const authPath = path5.join(agentDir, "auth.json");
16234
+ const extensionsDir = path5.join(agentDir, "extensions");
15845
16235
  const saveAuth = (auth) => (options.writeAuth ?? writeAuth)(authPath, JSON.stringify(auth, null, 2) + "\n");
15846
16236
  const resolve = () => options.resolveInstallation?.(authPath) ?? installation(options.command, env, authPath);
15847
- const location = (name) => path3.join(extensionsDir, `${PREFIX}${credentialImportNameSchema.parse(name)}`);
16237
+ const location = (name) => path5.join(extensionsDir, `${PREFIX}${credentialImportNameSchema.parse(name)}`);
15848
16238
  const readRecord = (name) => {
15849
16239
  const dir = location(name);
15850
16240
  if (lstatSync(dir).isSymbolicLink())
15851
16241
  throw new Error("Imported configuration was changed; manage it in Pi");
15852
- const value = JSON.parse(readFileSync(path3.join(dir, "import.json"), "utf8"));
16242
+ const value = JSON.parse(readFileSync(path5.join(dir, "import.json"), "utf8"));
15853
16243
  if (value.version !== 1 || typeof value.owner !== "string" || typeof value.extension !== "string")
15854
16244
  throw new Error("Invalid import metadata");
15855
- const record6 = value.record;
15856
- if (!object2(record6))
16245
+ const record7 = value.record;
16246
+ if (!object2(record7))
15857
16247
  throw new Error("Invalid import metadata");
15858
16248
  value.record = credentialImportRecordSchema.parse({
15859
- name: record6.name,
15860
- source: record6.source,
15861
- importedAt: record6.importedAt
16249
+ name: record7.name,
16250
+ source: record7.source,
16251
+ importedAt: record7.importedAt
15862
16252
  });
15863
16253
  if (value.record.name !== name)
15864
16254
  throw new Error("Import identity mismatch");
@@ -15866,7 +16256,7 @@ function createPiCredentialImports(options = {}) {
15866
16256
  };
15867
16257
  const owned = (meta3, auth) => {
15868
16258
  const credential = auth[meta3.record.name];
15869
- const file2 = path3.join(location(meta3.record.name), "index.ts");
16259
+ const file2 = path5.join(location(meta3.record.name), "index.ts");
15870
16260
  return existsSync(file2) && !lstatSync(file2).isSymbolicLink() && readFileSync(file2, "utf8") === meta3.extension && object2(credential) && credential.type === "oauth" && credential.codexhostImportId === meta3.owner;
15871
16261
  };
15872
16262
  const readAuth = () => existsSync(authPath) ? parseAuth(readFileSync(authPath, "utf8")) : {};
@@ -15880,7 +16270,7 @@ function createPiCredentialImports(options = {}) {
15880
16270
  const name = entry.slice(PREFIX.length);
15881
16271
  if (!credentialImportNameSchema.safeParse(name).success)
15882
16272
  continue;
15883
- if (!existsSync(path3.join(location(name), "import.json")))
16273
+ if (!existsSync(path5.join(location(name), "import.json")))
15884
16274
  continue;
15885
16275
  try {
15886
16276
  const meta3 = readRecord(name);
@@ -15901,7 +16291,7 @@ function createPiCredentialImports(options = {}) {
15901
16291
  },
15902
16292
  async listOthers() {
15903
16293
  const auth = readAuth();
15904
- const ours = new Set(ownedRecords(auth).map((record6) => record6.name));
16294
+ const ours = new Set(ownedRecords(auth).map((record7) => record7.name));
15905
16295
  const result = /* @__PURE__ */ new Map();
15906
16296
  const usable = (provider) => Boolean(provider) && provider.length <= 128 && !ours.has(provider) && !result.has(provider);
15907
16297
  for (const [provider, credential] of Object.entries(auth)) {
@@ -15914,7 +16304,7 @@ function createPiCredentialImports(options = {}) {
15914
16304
  ...describeOauth(credential)
15915
16305
  });
15916
16306
  }
15917
- const modelsPath = path3.join(agentDir, "models.json");
16307
+ const modelsPath = path5.join(agentDir, "models.json");
15918
16308
  if (existsSync(modelsPath)) {
15919
16309
  const models = JSON.parse(readFileSync(modelsPath, "utf8"));
15920
16310
  const providers = object2(models) && object2(models.providers) ? models.providers : {};
@@ -15936,7 +16326,7 @@ function createPiCredentialImports(options = {}) {
15936
16326
  if (sdk.reservedNames.includes(name) || (await sdk.configuredProviderNames?.())?.includes(name))
15937
16327
  throw new Error("Provider name already exists; choose another name");
15938
16328
  const owner = randomUUID();
15939
- const record6 = credentialImportRecordSchema.parse({
16329
+ const record7 = credentialImportRecordSchema.parse({
15940
16330
  name,
15941
16331
  source: transfer.source,
15942
16332
  importedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -15948,15 +16338,15 @@ function createPiCredentialImports(options = {}) {
15948
16338
  try {
15949
16339
  sdk.backend.withLock((current) => {
15950
16340
  const auth = parseAuth(current);
15951
- const modelsPath = path3.join(agentDir, "models.json");
16341
+ const modelsPath = path5.join(agentDir, "models.json");
15952
16342
  const models = existsSync(modelsPath) ? JSON.parse(readFileSync(modelsPath, "utf8")) : {};
15953
- if (Object.hasOwn(auth, name) || Object.hasOwn(models.providers ?? {}, name) || existsSync(dir) || existsSync(path3.join(extensionsDir, `${name}-provider.ts`)))
16343
+ if (Object.hasOwn(auth, name) || Object.hasOwn(models.providers ?? {}, name) || existsSync(dir) || existsSync(path5.join(extensionsDir, `${name}-provider.ts`)))
15954
16344
  throw new Error("Provider name already exists; choose another name");
15955
16345
  mkdirSync(extensionsDir, { recursive: true, mode: 448 });
15956
16346
  mkdirSync(dir, { mode: 448 });
15957
16347
  created = true;
15958
- writeFileSync(path3.join(dir, "import.json"), JSON.stringify({ version: 1, owner, record: record6, extension }), { flag: "wx", mode: 384 });
15959
- writeFileSync(path3.join(dir, "index.ts"), extension, { flag: "wx", mode: 384 });
16348
+ writeFileSync(path5.join(dir, "import.json"), JSON.stringify({ version: 1, owner, record: record7, extension }), { flag: "wx", mode: 384 });
16349
+ writeFileSync(path5.join(dir, "index.ts"), extension, { flag: "wx", mode: 384 });
15960
16350
  auth[name] = { type: "oauth", ...transfer.oauth, codexhostImportId: owner };
15961
16351
  saveAuth(auth);
15962
16352
  committed = true;
@@ -15975,7 +16365,7 @@ function createPiCredentialImports(options = {}) {
15975
16365
  const auth = parseAuth(current);
15976
16366
  if (!owned(meta3, auth) || meta3.record.source.id !== transfer.source.id || meta3.record.source.provider !== transfer.source.provider)
15977
16367
  throw new Error("Import ownership or source account changed; refusing replacement");
15978
- const metadataPath = path3.join(location(name), "import.json");
16368
+ const metadataPath = path5.join(location(name), "import.json");
15979
16369
  const previous = readFileSync(metadataPath, "utf8");
15980
16370
  const updated = {
15981
16371
  ...meta3,
@@ -16009,15 +16399,229 @@ function createPiCredentialImports(options = {}) {
16009
16399
  };
16010
16400
  }
16011
16401
 
16402
+ // dist/pi-fast-mode.js
16403
+ import { createHash, randomUUID as randomUUID2 } from "node:crypto";
16404
+ import { mkdir, readFile as readFile2, rename, rm, writeFile } from "node:fs/promises";
16405
+ import { homedir as homedir3 } from "node:os";
16406
+ import path6 from "node:path";
16407
+
16408
+ // dist/pi-model-catalog.js
16409
+ var PI_MODEL_REF_PREFIX = "pi-model-v1.";
16410
+ var PI_DRAFT_THINKING_OPTION_IDS = [
16411
+ "off",
16412
+ "minimal",
16413
+ "low",
16414
+ "medium",
16415
+ "high",
16416
+ "xhigh",
16417
+ "max"
16418
+ ].map((id) => harnessThinkingOptionIdSchema.parse(id));
16419
+ var PI_THINKING_LABELS = {
16420
+ off: "Off",
16421
+ minimal: "Minimal",
16422
+ low: "Low",
16423
+ medium: "Medium",
16424
+ high: "High",
16425
+ xhigh: "Extra High",
16426
+ max: "Max"
16427
+ };
16428
+ function compareText(left, right) {
16429
+ return left < right ? -1 : left > right ? 1 : 0;
16430
+ }
16431
+ function assertNativePart(value, name) {
16432
+ if (value.trim().length === 0)
16433
+ throw new Error(`Pi ${name} must not be empty`);
16434
+ }
16435
+ function encodePiModelRef(model) {
16436
+ assertNativePart(model.provider, "Model provider");
16437
+ assertNativePart(model.id, "Model id");
16438
+ const encoded = Buffer.from(JSON.stringify(model.fast ? [model.provider, model.id, true] : [model.provider, model.id]), "utf8").toString("base64url");
16439
+ return harnessModelRefSchema.parse({ id: `${PI_MODEL_REF_PREFIX}${encoded}` });
16440
+ }
16441
+ function decodePiModelRef(ref) {
16442
+ const parsedRef = harnessModelRefSchema.parse(ref);
16443
+ if (!parsedRef.id.startsWith(PI_MODEL_REF_PREFIX)) {
16444
+ throw new Error("Model Ref does not belong to PiAdapter");
16445
+ }
16446
+ const encoded = parsedRef.id.slice(PI_MODEL_REF_PREFIX.length);
16447
+ let decoded;
16448
+ try {
16449
+ decoded = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
16450
+ } catch {
16451
+ throw new Error("Pi Model Ref is malformed");
16452
+ }
16453
+ if (!Array.isArray(decoded) || decoded.length !== 2 && !(decoded.length === 3 && decoded[2] === true) || typeof decoded[0] !== "string" || typeof decoded[1] !== "string") {
16454
+ throw new Error("Pi Model Ref has an invalid native identity");
16455
+ }
16456
+ const native = {
16457
+ provider: decoded[0],
16458
+ id: decoded[1],
16459
+ ...decoded[2] === true ? { fast: true } : {}
16460
+ };
16461
+ assertNativePart(native.provider, "Model provider");
16462
+ assertNativePart(native.id, "Model id");
16463
+ if (encodePiModelRef(native).id !== parsedRef.id) {
16464
+ throw new Error("Pi Model Ref is not canonical");
16465
+ }
16466
+ return native;
16467
+ }
16468
+ function samePiModel(left, right) {
16469
+ return left === null ? right === null : right !== null && left.provider === right.provider && left.id === right.id;
16470
+ }
16471
+ function fallbackThinkingLabel(id) {
16472
+ const label = id.split(/[._~-]+/u).filter((part) => part.length > 0).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
16473
+ return label || id;
16474
+ }
16475
+ function normalizePiThinkingOptions(levels) {
16476
+ return levels.map((id) => harnessThinkingOptionSchema.parse({
16477
+ id,
16478
+ label: PI_THINKING_LABELS[id] ?? fallbackThinkingLabel(id)
16479
+ }));
16480
+ }
16481
+ function normalizePiModelCatalog(nativeModels, effectiveModel, thinkingLevels, effectiveThinkingOptionId) {
16482
+ const byRef = /* @__PURE__ */ new Map();
16483
+ for (const native of nativeModels) {
16484
+ const ref = encodePiModelRef(native);
16485
+ const existing = byRef.get(ref.id);
16486
+ if (existing) {
16487
+ if (existing.reasoning !== native.reasoning) {
16488
+ throw new Error("Pi duplicate Model entries disagree on reasoning capability");
16489
+ }
16490
+ continue;
16491
+ }
16492
+ byRef.set(ref.id, {
16493
+ model: {
16494
+ ref,
16495
+ label: `${native.provider} / ${native.id}`
16496
+ },
16497
+ reasoning: native.reasoning
16498
+ });
16499
+ }
16500
+ const defaultModel = effectiveModel ? encodePiModelRef(effectiveModel) : void 0;
16501
+ if (defaultModel && !byRef.has(defaultModel.id)) {
16502
+ throw new Error("Pi effective Model is absent from the available Model catalog");
16503
+ }
16504
+ if (thinkingLevels && effectiveThinkingOptionId && !thinkingLevels.includes(effectiveThinkingOptionId)) {
16505
+ throw new Error("Pi effective Thinking option is absent from the available option catalog");
16506
+ }
16507
+ if (thinkingLevels && !effectiveThinkingOptionId) {
16508
+ throw new Error("Pi did not report an effective Thinking option");
16509
+ }
16510
+ const thinkingOptions = thinkingLevels ? normalizePiThinkingOptions(PI_DRAFT_THINKING_OPTION_IDS) : [];
16511
+ const allThinkingOptionIds = thinkingOptions.map(({ id }) => id);
16512
+ const offThinkingOptionId = thinkingOptions.find(({ id }) => id === "off")?.id;
16513
+ const models = [...byRef.values()].map(({ model, reasoning }) => ({
16514
+ ...model,
16515
+ supportedThinkingOptionIds: reasoning ? allThinkingOptionIds : offThinkingOptionId ? [offThinkingOptionId] : []
16516
+ })).sort((left, right) => compareText(left.label, right.label) || compareText(left.ref.id, right.ref.id));
16517
+ const defaultThinkingOptionId = thinkingOptions.find(({ id }) => id === effectiveThinkingOptionId)?.id;
16518
+ return harnessModelCatalogSchema.parse({
16519
+ models,
16520
+ ...defaultModel ? { defaultModel } : {},
16521
+ thinkingOptions,
16522
+ ...defaultThinkingOptionId ? { defaultThinkingOptionId } : {}
16523
+ });
16524
+ }
16525
+
16526
+ // dist/pi-fast-mode.js
16527
+ var PI_FAST_COMMAND = "codexhost-fast-mode";
16528
+ var PI_FAST_ACK = "codexhost-fast-mode:";
16529
+ var PI_FAST_EXTENSION = `export default function(pi) {
16530
+ let target;
16531
+ const wrapped = new Set();
16532
+ pi.on("model_select", (_event, ctx) => {
16533
+ if (target && (target.provider !== ctx.model?.provider || target.id !== ctx.model?.id || ctx.model?.api !== "openai-codex-responses")) target = undefined;
16534
+ });
16535
+ pi.on("session_start", (_event, ctx) => {
16536
+ if (typeof ctx.modelRegistry.getProvider !== "function") return;
16537
+ pi.registerCommand("${PI_FAST_COMMAND}", {
16538
+ description: "Codex Host Fast mode",
16539
+ handler: async (args, ctx) => {
16540
+ const [mode, nonce] = args.split(" ");
16541
+ if (!nonce || (mode !== "on" && mode !== "off")) throw new Error("Invalid Fast selection");
16542
+ if (mode === "on") {
16543
+ const model = ctx.model;
16544
+ if (!model || model.api !== "openai-codex-responses") throw new Error("Fast requires the Codex API");
16545
+ const original = ctx.modelRegistry.getProvider(model.provider);
16546
+ if (!original) throw new Error("Codex Provider is unavailable");
16547
+ if (!wrapped.has(model.provider)) {
16548
+ const options = (model, value) => target && model.api === "openai-codex-responses" && target.provider === model.provider && target.id === model.id
16549
+ ? {
16550
+ ...value,
16551
+ serviceTier: "priority",
16552
+ // Pi streamSimple drops serviceTier but preserves onPayload.
16553
+ onPayload: async (payload, requestModel) => {
16554
+ const request = { ...payload, service_tier: "priority" };
16555
+ const replacement = await value?.onPayload?.(request, requestModel);
16556
+ return { ...(replacement === undefined ? request : replacement), service_tier: "priority" };
16557
+ },
16558
+ } : value;
16559
+ pi.registerProvider({
16560
+ ...original,
16561
+ stream: (model, context, value) => original.stream(model, context, options(model, value)),
16562
+ streamSimple: (model, context, value) => original.streamSimple(model, context, options(model, value)),
16563
+ });
16564
+ wrapped.add(model.provider);
16565
+ }
16566
+ target = { provider: model.provider, id: model.id };
16567
+ } else target = undefined;
16568
+ ctx.ui.notify("${PI_FAST_ACK}" + nonce + ":" + mode, "info");
16569
+ },
16570
+ });
16571
+ });
16572
+ }
16573
+ `;
16574
+ async function ensurePiFastExtension(environment) {
16575
+ const digest = createHash("sha256").update(PI_FAST_EXTENSION).digest("hex").slice(0, 16);
16576
+ const dataDirectory = environment.CODEXHOST_DATA_DIR ?? path6.join(environment.HOME ?? environment.USERPROFILE ?? homedir3(), ".codexhost");
16577
+ const directory = path6.resolve(dataDirectory, "extensions", "pi-codex-fast");
16578
+ const file2 = path6.join(directory, `${digest}.mjs`);
16579
+ if (await readFile2(file2, "utf8").catch(() => "") === PI_FAST_EXTENSION)
16580
+ return file2;
16581
+ await mkdir(directory, { recursive: true });
16582
+ const temporary = `${file2}.${randomUUID2()}.tmp`;
16583
+ try {
16584
+ await writeFile(temporary, PI_FAST_EXTENSION, { mode: 384 });
16585
+ try {
16586
+ await rename(temporary, file2);
16587
+ } catch (error51) {
16588
+ if (await readFile2(file2, "utf8").catch(() => "") !== PI_FAST_EXTENSION)
16589
+ throw error51;
16590
+ }
16591
+ } finally {
16592
+ await rm(temporary, { force: true });
16593
+ }
16594
+ return file2;
16595
+ }
16596
+ async function piFastModelKeys(models, environment) {
16597
+ try {
16598
+ const codexHome = environment.CODEX_HOME ?? path6.join(environment.HOME ?? environment.USERPROFILE ?? homedir3(), ".codex");
16599
+ const cache = JSON.parse(await readFile2(path6.join(codexHome, "models_cache.json"), "utf8"));
16600
+ if (!cache || typeof cache !== "object" || !("models" in cache) || !Array.isArray(cache.models))
16601
+ return /* @__PURE__ */ new Set();
16602
+ const priority = new Set(cache.models.filter((model) => typeof model?.slug === "string" && Array.isArray(model.service_tiers) && model.service_tiers.some((tier) => tier?.id === "priority")).map((model) => model.slug));
16603
+ const codexProviders = new Set(readPiCodexProviderNames(environment));
16604
+ return new Set(models.filter((model) => model.api === "openai-codex-responses" && codexProviders.has(model.provider) && priority.has(model.id)).map((model) => encodePiModelRef(model).id));
16605
+ } catch {
16606
+ return /* @__PURE__ */ new Set();
16607
+ }
16608
+ }
16609
+ function withPiFast(catalog, supported) {
16610
+ return {
16611
+ ...catalog,
16612
+ models: catalog.models.map((model) => supported.has(model.ref.id) ? { ...model, fastModel: encodePiModelRef({ ...decodePiModelRef(model.ref), fast: true }) } : model)
16613
+ };
16614
+ }
16615
+
16012
16616
  // dist/pi-empty-session.js
16013
16617
  import { createReadStream } from "node:fs";
16014
16618
  import { createInterface } from "node:readline";
16015
- import { randomUUID as randomUUID2 } from "node:crypto";
16016
- import { link, open as open2, rm } from "node:fs/promises";
16017
- import path4 from "node:path";
16619
+ import { randomUUID as randomUUID3 } from "node:crypto";
16620
+ import { link, open as open2, rm as rm2 } from "node:fs/promises";
16621
+ import path7 from "node:path";
16018
16622
 
16019
16623
  // dist/pi-subagents.js
16020
- import { createHash } from "node:crypto";
16624
+ import { createHash as createHash2 } from "node:crypto";
16021
16625
 
16022
16626
  // dist/pi-subagent-workflow.js
16023
16627
  var PREFIX2 = "pi-subagents-workflow-v1:";
@@ -16031,23 +16635,23 @@ var STATES = {
16031
16635
  rejected: "failed",
16032
16636
  detached: "running"
16033
16637
  };
16034
- function record2(value) {
16638
+ function record3(value) {
16035
16639
  return typeof value === "object" && value !== null && !Array.isArray(value);
16036
16640
  }
16037
16641
  function text(value, limit = 256) {
16038
16642
  return typeof value === "string" && value.length > 0 && value.length <= limit;
16039
16643
  }
16040
16644
  function piWorkflowSummary(result) {
16041
- if (!record2(result) || !record2(result.details) || result.details.mode !== "workflow" || result.details.asyncId !== void 0)
16645
+ if (!record3(result) || !record3(result.details) || result.details.mode !== "workflow" || result.details.asyncId !== void 0)
16042
16646
  return null;
16043
16647
  const details = result.details;
16044
16648
  const summary = details.workflowChildren;
16045
- 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)
16649
+ if (!record3(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)
16046
16650
  return null;
16047
16651
  const children = [];
16048
16652
  const seen = /* @__PURE__ */ new Set();
16049
16653
  for (const child of summary.children) {
16050
- if (!record2(child) || !text(child.childId) || seen.has(child.childId) || typeof child.state !== "string" || !Object.hasOwn(STATES, child.state))
16654
+ if (!record3(child) || !text(child.childId) || seen.has(child.childId) || typeof child.state !== "string" || !Object.hasOwn(STATES, child.state))
16051
16655
  return null;
16052
16656
  for (const key of ["agent", "sessionName", "model", "thinking"]) {
16053
16657
  if (child[key] !== void 0 && !text(child[key], 2048))
@@ -16120,7 +16724,7 @@ var STATUS_PREFIX = "PI_SUBAGENT_ASYNC_JSON:";
16120
16724
  var INSPECT_PREFIX = "PI_SUBAGENT_INSPECT_JSON:";
16121
16725
  var ID_PREFIX = "pi-subagents-v1:";
16122
16726
  var MAX_BYTES = 64 * 1024;
16123
- function record3(value) {
16727
+ function record4(value) {
16124
16728
  return typeof value === "object" && value !== null && !Array.isArray(value);
16125
16729
  }
16126
16730
  function token(value) {
@@ -16137,7 +16741,7 @@ var statuses = {
16137
16741
  rejected: "failed"
16138
16742
  };
16139
16743
  function node(value, depth, budget) {
16140
- 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))
16744
+ if (!record4(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))
16141
16745
  return null;
16142
16746
  const children = [];
16143
16747
  if (value.children !== void 0) {
@@ -16159,14 +16763,14 @@ function node(value, depth, budget) {
16159
16763
  };
16160
16764
  }
16161
16765
  function widget(value, key, prefix) {
16162
- if (!record3(value) || value.type !== "extension_ui_request" || value.method !== "setWidget" || value.widgetKey !== key || !Array.isArray(value.widgetLines))
16766
+ if (!record4(value) || value.type !== "extension_ui_request" || value.method !== "setWidget" || value.widgetKey !== key || !Array.isArray(value.widgetLines))
16163
16767
  return null;
16164
16768
  const line = value.widgetLines.find((part) => typeof part === "string" && part.startsWith(prefix));
16165
16769
  if (!line || Buffer.byteLength(line) > MAX_BYTES + prefix.length)
16166
16770
  return null;
16167
16771
  try {
16168
16772
  const parsed = JSON.parse(line.slice(prefix.length));
16169
- return record3(parsed) && parsed.version === 1 ? parsed : null;
16773
+ return record4(parsed) && parsed.version === 1 ? parsed : null;
16170
16774
  } catch {
16171
16775
  return null;
16172
16776
  }
@@ -16230,7 +16834,7 @@ function states(run) {
16230
16834
  return result;
16231
16835
  }
16232
16836
  function asyncRunId(toolName, result) {
16233
- if (toolName !== "subagent" || !record3(result) || !record3(result.details))
16837
+ if (toolName !== "subagent" || !record4(result) || !record4(result.details))
16234
16838
  return null;
16235
16839
  const details = result.details;
16236
16840
  return ["single", "parallel", "chain", "workflow"].includes(String(details.mode)) && token(details.asyncId) && typeof details.asyncDir === "string" ? details.asyncId : null;
@@ -16370,15 +16974,15 @@ function parsePiSubagentInspection(value) {
16370
16974
  const parsed = widget(value, "subagent-inspect", INSPECT_PREFIX);
16371
16975
  if (!parsed || parsed.kind !== "pi-subagents.inspect-reply" || !token(parsed.requestId))
16372
16976
  return null;
16373
- if (parsed.error !== void 0 && (!record3(parsed.error) || typeof parsed.error.code !== "string" || typeof parsed.error.message !== "string"))
16977
+ if (parsed.error !== void 0 && (!record4(parsed.error) || typeof parsed.error.code !== "string" || typeof parsed.error.message !== "string"))
16374
16978
  return null;
16375
16979
  for (const field of ["asyncId", "childId", "status", "task", "finalOutput"]) {
16376
16980
  if (parsed[field] !== void 0 && typeof parsed[field] !== "string")
16377
16981
  return null;
16378
16982
  }
16379
- 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")))
16983
+ if (parsed.messages !== void 0 && (!Array.isArray(parsed.messages) || parsed.messages.length > 200 || parsed.messages.some((entry) => !record4(entry) || typeof entry.role !== "string" || typeof entry.text !== "string" || !["text", "toolCall", "toolResult"].includes(String(entry.kind)) || entry.name !== void 0 && typeof entry.name !== "string")))
16380
16984
  return null;
16381
- 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))
16985
+ if (parsed.truncated !== void 0 && (!record4(parsed.truncated) || typeof parsed.truncated.task !== "boolean" || typeof parsed.truncated.finalOutput !== "boolean" || !Number.isSafeInteger(parsed.truncated.messages) || Number(parsed.truncated.messages) < 0))
16382
16986
  return null;
16383
16987
  return parsed;
16384
16988
  }
@@ -16397,7 +17001,7 @@ ${entry.text}`);
16397
17001
  nativeTurnRef: nativeTurnRefSchema.parse({
16398
17002
  harnessId: "pi",
16399
17003
  nativeSessionId: parentSessionId,
16400
- nativeTurnKey: `pi-subagent-${createHash("sha256").update(id).digest("hex")}`,
17004
+ nativeTurnKey: `pi-subagent-${createHash2("sha256").update(id).digest("hex")}`,
16401
17005
  formatVersion: 1
16402
17006
  }),
16403
17007
  input: reply.task ? [{ type: "text", text: reply.task }] : [],
@@ -16405,7 +17009,7 @@ ${entry.text}`);
16405
17009
  item: {
16406
17010
  type: "agentMessage",
16407
17011
  text: text2,
16408
- itemId: hostItemIdSchema.parse(`pi-subagent-${createHash("sha256").update(`${id}:${index}:${text2}`).digest("hex")}`)
17012
+ itemId: hostItemIdSchema.parse(`pi-subagent-${createHash2("sha256").update(`${id}:${index}:${text2}`).digest("hex")}`)
16409
17013
  },
16410
17014
  outcome: { status: "succeeded" }
16411
17015
  })),
@@ -16425,120 +17029,6 @@ ${entry.text}`);
16425
17029
  };
16426
17030
  }
16427
17031
 
16428
- // dist/pi-model-catalog.js
16429
- var PI_MODEL_REF_PREFIX = "pi-model-v1.";
16430
- var PI_DRAFT_THINKING_OPTION_IDS = [
16431
- "off",
16432
- "minimal",
16433
- "low",
16434
- "medium",
16435
- "high",
16436
- "xhigh",
16437
- "max"
16438
- ].map((id) => harnessThinkingOptionIdSchema.parse(id));
16439
- var PI_THINKING_LABELS = {
16440
- off: "Off",
16441
- minimal: "Minimal",
16442
- low: "Low",
16443
- medium: "Medium",
16444
- high: "High",
16445
- xhigh: "Extra High",
16446
- max: "Max"
16447
- };
16448
- function compareText(left, right) {
16449
- return left < right ? -1 : left > right ? 1 : 0;
16450
- }
16451
- function assertNativePart(value, name) {
16452
- if (value.trim().length === 0)
16453
- throw new Error(`Pi ${name} must not be empty`);
16454
- }
16455
- function encodePiModelRef(model) {
16456
- assertNativePart(model.provider, "Model provider");
16457
- assertNativePart(model.id, "Model id");
16458
- const encoded = Buffer.from(JSON.stringify([model.provider, model.id]), "utf8").toString("base64url");
16459
- return harnessModelRefSchema.parse({ id: `${PI_MODEL_REF_PREFIX}${encoded}` });
16460
- }
16461
- function decodePiModelRef(ref) {
16462
- const parsedRef = harnessModelRefSchema.parse(ref);
16463
- if (!parsedRef.id.startsWith(PI_MODEL_REF_PREFIX)) {
16464
- throw new Error("Model Ref does not belong to PiAdapter");
16465
- }
16466
- const encoded = parsedRef.id.slice(PI_MODEL_REF_PREFIX.length);
16467
- let decoded;
16468
- try {
16469
- decoded = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
16470
- } catch {
16471
- throw new Error("Pi Model Ref is malformed");
16472
- }
16473
- if (!Array.isArray(decoded) || decoded.length !== 2 || typeof decoded[0] !== "string" || typeof decoded[1] !== "string") {
16474
- throw new Error("Pi Model Ref has an invalid native identity");
16475
- }
16476
- const native = { provider: decoded[0], id: decoded[1] };
16477
- assertNativePart(native.provider, "Model provider");
16478
- assertNativePart(native.id, "Model id");
16479
- if (encodePiModelRef(native).id !== parsedRef.id) {
16480
- throw new Error("Pi Model Ref is not canonical");
16481
- }
16482
- return native;
16483
- }
16484
- function samePiModel(left, right) {
16485
- return left === null ? right === null : right !== null && left.provider === right.provider && left.id === right.id;
16486
- }
16487
- function fallbackThinkingLabel(id) {
16488
- const label = id.split(/[._~-]+/u).filter((part) => part.length > 0).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
16489
- return label || id;
16490
- }
16491
- function normalizePiThinkingOptions(levels) {
16492
- return levels.map((id) => harnessThinkingOptionSchema.parse({
16493
- id,
16494
- label: PI_THINKING_LABELS[id] ?? fallbackThinkingLabel(id)
16495
- }));
16496
- }
16497
- function normalizePiModelCatalog(nativeModels, effectiveModel, thinkingLevels, effectiveThinkingOptionId) {
16498
- const byRef = /* @__PURE__ */ new Map();
16499
- for (const native of nativeModels) {
16500
- const ref = encodePiModelRef(native);
16501
- const existing = byRef.get(ref.id);
16502
- if (existing) {
16503
- if (existing.reasoning !== native.reasoning) {
16504
- throw new Error("Pi duplicate Model entries disagree on reasoning capability");
16505
- }
16506
- continue;
16507
- }
16508
- byRef.set(ref.id, {
16509
- model: {
16510
- ref,
16511
- label: `${native.provider} / ${native.id}`
16512
- },
16513
- reasoning: native.reasoning
16514
- });
16515
- }
16516
- const defaultModel = effectiveModel ? encodePiModelRef(effectiveModel) : void 0;
16517
- if (defaultModel && !byRef.has(defaultModel.id)) {
16518
- throw new Error("Pi effective Model is absent from the available Model catalog");
16519
- }
16520
- if (thinkingLevels && effectiveThinkingOptionId && !thinkingLevels.includes(effectiveThinkingOptionId)) {
16521
- throw new Error("Pi effective Thinking option is absent from the available option catalog");
16522
- }
16523
- if (thinkingLevels && !effectiveThinkingOptionId) {
16524
- throw new Error("Pi did not report an effective Thinking option");
16525
- }
16526
- const thinkingOptions = thinkingLevels ? normalizePiThinkingOptions(PI_DRAFT_THINKING_OPTION_IDS) : [];
16527
- const allThinkingOptionIds = thinkingOptions.map(({ id }) => id);
16528
- const offThinkingOptionId = thinkingOptions.find(({ id }) => id === "off")?.id;
16529
- const models = [...byRef.values()].map(({ model, reasoning }) => ({
16530
- ...model,
16531
- supportedThinkingOptionIds: reasoning ? allThinkingOptionIds : offThinkingOptionId ? [offThinkingOptionId] : []
16532
- })).sort((left, right) => compareText(left.label, right.label) || compareText(left.ref.id, right.ref.id));
16533
- const defaultThinkingOptionId = thinkingOptions.find(({ id }) => id === effectiveThinkingOptionId)?.id;
16534
- return harnessModelCatalogSchema.parse({
16535
- models,
16536
- ...defaultModel ? { defaultModel } : {},
16537
- thinkingOptions,
16538
- ...defaultThinkingOptionId ? { defaultThinkingOptionId } : {}
16539
- });
16540
- }
16541
-
16542
17032
  // dist/pi-history.js
16543
17033
  var piHarnessId = harnessIdSchema.parse("pi");
16544
17034
  function isRecord(value) {
@@ -16844,7 +17334,7 @@ async function verifyPiSessionCwd(input) {
16844
17334
  async function persistEmptyPiSession(input) {
16845
17335
  const { state: state2, history, sourceSessionFile, sourceSessionId, cwd } = input;
16846
17336
  const destination = state2.sessionFile;
16847
- if (!destination || !path4.isAbsolute(destination) || path4.resolve(destination) === path4.resolve(sourceSessionFile) || state2.sessionId === sourceSessionId || mapPiSnapshot(history, { sessionId: state2.sessionId, model: null }).turns.length !== 0)
17337
+ if (!destination || !path7.isAbsolute(destination) || path7.resolve(destination) === path7.resolve(sourceSessionFile) || state2.sessionId === sourceSessionId || mapPiSnapshot(history, { sessionId: state2.sessionId, model: null }).turns.length !== 0)
16848
17338
  throw new Error("Pi empty Session is not an independent empty native fork");
16849
17339
  await verifyPiSessionCwd({
16850
17340
  sessionFile: sourceSessionFile,
@@ -16868,7 +17358,7 @@ async function persistEmptyPiSession(input) {
16868
17358
  cwd,
16869
17359
  parentSession: sourceSessionFile
16870
17360
  };
16871
- const temporary = path4.join(path4.dirname(destination), `.codexhost-${randomUUID2()}.tmp`);
17361
+ const temporary = path7.join(path7.dirname(destination), `.codexhost-${randomUUID3()}.tmp`);
16872
17362
  try {
16873
17363
  const file2 = await open2(temporary, "wx", 384);
16874
17364
  try {
@@ -16879,7 +17369,7 @@ async function persistEmptyPiSession(input) {
16879
17369
  }
16880
17370
  await link(temporary, destination);
16881
17371
  if (process.platform !== "win32") {
16882
- const directory = await open2(path4.dirname(destination), "r");
17372
+ const directory = await open2(path7.dirname(destination), "r");
16883
17373
  try {
16884
17374
  await directory.sync();
16885
17375
  } finally {
@@ -16887,7 +17377,7 @@ async function persistEmptyPiSession(input) {
16887
17377
  }
16888
17378
  }
16889
17379
  } finally {
16890
- await rm(temporary, { force: true });
17380
+ await rm2(temporary, { force: true });
16891
17381
  }
16892
17382
  }
16893
17383
  async function readPiEmptySessionConfiguration(sessionFile) {
@@ -17042,16 +17532,16 @@ var Diff = class {
17042
17532
  }
17043
17533
  }
17044
17534
  }
17045
- addToPath(path10, added, removed, oldPosInc, options) {
17046
- const last = path10.lastComponent;
17535
+ addToPath(path13, added, removed, oldPosInc, options) {
17536
+ const last = path13.lastComponent;
17047
17537
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
17048
17538
  return {
17049
- oldPos: path10.oldPos + oldPosInc,
17539
+ oldPos: path13.oldPos + oldPosInc,
17050
17540
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
17051
17541
  };
17052
17542
  } else {
17053
17543
  return {
17054
- oldPos: path10.oldPos + oldPosInc,
17544
+ oldPos: path13.oldPos + oldPosInc,
17055
17545
  lastComponent: { count: 1, added, removed, previousComponent: last }
17056
17546
  };
17057
17547
  }
@@ -17463,8 +17953,8 @@ function splitLines(text2) {
17463
17953
  }
17464
17954
 
17465
17955
  // dist/pi-adapter.js
17466
- import { randomUUID as randomUUID5 } from "node:crypto";
17467
- import path9 from "node:path";
17956
+ import { randomUUID as randomUUID6 } from "node:crypto";
17957
+ import path12 from "node:path";
17468
17958
 
17469
17959
  // ../../harness-adapter/dist/question.js
17470
17960
  function invalidRequest(message3) {
@@ -17769,16 +18259,16 @@ function mergeLiveHarnessCommands(builtIns, idPrefix, live, exclusions = {}) {
17769
18259
  }
17770
18260
 
17771
18261
  // dist/pi-workflow-child-history.js
17772
- import { createHash as createHash2 } from "node:crypto";
18262
+ import { createHash as createHash3 } from "node:crypto";
17773
18263
  import { constants } from "node:fs";
17774
18264
  import { open as open3 } from "node:fs/promises";
17775
- import path5 from "node:path";
17776
- function record4(value) {
18265
+ import path8 from "node:path";
18266
+ function record5(value) {
17777
18267
  return typeof value === "object" && value !== null && !Array.isArray(value);
17778
18268
  }
17779
18269
  var MAX_SESSION_BYTES = 8 * 1024 * 1024;
17780
18270
  async function childHistory(file2, parentSessionId, identity) {
17781
- if (!path5.isAbsolute(file2))
18271
+ if (!path8.isAbsolute(file2))
17782
18272
  throw new Error("Pi child Session path is not absolute");
17783
18273
  const handle = await open3(file2, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
17784
18274
  try {
@@ -17791,18 +18281,18 @@ async function childHistory(file2, parentSessionId, identity) {
17791
18281
  throw new Error("Pi child Session exceeds read bounds");
17792
18282
  const values = buffer.subarray(0, bytesRead).toString("utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
17793
18283
  const header = values[0];
17794
- if (!record4(header) || header.type !== "session" || typeof header.id !== "string" || header.version !== 3)
18284
+ if (!record5(header) || header.type !== "session" || typeof header.id !== "string" || header.version !== 3)
17795
18285
  throw new Error("Unsupported Pi child Session header");
17796
18286
  const entries = [];
17797
18287
  for (const entry of values.slice(1)) {
17798
18288
  const parsed = jsonValueSchema.safeParse(entry);
17799
- if (!parsed.success || !record4(parsed.data) || typeof parsed.data.id !== "string")
18289
+ if (!parsed.success || !record5(parsed.data) || typeof parsed.data.id !== "string")
17800
18290
  throw new Error("Malformed Pi child Session entry");
17801
18291
  entries.push(parsed.data);
17802
18292
  }
17803
18293
  const history = { entries, leafId: String(entries.at(-1)?.id ?? "") || null };
17804
18294
  const snapshot = mapPiSnapshot(history, { sessionId: parentSessionId, model: null });
17805
- const prefix = createHash2("sha256").update(identity).digest("hex");
18295
+ const prefix = createHash3("sha256").update(identity).digest("hex");
17806
18296
  return {
17807
18297
  turns: snapshot.turns.map((turn) => {
17808
18298
  const readonlyTurn = {
@@ -17823,7 +18313,7 @@ async function childHistory(file2, parentSessionId, identity) {
17823
18313
  async function readPiWorkflowChild(history, parentSessionId, address) {
17824
18314
  for (const entry of activePiEntries(history).reverse()) {
17825
18315
  const message3 = entry.message;
17826
- if (!record4(message3) || message3.role !== "toolResult" || message3.toolName !== "subagent")
18316
+ if (!record5(message3) || message3.role !== "toolResult" || message3.toolName !== "subagent")
17827
18317
  continue;
17828
18318
  const summary = piWorkflowSummary(message3);
17829
18319
  if (!summary || summary.workflowRunId !== address.workflowRunId || summary.parentToolCallId !== message3.toolCallId)
@@ -17832,10 +18322,10 @@ async function readPiWorkflowChild(history, parentSessionId, address) {
17832
18322
  if (!child)
17833
18323
  break;
17834
18324
  const details = message3.details;
17835
- if (!record4(details) || !Array.isArray(details.results))
18325
+ if (!record5(details) || !Array.isArray(details.results))
17836
18326
  break;
17837
- const result = details.results.findLast((candidate) => record4(candidate) && candidate.workflowKey === address.childId);
17838
- if (!record4(result))
18327
+ const result = details.results.findLast((candidate) => record5(candidate) && candidate.workflowKey === address.childId);
18328
+ if (!record5(result))
17839
18329
  break;
17840
18330
  const id = piWorkflowSubagentId(address);
17841
18331
  if (typeof result.sessionFile === "string") {
@@ -17881,22 +18371,22 @@ ${output}`,
17881
18371
  // dist/pi-subagent-history.js
17882
18372
  import { constants as constants2 } from "node:fs";
17883
18373
  import { open as open4 } from "node:fs/promises";
17884
- import path6 from "node:path";
17885
- function record5(value) {
18374
+ import path9 from "node:path";
18375
+ function record6(value) {
17886
18376
  return typeof value === "object" && value !== null && !Array.isArray(value);
17887
18377
  }
17888
18378
  function state(value) {
17889
18379
  return value === "pending" ? "queued" : value === "completed" ? "complete" : value;
17890
18380
  }
17891
18381
  function piSubagentArtifact(value, runId, parentSessionId) {
17892
- if (!record5(value) || value.lifecycleArtifactVersion !== 3 || value.runId !== runId || value.sessionId !== parentSessionId || !["single", "parallel", "chain", "workflow"].includes(String(value.mode)))
18382
+ if (!record6(value) || value.lifecycleArtifactVersion !== 3 || value.runId !== runId || value.sessionId !== parentSessionId || !["single", "parallel", "chain", "workflow"].includes(String(value.mode)))
17893
18383
  return null;
17894
18384
  if (value.steps !== void 0 && (!Array.isArray(value.steps) || value.steps.length > 128))
17895
18385
  return null;
17896
18386
  const steps = Array.isArray(value.steps) ? value.steps : [];
17897
18387
  const children = [];
17898
18388
  for (const [index, step] of steps.entries()) {
17899
- if (!record5(step) || typeof step.agent !== "string")
18389
+ if (!record6(step) || typeof step.agent !== "string")
17900
18390
  return null;
17901
18391
  children.push({
17902
18392
  id: step.workflowKey ?? step.runId ?? `step:${index}`,
@@ -17929,17 +18419,17 @@ function piSubagentArtifact(value, runId, parentSessionId) {
17929
18419
  async function restorePiSubagents(history, parentSessionId, observer) {
17930
18420
  const receipts = /* @__PURE__ */ new Map();
17931
18421
  for (const entry of activePiEntries(history)) {
17932
- if (!record5(entry.message) || entry.message.role !== "toolResult" || entry.message.toolName !== "subagent" || entry.message.isError !== false || !record5(entry.message.details))
18422
+ if (!record6(entry.message) || entry.message.role !== "toolResult" || entry.message.toolName !== "subagent" || entry.message.isError !== false || !record6(entry.message.details))
17933
18423
  continue;
17934
18424
  const details = entry.message.details;
17935
- 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)
18425
+ if (!["single", "parallel", "chain", "workflow"].includes(String(details.mode)) || typeof details.asyncId !== "string" || typeof details.asyncDir !== "string" || !path9.isAbsolute(details.asyncDir) || path9.basename(details.asyncDir) !== details.asyncId)
17936
18426
  continue;
17937
18427
  receipts.set(details.asyncId, details.asyncDir);
17938
18428
  }
17939
18429
  for (const [id, directory] of [...receipts].slice(-128)) {
17940
18430
  let file2;
17941
18431
  try {
17942
- file2 = await open4(path6.join(directory, "status.json"), constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
18432
+ file2 = await open4(path9.join(directory, "status.json"), constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
17943
18433
  const stat2 = await file2.stat();
17944
18434
  if (!stat2.isFile() || stat2.size > 1024 * 1024)
17945
18435
  continue;
@@ -18021,7 +18511,7 @@ async function rollbackPiLastTurn(transport, sourceSessionId, cwd) {
18021
18511
  import { createReadStream as createReadStream2 } from "node:fs";
18022
18512
  import { opendir, realpath as realpath3, stat } from "node:fs/promises";
18023
18513
  import os3 from "node:os";
18024
- import path7 from "node:path";
18514
+ import path10 from "node:path";
18025
18515
  import { createInterface as createInterface2 } from "node:readline";
18026
18516
  var PiSessionChangedError = class extends Error {
18027
18517
  constructor() {
@@ -18038,7 +18528,7 @@ function missing(error51) {
18038
18528
  return isRecord4(error51) && error51.code === "ENOENT";
18039
18529
  }
18040
18530
  function expandDirectory(value, home) {
18041
- return path7.resolve(value === "~" ? home : value.startsWith(`~${path7.sep}`) || value.startsWith("~/") ? path7.join(home, value.slice(2)) : value);
18531
+ return path10.resolve(value === "~" ? home : value.startsWith(`~${path10.sep}`) || value.startsWith("~/") ? path10.join(home, value.slice(2)) : value);
18042
18532
  }
18043
18533
  function piSessionImportDirectory(environment) {
18044
18534
  const home = (process.platform === "win32" ? environment.USERPROFILE : environment.HOME) || os3.homedir();
@@ -18047,7 +18537,7 @@ function piSessionImportDirectory(environment) {
18047
18537
  return { directory: expandDirectory(custom2, home), flat: true };
18048
18538
  const agent = environment.PI_CODING_AGENT_DIR;
18049
18539
  return {
18050
- directory: path7.join(agent ? expandDirectory(agent, home) : path7.join(home, ".pi", "agent"), "sessions"),
18540
+ directory: path10.join(agent ? expandDirectory(agent, home) : path10.join(home, ".pi", "agent"), "sessions"),
18051
18541
  flat: false
18052
18542
  };
18053
18543
  }
@@ -18065,9 +18555,9 @@ async function sessionFiles(directory, flat, signal) {
18065
18555
  for await (const entry of entries) {
18066
18556
  signal.throwIfAborted();
18067
18557
  if (projectLevel && entry.isDirectory())
18068
- await visit(path7.join(dir, entry.name), false);
18558
+ await visit(path10.join(dir, entry.name), false);
18069
18559
  else if (!projectLevel && entry.isFile() && entry.name.endsWith(".jsonl")) {
18070
- files.push(path7.join(dir, entry.name));
18560
+ files.push(path10.join(dir, entry.name));
18071
18561
  }
18072
18562
  }
18073
18563
  };
@@ -18100,7 +18590,7 @@ async function readCandidate(file2, signal) {
18100
18590
  if (!isRecord4(entry))
18101
18591
  return null;
18102
18592
  if (!header) {
18103
- if (entry.type !== "session" || entry.version !== 3 || typeof entry.id !== "string" || typeof entry.cwd !== "string" || !path7.isAbsolute(entry.cwd))
18593
+ if (entry.type !== "session" || entry.version !== 3 || typeof entry.id !== "string" || typeof entry.cwd !== "string" || !path10.isAbsolute(entry.cwd))
18104
18594
  return null;
18105
18595
  header = entry;
18106
18596
  continue;
@@ -18250,8 +18740,8 @@ var PiSessionImportIndex = class {
18250
18740
 
18251
18741
  // dist/pi-rpc-session.js
18252
18742
  import { spawn, spawnSync } from "node:child_process";
18253
- import { randomUUID as randomUUID4 } from "node:crypto";
18254
- import path8 from "node:path";
18743
+ import { randomUUID as randomUUID5 } from "node:crypto";
18744
+ import path11 from "node:path";
18255
18745
 
18256
18746
  // dist/pi-slash-commands.js
18257
18747
  var DYNAMIC_ID_PREFIX = "pi.slash.";
@@ -18273,15 +18763,15 @@ function parsePiNativeCommands(response) {
18273
18763
  return data.commands.flatMap((entry) => {
18274
18764
  if (typeof entry !== "object" || entry === null)
18275
18765
  return [];
18276
- const record6 = entry;
18277
- const name = typeof record6.name === "string" ? record6.name.trim().replace(/^\//u, "") : "";
18766
+ const record7 = entry;
18767
+ const name = typeof record7.name === "string" ? record7.name.trim().replace(/^\//u, "") : "";
18278
18768
  if (!name)
18279
18769
  return [];
18280
18770
  return [
18281
18771
  {
18282
18772
  name,
18283
- ...typeof record6.description === "string" ? { description: record6.description } : {},
18284
- ...typeof record6.source === "string" ? { source: record6.source } : {}
18773
+ ...typeof record7.description === "string" ? { description: record7.description } : {},
18774
+ ...typeof record7.source === "string" ? { source: record7.source } : {}
18285
18775
  }
18286
18776
  ];
18287
18777
  });
@@ -18369,7 +18859,7 @@ function optionalPiStateContextUsage(value) {
18369
18859
  }
18370
18860
 
18371
18861
  // dist/pi-subagent-rpc.js
18372
- import { randomUUID as randomUUID3 } from "node:crypto";
18862
+ import { randomUUID as randomUUID4 } from "node:crypto";
18373
18863
  var PiSubagentRpc = class {
18374
18864
  send;
18375
18865
  timeoutMs;
@@ -18411,7 +18901,7 @@ var PiSubagentRpc = class {
18411
18901
  if (!Array.isArray(data?.commands) || !data.commands.some((command) => command?.name === "subagents-inspect-rpc" && command.source === "extension")) {
18412
18902
  throw new Error("Installed Pi has no pi-subagents Host inspection command");
18413
18903
  }
18414
- const requestId = randomUUID3();
18904
+ const requestId = randomUUID4();
18415
18905
  const reply = new Promise((resolve, reject) => {
18416
18906
  const timer = setTimeout(() => {
18417
18907
  this.#pending.delete(requestId);
@@ -18557,7 +19047,11 @@ function parseAvailableModels(response) {
18557
19047
  if (!parsed || !isRecord6(model) || typeof model.reasoning !== "boolean") {
18558
19048
  throw new PiRpcFaultError("protocolError", "Pi RPC catalog contains a Model without reasoning capability");
18559
19049
  }
18560
- return { ...parsed, reasoning: model.reasoning };
19050
+ return {
19051
+ ...parsed,
19052
+ reasoning: model.reasoning,
19053
+ ...typeof model.api === "string" ? { api: model.api } : {}
19054
+ };
18561
19055
  });
18562
19056
  }
18563
19057
  function assistantText(value) {
@@ -18642,13 +19136,14 @@ function piRpcProcessCommand(options, dependencies = {}) {
18642
19136
  const modelArguments = startupModel ? ["--provider", startupModel.provider, "--model", startupModel.id] : [];
18643
19137
  const thinkingArguments = options.emptySessionConfiguration ? ["--thinking", options.emptySessionConfiguration.thinkingLevel] : [];
18644
19138
  const arguments_ = [
19139
+ ...options.fastExtension ? ["--extension", options.fastExtension] : [],
18645
19140
  "--mode",
18646
19141
  "rpc",
18647
19142
  ...modelArguments,
18648
19143
  ...thinkingArguments,
18649
19144
  ...sessionArguments
18650
19145
  ];
18651
- const extension = path8.win32.extname(command).toLowerCase();
19146
+ const extension = path11.win32.extname(command).toLowerCase();
18652
19147
  if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
18653
19148
  return { command, arguments: arguments_, windowsVerbatimArguments: false };
18654
19149
  }
@@ -18687,6 +19182,8 @@ var PiRpcSession = class {
18687
19182
  #failed = false;
18688
19183
  #pending = /* @__PURE__ */ new Map();
18689
19184
  #state = null;
19185
+ #fast = null;
19186
+ #fastAcknowledgement = null;
18690
19187
  #latestCacheHitRatePercent;
18691
19188
  #manualCompaction = null;
18692
19189
  #stderrTail = "";
@@ -18713,7 +19210,9 @@ var PiRpcSession = class {
18713
19210
  get state() {
18714
19211
  if (!this.#state)
18715
19212
  throw new Error("Pi RPC Session has not started");
18716
- return this.#state;
19213
+ if (this.#fast && (this.#fast.provider !== this.#state.provider || this.#fast.id !== this.#state.modelId))
19214
+ this.#fast = null;
19215
+ return this.#fast ? { ...this.#state, fast: true } : this.#state;
18717
19216
  }
18718
19217
  get stderrTail() {
18719
19218
  return this.#stderrTail;
@@ -18730,8 +19229,10 @@ var PiRpcSession = class {
18730
19229
  async start() {
18731
19230
  if (this.#child || this.#closed)
18732
19231
  throw new Error("Pi RPC Session cannot be started twice");
19232
+ const fastExtension = this.#processAdapter === nodeProcessAdapter ? await ensurePiFastExtension({ ...process.env, ...this.#options.environment }) : void 0;
18733
19233
  const child = this.#processAdapter.spawn({
18734
19234
  cwd: this.#options.cwd,
19235
+ ...fastExtension ? { fastExtension } : {},
18735
19236
  ...this.#options.command ? { command: this.#options.command } : {},
18736
19237
  environment: withNodeRuntimeOnPath({
18737
19238
  ...process.env,
@@ -18878,7 +19379,36 @@ var PiRpcSession = class {
18878
19379
  throw error51;
18879
19380
  }
18880
19381
  }
19382
+ async supportsFastMode() {
19383
+ return (await this.getCommands()).some((command) => command.name === PI_FAST_COMMAND && command.source === "extension");
19384
+ }
19385
+ async selectFastMode(enabled) {
19386
+ if (!enabled && !this.#fast)
19387
+ return this.state;
19388
+ if (!await this.supportsFastMode())
19389
+ throw new Error("Installed Pi does not support the Host Fast extension");
19390
+ const nonce = randomUUID5();
19391
+ const mode = enabled ? "on" : "off";
19392
+ const acknowledgement = { message: `${PI_FAST_ACK}${nonce}:${mode}`, received: false };
19393
+ this.#fastAcknowledgement = acknowledgement;
19394
+ try {
19395
+ await this.#send("prompt", { message: `/${PI_FAST_COMMAND} ${mode} ${nonce}` });
19396
+ if (!acknowledgement.received)
19397
+ throw new Error("Pi did not confirm the Fast selection");
19398
+ this.#fast = enabled ? { provider: this.state.provider ?? "", id: this.state.modelId ?? "" } : null;
19399
+ return this.state;
19400
+ } catch (error51) {
19401
+ const fault = error51 instanceof PiRpcFaultError ? error51 : new PiRpcFaultError("protocolError", `Pi Fast selection could not be confirmed: ${message2(error51)}`);
19402
+ this.#fail(fault);
19403
+ await this.close().catch(() => void 0);
19404
+ throw fault;
19405
+ } finally {
19406
+ this.#fastAcknowledgement = null;
19407
+ }
19408
+ }
18881
19409
  async selectModel(model) {
19410
+ if (this.#fast)
19411
+ await this.selectFastMode(false);
18882
19412
  await this.#send("set_model", { provider: model.provider, modelId: model.id });
18883
19413
  return this.#refreshState("Model");
18884
19414
  }
@@ -18890,7 +19420,7 @@ var PiRpcSession = class {
18890
19420
  async #refreshState(operation) {
18891
19421
  try {
18892
19422
  this.#state = parseSessionState(await this.#send("get_state", {}));
18893
- return this.#state;
19423
+ return this.state;
18894
19424
  } catch (error51) {
18895
19425
  const fault = error51 instanceof PiRpcFaultError ? error51 : new PiRpcFaultError("protocolError", `Pi RPC ${operation} state could not be confirmed: ${message2(error51)}`);
18896
19426
  this.#fail(fault);
@@ -19046,6 +19576,11 @@ var PiRpcSession = class {
19046
19576
  }
19047
19577
  }
19048
19578
  #handle(value) {
19579
+ if (value.type === "extension_ui_request" && value.method === "notify" && typeof value.message === "string" && value.message.startsWith(PI_FAST_ACK)) {
19580
+ if (this.#fastAcknowledgement?.message === value.message)
19581
+ this.#fastAcknowledgement.received = true;
19582
+ return;
19583
+ }
19049
19584
  if (this.#closed || this.#failed)
19050
19585
  return;
19051
19586
  if (value.type === "response") {
@@ -19168,7 +19703,7 @@ var PiRpcSession = class {
19168
19703
  const active = {
19169
19704
  origin: "autonomous",
19170
19705
  autonomousEvents: events,
19171
- nativeTurnKey: assistantMessageId(value) ?? randomUUID4(),
19706
+ nativeTurnKey: assistantMessageId(value) ?? randomUUID5(),
19172
19707
  nativeCancellationObserved: false,
19173
19708
  text: "",
19174
19709
  assistantMessageId: null,
@@ -19411,7 +19946,7 @@ var PiRpcSession = class {
19411
19946
  if (active.assistantMessageId !== null && active.reasoningMessageOpen) {
19412
19947
  active.onEvent({ type: "reasoning.completed", messageId: active.assistantMessageId });
19413
19948
  }
19414
- const messageId = assistantMessageId(value) ?? randomUUID4();
19949
+ const messageId = assistantMessageId(value) ?? randomUUID5();
19415
19950
  active.assistantMessageId = messageId;
19416
19951
  active.sawStreamedMessageText = false;
19417
19952
  active.sawStreamedMessageReasoning = false;
@@ -19472,7 +20007,7 @@ var PiRpcSession = class {
19472
20007
  if (!child?.stdin.writable || this.#closed || this.#failed) {
19473
20008
  return Promise.reject(new Error("Pi RPC stdin is unavailable"));
19474
20009
  }
19475
- const id = `codexhost-${randomUUID4()}`;
20010
+ const id = `codexhost-${randomUUID5()}`;
19476
20011
  return new Promise((resolve, reject) => {
19477
20012
  const pending = {
19478
20013
  command: type,
@@ -19647,7 +20182,7 @@ function nativeModelFromState(state2) {
19647
20182
  }
19648
20183
  function effectiveModelFromState(state2) {
19649
20184
  const model = nativeModelFromState(state2);
19650
- return model ? encodePiModelRef(model) : void 0;
20185
+ return model ? encodePiModelRef({ ...model, ...state2.fast ? { fast: true } : {} }) : void 0;
19651
20186
  }
19652
20187
  function harnessStateFromPi(state2, thinkingLevels) {
19653
20188
  const effectiveModel = effectiveModelFromState(state2);
@@ -19733,10 +20268,10 @@ function stripDiffPrefix(pathString) {
19733
20268
  return pathString.startsWith("a/") || pathString.startsWith("b/") ? pathString.slice(2) : pathString;
19734
20269
  }
19735
20270
  function displayPath(nativePath, cwd) {
19736
- const resolvedCwd = path9.resolve(cwd);
19737
- const resolvedPath = path9.isAbsolute(nativePath) ? path9.resolve(nativePath) : path9.resolve(cwd, nativePath);
19738
- const relative = path9.relative(resolvedCwd, resolvedPath);
19739
- const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path9.sep}`);
20271
+ const resolvedCwd = path12.resolve(cwd);
20272
+ const resolvedPath = path12.isAbsolute(nativePath) ? path12.resolve(nativePath) : path12.resolve(cwd, nativePath);
20273
+ const relative = path12.relative(resolvedCwd, resolvedPath);
20274
+ const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path12.sep}`);
19740
20275
  const selected = inside ? relative : resolvedPath;
19741
20276
  const normalized = selected.replaceAll("\\", "/");
19742
20277
  if (normalized.length === 0 || normalized === ".")
@@ -19935,6 +20470,7 @@ var PiHarnessSession = class {
19935
20470
  #requestedModel;
19936
20471
  #requestedThinkingOptionId;
19937
20472
  #toolOutputLimit;
20473
+ #isFastSupported;
19938
20474
  #acceptingTurn = false;
19939
20475
  #active = null;
19940
20476
  #closePromise = null;
@@ -19956,6 +20492,7 @@ var PiHarnessSession = class {
19956
20492
  this.#requestedModel = options.model;
19957
20493
  this.#requestedThinkingOptionId = options.thinkingOptionId;
19958
20494
  this.#toolOutputLimit = options.toolOutputLimit;
20495
+ this.#isFastSupported = options.isFastSupported;
19959
20496
  this.capabilities = {
19960
20497
  configuration: {
19961
20498
  selectModel: true,
@@ -19984,13 +20521,13 @@ var PiHarnessSession = class {
19984
20521
  return this.#transport?.state.sessionId === id;
19985
20522
  }
19986
20523
  async readSubagentHistory(cwd) {
19987
- if (this.#phase !== "open" || path9.resolve(cwd) !== path9.resolve(this.#cwd)) {
20524
+ if (this.#phase !== "open" || path12.resolve(cwd) !== path12.resolve(this.#cwd)) {
19988
20525
  throw new Error("Pi Subagent parent workspace or Session is unavailable");
19989
20526
  }
19990
20527
  return (await this.#ensureTransport()).getEntries();
19991
20528
  }
19992
20529
  async inspectSubagent(id, cwd) {
19993
- if (this.#phase !== "open" || path9.resolve(cwd) !== path9.resolve(this.#cwd)) {
20530
+ if (this.#phase !== "open" || path12.resolve(cwd) !== path12.resolve(this.#cwd)) {
19994
20531
  throw new Error("Pi Subagent parent workspace or Session is unavailable");
19995
20532
  }
19996
20533
  const transport = await this.#ensureTransport();
@@ -20233,20 +20770,27 @@ var PiHarnessSession = class {
20233
20770
  error: invalidState("Pi Model selection requires a started Native Session")
20234
20771
  };
20235
20772
  }
20236
- let requested;
20237
- try {
20238
- requested = decodePiModelRef(command.model);
20239
- } catch (error51) {
20240
- return { ok: false, error: normalizedError(error51, "invalidRequest") };
20241
- }
20242
20773
  const previousModel = this.#state.effectiveModel;
20243
20774
  this.#configuring = true;
20244
20775
  try {
20776
+ let requested;
20777
+ try {
20778
+ requested = decodePiModelRef(command.model);
20779
+ if (requested.fast && !await this.#isFastSupported(command.model, transport))
20780
+ throw new Error("Fast is unavailable for this Pi Model");
20781
+ } catch (error51) {
20782
+ return { ok: false, error: normalizedError(error51, "invalidRequest") };
20783
+ }
20245
20784
  let state2;
20246
20785
  let thinkingLevels;
20247
20786
  try {
20248
- state2 = await transport.selectModel(requested);
20787
+ state2 = samePiModel(nativeModelFromState(transport.state), requested) ? transport.state : await transport.selectModel(requested);
20249
20788
  thinkingLevels = await transport.getAvailableThinkingLevels();
20789
+ if (requested.fast || state2.fast) {
20790
+ if (!transport.selectFastMode)
20791
+ throw new Error("Pi Fast extension is unavailable");
20792
+ state2 = await transport.selectFastMode(requested.fast === true);
20793
+ }
20250
20794
  this.#publishTransportState(state2, thinkingLevels);
20251
20795
  } catch (error51) {
20252
20796
  if (error51 instanceof PiRpcFaultError)
@@ -20383,7 +20927,7 @@ var PiHarnessSession = class {
20383
20927
  const transport = this.#transport;
20384
20928
  if (this.#phase === "open" && transport?.getCommands) {
20385
20929
  try {
20386
- this.#liveCommands = piLiveCommandCatalog(piCommandCatalog, await transport.getCommands());
20930
+ this.#liveCommands = piLiveCommandCatalog(piCommandCatalog, (await transport.getCommands()).filter((command) => command.name !== PI_FAST_COMMAND));
20387
20931
  } catch {
20388
20932
  }
20389
20933
  }
@@ -20530,6 +21074,11 @@ var PiHarnessSession = class {
20530
21074
  this.#publishTransportState(state2, thinkingLevels);
20531
21075
  throw new Error("Pi did not activate the requested create Model");
20532
21076
  }
21077
+ if (requested.fast) {
21078
+ if (!await this.#isFastSupported(this.#requestedModel, transport) || !transport.selectFastMode)
21079
+ throw new Error("Fast is unavailable for this Pi Model");
21080
+ state2 = await transport.selectFastMode(true);
21081
+ }
20533
21082
  }
20534
21083
  if (this.#requestedThinkingOptionId) {
20535
21084
  if (!thinkingLevels) {
@@ -20610,7 +21159,7 @@ var PiHarnessSession = class {
20610
21159
  }));
20611
21160
  return;
20612
21161
  }
20613
- const turnId = hostTurnIdSchema.parse(randomUUID5());
21162
+ const turnId = hostTurnIdSchema.parse(randomUUID6());
20614
21163
  let resolveCompletion = () => void 0;
20615
21164
  const completion = new Promise((resolve) => {
20616
21165
  resolveCompletion = resolve;
@@ -20772,7 +21321,7 @@ var PiHarnessSession = class {
20772
21321
  if (active.interactionByNativeId.has(request.requestId)) {
20773
21322
  throw new Error("Pi Interaction started more than once");
20774
21323
  }
20775
- const interactionId = hostInteractionIdSchema.parse(randomUUID5());
21324
+ const interactionId = hostInteractionIdSchema.parse(randomUUID6());
20776
21325
  const question = request.method === "select" ? {
20777
21326
  id: "answer",
20778
21327
  type: "choice",
@@ -21119,7 +21668,7 @@ var PiHarnessSession = class {
21119
21668
  this.#channel.emit({ kind: "event", event });
21120
21669
  }
21121
21670
  #newItemId() {
21122
- return hostItemIdSchema.parse(randomUUID5());
21671
+ return hostItemIdSchema.parse(randomUUID6());
21123
21672
  }
21124
21673
  };
21125
21674
  var PiAdapter = class {
@@ -21210,6 +21759,7 @@ var PiAdapter = class {
21210
21759
  #inspections = /* @__PURE__ */ new Set();
21211
21760
  #sessions = /* @__PURE__ */ new Set();
21212
21761
  #toolOutputLimit;
21762
+ #environment;
21213
21763
  #closePromise = null;
21214
21764
  #thinkingSelectionSupported = null;
21215
21765
  constructor(options = {}, dependencies = {
@@ -21229,10 +21779,21 @@ var PiAdapter = class {
21229
21779
  remove: (name) => updateCatalog(imports.remove(name))
21230
21780
  };
21231
21781
  this.#createTransport = dependencies.createTransport;
21782
+ this.#environment = options.environment ?? process.env;
21232
21783
  this.#importIndex = new PiSessionImportIndex({ ...process.env, ...options.environment });
21233
21784
  this.#closeTimeoutMs = options.closeTimeoutMs ?? 2e3;
21234
21785
  this.#toolOutputLimit = options.toolOutputLimit ?? DEFAULT_TOOL_OUTPUT_LIMIT;
21235
21786
  }
21787
+ /** Pi itself holds no Account; this reports configured Provider balances. */
21788
+ async inspectAccounts() {
21789
+ if (this.#closePromise)
21790
+ return [];
21791
+ return fetchPiAccounts({ environment: this.#environment });
21792
+ }
21793
+ async inspectAccount() {
21794
+ const accounts = await this.inspectAccounts();
21795
+ return accounts[0] ?? null;
21796
+ }
21236
21797
  #readImport(operation) {
21237
21798
  if (this.#importAbort.signal.aborted)
21238
21799
  return Promise.resolve({ ok: false, error: invalidState("Pi Adapter is closed") });
@@ -21292,7 +21853,9 @@ var PiAdapter = class {
21292
21853
  stage = "capabilities";
21293
21854
  const thinkingLevels = await transport.getAvailableThinkingLevels();
21294
21855
  this.#thinkingSelectionSupported = thinkingLevels !== null;
21295
- const catalog = normalizePiModelCatalog(models, nativeModelFromState(transport.state), thinkingLevels, transport.state.thinkingLevel);
21856
+ const normalized = normalizePiModelCatalog(models, nativeModelFromState(transport.state), thinkingLevels, transport.state.thinkingLevel);
21857
+ const fastModels = await transport.supportsFastMode?.() ? await piFastModelKeys(models, this.#environment) : /* @__PURE__ */ new Set();
21858
+ const catalog = withPiFast(normalized, fastModels);
21296
21859
  await transport.close();
21297
21860
  return {
21298
21861
  status: "ready",
@@ -21329,6 +21892,27 @@ var PiAdapter = class {
21329
21892
  if (this.#closePromise) {
21330
21893
  return { ok: false, error: invalidState("Pi Adapter is closed") };
21331
21894
  }
21895
+ if ("model" in input && input.model) {
21896
+ let model;
21897
+ try {
21898
+ model = decodePiModelRef(input.model);
21899
+ } catch (error51) {
21900
+ return { ok: false, error: normalizedError(error51, "invalidRequest") };
21901
+ }
21902
+ if (model.fast) {
21903
+ if (!this.#isFastSupported(input.model, input.cwd))
21904
+ await this.inspect({ cwd: input.cwd });
21905
+ if (!this.#isFastSupported(input.model, input.cwd) && input.kind !== "resume")
21906
+ return {
21907
+ ok: false,
21908
+ error: {
21909
+ code: "unsupported",
21910
+ message: "Fast is unavailable for this Pi Model",
21911
+ retryable: false
21912
+ }
21913
+ };
21914
+ }
21915
+ }
21332
21916
  if (input.cwd.length === 0) {
21333
21917
  return {
21334
21918
  ok: false,
@@ -21499,6 +22083,11 @@ var PiAdapter = class {
21499
22083
  await transport.verifySessionCwd(input.cwd);
21500
22084
  }
21501
22085
  }
22086
+ if (input.kind === "resume" && input.model && this.#isFastSupported(input.model, input.cwd) && decodePiModelRef(input.model).fast && samePiModel(nativeModelFromState(transport.state), decodePiModelRef(input.model))) {
22087
+ if (!transport.selectFastMode)
22088
+ throw new Error("Pi Fast extension is unavailable");
22089
+ await transport.selectFastMode(true);
22090
+ }
21502
22091
  const startedThinkingLevels = await transport.getAvailableThinkingLevels();
21503
22092
  this.#thinkingSelectionSupported = startedThinkingLevels !== null;
21504
22093
  const initialUsage = await transport.getSessionUsage().catch(() => null);
@@ -21515,6 +22104,9 @@ var PiAdapter = class {
21515
22104
  return { ok: false, error: normalizedError(error51, "nativeFailure") };
21516
22105
  }
21517
22106
  }
22107
+ #isFastSupported(ref, cwd) {
22108
+ return this.#inspectionCache.get(cwd)?.catalog.models.some((model) => model.fastModel?.id === ref.id) ?? false;
22109
+ }
21518
22110
  #trackSession(cwd, options) {
21519
22111
  const environment = options.environment;
21520
22112
  const createTransport = environment ? (input) => this.#createTransport({ ...input, environment }) : this.#createTransport;
@@ -21526,6 +22118,14 @@ var PiAdapter = class {
21526
22118
  ...options.thinkingOptionId ? { thinkingOptionId: options.thinkingOptionId } : {},
21527
22119
  toolOutputLimit: this.#toolOutputLimit,
21528
22120
  supportsThinkingSelection: options.supportsThinkingSelection,
22121
+ isFastSupported: async (ref, transport) => {
22122
+ if (this.#inspectionCache.has(cwd))
22123
+ return this.#isFastSupported(ref, cwd);
22124
+ if (!await transport.supportsFastMode?.())
22125
+ return false;
22126
+ const fastModels = await piFastModelKeys(await transport.getAvailableModels(), environment ?? this.#environment);
22127
+ return fastModels.has(encodePiModelRef({ ...decodePiModelRef(ref), fast: false }).id);
22128
+ },
21529
22129
  ...options.startedTransport ? { startedTransport: options.startedTransport } : {},
21530
22130
  ...options.startedThinkingLevels !== void 0 ? { startedThinkingLevels: options.startedThinkingLevels } : {},
21531
22131
  ...options.initialUsage !== void 0 ? { initialUsage: options.initialUsage } : {}
@@ -21546,14 +22146,36 @@ var PiAdapter = class {
21546
22146
  }
21547
22147
  };
21548
22148
 
22149
+ // dist/installation.js
22150
+ var PI_LATEST_VERSION_URL = "https://pi.dev/api/latest-version";
22151
+ function createPiInstallation(environment, command) {
22152
+ const run = (args, timeout) => runInstallationCommand(resolvePiExecutable({ environment, ...command ? { command } : {} }), args, environment, timeout);
22153
+ return createInstallationManager({
22154
+ async check() {
22155
+ const currentVersion = versionFromOutput(await run(["--version"]));
22156
+ const payload = JSON.parse(await fetchInstallationText(PI_LATEST_VERSION_URL));
22157
+ const latestVersion = installationVersion(payload.version);
22158
+ return {
22159
+ currentVersion,
22160
+ latestVersion,
22161
+ updateAvailable: newerInstallationVersion(currentVersion, latestVersion),
22162
+ canUpdate: true
22163
+ };
22164
+ },
22165
+ async update() {
22166
+ await run(["update"], 3e5);
22167
+ }
22168
+ });
22169
+ }
22170
+
21549
22171
  // dist/plugin.js
21550
22172
  var PI_COMMAND_ENV = "CODEXHOST_PI_COMMAND";
21551
22173
  function createHarnessAdapter(context) {
21552
22174
  const environment = { ...context.environment };
21553
- return new PiAdapter({
22175
+ return Object.assign(new PiAdapter({
21554
22176
  ...environment[PI_COMMAND_ENV] ? { command: environment[PI_COMMAND_ENV] } : {},
21555
22177
  environment
21556
- });
22178
+ }), { installation: createPiInstallation(environment, environment[PI_COMMAND_ENV]) });
21557
22179
  }
21558
22180
  export {
21559
22181
  PI_COMMAND_ENV,