@cortexkit/aft-opencode 0.47.2 → 0.48.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
@@ -71,6 +71,11 @@ export declare const AftConfigSchema: z.ZodPreprocess<z.ZodObject<{
71
71
  max_depth: z.ZodOptional<z.ZodNumber>;
72
72
  max_file_size: z.ZodOptional<z.ZodNumber>;
73
73
  }, z.core.$strip>>;
74
+ sandbox: z.ZodOptional<z.ZodObject<{
75
+ enabled: z.ZodOptional<z.ZodBoolean>;
76
+ write_allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
77
+ read_deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
78
+ }, z.core.$strip>>;
74
79
  bash: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
75
80
  rewrite: z.ZodOptional<z.ZodBoolean>;
76
81
  compress: z.ZodOptional<z.ZodBoolean>;
@@ -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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAoNlD;;;;;;;;;;;;;;;;GAgBG;AAQH,QAAA,MAAM,MAAM,EAAE,MAA6D,CAAC;AAsjC5E,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAiNlD;;;;;;;;;;;;;;;;GAgBG;AAQH,QAAA,MAAM,MAAM,EAAE,MAA6D,CAAC;AAsjC5E,eAAe,MAAM,CAAC"}
package/dist/index.js CHANGED
@@ -14328,6 +14328,9 @@ class SubcTransportPool {
14328
14328
  if (record.routeEntry === entry2) {
14329
14329
  entry2.closed = true;
14330
14330
  record.routeEntry = null;
14331
+ if (entry2.handle != null) {
14332
+ safeCloseRoute(entry2.client, entry2.handle);
14333
+ }
14331
14334
  }
14332
14335
  };
