thoth-agents 0.2.10 → 0.2.11

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.
@@ -425,7 +425,27 @@ function writeConfig(configPath, config) {
425
425
  writeFileSync(tmpPath, content);
426
426
  renameSync(tmpPath, configPath);
427
427
  }
428
- async function addPluginToOpenCodeConfig() {
428
+ function mergeOpenCodeMainConfig(config, update) {
429
+ if (update.ensurePlugin) {
430
+ const plugins = Array.isArray(config.plugin) ? config.plugin : [];
431
+ config.plugin = [
432
+ ...plugins.filter(
433
+ (plugin) => plugin !== PACKAGE_NAME && !plugin.startsWith(`${PACKAGE_NAME}@`)
434
+ ),
435
+ `${PACKAGE_NAME}@latest`
436
+ ];
437
+ }
438
+ if (update.disableDefaults) {
439
+ const agent = config.agent && typeof config.agent === "object" ? { ...config.agent } : {};
440
+ const explore = agent.explore && typeof agent.explore === "object" ? { ...agent.explore } : {};
441
+ const general = agent.general && typeof agent.general === "object" ? { ...agent.general } : {};
442
+ agent.explore = { ...explore, disable: true };
443
+ agent.general = { ...general, disable: true };
444
+ config.agent = agent;
445
+ }
446
+ return config;
447
+ }
448
+ function updateOpenCodeMainConfig(update) {
429
449
  const configPath = getExistingConfigPath();
430
450
  try {
431
451
  ensureOpenCodeConfigDir();
@@ -445,14 +465,10 @@ async function addPluginToOpenCodeConfig() {
445
465
  error: `Failed to parse config: ${error}`
446
466
  };
447
467
  }
448
- const config = parsedConfig ?? {};
449
- const plugins = config.plugin ?? [];
450
- const filteredPlugins = plugins.filter(
451
- (p) => p !== PACKAGE_NAME && !p.startsWith(`${PACKAGE_NAME}@`)
468
+ writeConfig(
469
+ configPath,
470
+ mergeOpenCodeMainConfig(parsedConfig ?? {}, update)
452
471
  );
453
- filteredPlugins.push(`${PACKAGE_NAME}@latest`);
454
- config.plugin = filteredPlugins;
455
- writeConfig(configPath, config);
456
472
  return { success: true, configPath };
457
473
  } catch (err) {
458
474
  return {
@@ -485,33 +501,6 @@ function writeLiteConfig(installConfig, targetPath) {
485
501
  };
486
502
  }
487
503
  }
488
- function disableDefaultAgents() {
489
- const configPath = getExistingConfigPath();
490
- try {
491
- ensureOpenCodeConfigDir();
492
- const { config: parsedConfig, error } = parseConfig(configPath);
493
- if (error) {
494
- return {
495
- success: false,
496
- configPath,
497
- error: `Failed to parse config: ${error}`
498
- };
499
- }
500
- const config = parsedConfig ?? {};
501
- const agent = config.agent ?? {};
502
- agent.explore = { disable: true };
503
- agent.general = { disable: true };
504
- config.agent = agent;
505
- writeConfig(configPath, config);
506
- return { success: true, configPath };
507
- } catch (err) {
508
- return {
509
- success: false,
510
- configPath,
511
- error: `Failed to disable default agents: ${err}`
512
- };
513
- }
514
- }
515
504
  function detectCurrentConfig() {
516
505
  const result = {
517
506
  isInstalled: false,
@@ -2114,6 +2103,9 @@ function resolvePackageRoot(packageRoot) {
2114
2103
  const moduleDir = fileURLToPath(new URL(".", import.meta.url));
2115
2104
  return findPackageRoot(moduleDir) ?? fileURLToPath(new URL("../..", import.meta.url));
2116
2105
  }
2106
+ function checkCustomSkillsNeedUpdate(packageRoot) {
2107
+ return checkSkillsNeedUpdate(resolvePackageRoot(packageRoot));
2108
+ }
2117
2109
  function installCustomSkillFiles(skill, packageRoot) {
2118
2110
  const sourcePath = join4(packageRoot, skill.sourcePath);
2119
2111
  const targetPath = join4(getCustomSkillsDir(), skill.name);
@@ -2310,14 +2302,12 @@ export {
2310
2302
  getExistingLiteConfigPath,
2311
2303
  getExistingConfigPath,
2312
2304
  ensureConfigDir,
2313
- ensureOpenCodeConfigDir,
2314
2305
  generateLiteConfig,
2315
2306
  stripJsonComments,
2316
2307
  parseConfig,
2317
2308
  writeConfig,
2318
- addPluginToOpenCodeConfig,
2309
+ updateOpenCodeMainConfig,
2319
2310
  writeLiteConfig,
2320
- disableDefaultAgents,
2321
2311
  detectCurrentConfig,
2322
2312
  loadPluginConfig,
2323
2313
  loadAgentPrompt,
@@ -2344,6 +2334,7 @@ export {
2344
2334
  CUSTOM_SKILLS,
2345
2335
  getCustomSkillsDir,
2346
2336
  findPackageRoot,
2337
+ checkCustomSkillsNeedUpdate,
2347
2338
  installCustomSkills,
2348
2339
  CONTEXT7_MCP_URL,
2349
2340
  context7,
@@ -16,6 +16,11 @@ export declare function parseConfig(path: string): {
16
16
  */
17
17
  export declare function writeConfig(configPath: string, config: OpenCodeConfig): void;
18
18
  export declare function addPluginToOpenCodeConfig(): Promise<ConfigMergeResult>;
19
+ export interface OpenCodeMainConfigUpdate {
20
+ ensurePlugin?: boolean;
21
+ disableDefaults?: boolean;
22
+ }
23
+ export declare function updateOpenCodeMainConfig(update: OpenCodeMainConfigUpdate): ConfigMergeResult;
19
24
  export declare function writeLiteConfig(installConfig: InstallConfig, targetPath?: string): ConfigMergeResult;
20
25
  export declare function disableDefaultAgents(): ConfigMergeResult;
21
26
  export declare function canModifyOpenCodeConfig(): boolean;
@@ -1,4 +1,4 @@
1
- import { type SkillUpdateReason } from './skill-manifest';
1
+ import { type SkillUpdateCheck, type SkillUpdateReason } from './skill-manifest';
2
2
  /**
3
3
  * A custom skill bundled in this repository.
4
4
  * Unlike npx-installed skills, these are copied from src/skills/ to the OpenCode skills directory
@@ -37,6 +37,7 @@ export interface InstallCustomSkillsReport {
37
37
  */
38
38
  export declare function getCustomSkillsDir(): string;
39
39
  export declare function findPackageRoot(startDir: string): string | null;
40
+ export declare function checkCustomSkillsNeedUpdate(packageRoot?: string): SkillUpdateCheck;
40
41
  export declare function removeObsoleteSkills(removedSkillNames: string[]): string[];
41
42
  export declare function installCustomSkills(packageRoot?: string): InstallCustomSkillsReport;
42
43
  /**
package/dist/cli/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  getOpenCodeVersion,
5
5
  isOpenCodeInstalled,
6
6
  opencodeAdapter
7
- } from "../chunk-MF5NNCPC.js";
7
+ } from "../chunk-6BNAV534.js";
8
8
  import {
9
9
  CODEX_ROLE_NAMES,
10
10
  RECOMMENDED_SKILLS,
@@ -41,19 +41,18 @@ import {
41
41
  installRecommendedSkill,
42
42
  listOperationHarnesses,
43
43
  normalizeEffortSelection
44
- } from "../chunk-YYVE7YHR.js";
44
+ } from "../chunk-ASKXWU6E.js";
45
45
  import {
46
46
  ALL_AGENT_NAMES,
47
47
  CUSTOM_SKILLS,
48
48
  DEFAULT_MODELS,
49
- addPluginToOpenCodeConfig,
50
49
  detectCurrentConfig,
51
- disableDefaultAgents,
52
50
  generateLiteConfig,
53
51
  getExistingLiteConfigPath,
54
52
  installCustomSkills,
53
+ updateOpenCodeMainConfig,
55
54
  writeLiteConfig
56
- } from "../chunk-WBRGPRRB.js";
55
+ } from "../chunk-OZE7JVGS.js";
57
56
 
58
57
  // src/cli/index.ts
59
58
  import { pathToFileURL } from "url";
@@ -167,7 +166,7 @@ async function runInstall(config) {
167
166
  const detected = detectCurrentConfig();
168
167
  const isUpdate = detected.isInstalled;
169
168
  printHeader(isUpdate);
170
- let totalSteps = 4;
169
+ let totalSteps = 3;
171
170
  if (config.installSkills) totalSteps += 1;
172
171
  if (config.installCustomSkills) totalSteps += 1;
173
172
  let step = 1;
@@ -178,19 +177,19 @@ async function runInstall(config) {
178
177
  const { ok } = await checkOpenCodeInstalled();
179
178
  if (!ok) return 1;
180
179
  }
181
- printStep(step++, totalSteps, "Adding thoth-agents plugin...");
182
- if (config.dryRun) {
183
- printInfo("Dry run mode - skipping plugin installation");
184
- } else {
185
- const pluginResult = await addPluginToOpenCodeConfig();
186
- if (!handleStepResult(pluginResult, "Plugin added")) return 1;
187
- }
188
- printStep(step++, totalSteps, "Disabling OpenCode default agents...");
180
+ printStep(
181
+ step++,
182
+ totalSteps,
183
+ "Configuring the thoth-agents plugin and OpenCode default agents..."
184
+ );
189
185
  if (config.dryRun) {
190
- printInfo("Dry run mode - skipping agent disabling");
186
+ printInfo("Dry run mode - skipping main config update");
191
187
  } else {
192
- const agentResult = disableDefaultAgents();
193
- if (!handleStepResult(agentResult, "Default agents disabled")) return 1;
188
+ const mainConfigResult = updateOpenCodeMainConfig({
189
+ ensurePlugin: true,
190
+ disableDefaults: true
191
+ });
192
+ if (!handleStepResult(mainConfigResult, "Main config updated")) return 1;
194
193
  }
195
194
  printStep(step++, totalSteps, "Writing thoth-agents configuration...");
196
195
  if (config.dryRun) {
@@ -382,7 +381,7 @@ function formatPaths(paths) {
382
381
  }
383
382
  function formatWarnings(warnings) {
384
383
  return warnings.map(
385
- (warning) => `- [${warning.severity}] ${warning.message}`
384
+ (warning) => `- [${warning.severity}]${warning.code ? ` [${warning.code}]` : ""} ${warning.message}`
386
385
  );
387
386
  }
388
387
  function formatDisclaimers(disclaimers) {
@@ -447,6 +446,7 @@ function formatOperationPlan(plan) {
447
446
  `Summary: ${plan.summary}`
448
447
  ],
449
448
  plan.targets.length > 0 ? ["Targets:", ...plan.targets.map(formatTarget)] : [],
449
+ plan.blockerTargets?.length ? ["Blocking targets:", ...plan.blockerTargets.map(formatTarget)] : [],
450
450
  plan.surfaces.length > 0 ? [
451
451
  "Managed surfaces:",
452
452
  ...plan.surfaces.map(
@@ -476,6 +476,7 @@ function formatOperationApplyResult(result) {
476
476
  `Summary: ${result.summary}`
477
477
  ],
478
478
  result.changedTargets.length > 0 ? ["Changed targets:", ...result.changedTargets.map(formatTarget)] : [],
479
+ result.diagnosticTargets?.length ? ["Diagnostic targets:", ...result.diagnosticTargets.map(formatTarget)] : [],
479
480
  result.backups.length > 0 ? ["Backups:", ...formatPaths(result.backups)] : [],
480
481
  result.warnings.length > 0 ? ["Warnings:", ...formatWarnings(result.warnings)] : [],
481
482
  result.disclaimers.length > 0 ? ["Disclaimers:", ...formatDisclaimers(result.disclaimers)] : []
@@ -80,6 +80,7 @@ export interface OperationPlan {
80
80
  dryRun: boolean;
81
81
  canApply: boolean;
82
82
  targets: ManagedTarget[];
83
+ blockerTargets?: ManagedTarget[];
83
84
  surfaces: ManagedSurface[];
84
85
  backup: BackupExpectation;
85
86
  items: OperationPlanItem[];
@@ -108,6 +109,7 @@ export interface OperationApplyResult {
108
109
  applied: boolean;
109
110
  summary: string;
110
111
  changedTargets: ManagedTarget[];
112
+ diagnosticTargets?: ManagedTarget[];
111
113
  backups: OperationPath[];
112
114
  warnings: OperationWarning[];
113
115
  disclaimers: OperationDisclaimer[];
@@ -2,8 +2,8 @@ import {
2
2
  defaultTuiOperations,
3
3
  effortChoicesForModel,
4
4
  listOperationHarnesses
5
- } from "../../chunk-YYVE7YHR.js";
6
- import "../../chunk-WBRGPRRB.js";
5
+ } from "../../chunk-ASKXWU6E.js";
6
+ import "../../chunk-OZE7JVGS.js";
7
7
 
8
8
  // src/cli/tui/index.tsx
9
9
  import { render } from "ink";
@@ -255,11 +255,21 @@ function PathLine({ label, value, width }) {
255
255
 
256
256
  // src/cli/tui/components/PlanPreview.tsx
257
257
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
258
+ function targetText(target) {
259
+ const label = target.label ?? target.path ?? target.kind;
260
+ const state = target.state ? `: [${target.state}]` : "";
261
+ const observed = target.observed ? ` - ${target.observed}` : "";
262
+ return `${label}${state}${observed}`;
263
+ }
264
+ function warningText(warning) {
265
+ return `[${warning.severity}]${warning.code ? ` [${warning.code}]` : ""} ${warning.message}`;
266
+ }
258
267
  function PlanPreview({
259
268
  plan,
260
269
  selectedAction,
261
270
  result
262
271
  }) {
272
+ const blockerTargets = plan.blockerTargets ?? [];
263
273
  return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
264
274
  /* @__PURE__ */ jsx6(Text6, { bold: true, children: plan.title }),
265
275
  /* @__PURE__ */ jsx6(Text6, { children: plan.summary }),
@@ -275,6 +285,19 @@ function PlanPreview({
275
285
  "Can apply: ",
276
286
  plan.canApply ? "yes" : "no"
277
287
  ] }),
288
+ !plan.canApply && blockerTargets.length > 0 ? /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
289
+ /* @__PURE__ */ jsx6(Text6, { color: theme.warning, children: "Blocker targets" }),
290
+ blockerTargets.map((target, index) => /* @__PURE__ */ jsxs5(
291
+ Text6,
292
+ {
293
+ children: [
294
+ "- ",
295
+ targetText(target)
296
+ ]
297
+ },
298
+ `${target.label ?? target.path ?? target.kind}-${index}`
299
+ ))
300
+ ] }) : null,
278
301
  plan.surfaces.length > 0 ? /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "Managed surfaces" }) : null,
279
302
  plan.surfaces.map((surface) => /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
280
303
  /* @__PURE__ */ jsxs5(Text6, { children: [
@@ -306,10 +329,8 @@ function PlanPreview({
306
329
  " more items"
307
330
  ] }) : null,
308
331
  plan.warnings.map((warning) => /* @__PURE__ */ jsxs5(Text6, { color: theme.warning, children: [
309
- "- [",
310
- warning.severity,
311
- "] ",
312
- warning.message
332
+ "- ",
333
+ warningText(warning)
313
334
  ] }, warning.code ?? warning.message)),
314
335
  plan.disclaimers.map((disclaimer) => /* @__PURE__ */ jsxs5(Text6, { color: theme.dim, children: [
315
336
  "- ",
@@ -321,7 +342,33 @@ function PlanPreview({
321
342
  /* @__PURE__ */ jsx6(Text6, { color: selectedAction === "cancel" ? theme.accent : void 0, children: "[Cancel]" })
322
343
  ] }),
323
344
  /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "Enter selects. a applies. c cancels." }),
324
- result ? /* @__PURE__ */ jsx6(Text6, { color: result.applied ? theme.ok : theme.warning, children: result.summary }) : null
345
+ result ? /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
346
+ /* @__PURE__ */ jsx6(Text6, { color: result.applied ? theme.ok : theme.warning, children: result.summary }),
347
+ !result.applied && ((result.diagnosticTargets?.length ?? 0) > 0 || result.warnings.length > 0) ? /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
348
+ /* @__PURE__ */ jsx6(Text6, { color: theme.warning, children: "Apply diagnostics" }),
349
+ result.diagnosticTargets?.map((target, index) => /* @__PURE__ */ jsxs5(
350
+ Text6,
351
+ {
352
+ children: [
353
+ "- ",
354
+ targetText(target)
355
+ ]
356
+ },
357
+ `${target.label ?? target.path ?? target.kind}-${index}`
358
+ )),
359
+ result.warnings.map((warning) => /* @__PURE__ */ jsxs5(
360
+ Text6,
361
+ {
362
+ color: theme.warning,
363
+ children: [
364
+ "- ",
365
+ warningText(warning)
366
+ ]
367
+ },
368
+ warning.code ?? warning.message
369
+ ))
370
+ ] }) : null
371
+ ] }) : null
325
372
  ] });
