@h-rig/harness-plugin 0.0.6-alpha.186

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.
Files changed (82) hide show
  1. package/README.md +1 -0
  2. package/dist/bin/rig-agent-dispatch.d.ts +2 -0
  3. package/dist/bin/rig-agent-dispatch.js +826 -0
  4. package/dist/src/agent-command.d.ts +3 -0
  5. package/dist/src/agent-command.js +233 -0
  6. package/dist/src/agent-harness/agent-mode.d.ts +1 -0
  7. package/dist/src/agent-harness/agent-mode.js +48 -0
  8. package/dist/src/agent-harness/agent-wrapper.d.ts +60 -0
  9. package/dist/src/agent-harness/agent-wrapper.js +842 -0
  10. package/dist/src/agent-harness/controlled-bash.d.ts +3 -0
  11. package/dist/src/agent-harness/controlled-bash.js +45 -0
  12. package/dist/src/agent-harness/git-ops.d.ts +2 -0
  13. package/dist/src/agent-harness/git-ops.js +27 -0
  14. package/dist/src/agent-harness/repo-ops.d.ts +14 -0
  15. package/dist/src/agent-harness/repo-ops.js +37 -0
  16. package/dist/src/agent-harness/rig-agent-entrypoint.d.ts +1 -0
  17. package/dist/src/agent-harness/rig-agent-entrypoint.js +1362 -0
  18. package/dist/src/agent-harness/rig-agent.d.ts +2 -0
  19. package/dist/src/agent-harness/rig-agent.js +1324 -0
  20. package/dist/src/agent-harness/runtime-snapshot-config.d.ts +2 -0
  21. package/dist/src/agent-harness/runtime-snapshot-config.js +25 -0
  22. package/dist/src/agent-harness/task-data.d.ts +27 -0
  23. package/dist/src/agent-harness/task-data.js +286 -0
  24. package/dist/src/agent-harness/task-ops.d.ts +10 -0
  25. package/dist/src/agent-harness/task-ops.js +352 -0
  26. package/dist/src/index.d.ts +6 -0
  27. package/dist/src/index.js +4525 -0
  28. package/dist/src/model.d.ts +80 -0
  29. package/dist/src/model.js +64 -0
  30. package/dist/src/pi-command.d.ts +3 -0
  31. package/dist/src/pi-command.js +154 -0
  32. package/dist/src/pi-settings-materializer.d.ts +10 -0
  33. package/dist/src/pi-settings-materializer.js +52 -0
  34. package/dist/src/plugin.d.ts +24 -0
  35. package/dist/src/plugin.js +4486 -0
  36. package/dist/src/profile-command.d.ts +3 -0
  37. package/dist/src/profile-command.js +79 -0
  38. package/dist/src/profile-state.d.ts +7 -0
  39. package/dist/src/profile-state.js +39 -0
  40. package/dist/src/rig-task-run-skill.d.ts +8 -0
  41. package/dist/src/rig-task-run-skill.js +39 -0
  42. package/dist/src/runtime-instructions.d.ts +4 -0
  43. package/dist/src/runtime-instructions.js +26 -0
  44. package/dist/src/runtime-secrets.d.ts +6 -0
  45. package/dist/src/runtime-secrets.js +58 -0
  46. package/dist/src/service.d.ts +14 -0
  47. package/dist/src/service.js +33 -0
  48. package/dist/src/session-asset-materializer-service.d.ts +13 -0
  49. package/dist/src/session-asset-materializer-service.js +164 -0
  50. package/dist/src/session-hook-materializer-service.d.ts +34 -0
  51. package/dist/src/session-hook-materializer-service.js +142 -0
  52. package/dist/src/skill-materializer.d.ts +25 -0
  53. package/dist/src/skill-materializer.js +86 -0
  54. package/dist/src/tooling/browser-tool-entrypoint.d.ts +2 -0
  55. package/dist/src/tooling/browser-tool-entrypoint.js +125 -0
  56. package/dist/src/tooling/browser-tools.d.ts +3 -0
  57. package/dist/src/tooling/browser-tools.js +27 -0
  58. package/dist/src/tooling/claude-router-binary.d.ts +3 -0
  59. package/dist/src/tooling/claude-router-binary.js +62 -0
  60. package/dist/src/tooling/claude-router.d.ts +22 -0
  61. package/dist/src/tooling/claude-router.js +524 -0
  62. package/dist/src/tooling/embedded-native-assets.d.ts +7 -0
  63. package/dist/src/tooling/embedded-native-assets.js +6 -0
  64. package/dist/src/tooling/file-tools.d.ts +5 -0
  65. package/dist/src/tooling/file-tools.js +192 -0
  66. package/dist/src/tooling/gateway.d.ts +4 -0
  67. package/dist/src/tooling/gateway.js +400 -0
  68. package/dist/src/tooling/shell-tools.d.ts +5 -0
  69. package/dist/src/tooling/shell-tools.js +185 -0
  70. package/native/darwin-arm64/rig-shell +0 -0
  71. package/native/darwin-arm64/rig-shell.build-manifest.json +4 -0
  72. package/native/darwin-arm64/rig-tools +0 -0
  73. package/native/darwin-arm64/rig-tools.build-manifest.json +4 -0
  74. package/native/darwin-x64/rig-shell +0 -0
  75. package/native/darwin-x64/rig-tools +0 -0
  76. package/native/linux-arm64/rig-shell +0 -0
  77. package/native/linux-arm64/rig-tools +0 -0
  78. package/native/linux-x64/rig-shell +0 -0
  79. package/native/linux-x64/rig-tools +0 -0
  80. package/native/win32-x64/rig-shell.exe +0 -0
  81. package/native/win32-x64/rig-tools.exe +0 -0
  82. package/package.json +101 -0