14333
14336
  const handleRequestFailure = (err, entry2) => {
@@ -30137,6 +30140,11 @@ var BashFeaturesSchema = exports_external.object({
30137
30140
  foreground_wait_window_ms: exports_external.number().int().positive().optional()
30138
30141
  });
30139
30142
  var BashConfigSchema = exports_external.union([exports_external.boolean(), BashFeaturesSchema]);
30143
+ var SandboxConfigSchema = exports_external.object({
30144
+ enabled: exports_external.boolean().optional(),
30145
+ write_allow: exports_external.array(exports_external.string()).optional(),
30146
+ read_deny: exports_external.array(exports_external.string()).optional()
30147
+ });
30140
30148
  var BridgeConfigSchema = exports_external.object({
30141
30149
  request_timeout_ms: exports_external.number().int().min(1000, { message: "bridge.request_timeout_ms must be at least 1000" }).optional(),
30142
30150
  hang_threshold: exports_external.number().int().min(1, { message: "bridge.hang_threshold must be at least 1" }).optional()
@@ -30178,6 +30186,7 @@ var AftConfigSchema = exports_external.preprocess((value) => stripHarnessSpecifi
30178
30186
  callgraph_chunk_size: exports_external.number().optional(),
30179
30187
  inspect: InspectConfigSchema.optional(),
30180
30188
  backup: BackupConfigSchema.optional(),
30189
+ sandbox: SandboxConfigSchema.optional(),
30181
30190
  bash: BashConfigSchema.optional(),
30182
30191
  experimental: ExperimentalConfigSchema.optional(),
30183
30192
  lsp: LspConfigSchema.optional(),
@@ -30511,6 +30520,15 @@ function mergeInspectConfig(baseInspect, overrideInspect) {
30511
30520
  }
30512
30521
  return Object.fromEntries(Object.entries(inspect).filter(([, value]) => value !== undefined));
30513
30522
  }
30523
+ function mergeSandboxConfig(base, project) {
30524
+ const readDeny = [...new Set([...base?.read_deny ?? [], ...project?.read_deny ?? []])];
30525
+ const merged = {
30526
+ ...base,
30527
+ ...readDeny.length > 0 ? { read_deny: readDeny } : {},
30528
+ ...project?.enabled === true ? { enabled: true } : {}
30529
+ };
30530
+ return Object.keys(merged).length > 0 ? merged : undefined;
30531
+ }
30514
30532
  function mergeBashConfig(baseBash, overrideBash) {
30515
30533
  if (baseBash === undefined && overrideBash === undefined)
30516
30534
  return;
@@ -30599,6 +30617,10 @@ function getStrippedTopLevelKeys(override) {
30599
30617
  stripped.push("bridge");
30600
30618
  if (override.backup !== undefined)
30601
30619
  stripped.push("backup");
30620
+ if (override.sandbox?.enabled === false)
30621
+ stripped.push("sandbox.enabled");
30622
+ if (override.sandbox?.write_allow !== undefined)
30623
+ stripped.push("sandbox.write_allow");
30602
30624
  if (override.subc !== undefined)
30603
30625
  stripped.push("subc");
30604
30626
  if (override.disabled_tools?.includes("aft_safety"))
@@ -30617,6 +30639,7 @@ function mergeConfigs(base, override) {
30617
30639
  const experimental = mergeExperimentalConfig(base.experimental, override.experimental);
30618
30640
  const bash = mergeBashConfig(base.bash, override.bash);
30619
30641
  const inspect = mergeInspectConfig(base.inspect, override.inspect);
30642
+ const sandbox = mergeSandboxConfig(base.sandbox, override.sandbox);
30620
30643
  const bridge = base.bridge;
30621
30644
  const safeOverride = pickProjectSafeFields(override);
30622
30645
  delete safeOverride.bash;
@@ -30629,6 +30652,7 @@ function mergeConfigs(base, override) {
30629
30652
  ...lsp ? { lsp } : {},
30630
30653
  ...bash !== undefined ? { bash } : {},
30631
30654
  ...inspect !== undefined ? { inspect } : {},
30655
+ ...sandbox !== undefined ? { sandbox } : {},
30632
30656
  experimental,
30633
30657
  semantic,
30634
30658
  ...bridge !== undefined ? { bridge } : {},
@@ -35016,7 +35040,6 @@ function astTools(ctx) {
35016
35040
  }
35017
35041
 
35018
35042
  // src/tools/bash.ts
35019
- import * as fs4 from "node:fs/promises";
35020
35043
  import { tool as tool4 } from "@opencode-ai/plugin";
35021
35044
 
35022
35045
  // src/shared/subagent-detect.ts
@@ -35110,8 +35133,8 @@ function groupBashPermissionAsks(asks) {
35110
35133
  bashAsk = { kind: "bash", patterns: [], always: [] };
35111
35134
  grouped.push(bashAsk);
35112
35135
  }
35113
- pushUnique(bashAsk.patterns, ask.patterns);
35114
- pushUnique(bashAsk.always, ask.always);
35136
+ pushUnique(bashAsk.patterns ?? [], ask.patterns ?? []);
35137
+ pushUnique(bashAsk.always ?? [], ask.always ?? []);
35115
35138
  continue;
35116
35139
  }
35117
35140
  grouped.push(ask);
@@ -35119,27 +35142,53 @@ function groupBashPermissionAsks(asks) {
35119
35142
  return grouped;
35120
35143
  }
35121
35144
  function permissionsGrantedForRetry(asks) {
35122
- return asks.flatMap((ask) => ask.always.length > 0 ? ask.always : ask.patterns);
35145
+ return asks.flatMap((ask) => {
35146
+ if (ask.kind === "escalation")
35147
+ return ask.grant_id ? [ask.grant_id] : [];
35148
+ const always = ask.always ?? [];
35149
+ return always.length > 0 ? always : ask.patterns ?? [];
35150
+ });
35151
+ }
35152
+ function escalationAskText(ask) {
35153
+ return `This command will run UNSANDBOXED on the host.
35154
+
35155
+ Exact command:
35156
+ ${ask.command ?? ""}
35157
+
35158
+ Working directory:
35159
+ ${ask.cwd ?? ""}`;
35123
35160
  }
35124
35161
  async function withPermissionLoop(ctx, runtime, params, bridgeCall, options) {
35125
- const first = await bridgeCall(ctx, runtime, "bash", params, options);
35126
- if (first.success !== false || first.code !== "permission_required")
35127
- return first;
35128
- const asks = Array.isArray(first.asks) ? first.asks : [];
35129
- for (const ask of groupBashPermissionAsks(asks)) {
35130
- const permission = ask.kind === "external_directory" ? "external_directory" : "bash";
35131
- await runAsk(runtime.ask({
35132
- permission,
35133
- patterns: ask.patterns,
35134
- always: ask.always,
35135
- metadata: {}
35136
- }));
35137
- }
35138
- const second = await bridgeCall(ctx, runtime, "bash", { ...params, permissions_granted: permissionsGrantedForRetry(asks) }, options);
35139
- if (second.success === false && second.code === "permission_required") {
35140
- throw new Error("bash permission retry failed");
35162
+ const granted = Array.isArray(params.permissions_granted) ? params.permissions_granted.filter((value) => typeof value === "string") : [];
35163
+ let response = await bridgeCall(ctx, runtime, "bash", params, options);
35164
+ for (let round = 0;round < 8; round++) {
35165
+ if (response.success !== false || response.code !== "permission_required")
35166
+ return response;
35167
+ const asks = Array.isArray(response.asks) ? response.asks : [];
35168
+ if (asks.length === 0)
35169
+ throw new Error("bash permission retry failed: no asks returned");
35170
+ for (const ask of groupBashPermissionAsks(asks)) {
35171
+ const permission = ask.kind === "external_directory" ? "external_directory" : "bash";
35172
+ const escalation = ask.kind === "escalation";
35173
+ await runAsk(runtime.ask({
35174
+ permission,
35175
+ patterns: escalation ? [escalationAskText(ask)] : ask.patterns ?? [],
35176
+ always: escalation ? [] : ask.always ?? [],
35177
+ metadata: escalation ? {
35178
+ command: ask.command ?? "",
35179
+ cwd: ask.cwd ?? "",
35180
+ grant_id: ask.grant_id ?? "",
35181
+ unsandboxed: true
35182
+ } : {}
35183
+ }));
35184
+ }
35185
+ for (const grant of permissionsGrantedForRetry(asks)) {
35186
+ if (!granted.includes(grant))
35187
+ granted.push(grant);
35188
+ }
35189
+ response = await bridgeCall(ctx, runtime, "bash", { ...params, permissions_granted: granted }, options);
35141
35190
  }
35142
- return second;
35191
+ throw new Error("bash permission retry failed: too many rounds");
35143
35192
  }
35144
35193
  function createBashTool(ctx, aftSearchRegisteredOverride) {
35145
35194
  const initialBashCfg = resolveBashConfig(ctx.config);
@@ -35157,6 +35206,7 @@ function createBashTool(ctx, aftSearchRegisteredOverride) {
35157
35206
  workdir: z4.string().optional().describe("Working directory for command execution. Relative paths resolve through the bridge; defaults to the current tool context/project root when omitted."),
35158
35207
  description: z4.string().optional().describe("Short 5-10 word human-readable summary shown in OpenCode UI metadata instead of raw shell syntax."),
35159
35208
  wait: z4.boolean().optional().describe("When true, run in the foreground without auto-promoting and wait until the command finishes or reaches its timeout; if you send a new message, the wait detaches to background. Use only when you know the result is required before doing anything else."),
35209
+ sandbox: z4.literal("host").optional().describe("Request one-command approval to run unsandboxed on the host; use only when native sandboxing blocks required work, and note that it is a no-op when sandboxing is disabled."),
35160
35210
  ...backgroundFlagArg,
35161
35211
  compressed: z4.boolean().optional().describe("When true or omitted, return compressed output with noisy terminal control sequences reduced. Set to false for raw output."),
35162
35212
  ...ptyArgs
@@ -35219,7 +35269,8 @@ function createBashTool(ctx, aftSearchRegisteredOverride) {
35219
35269
  permissions_requested: true,
35220
35270
  foreground_orchestrate: true,
35221
35271
  block_to_completion: blockToCompletion,
35222
- wait: requestedWait
35272
+ wait: requestedWait,
35273
+ sandbox: args2.sandbox
35223
35274
  }, callBashBridge, {
35224
35275
  transportTimeoutMs: orchestratedTransportTimeoutMs(blockToCompletion, requestedWait, effectiveTimeout, foregroundWaitMs),
35225
35276
  onProgress: ({ text }) => {
@@ -35315,19 +35366,15 @@ A completion reminder will be delivered automatically; don't poll.`;
35315
35366
  return text;
35316
35367
  }
35317
35368
  async function formatPtyStatus(_runtime, taskId, data, requestedOutputMode) {
35318
- const outputPath = data.output_path;
35319
- if (!outputPath)
35320
- return `
35321
- [PTY output path unavailable]`;
35322
35369
  const outputMode = requestedOutputMode ?? "screen";
35323
- const raw = outputMode === "raw" || outputMode === "both" ? await fs4.readFile(outputPath) : undefined;
35370
+ const raw = typeof data.pty_raw === "string" ? data.pty_raw : "";
35324
35371
  let suffix = "";
35325
35372
  if (outputMode === "raw") {
35326
- suffix = raw && raw.length > 0 ? `
35327
- ${raw.toString("utf8")}` : "";
35373
+ suffix = raw.length > 0 ? `
35374
+ ${raw}` : "";
35328
35375
  } else if (outputMode === "both") {
35329
35376
  suffix = `
35330
- ${JSON.stringify({ screen: String(data.pty_screen ?? ""), raw: raw?.toString("utf8") ?? "" }, null, 2)}`;
35377
+ ${JSON.stringify({ screen: String(data.pty_screen ?? ""), raw }, null, 2)}`;
35331
35378
  } else {
35332
35379
  const screen = data.pty_screen;
35333
35380
  suffix = screen ? `
@@ -35401,12 +35448,11 @@ function conflictTools(ctx) {
35401
35448
  }
35402
35449
 
35403
35450
  // src/tools/hoisted.ts
35404
- import * as fs6 from "node:fs";
35451
+ import * as fs4 from "node:fs";
35405
35452
  import * as path4 from "node:path";
35406
35453
  import { tool as tool8 } from "@opencode-ai/plugin";
35407
35454
 
35408
35455
  // src/tools/bash_watch.ts
35409
- import * as fs5 from "node:fs/promises";
35410
35456
  import { tool as tool6 } from "@opencode-ai/plugin";
35411
35457
  var z6 = tool6.schema;
35412
35458
  var BASH_WAIT_POLL_INTERVAL_MS = 100;
@@ -35538,8 +35584,13 @@ ${preview2}`;
35538
35584
  }
35539
35585
  return text;
35540
35586
  }
35541
- async function bashStatusSnapshot2(ctx, runtime, taskId, outputMode, options) {
35542
- const data = await callBashBridge(ctx, runtime, "bash_status", { task_id: taskId, output_mode: outputMode }, options);
35587
+ async function bashStatusSnapshot2(ctx, runtime, taskId, outputMode, cursor, options) {
35588
+ const data = await callBashBridge(ctx, runtime, "bash_status", {
35589
+ task_id: taskId,
35590
+ output_mode: outputMode,
35591
+ output_offset: cursor?.output,
35592
+ stderr_offset: cursor?.stderr
35593
+ }, options);
35543
35594
  if (data.success === false)
35544
35595
  throw new Error(data.message ?? "bash_status failed");
35545
35596
  return data;
@@ -35564,7 +35615,7 @@ async function waitForBashStatus(ctx, runtime, taskId, outputMode, waitFor, effe
35564
35615
  while (true) {
35565
35616
  let data;
35566
35617
  try {
35567
- data = await bashStatusSnapshot2(ctx, runtime, taskId, outputMode, bridgeOptions);
35618
+ data = await bashStatusSnapshot2(ctx, runtime, taskId, outputMode, waitFor ? spillCursor : undefined, bridgeOptions);
35568
35619
  } catch (err) {
35569
35620
  if (!isBridgeTransportTimeout(err))
35570
35621
  throw err;
@@ -35643,14 +35694,9 @@ async function waitForBashStatus(ctx, runtime, taskId, outputMode, waitFor, effe
35643
35694
  }
35644
35695
  }
35645
35696
  async function readNewTaskOutput(data, cursor) {
35646
- const outputPath = data.output_path;
35647
- const stderrPath = data.mode === "pty" ? undefined : data.stderr_path;
35648
- if (!outputPath && !stderrPath)
35649
- return;
35650
- const stdoutBytes = outputPath ? await readFileBytesFrom(outputPath, cursor.output) : Buffer.alloc(0);
35651
- const stderrBytes = stderrPath ? await readFileBytesFrom(stderrPath, cursor.stderr) : Buffer.alloc(0);
35652
- const bytesRead = stdoutBytes.length + stderrBytes.length;
35653
- if (bytesRead === 0)
35697
+ const stdoutBytes = typeof data.output_chunk_base64 === "string" ? Buffer.from(data.output_chunk_base64, "base64") : Buffer.alloc(0);
35698
+ const stderrBytes = typeof data.stderr_chunk_base64 === "string" ? Buffer.from(data.stderr_chunk_base64, "base64") : Buffer.alloc(0);
35699
+ if (stdoutBytes.length + stderrBytes.length === 0)
35654
35700
  return;
35655
35701
  const chunks = [];
35656
35702
  if (stdoutBytes.length > 0) {
@@ -35670,31 +35716,11 @@ async function readNewTaskOutput(data, cursor) {
35670
35716
  return {
35671
35717
  chunks,
35672
35718
  nextCursor: {
35673
- output: cursor.output + stdoutBytes.length,
35674
- stderr: cursor.stderr + stderrBytes.length
35719
+ output: typeof data.output_next_offset === "number" ? data.output_next_offset : cursor.output + stdoutBytes.length,
35720
+ stderr: typeof data.stderr_next_offset === "number" ? data.stderr_next_offset : cursor.stderr + stderrBytes.length
35675
35721
  }
35676
35722
  };
35677
35723
  }
35678
- async function readFileBytesFrom(outputPath, cursor) {
35679
- const handle = await fs5.open(outputPath, "r");
35680
- try {
35681
- const chunks = [];
35682
- let offset = cursor;
35683
- while (true) {
35684
- const buffer2 = Buffer.allocUnsafe(64 * 1024);
35685
- const { bytesRead } = await handle.read(buffer2, 0, buffer2.length, offset);
35686
- if (bytesRead === 0)
35687
- break;
35688
- chunks.push(Buffer.from(buffer2.subarray(0, bytesRead)));
35689
- offset += bytesRead;
35690
- }
35691
- return Buffer.concat(chunks);
35692
- } finally {
35693
- await handle.close().catch(() => {
35694
- return;
35695
- });
35696
- }
35697
- }
35698
35724
  function parseWaitPattern(value) {
35699
35725
  if (typeof value === "string")
35700
35726
  return { kind: "substring", value };
@@ -35973,7 +35999,7 @@ function diagnosticsOnEditDefault(ctx) {
35973
35999
  }
35974
36000
  async function readCurrentFileForPreview(filePath) {
35975
36001
  try {
35976
- return await fs6.promises.readFile(filePath, "utf-8");
36002
+ return await fs4.promises.readFile(filePath, "utf-8");
35977
36003
  } catch (error53) {
35978
36004
  if (error53 && typeof error53 === "object" && "code" in error53 && error53.code === "ENOENT") {
35979
36005
  return "";
@@ -37355,7 +37381,7 @@ function safetyTools(ctx) {
37355
37381
  }
37356
37382
 
37357
37383
  // src/tools/search.ts
37358
- import * as fs7 from "node:fs";
37384
+ import * as fs5 from "node:fs";
37359
37385
  import * as path6 from "node:path";
37360
37386
  function arg2(schema) {
37361
37387
  return schema;
@@ -37364,7 +37390,7 @@ function absoluteSearchPath(projectRoot, target) {
37364
37390
  return resolvePathFromProjectRoot(projectRoot, expandTilde2(target));
37365
37391
  }
37366
37392
  function searchPathExists(projectRoot, target) {
37367
- return fs7.existsSync(absoluteSearchPath(projectRoot, target));
37393
+ return fs5.existsSync(absoluteSearchPath(projectRoot, target));
37368
37394
  }
37369
37395
  function splitSearchPathArg(projectRoot, raw) {
37370
37396
  if (searchPathExists(projectRoot, raw) || !/\s/.test(raw)) {
@@ -37407,7 +37433,7 @@ ${note}` : note;
37407
37433
  }
37408
37434
  function searchPathKind(projectRoot, target, defaultKind) {
37409
37435
  try {
37410
- const stat2 = fs7.lstatSync(absoluteSearchPath(projectRoot, target));
37436
+ const stat2 = fs5.lstatSync(absoluteSearchPath(projectRoot, target));
37411
37437
  if (defaultKind === "file") {
37412
37438
  return stat2.isDirectory() ? "directory" : "file";
37413
37439
  }
@@ -37702,14 +37728,11 @@ var PLUGIN_VERSION = (() => {
37702
37728
  return "0.0.0";
37703
37729
  }
37704
37730
  })();
37705
- var ANNOUNCEMENT_VERSION = "0.47.2";
37731
+ var ANNOUNCEMENT_VERSION = "0.48.0";
37706
37732
  var ANNOUNCEMENT_FEATURES = [
37707
- "Fixed: apply_patch wrote mixed line endings when editing CRLF (Windows) files; the file's dominant line ending is now preserved.",
37708
- "Fixed: inlining a function argument like twice(1 + 2) could change operator precedence; non-atomic arguments are now parenthesized.",
37709
- "Fixed: removing one name from a Python import with an aliased sibling (from m import a, b as c) could delete the whole line.",
37710
- "Fixed: bash_watch could report a match that spanned the stdout/stderr seam; streams are now scanned independently.",
37711
- "GitHub and GitLab file links (…/blob/…) now read raw file content in aft_outline/aft_zoom, and documentation heading lookups tolerate numeric prefixes, link labels, emoji, and anchor slugs.",
37712
- "bash now finds tools on a PATH exported from your shell rc (e.g. zsh .zshrc), and several warm hot paths got faster."
37733
+ "New (beta, off by default): an optional native sandbox for hoisted bash. Confines commands to your project and blocks reads of your credentials (~/.ssh, ~/.aws, cloud configs). Enable with sandbox.enabled in aft.jsonc macOS and Linux; see docs/config.md for the platform matrix.",
37734
+ "Fixed: Windows background bash tasks could report failed with no exit code after a detach/rebind completion is now recorded reliably.",
37735
+ "Fixed: search no longer rebuilds its index unnecessarily for repositories with grafted history."
37713
37736
  ];
37714
37737
  var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
37715
37738
  var plugin = async (input) => initializePluginForDirectory(input);
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAMvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAuCjD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,mBAAmB,EAAE,OAAO,EAC5B,aAAa,EAAE,OAAO,EACtB,YAAY,EAAE,OAAO,GACpB,MAAM,CAaR;AA6ED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,aAAa,EAClB,2BAA2B,CAAC,EAAE,OAAO,GACpC,cAAc,CA2NhB;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CA2BvE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAwBrE"}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAMvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAuCjD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,mBAAmB,EAAE,OAAO,EAC5B,aAAa,EAAE,OAAO,EACtB,YAAY,EAAE,OAAO,GACpB,MAAM,CAaR;AAwGD,wBAAgB,cAAc,CAC5B,GAAG,EAAE,aAAa,EAClB,2BAA2B,CAAC,EAAE,OAAO,GACpC,cAAc,CAkOhB;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CA2BvE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAwBrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"bash_watch.d.ts","sourceRoot":"","sources":["../../src/tools/bash_watch.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAavE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AASjD,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACtC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,cAAc,GAAG,aAAa,CAAC;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACpC,CAAC;AAUF,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAMlF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CA0GtE;AAiHD,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,EAAE,eAAe,GAAG,SAAS,EACpC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,kBAAkB,CAAC,CAoH7B;AA2DD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS,CAI5E;AAkGD,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAEtC"}
1
+ {"version":3,"file":"bash_watch.d.ts","sourceRoot":"","sources":["../../src/tools/bash_watch.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAavE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AASjD,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACtC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,cAAc,GAAG,aAAa,CAAC;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACpC,CAAC;AAUF,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAMlF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CA0GtE;AAuHD,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,EAAE,eAAe,GAAG,SAAS,EACpC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,kBAAkB,CAAC,CA2H7B;AA6CD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS,CAI5E;AAkGD,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAEtC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/aft-opencode",
3
- "version": "0.47.2",
3
+ "version": "0.48.0",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Agent File Tools (AFT) — tree-sitter and lsp powered code analysis",
6
6
  "main": "dist/index.js",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@clack/prompts": "^1.6.0",
37
- "@cortexkit/aft-bridge": "0.47.2",
37
+ "@cortexkit/aft-bridge": "0.48.0",
38
38
  "@opentui/core": "0.4.3",
39
39
  "@opentui/solid": "0.4.3",
40
40
  "comment-json": "^4.6.2",
@@ -43,12 +43,12 @@
43
43
  "zod": "^4.4.3"
44
44
  },
45
45
  "optionalDependencies": {
46
- "@cortexkit/aft-darwin-arm64": "0.47.2",
47
- "@cortexkit/aft-darwin-x64": "0.47.2",
48
- "@cortexkit/aft-linux-arm64": "0.47.2",
49
- "@cortexkit/aft-linux-x64": "0.47.2",
50
- "@cortexkit/aft-win32-arm64": "0.47.2",
51
- "@cortexkit/aft-win32-x64": "0.47.2"
46
+ "@cortexkit/aft-darwin-arm64": "0.48.0",
47
+ "@cortexkit/aft-darwin-x64": "0.48.0",
48
+ "@cortexkit/aft-linux-arm64": "0.48.0",
49
+ "@cortexkit/aft-linux-x64": "0.48.0",
50
+ "@cortexkit/aft-win32-arm64": "0.48.0",
51
+ "@cortexkit/aft-win32-x64": "0.48.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@opencode-ai/plugin": "^1.17.11",