@h-rig/cli 0.0.6-alpha.34 → 0.0.6-alpha.36
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/bin/rig.js +484 -238
- package/dist/src/commands/_help-catalog.js +14 -0
- package/dist/src/commands/_operator-view.js +35 -4
- package/dist/src/commands/_pi-frontend.js +35 -4
- package/dist/src/commands/_pi-worker-bridge-extension.js +35 -2
- package/dist/src/commands/_server-client.js +0 -9
- package/dist/src/commands/inspect.js +227 -11
- package/dist/src/commands/pi.js +168 -0
- package/dist/src/commands/run.js +62 -4
- package/dist/src/commands/server.js +7 -2
- package/dist/src/commands/task.js +49 -4
- package/dist/src/commands.js +476 -230
- package/dist/src/index.js +484 -238
- package/package.json +6 -6
package/dist/src/index.js
CHANGED
|
@@ -527,9 +527,9 @@ var init_plugin = __esm(() => {
|
|
|
527
527
|
// packages/cli/src/commands.ts
|
|
528
528
|
init_runner();
|
|
529
529
|
import {
|
|
530
|
-
existsSync as
|
|
530
|
+
existsSync as existsSync16
|
|
531
531
|
} from "fs";
|
|
532
|
-
import { resolve as
|
|
532
|
+
import { resolve as resolve25 } from "path";
|
|
533
533
|
import { readBuildConfig } from "@rig/runtime/build-time-config";
|
|
534
534
|
|
|
535
535
|
// packages/cli/src/commands/browser.ts
|
|
@@ -2640,6 +2640,157 @@ async function executeHarness(context, args) {
|
|
|
2640
2640
|
// packages/cli/src/commands.ts
|
|
2641
2641
|
init_plugin();
|
|
2642
2642
|
|
|
2643
|
+
// packages/cli/src/commands/pi.ts
|
|
2644
|
+
init_runner();
|
|
2645
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2646
|
+
import { homedir as homedir2 } from "os";
|
|
2647
|
+
import { dirname, resolve as resolve9 } from "path";
|
|
2648
|
+
function settingsPath(root) {
|
|
2649
|
+
return resolve9(root, ".pi", "settings.json");
|
|
2650
|
+
}
|
|
2651
|
+
function userSettingsPath() {
|
|
2652
|
+
return resolve9(homedir2(), ".pi", "agent", "settings.json");
|
|
2653
|
+
}
|
|
2654
|
+
function readJson(path, fallback) {
|
|
2655
|
+
if (!existsSync5(path))
|
|
2656
|
+
return fallback;
|
|
2657
|
+
try {
|
|
2658
|
+
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
2659
|
+
} catch {
|
|
2660
|
+
return fallback;
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
function packageKey(entry) {
|
|
2664
|
+
if (typeof entry === "string")
|
|
2665
|
+
return entry;
|
|
2666
|
+
if (entry && typeof entry === "object" && typeof entry.source === "string") {
|
|
2667
|
+
return entry.source;
|
|
2668
|
+
}
|
|
2669
|
+
return JSON.stringify(entry);
|
|
2670
|
+
}
|
|
2671
|
+
function writeSettings(path, settings) {
|
|
2672
|
+
mkdirSync5(dirname(path), { recursive: true });
|
|
2673
|
+
writeFileSync3(path, `${JSON.stringify(settings, null, 2)}
|
|
2674
|
+
`, "utf-8");
|
|
2675
|
+
}
|
|
2676
|
+
async function searchNpmForPiExtensions(term) {
|
|
2677
|
+
const query = encodeURIComponent(term ? `${term} pi extension` : "pi extension");
|
|
2678
|
+
const url = `https://registry.npmjs.org/-/v1/search?text=${query}&size=20`;
|
|
2679
|
+
const response = await fetch(url);
|
|
2680
|
+
if (!response.ok) {
|
|
2681
|
+
throw new CliError2(`npm registry search failed (${response.status}).`, 2);
|
|
2682
|
+
}
|
|
2683
|
+
const payload = await response.json();
|
|
2684
|
+
const results = [];
|
|
2685
|
+
for (const entry of payload.objects ?? []) {
|
|
2686
|
+
const pkg = entry.package;
|
|
2687
|
+
if (!pkg?.name)
|
|
2688
|
+
continue;
|
|
2689
|
+
const keywords = (pkg.keywords ?? []).map((k) => k.toLowerCase());
|
|
2690
|
+
const piLike = pkg.name.startsWith("pi-") || pkg.name.includes("-pi") || keywords.includes("pi") || keywords.includes("pi-extension") || (pkg.description ?? "").toLowerCase().includes("pi extension") || (pkg.description ?? "").toLowerCase().includes("pi coding agent");
|
|
2691
|
+
if (!piLike)
|
|
2692
|
+
continue;
|
|
2693
|
+
results.push({ name: pkg.name, version: pkg.version ?? "", description: pkg.description ?? "" });
|
|
2694
|
+
}
|
|
2695
|
+
return results;
|
|
2696
|
+
}
|
|
2697
|
+
async function executePi(context, args) {
|
|
2698
|
+
const [command = "list", ...rest] = args;
|
|
2699
|
+
const projectSettingsPath = settingsPath(context.projectRoot);
|
|
2700
|
+
const managedRecordPath = resolve9(context.projectRoot, ".rig", "state", "pi-managed-packages.json");
|
|
2701
|
+
switch (command) {
|
|
2702
|
+
case "list": {
|
|
2703
|
+
requireNoExtraArgs(rest, "rig pi list");
|
|
2704
|
+
const project = readJson(projectSettingsPath, {});
|
|
2705
|
+
const managed = new Set(readJson(managedRecordPath, []));
|
|
2706
|
+
const user = readJson(userSettingsPath(), {});
|
|
2707
|
+
const projectPackages = (Array.isArray(project.packages) ? project.packages : []).map((entry) => ({
|
|
2708
|
+
source: packageKey(entry),
|
|
2709
|
+
managedByRigConfig: managed.has(packageKey(entry))
|
|
2710
|
+
}));
|
|
2711
|
+
const userPackages = (Array.isArray(user.packages) ? user.packages : []).map(packageKey);
|
|
2712
|
+
if (context.outputMode === "text") {
|
|
2713
|
+
console.log("Project Pi packages (.pi/settings.json):");
|
|
2714
|
+
if (projectPackages.length === 0)
|
|
2715
|
+
console.log(" (none)");
|
|
2716
|
+
for (const pkg of projectPackages) {
|
|
2717
|
+
console.log(` ${pkg.source}${pkg.managedByRigConfig ? " [from rig.config runtime.pi.packages]" : ""}`);
|
|
2718
|
+
}
|
|
2719
|
+
console.log("User Pi packages (~/.pi/agent/settings.json):");
|
|
2720
|
+
if (userPackages.length === 0)
|
|
2721
|
+
console.log(" (none)");
|
|
2722
|
+
for (const pkg of userPackages)
|
|
2723
|
+
console.log(` ${pkg}`);
|
|
2724
|
+
console.log("Add more: `rig pi add <npm-package>` \xB7 discover: `rig pi search <term>`");
|
|
2725
|
+
}
|
|
2726
|
+
return { ok: true, group: "pi", command, details: { projectPackages, userPackages } };
|
|
2727
|
+
}
|
|
2728
|
+
case "add": {
|
|
2729
|
+
const [source, ...extra] = rest;
|
|
2730
|
+
requireNoExtraArgs(extra, "rig pi add <package-source>");
|
|
2731
|
+
if (!source) {
|
|
2732
|
+
throw new CliError2("Usage: rig pi add <package-source> (npm name, name@version, or git URL)", 2);
|
|
2733
|
+
}
|
|
2734
|
+
const settings = readJson(projectSettingsPath, {});
|
|
2735
|
+
const packages = Array.isArray(settings.packages) ? settings.packages : [];
|
|
2736
|
+
if (packages.some((entry) => packageKey(entry) === source)) {
|
|
2737
|
+
throw new CliError2(`"${source}" is already in ${projectSettingsPath}.`, 2);
|
|
2738
|
+
}
|
|
2739
|
+
writeSettings(projectSettingsPath, { ...settings, packages: [...packages, source] });
|
|
2740
|
+
if (context.outputMode === "text") {
|
|
2741
|
+
console.log(`Added ${source} to ${projectSettingsPath}.`);
|
|
2742
|
+
console.log("Pi installs missing packages automatically at the next session start (local and worker).");
|
|
2743
|
+
}
|
|
2744
|
+
return { ok: true, group: "pi", command, details: { source, settingsPath: projectSettingsPath } };
|
|
2745
|
+
}
|
|
2746
|
+
case "remove": {
|
|
2747
|
+
const [source, ...extra] = rest;
|
|
2748
|
+
requireNoExtraArgs(extra, "rig pi remove <package-source>");
|
|
2749
|
+
if (!source) {
|
|
2750
|
+
throw new CliError2("Usage: rig pi remove <package-source>", 2);
|
|
2751
|
+
}
|
|
2752
|
+
const managed = new Set(readJson(managedRecordPath, []));
|
|
2753
|
+
if (managed.has(source)) {
|
|
2754
|
+
throw new CliError2(`"${source}" is managed by rig.config.ts (runtime.pi.packages); remove it there instead.`, 2);
|
|
2755
|
+
}
|
|
2756
|
+
const settings = readJson(projectSettingsPath, {});
|
|
2757
|
+
const packages = Array.isArray(settings.packages) ? settings.packages : [];
|
|
2758
|
+
const next = packages.filter((entry) => packageKey(entry) !== source);
|
|
2759
|
+
if (next.length === packages.length) {
|
|
2760
|
+
throw new CliError2(`"${source}" is not in ${projectSettingsPath}.`, 2);
|
|
2761
|
+
}
|
|
2762
|
+
const nextSettings = { ...settings };
|
|
2763
|
+
if (next.length > 0)
|
|
2764
|
+
nextSettings.packages = next;
|
|
2765
|
+
else
|
|
2766
|
+
delete nextSettings.packages;
|
|
2767
|
+
writeSettings(projectSettingsPath, nextSettings);
|
|
2768
|
+
if (context.outputMode === "text") {
|
|
2769
|
+
console.log(`Removed ${source} from ${projectSettingsPath}.`);
|
|
2770
|
+
}
|
|
2771
|
+
return { ok: true, group: "pi", command, details: { source } };
|
|
2772
|
+
}
|
|
2773
|
+
case "search": {
|
|
2774
|
+
const term = rest.join(" ").trim();
|
|
2775
|
+
const results = await searchNpmForPiExtensions(term);
|
|
2776
|
+
if (context.outputMode === "text") {
|
|
2777
|
+
if (results.length === 0) {
|
|
2778
|
+
console.log(`No Pi extension packages found on npm${term ? ` for "${term}"` : ""}.`);
|
|
2779
|
+
} else {
|
|
2780
|
+
console.log(`Pi extension packages on npm${term ? ` matching "${term}"` : ""}:`);
|
|
2781
|
+
for (const pkg of results) {
|
|
2782
|
+
console.log(` ${pkg.name}@${pkg.version} ${pkg.description.slice(0, 80)}`);
|
|
2783
|
+
}
|
|
2784
|
+
console.log("Install one: `rig pi add <name>`");
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
return { ok: true, group: "pi", command, details: { term, results } };
|
|
2788
|
+
}
|
|
2789
|
+
default:
|
|
2790
|
+
throw new CliError2(`Unknown pi command: ${command}. Use list|add|remove|search.`);
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2643
2794
|
// packages/cli/src/commands/queue.ts
|
|
2644
2795
|
init_runner();
|
|
2645
2796
|
init__parsers();
|
|
@@ -2651,33 +2802,33 @@ import { ensureProjectMainFreshBeforeRun } from "@rig/runtime/control-plane/proj
|
|
|
2651
2802
|
|
|
2652
2803
|
// packages/cli/src/commands/_connection-state.ts
|
|
2653
2804
|
init_runner();
|
|
2654
|
-
import { existsSync as
|
|
2655
|
-
import { homedir as
|
|
2656
|
-
import { dirname, resolve as
|
|
2805
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
2806
|
+
import { homedir as homedir3 } from "os";
|
|
2807
|
+
import { dirname as dirname2, resolve as resolve10 } from "path";
|
|
2657
2808
|
function resolveGlobalConnectionsPath(env = process.env) {
|
|
2658
2809
|
const explicit = env.RIG_CONNECTIONS_FILE?.trim();
|
|
2659
2810
|
if (explicit)
|
|
2660
|
-
return
|
|
2811
|
+
return resolve10(explicit);
|
|
2661
2812
|
const stateDir = env.RIG_GLOBAL_STATE_DIR?.trim();
|
|
2662
2813
|
if (stateDir)
|
|
2663
|
-
return
|
|
2664
|
-
return
|
|
2814
|
+
return resolve10(stateDir, "connections.json");
|
|
2815
|
+
return resolve10(homedir3(), ".rig", "connections.json");
|
|
2665
2816
|
}
|
|
2666
2817
|
function resolveRepoConnectionPath(projectRoot) {
|
|
2667
|
-
return
|
|
2818
|
+
return resolve10(projectRoot, ".rig", "state", "connection.json");
|
|
2668
2819
|
}
|
|
2669
2820
|
function readJsonFile2(path) {
|
|
2670
|
-
if (!
|
|
2821
|
+
if (!existsSync6(path))
|
|
2671
2822
|
return null;
|
|
2672
2823
|
try {
|
|
2673
|
-
return JSON.parse(
|
|
2824
|
+
return JSON.parse(readFileSync3(path, "utf8"));
|
|
2674
2825
|
} catch (error) {
|
|
2675
2826
|
throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
2676
2827
|
}
|
|
2677
2828
|
}
|
|
2678
2829
|
function writeJsonFile2(path, value) {
|
|
2679
|
-
|
|
2680
|
-
|
|
2830
|
+
mkdirSync6(dirname2(path), { recursive: true });
|
|
2831
|
+
writeFileSync4(path, `${JSON.stringify(value, null, 2)}
|
|
2681
2832
|
`, "utf8");
|
|
2682
2833
|
}
|
|
2683
2834
|
function normalizeConnection(value) {
|
|
@@ -2754,8 +2905,8 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
2754
2905
|
|
|
2755
2906
|
// packages/cli/src/commands/_server-client.ts
|
|
2756
2907
|
init_runner();
|
|
2757
|
-
import { existsSync as
|
|
2758
|
-
import { resolve as
|
|
2908
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
2909
|
+
import { resolve as resolve11 } from "path";
|
|
2759
2910
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
2760
2911
|
var scopedGitHubBearerTokens = new Map;
|
|
2761
2912
|
function cleanToken(value) {
|
|
@@ -2763,22 +2914,22 @@ function cleanToken(value) {
|
|
|
2763
2914
|
return trimmed ? trimmed : null;
|
|
2764
2915
|
}
|
|
2765
2916
|
function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
|
|
2766
|
-
const scopedKey =
|
|
2917
|
+
const scopedKey = resolve11(projectRoot ?? process.cwd());
|
|
2767
2918
|
scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
|
|
2768
2919
|
}
|
|
2769
2920
|
function readPrivateRemoteSessionToken(projectRoot) {
|
|
2770
|
-
const path =
|
|
2771
|
-
if (!
|
|
2921
|
+
const path = resolve11(projectRoot, ".rig", "state", "github-auth.json");
|
|
2922
|
+
if (!existsSync7(path))
|
|
2772
2923
|
return null;
|
|
2773
2924
|
try {
|
|
2774
|
-
const parsed = JSON.parse(
|
|
2925
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
2775
2926
|
return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
|
|
2776
2927
|
} catch {
|
|
2777
2928
|
return null;
|
|
2778
2929
|
}
|
|
2779
2930
|
}
|
|
2780
2931
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
2781
|
-
const scopedKey =
|
|
2932
|
+
const scopedKey = resolve11(projectRoot);
|
|
2782
2933
|
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
2783
2934
|
return scopedGitHubBearerTokens.get(scopedKey) ?? null;
|
|
2784
2935
|
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
@@ -2920,7 +3071,7 @@ async function registerProjectViaServer(context, input) {
|
|
|
2920
3071
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
2921
3072
|
}
|
|
2922
3073
|
function sleep(ms) {
|
|
2923
|
-
return new Promise((
|
|
3074
|
+
return new Promise((resolve12) => setTimeout(resolve12, ms));
|
|
2924
3075
|
}
|
|
2925
3076
|
function isRetryableProjectRootSwitchError(error) {
|
|
2926
3077
|
if (!(error instanceof Error))
|
|
@@ -3403,7 +3554,7 @@ async function executeQueue(context, args) {
|
|
|
3403
3554
|
|
|
3404
3555
|
// packages/cli/src/commands/agent.ts
|
|
3405
3556
|
init_runner();
|
|
3406
|
-
import { resolve as
|
|
3557
|
+
import { resolve as resolve13 } from "path";
|
|
3407
3558
|
import {
|
|
3408
3559
|
agentId,
|
|
3409
3560
|
cleanupAgentRuntime,
|
|
@@ -3413,8 +3564,8 @@ import {
|
|
|
3413
3564
|
} from "@rig/runtime/control-plane/runtime/isolation";
|
|
3414
3565
|
|
|
3415
3566
|
// packages/cli/src/commands/_authority-runs.ts
|
|
3416
|
-
import { existsSync as
|
|
3417
|
-
import { resolve as
|
|
3567
|
+
import { existsSync as existsSync8 } from "fs";
|
|
3568
|
+
import { resolve as resolve12 } from "path";
|
|
3418
3569
|
import {
|
|
3419
3570
|
readAuthorityRun,
|
|
3420
3571
|
readJsonlFile as readJsonlFile2,
|
|
@@ -3436,8 +3587,8 @@ function normalizeRuntimeAdapter(value) {
|
|
|
3436
3587
|
return "claude-code";
|
|
3437
3588
|
}
|
|
3438
3589
|
function readLatestBeadRecord(projectRoot, taskId) {
|
|
3439
|
-
const issuesPath =
|
|
3440
|
-
if (!
|
|
3590
|
+
const issuesPath = resolve12(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
|
|
3591
|
+
if (!existsSync8(issuesPath)) {
|
|
3441
3592
|
return null;
|
|
3442
3593
|
}
|
|
3443
3594
|
let latest = null;
|
|
@@ -3505,7 +3656,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
|
|
|
3505
3656
|
} else if ("errorText" in next) {
|
|
3506
3657
|
delete next.errorText;
|
|
3507
3658
|
}
|
|
3508
|
-
writeJsonFile3(
|
|
3659
|
+
writeJsonFile3(resolve12(resolveAuthorityRunDir(projectRoot, input.runId), "run.json"), next);
|
|
3509
3660
|
return next;
|
|
3510
3661
|
}
|
|
3511
3662
|
|
|
@@ -3627,10 +3778,10 @@ async function executeAgent(context, args) {
|
|
|
3627
3778
|
status: "running",
|
|
3628
3779
|
startedAt: createdAt,
|
|
3629
3780
|
worktreePath: runtime.workspaceDir,
|
|
3630
|
-
artifactRoot:
|
|
3781
|
+
artifactRoot: resolve13(runtime.workspaceDir, "artifacts", taskId),
|
|
3631
3782
|
logRoot: runtime.logsDir,
|
|
3632
|
-
sessionPath:
|
|
3633
|
-
sessionLogPath:
|
|
3783
|
+
sessionPath: resolve13(runtime.sessionDir, "session.json"),
|
|
3784
|
+
sessionLogPath: resolve13(runtime.logsDir, "agent-stdout.log"),
|
|
3634
3785
|
pid: process.pid
|
|
3635
3786
|
});
|
|
3636
3787
|
const result = await runInAgentRuntime({
|
|
@@ -3650,10 +3801,10 @@ async function executeAgent(context, args) {
|
|
|
3650
3801
|
startedAt: createdAt,
|
|
3651
3802
|
completedAt: failedAt,
|
|
3652
3803
|
worktreePath: runtime.workspaceDir,
|
|
3653
|
-
artifactRoot:
|
|
3804
|
+
artifactRoot: resolve13(runtime.workspaceDir, "artifacts", taskId),
|
|
3654
3805
|
logRoot: runtime.logsDir,
|
|
3655
|
-
sessionPath:
|
|
3656
|
-
sessionLogPath:
|
|
3806
|
+
sessionPath: resolve13(runtime.sessionDir, "session.json"),
|
|
3807
|
+
sessionLogPath: resolve13(runtime.logsDir, "agent-stdout.log"),
|
|
3657
3808
|
pid: process.pid,
|
|
3658
3809
|
errorText: result.stderr ? result.stderr.trim() : `Agent runtime command failed (${result.exitCode})`
|
|
3659
3810
|
});
|
|
@@ -3670,10 +3821,10 @@ ${result.stderr.trim()}` : ""}`, result.exitCode);
|
|
|
3670
3821
|
startedAt: createdAt,
|
|
3671
3822
|
completedAt,
|
|
3672
3823
|
worktreePath: runtime.workspaceDir,
|
|
3673
|
-
artifactRoot:
|
|
3824
|
+
artifactRoot: resolve13(runtime.workspaceDir, "artifacts", taskId),
|
|
3674
3825
|
logRoot: runtime.logsDir,
|
|
3675
|
-
sessionPath:
|
|
3676
|
-
sessionLogPath:
|
|
3826
|
+
sessionPath: resolve13(runtime.sessionDir, "session.json"),
|
|
3827
|
+
sessionLogPath: resolve13(runtime.logsDir, "agent-stdout.log"),
|
|
3677
3828
|
pid: process.pid
|
|
3678
3829
|
});
|
|
3679
3830
|
return {
|
|
@@ -3749,8 +3900,8 @@ init__parsers();
|
|
|
3749
3900
|
import {
|
|
3750
3901
|
chmodSync,
|
|
3751
3902
|
copyFileSync as copyFileSync2,
|
|
3752
|
-
existsSync as
|
|
3753
|
-
mkdirSync as
|
|
3903
|
+
existsSync as existsSync9,
|
|
3904
|
+
mkdirSync as mkdirSync7,
|
|
3754
3905
|
readdirSync,
|
|
3755
3906
|
readlinkSync,
|
|
3756
3907
|
rmSync as rmSync3,
|
|
@@ -3758,8 +3909,8 @@ import {
|
|
|
3758
3909
|
symlinkSync,
|
|
3759
3910
|
unlinkSync
|
|
3760
3911
|
} from "fs";
|
|
3761
|
-
import { homedir as
|
|
3762
|
-
import { resolve as
|
|
3912
|
+
import { homedir as homedir4 } from "os";
|
|
3913
|
+
import { resolve as resolve14 } from "path";
|
|
3763
3914
|
import { buildBinary as buildBinary2 } from "@rig/runtime/control-plane/runtime/isolation";
|
|
3764
3915
|
import {
|
|
3765
3916
|
computeRuntimeImageFingerprint,
|
|
@@ -3778,13 +3929,13 @@ async function runQuietBinaryProbe(binaryPath, args, cwd) {
|
|
|
3778
3929
|
|
|
3779
3930
|
// packages/cli/src/commands/dist.ts
|
|
3780
3931
|
function collectRigValidatorBuildTargets(input) {
|
|
3781
|
-
const validatorsRoot =
|
|
3782
|
-
if (!
|
|
3932
|
+
const validatorsRoot = resolve14(input.hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
3933
|
+
if (!existsSync9(validatorsRoot))
|
|
3783
3934
|
return [];
|
|
3784
3935
|
const targets = [];
|
|
3785
3936
|
const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
3786
3937
|
for (const category of categories) {
|
|
3787
|
-
const categoryDir =
|
|
3938
|
+
const categoryDir = resolve14(validatorsRoot, category.name);
|
|
3788
3939
|
for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
|
|
3789
3940
|
if (!entry.isFile() || !entry.name.endsWith(".ts"))
|
|
3790
3941
|
continue;
|
|
@@ -3793,7 +3944,7 @@ function collectRigValidatorBuildTargets(input) {
|
|
|
3793
3944
|
continue;
|
|
3794
3945
|
targets.push({
|
|
3795
3946
|
source: `packages/runtime/src/control-plane/validators/${category.name}/${entry.name}`,
|
|
3796
|
-
dest:
|
|
3947
|
+
dest: resolve14(input.imageDir, `bin/validators/${category.name}-${check}`),
|
|
3797
3948
|
cwd: input.hostProjectRoot
|
|
3798
3949
|
});
|
|
3799
3950
|
}
|
|
@@ -3802,16 +3953,16 @@ function collectRigValidatorBuildTargets(input) {
|
|
|
3802
3953
|
}
|
|
3803
3954
|
async function findLatestDistBinary(projectRoot) {
|
|
3804
3955
|
const distRoot = resolveControlPlaneHostDistDir(projectRoot);
|
|
3805
|
-
if (!
|
|
3956
|
+
if (!existsSync9(distRoot)) {
|
|
3806
3957
|
return null;
|
|
3807
3958
|
}
|
|
3808
3959
|
const entries = readdirSync(distRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith("rig-")).map((entry) => ({
|
|
3809
3960
|
name: entry.name,
|
|
3810
|
-
mtimeMs: statSync(
|
|
3961
|
+
mtimeMs: statSync(resolve14(distRoot, entry.name)).mtimeMs
|
|
3811
3962
|
})).sort((a, b) => b.mtimeMs - a.mtimeMs || b.name.localeCompare(a.name));
|
|
3812
3963
|
for (const { name } of entries) {
|
|
3813
|
-
const candidate =
|
|
3814
|
-
if (
|
|
3964
|
+
const candidate = resolve14(distRoot, name, "bin", "rig");
|
|
3965
|
+
if (existsSync9(candidate) && await isRunnableRigBinary(candidate, projectRoot)) {
|
|
3815
3966
|
return candidate;
|
|
3816
3967
|
}
|
|
3817
3968
|
}
|
|
@@ -3823,7 +3974,7 @@ async function isRunnableRigBinary(binaryPath, projectRoot) {
|
|
|
3823
3974
|
async function runDistDoctor(projectRoot) {
|
|
3824
3975
|
const bunPath = Bun.which("bun");
|
|
3825
3976
|
const rigPath = Bun.which("rig");
|
|
3826
|
-
const userBinDir =
|
|
3977
|
+
const userBinDir = resolve14(homedir4(), ".local/bin");
|
|
3827
3978
|
const userBinInPath = (process.env.PATH || "").split(":").filter(Boolean).includes(userBinDir);
|
|
3828
3979
|
let rigRunnable = false;
|
|
3829
3980
|
if (rigPath) {
|
|
@@ -3867,19 +4018,19 @@ async function executeDist(context, args) {
|
|
|
3867
4018
|
requireNoExtraArgs(pending, "rig dist install [--scope user|system] [--path <dir>]");
|
|
3868
4019
|
const scope = parseInstallScope(scopeResult.value);
|
|
3869
4020
|
const installDir = resolveInstallDir(scope, pathResult.value);
|
|
3870
|
-
|
|
4021
|
+
mkdirSync7(installDir, { recursive: true });
|
|
3871
4022
|
let source = await findLatestDistBinary(context.projectRoot);
|
|
3872
4023
|
let buildDir = null;
|
|
3873
4024
|
if (!source) {
|
|
3874
|
-
buildDir =
|
|
4025
|
+
buildDir = resolve14(resolveControlPlaneHostDistDir(context.projectRoot), `rig-install-${Date.now()}`);
|
|
3875
4026
|
await context.runCommand(["bun", "run", "packages/cli/bin/build-rig-binaries.ts", "--output-dir", buildDir]);
|
|
3876
|
-
source =
|
|
4027
|
+
source = resolve14(buildDir, "bin", "rig");
|
|
3877
4028
|
}
|
|
3878
|
-
if (!
|
|
4029
|
+
if (!existsSync9(source)) {
|
|
3879
4030
|
throw new CliError2(`Unable to locate rig binary at ${source}.`, 2);
|
|
3880
4031
|
}
|
|
3881
|
-
const installedPath =
|
|
3882
|
-
if (
|
|
4032
|
+
const installedPath = resolve14(installDir, "rig");
|
|
4033
|
+
if (existsSync9(installedPath)) {
|
|
3883
4034
|
unlinkSync(installedPath);
|
|
3884
4035
|
}
|
|
3885
4036
|
copyFileSync2(source, installedPath);
|
|
@@ -3921,22 +4072,22 @@ async function executeDist(context, args) {
|
|
|
3921
4072
|
requireNoExtraArgs(rest, "rig dist rebuild-agent");
|
|
3922
4073
|
const fp = await computeRuntimeImageFingerprint(context.projectRoot);
|
|
3923
4074
|
const currentId = computeRuntimeImageId(fp);
|
|
3924
|
-
const imagesDir =
|
|
3925
|
-
|
|
4075
|
+
const imagesDir = resolve14(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
|
|
4076
|
+
mkdirSync7(imagesDir, { recursive: true });
|
|
3926
4077
|
let pruned = 0;
|
|
3927
4078
|
for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
|
|
3928
4079
|
if (entry.isDirectory() && entry.name !== currentId) {
|
|
3929
|
-
rmSync3(
|
|
4080
|
+
rmSync3(resolve14(imagesDir, entry.name), { recursive: true, force: true });
|
|
3930
4081
|
pruned++;
|
|
3931
4082
|
}
|
|
3932
4083
|
}
|
|
3933
4084
|
if (pruned > 0 && context.outputMode === "text") {
|
|
3934
4085
|
console.log(`Pruned ${pruned} stale image(s).`);
|
|
3935
4086
|
}
|
|
3936
|
-
const imageDir =
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
4087
|
+
const imageDir = resolve14(imagesDir, currentId);
|
|
4088
|
+
mkdirSync7(resolve14(imageDir, "bin/hooks"), { recursive: true });
|
|
4089
|
+
mkdirSync7(resolve14(imageDir, "bin/plugins"), { recursive: true });
|
|
4090
|
+
mkdirSync7(resolve14(imageDir, "bin/validators"), { recursive: true });
|
|
3940
4091
|
const hookNames = [
|
|
3941
4092
|
"scope-guard",
|
|
3942
4093
|
"import-guard",
|
|
@@ -3950,25 +4101,25 @@ async function executeDist(context, args) {
|
|
|
3950
4101
|
];
|
|
3951
4102
|
const targets = [];
|
|
3952
4103
|
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || context.projectRoot;
|
|
3953
|
-
targets.push({ source: "packages/runtime/bin/rig-agent.ts", dest:
|
|
3954
|
-
targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest:
|
|
4104
|
+
targets.push({ source: "packages/runtime/bin/rig-agent.ts", dest: resolve14(imageDir, "bin/rig-agent"), cwd: hostProjectRoot });
|
|
4105
|
+
targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest: resolve14(resolveControlPlaneHostBinDir(context.projectRoot), "rig-agent"), cwd: hostProjectRoot });
|
|
3955
4106
|
for (const hookName of hookNames) {
|
|
3956
4107
|
const src = `packages/runtime/src/control-plane/hooks/${hookName}.ts`;
|
|
3957
|
-
targets.push({ source: src, dest:
|
|
3958
|
-
targets.push({ source: src, dest:
|
|
3959
|
-
}
|
|
3960
|
-
const pluginsDir =
|
|
3961
|
-
const binPluginsDir =
|
|
3962
|
-
const validatorsRoot =
|
|
3963
|
-
const binValidatorsDir =
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
if (
|
|
4108
|
+
targets.push({ source: src, dest: resolve14(imageDir, `bin/hooks/${hookName}`), cwd: hostProjectRoot });
|
|
4109
|
+
targets.push({ source: src, dest: resolve14(resolveControlPlaneHostBinDir(context.projectRoot), `hooks/${hookName}`), cwd: hostProjectRoot });
|
|
4110
|
+
}
|
|
4111
|
+
const pluginsDir = resolve14(context.projectRoot, "rig/plugins");
|
|
4112
|
+
const binPluginsDir = resolve14(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
|
|
4113
|
+
const validatorsRoot = resolve14(hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
4114
|
+
const binValidatorsDir = resolve14(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
|
|
4115
|
+
mkdirSync7(binPluginsDir, { recursive: true });
|
|
4116
|
+
mkdirSync7(binValidatorsDir, { recursive: true });
|
|
4117
|
+
if (existsSync9(pluginsDir)) {
|
|
3967
4118
|
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
3968
4119
|
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
3969
4120
|
if (!m)
|
|
3970
4121
|
continue;
|
|
3971
|
-
targets.push({ source: `rig/plugins/${entry.name}`, dest:
|
|
4122
|
+
targets.push({ source: `rig/plugins/${entry.name}`, dest: resolve14(imageDir, `bin/plugins/${m[1]}`), cwd: context.projectRoot });
|
|
3972
4123
|
}
|
|
3973
4124
|
}
|
|
3974
4125
|
targets.push(...collectRigValidatorBuildTargets({ contextProjectRoot: context.projectRoot, hostProjectRoot, imageDir }));
|
|
@@ -3979,17 +4130,17 @@ async function executeDist(context, args) {
|
|
|
3979
4130
|
const isValidator = dest.includes("/bin/validators/");
|
|
3980
4131
|
await buildBinary2(source, dest, cwd, isValidator ? { AGENT_BUN_PATH: Bun.which("bun") || "bun" } : { AGENT_PROJECT_ROOT: context.projectRoot });
|
|
3981
4132
|
}
|
|
3982
|
-
if (
|
|
4133
|
+
if (existsSync9(pluginsDir)) {
|
|
3983
4134
|
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
3984
4135
|
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
3985
4136
|
if (!m)
|
|
3986
4137
|
continue;
|
|
3987
4138
|
const pluginName = m[1];
|
|
3988
|
-
const imageBin =
|
|
4139
|
+
const imageBin = resolve14(imageDir, `bin/plugins/${pluginName}`);
|
|
3989
4140
|
if (!pluginName)
|
|
3990
4141
|
continue;
|
|
3991
|
-
const symlinkPath =
|
|
3992
|
-
if (
|
|
4142
|
+
const symlinkPath = resolve14(binPluginsDir, pluginName);
|
|
4143
|
+
if (existsSync9(imageBin)) {
|
|
3993
4144
|
try {
|
|
3994
4145
|
unlinkSync(symlinkPath);
|
|
3995
4146
|
} catch {}
|
|
@@ -3997,10 +4148,10 @@ async function executeDist(context, args) {
|
|
|
3997
4148
|
}
|
|
3998
4149
|
}
|
|
3999
4150
|
}
|
|
4000
|
-
if (
|
|
4151
|
+
if (existsSync9(validatorsRoot)) {
|
|
4001
4152
|
const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
4002
4153
|
for (const category of categories) {
|
|
4003
|
-
const categoryDir =
|
|
4154
|
+
const categoryDir = resolve14(validatorsRoot, category.name);
|
|
4004
4155
|
for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
|
|
4005
4156
|
if (!entry.isFile() || !entry.name.endsWith(".ts"))
|
|
4006
4157
|
continue;
|
|
@@ -4008,9 +4159,9 @@ async function executeDist(context, args) {
|
|
|
4008
4159
|
if (!check || check === "index" || check === "shared")
|
|
4009
4160
|
continue;
|
|
4010
4161
|
const validatorName = `${category.name}-${check}`;
|
|
4011
|
-
const imageBin =
|
|
4012
|
-
const symlinkPath =
|
|
4013
|
-
if (
|
|
4162
|
+
const imageBin = resolve14(imageDir, `bin/validators/${validatorName}`);
|
|
4163
|
+
const symlinkPath = resolve14(binValidatorsDir, validatorName);
|
|
4164
|
+
if (existsSync9(imageBin)) {
|
|
4014
4165
|
try {
|
|
4015
4166
|
unlinkSync(symlinkPath);
|
|
4016
4167
|
} catch {}
|
|
@@ -4019,18 +4170,18 @@ async function executeDist(context, args) {
|
|
|
4019
4170
|
}
|
|
4020
4171
|
}
|
|
4021
4172
|
}
|
|
4022
|
-
const agentsDir =
|
|
4023
|
-
if (
|
|
4173
|
+
const agentsDir = resolve14(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "agents");
|
|
4174
|
+
if (existsSync9(agentsDir)) {
|
|
4024
4175
|
let relinkCount = 0;
|
|
4025
4176
|
for (const agentEntry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
4026
4177
|
if (!agentEntry.isDirectory())
|
|
4027
4178
|
continue;
|
|
4028
|
-
const agentBinDir =
|
|
4029
|
-
if (!
|
|
4179
|
+
const agentBinDir = resolve14(agentsDir, agentEntry.name, "worktree", ".rig", "bin");
|
|
4180
|
+
if (!existsSync9(agentBinDir))
|
|
4030
4181
|
continue;
|
|
4031
4182
|
const walkDir = (dir) => {
|
|
4032
4183
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
4033
|
-
const fullPath =
|
|
4184
|
+
const fullPath = resolve14(dir, entry.name);
|
|
4034
4185
|
if (entry.isDirectory()) {
|
|
4035
4186
|
walkDir(fullPath);
|
|
4036
4187
|
} else if (entry.isSymbolicLink()) {
|
|
@@ -4064,8 +4215,8 @@ async function executeDist(context, args) {
|
|
|
4064
4215
|
|
|
4065
4216
|
// packages/cli/src/commands/inbox.ts
|
|
4066
4217
|
init_runner();
|
|
4067
|
-
import { writeFileSync as
|
|
4068
|
-
import { resolve as
|
|
4218
|
+
import { writeFileSync as writeFileSync5 } from "fs";
|
|
4219
|
+
import { resolve as resolve15 } from "path";
|
|
4069
4220
|
import {
|
|
4070
4221
|
listAuthorityRuns,
|
|
4071
4222
|
readJsonlFile as readJsonlFile3,
|
|
@@ -4467,7 +4618,7 @@ async function listRemoteInboxRecords(context, kind, filters) {
|
|
|
4467
4618
|
function listLocalInboxRecords(context, kind, filters) {
|
|
4468
4619
|
const fileName = kind === "approvals" ? "approvals.jsonl" : "user-input.jsonl";
|
|
4469
4620
|
const runs = listAuthorityRuns(context.projectRoot).filter((entry) => (!filters.run || entry.runId === filters.run) && (!filters.task || entry.taskId === filters.task));
|
|
4470
|
-
return runs.flatMap((entry) => readJsonlFile3(
|
|
4621
|
+
return runs.flatMap((entry) => readJsonlFile3(resolve15(resolveAuthorityRunDir2(context.projectRoot, entry.runId), fileName)).map((record) => ({
|
|
4471
4622
|
runId: entry.runId,
|
|
4472
4623
|
taskId: entry.taskId ?? undefined,
|
|
4473
4624
|
record
|
|
@@ -4515,11 +4666,11 @@ async function executeInbox(context, args) {
|
|
|
4515
4666
|
if (isRemoteConnectionSelected(context.projectRoot)) {
|
|
4516
4667
|
throw new CliError2("Remote approval resolution is not available from this CLI yet; use the server UI/API or switch to local state for direct JSONL edits.", 2);
|
|
4517
4668
|
}
|
|
4518
|
-
const approvalsPath =
|
|
4669
|
+
const approvalsPath = resolve15(resolveAuthorityRunDir2(context.projectRoot, run.value), "approvals.jsonl");
|
|
4519
4670
|
const approvals = readJsonlFile3(approvalsPath);
|
|
4520
4671
|
const resolvedAt = new Date().toISOString();
|
|
4521
4672
|
const next = approvals.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", decision: decision.value, note: note4.value ?? null, resolvedAt } : entry);
|
|
4522
|
-
|
|
4673
|
+
writeFileSync5(approvalsPath, `${next.map((entry) => JSON.stringify(entry)).join(`
|
|
4523
4674
|
`)}
|
|
4524
4675
|
`, "utf8");
|
|
4525
4676
|
return { ok: true, group: "inbox", command, details: { runId: run.value, requestId: request.value, decision: decision.value } };
|
|
@@ -4571,11 +4722,11 @@ async function executeInbox(context, args) {
|
|
|
4571
4722
|
const [key, ...restValue] = entry.split("=");
|
|
4572
4723
|
return [key, restValue.join("=")];
|
|
4573
4724
|
}));
|
|
4574
|
-
const requestsPath =
|
|
4725
|
+
const requestsPath = resolve15(resolveAuthorityRunDir2(context.projectRoot, run.value), "user-input.jsonl");
|
|
4575
4726
|
const requests = readJsonlFile3(requestsPath);
|
|
4576
4727
|
const resolvedAt = new Date().toISOString();
|
|
4577
4728
|
const next = requests.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", answers: parsedAnswers, respondedAt: resolvedAt, resolvedAt } : entry);
|
|
4578
|
-
|
|
4729
|
+
writeFileSync5(requestsPath, `${next.map((entry) => JSON.stringify(entry)).join(`
|
|
4579
4730
|
`)}
|
|
4580
4731
|
`, "utf8");
|
|
4581
4732
|
return { ok: true, group: "inbox", command, details: { runId: run.value, requestId: request.value, answers: parsedAnswers } };
|
|
@@ -4587,16 +4738,16 @@ async function executeInbox(context, args) {
|
|
|
4587
4738
|
|
|
4588
4739
|
// packages/cli/src/commands/init.ts
|
|
4589
4740
|
init_runner();
|
|
4590
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
4741
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
4591
4742
|
import { spawnSync } from "child_process";
|
|
4592
|
-
import { resolve as
|
|
4743
|
+
import { resolve as resolve19 } from "path";
|
|
4593
4744
|
import { buildRigInitConfigSource } from "@rig/core";
|
|
4594
4745
|
import { listGitHubProjects as listGitHubProjectsDirect, resolveProjectStatusField as resolveProjectStatusFieldDirect } from "@rig/server";
|
|
4595
4746
|
|
|
4596
4747
|
// packages/cli/src/commands/_pi-install.ts
|
|
4597
|
-
import { existsSync as
|
|
4598
|
-
import { homedir as
|
|
4599
|
-
import { resolve as
|
|
4748
|
+
import { existsSync as existsSync10, readFileSync as readFileSync5, rmSync as rmSync4 } from "fs";
|
|
4749
|
+
import { homedir as homedir5 } from "os";
|
|
4750
|
+
import { resolve as resolve16 } from "path";
|
|
4600
4751
|
var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
|
|
4601
4752
|
var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
|
|
4602
4753
|
var LEGACY_PI_RIG_MARKER = `// Managed by Rig. Source package: @rig/pi-rig.
|
|
@@ -4612,16 +4763,16 @@ async function defaultCommandRunner(command, options = {}) {
|
|
|
4612
4763
|
return { exitCode, stdout, stderr };
|
|
4613
4764
|
}
|
|
4614
4765
|
function resolvePiRigExtensionPath(homeDir) {
|
|
4615
|
-
return
|
|
4766
|
+
return resolve16(homeDir, ".pi", "agent", "extensions", "pi-rig");
|
|
4616
4767
|
}
|
|
4617
|
-
function resolvePiRigPackageSource(projectRoot, exists =
|
|
4618
|
-
const localPackage =
|
|
4619
|
-
if (exists(
|
|
4768
|
+
function resolvePiRigPackageSource(projectRoot, exists = existsSync10) {
|
|
4769
|
+
const localPackage = resolve16(projectRoot, "packages", "pi-rig");
|
|
4770
|
+
if (exists(resolve16(localPackage, "package.json")))
|
|
4620
4771
|
return localPackage;
|
|
4621
4772
|
return `npm:${PI_RIG_PACKAGE_NAME}`;
|
|
4622
4773
|
}
|
|
4623
4774
|
function resolvePiHomeDir(inputHomeDir) {
|
|
4624
|
-
return inputHomeDir ?? process.env.RIG_PI_HOME_DIR?.trim() ??
|
|
4775
|
+
return inputHomeDir ?? process.env.RIG_PI_HOME_DIR?.trim() ?? homedir5();
|
|
4625
4776
|
}
|
|
4626
4777
|
function piListContainsPiRig(output) {
|
|
4627
4778
|
return output.split(/\r?\n/).some((line) => {
|
|
@@ -4667,13 +4818,13 @@ async function ensurePiBinaryAvailable(input) {
|
|
|
4667
4818
|
...next.exitCode === 0 ? {} : { error: (next.stderr || next.stdout).trim() || "pi --version failed after install" }
|
|
4668
4819
|
};
|
|
4669
4820
|
}
|
|
4670
|
-
function removeManagedLegacyPiRigBridge(homeDir, exists =
|
|
4821
|
+
function removeManagedLegacyPiRigBridge(homeDir, exists = existsSync10) {
|
|
4671
4822
|
const extensionPath = resolvePiRigExtensionPath(homeDir);
|
|
4672
|
-
const indexPath =
|
|
4823
|
+
const indexPath = resolve16(extensionPath, "index.ts");
|
|
4673
4824
|
if (!exists(indexPath))
|
|
4674
4825
|
return;
|
|
4675
4826
|
try {
|
|
4676
|
-
const content =
|
|
4827
|
+
const content = readFileSync5(indexPath, "utf8");
|
|
4677
4828
|
if (content === LEGACY_PI_RIG_MARKER || content.includes("Managed by Rig. Source package: @rig/pi-rig")) {
|
|
4678
4829
|
rmSync4(extensionPath, { recursive: true, force: true });
|
|
4679
4830
|
}
|
|
@@ -4689,13 +4840,13 @@ async function checkPiRigInstall(input = {}) {
|
|
|
4689
4840
|
piRig: { ok: true, label: "pi-rig global extension", detail: extensionPath }
|
|
4690
4841
|
};
|
|
4691
4842
|
}
|
|
4692
|
-
const exists = input.exists ??
|
|
4843
|
+
const exists = input.exists ?? existsSync10;
|
|
4693
4844
|
const runner = input.commandRunner ?? defaultCommandRunner;
|
|
4694
4845
|
const piResult = await safeRun(runner, ["pi", "--version"]);
|
|
4695
4846
|
const piListResult = piResult.exitCode === 0 ? await safeRun(runner, ["pi", "list"]) : { exitCode: 1, stdout: "", stderr: "" };
|
|
4696
4847
|
const listedPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
|
|
4697
4848
|
${piListResult.stderr}`);
|
|
4698
|
-
const legacyBridge = exists(
|
|
4849
|
+
const legacyBridge = exists(resolve16(extensionPath, "index.ts"));
|
|
4699
4850
|
const hasPiRig = listedPiRig;
|
|
4700
4851
|
return {
|
|
4701
4852
|
extensionPath,
|
|
@@ -4772,7 +4923,7 @@ async function buildPiSetupChecks(input = {}) {
|
|
|
4772
4923
|
|
|
4773
4924
|
// packages/cli/src/commands/_snapshot-upload.ts
|
|
4774
4925
|
import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
4775
|
-
import { dirname as
|
|
4926
|
+
import { dirname as dirname3, resolve as resolve17, relative, sep } from "path";
|
|
4776
4927
|
var SNAPSHOT_ARCHIVE_VERSION = 1;
|
|
4777
4928
|
var SNAPSHOT_ARCHIVE_CONTENT_TYPE = "application/vnd.rig.snapshot+json";
|
|
4778
4929
|
var DEFAULT_EXCLUDED_DIRECTORIES = new Set([
|
|
@@ -4794,15 +4945,15 @@ function assertManifestPath(root, relativePath) {
|
|
|
4794
4945
|
if (!relativePath || relativePath.startsWith("/") || relativePath.includes("\x00")) {
|
|
4795
4946
|
throw new Error(`Invalid snapshot path: ${relativePath}`);
|
|
4796
4947
|
}
|
|
4797
|
-
const resolved =
|
|
4948
|
+
const resolved = resolve17(root, relativePath);
|
|
4798
4949
|
const relativeToRoot = relative(root, resolved);
|
|
4799
|
-
if (relativeToRoot.startsWith("..") || relativeToRoot === ".." ||
|
|
4950
|
+
if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || resolve17(relativeToRoot) === resolved) {
|
|
4800
4951
|
throw new Error(`Snapshot path escapes project root: ${relativePath}`);
|
|
4801
4952
|
}
|
|
4802
4953
|
return resolved;
|
|
4803
4954
|
}
|
|
4804
4955
|
async function buildSnapshotUploadManifest(projectRoot, options = {}) {
|
|
4805
|
-
const root =
|
|
4956
|
+
const root = resolve17(projectRoot);
|
|
4806
4957
|
const excludedDirectories = [...new Set([
|
|
4807
4958
|
...DEFAULT_EXCLUDED_DIRECTORIES,
|
|
4808
4959
|
...options.excludedDirectories ?? []
|
|
@@ -4814,7 +4965,7 @@ async function buildSnapshotUploadManifest(projectRoot, options = {}) {
|
|
|
4814
4965
|
for (const entry of entries) {
|
|
4815
4966
|
if (entry.isDirectory() && excludedSet.has(entry.name))
|
|
4816
4967
|
continue;
|
|
4817
|
-
const fullPath =
|
|
4968
|
+
const fullPath = resolve17(dir, entry.name);
|
|
4818
4969
|
if (entry.isDirectory()) {
|
|
4819
4970
|
await visit(fullPath);
|
|
4820
4971
|
continue;
|
|
@@ -4863,8 +5014,8 @@ async function uploadSnapshotArchiveViaServer(context, input) {
|
|
|
4863
5014
|
|
|
4864
5015
|
// packages/cli/src/commands/_doctor-checks.ts
|
|
4865
5016
|
init_runner();
|
|
4866
|
-
import { existsSync as
|
|
4867
|
-
import { resolve as
|
|
5017
|
+
import { existsSync as existsSync11, readFileSync as readFileSync6 } from "fs";
|
|
5018
|
+
import { resolve as resolve18 } from "path";
|
|
4868
5019
|
import { isSupportedBunVersion, MIN_SUPPORTED_BUN_VERSION } from "@rig/runtime/control-plane/setup-version";
|
|
4869
5020
|
init__parsers();
|
|
4870
5021
|
function check(id, label, status, detail, remediation) {
|
|
@@ -4905,11 +5056,11 @@ function repoSlugFromConfig(config) {
|
|
|
4905
5056
|
function loadFallbackConfig(projectRoot) {
|
|
4906
5057
|
const candidates = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
|
|
4907
5058
|
for (const name of candidates) {
|
|
4908
|
-
const path =
|
|
4909
|
-
if (!
|
|
5059
|
+
const path = resolve18(projectRoot, name);
|
|
5060
|
+
if (!existsSync11(path))
|
|
4910
5061
|
continue;
|
|
4911
5062
|
try {
|
|
4912
|
-
const source =
|
|
5063
|
+
const source = readFileSync6(path, "utf8");
|
|
4913
5064
|
if (name.endsWith(".json"))
|
|
4914
5065
|
return JSON.parse(source);
|
|
4915
5066
|
const owner = source.match(/owner\s*:\s*["']([^"']+)["']/)?.[1];
|
|
@@ -4988,7 +5139,7 @@ async function runRigDoctorChecks(options) {
|
|
|
4988
5139
|
checks.push(check("bun", `bun >= ${MIN_SUPPORTED_BUN_VERSION}`, isSupportedBunVersion(bunVersion) ? "pass" : "fail", `found ${bunVersion}`, `Install Bun ${MIN_SUPPORTED_BUN_VERSION} or newer.`), check("git", "git", which("git") ? "pass" : "fail", which("git") ?? undefined, "Install git and ensure it is on PATH."), check("jq", "jq", which("jq") ? "pass" : "warn", which("jq") ?? undefined, "Install jq (for example `brew install jq`)."));
|
|
4989
5140
|
const loadedConfig = await loadConfig(projectRoot).catch(() => null);
|
|
4990
5141
|
const config = loadedConfig ?? loadFallbackConfig(projectRoot);
|
|
4991
|
-
const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) =>
|
|
5142
|
+
const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync11(resolve18(projectRoot, name)));
|
|
4992
5143
|
checks.push(config ? check("config", "rig.config loadable", "pass") : check("config", "rig.config loadable", hasConfigFile ? "fail" : "fail", hasConfigFile ? "config file exists but failed to load" : "missing rig.config.ts/json", "Run `rig init` or fix the config error."));
|
|
4993
5144
|
const taskSourceKind = config?.taskSource?.kind;
|
|
4994
5145
|
checks.push(taskSourceKind ? check("task-source", "task source configured", "pass", taskSourceKind) : check("task-source", "task source configured", "fail", "missing taskSource", "Configure taskSource in rig.config.ts."));
|
|
@@ -5107,20 +5258,20 @@ function parseRepoSlug(value) {
|
|
|
5107
5258
|
return { owner: match[1], repo: match[2], slug: `${match[1]}/${match[2]}` };
|
|
5108
5259
|
}
|
|
5109
5260
|
function ensureRigPrivateDirs(projectRoot) {
|
|
5110
|
-
const rigDir =
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
const taskConfigPath =
|
|
5117
|
-
if (!
|
|
5118
|
-
|
|
5261
|
+
const rigDir = resolve19(projectRoot, ".rig");
|
|
5262
|
+
mkdirSync8(resolve19(rigDir, "state"), { recursive: true });
|
|
5263
|
+
mkdirSync8(resolve19(rigDir, "logs"), { recursive: true });
|
|
5264
|
+
mkdirSync8(resolve19(rigDir, "runs"), { recursive: true });
|
|
5265
|
+
mkdirSync8(resolve19(rigDir, "tmp"), { recursive: true });
|
|
5266
|
+
mkdirSync8(resolve19(projectRoot, "artifacts"), { recursive: true });
|
|
5267
|
+
const taskConfigPath = resolve19(rigDir, "task-config.json");
|
|
5268
|
+
if (!existsSync12(taskConfigPath))
|
|
5269
|
+
writeFileSync6(taskConfigPath, `{}
|
|
5119
5270
|
`, "utf-8");
|
|
5120
5271
|
}
|
|
5121
5272
|
function ensureGitignoreEntries(projectRoot) {
|
|
5122
|
-
const path =
|
|
5123
|
-
const existing =
|
|
5273
|
+
const path = resolve19(projectRoot, ".gitignore");
|
|
5274
|
+
const existing = existsSync12(path) ? readFileSync7(path, "utf8") : "";
|
|
5124
5275
|
const entries = [".rig/state/", ".rig/logs/", ".rig/runs/", ".rig/tmp/"];
|
|
5125
5276
|
const missing = entries.filter((entry) => !existing.split(/\r?\n/).includes(entry));
|
|
5126
5277
|
if (missing.length === 0)
|
|
@@ -5133,17 +5284,17 @@ function ensureGitignoreEntries(projectRoot) {
|
|
|
5133
5284
|
`, "utf8");
|
|
5134
5285
|
}
|
|
5135
5286
|
function ensureRigConfigPackageDependencies(projectRoot) {
|
|
5136
|
-
const path =
|
|
5137
|
-
const existing =
|
|
5287
|
+
const path = resolve19(projectRoot, "package.json");
|
|
5288
|
+
const existing = existsSync12(path) ? JSON.parse(readFileSync7(path, "utf8")) : {};
|
|
5138
5289
|
const devDependencies = existing.devDependencies && typeof existing.devDependencies === "object" && !Array.isArray(existing.devDependencies) ? { ...existing.devDependencies } : {};
|
|
5139
5290
|
for (const [name, spec] of Object.entries(RIG_CONFIG_DEV_DEPENDENCIES)) {
|
|
5140
5291
|
devDependencies[name] = spec;
|
|
5141
5292
|
}
|
|
5142
5293
|
const next = {
|
|
5143
|
-
...
|
|
5294
|
+
...existsSync12(path) ? existing : { name: "rig-project", private: true },
|
|
5144
5295
|
devDependencies
|
|
5145
5296
|
};
|
|
5146
|
-
|
|
5297
|
+
writeFileSync6(path, `${JSON.stringify(next, null, 2)}
|
|
5147
5298
|
`, "utf8");
|
|
5148
5299
|
}
|
|
5149
5300
|
function applyGitHubProjectConfig(source, options) {
|
|
@@ -5392,7 +5543,7 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
5392
5543
|
};
|
|
5393
5544
|
}
|
|
5394
5545
|
function sleep2(ms) {
|
|
5395
|
-
return new Promise((
|
|
5546
|
+
return new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
5396
5547
|
}
|
|
5397
5548
|
function positiveIntFromEnv(name, fallback) {
|
|
5398
5549
|
const value = Number.parseInt(process.env[name] ?? "", 10);
|
|
@@ -5421,7 +5572,7 @@ function remoteGitHubAuthMetadata(payload) {
|
|
|
5421
5572
|
};
|
|
5422
5573
|
}
|
|
5423
5574
|
function writeRemoteGitHubAuthState(projectRoot, input) {
|
|
5424
|
-
|
|
5575
|
+
writeFileSync6(resolve19(projectRoot, ".rig", "state", "github-auth.json"), `${JSON.stringify({
|
|
5425
5576
|
authenticated: true,
|
|
5426
5577
|
source: input.source,
|
|
5427
5578
|
storedOnServer: true,
|
|
@@ -5478,9 +5629,9 @@ async function runControlPlaneInit(context, options) {
|
|
|
5478
5629
|
});
|
|
5479
5630
|
ensureRigPrivateDirs(projectRoot);
|
|
5480
5631
|
ensureGitignoreEntries(projectRoot);
|
|
5481
|
-
const configTsPath =
|
|
5482
|
-
const configJsonPath =
|
|
5483
|
-
const configExists =
|
|
5632
|
+
const configTsPath = resolve19(projectRoot, "rig.config.ts");
|
|
5633
|
+
const configJsonPath = resolve19(projectRoot, "rig.config.json");
|
|
5634
|
+
const configExists = existsSync12(configTsPath) || existsSync12(configJsonPath);
|
|
5484
5635
|
if (!options.privateStateOnly) {
|
|
5485
5636
|
if (configExists && !options.repair) {
|
|
5486
5637
|
if (context.outputMode !== "json")
|
|
@@ -5492,11 +5643,11 @@ async function runControlPlaneInit(context, options) {
|
|
|
5492
5643
|
taskSource: { kind: "github-issues", owner: repo.owner, repo: repo.repo },
|
|
5493
5644
|
useStandardPlugin: true
|
|
5494
5645
|
}), options);
|
|
5495
|
-
|
|
5646
|
+
writeFileSync6(configTsPath, source, "utf-8");
|
|
5496
5647
|
}
|
|
5497
5648
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
5498
5649
|
}
|
|
5499
|
-
|
|
5650
|
+
writeFileSync6(resolve19(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
|
|
5500
5651
|
`, "utf8");
|
|
5501
5652
|
const checkout = checkoutForInit(projectRoot, serverKind, options.remoteCheckout);
|
|
5502
5653
|
let uploadedSnapshot = null;
|
|
@@ -5692,7 +5843,7 @@ function parseInitOptions(args) {
|
|
|
5692
5843
|
async function runInteractiveControlPlaneInit(context, prompts) {
|
|
5693
5844
|
prompts.intro?.("Initialize a Rig control-plane project");
|
|
5694
5845
|
const projectRoot = context.projectRoot;
|
|
5695
|
-
const existingConfig =
|
|
5846
|
+
const existingConfig = existsSync12(resolve19(projectRoot, "rig.config.ts")) || existsSync12(resolve19(projectRoot, "rig.config.json"));
|
|
5696
5847
|
let repair = false;
|
|
5697
5848
|
let privateStateOnly = false;
|
|
5698
5849
|
if (existingConfig) {
|
|
@@ -5995,8 +6146,8 @@ async function executeDoctor(context, args) {
|
|
|
5995
6146
|
|
|
5996
6147
|
// packages/cli/src/commands/_run-driver-helpers.ts
|
|
5997
6148
|
init_runner();
|
|
5998
|
-
import { readFileSync as
|
|
5999
|
-
import { resolve as
|
|
6149
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
6150
|
+
import { resolve as resolve20 } from "path";
|
|
6000
6151
|
import {
|
|
6001
6152
|
appendJsonlRecord as appendJsonlRecord2,
|
|
6002
6153
|
readAuthorityRun as readAuthorityRun2,
|
|
@@ -6016,7 +6167,7 @@ function patchAuthorityRun(projectRoot, runId, patch) {
|
|
|
6016
6167
|
...patch,
|
|
6017
6168
|
updatedAt: new Date().toISOString()
|
|
6018
6169
|
};
|
|
6019
|
-
writeJsonFile4(
|
|
6170
|
+
writeJsonFile4(resolve20(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), next);
|
|
6020
6171
|
return next;
|
|
6021
6172
|
}
|
|
6022
6173
|
function touchAuthorityRun(projectRoot, runId) {
|
|
@@ -6024,21 +6175,21 @@ function touchAuthorityRun(projectRoot, runId) {
|
|
|
6024
6175
|
if (!current) {
|
|
6025
6176
|
return;
|
|
6026
6177
|
}
|
|
6027
|
-
writeJsonFile4(
|
|
6178
|
+
writeJsonFile4(resolve20(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), {
|
|
6028
6179
|
...current,
|
|
6029
6180
|
updatedAt: new Date().toISOString()
|
|
6030
6181
|
});
|
|
6031
6182
|
}
|
|
6032
6183
|
function appendRunTimeline(projectRoot, runId, value) {
|
|
6033
|
-
appendJsonlRecord2(
|
|
6184
|
+
appendJsonlRecord2(resolve20(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), value);
|
|
6034
6185
|
touchAuthorityRun(projectRoot, runId);
|
|
6035
6186
|
}
|
|
6036
6187
|
function appendRunLog(projectRoot, runId, value) {
|
|
6037
|
-
appendJsonlRecord2(
|
|
6188
|
+
appendJsonlRecord2(resolve20(resolveAuthorityRunDir3(projectRoot, runId), "logs.jsonl"), value);
|
|
6038
6189
|
touchAuthorityRun(projectRoot, runId);
|
|
6039
6190
|
}
|
|
6040
6191
|
function appendRunAction(projectRoot, runId, value) {
|
|
6041
|
-
appendJsonlRecord2(
|
|
6192
|
+
appendJsonlRecord2(resolve20(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), {
|
|
6042
6193
|
id: value.id,
|
|
6043
6194
|
type: "action",
|
|
6044
6195
|
actionType: value.actionType,
|
|
@@ -6109,7 +6260,7 @@ function buildRunPrompt(input) {
|
|
|
6109
6260
|
})();
|
|
6110
6261
|
const scopeText = (() => {
|
|
6111
6262
|
try {
|
|
6112
|
-
const parsed = JSON.parse(
|
|
6263
|
+
const parsed = JSON.parse(readFileSync8(resolveControlPlaneTaskConfigPath(input.projectRoot), "utf8"));
|
|
6113
6264
|
const entry = parsed[input.taskId] ?? {};
|
|
6114
6265
|
const scope = Array.isArray(entry.scope) ? entry.scope.filter((item) => typeof item === "string") : [];
|
|
6115
6266
|
const validation = Array.isArray(entry.validation) ? entry.validation.filter((item) => typeof item === "string") : [];
|
|
@@ -6223,8 +6374,8 @@ function renderSourceScopeValidation(task, validation) {
|
|
|
6223
6374
|
|
|
6224
6375
|
// packages/cli/src/commands/inspect.ts
|
|
6225
6376
|
init_runner();
|
|
6226
|
-
import { existsSync as
|
|
6227
|
-
import { resolve as
|
|
6377
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
|
|
6378
|
+
import { resolve as resolve21 } from "path";
|
|
6228
6379
|
import {
|
|
6229
6380
|
listAuthorityRuns as listAuthorityRuns2,
|
|
6230
6381
|
readAuthorityRun as readAuthorityRun3,
|
|
@@ -6243,10 +6394,27 @@ async function executeInspect(context, args) {
|
|
|
6243
6394
|
const requiredTask = requireTask(task, "rig inspect logs --task <task-id>");
|
|
6244
6395
|
const latestRun = listAuthorityRuns2(context.projectRoot).map((entry) => readAuthorityRun3(context.projectRoot, entry.runId)).filter((run) => Boolean(run)).filter((run) => run.taskId === requiredTask).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")))[0];
|
|
6245
6396
|
if (!latestRun) {
|
|
6246
|
-
|
|
6397
|
+
const serverRuns = await listRunsViaServer(context, { limit: 200 }).catch(() => []);
|
|
6398
|
+
const serverRun = serverRuns.filter((run) => String(run.taskId ?? "") === requiredTask).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")))[0];
|
|
6399
|
+
if (!serverRun || typeof serverRun.runId !== "string") {
|
|
6400
|
+
throw new CliError2(`No runs found for ${requiredTask} (local or on the selected server).`);
|
|
6401
|
+
}
|
|
6402
|
+
const page = await getRunLogsViaServer(context, serverRun.runId, { limit: 500 });
|
|
6403
|
+
const entries = Array.isArray(page.entries) ? page.entries : [];
|
|
6404
|
+
if (context.outputMode === "text") {
|
|
6405
|
+
for (const entry of entries) {
|
|
6406
|
+
const record = entry && typeof entry === "object" ? entry : {};
|
|
6407
|
+
const title = String(record.title ?? "");
|
|
6408
|
+
const detail = String(record.detail ?? "");
|
|
6409
|
+
console.log([title, detail].filter(Boolean).join(" \u2014 "));
|
|
6410
|
+
}
|
|
6411
|
+
if (entries.length === 0)
|
|
6412
|
+
console.log(`(no log entries for run ${serverRun.runId})`);
|
|
6413
|
+
}
|
|
6414
|
+
return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: serverRun.runId, source: "server", entries } };
|
|
6247
6415
|
}
|
|
6248
|
-
const logsPath =
|
|
6249
|
-
if (!
|
|
6416
|
+
const logsPath = resolve21(resolveAuthorityRunDir4(context.projectRoot, latestRun.runId), "logs.jsonl");
|
|
6417
|
+
if (!existsSync13(logsPath)) {
|
|
6250
6418
|
throw new CliError2(`No logs found for run ${latestRun.runId}.`);
|
|
6251
6419
|
}
|
|
6252
6420
|
await context.runCommand(["cat", logsPath]);
|
|
@@ -6256,7 +6424,7 @@ async function executeInspect(context, args) {
|
|
|
6256
6424
|
const { value: task, rest: remaining } = takeOption(rest, "--task");
|
|
6257
6425
|
requireNoExtraArgs(remaining, "rig inspect artifacts --task <task-id>");
|
|
6258
6426
|
const requiredTask = requireTask(task, "rig inspect artifacts --task <task-id>");
|
|
6259
|
-
const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) =>
|
|
6427
|
+
const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) => existsSync13(path));
|
|
6260
6428
|
if (!artifactRoot) {
|
|
6261
6429
|
throw new CliError2(`No artifacts found for ${requiredTask}.`);
|
|
6262
6430
|
}
|
|
@@ -6313,10 +6481,10 @@ async function executeInspect(context, args) {
|
|
|
6313
6481
|
case "failures": {
|
|
6314
6482
|
requireNoExtraArgs(rest, "rig inspect failures");
|
|
6315
6483
|
const failed = resolveHarnessPaths2(context.projectRoot).failedApproachesPath;
|
|
6316
|
-
if (!
|
|
6484
|
+
if (!existsSync13(failed)) {
|
|
6317
6485
|
console.log("No failures recorded.");
|
|
6318
6486
|
} else {
|
|
6319
|
-
process.stdout.write(
|
|
6487
|
+
process.stdout.write(readFileSync9(failed, "utf-8"));
|
|
6320
6488
|
}
|
|
6321
6489
|
return { ok: true, group: "inspect", command };
|
|
6322
6490
|
}
|
|
@@ -6333,11 +6501,11 @@ async function executeInspect(context, args) {
|
|
|
6333
6501
|
return { ok: true, group: "inspect", command };
|
|
6334
6502
|
case "audit": {
|
|
6335
6503
|
requireNoExtraArgs(rest, "rig inspect audit");
|
|
6336
|
-
const auditPath =
|
|
6337
|
-
if (!
|
|
6504
|
+
const auditPath = resolve21(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
|
|
6505
|
+
if (!existsSync13(auditPath)) {
|
|
6338
6506
|
console.log("No audit log found.");
|
|
6339
6507
|
} else {
|
|
6340
|
-
const lines =
|
|
6508
|
+
const lines = readFileSync9(auditPath, "utf-8").split(/\r?\n/).filter(Boolean).slice(-20);
|
|
6341
6509
|
for (const line of lines) {
|
|
6342
6510
|
console.log(line);
|
|
6343
6511
|
}
|
|
@@ -7528,7 +7696,38 @@ function parseWsPayload(message2) {
|
|
|
7528
7696
|
return JSON.parse(message2.data);
|
|
7529
7697
|
return JSON.parse(Buffer.from(message2.data).toString("utf8"));
|
|
7530
7698
|
}
|
|
7531
|
-
|
|
7699
|
+
var BRIDGE_LOCAL_COMMANDS = new Set(["detach", "quit", "q", "stop"]);
|
|
7700
|
+
function registerDaemonCommandsNatively(pi, options, ctx, state, commands, registered) {
|
|
7701
|
+
for (const command of commands) {
|
|
7702
|
+
const record = recordOf(command);
|
|
7703
|
+
const name = typeof record?.name === "string" ? record.name : "";
|
|
7704
|
+
if (!name || registered.has(name) || BRIDGE_LOCAL_COMMANDS.has(name))
|
|
7705
|
+
continue;
|
|
7706
|
+
registered.add(name);
|
|
7707
|
+
const description = typeof record?.description === "string" ? record.description : undefined;
|
|
7708
|
+
const source = typeof record?.source === "string" ? record.source : "worker";
|
|
7709
|
+
try {
|
|
7710
|
+
pi.registerCommand(name, {
|
|
7711
|
+
description: `[worker ${source}] ${description ?? ""}`.trim(),
|
|
7712
|
+
handler: async (args) => {
|
|
7713
|
+
const text2 = `/${name}${args ? ` ${args}` : ""}`;
|
|
7714
|
+
appendTranscript(state, "You", text2);
|
|
7715
|
+
try {
|
|
7716
|
+
const result = await runRunPiCommandViaServer(options.context, options.runId, text2);
|
|
7717
|
+
const message2 = typeof result.message === "string" ? result.message : "worker command accepted";
|
|
7718
|
+
appendTranscript(state, "System", message2);
|
|
7719
|
+
if (state.nativeStream)
|
|
7720
|
+
ctx.ui.notify(message2, "info");
|
|
7721
|
+
} catch (error) {
|
|
7722
|
+
reportBridgeError(ctx, state, error instanceof Error ? error.message : String(error));
|
|
7723
|
+
}
|
|
7724
|
+
updatePiUi(ctx, state);
|
|
7725
|
+
}
|
|
7726
|
+
});
|
|
7727
|
+
} catch {}
|
|
7728
|
+
}
|
|
7729
|
+
}
|
|
7730
|
+
async function connectWorkerStream(options, pi, ctx, state, registeredDaemonCommands) {
|
|
7532
7731
|
const ready = await waitForWorkerReady(options, ctx, state);
|
|
7533
7732
|
if (!ready)
|
|
7534
7733
|
return;
|
|
@@ -7536,7 +7735,7 @@ async function connectWorkerStream(options, ctx, state) {
|
|
|
7536
7735
|
const buffered = [];
|
|
7537
7736
|
const wsUrl = await buildRunPiEventsWebSocketUrl(options.context, options.runId);
|
|
7538
7737
|
const socket = new WebSocket(wsUrl);
|
|
7539
|
-
const closePromise = new Promise((
|
|
7738
|
+
const closePromise = new Promise((resolve22) => {
|
|
7540
7739
|
socket.onopen = () => {
|
|
7541
7740
|
state.wsConnected = true;
|
|
7542
7741
|
state.status = "live worker Pi WebSocket connected";
|
|
@@ -7561,7 +7760,7 @@ async function connectWorkerStream(options, ctx, state) {
|
|
|
7561
7760
|
state.wsConnected = false;
|
|
7562
7761
|
state.status = "worker Pi WebSocket disconnected";
|
|
7563
7762
|
updatePiUi(ctx, state);
|
|
7564
|
-
|
|
7763
|
+
resolve22();
|
|
7565
7764
|
};
|
|
7566
7765
|
});
|
|
7567
7766
|
try {
|
|
@@ -7583,6 +7782,7 @@ async function connectWorkerStream(options, ctx, state) {
|
|
|
7583
7782
|
const record = recordOf(command);
|
|
7584
7783
|
return typeof record?.name === "string" ? [`/${record.name}`] : [];
|
|
7585
7784
|
});
|
|
7785
|
+
registerDaemonCommandsNatively(pi, options, ctx, state, commands, registeredDaemonCommands);
|
|
7586
7786
|
catchupDone = true;
|
|
7587
7787
|
for (const payload of buffered.splice(0))
|
|
7588
7788
|
applyEnvelope(ctx, state, payload);
|
|
@@ -7597,11 +7797,11 @@ async function connectWorkerStream(options, ctx, state) {
|
|
|
7597
7797
|
function createRemoteBashOperations(options, state, excludeFromContext) {
|
|
7598
7798
|
return {
|
|
7599
7799
|
exec(command, _cwd, execOptions) {
|
|
7600
|
-
return new Promise((
|
|
7800
|
+
return new Promise((resolve22, reject) => {
|
|
7601
7801
|
const pending = {
|
|
7602
7802
|
command,
|
|
7603
7803
|
onData: execOptions.onData,
|
|
7604
|
-
resolve:
|
|
7804
|
+
resolve: resolve22,
|
|
7605
7805
|
reject,
|
|
7606
7806
|
sawChunk: false
|
|
7607
7807
|
};
|
|
@@ -7710,6 +7910,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
7710
7910
|
};
|
|
7711
7911
|
if (options.initialMessageSent)
|
|
7712
7912
|
appendTranscript(state, "System", "Initial message sent to worker Pi daemon.");
|
|
7913
|
+
const registeredDaemonCommands = new Set;
|
|
7713
7914
|
let nativePiUiContextAvailable = false;
|
|
7714
7915
|
pi.on("user_bash", (event) => {
|
|
7715
7916
|
state.nativeStream = Boolean(state.nativeStream || nativePiUiContextAvailable);
|
|
@@ -7742,7 +7943,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
7742
7943
|
});
|
|
7743
7944
|
return { consume: true };
|
|
7744
7945
|
});
|
|
7745
|
-
connectWorkerStream(options, ctx, state).catch((error) => {
|
|
7946
|
+
connectWorkerStream(options, pi, ctx, state, registeredDaemonCommands).catch((error) => {
|
|
7746
7947
|
appendTranscript(state, "Error", error instanceof Error ? error.message : String(error));
|
|
7747
7948
|
updatePiUi(ctx, state);
|
|
7748
7949
|
});
|
|
@@ -7789,8 +7990,6 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
7789
7990
|
"--no-tools",
|
|
7790
7991
|
"--no-builtin-tools",
|
|
7791
7992
|
"--no-skills",
|
|
7792
|
-
"--no-prompt-templates",
|
|
7793
|
-
"--no-themes",
|
|
7794
7993
|
"--no-context-files",
|
|
7795
7994
|
"--no-approve"
|
|
7796
7995
|
], {
|
|
@@ -8264,6 +8463,33 @@ async function executeRun(context, args) {
|
|
|
8264
8463
|
}
|
|
8265
8464
|
return { ok: true, group: "run", command, details: restarted };
|
|
8266
8465
|
}
|
|
8466
|
+
case "steer": {
|
|
8467
|
+
const runOption = takeOption(rest, "--run");
|
|
8468
|
+
const messageOption = takeOption(runOption.rest, "--message");
|
|
8469
|
+
const shortMessageOption = takeOption(messageOption.rest, "-m");
|
|
8470
|
+
const positionalRunId = shortMessageOption.rest.length > 0 ? shortMessageOption.rest[0] : undefined;
|
|
8471
|
+
const extra = positionalRunId ? shortMessageOption.rest.slice(1) : shortMessageOption.rest;
|
|
8472
|
+
requireNoExtraArgs(extra, "rig run steer [<run-id>|--run <id>] --message <text>");
|
|
8473
|
+
const runId = runOption.value ?? positionalRunId;
|
|
8474
|
+
const message2 = messageOption.value ?? shortMessageOption.value;
|
|
8475
|
+
if (!runId) {
|
|
8476
|
+
throw new CliError2("run steer requires a run id (positional or --run <id>).", 2);
|
|
8477
|
+
}
|
|
8478
|
+
if (!message2?.trim()) {
|
|
8479
|
+
throw new CliError2("run steer requires --message <text>.", 2);
|
|
8480
|
+
}
|
|
8481
|
+
if (context.dryRun) {
|
|
8482
|
+
if (context.outputMode === "text") {
|
|
8483
|
+
console.log(`[dry-run] rig run steer ${runId} --message ${JSON.stringify(message2)}`);
|
|
8484
|
+
}
|
|
8485
|
+
return { ok: true, group: "run", command, details: { runId, dryRun: true } };
|
|
8486
|
+
}
|
|
8487
|
+
await steerRunViaServer(context, runId, message2.trim());
|
|
8488
|
+
if (context.outputMode === "text") {
|
|
8489
|
+
console.log(`Steering message queued for ${runId}.`);
|
|
8490
|
+
}
|
|
8491
|
+
return { ok: true, group: "run", command, details: { runId, queued: true } };
|
|
8492
|
+
}
|
|
8267
8493
|
case "stop": {
|
|
8268
8494
|
const runOption = takeOption(rest, "--run");
|
|
8269
8495
|
const positionalRunId = runOption.rest.length > 0 ? runOption.rest[0] : undefined;
|
|
@@ -8308,6 +8534,7 @@ async function executeRun(context, args) {
|
|
|
8308
8534
|
|
|
8309
8535
|
// packages/cli/src/commands/server.ts
|
|
8310
8536
|
init_runner();
|
|
8537
|
+
import { resolveRigServerCommand } from "@rig/runtime/local-server";
|
|
8311
8538
|
async function executeServer(context, args, options) {
|
|
8312
8539
|
const [command = "status", ...rest] = args;
|
|
8313
8540
|
if (["status", "list", "add", "use"].includes(command)) {
|
|
@@ -8325,7 +8552,8 @@ async function executeServer(context, args, options) {
|
|
|
8325
8552
|
const authTokenResult = takeOption(pending, "--auth-token");
|
|
8326
8553
|
pending = authTokenResult.rest;
|
|
8327
8554
|
requireNoExtraArgs(pending, "rig server start [--host <host>] [--port <n>] [--poll-ms <n>] [--auth-token <token>]");
|
|
8328
|
-
const
|
|
8555
|
+
const serverCommand = resolveRigServerCommand(context.projectRoot);
|
|
8556
|
+
const commandParts = [serverCommand.command, ...serverCommand.commandArgs, "start"];
|
|
8329
8557
|
if (hostResult.value) {
|
|
8330
8558
|
commandParts.push("--host", hostResult.value);
|
|
8331
8559
|
}
|
|
@@ -8348,7 +8576,8 @@ async function executeServer(context, args, options) {
|
|
|
8348
8576
|
const eventResult = takeOption(pending, "--event");
|
|
8349
8577
|
pending = eventResult.rest;
|
|
8350
8578
|
requireNoExtraArgs(pending, "rig server notify-test [--event <type>]");
|
|
8351
|
-
const
|
|
8579
|
+
const serverCommand = resolveRigServerCommand(context.projectRoot);
|
|
8580
|
+
const commandParts = [serverCommand.command, ...serverCommand.commandArgs, "notify-test"];
|
|
8352
8581
|
if (eventResult.value) {
|
|
8353
8582
|
commandParts.push("--event", eventResult.value);
|
|
8354
8583
|
}
|
|
@@ -8410,9 +8639,9 @@ async function executeServer(context, args, options) {
|
|
|
8410
8639
|
|
|
8411
8640
|
// packages/cli/src/commands/task.ts
|
|
8412
8641
|
init_runner();
|
|
8413
|
-
import { readFileSync as
|
|
8642
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
8414
8643
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
8415
|
-
import { resolve as
|
|
8644
|
+
import { resolve as resolve22 } from "path";
|
|
8416
8645
|
import { cancel as cancel4, confirm as confirm2, isCancel as isCancel4 } from "@clack/prompts";
|
|
8417
8646
|
import {
|
|
8418
8647
|
taskArtifactDir,
|
|
@@ -8590,6 +8819,7 @@ var PRIMARY_GROUPS = [
|
|
|
8590
8819
|
{ command: "show <id>|--run <id> [--raw]", description: "Show a human run summary; --raw prints the full payload.", primary: true },
|
|
8591
8820
|
{ command: "attach <run-id>|--run <id> [--follow]", description: "Attach to the run; --follow launches native bundled Pi for live Pi runs.", primary: true },
|
|
8592
8821
|
{ command: "stop [<run-id>|--run <id>]", description: "Request stop for one run or local active runs.", primary: true },
|
|
8822
|
+
{ command: "steer <run-id> --message <text>", description: "Queue a steering message into a live worker without attaching." },
|
|
8593
8823
|
{ command: "timeline --run <id> [--follow]", description: "Stream raw run timeline events." },
|
|
8594
8824
|
{ command: "resume", description: "Resume the most recent interrupted local run." },
|
|
8595
8825
|
{ command: "restart", description: "Restart the most recent local run from a clean runtime." },
|
|
@@ -8691,6 +8921,19 @@ var ADVANCED_GROUPS = [
|
|
|
8691
8921
|
{ command: "hp-next <dev|check|e2e|reset>", description: "Drive the hp-next browser test harness." }
|
|
8692
8922
|
]
|
|
8693
8923
|
},
|
|
8924
|
+
{
|
|
8925
|
+
name: "pi",
|
|
8926
|
+
summary: "Manage Pi extension packages for this project (community extensions from npm/git).",
|
|
8927
|
+
usage: ["rig pi <list|add|remove|search> [args]"],
|
|
8928
|
+
commands: [
|
|
8929
|
+
{ command: "list", description: "Show project and user Pi extension packages." },
|
|
8930
|
+
{ command: "add <source>", description: "Add an npm/git Pi extension to .pi/settings.json (auto-installs at next session)." },
|
|
8931
|
+
{ command: "remove <source>", description: "Remove an operator-added Pi extension." },
|
|
8932
|
+
{ command: "search [term]", description: "Discover Pi extension packages on the npm registry." }
|
|
8933
|
+
],
|
|
8934
|
+
examples: ["rig pi search subagents", "rig pi add pi-subagents", "rig pi list"],
|
|
8935
|
+
next: ["Config-managed extensions: declare `runtime: { pi: { packages: [...] } }` in rig.config.ts \u2014 workers pick them up automatically."]
|
|
8936
|
+
},
|
|
8694
8937
|
{
|
|
8695
8938
|
name: "plugin",
|
|
8696
8939
|
summary: "Plugin listing, validation, and plugin-contributed commands.",
|
|
@@ -9121,7 +9364,7 @@ async function executeTask(context, args, options) {
|
|
|
9121
9364
|
const fileFlag = takeOption(rest.slice(1), "--file");
|
|
9122
9365
|
let content;
|
|
9123
9366
|
if (fileFlag.value) {
|
|
9124
|
-
content =
|
|
9367
|
+
content = readFileSync10(resolve22(context.projectRoot, fileFlag.value), "utf-8");
|
|
9125
9368
|
} else {
|
|
9126
9369
|
content = await readStdin();
|
|
9127
9370
|
}
|
|
@@ -9355,8 +9598,8 @@ async function executeTask(context, args, options) {
|
|
|
9355
9598
|
|
|
9356
9599
|
// packages/cli/src/commands/task-run-driver.ts
|
|
9357
9600
|
init_runner();
|
|
9358
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
9359
|
-
import { resolve as
|
|
9601
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync11, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
9602
|
+
import { resolve as resolve23 } from "path";
|
|
9360
9603
|
import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
|
|
9361
9604
|
import { createInterface as createLineInterface } from "readline";
|
|
9362
9605
|
import { loadConfig as loadConfig2 } from "@rig/core/load-config";
|
|
@@ -9439,12 +9682,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
|
|
|
9439
9682
|
return 0;
|
|
9440
9683
|
let copied = 0;
|
|
9441
9684
|
for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
|
|
9442
|
-
const sourcePath =
|
|
9443
|
-
const targetPath =
|
|
9685
|
+
const sourcePath = resolve23(sourceRoot, relativePath);
|
|
9686
|
+
const targetPath = resolve23(targetRoot, relativePath);
|
|
9444
9687
|
try {
|
|
9445
9688
|
if (!statSync2(sourcePath).isFile())
|
|
9446
9689
|
continue;
|
|
9447
|
-
|
|
9690
|
+
mkdirSync9(resolve23(targetPath, ".."), { recursive: true });
|
|
9448
9691
|
copyFileSync3(sourcePath, targetPath);
|
|
9449
9692
|
copied += 1;
|
|
9450
9693
|
} catch {}
|
|
@@ -9483,7 +9726,7 @@ function buildDirtyBaselineHandshakeEnv(input) {
|
|
|
9483
9726
|
return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
|
|
9484
9727
|
return {
|
|
9485
9728
|
RIG_BASELINE_MODE: "dirty-snapshot",
|
|
9486
|
-
RIG_DIRTY_BASELINE_READY_FILE:
|
|
9729
|
+
RIG_DIRTY_BASELINE_READY_FILE: resolve23(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
|
|
9487
9730
|
};
|
|
9488
9731
|
}
|
|
9489
9732
|
function positiveInt(value, fallback) {
|
|
@@ -9594,9 +9837,9 @@ function createCommandRunner(binary) {
|
|
|
9594
9837
|
const stderrChunks = [];
|
|
9595
9838
|
child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
|
|
9596
9839
|
child.stderr.on("data", (chunk) => stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
|
|
9597
|
-
return await new Promise((
|
|
9598
|
-
child.once("error", (error) =>
|
|
9599
|
-
child.once("close", (code) =>
|
|
9840
|
+
return await new Promise((resolve24) => {
|
|
9841
|
+
child.once("error", (error) => resolve24({ exitCode: 1, stderr: error.message }));
|
|
9842
|
+
child.once("close", (code) => resolve24({
|
|
9600
9843
|
exitCode: code ?? 1,
|
|
9601
9844
|
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
9602
9845
|
stderr: Buffer.concat(stderrChunks).toString("utf8")
|
|
@@ -9670,7 +9913,7 @@ async function runTaskRunPostValidationLifecycle(input) {
|
|
|
9670
9913
|
config,
|
|
9671
9914
|
sourceTask: input.sourceTask,
|
|
9672
9915
|
uploadedSnapshot: input.uploadedSnapshot,
|
|
9673
|
-
artifactRoot:
|
|
9916
|
+
artifactRoot: resolve23(input.projectRoot, "artifacts", taskId3),
|
|
9674
9917
|
command: ghCommand,
|
|
9675
9918
|
gitCommand,
|
|
9676
9919
|
steerPi,
|
|
@@ -9800,7 +10043,7 @@ function summarizeValidationFailure(projectRoot, taskId3) {
|
|
|
9800
10043
|
return null;
|
|
9801
10044
|
}
|
|
9802
10045
|
for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId3)) {
|
|
9803
|
-
const summary = readJsonFile3(
|
|
10046
|
+
const summary = readJsonFile3(resolve23(artifactDir, "validation-summary.json"), null);
|
|
9804
10047
|
if (!summary || summary.status !== "fail") {
|
|
9805
10048
|
continue;
|
|
9806
10049
|
}
|
|
@@ -9881,9 +10124,9 @@ function readTaskRunAcceptedArtifactState(input) {
|
|
|
9881
10124
|
if (!input.taskId || !input.workspaceDir) {
|
|
9882
10125
|
return { accepted: false, reason: null };
|
|
9883
10126
|
}
|
|
9884
|
-
const artifactDir =
|
|
9885
|
-
const reviewStatusPath =
|
|
9886
|
-
const taskResultPath =
|
|
10127
|
+
const artifactDir = resolve23(input.workspaceDir, "artifacts", input.taskId);
|
|
10128
|
+
const reviewStatusPath = resolve23(artifactDir, "review-status.txt");
|
|
10129
|
+
const taskResultPath = resolve23(artifactDir, "task-result.json");
|
|
9887
10130
|
const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
|
|
9888
10131
|
if (reviewStatus !== "APPROVED") {
|
|
9889
10132
|
return { accepted: false, reason: null };
|
|
@@ -9920,12 +10163,12 @@ function resolveTaskRunRetryContext(input) {
|
|
|
9920
10163
|
if (!input.taskId || !input.workspaceDir) {
|
|
9921
10164
|
return { shouldRetry: false, failureDetail: null, nextPrompt: null };
|
|
9922
10165
|
}
|
|
9923
|
-
const artifactDir =
|
|
9924
|
-
const reviewStatePath =
|
|
9925
|
-
const reviewFeedbackPath =
|
|
9926
|
-
const reviewStatusPath =
|
|
9927
|
-
const failedApproachesPath =
|
|
9928
|
-
const validationSummaryPath =
|
|
10166
|
+
const artifactDir = resolve23(input.workspaceDir, "artifacts", input.taskId);
|
|
10167
|
+
const reviewStatePath = resolve23(artifactDir, "review-state.json");
|
|
10168
|
+
const reviewFeedbackPath = resolve23(artifactDir, "review-feedback.md");
|
|
10169
|
+
const reviewStatusPath = resolve23(artifactDir, "review-status.txt");
|
|
10170
|
+
const failedApproachesPath = resolve23(input.workspaceDir, ".rig", "state", "failed_approaches.md");
|
|
10171
|
+
const validationSummaryPath = resolve23(artifactDir, "validation-summary.json");
|
|
9929
10172
|
const reviewState = readJsonFile3(reviewStatePath, null);
|
|
9930
10173
|
const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
|
|
9931
10174
|
const reviewRejected = isTaskRunReviewRejected(reviewState);
|
|
@@ -10111,11 +10354,11 @@ function appendToolTimelineFromLog(input) {
|
|
|
10111
10354
|
});
|
|
10112
10355
|
}
|
|
10113
10356
|
function readTaskRunReviewStatus(reviewStatusPath) {
|
|
10114
|
-
if (!
|
|
10357
|
+
if (!existsSync14(reviewStatusPath)) {
|
|
10115
10358
|
return null;
|
|
10116
10359
|
}
|
|
10117
10360
|
try {
|
|
10118
|
-
const status =
|
|
10361
|
+
const status = readFileSync11(reviewStatusPath, "utf8").trim().toUpperCase();
|
|
10119
10362
|
return status === "APPROVED" || status === "REJECTED" ? status : null;
|
|
10120
10363
|
} catch {
|
|
10121
10364
|
return null;
|
|
@@ -10329,15 +10572,15 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
10329
10572
|
const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
|
|
10330
10573
|
const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
|
|
10331
10574
|
const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
|
|
10332
|
-
const planningArtifactPath =
|
|
10575
|
+
const planningArtifactPath = resolve23("artifacts", runtimeTaskId, "implementation-plan.md");
|
|
10333
10576
|
const persistedPlanning = {
|
|
10334
10577
|
...planningClassification,
|
|
10335
10578
|
classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
|
|
10336
10579
|
artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
|
|
10337
10580
|
classifiedAt: new Date().toISOString()
|
|
10338
10581
|
};
|
|
10339
|
-
|
|
10340
|
-
|
|
10582
|
+
mkdirSync9(resolve23(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
|
|
10583
|
+
writeFileSync7(resolve23(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
|
|
10341
10584
|
`, "utf8");
|
|
10342
10585
|
patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
|
|
10343
10586
|
prompt = `${prompt}
|
|
@@ -10387,7 +10630,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10387
10630
|
let verificationStarted = false;
|
|
10388
10631
|
let reviewStarted = false;
|
|
10389
10632
|
let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
|
|
10390
|
-
let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ?
|
|
10633
|
+
let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve23(existingRunRecord.sessionPath, "..") : null;
|
|
10391
10634
|
let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
|
|
10392
10635
|
let latestProviderCommand = null;
|
|
10393
10636
|
let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
|
|
@@ -10473,10 +10716,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10473
10716
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
10474
10717
|
status: "running",
|
|
10475
10718
|
worktreePath: latestRuntimeWorkspace,
|
|
10476
|
-
artifactRoot: latestRuntimeWorkspace && input.taskId ?
|
|
10719
|
+
artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve23(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
|
|
10477
10720
|
logRoot: latestLogsDir,
|
|
10478
|
-
sessionPath: latestSessionDir ?
|
|
10479
|
-
sessionLogPath: latestLogsDir ?
|
|
10721
|
+
sessionPath: latestSessionDir ? resolve23(latestSessionDir, "session.json") : null,
|
|
10722
|
+
sessionLogPath: latestLogsDir ? resolve23(latestLogsDir, "agent-stdout.log") : null,
|
|
10480
10723
|
branch: runtimeId
|
|
10481
10724
|
});
|
|
10482
10725
|
if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
|
|
@@ -10484,8 +10727,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10484
10727
|
const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
|
|
10485
10728
|
const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
|
|
10486
10729
|
if (readyFile) {
|
|
10487
|
-
|
|
10488
|
-
|
|
10730
|
+
mkdirSync9(resolve23(readyFile, ".."), { recursive: true });
|
|
10731
|
+
writeFileSync7(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
|
|
10489
10732
|
`, "utf8");
|
|
10490
10733
|
}
|
|
10491
10734
|
appendRunLog(context.projectRoot, input.runId, {
|
|
@@ -10869,7 +11112,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10869
11112
|
let acceptedArtifactObservedAt = null;
|
|
10870
11113
|
let acceptedArtifactPollTimer = null;
|
|
10871
11114
|
let acceptedArtifactKillTimer = null;
|
|
10872
|
-
const attemptExit = await new Promise((
|
|
11115
|
+
const attemptExit = await new Promise((resolve24) => {
|
|
10873
11116
|
let settled = false;
|
|
10874
11117
|
const settle = (result) => {
|
|
10875
11118
|
if (settled)
|
|
@@ -10877,7 +11120,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10877
11120
|
settled = true;
|
|
10878
11121
|
if (acceptedArtifactPollTimer)
|
|
10879
11122
|
clearInterval(acceptedArtifactPollTimer);
|
|
10880
|
-
|
|
11123
|
+
resolve24(result);
|
|
10881
11124
|
};
|
|
10882
11125
|
const pollAcceptedArtifacts = () => {
|
|
10883
11126
|
const artifactState = readTaskRunAcceptedArtifactState({
|
|
@@ -11079,8 +11322,8 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
11079
11322
|
}
|
|
11080
11323
|
if (planningClassification.planningRequired) {
|
|
11081
11324
|
const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
|
|
11082
|
-
const expectedPlanPath =
|
|
11083
|
-
if (!
|
|
11325
|
+
const expectedPlanPath = resolve23(planWorkspace, planningArtifactPath);
|
|
11326
|
+
if (!existsSync14(expectedPlanPath)) {
|
|
11084
11327
|
const failedAt = new Date().toISOString();
|
|
11085
11328
|
const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
|
|
11086
11329
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
@@ -11250,9 +11493,9 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
11250
11493
|
});
|
|
11251
11494
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
|
|
11252
11495
|
});
|
|
11253
|
-
const exitCode = await new Promise((
|
|
11254
|
-
child.once("error", () =>
|
|
11255
|
-
child.once("close", (code) =>
|
|
11496
|
+
const exitCode = await new Promise((resolve24) => {
|
|
11497
|
+
child.once("error", () => resolve24(1));
|
|
11498
|
+
child.once("close", (code) => resolve24(code ?? 1));
|
|
11256
11499
|
});
|
|
11257
11500
|
for (const pendingLog of flushPendingClaudeToolUseLogs({
|
|
11258
11501
|
runId: input.runId,
|
|
@@ -11394,8 +11637,8 @@ async function executeTest(context, args) {
|
|
|
11394
11637
|
|
|
11395
11638
|
// packages/cli/src/commands/setup.ts
|
|
11396
11639
|
init_runner();
|
|
11397
|
-
import { existsSync as
|
|
11398
|
-
import { resolve as
|
|
11640
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync10, readdirSync as readdirSync2, writeFileSync as writeFileSync8 } from "fs";
|
|
11641
|
+
import { resolve as resolve24 } from "path";
|
|
11399
11642
|
import { createPluginHost } from "@rig/core";
|
|
11400
11643
|
import {
|
|
11401
11644
|
isSupportedBunVersion as isSupportedBunVersion2,
|
|
@@ -11450,12 +11693,12 @@ function runSetupInit(projectRoot) {
|
|
|
11450
11693
|
const stateDir = resolveControlPlaneHostStateDir(projectRoot);
|
|
11451
11694
|
const logsDir = resolveControlPlaneHostLogsDir(projectRoot);
|
|
11452
11695
|
const artifactsDir = resolveControlPlaneArtifactsDir(projectRoot);
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
const failuresPath =
|
|
11457
|
-
if (!
|
|
11458
|
-
|
|
11696
|
+
mkdirSync10(stateDir, { recursive: true });
|
|
11697
|
+
mkdirSync10(logsDir, { recursive: true });
|
|
11698
|
+
mkdirSync10(artifactsDir, { recursive: true });
|
|
11699
|
+
const failuresPath = resolve24(stateDir, "failed_approaches.md");
|
|
11700
|
+
if (!existsSync15(failuresPath)) {
|
|
11701
|
+
writeFileSync8(failuresPath, `# Failed Approaches
|
|
11459
11702
|
|
|
11460
11703
|
`, "utf-8");
|
|
11461
11704
|
}
|
|
@@ -11472,18 +11715,18 @@ async function runSetupCheck(projectRoot) {
|
|
|
11472
11715
|
}
|
|
11473
11716
|
async function runSetupPreflight(projectRoot) {
|
|
11474
11717
|
await runSetupCheck(projectRoot);
|
|
11475
|
-
const validationRoot =
|
|
11476
|
-
if (
|
|
11718
|
+
const validationRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
|
|
11719
|
+
if (existsSync15(validationRoot)) {
|
|
11477
11720
|
const validators = readdirSync2(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
11478
11721
|
for (const validator of validators) {
|
|
11479
|
-
const script =
|
|
11480
|
-
if (
|
|
11722
|
+
const script = resolve24(validationRoot, validator.name, "validate.sh");
|
|
11723
|
+
if (existsSync15(script)) {
|
|
11481
11724
|
console.log(`OK: validator script ${script}`);
|
|
11482
11725
|
}
|
|
11483
11726
|
}
|
|
11484
11727
|
}
|
|
11485
|
-
const hooksRoot =
|
|
11486
|
-
if (
|
|
11728
|
+
const hooksRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
|
|
11729
|
+
if (existsSync15(hooksRoot)) {
|
|
11487
11730
|
const hooks = readdirSync2(hooksRoot).filter((name) => name.endsWith(".sh"));
|
|
11488
11731
|
for (const hook of hooks) {
|
|
11489
11732
|
console.log(`OK: hook ${hook}`);
|
|
@@ -11628,7 +11871,7 @@ var PROJECT_REQUIRED_GROUPS = new Set([
|
|
|
11628
11871
|
]);
|
|
11629
11872
|
var RIG_CONFIG_FILENAMES = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
|
|
11630
11873
|
function hasInitializedRigProject(projectRoot) {
|
|
11631
|
-
return RIG_CONFIG_FILENAMES.some((name) =>
|
|
11874
|
+
return RIG_CONFIG_FILENAMES.some((name) => existsSync16(resolve25(projectRoot, name))) || existsSync16(resolve25(projectRoot, ".rig"));
|
|
11632
11875
|
}
|
|
11633
11876
|
function requireInitializedRigProject(context, group) {
|
|
11634
11877
|
if (hasInitializedRigProject(context.projectRoot)) {
|
|
@@ -11654,6 +11897,7 @@ var GROUPS = new Set([
|
|
|
11654
11897
|
"review",
|
|
11655
11898
|
"git",
|
|
11656
11899
|
"harness",
|
|
11900
|
+
"pi",
|
|
11657
11901
|
"plugin",
|
|
11658
11902
|
"queue",
|
|
11659
11903
|
"agent",
|
|
@@ -11799,6 +12043,8 @@ async function executeGroup(context, group, args) {
|
|
|
11799
12043
|
return executeGit(context, args);
|
|
11800
12044
|
case "harness":
|
|
11801
12045
|
return executeHarness(context, args);
|
|
12046
|
+
case "pi":
|
|
12047
|
+
return executePi(context, args);
|
|
11802
12048
|
case "plugin":
|
|
11803
12049
|
return executePlugin(context, args);
|
|
11804
12050
|
case "queue":
|
|
@@ -11845,8 +12091,8 @@ var __testOnly = {
|
|
|
11845
12091
|
validateRequiredBugPromptValue
|
|
11846
12092
|
};
|
|
11847
12093
|
// packages/cli/src/launcher.ts
|
|
11848
|
-
import { existsSync as
|
|
11849
|
-
import { basename as basename2, resolve as
|
|
12094
|
+
import { existsSync as existsSync17 } from "fs";
|
|
12095
|
+
import { basename as basename2, resolve as resolve26 } from "path";
|
|
11850
12096
|
import { loadDotEnvSecrets } from "@rig/runtime/baked-secrets";
|
|
11851
12097
|
import { RIG_DEFINITION_DIRNAME, RIG_STATE_DIRNAME, resolveNearestRigProjectRoot } from "@rig/runtime/layout";
|
|
11852
12098
|
function parsePolicyMode(value) {
|
|
@@ -11859,7 +12105,7 @@ function parsePolicyMode(value) {
|
|
|
11859
12105
|
throw new Error(`Invalid --policy-mode value: ${value}. Use off|observe|enforce.`);
|
|
11860
12106
|
}
|
|
11861
12107
|
function hasRigProjectMarker(candidate) {
|
|
11862
|
-
return
|
|
12108
|
+
return existsSync17(resolve26(candidate, RIG_DEFINITION_DIRNAME)) || existsSync17(resolve26(candidate, RIG_STATE_DIRNAME)) || existsSync17(resolve26(candidate, "rig.config.ts")) || existsSync17(resolve26(candidate, "rig.config.json")) || existsSync17(resolve26(candidate, ".git"));
|
|
11863
12109
|
}
|
|
11864
12110
|
function resolveProjectRoot({
|
|
11865
12111
|
envProjectRoot,
|
|
@@ -11868,19 +12114,19 @@ function resolveProjectRoot({
|
|
|
11868
12114
|
cwd = process.cwd()
|
|
11869
12115
|
}) {
|
|
11870
12116
|
if (envProjectRoot) {
|
|
11871
|
-
return
|
|
12117
|
+
return resolve26(cwd, envProjectRoot);
|
|
11872
12118
|
}
|
|
11873
12119
|
const fallbackImportDir = importDir ?? cwd;
|
|
11874
12120
|
const execName = basename2(execPath).toLowerCase();
|
|
11875
|
-
const execCandidates = execName === "rig" || execName === "rig.exe" ? [
|
|
11876
|
-
const candidates = [cwd, ...execCandidates,
|
|
12121
|
+
const execCandidates = execName === "rig" || execName === "rig.exe" ? [resolve26(execPath, "..", "..")] : [];
|
|
12122
|
+
const candidates = [cwd, ...execCandidates, resolve26(fallbackImportDir, "..")];
|
|
11877
12123
|
for (const candidate of candidates) {
|
|
11878
12124
|
const nearest = resolveNearestRigProjectRoot(candidate);
|
|
11879
12125
|
if (hasRigProjectMarker(nearest)) {
|
|
11880
12126
|
return nearest;
|
|
11881
12127
|
}
|
|
11882
12128
|
}
|
|
11883
|
-
return
|
|
12129
|
+
return resolve26(cwd);
|
|
11884
12130
|
}
|
|
11885
12131
|
function normalizeCliErrorCode(message2, isCliError) {
|
|
11886
12132
|
if (message2.startsWith("Invalid --policy-mode value:")) {
|
|
@@ -11947,7 +12193,7 @@ async function runRigCli(module, options = {}) {
|
|
|
11947
12193
|
runId: context.runId,
|
|
11948
12194
|
outcome,
|
|
11949
12195
|
eventsFile: context.eventBus.getEventsFile(),
|
|
11950
|
-
policyFile:
|
|
12196
|
+
policyFile: resolve26(projectRoot, "rig", "policy", "policy.json"),
|
|
11951
12197
|
policyMode: context.policyMode ?? policyMode ?? module.loadPolicy(projectRoot).mode
|
|
11952
12198
|
}, null, 2));
|
|
11953
12199
|
}
|