@cortexkit/aft-pi 0.30.3 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/config.d.ts CHANGED
@@ -107,7 +107,7 @@ export interface AftConfig {
107
107
  semantic?: SemanticConfig;
108
108
  /**
109
109
  * Maximum source files allowed for call-graph operations (callers, trace_to,
110
- * trace_data, impact). Projects above this size return `project_too_large`.
110
+ * trace_to_symbol, trace_data, impact). Projects above this size return `project_too_large`.
111
111
  * Default: 20000 (applied Rust-side; undefined here means "use default").
112
112
  */
113
113
  max_callgraph_files?: number;
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@
17
17
  * - aft_outline Structural outline (symbols, headings) for files/URLs
18
18
  * - aft_zoom Symbol-level inspection with call-graph annotations
19
19
  * - aft_search Semantic search (when semantic_search=true)
20
- * - aft_navigate Call-graph navigation (callers, call_tree, impact, trace_to, trace_data)
20
+ * - aft_navigate Call-graph navigation (callers, call_tree, impact, trace_to, trace_to_symbol, trace_data)
21
21
  * - aft_conflicts One-call merge conflict inspection
22
22
  * - aft_import Language-aware import add/remove/organize
23
23
  * - aft_safety Per-file undo, checkpoints, restore
@@ -61,6 +61,7 @@ declare function resolveToolSurface(config: ReturnType<typeof loadAftConfig>): {
61
61
  hoistWrite: boolean;
62
62
  hoistEdit: boolean;
63
63
  hoistGrep: boolean;
64
+ restrictToProjectRoot: boolean;
64
65
  outline: boolean;
65
66
  zoom: boolean;
66
67
  semantic: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAcH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AASpE,OAAO,EACL,KAAK,SAAS,EACd,aAAa,EAId,MAAM,aAAa,CAAC;AA6DrB,KAAK,mBAAmB,GAAG;IACzB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9C,CAAC;AAEF,iBAAS,4BAA4B,CACnC,OAAO,EAAE,MAAM,mBAAmB,GAAG,SAAS,EAC9C,sBAAsB,GAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAgB,IAOrE,eAAe,MAAM,EAAE,YAAY,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyCjF;AA6DD,iBAAS,wBAAwB,CAC/B,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,iBAAiB,GAAG,UAAU,CAAC,GACtD,OAAO,CAGT;AAED,iBAAS,2BAA2B,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG9E;AASD,iBAAe,iCAAiC,CAAC,OAAO,EAAE;IACxD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC,OAAO,uBAAuB,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IACnE,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiChB;AAED;;;;;;;;GAQG;AACH,iBAAS,kBAAkB,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,GAAG;IACrE,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAiEA;AAED;;;;GAIG;AACH,yBAA+B,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAkc9D;AAED,eAAO,MAAM,QAAQ;;;;;;CAMpB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAcH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AASpE,OAAO,EACL,KAAK,SAAS,EACd,aAAa,EAId,MAAM,aAAa,CAAC;AA6DrB,KAAK,mBAAmB,GAAG;IACzB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9C,CAAC;AAEF,iBAAS,4BAA4B,CACnC,OAAO,EAAE,MAAM,mBAAmB,GAAG,SAAS,EAC9C,sBAAsB,GAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAgB,IAOrE,eAAe,MAAM,EAAE,YAAY,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyCjF;AA6DD,iBAAS,wBAAwB,CAC/B,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,iBAAiB,GAAG,UAAU,CAAC,GACtD,OAAO,CAGT;AAED,iBAAS,2BAA2B,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG9E;AASD,iBAAe,iCAAiC,CAAC,OAAO,EAAE;IACxD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC,OAAO,uBAAuB,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IACnE,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiChB;AAED;;;;;;;;GAQG;AACH,iBAAS,kBAAkB,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,GAAG;IACrE,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAwEA;AAED;;;;GAIG;AACH,yBAA+B,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAkc9D;AAED,eAAO,MAAM,QAAQ;;;;;;CAMpB,CAAC"}
package/dist/index.js CHANGED
@@ -13035,7 +13035,7 @@ async function ensureStorageMigrated(opts) {
13035
13035
  import { execFileSync } from "node:child_process";
13036
13036
  import { createHash as createHash2 } from "node:crypto";
13037
13037
  import { chmodSync as chmodSync3, closeSync as closeSync2, copyFileSync as copyFileSync2, createWriteStream as createWriteStream2, existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync5, openSync as openSync2, readdirSync, readFileSync as readFileSync3, readlinkSync, realpathSync, rmSync as rmSync2, statSync as statSync2, symlinkSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
13038
- import { basename, dirname as dirname3, join as join6, relative, resolve } from "node:path";
13038
+ import { basename, dirname as dirname3, isAbsolute, join as join6, relative, resolve, win32 } from "node:path";
13039
13039
  import { Readable as Readable2 } from "node:stream";
13040
13040
  import { pipeline as pipeline2 } from "node:stream/promises";
13041
13041
  var ORT_VERSION = "1.24.4";
@@ -13238,6 +13238,29 @@ function isOnnxVersionCompatible(version) {
13238
13238
  return false;
13239
13239
  return minor >= REQUIRED_ORT_MIN_MINOR;
13240
13240
  }
13241
+ function pathEnvValue() {
13242
+ return process.env.PATH ?? process.env.Path ?? process.env.path ?? "";
13243
+ }
13244
+ function pathEntriesForPlatform() {
13245
+ const delimiter = process.platform === "win32" ? ";" : ":";
13246
+ return pathEnvValue().split(delimiter).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
13247
+ if (!entry || entry === "." || entry.includes("\x00"))
13248
+ return false;
13249
+ return isAbsolute(entry) || win32.isAbsolute(entry);
13250
+ });
13251
+ }
13252
+ function directoryContainsLibrary(dir, libName) {
13253
+ try {
13254
+ const entries = readdirSync(dir);
13255
+ if (process.platform === "win32") {
13256
+ const expected = libName.toLowerCase();
13257
+ return entries.some((entry) => entry.toLowerCase() === expected);
13258
+ }
13259
+ return entries.includes(libName);
13260
+ } catch {
13261
+ return false;
13262
+ }
13263
+ }
13241
13264
  function findSystemOnnxRuntime(libName) {
13242
13265
  if (!libName)
13243
13266
  return null;
@@ -13246,9 +13269,15 @@ function findSystemOnnxRuntime(libName) {
13246
13269
  searchPaths.push("/opt/homebrew/lib", "/usr/local/lib");
13247
13270
  } else if (process.platform === "linux") {
13248
13271
  searchPaths.push("/usr/lib", "/usr/lib/x86_64-linux-gnu", "/usr/lib/aarch64-linux-gnu", "/usr/local/lib");
13272
+ } else if (process.platform === "win32") {
13273
+ searchPaths.push(...pathEntriesForPlatform());
13249
13274
  }
13275
+ const seen = new Set;
13250
13276
  for (const dir of searchPaths) {
13251
- if (!existsSync5(join6(dir, libName)))
13277
+ if (seen.has(dir))
13278
+ continue;
13279
+ seen.add(dir);
13280
+ if (!directoryContainsLibrary(dir, libName))
13252
13281
  continue;
13253
13282
  const version = detectOnnxVersion(dir, libName);
13254
13283
  if (version && !isOnnxVersionCompatible(version)) {
@@ -13827,6 +13856,36 @@ function formatZoomText(targetLabel, response) {
13827
13856
  return out.join(`
13828
13857
  `);
13829
13858
  }
13859
+ function formatZoomMultiTargetResult(entries) {
13860
+ const rendered = entries.map((entry) => {
13861
+ const { targetLabel, name, response } = entry;
13862
+ if (response.success === false) {
13863
+ const message = typeof response.message === "string" && response.message.length > 0 ? response.message : "zoom failed";
13864
+ return { targetLabel, name, success: false, error: message };
13865
+ }
13866
+ return {
13867
+ targetLabel,
13868
+ name,
13869
+ success: true,
13870
+ content: formatZoomText(targetLabel, response)
13871
+ };
13872
+ });
13873
+ const complete = rendered.every((entry) => entry.success);
13874
+ const sections = [];
13875
+ if (!complete) {
13876
+ sections.push("Incomplete zoom results: one or more symbols failed.");
13877
+ }
13878
+ for (const entry of rendered) {
13879
+ if (entry.success) {
13880
+ sections.push(entry.content ?? "");
13881
+ } else {
13882
+ sections.push(`Symbol "${entry.name}" not found in ${entry.targetLabel}: ${entry.error ?? "zoom failed"}`);
13883
+ }
13884
+ }
13885
+ return { complete, entries: rendered, text: sections.join(`
13886
+
13887
+ `) };
13888
+ }
13830
13889
  // src/logger.ts
13831
13890
  import * as fs from "node:fs";
13832
13891
  import * as os from "node:os";
@@ -14475,7 +14534,7 @@ import {
14475
14534
  // package.json
14476
14535
  var package_default = {
14477
14536
  name: "@cortexkit/aft-pi",
14478
- version: "0.30.3",
14537
+ version: "0.31.1",
14479
14538
  type: "module",
14480
14539
  description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
14481
14540
  main: "dist/index.js",
@@ -14497,7 +14556,7 @@ var package_default = {
14497
14556
  prepublishOnly: "bun run build"
14498
14557
  },
14499
14558
  dependencies: {
14500
- "@cortexkit/aft-bridge": "0.30.3",
14559
+ "@cortexkit/aft-bridge": "0.31.1",
14501
14560
  "@xterm/headless": "^5.5.0",
14502
14561
  "comment-json": "^5.0.0",
14503
14562
  diff: "^8.0.4",
@@ -14505,12 +14564,12 @@ var package_default = {
14505
14564
  zod: "^4.1.8"
14506
14565
  },
14507
14566
  optionalDependencies: {
14508
- "@cortexkit/aft-darwin-arm64": "0.30.3",
14509
- "@cortexkit/aft-darwin-x64": "0.30.3",
14510
- "@cortexkit/aft-linux-arm64": "0.30.3",
14511
- "@cortexkit/aft-linux-x64": "0.30.3",
14512
- "@cortexkit/aft-win32-arm64": "0.30.3",
14513
- "@cortexkit/aft-win32-x64": "0.30.3"
14567
+ "@cortexkit/aft-darwin-arm64": "0.31.1",
14568
+ "@cortexkit/aft-darwin-x64": "0.31.1",
14569
+ "@cortexkit/aft-linux-arm64": "0.31.1",
14570
+ "@cortexkit/aft-linux-x64": "0.31.1",
14571
+ "@cortexkit/aft-win32-arm64": "0.31.1",
14572
+ "@cortexkit/aft-win32-x64": "0.31.1"
14514
14573
  },
14515
14574
  devDependencies: {
14516
14575
  "@earendil-works/pi-coding-agent": "*",
@@ -14723,6 +14782,7 @@ function coerceOptionalInt(v, paramName, min, max) {
14723
14782
  var LONG_RUNNING_COMMAND_TIMEOUT_MS = {
14724
14783
  callers: 60000,
14725
14784
  trace_to: 60000,
14785
+ trace_to_symbol: 60000,
14726
14786
  trace_data: 60000,
14727
14787
  impact: 60000,
14728
14788
  grep: 60000,
@@ -14732,6 +14792,68 @@ var LONG_RUNNING_COMMAND_TIMEOUT_MS = {
14732
14792
  function timeoutForCommand(command) {
14733
14793
  return LONG_RUNNING_COMMAND_TIMEOUT_MS[command];
14734
14794
  }
14795
+ function asPlainObject(value) {
14796
+ if (!value || typeof value !== "object" || Array.isArray(value))
14797
+ return;
14798
+ return value;
14799
+ }
14800
+ function candidateLocation(candidate) {
14801
+ const file = typeof candidate.file === "string" && candidate.file.length > 0 ? candidate.file : undefined;
14802
+ if (!file)
14803
+ return;
14804
+ const line = typeof candidate.line === "number" && Number.isFinite(candidate.line) ? candidate.line : undefined;
14805
+ return line === undefined ? file : `${file}:${line}`;
14806
+ }
14807
+ function stringifyData(data) {
14808
+ if (data === undefined)
14809
+ return;
14810
+ try {
14811
+ return JSON.stringify(data, null, 2);
14812
+ } catch {
14813
+ return String(data);
14814
+ }
14815
+ }
14816
+ function formatBridgeErrorMessage(command, response, params = {}) {
14817
+ const code = typeof response.code === "string" && response.code.length > 0 ? response.code : undefined;
14818
+ const message = typeof response.message === "string" && response.message.length > 0 ? response.message : `${command} failed`;
14819
+ const data = asPlainObject(response.data);
14820
+ const rawCandidates = Array.isArray(response.candidates) ? response.candidates : Array.isArray(data?.candidates) ? data.candidates : undefined;
14821
+ const rawSymbol = typeof response.symbol === "string" && response.symbol.length > 0 ? response.symbol : typeof data?.symbol === "string" && data.symbol.length > 0 ? data.symbol : undefined;
14822
+ if (code === "ambiguous_target" || code === "target_symbol_not_in_file") {
14823
+ const candidates = (rawCandidates ?? []).map(asPlainObject).filter((candidate) => candidate !== undefined).map(candidateLocation).filter((candidate) => candidate !== undefined);
14824
+ if (candidates.length > 0) {
14825
+ const symbol = typeof params.toSymbol === "string" && params.toSymbol.length > 0 ? params.toSymbol : rawSymbol;
14826
+ const target = symbol ? `multiple symbols named "${symbol}"` : message.replace(/[.!?]+$/, "");
14827
+ const action = code === "ambiguous_target" ? "Pass toFile to disambiguate" : "Try one of these files for toFile";
14828
+ return `${command}: ${code} — ${target}. ${action}:
14829
+ ${candidates.map((candidate) => ` - ${candidate}`).join(`
14830
+ `)}`;
14831
+ }
14832
+ }
14833
+ if (!code)
14834
+ return message;
14835
+ const lines = [`${command}: ${code} — ${message}`];
14836
+ const extras = collectStructuredExtras(response);
14837
+ if (extras)
14838
+ lines.push(`data: ${extras}`);
14839
+ return lines.join(`
14840
+ `);
14841
+ }
14842
+ function collectStructuredExtras(response) {
14843
+ const reserved = new Set(["id", "success", "code", "message", "data"]);
14844
+ const extras = {};
14845
+ for (const [key, value] of Object.entries(response)) {
14846
+ if (reserved.has(key))
14847
+ continue;
14848
+ extras[key] = value;
14849
+ }
14850
+ if (Object.keys(extras).length === 0) {
14851
+ return stringifyData(response.data);
14852
+ }
14853
+ if (response.data !== undefined)
14854
+ extras.data = response.data;
14855
+ return stringifyData(extras);
14856
+ }
14735
14857
  function bridgeFor(ctx, cwd) {
14736
14858
  return ctx.pool.getBridge(cwd);
14737
14859
  }
@@ -14754,8 +14876,7 @@ async function callBridge(bridge, command, params = {}, extCtx, options) {
14754
14876
  };
14755
14877
  const response = await bridge.send(command, merged, Object.keys(sendOptions).length > 0 ? sendOptions : undefined);
14756
14878
  if (response.success === false) {
14757
- const message = typeof response.message === "string" && response.message.length > 0 ? response.message : `${command} failed`;
14758
- throw new Error(message);
14879
+ throw new Error(formatBridgeErrorMessage(command, response, merged));
14759
14880
  }
14760
14881
  ingestBgCompletions(sessionId, response.bg_completions);
14761
14882
  return response;
@@ -31708,7 +31829,7 @@ function createBashStatusTool(ctx) {
31708
31829
  return {
31709
31830
  name: "bash_status",
31710
31831
  label: "bash_status",
31711
- description: "Read-only snapshot of a background bash task. Returns immediately. Use bash_watch to block on or register for pattern matches and exit events.",
31832
+ description: "Read-only snapshot of a background bash task. Returns immediately. Never waits. Use bash_watch to block on or register for pattern matches and exit events.",
31712
31833
  promptSnippet: "Inspect a background bash task by task_id",
31713
31834
  parameters: BashStatusParams,
31714
31835
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
@@ -32170,8 +32291,12 @@ var DeleteParams = Type5.Object({
32170
32291
  }))
32171
32292
  });
32172
32293
  var MoveParams = Type5.Object({
32173
- filePath: Type5.String({ description: "Source file path to move" }),
32174
- destination: Type5.String({ description: "Destination file path" })
32294
+ filePath: Type5.String({
32295
+ description: "Source file path to move (absolute or relative to project root)"
32296
+ }),
32297
+ destination: Type5.String({
32298
+ description: "Destination file path (absolute or relative to project root)"
32299
+ })
32175
32300
  });
32176
32301
  function renderFsCall(toolName, args, theme, context) {
32177
32302
  if (toolName === "aft_delete") {
@@ -32274,7 +32399,7 @@ function registerFsTools(pi, ctx, surface) {
32274
32399
  // src/tools/hoisted.ts
32275
32400
  import { stat } from "node:fs/promises";
32276
32401
  import { homedir as homedir9 } from "node:os";
32277
- import { isAbsolute, relative as relative3, resolve as resolve3 } from "node:path";
32402
+ import { isAbsolute as isAbsolute2, relative as relative3, resolve as resolve3, sep } from "node:path";
32278
32403
  import {
32279
32404
  renderDiff as renderDiff2
32280
32405
  } from "@earendil-works/pi-coding-agent";
@@ -32386,32 +32511,76 @@ function formatDiffForPi(oldContent, newContent, contextLines = DEFAULT_CONTEXT_
32386
32511
  // src/tools/hoisted.ts
32387
32512
  function containsPath(parent, child) {
32388
32513
  const rel = relative3(parent, child);
32389
- return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
32514
+ return rel === "" || !rel.startsWith("..") && !isAbsolute2(rel);
32515
+ }
32516
+ function expandTilde(path2) {
32517
+ if (!path2 || !path2.startsWith("~"))
32518
+ return path2;
32519
+ if (path2 === "~")
32520
+ return homedir9();
32521
+ if (path2.startsWith(`~${sep}`) || path2.startsWith("~/")) {
32522
+ return resolve3(homedir9(), path2.slice(2));
32523
+ }
32524
+ return path2;
32390
32525
  }
32391
- async function assertExternalDirectoryPermission(extCtx, target, action = "modify") {
32526
+ function externalDirectoryPromptTimeoutMs() {
32527
+ const raw = process.env.AFT_PI_EXTERNAL_PROMPT_TIMEOUT_MS;
32528
+ if (raw === undefined)
32529
+ return 30000;
32530
+ const parsed = Number.parseInt(raw, 10);
32531
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 30000;
32532
+ }
32533
+ async function assertExternalDirectoryPermission(extCtx, target, action = "modify", options = {}) {
32392
32534
  if (!target)
32393
32535
  return;
32394
- const absoluteTarget = isAbsolute(target) ? target : resolve3(extCtx.cwd, target);
32536
+ const expanded = expandTilde(target);
32537
+ const absoluteTarget = isAbsolute2(expanded) ? expanded : resolve3(extCtx.cwd, expanded);
32395
32538
  if (containsPath(extCtx.cwd, absoluteTarget))
32396
32539
  return;
32397
- const confirmed = await extCtx.ui?.confirm?.("Allow external directory access?", `AFT wants to ${action} outside the project: ${absoluteTarget}`);
32398
- if (confirmed === true)
32540
+ if (options.restrictToProjectRoot === false)
32399
32541
  return;
32400
- throw new Error("Permission denied: external directory access was cancelled.");
32542
+ const confirmFn = extCtx.ui?.confirm;
32543
+ if (extCtx.hasUI === false || !confirmFn) {
32544
+ throw new Error(`Permission denied: cannot prompt for ${action} outside the project (${absoluteTarget}).`);
32545
+ }
32546
+ const timeoutMs = externalDirectoryPromptTimeoutMs();
32547
+ let timer;
32548
+ const timeoutPromise = new Promise((resolve4) => {
32549
+ timer = setTimeout(() => resolve4("timeout"), timeoutMs);
32550
+ });
32551
+ try {
32552
+ const result = await Promise.race([
32553
+ confirmFn("Allow external directory access?", `AFT wants to ${action} outside the project: ${absoluteTarget}`),
32554
+ timeoutPromise
32555
+ ]);
32556
+ if (result === true)
32557
+ return;
32558
+ if (result === "timeout") {
32559
+ throw new Error(`Permission denied: external directory prompt timed out after ${timeoutMs}ms.`);
32560
+ }
32561
+ throw new Error("Permission denied: external directory access was cancelled.");
32562
+ } finally {
32563
+ if (timer !== undefined)
32564
+ clearTimeout(timer);
32565
+ }
32401
32566
  }
32402
32567
  var ReadParams = Type6.Object({
32403
- path: Type6.String({ description: "Path to the file to read (relative or absolute)" }),
32568
+ path: Type6.String({
32569
+ description: "Path to the file to read (absolute or relative to project root)"
32570
+ }),
32404
32571
  offset: optionalInt(1, Number.MAX_SAFE_INTEGER),
32405
32572
  limit: optionalInt(1, Number.MAX_SAFE_INTEGER)
32406
32573
  });
32407
32574
  var WriteParams = Type6.Object({
32408
32575
  filePath: Type6.String({
32409
- description: "Path to the file to write (absolute or project-relative)"
32576
+ description: "Path to the file to write (absolute or relative to project root)"
32410
32577
  }),
32411
32578
  content: Type6.String({ description: "Full file contents to write" })
32412
32579
  });
32413
32580
  var EditParams = Type6.Object({
32414
- filePath: Type6.String({ description: "Path to the file to edit" }),
32581
+ filePath: Type6.String({
32582
+ description: "Path to the file to edit (absolute or relative to project root)"
32583
+ }),
32415
32584
  oldString: Type6.Optional(Type6.String({ description: "Text to find (exact match, fuzzy fallback)" })),
32416
32585
  newString: Type6.Optional(Type6.String({ description: "Replacement text (omit to delete match)" })),
32417
32586
  replaceAll: Type6.Optional(Type6.Boolean({ description: "Replace every occurrence" })),
@@ -32422,7 +32591,9 @@ var EditParams = Type6.Object({
32422
32591
  });
32423
32592
  var GrepParams = Type6.Object({
32424
32593
  pattern: Type6.String({ description: "Regex pattern to search for" }),
32425
- path: Type6.Optional(Type6.String({ description: "Path scope (file or directory)" })),
32594
+ path: Type6.Optional(Type6.String({
32595
+ description: "Path scope (file or directory; absolute or relative to project root)"
32596
+ })),
32426
32597
  include: Type6.Optional(Type6.String({ description: "Glob filter for included files (e.g. '*.ts,*.tsx')" })),
32427
32598
  caseSensitive: Type6.Optional(Type6.Boolean({ description: "Case-sensitive matching" })),
32428
32599
  contextLines: optionalInt(1, Number.MAX_SAFE_INTEGER)
@@ -32472,7 +32643,9 @@ function registerHoistedTools(pi, ctx, surface) {
32472
32643
  promptGuidelines: ["Use write only for new files or complete rewrites."],
32473
32644
  parameters: WriteParams,
32474
32645
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
32475
- await assertExternalDirectoryPermission(extCtx, params.filePath, "modify");
32646
+ await assertExternalDirectoryPermission(extCtx, params.filePath, "modify", {
32647
+ restrictToProjectRoot: surface.restrictToProjectRoot
32648
+ });
32476
32649
  const bridge = bridgeFor(ctx, extCtx.cwd);
32477
32650
  const response = await callBridge(bridge, "write", {
32478
32651
  file: params.filePath,
@@ -32503,7 +32676,9 @@ function registerHoistedTools(pi, ctx, surface) {
32503
32676
  ],
32504
32677
  parameters: EditParams,
32505
32678
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
32506
- await assertExternalDirectoryPermission(extCtx, params.filePath, "modify");
32679
+ await assertExternalDirectoryPermission(extCtx, params.filePath, "modify", {
32680
+ restrictToProjectRoot: surface.restrictToProjectRoot
32681
+ });
32507
32682
  const bridge = bridgeFor(ctx, extCtx.cwd);
32508
32683
  if (typeof params.appendContent === "string") {
32509
32684
  const req2 = {
@@ -32551,7 +32726,9 @@ function registerHoistedTools(pi, ctx, surface) {
32551
32726
  const bridge = bridgeFor(ctx, extCtx.cwd);
32552
32727
  const req = { pattern: params.pattern };
32553
32728
  if (params.path) {
32554
- await assertExternalDirectoryPermission(extCtx, params.path, "search");
32729
+ await assertExternalDirectoryPermission(extCtx, params.path, "search", {
32730
+ restrictToProjectRoot: surface.restrictToProjectRoot
32731
+ });
32555
32732
  req.path = await resolvePathArg(extCtx.cwd, params.path);
32556
32733
  }
32557
32734
  if (params.include)
@@ -32724,12 +32901,13 @@ function shortenPath2(path2) {
32724
32901
  return path2;
32725
32902
  }
32726
32903
  async function resolvePathArg(cwd, path2) {
32727
- const abs = resolve3(cwd, path2);
32904
+ const expanded = expandTilde(path2);
32905
+ const abs = isAbsolute2(expanded) ? expanded : resolve3(cwd, expanded);
32728
32906
  try {
32729
32907
  await stat(abs);
32730
32908
  return abs;
32731
32909
  } catch {
32732
- return path2;
32910
+ return expanded;
32733
32911
  }
32734
32912
  }
32735
32913
  function splitIncludeGlobs(include) {
@@ -32782,7 +32960,7 @@ import { StringEnum as StringEnum2 } from "@earendil-works/pi-ai";
32782
32960
  import { Type as Type7 } from "typebox";
32783
32961
  var ImportParams = Type7.Object({
32784
32962
  op: StringEnum2(["add", "remove", "organize"], { description: "Import operation" }),
32785
- filePath: Type7.String({ description: "Path to the file" }),
32963
+ filePath: Type7.String({ description: "Path to the file (absolute or relative to project root)" }),
32786
32964
  module: Type7.Optional(Type7.String({ description: "Module path (required for add/remove), e.g. 'react', './utils'" })),
32787
32965
  names: Type7.Optional(Type7.Array(Type7.String(), { description: "Named imports to add, e.g. ['useState']" })),
32788
32966
  defaultImport: Type7.Optional(Type7.String({ description: "Default import name (e.g. 'React')" })),
@@ -32939,7 +33117,7 @@ function registerLspTools(pi, ctx) {
32939
33117
  pi.registerTool({
32940
33118
  name: "lsp_diagnostics",
32941
33119
  label: "lsp diagnostics",
32942
- description: "On-demand LSP file/scope check. Spawns the relevant language server (if registered for the extension), opens the document, prefers LSP 3.17 pull diagnostics where supported, falls back to push + waitMs otherwise. NOT a project-wide type checker — for full coverage run `tsc --noEmit`, `cargo check`, `pyright`, etc.\n\nResponse fields: `diagnostics`, `total`, `files_with_errors`, `complete` (true = trustable absence), `lsp_servers_used` (per-server status, e.g. `pull_ok`, `push_only`, `binary_not_installed: <name>`, `no_root_marker (...)`), and (directory mode) `unchecked_files`.\n\nReading honestly:\n- `total: 0` + empty `lsp_servers_used` → **nothing was checked** (no server registered for this extension). Tell the user, don't claim 'no errors'.\n- `total: 0` + `pull_ok` the file is genuinely clean.\n- `binary_not_installed: <name>` server matched the extension but its binary isn't on PATH. Tell the user to install it.\n- `no_root_marker (...)` → server is registered but couldn't find a workspace root marker. The user's project layout doesn't match what the server expects.\n\nProvide `filePath` for a single file, `directory` for files under a path (workspace pull from active servers + 200-file walk for unchecked listing), or omit both to dump cached diagnostics.\n\n**When this tool gives an unhelpful answer**, run `npx @cortexkit/aft doctor lsp <filePath>` from a terminal to get a full per-server breakdown (registered servers, binary resolution, root-marker resolution, spawn outcome).",
33120
+ description: "On-demand LSP file/scope check. NOT a project-wide type checker — use `tsc --noEmit`, `cargo check`, `pyright` etc. for full coverage.\n\nHonesty: `total: 0` is only clean when `complete: true` AND `lsp_servers_used[].status` includes `pull_ok`. Empty `lsp_servers_used`, or any `binary_not_installed`/`spawn_failed`/`no_root_marker`/`push_only` without diagnostics means the file wasn't actually checked say so, don't report 'clean'. For per-server breakdown run `npx @cortexkit/aft doctor lsp <filePath>`.",
32943
33121
  parameters: LspDiagnosticsParams,
32944
33122
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
32945
33123
  const hasFile = typeof params.filePath === "string" && params.filePath.length > 0;
@@ -32974,13 +33152,21 @@ import { StringEnum as StringEnum4 } from "@earendil-works/pi-ai";
32974
33152
  import { Type as Type9 } from "typebox";
32975
33153
  function navigateParamsSchema() {
32976
33154
  return Type9.Object({
32977
- op: StringEnum4(["call_tree", "callers", "trace_to", "impact", "trace_data"], {
33155
+ op: StringEnum4(["call_tree", "callers", "trace_to", "trace_to_symbol", "impact", "trace_data"], {
32978
33156
  description: "Navigation operation"
32979
33157
  }),
32980
- filePath: Type9.String({ description: "Source file containing the symbol" }),
33158
+ filePath: Type9.String({
33159
+ description: "Source file containing the symbol (absolute or relative to project root)"
33160
+ }),
32981
33161
  symbol: Type9.String({ description: "Name of the symbol to analyze" }),
32982
33162
  depth: optionalInt(1, Number.MAX_SAFE_INTEGER),
32983
- expression: Type9.Optional(Type9.String({ description: "Expression to track (required for trace_data)" }))
33163
+ expression: Type9.Optional(Type9.String({ description: "Expression to track (required for trace_data)" })),
33164
+ toSymbol: Type9.Optional(Type9.String({
33165
+ description: "Target symbol for trace_to_symbol; the returned path ends here"
33166
+ })),
33167
+ toFile: Type9.Optional(Type9.String({
33168
+ description: "Optional target file for trace_to_symbol; required when toSymbol exists in multiple files"
33169
+ }))
32984
33170
  });
32985
33171
  }
32986
33172
  function treeLine(depth, text) {
@@ -33042,6 +33228,23 @@ function buildNavigateSections(args, payload, theme) {
33042
33228
  });
33043
33229
  return sections2;
33044
33230
  }
33231
+ if (args.op === "trace_to_symbol") {
33232
+ const path2 = asRecords(response.path);
33233
+ const complete = asBoolean(response.complete);
33234
+ const reason = asString(response.reason);
33235
+ if (path2.length === 0) {
33236
+ const prefix = complete === false ? theme.fg("warning", "No complete path") : theme.fg("muted", "No path");
33237
+ return [`${prefix}${reason ? ` (${reason})` : ""}`];
33238
+ }
33239
+ const lines = [theme.fg("success", `${path2.length} hop${path2.length === 1 ? "" : "s"}`)];
33240
+ path2.forEach((hop, index) => {
33241
+ const symbol2 = asString(hop.symbol) ?? "(unknown)";
33242
+ const file2 = shortenPath(asString(hop.file) ?? "(unknown file)");
33243
+ const line = asNumber(hop.line);
33244
+ lines.push(treeLine(index + 1, `${symbol2} ${line !== undefined ? `[${file2}:${line}]` : `[${file2}]`}`));
33245
+ });
33246
+ return lines;
33247
+ }
33045
33248
  if (args.op === "trace_to") {
33046
33249
  const paths = asRecords(response.paths);
33047
33250
  const warning = depthWarning(response, theme, "max_depth_reached", "truncated_paths");
@@ -33103,7 +33306,8 @@ function renderNavigateCall(args, theme, context) {
33103
33306
  const summary = [
33104
33307
  theme.fg("accent", args.op),
33105
33308
  accentPath(theme, args.filePath),
33106
- theme.fg("toolOutput", args.symbol)
33309
+ theme.fg("toolOutput", args.symbol),
33310
+ args.toSymbol ? theme.fg("toolOutput", `→ ${args.toSymbol}`) : undefined
33107
33311
  ].filter(Boolean).join(" ");
33108
33312
  return renderToolCall("navigate", summary, theme, context);
33109
33313
  }
@@ -33116,12 +33320,15 @@ function registerNavigateTool(pi, ctx) {
33116
33320
  pi.registerTool({
33117
33321
  name: "aft_navigate",
33118
33322
  label: "navigate",
33119
- description: "Navigate code structure across files using call graph analysis. All ops require both `filePath` and `symbol`. Use `call_tree` for what a function calls, `callers` for call sites, `trace_to` for entry points, `impact` for blast radius, `trace_data` to follow a value.",
33323
+ description: "Navigate code structure across files using call graph analysis. All ops require both `filePath` and `symbol`. Use `call_tree` for what a function calls, `callers` for call sites, `trace_to` for entry points, `trace_to_symbol` for a path from one symbol to another (requires `toSymbol`; if ambiguous, the error returns candidate files — retry with `toFile`), `impact` for blast radius, `trace_data` to follow a value.",
33120
33324
  parameters: navigateParamsSchema(),
33121
33325
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
33122
33326
  if (params.op === "trace_data" && !params.expression) {
33123
33327
  throw new Error("op='trace_data' requires an `expression`");
33124
33328
  }
33329
+ if (params.op === "trace_to_symbol" && !params.toSymbol) {
33330
+ throw new Error("op='trace_to_symbol' requires a `toSymbol`");
33331
+ }
33125
33332
  const bridge = bridgeFor(ctx, extCtx.cwd);
33126
33333
  const req = {
33127
33334
  op: params.op,
@@ -33133,6 +33340,10 @@ function registerNavigateTool(pi, ctx) {
33133
33340
  req.depth = depth;
33134
33341
  if (params.expression !== undefined)
33135
33342
  req.expression = params.expression;
33343
+ if (params.toSymbol !== undefined)
33344
+ req.toSymbol = params.toSymbol;
33345
+ if (params.toFile !== undefined)
33346
+ req.toFile = params.toFile;
33136
33347
  const response = await callBridge(bridge, params.op, req, extCtx);
33137
33348
  return textResult(JSON.stringify(response, null, 2));
33138
33349
  },
@@ -33152,15 +33363,26 @@ import { Type as Type10 } from "typebox";
33152
33363
  var OutlineParams = Type10.Object({
33153
33364
  target: Type10.Union([Type10.String(), Type10.Array(Type10.String())], {
33154
33365
  description: "What to outline: a file path, directory path, URL (http:// or https://), or array of file paths. The mode is auto-detected: URLs by `http://`/`https://` prefix, directories by stat, arrays as multi-file. Directory walks cap at 200 files."
33155
- })
33366
+ }),
33367
+ files: Type10.Optional(Type10.Boolean({
33368
+ description: "Directory-only mode: when true, target must be a directory or array of directories and the result is a flat file tree with path, language, symbol count, and byte size instead of a symbol outline."
33369
+ }))
33370
+ });
33371
+ var ZoomTarget = Type10.Object({
33372
+ filePath: Type10.String({ description: "Path to file (absolute or project-relative)" }),
33373
+ symbol: Type10.String({ description: "Symbol name in that file" })
33156
33374
  });
33157
33375
  var ZoomParams = Type10.Object({
33158
33376
  filePath: Type10.Optional(Type10.String({ description: "Path to file (absolute or project-relative)" })),
33159
33377
  url: Type10.Optional(Type10.String({
33160
33378
  description: "HTTP/HTTPS URL of an HTML or Markdown document to fetch and zoom into"
33161
33379
  })),
33162
- symbol: Type10.Optional(Type10.String({ description: "Symbol name (function/class/type) or Markdown heading" })),
33163
- symbols: Type10.Optional(Type10.Array(Type10.String(), { description: "Multiple symbols returns array of matches" })),
33380
+ symbols: Type10.Optional(Type10.Union([Type10.String(), Type10.Array(Type10.String())], {
33381
+ description: "Symbol name for code, or heading text for Markdown/HTML. Pass a string for one lookup or an array for batched lookups in the same file/URL."
33382
+ })),
33383
+ targets: Type10.Optional(Type10.Union([ZoomTarget, Type10.Array(ZoomTarget)], {
33384
+ description: "Cross-file batch: `{ filePath, symbol }` or an array of them. Mutually exclusive with filePath/url/symbols."
33385
+ })),
33164
33386
  contextLines: Type10.Optional(Type10.Number({ description: "Lines of context before/after (default: 3)" }))
33165
33387
  });
33166
33388
  function isUrl(s) {
@@ -33241,7 +33463,7 @@ function buildZoomSections(args, payload, theme) {
33241
33463
  }).filter(Boolean);
33242
33464
  }
33243
33465
  function renderOutlineCall(args, theme, context) {
33244
- const summary = Array.isArray(args.target) ? theme.fg("accent", `${args.target.length} files`) : typeof args.target === "string" ? accentPath(theme, args.target) : undefined;
33466
+ const summary = Array.isArray(args.target) ? theme.fg("accent", `${args.target.length} ${args.files ? "directories" : "files"}`) : typeof args.target === "string" ? `${accentPath(theme, args.target)}${args.files ? " files" : ""}` : undefined;
33245
33467
  return renderToolCall("outline", summary, theme, context);
33246
33468
  }
33247
33469
  function renderOutlineResult(result, theme, context) {
@@ -33250,8 +33472,21 @@ function renderOutlineResult(result, theme, context) {
33250
33472
  return renderSections(buildOutlineSections(collectTextContent(result), theme), context);
33251
33473
  }
33252
33474
  function renderZoomCall(args, theme, context) {
33253
- const target = args.symbol ? theme.fg("toolOutput", args.symbol) : args.symbols && args.symbols.length > 0 ? theme.fg("toolOutput", `${args.symbols.length} symbols`) : theme.fg("toolOutput", "lines");
33254
- return renderToolCall("zoom", `${accentPath(theme, zoomTargetLabel(args))} ${target}`, theme, context);
33475
+ const symbols = args.symbols;
33476
+ const targets = args.targets;
33477
+ let summary;
33478
+ if (typeof symbols === "string") {
33479
+ summary = theme.fg("toolOutput", symbols);
33480
+ } else if (Array.isArray(symbols) && symbols.length > 0) {
33481
+ summary = theme.fg("toolOutput", `${symbols.length} symbols`);
33482
+ } else if (Array.isArray(targets) && targets.length > 0) {
33483
+ summary = theme.fg("toolOutput", `${targets.length} targets`);
33484
+ } else if (targets && typeof targets === "object" && !Array.isArray(targets)) {
33485
+ summary = theme.fg("toolOutput", targets.symbol ?? "1 target");
33486
+ } else {
33487
+ summary = theme.fg("toolOutput", "lines");
33488
+ }
33489
+ return renderToolCall("zoom", `${accentPath(theme, zoomTargetLabel(args))} ${summary}`, theme, context);
33255
33490
  }
33256
33491
  function renderZoomResult(result, args, theme, context) {
33257
33492
  if (context.isError)
@@ -33263,18 +33498,46 @@ function registerReadingTools(pi, ctx, surface) {
33263
33498
  pi.registerTool({
33264
33499
  name: "aft_outline",
33265
33500
  label: "outline",
33266
- description: `Structural outline of source code, documentation files, or remote URLs. For code, returns symbols (functions, classes, types) with line ranges. For Markdown and HTML, returns heading hierarchy. Use this to explore structure before reading specific sections with aft_zoom.
33501
+ description: `Structural outline of source code, documentation files, or remote URLs. For code, returns symbols (functions, classes, types) with line ranges. For Markdown and HTML, returns heading hierarchy. Use this to explore structure before reading specific sections with aft_zoom. Set \`files: true\` with a directory target for a flat indexed file tree with language, symbol count, and byte metadata.
33267
33502
 
33268
33503
  Pass a single \`target\`:
33269
33504
  • file path → outline that file (with signatures)
33270
33505
  • directory path → outline source files under it (recursively, up to 200 files)
33271
33506
  • URL (http:// or https://) → fetch and outline a remote HTML/Markdown document
33272
- • array of paths → outline multiple files in one call`,
33507
+ • array of paths → outline multiple files in one call; with files:true, every path must be a directory`,
33273
33508
  parameters: OutlineParams,
33274
33509
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
33275
33510
  const bridge = bridgeFor(ctx, extCtx.cwd);
33276
33511
  const target = params.target;
33512
+ const filesMode = params.files === true;
33277
33513
  const isArray = Array.isArray(target) && target.length > 0;
33514
+ if (filesMode) {
33515
+ if (Array.isArray(target)) {
33516
+ if (target.length === 0) {
33517
+ throw new Error("'target' must be a non-empty string or array of strings");
33518
+ }
33519
+ const response3 = await callBridge(bridge, "outline", { target, files: true }, extCtx);
33520
+ if (response3.success === false) {
33521
+ throw new Error(response3.message || "outline failed");
33522
+ }
33523
+ return textResult(formatOutlineFilesText(response3), response3);
33524
+ }
33525
+ if (typeof target !== "string" || target.length === 0) {
33526
+ throw new Error("'target' must be a non-empty string or array of strings");
33527
+ }
33528
+ let isDirectory2 = false;
33529
+ try {
33530
+ const resolved = resolve4(extCtx.cwd, target);
33531
+ const st = await stat2(resolved);
33532
+ isDirectory2 = st.isDirectory();
33533
+ } catch {}
33534
+ const request = isDirectory2 ? { directory: resolve4(extCtx.cwd, target), files: true } : { file: target, files: true };
33535
+ const response2 = await callBridge(bridge, "outline", request, extCtx);
33536
+ if (response2.success === false) {
33537
+ throw new Error(response2.message || "outline failed");
33538
+ }
33539
+ return textResult(formatOutlineFilesText(response2), response2);
33540
+ }
33278
33541
  if (typeof target === "string" && isUrl(target)) {
33279
33542
  const response2 = await callBridge(bridge, "outline", { file: target }, extCtx);
33280
33543
  if (response2.success === false) {
@@ -33315,22 +33578,58 @@ Pass a single \`target\`:
33315
33578
  pi.registerTool({
33316
33579
  name: "aft_zoom",
33317
33580
  label: "zoom",
33318
- description: "Inspect a code symbol or Markdown/HTML section. For code, returns the full source of the symbol with call-graph annotations (calls/called-by). Pass `symbols` for batched lookups.\n\nProvide exactly ONE of `filePath` or `url`.",
33581
+ description: "Inspect code symbols or documentation sections. For code, returns the full source of a symbol with call-graph annotations (calls/called-by). For Markdown and HTML, returns the section content under the given heading.\n\nUse exactly ONE mode: `{ filePath, symbols }`, `{ url, symbols }`, or `{ targets }`. `symbols` can be a string or array (one or many lookups in the same file/URL). Use `targets` for cross-file batches: `{ filePath, symbol }` or an array of them.",
33319
33582
  parameters: ZoomParams,
33320
33583
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
33321
33584
  const bridge = bridgeFor(ctx, extCtx.cwd);
33322
33585
  const hasFilePath = typeof params.filePath === "string" && params.filePath.length > 0;
33323
33586
  const hasUrl = typeof params.url === "string" && params.url.length > 0;
33587
+ const hasTargets = params.targets !== undefined && params.targets !== null;
33588
+ const hasSymbols = params.symbols !== undefined && params.symbols !== null && (typeof params.symbols === "string" ? params.symbols.length > 0 : Array.isArray(params.symbols) && params.symbols.length > 0);
33589
+ if (hasTargets) {
33590
+ if (hasFilePath || hasUrl || hasSymbols) {
33591
+ throw new Error("'targets' is mutually exclusive with 'filePath', 'url', and 'symbols'");
33592
+ }
33593
+ const targets = Array.isArray(params.targets) ? params.targets : [params.targets];
33594
+ if (targets.length === 0) {
33595
+ throw new Error("'targets' must be a non-empty object or array");
33596
+ }
33597
+ for (const [i, entry] of targets.entries()) {
33598
+ if (!entry || typeof entry.filePath !== "string" || entry.filePath.length === 0) {
33599
+ throw new Error(`targets[${i}].filePath must be a non-empty string`);
33600
+ }
33601
+ if (typeof entry.symbol !== "string" || entry.symbol.length === 0) {
33602
+ throw new Error(`targets[${i}].symbol must be a non-empty string`);
33603
+ }
33604
+ }
33605
+ const responses = await Promise.all(targets.map((t) => {
33606
+ const req2 = { file: t.filePath, symbol: t.symbol };
33607
+ if (params.contextLines !== undefined)
33608
+ req2.context_lines = params.contextLines;
33609
+ return callBridge(bridge, "zoom", req2, extCtx).catch((err) => ({
33610
+ success: false,
33611
+ message: err instanceof Error ? err.message : String(err)
33612
+ }));
33613
+ }));
33614
+ const entries = targets.map((t, i) => ({
33615
+ targetLabel: t.filePath,
33616
+ name: t.symbol,
33617
+ response: responses[i] ?? { success: false, message: "missing zoom response" }
33618
+ }));
33619
+ const batch = formatZoomMultiTargetResult(entries);
33620
+ return textResult(batch.text, batch);
33621
+ }
33324
33622
  if (!hasFilePath && !hasUrl) {
33325
- throw new Error("Provide exactly one of 'filePath' or 'url'");
33623
+ throw new Error("Provide exactly one of 'filePath', 'url', or 'targets'");
33326
33624
  }
33327
33625
  if (hasFilePath && hasUrl) {
33328
33626
  throw new Error("Provide exactly ONE of 'filePath' or 'url' — not both");
33329
33627
  }
33330
33628
  const file2 = hasUrl ? params.url : params.filePath;
33331
33629
  const targetLabel = (hasUrl ? params.url : params.filePath) ?? file2;
33332
- if (Array.isArray(params.symbols) && params.symbols.length > 0) {
33333
- const results = await Promise.all(params.symbols.map((sym) => {
33630
+ const symbolsArray = hasSymbols ? typeof params.symbols === "string" ? [params.symbols] : params.symbols : undefined;
33631
+ if (symbolsArray) {
33632
+ const results = await Promise.all(symbolsArray.map((sym) => {
33334
33633
  const req2 = { file: file2, symbol: sym };
33335
33634
  if (params.contextLines !== undefined)
33336
33635
  req2.context_lines = params.contextLines;
@@ -33339,12 +33638,17 @@ Pass a single \`target\`:
33339
33638
  message: err instanceof Error ? err.message : String(err)
33340
33639
  }));
33341
33640
  }));
33342
- const batch = formatZoomBatchResult(targetLabel, params.symbols, results);
33641
+ if (symbolsArray.length === 1) {
33642
+ const response2 = results[0] ?? { success: false, message: "missing zoom response" };
33643
+ if (response2.success === false) {
33644
+ throw new Error(response2.message || "zoom failed");
33645
+ }
33646
+ return textResult(formatZoomText(targetLabel, response2), response2);
33647
+ }
33648
+ const batch = formatZoomBatchResult(targetLabel, symbolsArray, results);
33343
33649
  return textResult(batch.text, batch);
33344
33650
  }
33345
33651
  const req = { file: file2 };
33346
- if (params.symbol)
33347
- req.symbol = params.symbol;
33348
33652
  if (params.contextLines !== undefined)
33349
33653
  req.context_lines = params.contextLines;
33350
33654
  const response = await callBridge(bridge, "zoom", req, extCtx);
@@ -33387,6 +33691,7 @@ function formatZoomBatchResult(targetLabel, symbols, responses) {
33387
33691
 
33388
33692
  `) };
33389
33693
  }
33694
+ var MAX_UNCHECKED_FILES_IN_FOOTER = 10;
33390
33695
  function formatOutlineText(response) {
33391
33696
  const text = response.text ?? "";
33392
33697
  const skipped = response.skipped_files;
@@ -33401,13 +33706,45 @@ function formatOutlineText(response) {
33401
33706
  return `${header}Skipped ${skipped.length} file(s):
33402
33707
  ${lines}`;
33403
33708
  }
33709
+ function formatOutlineFilesText(response) {
33710
+ const text = formatOutlineText(response);
33711
+ const uncheckedFiles = Array.isArray(response.unchecked_files) ? response.unchecked_files.filter((file2) => typeof file2 === "string" && file2.length > 0) : [];
33712
+ const isPartial = response.complete === false || response.walk_truncated === true || uncheckedFiles.length > 0;
33713
+ if (!isPartial) {
33714
+ return text;
33715
+ }
33716
+ const footer = [];
33717
+ if (response.walk_truncated === true) {
33718
+ const uncheckedCount = uncheckedFiles.length;
33719
+ const suffix = uncheckedCount > 0 ? ` ${uncheckedCount} additional files in this directory were not indexed.` : " Some files in this directory were not indexed.";
33720
+ footer.push(`⚠ Partial result: walk truncated at 200 files.${suffix}`);
33721
+ } else {
33722
+ const suffix = uncheckedFiles.length > 0 ? ` ${uncheckedFiles.length} files in this directory were not indexed.` : " Some files in this directory were not indexed.";
33723
+ footer.push(`⚠ Partial result:${suffix}`);
33724
+ }
33725
+ if (uncheckedFiles.length > 0) {
33726
+ footer.push("Unchecked files:");
33727
+ footer.push(...uncheckedFiles.slice(0, MAX_UNCHECKED_FILES_IN_FOOTER).map((file2) => ` ${file2}`));
33728
+ const remaining = uncheckedFiles.length - MAX_UNCHECKED_FILES_IN_FOOTER;
33729
+ if (remaining > 0) {
33730
+ footer.push(` ... +${remaining} more`);
33731
+ }
33732
+ }
33733
+ const header = text.length > 0 ? `${text}
33734
+
33735
+ ` : "";
33736
+ return `${header}${footer.join(`
33737
+ `)}`;
33738
+ }
33404
33739
 
33405
33740
  // src/tools/refactor.ts
33406
33741
  import { StringEnum as StringEnum5 } from "@earendil-works/pi-ai";
33407
33742
  import { Type as Type11 } from "typebox";
33408
33743
  var RefactorParams = Type11.Object({
33409
33744
  op: StringEnum5(["move", "extract", "inline"], { description: "Refactoring operation" }),
33410
- filePath: Type11.String({ description: "Source file" }),
33745
+ filePath: Type11.String({
33746
+ description: "Source file (absolute or relative to project root)"
33747
+ }),
33411
33748
  symbol: Type11.Optional(Type11.String({ description: "Symbol name (for move, inline)" })),
33412
33749
  destination: Type11.Optional(Type11.String({ description: "Target file (for move)" })),
33413
33750
  scope: Type11.Optional(Type11.String({ description: "Disambiguation scope for move op" })),
@@ -33509,7 +33846,9 @@ var SafetyParams = Type12.Object({
33509
33846
  op: StringEnum6(["undo", "history", "checkpoint", "restore", "list"], {
33510
33847
  description: "Safety operation"
33511
33848
  }),
33512
- filePath: Type12.Optional(Type12.String({ description: "File path (required for history, optional for undo)" })),
33849
+ filePath: Type12.Optional(Type12.String({
33850
+ description: "File path (required for history, optional for undo). Absolute or relative to project root."
33851
+ })),
33513
33852
  name: Type12.Optional(Type12.String({ description: "Checkpoint name (required for checkpoint, restore)" })),
33514
33853
  files: Type12.Optional(Type12.Array(Type12.String(), {
33515
33854
  description: "Specific files for checkpoint (optional, defaults to all tracked)"
@@ -33751,7 +34090,9 @@ import { StringEnum as StringEnum7 } from "@earendil-works/pi-ai";
33751
34090
  import { Type as Type14 } from "typebox";
33752
34091
  var TransformParams = Type14.Object({
33753
34092
  op: StringEnum7(["add_member", "add_derive", "wrap_try_catch", "add_decorator", "add_struct_tags"], { description: "Transformation operation" }),
33754
- filePath: Type14.String({ description: "Path to the source file" }),
34093
+ filePath: Type14.String({
34094
+ description: "Path to the source file (absolute or relative to project root)"
34095
+ }),
33755
34096
  container: Type14.Optional(Type14.String({ description: "Class/struct/impl name for add_member" })),
33756
34097
  code: Type14.Optional(Type14.String({ description: "Member code to insert (add_member)" })),
33757
34098
  target: Type14.Optional(Type14.String({ description: "Target symbol name" })),
@@ -33883,7 +34224,7 @@ function buildWorkflowHints(opts) {
33883
34224
  const hasNavigate = opts.toolSurface === "all" && !opts.absentTools.has("aft_navigate");
33884
34225
  const hasBgBash = opts.bashBackgroundEnabled && !opts.absentTools.has(bashName) && !opts.absentTools.has("bash_status");
33885
34226
  if (hasOutline && hasZoom) {
33886
- sections.push(`**Web/URL access**: \`aft_outline({ target: "<url>" })\` first for structure, then \`aft_zoom({ target: "<url>", symbol: "<heading>" })\` for the specific section.`);
34227
+ sections.push(`**Web/URL access**: \`aft_outline({ target: "<url>" })\` first for structure, then \`aft_zoom({ url: "<url>", symbols: "<heading>" })\` for the specific section.`);
33887
34228
  }
33888
34229
  if (hasOutline && hasZoom && (hasGrep || hasSearch)) {
33889
34230
  const locator = hasGrep ? `\`${grepName}\`` : "`aft_search`";
@@ -33895,6 +34236,7 @@ function buildWorkflowHints(opts) {
33895
34236
  "- `callers` — find all call sites before changing a function signature",
33896
34237
  "- `impact` — blast radius (which functions/files will need updates)",
33897
34238
  "- `trace_to` — how execution reaches this code from entry points (routes, exports, main)",
34239
+ "- `trace_to_symbol` — shortest call path from one symbol to another",
33898
34240
  "- `trace_data` — follow a value through assignments and parameters across files"
33899
34241
  ].join(`
33900
34242
  `));
@@ -33994,13 +34336,13 @@ var PLUGIN_VERSION = (() => {
33994
34336
  return "0.0.0";
33995
34337
  }
33996
34338
  })();
33997
- var ANNOUNCEMENT_VERSION = "0.30.0";
34339
+ var ANNOUNCEMENT_VERSION = "0.31.0";
33998
34340
  var ANNOUNCEMENT_FEATURES = [
33999
- 'PTY support for interactive bash. `bash({pty: true, background: true})` spawns commands inside a real terminal runs Python/Node REPLs, vim, htop, less, and nested TUIs. Use `ptyRows`/`ptyCols` (up to 60×140) to size the terminal, `bash_status({outputMode: "screen"})` for the rendered view, and `bash_write` to send keystrokes.',
34000
- "New `bash_watch` tool unifies pattern notifications and sync waits. `bash_watch({taskId, pattern?, timeoutMs?})` blocks inline; `bash_watch({taskId, pattern, background: true})` registers an async watcher that fires `[BG BASH NOTIFY]` on match or task exit and suppresses the default completion reminder.",
34001
- "`bash_status` is now a pure snapshot tool wait and watch semantics moved to `bash_watch`.",
34002
- "URL fetches in `aft_outline` and `aft_zoom` no longer hang indefinitely on slow servers body reads abort with a clear stall error after 15 seconds without data.",
34003
- "Post-restart bg-bash replay is fixed: previously-delivered task completions no longer fire fresh reminders after OpenCode restarts."
34341
+ "`aft_navigate` has a new `trace_to_symbol` op for path-between-symbols queries. One call returns the shortest call path from one function to another with file + line for every hop. Honest errors for ambiguous, missing, or unreachable targets including a candidate list to disambiguate.",
34342
+ '`aft_outline target: "<dir>", files: true` returns an indexed file tree with language, symbol count, and byte size per file. Lets agents pick which files to actually open without first reading symbol bodies. Honest truncation (`complete: false` + `walk_truncated`/`unchecked_files`) when the directory exceeds the walk cap.',
34343
+ '`aft_zoom` adds `targets` for cross-file batchespull bodies from different files in one call. Schema breaking change: `symbol` is removed; pass `symbols: "name"` (string) or `symbols: ["a", "b"]` (array). Same shape works for `url` mode so you can grab multiple sections from one URL fetch.',
34344
+ "Pi `grep`/`write`/`edit` no longer hang on external paths. The plugin used to nag with an `Allow external directory access?` prompt even under the Pi default (`restrict_to_project_root: false`) which explicitly opts into no restriction. The plugin now defers to Rust without prompting in that case, expands `~/...` paths correctly, and bounds the prompt with a 30s timeout when strict mode is enabled.",
34345
+ "Tool descriptions trimmed: ~1.2K agent-facing tokens removed by dropping redundant `Returns:` blocks and compressing `lsp_diagnostics` while preserving its load-bearing honesty guidance."
34004
34346
  ];
34005
34347
  var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
34006
34348
  var ALL_ONLY_TOOLS = new Set([
@@ -34066,6 +34408,7 @@ function resolveToolSurface(config2) {
34066
34408
  const disabled = new Set(config2.disabled_tools ?? []);
34067
34409
  const ok = (name) => !disabled.has(name);
34068
34410
  const allOnly = (name) => ALL_ONLY_TOOLS.has(name) && ok(name);
34411
+ const restrictToProjectRoot = config2.restrict_to_project_root ?? false;
34069
34412
  if (surface === "minimal") {
34070
34413
  return {
34071
34414
  hoistBash: ok("bash"),
@@ -34073,6 +34416,7 @@ function resolveToolSurface(config2) {
34073
34416
  hoistWrite: false,
34074
34417
  hoistEdit: false,
34075
34418
  hoistGrep: false,
34419
+ restrictToProjectRoot,
34076
34420
  outline: ok("aft_outline"),
34077
34421
  zoom: ok("aft_zoom"),
34078
34422
  semantic: false,
@@ -34095,6 +34439,7 @@ function resolveToolSurface(config2) {
34095
34439
  hoistWrite: ok("write"),
34096
34440
  hoistEdit: ok("edit"),
34097
34441
  hoistGrep: ok("grep") && config2.search_index === true,
34442
+ restrictToProjectRoot,
34098
34443
  outline: ok("aft_outline"),
34099
34444
  zoom: ok("aft_zoom"),
34100
34445
  semantic: ok("aft_search") && config2.semantic_search === true,
@@ -18,6 +18,8 @@ export declare function coerceOptionalInt(v: unknown, paramName: string, min: nu
18
18
  export declare const LONG_RUNNING_COMMAND_TIMEOUT_MS: Record<string, number>;
19
19
  /** Returns the per-command timeout override, or undefined to use the bridge default. */
20
20
  export declare function timeoutForCommand(command: string): number | undefined;
21
+ /** Format bridge failure envelopes without dropping structured error data. */
22
+ export declare function formatBridgeErrorMessage(command: string, response: Record<string, unknown>, params?: Record<string, unknown>): string;
21
23
  /** Get the session bridge for the current working directory. */
22
24
  export declare function bridgeFor(ctx: PluginContext, cwd: string): BinaryBridge;
23
25
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/tools/_shared.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,8BACC,CAAC;AAExD,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,OAAO,EACV,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQlE,CAAC;AAEF,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AAED,gEAAgE;AAChE,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAEvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAK7E;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,MAAM,CAAC,EAAE,gBAAgB,EACzB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA0BlC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,GAAG,OAAO,EAC3C,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,QAAQ,GACjB,eAAe,CAAC,QAAQ,CAAC,CAK3B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,GAAG,OAAO,EAC/C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,OAAO,CAAC,EAAE,QAAQ,GACjB,eAAe,CAAC,QAAQ,CAAC,CAE3B;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGvF"}
1
+ {"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/tools/_shared.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,8BACC,CAAC;AAExD,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,OAAO,EACV,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CASlE,CAAC;AAEF,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AA2BD,8EAA8E;AAC9E,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,MAAM,CAsDR;AAsBD,gEAAgE;AAChE,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAEvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAK7E;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,MAAM,CAAC,EAAE,gBAAgB,EACzB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAsBlC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,GAAG,OAAO,EAC3C,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,QAAQ,GACjB,eAAe,CAAC,QAAQ,CAAC,CAK3B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,GAAG,OAAO,EAC/C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,OAAO,CAAC,EAAE,QAAQ,GACjB,eAAe,CAAC,QAAQ,CAAC,CAE3B;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGvF"}
@@ -1 +1 @@
1
- {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/tools/fs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAEL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,YAAY;;;EAWhB,CAAC;AAEH,QAAA,MAAM,UAAU;;;EAGd,CAAC;AAEH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wCAAwC;AACxC,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,YAAY,GAAG,UAAU,EACnC,IAAI,EAAE,MAAM,CAAC,OAAO,YAAY,CAAC,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,EAC7D,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAkB3B;AAED,wCAAwC;AACxC,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,YAAY,GAAG,UAAU,EACnC,IAAI,EAAE,MAAM,CAAC,OAAO,YAAY,CAAC,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,EAC7D,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAsC3B;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,GAAG,IAAI,CA+F9F"}
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/tools/fs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAEL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,YAAY;;;EAWhB,CAAC;AAEH,QAAA,MAAM,UAAU;;;EAOd,CAAC;AAEH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wCAAwC;AACxC,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,YAAY,GAAG,UAAU,EACnC,IAAI,EAAE,MAAM,CAAC,OAAO,YAAY,CAAC,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,EAC7D,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAkB3B;AAED,wCAAwC;AACxC,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,YAAY,GAAG,UAAU,EACnC,IAAI,EAAE,MAAM,CAAC,OAAO,YAAY,CAAC,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,EAC7D,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAsC3B;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,GAAG,IAAI,CA+F9F"}
@@ -23,6 +23,19 @@ export interface ToolSurfaceFlags {
23
23
  hoistWrite: boolean;
24
24
  hoistEdit: boolean;
25
25
  hoistGrep: boolean;
26
+ /**
27
+ * Mirrors the user's `restrict_to_project_root` AFT config (Pi default
28
+ * `false`). When false, the user has explicitly opted into "no
29
+ * restriction" — Pi has no host-level external_directory allow-list, so
30
+ * a `ui.confirm` prompt has no policy to consult and would only annoy
31
+ * the user. When true, Rust hard-rejects out-of-root paths before the
32
+ * plugin layer sees them anyway, so the prompt is also unreachable. We
33
+ * pass this through so `assertExternalDirectoryPermission` can skip the
34
+ * prompt in the false case (the common one) and the helper stays in
35
+ * place as a safety net for unusual contexts that opt into restriction
36
+ * but still want a chance to allow a one-off external write.
37
+ */
38
+ restrictToProjectRoot: boolean;
26
39
  }
27
40
  /** Details surfaced to both renderer and agent message stream. */
28
41
  interface FileMutationDetails {
@@ -1 +1 @@
1
- {"version":3,"file":"hoisted.d.ts","sourceRoot":"","sources":["../../src/tools/hoisted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,YAAY,EAGlB,MAAM,iCAAiC,CAAC;AAGzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA2EjD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,kEAAkE;AAClE,UAAU,mBAAmB;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAsMN;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,eAAe,CAAC,mBAAmB,CAAC,CAiGtC;AAyJD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CA0B3D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,mBAAmB,EAAE,OAAO,EAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAgBR"}
1
+ {"version":3,"file":"hoisted.d.ts","sourceRoot":"","sources":["../../src/tools/hoisted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,YAAY,EAGlB,MAAM,iCAAiC,CAAC;AAGzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA8JjD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;;;;;;OAWG;IACH,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAED,kEAAkE;AAClE,UAAU,mBAAmB;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,gBAAgB,GACxB,IAAI,CA4MN;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,eAAe,CAAC,mBAAmB,CAAC,CAiGtC;AA0JD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CA0B3D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,mBAAmB,EAAE,OAAO,EAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAgBR"}
@@ -1,17 +1,19 @@
1
1
  /**
2
2
  * aft_navigate — call-graph navigation across files.
3
- * Ops: call_tree, callers, trace_to, impact, trace_data.
3
+ * Ops: call_tree, callers, trace_to, trace_to_symbol, impact, trace_data.
4
4
  */
5
5
  import type { AgentToolResult, ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
6
6
  import { type Static, Type } from "typebox";
7
7
  import type { PluginContext } from "../types.js";
8
8
  import { type RenderContextLike } from "./render-helpers.js";
9
9
  declare function navigateParamsSchema(): Type.TObject<{
10
- op: Type.TUnsafe<"callers" | "trace_to" | "trace_data" | "impact" | "call_tree">;
10
+ op: Type.TUnsafe<"callers" | "trace_to" | "trace_to_symbol" | "trace_data" | "impact" | "call_tree">;
11
11
  filePath: Type.TString;
12
12
  symbol: Type.TString;
13
13
  depth: Type.TOptional<Type.TAny>;
14
14
  expression: Type.TOptional<Type.TString>;
15
+ toSymbol: Type.TOptional<Type.TString>;
16
+ toFile: Type.TOptional<Type.TString>;
15
17
  }>;
16
18
  type NavigateArgs = Static<ReturnType<typeof navigateParamsSchema>>;
17
19
  /** Exported for renderer unit tests. */
@@ -1 +1 @@
1
- {"version":3,"file":"navigate.d.ts","sourceRoot":"","sources":["../../src/tools/navigate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAQL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,iBAAS,oBAAoB;;;;;;GAY5B;AAED,KAAK,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC;AA6CpE,wCAAwC;AACxC,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,GACX,MAAM,EAAE,CA+FV;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,iBAAiB,yCAS9F;AAED,wCAAwC;AACxC,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAO3B;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CA8B/E"}
1
+ {"version":3,"file":"navigate.d.ts","sourceRoot":"","sources":["../../src/tools/navigate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAQL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,iBAAS,oBAAoB;;;;;;;;GA4B5B;AAED,KAAK,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC;AA6CpE,wCAAwC;AACxC,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,GACX,MAAM,EAAE,CAoHV;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,iBAAiB,yCAU9F;AAED,wCAAwC;AACxC,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAO3B;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAmC/E"}
@@ -8,12 +8,19 @@ import type { PluginContext } from "../types.js";
8
8
  import { type RenderContextLike } from "./render-helpers.js";
9
9
  declare const OutlineParams: Type.TObject<{
10
10
  target: Type.TUnion<[Type.TString, Type.TArray<Type.TString>]>;
11
+ files: Type.TOptional<Type.TBoolean>;
11
12
  }>;
12
13
  declare const ZoomParams: Type.TObject<{
13
14
  filePath: Type.TOptional<Type.TString>;
14
15
  url: Type.TOptional<Type.TString>;
15
- symbol: Type.TOptional<Type.TString>;
16
- symbols: Type.TOptional<Type.TArray<Type.TString>>;
16
+ symbols: Type.TOptional<Type.TUnion<[Type.TString, Type.TArray<Type.TString>]>>;
17
+ targets: Type.TOptional<Type.TUnion<[Type.TObject<{
18
+ filePath: Type.TString;
19
+ symbol: Type.TString;
20
+ }>, Type.TArray<Type.TObject<{
21
+ filePath: Type.TString;
22
+ symbol: Type.TString;
23
+ }>>]>>;
17
24
  contextLines: Type.TOptional<Type.TNumber>;
18
25
  }>;
19
26
  export interface ReadingSurface {
@@ -54,5 +61,6 @@ export declare function registerReadingTools(pi: ExtensionAPI, ctx: PluginContex
54
61
  * `@cortexkit/aft-bridge` so the agent sees the same shape across hosts.
55
62
  */
56
63
  export declare function formatZoomBatchResult(targetLabel: string, symbols: string[], responses: Record<string, unknown>[]): ZoomBatchResult;
64
+ export declare function formatOutlineFilesText(response: Record<string, unknown>): string;
57
65
  export {};
58
66
  //# sourceMappingURL=reading.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reading.d.ts","sourceRoot":"","sources":["../../src/tools/reading.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAOL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,aAAa;;EAKjB,CAAC;AAEH,QAAA,MAAM,UAAU;;;;;;EAkBd,CAAC;AAWH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,UAAU,qBAAqB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,eAAe;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wCAAwC;AACxC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,CAOzE;AAED,wCAAwC;AACxC,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,OAAO,UAAU,CAAC,EAC/B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,GACX,MAAM,EAAE,CAwFV;AAED,wCAAwC;AACxC,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,OAAO,aAAa,CAAC,EAClC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAQ3B;AAED,wCAAwC;AACxC,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAI3B;AAED,wCAAwC;AACxC,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,CAAC,OAAO,UAAU,CAAC,EAC/B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAa3B;AAED,wCAAwC;AACxC,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,IAAI,EAAE,MAAM,CAAC,OAAO,UAAU,CAAC,EAC/B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAI3B;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,cAAc,GACtB,IAAI,CAiJN;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GACnC,eAAe,CAyBjB"}
1
+ {"version":3,"file":"reading.d.ts","sourceRoot":"","sources":["../../src/tools/reading.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAOL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,aAAa;;;EAWjB,CAAC;AAOH,QAAA,MAAM,UAAU;;;;;;;;;;;;EAwBd,CAAC;AAWH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,UAAU,qBAAqB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,eAAe;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wCAAwC;AACxC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,CAOzE;AAED,wCAAwC;AACxC,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,OAAO,UAAU,CAAC,EAC/B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,GACX,MAAM,EAAE,CAwFV;AAED,wCAAwC;AACxC,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,OAAO,aAAa,CAAC,EAClC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAQ3B;AAED,wCAAwC;AACxC,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAI3B;AAED,wCAAwC;AACxC,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,CAAC,OAAO,UAAU,CAAC,EAC/B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAuB3B;AAED,wCAAwC;AACxC,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,IAAI,EAAE,MAAM,CAAC,OAAO,UAAU,CAAC,EAC/B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAI3B;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,cAAc,GACtB,IAAI,CAwPN;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GACnC,eAAe,CAyBjB;AA0BD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CA2ChF"}
@@ -1 +1 @@
1
- {"version":3,"file":"refactor.d.ts","sourceRoot":"","sources":["../../src/tools/refactor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAOL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,cAAc;;;;;;;;;;EAUlB,CAAC;AAEH,wCAAwC;AACxC,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,OAAO,cAAc,CAAC,EACnC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,GACX,MAAM,EAAE,CAiCV;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,CAAC,OAAO,cAAc,CAAC,EACnC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAU3B;AAED,wCAAwC;AACxC,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,IAAI,EAAE,MAAM,CAAC,OAAO,cAAc,CAAC,EACnC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAO3B;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAsD/E"}
1
+ {"version":3,"file":"refactor.d.ts","sourceRoot":"","sources":["../../src/tools/refactor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAOL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,cAAc;;;;;;;;;;EAYlB,CAAC;AAEH,wCAAwC;AACxC,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,OAAO,cAAc,CAAC,EACnC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,GACX,MAAM,EAAE,CAiCV;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,CAAC,OAAO,cAAc,CAAC,EACnC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAU3B;AAED,wCAAwC;AACxC,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,IAAI,EAAE,MAAM,CAAC,OAAO,cAAc,CAAC,EACnC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAO3B;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAsD/E"}
@@ -1 +1 @@
1
- {"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/tools/safety.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAQL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,YAAY;;;;;EAehB,CAAC;AAEH,wCAAwC;AACxC,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,CAAC,OAAO,YAAY,CAAC,EACjC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,GACX,MAAM,EAAE,CA4EV;AAED,wCAAwC;AACxC,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,CAAC,OAAO,YAAY,CAAC,EACjC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAO3B;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,IAAI,EAAE,MAAM,CAAC,OAAO,YAAY,CAAC,EACjC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAO3B;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAwD7E"}
1
+ {"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/tools/safety.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAQL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,YAAY;;;;;EAkBhB,CAAC;AAEH,wCAAwC;AACxC,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,CAAC,OAAO,YAAY,CAAC,EACjC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,GACX,MAAM,EAAE,CA4EV;AAED,wCAAwC;AACxC,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,CAAC,OAAO,YAAY,CAAC,EACjC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAO3B;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,IAAI,EAAE,MAAM,CAAC,OAAO,YAAY,CAAC,EACjC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAO3B;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAwD7E"}
@@ -1 +1 @@
1
- {"version":3,"file":"structure.d.ts","sourceRoot":"","sources":["../../src/tools/structure.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAKL,KAAK,iBAAiB,EAIvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,eAAe;;;;;;;;;;;;;;EAgCnB,CAAC;AAEH,wCAAwC;AACxC,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,CAAC,OAAO,eAAe,CAAC,EACpC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,GACX,MAAM,EAAE,CAiBV;AAED,wCAAwC;AACxC,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,CAAC,OAAO,eAAe,CAAC,EACpC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAW3B;AAED,wCAAwC;AACxC,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,IAAI,EAAE,MAAM,CAAC,OAAO,eAAe,CAAC,EACpC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAO3B;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAwChF"}
1
+ {"version":3,"file":"structure.d.ts","sourceRoot":"","sources":["../../src/tools/structure.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAKL,KAAK,iBAAiB,EAIvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,eAAe;;;;;;;;;;;;;;EAkCnB,CAAC;AAEH,wCAAwC;AACxC,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,CAAC,OAAO,eAAe,CAAC,EACpC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,GACX,MAAM,EAAE,CAiBV;AAED,wCAAwC;AACxC,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,CAAC,OAAO,eAAe,CAAC,EACpC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,yCAW3B;AAED,wCAAwC;AACxC,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,IAAI,EAAE,MAAM,CAAC,OAAO,eAAe,CAAC,EACpC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,sFAO3B;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAwChF"}
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-hints.d.ts","sourceRoot":"","sources":["../src/workflow-hints.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7C,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,SAAS,GAAG,aAAa,GAAG,KAAK,CAAC;IAC/C,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kEAAkE;IAClE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC1B;AAID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,CA8DzE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,aAAa,EAAE,OAAO,GACrB,MAAM,GAAG,IAAI,CAYf;AAMD,UAAU,gBAAgB;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,YAAY,EAChB,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,gBAAgB,GACxB,IAAI,CA8BN"}
1
+ {"version":3,"file":"workflow-hints.d.ts","sourceRoot":"","sources":["../src/workflow-hints.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7C,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,SAAS,GAAG,aAAa,GAAG,KAAK,CAAC;IAC/C,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kEAAkE;IAClE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC1B;AAID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,CA+DzE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,aAAa,EAAE,OAAO,GACrB,MAAM,GAAG,IAAI,CAYf;AAMD,UAAU,gBAAgB;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,YAAY,EAChB,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,gBAAgB,GACxB,IAAI,CA8BN"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/aft-pi",
3
- "version": "0.30.3",
3
+ "version": "0.31.1",
4
4
  "type": "module",
5
5
  "description": "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "prepublishOnly": "bun run build"
23
23
  },
24
24
  "dependencies": {
25
- "@cortexkit/aft-bridge": "0.30.3",
25
+ "@cortexkit/aft-bridge": "0.31.1",
26
26
  "@xterm/headless": "^5.5.0",
27
27
  "comment-json": "^5.0.0",
28
28
  "diff": "^8.0.4",
@@ -30,12 +30,12 @@
30
30
  "zod": "^4.1.8"
31
31
  },
32
32
  "optionalDependencies": {
33
- "@cortexkit/aft-darwin-arm64": "0.30.3",
34
- "@cortexkit/aft-darwin-x64": "0.30.3",
35
- "@cortexkit/aft-linux-arm64": "0.30.3",
36
- "@cortexkit/aft-linux-x64": "0.30.3",
37
- "@cortexkit/aft-win32-arm64": "0.30.3",
38
- "@cortexkit/aft-win32-x64": "0.30.3"
33
+ "@cortexkit/aft-darwin-arm64": "0.31.1",
34
+ "@cortexkit/aft-darwin-x64": "0.31.1",
35
+ "@cortexkit/aft-linux-arm64": "0.31.1",
36
+ "@cortexkit/aft-linux-x64": "0.31.1",
37
+ "@cortexkit/aft-win32-arm64": "0.31.1",
38
+ "@cortexkit/aft-win32-x64": "0.31.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@earendil-works/pi-coding-agent": "*",