@cortexkit/aft-pi 0.30.3 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -13827,6 +13827,36 @@ function formatZoomText(targetLabel, response) {
13827
13827
  return out.join(`
13828
13828
  `);
13829
13829
  }
13830
+ function formatZoomMultiTargetResult(entries) {
13831
+ const rendered = entries.map((entry) => {
13832
+ const { targetLabel, name, response } = entry;
13833
+ if (response.success === false) {
13834
+ const message = typeof response.message === "string" && response.message.length > 0 ? response.message : "zoom failed";
13835
+ return { targetLabel, name, success: false, error: message };
13836
+ }
13837
+ return {
13838
+ targetLabel,
13839
+ name,
13840
+ success: true,
13841
+ content: formatZoomText(targetLabel, response)
13842
+ };
13843
+ });
13844
+ const complete = rendered.every((entry) => entry.success);
13845
+ const sections = [];
13846
+ if (!complete) {
13847
+ sections.push("Incomplete zoom results: one or more symbols failed.");
13848
+ }
13849
+ for (const entry of rendered) {
13850
+ if (entry.success) {
13851
+ sections.push(entry.content ?? "");
13852
+ } else {
13853
+ sections.push(`Symbol "${entry.name}" not found in ${entry.targetLabel}: ${entry.error ?? "zoom failed"}`);
13854
+ }
13855
+ }
13856
+ return { complete, entries: rendered, text: sections.join(`
13857
+
13858
+ `) };
13859
+ }
13830
13860
  // src/logger.ts
13831
13861
  import * as fs from "node:fs";
13832
13862
  import * as os from "node:os";
