@nocville/npc 0.0.0-stage → 0.2.1
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 +268 -2
- package/dist/cjs/cli.js +584 -0
- package/dist/cjs/core/api-key.js +69 -0
- package/dist/cjs/core/base-npc.js +160 -0
- package/dist/cjs/core/config.js +108 -0
- package/dist/cjs/core/event-npc.js +14 -0
- package/dist/cjs/core/logger.js +39 -0
- package/dist/cjs/core/polling-npc.js +65 -0
- package/dist/cjs/core/screen.js +28 -0
- package/dist/cjs/core/session-filter.js +150 -0
- package/dist/cjs/core/text.js +15 -0
- package/dist/cjs/core/thresholds.js +48 -0
- package/dist/cjs/core/types.js +10 -0
- package/dist/cjs/core/user-config.js +92 -0
- package/dist/cjs/doctor.js +130 -0
- package/dist/cjs/index.js +95 -0
- package/dist/cjs/npcs/agent-common/activity.js +291 -0
- package/dist/cjs/npcs/agent-common/git-stats.js +71 -0
- package/dist/cjs/npcs/agent-common/hook-runner.js +252 -0
- package/dist/cjs/npcs/agent-common/hook-settings.js +279 -0
- package/dist/cjs/npcs/agent-common/liveness.js +112 -0
- package/dist/cjs/npcs/agent-common/lock.js +99 -0
- package/dist/cjs/npcs/agent-common/runtime.js +154 -0
- package/dist/cjs/npcs/agent-common/session.js +412 -0
- package/dist/cjs/npcs/agent-common/shim.js +96 -0
- package/dist/cjs/npcs/agent-common/watchdog.js +149 -0
- package/dist/cjs/npcs/claude-code/defaults.js +20 -0
- package/dist/cjs/npcs/claude-code/hook-handler.js +139 -0
- package/dist/cjs/npcs/claude-code/index.js +104 -0
- package/dist/cjs/npcs/claude-code/setup.js +133 -0
- package/dist/cjs/npcs/claude-code/state-machine.js +130 -0
- package/dist/cjs/npcs/codex/defaults.js +32 -0
- package/dist/cjs/npcs/codex/hook-handler.js +116 -0
- package/dist/cjs/npcs/codex/index.js +92 -0
- package/dist/cjs/npcs/codex/rollout.js +246 -0
- package/dist/cjs/npcs/codex/setup.js +104 -0
- package/dist/cjs/npcs/codex/watcher.js +361 -0
- package/dist/cjs/npcs/cursor/defaults.js +15 -0
- package/dist/cjs/npcs/cursor/hook-handler.js +65 -0
- package/dist/cjs/npcs/cursor/index.js +72 -0
- package/dist/cjs/npcs/cursor/normalize.js +54 -0
- package/dist/cjs/npcs/cursor/setup.js +98 -0
- package/dist/cjs/npcs/gemini/defaults.js +15 -0
- package/dist/cjs/npcs/gemini/hook-handler.js +93 -0
- package/dist/cjs/npcs/gemini/index.js +69 -0
- package/dist/cjs/npcs/gemini/setup.js +98 -0
- package/dist/cjs/npcs/github-watcher/defaults.js +11 -0
- package/dist/cjs/npcs/github-watcher/format.js +21 -0
- package/dist/cjs/npcs/github-watcher/github-api.js +126 -0
- package/dist/cjs/npcs/github-watcher/index.js +148 -0
- package/dist/cjs/npcs/internet-connectivity/checks.js +92 -0
- package/dist/cjs/npcs/internet-connectivity/defaults.js +22 -0
- package/dist/cjs/npcs/internet-connectivity/index.js +251 -0
- package/dist/cjs/npcs/log-watcher/buffer.js +40 -0
- package/dist/cjs/npcs/log-watcher/defaults.js +12 -0
- package/dist/cjs/npcs/log-watcher/index.js +161 -0
- package/dist/cjs/npcs/log-watcher/tail.js +81 -0
- package/dist/cjs/npcs/process-watcher/defaults.js +9 -0
- package/dist/cjs/npcs/process-watcher/index.js +140 -0
- package/dist/cjs/npcs/process-watcher/process-scanner.js +114 -0
- package/dist/cjs/npcs/receptionist/defaults.js +9 -0
- package/dist/cjs/npcs/receptionist/index.js +120 -0
- package/dist/cjs/npcs/receptionist/weather.js +129 -0
- package/dist/cjs/npcs/system-monitor/collectors.js +68 -0
- package/dist/cjs/npcs/system-monitor/defaults.js +13 -0
- package/dist/cjs/npcs/system-monitor/index.js +105 -0
- package/dist/cjs/npcs/web-page-watcher/basic-mode.js +58 -0
- package/dist/cjs/npcs/web-page-watcher/capture.js +80 -0
- package/dist/cjs/npcs/web-page-watcher/defaults.js +31 -0
- package/dist/cjs/npcs/web-page-watcher/index.js +234 -0
- package/dist/cjs/npcs/web-page-watcher/pixelate.js +181 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +549 -0
- package/dist/core/api-key.d.ts +34 -0
- package/dist/core/api-key.js +64 -0
- package/dist/core/base-npc.d.ts +41 -0
- package/dist/core/base-npc.js +156 -0
- package/dist/core/config.d.ts +22 -0
- package/dist/core/config.js +101 -0
- package/dist/core/event-npc.d.ts +8 -0
- package/dist/core/event-npc.js +10 -0
- package/dist/core/logger.d.ts +11 -0
- package/dist/core/logger.js +35 -0
- package/dist/core/polling-npc.d.ts +18 -0
- package/dist/core/polling-npc.js +61 -0
- package/dist/core/screen.d.ts +11 -0
- package/dist/core/screen.js +24 -0
- package/dist/core/session-filter.d.ts +59 -0
- package/dist/core/session-filter.js +143 -0
- package/dist/core/text.d.ts +6 -0
- package/dist/core/text.js +12 -0
- package/dist/core/thresholds.d.ts +10 -0
- package/dist/core/thresholds.js +44 -0
- package/dist/core/types.d.ts +60 -0
- package/dist/core/types.js +7 -0
- package/dist/core/user-config.d.ts +43 -0
- package/dist/core/user-config.js +85 -0
- package/dist/doctor.d.ts +8 -0
- package/dist/doctor.js +126 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +26 -0
- package/dist/npcs/agent-common/activity.d.ts +42 -0
- package/dist/npcs/agent-common/activity.js +280 -0
- package/dist/npcs/agent-common/git-stats.d.ts +11 -0
- package/dist/npcs/agent-common/git-stats.js +67 -0
- package/dist/npcs/agent-common/hook-runner.d.ts +62 -0
- package/dist/npcs/agent-common/hook-runner.js +245 -0
- package/dist/npcs/agent-common/hook-settings.d.ts +75 -0
- package/dist/npcs/agent-common/hook-settings.js +265 -0
- package/dist/npcs/agent-common/liveness.d.ts +12 -0
- package/dist/npcs/agent-common/liveness.js +105 -0
- package/dist/npcs/agent-common/lock.d.ts +6 -0
- package/dist/npcs/agent-common/lock.js +95 -0
- package/dist/npcs/agent-common/runtime.d.ts +16 -0
- package/dist/npcs/agent-common/runtime.js +149 -0
- package/dist/npcs/agent-common/session.d.ts +192 -0
- package/dist/npcs/agent-common/session.js +390 -0
- package/dist/npcs/agent-common/shim.d.ts +4 -0
- package/dist/npcs/agent-common/shim.js +90 -0
- package/dist/npcs/agent-common/watchdog.d.ts +16 -0
- package/dist/npcs/agent-common/watchdog.js +144 -0
- package/dist/npcs/claude-code/defaults.d.ts +15 -0
- package/dist/npcs/claude-code/defaults.js +17 -0
- package/dist/npcs/claude-code/hook-handler.d.ts +40 -0
- package/dist/npcs/claude-code/hook-handler.js +131 -0
- package/dist/npcs/claude-code/index.d.ts +36 -0
- package/dist/npcs/claude-code/index.js +92 -0
- package/dist/npcs/claude-code/setup.d.ts +58 -0
- package/dist/npcs/claude-code/setup.js +121 -0
- package/dist/npcs/claude-code/state-machine.d.ts +28 -0
- package/dist/npcs/claude-code/state-machine.js +125 -0
- package/dist/npcs/codex/defaults.d.ts +24 -0
- package/dist/npcs/codex/defaults.js +28 -0
- package/dist/npcs/codex/hook-handler.d.ts +24 -0
- package/dist/npcs/codex/hook-handler.js +110 -0
- package/dist/npcs/codex/index.d.ts +21 -0
- package/dist/npcs/codex/index.js +76 -0
- package/dist/npcs/codex/rollout.d.ts +39 -0
- package/dist/npcs/codex/rollout.js +242 -0
- package/dist/npcs/codex/setup.d.ts +37 -0
- package/dist/npcs/codex/setup.js +96 -0
- package/dist/npcs/codex/watcher.d.ts +65 -0
- package/dist/npcs/codex/watcher.js +356 -0
- package/dist/npcs/cursor/defaults.d.ts +9 -0
- package/dist/npcs/cursor/defaults.js +11 -0
- package/dist/npcs/cursor/hook-handler.d.ts +8 -0
- package/dist/npcs/cursor/hook-handler.js +60 -0
- package/dist/npcs/cursor/index.d.ts +18 -0
- package/dist/npcs/cursor/index.js +57 -0
- package/dist/npcs/cursor/normalize.d.ts +6 -0
- package/dist/npcs/cursor/normalize.js +49 -0
- package/dist/npcs/cursor/setup.d.ts +29 -0
- package/dist/npcs/cursor/setup.js +90 -0
- package/dist/npcs/gemini/defaults.d.ts +9 -0
- package/dist/npcs/gemini/defaults.js +11 -0
- package/dist/npcs/gemini/hook-handler.d.ts +10 -0
- package/dist/npcs/gemini/hook-handler.js +87 -0
- package/dist/npcs/gemini/index.d.ts +17 -0
- package/dist/npcs/gemini/index.js +56 -0
- package/dist/npcs/gemini/setup.d.ts +29 -0
- package/dist/npcs/gemini/setup.js +90 -0
- package/dist/npcs/github-watcher/defaults.d.ts +8 -0
- package/dist/npcs/github-watcher/defaults.js +8 -0
- package/dist/npcs/github-watcher/format.d.ts +3 -0
- package/dist/npcs/github-watcher/format.js +18 -0
- package/dist/npcs/github-watcher/github-api.d.ts +55 -0
- package/dist/npcs/github-watcher/github-api.js +120 -0
- package/dist/npcs/github-watcher/index.d.ts +35 -0
- package/dist/npcs/github-watcher/index.js +144 -0
- package/dist/npcs/internet-connectivity/checks.d.ts +24 -0
- package/dist/npcs/internet-connectivity/checks.js +84 -0
- package/dist/npcs/internet-connectivity/defaults.d.ts +20 -0
- package/dist/npcs/internet-connectivity/defaults.js +19 -0
- package/dist/npcs/internet-connectivity/index.d.ts +55 -0
- package/dist/npcs/internet-connectivity/index.js +246 -0
- package/dist/npcs/log-watcher/buffer.d.ts +18 -0
- package/dist/npcs/log-watcher/buffer.js +34 -0
- package/dist/npcs/log-watcher/defaults.d.ts +9 -0
- package/dist/npcs/log-watcher/defaults.js +9 -0
- package/dist/npcs/log-watcher/index.d.ts +45 -0
- package/dist/npcs/log-watcher/index.js +157 -0
- package/dist/npcs/log-watcher/tail.d.ts +9 -0
- package/dist/npcs/log-watcher/tail.js +78 -0
- package/dist/npcs/process-watcher/defaults.d.ts +6 -0
- package/dist/npcs/process-watcher/defaults.js +6 -0
- package/dist/npcs/process-watcher/index.d.ts +26 -0
- package/dist/npcs/process-watcher/index.js +136 -0
- package/dist/npcs/process-watcher/process-scanner.d.ts +19 -0
- package/dist/npcs/process-watcher/process-scanner.js +110 -0
- package/dist/npcs/receptionist/defaults.d.ts +6 -0
- package/dist/npcs/receptionist/defaults.js +6 -0
- package/dist/npcs/receptionist/index.d.ts +29 -0
- package/dist/npcs/receptionist/index.js +116 -0
- package/dist/npcs/receptionist/weather.d.ts +37 -0
- package/dist/npcs/receptionist/weather.js +121 -0
- package/dist/npcs/system-monitor/collectors.d.ts +45 -0
- package/dist/npcs/system-monitor/collectors.js +60 -0
- package/dist/npcs/system-monitor/defaults.d.ts +7 -0
- package/dist/npcs/system-monitor/defaults.js +10 -0
- package/dist/npcs/system-monitor/index.d.ts +27 -0
- package/dist/npcs/system-monitor/index.js +101 -0
- package/dist/npcs/web-page-watcher/basic-mode.d.ts +16 -0
- package/dist/npcs/web-page-watcher/basic-mode.js +52 -0
- package/dist/npcs/web-page-watcher/capture.d.ts +49 -0
- package/dist/npcs/web-page-watcher/capture.js +75 -0
- package/dist/npcs/web-page-watcher/defaults.d.ts +19 -0
- package/dist/npcs/web-page-watcher/defaults.js +27 -0
- package/dist/npcs/web-page-watcher/index.d.ts +42 -0
- package/dist/npcs/web-page-watcher/index.js +230 -0
- package/dist/npcs/web-page-watcher/pixelate.d.ts +36 -0
- package/dist/npcs/web-page-watcher/pixelate.js +172 -0
- package/package.json +73 -3
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { homedir, tmpdir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
export const CODEX_DEFAULTS = {
|
|
4
|
+
/** Hook-mode per-session state (shared with the watcher to avoid double pushes). */
|
|
5
|
+
stateDir: join(tmpdir(), 'nocville-codex'),
|
|
6
|
+
stateFileMaxAge: 24 * 60 * 60 * 1000,
|
|
7
|
+
/** Watchdog-backed sessions become unknown after three minutes without a heartbeat. */
|
|
8
|
+
heartbeatSeconds: 90,
|
|
9
|
+
minPushGapMs: 1500,
|
|
10
|
+
hookTimeoutSeconds: 10,
|
|
11
|
+
/** Watcher: Codex session rollout logs. */
|
|
12
|
+
sessionsDir: join(process.env['CODEX_HOME'] ?? join(homedir(), '.codex'), 'sessions'),
|
|
13
|
+
/** Watcher: poll interval for new sessions / appended lines. */
|
|
14
|
+
pollMs: 1000,
|
|
15
|
+
/**
|
|
16
|
+
* Watcher: a session whose rollout file hasn't grown for this long is treated
|
|
17
|
+
* as ended (offline push). Matches Codex's own 30-minute idle SessionEnd.
|
|
18
|
+
*/
|
|
19
|
+
idleTimeoutMs: 30 * 60 * 1000,
|
|
20
|
+
/** Watcher: bytes read from the end of an already-active rollout on discovery. */
|
|
21
|
+
initialTailBytes: 256 * 1024,
|
|
22
|
+
/** Watcher: max bytes read per tick per session before skipping ahead to the tail. */
|
|
23
|
+
maxReadBytes: 8 * 1024 * 1024,
|
|
24
|
+
};
|
|
25
|
+
export function codexHome() {
|
|
26
|
+
return process.env['CODEX_HOME'] ?? join(homedir(), '.codex');
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { NpcConfig } from '../../core/types.js';
|
|
2
|
+
import type { AgentHookEvent, AgentHookSpec, HookRunOptions } from '../agent-common/hook-runner.js';
|
|
3
|
+
import type { AgentAdapter, AgentSessionState, AgentTransition } from '../agent-common/session.js';
|
|
4
|
+
export declare const CODEX_ADAPTER: AgentAdapter;
|
|
5
|
+
/**
|
|
6
|
+
* Codex session ids are UUIDv7 (time-ordered): the leading chars are shared by
|
|
7
|
+
* sessions started close together, so key the serviceId on the random tail.
|
|
8
|
+
*/
|
|
9
|
+
export declare function codexServiceId(sessionId: string, cwd: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Map one Codex hook event to a phase + activity line. Events and payload
|
|
12
|
+
* fields per the Codex hooks reference (developers.openai.com/codex/hooks):
|
|
13
|
+
* SessionStart, SessionEnd, UserPromptSubmit, PreToolUse, PostToolUse,
|
|
14
|
+
* PermissionRequest, Stop, Interrupt, PreCompact, PostCompact, SubagentStart,
|
|
15
|
+
* SubagentStop. Bash/apply_patch carry `tool_input.command`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function codexTransition(event: AgentHookEvent, prev: AgentSessionState | null): AgentTransition;
|
|
18
|
+
export declare const CODEX_HOOK_SPEC: AgentHookSpec;
|
|
19
|
+
/**
|
|
20
|
+
* Handle a single Codex hook event (stdin JSON unless `rawInput` is given).
|
|
21
|
+
* In-process push by default; the CLI passes `mode: 'detach'`. Never throws.
|
|
22
|
+
*/
|
|
23
|
+
export declare function handleCodexHookEvent(config: NpcConfig, rawInput?: string, opts?: HookRunOptions): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=hook-handler.d.ts.map
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { THINKING, describeToolUse, failureText, isQuestionTool, } from '../agent-common/activity.js';
|
|
2
|
+
import { hookEventName, readStdin, runAgentHook } from '../agent-common/hook-runner.js';
|
|
3
|
+
import { projectNameOf, sanitizeServiceId } from '../agent-common/session.js';
|
|
4
|
+
import { CODEX_DEFAULTS } from './defaults.js';
|
|
5
|
+
export const CODEX_ADAPTER = {
|
|
6
|
+
command: 'codex',
|
|
7
|
+
label: 'Codex',
|
|
8
|
+
family: 'codex',
|
|
9
|
+
stateDir: CODEX_DEFAULTS.stateDir,
|
|
10
|
+
heartbeatSeconds: CODEX_DEFAULTS.heartbeatSeconds,
|
|
11
|
+
processNames: ['codex'],
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Codex session ids are UUIDv7 (time-ordered): the leading chars are shared by
|
|
15
|
+
* sessions started close together, so key the serviceId on the random tail.
|
|
16
|
+
*/
|
|
17
|
+
export function codexServiceId(sessionId, cwd) {
|
|
18
|
+
const hex = sessionId.replace(/[^A-Za-z0-9]/g, '');
|
|
19
|
+
return sanitizeServiceId(`codex-${projectNameOf(cwd)}-${hex.slice(-8) || 'session'}`);
|
|
20
|
+
}
|
|
21
|
+
const working = (activity, warn = false) => ({
|
|
22
|
+
state: 'WORKING',
|
|
23
|
+
activity,
|
|
24
|
+
status: warn ? 'warning' : 'healthy',
|
|
25
|
+
mood: warn ? 'concerned' : 'happy',
|
|
26
|
+
});
|
|
27
|
+
const waiting = (activity) => ({
|
|
28
|
+
state: 'WAITING',
|
|
29
|
+
activity,
|
|
30
|
+
status: 'warning',
|
|
31
|
+
mood: 'concerned',
|
|
32
|
+
});
|
|
33
|
+
const idle = (activity) => ({
|
|
34
|
+
state: 'IDLE',
|
|
35
|
+
activity,
|
|
36
|
+
status: 'healthy',
|
|
37
|
+
mood: 'idle',
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Map one Codex hook event to a phase + activity line. Events and payload
|
|
41
|
+
* fields per the Codex hooks reference (developers.openai.com/codex/hooks):
|
|
42
|
+
* SessionStart, SessionEnd, UserPromptSubmit, PreToolUse, PostToolUse,
|
|
43
|
+
* PermissionRequest, Stop, Interrupt, PreCompact, PostCompact, SubagentStart,
|
|
44
|
+
* SubagentStop. Bash/apply_patch carry `tool_input.command`.
|
|
45
|
+
*/
|
|
46
|
+
export function codexTransition(event, prev) {
|
|
47
|
+
const name = hookEventName(event);
|
|
48
|
+
const cwd = (typeof event.cwd === 'string' && event.cwd) || prev?.projectDir;
|
|
49
|
+
const keep = prev?.state ?? 'IDLE';
|
|
50
|
+
switch (name) {
|
|
51
|
+
case 'SessionStart':
|
|
52
|
+
return idle('Ready for a task');
|
|
53
|
+
case 'UserPromptSubmit':
|
|
54
|
+
return working(THINKING);
|
|
55
|
+
case 'PreToolUse': {
|
|
56
|
+
const activity = describeToolUse(event.tool_name, event.tool_input, cwd);
|
|
57
|
+
return isQuestionTool(event.tool_name) ? waiting(activity) : working(activity);
|
|
58
|
+
}
|
|
59
|
+
case 'PostToolUse':
|
|
60
|
+
case 'PostCompact':
|
|
61
|
+
return { ...working(undefined), quiet: prev?.state === 'WORKING' };
|
|
62
|
+
case 'PostToolUseFailure':
|
|
63
|
+
return working(failureText(event.tool_name), true);
|
|
64
|
+
case 'PermissionRequest': {
|
|
65
|
+
const what = event.tool_name ? describeToolUse(event.tool_name, event.tool_input, cwd) : '';
|
|
66
|
+
return waiting(what ? `Needs your approval: ${what}` : 'Needs your approval');
|
|
67
|
+
}
|
|
68
|
+
case 'Stop':
|
|
69
|
+
return idle('Done — waiting for next task');
|
|
70
|
+
case 'Interrupt':
|
|
71
|
+
return idle('Interrupted — waiting for you');
|
|
72
|
+
case 'PreCompact':
|
|
73
|
+
return working('Compacting context');
|
|
74
|
+
case 'SubagentStart':
|
|
75
|
+
return working('Delegating to a subagent');
|
|
76
|
+
case 'SubagentStop':
|
|
77
|
+
return working('Subagent finished');
|
|
78
|
+
case 'SessionEnd':
|
|
79
|
+
return {
|
|
80
|
+
state: 'IDLE',
|
|
81
|
+
activity: 'Session ended',
|
|
82
|
+
status: 'unknown',
|
|
83
|
+
mood: 'idle',
|
|
84
|
+
offline: true,
|
|
85
|
+
};
|
|
86
|
+
default:
|
|
87
|
+
return {
|
|
88
|
+
state: keep,
|
|
89
|
+
status: prev?.status ?? 'healthy',
|
|
90
|
+
mood: prev?.mood ?? 'idle',
|
|
91
|
+
quiet: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export const CODEX_HOOK_SPEC = {
|
|
96
|
+
adapter: CODEX_ADAPTER,
|
|
97
|
+
serviceIdFor: codexServiceId,
|
|
98
|
+
transition: codexTransition,
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Handle a single Codex hook event (stdin JSON unless `rawInput` is given).
|
|
102
|
+
* In-process push by default; the CLI passes `mode: 'detach'`. Never throws.
|
|
103
|
+
*/
|
|
104
|
+
export async function handleCodexHookEvent(config, rawInput, opts = {}) {
|
|
105
|
+
await runAgentHook(CODEX_HOOK_SPEC, config, rawInput ?? readStdin(), {
|
|
106
|
+
minPushGapMs: CODEX_DEFAULTS.minPushGapMs,
|
|
107
|
+
...opts,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=hook-handler.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { NpcConfig } from '../../core/types.js';
|
|
2
|
+
export { CODEX_DEFAULTS } from './defaults.js';
|
|
3
|
+
export { CODEX_ADAPTER, codexTransition, codexServiceId, handleCodexHookEvent, } from './hook-handler.js';
|
|
4
|
+
export { setupCodexHooks, uninstallCodexHooks, installCodexHooksInto, CODEX_HOOK_EVENTS, } from './setup.js';
|
|
5
|
+
export type { CodexSetupOptions } from './setup.js';
|
|
6
|
+
export { parseRolloutLine, describeExecScript } from './rollout.js';
|
|
7
|
+
export type { RolloutSignal } from './rollout.js';
|
|
8
|
+
export { CodexWatcher } from './watcher.js';
|
|
9
|
+
export type { CodexWatcherOptions } from './watcher.js';
|
|
10
|
+
export interface CodexSubcommandOptions {
|
|
11
|
+
subcommand: string;
|
|
12
|
+
config: NpcConfig;
|
|
13
|
+
flags: Record<string, string | boolean>;
|
|
14
|
+
args?: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* codex subcommands: setup | uninstall | hook | flush | watch | cleanup.
|
|
18
|
+
* `hook`/`flush` are invoked by Codex / ourselves and stay silent on stdout.
|
|
19
|
+
*/
|
|
20
|
+
export declare function handleCodexCommand(opts: CodexSubcommandOptions): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { boolFlag, numberFlag, stringFlag } from '../../core/config.js';
|
|
2
|
+
import { readStdin, runFlushCommand } from '../agent-common/hook-runner.js';
|
|
3
|
+
import { runWatchdog } from '../agent-common/watchdog.js';
|
|
4
|
+
import { cleanupSessionStates } from '../agent-common/session.js';
|
|
5
|
+
import { CODEX_DEFAULTS } from './defaults.js';
|
|
6
|
+
import { CODEX_ADAPTER, handleCodexHookEvent } from './hook-handler.js';
|
|
7
|
+
import { setupCodexHooks, uninstallCodexHooks } from './setup.js';
|
|
8
|
+
import { CodexWatcher } from './watcher.js';
|
|
9
|
+
export { CODEX_DEFAULTS } from './defaults.js';
|
|
10
|
+
export { CODEX_ADAPTER, codexTransition, codexServiceId, handleCodexHookEvent, } from './hook-handler.js';
|
|
11
|
+
export { setupCodexHooks, uninstallCodexHooks, installCodexHooksInto, CODEX_HOOK_EVENTS, } from './setup.js';
|
|
12
|
+
export { parseRolloutLine, describeExecScript } from './rollout.js';
|
|
13
|
+
export { CodexWatcher } from './watcher.js';
|
|
14
|
+
/**
|
|
15
|
+
* codex subcommands: setup | uninstall | hook | flush | watch | cleanup.
|
|
16
|
+
* `hook`/`flush` are invoked by Codex / ourselves and stay silent on stdout.
|
|
17
|
+
*/
|
|
18
|
+
export async function handleCodexCommand(opts) {
|
|
19
|
+
const { subcommand, config, flags } = opts;
|
|
20
|
+
switch (subcommand) {
|
|
21
|
+
case 'setup': {
|
|
22
|
+
if (flags['uninstall']) {
|
|
23
|
+
uninstallCodexHooks();
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
const ok = setupCodexHooks({
|
|
27
|
+
apiUrl: stringFlag(flags, 'api-url') ?? process.env['NOCVILLE_API_URL'],
|
|
28
|
+
apiKey: stringFlag(flags, 'api-key') ?? process.env['NOCVILLE_API_KEY'],
|
|
29
|
+
map: stringFlag(flags, 'map'),
|
|
30
|
+
cliPath: process.argv[1],
|
|
31
|
+
});
|
|
32
|
+
if (!ok)
|
|
33
|
+
process.exitCode = 1;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
case 'uninstall':
|
|
37
|
+
uninstallCodexHooks();
|
|
38
|
+
break;
|
|
39
|
+
case 'hook':
|
|
40
|
+
await handleCodexHookEvent(config, readStdin(), { mode: 'detach' });
|
|
41
|
+
break;
|
|
42
|
+
case 'watchdog':
|
|
43
|
+
await runWatchdog(CODEX_ADAPTER, config, opts.args?.[0]);
|
|
44
|
+
break;
|
|
45
|
+
case 'flush':
|
|
46
|
+
await runFlushCommand(CODEX_ADAPTER, config, opts.args?.[0], numberFlag(flags, 'delay'), flags['stats'] === true);
|
|
47
|
+
break;
|
|
48
|
+
case 'watch': {
|
|
49
|
+
console.error('codex watch is a fallback for Codex builds without hooks; prefer `nocville-npc codex setup`.');
|
|
50
|
+
if (!config.apiKey) {
|
|
51
|
+
console.error('Error: no API key — run `nocville-npc init --api-key=<key>` or pass --api-key');
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const idleMin = numberFlag(flags, 'idle-timeout');
|
|
56
|
+
const watcher = new CodexWatcher(config, {
|
|
57
|
+
sessionsDir: stringFlag(flags, 'sessions-dir'),
|
|
58
|
+
idleTimeoutMs: idleMin !== undefined ? idleMin * 60_000 : undefined,
|
|
59
|
+
includeExec: boolFlag(flags, 'include-exec') ?? false,
|
|
60
|
+
pollMs: numberFlag(flags, 'poll-interval'),
|
|
61
|
+
});
|
|
62
|
+
await watcher.start();
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case 'cleanup': {
|
|
66
|
+
const removed = await cleanupSessionStates(CODEX_DEFAULTS.stateDir, CODEX_DEFAULTS.stateFileMaxAge);
|
|
67
|
+
console.log(`Cleanup complete: ${removed} stale file(s) removed`);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
default:
|
|
71
|
+
console.error(`Unknown codex subcommand: ${subcommand}`);
|
|
72
|
+
console.error('Available subcommands: setup, uninstall, watch, hook, cleanup');
|
|
73
|
+
process.exitCode = 1;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser for Codex session rollout logs (`~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl`).
|
|
3
|
+
*
|
|
4
|
+
* Each line is `{ timestamp, type, payload }`. The format is internal to Codex
|
|
5
|
+
* and has shifted between releases, so this is deliberately defensive: it
|
|
6
|
+
* recognises both the older `event_msg` records (exec_command_begin,
|
|
7
|
+
* patch_apply_begin, *_approval_request, user_message) and the newer ones
|
|
8
|
+
* (custom_tool_call "exec" scripts, function_call, item_completed), and
|
|
9
|
+
* ignores everything else. Content (prompts, outputs) is never surfaced.
|
|
10
|
+
*/
|
|
11
|
+
export type RolloutSignal = {
|
|
12
|
+
kind: 'meta';
|
|
13
|
+
sessionId: string;
|
|
14
|
+
cwd?: string;
|
|
15
|
+
/** Spawned subagent / guardian reviewer — not a user-facing session. */
|
|
16
|
+
subagent: boolean;
|
|
17
|
+
/** Non-interactive `codex exec` run. */
|
|
18
|
+
exec: boolean;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'cwd';
|
|
21
|
+
cwd: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'working';
|
|
24
|
+
activity: string;
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'waiting';
|
|
27
|
+
activity: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'idle';
|
|
30
|
+
activity: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Describe a Codex "exec" code-mode script (`text(await tools.exec_command({cmd:"…"}))`)
|
|
34
|
+
* by its first tool call. Returns null for no-op helpers.
|
|
35
|
+
*/
|
|
36
|
+
export declare function describeExecScript(script: string, cwd?: string): string | null;
|
|
37
|
+
/** Parse one rollout line into a signal (or null when it carries nothing useful). */
|
|
38
|
+
export declare function parseRolloutLine(line: string, cwd?: string): RolloutSignal | null;
|
|
39
|
+
//# sourceMappingURL=rollout.d.ts.map
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// Unsupported, best-effort fallback: Codex rollout logs are an internal format. Prefer hooks.
|
|
2
|
+
import { THINKING, describeToolUse, editingFiles, patchFiles, shortCommand, } from '../agent-common/activity.js';
|
|
3
|
+
const isObj = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
4
|
+
const s = (v) => (typeof v === 'string' && v ? v : undefined);
|
|
5
|
+
function stripFileUrl(p) {
|
|
6
|
+
return p.replace(/^file:\/\//, '');
|
|
7
|
+
}
|
|
8
|
+
/** Pull a JS/JSON string property (`cmd:"…"` / `"cmd": "…"`) out of a script. */
|
|
9
|
+
function scriptString(script, key) {
|
|
10
|
+
const re = new RegExp(`["']?${key}["']?\\s*:\\s*"((?:[^"\\\\]|\\\\.)*)"`);
|
|
11
|
+
const m = script.match(re);
|
|
12
|
+
if (!m)
|
|
13
|
+
return undefined;
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(`"${m[1]}"`);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return m[1];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Tool helpers inside exec scripts that carry nothing worth showing. */
|
|
22
|
+
const QUIET_SCRIPT_TOOLS = new Set(['write_stdin', 'wait', 'clock__curr_time', 'get_goal']);
|
|
23
|
+
/**
|
|
24
|
+
* Describe a Codex "exec" code-mode script (`text(await tools.exec_command({cmd:"…"}))`)
|
|
25
|
+
* by its first tool call. Returns null for no-op helpers.
|
|
26
|
+
*/
|
|
27
|
+
export function describeExecScript(script, cwd) {
|
|
28
|
+
const m = script.match(/tools\.([A-Za-z0-9_]+)\s*\(/);
|
|
29
|
+
if (!m)
|
|
30
|
+
return 'Running code';
|
|
31
|
+
const tool = m[1];
|
|
32
|
+
if (QUIET_SCRIPT_TOOLS.has(tool))
|
|
33
|
+
return null;
|
|
34
|
+
switch (tool) {
|
|
35
|
+
case 'exec_command': {
|
|
36
|
+
const cmd = scriptString(script, 'cmd') ?? scriptString(script, 'command');
|
|
37
|
+
const short = cmd ? shortCommand(cmd) : '';
|
|
38
|
+
return short ? `Running ${short}` : 'Running a command';
|
|
39
|
+
}
|
|
40
|
+
case 'apply_patch': {
|
|
41
|
+
// The patch is embedded as a JS string with escaped newlines.
|
|
42
|
+
return editingFiles(patchFiles(script.replace(/\\n/g, '\n')), cwd);
|
|
43
|
+
}
|
|
44
|
+
case 'view_image':
|
|
45
|
+
return 'Viewing an image';
|
|
46
|
+
case 'update_plan':
|
|
47
|
+
return 'Planning';
|
|
48
|
+
case 'web__run':
|
|
49
|
+
case 'web_search':
|
|
50
|
+
return 'Browsing the web';
|
|
51
|
+
case 'image_gen__imagegen':
|
|
52
|
+
return 'Generating an image';
|
|
53
|
+
case 'spawn_agent':
|
|
54
|
+
return 'Delegating to a subagent';
|
|
55
|
+
default:
|
|
56
|
+
return describeToolUse(tool.includes('__') ? `mcp__${tool}` : tool, {}, cwd);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function parseArgs(raw) {
|
|
60
|
+
if (isObj(raw))
|
|
61
|
+
return raw;
|
|
62
|
+
if (typeof raw === 'string') {
|
|
63
|
+
try {
|
|
64
|
+
const parsed = JSON.parse(raw);
|
|
65
|
+
if (isObj(parsed))
|
|
66
|
+
return parsed;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return { input: raw };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
/** Describe a `function_call` / `custom_tool_call` response item. */
|
|
75
|
+
function describeCall(name, rawArgs, cwd) {
|
|
76
|
+
switch (name) {
|
|
77
|
+
case 'exec':
|
|
78
|
+
return typeof rawArgs === 'string' ? describeExecScript(rawArgs, cwd) : 'Running code';
|
|
79
|
+
case 'wait':
|
|
80
|
+
case 'write_stdin':
|
|
81
|
+
case 'list_agents':
|
|
82
|
+
return null;
|
|
83
|
+
case 'send_message':
|
|
84
|
+
case 'followup_task':
|
|
85
|
+
return 'Coordinating subagents';
|
|
86
|
+
case 'apply_patch': {
|
|
87
|
+
const args = parseArgs(rawArgs);
|
|
88
|
+
const patch = s(args['input']) ?? s(args['patch']) ?? (typeof rawArgs === 'string' ? rawArgs : '');
|
|
89
|
+
return editingFiles(patchFiles(patch), cwd);
|
|
90
|
+
}
|
|
91
|
+
case 'shell':
|
|
92
|
+
case 'local_shell':
|
|
93
|
+
case 'exec_command':
|
|
94
|
+
case 'container.exec': {
|
|
95
|
+
const args = parseArgs(rawArgs);
|
|
96
|
+
return describeToolUse('Bash', { command: args['command'] ?? args['cmd'] }, cwd);
|
|
97
|
+
}
|
|
98
|
+
default:
|
|
99
|
+
return describeToolUse(name, parseArgs(rawArgs), cwd);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function approvalText(payload, cwd) {
|
|
103
|
+
const cmd = payload['command'];
|
|
104
|
+
if (cmd) {
|
|
105
|
+
const short = shortCommand(cmd);
|
|
106
|
+
if (short)
|
|
107
|
+
return `Needs your approval: Running ${short}`;
|
|
108
|
+
}
|
|
109
|
+
const changes = payload['changes'];
|
|
110
|
+
if (isObj(changes)) {
|
|
111
|
+
return `Needs your approval: ${editingFiles(Object.keys(changes).map(stripFileUrl), cwd)}`;
|
|
112
|
+
}
|
|
113
|
+
return 'Needs your approval';
|
|
114
|
+
}
|
|
115
|
+
function parseEventMsg(payload, cwd) {
|
|
116
|
+
const type = s(payload['type']) ?? '';
|
|
117
|
+
switch (type) {
|
|
118
|
+
case 'task_started':
|
|
119
|
+
case 'user_message':
|
|
120
|
+
return { kind: 'working', activity: THINKING };
|
|
121
|
+
case 'task_complete':
|
|
122
|
+
return { kind: 'idle', activity: 'Done — waiting for next task' };
|
|
123
|
+
case 'turn_aborted':
|
|
124
|
+
return { kind: 'idle', activity: 'Interrupted — waiting for you' };
|
|
125
|
+
case 'exec_command_begin': {
|
|
126
|
+
const short = shortCommand(payload['command']);
|
|
127
|
+
return { kind: 'working', activity: short ? `Running ${short}` : 'Running a command' };
|
|
128
|
+
}
|
|
129
|
+
case 'patch_apply_begin': {
|
|
130
|
+
const changes = isObj(payload['changes']) ? Object.keys(payload['changes']) : [];
|
|
131
|
+
return { kind: 'working', activity: editingFiles(changes.map(stripFileUrl), cwd) };
|
|
132
|
+
}
|
|
133
|
+
case 'web_search_begin':
|
|
134
|
+
return { kind: 'working', activity: 'Searching the web' };
|
|
135
|
+
case 'request_user_input':
|
|
136
|
+
return { kind: 'waiting', activity: 'Has a question for you' };
|
|
137
|
+
case 'item_started': {
|
|
138
|
+
const item = isObj(payload['item']) ? payload['item'] : {};
|
|
139
|
+
const itemType = s(item['type']);
|
|
140
|
+
if (itemType === 'CommandExecution') {
|
|
141
|
+
const short = shortCommand(item['command']);
|
|
142
|
+
return { kind: 'working', activity: short ? `Running ${short}` : 'Running a command' };
|
|
143
|
+
}
|
|
144
|
+
if (itemType === 'FileChange' && isObj(item['changes'])) {
|
|
145
|
+
return {
|
|
146
|
+
kind: 'working',
|
|
147
|
+
activity: editingFiles(Object.keys(item['changes']).map(stripFileUrl), cwd),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
case 'item_completed': {
|
|
153
|
+
// Newer builds log file edits only on completion; still the best signal.
|
|
154
|
+
const item = isObj(payload['item']) ? payload['item'] : {};
|
|
155
|
+
if (s(item['type']) === 'FileChange' && isObj(item['changes'])) {
|
|
156
|
+
return {
|
|
157
|
+
kind: 'working',
|
|
158
|
+
activity: editingFiles(Object.keys(item['changes']).map(stripFileUrl), cwd),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
default:
|
|
164
|
+
if (/approval_request$/.test(type) || type === 'request_permissions') {
|
|
165
|
+
return { kind: 'waiting', activity: approvalText(payload, cwd) };
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function parseResponseItem(payload, cwd) {
|
|
171
|
+
const type = s(payload['type']) ?? '';
|
|
172
|
+
if (type === 'custom_tool_call' || type === 'function_call') {
|
|
173
|
+
const name = s(payload['name']) ?? '';
|
|
174
|
+
const activity = describeCall(name, payload['input'] ?? payload['arguments'], cwd);
|
|
175
|
+
return activity ? { kind: 'working', activity } : null;
|
|
176
|
+
}
|
|
177
|
+
if (type === 'local_shell_call') {
|
|
178
|
+
const action = isObj(payload['action']) ? payload['action'] : {};
|
|
179
|
+
const short = shortCommand(action['command']);
|
|
180
|
+
return { kind: 'working', activity: short ? `Running ${short}` : 'Running a command' };
|
|
181
|
+
}
|
|
182
|
+
if (type === 'web_search_call')
|
|
183
|
+
return { kind: 'working', activity: 'Searching the web' };
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
/** Parse one rollout line into a signal (or null when it carries nothing useful). */
|
|
187
|
+
export function parseRolloutLine(line, cwd) {
|
|
188
|
+
const trimmed = line.trim();
|
|
189
|
+
if (!trimmed || trimmed[0] !== '{')
|
|
190
|
+
return null;
|
|
191
|
+
let rec;
|
|
192
|
+
try {
|
|
193
|
+
const parsed = JSON.parse(trimmed);
|
|
194
|
+
if (!isObj(parsed))
|
|
195
|
+
return null;
|
|
196
|
+
rec = parsed;
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
const type = s(rec['type']) ?? '';
|
|
202
|
+
const payload = isObj(rec['payload']) ? rec['payload'] : {};
|
|
203
|
+
switch (type) {
|
|
204
|
+
case 'session_meta': {
|
|
205
|
+
const meta = isObj(payload['meta']) ? payload['meta'] : payload; // older nesting
|
|
206
|
+
const sessionId = s(meta['id']) ?? s(meta['session_id']);
|
|
207
|
+
if (!sessionId)
|
|
208
|
+
return null;
|
|
209
|
+
const source = meta['source'];
|
|
210
|
+
const threadSource = s(meta['thread_source']);
|
|
211
|
+
const subagent = (isObj(source) && 'subagent' in source) ||
|
|
212
|
+
threadSource === 'subagent' ||
|
|
213
|
+
threadSource === 'guardian_review';
|
|
214
|
+
const exec = source === 'exec' || s(meta['originator']) === 'codex_exec';
|
|
215
|
+
return { kind: 'meta', sessionId, cwd: s(meta['cwd']), subagent, exec };
|
|
216
|
+
}
|
|
217
|
+
case 'turn_context': {
|
|
218
|
+
const c = s(payload['cwd']);
|
|
219
|
+
return c ? { kind: 'cwd', cwd: c } : null;
|
|
220
|
+
}
|
|
221
|
+
case 'event_msg':
|
|
222
|
+
return parseEventMsg(payload, cwd);
|
|
223
|
+
case 'response_item':
|
|
224
|
+
return parseResponseItem(payload, cwd);
|
|
225
|
+
case 'function_call':
|
|
226
|
+
case 'custom_tool_call':
|
|
227
|
+
case 'local_shell_call':
|
|
228
|
+
case 'web_search_call':
|
|
229
|
+
// 2025-era rollouts wrote response items unwrapped.
|
|
230
|
+
return parseResponseItem(rec, cwd);
|
|
231
|
+
case '': {
|
|
232
|
+
// 2025-era first line: bare `{ id, timestamp, instructions }` session header.
|
|
233
|
+
const id = s(rec['id']);
|
|
234
|
+
return id && s(rec['timestamp'])
|
|
235
|
+
? { kind: 'meta', sessionId: id, subagent: false, exec: false }
|
|
236
|
+
: null;
|
|
237
|
+
}
|
|
238
|
+
default:
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=rollout.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { HooksFile } from '../agent-common/hook-settings.js';
|
|
2
|
+
/**
|
|
3
|
+
* Codex hook events we install (developers.openai.com/codex/hooks). PostCompact
|
|
4
|
+
* is omitted — it carries nothing displayable.
|
|
5
|
+
*/
|
|
6
|
+
export declare const CODEX_HOOK_EVENTS: readonly ["SessionStart", "SessionEnd", "UserPromptSubmit", "PreToolUse", "PostToolUse", "PermissionRequest", "Stop", "Interrupt", "PreCompact", "SubagentStart", "SubagentStop"];
|
|
7
|
+
export declare function codexHooksPath(): string;
|
|
8
|
+
export interface CodexSetupOptions {
|
|
9
|
+
apiUrl?: string;
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
map?: string;
|
|
12
|
+
cliPath?: string;
|
|
13
|
+
/** Override ~/.codex/hooks.json (tests). */
|
|
14
|
+
hooksPath?: string;
|
|
15
|
+
quiet?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Install the nocville group into every Codex event. Mutates `file`. */
|
|
18
|
+
export declare function installCodexHooksInto(file: HooksFile, command: string, opts?: {
|
|
19
|
+
timeout?: number;
|
|
20
|
+
}): {
|
|
21
|
+
migrated: number;
|
|
22
|
+
installed: number;
|
|
23
|
+
};
|
|
24
|
+
export declare function buildCodexHookCommand(_cliPath: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Install Nocville hooks into `~/.codex/hooks.json` (same matcher-group JSON
|
|
27
|
+
* format as Claude Code). Merges with existing hooks, idempotent, keeps a
|
|
28
|
+
* one-time `.nocville-backup`. Codex requires new hooks to be reviewed and
|
|
29
|
+
* trusted once via `/hooks` before they run — we print that instruction.
|
|
30
|
+
*/
|
|
31
|
+
export declare function setupCodexHooks(opts?: CodexSetupOptions): boolean;
|
|
32
|
+
/** Remove all Nocville hooks from `~/.codex/hooks.json`. */
|
|
33
|
+
export declare function uninstallCodexHooks(opts?: {
|
|
34
|
+
hooksPath?: string;
|
|
35
|
+
quiet?: boolean;
|
|
36
|
+
}): number;
|
|
37
|
+
//# sourceMappingURL=setup.d.ts.map
|