thoth-agents 0.1.19 → 0.2.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.
@@ -1,5 +1,7 @@
1
1
  import {
2
2
  ALL_AGENT_NAMES,
3
+ CLAUDE_CODE_PROMPT_DIALECT,
4
+ CLAUDE_CODE_SUBAGENT_NAMESPACE,
3
5
  CODEX_PROMPT_DIALECT,
4
6
  CONTEXT7_MCP_URL,
5
7
  CUSTOM_SKILLS,
@@ -7,6 +9,7 @@ import {
7
9
  DEFAULT_THOTH_COMMAND,
8
10
  GREP_APP_MCP_URL,
9
11
  appendPromptSections,
12
+ claudeCodeSubagentType,
10
13
  composeAgentPrompt,
11
14
  createModelFamilySection,
12
15
  createOrchestratorPromptSections,
@@ -23,6 +26,7 @@ import {
23
26
  getCustomSkillsDir,
24
27
  getExistingConfigPath,
25
28
  getExistingLiteConfigPath,
29
+ getPrimaryModelId,
26
30
  getSkillRegistry,
27
31
  installCustomSkills,
28
32
  loadAgentPrompt,
@@ -31,11 +35,58 @@ import {
31
35
  renderRolePrompt,
32
36
  writeConfig,
33
37
  writeLiteConfig
34
- } from "./chunk-2SGSRR6L.js";
38
+ } from "./chunk-3NOVCFN7.js";
39
+
40
+ // src/cli/codex-paths.ts
41
+ import { homedir } from "os";
42
+ import { join } from "path";
43
+ var CODEX_ROLE_NAMES = [
44
+ "explorer",
45
+ "librarian",
46
+ "oracle",
47
+ "designer",
48
+ "quick",
49
+ "deep"
50
+ ];
51
+ function getCodexHome(options = {}) {
52
+ const explicit = options.codexHome ?? process.env.CODEX_HOME?.trim();
53
+ return explicit || join(options.homeDir ?? homedir(), ".codex");
54
+ }
55
+ function resolveCodexTargets(options) {
56
+ const codexHome = getCodexHome(options);
57
+ const agentsDir = options.scope === "project" ? join(options.projectRoot, ".codex", "agents") : join(codexHome, "agents");
58
+ return {
59
+ scope: options.scope,
60
+ codexHome,
61
+ configPath: join(codexHome, "config.toml"),
62
+ rootInstructionsPath: join(codexHome, "AGENTS.md"),
63
+ roleAgentPaths: CODEX_ROLE_NAMES.map((role) => ({
64
+ role,
65
+ path: join(agentsDir, `thoth-agents-${role}.toml`)
66
+ })),
67
+ managedModelsPath: join(
68
+ codexHome,
69
+ "agents",
70
+ ".thoth-agents-managed-models.json"
71
+ ),
72
+ skillsDir: options.scope === "project" ? join(options.projectRoot, ".agents", "skills") : join(options.homeDir ?? homedir(), ".agents", "skills"),
73
+ packageRoot: join(options.projectRoot, ".codex-plugin"),
74
+ personalPluginRoot: join(codexHome, "plugins", "thoth-agents"),
75
+ personalMarketplacePath: join(
76
+ options.homeDir ?? homedir(),
77
+ ".agents",
78
+ "plugins",
79
+ "marketplace.json"
80
+ )
81
+ };
82
+ }
83
+
84
+ // src/cli/codex-install.ts
85
+ import { existsSync as existsSync5, readFileSync as readFileSync5, rmSync } from "fs";
86
+ import { basename, dirname as dirname4, isAbsolute, join as join5, relative as relative2 } from "path";
87
+ import { fileURLToPath as fileURLToPath2 } from "url";
35
88
 
36
89
  // src/harness/adapters/codex.ts
37
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
38
- import { dirname, resolve } from "path";
39
90
  import { fileURLToPath } from "url";
40
91
 
41
92
  // src/harness/core/agent-pack.ts
@@ -310,6 +361,41 @@ function memoryGovernanceDiagnostics(input) {
310
361
  return diagnostics;
311
362
  }
312
363
 
364
+ // src/harness/core/package-version.ts
365
+ import { existsSync, readFileSync } from "fs";
366
+ import { dirname, resolve } from "path";
367
+ function findRootPackageJsonPath(startDirs) {
368
+ for (const startDir of startDirs) {
369
+ let currentDir = resolve(startDir);
370
+ while (true) {
371
+ const packageJsonPath = resolve(currentDir, "package.json");
372
+ if (existsSync(packageJsonPath)) {
373
+ const packageJsonText = readFileSync(packageJsonPath, "utf8");
374
+ const packageJson = JSON.parse(packageJsonText);
375
+ if (packageJson.name === "thoth-agents") {
376
+ return packageJsonPath;
377
+ }
378
+ }
379
+ const parentDir = dirname(currentDir);
380
+ if (parentDir === currentDir) {
381
+ break;
382
+ }
383
+ currentDir = parentDir;
384
+ }
385
+ }
386
+ throw new Error(
387
+ "Unable to locate the thoth-agents root package.json from the render context or current working directory."
388
+ );
389
+ }
390
+ function readPackageJsonVersion(packageJsonPath) {
391
+ const packageJsonText = readFileSync(packageJsonPath, "utf8");
392
+ const packageJson = JSON.parse(packageJsonText);
393
+ if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
394
+ throw new Error("Root package.json version must be a non-empty string.");
395
+ }
396
+ return packageJson.version;
397
+ }
398
+
313
399
  // src/harness/writers/codex-plugin-package.ts
314
400
  import { createHash } from "crypto";
315
401
 
@@ -740,8 +826,8 @@ function normalizePath(value) {
740
826
  }
741
827
  function pluginRootReference(pathValue) {
742
828
  const normalized = normalizePath(pathValue);
743
- const relative3 = normalized.slice(".codex-plugin/".length);
744
- return `./${relative3}`;
829
+ const relative4 = normalized.slice(".codex-plugin/".length);
830
+ return `./${relative4}`;
745
831
  }
746
832
  function sha256(content) {
747
833
  return `sha256:${createHash("sha256").update(content).digest("hex")}`;
@@ -1087,43 +1173,49 @@ function renderCodexToml(input) {
1087
1173
  }
1088
1174
 
1089
1175
  // src/harness/writers/skill-layout.ts
1176
+ import * as fs2 from "fs";
1177
+ import * as path2 from "path";
1178
+
1179
+ // src/harness/writers/fs-skill-collect.ts
1090
1180
  import { createHash as createHash2 } from "crypto";
1091
1181
  import * as fs from "fs";
1092
1182
  import * as path from "path";
1093
- var OUTPUT_MODE_CONFIG = {
1094
- "plugin-package": {
1095
- basePath: ".codex-plugin/skills",
1096
- manifestPath: ".codex-plugin/skills/.thoth-agents-manifest.json",
1097
- surfaceId: "plugin-skills-directory",
1098
- label: "plugin-bundled"
1099
- },
1100
- "repo-local-fallback": {
1101
- basePath: ".agents/skills",
1102
- manifestPath: ".agents/skills/.thoth-agents-manifest.json",
1103
- surfaceId: "repo-skills-directory",
1104
- label: "fallback .agents/skills"
1105
- }
1106
- };
1107
- function normalizePath2(value) {
1183
+ function normalizeSkillPath(value) {
1108
1184
  return value.split(path.sep).join("/");
1109
1185
  }
1110
- function collectFiles(directory) {
1186
+ function collectSkillFiles(directory) {
1111
1187
  if (!fs.existsSync(directory)) return [];
1112
1188
  const entries = fs.readdirSync(directory, { withFileTypes: true });
1113
1189
  const files = [];
1114
1190
  for (const entry of entries) {
1115
1191
  const entryPath = path.join(directory, entry.name);
1116
1192
  if (entry.isDirectory()) {
1117
- files.push(...collectFiles(entryPath));
1193
+ files.push(...collectSkillFiles(entryPath));
1118
1194
  } else if (entry.isFile()) {
1119
1195
  files.push(entryPath);
1120
1196
  }
1121
1197
  }
1122
1198
  return files.sort((left, right) => left.localeCompare(right));
1123
1199
  }
1124
- function sha2562(content) {
1200
+ function sha256Hash(content) {
1125
1201
  return `sha256:${createHash2("sha256").update(content).digest("hex")}`;
1126
1202
  }
1203
+
1204
+ // src/harness/writers/skill-layout.ts
1205
+ var OUTPUT_MODE_CONFIG = {
1206
+ "plugin-package": {
1207
+ basePath: ".codex-plugin/skills",
1208
+ manifestPath: ".codex-plugin/skills/.thoth-agents-manifest.json",
1209
+ surfaceId: "plugin-skills-directory",
1210
+ label: "plugin-bundled"
1211
+ },
1212
+ "repo-local-fallback": {
1213
+ basePath: ".agents/skills",
1214
+ manifestPath: ".agents/skills/.thoth-agents-manifest.json",
1215
+ surfaceId: "repo-skills-directory",
1216
+ label: "fallback .agents/skills"
1217
+ }
1218
+ };
1127
1219
  function resolveOutputModes(input) {
1128
1220
  const requested = input.outputModes ?? (input.outputMode ? [input.outputMode] : []);
1129
1221
  const modes = requested.length > 0 ? requested : ["plugin-package"];
@@ -1166,8 +1258,8 @@ function renderCodexSkillLayout(input) {
1166
1258
  (left, right) => left.name.localeCompare(right.name)
1167
1259
  )) {
1168
1260
  const sourceBaseRoot = input.packageRoot ?? input.projectRoot;
1169
- const sourceRoot = path.join(sourceBaseRoot, skill.sourcePath);
1170
- const files = collectFiles(sourceRoot);
1261
+ const sourceRoot = path2.join(sourceBaseRoot, skill.sourcePath);
1262
+ const files = collectSkillFiles(sourceRoot);
1171
1263
  if (files.length === 0) {
1172
1264
  diagnostics.push({
1173
1265
  severity: "warning",
@@ -1180,12 +1272,14 @@ function renderCodexSkillLayout(input) {
1180
1272
  continue;
1181
1273
  }
1182
1274
  for (const file of files) {
1183
- const relative3 = normalizePath2(path.relative(sourceRoot, file));
1184
- const content = fs.readFileSync(file, "utf8");
1185
- const sourcePath = normalizePath2(path.relative(sourceBaseRoot, file));
1275
+ const relative4 = normalizeSkillPath(path2.relative(sourceRoot, file));
1276
+ const content = fs2.readFileSync(file, "utf8");
1277
+ const sourcePath = normalizeSkillPath(
1278
+ path2.relative(sourceBaseRoot, file)
1279
+ );
1186
1280
  for (const mode of outputModes) {
1187
1281
  const config = OUTPUT_MODE_CONFIG[mode];
1188
- const outputPath = `${config.basePath}/${skill.name}/${relative3}`;
1282
+ const outputPath = `${config.basePath}/${skill.name}/${relative4}`;
1189
1283
  artifacts.push({
1190
1284
  harness: "codex",
1191
1285
  kind: "skill",
@@ -1197,7 +1291,7 @@ function renderCodexSkillLayout(input) {
1197
1291
  name: skill.name,
1198
1292
  sourcePath,
1199
1293
  outputPath,
1200
- sha256: sha2562(content)
1294
+ sha256: sha256Hash(content)
1201
1295
  });
1202
1296
  }
1203
1297
  }
@@ -1233,37 +1327,6 @@ function createCodexPluginPackageManifest(context) {
1233
1327
  description: "Delegate-first OpenCode plugin with seven agents, thoth-mem persistence, and bundled SDD skills."
1234
1328
  };
1235
1329
  }
1236
- function findRootPackageJsonPath(startDirs) {
1237
- for (const startDir of startDirs) {
1238
- let currentDir = resolve(startDir);
1239
- while (true) {
1240
- const packageJsonPath = resolve(currentDir, "package.json");
1241
- if (existsSync2(packageJsonPath)) {
1242
- const packageJsonText = readFileSync2(packageJsonPath, "utf8");
1243
- const packageJson = JSON.parse(packageJsonText);
1244
- if (packageJson.name === "thoth-agents") {
1245
- return packageJsonPath;
1246
- }
1247
- }
1248
- const parentDir = dirname(currentDir);
1249
- if (parentDir === currentDir) {
1250
- break;
1251
- }
1252
- currentDir = parentDir;
1253
- }
1254
- }
1255
- throw new Error(
1256
- "Unable to locate the thoth-agents root package.json from the render context or current working directory."
1257
- );
1258
- }
1259
- function readPackageJsonVersion(packageJsonPath) {
1260
- const packageJsonText = readFileSync2(packageJsonPath, "utf8");
1261
- const packageJson = JSON.parse(packageJsonText);
1262
- if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
1263
- throw new Error("Root package.json version must be a non-empty string.");
1264
- }
1265
- return packageJson.version;
1266
- }
1267
1330
  function stableJson2(value) {
1268
1331
  return `${JSON.stringify(value, null, 2)}
1269
1332
  `;
@@ -1437,13 +1500,6 @@ function agentModelReasoningEffort(role) {
1437
1500
  function isCodexSubagentName(name) {
1438
1501
  return name in CODEX_SUBAGENT_DEFAULT_MODELS;
1439
1502
  }
1440
- function getPrimaryModelId(model) {
1441
- if (Array.isArray(model)) {
1442
- const first = model[0];
1443
- return typeof first === "string" ? first : first?.id;
1444
- }
1445
- return model;
1446
- }
1447
1503
  function getCodexAgentModel(role, config) {
1448
1504
  if (!isCodexSubagentName(role.name)) return void 0;
1449
1505
  return getPrimaryModelId(config?.agents?.[role.name]?.model) ?? CODEX_SUBAGENT_DEFAULT_MODELS[role.name];
@@ -1626,64 +1682,8 @@ var codexAdapter = {
1626
1682
  }
1627
1683
  };
1628
1684
 
1629
- // src/cli/codex-paths.ts
1630
- import { homedir } from "os";
1631
- import { join as join2 } from "path";
1632
- var CODEX_ROLE_NAMES = [
1633
- "explorer",
1634
- "librarian",
1635
- "oracle",
1636
- "designer",
1637
- "quick",
1638
- "deep"
1639
- ];
1640
- function getCodexHome(options = {}) {
1641
- const explicit = options.codexHome ?? process.env.CODEX_HOME?.trim();
1642
- return explicit || join2(options.homeDir ?? homedir(), ".codex");
1643
- }
1644
- function resolveCodexTargets(options) {
1645
- const codexHome = getCodexHome(options);
1646
- const agentsDir = options.scope === "project" ? join2(options.projectRoot, ".codex", "agents") : join2(codexHome, "agents");
1647
- return {
1648
- scope: options.scope,
1649
- codexHome,
1650
- configPath: join2(codexHome, "config.toml"),
1651
- rootInstructionsPath: join2(codexHome, "AGENTS.md"),
1652
- roleAgentPaths: CODEX_ROLE_NAMES.map((role) => ({
1653
- role,
1654
- path: join2(agentsDir, `thoth-agents-${role}.toml`)
1655
- })),
1656
- managedModelsPath: join2(
1657
- codexHome,
1658
- "agents",
1659
- ".thoth-agents-managed-models.json"
1660
- ),
1661
- skillsDir: options.scope === "project" ? join2(options.projectRoot, ".agents", "skills") : join2(options.homeDir ?? homedir(), ".agents", "skills"),
1662
- packageRoot: join2(options.projectRoot, ".codex-plugin"),
1663
- personalPluginRoot: join2(codexHome, "plugins", "thoth-agents"),
1664
- personalMarketplacePath: join2(
1665
- options.homeDir ?? homedir(),
1666
- ".agents",
1667
- "plugins",
1668
- "marketplace.json"
1669
- )
1670
- };
1671
- }
1672
-
1673
- // src/cli/codex-install.ts
1674
- import {
1675
- copyFileSync as copyFileSync2,
1676
- existsSync as existsSync4,
1677
- mkdirSync as mkdirSync2,
1678
- readFileSync as readFileSync4,
1679
- rmSync,
1680
- writeFileSync as writeFileSync2
1681
- } from "fs";
1682
- import { basename, dirname as dirname3, isAbsolute, join as join4, relative as relative2 } from "path";
1683
- import { fileURLToPath as fileURLToPath2 } from "url";
1684
-
1685
1685
  // src/harness/codex-plugin-paths.ts
1686
- import { join as join3 } from "path";
1686
+ import { join as join4 } from "path";
1687
1687
  var CODEX_PLUGIN_ARTIFACT_PREFIX = ".codex-plugin/";
1688
1688
  function codexPluginRootArtifactPath(artifactPath) {
1689
1689
  if (!artifactPath.startsWith(CODEX_PLUGIN_ARTIFACT_PREFIX)) {
@@ -1692,7 +1692,7 @@ function codexPluginRootArtifactPath(artifactPath) {
1692
1692
  const relativePath = artifactPath.slice(CODEX_PLUGIN_ARTIFACT_PREFIX.length);
1693
1693
  if (relativePath === ".mcp.json") return relativePath;
1694
1694
  if (relativePath === "plugin.json" || relativePath.startsWith(".")) {
1695
- return join3(".codex-plugin", relativePath);
1695
+ return join4(".codex-plugin", relativePath);
1696
1696
  }
1697
1697
  return relativePath;
1698
1698
  }
@@ -1837,6 +1837,62 @@ function writeCodexConfigMerge(options) {
1837
1837
  }
1838
1838
  }
1839
1839
 
1840
+ // src/cli/managed-state-io.ts
1841
+ import {
1842
+ copyFileSync as copyFileSync2,
1843
+ existsSync as existsSync4,
1844
+ mkdirSync as mkdirSync2,
1845
+ readFileSync as readFileSync4,
1846
+ writeFileSync as writeFileSync2
1847
+ } from "fs";
1848
+ import { dirname as dirname3 } from "path";
1849
+ function writeTextWithBackup(path4, content) {
1850
+ mkdirSync2(dirname3(path4), { recursive: true });
1851
+ if (existsSync4(path4) && readFileSync4(path4, "utf8") === content) return false;
1852
+ if (existsSync4(path4)) copyFileSync2(path4, `${path4}.bak`);
1853
+ writeFileSync2(path4, content);
1854
+ return true;
1855
+ }
1856
+ function stableJson3(value) {
1857
+ return `${JSON.stringify(value, null, 2)}
1858
+ `;
1859
+ }
1860
+ function uniqueMessages(messages) {
1861
+ return [...new Set(messages)];
1862
+ }
1863
+ function stringRecord(value) {
1864
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
1865
+ return Object.fromEntries(
1866
+ Object.entries(value).filter(
1867
+ (entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
1868
+ )
1869
+ );
1870
+ }
1871
+ function emptyManagedModelState(version) {
1872
+ return { version, models: {} };
1873
+ }
1874
+ function parseManagedModelStateJson(text, version) {
1875
+ if (!text) return emptyManagedModelState(version);
1876
+ try {
1877
+ const parsed = JSON.parse(text);
1878
+ if (parsed.version !== version || !parsed.models || typeof parsed.models !== "object" || Array.isArray(parsed.models)) {
1879
+ return emptyManagedModelState(version);
1880
+ }
1881
+ const configuredModels = stringRecord(parsed.configuredModels);
1882
+ return {
1883
+ version,
1884
+ models: stringRecord(parsed.models),
1885
+ ...Object.keys(configuredModels).length > 0 ? { configuredModels } : {}
1886
+ };
1887
+ } catch {
1888
+ return emptyManagedModelState(version);
1889
+ }
1890
+ }
1891
+ function readManagedModelState(path4, version) {
1892
+ if (!existsSync4(path4)) return emptyManagedModelState(version);
1893
+ return parseManagedModelStateJson(readFileSync4(path4, "utf8"), version);
1894
+ }
1895
+
1840
1896
  // src/cli/codex-install.ts
1841
1897
  var ROOT_START = "<!-- thoth-agents:codex-root:start -->";
1842
1898
  var ROOT_END = "<!-- thoth-agents:codex-root:end -->";
@@ -1850,23 +1906,16 @@ function mergeManagedBlock(existing, managedBlock) {
1850
1906
  return `${existing}${existing.endsWith("\n") || existing.length === 0 ? "" : "\n"}
1851
1907
  ${managedBlock}`;
1852
1908
  }
1853
- function writeTextWithBackup(path2, content) {
1854
- mkdirSync2(dirname3(path2), { recursive: true });
1855
- if (existsSync4(path2) && readFileSync4(path2, "utf8") === content) return false;
1856
- if (existsSync4(path2)) copyFileSync2(path2, `${path2}.bak`);
1857
- writeFileSync2(path2, content);
1858
- return true;
1859
- }
1860
1909
  function packageArtifactTarget(packageRoot, artifact) {
1861
- return join4(packageRoot, codexPluginRootArtifactPath(artifact.path));
1910
+ return join5(packageRoot, codexPluginRootArtifactPath(artifact.path));
1862
1911
  }
1863
1912
  function resolvePackageRoot(packageRoot) {
1864
1913
  if (packageRoot) return packageRoot;
1865
1914
  return findPackageRoot(fileURLToPath2(new URL(".", import.meta.url))) ?? void 0;
1866
1915
  }
1867
- function normalizeRelativeMarketplacePath(path2) {
1868
- const normalized = path2.replaceAll("\\", "/");
1869
- if (isAbsolute(path2) || /^[A-Za-z]:\//.test(normalized)) return normalized;
1916
+ function normalizeRelativeMarketplacePath(path4) {
1917
+ const normalized = path4.replaceAll("\\", "/");
1918
+ if (isAbsolute(path4) || /^[A-Za-z]:\//.test(normalized)) return normalized;
1870
1919
  if (normalized.startsWith("./")) return normalized;
1871
1920
  return `./${normalized}`;
1872
1921
  }
@@ -1889,39 +1938,11 @@ function managedMarketplaceEntry(homeDir, personalPluginRoot) {
1889
1938
  category: "Productivity"
1890
1939
  };
1891
1940
  }
1892
- function stableJson3(value) {
1893
- return `${JSON.stringify(value, null, 2)}
1894
- `;
1895
- }
1896
- function emptyManagedModelState() {
1897
- return {
1898
- version: MANAGED_MODEL_STATE_VERSION,
1899
- models: {}
1900
- };
1901
- }
1902
- function stringRecord(value) {
1903
- if (!value || typeof value !== "object" || Array.isArray(value)) return {};
1904
- return Object.fromEntries(
1905
- Object.entries(value).filter(
1906
- (entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
1907
- )
1908
- );
1941
+ function emptyManagedModelState2() {
1942
+ return emptyManagedModelState(MANAGED_MODEL_STATE_VERSION);
1909
1943
  }
1910
- function readManagedModelState(path2) {
1911
- if (!existsSync4(path2)) return emptyManagedModelState();
1912
- try {
1913
- const parsed = JSON.parse(readFileSync4(path2, "utf8"));
1914
- if (parsed.version !== MANAGED_MODEL_STATE_VERSION || !parsed.models || typeof parsed.models !== "object" || Array.isArray(parsed.models)) {
1915
- return emptyManagedModelState();
1916
- }
1917
- return {
1918
- version: MANAGED_MODEL_STATE_VERSION,
1919
- models: stringRecord(parsed.models),
1920
- ...Object.keys(stringRecord(parsed.configuredModels)).length > 0 ? { configuredModels: stringRecord(parsed.configuredModels) } : {}
1921
- };
1922
- } catch {
1923
- return emptyManagedModelState();
1924
- }
1944
+ function readManagedModelState2(path4) {
1945
+ return readManagedModelState(path4, MANAGED_MODEL_STATE_VERSION);
1925
1946
  }
1926
1947
  function parseRoleTomlModel(content) {
1927
1948
  const match = /^model\s*=\s*"((?:\\.|[^"\\])*)"\s*$/m.exec(content);
@@ -1939,8 +1960,8 @@ function replaceRoleTomlModel(content, model) {
1939
1960
  return `${rendered}
1940
1961
  ${content}`;
1941
1962
  }
1942
- function roleManagedModelStateKey(path2) {
1943
- return basename(path2);
1963
+ function roleManagedModelStateKey(path4) {
1964
+ return basename(path4);
1944
1965
  }
1945
1966
  function applyCodexManagedModelOverrides(config, overrides) {
1946
1967
  if (config.dryRun) {
@@ -1970,7 +1991,7 @@ function applyCodexManagedModelOverrides(config, overrides) {
1970
1991
  ...plan.diagnostics,
1971
1992
  ...plan.disclaimers
1972
1993
  ]);
1973
- const state = readManagedModelState(statePath);
1994
+ const state = readManagedModelState2(statePath);
1974
1995
  const nextState = {
1975
1996
  version: MANAGED_MODEL_STATE_VERSION,
1976
1997
  models: { ...state.models },
@@ -1986,7 +2007,7 @@ function applyCodexManagedModelOverrides(config, overrides) {
1986
2007
  `Missing Codex role TOML content for ${override.role}.`
1987
2008
  );
1988
2009
  }
1989
- const before = existsSync4(roleItem.targetPath) ? readFileSync4(roleItem.targetPath, "utf8") : roleItem.content;
2010
+ const before = existsSync5(roleItem.targetPath) ? readFileSync5(roleItem.targetPath, "utf8") : roleItem.content;
1990
2011
  const updated = replaceRoleTomlModel(before, override.model);
1991
2012
  if (writeTextWithBackup(roleItem.targetPath, updated)) {
1992
2013
  changed.push(roleItem.targetPath);
@@ -2018,7 +2039,7 @@ function resolveRoleTomlContent(options) {
2018
2039
  const key = roleManagedModelStateKey(options.targetPath);
2019
2040
  if (!renderedModel) return options.renderedContent;
2020
2041
  const configuredModel = options.reset ? void 0 : options.state.configuredModels?.[key];
2021
- if (options.reset || !existsSync4(options.targetPath)) {
2042
+ if (options.reset || !existsSync5(options.targetPath)) {
2022
2043
  options.nextState.models[key] = renderedModel;
2023
2044
  if (configuredModel !== void 0) {
2024
2045
  options.nextState.configuredModels ??= {};
@@ -2028,7 +2049,7 @@ function resolveRoleTomlContent(options) {
2028
2049
  return options.renderedContent;
2029
2050
  }
2030
2051
  const currentModel = parseRoleTomlModel(
2031
- readFileSync4(options.targetPath, "utf8")
2052
+ readFileSync5(options.targetPath, "utf8")
2032
2053
  );
2033
2054
  if (configuredModel !== void 0) {
2034
2055
  options.nextState.models[key] = renderedModel;
@@ -2064,10 +2085,10 @@ function mergePersonalMarketplace(existing, homeDir, personalPluginRoot) {
2064
2085
  });
2065
2086
  }
2066
2087
  function roleArtifactContent(role, artifacts) {
2067
- const path2 = `.codex/agents/thoth-agents-${role}.toml`;
2068
- const artifact = artifacts.find((candidate) => candidate.path === path2);
2088
+ const path4 = `.codex/agents/thoth-agents-${role}.toml`;
2089
+ const artifact = artifacts.find((candidate) => candidate.path === path4);
2069
2090
  if (!artifact?.content)
2070
- throw new Error(`Missing Codex role artifact: ${path2}`);
2091
+ throw new Error(`Missing Codex role artifact: ${path4}`);
2071
2092
  return String(artifact.content);
2072
2093
  }
2073
2094
  function buildCodexSetupPlan(config) {
@@ -2086,8 +2107,8 @@ function buildCodexSetupPlan(config) {
2086
2107
  (artifact) => artifact.path.startsWith(".codex-plugin/")
2087
2108
  );
2088
2109
  const rootBlock = renderCodexRootInstructions();
2089
- const managedModelState2 = readManagedModelState(targets.managedModelsPath);
2090
- const nextManagedModelState = emptyManagedModelState();
2110
+ const managedModelState2 = readManagedModelState2(targets.managedModelsPath);
2111
+ const nextManagedModelState = emptyManagedModelState2();
2091
2112
  const items = [
2092
2113
  {
2093
2114
  kind: "root-instructions",
@@ -2103,7 +2124,7 @@ function buildCodexSetupPlan(config) {
2103
2124
  action: "write-role-toml",
2104
2125
  targetPath: target.path,
2105
2126
  description: `Materialize Codex role subagent ${target.role}.`,
2106
- requiresBackup: existsSync4(target.path),
2127
+ requiresBackup: existsSync5(target.path),
2107
2128
  role: target.role,
2108
2129
  content: resolveRoleTomlContent({
2109
2130
  renderedContent: roleArtifactContent(target.role, render.artifacts),
@@ -2119,7 +2140,7 @@ function buildCodexSetupPlan(config) {
2119
2140
  action: "write-managed-model-state",
2120
2141
  targetPath: targets.managedModelsPath,
2121
2142
  description: "Record thoth-agents-managed Codex role model ownership state.",
2122
- requiresBackup: existsSync4(targets.managedModelsPath),
2143
+ requiresBackup: existsSync5(targets.managedModelsPath),
2123
2144
  content: stableJson3(nextManagedModelState)
2124
2145
  },
2125
2146
  ...packageArtifacts.map(
@@ -2137,7 +2158,7 @@ function buildCodexSetupPlan(config) {
2137
2158
  action: "merge-marketplace",
2138
2159
  targetPath: targets.personalMarketplacePath,
2139
2160
  description: "Register Personal Codex marketplace entry for the local thoth-agents plugin source.",
2140
- requiresBackup: existsSync4(targets.personalMarketplacePath),
2161
+ requiresBackup: existsSync5(targets.personalMarketplacePath),
2141
2162
  content: targets.personalPluginRoot
2142
2163
  },
2143
2164
  {
@@ -2201,21 +2222,18 @@ function formatRefreshPackageGroup(kind, groups) {
2201
2222
  }
2202
2223
  function commonTargetDirectory(items) {
2203
2224
  if (items.length === 0) return "";
2204
- let common = dirname3(items[0]?.targetPath ?? "");
2225
+ let common = dirname4(items[0]?.targetPath ?? "");
2205
2226
  for (const item of items.slice(1)) {
2206
2227
  while (!isSameOrChildPath(item.targetPath, common)) {
2207
- const parent = dirname3(common);
2228
+ const parent = dirname4(common);
2208
2229
  if (parent === common) return common;
2209
2230
  common = parent;
2210
2231
  }
2211
2232
  }
2212
2233
  return common;
2213
2234
  }
2214
- function isSameOrChildPath(path2, parent) {
2215
- return path2 === parent || path2.startsWith(`${parent}\\`) || path2.startsWith(`${parent}/`);
2216
- }
2217
- function uniqueMessages(messages) {
2218
- return [...new Set(messages)];
2235
+ function isSameOrChildPath(path4, parent) {
2236
+ return path4 === parent || path4.startsWith(`${parent}\\`) || path4.startsWith(`${parent}/`);
2219
2237
  }
2220
2238
  function applyCodexSetup(plan) {
2221
2239
  const changed = [];
@@ -2244,8 +2262,8 @@ function applyCodexSetup(plan) {
2244
2262
  if (item.action === "merge-marketplace") {
2245
2263
  if (item.content === void 0) continue;
2246
2264
  const content2 = mergePersonalMarketplace(
2247
- existsSync4(item.targetPath) ? readFileSync4(item.targetPath, "utf8") : "",
2248
- dirname3(dirname3(dirname3(item.targetPath))),
2265
+ existsSync5(item.targetPath) ? readFileSync5(item.targetPath, "utf8") : "",
2266
+ dirname4(dirname4(dirname4(item.targetPath))),
2249
2267
  item.content
2250
2268
  );
2251
2269
  if (writeTextWithBackup(item.targetPath, content2))
@@ -2254,7 +2272,7 @@ function applyCodexSetup(plan) {
2254
2272
  }
2255
2273
  if (item.content === void 0) continue;
2256
2274
  const content = item.action === "merge-managed-block" ? mergeManagedBlock(
2257
- existsSync4(item.targetPath) ? readFileSync4(item.targetPath, "utf8") : "",
2275
+ existsSync5(item.targetPath) ? readFileSync5(item.targetPath, "utf8") : "",
2258
2276
  item.content
2259
2277
  ) : item.content;
2260
2278
  if (writeTextWithBackup(item.targetPath, content))
@@ -2278,31 +2296,1150 @@ function managedRefreshRoots(plan) {
2278
2296
  group.push(item);
2279
2297
  refreshGroups.set(item.kind, group);
2280
2298
  }
2281
- return [...refreshGroups].filter(([kind]) => kind === "personal-plugin-source").map(([, items]) => commonTargetDirectory(items)).filter((path2) => path2.length > 0);
2299
+ return [...refreshGroups].filter(([kind]) => kind === "personal-plugin-source").map(([, items]) => commonTargetDirectory(items)).filter((path4) => path4.length > 0);
2282
2300
  }
2283
2301
 
2284
- // src/cli/operations/codex.ts
2285
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
2302
+ // src/cli/operations/claude-code.ts
2303
+ import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
2286
2304
  import { basename as basename2 } from "path";
2287
- var CODEX_DISPLAY_NAME = "Codex";
2288
- var codexPlanSources = /* @__PURE__ */ new WeakMap();
2289
- var codexModelSources = /* @__PURE__ */ new WeakMap();
2290
- var codexActions = [
2291
- {
2292
- id: "codex-status",
2293
- kind: "status",
2294
- label: "Status",
2295
- description: "Inspect managed Codex setup state",
2296
- dryRun: false,
2297
- requiresConfirmation: false,
2298
- supported: true
2299
- },
2300
- {
2301
- id: "codex-list",
2302
- kind: "list",
2303
- label: "List",
2304
- description: "List managed Codex surfaces and actions",
2305
- dryRun: false,
2305
+
2306
+ // src/harness/adapters/claude-code.ts
2307
+ import { fileURLToPath as fileURLToPath3 } from "url";
2308
+
2309
+ // src/harness/writers/claude-code-plugin-package.ts
2310
+ var CLAUDE_PLUGIN_MANIFEST_FIELDS = [
2311
+ "name",
2312
+ "version",
2313
+ "description",
2314
+ "author"
2315
+ ];
2316
+ var PLUGIN_MANIFEST_PATH = ".claude-plugin/plugin.json";
2317
+ var PLUGIN_ASSETS_PATH = ".claude-plugin/.thoth-agents-plugin-assets.json";
2318
+ function normalizePath2(value) {
2319
+ return value.replace(/\\/g, "/");
2320
+ }
2321
+ function stableJson4(value) {
2322
+ return `${JSON.stringify(value, null, 2)}
2323
+ `;
2324
+ }
2325
+ function orderedManifest(manifest) {
2326
+ const ordered = {};
2327
+ for (const field of CLAUDE_PLUGIN_MANIFEST_FIELDS) {
2328
+ const value = manifest[field];
2329
+ if (value !== void 0) ordered[field] = value;
2330
+ }
2331
+ return ordered;
2332
+ }
2333
+ function provenanceFor(artifact) {
2334
+ const path4 = normalizePath2(artifact.path);
2335
+ if (path4.endsWith("/")) return void 0;
2336
+ const content = typeof artifact.content === "string" ? artifact.content : Buffer.from(artifact.content).toString("utf8");
2337
+ return { path: path4, kind: artifact.kind, sha256: sha256Hash(content) };
2338
+ }
2339
+ function renderClaudeCodePluginPackage(input) {
2340
+ const components = [...input.componentArtifacts].sort(
2341
+ (left, right) => normalizePath2(left.path).localeCompare(normalizePath2(right.path))
2342
+ );
2343
+ const provenance = components.map(provenanceFor).filter((entry) => entry !== void 0).sort((left, right) => left.path.localeCompare(right.path));
2344
+ const manifestArtifact = {
2345
+ harness: "claude",
2346
+ kind: "manifest",
2347
+ path: PLUGIN_MANIFEST_PATH,
2348
+ description: "Deterministic Claude Code plugin package manifest.",
2349
+ content: stableJson4(orderedManifest(input.manifest))
2350
+ };
2351
+ const provenanceArtifact = {
2352
+ harness: "claude",
2353
+ kind: "manifest",
2354
+ path: PLUGIN_ASSETS_PATH,
2355
+ description: "Deterministic Claude Code plugin package asset provenance.",
2356
+ content: stableJson4({ generatedBy: "thoth-agents", assets: provenance })
2357
+ };
2358
+ return {
2359
+ artifacts: [manifestArtifact, provenanceArtifact, ...components],
2360
+ diagnostics: []
2361
+ };
2362
+ }
2363
+
2364
+ // src/harness/writers/claude-code-skill-layout.ts
2365
+ import * as fs3 from "fs";
2366
+ import * as path3 from "path";
2367
+ var SKILLS_BASE_PATH = "skills";
2368
+ var SKILLS_MANIFEST_PATH = "skills/.thoth-agents-manifest.json";
2369
+ function renderClaudeCodeSkillLayout(input) {
2370
+ const artifacts = [];
2371
+ const diagnostics = [];
2372
+ const manifest = [];
2373
+ const sourceBaseRoot = input.packageRoot ?? input.projectRoot;
2374
+ for (const skill of [...input.skills].sort(
2375
+ (left, right) => left.name.localeCompare(right.name)
2376
+ )) {
2377
+ const sourceRoot = path3.join(sourceBaseRoot, skill.sourcePath);
2378
+ const files = collectSkillFiles(sourceRoot);
2379
+ if (files.length === 0) {
2380
+ diagnostics.push({
2381
+ severity: "warning",
2382
+ code: "claude-code.skill.source_missing",
2383
+ message: `Skipping Claude Code skill "${skill.name}" because source path "${skill.sourcePath}" was not found.`,
2384
+ harness: "claude",
2385
+ surface: "plugin-skills-directory",
2386
+ fallback: "diagnostic-only"
2387
+ });
2388
+ continue;
2389
+ }
2390
+ for (const file of files) {
2391
+ const relative4 = normalizeSkillPath(path3.relative(sourceRoot, file));
2392
+ const content = fs3.readFileSync(file, "utf8");
2393
+ const sourcePath = normalizeSkillPath(
2394
+ path3.relative(sourceBaseRoot, file)
2395
+ );
2396
+ const outputPath = `${SKILLS_BASE_PATH}/${skill.name}/${relative4}`;
2397
+ artifacts.push({
2398
+ harness: "claude",
2399
+ kind: "skill",
2400
+ path: outputPath,
2401
+ description: `Claude Code plugin-bundled skill artifact for ${skill.name}`,
2402
+ content
2403
+ });
2404
+ manifest.push({
2405
+ name: skill.name,
2406
+ sourcePath,
2407
+ outputPath,
2408
+ sha256: sha256Hash(content)
2409
+ });
2410
+ }
2411
+ }
2412
+ artifacts.push({
2413
+ harness: "claude",
2414
+ kind: "manifest",
2415
+ path: SKILLS_MANIFEST_PATH,
2416
+ description: "Generated Claude Code plugin-bundled skill source manifest with source hashes.",
2417
+ content: `${JSON.stringify({ generatedBy: "thoth-agents", skills: manifest }, null, 2)}
2418
+ `
2419
+ });
2420
+ return { artifacts, diagnostics };
2421
+ }
2422
+
2423
+ // src/harness/writers/claude-code-subagent.ts
2424
+ var CLAUDE_CODE_MODELS = [
2425
+ "sonnet",
2426
+ "opus",
2427
+ "haiku",
2428
+ "inherit"
2429
+ ];
2430
+ function isClaudeCodeModel(value) {
2431
+ return CLAUDE_CODE_MODELS.includes(value);
2432
+ }
2433
+ function yamlScalar(value) {
2434
+ const needsQuoting = /[:#\-?*&!|>'"%@`{}[\],]|^\s|\s$|^$/.test(value);
2435
+ if (!needsQuoting) return value;
2436
+ const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
2437
+ return `"${escaped}"`;
2438
+ }
2439
+ function renderClaudeCodeSubagent(input) {
2440
+ const frontmatter = [
2441
+ "---",
2442
+ `name: ${yamlScalar(input.name)}`,
2443
+ `description: ${yamlScalar(input.description)}`,
2444
+ `model: ${input.model}`,
2445
+ ...input.tools !== void 0 ? [`tools: ${yamlScalar(input.tools)}`] : [],
2446
+ "---"
2447
+ ].join("\n");
2448
+ const body = input.instructions.trimEnd();
2449
+ return `${frontmatter}
2450
+
2451
+ ${body}
2452
+ `;
2453
+ }
2454
+
2455
+ // src/harness/adapters/claude-code.ts
2456
+ var CLAUDE_CODE_CAPABILITIES = CLAUDE_CODE_PROMPT_DIALECT.capabilities.capabilities;
2457
+ var CLAUDE_CODE_SUBAGENT_DEFAULT_MODELS = {
2458
+ explorer: "haiku",
2459
+ librarian: "sonnet",
2460
+ oracle: "opus",
2461
+ designer: "sonnet",
2462
+ quick: "haiku",
2463
+ deep: "sonnet"
2464
+ };
2465
+ var READ_ONLY_ROLE_TOOLS = {
2466
+ explorer: "Read, Grep, Glob",
2467
+ librarian: "Read, Grep, Glob, WebSearch, WebFetch",
2468
+ oracle: "Read, Grep, Glob"
2469
+ };
2470
+ var WRITE_CAPABLE_ROLE_TOOLS = "Read, Edit, Write, Bash, Grep, Glob";
2471
+ function isClaudeCodeSubagentName(name) {
2472
+ return name in CLAUDE_CODE_SUBAGENT_DEFAULT_MODELS;
2473
+ }
2474
+ function getClaudeCodeAgentModel(role, config) {
2475
+ if (!isClaudeCodeSubagentName(role.name)) return "inherit";
2476
+ const override = getPrimaryModelId(config?.agents?.[role.name]?.model);
2477
+ if (override && isClaudeCodeModel(override)) return override;
2478
+ return CLAUDE_CODE_SUBAGENT_DEFAULT_MODELS[role.name];
2479
+ }
2480
+ function toolsForRole(role) {
2481
+ if (role.canMutateWorkspace) return WRITE_CAPABLE_ROLE_TOOLS;
2482
+ return READ_ONLY_ROLE_TOOLS[role.name] ?? "Read, Grep, Glob";
2483
+ }
2484
+ function claudeCodePromptSections(roleName) {
2485
+ switch (roleName) {
2486
+ case "orchestrator":
2487
+ return createOrchestratorPromptSections();
2488
+ case "explorer":
2489
+ case "librarian":
2490
+ case "oracle":
2491
+ return createReadOnlySpecialistPromptSections(roleName);
2492
+ case "designer":
2493
+ case "quick":
2494
+ case "deep":
2495
+ return createWriteCapableSpecialistPromptSections(roleName);
2496
+ }
2497
+ }
2498
+ function claudeCodeModelFamilyPromptSection(roleName, model) {
2499
+ const section = createModelFamilySection(roleName, model);
2500
+ return section ? renderPromptSection(section, CLAUDE_CODE_PROMPT_DIALECT) : void 0;
2501
+ }
2502
+ function claudeCodeStepBudgetPromptSection(steps) {
2503
+ const section = createStepBudgetSection(steps);
2504
+ return section ? renderPromptSection(section, CLAUDE_CODE_PROMPT_DIALECT) : void 0;
2505
+ }
2506
+ function renderClaudeCodeRolePrompt(roleName, config, model) {
2507
+ const promptOverrides = loadAgentPrompt(roleName, config?.preset);
2508
+ const override = getAgentOverride(config, roleName);
2509
+ const basePrompt = renderRolePrompt(
2510
+ claudeCodePromptSections(roleName),
2511
+ CLAUDE_CODE_PROMPT_DIALECT
2512
+ );
2513
+ const prompt = composeAgentPrompt({
2514
+ basePrompt,
2515
+ customPrompt: promptOverrides.prompt,
2516
+ customAppendPrompt: appendPromptSections(
2517
+ claudeCodeModelFamilyPromptSection(roleName, model),
2518
+ promptOverrides.appendPrompt
2519
+ )
2520
+ });
2521
+ return appendPromptSections(
2522
+ prompt,
2523
+ claudeCodeStepBudgetPromptSection(override?.steps)
2524
+ );
2525
+ }
2526
+ function claudeCodeRoleInstructions(role) {
2527
+ return [
2528
+ "<role-operational-contract>",
2529
+ `- Role: ${role.name}`,
2530
+ `- Mode: ${role.mode}`,
2531
+ `- Scope: ${role.scope}`,
2532
+ `- Responsibility: ${role.responsibility}`,
2533
+ "- Use AskUserQuestion for local blocking decisions.",
2534
+ `- ${role.name} runs as an auto-discovered Claude Code plugin subagent invoked via Task(subagent_type: ${claudeCodeSubagentType(role.name)}); plugin subagents are namespaced with the plugin name. The orchestrator is the main Claude Code session.`,
2535
+ "- Role permissions are enforced by this subagent's frontmatter `tools` allowlist; read-only roles cannot mutate the workspace.",
2536
+ ...role.toolGovernance.map((rule) => `- ${rule}`),
2537
+ ...role.verification.map((rule) => `- ${rule}`),
2538
+ "</role-operational-contract>"
2539
+ ].join("\n");
2540
+ }
2541
+ function roleInstructions2(role, config) {
2542
+ const model = getClaudeCodeAgentModel(role, config);
2543
+ return [
2544
+ renderClaudeCodeRolePrompt(role.name, config, model),
2545
+ claudeCodeRoleInstructions(role),
2546
+ renderMemoryGovernanceInstructions(role, CLAUDE_CODE_PROMPT_DIALECT)
2547
+ ].join("\n\n");
2548
+ }
2549
+ function renderClaudeCodeRootInstructions(config) {
2550
+ const rootOverride = getAgentOverride(config, "orchestrator");
2551
+ const rootPrompt = renderClaudeCodeRolePrompt(
2552
+ "orchestrator",
2553
+ config,
2554
+ rootOverride?.model ?? DEFAULT_MODELS.orchestrator
2555
+ );
2556
+ const specialists = getAgentPackContract().roles.filter((role) => role.name !== "orchestrator").map((role) => claudeCodeSubagentType(role.name)).join(", ");
2557
+ return [
2558
+ rootPrompt,
2559
+ "<claude-code-runtime>",
2560
+ "- You ARE the Claude Code main-thread agent: the delegate-first root coordinator. This is your system prompt (activated via the plugin settings.json `agent` key), so orchestrator-only and root-owned rules apply to you directly.",
2561
+ '- As your FIRST action on a new session, when thoth-mem tools are installed and session/project identity is known, call mem_session(action="start") as step 0 before any other thoth-mem call, then save the real user prompt with mem_save(kind="prompt") before later delegation.',
2562
+ "- thoth-mem tools are provided by this plugin's bundled MCP server and are exposed under a plugin namespace; call the available namespaced tool whose name ends in mem_session, mem_recall, mem_context, mem_save, mem_get, or mem_project (do not assume a bare, unnamespaced tool name).",
2563
+ "- If thoth-mem tools or identity values are unavailable, disclose that memory bootstrap could not run and continue without claiming memory was saved.",
2564
+ `- Delegate via the Task tool with \`subagent_type\` set to a plugin-namespaced specialist: ${specialists}. Bare role names (e.g. "explorer") are NOT valid in this harness \u2014 always use the ${CLAUDE_CODE_SUBAGENT_NAMESPACE}: prefix.`,
2565
+ "- Parallel delegation is supported: issue multiple Task calls in one turn for independent work.",
2566
+ '- Before delegating after meaningful context changes, refresh the handoff body with root-owned mem_session(action="summary") or mem_save(kind="session_summary") when available.',
2567
+ "- Use AskUserQuestion for blocking user decisions; do not ask those questions in plain prose.",
2568
+ "- Track progress with TodoWrite; subagents do not own progress checkboxes or root-only memory.",
2569
+ "- Role permissions are enforced at runtime by each subagent's frontmatter `tools` allowlist.",
2570
+ "</claude-code-runtime>"
2571
+ ].join("\n");
2572
+ }
2573
+ function claudeCodeMcpServers() {
2574
+ const [exaCommand = "", ...exaArgs] = exa.command;
2575
+ const [thothCommand = "", ...thothArgs] = DEFAULT_THOTH_COMMAND;
2576
+ return {
2577
+ exa: {
2578
+ command: exaCommand,
2579
+ ...exaArgs.length > 0 ? { args: exaArgs } : {},
2580
+ ...exa.environment && Object.keys(exa.environment).length > 0 ? { env: exa.environment } : {}
2581
+ },
2582
+ context7: { type: "http", url: CONTEXT7_MCP_URL },
2583
+ grep_app: { type: "http", url: GREP_APP_MCP_URL },
2584
+ thoth_mem: {
2585
+ command: thothCommand,
2586
+ ...thothArgs.length > 0 ? { args: thothArgs } : {}
2587
+ }
2588
+ };
2589
+ }
2590
+ function stableJson5(value) {
2591
+ return `${JSON.stringify(value, null, 2)}
2592
+ `;
2593
+ }
2594
+ function readRootPackageVersion2(context) {
2595
+ const packageJsonPath = findRootPackageJsonPath([
2596
+ ...hasPackageRoot(context) ? [context.packageRoot] : [],
2597
+ context.projectRoot,
2598
+ process.cwd(),
2599
+ fileURLToPath3(new URL(".", import.meta.url))
2600
+ ]);
2601
+ return readPackageJsonVersion(packageJsonPath);
2602
+ }
2603
+ function hasConfig(context) {
2604
+ return "config" in context;
2605
+ }
2606
+ function hasPackageRoot(context) {
2607
+ return "packageRoot" in context && typeof context.packageRoot === "string" && context.packageRoot.length > 0;
2608
+ }
2609
+ function createPluginManifest(context) {
2610
+ return {
2611
+ name: "thoth-agents",
2612
+ version: readRootPackageVersion2(context),
2613
+ description: "Delegate-first agent pack with seven roles, thoth-mem persistence, and bundled SDD skills, packaged for Claude Code.",
2614
+ author: { name: "thoth-agents" }
2615
+ };
2616
+ }
2617
+ function renderSubagentArtifacts(config) {
2618
+ const artifacts = [];
2619
+ for (const role of getAgentPackContract().roles.filter(
2620
+ (candidate) => candidate.name !== "orchestrator"
2621
+ )) {
2622
+ const content = renderClaudeCodeSubagent({
2623
+ name: role.name,
2624
+ description: role.responsibility,
2625
+ tools: toolsForRole(role),
2626
+ model: getClaudeCodeAgentModel(role, config),
2627
+ instructions: roleInstructions2(role, config)
2628
+ });
2629
+ artifacts.push({
2630
+ harness: "claude",
2631
+ kind: "agent-config",
2632
+ path: `agents/${role.name}.md`,
2633
+ description: `Claude Code subagent definition for ${role.name}.`,
2634
+ content
2635
+ });
2636
+ }
2637
+ return artifacts;
2638
+ }
2639
+ function renderOrchestratorArtifact(config) {
2640
+ const orchestrator = getAgentPackContract().roles.find(
2641
+ (role) => role.name === "orchestrator"
2642
+ );
2643
+ const content = renderClaudeCodeSubagent({
2644
+ name: "orchestrator",
2645
+ description: orchestrator?.responsibility ?? "Delegate-first root coordinator for SDD workflow and specialist dispatch.",
2646
+ model: "inherit",
2647
+ instructions: renderClaudeCodeRootInstructions(config)
2648
+ });
2649
+ return {
2650
+ harness: "claude",
2651
+ kind: "agent-config",
2652
+ path: "agents/orchestrator.md",
2653
+ description: "Claude Code orchestrator agent, activated as the main thread via settings.json.",
2654
+ content
2655
+ };
2656
+ }
2657
+ var claudeCodeAdapter = {
2658
+ id: "claude",
2659
+ displayName: "Claude Code",
2660
+ capabilities: CLAUDE_CODE_CAPABILITIES,
2661
+ render(context) {
2662
+ const config = hasConfig(context) ? context.config : void 0;
2663
+ const componentArtifacts = [
2664
+ ...renderSubagentArtifacts(config),
2665
+ renderOrchestratorArtifact(config),
2666
+ {
2667
+ harness: "claude",
2668
+ kind: "mcp-config",
2669
+ path: ".mcp.json",
2670
+ description: "Claude Code plugin-bundled MCP server definitions.",
2671
+ content: stableJson5({ mcpServers: claudeCodeMcpServers() })
2672
+ },
2673
+ {
2674
+ harness: "claude",
2675
+ kind: "harness-config",
2676
+ path: "settings.json",
2677
+ description: "Activates the orchestrator agent as the Claude Code main thread.",
2678
+ content: stableJson5({ agent: "orchestrator" })
2679
+ }
2680
+ ];
2681
+ const skillLayout = renderClaudeCodeSkillLayout({
2682
+ projectRoot: context.projectRoot,
2683
+ ...hasPackageRoot(context) ? { packageRoot: context.packageRoot } : {},
2684
+ skills: getSkillRegistry()
2685
+ });
2686
+ componentArtifacts.push(...skillLayout.artifacts);
2687
+ const pluginPackage = renderClaudeCodePluginPackage({
2688
+ manifest: createPluginManifest(context),
2689
+ componentArtifacts
2690
+ });
2691
+ return {
2692
+ harness: "claude",
2693
+ artifacts: pluginPackage.artifacts,
2694
+ diagnostics: [...skillLayout.diagnostics, ...pluginPackage.diagnostics]
2695
+ };
2696
+ }
2697
+ };
2698
+
2699
+ // src/cli/claude-code-install.ts
2700
+ import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
2701
+ import { join as join8 } from "path";
2702
+ import { fileURLToPath as fileURLToPath4 } from "url";
2703
+
2704
+ // src/cli/claude-code-paths.ts
2705
+ import { homedir as homedir2 } from "os";
2706
+ import { join as join7 } from "path";
2707
+ var CLAUDE_CODE_ROLE_NAMES = [
2708
+ "explorer",
2709
+ "librarian",
2710
+ "oracle",
2711
+ "designer",
2712
+ "quick",
2713
+ "deep"
2714
+ ];
2715
+ function resolveClaudeCodeTargets(options) {
2716
+ const home = options.homeDir ?? homedir2();
2717
+ const pluginRoot = options.scope === "project" ? join7(options.projectRoot, ".claude", "skills", "thoth-agents") : join7(home, ".claude", "skills", "thoth-agents");
2718
+ return {
2719
+ scope: options.scope,
2720
+ pluginRoot,
2721
+ pluginManifestPath: join7(pluginRoot, ".claude-plugin", "plugin.json"),
2722
+ agentPaths: CLAUDE_CODE_ROLE_NAMES.map((role) => ({
2723
+ role,
2724
+ path: join7(pluginRoot, "agents", `${role}.md`)
2725
+ })),
2726
+ mcpPath: join7(pluginRoot, ".mcp.json"),
2727
+ hooksPath: join7(pluginRoot, "hooks", "hooks.json"),
2728
+ skillsDir: join7(pluginRoot, "skills"),
2729
+ managedModelsPath: join7(pluginRoot, ".thoth-agents-managed-models.json")
2730
+ };
2731
+ }
2732
+
2733
+ // src/cli/claude-code-install.ts
2734
+ var CLAUDE_CODE_MANAGED_MODEL_STATE_VERSION = 1;
2735
+ var isClaudeCodeModelAlias = isClaudeCodeModel;
2736
+ function parseSubagentModel(content) {
2737
+ return /^model:\s*(\S+)\s*$/m.exec(content)?.[1];
2738
+ }
2739
+ function replaceSubagentModel(content, model) {
2740
+ if (/^model:\s*\S+\s*$/m.test(content)) {
2741
+ return content.replace(/^model:\s*\S+\s*$/m, `model: ${model}`);
2742
+ }
2743
+ return content;
2744
+ }
2745
+ function emptyManagedModelState3() {
2746
+ return emptyManagedModelState(CLAUDE_CODE_MANAGED_MODEL_STATE_VERSION);
2747
+ }
2748
+ function parseManagedModelStateJson2(text) {
2749
+ return parseManagedModelStateJson(
2750
+ text,
2751
+ CLAUDE_CODE_MANAGED_MODEL_STATE_VERSION
2752
+ );
2753
+ }
2754
+ function readManagedModelState3(path4) {
2755
+ return readManagedModelState(
2756
+ path4,
2757
+ CLAUDE_CODE_MANAGED_MODEL_STATE_VERSION
2758
+ );
2759
+ }
2760
+ function resolvePackageRoot2(packageRoot) {
2761
+ if (packageRoot) return packageRoot;
2762
+ return findPackageRoot(fileURLToPath4(new URL(".", import.meta.url))) ?? void 0;
2763
+ }
2764
+ function targetKindForArtifact(artifact) {
2765
+ const path4 = artifact.path.replaceAll("\\", "/");
2766
+ if (path4 === ".claude-plugin/plugin.json") return "plugin-manifest";
2767
+ if (path4.startsWith("agents/")) return "subagent";
2768
+ if (path4 === ".mcp.json") return "mcp-config";
2769
+ if (path4.startsWith("hooks/")) return "hook";
2770
+ if (path4.startsWith("skills/")) return "skill";
2771
+ return "plugin-asset";
2772
+ }
2773
+ function roleForArtifact(artifact) {
2774
+ const match = /^agents\/([^/]+)\.md$/.exec(
2775
+ artifact.path.replaceAll("\\", "/")
2776
+ );
2777
+ const name = match?.[1];
2778
+ return name && CLAUDE_CODE_ROLE_NAMES.includes(name) ? name : void 0;
2779
+ }
2780
+ function applyConfiguredModel(content, role, state, nextState, reset) {
2781
+ const renderedModel = parseSubagentModel(content);
2782
+ if (!role || !renderedModel) return content;
2783
+ nextState.models[role] = renderedModel;
2784
+ const configured = reset ? void 0 : state.configuredModels?.[role];
2785
+ if (configured === void 0) return content;
2786
+ nextState.configuredModels ??= {};
2787
+ nextState.configuredModels[role] = configured;
2788
+ return replaceSubagentModel(content, configured);
2789
+ }
2790
+ function buildClaudeCodeSetupPlan(config) {
2791
+ const targets = resolveClaudeCodeTargets({
2792
+ scope: config.scope,
2793
+ projectRoot: config.projectRoot,
2794
+ homeDir: config.homeDir
2795
+ });
2796
+ const packageRoot = resolvePackageRoot2(config.packageRoot);
2797
+ const render = claudeCodeAdapter.render({
2798
+ projectRoot: config.projectRoot,
2799
+ ...packageRoot ? { packageRoot } : {}
2800
+ });
2801
+ const state = readManagedModelState3(targets.managedModelsPath);
2802
+ const nextState = emptyManagedModelState3();
2803
+ const items = render.artifacts.map((artifact) => {
2804
+ const role = roleForArtifact(artifact);
2805
+ const rendered = String(artifact.content ?? "");
2806
+ const content = role !== void 0 ? applyConfiguredModel(rendered, role, state, nextState, config.reset) : rendered;
2807
+ const targetPath = join8(targets.pluginRoot, artifact.path);
2808
+ return {
2809
+ kind: targetKindForArtifact(artifact),
2810
+ action: "write-plugin-file",
2811
+ targetPath,
2812
+ description: `Materialize Claude Code plugin asset ${artifact.path}.`,
2813
+ requiresBackup: existsSync6(targetPath),
2814
+ content,
2815
+ ...role ? { role } : {}
2816
+ };
2817
+ });
2818
+ items.push({
2819
+ kind: "managed-model-state",
2820
+ action: "write-managed-model-state",
2821
+ targetPath: targets.managedModelsPath,
2822
+ description: "Record thoth-agents-managed Claude Code subagent model ownership state.",
2823
+ requiresBackup: existsSync6(targets.managedModelsPath),
2824
+ content: stableJson3(nextState)
2825
+ });
2826
+ return {
2827
+ dryRun: config.dryRun === true,
2828
+ reset: config.reset,
2829
+ items,
2830
+ pluginRoot: targets.pluginRoot,
2831
+ diagnostics: [
2832
+ `Installed as a skills-directory plugin at ${targets.pluginRoot}; it auto-loads as thoth-agents@skills-dir on the next Claude Code session.`,
2833
+ "Restart Claude Code or run /reload-plugins to activate it; run /plugin (Installed tab) to confirm thoth-agents@skills-dir is loaded.",
2834
+ "The plugin settings.json activates the orchestrator agent as the main thread, so the session starts in delegate-first mode and bootstraps thoth-mem on its first turn."
2835
+ ],
2836
+ disclaimers: [
2837
+ "The orchestrator agent is the Claude Code main thread (plugin settings.json `agent` key); while enabled it replaces the default system prompt for every session in scope.",
2838
+ "Role permissions are enforced by each specialist subagent frontmatter `tools` allowlist; the orchestrator inherits all tools.",
2839
+ "Subagent models accept only sonnet, opus, haiku, or inherit.",
2840
+ "User-scope skills-directory plugins load hooks and MCP servers without extra approval; project-scope requires accepting the workspace trust dialog."
2841
+ ]
2842
+ };
2843
+ }
2844
+ function applyClaudeCodeSetup(plan) {
2845
+ const changed = [];
2846
+ const diagnostics = uniqueMessages([
2847
+ ...plan.diagnostics,
2848
+ ...plan.disclaimers
2849
+ ]);
2850
+ if (plan.dryRun) return { success: true, changed, diagnostics };
2851
+ try {
2852
+ for (const item of plan.items) {
2853
+ if (writeTextWithBackup(item.targetPath, item.content)) {
2854
+ changed.push(item.targetPath);
2855
+ }
2856
+ }
2857
+ return { success: true, changed, diagnostics };
2858
+ } catch (error) {
2859
+ return {
2860
+ success: false,
2861
+ changed,
2862
+ diagnostics,
2863
+ error: error instanceof Error ? error.message : String(error)
2864
+ };
2865
+ }
2866
+ }
2867
+ function applyClaudeCodeManagedModelOverrides(config, overrides) {
2868
+ if (config.dryRun) {
2869
+ return {
2870
+ success: true,
2871
+ changed: [],
2872
+ diagnostics: [
2873
+ "Dry-run Claude Code model override apply requested; no files were written."
2874
+ ]
2875
+ };
2876
+ }
2877
+ const plan = buildClaudeCodeSetupPlan({
2878
+ ...config,
2879
+ dryRun: true,
2880
+ reset: false
2881
+ });
2882
+ const stateItem = plan.items.find(
2883
+ (item) => item.action === "write-managed-model-state"
2884
+ );
2885
+ const statePath = stateItem?.targetPath;
2886
+ if (!statePath) {
2887
+ return {
2888
+ success: false,
2889
+ changed: [],
2890
+ diagnostics: plan.diagnostics,
2891
+ error: "Claude Code managed model state target was not found."
2892
+ };
2893
+ }
2894
+ const changed = [];
2895
+ const diagnostics = uniqueMessages([
2896
+ ...plan.diagnostics,
2897
+ ...plan.disclaimers
2898
+ ]);
2899
+ const state = parseManagedModelStateJson2(stateItem?.content);
2900
+ const nextState = {
2901
+ version: CLAUDE_CODE_MANAGED_MODEL_STATE_VERSION,
2902
+ models: { ...state.models },
2903
+ ...state.configuredModels ? { configuredModels: { ...state.configuredModels } } : {}
2904
+ };
2905
+ try {
2906
+ for (const override of overrides) {
2907
+ if (!isClaudeCodeModelAlias(override.model)) {
2908
+ throw new Error(
2909
+ `Unsupported Claude Code model "${override.model}" for ${override.role}; use sonnet, opus, haiku, or inherit.`
2910
+ );
2911
+ }
2912
+ const roleItem = plan.items.find(
2913
+ (item) => item.kind === "subagent" && item.role === override.role
2914
+ );
2915
+ if (!roleItem) {
2916
+ throw new Error(`Missing Claude Code subagent for ${override.role}.`);
2917
+ }
2918
+ const before = existsSync6(roleItem.targetPath) ? readFileSync7(roleItem.targetPath, "utf8") : roleItem.content;
2919
+ const updated = replaceSubagentModel(before, override.model);
2920
+ if (writeTextWithBackup(roleItem.targetPath, updated)) {
2921
+ changed.push(roleItem.targetPath);
2922
+ }
2923
+ nextState.configuredModels ??= {};
2924
+ nextState.configuredModels[override.role] = override.model;
2925
+ }
2926
+ if (writeTextWithBackup(statePath, stableJson3(nextState))) {
2927
+ changed.push(statePath);
2928
+ }
2929
+ return { success: true, changed, diagnostics };
2930
+ } catch (error) {
2931
+ return {
2932
+ success: false,
2933
+ changed,
2934
+ diagnostics,
2935
+ error: error instanceof Error ? error.message : String(error)
2936
+ };
2937
+ }
2938
+ }
2939
+ function formatClaudeCodeSetupPlan(plan) {
2940
+ const lines = plan.items.map(
2941
+ (item) => `- ${item.action}: ${item.targetPath} (${item.description})`
2942
+ );
2943
+ return ["Claude Code setup plan:", ...lines].join("\n");
2944
+ }
2945
+
2946
+ // src/cli/operations/claude-code.ts
2947
+ var CLAUDE_CODE_DISPLAY_NAME = "Claude Code";
2948
+ var claudeCodePlanSources = /* @__PURE__ */ new WeakMap();
2949
+ var claudeCodeModelSources = /* @__PURE__ */ new WeakMap();
2950
+ var claudeCodeActions = [
2951
+ {
2952
+ id: "claude-code-status",
2953
+ kind: "status",
2954
+ label: "Status",
2955
+ description: "Inspect managed Claude Code plugin state",
2956
+ dryRun: false,
2957
+ requiresConfirmation: false,
2958
+ supported: true
2959
+ },
2960
+ {
2961
+ id: "claude-code-list",
2962
+ kind: "list",
2963
+ label: "List",
2964
+ description: "List managed Claude Code surfaces and actions",
2965
+ dryRun: false,
2966
+ requiresConfirmation: false,
2967
+ supported: true
2968
+ },
2969
+ {
2970
+ id: "claude-code-install",
2971
+ kind: "install",
2972
+ label: "Install",
2973
+ description: "Preview Claude Code plugin package install",
2974
+ dryRun: true,
2975
+ requiresConfirmation: true,
2976
+ supported: true
2977
+ },
2978
+ {
2979
+ id: "claude-code-update",
2980
+ kind: "update",
2981
+ label: "Update",
2982
+ description: "Preview Claude Code managed plugin refresh",
2983
+ dryRun: true,
2984
+ requiresConfirmation: true,
2985
+ supported: true
2986
+ },
2987
+ {
2988
+ id: "claude-code-sync",
2989
+ kind: "sync",
2990
+ label: "Sync",
2991
+ description: "Preview Claude Code managed plugin sync",
2992
+ dryRun: true,
2993
+ requiresConfirmation: true,
2994
+ supported: true
2995
+ },
2996
+ {
2997
+ id: "claude-code-model-config",
2998
+ kind: "model-config",
2999
+ label: "Model",
3000
+ description: "Preview supported Claude Code subagent model line changes",
3001
+ dryRun: true,
3002
+ requiresConfirmation: true,
3003
+ supported: true
3004
+ }
3005
+ ];
3006
+ var claudeCodeOperationAdapter = {
3007
+ id: "claude",
3008
+ displayName: CLAUDE_CODE_DISPLAY_NAME,
3009
+ available: true,
3010
+ description: "Claude Code plugin package and managed subagent surfaces.",
3011
+ actions: claudeCodeActions
3012
+ };
3013
+ function claudeCodeConfig(context = { cwd: process.cwd() }, dryRun) {
3014
+ return {
3015
+ dryRun,
3016
+ reset: false,
3017
+ // Match the installer (install.ts uses 'user') so post-install status,
3018
+ // update, sync, and model commands resolve the same plugin root.
3019
+ scope: context.scope ?? "user",
3020
+ projectRoot: context.cwd,
3021
+ homeDir: context.homeDir,
3022
+ packageRoot: context.packageRoot
3023
+ };
3024
+ }
3025
+ function claudeCodeDisclaimers() {
3026
+ return [
3027
+ {
3028
+ message: "Role permissions are enforced by subagent frontmatter tools; the orchestrator is the main session, injected via the SessionStart hook.",
3029
+ code: "claude-code-first-class"
3030
+ },
3031
+ {
3032
+ message: "Subagent models accept only sonnet, opus, haiku, or inherit.",
3033
+ code: "claude-code-model-aliases"
3034
+ }
3035
+ ];
3036
+ }
3037
+ function warning(message, code) {
3038
+ return { severity: "important", message, code };
3039
+ }
3040
+ function targetForItem(item, state, observed) {
3041
+ return {
3042
+ kind: item.kind === "managed-model-state" ? "memory-state" : "generated-artifact",
3043
+ path: item.targetPath,
3044
+ label: item.role ? `Claude Code ${item.role} subagent` : item.kind.replaceAll("-", " "),
3045
+ state,
3046
+ expected: item.action,
3047
+ observed,
3048
+ description: item.description
3049
+ };
3050
+ }
3051
+ function surfaceForItem(item) {
3052
+ return {
3053
+ id: `${item.kind}:${item.role ?? basename2(item.targetPath)}`,
3054
+ label: item.role ? `Claude Code ${item.role} subagent` : item.kind.replaceAll("-", " "),
3055
+ path: item.targetPath,
3056
+ description: item.description
3057
+ };
3058
+ }
3059
+ function backupForItem(item) {
3060
+ return {
3061
+ required: item.requiresBackup,
3062
+ strategy: item.requiresBackup ? "managed-backup-file" : "none",
3063
+ destinations: item.requiresBackup ? [{ path: `${item.targetPath}.bak`, label: "managed backup" }] : []
3064
+ };
3065
+ }
3066
+ function manifestState(item) {
3067
+ if (!existsSync7(item.targetPath))
3068
+ return { state: "missing", observed: "absent" };
3069
+ const observed = readFileSync8(item.targetPath, "utf8");
3070
+ if (observed === item.content)
3071
+ return { state: "installed", observed: "current" };
3072
+ try {
3073
+ const expectedVersion = JSON.parse(item.content).version;
3074
+ const observedVersion = JSON.parse(observed).version;
3075
+ if (typeof expectedVersion === "string" && typeof observedVersion === "string" && expectedVersion !== observedVersion) {
3076
+ return {
3077
+ state: "outdated",
3078
+ observed: `version ${observedVersion}; expected ${expectedVersion}`
3079
+ };
3080
+ }
3081
+ } catch {
3082
+ return { state: "unknown", observed: "unparseable plugin manifest" };
3083
+ }
3084
+ return { state: "drift", observed: "content differs" };
3085
+ }
3086
+ function contentState(item) {
3087
+ if (!existsSync7(item.targetPath))
3088
+ return { state: "missing", observed: "absent" };
3089
+ return readFileSync8(item.targetPath, "utf8") === item.content ? { state: "installed", observed: "current" } : { state: "drift", observed: "content differs" };
3090
+ }
3091
+ function classifyItem(item) {
3092
+ if (item.kind === "plugin-manifest") return manifestState(item);
3093
+ return contentState(item);
3094
+ }
3095
+ function aggregateState(states) {
3096
+ if (states.includes("unknown")) return "unknown";
3097
+ if (states.includes("drift")) return "drift";
3098
+ if (states.includes("outdated")) return "outdated";
3099
+ if (states.includes("missing")) return "missing";
3100
+ return "installed";
3101
+ }
3102
+ function statusSummary(state) {
3103
+ switch (state) {
3104
+ case "installed":
3105
+ return "Claude Code managed plugin is installed and current.";
3106
+ case "missing":
3107
+ return "Claude Code managed plugin is missing.";
3108
+ case "drift":
3109
+ return "Claude Code managed plugin exists but differs from expected output.";
3110
+ case "outdated":
3111
+ return "Claude Code managed plugin includes an older generated manifest.";
3112
+ case "unknown":
3113
+ return "Claude Code managed plugin could not be classified safely.";
3114
+ }
3115
+ }
3116
+ function statusFromSetupPlan(plan) {
3117
+ const classified = plan.items.map((item) => ({
3118
+ item,
3119
+ ...classifyItem(item)
3120
+ }));
3121
+ const state = aggregateState(classified.map((entry) => entry.state));
3122
+ return {
3123
+ harness: "claude",
3124
+ displayName: CLAUDE_CODE_DISPLAY_NAME,
3125
+ state,
3126
+ summary: statusSummary(state),
3127
+ targets: classified.map(
3128
+ ({ item, state: state2, observed }) => targetForItem(item, state2, observed)
3129
+ ),
3130
+ diagnostics: plan.diagnostics.map((message) => ({
3131
+ severity: "minor",
3132
+ message,
3133
+ code: "claude-code-diagnostic"
3134
+ })),
3135
+ actions: claudeCodeActions,
3136
+ disclaimers: [
3137
+ ...claudeCodeDisclaimers(),
3138
+ ...plan.disclaimers.map((message) => ({ message }))
3139
+ ]
3140
+ };
3141
+ }
3142
+ function getClaudeCodeStatus(context = { cwd: process.cwd() }) {
3143
+ let plan;
3144
+ try {
3145
+ plan = buildClaudeCodeSetupPlan(claudeCodeConfig(context, true));
3146
+ } catch (error) {
3147
+ const message = error instanceof Error ? error.message : String(error);
3148
+ return {
3149
+ harness: "claude",
3150
+ displayName: CLAUDE_CODE_DISPLAY_NAME,
3151
+ state: "unknown",
3152
+ summary: `Claude Code setup plan could not be built: ${message}`,
3153
+ targets: [],
3154
+ diagnostics: [
3155
+ {
3156
+ severity: "critical",
3157
+ message,
3158
+ code: "claude-code-plan-build-failed"
3159
+ }
3160
+ ],
3161
+ actions: claudeCodeActions,
3162
+ disclaimers: claudeCodeDisclaimers()
3163
+ };
3164
+ }
3165
+ return statusFromSetupPlan(plan);
3166
+ }
3167
+ function planItemFromSetup(item) {
3168
+ return {
3169
+ title: item.description,
3170
+ target: targetForItem(item),
3171
+ preview: item.content,
3172
+ backup: backupForItem(item)
3173
+ };
3174
+ }
3175
+ function planFromSetup(id, action, title, summary, setupPlan) {
3176
+ const status = statusFromSetupPlan(setupPlan);
3177
+ const canApply = status.state === "installed" || status.state === "missing" || status.state === "outdated" || status.state === "drift";
3178
+ const plan = {
3179
+ id,
3180
+ harness: "claude",
3181
+ action,
3182
+ title,
3183
+ summary,
3184
+ dryRun: true,
3185
+ canApply,
3186
+ targets: status.targets,
3187
+ surfaces: setupPlan.items.map(surfaceForItem),
3188
+ backup: {
3189
+ required: setupPlan.items.some((item) => item.requiresBackup),
3190
+ strategy: "managed-backup-file",
3191
+ description: "Existing Claude Code plugin files are backed up before being overwritten."
3192
+ },
3193
+ items: setupPlan.items.map(planItemFromSetup),
3194
+ warnings: status.diagnostics,
3195
+ disclaimers: [
3196
+ ...claudeCodeDisclaimers(),
3197
+ ...setupPlan.disclaimers.map((message) => ({ message }))
3198
+ ]
3199
+ };
3200
+ claudeCodePlanSources.set(plan, setupPlan);
3201
+ return plan;
3202
+ }
3203
+ function buildClaudeCodeInstallPlan(context = { cwd: process.cwd() }) {
3204
+ return planFromSetup(
3205
+ "claude-code-install-preview",
3206
+ "install",
3207
+ "Install Claude Code plugin package",
3208
+ "Preview Claude Code plugin package install using buildClaudeCodeSetupPlan().",
3209
+ buildClaudeCodeSetupPlan(claudeCodeConfig(context, true))
3210
+ );
3211
+ }
3212
+ function buildClaudeCodeUpdatePlan(context = { cwd: process.cwd() }) {
3213
+ return planFromSetup(
3214
+ "claude-code-update-preview",
3215
+ "update",
3216
+ "Update Claude Code plugin package",
3217
+ "Preview Claude Code managed plugin refresh using buildClaudeCodeSetupPlan().",
3218
+ buildClaudeCodeSetupPlan(claudeCodeConfig(context, true))
3219
+ );
3220
+ }
3221
+ function buildClaudeCodeSyncPlan(context = { cwd: process.cwd() }) {
3222
+ return planFromSetup(
3223
+ "claude-code-sync-preview",
3224
+ "sync",
3225
+ "Sync Claude Code plugin package",
3226
+ "Preview Claude Code managed plugin subagents, MCP, hooks, and skills.",
3227
+ buildClaudeCodeSetupPlan(claudeCodeConfig(context, true))
3228
+ );
3229
+ }
3230
+ function isClaudeCodeRole(role) {
3231
+ return CLAUDE_CODE_ROLE_NAMES.includes(role);
3232
+ }
3233
+ function buildClaudeCodeModelPlan(input, context = { cwd: process.cwd() }) {
3234
+ const status = getClaudeCodeStatus(context);
3235
+ const supportedRoles = input.roles.filter((role) => isClaudeCodeRole(role.role)).filter((role) => isClaudeCodeModelAlias(role.model)).map((role) => ({
3236
+ role: role.role,
3237
+ model: role.model
3238
+ }));
3239
+ const rejectedRoles = input.roles.filter(
3240
+ (role) => !isClaudeCodeRole(role.role) || !isClaudeCodeModelAlias(role.model)
3241
+ );
3242
+ const warnings = [
3243
+ ...status.diagnostics,
3244
+ ...input.warnings ?? [],
3245
+ ...rejectedRoles.map(
3246
+ (role) => warning(
3247
+ `Claude Code does not accept role "${role.role}" with model "${role.model}"; roles must be one of ${CLAUDE_CODE_ROLE_NAMES.join(", ")} and models must be sonnet, opus, haiku, or inherit.`,
3248
+ "claude-code-unsupported-model-role"
3249
+ )
3250
+ )
3251
+ ];
3252
+ if (input.harness !== "claude") {
3253
+ warnings.push(
3254
+ warning(
3255
+ "Model plan target harness must be claude.",
3256
+ "claude-code-model-harness-mismatch"
3257
+ )
3258
+ );
3259
+ }
3260
+ const targets = supportedRoles.map(({ role }) => {
3261
+ const target = status.targets.find(
3262
+ (candidate) => candidate.path?.endsWith(`agents${pathSep()}${role}.md`)
3263
+ );
3264
+ return target ?? {
3265
+ kind: "generated-artifact",
3266
+ label: `Claude Code ${role} subagent`,
3267
+ state: "missing"
3268
+ };
3269
+ });
3270
+ const stateTarget = status.targets.find(
3271
+ (target) => target.path?.endsWith(".thoth-agents-managed-models.json")
3272
+ );
3273
+ const plan = {
3274
+ id: "claude-code-model-config-preview",
3275
+ harness: "claude",
3276
+ action: "model-config",
3277
+ title: "Configure Claude Code subagent model lines",
3278
+ summary: "Preview model changes for generated Claude Code subagent files and managed model state only.",
3279
+ dryRun: true,
3280
+ canApply: input.harness === "claude" && supportedRoles.length > 0 && status.state !== "unknown",
3281
+ targets: [...targets, ...stateTarget ? [stateTarget] : []],
3282
+ surfaces: targets.map((target) => ({
3283
+ id: `claude-code-model:${target.label}`,
3284
+ label: target.label ?? "Claude Code subagent",
3285
+ path: target.path,
3286
+ state: target.state
3287
+ })),
3288
+ backup: {
3289
+ required: true,
3290
+ strategy: "managed-backup-file",
3291
+ description: "Existing subagent files and managed model state are backed up by the managed write helper."
3292
+ },
3293
+ items: supportedRoles.map(({ role, model }) => ({
3294
+ title: `Set ${role} Claude Code subagent model line`,
3295
+ target: targets.find(
3296
+ (target) => target.path?.endsWith(`agents${pathSep()}${role}.md`)
3297
+ ) ?? {
3298
+ kind: "generated-artifact",
3299
+ label: `Claude Code ${role} subagent`
3300
+ },
3301
+ preview: JSON.stringify({ role, model }),
3302
+ backup: { required: true, strategy: "managed-backup-file" }
3303
+ })),
3304
+ warnings,
3305
+ disclaimers: [
3306
+ ...claudeCodeDisclaimers(),
3307
+ ...input.disclaimers ?? [],
3308
+ {
3309
+ message: "Claude Code model configuration writes only generated subagent frontmatter model lines and the managed model state JSON.",
3310
+ code: "claude-code-model-supported-surface"
3311
+ }
3312
+ ]
3313
+ };
3314
+ claudeCodeModelSources.set(plan, {
3315
+ config: claudeCodeConfig(context, false),
3316
+ roles: supportedRoles
3317
+ });
3318
+ return plan;
3319
+ }
3320
+ function pathSep() {
3321
+ return process.platform === "win32" ? "\\" : "/";
3322
+ }
3323
+ function rejectPlan(plan, message, severity = "critical") {
3324
+ return {
3325
+ harness: plan.harness,
3326
+ action: plan.action,
3327
+ applied: false,
3328
+ summary: message,
3329
+ changedTargets: [],
3330
+ backups: [],
3331
+ warnings: [{ severity, message }],
3332
+ disclaimers: claudeCodeDisclaimers()
3333
+ };
3334
+ }
3335
+ function validateClaudeCodePlan(plan) {
3336
+ if (plan.harness !== "claude") {
3337
+ return rejectPlan(plan, "Only Claude Code operation plans can be applied.");
3338
+ }
3339
+ if (!plan.canApply) {
3340
+ return rejectPlan(
3341
+ plan,
3342
+ "Claude Code plan cannot be applied because canApply is false."
3343
+ );
3344
+ }
3345
+ if (!["install", "update", "sync", "model-config"].includes(plan.action)) {
3346
+ return rejectPlan(
3347
+ plan,
3348
+ `Unsupported Claude Code apply action: ${plan.action}.`
3349
+ );
3350
+ }
3351
+ if (plan.items.length === 0) {
3352
+ return rejectPlan(plan, "Claude Code plan has no items to apply.");
3353
+ }
3354
+ return null;
3355
+ }
3356
+ function applyClaudeCodePlan(plan) {
3357
+ const rejection = validateClaudeCodePlan(plan);
3358
+ if (rejection) return rejection;
3359
+ if (plan.action === "model-config") {
3360
+ const source = claudeCodeModelSources.get(plan);
3361
+ if (!source) {
3362
+ return rejectPlan(
3363
+ plan,
3364
+ "Claude Code model plan was not produced by buildClaudeCodeModelPlan in this process."
3365
+ );
3366
+ }
3367
+ const result2 = applyClaudeCodeManagedModelOverrides(
3368
+ source.config,
3369
+ source.roles.map((role) => ({
3370
+ role: role.role,
3371
+ model: role.model
3372
+ }))
3373
+ );
3374
+ return {
3375
+ harness: "claude",
3376
+ action: "model-config",
3377
+ applied: result2.success,
3378
+ summary: result2.success ? "Applied Claude Code subagent model overrides." : result2.error ?? "Failed to apply Claude Code subagent model overrides.",
3379
+ changedTargets: result2.changed.map((path4) => ({
3380
+ kind: path4.endsWith(".json") ? "memory-state" : "generated-artifact",
3381
+ path: path4,
3382
+ label: basename2(path4),
3383
+ state: "installed"
3384
+ })),
3385
+ backups: result2.changed.filter((path4) => existsSync7(`${path4}.bak`)).map((path4) => ({ path: `${path4}.bak`, label: "managed backup" })),
3386
+ warnings: result2.success ? [] : [{ severity: "critical", message: result2.error ?? "apply failed." }],
3387
+ disclaimers: claudeCodeDisclaimers()
3388
+ };
3389
+ }
3390
+ const setupPlan = claudeCodePlanSources.get(plan);
3391
+ if (!setupPlan) {
3392
+ return rejectPlan(
3393
+ plan,
3394
+ "Claude Code setup plan was not produced by a Claude Code operation plan builder in this process."
3395
+ );
3396
+ }
3397
+ const result = applyClaudeCodeSetup({ ...setupPlan, dryRun: false });
3398
+ return {
3399
+ harness: "claude",
3400
+ action: plan.action,
3401
+ applied: result.success,
3402
+ summary: result.success ? `Applied Claude Code managed ${plan.action} plan.` : result.error ?? `Failed to apply Claude Code ${plan.action} plan.`,
3403
+ changedTargets: result.changed.map((path4) => ({
3404
+ kind: path4.endsWith(".json") ? "memory-state" : "generated-artifact",
3405
+ path: path4,
3406
+ label: basename2(path4),
3407
+ state: "installed"
3408
+ })),
3409
+ backups: result.changed.filter((path4) => existsSync7(`${path4}.bak`)).map((path4) => ({ path: `${path4}.bak`, label: "managed backup" })),
3410
+ warnings: result.success ? [] : [{ severity: "critical", message: result.error ?? "apply failed." }],
3411
+ disclaimers: claudeCodeDisclaimers()
3412
+ };
3413
+ }
3414
+ function defaultClaudeCodeModelRoles() {
3415
+ return CLAUDE_CODE_ROLE_NAMES.map((role) => ({
3416
+ role,
3417
+ model: CLAUDE_CODE_SUBAGENT_DEFAULT_MODELS[role]
3418
+ }));
3419
+ }
3420
+
3421
+ // src/cli/operations/codex.ts
3422
+ import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
3423
+ import { basename as basename3 } from "path";
3424
+ var CODEX_DISPLAY_NAME = "Codex";
3425
+ var codexPlanSources = /* @__PURE__ */ new WeakMap();
3426
+ var codexModelSources = /* @__PURE__ */ new WeakMap();
3427
+ var codexActions = [
3428
+ {
3429
+ id: "codex-status",
3430
+ kind: "status",
3431
+ label: "Status",
3432
+ description: "Inspect managed Codex setup state",
3433
+ dryRun: false,
3434
+ requiresConfirmation: false,
3435
+ supported: true
3436
+ },
3437
+ {
3438
+ id: "codex-list",
3439
+ kind: "list",
3440
+ label: "List",
3441
+ description: "List managed Codex surfaces and actions",
3442
+ dryRun: false,
2306
3443
  requiresConfirmation: false,
2307
3444
  supported: true
2308
3445
  },
@@ -2374,10 +3511,10 @@ function codexDisclaimers() {
2374
3511
  }
2375
3512
  ];
2376
3513
  }
2377
- function warning(message, code) {
3514
+ function warning2(message, code) {
2378
3515
  return { severity: "important", message, code };
2379
3516
  }
2380
- function targetForItem(item, state, observed) {
3517
+ function targetForItem2(item, state, observed) {
2381
3518
  return {
2382
3519
  kind: item.kind === "managed-model-state" ? "memory-state" : "generated-artifact",
2383
3520
  path: item.targetPath,
@@ -2388,15 +3525,15 @@ function targetForItem(item, state, observed) {
2388
3525
  description: item.description
2389
3526
  };
2390
3527
  }
2391
- function surfaceForItem(item) {
3528
+ function surfaceForItem2(item) {
2392
3529
  return {
2393
- id: `${item.kind}:${item.role ?? basename2(item.targetPath)}`,
3530
+ id: `${item.kind}:${item.role ?? basename3(item.targetPath)}`,
2394
3531
  label: item.role ? `Codex ${item.role} subagent TOML` : item.kind.replaceAll("-", " "),
2395
3532
  path: item.targetPath,
2396
3533
  description: item.description
2397
3534
  };
2398
3535
  }
2399
- function backupForItem(item) {
3536
+ function backupForItem2(item) {
2400
3537
  return {
2401
3538
  required: item.requiresBackup,
2402
3539
  strategy: item.requiresBackup ? "managed-backup-file" : "none",
@@ -2404,9 +3541,9 @@ function backupForItem(item) {
2404
3541
  };
2405
3542
  }
2406
3543
  function rootBlockState(item) {
2407
- if (!existsSync5(item.targetPath))
3544
+ if (!existsSync8(item.targetPath))
2408
3545
  return { state: "missing", observed: "absent" };
2409
- const content = readFileSync5(item.targetPath, "utf8");
3546
+ const content = readFileSync9(item.targetPath, "utf8");
2410
3547
  if (item.content && content.includes(item.content)) {
2411
3548
  return { state: "installed", observed: "managed root block present" };
2412
3549
  }
@@ -2416,22 +3553,22 @@ function rootBlockState(item) {
2416
3553
  return { state: "missing", observed: "managed root block absent" };
2417
3554
  }
2418
3555
  function managedModelState(item) {
2419
- if (!existsSync5(item.targetPath))
3556
+ if (!existsSync8(item.targetPath))
2420
3557
  return { state: "missing", observed: "absent" };
2421
3558
  try {
2422
- const parsed = JSON.parse(readFileSync5(item.targetPath, "utf8"));
3559
+ const parsed = JSON.parse(readFileSync9(item.targetPath, "utf8"));
2423
3560
  if (parsed.version !== MANAGED_MODEL_STATE_VERSION || !parsed.models || typeof parsed.models !== "object" || Array.isArray(parsed.models)) {
2424
3561
  return { state: "unknown", observed: "invalid managed model state" };
2425
3562
  }
2426
- return item.content === readFileSync5(item.targetPath, "utf8") ? { state: "installed", observed: "managed model state current" } : { state: "drift", observed: "managed model state differs" };
3563
+ return item.content === readFileSync9(item.targetPath, "utf8") ? { state: "installed", observed: "managed model state current" } : { state: "drift", observed: "managed model state differs" };
2427
3564
  } catch {
2428
3565
  return { state: "unknown", observed: "unparseable managed model state" };
2429
3566
  }
2430
3567
  }
2431
3568
  function userConfigState(item) {
2432
- if (!existsSync5(item.targetPath))
3569
+ if (!existsSync8(item.targetPath))
2433
3570
  return { state: "missing", observed: "absent" };
2434
- const content = readFileSync5(item.targetPath, "utf8");
3571
+ const content = readFileSync9(item.targetPath, "utf8");
2435
3572
  if (/^\s*default_mode_request_user_input\s*=\s*true\b/m.test(content)) {
2436
3573
  return {
2437
3574
  state: "installed",
@@ -2444,10 +3581,10 @@ function userConfigState(item) {
2444
3581
  return { state: "missing", observed: "managed feature flag absent" };
2445
3582
  }
2446
3583
  function marketplaceState(item) {
2447
- if (!existsSync5(item.targetPath))
3584
+ if (!existsSync8(item.targetPath))
2448
3585
  return { state: "missing", observed: "absent" };
2449
3586
  try {
2450
- const parsed = JSON.parse(readFileSync5(item.targetPath, "utf8"));
3587
+ const parsed = JSON.parse(readFileSync9(item.targetPath, "utf8"));
2451
3588
  const plugins = Array.isArray(parsed.plugins) ? parsed.plugins : [];
2452
3589
  const entry = plugins.find(
2453
3590
  (plugin) => plugin && typeof plugin === "object" && "name" in plugin && plugin.name === "thoth-agents"
@@ -2460,11 +3597,11 @@ function marketplaceState(item) {
2460
3597
  return { state: "unknown", observed: "unparseable marketplace JSON" };
2461
3598
  }
2462
3599
  }
2463
- function contentState(item) {
2464
- if (!existsSync5(item.targetPath))
3600
+ function contentState2(item) {
3601
+ if (!existsSync8(item.targetPath))
2465
3602
  return { state: "missing", observed: "absent" };
2466
- const observed = readFileSync5(item.targetPath, "utf8");
2467
- if (basename2(item.targetPath) === "plugin.json" && item.targetPath.replaceAll("\\", "/").includes("/.codex-plugin/")) {
3603
+ const observed = readFileSync9(item.targetPath, "utf8");
3604
+ if (basename3(item.targetPath) === "plugin.json" && item.targetPath.replaceAll("\\", "/").includes("/.codex-plugin/")) {
2468
3605
  try {
2469
3606
  const expectedVersion = JSON.parse(item.content ?? "{}").version;
2470
3607
  const observedVersion = JSON.parse(observed).version;
@@ -2492,7 +3629,7 @@ function contentState(item) {
2492
3629
  }
2493
3630
  return { state: "drift", observed: "content differs" };
2494
3631
  }
2495
- function classifyItem(item) {
3632
+ function classifyItem2(item) {
2496
3633
  if (item.action === "diagnose-only") {
2497
3634
  return { state: "unknown", observed: "diagnostic guidance only" };
2498
3635
  }
@@ -2502,16 +3639,16 @@ function classifyItem(item) {
2502
3639
  }
2503
3640
  if (item.action === "merge-toml") return userConfigState(item);
2504
3641
  if (item.action === "merge-marketplace") return marketplaceState(item);
2505
- return contentState(item);
3642
+ return contentState2(item);
2506
3643
  }
2507
- function aggregateState(states) {
3644
+ function aggregateState2(states) {
2508
3645
  if (states.includes("unknown")) return "unknown";
2509
3646
  if (states.includes("drift")) return "drift";
2510
3647
  if (states.includes("outdated")) return "outdated";
2511
3648
  if (states.includes("missing")) return "missing";
2512
3649
  return "installed";
2513
3650
  }
2514
- function statusSummary(state) {
3651
+ function statusSummary2(state) {
2515
3652
  switch (state) {
2516
3653
  case "installed":
2517
3654
  return "Codex managed setup surfaces are installed and current.";
@@ -2548,8 +3685,8 @@ function getCodexStatus(context = { cwd: process.cwd() }) {
2548
3685
  disclaimers: codexDisclaimers()
2549
3686
  };
2550
3687
  }
2551
- const classified = plan.items.filter((item) => item.action !== "diagnose-only").map((item) => ({ item, ...classifyItem(item) }));
2552
- const state = aggregateState(classified.map((item) => item.state));
3688
+ const classified = plan.items.filter((item) => item.action !== "diagnose-only").map((item) => ({ item, ...classifyItem2(item) }));
3689
+ const state = aggregateState2(classified.map((item) => item.state));
2553
3690
  const diagnostics = plan.diagnostics.map((message) => ({
2554
3691
  severity: "minor",
2555
3692
  message,
@@ -2559,9 +3696,9 @@ function getCodexStatus(context = { cwd: process.cwd() }) {
2559
3696
  harness: "codex",
2560
3697
  displayName: CODEX_DISPLAY_NAME,
2561
3698
  state,
2562
- summary: statusSummary(state),
3699
+ summary: statusSummary2(state),
2563
3700
  targets: classified.map(
2564
- ({ item, state: state2, observed }) => targetForItem(item, state2, observed)
3701
+ ({ item, state: state2, observed }) => targetForItem2(item, state2, observed)
2565
3702
  ),
2566
3703
  diagnostics,
2567
3704
  actions: codexActions,
@@ -2571,15 +3708,15 @@ function getCodexStatus(context = { cwd: process.cwd() }) {
2571
3708
  ]
2572
3709
  };
2573
3710
  }
2574
- function planItemFromSetup(item) {
3711
+ function planItemFromSetup2(item) {
2575
3712
  return {
2576
3713
  title: item.description,
2577
- target: targetForItem(item),
3714
+ target: targetForItem2(item),
2578
3715
  preview: item.content,
2579
- backup: backupForItem(item)
3716
+ backup: backupForItem2(item)
2580
3717
  };
2581
3718
  }
2582
- function planFromSetup(id, action, title, summary, setupPlan, context) {
3719
+ function planFromSetup2(id, action, title, summary, setupPlan, context) {
2583
3720
  const status = getCodexStatus(context);
2584
3721
  const canApply = status.state === "installed" || status.state === "missing" || status.state === "outdated";
2585
3722
  const plan = {
@@ -2591,17 +3728,17 @@ function planFromSetup(id, action, title, summary, setupPlan, context) {
2591
3728
  dryRun: true,
2592
3729
  canApply,
2593
3730
  targets: status.targets,
2594
- surfaces: setupPlan.items.filter((item) => item.action !== "diagnose-only").map(surfaceForItem),
3731
+ surfaces: setupPlan.items.filter((item) => item.action !== "diagnose-only").map(surfaceForItem2),
2595
3732
  backup: {
2596
3733
  required: setupPlan.items.some((item) => item.requiresBackup),
2597
3734
  strategy: "existing-helper",
2598
3735
  description: "Codex setup apply uses the existing installer backup behavior for files that already exist."
2599
3736
  },
2600
- items: setupPlan.items.map(planItemFromSetup),
3737
+ items: setupPlan.items.map(planItemFromSetup2),
2601
3738
  warnings: [
2602
3739
  ...status.diagnostics,
2603
3740
  ...canApply ? [] : [
2604
- warning(
3741
+ warning2(
2605
3742
  `Codex state is ${status.state}; apply is disabled until the state is safely classified or repaired.`,
2606
3743
  "codex-unsafe-state"
2607
3744
  )
@@ -2617,7 +3754,7 @@ function planFromSetup(id, action, title, summary, setupPlan, context) {
2617
3754
  }
2618
3755
  function buildCodexUpdatePlan(context = { cwd: process.cwd() }) {
2619
3756
  const setupPlan = buildCodexSetupPlan(codexConfig(context, true));
2620
- return planFromSetup(
3757
+ return planFromSetup2(
2621
3758
  "codex-update-preview",
2622
3759
  "update",
2623
3760
  "Update Codex managed setup",
@@ -2628,7 +3765,7 @@ function buildCodexUpdatePlan(context = { cwd: process.cwd() }) {
2628
3765
  }
2629
3766
  function buildCodexSyncPlan(context = { cwd: process.cwd() }) {
2630
3767
  const setupPlan = buildCodexSetupPlan(codexConfig(context, true));
2631
- return planFromSetup(
3768
+ return planFromSetup2(
2632
3769
  "codex-sync-preview",
2633
3770
  "sync",
2634
3771
  "Sync Codex managed configuration",
@@ -2639,7 +3776,7 @@ function buildCodexSyncPlan(context = { cwd: process.cwd() }) {
2639
3776
  }
2640
3777
  function buildCodexInstallPlan(context = { cwd: process.cwd() }) {
2641
3778
  const setupPlan = buildCodexSetupPlan(codexConfig(context, true));
2642
- return planFromSetup(
3779
+ return planFromSetup2(
2643
3780
  "codex-install-preview",
2644
3781
  "install",
2645
3782
  "Install Codex managed setup",
@@ -2670,7 +3807,7 @@ function buildCodexModelPlan(input, context = { cwd: process.cwd() }) {
2670
3807
  ...status.diagnostics,
2671
3808
  ...input.warnings ?? [],
2672
3809
  ...unsupportedRoles.map(
2673
- (role) => warning(
3810
+ (role) => warning2(
2674
3811
  `Codex does not expose a supported generated model surface for ${role.role}; this plan will not write that role.`,
2675
3812
  "codex-unsupported-model-role"
2676
3813
  )
@@ -2678,7 +3815,7 @@ function buildCodexModelPlan(input, context = { cwd: process.cwd() }) {
2678
3815
  ];
2679
3816
  if (input.harness !== "codex") {
2680
3817
  warnings.push(
2681
- warning(
3818
+ warning2(
2682
3819
  "Model plan target harness must be codex.",
2683
3820
  "codex-model-harness-mismatch"
2684
3821
  )
@@ -2745,7 +3882,7 @@ function buildCodexModelPlan(input, context = { cwd: process.cwd() }) {
2745
3882
  codexModelSources.set(plan, { config, roles: supportedRoles });
2746
3883
  return plan;
2747
3884
  }
2748
- function rejectPlan(plan, message, severity = "critical") {
3885
+ function rejectPlan2(plan, message, severity = "critical") {
2749
3886
  return {
2750
3887
  harness: plan.harness,
2751
3888
  action: plan.action,
@@ -2759,19 +3896,19 @@ function rejectPlan(plan, message, severity = "critical") {
2759
3896
  }
2760
3897
  function validateCodexPlan(plan) {
2761
3898
  if (plan.harness !== "codex") {
2762
- return rejectPlan(plan, "Only Codex operation plans can be applied.");
3899
+ return rejectPlan2(plan, "Only Codex operation plans can be applied.");
2763
3900
  }
2764
3901
  if (!plan.canApply) {
2765
- return rejectPlan(
3902
+ return rejectPlan2(
2766
3903
  plan,
2767
3904
  "Codex plan cannot be applied because canApply is false."
2768
3905
  );
2769
3906
  }
2770
3907
  if (!["install", "update", "sync", "model-config"].includes(plan.action)) {
2771
- return rejectPlan(plan, `Unsupported Codex apply action: ${plan.action}.`);
3908
+ return rejectPlan2(plan, `Unsupported Codex apply action: ${plan.action}.`);
2772
3909
  }
2773
3910
  if (plan.items.length === 0) {
2774
- return rejectPlan(plan, "Codex plan has no items to apply.");
3911
+ return rejectPlan2(plan, "Codex plan has no items to apply.");
2775
3912
  }
2776
3913
  return null;
2777
3914
  }
@@ -2781,7 +3918,7 @@ function applyCodexPlan(plan) {
2781
3918
  if (plan.action === "model-config") {
2782
3919
  const source = codexModelSources.get(plan);
2783
3920
  if (!source) {
2784
- return rejectPlan(
3921
+ return rejectPlan2(
2785
3922
  plan,
2786
3923
  "Codex model plan was not produced by buildCodexModelPlan in this process."
2787
3924
  );
@@ -2792,13 +3929,13 @@ function applyCodexPlan(plan) {
2792
3929
  action: "model-config",
2793
3930
  applied: result2.success,
2794
3931
  summary: result2.success ? "Applied Codex subagent model overrides." : result2.error ?? "Failed to apply Codex subagent model overrides.",
2795
- changedTargets: result2.changed.map((path2) => ({
2796
- kind: path2.endsWith(".json") ? "memory-state" : "generated-artifact",
2797
- path: path2,
2798
- label: basename2(path2),
3932
+ changedTargets: result2.changed.map((path4) => ({
3933
+ kind: path4.endsWith(".json") ? "memory-state" : "generated-artifact",
3934
+ path: path4,
3935
+ label: basename3(path4),
2799
3936
  state: "installed"
2800
3937
  })),
2801
- backups: result2.changed.filter((path2) => existsSync5(`${path2}.bak`)).map((path2) => ({ path: `${path2}.bak`, label: "managed backup" })),
3938
+ backups: result2.changed.filter((path4) => existsSync8(`${path4}.bak`)).map((path4) => ({ path: `${path4}.bak`, label: "managed backup" })),
2802
3939
  warnings: result2.success ? [] : [
2803
3940
  {
2804
3941
  severity: "critical",
@@ -2810,7 +3947,7 @@ function applyCodexPlan(plan) {
2810
3947
  }
2811
3948
  const setupPlan = codexPlanSources.get(plan);
2812
3949
  if (!setupPlan) {
2813
- return rejectPlan(
3950
+ return rejectPlan2(
2814
3951
  plan,
2815
3952
  "Codex setup plan was not produced by a Codex operation plan builder in this process."
2816
3953
  );
@@ -2821,13 +3958,13 @@ function applyCodexPlan(plan) {
2821
3958
  action: plan.action,
2822
3959
  applied: result.success,
2823
3960
  summary: result.success ? `Applied Codex managed ${plan.action} plan.` : result.error ?? `Failed to apply Codex ${plan.action} plan.`,
2824
- changedTargets: result.changed.map((path2) => ({
2825
- kind: path2.endsWith(".json") ? "memory-state" : "generated-artifact",
2826
- path: path2,
2827
- label: basename2(path2),
3961
+ changedTargets: result.changed.map((path4) => ({
3962
+ kind: path4.endsWith(".json") ? "memory-state" : "generated-artifact",
3963
+ path: path4,
3964
+ label: basename3(path4),
2828
3965
  state: "installed"
2829
3966
  })),
2830
- backups: result.changed.filter((path2) => existsSync5(`${path2}.bak`)).map((path2) => ({ path: `${path2}.bak`, label: "managed backup" })),
3967
+ backups: result.changed.filter((path4) => existsSync8(`${path4}.bak`)).map((path4) => ({ path: `${path4}.bak`, label: "managed backup" })),
2831
3968
  warnings: result.success ? [] : [
2832
3969
  {
2833
3970
  severity: "critical",
@@ -2839,14 +3976,14 @@ function applyCodexPlan(plan) {
2839
3976
  }
2840
3977
 
2841
3978
  // src/cli/operations/opencode.ts
2842
- import { existsSync as existsSync7 } from "fs";
2843
- import { join as join6 } from "path";
3979
+ import { existsSync as existsSync10 } from "fs";
3980
+ import { join as join10 } from "path";
2844
3981
 
2845
3982
  // src/cli/skills.ts
2846
3983
  import { spawnSync } from "child_process";
2847
- import { existsSync as existsSync6 } from "fs";
2848
- import { homedir as homedir2 } from "os";
2849
- import { join as join5 } from "path";
3984
+ import { existsSync as existsSync9 } from "fs";
3985
+ import { homedir as homedir3 } from "os";
3986
+ import { join as join9 } from "path";
2850
3987
  var RECOMMENDED_SKILLS = [
2851
3988
  {
2852
3989
  name: "simplify",
@@ -2861,11 +3998,11 @@ var RECOMMENDED_SKILLS = [
2861
3998
  description: "Browser automation for visual checks and testing"
2862
3999
  }
2863
4000
  ];
2864
- function getRecommendedSkillPath(skill, homeDir = homedir2()) {
2865
- return join5(homeDir, ".agents", "skills", skill.skillName, "SKILL.md");
4001
+ function getRecommendedSkillPath(skill, homeDir = homedir3()) {
4002
+ return join9(homeDir, ".agents", "skills", skill.skillName, "SKILL.md");
2866
4003
  }
2867
4004
  function isRecommendedSkillInstalled(skill, options = {}) {
2868
- return existsSync6(getRecommendedSkillPath(skill, options.homeDir));
4005
+ return existsSync9(getRecommendedSkillPath(skill, options.homeDir));
2869
4006
  }
2870
4007
  function runSkillInstallCommand(skill) {
2871
4008
  const args = [
@@ -3019,11 +4156,11 @@ function openCodeSkillTargets(context) {
3019
4156
  const homeDir = homeDirFromContext(context);
3020
4157
  const recommendedTargets = RECOMMENDED_SKILLS.map(
3021
4158
  (skill) => {
3022
- const path2 = getRecommendedSkillPath(skill, homeDir);
3023
- const installed = existsSync7(path2);
4159
+ const path4 = getRecommendedSkillPath(skill, homeDir);
4160
+ const installed = existsSync10(path4);
3024
4161
  return {
3025
4162
  kind: "skill",
3026
- path: path2,
4163
+ path: path4,
3027
4164
  label: titleCaseSkillName(skill.skillName),
3028
4165
  state: installed ? "installed" : "missing",
3029
4166
  expected: "recommended global OpenCode skill",
@@ -3032,11 +4169,11 @@ function openCodeSkillTargets(context) {
3032
4169
  }
3033
4170
  );
3034
4171
  const bundledTargets = CUSTOM_SKILLS.map((skill) => {
3035
- const path2 = join6(getCustomSkillsDir(), skill.name, "SKILL.md");
3036
- const installed = existsSync7(path2);
4172
+ const path4 = join10(getCustomSkillsDir(), skill.name, "SKILL.md");
4173
+ const installed = existsSync10(path4);
3037
4174
  return {
3038
4175
  kind: "skill",
3039
- path: path2,
4176
+ path: path4,
3040
4177
  label: titleCaseSkillName(skill.name),
3041
4178
  state: installed ? "installed" : "missing",
3042
4179
  expected: "bundled thoth-agents OpenCode skill",
@@ -3139,8 +4276,8 @@ function getOpenCodeStatus(context = { cwd: process.cwd() }) {
3139
4276
  actions: openCodeActions
3140
4277
  };
3141
4278
  }
3142
- const mainExists = existsSync7(mainPath);
3143
- const liteExists = existsSync7(litePath);
4279
+ const mainExists = existsSync10(mainPath);
4280
+ const liteExists = existsSync10(litePath);
3144
4281
  const mainTarget = {
3145
4282
  ...targetForMainConfig(),
3146
4283
  observed: configPluginMarker(main.config)
@@ -3237,11 +4374,11 @@ function getOpenCodeStatus(context = { cwd: process.cwd() }) {
3237
4374
  actions: openCodeActions
3238
4375
  };
3239
4376
  }
3240
- function defaultBackup(path2) {
4377
+ function defaultBackup(path4) {
3241
4378
  return {
3242
4379
  required: true,
3243
4380
  strategy: "managed-backup-file",
3244
- destinations: [{ path: `${path2}.bak`, label: "managed backup" }]
4381
+ destinations: [{ path: `${path4}.bak`, label: "managed backup" }]
3245
4382
  };
3246
4383
  }
3247
4384
  function defaultDisclaimers() {
@@ -3293,7 +4430,7 @@ function planFromItems(id, action, title, summary, items) {
3293
4430
  };
3294
4431
  }
3295
4432
  function buildOpenCodeUpdatePlan(_context = { cwd: process.cwd() }) {
3296
- const path2 = getExistingConfigPath();
4433
+ const path4 = getExistingConfigPath();
3297
4434
  return planFromItems(
3298
4435
  "opencode-update-preview",
3299
4436
  "update",
@@ -3305,7 +4442,7 @@ function buildOpenCodeUpdatePlan(_context = { cwd: process.cwd() }) {
3305
4442
  target: targetForMainConfig(),
3306
4443
  state: getOpenCodeStatus().state,
3307
4444
  preview: `plugin: ["${EXPECTED_PLUGIN}"]`,
3308
- backup: defaultBackup(path2)
4445
+ backup: defaultBackup(path4)
3309
4446
  }
3310
4447
  ]
3311
4448
  );
@@ -3472,7 +4609,7 @@ function buildOpenCodeModelPlan(input, _context = { cwd: process.cwd() }) {
3472
4609
  }
3473
4610
  return plan;
3474
4611
  }
3475
- function rejectPlan2(plan, message, severity = "critical") {
4612
+ function rejectPlan3(plan, message, severity = "critical") {
3476
4613
  return {
3477
4614
  harness: plan.harness,
3478
4615
  action: plan.action,
@@ -3516,27 +4653,27 @@ function ensureLatestPluginEntry() {
3516
4653
  }
3517
4654
  function validateApplyPlan(plan) {
3518
4655
  if (plan.harness !== "opencode") {
3519
- return rejectPlan2(plan, "Only OpenCode operation plans can be applied.");
4656
+ return rejectPlan3(plan, "Only OpenCode operation plans can be applied.");
3520
4657
  }
3521
4658
  if (!plan.canApply) {
3522
- return rejectPlan2(
4659
+ return rejectPlan3(
3523
4660
  plan,
3524
4661
  "OpenCode plan cannot be applied because canApply is false."
3525
4662
  );
3526
4663
  }
3527
4664
  if (!["install", "update", "sync", "model-config"].includes(plan.action)) {
3528
- return rejectPlan2(
4665
+ return rejectPlan3(
3529
4666
  plan,
3530
4667
  `Unsupported OpenCode apply action: ${plan.action}.`
3531
4668
  );
3532
4669
  }
3533
4670
  if (plan.items.length === 0) {
3534
- return rejectPlan2(plan, "OpenCode plan has no items to apply.");
4671
+ return rejectPlan3(plan, "OpenCode plan has no items to apply.");
3535
4672
  }
3536
4673
  if (plan.items.some(
3537
4674
  (item) => !item.title || !item.target.path && item.target.kind !== "skill" || item.state === "drift" || item.state === "unknown"
3538
4675
  )) {
3539
- return rejectPlan2(
4676
+ return rejectPlan3(
3540
4677
  plan,
3541
4678
  "OpenCode plan contains malformed or unsafe items."
3542
4679
  );
@@ -3548,7 +4685,7 @@ function applyModelPlan(plan) {
3548
4685
  for (const item of plan.items) {
3549
4686
  const match = /^Set (.+) OpenCode model override$/.exec(item.title);
3550
4687
  if (!match) {
3551
- return rejectPlan2(
4688
+ return rejectPlan3(
3552
4689
  plan,
3553
4690
  "OpenCode model plan contains an unrecognized item."
3554
4691
  );
@@ -3557,7 +4694,7 @@ function applyModelPlan(plan) {
3557
4694
  try {
3558
4695
  parsed2 = item.preview ? JSON.parse(item.preview) : {};
3559
4696
  } catch {
3560
- return rejectPlan2(
4697
+ return rejectPlan3(
3561
4698
  plan,
3562
4699
  "OpenCode model plan contains malformed preview JSON."
3563
4700
  );
@@ -3565,7 +4702,7 @@ function applyModelPlan(plan) {
3565
4702
  const role = match[1] ?? "";
3566
4703
  const model = parsed2[role]?.model;
3567
4704
  if (!ROLE_NAMES.includes(role) || typeof model !== "string") {
3568
- return rejectPlan2(
4705
+ return rejectPlan3(
3569
4706
  plan,
3570
4707
  "OpenCode model plan contains an invalid role or model."
3571
4708
  );
@@ -3573,7 +4710,7 @@ function applyModelPlan(plan) {
3573
4710
  roleModels.set(role, model);
3574
4711
  }
3575
4712
  if (roleModels.size === 0) {
3576
- return rejectPlan2(
4713
+ return rejectPlan3(
3577
4714
  plan,
3578
4715
  "OpenCode model plan does not contain any role overrides."
3579
4716
  );
@@ -3609,7 +4746,7 @@ function applyModelPlan(plan) {
3609
4746
  observed: "agents role overrides updated"
3610
4747
  }
3611
4748
  ],
3612
- backups: existsSync7(`${targetPath}.bak`) ? [{ path: `${targetPath}.bak`, label: "managed backup" }] : [],
4749
+ backups: existsSync10(`${targetPath}.bak`) ? [{ path: `${targetPath}.bak`, label: "managed backup" }] : [],
3613
4750
  warnings: [],
3614
4751
  disclaimers: defaultDisclaimers()
3615
4752
  };
@@ -3618,7 +4755,7 @@ function applyInstallSkills(plan) {
3618
4755
  for (const skill of RECOMMENDED_SKILLS) {
3619
4756
  const result = installRecommendedSkill(skill);
3620
4757
  if (result.status === "failed") {
3621
- return rejectPlan2(
4758
+ return rejectPlan3(
3622
4759
  plan,
3623
4760
  `Failed to install recommended OpenCode skill: ${skill.name}.`
3624
4761
  );
@@ -3626,7 +4763,7 @@ function applyInstallSkills(plan) {
3626
4763
  }
3627
4764
  const bundled = installCustomSkills();
3628
4765
  if (!bundled.success) {
3629
- return rejectPlan2(
4766
+ return rejectPlan3(
3630
4767
  plan,
3631
4768
  "Failed to install bundled thoth-agents OpenCode skills."
3632
4769
  );
@@ -3638,7 +4775,7 @@ function applyOpenCodePlan(plan) {
3638
4775
  if (rejection) return rejection;
3639
4776
  const status = getOpenCodeStatus();
3640
4777
  if (!classifyApplySafety(status.state)) {
3641
- return rejectPlan2(
4778
+ return rejectPlan3(
3642
4779
  plan,
3643
4780
  `OpenCode state is ${status.state}; refusing to apply plan without a safe status.`
3644
4781
  );
@@ -3648,7 +4785,7 @@ function applyOpenCodePlan(plan) {
3648
4785
  const backups = [];
3649
4786
  const pluginResult = ensureLatestPluginEntry();
3650
4787
  if (!pluginResult.success) {
3651
- return rejectPlan2(
4788
+ return rejectPlan3(
3652
4789
  plan,
3653
4790
  pluginResult.error ?? "Failed to update OpenCode plugin config."
3654
4791
  );
@@ -3657,7 +4794,7 @@ function applyOpenCodePlan(plan) {
3657
4794
  ...targetForMainConfig("installed"),
3658
4795
  observed: `plugin includes ${EXPECTED_PLUGIN}`
3659
4796
  });
3660
- if (existsSync7(`${pluginResult.configPath}.bak`)) {
4797
+ if (existsSync10(`${pluginResult.configPath}.bak`)) {
3661
4798
  backups.push({
3662
4799
  path: `${pluginResult.configPath}.bak`,
3663
4800
  label: "OpenCode config backup"
@@ -3666,7 +4803,7 @@ function applyOpenCodePlan(plan) {
3666
4803
  if (plan.action === "sync" || plan.action === "install") {
3667
4804
  const defaultAgentResult = disableDefaultAgents();
3668
4805
  if (!defaultAgentResult.success) {
3669
- return rejectPlan2(
4806
+ return rejectPlan3(
3670
4807
  plan,
3671
4808
  defaultAgentResult.error ?? "Failed to disable OpenCode default agents."
3672
4809
  );
@@ -3683,7 +4820,7 @@ function applyOpenCodePlan(plan) {
3683
4820
  getExistingLiteConfigPath()
3684
4821
  );
3685
4822
  if (!liteResult.success) {
3686
- return rejectPlan2(
4823
+ return rejectPlan3(
3687
4824
  plan,
3688
4825
  liteResult.error ?? "Failed to write thoth-agents config."
3689
4826
  );
@@ -3692,7 +4829,7 @@ function applyOpenCodePlan(plan) {
3692
4829
  ...targetForLiteConfig("installed"),
3693
4830
  observed: "seven-agent roster written"
3694
4831
  });
3695
- if (existsSync7(`${liteResult.configPath}.bak`)) {
4832
+ if (existsSync10(`${liteResult.configPath}.bak`)) {
3696
4833
  backups.push({
3697
4834
  path: `${liteResult.configPath}.bak`,
3698
4835
  label: "thoth-agents config backup"
@@ -3724,7 +4861,8 @@ function applyOpenCodePlan(plan) {
3724
4861
  // src/cli/operations/index.ts
3725
4862
  var OPERATION_HARNESSES = {
3726
4863
  opencode: opencodeOperationAdapter,
3727
- codex: codexOperationAdapter
4864
+ codex: codexOperationAdapter,
4865
+ claude: claudeCodeOperationAdapter
3728
4866
  };
3729
4867
  var SUPPORTED_OPERATION_HARNESSES = Object.keys(
3730
4868
  OPERATION_HARNESSES
@@ -3739,14 +4877,27 @@ function getOperationHarness(harness) {
3739
4877
  }
3740
4878
 
3741
4879
  export {
4880
+ claudeCodeAdapter,
3742
4881
  codexAdapter,
3743
4882
  CODEX_ROLE_NAMES,
3744
4883
  parseRoleTomlModel,
3745
4884
  buildCodexSetupPlan,
3746
4885
  formatCodexSetupPlan,
3747
4886
  applyCodexSetup,
4887
+ CLAUDE_CODE_ROLE_NAMES,
4888
+ parseSubagentModel,
4889
+ buildClaudeCodeSetupPlan,
4890
+ applyClaudeCodeSetup,
4891
+ formatClaudeCodeSetupPlan,
3748
4892
  RECOMMENDED_SKILLS,
3749
4893
  installRecommendedSkill,
4894
+ getClaudeCodeStatus,
4895
+ buildClaudeCodeInstallPlan,
4896
+ buildClaudeCodeUpdatePlan,
4897
+ buildClaudeCodeSyncPlan,
4898
+ buildClaudeCodeModelPlan,
4899
+ applyClaudeCodePlan,
4900
+ defaultClaudeCodeModelRoles,
3750
4901
  getCodexStatus,
3751
4902
  buildCodexUpdatePlan,
3752
4903
  buildCodexSyncPlan,