@manehorizons/cadence-host-codex 1.13.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.
- package/LICENSE +21 -0
- package/README.md +22 -0
- package/bin/cadence-host-codex.cjs +4 -0
- package/dist/capabilities.d.ts +11 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +26 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +119 -0
- package/dist/cli.js.map +1 -0
- package/dist/event-map.d.ts +19 -0
- package/dist/event-map.d.ts.map +1 -0
- package/dist/event-map.js +60 -0
- package/dist/event-map.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/install-commands.d.ts +27 -0
- package/dist/install-commands.d.ts.map +1 -0
- package/dist/install-commands.js +76 -0
- package/dist/install-commands.js.map +1 -0
- package/dist/install.d.ts +28 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +54 -0
- package/dist/install.js.map +1 -0
- package/dist/locate-self.d.ts +14 -0
- package/dist/locate-self.d.ts.map +1 -0
- package/dist/locate-self.js +18 -0
- package/dist/locate-self.js.map +1 -0
- package/dist/shim.d.ts +15 -0
- package/dist/shim.d.ts.map +1 -0
- package/dist/shim.js +43 -0
- package/dist/shim.js.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thomas Powers
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @manehorizons/cadence-host-codex
|
|
2
|
+
|
|
3
|
+
CADENCE host adapter for the OpenAI Codex CLI — the `cadence-host-codex` command
|
|
4
|
+
(hook install + slash-command prompts + event mapping).
|
|
5
|
+
|
|
6
|
+
Part of the [CADENCE](https://github.com/manehorizons/cadence) monorepo. MIT licensed.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# Install hooks into a project + the cadence slash commands (global prompts)
|
|
10
|
+
npx @manehorizons/cadence-host-codex install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`install` writes project-level hook config to `.codex/hooks.json` and the cadence
|
|
14
|
+
slash commands to the **global** Codex prompts dir (`$CODEX_HOME/prompts/`,
|
|
15
|
+
default `~/.codex/prompts/`) — Codex has no project-level prompt directory yet, so
|
|
16
|
+
the prompts apply to every project on the machine; the CLI warns accordingly. Use
|
|
17
|
+
`--no-commands` to skip them, or `--no-hooks` to skip the hook config.
|
|
18
|
+
|
|
19
|
+
The second conformance consumer of the CADENCE
|
|
20
|
+
[host-adapter contract](https://github.com/manehorizons/cadence/blob/main/docs/host-adapters.md);
|
|
21
|
+
see that guide for how the Codex adapter maps Codex's lifecycle onto the shared
|
|
22
|
+
engine.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HostCapabilities } from '@manehorizons/cadence-types';
|
|
2
|
+
/**
|
|
3
|
+
* What the OpenAI Codex CLI environment can do, per the phase-65 spike
|
|
4
|
+
* (FINDINGS §4). Codex's hook lifecycle is a near-clone of Claude Code's, so the
|
|
5
|
+
* mapped event set matches; the meaningful divergence is the command surface —
|
|
6
|
+
* Codex custom prompts are a real slash-command surface (`slashCommands: true`)
|
|
7
|
+
* but are install-global and deprecated in favor of "skills", so `skillSystem`
|
|
8
|
+
* is `'prompted'` (we ship prompts today; skills are the forward migration).
|
|
9
|
+
*/
|
|
10
|
+
export declare const codexCapabilities: HostCapabilities;
|
|
11
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,gBAgB/B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the OpenAI Codex CLI environment can do, per the phase-65 spike
|
|
3
|
+
* (FINDINGS §4). Codex's hook lifecycle is a near-clone of Claude Code's, so the
|
|
4
|
+
* mapped event set matches; the meaningful divergence is the command surface —
|
|
5
|
+
* Codex custom prompts are a real slash-command surface (`slashCommands: true`)
|
|
6
|
+
* but are install-global and deprecated in favor of "skills", so `skillSystem`
|
|
7
|
+
* is `'prompted'` (we ship prompts today; skills are the forward migration).
|
|
8
|
+
*/
|
|
9
|
+
export const codexCapabilities = {
|
|
10
|
+
hooks: [
|
|
11
|
+
'session-start',
|
|
12
|
+
'user-prompt',
|
|
13
|
+
'pre-tool-edit',
|
|
14
|
+
'post-tool-edit',
|
|
15
|
+
'session-stop',
|
|
16
|
+
'subagent-result',
|
|
17
|
+
],
|
|
18
|
+
slashCommands: true,
|
|
19
|
+
skillSystem: 'prompted',
|
|
20
|
+
// Codex denies a tool via exit-2 / permissionDecision:"deny" (PreToolUse) and
|
|
21
|
+
// can continue/block a turn end (Stop) — both are blocking points.
|
|
22
|
+
blockingHooks: ['pre-tool-edit', 'session-stop'],
|
|
23
|
+
subagentSpawn: 'native',
|
|
24
|
+
streamingOutput: true,
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAqB;IACjD,KAAK,EAAE;QACL,eAAe;QACf,aAAa;QACb,eAAe;QACf,gBAAgB;QAChB,cAAc;QACd,iBAAiB;KAClB;IACD,aAAa,EAAE,IAAI;IACnB,WAAW,EAAE,UAAU;IACvB,8EAA8E;IAC9E,mEAAmE;IACnE,aAAa,EAAE,CAAC,eAAe,EAAE,cAAc,CAAC;IAChD,aAAa,EAAE,QAAQ;IACvB,eAAe,EAAE,IAAI;CACtB,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { installHooks } from './install.js';
|
|
7
|
+
import { installCommands, resolveCodexHome } from './install-commands.js';
|
|
8
|
+
import { routeHookEvent } from './shim.js';
|
|
9
|
+
// Read the real version from package.json so `--version` never drifts.
|
|
10
|
+
const pkg = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '../package.json'), 'utf8'));
|
|
11
|
+
const program = new Command();
|
|
12
|
+
program.name('cadence-host-codex').description('OpenAI Codex CLI host adapter for CADENCE').version(pkg.version);
|
|
13
|
+
program
|
|
14
|
+
.command('install')
|
|
15
|
+
.description('Write Codex hook config (.codex/hooks.json) and global slash-command prompts')
|
|
16
|
+
.option('--cwd <dir>', 'project root', process.cwd())
|
|
17
|
+
.option('--command <cmd>', 'base command for the shim (default: "npx @manehorizons/cadence-host-codex hook")')
|
|
18
|
+
.option('--cadence <cmd>', 'base command the shim uses to invoke core (default: "npx @manehorizons/cadence-core")')
|
|
19
|
+
.option('--codex-home <dir>', 'Codex home dir for prompts (default: $CODEX_HOME or ~/.codex)')
|
|
20
|
+
.option('--no-hooks', 'skip writing .codex/hooks.json')
|
|
21
|
+
.option('--no-commands', 'skip writing slash-command prompts')
|
|
22
|
+
.option('--local', 'use absolute paths to the local workspace builds (monorepo dogfood)')
|
|
23
|
+
.action(async (opts) => {
|
|
24
|
+
try {
|
|
25
|
+
if (opts.hooks) {
|
|
26
|
+
const installOpts = {};
|
|
27
|
+
if (opts.command !== undefined)
|
|
28
|
+
installOpts.command = opts.command;
|
|
29
|
+
if (opts.cadence !== undefined)
|
|
30
|
+
installOpts.cadenceCommand = opts.cadence;
|
|
31
|
+
if (opts.local)
|
|
32
|
+
installOpts.local = true;
|
|
33
|
+
await installHooks(opts.cwd, installOpts);
|
|
34
|
+
process.stdout.write(`Installed CADENCE Codex hooks → ${opts.cwd}/.codex/hooks.json\n`);
|
|
35
|
+
}
|
|
36
|
+
if (opts.commands) {
|
|
37
|
+
const cmdOpts = {};
|
|
38
|
+
if (opts.cadence !== undefined)
|
|
39
|
+
cmdOpts.cadenceCommand = opts.cadence;
|
|
40
|
+
if (opts.codexHome !== undefined)
|
|
41
|
+
cmdOpts.codexHome = opts.codexHome;
|
|
42
|
+
if (opts.local)
|
|
43
|
+
cmdOpts.local = true;
|
|
44
|
+
const promptsDir = join(resolveCodexHome(opts.codexHome), 'prompts');
|
|
45
|
+
await installCommands(opts.cwd, cmdOpts);
|
|
46
|
+
process.stdout.write(`Installed CADENCE slash-command prompts → ${promptsDir}/\n`);
|
|
47
|
+
// Codex prompts are GLOBAL (no project-level dir yet — openai/codex#4734),
|
|
48
|
+
// so they affect every project on this machine. Always say so.
|
|
49
|
+
process.stderr.write(`warning: Codex slash-command prompts install GLOBALLY to ${promptsDir} and ` +
|
|
50
|
+
'apply to EVERY project on this machine (Codex has no project-level prompt ' +
|
|
51
|
+
'dir yet). Run `install --no-commands` to skip them.\n');
|
|
52
|
+
}
|
|
53
|
+
process.stdout.write('Approve the new hooks in Codex, then start a new session to activate.\n');
|
|
54
|
+
if (opts.local) {
|
|
55
|
+
const surfaces = [];
|
|
56
|
+
if (opts.hooks)
|
|
57
|
+
surfaces.push('.codex/hooks.json');
|
|
58
|
+
if (opts.commands)
|
|
59
|
+
surfaces.push(`${join(resolveCodexHome(opts.codexHome), 'prompts')}/cadence-*.md`);
|
|
60
|
+
if (surfaces.length > 0) {
|
|
61
|
+
process.stderr.write(`warning: --local wrote machine-absolute paths into ${surfaces.join(' and ')}. ` +
|
|
62
|
+
'Do NOT commit them — they cannot be resolved on other clones or machines. ' +
|
|
63
|
+
'Run plain `install` (no --local) for the portable `cadence` form.\n');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
process.stderr.write(`install failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
program
|
|
73
|
+
.command('hook')
|
|
74
|
+
.description('Shim invoked by Codex hooks: translates stdin and calls cadence hook <event>')
|
|
75
|
+
.option('--cadence <cmd>', 'base command to invoke core (default: "npx @manehorizons/cadence-core")', 'npx @manehorizons/cadence-core')
|
|
76
|
+
.action(async (opts) => {
|
|
77
|
+
try {
|
|
78
|
+
let raw = '';
|
|
79
|
+
if (!process.stdin.isTTY) {
|
|
80
|
+
for await (const chunk of process.stdin)
|
|
81
|
+
raw += chunk.toString();
|
|
82
|
+
}
|
|
83
|
+
const { abstractEvent, translatedStdin } = routeHookEvent(raw);
|
|
84
|
+
if (abstractEvent === null)
|
|
85
|
+
return; // exit 0 silently for unmapped events
|
|
86
|
+
const [exe, ...baseArgs] = opts.cadence.split(/\s+/).filter(Boolean);
|
|
87
|
+
if (!exe) {
|
|
88
|
+
process.stderr.write('--cadence command is empty\n');
|
|
89
|
+
process.exitCode = 1;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const child = spawn(exe, [...baseArgs, 'hook', abstractEvent], {
|
|
93
|
+
stdio: ['pipe', 'inherit', 'inherit'],
|
|
94
|
+
shell: process.platform === 'win32',
|
|
95
|
+
});
|
|
96
|
+
child.stdin.write(translatedStdin);
|
|
97
|
+
child.stdin.end();
|
|
98
|
+
await new Promise((resolve) => {
|
|
99
|
+
child.on('exit', (code) => {
|
|
100
|
+
process.exitCode = code ?? 0;
|
|
101
|
+
resolve();
|
|
102
|
+
});
|
|
103
|
+
child.on('error', (err) => {
|
|
104
|
+
process.stderr.write(`shim spawn failed: ${err.message}\n`);
|
|
105
|
+
process.exitCode = 1;
|
|
106
|
+
resolve();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
process.stderr.write(`hook shim failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
112
|
+
process.exitCode = 1;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
116
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AbstractEvent, ExtractedPayload } from '@manehorizons/cadence-types';
|
|
2
|
+
export type { ExtractedPayload };
|
|
3
|
+
/** Codex's edit tool. Unlike Claude (Edit/Write/…), all edits flow through one tool. */
|
|
4
|
+
export declare const EDIT_TOOL_MATCHER = "apply_patch";
|
|
5
|
+
/**
|
|
6
|
+
* Map a Codex CLI hook event name to its cadence abstract event, or null when
|
|
7
|
+
* unmapped (e.g. PreCompact/PostCompact/PermissionRequest/SubagentStart — the
|
|
8
|
+
* contract permits null for events cadence does not act on).
|
|
9
|
+
*/
|
|
10
|
+
export declare function mapEvent(codexEvent: string, _toolName?: string): AbstractEvent | null;
|
|
11
|
+
/**
|
|
12
|
+
* Extract the normalized payload from a Codex raw hook event. For `apply_patch`
|
|
13
|
+
* (Codex's sole edit tool) the patch envelope lives in `tool_input`, but the
|
|
14
|
+
* Codex docs are ambiguous about the exact field (`input` vs `command`), so we
|
|
15
|
+
* scan every string-valued field for the patch markers. Non-edit tools (Bash,
|
|
16
|
+
* MCP) and non-tool events yield undefined — matching the Claude adapter's shape.
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractPayload(raw: unknown): ExtractedPayload | undefined;
|
|
19
|
+
//# sourceMappingURL=event-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-map.d.ts","sourceRoot":"","sources":["../src/event-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAInF,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAW/C;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAErF;AAkBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAkBzE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Codex's edit tool. Unlike Claude (Edit/Write/…), all edits flow through one tool. */
|
|
2
|
+
export const EDIT_TOOL_MATCHER = 'apply_patch';
|
|
3
|
+
const EVENT_TABLE = {
|
|
4
|
+
SessionStart: 'session-start',
|
|
5
|
+
UserPromptSubmit: 'user-prompt',
|
|
6
|
+
PreToolUse: 'pre-tool-edit',
|
|
7
|
+
PostToolUse: 'post-tool-edit',
|
|
8
|
+
Stop: 'session-stop',
|
|
9
|
+
SubagentStop: 'subagent-result',
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Map a Codex CLI hook event name to its cadence abstract event, or null when
|
|
13
|
+
* unmapped (e.g. PreCompact/PostCompact/PermissionRequest/SubagentStart — the
|
|
14
|
+
* contract permits null for events cadence does not act on).
|
|
15
|
+
*/
|
|
16
|
+
export function mapEvent(codexEvent, _toolName) {
|
|
17
|
+
return EVENT_TABLE[codexEvent] ?? null;
|
|
18
|
+
}
|
|
19
|
+
// `*** Add File: <p>` / `*** Update File: <p>` / `*** Delete File: <p>` /
|
|
20
|
+
// `*** Move to: <p>` — the markers in OpenAI's apply_patch envelope. Each names
|
|
21
|
+
// a path the patch touches; for boundary checking we collect them all (a Move
|
|
22
|
+
// touches both its Update source and its destination).
|
|
23
|
+
const PATCH_MARKER = /^\*\*\* (?:Add File|Update File|Delete File|Move to):\s*(.+?)\s*$/;
|
|
24
|
+
/** Pull every touched path out of an apply_patch envelope string, in order. */
|
|
25
|
+
function pathsFromPatch(patch) {
|
|
26
|
+
const files = [];
|
|
27
|
+
for (const line of patch.split(/\r?\n/)) {
|
|
28
|
+
const m = PATCH_MARKER.exec(line);
|
|
29
|
+
if (m && m[1])
|
|
30
|
+
files.push(m[1]);
|
|
31
|
+
}
|
|
32
|
+
return files;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Extract the normalized payload from a Codex raw hook event. For `apply_patch`
|
|
36
|
+
* (Codex's sole edit tool) the patch envelope lives in `tool_input`, but the
|
|
37
|
+
* Codex docs are ambiguous about the exact field (`input` vs `command`), so we
|
|
38
|
+
* scan every string-valued field for the patch markers. Non-edit tools (Bash,
|
|
39
|
+
* MCP) and non-tool events yield undefined — matching the Claude adapter's shape.
|
|
40
|
+
*/
|
|
41
|
+
export function extractPayload(raw) {
|
|
42
|
+
if (!raw || typeof raw !== 'object')
|
|
43
|
+
return undefined;
|
|
44
|
+
const r = raw;
|
|
45
|
+
if (r.hook_event_name !== 'PreToolUse' && r.hook_event_name !== 'PostToolUse')
|
|
46
|
+
return undefined;
|
|
47
|
+
if (r.tool_name !== 'apply_patch')
|
|
48
|
+
return undefined;
|
|
49
|
+
if (!r.tool_input || typeof r.tool_input !== 'object')
|
|
50
|
+
return undefined;
|
|
51
|
+
for (const value of Object.values(r.tool_input)) {
|
|
52
|
+
if (typeof value === 'string' && value.includes('*** ')) {
|
|
53
|
+
const files = pathsFromPatch(value);
|
|
54
|
+
if (files.length > 0)
|
|
55
|
+
return { files };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=event-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-map.js","sourceRoot":"","sources":["../src/event-map.ts"],"names":[],"mappings":"AAMA,wFAAwF;AACxF,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAE/C,MAAM,WAAW,GAAkC;IACjD,YAAY,EAAE,eAAe;IAC7B,gBAAgB,EAAE,aAAa;IAC/B,UAAU,EAAE,eAAe;IAC3B,WAAW,EAAE,gBAAgB;IAC7B,IAAI,EAAE,cAAc;IACpB,YAAY,EAAE,iBAAiB;CAChC,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,UAAkB,EAAE,SAAkB;IAC7D,OAAO,WAAW,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC;AACzC,CAAC;AAED,0EAA0E;AAC1E,gFAAgF;AAChF,8EAA8E;AAC9E,uDAAuD;AACvD,MAAM,YAAY,GAAG,mEAAmE,CAAC;AAEzF,+EAA+E;AAC/E,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,GAAY;IACzC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACtD,MAAM,CAAC,GAAG,GAIT,CAAC;IACF,IAAI,CAAC,CAAC,eAAe,KAAK,YAAY,IAAI,CAAC,CAAC,eAAe,KAAK,aAAa;QAAE,OAAO,SAAS,CAAC;IAChG,IAAI,CAAC,CAAC,SAAS,KAAK,aAAa;QAAE,OAAO,SAAS,CAAC;IACpD,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAExE,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;QAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACxD,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;YACpC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACzC,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { mapEvent, extractPayload } from './event-map.js';
|
|
2
|
+
import { installHooks } from './install.js';
|
|
3
|
+
import { installCommands } from './install-commands.js';
|
|
4
|
+
export { mapEvent, extractPayload, EDIT_TOOL_MATCHER } from './event-map.js';
|
|
5
|
+
export type { ExtractedPayload } from './event-map.js';
|
|
6
|
+
export { routeHookEvent } from './shim.js';
|
|
7
|
+
export type { RouteResult } from './shim.js';
|
|
8
|
+
export { codexCapabilities } from './capabilities.js';
|
|
9
|
+
export type { HostCapabilities } from '@manehorizons/cadence-types';
|
|
10
|
+
export { ADAPTER_CONTRACT_VERSION } from '@manehorizons/cadence-types';
|
|
11
|
+
export type { HostAdapter } from '@manehorizons/cadence-types';
|
|
12
|
+
export { installHooks } from './install.js';
|
|
13
|
+
export type { InstallOptions } from './install.js';
|
|
14
|
+
export { installCommands } from './install-commands.js';
|
|
15
|
+
export type { InstallCommandsOptions } from './install-commands.js';
|
|
16
|
+
/**
|
|
17
|
+
* The OpenAI Codex CLI host adapter — the second consumer of the
|
|
18
|
+
* {@link HostAdapter} contract (phase 60), proving it is not Claude-Code-shaped.
|
|
19
|
+
* Capabilities + event translation + apply_patch payload extraction (phase 66),
|
|
20
|
+
* the install surface — project `.codex/hooks.json` + global `~/.codex/prompts/`
|
|
21
|
+
* (phase 67) — and the runtime `hook` shim (phase 68) are all wired here. Only
|
|
22
|
+
* the publish/docs remain (phase 69). The `satisfies` check is the compile-time
|
|
23
|
+
* conformance proof.
|
|
24
|
+
*/
|
|
25
|
+
export declare const codexAdapter: {
|
|
26
|
+
contractVersion: number;
|
|
27
|
+
capabilities: {
|
|
28
|
+
hooks: ("session-start" | "user-prompt" | "pre-tool-edit" | "post-tool-edit" | "session-stop" | "subagent-result" | "skill-invoke")[];
|
|
29
|
+
slashCommands: boolean;
|
|
30
|
+
skillSystem: "none" | "native" | "prompted";
|
|
31
|
+
blockingHooks: ("session-start" | "user-prompt" | "pre-tool-edit" | "post-tool-edit" | "session-stop" | "subagent-result" | "skill-invoke")[];
|
|
32
|
+
subagentSpawn: "none" | "native" | "shell-out";
|
|
33
|
+
streamingOutput: boolean;
|
|
34
|
+
};
|
|
35
|
+
mapEvent: typeof mapEvent;
|
|
36
|
+
extractPayload: typeof extractPayload;
|
|
37
|
+
installHooks: typeof installHooks;
|
|
38
|
+
installCommands: typeof installCommands;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE1D,OAAO,EAAE,YAAY,EAAuB,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAA+B,MAAM,uBAAuB,CAAC;AAErF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpE;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAOsC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ADAPTER_CONTRACT_VERSION } from '@manehorizons/cadence-types';
|
|
2
|
+
import { mapEvent, extractPayload } from './event-map.js';
|
|
3
|
+
import { codexCapabilities } from './capabilities.js';
|
|
4
|
+
import { installHooks } from './install.js';
|
|
5
|
+
import { installCommands } from './install-commands.js';
|
|
6
|
+
export { mapEvent, extractPayload, EDIT_TOOL_MATCHER } from './event-map.js';
|
|
7
|
+
export { routeHookEvent } from './shim.js';
|
|
8
|
+
export { codexCapabilities } from './capabilities.js';
|
|
9
|
+
export { ADAPTER_CONTRACT_VERSION } from '@manehorizons/cadence-types';
|
|
10
|
+
export { installHooks } from './install.js';
|
|
11
|
+
export { installCommands } from './install-commands.js';
|
|
12
|
+
/**
|
|
13
|
+
* The OpenAI Codex CLI host adapter — the second consumer of the
|
|
14
|
+
* {@link HostAdapter} contract (phase 60), proving it is not Claude-Code-shaped.
|
|
15
|
+
* Capabilities + event translation + apply_patch payload extraction (phase 66),
|
|
16
|
+
* the install surface — project `.codex/hooks.json` + global `~/.codex/prompts/`
|
|
17
|
+
* (phase 67) — and the runtime `hook` shim (phase 68) are all wired here. Only
|
|
18
|
+
* the publish/docs remain (phase 69). The `satisfies` check is the compile-time
|
|
19
|
+
* conformance proof.
|
|
20
|
+
*/
|
|
21
|
+
export const codexAdapter = {
|
|
22
|
+
contractVersion: ADAPTER_CONTRACT_VERSION,
|
|
23
|
+
capabilities: codexCapabilities,
|
|
24
|
+
mapEvent,
|
|
25
|
+
extractPayload,
|
|
26
|
+
installHooks,
|
|
27
|
+
installCommands,
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAoB,MAAM,6BAA6B,CAAC;AACzF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAuB,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAA+B,MAAM,uBAAuB,CAAC;AAErF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAE7E,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,eAAe,EAAE,wBAAwB;IACzC,YAAY,EAAE,iBAAiB;IAC/B,QAAQ;IACR,cAAc;IACd,YAAY;IACZ,eAAe;CAC8C,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface InstallCommandsOptions {
|
|
2
|
+
/** Base CLI invocation written into prompts. Default `cadence`. */
|
|
3
|
+
cadenceCommand?: string;
|
|
4
|
+
/**
|
|
5
|
+
* Codex home dir whose `prompts/` receives the files. Default
|
|
6
|
+
* `$CODEX_HOME` ?? `~/.codex`. Tests MUST pass a temp dir here — Codex
|
|
7
|
+
* prompts are GLOBAL, so a real install touches every project.
|
|
8
|
+
*/
|
|
9
|
+
codexHome?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Use the absolute workspace core CLI path instead of the `cadence`
|
|
12
|
+
* shorthand. Monorepo dogfood only — writes a machine-absolute path that must
|
|
13
|
+
* not be committed.
|
|
14
|
+
*/
|
|
15
|
+
local?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Resolve the Codex home dir: explicit override → $CODEX_HOME → ~/.codex. */
|
|
18
|
+
export declare function resolveCodexHome(override?: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Write the cadence slash commands as Codex custom prompts into
|
|
21
|
+
* `<codexHome>/prompts/cadence-*.md` (FINDINGS §1). Unlike the Claude adapter's
|
|
22
|
+
* project-scoped `.claude/commands/`, Codex has no project-level prompt dir yet
|
|
23
|
+
* (openai/codex#4734), so this is a GLOBAL install — the CLI warns accordingly.
|
|
24
|
+
* User-customized files (missing the managed marker) are left untouched.
|
|
25
|
+
*/
|
|
26
|
+
export declare function installCommands(_root: string, opts?: InstallCommandsOptions): Promise<void>;
|
|
27
|
+
//# sourceMappingURL=install-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-commands.d.ts","sourceRoot":"","sources":["../src/install-commands.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAoDD,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,sBAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBrG"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { resolveLocalPaths } from './locate-self.js';
|
|
5
|
+
const MANAGED_MARKER = '<!-- managed-by: cadence -->';
|
|
6
|
+
// The cadence slash-command catalog, rendered as Codex *prompts*. Same commands
|
|
7
|
+
// as the Claude adapter, but Codex prompts are prompt templates (no `!`-autorun,
|
|
8
|
+
// no `allowed-tools`), so the rendering differs. (Catalog duplication with the
|
|
9
|
+
// Claude adapter is deliberate for now; a shared catalog is a future cleanup.)
|
|
10
|
+
const COMMANDS = [
|
|
11
|
+
{ name: 'cadence-progress', description: "Show CADENCE's next suggested action", cli: 'progress', trailing: 'Read the output and take the suggested next step.' },
|
|
12
|
+
{ name: 'cadence-draft', description: 'Scaffold a new DRAFT.md for a phase task', argumentHint: '<phase-id> <task-num> [--title=<title>]', cli: 'draft new $ARGUMENTS', trailing: 'Open the new DRAFT.md and fill in summary, ACs, and tasks.' },
|
|
13
|
+
{ name: 'cadence-approve', description: 'Approve a draft and enter BUILD', argumentHint: '<phase-id> <task-num>', cli: 'draft approve $ARGUMENTS', trailing: 'Loop is now in BUILD. Use /cadence-build to record task outcomes.' },
|
|
14
|
+
{ name: 'cadence-check', description: 'Run structural coherence check on a draft', argumentHint: '<phase-id> <task-num>', cli: 'draft check $ARGUMENTS', trailing: 'Address any issues reported before approving the draft.' },
|
|
15
|
+
{ name: 'cadence-build', description: 'Record outcome of a build task', argumentHint: '<task-id> --status=<PASS|FAIL|BLOCKED|ESCALATED>', cli: 'build task $ARGUMENTS', trailing: 'Continue with the next task or run /cadence-settle when done.' },
|
|
16
|
+
{ name: 'cadence-settle', description: 'Close the loop and write SUMMARY', argumentHint: '[--ac AC-1=pass ...]', cli: 'settle run $ARGUMENTS', trailing: 'Review SUMMARY.md; loop is back to IDLE.' },
|
|
17
|
+
{ name: 'cadence-done', description: 'Mark a task DONE (shortcut for build task --status=DONE)', argumentHint: '<task-id> [--notes=<n>]', cli: 'done $ARGUMENTS', trailing: 'Continue with the next task or run /cadence-settle when done.' },
|
|
18
|
+
{ name: 'cadence-block', description: 'Mark a task BLOCKED (shortcut for build task --status=BLOCKED)', argumentHint: '<task-id> [--notes=<n>]', cli: 'block $ARGUMENTS', trailing: 'Record the blocker, then unblock or escalate before settling.' },
|
|
19
|
+
{ name: 'cadence-needs-context', description: 'Mark a task NEEDS_CONTEXT (shortcut for build task --status=NEEDS_CONTEXT)', argumentHint: '<task-id> [--notes=<n>]', cli: 'needs-context $ARGUMENTS', trailing: 'Supply the missing context, then re-run the task.' },
|
|
20
|
+
{ name: 'cadence-handoff', description: 'Scaffold a SESSION handoff doc with machine facts pre-filled', argumentHint: '[label]', cli: 'handoff $ARGUMENTS', trailing: 'Open the new SESSION doc and fill the narrative sections.' },
|
|
21
|
+
{ name: 'cadence-resume', description: 'Replay the freshest session handoff (brief by default; --full adds live context)', cli: 'resume', trailing: 'Read the replayed handoff and continue from the documented next action.' },
|
|
22
|
+
];
|
|
23
|
+
function renderFile(spec, cadenceCommand) {
|
|
24
|
+
const fm = ['---', `description: ${spec.description}`];
|
|
25
|
+
if (spec.argumentHint)
|
|
26
|
+
fm.push(`argument-hint: ${spec.argumentHint}`);
|
|
27
|
+
fm.push('---');
|
|
28
|
+
const lines = [
|
|
29
|
+
fm.join('\n'),
|
|
30
|
+
'',
|
|
31
|
+
MANAGED_MARKER,
|
|
32
|
+
'',
|
|
33
|
+
'Run the following command in the terminal and act on its output:',
|
|
34
|
+
'',
|
|
35
|
+
'```',
|
|
36
|
+
`${cadenceCommand} ${spec.cli}`.trimEnd(),
|
|
37
|
+
'```',
|
|
38
|
+
'',
|
|
39
|
+
];
|
|
40
|
+
if (spec.body)
|
|
41
|
+
lines.push(spec.body, '');
|
|
42
|
+
if (spec.trailing)
|
|
43
|
+
lines.push(spec.trailing, '');
|
|
44
|
+
return lines.join('\n');
|
|
45
|
+
}
|
|
46
|
+
/** Resolve the Codex home dir: explicit override → $CODEX_HOME → ~/.codex. */
|
|
47
|
+
export function resolveCodexHome(override) {
|
|
48
|
+
return override ?? process.env.CODEX_HOME ?? join(homedir(), '.codex');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Write the cadence slash commands as Codex custom prompts into
|
|
52
|
+
* `<codexHome>/prompts/cadence-*.md` (FINDINGS §1). Unlike the Claude adapter's
|
|
53
|
+
* project-scoped `.claude/commands/`, Codex has no project-level prompt dir yet
|
|
54
|
+
* (openai/codex#4734), so this is a GLOBAL install — the CLI warns accordingly.
|
|
55
|
+
* User-customized files (missing the managed marker) are left untouched.
|
|
56
|
+
*/
|
|
57
|
+
export async function installCommands(_root, opts = {}) {
|
|
58
|
+
const local = opts.local ? resolveLocalPaths() : null;
|
|
59
|
+
const cadenceCommand = opts.cadenceCommand ?? (local ? `node ${local.coreCli}` : 'cadence');
|
|
60
|
+
const dir = join(resolveCodexHome(opts.codexHome), 'prompts');
|
|
61
|
+
await mkdir(dir, { recursive: true });
|
|
62
|
+
for (const spec of COMMANDS) {
|
|
63
|
+
const path = join(dir, `${spec.name}.md`);
|
|
64
|
+
let existing = null;
|
|
65
|
+
try {
|
|
66
|
+
existing = await readFile(path, 'utf8');
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// missing — create fresh
|
|
70
|
+
}
|
|
71
|
+
if (existing !== null && !existing.includes(MANAGED_MARKER))
|
|
72
|
+
continue; // user-customized
|
|
73
|
+
await writeFile(path, renderFile(spec, cadenceCommand), 'utf8');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=install-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-commands.js","sourceRoot":"","sources":["../src/install-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAmBrD,MAAM,cAAc,GAAG,8BAA8B,CAAC;AAWtD,gFAAgF;AAChF,iFAAiF;AACjF,+EAA+E;AAC/E,+EAA+E;AAC/E,MAAM,QAAQ,GAAkB;IAC9B,EAAE,IAAI,EAAE,kBAAkB,EAAE,WAAW,EAAE,sCAAsC,EAAE,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,mDAAmD,EAAE;IACjK,EAAE,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,0CAA0C,EAAE,YAAY,EAAE,yCAAyC,EAAE,GAAG,EAAE,sBAAsB,EAAE,QAAQ,EAAE,4DAA4D,EAAE;IAChP,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,iCAAiC,EAAE,YAAY,EAAE,uBAAuB,EAAE,GAAG,EAAE,0BAA0B,EAAE,QAAQ,EAAE,mEAAmE,EAAE;IAClO,EAAE,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,2CAA2C,EAAE,YAAY,EAAE,uBAAuB,EAAE,GAAG,EAAE,wBAAwB,EAAE,QAAQ,EAAE,yDAAyD,EAAE;IAC9N,EAAE,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,gCAAgC,EAAE,YAAY,EAAE,kDAAkD,EAAE,GAAG,EAAE,uBAAuB,EAAE,QAAQ,EAAE,+DAA+D,EAAE;IACnP,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,EAAE,kCAAkC,EAAE,YAAY,EAAE,sBAAsB,EAAE,GAAG,EAAE,uBAAuB,EAAE,QAAQ,EAAE,0CAA0C,EAAE;IACrM,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,0DAA0D,EAAE,YAAY,EAAE,yBAAyB,EAAE,GAAG,EAAE,iBAAiB,EAAE,QAAQ,EAAE,+DAA+D,EAAE;IAC7O,EAAE,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,gEAAgE,EAAE,YAAY,EAAE,yBAAyB,EAAE,GAAG,EAAE,kBAAkB,EAAE,QAAQ,EAAE,+DAA+D,EAAE;IACrP,EAAE,IAAI,EAAE,uBAAuB,EAAE,WAAW,EAAE,4EAA4E,EAAE,YAAY,EAAE,yBAAyB,EAAE,GAAG,EAAE,0BAA0B,EAAE,QAAQ,EAAE,mDAAmD,EAAE;IACrQ,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,8DAA8D,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,oBAAoB,EAAE,QAAQ,EAAE,2DAA2D,EAAE;IACnO,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,EAAE,kFAAkF,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,yEAAyE,EAAE;CAChO,CAAC;AAEF,SAAS,UAAU,CAAC,IAAiB,EAAE,cAAsB;IAC3D,MAAM,EAAE,GAAa,CAAC,KAAK,EAAE,gBAAgB,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACjE,IAAI,IAAI,CAAC,YAAY;QAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;IACtE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACf,MAAM,KAAK,GAAG;QACZ,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;QACb,EAAE;QACF,cAAc;QACd,EAAE;QACF,kEAAkE;QAClE,EAAE;QACF,KAAK;QACL,GAAG,cAAc,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE;QACzC,KAAK;QACL,EAAE;KACH,CAAC;IACF,IAAI,IAAI,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACzC,IAAI,IAAI,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACjD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,gBAAgB,CAAC,QAAiB;IAChD,OAAO,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAa,EAAE,OAA+B,EAAE;IACpF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACtD,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC5F,MAAM,GAAG,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC;IAC9D,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC;QAC1C,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;QACD,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC;YAAE,SAAS,CAAC,kBAAkB;QACzF,MAAM,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface InstallOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Shim command Codex invokes for every hook event. The shim reads stdin,
|
|
4
|
+
* translates the payload, and spawns the core CLI.
|
|
5
|
+
* Default: `npx @manehorizons/cadence-host-codex hook`.
|
|
6
|
+
*/
|
|
7
|
+
command?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Base command the shim itself uses to invoke `@manehorizons/cadence-core`.
|
|
10
|
+
* If set, appended as `--cadence "<cmd>"`. Default: the shim's own default.
|
|
11
|
+
*/
|
|
12
|
+
cadenceCommand?: string;
|
|
13
|
+
/** Hook config path relative to root. Default `.codex/hooks.json`. */
|
|
14
|
+
hooksPath?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Use absolute paths to the local workspace builds instead of the `npx`
|
|
17
|
+
* defaults. Monorepo dogfood only — writes machine-absolute paths.
|
|
18
|
+
*/
|
|
19
|
+
local?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Write cadence-managed Codex hook entries into project-level
|
|
23
|
+
* `{root}/.codex/hooks.json` (FINDINGS §3). Idempotent: cadence-managed entries
|
|
24
|
+
* are replaced on re-install; user-authored entries on the same event are
|
|
25
|
+
* preserved. Hooks are project-scoped — unlike the global slash-command prompts.
|
|
26
|
+
*/
|
|
27
|
+
export declare function installHooks(root: string, opts?: InstallOptions): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAmBD;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyCzF"}
|
package/dist/install.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { EDIT_TOOL_MATCHER } from './event-map.js';
|
|
4
|
+
import { resolveLocalPaths } from './locate-self.js';
|
|
5
|
+
// Codex's apply_patch is the sole edit tool; the matcher is applied to
|
|
6
|
+
// `tool_name` for Pre/PostToolUse, anchored so it matches only apply_patch.
|
|
7
|
+
const PATCH_MATCHER = `^${EDIT_TOOL_MATCHER}$`;
|
|
8
|
+
const isCadenceEntry = (e) => e._managedBy === 'cadence';
|
|
9
|
+
/**
|
|
10
|
+
* Write cadence-managed Codex hook entries into project-level
|
|
11
|
+
* `{root}/.codex/hooks.json` (FINDINGS §3). Idempotent: cadence-managed entries
|
|
12
|
+
* are replaced on re-install; user-authored entries on the same event are
|
|
13
|
+
* preserved. Hooks are project-scoped — unlike the global slash-command prompts.
|
|
14
|
+
*/
|
|
15
|
+
export async function installHooks(root, opts = {}) {
|
|
16
|
+
const local = opts.local ? resolveLocalPaths() : null;
|
|
17
|
+
const base = opts.command ?? (local ? `node ${local.shimCli} hook` : 'npx @manehorizons/cadence-host-codex hook');
|
|
18
|
+
const cadenceCommand = opts.cadenceCommand ?? (local ? `node ${local.coreCli}` : undefined);
|
|
19
|
+
const command = cadenceCommand ? `${base} --cadence "${cadenceCommand}"` : base;
|
|
20
|
+
const hooksPath = join(root, opts.hooksPath ?? '.codex/hooks.json');
|
|
21
|
+
let current = {};
|
|
22
|
+
try {
|
|
23
|
+
current = JSON.parse(await readFile(hooksPath, 'utf8'));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// absent or malformed → start fresh
|
|
27
|
+
}
|
|
28
|
+
if (typeof current !== 'object' || current === null || Array.isArray(current))
|
|
29
|
+
current = {};
|
|
30
|
+
const plain = () => ({ hooks: [{ type: 'command', command }], _managedBy: 'cadence' });
|
|
31
|
+
const matched = (matcher) => ({
|
|
32
|
+
matcher,
|
|
33
|
+
hooks: [{ type: 'command', command }],
|
|
34
|
+
_managedBy: 'cadence',
|
|
35
|
+
});
|
|
36
|
+
const desired = {
|
|
37
|
+
SessionStart: [plain()],
|
|
38
|
+
UserPromptSubmit: [plain()],
|
|
39
|
+
PreToolUse: [matched(PATCH_MATCHER)],
|
|
40
|
+
PostToolUse: [matched(PATCH_MATCHER)],
|
|
41
|
+
Stop: [plain()],
|
|
42
|
+
SubagentStop: [plain()],
|
|
43
|
+
};
|
|
44
|
+
const hooks = current.hooks ?? {};
|
|
45
|
+
for (const [event, entries] of Object.entries(desired)) {
|
|
46
|
+
const kept = (hooks[event] ?? []).filter((e) => !isCadenceEntry(e));
|
|
47
|
+
kept.push(...entries);
|
|
48
|
+
hooks[event] = kept;
|
|
49
|
+
}
|
|
50
|
+
current.hooks = hooks;
|
|
51
|
+
await mkdir(dirname(hooksPath), { recursive: true });
|
|
52
|
+
await writeFile(hooksPath, JSON.stringify(current, null, 2) + '\n', 'utf8');
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface LocalPaths {
|
|
2
|
+
/** Absolute path to this adapter's compiled CLI entry (dist/cli.js). */
|
|
3
|
+
shimCli: string;
|
|
4
|
+
/** Absolute path to the workspace @manehorizons/cadence-core CLI entry (dist/cli/index.js). */
|
|
5
|
+
coreCli: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Resolve absolute paths to the local (workspace) builds of this adapter and
|
|
9
|
+
* `@manehorizons/cadence-core`. Works both at runtime (running from
|
|
10
|
+
* `packages/host-codex/dist/locate-self.js`) and under vitest (running from
|
|
11
|
+
* `packages/host-codex/src/locate-self.ts`). Mirrors the Claude adapter.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveLocalPaths(): LocalPaths;
|
|
14
|
+
//# sourceMappingURL=locate-self.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locate-self.d.ts","sourceRoot":"","sources":["../src/locate-self.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,+FAA+F;IAC/F,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,UAAU,CAQ9C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { basename, dirname, resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve absolute paths to the local (workspace) builds of this adapter and
|
|
5
|
+
* `@manehorizons/cadence-core`. Works both at runtime (running from
|
|
6
|
+
* `packages/host-codex/dist/locate-self.js`) and under vitest (running from
|
|
7
|
+
* `packages/host-codex/src/locate-self.ts`). Mirrors the Claude adapter.
|
|
8
|
+
*/
|
|
9
|
+
export function resolveLocalPaths() {
|
|
10
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const distDir = basename(here) === 'src' ? resolve(here, '..', 'dist') : here;
|
|
12
|
+
const adapterRoot = resolve(distDir, '..');
|
|
13
|
+
return {
|
|
14
|
+
shimCli: resolve(distDir, 'cli.js'),
|
|
15
|
+
coreCli: resolve(adapterRoot, '..', 'core', 'dist', 'cli', 'index.js'),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=locate-self.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locate-self.js","sourceRoot":"","sources":["../src/locate-self.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AASzC;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9E,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC3C,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC;QACnC,OAAO,EAAE,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC;KACvE,CAAC;AACJ,CAAC"}
|
package/dist/shim.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AbstractEvent } from '@manehorizons/cadence-types';
|
|
2
|
+
export interface RouteResult {
|
|
3
|
+
abstractEvent: AbstractEvent | null;
|
|
4
|
+
translatedStdin: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Translate one Codex stdin-JSON hook event into a cadence abstract event plus
|
|
8
|
+
* the stdin the core dispatcher should receive. Mirrors the Claude adapter's
|
|
9
|
+
* shim; the difference is Codex's sole edit tool (`apply_patch`) and the
|
|
10
|
+
* multi-file payload extraction. Unmapped events, malformed JSON, and
|
|
11
|
+
* Pre/PostToolUse for non-edit tools return `{ abstractEvent: null }` with the
|
|
12
|
+
* raw stdin passed through (the core never sees them).
|
|
13
|
+
*/
|
|
14
|
+
export declare function routeHookEvent(raw: string): RouteResult;
|
|
15
|
+
//# sourceMappingURL=shim.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shim.d.ts","sourceRoot":"","sources":["../src/shim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IACpC,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CA8BvD"}
|
package/dist/shim.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { extractPayload, mapEvent, EDIT_TOOL_MATCHER } from './event-map.js';
|
|
2
|
+
/**
|
|
3
|
+
* Translate one Codex stdin-JSON hook event into a cadence abstract event plus
|
|
4
|
+
* the stdin the core dispatcher should receive. Mirrors the Claude adapter's
|
|
5
|
+
* shim; the difference is Codex's sole edit tool (`apply_patch`) and the
|
|
6
|
+
* multi-file payload extraction. Unmapped events, malformed JSON, and
|
|
7
|
+
* Pre/PostToolUse for non-edit tools return `{ abstractEvent: null }` with the
|
|
8
|
+
* raw stdin passed through (the core never sees them).
|
|
9
|
+
*/
|
|
10
|
+
export function routeHookEvent(raw) {
|
|
11
|
+
let parsed;
|
|
12
|
+
try {
|
|
13
|
+
parsed = JSON.parse(raw);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return { abstractEvent: null, translatedStdin: raw };
|
|
17
|
+
}
|
|
18
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
19
|
+
return { abstractEvent: null, translatedStdin: raw };
|
|
20
|
+
}
|
|
21
|
+
const obj = parsed;
|
|
22
|
+
if (typeof obj.hook_event_name !== 'string') {
|
|
23
|
+
return { abstractEvent: null, translatedStdin: raw };
|
|
24
|
+
}
|
|
25
|
+
const toolName = typeof obj.tool_name === 'string' ? obj.tool_name : undefined;
|
|
26
|
+
const abstractEvent = mapEvent(obj.hook_event_name, toolName);
|
|
27
|
+
if (abstractEvent === null) {
|
|
28
|
+
return { abstractEvent: null, translatedStdin: raw };
|
|
29
|
+
}
|
|
30
|
+
// Defensive filter: the hooks.json matcher already restricts Pre/PostToolUse to
|
|
31
|
+
// apply_patch, but drop any non-apply_patch edit event that slips through.
|
|
32
|
+
if (abstractEvent === 'pre-tool-edit' || abstractEvent === 'post-tool-edit') {
|
|
33
|
+
if (toolName !== EDIT_TOOL_MATCHER) {
|
|
34
|
+
return { abstractEvent: null, translatedStdin: raw };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const extracted = extractPayload(parsed);
|
|
38
|
+
const translated = { ...parsed };
|
|
39
|
+
if (extracted?.files)
|
|
40
|
+
translated.files = extracted.files;
|
|
41
|
+
return { abstractEvent, translatedStdin: JSON.stringify(translated) };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=shim.js.map
|
package/dist/shim.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shim.js","sourceRoot":"","sources":["../src/shim.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAO7E;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC;IACvD,CAAC;IACD,MAAM,GAAG,GAAG,MAA4D,CAAC;IACzE,IAAI,OAAO,GAAG,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC;IACvD,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/E,MAAM,aAAa,GAAG,QAAQ,CAAC,GAAG,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IAC9D,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3B,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC;IACvD,CAAC;IACD,gFAAgF;IAChF,2EAA2E;IAC3E,IAAI,aAAa,KAAK,eAAe,IAAI,aAAa,KAAK,gBAAgB,EAAE,CAAC;QAC5E,IAAI,QAAQ,KAAK,iBAAiB,EAAE,CAAC;YACnC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC;QACvD,CAAC;IACH,CAAC;IACD,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,UAAU,GAA4B,EAAE,GAAI,MAAkC,EAAE,CAAC;IACvF,IAAI,SAAS,EAAE,KAAK;QAAE,UAAU,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC;IACzD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;AACxE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@manehorizons/cadence-host-codex",
|
|
3
|
+
"version": "1.13.0",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=20"
|
|
6
|
+
},
|
|
7
|
+
"description": "OpenAI Codex CLI adapter for CADENCE — installs lifecycle hooks and slash commands that drive the CADENCE engine from inside Codex.",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"author": "Thomas Powers",
|
|
10
|
+
"homepage": "https://github.com/manehorizons/cadence#readme",
|
|
11
|
+
"bugs": "https://github.com/manehorizons/cadence/issues",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"cadence",
|
|
14
|
+
"codex",
|
|
15
|
+
"openai-codex",
|
|
16
|
+
"ai",
|
|
17
|
+
"agents",
|
|
18
|
+
"hooks",
|
|
19
|
+
"slash-commands"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "./dist/index.js",
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"import": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"bin": {
|
|
31
|
+
"cadence-host-codex": "./bin/cadence-host-codex.cjs"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"bin",
|
|
36
|
+
"!dist/tsconfig.tsbuildinfo"
|
|
37
|
+
],
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/manehorizons/cadence.git",
|
|
44
|
+
"directory": "packages/host-codex"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"commander": "^14.0.0",
|
|
48
|
+
"@manehorizons/cadence-core": "1.13.0",
|
|
49
|
+
"@manehorizons/cadence-types": "1.13.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"vitest": "^2.1.0",
|
|
53
|
+
"@manehorizons/cadence-testkit": "1.4.0"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsc -p tsconfig.json",
|
|
57
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"lint": "eslint src",
|
|
60
|
+
"clean": "rm -rf dist .turbo"
|
|
61
|
+
}
|
|
62
|
+
}
|