@h-rig/runtime 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-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 +544 -463
- package/dist/src/control-plane/hooks/completion-verification.js +369 -288
- 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 +529 -448
- package/dist/src/control-plane/native/task-ops.js +408 -327
- package/dist/src/control-plane/native/validator.js +159 -100
- package/dist/src/control-plane/native/verifier.js +243 -171
- package/dist/src/control-plane/pi-sessiond/bin.js +0 -7
- package/dist/src/control-plane/pi-sessiond/server.js +0 -7
- package/dist/src/control-plane/pi-sessiond/session-service.js +0 -3
- 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/dist/src/index.js +16 -8
- package/dist/src/local-server.js +17 -8
- package/package.json +8 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/runtime/src/control-plane/native/verifier.ts
|
|
3
|
-
import { existsSync as
|
|
4
|
-
import { resolve as
|
|
3
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
4
|
+
import { resolve as resolve15 } from "path";
|
|
5
5
|
|
|
6
6
|
// packages/runtime/src/control-plane/runtime/baked-secrets.ts
|
|
7
7
|
var BAKED_RUNTIME_SECRETS = {
|
|
@@ -47,8 +47,8 @@ function resolveRuntimeSecrets(env, baked = BAKED_RUNTIME_SECRETS) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// packages/runtime/src/control-plane/native/git-ops.ts
|
|
50
|
-
import { existsSync as
|
|
51
|
-
import { dirname as
|
|
50
|
+
import { existsSync as existsSync13, lstatSync, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
51
|
+
import { dirname as dirname9, isAbsolute as isAbsolute2, resolve as resolve14 } from "path";
|
|
52
52
|
|
|
53
53
|
// packages/runtime/src/control-plane/runtime/context.ts
|
|
54
54
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -262,6 +262,8 @@ import { basename as basename2, dirname as dirname4, resolve as resolve4 } from
|
|
|
262
262
|
var sharedNativeToolsOutputDir = resolve4(tmpdir3(), "rig-native");
|
|
263
263
|
var sharedNativeToolsOutputPath = resolve4(sharedNativeToolsOutputDir, `rig-tools-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
264
264
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
265
|
+
import { existsSync as existsSync6 } from "fs";
|
|
266
|
+
import { resolve as resolvePath } from "path";
|
|
265
267
|
import { createPluginHost } from "@rig/core";
|
|
266
268
|
import { loadConfig } from "@rig/core/load-config";
|
|
267
269
|
|
|
@@ -588,6 +590,55 @@ async function materializeSkills(projectRoot, entries) {
|
|
|
588
590
|
return written;
|
|
589
591
|
}
|
|
590
592
|
|
|
593
|
+
// packages/runtime/src/control-plane/pi-settings-materializer.ts
|
|
594
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
595
|
+
import { dirname as dirname6, resolve as resolve7 } from "path";
|
|
596
|
+
var SETTINGS_RELATIVE_PATH = ".pi/settings.json";
|
|
597
|
+
var MANAGED_RECORD_RELATIVE_PATH = ".rig/state/pi-managed-packages.json";
|
|
598
|
+
function readJson(path, fallback) {
|
|
599
|
+
if (!existsSync5(path))
|
|
600
|
+
return fallback;
|
|
601
|
+
try {
|
|
602
|
+
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
603
|
+
} catch {
|
|
604
|
+
return fallback;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
function packageKey(entry) {
|
|
608
|
+
if (typeof entry === "string")
|
|
609
|
+
return entry;
|
|
610
|
+
if (entry && typeof entry === "object" && typeof entry.source === "string") {
|
|
611
|
+
return entry.source;
|
|
612
|
+
}
|
|
613
|
+
return JSON.stringify(entry);
|
|
614
|
+
}
|
|
615
|
+
function materializePiPackages(projectRoot, declaredPackages) {
|
|
616
|
+
const settingsPath = resolve7(projectRoot, SETTINGS_RELATIVE_PATH);
|
|
617
|
+
const managedRecordPath = resolve7(projectRoot, MANAGED_RECORD_RELATIVE_PATH);
|
|
618
|
+
const settings = readJson(settingsPath, {});
|
|
619
|
+
const previouslyManaged = new Set(readJson(managedRecordPath, []));
|
|
620
|
+
const existing = Array.isArray(settings.packages) ? settings.packages : [];
|
|
621
|
+
const operatorEntries = existing.filter((entry) => !previouslyManaged.has(packageKey(entry)));
|
|
622
|
+
const operatorKeys = new Set(operatorEntries.map(packageKey));
|
|
623
|
+
const managedToAdd = declaredPackages.filter((pkg) => !operatorKeys.has(pkg));
|
|
624
|
+
const nextPackages = [...operatorEntries, ...managedToAdd];
|
|
625
|
+
if (nextPackages.length > 0 || existsSync5(settingsPath)) {
|
|
626
|
+
const nextSettings = { ...settings };
|
|
627
|
+
if (nextPackages.length > 0) {
|
|
628
|
+
nextSettings.packages = nextPackages;
|
|
629
|
+
} else {
|
|
630
|
+
delete nextSettings.packages;
|
|
631
|
+
}
|
|
632
|
+
mkdirSync4(dirname6(settingsPath), { recursive: true });
|
|
633
|
+
writeFileSync4(settingsPath, `${JSON.stringify(nextSettings, null, 2)}
|
|
634
|
+
`, "utf-8");
|
|
635
|
+
}
|
|
636
|
+
mkdirSync4(dirname6(managedRecordPath), { recursive: true });
|
|
637
|
+
writeFileSync4(managedRecordPath, `${JSON.stringify(managedToAdd, null, 2)}
|
|
638
|
+
`, "utf-8");
|
|
639
|
+
return { settingsPath, packages: managedToAdd };
|
|
640
|
+
}
|
|
641
|
+
|
|
591
642
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
592
643
|
async function buildPluginHostContext(projectRoot) {
|
|
593
644
|
let config;
|
|
@@ -635,6 +686,14 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
635
686
|
} catch (err) {
|
|
636
687
|
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
637
688
|
}
|
|
689
|
+
try {
|
|
690
|
+
const piPackages = config.runtime?.pi?.packages ?? [];
|
|
691
|
+
if (piPackages.length > 0 || existsSync6(resolvePath(projectRoot, ".rig/state/pi-managed-packages.json"))) {
|
|
692
|
+
materializePiPackages(projectRoot, piPackages);
|
|
693
|
+
}
|
|
694
|
+
} catch (err) {
|
|
695
|
+
console.warn(`[plugin-host] Pi package materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
696
|
+
}
|
|
638
697
|
return {
|
|
639
698
|
config,
|
|
640
699
|
pluginHost,
|
|
@@ -648,12 +707,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
648
707
|
|
|
649
708
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
650
709
|
import { spawnSync } from "child_process";
|
|
651
|
-
import { existsSync as
|
|
652
|
-
import { basename as basename3, join as join2, resolve as
|
|
710
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync2, statSync, writeFileSync as writeFileSync5 } from "fs";
|
|
711
|
+
import { basename as basename3, join as join2, resolve as resolve9 } from "path";
|
|
653
712
|
|
|
654
713
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
655
|
-
import { existsSync as
|
|
656
|
-
import { resolve as
|
|
714
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
|
|
715
|
+
import { resolve as resolve8 } from "path";
|
|
657
716
|
|
|
658
717
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
659
718
|
async function findTaskById(reader, id) {
|
|
@@ -676,7 +735,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
676
735
|
}
|
|
677
736
|
}
|
|
678
737
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
679
|
-
const configPath = options.configPath ??
|
|
738
|
+
const configPath = options.configPath ?? resolve8(projectRoot, ".rig", "task-config.json");
|
|
680
739
|
const reader = {
|
|
681
740
|
async listTasks() {
|
|
682
741
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -687,8 +746,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
687
746
|
};
|
|
688
747
|
return reader;
|
|
689
748
|
}
|
|
690
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
691
|
-
if (!
|
|
749
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve8(projectRoot, ".rig", "task-config.json")) {
|
|
750
|
+
if (!existsSync7(configPath)) {
|
|
692
751
|
return [];
|
|
693
752
|
}
|
|
694
753
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -696,7 +755,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve7(projectRoot, "
|
|
|
696
755
|
}
|
|
697
756
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
698
757
|
try {
|
|
699
|
-
const parsed = JSON.parse(
|
|
758
|
+
const parsed = JSON.parse(readFileSync5(configPath, "utf8"));
|
|
700
759
|
if (isPlainRecord(parsed)) {
|
|
701
760
|
return parsed;
|
|
702
761
|
}
|
|
@@ -780,7 +839,7 @@ function isPlainRecord(candidate) {
|
|
|
780
839
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
781
840
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
782
841
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
783
|
-
const configPath = options.configPath ??
|
|
842
|
+
const configPath = options.configPath ?? resolve9(projectRoot, ".rig", "task-config.json");
|
|
784
843
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
785
844
|
const spawnFn = options.spawn ?? spawnSync;
|
|
786
845
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -863,10 +922,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
863
922
|
return metadata;
|
|
864
923
|
}
|
|
865
924
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
866
|
-
const jsonPath =
|
|
867
|
-
if (
|
|
925
|
+
const jsonPath = resolve9(projectRoot, "rig.config.json");
|
|
926
|
+
if (existsSync8(jsonPath)) {
|
|
868
927
|
try {
|
|
869
|
-
const parsed = JSON.parse(
|
|
928
|
+
const parsed = JSON.parse(readFileSync6(jsonPath, "utf8"));
|
|
870
929
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
871
930
|
const source = parsed.taskSource;
|
|
872
931
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -875,12 +934,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
875
934
|
return null;
|
|
876
935
|
}
|
|
877
936
|
}
|
|
878
|
-
const tsPath =
|
|
879
|
-
if (!
|
|
937
|
+
const tsPath = resolve9(projectRoot, "rig.config.ts");
|
|
938
|
+
if (!existsSync8(tsPath)) {
|
|
880
939
|
return null;
|
|
881
940
|
}
|
|
882
941
|
try {
|
|
883
|
-
const source =
|
|
942
|
+
const source = readFileSync6(tsPath, "utf8");
|
|
884
943
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
885
944
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
886
945
|
if (kind !== "files") {
|
|
@@ -900,10 +959,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
900
959
|
return isPlainRecord2(entry) ? entry : null;
|
|
901
960
|
}
|
|
902
961
|
function readRawTaskConfig(configPath) {
|
|
903
|
-
if (!
|
|
962
|
+
if (!existsSync8(configPath)) {
|
|
904
963
|
return null;
|
|
905
964
|
}
|
|
906
|
-
const parsed = JSON.parse(
|
|
965
|
+
const parsed = JSON.parse(readFileSync6(configPath, "utf8"));
|
|
907
966
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
908
967
|
}
|
|
909
968
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -911,8 +970,8 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
911
970
|
return tasks;
|
|
912
971
|
}
|
|
913
972
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
914
|
-
const directory =
|
|
915
|
-
if (!
|
|
973
|
+
const directory = resolve9(projectRoot, sourcePath);
|
|
974
|
+
if (!existsSync8(directory)) {
|
|
916
975
|
return [];
|
|
917
976
|
}
|
|
918
977
|
const tasks = [];
|
|
@@ -927,11 +986,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
927
986
|
return tasks;
|
|
928
987
|
}
|
|
929
988
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
930
|
-
const file = findFileBackedTaskFile(
|
|
989
|
+
const file = findFileBackedTaskFile(resolve9(projectRoot, sourcePath), taskId);
|
|
931
990
|
if (!file) {
|
|
932
991
|
return null;
|
|
933
992
|
}
|
|
934
|
-
const raw = JSON.parse(
|
|
993
|
+
const raw = JSON.parse(readFileSync6(file, "utf8"));
|
|
935
994
|
if (!isPlainRecord2(raw)) {
|
|
936
995
|
return null;
|
|
937
996
|
}
|
|
@@ -944,7 +1003,7 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
944
1003
|
};
|
|
945
1004
|
}
|
|
946
1005
|
function findFileBackedTaskFile(directory, taskId) {
|
|
947
|
-
if (!
|
|
1006
|
+
if (!existsSync8(directory)) {
|
|
948
1007
|
return null;
|
|
949
1008
|
}
|
|
950
1009
|
for (const name of readdirSync2(directory)) {
|
|
@@ -954,7 +1013,7 @@ function findFileBackedTaskFile(directory, taskId) {
|
|
|
954
1013
|
try {
|
|
955
1014
|
if (!statSync(file).isFile())
|
|
956
1015
|
continue;
|
|
957
|
-
const raw = JSON.parse(
|
|
1016
|
+
const raw = JSON.parse(readFileSync6(file, "utf8"));
|
|
958
1017
|
const inferredId = basename3(file).replace(FILE_TASK_PATTERN, "");
|
|
959
1018
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
960
1019
|
if (id === taskId) {
|
|
@@ -1114,8 +1173,8 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
1114
1173
|
}
|
|
1115
1174
|
|
|
1116
1175
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
1117
|
-
import { existsSync as
|
|
1118
|
-
import { basename as basename5, resolve as
|
|
1176
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
1177
|
+
import { basename as basename5, resolve as resolve13 } from "path";
|
|
1119
1178
|
|
|
1120
1179
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
1121
1180
|
var CANONICAL_TASK_LIFECYCLE_STATUSES = new Set([
|
|
@@ -1130,46 +1189,46 @@ var CANONICAL_TASK_LIFECYCLE_STATUSES = new Set([
|
|
|
1130
1189
|
"cancelled"
|
|
1131
1190
|
]);
|
|
1132
1191
|
// packages/runtime/src/control-plane/native/utils.ts
|
|
1133
|
-
import { existsSync as
|
|
1134
|
-
import { resolve as
|
|
1192
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
|
|
1193
|
+
import { resolve as resolve12 } from "path";
|
|
1135
1194
|
|
|
1136
1195
|
// packages/runtime/src/layout.ts
|
|
1137
|
-
import { existsSync as
|
|
1138
|
-
import { basename as basename4, dirname as
|
|
1196
|
+
import { existsSync as existsSync9 } from "fs";
|
|
1197
|
+
import { basename as basename4, dirname as dirname7, resolve as resolve10 } from "path";
|
|
1139
1198
|
var RIG_DEFINITION_DIRNAME = "rig";
|
|
1140
1199
|
var RIG_ARTIFACTS_DIRNAME = "artifacts";
|
|
1141
1200
|
function resolveMonorepoRoot(projectRoot) {
|
|
1142
|
-
const normalizedProjectRoot =
|
|
1201
|
+
const normalizedProjectRoot = resolve10(projectRoot);
|
|
1143
1202
|
const explicit = process.env.MONOREPO_ROOT?.trim();
|
|
1144
1203
|
if (explicit) {
|
|
1145
|
-
const explicitRoot =
|
|
1146
|
-
const explicitParent =
|
|
1204
|
+
const explicitRoot = resolve10(explicit);
|
|
1205
|
+
const explicitParent = dirname7(explicitRoot);
|
|
1147
1206
|
if (basename4(explicitParent) === ".worktrees") {
|
|
1148
|
-
const owner =
|
|
1149
|
-
const ownerHasGit =
|
|
1150
|
-
const ownerHasTaskConfig =
|
|
1151
|
-
const ownerHasRigConfig =
|
|
1207
|
+
const owner = dirname7(explicitParent);
|
|
1208
|
+
const ownerHasGit = existsSync9(resolve10(owner, ".git"));
|
|
1209
|
+
const ownerHasTaskConfig = existsSync9(resolve10(owner, ".rig", "task-config.json"));
|
|
1210
|
+
const ownerHasRigConfig = existsSync9(resolve10(owner, "rig.config.ts"));
|
|
1152
1211
|
if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
|
|
1153
1212
|
return owner;
|
|
1154
1213
|
}
|
|
1155
1214
|
throw new Error(`MONOREPO_ROOT points to worktree ${explicitRoot}, but the owner checkout is incomplete at ${owner}.`);
|
|
1156
1215
|
}
|
|
1157
|
-
if (!
|
|
1216
|
+
if (!existsSync9(resolve10(explicitRoot, ".git"))) {
|
|
1158
1217
|
throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but no git checkout was found there.`);
|
|
1159
1218
|
}
|
|
1160
|
-
const hasTaskConfig =
|
|
1161
|
-
const hasRigConfig =
|
|
1219
|
+
const hasTaskConfig = existsSync9(resolve10(explicitRoot, ".rig", "task-config.json"));
|
|
1220
|
+
const hasRigConfig = existsSync9(resolve10(explicitRoot, "rig.config.ts"));
|
|
1162
1221
|
if (!hasTaskConfig && !hasRigConfig) {
|
|
1163
1222
|
throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but neither .rig/task-config.json nor rig.config.ts exists there.`);
|
|
1164
1223
|
}
|
|
1165
1224
|
return explicitRoot;
|
|
1166
1225
|
}
|
|
1167
|
-
const projectParent =
|
|
1226
|
+
const projectParent = dirname7(normalizedProjectRoot);
|
|
1168
1227
|
if (basename4(projectParent) === ".worktrees") {
|
|
1169
|
-
const worktreeOwner =
|
|
1170
|
-
const ownerHasGit =
|
|
1171
|
-
const ownerHasTaskConfig =
|
|
1172
|
-
const ownerHasRigConfig =
|
|
1228
|
+
const worktreeOwner = dirname7(projectParent);
|
|
1229
|
+
const ownerHasGit = existsSync9(resolve10(worktreeOwner, ".git"));
|
|
1230
|
+
const ownerHasTaskConfig = existsSync9(resolve10(worktreeOwner, ".rig", "task-config.json"));
|
|
1231
|
+
const ownerHasRigConfig = existsSync9(resolve10(worktreeOwner, "rig.config.ts"));
|
|
1173
1232
|
if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
|
|
1174
1233
|
return worktreeOwner;
|
|
1175
1234
|
}
|
|
@@ -1177,28 +1236,28 @@ function resolveMonorepoRoot(projectRoot) {
|
|
|
1177
1236
|
return normalizedProjectRoot;
|
|
1178
1237
|
}
|
|
1179
1238
|
function resolveRuntimeWorkspaceLayout(workspaceDir) {
|
|
1180
|
-
const root =
|
|
1181
|
-
const rigRoot =
|
|
1182
|
-
const logsDir =
|
|
1183
|
-
const stateDir =
|
|
1184
|
-
const runtimeDir =
|
|
1185
|
-
const binDir =
|
|
1239
|
+
const root = resolve10(workspaceDir);
|
|
1240
|
+
const rigRoot = resolve10(root, ".rig");
|
|
1241
|
+
const logsDir = resolve10(rigRoot, "logs");
|
|
1242
|
+
const stateDir = resolve10(rigRoot, "state");
|
|
1243
|
+
const runtimeDir = resolve10(rigRoot, "runtime");
|
|
1244
|
+
const binDir = resolve10(rigRoot, "bin");
|
|
1186
1245
|
return {
|
|
1187
1246
|
workspaceDir: root,
|
|
1188
1247
|
rigRoot,
|
|
1189
1248
|
stateDir,
|
|
1190
1249
|
logsDir,
|
|
1191
|
-
artifactsRoot:
|
|
1250
|
+
artifactsRoot: resolve10(root, RIG_ARTIFACTS_DIRNAME),
|
|
1192
1251
|
runtimeDir,
|
|
1193
|
-
homeDir:
|
|
1194
|
-
tmpDir:
|
|
1195
|
-
cacheDir:
|
|
1196
|
-
sessionDir:
|
|
1252
|
+
homeDir: resolve10(rigRoot, "home"),
|
|
1253
|
+
tmpDir: resolve10(rigRoot, "tmp"),
|
|
1254
|
+
cacheDir: resolve10(rigRoot, "cache"),
|
|
1255
|
+
sessionDir: resolve10(rigRoot, "session"),
|
|
1197
1256
|
binDir,
|
|
1198
|
-
distDir:
|
|
1199
|
-
pluginBinDir:
|
|
1200
|
-
contextPath:
|
|
1201
|
-
controlPlaneEventsFile:
|
|
1257
|
+
distDir: resolve10(rigRoot, "dist"),
|
|
1258
|
+
pluginBinDir: resolve10(binDir, "plugins"),
|
|
1259
|
+
contextPath: resolve10(rigRoot, "runtime-context.json"),
|
|
1260
|
+
controlPlaneEventsFile: resolve10(logsDir, "control-plane.events.jsonl")
|
|
1202
1261
|
};
|
|
1203
1262
|
}
|
|
1204
1263
|
function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
|
|
@@ -1206,14 +1265,14 @@ function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
|
|
|
1206
1265
|
if (!explicit) {
|
|
1207
1266
|
throw new Error("No active runtime workspace. Set RIG_TASK_WORKSPACE or provision a task runtime first.");
|
|
1208
1267
|
}
|
|
1209
|
-
return
|
|
1268
|
+
return resolve10(explicit);
|
|
1210
1269
|
}
|
|
1211
1270
|
function resolveRigLayout(projectRoot) {
|
|
1212
1271
|
const monorepoRoot = resolveMonorepoRoot(projectRoot);
|
|
1213
|
-
const definitionRoot =
|
|
1272
|
+
const definitionRoot = resolve10(projectRoot, RIG_DEFINITION_DIRNAME);
|
|
1214
1273
|
const runtimeWorkspaceRoot = resolveActiveRuntimeWorkspaceRoot(monorepoRoot);
|
|
1215
1274
|
const runtimeLayout = resolveRuntimeWorkspaceLayout(runtimeWorkspaceRoot);
|
|
1216
|
-
const policyDir =
|
|
1275
|
+
const policyDir = resolve10(definitionRoot, "policy");
|
|
1217
1276
|
return {
|
|
1218
1277
|
projectRoot,
|
|
1219
1278
|
monorepoRoot,
|
|
@@ -1221,48 +1280,48 @@ function resolveRigLayout(projectRoot) {
|
|
|
1221
1280
|
runtimeWorkspaceRoot,
|
|
1222
1281
|
stateRoot: runtimeLayout.rigRoot,
|
|
1223
1282
|
artifactsRoot: runtimeLayout.artifactsRoot,
|
|
1224
|
-
configPath:
|
|
1225
|
-
taskConfigPath:
|
|
1283
|
+
configPath: resolve10(definitionRoot, "config.sh"),
|
|
1284
|
+
taskConfigPath: resolve10(runtimeWorkspaceRoot, ".rig", "task-config.json"),
|
|
1226
1285
|
policyDir,
|
|
1227
|
-
policyFile:
|
|
1228
|
-
pluginsDir:
|
|
1229
|
-
hooksDir:
|
|
1230
|
-
toolsDir:
|
|
1231
|
-
templatesDir:
|
|
1232
|
-
validationDir:
|
|
1286
|
+
policyFile: resolve10(policyDir, "policy.json"),
|
|
1287
|
+
pluginsDir: resolve10(definitionRoot, "plugins"),
|
|
1288
|
+
hooksDir: resolve10(definitionRoot, "hooks"),
|
|
1289
|
+
toolsDir: resolve10(definitionRoot, "tools"),
|
|
1290
|
+
templatesDir: resolve10(definitionRoot, "templates"),
|
|
1291
|
+
validationDir: resolve10(definitionRoot, "validation"),
|
|
1233
1292
|
stateDir: runtimeLayout.stateDir,
|
|
1234
1293
|
logsDir: runtimeLayout.logsDir,
|
|
1235
|
-
notificationsDir:
|
|
1294
|
+
notificationsDir: resolve10(definitionRoot, "notifications"),
|
|
1236
1295
|
runtimeDir: runtimeLayout.runtimeDir,
|
|
1237
1296
|
distDir: runtimeLayout.distDir,
|
|
1238
1297
|
binDir: runtimeLayout.binDir,
|
|
1239
1298
|
pluginBinDir: runtimeLayout.pluginBinDir,
|
|
1240
|
-
keybindingsPath:
|
|
1299
|
+
keybindingsPath: resolve10(definitionRoot, "keybindings.json"),
|
|
1241
1300
|
controlPlaneEventsFile: runtimeLayout.controlPlaneEventsFile
|
|
1242
1301
|
};
|
|
1243
1302
|
}
|
|
1244
1303
|
|
|
1245
1304
|
// packages/runtime/src/control-plane/native/runtime-native.ts
|
|
1246
1305
|
import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
|
|
1247
|
-
import { copyFileSync, existsSync as
|
|
1306
|
+
import { copyFileSync, existsSync as existsSync10, mkdirSync as mkdirSync5, renameSync, rmSync as rmSync2, statSync as statSync2 } from "fs";
|
|
1248
1307
|
import { tmpdir as tmpdir4 } from "os";
|
|
1249
|
-
import { dirname as
|
|
1250
|
-
var sharedNativeRuntimeOutputDir =
|
|
1251
|
-
var sharedNativeRuntimeOutputPath =
|
|
1308
|
+
import { dirname as dirname8, resolve as resolve11 } from "path";
|
|
1309
|
+
var sharedNativeRuntimeOutputDir = resolve11(tmpdir4(), "rig-native");
|
|
1310
|
+
var sharedNativeRuntimeOutputPath = resolve11(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
|
|
1252
1311
|
var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
|
|
1253
1312
|
var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
|
|
1254
1313
|
async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOutputPath, options = {}) {
|
|
1255
1314
|
if (await buildNativeRuntimeLibrary(outputPath, options)) {
|
|
1256
1315
|
return outputPath;
|
|
1257
1316
|
}
|
|
1258
|
-
return !options.force &&
|
|
1317
|
+
return !options.force && existsSync10(outputPath) ? outputPath : null;
|
|
1259
1318
|
}
|
|
1260
1319
|
async function loadNativeRuntimeLibrary() {
|
|
1261
1320
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
1262
1321
|
return null;
|
|
1263
1322
|
}
|
|
1264
1323
|
for (const candidate of nativeRuntimeLibraryCandidates()) {
|
|
1265
|
-
if (!candidate || !
|
|
1324
|
+
if (!candidate || !existsSync10(candidate)) {
|
|
1266
1325
|
continue;
|
|
1267
1326
|
}
|
|
1268
1327
|
const loaded = tryDlopenNativeRuntimeLibrary(candidate);
|
|
@@ -1278,12 +1337,12 @@ async function loadNativeRuntimeLibrary() {
|
|
|
1278
1337
|
}
|
|
1279
1338
|
function nativePackageLibraryCandidates(fromDir, names) {
|
|
1280
1339
|
const candidates = [];
|
|
1281
|
-
let cursor =
|
|
1340
|
+
let cursor = resolve11(fromDir);
|
|
1282
1341
|
for (let index = 0;index < 8; index += 1) {
|
|
1283
1342
|
for (const name of names) {
|
|
1284
|
-
candidates.push(
|
|
1343
|
+
candidates.push(resolve11(cursor, "native", `${process.platform}-${process.arch}`, name), resolve11(cursor, "native", `${process.platform}-${process.arch}`, "lib", name), resolve11(cursor, "native", name), resolve11(cursor, "native", "lib", name));
|
|
1285
1344
|
}
|
|
1286
|
-
const parent =
|
|
1345
|
+
const parent = dirname8(cursor);
|
|
1287
1346
|
if (parent === cursor)
|
|
1288
1347
|
break;
|
|
1289
1348
|
cursor = parent;
|
|
@@ -1292,27 +1351,27 @@ function nativePackageLibraryCandidates(fromDir, names) {
|
|
|
1292
1351
|
}
|
|
1293
1352
|
function nativeRuntimeLibraryCandidates() {
|
|
1294
1353
|
const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
|
|
1295
|
-
const execDir = process.execPath?.trim() ?
|
|
1354
|
+
const execDir = process.execPath?.trim() ? dirname8(process.execPath.trim()) : "";
|
|
1296
1355
|
const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
|
|
1297
1356
|
return [...new Set([
|
|
1298
1357
|
explicit,
|
|
1299
1358
|
...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
|
|
1300
|
-
execDir ?
|
|
1301
|
-
execDir ?
|
|
1302
|
-
execDir ?
|
|
1303
|
-
execDir ?
|
|
1304
|
-
execDir ?
|
|
1305
|
-
execDir ?
|
|
1359
|
+
execDir ? resolve11(execDir, colocatedNativeRuntimeFileName) : "",
|
|
1360
|
+
execDir ? resolve11(execDir, platformSpecific) : "",
|
|
1361
|
+
execDir ? resolve11(execDir, "..", colocatedNativeRuntimeFileName) : "",
|
|
1362
|
+
execDir ? resolve11(execDir, "..", platformSpecific) : "",
|
|
1363
|
+
execDir ? resolve11(execDir, "lib", colocatedNativeRuntimeFileName) : "",
|
|
1364
|
+
execDir ? resolve11(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
|
|
1306
1365
|
sharedNativeRuntimeOutputPath
|
|
1307
1366
|
].filter(Boolean))];
|
|
1308
1367
|
}
|
|
1309
1368
|
function resolveNativeRuntimeSourcePath() {
|
|
1310
1369
|
const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
|
|
1311
|
-
if (explicit &&
|
|
1370
|
+
if (explicit && existsSync10(explicit)) {
|
|
1312
1371
|
return explicit;
|
|
1313
1372
|
}
|
|
1314
|
-
const bundled =
|
|
1315
|
-
return
|
|
1373
|
+
const bundled = resolve11(import.meta.dir, "../../../native/snapshot.zig");
|
|
1374
|
+
return existsSync10(bundled) ? bundled : null;
|
|
1316
1375
|
}
|
|
1317
1376
|
async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
1318
1377
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
@@ -1325,8 +1384,8 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
1325
1384
|
}
|
|
1326
1385
|
const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
1327
1386
|
try {
|
|
1328
|
-
|
|
1329
|
-
const needsBuild = options.force === true || !
|
|
1387
|
+
mkdirSync5(dirname8(outputPath), { recursive: true });
|
|
1388
|
+
const needsBuild = options.force === true || !existsSync10(outputPath) || statSync2(sourcePath).mtimeMs > statSync2(outputPath).mtimeMs;
|
|
1330
1389
|
if (!needsBuild) {
|
|
1331
1390
|
return true;
|
|
1332
1391
|
}
|
|
@@ -1344,7 +1403,7 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
1344
1403
|
stderr: "pipe"
|
|
1345
1404
|
});
|
|
1346
1405
|
const exitCode = await build.exited;
|
|
1347
|
-
if (exitCode !== 0 || !
|
|
1406
|
+
if (exitCode !== 0 || !existsSync10(tempOutputPath)) {
|
|
1348
1407
|
rmSync2(tempOutputPath, { force: true });
|
|
1349
1408
|
return false;
|
|
1350
1409
|
}
|
|
@@ -1431,11 +1490,11 @@ function runCapture(command, cwd, env) {
|
|
|
1431
1490
|
};
|
|
1432
1491
|
}
|
|
1433
1492
|
function readJsonFile(path, fallback) {
|
|
1434
|
-
if (!
|
|
1493
|
+
if (!existsSync11(path)) {
|
|
1435
1494
|
return fallback;
|
|
1436
1495
|
}
|
|
1437
1496
|
try {
|
|
1438
|
-
return JSON.parse(
|
|
1497
|
+
return JSON.parse(readFileSync7(path, "utf-8"));
|
|
1439
1498
|
} catch {
|
|
1440
1499
|
return fallback;
|
|
1441
1500
|
}
|
|
@@ -1446,31 +1505,31 @@ function nowIso() {
|
|
|
1446
1505
|
function resolveHarnessPaths(projectRoot) {
|
|
1447
1506
|
const hasRuntimeWorkspace = Boolean(process.env.RIG_TASK_WORKSPACE?.trim());
|
|
1448
1507
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
1449
|
-
const harnessRoot =
|
|
1450
|
-
const stateRoot =
|
|
1508
|
+
const harnessRoot = resolve12(projectRoot, "rig");
|
|
1509
|
+
const stateRoot = resolve12(projectRoot, ".rig");
|
|
1451
1510
|
const layout = hasRuntimeWorkspace ? resolveRigLayout(projectRoot) : null;
|
|
1452
|
-
const stateDir = layout?.stateDir ??
|
|
1453
|
-
const logsDir = layout?.logsDir ??
|
|
1454
|
-
const artifactsDir = layout?.artifactsRoot ??
|
|
1455
|
-
const taskConfigPath = layout?.taskConfigPath ??
|
|
1456
|
-
const binDir = layout?.binDir ??
|
|
1511
|
+
const stateDir = layout?.stateDir ?? resolve12(stateRoot, "state");
|
|
1512
|
+
const logsDir = layout?.logsDir ?? resolve12(stateRoot, "logs");
|
|
1513
|
+
const artifactsDir = layout?.artifactsRoot ?? resolve12(monorepoRoot, "artifacts");
|
|
1514
|
+
const taskConfigPath = layout?.taskConfigPath ?? resolve12(monorepoRoot, ".rig", "task-config.json");
|
|
1515
|
+
const binDir = layout?.binDir ?? resolve12(stateRoot, "bin");
|
|
1457
1516
|
return {
|
|
1458
1517
|
harnessRoot,
|
|
1459
1518
|
stateDir: process.env.RIG_STATE_DIR || stateDir,
|
|
1460
1519
|
artifactsDir,
|
|
1461
1520
|
logsDir: process.env.RIG_LOGS_DIR || logsDir,
|
|
1462
1521
|
binDir,
|
|
1463
|
-
hooksDir:
|
|
1464
|
-
validationDir:
|
|
1522
|
+
hooksDir: resolve12(harnessRoot, "hooks"),
|
|
1523
|
+
validationDir: resolve12(harnessRoot, "validation"),
|
|
1465
1524
|
taskConfigPath,
|
|
1466
|
-
sessionPath: process.env.RIG_SESSION_FILE ||
|
|
1525
|
+
sessionPath: process.env.RIG_SESSION_FILE || resolve12(stateRoot, "session", "session.json"),
|
|
1467
1526
|
monorepoRoot,
|
|
1468
|
-
tsApiTestsDir: process.env.TS_API_TESTS_DIR ||
|
|
1469
|
-
taskRepoCommitsPath:
|
|
1470
|
-
baseRepoPinsPath:
|
|
1471
|
-
failedApproachesPath:
|
|
1472
|
-
agentProfilePath:
|
|
1473
|
-
reviewProfilePath:
|
|
1527
|
+
tsApiTestsDir: process.env.TS_API_TESTS_DIR || resolve12(monorepoRoot, "TSAPITests"),
|
|
1528
|
+
taskRepoCommitsPath: resolve12(stateDir, "task-repo-commits.json"),
|
|
1529
|
+
baseRepoPinsPath: resolve12(stateDir, "base-repo-pins.json"),
|
|
1530
|
+
failedApproachesPath: resolve12(stateDir, "failed_approaches.md"),
|
|
1531
|
+
agentProfilePath: resolve12(stateDir, "agent-profile.json"),
|
|
1532
|
+
reviewProfilePath: resolve12(stateDir, "review-profile.json")
|
|
1474
1533
|
};
|
|
1475
1534
|
}
|
|
1476
1535
|
// packages/runtime/src/control-plane/state-sync/reconcile.ts
|
|
@@ -1525,25 +1584,25 @@ function lookupTask(projectRoot, input) {
|
|
|
1525
1584
|
function artifactDirForId(projectRoot, id) {
|
|
1526
1585
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
1527
1586
|
if (workspaceDir) {
|
|
1528
|
-
const worktreeArtifacts =
|
|
1529
|
-
if (
|
|
1587
|
+
const worktreeArtifacts = resolve13(workspaceDir, "artifacts", id);
|
|
1588
|
+
if (existsSync12(worktreeArtifacts) || existsSync12(resolve13(workspaceDir, "artifacts"))) {
|
|
1530
1589
|
return worktreeArtifacts;
|
|
1531
1590
|
}
|
|
1532
1591
|
}
|
|
1533
1592
|
try {
|
|
1534
1593
|
const paths = resolveHarnessPaths(projectRoot);
|
|
1535
|
-
return
|
|
1594
|
+
return resolve13(paths.artifactsDir, id);
|
|
1536
1595
|
} catch {
|
|
1537
|
-
return
|
|
1596
|
+
return resolve13(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
1538
1597
|
}
|
|
1539
1598
|
}
|
|
1540
1599
|
function resolveTaskConfigPath(projectRoot) {
|
|
1541
1600
|
const paths = resolveHarnessPaths(projectRoot);
|
|
1542
|
-
if (
|
|
1601
|
+
if (existsSync12(paths.taskConfigPath)) {
|
|
1543
1602
|
return paths.taskConfigPath;
|
|
1544
1603
|
}
|
|
1545
1604
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
1546
|
-
if (
|
|
1605
|
+
if (existsSync12(candidate)) {
|
|
1547
1606
|
return candidate;
|
|
1548
1607
|
}
|
|
1549
1608
|
}
|
|
@@ -1551,7 +1610,7 @@ function resolveTaskConfigPath(projectRoot) {
|
|
|
1551
1610
|
}
|
|
1552
1611
|
function findSourceTaskConfigPath(projectRoot) {
|
|
1553
1612
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
1554
|
-
if (
|
|
1613
|
+
if (existsSync12(candidate)) {
|
|
1555
1614
|
return candidate;
|
|
1556
1615
|
}
|
|
1557
1616
|
}
|
|
@@ -1564,7 +1623,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
1564
1623
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
1565
1624
|
if (sourcePath && synced.updated) {
|
|
1566
1625
|
try {
|
|
1567
|
-
|
|
1626
|
+
writeFileSync6(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
1568
1627
|
`, "utf-8");
|
|
1569
1628
|
} catch {}
|
|
1570
1629
|
}
|
|
@@ -1616,12 +1675,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
1616
1675
|
return !candidate.role;
|
|
1617
1676
|
}
|
|
1618
1677
|
function readSourceIssueRecords(projectRoot) {
|
|
1619
|
-
const issuesPath =
|
|
1620
|
-
if (!
|
|
1678
|
+
const issuesPath = resolve13(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
1679
|
+
if (!existsSync12(issuesPath)) {
|
|
1621
1680
|
return [];
|
|
1622
1681
|
}
|
|
1623
1682
|
const records = [];
|
|
1624
|
-
for (const line of
|
|
1683
|
+
for (const line of readFileSync8(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
1625
1684
|
const trimmed = line.trim();
|
|
1626
1685
|
if (!trimmed) {
|
|
1627
1686
|
continue;
|
|
@@ -1677,19 +1736,19 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
1677
1736
|
if (!sourcePath) {
|
|
1678
1737
|
return {};
|
|
1679
1738
|
}
|
|
1680
|
-
const directory =
|
|
1681
|
-
if (!
|
|
1739
|
+
const directory = resolve13(projectRoot, sourcePath);
|
|
1740
|
+
if (!existsSync12(directory)) {
|
|
1682
1741
|
return {};
|
|
1683
1742
|
}
|
|
1684
1743
|
const config = {};
|
|
1685
1744
|
for (const name of readdirSync3(directory)) {
|
|
1686
1745
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
1687
1746
|
continue;
|
|
1688
|
-
const file =
|
|
1747
|
+
const file = resolve13(directory, name);
|
|
1689
1748
|
try {
|
|
1690
1749
|
if (!statSync3(file).isFile())
|
|
1691
1750
|
continue;
|
|
1692
|
-
const raw = JSON.parse(
|
|
1751
|
+
const raw = JSON.parse(readFileSync8(file, "utf8"));
|
|
1693
1752
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
1694
1753
|
continue;
|
|
1695
1754
|
const record = raw;
|
|
@@ -1731,10 +1790,10 @@ function firstStringList2(...candidates) {
|
|
|
1731
1790
|
return [];
|
|
1732
1791
|
}
|
|
1733
1792
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
1734
|
-
const jsonPath =
|
|
1735
|
-
if (
|
|
1793
|
+
const jsonPath = resolve13(projectRoot, "rig.config.json");
|
|
1794
|
+
if (existsSync12(jsonPath)) {
|
|
1736
1795
|
try {
|
|
1737
|
-
const parsed = JSON.parse(
|
|
1796
|
+
const parsed = JSON.parse(readFileSync8(jsonPath, "utf8"));
|
|
1738
1797
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1739
1798
|
const taskSource = parsed.taskSource;
|
|
1740
1799
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -1746,12 +1805,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
1746
1805
|
return null;
|
|
1747
1806
|
}
|
|
1748
1807
|
}
|
|
1749
|
-
const tsPath =
|
|
1750
|
-
if (!
|
|
1808
|
+
const tsPath = resolve13(projectRoot, "rig.config.ts");
|
|
1809
|
+
if (!existsSync12(tsPath)) {
|
|
1751
1810
|
return null;
|
|
1752
1811
|
}
|
|
1753
1812
|
try {
|
|
1754
|
-
const source =
|
|
1813
|
+
const source = readFileSync8(tsPath, "utf8");
|
|
1755
1814
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
1756
1815
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
1757
1816
|
if (kind !== "files") {
|
|
@@ -1765,9 +1824,9 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
1765
1824
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
1766
1825
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
1767
1826
|
return [
|
|
1768
|
-
runtimeContext?.monorepoMainRoot ?
|
|
1769
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
1770
|
-
|
|
1827
|
+
runtimeContext?.monorepoMainRoot ? resolve13(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
1828
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve13(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
1829
|
+
resolve13(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
1771
1830
|
].filter(Boolean);
|
|
1772
1831
|
}
|
|
1773
1832
|
|
|
@@ -3065,12 +3124,12 @@ var TASK_ARTIFACT_STAGE_FALLBACK = new Set([
|
|
|
3065
3124
|
"validation-summary.json"
|
|
3066
3125
|
]);
|
|
3067
3126
|
function readPrMetadata(projectRoot, taskId) {
|
|
3068
|
-
const path =
|
|
3069
|
-
if (!
|
|
3127
|
+
const path = resolve14(artifactDirForId(projectRoot, taskId), "pr-state.json");
|
|
3128
|
+
if (!existsSync13(path)) {
|
|
3070
3129
|
return [];
|
|
3071
3130
|
}
|
|
3072
3131
|
try {
|
|
3073
|
-
const parsed = JSON.parse(
|
|
3132
|
+
const parsed = JSON.parse(readFileSync9(path, "utf-8"));
|
|
3074
3133
|
if (!parsed || typeof parsed !== "object") {
|
|
3075
3134
|
return [];
|
|
3076
3135
|
}
|
|
@@ -3096,11 +3155,11 @@ async function verifyTask(options) {
|
|
|
3096
3155
|
const taskId = options.taskId;
|
|
3097
3156
|
const normalizedTaskId = lookupTask(options.projectRoot, taskId);
|
|
3098
3157
|
const artifactDir = artifactDirForId(options.projectRoot, taskId);
|
|
3099
|
-
|
|
3100
|
-
const validationSummaryPath =
|
|
3101
|
-
const reviewFeedbackPath =
|
|
3102
|
-
const reviewStatePath =
|
|
3103
|
-
const greptileRawPath =
|
|
3158
|
+
mkdirSync7(artifactDir, { recursive: true });
|
|
3159
|
+
const validationSummaryPath = resolve15(artifactDir, "validation-summary.json");
|
|
3160
|
+
const reviewFeedbackPath = resolve15(artifactDir, "review-feedback.md");
|
|
3161
|
+
const reviewStatePath = resolve15(artifactDir, "review-state.json");
|
|
3162
|
+
const greptileRawPath = resolve15(artifactDir, "review-greptile-raw.json");
|
|
3104
3163
|
const prStates = readPrMetadata(options.projectRoot, taskId);
|
|
3105
3164
|
const prState = prStates[0] || null;
|
|
3106
3165
|
const localReasons = [];
|
|
@@ -3112,7 +3171,7 @@ async function verifyTask(options) {
|
|
|
3112
3171
|
if (!normalizedTaskId && !await hasConfiguredSourceTask(options.projectRoot, taskId)) {
|
|
3113
3172
|
localReasons.push(`[Task Config] Unknown task id '${taskId}' in task-config or configured task source.`);
|
|
3114
3173
|
}
|
|
3115
|
-
if (!
|
|
3174
|
+
if (!existsSync14(validationSummaryPath)) {
|
|
3116
3175
|
localReasons.push(`[Artifact Quality] validation-summary.json not found at ${validationSummaryPath}.`);
|
|
3117
3176
|
} else {
|
|
3118
3177
|
const summary = await parseValidationSummary(validationSummaryPath);
|
|
@@ -3121,13 +3180,13 @@ async function verifyTask(options) {
|
|
|
3121
3180
|
}
|
|
3122
3181
|
}
|
|
3123
3182
|
for (const file of ["task-result.json", "decision-log.md", "next-actions.md", "changed-files.txt"]) {
|
|
3124
|
-
const requiredPath =
|
|
3125
|
-
if (!
|
|
3183
|
+
const requiredPath = resolve15(artifactDir, file);
|
|
3184
|
+
if (!existsSync14(requiredPath)) {
|
|
3126
3185
|
localReasons.push(`[Artifact Quality] Missing required artifact file: ${requiredPath}`);
|
|
3127
3186
|
}
|
|
3128
3187
|
}
|
|
3129
|
-
const taskResultPath =
|
|
3130
|
-
if (
|
|
3188
|
+
const taskResultPath = resolve15(artifactDir, "task-result.json");
|
|
3189
|
+
if (existsSync14(taskResultPath)) {
|
|
3131
3190
|
const taskResult = await readJsonFile2(taskResultPath);
|
|
3132
3191
|
const artifactStatus = typeof taskResult?.status === "string" ? taskResult.status.trim().toLowerCase() : "";
|
|
3133
3192
|
if (artifactStatus === "partial") {
|
|
@@ -3140,8 +3199,8 @@ async function verifyTask(options) {
|
|
|
3140
3199
|
localReasons.push("[Artifact Quality] task-result.json next actions indicate remaining implementation scope.");
|
|
3141
3200
|
}
|
|
3142
3201
|
}
|
|
3143
|
-
const nextActionsPath =
|
|
3144
|
-
if (
|
|
3202
|
+
const nextActionsPath = resolve15(artifactDir, "next-actions.md");
|
|
3203
|
+
if (existsSync14(nextActionsPath)) {
|
|
3145
3204
|
const nextActionsContent = await Bun.file(nextActionsPath).text();
|
|
3146
3205
|
if (nextActionsContent.includes("TODO: Replace this scaffold") || nextActionsContent.includes("bd-<downstream-task-id>")) {
|
|
3147
3206
|
localReasons.push("[Artifact Quality] next-actions.md still contains scaffold placeholder text. Replace with real recommendations.");
|
|
@@ -3172,7 +3231,7 @@ async function verifyTask(options) {
|
|
|
3172
3231
|
aiReasons.push(`[AI Review] Required mode needs a completed Greptile approval; current verdict is ${ai.verdict}.`);
|
|
3173
3232
|
}
|
|
3174
3233
|
if (persistArtifacts && ai.rawResponse) {
|
|
3175
|
-
|
|
3234
|
+
writeFileSync8(greptileRawPath, `${ai.rawResponse}
|
|
3176
3235
|
`, "utf-8");
|
|
3177
3236
|
}
|
|
3178
3237
|
} else if (!options.skipAiReview && reviewMode === "off") {
|
|
@@ -3415,7 +3474,7 @@ function evaluateSourceCloseoutChecks(prState, prLabel) {
|
|
|
3415
3474
|
if (!Array.isArray(checks) || checks.length === 0) {
|
|
3416
3475
|
return [`[Source Issue] PR ${prLabel} must have green check evidence before completion.`];
|
|
3417
3476
|
}
|
|
3418
|
-
const ciGate = evaluatePullRequestCiChecks(checks, "PR", 0);
|
|
3477
|
+
const ciGate = evaluatePullRequestCiChecks(checks, "PR", 0, { mergeStateStatus: prState.mergeStateStatus });
|
|
3419
3478
|
if (ciGate.verdict === "APPROVE") {
|
|
3420
3479
|
return [];
|
|
3421
3480
|
}
|
|
@@ -3511,7 +3570,7 @@ function isAcceptedValidationSummary(summary) {
|
|
|
3511
3570
|
return summary.status === "skipped" && summary.total === 0 && summary.failed === 0;
|
|
3512
3571
|
}
|
|
3513
3572
|
async function loadReviewMode(reviewProfilePath, fallback) {
|
|
3514
|
-
const parsed =
|
|
3573
|
+
const parsed = existsSync14(reviewProfilePath) ? await readJsonFile2(reviewProfilePath) : null;
|
|
3515
3574
|
const mode = parsed?.mode;
|
|
3516
3575
|
if (mode === "off" || mode === "advisory" || mode === "required") {
|
|
3517
3576
|
return mode;
|
|
@@ -3522,7 +3581,7 @@ async function loadReviewMode(reviewProfilePath, fallback) {
|
|
|
3522
3581
|
return "advisory";
|
|
3523
3582
|
}
|
|
3524
3583
|
async function loadReviewProvider(reviewProfilePath, fallback) {
|
|
3525
|
-
const parsed =
|
|
3584
|
+
const parsed = existsSync14(reviewProfilePath) ? await readJsonFile2(reviewProfilePath) : null;
|
|
3526
3585
|
const provider = parsed?.provider;
|
|
3527
3586
|
if (typeof provider === "string" && provider.trim().length > 0) {
|
|
3528
3587
|
return provider;
|
|
@@ -3681,7 +3740,7 @@ function writeFeedbackFile(options) {
|
|
|
3681
3740
|
if (options.aiRawFeedback) {
|
|
3682
3741
|
lines.push("## Raw Reviewer Feedback", "", "```text", options.aiRawFeedback, "```", "");
|
|
3683
3742
|
}
|
|
3684
|
-
|
|
3743
|
+
writeFileSync8(options.output, `${lines.join(`
|
|
3685
3744
|
`)}
|
|
3686
3745
|
`, "utf-8");
|
|
3687
3746
|
}
|
|
@@ -3698,7 +3757,7 @@ function writeReviewStateFile(options) {
|
|
|
3698
3757
|
ai_warnings: options.aiWarnings,
|
|
3699
3758
|
updated_at: nowIso()
|
|
3700
3759
|
};
|
|
3701
|
-
|
|
3760
|
+
writeFileSync8(options.output, `${JSON.stringify(payload, null, 2)}
|
|
3702
3761
|
`, "utf-8");
|
|
3703
3762
|
}
|
|
3704
3763
|
async function runGreptileReviewForPr(options) {
|
|
@@ -3779,7 +3838,7 @@ async function runGreptileReviewForPr(options) {
|
|
|
3779
3838
|
}
|
|
3780
3839
|
await Bun.sleep(options.pollIntervalMs);
|
|
3781
3840
|
}
|
|
3782
|
-
const ciGate = evaluatePullRequestCiChecks(githubCheckRollup, repoName, prNumber);
|
|
3841
|
+
const ciGate = evaluatePullRequestCiChecks(githubCheckRollup, repoName, prNumber, { mergeStateStatus: options.prState.mergeStateStatus });
|
|
3783
3842
|
if (ciGate.verdict !== "APPROVE") {
|
|
3784
3843
|
return {
|
|
3785
3844
|
verdict: ciGate.verdict,
|
|
@@ -4037,7 +4096,7 @@ async function runGithubGreptileFallbackReviewForPr(options) {
|
|
|
4037
4096
|
}
|
|
4038
4097
|
await Bun.sleep(options.pollIntervalMs);
|
|
4039
4098
|
}
|
|
4040
|
-
const ciGate = evaluatePullRequestCiChecks(checkRollup, repoName, prNumber);
|
|
4099
|
+
const ciGate = evaluatePullRequestCiChecks(checkRollup, repoName, prNumber, { mergeStateStatus: options.prState.mergeStateStatus });
|
|
4041
4100
|
if (ciGate.verdict !== "APPROVE") {
|
|
4042
4101
|
return {
|
|
4043
4102
|
verdict: ciGate.verdict,
|
|
@@ -4392,19 +4451,31 @@ function loadGithubPullRequestCheckRollup(projectRoot, repoName, prNumber) {
|
|
|
4392
4451
|
]);
|
|
4393
4452
|
return response.statusCheckRollup || [];
|
|
4394
4453
|
}
|
|
4395
|
-
function evaluatePullRequestCiChecks(checks, repoName, prNumber) {
|
|
4396
|
-
const
|
|
4397
|
-
const label = (check.name || check.context || "").toLowerCase();
|
|
4398
|
-
return label.length > 0 && !label.includes("greptile");
|
|
4399
|
-
});
|
|
4400
|
-
const pending = nonGreptileChecks.filter((check) => {
|
|
4454
|
+
function evaluatePullRequestCiChecks(checks, repoName, prNumber, options = {}) {
|
|
4455
|
+
const isPendingCheck2 = (check) => {
|
|
4401
4456
|
if ((check.__typename || "") === "CheckRun") {
|
|
4402
4457
|
return (check.status || "").toUpperCase() !== "COMPLETED";
|
|
4403
4458
|
}
|
|
4404
4459
|
const state = (check.state || check.status || "").toUpperCase();
|
|
4405
4460
|
return state === "PENDING" || state === "EXPECTED" || state === "QUEUED" || state === "IN_PROGRESS";
|
|
4461
|
+
};
|
|
4462
|
+
const pendingGreptile = checks.filter((check) => {
|
|
4463
|
+
const label = (check.name || check.context || "").toLowerCase();
|
|
4464
|
+
return label.includes("greptile") && isPendingCheck2(check);
|
|
4465
|
+
});
|
|
4466
|
+
if (pendingGreptile.length > 0) {
|
|
4467
|
+
return {
|
|
4468
|
+
verdict: "SKIP",
|
|
4469
|
+
reasons: pendingGreptile.map((check) => `[CI] ${repoName}#${prNumber} mandatory Greptile check is still pending: ${check.name || check.context || "unknown"}.`)
|
|
4470
|
+
};
|
|
4471
|
+
}
|
|
4472
|
+
const nonGreptileChecks = checks.filter((check) => {
|
|
4473
|
+
const label = (check.name || check.context || "").toLowerCase();
|
|
4474
|
+
return label.length > 0 && !label.includes("greptile");
|
|
4406
4475
|
});
|
|
4407
|
-
|
|
4476
|
+
const pending = nonGreptileChecks.filter(isPendingCheck2);
|
|
4477
|
+
const mergeClean = (options.mergeStateStatus || "").toUpperCase() === "CLEAN";
|
|
4478
|
+
if (pending.length > 0 && !mergeClean) {
|
|
4408
4479
|
return {
|
|
4409
4480
|
verdict: "SKIP",
|
|
4410
4481
|
reasons: pending.map((check) => `[CI] ${repoName}#${prNumber} check is still pending: ${check.name || check.context || "unknown"}.`)
|
|
@@ -4488,7 +4559,7 @@ function filterActionableGithubGreptileThreads(threads) {
|
|
|
4488
4559
|
}
|
|
4489
4560
|
function resolvePrRepoRoot(projectRoot, prState) {
|
|
4490
4561
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
4491
|
-
if (prState.target === "monorepo" && runtimeWorkspace &&
|
|
4562
|
+
if (prState.target === "monorepo" && runtimeWorkspace && existsSync14(resolve15(runtimeWorkspace, ".git"))) {
|
|
4492
4563
|
return runtimeWorkspace;
|
|
4493
4564
|
}
|
|
4494
4565
|
const paths = resolveHarnessPaths(projectRoot);
|
|
@@ -4538,5 +4609,6 @@ export {
|
|
|
4538
4609
|
verifyTask,
|
|
4539
4610
|
pickRelevantCodeReview,
|
|
4540
4611
|
filterActionableGreptileComments,
|
|
4612
|
+
evaluatePullRequestCiChecks,
|
|
4541
4613
|
__testOnly
|
|
4542
4614
|
};
|