thoth-agents 0.3.8 → 0.3.10

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.
Files changed (41) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +27 -0
  3. package/dist/agents/prompt-dialects.d.ts +3 -0
  4. package/dist/{chunk-3WNTCPVK.js → chunk-JBG7XMIG.js} +1291 -290
  5. package/dist/{chunk-F2K4CS5J.js → chunk-M2WF46BP.js} +186 -128
  6. package/dist/{chunk-6GQYMWWT.js → chunk-TKIDBRM3.js} +1 -1
  7. package/dist/cli/commands.d.ts +1 -0
  8. package/dist/cli/config-io.d.ts +2 -1
  9. package/dist/cli/index.js +126 -428
  10. package/dist/cli/install-completion.d.ts +34 -0
  11. package/dist/cli/install-ledger.d.ts +44 -0
  12. package/dist/cli/install.d.ts +9 -1
  13. package/dist/cli/operations/claude-code.d.ts +12 -1
  14. package/dist/cli/operations/codex.d.ts +16 -0
  15. package/dist/cli/operations/opencode.d.ts +20 -3
  16. package/dist/cli/operations/types.d.ts +13 -0
  17. package/dist/cli/package-version.d.ts +19 -0
  18. package/dist/cli/tui/index.js +63 -24
  19. package/dist/harness/core/sdd.d.ts +1 -1
  20. package/dist/hooks/auto-update-checker/checker.d.ts +0 -5
  21. package/dist/hooks/auto-update-checker/index.d.ts +1 -2
  22. package/dist/hooks/auto-update-checker/types.d.ts +0 -1
  23. package/dist/index.js +98 -251
  24. package/package.json +1 -1
  25. package/plugin/.claude-plugin/.thoth-agents-plugin-assets.json +1 -1
  26. package/plugin/.claude-plugin/plugin.json +1 -1
  27. package/plugin/.codex-plugin/plugin.json +1 -1
  28. package/plugin/agents/orchestrator.md +17 -17
  29. package/plugin/skills/thoth-archive/SKILL.md +7 -0
  30. package/plugin/skills/thoth-archive/scripts/archive.mjs +28 -74
  31. package/plugin/skills/thoth-sdd/references/phases/specify.md +12 -1
  32. package/plugin/skills/thoth-sdd/scripts/durable-deltas.mjs +158 -0
  33. package/plugin/skills/thoth-sdd/scripts/validate.mjs +67 -28
  34. package/plugin/skills/thoth-sdd/templates/spec.md +9 -1
  35. package/skills/thoth-archive/SKILL.md +7 -0
  36. package/skills/thoth-archive/scripts/archive.mjs +28 -74
  37. package/skills/thoth-sdd/references/phases/specify.md +12 -1
  38. package/skills/thoth-sdd/scripts/durable-deltas.mjs +158 -0
  39. package/skills/thoth-sdd/scripts/validate.mjs +67 -28
  40. package/skills/thoth-sdd/templates/spec.md +9 -1
  41. package/dist/hooks/auto-update-checker/cache.d.ts +0 -7
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  renderOpenCodeAgentConfigs,
4
4
  spawn,
5
5
  spawnSync
6
- } from "./chunk-6GQYMWWT.js";
6
+ } from "./chunk-TKIDBRM3.js";
7
7
  import {
8
8
  POLL_INTERVAL_BACKGROUND_MS,
9
9
  context7,
@@ -12,7 +12,7 @@ import {
12
12
  grep_app,
13
13
  loadPluginConfig,
14
14
  stripJsonComments
15
- } from "./chunk-F2K4CS5J.js";
15
+ } from "./chunk-M2WF46BP.js";
16
16
 
17
17
  // src/index.ts
18
18
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -61,24 +61,25 @@ import { createRequire } from "module";
61
61
  var require2 = createRequire(import.meta.url);
62
62
  function getLogFile() {
63
63
  const os2 = require2("node:os");
64
- const path4 = require2("node:path");
64
+ const path3 = require2("node:path");
65
65
  const configuredPath = process.env.THOTH_AGENTS_LOG_FILE?.trim();
66
- return configuredPath || path4.join(os2.tmpdir(), "thoth-agents.log");
66
+ return configuredPath || path3.join(os2.tmpdir(), "thoth-agents.log");
67
67
  }
68
68
  function log(message, data) {
69
69
  try {
70
- const fs3 = require2("node:fs");
70
+ const fs2 = require2("node:fs");
71
71
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
72
72
  const logEntry = `[${timestamp}] ${message} ${data ? JSON.stringify(data) : ""}
73
73
  `;
74
- fs3.appendFileSync(getLogFile(), logEntry);
74
+ fs2.appendFileSync(getLogFile(), logEntry);
75
75
  } catch {
76
76
  }
77
77
  }
78
78
 
