@ashx-j/lunr-dev 0.2.13-dev.7.1 → 0.2.13-dev.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/catalog/models.json +1 -1
  2. package/dist/catalog/providers/amazon-bedrock.json +1 -1
  3. package/dist/catalog/providers/azure-openai-responses.json +1 -1
  4. package/dist/catalog/providers/fireworks.json +1 -1
  5. package/dist/catalog/providers/github-copilot.json +1 -1
  6. package/dist/catalog/providers/openai-codex.json +1 -1
  7. package/dist/catalog/providers/openai.json +1 -1
  8. package/dist/catalog/providers/opencode.json +1 -1
  9. package/dist/catalog/providers/openrouter.json +1 -1
  10. package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
  11. package/dist/catalog/publication.json +131 -3
  12. package/dist/cli/list-models.d.ts.map +1 -1
  13. package/dist/cli/list-models.js +1 -0
  14. package/dist/cli/list-models.js.map +1 -1
  15. package/dist/core/catalog-cache-scope.d.ts +3 -0
  16. package/dist/core/catalog-cache-scope.d.ts.map +1 -0
  17. package/dist/core/catalog-cache-scope.js +12 -0
  18. package/dist/core/catalog-cache-scope.js.map +1 -0
  19. package/dist/core/catalog-merge.d.ts +2 -0
  20. package/dist/core/catalog-merge.d.ts.map +1 -1
  21. package/dist/core/catalog-merge.js +29 -2
  22. package/dist/core/catalog-merge.js.map +1 -1
  23. package/dist/core/catalog-refresh-polling.d.ts +8 -0
  24. package/dist/core/catalog-refresh-polling.d.ts.map +1 -0
  25. package/dist/core/catalog-refresh-polling.js +30 -0
  26. package/dist/core/catalog-refresh-polling.js.map +1 -0
  27. package/dist/core/codex-catalog.d.ts +3 -0
  28. package/dist/core/codex-catalog.d.ts.map +1 -0
  29. package/dist/core/codex-catalog.js +15 -0
  30. package/dist/core/codex-catalog.js.map +1 -0
  31. package/dist/core/live-catalog.d.ts +5 -2
  32. package/dist/core/live-catalog.d.ts.map +1 -1
  33. package/dist/core/live-catalog.js +108 -27
  34. package/dist/core/live-catalog.js.map +1 -1
  35. package/dist/core/model-runtime.d.ts +8 -0
  36. package/dist/core/model-runtime.d.ts.map +1 -1
  37. package/dist/core/model-runtime.js +64 -12
  38. package/dist/core/model-runtime.js.map +1 -1
  39. package/dist/core/official-catalog.d.ts +4 -0
  40. package/dist/core/official-catalog.d.ts.map +1 -1
  41. package/dist/core/official-catalog.js +86 -21
  42. package/dist/core/official-catalog.js.map +1 -1
  43. package/dist/main.d.ts.map +1 -1
  44. package/dist/main.js +9 -0
  45. package/dist/main.js.map +1 -1
  46. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  47. package/dist/modes/interactive/components/model-selector.js +4 -1
  48. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  49. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  50. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  51. package/dist/modes/interactive/interactive-mode.js +34 -76
  52. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  53. package/docs/model-catalog.md +29 -0
  54. package/package.json +4 -4
@@ -1,10 +1,12 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
2
3
  import { dirname, join } from "node:path";
3
4
  import { fileURLToPath } from "node:url";
4
5
  import { getAgentDir, getPackageDir, VERSION } from "../config.js";
5
6
  import { getPiUserAgent } from "../utils/pi-user-agent.js";
6
7
  /** Directory on GitHub raw (`providers.json` + `providers/{id}.json`). Override with `LUNR_OFFICIAL_CATALOG_URL`. */
7
8
  export const OFFICIAL_CATALOG_DEFAULT_URL = "https://raw.githubusercontent.com/ashx-j/lunR/master/catalog";
9
+ export const VERSIONED_CATALOG_URL = "https://raw.githubusercontent.com/ashx-j/lunR/model-catalog/catalog";
8
10
  export const OFFICIAL_CATALOG_TIMEOUT_MS = 4000;
9
11
  export const OFFICIAL_CATALOG_CACHE_FILENAME = "official-catalog-cache.json";
10
12
  const THINKING_LEVEL_KEYS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
@@ -72,6 +74,21 @@ function parseCost(value) {
72
74
  output,
73
75
  cacheRead: asFiniteNumber(value.cacheRead) ?? 0,
74
76
  cacheWrite: asFiniteNumber(value.cacheWrite) ?? 0,
77
+ ...(Array.isArray(value.tiers)
78
+ ? {
79
+ tiers: value.tiers.flatMap((tier) => {
80
+ if (!isRecord(tier) || !(typeof tier.inputTokensAbove === "number" && tier.inputTokensAbove >= 0))
81
+ return [];
82
+ const rates = parseCost({
83
+ input: tier.input,
84
+ output: tier.output,
85
+ cacheRead: tier.cacheRead,
86
+ cacheWrite: tier.cacheWrite,
87
+ });
88
+ return rates ? [{ ...rates, inputTokensAbove: tier.inputTokensAbove }] : [];
89
+ }),
90
+ }
91
+ : {}),
75
92
  };
76
93
  }
