@evo-dev/evodev 0.0.1-alpha.1 → 0.0.1-alpha.2

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.
@@ -1,6 +1,9 @@
1
- import { copyFile, mkdir, readFile, stat, writeFile } from "node:fs/promises";
2
- import { dirname } from "node:path";
1
+ import type { Dirent } from "node:fs";
2
+ import { copyFile, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
3
5
  import {
6
+ CANONICAL_HOOK_EVENT_TYPES,
4
7
  type CanonicalHookEventType,
5
8
  type HookEventV1,
6
9
  type HookInputEventType,
@@ -76,9 +79,20 @@ export interface CodexHookConfig {
76
79
  }
77
80
 
78
81
  export const CLAUDE_HOOK_RUNTIME_COMMAND =
79
- 'bun run "${CLAUDE_PLUGIN_ROOT}/hooks/runtime.ts" hook runtime --target claude';
80
- export const CODEX_HOOK_RUNTIME_COMMAND =
81
- 'bun run "${PLUGIN_ROOT}/hooks/runtime.ts" hook runtime --target codex';
82
+ 'cd "${CLAUDE_PLUGIN_ROOT}" && bun run hooks/runtime.ts hook runtime --target claude';
83
+ export const DEFAULT_CLAUDE_PLUGIN_SELECTOR = "evodev@evo-dev";
84
+ export const CODEX_HOOK_RUNTIME_COMMAND = [
85
+ "sh -lc '",
86
+ 'root="${PLUGIN_ROOT:-}"; ',
87
+ 'if [ -z "$root" ]; then ',
88
+ 'for candidate in "$HOME/.codex/plugins/cache/evodev/evodev"/* "$HOME/.codex/plugins/evodev"; do ',
89
+ 'if [ -f "$candidate/hooks/runtime.ts" ]; then root="$candidate"; break; fi; ',
90
+ "done; ",
91
+ "fi; ",
92
+ 'if [ -z "$root" ] || [ ! -f "$root/hooks/runtime.ts" ]; then exit 0; fi; ',
93
+ 'cd "$root" && bun run hooks/runtime.ts hook runtime --target codex || exit 0',
94
+ "'",
95
+ ].join("");
82
96
  const CODEX_FEATURE_FLAGS = ["plugins", "plugin_hooks", "hooks"] as const;
83
97
  const CLAUDE_TOOL_EVENTS = new Set<CanonicalHookEventType>([
84
98
  "PreToolUse",
@@ -127,6 +141,10 @@ const CODEX_EVENT_MATCHERS: Partial<Record<CanonicalHookEventType, string>> = {
127
141
  SubagentStop: "*",
128
142
  Stop: "*",
129
143
  };
144
+ const RUNTIME_HOOK_EVENT_TYPES = [...CANONICAL_HOOK_EVENT_TYPES, "AgentStop"] as const;
145
+ const RUNTIME_HOOK_EVENT_TYPE_BY_KEY = new Map<string, HookInputEventType>(
146
+ RUNTIME_HOOK_EVENT_TYPES.map((type) => [normalizeRuntimeHookEventName(type), type]),
147
+ );
130
148
 
131
149
  export function planClaudeHookInstallDryRun(
132
150
  input: ClaudeHookInstallDryRunInput,
@@ -172,10 +190,15 @@ export async function installClaudeHooks(input: {
172
190
  homeDir: string;
173
191
  paths?: ClaudePaths;
174
192
  now?: string;
193
+ pluginSelector?: string;
175
194
  }): Promise<HookInstallResult> {
176
195
  const paths = input.paths ?? resolveClaudePaths({ homeDir: input.homeDir });
177
196
  const existing = await readTextIfExists(paths.settingsPath);
178
- const next = mergeClaudeSettingsHooks(existing, createClaudeHookConfig().hooks);
197
+ const runtimeCommand = await resolveClaudeUserHookRuntimeCommand({
198
+ paths,
199
+ pluginSelector: input.pluginSelector ?? DEFAULT_CLAUDE_PLUGIN_SELECTOR,
200
+ });
201
+ const next = mergeClaudeSettingsHooks(existing, createClaudeHookConfig(runtimeCommand).hooks);
179
202
  return writeMergedConfig({
180
203
  target: "claude",
181
204
  path: paths.settingsPath,
@@ -186,6 +209,101 @@ export async function installClaudeHooks(input: {
186
209
  });
187
210
  }
188
211
 
212
+ async function resolveClaudeUserHookRuntimeCommand(input: {
213
+ paths: ClaudePaths;
214
+ pluginSelector: string;
215
+ }): Promise<string> {
216
+ const runtimePath =
217
+ (await resolveInstalledClaudePluginRuntimePath(input)) ?? (await resolveLocalRuntimePath());
218
+ const pluginRoot = dirname(dirname(runtimePath));
219
+ return `cd ${shellQuote(pluginRoot)} && bun run hooks/runtime.ts hook runtime --target claude`;
220
+ }
221
+
222
+ async function resolveInstalledClaudePluginRuntimePath(input: {
223
+ paths: ClaudePaths;
224
+ pluginSelector: string;
225
+ }): Promise<string | null> {
226
+ const marketplaceName = extractMarketplaceNameFromSelector(input.pluginSelector);
227
+ const pluginName = extractPluginNameFromSelector(input.pluginSelector);
228
+ if (marketplaceName === null || pluginName === null) return null;
229
+ if (!isSafePluginCacheSegment(marketplaceName) || !isSafePluginCacheSegment(pluginName)) {
230
+ return null;
231
+ }
232
+
233
+ const cacheRoot = join(input.paths.claudeDir, "plugins", "cache", marketplaceName, pluginName);
234
+ let entries: Dirent[];
235
+ try {
236
+ entries = await readdir(cacheRoot, { withFileTypes: true });
237
+ } catch (error) {
238
+ if (isNotFoundError(error)) return null;
239
+ throw error;
240
+ }
241
+
242
+ const candidates = (
243
+ await Promise.all(
244
+ entries
245
+ .filter((entry) => entry.isDirectory())
246
+ .map(async (entry) => {
247
+ const runtimePath = join(cacheRoot, entry.name, "hooks", "runtime.ts");
248
+ try {
249
+ const runtimeStat = await stat(runtimePath);
250
+ return runtimeStat.isFile()
251
+ ? { path: runtimePath, mtimeMs: runtimeStat.mtimeMs }
252
+ : null;
253
+ } catch (error) {
254
+ if (isNotFoundError(error)) return null;
255
+ throw error;
256
+ }
257
+ }),
258
+ )
259
+ ).filter((candidate): candidate is { path: string; mtimeMs: number } => candidate !== null);
260
+
261
+ if (candidates.length === 0) return null;
262
+ candidates.sort(
263
+ (left, right) => right.mtimeMs - left.mtimeMs || right.path.localeCompare(left.path),
264
+ );
265
+ return candidates[0].path;
266
+ }
267
+
268
+ function extractMarketplaceNameFromSelector(selector: string): string | null {
269
+ const separator = selector.lastIndexOf("@");
270
+ if (separator <= 0 || separator === selector.length - 1) return null;
271
+ const marketplaceName = selector.slice(separator + 1).trim();
272
+ return marketplaceName === "" ? null : marketplaceName;
273
+ }
274
+
275
+ function extractPluginNameFromSelector(selector: string): string | null {
276
+ const separator = selector.lastIndexOf("@");
277
+ const pluginName = (separator <= 0 ? selector : selector.slice(0, separator)).trim();
278
+ return pluginName === "" ? null : pluginName;
279
+ }
280
+
281
+ function isSafePluginCacheSegment(segment: string): boolean {
282
+ return /^[A-Za-z0-9._-]+$/.test(segment) && segment !== "." && segment !== "..";
283
+ }
284
+
285
+ async function resolveLocalRuntimePath(): Promise<string> {
286
+ const currentDir = dirname(fileURLToPath(import.meta.url));
287
+ const candidates = [
288
+ join(currentDir, "runtime.ts"),
289
+ join(currentDir, "plugins", "evodev", "hooks", "runtime.ts"),
290
+ ];
291
+
292
+ for (const candidate of candidates) {
293
+ try {
294
+ const candidateStat = await stat(candidate);
295
+ if (candidateStat.isFile()) return candidate;
296
+ } catch (error) {
297
+ if (isNotFoundError(error)) continue;
298
+ throw error;
299
+ }
300
+ }
301
+
302
+ throw new Error(
303
+ `Cannot resolve Claude user-level hook runtime path. Checked: ${candidates.join(", ")}`,
304
+ );
305
+ }
306
+
189
307
  export async function installCodexHooks(input: {
190
308
  homeDir: string;
191
309
  paths?: CodexPaths;
@@ -225,12 +343,11 @@ export function normalizeClaudeRuntimeHookPayload(input: {
225
343
  payload: Record<string, unknown>;
226
344
  receivedAt?: string;
227
345
  }): HookEventV1 {
228
- const type = input.payload.hook_event_name ?? input.payload.hookEventName;
229
- if (typeof type !== "string" || type.trim() === "") {
230
- throw new Error("Claude hook payload is missing hook_event_name.");
231
- }
232
346
  return normalizeClaudeHookPayload({
233
- type: type as HookInputEventType,
347
+ type: readRuntimeHookEventType(
348
+ input.payload.hook_event_name ?? input.payload.hookEventName,
349
+ "Claude",
350
+ ),
234
351
  payload: input.payload,
235
352
  receivedAt: input.receivedAt,
236
353
  });
@@ -254,21 +371,34 @@ export function normalizeCodexRuntimeHookPayload(input: {
254
371
  payload: Record<string, unknown>;
255
372
  receivedAt?: string;
256
373
  }): HookEventV1 {
257
- const type =
258
- input.payload.hook_event_name ??
259
- input.payload.hookEventName ??
260
- input.payload.event ??
261
- input.payload.name;
262
- if (typeof type !== "string" || type.trim() === "") {
263
- throw new Error("Codex hook payload is missing hook_event_name.");
264
- }
265
374
  return normalizeCodexHookPayload({
266
- type: type as HookInputEventType,
375
+ type: readRuntimeHookEventType(
376
+ input.payload.hook_event_name ??
377
+ input.payload.hookEventName ??
378
+ input.payload.event ??
379
+ input.payload.name,
380
+ "Codex",
381
+ ),
267
382
  payload: input.payload,
268
383
  receivedAt: input.receivedAt,
269
384
  });
270
385
  }
271
386
 
387
+ function readRuntimeHookEventType(value: unknown, target: "Claude" | "Codex"): HookInputEventType {
388
+ if (typeof value !== "string" || value.trim() === "") {
389
+ throw new Error(`${target} hook payload is missing hook_event_name.`);
390
+ }
391
+ const normalized = RUNTIME_HOOK_EVENT_TYPE_BY_KEY.get(normalizeRuntimeHookEventName(value));
392
+ if (normalized === undefined) {
393
+ throw new Error(`Unsupported hook event type: ${value}`);
394
+ }
395
+ return normalized;
396
+ }
397
+
398
+ function normalizeRuntimeHookEventName(value: string): string {
399
+ return value.replace(/[^A-Za-z0-9]/g, "").toLowerCase();
400
+ }
401
+
272
402
  export function createClaudeHookConfig(
273
403
  command: string = CLAUDE_HOOK_RUNTIME_COMMAND,
274
404
  ): ClaudeHookConfig {
@@ -283,7 +413,7 @@ export function createClaudeHookConfig(
283
413
  }
284
414
  return {
285
415
  description:
286
- "EvoDev observes Claude Code lifecycle events through evodev hook runtime for local trace and advisory workflow suggestions.",
416
+ "EvoDev observes Claude Code lifecycle events through evodev hook runtime for local trace and action-required advisories.",
287
417
  hooks,
288
418
  };
289
419
  }
@@ -452,6 +582,10 @@ function backupTimestamp(value?: string): string {
452
582
  return source.replace(/[^0-9A-Za-z]/g, "").slice(0, 20) || "now";
453
583
  }
454
584
 
585
+ function shellQuote(value: string): string {
586
+ return `'${value.replace(/'/g, "'\\''")}'`;
587
+ }
588
+
455
589
  async function fileExists(path: string): Promise<boolean> {
456
590
  try {
457
591
  return (await stat(path)).isFile();
@@ -1,22 +1,20 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- import {
4
- type HookEventV1,
5
- type HookRuntimeResult,
6
- appendTraceLogEntry,
7
- createCoreConfigStore,
8
- createDefaultSettings,
9
- createTraceLogEntry,
10
- formatHookRuntimeOutput,
11
- handleHookRuntime,
12
- resolveTraceTeamContext,
13
- } from "@evo-dev/core";
14
- import { normalizeClaudeRuntimeHookPayload, normalizeCodexRuntimeHookPayload } from "./hooks.ts";
3
+ import type { HookEventV1, HookRuntimeResult } from "@evo-dev/core";
4
+
5
+ export type HookRuntimeCoreApi = typeof import("@evo-dev/core");
6
+ export type HookRuntimeNormalizerApi = typeof import("./hooks.ts");
7
+
8
+ export interface HookRuntimeApi {
9
+ core: HookRuntimeCoreApi;
10
+ normalizers: HookRuntimeNormalizerApi;
11
+ }
15
12
 
16
13
  export interface HookRuntimeCliOptions {
17
14
  argv?: string[];
18
15
  environment?: Record<string, string | undefined>;
19
16
  homeDir?: string;
17
+ loadRuntimeApi?: () => Promise<HookRuntimeApi>;
20
18
  stdin?: string | (() => Promise<string>);
21
19
  write?: (message: string) => void;
22
20
  }
@@ -26,7 +24,9 @@ export async function runHookRuntimeCli(options: HookRuntimeCliOptions = {}): Pr
26
24
  const environment = options.environment ?? process.env;
27
25
  const write = options.write ?? process.stdout.write.bind(process.stdout);
28
26
  const startedAt = new Date();
27
+ const loadRuntimeApi = options.loadRuntimeApi ?? loadDefaultHookRuntimeApi;
29
28
  let homeDir = options.homeDir ?? process.env.HOME ?? "~";
29
+ let runtimeApi: HookRuntimeApi | null = null;
30
30
  let target = "unknown";
31
31
  let payload: Record<string, unknown> | null = null;
32
32
  let stdinBytes: number | null = null;
@@ -45,8 +45,10 @@ export async function runHookRuntimeCli(options: HookRuntimeCliOptions = {}): Pr
45
45
  homeDir = options.homeDir ?? process.env.HOME ?? "~";
46
46
  const stdin = await readHookRuntimeStdin(options.stdin);
47
47
  stdinBytes = Buffer.byteLength(stdin, "utf8");
48
+ runtimeApi = await loadRuntimeApi();
48
49
  payload = JSON.parse(stdin) as Record<string, unknown>;
49
- await appendTraceLogSafely({
50
+ await appendExecutionEventSafely({
51
+ core: runtimeApi.core,
50
52
  homeDir,
51
53
  phase: "started",
52
54
  target,
@@ -56,28 +58,31 @@ export async function runHookRuntimeCli(options: HookRuntimeCliOptions = {}): Pr
56
58
  environment,
57
59
  });
58
60
 
59
- const settings = await readHookSettings(homeDir);
61
+ const settings = await readHookSettings(runtimeApi.core, homeDir);
60
62
  const event =
61
63
  flags.target === "codex"
62
- ? normalizeCodexRuntimeHookPayload({
64
+ ? runtimeApi.normalizers.normalizeCodexRuntimeHookPayload({
63
65
  payload,
64
66
  receivedAt: new Date().toISOString(),
65
67
  })
66
- : normalizeClaudeRuntimeHookPayload({
68
+ : runtimeApi.normalizers.normalizeClaudeRuntimeHookPayload({
67
69
  payload,
68
70
  receivedAt: new Date().toISOString(),
69
71
  });
70
- const result = await handleHookRuntime({
72
+ const result = await runtimeApi.core.handleHookRuntime({
71
73
  target: flags.target,
72
74
  homeDir,
73
75
  settings: settings.hooks,
76
+ teamRuntimeDisplayMode: settings.teamRuntime.displayMode,
74
77
  event,
75
78
  rawPayload: payload,
76
79
  receivedAt: event.time.receivedAt,
77
80
  environment,
81
+ runtimeInjectionEnabled: settings.memory.runtimeInjection,
78
82
  });
79
- const formatted = formatHookRuntimeOutput(result);
80
- await appendTraceLogSafely({
83
+ const formatted = runtimeApi.core.formatHookRuntimeOutput(result);
84
+ await appendExecutionEventSafely({
85
+ core: runtimeApi.core,
81
86
  homeDir,
82
87
  phase: "completed",
83
88
  target,
@@ -86,14 +91,14 @@ export async function runHookRuntimeCli(options: HookRuntimeCliOptions = {}): Pr
86
91
  stdinBytes,
87
92
  event,
88
93
  result,
89
- formatted,
90
94
  environment,
91
95
  durationMs: Date.now() - startedAt.getTime(),
92
96
  });
93
97
  if (formatted.length > 0) write(formatted);
94
98
  return 0;
95
99
  } catch (error) {
96
- await appendTraceLogSafely({
100
+ await appendExecutionEventSafely({
101
+ core: runtimeApi?.core,
97
102
  homeDir,
98
103
  phase: "failed",
99
104
  target,
@@ -104,10 +109,15 @@ export async function runHookRuntimeCli(options: HookRuntimeCliOptions = {}): Pr
104
109
  environment,
105
110
  durationMs: Date.now() - startedAt.getTime(),
106
111
  });
107
- throw error;
112
+ return 0;
108
113
  }
109
114
  }
110
115
 
116
+ async function loadDefaultHookRuntimeApi(): Promise<HookRuntimeApi> {
117
+ const [core, normalizers] = await Promise.all([import("@evo-dev/core"), import("./hooks.ts")]);
118
+ return { core, normalizers };
119
+ }
120
+
111
121
  function parseHookRuntimeFlags(argv: string[]): { target: string } {
112
122
  let target: string | undefined;
113
123
  for (let index = 0; index < argv.length; index += 1) {
@@ -138,18 +148,19 @@ async function readHookRuntimeStdin(stdin: HookRuntimeCliOptions["stdin"]): Prom
138
148
  return Buffer.concat(chunks).toString("utf8");
139
149
  }
140
150
 
141
- async function readHookSettings(homeDir: string) {
151
+ async function readHookSettings(core: HookRuntimeCoreApi, homeDir: string) {
142
152
  try {
143
- return await createCoreConfigStore(homeDir).readSettings();
153
+ return await core.createCoreConfigStore(homeDir).readSettings();
144
154
  } catch (error) {
145
155
  if (isNotFoundError(error)) {
146
- return createDefaultSettings();
156
+ return core.createDefaultSettings();
147
157
  }
148
- throw error;
158
+ return core.createDefaultSettings();
149
159
  }
150
160
  }
151
161
 
152
- async function appendTraceLogSafely(input: {
162
+ async function appendExecutionEventSafely(input: {
163
+ core?: HookRuntimeCoreApi;
153
164
  homeDir: string;
154
165
  phase: "started" | "completed" | "failed";
155
166
  target: string;
@@ -158,56 +169,115 @@ async function appendTraceLogSafely(input: {
158
169
  stdinBytes: number | null;
159
170
  event?: HookEventV1;
160
171
  result?: HookRuntimeResult;
161
- formatted?: string;
162
172
  durationMs?: number | null;
163
173
  error?: unknown;
164
174
  environment?: Record<string, string | undefined>;
165
175
  }): Promise<void> {
176
+ if (input.core === undefined) return;
177
+
166
178
  try {
167
- await appendTraceLogEntry(
179
+ const sessionKey =
180
+ input.payload === null ? "session-local" : input.core.resolveTraceSessionKey(input.payload);
181
+ const team = input.core.resolveTraceTeamContext({
182
+ homeDir: input.homeDir,
183
+ environment: input.environment,
184
+ payload: input.payload,
185
+ });
186
+ const traceRefId = await recordTraceRefSafely(input);
187
+ await input.core.appendEvoDevExecutionEvent(
168
188
  input.homeDir,
169
- createTraceLogEntry({
170
- phase: input.phase,
189
+ input.core.createEvoDevExecutionEvent({
190
+ eventId: input.event?.eventId,
171
191
  target: input.target,
172
- runtime: {
173
- surface: "plugin",
174
- argv: input.argv,
175
- runtimeFile: import.meta.url,
176
- },
177
- payload: input.payload,
178
- stdinBytes: input.stdinBytes,
179
- team: resolveTraceTeamContext({
180
- homeDir: input.homeDir,
181
- environment: input.environment,
182
- payload: input.payload,
183
- }),
184
- event:
185
- input.event === undefined
186
- ? null
187
- : {
188
- eventId: input.event.eventId,
189
- type: input.event.type,
190
- summary: input.event.payload.summary,
191
- metadata: input.event.payload.metadata,
192
- decision: input.event.decision,
193
- },
194
- result:
195
- input.result === undefined
196
- ? null
197
- : {
198
- enabled: input.result.enabled,
199
- summary: input.result.summary,
200
- stateWrites: input.result.stateWrites,
201
- warnings: input.result.warnings,
202
- formattedResponse: input.formatted?.trim() || null,
203
- durationMs: input.durationMs ?? null,
204
- },
205
- error: input.error,
192
+ eventType: input.event?.type ?? runtimePhaseEventType(input.phase),
193
+ sessionKey,
194
+ projectKey: team?.projectKey ?? null,
195
+ runId: team?.runId ?? null,
196
+ roleId: team?.roleId ?? null,
197
+ taskId: input.event?.scope.taskId ?? null,
198
+ summary: summarizeExecutionEvent(input),
199
+ metadata: createExecutionEventMetadata(input),
200
+ decision: input.event?.decision ?? null,
201
+ codeAgentTraceRefId: traceRefId,
206
202
  }),
207
203
  );
208
204
  } catch {
209
- // Trace logging must never change hook runtime behavior.
205
+ // Execution event logging must never change hook runtime behavior.
206
+ }
207
+ }
208
+
209
+ async function recordTraceRefSafely(input: {
210
+ core?: HookRuntimeCoreApi;
211
+ homeDir: string;
212
+ target: string;
213
+ payload: Record<string, unknown> | null;
214
+ event?: HookEventV1;
215
+ environment?: Record<string, string | undefined>;
216
+ }): Promise<string | null> {
217
+ if (
218
+ input.core === undefined ||
219
+ input.payload === null ||
220
+ (input.target !== "claude" && input.target !== "codex")
221
+ ) {
222
+ return null;
210
223
  }
224
+ try {
225
+ const record = await input.core.recordCodeAgentTraceRefFromHook({
226
+ homeDir: input.homeDir,
227
+ target: input.target,
228
+ payload: input.payload,
229
+ environment: input.environment,
230
+ now:
231
+ input.event?.time.receivedAt === undefined || input.event.time.receivedAt === "dry-run"
232
+ ? undefined
233
+ : input.event.time.receivedAt,
234
+ });
235
+ return record?.ref.id ?? null;
236
+ } catch {
237
+ return null;
238
+ }
239
+ }
240
+
241
+ function runtimePhaseEventType(phase: "started" | "completed" | "failed"): string {
242
+ if (phase === "started") return "HookRuntimeStarted";
243
+ if (phase === "completed") return "HookRuntimeCompleted";
244
+ return "HookRuntimeFailed";
245
+ }
246
+
247
+ function summarizeExecutionEvent(input: {
248
+ phase: "started" | "completed" | "failed";
249
+ event?: HookEventV1;
250
+ result?: HookRuntimeResult;
251
+ error?: unknown;
252
+ }): string {
253
+ if (input.phase === "failed") return "Hook runtime failed before completion.";
254
+ if (input.result !== undefined) return input.result.summary;
255
+ if (input.event !== undefined) return input.event.payload.summary;
256
+ return "Hook runtime started.";
257
+ }
258
+
259
+ function createExecutionEventMetadata(input: {
260
+ phase: "started" | "completed" | "failed";
261
+ stdinBytes: number | null;
262
+ event?: HookEventV1;
263
+ result?: HookRuntimeResult;
264
+ durationMs?: number | null;
265
+ }): Record<string, unknown> {
266
+ return {
267
+ phase: input.phase,
268
+ runtimeSurface: "plugin",
269
+ stdinBytes: input.stdinBytes,
270
+ durationMs: input.durationMs ?? null,
271
+ enabled: input.result?.enabled,
272
+ stateWriteCount: input.result?.stateWrites.length,
273
+ warningCount: input.result?.warnings.length,
274
+ commandClass: input.event?.payload.metadata.commandClass,
275
+ exitCode: input.event?.payload.metadata.exitCode,
276
+ status: input.event?.payload.metadata.status ?? input.phase,
277
+ redactionCount: input.event?.payload.redactionCount,
278
+ redactionLabels: input.event?.payload.redactions,
279
+ normalizedEventType: input.event?.type,
280
+ };
211
281
  }
212
282
 
213
283
  function isNotFoundError(error: unknown): boolean {
@@ -222,7 +292,6 @@ if (import.meta.main) {
222
292
  try {
223
293
  process.exitCode = await runHookRuntimeCli();
224
294
  } catch (error) {
225
- console.error(error instanceof Error ? error.message : String(error));
226
- process.exitCode = 1;
295
+ process.exitCode = 0;
227
296
  }
228
297
  }
@@ -108,7 +108,6 @@ async function writeRuntimeCorePackage(input: {
108
108
  >;
109
109
  const runtimePackageJson = {
110
110
  ...sourcePackageJson,
111
- exports: rewritePackageExportsToSource(sourcePackageJson.exports),
112
111
  files: ["src", "assets", "package.json"],
113
112
  };
114
113
  await writeFile(
@@ -118,32 +117,6 @@ async function writeRuntimeCorePackage(input: {
118
117
  );
119
118
  }
120
119
 
121
- function rewritePackageExportsToSource(exportsValue: unknown): unknown {
122
- if (typeof exportsValue === "string") {
123
- return rewriteDistPathToSource(exportsValue);
124
- }
125
- if (Array.isArray(exportsValue)) {
126
- return exportsValue.map((value) => rewritePackageExportsToSource(value));
127
- }
128
- if (exportsValue !== null && typeof exportsValue === "object") {
129
- return Object.fromEntries(
130
- Object.entries(exportsValue).map(([key, value]) => [
131
- key,
132
- rewritePackageExportsToSource(value),
133
- ]),
134
- );
135
- }
136
- return exportsValue;
137
- }
138
-
139
- function rewriteDistPathToSource(path: string): string {
140
- if (!path.startsWith("./dist/") || !path.endsWith(".js")) {
141
- return path;
142
- }
143
-
144
- return `./src/${path.slice("./dist/".length, -".js".length)}.ts`;
145
- }
146
-
147
120
  async function isDirectory(path: string): Promise<boolean> {
148
121
  try {
149
122
  return (await stat(path)).isDirectory();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evo-dev/plugin",
3
- "version": "0.0.1-alpha.1",
3
+ "version": "0.0.1-alpha.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./hooks/index.ts"