@@ -0,0 +1,142 @@
1
+ // @bun
2
+ // packages/harness-plugin/src/session-hook-materializer-service.ts
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
4
+ import { dirname, resolve } from "path";
5
+ import { buildTypedHookShimCommand } from "@rig/core/hook-materializer";
6
+ var MARKER_PLUGIN = "_rigPlugin";
7
+ var MARKER_HOOK_ID = "_rigHookId";
8
+ function matcherToString(matcher) {
9
+ if (matcher.kind === "all")
10
+ return;
11
+ if (matcher.kind === "tool")
12
+ return matcher.name;
13
+ return matcher.pattern;
14
+ }
15
+ function isPluginOwned(cmd) {
16
+ return typeof cmd[MARKER_PLUGIN] === "string";
17
+ }
18
+ function createPiNoopSessionHookAdapter() {
19
+ return {
20
+ id: "pi",
21
+ materialize() {
22
+ return {
23
+ adapterId: "pi",
24
+ status: "skipped",
25
+ reason: "Pi sessions do not consume Claude Code settings hooks."
26
+ };
27
+ }
28
+ };
29
+ }
30
+ function createClaudeCodeSessionHookAdapter() {
31
+ return {
32
+ id: "claude-code",
33
+ materialize(projectRoot, entries) {
34
+ return writeClaudeCodeHookSettings(projectRoot, entries);
35
+ }
36
+ };
37
+ }
38
+ function defaultAgentSessionHookAdapters(env = process.env) {
39
+ if (env.RIG_AGENT_SESSION_HOOK_ADAPTER === "claude-code") {
40
+ return [createClaudeCodeSessionHookAdapter()];
41
+ }
42
+ if (env.RIG_AGENT_SESSION_HOOK_ADAPTER === "pi" || typeof env.PI_CODING_AGENT_SESSION_DIR === "string" && env.PI_CODING_AGENT_SESSION_DIR.trim().length > 0 || env.RIG_RUN_PROCESS === "1") {
43
+ return [createPiNoopSessionHookAdapter()];
44
+ }
45
+ return [createClaudeCodeSessionHookAdapter()];
46
+ }
47
+ function materializeSessionHookAdapters(projectRoot, entries, adapters = defaultAgentSessionHookAdapters()) {
48
+ return adapters.map((adapter) => adapter.materialize(projectRoot, entries));
49
+ }
50
+ function materializeHooks(projectRoot, entries) {
51
+ const result = createClaudeCodeSessionHookAdapter().materialize(projectRoot, entries);
52
+ return result.status === "materialized" ? result.path : resolve(projectRoot, ".claude", "settings.json");
53
+ }
54
+ function applyClaudeCodeSessionHooksToSettings(existing, entries, projectRoot, options = {}) {
55
+ const hooks = typeof existing.hooks === "object" && existing.hooks !== null && !Array.isArray(existing.hooks) ? existing.hooks : {};
56
+ const replacePluginOwned = options.replacePluginOwned ?? true;
57
+ if (replacePluginOwned) {
58
+ for (const event of Object.keys(hooks)) {
59
+ const groups = hooks[event] ?? [];
60
+ const cleaned = [];
61
+ for (const group of groups) {
62
+ const operatorHooks = group.hooks.filter((h) => !isPluginOwned(h));
63
+ if (operatorHooks.length > 0) {
64
+ cleaned.push({ ...group, hooks: operatorHooks });
65
+ }
66
+ }
67
+ if (cleaned.length > 0) {
68
+ hooks[event] = cleaned;
69
+ } else {
70
+ delete hooks[event];
71
+ }
72
+ }
73
+ }
74
+ const materializedEvents = new Set;
75
+ for (const { pluginName, hook, typed } of entries) {
76
+ const command = hook.command ?? (typed ? buildTypedHookShimCommand(pluginName, hook, projectRoot) : undefined);
77
+ if (!command) {
78
+ continue;
79
+ }
80
+ const event = hook.event;
81
+ materializedEvents.add(event);
82
+ const matcherString = matcherToString(hook.matcher);
83
+ const groups = hooks[event] ??= [];
84
+ let group = groups.find((g) => g.matcher === matcherString);
85
+ if (!group) {
86
+ group = matcherString === undefined ? { hooks: [] } : { matcher: matcherString, hooks: [] };
87
+ groups.push(group);
88
+ }
89
+ const alreadyPresent = group.hooks.some((candidate) => candidate[MARKER_PLUGIN] === pluginName && candidate[MARKER_HOOK_ID] === hook.id);
90
+ if (alreadyPresent) {
91
+ continue;
92
+ }
93
+ group.hooks.push({
94
+ type: "command",
95
+ command,
96
+ [MARKER_PLUGIN]: pluginName,
97
+ [MARKER_HOOK_ID]: hook.id
98
+ });
99
+ }
100
+ const next = { ...existing };
101
+ if (Object.keys(hooks).length > 0) {
102
+ next.hooks = hooks;
103
+ } else {
104
+ delete next.hooks;
105
+ }
106
+ return { settings: next, events: [...materializedEvents].sort() };
107
+ }
108
+ function writeClaudeCodeHookSettings(projectRoot, entries) {
109
+ const settingsPath = resolve(projectRoot, ".claude", "settings.json");
110
+ const existing = existsSync(settingsPath) ? safeReadJson(settingsPath) : {};
111
+ const { settings, events } = applyClaudeCodeSessionHooksToSettings(existing, entries, projectRoot);
112
+ mkdirSync(dirname(settingsPath), { recursive: true });
113
+ writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}
114
+ `, "utf-8");
115
+ return {
116
+ adapterId: "claude-code",
117
+ status: "materialized",
118
+ path: settingsPath,
119
+ events
120
+ };
121
+ }
122
+ function safeReadJson(path) {
123
+ try {
124
+ return JSON.parse(readFileSync(path, "utf-8"));
125
+ } catch {
126
+ return {};
127
+ }
128
+ }
129
+ var sessionHookMaterializer = {
130
+ materializeSessionHooks(projectRoot, entries) {
131
+ return materializeSessionHookAdapters(projectRoot, entries, defaultAgentSessionHookAdapters());
132
+ }
133
+ };
134
+ export {
135
+ sessionHookMaterializer,
136
+ materializeSessionHookAdapters,
137
+ materializeHooks,
138
+ defaultAgentSessionHookAdapters,
139
+ createPiNoopSessionHookAdapter,
140
+ createClaudeCodeSessionHookAdapter,
141
+ applyClaudeCodeSessionHooksToSettings
142
+ };
@@ -0,0 +1,25 @@
1
+ import type { SkillRegistration } from "@rig/contracts";
2
+ export interface PluginSkillEntry {
3
+ /** The plugin that owns this skill. Recorded in the marker file. */
4
+ pluginName: string;
5
+ /** The plugin's skill registration. `path` is resolved against projectRoot
6
+ * unless absolute. */
7
+ skill: SkillRegistration;
8
+ }
9
+ export interface MaterializedSkill {
10
+ id: string;
11
+ pluginName: string;
12
+ directory: string;
13
+ }
14
+ /**
15
+ * Materialize plugin-contributed skills into `.pi/skills/<id>/SKILL.md`.
16
+ *
17
+ * Removes any previously-materialized plugin skill directories (identified by
18
+ * the `.rig-plugin` marker file) before re-inserting the current set, so the
19
+ * function is idempotent and never touches operator-authored skill
20
+ * directories. Skills whose source file is missing or fails frontmatter
21
+ * parsing are skipped with a warning rather than failing the boot.
22
+ *
23
+ * @returns the skills that were written.
24
+ */
25
+ export declare function materializeSkills(projectRoot: string, entries: readonly PluginSkillEntry[]): Promise<MaterializedSkill[]>;
@@ -0,0 +1,86 @@
1
+ // @bun
2
+ // packages/harness-plugin/src/skill-materializer.ts
3
+ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs";
4
+ import { resolve } from "path";
5
+ var MARKER_FILENAME = ".rig-plugin";
6
+ var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
7
+ function parseFrontmatter(raw) {
8
+ const m = raw.match(FRONTMATTER_RE);
9
+ if (!m) {
10
+ return { meta: {}, body: raw };
11
+ }
12
+ const yaml = m[1] ?? "";
13
+ const body = m[2] ?? "";
14
+ const meta = {};
15
+ for (const line of yaml.split(/\r?\n/)) {
16
+ const trimmed = line.trim();
17
+ if (!trimmed || trimmed.startsWith("#"))
18
+ continue;
19
+ const idx = trimmed.indexOf(":");
20
+ if (idx === -1)
21
+ continue;
22
+ const key = trimmed.slice(0, idx).trim();
23
+ let value = trimmed.slice(idx + 1).trim();
24
+ if (typeof value === "string") {
25
+ const s = value;
26
+ if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
27
+ value = s.slice(1, -1);
28
+ } else if (s === "true")
29
+ value = true;
30
+ else if (s === "false")
31
+ value = false;
32
+ else if (/^-?\d+$/.test(s))
33
+ value = parseInt(s, 10);
34
+ else if (/^-?\d+\.\d+$/.test(s))
35
+ value = parseFloat(s);
36
+ }
37
+ meta[key] = value;
38
+ }
39
+ return { meta, body };
40
+ }
41
+ function assertValidSkillFrontmatter(path, raw) {
42
+ const { meta } = parseFrontmatter(raw);
43
+ if (typeof meta.name !== "string") {
44
+ throw new Error(`SKILL.md missing required field "name": ${path}`);
45
+ }
46
+ }
47
+ function skillDirName(id) {
48
+ return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
49
+ }
50
+ async function materializeSkills(projectRoot, entries) {
51
+ const skillsRoot = resolve(projectRoot, ".pi", "skills");
52
+ if (existsSync(skillsRoot)) {
53
+ for (const name of readdirSync(skillsRoot)) {
54
+ const dir = resolve(skillsRoot, name);
55
+ if (existsSync(resolve(dir, MARKER_FILENAME))) {
56
+ rmSync(dir, { recursive: true, force: true });
57
+ }
58
+ }
59
+ }
60
+ const written = [];
61
+ for (const { pluginName, skill } of entries) {
62
+ const sourcePath = resolve(projectRoot, skill.path);
63
+ if (!existsSync(sourcePath)) {
64
+ console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
65
+ continue;
66
+ }
67
+ let body;
68
+ try {
69
+ body = readFileSync(sourcePath, "utf-8");
70
+ assertValidSkillFrontmatter(sourcePath, body);
71
+ } catch (err) {
72
+ console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
73
+ continue;
74
+ }
75
+ const dir = resolve(skillsRoot, skillDirName(skill.id));
76
+ mkdirSync(dir, { recursive: true });
77
+ writeFileSync(resolve(dir, "SKILL.md"), body, "utf-8");
78
+ writeFileSync(resolve(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
79
+ `, "utf-8");
80
+ written.push({ id: skill.id, pluginName, directory: dir });
81
+ }
82
+ return written;
83
+ }
84
+ export {
85
+ materializeSkills
86
+ };
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+
4
+ // packages/harness-plugin/src/tooling/browser-tool-entrypoint.ts
5
+ import { existsSync, rmSync } from "fs";
6
+ import { basename, dirname, resolve } from "path";
7
+ import { loadRuntimeContext } from "@rig/core/runtime-context";
8
+ function currentCommand() {
9
+ return basename(process.argv[1] || "");
10
+ }
11
+ function runtimeContextPath() {
12
+ const explicit = process.env.RIG_RUNTIME_CONTEXT_FILE?.trim();
13
+ if (explicit) {
14
+ return explicit;
15
+ }
16
+ return resolve(dirname(resolve(process.argv[1] || "")), "..", "runtime-context.json");
17
+ }
18
+ function loadBrowserContext() {
19
+ const contextPath = runtimeContextPath();
20
+ if (!existsSync(contextPath)) {
21
+ throw new Error(`Runtime context file not found for ${currentCommand()}: ${contextPath}`);
22
+ }
23
+ const runtimeContext = loadRuntimeContext(contextPath);
24
+ if (!runtimeContext.browser?.required) {
25
+ throw new Error(`No browser contract is configured for ${runtimeContext.taskId}.`);
26
+ }
27
+ if (!runtimeContext.hostProjectRoot) {
28
+ throw new Error(`Runtime browser command ${currentCommand()} requires hostProjectRoot in runtime context.`);
29
+ }
30
+ return {
31
+ browser: runtimeContext.browser,
32
+ hostProjectRoot: runtimeContext.hostProjectRoot
33
+ };
34
+ }
35
+ async function runConfiguredCommand(command, browser, hostProjectRoot) {
36
+ if (!command) {
37
+ throw new Error(`No backing command is configured for ${currentCommand()}.`);
38
+ }
39
+ const attachUrl = new URL(browser.effectiveAttachUrl);
40
+ const child = Bun.spawn({
41
+ cmd: ["/bin/bash", "-lc", command],
42
+ cwd: hostProjectRoot,
43
+ stdin: "inherit",
44
+ stdout: "inherit",
45
+ stderr: "inherit",
46
+ env: {
47
+ ...process.env,
48
+ RIG_STATE_DIR: browser.stateDir,
49
+ T3CODE_STATE_DIR: browser.stateDir,
50
+ RIG_BROWSER_PROFILE: browser.effectiveProfile,
51
+ RIG_BROWSER_REMOTE_DEBUGGING_PORT: attachUrl.port,
52
+ RIG_BROWSER_ATTACH_URL: browser.effectiveAttachUrl
53
+ }
54
+ });
55
+ return await child.exited;
56
+ }
57
+ function printAttachInfo(browser, hostProjectRoot) {
58
+ const payload = {
59
+ preset: browser.preset,
60
+ mode: browser.mode,
61
+ stateDir: browser.stateDir,
62
+ hostProjectRoot,
63
+ defaultProfile: browser.defaultProfile,
64
+ effectiveProfile: browser.effectiveProfile,
65
+ defaultAttachUrl: browser.defaultAttachUrl,
66
+ effectiveAttachUrl: browser.effectiveAttachUrl,
67
+ launchHelper: browser.launchHelper,
68
+ checkHelper: browser.checkHelper,
69
+ attachInfoHelper: browser.attachInfoHelper,
70
+ e2eHelper: browser.e2eHelper,
71
+ resetProfileHelper: browser.resetProfileHelper,
72
+ devCommand: browser.devCommand,
73
+ launchCommand: browser.launchCommand,
74
+ checkCommand: browser.checkCommand,
75
+ e2eCommand: browser.e2eCommand
76
+ };
77
+ if (process.argv.includes("--json")) {
78
+ console.log(JSON.stringify(payload, null, 2));
79
+ return;
80
+ }
81
+ console.log("Rig Browser");
82
+ console.log(` Preset: ${browser.preset}`);
83
+ console.log(` Mode: ${browser.mode}`);
84
+ console.log(` State dir: ${browser.stateDir}`);
85
+ console.log(` Default profile: ${browser.defaultProfile}`);
86
+ console.log(` Effective profile: ${browser.effectiveProfile}`);
87
+ console.log(` Default attach URL: ${browser.defaultAttachUrl}`);
88
+ console.log(` Effective attach URL: ${browser.effectiveAttachUrl}`);
89
+ console.log(` Launch helper: ${browser.launchHelper}${browser.devCommand ? " [--dev]" : ""}`);
90
+ console.log(` Check helper: ${browser.checkHelper}`);
91
+ console.log(` E2E helper: ${browser.e2eHelper}`);
92
+ console.log(` Reset helper: ${browser.resetProfileHelper}`);
93
+ }
94
+ function resetProfile(browser) {
95
+ const profileRoot = resolve(browser.stateDir, "browser", "profiles", browser.effectiveProfile);
96
+ rmSync(profileRoot, { recursive: true, force: true });
97
+ console.log(`Removed Rig Browser profile: ${profileRoot}`);
98
+ }
99
+ async function main() {
100
+ const { browser, hostProjectRoot } = loadBrowserContext();
101
+ const command = currentCommand();
102
+ if (command === browser.attachInfoHelper) {
103
+ printAttachInfo(browser, hostProjectRoot);
104
+ return;
105
+ }
106
+ if (command === browser.resetProfileHelper) {
107
+ resetProfile(browser);
108
+ return;
109
+ }
110
+ if (command === browser.launchHelper) {
111
+ const launchCommand = process.argv.includes("--dev") ? browser.devCommand : browser.launchCommand;
112
+ process.exit(await runConfiguredCommand(launchCommand, browser, hostProjectRoot));
113
+ }
114
+ if (command === browser.checkHelper) {
115
+ process.exit(await runConfiguredCommand(browser.checkCommand, browser, hostProjectRoot));
116
+ }
117
+ if (command === browser.e2eHelper) {
118
+ process.exit(await runConfiguredCommand(browser.e2eCommand ?? browser.checkCommand, browser, hostProjectRoot));
119
+ }
120
+ throw new Error(`Unknown Rig Browser helper: ${command}`);
121
+ }
122
+ main().catch((error) => {
123
+ console.error(error instanceof Error ? error.message : String(error));
124
+ process.exit(1);
125
+ });
@@ -0,0 +1,3 @@
1
+ export declare function runtimeBrowserToolBinaryName(): string;
2
+ export declare function runtimeBrowserToolNames(): string[];
3
+ export declare function materializeRuntimeBrowserTools(targetDir: string): Promise<string>;
@@ -0,0 +1,27 @@
1
+ // @bun
2
+ // packages/harness-plugin/src/tooling/browser-tools.ts
3
+ import { existsSync, rmSync, symlinkSync } from "fs";
4
+ import { resolve } from "path";
5
+ import { RUNTIME_BROWSER_TOOL_NAMES } from "@rig/contracts";
6
+ function runtimeBrowserToolBinaryName() {
7
+ return `rig-browser-tool${process.platform === "win32" ? ".exe" : ""}`;
8
+ }
9
+ function runtimeBrowserToolNames() {
10
+ return [...RUNTIME_BROWSER_TOOL_NAMES];
11
+ }
12
+ async function materializeRuntimeBrowserTools(targetDir) {
13
+ const binaryPath = resolve(targetDir, runtimeBrowserToolBinaryName());
14
+ for (const tool of runtimeBrowserToolNames()) {
15
+ const toolPath = resolve(targetDir, tool);
16
+ if (existsSync(toolPath)) {
17
+ rmSync(toolPath, { force: true, recursive: true });
18
+ }
19
+ symlinkSync(binaryPath, toolPath);
20
+ }
21
+ return binaryPath;
22
+ }
23
+ export {
24
+ runtimeBrowserToolNames,
25
+ runtimeBrowserToolBinaryName,
26
+ materializeRuntimeBrowserTools
27
+ };
@@ -0,0 +1,3 @@
1
+ export declare function runtimeClaudeToolRouterFileName(): string;
2
+ export declare function ensureClaudeToolRouterBinaryPath(projectRoot: string, outputPath?: string): Promise<string>;
3
+ export declare function materializeClaudeToolRouterBinary(projectRoot: string, targetDir: string): Promise<string>;
@@ -0,0 +1,62 @@
1
+ // @bun
2
+ var __require = import.meta.require;
3
+
4
+ // packages/harness-plugin/src/tooling/claude-router-binary.ts
5
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, statSync } from "fs";
6
+ import { tmpdir } from "os";
7
+ import { dirname, resolve } from "path";
8
+
9
+ // packages/harness-plugin/src/tooling/embedded-native-assets.ts
10
+ var embeddedNatives = null;
11
+
12
+ // packages/harness-plugin/src/tooling/claude-router-binary.ts
13
+ import { getNativeExtractor } from "@rig/core/native-extract";
14
+ var { hasEmbeddedNatives } = getNativeExtractor(embeddedNatives);
15
+ var sharedRouterOutputDir = resolve(tmpdir(), "rig-native");
16
+ var sharedRouterOutputPath = resolve(sharedRouterOutputDir, `rig-tool-router-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
17
+ function runtimeClaudeToolRouterFileName() {
18
+ return `rig-tool-router${process.platform === "win32" ? ".exe" : ""}`;
19
+ }
20
+ async function requireNativeToolchainRuntimeBinaryBuild(_projectRoot) {
21
+ const { runtimeBinaryBuildService } = await import("@rig/core/native-toolchain/runtime-binary-build");
22
+ return runtimeBinaryBuildService;
23
+ }
24
+ async function ensureClaudeToolRouterBinaryPath(projectRoot, outputPath = sharedRouterOutputPath) {
25
+ const sourcePath = resolve(projectRoot, "packages/harness-plugin/src/tooling/claude-router.ts");
26
+ mkdirSync(dirname(outputPath), { recursive: true });
27
+ const needsBuild = !existsSync(outputPath) || statSync(sourcePath).mtimeMs > statSync(outputPath).mtimeMs;
28
+ if (!needsBuild) {
29
+ return outputPath;
30
+ }
31
+ const service = await requireNativeToolchainRuntimeBinaryBuild(projectRoot);
32
+ const engine = service.createRuntimeBinaryBuildEngine({ embeddedNatives });
33
+ await engine.buildRuntimeBinary({
34
+ sourcePath: "packages/harness-plugin/src/tooling/claude-router.ts",
35
+ outputPath,
36
+ cwd: projectRoot
37
+ });
38
+ chmodSync(outputPath, 493);
39
+ return outputPath;
40
+ }
41
+ async function materializeClaudeToolRouterBinary(projectRoot, targetDir) {
42
+ if (hasEmbeddedNatives()) {
43
+ const targetPath2 = resolve(targetDir, runtimeClaudeToolRouterFileName());
44
+ const service = await requireNativeToolchainRuntimeBinaryBuild(projectRoot);
45
+ service.materializeSelfExecRole(targetPath2);
46
+ return targetPath2;
47
+ }
48
+ const sourcePath = await ensureClaudeToolRouterBinaryPath(projectRoot);
49
+ const targetPath = resolve(targetDir, runtimeClaudeToolRouterFileName());
50
+ mkdirSync(targetDir, { recursive: true });
51
+ const needsCopy = !existsSync(targetPath) || statSync(sourcePath).mtimeMs > statSync(targetPath).mtimeMs;
52
+ if (needsCopy) {
53
+ copyFileSync(sourcePath, targetPath);
54
+ chmodSync(targetPath, 493);
55
+ }
56
+ return targetPath;
57
+ }
58
+ export {
59
+ runtimeClaudeToolRouterFileName,
60
+ materializeClaudeToolRouterBinary,
61
+ ensureClaudeToolRouterBinaryPath
62
+ };
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bun
2
+ export declare const CLAUDE_ROUTER_SERVER_NAME = "rig_runtime_tools";
3
+ export declare const CLAUDE_DISABLED_FILE_TOOLS: readonly ["Read", "Edit", "Write", "NotebookEdit", "Glob", "Grep"];
4
+ type RouterConfigOptions = {
5
+ binDir: string;
6
+ stateDir: string;
7
+ contextFile: string;
8
+ };
9
+ export type ToolDefinition = {
10
+ name: string;
11
+ description: string;
12
+ inputSchema: Record<string, unknown>;
13
+ };
14
+ export declare const CLAUDE_ROUTER_TOOL_DEFINITIONS: ToolDefinition[];
15
+ export declare function claudeRuntimeToolCliArgs(configPath: string): string[];
16
+ export declare function codexRuntimeToolCliArgs(options: RouterConfigOptions): string[];
17
+ export declare function writeClaudeRuntimeToolRouterConfig(options: RouterConfigOptions): string;
18
+ export declare function runClaudeToolRouterServer(): Promise<void>;
19
+ export declare function invokeRuntimeTool(toolName: string, args: Record<string, unknown>, options?: {
20
+ env?: Record<string, string | undefined>;
21
+ }): Promise<Record<string, unknown>>;
22
+ export {};