79
- // src/hooks/auto-update-checker/cache.ts
79
+ // src/hooks/auto-update-checker/checker.ts
80
80
  import * as fs from "fs";
81
81
  import * as path2 from "path";
82
+ import { fileURLToPath } from "url";
82
83
 
83
84
  // src/hooks/auto-update-checker/constants.ts
84
85
  import * as os from "os";
@@ -103,54 +104,7 @@ var configPaths = getOpenCodeConfigPaths();
103
104
  var USER_OPENCODE_CONFIG = configPaths[0];
104
105
  var USER_OPENCODE_CONFIG_JSONC = configPaths[1];
105
106
 
106
- // src/hooks/auto-update-checker/cache.ts
107
- function invalidatePnpmPackageCache(packageName = PACKAGE_NAME) {
108
- try {
109
- const pkgDir = path2.join(CACHE_DIR, "node_modules", packageName);
110
- const pkgJsonPath = path2.join(CACHE_DIR, "package.json");
111
- let packageRemoved = false;
112
- let dependencyRemoved = false;
113
- if (fs.existsSync(pkgDir)) {
114
- fs.rmSync(pkgDir, { recursive: true, force: true });
115
- log(`[auto-update-checker] Package removed: ${pkgDir}`);
116
- packageRemoved = true;
117
- }
118
- if (fs.existsSync(pkgJsonPath)) {
119
- try {
120
- const content = fs.readFileSync(pkgJsonPath, "utf-8");
121
- const pkgJson = JSON.parse(stripJsonComments(content));
122
- if (pkgJson.dependencies?.[packageName]) {
123
- delete pkgJson.dependencies[packageName];
124
- fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
125
- log(
126
- `[auto-update-checker] Dependency removed from package.json: ${packageName}`
127
- );
128
- dependencyRemoved = true;
129
- }
130
- } catch (err) {
131
- log(
132
- `[auto-update-checker] Failed to update package.json for invalidation:`,
133
- err
134
- );
135
- }
136
- }
137
- if (!packageRemoved && !dependencyRemoved) {
138
- log(
139
- `[auto-update-checker] Package not found, nothing to invalidate: ${packageName}`
140
- );
141
- return false;
142
- }
143
- return true;
144
- } catch (err) {
145
- log("[auto-update-checker] Failed to invalidate package:", err);
146
- return false;
147
- }
148
- }
149
-
150
107
  // src/hooks/auto-update-checker/checker.ts
151
- import * as fs2 from "fs";
152
- import * as path3 from "path";
153
- import { fileURLToPath } from "url";
154
108
  function isPrereleaseVersion(version) {
155
109
  return version.includes("-");
156
110
  }
@@ -171,8 +125,8 @@ function extractChannel(version) {
171
125
  }
