@cortexkit/aft-pi 0.18.2 → 0.18.4

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.
@@ -7,6 +7,10 @@ export interface BgCompletion {
7
7
  duration_ms?: number;
8
8
  runtime_ms?: number;
9
9
  runtime?: number;
10
+ /** Tail of stdout+stderr captured at completion (≤300 bytes from Rust). */
11
+ output_preview?: string;
12
+ /** True when the captured tail is shorter than the actual output. */
13
+ output_truncated?: boolean;
10
14
  }
11
15
  type SessionBgState = {
12
16
  outstandingTaskIds: Set<string>;
@@ -16,6 +20,11 @@ type SessionBgState = {
16
20
  firstCompletionAt: number | null;
17
21
  scheduledFireAt: number | null;
18
22
  scheduledCompletionCount: number;
23
+ retryDelayMs: number | null;
24
+ unknownCompletions: Array<{
25
+ completion: BgCompletion;
26
+ receivedAt: number;
27
+ }>;
19
28
  lastSeenAt: number;
20
29
  };
21
30
  type TextContent = {
@@ -30,7 +39,9 @@ type ImageContent = {
30
39
  };
31
40
  type ContentBlock = TextContent | ImageContent;
32
41
  type SendUserMessageRuntime = {
33
- sendUserMessage: (content: string) => void;
42
+ sendUserMessage: (content: string, options?: {
43
+ deliverAs?: "steer" | "followUp";
44
+ }) => void;
34
45
  };
35
46
  export declare const sessionBgStates: Map<string, SessionBgState>;
36
47
  export declare const SESSION_BG_STATE_IDLE_TTL_MS: number;
@@ -38,9 +49,13 @@ interface DrainContext {
38
49
  ctx: PluginContext;
39
50
  directory: string;
40
51
  sessionID?: string;
52
+ isActive?: () => boolean;
41
53
  }
42
54
  export declare function trackBgTask(sessionID: string | undefined, taskId: string): void;
43
55
  export declare function ingestBgCompletions(sessionID: string | undefined, completions: unknown): BgCompletion[];
56
+ export declare function handlePushedBgCompletion(drainContext: DrainContext & {
57
+ runtime: SendUserMessageRuntime;
58
+ }, completion: unknown): Promise<void>;
44
59
  export declare function appendToolResultBgCompletions(drainContext: DrainContext, content: ContentBlock[]): Promise<ContentBlock[] | undefined>;
45
60
  export declare function handleTurnEndBgCompletions(drainContext: DrainContext & {
46
61
  runtime: SendUserMessageRuntime;
@@ -1 +1 @@
1
- {"version":3,"file":"bg-notifications.d.ts","sourceRoot":"","sources":["../src/bg-notifications.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,cAAc,GAAG;IACpB,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,kBAAkB,EAAE,YAAY,EAAE,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IACrC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,wBAAwB,EAAE,MAAM,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,KAAK,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC1E,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AACtE,KAAK,YAAY,GAAG,WAAW,GAAG,YAAY,CAAC;AAC/C,KAAK,sBAAsB,GAAG;IAAE,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAAC;AAE7E,eAAO,MAAM,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAa,CAAC;AAGtE,eAAO,MAAM,4BAA4B,QAAiB,CAAC;AAM3D,UAAU,YAAY;IACpB,GAAG,EAAE,aAAa,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAE/E;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,WAAW,EAAE,OAAO,GACnB,YAAY,EAAE,CAiBhB;AAED,wBAAsB,6BAA6B,CACjD,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,YAAY,EAAE,GACtB,OAAO,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC,CAarC;AAED,wBAAsB,0BAA0B,CAC9C,YAAY,EAAE,YAAY,GAAG;IAAE,OAAO,EAAE,sBAAsB,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAE/D;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAGjF;AAED,wBAAgB,kCAAkC,IAAI,IAAI,CAKzD;AA2ED,wBAAgB,wBAAwB,CAAC,GAAG,GAAE,MAAmB,GAAG,IAAI,CAQvE"}
1
+ {"version":3,"file":"bg-notifications.d.ts","sourceRoot":"","sources":["../src/bg-notifications.ts"],"names":[],"mappings":"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"}
package/dist/bridge.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { BgCompletion } from "./bg-notifications.js";
1
2
  /**
2
3
  * Compare two semver version strings (major.minor.patch plus pre-release).
3
4
  * Returns: negative if a < b, 0 if equal, positive if a > b.
@@ -20,6 +21,12 @@ export interface BridgeOptions {
20
21
  onVersionMismatch?: (binaryVersion: string, minVersion: string) => void;
21
22
  /** Called after the first successful configure returns user-visible warnings. */
22
23
  onConfigureWarnings?: (context: ConfigureWarningsContext) => void | Promise<void>;
24
+ /** Called for server-pushed background bash completions. */
25
+ onBashCompletion?: (completion: BashCompletedPayload, bridge: BinaryBridge) => void | Promise<void>;
26
+ }
27
+ export interface BashCompletedPayload extends BgCompletion {
28
+ type: "bash_completed";
29
+ session_id: string;
23
30
  }
24
31
  export interface BridgeRequestOptions {
25
32
  onProgress?: (chunk: {
@@ -28,6 +35,22 @@ export interface BridgeRequestOptions {
28
35
  }) => void;
29
36
  /** Per-call transport timeout in milliseconds. Defaults to the bridge-wide timeout. */
30
37
  transportTimeoutMs?: number;
38
+ /**
39
+ * Skip the "kill the child process on timeout" behavior for this request.
40
+ *
41
+ * The default (false) treats a transport-level timeout as evidence the bridge
42
+ * is wedged — Rust normally responds well within the budget, so silence past
43
+ * the deadline almost always means a stuck child. Killing forces a clean
44
+ * respawn on the next call.
45
+ *
46
+ * Some commands enforce their own timeouts on the Rust side (notably `bash`,
47
+ * which uses a watchdog thread to terminate the child shell and return a
48
+ * timeout response). For those, a transport timeout means the response was
49
+ * lost or queued behind something else — the bridge itself is still healthy
50
+ * and should keep its warm state. Pass `keepBridgeOnTimeout: true` to
51
+ * reject the request without tearing down the bridge.
52
+ */
53
+ keepBridgeOnTimeout?: boolean;
31
54
  }
32
55
  interface SendOptions extends BridgeRequestOptions {
33
56
  timeoutMs?: number;
@@ -60,12 +83,14 @@ export declare class BinaryBridge {
60
83
  private minVersion;
61
84
  private onVersionMismatch;
62
85
  private onConfigureWarnings;
86
+ private onBashCompletion;
63
87
  private restartResetTimer;
64
88
  constructor(binaryPath: string, cwd: string, options?: BridgeOptions, configOverrides?: Record<string, unknown>);
65
89
  /** Number of times the binary has been restarted after a crash. */
66
90
  get restartCount(): number;
67
91
  /** Whether the child process is currently alive. */
68
92
  isAlive(): boolean;
93
+ hasPendingRequests(): boolean;
69
94
  /**
70
95
  * Send a command to the binary and return the parsed response.
71
96
  * Lazy-spawns the binary on first call.
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -50,6 +50,8 @@ export interface ConfigureExperimentalOverrides {
50
50
  export type ToolSurface = "minimal" | "recommended" | "all";
51
51
  export interface AftConfig {
52
52
  format_on_edit?: boolean;
53
+ /** Maximum formatter subprocess wallclock seconds. Bounded 1..=600. Default 10. */
54
+ formatter_timeout_secs?: number;
53
55
  validate_on_edit?: "syntax" | "full";
54
56
  formatter?: Record<string, Formatter>;
55
57
  checker?: Record<string, Checker>;
@@ -81,6 +83,7 @@ export declare const LspServerSchema: z.ZodObject<{
81
83
  }, z.core.$strip>;
82
84
  export declare const AftConfigSchema: z.ZodObject<{
83
85
  format_on_edit: z.ZodOptional<z.ZodBoolean>;
86
+ formatter_timeout_secs: z.ZodOptional<z.ZodNumber>;
84
87
  validate_on_edit: z.ZodOptional<z.ZodEnum<{
85
88
  syntax: "syntax";
86
89
  full: "full";
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -30,10 +30,45 @@
30
30
  * - /aft-status Status dialog (index states, LSP servers, storage dir)
31
31
  */
32
32
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
33
+ import { loadAftConfig } from "./config.js";
34
+ /**
35
+ * Tool surface mirrors opencode-plugin: navigate/delete/move/transform/refactor
36
+ * are all-only. recommended exposes hoisted + read/safety/import/ast/lsp/conflicts
37
+ * + experimental search/semantic when enabled.
38
+ *
39
+ * Returns the set of AFT tool names that should be registered given the
40
+ * configured surface + disabled_tools filter. Pi's built-in tools are always
41
+ * present; registering an AFT tool with the same name replaces them.
42
+ */
43
+ declare function resolveToolSurface(config: ReturnType<typeof loadAftConfig>): {
44
+ hoistBash: boolean;
45
+ hoistRead: boolean;
46
+ hoistWrite: boolean;
47
+ hoistEdit: boolean;
48
+ hoistGrep: boolean;
49
+ outline: boolean;
50
+ zoom: boolean;
51
+ semantic: boolean;
52
+ navigate: boolean;
53
+ conflicts: boolean;
54
+ importTool: boolean;
55
+ safety: boolean;
56
+ delete: boolean;
57
+ move: boolean;
58
+ astSearch: boolean;
59
+ astReplace: boolean;
60
+ lspDiagnostics: boolean;
61
+ structure: boolean;
62
+ refactor: boolean;
63
+ };
33
64
  /**
34
65
  * Pi extension default export.
35
66
  *
36
67
  * Called once per session. Registers tools, commands, and session shutdown hooks.
37
68
  */
38
69
  export default function (pi: ExtensionAPI): Promise<void>;
70
+ export declare const __test__: {
71
+ resolveToolSurface: typeof resolveToolSurface;
72
+ };
73
+ export {};
39
74
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAyLlE;;;;GAIG;AACH,yBAA+B,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAyS9D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAQlE,OAAO,EACL,aAAa,EAGd,MAAM,aAAa,CAAC;AAkFrB;;;;;;;;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,CA6T9D;AAED,eAAO,MAAM,QAAQ;;CAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -7893,7 +7893,8 @@ import * as fs from "node:fs";
7893
7893
  import * as os from "node:os";
7894
7894
  import * as path from "node:path";
7895
7895
  var TAG = "[aft-pi]";
7896
- var logFile = path.join(os.tmpdir(), "aft-pi.log");
7896
+ var isTestEnv = process.env.BUN_TEST === "1" || false;
7897
+ var logFile = path.join(os.tmpdir(), isTestEnv ? "aft-pi-test.log" : "aft-pi.log");
7897
7898
  var useStderr = process.env.AFT_LOG_STDERR === "1";
7898
7899
  var buffer = [];
7899
7900
  var flushTimer = null;
@@ -7951,6 +7952,9 @@ function warn(message, data) {
7951
7952
  function error(message, data) {
7952
7953
  write("ERROR", message, data);
7953
7954
  }
7955
+ function sessionLog(sessionId, message, data) {
7956
+ write("INFO", message, data, sessionId);
7957
+ }
7954
7958
  function sessionWarn(sessionId, message, data) {
7955
7959
  write("WARN", message, data, sessionId);
7956
7960
  }
@@ -7963,10 +7967,24 @@ var sessionBgStates = new Map;
7963
7967
  var SESSION_BG_STATE_IDLE_TTL_MS = 60 * 60 * 1000;
7964
7968
  var DEBOUNCE_STEP_MS = 200;
7965
7969
  var DEBOUNCE_CAP_MS = 1000;
7970
+ var UNKNOWN_COMPLETION_TTL_MS = 5000;
7971
+ var UNKNOWN_COMPLETION_CAP = 32;
7966
7972
  var DEFAULT_SESSION_ID = "__default__";
7967
7973
  var LOG_PREFIX = "[aft-pi] bg-notifications:";
7968
7974
  function trackBgTask(sessionID, taskId) {
7969
- stateFor(sessionID).outstandingTaskIds.add(taskId);
7975
+ const state = stateFor(sessionID);
7976
+ pruneUnknownCompletions(state, Date.now());
7977
+ const buffered = state.unknownCompletions.filter((entry) => entry.completion.task_id === taskId);
7978
+ state.unknownCompletions = state.unknownCompletions.filter((entry) => entry.completion.task_id !== taskId);
7979
+ if (buffered.length > 0) {
7980
+ for (const entry of buffered) {
7981
+ if (!state.pendingCompletions.some((pending) => pending.task_id === taskId)) {
7982
+ state.pendingCompletions.push(entry.completion);
7983
+ }
7984
+ }
7985
+ return;
7986
+ }
7987
+ state.outstandingTaskIds.add(taskId);
7970
7988
  }
7971
7989
  function ingestBgCompletions(sessionID, completions) {
7972
7990
  if (!Array.isArray(completions) || completions.length === 0)
@@ -7976,8 +7994,10 @@ function ingestBgCompletions(sessionID, completions) {
7976
7994
  for (const completion of completions) {
7977
7995
  if (!isBgCompletion(completion))
7978
7996
  continue;
7979
- if (!state.outstandingTaskIds.has(completion.task_id))
7997
+ if (!state.outstandingTaskIds.has(completion.task_id)) {
7998
+ bufferUnknownCompletion(state, completion);
7980
7999
  continue;
8000
+ }
7981
8001
  state.outstandingTaskIds.delete(completion.task_id);
7982
8002
  if (!state.pendingCompletions.some((pending) => pending.task_id === completion.task_id) && !accepted.some((pending) => pending.task_id === completion.task_id)) {
7983
8003
  accepted.push(completion);
@@ -7986,6 +8006,10 @@ function ingestBgCompletions(sessionID, completions) {
7986
8006
  state.pendingCompletions.push(...accepted);
7987
8007
  return accepted;
7988
8008
  }
8009
+ async function handlePushedBgCompletion(drainContext, completion) {
8010
+ ingestBgCompletions(drainContext.sessionID, [completion]);
8011
+ await triggerWakeIfPending(drainContext, true);
8012
+ }
7989
8013
  async function appendToolResultBgCompletions(drainContext, content) {
7990
8014
  const state = stateFor(drainContext.sessionID);
7991
8015
  if (state.outstandingTaskIds.size === 0 && state.pendingCompletions.length === 0)
@@ -8000,50 +8024,56 @@ async function appendToolResultBgCompletions(drainContext, content) {
8000
8024
  return [...content, { type: "text", text: reminder }];
8001
8025
  }
8002
8026
  async function handleTurnEndBgCompletions(drainContext) {
8027
+ await triggerWakeIfPending(drainContext, false);
8028
+ }
8029
+ async function triggerWakeIfPending(drainContext, skipDrain) {
8003
8030
  const state = stateFor(drainContext.sessionID);
8004
8031
  if (state.wakeFiredThisIdle)
8005
8032
  return;
8006
- if (state.outstandingTaskIds.size > 0) {
8033
+ if (drainContext.isActive?.())
8034
+ return;
8035
+ if (!skipDrain && state.outstandingTaskIds.size > 0) {
8007
8036
  await drainCompletions(drainContext);
8008
8037
  }
8009
8038
  if (state.pendingCompletions.length === 0)
8010
8039
  return;
8011
8040
  scheduleWake(state, async (reminder) => {
8012
- try {
8013
- drainContext.runtime.sendUserMessage(reminder);
8014
- } catch (err) {
8015
- warn(`${LOG_PREFIX} wake send failed: ${err instanceof Error ? err.message : String(err)}`);
8016
- }
8041
+ drainContext.runtime.sendUserMessage(reminder, { deliverAs: "followUp" });
8042
+ }, (err) => {
8043
+ sessionWarn(drainContext.sessionID ?? "", `${LOG_PREFIX} wake send failed: ${err instanceof Error ? err.message : String(err)}`);
8017
8044
  });
8018
8045
  }
8019
8046
  function resetBgWake(sessionID) {
8020
8047
  stateFor(sessionID).wakeFiredThisIdle = false;
8021
8048
  }
8022
8049
  function formatSystemReminder(completions) {
8023
- const bullets = completions.map((completion) => `- ${formatCompletion(completion)}`).join(`
8050
+ const bullets = completions.map((completion) => formatCompletion(completion)).join(`
8024
8051
  `);
8052
+ const anyTruncated = completions.some((c) => c.output_truncated === true);
8053
+ const tail = anyTruncated ? `
8054
+
8055
+ For truncated tasks, use bash_status({ task_id: "..." }) to retrieve full output.` : "";
8025
8056
  return `<system-reminder>
8026
8057
  [BACKGROUND BASH COMPLETED]
8027
- ${bullets}
8028
-
8029
- Use bash_status({ task_id: "..." }) to retrieve full output.
8058
+ ${bullets}${tail}
8030
8059
  </system-reminder>`;
8031
8060
  }
8032
8061
  async function drainCompletions({ ctx, directory, sessionID }) {
8033
8062
  try {
8034
8063
  const bridge = ctx.pool.getAnyActiveBridge(directory) ?? ctx.pool.getBridge(directory);
8035
- const params = sessionID ? { session_id: sessionID } : {};
8036
- const response = await bridge.send("bash_drain_completions", params);
8064
+ if (!sessionID)
8065
+ return;
8066
+ const response = await bridge.send("bash_drain_completions", { session_id: sessionID });
8037
8067
  if (response.success === false) {
8038
- warn(`${LOG_PREFIX} drain failed: ${String(response.message ?? "unknown error")}`);
8068
+ sessionWarn(sessionID ?? "", `${LOG_PREFIX} drain failed: ${String(response.message ?? "unknown error")}`);
8039
8069
  return;
8040
8070
  }
8041
8071
  ingestBgCompletions(sessionID, response.bg_completions);
8042
8072
  } catch (err) {
8043
- warn(`${LOG_PREFIX} drain failed: ${err instanceof Error ? err.message : String(err)}`);
8073
+ sessionWarn(sessionID ?? "", `${LOG_PREFIX} drain failed: ${err instanceof Error ? err.message : String(err)}`);
8044
8074
  }
8045
8075
  }
8046
- function scheduleWake(state, sendWake) {
8076
+ function scheduleWake(state, sendWake, onSendFailure) {
8047
8077
  const now = Date.now();
8048
8078
  if (state.debounceTimer && state.pendingCompletions.length <= state.scheduledCompletionCount) {
8049
8079
  return;
@@ -8058,16 +8088,24 @@ function scheduleWake(state, sendWake) {
8058
8088
  state.scheduledCompletionCount = state.pendingCompletions.length;
8059
8089
  if (state.debounceTimer)
8060
8090
  clearTimeout(state.debounceTimer);
8061
- const delay = Math.max(0, (state.scheduledFireAt ?? now) - now);
8091
+ const delay = state.retryDelayMs ?? Math.max(0, (state.scheduledFireAt ?? now) - now);
8062
8092
  state.debounceTimer = setTimeout(() => {
8063
- const reminder = formatSystemReminder(state.pendingCompletions);
8093
+ const pending = state.pendingCompletions;
8094
+ const reminder = formatSystemReminder(pending);
8064
8095
  state.pendingCompletions = [];
8065
8096
  state.debounceTimer = null;
8066
- state.wakeFiredThisIdle = true;
8067
8097
  state.firstCompletionAt = null;
8068
8098
  state.scheduledFireAt = null;
8069
8099
  state.scheduledCompletionCount = 0;
8070
- sendWake(reminder);
8100
+ sendWake(reminder).then(() => {
8101
+ state.retryDelayMs = null;
8102
+ state.wakeFiredThisIdle = true;
8103
+ }).catch((err) => {
8104
+ state.pendingCompletions = [...pending, ...state.pendingCompletions];
8105
+ state.retryDelayMs = Math.min((delay || DEBOUNCE_STEP_MS) * 2, DEBOUNCE_CAP_MS);
8106
+ onSendFailure(err);
8107
+ scheduleWake(state, sendWake, onSendFailure);
8108
+ });
8071
8109
  }, delay);
8072
8110
  state.debounceTimer.unref?.();
8073
8111
  }
@@ -8085,6 +8123,8 @@ function stateFor(sessionID) {
8085
8123
  firstCompletionAt: null,
8086
8124
  scheduledFireAt: null,
8087
8125
  scheduledCompletionCount: 0,
8126
+ retryDelayMs: null,
8127
+ unknownCompletions: [],
8088
8128
  lastSeenAt: now
8089
8129
  };
8090
8130
  sessionBgStates.set(key, state);
@@ -8105,6 +8145,18 @@ function cleanupIdleSessionStates(now = Date.now()) {
8105
8145
  sessionBgStates.delete(sessionID);
8106
8146
  }
8107
8147
  }
8148
+ function bufferUnknownCompletion(state, completion) {
8149
+ const now = Date.now();
8150
+ pruneUnknownCompletions(state, now);
8151
+ state.unknownCompletions = state.unknownCompletions.filter((entry) => entry.completion.task_id !== completion.task_id);
8152
+ state.unknownCompletions.push({ completion, receivedAt: now });
8153
+ if (state.unknownCompletions.length > UNKNOWN_COMPLETION_CAP) {
8154
+ state.unknownCompletions.splice(0, state.unknownCompletions.length - UNKNOWN_COMPLETION_CAP);
8155
+ }
8156
+ }
8157
+ function pruneUnknownCompletions(state, now) {
8158
+ state.unknownCompletions = state.unknownCompletions.filter((entry) => now - entry.receivedAt <= UNKNOWN_COMPLETION_TTL_MS);
8159
+ }
8108
8160
  function isBgCompletion(value) {
8109
8161
  if (!value || typeof value !== "object" || Array.isArray(value))
8110
8162
  return false;
@@ -8114,10 +8166,26 @@ function isBgCompletion(value) {
8114
8166
  function formatCompletion(completion) {
8115
8167
  const status = formatStatus(completion);
8116
8168
  const duration = formatDuration(completion);
8117
- return `task ${completion.task_id} (${status}${duration ? `, ${duration}` : ""}): ${completion.command}`;
8169
+ const header = `- task ${completion.task_id} (${status}${duration ? `, ${duration}` : ""})`;
8170
+ const previewBlock = formatOutputPreview(completion);
8171
+ return previewBlock ? `${header}
8172
+ ${previewBlock}` : header;
8173
+ }
8174
+ function formatOutputPreview(completion) {
8175
+ const ansiRegex = /\x1b\[[0-9;]*[a-zA-Z]/g;
8176
+ const raw = (completion.output_preview ?? "").replace(ansiRegex, "");
8177
+ if (!raw.trim())
8178
+ return "";
8179
+ const trimmed = raw.replace(/\n+$/, "");
8180
+ const ellipsis = completion.output_truncated ? "…" : "";
8181
+ const indented = trimmed.split(`
8182
+ `).map((line) => ` ${line}`).join(`
8183
+ `);
8184
+ return ellipsis ? ` ${ellipsis}
8185
+ ${indented}` : indented;
8118
8186
  }
8119
8187
  function formatStatus(completion) {
8120
- if (completion.status === "timeout")
8188
+ if (completion.status === "timed_out" || completion.status === "timeout")
8121
8189
  return "timed out";
8122
8190
  if (completion.status === "killed")
8123
8191
  return "killed";
@@ -21949,6 +22017,7 @@ var ExperimentalConfigSchema = exports_external.object({
21949
22017
  });
21950
22018
  var AftConfigSchema = exports_external.object({
21951
22019
  format_on_edit: exports_external.boolean().optional(),
22020
+ formatter_timeout_secs: exports_external.number().int().min(1).max(600).optional(),
21952
22021
  validate_on_edit: exports_external.enum(["syntax", "full"]).optional(),
21953
22022
  formatter: exports_external.record(exports_external.string(), FormatterEnum).optional(),
21954
22023
  checker: exports_external.record(exports_external.string(), CheckerEnum).optional(),
@@ -22038,6 +22107,18 @@ function isWritableMigrationError(errorValue) {
22038
22107
  const code = errorValue?.code;
22039
22108
  return code === "EROFS" || code === "EACCES" || code === "EPERM";
22040
22109
  }
22110
+ function extractCommentsForPreservation(content) {
22111
+ const comments = [];
22112
+ const linePattern = /\/\/[^\n]*/g;
22113
+ for (const match of content.match(linePattern) ?? []) {
22114
+ comments.push(match.trim());
22115
+ }
22116
+ const blockPattern = /\/\*[\s\S]*?\*\//g;
22117
+ for (const match of content.match(blockPattern) ?? []) {
22118
+ comments.push(match.replace(/\s+/g, " ").trim());
22119
+ }
22120
+ return comments;
22121
+ }
22041
22122
  function ensureRecordAtPath(root, path2) {
22042
22123
  let current = root;
22043
22124
  for (const segment of path2) {
@@ -22096,10 +22177,9 @@ function migrateAftConfigFile(configPath, logger = { log, warn }) {
22096
22177
  if (oldKeys.length === 0) {
22097
22178
  return { migrated: false, oldKeys: [] };
22098
22179
  }
22099
- const comments = content.match(/^\s*\/\/.*$/gm) ?? [];
22100
22180
  const serialized = `${import_comment_json.stringify(rawConfig, null, 2)}
22101
22181
  `;
22102
- const preservedComments = comments.filter((comment) => !serialized.includes(comment.trim()));
22182
+ const preservedComments = extractCommentsForPreservation(content).filter((comment) => !serialized.includes(comment.trim()));
22103
22183
  const nextContent = preservedComments.length > 0 ? `${preservedComments.join(`
22104
22184
  `)}
22105
22185
  ${serialized}` : serialized;
@@ -23738,7 +23818,7 @@ import { join as join6 } from "node:path";
23738
23818
  var WARNING_MARKER = "\uD83D\uDD27 AFT: ⚠️";
23739
23819
  var FEATURE_MARKER = "\uD83D\uDD27 AFT: ✨";
23740
23820
  var WARNED_TOOLS_FILE = "warned_tools.json";
23741
- function sendIgnoredMessage(client, _sessionId, text) {
23821
+ function sendIgnoredMessage(client, sessionId, text) {
23742
23822
  const typedClient = client;
23743
23823
  if (typeof typedClient.ui?.notify !== "function")
23744
23824
  return false;
@@ -23746,7 +23826,7 @@ function sendIgnoredMessage(client, _sessionId, text) {
23746
23826
  typedClient.ui.notify(text, "warning");
23747
23827
  return true;
23748
23828
  } catch (err) {
23749
- log(`[aft-pi] notification send failed: ${err instanceof Error ? err.message : String(err)}`);
23829
+ sessionLog(sessionId, `[aft-pi] notification send failed: ${err instanceof Error ? err.message : String(err)}`);
23750
23830
  return false;
23751
23831
  }
23752
23832
  }
@@ -24387,6 +24467,7 @@ class BinaryBridge {
24387
24467
  minVersion;
24388
24468
  onVersionMismatch;
24389
24469
  onConfigureWarnings;
24470
+ onBashCompletion;
24390
24471
  restartResetTimer = null;
24391
24472
  constructor(binaryPath, cwd, options, configOverrides) {
24392
24473
  this.binaryPath = binaryPath;
@@ -24397,6 +24478,7 @@ class BinaryBridge {
24397
24478
  this.minVersion = options?.minVersion;
24398
24479
  this.onVersionMismatch = options?.onVersionMismatch;
24399
24480
  this.onConfigureWarnings = options?.onConfigureWarnings;
24481
+ this.onBashCompletion = options?.onBashCompletion;
24400
24482
  }
24401
24483
  get restartCount() {
24402
24484
  return this._restartCount;
@@ -24404,6 +24486,9 @@ class BinaryBridge {
24404
24486
  isAlive() {
24405
24487
  return this.process !== null && this.process.exitCode === null && !this.process.killed;
24406
24488
  }
24489
+ hasPendingRequests() {
24490
+ return this.pending.size > 0;
24491
+ }
24407
24492
  async send(command, params = {}, options) {
24408
24493
  if (this._shuttingDown) {
24409
24494
  throw new Error(`[aft-pi] Bridge is shutting down, cannot send "${command}"`);
@@ -24457,17 +24542,21 @@ class BinaryBridge {
24457
24542
  `;
24458
24543
  const effectiveTimeoutMs = options?.transportTimeoutMs ?? options?.timeoutMs ?? this.timeoutMs;
24459
24544
  const requestSessionId = typeof params.session_id === "string" && params.session_id.length > 0 ? params.session_id : undefined;
24545
+ const keepBridgeOnTimeout = options?.keepBridgeOnTimeout === true;
24460
24546
  return new Promise((resolve3, reject) => {
24461
24547
  const timer = setTimeout(() => {
24462
24548
  this.pending.delete(id);
24463
- const timeoutMsg = `Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms — restarting bridge`;
24549
+ const restartSuffix = keepBridgeOnTimeout ? "" : " — restarting bridge";
24550
+ const timeoutMsg = `Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms${restartSuffix}`;
24464
24551
  if (requestSessionId) {
24465
24552
  sessionWarn(requestSessionId, timeoutMsg);
24466
24553
  } else {
24467
24554
  warn(timeoutMsg);
24468
24555
  }
24469
24556
  reject(new Error(`[aft-pi] Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
24470
- this.handleTimeout();
24557
+ if (!keepBridgeOnTimeout) {
24558
+ this.handleTimeout();
24559
+ }
24471
24560
  }, effectiveTimeoutMs);
24472
24561
  this.pending.set(id, { resolve: resolve3, reject, timer, onProgress: options?.onProgress });
24473
24562
  if (!this.process?.stdin?.writable) {
@@ -24672,6 +24761,10 @@ class BinaryBridge {
24672
24761
  }
24673
24762
  continue;
24674
24763
  }
24764
+ if (response.type === "bash_completed") {
24765
+ this.onBashCompletion?.(response, this);
24766
+ continue;
24767
+ }
24675
24768
  const id = response.id;
24676
24769
  if (id && this.pending.has(id)) {
24677
24770
  const entry = this.pending.get(id);
@@ -24681,6 +24774,8 @@ class BinaryBridge {
24681
24774
  clearTimeout(entry.timer);
24682
24775
  this.scheduleRestartCountReset();
24683
24776
  entry.resolve(response);
24777
+ } else if (typeof response.type === "string") {
24778
+ log(`Ignoring unknown stdout push frame type: ${response.type}`);
24684
24779
  }
24685
24780
  } catch (_err) {
24686
24781
  warn(`Failed to parse stdout line: ${line}`);
@@ -24778,7 +24873,8 @@ class BridgePool {
24778
24873
  maxRestarts: options.maxRestarts,
24779
24874
  minVersion: options.minVersion,
24780
24875
  onVersionMismatch: options.onVersionMismatch,
24781
- onConfigureWarnings: options.onConfigureWarnings
24876
+ onConfigureWarnings: options.onConfigureWarnings,
24877
+ onBashCompletion: options.onBashCompletion
24782
24878
  };
24783
24879
  this.configOverrides = configOverrides;
24784
24880
  if (Number.isFinite(this.idleTimeoutMs)) {
@@ -24801,6 +24897,14 @@ class BridgePool {
24801
24897
  }
24802
24898
  return null;
24803
24899
  }
24900
+ getActiveBridgeForRoot(directory) {
24901
+ const key = canonicalKey(directory);
24902
+ const entry = this.bridges.get(key);
24903
+ if (!entry?.bridge.isAlive())
24904
+ return null;
24905
+ entry.lastUsed = Date.now();
24906
+ return entry.bridge;
24907
+ }
24804
24908
  getBridge(directory) {
24805
24909
  const key = canonicalKey(directory);
24806
24910
  const existing = this.bridges.get(key);
@@ -25674,6 +25778,7 @@ function registerBashTool(pi, ctx) {
25674
25778
  compressed: params.compressed
25675
25779
  }, extCtx, {
25676
25780
  transportTimeoutMs: bashTransportTimeoutMs(params.timeout),
25781
+ keepBridgeOnTimeout: true,
25677
25782
  onProgress: ({ text }) => {
25678
25783
  streamed += text;
25679
25784
  const displayText = truncateToVisualLines(streamed, 100);
@@ -25748,7 +25853,7 @@ function createBashKillTool(ctx) {
25748
25853
  throw new Error(data.message ?? "bash_kill failed");
25749
25854
  }
25750
25855
  const details = data;
25751
- return bashKillResult(`Task ${params.task_id}: killed`, details);
25856
+ return bashKillResult(`Task ${params.task_id}: ${details.status}`, details);
25752
25857
  }
25753
25858
  };
25754
25859
  }
@@ -25779,10 +25884,11 @@ function bashKillResult(output, details) {
25779
25884
  }
25780
25885
  function formatBashStatus(taskId, details) {
25781
25886
  const exit = typeof details.exit_code === "number" ? ` (exit ${details.exit_code})` : "";
25782
- let text = `Task ${taskId}: ${details.status}${exit}`;
25887
+ const dur = typeof details.duration_ms === "number" ? ` ${Math.round(details.duration_ms / 1000)}s` : "";
25888
+ let text = `Task ${taskId}: ${details.status}${exit}${dur}`;
25783
25889
  if (isTerminalStatus(details.status) && details.output_preview) {
25784
25890
  text += `
25785
- ${details.output_preview.slice(0, 200)}`;
25891
+ ${details.output_preview.slice(0, 2000)}`;
25786
25892
  }
25787
25893
  return text;
25788
25894
  }
@@ -25810,6 +25916,17 @@ ${theme.fg("error", errorText || "bash failed")}`);
25810
25916
  const container = reuseContainer2(context.lastComponent);
25811
25917
  container.clear();
25812
25918
  container.addChild(new Spacer2(1));
25919
+ const rawOutput = result.content.filter((c) => c.type === "text").map((c) => c.text ?? "").join(`
25920
+ `).trim();
25921
+ if (rawOutput) {
25922
+ const lines = rawOutput.split(`
25923
+ `);
25924
+ const preview = lines.length > 25 ? `... (${lines.length - 25} lines omitted)
25925
+ ${lines.slice(-25).join(`
25926
+ `)}` : rawOutput;
25927
+ container.addChild(new Text2(preview, 1, 0));
25928
+ container.addChild(new Spacer2(1));
25929
+ }
25813
25930
  if (exitCode !== undefined) {
25814
25931
  const exitColor = exitCode === 0 ? "success" : "error";
25815
25932
  const exitText = theme.fg(exitColor, `exit ${exitCode}`);
@@ -26248,12 +26365,15 @@ function buildMutationResult(filePath, response) {
26248
26365
  const replacements = response.replacements;
26249
26366
  const diagnostics = response.lsp_diagnostics;
26250
26367
  const truncated = diffObj?.truncated === true;
26368
+ const formatted = response.formatted;
26369
+ const formatSkippedReason = response.format_skipped_reason;
26370
+ const globFormatSkipReasons = response.format_skip_reasons;
26251
26371
  let diffText;
26252
26372
  let firstChangedLine;
26253
26373
  if (diffObj && !truncated && typeof diffObj.before === "string" && typeof diffObj.after === "string") {
26254
- const formatted = formatDiffForPi(diffObj.before, diffObj.after);
26255
- diffText = formatted.diff;
26256
- firstChangedLine = formatted.firstChangedLine;
26374
+ const piDiff = formatDiffForPi(diffObj.before, diffObj.after);
26375
+ diffText = piDiff.diff;
26376
+ firstChangedLine = piDiff.firstChangedLine;
26257
26377
  }
26258
26378
  const summaryHeader = replacements !== undefined ? `Edited ${filePath} (+${additions}/-${deletions}, ${replacements} replacement${replacements === 1 ? "" : "s"})` : `Wrote ${filePath} (+${additions}/-${deletions})`;
26259
26379
  let text = summaryHeader;
@@ -26266,6 +26386,16 @@ ${diffText}`;
26266
26386
 
26267
26387
  (diff truncated — file too large to include before/after content)`;
26268
26388
  }
26389
+ const skipNote = formatSkipReasonNote(formatSkippedReason);
26390
+ if (skipNote)
26391
+ text += `
26392
+
26393
+ ${skipNote}`;
26394
+ const globSkipNote = formatGlobSkipReasonsNote(globFormatSkipReasons);
26395
+ if (globSkipNote)
26396
+ text += `
26397
+
26398
+ ${globSkipNote}`;
26269
26399
  if (diagnostics && diagnostics.length > 0) {
26270
26400
  text += `
26271
26401
 
@@ -26281,10 +26411,34 @@ ${formatDiagnosticsText(diagnostics)}`;
26281
26411
  deletions,
26282
26412
  replacements,
26283
26413
  diagnostics,
26284
- truncated: truncated || undefined
26414
+ truncated: truncated || undefined,
26415
+ formatted,
26416
+ formatSkippedReason
26285
26417
  }
26286
26418
  };
26287
26419
  }
26420
+ function formatGlobSkipReasonsNote(reasons) {
26421
+ if (!Array.isArray(reasons))
26422
+ return;
26423
+ const actionable = reasons.filter((reason) => typeof reason === "string").filter((reason) => ["formatter_not_installed", "formatter_excluded_path", "timeout", "error"].includes(reason));
26424
+ if (actionable.length === 0)
26425
+ return;
26426
+ return `Note: formatter skipped some glob edit result file(s): ${[...new Set(actionable)].sort().join(", ")}. See per-file format_skipped_reason values for details.`;
26427
+ }
26428
+ function formatSkipReasonNote(reason) {
26429
+ switch (reason) {
26430
+ case "formatter_not_installed":
26431
+ return "Note: formatter binary not installed; file written unformatted.";
26432
+ case "timeout":
26433
+ return "Note: formatter timed out; file written unformatted. Raise formatter_timeout_secs or check the formatter for hangs.";
26434
+ case "formatter_excluded_path":
26435
+ return "Note: formatter is configured to ignore this path (e.g. biome.json files.includes, .prettierignore). File written unformatted.";
26436
+ case "error":
26437
+ return "Note: formatter exited with an unrecognized error; file written unformatted.";
26438
+ default:
26439
+ return;
26440
+ }
26441
+ }
26288
26442
  function formatDiagnosticsText(diagnostics) {
26289
26443
  try {
26290
26444
  return diagnostics.map((d) => {
@@ -26856,6 +27010,29 @@ function buildOutlineSections(text, theme) {
26856
27010
  `)];
26857
27011
  }
26858
27012
  function buildZoomSections(args, payload, theme) {
27013
+ const batch = asRecord2(payload);
27014
+ if (Array.isArray(batch?.symbols)) {
27015
+ const header = batch.complete === false ? [theme.fg("warning", "Incomplete zoom results")] : [];
27016
+ const items2 = batch.symbols;
27017
+ return [
27018
+ ...header,
27019
+ ...items2.map((item) => {
27020
+ const record2 = asRecord2(item);
27021
+ if (!record2)
27022
+ return theme.fg("muted", "No zoom result available.");
27023
+ const name = asString(record2.name) ?? "(unknown symbol)";
27024
+ if (record2.success === false) {
27025
+ return theme.fg("error", `Symbol "${name}" not found: ${asString(record2.error) ?? "zoom failed"}`);
27026
+ }
27027
+ const content = asString(record2.content);
27028
+ return [
27029
+ `${theme.fg("accent", name)} ${theme.fg("muted", shortenPath(args.filePath))}`,
27030
+ content
27031
+ ].filter(Boolean).join(`
27032
+ `);
27033
+ })
27034
+ ];
27035
+ }
26859
27036
  const items = Array.isArray(payload) ? payload : payload ? [payload] : [];
26860
27037
  if (items.length === 0)
26861
27038
  return [theme.fg("muted", "No zoom result available.")];
@@ -26974,9 +27151,13 @@ function registerReadingTools(pi, ctx, surface) {
26974
27151
  const req2 = { file: params.filePath, symbol: sym };
26975
27152
  if (params.contextLines !== undefined)
26976
27153
  req2.context_lines = params.contextLines;
26977
- return callBridge(bridge, "zoom", req2, extCtx);
27154
+ return callBridge(bridge, "zoom", req2, extCtx).catch((err) => ({
27155
+ success: false,
27156
+ message: err instanceof Error ? err.message : String(err)
27157
+ }));
26978
27158
  }));
26979
- return textResult(JSON.stringify(results, null, 2));
27159
+ const batch = formatZoomBatchResult(params.symbols, results);
27160
+ return textResult(batch.text, batch);
26980
27161
  }
26981
27162
  const req = { file: params.filePath };
26982
27163
  if (params.symbol)
@@ -26995,6 +27176,40 @@ function registerReadingTools(pi, ctx, surface) {
26995
27176
  });
26996
27177
  }
26997
27178
  }
27179
+ function formatZoomBatchResult(symbols, responses) {
27180
+ const entries = symbols.map((name, index) => {
27181
+ const response = responses[index] ?? { success: false, message: "missing zoom response" };
27182
+ if (response.success === false) {
27183
+ const message = typeof response.message === "string" && response.message.length > 0 ? response.message : "zoom failed";
27184
+ return { name, success: false, error: message };
27185
+ }
27186
+ return { name, success: true, content: zoomResponseContent(response) };
27187
+ });
27188
+ const complete = entries.every((entry) => entry.success);
27189
+ const lines = [];
27190
+ if (!complete) {
27191
+ lines.push("Incomplete zoom results: one or more symbols failed.");
27192
+ }
27193
+ for (const entry of entries) {
27194
+ if (entry.success) {
27195
+ lines.push(`Symbol "${entry.name}":
27196
+ ${entry.content ?? ""}`.trimEnd());
27197
+ } else {
27198
+ lines.push(`Symbol "${entry.name}" not found: ${entry.error ?? "zoom failed"}`);
27199
+ }
27200
+ }
27201
+ return { complete, symbols: entries, text: lines.join(`
27202
+
27203
+ `) };
27204
+ }
27205
+ function zoomResponseContent(response) {
27206
+ if (typeof response.content === "string")
27207
+ return response.content;
27208
+ if (typeof response.text === "string")
27209
+ return response.text;
27210
+ const { success: _success2, ...rest } = response;
27211
+ return JSON.stringify(rest, null, 2);
27212
+ }
26998
27213
  function formatOutlineText(response) {
26999
27214
  const text = response.text ?? "";
27000
27215
  const skipped = response.skipped_files;
@@ -27486,6 +27701,83 @@ function validateTransformParams(params) {
27486
27701
  }
27487
27702
  }
27488
27703
 
27704
+ // src/workflow-hints.ts
27705
+ var HEADING = "## Prefer AFT tools for token efficiency";
27706
+ function buildWorkflowHints(opts) {
27707
+ const sections = [];
27708
+ const grepName = opts.hoistBuiltins ? "grep" : "aft_grep";
27709
+ const bashName = opts.hoistBuiltins ? "bash" : "aft_bash";
27710
+ const hasOutline = !opts.absentTools.has("aft_outline");
27711
+ const hasZoom = !opts.absentTools.has("aft_zoom");
27712
+ const hasGrep = opts.toolSurface !== "minimal" && !opts.absentTools.has(grepName);
27713
+ const hasSearch = opts.toolSurface !== "minimal" && opts.semanticEnabled && !opts.absentTools.has("aft_search");
27714
+ const hasNavigate = opts.toolSurface === "all" && !opts.absentTools.has("aft_navigate");
27715
+ const hasBgBash = opts.bashBackgroundEnabled && !opts.absentTools.has(bashName) && !opts.absentTools.has("bash_status");
27716
+ if (hasOutline && hasZoom) {
27717
+ sections.push(`**Web/URL access**: \`aft_outline({ url })\` first for structure, then \`aft_zoom({ url, symbol: "<heading>" })\` for the specific section.`);
27718
+ }
27719
+ if (hasOutline && hasZoom && (hasGrep || hasSearch)) {
27720
+ const locator = hasGrep && hasSearch ? `\`${grepName}\` or \`aft_search\`` : hasGrep ? `\`${grepName}\`` : "`aft_search`";
27721
+ sections.push(`**Code exploration**: ${locator} to locate → \`aft_outline\` for structure → \`aft_zoom\` for symbol(s).`);
27722
+ }
27723
+ if (hasNavigate) {
27724
+ sections.push([
27725
+ "Use `aft_navigate` instead of grep + read chains for relationship questions:",
27726
+ "- `callers` — find all call sites before changing a function signature",
27727
+ "- `impact` — blast radius (which functions/files will need updates)",
27728
+ "- `trace_to` — how execution reaches this code from entry points (routes, exports, main)",
27729
+ "- `trace_data` — follow a value through assignments and parameters across files"
27730
+ ].join(`
27731
+ `));
27732
+ }
27733
+ if (hasBgBash) {
27734
+ sections.push(`**Long-running commands** (builds, installs, full test suites): \`${bashName}({ background: true })\` returns immediately with a \`taskId\`. Check progress with \`bash_status({ taskId })\`.`);
27735
+ }
27736
+ if (sections.length === 0) {
27737
+ return null;
27738
+ }
27739
+ return `${HEADING}
27740
+
27741
+ ${sections.join(`
27742
+
27743
+ `)}`;
27744
+ }
27745
+ function buildHintsFromConfig(config2, absentTools, hoistBuiltins) {
27746
+ return buildWorkflowHints({
27747
+ toolSurface: config2.tool_surface ?? "recommended",
27748
+ hoistBuiltins,
27749
+ semanticEnabled: config2.semantic_search === true,
27750
+ bashBackgroundEnabled: config2.experimental?.bash?.background === true,
27751
+ absentTools
27752
+ });
27753
+ }
27754
+ function registerWorkflowHints(pi, config2, surface) {
27755
+ const absent = new Set;
27756
+ if (!surface.outline)
27757
+ absent.add("aft_outline");
27758
+ if (!surface.zoom)
27759
+ absent.add("aft_zoom");
27760
+ if (!surface.semantic)
27761
+ absent.add("aft_search");
27762
+ if (!surface.navigate)
27763
+ absent.add("aft_navigate");
27764
+ if (!surface.hoistGrep)
27765
+ absent.add("grep");
27766
+ if (!surface.hoistBash) {
27767
+ absent.add("bash");
27768
+ absent.add("bash_status");
27769
+ }
27770
+ const hintsBlock = buildHintsFromConfig(config2, absent, true);
27771
+ if (!hintsBlock)
27772
+ return;
27773
+ log(`Workflow hints injected (${hintsBlock.length} chars)`);
27774
+ pi.on("before_agent_start", (event) => {
27775
+ return { systemPrompt: `${event.systemPrompt}
27776
+
27777
+ ${hintsBlock}` };
27778
+ });
27779
+ }
27780
+
27489
27781
  // src/index.ts
27490
27782
  var PLUGIN_VERSION = (() => {
27491
27783
  try {
@@ -27531,6 +27823,7 @@ function resolveToolSurface(config2) {
27531
27823
  const allOnly = (name) => ALL_ONLY_TOOLS.has(name) && ok(name);
27532
27824
  if (surface === "minimal") {
27533
27825
  return {
27826
+ hoistBash: ok("bash"),
27534
27827
  hoistRead: false,
27535
27828
  hoistWrite: false,
27536
27829
  hoistEdit: false,
@@ -27552,6 +27845,7 @@ function resolveToolSurface(config2) {
27552
27845
  };
27553
27846
  }
27554
27847
  const base = {
27848
+ hoistBash: ok("bash"),
27555
27849
  hoistRead: ok("read"),
27556
27850
  hoistWrite: ok("write"),
27557
27851
  hoistEdit: ok("edit"),
@@ -27608,6 +27902,8 @@ async function src_default(pi) {
27608
27902
  const configOverrides = {};
27609
27903
  if (config2.format_on_edit !== undefined)
27610
27904
  configOverrides.format_on_edit = config2.format_on_edit;
27905
+ if (config2.formatter_timeout_secs !== undefined)
27906
+ configOverrides.formatter_timeout_secs = config2.formatter_timeout_secs;
27611
27907
  if (config2.validate_on_edit !== undefined)
27612
27908
  configOverrides.validate_on_edit = config2.validate_on_edit;
27613
27909
  if (config2.formatter !== undefined)
@@ -27709,6 +28005,15 @@ ${lines}
27709
28005
  pluginVersion: PLUGIN_VERSION,
27710
28006
  projectRoot
27711
28007
  }, validWarnings);
28008
+ },
28009
+ onBashCompletion: (completion, bridge) => {
28010
+ handlePushedBgCompletion({
28011
+ ctx,
28012
+ directory: process.cwd(),
28013
+ sessionID: completion.session_id,
28014
+ runtime: pi,
28015
+ isActive: () => bridge.hasPendingRequests()
28016
+ }, completion);
27712
28017
  }
27713
28018
  }, configOverrides);
27714
28019
  const ctx = { pool, config: config2, storageDir };
@@ -27716,7 +28021,7 @@ ${lines}
27716
28021
  sendFeatureAnnouncement(ANNOUNCEMENT_VERSION, ANNOUNCEMENT_FEATURES, storageDir);
27717
28022
  }
27718
28023
  const surface = resolveToolSurface(config2);
27719
- if (surface.hoistRead) {
28024
+ if (surface.hoistBash) {
27720
28025
  registerBashTool(pi, ctx);
27721
28026
  }
27722
28027
  registerHoistedTools(pi, ctx, surface);
@@ -27753,6 +28058,7 @@ ${lines}
27753
28058
  if (surface.refactor) {
27754
28059
  registerRefactorTool(pi, ctx);
27755
28060
  }
28061
+ registerWorkflowHints(pi, config2, surface);
27756
28062
  registerStatusCommand(pi, ctx);
27757
28063
  pi.on("tool_result", async (event, extCtx) => {
27758
28064
  const content = await appendToolResultBgCompletions({ ctx, directory: extCtx.cwd, sessionID: resolveSessionId(extCtx) }, event.content);
@@ -27791,6 +28097,8 @@ ${lines}
27791
28097
  });
27792
28098
  log(`AFT extension ready (surface=${config2.tool_surface ?? "recommended"})`);
27793
28099
  }
28100
+ var __test__ = { resolveToolSurface };
27794
28101
  export {
27795
- src_default as default
28102
+ src_default as default,
28103
+ __test__
27796
28104
  };
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAiEA,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAEzD;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAE1D;AAED,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAEnF;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAEpF;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAErF;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAmEA,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAEzD;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAE1D;AAED,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAEnF;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAEpF;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAErF;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,yBAAyB,GAAG,uBAAuB,GAAG,oBAAoB,CAAC;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA2FD,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,uBAAuB,EAC7B,QAAQ,EAAE,gBAAgB,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,EAAE,MAAM,GACjB,IAAI,CAqBN"}
1
+ {"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,yBAAyB,GAAG,uBAAuB,GAAG,oBAAoB,CAAC;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA8FD,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,uBAAuB,EAC7B,QAAQ,EAAE,gBAAgB,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,EAAE,MAAM,GACjB,IAAI,CAqBN"}
package/dist/pool.d.ts CHANGED
@@ -22,6 +22,8 @@ export declare class BridgePool {
22
22
  constructor(binaryPath: string, options?: PoolOptions, configOverrides?: Record<string, unknown>);
23
23
  /** Get any existing alive bridge, preferring the given directory. */
24
24
  getAnyActiveBridge(directory: string): BinaryBridge | null;
25
+ /** Get an alive bridge only when it belongs to the requested directory. */
26
+ getActiveBridgeForRoot(directory: string): BinaryBridge | null;
25
27
  /** Get or create a bridge for the given directory. */
26
28
  getBridge(directory: string): BinaryBridge;
27
29
  private cleanup;
@@ -1 +1 @@
1
- {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAY/D,MAAM,WAAW,WAAY,SAAQ,aAAa;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0B;IAC1D,OAAO,CAAC,YAAY,CAA+C;gBAGjE,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,WAAgB,EACzB,eAAe,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAmB/C,qEAAqE;IACrE,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAgB1D,sDAAsD;IACtD,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY;IAiB1C,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,QAAQ;IAgBV,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAUzB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQnD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
1
+ {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAY/D,MAAM,WAAW,WAAY,SAAQ,aAAa;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0B;IAC1D,OAAO,CAAC,YAAY,CAA+C;gBAGjE,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,WAAgB,EACzB,eAAe,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAoB/C,qEAAqE;IACrE,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAgB1D,2EAA2E;IAC3E,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAQ9D,sDAAsD;IACtD,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY;IAiB1C,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,QAAQ;IAgBV,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAUzB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQnD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -8,6 +8,7 @@ interface BashStatusDetails {
8
8
  success: boolean;
9
9
  status: string;
10
10
  exit_code?: number;
11
+ duration_ms?: number;
11
12
  output_preview?: string;
12
13
  command?: string;
13
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,gBAAgB,EAEjB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAEtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA2DjD,QAAA,MAAM,cAAc;;EAIlB,CAAC;AAWH,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAsCD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAqG3E;AAOD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa;;;;;;;;yBASpC,MAAM,UACX,MAAM,CAAC,OAAO,cAAc,CAAC,WAC5B,WAAW,GAAG,SAAS,aACrB,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,UACrE,gBAAgB;EAW7B;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa;;;;;;;;yBASlC,MAAM,UACX,MAAM,CAAC,OAAO,cAAc,CAAC,WAC5B,WAAW,GAAG,SAAS,aACrB,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,UACnE,gBAAgB;EAW7B"}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,gBAAgB,EAEjB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAEtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA2DjD,QAAA,MAAM,cAAc;;EAIlB,CAAC;AAWH,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAsCD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CA2G3E;AAOD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa;;;;;;;;yBASpC,MAAM,UACX,MAAM,CAAC,OAAO,cAAc,CAAC,WAC5B,WAAW,GAAG,SAAS,aACrB,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,UACrE,gBAAgB;EAW7B;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa;;;;;;;;yBASlC,MAAM,UACX,MAAM,CAAC,OAAO,cAAc,CAAC,WAC5B,WAAW,GAAG,SAAS,aACrB,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,UACnE,gBAAgB;EAW7B"}
@@ -39,6 +39,22 @@ interface FileMutationDetails {
39
39
  * surface this explicitly rather than silently showing a summary.
40
40
  */
41
41
  truncated?: boolean;
42
+ /**
43
+ * Whether AFT's auto-formatter ran on the post-write content. Mirrors the
44
+ * `data.formatted` field from the Rust write/edit response. When true,
45
+ * the file content on disk is what the formatter produced; when false,
46
+ * `formatSkippedReason` explains why.
47
+ */
48
+ formatted?: boolean;
49
+ /**
50
+ * Reason the formatter was skipped, when `formatted=false`. One of the
51
+ * documented values from `crates/aft/src/format.rs::auto_format`:
52
+ * `"unsupported_language"`, `"no_formatter_configured"`,
53
+ * `"formatter_not_installed"`, `"formatter_excluded_path"`, `"timeout"`,
54
+ * `"error"`. Pi agents read this to decide whether to retry, fix config,
55
+ * or accept the unformatted result.
56
+ */
57
+ formatSkippedReason?: string;
42
58
  }
43
59
  export declare function registerHoistedTools(pi: ExtensionAPI, ctx: PluginContext, surface: ToolSurfaceFlags): void;
44
60
  /**
@@ -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,+BAA+B,CAAC;AAGvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA2DjD,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;CACrB;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAmLN;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,eAAe,CAAC,mBAAmB,CAAC,CA6DtC;AAwHD;;;;;;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,+BAA+B,CAAC;AAGvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA2DjD,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;CAC9B;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAmLN;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,eAAe,CAAC,mBAAmB,CAAC,CAiFtC;AAwJD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,mBAAmB,EAAE,OAAO,EAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAgBR"}
@@ -21,6 +21,17 @@ export interface ReadingSurface {
21
21
  outline: boolean;
22
22
  zoom: boolean;
23
23
  }
24
+ interface ZoomBatchSymbolResult {
25
+ name: string;
26
+ success: boolean;
27
+ content?: string;
28
+ error?: string;
29
+ }
30
+ interface ZoomBatchResult {
31
+ complete: boolean;
32
+ symbols: ZoomBatchSymbolResult[];
33
+ text: string;
34
+ }
24
35
  /** Exported for renderer unit tests. */
25
36
  export declare function buildOutlineSections(text: string, theme: Theme): string[];
26
37
  /** Exported for renderer unit tests. */
@@ -34,5 +45,7 @@ export declare function renderZoomCall(args: Static<typeof ZoomParams>, theme: T
34
45
  /** Exported for renderer unit tests. */
35
46
  export declare function renderZoomResult(result: AgentToolResult<unknown>, args: Static<typeof ZoomParams>, theme: Theme, context: RenderContextLike): import("@mariozechner/pi-tui").Text | import("@mariozechner/pi-tui").Container;
36
47
  export declare function registerReadingTools(pi: ExtensionAPI, ctx: PluginContext, surface: ReadingSurface): void;
48
+ /** Exported for regression tests. */
49
+ export declare function formatZoomBatchResult(symbols: string[], responses: Record<string, unknown>[]): ZoomBatchResult;
37
50
  export {};
38
51
  //# sourceMappingURL=reading.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reading.d.ts","sourceRoot":"","sources":["../../src/tools/reading.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAC1F,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAEtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAOL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,aAAa;;;;EAYjB,CAAC;AAEH,QAAA,MAAM,UAAU;;;;;EAWd,CAAC;AAEH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf;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,CA4DV;AAED,wCAAwC;AACxC,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,OAAO,aAAa,CAAC,EAClC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,uCAU3B;AAED,wCAAwC;AACxC,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,kFAI3B;AAED,wCAAwC;AACxC,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,CAAC,OAAO,UAAU,CAAC,EAC/B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,uCAQ3B;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,kFAI3B;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,cAAc,GACtB,IAAI,CAkHN"}
1
+ {"version":3,"file":"reading.d.ts","sourceRoot":"","sources":["../../src/tools/reading.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAC1F,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAEtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAOL,KAAK,iBAAiB,EAKvB,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,aAAa;;;;EAYjB,CAAC;AAEH,QAAA,MAAM,UAAU;;;;;EAWd,CAAC;AAEH,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,CAuFV;AAED,wCAAwC;AACxC,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,OAAO,aAAa,CAAC,EAClC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,uCAU3B;AAED,wCAAwC;AACxC,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,kFAI3B;AAED,wCAAwC;AACxC,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,CAAC,OAAO,UAAU,CAAC,EAC/B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,uCAQ3B;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,kFAI3B;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,cAAc,GACtB,IAAI,CAsHN;AAED,qCAAqC;AACrC,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GACnC,eAAe,CA0BjB"}
@@ -0,0 +1,31 @@
1
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
+ import type { AftConfig } from "./config.js";
3
+ export interface WorkflowHintsOpts {
4
+ toolSurface: "minimal" | "recommended" | "all";
5
+ hoistBuiltins: boolean;
6
+ semanticEnabled: boolean;
7
+ bashBackgroundEnabled: boolean;
8
+ /** Set of tool names KNOWN-ABSENT from the registered surface. */
9
+ absentTools: Set<string>;
10
+ }
11
+ export declare function buildWorkflowHints(opts: WorkflowHintsOpts): string | null;
12
+ export declare function buildHintsFromConfig(config: AftConfig, absentTools: Set<string>, hoistBuiltins: boolean): string | null;
13
+ interface ToolSurfaceFlags {
14
+ outline: boolean;
15
+ zoom: boolean;
16
+ semantic: boolean;
17
+ navigate: boolean;
18
+ hoistGrep: boolean;
19
+ hoistBash: boolean;
20
+ }
21
+ /**
22
+ * Register the workflow-hints extension on Pi via `before_agent_start`.
23
+ *
24
+ * Pi assembles a fresh system prompt for every turn, then fires
25
+ * `before_agent_start` with the assembled prompt. Our handler appends the
26
+ * AFT workflow hints block to that prompt. If multiple extensions return a
27
+ * `systemPrompt`, Pi chains them — so we always append (never replace).
28
+ */
29
+ export declare function registerWorkflowHints(pi: ExtensionAPI, config: AftConfig, surface: ToolSurfaceFlags): void;
30
+ export {};
31
+ //# sourceMappingURL=workflow-hints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-hints.d.ts","sourceRoot":"","sources":["../src/workflow-hints.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,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,CAQf;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.18.2",
3
+ "version": "0.18.4",
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",
@@ -18,6 +18,7 @@
18
18
  "build": "bun build src/index.ts --outdir dist --target node --format esm --external @mariozechner/pi-coding-agent --external @mariozechner/pi-ai --external @mariozechner/pi-tui --external @sinclair/typebox --external diff && tsc --emitDeclarationOnly",
19
19
  "typecheck": "tsc --noEmit",
20
20
  "test": "bun test src/__tests__/",
21
+ "lint": "biome check src",
21
22
  "prepublishOnly": "bun run build"
22
23
  },
23
24
  "dependencies": {
@@ -27,11 +28,11 @@
27
28
  "zod": "^4.1.8"
28
29
  },
29
30
  "optionalDependencies": {
30
- "@cortexkit/aft-darwin-arm64": "0.18.2",
31
- "@cortexkit/aft-darwin-x64": "0.18.2",
32
- "@cortexkit/aft-linux-arm64": "0.18.2",
33
- "@cortexkit/aft-linux-x64": "0.18.2",
34
- "@cortexkit/aft-win32-x64": "0.18.2"
31
+ "@cortexkit/aft-darwin-arm64": "0.18.4",
32
+ "@cortexkit/aft-darwin-x64": "0.18.4",
33
+ "@cortexkit/aft-linux-arm64": "0.18.4",
34
+ "@cortexkit/aft-linux-x64": "0.18.4",
35
+ "@cortexkit/aft-win32-x64": "0.18.4"
35
36
  },
36
37
  "devDependencies": {
37
38
  "@mariozechner/pi-coding-agent": "*",