@@ -14475,7 +14505,7 @@ import {
14475
14505
  // package.json
14476
14506
  var package_default = {
14477
14507
  name: "@cortexkit/aft-pi",
14478
- version: "0.30.3",
14508
+ version: "0.31.0",
14479
14509
  type: "module",
14480
14510
  description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
14481
14511
  main: "dist/index.js",
@@ -14497,7 +14527,7 @@ var package_default = {
14497
14527
  prepublishOnly: "bun run build"
14498
14528
  },
14499
14529
  dependencies: {
14500
- "@cortexkit/aft-bridge": "0.30.3",
14530
+ "@cortexkit/aft-bridge": "0.31.0",
14501
14531
  "@xterm/headless": "^5.5.0",
14502
14532
  "comment-json": "^5.0.0",
14503
14533
  diff: "^8.0.4",
@@ -14505,12 +14535,12 @@ var package_default = {
14505
14535
  zod: "^4.1.8"
14506
14536
  },
14507
14537
  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"
14538
+ "@cortexkit/aft-darwin-arm64": "0.31.0",
14539
+ "@cortexkit/aft-darwin-x64": "0.31.0",
14540
+ "@cortexkit/aft-linux-arm64": "0.31.0",
14541
+ "@cortexkit/aft-linux-x64": "0.31.0",
14542
+ "@cortexkit/aft-win32-arm64": "0.31.0",
14543
+ "@cortexkit/aft-win32-x64": "0.31.0"
14514
14544
  },
14515
14545
  devDependencies: {
14516
14546
  "@earendil-works/pi-coding-agent": "*",
@@ -14723,6 +14753,7 @@ function coerceOptionalInt(v, paramName, min, max) {
14723
14753
  var LONG_RUNNING_COMMAND_TIMEOUT_MS = {
14724
14754
  callers: 60000,
14725
14755
  trace_to: 60000,
14756
+ trace_to_symbol: 60000,
14726
14757
  trace_data: 60000,
14727
14758
  impact: 60000,
14728
14759
  grep: 60000,
@@ -14732,6 +14763,68 @@ var LONG_RUNNING_COMMAND_TIMEOUT_MS = {
14732
14763
  function timeoutForCommand(command) {
14733
14764
  return LONG_RUNNING_COMMAND_TIMEOUT_MS[command];
14734
14765
  }
14766
+ function asPlainObject(value) {
14767
+ if (!value || typeof value !== "object" || Array.isArray(value))
14768
+ return;
14769
+ return value;
14770
+ }
14771
+ function candidateLocation(candidate) {
14772
+ const file = typeof candidate.file === "string" && candidate.file.length > 0 ? candidate.file : undefined;
14773
+ if (!file)
14774
+ return;
14775
+ const line = typeof candidate.line === "number" && Number.isFinite(candidate.line) ? candidate.line : undefined;
14776
+ return line === undefined ? file : `${file}:${line}`;
14777
+ }
14778
+ function stringifyData(data) {
14779
+ if (data === undefined)
14780
+ return;
14781
+ try {
14782
+ return JSON.stringify(data, null, 2);
14783
+ } catch {
14784
+ return String(data);
14785
+ }
14786
+ }
14787
+ function formatBridgeErrorMessage(command, response, params = {}) {
14788
+ const code = typeof response.code === "string" && response.code.length > 0 ? response.code : undefined;
14789
+ const message = typeof response.message === "string" && response.message.length > 0 ? response.message : `${command} failed`;
14790
+ const data = asPlainObject(response.data);
14791
+ const rawCandidates = Array.isArray(response.candidates) ? response.candidates : Array.isArray(data?.candidates) ? data.candidates : undefined;
14792
+ const rawSymbol = typeof response.symbol === "string" && response.symbol.length > 0 ? response.symbol : typeof data?.symbol === "string" && data.symbol.length > 0 ? data.symbol : undefined;
14793
+ if (code === "ambiguous_target" || code === "target_symbol_not_in_file") {
14794
+ const candidates = (rawCandidates ?? []).map(asPlainObject).filter((candidate) => candidate !== undefined).map(candidateLocation).filter((candidate) => candidate !== undefined);
14795
+ if (candidates.length > 0) {
14796
+ const symbol = typeof params.toSymbol === "string" && params.toSymbol.length > 0 ? params.toSymbol : rawSymbol;
14797
+ const target = symbol ? `multiple symbols named "${symbol}"` : message.replace(/[.!?]+$/, "");
14798
+ const action = code === "ambiguous_target" ? "Pass toFile to disambiguate" : "Try one of these files for toFile";
14799
+ return `${command}: ${code} — ${target}. ${action}:
14800
+ ${candidates.map((candidate) => ` - ${candidate}`).join(`
14801
+ `)}`;
14802
+ }
14803
+ }
14804
+ if (!code)
14805
+ return message;
14806
+ const lines = [`${command}: ${code} — ${message}`];
14807
+ const extras = collectStructuredExtras(response);
14808
+ if (extras)
14809
+ lines.push(`data: ${extras}`);
14810
+ return lines.join(`
14811
+ `);
14812
+ }
14813
+ function collectStructuredExtras(response) {
14814
+ const reserved = new Set(["id", "success", "code", "message", "data"]);
14815
+ const extras = {};
14816
+ for (const [key, value] of Object.entries(response)) {
14817
+ if (reserved.has(key))
14818
+ continue;
14819
+ extras[key] = value;
14820
+ }
14821
+ if (Object.keys(extras).length === 0) {
14822
+ return stringifyData(response.data);
14823
+ }
14824
+ if (response.data !== undefined)
14825
+ extras.data = response.data;
14826
+ return stringifyData(extras);
14827
+ }
14735
14828
  function bridgeFor(ctx, cwd) {
14736
14829
  return ctx.pool.getBridge(cwd);
14737
14830
  }
@@ -14754,8 +14847,7 @@ async function callBridge(bridge, command, params = {}, extCtx, options) {
14754
14847
  };
14755
14848
  const response = await bridge.send(command, merged, Object.keys(sendOptions).length > 0 ? sendOptions : undefined);
14756
14849
  if (response.success === false) {
14757
- const message = typeof response.message === "string" && response.message.length > 0 ? response.message : `${command} failed`;
14758
- throw new Error(message);
14850
+ throw new Error(formatBridgeErrorMessage(command, response, merged));
14759
14851
  }
14760
14852
  ingestBgCompletions(sessionId, response.bg_completions);
14761
14853
  return response;
@@ -31708,7 +31800,7 @@ function createBashStatusTool(ctx) {
31708
31800
  return {
31709
31801
  name: "bash_status",
31710
31802
  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.",
31803
+ 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
31804
  promptSnippet: "Inspect a background bash task by task_id",
31713
31805
  parameters: BashStatusParams,
31714
31806
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
@@ -32170,8 +32262,12 @@ var DeleteParams = Type5.Object({
32170
32262
  }))
32171
32263
  });
32172
32264
  var MoveParams = Type5.Object({
32173
- filePath: Type5.String({ description: "Source file path to move" }),
32174
- destination: Type5.String({ description: "Destination file path" })
32265
+ filePath: Type5.String({
32266
+ description: "Source file path to move (absolute or relative to project root)"
32267
+ }),
32268
+ destination: Type5.String({
32269
+ description: "Destination file path (absolute or relative to project root)"
32270
+ })
32175
32271
  });
32176
32272
  function renderFsCall(toolName, args, theme, context) {
32177
32273
  if (toolName === "aft_delete") {
@@ -32274,7 +32370,7 @@ function registerFsTools(pi, ctx, surface) {
32274
32370
  // src/tools/hoisted.ts
32275
32371
  import { stat } from "node:fs/promises";
32276
32372
  import { homedir as homedir9 } from "node:os";
32277
- import { isAbsolute, relative as relative3, resolve as resolve3 } from "node:path";
32373
+ import { isAbsolute, relative as relative3, resolve as resolve3, sep } from "node:path";
32278
32374
  import {
32279
32375
  renderDiff as renderDiff2
32280
32376
  } from "@earendil-works/pi-coding-agent";
@@ -32388,30 +32484,74 @@ function containsPath(parent, child) {
32388
32484
  const rel = relative3(parent, child);
32389
32485
  return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
32390
32486
  }
32391
- async function assertExternalDirectoryPermission(extCtx, target, action = "modify") {
32487
+ function expandTilde(path2) {
32488
+ if (!path2 || !path2.startsWith("~"))
32489
+ return path2;
32490
+ if (path2 === "~")
32491
+ return homedir9();
32492
+ if (path2.startsWith(`~${sep}`) || path2.startsWith("~/")) {
32493
+ return resolve3(homedir9(), path2.slice(2));
32494
+ }
32495
+ return path2;
32496
+ }
32497
+ function externalDirectoryPromptTimeoutMs() {
32498
+ const raw = process.env.AFT_PI_EXTERNAL_PROMPT_TIMEOUT_MS;
32499
+ if (raw === undefined)
32500
+ return 30000;
32501
+ const parsed = Number.parseInt(raw, 10);
32502
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 30000;
32503
+ }
32504
+ async function assertExternalDirectoryPermission(extCtx, target, action = "modify", options = {}) {
32392
32505
  if (!target)
32393
32506
  return;
32394
- const absoluteTarget = isAbsolute(target) ? target : resolve3(extCtx.cwd, target);
32507
+ const expanded = expandTilde(target);
32508
+ const absoluteTarget = isAbsolute(expanded) ? expanded : resolve3(extCtx.cwd, expanded);
32395
32509
  if (containsPath(extCtx.cwd, absoluteTarget))
32396
32510
  return;
32397
- const confirmed = await extCtx.ui?.confirm?.("Allow external directory access?", `AFT wants to ${action} outside the project: ${absoluteTarget}`);
32398
- if (confirmed === true)
32511
+ if (options.restrictToProjectRoot === false)
32399
32512
  return;
32400
- throw new Error("Permission denied: external directory access was cancelled.");
32513
+ const confirmFn = extCtx.ui?.confirm;
32514
+ if (extCtx.hasUI === false || !confirmFn) {
32515
+ throw new Error(`Permission denied: cannot prompt for ${action} outside the project (${absoluteTarget}).`);
32516
+ }
32517
+ const timeoutMs = externalDirectoryPromptTimeoutMs();
32518
+ let timer;
32519
+ const timeoutPromise = new Promise((resolve4) => {
32520
+ timer = setTimeout(() => resolve4("timeout"), timeoutMs);
32521
+ });
32522
+ try {
32523
+ const result = await Promise.race([
32524
+ confirmFn("Allow external directory access?", `AFT wants to ${action} outside the project: ${absoluteTarget}`),
32525
+ timeoutPromise
32526
+ ]);
32527
+ if (result === true)
32528
+ return;
32529
+ if (result === "timeout") {
32530
+ throw new Error(`Permission denied: external directory prompt timed out after ${timeoutMs}ms.`);
32531
+ }
32532
+ throw new Error("Permission denied: external directory access was cancelled.");
32533
+ } finally {
32534
+ if (timer !== undefined)
32535
+ clearTimeout(timer);
32536
+ }
32401
32537
  }
32402
32538
  var ReadParams = Type6.Object({
32403
- path: Type6.String({ description: "Path to the file to read (relative or absolute)" }),
32539
+ path: Type6.String({
32540
+ description: "Path to the file to read (absolute or relative to project root)"
32541
+ }),
32404
32542
  offset: optionalInt(1, Number.MAX_SAFE_INTEGER),
32405
32543
  limit: optionalInt(1, Number.MAX_SAFE_INTEGER)
32406
32544
  });
32407
32545
  var WriteParams = Type6.Object({
32408
32546
  filePath: Type6.String({
32409
- description: "Path to the file to write (absolute or project-relative)"
32547
+ description: "Path to the file to write (absolute or relative to project root)"
32410
32548
  }),
32411
32549
  content: Type6.String({ description: "Full file contents to write" })
32412
32550
  });
32413
32551
  var EditParams = Type6.Object({
32414
- filePath: Type6.String({ description: "Path to the file to edit" }),
32552
+ filePath: Type6.String({
32553
+ description: "Path to the file to edit (absolute or relative to project root)"
32554
+ }),
32415
32555
  oldString: Type6.Optional(Type6.String({ description: "Text to find (exact match, fuzzy fallback)" })),
32416
32556
  newString: Type6.Optional(Type6.String({ description: "Replacement text (omit to delete match)" })),
32417
32557
  replaceAll: Type6.Optional(Type6.Boolean({ description: "Replace every occurrence" })),
@@ -32422,7 +32562,9 @@ var EditParams = Type6.Object({
32422
32562
  });
32423
32563
  var GrepParams = Type6.Object({
32424
32564
  pattern: Type6.String({ description: "Regex pattern to search for" }),
32425
- path: Type6.Optional(Type6.String({ description: "Path scope (file or directory)" })),
32565
+ path: Type6.Optional(Type6.String({
32566
+ description: "Path scope (file or directory; absolute or relative to project root)"
32567
+ })),
32426
32568
  include: Type6.Optional(Type6.String({ description: "Glob filter for included files (e.g. '*.ts,*.tsx')" })),
32427
32569
  caseSensitive: Type6.Optional(Type6.Boolean({ description: "Case-sensitive matching" })),
32428
32570
  contextLines: optionalInt(1, Number.MAX_SAFE_INTEGER)
@@ -32472,7 +32614,9 @@ function registerHoistedTools(pi, ctx, surface) {
32472
32614
  promptGuidelines: ["Use write only for new files or complete rewrites."],
32473
32615
  parameters: WriteParams,
32474
32616
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
32475
- await assertExternalDirectoryPermission(extCtx, params.filePath, "modify");
32617
+ await assertExternalDirectoryPermission(extCtx, params.filePath, "modify", {
32618
+ restrictToProjectRoot: surface.restrictToProjectRoot
32619
+ });
32476
32620
  const bridge = bridgeFor(ctx, extCtx.cwd);
32477
32621
  const response = await callBridge(bridge, "write", {
32478
32622
  file: params.filePath,
@@ -32503,7 +32647,9 @@ function registerHoistedTools(pi, ctx, surface) {
32503
32647
  ],
32504
32648
  parameters: EditParams,
32505
32649
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
32506
- await assertExternalDirectoryPermission(extCtx, params.filePath, "modify");
32650
+ await assertExternalDirectoryPermission(extCtx, params.filePath, "modify", {
32651
+ restrictToProjectRoot: surface.restrictToProjectRoot
32652
+ });
32507
32653
  const bridge = bridgeFor(ctx, extCtx.cwd);
32508
32654
  if (typeof params.appendContent === "string") {
32509
32655
  const req2 = {
@@ -32551,7 +32697,9 @@ function registerHoistedTools(pi, ctx, surface) {
32551
32697
  const bridge = bridgeFor(ctx, extCtx.cwd);
32552
32698
  const req = { pattern: params.pattern };
32553
32699
  if (params.path) {
32554
- await assertExternalDirectoryPermission(extCtx, params.path, "search");
32700
+ await assertExternalDirectoryPermission(extCtx, params.path, "search", {
32701
+ restrictToProjectRoot: surface.restrictToProjectRoot
32702
+ });
32555
32703
  req.path = await resolvePathArg(extCtx.cwd, params.path);
32556
32704
  }
32557
32705
  if (params.include)
@@ -32724,12 +32872,13 @@ function shortenPath2(path2) {
32724
32872
  return path2;
32725
32873
  }
32726
32874
  async function resolvePathArg(cwd, path2) {
32727
- const abs = resolve3(cwd, path2);
32875
+ const expanded = expandTilde(path2);
32876
+ const abs = isAbsolute(expanded) ? expanded : resolve3(cwd, expanded);
32728
32877
  try {
32729
32878
  await stat(abs);
32730
32879
  return abs;
32731
32880
  } catch {
32732
- return path2;
32881
+ return expanded;
32733
32882
  }
32734
32883
  }
32735
32884
  function splitIncludeGlobs(include) {
@@ -32782,7 +32931,7 @@ import { StringEnum as StringEnum2 } from "@earendil-works/pi-ai";
32782
32931
  import { Type as Type7 } from "typebox";
32783
32932
  var ImportParams = Type7.Object({
32784
32933
  op: StringEnum2(["add", "remove", "organize"], { description: "Import operation" }),
32785
- filePath: Type7.String({ description: "Path to the file" }),
32934
+ filePath: Type7.String({ description: "Path to the file (absolute or relative to project root)" }),
32786
32935
  module: Type7.Optional(Type7.String({ description: "Module path (required for add/remove), e.g. 'react', './utils'" })),
32787
32936
  names: Type7.Optional(Type7.Array(Type7.String(), { description: "Named imports to add, e.g. ['useState']" })),
32788
32937
  defaultImport: Type7.Optional(Type7.String({ description: "Default import name (e.g. 'React')" })),
@@ -32939,7 +33088,7 @@ function registerLspTools(pi, ctx) {
32939
33088
  pi.registerTool({
32940
33089
  name: "lsp_diagnostics",
32941
33090
  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).",
33091
+ 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
33092
  parameters: LspDiagnosticsParams,
32944
33093
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
32945
33094
  const hasFile = typeof params.filePath === "string" && params.filePath.length > 0;
@@ -32974,13 +33123,21 @@ import { StringEnum as StringEnum4 } from "@earendil-works/pi-ai";
32974
33123
  import { Type as Type9 } from "typebox";
32975
33124
  function navigateParamsSchema() {
32976
33125
  return Type9.Object({
32977
- op: StringEnum4(["call_tree", "callers", "trace_to", "impact", "trace_data"], {
33126
+ op: StringEnum4(["call_tree", "callers", "trace_to", "trace_to_symbol", "impact", "trace_data"], {
32978
33127
  description: "Navigation operation"
32979
33128
  }),
32980
- filePath: Type9.String({ description: "Source file containing the symbol" }),
33129
+ filePath: Type9.String({
33130
+ description: "Source file containing the symbol (absolute or relative to project root)"
33131
+ }),
32981
33132
  symbol: Type9.String({ description: "Name of the symbol to analyze" }),
32982
33133
  depth: optionalInt(1, Number.MAX_SAFE_INTEGER),
32983
- expression: Type9.Optional(Type9.String({ description: "Expression to track (required for trace_data)" }))
33134
+ expression: Type9.Optional(Type9.String({ description: "Expression to track (required for trace_data)" })),
33135
+ toSymbol: Type9.Optional(Type9.String({
33136
+ description: "Target symbol for trace_to_symbol; the returned path ends here"
33137
+ })),
33138
+ toFile: Type9.Optional(Type9.String({
33139
+ description: "Optional target file for trace_to_symbol; required when toSymbol exists in multiple files"
33140
+ }))
32984
33141
  });
32985
33142
  }
32986
33143
  function treeLine(depth, text) {
@@ -33042,6 +33199,23 @@ function buildNavigateSections(args, payload, theme) {
33042
33199
  });
33043
33200
  return sections2;
33044
33201
  }
33202
+ if (args.op === "trace_to_symbol") {
33203
+ const path2 = asRecords(response.path);
33204
+ const complete = asBoolean(response.complete);
33205
+ const reason = asString(response.reason);
33206
+ if (path2.length === 0) {
33207
+ const prefix = complete === false ? theme.fg("warning", "No complete path") : theme.fg("muted", "No path");
33208
+ return [`${prefix}${reason ? ` (${reason})` : ""}`];
33209
+ }
33210
+ const lines = [theme.fg("success", `${path2.length} hop${path2.length === 1 ? "" : "s"}`)];
33211
+ path2.forEach((hop, index) => {
33212
+ const symbol2 = asString(hop.symbol) ?? "(unknown)";
33213
+ const file2 = shortenPath(asString(hop.file) ?? "(unknown file)");
33214
+ const line = asNumber(hop.line);
33215
+ lines.push(treeLine(index + 1, `${symbol2} ${line !== undefined ? `[${file2}:${line}]` : `[${file2}]`}`));
33216
+ });
33217
+ return lines;
33218
+ }
33045
33219
  if (args.op === "trace_to") {
33046
33220
  const paths = asRecords(response.paths);
33047
33221
  const warning = depthWarning(response, theme, "max_depth_reached", "truncated_paths");
@@ -33103,7 +33277,8 @@ function renderNavigateCall(args, theme, context) {
33103
33277
  const summary = [
33104
33278
  theme.fg("accent", args.op),
33105
33279
  accentPath(theme, args.filePath),
33106
- theme.fg("toolOutput", args.symbol)
33280
+ theme.fg("toolOutput", args.symbol),
33281
+ args.toSymbol ? theme.fg("toolOutput", `→ ${args.toSymbol}`) : undefined
33107
33282
  ].filter(Boolean).join(" ");
33108
33283
  return renderToolCall("navigate", summary, theme, context);
33109
33284
  }
@@ -33116,12 +33291,15 @@ function registerNavigateTool(pi, ctx) {
33116
33291
  pi.registerTool({
33117
33292
  name: "aft_navigate",
33118
33293
  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.",
33294
+ 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
33295
  parameters: navigateParamsSchema(),
33121
33296
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
33122
33297
  if (params.op === "trace_data" && !params.expression) {
33123
33298
  throw new Error("op='trace_data' requires an `expression`");
33124
33299
  }
33300
+ if (params.op === "trace_to_symbol" && !params.toSymbol) {
33301
+ throw new Error("op='trace_to_symbol' requires a `toSymbol`");
33302
+ }
33125
33303
  const bridge = bridgeFor(ctx, extCtx.cwd);
33126
33304
  const req = {
33127
33305
  op: params.op,
@@ -33133,6 +33311,10 @@ function registerNavigateTool(pi, ctx) {
33133
33311
  req.depth = depth;
33134
33312
  if (params.expression !== undefined)
33135
33313
  req.expression = params.expression;
33314
+ if (params.toSymbol !== undefined)
33315
+ req.toSymbol = params.toSymbol;
33316
+ if (params.toFile !== undefined)
33317
+ req.toFile = params.toFile;
33136
33318
  const response = await callBridge(bridge, params.op, req, extCtx);
33137
33319
  return textResult(JSON.stringify(response, null, 2));
33138
33320
  },
@@ -33152,15 +33334,26 @@ import { Type as Type10 } from "typebox";
33152
33334
  var OutlineParams = Type10.Object({
33153
33335
  target: Type10.Union([Type10.String(), Type10.Array(Type10.String())], {
33154
33336
  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
- })
33337
+ }),
33338
+ files: Type10.Optional(Type10.Boolean({
33339
+ 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."
33340
+ }))
33341
+ });
33342
+ var ZoomTarget = Type10.Object({
33343
+ filePath: Type10.String({ description: "Path to file (absolute or project-relative)" }),
33344
+ symbol: Type10.String({ description: "Symbol name in that file" })
33156
33345
  });
33157
33346
  var ZoomParams = Type10.Object({
33158
33347
  filePath: Type10.Optional(Type10.String({ description: "Path to file (absolute or project-relative)" })),
33159
33348
  url: Type10.Optional(Type10.String({
33160
33349
  description: "HTTP/HTTPS URL of an HTML or Markdown document to fetch and zoom into"
33161
33350
  })),
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" })),
33351
+ symbols: Type10.Optional(Type10.Union([Type10.String(), Type10.Array(Type10.String())], {
33352
+ 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."
33353
+ })),
33354
+ targets: Type10.Optional(Type10.Union([ZoomTarget, Type10.Array(ZoomTarget)], {
33355
+ description: "Cross-file batch: `{ filePath, symbol }` or an array of them. Mutually exclusive with filePath/url/symbols."
33356
+ })),
33164
33357
  contextLines: Type10.Optional(Type10.Number({ description: "Lines of context before/after (default: 3)" }))
33165
33358
  });
33166
33359
  function isUrl(s) {
@@ -33241,7 +33434,7 @@ function buildZoomSections(args, payload, theme) {
33241
33434
  }).filter(Boolean);
33242
33435
  }
33243
33436
  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;
33437
+ 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
33438
  return renderToolCall("outline", summary, theme, context);
33246
33439
  }
33247
33440
  function renderOutlineResult(result, theme, context) {
@@ -33250,8 +33443,21 @@ function renderOutlineResult(result, theme, context) {
33250
33443
  return renderSections(buildOutlineSections(collectTextContent(result), theme), context);
33251
33444
  }
33252
33445
  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);
33446
+ const symbols = args.symbols;
33447
+ const targets = args.targets;
33448
+ let summary;
33449
+ if (typeof symbols === "string") {
33450
+ summary = theme.fg("toolOutput", symbols);
33451
+ } else if (Array.isArray(symbols) && symbols.length > 0) {
33452
+ summary = theme.fg("toolOutput", `${symbols.length} symbols`);
33453
+ } else if (Array.isArray(targets) && targets.length > 0) {
33454
+ summary = theme.fg("toolOutput", `${targets.length} targets`);
33455
+ } else if (targets && typeof targets === "object" && !Array.isArray(targets)) {
33456
+ summary = theme.fg("toolOutput", targets.symbol ?? "1 target");
33457
+ } else {
33458
+ summary = theme.fg("toolOutput", "lines");
33459
+ }
33460
+ return renderToolCall("zoom", `${accentPath(theme, zoomTargetLabel(args))} ${summary}`, theme, context);
33255
33461
  }
33256
33462
  function renderZoomResult(result, args, theme, context) {
33257
33463
  if (context.isError)
@@ -33263,18 +33469,46 @@ function registerReadingTools(pi, ctx, surface) {
33263
33469
  pi.registerTool({
33264
33470
  name: "aft_outline",
33265
33471
  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.
33472
+ 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
33473
 
33268
33474
  Pass a single \`target\`:
33269
33475
  • file path → outline that file (with signatures)
33270
33476
  • directory path → outline source files under it (recursively, up to 200 files)
33271
33477
  • URL (http:// or https://) → fetch and outline a remote HTML/Markdown document
33272
- • array of paths → outline multiple files in one call`,
33478
+ • array of paths → outline multiple files in one call; with files:true, every path must be a directory`,
33273
33479
  parameters: OutlineParams,
33274
33480
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
33275
33481
  const bridge = bridgeFor(ctx, extCtx.cwd);
33276
33482
  const target = params.target;
33483
+ const filesMode = params.files === true;
33277
33484
  const isArray = Array.isArray(target) && target.length > 0;
33485
+ if (filesMode) {
33486
+ if (Array.isArray(target)) {
33487
+ if (target.length === 0) {
33488
+ throw new Error("'target' must be a non-empty string or array of strings");
33489
+ }
33490
+ const response3 = await callBridge(bridge, "outline", { target, files: true }, extCtx);
33491
+ if (response3.success === false) {
33492
+ throw new Error(response3.message || "outline failed");
33493
+ }
33494
+ return textResult(formatOutlineFilesText(response3), response3);
33495
+ }
33496
+ if (typeof target !== "string" || target.length === 0) {
33497
+ throw new Error("'target' must be a non-empty string or array of strings");
33498
+ }
33499
+ let isDirectory2 = false;
33500
+ try {
33501
+ const resolved = resolve4(extCtx.cwd, target);
33502
+ const st = await stat2(resolved);
33503
+ isDirectory2 = st.isDirectory();
33504
+ } catch {}
33505
+ const request = isDirectory2 ? { directory: resolve4(extCtx.cwd, target), files: true } : { file: target, files: true };
33506
+ const response2 = await callBridge(bridge, "outline", request, extCtx);
33507
+ if (response2.success === false) {
33508
+ throw new Error(response2.message || "outline failed");
33509
+ }
33510
+ return textResult(formatOutlineFilesText(response2), response2);
33511
+ }
33278
33512
  if (typeof target === "string" && isUrl(target)) {
33279
33513
  const response2 = await callBridge(bridge, "outline", { file: target }, extCtx);
33280
33514
  if (response2.success === false) {
@@ -33315,22 +33549,58 @@ Pass a single \`target\`:
33315
33549
  pi.registerTool({
33316
33550
  name: "aft_zoom",
33317
33551
  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`.",
33552
+ 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
33553
  parameters: ZoomParams,
33320
33554
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
33321
33555
  const bridge = bridgeFor(ctx, extCtx.cwd);
33322
33556
  const hasFilePath = typeof params.filePath === "string" && params.filePath.length > 0;
33323
33557
  const hasUrl = typeof params.url === "string" && params.url.length > 0;
33558
+ const hasTargets = params.targets !== undefined && params.targets !== null;
33559
+ const hasSymbols = params.symbols !== undefined && params.symbols !== null && (typeof params.symbols === "string" ? params.symbols.length > 0 : Array.isArray(params.symbols) && params.symbols.length > 0);
33560
+ if (hasTargets) {
33561
+ if (hasFilePath || hasUrl || hasSymbols) {
33562
+ throw new Error("'targets' is mutually exclusive with 'filePath', 'url', and 'symbols'");
33563
+ }
33564
+ const targets = Array.isArray(params.targets) ? params.targets : [params.targets];
33565
+ if (targets.length === 0) {
33566
+ throw new Error("'targets' must be a non-empty object or array");
33567
+ }
33568
+ for (const [i, entry] of targets.entries()) {
33569
+ if (!entry || typeof entry.filePath !== "string" || entry.filePath.length === 0) {
33570
+ throw new Error(`targets[${i}].filePath must be a non-empty string`);
33571
+ }
33572
+ if (typeof entry.symbol !== "string" || entry.symbol.length === 0) {
33573
+ throw new Error(`targets[${i}].symbol must be a non-empty string`);
33574
+ }
33575
+ }
33576
+ const responses = await Promise.all(targets.map((t) => {
33577
+ const req2 = { file: t.filePath, symbol: t.symbol };
33578
+ if (params.contextLines !== undefined)
33579
+ req2.context_lines = params.contextLines;
33580
+ return callBridge(bridge, "zoom", req2, extCtx).catch((err) => ({
33581
+ success: false,
33582
+ message: err instanceof Error ? err.message : String(err)
33583
+ }));
33584
+ }));
33585
+ const entries = targets.map((t, i) => ({
33586
+ targetLabel: t.filePath,
33587
+ name: t.symbol,
33588
+ response: responses[i] ?? { success: false, message: "missing zoom response" }
33589
+ }));
33590
+ const batch = formatZoomMultiTargetResult(entries);
33591
+ return textResult(batch.text, batch);
33592
+ }
33324
33593
  if (!hasFilePath && !hasUrl) {
33325
- throw new Error("Provide exactly one of 'filePath' or 'url'");
33594
+ throw new Error("Provide exactly one of 'filePath', 'url', or 'targets'");
33326
33595
  }
33327
33596
  if (hasFilePath && hasUrl) {
33328
33597
  throw new Error("Provide exactly ONE of 'filePath' or 'url' — not both");
33329
33598
  }
33330
33599
  const file2 = hasUrl ? params.url : params.filePath;
33331
33600
  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) => {
33601
+ const symbolsArray = hasSymbols ? typeof params.symbols === "string" ? [params.symbols] : params.symbols : undefined;
33602
+ if (symbolsArray) {
33603
+ const results = await Promise.all(symbolsArray.map((sym) => {
33334
33604
  const req2 = { file: file2, symbol: sym };
33335
33605
  if (params.contextLines !== undefined)
33336
33606
  req2.context_lines = params.contextLines;
@@ -33339,12 +33609,17 @@ Pass a single \`target\`:
33339
33609
  message: err instanceof Error ? err.message : String(err)
33340
33610
  }));
33341
33611
  }));
33342
- const batch = formatZoomBatchResult(targetLabel, params.symbols, results);
33612
+ if (symbolsArray.length === 1) {
33613
+ const response2 = results[0] ?? { success: false, message: "missing zoom response" };
33614
+ if (response2.success === false) {
33615
+ throw new Error(response2.message || "zoom failed");
33616
+ }
33617
+ return textResult(formatZoomText(targetLabel, response2), response2);
33618
+ }
33619
+ const batch = formatZoomBatchResult(targetLabel, symbolsArray, results);
33343
33620
  return textResult(batch.text, batch);
33344
33621
  }
33345
33622
  const req = { file: file2 };
33346
- if (params.symbol)
33347
- req.symbol = params.symbol;
33348
33623
  if (params.contextLines !== undefined)
33349
33624
  req.context_lines = params.contextLines;
33350
33625
  const response = await callBridge(bridge, "zoom", req, extCtx);
@@ -33387,6 +33662,7 @@ function formatZoomBatchResult(targetLabel, symbols, responses) {
33387
33662
 
33388
33663
  `) };
33389
33664
  }
33665
+ var MAX_UNCHECKED_FILES_IN_FOOTER = 10;
33390
33666
  function formatOutlineText(response) {
33391
33667
  const text = response.text ?? "";
33392
33668
  const skipped = response.skipped_files;
@@ -33401,13 +33677,45 @@ function formatOutlineText(response) {
33401
33677
  return `${header}Skipped ${skipped.length} file(s):
33402
33678
  ${lines}`;
33403
33679
  }
33680
+ function formatOutlineFilesText(response) {
33681
+ const text = formatOutlineText(response);
33682
+ const uncheckedFiles = Array.isArray(response.unchecked_files) ? response.unchecked_files.filter((file2) => typeof file2 === "string" && file2.length > 0) : [];
33683
+ const isPartial = response.complete === false || response.walk_truncated === true || uncheckedFiles.length > 0;
33684
+ if (!isPartial) {
33685
+ return text;
33686
+ }
33687
+ const footer = [];
33688
+ if (response.walk_truncated === true) {
33689
+ const uncheckedCount = uncheckedFiles.length;
33690
+ const suffix = uncheckedCount > 0 ? ` ${uncheckedCount} additional files in this directory were not indexed.` : " Some files in this directory were not indexed.";
33691
+ footer.push(`⚠ Partial result: walk truncated at 200 files.${suffix}`);
33692
+ } else {
33693
+ const suffix = uncheckedFiles.length > 0 ? ` ${uncheckedFiles.length} files in this directory were not indexed.` : " Some files in this directory were not indexed.";
33694
+ footer.push(`⚠ Partial result:${suffix}`);
33695
+ }
33696
+ if (uncheckedFiles.length > 0) {
33697
+ footer.push("Unchecked files:");
33698
+ footer.push(...uncheckedFiles.slice(0, MAX_UNCHECKED_FILES_IN_FOOTER).map((file2) => ` ${file2}`));
33699
+ const remaining = uncheckedFiles.length - MAX_UNCHECKED_FILES_IN_FOOTER;
33700
+ if (remaining > 0) {
33701
+ footer.push(` ... +${remaining} more`);
33702
+ }
33703
+ }
33704
+ const header = text.length > 0 ? `${text}
33705
+
33706
+ ` : "";
33707
+ return `${header}${footer.join(`
33708
+ `)}`;
33709
+ }
33404
33710
 
33405
33711
  // src/tools/refactor.ts
33406
33712
  import { StringEnum as StringEnum5 } from "@earendil-works/pi-ai";
33407
33713
  import { Type as Type11 } from "typebox";
33408
33714
  var RefactorParams = Type11.Object({
33409
33715
  op: StringEnum5(["move", "extract", "inline"], { description: "Refactoring operation" }),
33410
- filePath: Type11.String({ description: "Source file" }),
33716
+ filePath: Type11.String({
33717
+ description: "Source file (absolute or relative to project root)"
33718
+ }),
33411
33719
  symbol: Type11.Optional(Type11.String({ description: "Symbol name (for move, inline)" })),
33412
33720
  destination: Type11.Optional(Type11.String({ description: "Target file (for move)" })),
33413
33721
  scope: Type11.Optional(Type11.String({ description: "Disambiguation scope for move op" })),
@@ -33509,7 +33817,9 @@ var SafetyParams = Type12.Object({
33509
33817
  op: StringEnum6(["undo", "history", "checkpoint", "restore", "list"], {
33510
33818
  description: "Safety operation"
33511
33819
  }),
33512
- filePath: Type12.Optional(Type12.String({ description: "File path (required for history, optional for undo)" })),
33820
+ filePath: Type12.Optional(Type12.String({
33821
+ description: "File path (required for history, optional for undo). Absolute or relative to project root."
33822
+ })),
33513
33823
  name: Type12.Optional(Type12.String({ description: "Checkpoint name (required for checkpoint, restore)" })),
33514
33824
  files: Type12.Optional(Type12.Array(Type12.String(), {
33515
33825
  description: "Specific files for checkpoint (optional, defaults to all tracked)"
@@ -33751,7 +34061,9 @@ import { StringEnum as StringEnum7 } from "@earendil-works/pi-ai";
33751
34061
  import { Type as Type14 } from "typebox";
33752
34062
  var TransformParams = Type14.Object({
33753
34063
  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" }),
34064
+ filePath: Type14.String({
34065
+ description: "Path to the source file (absolute or relative to project root)"
34066
+ }),
33755
34067
  container: Type14.Optional(Type14.String({ description: "Class/struct/impl name for add_member" })),
33756
34068
  code: Type14.Optional(Type14.String({ description: "Member code to insert (add_member)" })),
33757
34069
  target: Type14.Optional(Type14.String({ description: "Target symbol name" })),
@@ -33883,7 +34195,7 @@ function buildWorkflowHints(opts) {
33883
34195
  const hasNavigate = opts.toolSurface === "all" && !opts.absentTools.has("aft_navigate");
33884
34196
  const hasBgBash = opts.bashBackgroundEnabled && !opts.absentTools.has(bashName) && !opts.absentTools.has("bash_status");
33885
34197
  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.`);
34198
+ sections.push(`**Web/URL access**: \`aft_outline({ target: "<url>" })\` first for structure, then \`aft_zoom({ url: "<url>", symbols: "<heading>" })\` for the specific section.`);
33887
34199
  }
33888
34200
  if (hasOutline && hasZoom && (hasGrep || hasSearch)) {
33889
34201
  const locator = hasGrep ? `\`${grepName}\`` : "`aft_search`";
@@ -33895,6 +34207,7 @@ function buildWorkflowHints(opts) {
33895
34207
  "- `callers` — find all call sites before changing a function signature",
33896
34208
  "- `impact` — blast radius (which functions/files will need updates)",
33897
34209
  "- `trace_to` — how execution reaches this code from entry points (routes, exports, main)",
34210
+ "- `trace_to_symbol` — shortest call path from one symbol to another",
33898
34211
  "- `trace_data` — follow a value through assignments and parameters across files"
33899
34212
  ].join(`
33900
34213
  `));
@@ -33994,13 +34307,13 @@ var PLUGIN_VERSION = (() => {
33994
34307
  return "0.0.0";
33995
34308
  }
33996
34309
  })();
33997
- var ANNOUNCEMENT_VERSION = "0.30.0";
34310
+ var ANNOUNCEMENT_VERSION = "0.31.0";
33998
34311
  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."
34312
+ "`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.",
34313
+ '`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.',
34314
+ '`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.',
34315
+ "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.",
34316
+ "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
34317
  ];
34005
34318
  var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
34006
34319
  var ALL_ONLY_TOOLS = new Set([
@@ -34066,6 +34379,7 @@ function resolveToolSurface(config2) {
34066
34379
  const disabled = new Set(config2.disabled_tools ?? []);
34067
34380
  const ok = (name) => !disabled.has(name);
34068
34381
  const allOnly = (name) => ALL_ONLY_TOOLS.has(name) && ok(name);
34382
+ const restrictToProjectRoot = config2.restrict_to_project_root ?? false;
34069
34383
  if (surface === "minimal") {
34070
34384
  return {
34071
34385
  hoistBash: ok("bash"),
@@ -34073,6 +34387,7 @@ function resolveToolSurface(config2) {
34073
34387
  hoistWrite: false,
34074
34388
  hoistEdit: false,
34075
34389
  hoistGrep: false,
34390
+ restrictToProjectRoot,
34076
34391
  outline: ok("aft_outline"),
34077
34392
  zoom: ok("aft_zoom"),
34078
34393
  semantic: false,
@@ -34095,6 +34410,7 @@ function resolveToolSurface(config2) {
34095
34410
  hoistWrite: ok("write"),
34096
34411
  hoistEdit: ok("edit"),
34097
34412
  hoistGrep: ok("grep") && config2.search_index === true,
34413
+ restrictToProjectRoot,
34098
34414
  outline: ok("aft_outline"),
34099
34415
  zoom: ok("aft_zoom"),
34100
34416
  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.0",
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.0",
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.0",
34
+ "@cortexkit/aft-darwin-x64": "0.31.0",
35
+ "@cortexkit/aft-linux-arm64": "0.31.0",
36
+ "@cortexkit/aft-linux-x64": "0.31.0",
37
+ "@cortexkit/aft-win32-arm64": "0.31.0",
38
+ "@cortexkit/aft-win32-x64": "0.31.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@earendil-works/pi-coding-agent": "*",