326
373
  }
327
374
 
@@ -348,10 +395,23 @@ var categoryOrder = [
348
395
  "Model state",
349
396
  "Other"
350
397
  ];
398
+ function titleCasePart(part) {
399
+ const normalized = part.toLowerCase();
400
+ switch (normalized) {
401
+ case "sdd":
402
+ return "SDD";
403
+ case "cli":
404
+ return "CLI";
405
+ case "mcp":
406
+ return "MCP";
407
+ case "opencode":
408
+ return "OpenCode";
409
+ default:
410
+ return `${part.charAt(0).toUpperCase()}${part.slice(1).toLowerCase()}`;
411
+ }
412
+ }
351
413
  function titleCase(value, separator = " ") {
352
- return value.split(/[-_\s]+/).filter(Boolean).map(
353
- (part) => part.toLowerCase() === "sdd" ? "SDD" : part.toLowerCase() === "cli" ? "CLI" : part.toLowerCase() === "mcp" ? "MCP" : part.toLowerCase() === "opencode" ? "OpenCode" : `${part.charAt(0).toUpperCase()}${part.slice(1).toLowerCase()}`
354
- ).join(separator);
414
+ return value.split(/[-_\s]+/).filter(Boolean).map(titleCasePart).join(separator);
355
415
  }
