@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.
- package/README.md +1 -0
- package/dist/bin/rig-agent-dispatch.d.ts +2 -0
- package/dist/bin/rig-agent-dispatch.js +826 -0
- package/dist/src/agent-command.d.ts +3 -0
- package/dist/src/agent-command.js +233 -0
- package/dist/src/agent-harness/agent-mode.d.ts +1 -0
- package/dist/src/agent-harness/agent-mode.js +48 -0
- package/dist/src/agent-harness/agent-wrapper.d.ts +60 -0
- package/dist/src/agent-harness/agent-wrapper.js +842 -0
- package/dist/src/agent-harness/controlled-bash.d.ts +3 -0
- package/dist/src/agent-harness/controlled-bash.js +45 -0
- package/dist/src/agent-harness/git-ops.d.ts +2 -0
- package/dist/src/agent-harness/git-ops.js +27 -0
- package/dist/src/agent-harness/repo-ops.d.ts +14 -0
- package/dist/src/agent-harness/repo-ops.js +37 -0
- package/dist/src/agent-harness/rig-agent-entrypoint.d.ts +1 -0
- package/dist/src/agent-harness/rig-agent-entrypoint.js +1362 -0
- package/dist/src/agent-harness/rig-agent.d.ts +2 -0
- package/dist/src/agent-harness/rig-agent.js +1324 -0
- package/dist/src/agent-harness/runtime-snapshot-config.d.ts +2 -0
- package/dist/src/agent-harness/runtime-snapshot-config.js +25 -0
- package/dist/src/agent-harness/task-data.d.ts +27 -0
- package/dist/src/agent-harness/task-data.js +286 -0
- package/dist/src/agent-harness/task-ops.d.ts +10 -0
- package/dist/src/agent-harness/task-ops.js +352 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +4525 -0
- package/dist/src/model.d.ts +80 -0
- package/dist/src/model.js +64 -0
- package/dist/src/pi-command.d.ts +3 -0
- package/dist/src/pi-command.js +154 -0
- package/dist/src/pi-settings-materializer.d.ts +10 -0
- package/dist/src/pi-settings-materializer.js +52 -0
- package/dist/src/plugin.d.ts +24 -0
- package/dist/src/plugin.js +4486 -0
- package/dist/src/profile-command.d.ts +3 -0
- package/dist/src/profile-command.js +79 -0
- package/dist/src/profile-state.d.ts +7 -0
- package/dist/src/profile-state.js +39 -0
- package/dist/src/rig-task-run-skill.d.ts +8 -0
- package/dist/src/rig-task-run-skill.js +39 -0
- package/dist/src/runtime-instructions.d.ts +4 -0
- package/dist/src/runtime-instructions.js +26 -0
- package/dist/src/runtime-secrets.d.ts +6 -0
- package/dist/src/runtime-secrets.js +58 -0
- package/dist/src/service.d.ts +14 -0
- package/dist/src/service.js +33 -0
- package/dist/src/session-asset-materializer-service.d.ts +13 -0
- package/dist/src/session-asset-materializer-service.js +164 -0
- package/dist/src/session-hook-materializer-service.d.ts +34 -0
- package/dist/src/session-hook-materializer-service.js +142 -0
- package/dist/src/skill-materializer.d.ts +25 -0
- package/dist/src/skill-materializer.js +86 -0
- package/dist/src/tooling/browser-tool-entrypoint.d.ts +2 -0
- package/dist/src/tooling/browser-tool-entrypoint.js +125 -0
- package/dist/src/tooling/browser-tools.d.ts +3 -0
- package/dist/src/tooling/browser-tools.js +27 -0
- package/dist/src/tooling/claude-router-binary.d.ts +3 -0
- package/dist/src/tooling/claude-router-binary.js +62 -0
- package/dist/src/tooling/claude-router.d.ts +22 -0
- package/dist/src/tooling/claude-router.js +524 -0
- package/dist/src/tooling/embedded-native-assets.d.ts +7 -0
- package/dist/src/tooling/embedded-native-assets.js +6 -0
- package/dist/src/tooling/file-tools.d.ts +5 -0
- package/dist/src/tooling/file-tools.js +192 -0
- package/dist/src/tooling/gateway.d.ts +4 -0
- package/dist/src/tooling/gateway.js +400 -0
- package/dist/src/tooling/shell-tools.d.ts +5 -0
- package/dist/src/tooling/shell-tools.js +185 -0
- package/native/darwin-arm64/rig-shell +0 -0
- package/native/darwin-arm64/rig-shell.build-manifest.json +4 -0
- package/native/darwin-arm64/rig-tools +0 -0
- package/native/darwin-arm64/rig-tools.build-manifest.json +4 -0
- package/native/darwin-x64/rig-shell +0 -0
- package/native/darwin-x64/rig-tools +0 -0
- package/native/linux-arm64/rig-shell +0 -0
- package/native/linux-arm64/rig-tools +0 -0
- package/native/linux-x64/rig-shell +0 -0
- package/native/linux-x64/rig-tools +0 -0
- package/native/win32-x64/rig-shell.exe +0 -0
- package/native/win32-x64/rig-tools.exe +0 -0
- package/package.json +101 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/harness-plugin/src/profile-command.ts
|
|
3
|
+
import { CliError, requireNoExtraArgs, takeOption } from "@rig/std-shared/cli-args";
|
|
4
|
+
import { HARNESS_PROFILE_STATE } from "@rig/contracts";
|
|
5
|
+
import { defineCapability } from "@rig/core/capability";
|
|
6
|
+
import { loadCapabilityForRoot } from "@rig/core/capability-loaders";
|
|
7
|
+
import { withMutedConsole } from "@rig/std-shared/cli-muted-console";
|
|
8
|
+
var HarnessProfileStateCap = defineCapability(HARNESS_PROFILE_STATE);
|
|
9
|
+
async function profileState(projectRoot) {
|
|
10
|
+
const service = await loadCapabilityForRoot(projectRoot, HarnessProfileStateCap);
|
|
11
|
+
if (!service) {
|
|
12
|
+
throw new CliError("Harness profile state capability unavailable: load @rig/harness-plugin (standard bundle).", 2);
|
|
13
|
+
}
|
|
14
|
+
return service;
|
|
15
|
+
}
|
|
16
|
+
var DEFAULT_AGENT_PROFILE = {
|
|
17
|
+
model: "pi",
|
|
18
|
+
runtime: "pi",
|
|
19
|
+
agent_plugin: "pi",
|
|
20
|
+
updated_at: new Date().toISOString()
|
|
21
|
+
};
|
|
22
|
+
var AGENT_PROFILE_FILE = "agent-profile.json";
|
|
23
|
+
async function showProfile(projectRoot) {
|
|
24
|
+
const state = await profileState(projectRoot);
|
|
25
|
+
const profile = { ...DEFAULT_AGENT_PROFILE, ...state.readHarnessStateJson(projectRoot, AGENT_PROFILE_FILE), model: "pi", runtime: "pi", agent_plugin: "pi" };
|
|
26
|
+
console.log("Execution Profile:");
|
|
27
|
+
console.log(` model: ${profile.model}`);
|
|
28
|
+
console.log(` runtime: ${profile.runtime}`);
|
|
29
|
+
console.log(` plugin: ${profile.agent_plugin}`);
|
|
30
|
+
}
|
|
31
|
+
async function setProfile(projectRoot, options) {
|
|
32
|
+
const invalid = [options.model, options.runtime, options.plugin, options.preset].filter((value) => typeof value === "string" && value.trim().length > 0 && value.trim() !== "pi");
|
|
33
|
+
if (invalid.length > 0) {
|
|
34
|
+
throw new CliError("Only the Pi runtime profile is supported by this Rig substrate.", 1, {
|
|
35
|
+
hint: 'Omit --model/--runtime/--plugin/--preset or pass "pi" explicitly.'
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const state = await profileState(projectRoot);
|
|
39
|
+
state.writeHarnessStateJson(projectRoot, AGENT_PROFILE_FILE, { ...DEFAULT_AGENT_PROFILE, updated_at: new Date().toISOString() });
|
|
40
|
+
await showProfile(projectRoot);
|
|
41
|
+
}
|
|
42
|
+
async function executeProfile(context, args) {
|
|
43
|
+
const [command = "show", ...rest] = args;
|
|
44
|
+
switch (command) {
|
|
45
|
+
case "show":
|
|
46
|
+
requireNoExtraArgs(rest, "rig profile show");
|
|
47
|
+
await withMutedConsole(context.outputMode === "json", () => showProfile(context.projectRoot));
|
|
48
|
+
return { ok: true, group: "profile", command };
|
|
49
|
+
case "set": {
|
|
50
|
+
let pending = rest;
|
|
51
|
+
const presetResult = takeOption(pending, "--preset");
|
|
52
|
+
pending = presetResult.rest;
|
|
53
|
+
const modelResult = takeOption(pending, "--model");
|
|
54
|
+
pending = modelResult.rest;
|
|
55
|
+
const runtimeResult = takeOption(pending, "--runtime");
|
|
56
|
+
pending = runtimeResult.rest;
|
|
57
|
+
const pluginResult = takeOption(pending, "--plugin");
|
|
58
|
+
pending = pluginResult.rest;
|
|
59
|
+
requireNoExtraArgs(pending, "rig profile set [--model ...] [--runtime ...] [--plugin ...]");
|
|
60
|
+
if (!presetResult.value && !modelResult.value && !runtimeResult.value && !pluginResult.value && rest.length === 0) {
|
|
61
|
+
throw new CliError("Provide at least one of --model, --runtime, or --plugin.", 1, {
|
|
62
|
+
hint: "Example: `rig profile set --model pi`. See current values with `rig profile show`."
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
await withMutedConsole(context.outputMode === "json", () => setProfile(context.projectRoot, {
|
|
66
|
+
...modelResult.value !== undefined ? { model: modelResult.value } : {},
|
|
67
|
+
...runtimeResult.value !== undefined ? { runtime: runtimeResult.value } : {},
|
|
68
|
+
...pluginResult.value !== undefined ? { plugin: pluginResult.value } : {},
|
|
69
|
+
...presetResult.value !== undefined ? { preset: presetResult.value } : {}
|
|
70
|
+
}));
|
|
71
|
+
return { ok: true, group: "profile", command, details: { lockedTo: "pi" } };
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
throw new CliError(`Unknown profile command: ${command}`, 1, { hint: "Run `rig profile --help` \u2014 commands are show|set." });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
executeProfile
|
|
79
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HarnessProfileStateService } from "@rig/contracts";
|
|
2
|
+
type JsonObject = object;
|
|
3
|
+
export declare function harnessStateJsonPath(projectRoot: string, filename: string): string;
|
|
4
|
+
export declare function readHarnessStateJson<T extends JsonObject>(projectRoot: string, filename: string): Partial<T> | null;
|
|
5
|
+
export declare function writeHarnessStateJson<T extends JsonObject>(projectRoot: string, filename: string, value: T): string;
|
|
6
|
+
export declare const harnessProfileStateService: HarnessProfileStateService;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/harness-plugin/src/profile-state.ts
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4
|
+
import { resolve } from "path";
|
|
5
|
+
import { resolveHarnessPaths } from "@rig/core/harness-paths";
|
|
6
|
+
function harnessStateJsonPath(projectRoot, filename) {
|
|
7
|
+
return resolve(resolveHarnessPaths(projectRoot).stateDir, filename);
|
|
8
|
+
}
|
|
9
|
+
function readHarnessStateJson(projectRoot, filename) {
|
|
10
|
+
const path = harnessStateJsonPath(projectRoot, filename);
|
|
11
|
+
if (!existsSync(path)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
16
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function writeHarnessStateJson(projectRoot, filename, value) {
|
|
22
|
+
const paths = resolveHarnessPaths(projectRoot);
|
|
23
|
+
mkdirSync(paths.stateDir, { recursive: true });
|
|
24
|
+
const path = resolve(paths.stateDir, filename);
|
|
25
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
26
|
+
`, "utf-8");
|
|
27
|
+
return path;
|
|
28
|
+
}
|
|
29
|
+
var harnessProfileStateService = {
|
|
30
|
+
harnessStateJsonPath,
|
|
31
|
+
readHarnessStateJson,
|
|
32
|
+
writeHarnessStateJson
|
|
33
|
+
};
|
|
34
|
+
export {
|
|
35
|
+
writeHarnessStateJson,
|
|
36
|
+
readHarnessStateJson,
|
|
37
|
+
harnessStateJsonPath,
|
|
38
|
+
harnessProfileStateService
|
|
39
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Return the rig-task-run skill body (markdown without frontmatter).
|
|
3
|
+
*
|
|
4
|
+
* The file is shipped at `packages/runtime/skills/rig-task-run.md`. We search
|
|
5
|
+
* a few paths so it resolves whether the caller is running from monorepo
|
|
6
|
+
* source, from a sibling import, or via the published @rig/runtime exports.
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadRigTaskRunSkillBody(): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/harness-plugin/src/rig-task-run-skill.ts
|
|
3
|
+
import { existsSync, readFileSync } from "fs";
|
|
4
|
+
import { dirname, resolve } from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
var SKILL_FILENAME = "rig-task-run.md";
|
|
7
|
+
var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
8
|
+
var cachedBody = null;
|
|
9
|
+
function loadRigTaskRunSkillBody() {
|
|
10
|
+
if (cachedBody !== null) {
|
|
11
|
+
return cachedBody;
|
|
12
|
+
}
|
|
13
|
+
const path = resolveSkillPath();
|
|
14
|
+
if (!path) {
|
|
15
|
+
cachedBody = "";
|
|
16
|
+
return cachedBody;
|
|
17
|
+
}
|
|
18
|
+
const raw = readFileSync(path, "utf-8");
|
|
19
|
+
const match = raw.match(FRONTMATTER_RE);
|
|
20
|
+
cachedBody = (match ? match[2] ?? raw : raw).trim();
|
|
21
|
+
return cachedBody;
|
|
22
|
+
}
|
|
23
|
+
function resolveSkillPath() {
|
|
24
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const candidates = [
|
|
26
|
+
resolve(here, "..", "skills", SKILL_FILENAME),
|
|
27
|
+
resolve(here, "..", "..", "skills", SKILL_FILENAME),
|
|
28
|
+
resolve(here, "..", "..", "..", "skills", SKILL_FILENAME)
|
|
29
|
+
];
|
|
30
|
+
for (const candidate of candidates) {
|
|
31
|
+
if (existsSync(candidate)) {
|
|
32
|
+
return candidate;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
loadRigTaskRunSkillBody
|
|
39
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type RuntimeInstructionProvider = "pi";
|
|
2
|
+
export declare function normalizeRuntimeInstructionProvider(_value: string | undefined | null): RuntimeInstructionProvider;
|
|
3
|
+
export declare function buildProviderTaskRunInstructionLines(_provider: RuntimeInstructionProvider): string[];
|
|
4
|
+
export declare function buildProviderRuntimeContextLines(_provider: RuntimeInstructionProvider): string[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/harness-plugin/src/runtime-instructions.ts
|
|
3
|
+
function normalizeRuntimeInstructionProvider(_value) {
|
|
4
|
+
return "pi";
|
|
5
|
+
}
|
|
6
|
+
function buildProviderTaskRunInstructionLines(_provider) {
|
|
7
|
+
return [
|
|
8
|
+
"Use Pi's built-in `read`, `write`, `edit`, and `bash` tools from the isolated Rig task worktree.",
|
|
9
|
+
"Keep file writes inside the scoped task workspace unless Rig explicitly tells you a path is host/project metadata.",
|
|
10
|
+
"Prefer `read`, `write`, and `edit` over shell one-liners whenever those tools fit.",
|
|
11
|
+
"When shell access is needed, keep commands narrow and bounded; avoid repo-wide searches without an explicit path and output cap."
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
function buildProviderRuntimeContextLines(_provider) {
|
|
15
|
+
return [
|
|
16
|
+
"Pi runs from the isolated Rig task worktree with its built-in `read`, `write`, `edit`, and `bash` tools enabled.",
|
|
17
|
+
"Keep writes scoped to the task workspace unless Rig-provided instructions name an explicit metadata path.",
|
|
18
|
+
"Prefer Pi file tools over shell one-liners for file reads and edits.",
|
|
19
|
+
"Keep shell commands narrow and bounded; cap broad searches before widening."
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
normalizeRuntimeInstructionProvider,
|
|
24
|
+
buildProviderTaskRunInstructionLines,
|
|
25
|
+
buildProviderRuntimeContextLines
|
|
26
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RuntimeSecrets, RuntimeSecretsService } from "@rig/contracts";
|
|
2
|
+
export declare const BAKED_RUNTIME_SECRETS: RuntimeSecrets;
|
|
3
|
+
export declare function resolveRuntimeSecrets(env: Record<string, string | undefined>, baked?: RuntimeSecrets): RuntimeSecrets;
|
|
4
|
+
export declare function loadDotEnvSecrets(projectRoot: string, env?: Record<string, string | undefined>): RuntimeSecrets;
|
|
5
|
+
export declare function secretDefinesFromEnv(env?: Record<string, string | undefined>, projectRoot?: string): Record<string, string>;
|
|
6
|
+
export declare const runtimeSecretsService: RuntimeSecretsService;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/harness-plugin/src/runtime-secrets.ts
|
|
3
|
+
import { loadDotEnvValues, resolveRuntimeConfigValues } from "@rig/core/baked-secrets";
|
|
4
|
+
var BAKED_RUNTIME_SECRETS = {
|
|
5
|
+
ANTHROPIC_API_KEY: typeof RIG_BAKED_ANTHROPIC_API_KEY !== "undefined" ? RIG_BAKED_ANTHROPIC_API_KEY : "",
|
|
6
|
+
OPENAI_API_KEY: typeof RIG_BAKED_OPENAI_API_KEY !== "undefined" ? RIG_BAKED_OPENAI_API_KEY : "",
|
|
7
|
+
OPENROUTER_API_KEY: typeof RIG_BAKED_OPENROUTER_API_KEY !== "undefined" ? RIG_BAKED_OPENROUTER_API_KEY : "",
|
|
8
|
+
AI_REVIEW_MODE: typeof RIG_BAKED_AI_REVIEW_MODE !== "undefined" ? RIG_BAKED_AI_REVIEW_MODE : "",
|
|
9
|
+
AI_REVIEW_PROVIDER: typeof RIG_BAKED_AI_REVIEW_PROVIDER !== "undefined" ? RIG_BAKED_AI_REVIEW_PROVIDER : "",
|
|
10
|
+
GH_TOKEN: typeof RIG_BAKED_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GITHUB_TOKEN : "",
|
|
11
|
+
GITHUB_TOKEN: typeof RIG_BAKED_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GITHUB_TOKEN : "",
|
|
12
|
+
GITHUB_SSH_KEY: typeof RIG_BAKED_GITHUB_SSH_KEY !== "undefined" ? RIG_BAKED_GITHUB_SSH_KEY : "",
|
|
13
|
+
AWS_ACCESS_KEY_ID: typeof RIG_BAKED_AWS_ACCESS_KEY_ID !== "undefined" ? RIG_BAKED_AWS_ACCESS_KEY_ID : "",
|
|
14
|
+
AWS_SECRET_ACCESS_KEY: typeof RIG_BAKED_AWS_SECRET_ACCESS_KEY !== "undefined" ? RIG_BAKED_AWS_SECRET_ACCESS_KEY : "",
|
|
15
|
+
AWS_REGION: typeof RIG_BAKED_AWS_REGION !== "undefined" ? RIG_BAKED_AWS_REGION : "",
|
|
16
|
+
LINEAR_API_KEY: typeof RIG_BAKED_LINEAR_API_KEY !== "undefined" ? RIG_BAKED_LINEAR_API_KEY : "",
|
|
17
|
+
LINEAR_WEBHOOK_SECRET: typeof RIG_BAKED_LINEAR_WEBHOOK_SECRET !== "undefined" ? RIG_BAKED_LINEAR_WEBHOOK_SECRET : ""
|
|
18
|
+
};
|
|
19
|
+
var RUNTIME_SECRET_KEYS = Object.keys(BAKED_RUNTIME_SECRETS);
|
|
20
|
+
function resolveRuntimeSecrets(env, baked = BAKED_RUNTIME_SECRETS) {
|
|
21
|
+
return resolveRuntimeConfigValues(env, RUNTIME_SECRET_KEYS, baked);
|
|
22
|
+
}
|
|
23
|
+
function loadDotEnvSecrets(projectRoot, env = process.env) {
|
|
24
|
+
return loadDotEnvValues(projectRoot, RUNTIME_SECRET_KEYS, env);
|
|
25
|
+
}
|
|
26
|
+
function secretDefinesFromEnv(env = process.env, projectRoot) {
|
|
27
|
+
const dotenvSecrets = projectRoot ? loadDotEnvSecrets(projectRoot, env) : {};
|
|
28
|
+
const resolved = resolveRuntimeSecrets(env, {
|
|
29
|
+
...BAKED_RUNTIME_SECRETS,
|
|
30
|
+
...dotenvSecrets
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
RIG_BAKED_ANTHROPIC_API_KEY: resolved.ANTHROPIC_API_KEY || "",
|
|
34
|
+
RIG_BAKED_OPENAI_API_KEY: resolved.OPENAI_API_KEY || "",
|
|
35
|
+
RIG_BAKED_OPENROUTER_API_KEY: resolved.OPENROUTER_API_KEY || "",
|
|
36
|
+
RIG_BAKED_AI_REVIEW_MODE: resolved.AI_REVIEW_MODE || "",
|
|
37
|
+
RIG_BAKED_AI_REVIEW_PROVIDER: resolved.AI_REVIEW_PROVIDER || "",
|
|
38
|
+
RIG_BAKED_GITHUB_TOKEN: resolved.GITHUB_TOKEN || resolved.GH_TOKEN || "",
|
|
39
|
+
RIG_BAKED_GITHUB_SSH_KEY: resolved.GITHUB_SSH_KEY || "",
|
|
40
|
+
RIG_BAKED_AWS_ACCESS_KEY_ID: resolved.AWS_ACCESS_KEY_ID || "",
|
|
41
|
+
RIG_BAKED_AWS_SECRET_ACCESS_KEY: resolved.AWS_SECRET_ACCESS_KEY || "",
|
|
42
|
+
RIG_BAKED_AWS_REGION: resolved.AWS_REGION || "",
|
|
43
|
+
RIG_BAKED_LINEAR_API_KEY: resolved.LINEAR_API_KEY || "",
|
|
44
|
+
RIG_BAKED_LINEAR_WEBHOOK_SECRET: resolved.LINEAR_WEBHOOK_SECRET || ""
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
var runtimeSecretsService = {
|
|
48
|
+
resolveRuntimeSecrets,
|
|
49
|
+
loadDotEnvSecrets,
|
|
50
|
+
secretDefinesFromEnv
|
|
51
|
+
};
|
|
52
|
+
export {
|
|
53
|
+
secretDefinesFromEnv,
|
|
54
|
+
runtimeSecretsService,
|
|
55
|
+
resolveRuntimeSecrets,
|
|
56
|
+
loadDotEnvSecrets,
|
|
57
|
+
BAKED_RUNTIME_SECRETS
|
|
58
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* service.ts — the concrete agent-harness instruction service the runtime port
|
|
3
|
+
* resolves and consumes.
|
|
4
|
+
*
|
|
5
|
+
* CONFIG-LIGHT: this module top-level-imports the instruction-builder impl. It
|
|
6
|
+
* is loaded LAZILY by the capability `run()` in plugin.ts
|
|
7
|
+
* (`(await import("./service")).svc`), so merely evaluating rig.config.ts never
|
|
8
|
+
* drags the provider impl into scope.
|
|
9
|
+
*/
|
|
10
|
+
import type { RuntimeInstructionService } from "@rig/contracts";
|
|
11
|
+
/** The concrete agent-harness instruction service the runtime port resolves. */
|
|
12
|
+
export declare const svc: RuntimeInstructionService;
|
|
13
|
+
/** Back-compat alias. */
|
|
14
|
+
export declare const runtimeInstructionService: RuntimeInstructionService;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/harness-plugin/src/runtime-instructions.ts
|
|
3
|
+
function normalizeRuntimeInstructionProvider(_value) {
|
|
4
|
+
return "pi";
|
|
5
|
+
}
|
|
6
|
+
function buildProviderTaskRunInstructionLines(_provider) {
|
|
7
|
+
return [
|
|
8
|
+
"Use Pi's built-in `read`, `write`, `edit`, and `bash` tools from the isolated Rig task worktree.",
|
|
9
|
+
"Keep file writes inside the scoped task workspace unless Rig explicitly tells you a path is host/project metadata.",
|
|
10
|
+
"Prefer `read`, `write`, and `edit` over shell one-liners whenever those tools fit.",
|
|
11
|
+
"When shell access is needed, keep commands narrow and bounded; avoid repo-wide searches without an explicit path and output cap."
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
function buildProviderRuntimeContextLines(_provider) {
|
|
15
|
+
return [
|
|
16
|
+
"Pi runs from the isolated Rig task worktree with its built-in `read`, `write`, `edit`, and `bash` tools enabled.",
|
|
17
|
+
"Keep writes scoped to the task workspace unless Rig-provided instructions name an explicit metadata path.",
|
|
18
|
+
"Prefer Pi file tools over shell one-liners for file reads and edits.",
|
|
19
|
+
"Keep shell commands narrow and bounded; cap broad searches before widening."
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// packages/harness-plugin/src/service.ts
|
|
24
|
+
var svc = {
|
|
25
|
+
normalizeProvider: normalizeRuntimeInstructionProvider,
|
|
26
|
+
buildTaskRunInstructionLines: buildProviderTaskRunInstructionLines,
|
|
27
|
+
buildRuntimeContextLines: buildProviderRuntimeContextLines
|
|
28
|
+
};
|
|
29
|
+
var runtimeInstructionService = svc;
|
|
30
|
+
export {
|
|
31
|
+
svc,
|
|
32
|
+
runtimeInstructionService
|
|
33
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SessionAssetMaterializerService } from "@rig/contracts";
|
|
2
|
+
/**
|
|
3
|
+
* Provider-owned implementation of the SESSION_ASSET_MATERIALIZER capability.
|
|
4
|
+
*
|
|
5
|
+
* This is the logic that previously lived inline in the runtime's
|
|
6
|
+
* `plugin-host-context`: extract plugin-contributed skills + config-declared Pi
|
|
7
|
+
* packages from the loaded rig.config and materialize them into the workspace's
|
|
8
|
+
* `.pi/` directory. It moved here (provider domain) so the plugin-host assembler
|
|
9
|
+
* in @rig/core can trigger materialization through the capability seam without a
|
|
10
|
+
* floor->plugin import. Every step is non-fatal — a write failure logs and
|
|
11
|
+
* continues so it can never deadlock harness boot.
|
|
12
|
+
*/
|
|
13
|
+
export declare const sessionAssetMaterializer: SessionAssetMaterializerService;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/harness-plugin/src/session-asset-materializer-service.ts
|
|
3
|
+
import { existsSync as existsSync3 } from "fs";
|
|
4
|
+
import { resolve as resolvePath } from "path";
|
|
5
|
+
|
|
6
|
+
// packages/harness-plugin/src/skill-materializer.ts
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs";
|
|
8
|
+
import { resolve } from "path";
|
|
9
|
+
var MARKER_FILENAME = ".rig-plugin";
|
|
10
|
+
var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
11
|
+
function parseFrontmatter(raw) {
|
|
12
|
+
const m = raw.match(FRONTMATTER_RE);
|
|
13
|
+
if (!m) {
|
|
14
|
+
return { meta: {}, body: raw };
|
|
15
|
+
}
|
|
16
|
+
const yaml = m[1] ?? "";
|
|
17
|
+
const body = m[2] ?? "";
|
|
18
|
+
const meta = {};
|
|
19
|
+
for (const line of yaml.split(/\r?\n/)) {
|
|
20
|
+
const trimmed = line.trim();
|
|
21
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
22
|
+
continue;
|
|
23
|
+
const idx = trimmed.indexOf(":");
|
|
24
|
+
if (idx === -1)
|
|
25
|
+
continue;
|
|
26
|
+
const key = trimmed.slice(0, idx).trim();
|
|
27
|
+
let value = trimmed.slice(idx + 1).trim();
|
|
28
|
+
if (typeof value === "string") {
|
|
29
|
+
const s = value;
|
|
30
|
+
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
31
|
+
value = s.slice(1, -1);
|
|
32
|
+
} else if (s === "true")
|
|
33
|
+
value = true;
|
|
34
|
+
else if (s === "false")
|
|
35
|
+
value = false;
|
|
36
|
+
else if (/^-?\d+$/.test(s))
|
|
37
|
+
value = parseInt(s, 10);
|
|
38
|
+
else if (/^-?\d+\.\d+$/.test(s))
|
|
39
|
+
value = parseFloat(s);
|
|
40
|
+
}
|
|
41
|
+
meta[key] = value;
|
|
42
|
+
}
|
|
43
|
+
return { meta, body };
|
|
44
|
+
}
|
|
45
|
+
function assertValidSkillFrontmatter(path, raw) {
|
|
46
|
+
const { meta } = parseFrontmatter(raw);
|
|
47
|
+
if (typeof meta.name !== "string") {
|
|
48
|
+
throw new Error(`SKILL.md missing required field "name": ${path}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function skillDirName(id) {
|
|
52
|
+
return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
53
|
+
}
|
|
54
|
+
async function materializeSkills(projectRoot, entries) {
|
|
55
|
+
const skillsRoot = resolve(projectRoot, ".pi", "skills");
|
|
56
|
+
if (existsSync(skillsRoot)) {
|
|
57
|
+
for (const name of readdirSync(skillsRoot)) {
|
|
58
|
+
const dir = resolve(skillsRoot, name);
|
|
59
|
+
if (existsSync(resolve(dir, MARKER_FILENAME))) {
|
|
60
|
+
rmSync(dir, { recursive: true, force: true });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const written = [];
|
|
65
|
+
for (const { pluginName, skill } of entries) {
|
|
66
|
+
const sourcePath = resolve(projectRoot, skill.path);
|
|
67
|
+
if (!existsSync(sourcePath)) {
|
|
68
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
let body;
|
|
72
|
+
try {
|
|
73
|
+
body = readFileSync(sourcePath, "utf-8");
|
|
74
|
+
assertValidSkillFrontmatter(sourcePath, body);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const dir = resolve(skillsRoot, skillDirName(skill.id));
|
|
80
|
+
mkdirSync(dir, { recursive: true });
|
|
81
|
+
writeFileSync(resolve(dir, "SKILL.md"), body, "utf-8");
|
|
82
|
+
writeFileSync(resolve(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
|
|
83
|
+
`, "utf-8");
|
|
84
|
+
written.push({ id: skill.id, pluginName, directory: dir });
|
|
85
|
+
}
|
|
86
|
+
return written;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// packages/harness-plugin/src/pi-settings-materializer.ts
|
|
90
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
91
|
+
import { dirname, resolve as resolve2 } from "path";
|
|
92
|
+
var SETTINGS_RELATIVE_PATH = ".pi/settings.json";
|
|
93
|
+
var MANAGED_RECORD_RELATIVE_PATH = ".rig/state/pi-managed-packages.json";
|
|
94
|
+
function readJson(path, fallback) {
|
|
95
|
+
if (!existsSync2(path))
|
|
96
|
+
return fallback;
|
|
97
|
+
try {
|
|
98
|
+
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
99
|
+
} catch {
|
|
100
|
+
return fallback;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function packageKey(entry) {
|
|
104
|
+
if (typeof entry === "string")
|
|
105
|
+
return entry;
|
|
106
|
+
if (entry && typeof entry === "object" && typeof entry.source === "string") {
|
|
107
|
+
return entry.source;
|
|
108
|
+
}
|
|
109
|
+
return JSON.stringify(entry);
|
|
110
|
+
}
|
|
111
|
+
function materializePiPackages(projectRoot, declaredPackages) {
|
|
112
|
+
const settingsPath = resolve2(projectRoot, SETTINGS_RELATIVE_PATH);
|
|
113
|
+
const managedRecordPath = resolve2(projectRoot, MANAGED_RECORD_RELATIVE_PATH);
|
|
114
|
+
const settings = readJson(settingsPath, {});
|
|
115
|
+
const previouslyManaged = new Set(readJson(managedRecordPath, []));
|
|
116
|
+
const existing = Array.isArray(settings.packages) ? settings.packages : [];
|
|
117
|
+
const operatorEntries = existing.filter((entry) => !previouslyManaged.has(packageKey(entry)));
|
|
118
|
+
const operatorKeys = new Set(operatorEntries.map(packageKey));
|
|
119
|
+
const managedToAdd = declaredPackages.filter((pkg) => !operatorKeys.has(pkg));
|
|
120
|
+
const nextPackages = [...operatorEntries, ...managedToAdd];
|
|
121
|
+
if (nextPackages.length > 0 || existsSync2(settingsPath)) {
|
|
122
|
+
const nextSettings = { ...settings };
|
|
123
|
+
if (nextPackages.length > 0) {
|
|
124
|
+
nextSettings.packages = nextPackages;
|
|
125
|
+
} else {
|
|
126
|
+
delete nextSettings.packages;
|
|
127
|
+
}
|
|
128
|
+
mkdirSync2(dirname(settingsPath), { recursive: true });
|
|
129
|
+
writeFileSync2(settingsPath, `${JSON.stringify(nextSettings, null, 2)}
|
|
130
|
+
`, "utf-8");
|
|
131
|
+
}
|
|
132
|
+
mkdirSync2(dirname(managedRecordPath), { recursive: true });
|
|
133
|
+
writeFileSync2(managedRecordPath, `${JSON.stringify(managedToAdd, null, 2)}
|
|
134
|
+
`, "utf-8");
|
|
135
|
+
return { settingsPath, packages: managedToAdd };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// packages/harness-plugin/src/session-asset-materializer-service.ts
|
|
139
|
+
var sessionAssetMaterializer = {
|
|
140
|
+
async materializeSessionAssets(projectRoot, config) {
|
|
141
|
+
try {
|
|
142
|
+
const skillEntries = config.plugins.flatMap((plugin) => (plugin.contributes?.skills ?? []).map((skill) => ({
|
|
143
|
+
pluginName: plugin.name,
|
|
144
|
+
skill
|
|
145
|
+
})));
|
|
146
|
+
if (skillEntries.length > 0) {
|
|
147
|
+
await materializeSkills(projectRoot, skillEntries);
|
|
148
|
+
}
|
|
149
|
+
} catch (err) {
|
|
150
|
+
console.warn(`[session-assets] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const piPackages = config.runtime?.pi?.packages ?? [];
|
|
154
|
+
if (piPackages.length > 0 || existsSync3(resolvePath(projectRoot, ".rig/state/pi-managed-packages.json"))) {
|
|
155
|
+
materializePiPackages(projectRoot, piPackages);
|
|
156
|
+
}
|
|
157
|
+
} catch (err) {
|
|
158
|
+
console.warn(`[session-assets] Pi package materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
export {
|
|
163
|
+
sessionAssetMaterializer
|
|
164
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { HookEvent, PluginHookEntry, SessionHookMaterializerService } from "@rig/contracts";
|
|
2
|
+
export type SessionHookAdapterResult = {
|
|
3
|
+
readonly adapterId: "claude-code";
|
|
4
|
+
readonly status: "materialized";
|
|
5
|
+
readonly path: string;
|
|
6
|
+
readonly events: readonly HookEvent[];
|
|
7
|
+
} | {
|
|
8
|
+
readonly adapterId: "pi";
|
|
9
|
+
readonly status: "skipped";
|
|
10
|
+
readonly reason: string;
|
|
11
|
+
};
|
|
12
|
+
export interface AgentSessionHookAdapter {
|
|
13
|
+
readonly id: "claude-code" | "pi";
|
|
14
|
+
materialize(projectRoot: string, entries: readonly PluginHookEntry[]): SessionHookAdapterResult;
|
|
15
|
+
}
|
|
16
|
+
export declare function createPiNoopSessionHookAdapter(): AgentSessionHookAdapter;
|
|
17
|
+
export declare function createClaudeCodeSessionHookAdapter(): AgentSessionHookAdapter;
|
|
18
|
+
export type AgentSessionHookAdapterEnv = Record<string, string | undefined>;
|
|
19
|
+
export declare function defaultAgentSessionHookAdapters(env?: AgentSessionHookAdapterEnv): readonly AgentSessionHookAdapter[];
|
|
20
|
+
export declare function materializeSessionHookAdapters(projectRoot: string, entries: readonly PluginHookEntry[], adapters?: readonly AgentSessionHookAdapter[]): readonly SessionHookAdapterResult[];
|
|
21
|
+
/**
|
|
22
|
+
* Materialize plugin-contributed hooks into `.claude/settings.json` via the
|
|
23
|
+
* Claude Code session-hook adapter. Kept provider-owned for tests/CLI helpers;
|
|
24
|
+
* core no longer imports or calls this function.
|
|
25
|
+
*/
|
|
26
|
+
export declare function materializeHooks(projectRoot: string, entries: readonly PluginHookEntry[]): string;
|
|
27
|
+
export type ApplyClaudeCodeSessionHooksOptions = {
|
|
28
|
+
readonly replacePluginOwned?: boolean;
|
|
29
|
+
};
|
|
30
|
+
export declare function applyClaudeCodeSessionHooksToSettings(existing: Record<string, unknown>, entries: readonly PluginHookEntry[], projectRoot: string, options?: ApplyClaudeCodeSessionHooksOptions): {
|
|
31
|
+
readonly settings: Record<string, unknown>;
|
|
32
|
+
readonly events: readonly HookEvent[];
|
|
33
|
+
};
|
|
34
|
+
export declare const sessionHookMaterializer: SessionHookMaterializerService;
|