77
94
  function parseInput(value) {
@@ -125,6 +142,9 @@ function parseOfficialEntry(value) {
125
142
  const headers = parseHeaders(value.headers);
126
143
  return {
127
144
  id,
145
+ ...(isRecord(value.catalog) && value.catalog.source === "provider" && Array.isArray(value.catalog.supplied)
146
+ ? { catalog: value.catalog }
147
+ : {}),
128
148
  name,
129
149
  api: api,
130
150
  provider,
@@ -232,13 +252,23 @@ export function loadCachedOfficialCatalog(cachePath) {
232
252
  return readCatalogFile(cachePath);
233
253
  }
234
254
  export function writeOfficialCatalogCache(catalog, cachePath) {
255
+ const temporary = `${cachePath}.${randomUUID()}.tmp`;
235
256
  try {
236
257
  mkdirSync(dirname(cachePath), { recursive: true, mode: 0o700 });
237
- writeFileSync(cachePath, `${JSON.stringify(catalog, null, 2)}\n`, "utf-8");
258
+ writeFileSync(temporary, `${JSON.stringify(catalog, null, 2)}\n`, { encoding: "utf-8", mode: 0o600 });
259
+ renameSync(temporary, cachePath);
238
260
  }
239
261
  catch {
240
262
  // Cache is best-effort.
241
263
  }
264
+ finally {
265
+ try {
266
+ unlinkSync(temporary);
267
+ }
268
+ catch {
269
+ /* Renamed or never created. */
270
+ }
271
+ }
242
272
  }
243
273
  export function officialModelsByProvider(catalog) {
244
274
  const byProvider = new Map();
@@ -273,7 +303,7 @@ export function preferOfficialCatalog(previous, next) {
273
303
  if (next.source === "github")
274
304
  return next;
275
305
  if (previous?.source === "github")
276
- return previous;
306
+ return { ...previous, errors: next.errors };
277
307
  return next;
278
308
  }
279
309
  export function officialModelKeys(catalog) {
@@ -282,6 +312,7 @@ export function officialModelKeys(catalog) {
282
312
  const ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
283
313
  export function officialEntryToModel(entry, template) {
284
314
  return {
315
+ catalog: entry.catalog,
285
316
  id: entry.id,
286
317
  name: entry.name,
287
318
  api: entry.api || template?.api || "openai-completions",
@@ -324,20 +355,22 @@ async function fetchJson(url, options) {
324
355
  error.name = "AbortError";
325
356
  return error;
326
357
  };
327
- const response = await Promise.race([
328
- options.fetchImpl(url, {
329
- headers: options.headers,
330
- signal: controller.signal,
331
- }),
358
+ return await Promise.race([
359
+ (async () => {
360
+ const response = await options.fetchImpl(url, {
361
+ headers: options.headers,
362
+ signal: controller.signal,
363
+ });
364
+ if (!response.ok)
365
+ return { ok: false, status: response.status };
366
+ return { ok: true, value: await response.json() };
367
+ })(),
332
368
  new Promise((_, reject) => {
333
369
  controller.signal.addEventListener("abort", () => reject(abortError()), { once: true });
334
370
  if (controller.signal.aborted)
335
371
  reject(abortError());
336
372
  }),
337
373
  ]);
338
- if (!response.ok)
339
- return { ok: false, status: response.status };
340
- return { ok: true, value: await response.json() };
341
374
  }
342
375
  catch {
343
376
  return { ok: false };
@@ -367,38 +400,70 @@ export async function loadOfficialCatalog(options = {}) {
367
400
  "User-Agent": getPiUserAgent(VERSION),
368
401
  };
369
402
  const fetchOptions = { timeoutMs, signal: options.signal, fetchImpl, headers };
370
- const base = options.url ?? officialCatalogBaseUrl();
403
+ const unavailable = () => ({
404
+ ...fallbackCatalog(bundled, cachePath),
405
+ errors: Object.fromEntries((options.providerIds ?? []).map((id) => [id, "Published catalog unavailable; using cached metadata"])),
406
+ });
407
+ let base = options.url ?? officialCatalogBaseUrl();
408
+ let manifest;
409
+ // Existing custom mirrors remain compatible with the v1 index/shard format.
410
+ if (!options.url && !process.env.LUNR_OFFICIAL_CATALOG_URL) {
411
+ const result = await fetchJson(`${VERSIONED_CATALOG_URL}/publication.json`, fetchOptions);
412
+ if (result.ok &&
413
+ isRecord(result.value) &&
414
+ result.value.version === 2 &&
415
+ typeof result.value.revision === "string" &&
416
+ /^sha256-[a-f0-9]{64}$/.test(result.value.revision) &&
417
+ isRecord(result.value.shards) &&
418
+ parseProviderIndex(result.value.providers)) {
419
+ manifest = result.value;
420
+ base = `${VERSIONED_CATALOG_URL}/snapshots/${result.value.revision}`;
421
+ }
422
+ }
371
423
  try {
372
- const indexResult = await fetchJson(officialCatalogUrlFor("providers.json", base), fetchOptions);
424
+ const indexResult = manifest
425
+ ? { ok: true, value: manifest.providers }
426
+ : await fetchJson(officialCatalogUrlFor("providers.json", base), fetchOptions);
373
427
  if (!indexResult.ok)
374
- return fallbackCatalog(bundled, cachePath);
428
+ return unavailable();
375
429
  const index = parseProviderIndex(indexResult.value);
376
430
  if (!index)
377
- return fallbackCatalog(bundled, cachePath);
431
+ return unavailable();
378
432
  const wanted = new Set(index);
379
433
  const requested = options.providerIds ?? [];
380
434
  const shardIds = requested.filter((providerId) => wanted.has(providerId));
381
435
  if (shardIds.length === 0)
382
436
  return fallbackCatalog(bundled, cachePath);
383
437
  const replacements = new Map();
438
+ const errors = {};
384
439
  await Promise.all(shardIds.map(async (providerId) => {
385
440
  const result = await fetchJson(officialCatalogUrlFor(`providers/${encodeURIComponent(providerId)}.json`, base), fetchOptions);
386
- if (!result.ok)
441
+ if (!result.ok) {
442
+ errors[providerId] = "Catalog shard unavailable; using cached metadata";
387
443
  return;
444
+ }
445
+ if (manifest &&
446
+ manifest.shards[providerId] !==
447
+ createHash("sha256").update(JSON.stringify(result.value)).digest("hex")) {
448
+ errors[providerId] = "Catalog shard checksum mismatch; using cached metadata";
449
+ return;
450
+ }
388
451
  const parsed = parseOfficialCatalog(result.value);
389
- if (!parsed || parsed.models.length === 0)
452
+ if (!parsed || parsed.models.length === 0 || parsed.models.some((model) => model.provider !== providerId)) {
453
+ errors[providerId] = "Invalid catalog shard; using cached metadata";
390
454
  return;
455
+ }
391
456
  replacements.set(providerId, parsed.models);
392
457
  }));
393
458
  if (replacements.size === 0)
394
- return fallbackCatalog(bundled, cachePath);
395
- const catalog = mergeOfficialCatalogByProvider(officialCatalogBase(bundled, cachePath), replacements);
459
+ return { ...fallbackCatalog(bundled, cachePath), errors };
460
+ const catalog = mergeOfficialCatalogByProvider(officialCatalogBase(bundled, cachePath), replacements, typeof manifest?.generatedAt === "string" ? manifest.generatedAt : undefined);
396
461
  if (cachePath)
397
462
  writeOfficialCatalogCache(catalog, cachePath);
398
- return { catalog, source: "github" };
463
+ return { catalog, source: "github", ...(Object.keys(errors).length ? { errors } : {}) };
399
464
  }
400
465
  catch {
401
- return fallbackCatalog(bundled, cachePath);
466
+ return unavailable();
402
467
  }
403
468
  }
404
469
  //# sourceMappingURL=official-catalog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"official-catalog.js","sourceRoot":"","sources":["../../src/core/official-catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Api, Model, ThinkingLevelMap } from \"@ashx-j/lunr-ai\";\nimport { getAgentDir, getPackageDir, VERSION } from \"../config.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\n\n/** Directory on GitHub raw (`providers.json` + `providers/{id}.json`). Override with `LUNR_OFFICIAL_CATALOG_URL`. */\nexport const OFFICIAL_CATALOG_DEFAULT_URL = \"https://raw.githubusercontent.com/ashx-j/lunR/master/catalog\";\nexport const OFFICIAL_CATALOG_TIMEOUT_MS = 4000;\nexport const OFFICIAL_CATALOG_CACHE_FILENAME = \"official-catalog-cache.json\";\n\nconst THINKING_LEVEL_KEYS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const;\nconst META_KEYS = new Set([\"version\", \"updatedAt\", \"generatedAt\", \"sourceCommit\", \"providerCount\", \"modelCount\"]);\n\nexport interface OfficialModelCost {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n}\n\nexport interface OfficialModelEntry {\n\tid: string;\n\tname: string;\n\tapi: Api;\n\tprovider: string;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: (\"text\" | \"image\")[];\n\tcost: OfficialModelCost;\n\tcontextWindow: number;\n\tmaxTokens: number;\n\tcompat?: Model<Api>[\"compat\"];\n\tthinkingLevelMap?: ThinkingLevelMap;\n\theaders?: Record<string, string>;\n}\n\nexport interface OfficialCatalogFile {\n\tversion: number;\n\tupdatedAt: string;\n\tmodels: OfficialModelEntry[];\n}\n\nexport type OfficialCatalogSource = \"github\" | \"cache\" | \"bundled\";\n\nexport interface OfficialCatalogLoadResult {\n\tcatalog: OfficialCatalogFile;\n\tsource: OfficialCatalogSource;\n}\n\n/** Seed shipped in-repo; used when the JSON file cannot be read. */\nexport const BUNDLED_OFFICIAL_CATALOG: OfficialCatalogFile = {\n\tversion: 1,\n\tupdatedAt: \"2026-08-15T00:00:00Z\",\n\tmodels: [\n\t\t{\n\t\t\tid: \"grok-4.6\",\n\t\t\tname: \"Grok 4.6\",\n\t\t\tapi: \"openai-completions\",\n\t\t\tprovider: \"xai\",\n\t\t\tbaseUrl: \"https://api.x.ai/v1\",\n\t\t\treasoning: true,\n\t\t\tinput: [\"text\", \"image\"],\n\t\t\tcost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 },\n\t\t\tcontextWindow: 500000,\n\t\t\tmaxTokens: 500000,\n\t\t},\n\t],\n};\n\nexport function officialCatalogCachePath(agentDir: string = getAgentDir()): string {\n\treturn join(agentDir, OFFICIAL_CATALOG_CACHE_FILENAME);\n}\n\n/** Base URL (no trailing slash). `LUNR_OFFICIAL_CATALOG_URL` overrides the directory, not a single file. */\nexport function officialCatalogBaseUrl(override?: string): string {\n\tconst raw = (override ?? process.env.LUNR_OFFICIAL_CATALOG_URL)?.trim() || OFFICIAL_CATALOG_DEFAULT_URL;\n\treturn raw.replace(/\\/+$/, \"\");\n}\n\n/** @deprecated Use officialCatalogBaseUrl. Kept as an alias for the directory base. */\nexport function officialCatalogUrl(): string {\n\treturn officialCatalogBaseUrl();\n}\n\nexport function officialCatalogUrlFor(path: string, base?: string): string {\n\tconst normalized = path.replace(/^\\/+/, \"\");\n\treturn `${officialCatalogBaseUrl(base)}/${normalized}`;\n}\n\nexport function modelKey(provider: string, id: string): string {\n\treturn `${provider}/${id}`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asFiniteNumber(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (typeof value === \"string\" && value.trim()) {\n\t\tconst parsed = Number(value);\n\t\tif (Number.isFinite(parsed)) return parsed;\n\t}\n\treturn undefined;\n}\n\nfunction parseCost(value: unknown): OfficialModelCost | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst input = asFiniteNumber(value.input);\n\tconst output = asFiniteNumber(value.output);\n\tif (input === undefined || output === undefined) return undefined;\n\treturn {\n\t\tinput,\n\t\toutput,\n\t\tcacheRead: asFiniteNumber(value.cacheRead) ?? 0,\n\t\tcacheWrite: asFiniteNumber(value.cacheWrite) ?? 0,\n\t};\n}\n\nfunction parseInput(value: unknown): (\"text\" | \"image\")[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst input: (\"text\" | \"image\")[] = [];\n\tfor (const entry of value) {\n\t\tif (entry === \"text\" || entry === \"image\") input.push(entry);\n\t}\n\treturn input.length > 0 ? input : undefined;\n}\n\nfunction parseThinkingLevelMap(value: unknown): ThinkingLevelMap | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst map: ThinkingLevelMap = {};\n\tlet any = false;\n\tfor (const level of THINKING_LEVEL_KEYS) {\n\t\tconst mapped = value[level];\n\t\tif (mapped === null || typeof mapped === \"string\") {\n\t\t\tmap[level] = mapped;\n\t\t\tany = true;\n\t\t}\n\t}\n\treturn any ? map : undefined;\n}\n\nfunction parseHeaders(value: unknown): Record<string, string> | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst headers: Record<string, string> = {};\n\tfor (const [name, headerValue] of Object.entries(value)) {\n\t\tif (typeof headerValue === \"string\") headers[name] = headerValue;\n\t}\n\treturn Object.keys(headers).length > 0 ? headers : undefined;\n}\n\nfunction parseOfficialEntry(value: unknown): OfficialModelEntry | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst id = typeof value.id === \"string\" ? value.id.trim() : \"\";\n\tconst provider = typeof value.provider === \"string\" ? value.provider.trim() : \"\";\n\tif (!id || !provider) return undefined;\n\tconst api = typeof value.api === \"string\" && value.api.trim() ? value.api.trim() : \"openai-completions\";\n\tconst name = typeof value.name === \"string\" && value.name.trim() ? value.name.trim() : id;\n\tconst baseUrl = typeof value.baseUrl === \"string\" ? value.baseUrl.trim() : \"\";\n\tconst cost = parseCost(value.cost) ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\tconst input = parseInput(value.input) ?? [\"text\"];\n\tconst compat = isRecord(value.compat) ? (value.compat as Model<Api>[\"compat\"]) : undefined;\n\tconst thinkingLevelMap = parseThinkingLevelMap(value.thinkingLevelMap);\n\tconst headers = parseHeaders(value.headers);\n\treturn {\n\t\tid,\n\t\tname,\n\t\tapi: api as Api,\n\t\tprovider,\n\t\tbaseUrl,\n\t\treasoning: value.reasoning === true,\n\t\tinput,\n\t\tcost,\n\t\tcontextWindow: asFiniteNumber(value.contextWindow) ?? 128000,\n\t\tmaxTokens: asFiniteNumber(value.maxTokens) ?? 8192,\n\t\t...(compat ? { compat } : {}),\n\t\t...(thinkingLevelMap ? { thinkingLevelMap } : {}),\n\t\t...(headers ? { headers } : {}),\n\t};\n}\n\nfunction catalogFile(models: OfficialModelEntry[], value?: Record<string, unknown>): OfficialCatalogFile {\n\tconst version = value ? (asFiniteNumber(value.version) ?? 1) : 1;\n\tconst updatedAt = value && typeof value.updatedAt === \"string\" && value.updatedAt.trim() ? value.updatedAt : \"\";\n\treturn { version, updatedAt, models };\n}\n\nfunction parseKeyedCatalog(value: Record<string, unknown>): OfficialCatalogFile | undefined {\n\tconst models: OfficialModelEntry[] = [];\n\tfor (const [key, entry] of Object.entries(value)) {\n\t\tif (META_KEYS.has(key) || !isRecord(entry)) continue;\n\t\tif (typeof entry.id === \"string\") {\n\t\t\tconst parsed = parseOfficialEntry(entry);\n\t\t\tif (parsed) models.push(parsed);\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const [modelId, model] of Object.entries(entry)) {\n\t\t\tif (!isRecord(model)) continue;\n\t\t\tconst parsed = parseOfficialEntry({\n\t\t\t\t...model,\n\t\t\t\tid: typeof model.id === \"string\" && model.id.trim() ? model.id : modelId,\n\t\t\t\tprovider: typeof model.provider === \"string\" && model.provider.trim() ? model.provider : key,\n\t\t\t});\n\t\t\tif (parsed) models.push(parsed);\n\t\t}\n\t}\n\treturn models.length > 0 ? catalogFile(models, value) : undefined;\n}\n\n/** Parse an official catalog document. Returns undefined on a bad shape (never throws). */\nexport function parseOfficialCatalog(value: unknown): OfficialCatalogFile | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (Array.isArray(value.models)) {\n\t\tconst models: OfficialModelEntry[] = [];\n\t\tfor (const entry of value.models) {\n\t\t\tconst parsed = parseOfficialEntry(entry);\n\t\t\tif (parsed) models.push(parsed);\n\t\t}\n\t\treturn catalogFile(models, value);\n\t}\n\tif (\"models\" in value) return undefined;\n\treturn parseKeyedCatalog(value);\n}\n\nfunction parseProviderIndex(value: unknown): string[] | undefined {\n\tif (!Array.isArray(value) || !value.every((entry) => typeof entry === \"string\")) return undefined;\n\treturn value;\n}\n\nfunction readCatalogFile(path: string): OfficialCatalogFile | undefined {\n\ttry {\n\t\tif (!existsSync(path)) return undefined;\n\t\treturn parseOfficialCatalog(JSON.parse(readFileSync(path, \"utf-8\")));\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction bundledCatalogCandidates(): string[] {\n\tconst here = dirname(fileURLToPath(import.meta.url));\n\tconst packageDir = getPackageDir();\n\treturn [\n\t\tjoin(packageDir, \"dist\", \"catalog\", \"models.json\"),\n\t\tjoin(packageDir, \"..\", \"..\", \"catalog\", \"models.json\"),\n\t\tjoin(here, \"../../../../catalog/models.json\"),\n\t\tjoin(packageDir, \"catalog\", \"models.json\"),\n\t\tjoin(here, \"../catalog/models.json\"),\n\t\tjoin(here, \"models.json\"),\n\t\tjoin(packageDir, \"dist\", \"catalog\", \"official-models.json\"),\n\t\tjoin(packageDir, \"..\", \"..\", \"catalog\", \"official-models.json\"),\n\t\tjoin(here, \"../../../../catalog/official-models.json\"),\n\t\tjoin(here, \"official-models.json\"),\n\t\tjoin(here, \"../catalog/official-models.json\"),\n\t];\n}\n\nexport function loadBundledOfficialCatalog(): OfficialCatalogFile {\n\tfor (const path of bundledCatalogCandidates()) {\n\t\tconst parsed = readCatalogFile(path);\n\t\tif (parsed) return parsed;\n\t}\n\treturn BUNDLED_OFFICIAL_CATALOG;\n}\n\nexport function loadCachedOfficialCatalog(cachePath?: string): OfficialCatalogFile | undefined {\n\tif (!cachePath) return undefined;\n\treturn readCatalogFile(cachePath);\n}\n\nexport function writeOfficialCatalogCache(catalog: OfficialCatalogFile, cachePath: string): void {\n\ttry {\n\t\tmkdirSync(dirname(cachePath), { recursive: true, mode: 0o700 });\n\t\twriteFileSync(cachePath, `${JSON.stringify(catalog, null, 2)}\\n`, \"utf-8\");\n\t} catch {\n\t\t// Cache is best-effort.\n\t}\n}\n\nexport function officialModelsByProvider(catalog: OfficialCatalogFile): Map<string, OfficialModelEntry[]> {\n\tconst byProvider = new Map<string, OfficialModelEntry[]>();\n\tfor (const model of catalog.models) {\n\t\tconst list = byProvider.get(model.provider) ?? [];\n\t\tlist.push(model);\n\t\tbyProvider.set(model.provider, list);\n\t}\n\treturn byProvider;\n}\n\n/** Replace or add per-provider rows. Existing providers not in `replacements` are kept. */\nexport function mergeOfficialCatalogByProvider(\n\tbase: OfficialCatalogFile,\n\treplacements: ReadonlyMap<string, OfficialModelEntry[]>,\n\tupdatedAt?: string,\n): OfficialCatalogFile {\n\tconst byProvider = officialModelsByProvider(base);\n\tfor (const [providerId, models] of replacements) {\n\t\tbyProvider.set(providerId, models);\n\t}\n\treturn {\n\t\tversion: base.version || 1,\n\t\tupdatedAt: updatedAt ?? new Date().toISOString(),\n\t\tmodels: [...byProvider.values()].flat(),\n\t};\n}\n\n/** Bundled as the floor; cache rows win per provider. */\nexport function officialCatalogBase(bundled: OfficialCatalogFile, cachePath?: string): OfficialCatalogFile {\n\tconst cached = loadCachedOfficialCatalog(cachePath);\n\tif (!cached) return bundled;\n\treturn mergeOfficialCatalogByProvider(bundled, officialModelsByProvider(cached), cached.updatedAt);\n}\n\n/** A completed GitHub overlay must not be replaced by cache/bundled. */\nexport function preferOfficialCatalog(\n\tprevious: OfficialCatalogLoadResult | undefined,\n\tnext: OfficialCatalogLoadResult,\n): OfficialCatalogLoadResult {\n\tif (next.source === \"github\") return next;\n\tif (previous?.source === \"github\") return previous;\n\treturn next;\n}\n\nexport function officialModelKeys(catalog: OfficialCatalogFile): Set<string> {\n\treturn new Set(catalog.models.map((model) => modelKey(model.provider, model.id)));\n}\n\nconst ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\nexport function officialEntryToModel(entry: OfficialModelEntry, template?: Model<Api>): Model<Api> {\n\treturn {\n\t\tid: entry.id,\n\t\tname: entry.name,\n\t\tapi: entry.api || template?.api || \"openai-completions\",\n\t\tprovider: entry.provider,\n\t\tbaseUrl: entry.baseUrl || template?.baseUrl || \"\",\n\t\treasoning: entry.reasoning,\n\t\tinput: entry.input.length > 0 ? entry.input : (template?.input ?? [\"text\"]),\n\t\tcost: entry.cost ?? template?.cost ?? ZERO_COST,\n\t\tcontextWindow: entry.contextWindow,\n\t\tmaxTokens: entry.maxTokens,\n\t\tcompat: entry.compat ?? template?.compat,\n\t\tthinkingLevelMap: entry.thinkingLevelMap ?? template?.thinkingLevelMap,\n\t\theaders: entry.headers ?? template?.headers,\n\t};\n}\n\nexport interface LoadOfficialCatalogOptions {\n\tallowNetwork?: boolean;\n\tcachePath?: string;\n\tbundled?: OfficialCatalogFile;\n\t/** Catalog directory base (not a single-file URL). */\n\turl?: string;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n\tfetchImpl?: typeof fetch;\n\t/** Stored-credential provider ids. Only these shards are fetched. */\n\tproviderIds?: readonly string[];\n}\n\nfunction resolveBundledCatalog(bundled?: OfficialCatalogFile): OfficialCatalogFile {\n\tif (bundled) return bundled;\n\treturn loadBundledOfficialCatalog();\n}\n\nfunction fallbackCatalog(bundled: OfficialCatalogFile | undefined, cachePath?: string): OfficialCatalogLoadResult {\n\tconst cached = loadCachedOfficialCatalog(cachePath);\n\tif (cached) return { catalog: cached, source: \"cache\" };\n\tconst resolved = resolveBundledCatalog(bundled);\n\tif (resolved.models.length > 0) return { catalog: resolved, source: \"bundled\" };\n\treturn { catalog: BUNDLED_OFFICIAL_CATALOG, source: \"bundled\" };\n}\n\nasync function fetchJson(\n\turl: string,\n\toptions: {\n\t\ttimeoutMs: number;\n\t\tsignal?: AbortSignal;\n\t\tfetchImpl: typeof fetch;\n\t\theaders: Record<string, string>;\n\t},\n): Promise<{ ok: true; value: unknown } | { ok: false; status?: number }> {\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => controller.abort(), options.timeoutMs);\n\tconst onParentAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onParentAbort, { once: true });\n\tif (options.signal?.aborted) controller.abort();\n\ttry {\n\t\tconst abortError = () => {\n\t\t\tconst error = new Error(\"The operation was aborted\");\n\t\t\terror.name = \"AbortError\";\n\t\t\treturn error;\n\t\t};\n\t\tconst response = await Promise.race([\n\t\t\toptions.fetchImpl(url, {\n\t\t\t\theaders: options.headers,\n\t\t\t\tsignal: controller.signal,\n\t\t\t}),\n\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\tcontroller.signal.addEventListener(\"abort\", () => reject(abortError()), { once: true });\n\t\t\t\tif (controller.signal.aborted) reject(abortError());\n\t\t\t}),\n\t\t]);\n\t\tif (!response.ok) return { ok: false, status: response.status };\n\t\treturn { ok: true, value: await response.json() };\n\t} catch {\n\t\treturn { ok: false };\n\t} finally {\n\t\tclearTimeout(timer);\n\t\toptions.signal?.removeEventListener(\"abort\", onParentAbort);\n\t}\n}\n\n/**\n * Load the official overlay. Network only when allowNetwork is true.\n * Fetches providers.json, then providers/{id}.json for stored-credential providers.\n * Successful shards replace that provider only; failed shards keep cache/bundled rows.\n * All requested shards failed → cache, then bundled. Never writes a worse cache. Never throws.\n */\nexport async function loadOfficialCatalog(\n\toptions: LoadOfficialCatalogOptions = {},\n): Promise<OfficialCatalogLoadResult> {\n\tconst cachePath = options.cachePath;\n\t// Cache-only: prefer the on-disk cache and skip parsing bundled models.json.\n\tif (!options.allowNetwork) {\n\t\treturn fallbackCatalog(options.bundled, cachePath);\n\t}\n\n\tconst bundled = resolveBundledCatalog(options.bundled);\n\tconst timeoutMs = options.timeoutMs ?? OFFICIAL_CATALOG_TIMEOUT_MS;\n\tconst fetchImpl = options.fetchImpl ?? fetch;\n\tconst headers = {\n\t\taccept: \"application/json\",\n\t\t\"User-Agent\": getPiUserAgent(VERSION),\n\t};\n\tconst fetchOptions = { timeoutMs, signal: options.signal, fetchImpl, headers };\n\tconst base = options.url ?? officialCatalogBaseUrl();\n\n\ttry {\n\t\tconst indexResult = await fetchJson(officialCatalogUrlFor(\"providers.json\", base), fetchOptions);\n\t\tif (!indexResult.ok) return fallbackCatalog(bundled, cachePath);\n\t\tconst index = parseProviderIndex(indexResult.value);\n\t\tif (!index) return fallbackCatalog(bundled, cachePath);\n\n\t\tconst wanted = new Set(index);\n\t\tconst requested = options.providerIds ?? [];\n\t\tconst shardIds = requested.filter((providerId) => wanted.has(providerId));\n\t\tif (shardIds.length === 0) return fallbackCatalog(bundled, cachePath);\n\n\t\tconst replacements = new Map<string, OfficialModelEntry[]>();\n\t\tawait Promise.all(\n\t\t\tshardIds.map(async (providerId) => {\n\t\t\t\tconst result = await fetchJson(\n\t\t\t\t\tofficialCatalogUrlFor(`providers/${encodeURIComponent(providerId)}.json`, base),\n\t\t\t\t\tfetchOptions,\n\t\t\t\t);\n\t\t\t\tif (!result.ok) return;\n\t\t\t\tconst parsed = parseOfficialCatalog(result.value);\n\t\t\t\tif (!parsed || parsed.models.length === 0) return;\n\t\t\t\treplacements.set(providerId, parsed.models);\n\t\t\t}),\n\t\t);\n\t\tif (replacements.size === 0) return fallbackCatalog(bundled, cachePath);\n\n\t\tconst catalog = mergeOfficialCatalogByProvider(officialCatalogBase(bundled, cachePath), replacements);\n\t\tif (cachePath) writeOfficialCatalogCache(catalog, cachePath);\n\t\treturn { catalog, source: \"github\" };\n\t} catch {\n\t\treturn fallbackCatalog(bundled, cachePath);\n\t}\n}\n"]}
1
+ {"version":3,"file":"official-catalog.js","sourceRoot":"","sources":["../../src/core/official-catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Api, Model, ThinkingLevelMap } from \"@ashx-j/lunr-ai\";\nimport { getAgentDir, getPackageDir, VERSION } from \"../config.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\n\n/** Directory on GitHub raw (`providers.json` + `providers/{id}.json`). Override with `LUNR_OFFICIAL_CATALOG_URL`. */\nexport const OFFICIAL_CATALOG_DEFAULT_URL = \"https://raw.githubusercontent.com/ashx-j/lunR/master/catalog\";\nexport const VERSIONED_CATALOG_URL = \"https://raw.githubusercontent.com/ashx-j/lunR/model-catalog/catalog\";\nexport const OFFICIAL_CATALOG_TIMEOUT_MS = 4000;\nexport const OFFICIAL_CATALOG_CACHE_FILENAME = \"official-catalog-cache.json\";\n\nconst THINKING_LEVEL_KEYS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const;\nconst META_KEYS = new Set([\"version\", \"updatedAt\", \"generatedAt\", \"sourceCommit\", \"providerCount\", \"modelCount\"]);\n\nexport interface OfficialModelCost {\n\ttiers?: Model<Api>[\"cost\"][\"tiers\"];\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n}\n\nexport interface OfficialModelEntry {\n\tcatalog?: Model<Api>[\"catalog\"];\n\tid: string;\n\tname: string;\n\tapi: Api;\n\tprovider: string;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: (\"text\" | \"image\")[];\n\tcost: OfficialModelCost;\n\tcontextWindow: number;\n\tmaxTokens: number;\n\tcompat?: Model<Api>[\"compat\"];\n\tthinkingLevelMap?: ThinkingLevelMap;\n\theaders?: Record<string, string>;\n}\n\nexport interface OfficialCatalogFile {\n\tversion: number;\n\tupdatedAt: string;\n\tmodels: OfficialModelEntry[];\n}\n\nexport type OfficialCatalogSource = \"github\" | \"cache\" | \"bundled\";\n\nexport interface OfficialCatalogLoadResult {\n\terrors?: Record<string, string>;\n\tcatalog: OfficialCatalogFile;\n\tsource: OfficialCatalogSource;\n}\n\n/** Seed shipped in-repo; used when the JSON file cannot be read. */\nexport const BUNDLED_OFFICIAL_CATALOG: OfficialCatalogFile = {\n\tversion: 1,\n\tupdatedAt: \"2026-08-15T00:00:00Z\",\n\tmodels: [\n\t\t{\n\t\t\tid: \"grok-4.6\",\n\t\t\tname: \"Grok 4.6\",\n\t\t\tapi: \"openai-completions\",\n\t\t\tprovider: \"xai\",\n\t\t\tbaseUrl: \"https://api.x.ai/v1\",\n\t\t\treasoning: true,\n\t\t\tinput: [\"text\", \"image\"],\n\t\t\tcost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 },\n\t\t\tcontextWindow: 500000,\n\t\t\tmaxTokens: 500000,\n\t\t},\n\t],\n};\n\nexport function officialCatalogCachePath(agentDir: string = getAgentDir()): string {\n\treturn join(agentDir, OFFICIAL_CATALOG_CACHE_FILENAME);\n}\n\n/** Base URL (no trailing slash). `LUNR_OFFICIAL_CATALOG_URL` overrides the directory, not a single file. */\nexport function officialCatalogBaseUrl(override?: string): string {\n\tconst raw = (override ?? process.env.LUNR_OFFICIAL_CATALOG_URL)?.trim() || OFFICIAL_CATALOG_DEFAULT_URL;\n\treturn raw.replace(/\\/+$/, \"\");\n}\n\n/** @deprecated Use officialCatalogBaseUrl. Kept as an alias for the directory base. */\nexport function officialCatalogUrl(): string {\n\treturn officialCatalogBaseUrl();\n}\n\nexport function officialCatalogUrlFor(path: string, base?: string): string {\n\tconst normalized = path.replace(/^\\/+/, \"\");\n\treturn `${officialCatalogBaseUrl(base)}/${normalized}`;\n}\n\nexport function modelKey(provider: string, id: string): string {\n\treturn `${provider}/${id}`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asFiniteNumber(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (typeof value === \"string\" && value.trim()) {\n\t\tconst parsed = Number(value);\n\t\tif (Number.isFinite(parsed)) return parsed;\n\t}\n\treturn undefined;\n}\n\nfunction parseCost(value: unknown): OfficialModelCost | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst input = asFiniteNumber(value.input);\n\tconst output = asFiniteNumber(value.output);\n\tif (input === undefined || output === undefined) return undefined;\n\treturn {\n\t\tinput,\n\t\toutput,\n\t\tcacheRead: asFiniteNumber(value.cacheRead) ?? 0,\n\t\tcacheWrite: asFiniteNumber(value.cacheWrite) ?? 0,\n\t\t...(Array.isArray(value.tiers)\n\t\t\t? {\n\t\t\t\t\ttiers: value.tiers.flatMap((tier) => {\n\t\t\t\t\t\tif (!isRecord(tier) || !(typeof tier.inputTokensAbove === \"number\" && tier.inputTokensAbove >= 0))\n\t\t\t\t\t\t\treturn [];\n\t\t\t\t\t\tconst rates = parseCost({\n\t\t\t\t\t\t\tinput: tier.input,\n\t\t\t\t\t\t\toutput: tier.output,\n\t\t\t\t\t\t\tcacheRead: tier.cacheRead,\n\t\t\t\t\t\t\tcacheWrite: tier.cacheWrite,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn rates ? [{ ...rates, inputTokensAbove: tier.inputTokensAbove }] : [];\n\t\t\t\t\t}),\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\n\nfunction parseInput(value: unknown): (\"text\" | \"image\")[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst input: (\"text\" | \"image\")[] = [];\n\tfor (const entry of value) {\n\t\tif (entry === \"text\" || entry === \"image\") input.push(entry);\n\t}\n\treturn input.length > 0 ? input : undefined;\n}\n\nfunction parseThinkingLevelMap(value: unknown): ThinkingLevelMap | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst map: ThinkingLevelMap = {};\n\tlet any = false;\n\tfor (const level of THINKING_LEVEL_KEYS) {\n\t\tconst mapped = value[level];\n\t\tif (mapped === null || typeof mapped === \"string\") {\n\t\t\tmap[level] = mapped;\n\t\t\tany = true;\n\t\t}\n\t}\n\treturn any ? map : undefined;\n}\n\nfunction parseHeaders(value: unknown): Record<string, string> | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst headers: Record<string, string> = {};\n\tfor (const [name, headerValue] of Object.entries(value)) {\n\t\tif (typeof headerValue === \"string\") headers[name] = headerValue;\n\t}\n\treturn Object.keys(headers).length > 0 ? headers : undefined;\n}\n\nfunction parseOfficialEntry(value: unknown): OfficialModelEntry | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst id = typeof value.id === \"string\" ? value.id.trim() : \"\";\n\tconst provider = typeof value.provider === \"string\" ? value.provider.trim() : \"\";\n\tif (!id || !provider) return undefined;\n\tconst api = typeof value.api === \"string\" && value.api.trim() ? value.api.trim() : \"openai-completions\";\n\tconst name = typeof value.name === \"string\" && value.name.trim() ? value.name.trim() : id;\n\tconst baseUrl = typeof value.baseUrl === \"string\" ? value.baseUrl.trim() : \"\";\n\tconst cost = parseCost(value.cost) ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\tconst input = parseInput(value.input) ?? [\"text\"];\n\tconst compat = isRecord(value.compat) ? (value.compat as Model<Api>[\"compat\"]) : undefined;\n\tconst thinkingLevelMap = parseThinkingLevelMap(value.thinkingLevelMap);\n\tconst headers = parseHeaders(value.headers);\n\treturn {\n\t\tid,\n\t\t...(isRecord(value.catalog) && value.catalog.source === \"provider\" && Array.isArray(value.catalog.supplied)\n\t\t\t? { catalog: value.catalog as Model<Api>[\"catalog\"] }\n\t\t\t: {}),\n\t\tname,\n\t\tapi: api as Api,\n\t\tprovider,\n\t\tbaseUrl,\n\t\treasoning: value.reasoning === true,\n\t\tinput,\n\t\tcost,\n\t\tcontextWindow: asFiniteNumber(value.contextWindow) ?? 128000,\n\t\tmaxTokens: asFiniteNumber(value.maxTokens) ?? 8192,\n\t\t...(compat ? { compat } : {}),\n\t\t...(thinkingLevelMap ? { thinkingLevelMap } : {}),\n\t\t...(headers ? { headers } : {}),\n\t};\n}\n\nfunction catalogFile(models: OfficialModelEntry[], value?: Record<string, unknown>): OfficialCatalogFile {\n\tconst version = value ? (asFiniteNumber(value.version) ?? 1) : 1;\n\tconst updatedAt = value && typeof value.updatedAt === \"string\" && value.updatedAt.trim() ? value.updatedAt : \"\";\n\treturn { version, updatedAt, models };\n}\n\nfunction parseKeyedCatalog(value: Record<string, unknown>): OfficialCatalogFile | undefined {\n\tconst models: OfficialModelEntry[] = [];\n\tfor (const [key, entry] of Object.entries(value)) {\n\t\tif (META_KEYS.has(key) || !isRecord(entry)) continue;\n\t\tif (typeof entry.id === \"string\") {\n\t\t\tconst parsed = parseOfficialEntry(entry);\n\t\t\tif (parsed) models.push(parsed);\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const [modelId, model] of Object.entries(entry)) {\n\t\t\tif (!isRecord(model)) continue;\n\t\t\tconst parsed = parseOfficialEntry({\n\t\t\t\t...model,\n\t\t\t\tid: typeof model.id === \"string\" && model.id.trim() ? model.id : modelId,\n\t\t\t\tprovider: typeof model.provider === \"string\" && model.provider.trim() ? model.provider : key,\n\t\t\t});\n\t\t\tif (parsed) models.push(parsed);\n\t\t}\n\t}\n\treturn models.length > 0 ? catalogFile(models, value) : undefined;\n}\n\n/** Parse an official catalog document. Returns undefined on a bad shape (never throws). */\nexport function parseOfficialCatalog(value: unknown): OfficialCatalogFile | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (Array.isArray(value.models)) {\n\t\tconst models: OfficialModelEntry[] = [];\n\t\tfor (const entry of value.models) {\n\t\t\tconst parsed = parseOfficialEntry(entry);\n\t\t\tif (parsed) models.push(parsed);\n\t\t}\n\t\treturn catalogFile(models, value);\n\t}\n\tif (\"models\" in value) return undefined;\n\treturn parseKeyedCatalog(value);\n}\n\nfunction parseProviderIndex(value: unknown): string[] | undefined {\n\tif (!Array.isArray(value) || !value.every((entry) => typeof entry === \"string\")) return undefined;\n\treturn value;\n}\n\nfunction readCatalogFile(path: string): OfficialCatalogFile | undefined {\n\ttry {\n\t\tif (!existsSync(path)) return undefined;\n\t\treturn parseOfficialCatalog(JSON.parse(readFileSync(path, \"utf-8\")));\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction bundledCatalogCandidates(): string[] {\n\tconst here = dirname(fileURLToPath(import.meta.url));\n\tconst packageDir = getPackageDir();\n\treturn [\n\t\tjoin(packageDir, \"dist\", \"catalog\", \"models.json\"),\n\t\tjoin(packageDir, \"..\", \"..\", \"catalog\", \"models.json\"),\n\t\tjoin(here, \"../../../../catalog/models.json\"),\n\t\tjoin(packageDir, \"catalog\", \"models.json\"),\n\t\tjoin(here, \"../catalog/models.json\"),\n\t\tjoin(here, \"models.json\"),\n\t\tjoin(packageDir, \"dist\", \"catalog\", \"official-models.json\"),\n\t\tjoin(packageDir, \"..\", \"..\", \"catalog\", \"official-models.json\"),\n\t\tjoin(here, \"../../../../catalog/official-models.json\"),\n\t\tjoin(here, \"official-models.json\"),\n\t\tjoin(here, \"../catalog/official-models.json\"),\n\t];\n}\n\nexport function loadBundledOfficialCatalog(): OfficialCatalogFile {\n\tfor (const path of bundledCatalogCandidates()) {\n\t\tconst parsed = readCatalogFile(path);\n\t\tif (parsed) return parsed;\n\t}\n\treturn BUNDLED_OFFICIAL_CATALOG;\n}\n\nexport function loadCachedOfficialCatalog(cachePath?: string): OfficialCatalogFile | undefined {\n\tif (!cachePath) return undefined;\n\treturn readCatalogFile(cachePath);\n}\n\nexport function writeOfficialCatalogCache(catalog: OfficialCatalogFile, cachePath: string): void {\n\tconst temporary = `${cachePath}.${randomUUID()}.tmp`;\n\ttry {\n\t\tmkdirSync(dirname(cachePath), { recursive: true, mode: 0o700 });\n\t\twriteFileSync(temporary, `${JSON.stringify(catalog, null, 2)}\\n`, { encoding: \"utf-8\", mode: 0o600 });\n\t\trenameSync(temporary, cachePath);\n\t} catch {\n\t\t// Cache is best-effort.\n\t} finally {\n\t\ttry {\n\t\t\tunlinkSync(temporary);\n\t\t} catch {\n\t\t\t/* Renamed or never created. */\n\t\t}\n\t}\n}\n\nexport function officialModelsByProvider(catalog: OfficialCatalogFile): Map<string, OfficialModelEntry[]> {\n\tconst byProvider = new Map<string, OfficialModelEntry[]>();\n\tfor (const model of catalog.models) {\n\t\tconst list = byProvider.get(model.provider) ?? [];\n\t\tlist.push(model);\n\t\tbyProvider.set(model.provider, list);\n\t}\n\treturn byProvider;\n}\n\n/** Replace or add per-provider rows. Existing providers not in `replacements` are kept. */\nexport function mergeOfficialCatalogByProvider(\n\tbase: OfficialCatalogFile,\n\treplacements: ReadonlyMap<string, OfficialModelEntry[]>,\n\tupdatedAt?: string,\n): OfficialCatalogFile {\n\tconst byProvider = officialModelsByProvider(base);\n\tfor (const [providerId, models] of replacements) {\n\t\tbyProvider.set(providerId, models);\n\t}\n\treturn {\n\t\tversion: base.version || 1,\n\t\tupdatedAt: updatedAt ?? new Date().toISOString(),\n\t\tmodels: [...byProvider.values()].flat(),\n\t};\n}\n\n/** Bundled as the floor; cache rows win per provider. */\nexport function officialCatalogBase(bundled: OfficialCatalogFile, cachePath?: string): OfficialCatalogFile {\n\tconst cached = loadCachedOfficialCatalog(cachePath);\n\tif (!cached) return bundled;\n\treturn mergeOfficialCatalogByProvider(bundled, officialModelsByProvider(cached), cached.updatedAt);\n}\n\n/** A completed GitHub overlay must not be replaced by cache/bundled. */\nexport function preferOfficialCatalog(\n\tprevious: OfficialCatalogLoadResult | undefined,\n\tnext: OfficialCatalogLoadResult,\n): OfficialCatalogLoadResult {\n\tif (next.source === \"github\") return next;\n\tif (previous?.source === \"github\") return { ...previous, errors: next.errors };\n\treturn next;\n}\n\nexport function officialModelKeys(catalog: OfficialCatalogFile): Set<string> {\n\treturn new Set(catalog.models.map((model) => modelKey(model.provider, model.id)));\n}\n\nconst ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\nexport function officialEntryToModel(entry: OfficialModelEntry, template?: Model<Api>): Model<Api> {\n\treturn {\n\t\tcatalog: entry.catalog,\n\t\tid: entry.id,\n\t\tname: entry.name,\n\t\tapi: entry.api || template?.api || \"openai-completions\",\n\t\tprovider: entry.provider,\n\t\tbaseUrl: entry.baseUrl || template?.baseUrl || \"\",\n\t\treasoning: entry.reasoning,\n\t\tinput: entry.input.length > 0 ? entry.input : (template?.input ?? [\"text\"]),\n\t\tcost: entry.cost ?? template?.cost ?? ZERO_COST,\n\t\tcontextWindow: entry.contextWindow,\n\t\tmaxTokens: entry.maxTokens,\n\t\tcompat: entry.compat ?? template?.compat,\n\t\tthinkingLevelMap: entry.thinkingLevelMap ?? template?.thinkingLevelMap,\n\t\theaders: entry.headers ?? template?.headers,\n\t};\n}\n\nexport interface LoadOfficialCatalogOptions {\n\tallowNetwork?: boolean;\n\tcachePath?: string;\n\tbundled?: OfficialCatalogFile;\n\t/** Catalog directory base (not a single-file URL). */\n\turl?: string;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n\tfetchImpl?: typeof fetch;\n\t/** Stored-credential provider ids. Only these shards are fetched. */\n\tproviderIds?: readonly string[];\n}\n\nfunction resolveBundledCatalog(bundled?: OfficialCatalogFile): OfficialCatalogFile {\n\tif (bundled) return bundled;\n\treturn loadBundledOfficialCatalog();\n}\n\nfunction fallbackCatalog(bundled: OfficialCatalogFile | undefined, cachePath?: string): OfficialCatalogLoadResult {\n\tconst cached = loadCachedOfficialCatalog(cachePath);\n\tif (cached) return { catalog: cached, source: \"cache\" };\n\tconst resolved = resolveBundledCatalog(bundled);\n\tif (resolved.models.length > 0) return { catalog: resolved, source: \"bundled\" };\n\treturn { catalog: BUNDLED_OFFICIAL_CATALOG, source: \"bundled\" };\n}\n\nasync function fetchJson(\n\turl: string,\n\toptions: {\n\t\ttimeoutMs: number;\n\t\tsignal?: AbortSignal;\n\t\tfetchImpl: typeof fetch;\n\t\theaders: Record<string, string>;\n\t},\n): Promise<{ ok: true; value: unknown } | { ok: false; status?: number }> {\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => controller.abort(), options.timeoutMs);\n\tconst onParentAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onParentAbort, { once: true });\n\tif (options.signal?.aborted) controller.abort();\n\ttry {\n\t\tconst abortError = () => {\n\t\t\tconst error = new Error(\"The operation was aborted\");\n\t\t\terror.name = \"AbortError\";\n\t\t\treturn error;\n\t\t};\n\t\treturn await Promise.race([\n\t\t\t(async () => {\n\t\t\t\tconst response = await options.fetchImpl(url, {\n\t\t\t\t\theaders: options.headers,\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t});\n\t\t\t\tif (!response.ok) return { ok: false as const, status: response.status };\n\t\t\t\treturn { ok: true as const, value: await response.json() };\n\t\t\t})(),\n\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\tcontroller.signal.addEventListener(\"abort\", () => reject(abortError()), { once: true });\n\t\t\t\tif (controller.signal.aborted) reject(abortError());\n\t\t\t}),\n\t\t]);\n\t} catch {\n\t\treturn { ok: false };\n\t} finally {\n\t\tclearTimeout(timer);\n\t\toptions.signal?.removeEventListener(\"abort\", onParentAbort);\n\t}\n}\n\n/**\n * Load the official overlay. Network only when allowNetwork is true.\n * Fetches providers.json, then providers/{id}.json for stored-credential providers.\n * Successful shards replace that provider only; failed shards keep cache/bundled rows.\n * All requested shards failed → cache, then bundled. Never writes a worse cache. Never throws.\n */\nexport async function loadOfficialCatalog(\n\toptions: LoadOfficialCatalogOptions = {},\n): Promise<OfficialCatalogLoadResult> {\n\tconst cachePath = options.cachePath;\n\t// Cache-only: prefer the on-disk cache and skip parsing bundled models.json.\n\tif (!options.allowNetwork) {\n\t\treturn fallbackCatalog(options.bundled, cachePath);\n\t}\n\n\tconst bundled = resolveBundledCatalog(options.bundled);\n\tconst timeoutMs = options.timeoutMs ?? OFFICIAL_CATALOG_TIMEOUT_MS;\n\tconst fetchImpl = options.fetchImpl ?? fetch;\n\tconst headers = {\n\t\taccept: \"application/json\",\n\t\t\"User-Agent\": getPiUserAgent(VERSION),\n\t};\n\tconst fetchOptions = { timeoutMs, signal: options.signal, fetchImpl, headers };\n\tconst unavailable = (): OfficialCatalogLoadResult => ({\n\t\t...fallbackCatalog(bundled, cachePath),\n\t\terrors: Object.fromEntries(\n\t\t\t(options.providerIds ?? []).map((id) => [id, \"Published catalog unavailable; using cached metadata\"]),\n\t\t),\n\t});\n\tlet base = options.url ?? officialCatalogBaseUrl();\n\tlet manifest: Record<string, unknown> | undefined;\n\t// Existing custom mirrors remain compatible with the v1 index/shard format.\n\tif (!options.url && !process.env.LUNR_OFFICIAL_CATALOG_URL) {\n\t\tconst result = await fetchJson(`${VERSIONED_CATALOG_URL}/publication.json`, fetchOptions);\n\t\tif (\n\t\t\tresult.ok &&\n\t\t\tisRecord(result.value) &&\n\t\t\tresult.value.version === 2 &&\n\t\t\ttypeof result.value.revision === \"string\" &&\n\t\t\t/^sha256-[a-f0-9]{64}$/.test(result.value.revision) &&\n\t\t\tisRecord(result.value.shards) &&\n\t\t\tparseProviderIndex(result.value.providers)\n\t\t) {\n\t\t\tmanifest = result.value;\n\t\t\tbase = `${VERSIONED_CATALOG_URL}/snapshots/${result.value.revision}`;\n\t\t}\n\t}\n\n\ttry {\n\t\tconst indexResult = manifest\n\t\t\t? { ok: true as const, value: manifest.providers }\n\t\t\t: await fetchJson(officialCatalogUrlFor(\"providers.json\", base), fetchOptions);\n\t\tif (!indexResult.ok) return unavailable();\n\t\tconst index = parseProviderIndex(indexResult.value);\n\t\tif (!index) return unavailable();\n\n\t\tconst wanted = new Set(index);\n\t\tconst requested = options.providerIds ?? [];\n\t\tconst shardIds = requested.filter((providerId) => wanted.has(providerId));\n\t\tif (shardIds.length === 0) return fallbackCatalog(bundled, cachePath);\n\n\t\tconst replacements = new Map<string, OfficialModelEntry[]>();\n\t\tconst errors: Record<string, string> = {};\n\t\tawait Promise.all(\n\t\t\tshardIds.map(async (providerId) => {\n\t\t\t\tconst result = await fetchJson(\n\t\t\t\t\tofficialCatalogUrlFor(`providers/${encodeURIComponent(providerId)}.json`, base),\n\t\t\t\t\tfetchOptions,\n\t\t\t\t);\n\t\t\t\tif (!result.ok) {\n\t\t\t\t\terrors[providerId] = \"Catalog shard unavailable; using cached metadata\";\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\tmanifest &&\n\t\t\t\t\t(manifest.shards as Record<string, unknown>)[providerId] !==\n\t\t\t\t\t\tcreateHash(\"sha256\").update(JSON.stringify(result.value)).digest(\"hex\")\n\t\t\t\t) {\n\t\t\t\t\terrors[providerId] = \"Catalog shard checksum mismatch; using cached metadata\";\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst parsed = parseOfficialCatalog(result.value);\n\t\t\t\tif (!parsed || parsed.models.length === 0 || parsed.models.some((model) => model.provider !== providerId)) {\n\t\t\t\t\terrors[providerId] = \"Invalid catalog shard; using cached metadata\";\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treplacements.set(providerId, parsed.models);\n\t\t\t}),\n\t\t);\n\t\tif (replacements.size === 0) return { ...fallbackCatalog(bundled, cachePath), errors };\n\n\t\tconst catalog = mergeOfficialCatalogByProvider(\n\t\t\tofficialCatalogBase(bundled, cachePath),\n\t\t\treplacements,\n\t\t\ttypeof manifest?.generatedAt === \"string\" ? manifest.generatedAt : undefined,\n\t\t);\n\t\tif (cachePath) writeOfficialCatalogCache(catalog, cachePath);\n\t\treturn { catalog, source: \"github\", ...(Object.keys(errors).length ? { errors } : {}) };\n\t} catch {\n\t\treturn unavailable();\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgCH,OAAO,KAAK,EAAE,eAAe,EAAuB,MAAM,4BAA4B,CAAC;AAyBvF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAa9E;;;GAGG;AACH,wBAAsB,cAAc,CACnC,MAAM,GAAE,MAAM,CAAC,UAA0B,EACzC,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GACtD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA0C7B;AA2aD,MAAM,WAAW,WAAW;IAC3B,kBAAkB,CAAC,EAAE,eAAe,EAAE,CAAC;IACvC,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACvC;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,iBAoe/D","sourcesContent":["/**\n * Main entry point for the coding agent CLI.\n *\n * This file handles CLI argument parsing and translates them into\n * createAgentSession() options. The SDK does the heavy lifting.\n */\n\nimport { createInterface } from \"node:readline\";\nimport { type ImageContent, modelsAreEqual } from \"@ashx-j/lunr-ai\";\nimport chalk from \"chalk\";\nimport { lightBuiltinExtensions, loadAllBuiltinExtensions } from \"./builtin-extensions/index.ts\";\nimport { type Args, type Mode, parseArgs, printHelp } from \"./cli/args.ts\";\nimport { processFileArguments } from \"./cli/file-processor.ts\";\nimport { buildInitialMessage } from \"./cli/initial-message.ts\";\nimport { handleInstallCli } from \"./cli/install-cli.ts\";\nimport { listModels } from \"./cli/list-models.ts\";\nimport { createProjectTrustContext } from \"./cli/project-trust.ts\";\nimport { selectSession } from \"./cli/session-picker.ts\";\nimport { shouldRunFirstTimeSetup, showFirstTimeSetup, showStartupSelector } from \"./cli/startup-ui.ts\";\nimport { handleUpdateCli } from \"./cli/update-cli.ts\";\nimport {\n\tAPP_NAME,\n\tappendDebugLog,\n\tENV_SESSION_DIR,\n\texpandTildePath,\n\tgetAgentDir,\n\tgetSessionsDir,\n\tVERSION,\n} from \"./config.ts\";\nimport { type CreateAgentSessionRuntimeFactory, createAgentSessionRuntime } from \"./core/agent-session-runtime.ts\";\nimport {\n\ttype AgentSessionRuntimeDiagnostic,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./core/agent-session-services.ts\";\nimport { formatNoModelsAvailableMessage } from \"./core/auth-guidance.ts\";\nimport { registerCustomizeBridge } from \"./core/customize.ts\";\nimport type { InlineExtension, ProjectTrustContext } from \"./core/extensions/types.ts\";\nimport { applyHttpProxySettings, configureHttpDispatcher } from \"./core/http-dispatcher.ts\";\nimport { registerMemoryCapBridge } from \"./core/memory-cap.ts\";\nimport { resolveCliModel, resolveModelScope, type ScopedModel } from \"./core/model-resolver.ts\";\nimport type { ModelRuntime } from \"./core/model-runtime.ts\";\nimport { registerModelTierBridge } from \"./core/model-tiers.ts\";\nimport { restoreStdout, takeOverStdout } from \"./core/output-guard.ts\";\nimport { type AppMode, resolveProjectTrusted } from \"./core/project-trust.ts\";\nimport { bindRuntimeBridges } from \"./core/runtime-bridges.ts\";\nimport type { CreateAgentSessionOptions } from \"./core/sdk.ts\";\nimport {\n\tformatMissingSessionCwdPrompt,\n\tgetMissingSessionCwdIssue,\n\tMissingSessionCwdError,\n\ttype SessionCwdIssue,\n} from \"./core/session-cwd.ts\";\nimport { assertValidSessionId, SessionManager } from \"./core/session-manager.ts\";\nimport { pruneOldSessions } from \"./core/session-retention.ts\";\nimport { SettingsManager } from \"./core/settings-manager.ts\";\nimport { applyInheritedSubagentPermissions } from \"./core/subagent-permission-inherit.ts\";\nimport { printTimings, resetTimings, time } from \"./core/timings.ts\";\nimport { hasTrustRequiringProjectResources, ProjectTrustStore } from \"./core/trust-manager.ts\";\nimport { runMigrations, showDeprecationWarnings } from \"./migrations.ts\";\nimport { initTheme, stopThemeWatcher } from \"./modes/interactive/theme/theme.ts\";\nimport { handleConfigCommand, handlePackageCommand } from \"./package-manager-cli.ts\";\nimport type { InteractiveStartupShell } from \"./startup/interactive-shell.ts\";\nimport { markStartupMilestone } from \"./startup/startup-milestones.ts\";\nimport { isLocalPath, normalizePath, resolvePath } from \"./utils/paths.ts\";\n\nconst EXTENSION_LOAD_FAILURE_HINT = `Hint: Start without extensions using \"${APP_NAME} -ne\".`;\n\n/**\n * Read all content from piped stdin.\n * Returns undefined if stdin is a TTY (interactive terminal).\n */\nconst PIPED_STDIN_FIRST_CHUNK_MS = 50;\nconst PIPED_STDIN_IDLE_MS = 2000;\n\n/**\n * Read piped stdin. A non-TTY that never emits data (Windows console, leftover\n * redirected handle) must not block interactive start forever.\n */\nexport async function readPipedStdin(\n\tstream: NodeJS.ReadStream = process.stdin,\n\toptions: { firstChunkMs?: number; idleMs?: number } = {},\n): Promise<string | undefined> {\n\tif (stream.isTTY) {\n\t\treturn undefined;\n\t}\n\n\tconst firstChunkMs = options.firstChunkMs ?? PIPED_STDIN_FIRST_CHUNK_MS;\n\tconst idleMs = options.idleMs ?? PIPED_STDIN_IDLE_MS;\n\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tlet settled = false;\n\t\tlet sawData = false;\n\t\tlet idleTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst firstChunkTimer = setTimeout(() => {\n\t\t\tif (!sawData) finish(undefined);\n\t\t}, firstChunkMs);\n\n\t\tconst finish = (value: string | undefined) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(firstChunkTimer);\n\t\t\tif (idleTimer) clearTimeout(idleTimer);\n\t\t\tstream.off(\"data\", onData);\n\t\t\tstream.off(\"end\", onEnd);\n\t\t\tstream.off(\"error\", onEnd);\n\t\t\tresolve(value);\n\t\t};\n\n\t\tconst onEnd = () => finish(data.trim() || undefined);\n\t\tconst onData = (chunk: string | Buffer) => {\n\t\t\tsawData = true;\n\t\t\tdata += typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n\t\t\tif (idleTimer) clearTimeout(idleTimer);\n\t\t\tidleTimer = setTimeout(onEnd, idleMs);\n\t\t};\n\n\t\tstream.setEncoding(\"utf8\");\n\t\tstream.on(\"data\", onData);\n\t\tstream.on(\"end\", onEnd);\n\t\tstream.on(\"error\", onEnd);\n\t\tstream.resume();\n\t});\n}\n\nfunction collectSettingsDiagnostics(\n\tsettingsManager: SettingsManager,\n\tcontext: string,\n): AgentSessionRuntimeDiagnostic[] {\n\treturn settingsManager.drainErrors().map(({ scope, error }) => ({\n\t\ttype: \"warning\",\n\t\tmessage: `(${context}, ${scope} settings) ${error.message}`,\n\t}));\n}\n\nfunction reportDiagnostics(diagnostics: readonly AgentSessionRuntimeDiagnostic[]): void {\n\tfor (const diagnostic of diagnostics) {\n\t\tconst color = diagnostic.type === \"error\" ? chalk.red : diagnostic.type === \"warning\" ? chalk.yellow : chalk.dim;\n\t\tconst prefix = diagnostic.type === \"error\" ? \"Error: \" : diagnostic.type === \"warning\" ? \"Warning: \" : \"\";\n\t\tconsole.error(color(`${prefix}${diagnostic.message}`));\n\t}\n}\n\nfunction isTruthyEnvFlag(value: string | undefined): boolean {\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\n\nfunction resolveAppMode(parsed: Args, stdinIsTTY: boolean, stdoutIsTTY: boolean): AppMode {\n\tif (parsed.mode === \"rpc\") {\n\t\treturn \"rpc\";\n\t}\n\tif (parsed.mode === \"json\") {\n\t\treturn \"json\";\n\t}\n\t// PI_STARTUP_BENCHMARK=1 times interactive first paint even when stdin/stdout\n\t// are not TTYs (repo npx, CI, redirected logs).\n\tif (isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK) && !parsed.print) {\n\t\treturn \"interactive\";\n\t}\n\tif (parsed.print || !stdinIsTTY || !stdoutIsTTY) {\n\t\treturn \"print\";\n\t}\n\treturn \"interactive\";\n}\n\nfunction toPrintOutputMode(appMode: AppMode): Exclude<Mode, \"rpc\"> {\n\treturn appMode === \"json\" ? \"json\" : \"text\";\n}\n\nfunction isPlainRuntimeMetadataCommand(parsed: Args): boolean {\n\treturn !parsed.print && parsed.mode === undefined && (parsed.help === true || parsed.listModels !== undefined);\n}\n\nasync function prepareInitialMessage(\n\tparsed: Args,\n\tautoResizeImages: boolean,\n\tstdinContent?: string,\n): Promise<{\n\tinitialMessage?: string;\n\tinitialImages?: ImageContent[];\n}> {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn buildInitialMessage({ parsed, stdinContent });\n\t}\n\n\tconst { text, images } = await processFileArguments(parsed.fileArgs, { autoResizeImages });\n\treturn buildInitialMessage({\n\t\tparsed,\n\t\tfileText: text,\n\t\tfileImages: images,\n\t\tstdinContent,\n\t});\n}\n\n/** Result from resolving a session argument */\ntype ResolvedSession =\n\t| { type: \"path\"; path: string } // Direct file path\n\t| { type: \"local\"; path: string } // Found in current project\n\t| { type: \"global\"; path: string; cwd: string } // Found in different project\n\t| { type: \"not_found\"; arg: string }; // Not found anywhere\n\n/**\n * Resolve a session argument to a file path.\n * If it looks like a path, use as-is. Otherwise try to match as session ID prefix.\n */\nasync function findLocalSessionByExactId(\n\tsessionId: string,\n\tcwd: string,\n\tsessionDir?: string,\n): Promise<{ type: \"local\"; path: string } | undefined> {\n\tconst localSessions = await SessionManager.list(cwd, sessionDir);\n\tconst localMatch = localSessions.find((s) => s.id === sessionId);\n\treturn localMatch ? { type: \"local\", path: localMatch.path } : undefined;\n}\n\nasync function resolveSessionPath(sessionArg: string, cwd: string, sessionDir?: string): Promise<ResolvedSession> {\n\t// If it looks like a file path, resolve it before handing it to the session manager.\n\tif (sessionArg.includes(\"/\") || sessionArg.includes(\"\\\\\") || sessionArg.endsWith(\".jsonl\")) {\n\t\treturn { type: \"path\", path: resolvePath(sessionArg, cwd) };\n\t}\n\n\t// Try to match as session ID in current project first\n\tconst localSessions = await SessionManager.list(cwd, sessionDir);\n\tconst localMatch =\n\t\tlocalSessions.find((s) => s.id === sessionArg) ?? localSessions.find((s) => s.id.startsWith(sessionArg));\n\n\tif (localMatch) {\n\t\treturn { type: \"local\", path: localMatch.path };\n\t}\n\n\t// Try global search across all projects\n\tconst allSessions = await SessionManager.listAll(sessionDir);\n\tconst globalMatch =\n\t\tallSessions.find((s) => s.id === sessionArg) ?? allSessions.find((s) => s.id.startsWith(sessionArg));\n\n\tif (globalMatch) {\n\t\treturn { type: \"global\", path: globalMatch.path, cwd: globalMatch.cwd };\n\t}\n\n\t// Not found anywhere\n\treturn { type: \"not_found\", arg: sessionArg };\n}\n\n/** Prompt user for yes/no confirmation */\nasync function promptConfirm(message: string, startupShell?: InteractiveStartupShell): Promise<boolean> {\n\tif (startupShell) {\n\t\treturn startupShell.confirm(\"Confirm\", message);\n\t}\n\treturn new Promise((resolve) => {\n\t\tconst rl = createInterface({\n\t\t\tinput: process.stdin,\n\t\t\toutput: process.stdout,\n\t\t});\n\t\trl.question(`${message} [y/N] `, (answer) => {\n\t\t\trl.close();\n\t\t\tresolve(answer.toLowerCase() === \"y\" || answer.toLowerCase() === \"yes\");\n\t\t});\n\t});\n}\n\nfunction validateForkFlags(parsed: Args): void {\n\tif (!parsed.fork) return;\n\n\tconst conflictingFlags = [\n\t\tparsed.session ? \"--session\" : undefined,\n\t\tparsed.continue ? \"--continue\" : undefined,\n\t\tparsed.resume ? \"--resume\" : undefined,\n\t\tparsed.noSession ? \"--no-session\" : undefined,\n\t].filter((flag): flag is string => flag !== undefined);\n\n\tif (conflictingFlags.length > 0) {\n\t\tconsole.error(chalk.red(`Error: --fork cannot be combined with ${conflictingFlags.join(\", \")}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nfunction validateSessionIdFlags(parsed: Args): void {\n\tif (parsed.sessionId === undefined) return;\n\n\tconst conflictingFlags = [\n\t\tparsed.session ? \"--session\" : undefined,\n\t\tparsed.continue ? \"--continue\" : undefined,\n\t\tparsed.resume ? \"--resume\" : undefined,\n\t].filter((flag): flag is string => flag !== undefined);\n\n\tif (conflictingFlags.length > 0) {\n\t\tconsole.error(chalk.red(`Error: --session-id cannot be combined with ${conflictingFlags.join(\", \")}`));\n\t\tprocess.exit(1);\n\t}\n\n\ttry {\n\t\tassertValidSessionId(parsed.sessionId);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nfunction openSessionOrExit(path: string, sessionDir?: string): SessionManager {\n\ttry {\n\t\treturn SessionManager.open(path, sessionDir);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nfunction forkSessionOrExit(sourcePath: string, cwd: string, sessionDir?: string, sessionId?: string): SessionManager {\n\ttry {\n\t\treturn SessionManager.forkFrom(sourcePath, cwd, sessionDir, { id: sessionId });\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nasync function createSessionManager(\n\tparsed: Args,\n\tcwd: string,\n\tsessionDir: string | undefined,\n\tsettingsManager: SettingsManager,\n\tstartupShell?: InteractiveStartupShell,\n): Promise<SessionManager> {\n\tif (parsed.noSession || parsed.help || parsed.listModels !== undefined) {\n\t\treturn SessionManager.inMemory(cwd, parsed.sessionId !== undefined ? { id: parsed.sessionId } : undefined);\n\t}\n\n\tif (parsed.fork) {\n\t\tif (parsed.sessionId) {\n\t\t\tconst existingTarget = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);\n\t\t\tif (existingTarget) {\n\t\t\t\tconsole.error(chalk.red(`Session already exists with id '${parsed.sessionId}'`));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t}\n\n\t\tconst resolved = await resolveSessionPath(parsed.fork, cwd, sessionDir);\n\n\t\tswitch (resolved.type) {\n\t\t\tcase \"path\":\n\t\t\tcase \"local\":\n\t\t\tcase \"global\":\n\t\t\t\treturn forkSessionOrExit(resolved.path, cwd, sessionDir, parsed.sessionId);\n\n\t\t\tcase \"not_found\":\n\t\t\t\tconsole.error(chalk.red(`No session found matching '${resolved.arg}'`));\n\t\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.session) {\n\t\tconst resolved = await resolveSessionPath(parsed.session, cwd, sessionDir);\n\n\t\tswitch (resolved.type) {\n\t\t\tcase \"path\":\n\t\t\tcase \"local\":\n\t\t\t\treturn openSessionOrExit(resolved.path, sessionDir);\n\n\t\t\tcase \"global\": {\n\t\t\t\tconsole.log(chalk.yellow(`Session found in different project: ${resolved.cwd}`));\n\t\t\t\tconst shouldFork = await promptConfirm(\"Fork this session into current directory?\", startupShell);\n\t\t\t\tif (!shouldFork) {\n\t\t\t\t\tconsole.log(chalk.dim(\"Aborted.\"));\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t}\n\t\t\t\treturn forkSessionOrExit(resolved.path, cwd, sessionDir);\n\t\t\t}\n\n\t\t\tcase \"not_found\":\n\t\t\t\tconsole.error(chalk.red(`No session found matching '${resolved.arg}'`));\n\t\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.resume) {\n\t\ttry {\n\t\t\tconst currentSessionsLoader = (onProgress?: Parameters<typeof SessionManager.list>[2]) =>\n\t\t\t\tSessionManager.list(cwd, sessionDir, onProgress);\n\t\t\tconst allSessionsLoader = (onProgress?: Parameters<typeof SessionManager.listAll>[1]) =>\n\t\t\t\tSessionManager.listAll(sessionDir, onProgress);\n\t\t\tconst selectedPath = startupShell\n\t\t\t\t? await startupShell.selectSession(currentSessionsLoader, allSessionsLoader)\n\t\t\t\t: await selectSession(currentSessionsLoader, allSessionsLoader, settingsManager);\n\t\t\tif (!selectedPath) {\n\t\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t\treturn SessionManager.open(selectedPath, sessionDir);\n\t\t} finally {\n\t\t\tstopThemeWatcher();\n\t\t}\n\t}\n\n\tif (parsed.continue) {\n\t\treturn SessionManager.continueRecent(cwd, sessionDir);\n\t}\n\n\tif (parsed.sessionId) {\n\t\tconst existingSession = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);\n\t\tif (existingSession) {\n\t\t\treturn SessionManager.open(existingSession.path, sessionDir);\n\t\t}\n\t\tconsole.error(\n\t\t\tchalk.yellow(\n\t\t\t\t`Warning: No project session found with id '${parsed.sessionId}'; creating a new session with that id.`,\n\t\t\t),\n\t\t);\n\t}\n\n\treturn SessionManager.create(cwd, sessionDir, { id: parsed.sessionId });\n}\n\nfunction buildSessionOptions(\n\tparsed: Args,\n\tscopedModels: ScopedModel[],\n\thasExistingSession: boolean,\n\tmodelRuntime: ModelRuntime,\n\tsettingsManager: SettingsManager,\n): {\n\toptions: CreateAgentSessionOptions;\n\tcliThinkingFromModel: boolean;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n} {\n\tconst options: CreateAgentSessionOptions = {};\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tlet cliThinkingFromModel = false;\n\n\t// Model from CLI\n\t// - supports --provider <name> --model <pattern>\n\t// - supports --model <provider>/<pattern>\n\tif (parsed.model) {\n\t\tconst resolved = resolveCliModel({\n\t\t\tcliProvider: parsed.provider,\n\t\t\tcliModel: parsed.model,\n\t\t\tcliThinking: parsed.thinking,\n\t\t\tmodelRuntime,\n\t\t});\n\t\tif (resolved.warning) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: resolved.warning });\n\t\t}\n\t\tif (resolved.error) {\n\t\t\tdiagnostics.push({ type: \"error\", message: resolved.error });\n\t\t}\n\t\tif (resolved.model) {\n\t\t\toptions.model = resolved.model;\n\t\t\t// Allow \"--model <pattern>:<thinking>\" as a shorthand.\n\t\t\t// Explicit --thinking still takes precedence (applied later).\n\t\t\tif (!parsed.thinking && resolved.thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = resolved.thinkingLevel;\n\t\t\t\tcliThinkingFromModel = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!options.model && scopedModels.length > 0 && !hasExistingSession) {\n\t\t// Check if saved default is in scoped models - use it if so, otherwise first scoped model\n\t\tconst savedProvider = settingsManager.getDefaultProvider();\n\t\tconst savedModelId = settingsManager.getDefaultModel();\n\t\tconst savedModel = savedProvider && savedModelId ? modelRuntime.getModel(savedProvider, savedModelId) : undefined;\n\t\tconst savedInScope = savedModel ? scopedModels.find((sm) => modelsAreEqual(sm.model, savedModel)) : undefined;\n\n\t\tif (savedInScope) {\n\t\t\toptions.model = savedInScope.model;\n\t\t\t// Use thinking level from scoped model config if explicitly set\n\t\t\tif (!parsed.thinking && savedInScope.thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = savedInScope.thinkingLevel;\n\t\t\t}\n\t\t} else {\n\t\t\toptions.model = scopedModels[0].model;\n\t\t\t// Use thinking level from first scoped model if explicitly set\n\t\t\tif (!parsed.thinking && scopedModels[0].thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = scopedModels[0].thinkingLevel;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Thinking level from CLI (takes precedence over scoped model thinking levels set above)\n\tif (parsed.thinking) {\n\t\toptions.thinkingLevel = parsed.thinking;\n\t}\n\n\t// Scoped models for Ctrl+P cycling\n\t// Keep thinking level undefined when not explicitly set in the model pattern.\n\t// Undefined means \"inherit current session thinking level\" during cycling.\n\tif (scopedModels.length > 0) {\n\t\toptions.scopedModels = scopedModels.map((sm) => ({\n\t\t\tmodel: sm.model,\n\t\t\tthinkingLevel: sm.thinkingLevel,\n\t\t}));\n\t}\n\n\t// API key from CLI - set as a non-persistent runtime override\n\t// (handled by caller before createAgentSession)\n\n\t// Tools\n\tif (parsed.noTools) {\n\t\toptions.noTools = \"all\";\n\t} else if (parsed.noBuiltinTools) {\n\t\toptions.noTools = \"builtin\";\n\t}\n\tif (parsed.tools) {\n\t\toptions.tools = [...parsed.tools];\n\t}\n\tif (parsed.excludeTools) {\n\t\toptions.excludeTools = [...parsed.excludeTools];\n\t}\n\n\treturn { options, cliThinkingFromModel, diagnostics };\n}\n\nfunction resolveCliPaths(cwd: string, paths: string[] | undefined): string[] | undefined {\n\treturn paths?.map((value) => (isLocalPath(value) ? resolvePath(value, cwd) : value));\n}\n\nfunction createStartupShellTrustContext(cwd: string, startupShell: InteractiveStartupShell): ProjectTrustContext {\n\treturn {\n\t\tcwd,\n\t\tmode: \"tui\",\n\t\thasUI: true,\n\t\tui: {\n\t\t\tselect: (title, options) =>\n\t\t\t\tstartupShell.select(\n\t\t\t\t\ttitle,\n\t\t\t\t\toptions.map((option) => ({ label: option, value: option })),\n\t\t\t\t),\n\t\t\tconfirm: (title, message) => startupShell.confirm(title, message),\n\t\t\tinput: (title, placeholder) => startupShell.input(title, placeholder),\n\t\t\tnotify: () => {},\n\t\t},\n\t};\n}\n\nasync function promptForMissingSessionCwd(\n\tissue: SessionCwdIssue,\n\tsettingsManager: SettingsManager,\n\tstartupShell?: InteractiveStartupShell,\n): Promise<string | undefined> {\n\tconst options = [\n\t\t{ label: \"Continue\", value: issue.fallbackCwd },\n\t\t{ label: \"Cancel\", value: undefined },\n\t];\n\treturn startupShell\n\t\t? startupShell.select(formatMissingSessionCwdPrompt(issue), options)\n\t\t: showStartupSelector(settingsManager, formatMissingSessionCwdPrompt(issue), options);\n}\n\nexport interface MainOptions {\n\textensionFactories?: InlineExtension[];\n\tstartupShell?: InteractiveStartupShell;\n}\n\nexport async function main(args: string[], options?: MainOptions) {\n\tresetTimings();\n\tconst offlineMode = args.includes(\"--offline\") || isTruthyEnvFlag(process.env.PI_OFFLINE);\n\tif (offlineMode) {\n\t\tprocess.env.PI_OFFLINE = \"1\";\n\t}\n\n\tconst cwd = process.cwd();\n\tconst agentDir = getAgentDir();\n\tconst bootstrapSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted: false });\n\tapplyHttpProxySettings(bootstrapSettingsManager.getGlobalSettings().httpProxy);\n\tconfigureHttpDispatcher();\n\n\tif (await handleInstallCli(args)) {\n\t\treturn;\n\t}\n\n\tif (await handleUpdateCli(args)) {\n\t\treturn;\n\t}\n\n\tif (await handlePackageCommand(args, { extensionFactories: options?.extensionFactories })) {\n\t\tconst exitCode = process.exitCode ?? 0;\n\t\tprocess.exit(exitCode);\n\t\treturn;\n\t}\n\n\tif (await handleConfigCommand(args, { extensionFactories: options?.extensionFactories })) {\n\t\treturn;\n\t}\n\n\tif (args[0] === \"gateway\") {\n\t\tconst { handleGatewayCommand } = await import(\"./gateway/command.ts\");\n\t\tif (await handleGatewayCommand(args)) return;\n\t}\n\n\tconst parsed = parseArgs(args);\n\tif (parsed.diagnostics.length > 0) {\n\t\tfor (const d of parsed.diagnostics) {\n\t\t\tconst color = d.type === \"error\" ? chalk.red : chalk.yellow;\n\t\t\tconsole.error(color(`${d.type === \"error\" ? \"Error\" : \"Warning\"}: ${d.message}`));\n\t\t}\n\t\tif (parsed.diagnostics.some((d) => d.type === \"error\")) {\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\ttime(\"parseArgs\");\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\tprocess.exit(0);\n\t}\n\n\tif (parsed.export) {\n\t\tlet result: string;\n\t\ttry {\n\t\t\tconst { exportFromFile } = await import(\"./core/export-html/index.ts\");\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tresult = await exportFromFile(parsed.export, outputPath);\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tconsole.log(`Exported to: ${result}`);\n\t\tprocess.exit(0);\n\t}\n\n\tlet appMode = resolveAppMode(parsed, process.stdin.isTTY, process.stdout.isTTY);\n\tconst interactiveModeImport =\n\t\tappMode === \"interactive\" ? import(\"./modes/interactive/interactive-mode.ts\") : undefined;\n\tconst startupShell = appMode === \"interactive\" ? options?.startupShell : undefined;\n\tif (options?.startupShell && !startupShell) options.startupShell.stop();\n\t// lunr: parent-delegated children inherit plan or auto before any tool call.\n\t// Non-child print/json stays fail-closed (module default manual, no handler).\n\tapplyInheritedSubagentPermissions();\n\tconst shouldTakeOverStdout = appMode !== \"interactive\" && !isPlainRuntimeMetadataCommand(parsed);\n\tif (shouldTakeOverStdout) {\n\t\ttakeOverStdout();\n\t}\n\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tvalidateForkFlags(parsed);\n\tvalidateSessionIdFlags(parsed);\n\n\t// Run migrations (pass cwd for project-local migrations)\n\tconst { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(cwd);\n\ttime(\"runMigrations\");\n\n\tconst startupSettingsManager = SettingsManager.create(cwd, agentDir);\n\treportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, \"startup session lookup\"));\n\n\t// Register the model-tier bridge before extensions load so pi-subagents can read\n\t// tier settings when building its tool description. Re-pointed to the runtime\n\t// settings manager below once services exist.\n\tregisterModelTierBridge(startupSettingsManager);\n\t// lunr: same for the simple-pi-memory character cap — extensions read it via the\n\t// bridge at load/runtime; re-pointed to the runtime settings manager below.\n\tregisterMemoryCapBridge(startupSettingsManager);\n\t// lunr: TUI customize settings (spinner, dividers, rail, prompt symbol) read by\n\t// ashxj-spinners and ashxj-tui via the bridge; re-pointed to runtime below.\n\tregisterCustomizeBridge(startupSettingsManager);\n\n\t// Experimental first-time setup: theme choice and analytics opt-in.\n\t// Runs before any runtime services are created so the chosen settings apply everywhere.\n\tif (appMode === \"interactive\" && !parsed.help && parsed.listModels === undefined && shouldRunFirstTimeSetup()) {\n\t\tstartupShell?.pause();\n\t\tawait showFirstTimeSetup(startupSettingsManager);\n\t\tstartupShell?.resume();\n\t\ttime(\"firstTimeSetup\");\n\t}\n\n\t// Decide the final runtime cwd before creating cwd-bound runtime services.\n\t// --session and --resume may select a session from another project, so project-local\n\t// settings, resources, provider registrations, and models must be resolved only after\n\t// the target session cwd is known. The startup-cwd settings manager is used only for\n\t// sessionDir lookup during session selection.\n\tconst envSessionDir = process.env[ENV_SESSION_DIR];\n\tconst sessionDir =\n\t\t(parsed.sessionDir ? normalizePath(parsed.sessionDir) : undefined) ??\n\t\t(envSessionDir ? expandTildePath(envSessionDir) : undefined) ??\n\t\tstartupSettingsManager.getSessionDir();\n\tlet sessionManager = await createSessionManager(parsed, cwd, sessionDir, startupSettingsManager, startupShell);\n\tconst missingSessionCwdIssue = getMissingSessionCwdIssue(sessionManager, cwd);\n\tif (missingSessionCwdIssue) {\n\t\tif (appMode === \"interactive\") {\n\t\t\tconst selectedCwd = await promptForMissingSessionCwd(\n\t\t\t\tmissingSessionCwdIssue,\n\t\t\t\tstartupSettingsManager,\n\t\t\t\tstartupShell,\n\t\t\t);\n\t\t\tif (!selectedCwd) {\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t\tsessionManager = SessionManager.open(missingSessionCwdIssue.sessionFile!, sessionDir, selectedCwd);\n\t\t} else {\n\t\t\tconsole.error(chalk.red(new MissingSessionCwdError(missingSessionCwdIssue).message));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\tif (parsed.name !== undefined) {\n\t\tconst name = parsed.name.trim();\n\t\tif (!name) {\n\t\t\tconsole.error(chalk.red(\"Error: --name requires a non-empty value\"));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tsessionManager.appendSessionInfo(name);\n\t}\n\ttime(\"createSessionManager\");\n\n\tconst runSessionRetention = async () => {\n\t\ttry {\n\t\t\tconst retentionDays = startupSettingsManager.getSessionRetentionDays();\n\t\t\tif (retentionDays <= 0) return;\n\t\t\tconst activeSessionFile = sessionManager.getSessionFile();\n\t\t\tconst { deleted } = await pruneOldSessions(getSessionsDir(), retentionDays, {\n\t\t\t\texcludeFile: activeSessionFile,\n\t\t\t});\n\t\t\tif (sessionDir) {\n\t\t\t\tconst extra = await pruneOldSessions(sessionDir, retentionDays, { excludeFile: activeSessionFile });\n\t\t\t\tdeleted.push(...extra.deleted);\n\t\t\t}\n\t\t\tif (deleted.length > 0) {\n\t\t\t\tappendDebugLog(\n\t\t\t\t\t`session-retention: deleted ${deleted.length} file(s):\\n${deleted.map((path) => ` ${path}`).join(\"\\n\")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tappendDebugLog(`session-retention: prune failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t};\n\n\tconst trustStore = new ProjectTrustStore(agentDir);\n\tconst sessionCwd = sessionManager.getCwd();\n\tconst autoTrustOnReloadCwd =\n\t\tparsed.projectTrustOverride === undefined && !hasTrustRequiringProjectResources(sessionCwd)\n\t\t\t? sessionCwd\n\t\t\t: undefined;\n\tconst trustPromptMode: AppMode = parsed.help || parsed.listModels !== undefined ? \"print\" : appMode;\n\tconst projectTrustByCwd = new Map<string, boolean>();\n\n\tconst resolvedExtensionPaths = resolveCliPaths(cwd, parsed.extensions);\n\tconst resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);\n\tconst resolvedPromptTemplatePaths = resolveCliPaths(cwd, parsed.promptTemplates);\n\tconst resolvedThemePaths = resolveCliPaths(cwd, parsed.themes);\n\tconst builtinRoster = appMode === \"interactive\" ? [...lightBuiltinExtensions] : await loadAllBuiltinExtensions();\n\tconst rememberAttachedFactories = (factories: InlineExtension[]) => {\n\t\tconst seen = new Set(\n\t\t\tbuiltinRoster.map((entry) => (typeof entry === \"function\" ? undefined : entry.name)).filter(Boolean),\n\t\t);\n\t\tfor (const factory of factories) {\n\t\t\tconst name = typeof factory === \"function\" ? undefined : factory.name;\n\t\t\tif (name && seen.has(name)) continue;\n\t\t\tif (name) seen.add(name);\n\t\t\tbuiltinRoster.push(factory);\n\t\t}\n\t};\n\tconst createRuntime: CreateAgentSessionRuntimeFactory = async ({\n\t\tcwd,\n\t\tagentDir,\n\t\tsessionManager,\n\t\tsessionStartEvent,\n\t\tprojectTrustContext,\n\t}) => {\n\t\tconst isInitialRuntime = sessionStartEvent === undefined;\n\t\tconst projectTrustDiagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\t\tconst cachedProjectTrust = projectTrustByCwd.get(cwd);\n\t\tconst hasTrustRequiringResources = hasTrustRequiringProjectResources(cwd);\n\t\tconst shouldResolveProjectTrust =\n\t\t\tparsed.projectTrustOverride === undefined && cachedProjectTrust === undefined && hasTrustRequiringResources;\n\t\tconst projectTrusted = shouldResolveProjectTrust\n\t\t\t? false\n\t\t\t: (cachedProjectTrust ??\n\t\t\t\tparsed.projectTrustOverride ??\n\t\t\t\t(!hasTrustRequiringResources || trustStore.get(cwd) === true));\n\t\tconst runtimeSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted });\n\t\tconst skipMissingPackageInstall = isInitialRuntime && appMode === \"interactive\";\n\t\tconst services = await createAgentSessionServices({\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tsettingsManager: runtimeSettingsManager,\n\t\t\textensionFlagValues: parsed.unknownFlags,\n\t\t\tresourceLoaderReloadOptions: shouldResolveProjectTrust\n\t\t\t\t? {\n\t\t\t\t\t\tskipMissingPackageInstall,\n\t\t\t\t\t\tresolveProjectTrust: async ({ extensionsResult }) => {\n\t\t\t\t\t\t\tconst trusted = await resolveProjectTrusted({\n\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\ttrustStore,\n\t\t\t\t\t\t\t\ttrustOverride: parsed.projectTrustOverride,\n\t\t\t\t\t\t\t\tdefaultProjectTrust: startupSettingsManager.getDefaultProjectTrust(),\n\t\t\t\t\t\t\t\textensionsResult,\n\t\t\t\t\t\t\t\tprojectTrustContext:\n\t\t\t\t\t\t\t\t\tprojectTrustContext ??\n\t\t\t\t\t\t\t\t\t(isInitialRuntime && startupShell\n\t\t\t\t\t\t\t\t\t\t? createStartupShellTrustContext(cwd, startupShell)\n\t\t\t\t\t\t\t\t\t\t: createProjectTrustContext({\n\t\t\t\t\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\t\t\t\t\tmode: isInitialRuntime ? trustPromptMode : appMode,\n\t\t\t\t\t\t\t\t\t\t\t\tsettingsManager: startupSettingsManager,\n\t\t\t\t\t\t\t\t\t\t\t\thasUI: isInitialRuntime && trustPromptMode === \"interactive\",\n\t\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\tonExtensionError: (message) => projectTrustDiagnostics.push({ type: \"warning\", message }),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tprojectTrustByCwd.set(cwd, trusted);\n\t\t\t\t\t\t\treturn trusted;\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: skipMissingPackageInstall\n\t\t\t\t\t? { skipMissingPackageInstall }\n\t\t\t\t\t: undefined,\n\t\t\tresourceLoaderOptions: {\n\t\t\t\tadditionalExtensionPaths: resolvedExtensionPaths,\n\t\t\t\tadditionalSkillPaths: resolvedSkillPaths,\n\t\t\t\tadditionalPromptTemplatePaths: resolvedPromptTemplatePaths,\n\t\t\t\tadditionalThemePaths: resolvedThemePaths,\n\t\t\t\tnoExtensions: parsed.noExtensions,\n\t\t\t\tnoSkills: parsed.noSkills,\n\t\t\t\tnoPromptTemplates: parsed.noPromptTemplates,\n\t\t\t\tnoThemes: parsed.noThemes,\n\t\t\t\tnoContextFiles: parsed.noContextFiles,\n\t\t\t\tsystemPrompt: parsed.systemPrompt,\n\t\t\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\t\t\textensionFactories: [...builtinRoster, ...(options?.extensionFactories ?? [])],\n\t\t\t},\n\t\t});\n\t\tconst { settingsManager, modelRuntime, resourceLoader } = services;\n\t\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [\n\t\t\t...projectTrustDiagnostics,\n\t\t\t...services.diagnostics,\n\t\t\t...collectSettingsDiagnostics(settingsManager, \"runtime creation\"),\n\t\t\t...resourceLoader.getExtensions().errors.map(({ path, error }) => ({\n\t\t\t\ttype: \"error\" as const,\n\t\t\t\tmessage: `Failed to load extension \"${path}\": ${error}`,\n\t\t\t})),\n\t\t];\n\n\t\tconst modelPatterns = parsed.models ?? settingsManager.getEnabledModels();\n\t\tconst scopedModels =\n\t\t\tmodelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRuntime) : [];\n\t\tconst {\n\t\t\toptions: sessionOptions,\n\t\t\tcliThinkingFromModel,\n\t\t\tdiagnostics: sessionOptionDiagnostics,\n\t\t} = buildSessionOptions(\n\t\t\tparsed,\n\t\t\tscopedModels,\n\t\t\tsessionManager.buildSessionContext().messages.length > 0,\n\t\t\tmodelRuntime,\n\t\t\tsettingsManager,\n\t\t);\n\t\tdiagnostics.push(...sessionOptionDiagnostics);\n\n\t\tif (parsed.apiKey) {\n\t\t\tif (!sessionOptions.model) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"error\",\n\t\t\t\t\tmessage: \"--api-key requires a model to be specified via --model, --provider/--model, or --models\",\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Cache-only: do not wait on GitHub / provider /v1/models before first paint.\n\t\t\t\tawait modelRuntime.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey, {\n\t\t\t\t\tallowNetwork: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst created = await createAgentSessionFromServices({\n\t\t\tservices,\n\t\t\tsessionManager,\n\t\t\tsessionStartEvent,\n\t\t\tmodel: sessionOptions.model,\n\t\t\tthinkingLevel: sessionOptions.thinkingLevel,\n\t\t\tscopedModels: sessionOptions.scopedModels,\n\t\t\ttools: sessionOptions.tools,\n\t\t\texcludeTools: sessionOptions.excludeTools,\n\t\t\tnoTools: sessionOptions.noTools,\n\t\t\tcustomTools: sessionOptions.customTools,\n\t\t});\n\t\tconst cliThinkingOverride = parsed.thinking !== undefined || cliThinkingFromModel;\n\t\tif (created.session.model && cliThinkingOverride) {\n\t\t\tcreated.session.setThinkingLevel(created.session.thinkingLevel);\n\t\t}\n\n\t\treturn {\n\t\t\t...created,\n\t\t\tservices,\n\t\t\tdiagnostics,\n\t\t};\n\t};\n\ttime(\"createRuntime\");\n\tconst runtime = await createAgentSessionRuntime(createRuntime, {\n\t\tcwd: sessionManager.getCwd(),\n\t\tagentDir,\n\t\tsessionManager,\n\t\tonRuntimeApplied: bindRuntimeBridges,\n\t});\n\tif (startupShell?.isExitRequested) {\n\t\tawait runtime.dispose();\n\t\treturn;\n\t}\n\tmarkStartupMilestone(\"runtime_hydrated\");\n\ttime(\"createAgentSessionRuntime\");\n\tif (appMode !== \"interactive\") await runSessionRetention();\n\tconst { services, session, modelFallbackMessage } = runtime;\n\tconst { settingsManager, modelRuntime, resourceLoader } = services;\n\tapplyHttpProxySettings(settingsManager.getGlobalSettings().httpProxy);\n\tconfigureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs());\n\n\tif (parsed.help) {\n\t\tconst extensionFlags = resourceLoader\n\t\t\t.getExtensions()\n\t\t\t.extensions.flatMap((extension) => Array.from(extension.flags.values()));\n\t\tprintHelp(extensionFlags);\n\t\tprocess.exit(0);\n\t}\n\n\tif (parsed.listModels !== undefined) {\n\t\tconst searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : undefined;\n\t\tawait listModels(modelRuntime, searchPattern);\n\t\tprocess.exit(0);\n\t}\n\n\t// Read piped stdin content (if any) - skip for RPC mode which uses stdin for JSON-RPC.\n\t// Startup benchmark must stay interactive even if a leftover redirected handle has bytes.\n\tlet stdinContent: string | undefined;\n\tconst startupBenchmark = isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK);\n\tif (appMode !== \"rpc\" && !startupBenchmark) {\n\t\tstdinContent = await readPipedStdin();\n\t\tif (stdinContent !== undefined && appMode === \"interactive\") {\n\t\t\tappMode = \"print\";\n\t\t}\n\t}\n\ttime(\"readPipedStdin\");\n\n\tconst { initialMessage, initialImages } = await prepareInitialMessage(\n\t\tparsed,\n\t\tsettingsManager.getImageAutoResize(),\n\t\tstdinContent,\n\t);\n\ttime(\"prepareInitialMessage\");\n\tinitTheme(settingsManager.getTheme(), appMode === \"interactive\");\n\ttime(\"initTheme\");\n\n\tif (appMode === \"interactive\" && !startupShell && deprecationWarnings.length > 0) {\n\t\tawait showDeprecationWarnings(deprecationWarnings);\n\t}\n\n\ttime(\"resolveModelScope\");\n\tif (!(appMode === \"interactive\" && startupShell)) reportDiagnostics(runtime.diagnostics);\n\tif (runtime.diagnostics.some((diagnostic) => diagnostic.type === \"error\")) {\n\t\tconst extensionHint = runtime.diagnostics.some((diagnostic) =>\n\t\t\tdiagnostic.message.includes(\"Failed to load extension\"),\n\t\t)\n\t\t\t? `\\n${EXTENSION_LOAD_FAILURE_HINT}`\n\t\t\t: \"\";\n\t\tif (startupShell) {\n\t\t\tawait startupShell.fail(\n\t\t\t\t`${runtime.diagnostics.map((diagnostic) => diagnostic.message).join(\"\\n\")}${extensionHint}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tif (extensionHint) console.error(chalk.yellow(EXTENSION_LOAD_FAILURE_HINT));\n\t\tprocess.exit(1);\n\t}\n\ttime(\"createAgentSession\");\n\n\tif (appMode !== \"interactive\" && !session.model) {\n\t\tconsole.error(chalk.red(formatNoModelsAvailableMessage()));\n\t\tprocess.exit(1);\n\t}\n\n\tif (startupBenchmark && appMode !== \"interactive\") {\n\t\tconsole.error(chalk.red(\"Error: PI_STARTUP_BENCHMARK only supports interactive mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tif (appMode === \"rpc\") {\n\t\tconst { runRpcMode } = await import(\"./modes/rpc/rpc-mode.ts\");\n\t\tprintTimings();\n\t\tawait runRpcMode(runtime);\n\t} else if (appMode === \"interactive\") {\n\t\tconst [{ InteractiveMode }, { loadDeferredBuiltinExtensionsResult }] = await Promise.all([\n\t\t\tinteractiveModeImport!,\n\t\t\timport(\"./builtin-extensions/index.ts\"),\n\t\t]);\n\t\tconst interactiveMode = new InteractiveMode(runtime, {\n\t\t\tmigratedProviders,\n\t\t\tmodelFallbackMessage,\n\t\t\tautoTrustOnReloadCwd,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\n\t\t\tinitialMessages: parsed.messages,\n\t\t\tverbose: parsed.verbose,\n\t\t\tdeprecationWarnings: startupShell ? deprecationWarnings : undefined,\n\t\t\tstartupDiagnostics: startupShell\n\t\t\t\t? runtime.diagnostics.filter((diagnostic) => diagnostic.type !== \"error\")\n\t\t\t\t: undefined,\n\t\t\tstartupShellBinding: startupShell?.binding(),\n\t\t\tdeferredMaintenance: runSessionRetention,\n\t\t\tdeferredBuiltinFactories: parsed.noExtensions ? undefined : loadDeferredBuiltinExtensionsResult,\n\t\t\tonDeferredBuiltinsAttached: rememberAttachedFactories,\n\t\t});\n\t\tif (startupBenchmark) {\n\t\t\tawait interactiveMode.init();\n\t\t\ttime(\"interactiveMode.init\");\n\t\t\tawait interactiveMode.waitForPromptBarrier();\n\t\t\ttime(\"promptBarrier\");\n\t\t\tinteractiveMode.stop();\n\t\t\tstopThemeWatcher();\n\t\t\tprintTimings();\n\t\t\tif (process.stdout.writableLength > 0) {\n\t\t\t\tawait new Promise<void>((resolve) => process.stdout.once(\"drain\", resolve));\n\t\t\t}\n\t\t\tif (process.stderr.writableLength > 0) {\n\t\t\t\tawait new Promise<void>((resolve) => process.stderr.once(\"drain\", resolve));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tawait interactiveMode.init();\n\t\ttime(\"interactiveMode.init\");\n\t\tprintTimings();\n\t\tawait interactiveMode.run();\n\t} else {\n\t\tconst { runPrintMode } = await import(\"./modes/print-mode.ts\");\n\t\tprintTimings();\n\t\tconst exitCode = await runPrintMode(runtime, {\n\t\t\tmode: toPrintOutputMode(appMode),\n\t\t\tmessages: parsed.messages,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\n\t\t});\n\t\tstopThemeWatcher();\n\t\trestoreStdout();\n\t\tif (exitCode !== 0) {\n\t\t\tprocess.exitCode = exitCode;\n\t\t}\n\t\treturn;\n\t}\n}\n"]}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgCH,OAAO,KAAK,EAAE,eAAe,EAAuB,MAAM,4BAA4B,CAAC;AAyBvF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAa9E;;;GAGG;AACH,wBAAsB,cAAc,CACnC,MAAM,GAAE,MAAM,CAAC,UAA0B,EACzC,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GACtD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA0C7B;AA2aD,MAAM,WAAW,WAAW;IAC3B,kBAAkB,CAAC,EAAE,eAAe,EAAE,CAAC;IACvC,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACvC;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,iBA+e/D","sourcesContent":["/**\n * Main entry point for the coding agent CLI.\n *\n * This file handles CLI argument parsing and translates them into\n * createAgentSession() options. The SDK does the heavy lifting.\n */\n\nimport { createInterface } from \"node:readline\";\nimport { type ImageContent, modelsAreEqual } from \"@ashx-j/lunr-ai\";\nimport chalk from \"chalk\";\nimport { lightBuiltinExtensions, loadAllBuiltinExtensions } from \"./builtin-extensions/index.ts\";\nimport { type Args, type Mode, parseArgs, printHelp } from \"./cli/args.ts\";\nimport { processFileArguments } from \"./cli/file-processor.ts\";\nimport { buildInitialMessage } from \"./cli/initial-message.ts\";\nimport { handleInstallCli } from \"./cli/install-cli.ts\";\nimport { listModels } from \"./cli/list-models.ts\";\nimport { createProjectTrustContext } from \"./cli/project-trust.ts\";\nimport { selectSession } from \"./cli/session-picker.ts\";\nimport { shouldRunFirstTimeSetup, showFirstTimeSetup, showStartupSelector } from \"./cli/startup-ui.ts\";\nimport { handleUpdateCli } from \"./cli/update-cli.ts\";\nimport {\n\tAPP_NAME,\n\tappendDebugLog,\n\tENV_SESSION_DIR,\n\texpandTildePath,\n\tgetAgentDir,\n\tgetSessionsDir,\n\tVERSION,\n} from \"./config.ts\";\nimport { type CreateAgentSessionRuntimeFactory, createAgentSessionRuntime } from \"./core/agent-session-runtime.ts\";\nimport {\n\ttype AgentSessionRuntimeDiagnostic,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./core/agent-session-services.ts\";\nimport { formatNoModelsAvailableMessage } from \"./core/auth-guidance.ts\";\nimport { registerCustomizeBridge } from \"./core/customize.ts\";\nimport type { InlineExtension, ProjectTrustContext } from \"./core/extensions/types.ts\";\nimport { applyHttpProxySettings, configureHttpDispatcher } from \"./core/http-dispatcher.ts\";\nimport { registerMemoryCapBridge } from \"./core/memory-cap.ts\";\nimport { resolveCliModel, resolveModelScope, type ScopedModel } from \"./core/model-resolver.ts\";\nimport type { ModelRuntime } from \"./core/model-runtime.ts\";\nimport { registerModelTierBridge } from \"./core/model-tiers.ts\";\nimport { restoreStdout, takeOverStdout } from \"./core/output-guard.ts\";\nimport { type AppMode, resolveProjectTrusted } from \"./core/project-trust.ts\";\nimport { bindRuntimeBridges } from \"./core/runtime-bridges.ts\";\nimport type { CreateAgentSessionOptions } from \"./core/sdk.ts\";\nimport {\n\tformatMissingSessionCwdPrompt,\n\tgetMissingSessionCwdIssue,\n\tMissingSessionCwdError,\n\ttype SessionCwdIssue,\n} from \"./core/session-cwd.ts\";\nimport { assertValidSessionId, SessionManager } from \"./core/session-manager.ts\";\nimport { pruneOldSessions } from \"./core/session-retention.ts\";\nimport { SettingsManager } from \"./core/settings-manager.ts\";\nimport { applyInheritedSubagentPermissions } from \"./core/subagent-permission-inherit.ts\";\nimport { printTimings, resetTimings, time } from \"./core/timings.ts\";\nimport { hasTrustRequiringProjectResources, ProjectTrustStore } from \"./core/trust-manager.ts\";\nimport { runMigrations, showDeprecationWarnings } from \"./migrations.ts\";\nimport { initTheme, stopThemeWatcher } from \"./modes/interactive/theme/theme.ts\";\nimport { handleConfigCommand, handlePackageCommand } from \"./package-manager-cli.ts\";\nimport type { InteractiveStartupShell } from \"./startup/interactive-shell.ts\";\nimport { markStartupMilestone } from \"./startup/startup-milestones.ts\";\nimport { isLocalPath, normalizePath, resolvePath } from \"./utils/paths.ts\";\n\nconst EXTENSION_LOAD_FAILURE_HINT = `Hint: Start without extensions using \"${APP_NAME} -ne\".`;\n\n/**\n * Read all content from piped stdin.\n * Returns undefined if stdin is a TTY (interactive terminal).\n */\nconst PIPED_STDIN_FIRST_CHUNK_MS = 50;\nconst PIPED_STDIN_IDLE_MS = 2000;\n\n/**\n * Read piped stdin. A non-TTY that never emits data (Windows console, leftover\n * redirected handle) must not block interactive start forever.\n */\nexport async function readPipedStdin(\n\tstream: NodeJS.ReadStream = process.stdin,\n\toptions: { firstChunkMs?: number; idleMs?: number } = {},\n): Promise<string | undefined> {\n\tif (stream.isTTY) {\n\t\treturn undefined;\n\t}\n\n\tconst firstChunkMs = options.firstChunkMs ?? PIPED_STDIN_FIRST_CHUNK_MS;\n\tconst idleMs = options.idleMs ?? PIPED_STDIN_IDLE_MS;\n\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tlet settled = false;\n\t\tlet sawData = false;\n\t\tlet idleTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst firstChunkTimer = setTimeout(() => {\n\t\t\tif (!sawData) finish(undefined);\n\t\t}, firstChunkMs);\n\n\t\tconst finish = (value: string | undefined) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(firstChunkTimer);\n\t\t\tif (idleTimer) clearTimeout(idleTimer);\n\t\t\tstream.off(\"data\", onData);\n\t\t\tstream.off(\"end\", onEnd);\n\t\t\tstream.off(\"error\", onEnd);\n\t\t\tresolve(value);\n\t\t};\n\n\t\tconst onEnd = () => finish(data.trim() || undefined);\n\t\tconst onData = (chunk: string | Buffer) => {\n\t\t\tsawData = true;\n\t\t\tdata += typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\n\t\t\tif (idleTimer) clearTimeout(idleTimer);\n\t\t\tidleTimer = setTimeout(onEnd, idleMs);\n\t\t};\n\n\t\tstream.setEncoding(\"utf8\");\n\t\tstream.on(\"data\", onData);\n\t\tstream.on(\"end\", onEnd);\n\t\tstream.on(\"error\", onEnd);\n\t\tstream.resume();\n\t});\n}\n\nfunction collectSettingsDiagnostics(\n\tsettingsManager: SettingsManager,\n\tcontext: string,\n): AgentSessionRuntimeDiagnostic[] {\n\treturn settingsManager.drainErrors().map(({ scope, error }) => ({\n\t\ttype: \"warning\",\n\t\tmessage: `(${context}, ${scope} settings) ${error.message}`,\n\t}));\n}\n\nfunction reportDiagnostics(diagnostics: readonly AgentSessionRuntimeDiagnostic[]): void {\n\tfor (const diagnostic of diagnostics) {\n\t\tconst color = diagnostic.type === \"error\" ? chalk.red : diagnostic.type === \"warning\" ? chalk.yellow : chalk.dim;\n\t\tconst prefix = diagnostic.type === \"error\" ? \"Error: \" : diagnostic.type === \"warning\" ? \"Warning: \" : \"\";\n\t\tconsole.error(color(`${prefix}${diagnostic.message}`));\n\t}\n}\n\nfunction isTruthyEnvFlag(value: string | undefined): boolean {\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\n\nfunction resolveAppMode(parsed: Args, stdinIsTTY: boolean, stdoutIsTTY: boolean): AppMode {\n\tif (parsed.mode === \"rpc\") {\n\t\treturn \"rpc\";\n\t}\n\tif (parsed.mode === \"json\") {\n\t\treturn \"json\";\n\t}\n\t// PI_STARTUP_BENCHMARK=1 times interactive first paint even when stdin/stdout\n\t// are not TTYs (repo npx, CI, redirected logs).\n\tif (isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK) && !parsed.print) {\n\t\treturn \"interactive\";\n\t}\n\tif (parsed.print || !stdinIsTTY || !stdoutIsTTY) {\n\t\treturn \"print\";\n\t}\n\treturn \"interactive\";\n}\n\nfunction toPrintOutputMode(appMode: AppMode): Exclude<Mode, \"rpc\"> {\n\treturn appMode === \"json\" ? \"json\" : \"text\";\n}\n\nfunction isPlainRuntimeMetadataCommand(parsed: Args): boolean {\n\treturn !parsed.print && parsed.mode === undefined && (parsed.help === true || parsed.listModels !== undefined);\n}\n\nasync function prepareInitialMessage(\n\tparsed: Args,\n\tautoResizeImages: boolean,\n\tstdinContent?: string,\n): Promise<{\n\tinitialMessage?: string;\n\tinitialImages?: ImageContent[];\n}> {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn buildInitialMessage({ parsed, stdinContent });\n\t}\n\n\tconst { text, images } = await processFileArguments(parsed.fileArgs, { autoResizeImages });\n\treturn buildInitialMessage({\n\t\tparsed,\n\t\tfileText: text,\n\t\tfileImages: images,\n\t\tstdinContent,\n\t});\n}\n\n/** Result from resolving a session argument */\ntype ResolvedSession =\n\t| { type: \"path\"; path: string } // Direct file path\n\t| { type: \"local\"; path: string } // Found in current project\n\t| { type: \"global\"; path: string; cwd: string } // Found in different project\n\t| { type: \"not_found\"; arg: string }; // Not found anywhere\n\n/**\n * Resolve a session argument to a file path.\n * If it looks like a path, use as-is. Otherwise try to match as session ID prefix.\n */\nasync function findLocalSessionByExactId(\n\tsessionId: string,\n\tcwd: string,\n\tsessionDir?: string,\n): Promise<{ type: \"local\"; path: string } | undefined> {\n\tconst localSessions = await SessionManager.list(cwd, sessionDir);\n\tconst localMatch = localSessions.find((s) => s.id === sessionId);\n\treturn localMatch ? { type: \"local\", path: localMatch.path } : undefined;\n}\n\nasync function resolveSessionPath(sessionArg: string, cwd: string, sessionDir?: string): Promise<ResolvedSession> {\n\t// If it looks like a file path, resolve it before handing it to the session manager.\n\tif (sessionArg.includes(\"/\") || sessionArg.includes(\"\\\\\") || sessionArg.endsWith(\".jsonl\")) {\n\t\treturn { type: \"path\", path: resolvePath(sessionArg, cwd) };\n\t}\n\n\t// Try to match as session ID in current project first\n\tconst localSessions = await SessionManager.list(cwd, sessionDir);\n\tconst localMatch =\n\t\tlocalSessions.find((s) => s.id === sessionArg) ?? localSessions.find((s) => s.id.startsWith(sessionArg));\n\n\tif (localMatch) {\n\t\treturn { type: \"local\", path: localMatch.path };\n\t}\n\n\t// Try global search across all projects\n\tconst allSessions = await SessionManager.listAll(sessionDir);\n\tconst globalMatch =\n\t\tallSessions.find((s) => s.id === sessionArg) ?? allSessions.find((s) => s.id.startsWith(sessionArg));\n\n\tif (globalMatch) {\n\t\treturn { type: \"global\", path: globalMatch.path, cwd: globalMatch.cwd };\n\t}\n\n\t// Not found anywhere\n\treturn { type: \"not_found\", arg: sessionArg };\n}\n\n/** Prompt user for yes/no confirmation */\nasync function promptConfirm(message: string, startupShell?: InteractiveStartupShell): Promise<boolean> {\n\tif (startupShell) {\n\t\treturn startupShell.confirm(\"Confirm\", message);\n\t}\n\treturn new Promise((resolve) => {\n\t\tconst rl = createInterface({\n\t\t\tinput: process.stdin,\n\t\t\toutput: process.stdout,\n\t\t});\n\t\trl.question(`${message} [y/N] `, (answer) => {\n\t\t\trl.close();\n\t\t\tresolve(answer.toLowerCase() === \"y\" || answer.toLowerCase() === \"yes\");\n\t\t});\n\t});\n}\n\nfunction validateForkFlags(parsed: Args): void {\n\tif (!parsed.fork) return;\n\n\tconst conflictingFlags = [\n\t\tparsed.session ? \"--session\" : undefined,\n\t\tparsed.continue ? \"--continue\" : undefined,\n\t\tparsed.resume ? \"--resume\" : undefined,\n\t\tparsed.noSession ? \"--no-session\" : undefined,\n\t].filter((flag): flag is string => flag !== undefined);\n\n\tif (conflictingFlags.length > 0) {\n\t\tconsole.error(chalk.red(`Error: --fork cannot be combined with ${conflictingFlags.join(\", \")}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nfunction validateSessionIdFlags(parsed: Args): void {\n\tif (parsed.sessionId === undefined) return;\n\n\tconst conflictingFlags = [\n\t\tparsed.session ? \"--session\" : undefined,\n\t\tparsed.continue ? \"--continue\" : undefined,\n\t\tparsed.resume ? \"--resume\" : undefined,\n\t].filter((flag): flag is string => flag !== undefined);\n\n\tif (conflictingFlags.length > 0) {\n\t\tconsole.error(chalk.red(`Error: --session-id cannot be combined with ${conflictingFlags.join(\", \")}`));\n\t\tprocess.exit(1);\n\t}\n\n\ttry {\n\t\tassertValidSessionId(parsed.sessionId);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nfunction openSessionOrExit(path: string, sessionDir?: string): SessionManager {\n\ttry {\n\t\treturn SessionManager.open(path, sessionDir);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nfunction forkSessionOrExit(sourcePath: string, cwd: string, sessionDir?: string, sessionId?: string): SessionManager {\n\ttry {\n\t\treturn SessionManager.forkFrom(sourcePath, cwd, sessionDir, { id: sessionId });\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nasync function createSessionManager(\n\tparsed: Args,\n\tcwd: string,\n\tsessionDir: string | undefined,\n\tsettingsManager: SettingsManager,\n\tstartupShell?: InteractiveStartupShell,\n): Promise<SessionManager> {\n\tif (parsed.noSession || parsed.help || parsed.listModels !== undefined) {\n\t\treturn SessionManager.inMemory(cwd, parsed.sessionId !== undefined ? { id: parsed.sessionId } : undefined);\n\t}\n\n\tif (parsed.fork) {\n\t\tif (parsed.sessionId) {\n\t\t\tconst existingTarget = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);\n\t\t\tif (existingTarget) {\n\t\t\t\tconsole.error(chalk.red(`Session already exists with id '${parsed.sessionId}'`));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t}\n\n\t\tconst resolved = await resolveSessionPath(parsed.fork, cwd, sessionDir);\n\n\t\tswitch (resolved.type) {\n\t\t\tcase \"path\":\n\t\t\tcase \"local\":\n\t\t\tcase \"global\":\n\t\t\t\treturn forkSessionOrExit(resolved.path, cwd, sessionDir, parsed.sessionId);\n\n\t\t\tcase \"not_found\":\n\t\t\t\tconsole.error(chalk.red(`No session found matching '${resolved.arg}'`));\n\t\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.session) {\n\t\tconst resolved = await resolveSessionPath(parsed.session, cwd, sessionDir);\n\n\t\tswitch (resolved.type) {\n\t\t\tcase \"path\":\n\t\t\tcase \"local\":\n\t\t\t\treturn openSessionOrExit(resolved.path, sessionDir);\n\n\t\t\tcase \"global\": {\n\t\t\t\tconsole.log(chalk.yellow(`Session found in different project: ${resolved.cwd}`));\n\t\t\t\tconst shouldFork = await promptConfirm(\"Fork this session into current directory?\", startupShell);\n\t\t\t\tif (!shouldFork) {\n\t\t\t\t\tconsole.log(chalk.dim(\"Aborted.\"));\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t}\n\t\t\t\treturn forkSessionOrExit(resolved.path, cwd, sessionDir);\n\t\t\t}\n\n\t\t\tcase \"not_found\":\n\t\t\t\tconsole.error(chalk.red(`No session found matching '${resolved.arg}'`));\n\t\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.resume) {\n\t\ttry {\n\t\t\tconst currentSessionsLoader = (onProgress?: Parameters<typeof SessionManager.list>[2]) =>\n\t\t\t\tSessionManager.list(cwd, sessionDir, onProgress);\n\t\t\tconst allSessionsLoader = (onProgress?: Parameters<typeof SessionManager.listAll>[1]) =>\n\t\t\t\tSessionManager.listAll(sessionDir, onProgress);\n\t\t\tconst selectedPath = startupShell\n\t\t\t\t? await startupShell.selectSession(currentSessionsLoader, allSessionsLoader)\n\t\t\t\t: await selectSession(currentSessionsLoader, allSessionsLoader, settingsManager);\n\t\t\tif (!selectedPath) {\n\t\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t\treturn SessionManager.open(selectedPath, sessionDir);\n\t\t} finally {\n\t\t\tstopThemeWatcher();\n\t\t}\n\t}\n\n\tif (parsed.continue) {\n\t\treturn SessionManager.continueRecent(cwd, sessionDir);\n\t}\n\n\tif (parsed.sessionId) {\n\t\tconst existingSession = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);\n\t\tif (existingSession) {\n\t\t\treturn SessionManager.open(existingSession.path, sessionDir);\n\t\t}\n\t\tconsole.error(\n\t\t\tchalk.yellow(\n\t\t\t\t`Warning: No project session found with id '${parsed.sessionId}'; creating a new session with that id.`,\n\t\t\t),\n\t\t);\n\t}\n\n\treturn SessionManager.create(cwd, sessionDir, { id: parsed.sessionId });\n}\n\nfunction buildSessionOptions(\n\tparsed: Args,\n\tscopedModels: ScopedModel[],\n\thasExistingSession: boolean,\n\tmodelRuntime: ModelRuntime,\n\tsettingsManager: SettingsManager,\n): {\n\toptions: CreateAgentSessionOptions;\n\tcliThinkingFromModel: boolean;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n} {\n\tconst options: CreateAgentSessionOptions = {};\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tlet cliThinkingFromModel = false;\n\n\t// Model from CLI\n\t// - supports --provider <name> --model <pattern>\n\t// - supports --model <provider>/<pattern>\n\tif (parsed.model) {\n\t\tconst resolved = resolveCliModel({\n\t\t\tcliProvider: parsed.provider,\n\t\t\tcliModel: parsed.model,\n\t\t\tcliThinking: parsed.thinking,\n\t\t\tmodelRuntime,\n\t\t});\n\t\tif (resolved.warning) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: resolved.warning });\n\t\t}\n\t\tif (resolved.error) {\n\t\t\tdiagnostics.push({ type: \"error\", message: resolved.error });\n\t\t}\n\t\tif (resolved.model) {\n\t\t\toptions.model = resolved.model;\n\t\t\t// Allow \"--model <pattern>:<thinking>\" as a shorthand.\n\t\t\t// Explicit --thinking still takes precedence (applied later).\n\t\t\tif (!parsed.thinking && resolved.thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = resolved.thinkingLevel;\n\t\t\t\tcliThinkingFromModel = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!options.model && scopedModels.length > 0 && !hasExistingSession) {\n\t\t// Check if saved default is in scoped models - use it if so, otherwise first scoped model\n\t\tconst savedProvider = settingsManager.getDefaultProvider();\n\t\tconst savedModelId = settingsManager.getDefaultModel();\n\t\tconst savedModel = savedProvider && savedModelId ? modelRuntime.getModel(savedProvider, savedModelId) : undefined;\n\t\tconst savedInScope = savedModel ? scopedModels.find((sm) => modelsAreEqual(sm.model, savedModel)) : undefined;\n\n\t\tif (savedInScope) {\n\t\t\toptions.model = savedInScope.model;\n\t\t\t// Use thinking level from scoped model config if explicitly set\n\t\t\tif (!parsed.thinking && savedInScope.thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = savedInScope.thinkingLevel;\n\t\t\t}\n\t\t} else {\n\t\t\toptions.model = scopedModels[0].model;\n\t\t\t// Use thinking level from first scoped model if explicitly set\n\t\t\tif (!parsed.thinking && scopedModels[0].thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = scopedModels[0].thinkingLevel;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Thinking level from CLI (takes precedence over scoped model thinking levels set above)\n\tif (parsed.thinking) {\n\t\toptions.thinkingLevel = parsed.thinking;\n\t}\n\n\t// Scoped models for Ctrl+P cycling\n\t// Keep thinking level undefined when not explicitly set in the model pattern.\n\t// Undefined means \"inherit current session thinking level\" during cycling.\n\tif (scopedModels.length > 0) {\n\t\toptions.scopedModels = scopedModels.map((sm) => ({\n\t\t\tmodel: sm.model,\n\t\t\tthinkingLevel: sm.thinkingLevel,\n\t\t}));\n\t}\n\n\t// API key from CLI - set as a non-persistent runtime override\n\t// (handled by caller before createAgentSession)\n\n\t// Tools\n\tif (parsed.noTools) {\n\t\toptions.noTools = \"all\";\n\t} else if (parsed.noBuiltinTools) {\n\t\toptions.noTools = \"builtin\";\n\t}\n\tif (parsed.tools) {\n\t\toptions.tools = [...parsed.tools];\n\t}\n\tif (parsed.excludeTools) {\n\t\toptions.excludeTools = [...parsed.excludeTools];\n\t}\n\n\treturn { options, cliThinkingFromModel, diagnostics };\n}\n\nfunction resolveCliPaths(cwd: string, paths: string[] | undefined): string[] | undefined {\n\treturn paths?.map((value) => (isLocalPath(value) ? resolvePath(value, cwd) : value));\n}\n\nfunction createStartupShellTrustContext(cwd: string, startupShell: InteractiveStartupShell): ProjectTrustContext {\n\treturn {\n\t\tcwd,\n\t\tmode: \"tui\",\n\t\thasUI: true,\n\t\tui: {\n\t\t\tselect: (title, options) =>\n\t\t\t\tstartupShell.select(\n\t\t\t\t\ttitle,\n\t\t\t\t\toptions.map((option) => ({ label: option, value: option })),\n\t\t\t\t),\n\t\t\tconfirm: (title, message) => startupShell.confirm(title, message),\n\t\t\tinput: (title, placeholder) => startupShell.input(title, placeholder),\n\t\t\tnotify: () => {},\n\t\t},\n\t};\n}\n\nasync function promptForMissingSessionCwd(\n\tissue: SessionCwdIssue,\n\tsettingsManager: SettingsManager,\n\tstartupShell?: InteractiveStartupShell,\n): Promise<string | undefined> {\n\tconst options = [\n\t\t{ label: \"Continue\", value: issue.fallbackCwd },\n\t\t{ label: \"Cancel\", value: undefined },\n\t];\n\treturn startupShell\n\t\t? startupShell.select(formatMissingSessionCwdPrompt(issue), options)\n\t\t: showStartupSelector(settingsManager, formatMissingSessionCwdPrompt(issue), options);\n}\n\nexport interface MainOptions {\n\textensionFactories?: InlineExtension[];\n\tstartupShell?: InteractiveStartupShell;\n}\n\nexport async function main(args: string[], options?: MainOptions) {\n\tresetTimings();\n\tconst offlineMode = args.includes(\"--offline\") || isTruthyEnvFlag(process.env.PI_OFFLINE);\n\tif (offlineMode) {\n\t\tprocess.env.PI_OFFLINE = \"1\";\n\t}\n\n\tconst cwd = process.cwd();\n\tconst agentDir = getAgentDir();\n\tconst bootstrapSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted: false });\n\tapplyHttpProxySettings(bootstrapSettingsManager.getGlobalSettings().httpProxy);\n\tconfigureHttpDispatcher();\n\n\tif (await handleInstallCli(args)) {\n\t\treturn;\n\t}\n\n\tif (await handleUpdateCli(args)) {\n\t\treturn;\n\t}\n\n\tif (await handlePackageCommand(args, { extensionFactories: options?.extensionFactories })) {\n\t\tconst exitCode = process.exitCode ?? 0;\n\t\tprocess.exit(exitCode);\n\t\treturn;\n\t}\n\n\tif (await handleConfigCommand(args, { extensionFactories: options?.extensionFactories })) {\n\t\treturn;\n\t}\n\n\tif (args[0] === \"gateway\") {\n\t\tconst { handleGatewayCommand } = await import(\"./gateway/command.ts\");\n\t\tif (await handleGatewayCommand(args)) return;\n\t}\n\n\tconst parsed = parseArgs(args);\n\tif (parsed.diagnostics.length > 0) {\n\t\tfor (const d of parsed.diagnostics) {\n\t\t\tconst color = d.type === \"error\" ? chalk.red : chalk.yellow;\n\t\t\tconsole.error(color(`${d.type === \"error\" ? \"Error\" : \"Warning\"}: ${d.message}`));\n\t\t}\n\t\tif (parsed.diagnostics.some((d) => d.type === \"error\")) {\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\ttime(\"parseArgs\");\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\tprocess.exit(0);\n\t}\n\n\tif (parsed.export) {\n\t\tlet result: string;\n\t\ttry {\n\t\t\tconst { exportFromFile } = await import(\"./core/export-html/index.ts\");\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tresult = await exportFromFile(parsed.export, outputPath);\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tconsole.log(`Exported to: ${result}`);\n\t\tprocess.exit(0);\n\t}\n\n\tlet appMode = resolveAppMode(parsed, process.stdin.isTTY, process.stdout.isTTY);\n\tconst interactiveModeImport =\n\t\tappMode === \"interactive\" ? import(\"./modes/interactive/interactive-mode.ts\") : undefined;\n\tconst startupShell = appMode === \"interactive\" ? options?.startupShell : undefined;\n\tif (options?.startupShell && !startupShell) options.startupShell.stop();\n\t// lunr: parent-delegated children inherit plan or auto before any tool call.\n\t// Non-child print/json stays fail-closed (module default manual, no handler).\n\tapplyInheritedSubagentPermissions();\n\tconst shouldTakeOverStdout = appMode !== \"interactive\" && !isPlainRuntimeMetadataCommand(parsed);\n\tif (shouldTakeOverStdout) {\n\t\ttakeOverStdout();\n\t}\n\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tvalidateForkFlags(parsed);\n\tvalidateSessionIdFlags(parsed);\n\n\t// Run migrations (pass cwd for project-local migrations)\n\tconst { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(cwd);\n\ttime(\"runMigrations\");\n\n\tconst startupSettingsManager = SettingsManager.create(cwd, agentDir);\n\treportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, \"startup session lookup\"));\n\n\t// Register the model-tier bridge before extensions load so pi-subagents can read\n\t// tier settings when building its tool description. Re-pointed to the runtime\n\t// settings manager below once services exist.\n\tregisterModelTierBridge(startupSettingsManager);\n\t// lunr: same for the simple-pi-memory character cap — extensions read it via the\n\t// bridge at load/runtime; re-pointed to the runtime settings manager below.\n\tregisterMemoryCapBridge(startupSettingsManager);\n\t// lunr: TUI customize settings (spinner, dividers, rail, prompt symbol) read by\n\t// ashxj-spinners and ashxj-tui via the bridge; re-pointed to runtime below.\n\tregisterCustomizeBridge(startupSettingsManager);\n\n\t// Experimental first-time setup: theme choice and analytics opt-in.\n\t// Runs before any runtime services are created so the chosen settings apply everywhere.\n\tif (appMode === \"interactive\" && !parsed.help && parsed.listModels === undefined && shouldRunFirstTimeSetup()) {\n\t\tstartupShell?.pause();\n\t\tawait showFirstTimeSetup(startupSettingsManager);\n\t\tstartupShell?.resume();\n\t\ttime(\"firstTimeSetup\");\n\t}\n\n\t// Decide the final runtime cwd before creating cwd-bound runtime services.\n\t// --session and --resume may select a session from another project, so project-local\n\t// settings, resources, provider registrations, and models must be resolved only after\n\t// the target session cwd is known. The startup-cwd settings manager is used only for\n\t// sessionDir lookup during session selection.\n\tconst envSessionDir = process.env[ENV_SESSION_DIR];\n\tconst sessionDir =\n\t\t(parsed.sessionDir ? normalizePath(parsed.sessionDir) : undefined) ??\n\t\t(envSessionDir ? expandTildePath(envSessionDir) : undefined) ??\n\t\tstartupSettingsManager.getSessionDir();\n\tlet sessionManager = await createSessionManager(parsed, cwd, sessionDir, startupSettingsManager, startupShell);\n\tconst missingSessionCwdIssue = getMissingSessionCwdIssue(sessionManager, cwd);\n\tif (missingSessionCwdIssue) {\n\t\tif (appMode === \"interactive\") {\n\t\t\tconst selectedCwd = await promptForMissingSessionCwd(\n\t\t\t\tmissingSessionCwdIssue,\n\t\t\t\tstartupSettingsManager,\n\t\t\t\tstartupShell,\n\t\t\t);\n\t\t\tif (!selectedCwd) {\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t\tsessionManager = SessionManager.open(missingSessionCwdIssue.sessionFile!, sessionDir, selectedCwd);\n\t\t} else {\n\t\t\tconsole.error(chalk.red(new MissingSessionCwdError(missingSessionCwdIssue).message));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\tif (parsed.name !== undefined) {\n\t\tconst name = parsed.name.trim();\n\t\tif (!name) {\n\t\t\tconsole.error(chalk.red(\"Error: --name requires a non-empty value\"));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tsessionManager.appendSessionInfo(name);\n\t}\n\ttime(\"createSessionManager\");\n\n\tconst runSessionRetention = async () => {\n\t\ttry {\n\t\t\tconst retentionDays = startupSettingsManager.getSessionRetentionDays();\n\t\t\tif (retentionDays <= 0) return;\n\t\t\tconst activeSessionFile = sessionManager.getSessionFile();\n\t\t\tconst { deleted } = await pruneOldSessions(getSessionsDir(), retentionDays, {\n\t\t\t\texcludeFile: activeSessionFile,\n\t\t\t});\n\t\t\tif (sessionDir) {\n\t\t\t\tconst extra = await pruneOldSessions(sessionDir, retentionDays, { excludeFile: activeSessionFile });\n\t\t\t\tdeleted.push(...extra.deleted);\n\t\t\t}\n\t\t\tif (deleted.length > 0) {\n\t\t\t\tappendDebugLog(\n\t\t\t\t\t`session-retention: deleted ${deleted.length} file(s):\\n${deleted.map((path) => ` ${path}`).join(\"\\n\")}`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tappendDebugLog(`session-retention: prune failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t};\n\n\tconst trustStore = new ProjectTrustStore(agentDir);\n\tconst sessionCwd = sessionManager.getCwd();\n\tconst autoTrustOnReloadCwd =\n\t\tparsed.projectTrustOverride === undefined && !hasTrustRequiringProjectResources(sessionCwd)\n\t\t\t? sessionCwd\n\t\t\t: undefined;\n\tconst trustPromptMode: AppMode = parsed.help || parsed.listModels !== undefined ? \"print\" : appMode;\n\tconst projectTrustByCwd = new Map<string, boolean>();\n\n\tconst resolvedExtensionPaths = resolveCliPaths(cwd, parsed.extensions);\n\tconst resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);\n\tconst resolvedPromptTemplatePaths = resolveCliPaths(cwd, parsed.promptTemplates);\n\tconst resolvedThemePaths = resolveCliPaths(cwd, parsed.themes);\n\tconst builtinRoster = appMode === \"interactive\" ? [...lightBuiltinExtensions] : await loadAllBuiltinExtensions();\n\tconst rememberAttachedFactories = (factories: InlineExtension[]) => {\n\t\tconst seen = new Set(\n\t\t\tbuiltinRoster.map((entry) => (typeof entry === \"function\" ? undefined : entry.name)).filter(Boolean),\n\t\t);\n\t\tfor (const factory of factories) {\n\t\t\tconst name = typeof factory === \"function\" ? undefined : factory.name;\n\t\t\tif (name && seen.has(name)) continue;\n\t\t\tif (name) seen.add(name);\n\t\t\tbuiltinRoster.push(factory);\n\t\t}\n\t};\n\tconst createRuntime: CreateAgentSessionRuntimeFactory = async ({\n\t\tcwd,\n\t\tagentDir,\n\t\tsessionManager,\n\t\tsessionStartEvent,\n\t\tprojectTrustContext,\n\t}) => {\n\t\tconst isInitialRuntime = sessionStartEvent === undefined;\n\t\tconst projectTrustDiagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\t\tconst cachedProjectTrust = projectTrustByCwd.get(cwd);\n\t\tconst hasTrustRequiringResources = hasTrustRequiringProjectResources(cwd);\n\t\tconst shouldResolveProjectTrust =\n\t\t\tparsed.projectTrustOverride === undefined && cachedProjectTrust === undefined && hasTrustRequiringResources;\n\t\tconst projectTrusted = shouldResolveProjectTrust\n\t\t\t? false\n\t\t\t: (cachedProjectTrust ??\n\t\t\t\tparsed.projectTrustOverride ??\n\t\t\t\t(!hasTrustRequiringResources || trustStore.get(cwd) === true));\n\t\tconst runtimeSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted });\n\t\tconst skipMissingPackageInstall = isInitialRuntime && appMode === \"interactive\";\n\t\tconst services = await createAgentSessionServices({\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tsettingsManager: runtimeSettingsManager,\n\t\t\textensionFlagValues: parsed.unknownFlags,\n\t\t\tresourceLoaderReloadOptions: shouldResolveProjectTrust\n\t\t\t\t? {\n\t\t\t\t\t\tskipMissingPackageInstall,\n\t\t\t\t\t\tresolveProjectTrust: async ({ extensionsResult }) => {\n\t\t\t\t\t\t\tconst trusted = await resolveProjectTrusted({\n\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\ttrustStore,\n\t\t\t\t\t\t\t\ttrustOverride: parsed.projectTrustOverride,\n\t\t\t\t\t\t\t\tdefaultProjectTrust: startupSettingsManager.getDefaultProjectTrust(),\n\t\t\t\t\t\t\t\textensionsResult,\n\t\t\t\t\t\t\t\tprojectTrustContext:\n\t\t\t\t\t\t\t\t\tprojectTrustContext ??\n\t\t\t\t\t\t\t\t\t(isInitialRuntime && startupShell\n\t\t\t\t\t\t\t\t\t\t? createStartupShellTrustContext(cwd, startupShell)\n\t\t\t\t\t\t\t\t\t\t: createProjectTrustContext({\n\t\t\t\t\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\t\t\t\t\tmode: isInitialRuntime ? trustPromptMode : appMode,\n\t\t\t\t\t\t\t\t\t\t\t\tsettingsManager: startupSettingsManager,\n\t\t\t\t\t\t\t\t\t\t\t\thasUI: isInitialRuntime && trustPromptMode === \"interactive\",\n\t\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\tonExtensionError: (message) => projectTrustDiagnostics.push({ type: \"warning\", message }),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tprojectTrustByCwd.set(cwd, trusted);\n\t\t\t\t\t\t\treturn trusted;\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: skipMissingPackageInstall\n\t\t\t\t\t? { skipMissingPackageInstall }\n\t\t\t\t\t: undefined,\n\t\t\tresourceLoaderOptions: {\n\t\t\t\tadditionalExtensionPaths: resolvedExtensionPaths,\n\t\t\t\tadditionalSkillPaths: resolvedSkillPaths,\n\t\t\t\tadditionalPromptTemplatePaths: resolvedPromptTemplatePaths,\n\t\t\t\tadditionalThemePaths: resolvedThemePaths,\n\t\t\t\tnoExtensions: parsed.noExtensions,\n\t\t\t\tnoSkills: parsed.noSkills,\n\t\t\t\tnoPromptTemplates: parsed.noPromptTemplates,\n\t\t\t\tnoThemes: parsed.noThemes,\n\t\t\t\tnoContextFiles: parsed.noContextFiles,\n\t\t\t\tsystemPrompt: parsed.systemPrompt,\n\t\t\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\t\t\textensionFactories: [...builtinRoster, ...(options?.extensionFactories ?? [])],\n\t\t\t},\n\t\t});\n\t\tconst { settingsManager, modelRuntime, resourceLoader } = services;\n\t\tif (\n\t\t\tparsed.model &&\n\t\t\t!resolveCliModel({\n\t\t\t\tcliProvider: parsed.provider,\n\t\t\t\tcliModel: parsed.model,\n\t\t\t\tcliThinking: parsed.thinking,\n\t\t\t\tmodelRuntime,\n\t\t\t}).model\n\t\t) {\n\t\t\tawait modelRuntime.refreshIfStale();\n\t\t}\n\t\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [\n\t\t\t...projectTrustDiagnostics,\n\t\t\t...services.diagnostics,\n\t\t\t...collectSettingsDiagnostics(settingsManager, \"runtime creation\"),\n\t\t\t...resourceLoader.getExtensions().errors.map(({ path, error }) => ({\n\t\t\t\ttype: \"error\" as const,\n\t\t\t\tmessage: `Failed to load extension \"${path}\": ${error}`,\n\t\t\t})),\n\t\t];\n\n\t\tconst modelPatterns = parsed.models ?? settingsManager.getEnabledModels();\n\t\tconst scopedModels =\n\t\t\tmodelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRuntime) : [];\n\t\tconst {\n\t\t\toptions: sessionOptions,\n\t\t\tcliThinkingFromModel,\n\t\t\tdiagnostics: sessionOptionDiagnostics,\n\t\t} = buildSessionOptions(\n\t\t\tparsed,\n\t\t\tscopedModels,\n\t\t\tsessionManager.buildSessionContext().messages.length > 0,\n\t\t\tmodelRuntime,\n\t\t\tsettingsManager,\n\t\t);\n\t\tdiagnostics.push(...sessionOptionDiagnostics);\n\n\t\tif (parsed.apiKey) {\n\t\t\tif (!sessionOptions.model) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"error\",\n\t\t\t\t\tmessage: \"--api-key requires a model to be specified via --model, --provider/--model, or --models\",\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Cache-only: do not wait on GitHub / provider /v1/models before first paint.\n\t\t\t\tawait modelRuntime.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey, {\n\t\t\t\t\tallowNetwork: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst created = await createAgentSessionFromServices({\n\t\t\tservices,\n\t\t\tsessionManager,\n\t\t\tsessionStartEvent,\n\t\t\tmodel: sessionOptions.model,\n\t\t\tthinkingLevel: sessionOptions.thinkingLevel,\n\t\t\tscopedModels: sessionOptions.scopedModels,\n\t\t\ttools: sessionOptions.tools,\n\t\t\texcludeTools: sessionOptions.excludeTools,\n\t\t\tnoTools: sessionOptions.noTools,\n\t\t\tcustomTools: sessionOptions.customTools,\n\t\t});\n\t\tconst cliThinkingOverride = parsed.thinking !== undefined || cliThinkingFromModel;\n\t\tif (created.session.model && cliThinkingOverride) {\n\t\t\tcreated.session.setThinkingLevel(created.session.thinkingLevel);\n\t\t}\n\n\t\treturn {\n\t\t\t...created,\n\t\t\tservices,\n\t\t\tdiagnostics,\n\t\t};\n\t};\n\ttime(\"createRuntime\");\n\tconst runtime = await createAgentSessionRuntime(createRuntime, {\n\t\tcwd: sessionManager.getCwd(),\n\t\tagentDir,\n\t\tsessionManager,\n\t\tonRuntimeApplied: bindRuntimeBridges,\n\t});\n\tif (startupShell?.isExitRequested) {\n\t\tawait runtime.dispose();\n\t\treturn;\n\t}\n\tmarkStartupMilestone(\"runtime_hydrated\");\n\ttime(\"createAgentSessionRuntime\");\n\tif (appMode !== \"interactive\") await runSessionRetention();\n\tconst { services, session, modelFallbackMessage } = runtime;\n\tconst { settingsManager, modelRuntime, resourceLoader } = services;\n\tapplyHttpProxySettings(settingsManager.getGlobalSettings().httpProxy);\n\tconfigureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs());\n\n\tif (parsed.help) {\n\t\tconst extensionFlags = resourceLoader\n\t\t\t.getExtensions()\n\t\t\t.extensions.flatMap((extension) => Array.from(extension.flags.values()));\n\t\tprintHelp(extensionFlags);\n\t\tprocess.exit(0);\n\t}\n\n\tif (parsed.listModels !== undefined) {\n\t\tconst searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : undefined;\n\t\tawait listModels(modelRuntime, searchPattern);\n\t\tprocess.exit(0);\n\t}\n\n\t// Read piped stdin content (if any) - skip for RPC mode which uses stdin for JSON-RPC.\n\t// Startup benchmark must stay interactive even if a leftover redirected handle has bytes.\n\tlet stdinContent: string | undefined;\n\tconst startupBenchmark = isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK);\n\tif (appMode !== \"rpc\" && !startupBenchmark) {\n\t\tstdinContent = await readPipedStdin();\n\t\tif (stdinContent !== undefined && appMode === \"interactive\") {\n\t\t\tappMode = \"print\";\n\t\t}\n\t}\n\ttime(\"readPipedStdin\");\n\n\tconst { initialMessage, initialImages } = await prepareInitialMessage(\n\t\tparsed,\n\t\tsettingsManager.getImageAutoResize(),\n\t\tstdinContent,\n\t);\n\ttime(\"prepareInitialMessage\");\n\tinitTheme(settingsManager.getTheme(), appMode === \"interactive\");\n\ttime(\"initTheme\");\n\n\tif (appMode === \"interactive\" && !startupShell && deprecationWarnings.length > 0) {\n\t\tawait showDeprecationWarnings(deprecationWarnings);\n\t}\n\n\ttime(\"resolveModelScope\");\n\tif (!(appMode === \"interactive\" && startupShell)) reportDiagnostics(runtime.diagnostics);\n\tif (runtime.diagnostics.some((diagnostic) => diagnostic.type === \"error\")) {\n\t\tconst extensionHint = runtime.diagnostics.some((diagnostic) =>\n\t\t\tdiagnostic.message.includes(\"Failed to load extension\"),\n\t\t)\n\t\t\t? `\\n${EXTENSION_LOAD_FAILURE_HINT}`\n\t\t\t: \"\";\n\t\tif (startupShell) {\n\t\t\tawait startupShell.fail(\n\t\t\t\t`${runtime.diagnostics.map((diagnostic) => diagnostic.message).join(\"\\n\")}${extensionHint}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tif (extensionHint) console.error(chalk.yellow(EXTENSION_LOAD_FAILURE_HINT));\n\t\tprocess.exit(1);\n\t}\n\ttime(\"createAgentSession\");\n\n\tif (appMode !== \"interactive\" && !session.model) {\n\t\tconsole.error(chalk.red(formatNoModelsAvailableMessage()));\n\t\tprocess.exit(1);\n\t}\n\n\tif (startupBenchmark && appMode !== \"interactive\") {\n\t\tconsole.error(chalk.red(\"Error: PI_STARTUP_BENCHMARK only supports interactive mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tif (appMode === \"rpc\") {\n\t\tconst { runRpcMode } = await import(\"./modes/rpc/rpc-mode.ts\");\n\t\tprintTimings();\n\t\tawait runRpcMode(runtime);\n\t} else if (appMode === \"interactive\") {\n\t\tconst [{ InteractiveMode }, { loadDeferredBuiltinExtensionsResult }] = await Promise.all([\n\t\t\tinteractiveModeImport!,\n\t\t\timport(\"./builtin-extensions/index.ts\"),\n\t\t]);\n\t\tconst interactiveMode = new InteractiveMode(runtime, {\n\t\t\tmigratedProviders,\n\t\t\tmodelFallbackMessage,\n\t\t\tautoTrustOnReloadCwd,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\n\t\t\tinitialMessages: parsed.messages,\n\t\t\tverbose: parsed.verbose,\n\t\t\tdeprecationWarnings: startupShell ? deprecationWarnings : undefined,\n\t\t\tstartupDiagnostics: startupShell\n\t\t\t\t? runtime.diagnostics.filter((diagnostic) => diagnostic.type !== \"error\")\n\t\t\t\t: undefined,\n\t\t\tstartupShellBinding: startupShell?.binding(),\n\t\t\tdeferredMaintenance: runSessionRetention,\n\t\t\tdeferredBuiltinFactories: parsed.noExtensions ? undefined : loadDeferredBuiltinExtensionsResult,\n\t\t\tonDeferredBuiltinsAttached: rememberAttachedFactories,\n\t\t});\n\t\tif (startupBenchmark) {\n\t\t\tawait interactiveMode.init();\n\t\t\ttime(\"interactiveMode.init\");\n\t\t\tawait interactiveMode.waitForPromptBarrier();\n\t\t\ttime(\"promptBarrier\");\n\t\t\tinteractiveMode.stop();\n\t\t\tstopThemeWatcher();\n\t\t\tprintTimings();\n\t\t\tif (process.stdout.writableLength > 0) {\n\t\t\t\tawait new Promise<void>((resolve) => process.stdout.once(\"drain\", resolve));\n\t\t\t}\n\t\t\tif (process.stderr.writableLength > 0) {\n\t\t\t\tawait new Promise<void>((resolve) => process.stderr.once(\"drain\", resolve));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tawait interactiveMode.init();\n\t\ttime(\"interactiveMode.init\");\n\t\tprintTimings();\n\t\tawait interactiveMode.run();\n\t} else {\n\t\tconst { runPrintMode } = await import(\"./modes/print-mode.ts\");\n\t\tprintTimings();\n\t\tconst exitCode = await runPrintMode(runtime, {\n\t\t\tmode: toPrintOutputMode(appMode),\n\t\t\tmessages: parsed.messages,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\n\t\t});\n\t\tstopThemeWatcher();\n\t\trestoreStdout();\n\t\tif (exitCode !== 0) {\n\t\t\tprocess.exitCode = exitCode;\n\t\t}\n\t\treturn;\n\t}\n}\n"]}
package/dist/main.js CHANGED
@@ -665,6 +665,15 @@ export async function main(args, options) {
665
665
  },
666
666
  });
667
667
  const { settingsManager, modelRuntime, resourceLoader } = services;
668
+ if (parsed.model &&
669
+ !resolveCliModel({
670
+ cliProvider: parsed.provider,
671
+ cliModel: parsed.model,
672
+ cliThinking: parsed.thinking,
673
+ modelRuntime,
674
+ }).model) {
675
+ await modelRuntime.refreshIfStale();
676
+ }
668
677
  const diagnostics = [
669
678
  ...projectTrustDiagnostics,
670
679
  ...services.diagnostics,