356
416
  function compactPath(path) {
357
417
  return path.replaceAll("\\", "/");
@@ -359,45 +419,56 @@ function compactPath(path) {
359
419
  function categorizeTarget(target) {
360
420
  const path = target.path ? compactPath(target.path) : "";
361
421
  const label = target.label ?? target.kind;
422
+ const detail = target.state !== "installed" ? target.observed : void 0;
362
423
  const agent = path.match(/thoth-agents-([a-z0-9_-]+)\.toml$/i);
363
424
  const skill = path.match(/skills\/([^/]+)\/SKILL\.md$/i);
364
425
  if (agent?.[1]) {
365
426
  return {
366
427
  category: "Agents",
367
428
  label: titleCase(agent[1]),
368
- state: target.state
429
+ state: target.state,
430
+ detail
369
431
  };
370
432
  }
371
433
  if (skill?.[1] || target.kind === "skill") {
372
434
  return {
373
435
  category: "Skills",
374
- label: titleCase(skill?.[1] ?? label, "-"),
375
- state: target.state
436
+ label: skill?.[1] ? titleCase(skill[1], "-") : label,
437
+ state: target.state,
438
+ detail
376
439
  };
377
440
  }
378
441
  if (/marketplace\.json$/i.test(path)) {
379
442
  return {
380
443
  category: "Marketplace",
381
444
  label: "Marketplace",
382
- state: target.state
445
+ state: target.state,
446
+ detail
383
447
  };
384
448
  }
385
449
  if (/\.mcp\.json$/i.test(path) || /plugin\.json$/i.test(path) || /plugin-assets/i.test(path) || /manifest/i.test(path)) {
386
450
  return {
387
451
  category: "Plugin/MCP",
388
452
  label: titleCase(label.replace(/^codex\s+/i, "")),
389
- state: target.state
453
+ state: target.state,
454
+ detail
390
455
  };
391
456
  }
392
457
  if (/AGENTS\.md$/i.test(path) || /root instructions/i.test(label)) {
393
458
  return {
394
459
  category: "Root instructions",
395
460
  label: "AGENTS.md",
396
- state: target.state
461
+ state: target.state,
462
+ detail
397
463
  };
398
464
  }
399
465
  if (/config\.toml$/i.test(path) || target.kind === "config") {
400
- return { category: "Config", label: titleCase(label), state: target.state };
466
+ return {
467
+ category: "Config",
468
+ label: titleCase(label),
469
+ state: target.state,
470
+ detail
471
+ };
401
472
  }
402
473
  if (target.kind === "memory-state" || /model/i.test(label)) {
403
474
  return {
@@ -487,7 +558,9 @@ function StatusView({ report }) {
487
558
  warnings.map((warning) => /* @__PURE__ */ jsxs6(Text7, { color: theme.warning, children: [
488
559
  "- [",
489
560
  warning.severity,
490
- "] ",
561
+ "]",
562
+ warning.code ? ` [${warning.code}]` : "",
563
+ " ",
491
564
  warning.message
492
565
  ] }, warning.code ?? warning.message)),
493
566
  hiddenWarnings > 0 ? /* @__PURE__ */ jsxs6(Text7, { color: theme.dim, children: [
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  renderOpenCodeAgentConfigs,
4
4
  spawn,
5
5
  spawnSync
6
- } from "./chunk-MF5NNCPC.js";
6
+ } from "./chunk-6BNAV534.js";
7
7
  import {
8
8
  DEFAULT_THOTH_COMMAND,
9
9
  POLL_INTERVAL_BACKGROUND_MS,
@@ -14,7 +14,7 @@ import {
14
14
  installCustomSkills,
15
15
  loadPluginConfig,
16
16
  stripJsonComments
17
- } from "./chunk-WBRGPRRB.js";
17
+ } from "./chunk-OZE7JVGS.js";
18
18
 
19
19
  // src/index.ts
20
20
  import path4 from "path";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thoth-agents",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "Delegate-first OpenCode plugin with seven agents, thoth-mem persistence, and bundled SDD skills.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",