@acpus/runtime 0.8.0 → 0.9.0-alpha.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/dist/.tsbuildinfo +1 -0
- package/dist/admission/input.d.ts +5 -0
- package/dist/admission/input.d.ts.map +1 -0
- package/dist/admission/input.js +17 -0
- package/dist/admission/input.js.map +1 -0
- package/dist/artifacts/rewrite.d.ts +7 -0
- package/dist/artifacts/rewrite.d.ts.map +1 -0
- package/dist/artifacts/rewrite.js +28 -0
- package/dist/artifacts/rewrite.js.map +1 -0
- package/dist/control/agent-overrides.d.ts +4 -0
- package/dist/control/agent-overrides.d.ts.map +1 -0
- package/dist/control/agent-overrides.js +40 -0
- package/dist/control/agent-overrides.js.map +1 -0
- package/dist/daemon/loop.d.ts +16 -0
- package/dist/daemon/loop.d.ts.map +1 -0
- package/dist/daemon/loop.js +191 -0
- package/dist/daemon/loop.js.map +1 -0
- package/dist/daemon/sessions.d.ts +23 -0
- package/dist/daemon/sessions.d.ts.map +1 -0
- package/dist/daemon/sessions.js +190 -0
- package/dist/daemon/sessions.js.map +1 -0
- package/dist/daemon/socket.d.ts +82 -0
- package/dist/daemon/socket.d.ts.map +1 -0
- package/dist/daemon/socket.js +341 -0
- package/dist/daemon/socket.js.map +1 -0
- package/dist/daemon/tick.d.ts +9 -0
- package/dist/daemon/tick.d.ts.map +1 -0
- package/dist/daemon/tick.js +18 -0
- package/dist/daemon/tick.js.map +1 -0
- package/dist/evaluation/admissible.d.ts +2 -0
- package/dist/evaluation/admissible.d.ts.map +1 -0
- package/dist/evaluation/admissible.js +50 -0
- package/dist/evaluation/admissible.js.map +1 -0
- package/dist/evaluation/evaluator.d.ts +14 -0
- package/dist/evaluation/evaluator.d.ts.map +1 -0
- package/dist/evaluation/evaluator.js +34 -0
- package/dist/evaluation/evaluator.js.map +1 -0
- package/dist/evaluation/loop-limit.d.ts +4 -0
- package/dist/evaluation/loop-limit.d.ts.map +1 -0
- package/dist/evaluation/loop-limit.js +9 -0
- package/dist/evaluation/loop-limit.js.map +1 -0
- package/dist/evaluation/schema.d.ts +4 -0
- package/dist/evaluation/schema.d.ts.map +1 -0
- package/dist/evaluation/schema.js +92 -0
- package/dist/evaluation/schema.js.map +1 -0
- package/dist/execution/advance.d.ts +18 -0
- package/dist/execution/advance.d.ts.map +1 -0
- package/dist/execution/advance.js +57 -0
- package/dist/execution/advance.js.map +1 -0
- package/dist/execution/agent-node.d.ts +23 -0
- package/dist/execution/agent-node.d.ts.map +1 -0
- package/dist/execution/agent-node.js +512 -0
- package/dist/execution/agent-node.js.map +1 -0
- package/dist/execution/duration.d.ts +2 -0
- package/dist/execution/duration.d.ts.map +1 -0
- package/dist/execution/duration.js +15 -0
- package/dist/execution/duration.js.map +1 -0
- package/dist/execution/ir.d.ts +3 -0
- package/dist/execution/ir.d.ts.map +1 -0
- package/dist/execution/ir.js +46 -0
- package/dist/execution/ir.js.map +1 -0
- package/dist/execution/scheduler.d.ts +59 -0
- package/dist/execution/scheduler.d.ts.map +1 -0
- package/dist/execution/scheduler.js +306 -0
- package/dist/execution/scheduler.js.map +1 -0
- package/dist/execution/task-executor.d.ts +14 -0
- package/dist/execution/task-executor.d.ts.map +1 -0
- package/dist/execution/task-executor.js +186 -0
- package/dist/execution/task-executor.js.map +1 -0
- package/dist/hooks/config.d.ts +32 -0
- package/dist/hooks/config.d.ts.map +1 -0
- package/dist/hooks/config.js +112 -0
- package/dist/hooks/config.js.map +1 -0
- package/dist/hooks/context.d.ts +50 -0
- package/dist/hooks/context.d.ts.map +1 -0
- package/dist/hooks/context.js +116 -0
- package/dist/hooks/context.js.map +1 -0
- package/dist/hooks/events.d.ts +22 -0
- package/dist/hooks/events.d.ts.map +1 -0
- package/dist/hooks/events.js +41 -0
- package/dist/hooks/events.js.map +1 -0
- package/dist/hooks/journal.d.ts +21 -19
- package/dist/hooks/journal.d.ts.map +1 -1
- package/dist/hooks/journal.js +1 -48
- package/dist/hooks/journal.js.map +1 -1
- package/dist/hooks/loader.d.ts +33 -39
- package/dist/hooks/loader.d.ts.map +1 -1
- package/dist/hooks/loader.js +79 -95
- package/dist/hooks/loader.js.map +1 -1
- package/dist/hooks/runner.d.ts +14 -41
- package/dist/hooks/runner.d.ts.map +1 -1
- package/dist/hooks/runner.js +177 -145
- package/dist/hooks/runner.js.map +1 -1
- package/dist/index.d.ts +13 -28
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -33
- package/dist/index.js.map +1 -1
- package/dist/runs/advance-runtime.d.ts +50 -0
- package/dist/runs/advance-runtime.d.ts.map +1 -0
- package/dist/runs/advance-runtime.js +82 -0
- package/dist/runs/advance-runtime.js.map +1 -0
- package/dist/runs/use-cases.d.ts +111 -0
- package/dist/runs/use-cases.d.ts.map +1 -0
- package/dist/runs/use-cases.js +539 -0
- package/dist/runs/use-cases.js.map +1 -0
- package/dist/scheduler/advance.d.ts +65 -0
- package/dist/scheduler/advance.d.ts.map +1 -0
- package/dist/scheduler/advance.js +435 -0
- package/dist/scheduler/advance.js.map +1 -0
- package/dist/scheduler/control.d.ts +49 -0
- package/dist/scheduler/control.d.ts.map +1 -0
- package/dist/scheduler/control.js +212 -0
- package/dist/scheduler/control.js.map +1 -0
- package/dist/scheduler/event-codec.d.ts +4 -0
- package/dist/scheduler/event-codec.d.ts.map +1 -0
- package/dist/scheduler/event-codec.js +57 -0
- package/dist/scheduler/event-codec.js.map +1 -0
- package/dist/scheduler/events.d.ts +193 -0
- package/dist/scheduler/events.d.ts.map +1 -0
- package/dist/scheduler/events.js +13 -0
- package/dist/scheduler/events.js.map +1 -0
- package/dist/scheduler/fork-seed.d.ts +38 -0
- package/dist/scheduler/fork-seed.d.ts.map +1 -0
- package/dist/scheduler/fork-seed.js +590 -0
- package/dist/scheduler/fork-seed.js.map +1 -0
- package/dist/scheduler/identity.d.ts +8 -0
- package/dist/scheduler/identity.d.ts.map +1 -0
- package/dist/scheduler/identity.js +49 -0
- package/dist/scheduler/identity.js.map +1 -0
- package/dist/scheduler/ir-walk.d.ts +3 -0
- package/dist/scheduler/ir-walk.d.ts.map +1 -0
- package/dist/scheduler/ir-walk.js +25 -0
- package/dist/scheduler/ir-walk.js.map +1 -0
- package/dist/scheduler/limiter.d.ts +7 -0
- package/dist/scheduler/limiter.d.ts.map +1 -0
- package/dist/scheduler/limiter.js +10 -0
- package/dist/scheduler/limiter.js.map +1 -0
- package/dist/scheduler/materialize.d.ts +7 -0
- package/dist/scheduler/materialize.d.ts.map +1 -0
- package/dist/scheduler/materialize.js +756 -0
- package/dist/scheduler/materialize.js.map +1 -0
- package/dist/scheduler/membership.d.ts +12 -0
- package/dist/scheduler/membership.d.ts.map +1 -0
- package/dist/scheduler/membership.js +74 -0
- package/dist/scheduler/membership.js.map +1 -0
- package/dist/scheduler/node-executor.d.ts +15 -0
- package/dist/scheduler/node-executor.d.ts.map +1 -0
- package/dist/scheduler/node-executor.js +69 -0
- package/dist/scheduler/node-executor.js.map +1 -0
- package/dist/scheduler/runtime-runner.d.ts +44 -0
- package/dist/scheduler/runtime-runner.d.ts.map +1 -0
- package/dist/scheduler/runtime-runner.js +155 -0
- package/dist/scheduler/runtime-runner.js.map +1 -0
- package/dist/scheduler/scope.d.ts +6 -0
- package/dist/scheduler/scope.d.ts.map +1 -0
- package/dist/scheduler/scope.js +56 -0
- package/dist/scheduler/scope.js.map +1 -0
- package/dist/scheduler/store-port.d.ts +211 -0
- package/dist/scheduler/store-port.d.ts.map +1 -0
- package/dist/scheduler/store-port.js +28 -0
- package/dist/scheduler/store-port.js.map +1 -0
- package/dist/scheduler/transitions.d.ts +89 -0
- package/dist/scheduler/transitions.d.ts.map +1 -0
- package/dist/scheduler/transitions.js +967 -0
- package/dist/scheduler/transitions.js.map +1 -0
- package/dist/scheduler/types.d.ts +146 -0
- package/dist/scheduler/types.d.ts.map +1 -0
- package/dist/{executors → scheduler}/types.js.map +1 -1
- package/dist/store/store.d.ts +390 -0
- package/dist/store/store.d.ts.map +1 -0
- package/dist/store/store.js +3053 -0
- package/dist/store/store.js.map +1 -0
- package/dist/visualization/overlay.d.ts +86 -0
- package/dist/visualization/overlay.d.ts.map +1 -0
- package/dist/visualization/overlay.js +161 -0
- package/dist/visualization/overlay.js.map +1 -0
- package/package.json +19 -37
- package/README.md +0 -7
- package/dist/agent-telemetry.d.ts +0 -56
- package/dist/agent-telemetry.d.ts.map +0 -1
- package/dist/agent-telemetry.js +0 -304
- package/dist/agent-telemetry.js.map +0 -1
- package/dist/artifacts.d.ts +0 -45
- package/dist/artifacts.d.ts.map +0 -1
- package/dist/artifacts.js +0 -163
- package/dist/artifacts.js.map +0 -1
- package/dist/attempt-artifacts.d.ts +0 -35
- package/dist/attempt-artifacts.d.ts.map +0 -1
- package/dist/attempt-artifacts.js +0 -90
- package/dist/attempt-artifacts.js.map +0 -1
- package/dist/client.d.ts +0 -82
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -200
- package/dist/client.js.map +0 -1
- package/dist/evaluator.d.ts +0 -36
- package/dist/evaluator.d.ts.map +0 -1
- package/dist/evaluator.js +0 -101
- package/dist/evaluator.js.map +0 -1
- package/dist/executors/agent.d.ts +0 -103
- package/dist/executors/agent.d.ts.map +0 -1
- package/dist/executors/agent.js +0 -516
- package/dist/executors/agent.js.map +0 -1
- package/dist/executors/mock-program.d.ts +0 -26
- package/dist/executors/mock-program.d.ts.map +0 -1
- package/dist/executors/mock-program.js +0 -100
- package/dist/executors/mock-program.js.map +0 -1
- package/dist/executors/output-preview.d.ts +0 -2
- package/dist/executors/output-preview.d.ts.map +0 -1
- package/dist/executors/output-preview.js +0 -20
- package/dist/executors/output-preview.js.map +0 -1
- package/dist/executors/program.d.ts +0 -30
- package/dist/executors/program.d.ts.map +0 -1
- package/dist/executors/program.js +0 -230
- package/dist/executors/program.js.map +0 -1
- package/dist/executors/types.d.ts +0 -32
- package/dist/executors/types.d.ts.map +0 -1
- package/dist/fork.d.ts +0 -74
- package/dist/fork.d.ts.map +0 -1
- package/dist/fork.js +0 -278
- package/dist/fork.js.map +0 -1
- package/dist/hooks/payload.d.ts +0 -17
- package/dist/hooks/payload.d.ts.map +0 -1
- package/dist/hooks/payload.js +0 -45
- package/dist/hooks/payload.js.map +0 -1
- package/dist/interpreter.d.ts +0 -168
- package/dist/interpreter.d.ts.map +0 -1
- package/dist/interpreter.js +0 -1747
- package/dist/interpreter.js.map +0 -1
- package/dist/keys.d.ts +0 -77
- package/dist/keys.d.ts.map +0 -1
- package/dist/keys.js +0 -382
- package/dist/keys.js.map +0 -1
- package/dist/run-control.d.ts +0 -45
- package/dist/run-control.d.ts.map +0 -1
- package/dist/run-control.js +0 -255
- package/dist/run-control.js.map +0 -1
- package/dist/run-id.d.ts +0 -3
- package/dist/run-id.d.ts.map +0 -1
- package/dist/run-id.js +0 -10
- package/dist/run-id.js.map +0 -1
- package/dist/state-machine.d.ts +0 -31
- package/dist/state-machine.d.ts.map +0 -1
- package/dist/state-machine.js +0 -102
- package/dist/state-machine.js.map +0 -1
- package/dist/store.d.ts +0 -92
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -420
- package/dist/store.js.map +0 -1
- package/dist/supervisor-app.d.ts +0 -27
- package/dist/supervisor-app.d.ts.map +0 -1
- package/dist/supervisor-app.js +0 -694
- package/dist/supervisor-app.js.map +0 -1
- package/dist/supervisor-discovery.d.ts +0 -18
- package/dist/supervisor-discovery.d.ts.map +0 -1
- package/dist/supervisor-discovery.js +0 -180
- package/dist/supervisor-discovery.js.map +0 -1
- package/dist/supervisor-entry.d.ts +0 -11
- package/dist/supervisor-entry.d.ts.map +0 -1
- package/dist/supervisor-entry.js +0 -50
- package/dist/supervisor-entry.js.map +0 -1
- package/dist/supervisor-lock.d.ts +0 -26
- package/dist/supervisor-lock.d.ts.map +0 -1
- package/dist/supervisor-lock.js +0 -49
- package/dist/supervisor-lock.js.map +0 -1
- package/dist/supervisor-runner.d.ts +0 -11
- package/dist/supervisor-runner.d.ts.map +0 -1
- package/dist/supervisor-runner.js +0 -128
- package/dist/supervisor-runner.js.map +0 -1
- package/dist/types.d.ts +0 -375
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -7
- package/dist/types.js.map +0 -1
- package/dist/validate-input.d.ts +0 -27
- package/dist/validate-input.d.ts.map +0 -1
- package/dist/validate-input.js +0 -56
- package/dist/validate-input.js.map +0 -1
- package/dist/validate-signal.d.ts +0 -14
- package/dist/validate-signal.d.ts.map +0 -1
- package/dist/validate-signal.js +0 -31
- package/dist/validate-signal.js.map +0 -1
- package/dist/workflow-context.d.ts +0 -4
- package/dist/workflow-context.d.ts.map +0 -1
- package/dist/workflow-context.js +0 -11
- package/dist/workflow-context.js.map +0 -1
- package/dist/workflow-outputs.d.ts +0 -9
- package/dist/workflow-outputs.d.ts.map +0 -1
- package/dist/workflow-outputs.js +0 -60
- package/dist/workflow-outputs.js.map +0 -1
- /package/dist/{executors → scheduler}/types.js +0 -0
package/dist/hooks/loader.js
CHANGED
|
@@ -1,110 +1,94 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { join
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { err, ok } from "neverthrow";
|
|
6
|
+
import { hookEvents, validateHooksFile } from "./config.js";
|
|
7
|
+
export function formatHookLoadError(error) {
|
|
8
|
+
if (error.type === "invalid-config") {
|
|
9
|
+
return `Invalid hooks config at ${error.path}: ${error.errors.map(item => `${item.path}: ${item.message}`).join("; ")}`;
|
|
10
|
+
}
|
|
11
|
+
return `Invalid hooks config at ${error.path}: ${error.message}`;
|
|
12
|
+
}
|
|
13
|
+
export function projectHooksPath(workspaceDir) {
|
|
14
|
+
return join(workspaceDir, ".acpus", "hooks.json");
|
|
15
|
+
}
|
|
16
|
+
export function globalHooksPath(homeDir = homedir()) {
|
|
17
|
+
return join(homeDir, ".acpus", "hooks.json");
|
|
10
18
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return
|
|
19
|
+
export async function loadHooksConfig(workspaceDir, options = {}) {
|
|
20
|
+
const scoped = await loadHooksConfigScopes(workspaceDir, options);
|
|
21
|
+
return scoped.map(scopes => scopes.flatMap(scope => scope.hooks));
|
|
14
22
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
export async function loadHooksConfigScopes(workspaceDir, options = {}) {
|
|
24
|
+
const project = await loadHooksConfigScope("project", projectHooksPath(workspaceDir));
|
|
25
|
+
if (project.isErr())
|
|
26
|
+
return err(project.error);
|
|
27
|
+
const global = await loadHooksConfigScope("global", globalHooksPath(options.homeDir));
|
|
28
|
+
if (global.isErr())
|
|
29
|
+
return err(global.error);
|
|
30
|
+
return ok([project.value, global.value]);
|
|
20
31
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
export async function loadHooksConfigScope(source, path) {
|
|
33
|
+
return loadScope(source, path);
|
|
34
|
+
}
|
|
35
|
+
export function flattenHooksFile(file, source, sourcePath) {
|
|
36
|
+
const hooks = [];
|
|
37
|
+
for (const event of hookEvents) {
|
|
38
|
+
const entries = file[event] ?? [];
|
|
39
|
+
for (const [definitionIndex, entry] of entries.entries()) {
|
|
40
|
+
const definitionHash = hashDefinition(source, sourcePath, event, definitionIndex, entry);
|
|
41
|
+
hooks.push({
|
|
42
|
+
...entry,
|
|
43
|
+
event,
|
|
44
|
+
source,
|
|
45
|
+
sourcePath,
|
|
46
|
+
definitionIndex,
|
|
47
|
+
definitionHash,
|
|
48
|
+
effectiveId: entry.id ?? `${source}:${event}:${definitionIndex}:${definitionHash.slice(0, 12)}`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
31
51
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return { path, config: {}, exists: true };
|
|
39
|
-
const parsed = parseYaml(raw);
|
|
40
|
-
validateHookConfig(parsed, path);
|
|
41
|
-
return { path, config: parsed, exists: true };
|
|
52
|
+
return hooks;
|
|
53
|
+
}
|
|
54
|
+
async function loadScope(source, path) {
|
|
55
|
+
let bytes;
|
|
56
|
+
try {
|
|
57
|
+
bytes = await readFile(path, "utf8");
|
|
42
58
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const merged = mergeHookConfigs(globalLayer.config, projectLayer.config);
|
|
48
|
-
return { merged, globalLayer, projectLayer };
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (isNotFound(error))
|
|
61
|
+
return ok({ source, path, hooks: [] });
|
|
62
|
+
return err({ type: "read-failed", source, path, message: error instanceof Error ? error.message : String(error) });
|
|
49
63
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
*/
|
|
54
|
-
freeze() {
|
|
55
|
-
const { merged, globalLayer, projectLayer } = this.load();
|
|
56
|
-
if (isEmptyHookConfig(merged))
|
|
57
|
-
return undefined;
|
|
58
|
-
return {
|
|
59
|
-
hash: hashHookConfig(merged),
|
|
60
|
-
globalConfigPath: globalLayer.exists ? globalLayer.path : undefined,
|
|
61
|
-
projectConfigPath: projectLayer.exists ? projectLayer.path : undefined,
|
|
62
|
-
mergedConfig: merged
|
|
63
|
-
};
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = JSON.parse(bytes);
|
|
64
67
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
function validateHookConfig(config, path) {
|
|
68
|
-
const [issue] = validateHookConfigShape(config);
|
|
69
|
-
if (!issue)
|
|
70
|
-
return;
|
|
71
|
-
throw new Error(`${path}: ${issue.path ? `${issue.path} ` : ""}${issue.message}`);
|
|
72
|
-
}
|
|
73
|
-
/** Concatenate handler arrays per key; global handlers precede project handlers. */
|
|
74
|
-
export function mergeHookConfigs(global, project) {
|
|
75
|
-
const injectors = {};
|
|
76
|
-
for (const key of INJECTOR_NAMES) {
|
|
77
|
-
const combined = [...(global.injectors?.[key] ?? []), ...(project.injectors?.[key] ?? [])];
|
|
78
|
-
if (combined.length > 0)
|
|
79
|
-
injectors[key] = combined;
|
|
80
|
-
}
|
|
81
|
-
const events = {};
|
|
82
|
-
for (const key of EVENT_NAMES) {
|
|
83
|
-
const combined = [...(global.events?.[key] ?? []), ...(project.events?.[key] ?? [])];
|
|
84
|
-
if (combined.length > 0)
|
|
85
|
-
events[key] = combined;
|
|
68
|
+
catch (error) {
|
|
69
|
+
return err({ type: "invalid-json", source, path, message: error instanceof Error ? error.message : String(error) });
|
|
86
70
|
}
|
|
87
|
-
const
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
71
|
+
const validated = validateHooksFile(parsed);
|
|
72
|
+
if (validated.isErr())
|
|
73
|
+
return err({ type: "invalid-config", source, path, errors: validated.error });
|
|
74
|
+
return ok({ source, path, hooks: flattenHooksFile(validated.value, source, path) });
|
|
75
|
+
}
|
|
76
|
+
function hashDefinition(source, sourcePath, event, definitionIndex, config) {
|
|
77
|
+
return createHash("sha256")
|
|
78
|
+
.update(stableJson({ source, sourcePath, event, definitionIndex, config }))
|
|
79
|
+
.digest("hex");
|
|
93
80
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return `sha256:${createHash("sha256").update(canonicalJson(config)).digest("hex")}`;
|
|
81
|
+
function stableJson(value) {
|
|
82
|
+
return JSON.stringify(sortValue(value));
|
|
97
83
|
}
|
|
98
|
-
|
|
99
|
-
function canonicalJson(value) {
|
|
84
|
+
function sortValue(value) {
|
|
100
85
|
if (Array.isArray(value))
|
|
101
|
-
return
|
|
102
|
-
if (value
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return JSON.stringify(value ?? null);
|
|
86
|
+
return value.map(sortValue);
|
|
87
|
+
if (!value || typeof value !== "object")
|
|
88
|
+
return value;
|
|
89
|
+
return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, sortValue(item)]));
|
|
90
|
+
}
|
|
91
|
+
function isNotFound(error) {
|
|
92
|
+
return !!error && typeof error === "object" && "code" in error && error.code === "ENOENT";
|
|
109
93
|
}
|
|
110
94
|
//# sourceMappingURL=loader.js.map
|
package/dist/hooks/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/hooks/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/hooks/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAqG,MAAM,aAAa,CAAC;AAa/J,MAAM,UAAU,mBAAmB,CAAC,KAAoB;IACtD,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;QACpC,OAAO,2BAA2B,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1H,CAAC;IACD,OAAO,2BAA2B,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,YAAoB;IACnD,OAAO,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAO,GAAG,OAAO,EAAE;IACjD,OAAO,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,YAAoB,EAAE,UAAgC,EAAE;IAC5F,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,YAAoB,EAAE,UAAgC,EAAE;IAClG,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,SAAS,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC;IACtF,IAAI,OAAO,CAAC,KAAK,EAAE;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IACtF,IAAI,MAAM,CAAC,KAAK,EAAE;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7C,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,MAAkB,EAAE,IAAY;IACzE,OAAO,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAe,EAAE,MAAkB,EAAE,UAAkB;IACtF,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAClC,KAAK,MAAM,CAAC,eAAe,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YACzD,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,CAAC,CAAC;YACzF,KAAK,CAAC,IAAI,CAAC;gBACT,GAAG,KAAK;gBACR,KAAK;gBACL,MAAM;gBACN,UAAU;gBACV,eAAe;gBACf,cAAc;gBACd,WAAW,EAAE,KAAK,CAAC,EAAE,IAAI,GAAG,MAAM,IAAI,KAAK,IAAI,eAAe,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE;aAChG,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,MAAkB,EAAE,IAAY;IACvD,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,UAAU,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9D,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACrH,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAY,CAAC;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtH,CAAC;IAED,MAAM,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,SAAS,CAAC,KAAK,EAAE;QAAE,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;IACrG,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,gBAAgB,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,cAAc,CAAC,MAAkB,EAAE,UAAkB,EAAE,KAAa,EAAE,eAAuB,EAAE,MAAkB;IACxH,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,CAAC;SAC1E,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACrJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,IAAK,KAA4B,CAAC,IAAI,KAAK,QAAQ,CAAC;AACpH,CAAC"}
|
package/dist/hooks/runner.d.ts
CHANGED
|
@@ -1,42 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
private readonly config;
|
|
16
|
-
constructor(config: HookConfig);
|
|
17
|
-
hasInjector(name: InjectorName): boolean;
|
|
18
|
-
hasEvent(name: EventName): boolean;
|
|
19
|
-
injectorHandlers(name: InjectorName): InjectorHookHandler[];
|
|
20
|
-
/**
|
|
21
|
-
* Run all handlers for an injector sequentially, merging their results.
|
|
22
|
-
* `prependPrompt` is concatenated in order for beforeAgentExec; `env` maps
|
|
23
|
-
* merge with later handlers overriding earlier ones for beforeProgramExec.
|
|
24
|
-
* A failing handler under `fail` throws
|
|
25
|
-
* HookFailureError; under `skip` it logs a warning and injects nothing.
|
|
26
|
-
*
|
|
27
|
-
* `onHandler` is called once per handler with the resolved per-handler result
|
|
28
|
-
* (for journaling).
|
|
29
|
-
*/
|
|
30
|
-
runInjector(name: InjectorName, payload: HookPayload, onHandler?: (handlerIndex: number, result: InjectorResult, durationMs: number) => void): Promise<InjectorResult>;
|
|
31
|
-
/**
|
|
32
|
-
* Fire all handlers for an event. Event handlers are async by default;
|
|
33
|
-
* `sync: true` handlers are awaited. Event handlers never throw and never
|
|
34
|
-
* affect Run/Node outcome — failures are logged as warnings.
|
|
35
|
-
*/
|
|
36
|
-
emitEvent(name: EventName, payload: HookPayload): Promise<void>;
|
|
37
|
-
private runHandler;
|
|
38
|
-
private runCommand;
|
|
39
|
-
/** Parse handler stdout as an InjectorResult. Empty output → empty result. */
|
|
40
|
-
private parseInjectorStdout;
|
|
41
|
-
}
|
|
1
|
+
import type { HookEvent, LoadedHookConfig } from "./config.js";
|
|
2
|
+
import type { HookContext } from "./context.js";
|
|
3
|
+
import type { HookJournalEntry } from "./journal.js";
|
|
4
|
+
export type HookRunner = {
|
|
5
|
+
trigger(event: HookEvent, context: HookContext): void;
|
|
6
|
+
drain(): Promise<void>;
|
|
7
|
+
activeCount(): number;
|
|
8
|
+
};
|
|
9
|
+
export type HookJournalWriter = {
|
|
10
|
+
writeHookJournal(entry: HookJournalEntry): void;
|
|
11
|
+
};
|
|
12
|
+
export declare function createHookRunner(hooks: readonly LoadedHookConfig[], journal: HookJournalWriter, options?: {
|
|
13
|
+
now?: () => Date;
|
|
14
|
+
}): HookRunner;
|
|
42
15
|
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/hooks/runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/hooks/runner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAa,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IACtD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,WAAW,IAAI,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACjD,CAAC;AAKF,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,gBAAgB,EAAE,EAClC,OAAO,EAAE,iBAAiB,EAC1B,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CAAO,GACjC,UAAU,CA0BZ"}
|
package/dist/hooks/runner.js
CHANGED
|
@@ -1,161 +1,193 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { parseDurationMs } from "
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
this.name = "HookFailureError";
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Executes hook command handlers. Injectors run sequentially and may fail the
|
|
17
|
-
* node; events never affect outcome. The runner holds the frozen, merged
|
|
18
|
-
* configuration for a single Run.
|
|
19
|
-
*/
|
|
20
|
-
export class HookRunner {
|
|
21
|
-
config;
|
|
22
|
-
constructor(config) {
|
|
23
|
-
this.config = config;
|
|
24
|
-
}
|
|
25
|
-
hasInjector(name) {
|
|
26
|
-
return (this.config.injectors?.[name]?.length ?? 0) > 0;
|
|
27
|
-
}
|
|
28
|
-
hasEvent(name) {
|
|
29
|
-
return (this.config.events?.[name]?.length ?? 0) > 0;
|
|
30
|
-
}
|
|
31
|
-
injectorHandlers(name) {
|
|
32
|
-
return this.config.injectors?.[name] ?? [];
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Run all handlers for an injector sequentially, merging their results.
|
|
36
|
-
* `prependPrompt` is concatenated in order for beforeAgentExec; `env` maps
|
|
37
|
-
* merge with later handlers overriding earlier ones for beforeProgramExec.
|
|
38
|
-
* A failing handler under `fail` throws
|
|
39
|
-
* HookFailureError; under `skip` it logs a warning and injects nothing.
|
|
40
|
-
*
|
|
41
|
-
* `onHandler` is called once per handler with the resolved per-handler result
|
|
42
|
-
* (for journaling).
|
|
43
|
-
*/
|
|
44
|
-
async runInjector(name, payload, onHandler) {
|
|
45
|
-
const handlers = this.injectorHandlers(name);
|
|
46
|
-
const contexts = [];
|
|
47
|
-
let env;
|
|
48
|
-
for (let i = 0; i < handlers.length; i++) {
|
|
49
|
-
const handler = handlers[i];
|
|
50
|
-
const started = Date.now();
|
|
51
|
-
const outcome = await this.runHandler(handler, payload, DEFAULT_INJECTOR_TIMEOUT_MS, true);
|
|
52
|
-
const durationMs = Date.now() - started;
|
|
53
|
-
if (!outcome.ok) {
|
|
54
|
-
const policy = handler.on_failure ?? "fail";
|
|
55
|
-
if (policy === "fail") {
|
|
56
|
-
throw new HookFailureError(`Injector '${name}' handler #${i} failed: ${outcome.error ?? "unknown error"}`);
|
|
57
|
-
}
|
|
58
|
-
console.warn(`Injector '${name}' handler #${i} failed (skipped): ${outcome.error ?? "unknown error"}`);
|
|
59
|
-
onHandler?.(i, {}, durationMs);
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { parseDurationMs } from "../execution/duration.js";
|
|
3
|
+
const defaultTimeout = "30s";
|
|
4
|
+
const outputLimit = 4 * 1024;
|
|
5
|
+
export function createHookRunner(hooks, journal, options = {}) {
|
|
6
|
+
const now = options.now ?? (() => new Date());
|
|
7
|
+
const active = new Set();
|
|
8
|
+
let nextTriggerOrder = 1;
|
|
9
|
+
function trigger(event, context) {
|
|
10
|
+
for (const hook of hooks) {
|
|
11
|
+
if (hook.event !== event || !matches(hook.match, context))
|
|
60
12
|
continue;
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
if (name === "beforeProgramExec") {
|
|
70
|
-
const programResult = result;
|
|
71
|
-
if (programResult.env && Object.keys(programResult.env).length > 0) {
|
|
72
|
-
env = { ...(env ?? {}), ...programResult.env };
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
onHandler?.(i, result, durationMs);
|
|
13
|
+
const startedAt = now();
|
|
14
|
+
const triggerOrder = nextTriggerOrder++;
|
|
15
|
+
const running = spawnHook(hook, context, startedAt, triggerOrder, journal)
|
|
16
|
+
.catch(() => undefined)
|
|
17
|
+
.finally(() => active.delete(running));
|
|
18
|
+
active.add(running);
|
|
76
19
|
}
|
|
77
|
-
if (name === "beforeAgentExec") {
|
|
78
|
-
const merged = {};
|
|
79
|
-
if (contexts.length > 0)
|
|
80
|
-
merged.prependPrompt = contexts.join("\n");
|
|
81
|
-
return merged;
|
|
82
|
-
}
|
|
83
|
-
const merged = {};
|
|
84
|
-
if (env)
|
|
85
|
-
merged.env = env;
|
|
86
|
-
return merged;
|
|
87
20
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
21
|
+
return {
|
|
22
|
+
trigger,
|
|
23
|
+
async drain() {
|
|
24
|
+
await Promise.all([...active]);
|
|
25
|
+
},
|
|
26
|
+
activeCount() {
|
|
27
|
+
return active.size;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function matches(match, context) {
|
|
32
|
+
if (!match)
|
|
33
|
+
return true;
|
|
34
|
+
return matchesField(match.workflow, context.run.workflowName)
|
|
35
|
+
&& matchesField(match.nodeId, context.node?.id)
|
|
36
|
+
&& matchesField(match.nodeKey, context.node?.key)
|
|
37
|
+
&& matchesField(match.kind, context.node?.kind);
|
|
38
|
+
}
|
|
39
|
+
function matchesField(regex, value) {
|
|
40
|
+
return regex === undefined || (value !== undefined && new RegExp(regex).test(value));
|
|
41
|
+
}
|
|
42
|
+
async function spawnHook(hook, context, startedAt, triggerOrder, journal) {
|
|
43
|
+
const timeoutMs = parseDurationMs(hook.timeout ?? defaultTimeout);
|
|
44
|
+
const startedMs = startedAt.getTime();
|
|
45
|
+
const result = await runShellCommand(hook.command, context, timeoutMs);
|
|
46
|
+
writeJournal(journal, journalEntry(hook, context, triggerOrder, {
|
|
47
|
+
...result,
|
|
48
|
+
durationMs: Math.max(0, Date.now() - startedMs),
|
|
49
|
+
triggeredAt: startedAt.toISOString(),
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
function runShellCommand(command, context, timeoutMs) {
|
|
53
|
+
return new Promise(resolve => {
|
|
54
|
+
const child = spawn(command, { shell: true, cwd: context.run.workspaceDir, detached: process.platform !== "win32" });
|
|
55
|
+
const stdout = new OutputCollector(outputLimit);
|
|
56
|
+
const stderr = new OutputCollector(outputLimit);
|
|
57
|
+
let timedOut = false;
|
|
58
|
+
let settled = false;
|
|
59
|
+
let killTimer;
|
|
60
|
+
const timeout = setTimeout(() => {
|
|
61
|
+
timedOut = true;
|
|
62
|
+
killProcessTree(child.pid, "SIGTERM");
|
|
63
|
+
killTimer = setTimeout(() => killProcessTree(child.pid, "SIGKILL"), 2_000);
|
|
64
|
+
}, timeoutMs);
|
|
65
|
+
child.stdout?.on("data", chunk => stdout.append(Buffer.from(chunk)));
|
|
66
|
+
child.stderr?.on("data", chunk => stderr.append(Buffer.from(chunk)));
|
|
67
|
+
child.stdin?.on("error", () => {
|
|
68
|
+
// Hooks are non-interfering; a command that exits before reading stdin
|
|
69
|
+
// should be recorded from process close/error, not crash the daemon.
|
|
70
|
+
});
|
|
71
|
+
child.on("error", error => finish({
|
|
72
|
+
status: "failed",
|
|
73
|
+
stdout: stdout.toString(),
|
|
74
|
+
stderr: stderr.toString(),
|
|
75
|
+
error: error.message,
|
|
76
|
+
}));
|
|
77
|
+
child.on("close", code => finish({
|
|
78
|
+
status: timedOut ? "timed_out" : code === 0 ? "completed" : "failed",
|
|
79
|
+
...(timedOut || code === null ? {} : { exitCode: code }),
|
|
80
|
+
stdout: stdout.toString(),
|
|
81
|
+
stderr: stderr.toString(),
|
|
82
|
+
...(timedOut ? { error: "timeout" } : code === 0 ? {} : { error: `exit_code_${code ?? "null"}` }),
|
|
83
|
+
}));
|
|
84
|
+
child.stdin?.end(JSON.stringify(context));
|
|
85
|
+
function finish(result) {
|
|
86
|
+
if (settled)
|
|
87
|
+
return;
|
|
88
|
+
settled = true;
|
|
89
|
+
clearTimeout(timeout);
|
|
90
|
+
if (killTimer)
|
|
91
|
+
clearTimeout(killTimer);
|
|
92
|
+
resolve(result);
|
|
108
93
|
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function journalEntry(hook, context, triggerOrder, result) {
|
|
97
|
+
return {
|
|
98
|
+
runId: context.run.id,
|
|
99
|
+
eventSequence: context.eventSequence,
|
|
100
|
+
triggerOrder,
|
|
101
|
+
event: context.event,
|
|
102
|
+
source: hook.source,
|
|
103
|
+
sourcePath: hook.sourcePath,
|
|
104
|
+
handlerId: hook.id ?? hook.effectiveId,
|
|
105
|
+
definitionHash: hook.definitionHash,
|
|
106
|
+
...(context.node?.key === undefined ? {} : { nodeKey: context.node.key }),
|
|
107
|
+
status: result.status,
|
|
108
|
+
...(result.exitCode === undefined ? {} : { exitCode: result.exitCode }),
|
|
109
|
+
...(result.stdout === undefined ? {} : { stdout: result.stdout }),
|
|
110
|
+
...(result.stderr === undefined ? {} : { stderr: result.stderr }),
|
|
111
|
+
...(result.durationMs === undefined ? {} : { durationMs: result.durationMs }),
|
|
112
|
+
...(result.error === undefined ? {} : { error: result.error }),
|
|
113
|
+
triggeredAt: result.triggeredAt,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function writeJournal(journal, entry) {
|
|
117
|
+
try {
|
|
118
|
+
journal.writeHookJournal(entry);
|
|
109
119
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const timeoutMs = handler.timeout ? parseDurationMs(handler.timeout) || defaultTimeoutMs : defaultTimeoutMs;
|
|
113
|
-
return this.runCommand(handler, payload, timeoutMs, parseResult);
|
|
120
|
+
catch {
|
|
121
|
+
// Hooks are non-interfering; journal failures must not affect workflow execution.
|
|
114
122
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
env: handler.env
|
|
124
|
-
? { ...Object.fromEntries(Object.entries(process.env).filter(([, v]) => v !== undefined)), ...handler.env }
|
|
125
|
-
: undefined
|
|
126
|
-
});
|
|
127
|
-
if (result.timedOut) {
|
|
128
|
-
return { ok: false, error: `timed out after ${timeoutMs}ms` };
|
|
129
|
-
}
|
|
130
|
-
if ((result.exitCode ?? 0) !== 0) {
|
|
131
|
-
return { ok: false, error: `exit code ${result.exitCode}: ${stderrTail(result.stderr)}` };
|
|
132
|
-
}
|
|
133
|
-
if (!parseResult)
|
|
134
|
-
return { ok: true };
|
|
135
|
-
return this.parseInjectorStdout(result.stdout ?? "");
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
123
|
+
}
|
|
124
|
+
function killProcessTree(pid, signal) {
|
|
125
|
+
if (pid === undefined)
|
|
126
|
+
return;
|
|
127
|
+
try {
|
|
128
|
+
if (process.platform === "win32") {
|
|
129
|
+
spawn("taskkill", ["/pid", String(pid), "/T", signal === "SIGKILL" ? "/F" : ""].filter(Boolean), { stdio: "ignore" }).unref();
|
|
130
|
+
return;
|
|
139
131
|
}
|
|
132
|
+
process.kill(-pid, signal);
|
|
140
133
|
}
|
|
141
|
-
|
|
142
|
-
parseInjectorStdout(raw) {
|
|
143
|
-
const trimmed = raw.trim();
|
|
144
|
-
if (trimmed.length === 0)
|
|
145
|
-
return { ok: true, result: {} };
|
|
134
|
+
catch {
|
|
146
135
|
try {
|
|
147
|
-
|
|
148
|
-
return { ok: true, result: parsed ?? {} };
|
|
136
|
+
process.kill(pid, signal);
|
|
149
137
|
}
|
|
150
138
|
catch {
|
|
151
|
-
|
|
139
|
+
// Best effort; hook timeout is non-interfering.
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
class OutputCollector {
|
|
144
|
+
limit;
|
|
145
|
+
full = Buffer.alloc(0);
|
|
146
|
+
head = Buffer.alloc(0);
|
|
147
|
+
tail = Buffer.alloc(0);
|
|
148
|
+
total = 0;
|
|
149
|
+
truncated = false;
|
|
150
|
+
constructor(limit) {
|
|
151
|
+
this.limit = limit;
|
|
152
|
+
}
|
|
153
|
+
append(chunk) {
|
|
154
|
+
const nextTotal = this.total + chunk.length;
|
|
155
|
+
if (!this.truncated && nextTotal <= this.limit * 2) {
|
|
156
|
+
this.full = Buffer.concat([this.full, chunk]);
|
|
157
|
+
this.total = nextTotal;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (!this.truncated) {
|
|
161
|
+
this.head = this.full.length >= this.limit
|
|
162
|
+
? this.full.subarray(0, this.limit)
|
|
163
|
+
: Buffer.concat([this.full, chunk.subarray(0, this.limit - this.full.length)]);
|
|
164
|
+
this.tail = lastBytes(this.full.subarray(Math.max(0, this.full.length - this.limit)), chunk, this.limit);
|
|
165
|
+
this.full = Buffer.alloc(0);
|
|
166
|
+
this.truncated = true;
|
|
167
|
+
this.total = nextTotal;
|
|
168
|
+
return;
|
|
152
169
|
}
|
|
170
|
+
this.total += chunk.length;
|
|
171
|
+
this.tail = lastBytes(this.tail, chunk, this.limit);
|
|
153
172
|
}
|
|
173
|
+
toString() {
|
|
174
|
+
return boundedUtf8(this.truncated ? Buffer.concat([this.head, this.tail]) : this.full, this.limit * 2);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function lastBytes(previousTail, chunk, limit) {
|
|
178
|
+
if (chunk.length >= limit)
|
|
179
|
+
return chunk.subarray(chunk.length - limit);
|
|
180
|
+
const combined = Buffer.concat([previousTail, chunk]);
|
|
181
|
+
return combined.length <= limit ? combined : combined.subarray(combined.length - limit);
|
|
154
182
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
183
|
+
function boundedUtf8(buffer, maxBytes) {
|
|
184
|
+
let end = Math.min(buffer.length, maxBytes);
|
|
185
|
+
while (end >= 0) {
|
|
186
|
+
const value = buffer.subarray(0, end).toString("utf8");
|
|
187
|
+
if (Buffer.byteLength(value, "utf8") <= maxBytes)
|
|
188
|
+
return value;
|
|
189
|
+
end -= 1;
|
|
190
|
+
}
|
|
191
|
+
return "";
|
|
160
192
|
}
|
|
161
193
|
//# sourceMappingURL=runner.js.map
|