@h-rig/core 0.0.6-alpha.17 → 0.0.6-alpha.170
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/src/agent-role-registry.d.ts +4 -0
- package/dist/src/agent-role-registry.js +27 -0
- package/dist/src/authority-paths.d.ts +15 -0
- package/dist/src/authority-paths.js +80 -0
- package/dist/src/baked-secrets.d.ts +6 -0
- package/dist/src/baked-secrets.js +121 -0
- package/dist/src/build-time-config.d.ts +12 -0
- package/dist/src/build-time-config.js +25 -0
- package/dist/src/build-time-config.macro.d.ts +1 -0
- package/dist/src/capability-loaders.d.ts +51 -0
- package/dist/src/capability-loaders.js +758 -0
- package/dist/src/capability.d.ts +79 -0
- package/dist/src/capability.js +63 -0
- package/dist/src/checkout-root.d.ts +1 -0
- package/dist/src/checkout-root.js +30 -0
- package/dist/src/config-env.d.ts +4 -0
- package/dist/src/config-env.js +23 -0
- package/dist/src/config.d.ts +3 -0
- package/dist/src/config.js +44 -0
- package/dist/src/declarative-config.d.ts +14 -0
- package/dist/src/declarative-config.js +82 -0
- package/dist/src/default-kernel.d.ts +1 -0
- package/dist/src/default-kernel.js +12 -0
- package/dist/src/define-config.d.ts +20 -0
- package/dist/src/define-config.js +28 -15
- package/dist/src/define-plugin.d.ts +13 -0
- package/dist/src/define-plugin.js +4 -43
- package/dist/src/embedded-plugins.d.ts +59 -0
- package/dist/src/embedded-plugins.js +22 -0
- package/dist/src/exec.d.ts +13 -0
- package/dist/src/exec.js +101 -0
- package/dist/src/harness-paths.d.ts +18 -0
- package/dist/src/harness-paths.js +141 -0
- package/dist/src/hook-materializer.d.ts +72 -0
- package/dist/src/hook-materializer.js +281 -0
- package/dist/src/hook-protocol.d.ts +2 -0
- package/dist/src/hook-protocol.js +462 -0
- package/dist/src/hook-runner.d.ts +48 -0
- package/dist/src/hook-runner.js +756 -0
- package/dist/src/hook-runtime.d.ts +52 -0
- package/dist/src/hook-runtime.js +462 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.js +210 -2499
- package/dist/src/json-files.d.ts +9 -0
- package/dist/src/json-files.js +125 -0
- package/dist/src/kernel-boot.d.ts +2 -0
- package/dist/src/kernel-boot.js +10 -0
- package/dist/src/kernel-entrypoint.d.ts +22 -0
- package/dist/src/kernel-entrypoint.js +548 -0
- package/dist/src/kernel-plugin-abi.d.ts +1 -0
- package/dist/src/kernel-plugin-abi.js +1 -0
- package/dist/src/kernel-resolver.d.ts +2 -0
- package/dist/src/kernel-resolver.js +6 -0
- package/dist/src/layout.d.ts +10 -0
- package/dist/src/layout.js +144 -0
- package/dist/src/load-config.d.ts +2 -0
- package/dist/src/load-config.js +423 -30
- package/dist/src/placement.d.ts +50 -0
- package/dist/src/placement.js +996 -0
- package/dist/src/plugin-host-context.d.ts +66 -0
- package/dist/src/plugin-host-context.js +1292 -0
- package/dist/src/plugin-host-registries.d.ts +31 -0
- package/dist/src/plugin-host-registries.js +79 -0
- package/dist/src/plugin-host.d.ts +77 -0
- package/dist/src/plugin-host.js +127 -63
- package/dist/src/plugin-runtime.d.ts +173 -0
- package/dist/src/profile-ops.d.ts +9 -0
- package/dist/src/profile-ops.js +252 -0
- package/dist/src/project-plugins.d.ts +63 -0
- package/dist/src/project-plugins.js +793 -0
- package/dist/src/remote-config.d.ts +183 -0
- package/dist/src/remote-config.js +574 -0
- package/dist/src/root-resolver.d.ts +5 -0
- package/dist/src/root-resolver.js +69 -0
- package/dist/src/run-provisioning.d.ts +58 -0
- package/dist/src/run-provisioning.js +128 -0
- package/dist/src/runtime-context.d.ts +20 -0
- package/dist/src/runtime-context.js +257 -0
- package/dist/src/runtime-events.d.ts +44 -0
- package/dist/src/runtime-events.js +212 -0
- package/dist/src/runtime-overlay.d.ts +11 -0
- package/dist/src/runtime-overlay.js +71 -0
- package/dist/src/runtime-paths.d.ts +21 -0
- package/dist/src/runtime-paths.js +181 -0
- package/dist/src/runtime-provisioning-env.d.ts +5 -0
- package/dist/src/runtime-provisioning-env.js +217 -0
- package/dist/src/runtime-runner-context.d.ts +12 -0
- package/dist/src/runtime-runner-context.js +1 -0
- package/dist/src/safe-identifiers.d.ts +44 -0
- package/dist/src/safe-identifiers.js +96 -0
- package/dist/src/scope-rules.d.ts +4 -0
- package/dist/src/scope-rules.js +21 -0
- package/dist/src/server-paths.d.ts +26 -0
- package/dist/src/server-paths.js +308 -0
- package/dist/src/setup-version.d.ts +3 -0
- package/dist/src/setup-version.js +14 -0
- package/dist/src/task-record-reader.d.ts +3 -0
- package/dist/src/task-record-reader.js +9 -0
- package/dist/src/validator-registry.d.ts +27 -0
- package/dist/src/validator-registry.js +64 -0
- package/package.json +166 -10
- package/dist/src/engineReadModelReducer.js +0 -1780
- package/dist/src/rig-init-builder.js +0 -57
- package/dist/src/rigSelectors.js +0 -293
- package/dist/src/taskGraph.js +0 -64
- package/dist/src/taskGraphCodes.js +0 -26
- package/dist/src/taskGraphLayout.js +0 -374
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type HookContext as PluginHookContext, type HookEvent, type HookImplementation, type HookResult } from "@rig/contracts";
|
|
2
|
+
export type HookInput = {
|
|
3
|
+
tool_name?: string;
|
|
4
|
+
tool_input?: Record<string, unknown>;
|
|
5
|
+
command?: string;
|
|
6
|
+
};
|
|
7
|
+
export type ParsedHookInput = {
|
|
8
|
+
input: HookInput;
|
|
9
|
+
valid: boolean;
|
|
10
|
+
hadPayload: boolean;
|
|
11
|
+
};
|
|
12
|
+
export interface TypedHookOptions {
|
|
13
|
+
readonly event: HookEvent;
|
|
14
|
+
readonly projectRoot?: string;
|
|
15
|
+
readonly taskId?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const BAKED_PROJECT_ROOT: string;
|
|
18
|
+
export declare const BAKED_TASK_ID: string;
|
|
19
|
+
export declare const BAKED_STATE_DIR: string;
|
|
20
|
+
export declare const BAKED_BUN_PATH: string;
|
|
21
|
+
export declare const BAKED_TASK_CONFIG: string;
|
|
22
|
+
export declare const BAKED_POLICY_CONTENT: string;
|
|
23
|
+
export declare const BAKED_TASK_SCOPES: string;
|
|
24
|
+
export declare function resolveProjectRoot(): string;
|
|
25
|
+
export declare function resolveTaskIdForHook(_projectRoot: string): string;
|
|
26
|
+
export declare function resolveTaskConfig(_projectRoot: string, _taskId: string): Promise<{
|
|
27
|
+
scope?: string[];
|
|
28
|
+
validation?: string[];
|
|
29
|
+
role?: string;
|
|
30
|
+
}>;
|
|
31
|
+
export declare function resolveTaskScopes(projectRoot: string, taskId: string): Promise<string[]>;
|
|
32
|
+
export declare function resolvePolicyContent(projectRoot: string): string;
|
|
33
|
+
export declare function readHookInput(): Promise<ParsedHookInput>;
|
|
34
|
+
export declare function extractToolFilePaths(toolName: string, input: Record<string, unknown>): string[];
|
|
35
|
+
export declare function isTestFilePath(path: string): boolean;
|
|
36
|
+
export declare function buildPluginHookContext(parsed: ParsedHookInput, opts: {
|
|
37
|
+
event: HookEvent;
|
|
38
|
+
projectRoot: string;
|
|
39
|
+
taskId: string;
|
|
40
|
+
}): PluginHookContext;
|
|
41
|
+
export declare function hookResultToProtocol(result: HookResult): {
|
|
42
|
+
exitCode: 0 | 1;
|
|
43
|
+
stdout: string;
|
|
44
|
+
};
|
|
45
|
+
export declare function escapeRegExp(value: string): string;
|
|
46
|
+
export declare function block(hookName: string, message: string, projectRoot: string): never;
|
|
47
|
+
export declare function resolveBunCli(): string;
|
|
48
|
+
export declare function resolveBunCliInvocation(): {
|
|
49
|
+
command: string;
|
|
50
|
+
env: Record<string, string>;
|
|
51
|
+
};
|
|
52
|
+
export declare function runTypedHook(fn: HookImplementation, opts: TypedHookOptions): Promise<never>;
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/core/src/hook-runtime.ts
|
|
3
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, realpathSync, writeSync } from "fs";
|
|
4
|
+
import { resolve } from "path";
|
|
5
|
+
import { RIG_DEFINITION_DIRNAME, RIG_STATE_DIRNAME } from "@rig/contracts";
|
|
6
|
+
function bunRuntime() {
|
|
7
|
+
const runtime = globalThis;
|
|
8
|
+
return runtime.Bun;
|
|
9
|
+
}
|
|
10
|
+
function normalizeBuildConfig(value) {
|
|
11
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"));
|
|
15
|
+
}
|
|
16
|
+
function readBuildConfigForCoreHooks() {
|
|
17
|
+
if (typeof __RIG_BUILD_CONFIG__ !== "undefined") {
|
|
18
|
+
return normalizeBuildConfig(__RIG_BUILD_CONFIG__);
|
|
19
|
+
}
|
|
20
|
+
const raw = process.env.RIG_BUILD_CONFIG_JSON?.trim();
|
|
21
|
+
if (!raw) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
return normalizeBuildConfig(JSON.parse(raw));
|
|
26
|
+
} catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
var BUILD_CONFIG = readBuildConfigForCoreHooks();
|
|
31
|
+
var BAKED_PROJECT_ROOT = BUILD_CONFIG.AGENT_PROJECT_ROOT ?? "";
|
|
32
|
+
var BAKED_TASK_ID = BUILD_CONFIG.AGENT_TASK_ID ?? "";
|
|
33
|
+
var BAKED_STATE_DIR = BUILD_CONFIG.AGENT_STATE_DIR ?? "";
|
|
34
|
+
var BAKED_BUN_PATH = BUILD_CONFIG.AGENT_BUN_PATH ?? "";
|
|
35
|
+
var BAKED_TASK_CONFIG = BUILD_CONFIG.AGENT_TASK_CONFIG ?? "";
|
|
36
|
+
var BAKED_POLICY_CONTENT = BUILD_CONFIG.AGENT_POLICY_CONTENT ?? "";
|
|
37
|
+
var BAKED_TASK_SCOPES = BUILD_CONFIG.AGENT_TASK_SCOPES ?? "";
|
|
38
|
+
var RUNTIME_CONTEXT_ENV = "RIG_RUNTIME_CONTEXT_FILE";
|
|
39
|
+
function isPlainObject(value) {
|
|
40
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
41
|
+
}
|
|
42
|
+
function isStringArray(value) {
|
|
43
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
44
|
+
}
|
|
45
|
+
function loadHookContextFromEnv() {
|
|
46
|
+
const contextFile = process.env[RUNTIME_CONTEXT_ENV]?.trim();
|
|
47
|
+
let filePath = contextFile || "";
|
|
48
|
+
if (!filePath) {
|
|
49
|
+
let current = resolve(process.cwd());
|
|
50
|
+
while (true) {
|
|
51
|
+
const candidate = resolve(current, "runtime-context.json");
|
|
52
|
+
if (existsSync(candidate)) {
|
|
53
|
+
filePath = candidate;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
const parent = resolve(current, "..");
|
|
57
|
+
if (parent === current) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
current = parent;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!filePath || !existsSync(filePath)) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const raw = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
68
|
+
if (!isPlainObject(raw)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const taskId = typeof raw.taskId === "string" ? raw.taskId : "";
|
|
72
|
+
const role = typeof raw.role === "string" ? raw.role : "";
|
|
73
|
+
const scopes = isStringArray(raw.scopes) ? raw.scopes : [];
|
|
74
|
+
const validation = isStringArray(raw.validation) ? raw.validation : [];
|
|
75
|
+
const hostProjectRoot = typeof raw.hostProjectRoot === "string" ? raw.hostProjectRoot : undefined;
|
|
76
|
+
const monorepoMainRoot = typeof raw.monorepoMainRoot === "string" ? raw.monorepoMainRoot : undefined;
|
|
77
|
+
const stateDir = typeof raw.stateDir === "string" ? raw.stateDir : "";
|
|
78
|
+
const policyFile = typeof raw.policyFile === "string" ? raw.policyFile : "";
|
|
79
|
+
if (!taskId || !stateDir) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
taskId,
|
|
84
|
+
role,
|
|
85
|
+
scopes,
|
|
86
|
+
validation,
|
|
87
|
+
hostProjectRoot,
|
|
88
|
+
monorepoMainRoot,
|
|
89
|
+
stateDir,
|
|
90
|
+
policyFile
|
|
91
|
+
};
|
|
92
|
+
} catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
var cachedContext;
|
|
97
|
+
function getContext() {
|
|
98
|
+
if (cachedContext !== undefined) {
|
|
99
|
+
return cachedContext;
|
|
100
|
+
}
|
|
101
|
+
cachedContext = loadHookContextFromEnv();
|
|
102
|
+
return cachedContext;
|
|
103
|
+
}
|
|
104
|
+
function resolveProjectRoot() {
|
|
105
|
+
const ctx = getContext();
|
|
106
|
+
if (ctx?.hostProjectRoot)
|
|
107
|
+
return ctx.hostProjectRoot;
|
|
108
|
+
if (BAKED_PROJECT_ROOT) {
|
|
109
|
+
return BAKED_PROJECT_ROOT;
|
|
110
|
+
}
|
|
111
|
+
if (process.env.PROJECT_RIG_ROOT) {
|
|
112
|
+
return process.env.PROJECT_RIG_ROOT;
|
|
113
|
+
}
|
|
114
|
+
const candidates = [process.cwd(), resolve(import.meta.dirname, "../..")];
|
|
115
|
+
for (const candidate of candidates) {
|
|
116
|
+
if (existsSync(resolve(candidate, RIG_DEFINITION_DIRNAME)) || existsSync(resolve(candidate, RIG_STATE_DIRNAME))) {
|
|
117
|
+
return candidate;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return resolve(import.meta.dirname, "../..");
|
|
121
|
+
}
|
|
122
|
+
function resolveTaskIdForHook(_projectRoot) {
|
|
123
|
+
const ctx = getContext();
|
|
124
|
+
if (ctx)
|
|
125
|
+
return ctx.taskId;
|
|
126
|
+
if (BAKED_TASK_ID) {
|
|
127
|
+
return BAKED_TASK_ID;
|
|
128
|
+
}
|
|
129
|
+
const fromEnv = (process.env.RIG_TASK_ID || "").trim();
|
|
130
|
+
if (fromEnv) {
|
|
131
|
+
return fromEnv;
|
|
132
|
+
}
|
|
133
|
+
const runtimeId = (process.env.RIG_TASK_RUNTIME_ID || "").trim();
|
|
134
|
+
if (runtimeId.startsWith("task-") && runtimeId.length > "task-".length) {
|
|
135
|
+
return runtimeId.slice("task-".length);
|
|
136
|
+
}
|
|
137
|
+
return "";
|
|
138
|
+
}
|
|
139
|
+
function isTaskConfigEntry(value) {
|
|
140
|
+
if (!isPlainObject(value)) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
if ("role" in value && value.role !== undefined && typeof value.role !== "string") {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if ("scope" in value && value.scope !== undefined && !isStringArray(value.scope)) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
if ("validation" in value && value.validation !== undefined && !isStringArray(value.validation)) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
async function readTaskConfigFromDisk(configPath) {
|
|
155
|
+
if (!existsSync(configPath)) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
const bunFile = bunRuntime()?.file;
|
|
160
|
+
const content = bunFile ? await bunFile(configPath).json() : JSON.parse(readFileSync(configPath, "utf-8"));
|
|
161
|
+
return isPlainObject(content) ? content : null;
|
|
162
|
+
} catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function taskConfigCandidates(ctx) {
|
|
167
|
+
const taskWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
168
|
+
return [
|
|
169
|
+
ctx?.monorepoMainRoot ? resolve(ctx.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
170
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
171
|
+
taskWorkspace ? resolve(taskWorkspace, ".rig", "task-config.json") : ""
|
|
172
|
+
].filter(Boolean);
|
|
173
|
+
}
|
|
174
|
+
async function resolveTaskConfig(_projectRoot, _taskId) {
|
|
175
|
+
const ctx = getContext();
|
|
176
|
+
if (ctx) {
|
|
177
|
+
return {
|
|
178
|
+
scope: ctx.scopes,
|
|
179
|
+
validation: ctx.validation,
|
|
180
|
+
role: ctx.role
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (BAKED_TASK_CONFIG) {
|
|
184
|
+
try {
|
|
185
|
+
const parsed = JSON.parse(BAKED_TASK_CONFIG);
|
|
186
|
+
if (isTaskConfigEntry(parsed) && Object.keys(parsed).length > 0) {
|
|
187
|
+
return parsed;
|
|
188
|
+
}
|
|
189
|
+
} catch {}
|
|
190
|
+
}
|
|
191
|
+
for (const configPath of taskConfigCandidates(ctx)) {
|
|
192
|
+
const config = await readTaskConfigFromDisk(configPath);
|
|
193
|
+
if (!config) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const taskEntry = config[_taskId];
|
|
197
|
+
if (isTaskConfigEntry(taskEntry)) {
|
|
198
|
+
return taskEntry;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return {};
|
|
202
|
+
}
|
|
203
|
+
async function resolveTaskScopes(projectRoot, taskId) {
|
|
204
|
+
const ctx = getContext();
|
|
205
|
+
if (ctx && ctx.scopes.length > 0)
|
|
206
|
+
return ctx.scopes;
|
|
207
|
+
if (BAKED_TASK_SCOPES) {
|
|
208
|
+
try {
|
|
209
|
+
const parsed = JSON.parse(BAKED_TASK_SCOPES);
|
|
210
|
+
if (Array.isArray(parsed) && parsed.length > 0 && parsed.every((item) => typeof item === "string")) {
|
|
211
|
+
return parsed;
|
|
212
|
+
}
|
|
213
|
+
} catch {}
|
|
214
|
+
}
|
|
215
|
+
return (await resolveTaskConfig(projectRoot, taskId)).scope || [];
|
|
216
|
+
}
|
|
217
|
+
function resolvePolicyContent(projectRoot) {
|
|
218
|
+
const ctx = getContext();
|
|
219
|
+
if (ctx?.policyFile && existsSync(ctx.policyFile)) {
|
|
220
|
+
return readFileSync(ctx.policyFile, "utf-8");
|
|
221
|
+
}
|
|
222
|
+
if (BAKED_POLICY_CONTENT)
|
|
223
|
+
return BAKED_POLICY_CONTENT;
|
|
224
|
+
const policyPath = resolve(projectRoot, "rig/policy/policy.json");
|
|
225
|
+
if (existsSync(policyPath))
|
|
226
|
+
return readFileSync(policyPath, "utf-8");
|
|
227
|
+
return "{}";
|
|
228
|
+
}
|
|
229
|
+
async function readHookInput() {
|
|
230
|
+
let text = "";
|
|
231
|
+
const inputFile = process.env.RIG_HOOK_INPUT_FILE?.trim();
|
|
232
|
+
if (inputFile) {
|
|
233
|
+
text = readFileSync(inputFile, "utf-8");
|
|
234
|
+
} else {
|
|
235
|
+
try {
|
|
236
|
+
text = readFileSync("/dev/stdin", "utf-8");
|
|
237
|
+
} catch {
|
|
238
|
+
text = readFileSync(0, "utf-8");
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (!text.trim()) {
|
|
242
|
+
return { input: {}, valid: true, hadPayload: false };
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
return {
|
|
246
|
+
input: JSON.parse(text),
|
|
247
|
+
valid: true,
|
|
248
|
+
hadPayload: true
|
|
249
|
+
};
|
|
250
|
+
} catch {
|
|
251
|
+
return { input: {}, valid: false, hadPayload: true };
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function extractToolFilePaths(toolName, input) {
|
|
255
|
+
const paths = [];
|
|
256
|
+
const add = (value) => {
|
|
257
|
+
if (typeof value === "string" && value.trim()) {
|
|
258
|
+
paths.push(value.trim());
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
if (toolName === "Read" || toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit") {
|
|
262
|
+
add(input.file_path);
|
|
263
|
+
add(input.path);
|
|
264
|
+
} else if (toolName === "Glob") {
|
|
265
|
+
add(input.path);
|
|
266
|
+
} else if (toolName === "Grep") {
|
|
267
|
+
add(input.path);
|
|
268
|
+
} else {
|
|
269
|
+
add(input.file_path);
|
|
270
|
+
add(input.path);
|
|
271
|
+
}
|
|
272
|
+
return paths;
|
|
273
|
+
}
|
|
274
|
+
function isTestFilePath(path) {
|
|
275
|
+
return /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(path) || /\/(__tests__|tests|test)\//.test(path);
|
|
276
|
+
}
|
|
277
|
+
function buildPluginHookContext(parsed, opts) {
|
|
278
|
+
const toolName = parsed.input.tool_name;
|
|
279
|
+
const toolInput = parsed.input.tool_input ?? {};
|
|
280
|
+
return {
|
|
281
|
+
event: opts.event,
|
|
282
|
+
toolName,
|
|
283
|
+
toolInput,
|
|
284
|
+
filePaths: toolName ? extractToolFilePaths(toolName, toolInput) : [],
|
|
285
|
+
projectRoot: opts.projectRoot,
|
|
286
|
+
taskId: opts.taskId
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function hookResultToProtocol(result) {
|
|
290
|
+
if (result.decision === "block") {
|
|
291
|
+
const lines = [`BLOCKED: ${result.reason ?? "blocked by plugin hook"}`];
|
|
292
|
+
if (result.systemMessage) {
|
|
293
|
+
lines.push(result.systemMessage);
|
|
294
|
+
}
|
|
295
|
+
return { exitCode: 1, stdout: `${lines.join(`
|
|
296
|
+
`)}
|
|
297
|
+
` };
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
exitCode: 0,
|
|
301
|
+
stdout: result.systemMessage ? `${result.systemMessage}
|
|
302
|
+
` : ""
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function escapeRegExp(value) {
|
|
306
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
307
|
+
}
|
|
308
|
+
function block(hookName, message, projectRoot) {
|
|
309
|
+
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
310
|
+
const stateDir = BAKED_STATE_DIR || (runtimeWorkspace ? resolve(runtimeWorkspace, ".rig", "state") : resolve(projectRoot, ".rig", "state"));
|
|
311
|
+
mkdirSync(stateDir, { recursive: true });
|
|
312
|
+
const tripLog = resolve(stateDir, "hook_trips.log");
|
|
313
|
+
let count = 0;
|
|
314
|
+
if (existsSync(tripLog)) {
|
|
315
|
+
const content = readFileSync(tripLog, "utf-8");
|
|
316
|
+
count = (content.match(new RegExp(`^${escapeRegExp(hookName)}\\s`, "gm")) || []).length;
|
|
317
|
+
}
|
|
318
|
+
appendFileSync(tripLog, `${hookName} ${new Date().toISOString()}
|
|
319
|
+
`, "utf-8");
|
|
320
|
+
count += 1;
|
|
321
|
+
const lines = [
|
|
322
|
+
`BLOCKED: ${message}`,
|
|
323
|
+
"",
|
|
324
|
+
"Re-read CLAUDE.md safety rules before your next action."
|
|
325
|
+
];
|
|
326
|
+
if (count >= 3) {
|
|
327
|
+
lines.push("");
|
|
328
|
+
lines.push(`REPEATED VIOLATION (${count}x ${hookName}).`);
|
|
329
|
+
lines.push("STOP. Read the FULL CLAUDE.md from top to bottom.");
|
|
330
|
+
lines.push("If stuck, write the problem to .rig/state/failed_approaches.md and request help.");
|
|
331
|
+
}
|
|
332
|
+
writeSync(1, `${lines.join(`
|
|
333
|
+
`)}
|
|
334
|
+
`);
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
function normalizeExecutablePath(candidate) {
|
|
338
|
+
if (!candidate) {
|
|
339
|
+
return "";
|
|
340
|
+
}
|
|
341
|
+
const normalized = resolve(candidate);
|
|
342
|
+
if (!existsSync(normalized)) {
|
|
343
|
+
return "";
|
|
344
|
+
}
|
|
345
|
+
try {
|
|
346
|
+
return realpathSync(normalized);
|
|
347
|
+
} catch {
|
|
348
|
+
return normalized;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
function looksLikeRuntimeGateway(candidate) {
|
|
352
|
+
const normalized = resolve(candidate).replace(/\\/g, "/");
|
|
353
|
+
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
354
|
+
}
|
|
355
|
+
function resolveBunBinaryPath() {
|
|
356
|
+
const explicit = normalizeExecutablePath(process.env.RIG_BUN_PATH?.trim());
|
|
357
|
+
if (explicit) {
|
|
358
|
+
return explicit;
|
|
359
|
+
}
|
|
360
|
+
const bunWhich = bunRuntime()?.which?.("bun");
|
|
361
|
+
const pathBun = normalizeExecutablePath(bunWhich?.trim());
|
|
362
|
+
if (pathBun && !looksLikeRuntimeGateway(pathBun)) {
|
|
363
|
+
return pathBun;
|
|
364
|
+
}
|
|
365
|
+
const home = process.env.HOME?.trim();
|
|
366
|
+
const fallbackCandidates = [
|
|
367
|
+
home ? resolve(home, ".bun/bin/bun") : "",
|
|
368
|
+
"/opt/homebrew/bin/bun",
|
|
369
|
+
"/usr/local/bin/bun",
|
|
370
|
+
"/usr/bin/bun"
|
|
371
|
+
];
|
|
372
|
+
for (const candidate of fallbackCandidates) {
|
|
373
|
+
const normalized = normalizeExecutablePath(candidate);
|
|
374
|
+
if (normalized) {
|
|
375
|
+
return normalized;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const execPath = normalizeExecutablePath(process.execPath?.trim());
|
|
379
|
+
if (execPath && !looksLikeRuntimeGateway(execPath)) {
|
|
380
|
+
return execPath;
|
|
381
|
+
}
|
|
382
|
+
throw new Error("bun not found in PATH");
|
|
383
|
+
}
|
|
384
|
+
function resolveBunCli() {
|
|
385
|
+
return resolveBunCliInvocation().command;
|
|
386
|
+
}
|
|
387
|
+
function resolveBunCliInvocation() {
|
|
388
|
+
if (BAKED_BUN_PATH) {
|
|
389
|
+
return {
|
|
390
|
+
command: BAKED_BUN_PATH,
|
|
391
|
+
env: {}
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
if (process.env.RIG_BUN_PATH?.trim()) {
|
|
395
|
+
return {
|
|
396
|
+
command: process.env.RIG_BUN_PATH.trim(),
|
|
397
|
+
env: {}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
try {
|
|
401
|
+
const systemBun = resolveBunBinaryPath();
|
|
402
|
+
return {
|
|
403
|
+
command: systemBun,
|
|
404
|
+
env: {}
|
|
405
|
+
};
|
|
406
|
+
} catch {}
|
|
407
|
+
if (process.execPath?.trim()) {
|
|
408
|
+
return {
|
|
409
|
+
command: process.execPath,
|
|
410
|
+
env: { BUN_BE_BUN: "1" }
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
return { command: "bun", env: {} };
|
|
414
|
+
}
|
|
415
|
+
async function runTypedHook(fn, opts) {
|
|
416
|
+
const parsed = await readHookInput();
|
|
417
|
+
const projectRoot = opts.projectRoot ?? resolveProjectRoot();
|
|
418
|
+
const taskId = opts.taskId ?? resolveTaskIdForHook(projectRoot);
|
|
419
|
+
const ctx = buildPluginHookContext(parsed, {
|
|
420
|
+
event: opts.event,
|
|
421
|
+
projectRoot,
|
|
422
|
+
taskId
|
|
423
|
+
});
|
|
424
|
+
let result;
|
|
425
|
+
try {
|
|
426
|
+
result = await fn(ctx);
|
|
427
|
+
} catch (err) {
|
|
428
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
429
|
+
writeSync(2, `[rig hook] typed hook threw: ${message}
|
|
430
|
+
`);
|
|
431
|
+
process.exit(0);
|
|
432
|
+
}
|
|
433
|
+
const { exitCode, stdout } = hookResultToProtocol(result);
|
|
434
|
+
if (stdout) {
|
|
435
|
+
writeSync(1, stdout);
|
|
436
|
+
}
|
|
437
|
+
process.exit(exitCode);
|
|
438
|
+
}
|
|
439
|
+
export {
|
|
440
|
+
runTypedHook,
|
|
441
|
+
resolveTaskScopes,
|
|
442
|
+
resolveTaskIdForHook,
|
|
443
|
+
resolveTaskConfig,
|
|
444
|
+
resolveProjectRoot,
|
|
445
|
+
resolvePolicyContent,
|
|
446
|
+
resolveBunCliInvocation,
|
|
447
|
+
resolveBunCli,
|
|
448
|
+
readHookInput,
|
|
449
|
+
isTestFilePath,
|
|
450
|
+
hookResultToProtocol,
|
|
451
|
+
extractToolFilePaths,
|
|
452
|
+
escapeRegExp,
|
|
453
|
+
buildPluginHookContext,
|
|
454
|
+
block,
|
|
455
|
+
BAKED_TASK_SCOPES,
|
|
456
|
+
BAKED_TASK_ID,
|
|
457
|
+
BAKED_TASK_CONFIG,
|
|
458
|
+
BAKED_STATE_DIR,
|
|
459
|
+
BAKED_PROJECT_ROOT,
|
|
460
|
+
BAKED_POLICY_CONTENT,
|
|
461
|
+
BAKED_BUN_PATH
|
|
462
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const RIG_CORE_PACKAGE = "@rig/core";
|
|
2
|
+
export { definePlugin } from "./define-plugin";
|
|
3
|
+
export { defineConfig } from "./define-config";
|
|
4
|
+
export { createPluginHost } from "./plugin-host";
|
|
5
|
+
export type { PluginHost } from "./plugin-host";
|
|
6
|
+
export { defineCapability, defineServiceCapability, CapabilityProviderMissingError } from "./capability";
|
|
7
|
+
export type { Capability, CapabilityImpl, CapabilityProvideOptions, ServiceCapability, ServiceCapabilityImpl, } from "./capability";
|
|
8
|
+
export type { RigPlugin, PluginContributes, Validator, TaskSource, FeatureCapability, Panel, BlockerClassifierEntry, CliCommand, Hook, StageEntry, SessionExtensionEntry, SessionExtensionInstall, SeedEntrypoint, SeedEntrypointContext, SeedEntrypointRunResult, TaskSourceFactoryContext, RuntimeCliContext, ValidatorContext, ValidatorResult, } from "./plugin-runtime";
|