thoth-agents 0.3.1 → 0.3.3

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.
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "name": "thoth-agents",
11
11
  "description": "Adaptive root orchestration, six specialist subagents, and a runtime-autonomous Spec Kit-compatible SDD bundle.",
12
- "version": "0.3.1",
12
+ "version": "0.3.3",
13
13
  "author": {
14
14
  "name": "thoth-agents maintainers"
15
15
  },
package/README.md CHANGED
@@ -65,25 +65,19 @@ from the CLI step. Existing project-owned files are preserved.
65
65
 
66
66
  ### Codex
67
67
 
68
- Register the repository marketplace from a terminal:
69
-
70
- ```bash
71
- codex plugin marketplace add EremesNG/thoth-agents
72
- ```
73
-
74
- Restart Codex, open `/plugins`, and install or enable `thoth-agents`. Then return
75
- to a terminal and apply the mandatory global layer:
68
+ Preview, then run the combined native-plugin and global-layer installer:
76
69
 
77
70
  ```bash
78
71
  npx thoth-agents@latest install --agent=codex --dry-run
79
72
  npx thoth-agents@latest install --agent=codex
80
73
  ```
81
74
 
82
- The CLI writes the orchestrator block to `~/.codex/AGENTS.md`, creates six
83
- custom-agent TOMLs under `~/.codex/agents/`, and merges the managed feature into
84
- `~/.codex/config.toml`. It also installs the external skills and invokes
85
- provider-owned thoth-mem setup. Restart Codex again, then initialize each target
86
- repository's SDD governance:
75
+ The CLI first uses Codex's native manager to register `EremesNG/thoth-agents`
76
+ and install or enable `thoth-agents@thoth-agents`. It then writes the
77
+ orchestrator block to `~/.codex/AGENTS.md`, creates six custom-agent TOMLs under
78
+ `~/.codex/agents/`, merges the managed feature into `~/.codex/config.toml`,
79
+ installs the external skills, and invokes provider-owned thoth-mem setup.
80
+ Restart Codex, then initialize each target repository's SDD governance:
87
81
 
88
82
  ```text
89
83
  $thoth-init
@@ -345,7 +339,7 @@ diagnostics, manual actions, and receipt paths remain visible for recovery.
345
339
  | Harness | Important limitation |
346
340
  | --- | --- |
347
341
  | OpenCode | Strongest integrated path. The CLI installs the npm plugin configuration, external skills, and provider-owned thoth-mem setup; `/thoth-init` materializes thoth-owned project skills/governance. Only the OpenAI built-in preset ships. |
348
- | Codex | Native plugin installation is incomplete without the CLI. The CLI manages global `AGENTS.md`, six agent TOMLs, config, external skills, and thoth-mem setup; `$thoth-init` only initializes per-repository SDD governance. Runtime role matching and some permissions remain instruction-level. |
342
+ | Codex | The CLI installs the native plugin and manages global `AGENTS.md`, six agent TOMLs, config, external skills, and thoth-mem setup; `$thoth-init` only initializes per-repository SDD governance. Runtime role matching and some permissions remain instruction-level. |
349
343
  | Claude Code | Run both native marketplace commands before the CLI installs external skills and requests thoth-mem setup. The native manager owns cache files; fine-grained path restrictions remain instruction-level. |
350
344
 
351
345
  Codex and Claude marketplace manifests are versioned in
@@ -385,7 +379,8 @@ npx thoth-agents@latest install --agent=claude
385
379
  npx thoth-agents@latest model --harness=codex --role=deep --model=gpt-5.6-sol
386
380
  ```
387
381
 
388
- It does not replace native marketplace trust or mutate manager-owned caches.
382
+ It does not bypass native marketplace trust or edit manager-owned caches
383
+ directly; Codex and Claude own their native manager mutations.
389
384
 
390
385
  ## Documentation
391
386
 
@@ -1411,11 +1411,11 @@ function buildCodexManagedConfigPatch(content, options) {
1411
1411
  ];
