@h-rig/runtime 0.0.6-alpha.34 → 0.0.6-alpha.35
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-agent-dispatch.js +518 -459
- package/dist/bin/rig-agent.js +430 -361
- package/dist/src/control-plane/agent-wrapper.js +523 -464
- package/dist/src/control-plane/harness-main.js +528 -458
- package/dist/src/control-plane/hooks/completion-verification.js +353 -283
- package/dist/src/control-plane/hooks/inject-context.js +158 -99
- package/dist/src/control-plane/hooks/submodule-branch.js +538 -479
- package/dist/src/control-plane/hooks/task-runtime-start.js +538 -479
- package/dist/src/control-plane/materialize-task-config.js +68 -8
- package/dist/src/control-plane/native/git-ops.js +10 -0
- package/dist/src/control-plane/native/harness-cli.js +513 -443
- package/dist/src/control-plane/native/task-ops.js +392 -322
- package/dist/src/control-plane/native/validator.js +159 -100
- package/dist/src/control-plane/native/verifier.js +227 -166
- package/dist/src/control-plane/pi-settings-materializer.js +52 -0
- package/dist/src/control-plane/plugin-host-context.js +59 -0
- package/dist/src/control-plane/runtime/index.js +469 -410
- package/dist/src/control-plane/runtime/isolation/index.js +493 -434
- package/dist/src/control-plane/runtime/isolation.js +493 -434
- package/dist/src/control-plane/runtime/queue.js +411 -352
- package/dist/src/control-plane/tasks/source-lifecycle.js +87 -28
- package/package.json +8 -8
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// packages/runtime/src/control-plane/hooks/inject-context.ts
|
|
5
|
-
import { existsSync as
|
|
6
|
-
import { resolve as
|
|
5
|
+
import { existsSync as existsSync23, readFileSync as readFileSync14 } from "fs";
|
|
6
|
+
import { resolve as resolve23 } from "path";
|
|
7
7
|
import { resolveProjectRoot } from "@rig/hook-kit";
|
|
8
8
|
|
|
9
9
|
// packages/runtime/src/control-plane/memory-sync/db.ts
|
|
@@ -1128,8 +1128,8 @@ async function loadReviewProfile(path) {
|
|
|
1128
1128
|
}
|
|
1129
1129
|
|
|
1130
1130
|
// packages/runtime/src/control-plane/native/repo-ops.ts
|
|
1131
|
-
import { existsSync as
|
|
1132
|
-
import { basename as basename7, dirname as
|
|
1131
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync13, readFileSync as readFileSync13, readdirSync as readdirSync5, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "fs";
|
|
1132
|
+
import { basename as basename7, dirname as dirname12, resolve as resolve22 } from "path";
|
|
1133
1133
|
|
|
1134
1134
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
1135
1135
|
var SUPPORTED_TASK_STATE_SCHEMA_VERSION = 1;
|
|
@@ -1626,8 +1626,8 @@ function syncManagedRepo(projectRoot, repoId) {
|
|
|
1626
1626
|
return { layout, headCommit };
|
|
1627
1627
|
}
|
|
1628
1628
|
// packages/runtime/src/control-plane/native/task-ops.ts
|
|
1629
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
1630
|
-
import { resolve as
|
|
1629
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
1630
|
+
import { resolve as resolve21 } from "path";
|
|
1631
1631
|
|
|
1632
1632
|
// packages/runtime/src/build-time-config.ts
|
|
1633
1633
|
function normalizeBuildConfig(value) {
|
|
@@ -2084,6 +2084,8 @@ function buildBrowserGuidanceLines(browser) {
|
|
|
2084
2084
|
}
|
|
2085
2085
|
|
|
2086
2086
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
2087
|
+
import { existsSync as existsSync15 } from "fs";
|
|
2088
|
+
import { resolve as resolvePath } from "path";
|
|
2087
2089
|
import { createPluginHost } from "@rig/core";
|
|
2088
2090
|
import { loadConfig } from "@rig/core/load-config";
|
|
2089
2091
|
|
|
@@ -2365,6 +2367,55 @@ async function materializeSkills(projectRoot, entries) {
|
|
|
2365
2367
|
return written;
|
|
2366
2368
|
}
|
|
2367
2369
|
|
|
2370
|
+
// packages/runtime/src/control-plane/pi-settings-materializer.ts
|
|
2371
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
2372
|
+
import { dirname as dirname11, resolve as resolve15 } from "path";
|
|
2373
|
+
var SETTINGS_RELATIVE_PATH = ".pi/settings.json";
|
|
2374
|
+
var MANAGED_RECORD_RELATIVE_PATH = ".rig/state/pi-managed-packages.json";
|
|
2375
|
+
function readJson(path, fallback) {
|
|
2376
|
+
if (!existsSync14(path))
|
|
2377
|
+
return fallback;
|
|
2378
|
+
try {
|
|
2379
|
+
return JSON.parse(readFileSync7(path, "utf-8"));
|
|
2380
|
+
} catch {
|
|
2381
|
+
return fallback;
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
function packageKey(entry) {
|
|
2385
|
+
if (typeof entry === "string")
|
|
2386
|
+
return entry;
|
|
2387
|
+
if (entry && typeof entry === "object" && typeof entry.source === "string") {
|
|
2388
|
+
return entry.source;
|
|
2389
|
+
}
|
|
2390
|
+
return JSON.stringify(entry);
|
|
2391
|
+
}
|
|
2392
|
+
function materializePiPackages(projectRoot, declaredPackages) {
|
|
2393
|
+
const settingsPath = resolve15(projectRoot, SETTINGS_RELATIVE_PATH);
|
|
2394
|
+
const managedRecordPath = resolve15(projectRoot, MANAGED_RECORD_RELATIVE_PATH);
|
|
2395
|
+
const settings = readJson(settingsPath, {});
|
|
2396
|
+
const previouslyManaged = new Set(readJson(managedRecordPath, []));
|
|
2397
|
+
const existing = Array.isArray(settings.packages) ? settings.packages : [];
|
|
2398
|
+
const operatorEntries = existing.filter((entry) => !previouslyManaged.has(packageKey(entry)));
|
|
2399
|
+
const operatorKeys = new Set(operatorEntries.map(packageKey));
|
|
2400
|
+
const managedToAdd = declaredPackages.filter((pkg) => !operatorKeys.has(pkg));
|
|
2401
|
+
const nextPackages = [...operatorEntries, ...managedToAdd];
|
|
2402
|
+
if (nextPackages.length > 0 || existsSync14(settingsPath)) {
|
|
2403
|
+
const nextSettings = { ...settings };
|
|
2404
|
+
if (nextPackages.length > 0) {
|
|
2405
|
+
nextSettings.packages = nextPackages;
|
|
2406
|
+
} else {
|
|
2407
|
+
delete nextSettings.packages;
|
|
2408
|
+
}
|
|
2409
|
+
mkdirSync11(dirname11(settingsPath), { recursive: true });
|
|
2410
|
+
writeFileSync7(settingsPath, `${JSON.stringify(nextSettings, null, 2)}
|
|
2411
|
+
`, "utf-8");
|
|
2412
|
+
}
|
|
2413
|
+
mkdirSync11(dirname11(managedRecordPath), { recursive: true });
|
|
2414
|
+
writeFileSync7(managedRecordPath, `${JSON.stringify(managedToAdd, null, 2)}
|
|
2415
|
+
`, "utf-8");
|
|
2416
|
+
return { settingsPath, packages: managedToAdd };
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2368
2419
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
2369
2420
|
async function buildPluginHostContext(projectRoot) {
|
|
2370
2421
|
let config;
|
|
@@ -2412,6 +2463,14 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
2412
2463
|
} catch (err) {
|
|
2413
2464
|
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
2414
2465
|
}
|
|
2466
|
+
try {
|
|
2467
|
+
const piPackages = config.runtime?.pi?.packages ?? [];
|
|
2468
|
+
if (piPackages.length > 0 || existsSync15(resolvePath(projectRoot, ".rig/state/pi-managed-packages.json"))) {
|
|
2469
|
+
materializePiPackages(projectRoot, piPackages);
|
|
2470
|
+
}
|
|
2471
|
+
} catch (err) {
|
|
2472
|
+
console.warn(`[plugin-host] Pi package materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
2473
|
+
}
|
|
2415
2474
|
return {
|
|
2416
2475
|
config,
|
|
2417
2476
|
pluginHost,
|
|
@@ -2425,12 +2484,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
2425
2484
|
|
|
2426
2485
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
2427
2486
|
import { spawnSync } from "child_process";
|
|
2428
|
-
import { existsSync as
|
|
2429
|
-
import { basename as basename5, join as join4, resolve as
|
|
2487
|
+
import { existsSync as existsSync17, readFileSync as readFileSync9, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync8 } from "fs";
|
|
2488
|
+
import { basename as basename5, join as join4, resolve as resolve17 } from "path";
|
|
2430
2489
|
|
|
2431
2490
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
2432
|
-
import { existsSync as
|
|
2433
|
-
import { resolve as
|
|
2491
|
+
import { existsSync as existsSync16, readFileSync as readFileSync8 } from "fs";
|
|
2492
|
+
import { resolve as resolve16 } from "path";
|
|
2434
2493
|
|
|
2435
2494
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
2436
2495
|
async function findTaskById(reader, id) {
|
|
@@ -2453,7 +2512,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
2453
2512
|
}
|
|
2454
2513
|
}
|
|
2455
2514
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
2456
|
-
const configPath = options.configPath ??
|
|
2515
|
+
const configPath = options.configPath ?? resolve16(projectRoot, ".rig", "task-config.json");
|
|
2457
2516
|
const reader = {
|
|
2458
2517
|
async listTasks() {
|
|
2459
2518
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -2464,8 +2523,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
2464
2523
|
};
|
|
2465
2524
|
return reader;
|
|
2466
2525
|
}
|
|
2467
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
2468
|
-
if (!
|
|
2526
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve16(projectRoot, ".rig", "task-config.json")) {
|
|
2527
|
+
if (!existsSync16(configPath)) {
|
|
2469
2528
|
return [];
|
|
2470
2529
|
}
|
|
2471
2530
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -2473,7 +2532,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve15(projectRoot,
|
|
|
2473
2532
|
}
|
|
2474
2533
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
2475
2534
|
try {
|
|
2476
|
-
const parsed = JSON.parse(
|
|
2535
|
+
const parsed = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
2477
2536
|
if (isPlainRecord(parsed)) {
|
|
2478
2537
|
return parsed;
|
|
2479
2538
|
}
|
|
@@ -2557,7 +2616,7 @@ function isPlainRecord(candidate) {
|
|
|
2557
2616
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
2558
2617
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
2559
2618
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
2560
|
-
const configPath = options.configPath ??
|
|
2619
|
+
const configPath = options.configPath ?? resolve17(projectRoot, ".rig", "task-config.json");
|
|
2561
2620
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
2562
2621
|
const spawnFn = options.spawn ?? spawnSync;
|
|
2563
2622
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -2640,10 +2699,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
2640
2699
|
return metadata;
|
|
2641
2700
|
}
|
|
2642
2701
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
2643
|
-
const jsonPath =
|
|
2644
|
-
if (
|
|
2702
|
+
const jsonPath = resolve17(projectRoot, "rig.config.json");
|
|
2703
|
+
if (existsSync17(jsonPath)) {
|
|
2645
2704
|
try {
|
|
2646
|
-
const parsed = JSON.parse(
|
|
2705
|
+
const parsed = JSON.parse(readFileSync9(jsonPath, "utf8"));
|
|
2647
2706
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
2648
2707
|
const source = parsed.taskSource;
|
|
2649
2708
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -2652,12 +2711,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
2652
2711
|
return null;
|
|
2653
2712
|
}
|
|
2654
2713
|
}
|
|
2655
|
-
const tsPath =
|
|
2656
|
-
if (!
|
|
2714
|
+
const tsPath = resolve17(projectRoot, "rig.config.ts");
|
|
2715
|
+
if (!existsSync17(tsPath)) {
|
|
2657
2716
|
return null;
|
|
2658
2717
|
}
|
|
2659
2718
|
try {
|
|
2660
|
-
const source =
|
|
2719
|
+
const source = readFileSync9(tsPath, "utf8");
|
|
2661
2720
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
2662
2721
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
2663
2722
|
if (kind !== "files") {
|
|
@@ -2677,10 +2736,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
2677
2736
|
return isPlainRecord2(entry) ? entry : null;
|
|
2678
2737
|
}
|
|
2679
2738
|
function readRawTaskConfig(configPath) {
|
|
2680
|
-
if (!
|
|
2739
|
+
if (!existsSync17(configPath)) {
|
|
2681
2740
|
return null;
|
|
2682
2741
|
}
|
|
2683
|
-
const parsed = JSON.parse(
|
|
2742
|
+
const parsed = JSON.parse(readFileSync9(configPath, "utf8"));
|
|
2684
2743
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
2685
2744
|
}
|
|
2686
2745
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -2688,8 +2747,8 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
2688
2747
|
return tasks;
|
|
2689
2748
|
}
|
|
2690
2749
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
2691
|
-
const directory =
|
|
2692
|
-
if (!
|
|
2750
|
+
const directory = resolve17(projectRoot, sourcePath);
|
|
2751
|
+
if (!existsSync17(directory)) {
|
|
2693
2752
|
return [];
|
|
2694
2753
|
}
|
|
2695
2754
|
const tasks = [];
|
|
@@ -2704,11 +2763,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
2704
2763
|
return tasks;
|
|
2705
2764
|
}
|
|
2706
2765
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
2707
|
-
const file = findFileBackedTaskFile(
|
|
2766
|
+
const file = findFileBackedTaskFile(resolve17(projectRoot, sourcePath), taskId);
|
|
2708
2767
|
if (!file) {
|
|
2709
2768
|
return null;
|
|
2710
2769
|
}
|
|
2711
|
-
const raw = JSON.parse(
|
|
2770
|
+
const raw = JSON.parse(readFileSync9(file, "utf8"));
|
|
2712
2771
|
if (!isPlainRecord2(raw)) {
|
|
2713
2772
|
return null;
|
|
2714
2773
|
}
|
|
@@ -2721,7 +2780,7 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
2721
2780
|
};
|
|
2722
2781
|
}
|
|
2723
2782
|
function findFileBackedTaskFile(directory, taskId) {
|
|
2724
|
-
if (!
|
|
2783
|
+
if (!existsSync17(directory)) {
|
|
2725
2784
|
return null;
|
|
2726
2785
|
}
|
|
2727
2786
|
for (const name of readdirSync3(directory)) {
|
|
@@ -2731,7 +2790,7 @@ function findFileBackedTaskFile(directory, taskId) {
|
|
|
2731
2790
|
try {
|
|
2732
2791
|
if (!statSync3(file).isFile())
|
|
2733
2792
|
continue;
|
|
2734
|
-
const raw = JSON.parse(
|
|
2793
|
+
const raw = JSON.parse(readFileSync9(file, "utf8"));
|
|
2735
2794
|
const inferredId = basename5(file).replace(FILE_TASK_PATTERN, "");
|
|
2736
2795
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
2737
2796
|
if (id === taskId) {
|
|
@@ -2891,20 +2950,20 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
2891
2950
|
}
|
|
2892
2951
|
|
|
2893
2952
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
2894
|
-
import { existsSync as
|
|
2895
|
-
import { basename as basename6, resolve as
|
|
2953
|
+
import { existsSync as existsSync20, readFileSync as readFileSync11, readdirSync as readdirSync4, statSync as statSync4, writeFileSync as writeFileSync9 } from "fs";
|
|
2954
|
+
import { basename as basename6, resolve as resolve20 } from "path";
|
|
2896
2955
|
// packages/runtime/src/control-plane/state-sync/read.ts
|
|
2897
|
-
import { existsSync as
|
|
2898
|
-
import { resolve as
|
|
2956
|
+
import { existsSync as existsSync19, readFileSync as readFileSync10 } from "fs";
|
|
2957
|
+
import { resolve as resolve19 } from "path";
|
|
2899
2958
|
|
|
2900
2959
|
// packages/runtime/src/control-plane/state-sync/repo.ts
|
|
2901
|
-
import { existsSync as
|
|
2902
|
-
import { resolve as
|
|
2960
|
+
import { existsSync as existsSync18 } from "fs";
|
|
2961
|
+
import { resolve as resolve18 } from "path";
|
|
2903
2962
|
function resolveTrackerRepoPath(projectRoot) {
|
|
2904
2963
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2905
2964
|
try {
|
|
2906
2965
|
const layout = resolveMonorepoRepoLayout(projectRoot);
|
|
2907
|
-
if (
|
|
2966
|
+
if (existsSync18(resolve18(layout.mirrorRoot, "HEAD"))) {
|
|
2908
2967
|
return layout.mirrorRoot;
|
|
2909
2968
|
}
|
|
2910
2969
|
} catch {}
|
|
@@ -2915,8 +2974,8 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
2915
2974
|
var DEFAULT_READ_DEPS = {
|
|
2916
2975
|
fetchRef: nativeFetchRef,
|
|
2917
2976
|
readBlobAtRef: nativeReadBlobAtRef,
|
|
2918
|
-
exists:
|
|
2919
|
-
readFile: (path) =>
|
|
2977
|
+
exists: existsSync19,
|
|
2978
|
+
readFile: (path) => readFileSync10(path, "utf8")
|
|
2920
2979
|
};
|
|
2921
2980
|
function parseIssueStatus(rawStatus) {
|
|
2922
2981
|
const normalized = normalizeTaskLifecycleStatus(rawStatus);
|
|
@@ -2997,12 +3056,12 @@ function shouldPreferLocalTrackerState(options) {
|
|
|
2997
3056
|
if (runtimeContextPath) {
|
|
2998
3057
|
return true;
|
|
2999
3058
|
}
|
|
3000
|
-
return
|
|
3059
|
+
return existsSync19(resolve19(runtimeWorkspace, ".rig", "runtime-context.json"));
|
|
3001
3060
|
}
|
|
3002
3061
|
function readLocalTrackerState(projectRoot, deps) {
|
|
3003
3062
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
3004
|
-
const issuesPath =
|
|
3005
|
-
const taskStatePath =
|
|
3063
|
+
const issuesPath = resolve19(monorepoRoot, ".beads", "issues.jsonl");
|
|
3064
|
+
const taskStatePath = resolve19(monorepoRoot, ".beads", "task-state.json");
|
|
3006
3065
|
return projectSyncedTrackerSnapshot({
|
|
3007
3066
|
source: "local",
|
|
3008
3067
|
issuesBaseOid: null,
|
|
@@ -3064,7 +3123,7 @@ function readValidationDescriptions(projectRoot) {
|
|
|
3064
3123
|
return readValidationDescriptionMap(raw);
|
|
3065
3124
|
}
|
|
3066
3125
|
function readSourceValidationDescriptions(projectRoot) {
|
|
3067
|
-
const rootRaw = readJsonFile(
|
|
3126
|
+
const rootRaw = readJsonFile(resolve20(projectRoot, "rig", "task-config.json"), {});
|
|
3068
3127
|
const sourcePath = findSourceTaskConfigPath(projectRoot);
|
|
3069
3128
|
const sourceRaw = sourcePath ? readJsonFile(sourcePath, {}) : {};
|
|
3070
3129
|
const rootDescriptions = readValidationDescriptionMap(rootRaw);
|
|
@@ -3140,15 +3199,15 @@ function readValidationDescriptionsFromMeta(meta) {
|
|
|
3140
3199
|
return meta.validation_descriptions;
|
|
3141
3200
|
}
|
|
3142
3201
|
function readLocalSourceTaskStateEnvelope(projectRoot) {
|
|
3143
|
-
const taskStatePath =
|
|
3202
|
+
const taskStatePath = resolve20(resolveMonorepoRoot2(projectRoot), ".beads", "task-state.json");
|
|
3144
3203
|
return readTaskStateMetadataEnvelope(readJsonFile(taskStatePath, {}));
|
|
3145
3204
|
}
|
|
3146
3205
|
function readLocalSourceTaskLifecycleStatus(projectRoot, taskId) {
|
|
3147
|
-
const issuesPath =
|
|
3148
|
-
if (!
|
|
3206
|
+
const issuesPath = resolve20(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
3207
|
+
if (!existsSync20(issuesPath)) {
|
|
3149
3208
|
return null;
|
|
3150
3209
|
}
|
|
3151
|
-
for (const line of
|
|
3210
|
+
for (const line of readFileSync11(issuesPath, "utf8").split(/\r?\n/)) {
|
|
3152
3211
|
const trimmed = line.trim();
|
|
3153
3212
|
if (!trimmed) {
|
|
3154
3213
|
continue;
|
|
@@ -3173,25 +3232,25 @@ function inferTaskIdFromRuntimePath(path) {
|
|
|
3173
3232
|
function artifactDirForId(projectRoot, id) {
|
|
3174
3233
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
3175
3234
|
if (workspaceDir) {
|
|
3176
|
-
const worktreeArtifacts =
|
|
3177
|
-
if (
|
|
3235
|
+
const worktreeArtifacts = resolve20(workspaceDir, "artifacts", id);
|
|
3236
|
+
if (existsSync20(worktreeArtifacts) || existsSync20(resolve20(workspaceDir, "artifacts"))) {
|
|
3178
3237
|
return worktreeArtifacts;
|
|
3179
3238
|
}
|
|
3180
3239
|
}
|
|
3181
3240
|
try {
|
|
3182
3241
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3183
|
-
return
|
|
3242
|
+
return resolve20(paths.artifactsDir, id);
|
|
3184
3243
|
} catch {
|
|
3185
|
-
return
|
|
3244
|
+
return resolve20(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
3186
3245
|
}
|
|
3187
3246
|
}
|
|
3188
3247
|
function resolveTaskConfigPath(projectRoot) {
|
|
3189
3248
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3190
|
-
if (
|
|
3249
|
+
if (existsSync20(paths.taskConfigPath)) {
|
|
3191
3250
|
return paths.taskConfigPath;
|
|
3192
3251
|
}
|
|
3193
3252
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
3194
|
-
if (
|
|
3253
|
+
if (existsSync20(candidate)) {
|
|
3195
3254
|
return candidate;
|
|
3196
3255
|
}
|
|
3197
3256
|
}
|
|
@@ -3199,7 +3258,7 @@ function resolveTaskConfigPath(projectRoot) {
|
|
|
3199
3258
|
}
|
|
3200
3259
|
function findSourceTaskConfigPath(projectRoot) {
|
|
3201
3260
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
3202
|
-
if (
|
|
3261
|
+
if (existsSync20(candidate)) {
|
|
3203
3262
|
return candidate;
|
|
3204
3263
|
}
|
|
3205
3264
|
}
|
|
@@ -3212,7 +3271,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
3212
3271
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
3213
3272
|
if (sourcePath && synced.updated) {
|
|
3214
3273
|
try {
|
|
3215
|
-
|
|
3274
|
+
writeFileSync9(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
3216
3275
|
`, "utf-8");
|
|
3217
3276
|
} catch {}
|
|
3218
3277
|
}
|
|
@@ -3264,12 +3323,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
3264
3323
|
return !candidate.role;
|
|
3265
3324
|
}
|
|
3266
3325
|
function readSourceIssueRecords(projectRoot) {
|
|
3267
|
-
const issuesPath =
|
|
3268
|
-
if (!
|
|
3326
|
+
const issuesPath = resolve20(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
3327
|
+
if (!existsSync20(issuesPath)) {
|
|
3269
3328
|
return [];
|
|
3270
3329
|
}
|
|
3271
3330
|
const records = [];
|
|
3272
|
-
for (const line of
|
|
3331
|
+
for (const line of readFileSync11(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
3273
3332
|
const trimmed = line.trim();
|
|
3274
3333
|
if (!trimmed) {
|
|
3275
3334
|
continue;
|
|
@@ -3325,19 +3384,19 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
3325
3384
|
if (!sourcePath) {
|
|
3326
3385
|
return {};
|
|
3327
3386
|
}
|
|
3328
|
-
const directory =
|
|
3329
|
-
if (!
|
|
3387
|
+
const directory = resolve20(projectRoot, sourcePath);
|
|
3388
|
+
if (!existsSync20(directory)) {
|
|
3330
3389
|
return {};
|
|
3331
3390
|
}
|
|
3332
3391
|
const config = {};
|
|
3333
3392
|
for (const name of readdirSync4(directory)) {
|
|
3334
3393
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
3335
3394
|
continue;
|
|
3336
|
-
const file =
|
|
3395
|
+
const file = resolve20(directory, name);
|
|
3337
3396
|
try {
|
|
3338
3397
|
if (!statSync4(file).isFile())
|
|
3339
3398
|
continue;
|
|
3340
|
-
const raw = JSON.parse(
|
|
3399
|
+
const raw = JSON.parse(readFileSync11(file, "utf8"));
|
|
3341
3400
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
3342
3401
|
continue;
|
|
3343
3402
|
const record = raw;
|
|
@@ -3379,10 +3438,10 @@ function firstStringList2(...candidates) {
|
|
|
3379
3438
|
return [];
|
|
3380
3439
|
}
|
|
3381
3440
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
3382
|
-
const jsonPath =
|
|
3383
|
-
if (
|
|
3441
|
+
const jsonPath = resolve20(projectRoot, "rig.config.json");
|
|
3442
|
+
if (existsSync20(jsonPath)) {
|
|
3384
3443
|
try {
|
|
3385
|
-
const parsed = JSON.parse(
|
|
3444
|
+
const parsed = JSON.parse(readFileSync11(jsonPath, "utf8"));
|
|
3386
3445
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3387
3446
|
const taskSource = parsed.taskSource;
|
|
3388
3447
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -3394,12 +3453,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
3394
3453
|
return null;
|
|
3395
3454
|
}
|
|
3396
3455
|
}
|
|
3397
|
-
const tsPath =
|
|
3398
|
-
if (!
|
|
3456
|
+
const tsPath = resolve20(projectRoot, "rig.config.ts");
|
|
3457
|
+
if (!existsSync20(tsPath)) {
|
|
3399
3458
|
return null;
|
|
3400
3459
|
}
|
|
3401
3460
|
try {
|
|
3402
|
-
const source =
|
|
3461
|
+
const source = readFileSync11(tsPath, "utf8");
|
|
3403
3462
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
3404
3463
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
3405
3464
|
if (kind !== "files") {
|
|
@@ -3413,9 +3472,9 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
3413
3472
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
3414
3473
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
3415
3474
|
return [
|
|
3416
|
-
runtimeContext?.monorepoMainRoot ?
|
|
3417
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
3418
|
-
|
|
3475
|
+
runtimeContext?.monorepoMainRoot ? resolve20(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
3476
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve20(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
3477
|
+
resolve20(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
3419
3478
|
].filter(Boolean);
|
|
3420
3479
|
}
|
|
3421
3480
|
|
|
@@ -3714,16 +3773,16 @@ async function taskDeps(projectRoot, taskId) {
|
|
|
3714
3773
|
for (const dep of deps) {
|
|
3715
3774
|
const artifactDir = artifactDirForId(projectRoot, dep);
|
|
3716
3775
|
console.log(`=== ${dep} ===`);
|
|
3717
|
-
if (!
|
|
3776
|
+
if (!existsSync21(artifactDir)) {
|
|
3718
3777
|
console.log(` (no artifacts yet)
|
|
3719
3778
|
`);
|
|
3720
3779
|
continue;
|
|
3721
3780
|
}
|
|
3722
|
-
printArtifactSection(
|
|
3723
|
-
printArtifactSection(
|
|
3724
|
-
const changedFiles =
|
|
3725
|
-
if (
|
|
3726
|
-
const lines =
|
|
3781
|
+
printArtifactSection(resolve21(artifactDir, "decision-log.md"), "--- Decisions ---");
|
|
3782
|
+
printArtifactSection(resolve21(artifactDir, "next-actions.md"), "--- Next Actions (for you) ---");
|
|
3783
|
+
const changedFiles = resolve21(artifactDir, "changed-files.txt");
|
|
3784
|
+
if (existsSync21(changedFiles)) {
|
|
3785
|
+
const lines = readFileSync12(changedFiles, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
3727
3786
|
console.log(`--- Changed Files (${lines.length}) ---`);
|
|
3728
3787
|
for (const line of lines) {
|
|
3729
3788
|
console.log(line);
|
|
@@ -3824,12 +3883,12 @@ function printIndented(text) {
|
|
|
3824
3883
|
}
|
|
3825
3884
|
}
|
|
3826
3885
|
function readLocalBeadsTasks(projectRoot) {
|
|
3827
|
-
const issuesPath =
|
|
3828
|
-
if (!
|
|
3886
|
+
const issuesPath = resolve21(resolveMonorepoRoot2(projectRoot), ".beads/issues.jsonl");
|
|
3887
|
+
if (!existsSync21(issuesPath)) {
|
|
3829
3888
|
return [];
|
|
3830
3889
|
}
|
|
3831
3890
|
const tasks = [];
|
|
3832
|
-
for (const line of
|
|
3891
|
+
for (const line of readFileSync12(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
3833
3892
|
const trimmed = line.trim();
|
|
3834
3893
|
if (!trimmed) {
|
|
3835
3894
|
continue;
|
|
@@ -3942,11 +4001,11 @@ function taskDependencies(projectRoot, taskId, tracker) {
|
|
|
3942
4001
|
return [...ids].sort();
|
|
3943
4002
|
}
|
|
3944
4003
|
function printArtifactSection(path, header) {
|
|
3945
|
-
if (!
|
|
4004
|
+
if (!existsSync21(path)) {
|
|
3946
4005
|
return;
|
|
3947
4006
|
}
|
|
3948
4007
|
console.log(header);
|
|
3949
|
-
process.stdout.write(
|
|
4008
|
+
process.stdout.write(readFileSync12(path, "utf-8"));
|
|
3950
4009
|
console.log("");
|
|
3951
4010
|
}
|
|
3952
4011
|
|
|
@@ -3972,7 +4031,7 @@ function repoDiscover(projectRoot, taskId) {
|
|
|
3972
4031
|
}
|
|
3973
4032
|
function repoBaseline(projectRoot, refresh = false) {
|
|
3974
4033
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
3975
|
-
if (!refresh &&
|
|
4034
|
+
if (!refresh && existsSync22(paths.baseRepoPinsPath)) {
|
|
3976
4035
|
const baseline = readJsonFile(paths.baseRepoPinsPath, { recorded_at: nowIso(), repos: {} });
|
|
3977
4036
|
return baseline.repos || {};
|
|
3978
4037
|
}
|
|
@@ -3986,8 +4045,8 @@ function repoBaseline(projectRoot, refresh = false) {
|
|
|
3986
4045
|
}
|
|
3987
4046
|
function persistBaselinePins(projectRoot, repos) {
|
|
3988
4047
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
3989
|
-
|
|
3990
|
-
|
|
4048
|
+
mkdirSync13(resolve22(paths.baseRepoPinsPath, ".."), { recursive: true });
|
|
4049
|
+
writeFileSync11(paths.baseRepoPinsPath, `${JSON.stringify({ recorded_at: nowIso(), repos }, null, 2)}
|
|
3991
4050
|
`, "utf-8");
|
|
3992
4051
|
return repos;
|
|
3993
4052
|
}
|
|
@@ -4059,28 +4118,28 @@ function readRepoDiscoveryTaskConfig(projectRoot) {
|
|
|
4059
4118
|
function resolveRepoDiscoveryPaths(projectRoot) {
|
|
4060
4119
|
const monorepoRoot = resolveMonorepoRepoLayout(projectRoot).checkoutRoot;
|
|
4061
4120
|
const explicitHostProjectRoot = (process.env.RIG_HOST_PROJECT_ROOT || "").trim();
|
|
4062
|
-
const normalizedProjectRoot =
|
|
4121
|
+
const normalizedProjectRoot = resolve22(projectRoot);
|
|
4063
4122
|
const hostProjectRoot = explicitHostProjectRoot && shouldUseHostProjectStateRoot(normalizedProjectRoot) ? explicitHostProjectRoot : normalizedProjectRoot;
|
|
4064
|
-
const stateDir =
|
|
4123
|
+
const stateDir = resolve22(hostProjectRoot, ".rig", "state");
|
|
4065
4124
|
return {
|
|
4066
4125
|
monorepoRoot,
|
|
4067
|
-
taskRepoCommitsPath:
|
|
4068
|
-
baseRepoPinsPath:
|
|
4126
|
+
taskRepoCommitsPath: resolve22(stateDir, "task-repo-commits.json"),
|
|
4127
|
+
baseRepoPinsPath: resolve22(stateDir, "base-repo-pins.json")
|
|
4069
4128
|
};
|
|
4070
4129
|
}
|
|
4071
4130
|
function shouldUseHostProjectStateRoot(projectRoot) {
|
|
4072
4131
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
4073
|
-
if (runtimeWorkspace &&
|
|
4132
|
+
if (runtimeWorkspace && resolve22(runtimeWorkspace) === projectRoot) {
|
|
4074
4133
|
return true;
|
|
4075
4134
|
}
|
|
4076
|
-
return basename7(
|
|
4135
|
+
return basename7(dirname12(projectRoot)) === ".worktrees";
|
|
4077
4136
|
}
|
|
4078
4137
|
function readPinFromArtifact(projectRoot, depTask, repoKey) {
|
|
4079
|
-
const snapshot =
|
|
4080
|
-
if (!
|
|
4138
|
+
const snapshot = resolve22(artifactDirForId(projectRoot, depTask), "git-state.txt");
|
|
4139
|
+
if (!existsSync22(snapshot)) {
|
|
4081
4140
|
return "";
|
|
4082
4141
|
}
|
|
4083
|
-
const content =
|
|
4142
|
+
const content = readFileSync13(snapshot, "utf-8");
|
|
4084
4143
|
const chunk = content.split(/\r?\n/);
|
|
4085
4144
|
let inSection = false;
|
|
4086
4145
|
for (const line of chunk) {
|
|
@@ -4109,7 +4168,7 @@ function defaultMemoryQuery(taskId, runtimeContext) {
|
|
|
4109
4168
|
async function printSharedMemorySection(taskId) {
|
|
4110
4169
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
4111
4170
|
const memory = runtimeContext?.memory;
|
|
4112
|
-
if (!memory?.hydratedPath || !
|
|
4171
|
+
if (!memory?.hydratedPath || !existsSync23(memory.hydratedPath)) {
|
|
4113
4172
|
return;
|
|
4114
4173
|
}
|
|
4115
4174
|
const db = await openMemoryDb(memory.hydratedPath);
|
|
@@ -4156,17 +4215,17 @@ async function main() {
|
|
|
4156
4215
|
console.log("(no explicit/discovered task pins)");
|
|
4157
4216
|
} else {
|
|
4158
4217
|
for (const [key, expected] of Object.entries(pins)) {
|
|
4159
|
-
const repoPath = key.startsWith("/") ? key :
|
|
4218
|
+
const repoPath = key.startsWith("/") ? key : resolve23(projectRoot, key);
|
|
4160
4219
|
let current = "missing";
|
|
4161
|
-
if (
|
|
4220
|
+
if (existsSync23(resolve23(repoPath, ".git"))) {
|
|
4162
4221
|
current = runCapture(["git", "-C", repoPath, "rev-parse", "HEAD"], projectRoot).stdout.trim() || "unknown";
|
|
4163
4222
|
}
|
|
4164
4223
|
console.log(`${current === expected ? "OK " : "WARN"} ${key} expected ${expected} got ${current}`);
|
|
4165
4224
|
}
|
|
4166
4225
|
}
|
|
4167
|
-
const failedPath =
|
|
4168
|
-
if (
|
|
4169
|
-
const lines =
|
|
4226
|
+
const failedPath = resolve23(resolveHarnessPaths(projectRoot).stateDir, "failed_approaches.md");
|
|
4227
|
+
if (existsSync23(failedPath)) {
|
|
4228
|
+
const lines = readFileSync14(failedPath, "utf-8").split(/\r?\n/);
|
|
4170
4229
|
let printing = false;
|
|
4171
4230
|
const failureLines = [];
|
|
4172
4231
|
for (const line of lines) {
|