@cydm/pie 1.0.7 → 1.0.8

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/dist/cli.js CHANGED
@@ -1,17 +1,29 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
3
3
  import {
4
- createCliHostCapabilities
5
- } from "./chunks/chunk-GDTN4UPJ.js";
4
+ createCliHostCapabilities,
5
+ createCliWebResearchHealthStore,
6
+ getAgentDir,
7
+ getBuiltinDir,
8
+ getConfigDir,
9
+ getCustomThemesDir,
10
+ getLogsDir,
11
+ getPackageDir,
12
+ getRuntimeLogPath,
13
+ getSessionsDir,
14
+ getSettingsPath,
15
+ getThemesDir,
16
+ migrateConfigFromAgentDir
17
+ } from "./chunks/chunk-ZRONUKTW.js";
6
18
  import {
19
+ AGENTS_CONTEXT_FILE_NAME,
7
20
  AgentSessionController,
8
21
  BUILTIN_TOOL_CAPABILITY_METADATA,
9
22
  SessionTraceSnapshotWriter,
10
23
  abortExecutionState,
11
24
  attachAgentEventsToSessionTrace,
12
25
  buildExecutionReminder,
13
- buildKnowledgeIndexEntry,
14
- buildKnowledgeIndexSection,
26
+ buildProjectContextSection,
15
27
  buildToolsPromptSection,
16
28
  calculateTotalTokens,
17
29
  continueExecutionState,
@@ -21,11 +33,9 @@ import {
21
33
  createExecutionStateStore,
22
34
  createPolicyEnforcedTools,
23
35
  createReadFileUnderstandingHandler,
24
- createReadResourceCapability,
25
- createReadSkillCapability,
26
- createResolveResourceCapability,
27
36
  createSessionManager,
28
37
  createSharedFileSystemTools,
38
+ createSharedWebSearchTool,
29
39
  createTodoWidgetView,
30
40
  evaluateTodoClosureAfterAbort,
31
41
  evaluateTodoClosureAfterCompletedTurn,
@@ -35,13 +45,14 @@ import {
35
45
  hasInteractionHandler,
36
46
  maybeAdvanceTodoExecutionState,
37
47
  modalityForReadFileUnderstandingKind,
48
+ pauseExecutionState,
38
49
  registerInteractionHandler,
39
50
  requestInteraction,
40
51
  restoreExecutionState,
41
52
  selectToolsForRuntimePolicy,
42
53
  shouldPreserveExecutionStateForUserText,
43
54
  supersedeExecutionState
44
- } from "./chunks/chunk-BHNULR7U.js";
55
+ } from "./chunks/chunk-6WD2NFIC.js";
45
56
  import {
46
57
  Deref,
47
58
  Errors,
@@ -76,6 +87,9 @@ import {
76
87
  sortToolModelCandidatesByCapability,
77
88
  type_exports
78
89
  } from "./chunks/chunk-A5JSJAPK.js";
90
+ import {
91
+ resolveCliProjectRoot
92
+ } from "./chunks/chunk-NTYHFBUA.js";
79
93
  import {
80
94
  __commonJS,
81
95
  __require,
@@ -1883,7 +1897,7 @@ var require_core = __commonJS({
1883
1897
  return match && match.index === 0;
1884
1898
  }
1885
1899
  var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
1886
- function join20(regexps, separator = "|") {
1900
+ function join19(regexps, separator = "|") {
1887
1901
  let numCaptures = 0;
1888
1902
  return regexps.map((regex) => {
1889
1903
  numCaptures += 1;
@@ -2187,7 +2201,7 @@ var require_core = __commonJS({
2187
2201
  this.exec = () => null;
2188
2202
  }
2189
2203
  const terminators = this.regexes.map((el) => el[1]);
2190
- this.matcherRe = langRe(join20(terminators), true);
2204
+ this.matcherRe = langRe(join19(terminators), true);
2191
2205
  this.lastIndex = 0;
2192
2206
  }
2193
2207
  /** @param {string} s */
@@ -14049,7 +14063,7 @@ var require_http = __commonJS({
14049
14063
  return joined;
14050
14064
  }
14051
14065
  function http(hljs) {
14052
- const VERSION2 = "HTTP/(2|1\\.[01])";
14066
+ const VERSION = "HTTP/(2|1\\.[01])";
14053
14067
  const HEADER_NAME = /[A-Za-z][A-Za-z0-9-]*/;
14054
14068
  const HEADER = {
14055
14069
  className: "attribute",
@@ -14082,12 +14096,12 @@ var require_http = __commonJS({
14082
14096
  contains: [
14083
14097
  // response
14084
14098
  {
14085
- begin: "^(?=" + VERSION2 + " \\d{3})",
14099
+ begin: "^(?=" + VERSION + " \\d{3})",
14086
14100
  end: /$/,
14087
14101
  contains: [
14088
14102
  {
14089
14103
  className: "meta",
14090
- begin: VERSION2
14104
+ begin: VERSION
14091
14105
  },
14092
14106
  {
14093
14107
  className: "number",
@@ -14102,7 +14116,7 @@ var require_http = __commonJS({
14102
14116
  },
14103
14117
  // request
14104
14118
  {
14105
- begin: "(?=^[A-Z]+ (.*?) " + VERSION2 + "$)",
14119
+ begin: "(?=^[A-Z]+ (.*?) " + VERSION + "$)",
14106
14120
  end: /$/,
14107
14121
  contains: [
14108
14122
  {
@@ -14114,7 +14128,7 @@ var require_http = __commonJS({
14114
14128
  },
14115
14129
  {
14116
14130
  className: "meta",
14117
- begin: VERSION2
14131
+ begin: VERSION
14118
14132
  },
14119
14133
  {
14120
14134
  className: "keyword",
@@ -50554,7 +50568,7 @@ var ProcessTerminal = class {
50554
50568
  const timeLeft = endTime - now;
50555
50569
  if (timeLeft <= 0) break;
50556
50570
  if (now - lastDataTime >= idleMs) break;
50557
- await new Promise((resolve6) => setTimeout(resolve6, Math.min(idleMs, timeLeft)));
50571
+ await new Promise((resolve4) => setTimeout(resolve4, Math.min(idleMs, timeLeft)));
50558
50572
  }
50559
50573
  } finally {
50560
50574
  process.stdin.removeListener("data", onData);
@@ -50629,120 +50643,8 @@ var ProcessTerminal = class {
50629
50643
  };
50630
50644
 
50631
50645
  // src/keybindings.ts
50632
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
50633
- import { join as join3 } from "path";
50634
-
50635
- // src/config.ts
50636
- import { existsSync, mkdirSync as mkdirSync2, readFileSync, renameSync } from "fs";
50637
- import { homedir as homedir2 } from "os";
50638
- import { dirname as dirname2, join as join2 } from "path";
50639
- import { fileURLToPath } from "url";
50640
- var __filename = fileURLToPath(import.meta.url);
50641
- var __dirname = dirname2(__filename);
50642
- var isBunRuntime = !!process.versions.bun;
50643
- function getPackageDir() {
50644
- const envDir = process.env.PIE_PACKAGE_DIR;
50645
- if (envDir) {
50646
- if (envDir === "~") return homedir2();
50647
- if (envDir.startsWith("~/")) return homedir2() + envDir.slice(1);
50648
- return envDir;
50649
- }
50650
- let dir = __dirname;
50651
- while (dir !== dirname2(dir)) {
50652
- if (existsSync(join2(dir, "package.json"))) {
50653
- return dir;
50654
- }
50655
- dir = dirname2(dir);
50656
- }
50657
- return __dirname;
50658
- }
50659
- function getThemesDir() {
50660
- const packageDir = getPackageDir();
50661
- const srcOrDist = existsSync(join2(packageDir, "src")) ? "src" : "dist";
50662
- return join2(packageDir, srcOrDist, "theme");
50663
- }
50664
- function getBuiltinDir() {
50665
- const packageDir = getPackageDir();
50666
- const distBuiltinDir = join2(packageDir, "dist", "builtin");
50667
- if (existsSync(distBuiltinDir)) {
50668
- return distBuiltinDir;
50669
- }
50670
- return join2(packageDir, "builtin");
50671
- }
50672
- function getPackageJsonPath() {
50673
- return join2(getPackageDir(), "package.json");
50674
- }
50675
- var pkg = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8"));
50676
- var CONFIG_DIR_NAME = ".pie";
50677
- var VERSION = pkg.version;
50678
- var ENV_AGENT_DIR = "PIE_CODING_AGENT_DIR";
50679
- function getConfigDir() {
50680
- const envDir = process.env[ENV_AGENT_DIR];
50681
- if (envDir) {
50682
- if (envDir === "~") return homedir2();
50683
- if (envDir.startsWith("~/")) return homedir2() + envDir.slice(1);
50684
- return envDir;
50685
- }
50686
- return join2(homedir2(), CONFIG_DIR_NAME);
50687
- }
50688
- function getAgentDir() {
50689
- return getConfigDir();
50690
- }
50691
- function getCustomThemesDir() {
50692
- return join2(getConfigDir(), "themes");
50693
- }
50694
- function getSettingsPath() {
50695
- return join2(getConfigDir(), "settings.json");
50696
- }
50697
- function getSessionsDir() {
50698
- return join2(getConfigDir(), "sessions");
50699
- }
50700
- function getLogsDir() {
50701
- return join2(getConfigDir(), "logs");
50702
- }
50703
- function getRuntimeLogPath() {
50704
- return join2(getLogsDir(), "pie-cli.log");
50705
- }
50706
- function migrateConfigFromAgentDir() {
50707
- const oldAgentDir = join2(homedir2(), CONFIG_DIR_NAME, "agent");
50708
- const newConfigDir = getConfigDir();
50709
- if (!existsSync(oldAgentDir)) {
50710
- return;
50711
- }
50712
- if (!existsSync(newConfigDir)) {
50713
- mkdirSync2(newConfigDir, { recursive: true });
50714
- }
50715
- const filesToMigrate = [
50716
- "keybindings.json",
50717
- "settings.json",
50718
- "pie-debug.log"
50719
- ];
50720
- for (const file of filesToMigrate) {
50721
- const oldPath = join2(oldAgentDir, file);
50722
- const newPath = file === "pie-debug.log" ? getRuntimeLogPath() : join2(newConfigDir, file);
50723
- if (existsSync(oldPath) && !existsSync(newPath)) {
50724
- try {
50725
- if (file === "pie-debug.log") {
50726
- mkdirSync2(getLogsDir(), { recursive: true });
50727
- }
50728
- renameSync(oldPath, newPath);
50729
- console.log(`[Config] Migrated ${file} to ${newPath}`);
50730
- } catch (e) {
50731
- }
50732
- }
50733
- }
50734
- const oldThemesDir = join2(oldAgentDir, "themes");
50735
- const newThemesDir = getCustomThemesDir();
50736
- if (existsSync(oldThemesDir) && !existsSync(newThemesDir)) {
50737
- try {
50738
- renameSync(oldThemesDir, newThemesDir);
50739
- console.log(`[Config] Migrated themes to ${newThemesDir}`);
50740
- } catch (e) {
50741
- }
50742
- }
50743
- }
50744
-
50745
- // src/keybindings.ts
50646
+ import { existsSync, readFileSync } from "fs";
50647
+ import { join as join2 } from "path";
50746
50648
  var DEFAULT_APP_KEYBINDINGS = {
50747
50649
  interrupt: "escape",
50748
50650
  clear: "ctrl+c",
@@ -50804,7 +50706,7 @@ var KeybindingsManager = class _KeybindingsManager {
50804
50706
  * Create from config file and set up editor keybindings.
50805
50707
  */
50806
50708
  static create(agentDir = getAgentDir()) {
50807
- const configPath = join3(agentDir, "keybindings.json");
50709
+ const configPath = join2(agentDir, "keybindings.json");
50808
50710
  const config = _KeybindingsManager.loadFromFile(configPath);
50809
50711
  const manager = new _KeybindingsManager(config);
50810
50712
  const editorConfig = {};
@@ -50823,9 +50725,9 @@ var KeybindingsManager = class _KeybindingsManager {
50823
50725
  return new _KeybindingsManager(config);
50824
50726
  }
50825
50727
  static loadFromFile(path26) {
50826
- if (!existsSync2(path26)) return {};
50728
+ if (!existsSync(path26)) return {};
50827
50729
  try {
50828
- return JSON.parse(readFileSync2(path26, "utf-8"));
50730
+ return JSON.parse(readFileSync(path26, "utf-8"));
50829
50731
  } catch {
50830
50732
  return {};
50831
50733
  }
@@ -50876,21 +50778,70 @@ var KeybindingsManager = class _KeybindingsManager {
50876
50778
  // src/project-knowledge.ts
50877
50779
  import fs3 from "node:fs";
50878
50780
  import path2 from "node:path";
50879
- function buildCliKnowledgeIndexSection(cwd) {
50880
- const agentsPath = path2.join(cwd, ".pie", "agents.md");
50881
- if (!fs3.existsSync(agentsPath)) return "";
50882
- try {
50883
- const content = fs3.readFileSync(agentsPath, "utf-8");
50884
- const entry = buildKnowledgeIndexEntry(".pie/agents.md", content);
50885
- return buildKnowledgeIndexSection(entry ? [entry] : []);
50886
- } catch {
50887
- return "";
50781
+ function collectAncestorAgentsFiles(cwd) {
50782
+ const resolvedCwd = path2.resolve(cwd || process.cwd());
50783
+ const projectRoot = resolveCliProjectRoot(resolvedCwd);
50784
+ const candidates = [];
50785
+ let current = resolvedCwd;
50786
+ while (true) {
50787
+ candidates.unshift(path2.join(current, AGENTS_CONTEXT_FILE_NAME));
50788
+ if (current === projectRoot) {
50789
+ break;
50790
+ }
50791
+ const parent = path2.dirname(current);
50792
+ if (parent === current) {
50793
+ break;
50794
+ }
50795
+ current = parent;
50796
+ }
50797
+ const files = [];
50798
+ for (const candidate of candidates) {
50799
+ if (!fs3.existsSync(candidate)) {
50800
+ continue;
50801
+ }
50802
+ try {
50803
+ files.push({
50804
+ path: path2.relative(resolvedCwd, candidate) || AGENTS_CONTEXT_FILE_NAME,
50805
+ content: fs3.readFileSync(candidate, "utf-8")
50806
+ });
50807
+ } catch {
50808
+ }
50809
+ }
50810
+ return files;
50811
+ }
50812
+ function buildCliProjectContextSection(cwd) {
50813
+ return buildProjectContextSection(collectAncestorAgentsFiles(cwd));
50814
+ }
50815
+
50816
+ // src/file-access-context.ts
50817
+ import * as path3 from "node:path";
50818
+ function uniqueNormalizedPaths(paths) {
50819
+ const seen = /* @__PURE__ */ new Set();
50820
+ const result = [];
50821
+ for (const entry of paths) {
50822
+ const trimmed = String(entry || "").trim();
50823
+ if (!trimmed) continue;
50824
+ const normalized = path3.normalize(trimmed);
50825
+ if (seen.has(normalized)) continue;
50826
+ seen.add(normalized);
50827
+ result.push(normalized);
50888
50828
  }
50829
+ return result;
50830
+ }
50831
+ function buildCliFileAccessOptions(params) {
50832
+ return {
50833
+ accessRoots: uniqueNormalizedPaths([
50834
+ resolveCliProjectRoot(params.cwd),
50835
+ params.configDir,
50836
+ ...params.skills.map((skill) => skill.baseDir)
50837
+ ]),
50838
+ allowlistedDirs: params.allowlistedDirs
50839
+ };
50889
50840
  }
50890
50841
 
50891
50842
  // src/theme/theme.ts
50892
50843
  import * as fs4 from "node:fs";
50893
- import * as path3 from "node:path";
50844
+ import * as path4 from "node:path";
50894
50845
 
50895
50846
  // ../../node_modules/@sinclair/typebox/build/esm/compiler/compiler.mjs
50896
50847
  var TypeCheck = class {
@@ -51777,8 +51728,8 @@ var BUILTIN_THEMES;
51777
51728
  function getBuiltinThemes() {
51778
51729
  if (!BUILTIN_THEMES) {
51779
51730
  const themesDir = getThemesDir();
51780
- const darkPath = path3.join(themesDir, "dark.json");
51781
- const lightPath = path3.join(themesDir, "light.json");
51731
+ const darkPath = path4.join(themesDir, "dark.json");
51732
+ const lightPath = path4.join(themesDir, "light.json");
51782
51733
  BUILTIN_THEMES = {
51783
51734
  dark: JSON.parse(fs4.readFileSync(darkPath, "utf-8")),
51784
51735
  light: JSON.parse(fs4.readFileSync(lightPath, "utf-8"))
@@ -51858,7 +51809,7 @@ function loadThemeJson(name) {
51858
51809
  throw new Error(`Theme "${name}" does not have a source path for export`);
51859
51810
  }
51860
51811
  const customThemesDir = getCustomThemesDir();
51861
- const themePath = path3.join(customThemesDir, `${name}.json`);
51812
+ const themePath = path4.join(customThemesDir, `${name}.json`);
51862
51813
  if (!fs4.existsSync(themePath)) {
51863
51814
  throw new Error(`Theme not found: ${name}`);
51864
51815
  }
@@ -51975,7 +51926,7 @@ function startThemeWatcher() {
51975
51926
  return;
51976
51927
  }
51977
51928
  const customThemesDir = getCustomThemesDir();
51978
- const themeFile = path3.join(customThemesDir, `${currentThemeName}.json`);
51929
+ const themeFile = path4.join(customThemesDir, `${currentThemeName}.json`);
51979
51930
  if (!fs4.existsSync(themeFile)) {
51980
51931
  return;
51981
51932
  }
@@ -52165,36 +52116,7 @@ function getEditorTheme() {
52165
52116
 
52166
52117
  // src/skills/loader.ts
52167
52118
  import * as fs5 from "fs";
52168
- import * as path4 from "path";
52169
- function inferResourceKind(resourcePath) {
52170
- const lower = resourcePath.toLowerCase();
52171
- if (lower.endsWith(".md")) return "document";
52172
- if (lower.endsWith(".js") || lower.endsWith(".mjs") || lower.endsWith(".sh") || lower.endsWith(".py")) return "script";
52173
- return void 0;
52174
- }
52175
- function extractResourceRefs(content) {
52176
- const refs = /* @__PURE__ */ new Map();
52177
- const patterns = [
52178
- /`((?:references|scripts|assets|examples)\/[^`\n]+)`/g,
52179
- /\b((?:references|scripts|assets|examples)\/[A-Za-z0-9._/-]+)/g,
52180
- /`(\.?\/[A-Za-z0-9._/-]+\.[A-Za-z0-9]+)`/g
52181
- ];
52182
- for (const pattern of patterns) {
52183
- for (const match of content.matchAll(pattern)) {
52184
- const rawPath = String(match[1] || "").trim().replace(/\\/g, "/");
52185
- if (!rawPath) continue;
52186
- const normalizedPath = rawPath.replace(/^\.\/+/, "");
52187
- if (!normalizedPath || normalizedPath.startsWith("/") || normalizedPath.includes("..")) continue;
52188
- if (!refs.has(normalizedPath)) {
52189
- refs.set(normalizedPath, {
52190
- path: normalizedPath,
52191
- kind: inferResourceKind(normalizedPath)
52192
- });
52193
- }
52194
- }
52195
- }
52196
- return Array.from(refs.values());
52197
- }
52119
+ import * as path5 from "path";
52198
52120
  function parseSkillDescription(content) {
52199
52121
  const frontmatterMatch = content.match(/^---\n[\s\S]*?description:\s*["']?(.+?)["']?(?:\n|$)/m);
52200
52122
  if (frontmatterMatch) return frontmatterMatch[1].trim();
@@ -52218,9 +52140,9 @@ function loadSkillsFromDir(dir, source) {
52218
52140
  const entries = fs5.readdirSync(dir, { withFileTypes: true });
52219
52141
  for (const entry of entries) {
52220
52142
  if (entry.name.startsWith(".")) continue;
52221
- const fullPath = path4.join(dir, entry.name);
52143
+ const fullPath = path5.join(dir, entry.name);
52222
52144
  if (entry.isDirectory()) {
52223
- const skillMdPath = path4.join(fullPath, "SKILL.md");
52145
+ const skillMdPath = path5.join(fullPath, "SKILL.md");
52224
52146
  if (fs5.existsSync(skillMdPath)) {
52225
52147
  try {
52226
52148
  const content = fs5.readFileSync(skillMdPath, "utf-8");
@@ -52231,8 +52153,7 @@ function loadSkillsFromDir(dir, source) {
52231
52153
  content,
52232
52154
  filePath: skillMdPath,
52233
52155
  source,
52234
- baseDir: fullPath,
52235
- resourceRefs: extractResourceRefs(content)
52156
+ baseDir: fullPath
52236
52157
  });
52237
52158
  } catch (e) {
52238
52159
  diagnostics.push({
@@ -52253,8 +52174,7 @@ function loadSkillsFromDir(dir, source) {
52253
52174
  content,
52254
52175
  filePath: fullPath,
52255
52176
  source,
52256
- baseDir: dir,
52257
- resourceRefs: extractResourceRefs(content)
52177
+ baseDir: dir
52258
52178
  });
52259
52179
  } catch (e) {
52260
52180
  diagnostics.push({
@@ -52441,84 +52361,8 @@ function validateSkillName(name) {
52441
52361
  return { valid: true };
52442
52362
  }
52443
52363
 
52444
- // src/skills/runtime.ts
52445
- import * as fs6 from "node:fs";
52446
- import * as path5 from "node:path";
52447
- function resolveSkill(skills, name) {
52448
- return skills.find((entry) => entry.name === name) ?? null;
52449
- }
52450
- function resolveSkillResource(skill, resourcePath) {
52451
- const trimmed = String(resourcePath || "").trim().replace(/\\/g, "/");
52452
- if (!trimmed || trimmed.startsWith("/") || /^[A-Za-z]:\//.test(trimmed)) {
52453
- return null;
52454
- }
52455
- const segments = trimmed.split("/").filter(Boolean);
52456
- if (segments.some((segment) => segment === "..")) {
52457
- return null;
52458
- }
52459
- const absolutePath = path5.resolve(skill.baseDir, ...segments);
52460
- const relativePath = path5.relative(skill.baseDir, absolutePath).replace(/\\/g, "/");
52461
- if (relativePath.startsWith("../") || relativePath === "..") {
52462
- return null;
52463
- }
52464
- return absolutePath;
52465
- }
52466
- function createCliReadSkillTool(skills) {
52467
- return createReadSkillCapability({
52468
- resolveSkill(name) {
52469
- const skill = resolveSkill(skills, name);
52470
- if (!skill) {
52471
- return null;
52472
- }
52473
- return {
52474
- name: skill.name,
52475
- content: skill.content,
52476
- resources: skill.resourceRefs
52477
- };
52478
- }
52479
- }).tool;
52480
- }
52481
- function createCliReadResourceTool(skills) {
52482
- return createReadResourceCapability({
52483
- resolveResource(owner, resourcePath) {
52484
- const skill = resolveSkill(skills, owner);
52485
- if (!skill) {
52486
- return null;
52487
- }
52488
- const absolutePath = resolveSkillResource(skill, resourcePath);
52489
- if (!absolutePath || !fs6.existsSync(absolutePath) || !fs6.statSync(absolutePath).isFile()) {
52490
- return null;
52491
- }
52492
- return {
52493
- owner: skill.name,
52494
- path: resourcePath.replace(/\\/g, "/").replace(/^\.\/+/, ""),
52495
- content: fs6.readFileSync(absolutePath, "utf8")
52496
- };
52497
- }
52498
- }).tool;
52499
- }
52500
- function createCliResolveResourceTool(skills) {
52501
- return createResolveResourceCapability({
52502
- resolveResource(owner, resourcePath) {
52503
- const skill = resolveSkill(skills, owner);
52504
- if (!skill) {
52505
- return null;
52506
- }
52507
- const absolutePath = resolveSkillResource(skill, resourcePath);
52508
- if (!absolutePath || !fs6.existsSync(absolutePath) || !fs6.statSync(absolutePath).isFile()) {
52509
- return null;
52510
- }
52511
- return {
52512
- owner: skill.name,
52513
- path: resourcePath.replace(/\\/g, "/").replace(/^\.\/+/, ""),
52514
- resolvedPath: absolutePath
52515
- };
52516
- }
52517
- }).tool;
52518
- }
52519
-
52520
52364
  // src/debug/file-logger.ts
52521
- import * as fs7 from "fs";
52365
+ import * as fs6 from "fs";
52522
52366
  import * as path6 from "path";
52523
52367
  var FileLogger = class {
52524
52368
  config = {
@@ -52560,8 +52404,8 @@ var FileLogger = class {
52560
52404
  this.config.filePath = filePath;
52561
52405
  }
52562
52406
  const dir = path6.dirname(this.config.filePath);
52563
- if (!fs7.existsSync(dir)) {
52564
- fs7.mkdirSync(dir, { recursive: true });
52407
+ if (!fs6.existsSync(dir)) {
52408
+ fs6.mkdirSync(dir, { recursive: true });
52565
52409
  }
52566
52410
  this.log("file-logger", `File logging enabled: ${this.config.filePath}`);
52567
52411
  }
@@ -52599,8 +52443,8 @@ var FileLogger = class {
52599
52443
  this.buffer = [];
52600
52444
  this.bufferIndex = 0;
52601
52445
  this.totalLines = 0;
52602
- if (fs7.existsSync(this.config.filePath)) {
52603
- fs7.writeFileSync(this.config.filePath, "");
52446
+ if (fs6.existsSync(this.config.filePath)) {
52447
+ fs6.writeFileSync(this.config.filePath, "");
52604
52448
  }
52605
52449
  }
52606
52450
  /**
@@ -52641,8 +52485,8 @@ var FileLogger = class {
52641
52485
  */
52642
52486
  getStats() {
52643
52487
  let size = 0;
52644
- if (fs7.existsSync(this.config.filePath)) {
52645
- const stats = fs7.statSync(this.config.filePath);
52488
+ if (fs6.existsSync(this.config.filePath)) {
52489
+ const stats = fs6.statSync(this.config.filePath);
52646
52490
  size = stats.size;
52647
52491
  }
52648
52492
  return {
@@ -52656,11 +52500,11 @@ var FileLogger = class {
52656
52500
  * Read last N lines from file (fallback when buffer is not enough)
52657
52501
  */
52658
52502
  readLastLines(count) {
52659
- if (!fs7.existsSync(this.config.filePath)) {
52503
+ if (!fs6.existsSync(this.config.filePath)) {
52660
52504
  return [];
52661
52505
  }
52662
52506
  try {
52663
- const content = fs7.readFileSync(this.config.filePath, "utf-8");
52507
+ const content = fs6.readFileSync(this.config.filePath, "utf-8");
52664
52508
  const lines = content.split("\n").filter(Boolean);
52665
52509
  return lines.slice(-count);
52666
52510
  } catch {
@@ -52678,10 +52522,10 @@ var FileLogger = class {
52678
52522
  const entry = this.formatEntry(level, module, message, data);
52679
52523
  try {
52680
52524
  const dir = path6.dirname(this.config.filePath);
52681
- if (!fs7.existsSync(dir)) {
52682
- fs7.mkdirSync(dir, { recursive: true });
52525
+ if (!fs6.existsSync(dir)) {
52526
+ fs6.mkdirSync(dir, { recursive: true });
52683
52527
  }
52684
- fs7.appendFileSync(this.config.filePath, entry + "\n");
52528
+ fs6.appendFileSync(this.config.filePath, entry + "\n");
52685
52529
  } catch {
52686
52530
  return;
52687
52531
  }
@@ -52770,7 +52614,7 @@ function flushEarlyLogs() {
52770
52614
 
52771
52615
  // src/capabilities/read-file-understanding.ts
52772
52616
  import * as path15 from "node:path";
52773
- import * as fs15 from "node:fs/promises";
52617
+ import * as fs14 from "node:fs/promises";
52774
52618
 
52775
52619
  // src/core/provider-capabilities.ts
52776
52620
  var PLATFORM_DISPLAY_NAMES = {
@@ -52796,7 +52640,7 @@ function getProviderDisplayName(platform2) {
52796
52640
  }
52797
52641
 
52798
52642
  // src/files/adapters/kimi-adapter.ts
52799
- import * as fs8 from "node:fs";
52643
+ import * as fs7 from "node:fs";
52800
52644
  import * as path7 from "node:path";
52801
52645
 
52802
52646
  // src/files/errors.ts
@@ -52937,14 +52781,14 @@ var KimiFileAdapter = class {
52937
52781
  const fileName = options.sourceName || path7.basename(filePath);
52938
52782
  const mimeType = options.mimeType || this.guessMimeType(fileName);
52939
52783
  const purpose = this.detectPurpose(filePath, options.purpose, mimeType);
52940
- const stats = fs8.statSync(filePath);
52784
+ const stats = fs7.statSync(filePath);
52941
52785
  if (stats.size > this.capabilities.maxFileSize) {
52942
52786
  throw new FileManagerError(
52943
52787
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
52944
52788
  `File size ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds Kimi limit of 100MB`
52945
52789
  );
52946
52790
  }
52947
- const fileBuffer = fs8.readFileSync(filePath);
52791
+ const fileBuffer = fs7.readFileSync(filePath);
52948
52792
  const file = new File([fileBuffer], fileName, { type: mimeType });
52949
52793
  const formData = new FormData();
52950
52794
  formData.append("file", file);
@@ -53158,7 +53002,7 @@ var KimiFileAdapter = class {
53158
53002
  };
53159
53003
 
53160
53004
  // src/files/adapters/gemini-adapter.ts
53161
- import * as fs9 from "node:fs";
53005
+ import * as fs8 from "node:fs";
53162
53006
  import * as path8 from "node:path";
53163
53007
  import { Readable } from "node:stream";
53164
53008
  var GeminiFileAdapter = class {
@@ -53216,7 +53060,7 @@ var GeminiFileAdapter = class {
53216
53060
  // Upload
53217
53061
  // ============================================================================
53218
53062
  async upload(filePath, options = {}) {
53219
- const stats = fs9.statSync(filePath);
53063
+ const stats = fs8.statSync(filePath);
53220
53064
  if (stats.size > this.capabilities.maxFileSize) {
53221
53065
  throw new FileManagerError(
53222
53066
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
@@ -53255,7 +53099,7 @@ var GeminiFileAdapter = class {
53255
53099
  "No upload URL received"
53256
53100
  );
53257
53101
  }
53258
- const fileStream = Readable.toWeb(fs9.createReadStream(filePath));
53102
+ const fileStream = Readable.toWeb(fs8.createReadStream(filePath));
53259
53103
  const uploadResponse = await fetch(uploadUrl, {
53260
53104
  method: "POST",
53261
53105
  headers: {
@@ -53459,7 +53303,7 @@ var GeminiFileAdapter = class {
53459
53303
  };
53460
53304
 
53461
53305
  // src/files/adapters/openai-compatible-files-adapter.ts
53462
- import * as fs10 from "node:fs";
53306
+ import * as fs9 from "node:fs";
53463
53307
  import * as path9 from "node:path";
53464
53308
  var OpenAICompatibleFilesAdapter = class {
53465
53309
  constructor(apiKey, baseUrl, extraHeaders = {}) {
@@ -53488,14 +53332,14 @@ var OpenAICompatibleFilesAdapter = class {
53488
53332
  async upload(filePath, options = {}) {
53489
53333
  const fileName = options.sourceName || path9.basename(filePath);
53490
53334
  const mimeType = options.mimeType || guessMimeType(fileName);
53491
- const stats = fs10.statSync(filePath);
53335
+ const stats = fs9.statSync(filePath);
53492
53336
  if (stats.size > this.capabilities.maxFileSize) {
53493
53337
  throw new FileManagerError(
53494
53338
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
53495
53339
  `File size ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds OpenAI-compatible Files limit of ${this.capabilities.maxFileSize / 1024 / 1024}MB`
53496
53340
  );
53497
53341
  }
53498
- const file = new File([fs10.readFileSync(filePath)], fileName, { type: mimeType });
53342
+ const file = new File([fs9.readFileSync(filePath)], fileName, { type: mimeType });
53499
53343
  const formData = new FormData();
53500
53344
  formData.append("file", file);
53501
53345
  formData.append("purpose", options.purpose && options.purpose !== "auto" ? options.purpose : "file-extract");
@@ -53628,12 +53472,12 @@ function guessMimeType(filename) {
53628
53472
  }
53629
53473
 
53630
53474
  // src/files/file-manager.ts
53631
- import * as fs14 from "node:fs";
53475
+ import * as fs13 from "node:fs";
53632
53476
  import * as path14 from "node:path";
53633
53477
  import * as crypto2 from "node:crypto";
53634
53478
 
53635
53479
  // src/files/file-cache.ts
53636
- import * as fs11 from "node:fs";
53480
+ import * as fs10 from "node:fs";
53637
53481
  import * as path11 from "node:path";
53638
53482
  import * as crypto from "node:crypto";
53639
53483
 
@@ -53780,22 +53624,22 @@ var FileCache = class _FileCache {
53780
53624
  // Directory Management
53781
53625
  // ============================================================================
53782
53626
  ensureDirectories() {
53783
- if (!fs11.existsSync(this.baseDir)) {
53784
- fs11.mkdirSync(this.baseDir, { recursive: true });
53627
+ if (!fs10.existsSync(this.baseDir)) {
53628
+ fs10.mkdirSync(this.baseDir, { recursive: true });
53785
53629
  }
53786
- if (!fs11.existsSync(this.dataDir)) {
53787
- fs11.mkdirSync(this.dataDir, { recursive: true });
53630
+ if (!fs10.existsSync(this.dataDir)) {
53631
+ fs10.mkdirSync(this.dataDir, { recursive: true });
53788
53632
  }
53789
53633
  }
53790
53634
  // ============================================================================
53791
53635
  // Index Management
53792
53636
  // ============================================================================
53793
53637
  loadIndex() {
53794
- if (!fs11.existsSync(this.indexPath)) {
53638
+ if (!fs10.existsSync(this.indexPath)) {
53795
53639
  return { version: CACHE_VERSION, files: {}, pathHints: {} };
53796
53640
  }
53797
53641
  try {
53798
- const data = JSON.parse(fs11.readFileSync(this.indexPath, "utf-8"));
53642
+ const data = JSON.parse(fs10.readFileSync(this.indexPath, "utf-8"));
53799
53643
  if (data.version !== CACHE_VERSION) {
53800
53644
  cacheLogger.warn(`Index version mismatch: ${data.version} vs ${CACHE_VERSION}`);
53801
53645
  }
@@ -53811,7 +53655,7 @@ var FileCache = class _FileCache {
53811
53655
  }
53812
53656
  saveIndex() {
53813
53657
  try {
53814
- fs11.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
53658
+ fs10.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
53815
53659
  } catch (err) {
53816
53660
  cacheLogger.error(" Failed to save index:", err);
53817
53661
  throw err;
@@ -53821,11 +53665,11 @@ var FileCache = class _FileCache {
53821
53665
  // Hash Computation
53822
53666
  // ============================================================================
53823
53667
  async computeHash(filePath) {
53824
- return new Promise((resolve6, reject) => {
53668
+ return new Promise((resolve4, reject) => {
53825
53669
  const hash = crypto.createHash("sha256");
53826
- const stream = fs11.createReadStream(filePath);
53670
+ const stream = fs10.createReadStream(filePath);
53827
53671
  stream.on("data", (chunk) => hash.update(chunk));
53828
- stream.on("end", () => resolve6(hash.digest("hex")));
53672
+ stream.on("end", () => resolve4(hash.digest("hex")));
53829
53673
  stream.on("error", reject);
53830
53674
  });
53831
53675
  }
@@ -53838,8 +53682,8 @@ var FileCache = class _FileCache {
53838
53682
  getStoragePath(hash) {
53839
53683
  const subdir = hash.slice(0, 2);
53840
53684
  const fullDir = path11.join(this.dataDir, subdir);
53841
- if (!fs11.existsSync(fullDir)) {
53842
- fs11.mkdirSync(fullDir, { recursive: true });
53685
+ if (!fs10.existsSync(fullDir)) {
53686
+ fs10.mkdirSync(fullDir, { recursive: true });
53843
53687
  }
53844
53688
  return path11.join(fullDir, hash);
53845
53689
  }
@@ -53851,11 +53695,11 @@ var FileCache = class _FileCache {
53851
53695
  const hash = await this.computeHash(sourcePath);
53852
53696
  const storagePath = this.getStoragePath(hash);
53853
53697
  this.rememberPathHint(sourcePath, hash, name);
53854
- if (fs11.existsSync(storagePath)) {
53698
+ if (fs10.existsSync(storagePath)) {
53855
53699
  return { hash, localPath: storagePath };
53856
53700
  }
53857
- fs11.copyFileSync(sourcePath, storagePath);
53858
- const stat2 = fs11.statSync(storagePath);
53701
+ fs10.copyFileSync(sourcePath, storagePath);
53702
+ const stat2 = fs10.statSync(storagePath);
53859
53703
  this.index.files[hash] = {
53860
53704
  hash,
53861
53705
  name,
@@ -53872,10 +53716,10 @@ var FileCache = class _FileCache {
53872
53716
  async storeBuffer(data, name, mimeType) {
53873
53717
  const hash = this.computeHashSync(data);
53874
53718
  const storagePath = this.getStoragePath(hash);
53875
- if (fs11.existsSync(storagePath)) {
53719
+ if (fs10.existsSync(storagePath)) {
53876
53720
  return { hash, localPath: storagePath };
53877
53721
  }
53878
- fs11.writeFileSync(storagePath, data);
53722
+ fs10.writeFileSync(storagePath, data);
53879
53723
  this.index.files[hash] = {
53880
53724
  hash,
53881
53725
  name,
@@ -53947,7 +53791,7 @@ var FileCache = class _FileCache {
53947
53791
  getPathHint(filePath) {
53948
53792
  try {
53949
53793
  const resolvedPath = this.getResolvedHintPath(filePath);
53950
- const stat2 = fs11.statSync(resolvedPath);
53794
+ const stat2 = fs10.statSync(resolvedPath);
53951
53795
  if (!stat2.isFile()) return void 0;
53952
53796
  const normalizedMtimeMs = this.normalizeHintMtimeMs(stat2.mtimeMs);
53953
53797
  const key = this.getPathHintKey(resolvedPath);
@@ -53977,7 +53821,7 @@ var FileCache = class _FileCache {
53977
53821
  rememberPathHint(filePath, hash, name) {
53978
53822
  try {
53979
53823
  const resolvedPath = this.getResolvedHintPath(filePath);
53980
- const stat2 = fs11.statSync(resolvedPath);
53824
+ const stat2 = fs10.statSync(resolvedPath);
53981
53825
  if (!stat2.isFile()) return;
53982
53826
  const entry = this.index.files[hash];
53983
53827
  const normalizedMtimeMs = this.normalizeHintMtimeMs(stat2.mtimeMs);
@@ -54036,8 +53880,8 @@ var FileCache = class _FileCache {
54036
53880
  entry = entry || this.index.files[hash];
54037
53881
  if (!entry) return;
54038
53882
  const localPath = path11.join(this.dataDir, entry.localPath);
54039
- if (fs11.existsSync(localPath)) {
54040
- fs11.unlinkSync(localPath);
53883
+ if (fs10.existsSync(localPath)) {
53884
+ fs10.unlinkSync(localPath);
54041
53885
  }
54042
53886
  delete this.index.files[hash];
54043
53887
  if (this.index.pathHints) {
@@ -54052,8 +53896,8 @@ var FileCache = class _FileCache {
54052
53896
  clear() {
54053
53897
  for (const entry of Object.values(this.index.files)) {
54054
53898
  const localPath = path11.join(this.dataDir, entry.localPath);
54055
- if (fs11.existsSync(localPath)) {
54056
- fs11.unlinkSync(localPath);
53899
+ if (fs10.existsSync(localPath)) {
53900
+ fs10.unlinkSync(localPath);
54057
53901
  }
54058
53902
  }
54059
53903
  this.index = { version: CACHE_VERSION, files: {}, pathHints: {} };
@@ -54141,7 +53985,7 @@ var FileCache = class _FileCache {
54141
53985
  getResolvedHintPath(filePath) {
54142
53986
  const resolvedPath = resolvePath(filePath);
54143
53987
  try {
54144
- return fs11.realpathSync.native ? fs11.realpathSync.native(resolvedPath) : fs11.realpathSync(resolvedPath);
53988
+ return fs10.realpathSync.native ? fs10.realpathSync.native(resolvedPath) : fs10.realpathSync(resolvedPath);
54145
53989
  } catch {
54146
53990
  return resolvedPath;
54147
53991
  }
@@ -54149,7 +53993,7 @@ var FileCache = class _FileCache {
54149
53993
  };
54150
53994
 
54151
53995
  // src/files/session-file-manager.ts
54152
- import * as fs12 from "node:fs";
53996
+ import * as fs11 from "node:fs";
54153
53997
  import * as path12 from "node:path";
54154
53998
  var INITIAL_REFRESH_BACKOFF_MS = 6e4;
54155
53999
  var MAX_REFRESH_BACKOFF_MS = 60 * 60 * 1e3;
@@ -54174,15 +54018,15 @@ var SessionFileManager = class {
54174
54018
  // Directory Management
54175
54019
  // ============================================================================
54176
54020
  ensureDirectories() {
54177
- if (!fs12.existsSync(this.sessionsDir)) {
54178
- fs12.mkdirSync(this.sessionsDir, { recursive: true });
54021
+ if (!fs11.existsSync(this.sessionsDir)) {
54022
+ fs11.mkdirSync(this.sessionsDir, { recursive: true });
54179
54023
  }
54180
54024
  }
54181
54025
  // ============================================================================
54182
54026
  // State Management
54183
54027
  // ============================================================================
54184
54028
  loadState() {
54185
- if (!fs12.existsSync(this.statePath)) {
54029
+ if (!fs11.existsSync(this.statePath)) {
54186
54030
  return {
54187
54031
  sessionId: this.sessionId,
54188
54032
  lastSyncedAt: 0,
@@ -54190,7 +54034,7 @@ var SessionFileManager = class {
54190
54034
  };
54191
54035
  }
54192
54036
  try {
54193
- return JSON.parse(fs12.readFileSync(this.statePath, "utf-8"));
54037
+ return JSON.parse(fs11.readFileSync(this.statePath, "utf-8"));
54194
54038
  } catch (err) {
54195
54039
  sessionLogger.error(" Failed to load state:", err);
54196
54040
  return {
@@ -54203,12 +54047,12 @@ var SessionFileManager = class {
54203
54047
  saveState() {
54204
54048
  try {
54205
54049
  if (Object.keys(this.state.files).length === 0) {
54206
- if (fs12.existsSync(this.statePath)) {
54207
- fs12.unlinkSync(this.statePath);
54050
+ if (fs11.existsSync(this.statePath)) {
54051
+ fs11.unlinkSync(this.statePath);
54208
54052
  }
54209
54053
  return;
54210
54054
  }
54211
- fs12.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
54055
+ fs11.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
54212
54056
  } catch (err) {
54213
54057
  sessionLogger.error(" Failed to save state:", err);
54214
54058
  }
@@ -54354,7 +54198,7 @@ var SessionFileManager = class {
54354
54198
  return { success: false, coolingDown: true };
54355
54199
  }
54356
54200
  const localPath = this.fileCache.getLocalPath(entry.hash);
54357
- if (!localPath || !fs12.existsSync(localPath)) {
54201
+ if (!localPath || !fs11.existsSync(localPath)) {
54358
54202
  sessionLogger.warn(`Local file not found for ${fileId}`);
54359
54203
  entry.status = "expired";
54360
54204
  entry.error = "Local file missing";
@@ -54505,15 +54349,15 @@ var SessionFileManager = class {
54505
54349
  // Static Utilities
54506
54350
  // ============================================================================
54507
54351
  static cleanupOldSessions(sessionsDir, maxAge = 30 * 24 * 60 * 60 * 1e3) {
54508
- if (!fs12.existsSync(sessionsDir)) return;
54352
+ if (!fs11.existsSync(sessionsDir)) return;
54509
54353
  const now = Date.now();
54510
- const files = fs12.readdirSync(sessionsDir);
54354
+ const files = fs11.readdirSync(sessionsDir);
54511
54355
  for (const file of files) {
54512
54356
  if (!file.endsWith(".json")) continue;
54513
54357
  const filePath = path12.join(sessionsDir, file);
54514
- const stat2 = fs12.statSync(filePath);
54358
+ const stat2 = fs11.statSync(filePath);
54515
54359
  if (now - stat2.mtime.getTime() > maxAge) {
54516
- fs12.unlinkSync(filePath);
54360
+ fs11.unlinkSync(filePath);
54517
54361
  sessionLogger.debug(`Cleaned up old session: ${file}`);
54518
54362
  }
54519
54363
  }
@@ -54521,7 +54365,7 @@ var SessionFileManager = class {
54521
54365
  };
54522
54366
 
54523
54367
  // src/files/ffmpeg-processor.ts
54524
- import * as fs13 from "node:fs";
54368
+ import * as fs12 from "node:fs";
54525
54369
  import * as path13 from "node:path";
54526
54370
  import { spawn } from "node:child_process";
54527
54371
  var FFmpegProcessor = class {
@@ -54535,17 +54379,17 @@ var FFmpegProcessor = class {
54535
54379
  // Detection
54536
54380
  // ============================================================================
54537
54381
  async checkAvailability() {
54538
- return new Promise((resolve6) => {
54382
+ return new Promise((resolve4) => {
54539
54383
  const proc = spawn(this.ffmpegPath, ["-version"]);
54540
- proc.on("error", () => resolve6(false));
54541
- proc.on("exit", (code) => resolve6(code === 0));
54384
+ proc.on("error", () => resolve4(false));
54385
+ proc.on("exit", (code) => resolve4(code === 0));
54542
54386
  });
54543
54387
  }
54544
54388
  // ============================================================================
54545
54389
  // Video Analysis
54546
54390
  // ============================================================================
54547
54391
  async analyzeVideo(videoPath) {
54548
- return new Promise((resolve6, reject) => {
54392
+ return new Promise((resolve4, reject) => {
54549
54393
  const args = [
54550
54394
  "-v",
54551
54395
  "error",
@@ -54574,7 +54418,7 @@ var FFmpegProcessor = class {
54574
54418
  }
54575
54419
  try {
54576
54420
  const info = this.parseProbeOutput(stdout, videoPath);
54577
- resolve6(info);
54421
+ resolve4(info);
54578
54422
  } catch (err) {
54579
54423
  reject(err);
54580
54424
  }
@@ -54657,7 +54501,7 @@ var FFmpegProcessor = class {
54657
54501
  onProgress?.(percent);
54658
54502
  }
54659
54503
  });
54660
- const outputStat = fs13.statSync(outputPath);
54504
+ const outputStat = fs12.statSync(outputPath);
54661
54505
  return {
54662
54506
  type: "video",
54663
54507
  output: outputPath,
@@ -54689,7 +54533,7 @@ var FFmpegProcessor = class {
54689
54533
  async extractKeyframes(inputPath, outputDir, info, opts, onProgress) {
54690
54534
  const interval = Math.floor(info.duration / opts.keyframeCount);
54691
54535
  const framesDir = path13.join(outputDir, `keyframes_${Date.now()}`);
54692
- fs13.mkdirSync(framesDir, { recursive: true });
54536
+ fs12.mkdirSync(framesDir, { recursive: true });
54693
54537
  const outputPattern = path13.join(framesDir, "frame_%03d.jpg");
54694
54538
  const args = [
54695
54539
  "-i",
@@ -54708,10 +54552,10 @@ var FFmpegProcessor = class {
54708
54552
  onProgress?.(percent);
54709
54553
  }
54710
54554
  });
54711
- let frames = fs13.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path13.join(framesDir, f));
54555
+ let frames = fs12.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path13.join(framesDir, f));
54712
54556
  if (frames.length < opts.keyframeCount / 2) {
54713
- fs13.rmSync(framesDir, { recursive: true, force: true });
54714
- fs13.mkdirSync(framesDir, { recursive: true });
54557
+ fs12.rmSync(framesDir, { recursive: true, force: true });
54558
+ fs12.mkdirSync(framesDir, { recursive: true });
54715
54559
  const uniformArgs = [
54716
54560
  "-i",
54717
54561
  inputPath,
@@ -54727,10 +54571,10 @@ var FFmpegProcessor = class {
54727
54571
  onProgress?.(percent);
54728
54572
  }
54729
54573
  });
54730
- frames = fs13.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path13.join(framesDir, f));
54574
+ frames = fs12.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path13.join(framesDir, f));
54731
54575
  }
54732
54576
  const totalOutputSize = frames.reduce(
54733
- (sum, f) => sum + fs13.statSync(f).size,
54577
+ (sum, f) => sum + fs12.statSync(f).size,
54734
54578
  0
54735
54579
  );
54736
54580
  return {
@@ -54769,7 +54613,7 @@ var FFmpegProcessor = class {
54769
54613
  // FFmpeg Execution
54770
54614
  // ============================================================================
54771
54615
  runFFmpeg(args) {
54772
- return new Promise((resolve6, reject) => {
54616
+ return new Promise((resolve4, reject) => {
54773
54617
  const proc = spawn(this.ffmpegPath, args);
54774
54618
  let stderr = "";
54775
54619
  proc.stderr.on("data", (data) => {
@@ -54784,7 +54628,7 @@ var FFmpegProcessor = class {
54784
54628
  )
54785
54629
  );
54786
54630
  } else {
54787
- resolve6();
54631
+ resolve4();
54788
54632
  }
54789
54633
  });
54790
54634
  proc.on("error", (err) => {
@@ -54801,7 +54645,7 @@ var FFmpegProcessor = class {
54801
54645
  // Progress Monitoring (for future use)
54802
54646
  // ============================================================================
54803
54647
  async runWithProgress(args, onProgress) {
54804
- return new Promise((resolve6, reject) => {
54648
+ return new Promise((resolve4, reject) => {
54805
54649
  const progressArgs = [
54806
54650
  ...args,
54807
54651
  "-progress",
@@ -54831,7 +54675,7 @@ var FFmpegProcessor = class {
54831
54675
  )
54832
54676
  );
54833
54677
  } else {
54834
- resolve6();
54678
+ resolve4();
54835
54679
  }
54836
54680
  });
54837
54681
  });
@@ -54950,8 +54794,8 @@ var FileManager = class {
54950
54794
  directoryListingCache = /* @__PURE__ */ new Map();
54951
54795
  authFingerprint;
54952
54796
  ensureDirectories() {
54953
- if (!fs14.existsSync(this.tempDir)) {
54954
- fs14.mkdirSync(this.tempDir, { recursive: true });
54797
+ if (!fs13.existsSync(this.tempDir)) {
54798
+ fs13.mkdirSync(this.tempDir, { recursive: true });
54955
54799
  }
54956
54800
  }
54957
54801
  // ============================================================================
@@ -54982,7 +54826,7 @@ var FileManager = class {
54982
54826
  async stageLocal(filePath, options = {}) {
54983
54827
  const resolvedPath = resolvePath(filePath);
54984
54828
  const sourceName = options.sourceName || path14.basename(resolvedPath);
54985
- if (!fs14.existsSync(resolvedPath)) {
54829
+ if (!fs13.existsSync(resolvedPath)) {
54986
54830
  throw new FileManagerError(
54987
54831
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
54988
54832
  `File not found: ${filePath}`
@@ -54997,7 +54841,7 @@ var FileManager = class {
54997
54841
  this.fileCache.rememberPathHint(resolvedPath, hash, sourceName);
54998
54842
  this.invalidateDirectoryListingCacheForPath(resolvedPath);
54999
54843
  const entry = this.fileCache.getByHash(hash);
55000
- const size = entry?.size ?? fs14.statSync(resolvedPath).size;
54844
+ const size = entry?.size ?? fs13.statSync(resolvedPath).size;
55001
54845
  return {
55002
54846
  success: true,
55003
54847
  hash,
@@ -55012,7 +54856,7 @@ var FileManager = class {
55012
54856
  async upload(filePath, options = {}) {
55013
54857
  const resolvedPath = resolvePath(filePath);
55014
54858
  const sourceName = options.sourceName || path14.basename(resolvedPath);
55015
- if (!fs14.existsSync(resolvedPath)) {
54859
+ if (!fs13.existsSync(resolvedPath)) {
55016
54860
  throw new FileManagerError(
55017
54861
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
55018
54862
  `File not found: ${filePath}`
@@ -55093,7 +54937,7 @@ var FileManager = class {
55093
54937
  // ============================================================================
55094
54938
  async uploadPic(filePath, options = {}) {
55095
54939
  const resolvedPath = resolvePath(filePath);
55096
- if (!fs14.existsSync(resolvedPath)) {
54940
+ if (!fs13.existsSync(resolvedPath)) {
55097
54941
  throw new FileManagerError(
55098
54942
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
55099
54943
  `File not found: ${filePath}`
@@ -55123,7 +54967,7 @@ var FileManager = class {
55123
54967
  this.fileCache.rememberPathHint(resolvedPath, result.hash, path14.basename(resolvedPath));
55124
54968
  this.invalidateDirectoryListingCacheForPath(resolvedPath);
55125
54969
  try {
55126
- fs14.unlinkSync(optimizedPath);
54970
+ fs13.unlinkSync(optimizedPath);
55127
54971
  } catch {
55128
54972
  }
55129
54973
  return result;
@@ -55133,7 +54977,7 @@ var FileManager = class {
55133
54977
  // ============================================================================
55134
54978
  async uploadVideo(filePath, options = {}) {
55135
54979
  const resolvedPath = resolvePath(filePath);
55136
- if (!fs14.existsSync(resolvedPath)) {
54980
+ if (!fs13.existsSync(resolvedPath)) {
55137
54981
  throw new FileManagerError(
55138
54982
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
55139
54983
  `File not found: ${filePath}`
@@ -55527,13 +55371,13 @@ var FileManager = class {
55527
55371
  cleanupTempFiles(output) {
55528
55372
  try {
55529
55373
  if (typeof output === "string") {
55530
- if (fs14.existsSync(output)) {
55531
- fs14.unlinkSync(output);
55374
+ if (fs13.existsSync(output)) {
55375
+ fs13.unlinkSync(output);
55532
55376
  }
55533
55377
  } else {
55534
55378
  for (const file of output) {
55535
- if (fs14.existsSync(file)) {
55536
- fs14.unlinkSync(file);
55379
+ if (fs13.existsSync(file)) {
55380
+ fs13.unlinkSync(file);
55537
55381
  }
55538
55382
  }
55539
55383
  }
@@ -55565,7 +55409,7 @@ var FileManager = class {
55565
55409
  }];
55566
55410
  }
55567
55411
  const localPath = this.fileCache.getLocalPath(entry.hash);
55568
- if (localPath && fs14.existsSync(localPath)) {
55412
+ if (localPath && fs13.existsSync(localPath)) {
55569
55413
  return [{
55570
55414
  fileId,
55571
55415
  name: cacheEntry.name,
@@ -55662,7 +55506,7 @@ var FileManager = class {
55662
55506
  directories: []
55663
55507
  };
55664
55508
  try {
55665
- const entries = fs14.readdirSync(resolvedDir, { withFileTypes: true });
55509
+ const entries = fs13.readdirSync(resolvedDir, { withFileTypes: true });
55666
55510
  for (const entry of entries) {
55667
55511
  if (!entry.name || entry.name.startsWith(".")) {
55668
55512
  continue;
@@ -55676,7 +55520,7 @@ var FileManager = class {
55676
55520
  let isFile = entry.isFile();
55677
55521
  if (entry.isSymbolicLink()) {
55678
55522
  try {
55679
- const targetStat = fs14.statSync(fullPath);
55523
+ const targetStat = fs13.statSync(fullPath);
55680
55524
  isDirectory = targetStat.isDirectory();
55681
55525
  isFile = targetStat.isFile();
55682
55526
  } catch {
@@ -55694,7 +55538,7 @@ var FileManager = class {
55694
55538
  if (!type) {
55695
55539
  continue;
55696
55540
  }
55697
- const stat2 = fs14.statSync(fullPath);
55541
+ const stat2 = fs13.statSync(fullPath);
55698
55542
  listing.files.push({
55699
55543
  name: entry.name,
55700
55544
  path: fullPath,
@@ -55793,7 +55637,7 @@ function isInlineMediaRequest(request) {
55793
55637
  return request.kind === "image" || request.kind === "video";
55794
55638
  }
55795
55639
  async function prepareInlineMediaContent(params) {
55796
- const stat2 = await fs15.stat(params.request.absolutePath);
55640
+ const stat2 = await fs14.stat(params.request.absolutePath);
55797
55641
  const limitMb = getCapabilityLimitMb(params.model, params.request.kind);
55798
55642
  const limitBytes = limitMb * 1024 * 1024;
55799
55643
  if (stat2.size > limitBytes) {
@@ -55801,7 +55645,7 @@ async function prepareInlineMediaContent(params) {
55801
55645
  `${params.request.kind} understanding for ${params.model.provider}/${params.model.id} supports inline files up to ${limitMb}MB; ${path15.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.`
55802
55646
  );
55803
55647
  }
55804
- const data = await fs15.readFile(params.request.absolutePath, "base64");
55648
+ const data = await fs14.readFile(params.request.absolutePath, "base64");
55805
55649
  const content = params.request.kind === "video" ? [{ type: "video", data, mimeType: params.request.mimeType }] : [{ type: "image", data, mimeType: params.request.mimeType }];
55806
55650
  return {
55807
55651
  content,
@@ -55821,7 +55665,7 @@ async function waitForReady(params) {
55821
55665
  if (status.status === "error" || status.status === "expired") {
55822
55666
  throw new Error(`Uploaded file is not ready: ${status.status}${status.error ? ` (${status.error})` : ""}`);
55823
55667
  }
55824
- await new Promise((resolve6) => setTimeout(resolve6, 1500));
55668
+ await new Promise((resolve4) => setTimeout(resolve4, 1500));
55825
55669
  }
55826
55670
  throw new Error("Timed out waiting for uploaded file to become ready");
55827
55671
  }
@@ -55957,7 +55801,7 @@ var ExecutionStateManager = class {
55957
55801
  case "aborted":
55958
55802
  return "Todo run aborted. Cleared the remaining todo list.";
55959
55803
  case "failed_turn":
55960
- return "Todo run failed during the latest turn. Cleared the remaining todo list.";
55804
+ return "Todo run failed during the latest turn. Preserved the todo list and paused automatic continuation.";
55961
55805
  case "max_attempts":
55962
55806
  return "Todo run reached the maximum follow-up attempts and was cleared as failed.";
55963
55807
  case "stagnated":
@@ -56075,6 +55919,18 @@ var ExecutionStateManager = class {
56075
55919
  return { changed: false };
56076
55920
  }
56077
55921
  const decision = evaluateTodoClosureAfterFailedTurn(previous.loop);
55922
+ if (decision.action === "pause_failed") {
55923
+ const paused = pauseExecutionState({
55924
+ ...previous,
55925
+ loop: decision.loop
55926
+ }, this.summarizeFailure(decision.reason));
55927
+ this.store.replace(paused);
55928
+ return {
55929
+ changed: true,
55930
+ terminalStatus: "paused",
55931
+ terminalSummary: paused.failureSummary || void 0
55932
+ };
55933
+ }
56078
55934
  if (decision.action === "clear_failed") {
56079
55935
  this.clearWithSummary(this.summarizeFailure(decision.reason));
56080
55936
  return {
@@ -56086,6 +55942,14 @@ var ExecutionStateManager = class {
56086
55942
  }
56087
55943
  return { changed: false };
56088
55944
  }
55945
+ resumePausedTodo() {
55946
+ const previous = this.store.read();
55947
+ if (previous.mode !== "todo" || previous.lifecycle !== "paused" || previous.steps.length === 0) {
55948
+ return { changed: false };
55949
+ }
55950
+ const next = this.store.replace(continueExecutionState(previous));
55951
+ return { changed: !this.unchanged(previous, next) };
55952
+ }
56089
55953
  markAwaitingContinuationStalled() {
56090
55954
  const previous = this.store.read();
56091
55955
  if (previous.mode !== "todo" || !previous.awaitingContinuation) {
@@ -56123,7 +55987,7 @@ var ExecutionStateManager = class {
56123
55987
  return null;
56124
55988
  }
56125
55989
  if (shouldPreserveExecutionStateForUserText(text)) {
56126
- if (state.lifecycle === "aborted") {
55990
+ if (state.lifecycle === "paused" || state.lifecycle === "aborted") {
56127
55991
  this.store.replace(continueExecutionState(state));
56128
55992
  return "continued";
56129
55993
  }
@@ -56151,7 +56015,7 @@ var ExecutionStateManager = class {
56151
56015
  };
56152
56016
 
56153
56017
  // src/session-trace.ts
56154
- import * as fs16 from "node:fs";
56018
+ import * as fs15 from "node:fs";
56155
56019
  import * as path16 from "node:path";
56156
56020
  var SessionTraceWriter = class extends SessionTraceSnapshotWriter {
56157
56021
  constructor(sessionsDir, sessionManager) {
@@ -56159,9 +56023,9 @@ var SessionTraceWriter = class extends SessionTraceSnapshotWriter {
56159
56023
  getSessionId: () => sessionManager.getActiveSessionId(),
56160
56024
  loadTrace: (sessionId) => {
56161
56025
  const tracePath = path16.join(sessionsDir, `${sessionId}.trace.json`);
56162
- if (!fs16.existsSync(tracePath)) return null;
56026
+ if (!fs15.existsSync(tracePath)) return null;
56163
56027
  try {
56164
- return JSON.parse(fs16.readFileSync(tracePath, "utf8"));
56028
+ return JSON.parse(fs15.readFileSync(tracePath, "utf8"));
56165
56029
  } catch {
56166
56030
  return null;
56167
56031
  }
@@ -56169,8 +56033,8 @@ var SessionTraceWriter = class extends SessionTraceSnapshotWriter {
56169
56033
  saveTrace: (trace) => {
56170
56034
  const tracePath = path16.join(sessionsDir, `${trace.sessionId}.trace.json`);
56171
56035
  const tempPath = `${tracePath}.tmp`;
56172
- fs16.writeFileSync(tempPath, JSON.stringify(trace, null, 2), "utf8");
56173
- fs16.renameSync(tempPath, tracePath);
56036
+ fs15.writeFileSync(tempPath, JSON.stringify(trace, null, 2), "utf8");
56037
+ fs15.renameSync(tempPath, tracePath);
56174
56038
  }
56175
56039
  });
56176
56040
  this.sessionsDir = sessionsDir;
@@ -56777,7 +56641,7 @@ async function handleCacheTest(host) {
56777
56641
  host.chatContainer.addChild(new Text(theme.fg("dim", ` ${summarizeUsage(result1.usage)}`), 1, 0));
56778
56642
  host.chatContainer.addChild(new Text(theme.fg("dim", " Waiting 2s before replaying identical request..."), 1, 0));
56779
56643
  host.ui.requestRender();
56780
- await new Promise((resolve6) => setTimeout(resolve6, 2e3));
56644
+ await new Promise((resolve4) => setTimeout(resolve4, 2e3));
56781
56645
  host.chatContainer.addChild(new Text(theme.fg("accent", "Request 2/2: replaying identical request..."), 1, 0));
56782
56646
  host.ui.requestRender();
56783
56647
  result2 = await completeSimple(model, context, options);
@@ -58860,7 +58724,7 @@ async function handleForkCommand(host) {
58860
58724
  }
58861
58725
 
58862
58726
  // src/commands/interactive-skill-commands.ts
58863
- import * as fs17 from "fs";
58727
+ import * as fs16 from "fs";
58864
58728
  import * as os3 from "os";
58865
58729
  import * as path17 from "path";
58866
58730
 
@@ -59204,7 +59068,7 @@ function expandSkillCommand(host, text) {
59204
59068
  const skill = host.skills.find((s) => s.name === skillName);
59205
59069
  if (!skill) return text;
59206
59070
  try {
59207
- const content = fs17.readFileSync(skill.filePath, "utf-8");
59071
+ const content = fs16.readFileSync(skill.filePath, "utf-8");
59208
59072
  const body = host.stripFrontmatter(content).trim();
59209
59073
  const skillBlock = `<skill name="${skill.name}" location="${skill.filePath}">
59210
59074
  References are relative to ${skill.baseDir}.
@@ -59274,13 +59138,13 @@ async function handleSkillsCreate(host, args) {
59274
59138
  const skillDir = path17.join(skillsDir, name);
59275
59139
  const skillFile = path17.join(skillDir, "SKILL.md");
59276
59140
  console.error(`[SkillsCreate] Creating at: ${skillFile}`);
59277
- if (fs17.existsSync(skillDir)) {
59141
+ if (fs16.existsSync(skillDir)) {
59278
59142
  host.showError(`Skill "${name}" already exists at ${skillDir}`);
59279
59143
  return;
59280
59144
  }
59281
- fs17.mkdirSync(skillDir, { recursive: true });
59145
+ fs16.mkdirSync(skillDir, { recursive: true });
59282
59146
  const template = createSkillTemplate(name, description);
59283
- fs17.writeFileSync(skillFile, template, "utf-8");
59147
+ fs16.writeFileSync(skillFile, template, "utf-8");
59284
59148
  console.error(`[SkillsCreate] Successfully created skill`);
59285
59149
  host.chatContainer.addChild(new Spacer(1));
59286
59150
  host.chatContainer.addChild(new Text(theme.fg("accent", `\u2713 Created skill: ${name}`), 1, 0));
@@ -60024,6 +59888,29 @@ async function handleCompactCommand(host) {
60024
59888
  }
60025
59889
  }
60026
59890
 
59891
+ // src/runtime/footer-lifecycle.ts
59892
+ function messageRole(event) {
59893
+ return String(event.message.role);
59894
+ }
59895
+ function formatFooterLifecycleEvent(event) {
59896
+ switch (event.type) {
59897
+ case "message_start":
59898
+ return `message_start(${messageRole(event)})`;
59899
+ case "message_end":
59900
+ return `message_end(${messageRole(event)})`;
59901
+ case "message_update":
59902
+ return event.message.role === "assistant" ? event.assistantMessageEvent.type : "message_update";
59903
+ case "tool_execution_start":
59904
+ return `tool_execution_start(${event.toolName})`;
59905
+ case "tool_execution_update":
59906
+ return `tool_execution_update(${event.toolName})`;
59907
+ case "tool_execution_end":
59908
+ return `tool_execution_end(${event.toolName})`;
59909
+ default:
59910
+ return event.type;
59911
+ }
59912
+ }
59913
+
60027
59914
  // src/runtime/interactive-runtime-events.ts
60028
59915
  function bindInteractiveRuntimeEvents(host) {
60029
59916
  host.agent.subscribe((event) => {
@@ -60046,7 +59933,7 @@ function bindInteractiveRuntimeEvents(host) {
60046
59933
  break;
60047
59934
  case "message_end":
60048
59935
  if (process.env.PIE_DEBUG_FOOTER) {
60049
- console.error(`[Footer Debug] message_end fired, setting status: ready`);
59936
+ console.error(`[Footer Debug] ${formatFooterLifecycleEvent(event)}`);
60050
59937
  }
60051
59938
  host.logDebug("message:end", { stopReason: event.message.role === "assistant" ? event.message.stopReason : void 0 });
60052
59939
  handleMessageEnd(host, event);
@@ -60248,7 +60135,7 @@ function handleMessageStart(host, event) {
60248
60135
  host.chatContainer.addChild(host.streamingComponent);
60249
60136
  host.sessionTrace.updateAssistantMessage(event.message);
60250
60137
  }
60251
- host.footer.setState({ lifecycleEvent: "message_start" });
60138
+ host.footer.setState({ lifecycleEvent: formatFooterLifecycleEvent(event) });
60252
60139
  host.emitExtensionEvent({ type: "message:start", message: event.message });
60253
60140
  host.safeRequestRender();
60254
60141
  }
@@ -60259,7 +60146,7 @@ function handleMessageUpdate(host, event) {
60259
60146
  host.pendingRender = true;
60260
60147
  return;
60261
60148
  }
60262
- host.footer.setState({ lifecycleEvent: "message_update" });
60149
+ host.footer.setState({ lifecycleEvent: formatFooterLifecycleEvent(event) });
60263
60150
  const message = event.message;
60264
60151
  let textContent = "";
60265
60152
  let thinkingContent = "";
@@ -60333,7 +60220,7 @@ function handleToolStart(host, event) {
60333
60220
  if (toolComponent) {
60334
60221
  }
60335
60222
  }
60336
- host.footer.setState({ lifecycleEvent: "tool_execution_start" });
60223
+ host.footer.setState({ lifecycleEvent: formatFooterLifecycleEvent(event) });
60337
60224
  host.emitExtensionEvent({
60338
60225
  type: "tool:execution:start",
60339
60226
  toolCallId: event.toolCallId,
@@ -60358,7 +60245,7 @@ function handleToolUpdate(host, event) {
60358
60245
  host.ui.requestRender();
60359
60246
  }
60360
60247
  }
60361
- host.footer.setState({ lifecycleEvent: "tool_execution_update" });
60248
+ host.footer.setState({ lifecycleEvent: formatFooterLifecycleEvent(event) });
60362
60249
  host.emitExtensionEvent({
60363
60250
  type: "tool:execution:update",
60364
60251
  toolCallId: event.toolCallId,
@@ -60391,7 +60278,7 @@ function handleToolEnd(host, event) {
60391
60278
  void host.refreshTodoWidget();
60392
60279
  }
60393
60280
  }
60394
- host.footer.setState({ lifecycleEvent: "tool_execution_end" });
60281
+ host.footer.setState({ lifecycleEvent: formatFooterLifecycleEvent(event) });
60395
60282
  host.emitExtensionEvent({
60396
60283
  type: "tool:execution:end",
60397
60284
  toolCallId: event.toolCallId,
@@ -60403,7 +60290,7 @@ function handleToolEnd(host, event) {
60403
60290
  }
60404
60291
  function handleMessageEnd(host, event) {
60405
60292
  host.streamingComponent = void 0;
60406
- host.footer.setState({ lifecycleEvent: "message_end" });
60293
+ host.footer.setState({ lifecycleEvent: formatFooterLifecycleEvent(event) });
60407
60294
  host.emitExtensionEvent({ type: "message:end", message: event.message });
60408
60295
  host.safeRequestRender();
60409
60296
  }
@@ -60668,7 +60555,7 @@ function setupInteractiveEditorSubmitHandler(host) {
60668
60555
  host.chatContainer.addChild(userMsg);
60669
60556
  host.editor.setText("");
60670
60557
  host.ui.requestRender();
60671
- await new Promise((resolve6) => setImmediate(resolve6));
60558
+ await new Promise((resolve4) => setImmediate(resolve4));
60672
60559
  let finalContent = messageContent;
60673
60560
  const reminderPrefix = host.executionReminder;
60674
60561
  const combinedPrefix = [reminderPrefix].filter((value) => Boolean(value)).join("");
@@ -60704,7 +60591,7 @@ function setupInteractiveEditorSubmitHandler(host) {
60704
60591
  }
60705
60592
 
60706
60593
  // src/input/interactive-file-pipeline.ts
60707
- import * as fs20 from "fs";
60594
+ import * as fs19 from "fs";
60708
60595
  import * as path20 from "path";
60709
60596
 
60710
60597
  // src/components/file-picker.ts
@@ -60926,7 +60813,7 @@ var FilePickerComponent = class extends Container {
60926
60813
  };
60927
60814
 
60928
60815
  // src/files/commands/file-commands.ts
60929
- import * as fs18 from "node:fs";
60816
+ import * as fs17 from "node:fs";
60930
60817
  import * as path18 from "node:path";
60931
60818
  var FileCommands = class {
60932
60819
  context;
@@ -60943,7 +60830,7 @@ var FileCommands = class {
60943
60830
  return;
60944
60831
  }
60945
60832
  const filePath = resolvePath(parsed.path);
60946
- if (!fs18.existsSync(filePath)) {
60833
+ if (!fs17.existsSync(filePath)) {
60947
60834
  this.context.showError(`File not found: ${parsed.path}`);
60948
60835
  return;
60949
60836
  }
@@ -60982,7 +60869,7 @@ var FileCommands = class {
60982
60869
  return;
60983
60870
  }
60984
60871
  const resolvedPath = resolvePath(filePath);
60985
- if (!fs18.existsSync(resolvedPath)) {
60872
+ if (!fs17.existsSync(resolvedPath)) {
60986
60873
  this.context.showError(`File not found: ${filePath}`);
60987
60874
  return;
60988
60875
  }
@@ -61013,7 +60900,7 @@ var FileCommands = class {
61013
60900
  return;
61014
60901
  }
61015
60902
  const resolvedPath = resolvePath(parsed.path);
61016
- if (!fs18.existsSync(resolvedPath)) {
60903
+ if (!fs17.existsSync(resolvedPath)) {
61017
60904
  this.context.showError(`File not found: ${parsed.path}`);
61018
60905
  return;
61019
60906
  }
@@ -61491,7 +61378,7 @@ var FileStatusMonitor = class {
61491
61378
  };
61492
61379
 
61493
61380
  // src/files/mention/mention-handler.ts
61494
- import * as fs19 from "node:fs";
61381
+ import * as fs18 from "node:fs";
61495
61382
  import * as path19 from "node:path";
61496
61383
  var MentionHandler = class {
61497
61384
  fileManager;
@@ -61861,8 +61748,8 @@ var MentionHandler = class {
61861
61748
  }
61862
61749
  if (this.isPath(query)) {
61863
61750
  const resolvedPath = resolvePath(query);
61864
- if (fs19.existsSync(resolvedPath)) {
61865
- const stats = fs19.statSync(resolvedPath);
61751
+ if (fs18.existsSync(resolvedPath)) {
61752
+ const stats = fs18.statSync(resolvedPath);
61866
61753
  if (stats.isFile()) {
61867
61754
  const type = FileCache.getFileTypeFromName(resolvedPath);
61868
61755
  const name = path19.basename(resolvedPath);
@@ -61886,7 +61773,7 @@ var MentionHandler = class {
61886
61773
  return void 0;
61887
61774
  }
61888
61775
  const queryPath = this.isPath(query) ? resolvePath(query) : void 0;
61889
- const filter = queryPath ? fs19.existsSync(queryPath) && fs19.statSync(queryPath).isDirectory() ? "" : path19.basename(queryPath) : query;
61776
+ const filter = queryPath ? fs18.existsSync(queryPath) && fs18.statSync(queryPath).isDirectory() ? "" : path19.basename(queryPath) : query;
61890
61777
  const entries = this.fileManager.listPathEntries(currentDir, filter);
61891
61778
  const options = [];
61892
61779
  const homeDir = process.env.HOME || "";
@@ -61927,7 +61814,7 @@ var MentionHandler = class {
61927
61814
  getBrowserDirectory(query = this.currentQuery) {
61928
61815
  if (this.isPath(query)) {
61929
61816
  const resolvedPath = resolvePath(query);
61930
- if (fs19.existsSync(resolvedPath) && fs19.statSync(resolvedPath).isDirectory()) {
61817
+ if (fs18.existsSync(resolvedPath) && fs18.statSync(resolvedPath).isDirectory()) {
61931
61818
  return resolvedPath;
61932
61819
  }
61933
61820
  return path19.dirname(resolvedPath);
@@ -62291,13 +62178,13 @@ function convertPreparedAttachmentItems(items) {
62291
62178
  break;
62292
62179
  case "image": {
62293
62180
  if (!item.data && !item.path) return void 0;
62294
- const data = item.data ?? fs20.readFileSync(item.path, "base64");
62181
+ const data = item.data ?? fs19.readFileSync(item.path, "base64");
62295
62182
  converted.push({ type: "image", data, mimeType: item.mimeType });
62296
62183
  break;
62297
62184
  }
62298
62185
  case "video": {
62299
62186
  if (!item.data && !item.path) return void 0;
62300
- const data = item.data ?? fs20.readFileSync(item.path, "base64");
62187
+ const data = item.data ?? fs19.readFileSync(item.path, "base64");
62301
62188
  converted.push({ type: "video", data, mimeType: item.mimeType });
62302
62189
  break;
62303
62190
  }
@@ -62688,6 +62575,7 @@ function buildCodingAgentGuidelinesSection(tools = []) {
62688
62575
  const hasGrep = toolNames.has("grep_text");
62689
62576
  const hasFind = toolNames.has("find_files");
62690
62577
  const hasBash = toolNames.has("bash");
62578
+ const hasWebResearch = toolNames.has("web_research");
62691
62579
  const hasWebSearch = toolNames.has("web_search");
62692
62580
  const hasWebFetch = toolNames.has("web_fetch");
62693
62581
  const hasCodeIntel = toolNames.has("code_intel");
@@ -62702,11 +62590,17 @@ function buildCodingAgentGuidelinesSection(tools = []) {
62702
62590
  if (hasGrep || hasFind || hasList) {
62703
62591
  guidelines.push("Prefer grep_text, find_files, and list_dir for workspace exploration when they are sufficient.");
62704
62592
  }
62705
- if (hasWebSearch) {
62593
+ if (hasWebResearch) {
62594
+ guidelines.push("Use web_research for general public web research, current information, official docs, news, releases, issues, or webpage summaries; it searches, fetches, and returns cited sources.");
62595
+ guidelines.push("When web_research returns fetched sources that answer the request, synthesize the answer from that pack instead of calling web_search or web_fetch again.");
62596
+ }
62597
+ if (hasWebSearch && !hasWebResearch) {
62706
62598
  guidelines.push("Use web_search for public web research and grep_text/find_files/list_dir for local workspace search.");
62707
62599
  }
62708
- if (hasWebFetch) {
62600
+ if (hasWebFetch && !hasWebResearch) {
62709
62601
  guidelines.push("After web_search identifies a public source, use web_fetch to read the chosen URL before relying on it; also use web_fetch for user-supplied URLs.");
62602
+ } else if (hasWebResearch && hasWebSearch && hasWebFetch) {
62603
+ guidelines.push("Use web_search and web_fetch directly only when you need low-level control over exact queries or URLs.");
62710
62604
  }
62711
62605
  if (hasCodeIntel) {
62712
62606
  guidelines.push("Use code_intel for JS/TS diagnostics, definitions, references, symbols, or hover when type or symbol information matters before editing.");
@@ -63537,8 +63431,21 @@ function createInteractiveAgentSessionController(host) {
63537
63431
  } else if (event.type === "retry_start") {
63538
63432
  host.showStatus(`Retrying request (attempt ${event.attempt}/${event.maxRetries})...`);
63539
63433
  } else if (event.type === "retry_succeeded") {
63434
+ const outcome = host.executionState.resumePausedTodo();
63435
+ if (outcome.changed) {
63436
+ host.sessionTrace.noteRuntimeEvent("todo_resumed_after_retry", {
63437
+ lifecycle: host.executionState.read().lifecycle,
63438
+ currentStepId: host.executionState.read().currentStepId
63439
+ });
63440
+ host.persistExecutionState();
63441
+ void host.refreshTodoWidget();
63442
+ }
63540
63443
  host.showStatus("Retry succeeded");
63541
63444
  } else if (event.type === "retry_exhausted") {
63445
+ const state = host.executionState.read();
63446
+ if (state.mode === "todo" && state.lifecycle === "paused" && state.steps.length > 0) {
63447
+ host.showStatus("Todo list preserved. Send 'continue' when you want to resume it.");
63448
+ }
63542
63449
  host.showError(`Request failed after ${event.maxRetries} retries: ${event.errorMessage}`);
63543
63450
  } else if (event.type === "runtime_guard_triggered") {
63544
63451
  host.sessionTrace.noteStalled("runtime_guard_triggered", {
@@ -63770,7 +63677,7 @@ async function handleDirectBash(host, command) {
63770
63677
  }
63771
63678
  host.ui.requestRender();
63772
63679
  });
63773
- return new Promise((resolve6) => {
63680
+ return new Promise((resolve4) => {
63774
63681
  child.on("close", (code) => {
63775
63682
  if (code !== 0) {
63776
63683
  outputContainer.addChild(new Spacer(1));
@@ -63778,7 +63685,7 @@ async function handleDirectBash(host, command) {
63778
63685
  }
63779
63686
  host.chatContainer.addChild(new Spacer(1));
63780
63687
  host.ui.requestRender();
63781
- resolve6();
63688
+ resolve4();
63782
63689
  });
63783
63690
  });
63784
63691
  }
@@ -63854,11 +63761,11 @@ function installInteractiveInteractionHandler(host) {
63854
63761
  if (!("timeoutMs" in request) || !request.timeoutMs || request.timeoutMs <= 0) {
63855
63762
  return { value: await promise, timedOut: false };
63856
63763
  }
63857
- return await new Promise((resolve6, reject) => {
63858
- const timer = setTimeout(() => resolve6({ timedOut: true }), request.timeoutMs);
63764
+ return await new Promise((resolve4, reject) => {
63765
+ const timer = setTimeout(() => resolve4({ timedOut: true }), request.timeoutMs);
63859
63766
  promise.then((value) => {
63860
63767
  clearTimeout(timer);
63861
- resolve6({ value, timedOut: false });
63768
+ resolve4({ value, timedOut: false });
63862
63769
  }).catch((error) => {
63863
63770
  clearTimeout(timer);
63864
63771
  reject(error);
@@ -63958,15 +63865,15 @@ function showExtensionNotification(host, message, type = "info") {
63958
63865
  host.ui.requestRender();
63959
63866
  }
63960
63867
  function showExtensionSelector(host, title, options, opts) {
63961
- return new Promise((resolve6) => {
63868
+ return new Promise((resolve4) => {
63962
63869
  host.showStatus(`Waiting for selection: ${title}`);
63963
63870
  if (opts?.signal?.aborted) {
63964
- resolve6(void 0);
63871
+ resolve4(void 0);
63965
63872
  return;
63966
63873
  }
63967
63874
  const onAbort = () => {
63968
63875
  host.restoreEditor();
63969
- resolve6(void 0);
63876
+ resolve4(void 0);
63970
63877
  };
63971
63878
  opts?.signal?.addEventListener("abort", onAbort, { once: true });
63972
63879
  const selector = new ExtensionSelectorComponent(
@@ -63975,12 +63882,12 @@ function showExtensionSelector(host, title, options, opts) {
63975
63882
  (option) => {
63976
63883
  opts?.signal?.removeEventListener("abort", onAbort);
63977
63884
  host.restoreEditor();
63978
- resolve6(option);
63885
+ resolve4(option);
63979
63886
  },
63980
63887
  () => {
63981
63888
  opts?.signal?.removeEventListener("abort", onAbort);
63982
63889
  host.restoreEditor();
63983
- resolve6(void 0);
63890
+ resolve4(void 0);
63984
63891
  }
63985
63892
  );
63986
63893
  host.editorContainer.clear();
@@ -63996,15 +63903,15 @@ ${message}`, ["Yes", "No"], opts);
63996
63903
  return result === "Yes";
63997
63904
  }
63998
63905
  function showExtensionInput(host, title, placeholder, opts) {
63999
- return new Promise((resolve6) => {
63906
+ return new Promise((resolve4) => {
64000
63907
  host.showStatus(`Waiting for input: ${title}`);
64001
63908
  if (opts?.signal?.aborted) {
64002
- resolve6(void 0);
63909
+ resolve4(void 0);
64003
63910
  return;
64004
63911
  }
64005
63912
  const onAbort = () => {
64006
63913
  host.restoreEditor();
64007
- resolve6(void 0);
63914
+ resolve4(void 0);
64008
63915
  };
64009
63916
  opts?.signal?.addEventListener("abort", onAbort, { once: true });
64010
63917
  const input = new ExtensionInputComponent(
@@ -64013,12 +63920,12 @@ function showExtensionInput(host, title, placeholder, opts) {
64013
63920
  (value) => {
64014
63921
  opts?.signal?.removeEventListener("abort", onAbort);
64015
63922
  host.restoreEditor();
64016
- resolve6(value);
63923
+ resolve4(value);
64017
63924
  },
64018
63925
  () => {
64019
63926
  opts?.signal?.removeEventListener("abort", onAbort);
64020
63927
  host.restoreEditor();
64021
- resolve6(void 0);
63928
+ resolve4(void 0);
64022
63929
  }
64023
63930
  );
64024
63931
  host.editorContainer.clear();
@@ -64029,7 +63936,7 @@ function showExtensionInput(host, title, placeholder, opts) {
64029
63936
  });
64030
63937
  }
64031
63938
  function showExtensionEditor(host, title, prefill) {
64032
- return new Promise((resolve6) => {
63939
+ return new Promise((resolve4) => {
64033
63940
  host.showStatus(`Waiting for input: ${title}`);
64034
63941
  const container = new Container();
64035
63942
  container.addChild(new Text(theme.bold(theme.fg("accent", title)), 0, 0));
@@ -64051,12 +63958,12 @@ function showExtensionEditor(host, title, prefill) {
64051
63958
  preview: value.slice(0, 120)
64052
63959
  });
64053
63960
  host.restoreEditor();
64054
- resolve6(value);
63961
+ resolve4(value);
64055
63962
  };
64056
63963
  editor.onEscape = () => {
64057
63964
  host.logDebug("extension:editor:cancel", { title });
64058
63965
  host.restoreEditor();
64059
- resolve6(void 0);
63966
+ resolve4(void 0);
64060
63967
  };
64061
63968
  container.addChild(editor);
64062
63969
  container.addChild(new Spacer(1));
@@ -64070,14 +63977,14 @@ function showExtensionEditor(host, title, prefill) {
64070
63977
  }
64071
63978
  function showExtensionCustom(host, factory, options) {
64072
63979
  const savedText = host.editor.getText();
64073
- return new Promise((resolve6, reject) => {
63980
+ return new Promise((resolve4, reject) => {
64074
63981
  let closed = false;
64075
63982
  const close = (result) => {
64076
63983
  if (closed) return;
64077
63984
  closed = true;
64078
63985
  host.restoreEditor();
64079
63986
  host.editor.setText(savedText);
64080
- resolve6(result);
63987
+ resolve4(result);
64081
63988
  };
64082
63989
  Promise.resolve(factory(host.ui, theme, close)).then((component) => {
64083
63990
  if (closed) return;
@@ -64151,7 +64058,7 @@ var AttachmentResolver = class {
64151
64058
  };
64152
64059
 
64153
64060
  // src/extensions/loader.ts
64154
- import * as fs21 from "node:fs";
64061
+ import * as fs20 from "node:fs";
64155
64062
  import * as os4 from "os";
64156
64063
  import * as path21 from "path";
64157
64064
  import { pathToFileURL } from "node:url";
@@ -64335,7 +64242,7 @@ function normalizeExtensionImportPath(extensionPath) {
64335
64242
  }
64336
64243
  async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, hasUI, actions) {
64337
64244
  const resolvedPath = resolvePath2(extensionPath, cwd);
64338
- if (!fs21.existsSync(resolvedPath)) {
64245
+ if (!fs20.existsSync(resolvedPath)) {
64339
64246
  return { extension: null, error: `Extension not found: ${extensionPath}` };
64340
64247
  }
64341
64248
  try {
@@ -64356,12 +64263,12 @@ async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, h
64356
64263
  }
64357
64264
  }
64358
64265
  function discoverExtensionsInDir(dir) {
64359
- if (!fs21.existsSync(dir)) {
64266
+ if (!fs20.existsSync(dir)) {
64360
64267
  return [];
64361
64268
  }
64362
64269
  const discovered = [];
64363
64270
  try {
64364
- const entries = fs21.readdirSync(dir, { withFileTypes: true });
64271
+ const entries = fs20.readdirSync(dir, { withFileTypes: true });
64365
64272
  for (const entry of entries) {
64366
64273
  const entryPath = path21.join(dir, entry.name);
64367
64274
  if (entry.isFile() && (entry.name.endsWith(".cjs") || entry.name.endsWith(".js") || entry.name.endsWith(".ts"))) {
@@ -64370,16 +64277,16 @@ function discoverExtensionsInDir(dir) {
64370
64277
  }
64371
64278
  if (entry.isDirectory()) {
64372
64279
  const packageJsonPath = path21.join(entryPath, "package.json");
64373
- if (fs21.existsSync(packageJsonPath)) {
64280
+ if (fs20.existsSync(packageJsonPath)) {
64374
64281
  try {
64375
- const pkg2 = JSON.parse(fs21.readFileSync(packageJsonPath, "utf-8"));
64376
- const manifest = pkg2.pie;
64282
+ const pkg = JSON.parse(fs20.readFileSync(packageJsonPath, "utf-8"));
64283
+ const manifest = pkg.pie;
64377
64284
  if (manifest?.main) {
64378
64285
  const mainPath = path21.resolve(entryPath, manifest.main);
64379
- if (fs21.existsSync(mainPath)) {
64286
+ if (fs20.existsSync(mainPath)) {
64380
64287
  discovered.push({
64381
64288
  entryPath: mainPath,
64382
- manifestName: manifest.name || pkg2.name
64289
+ manifestName: manifest.name || pkg.name
64383
64290
  });
64384
64291
  continue;
64385
64292
  }
@@ -64388,17 +64295,17 @@ function discoverExtensionsInDir(dir) {
64388
64295
  }
64389
64296
  }
64390
64297
  const indexCjs = path21.join(entryPath, "index.cjs");
64391
- if (fs21.existsSync(indexCjs)) {
64298
+ if (fs20.existsSync(indexCjs)) {
64392
64299
  discovered.push({ entryPath: indexCjs });
64393
64300
  continue;
64394
64301
  }
64395
64302
  const indexJs = path21.join(entryPath, "index.js");
64396
- if (fs21.existsSync(indexJs)) {
64303
+ if (fs20.existsSync(indexJs)) {
64397
64304
  discovered.push({ entryPath: indexJs });
64398
64305
  continue;
64399
64306
  }
64400
64307
  const indexTs = path21.join(entryPath, "index.ts");
64401
- if (fs21.existsSync(indexTs)) {
64308
+ if (fs20.existsSync(indexTs)) {
64402
64309
  discovered.push({ entryPath: indexTs });
64403
64310
  continue;
64404
64311
  }
@@ -64447,11 +64354,11 @@ async function loadExtensions(configuredPaths, cwd, uiContext, abortFn, isIdleFn
64447
64354
  }
64448
64355
  for (const p of configuredPaths) {
64449
64356
  const resolved = resolvePath2(p, cwd);
64450
- if (!fs21.existsSync(resolved)) {
64357
+ if (!fs20.existsSync(resolved)) {
64451
64358
  errors.push({ path: p, error: `Extension path not found: ${p}` });
64452
64359
  continue;
64453
64360
  }
64454
- if (!fs21.statSync(resolved).isDirectory()) {
64361
+ if (!fs20.statSync(resolved).isDirectory()) {
64455
64362
  errors.push({ path: p, error: `Extension path must be a directory: ${p}` });
64456
64363
  continue;
64457
64364
  }
@@ -65200,7 +65107,7 @@ var InteractiveMode = class {
65200
65107
  this.skills = options.skills;
65201
65108
  this.originalTools = [...options.tools];
65202
65109
  this.skillsSection = formatSkillsForPrompt(options.skills);
65203
- this.knowledgeSection = buildCliKnowledgeIndexSection(options.cwd);
65110
+ this.knowledgeSection = buildCliProjectContextSection(options.cwd);
65204
65111
  }
65205
65112
  options;
65206
65113
  get runtimeEventHost() {
@@ -65241,10 +65148,15 @@ var InteractiveMode = class {
65241
65148
  }
65242
65149
  rebuildSkillAwareTools(sourceTools) {
65243
65150
  const preservedTools = sourceTools.filter(
65244
- (tool) => !CLI_FILESYSTEM_TOOL_NAMES.includes(tool.name) && tool.name !== "read_skill" && tool.name !== "read_resource" && tool.name !== "resolve_resource"
65151
+ (tool) => !CLI_FILESYSTEM_TOOL_NAMES.includes(tool.name)
65245
65152
  );
65246
65153
  const fileSystemToolOptions = (allowlistedDirs) => ({
65247
- allowlistedDirs,
65154
+ ...buildCliFileAccessOptions({
65155
+ cwd: this.options.cwd,
65156
+ configDir: this.options.configDir,
65157
+ skills: this.skills,
65158
+ allowlistedDirs
65159
+ }),
65248
65160
  configDir: this.options.configDir,
65249
65161
  getAgentModel: () => this.options.model,
65250
65162
  getSessionId: () => this.sessionManager.getActiveSessionId() || void 0,
@@ -65257,9 +65169,6 @@ var InteractiveMode = class {
65257
65169
  });
65258
65170
  const normalFsTools = createCliFileSystemTools(this.options.cwd, fileSystemToolOptions([this.options.configDir]));
65259
65171
  const currentFsTools = this.yoloMode ? createCliFileSystemTools(this.options.cwd, fileSystemToolOptions(["/"])) : normalFsTools;
65260
- const readSkillTool = createCliReadSkillTool(this.skills);
65261
- const readResourceTool = createCliReadResourceTool(this.skills);
65262
- const resolveResourceTool = createCliResolveResourceTool(this.skills);
65263
65172
  const getPolicyContext = () => ({
65264
65173
  mode: this.planModeEnabled ? "plan" : "normal",
65265
65174
  yoloMode: this.yoloMode,
@@ -65267,11 +65176,11 @@ var InteractiveMode = class {
65267
65176
  });
65268
65177
  return {
65269
65178
  currentTools: createPolicyEnforcedTools(
65270
- [...currentFsTools, readSkillTool, readResourceTool, resolveResourceTool, ...preservedTools],
65179
+ [...currentFsTools, ...preservedTools],
65271
65180
  { getContext: getPolicyContext }
65272
65181
  ),
65273
65182
  originalTools: createPolicyEnforcedTools(
65274
- [...normalFsTools, readSkillTool, readResourceTool, resolveResourceTool, ...preservedTools],
65183
+ [...normalFsTools, ...preservedTools],
65275
65184
  { getContext: getPolicyContext }
65276
65185
  )
65277
65186
  };
@@ -65765,8 +65674,8 @@ function parseCliInvocation(args) {
65765
65674
  }
65766
65675
 
65767
65676
  // src/cli.ts
65768
- import { mkdirSync as mkdirSync12, existsSync as existsSync19 } from "fs";
65769
- import * as fs26 from "fs";
65677
+ import { mkdirSync as mkdirSync11, existsSync as existsSync17 } from "fs";
65678
+ import * as fs25 from "fs";
65770
65679
  import * as path25 from "path";
65771
65680
 
65772
65681
  // src/logging/runtime-logger.ts
@@ -65904,7 +65813,7 @@ var AuthStorage = class {
65904
65813
  };
65905
65814
 
65906
65815
  // src/core/settings-manager.ts
65907
- import * as fs22 from "fs";
65816
+ import * as fs21 from "fs";
65908
65817
  var SettingsManager = class {
65909
65818
  settingsPath;
65910
65819
  legacyConfigPath;
@@ -65918,9 +65827,9 @@ var SettingsManager = class {
65918
65827
  this.legacyConfig = this.loadLegacyConfigFile();
65919
65828
  }
65920
65829
  readJson(filePath) {
65921
- if (!fs22.existsSync(filePath)) return null;
65830
+ if (!fs21.existsSync(filePath)) return null;
65922
65831
  try {
65923
- return JSON.parse(fs22.readFileSync(filePath, "utf-8"));
65832
+ return JSON.parse(fs21.readFileSync(filePath, "utf-8"));
65924
65833
  } catch {
65925
65834
  return null;
65926
65835
  }
@@ -65932,15 +65841,15 @@ var SettingsManager = class {
65932
65841
  return this.readJson(this.legacyConfigPath) || {};
65933
65842
  }
65934
65843
  ensureDir() {
65935
- fs22.mkdirSync(getConfigDir(), { recursive: true });
65844
+ fs21.mkdirSync(getConfigDir(), { recursive: true });
65936
65845
  }
65937
65846
  writeSettings() {
65938
65847
  this.ensureDir();
65939
- fs22.writeFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2));
65848
+ fs21.writeFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2));
65940
65849
  }
65941
65850
  writeLegacyConfig() {
65942
65851
  this.ensureDir();
65943
- fs22.writeFileSync(this.legacyConfigPath, JSON.stringify(this.legacyConfig, null, 2));
65852
+ fs21.writeFileSync(this.legacyConfigPath, JSON.stringify(this.legacyConfig, null, 2));
65944
65853
  }
65945
65854
  getLegacyApiKey() {
65946
65855
  return this.legacyConfig.apiKey;
@@ -65992,7 +65901,7 @@ var SettingsManager = class {
65992
65901
  };
65993
65902
 
65994
65903
  // src/core/model-registry.ts
65995
- import * as fs23 from "fs";
65904
+ import * as fs22 from "fs";
65996
65905
  import * as path22 from "path";
65997
65906
  function validateProfileConfig(profileId, profileConfig) {
65998
65907
  const missing = [];
@@ -66055,11 +65964,11 @@ var ModelRegistry = class {
66055
65964
  this.modelOrder = [];
66056
65965
  this.configDefaults = void 0;
66057
65966
  this.usingExternalProviders = false;
66058
- if (!fs23.existsSync(this.modelsPath)) {
65967
+ if (!fs22.existsSync(this.modelsPath)) {
66059
65968
  return;
66060
65969
  }
66061
65970
  try {
66062
- const raw = JSON.parse(fs23.readFileSync(this.modelsPath, "utf-8"));
65971
+ const raw = JSON.parse(fs22.readFileSync(this.modelsPath, "utf-8"));
66063
65972
  if (raw && typeof raw === "object" && "providers" in raw) {
66064
65973
  throw new Error('Legacy models.json format is no longer supported. Use top-level "profiles".');
66065
65974
  }
@@ -66308,11 +66217,12 @@ var ModelRegistry = class {
66308
66217
  // src/doctor.ts
66309
66218
  import { spawnSync } from "node:child_process";
66310
66219
  import { createRequire } from "node:module";
66311
- import * as fs24 from "node:fs";
66220
+ import * as fs23 from "node:fs";
66312
66221
  import * as os5 from "node:os";
66313
66222
  import * as path23 from "node:path";
66314
66223
  import { delimiter } from "node:path";
66315
66224
  var require2 = createRequire(import.meta.url);
66225
+ var UNITY_INSTANCE_MAX_AGE_SEC = 120;
66316
66226
  function checkStatus(checks) {
66317
66227
  return {
66318
66228
  pass: checks.filter((check) => check.status === "pass").length,
@@ -66344,19 +66254,19 @@ function checkShell() {
66344
66254
  }
66345
66255
  function canWriteDirectory(dir) {
66346
66256
  try {
66347
- fs24.mkdirSync(dir, { recursive: true });
66257
+ fs23.mkdirSync(dir, { recursive: true });
66348
66258
  const probe = path23.join(dir, `.pie-doctor-${process.pid}-${Date.now()}`);
66349
- fs24.writeFileSync(probe, "ok", "utf8");
66350
- fs24.rmSync(probe, { force: true });
66259
+ fs23.writeFileSync(probe, "ok", "utf8");
66260
+ fs23.rmSync(probe, { force: true });
66351
66261
  return { ok: true };
66352
66262
  } catch (error) {
66353
66263
  return { ok: false, error: error instanceof Error ? error.message : String(error) };
66354
66264
  }
66355
66265
  }
66356
66266
  function isExecutable(candidate) {
66357
- if (!candidate || !fs24.existsSync(candidate)) return false;
66267
+ if (!candidate || !fs23.existsSync(candidate)) return false;
66358
66268
  try {
66359
- fs24.accessSync(candidate, fs24.constants.X_OK);
66269
+ fs23.accessSync(candidate, fs23.constants.X_OK);
66360
66270
  return true;
66361
66271
  } catch {
66362
66272
  return os5.platform() === "win32";
@@ -66434,7 +66344,7 @@ function checkPlaywrightBrowser() {
66434
66344
  } catch {
66435
66345
  executablePath = void 0;
66436
66346
  }
66437
- if (executablePath && fs24.existsSync(executablePath)) {
66347
+ if (executablePath && fs23.existsSync(executablePath)) {
66438
66348
  return {
66439
66349
  id: "playwright_browser",
66440
66350
  label: "Playwright browser",
@@ -66452,37 +66362,98 @@ function checkPlaywrightBrowser() {
66452
66362
  details: { expectedExecutablePath: executablePath, skillWrapper }
66453
66363
  };
66454
66364
  }
66365
+ function isRecord2(value) {
66366
+ return !!value && typeof value === "object" && !Array.isArray(value);
66367
+ }
66368
+ function hasRequiredUnityIdentityFields(instance) {
66369
+ return typeof instance.instanceId === "string" && instance.instanceId.trim().length > 0 && typeof instance.projectPath === "string" && instance.projectPath.trim().length > 0 && Number(instance.port || 0) > 0 && Number(instance.pid || 0) > 0 && Number(instance.lastSeenUnix || 0) > 0;
66370
+ }
66371
+ function isProcessAlive(pid) {
66372
+ if (!Number.isInteger(pid) || pid <= 0) return false;
66373
+ try {
66374
+ process.kill(pid, 0);
66375
+ return true;
66376
+ } catch (error) {
66377
+ return error?.code === "EPERM";
66378
+ }
66379
+ }
66380
+ function isLiveUnityInstance(instance, nowUnix = Math.floor(Date.now() / 1e3)) {
66381
+ if (!hasRequiredUnityIdentityFields(instance)) return false;
66382
+ const lastSeenUnix = Number(instance.lastSeenUnix || 0);
66383
+ if (nowUnix - lastSeenUnix > UNITY_INSTANCE_MAX_AGE_SEC) return false;
66384
+ return isProcessAlive(Number(instance.pid || 0));
66385
+ }
66455
66386
  function checkUnityRegistry() {
66456
- const registryPath = path23.join(os5.homedir(), ".pie-unity", "registry.json");
66457
- if (!fs24.existsSync(registryPath)) {
66387
+ const registryDir = path23.join(os5.homedir(), ".pie-unity", "instances");
66388
+ if (!fs23.existsSync(registryDir)) {
66458
66389
  return {
66459
66390
  id: "unity_bridge",
66460
66391
  label: "Unity bridge",
66461
66392
  status: "warn",
66462
- message: "No pie-unity registry found. This is fine unless you plan to control Unity from Pie.",
66463
- details: { registryPath }
66393
+ message: "No pie-unity instance registry directory found. This is fine unless you plan to control Unity from Pie.",
66394
+ details: { registryDir }
66464
66395
  };
66465
66396
  }
66466
66397
  try {
66467
- const raw = JSON.parse(fs24.readFileSync(registryPath, "utf8"));
66468
- const instances = Array.isArray(raw?.instances) ? raw.instances : [];
66398
+ const nowUnix = Math.floor(Date.now() / 1e3);
66399
+ const files = fs23.readdirSync(registryDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => path23.join(registryDir, entry.name));
66400
+ let malformedFiles = 0;
66401
+ let invalidFiles = 0;
66402
+ const liveInstances = files.map((filePath) => {
66403
+ try {
66404
+ const parsed = JSON.parse(fs23.readFileSync(filePath, "utf8").replace(/^\uFEFF/, ""));
66405
+ if (!isRecord2(parsed)) {
66406
+ invalidFiles += 1;
66407
+ return null;
66408
+ }
66409
+ if (!isLiveUnityInstance(parsed, nowUnix)) {
66410
+ invalidFiles += 1;
66411
+ return null;
66412
+ }
66413
+ return parsed;
66414
+ } catch {
66415
+ malformedFiles += 1;
66416
+ return null;
66417
+ }
66418
+ }).filter((item) => Boolean(item));
66469
66419
  return {
66470
66420
  id: "unity_bridge",
66471
66421
  label: "Unity bridge",
66472
- status: instances.length > 0 ? "pass" : "warn",
66473
- message: instances.length > 0 ? `Found ${instances.length} registered pie-unity instance(s).` : "pie-unity registry exists but has no instances.",
66474
- details: { registryPath, instances: instances.length }
66422
+ status: liveInstances.length > 0 ? "pass" : "warn",
66423
+ message: liveInstances.length > 0 ? `Found ${liveInstances.length} live pie-unity instance(s).` : "pie-unity instance registry directory exists but has no live readable instances.",
66424
+ details: {
66425
+ registryDir,
66426
+ liveInstances: liveInstances.length,
66427
+ totalFiles: files.length,
66428
+ malformedFiles,
66429
+ invalidOrStaleFiles: invalidFiles
66430
+ }
66475
66431
  };
66476
66432
  } catch (error) {
66477
66433
  return {
66478
66434
  id: "unity_bridge",
66479
66435
  label: "Unity bridge",
66480
66436
  status: "warn",
66481
- message: `Could not read pie-unity registry: ${error instanceof Error ? error.message : String(error)}`,
66482
- details: { registryPath }
66437
+ message: `Could not read pie-unity instance registry directory: ${error instanceof Error ? error.message : String(error)}`,
66438
+ details: { registryDir }
66483
66439
  };
66484
66440
  }
66485
66441
  }
66442
+ function checkPieUnityRpcSkill() {
66443
+ return {
66444
+ id: "pie_unity_rpc_skill",
66445
+ label: "Pie Unity RPC skill",
66446
+ status: "pass",
66447
+ message: "pie-unity-rpc is package-contained. Use the helper from the current Unity project's resolved com.pie.agent package.",
66448
+ details: {
66449
+ lookupOrder: [
66450
+ "Packages/com.pie.agent/Skills/pie-unity-rpc",
66451
+ "Library/PackageCache/com.pie.agent@*/Skills/pie-unity-rpc",
66452
+ "Library/PackageCache/com.pie.agent*/Skills/pie-unity-rpc"
66453
+ ]
66454
+ }
66455
+ };
66456
+ }
66486
66457
  async function runDoctor() {
66487
66458
  const checks = [];
66488
66459
  const settings = new SettingsManager();
@@ -66506,7 +66477,7 @@ async function runDoctor() {
66506
66477
  let lockPath;
66507
66478
  while (dir !== path23.dirname(dir)) {
66508
66479
  const candidate = path23.join(dir, "package-lock.json");
66509
- if (fs24.existsSync(candidate)) {
66480
+ if (fs23.existsSync(candidate)) {
66510
66481
  lockPath = candidate;
66511
66482
  break;
66512
66483
  }
@@ -66571,6 +66542,26 @@ async function runDoctor() {
66571
66542
  preferredWebSearchCapability: webSearchCandidates[0]?.model?.webSearch?.type
66572
66543
  }
66573
66544
  });
66545
+ const webResearchHealth = createCliWebResearchHealthStore(getConfigDir()).loadProviderHealth();
66546
+ checks.push({
66547
+ id: "web_research_health",
66548
+ label: "Web research provider health",
66549
+ status: webResearchHealth.length > 0 ? "pass" : "warn",
66550
+ message: webResearchHealth.length > 0 ? `Loaded health for ${webResearchHealth.length} web research route(s).` : "No web research provider health has been recorded yet. Run verify:web or use web_research once to populate route quality data.",
66551
+ details: {
66552
+ routes: webResearchHealth.slice(0, 8).map((entry) => ({
66553
+ routeKey: entry.routeKey,
66554
+ attempts: entry.attempts,
66555
+ successRate: entry.attempts ? entry.successes / entry.attempts : 0,
66556
+ lowQualityRate: entry.attempts ? entry.lowQuality / entry.attempts : 0,
66557
+ rateLimited: entry.rateLimited,
66558
+ timeouts: entry.timeouts,
66559
+ averageLatencyMs: entry.attempts ? Math.round(entry.totalDurationMs / entry.attempts) : 0,
66560
+ averageSourceCount: entry.attempts ? entry.totalSources / entry.attempts : 0,
66561
+ updatedAt: entry.updatedAt
66562
+ }))
66563
+ }
66564
+ });
66574
66565
  checks.push({
66575
66566
  id: "tool_model_routes",
66576
66567
  label: "Tool model routes",
@@ -66596,6 +66587,7 @@ async function runDoctor() {
66596
66587
  checks.push(checkPlaywrightCli());
66597
66588
  checks.push(checkPlaywrightBrowser());
66598
66589
  checks.push(checkUnityRegistry());
66590
+ checks.push(checkPieUnityRpcSkill());
66599
66591
  const runtimeLog = getRuntimeLogPath();
66600
66592
  checks.push({
66601
66593
  id: "runtime_log",
@@ -66652,7 +66644,7 @@ Disable or narrow capabilities:
66652
66644
  }
66653
66645
 
66654
66646
  // src/commands/models-config.ts
66655
- import * as fs25 from "node:fs";
66647
+ import * as fs24 from "node:fs";
66656
66648
  import * as path24 from "node:path";
66657
66649
  function getDefaultModelsPath() {
66658
66650
  return path24.join(getConfigDir(), "models.json");
@@ -66758,16 +66750,16 @@ function initModelsConfig(options = {}) {
66758
66750
  if (options.stdout) {
66759
66751
  return { path: targetPath, content, wrote: false };
66760
66752
  }
66761
- if (fs25.existsSync(targetPath) && !options.force) {
66753
+ if (fs24.existsSync(targetPath) && !options.force) {
66762
66754
  throw new Error(`models.json already exists: ${targetPath}. Use --force to overwrite, or --stdout to print the template.`);
66763
66755
  }
66764
- fs25.mkdirSync(path24.dirname(targetPath), { recursive: true });
66765
- fs25.writeFileSync(targetPath, content, "utf8");
66756
+ fs24.mkdirSync(path24.dirname(targetPath), { recursive: true });
66757
+ fs24.writeFileSync(targetPath, content, "utf8");
66766
66758
  return { path: targetPath, content, wrote: true };
66767
66759
  }
66768
66760
  function validateModelsConfig(options = {}) {
66769
66761
  const modelsPath = resolveModelsPath(options.path);
66770
- if (!fs25.existsSync(modelsPath)) {
66762
+ if (!fs24.existsSync(modelsPath)) {
66771
66763
  return {
66772
66764
  ok: false,
66773
66765
  path: modelsPath,
@@ -66822,6 +66814,73 @@ function validateModelsConfig(options = {}) {
66822
66814
  toolModelRoutes
66823
66815
  };
66824
66816
  }
66817
+ async function probeModelsConfig(options) {
66818
+ const registry = new ModelRegistry(new AuthStorage(), resolveModelsPath(options.path));
66819
+ const loadError = registry.getLoadError();
66820
+ if (loadError) {
66821
+ return {
66822
+ purpose: options.probe,
66823
+ status: "failed",
66824
+ attempts: [],
66825
+ message: `Cannot probe invalid models.json: ${loadError}`
66826
+ };
66827
+ }
66828
+ if (options.probe !== "web_search") {
66829
+ return {
66830
+ purpose: options.probe,
66831
+ status: "skipped",
66832
+ attempts: [],
66833
+ message: `Unsupported probe: ${options.probe}`
66834
+ };
66835
+ }
66836
+ const candidates = registry.resolveToolModelCandidates("web_search").filter((route) => route.model);
66837
+ if (candidates.length === 0) {
66838
+ return {
66839
+ purpose: options.probe,
66840
+ status: "failed",
66841
+ attempts: [],
66842
+ message: "No configured model declares webSearch capability."
66843
+ };
66844
+ }
66845
+ const attempts = [];
66846
+ for (const candidate of candidates.slice(0, 3)) {
66847
+ const route = `${candidate.model?.provider}/${candidate.model?.id}:${candidate.model?.webSearch?.type}:${candidate.routeSource}`;
66848
+ const tool = createSharedWebSearchTool({
66849
+ getModel: () => candidate.model,
66850
+ getApiKey: () => candidate.apiKey,
66851
+ getMode: () => "live",
66852
+ resolveToolModelCandidates: () => [candidate]
66853
+ });
66854
+ try {
66855
+ const result = await tool.execute("models_probe_web_search", { query: "Pie web search capability probe current official source" });
66856
+ const details = result.details;
66857
+ attempts.push({
66858
+ route,
66859
+ status: result.isError ? "failed" : "passed",
66860
+ sourceCount: Number(details?.sourceCount || 0),
66861
+ failureCategory: details?.failureCategory,
66862
+ durationSeconds: details?.durationSeconds,
66863
+ message: result.content.find((item) => item.type === "text")?.text?.slice(0, 240)
66864
+ });
66865
+ if (!result.isError && Number(details?.sourceCount || 0) > 0) break;
66866
+ } catch (error) {
66867
+ attempts.push({
66868
+ route,
66869
+ status: "failed",
66870
+ sourceCount: 0,
66871
+ failureCategory: "provider_compat",
66872
+ message: error instanceof Error ? error.message : String(error)
66873
+ });
66874
+ }
66875
+ }
66876
+ const passed = attempts.some((attempt) => attempt.status === "passed" && attempt.sourceCount > 0);
66877
+ return {
66878
+ purpose: options.probe,
66879
+ status: passed ? "passed" : "failed",
66880
+ attempts,
66881
+ message: passed ? `web_search probe passed using ${attempts.find((attempt) => attempt.status === "passed")?.route}.` : "web_search probe failed for all configured candidate routes."
66882
+ };
66883
+ }
66825
66884
  function parseModelsCommandArgs(args) {
66826
66885
  const parsed = { force: false, stdout: false };
66827
66886
  for (let i = 0; i < args.length; i += 1) {
@@ -66830,6 +66889,12 @@ function parseModelsCommandArgs(args) {
66830
66889
  parsed.force = true;
66831
66890
  } else if (arg === "--stdout") {
66832
66891
  parsed.stdout = true;
66892
+ } else if (arg === "--probe" && args[i + 1]) {
66893
+ parsed.probe = args[i + 1] === "web_search" ? "web_search" : void 0;
66894
+ i += 1;
66895
+ } else if (arg.startsWith("--probe=")) {
66896
+ const value = arg.slice("--probe=".length);
66897
+ parsed.probe = value === "web_search" ? "web_search" : void 0;
66833
66898
  } else if (arg === "--path" && args[i + 1]) {
66834
66899
  parsed.path = args[i + 1];
66835
66900
  i += 1;
@@ -66846,8 +66911,8 @@ var logError = (msg, err) => {
66846
66911
  const logPath = getRuntimeLogPath();
66847
66912
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
66848
66913
  const stack = err instanceof Error ? err.stack || "" : "";
66849
- fs26.mkdirSync(path25.dirname(logPath), { recursive: true });
66850
- fs26.appendFileSync(logPath, `[${timestamp}] ${msg}
66914
+ fs25.mkdirSync(path25.dirname(logPath), { recursive: true });
66915
+ fs25.appendFileSync(logPath, `[${timestamp}] ${msg}
66851
66916
  ${stack}
66852
66917
 
66853
66918
  `);
@@ -66860,8 +66925,8 @@ var SKILLS_DIR = path25.join(CONFIG_DIR, "skills");
66860
66925
  var BUILTIN_DIR = getBuiltinDir();
66861
66926
  var BUILTIN_SKILLS_DIR = path25.join(BUILTIN_DIR, "skills");
66862
66927
  var BUILTIN_EXTENSIONS_DIR = path25.join(BUILTIN_DIR, "extensions");
66863
- if (!existsSync19(SKILLS_DIR)) {
66864
- mkdirSync12(SKILLS_DIR, { recursive: true });
66928
+ if (!existsSync17(SKILLS_DIR)) {
66929
+ mkdirSync11(SKILLS_DIR, { recursive: true });
66865
66930
  }
66866
66931
  function maskApiKey2(key) {
66867
66932
  if (key.length <= 6) return "***";
@@ -66916,7 +66981,7 @@ async function runDoctorCommand(args) {
66916
66981
  process.exitCode = 1;
66917
66982
  }
66918
66983
  }
66919
- function runModelsCommand(args) {
66984
+ async function runModelsCommand(args) {
66920
66985
  const subcommand = args[0] || "help";
66921
66986
  const parsed = parseModelsCommandArgs(args.slice(1));
66922
66987
  if (subcommand === "init") {
@@ -66958,11 +67023,19 @@ function runModelsCommand(args) {
66958
67023
  if (result.toolModelRoutes && result.toolModelRoutes.length > 0) {
66959
67024
  console.log(`Tool model routes: ${result.toolModelRoutes.join(", ")}`);
66960
67025
  }
67026
+ if (parsed.probe) {
67027
+ const probe = await probeModelsConfig({ path: parsed.path, probe: parsed.probe });
67028
+ console.log(`Probe ${probe.purpose}: ${probe.message}`);
67029
+ for (const attempt of probe.attempts) {
67030
+ console.log(`- ${attempt.status} ${attempt.route} sources=${attempt.sourceCount}${attempt.failureCategory ? ` failure=${attempt.failureCategory}` : ""}`);
67031
+ }
67032
+ if (probe.status === "failed") process.exitCode = 1;
67033
+ }
66961
67034
  return;
66962
67035
  }
66963
67036
  console.log(`Usage:
66964
67037
  pie models init [--path <path>] [--force] [--stdout]
66965
- pie models validate [--path <path>]`);
67038
+ pie models validate [--path <path>] [--probe web_search]`);
66966
67039
  }
66967
67040
  function createNoOpExtensionUIContext() {
66968
67041
  return {
@@ -67174,24 +67247,19 @@ async function startChat(initialPrompt, testCommand) {
67174
67247
  getApiKey: () => interactiveOptions?.apiKey ?? apiKey,
67175
67248
  getWebSearchMode: () => settingsManager.getWebSearchMode(),
67176
67249
  resolveToolModel: (purpose) => modelRegistry.resolveToolModel(purpose, interactiveOptions?.model ?? model),
67177
- resolveToolModelCandidates: (purpose) => modelRegistry.resolveToolModelCandidates(purpose, interactiveOptions?.model ?? model)
67250
+ resolveToolModelCandidates: (purpose) => modelRegistry.resolveToolModelCandidates(purpose, interactiveOptions?.model ?? model),
67251
+ configDir: CONFIG_DIR
67178
67252
  });
67179
67253
  const fileSystemToolOptions = {
67180
- allowlistedDirs: [CONFIG_DIR],
67254
+ ...buildCliFileAccessOptions({ cwd, configDir: CONFIG_DIR, skills, allowlistedDirs: [CONFIG_DIR] }),
67181
67255
  configDir: CONFIG_DIR,
67182
67256
  getAgentModel: () => interactiveOptions?.model ?? model,
67183
67257
  getSessionId: () => sessionManager.getActiveSessionId() || void 0,
67184
67258
  resolveToolModel: (purpose) => modelRegistry.resolveToolModel(purpose, interactiveOptions?.model ?? model),
67185
67259
  getPolicyContext: () => ({ mode: "normal", confirmationPolicy: "allow" })
67186
67260
  };
67187
- const readSkillTool = createCliReadSkillTool(skills);
67188
- const readResourceTool = createCliReadResourceTool(skills);
67189
- const resolveResourceTool = createCliResolveResourceTool(skills);
67190
67261
  const tools = createPolicyEnforcedTools([
67191
67262
  ...createCliFileSystemTools(cwd, fileSystemToolOptions),
67192
- readSkillTool,
67193
- readResourceTool,
67194
- resolveResourceTool,
67195
67263
  ...cliHostCapabilities.tools
67196
67264
  ], {
67197
67265
  getContext: () => ({ mode: "normal", confirmationPolicy: "allow" })
@@ -67201,7 +67269,7 @@ async function startChat(initialPrompt, testCommand) {
67201
67269
  console.log(`[CLI] ${diag.message}`);
67202
67270
  }
67203
67271
  const skillsSection = formatSkillsForPrompt(skills);
67204
- const knowledgeSection = buildCliKnowledgeIndexSection(cwd);
67272
+ const knowledgeSection = buildCliProjectContextSection(cwd);
67205
67273
  if (initialPrompt) {
67206
67274
  if (initialModel.unconfigured) {
67207
67275
  const errorText = initialModel.warning || "No models are configured. Add one in ~/.pie/models.json before sending messages.";
@@ -67353,9 +67421,9 @@ async function startChat(initialPrompt, testCommand) {
67353
67421
  flushEarlyLogs();
67354
67422
  if (testCommand) {
67355
67423
  console.log(`[TEST] Auto-executing command: ${testCommand}`);
67356
- await new Promise((resolve6) => setTimeout(resolve6, 500));
67424
+ await new Promise((resolve4) => setTimeout(resolve4, 500));
67357
67425
  await interactive.executeCommand(testCommand);
67358
- await new Promise((resolve6) => setTimeout(resolve6, 2e3));
67426
+ await new Promise((resolve4) => setTimeout(resolve4, 2e3));
67359
67427
  console.log("[TEST] Command executed, exiting...");
67360
67428
  process.exit(0);
67361
67429
  return;
@@ -67378,7 +67446,7 @@ async function main() {
67378
67446
  }
67379
67447
  if (args[0] === "models") {
67380
67448
  try {
67381
- runModelsCommand(args.slice(1));
67449
+ await runModelsCommand(args.slice(1));
67382
67450
  } catch (error) {
67383
67451
  console.error(error instanceof Error ? error.message : String(error));
67384
67452
  process.exitCode = 1;