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.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +10 -15
- package/dist/{chunk-2MZ5C2RN.js → chunk-UQOCEMU3.js} +30 -11
- package/dist/cli/codex-plugin-install.d.ts +51 -0
- package/dist/cli/index.js +265 -17
- package/dist/cli/npx-command.d.ts +9 -0
- package/dist/cli/skills.d.ts +3 -5
- package/dist/cli/thoth-mem-install.d.ts +3 -5
- package/dist/cli/tui/index.js +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
|
@@ -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.
|
|
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
|
-
|
|
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
|
|
83
|
-
|
|
84
|
-
`~/.codex/
|
|
85
|
-
|
|
86
|
-
|
|
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 |
|
|
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
|
|
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
|
|
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
|
|
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
|
-
"
|
|
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
|
-
|
|
2531
|
-
|
|
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(
|
|
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-
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
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
|
|
117
|
-
const result =
|
|
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
|
|
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
|
-
|
|
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 ??
|
|
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
|
|
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;
|
package/dist/cli/skills.d.ts
CHANGED
|
@@ -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:
|
|
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;
|
package/dist/cli/tui/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thoth-agents",
|
|
3
|
-
"version": "0.3.
|
|
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.
|
|
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"
|