@nurix/etna 0.19.22 → 0.19.23
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/README.md +6 -5
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/CLAUDE.md +10 -0
- package/data/harnesses/code/agents/brainstorm.md +11 -11
- package/data/harnesses/code/agents/change-review.md +4 -4
- package/data/harnesses/code/agents/maintenance.md +2 -1
- package/data/harnesses/code/agents/retro.md +45 -0
- package/data/harnesses/code/codex/agents/brainstorm.toml +11 -11
- package/data/harnesses/code/codex/agents/change-review.toml +4 -5
- package/data/harnesses/code/codex/agents/maintenance.toml +2 -1
- package/data/harnesses/code/codex/agents/retro.toml +43 -0
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/skills/documentation/SKILL.md +1 -0
- package/data/harnesses/code/skills/documentation/templates/refinement-ledger.md +33 -0
- package/data/harnesses/code/skills/documentation/templates/structure.md +2 -0
- package/data/harnesses/etna/CLAUDE.md +2 -0
- package/data/harnesses/etna/agents/brainstorm.md +11 -11
- package/data/harnesses/etna/agents/change-review.md +4 -4
- package/data/harnesses/etna/agents/maintenance.md +2 -1
- package/data/harnesses/etna/codex/agents/brainstorm.toml +11 -11
- package/data/harnesses/etna/codex/agents/change-review.toml +4 -5
- package/data/harnesses/etna/codex/agents/maintenance.toml +2 -1
- package/data/harnesses/etna/harness.json +2 -2
- package/data/harnesses/etna/skills/documentation/SKILL.md +1 -0
- package/data/harnesses/etna/skills/documentation/templates/refinement-ledger.md +33 -0
- package/data/harnesses/etna/skills/documentation/templates/structure.md +2 -0
- package/data/harnesses/hr/harness.json +1 -1
- package/lib/codex/README.md +17 -7
- package/lib/codex/agents-md.mjs +85 -6
- package/lib/codex/hooks.mjs +25 -1
- package/lib/codex/index.mjs +4 -3
- package/lib/codex/plugin-manifest.mjs +9 -3
- package/lib/codex/subagents.mjs +2 -2
- package/lib/codex/validate-codex-agents.mjs +126 -0
- package/package.json +2 -2
- package/lib/codex/gen-agents.mjs +0 -157
package/lib/codex/gen-agents.mjs
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
// packages/cli/lib/codex/gen-agents.mjs
|
|
2
|
-
// AUTHORING-TIME generator — runs ON A LAPTOP with the Codex CLI installed and
|
|
3
|
-
// authenticated, NEVER in CI. For each Claude subagent (agents/<name>.md in the
|
|
4
|
-
// shared catalog, plus harness/*/agents/*.md with --include-harness) it runs
|
|
5
|
-
// `codex exec` to translate the markdown into an OpenAI Codex subagent TOML and
|
|
6
|
-
// writes a committed sibling agents/<name>.codex.toml. The shippers (build-data.js,
|
|
7
|
-
// publish.mjs) then carry those committed files; the installer copies them into a
|
|
8
|
-
// consumer's .codex/agents/ with no Codex CLI required downstream.
|
|
9
|
-
//
|
|
10
|
-
// Usage:
|
|
11
|
-
// node packages/cli/lib/codex/gen-agents.mjs # shared catalog, only stale/missing
|
|
12
|
-
// node packages/cli/lib/codex/gen-agents.mjs --force # regenerate all shared agents
|
|
13
|
-
// node packages/cli/lib/codex/gen-agents.mjs --include-harness # + harness/*/agents/*.md
|
|
14
|
-
|
|
15
|
-
import {
|
|
16
|
-
existsSync,
|
|
17
|
-
readdirSync,
|
|
18
|
-
readFileSync,
|
|
19
|
-
writeFileSync,
|
|
20
|
-
statSync,
|
|
21
|
-
} from 'node:fs';
|
|
22
|
-
import { dirname, join, resolve, basename } from 'node:path';
|
|
23
|
-
import { fileURLToPath } from 'node:url';
|
|
24
|
-
import { spawnSync } from 'node:child_process';
|
|
25
|
-
|
|
26
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
27
|
-
const repoRoot = resolve(__dirname, '..', '..', '..', '..');
|
|
28
|
-
|
|
29
|
-
// Pinned conversion prompt — deterministic instructions so re-runs stay stable.
|
|
30
|
-
// Codex does the semantic md→toml; the body is copied verbatim, tools are dropped
|
|
31
|
-
// (no Codex equivalent) and recorded in a leading comment.
|
|
32
|
-
const CONVERSION_PROMPT = [
|
|
33
|
-
'Convert the Claude Code subagent definition provided on stdin into an OpenAI Codex subagent TOML document.',
|
|
34
|
-
'Output ONLY the raw TOML — no prose, no markdown code fences, nothing before or after.',
|
|
35
|
-
'Set `name` from the frontmatter `name`.',
|
|
36
|
-
'Set `description` as a TOML basic string (double quotes) from the frontmatter `description`, escaping any interior double-quote as \\".',
|
|
37
|
-
'Put the ENTIRE markdown body (everything after the closing frontmatter ---) VERBATIM into a TOML multi-line',
|
|
38
|
-
"LITERAL string delimited by triple SINGLE quotes: developer_instructions = '''<body>'''.",
|
|
39
|
-
'A literal string is verbatim — do NOT escape anything inside it, and do NOT use triple double-quotes (backslashes like \\s in the body must survive unchanged).',
|
|
40
|
-
'If frontmatter `model` is a real model id, set `model`; if it is `inherit`, omit `model`.',
|
|
41
|
-
'If frontmatter has a `tools:` line, do NOT translate it — instead put a single comment line',
|
|
42
|
-
'`# dropped Claude tools: <the list>` as the first line of the file.',
|
|
43
|
-
'Emit no keys other than name, description, model (optional), developer_instructions.',
|
|
44
|
-
].join(' ');
|
|
45
|
-
|
|
46
|
-
const args = process.argv.slice(2);
|
|
47
|
-
const force = args.includes('--force');
|
|
48
|
-
const includeHarness = args.includes('--include-harness');
|
|
49
|
-
|
|
50
|
-
function die(msg) {
|
|
51
|
-
console.error(`gen-codex-agents: ${msg}`);
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Codex must be present + authenticated — this step cannot run in CI.
|
|
56
|
-
function assertCodexReady() {
|
|
57
|
-
const which = spawnSync('codex', ['--version'], { encoding: 'utf8' });
|
|
58
|
-
if (which.status !== 0) {
|
|
59
|
-
die('the `codex` CLI is not installed / not on PATH. This generator runs only on an authoring laptop.');
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Every agents/<name>.md to convert: the shared catalog, plus harness-owned agents on request.
|
|
64
|
-
function collectAgentFiles() {
|
|
65
|
-
const files = [];
|
|
66
|
-
const shared = join(repoRoot, 'agents');
|
|
67
|
-
if (existsSync(shared)) {
|
|
68
|
-
for (const f of readdirSync(shared)) {
|
|
69
|
-
if (f.endsWith('.md')) files.push(join(shared, f));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (includeHarness) {
|
|
73
|
-
const harnessDir = join(repoRoot, 'harness');
|
|
74
|
-
if (existsSync(harnessDir)) {
|
|
75
|
-
for (const harness of readdirSync(harnessDir)) {
|
|
76
|
-
if (harness === 'common') continue; // not a harness — the shared root-files folder
|
|
77
|
-
const agentsDir = join(harnessDir, harness, 'agents');
|
|
78
|
-
if (!existsSync(agentsDir)) continue;
|
|
79
|
-
for (const f of readdirSync(agentsDir)) {
|
|
80
|
-
if (f.endsWith('.md')) files.push(join(agentsDir, f));
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return files.sort();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// A regen is due when forced, the toml is missing, or the md is newer than the toml.
|
|
89
|
-
function needsRegen(mdPath, tomlPath) {
|
|
90
|
-
if (force || !existsSync(tomlPath)) return true;
|
|
91
|
-
return statSync(mdPath).mtimeMs > statSync(tomlPath).mtimeMs;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Strip an accidental ```toml fence if the model wrapped its output despite the prompt.
|
|
95
|
-
function stripFences(text) {
|
|
96
|
-
const trimmed = text.trim();
|
|
97
|
-
const fence = trimmed.match(/^```(?:toml)?\n([\s\S]*?)\n```$/);
|
|
98
|
-
return (fence ? fence[1] : trimmed) + '\n';
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Validate that the produced TOML parses. Uses python3's tomllib when present
|
|
102
|
-
// (returns true/error string); returns null when python3 is unavailable so the
|
|
103
|
-
// caller proceeds best-effort rather than hard-failing on a missing dev tool.
|
|
104
|
-
function tomlError(toml) {
|
|
105
|
-
const res = spawnSync('python3', ['-c', 'import tomllib,sys; tomllib.loads(sys.stdin.read())'], {
|
|
106
|
-
input: toml,
|
|
107
|
-
encoding: 'utf8',
|
|
108
|
-
});
|
|
109
|
-
if (res.error && res.error.code === 'ENOENT') return null;
|
|
110
|
-
return res.status === 0 ? '' : (res.stderr || 'invalid TOML').trim();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function convert(mdPath) {
|
|
114
|
-
const md = readFileSync(mdPath, 'utf8');
|
|
115
|
-
const res = spawnSync('codex', ['exec', '--sandbox', 'read-only', CONVERSION_PROMPT], {
|
|
116
|
-
input: md,
|
|
117
|
-
encoding: 'utf8',
|
|
118
|
-
maxBuffer: 32 * 1024 * 1024,
|
|
119
|
-
});
|
|
120
|
-
if (res.status !== 0) {
|
|
121
|
-
throw new Error(`codex exec failed for ${mdPath}: ${(res.stderr || '').slice(-400)}`);
|
|
122
|
-
}
|
|
123
|
-
const toml = stripFences(res.stdout || '');
|
|
124
|
-
if (!/^\s*name\s*=/m.test(toml)) {
|
|
125
|
-
throw new Error(`codex output for ${mdPath} has no \`name =\` key — refusing to write. Got:\n${toml.slice(0, 200)}`);
|
|
126
|
-
}
|
|
127
|
-
const err = tomlError(toml);
|
|
128
|
-
if (err) {
|
|
129
|
-
throw new Error(`codex output for ${mdPath} is not valid TOML — refusing to write:\n${err.slice(0, 300)}`);
|
|
130
|
-
}
|
|
131
|
-
return toml;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
assertCodexReady();
|
|
135
|
-
const files = collectAgentFiles();
|
|
136
|
-
if (!files.length) die('no agents/*.md found to convert.');
|
|
137
|
-
|
|
138
|
-
let wrote = 0;
|
|
139
|
-
let skipped = 0;
|
|
140
|
-
for (const mdPath of files) {
|
|
141
|
-
const name = basename(mdPath, '.md');
|
|
142
|
-
const tomlPath = join(dirname(mdPath), `${name}.codex.toml`);
|
|
143
|
-
if (!needsRegen(mdPath, tomlPath)) {
|
|
144
|
-
skipped += 1;
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
process.stdout.write(`converting ${name} … `);
|
|
148
|
-
try {
|
|
149
|
-
writeFileSync(tomlPath, convert(mdPath));
|
|
150
|
-
wrote += 1;
|
|
151
|
-
console.log('ok');
|
|
152
|
-
} catch (e) {
|
|
153
|
-
console.log('FAILED');
|
|
154
|
-
console.error(` ${e.message}`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
console.log(`\ngen-codex-agents: wrote ${wrote}, skipped ${skipped} (up-to-date) of ${files.length} agent(s).`);
|