1412
1412
  if (options.pluginId) {
1413
1413
  diffSummary.push(
1414
- `plugin enablement for "${options.pluginId}" is not textually merged; use /plugins to enable it`
1414
+ `plugin enablement for "${options.pluginId}" is not textually merged; use the native Codex plugin manager`
1415
1415
  );
1416
1416
  } else {
1417
1417
  diffSummary.push(
1418
- "plugin enablement left to /plugins; no guessed plugin id written"
1418
+ "plugin installation and enablement owned by the native Codex plugin manager; no plugin table written"
1419
1419
  );
1420
1420
  }
1421
1421
  return {
@@ -1843,8 +1843,8 @@ function buildCodexSetupPlan(config) {
1843
1843
  configPath: targets.configPath,
1844
1844
  pluginId: config.pluginId,
1845
1845
  diagnostics: [
1846
- "Register the published marketplace with `codex plugin marketplace add EremesNG/thoth-agents`, restart Codex, then open /plugins to install and enable thoth-agents.",
1847
- "The CLI does not copy a plugin into ~/.codex/plugins or merge ~/.agents/plugins/marketplace.json; Codex owns marketplace snapshots and installed plugin cache state.",
1846
+ "The combined install flow runs `codex plugin marketplace add EremesNG/thoth-agents` and `codex plugin add thoth-agents@thoth-agents` through the native manager; restart Codex, then use /plugins to review its state.",
1847
+ "The CLI does not copy a plugin into ~/.codex/plugins or merge ~/.agents/plugins/marketplace.json directly; Codex owns marketplace snapshots and installed plugin cache state.",
1848
1848
  "The /hooks surface may show hooks from independently installed plugins; this thoth-agents setup plan does not install provider hooks.",
1849
1849
  "Codex Default mode user-input requests require features.default_mode_request_user_input = true and use the request_user_input tool; other modes may not expose it.",
1850
1850
  "Higher-precedence Codex config (project, profile, CLI, system, or admin) may override user config feature flags.",
@@ -2478,6 +2478,19 @@ import { spawnSync as spawnSync2 } from "child_process";
2478
2478
  import { existsSync as existsSync6 } from "fs";
2479
2479
  import { homedir as homedir2 } from "os";
2480
2480
  import { join as join3 } from "path";
2481
+
2482
+ // src/cli/npx-command.ts
2483
+ function getNpxCommand(args, options = {}) {
2484
+ if ((options.platform ?? process.platform) !== "win32") {
2485
+ return { command: "npx", args: [...args] };
2486
+ }
2487
+ return {
2488
+ command: options.commandShell ?? process.env.ComSpec ?? "cmd.exe",
2489
+ args: ["/d", "/s", "/c", "npx.cmd", ...args]
2490
+ };
2491
+ }
2492
+
2493
+ // src/cli/skills.ts
2481
2494
  var SKILLS_CLI_AGENT = {
2482
2495
  opencode: "opencode",
2483
2496
  codex: "codex",
@@ -2525,10 +2538,10 @@ function getRequiredSkillPath(skill, harness, homeDir = homedir2()) {
2525
2538
  function isRequiredSkillInstalled(skill, harness, options = {}) {
2526
2539
  return existsSync6(getRequiredSkillPath(skill, harness, options.homeDir));
2527
2540
  }
2528
- function getRequiredSkillInstallCommand(skill, harness) {
2529
- return {
2530
- command: "npx",
2531
- args: [
2541
+ function getRequiredSkillInstallCommand(skill, harness, options = {}) {
2542
+ return getNpxCommand(
2543
+ [
2544
+ "--yes",
2532
2545
  "skills",
2533
2546
  "add",
2534
2547
  skill.repo,
@@ -2538,15 +2551,20 @@ function getRequiredSkillInstallCommand(skill, harness) {
2538
2551
  "--agent",
2539
2552
  SKILLS_CLI_AGENT[harness],
2540
2553
  "--yes"
2541
- ]
2542
- };
2554
+ ],
2555
+ options
2556
+ );
2543
2557
  }
2544
2558
  function installRequiredSkill(skill, harness, options = {}) {
2545
2559
  const skillPath = getRequiredSkillPath(skill, harness, options.homeDir);
2546
2560
  if (isRequiredSkillInstalled(skill, harness, options)) {
2547
2561
  return { skill, harness, status: "already-installed", skillPath };
2548
2562
  }
2549
- const { command, args } = getRequiredSkillInstallCommand(skill, harness);
2563
+ const { command, args } = getRequiredSkillInstallCommand(
2564
+ skill,
2565
+ harness,
2566
+ options
2567
+ );
2550
2568
  try {
2551
2569
  const result = spawnSync2(command, args, { stdio: "inherit" });
2552
2570
  if (result.status === 0) {
@@ -5717,6 +5735,7 @@ export {
5717
5735
  buildClaudeCodeSetupPlan,
5718
5736
  applyClaudeCodeSetup,
5719
5737
  formatClaudeCodeSetupPlan,
5738
+ getNpxCommand,
5720
5739
  REQUIRED_SKILLS,
5721
5740
  getRequiredSkillInstallCommand,
5722
5741
  installRequiredSkill,
@@ -0,0 +1,51 @@
1
+ export type CodexPluginSetupAction = 'register-marketplace' | 'install-plugin';
2
+ export interface CodexCommandResult {
3
+ exitCode: number;
4
+ stdout: string;
5
+ stderr: string;
6
+ }
7
+ export interface CodexCommandOptions {
8
+ cwd: string;
9
+ }
10
+ export interface CodexCommandInvocationOptions {
11
+ platform?: NodeJS.Platform;
12
+ commandShell?: string;
13
+ }
14
+ export interface CodexCommandInvocation {
15
+ command: string;
16
+ args: string[];
17
+ }
18
+ export type CodexCommandExecutor = (command: string, args: readonly string[], options: CodexCommandOptions) => CodexCommandResult;
19
+ export interface CodexPluginInstallConfig {
20
+ dryRun?: boolean;
21
+ projectRoot: string;
22
+ commandExecutor?: CodexCommandExecutor;
23
+ }
24
+ export interface CodexPluginSetupPlanItem {
25
+ action: CodexPluginSetupAction;
26
+ targetPath: string;
27
+ description: string;
28
+ command: {
29
+ executable: 'codex';
30
+ args: string[];
31
+ cwd: string;
32
+ };
33
+ }
34
+ export interface CodexPluginSetupPlan {
35
+ dryRun: boolean;
36
+ items: CodexPluginSetupPlanItem[];
37
+ diagnostics: string[];
38
+ ready: boolean;
39
+ projectRoot: string;
40
+ commandExecutor: CodexCommandExecutor;
41
+ }
42
+ export interface CodexPluginApplyResult {
43
+ success: boolean;
44
+ changed: string[];
45
+ diagnostics: string[];
46
+ error?: string;
47
+ }
48
+ export declare function getCodexCommand(args: readonly string[], options?: CodexCommandInvocationOptions): CodexCommandInvocation;
49
+ export declare function buildCodexPluginSetupPlan(config: CodexPluginInstallConfig): CodexPluginSetupPlan;
50
+ export declare function applyCodexPluginSetup(plan: CodexPluginSetupPlan): CodexPluginApplyResult;
51
+ export declare function formatCodexPluginSetupPlan(plan: CodexPluginSetupPlan): string;
package/dist/cli/index.js CHANGED
@@ -35,6 +35,7 @@ import {
35
35
  getCodexModelRoles,
36
36
  getCodexStatus,
37
37
  getModelOptions,
38
+ getNpxCommand,
38
39
  getOpenCodeModelRoles,
39
40
  getOpenCodeStatus,
40
41
  getOperationHarness,
@@ -42,7 +43,7 @@ import {
42
43
  installRequiredSkill,
43
44
  listOperationHarnesses,
44
45
  normalizeEffortSelection
45
- } from "../chunk-2MZ5C2RN.js";
46
+ } from "../chunk-UQOCEMU3.js";
46
47
  import {
47
48
  ALL_AGENT_NAMES,
48
49
  detectCurrentConfig,
@@ -73,8 +74,243 @@ import { existsSync } from "fs";
73
74
  import { homedir } from "os";
74
75
  import { cwd } from "process";
75
76
 
76
- // src/cli/thoth-mem-install.ts
77
+ // src/cli/codex-plugin-install.ts
77
78
  import { spawnSync } from "child_process";
79
+ var MARKETPLACE_NAME = "thoth-agents";
80
+ var MARKETPLACE_SOURCE = "EremesNG/thoth-agents";
81
+ var PLUGIN_ID = "thoth-agents@thoth-agents";
82
+ var MARKETPLACE_TARGET = "codex://marketplaces/thoth-agents";
83
+ var PLUGIN_TARGET = "codex://plugins/thoth-agents@thoth-agents";
84
+ function getCodexCommand(args, options = {}) {
85
+ if ((options.platform ?? process.platform) !== "win32") {
86
+ return { command: "codex", args: [...args] };
87
+ }
88
+ return {
89
+ command: options.commandShell ?? process.env.ComSpec ?? "cmd.exe",
90
+ args: ["/d", "/s", "/c", "codex.cmd", ...args]
91
+ };
92
+ }
93
+ function defaultCommandExecutor(command, args, options) {
94
+ const invocation = command === "codex" ? getCodexCommand(args) : { command, args: [...args] };
95
+ const result = spawnSync(invocation.command, invocation.args, {
96
+ cwd: options.cwd,
97
+ encoding: "utf8",
98
+ shell: false,
99
+ windowsHide: true
100
+ });
101
+ return {
102
+ exitCode: result.status ?? (result.error ? 1 : 0),
103
+ stdout: result.stdout ?? "",
104
+ stderr: result.stderr ?? result.error?.message ?? ""
105
+ };
106
+ }
107
+ function isRecord(value) {
108
+ return typeof value === "object" && value !== null && !Array.isArray(value);
109
+ }
110
+ function parseRecordArray(value) {
111
+ return Array.isArray(value) && value.every(isRecord) ? value : null;
112
+ }
113
+ function parseManagerRecord(content) {
114
+ try {
115
+ const parsed = JSON.parse(content);
116
+ return isRecord(parsed) ? parsed : null;
117
+ } catch {
118
+ return null;
119
+ }
120
+ }
121
+ function normalizeMarketplaceSource(value) {
122
+ return value.trim().replace(/^git@github\.com:/i, "").replace(/^(?:https?|ssh):\/\/(?:git@)?github\.com\//i, "").replace(/^github\.com\//i, "").replace(/\/?\.git\/?$/i, "").replace(/\/$/, "").toLowerCase();
123
+ }
124
+ function marketplaceSources(entry) {
125
+ const sources = [entry.repo, entry.source];
126
+ if (isRecord(entry.marketplaceSource)) {
127
+ sources.push(entry.marketplaceSource.repo, entry.marketplaceSource.source);
128
+ }
129
+ return sources.filter(
130
+ (source) => typeof source === "string"
131
+ );
132
+ }
133
+ function isCanonicalMarketplace(entry) {
134
+ if (entry.name !== MARKETPLACE_NAME) return false;
135
+ const canonical = MARKETPLACE_SOURCE.toLowerCase();
136
+ return marketplaceSources(entry).some(
137
+ (source) => normalizeMarketplaceSource(source) === canonical
138
+ );
139
+ }
140
+ function inspectCodexManager(executor, cwd2) {
141
+ const marketplaceResult = executor(
142
+ "codex",
143
+ ["plugin", "marketplace", "list", "--json"],
144
+ { cwd: cwd2 }
145
+ );
146
+ const pluginResult = executor(
147
+ "codex",
148
+ ["plugin", "list", "--available", "--json"],
149
+ { cwd: cwd2 }
150
+ );
151
+ const diagnostics = [];
152
+ if (marketplaceResult.exitCode !== 0 || pluginResult.exitCode !== 0) {
153
+ diagnostics.push(
154
+ "Codex native plugin state could not be inspected; no manager mutation will be attempted."
155
+ );
156
+ return {
157
+ ready: false,
158
+ marketplace: "unknown",
159
+ plugin: "unknown",
160
+ diagnostics
161
+ };
162
+ }
163
+ const marketplaceRecord = parseManagerRecord(marketplaceResult.stdout);
164
+ const pluginRecord = parseManagerRecord(pluginResult.stdout);
165
+ const marketplaces = marketplaceRecord ? parseRecordArray(marketplaceRecord.marketplaces) : null;
166
+ const installedPlugins = pluginRecord ? parseRecordArray(pluginRecord.installed) : null;
167
+ if (!marketplaces || !installedPlugins) {
168
+ diagnostics.push(
169
+ "Codex returned unparseable plugin manager JSON; no manager mutation will be attempted."
170
+ );
171
+ return {
172
+ ready: false,
173
+ marketplace: "unknown",
174
+ plugin: "unknown",
175
+ diagnostics
176
+ };
177
+ }
178
+ const namedMarketplaces = marketplaces.filter(
179
+ (entry) => entry.name === MARKETPLACE_NAME
180
+ );
181
+ let marketplace = "absent";
182
+ if (namedMarketplaces.length > 0) {
183
+ marketplace = namedMarketplaces.every(isCanonicalMarketplace) ? "installed" : "conflict";
184
+ }
185
+ if (marketplace === "conflict") {
186
+ diagnostics.push(
187
+ "A Codex marketplace named thoth-agents is registered from a different source; resolve it through Codex before retrying."
188
+ );
189
+ }
190
+ const matchingPlugins = installedPlugins.filter(
191
+ (entry) => entry.pluginId === PLUGIN_ID
192
+ );
193
+ let plugin = "absent";
194
+ if (matchingPlugins.some((entry) => entry.enabled === true)) {
195
+ plugin = "installed";
196
+ } else if (matchingPlugins.length > 0) {
197
+ plugin = "disabled";
198
+ }
199
+ return {
200
+ ready: marketplace !== "conflict",
201
+ marketplace,
202
+ plugin,
203
+ diagnostics
204
+ };
205
+ }
206
+ function commandItem(action, projectRoot) {
207
+ if (action === "register-marketplace") {
208
+ return {
209
+ action,
210
+ targetPath: MARKETPLACE_TARGET,
211
+ description: "Register the package-owned thoth-agents Codex marketplace.",
212
+ command: {
213
+ executable: "codex",
214
+ args: ["plugin", "marketplace", "add", MARKETPLACE_SOURCE, "--json"],
215
+ cwd: projectRoot
216
+ }
217
+ };
218
+ }
219
+ return {
220
+ action,
221
+ targetPath: PLUGIN_TARGET,
222
+ description: "Install and enable the thoth-agents Codex plugin from its native marketplace.",
223
+ command: {
224
+ executable: "codex",
225
+ args: ["plugin", "add", PLUGIN_ID, "--json"],
226
+ cwd: projectRoot
227
+ }
228
+ };
229
+ }
230
+ function buildCodexPluginSetupPlan(config) {
231
+ const commandExecutor = config.commandExecutor ?? defaultCommandExecutor;
232
+ const inspection = inspectCodexManager(commandExecutor, config.projectRoot);
233
+ const items = [];
234
+ if (inspection.ready) {
235
+ if (inspection.marketplace === "absent") {
236
+ items.push(commandItem("register-marketplace", config.projectRoot));
237
+ }
238
+ if (inspection.plugin === "absent" || inspection.plugin === "disabled") {
239
+ items.push(commandItem("install-plugin", config.projectRoot));
240
+ }
241
+ }
242
+ return {
243
+ dryRun: config.dryRun === true,
244
+ items,
245
+ ready: inspection.ready,
246
+ projectRoot: config.projectRoot,
247
+ commandExecutor,
248
+ diagnostics: [
249
+ ...inspection.diagnostics,
250
+ "Codex installs thoth-agents from EremesNG/thoth-agents through its native plugin manager and owns the cached plugin files.",
251
+ "Restart Codex after installation; use /plugins to inspect marketplace and plugin state."
252
+ ]
253
+ };
254
+ }
255
+ function uniqueMessages(messages) {
256
+ return [...new Set(messages)];
257
+ }
258
+ function boundedCommandFailure(item, result) {
259
+ const detail = result.stderr.trim().replace(/\s+/g, " ").slice(0, 240);
260
+ return `${item.description} Codex exited with code ${result.exitCode}${detail ? `: ${detail}` : "."}`;
261
+ }
262
+ function applyCodexPluginSetup(plan) {
263
+ const changed = [];
264
+ const diagnostics = uniqueMessages(plan.diagnostics);
265
+ if (!plan.ready) {
266
+ return {
267
+ success: false,
268
+ changed,
269
+ diagnostics,
270
+ error: "Codex native plugin manager state is not safe to mutate."
271
+ };
272
+ }
273
+ if (plan.dryRun) return { success: true, changed, diagnostics };
274
+ for (const item of plan.items) {
275
+ const result = plan.commandExecutor(
276
+ item.command.executable,
277
+ item.command.args,
278
+ { cwd: item.command.cwd }
279
+ );
280
+ if (result.exitCode !== 0) {
281
+ return {
282
+ success: false,
283
+ changed,
284
+ diagnostics,
285
+ error: boundedCommandFailure(item, result)
286
+ };
287
+ }
288
+ changed.push(item.targetPath);
289
+ }
290
+ const inspection = inspectCodexManager(
291
+ plan.commandExecutor,
292
+ plan.projectRoot
293
+ );
294
+ diagnostics.push(...inspection.diagnostics);
295
+ if (inspection.marketplace !== "installed" || inspection.plugin !== "installed") {
296
+ return {
297
+ success: false,
298
+ changed,
299
+ diagnostics: uniqueMessages(diagnostics),
300
+ error: "Codex did not verify the expected marketplace and enabled plugin after mutation."
301
+ };
302
+ }
303
+ return { success: true, changed, diagnostics: uniqueMessages(diagnostics) };
304
+ }
305
+ function formatCodexPluginSetupPlan(plan) {
306
+ const lines = plan.items.map(
307
+ (item) => `- ${item.action}: ${item.command.executable} ${item.command.args.join(" ")}`
308
+ );
309
+ return ["Codex plugin setup plan:", ...lines].join("\n");
310
+ }
311
+
312
+ // src/cli/thoth-mem-install.ts
313
+ import { spawnSync as spawnSync2 } from "child_process";
78
314
  var THOTH_MEM_SETUP_TIMEOUT_MS = 12e4;
79
315
  var STATUS_EXIT_CODE = {
80
316
  complete: 0,
@@ -92,17 +328,17 @@ var STEP_OUTCOMES = /* @__PURE__ */ new Set([
92
328
  "failed",
93
329
  "unavailable"
94
330
  ]);
95
- function isRecord(value) {
331
+ function isRecord2(value) {
96
332
  return typeof value === "object" && value !== null && !Array.isArray(value);
97
333
  }
98
334
  function isStringArray(value) {
99
335
  return Array.isArray(value) && value.every((item) => typeof item === "string");
100
336
  }
101
337
  function isSetupStep(value) {
102
- return isRecord(value) && typeof value.name === "string" && value.name.length > 0 && typeof value.outcome === "string" && STEP_OUTCOMES.has(value.outcome);
338
+ return isRecord2(value) && typeof value.name === "string" && value.name.length > 0 && typeof value.outcome === "string" && STEP_OUTCOMES.has(value.outcome);
103
339
  }
104
340
  function isProviderSetupResult(value, expectedHarness) {
105
- return isRecord(value) && typeof value.status === "string" && SETUP_STATUSES.has(value.status) && typeof value.changed === "boolean" && value.harness === expectedHarness && value.scope === "global" && typeof value.target === "string" && value.target.length > 0 && Array.isArray(value.steps) && value.steps.every(isSetupStep) && isStringArray(value.diagnostics) && isStringArray(value.manual_actions) && (value.receipt === null || typeof value.receipt === "string");
341
+ return isRecord2(value) && typeof value.status === "string" && SETUP_STATUSES.has(value.status) && typeof value.changed === "boolean" && value.harness === expectedHarness && value.scope === "global" && typeof value.target === "string" && value.target.length > 0 && Array.isArray(value.steps) && value.steps.every(isSetupStep) && isStringArray(value.diagnostics) && isStringArray(value.manual_actions) && (value.receipt === null || typeof value.receipt === "string");
106
342
  }
107
343
  function parseProviderSetupResult(stdout, expectedHarness) {
108
344
  let value;
@@ -113,8 +349,8 @@ function parseProviderSetupResult(stdout, expectedHarness) {
113
349
  }
114
350
  return isProviderSetupResult(value, expectedHarness) ? value : void 0;
115
351
  }
116
- function defaultCommandExecutor(command, args, options) {
117
- const result = spawnSync(command, [...args], {
352
+ function defaultCommandExecutor2(command, args, options) {
353
+ const result = spawnSync2(command, [...args], {
118
354
  cwd: options.cwd,
119
355
  encoding: "utf8",
120
356
  stdio: ["ignore", "pipe", "pipe"],
@@ -131,7 +367,7 @@ function describeError(error) {
131
367
  return error instanceof Error ? error.message : String(error);
132
368
  }
133
369
  function isTimeoutError(error) {
134
- return isRecord(error) && error.code === "ETIMEDOUT";
370
+ return isRecord2(error) && error.code === "ETIMEDOUT";
135
371
  }
136
372
  function invalidResult(harness, command, args, exitCode, error) {
137
373
  return {
@@ -150,10 +386,9 @@ function invalidResult(harness, command, args, exitCode, error) {
150
386
  error
151
387
  };
152
388
  }
153
- function getThothMemSetupCommand(harness, dryRun) {
154
- return {
155
- command: "npx",
156
- args: [
389
+ function getThothMemSetupCommand(harness, dryRun, options = {}) {
390
+ return getNpxCommand(
391
+ [
157
392
  "-y",
158
393
  "thoth-mem@latest",
159
394
  "setup",
@@ -162,15 +397,16 @@ function getThothMemSetupCommand(harness, dryRun) {
162
397
  "global",
163
398
  ...dryRun ? ["--plan"] : [],
164
399
  "--json"
165
- ]
166
- };
400
+ ],
401
+ options
402
+ );
167
403
  }
168
404
  function runThothMemSetup(options) {
169
405
  const { command, args } = getThothMemSetupCommand(
170
406
  options.harness,
171
407
  options.dryRun ?? false
172
408
  );
173
- const executor = options.commandExecutor ?? defaultCommandExecutor;
409
+ const executor = options.commandExecutor ?? defaultCommandExecutor2;
174
410
  let commandResult;
175
411
  try {
176
412
  commandResult = executor(command, args, {
@@ -465,11 +701,23 @@ function createInstallConfig(args) {
465
701
  async function install(args, dependencies = {}) {
466
702
  const config = createInstallConfig(args);
467
703
  if (config.agent === "codex") {
704
+ const projectRoot = cwd();
705
+ const pluginPlan = buildCodexPluginSetupPlan({
706
+ dryRun: config.dryRun,
707
+ projectRoot
708
+ });
709
+ console.log(formatCodexPluginSetupPlan(pluginPlan));
710
+ const pluginResult = applyCodexPluginSetup(pluginPlan);
711
+ for (const diagnostic of pluginResult.diagnostics) printInfo(diagnostic);
712
+ if (!pluginResult.success) {
713
+ printError(`Codex plugin install failed: ${pluginResult.error}`);
714
+ return 1;
715
+ }
468
716
  const plan = buildCodexSetupPlan({
469
717
  dryRun: config.dryRun,
470
718
  reset: config.reset,
471
719
  scope: "user",
472
- projectRoot: cwd(),
720
+ projectRoot,
473
721
  homeDir: homedir()
474
722
  });
475
723
  console.log(formatCodexSetupPlan(plan));
@@ -484,7 +732,7 @@ async function install(args, dependencies = {}) {
484
732
  return 1;
485
733
  }
486
734
  printSuccess(
487
- config.dryRun ? "Codex dry-run complete; no files written" : "Codex agent-pack setup complete"
735
+ config.dryRun ? "Codex dry-run complete; no files written" : "Codex plugin installed as thoth-agents@thoth-agents and agent-pack setup complete (restart Codex to activate)"
488
736
  );
489
737
  return 0;
490
738
  }
@@ -0,0 +1,9 @@
1
+ export interface NpxCommandOptions {
2
+ platform?: NodeJS.Platform;
3
+ commandShell?: string;
4
+ }
5
+ export interface NpxCommand {
6
+ command: string;
7
+ args: string[];
8
+ }
9
+ export declare function getNpxCommand(args: readonly string[], options?: NpxCommandOptions): NpxCommand;
@@ -1,3 +1,4 @@
1
+ import { type NpxCommand, type NpxCommandOptions } from './npx-command';
1
2
  export type SkillInstallHarness = 'opencode' | 'codex' | 'claude';
2
3
  /** An external skill required by every supported thoth-agents harness. */
3
4
  export interface RequiredSkill {
@@ -14,16 +15,13 @@ export interface RequiredSkillInstallResult {
14
15
  skillPath: string;
15
16
  error?: unknown;
16
17
  }
17
- interface InstallRequiredSkillOptions {
18
+ interface InstallRequiredSkillOptions extends NpxCommandOptions {
18
19
  homeDir?: string;
19
20
  }
20
21
  export declare const REQUIRED_SKILLS: readonly RequiredSkill[];
21
22
  export declare function getRequiredSkillPath(skill: RequiredSkill, harness: SkillInstallHarness, homeDir?: string): string;
22
23
  export declare function isRequiredSkillInstalled(skill: RequiredSkill, harness: SkillInstallHarness, options?: InstallRequiredSkillOptions): boolean;
23
- export declare function getRequiredSkillInstallCommand(skill: RequiredSkill, harness: SkillInstallHarness): {
24
- command: 'npx';
25
- args: string[];
26
- };
24
+ export declare function getRequiredSkillInstallCommand(skill: RequiredSkill, harness: SkillInstallHarness, options?: NpxCommandOptions): NpxCommand;
27
25
  /** Install one mandatory skill into the selected harness's global skill root. */
28
26
  export declare function installRequiredSkill(skill: RequiredSkill, harness: SkillInstallHarness, options?: InstallRequiredSkillOptions): RequiredSkillInstallResult;
29
27
  export declare function installRequiredSkills(harness: SkillInstallHarness, options?: InstallRequiredSkillOptions): RequiredSkillInstallResult[];
@@ -1,3 +1,4 @@
1
+ import { type NpxCommand, type NpxCommandOptions } from './npx-command';
1
2
  import type { InstallAgent } from './types';
2
3
  export declare const THOTH_MEM_SETUP_TIMEOUT_MS = 120000;
3
4
  export type ThothMemSetupStatus = 'complete' | 'failed' | 'partial' | 'requires_user_action';
@@ -33,13 +34,10 @@ export interface ThothMemSetupResult {
33
34
  diagnostics: string[];
34
35
  manualActions: string[];
35
36
  receipt: string | null;
36
- command: 'npx';
37
+ command: string;
37
38
  args: string[];
38
39
  exitCode: number | null;
39
40
  error?: string;
40
41
  }
41
- export declare function getThothMemSetupCommand(harness: InstallAgent, dryRun: boolean): {
42
- command: 'npx';
43
- args: string[];
44
- };
42
+ export declare function getThothMemSetupCommand(harness: InstallAgent, dryRun: boolean, options?: NpxCommandOptions): NpxCommand;
45
43
  export declare function runThothMemSetup(options: ThothMemSetupOptions): ThothMemSetupResult;
@@ -2,7 +2,7 @@ import {
2
2
  defaultTuiOperations,
3
3
  effortChoicesForModel,
4
4
  listOperationHarnesses
5
- } from "../../chunk-2MZ5C2RN.js";
5
+ } from "../../chunk-UQOCEMU3.js";
6
6
  import "../../chunk-XO74DXBZ.js";
7
7
 
8
8
  // src/cli/tui/index.tsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thoth-agents",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Adaptive multi-harness orchestration with seven roles, runtime-autonomous Spec Kit-compatible SDD routes, and external provider boundaries.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thoth-agents",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Adaptive multi-harness agent pack with seven roles and a runtime-autonomous Spec Kit-compatible SDD bundle for Claude Code.",
5
5
  "author": {
6
6
  "name": "thoth-agents"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thoth-agents",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Bundled Spec Kit-compatible SDD skills and MCP configuration; the seven-role global Codex layer requires thoth-agents CLI setup.",
5
5
  "skills": "./skills/",
6
6
  "mcpServers": "./codex.mcp.json"