@cydm/pie 1.0.41 → 1.0.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -2
- package/dist/builtin/extensions/ask-user/index.js +4 -4
- package/dist/builtin/extensions/changelog/index.js +1 -1
- package/dist/builtin/extensions/deploy/index.js +1 -1
- package/dist/builtin/extensions/document-attachments/index.js +1 -1
- package/dist/builtin/extensions/files/index.js +1 -1
- package/dist/builtin/extensions/init/index.js +1 -1
- package/dist/builtin/extensions/kimi-attachments/index.js +1 -1
- package/dist/builtin/extensions/plan-mode/index.js +4 -4
- package/dist/builtin/extensions/subagent/index.js +5 -5
- package/dist/builtin/extensions/todo/index.js +4 -4
- package/dist/chunks/{chunk-OBCFKF6H.js → chunk-2GVFMYIV.js} +583 -91
- package/dist/chunks/{chunk-E3ELBCCX.js → chunk-JVLAKTAS.js} +1 -1
- package/dist/chunks/{chunk-TG2EQLX2.js → chunk-LZQXQOPJ.js} +5 -1
- package/dist/chunks/{chunk-YCPKJCUB.js → chunk-NGQ3PUOC.js} +40 -10
- package/dist/chunks/{chunk-4WGEYDPO.js → chunk-VYAW6RAX.js} +2 -2
- package/dist/chunks/{src-NHRMBQAJ.js → src-TQNFXZGK.js} +3 -3
- package/dist/chunks/{test-stream-I6S23PTW.js → test-stream-IPBFEEWH.js} +2 -2
- package/dist/cli.js +1751 -612
- package/dist/code-intel-worker.cjs +5 -1
- package/models.schema.json +412 -93
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
getThemesDir,
|
|
20
20
|
migrateConfigFromAgentDir,
|
|
21
21
|
truncateHeadTail
|
|
22
|
-
} from "./chunks/chunk-
|
|
22
|
+
} from "./chunks/chunk-VYAW6RAX.js";
|
|
23
23
|
import {
|
|
24
24
|
AGENTS_CONTEXT_FILE_NAME,
|
|
25
25
|
AgentSessionController,
|
|
@@ -69,8 +69,8 @@ import {
|
|
|
69
69
|
setExtensionEnabledInSettings,
|
|
70
70
|
shouldPreserveExecutionStateForUserText,
|
|
71
71
|
supersedeExecutionState
|
|
72
|
-
} from "./chunks/chunk-
|
|
73
|
-
import "./chunks/chunk-
|
|
72
|
+
} from "./chunks/chunk-2GVFMYIV.js";
|
|
73
|
+
import "./chunks/chunk-JVLAKTAS.js";
|
|
74
74
|
import {
|
|
75
75
|
Deref,
|
|
76
76
|
EMPTY_ASSISTANT_CONTENT_ERROR,
|
|
@@ -106,7 +106,7 @@ import {
|
|
|
106
106
|
setLogger,
|
|
107
107
|
sortToolModelCandidatesByCapability,
|
|
108
108
|
type_exports
|
|
109
|
-
} from "./chunks/chunk-
|
|
109
|
+
} from "./chunks/chunk-NGQ3PUOC.js";
|
|
110
110
|
import {
|
|
111
111
|
resolveCliProjectRoot
|
|
112
112
|
} from "./chunks/chunk-NTYHFBUA.js";
|
|
@@ -114,7 +114,7 @@ import {
|
|
|
114
114
|
__commonJS,
|
|
115
115
|
__require,
|
|
116
116
|
__toESM
|
|
117
|
-
} from "./chunks/chunk-
|
|
117
|
+
} from "./chunks/chunk-LZQXQOPJ.js";
|
|
118
118
|
|
|
119
119
|
// ../../node_modules/color-name/index.js
|
|
120
120
|
var require_color_name = __commonJS({
|
|
@@ -986,15 +986,15 @@ var require_route = __commonJS({
|
|
|
986
986
|
};
|
|
987
987
|
}
|
|
988
988
|
function wrapConversion(toModel, graph) {
|
|
989
|
-
const
|
|
989
|
+
const path33 = [graph[toModel].parent, toModel];
|
|
990
990
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
991
991
|
let cur = graph[toModel].parent;
|
|
992
992
|
while (graph[cur].parent) {
|
|
993
|
-
|
|
993
|
+
path33.unshift(graph[cur].parent);
|
|
994
994
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
995
995
|
cur = graph[cur].parent;
|
|
996
996
|
}
|
|
997
|
-
fn.conversion =
|
|
997
|
+
fn.conversion = path33;
|
|
998
998
|
return fn;
|
|
999
999
|
}
|
|
1000
1000
|
module.exports = function(fromModel) {
|
|
@@ -1234,7 +1234,7 @@ var require_has_flag = __commonJS({
|
|
|
1234
1234
|
var require_supports_color = __commonJS({
|
|
1235
1235
|
"../../node_modules/chalk/node_modules/supports-color/index.js"(exports, module) {
|
|
1236
1236
|
"use strict";
|
|
1237
|
-
var
|
|
1237
|
+
var os9 = __require("os");
|
|
1238
1238
|
var tty = __require("tty");
|
|
1239
1239
|
var hasFlag2 = require_has_flag();
|
|
1240
1240
|
var { env } = process;
|
|
@@ -1282,7 +1282,7 @@ var require_supports_color = __commonJS({
|
|
|
1282
1282
|
return min;
|
|
1283
1283
|
}
|
|
1284
1284
|
if (process.platform === "win32") {
|
|
1285
|
-
const osRelease =
|
|
1285
|
+
const osRelease = os9.release().split(".");
|
|
1286
1286
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
1287
1287
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
1288
1288
|
}
|
|
@@ -1917,7 +1917,7 @@ var require_core = __commonJS({
|
|
|
1917
1917
|
return match && match.index === 0;
|
|
1918
1918
|
}
|
|
1919
1919
|
var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
|
|
1920
|
-
function
|
|
1920
|
+
function join21(regexps, separator = "|") {
|
|
1921
1921
|
let numCaptures = 0;
|
|
1922
1922
|
return regexps.map((regex) => {
|
|
1923
1923
|
numCaptures += 1;
|
|
@@ -2221,7 +2221,7 @@ var require_core = __commonJS({
|
|
|
2221
2221
|
this.exec = () => null;
|
|
2222
2222
|
}
|
|
2223
2223
|
const terminators = this.regexes.map((el) => el[1]);
|
|
2224
|
-
this.matcherRe = langRe(
|
|
2224
|
+
this.matcherRe = langRe(join21(terminators), true);
|
|
2225
2225
|
this.lastIndex = 0;
|
|
2226
2226
|
}
|
|
2227
2227
|
/** @param {string} s */
|
|
@@ -43958,8 +43958,8 @@ var require_dist = __commonJS({
|
|
|
43958
43958
|
});
|
|
43959
43959
|
|
|
43960
43960
|
// src/cli.ts
|
|
43961
|
-
import * as
|
|
43962
|
-
import * as
|
|
43961
|
+
import * as fs28 from "fs";
|
|
43962
|
+
import * as path32 from "path";
|
|
43963
43963
|
|
|
43964
43964
|
// src/cli-args.ts
|
|
43965
43965
|
var FLAGS_WITH_VALUES = /* @__PURE__ */ new Set(["--session-id", "--extension-path", "--developer-instructions", "--developer-instructions-file"]);
|
|
@@ -44374,17 +44374,211 @@ function installInteractiveConsoleInterception(runtimeLogger) {
|
|
|
44374
44374
|
// src/doctor.ts
|
|
44375
44375
|
import { spawnSync } from "node:child_process";
|
|
44376
44376
|
import { createRequire } from "node:module";
|
|
44377
|
-
import * as
|
|
44377
|
+
import * as fs5 from "node:fs";
|
|
44378
44378
|
import * as os from "node:os";
|
|
44379
|
-
import * as
|
|
44379
|
+
import * as path5 from "node:path";
|
|
44380
44380
|
import { delimiter } from "node:path";
|
|
44381
44381
|
|
|
44382
44382
|
// src/core/auth-storage.ts
|
|
44383
|
-
|
|
44383
|
+
import * as fs2 from "fs";
|
|
44384
|
+
import * as path2 from "path";
|
|
44385
|
+
var AUTH_LOCK_WRITE_GRACE_MS = 1e3;
|
|
44386
|
+
var DEFAULT_AUTH_LOCK_WAIT_MS = 2e3;
|
|
44387
|
+
var OAUTH_EXPIRY_SKEW_MS = 3e4;
|
|
44388
|
+
function syncSleepMs(ms) {
|
|
44389
|
+
if (ms <= 0) return;
|
|
44390
|
+
const cell = new Int32Array(new SharedArrayBuffer(4));
|
|
44391
|
+
Atomics.wait(cell, 0, 0, ms);
|
|
44392
|
+
}
|
|
44393
|
+
function processIsAlive(pid) {
|
|
44394
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
44395
|
+
try {
|
|
44396
|
+
process.kill(pid, 0);
|
|
44397
|
+
return true;
|
|
44398
|
+
} catch (error) {
|
|
44399
|
+
return error.code === "EPERM";
|
|
44400
|
+
}
|
|
44401
|
+
}
|
|
44402
|
+
var InMemoryAuthStorageBackend = class {
|
|
44403
|
+
snapshot = { oauth: {} };
|
|
44404
|
+
read() {
|
|
44405
|
+
return { oauth: { ...this.snapshot.oauth } };
|
|
44406
|
+
}
|
|
44407
|
+
write(snapshot) {
|
|
44408
|
+
this.snapshot = { oauth: { ...snapshot.oauth } };
|
|
44409
|
+
}
|
|
44410
|
+
};
|
|
44411
|
+
var AUTH_FILE_VERSION = 1;
|
|
44412
|
+
var FileAuthStorageBackend = class {
|
|
44413
|
+
constructor(authPath = path2.join(getConfigDir(), "auth.json"), lockWaitMs = DEFAULT_AUTH_LOCK_WAIT_MS) {
|
|
44414
|
+
this.authPath = authPath;
|
|
44415
|
+
this.lockWaitMs = lockWaitMs;
|
|
44416
|
+
}
|
|
44417
|
+
authPath;
|
|
44418
|
+
lockWaitMs;
|
|
44419
|
+
errors = [];
|
|
44420
|
+
read() {
|
|
44421
|
+
try {
|
|
44422
|
+
if (!fs2.existsSync(this.authPath)) return { oauth: {} };
|
|
44423
|
+
const raw = JSON.parse(fs2.readFileSync(this.authPath, "utf8"));
|
|
44424
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return { oauth: {} };
|
|
44425
|
+
const oauth = raw.oauth;
|
|
44426
|
+
if (!oauth || typeof oauth !== "object" || Array.isArray(oauth)) return { oauth: {} };
|
|
44427
|
+
return { oauth: { ...oauth } };
|
|
44428
|
+
} catch (error) {
|
|
44429
|
+
this.errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
44430
|
+
return { oauth: {} };
|
|
44431
|
+
}
|
|
44432
|
+
}
|
|
44433
|
+
/** A lock whose owner is gone (or that never got populated) may be reclaimed. */
|
|
44434
|
+
lockIsStale(lockPath) {
|
|
44435
|
+
const stat2 = fs2.lstatSync(lockPath);
|
|
44436
|
+
if (stat2.isSymbolicLink() || !stat2.isFile()) return true;
|
|
44437
|
+
let owner;
|
|
44438
|
+
try {
|
|
44439
|
+
owner = JSON.parse(fs2.readFileSync(lockPath, "utf8"));
|
|
44440
|
+
} catch {
|
|
44441
|
+
}
|
|
44442
|
+
const age = Date.now() - stat2.mtimeMs;
|
|
44443
|
+
const validOwner = owner?.version === 1 && Number.isSafeInteger(owner.pid) && typeof owner.token === "string" && typeof owner.createdAt === "number";
|
|
44444
|
+
if (validOwner && processIsAlive(Number(owner.pid))) return false;
|
|
44445
|
+
return validOwner || age > AUTH_LOCK_WRITE_GRACE_MS;
|
|
44446
|
+
}
|
|
44447
|
+
/** Atomically claim a stale lock via hard-link identity comparison before removing it. */
|
|
44448
|
+
reclaimStaleLock(lockPath) {
|
|
44449
|
+
if (!this.lockIsStale(lockPath)) return false;
|
|
44450
|
+
const claimPath = `${lockPath}.reclaim-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
44451
|
+
try {
|
|
44452
|
+
fs2.linkSync(lockPath, claimPath);
|
|
44453
|
+
const claimed = fs2.lstatSync(claimPath);
|
|
44454
|
+
const current = fs2.lstatSync(lockPath);
|
|
44455
|
+
if (claimed.isSymbolicLink() || !claimed.isFile() || current.isSymbolicLink() || !current.isFile()) return false;
|
|
44456
|
+
if (claimed.dev !== current.dev || claimed.ino !== current.ino) return false;
|
|
44457
|
+
fs2.unlinkSync(lockPath);
|
|
44458
|
+
return true;
|
|
44459
|
+
} catch (error) {
|
|
44460
|
+
const code = error.code;
|
|
44461
|
+
if (code === "ENOENT" || code === "EEXIST") return false;
|
|
44462
|
+
throw error;
|
|
44463
|
+
} finally {
|
|
44464
|
+
try {
|
|
44465
|
+
fs2.unlinkSync(claimPath);
|
|
44466
|
+
} catch {
|
|
44467
|
+
}
|
|
44468
|
+
}
|
|
44469
|
+
}
|
|
44470
|
+
/** Acquire the fixed-path cross-process lock; the release fn is token-checked. */
|
|
44471
|
+
acquireLock(directory, lockPath) {
|
|
44472
|
+
fs2.mkdirSync(directory, { recursive: true, mode: 448 });
|
|
44473
|
+
const deadline = Date.now() + this.lockWaitMs;
|
|
44474
|
+
while (true) {
|
|
44475
|
+
const token = `${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
|
|
44476
|
+
try {
|
|
44477
|
+
const fd = fs2.openSync(lockPath, "wx", 384);
|
|
44478
|
+
try {
|
|
44479
|
+
fs2.writeFileSync(fd, `${JSON.stringify({ version: 1, pid: process.pid, token, createdAt: Date.now() })}
|
|
44480
|
+
`);
|
|
44481
|
+
} finally {
|
|
44482
|
+
fs2.closeSync(fd);
|
|
44483
|
+
}
|
|
44484
|
+
return () => {
|
|
44485
|
+
try {
|
|
44486
|
+
const owner = JSON.parse(fs2.readFileSync(lockPath, "utf8"));
|
|
44487
|
+
if (owner?.token === token) fs2.unlinkSync(lockPath);
|
|
44488
|
+
} catch {
|
|
44489
|
+
}
|
|
44490
|
+
};
|
|
44491
|
+
} catch (error) {
|
|
44492
|
+
if (error.code !== "EEXIST") throw error;
|
|
44493
|
+
try {
|
|
44494
|
+
if (this.reclaimStaleLock(lockPath)) continue;
|
|
44495
|
+
} catch (reclaimError) {
|
|
44496
|
+
if (reclaimError.code === "ENOENT") continue;
|
|
44497
|
+
throw reclaimError;
|
|
44498
|
+
}
|
|
44499
|
+
if (Date.now() >= deadline) throw new Error(`timed out waiting for auth storage lock: ${lockPath}`);
|
|
44500
|
+
syncSleepMs(25);
|
|
44501
|
+
}
|
|
44502
|
+
}
|
|
44503
|
+
}
|
|
44504
|
+
/**
|
|
44505
|
+
* Merge-on-write under a fixed-path cross-process lock: re-read the file,
|
|
44506
|
+
* apply explicit removals (logout), merge our snapshot's oauth entries
|
|
44507
|
+
* over whatever is on disk (preserving unrelated edits), then write back
|
|
44508
|
+
* atomically with 0600 permissions.
|
|
44509
|
+
*/
|
|
44510
|
+
write(snapshot) {
|
|
44511
|
+
const directory = path2.dirname(this.authPath);
|
|
44512
|
+
const lockPath = `${this.authPath}.lock`;
|
|
44513
|
+
let release;
|
|
44514
|
+
try {
|
|
44515
|
+
release = this.acquireLock(directory, lockPath);
|
|
44516
|
+
try {
|
|
44517
|
+
const onDisk = this.read();
|
|
44518
|
+
const mergedOauth = { ...onDisk.oauth };
|
|
44519
|
+
for (const removed of snapshot.removedOauth ?? []) {
|
|
44520
|
+
delete mergedOauth[removed];
|
|
44521
|
+
}
|
|
44522
|
+
Object.assign(mergedOauth, snapshot.oauth);
|
|
44523
|
+
const merged = {
|
|
44524
|
+
version: AUTH_FILE_VERSION,
|
|
44525
|
+
oauth: mergedOauth
|
|
44526
|
+
};
|
|
44527
|
+
const temporary = `${this.authPath}.${process.pid}.tmp`;
|
|
44528
|
+
try {
|
|
44529
|
+
fs2.writeFileSync(temporary, `${JSON.stringify(merged, null, 2)}
|
|
44530
|
+
`, { flag: "wx", mode: 384 });
|
|
44531
|
+
fs2.renameSync(temporary, this.authPath);
|
|
44532
|
+
} finally {
|
|
44533
|
+
if (fs2.existsSync(temporary)) fs2.unlinkSync(temporary);
|
|
44534
|
+
}
|
|
44535
|
+
} finally {
|
|
44536
|
+
release();
|
|
44537
|
+
}
|
|
44538
|
+
} catch (error) {
|
|
44539
|
+
this.errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
44540
|
+
}
|
|
44541
|
+
}
|
|
44542
|
+
drainErrors() {
|
|
44543
|
+
return this.errors.splice(0);
|
|
44544
|
+
}
|
|
44545
|
+
};
|
|
44546
|
+
var AuthStorage = class _AuthStorage {
|
|
44384
44547
|
providerApiKeys = /* @__PURE__ */ new Map();
|
|
44385
44548
|
runtimeApiKeys = /* @__PURE__ */ new Map();
|
|
44386
44549
|
providerEnvVars = /* @__PURE__ */ new Map();
|
|
44387
44550
|
legacyApiKey;
|
|
44551
|
+
oauthCredentials = /* @__PURE__ */ new Map();
|
|
44552
|
+
removedOauthProviders = /* @__PURE__ */ new Set();
|
|
44553
|
+
backend;
|
|
44554
|
+
constructor(backend) {
|
|
44555
|
+
this.backend = backend;
|
|
44556
|
+
if (backend) {
|
|
44557
|
+
for (const [provider, credentials] of Object.entries(backend.read().oauth)) {
|
|
44558
|
+
this.oauthCredentials.set(provider, credentials);
|
|
44559
|
+
}
|
|
44560
|
+
}
|
|
44561
|
+
}
|
|
44562
|
+
/** Runtime-only storage (no persistence). */
|
|
44563
|
+
static create() {
|
|
44564
|
+
return new _AuthStorage();
|
|
44565
|
+
}
|
|
44566
|
+
/** Storage bound to a persistence backend (OAuth credentials survive restarts). */
|
|
44567
|
+
static fromStorage(backend) {
|
|
44568
|
+
return new _AuthStorage(backend);
|
|
44569
|
+
}
|
|
44570
|
+
/** In-memory backend, for tests and embedders that manage their own persistence. */
|
|
44571
|
+
static inMemory() {
|
|
44572
|
+
return new _AuthStorage(new InMemoryAuthStorageBackend());
|
|
44573
|
+
}
|
|
44574
|
+
/** Drain buffered backend I/O errors (file backend only). */
|
|
44575
|
+
drainErrors() {
|
|
44576
|
+
const backend = this.backend;
|
|
44577
|
+
if (backend && typeof backend.drainErrors === "function") {
|
|
44578
|
+
return backend.drainErrors();
|
|
44579
|
+
}
|
|
44580
|
+
return [];
|
|
44581
|
+
}
|
|
44388
44582
|
setLegacyApiKey(apiKey) {
|
|
44389
44583
|
this.legacyApiKey = apiKey;
|
|
44390
44584
|
}
|
|
@@ -44412,20 +44606,104 @@ var AuthStorage = class {
|
|
|
44412
44606
|
getProviderEnvVar(provider) {
|
|
44413
44607
|
return this.providerEnvVars.get(provider);
|
|
44414
44608
|
}
|
|
44609
|
+
setOAuthCredentials(provider, credentials) {
|
|
44610
|
+
if (!credentials) {
|
|
44611
|
+
this.oauthCredentials.delete(provider);
|
|
44612
|
+
this.removedOauthProviders.add(provider);
|
|
44613
|
+
this.runtimeApiKeys.delete(provider);
|
|
44614
|
+
} else {
|
|
44615
|
+
this.oauthCredentials.set(provider, credentials);
|
|
44616
|
+
this.removedOauthProviders.delete(provider);
|
|
44617
|
+
}
|
|
44618
|
+
this.persistOAuth();
|
|
44619
|
+
}
|
|
44620
|
+
getOAuthCredentials(provider) {
|
|
44621
|
+
return this.oauthCredentials.get(provider);
|
|
44622
|
+
}
|
|
44623
|
+
/** Providers with persisted OAuth credentials (for restore/refresh passes). */
|
|
44624
|
+
getOAuthProviderNames() {
|
|
44625
|
+
return [...this.oauthCredentials.keys()];
|
|
44626
|
+
}
|
|
44627
|
+
persistOAuth() {
|
|
44628
|
+
if (!this.backend) return;
|
|
44629
|
+
this.backend.write({
|
|
44630
|
+
oauth: Object.fromEntries(this.oauthCredentials),
|
|
44631
|
+
removedOauth: [...this.removedOauthProviders]
|
|
44632
|
+
});
|
|
44633
|
+
}
|
|
44415
44634
|
getApiKey(provider, explicitEnvVar) {
|
|
44416
44635
|
const envVar = explicitEnvVar || this.getProviderEnvVar(provider);
|
|
44417
44636
|
const envApiKey = envVar && typeof process !== "undefined" ? process.env?.[envVar] : void 0;
|
|
44418
|
-
return this.runtimeApiKeys.get(provider) || this.providerApiKeys.get(provider) || envApiKey || this.legacyApiKey;
|
|
44637
|
+
return this.runtimeApiKeys.get(provider) || this.providerApiKeys.get(provider) || envApiKey || this.usableOAuthAccessToken(provider) || this.legacyApiKey;
|
|
44638
|
+
}
|
|
44639
|
+
/** Persisted OAuth access token, when it exists and has not expired. */
|
|
44640
|
+
usableOAuthAccessToken(provider) {
|
|
44641
|
+
const credentials = this.oauthCredentials.get(provider);
|
|
44642
|
+
if (!credentials?.access) return void 0;
|
|
44643
|
+
if (credentials.expires !== void 0 && credentials.expires <= Date.now() + OAUTH_EXPIRY_SKEW_MS) {
|
|
44644
|
+
return void 0;
|
|
44645
|
+
}
|
|
44646
|
+
return credentials.access;
|
|
44419
44647
|
}
|
|
44420
44648
|
};
|
|
44421
44649
|
|
|
44422
44650
|
// src/core/model-registry.ts
|
|
44423
|
-
import * as
|
|
44424
|
-
import * as
|
|
44651
|
+
import * as fs3 from "fs";
|
|
44652
|
+
import * as path3 from "path";
|
|
44425
44653
|
import { createHash, createHmac, randomBytes } from "node:crypto";
|
|
44654
|
+
var MODEL_OVERRIDE_KEYS = [
|
|
44655
|
+
"name",
|
|
44656
|
+
"reasoning",
|
|
44657
|
+
"input",
|
|
44658
|
+
"cost",
|
|
44659
|
+
"contextWindow",
|
|
44660
|
+
"maxTokens",
|
|
44661
|
+
"headers",
|
|
44662
|
+
"compat",
|
|
44663
|
+
"cacheCapability",
|
|
44664
|
+
"webSearch",
|
|
44665
|
+
"fileCapabilities",
|
|
44666
|
+
"displayName"
|
|
44667
|
+
];
|
|
44668
|
+
function validateExtensionProviderConfig(provider, config) {
|
|
44669
|
+
if (!provider || provider !== provider.trim() || /\s/.test(provider)) throw new Error(`registerProvider: invalid provider id "${provider}"`);
|
|
44670
|
+
if (!config || typeof config !== "object") throw new Error("registerProvider: config must be an object");
|
|
44671
|
+
if (typeof config.baseUrl !== "string" || !config.baseUrl) throw new Error(`registerProvider("${provider}"): baseUrl is required`);
|
|
44672
|
+
try {
|
|
44673
|
+
new URL(config.baseUrl);
|
|
44674
|
+
} catch {
|
|
44675
|
+
throw new Error(`registerProvider("${provider}"): baseUrl must be an absolute URL`);
|
|
44676
|
+
}
|
|
44677
|
+
assertHeadersShape(config.headers, `registerProvider("${provider}")`);
|
|
44678
|
+
for (const model of config.models ?? []) {
|
|
44679
|
+
if (!model || typeof model.id !== "string" || !model.id.trim() || /\s/.test(model.id)) throw new Error(`registerProvider("${provider}"): invalid model id`);
|
|
44680
|
+
assertHeadersShape(model.headers, `registerProvider("${provider}") model "${model.id}"`);
|
|
44681
|
+
validateCompat(model.compat, `registerProvider("${provider}") model "${model.id}" compat`);
|
|
44682
|
+
validateCacheCapability(model.cacheCapability, `registerProvider("${provider}") model "${model.id}" cacheCapability`);
|
|
44683
|
+
validateWebSearchCapability(model.webSearch, `registerProvider("${provider}") model "${model.id}" webSearch`);
|
|
44684
|
+
validateFileCapabilities(model.fileCapabilities, `registerProvider("${provider}") model "${model.id}" fileCapabilities`);
|
|
44685
|
+
}
|
|
44686
|
+
}
|
|
44426
44687
|
var REMOTE_CATALOG_CACHE_VERSION = 4;
|
|
44427
44688
|
var SUPPORTED_REMOTE_APIS = /* @__PURE__ */ new Set(["openai-completions", "anthropic-messages"]);
|
|
44428
44689
|
var MAX_REMOTE_CATALOG_BYTES = 2 * 1024 * 1024;
|
|
44690
|
+
var OAUTH_RESTORE_LEEWAY_MS = 6e4;
|
|
44691
|
+
var OAUTH_REFRESH_TIMEOUT_MS = 3e4;
|
|
44692
|
+
function withTimeout(promise, ms, timeoutMessage) {
|
|
44693
|
+
return new Promise((resolve7, reject) => {
|
|
44694
|
+
const timer = setTimeout(() => reject(new Error(timeoutMessage)), ms);
|
|
44695
|
+
Promise.resolve(promise).then(
|
|
44696
|
+
(value) => {
|
|
44697
|
+
clearTimeout(timer);
|
|
44698
|
+
resolve7(value);
|
|
44699
|
+
},
|
|
44700
|
+
(error) => {
|
|
44701
|
+
clearTimeout(timer);
|
|
44702
|
+
reject(error);
|
|
44703
|
+
}
|
|
44704
|
+
);
|
|
44705
|
+
});
|
|
44706
|
+
}
|
|
44429
44707
|
var REMOTE_REFRESH_LOCK_WAIT_MS = 6e4;
|
|
44430
44708
|
var REMOTE_REFRESH_LOCK_WRITE_GRACE_MS = 1e3;
|
|
44431
44709
|
var remoteRefreshTails = /* @__PURE__ */ new Map();
|
|
@@ -44449,40 +44727,40 @@ function remoteIdentityDigest(remote) {
|
|
|
44449
44727
|
return createHash("sha256").update(JSON.stringify({ version: REMOTE_CATALOG_CACHE_VERSION, ...canonicalRemote(remote) })).digest("hex");
|
|
44450
44728
|
}
|
|
44451
44729
|
function remoteCacheDirectory(modelsPath) {
|
|
44452
|
-
return
|
|
44730
|
+
return path3.join(path3.dirname(modelsPath), "cache", "remote-catalogs");
|
|
44453
44731
|
}
|
|
44454
44732
|
function safeRemoteCacheDirectory(modelsPath, create) {
|
|
44455
|
-
const configDirectory =
|
|
44456
|
-
if (!
|
|
44733
|
+
const configDirectory = path3.dirname(modelsPath);
|
|
44734
|
+
if (!fs3.existsSync(configDirectory)) {
|
|
44457
44735
|
if (!create) return void 0;
|
|
44458
|
-
|
|
44736
|
+
fs3.mkdirSync(configDirectory, { recursive: true, mode: 448 });
|
|
44459
44737
|
}
|
|
44460
|
-
const configRoot =
|
|
44461
|
-
const cacheRoot =
|
|
44738
|
+
const configRoot = fs3.realpathSync(configDirectory);
|
|
44739
|
+
const cacheRoot = path3.join(configDirectory, "cache");
|
|
44462
44740
|
const directory = remoteCacheDirectory(modelsPath);
|
|
44463
44741
|
for (const candidate of [cacheRoot, directory]) {
|
|
44464
|
-
if (!
|
|
44742
|
+
if (!fs3.existsSync(candidate)) {
|
|
44465
44743
|
if (!create) return void 0;
|
|
44466
|
-
|
|
44744
|
+
fs3.mkdirSync(candidate, { mode: 448 });
|
|
44467
44745
|
}
|
|
44468
|
-
const stat2 =
|
|
44746
|
+
const stat2 = fs3.lstatSync(candidate);
|
|
44469
44747
|
if (stat2.isSymbolicLink() || !stat2.isDirectory()) throw new Error(`remote catalog cache path must be a real directory: ${candidate}`);
|
|
44470
|
-
const canonical =
|
|
44471
|
-
const
|
|
44472
|
-
if (
|
|
44748
|
+
const canonical = fs3.realpathSync(candidate);
|
|
44749
|
+
const relative3 = path3.relative(configRoot, canonical);
|
|
44750
|
+
if (relative3 === ".." || relative3.startsWith(`..${path3.sep}`) || path3.isAbsolute(relative3)) {
|
|
44473
44751
|
throw new Error(`remote catalog cache path escapes the config directory: ${candidate}`);
|
|
44474
44752
|
}
|
|
44475
44753
|
try {
|
|
44476
|
-
|
|
44754
|
+
fs3.chmodSync(candidate, 448);
|
|
44477
44755
|
} catch {
|
|
44478
44756
|
}
|
|
44479
44757
|
}
|
|
44480
44758
|
return directory;
|
|
44481
44759
|
}
|
|
44482
44760
|
function remoteRefreshLockPath(modelsPath) {
|
|
44483
|
-
return
|
|
44761
|
+
return path3.join(remoteCacheDirectory(modelsPath), ".refresh.lock");
|
|
44484
44762
|
}
|
|
44485
|
-
function
|
|
44763
|
+
function processIsAlive2(pid) {
|
|
44486
44764
|
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
44487
44765
|
try {
|
|
44488
44766
|
process.kill(pid, 0);
|
|
@@ -44492,40 +44770,40 @@ function processIsAlive(pid) {
|
|
|
44492
44770
|
}
|
|
44493
44771
|
}
|
|
44494
44772
|
function remoteRefreshLockIsStale(lockPath) {
|
|
44495
|
-
const stat2 =
|
|
44773
|
+
const stat2 = fs3.lstatSync(lockPath);
|
|
44496
44774
|
if (stat2.isSymbolicLink() || !stat2.isFile()) throw new Error(`remote catalog refresh lock must be a regular file: ${lockPath}`);
|
|
44497
44775
|
let owner;
|
|
44498
44776
|
try {
|
|
44499
|
-
owner = JSON.parse(
|
|
44777
|
+
owner = JSON.parse(fs3.readFileSync(lockPath, "utf8"));
|
|
44500
44778
|
} catch {
|
|
44501
44779
|
}
|
|
44502
44780
|
const age = Date.now() - stat2.mtimeMs;
|
|
44503
44781
|
const validOwner = owner?.version === 1 && Number.isSafeInteger(owner.pid) && typeof owner.token === "string" && typeof owner.createdAt === "number";
|
|
44504
|
-
if (validOwner &&
|
|
44782
|
+
if (validOwner && processIsAlive2(Number(owner.pid))) return false;
|
|
44505
44783
|
return validOwner || age > REMOTE_REFRESH_LOCK_WRITE_GRACE_MS;
|
|
44506
44784
|
}
|
|
44507
44785
|
function sameFileIdentity(left, right, leftPath, rightPath) {
|
|
44508
44786
|
if (left.dev !== right.dev || left.ino !== right.ino) return false;
|
|
44509
44787
|
if (left.ino !== 0) return true;
|
|
44510
|
-
return left.size === right.size &&
|
|
44788
|
+
return left.size === right.size && fs3.readFileSync(leftPath).equals(fs3.readFileSync(rightPath));
|
|
44511
44789
|
}
|
|
44512
44790
|
function reclaimStaleRemoteRefreshLock(lockPath) {
|
|
44513
44791
|
if (!remoteRefreshLockIsStale(lockPath)) return false;
|
|
44514
44792
|
const claimPath = `${lockPath}.reclaim-${process.pid}-${randomBytes(8).toString("hex")}`;
|
|
44515
44793
|
try {
|
|
44516
|
-
|
|
44517
|
-
const claimed =
|
|
44518
|
-
const current =
|
|
44794
|
+
fs3.linkSync(lockPath, claimPath);
|
|
44795
|
+
const claimed = fs3.lstatSync(claimPath);
|
|
44796
|
+
const current = fs3.lstatSync(lockPath);
|
|
44519
44797
|
if (claimed.isSymbolicLink() || !claimed.isFile() || current.isSymbolicLink() || !current.isFile() || !sameFileIdentity(claimed, current, claimPath, lockPath)) return false;
|
|
44520
44798
|
if (!remoteRefreshLockIsStale(claimPath)) return false;
|
|
44521
|
-
|
|
44799
|
+
fs3.unlinkSync(lockPath);
|
|
44522
44800
|
return true;
|
|
44523
44801
|
} catch (error) {
|
|
44524
44802
|
if (["ENOENT", "EEXIST"].includes(error.code ?? "")) return false;
|
|
44525
44803
|
throw error;
|
|
44526
44804
|
} finally {
|
|
44527
44805
|
try {
|
|
44528
|
-
|
|
44806
|
+
fs3.unlinkSync(claimPath);
|
|
44529
44807
|
} catch {
|
|
44530
44808
|
}
|
|
44531
44809
|
}
|
|
@@ -44537,19 +44815,19 @@ async function acquireRemoteRefreshLock(modelsPath) {
|
|
|
44537
44815
|
while (true) {
|
|
44538
44816
|
const token = randomBytes(16).toString("hex");
|
|
44539
44817
|
try {
|
|
44540
|
-
const fd =
|
|
44818
|
+
const fd = fs3.openSync(lockPath, "wx", 384);
|
|
44541
44819
|
try {
|
|
44542
|
-
|
|
44820
|
+
fs3.writeFileSync(fd, `${JSON.stringify({ version: 1, pid: process.pid, token, createdAt: Date.now() })}
|
|
44543
44821
|
`);
|
|
44544
44822
|
} finally {
|
|
44545
|
-
|
|
44823
|
+
fs3.closeSync(fd);
|
|
44546
44824
|
}
|
|
44547
44825
|
return () => {
|
|
44548
44826
|
try {
|
|
44549
|
-
const stat2 =
|
|
44827
|
+
const stat2 = fs3.lstatSync(lockPath);
|
|
44550
44828
|
if (stat2.isSymbolicLink() || !stat2.isFile()) return;
|
|
44551
|
-
const current = JSON.parse(
|
|
44552
|
-
if (current.token === token)
|
|
44829
|
+
const current = JSON.parse(fs3.readFileSync(lockPath, "utf8"));
|
|
44830
|
+
if (current.token === token) fs3.unlinkSync(lockPath);
|
|
44553
44831
|
} catch {
|
|
44554
44832
|
}
|
|
44555
44833
|
};
|
|
@@ -44562,29 +44840,29 @@ async function acquireRemoteRefreshLock(modelsPath) {
|
|
|
44562
44840
|
throw lockError;
|
|
44563
44841
|
}
|
|
44564
44842
|
if (Date.now() >= deadline) throw new Error(`timed out waiting for remote catalog refresh lock: ${lockPath}`);
|
|
44565
|
-
await new Promise((
|
|
44843
|
+
await new Promise((resolve7) => setTimeout(resolve7, 25));
|
|
44566
44844
|
}
|
|
44567
44845
|
}
|
|
44568
44846
|
}
|
|
44569
44847
|
function readSafeRemoteCacheFile(directory, filepath) {
|
|
44570
|
-
const stat2 =
|
|
44848
|
+
const stat2 = fs3.lstatSync(filepath);
|
|
44571
44849
|
if (stat2.isSymbolicLink() || !stat2.isFile()) throw new Error(`remote catalog cache entry must be a regular file: ${filepath}`);
|
|
44572
|
-
const canonicalDirectory =
|
|
44573
|
-
const canonicalFile =
|
|
44574
|
-
const
|
|
44575
|
-
if (!
|
|
44850
|
+
const canonicalDirectory = fs3.realpathSync(directory);
|
|
44851
|
+
const canonicalFile = fs3.realpathSync(filepath);
|
|
44852
|
+
const relative3 = path3.relative(canonicalDirectory, canonicalFile);
|
|
44853
|
+
if (!relative3 || relative3 === ".." || relative3.startsWith(`..${path3.sep}`) || path3.isAbsolute(relative3)) {
|
|
44576
44854
|
throw new Error(`remote catalog cache entry escapes its cache directory: ${filepath}`);
|
|
44577
44855
|
}
|
|
44578
|
-
return
|
|
44856
|
+
return fs3.readFileSync(filepath);
|
|
44579
44857
|
}
|
|
44580
44858
|
function credentialNamespaceKey(modelsPath, create) {
|
|
44581
44859
|
const directory = safeRemoteCacheDirectory(modelsPath, create);
|
|
44582
44860
|
if (!directory) return void 0;
|
|
44583
|
-
const keyPath =
|
|
44584
|
-
if (!
|
|
44585
|
-
if (create && !
|
|
44861
|
+
const keyPath = path3.join(directory, ".credential-namespace-key");
|
|
44862
|
+
if (!fs3.existsSync(keyPath) && !create) return void 0;
|
|
44863
|
+
if (create && !fs3.existsSync(keyPath)) {
|
|
44586
44864
|
try {
|
|
44587
|
-
|
|
44865
|
+
fs3.writeFileSync(keyPath, randomBytes(32), { flag: "wx", mode: 384 });
|
|
44588
44866
|
} catch (error) {
|
|
44589
44867
|
if (!isPlainRecord(error) || error.code !== "EEXIST") throw error;
|
|
44590
44868
|
}
|
|
@@ -44592,7 +44870,7 @@ function credentialNamespaceKey(modelsPath, create) {
|
|
|
44592
44870
|
const key = readSafeRemoteCacheFile(directory, keyPath);
|
|
44593
44871
|
if (key.byteLength !== 32) throw new Error("remote catalog credential namespace key is invalid");
|
|
44594
44872
|
try {
|
|
44595
|
-
|
|
44873
|
+
fs3.chmodSync(keyPath, 384);
|
|
44596
44874
|
} catch {
|
|
44597
44875
|
}
|
|
44598
44876
|
return key;
|
|
@@ -44603,28 +44881,28 @@ function credentialFingerprint(modelsPath, remote, credential, create = false) {
|
|
|
44603
44881
|
return createHmac("sha256", key).update(remoteIdentityDigest(remote)).update("\0").update(credential).digest("hex");
|
|
44604
44882
|
}
|
|
44605
44883
|
function remoteCachePath(modelsPath, remote, fingerprint) {
|
|
44606
|
-
return
|
|
44884
|
+
return path3.join(remoteCacheDirectory(modelsPath), `${remoteIdentityDigest(remote)}-${fingerprint}.json`);
|
|
44607
44885
|
}
|
|
44608
44886
|
function pruneLegacyRemoteCatalogCaches(modelsPath) {
|
|
44609
44887
|
const directory = safeRemoteCacheDirectory(modelsPath, false);
|
|
44610
44888
|
if (!directory) return;
|
|
44611
|
-
for (const name of
|
|
44889
|
+
for (const name of fs3.readdirSync(directory)) {
|
|
44612
44890
|
if (!name.endsWith(".json")) continue;
|
|
44613
|
-
const filepath =
|
|
44891
|
+
const filepath = path3.join(directory, name);
|
|
44614
44892
|
try {
|
|
44615
44893
|
const value = JSON.parse(readSafeRemoteCacheFile(directory, filepath).toString("utf8"));
|
|
44616
44894
|
if (value.version === REMOTE_CATALOG_CACHE_VERSION) continue;
|
|
44617
44895
|
} catch {
|
|
44618
44896
|
let stat2;
|
|
44619
44897
|
try {
|
|
44620
|
-
stat2 =
|
|
44898
|
+
stat2 = fs3.lstatSync(filepath);
|
|
44621
44899
|
} catch {
|
|
44622
44900
|
continue;
|
|
44623
44901
|
}
|
|
44624
44902
|
if (stat2.isSymbolicLink() || !stat2.isFile()) continue;
|
|
44625
44903
|
}
|
|
44626
44904
|
try {
|
|
44627
|
-
|
|
44905
|
+
fs3.unlinkSync(filepath);
|
|
44628
44906
|
} catch {
|
|
44629
44907
|
}
|
|
44630
44908
|
}
|
|
@@ -44633,7 +44911,7 @@ function scrubActiveSecretsFromRemoteCaches(modelsPath, activeSecrets) {
|
|
|
44633
44911
|
if (activeSecrets.length === 0) return;
|
|
44634
44912
|
const directory = safeRemoteCacheDirectory(modelsPath, false);
|
|
44635
44913
|
if (!directory) return;
|
|
44636
|
-
const handle =
|
|
44914
|
+
const handle = fs3.opendirSync(directory);
|
|
44637
44915
|
try {
|
|
44638
44916
|
let scanned = 0;
|
|
44639
44917
|
while (true) {
|
|
@@ -44643,14 +44921,14 @@ function scrubActiveSecretsFromRemoteCaches(modelsPath, activeSecrets) {
|
|
|
44643
44921
|
const isCache = entry.name.endsWith(".json");
|
|
44644
44922
|
const isOrphanedTemporary = /^\..+\.json\.\d+\.[0-9a-f]+\.tmp$/.test(entry.name);
|
|
44645
44923
|
if (!entry.isFile() || !isCache && !isOrphanedTemporary) continue;
|
|
44646
|
-
const filepath =
|
|
44924
|
+
const filepath = path3.join(directory, entry.name);
|
|
44647
44925
|
try {
|
|
44648
44926
|
const raw = readSafeRemoteCacheFile(directory, filepath).toString("utf8");
|
|
44649
44927
|
assertNoSecretSubstrings(raw, activeSecrets, "remote catalog cache");
|
|
44650
44928
|
} catch {
|
|
44651
44929
|
try {
|
|
44652
|
-
const stat2 =
|
|
44653
|
-
if (!stat2.isSymbolicLink() && stat2.isFile())
|
|
44930
|
+
const stat2 = fs3.lstatSync(filepath);
|
|
44931
|
+
if (!stat2.isSymbolicLink() && stat2.isFile()) fs3.unlinkSync(filepath);
|
|
44654
44932
|
} catch {
|
|
44655
44933
|
}
|
|
44656
44934
|
}
|
|
@@ -44721,7 +44999,7 @@ function readRemoteCache(modelsPath, remote, fingerprint, activeSecrets) {
|
|
|
44721
44999
|
const directory = safeRemoteCacheDirectory(modelsPath, false);
|
|
44722
45000
|
if (!directory) return void 0;
|
|
44723
45001
|
const tombstone = remoteCacheTombstonePath(modelsPath, remote, fingerprint);
|
|
44724
|
-
if (
|
|
45002
|
+
if (fs3.existsSync(tombstone)) return void 0;
|
|
44725
45003
|
const value = JSON.parse(readSafeRemoteCacheFile(directory, remoteCachePath(modelsPath, remote, fingerprint)).toString("utf8"));
|
|
44726
45004
|
if (value.version !== REMOTE_CATALOG_CACHE_VERSION || !sameRemoteIdentity(value.identity, remote) || value.credentialFingerprint !== fingerprint || typeof value.payloadSha256 !== "string" || value.payloadSha256 !== payloadDigest(value.payload)) return void 0;
|
|
44727
45005
|
assertNoSecretSubstrings({ etag: value.etag, payload: value.payload }, activeSecrets, "remote catalog cache");
|
|
@@ -44741,23 +45019,23 @@ function removeRemoteCache(modelsPath, remote, fingerprint) {
|
|
|
44741
45019
|
const directory = safeRemoteCacheDirectory(modelsPath, false);
|
|
44742
45020
|
if (!directory) return;
|
|
44743
45021
|
const filepath = remoteCachePath(modelsPath, remote, fingerprint);
|
|
44744
|
-
if (
|
|
44745
|
-
const stat2 =
|
|
45022
|
+
if (fs3.existsSync(filepath)) {
|
|
45023
|
+
const stat2 = fs3.lstatSync(filepath);
|
|
44746
45024
|
if (stat2.isSymbolicLink() || !stat2.isFile()) throw new Error(`remote catalog cache entry is not a regular file: ${filepath}`);
|
|
44747
|
-
|
|
45025
|
+
fs3.unlinkSync(filepath);
|
|
44748
45026
|
}
|
|
44749
45027
|
const tombstone = remoteCacheTombstonePath(modelsPath, remote, fingerprint);
|
|
44750
|
-
if (
|
|
45028
|
+
if (fs3.existsSync(tombstone)) fs3.unlinkSync(tombstone);
|
|
44751
45029
|
return;
|
|
44752
45030
|
} catch (error) {
|
|
44753
45031
|
const directory = safeRemoteCacheDirectory(modelsPath, true);
|
|
44754
45032
|
if (!directory) throw error;
|
|
44755
45033
|
const tombstone = remoteCacheTombstonePath(modelsPath, remote, fingerprint);
|
|
44756
45034
|
try {
|
|
44757
|
-
|
|
45035
|
+
fs3.writeFileSync(tombstone, `${JSON.stringify({ version: 1, revoked: true })}
|
|
44758
45036
|
`, { flag: "wx", mode: 384 });
|
|
44759
45037
|
} catch (tombstoneError) {
|
|
44760
|
-
if (!
|
|
45038
|
+
if (!fs3.existsSync(tombstone)) throw tombstoneError;
|
|
44761
45039
|
}
|
|
44762
45040
|
}
|
|
44763
45041
|
}
|
|
@@ -44819,7 +45097,7 @@ function validatedRemoteCatalogs(value) {
|
|
|
44819
45097
|
}
|
|
44820
45098
|
function validateModelsDocumentShape(value) {
|
|
44821
45099
|
if (!isPlainRecord(value)) throw new Error("models.json must be an object");
|
|
44822
|
-
assertOnlyKeys(value, ["$schema", "profiles", "remoteCatalogs", "defaults"], "models.json");
|
|
45100
|
+
assertOnlyKeys(value, ["$schema", "profiles", "remoteCatalogs", "defaults", "modelOverrides"], "models.json");
|
|
44823
45101
|
if (value.$schema !== void 0 && (typeof value.$schema !== "string" || !value.$schema)) throw new Error("models.json $schema must be a non-empty string");
|
|
44824
45102
|
const hasProfiles = Object.prototype.hasOwnProperty.call(value, "profiles");
|
|
44825
45103
|
const hasRemoteCatalogs = Object.prototype.hasOwnProperty.call(value, "remoteCatalogs");
|
|
@@ -44832,6 +45110,7 @@ function validateModelsDocumentShape(value) {
|
|
|
44832
45110
|
validateProfileConfig(profileId, profile);
|
|
44833
45111
|
}
|
|
44834
45112
|
}
|
|
45113
|
+
validateModelOverrides(value.modelOverrides);
|
|
44835
45114
|
if (value.defaults !== void 0) {
|
|
44836
45115
|
if (!isPlainRecord(value.defaults)) throw new Error("models.json defaults must be an object");
|
|
44837
45116
|
assertOnlyKeys(value.defaults, ["provider", "modelId", "modelClasses", "toolModels"], "models.json defaults");
|
|
@@ -44916,6 +45195,8 @@ function validateCompat(value, label) {
|
|
|
44916
45195
|
"requiresAssistantAfterToolResult",
|
|
44917
45196
|
"requiresThinkingAsText",
|
|
44918
45197
|
"supportsStrictMode",
|
|
45198
|
+
"streamRequiresDone",
|
|
45199
|
+
"streamRequiresFinishReason",
|
|
44919
45200
|
"cacheCapability"
|
|
44920
45201
|
], label);
|
|
44921
45202
|
if (value.forcedReasoningEffort !== void 0 && value.forcedReasoningEffort !== "none") {
|
|
@@ -44929,7 +45210,9 @@ function validateCompat(value, label) {
|
|
|
44929
45210
|
"requiresToolResultName",
|
|
44930
45211
|
"requiresAssistantAfterToolResult",
|
|
44931
45212
|
"requiresThinkingAsText",
|
|
44932
|
-
"supportsStrictMode"
|
|
45213
|
+
"supportsStrictMode",
|
|
45214
|
+
"streamRequiresDone",
|
|
45215
|
+
"streamRequiresFinishReason"
|
|
44933
45216
|
]) assertOptionalBoolean(value[field], `${label}.${field}`);
|
|
44934
45217
|
if (value.maxTokensField !== void 0 && value.maxTokensField !== "max_completion_tokens" && value.maxTokensField !== "max_tokens") {
|
|
44935
45218
|
throw new Error(`${label}.maxTokensField is invalid`);
|
|
@@ -45108,6 +45391,46 @@ async function readResponseTextBounded(response, maxBytes) {
|
|
|
45108
45391
|
reader.releaseLock();
|
|
45109
45392
|
}
|
|
45110
45393
|
}
|
|
45394
|
+
function deepMergePlainRecords(base, patch) {
|
|
45395
|
+
const result = isPlainRecord(base) ? { ...base } : {};
|
|
45396
|
+
if (!isPlainRecord(patch)) return result;
|
|
45397
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
45398
|
+
const current = result[key];
|
|
45399
|
+
result[key] = isPlainRecord(current) && isPlainRecord(value) ? deepMergePlainRecords(current, value) : value;
|
|
45400
|
+
}
|
|
45401
|
+
return result;
|
|
45402
|
+
}
|
|
45403
|
+
function validateModelOverrides(value) {
|
|
45404
|
+
if (value === void 0) return;
|
|
45405
|
+
if (!isPlainRecord(value)) throw new Error("models.json modelOverrides must be an object");
|
|
45406
|
+
for (const [key, override] of Object.entries(value)) {
|
|
45407
|
+
if (!/^[^\s/]+\/[^\s/]+$/.test(key)) throw new Error(`models.json modelOverrides key must be "provider/modelId": ${key}`);
|
|
45408
|
+
if (!isPlainRecord(override)) throw new Error(`models.json modelOverrides["${key}"] must be an object`);
|
|
45409
|
+
assertOnlyKeys(override, [...MODEL_OVERRIDE_KEYS], `models.json modelOverrides["${key}"]`);
|
|
45410
|
+
if (override.name !== void 0 && (typeof override.name !== "string" || !override.name.trim())) throw new Error(`models.json modelOverrides["${key}"].name must be a non-empty string`);
|
|
45411
|
+
if (override.displayName !== void 0 && (typeof override.displayName !== "string" || !override.displayName.trim())) throw new Error(`models.json modelOverrides["${key}"].displayName must be a non-empty string`);
|
|
45412
|
+
if (override.reasoning !== void 0 && typeof override.reasoning !== "boolean") throw new Error(`models.json modelOverrides["${key}"].reasoning must be a boolean`);
|
|
45413
|
+
if (override.input !== void 0 && (!Array.isArray(override.input) || override.input.length === 0 || override.input.some((kind) => !["text", "image", "audio", "video"].includes(String(kind))))) throw new Error(`models.json modelOverrides["${key}"].input is invalid`);
|
|
45414
|
+
if (override.contextWindow !== void 0 && (!Number.isInteger(override.contextWindow) || Number(override.contextWindow) < 1)) throw new Error(`models.json modelOverrides["${key}"].contextWindow is invalid`);
|
|
45415
|
+
if (override.maxTokens !== void 0 && (!Number.isInteger(override.maxTokens) || Number(override.maxTokens) < 1)) throw new Error(`models.json modelOverrides["${key}"].maxTokens is invalid`);
|
|
45416
|
+
if (override.cost !== void 0) {
|
|
45417
|
+
if (!isPlainRecord(override.cost)) throw new Error(`models.json modelOverrides["${key}"].cost must be an object`);
|
|
45418
|
+
for (const field of ["input", "output", "cacheRead", "cacheWrite"]) {
|
|
45419
|
+
if (override.cost[field] !== void 0 && (typeof override.cost[field] !== "number" || Number.isNaN(override.cost[field]))) throw new Error(`models.json modelOverrides["${key}"].cost.${field} must be a number`);
|
|
45420
|
+
}
|
|
45421
|
+
}
|
|
45422
|
+
if (override.headers !== void 0) {
|
|
45423
|
+
if (!isPlainRecord(override.headers)) throw new Error(`models.json modelOverrides["${key}"].headers must be an object`);
|
|
45424
|
+
for (const [headerName, headerValue] of Object.entries(override.headers)) {
|
|
45425
|
+
if (typeof headerValue !== "string") throw new Error(`models.json modelOverrides["${key}"].headers.${headerName} must be a string`);
|
|
45426
|
+
}
|
|
45427
|
+
}
|
|
45428
|
+
validateCompat(override.compat, `models.json modelOverrides["${key}"].compat`);
|
|
45429
|
+
validateCacheCapability(override.cacheCapability, `models.json modelOverrides["${key}"].cacheCapability`);
|
|
45430
|
+
validateWebSearchCapability(override.webSearch, `models.json modelOverrides["${key}"].webSearch`);
|
|
45431
|
+
validateFileCapabilities(override.fileCapabilities, `models.json modelOverrides["${key}"].fileCapabilities`);
|
|
45432
|
+
}
|
|
45433
|
+
}
|
|
45111
45434
|
function validateProfileConfig(profileId, profileConfig) {
|
|
45112
45435
|
if (!isPlainRecord(profileConfig)) throw new Error(`Profile "${profileId}" must be an object.`);
|
|
45113
45436
|
assertOnlyKeys(profileConfig, [
|
|
@@ -45202,12 +45525,14 @@ var ModelRegistry = class {
|
|
|
45202
45525
|
modelsPath;
|
|
45203
45526
|
configDefaults;
|
|
45204
45527
|
modelOrder = [];
|
|
45528
|
+
modelOverrides = {};
|
|
45529
|
+
extensionOAuthProviders = /* @__PURE__ */ new Map();
|
|
45205
45530
|
usingExternalProviders = false;
|
|
45206
45531
|
localProfileIds = /* @__PURE__ */ new Set();
|
|
45207
45532
|
remoteCredentialEnvByProvider = /* @__PURE__ */ new Map();
|
|
45208
45533
|
remoteCatalogByProvider = /* @__PURE__ */ new Map();
|
|
45209
45534
|
remoteCredentialFingerprintByCatalog = /* @__PURE__ */ new Map();
|
|
45210
|
-
constructor(authStorage, modelsPath =
|
|
45535
|
+
constructor(authStorage, modelsPath = path3.join(getConfigDir(), "models.json")) {
|
|
45211
45536
|
this.authStorage = authStorage;
|
|
45212
45537
|
this.modelsPath = modelsPath;
|
|
45213
45538
|
this.load();
|
|
@@ -45228,6 +45553,7 @@ var ModelRegistry = class {
|
|
|
45228
45553
|
this.loadError = void 0;
|
|
45229
45554
|
this.models.clear();
|
|
45230
45555
|
this.modelOrder = [];
|
|
45556
|
+
this.modelOverrides = {};
|
|
45231
45557
|
this.configDefaults = void 0;
|
|
45232
45558
|
this.usingExternalProviders = false;
|
|
45233
45559
|
this.localProfileIds.clear();
|
|
@@ -45240,16 +45566,17 @@ var ModelRegistry = class {
|
|
|
45240
45566
|
this.loadError = error instanceof Error ? error.message : String(error);
|
|
45241
45567
|
return;
|
|
45242
45568
|
}
|
|
45243
|
-
if (!
|
|
45569
|
+
if (!fs3.existsSync(this.modelsPath)) {
|
|
45244
45570
|
return;
|
|
45245
45571
|
}
|
|
45246
45572
|
try {
|
|
45247
|
-
const raw = JSON.parse(
|
|
45573
|
+
const raw = JSON.parse(fs3.readFileSync(this.modelsPath, "utf-8"));
|
|
45248
45574
|
if (raw && typeof raw === "object" && "providers" in raw) {
|
|
45249
45575
|
throw new Error('Legacy models.json format is no longer supported. Use top-level "profiles".');
|
|
45250
45576
|
}
|
|
45251
45577
|
validateModelsDocumentShape(raw);
|
|
45252
45578
|
const remotes = validatedRemoteCatalogs(raw.remoteCatalogs);
|
|
45579
|
+
this.modelOverrides = raw.modelOverrides ?? {};
|
|
45253
45580
|
const activeRemoteSecrets = configuredRemoteCredentialValues(raw);
|
|
45254
45581
|
scrubActiveSecretsFromRemoteCaches(this.modelsPath, activeRemoteSecrets);
|
|
45255
45582
|
const configuredProviders = Object.entries(raw.profiles || {});
|
|
@@ -45335,10 +45662,40 @@ var ModelRegistry = class {
|
|
|
45335
45662
|
this.registerRemoteProfile(provider, profile, identity.apiKeyEnv, owner);
|
|
45336
45663
|
}
|
|
45337
45664
|
}
|
|
45665
|
+
this.applyModelOverrides();
|
|
45338
45666
|
} catch (error) {
|
|
45339
45667
|
this.loadError = error instanceof Error ? error.message : String(error);
|
|
45340
45668
|
}
|
|
45341
45669
|
}
|
|
45670
|
+
/**
|
|
45671
|
+
* Re-apply models.json modelOverrides after any (re)materialization pass
|
|
45672
|
+
* (initial load, remote catalog refresh). Overrides patch descriptive
|
|
45673
|
+
* fields only; nested plain objects deep-merge, arrays/scalars replace.
|
|
45674
|
+
*/
|
|
45675
|
+
applyModelOverrides() {
|
|
45676
|
+
for (const [key, override] of Object.entries(this.modelOverrides)) {
|
|
45677
|
+
const slash = key.indexOf("/");
|
|
45678
|
+
if (slash <= 0) continue;
|
|
45679
|
+
const provider = key.slice(0, slash);
|
|
45680
|
+
const modelId = key.slice(slash + 1);
|
|
45681
|
+
const existing = this.models.get(provider)?.get(modelId);
|
|
45682
|
+
if (!existing) continue;
|
|
45683
|
+
const patched = { ...existing };
|
|
45684
|
+
if (override.name !== void 0) patched.name = override.name;
|
|
45685
|
+
if (override.displayName !== void 0) patched.displayName = override.displayName;
|
|
45686
|
+
if (override.reasoning !== void 0) patched.reasoning = override.reasoning;
|
|
45687
|
+
if (override.input !== void 0) patched.input = [...override.input];
|
|
45688
|
+
if (override.contextWindow !== void 0) patched.contextWindow = override.contextWindow;
|
|
45689
|
+
if (override.maxTokens !== void 0) patched.maxTokens = override.maxTokens;
|
|
45690
|
+
if (override.cost !== void 0) patched.cost = { ...existing.cost, ...override.cost };
|
|
45691
|
+
if (override.headers !== void 0) patched.headers = { ...existing.headers, ...override.headers };
|
|
45692
|
+
if (override.compat !== void 0) patched.compat = deepMergePlainRecords(existing.compat, override.compat);
|
|
45693
|
+
if (override.cacheCapability !== void 0) patched.cacheCapability = { ...existing.cacheCapability, ...override.cacheCapability };
|
|
45694
|
+
if (override.webSearch !== void 0) patched.webSearch = { ...existing.webSearch, ...override.webSearch };
|
|
45695
|
+
if (override.fileCapabilities !== void 0) patched.fileCapabilities = deepMergePlainRecords(existing.fileCapabilities, override.fileCapabilities);
|
|
45696
|
+
this.upsert(patched);
|
|
45697
|
+
}
|
|
45698
|
+
}
|
|
45342
45699
|
registerRemoteProfile(provider, providerConfig, credentialEnv, catalogId) {
|
|
45343
45700
|
if (this.localProfileIds.has(provider)) return;
|
|
45344
45701
|
const existingCatalog = this.remoteCatalogByProvider.get(provider);
|
|
@@ -45398,27 +45755,28 @@ var ModelRegistry = class {
|
|
|
45398
45755
|
for (const [provider, profile] of candidates) {
|
|
45399
45756
|
this.registerRemoteProfile(provider, profile, credentialEnv, catalogId);
|
|
45400
45757
|
}
|
|
45758
|
+
this.applyModelOverrides();
|
|
45401
45759
|
}
|
|
45402
45760
|
writeRemoteCache(remote, fingerprint, value) {
|
|
45403
45761
|
const directory = safeRemoteCacheDirectory(this.modelsPath, true);
|
|
45404
45762
|
const target = remoteCachePath(this.modelsPath, remote, fingerprint);
|
|
45405
|
-
if (
|
|
45406
|
-
const stat2 =
|
|
45763
|
+
if (fs3.existsSync(target)) {
|
|
45764
|
+
const stat2 = fs3.lstatSync(target);
|
|
45407
45765
|
if (stat2.isSymbolicLink() || !stat2.isFile()) throw new Error(`remote catalog cache entry must be a regular file: ${target}`);
|
|
45408
45766
|
}
|
|
45409
|
-
const temporary =
|
|
45767
|
+
const temporary = path3.join(directory, `.${path3.basename(target)}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`);
|
|
45410
45768
|
try {
|
|
45411
|
-
|
|
45769
|
+
fs3.writeFileSync(temporary, `${JSON.stringify(value)}
|
|
45412
45770
|
`, { flag: "wx", mode: 384 });
|
|
45413
|
-
|
|
45771
|
+
fs3.renameSync(temporary, target);
|
|
45414
45772
|
const tombstone = remoteCacheTombstonePath(this.modelsPath, remote, fingerprint);
|
|
45415
|
-
if (
|
|
45773
|
+
if (fs3.existsSync(tombstone)) fs3.unlinkSync(tombstone);
|
|
45416
45774
|
} finally {
|
|
45417
|
-
if (
|
|
45775
|
+
if (fs3.existsSync(temporary)) fs3.unlinkSync(temporary);
|
|
45418
45776
|
}
|
|
45419
45777
|
}
|
|
45420
45778
|
refreshRemoteCatalogs() {
|
|
45421
|
-
const queueKey =
|
|
45779
|
+
const queueKey = path3.resolve(this.modelsPath);
|
|
45422
45780
|
const previous = remoteRefreshTails.get(queueKey) ?? Promise.resolve();
|
|
45423
45781
|
const refresh = previous.then(() => this.performRemoteCatalogRefresh());
|
|
45424
45782
|
const tail = refresh.catch(() => void 0);
|
|
@@ -45443,14 +45801,14 @@ var ModelRegistry = class {
|
|
|
45443
45801
|
this.loadError = error instanceof Error ? error.message : String(error);
|
|
45444
45802
|
return;
|
|
45445
45803
|
}
|
|
45446
|
-
if (!
|
|
45804
|
+
if (!fs3.existsSync(this.modelsPath)) {
|
|
45447
45805
|
for (const owner of new Set(this.remoteCatalogByProvider.values())) this.removeRemoteCatalogProfiles(owner);
|
|
45448
45806
|
this.remoteCredentialFingerprintByCatalog.clear();
|
|
45449
45807
|
return;
|
|
45450
45808
|
}
|
|
45451
45809
|
let config;
|
|
45452
45810
|
try {
|
|
45453
|
-
const decoded = JSON.parse(
|
|
45811
|
+
const decoded = JSON.parse(fs3.readFileSync(this.modelsPath, "utf8"));
|
|
45454
45812
|
validateModelsDocumentShape(decoded);
|
|
45455
45813
|
config = decoded;
|
|
45456
45814
|
} catch {
|
|
@@ -45458,6 +45816,7 @@ var ModelRegistry = class {
|
|
|
45458
45816
|
this.remoteCredentialFingerprintByCatalog.clear();
|
|
45459
45817
|
return;
|
|
45460
45818
|
}
|
|
45819
|
+
this.modelOverrides = config.modelOverrides ?? {};
|
|
45461
45820
|
let remotes;
|
|
45462
45821
|
try {
|
|
45463
45822
|
remotes = validatedRemoteCatalogs(config.remoteCatalogs);
|
|
@@ -45739,11 +46098,131 @@ var ModelRegistry = class {
|
|
|
45739
46098
|
if (remoteEnv) return typeof process !== "undefined" ? process.env?.[remoteEnv] : void 0;
|
|
45740
46099
|
return this.authStorage.getApiKey(provider);
|
|
45741
46100
|
}
|
|
46101
|
+
/**
|
|
46102
|
+
* Register a provider at runtime (extension API). Not persisted to
|
|
46103
|
+
* models.json: runtime registrations live for the process unless the
|
|
46104
|
+
* extension registers them again. Returns an unregister handle that
|
|
46105
|
+
* restores the provider's previous state (models, order, env binding).
|
|
46106
|
+
*
|
|
46107
|
+
* When the provider already exists (local profile or remote catalog),
|
|
46108
|
+
* models are merged by id: registered models upsert over existing entries
|
|
46109
|
+
* with the same id; existing entries not named in `config.models` survive.
|
|
46110
|
+
* baseUrl/api/headers patch every model of that provider (existing and
|
|
46111
|
+
* new) when provided.
|
|
46112
|
+
*/
|
|
46113
|
+
registerProvider(provider, config) {
|
|
46114
|
+
validateExtensionProviderConfig(provider, config);
|
|
46115
|
+
const previousModels = this.models.get(provider) ? new Map(this.models.get(provider)) : void 0;
|
|
46116
|
+
const previousOrder = [...this.modelOrder];
|
|
46117
|
+
const previousEnvVar = this.authStorage.getProviderEnvVar(provider);
|
|
46118
|
+
if (config.apiKey) {
|
|
46119
|
+
this.authStorage.setRuntimeApiKey(provider, config.apiKey);
|
|
46120
|
+
}
|
|
46121
|
+
if (config.apiKeyEnv) {
|
|
46122
|
+
this.authStorage.setProviderEnvVar(provider, config.apiKeyEnv);
|
|
46123
|
+
}
|
|
46124
|
+
const existing = this.models.get(provider);
|
|
46125
|
+
if (existing && (config.baseUrl || config.api || config.headers)) {
|
|
46126
|
+
for (const model of existing.values()) {
|
|
46127
|
+
this.upsert({
|
|
46128
|
+
...model,
|
|
46129
|
+
baseUrl: config.baseUrl || model.baseUrl,
|
|
46130
|
+
api: config.api || model.api,
|
|
46131
|
+
headers: config.headers ? { ...model.headers, ...config.headers } : model.headers
|
|
46132
|
+
});
|
|
46133
|
+
}
|
|
46134
|
+
}
|
|
46135
|
+
for (const customModel of config.models ?? []) {
|
|
46136
|
+
const baseModel = this.models.get(provider)?.get(customModel.id);
|
|
46137
|
+
this.upsert({
|
|
46138
|
+
id: customModel.id,
|
|
46139
|
+
name: customModel.name || baseModel?.name || customModel.id,
|
|
46140
|
+
api: config.api || baseModel?.api || "openai-completions",
|
|
46141
|
+
provider,
|
|
46142
|
+
baseUrl: config.baseUrl || baseModel?.baseUrl || "",
|
|
46143
|
+
reasoning: customModel.reasoning ?? baseModel?.reasoning ?? false,
|
|
46144
|
+
input: customModel.input || baseModel?.input || ["text"],
|
|
46145
|
+
cost: customModel.cost || baseModel?.cost || { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
46146
|
+
contextWindow: customModel.contextWindow || baseModel?.contextWindow || 128e3,
|
|
46147
|
+
maxTokens: customModel.maxTokens || baseModel?.maxTokens || 8192,
|
|
46148
|
+
apiKeyEnv: config.apiKeyEnv || baseModel?.apiKeyEnv,
|
|
46149
|
+
displayName: customModel.displayName || baseModel?.displayName || provider,
|
|
46150
|
+
headers: config.headers ? { ...baseModel?.headers, ...config.headers, ...customModel.headers } : customModel.headers || baseModel?.headers,
|
|
46151
|
+
compat: customModel.compat || baseModel?.compat,
|
|
46152
|
+
cacheCapability: customModel.cacheCapability || baseModel?.cacheCapability,
|
|
46153
|
+
webSearch: customModel.webSearch || baseModel?.webSearch,
|
|
46154
|
+
fileCapabilities: customModel.fileCapabilities || baseModel?.fileCapabilities
|
|
46155
|
+
});
|
|
46156
|
+
}
|
|
46157
|
+
this.applyModelOverrides();
|
|
46158
|
+
this.usingExternalProviders = true;
|
|
46159
|
+
const registeredOAuth = config.oauth;
|
|
46160
|
+
if (registeredOAuth) this.extensionOAuthProviders.set(provider, registeredOAuth);
|
|
46161
|
+
return () => {
|
|
46162
|
+
if (previousModels) this.models.set(provider, previousModels);
|
|
46163
|
+
else this.models.delete(provider);
|
|
46164
|
+
this.modelOrder = previousOrder;
|
|
46165
|
+
this.authStorage.setRuntimeApiKey(provider, void 0);
|
|
46166
|
+
this.authStorage.setProviderEnvVar(provider, previousEnvVar);
|
|
46167
|
+
if (registeredOAuth) this.extensionOAuthProviders.delete(provider);
|
|
46168
|
+
this.applyModelOverrides();
|
|
46169
|
+
};
|
|
46170
|
+
}
|
|
46171
|
+
/** OAuth flow declared by an extension-registered provider, if any. */
|
|
46172
|
+
getExtensionOAuth(provider) {
|
|
46173
|
+
return this.extensionOAuthProviders.get(provider);
|
|
46174
|
+
}
|
|
46175
|
+
/**
|
|
46176
|
+
* Restore persisted OAuth credentials now that extensions have registered
|
|
46177
|
+
* their providers: refresh expired tokens when the extension declares
|
|
46178
|
+
* refreshToken, and drop the runtime binding when a token cannot be
|
|
46179
|
+
* recovered (getApiKey then reports the provider as unauthenticated).
|
|
46180
|
+
* Never throws; returns per-provider outcomes for the host to surface.
|
|
46181
|
+
*/
|
|
46182
|
+
async restorePersistedOAuth() {
|
|
46183
|
+
const authStorage = this.authStorage;
|
|
46184
|
+
const results = [];
|
|
46185
|
+
for (const provider of authStorage.getOAuthProviderNames()) {
|
|
46186
|
+
const credentials = authStorage.getOAuthCredentials(provider);
|
|
46187
|
+
if (!credentials?.access) continue;
|
|
46188
|
+
const expired = credentials.expires !== void 0 && credentials.expires <= Date.now() + OAUTH_RESTORE_LEEWAY_MS;
|
|
46189
|
+
if (!expired) continue;
|
|
46190
|
+
const oauth = this.extensionOAuthProviders.get(provider);
|
|
46191
|
+
if (!oauth?.refreshToken || !credentials.refresh) {
|
|
46192
|
+
authStorage.setRuntimeApiKey(provider, void 0);
|
|
46193
|
+
results.push({ provider, action: "not-refreshable", detail: "token expired and no refresh flow" });
|
|
46194
|
+
continue;
|
|
46195
|
+
}
|
|
46196
|
+
try {
|
|
46197
|
+
const next = await withTimeout(
|
|
46198
|
+
oauth.refreshToken({
|
|
46199
|
+
access: credentials.access,
|
|
46200
|
+
refresh: credentials.refresh,
|
|
46201
|
+
expires: credentials.expires
|
|
46202
|
+
}),
|
|
46203
|
+
OAUTH_REFRESH_TIMEOUT_MS,
|
|
46204
|
+
`${provider} refreshToken timed out after ${OAUTH_REFRESH_TIMEOUT_MS}ms`
|
|
46205
|
+
);
|
|
46206
|
+
const merged = { ...credentials, ...next };
|
|
46207
|
+
authStorage.setOAuthCredentials(provider, merged);
|
|
46208
|
+
authStorage.setRuntimeApiKey(provider, merged.access);
|
|
46209
|
+
results.push({ provider, action: "refreshed" });
|
|
46210
|
+
} catch (error) {
|
|
46211
|
+
authStorage.setRuntimeApiKey(provider, void 0);
|
|
46212
|
+
results.push({ provider, action: "refresh-failed", detail: error instanceof Error ? error.message : String(error) });
|
|
46213
|
+
}
|
|
46214
|
+
}
|
|
46215
|
+
return results;
|
|
46216
|
+
}
|
|
46217
|
+
/** Credential store backing this registry (for OAuth persistence). */
|
|
46218
|
+
getAuthStorage() {
|
|
46219
|
+
return this.authStorage;
|
|
46220
|
+
}
|
|
45742
46221
|
};
|
|
45743
46222
|
|
|
45744
46223
|
// src/core/settings-manager.ts
|
|
45745
|
-
import * as
|
|
45746
|
-
import * as
|
|
46224
|
+
import * as fs4 from "fs";
|
|
46225
|
+
import * as path4 from "path";
|
|
45747
46226
|
var SettingsManager = class {
|
|
45748
46227
|
settingsPath;
|
|
45749
46228
|
legacyConfigPath;
|
|
@@ -45757,9 +46236,9 @@ var SettingsManager = class {
|
|
|
45757
46236
|
this.legacyConfig = this.loadLegacyConfigFile();
|
|
45758
46237
|
}
|
|
45759
46238
|
readJson(filePath) {
|
|
45760
|
-
if (!
|
|
46239
|
+
if (!fs4.existsSync(filePath)) return null;
|
|
45761
46240
|
try {
|
|
45762
|
-
return JSON.parse(
|
|
46241
|
+
return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
|
|
45763
46242
|
} catch {
|
|
45764
46243
|
return null;
|
|
45765
46244
|
}
|
|
@@ -45771,19 +46250,19 @@ var SettingsManager = class {
|
|
|
45771
46250
|
return this.readJson(this.legacyConfigPath) || {};
|
|
45772
46251
|
}
|
|
45773
46252
|
ensureDir() {
|
|
45774
|
-
|
|
46253
|
+
fs4.mkdirSync(getConfigDir(), { recursive: true });
|
|
45775
46254
|
}
|
|
45776
46255
|
writeSettings() {
|
|
45777
46256
|
this.ensureDir();
|
|
45778
|
-
|
|
46257
|
+
fs4.writeFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2));
|
|
45779
46258
|
}
|
|
45780
46259
|
writeSettingsValue(settings) {
|
|
45781
46260
|
this.ensureDir();
|
|
45782
|
-
|
|
46261
|
+
fs4.writeFileSync(this.settingsPath, JSON.stringify(settings, null, 2));
|
|
45783
46262
|
}
|
|
45784
46263
|
writeLegacyConfig() {
|
|
45785
46264
|
this.ensureDir();
|
|
45786
|
-
|
|
46265
|
+
fs4.writeFileSync(this.legacyConfigPath, JSON.stringify(this.legacyConfig, null, 2));
|
|
45787
46266
|
}
|
|
45788
46267
|
getLegacyApiKey() {
|
|
45789
46268
|
return this.legacyConfig.apiKey;
|
|
@@ -45832,6 +46311,9 @@ var SettingsManager = class {
|
|
|
45832
46311
|
}
|
|
45833
46312
|
return "auto";
|
|
45834
46313
|
}
|
|
46314
|
+
getBellNotificationsEnabled() {
|
|
46315
|
+
return this.settings.notifications?.bell !== false;
|
|
46316
|
+
}
|
|
45835
46317
|
// ==========================================================================
|
|
45836
46318
|
// Extension enablement (user ~/.pie/settings.json + project ./.pie/settings.json)
|
|
45837
46319
|
// ==========================================================================
|
|
@@ -45840,8 +46322,8 @@ var SettingsManager = class {
|
|
|
45840
46322
|
}
|
|
45841
46323
|
writeProjectSettings(cwd, settings) {
|
|
45842
46324
|
const settingsPath = getProjectSettingsPath(cwd);
|
|
45843
|
-
|
|
45844
|
-
|
|
46325
|
+
fs4.mkdirSync(path4.dirname(settingsPath), { recursive: true });
|
|
46326
|
+
fs4.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
45845
46327
|
}
|
|
45846
46328
|
/** Raw extension enablement map for one scope. */
|
|
45847
46329
|
getExtensionSettings(scope = "user", cwd = process.cwd()) {
|
|
@@ -45915,19 +46397,19 @@ function checkShell() {
|
|
|
45915
46397
|
}
|
|
45916
46398
|
function canWriteDirectory(dir) {
|
|
45917
46399
|
try {
|
|
45918
|
-
|
|
45919
|
-
const probe =
|
|
45920
|
-
|
|
45921
|
-
|
|
46400
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
46401
|
+
const probe = path5.join(dir, `.pie-doctor-${process.pid}-${Date.now()}`);
|
|
46402
|
+
fs5.writeFileSync(probe, "ok", "utf8");
|
|
46403
|
+
fs5.rmSync(probe, { force: true });
|
|
45922
46404
|
return { ok: true };
|
|
45923
46405
|
} catch (error) {
|
|
45924
46406
|
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
45925
46407
|
}
|
|
45926
46408
|
}
|
|
45927
46409
|
function isExecutable(candidate) {
|
|
45928
|
-
if (!candidate || !
|
|
46410
|
+
if (!candidate || !fs5.existsSync(candidate)) return false;
|
|
45929
46411
|
try {
|
|
45930
|
-
|
|
46412
|
+
fs5.accessSync(candidate, fs5.constants.X_OK);
|
|
45931
46413
|
return true;
|
|
45932
46414
|
} catch {
|
|
45933
46415
|
return os.platform() === "win32";
|
|
@@ -45937,7 +46419,7 @@ function findOnPath(names) {
|
|
|
45937
46419
|
for (const dir of (process.env.PATH || "").split(delimiter)) {
|
|
45938
46420
|
if (!dir) continue;
|
|
45939
46421
|
for (const name of names) {
|
|
45940
|
-
const candidate =
|
|
46422
|
+
const candidate = path5.join(dir, name);
|
|
45941
46423
|
if (isExecutable(candidate)) return candidate;
|
|
45942
46424
|
}
|
|
45943
46425
|
}
|
|
@@ -45953,10 +46435,10 @@ function findDoctorChromeExecutable() {
|
|
|
45953
46435
|
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
45954
46436
|
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
|
|
45955
46437
|
] : os.platform() === "win32" ? [
|
|
45956
|
-
|
|
45957
|
-
|
|
45958
|
-
|
|
45959
|
-
|
|
46438
|
+
path5.join(process.env.PROGRAMFILES || "C:\\Program Files", "Google", "Chrome", "Application", "chrome.exe"),
|
|
46439
|
+
path5.join(process.env["PROGRAMFILES(X86)"] || "C:\\Program Files (x86)", "Google", "Chrome", "Application", "chrome.exe"),
|
|
46440
|
+
path5.join(process.env.LOCALAPPDATA || path5.join(home, "AppData", "Local"), "Google", "Chrome", "Application", "chrome.exe"),
|
|
46441
|
+
path5.join(process.env.PROGRAMFILES || "C:\\Program Files", "Microsoft", "Edge", "Application", "msedge.exe")
|
|
45960
46442
|
] : [
|
|
45961
46443
|
"/usr/bin/google-chrome",
|
|
45962
46444
|
"/usr/bin/google-chrome-stable",
|
|
@@ -46005,7 +46487,7 @@ function checkPlaywrightBrowser() {
|
|
|
46005
46487
|
} catch {
|
|
46006
46488
|
executablePath = void 0;
|
|
46007
46489
|
}
|
|
46008
|
-
if (executablePath &&
|
|
46490
|
+
if (executablePath && fs5.existsSync(executablePath)) {
|
|
46009
46491
|
return {
|
|
46010
46492
|
id: "playwright_browser",
|
|
46011
46493
|
label: "Playwright browser",
|
|
@@ -46014,7 +46496,7 @@ function checkPlaywrightBrowser() {
|
|
|
46014
46496
|
details: { executablePath }
|
|
46015
46497
|
};
|
|
46016
46498
|
}
|
|
46017
|
-
const skillWrapper =
|
|
46499
|
+
const skillWrapper = path5.join(getBuiltinDir(), "skills", "browser-tools", "playwright-cli.js");
|
|
46018
46500
|
return {
|
|
46019
46501
|
id: "playwright_browser",
|
|
46020
46502
|
label: "Playwright browser",
|
|
@@ -46045,8 +46527,8 @@ function isLiveUnityInstance(instance, nowUnix = Math.floor(Date.now() / 1e3)) {
|
|
|
46045
46527
|
return isProcessAlive(Number(instance.pid || 0));
|
|
46046
46528
|
}
|
|
46047
46529
|
function checkUnityRegistry() {
|
|
46048
|
-
const registryDir =
|
|
46049
|
-
if (!
|
|
46530
|
+
const registryDir = path5.join(os.homedir(), ".pie-unity", "instances");
|
|
46531
|
+
if (!fs5.existsSync(registryDir)) {
|
|
46050
46532
|
return {
|
|
46051
46533
|
id: "unity_bridge",
|
|
46052
46534
|
label: "Unity bridge",
|
|
@@ -46057,12 +46539,12 @@ function checkUnityRegistry() {
|
|
|
46057
46539
|
}
|
|
46058
46540
|
try {
|
|
46059
46541
|
const nowUnix = Math.floor(Date.now() / 1e3);
|
|
46060
|
-
const files =
|
|
46542
|
+
const files = fs5.readdirSync(registryDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => path5.join(registryDir, entry.name));
|
|
46061
46543
|
let malformedFiles = 0;
|
|
46062
46544
|
let invalidFiles = 0;
|
|
46063
46545
|
const liveInstances = files.map((filePath) => {
|
|
46064
46546
|
try {
|
|
46065
|
-
const parsed = JSON.parse(
|
|
46547
|
+
const parsed = JSON.parse(fs5.readFileSync(filePath, "utf8").replace(/^\uFEFF/, ""));
|
|
46066
46548
|
if (!isRecord(parsed)) {
|
|
46067
46549
|
invalidFiles += 1;
|
|
46068
46550
|
return null;
|
|
@@ -46136,13 +46618,13 @@ async function runDoctor() {
|
|
|
46136
46618
|
const packageDir = getPackageDir();
|
|
46137
46619
|
let dir = packageDir;
|
|
46138
46620
|
let lockPath;
|
|
46139
|
-
while (dir !==
|
|
46140
|
-
const candidate =
|
|
46141
|
-
if (
|
|
46621
|
+
while (dir !== path5.dirname(dir)) {
|
|
46622
|
+
const candidate = path5.join(dir, "package-lock.json");
|
|
46623
|
+
if (fs5.existsSync(candidate)) {
|
|
46142
46624
|
lockPath = candidate;
|
|
46143
46625
|
break;
|
|
46144
46626
|
}
|
|
46145
|
-
dir =
|
|
46627
|
+
dir = path5.dirname(dir);
|
|
46146
46628
|
}
|
|
46147
46629
|
checks.push({
|
|
46148
46630
|
id: "package_lock",
|
|
@@ -46164,7 +46646,7 @@ async function runDoctor() {
|
|
|
46164
46646
|
message: result.ok ? `${dirPath} is writable.` : `${dirPath} is not writable: ${result.error}`
|
|
46165
46647
|
});
|
|
46166
46648
|
}
|
|
46167
|
-
const authStorage =
|
|
46649
|
+
const authStorage = AuthStorage.create();
|
|
46168
46650
|
const registry = new ModelRegistry(authStorage);
|
|
46169
46651
|
const loadError = registry.getLoadError();
|
|
46170
46652
|
const models = registry.getAll();
|
|
@@ -46305,10 +46787,10 @@ Disable or narrow capabilities:
|
|
|
46305
46787
|
}
|
|
46306
46788
|
|
|
46307
46789
|
// src/commands/models-config.ts
|
|
46308
|
-
import * as
|
|
46309
|
-
import * as
|
|
46790
|
+
import * as fs6 from "node:fs";
|
|
46791
|
+
import * as path6 from "node:path";
|
|
46310
46792
|
function getDefaultModelsPath() {
|
|
46311
|
-
return
|
|
46793
|
+
return path6.join(getConfigDir(), "models.json");
|
|
46312
46794
|
}
|
|
46313
46795
|
function createModelsTemplate() {
|
|
46314
46796
|
const template = {
|
|
@@ -46403,7 +46885,7 @@ function createModelsTemplate() {
|
|
|
46403
46885
|
`;
|
|
46404
46886
|
}
|
|
46405
46887
|
function resolveModelsPath(input) {
|
|
46406
|
-
return input ?
|
|
46888
|
+
return input ? path6.resolve(input) : getDefaultModelsPath();
|
|
46407
46889
|
}
|
|
46408
46890
|
function initModelsConfig(options = {}) {
|
|
46409
46891
|
const targetPath = resolveModelsPath(options.path);
|
|
@@ -46411,16 +46893,16 @@ function initModelsConfig(options = {}) {
|
|
|
46411
46893
|
if (options.stdout) {
|
|
46412
46894
|
return { path: targetPath, content, wrote: false };
|
|
46413
46895
|
}
|
|
46414
|
-
if (
|
|
46896
|
+
if (fs6.existsSync(targetPath) && !options.force) {
|
|
46415
46897
|
throw new Error(`models.json already exists: ${targetPath}. Use --force to overwrite, or --stdout to print the template.`);
|
|
46416
46898
|
}
|
|
46417
|
-
|
|
46418
|
-
|
|
46899
|
+
fs6.mkdirSync(path6.dirname(targetPath), { recursive: true });
|
|
46900
|
+
fs6.writeFileSync(targetPath, content, "utf8");
|
|
46419
46901
|
return { path: targetPath, content, wrote: true };
|
|
46420
46902
|
}
|
|
46421
46903
|
function validateModelsConfig(options = {}) {
|
|
46422
46904
|
const modelsPath = resolveModelsPath(options.path);
|
|
46423
|
-
if (!
|
|
46905
|
+
if (!fs6.existsSync(modelsPath)) {
|
|
46424
46906
|
return {
|
|
46425
46907
|
ok: false,
|
|
46426
46908
|
path: modelsPath,
|
|
@@ -46429,7 +46911,7 @@ function validateModelsConfig(options = {}) {
|
|
|
46429
46911
|
modelCount: 0
|
|
46430
46912
|
};
|
|
46431
46913
|
}
|
|
46432
|
-
const authStorage =
|
|
46914
|
+
const authStorage = AuthStorage.create();
|
|
46433
46915
|
const registry = new ModelRegistry(authStorage, modelsPath);
|
|
46434
46916
|
const loadError = registry.getLoadError();
|
|
46435
46917
|
if (loadError) {
|
|
@@ -46476,7 +46958,7 @@ function validateModelsConfig(options = {}) {
|
|
|
46476
46958
|
};
|
|
46477
46959
|
}
|
|
46478
46960
|
async function probeModelsConfig(options) {
|
|
46479
|
-
const registry = new ModelRegistry(
|
|
46961
|
+
const registry = new ModelRegistry(AuthStorage.create(), resolveModelsPath(options.path));
|
|
46480
46962
|
const loadError = registry.getLoadError();
|
|
46481
46963
|
if (loadError) {
|
|
46482
46964
|
return {
|
|
@@ -46569,7 +47051,7 @@ function parseModelsCommandArgs(args) {
|
|
|
46569
47051
|
}
|
|
46570
47052
|
|
|
46571
47053
|
// src/commands/sessions.ts
|
|
46572
|
-
import
|
|
47054
|
+
import fs7 from "node:fs";
|
|
46573
47055
|
|
|
46574
47056
|
// src/session-control.ts
|
|
46575
47057
|
var SessionControlError = class extends Error {
|
|
@@ -46714,15 +47196,15 @@ function buildForkResult(params) {
|
|
|
46714
47196
|
}
|
|
46715
47197
|
function pathToEntry(data, entryId) {
|
|
46716
47198
|
const byId = new Map(data.entries.map((entry) => [entry.id, entry]));
|
|
46717
|
-
const
|
|
47199
|
+
const path33 = [];
|
|
46718
47200
|
let current = entryId;
|
|
46719
47201
|
while (current) {
|
|
46720
47202
|
const entry = byId.get(current);
|
|
46721
47203
|
if (!entry) return [];
|
|
46722
|
-
|
|
47204
|
+
path33.unshift(entry);
|
|
46723
47205
|
current = entry.parentId;
|
|
46724
47206
|
}
|
|
46725
|
-
return
|
|
47207
|
+
return path33;
|
|
46726
47208
|
}
|
|
46727
47209
|
function cloneJson(value) {
|
|
46728
47210
|
return JSON.parse(JSON.stringify(value));
|
|
@@ -46968,7 +47450,7 @@ function cwdMatches(sessionCwd, requestedCwd) {
|
|
|
46968
47450
|
}
|
|
46969
47451
|
function realpathOrInput(value) {
|
|
46970
47452
|
try {
|
|
46971
|
-
return
|
|
47453
|
+
return fs7.realpathSync.native(value);
|
|
46972
47454
|
} catch {
|
|
46973
47455
|
return value;
|
|
46974
47456
|
}
|
|
@@ -47057,9 +47539,9 @@ function isRecord2(value) {
|
|
|
47057
47539
|
}
|
|
47058
47540
|
|
|
47059
47541
|
// src/extensions/loader.ts
|
|
47060
|
-
import * as
|
|
47542
|
+
import * as fs8 from "node:fs";
|
|
47061
47543
|
import * as os2 from "os";
|
|
47062
|
-
import * as
|
|
47544
|
+
import * as path7 from "path";
|
|
47063
47545
|
import { pathToFileURL } from "node:url";
|
|
47064
47546
|
|
|
47065
47547
|
// src/command-tree.ts
|
|
@@ -47072,19 +47554,19 @@ var CommandTree = class {
|
|
|
47072
47554
|
* register(["session", "new"], { description, handler })
|
|
47073
47555
|
* register(["tools", "subagent", "spawn", "local"], { description, handler })
|
|
47074
47556
|
*/
|
|
47075
|
-
register(
|
|
47076
|
-
if (
|
|
47557
|
+
register(path33, info) {
|
|
47558
|
+
if (path33.length === 0) {
|
|
47077
47559
|
throw new Error("Command path cannot be empty");
|
|
47078
47560
|
}
|
|
47079
47561
|
let current = this.root;
|
|
47080
47562
|
const fullPath = [];
|
|
47081
|
-
for (let i = 0; i <
|
|
47082
|
-
const segment =
|
|
47563
|
+
for (let i = 0; i < path33.length; i++) {
|
|
47564
|
+
const segment = path33[i];
|
|
47083
47565
|
fullPath.push(segment);
|
|
47084
47566
|
if (!current.children) {
|
|
47085
47567
|
current.children = [];
|
|
47086
47568
|
}
|
|
47087
|
-
const isLast = i ===
|
|
47569
|
+
const isLast = i === path33.length - 1;
|
|
47088
47570
|
let node = current.children.find((n) => n.name === segment);
|
|
47089
47571
|
if (!node) {
|
|
47090
47572
|
node = {
|
|
@@ -47114,31 +47596,31 @@ var CommandTree = class {
|
|
|
47114
47596
|
/**
|
|
47115
47597
|
* Find a node by path
|
|
47116
47598
|
*/
|
|
47117
|
-
find(
|
|
47118
|
-
if (
|
|
47599
|
+
find(path33) {
|
|
47600
|
+
if (path33.length === 0) {
|
|
47119
47601
|
return this.root;
|
|
47120
47602
|
}
|
|
47121
|
-
const key =
|
|
47603
|
+
const key = path33.join("/");
|
|
47122
47604
|
return this.pathCache.get(key) || null;
|
|
47123
47605
|
}
|
|
47124
47606
|
/**
|
|
47125
47607
|
* Get children of a path
|
|
47126
47608
|
*/
|
|
47127
|
-
getChildren(
|
|
47128
|
-
const node = this.find(
|
|
47609
|
+
getChildren(path33) {
|
|
47610
|
+
const node = this.find(path33);
|
|
47129
47611
|
return (node?.children || []).filter((child) => !child.hidden);
|
|
47130
47612
|
}
|
|
47131
47613
|
/**
|
|
47132
47614
|
* Check if a path exists (as category or command)
|
|
47133
47615
|
*/
|
|
47134
|
-
exists(
|
|
47135
|
-
return this.find(
|
|
47616
|
+
exists(path33) {
|
|
47617
|
+
return this.find(path33) !== null;
|
|
47136
47618
|
}
|
|
47137
47619
|
/**
|
|
47138
47620
|
* Check if path is a category (has children)
|
|
47139
47621
|
*/
|
|
47140
|
-
isCategory(
|
|
47141
|
-
const node = this.find(
|
|
47622
|
+
isCategory(path33) {
|
|
47623
|
+
const node = this.find(path33);
|
|
47142
47624
|
return node?.isCategory || false;
|
|
47143
47625
|
}
|
|
47144
47626
|
/**
|
|
@@ -47217,8 +47699,8 @@ var CommandTree = class {
|
|
|
47217
47699
|
* Supports dot notation: "tools.subagent.spawn.local"
|
|
47218
47700
|
*/
|
|
47219
47701
|
registerFromPath(pathStr, info) {
|
|
47220
|
-
const
|
|
47221
|
-
this.register(
|
|
47702
|
+
const path33 = pathStr.split(/[./]/).filter(Boolean);
|
|
47703
|
+
this.register(path33, info);
|
|
47222
47704
|
}
|
|
47223
47705
|
};
|
|
47224
47706
|
var commandTree = new CommandTree();
|
|
@@ -47332,6 +47814,33 @@ function createExtensionContext(extension, cwd, uiContext, abortFn, isIdleFn, ha
|
|
|
47332
47814
|
setSessionMetadata(key, value) {
|
|
47333
47815
|
actions?.setSessionMetadata?.(key, value);
|
|
47334
47816
|
},
|
|
47817
|
+
appendEntry(customType, data) {
|
|
47818
|
+
if (!actions?.appendEntry) throw new Error("appendEntry is not available in this host mode");
|
|
47819
|
+
return actions.appendEntry(customType, data);
|
|
47820
|
+
},
|
|
47821
|
+
setLabel(entryId, label) {
|
|
47822
|
+
if (!actions?.setLabel) throw new Error("setLabel is not available in this host mode");
|
|
47823
|
+
return actions.setLabel(entryId, label);
|
|
47824
|
+
},
|
|
47825
|
+
setSessionName(name) {
|
|
47826
|
+
if (!actions?.setSessionName) throw new Error("setSessionName is not available in this host mode");
|
|
47827
|
+
return actions.setSessionName(name);
|
|
47828
|
+
},
|
|
47829
|
+
getSessionName() {
|
|
47830
|
+
return actions?.getSessionName?.();
|
|
47831
|
+
},
|
|
47832
|
+
registerProvider(name, config) {
|
|
47833
|
+
if (!actions?.registerProvider) throw new Error("registerProvider is not available in this host mode");
|
|
47834
|
+
return actions.registerProvider(name, config);
|
|
47835
|
+
},
|
|
47836
|
+
async loginProvider(name) {
|
|
47837
|
+
if (!actions?.loginProvider) throw new Error("loginProvider is not available in this host mode");
|
|
47838
|
+
return actions.loginProvider(name);
|
|
47839
|
+
},
|
|
47840
|
+
async reload() {
|
|
47841
|
+
if (!actions?.reload) throw new Error("reload is not available in this host mode");
|
|
47842
|
+
return actions.reload();
|
|
47843
|
+
},
|
|
47335
47844
|
get yoloMode() {
|
|
47336
47845
|
return actions?.yoloMode ?? false;
|
|
47337
47846
|
}
|
|
@@ -47353,19 +47862,19 @@ function createExtension(extensionPath, resolvedPath, identity, source) {
|
|
|
47353
47862
|
}
|
|
47354
47863
|
function expandPath(p) {
|
|
47355
47864
|
if (p.startsWith("~/")) {
|
|
47356
|
-
return
|
|
47865
|
+
return path7.join(os2.homedir(), p.slice(2));
|
|
47357
47866
|
}
|
|
47358
47867
|
if (p.startsWith("~")) {
|
|
47359
|
-
return
|
|
47868
|
+
return path7.join(os2.homedir(), p.slice(1));
|
|
47360
47869
|
}
|
|
47361
47870
|
return p;
|
|
47362
47871
|
}
|
|
47363
47872
|
function resolvePath(extPath, cwd) {
|
|
47364
47873
|
const expanded = expandPath(extPath);
|
|
47365
|
-
if (
|
|
47874
|
+
if (path7.isAbsolute(expanded)) {
|
|
47366
47875
|
return expanded;
|
|
47367
47876
|
}
|
|
47368
|
-
return
|
|
47877
|
+
return path7.resolve(cwd, expanded);
|
|
47369
47878
|
}
|
|
47370
47879
|
async function loadExtensionModule(extensionPath) {
|
|
47371
47880
|
try {
|
|
@@ -47385,14 +47894,14 @@ function normalizeExtensionImportPath(extensionPath) {
|
|
|
47385
47894
|
if (/^[a-zA-Z]:[\\/]/.test(extensionPath)) {
|
|
47386
47895
|
return `file:///${extensionPath.replace(/\\/g, "/")}`;
|
|
47387
47896
|
}
|
|
47388
|
-
if (
|
|
47897
|
+
if (path7.isAbsolute(extensionPath)) {
|
|
47389
47898
|
return pathToFileURL(extensionPath).href;
|
|
47390
47899
|
}
|
|
47391
47900
|
return extensionPath;
|
|
47392
47901
|
}
|
|
47393
47902
|
async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, hasUI, actions, discovered) {
|
|
47394
47903
|
const resolvedPath = resolvePath(extensionPath, cwd);
|
|
47395
|
-
if (!
|
|
47904
|
+
if (!fs8.existsSync(resolvedPath)) {
|
|
47396
47905
|
return { extension: null, error: `Extension not found: ${extensionPath}` };
|
|
47397
47906
|
}
|
|
47398
47907
|
try {
|
|
@@ -47413,17 +47922,17 @@ async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, h
|
|
|
47413
47922
|
}
|
|
47414
47923
|
}
|
|
47415
47924
|
function discoverExtensionsInDir(dir, source) {
|
|
47416
|
-
if (!
|
|
47925
|
+
if (!fs8.existsSync(dir)) {
|
|
47417
47926
|
return [];
|
|
47418
47927
|
}
|
|
47419
47928
|
const discovered = [];
|
|
47420
47929
|
try {
|
|
47421
|
-
const entries =
|
|
47930
|
+
const entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
47422
47931
|
for (const entry of entries) {
|
|
47423
47932
|
if (entry.name.endsWith(".disabled")) {
|
|
47424
47933
|
continue;
|
|
47425
47934
|
}
|
|
47426
|
-
const entryPath =
|
|
47935
|
+
const entryPath = path7.join(dir, entry.name);
|
|
47427
47936
|
if (entry.isFile() && (entry.name.endsWith(".cjs") || entry.name.endsWith(".js") || entry.name.endsWith(".ts"))) {
|
|
47428
47937
|
discovered.push({
|
|
47429
47938
|
entryPath,
|
|
@@ -47433,13 +47942,13 @@ function discoverExtensionsInDir(dir, source) {
|
|
|
47433
47942
|
continue;
|
|
47434
47943
|
}
|
|
47435
47944
|
if (entry.isDirectory()) {
|
|
47436
|
-
const packageJsonPath =
|
|
47945
|
+
const packageJsonPath = path7.join(entryPath, "package.json");
|
|
47437
47946
|
let packageIdentity;
|
|
47438
47947
|
let packageDescription;
|
|
47439
47948
|
let packageMainPath;
|
|
47440
|
-
if (
|
|
47949
|
+
if (fs8.existsSync(packageJsonPath)) {
|
|
47441
47950
|
try {
|
|
47442
|
-
const pkg = JSON.parse(
|
|
47951
|
+
const pkg = JSON.parse(fs8.readFileSync(packageJsonPath, "utf-8"));
|
|
47443
47952
|
const manifest = pkg.pie && typeof pkg.pie === "object" && !Array.isArray(pkg.pie) ? pkg.pie : void 0;
|
|
47444
47953
|
packageIdentity = resolveExtensionIdentity({
|
|
47445
47954
|
pieName: typeof manifest?.name === "string" ? manifest.name : void 0,
|
|
@@ -47448,8 +47957,8 @@ function discoverExtensionsInDir(dir, source) {
|
|
|
47448
47957
|
});
|
|
47449
47958
|
packageDescription = typeof pkg.description === "string" ? pkg.description : void 0;
|
|
47450
47959
|
if (typeof manifest?.main === "string" && manifest.main.trim().length > 0) {
|
|
47451
|
-
const candidate =
|
|
47452
|
-
if (
|
|
47960
|
+
const candidate = path7.resolve(entryPath, manifest.main);
|
|
47961
|
+
if (fs8.existsSync(candidate)) {
|
|
47453
47962
|
packageMainPath = candidate;
|
|
47454
47963
|
}
|
|
47455
47964
|
}
|
|
@@ -47465,8 +47974,8 @@ function discoverExtensionsInDir(dir, source) {
|
|
|
47465
47974
|
});
|
|
47466
47975
|
continue;
|
|
47467
47976
|
}
|
|
47468
|
-
const indexCjs =
|
|
47469
|
-
if (
|
|
47977
|
+
const indexCjs = path7.join(entryPath, "index.cjs");
|
|
47978
|
+
if (fs8.existsSync(indexCjs)) {
|
|
47470
47979
|
discovered.push({
|
|
47471
47980
|
entryPath: indexCjs,
|
|
47472
47981
|
source,
|
|
@@ -47475,8 +47984,8 @@ function discoverExtensionsInDir(dir, source) {
|
|
|
47475
47984
|
});
|
|
47476
47985
|
continue;
|
|
47477
47986
|
}
|
|
47478
|
-
const indexJs =
|
|
47479
|
-
if (
|
|
47987
|
+
const indexJs = path7.join(entryPath, "index.js");
|
|
47988
|
+
if (fs8.existsSync(indexJs)) {
|
|
47480
47989
|
discovered.push({
|
|
47481
47990
|
entryPath: indexJs,
|
|
47482
47991
|
source,
|
|
@@ -47485,8 +47994,8 @@ function discoverExtensionsInDir(dir, source) {
|
|
|
47485
47994
|
});
|
|
47486
47995
|
continue;
|
|
47487
47996
|
}
|
|
47488
|
-
const indexTs =
|
|
47489
|
-
if (
|
|
47997
|
+
const indexTs = path7.join(entryPath, "index.ts");
|
|
47998
|
+
if (fs8.existsSync(indexTs)) {
|
|
47490
47999
|
discovered.push({
|
|
47491
48000
|
entryPath: indexTs,
|
|
47492
48001
|
source,
|
|
@@ -47507,21 +48016,21 @@ function collectDiscoveredExtensions(configuredPaths, cwd, options) {
|
|
|
47507
48016
|
const errors = [];
|
|
47508
48017
|
if (!options?.noExtensions) {
|
|
47509
48018
|
if (!options?.noBuiltinExtensions) {
|
|
47510
|
-
const builtinExtDir =
|
|
48019
|
+
const builtinExtDir = path7.join(getBuiltinDir(), "extensions");
|
|
47511
48020
|
discovered.push(...discoverExtensionsInDir(builtinExtDir, "builtin"));
|
|
47512
48021
|
}
|
|
47513
|
-
const globalExtDir =
|
|
48022
|
+
const globalExtDir = path7.join(os2.homedir(), ".pie", "extensions");
|
|
47514
48023
|
discovered.push(...discoverExtensionsInDir(globalExtDir, "global"));
|
|
47515
|
-
const localExtDir =
|
|
48024
|
+
const localExtDir = path7.join(cwd, ".pie", "extensions");
|
|
47516
48025
|
discovered.push(...discoverExtensionsInDir(localExtDir, "project"));
|
|
47517
48026
|
}
|
|
47518
48027
|
for (const p of configuredPaths) {
|
|
47519
48028
|
const resolved = resolvePath(p, cwd);
|
|
47520
|
-
if (!
|
|
48029
|
+
if (!fs8.existsSync(resolved)) {
|
|
47521
48030
|
errors.push({ path: p, error: `Extension path not found: ${p}` });
|
|
47522
48031
|
continue;
|
|
47523
48032
|
}
|
|
47524
|
-
if (!
|
|
48033
|
+
if (!fs8.statSync(resolved).isDirectory()) {
|
|
47525
48034
|
errors.push({ path: p, error: `Extension path must be a directory: ${p}` });
|
|
47526
48035
|
continue;
|
|
47527
48036
|
}
|
|
@@ -47612,6 +48121,7 @@ function convertExtensionTools(extensions, customExecutors) {
|
|
|
47612
48121
|
label: tool.label ?? name,
|
|
47613
48122
|
description: tool.description,
|
|
47614
48123
|
parameters: tool.parameters,
|
|
48124
|
+
renderHint: tool.renderHint,
|
|
47615
48125
|
execute: async (toolCallId, args, signal, onUpdate) => {
|
|
47616
48126
|
debugLog("ext-tool", `${name} EXECUTE START`, {
|
|
47617
48127
|
toolCallId: toolCallId.slice(0, 8),
|
|
@@ -47802,6 +48312,9 @@ Enablement overrides are stored sparsely; absent entries default to enabled.
|
|
|
47802
48312
|
Project scope writes ./.pie/settings.json and overrides user scope.`);
|
|
47803
48313
|
}
|
|
47804
48314
|
|
|
48315
|
+
// src/interactive-mode.ts
|
|
48316
|
+
import * as os8 from "os";
|
|
48317
|
+
|
|
47805
48318
|
// ../../packages/tui/src/fuzzy.ts
|
|
47806
48319
|
function fuzzyMatch(query, text) {
|
|
47807
48320
|
const queryLower = query.toLowerCase();
|
|
@@ -49352,9 +49865,9 @@ var KillRing = class {
|
|
|
49352
49865
|
};
|
|
49353
49866
|
|
|
49354
49867
|
// ../../packages/tui/src/tui.ts
|
|
49355
|
-
import * as
|
|
49868
|
+
import * as fs9 from "node:fs";
|
|
49356
49869
|
import * as os3 from "node:os";
|
|
49357
|
-
import * as
|
|
49870
|
+
import * as path8 from "node:path";
|
|
49358
49871
|
|
|
49359
49872
|
// ../../packages/tui/src/terminal-image.ts
|
|
49360
49873
|
var cachedCapabilities = null;
|
|
@@ -50030,11 +50543,11 @@ var TUI = class extends Container {
|
|
|
50030
50543
|
const debugRedraw = process.env.PIE_DEBUG_REDRAW === "1";
|
|
50031
50544
|
const logRedraw = (reason) => {
|
|
50032
50545
|
if (!debugRedraw) return;
|
|
50033
|
-
const logPath =
|
|
50034
|
-
|
|
50546
|
+
const logPath = path8.join(os3.homedir(), ".pie", "logs", "pie-cli.log");
|
|
50547
|
+
fs9.mkdirSync(path8.dirname(logPath), { recursive: true });
|
|
50035
50548
|
const msg = `[${(/* @__PURE__ */ new Date()).toISOString()}] [DEBUG] [ui] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})
|
|
50036
50549
|
`;
|
|
50037
|
-
|
|
50550
|
+
fs9.appendFileSync(logPath, msg);
|
|
50038
50551
|
};
|
|
50039
50552
|
if (this.previousLines.length === 0 && !widthChanged) {
|
|
50040
50553
|
logRedraw("first render");
|
|
@@ -50127,7 +50640,7 @@ var TUI = class extends Container {
|
|
|
50127
50640
|
const line = newLines[i];
|
|
50128
50641
|
const isImage = isImageLine(line);
|
|
50129
50642
|
if (!isImage && visibleWidth(line) > width) {
|
|
50130
|
-
const crashLogPath =
|
|
50643
|
+
const crashLogPath = path8.join(os3.homedir(), ".pie", "pie-crash.log");
|
|
50131
50644
|
const crashData = [
|
|
50132
50645
|
`Crash at ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
50133
50646
|
`Terminal width: ${width}`,
|
|
@@ -50137,8 +50650,8 @@ var TUI = class extends Container {
|
|
|
50137
50650
|
...newLines.map((l, idx) => `[${idx}] (w=${visibleWidth(l)}) ${l}`),
|
|
50138
50651
|
""
|
|
50139
50652
|
].join("\n");
|
|
50140
|
-
|
|
50141
|
-
|
|
50653
|
+
fs9.mkdirSync(path8.dirname(crashLogPath), { recursive: true });
|
|
50654
|
+
fs9.writeFileSync(crashLogPath, crashData);
|
|
50142
50655
|
this.stop();
|
|
50143
50656
|
const errorMsg = [
|
|
50144
50657
|
`Rendered line ${i} exceeds terminal width (${visibleWidth(line)} > ${width}).`,
|
|
@@ -50168,8 +50681,8 @@ var TUI = class extends Container {
|
|
|
50168
50681
|
buffer += "\x1B[?2026l";
|
|
50169
50682
|
if (process.env.PIE_TUI_DEBUG === "1") {
|
|
50170
50683
|
const debugDir = "/tmp/tui";
|
|
50171
|
-
|
|
50172
|
-
const debugPath =
|
|
50684
|
+
fs9.mkdirSync(debugDir, { recursive: true });
|
|
50685
|
+
const debugPath = path8.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);
|
|
50173
50686
|
const debugData = [
|
|
50174
50687
|
`firstChanged: ${firstChanged}`,
|
|
50175
50688
|
`viewportTop: ${viewportTop}`,
|
|
@@ -50192,7 +50705,7 @@ var TUI = class extends Container {
|
|
|
50192
50705
|
"=== buffer ===",
|
|
50193
50706
|
JSON.stringify(buffer)
|
|
50194
50707
|
].join("\n");
|
|
50195
|
-
|
|
50708
|
+
fs9.writeFileSync(debugPath, debugData);
|
|
50196
50709
|
}
|
|
50197
50710
|
this.terminal.write(buffer);
|
|
50198
50711
|
this.cursorRow = Math.max(0, newLines.length - 1);
|
|
@@ -54383,7 +54896,7 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
54383
54896
|
};
|
|
54384
54897
|
|
|
54385
54898
|
// ../../packages/tui/src/terminal.ts
|
|
54386
|
-
import * as
|
|
54899
|
+
import * as fs10 from "node:fs";
|
|
54387
54900
|
import koffi from "koffi";
|
|
54388
54901
|
var ProcessTerminal = class {
|
|
54389
54902
|
wasRaw = false;
|
|
@@ -54508,7 +55021,7 @@ var ProcessTerminal = class {
|
|
|
54508
55021
|
const timeLeft = endTime - now;
|
|
54509
55022
|
if (timeLeft <= 0) break;
|
|
54510
55023
|
if (now - lastDataTime >= idleMs) break;
|
|
54511
|
-
await new Promise((
|
|
55024
|
+
await new Promise((resolve7) => setTimeout(resolve7, Math.min(idleMs, timeLeft)));
|
|
54512
55025
|
}
|
|
54513
55026
|
} finally {
|
|
54514
55027
|
process.stdin.removeListener("data", onData);
|
|
@@ -54544,7 +55057,7 @@ var ProcessTerminal = class {
|
|
|
54544
55057
|
process.stdout.write(data);
|
|
54545
55058
|
if (this.writeLogPath) {
|
|
54546
55059
|
try {
|
|
54547
|
-
|
|
55060
|
+
fs10.appendFileSync(this.writeLogPath, data, { encoding: "utf8" });
|
|
54548
55061
|
} catch {
|
|
54549
55062
|
}
|
|
54550
55063
|
}
|
|
@@ -54618,6 +55131,8 @@ var ExtensionRunner = class {
|
|
|
54618
55131
|
actions;
|
|
54619
55132
|
contextActions;
|
|
54620
55133
|
hasUI;
|
|
55134
|
+
/** Unregister handles created through this runner, revoked on reload/teardown. */
|
|
55135
|
+
unregisterHandles = [];
|
|
54621
55136
|
constructor(extensions, actions, contextActions, hasUI = true) {
|
|
54622
55137
|
this.extensions = extensions;
|
|
54623
55138
|
this.actions = actions;
|
|
@@ -54649,6 +55164,39 @@ var ExtensionRunner = class {
|
|
|
54649
55164
|
this.uiContext = uiContext;
|
|
54650
55165
|
this.hasUI = true;
|
|
54651
55166
|
}
|
|
55167
|
+
/**
|
|
55168
|
+
* Wrap an unregister handle so this runner can revoke it during
|
|
55169
|
+
* reload/teardown even if the extension drops the handle it was returned.
|
|
55170
|
+
* The wrapper is idempotent.
|
|
55171
|
+
*/
|
|
55172
|
+
trackUnregisterHandle(unregister) {
|
|
55173
|
+
const entry = { invoked: false, unregister };
|
|
55174
|
+
this.unregisterHandles.push(entry);
|
|
55175
|
+
return () => {
|
|
55176
|
+
if (entry.invoked) return;
|
|
55177
|
+
entry.invoked = true;
|
|
55178
|
+
unregister();
|
|
55179
|
+
const index = this.unregisterHandles.indexOf(entry);
|
|
55180
|
+
if (index >= 0) this.unregisterHandles.splice(index, 1);
|
|
55181
|
+
};
|
|
55182
|
+
}
|
|
55183
|
+
/**
|
|
55184
|
+
* Revoke every provider registration made through this runner (runtime
|
|
55185
|
+
* reload / teardown). Old extension instances must not leave providers,
|
|
55186
|
+
* OAuth flows, or ambient state registered behind them.
|
|
55187
|
+
*/
|
|
55188
|
+
revokeRegistrations() {
|
|
55189
|
+
const pending = this.unregisterHandles.splice(0);
|
|
55190
|
+
for (const entry of pending) {
|
|
55191
|
+
if (entry.invoked) continue;
|
|
55192
|
+
entry.invoked = true;
|
|
55193
|
+
try {
|
|
55194
|
+
entry.unregister();
|
|
55195
|
+
} catch (error) {
|
|
55196
|
+
console.warn("[Extension] unregister provider failed during reload:", error);
|
|
55197
|
+
}
|
|
55198
|
+
}
|
|
55199
|
+
}
|
|
54652
55200
|
/**
|
|
54653
55201
|
* Get all registered tools from all extensions.
|
|
54654
55202
|
*/
|
|
@@ -54739,10 +55287,35 @@ var ExtensionRunner = class {
|
|
|
54739
55287
|
},
|
|
54740
55288
|
getAllTools: () => runner.actions.getAllTools(),
|
|
54741
55289
|
getRuntimeTools: () => runner.actions.getRuntimeTools(),
|
|
54742
|
-
resolveModelClass: (modelClass) => runner.actions.resolveModelClass?.(modelClass),
|
|
55290
|
+
resolveModelClass: (modelClass) => runner.actions.resolveModelClass?.(modelClass) ?? {},
|
|
54743
55291
|
getMessages: () => runner.actions.getMessages(),
|
|
54744
55292
|
getSessionMetadata: () => runner.actions.getSessionMetadata(),
|
|
54745
55293
|
setSessionMetadata: (key, value) => runner.actions.setSessionMetadata(key, value),
|
|
55294
|
+
appendEntry: (customType, data) => {
|
|
55295
|
+
if (!runner.actions.appendEntry) throw new Error("appendEntry is not available in this host mode");
|
|
55296
|
+
return runner.actions.appendEntry(customType, data);
|
|
55297
|
+
},
|
|
55298
|
+
setLabel: (entryId, label) => {
|
|
55299
|
+
if (!runner.actions.setLabel) throw new Error("setLabel is not available in this host mode");
|
|
55300
|
+
return runner.actions.setLabel(entryId, label);
|
|
55301
|
+
},
|
|
55302
|
+
setSessionName: (name) => {
|
|
55303
|
+
if (!runner.actions.setSessionName) throw new Error("setSessionName is not available in this host mode");
|
|
55304
|
+
return runner.actions.setSessionName(name);
|
|
55305
|
+
},
|
|
55306
|
+
getSessionName: () => runner.actions.getSessionName?.(),
|
|
55307
|
+
registerProvider: (name, config) => {
|
|
55308
|
+
if (!runner.actions.registerProvider) throw new Error("registerProvider is not available in this host mode");
|
|
55309
|
+
return runner.trackUnregisterHandle(runner.actions.registerProvider(name, config));
|
|
55310
|
+
},
|
|
55311
|
+
loginProvider: async (name) => {
|
|
55312
|
+
if (!runner.actions.loginProvider) throw new Error("loginProvider is not available in this host mode");
|
|
55313
|
+
return runner.actions.loginProvider(name);
|
|
55314
|
+
},
|
|
55315
|
+
reload: async () => {
|
|
55316
|
+
if (!runner.actions.reload) throw new Error("reload is not available in this host mode");
|
|
55317
|
+
return runner.actions.reload();
|
|
55318
|
+
},
|
|
54746
55319
|
get yoloMode() {
|
|
54747
55320
|
return runner.actions.yoloMode ?? false;
|
|
54748
55321
|
}
|
|
@@ -54822,6 +55395,81 @@ var ExtensionRunner = class {
|
|
|
54822
55395
|
isError: currentEvent.isError ?? event.isError
|
|
54823
55396
|
};
|
|
54824
55397
|
}
|
|
55398
|
+
/**
|
|
55399
|
+
* Emit session:before_switch. The first cancel wins; default allows.
|
|
55400
|
+
*/
|
|
55401
|
+
async emitSessionBeforeSwitch(event) {
|
|
55402
|
+
const ctx = this.createContext();
|
|
55403
|
+
for (const ext of this.extensions) {
|
|
55404
|
+
const handlers = ext.handlers.get("session:before_switch");
|
|
55405
|
+
if (!handlers || handlers.length === 0) continue;
|
|
55406
|
+
for (const handler of handlers) {
|
|
55407
|
+
try {
|
|
55408
|
+
const result = await handler(event, ctx);
|
|
55409
|
+
if (result && typeof result === "object" && result.cancel === true) return { cancel: true };
|
|
55410
|
+
} catch (err) {
|
|
55411
|
+
if (process.env.PIE_VERBOSE) {
|
|
55412
|
+
console.warn(`[Runner] session:before_switch handler failed in ${ext.path}:`, err);
|
|
55413
|
+
}
|
|
55414
|
+
}
|
|
55415
|
+
}
|
|
55416
|
+
}
|
|
55417
|
+
return {};
|
|
55418
|
+
}
|
|
55419
|
+
/**
|
|
55420
|
+
* Emit session:before_compact. The first cancel wins; the first custom
|
|
55421
|
+
* summary wins; default runs the built-in summarizer.
|
|
55422
|
+
*/
|
|
55423
|
+
async emitSessionBeforeCompact(event) {
|
|
55424
|
+
const ctx = this.createContext();
|
|
55425
|
+
for (const ext of this.extensions) {
|
|
55426
|
+
const handlers = ext.handlers.get("session:before_compact");
|
|
55427
|
+
if (!handlers || handlers.length === 0) continue;
|
|
55428
|
+
for (const handler of handlers) {
|
|
55429
|
+
try {
|
|
55430
|
+
const result = await handler(event, ctx);
|
|
55431
|
+
if (!result || typeof result !== "object") continue;
|
|
55432
|
+
if (result.cancel === true) return { cancel: true };
|
|
55433
|
+
if (typeof result.summary === "string" && result.summary.trim()) return { summary: result.summary };
|
|
55434
|
+
} catch (err) {
|
|
55435
|
+
if (process.env.PIE_VERBOSE) {
|
|
55436
|
+
console.warn(`[Runner] session:before_compact handler failed in ${ext.path}:`, err);
|
|
55437
|
+
}
|
|
55438
|
+
}
|
|
55439
|
+
}
|
|
55440
|
+
}
|
|
55441
|
+
return {};
|
|
55442
|
+
}
|
|
55443
|
+
/**
|
|
55444
|
+
* Emit terminal:input to all extensions. Transforms chain through handlers
|
|
55445
|
+
* in registration order (each handler sees the previous transform); a
|
|
55446
|
+
* consume result stops the chain and wins. Default: continue unchanged.
|
|
55447
|
+
*/
|
|
55448
|
+
async emitTerminalInput(event) {
|
|
55449
|
+
const ctx = this.createContext();
|
|
55450
|
+
let current = { action: "continue" };
|
|
55451
|
+
let text = event.text;
|
|
55452
|
+
for (const ext of this.extensions) {
|
|
55453
|
+
const handlers = ext.handlers.get("terminal:input");
|
|
55454
|
+
if (!handlers || handlers.length === 0) continue;
|
|
55455
|
+
for (const handler of handlers) {
|
|
55456
|
+
try {
|
|
55457
|
+
const result = await handler({ ...event, text }, ctx);
|
|
55458
|
+
if (!result || typeof result !== "object" || !("action" in result)) continue;
|
|
55459
|
+
if (result.action === "consume") return { action: "consume" };
|
|
55460
|
+
if (result.action === "transform" && typeof result.text === "string") {
|
|
55461
|
+
text = result.text;
|
|
55462
|
+
current = { action: "transform", text };
|
|
55463
|
+
}
|
|
55464
|
+
} catch (err) {
|
|
55465
|
+
if (process.env.PIE_VERBOSE) {
|
|
55466
|
+
console.warn(`[Runner] terminal:input handler failed in ${ext.path}:`, err);
|
|
55467
|
+
}
|
|
55468
|
+
}
|
|
55469
|
+
}
|
|
55470
|
+
}
|
|
55471
|
+
return current;
|
|
55472
|
+
}
|
|
54825
55473
|
/**
|
|
54826
55474
|
* Emit a generic event to all extensions.
|
|
54827
55475
|
*/
|
|
@@ -54959,8 +55607,8 @@ function wrapToolsWithExtensions(tools, runner) {
|
|
|
54959
55607
|
}
|
|
54960
55608
|
|
|
54961
55609
|
// src/keybindings.ts
|
|
54962
|
-
import { existsSync as
|
|
54963
|
-
import { join as
|
|
55610
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
|
|
55611
|
+
import { join as join7 } from "path";
|
|
54964
55612
|
var DEFAULT_APP_KEYBINDINGS = {
|
|
54965
55613
|
interrupt: "escape",
|
|
54966
55614
|
clear: "ctrl+c",
|
|
@@ -55024,7 +55672,7 @@ var KeybindingsManager = class _KeybindingsManager {
|
|
|
55024
55672
|
* Create from config file and set up editor keybindings.
|
|
55025
55673
|
*/
|
|
55026
55674
|
static create(agentDir = getAgentDir()) {
|
|
55027
|
-
const configPath =
|
|
55675
|
+
const configPath = join7(agentDir, "keybindings.json");
|
|
55028
55676
|
const config = _KeybindingsManager.loadFromFile(configPath);
|
|
55029
55677
|
const manager = new _KeybindingsManager(config);
|
|
55030
55678
|
const editorConfig = {};
|
|
@@ -55042,10 +55690,10 @@ var KeybindingsManager = class _KeybindingsManager {
|
|
|
55042
55690
|
static inMemory(config = {}) {
|
|
55043
55691
|
return new _KeybindingsManager(config);
|
|
55044
55692
|
}
|
|
55045
|
-
static loadFromFile(
|
|
55046
|
-
if (!
|
|
55693
|
+
static loadFromFile(path33) {
|
|
55694
|
+
if (!existsSync8(path33)) return {};
|
|
55047
55695
|
try {
|
|
55048
|
-
return JSON.parse(
|
|
55696
|
+
return JSON.parse(readFileSync7(path33, "utf-8"));
|
|
55049
55697
|
} catch {
|
|
55050
55698
|
return {};
|
|
55051
55699
|
}
|
|
@@ -55094,19 +55742,19 @@ var KeybindingsManager = class _KeybindingsManager {
|
|
|
55094
55742
|
};
|
|
55095
55743
|
|
|
55096
55744
|
// src/project-knowledge.ts
|
|
55097
|
-
import
|
|
55098
|
-
import
|
|
55745
|
+
import fs11 from "node:fs";
|
|
55746
|
+
import path9 from "node:path";
|
|
55099
55747
|
function collectAncestorAgentsFiles(cwd) {
|
|
55100
|
-
const resolvedCwd =
|
|
55748
|
+
const resolvedCwd = path9.resolve(cwd || process.cwd());
|
|
55101
55749
|
const projectRoot = resolveCliProjectRoot(resolvedCwd);
|
|
55102
55750
|
const candidates = [];
|
|
55103
55751
|
let current = resolvedCwd;
|
|
55104
55752
|
while (true) {
|
|
55105
|
-
candidates.unshift(
|
|
55753
|
+
candidates.unshift(path9.join(current, AGENTS_CONTEXT_FILE_NAME));
|
|
55106
55754
|
if (current === projectRoot) {
|
|
55107
55755
|
break;
|
|
55108
55756
|
}
|
|
55109
|
-
const parent =
|
|
55757
|
+
const parent = path9.dirname(current);
|
|
55110
55758
|
if (parent === current) {
|
|
55111
55759
|
break;
|
|
55112
55760
|
}
|
|
@@ -55114,13 +55762,13 @@ function collectAncestorAgentsFiles(cwd) {
|
|
|
55114
55762
|
}
|
|
55115
55763
|
const files = [];
|
|
55116
55764
|
for (const candidate of candidates) {
|
|
55117
|
-
if (!
|
|
55765
|
+
if (!fs11.existsSync(candidate)) {
|
|
55118
55766
|
continue;
|
|
55119
55767
|
}
|
|
55120
55768
|
try {
|
|
55121
55769
|
files.push({
|
|
55122
|
-
path:
|
|
55123
|
-
content:
|
|
55770
|
+
path: path9.relative(resolvedCwd, candidate) || AGENTS_CONTEXT_FILE_NAME,
|
|
55771
|
+
content: fs11.readFileSync(candidate, "utf-8")
|
|
55124
55772
|
});
|
|
55125
55773
|
} catch {
|
|
55126
55774
|
}
|
|
@@ -55132,14 +55780,14 @@ function buildCliProjectContextSection(cwd) {
|
|
|
55132
55780
|
}
|
|
55133
55781
|
|
|
55134
55782
|
// src/file-access-context.ts
|
|
55135
|
-
import * as
|
|
55783
|
+
import * as path10 from "node:path";
|
|
55136
55784
|
function uniqueNormalizedPaths(paths) {
|
|
55137
55785
|
const seen = /* @__PURE__ */ new Set();
|
|
55138
55786
|
const result = [];
|
|
55139
55787
|
for (const entry of paths) {
|
|
55140
55788
|
const trimmed = String(entry || "").trim();
|
|
55141
55789
|
if (!trimmed) continue;
|
|
55142
|
-
const normalized =
|
|
55790
|
+
const normalized = path10.normalize(trimmed);
|
|
55143
55791
|
if (seen.has(normalized)) continue;
|
|
55144
55792
|
seen.add(normalized);
|
|
55145
55793
|
result.push(normalized);
|
|
@@ -55158,8 +55806,8 @@ function buildCliFileAccessOptions(params) {
|
|
|
55158
55806
|
}
|
|
55159
55807
|
|
|
55160
55808
|
// src/theme/theme.ts
|
|
55161
|
-
import * as
|
|
55162
|
-
import * as
|
|
55809
|
+
import * as fs12 from "node:fs";
|
|
55810
|
+
import * as path11 from "node:path";
|
|
55163
55811
|
|
|
55164
55812
|
// ../../node_modules/@sinclair/typebox/build/esm/compiler/compiler.mjs
|
|
55165
55813
|
var TypeCheck = class {
|
|
@@ -56046,11 +56694,11 @@ var BUILTIN_THEMES;
|
|
|
56046
56694
|
function getBuiltinThemes() {
|
|
56047
56695
|
if (!BUILTIN_THEMES) {
|
|
56048
56696
|
const themesDir = getThemesDir();
|
|
56049
|
-
const darkPath =
|
|
56050
|
-
const lightPath =
|
|
56697
|
+
const darkPath = path11.join(themesDir, "dark.json");
|
|
56698
|
+
const lightPath = path11.join(themesDir, "light.json");
|
|
56051
56699
|
BUILTIN_THEMES = {
|
|
56052
|
-
dark: JSON.parse(
|
|
56053
|
-
light: JSON.parse(
|
|
56700
|
+
dark: JSON.parse(fs12.readFileSync(darkPath, "utf-8")),
|
|
56701
|
+
light: JSON.parse(fs12.readFileSync(lightPath, "utf-8"))
|
|
56054
56702
|
};
|
|
56055
56703
|
}
|
|
56056
56704
|
return BUILTIN_THEMES;
|
|
@@ -56058,8 +56706,8 @@ function getBuiltinThemes() {
|
|
|
56058
56706
|
function getAvailableThemes() {
|
|
56059
56707
|
const themes = new Set(Object.keys(getBuiltinThemes()));
|
|
56060
56708
|
const customThemesDir = getCustomThemesDir();
|
|
56061
|
-
if (
|
|
56062
|
-
const files =
|
|
56709
|
+
if (fs12.existsSync(customThemesDir)) {
|
|
56710
|
+
const files = fs12.readdirSync(customThemesDir);
|
|
56063
56711
|
for (const file of files) {
|
|
56064
56712
|
if (file.endsWith(".json")) {
|
|
56065
56713
|
themes.add(file.slice(0, -5));
|
|
@@ -56120,18 +56768,18 @@ function loadThemeJson(name) {
|
|
|
56120
56768
|
}
|
|
56121
56769
|
const registeredTheme = registeredThemes.get(name);
|
|
56122
56770
|
if (registeredTheme?.sourcePath) {
|
|
56123
|
-
const content2 =
|
|
56771
|
+
const content2 = fs12.readFileSync(registeredTheme.sourcePath, "utf-8");
|
|
56124
56772
|
return parseThemeJsonContent(registeredTheme.sourcePath, content2);
|
|
56125
56773
|
}
|
|
56126
56774
|
if (registeredTheme) {
|
|
56127
56775
|
throw new Error(`Theme "${name}" does not have a source path for export`);
|
|
56128
56776
|
}
|
|
56129
56777
|
const customThemesDir = getCustomThemesDir();
|
|
56130
|
-
const themePath =
|
|
56131
|
-
if (!
|
|
56778
|
+
const themePath = path11.join(customThemesDir, `${name}.json`);
|
|
56779
|
+
if (!fs12.existsSync(themePath)) {
|
|
56132
56780
|
throw new Error(`Theme not found: ${name}`);
|
|
56133
56781
|
}
|
|
56134
|
-
const content =
|
|
56782
|
+
const content = fs12.readFileSync(themePath, "utf-8");
|
|
56135
56783
|
return parseThemeJsonContent(name, content);
|
|
56136
56784
|
}
|
|
56137
56785
|
function createTheme(themeJson, mode, sourcePath) {
|
|
@@ -56244,12 +56892,12 @@ function startThemeWatcher() {
|
|
|
56244
56892
|
return;
|
|
56245
56893
|
}
|
|
56246
56894
|
const customThemesDir = getCustomThemesDir();
|
|
56247
|
-
const themeFile =
|
|
56248
|
-
if (!
|
|
56895
|
+
const themeFile = path11.join(customThemesDir, `${currentThemeName}.json`);
|
|
56896
|
+
if (!fs12.existsSync(themeFile)) {
|
|
56249
56897
|
return;
|
|
56250
56898
|
}
|
|
56251
56899
|
try {
|
|
56252
|
-
themeWatcher =
|
|
56900
|
+
themeWatcher = fs12.watch(themeFile, (eventType) => {
|
|
56253
56901
|
if (eventType === "change") {
|
|
56254
56902
|
setTimeout(() => {
|
|
56255
56903
|
try {
|
|
@@ -56262,7 +56910,7 @@ function startThemeWatcher() {
|
|
|
56262
56910
|
}, 100);
|
|
56263
56911
|
} else if (eventType === "rename") {
|
|
56264
56912
|
setTimeout(() => {
|
|
56265
|
-
if (!
|
|
56913
|
+
if (!fs12.existsSync(themeFile)) {
|
|
56266
56914
|
currentThemeName = "dark";
|
|
56267
56915
|
setGlobalTheme(loadTheme("dark"));
|
|
56268
56916
|
if (themeWatcher) {
|
|
@@ -56442,8 +57090,9 @@ function getSettingsListTheme() {
|
|
|
56442
57090
|
}
|
|
56443
57091
|
|
|
56444
57092
|
// src/skills/loader.ts
|
|
56445
|
-
import * as
|
|
56446
|
-
import * as
|
|
57093
|
+
import * as fs13 from "fs";
|
|
57094
|
+
import * as os4 from "os";
|
|
57095
|
+
import * as path12 from "path";
|
|
56447
57096
|
function parseSkillDescription(content) {
|
|
56448
57097
|
const frontmatterMatch = content.match(/^---\n[\s\S]*?description:\s*["']?(.+?)["']?(?:\n|$)/m);
|
|
56449
57098
|
if (frontmatterMatch) return frontmatterMatch[1].trim();
|
|
@@ -56458,21 +57107,53 @@ function parseSkillDescription(content) {
|
|
|
56458
57107
|
}
|
|
56459
57108
|
return "No description";
|
|
56460
57109
|
}
|
|
57110
|
+
var USER_CONTROLLED_SOURCES = /* @__PURE__ */ new Set(["user-agents", "user"]);
|
|
57111
|
+
function pathIsInside(child, parent) {
|
|
57112
|
+
const relative3 = path12.relative(parent, child);
|
|
57113
|
+
return relative3 !== "" && !relative3.startsWith(`..${path12.sep}`) && relative3 !== ".." && !path12.isAbsolute(relative3);
|
|
57114
|
+
}
|
|
57115
|
+
function resolveSkillSymlink(fullPath, dir, source) {
|
|
57116
|
+
let target;
|
|
57117
|
+
let stats;
|
|
57118
|
+
try {
|
|
57119
|
+
target = fs13.realpathSync(fullPath);
|
|
57120
|
+
stats = fs13.statSync(target);
|
|
57121
|
+
} catch {
|
|
57122
|
+
return { error: `broken skill symlink: ${fullPath}` };
|
|
57123
|
+
}
|
|
57124
|
+
if (!USER_CONTROLLED_SOURCES.has(source) && !pathIsInside(target, fs13.realpathSync(dir))) {
|
|
57125
|
+
return { error: `skill symlink escapes the "${source}" layer (not loaded): ${fullPath} -> ${target}` };
|
|
57126
|
+
}
|
|
57127
|
+
return { target, isDirectory: stats.isDirectory(), isFile: stats.isFile() };
|
|
57128
|
+
}
|
|
56461
57129
|
function loadSkillsFromDir(dir, source) {
|
|
56462
57130
|
const skills = [];
|
|
56463
57131
|
const diagnostics = [];
|
|
56464
|
-
if (!
|
|
57132
|
+
if (!fs13.existsSync(dir)) {
|
|
56465
57133
|
return { skills, diagnostics };
|
|
56466
57134
|
}
|
|
56467
|
-
const entries =
|
|
57135
|
+
const entries = fs13.readdirSync(dir, { withFileTypes: true });
|
|
56468
57136
|
for (const entry of entries) {
|
|
56469
57137
|
if (entry.name.startsWith(".")) continue;
|
|
56470
|
-
const fullPath =
|
|
56471
|
-
|
|
56472
|
-
|
|
56473
|
-
|
|
57138
|
+
const fullPath = path12.join(dir, entry.name);
|
|
57139
|
+
let entryPath = fullPath;
|
|
57140
|
+
let entryIsDirectory = entry.isDirectory();
|
|
57141
|
+
let entryIsFile = entry.isFile();
|
|
57142
|
+
if (entry.isSymbolicLink()) {
|
|
57143
|
+
const resolved = resolveSkillSymlink(fullPath, dir, source);
|
|
57144
|
+
if ("error" in resolved) {
|
|
57145
|
+
diagnostics.push({ type: "warning", message: resolved.error, path: fullPath });
|
|
57146
|
+
continue;
|
|
57147
|
+
}
|
|
57148
|
+
entryPath = resolved.target;
|
|
57149
|
+
entryIsDirectory = resolved.isDirectory;
|
|
57150
|
+
entryIsFile = resolved.isFile;
|
|
57151
|
+
}
|
|
57152
|
+
if (entryIsDirectory) {
|
|
57153
|
+
const skillMdPath = path12.join(entryPath, "SKILL.md");
|
|
57154
|
+
if (fs13.existsSync(skillMdPath)) {
|
|
56474
57155
|
try {
|
|
56475
|
-
const content =
|
|
57156
|
+
const content = fs13.readFileSync(skillMdPath, "utf-8");
|
|
56476
57157
|
const description = parseSkillDescription(content);
|
|
56477
57158
|
skills.push({
|
|
56478
57159
|
name: entry.name,
|
|
@@ -56480,7 +57161,7 @@ function loadSkillsFromDir(dir, source) {
|
|
|
56480
57161
|
content,
|
|
56481
57162
|
filePath: skillMdPath,
|
|
56482
57163
|
source,
|
|
56483
|
-
baseDir:
|
|
57164
|
+
baseDir: entryPath
|
|
56484
57165
|
});
|
|
56485
57166
|
} catch (e) {
|
|
56486
57167
|
diagnostics.push({
|
|
@@ -56490,64 +57171,72 @@ function loadSkillsFromDir(dir, source) {
|
|
|
56490
57171
|
});
|
|
56491
57172
|
}
|
|
56492
57173
|
}
|
|
56493
|
-
} else if (
|
|
57174
|
+
} else if (entryIsFile && entry.name.endsWith(".md")) {
|
|
56494
57175
|
const name = entry.name.slice(0, -3);
|
|
56495
57176
|
try {
|
|
56496
|
-
const content =
|
|
57177
|
+
const content = fs13.readFileSync(entryPath, "utf-8");
|
|
56497
57178
|
const description = parseSkillDescription(content);
|
|
56498
57179
|
skills.push({
|
|
56499
57180
|
name,
|
|
56500
57181
|
description,
|
|
56501
57182
|
content,
|
|
56502
|
-
filePath:
|
|
57183
|
+
filePath: entryPath,
|
|
56503
57184
|
source,
|
|
56504
|
-
baseDir:
|
|
57185
|
+
baseDir: path12.dirname(entryPath)
|
|
56505
57186
|
});
|
|
56506
57187
|
} catch (e) {
|
|
56507
57188
|
diagnostics.push({
|
|
56508
57189
|
type: "warning",
|
|
56509
57190
|
message: `Failed to load skill: ${name}`,
|
|
56510
|
-
path:
|
|
57191
|
+
path: entryPath
|
|
56511
57192
|
});
|
|
56512
57193
|
}
|
|
56513
57194
|
}
|
|
56514
57195
|
}
|
|
56515
57196
|
return { skills, diagnostics };
|
|
56516
57197
|
}
|
|
57198
|
+
function discoverAgentsSkillsDirs(cwd) {
|
|
57199
|
+
const resolvedCwd = path12.resolve(cwd || process.cwd());
|
|
57200
|
+
const projectRoot = resolveCliProjectRoot(resolvedCwd);
|
|
57201
|
+
const projectAgentsDirs = [];
|
|
57202
|
+
let current = projectRoot;
|
|
57203
|
+
while (true) {
|
|
57204
|
+
projectAgentsDirs.push(path12.join(current, ".agents", "skills"));
|
|
57205
|
+
if (current === resolvedCwd) break;
|
|
57206
|
+
const child = path12.relative(current, resolvedCwd).split(path12.sep)[0];
|
|
57207
|
+
if (!child) break;
|
|
57208
|
+
current = path12.join(current, child);
|
|
57209
|
+
}
|
|
57210
|
+
return { userAgentsDir: path12.join(os4.homedir(), ".agents", "skills"), projectAgentsDirs };
|
|
57211
|
+
}
|
|
57212
|
+
function buildSkillDirs(options) {
|
|
57213
|
+
const { userAgentsDir, projectAgentsDirs } = discoverAgentsSkillsDirs(options.cwd);
|
|
57214
|
+
return [
|
|
57215
|
+
{ dir: options.builtinDir, source: "builtin" },
|
|
57216
|
+
{ dir: userAgentsDir, source: "user-agents" },
|
|
57217
|
+
{ dir: options.userDir, source: "user" },
|
|
57218
|
+
...projectAgentsDirs.map((dir) => ({ dir, source: "project-agents" })),
|
|
57219
|
+
{ dir: options.projectDir, source: "project" }
|
|
57220
|
+
];
|
|
57221
|
+
}
|
|
56517
57222
|
function loadSkills(options) {
|
|
56518
|
-
const { builtinDir, userDir, projectDir } = options;
|
|
56519
57223
|
const skillMap = /* @__PURE__ */ new Map();
|
|
56520
57224
|
const diagnostics = [];
|
|
56521
|
-
const
|
|
56522
|
-
|
|
56523
|
-
|
|
56524
|
-
}
|
|
56525
|
-
diagnostics.push(...builtinResult.diagnostics);
|
|
56526
|
-
const userResult = loadSkillsFromDir(userDir, "user");
|
|
56527
|
-
for (const skill of userResult.skills) {
|
|
56528
|
-
if (skillMap.has(skill.name)) {
|
|
56529
|
-
diagnostics.push({
|
|
56530
|
-
type: "collision",
|
|
56531
|
-
message: `Skill "${skill.name}" collision: user skill overrides builtin`,
|
|
56532
|
-
path: skill.filePath
|
|
56533
|
-
});
|
|
56534
|
-
}
|
|
56535
|
-
skillMap.set(skill.name, skill);
|
|
56536
|
-
}
|
|
56537
|
-
diagnostics.push(...userResult.diagnostics);
|
|
56538
|
-
const projectResult = loadSkillsFromDir(projectDir, "project");
|
|
56539
|
-
for (const skill of projectResult.skills) {
|
|
56540
|
-
if (skillMap.has(skill.name)) {
|
|
57225
|
+
for (const { dir, source } of options.dirs) {
|
|
57226
|
+
const result = loadSkillsFromDir(dir, source);
|
|
57227
|
+
for (const skill of result.skills) {
|
|
56541
57228
|
const existing = skillMap.get(skill.name);
|
|
56542
|
-
|
|
56543
|
-
|
|
56544
|
-
|
|
56545
|
-
|
|
56546
|
-
|
|
57229
|
+
if (existing) {
|
|
57230
|
+
diagnostics.push({
|
|
57231
|
+
type: "collision",
|
|
57232
|
+
message: `Skill "${skill.name}" collision: ${source} skill overrides ${existing.source}`,
|
|
57233
|
+
path: skill.filePath
|
|
57234
|
+
});
|
|
57235
|
+
}
|
|
57236
|
+
skillMap.set(skill.name, skill);
|
|
56547
57237
|
}
|
|
56548
|
-
|
|
57238
|
+
diagnostics.push(...result.diagnostics);
|
|
56549
57239
|
}
|
|
56550
|
-
diagnostics.push(...projectResult.diagnostics);
|
|
56551
57240
|
return { skills: Array.from(skillMap.values()), diagnostics };
|
|
56552
57241
|
}
|
|
56553
57242
|
function formatSkillsForPrompt(skills) {
|
|
@@ -56688,9 +57377,12 @@ function validateSkillName(name) {
|
|
|
56688
57377
|
return { valid: true };
|
|
56689
57378
|
}
|
|
56690
57379
|
|
|
57380
|
+
// src/interactive-mode.ts
|
|
57381
|
+
import * as path29 from "path";
|
|
57382
|
+
|
|
56691
57383
|
// src/capabilities/read-file-understanding.ts
|
|
56692
|
-
import * as
|
|
56693
|
-
import * as
|
|
57384
|
+
import * as path21 from "node:path";
|
|
57385
|
+
import * as fs21 from "node:fs/promises";
|
|
56694
57386
|
|
|
56695
57387
|
// src/core/provider-capabilities.ts
|
|
56696
57388
|
var PLATFORM_DISPLAY_NAMES = {
|
|
@@ -56716,8 +57408,8 @@ function getProviderDisplayName(platform2) {
|
|
|
56716
57408
|
}
|
|
56717
57409
|
|
|
56718
57410
|
// src/files/adapters/kimi-adapter.ts
|
|
56719
|
-
import * as
|
|
56720
|
-
import * as
|
|
57411
|
+
import * as fs14 from "node:fs";
|
|
57412
|
+
import * as path13 from "node:path";
|
|
56721
57413
|
|
|
56722
57414
|
// src/files/errors.ts
|
|
56723
57415
|
var FileErrorMessages = {
|
|
@@ -56854,17 +57546,17 @@ var KimiFileAdapter = class {
|
|
|
56854
57546
|
// Upload
|
|
56855
57547
|
// ============================================================================
|
|
56856
57548
|
async upload(filePath, options = {}) {
|
|
56857
|
-
const fileName = options.sourceName ||
|
|
57549
|
+
const fileName = options.sourceName || path13.basename(filePath);
|
|
56858
57550
|
const mimeType = options.mimeType || this.guessMimeType(fileName);
|
|
56859
57551
|
const purpose = this.detectPurpose(filePath, options.purpose, mimeType);
|
|
56860
|
-
const stats =
|
|
57552
|
+
const stats = fs14.statSync(filePath);
|
|
56861
57553
|
if (stats.size > this.capabilities.maxFileSize) {
|
|
56862
57554
|
throw new FileManagerError(
|
|
56863
57555
|
"FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
|
|
56864
57556
|
`File size ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds Kimi limit of 100MB`
|
|
56865
57557
|
);
|
|
56866
57558
|
}
|
|
56867
|
-
const fileBuffer =
|
|
57559
|
+
const fileBuffer = fs14.readFileSync(filePath);
|
|
56868
57560
|
const file = new File([fileBuffer], fileName, { type: mimeType });
|
|
56869
57561
|
const formData = new FormData();
|
|
56870
57562
|
formData.append("file", file);
|
|
@@ -56916,7 +57608,7 @@ var KimiFileAdapter = class {
|
|
|
56916
57608
|
return "file-extract";
|
|
56917
57609
|
}
|
|
56918
57610
|
guessMimeType(filename) {
|
|
56919
|
-
const ext =
|
|
57611
|
+
const ext = path13.extname(filename).toLowerCase();
|
|
56920
57612
|
switch (ext) {
|
|
56921
57613
|
case ".jpg":
|
|
56922
57614
|
case ".jpeg":
|
|
@@ -57078,8 +57770,8 @@ var KimiFileAdapter = class {
|
|
|
57078
57770
|
};
|
|
57079
57771
|
|
|
57080
57772
|
// src/files/adapters/gemini-adapter.ts
|
|
57081
|
-
import * as
|
|
57082
|
-
import * as
|
|
57773
|
+
import * as fs15 from "node:fs";
|
|
57774
|
+
import * as path14 from "node:path";
|
|
57083
57775
|
import { Readable } from "node:stream";
|
|
57084
57776
|
var GeminiFileAdapter = class {
|
|
57085
57777
|
platform = "gemini";
|
|
@@ -57136,7 +57828,7 @@ var GeminiFileAdapter = class {
|
|
|
57136
57828
|
// Upload
|
|
57137
57829
|
// ============================================================================
|
|
57138
57830
|
async upload(filePath, options = {}) {
|
|
57139
|
-
const stats =
|
|
57831
|
+
const stats = fs15.statSync(filePath);
|
|
57140
57832
|
if (stats.size > this.capabilities.maxFileSize) {
|
|
57141
57833
|
throw new FileManagerError(
|
|
57142
57834
|
"FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
|
|
@@ -57144,7 +57836,7 @@ var GeminiFileAdapter = class {
|
|
|
57144
57836
|
);
|
|
57145
57837
|
}
|
|
57146
57838
|
const mimeType = options.mimeType || this.guessMimeType(filePath);
|
|
57147
|
-
const displayName = options.sourceName ||
|
|
57839
|
+
const displayName = options.sourceName || path14.basename(filePath);
|
|
57148
57840
|
const startResponse = await fetch(
|
|
57149
57841
|
`${this.baseUrl}/upload/v1beta/files?key=${this.apiKey}`,
|
|
57150
57842
|
{
|
|
@@ -57175,7 +57867,7 @@ var GeminiFileAdapter = class {
|
|
|
57175
57867
|
"No upload URL received"
|
|
57176
57868
|
);
|
|
57177
57869
|
}
|
|
57178
|
-
const fileStream = Readable.toWeb(
|
|
57870
|
+
const fileStream = Readable.toWeb(fs15.createReadStream(filePath));
|
|
57179
57871
|
const uploadResponse = await fetch(uploadUrl, {
|
|
57180
57872
|
method: "POST",
|
|
57181
57873
|
headers: {
|
|
@@ -57379,8 +58071,8 @@ var GeminiFileAdapter = class {
|
|
|
57379
58071
|
};
|
|
57380
58072
|
|
|
57381
58073
|
// src/files/adapters/openai-compatible-files-adapter.ts
|
|
57382
|
-
import * as
|
|
57383
|
-
import * as
|
|
58074
|
+
import * as fs16 from "node:fs";
|
|
58075
|
+
import * as path15 from "node:path";
|
|
57384
58076
|
var OpenAICompatibleFilesAdapter = class {
|
|
57385
58077
|
constructor(apiKey, baseUrl, extraHeaders = {}) {
|
|
57386
58078
|
this.apiKey = apiKey;
|
|
@@ -57406,16 +58098,16 @@ var OpenAICompatibleFilesAdapter = class {
|
|
|
57406
58098
|
]
|
|
57407
58099
|
};
|
|
57408
58100
|
async upload(filePath, options = {}) {
|
|
57409
|
-
const fileName = options.sourceName ||
|
|
58101
|
+
const fileName = options.sourceName || path15.basename(filePath);
|
|
57410
58102
|
const mimeType = options.mimeType || guessMimeType(fileName);
|
|
57411
|
-
const stats =
|
|
58103
|
+
const stats = fs16.statSync(filePath);
|
|
57412
58104
|
if (stats.size > this.capabilities.maxFileSize) {
|
|
57413
58105
|
throw new FileManagerError(
|
|
57414
58106
|
"FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
|
|
57415
58107
|
`File size ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds OpenAI-compatible Files limit of ${this.capabilities.maxFileSize / 1024 / 1024}MB`
|
|
57416
58108
|
);
|
|
57417
58109
|
}
|
|
57418
|
-
const file = new File([
|
|
58110
|
+
const file = new File([fs16.readFileSync(filePath)], fileName, { type: mimeType });
|
|
57419
58111
|
const formData = new FormData();
|
|
57420
58112
|
formData.append("file", file);
|
|
57421
58113
|
formData.append("purpose", options.purpose && options.purpose !== "auto" ? options.purpose : "file-extract");
|
|
@@ -57532,7 +58224,7 @@ function extractContentText(raw) {
|
|
|
57532
58224
|
return raw;
|
|
57533
58225
|
}
|
|
57534
58226
|
function guessMimeType(filename) {
|
|
57535
|
-
const ext =
|
|
58227
|
+
const ext = path15.extname(filename).toLowerCase();
|
|
57536
58228
|
switch (ext) {
|
|
57537
58229
|
case ".pdf":
|
|
57538
58230
|
return "application/pdf";
|
|
@@ -57548,13 +58240,13 @@ function guessMimeType(filename) {
|
|
|
57548
58240
|
}
|
|
57549
58241
|
|
|
57550
58242
|
// src/files/file-manager.ts
|
|
57551
|
-
import * as
|
|
57552
|
-
import * as
|
|
58243
|
+
import * as fs20 from "node:fs";
|
|
58244
|
+
import * as path20 from "node:path";
|
|
57553
58245
|
import * as crypto2 from "node:crypto";
|
|
57554
58246
|
|
|
57555
58247
|
// src/files/file-cache.ts
|
|
57556
|
-
import * as
|
|
57557
|
-
import * as
|
|
58248
|
+
import * as fs17 from "node:fs";
|
|
58249
|
+
import * as path17 from "node:path";
|
|
57558
58250
|
import * as crypto from "node:crypto";
|
|
57559
58251
|
|
|
57560
58252
|
// src/files/logger.ts
|
|
@@ -57649,14 +58341,14 @@ var DEFAULT_PIC_OPTIONS = {
|
|
|
57649
58341
|
};
|
|
57650
58342
|
|
|
57651
58343
|
// src/files/utils.ts
|
|
57652
|
-
import * as
|
|
57653
|
-
import { homedir as
|
|
58344
|
+
import * as path16 from "node:path";
|
|
58345
|
+
import { homedir as homedir5 } from "node:os";
|
|
57654
58346
|
var WINDOWS_ABSOLUTE_PATH_RE = /^(?:[a-zA-Z]:[\\/]|[\\/]{2}[^\\/]+[\\/][^\\/]+)/;
|
|
57655
58347
|
function isWindowsAbsolutePath(filePath) {
|
|
57656
58348
|
return WINDOWS_ABSOLUTE_PATH_RE.test(filePath);
|
|
57657
58349
|
}
|
|
57658
58350
|
function getHomeDirectory() {
|
|
57659
|
-
return
|
|
58351
|
+
return homedir5() || process.env.USERPROFILE || process.env.HOME || ".";
|
|
57660
58352
|
}
|
|
57661
58353
|
function looksLikeFilePath(inputPath) {
|
|
57662
58354
|
return inputPath.startsWith("/") || inputPath.startsWith("~") || inputPath.startsWith("./") || inputPath.startsWith("../") || inputPath.startsWith(".\\") || inputPath.startsWith("..\\") || isWindowsAbsolutePath(inputPath);
|
|
@@ -57670,13 +58362,13 @@ function formatBytes(bytes) {
|
|
|
57670
58362
|
}
|
|
57671
58363
|
function resolvePath2(inputPath) {
|
|
57672
58364
|
if (inputPath.startsWith("~")) {
|
|
57673
|
-
return
|
|
58365
|
+
return path16.join(getHomeDirectory(), inputPath.slice(1));
|
|
57674
58366
|
}
|
|
57675
58367
|
if (isWindowsAbsolutePath(inputPath)) {
|
|
57676
58368
|
return inputPath;
|
|
57677
58369
|
}
|
|
57678
|
-
if (!
|
|
57679
|
-
return
|
|
58370
|
+
if (!path16.isAbsolute(inputPath)) {
|
|
58371
|
+
return path16.resolve(process.cwd(), inputPath);
|
|
57680
58372
|
}
|
|
57681
58373
|
return inputPath;
|
|
57682
58374
|
}
|
|
@@ -57704,8 +58396,8 @@ var FileCache = class _FileCache {
|
|
|
57704
58396
|
maxEntries;
|
|
57705
58397
|
constructor(baseDir, maxEntries = DEFAULT_MAX_CACHE_ENTRIES) {
|
|
57706
58398
|
this.baseDir = baseDir;
|
|
57707
|
-
this.dataDir =
|
|
57708
|
-
this.indexPath =
|
|
58399
|
+
this.dataDir = path17.join(baseDir, "data");
|
|
58400
|
+
this.indexPath = path17.join(baseDir, "index.json");
|
|
57709
58401
|
this.maxEntries = maxEntries;
|
|
57710
58402
|
this.index = this.loadIndex();
|
|
57711
58403
|
this.ensureDirectories();
|
|
@@ -57714,22 +58406,22 @@ var FileCache = class _FileCache {
|
|
|
57714
58406
|
// Directory Management
|
|
57715
58407
|
// ============================================================================
|
|
57716
58408
|
ensureDirectories() {
|
|
57717
|
-
if (!
|
|
57718
|
-
|
|
58409
|
+
if (!fs17.existsSync(this.baseDir)) {
|
|
58410
|
+
fs17.mkdirSync(this.baseDir, { recursive: true });
|
|
57719
58411
|
}
|
|
57720
|
-
if (!
|
|
57721
|
-
|
|
58412
|
+
if (!fs17.existsSync(this.dataDir)) {
|
|
58413
|
+
fs17.mkdirSync(this.dataDir, { recursive: true });
|
|
57722
58414
|
}
|
|
57723
58415
|
}
|
|
57724
58416
|
// ============================================================================
|
|
57725
58417
|
// Index Management
|
|
57726
58418
|
// ============================================================================
|
|
57727
58419
|
loadIndex() {
|
|
57728
|
-
if (!
|
|
58420
|
+
if (!fs17.existsSync(this.indexPath)) {
|
|
57729
58421
|
return { version: CACHE_VERSION, files: {}, pathHints: {} };
|
|
57730
58422
|
}
|
|
57731
58423
|
try {
|
|
57732
|
-
const data = JSON.parse(
|
|
58424
|
+
const data = JSON.parse(fs17.readFileSync(this.indexPath, "utf-8"));
|
|
57733
58425
|
if (data.version !== CACHE_VERSION) {
|
|
57734
58426
|
cacheLogger.warn(`Index version mismatch: ${data.version} vs ${CACHE_VERSION}`);
|
|
57735
58427
|
}
|
|
@@ -57745,7 +58437,7 @@ var FileCache = class _FileCache {
|
|
|
57745
58437
|
}
|
|
57746
58438
|
saveIndex() {
|
|
57747
58439
|
try {
|
|
57748
|
-
|
|
58440
|
+
fs17.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
|
|
57749
58441
|
} catch (err) {
|
|
57750
58442
|
cacheLogger.error(" Failed to save index:", err);
|
|
57751
58443
|
throw err;
|
|
@@ -57755,11 +58447,11 @@ var FileCache = class _FileCache {
|
|
|
57755
58447
|
// Hash Computation
|
|
57756
58448
|
// ============================================================================
|
|
57757
58449
|
async computeHash(filePath) {
|
|
57758
|
-
return new Promise((
|
|
58450
|
+
return new Promise((resolve7, reject) => {
|
|
57759
58451
|
const hash = crypto.createHash("sha256");
|
|
57760
|
-
const stream =
|
|
58452
|
+
const stream = fs17.createReadStream(filePath);
|
|
57761
58453
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
57762
|
-
stream.on("end", () =>
|
|
58454
|
+
stream.on("end", () => resolve7(hash.digest("hex")));
|
|
57763
58455
|
stream.on("error", reject);
|
|
57764
58456
|
});
|
|
57765
58457
|
}
|
|
@@ -57771,25 +58463,25 @@ var FileCache = class _FileCache {
|
|
|
57771
58463
|
// ============================================================================
|
|
57772
58464
|
getStoragePath(hash) {
|
|
57773
58465
|
const subdir = hash.slice(0, 2);
|
|
57774
|
-
const fullDir =
|
|
57775
|
-
if (!
|
|
57776
|
-
|
|
58466
|
+
const fullDir = path17.join(this.dataDir, subdir);
|
|
58467
|
+
if (!fs17.existsSync(fullDir)) {
|
|
58468
|
+
fs17.mkdirSync(fullDir, { recursive: true });
|
|
57777
58469
|
}
|
|
57778
|
-
return
|
|
58470
|
+
return path17.join(fullDir, hash);
|
|
57779
58471
|
}
|
|
57780
58472
|
getStorageRelativePath(hash) {
|
|
57781
58473
|
const subdir = hash.slice(0, 2);
|
|
57782
|
-
return
|
|
58474
|
+
return path17.join(subdir, hash);
|
|
57783
58475
|
}
|
|
57784
58476
|
async storeFile(sourcePath, name, mimeType) {
|
|
57785
58477
|
const hash = await this.computeHash(sourcePath);
|
|
57786
58478
|
const storagePath = this.getStoragePath(hash);
|
|
57787
58479
|
this.rememberPathHint(sourcePath, hash, name);
|
|
57788
|
-
if (
|
|
58480
|
+
if (fs17.existsSync(storagePath)) {
|
|
57789
58481
|
return { hash, localPath: storagePath };
|
|
57790
58482
|
}
|
|
57791
|
-
|
|
57792
|
-
const stat2 =
|
|
58483
|
+
fs17.copyFileSync(sourcePath, storagePath);
|
|
58484
|
+
const stat2 = fs17.statSync(storagePath);
|
|
57793
58485
|
this.index.files[hash] = {
|
|
57794
58486
|
hash,
|
|
57795
58487
|
name,
|
|
@@ -57806,10 +58498,10 @@ var FileCache = class _FileCache {
|
|
|
57806
58498
|
async storeBuffer(data, name, mimeType) {
|
|
57807
58499
|
const hash = this.computeHashSync(data);
|
|
57808
58500
|
const storagePath = this.getStoragePath(hash);
|
|
57809
|
-
if (
|
|
58501
|
+
if (fs17.existsSync(storagePath)) {
|
|
57810
58502
|
return { hash, localPath: storagePath };
|
|
57811
58503
|
}
|
|
57812
|
-
|
|
58504
|
+
fs17.writeFileSync(storagePath, data);
|
|
57813
58505
|
this.index.files[hash] = {
|
|
57814
58506
|
hash,
|
|
57815
58507
|
name,
|
|
@@ -57841,7 +58533,7 @@ var FileCache = class _FileCache {
|
|
|
57841
58533
|
getLocalPath(hash) {
|
|
57842
58534
|
const entry = this.index.files[hash];
|
|
57843
58535
|
if (!entry) return void 0;
|
|
57844
|
-
return
|
|
58536
|
+
return path17.join(this.dataDir, entry.localPath);
|
|
57845
58537
|
}
|
|
57846
58538
|
exists(hash) {
|
|
57847
58539
|
return hash in this.index.files;
|
|
@@ -57881,7 +58573,7 @@ var FileCache = class _FileCache {
|
|
|
57881
58573
|
getPathHint(filePath) {
|
|
57882
58574
|
try {
|
|
57883
58575
|
const resolvedPath = this.getResolvedHintPath(filePath);
|
|
57884
|
-
const stat2 =
|
|
58576
|
+
const stat2 = fs17.statSync(resolvedPath);
|
|
57885
58577
|
if (!stat2.isFile()) return void 0;
|
|
57886
58578
|
const normalizedMtimeMs = this.normalizeHintMtimeMs(stat2.mtimeMs);
|
|
57887
58579
|
const key = this.getPathHintKey(resolvedPath);
|
|
@@ -57911,7 +58603,7 @@ var FileCache = class _FileCache {
|
|
|
57911
58603
|
rememberPathHint(filePath, hash, name) {
|
|
57912
58604
|
try {
|
|
57913
58605
|
const resolvedPath = this.getResolvedHintPath(filePath);
|
|
57914
|
-
const stat2 =
|
|
58606
|
+
const stat2 = fs17.statSync(resolvedPath);
|
|
57915
58607
|
if (!stat2.isFile()) return;
|
|
57916
58608
|
const entry = this.index.files[hash];
|
|
57917
58609
|
const normalizedMtimeMs = this.normalizeHintMtimeMs(stat2.mtimeMs);
|
|
@@ -57921,7 +58613,7 @@ var FileCache = class _FileCache {
|
|
|
57921
58613
|
this.index.pathHints[this.getPathHintKey(resolvedPath)] = {
|
|
57922
58614
|
path: resolvedPath,
|
|
57923
58615
|
hash,
|
|
57924
|
-
name: name || entry?.name ||
|
|
58616
|
+
name: name || entry?.name || path17.basename(resolvedPath),
|
|
57925
58617
|
size: stat2.size,
|
|
57926
58618
|
mtimeMs: normalizedMtimeMs,
|
|
57927
58619
|
lastSeenAt: Date.now(),
|
|
@@ -57969,9 +58661,9 @@ var FileCache = class _FileCache {
|
|
|
57969
58661
|
deleteEntry(hash, entry) {
|
|
57970
58662
|
entry = entry || this.index.files[hash];
|
|
57971
58663
|
if (!entry) return;
|
|
57972
|
-
const localPath =
|
|
57973
|
-
if (
|
|
57974
|
-
|
|
58664
|
+
const localPath = path17.join(this.dataDir, entry.localPath);
|
|
58665
|
+
if (fs17.existsSync(localPath)) {
|
|
58666
|
+
fs17.unlinkSync(localPath);
|
|
57975
58667
|
}
|
|
57976
58668
|
delete this.index.files[hash];
|
|
57977
58669
|
if (this.index.pathHints) {
|
|
@@ -57985,9 +58677,9 @@ var FileCache = class _FileCache {
|
|
|
57985
58677
|
}
|
|
57986
58678
|
clear() {
|
|
57987
58679
|
for (const entry of Object.values(this.index.files)) {
|
|
57988
|
-
const localPath =
|
|
57989
|
-
if (
|
|
57990
|
-
|
|
58680
|
+
const localPath = path17.join(this.dataDir, entry.localPath);
|
|
58681
|
+
if (fs17.existsSync(localPath)) {
|
|
58682
|
+
fs17.unlinkSync(localPath);
|
|
57991
58683
|
}
|
|
57992
58684
|
}
|
|
57993
58685
|
this.index = { version: CACHE_VERSION, files: {}, pathHints: {} };
|
|
@@ -58040,11 +58732,11 @@ var FileCache = class _FileCache {
|
|
|
58040
58732
|
};
|
|
58041
58733
|
}
|
|
58042
58734
|
static getMimeType(fileName) {
|
|
58043
|
-
const ext =
|
|
58735
|
+
const ext = path17.extname(fileName).toLowerCase();
|
|
58044
58736
|
return MIME_TYPES[ext] || "application/octet-stream";
|
|
58045
58737
|
}
|
|
58046
58738
|
static getFileTypeFromName(fileName) {
|
|
58047
|
-
const baseName =
|
|
58739
|
+
const baseName = path17.basename(fileName);
|
|
58048
58740
|
if (!baseName || baseName.startsWith(".")) {
|
|
58049
58741
|
return void 0;
|
|
58050
58742
|
}
|
|
@@ -58075,7 +58767,7 @@ var FileCache = class _FileCache {
|
|
|
58075
58767
|
getResolvedHintPath(filePath) {
|
|
58076
58768
|
const resolvedPath = resolvePath2(filePath);
|
|
58077
58769
|
try {
|
|
58078
|
-
return
|
|
58770
|
+
return fs17.realpathSync.native ? fs17.realpathSync.native(resolvedPath) : fs17.realpathSync(resolvedPath);
|
|
58079
58771
|
} catch {
|
|
58080
58772
|
return resolvedPath;
|
|
58081
58773
|
}
|
|
@@ -58083,8 +58775,8 @@ var FileCache = class _FileCache {
|
|
|
58083
58775
|
};
|
|
58084
58776
|
|
|
58085
58777
|
// src/files/session-file-manager.ts
|
|
58086
|
-
import * as
|
|
58087
|
-
import * as
|
|
58778
|
+
import * as fs18 from "node:fs";
|
|
58779
|
+
import * as path18 from "node:path";
|
|
58088
58780
|
var INITIAL_REFRESH_BACKOFF_MS = 6e4;
|
|
58089
58781
|
var MAX_REFRESH_BACKOFF_MS = 60 * 60 * 1e3;
|
|
58090
58782
|
var SessionFileManager = class {
|
|
@@ -58098,7 +58790,7 @@ var SessionFileManager = class {
|
|
|
58098
58790
|
constructor(sessionId, sessionsDir, fileCache, authFingerprint) {
|
|
58099
58791
|
this.sessionId = sessionId;
|
|
58100
58792
|
this.sessionsDir = sessionsDir;
|
|
58101
|
-
this.statePath =
|
|
58793
|
+
this.statePath = path18.join(this.sessionsDir, `${sessionId}-files.json`);
|
|
58102
58794
|
this.fileCache = fileCache;
|
|
58103
58795
|
this.authFingerprint = authFingerprint;
|
|
58104
58796
|
this.state = this.loadState();
|
|
@@ -58108,15 +58800,15 @@ var SessionFileManager = class {
|
|
|
58108
58800
|
// Directory Management
|
|
58109
58801
|
// ============================================================================
|
|
58110
58802
|
ensureDirectories() {
|
|
58111
|
-
if (!
|
|
58112
|
-
|
|
58803
|
+
if (!fs18.existsSync(this.sessionsDir)) {
|
|
58804
|
+
fs18.mkdirSync(this.sessionsDir, { recursive: true });
|
|
58113
58805
|
}
|
|
58114
58806
|
}
|
|
58115
58807
|
// ============================================================================
|
|
58116
58808
|
// State Management
|
|
58117
58809
|
// ============================================================================
|
|
58118
58810
|
loadState() {
|
|
58119
|
-
if (!
|
|
58811
|
+
if (!fs18.existsSync(this.statePath)) {
|
|
58120
58812
|
return {
|
|
58121
58813
|
sessionId: this.sessionId,
|
|
58122
58814
|
lastSyncedAt: 0,
|
|
@@ -58124,7 +58816,7 @@ var SessionFileManager = class {
|
|
|
58124
58816
|
};
|
|
58125
58817
|
}
|
|
58126
58818
|
try {
|
|
58127
|
-
return JSON.parse(
|
|
58819
|
+
return JSON.parse(fs18.readFileSync(this.statePath, "utf-8"));
|
|
58128
58820
|
} catch (err) {
|
|
58129
58821
|
sessionLogger.error(" Failed to load state:", err);
|
|
58130
58822
|
return {
|
|
@@ -58137,12 +58829,12 @@ var SessionFileManager = class {
|
|
|
58137
58829
|
saveState() {
|
|
58138
58830
|
try {
|
|
58139
58831
|
if (Object.keys(this.state.files).length === 0) {
|
|
58140
|
-
if (
|
|
58141
|
-
|
|
58832
|
+
if (fs18.existsSync(this.statePath)) {
|
|
58833
|
+
fs18.unlinkSync(this.statePath);
|
|
58142
58834
|
}
|
|
58143
58835
|
return;
|
|
58144
58836
|
}
|
|
58145
|
-
|
|
58837
|
+
fs18.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
|
|
58146
58838
|
} catch (err) {
|
|
58147
58839
|
sessionLogger.error(" Failed to save state:", err);
|
|
58148
58840
|
}
|
|
@@ -58288,7 +58980,7 @@ var SessionFileManager = class {
|
|
|
58288
58980
|
return { success: false, coolingDown: true };
|
|
58289
58981
|
}
|
|
58290
58982
|
const localPath = this.fileCache.getLocalPath(entry.hash);
|
|
58291
|
-
if (!localPath || !
|
|
58983
|
+
if (!localPath || !fs18.existsSync(localPath)) {
|
|
58292
58984
|
sessionLogger.warn(`Local file not found for ${fileId}`);
|
|
58293
58985
|
entry.status = "expired";
|
|
58294
58986
|
entry.error = "Local file missing";
|
|
@@ -58439,15 +59131,15 @@ var SessionFileManager = class {
|
|
|
58439
59131
|
// Static Utilities
|
|
58440
59132
|
// ============================================================================
|
|
58441
59133
|
static cleanupOldSessions(sessionsDir, maxAge = 30 * 24 * 60 * 60 * 1e3) {
|
|
58442
|
-
if (!
|
|
59134
|
+
if (!fs18.existsSync(sessionsDir)) return;
|
|
58443
59135
|
const now = Date.now();
|
|
58444
|
-
const files =
|
|
59136
|
+
const files = fs18.readdirSync(sessionsDir);
|
|
58445
59137
|
for (const file of files) {
|
|
58446
59138
|
if (!file.endsWith(".json")) continue;
|
|
58447
|
-
const filePath =
|
|
58448
|
-
const stat2 =
|
|
59139
|
+
const filePath = path18.join(sessionsDir, file);
|
|
59140
|
+
const stat2 = fs18.statSync(filePath);
|
|
58449
59141
|
if (now - stat2.mtime.getTime() > maxAge) {
|
|
58450
|
-
|
|
59142
|
+
fs18.unlinkSync(filePath);
|
|
58451
59143
|
sessionLogger.debug(`Cleaned up old session: ${file}`);
|
|
58452
59144
|
}
|
|
58453
59145
|
}
|
|
@@ -58455,8 +59147,8 @@ var SessionFileManager = class {
|
|
|
58455
59147
|
};
|
|
58456
59148
|
|
|
58457
59149
|
// src/files/ffmpeg-processor.ts
|
|
58458
|
-
import * as
|
|
58459
|
-
import * as
|
|
59150
|
+
import * as fs19 from "node:fs";
|
|
59151
|
+
import * as path19 from "node:path";
|
|
58460
59152
|
import { spawn } from "node:child_process";
|
|
58461
59153
|
var FFmpegProcessor = class {
|
|
58462
59154
|
ffmpegPath = "ffmpeg";
|
|
@@ -58469,17 +59161,17 @@ var FFmpegProcessor = class {
|
|
|
58469
59161
|
// Detection
|
|
58470
59162
|
// ============================================================================
|
|
58471
59163
|
async checkAvailability() {
|
|
58472
|
-
return new Promise((
|
|
59164
|
+
return new Promise((resolve7) => {
|
|
58473
59165
|
const proc = spawn(this.ffmpegPath, ["-version"]);
|
|
58474
|
-
proc.on("error", () =>
|
|
58475
|
-
proc.on("exit", (code) =>
|
|
59166
|
+
proc.on("error", () => resolve7(false));
|
|
59167
|
+
proc.on("exit", (code) => resolve7(code === 0));
|
|
58476
59168
|
});
|
|
58477
59169
|
}
|
|
58478
59170
|
// ============================================================================
|
|
58479
59171
|
// Video Analysis
|
|
58480
59172
|
// ============================================================================
|
|
58481
59173
|
async analyzeVideo(videoPath) {
|
|
58482
|
-
return new Promise((
|
|
59174
|
+
return new Promise((resolve7, reject) => {
|
|
58483
59175
|
const args = [
|
|
58484
59176
|
"-v",
|
|
58485
59177
|
"error",
|
|
@@ -58508,7 +59200,7 @@ var FFmpegProcessor = class {
|
|
|
58508
59200
|
}
|
|
58509
59201
|
try {
|
|
58510
59202
|
const info = this.parseProbeOutput(stdout, videoPath);
|
|
58511
|
-
|
|
59203
|
+
resolve7(info);
|
|
58512
59204
|
} catch (err) {
|
|
58513
59205
|
reject(err);
|
|
58514
59206
|
}
|
|
@@ -58560,7 +59252,7 @@ var FFmpegProcessor = class {
|
|
|
58560
59252
|
}
|
|
58561
59253
|
async compressVideo(inputPath, outputDir, info, opts, onProgress) {
|
|
58562
59254
|
const outputName = `compressed_${Date.now()}.mp4`;
|
|
58563
|
-
const outputPath =
|
|
59255
|
+
const outputPath = path19.join(outputDir, outputName);
|
|
58564
59256
|
const adaptiveParams = this.calculateAdaptiveParams(info.duration, opts);
|
|
58565
59257
|
const args = [
|
|
58566
59258
|
"-i",
|
|
@@ -58591,7 +59283,7 @@ var FFmpegProcessor = class {
|
|
|
58591
59283
|
onProgress?.(percent);
|
|
58592
59284
|
}
|
|
58593
59285
|
});
|
|
58594
|
-
const outputStat =
|
|
59286
|
+
const outputStat = fs19.statSync(outputPath);
|
|
58595
59287
|
return {
|
|
58596
59288
|
type: "video",
|
|
58597
59289
|
output: outputPath,
|
|
@@ -58622,9 +59314,9 @@ var FFmpegProcessor = class {
|
|
|
58622
59314
|
}
|
|
58623
59315
|
async extractKeyframes(inputPath, outputDir, info, opts, onProgress) {
|
|
58624
59316
|
const interval = Math.floor(info.duration / opts.keyframeCount);
|
|
58625
|
-
const framesDir =
|
|
58626
|
-
|
|
58627
|
-
const outputPattern =
|
|
59317
|
+
const framesDir = path19.join(outputDir, `keyframes_${Date.now()}`);
|
|
59318
|
+
fs19.mkdirSync(framesDir, { recursive: true });
|
|
59319
|
+
const outputPattern = path19.join(framesDir, "frame_%03d.jpg");
|
|
58628
59320
|
const args = [
|
|
58629
59321
|
"-i",
|
|
58630
59322
|
inputPath,
|
|
@@ -58642,10 +59334,10 @@ var FFmpegProcessor = class {
|
|
|
58642
59334
|
onProgress?.(percent);
|
|
58643
59335
|
}
|
|
58644
59336
|
});
|
|
58645
|
-
let frames =
|
|
59337
|
+
let frames = fs19.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path19.join(framesDir, f));
|
|
58646
59338
|
if (frames.length < opts.keyframeCount / 2) {
|
|
58647
|
-
|
|
58648
|
-
|
|
59339
|
+
fs19.rmSync(framesDir, { recursive: true, force: true });
|
|
59340
|
+
fs19.mkdirSync(framesDir, { recursive: true });
|
|
58649
59341
|
const uniformArgs = [
|
|
58650
59342
|
"-i",
|
|
58651
59343
|
inputPath,
|
|
@@ -58661,10 +59353,10 @@ var FFmpegProcessor = class {
|
|
|
58661
59353
|
onProgress?.(percent);
|
|
58662
59354
|
}
|
|
58663
59355
|
});
|
|
58664
|
-
frames =
|
|
59356
|
+
frames = fs19.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path19.join(framesDir, f));
|
|
58665
59357
|
}
|
|
58666
59358
|
const totalOutputSize = frames.reduce(
|
|
58667
|
-
(sum, f) => sum +
|
|
59359
|
+
(sum, f) => sum + fs19.statSync(f).size,
|
|
58668
59360
|
0
|
|
58669
59361
|
);
|
|
58670
59362
|
return {
|
|
@@ -58685,7 +59377,7 @@ var FFmpegProcessor = class {
|
|
|
58685
59377
|
const opts = { ...DEFAULT_PIC_OPTIONS, ...options };
|
|
58686
59378
|
const ext = opts.format === "webp" ? ".webp" : ".jpg";
|
|
58687
59379
|
const outputName = `optimized_${Date.now()}${ext}`;
|
|
58688
|
-
const outputPath =
|
|
59380
|
+
const outputPath = path19.join(outputDir, outputName);
|
|
58689
59381
|
const args = [
|
|
58690
59382
|
"-i",
|
|
58691
59383
|
inputPath,
|
|
@@ -58703,7 +59395,7 @@ var FFmpegProcessor = class {
|
|
|
58703
59395
|
// FFmpeg Execution
|
|
58704
59396
|
// ============================================================================
|
|
58705
59397
|
runFFmpeg(args) {
|
|
58706
|
-
return new Promise((
|
|
59398
|
+
return new Promise((resolve7, reject) => {
|
|
58707
59399
|
const proc = spawn(this.ffmpegPath, args);
|
|
58708
59400
|
let stderr = "";
|
|
58709
59401
|
proc.stderr.on("data", (data) => {
|
|
@@ -58718,7 +59410,7 @@ var FFmpegProcessor = class {
|
|
|
58718
59410
|
)
|
|
58719
59411
|
);
|
|
58720
59412
|
} else {
|
|
58721
|
-
|
|
59413
|
+
resolve7();
|
|
58722
59414
|
}
|
|
58723
59415
|
});
|
|
58724
59416
|
proc.on("error", (err) => {
|
|
@@ -58735,7 +59427,7 @@ var FFmpegProcessor = class {
|
|
|
58735
59427
|
// Progress Monitoring (for future use)
|
|
58736
59428
|
// ============================================================================
|
|
58737
59429
|
async runWithProgress(args, onProgress) {
|
|
58738
|
-
return new Promise((
|
|
59430
|
+
return new Promise((resolve7, reject) => {
|
|
58739
59431
|
const progressArgs = [
|
|
58740
59432
|
...args,
|
|
58741
59433
|
"-progress",
|
|
@@ -58765,7 +59457,7 @@ var FFmpegProcessor = class {
|
|
|
58765
59457
|
)
|
|
58766
59458
|
);
|
|
58767
59459
|
} else {
|
|
58768
|
-
|
|
59460
|
+
resolve7();
|
|
58769
59461
|
}
|
|
58770
59462
|
});
|
|
58771
59463
|
});
|
|
@@ -58860,8 +59552,8 @@ var DIRECTORY_LISTING_TTL_MS = 1500;
|
|
|
58860
59552
|
var FileManager = class {
|
|
58861
59553
|
constructor(options) {
|
|
58862
59554
|
this.options = options;
|
|
58863
|
-
const baseDir = options.baseDir ||
|
|
58864
|
-
const sessionsDir = options.sessionsDir ||
|
|
59555
|
+
const baseDir = options.baseDir || path20.join(process.env.HOME || ".", ".pie", "files");
|
|
59556
|
+
const sessionsDir = options.sessionsDir || path20.join(process.env.HOME || ".", ".pie", "sessions");
|
|
58865
59557
|
this.fileCache = new FileCache(baseDir);
|
|
58866
59558
|
this.authFingerprint = options.apiKey ? this.buildAuthFingerprint(options.apiKey) : void 0;
|
|
58867
59559
|
this.sessionManager = new SessionFileManager(
|
|
@@ -58872,7 +59564,7 @@ var FileManager = class {
|
|
|
58872
59564
|
);
|
|
58873
59565
|
this.ffmpeg = new FFmpegProcessor(options.ffmpegPath);
|
|
58874
59566
|
this.platform = normalizeFileManagerPlatform(options.platform);
|
|
58875
|
-
this.tempDir =
|
|
59567
|
+
this.tempDir = path20.join(baseDir, "temp");
|
|
58876
59568
|
this.ensureDirectories();
|
|
58877
59569
|
}
|
|
58878
59570
|
options;
|
|
@@ -58884,8 +59576,8 @@ var FileManager = class {
|
|
|
58884
59576
|
directoryListingCache = /* @__PURE__ */ new Map();
|
|
58885
59577
|
authFingerprint;
|
|
58886
59578
|
ensureDirectories() {
|
|
58887
|
-
if (!
|
|
58888
|
-
|
|
59579
|
+
if (!fs20.existsSync(this.tempDir)) {
|
|
59580
|
+
fs20.mkdirSync(this.tempDir, { recursive: true });
|
|
58889
59581
|
}
|
|
58890
59582
|
}
|
|
58891
59583
|
// ============================================================================
|
|
@@ -58915,8 +59607,8 @@ var FileManager = class {
|
|
|
58915
59607
|
// ============================================================================
|
|
58916
59608
|
async stageLocal(filePath, options = {}) {
|
|
58917
59609
|
const resolvedPath = resolvePath2(filePath);
|
|
58918
|
-
const sourceName = options.sourceName ||
|
|
58919
|
-
if (!
|
|
59610
|
+
const sourceName = options.sourceName || path20.basename(resolvedPath);
|
|
59611
|
+
if (!fs20.existsSync(resolvedPath)) {
|
|
58920
59612
|
throw new FileManagerError(
|
|
58921
59613
|
"LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
|
|
58922
59614
|
`File not found: ${filePath}`
|
|
@@ -58931,7 +59623,7 @@ var FileManager = class {
|
|
|
58931
59623
|
this.fileCache.rememberPathHint(resolvedPath, hash, sourceName);
|
|
58932
59624
|
this.invalidateDirectoryListingCacheForPath(resolvedPath);
|
|
58933
59625
|
const entry = this.fileCache.getByHash(hash);
|
|
58934
|
-
const size = entry?.size ??
|
|
59626
|
+
const size = entry?.size ?? fs20.statSync(resolvedPath).size;
|
|
58935
59627
|
return {
|
|
58936
59628
|
success: true,
|
|
58937
59629
|
hash,
|
|
@@ -58945,8 +59637,8 @@ var FileManager = class {
|
|
|
58945
59637
|
}
|
|
58946
59638
|
async upload(filePath, options = {}) {
|
|
58947
59639
|
const resolvedPath = resolvePath2(filePath);
|
|
58948
|
-
const sourceName = options.sourceName ||
|
|
58949
|
-
if (!
|
|
59640
|
+
const sourceName = options.sourceName || path20.basename(resolvedPath);
|
|
59641
|
+
if (!fs20.existsSync(resolvedPath)) {
|
|
58950
59642
|
throw new FileManagerError(
|
|
58951
59643
|
"LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
|
|
58952
59644
|
`File not found: ${filePath}`
|
|
@@ -59027,7 +59719,7 @@ var FileManager = class {
|
|
|
59027
59719
|
// ============================================================================
|
|
59028
59720
|
async uploadPic(filePath, options = {}) {
|
|
59029
59721
|
const resolvedPath = resolvePath2(filePath);
|
|
59030
|
-
if (!
|
|
59722
|
+
if (!fs20.existsSync(resolvedPath)) {
|
|
59031
59723
|
throw new FileManagerError(
|
|
59032
59724
|
"LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
|
|
59033
59725
|
`File not found: ${filePath}`
|
|
@@ -59035,7 +59727,7 @@ var FileManager = class {
|
|
|
59035
59727
|
}
|
|
59036
59728
|
const cachedResult = await this.tryReuseCachedSourceUpload(
|
|
59037
59729
|
resolvedPath,
|
|
59038
|
-
options.sourceName ||
|
|
59730
|
+
options.sourceName || path20.basename(resolvedPath),
|
|
59039
59731
|
options.platform || this.platform
|
|
59040
59732
|
);
|
|
59041
59733
|
if (cachedResult) {
|
|
@@ -59052,12 +59744,12 @@ var FileManager = class {
|
|
|
59052
59744
|
const result = await this.upload(optimizedPath, {
|
|
59053
59745
|
...options,
|
|
59054
59746
|
purpose: "image",
|
|
59055
|
-
sourceName:
|
|
59747
|
+
sourceName: path20.basename(resolvedPath)
|
|
59056
59748
|
});
|
|
59057
|
-
this.fileCache.rememberPathHint(resolvedPath, result.hash,
|
|
59749
|
+
this.fileCache.rememberPathHint(resolvedPath, result.hash, path20.basename(resolvedPath));
|
|
59058
59750
|
this.invalidateDirectoryListingCacheForPath(resolvedPath);
|
|
59059
59751
|
try {
|
|
59060
|
-
|
|
59752
|
+
fs20.unlinkSync(optimizedPath);
|
|
59061
59753
|
} catch {
|
|
59062
59754
|
}
|
|
59063
59755
|
return result;
|
|
@@ -59067,7 +59759,7 @@ var FileManager = class {
|
|
|
59067
59759
|
// ============================================================================
|
|
59068
59760
|
async uploadVideo(filePath, options = {}) {
|
|
59069
59761
|
const resolvedPath = resolvePath2(filePath);
|
|
59070
|
-
if (!
|
|
59762
|
+
if (!fs20.existsSync(resolvedPath)) {
|
|
59071
59763
|
throw new FileManagerError(
|
|
59072
59764
|
"LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
|
|
59073
59765
|
`File not found: ${filePath}`
|
|
@@ -59075,7 +59767,7 @@ var FileManager = class {
|
|
|
59075
59767
|
}
|
|
59076
59768
|
const cachedResult = await this.tryReuseCachedSourceUpload(
|
|
59077
59769
|
resolvedPath,
|
|
59078
|
-
options.sourceName ||
|
|
59770
|
+
options.sourceName || path20.basename(resolvedPath),
|
|
59079
59771
|
options.platform || this.platform
|
|
59080
59772
|
);
|
|
59081
59773
|
if (cachedResult) {
|
|
@@ -59125,9 +59817,9 @@ var FileManager = class {
|
|
|
59125
59817
|
result = await this.upload(preprocessResult.output, {
|
|
59126
59818
|
...options,
|
|
59127
59819
|
purpose: "video",
|
|
59128
|
-
sourceName:
|
|
59820
|
+
sourceName: path20.basename(resolvedPath)
|
|
59129
59821
|
});
|
|
59130
|
-
this.fileCache.rememberPathHint(resolvedPath, result.hash,
|
|
59822
|
+
this.fileCache.rememberPathHint(resolvedPath, result.hash, path20.basename(resolvedPath));
|
|
59131
59823
|
this.invalidateDirectoryListingCacheForPath(resolvedPath);
|
|
59132
59824
|
} else {
|
|
59133
59825
|
throw new FileManagerError(
|
|
@@ -59419,7 +60111,7 @@ var FileManager = class {
|
|
|
59419
60111
|
* Detect purpose from file path based on extension
|
|
59420
60112
|
*/
|
|
59421
60113
|
detectPurpose(filePath) {
|
|
59422
|
-
const ext =
|
|
60114
|
+
const ext = path20.extname(filePath).toLowerCase();
|
|
59423
60115
|
switch (ext) {
|
|
59424
60116
|
case ".mp4":
|
|
59425
60117
|
case ".mov":
|
|
@@ -59461,13 +60153,13 @@ var FileManager = class {
|
|
|
59461
60153
|
cleanupTempFiles(output) {
|
|
59462
60154
|
try {
|
|
59463
60155
|
if (typeof output === "string") {
|
|
59464
|
-
if (
|
|
59465
|
-
|
|
60156
|
+
if (fs20.existsSync(output)) {
|
|
60157
|
+
fs20.unlinkSync(output);
|
|
59466
60158
|
}
|
|
59467
60159
|
} else {
|
|
59468
60160
|
for (const file of output) {
|
|
59469
|
-
if (
|
|
59470
|
-
|
|
60161
|
+
if (fs20.existsSync(file)) {
|
|
60162
|
+
fs20.unlinkSync(file);
|
|
59471
60163
|
}
|
|
59472
60164
|
}
|
|
59473
60165
|
}
|
|
@@ -59499,7 +60191,7 @@ var FileManager = class {
|
|
|
59499
60191
|
}];
|
|
59500
60192
|
}
|
|
59501
60193
|
const localPath = this.fileCache.getLocalPath(entry.hash);
|
|
59502
|
-
if (localPath &&
|
|
60194
|
+
if (localPath && fs20.existsSync(localPath)) {
|
|
59503
60195
|
return [{
|
|
59504
60196
|
fileId,
|
|
59505
60197
|
name: cacheEntry.name,
|
|
@@ -59596,12 +60288,12 @@ var FileManager = class {
|
|
|
59596
60288
|
directories: []
|
|
59597
60289
|
};
|
|
59598
60290
|
try {
|
|
59599
|
-
const entries =
|
|
60291
|
+
const entries = fs20.readdirSync(resolvedDir, { withFileTypes: true });
|
|
59600
60292
|
for (const entry of entries) {
|
|
59601
60293
|
if (!entry.name || entry.name.startsWith(".")) {
|
|
59602
60294
|
continue;
|
|
59603
60295
|
}
|
|
59604
|
-
const fullPath =
|
|
60296
|
+
const fullPath = path20.join(resolvedDir, entry.name);
|
|
59605
60297
|
if (entry.isDirectory()) {
|
|
59606
60298
|
listing.directories.push({ name: entry.name, path: fullPath });
|
|
59607
60299
|
continue;
|
|
@@ -59610,7 +60302,7 @@ var FileManager = class {
|
|
|
59610
60302
|
let isFile = entry.isFile();
|
|
59611
60303
|
if (entry.isSymbolicLink()) {
|
|
59612
60304
|
try {
|
|
59613
|
-
const targetStat =
|
|
60305
|
+
const targetStat = fs20.statSync(fullPath);
|
|
59614
60306
|
isDirectory = targetStat.isDirectory();
|
|
59615
60307
|
isFile = targetStat.isFile();
|
|
59616
60308
|
} catch {
|
|
@@ -59628,7 +60320,7 @@ var FileManager = class {
|
|
|
59628
60320
|
if (!type) {
|
|
59629
60321
|
continue;
|
|
59630
60322
|
}
|
|
59631
|
-
const stat2 =
|
|
60323
|
+
const stat2 = fs20.statSync(fullPath);
|
|
59632
60324
|
listing.files.push({
|
|
59633
60325
|
name: entry.name,
|
|
59634
60326
|
path: fullPath,
|
|
@@ -59642,7 +60334,7 @@ var FileManager = class {
|
|
|
59642
60334
|
return listing;
|
|
59643
60335
|
}
|
|
59644
60336
|
invalidateDirectoryListingCacheForPath(filePath) {
|
|
59645
|
-
this.directoryListingCache.delete(
|
|
60337
|
+
this.directoryListingCache.delete(path20.dirname(resolvePath2(filePath)));
|
|
59646
60338
|
}
|
|
59647
60339
|
buildAuthFingerprint(apiKey) {
|
|
59648
60340
|
return crypto2.createHash("sha256").update(apiKey).digest("hex").slice(0, 16);
|
|
@@ -59691,8 +60383,8 @@ function createFileManagerForModel(params) {
|
|
|
59691
60383
|
sessionId: params.sessionId,
|
|
59692
60384
|
platform: platform2,
|
|
59693
60385
|
apiKey: params.apiKey,
|
|
59694
|
-
baseDir:
|
|
59695
|
-
sessionsDir:
|
|
60386
|
+
baseDir: path21.join(params.configDir, "files"),
|
|
60387
|
+
sessionsDir: path21.join(params.configDir, "sessions")
|
|
59696
60388
|
});
|
|
59697
60389
|
switch (getFileManagerAdapterKind(platform2)) {
|
|
59698
60390
|
case "kimi":
|
|
@@ -59727,15 +60419,15 @@ function isInlineMediaRequest(request) {
|
|
|
59727
60419
|
return request.kind === "image" || request.kind === "video";
|
|
59728
60420
|
}
|
|
59729
60421
|
async function prepareInlineMediaContent(params) {
|
|
59730
|
-
const stat2 = await
|
|
60422
|
+
const stat2 = await fs21.stat(params.request.absolutePath);
|
|
59731
60423
|
const limitMb = getCapabilityLimitMb(params.model, params.request.kind);
|
|
59732
60424
|
const limitBytes = limitMb * 1024 * 1024;
|
|
59733
60425
|
if (stat2.size > limitBytes) {
|
|
59734
60426
|
throw new Error(
|
|
59735
|
-
`${params.request.kind} understanding for ${params.model.provider}/${params.model.id} supports inline files up to ${limitMb}MB; ${
|
|
60427
|
+
`${params.request.kind} understanding for ${params.model.provider}/${params.model.id} supports inline files up to ${limitMb}MB; ${path21.basename(params.request.displayPath)} is ${(stat2.size / 1024 / 1024).toFixed(1)}MB. Configure a model with a file upload adapter, or compress/trim the file before reading it.`
|
|
59736
60428
|
);
|
|
59737
60429
|
}
|
|
59738
|
-
const data = await
|
|
60430
|
+
const data = await fs21.readFile(params.request.absolutePath, "base64");
|
|
59739
60431
|
const content = params.request.kind === "video" ? [{ type: "video", data, mimeType: params.request.mimeType }] : [{ type: "image", data, mimeType: params.request.mimeType }];
|
|
59740
60432
|
return {
|
|
59741
60433
|
content,
|
|
@@ -59755,7 +60447,7 @@ async function waitForReady(params) {
|
|
|
59755
60447
|
if (status.status === "error" || status.status === "expired") {
|
|
59756
60448
|
throw new Error(`Uploaded file is not ready: ${status.status}${status.error ? ` (${status.error})` : ""}`);
|
|
59757
60449
|
}
|
|
59758
|
-
await new Promise((
|
|
60450
|
+
await new Promise((resolve7) => setTimeout(resolve7, 1500));
|
|
59759
60451
|
}
|
|
59760
60452
|
throw new Error("Timed out waiting for uploaded file to become ready");
|
|
59761
60453
|
}
|
|
@@ -59771,7 +60463,7 @@ async function prepareFileContent(configDir, params) {
|
|
|
59771
60463
|
});
|
|
59772
60464
|
if (params.request.kind === "document") {
|
|
59773
60465
|
const upload2 = await manager.upload(params.request.absolutePath, {
|
|
59774
|
-
sourceName:
|
|
60466
|
+
sourceName: path21.basename(params.request.displayPath),
|
|
59775
60467
|
purpose: "file-extract"
|
|
59776
60468
|
});
|
|
59777
60469
|
await waitForReady({ manager, fileId: upload2.fileId, timeoutMs: 12e4, signal: params.request.signal });
|
|
@@ -59794,8 +60486,8 @@ async function prepareFileContent(configDir, params) {
|
|
|
59794
60486
|
}
|
|
59795
60487
|
};
|
|
59796
60488
|
}
|
|
59797
|
-
const upload = params.request.kind === "video" ? await manager.uploadVideo(params.request.absolutePath, { sourceName:
|
|
59798
|
-
sourceName:
|
|
60489
|
+
const upload = params.request.kind === "video" ? await manager.uploadVideo(params.request.absolutePath, { sourceName: path21.basename(params.request.displayPath), strategy: "compress" }) : await manager.upload(params.request.absolutePath, {
|
|
60490
|
+
sourceName: path21.basename(params.request.displayPath),
|
|
59799
60491
|
purpose: params.request.kind === "image" ? "image" : "file-extract"
|
|
59800
60492
|
});
|
|
59801
60493
|
if (params.request.kind !== "video") {
|
|
@@ -59851,8 +60543,8 @@ function createIsolatedRegexSession(pattern, ignoreCase) {
|
|
|
59851
60543
|
let initError;
|
|
59852
60544
|
let readyResolve;
|
|
59853
60545
|
let readyReject;
|
|
59854
|
-
const ready = new Promise((
|
|
59855
|
-
readyResolve =
|
|
60546
|
+
const ready = new Promise((resolve7, reject) => {
|
|
60547
|
+
readyResolve = resolve7;
|
|
59856
60548
|
readyReject = reject;
|
|
59857
60549
|
});
|
|
59858
60550
|
void ready.catch(() => void 0);
|
|
@@ -59874,7 +60566,7 @@ function createIsolatedRegexSession(pattern, ignoreCase) {
|
|
|
59874
60566
|
if (initError) throw initError;
|
|
59875
60567
|
if (signal?.aborted) throw new Error("Operation aborted");
|
|
59876
60568
|
const id = nextId++;
|
|
59877
|
-
return new Promise((
|
|
60569
|
+
return new Promise((resolve7, reject) => {
|
|
59878
60570
|
let settled = false;
|
|
59879
60571
|
const finish = (error, matches) => {
|
|
59880
60572
|
if (settled) return;
|
|
@@ -59884,7 +60576,7 @@ function createIsolatedRegexSession(pattern, ignoreCase) {
|
|
|
59884
60576
|
worker.off("message", onMessage);
|
|
59885
60577
|
worker.off("error", onWorkerError);
|
|
59886
60578
|
if (error) reject(error);
|
|
59887
|
-
else
|
|
60579
|
+
else resolve7(matches ?? []);
|
|
59888
60580
|
};
|
|
59889
60581
|
const terminate = (error) => {
|
|
59890
60582
|
disposed = true;
|
|
@@ -60214,22 +60906,22 @@ var ExecutionStateManager = class {
|
|
|
60214
60906
|
};
|
|
60215
60907
|
|
|
60216
60908
|
// src/session-trace.ts
|
|
60217
|
-
import * as
|
|
60218
|
-
import * as
|
|
60909
|
+
import * as fs22 from "node:fs";
|
|
60910
|
+
import * as path22 from "node:path";
|
|
60219
60911
|
function saveTraceFileBestEffort(tracePath, content) {
|
|
60220
60912
|
const tempPath = `${tracePath}.${process.pid}.${Date.now()}.tmp`;
|
|
60221
60913
|
try {
|
|
60222
|
-
|
|
60914
|
+
fs22.writeFileSync(tempPath, content, "utf8");
|
|
60223
60915
|
try {
|
|
60224
|
-
|
|
60916
|
+
fs22.renameSync(tempPath, tracePath);
|
|
60225
60917
|
return;
|
|
60226
60918
|
} catch {
|
|
60227
60919
|
try {
|
|
60228
|
-
|
|
60920
|
+
fs22.copyFileSync(tempPath, tracePath);
|
|
60229
60921
|
} catch {
|
|
60230
60922
|
} finally {
|
|
60231
60923
|
try {
|
|
60232
|
-
|
|
60924
|
+
fs22.unlinkSync(tempPath);
|
|
60233
60925
|
} catch {
|
|
60234
60926
|
}
|
|
60235
60927
|
}
|
|
@@ -60242,16 +60934,16 @@ var SessionTraceWriter = class extends SessionTraceSnapshotWriter {
|
|
|
60242
60934
|
super({
|
|
60243
60935
|
getSessionId: () => sessionManager.getActiveSessionId(),
|
|
60244
60936
|
loadTrace: (sessionId) => {
|
|
60245
|
-
const tracePath =
|
|
60246
|
-
if (!
|
|
60937
|
+
const tracePath = path22.join(sessionsDir, `${sessionId}.trace.json`);
|
|
60938
|
+
if (!fs22.existsSync(tracePath)) return null;
|
|
60247
60939
|
try {
|
|
60248
|
-
return JSON.parse(
|
|
60940
|
+
return JSON.parse(fs22.readFileSync(tracePath, "utf8"));
|
|
60249
60941
|
} catch {
|
|
60250
60942
|
return null;
|
|
60251
60943
|
}
|
|
60252
60944
|
},
|
|
60253
60945
|
saveTrace: (trace) => {
|
|
60254
|
-
const tracePath =
|
|
60946
|
+
const tracePath = path22.join(sessionsDir, `${trace.sessionId}.trace.json`);
|
|
60255
60947
|
saveTraceFileBestEffort(tracePath, JSON.stringify(trace, null, 2));
|
|
60256
60948
|
}
|
|
60257
60949
|
});
|
|
@@ -60758,7 +61450,7 @@ function normalizeSessionTitle(raw) {
|
|
|
60758
61450
|
}
|
|
60759
61451
|
|
|
60760
61452
|
// src/components/extension-selector.ts
|
|
60761
|
-
import * as
|
|
61453
|
+
import * as path23 from "node:path";
|
|
60762
61454
|
var ExtensionSelectorComponent = class extends Container {
|
|
60763
61455
|
selectList;
|
|
60764
61456
|
constructor(title, options, onSelect, onCancel) {
|
|
@@ -60828,8 +61520,8 @@ var ExtensionStateSubmenu = class extends Container {
|
|
|
60828
61520
|
}
|
|
60829
61521
|
};
|
|
60830
61522
|
function unidentifiedLabel(info) {
|
|
60831
|
-
const parentName =
|
|
60832
|
-
const fileName =
|
|
61523
|
+
const parentName = path23.basename(path23.dirname(info.entryPath));
|
|
61524
|
+
const fileName = path23.basename(info.entryPath);
|
|
60833
61525
|
return `(unidentified) ${parentName || fileName}`;
|
|
60834
61526
|
}
|
|
60835
61527
|
var ExtensionEnablementSelectorComponent = class extends Container {
|
|
@@ -61119,7 +61811,7 @@ async function handleCacheTest(host) {
|
|
|
61119
61811
|
host.chatContainer.addChild(new Text(theme.fg("dim", ` ${summarizeUsage(result1.usage)}`), 1, 0));
|
|
61120
61812
|
host.chatContainer.addChild(new Text(theme.fg("dim", " Waiting 2s before replaying identical request..."), 1, 0));
|
|
61121
61813
|
host.ui.requestRender();
|
|
61122
|
-
await new Promise((
|
|
61814
|
+
await new Promise((resolve7) => setTimeout(resolve7, 2e3));
|
|
61123
61815
|
host.chatContainer.addChild(new Text(theme.fg("accent", "Request 2/2: replaying identical request..."), 1, 0));
|
|
61124
61816
|
host.ui.requestRender();
|
|
61125
61817
|
result2 = await completeSimple(model, context, options);
|
|
@@ -61300,10 +61992,10 @@ async function handleDebugPackageCommand(host) {
|
|
|
61300
61992
|
}
|
|
61301
61993
|
|
|
61302
61994
|
// src/commands/interactive-session-commands.ts
|
|
61303
|
-
import * as
|
|
61995
|
+
import * as os6 from "os";
|
|
61304
61996
|
|
|
61305
61997
|
// src/components/session-selector.ts
|
|
61306
|
-
import * as
|
|
61998
|
+
import * as path24 from "node:path";
|
|
61307
61999
|
function formatDate(timestamp) {
|
|
61308
62000
|
const date = new Date(timestamp);
|
|
61309
62001
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -61334,7 +62026,7 @@ function getPathFlavor(value, peer) {
|
|
|
61334
62026
|
return "posix";
|
|
61335
62027
|
}
|
|
61336
62028
|
function getPathApi(flavor) {
|
|
61337
|
-
return flavor === "windows" ?
|
|
62029
|
+
return flavor === "windows" ? path24.win32 : path24.posix;
|
|
61338
62030
|
}
|
|
61339
62031
|
function normalizeForComparison(value, flavor) {
|
|
61340
62032
|
const pathApi = getPathApi(flavor);
|
|
@@ -61354,10 +62046,10 @@ function formatSessionCwdTag(sessionCwd, currentCwd, homeDir) {
|
|
|
61354
62046
|
const normalizedSessionCwd = pathApi.normalize(sessionCwd);
|
|
61355
62047
|
if (homeDir && getPathFlavor(homeDir, sessionCwd) === sessionFlavor) {
|
|
61356
62048
|
const normalizedHome = pathApi.normalize(homeDir);
|
|
61357
|
-
const
|
|
61358
|
-
const outsideHome =
|
|
62049
|
+
const relative3 = pathApi.relative(normalizedHome, normalizedSessionCwd);
|
|
62050
|
+
const outsideHome = relative3 === ".." || relative3.startsWith(`..${pathApi.sep}`) || pathApi.isAbsolute(relative3);
|
|
61359
62051
|
if (!outsideHome) {
|
|
61360
|
-
return
|
|
62052
|
+
return relative3 ? `~${pathApi.sep}${relative3}` : "~";
|
|
61361
62053
|
}
|
|
61362
62054
|
}
|
|
61363
62055
|
return normalizedSessionCwd;
|
|
@@ -62007,7 +62699,7 @@ var AssistantMessageComponent = class extends Container {
|
|
|
62007
62699
|
};
|
|
62008
62700
|
|
|
62009
62701
|
// src/components/tool-execution.ts
|
|
62010
|
-
import * as
|
|
62702
|
+
import * as os5 from "node:os";
|
|
62011
62703
|
|
|
62012
62704
|
// ../../node_modules/diff/libesm/diff/base.js
|
|
62013
62705
|
var Diff = class {
|
|
@@ -62109,16 +62801,16 @@ var Diff = class {
|
|
|
62109
62801
|
}
|
|
62110
62802
|
}
|
|
62111
62803
|
}
|
|
62112
|
-
addToPath(
|
|
62113
|
-
const last =
|
|
62804
|
+
addToPath(path33, added, removed, oldPosInc, options) {
|
|
62805
|
+
const last = path33.lastComponent;
|
|
62114
62806
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
62115
62807
|
return {
|
|
62116
|
-
oldPos:
|
|
62808
|
+
oldPos: path33.oldPos + oldPosInc,
|
|
62117
62809
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
62118
62810
|
};
|
|
62119
62811
|
} else {
|
|
62120
62812
|
return {
|
|
62121
|
-
oldPos:
|
|
62813
|
+
oldPos: path33.oldPos + oldPosInc,
|
|
62122
62814
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
62123
62815
|
};
|
|
62124
62816
|
}
|
|
@@ -62566,13 +63258,13 @@ function formatSize2(bytes) {
|
|
|
62566
63258
|
}
|
|
62567
63259
|
var DEFAULT_MAX_BYTES = 102400;
|
|
62568
63260
|
var DEFAULT_MAX_LINES = 100;
|
|
62569
|
-
function shortenPath(
|
|
62570
|
-
if (typeof
|
|
62571
|
-
const home =
|
|
62572
|
-
if (
|
|
62573
|
-
return `~${
|
|
63261
|
+
function shortenPath(path33) {
|
|
63262
|
+
if (typeof path33 !== "string") return "";
|
|
63263
|
+
const home = os5.homedir();
|
|
63264
|
+
if (path33.startsWith(home)) {
|
|
63265
|
+
return `~${path33.slice(home.length)}`;
|
|
62574
63266
|
}
|
|
62575
|
-
return
|
|
63267
|
+
return path33;
|
|
62576
63268
|
}
|
|
62577
63269
|
function replaceTabs(text) {
|
|
62578
63270
|
return text.replace(/\t/g, " ");
|
|
@@ -62598,11 +63290,13 @@ var ToolExecutionComponent = class extends Container {
|
|
|
62598
63290
|
isPartial = true;
|
|
62599
63291
|
ui;
|
|
62600
63292
|
result;
|
|
63293
|
+
renderHint;
|
|
62601
63294
|
constructor(toolName, args, options = {}, ui) {
|
|
62602
63295
|
super();
|
|
62603
63296
|
this.toolName = toolName;
|
|
62604
63297
|
this.args = args;
|
|
62605
63298
|
this.expanded = options.expanded ?? false;
|
|
63299
|
+
this.renderHint = options.renderHint;
|
|
62606
63300
|
this.ui = ui;
|
|
62607
63301
|
this.addChild(new Spacer(1));
|
|
62608
63302
|
this.contentBox = new Box(1, 1, (text) => theme.bg("toolPendingBg", text));
|
|
@@ -62653,14 +63347,14 @@ ${renderManageTodoListResult(this.result, { expanded: this.expanded }, theme)}`;
|
|
|
62653
63347
|
}
|
|
62654
63348
|
} else if (this.toolName === "read_file") {
|
|
62655
63349
|
const rawPath = str(this.args?.file_path ?? this.args?.path);
|
|
62656
|
-
const
|
|
63350
|
+
const path33 = rawPath !== null ? shortenPath(rawPath) : null;
|
|
62657
63351
|
const offset = typeof this.args?.offset === "number" ? this.args.offset : void 0;
|
|
62658
63352
|
const limit = typeof this.args?.limit === "number" ? this.args.limit : void 0;
|
|
62659
63353
|
let pathDisplay;
|
|
62660
|
-
if (
|
|
63354
|
+
if (path33 === null) {
|
|
62661
63355
|
pathDisplay = invalidArg;
|
|
62662
|
-
} else if (
|
|
62663
|
-
pathDisplay = theme.fg("accent",
|
|
63356
|
+
} else if (path33) {
|
|
63357
|
+
pathDisplay = theme.fg("accent", path33);
|
|
62664
63358
|
} else {
|
|
62665
63359
|
const partialPath = partialStr(this.args?.file_path ?? this.args?.path);
|
|
62666
63360
|
pathDisplay = theme.fg("toolOutput", partialPath);
|
|
@@ -62707,12 +63401,12 @@ ${renderManageTodoListResult(this.result, { expanded: this.expanded }, theme)}`;
|
|
|
62707
63401
|
} else if (this.toolName === "write_file") {
|
|
62708
63402
|
const rawPath = str(this.args?.file_path ?? this.args?.path);
|
|
62709
63403
|
const fileContent = str(this.args?.content);
|
|
62710
|
-
const
|
|
63404
|
+
const path33 = rawPath !== null ? shortenPath(rawPath) : null;
|
|
62711
63405
|
let pathDisplay;
|
|
62712
|
-
if (
|
|
63406
|
+
if (path33 === null) {
|
|
62713
63407
|
pathDisplay = invalidArg;
|
|
62714
|
-
} else if (
|
|
62715
|
-
pathDisplay = theme.fg("accent",
|
|
63408
|
+
} else if (path33) {
|
|
63409
|
+
pathDisplay = theme.fg("accent", path33);
|
|
62716
63410
|
} else {
|
|
62717
63411
|
const partialPath = partialStr(this.args?.file_path ?? this.args?.path);
|
|
62718
63412
|
pathDisplay = theme.fg("toolOutput", partialPath);
|
|
@@ -62749,12 +63443,12 @@ ${theme.fg("error", errorText)}`;
|
|
|
62749
63443
|
}
|
|
62750
63444
|
} else if (this.toolName === "edit_file") {
|
|
62751
63445
|
const rawPath = str(this.args?.file_path ?? this.args?.path);
|
|
62752
|
-
const
|
|
63446
|
+
const path33 = rawPath !== null ? shortenPath(rawPath) : null;
|
|
62753
63447
|
let pathDisplay;
|
|
62754
|
-
if (
|
|
63448
|
+
if (path33 === null) {
|
|
62755
63449
|
pathDisplay = invalidArg;
|
|
62756
|
-
} else if (
|
|
62757
|
-
pathDisplay = theme.fg("accent",
|
|
63450
|
+
} else if (path33) {
|
|
63451
|
+
pathDisplay = theme.fg("accent", path33);
|
|
62758
63452
|
} else {
|
|
62759
63453
|
const partialPath = partialStr(this.args?.file_path ?? this.args?.path);
|
|
62760
63454
|
pathDisplay = theme.fg("toolOutput", partialPath);
|
|
@@ -62779,7 +63473,7 @@ ${theme.fg("error", errorText)}`;
|
|
|
62779
63473
|
const diff = this.result.details.diff;
|
|
62780
63474
|
const firstChangedLine = this.result.details.firstChangedLine;
|
|
62781
63475
|
if (firstChangedLine) {
|
|
62782
|
-
text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent",
|
|
63476
|
+
text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent", path33 || rawPath)}${theme.fg("warning", `:${firstChangedLine}`)}`;
|
|
62783
63477
|
}
|
|
62784
63478
|
const lines = diff.split("\n");
|
|
62785
63479
|
const maxLines = this.expanded ? lines.length : 15;
|
|
@@ -62799,7 +63493,7 @@ ${theme.fg("error", errorText)}`;
|
|
|
62799
63493
|
const diff = generateEditDiff(oldText, newText, rawPath);
|
|
62800
63494
|
const firstChangedLine = findFirstChangedLine(oldText, newText);
|
|
62801
63495
|
if (firstChangedLine) {
|
|
62802
|
-
text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent",
|
|
63496
|
+
text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent", path33 || rawPath)}${theme.fg("warning", `:${firstChangedLine}`)}`;
|
|
62803
63497
|
}
|
|
62804
63498
|
const lines = diff.split("\n");
|
|
62805
63499
|
const maxLines = this.expanded ? lines.length : 15;
|
|
@@ -62818,9 +63512,9 @@ ${theme.fg("error", errorText)}`;
|
|
|
62818
63512
|
}
|
|
62819
63513
|
} else if (this.toolName === "list_dir") {
|
|
62820
63514
|
const rawPath = str(this.args?.path);
|
|
62821
|
-
const
|
|
63515
|
+
const path33 = rawPath !== null ? shortenPath(rawPath || ".") : null;
|
|
62822
63516
|
const limit = this.args?.limit;
|
|
62823
|
-
text = `${theme.fg("toolTitle", theme.bold("list_dir"))} ${
|
|
63517
|
+
text = `${theme.fg("toolTitle", theme.bold("list_dir"))} ${path33 === null ? invalidArg : theme.fg("accent", path33)}`;
|
|
62824
63518
|
if (limit !== void 0) {
|
|
62825
63519
|
text += theme.fg("toolOutput", ` (limit ${limit})`);
|
|
62826
63520
|
}
|
|
@@ -62856,9 +63550,9 @@ ${theme.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
|
|
|
62856
63550
|
} else if (this.toolName === "find_files") {
|
|
62857
63551
|
const pattern = str(this.args?.pattern);
|
|
62858
63552
|
const rawPath = str(this.args?.path);
|
|
62859
|
-
const
|
|
63553
|
+
const path33 = rawPath !== null ? shortenPath(rawPath || ".") : null;
|
|
62860
63554
|
const limit = this.args?.limit;
|
|
62861
|
-
text = theme.fg("toolTitle", theme.bold("find_files")) + " " + (pattern === null ? invalidArg : theme.fg("accent", pattern || "")) + theme.fg("toolOutput", ` in ${
|
|
63555
|
+
text = theme.fg("toolTitle", theme.bold("find_files")) + " " + (pattern === null ? invalidArg : theme.fg("accent", pattern || "")) + theme.fg("toolOutput", ` in ${path33 === null ? invalidArg : path33}`);
|
|
62862
63556
|
if (limit !== void 0) {
|
|
62863
63557
|
text += theme.fg("toolOutput", ` (limit ${limit})`);
|
|
62864
63558
|
}
|
|
@@ -62894,10 +63588,10 @@ ${theme.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
|
|
|
62894
63588
|
} else if (this.toolName === "grep_text") {
|
|
62895
63589
|
const pattern = str(this.args?.pattern);
|
|
62896
63590
|
const rawPath = str(this.args?.path);
|
|
62897
|
-
const
|
|
63591
|
+
const path33 = rawPath !== null ? shortenPath(rawPath || ".") : null;
|
|
62898
63592
|
const glob = str(this.args?.glob);
|
|
62899
63593
|
const limit = this.args?.limit;
|
|
62900
|
-
text = theme.fg("toolTitle", theme.bold("grep_text")) + " " + (pattern === null ? invalidArg : theme.fg("accent", `/${pattern || ""}/`)) + theme.fg("toolOutput", ` in ${
|
|
63594
|
+
text = theme.fg("toolTitle", theme.bold("grep_text")) + " " + (pattern === null ? invalidArg : theme.fg("accent", `/${pattern || ""}/`)) + theme.fg("toolOutput", ` in ${path33 === null ? invalidArg : path33}`);
|
|
62901
63595
|
if (glob) {
|
|
62902
63596
|
text += theme.fg("toolOutput", ` (${glob})`);
|
|
62903
63597
|
}
|
|
@@ -62977,33 +63671,97 @@ ${theme.fg("warning", `[${warnings.join(". ")}]`)}`;
|
|
|
62977
63671
|
}
|
|
62978
63672
|
}
|
|
62979
63673
|
} else {
|
|
62980
|
-
|
|
62981
|
-
if (
|
|
62982
|
-
|
|
62983
|
-
|
|
62984
|
-
|
|
62985
|
-
${theme.fg("toolOutput", content)}`;
|
|
63674
|
+
const hinted = this.formatWithRenderHint();
|
|
63675
|
+
if (hinted !== null) {
|
|
63676
|
+
text = hinted;
|
|
63677
|
+
} else {
|
|
63678
|
+
text = this.formatGenericTool();
|
|
62986
63679
|
}
|
|
62987
|
-
|
|
62988
|
-
|
|
62989
|
-
|
|
62990
|
-
|
|
62991
|
-
|
|
62992
|
-
|
|
62993
|
-
|
|
62994
|
-
|
|
62995
|
-
|
|
62996
|
-
|
|
63680
|
+
}
|
|
63681
|
+
return text;
|
|
63682
|
+
}
|
|
63683
|
+
/** Render via the extension renderHint; null means fall back. */
|
|
63684
|
+
formatWithRenderHint() {
|
|
63685
|
+
const hint = this.renderHint;
|
|
63686
|
+
if (!hint) return null;
|
|
63687
|
+
try {
|
|
63688
|
+
let text = theme.fg("toolTitle", theme.bold(this.toolName));
|
|
63689
|
+
let produced = false;
|
|
63690
|
+
if (hint.summary) {
|
|
63691
|
+
const summary = hint.summary(this.args);
|
|
63692
|
+
if (typeof summary === "string" && summary.trim()) {
|
|
63693
|
+
text += ` ${theme.fg("accent", summary.trim())}`;
|
|
63694
|
+
produced = true;
|
|
63695
|
+
}
|
|
63696
|
+
}
|
|
63697
|
+
if (this.result && hint.sections) {
|
|
63698
|
+
const sections = hint.sections(
|
|
63699
|
+
this.result,
|
|
63700
|
+
{ expanded: this.expanded }
|
|
63701
|
+
);
|
|
63702
|
+
if (Array.isArray(sections)) {
|
|
63703
|
+
for (const section of sections) {
|
|
63704
|
+
if (!section || typeof section.text !== "string" || !section.text) continue;
|
|
63705
|
+
produced = true;
|
|
63706
|
+
if (section.title) {
|
|
63707
|
+
text += `
|
|
63708
|
+
|
|
63709
|
+
${theme.fg("toolTitle", section.title)}`;
|
|
63710
|
+
}
|
|
63711
|
+
const lines = section.text.split("\n");
|
|
63712
|
+
const maxLines = this.expanded ? lines.length : 20;
|
|
63713
|
+
const displayLines = lines.slice(0, maxLines);
|
|
63714
|
+
const remaining = lines.length - maxLines;
|
|
63715
|
+
text += "\n" + displayLines.map((line) => theme.fg("toolOutput", line)).join("\n");
|
|
63716
|
+
if (remaining > 0) {
|
|
63717
|
+
text += theme.fg("muted", `
|
|
62997
63718
|
... (${remaining} more lines, press Ctrl+O to expand)`);
|
|
63719
|
+
}
|
|
62998
63720
|
}
|
|
62999
63721
|
}
|
|
63000
|
-
|
|
63001
|
-
|
|
63002
|
-
|
|
63722
|
+
}
|
|
63723
|
+
if (!produced) return null;
|
|
63724
|
+
if (this.result?.isError) {
|
|
63725
|
+
const errorOutput = this.getTextOutput() || "Unknown error";
|
|
63726
|
+
text += `
|
|
63003
63727
|
|
|
63004
63728
|
${theme.fg("error", "Error: " + errorOutput)}`;
|
|
63729
|
+
}
|
|
63730
|
+
return text;
|
|
63731
|
+
} catch (error) {
|
|
63732
|
+
if (process.env.PIE_VERBOSE) {
|
|
63733
|
+
console.warn(`[ToolExecution] renderHint for ${this.toolName} failed, falling back:`, error);
|
|
63734
|
+
}
|
|
63735
|
+
return null;
|
|
63736
|
+
}
|
|
63737
|
+
}
|
|
63738
|
+
formatGenericTool() {
|
|
63739
|
+
let text = theme.fg("toolTitle", theme.bold(this.toolName));
|
|
63740
|
+
if (this.args && Object.keys(this.args).length > 0) {
|
|
63741
|
+
const content = JSON.stringify(this.args, null, 2);
|
|
63742
|
+
text += `
|
|
63743
|
+
|
|
63744
|
+
${theme.fg("toolOutput", content)}`;
|
|
63745
|
+
}
|
|
63746
|
+
if (this.result) {
|
|
63747
|
+
const output = this.getTextOutput();
|
|
63748
|
+
if (output) {
|
|
63749
|
+
const lines = output.split("\n");
|
|
63750
|
+
const maxLines = this.expanded ? lines.length : 20;
|
|
63751
|
+
const displayLines = lines.slice(0, maxLines);
|
|
63752
|
+
const remaining = lines.length - maxLines;
|
|
63753
|
+
text += "\n\n" + displayLines.map((line) => theme.fg("toolOutput", line)).join("\n");
|
|
63754
|
+
if (remaining > 0) {
|
|
63755
|
+
text += theme.fg("muted", `
|
|
63756
|
+
... (${remaining} more lines, press Ctrl+O to expand)`);
|
|
63005
63757
|
}
|
|
63006
63758
|
}
|
|
63759
|
+
if (this.result.isError) {
|
|
63760
|
+
const errorOutput = this.getTextOutput() || "Unknown error";
|
|
63761
|
+
text += `
|
|
63762
|
+
|
|
63763
|
+
${theme.fg("error", "Error: " + errorOutput)}`;
|
|
63764
|
+
}
|
|
63007
63765
|
}
|
|
63008
63766
|
return text;
|
|
63009
63767
|
}
|
|
@@ -63048,7 +63806,7 @@ async function handleResumeCommand(host) {
|
|
|
63048
63806
|
}
|
|
63049
63807
|
}, {
|
|
63050
63808
|
currentCwd: host.options.cwd,
|
|
63051
|
-
homeDir:
|
|
63809
|
+
homeDir: os6.homedir(),
|
|
63052
63810
|
refreshMetadata: (sessionId) => host.sessionManager.refreshDerivedName(sessionId),
|
|
63053
63811
|
requestRender: () => host.ui.requestRender(),
|
|
63054
63812
|
totalCount
|
|
@@ -63057,6 +63815,15 @@ async function handleResumeCommand(host) {
|
|
|
63057
63815
|
});
|
|
63058
63816
|
}
|
|
63059
63817
|
async function loadSession(host, sessionId) {
|
|
63818
|
+
const beforeSwitch = await host.extensionRunner?.emitSessionBeforeSwitch({
|
|
63819
|
+
type: "session:before_switch",
|
|
63820
|
+
reason: "resume",
|
|
63821
|
+
targetSessionId: sessionId
|
|
63822
|
+
});
|
|
63823
|
+
if (beforeSwitch?.cancel) {
|
|
63824
|
+
host.showStatus("Session switch cancelled by an extension");
|
|
63825
|
+
return;
|
|
63826
|
+
}
|
|
63060
63827
|
try {
|
|
63061
63828
|
const success = await host.sessionManager.loadSession(sessionId);
|
|
63062
63829
|
if (!success) {
|
|
@@ -63351,8 +64118,8 @@ async function forkAtEntry(host, entryId) {
|
|
|
63351
64118
|
host.showError("Failed to branch at entry");
|
|
63352
64119
|
return;
|
|
63353
64120
|
}
|
|
63354
|
-
const
|
|
63355
|
-
const pathNames =
|
|
64121
|
+
const path33 = host.sessionManager.getPathToEntry(entryId);
|
|
64122
|
+
const pathNames = path33.map((e) => e.message?.role || "entry").join(" \u2192 ");
|
|
63356
64123
|
const messages = host.sessionManager.getMessages();
|
|
63357
64124
|
host.syncAgentFromActiveSession(messages);
|
|
63358
64125
|
await host.syncSessionScopedState(messages);
|
|
@@ -63365,7 +64132,7 @@ async function forkAtEntry(host, entryId) {
|
|
|
63365
64132
|
host.updatePendingMessagesDisplay();
|
|
63366
64133
|
host.renderMessageHistory(messages);
|
|
63367
64134
|
await host.sessionManager.save();
|
|
63368
|
-
host.showStatus(`Branched at: ${pathNames} (${
|
|
64135
|
+
host.showStatus(`Branched at: ${pathNames} (${path33.length} messages). Continue to add to this branch.`);
|
|
63369
64136
|
} catch (error) {
|
|
63370
64137
|
host.showError(
|
|
63371
64138
|
`Failed to branch: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -63393,10 +64160,10 @@ async function navigateToEntry(host, entryId) {
|
|
|
63393
64160
|
host.sessionManager.save().catch((err) => {
|
|
63394
64161
|
console.error("[Session] Save after navigation failed:", err);
|
|
63395
64162
|
});
|
|
63396
|
-
const
|
|
64163
|
+
const path33 = host.sessionManager.getPathToEntry(entryId);
|
|
63397
64164
|
const entry = host.sessionManager.getEntry(entryId);
|
|
63398
64165
|
const role = entry?.message?.role || "entry";
|
|
63399
|
-
host.showStatus(`Switched to branch: ${role} (${
|
|
64166
|
+
host.showStatus(`Switched to branch: ${role} (${path33.length} messages in path)`);
|
|
63400
64167
|
} catch (error) {
|
|
63401
64168
|
host.showError(
|
|
63402
64169
|
`Failed to navigate: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -63446,9 +64213,9 @@ async function handleForkCommand(host) {
|
|
|
63446
64213
|
}
|
|
63447
64214
|
|
|
63448
64215
|
// src/commands/interactive-skill-commands.ts
|
|
63449
|
-
import * as
|
|
63450
|
-
import * as
|
|
63451
|
-
import * as
|
|
64216
|
+
import * as fs23 from "fs";
|
|
64217
|
+
import * as os7 from "os";
|
|
64218
|
+
import * as path25 from "path";
|
|
63452
64219
|
|
|
63453
64220
|
// src/commands/subagent-command.ts
|
|
63454
64221
|
async function handleSubagentCommand(host, args) {
|
|
@@ -63633,7 +64400,7 @@ function expandSkillCommand(host, text) {
|
|
|
63633
64400
|
const skill = host.skills.find((s) => s.name === skillName);
|
|
63634
64401
|
if (!skill) return text;
|
|
63635
64402
|
try {
|
|
63636
|
-
const content =
|
|
64403
|
+
const content = fs23.readFileSync(skill.filePath, "utf-8");
|
|
63637
64404
|
const body = host.stripFrontmatter(content).trim();
|
|
63638
64405
|
const skillBlock = `<skill name="${skill.name}" location="${skill.filePath}">
|
|
63639
64406
|
References are relative to ${skill.baseDir}.
|
|
@@ -63699,17 +64466,17 @@ async function handleSkillsCreate(host, args) {
|
|
|
63699
64466
|
if (!description) {
|
|
63700
64467
|
description = `Skill for ${name}`;
|
|
63701
64468
|
}
|
|
63702
|
-
const skillsDir =
|
|
63703
|
-
const skillDir =
|
|
63704
|
-
const skillFile =
|
|
64469
|
+
const skillsDir = path25.join(os7.homedir(), ".pie", "skills");
|
|
64470
|
+
const skillDir = path25.join(skillsDir, name);
|
|
64471
|
+
const skillFile = path25.join(skillDir, "SKILL.md");
|
|
63705
64472
|
console.error(`[SkillsCreate] Creating at: ${skillFile}`);
|
|
63706
|
-
if (
|
|
64473
|
+
if (fs23.existsSync(skillDir)) {
|
|
63707
64474
|
host.showError(`Skill "${name}" already exists at ${skillDir}`);
|
|
63708
64475
|
return;
|
|
63709
64476
|
}
|
|
63710
|
-
|
|
64477
|
+
fs23.mkdirSync(skillDir, { recursive: true });
|
|
63711
64478
|
const template = createSkillTemplate(name, description);
|
|
63712
|
-
|
|
64479
|
+
fs23.writeFileSync(skillFile, template, "utf-8");
|
|
63713
64480
|
console.error(`[SkillsCreate] Successfully created skill`);
|
|
63714
64481
|
host.chatContainer.addChild(new Spacer(1));
|
|
63715
64482
|
host.chatContainer.addChild(new Text(theme.fg("accent", `\u2713 Created skill: ${name}`), 1, 0));
|
|
@@ -63745,10 +64512,10 @@ async function handleSkillsReload(host) {
|
|
|
63745
64512
|
host.chatContainer.addChild(new Text(theme.fg("accent", "Reloading skills..."), 1, 0));
|
|
63746
64513
|
host.ui.requestRender();
|
|
63747
64514
|
try {
|
|
63748
|
-
const builtinDir =
|
|
63749
|
-
const userDir =
|
|
63750
|
-
const projectDir =
|
|
63751
|
-
const result = loadSkills({ builtinDir, userDir, projectDir });
|
|
64515
|
+
const builtinDir = path25.join(getBuiltinDir(), "skills");
|
|
64516
|
+
const userDir = path25.join(os7.homedir(), ".pie", "skills");
|
|
64517
|
+
const projectDir = path25.join(process.cwd(), ".pie", "skills");
|
|
64518
|
+
const result = loadSkills({ dirs: buildSkillDirs({ builtinDir, userDir, projectDir, cwd: process.cwd() }) });
|
|
63752
64519
|
host.skills = result.skills;
|
|
63753
64520
|
host.skillsSection = formatSkillsForPrompt(host.skills);
|
|
63754
64521
|
host.applyRuntimeToolMode(host.allTools.length > 0 ? host.allTools : host.agent.state.tools);
|
|
@@ -63763,8 +64530,8 @@ async function handleSkillsReload(host) {
|
|
|
63763
64530
|
}
|
|
63764
64531
|
}
|
|
63765
64532
|
const builtinCount = host.skills.filter((s) => s.source === "builtin").length;
|
|
63766
|
-
const userCount = host.skills.filter((s) => s.source === "user").length;
|
|
63767
|
-
const projectCount = host.skills.filter((s) => s.source === "project").length;
|
|
64533
|
+
const userCount = host.skills.filter((s) => s.source === "user" || s.source === "user-agents").length;
|
|
64534
|
+
const projectCount = host.skills.filter((s) => s.source === "project" || s.source === "project-agents").length;
|
|
63768
64535
|
host.chatContainer.addChild(new Text(theme.fg("accent", `\u2713 Reloaded ${host.skills.length} skill(s)`), 1, 0));
|
|
63769
64536
|
host.chatContainer.addChild(new Text(theme.fg("dim", ` Builtin: ${builtinCount}, User: ${userCount}, Project: ${projectCount}`), 1, 0));
|
|
63770
64537
|
if (result.diagnostics.length > 0) {
|
|
@@ -64135,6 +64902,14 @@ function showThinkingLevelSelector(host) {
|
|
|
64135
64902
|
});
|
|
64136
64903
|
}
|
|
64137
64904
|
async function handleClearCommand(host) {
|
|
64905
|
+
const beforeSwitch = await host.extensionRunner?.emitSessionBeforeSwitch({
|
|
64906
|
+
type: "session:before_switch",
|
|
64907
|
+
reason: "new"
|
|
64908
|
+
});
|
|
64909
|
+
if (beforeSwitch?.cancel) {
|
|
64910
|
+
host.showStatus("Session switch cancelled by an extension");
|
|
64911
|
+
return;
|
|
64912
|
+
}
|
|
64138
64913
|
host.setControllerBusy(false);
|
|
64139
64914
|
host.setWaitingForUser(false);
|
|
64140
64915
|
host.executionState.clear();
|
|
@@ -64433,7 +65208,21 @@ async function handleCompactCommand(host) {
|
|
|
64433
65208
|
apiKey: host.options.apiKey,
|
|
64434
65209
|
systemPrompt: host.agent.state.systemPrompt
|
|
64435
65210
|
};
|
|
64436
|
-
|
|
65211
|
+
let summary;
|
|
65212
|
+
const beforeCompact = await host.extensionRunner?.emitSessionBeforeCompact({
|
|
65213
|
+
type: "session:before_compact",
|
|
65214
|
+
reason: "manual",
|
|
65215
|
+
messageCount: existingMessages.length
|
|
65216
|
+
});
|
|
65217
|
+
if (beforeCompact?.cancel) {
|
|
65218
|
+
host.showStatus("Compaction cancelled by an extension");
|
|
65219
|
+
return;
|
|
65220
|
+
}
|
|
65221
|
+
if (beforeCompact?.summary) {
|
|
65222
|
+
summary = beforeCompact.summary;
|
|
65223
|
+
} else {
|
|
65224
|
+
summary = await createCompactionSummary(existingMessages, compactOptions);
|
|
65225
|
+
}
|
|
64437
65226
|
const tokensBefore = calculateTotalTokens(existingMessages);
|
|
64438
65227
|
host.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore);
|
|
64439
65228
|
const compactedMessages = host.sessionManager.getMessages();
|
|
@@ -64496,6 +65285,31 @@ function formatFooterLifecycleEvent(event) {
|
|
|
64496
65285
|
}
|
|
64497
65286
|
}
|
|
64498
65287
|
|
|
65288
|
+
// src/runtime/terminal-bell.ts
|
|
65289
|
+
var BEL = "\x07";
|
|
65290
|
+
var DEFAULT_MIN_INTERVAL_MS = 500;
|
|
65291
|
+
var lastRingAtMs = 0;
|
|
65292
|
+
function ringTerminalBell(options = {}) {
|
|
65293
|
+
const {
|
|
65294
|
+
enabled = true,
|
|
65295
|
+
stdout = process.stdout,
|
|
65296
|
+
now = Date.now,
|
|
65297
|
+
minIntervalMs = DEFAULT_MIN_INTERVAL_MS
|
|
65298
|
+
} = options;
|
|
65299
|
+
if (!enabled) return false;
|
|
65300
|
+
if (!stdout.isTTY) return false;
|
|
65301
|
+
const atMs = now();
|
|
65302
|
+
if (atMs - lastRingAtMs < minIntervalMs) return false;
|
|
65303
|
+
lastRingAtMs = atMs;
|
|
65304
|
+
stdout.write(BEL);
|
|
65305
|
+
return true;
|
|
65306
|
+
}
|
|
65307
|
+
function ringTurnSettledBell(host) {
|
|
65308
|
+
if ((host.agentSessionController?.pendingMessageCount ?? 0) > 0) return;
|
|
65309
|
+
if (host.executionState.read().awaitingContinuation) return;
|
|
65310
|
+
host.ringAttentionBell?.();
|
|
65311
|
+
}
|
|
65312
|
+
|
|
64499
65313
|
// src/runtime/interactive-runtime-events.ts
|
|
64500
65314
|
function bindInteractiveRuntimeEvents(host) {
|
|
64501
65315
|
host.agent.subscribe((event) => {
|
|
@@ -64666,6 +65480,7 @@ function handleSemanticAgentEvent(host, event) {
|
|
|
64666
65480
|
host.appendWarningSummary(outcome.terminalSummary);
|
|
64667
65481
|
}
|
|
64668
65482
|
host.sessionTrace.completeTurn(event.message, false);
|
|
65483
|
+
ringTurnSettledBell(host);
|
|
64669
65484
|
host._semanticTurnIndex++;
|
|
64670
65485
|
break;
|
|
64671
65486
|
}
|
|
@@ -64700,6 +65515,7 @@ function handleSemanticAgentEvent(host, event) {
|
|
|
64700
65515
|
host.appendWarningSummary(outcome.terminalSummary);
|
|
64701
65516
|
}
|
|
64702
65517
|
host.sessionTrace.completeTurn(event.message, true);
|
|
65518
|
+
host.ringAttentionBell?.();
|
|
64703
65519
|
host._semanticTurnIndex++;
|
|
64704
65520
|
break;
|
|
64705
65521
|
}
|
|
@@ -64748,6 +65564,7 @@ function handleMessageStart(host, event) {
|
|
|
64748
65564
|
host.safeRequestRender();
|
|
64749
65565
|
}
|
|
64750
65566
|
function handleMessageUpdate(host, event) {
|
|
65567
|
+
host.noteContinuationActivity?.();
|
|
64751
65568
|
if (!host.streamingComponent || event.message?.role !== "assistant") return;
|
|
64752
65569
|
host.sessionTrace.updateAssistantMessage(event.message);
|
|
64753
65570
|
if (host.isComposing) {
|
|
@@ -64784,7 +65601,7 @@ function handleMessageUpdate(host, event) {
|
|
|
64784
65601
|
const toolComponent = new ToolExecutionComponent(
|
|
64785
65602
|
toolCall.name,
|
|
64786
65603
|
toolCall.arguments,
|
|
64787
|
-
{ expanded: host.toolOutputExpanded },
|
|
65604
|
+
{ expanded: host.toolOutputExpanded, renderHint: findToolRenderHint(host, toolCall.name) },
|
|
64788
65605
|
host.ui
|
|
64789
65606
|
);
|
|
64790
65607
|
host.pendingTools.set(toolId, toolComponent);
|
|
@@ -64820,6 +65637,15 @@ function handleMessageUpdate(host, event) {
|
|
|
64820
65637
|
});
|
|
64821
65638
|
host.safeRequestRender();
|
|
64822
65639
|
}
|
|
65640
|
+
function findToolRenderHint(host, toolName) {
|
|
65641
|
+
const tools = host.agent?.state?.tools ?? [];
|
|
65642
|
+
for (const tool of tools) {
|
|
65643
|
+
if (tool.name !== toolName) continue;
|
|
65644
|
+
const hint = tool.renderHint;
|
|
65645
|
+
if (hint) return hint;
|
|
65646
|
+
}
|
|
65647
|
+
return void 0;
|
|
65648
|
+
}
|
|
64823
65649
|
function handleToolStart(host, event) {
|
|
64824
65650
|
host.logDebug("tool:start", { toolName: event.toolName, toolCallId: event.toolCallId });
|
|
64825
65651
|
host.sessionTrace.startTool(event.toolCallId, event.toolName, event.args);
|
|
@@ -64831,7 +65657,7 @@ function handleToolStart(host, event) {
|
|
|
64831
65657
|
const newToolComponent = new ToolExecutionComponent(
|
|
64832
65658
|
event.toolName,
|
|
64833
65659
|
event.args,
|
|
64834
|
-
{ expanded: host.toolOutputExpanded },
|
|
65660
|
+
{ expanded: host.toolOutputExpanded, renderHint: findToolRenderHint(host, event.toolName) },
|
|
64835
65661
|
host.ui
|
|
64836
65662
|
);
|
|
64837
65663
|
host.pendingTools.set(event.toolCallId, newToolComponent);
|
|
@@ -64848,6 +65674,7 @@ function handleToolStart(host, event) {
|
|
|
64848
65674
|
host.safeRequestRender();
|
|
64849
65675
|
}
|
|
64850
65676
|
function handleToolUpdate(host, event) {
|
|
65677
|
+
host.noteContinuationActivity?.();
|
|
64851
65678
|
if (event.toolCallId) {
|
|
64852
65679
|
const toolComponent = host.pendingTools.get(event.toolCallId);
|
|
64853
65680
|
if (toolComponent) {
|
|
@@ -64924,6 +65751,20 @@ function setupInteractiveEditorSubmitHandler(host) {
|
|
|
64924
65751
|
host.editor.onSubmit = async (text) => {
|
|
64925
65752
|
text = text.trim();
|
|
64926
65753
|
if (!text) return;
|
|
65754
|
+
if (host.extensionRunner) {
|
|
65755
|
+
const decision = await host.extensionRunner.emitTerminalInput({ type: "terminal:input", text });
|
|
65756
|
+
if (decision.action === "consume") {
|
|
65757
|
+
host.editor.setText("");
|
|
65758
|
+
return;
|
|
65759
|
+
}
|
|
65760
|
+
if (decision.action === "transform") {
|
|
65761
|
+
text = decision.text.trim();
|
|
65762
|
+
if (!text) {
|
|
65763
|
+
host.editor.setText("");
|
|
65764
|
+
return;
|
|
65765
|
+
}
|
|
65766
|
+
}
|
|
65767
|
+
}
|
|
64927
65768
|
if (text.startsWith("/skills/skill:")) {
|
|
64928
65769
|
const skillText = text.slice("/skills/".length);
|
|
64929
65770
|
const expanded = host.expandSkillCommand(skillText);
|
|
@@ -65186,7 +66027,7 @@ function setupInteractiveEditorSubmitHandler(host) {
|
|
|
65186
66027
|
host.chatContainer.addChild(userMsg);
|
|
65187
66028
|
host.editor.setText("");
|
|
65188
66029
|
host.ui.requestRender();
|
|
65189
|
-
await new Promise((
|
|
66030
|
+
await new Promise((resolve7) => setImmediate(resolve7));
|
|
65190
66031
|
let finalContent = messageContent;
|
|
65191
66032
|
const reminderPrefix = host.executionReminder;
|
|
65192
66033
|
const combinedPrefix = [reminderPrefix].filter((value) => Boolean(value)).join("");
|
|
@@ -65222,8 +66063,8 @@ function setupInteractiveEditorSubmitHandler(host) {
|
|
|
65222
66063
|
}
|
|
65223
66064
|
|
|
65224
66065
|
// src/input/interactive-file-pipeline.ts
|
|
65225
|
-
import * as
|
|
65226
|
-
import * as
|
|
66066
|
+
import * as fs26 from "fs";
|
|
66067
|
+
import * as path28 from "path";
|
|
65227
66068
|
|
|
65228
66069
|
// src/components/file-picker.ts
|
|
65229
66070
|
var FilePickerComponent = class extends Container {
|
|
@@ -65444,8 +66285,8 @@ var FilePickerComponent = class extends Container {
|
|
|
65444
66285
|
};
|
|
65445
66286
|
|
|
65446
66287
|
// src/files/commands/file-commands.ts
|
|
65447
|
-
import * as
|
|
65448
|
-
import * as
|
|
66288
|
+
import * as fs24 from "node:fs";
|
|
66289
|
+
import * as path26 from "node:path";
|
|
65449
66290
|
var FileCommands = class {
|
|
65450
66291
|
context;
|
|
65451
66292
|
constructor(context) {
|
|
@@ -65461,11 +66302,11 @@ var FileCommands = class {
|
|
|
65461
66302
|
return;
|
|
65462
66303
|
}
|
|
65463
66304
|
const filePath = resolvePath2(parsed.path);
|
|
65464
|
-
if (!
|
|
66305
|
+
if (!fs24.existsSync(filePath)) {
|
|
65465
66306
|
this.context.showError(`File not found: ${parsed.path}`);
|
|
65466
66307
|
return;
|
|
65467
66308
|
}
|
|
65468
|
-
this.context.showStatus(`Uploading ${
|
|
66309
|
+
this.context.showStatus(`Uploading ${path26.basename(filePath)}...`);
|
|
65469
66310
|
try {
|
|
65470
66311
|
const result = await this.context.fileManager.upload(filePath, {
|
|
65471
66312
|
purpose: parsed.purpose,
|
|
@@ -65500,7 +66341,7 @@ var FileCommands = class {
|
|
|
65500
66341
|
return;
|
|
65501
66342
|
}
|
|
65502
66343
|
const resolvedPath = resolvePath2(filePath);
|
|
65503
|
-
if (!
|
|
66344
|
+
if (!fs24.existsSync(resolvedPath)) {
|
|
65504
66345
|
this.context.showError(`File not found: ${filePath}`);
|
|
65505
66346
|
return;
|
|
65506
66347
|
}
|
|
@@ -65531,7 +66372,7 @@ var FileCommands = class {
|
|
|
65531
66372
|
return;
|
|
65532
66373
|
}
|
|
65533
66374
|
const resolvedPath = resolvePath2(parsed.path);
|
|
65534
|
-
if (!
|
|
66375
|
+
if (!fs24.existsSync(resolvedPath)) {
|
|
65535
66376
|
this.context.showError(`File not found: ${parsed.path}`);
|
|
65536
66377
|
return;
|
|
65537
66378
|
}
|
|
@@ -66009,8 +66850,8 @@ var FileStatusMonitor = class {
|
|
|
66009
66850
|
};
|
|
66010
66851
|
|
|
66011
66852
|
// src/files/mention/mention-handler.ts
|
|
66012
|
-
import * as
|
|
66013
|
-
import * as
|
|
66853
|
+
import * as fs25 from "node:fs";
|
|
66854
|
+
import * as path27 from "node:path";
|
|
66014
66855
|
var MentionHandler = class {
|
|
66015
66856
|
fileManager;
|
|
66016
66857
|
onShowPicker;
|
|
@@ -66065,7 +66906,7 @@ var MentionHandler = class {
|
|
|
66065
66906
|
navigateBrowseParent() {
|
|
66066
66907
|
const currentDir = this.getBrowserDirectory();
|
|
66067
66908
|
if (!currentDir) return;
|
|
66068
|
-
const parentDir =
|
|
66909
|
+
const parentDir = path27.dirname(currentDir);
|
|
66069
66910
|
if (parentDir === currentDir) return;
|
|
66070
66911
|
this.browsingDirectory = parentDir;
|
|
66071
66912
|
this.showMentionPicker("");
|
|
@@ -66085,7 +66926,7 @@ var MentionHandler = class {
|
|
|
66085
66926
|
if (option.type === "parent") {
|
|
66086
66927
|
const currentDir = this.getBrowserDirectory();
|
|
66087
66928
|
if (currentDir) {
|
|
66088
|
-
this.browsingDirectory =
|
|
66929
|
+
this.browsingDirectory = path27.dirname(currentDir);
|
|
66089
66930
|
this.showMentionPicker("");
|
|
66090
66931
|
this.isPickerVisible = true;
|
|
66091
66932
|
}
|
|
@@ -66221,7 +67062,7 @@ var MentionHandler = class {
|
|
|
66221
67062
|
id: part.content,
|
|
66222
67063
|
name: part.name || fileInfo.name,
|
|
66223
67064
|
mimeType: fileInfo.mimeType,
|
|
66224
|
-
ext:
|
|
67065
|
+
ext: path27.extname(part.name || fileInfo.name).toLowerCase(),
|
|
66225
67066
|
size: fileInfo.size,
|
|
66226
67067
|
source: fileInfo.platforms.length > 0 ? "session" : "local",
|
|
66227
67068
|
fileId: part.content,
|
|
@@ -66379,11 +67220,11 @@ var MentionHandler = class {
|
|
|
66379
67220
|
}
|
|
66380
67221
|
if (this.isPath(query)) {
|
|
66381
67222
|
const resolvedPath = resolvePath2(query);
|
|
66382
|
-
if (
|
|
66383
|
-
const stats =
|
|
67223
|
+
if (fs25.existsSync(resolvedPath)) {
|
|
67224
|
+
const stats = fs25.statSync(resolvedPath);
|
|
66384
67225
|
if (stats.isFile()) {
|
|
66385
67226
|
const type = FileCache.getFileTypeFromName(resolvedPath);
|
|
66386
|
-
const name =
|
|
67227
|
+
const name = path27.basename(resolvedPath);
|
|
66387
67228
|
if (!seenNames.has(name.toLowerCase())) {
|
|
66388
67229
|
options.push({
|
|
66389
67230
|
type: "upload",
|
|
@@ -66404,16 +67245,16 @@ var MentionHandler = class {
|
|
|
66404
67245
|
return void 0;
|
|
66405
67246
|
}
|
|
66406
67247
|
const queryPath = this.isPath(query) ? resolvePath2(query) : void 0;
|
|
66407
|
-
const filter = queryPath ?
|
|
67248
|
+
const filter = queryPath ? fs25.existsSync(queryPath) && fs25.statSync(queryPath).isDirectory() ? "" : path27.basename(queryPath) : query;
|
|
66408
67249
|
const entries = this.fileManager.listPathEntries(currentDir, filter);
|
|
66409
67250
|
const options = [];
|
|
66410
67251
|
const homeDir = process.env.HOME || "";
|
|
66411
67252
|
const displayDir = currentDir.startsWith(homeDir) ? `~${currentDir.slice(homeDir.length)}` : currentDir;
|
|
66412
|
-
if (
|
|
67253
|
+
if (path27.dirname(currentDir) !== currentDir) {
|
|
66413
67254
|
options.push({
|
|
66414
67255
|
type: "parent",
|
|
66415
67256
|
name: "..",
|
|
66416
|
-
path:
|
|
67257
|
+
path: path27.dirname(currentDir),
|
|
66417
67258
|
icon: "\u21A9",
|
|
66418
67259
|
meta: "Parent directory"
|
|
66419
67260
|
});
|
|
@@ -66445,10 +67286,10 @@ var MentionHandler = class {
|
|
|
66445
67286
|
getBrowserDirectory(query = this.currentQuery) {
|
|
66446
67287
|
if (this.isPath(query)) {
|
|
66447
67288
|
const resolvedPath = resolvePath2(query);
|
|
66448
|
-
if (
|
|
67289
|
+
if (fs25.existsSync(resolvedPath) && fs25.statSync(resolvedPath).isDirectory()) {
|
|
66449
67290
|
return resolvedPath;
|
|
66450
67291
|
}
|
|
66451
|
-
return
|
|
67292
|
+
return path27.dirname(resolvedPath);
|
|
66452
67293
|
}
|
|
66453
67294
|
return this.browsingDirectory;
|
|
66454
67295
|
}
|
|
@@ -66535,8 +67376,8 @@ async function initializeFileManager(host) {
|
|
|
66535
67376
|
sessionId,
|
|
66536
67377
|
platform: platform2,
|
|
66537
67378
|
apiKey: host.options.apiKey,
|
|
66538
|
-
baseDir:
|
|
66539
|
-
sessionsDir:
|
|
67379
|
+
baseDir: path28.join(host.options.configDir, "files"),
|
|
67380
|
+
sessionsDir: path28.join(host.options.configDir, "sessions")
|
|
66540
67381
|
});
|
|
66541
67382
|
switch (getFileManagerAdapterKind(host.options.model?.filePlatform)) {
|
|
66542
67383
|
case "kimi":
|
|
@@ -66809,13 +67650,13 @@ function convertPreparedAttachmentItems(items) {
|
|
|
66809
67650
|
break;
|
|
66810
67651
|
case "image": {
|
|
66811
67652
|
if (!item.data && !item.path) return void 0;
|
|
66812
|
-
const data = item.data ??
|
|
67653
|
+
const data = item.data ?? fs26.readFileSync(item.path, "base64");
|
|
66813
67654
|
converted.push({ type: "image", data, mimeType: item.mimeType });
|
|
66814
67655
|
break;
|
|
66815
67656
|
}
|
|
66816
67657
|
case "video": {
|
|
66817
67658
|
if (!item.data && !item.path) return void 0;
|
|
66818
|
-
const data = item.data ??
|
|
67659
|
+
const data = item.data ?? fs26.readFileSync(item.path, "base64");
|
|
66819
67660
|
converted.push({ type: "video", data, mimeType: item.mimeType });
|
|
66820
67661
|
break;
|
|
66821
67662
|
}
|
|
@@ -67036,6 +67877,55 @@ function isCommandLikeInput(text) {
|
|
|
67036
67877
|
return text.startsWith("/") || text.startsWith("!!");
|
|
67037
67878
|
}
|
|
67038
67879
|
|
|
67880
|
+
// src/components/extension-widgets.ts
|
|
67881
|
+
var ExtensionWidgetsComponent = class extends Container {
|
|
67882
|
+
slots = /* @__PURE__ */ new Map();
|
|
67883
|
+
setWidget(key, lines) {
|
|
67884
|
+
const normalized = (lines ?? []).map((line) => String(line ?? "")).filter((line) => line.trim().length > 0);
|
|
67885
|
+
if (normalized.length === 0) {
|
|
67886
|
+
this.slots.delete(key);
|
|
67887
|
+
} else {
|
|
67888
|
+
this.slots.set(key, normalized.slice(0, 3));
|
|
67889
|
+
}
|
|
67890
|
+
this.rebuild();
|
|
67891
|
+
}
|
|
67892
|
+
clearAll() {
|
|
67893
|
+
if (this.slots.size === 0) return;
|
|
67894
|
+
this.slots.clear();
|
|
67895
|
+
this.rebuild();
|
|
67896
|
+
}
|
|
67897
|
+
rebuild() {
|
|
67898
|
+
this.clear();
|
|
67899
|
+
for (const lines of this.slots.values()) {
|
|
67900
|
+
for (const line of lines) {
|
|
67901
|
+
this.addChild(new Text(theme.fg("dim", `\xB7 ${line}`), 1, 0));
|
|
67902
|
+
}
|
|
67903
|
+
}
|
|
67904
|
+
}
|
|
67905
|
+
};
|
|
67906
|
+
var ExtensionStatusSlots = class {
|
|
67907
|
+
slots = /* @__PURE__ */ new Map();
|
|
67908
|
+
set(key, text) {
|
|
67909
|
+
const normalized = String(text ?? "").trim();
|
|
67910
|
+
if (!normalized) {
|
|
67911
|
+
if (!this.slots.delete(key)) return false;
|
|
67912
|
+
return true;
|
|
67913
|
+
}
|
|
67914
|
+
if (this.slots.get(key) === normalized) return false;
|
|
67915
|
+
this.slots.set(key, normalized);
|
|
67916
|
+
return true;
|
|
67917
|
+
}
|
|
67918
|
+
clear() {
|
|
67919
|
+
this.slots.clear();
|
|
67920
|
+
}
|
|
67921
|
+
/** Render-ready suffix for the footer line, e.g. " · git:clean · ci:ok". */
|
|
67922
|
+
format(maxWidth = 60) {
|
|
67923
|
+
if (this.slots.size === 0) return "";
|
|
67924
|
+
const joined = [...this.slots.values()].join(" \xB7 ");
|
|
67925
|
+
return ` \xB7 ${truncateToWidth(joined, maxWidth, "")}`;
|
|
67926
|
+
}
|
|
67927
|
+
};
|
|
67928
|
+
|
|
67039
67929
|
// src/components/footer.ts
|
|
67040
67930
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
67041
67931
|
var SPINNER_INTERVAL = 80;
|
|
@@ -67056,6 +67946,8 @@ var FooterComponent = class {
|
|
|
67056
67946
|
spinnerFrame = 0;
|
|
67057
67947
|
spinnerTimer = null;
|
|
67058
67948
|
onRequestRender;
|
|
67949
|
+
/** Keyed ambient status slots for extensions (ctx.ui.setStatus). */
|
|
67950
|
+
extensionStatuses = new ExtensionStatusSlots();
|
|
67059
67951
|
/** Set callback to request re-render when animation updates (pass true to force) */
|
|
67060
67952
|
setOnRequestRender(callback) {
|
|
67061
67953
|
this.onRequestRender = () => callback(true);
|
|
@@ -67168,6 +68060,7 @@ var FooterComponent = class {
|
|
|
67168
68060
|
const statusWithSpinner = spinner ? `${spinner} ${statusText}` : statusText;
|
|
67169
68061
|
statsParts.push(theme.fg(statusColor[state.status], statusWithSpinner));
|
|
67170
68062
|
let statsLeft = statsParts.join(" ");
|
|
68063
|
+
statsLeft += this.extensionStatuses.format();
|
|
67171
68064
|
const modelName = state.modelName || "no-model";
|
|
67172
68065
|
let rightSide = modelName;
|
|
67173
68066
|
if (state.thinkingLevel && state.thinkingLevel !== "off") {
|
|
@@ -67223,9 +68116,11 @@ var TodoWidgetComponent = class extends Container {
|
|
|
67223
68116
|
|
|
67224
68117
|
// src/agent-guidelines.ts
|
|
67225
68118
|
function buildCodingAgentGuidelinesSection(tools = []) {
|
|
67226
|
-
|
|
68119
|
+
const hasTodoTool = tools.some((tool) => tool.name === "manage_todo_list");
|
|
67227
68120
|
const guidelines = [
|
|
67228
68121
|
"Handle coding tasks by analyzing, planning, or making changes as the available tools and user request allow; do not stop at analysis when execution is expected.",
|
|
68122
|
+
`Keep going until the user's task is completely resolved before ending your turn. If you announce a next step (for example, "now run the tests"), execute it in the same turn instead of describing it; only end your turn when the task is done or you genuinely need user input.`,
|
|
68123
|
+
...hasTodoTool ? ["For multi-step tasks, set up progress tracking with manage_todo_list before starting, and keep exactly one step in progress until every step is complete."] : [],
|
|
67229
68124
|
"Work in the current workspace, preserve user changes, and keep edits focused.",
|
|
67230
68125
|
"Inspect the relevant code before changing it. Use file tools for workspace writes; do not use shell redirection or heredocs to bypass write_file/edit_file guards.",
|
|
67231
68126
|
"Run the most relevant existing test, build, or check after file changes when practical.",
|
|
@@ -67503,6 +68398,9 @@ function setupUI(host) {
|
|
|
67503
68398
|
host.todoWidgetContainer = new Container();
|
|
67504
68399
|
host.todoWidget = new TodoWidgetComponent(host.executionState);
|
|
67505
68400
|
host.todoWidgetContainer.addChild(host.todoWidget);
|
|
68401
|
+
host.extensionWidgetsContainer = new Container();
|
|
68402
|
+
host.extensionWidgets = new ExtensionWidgetsComponent();
|
|
68403
|
+
host.extensionWidgetsContainer.addChild(host.extensionWidgets);
|
|
67506
68404
|
const editorTheme = getEditorTheme();
|
|
67507
68405
|
host.editor = new Editor(host.ui, editorTheme, { paddingX: 1 });
|
|
67508
68406
|
host.editor.onChange = () => {
|
|
@@ -67517,6 +68415,7 @@ function setupUI(host) {
|
|
|
67517
68415
|
host.ui.addChild(host.chatContainer);
|
|
67518
68416
|
host.ui.addChild(host.pendingMessagesContainer);
|
|
67519
68417
|
host.ui.addChild(host.todoWidgetContainer);
|
|
68418
|
+
host.ui.addChild(host.extensionWidgetsContainer);
|
|
67520
68419
|
host.ui.addChild(new Spacer());
|
|
67521
68420
|
host.ui.addChild(host.footer);
|
|
67522
68421
|
host.ui.addChild(host.editorContainer);
|
|
@@ -67846,11 +68745,11 @@ var HierarchicalSelectorComponent = class extends Container {
|
|
|
67846
68745
|
// src/runtime/interactive-ui-helpers.ts
|
|
67847
68746
|
function showHierarchicalMenu(host, initialPath = []) {
|
|
67848
68747
|
const basePath = [...initialPath];
|
|
67849
|
-
const showAtPath = (
|
|
68748
|
+
const showAtPath = (path33) => {
|
|
67850
68749
|
host.showSelector((done) => {
|
|
67851
68750
|
const selector = new HierarchicalSelectorComponent({
|
|
67852
68751
|
tree: commandTree,
|
|
67853
|
-
path:
|
|
68752
|
+
path: path33,
|
|
67854
68753
|
basePath,
|
|
67855
68754
|
onNavigate: (newPath) => {
|
|
67856
68755
|
done();
|
|
@@ -67858,7 +68757,7 @@ function showHierarchicalMenu(host, initialPath = []) {
|
|
|
67858
68757
|
},
|
|
67859
68758
|
onSelect: async (selectedPath, node, searchArgs) => {
|
|
67860
68759
|
if (node.handler) {
|
|
67861
|
-
const args = searchArgs || (selectedPath.length >
|
|
68760
|
+
const args = searchArgs || (selectedPath.length > path33.length ? selectedPath.slice(path33.length).join(" ") : void 0);
|
|
67862
68761
|
const commandPath = "/" + selectedPath.join("/");
|
|
67863
68762
|
if (!args && host.isInteractiveCommand(commandPath)) {
|
|
67864
68763
|
done();
|
|
@@ -67952,10 +68851,17 @@ function getContinuationTimeoutMs() {
|
|
|
67952
68851
|
if (Number.isFinite(raw) && raw > 0) return raw;
|
|
67953
68852
|
return 2e4;
|
|
67954
68853
|
}
|
|
68854
|
+
var STALL_RECHECK_MS = 1e3;
|
|
68855
|
+
function getHardStallTimeoutMs() {
|
|
68856
|
+
const raw = Number(process.env.PIE_INTERACTIVE_HARD_STALL_TIMEOUT_MS || "");
|
|
68857
|
+
if (Number.isFinite(raw) && raw > 0) return raw;
|
|
68858
|
+
return 30 * 6e4;
|
|
68859
|
+
}
|
|
67955
68860
|
function clearContinuationTimeout(host, reason) {
|
|
67956
68861
|
if (!host.continuationTimeoutHandle) return;
|
|
67957
68862
|
clearTimeout(host.continuationTimeoutHandle);
|
|
67958
68863
|
host.continuationTimeoutHandle = void 0;
|
|
68864
|
+
host.continuationStallSinceMs = void 0;
|
|
67959
68865
|
host.logDebug("continuation_timeout:cleared", {
|
|
67960
68866
|
reason,
|
|
67961
68867
|
awaitingContinuation: host.executionState.read().awaitingContinuation
|
|
@@ -67988,6 +68894,36 @@ function appendWarningSummary(host, message) {
|
|
|
67988
68894
|
host.chatContainer.addChild(new Spacer(1));
|
|
67989
68895
|
host.safeRequestRender();
|
|
67990
68896
|
}
|
|
68897
|
+
async function recoverHardStalledTurn(host, stalledMs) {
|
|
68898
|
+
host.continuationStallSinceMs = void 0;
|
|
68899
|
+
host.logDebug("continuation_timeout:hard_stall_recovery", { stalledMs });
|
|
68900
|
+
host.agentSessionController?.abort();
|
|
68901
|
+
try {
|
|
68902
|
+
await Promise.race([
|
|
68903
|
+
host.agentSessionController?.waitForIdle() ?? Promise.resolve(),
|
|
68904
|
+
new Promise((resolve7) => setTimeout(resolve7, 2e3))
|
|
68905
|
+
]);
|
|
68906
|
+
} catch (error) {
|
|
68907
|
+
host.logDebug("continuation_timeout:hard_stall_wait_failed", {
|
|
68908
|
+
error: error instanceof Error ? error.message : String(error)
|
|
68909
|
+
});
|
|
68910
|
+
}
|
|
68911
|
+
host.agent.resetProcessingState();
|
|
68912
|
+
host.isProcessing = false;
|
|
68913
|
+
host.setSubmitLock(false);
|
|
68914
|
+
host.streamingComponent = void 0;
|
|
68915
|
+
host.pendingTools.clear();
|
|
68916
|
+
const abortOutcome = host.executionState.abort();
|
|
68917
|
+
host.persistExecutionState();
|
|
68918
|
+
void host.refreshTodoWidget();
|
|
68919
|
+
host.footer.setState({ status: "ready" });
|
|
68920
|
+
host.safeRequestRender();
|
|
68921
|
+
host.ringAttentionBell?.();
|
|
68922
|
+
appendWarningSummary(host, "Recovered from a stalled turn (no progress for " + Math.round(stalledMs / 1e3) + "s). The previous turn was interrupted; review its partial output before continuing.");
|
|
68923
|
+
if (abortOutcome.terminalSummary) {
|
|
68924
|
+
appendWarningSummary(host, abortOutcome.terminalSummary);
|
|
68925
|
+
}
|
|
68926
|
+
}
|
|
67991
68927
|
function scheduleContinuationTimeout(host) {
|
|
67992
68928
|
host.clearContinuationTimeout("reschedule");
|
|
67993
68929
|
const timeoutMs = getContinuationTimeoutMs();
|
|
@@ -67996,23 +68932,38 @@ function scheduleContinuationTimeout(host) {
|
|
|
67996
68932
|
currentStepId: host.executionState.read().currentStepId,
|
|
67997
68933
|
queueLength: host.agentSessionController?.pendingMessageCount ?? 0
|
|
67998
68934
|
});
|
|
67999
|
-
|
|
68935
|
+
const check = () => {
|
|
68000
68936
|
host.continuationTimeoutHandle = void 0;
|
|
68001
68937
|
const state = host.executionState.read();
|
|
68002
68938
|
if (!state.awaitingContinuation || isWaitingForUserInteraction(host)) {
|
|
68939
|
+
host.continuationStallSinceMs = void 0;
|
|
68003
68940
|
host.logDebug("continuation_timeout:skip", {
|
|
68004
68941
|
reason: !state.awaitingContinuation ? "no_longer_awaiting" : "waiting_for_user_interaction"
|
|
68005
68942
|
});
|
|
68006
68943
|
return;
|
|
68007
68944
|
}
|
|
68008
68945
|
if (host.agent.state.isStreaming || host.isProcessing || host.submitLock || host.pendingTools.size > 0) {
|
|
68009
|
-
|
|
68010
|
-
|
|
68011
|
-
|
|
68012
|
-
|
|
68013
|
-
|
|
68946
|
+
const now = Date.now();
|
|
68947
|
+
const stallSince = host.continuationStallSinceMs ?? now;
|
|
68948
|
+
host.continuationStallSinceMs = stallSince;
|
|
68949
|
+
const stalledMs = now - stallSince;
|
|
68950
|
+
const hardTimeoutMs = getHardStallTimeoutMs();
|
|
68951
|
+
if (stalledMs < hardTimeoutMs) {
|
|
68952
|
+
host.logDebug("continuation_timeout:active_work", {
|
|
68953
|
+
isStreaming: host.agent.state.isStreaming,
|
|
68954
|
+
isProcessing: host.isProcessing,
|
|
68955
|
+
pendingTools: host.pendingTools.size,
|
|
68956
|
+
stalledMs,
|
|
68957
|
+
hardTimeoutMs
|
|
68958
|
+
});
|
|
68959
|
+
const nextCheckMs = Math.max(50, Math.min(STALL_RECHECK_MS, hardTimeoutMs - stalledMs));
|
|
68960
|
+
host.continuationTimeoutHandle = setTimeout(check, nextCheckMs);
|
|
68961
|
+
return;
|
|
68962
|
+
}
|
|
68963
|
+
void recoverHardStalledTurn(host, stalledMs);
|
|
68014
68964
|
return;
|
|
68015
68965
|
}
|
|
68966
|
+
host.continuationStallSinceMs = void 0;
|
|
68016
68967
|
const outcome = host.executionState.markAwaitingContinuationStalled();
|
|
68017
68968
|
host.logDebug("continuation_timeout:expired", {
|
|
68018
68969
|
currentStepId: state.currentStepId,
|
|
@@ -68028,7 +68979,8 @@ function scheduleContinuationTimeout(host) {
|
|
|
68028
68979
|
}
|
|
68029
68980
|
}
|
|
68030
68981
|
host.agentSessionController?.requestQueueDispatch();
|
|
68031
|
-
}
|
|
68982
|
+
};
|
|
68983
|
+
host.continuationTimeoutHandle = setTimeout(check, timeoutMs);
|
|
68032
68984
|
}
|
|
68033
68985
|
|
|
68034
68986
|
// src/runtime/interactive-controller-setup.ts
|
|
@@ -68094,12 +69046,29 @@ function createInteractiveAgentSessionController(host) {
|
|
|
68094
69046
|
baseDelayMs: getCliRetryBaseDelayMs()
|
|
68095
69047
|
},
|
|
68096
69048
|
compaction: {
|
|
68097
|
-
compact: async (context) =>
|
|
68098
|
-
|
|
68099
|
-
|
|
68100
|
-
|
|
68101
|
-
|
|
68102
|
-
|
|
69049
|
+
compact: async (context) => {
|
|
69050
|
+
const beforeCompact = await host.extensionRunner?.emitSessionBeforeCompact({
|
|
69051
|
+
type: "session:before_compact",
|
|
69052
|
+
reason: context.reason === "overflow" ? "overflow" : "threshold",
|
|
69053
|
+
messageCount: context.messages.length
|
|
69054
|
+
});
|
|
69055
|
+
if (beforeCompact?.cancel) {
|
|
69056
|
+
host.showStatus("Auto-compaction cancelled by an extension");
|
|
69057
|
+
return { aborted: true };
|
|
69058
|
+
}
|
|
69059
|
+
if (beforeCompact?.summary) {
|
|
69060
|
+
const activeEntryId = context.sessionManager.getActiveEntryId();
|
|
69061
|
+
const firstKeptEntryId = activeEntryId ? findFirstKeptEntryId(context.sessionManager.getPathToEntry(activeEntryId)) : void 0;
|
|
69062
|
+
if (!firstKeptEntryId) return { aborted: true };
|
|
69063
|
+
return { summary: beforeCompact.summary, firstKeptEntryId };
|
|
69064
|
+
}
|
|
69065
|
+
return createCliAutoCompactionResult({
|
|
69066
|
+
context,
|
|
69067
|
+
model: host.options.model,
|
|
69068
|
+
apiKey: host.options.apiKey,
|
|
69069
|
+
systemPrompt: host.agent.state.systemPrompt
|
|
69070
|
+
});
|
|
69071
|
+
}
|
|
68103
69072
|
},
|
|
68104
69073
|
onEvent: (event) => {
|
|
68105
69074
|
host.sessionTrace.noteRuntimeEvent(event.type, event);
|
|
@@ -68168,6 +69137,7 @@ function createInteractiveAgentSessionController(host) {
|
|
|
68168
69137
|
host.appendWarningSummary(outcome.terminalSummary);
|
|
68169
69138
|
}
|
|
68170
69139
|
host.sessionTrace.completeTurn(event.message, false);
|
|
69140
|
+
ringTurnSettledBell(host);
|
|
68171
69141
|
host._semanticTurnIndex++;
|
|
68172
69142
|
} else if (event.type === "turn_settled") {
|
|
68173
69143
|
host.setControllerBusy(false);
|
|
@@ -68205,6 +69175,7 @@ function createInteractiveAgentSessionController(host) {
|
|
|
68205
69175
|
host.showStatus("Todo list preserved. Send 'continue' when you want to resume it.");
|
|
68206
69176
|
}
|
|
68207
69177
|
host.showError(event.failure.message);
|
|
69178
|
+
host.ringAttentionBell?.();
|
|
68208
69179
|
host.setControllerBusy(false);
|
|
68209
69180
|
} else if (event.type === "turn_cancelled") {
|
|
68210
69181
|
const outcome = host.executionState.abort();
|
|
@@ -68533,7 +69504,7 @@ async function handleDirectBash(host, command) {
|
|
|
68533
69504
|
child.stderr.on("data", (data) => {
|
|
68534
69505
|
output.append(data.toString());
|
|
68535
69506
|
});
|
|
68536
|
-
return new Promise((
|
|
69507
|
+
return new Promise((resolve7) => {
|
|
68537
69508
|
let settled = false;
|
|
68538
69509
|
const finish = (code) => {
|
|
68539
69510
|
if (settled) return;
|
|
@@ -68546,7 +69517,7 @@ async function handleDirectBash(host, command) {
|
|
|
68546
69517
|
}
|
|
68547
69518
|
host.chatContainer.addChild(new Spacer(1));
|
|
68548
69519
|
host.ui.requestRender();
|
|
68549
|
-
|
|
69520
|
+
resolve7();
|
|
68550
69521
|
};
|
|
68551
69522
|
child.on("error", (error) => {
|
|
68552
69523
|
output.append(error.message);
|
|
@@ -68566,7 +69537,15 @@ function createInteractiveExtensionUIContext(host) {
|
|
|
68566
69537
|
confirm: (title, message, opts) => showExtensionConfirm(host, title, message, opts),
|
|
68567
69538
|
input: (title, placeholder, opts) => showExtensionInput(host, title, placeholder, opts),
|
|
68568
69539
|
editor: (title, prefill) => showExtensionEditor(host, title, prefill),
|
|
68569
|
-
custom: (factory, options) => showExtensionCustom(host, factory, options)
|
|
69540
|
+
custom: (factory, options) => showExtensionCustom(host, factory, options),
|
|
69541
|
+
setStatus: (key, text) => {
|
|
69542
|
+
host.footer.extensionStatuses.set(key, text);
|
|
69543
|
+
host.ui.requestRender();
|
|
69544
|
+
},
|
|
69545
|
+
setWidget: (key, lines) => {
|
|
69546
|
+
host.extensionWidgets.setWidget(key, lines);
|
|
69547
|
+
host.ui.requestRender();
|
|
69548
|
+
}
|
|
68570
69549
|
};
|
|
68571
69550
|
}
|
|
68572
69551
|
function installInteractiveInteractionHandler(host) {
|
|
@@ -68575,6 +69554,7 @@ function installInteractiveInteractionHandler(host) {
|
|
|
68575
69554
|
host.activeInteractionCount++;
|
|
68576
69555
|
host.setWaitingForUser(true);
|
|
68577
69556
|
host.footer.setState({ lifecycleEvent: "waiting_for_user_input" });
|
|
69557
|
+
host.ringAttentionBell?.();
|
|
68578
69558
|
host.safeRequestRender();
|
|
68579
69559
|
};
|
|
68580
69560
|
const endWaitingForUser = () => {
|
|
@@ -68585,15 +69565,15 @@ function installInteractiveInteractionHandler(host) {
|
|
|
68585
69565
|
host.footer.setState({ lifecycleEvent: "tool_execution_start" });
|
|
68586
69566
|
host.safeRequestRender();
|
|
68587
69567
|
};
|
|
68588
|
-
const
|
|
69568
|
+
const withTimeout2 = async (promise) => {
|
|
68589
69569
|
if (!("timeoutMs" in request) || !request.timeoutMs || request.timeoutMs <= 0) {
|
|
68590
69570
|
return { value: await promise, timedOut: false };
|
|
68591
69571
|
}
|
|
68592
|
-
return await new Promise((
|
|
68593
|
-
const timer = setTimeout(() =>
|
|
69572
|
+
return await new Promise((resolve7, reject) => {
|
|
69573
|
+
const timer = setTimeout(() => resolve7({ timedOut: true }), request.timeoutMs);
|
|
68594
69574
|
promise.then((value) => {
|
|
68595
69575
|
clearTimeout(timer);
|
|
68596
|
-
|
|
69576
|
+
resolve7({ value, timedOut: false });
|
|
68597
69577
|
}).catch((error) => {
|
|
68598
69578
|
clearTimeout(timer);
|
|
68599
69579
|
reject(error);
|
|
@@ -68603,7 +69583,7 @@ function installInteractiveInteractionHandler(host) {
|
|
|
68603
69583
|
const waitForUser = async (createPromise) => {
|
|
68604
69584
|
beginWaitingForUser();
|
|
68605
69585
|
try {
|
|
68606
|
-
return await
|
|
69586
|
+
return await withTimeout2(createPromise());
|
|
68607
69587
|
} finally {
|
|
68608
69588
|
endWaitingForUser();
|
|
68609
69589
|
}
|
|
@@ -68693,15 +69673,15 @@ function showExtensionNotification(host, message, type = "info") {
|
|
|
68693
69673
|
host.ui.requestRender();
|
|
68694
69674
|
}
|
|
68695
69675
|
function showExtensionSelector2(host, title, options, opts) {
|
|
68696
|
-
return new Promise((
|
|
69676
|
+
return new Promise((resolve7) => {
|
|
68697
69677
|
host.showStatus(`Waiting for selection: ${title}`);
|
|
68698
69678
|
if (opts?.signal?.aborted) {
|
|
68699
|
-
|
|
69679
|
+
resolve7(void 0);
|
|
68700
69680
|
return;
|
|
68701
69681
|
}
|
|
68702
69682
|
const onAbort = () => {
|
|
68703
69683
|
host.restoreEditor();
|
|
68704
|
-
|
|
69684
|
+
resolve7(void 0);
|
|
68705
69685
|
};
|
|
68706
69686
|
opts?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
68707
69687
|
const selector = new ExtensionSelectorComponent(
|
|
@@ -68710,12 +69690,12 @@ function showExtensionSelector2(host, title, options, opts) {
|
|
|
68710
69690
|
(option) => {
|
|
68711
69691
|
opts?.signal?.removeEventListener("abort", onAbort);
|
|
68712
69692
|
host.restoreEditor();
|
|
68713
|
-
|
|
69693
|
+
resolve7(option);
|
|
68714
69694
|
},
|
|
68715
69695
|
() => {
|
|
68716
69696
|
opts?.signal?.removeEventListener("abort", onAbort);
|
|
68717
69697
|
host.restoreEditor();
|
|
68718
|
-
|
|
69698
|
+
resolve7(void 0);
|
|
68719
69699
|
}
|
|
68720
69700
|
);
|
|
68721
69701
|
host.editorContainer.clear();
|
|
@@ -68731,15 +69711,15 @@ ${message}`, ["Yes", "No"], opts);
|
|
|
68731
69711
|
return result === "Yes";
|
|
68732
69712
|
}
|
|
68733
69713
|
function showExtensionInput(host, title, placeholder, opts) {
|
|
68734
|
-
return new Promise((
|
|
69714
|
+
return new Promise((resolve7) => {
|
|
68735
69715
|
host.showStatus(`Waiting for input: ${title}`);
|
|
68736
69716
|
if (opts?.signal?.aborted) {
|
|
68737
|
-
|
|
69717
|
+
resolve7(void 0);
|
|
68738
69718
|
return;
|
|
68739
69719
|
}
|
|
68740
69720
|
const onAbort = () => {
|
|
68741
69721
|
host.restoreEditor();
|
|
68742
|
-
|
|
69722
|
+
resolve7(void 0);
|
|
68743
69723
|
};
|
|
68744
69724
|
opts?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
68745
69725
|
const input = new ExtensionInputComponent(
|
|
@@ -68748,12 +69728,12 @@ function showExtensionInput(host, title, placeholder, opts) {
|
|
|
68748
69728
|
(value) => {
|
|
68749
69729
|
opts?.signal?.removeEventListener("abort", onAbort);
|
|
68750
69730
|
host.restoreEditor();
|
|
68751
|
-
|
|
69731
|
+
resolve7(value);
|
|
68752
69732
|
},
|
|
68753
69733
|
() => {
|
|
68754
69734
|
opts?.signal?.removeEventListener("abort", onAbort);
|
|
68755
69735
|
host.restoreEditor();
|
|
68756
|
-
|
|
69736
|
+
resolve7(void 0);
|
|
68757
69737
|
}
|
|
68758
69738
|
);
|
|
68759
69739
|
host.editorContainer.clear();
|
|
@@ -68764,7 +69744,7 @@ function showExtensionInput(host, title, placeholder, opts) {
|
|
|
68764
69744
|
});
|
|
68765
69745
|
}
|
|
68766
69746
|
function showExtensionEditor(host, title, prefill) {
|
|
68767
|
-
return new Promise((
|
|
69747
|
+
return new Promise((resolve7) => {
|
|
68768
69748
|
host.showStatus(`Waiting for input: ${title}`);
|
|
68769
69749
|
const container = new Container();
|
|
68770
69750
|
container.addChild(new Text(theme.bold(theme.fg("accent", title)), 0, 0));
|
|
@@ -68786,12 +69766,12 @@ function showExtensionEditor(host, title, prefill) {
|
|
|
68786
69766
|
preview: value.slice(0, 120)
|
|
68787
69767
|
});
|
|
68788
69768
|
host.restoreEditor();
|
|
68789
|
-
|
|
69769
|
+
resolve7(value);
|
|
68790
69770
|
};
|
|
68791
69771
|
editor.onEscape = () => {
|
|
68792
69772
|
host.logDebug("extension:editor:cancel", { title });
|
|
68793
69773
|
host.restoreEditor();
|
|
68794
|
-
|
|
69774
|
+
resolve7(void 0);
|
|
68795
69775
|
};
|
|
68796
69776
|
container.addChild(editor);
|
|
68797
69777
|
container.addChild(new Spacer(1));
|
|
@@ -68805,14 +69785,14 @@ function showExtensionEditor(host, title, prefill) {
|
|
|
68805
69785
|
}
|
|
68806
69786
|
function showExtensionCustom(host, factory, options) {
|
|
68807
69787
|
const savedText = host.editor.getText();
|
|
68808
|
-
return new Promise((
|
|
69788
|
+
return new Promise((resolve7, reject) => {
|
|
68809
69789
|
let closed = false;
|
|
68810
69790
|
const close = (result) => {
|
|
68811
69791
|
if (closed) return;
|
|
68812
69792
|
closed = true;
|
|
68813
69793
|
host.restoreEditor();
|
|
68814
69794
|
host.editor.setText(savedText);
|
|
68815
|
-
|
|
69795
|
+
resolve7(result);
|
|
68816
69796
|
};
|
|
68817
69797
|
Promise.resolve(factory(host.ui, theme, close)).then((component) => {
|
|
68818
69798
|
if (closed) return;
|
|
@@ -68833,6 +69813,60 @@ function showExtensionCustom(host, factory, options) {
|
|
|
68833
69813
|
});
|
|
68834
69814
|
}
|
|
68835
69815
|
|
|
69816
|
+
// src/extensions/provider-login.ts
|
|
69817
|
+
var inFlightLogins = /* @__PURE__ */ new Map();
|
|
69818
|
+
async function loginExtensionProvider(options) {
|
|
69819
|
+
const { provider } = options;
|
|
69820
|
+
const existing = inFlightLogins.get(provider);
|
|
69821
|
+
if (existing) return existing;
|
|
69822
|
+
const attempt = runExtensionProviderLogin(options).finally(() => {
|
|
69823
|
+
if (inFlightLogins.get(provider) === attempt) inFlightLogins.delete(provider);
|
|
69824
|
+
});
|
|
69825
|
+
inFlightLogins.set(provider, attempt);
|
|
69826
|
+
return attempt;
|
|
69827
|
+
}
|
|
69828
|
+
async function runExtensionProviderLogin(options) {
|
|
69829
|
+
const { provider, modelRegistry, authStorage, requestInteraction: requestInteraction2 } = options;
|
|
69830
|
+
const oauth = modelRegistry.getExtensionOAuth(provider);
|
|
69831
|
+
if (!oauth) return false;
|
|
69832
|
+
const credentials = await oauth.login({
|
|
69833
|
+
onAuth: ({ url }) => {
|
|
69834
|
+
void requestInteraction2({
|
|
69835
|
+
type: "notify",
|
|
69836
|
+
message: `${oauth.name}: open this URL to sign in:
|
|
69837
|
+
${url}`,
|
|
69838
|
+
level: "info"
|
|
69839
|
+
});
|
|
69840
|
+
},
|
|
69841
|
+
onPrompt: async ({ message, placeholder }) => {
|
|
69842
|
+
const response = await requestInteraction2({
|
|
69843
|
+
type: "text_input",
|
|
69844
|
+
id: `oauth:${provider}`,
|
|
69845
|
+
prompt: `${oauth.name}: ${message}`,
|
|
69846
|
+
placeholder
|
|
69847
|
+
});
|
|
69848
|
+
if (response.type !== "text_input" || response.timedOut || response.skipped || response.value === void 0) {
|
|
69849
|
+
throw new Error(`${oauth.name} login cancelled.`);
|
|
69850
|
+
}
|
|
69851
|
+
return response.value;
|
|
69852
|
+
}
|
|
69853
|
+
});
|
|
69854
|
+
authStorage.setOAuthCredentials(provider, credentials);
|
|
69855
|
+
authStorage.setRuntimeApiKey(provider, credentials.access);
|
|
69856
|
+
const errors = authStorage.drainErrors();
|
|
69857
|
+
if (errors.length > 0) {
|
|
69858
|
+
throw new Error(`Failed to persist ${oauth.name} credentials: ${errors[0].message}`);
|
|
69859
|
+
}
|
|
69860
|
+
return true;
|
|
69861
|
+
}
|
|
69862
|
+
async function restoreExtensionProviderCredentials(modelRegistry) {
|
|
69863
|
+
for (const result of await modelRegistry.restorePersistedOAuth()) {
|
|
69864
|
+
if (process.env.PIE_VERBOSE) {
|
|
69865
|
+
console.error(`[Extension] OAuth restore ${result.provider}: ${result.action}${result.detail ? ` (${result.detail})` : ""}`);
|
|
69866
|
+
}
|
|
69867
|
+
}
|
|
69868
|
+
}
|
|
69869
|
+
|
|
68836
69870
|
// src/attachments/resolver.ts
|
|
68837
69871
|
var AttachmentResolver = class {
|
|
68838
69872
|
constructor(extensions) {
|
|
@@ -68996,6 +70030,26 @@ async function loadInteractiveExtensions(host) {
|
|
|
68996
70030
|
activeSession.metadata[key] = value;
|
|
68997
70031
|
activeSession.isDirty = true;
|
|
68998
70032
|
},
|
|
70033
|
+
appendEntry: (customType, data) => host.sessionManager.appendCustomEntry(customType, data).id,
|
|
70034
|
+
setLabel: (entryId, label) => host.sessionManager.setLabel(entryId, label),
|
|
70035
|
+
setSessionName: (name) => host.sessionManager.setSessionName(name),
|
|
70036
|
+
getSessionName: () => host.sessionManager.getSessionName(),
|
|
70037
|
+
registerProvider: (name, config) => {
|
|
70038
|
+
const unregister = host.options.modelRegistry.registerProvider(name, config);
|
|
70039
|
+
host.noteRuntimeModeChanged("extension_register_provider");
|
|
70040
|
+
return unregister;
|
|
70041
|
+
},
|
|
70042
|
+
loginProvider: async (name) => {
|
|
70043
|
+
const loggedIn = await loginExtensionProvider({
|
|
70044
|
+
provider: name,
|
|
70045
|
+
modelRegistry: host.options.modelRegistry,
|
|
70046
|
+
authStorage: host.options.modelRegistry.getAuthStorage(),
|
|
70047
|
+
requestInteraction
|
|
70048
|
+
});
|
|
70049
|
+
if (loggedIn) host.noteRuntimeModeChanged("extension_login_provider");
|
|
70050
|
+
return loggedIn;
|
|
70051
|
+
},
|
|
70052
|
+
reload: () => host.reloadRuntime(),
|
|
68999
70053
|
get yoloMode() {
|
|
69000
70054
|
return host.yoloMode;
|
|
69001
70055
|
}
|
|
@@ -69023,9 +70077,10 @@ async function loadInteractiveExtensions(host) {
|
|
|
69023
70077
|
true
|
|
69024
70078
|
);
|
|
69025
70079
|
host.extensionRunner.setUIContext(host.extensionUIContext);
|
|
70080
|
+
await restoreExtensionProviderCredentials(host.options.modelRegistry);
|
|
69026
70081
|
if (process.env.PIE_VERBOSE) {
|
|
69027
|
-
for (const { path:
|
|
69028
|
-
console.error(`[Extension] Failed to load ${
|
|
70082
|
+
for (const { path: path33, error } of errors) {
|
|
70083
|
+
console.error(`[Extension] Failed to load ${path33}: ${error}`);
|
|
69029
70084
|
}
|
|
69030
70085
|
}
|
|
69031
70086
|
const extensionTools = convertExtensionTools(extensions);
|
|
@@ -69079,6 +70134,8 @@ var InteractiveMode = class {
|
|
|
69079
70134
|
editorContainer;
|
|
69080
70135
|
todoWidgetContainer;
|
|
69081
70136
|
todoWidget;
|
|
70137
|
+
extensionWidgetsContainer;
|
|
70138
|
+
extensionWidgets;
|
|
69082
70139
|
executionState = new ExecutionStateManager();
|
|
69083
70140
|
sessionTrace;
|
|
69084
70141
|
keybindings;
|
|
@@ -69143,10 +70200,24 @@ var InteractiveMode = class {
|
|
|
69143
70200
|
lastStatusText;
|
|
69144
70201
|
lastSigintTime = 0;
|
|
69145
70202
|
continuationTimeoutHandle;
|
|
70203
|
+
continuationStallSinceMs;
|
|
69146
70204
|
activeInteractionCount = 0;
|
|
69147
70205
|
logDebug(message, data) {
|
|
69148
70206
|
fileLogger.log("interactive", message, data);
|
|
69149
70207
|
}
|
|
70208
|
+
/** Streams and tool updates prove the turn is alive; restart the no-progress clock. */
|
|
70209
|
+
noteContinuationActivity() {
|
|
70210
|
+
this.continuationStallSinceMs = void 0;
|
|
70211
|
+
}
|
|
70212
|
+
/**
|
|
70213
|
+
* Ring the terminal bell (BEL) when a turn needs the user's attention:
|
|
70214
|
+
* interaction prompts, turn completion/failure, and stall recovery. The
|
|
70215
|
+
* bell itself enforces a cross-call-site cooldown; the settings gate here
|
|
70216
|
+
* is the single opt-out point (settings.json `notifications.bell`).
|
|
70217
|
+
*/
|
|
70218
|
+
ringAttentionBell() {
|
|
70219
|
+
ringTerminalBell({ enabled: this.options.settingsManager.getBellNotificationsEnabled() });
|
|
70220
|
+
}
|
|
69150
70221
|
getContinuationTimeoutMs() {
|
|
69151
70222
|
return getContinuationTimeoutMs();
|
|
69152
70223
|
}
|
|
@@ -69389,7 +70460,7 @@ var InteractiveMode = class {
|
|
|
69389
70460
|
if (savedLevel) {
|
|
69390
70461
|
this.thinkingLevel = savedLevel;
|
|
69391
70462
|
}
|
|
69392
|
-
const { Agent } = await import("./chunks/src-
|
|
70463
|
+
const { Agent } = await import("./chunks/src-TQNFXZGK.js");
|
|
69393
70464
|
const activeSession = this.sessionManager.getActiveSession();
|
|
69394
70465
|
this.agent = new Agent({
|
|
69395
70466
|
initialState: {
|
|
@@ -69480,6 +70551,40 @@ var InteractiveMode = class {
|
|
|
69480
70551
|
installInteractiveInteractionHandler(this);
|
|
69481
70552
|
await loadInteractiveExtensions(this.extensionLoaderHost);
|
|
69482
70553
|
}
|
|
70554
|
+
/**
|
|
70555
|
+
* Full runtime reload (extension API `ctx.reload()`): re-discover skills
|
|
70556
|
+
* and extensions from disk and rebuild the tool surface and system prompt.
|
|
70557
|
+
* Rejects while a turn is processing. Listener lifecycle contract: the old
|
|
70558
|
+
* extension instances are dropped entirely (handlers, tools, commands),
|
|
70559
|
+
* the tool surface is reset to the pristine composition baseline, and the
|
|
70560
|
+
* fresh ExtensionRunner re-wraps from that baseline — no stale handlers
|
|
70561
|
+
* and no double-wrapped tools survive a reload.
|
|
70562
|
+
*/
|
|
70563
|
+
async reloadRuntime() {
|
|
70564
|
+
if (this.isProcessing) {
|
|
70565
|
+
throw new Error("Cannot reload while a response is being processed. Wait for the turn to finish or abort it first.");
|
|
70566
|
+
}
|
|
70567
|
+
const builtinDir = path29.join(getBuiltinDir(), "skills");
|
|
70568
|
+
const userDir = path29.join(os8.homedir(), ".pie", "skills");
|
|
70569
|
+
const projectDir = path29.join(this.options.cwd, ".pie", "skills");
|
|
70570
|
+
const { skills, diagnostics } = loadSkills({
|
|
70571
|
+
dirs: buildSkillDirs({ builtinDir, userDir, projectDir, cwd: this.options.cwd })
|
|
70572
|
+
});
|
|
70573
|
+
this.skills = skills;
|
|
70574
|
+
this.skillsSection = formatSkillsForPrompt(skills);
|
|
70575
|
+
for (const diag of diagnostics.filter((entry) => entry.type === "collision")) {
|
|
70576
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", `[reload] ${diag.message}`), 1, 0));
|
|
70577
|
+
}
|
|
70578
|
+
this.allTools = [...this.options.allTools];
|
|
70579
|
+
this.originalTools = [...this.options.allTools];
|
|
70580
|
+
this.agent.state.tools = [...this.options.allTools];
|
|
70581
|
+
this.extensionRunner?.revokeRegistrations();
|
|
70582
|
+
this.extensionWidgets?.clearAll();
|
|
70583
|
+
await this.loadExtensions();
|
|
70584
|
+
this.applyRuntimeToolMode();
|
|
70585
|
+
this.noteRuntimeModeChanged("extension_reload");
|
|
70586
|
+
this.ui.requestRender();
|
|
70587
|
+
}
|
|
69483
70588
|
calculateContextUsage() {
|
|
69484
70589
|
return calculateContextUsage(this.contextUiHost);
|
|
69485
70590
|
}
|
|
@@ -69728,8 +70833,8 @@ var InteractiveMode = class {
|
|
|
69728
70833
|
};
|
|
69729
70834
|
|
|
69730
70835
|
// src/app/runtime-composition.ts
|
|
69731
|
-
import { existsSync as
|
|
69732
|
-
import * as
|
|
70836
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync13 } from "fs";
|
|
70837
|
+
import * as path30 from "path";
|
|
69733
70838
|
var CliMissingApiKeyError = class extends Error {
|
|
69734
70839
|
constructor(message) {
|
|
69735
70840
|
super(message);
|
|
@@ -69750,13 +70855,13 @@ var CliSessionResumeError = class extends Error {
|
|
|
69750
70855
|
function getCliRuntimePaths() {
|
|
69751
70856
|
const configDir = getConfigDir();
|
|
69752
70857
|
const sessionsDir = getSessionsDir();
|
|
69753
|
-
const skillsDir =
|
|
69754
|
-
const builtinSkillsDir =
|
|
70858
|
+
const skillsDir = path30.join(configDir, "skills");
|
|
70859
|
+
const builtinSkillsDir = path30.join(getBuiltinDir(), "skills");
|
|
69755
70860
|
return { configDir, sessionsDir, skillsDir, builtinSkillsDir };
|
|
69756
70861
|
}
|
|
69757
70862
|
function ensureCliRuntimePaths(paths = getCliRuntimePaths()) {
|
|
69758
|
-
if (!
|
|
69759
|
-
|
|
70863
|
+
if (!existsSync18(paths.skillsDir)) {
|
|
70864
|
+
mkdirSync13(paths.skillsDir, { recursive: true });
|
|
69760
70865
|
}
|
|
69761
70866
|
return paths;
|
|
69762
70867
|
}
|
|
@@ -69782,7 +70887,7 @@ async function composeCliRuntime(params) {
|
|
|
69782
70887
|
const paths = ensureCliRuntimePaths(params.paths);
|
|
69783
70888
|
const compositionTrace = createCliCompositionTrace();
|
|
69784
70889
|
const settingsManager = new SettingsManager();
|
|
69785
|
-
const authStorage = new
|
|
70890
|
+
const authStorage = AuthStorage.fromStorage(new FileAuthStorageBackend());
|
|
69786
70891
|
authStorage.setLegacyApiKey(settingsManager.getLegacyApiKey());
|
|
69787
70892
|
const modelRegistry = new ModelRegistry(authStorage);
|
|
69788
70893
|
await modelRegistry.refreshRemoteCatalogs();
|
|
@@ -69868,11 +70973,14 @@ async function composeCliRuntime(params) {
|
|
|
69868
70973
|
fileLogger.log("cli", `Using API key for provider ${provider}`, {
|
|
69869
70974
|
keyPrefix: apiKey ? maskApiKey2(apiKey) : "none"
|
|
69870
70975
|
});
|
|
69871
|
-
const projectSkillsDir =
|
|
70976
|
+
const projectSkillsDir = path30.join(cwd, ".pie", "skills");
|
|
69872
70977
|
const { skills, diagnostics } = loadSkills({
|
|
69873
|
-
|
|
69874
|
-
|
|
69875
|
-
|
|
70978
|
+
dirs: buildSkillDirs({
|
|
70979
|
+
builtinDir: paths.builtinSkillsDir,
|
|
70980
|
+
userDir: paths.skillsDir,
|
|
70981
|
+
projectDir: projectSkillsDir,
|
|
70982
|
+
cwd
|
|
70983
|
+
})
|
|
69876
70984
|
});
|
|
69877
70985
|
let interactiveOptions;
|
|
69878
70986
|
const getCurrentModel = () => interactiveOptions?.model ?? model;
|
|
@@ -70063,6 +71171,17 @@ async function loadPrintModeExtensions(params) {
|
|
|
70063
71171
|
session.metadata[key] = value;
|
|
70064
71172
|
session.isDirty = true;
|
|
70065
71173
|
},
|
|
71174
|
+
appendEntry: (customType, data) => params.sessionManager.appendCustomEntry(customType, data).id,
|
|
71175
|
+
setLabel: (entryId, label) => params.sessionManager.setLabel(entryId, label),
|
|
71176
|
+
setSessionName: (name) => params.sessionManager.setSessionName(name),
|
|
71177
|
+
getSessionName: () => params.sessionManager.getSessionName(),
|
|
71178
|
+
registerProvider: (name, config) => params.modelRegistry.registerProvider(name, config),
|
|
71179
|
+
loginProvider: (name) => loginExtensionProvider({
|
|
71180
|
+
provider: name,
|
|
71181
|
+
modelRegistry: params.modelRegistry,
|
|
71182
|
+
authStorage: params.modelRegistry.getAuthStorage(),
|
|
71183
|
+
requestInteraction
|
|
71184
|
+
}),
|
|
70066
71185
|
yoloMode: false
|
|
70067
71186
|
};
|
|
70068
71187
|
const { extensions } = await loadExtensions(
|
|
@@ -70085,6 +71204,7 @@ async function loadPrintModeExtensions(params) {
|
|
|
70085
71204
|
false
|
|
70086
71205
|
);
|
|
70087
71206
|
runner.setUIContext(uiContext);
|
|
71207
|
+
await restoreExtensionProviderCredentials(params.modelRegistry);
|
|
70088
71208
|
const extensionTools = convertExtensionTools(extensions);
|
|
70089
71209
|
availableTools = [...availableTools, ...extensionTools];
|
|
70090
71210
|
return {
|
|
@@ -70110,7 +71230,7 @@ async function runPrintMode(params) {
|
|
|
70110
71230
|
`);
|
|
70111
71231
|
console.log("Assistant: ");
|
|
70112
71232
|
}
|
|
70113
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
71233
|
+
const { Agent: AgentClass } = await import("./chunks/src-TQNFXZGK.js");
|
|
70114
71234
|
let agent;
|
|
70115
71235
|
const printModeExtensions = await loadPrintModeExtensions({
|
|
70116
71236
|
cwd: runtime.cwd,
|
|
@@ -70126,6 +71246,8 @@ async function runPrintMode(params) {
|
|
|
70126
71246
|
allTools: runtime.allTools
|
|
70127
71247
|
});
|
|
70128
71248
|
const printModeTools = [...runtime.tools, ...printModeExtensions.extensionTools];
|
|
71249
|
+
const restoredApiKey = runtime.modelRegistry.getApiKey(runtime.model);
|
|
71250
|
+
if (restoredApiKey) runtime.apiKey = restoredApiKey;
|
|
70129
71251
|
recordCliCompositionStep(runtime.compositionTrace, {
|
|
70130
71252
|
id: "extensions_tool_wrapping",
|
|
70131
71253
|
inputSummary: `baseTools=${runtime.tools.length} extensionPaths=${runtime.extensionPaths.length}`,
|
|
@@ -70189,12 +71311,26 @@ async function runPrintMode(params) {
|
|
|
70189
71311
|
isContextOverflowError: isCliContextOverflowError
|
|
70190
71312
|
}),
|
|
70191
71313
|
compaction: {
|
|
70192
|
-
compact: async (context) =>
|
|
70193
|
-
|
|
70194
|
-
|
|
70195
|
-
|
|
70196
|
-
|
|
70197
|
-
|
|
71314
|
+
compact: async (context) => {
|
|
71315
|
+
const beforeCompact = await printModeExtensions.runner.emitSessionBeforeCompact({
|
|
71316
|
+
type: "session:before_compact",
|
|
71317
|
+
reason: context.reason === "overflow" ? "overflow" : "threshold",
|
|
71318
|
+
messageCount: context.messages.length
|
|
71319
|
+
});
|
|
71320
|
+
if (beforeCompact.cancel) return { aborted: true };
|
|
71321
|
+
if (beforeCompact.summary) {
|
|
71322
|
+
const activeEntryId = context.sessionManager.getActiveEntryId();
|
|
71323
|
+
const firstKeptEntryId = activeEntryId ? findFirstKeptEntryId(context.sessionManager.getPathToEntry(activeEntryId)) : void 0;
|
|
71324
|
+
if (!firstKeptEntryId) return { aborted: true };
|
|
71325
|
+
return { summary: beforeCompact.summary, firstKeptEntryId };
|
|
71326
|
+
}
|
|
71327
|
+
return createCliAutoCompactionResult({
|
|
71328
|
+
context,
|
|
71329
|
+
model: runtime.model,
|
|
71330
|
+
apiKey: runtime.apiKey,
|
|
71331
|
+
systemPrompt: agent?.state.systemPrompt ?? baseSystemPrompt
|
|
71332
|
+
});
|
|
71333
|
+
}
|
|
70198
71334
|
},
|
|
70199
71335
|
classifyFailure: (context) => classifyCliFailure(context),
|
|
70200
71336
|
onEvent: (event) => {
|
|
@@ -70516,6 +71652,7 @@ async function loadJsonModeExtensions(params) {
|
|
|
70516
71652
|
false
|
|
70517
71653
|
);
|
|
70518
71654
|
runner.setUIContext(uiContext);
|
|
71655
|
+
await restoreExtensionProviderCredentials(params.runtime.modelRegistry);
|
|
70519
71656
|
const extensionTools = convertExtensionTools(extensions);
|
|
70520
71657
|
availableTools = [...availableTools, ...extensionTools];
|
|
70521
71658
|
return {
|
|
@@ -70549,7 +71686,7 @@ async function runJsonEventsMode(params) {
|
|
|
70549
71686
|
return typeof message.sessionId === "string" && message.sessionId !== sessionId;
|
|
70550
71687
|
}
|
|
70551
71688
|
function delay(ms) {
|
|
70552
|
-
return new Promise((
|
|
71689
|
+
return new Promise((resolve7) => setTimeout(resolve7, Math.max(0, ms)));
|
|
70553
71690
|
}
|
|
70554
71691
|
async function waitForActiveController(timeoutMs = 1e3) {
|
|
70555
71692
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -71060,9 +72197,11 @@ async function runJsonEventsMode(params) {
|
|
|
71060
72197
|
if (runtime.initialModel.unconfigured || controller) {
|
|
71061
72198
|
return;
|
|
71062
72199
|
}
|
|
71063
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
72200
|
+
const { Agent: AgentClass } = await import("./chunks/src-TQNFXZGK.js");
|
|
71064
72201
|
const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
|
|
71065
72202
|
const tools = [...runtime.tools, ...jsonModeExtensions.extensionTools];
|
|
72203
|
+
const restoredApiKey = runtime.modelRegistry.getApiKey(runtime.model);
|
|
72204
|
+
if (restoredApiKey) runtime.apiKey = restoredApiKey;
|
|
71066
72205
|
recordCliCompositionStep(runtime.compositionTrace, {
|
|
71067
72206
|
id: "extensions_tool_wrapping",
|
|
71068
72207
|
inputSummary: `baseTools=${runtime.tools.length} extensionPaths=${runtime.extensionPaths.length}`,
|
|
@@ -71494,19 +72633,19 @@ async function runJsonEventsMode(params) {
|
|
|
71494
72633
|
}
|
|
71495
72634
|
|
|
71496
72635
|
// src/developer-instructions.ts
|
|
71497
|
-
import * as
|
|
71498
|
-
import * as
|
|
72636
|
+
import * as fs27 from "fs";
|
|
72637
|
+
import * as path31 from "path";
|
|
71499
72638
|
var MAX_DEVELOPER_INSTRUCTIONS_CHARS = 64e3;
|
|
71500
72639
|
function readTextFileBounded(filePath) {
|
|
71501
|
-
const resolved =
|
|
71502
|
-
const stat2 =
|
|
72640
|
+
const resolved = path31.resolve(filePath);
|
|
72641
|
+
const stat2 = fs27.statSync(resolved);
|
|
71503
72642
|
if (!stat2.isFile()) {
|
|
71504
72643
|
throw new Error(`Developer instructions file is not a regular file: ${filePath}`);
|
|
71505
72644
|
}
|
|
71506
72645
|
if (stat2.size > MAX_DEVELOPER_INSTRUCTIONS_CHARS * 4) {
|
|
71507
72646
|
throw new Error(`Developer instructions file is too large: ${filePath}`);
|
|
71508
72647
|
}
|
|
71509
|
-
return
|
|
72648
|
+
return fs27.readFileSync(resolved, "utf8");
|
|
71510
72649
|
}
|
|
71511
72650
|
function collectFlagValues(args, flag) {
|
|
71512
72651
|
const values = [];
|
|
@@ -71584,8 +72723,8 @@ var logError = (msg, err) => {
|
|
|
71584
72723
|
const logPath = getRuntimeLogPath();
|
|
71585
72724
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
71586
72725
|
const stack = err instanceof Error ? err.stack || "" : "";
|
|
71587
|
-
|
|
71588
|
-
|
|
72726
|
+
fs28.mkdirSync(path32.dirname(logPath), { recursive: true });
|
|
72727
|
+
fs28.appendFileSync(logPath, `[${timestamp}] ${msg}
|
|
71589
72728
|
${stack}
|
|
71590
72729
|
|
|
71591
72730
|
`);
|
|
@@ -71692,7 +72831,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
|
|
|
71692
72831
|
}
|
|
71693
72832
|
async function createCliTestStreamFnFromEnv() {
|
|
71694
72833
|
if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
|
|
71695
|
-
return (await import("./chunks/test-stream-
|
|
72834
|
+
return (await import("./chunks/test-stream-IPBFEEWH.js")).createTestStreamFnFromSequenceEnv();
|
|
71696
72835
|
}
|
|
71697
72836
|
async function startChat(initialPrompt, testCommand) {
|
|
71698
72837
|
const rawOutput = process.argv.includes("--raw-output");
|
|
@@ -71787,9 +72926,9 @@ async function startChat(initialPrompt, testCommand) {
|
|
|
71787
72926
|
flushEarlyLogs();
|
|
71788
72927
|
if (testCommand) {
|
|
71789
72928
|
console.log(`[TEST] Auto-executing command: ${testCommand}`);
|
|
71790
|
-
await new Promise((
|
|
72929
|
+
await new Promise((resolve7) => setTimeout(resolve7, 500));
|
|
71791
72930
|
await interactive.executeCommand(testCommand);
|
|
71792
|
-
await new Promise((
|
|
72931
|
+
await new Promise((resolve7) => setTimeout(resolve7, 2e3));
|
|
71793
72932
|
console.log("[TEST] Command executed, exiting...");
|
|
71794
72933
|
process.exit(0);
|
|
71795
72934
|
return;
|