@evo-dev/evodev 0.0.1-alpha
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/dist/.agents/plugins/marketplace.json +20 -0
- package/dist/.claude-plugin/marketplace.json +22 -0
- package/dist/assets/agents/review/code-reviewer/examples.md +19 -0
- package/dist/assets/agents/review/code-reviewer/manifest.json +10 -0
- package/dist/assets/agents/review/code-reviewer/prompt.md +59 -0
- package/dist/assets/agents/review/code-reviewer/verification.md +11 -0
- package/dist/assets/skills/coding/engineering-discipline/SKILL.md +63 -0
- package/dist/assets/skills/coding/engineering-discipline/anti-patterns.md +21 -0
- package/dist/assets/skills/coding/engineering-discipline/examples.md +19 -0
- package/dist/assets/skills/coding/engineering-discipline/manifest.json +10 -0
- package/dist/assets/skills/coding/engineering-discipline/verification.md +11 -0
- package/dist/assets/workflows/rd-bug-fix/WORKFLOW.json +45 -0
- package/dist/assets/workflows/rd-code-review/WORKFLOW.json +45 -0
- package/dist/assets/workflows/rd-docs-update/WORKFLOW.json +45 -0
- package/dist/assets/workflows/rd-feature-implementation/WORKFLOW.json +45 -0
- package/dist/assets/workflows/rd-refactor/WORKFLOW.json +45 -0
- package/dist/assets/workflows/rd-release-readiness/WORKFLOW.json +49 -0
- package/dist/assets/workflows/rd-security-boundary-review/WORKFLOW.json +45 -0
- package/dist/assets/workflows/rd-test-generation/WORKFLOW.json +45 -0
- package/dist/evodev +11 -0
- package/dist/index.js +11283 -0
- package/dist/plugins/evodev/.claude-plugin/plugin.json +9 -0
- package/dist/plugins/evodev/.codex-plugin/plugin.json +19 -0
- package/dist/plugins/evodev/hooks/codex-hooks.json +121 -0
- package/dist/plugins/evodev/hooks/codex.ts +257 -0
- package/dist/plugins/evodev/hooks/command-runner.ts +30 -0
- package/dist/plugins/evodev/hooks/detect.ts +101 -0
- package/dist/plugins/evodev/hooks/hooks.json +197 -0
- package/dist/plugins/evodev/hooks/hooks.ts +217 -0
- package/dist/plugins/evodev/hooks/index.ts +52 -0
- package/dist/plugins/evodev/hooks/paths.ts +53 -0
- package/dist/plugins/evodev/hooks/plugin.ts +513 -0
- package/dist/plugins/evodev/hooks/runtime.ts +113 -0
- package/dist/plugins/evodev/hooks/transform-agent.ts +30 -0
- package/dist/plugins/evodev/hooks/transform-skill.ts +18 -0
- package/dist/plugins/evodev/package.json +16 -0
- package/package.json +29 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "EvoDev routes Claude Code lifecycle events through evodev hook runtime for Task Contract, workflow, policy, and evidence control.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
10
|
+
"timeout": 30
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"UserPromptSubmit": [
|
|
16
|
+
{
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
21
|
+
"timeout": 30
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"PreToolUse": [
|
|
27
|
+
{
|
|
28
|
+
"matcher": "*",
|
|
29
|
+
"hooks": [
|
|
30
|
+
{
|
|
31
|
+
"type": "command",
|
|
32
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
33
|
+
"timeout": 30
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"PermissionRequest": [
|
|
39
|
+
{
|
|
40
|
+
"matcher": "*",
|
|
41
|
+
"hooks": [
|
|
42
|
+
{
|
|
43
|
+
"type": "command",
|
|
44
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
45
|
+
"timeout": 30
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"PostToolUse": [
|
|
51
|
+
{
|
|
52
|
+
"matcher": "*",
|
|
53
|
+
"hooks": [
|
|
54
|
+
{
|
|
55
|
+
"type": "command",
|
|
56
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
57
|
+
"timeout": 30
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"PostToolUseFailure": [
|
|
63
|
+
{
|
|
64
|
+
"matcher": "*",
|
|
65
|
+
"hooks": [
|
|
66
|
+
{
|
|
67
|
+
"type": "command",
|
|
68
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
69
|
+
"timeout": 30
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"PostToolBatch": [
|
|
75
|
+
{
|
|
76
|
+
"hooks": [
|
|
77
|
+
{
|
|
78
|
+
"type": "command",
|
|
79
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
80
|
+
"timeout": 30
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"PermissionDenied": [
|
|
86
|
+
{
|
|
87
|
+
"matcher": "*",
|
|
88
|
+
"hooks": [
|
|
89
|
+
{
|
|
90
|
+
"type": "command",
|
|
91
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
92
|
+
"timeout": 30
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
"SubagentStart": [
|
|
98
|
+
{
|
|
99
|
+
"hooks": [
|
|
100
|
+
{
|
|
101
|
+
"type": "command",
|
|
102
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
103
|
+
"timeout": 30
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"SubagentStop": [
|
|
109
|
+
{
|
|
110
|
+
"hooks": [
|
|
111
|
+
{
|
|
112
|
+
"type": "command",
|
|
113
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
114
|
+
"timeout": 30
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
"TaskCreated": [
|
|
120
|
+
{
|
|
121
|
+
"hooks": [
|
|
122
|
+
{
|
|
123
|
+
"type": "command",
|
|
124
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
125
|
+
"timeout": 30
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"TaskCompleted": [
|
|
131
|
+
{
|
|
132
|
+
"hooks": [
|
|
133
|
+
{
|
|
134
|
+
"type": "command",
|
|
135
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
136
|
+
"timeout": 30
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"Stop": [
|
|
142
|
+
{
|
|
143
|
+
"hooks": [
|
|
144
|
+
{
|
|
145
|
+
"type": "command",
|
|
146
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
147
|
+
"timeout": 30
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
"TeammateIdle": [
|
|
153
|
+
{
|
|
154
|
+
"hooks": [
|
|
155
|
+
{
|
|
156
|
+
"type": "command",
|
|
157
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
158
|
+
"timeout": 30
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
"PreCompact": [
|
|
164
|
+
{
|
|
165
|
+
"hooks": [
|
|
166
|
+
{
|
|
167
|
+
"type": "command",
|
|
168
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
169
|
+
"timeout": 30
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
"PostCompact": [
|
|
175
|
+
{
|
|
176
|
+
"hooks": [
|
|
177
|
+
{
|
|
178
|
+
"type": "command",
|
|
179
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
180
|
+
"timeout": 30
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
],
|
|
185
|
+
"SessionEnd": [
|
|
186
|
+
{
|
|
187
|
+
"hooks": [
|
|
188
|
+
{
|
|
189
|
+
"type": "command",
|
|
190
|
+
"command": "NODE_PATH=\"$(dirname \"$(bun pm bin -g)\")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}\" bun run \"${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts\" hook runtime --target claude",
|
|
191
|
+
"timeout": 5
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CanonicalHookEventType,
|
|
3
|
+
type HookEventV1,
|
|
4
|
+
type HookInputEventType,
|
|
5
|
+
normalizeHookEvent,
|
|
6
|
+
} from "@evo-dev/core";
|
|
7
|
+
import { type ClaudePaths, resolveClaudePaths } from "./paths.ts";
|
|
8
|
+
|
|
9
|
+
export interface ClaudeHookInstallDryRunInput {
|
|
10
|
+
homeDir: string;
|
|
11
|
+
paths?: ClaudePaths;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ClaudeHookInstallDryRunPlan {
|
|
15
|
+
target: "claude";
|
|
16
|
+
settingsPath: string;
|
|
17
|
+
plannedWrites: Array<{
|
|
18
|
+
action: "merge-with-backup" | "create";
|
|
19
|
+
targetPath: string;
|
|
20
|
+
reason: string;
|
|
21
|
+
}>;
|
|
22
|
+
warnings: string[];
|
|
23
|
+
blockers: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ClaudeHookCommand {
|
|
27
|
+
type: "command";
|
|
28
|
+
command: string;
|
|
29
|
+
timeout?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ClaudeHookMatcherGroup {
|
|
33
|
+
matcher?: string;
|
|
34
|
+
hooks: ClaudeHookCommand[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ClaudeHookConfig {
|
|
38
|
+
description: string;
|
|
39
|
+
hooks: Partial<Record<CanonicalHookEventType, ClaudeHookMatcherGroup[]>>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface CodexHookConfig {
|
|
43
|
+
hooks: Partial<Record<CanonicalHookEventType, ClaudeHookMatcherGroup[]>>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const CLAUDE_HOOK_RUNTIME_COMMAND =
|
|
47
|
+
'NODE_PATH="$(dirname "$(bun pm bin -g)")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}" bun run "${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts" hook runtime --target claude';
|
|
48
|
+
export const CODEX_HOOK_RUNTIME_COMMAND =
|
|
49
|
+
'NODE_PATH="$(dirname "$(bun pm bin -g)")/install/global/node_modules${NODE_PATH:+:$NODE_PATH}" bun run "${PLUGIN_ROOT}/hooks/runtime.ts" hook runtime --target codex';
|
|
50
|
+
const CLAUDE_TOOL_EVENTS = new Set<CanonicalHookEventType>([
|
|
51
|
+
"PreToolUse",
|
|
52
|
+
"PermissionRequest",
|
|
53
|
+
"PostToolUse",
|
|
54
|
+
"PostToolUseFailure",
|
|
55
|
+
"PermissionDenied",
|
|
56
|
+
]);
|
|
57
|
+
const CLAUDE_RUNTIME_EVENTS: CanonicalHookEventType[] = [
|
|
58
|
+
"SessionStart",
|
|
59
|
+
"UserPromptSubmit",
|
|
60
|
+
"PreToolUse",
|
|
61
|
+
"PermissionRequest",
|
|
62
|
+
"PostToolUse",
|
|
63
|
+
"PostToolUseFailure",
|
|
64
|
+
"PostToolBatch",
|
|
65
|
+
"PermissionDenied",
|
|
66
|
+
"SubagentStart",
|
|
67
|
+
"SubagentStop",
|
|
68
|
+
"TaskCreated",
|
|
69
|
+
"TaskCompleted",
|
|
70
|
+
"Stop",
|
|
71
|
+
"TeammateIdle",
|
|
72
|
+
"PreCompact",
|
|
73
|
+
"PostCompact",
|
|
74
|
+
"SessionEnd",
|
|
75
|
+
];
|
|
76
|
+
const CODEX_RUNTIME_EVENTS: CanonicalHookEventType[] = [
|
|
77
|
+
"SessionStart",
|
|
78
|
+
"UserPromptSubmit",
|
|
79
|
+
"PreToolUse",
|
|
80
|
+
"PermissionRequest",
|
|
81
|
+
"PostToolUse",
|
|
82
|
+
"PreCompact",
|
|
83
|
+
"PostCompact",
|
|
84
|
+
"SubagentStart",
|
|
85
|
+
"SubagentStop",
|
|
86
|
+
"Stop",
|
|
87
|
+
];
|
|
88
|
+
const CODEX_EVENT_MATCHERS: Partial<Record<CanonicalHookEventType, string>> = {
|
|
89
|
+
SessionStart: "startup|resume|clear|compact",
|
|
90
|
+
PreToolUse: "*",
|
|
91
|
+
PermissionRequest: "*",
|
|
92
|
+
PostToolUse: "*",
|
|
93
|
+
SubagentStart: "*",
|
|
94
|
+
SubagentStop: "*",
|
|
95
|
+
Stop: "*",
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export function planClaudeHookInstallDryRun(
|
|
99
|
+
input: ClaudeHookInstallDryRunInput,
|
|
100
|
+
): ClaudeHookInstallDryRunPlan {
|
|
101
|
+
const paths = input.paths ?? resolveClaudePaths({ homeDir: input.homeDir });
|
|
102
|
+
return {
|
|
103
|
+
target: "claude",
|
|
104
|
+
settingsPath: paths.settingsPath,
|
|
105
|
+
plannedWrites: [
|
|
106
|
+
{
|
|
107
|
+
action: "merge-with-backup",
|
|
108
|
+
targetPath: paths.settingsPath,
|
|
109
|
+
reason:
|
|
110
|
+
"dry-run only: would add disabled EvoDev user-level hooks after future confirmation; no file is written",
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
warnings: [
|
|
114
|
+
"Hooks remain disabled by default.",
|
|
115
|
+
"Project .claude, .codex, CLAUDE.md, and AGENTS.md are never targeted by this dry-run.",
|
|
116
|
+
],
|
|
117
|
+
blockers: [],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function normalizeClaudeHookPayload(input: {
|
|
122
|
+
type: HookInputEventType;
|
|
123
|
+
payload: Record<string, unknown>;
|
|
124
|
+
receivedAt?: string;
|
|
125
|
+
}): HookEventV1 {
|
|
126
|
+
return normalizeHookEvent({
|
|
127
|
+
pluginId: "claude",
|
|
128
|
+
agent: "claude-code",
|
|
129
|
+
type: input.type,
|
|
130
|
+
payload: input.payload,
|
|
131
|
+
receivedAt: input.receivedAt,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function normalizeClaudeRuntimeHookPayload(input: {
|
|
136
|
+
payload: Record<string, unknown>;
|
|
137
|
+
receivedAt?: string;
|
|
138
|
+
}): HookEventV1 {
|
|
139
|
+
const type = input.payload.hook_event_name ?? input.payload.hookEventName;
|
|
140
|
+
if (typeof type !== "string" || type.trim() === "") {
|
|
141
|
+
throw new Error("Claude hook payload is missing hook_event_name.");
|
|
142
|
+
}
|
|
143
|
+
return normalizeClaudeHookPayload({
|
|
144
|
+
type: type as HookInputEventType,
|
|
145
|
+
payload: input.payload,
|
|
146
|
+
receivedAt: input.receivedAt,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function normalizeCodexHookPayload(input: {
|
|
151
|
+
type: HookInputEventType;
|
|
152
|
+
payload: Record<string, unknown>;
|
|
153
|
+
receivedAt?: string;
|
|
154
|
+
}): HookEventV1 {
|
|
155
|
+
return normalizeHookEvent({
|
|
156
|
+
pluginId: "codex",
|
|
157
|
+
agent: "codex",
|
|
158
|
+
type: input.type,
|
|
159
|
+
payload: input.payload,
|
|
160
|
+
receivedAt: input.receivedAt,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function normalizeCodexRuntimeHookPayload(input: {
|
|
165
|
+
payload: Record<string, unknown>;
|
|
166
|
+
receivedAt?: string;
|
|
167
|
+
}): HookEventV1 {
|
|
168
|
+
const type =
|
|
169
|
+
input.payload.hook_event_name ??
|
|
170
|
+
input.payload.hookEventName ??
|
|
171
|
+
input.payload.event ??
|
|
172
|
+
input.payload.name;
|
|
173
|
+
if (typeof type !== "string" || type.trim() === "") {
|
|
174
|
+
throw new Error("Codex hook payload is missing hook_event_name.");
|
|
175
|
+
}
|
|
176
|
+
return normalizeCodexHookPayload({
|
|
177
|
+
type: type as HookInputEventType,
|
|
178
|
+
payload: input.payload,
|
|
179
|
+
receivedAt: input.receivedAt,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function createClaudeHookConfig(
|
|
184
|
+
command: string = CLAUDE_HOOK_RUNTIME_COMMAND,
|
|
185
|
+
): ClaudeHookConfig {
|
|
186
|
+
const hooks: Partial<Record<CanonicalHookEventType, ClaudeHookMatcherGroup[]>> = {};
|
|
187
|
+
for (const event of CLAUDE_RUNTIME_EVENTS) {
|
|
188
|
+
hooks[event] = [
|
|
189
|
+
{
|
|
190
|
+
...(CLAUDE_TOOL_EVENTS.has(event) ? { matcher: "*" } : {}),
|
|
191
|
+
hooks: [{ type: "command", command, timeout: event === "SessionEnd" ? 5 : 30 }],
|
|
192
|
+
},
|
|
193
|
+
];
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
description:
|
|
197
|
+
"EvoDev routes Claude Code lifecycle events through evodev hook runtime for Task Contract, workflow, policy, and evidence control.",
|
|
198
|
+
hooks,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function createCodexHookConfig(
|
|
203
|
+
command: string = CODEX_HOOK_RUNTIME_COMMAND,
|
|
204
|
+
): CodexHookConfig {
|
|
205
|
+
const hooks: Partial<Record<CanonicalHookEventType, ClaudeHookMatcherGroup[]>> = {};
|
|
206
|
+
for (const event of CODEX_RUNTIME_EVENTS) {
|
|
207
|
+
hooks[event] = [
|
|
208
|
+
{
|
|
209
|
+
...(CODEX_EVENT_MATCHERS[event] !== undefined
|
|
210
|
+
? { matcher: CODEX_EVENT_MATCHERS[event] }
|
|
211
|
+
: {}),
|
|
212
|
+
hooks: [{ type: "command", command, timeout: 30 }],
|
|
213
|
+
},
|
|
214
|
+
];
|
|
215
|
+
}
|
|
216
|
+
return { hooks };
|
|
217
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export {
|
|
2
|
+
type CodexCommandResult,
|
|
3
|
+
type CodexCommandRunner,
|
|
4
|
+
type CodexPluginOptions,
|
|
5
|
+
codexPlugin,
|
|
6
|
+
createCodexPlugin,
|
|
7
|
+
} from "./codex.ts";
|
|
8
|
+
|
|
9
|
+
export { type ClaudeCommandResult, type ClaudeCommandRunner, detectClaudeCode } from "./detect.ts";
|
|
10
|
+
export {
|
|
11
|
+
type ClaudePaths,
|
|
12
|
+
type ResolveClaudePathsOptions,
|
|
13
|
+
assertSafeClaudeAssetName,
|
|
14
|
+
resolveClaudeAgentTargetPath,
|
|
15
|
+
resolveClaudePaths,
|
|
16
|
+
resolveClaudeSkillTargetPath,
|
|
17
|
+
} from "./paths.ts";
|
|
18
|
+
export {
|
|
19
|
+
CLAUDE_HOOK_RUNTIME_COMMAND,
|
|
20
|
+
CODEX_HOOK_RUNTIME_COMMAND,
|
|
21
|
+
type ClaudeHookCommand,
|
|
22
|
+
type ClaudeHookConfig,
|
|
23
|
+
type ClaudeHookInstallDryRunInput,
|
|
24
|
+
type ClaudeHookInstallDryRunPlan,
|
|
25
|
+
type ClaudeHookMatcherGroup,
|
|
26
|
+
type CodexHookConfig,
|
|
27
|
+
createCodexHookConfig,
|
|
28
|
+
createClaudeHookConfig,
|
|
29
|
+
normalizeCodexHookPayload,
|
|
30
|
+
normalizeCodexRuntimeHookPayload,
|
|
31
|
+
normalizeClaudeHookPayload,
|
|
32
|
+
normalizeClaudeRuntimeHookPayload,
|
|
33
|
+
planClaudeHookInstallDryRun,
|
|
34
|
+
} from "./hooks.ts";
|
|
35
|
+
export {
|
|
36
|
+
type ClaudePathAccess,
|
|
37
|
+
type ClaudePathAccessResult,
|
|
38
|
+
type ClaudePluginOptions,
|
|
39
|
+
type ClaudeSyncFileSystem,
|
|
40
|
+
claudePlugin,
|
|
41
|
+
createClaudePlugin,
|
|
42
|
+
} from "./plugin.ts";
|
|
43
|
+
export {
|
|
44
|
+
type ClaudeAgentTransformInput,
|
|
45
|
+
type ClaudeAgentTransformResult,
|
|
46
|
+
transformClaudeAgent,
|
|
47
|
+
} from "./transform-agent.ts";
|
|
48
|
+
export {
|
|
49
|
+
type ClaudeSkillTransformInput,
|
|
50
|
+
type ClaudeSkillTransformResult,
|
|
51
|
+
transformClaudeSkill,
|
|
52
|
+
} from "./transform-skill.ts";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface ClaudePaths {
|
|
2
|
+
homeDir: string;
|
|
3
|
+
claudeDir: string;
|
|
4
|
+
settingsPath: string;
|
|
5
|
+
skillsDir: string;
|
|
6
|
+
agentsDir: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ResolveClaudePathsOptions {
|
|
10
|
+
homeDir: string;
|
|
11
|
+
claudeDir?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function resolveClaudePaths(options: ResolveClaudePathsOptions): ClaudePaths {
|
|
15
|
+
const homeDir = stripTrailingSlash(options.homeDir);
|
|
16
|
+
const claudeDir = stripTrailingSlash(options.claudeDir ?? `${homeDir}/.claude`);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
homeDir,
|
|
20
|
+
claudeDir,
|
|
21
|
+
settingsPath: `${claudeDir}/settings.json`,
|
|
22
|
+
skillsDir: `${claudeDir}/skills`,
|
|
23
|
+
agentsDir: `${claudeDir}/agents`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function resolveClaudeSkillTargetPath(skillName: string, paths: ClaudePaths): string {
|
|
28
|
+
const safeSkillName = assertSafeClaudeAssetName(skillName, "skillName");
|
|
29
|
+
return `${paths.skillsDir}/${safeSkillName}/SKILL.md`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function resolveClaudeAgentTargetPath(agentName: string, paths: ClaudePaths): string {
|
|
33
|
+
const safeAgentName = assertSafeClaudeAssetName(agentName, "agentName");
|
|
34
|
+
return `${paths.agentsDir}/${safeAgentName}.md`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function assertSafeClaudeAssetName(name: string, label = "name"): string {
|
|
38
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name) || name === "." || name === "..") {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`Invalid Claude asset ${label}: must be a single safe path segment using letters, numbers, dot, underscore, or hyphen`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return name;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function stripTrailingSlash(path: string): string {
|
|
48
|
+
if (path === "/") {
|
|
49
|
+
return path;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return path.replace(/\/+$/, "");
|
|
53
|
+
}
|