172
126
  function getConfigPaths(directory) {
173
127
  return [
174
- path3.join(directory, ".opencode", "opencode.json"),
175
- path3.join(directory, ".opencode", "opencode.jsonc"),
128
+ path2.join(directory, ".opencode", "opencode.json"),
129
+ path2.join(directory, ".opencode", "opencode.jsonc"),
176
130
  USER_OPENCODE_CONFIG,
177
131
  USER_OPENCODE_CONFIG_JSONC
178
132
  ];
@@ -180,8 +134,8 @@ function getConfigPaths(directory) {
180
134
  function getLocalDevPath(directory) {
181
135
  for (const configPath of getConfigPaths(directory)) {
182
136
  try {
183
- if (!fs2.existsSync(configPath)) continue;
184
- const content = fs2.readFileSync(configPath, "utf-8");
137
+ if (!fs.existsSync(configPath)) continue;
138
+ const content = fs.readFileSync(configPath, "utf-8");
185
139
  const config = JSON.parse(stripJsonComments(content));
186
140
  const plugins = config.plugin ?? [];
187
141
  for (const entry of plugins) {
@@ -200,19 +154,19 @@ function getLocalDevPath(directory) {
200
154
  }
201
155
  function findPackageJsonUp(startPath) {
202
156
  try {
203
- const stat = fs2.statSync(startPath);
204
- let dir = stat.isDirectory() ? startPath : path3.dirname(startPath);
157
+ const stat = fs.statSync(startPath);
158
+ let dir = stat.isDirectory() ? startPath : path2.dirname(startPath);
205
159
  for (let i = 0; i < 10; i++) {
206
- const pkgPath = path3.join(dir, "package.json");
207
- if (fs2.existsSync(pkgPath)) {
160
+ const pkgPath = path2.join(dir, "package.json");
161
+ if (fs.existsSync(pkgPath)) {
208
162
  try {
209
- const content = fs2.readFileSync(pkgPath, "utf-8");
163
+ const content = fs.readFileSync(pkgPath, "utf-8");
210
164
  const pkg = JSON.parse(content);
211
165
  if (pkg.name === PACKAGE_NAME) return pkgPath;
212
166
  } catch {
213
167
  }
214
168
  }
215
- const parent = path3.dirname(dir);
169
+ const parent = path2.dirname(dir);
216
170
  if (parent === dir) break;
217
171
  dir = parent;
218
172
  }
@@ -226,7 +180,7 @@ function getLocalDevVersion(directory) {
226
180
  try {
227
181
  const pkgPath = findPackageJsonUp(localPath);
228
182
  if (!pkgPath) return null;
229
- const content = fs2.readFileSync(pkgPath, "utf-8");
183
+ const content = fs.readFileSync(pkgPath, "utf-8");
230
184
  const pkg = JSON.parse(content);
231
185
  return pkg.version ?? null;
232
186
  } catch {
@@ -236,8 +190,8 @@ function getLocalDevVersion(directory) {
236
190
  function findPluginEntry(directory) {
237
191
  for (const configPath of getConfigPaths(directory)) {
238
192
  try {
239
- if (!fs2.existsSync(configPath)) continue;
240
- const content = fs2.readFileSync(configPath, "utf-8");
193
+ if (!fs.existsSync(configPath)) continue;
194
+ const content = fs.readFileSync(configPath, "utf-8");
241
195
  const config = JSON.parse(stripJsonComments(content));
242
196
  const plugins = config.plugin ?? [];
243
197
  for (const entry of plugins) {
@@ -264,8 +218,8 @@ var cachedPackageVersion = null;
264
218
  function getCachedVersion() {
265
219
  if (cachedPackageVersion) return cachedPackageVersion;
266
220
  try {
267
- if (fs2.existsSync(INSTALLED_PACKAGE_JSON)) {
268
- const content = fs2.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
221
+ if (fs.existsSync(INSTALLED_PACKAGE_JSON)) {
222
+ const content = fs.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
269
223
  const pkg = JSON.parse(content);
270
224
  if (pkg.version) {
271
225
  cachedPackageVersion = pkg.version;
@@ -275,10 +229,10 @@ function getCachedVersion() {
275
229
  } catch {
276
230
  }
277
231
  try {
278
- const currentDir = path3.dirname(fileURLToPath(import.meta.url));
232
+ const currentDir = path2.dirname(fileURLToPath(import.meta.url));
279
233
  const pkgPath = findPackageJsonUp(currentDir);
280
234
  if (pkgPath) {
281
- const content = fs2.readFileSync(pkgPath, "utf-8");
235
+ const content = fs.readFileSync(pkgPath, "utf-8");
282
236
  const pkg = JSON.parse(content);
283
237
  if (pkg.version) {
284
238
  cachedPackageVersion = pkg.version;
@@ -293,36 +247,6 @@ function getCachedVersion() {
293
247
  }
294
248
  return null;
295
249
  }
296
- function updatePinnedVersion(configPath, oldEntry, newVersion) {
297
- try {
298
- if (!fs2.existsSync(configPath)) return false;
299
- const content = fs2.readFileSync(configPath, "utf-8");
300
- const newEntry = `${PACKAGE_NAME}@${newVersion}`;
301
- const escapedOldEntry = oldEntry.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
302
- const entryRegex = new RegExp(`(["'])${escapedOldEntry}\\1`, "g");
303
- if (!entryRegex.test(content)) {
304
- log(
305
- `[auto-update-checker] Entry "${oldEntry}" not found in ${configPath}`
306
- );
307
- return false;
308
- }
309
- const updatedContent = content.replace(entryRegex, `$1${newEntry}$1`);
310
- if (updatedContent === content) {
311
- return false;
312
- }
313
- fs2.writeFileSync(configPath, updatedContent, "utf-8");
314
- log(
315
- `[auto-update-checker] Updated ${configPath}: ${oldEntry} \u2192 ${newEntry}`
316
- );
317
- return true;
318
- } catch (err) {
319
- log(
320
- `[auto-update-checker] Failed to update config file ${configPath}:`,
321
- err
322
- );
323
- return false;
324
- }
325
- }
326
250
  async function getLatestVersion(channel = "latest") {
327
251
  const controller = new AbortController();
328
252
  const timeoutId = setTimeout(() => controller.abort(), NPM_FETCH_TIMEOUT);
@@ -342,8 +266,8 @@ async function getLatestVersion(channel = "latest") {
342
266
  }
343
267
 
344
268
  // src/hooks/auto-update-checker/index.ts
345
- function createAutoUpdateCheckerHook(ctx, options = {}, shell) {
346
- const { showStartupToast = true, autoUpdate = true } = options;
269
+ function createAutoUpdateCheckerHook(ctx, options = {}) {
270
+ const { showStartupToast = true } = options;
347
271
  let hasChecked = false;
348
272
  return {
349
273
  event: ({ event }) => {
@@ -376,14 +300,14 @@ function createAutoUpdateCheckerHook(ctx, options = {}, shell) {
376
300
  "info"
377
301
  );
378
302
  }
379
- runBackgroundUpdateCheck(ctx, shell, autoUpdate).catch((err) => {
303
+ runBackgroundUpdateCheck(ctx).catch((err) => {
380
304
  log("[auto-update-checker] Background update check failed:", err);
381
305
  });
382
306
  }, 0);
383
307
  }
384
308
  };
385
309
  }
386
- async function runBackgroundUpdateCheck(ctx, shell, autoUpdate) {
310
+ async function runBackgroundUpdateCheck(ctx) {
387
311
  const pluginInfo = findPluginEntry(ctx.directory);
388
312
  if (!pluginInfo) {
389
313
  log("[auto-update-checker] Plugin not found in config");
@@ -414,86 +338,14 @@ async function runBackgroundUpdateCheck(ctx, shell, autoUpdate) {
414
338
  log(
415
339
  `[auto-update-checker] Update available (${channel}): ${currentVersion} \u2192 ${latestVersion}`
416
340
  );
417
- if (!autoUpdate) {
418
- showToast(
419
- ctx,
420
- `thoth-agents ${latestVersion}`,
421
- `v${latestVersion} available. Restart to apply.`,
422
- "info",
423
- 8e3
424
- );
425
- log("[auto-update-checker] Auto-update disabled, notification only");
426
- return;
427
- }
428
- if (pluginInfo.isPinned) {
429
- const updated = updatePinnedVersion(
430
- pluginInfo.configPath,
431
- pluginInfo.entry,
432
- latestVersion
433
- );
434
- if (!updated) {
435
- showToast(
436
- ctx,
437
- `thoth-agents ${latestVersion}`,
438
- `v${latestVersion} available. Restart to apply.`,
439
- "info",
440
- 8e3
441
- );
442
- log("[auto-update-checker] Failed to update pinned version in config");
443
- return;
444
- }
445
- log(
446
- `[auto-update-checker] Config updated: ${pluginInfo.entry} \u2192 ${PACKAGE_NAME}@${latestVersion}`
447
- );
448
- }
449
- invalidatePnpmPackageCache(PACKAGE_NAME);
450
- const installSuccess = await runPnpmInstallSafe(ctx, shell);
451
- if (installSuccess) {
452
- showToast(
453
- ctx,
454
- "thoth-agents Updated!",
455
- `v${currentVersion} \u2192 v${latestVersion}
456
- Restart OpenCode to apply.`,
457
- "success",
458
- 8e3
459
- );
460
- log(
461
- `[auto-update-checker] Update installed: ${currentVersion} \u2192 ${latestVersion}`
462
- );
463
- } else {
464
- showToast(
465
- ctx,
466
- `thoth-agents ${latestVersion}`,
467
- `v${latestVersion} available. Restart to apply.`,
468
- "info",
469
- 8e3
470
- );
471
- log("[auto-update-checker] pnpm install failed; update not installed");
472
- }
473
- }
474
- async function runPnpmInstallSafe(ctx, shell) {
475
- try {
476
- const timeoutPromise = new Promise(
477
- (resolve4) => setTimeout(() => resolve4("timeout"), 6e4)
478
- );
479
- const installPromise = (async () => {
480
- try {
481
- await shell`cd ${ctx.directory} && pnpm install`;
482
- return "completed";
483
- } catch {
484
- return "failed";
485
- }
486
- })();
487
- const result = await Promise.race([installPromise, timeoutPromise]);
488
- if (result === "timeout") {
489
- log("[auto-update-checker] pnpm install timed out after 60 seconds");
490
- return false;
491
- }
492
- return result === "completed";
493
- } catch (err) {
494
- log("[auto-update-checker] pnpm install error:", err);
495
- return false;
496
- }
341
+ showToast(
342
+ ctx,
343
+ `thoth-agents ${latestVersion} available`,
344
+ `v${currentVersion} \u2192 v${latestVersion}. Run npx thoth-agents@latest install --agent=opencode or use interactive CLI Update.`,
345
+ "info",
346
+ 1e4
347
+ );
348
+ log("[auto-update-checker] Notification only; explicit CLI update required");
497
349
  }
498
350
  function showToast(ctx, title, message, variant = "info", duration = 3e3) {
499
351
  ctx.client.tui.showToast({
@@ -925,19 +777,19 @@ function createBuiltinMcps(disabledMcps = []) {
925
777
  import { tool } from "@opencode-ai/plugin/tool";
926
778
 
927
779
  // src/tools/ast-grep/cli.ts
928
- import { existsSync as existsSync6 } from "fs";
780
+ import { existsSync as existsSync5 } from "fs";
929
781
 
930
782
  // src/tools/ast-grep/constants.ts
931
783
  import { spawnSync as spawnSync2 } from "child_process";
932
- import { existsSync as existsSync5, statSync as statSync2 } from "fs";
784
+ import { existsSync as existsSync4, statSync as statSync2 } from "fs";
933
785
  import { createRequire as createRequire3 } from "module";
934
- import { dirname as dirname2, join as join6 } from "path";
786
+ import { dirname as dirname2, join as join5 } from "path";
935
787
 
936
788
  // src/tools/ast-grep/downloader.ts
937
- import { chmodSync, existsSync as existsSync4, mkdirSync, unlinkSync } from "fs";
789
+ import { chmodSync, existsSync as existsSync3, mkdirSync, unlinkSync } from "fs";
938
790
  import { createRequire as createRequire2 } from "module";
939
791
  import { homedir as homedir2 } from "os";
940
- import { join as join5 } from "path";
792
+ import { join as join4 } from "path";
941
793
 
942
794
  // src/utils/tmux.ts
943
795
  var tmuxPath = null;
@@ -991,22 +843,22 @@ async function findTmuxPath() {
991
843
  return null;
992
844
  }
993
845
  const stdout = await new Response(proc.stdout).text();
994
- const path4 = stdout.trim().split("\n")[0];
995
- if (!path4) {
846
+ const path3 = stdout.trim().split("\n")[0];
847
+ if (!path3) {
996
848
  log("[tmux] findTmuxPath: no path in output");
997
849
  return null;
998
850
  }
999
- const verifyProc = spawn([path4, "-V"], {
851
+ const verifyProc = spawn([path3, "-V"], {
1000
852
  stdout: "pipe",
1001
853
  stderr: "pipe"
1002
854
  });
1003
855
  const verifyExit = await verifyProc.exited;
1004
856
  if (verifyExit !== 0) {
1005
- log("[tmux] findTmuxPath: tmux -V failed", { path: path4, verifyExit });
857
+ log("[tmux] findTmuxPath: tmux -V failed", { path: path3, verifyExit });
1006
858
  return null;
1007
859
  }
1008
- log("[tmux] findTmuxPath: found tmux", { path: path4 });
1009
- return path4;
860
+ log("[tmux] findTmuxPath: found tmux", { path: path3 });
861
+ return path3;
1010
862
  } catch (err) {
1011
863
  log("[tmux] findTmuxPath: exception", { error: String(err) });
1012
864
  return null;
@@ -1206,8 +1058,8 @@ function isPwshAvailable() {
1206
1058
  });
1207
1059
  return result.exitCode === 0;
1208
1060
  }
1209
- function escapePowerShellPath(path4) {
1210
- return path4.replace(/'/g, "''");
1061
+ function escapePowerShellPath(path3) {
1062
+ return path3.replace(/'/g, "''");
1211
1063
  }
1212
1064
  function getWindowsZipExtractor() {
1213
1065
  const buildNumber = getWindowsBuildNumber();
@@ -1303,19 +1155,19 @@ var PLATFORM_MAP = {
1303
1155
  function getCacheDir2() {
1304
1156
  if (process.platform === "win32") {
1305
1157
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
1306
- const base2 = localAppData || join5(homedir2(), "AppData", "Local");
1307
- return join5(base2, "thoth-agents", "bin");
1158
+ const base2 = localAppData || join4(homedir2(), "AppData", "Local");
1159
+ return join4(base2, "thoth-agents", "bin");
1308
1160
  }
1309
1161
  const xdgCache = process.env.XDG_CACHE_HOME;
1310
- const base = xdgCache || join5(homedir2(), ".cache");
1311
- return join5(base, "thoth-agents", "bin");
1162
+ const base = xdgCache || join4(homedir2(), ".cache");
1163
+ return join4(base, "thoth-agents", "bin");
1312
1164
  }
1313
1165
  function getBinaryName() {
1314
1166
  return process.platform === "win32" ? "sg.exe" : "sg";
1315
1167
  }
1316
1168
  function getCachedBinaryPath() {
1317
- const binaryPath = join5(getCacheDir2(), getBinaryName());
1318
- return existsSync4(binaryPath) ? binaryPath : null;
1169
+ const binaryPath = join4(getCacheDir2(), getBinaryName());
1170
+ return existsSync3(binaryPath) ? binaryPath : null;
1319
1171
  }
1320
1172
  async function downloadAstGrep(version = DEFAULT_VERSION) {
1321
1173
  const platformKey = `${process.platform}-${process.arch}`;
@@ -1328,8 +1180,8 @@ async function downloadAstGrep(version = DEFAULT_VERSION) {
1328
1180
  }
1329
1181
  const cacheDir = getCacheDir2();
1330
1182
  const binaryName = getBinaryName();
1331
- const binaryPath = join5(cacheDir, binaryName);
1332
- if (existsSync4(binaryPath)) {
1183
+ const binaryPath = join4(cacheDir, binaryName);
1184
+ if (existsSync3(binaryPath)) {
1333
1185
  return binaryPath;
1334
1186
  }
1335
1187
  const { arch, os: os2 } = platformInfo;
@@ -1337,21 +1189,21 @@ async function downloadAstGrep(version = DEFAULT_VERSION) {
1337
1189
  const downloadUrl = `https://github.com/${REPO}/releases/download/${version}/${assetName}`;
1338
1190
  console.log(`[thoth-agents] Downloading ast-grep binary...`);
1339
1191
  try {
1340
- if (!existsSync4(cacheDir)) {
1192
+ if (!existsSync3(cacheDir)) {
1341
1193
  mkdirSync(cacheDir, { recursive: true });
1342
1194
  }
1343
1195
  const response = await fetch(downloadUrl, { redirect: "follow" });
1344
1196
  if (!response.ok) {
1345
1197
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
1346
1198
  }
1347
- const archivePath = join5(cacheDir, assetName);
1199
+ const archivePath = join4(cacheDir, assetName);
1348
1200
  const arrayBuffer = await response.arrayBuffer();
1349
1201
  await writeTextFile(archivePath, arrayBuffer);
1350
1202
  await extractZip(archivePath, cacheDir);
1351
- if (existsSync4(archivePath)) {
1203
+ if (existsSync3(archivePath)) {
1352
1204
  unlinkSync(archivePath);
1353
1205
  }
1354
- if (process.platform !== "win32" && existsSync4(binaryPath)) {
1206
+ if (process.platform !== "win32" && existsSync3(binaryPath)) {
1355
1207
  chmodSync(binaryPath, 493);
1356
1208
  }
1357
1209
  console.log(`[thoth-agents] ast-grep binary ready.`);
@@ -1435,8 +1287,8 @@ function findSgCliPathSync() {
1435
1287
  const require3 = createRequire3(import.meta.url);
1436
1288
  const cliPkgPath = require3.resolve("@ast-grep/cli/package.json");
1437
1289
  const cliDir = dirname2(cliPkgPath);
1438
- const sgPath = join6(cliDir, binaryName);
1439
- if (existsSync5(sgPath) && isValidBinary(sgPath)) {
1290
+ const sgPath = join5(cliDir, binaryName);
1291
+ if (existsSync4(sgPath) && isValidBinary(sgPath)) {
1440
1292
  return sgPath;
1441
1293
  }
1442
1294
  } catch {
@@ -1448,8 +1300,8 @@ function findSgCliPathSync() {
1448
1300
  const pkgPath = require3.resolve(`${platformPkg}/package.json`);
1449
1301
  const pkgDir = dirname2(pkgPath);
1450
1302
  const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
1451
- const binaryPath = join6(pkgDir, astGrepName);
1452
- if (existsSync5(binaryPath) && isValidBinary(binaryPath)) {
1303
+ const binaryPath = join5(pkgDir, astGrepName);
1304
+ if (existsSync4(binaryPath) && isValidBinary(binaryPath)) {
1453
1305
  return binaryPath;
1454
1306
  }
1455
1307
  } catch {
@@ -1457,9 +1309,9 @@ function findSgCliPathSync() {
1457
1309
  }
1458
1310
  if (process.platform === "darwin") {
1459
1311
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
1460
- for (const path4 of homebrewPaths) {
1461
- if (existsSync5(path4) && isValidBinary(path4)) {
1462
- return path4;
1312
+ for (const path3 of homebrewPaths) {
1313
+ if (existsSync4(path3) && isValidBinary(path3)) {
1314
+ return path3;
1463
1315
  }
1464
1316
  }
1465
1317
  }
@@ -1476,8 +1328,8 @@ function getSgCliPath() {
1476
1328
  }
1477
1329
  return "sg";
1478
1330
  }
1479
- function setSgCliPath(path4) {
1480
- resolvedCliPath = path4;
1331
+ function setSgCliPath(path3) {
1332
+ resolvedCliPath = path3;
1481
1333
  }
1482
1334
  var DEFAULT_TIMEOUT_MS = 3e5;
1483
1335
  var DEFAULT_MAX_OUTPUT_BYTES = 1 * 1024 * 1024;
@@ -1487,7 +1339,7 @@ var DEFAULT_MAX_MATCHES = 500;
1487
1339
  var initPromise = null;
1488
1340
  async function getAstGrepPath() {
1489
1341
  const currentPath = getSgCliPath();
1490
- if (currentPath !== "sg" && existsSync6(currentPath)) {
1342
+ if (currentPath !== "sg" && existsSync5(currentPath)) {
1491
1343
  return currentPath;
1492
1344
  }
1493
1345
  if (initPromise) {
@@ -1495,7 +1347,7 @@ async function getAstGrepPath() {
1495
1347
  }
1496
1348
  initPromise = (async () => {
1497
1349
  const syncPath = findSgCliPathSync();
1498
- if (syncPath && existsSync6(syncPath)) {
1350
+ if (syncPath && existsSync5(syncPath)) {
1499
1351
  setSgCliPath(syncPath);
1500
1352
  return syncPath;
1501
1353
  }
@@ -1534,7 +1386,7 @@ async function runSg(options) {
1534
1386
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
1535
1387
  args.push(...paths);
1536
1388
  let cliPath = getSgCliPath();
1537
- if (!existsSync6(cliPath) && cliPath !== "sg") {
1389
+ if (!existsSync5(cliPath) && cliPath !== "sg") {
1538
1390
  const downloadedPath = await getAstGrepPath();
1539
1391
  if (downloadedPath) {
1540
1392
  cliPath = downloadedPath;
@@ -1827,7 +1679,7 @@ var ast_grep_replace = tool({
1827
1679
  });
1828
1680
 
1829
1681
  // src/tools/lsp/client.ts
1830
- import { readFileSync as readFileSync4 } from "fs";
1682
+ import { readFileSync as readFileSync3 } from "fs";
1831
1683
  import { extname, resolve as resolve2 } from "path";
1832
1684
  import { Readable, Writable } from "stream";
1833
1685
  import { pathToFileURL } from "url";
@@ -1838,9 +1690,9 @@ import {
1838
1690
  } from "vscode-jsonrpc/node.js";
1839
1691
 
1840
1692
  // src/tools/lsp/config.ts
1841
- import { existsSync as existsSync8 } from "fs";
1693
+ import { existsSync as existsSync7 } from "fs";
1842
1694
  import { homedir as homedir3 } from "os";
1843
- import { join as join7 } from "path";
1695
+ import { join as join6 } from "path";
1844
1696
  import whichSync from "which";
1845
1697
 
1846
1698
  // src/tools/lsp/config-store.ts
@@ -1871,7 +1723,7 @@ function hasUserLspConfig() {
1871
1723
  }
1872
1724
 
1873
1725
  // src/tools/lsp/constants.ts
1874
- import { existsSync as existsSync7, readdirSync, statSync as statSync3 } from "fs";
1726
+ import { existsSync as existsSync6, readdirSync, statSync as statSync3 } from "fs";
1875
1727
  import { dirname as dirname3, resolve } from "path";
1876
1728
  var SEVERITY_MAP = {
1877
1729
  1: "error",
@@ -1911,7 +1763,7 @@ function NearestRoot(includePatterns, excludePatterns) {
1911
1763
  if (excludePatterns) {
1912
1764
  for (const dir of walkUpDirectories(file, cwd)) {
1913
1765
  for (const pattern of excludePatterns) {
1914
- if (existsSync7(`${dir}/${pattern}`)) {
1766
+ if (existsSync6(`${dir}/${pattern}`)) {
1915
1767
  return void 0;
1916
1768
  }
1917
1769
  }
@@ -1930,7 +1782,7 @@ function NearestRoot(includePatterns, excludePatterns) {
1930
1782
  }
1931
1783
  } catch {
1932
1784
  }
1933
- } else if (existsSync7(`${dir}/${pattern}`)) {
1785
+ } else if (existsSync6(`${dir}/${pattern}`)) {
1934
1786
  return dir;
1935
1787
  }
1936
1788
  }
@@ -2552,11 +2404,11 @@ function isServerInstalled(command) {
2552
2404
  if (command.length === 0) return false;
2553
2405
  const cmd = command[0];
2554
2406
  if (cmd.includes("/") || cmd.includes("\\")) {
2555
- return existsSync8(cmd);
2407
+ return existsSync7(cmd);
2556
2408
  }
2557
2409
  const isWindows = process.platform === "win32";
2558
2410
  const ext = isWindows ? ".exe" : "";
2559
- const opencodeBin = join7(homedir3(), ".config", "opencode", "bin");
2411
+ const opencodeBin = join6(homedir3(), ".config", "opencode", "bin");
2560
2412
  const searchPath = (process.env.PATH ?? "") + (isWindows ? ";" : ":") + opencodeBin;
2561
2413
  const result = whichSync.sync(cmd, {
2562
2414
  path: searchPath,
@@ -2567,8 +2419,8 @@ function isServerInstalled(command) {
2567
2419
  return true;
2568
2420
  }
2569
2421
  const cwd = process.cwd();
2570
- const localBin = join7(cwd, "node_modules", ".bin", cmd);
2571
- if (existsSync8(localBin) || existsSync8(localBin + ext)) {
2422
+ const localBin = join6(cwd, "node_modules", ".bin", cmd);
2423
+ if (existsSync7(localBin) || existsSync7(localBin + ext)) {
2572
2424
  return true;
2573
2425
  }
2574
2426
  return false;
@@ -2908,7 +2760,7 @@ stderr: ${stderr}` : "")
2908
2760
  log("[lsp] openFile: already open, skipping", { filePath: absPath });
2909
2761
  return;
2910
2762
  }
2911
- const text = readFileSync4(absPath, "utf-8");
2763
+ const text = readFileSync3(absPath, "utf-8");
2912
2764
  const ext = extname(absPath);
2913
2765
  const languageId = getLanguageId(ext);
2914
2766
  log("[lsp] openFile: opening document", {
@@ -2999,13 +2851,13 @@ import { tool as tool2 } from "@opencode-ai/plugin/tool";
2999
2851
 
3000
2852
  // src/tools/lsp/utils.ts
3001
2853
  import {
3002
- existsSync as existsSync9,
3003
- readFileSync as readFileSync5,
2854
+ existsSync as existsSync8,
2855
+ readFileSync as readFileSync4,
3004
2856
  statSync as statSync4,
3005
2857
  unlinkSync as unlinkSync2,
3006
- writeFileSync as writeFileSync3
2858
+ writeFileSync
3007
2859
  } from "fs";
3008
- import { dirname as dirname4, extname as extname2, join as join8, resolve as resolve3 } from "path";
2860
+ import { dirname as dirname4, extname as extname2, join as join7, resolve as resolve3 } from "path";
3009
2861
  import { fileURLToPath as fileURLToPath2 } from "url";
3010
2862
  function findServerProjectRoot(filePath, server) {
3011
2863
  if (server.root) {
@@ -3111,7 +2963,7 @@ function filterDiagnosticsBySeverity(diagnostics, severityFilter) {
3111
2963
  }
3112
2964
  function applyTextEditsToFile(filePath, edits) {
3113
2965
  try {
3114
- const content = readFileSync5(filePath, "utf-8");
2966
+ const content = readFileSync4(filePath, "utf-8");
3115
2967
  const lines = content.split("\n");
3116
2968
  const sortedEdits = [...edits].sort((a, b) => {
3117
2969
  if (b.range.start.line !== a.range.start.line) {
@@ -3138,7 +2990,7 @@ function applyTextEditsToFile(filePath, edits) {
3138
2990
  );
3139
2991
  }
3140
2992
  }
3141
- writeFileSync3(filePath, lines.join("\n"), "utf-8");
2993
+ writeFileSync(filePath, lines.join("\n"), "utf-8");
3142
2994
  return { success: true, editCount: edits.length };
3143
2995
  } catch (err) {
3144
2996
  return {
@@ -3185,7 +3037,7 @@ function applyWorkspaceEdit(edit) {
3185
3037
  if (change.kind === "create") {
3186
3038
  try {
3187
3039
  const filePath = uriToPath(change.uri);
3188
- writeFileSync3(filePath, "", "utf-8");
3040
+ writeFileSync(filePath, "", "utf-8");
3189
3041
  result.filesModified.push(filePath);
3190
3042
  } catch (err) {
3191
3043
  result.success = false;
@@ -3195,8 +3047,8 @@ function applyWorkspaceEdit(edit) {
3195
3047
  try {
3196
3048
  const oldPath = uriToPath(change.oldUri);
3197
3049
  const newPath = uriToPath(change.newUri);
3198
- const content = readFileSync5(oldPath, "utf-8");
3199
- writeFileSync3(newPath, content, "utf-8");
3050
+ const content = readFileSync4(oldPath, "utf-8");
3051
+ writeFileSync(newPath, content, "utf-8");
3200
3052
  unlinkSync2(oldPath);
3201
3053
  result.filesModified.push(newPath);
3202
3054
  } catch (err) {
@@ -3578,7 +3430,7 @@ var TmuxSessionManager = class {
3578
3430
 
3579
3431
  // src/index.ts
3580
3432
  var ThothAgents = async (ctx, _options) => {
3581
- const { client, directory, $: shell } = ctx;
3433
+ const { client, directory } = ctx;
3582
3434
  const config = loadPluginConfig(directory);
3583
3435
  const agentDefs = createAgents(config);
3584
3436
  const agents = renderOpenCodeAgentConfigs(config);
@@ -3629,14 +3481,9 @@ var ThothAgents = async (ctx, _options) => {
3629
3481
  }
3630
3482
  const mcps = createBuiltinMcps(config.disabled_mcps);
3631
3483
  const tmuxSessionManager = new TmuxSessionManager(ctx, tmuxConfig);
3632
- const autoUpdateChecker = createAutoUpdateCheckerHook(
3633
- ctx,
3634
- {
3635
- showStartupToast: true,
3636
- autoUpdate: true
3637
- },
3638
- shell
3639
- );
3484
+ const autoUpdateChecker = createAutoUpdateCheckerHook(ctx, {
3485
+ showStartupToast: true
3486
+ });
3640
3487
  const delegateTaskRetryHook = createDelegateTaskRetryHook(ctx);
3641
3488
  const jsonErrorRecoveryHook = createJsonErrorRecoveryHook(ctx);
3642
3489
  const foregroundFallback = new ForegroundFallbackManager(