@h-rig/runtime 0.0.6-alpha.32 → 0.0.6-alpha.34
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 +12 -0
- package/dist/bin/rig-agent.js +13 -15
- package/dist/src/control-plane/agent-wrapper.js +12 -0
- package/dist/src/control-plane/harness-main.js +1354 -1399
- package/dist/src/control-plane/hooks/completion-verification.js +510 -511
- package/dist/src/control-plane/hooks/inject-context.js +333 -333
- package/dist/src/control-plane/hooks/submodule-branch.js +1600 -1600
- package/dist/src/control-plane/hooks/task-runtime-start.js +1600 -1600
- package/dist/src/control-plane/native/git-ops.js +79 -152
- package/dist/src/control-plane/native/harness-cli.js +1354 -1399
- package/dist/src/control-plane/native/repo-ops.js +50 -50
- package/dist/src/control-plane/native/task-ops.js +1467 -1503
- package/dist/src/control-plane/native/verifier.js +34 -34
- package/dist/src/control-plane/pi-sessiond/bin.js +65 -2
- package/dist/src/control-plane/pi-sessiond/launcher.js +12 -0
- package/dist/src/control-plane/pi-sessiond/server.js +65 -2
- package/dist/src/control-plane/pi-sessiond/session-service.js +65 -2
- package/package.json +8 -8
|
@@ -1361,16 +1361,297 @@ function readBuildConfig() {
|
|
|
1361
1361
|
}
|
|
1362
1362
|
}
|
|
1363
1363
|
|
|
1364
|
-
// packages/runtime/src/control-plane/
|
|
1364
|
+
// packages/runtime/src/control-plane/native/git-native.ts
|
|
1365
|
+
import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync5, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
1365
1366
|
import { tmpdir as tmpdir2 } from "os";
|
|
1366
|
-
import {
|
|
1367
|
-
|
|
1368
|
-
var
|
|
1369
|
-
|
|
1367
|
+
import { dirname as dirname4, isAbsolute, resolve as resolve7 } from "path";
|
|
1368
|
+
import { createHash } from "crypto";
|
|
1369
|
+
var sharedGitNativeOutputDir = resolve7(tmpdir2(), "rig-native");
|
|
1370
|
+
var sharedGitNativeOutputPath = resolve7(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
1371
|
+
var trackerCommandUsageProbe = "usage: rig-git fetch-ref <repo-path> <remote> <branch>";
|
|
1372
|
+
function temporaryGitBinaryOutputPath(outputPath) {
|
|
1373
|
+
const suffix2 = process.platform === "win32" ? ".exe" : "";
|
|
1374
|
+
return resolve7(dirname4(outputPath), `.rig-git-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}${suffix2}`);
|
|
1375
|
+
}
|
|
1376
|
+
function publishGitBinary(tempOutputPath, outputPath) {
|
|
1377
|
+
try {
|
|
1378
|
+
renameSync2(tempOutputPath, outputPath);
|
|
1379
|
+
} catch (error) {
|
|
1380
|
+
if (process.platform === "win32" && existsSync7(outputPath)) {
|
|
1381
|
+
rmSync2(outputPath, { force: true });
|
|
1382
|
+
renameSync2(tempOutputPath, outputPath);
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
throw error;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
function runtimeRigGitFileName() {
|
|
1389
|
+
return `rig-git${process.platform === "win32" ? ".exe" : ""}`;
|
|
1390
|
+
}
|
|
1391
|
+
function rigGitSourceCandidates() {
|
|
1392
|
+
const execDir = process.execPath?.trim() ? dirname4(process.execPath.trim()) : "";
|
|
1393
|
+
const cwd = process.cwd()?.trim() || "";
|
|
1394
|
+
const projectRoot = process.env.PROJECT_RIG_ROOT?.trim() || "";
|
|
1395
|
+
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || "";
|
|
1396
|
+
const moduleRelativeSource = resolve7(import.meta.dir, "../../../native/rig-git.zig");
|
|
1397
|
+
return [...new Set([
|
|
1398
|
+
process.env.RIG_NATIVE_GIT_SOURCE?.trim() || "",
|
|
1399
|
+
moduleRelativeSource,
|
|
1400
|
+
projectRoot ? resolve7(projectRoot, "packages/runtime/native/rig-git.zig") : "",
|
|
1401
|
+
hostProjectRoot ? resolve7(hostProjectRoot, "packages/runtime/native/rig-git.zig") : "",
|
|
1402
|
+
cwd ? resolve7(cwd, "packages/runtime/native/rig-git.zig") : "",
|
|
1403
|
+
execDir ? resolve7(execDir, "..", "..", "packages/runtime/native/rig-git.zig") : "",
|
|
1404
|
+
execDir ? resolve7(execDir, "..", "native", "rig-git.zig") : ""
|
|
1405
|
+
].filter(Boolean))];
|
|
1406
|
+
}
|
|
1407
|
+
function nativePackageBinaryCandidates(fromDir, fileName) {
|
|
1408
|
+
const candidates = [];
|
|
1409
|
+
let cursor = resolve7(fromDir);
|
|
1410
|
+
for (let index = 0;index < 8; index += 1) {
|
|
1411
|
+
candidates.push(resolve7(cursor, "native", `${process.platform}-${process.arch}`, fileName), resolve7(cursor, "native", `${process.platform}-${process.arch}`, "bin", fileName), resolve7(cursor, "native", fileName), resolve7(cursor, "native", "bin", fileName));
|
|
1412
|
+
const parent = dirname4(cursor);
|
|
1413
|
+
if (parent === cursor)
|
|
1414
|
+
break;
|
|
1415
|
+
cursor = parent;
|
|
1416
|
+
}
|
|
1417
|
+
return candidates;
|
|
1418
|
+
}
|
|
1419
|
+
function rigGitBinaryCandidates() {
|
|
1420
|
+
const execDir = process.execPath?.trim() ? dirname4(process.execPath.trim()) : "";
|
|
1421
|
+
const fileName = runtimeRigGitFileName();
|
|
1422
|
+
const explicit = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
|
|
1423
|
+
return [...new Set([
|
|
1424
|
+
explicit,
|
|
1425
|
+
...nativePackageBinaryCandidates(import.meta.dir, fileName),
|
|
1426
|
+
execDir ? resolve7(execDir, fileName) : "",
|
|
1427
|
+
execDir ? resolve7(execDir, "..", fileName) : "",
|
|
1428
|
+
execDir ? resolve7(execDir, "..", "bin", fileName) : "",
|
|
1429
|
+
sharedGitNativeOutputPath
|
|
1430
|
+
].filter(Boolean))];
|
|
1431
|
+
}
|
|
1432
|
+
function resolveGitSourcePath() {
|
|
1433
|
+
for (const candidate of rigGitSourceCandidates()) {
|
|
1434
|
+
if (candidate && existsSync7(candidate)) {
|
|
1435
|
+
return candidate;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
return null;
|
|
1439
|
+
}
|
|
1440
|
+
function resolveGitBinaryPath() {
|
|
1441
|
+
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
1442
|
+
return null;
|
|
1443
|
+
}
|
|
1444
|
+
for (const candidate of rigGitBinaryCandidates()) {
|
|
1445
|
+
if (candidate && existsSync7(candidate)) {
|
|
1446
|
+
return candidate;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
function preferredGitBinaryOutputPath() {
|
|
1452
|
+
const explicit = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
|
|
1453
|
+
return explicit || sharedGitNativeOutputPath;
|
|
1454
|
+
}
|
|
1455
|
+
function binarySupportsTrackerCommandsSync(binaryPath) {
|
|
1456
|
+
try {
|
|
1457
|
+
const probe = Bun.spawnSync([binaryPath, "fetch-ref", "."], {
|
|
1458
|
+
stdout: "pipe",
|
|
1459
|
+
stderr: "pipe"
|
|
1460
|
+
});
|
|
1461
|
+
const stdout = probe.stdout.toString().trim();
|
|
1462
|
+
const stderr = probe.stderr.toString().trim();
|
|
1463
|
+
if (stdout.includes('"error":"unknown command"')) {
|
|
1464
|
+
return false;
|
|
1465
|
+
}
|
|
1466
|
+
return probe.exitCode === 2 && stderr.includes(trackerCommandUsageProbe);
|
|
1467
|
+
} catch {
|
|
1468
|
+
return false;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
function nativeBuildManifestPath(outputPath) {
|
|
1472
|
+
return `${outputPath}.build-manifest.json`;
|
|
1473
|
+
}
|
|
1474
|
+
function hasMatchingNativeBuildManifestSync(manifestPath, buildKey) {
|
|
1475
|
+
if (!existsSync7(manifestPath)) {
|
|
1476
|
+
return false;
|
|
1477
|
+
}
|
|
1478
|
+
try {
|
|
1479
|
+
const manifest = JSON.parse(readFileSync5(manifestPath, "utf8"));
|
|
1480
|
+
return manifest.version === 1 && manifest.buildKey === buildKey;
|
|
1481
|
+
} catch {
|
|
1482
|
+
return false;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
function sha256FileSync(path) {
|
|
1486
|
+
return createHash("sha256").update(readFileSync5(path)).digest("hex");
|
|
1487
|
+
}
|
|
1488
|
+
function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath()) {
|
|
1489
|
+
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
1490
|
+
throw new Error("Zig native git is disabled via RIG_DISABLE_ZIG_NATIVE=1");
|
|
1491
|
+
}
|
|
1492
|
+
const sourcePath = resolveGitSourcePath();
|
|
1493
|
+
if (!sourcePath) {
|
|
1494
|
+
const binaryPath = resolveGitBinaryPath();
|
|
1495
|
+
if (binaryPath) {
|
|
1496
|
+
return binaryPath;
|
|
1497
|
+
}
|
|
1498
|
+
throw new Error("rig-git.zig source file not found.");
|
|
1499
|
+
}
|
|
1500
|
+
const zigBinary = Bun.which("zig");
|
|
1501
|
+
if (!zigBinary) {
|
|
1502
|
+
throw new Error("zig is required to build native Rig git tools.");
|
|
1503
|
+
}
|
|
1504
|
+
mkdirSync3(dirname4(outputPath), { recursive: true });
|
|
1505
|
+
const sourceDigest = sha256FileSync(sourcePath);
|
|
1506
|
+
const buildKey = JSON.stringify({
|
|
1507
|
+
version: 1,
|
|
1508
|
+
zigBinary,
|
|
1509
|
+
platform: process.platform,
|
|
1510
|
+
arch: process.arch,
|
|
1511
|
+
sourcePath,
|
|
1512
|
+
sourceDigest
|
|
1513
|
+
});
|
|
1514
|
+
const manifestPath = nativeBuildManifestPath(outputPath);
|
|
1515
|
+
const needsBuild = !existsSync7(outputPath) || !hasMatchingNativeBuildManifestSync(manifestPath, buildKey) || !binarySupportsTrackerCommandsSync(outputPath);
|
|
1516
|
+
if (!needsBuild) {
|
|
1517
|
+
chmodSync(outputPath, 493);
|
|
1518
|
+
return outputPath;
|
|
1519
|
+
}
|
|
1520
|
+
const tempOutputPath = temporaryGitBinaryOutputPath(outputPath);
|
|
1521
|
+
const build = Bun.spawnSync([
|
|
1522
|
+
zigBinary,
|
|
1523
|
+
"build-exe",
|
|
1524
|
+
sourcePath,
|
|
1525
|
+
"-O",
|
|
1526
|
+
"ReleaseFast",
|
|
1527
|
+
`-femit-bin=${tempOutputPath}`
|
|
1528
|
+
], {
|
|
1529
|
+
cwd: dirname4(sourcePath),
|
|
1530
|
+
stdout: "pipe",
|
|
1531
|
+
stderr: "pipe"
|
|
1532
|
+
});
|
|
1533
|
+
if (build.exitCode !== 0 || !existsSync7(tempOutputPath)) {
|
|
1534
|
+
const stderr = build.stderr.toString().trim();
|
|
1535
|
+
const stdout = build.stdout.toString().trim();
|
|
1536
|
+
const details = [stderr, stdout].filter(Boolean).join(`
|
|
1537
|
+
`);
|
|
1538
|
+
throw new Error(`Failed to build native Rig git tools: ${details || `zig exited with code ${build.exitCode}`}`);
|
|
1539
|
+
}
|
|
1540
|
+
chmodSync(tempOutputPath, 493);
|
|
1541
|
+
if (existsSync7(outputPath) && hasMatchingNativeBuildManifestSync(manifestPath, buildKey)) {
|
|
1542
|
+
rmSync2(tempOutputPath, { force: true });
|
|
1543
|
+
chmodSync(outputPath, 493);
|
|
1544
|
+
return outputPath;
|
|
1545
|
+
}
|
|
1546
|
+
publishGitBinary(tempOutputPath, outputPath);
|
|
1547
|
+
if (!binarySupportsTrackerCommandsSync(outputPath)) {
|
|
1548
|
+
rmSync2(outputPath, { force: true });
|
|
1549
|
+
throw new Error("Failed to build native Rig git tools: tracker command probe failed");
|
|
1550
|
+
}
|
|
1551
|
+
writeFileSync2(manifestPath, `${JSON.stringify({ version: 1, buildKey }, null, 2)}
|
|
1552
|
+
`, "utf8");
|
|
1553
|
+
return outputPath;
|
|
1554
|
+
}
|
|
1555
|
+
function runGitNative(command, args) {
|
|
1556
|
+
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
1557
|
+
return { ok: false, error: "rig-git native disabled" };
|
|
1558
|
+
}
|
|
1559
|
+
const trackerCommand = command === "fetch-ref" || command === "read-blob-at-ref" || command === "write-tree-commit" || command === "push-ref-with-lease";
|
|
1560
|
+
let binaryPath = null;
|
|
1561
|
+
if (trackerCommand) {
|
|
1562
|
+
try {
|
|
1563
|
+
binaryPath = ensureRigGitBinaryPathSync(preferredGitBinaryOutputPath());
|
|
1564
|
+
} catch (error) {
|
|
1565
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1566
|
+
if (message.includes("rig-git.zig source file not found")) {
|
|
1567
|
+
return { ok: false, error: "rig-git binary not found" };
|
|
1568
|
+
}
|
|
1569
|
+
return { ok: false, error: message };
|
|
1570
|
+
}
|
|
1571
|
+
} else {
|
|
1572
|
+
const explicitBinaryPath = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
|
|
1573
|
+
binaryPath = explicitBinaryPath && existsSync7(explicitBinaryPath) ? explicitBinaryPath : !explicitBinaryPath ? resolveGitBinaryPath() : null;
|
|
1574
|
+
if (!binaryPath) {
|
|
1575
|
+
try {
|
|
1576
|
+
binaryPath = ensureRigGitBinaryPathSync(preferredGitBinaryOutputPath());
|
|
1577
|
+
} catch (error) {
|
|
1578
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1579
|
+
if (message.includes("rig-git.zig source file not found")) {
|
|
1580
|
+
return { ok: false, error: "rig-git binary not found" };
|
|
1581
|
+
}
|
|
1582
|
+
return { ok: false, error: message };
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
try {
|
|
1587
|
+
const proc = Bun.spawnSync([binaryPath, command, ...args], {
|
|
1588
|
+
stdout: "pipe",
|
|
1589
|
+
stderr: "pipe",
|
|
1590
|
+
env: process.env
|
|
1591
|
+
});
|
|
1592
|
+
if (proc.exitCode !== 0) {
|
|
1593
|
+
const stdoutText = proc.stdout.toString().trim();
|
|
1594
|
+
if (stdoutText) {
|
|
1595
|
+
try {
|
|
1596
|
+
const parsed = JSON.parse(stdoutText);
|
|
1597
|
+
if (!parsed.ok) {
|
|
1598
|
+
return parsed;
|
|
1599
|
+
}
|
|
1600
|
+
} catch {}
|
|
1601
|
+
}
|
|
1602
|
+
const errText = proc.stderr.toString().trim() || `exit code ${proc.exitCode}`;
|
|
1603
|
+
return { ok: false, error: errText };
|
|
1604
|
+
}
|
|
1605
|
+
const output = proc.stdout.toString().trim();
|
|
1606
|
+
return JSON.parse(output);
|
|
1607
|
+
} catch (err) {
|
|
1608
|
+
return { ok: false, error: String(err) };
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
function nativeBranchName(repoPath) {
|
|
1612
|
+
const result = runGitNative("branch-name", [repoPath]);
|
|
1613
|
+
if (!result.ok)
|
|
1614
|
+
return null;
|
|
1615
|
+
if ("value" in result && typeof result.value === "string")
|
|
1616
|
+
return result.value;
|
|
1617
|
+
return null;
|
|
1618
|
+
}
|
|
1619
|
+
function nativeChangeCount(repoPath) {
|
|
1620
|
+
const result = runGitNative("change-count", [repoPath]);
|
|
1621
|
+
if (!result.ok)
|
|
1622
|
+
return null;
|
|
1623
|
+
if ("count" in result && typeof result.count === "number")
|
|
1624
|
+
return result.count;
|
|
1625
|
+
return null;
|
|
1626
|
+
}
|
|
1627
|
+
function nativePendingFiles(repoPath) {
|
|
1628
|
+
const result = runGitNative("pending-files", [repoPath]);
|
|
1629
|
+
if (!result.ok)
|
|
1630
|
+
return null;
|
|
1631
|
+
if ("files" in result && Array.isArray(result.files)) {
|
|
1632
|
+
return result.files.map((f) => ({ path: f.path, status: f.status }));
|
|
1633
|
+
}
|
|
1634
|
+
return null;
|
|
1635
|
+
}
|
|
1636
|
+
function nativeFileHasChanges(repoPath, filePath) {
|
|
1637
|
+
const result = runGitNative("file-has-changes", [repoPath, filePath]);
|
|
1638
|
+
if (!result.ok)
|
|
1639
|
+
return null;
|
|
1640
|
+
if ("has_changes" in result && typeof result.has_changes === "boolean")
|
|
1641
|
+
return result.has_changes;
|
|
1642
|
+
return null;
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
// packages/runtime/src/control-plane/runtime/tooling/shell.ts
|
|
1370
1646
|
import { tmpdir as tmpdir3 } from "os";
|
|
1371
|
-
import { basename as
|
|
1372
|
-
var
|
|
1373
|
-
var
|
|
1647
|
+
import { basename as basename2, dirname as dirname5, resolve as resolve8 } from "path";
|
|
1648
|
+
var sharedNativeShellOutputDir = resolve8(tmpdir3(), "rig-native");
|
|
1649
|
+
var sharedNativeShellOutputPath = resolve8(sharedNativeShellOutputDir, `rig-shell-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
1650
|
+
// packages/runtime/src/control-plane/runtime/tooling/file-tools.ts
|
|
1651
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
1652
|
+
import { basename as basename3, dirname as dirname6, resolve as resolve9 } from "path";
|
|
1653
|
+
var sharedNativeToolsOutputDir = resolve9(tmpdir4(), "rig-native");
|
|
1654
|
+
var sharedNativeToolsOutputPath = resolve9(sharedNativeToolsOutputDir, `rig-tools-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
1374
1655
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
1375
1656
|
import { createPluginHost } from "@rig/core";
|
|
1376
1657
|
import { loadConfig } from "@rig/core/load-config";
|
|
@@ -1517,7 +1798,7 @@ function createTaskFieldRegistry(extensions) {
|
|
|
1517
1798
|
}
|
|
1518
1799
|
|
|
1519
1800
|
// packages/runtime/src/control-plane/validators/runtime-registration.ts
|
|
1520
|
-
import { existsSync as
|
|
1801
|
+
import { existsSync as existsSync8 } from "fs";
|
|
1521
1802
|
import { join } from "path";
|
|
1522
1803
|
function createValidatorRegistry() {
|
|
1523
1804
|
const map = new Map;
|
|
@@ -1550,7 +1831,7 @@ function registerBuiltInValidators(registry) {
|
|
|
1550
1831
|
}
|
|
1551
1832
|
async function runStdTypecheck(ctx) {
|
|
1552
1833
|
const packageJsonPath = join(ctx.workspaceRoot, "package.json");
|
|
1553
|
-
if (!
|
|
1834
|
+
if (!existsSync8(packageJsonPath)) {
|
|
1554
1835
|
return {
|
|
1555
1836
|
id: "std:typecheck",
|
|
1556
1837
|
passed: false,
|
|
@@ -1578,8 +1859,8 @@ async function runStdTypecheck(ctx) {
|
|
|
1578
1859
|
}
|
|
1579
1860
|
|
|
1580
1861
|
// packages/runtime/src/control-plane/hook-materializer.ts
|
|
1581
|
-
import { existsSync as
|
|
1582
|
-
import { dirname as
|
|
1862
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
|
|
1863
|
+
import { dirname as dirname7, resolve as resolve10 } from "path";
|
|
1583
1864
|
var MARKER_PLUGIN = "_rigPlugin";
|
|
1584
1865
|
var MARKER_HOOK_ID = "_rigHookId";
|
|
1585
1866
|
function matcherToString(matcher) {
|
|
@@ -1593,8 +1874,8 @@ function isPluginOwned(cmd) {
|
|
|
1593
1874
|
return typeof cmd[MARKER_PLUGIN] === "string";
|
|
1594
1875
|
}
|
|
1595
1876
|
function materializeHooks(projectRoot, entries) {
|
|
1596
|
-
const settingsPath =
|
|
1597
|
-
const existing =
|
|
1877
|
+
const settingsPath = resolve10(projectRoot, ".claude", "settings.json");
|
|
1878
|
+
const existing = existsSync9(settingsPath) ? safeReadJson(settingsPath) : {};
|
|
1598
1879
|
const hooks = existing.hooks ?? {};
|
|
1599
1880
|
for (const event of Object.keys(hooks)) {
|
|
1600
1881
|
const groups = hooks[event] ?? [];
|
|
@@ -1636,56 +1917,56 @@ function materializeHooks(projectRoot, entries) {
|
|
|
1636
1917
|
} else {
|
|
1637
1918
|
delete next.hooks;
|
|
1638
1919
|
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1920
|
+
mkdirSync4(dirname7(settingsPath), { recursive: true });
|
|
1921
|
+
writeFileSync3(settingsPath, `${JSON.stringify(next, null, 2)}
|
|
1641
1922
|
`, "utf-8");
|
|
1642
1923
|
return settingsPath;
|
|
1643
1924
|
}
|
|
1644
1925
|
function safeReadJson(path) {
|
|
1645
1926
|
try {
|
|
1646
|
-
return JSON.parse(
|
|
1927
|
+
return JSON.parse(readFileSync6(path, "utf-8"));
|
|
1647
1928
|
} catch {
|
|
1648
1929
|
return {};
|
|
1649
1930
|
}
|
|
1650
1931
|
}
|
|
1651
1932
|
|
|
1652
1933
|
// packages/runtime/src/control-plane/skill-materializer.ts
|
|
1653
|
-
import { existsSync as
|
|
1654
|
-
import { resolve as
|
|
1934
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync7, readdirSync, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
1935
|
+
import { resolve as resolve11 } from "path";
|
|
1655
1936
|
import { loadSkill } from "@rig/skill-loader";
|
|
1656
1937
|
var MARKER_FILENAME = ".rig-plugin";
|
|
1657
1938
|
function skillDirName(id) {
|
|
1658
1939
|
return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
1659
1940
|
}
|
|
1660
1941
|
async function materializeSkills(projectRoot, entries) {
|
|
1661
|
-
const skillsRoot =
|
|
1662
|
-
if (
|
|
1942
|
+
const skillsRoot = resolve11(projectRoot, ".pi", "skills");
|
|
1943
|
+
if (existsSync10(skillsRoot)) {
|
|
1663
1944
|
for (const name of readdirSync(skillsRoot)) {
|
|
1664
|
-
const dir =
|
|
1665
|
-
if (
|
|
1666
|
-
|
|
1945
|
+
const dir = resolve11(skillsRoot, name);
|
|
1946
|
+
if (existsSync10(resolve11(dir, MARKER_FILENAME))) {
|
|
1947
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
1667
1948
|
}
|
|
1668
1949
|
}
|
|
1669
1950
|
}
|
|
1670
1951
|
const written = [];
|
|
1671
1952
|
for (const { pluginName, skill } of entries) {
|
|
1672
|
-
const sourcePath =
|
|
1673
|
-
if (!
|
|
1953
|
+
const sourcePath = resolve11(projectRoot, skill.path);
|
|
1954
|
+
if (!existsSync10(sourcePath)) {
|
|
1674
1955
|
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
|
|
1675
1956
|
continue;
|
|
1676
1957
|
}
|
|
1677
1958
|
let body;
|
|
1678
1959
|
try {
|
|
1679
1960
|
await loadSkill(sourcePath);
|
|
1680
|
-
body =
|
|
1961
|
+
body = readFileSync7(sourcePath, "utf-8");
|
|
1681
1962
|
} catch (err) {
|
|
1682
1963
|
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
|
|
1683
1964
|
continue;
|
|
1684
1965
|
}
|
|
1685
|
-
const dir =
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1966
|
+
const dir = resolve11(skillsRoot, skillDirName(skill.id));
|
|
1967
|
+
mkdirSync5(dir, { recursive: true });
|
|
1968
|
+
writeFileSync4(resolve11(dir, "SKILL.md"), body, "utf-8");
|
|
1969
|
+
writeFileSync4(resolve11(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
|
|
1689
1970
|
`, "utf-8");
|
|
1690
1971
|
written.push({ id: skill.id, pluginName, directory: dir });
|
|
1691
1972
|
}
|
|
@@ -1752,12 +2033,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1752
2033
|
|
|
1753
2034
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
1754
2035
|
import { spawnSync } from "child_process";
|
|
1755
|
-
import { existsSync as
|
|
1756
|
-
import { basename as basename4, join as join2, resolve as
|
|
2036
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9, readdirSync as readdirSync2, statSync as statSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
2037
|
+
import { basename as basename4, join as join2, resolve as resolve13 } from "path";
|
|
1757
2038
|
|
|
1758
2039
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
1759
|
-
import { existsSync as
|
|
1760
|
-
import { resolve as
|
|
2040
|
+
import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
|
|
2041
|
+
import { resolve as resolve12 } from "path";
|
|
1761
2042
|
|
|
1762
2043
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
1763
2044
|
async function findTaskById(reader, id) {
|
|
@@ -1780,7 +2061,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
1780
2061
|
}
|
|
1781
2062
|
}
|
|
1782
2063
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1783
|
-
const configPath = options.configPath ??
|
|
2064
|
+
const configPath = options.configPath ?? resolve12(projectRoot, ".rig", "task-config.json");
|
|
1784
2065
|
const reader = {
|
|
1785
2066
|
async listTasks() {
|
|
1786
2067
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -1791,8 +2072,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
1791
2072
|
};
|
|
1792
2073
|
return reader;
|
|
1793
2074
|
}
|
|
1794
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
1795
|
-
if (!
|
|
2075
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve12(projectRoot, ".rig", "task-config.json")) {
|
|
2076
|
+
if (!existsSync11(configPath)) {
|
|
1796
2077
|
return [];
|
|
1797
2078
|
}
|
|
1798
2079
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -1800,7 +2081,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve11(projectRoot,
|
|
|
1800
2081
|
}
|
|
1801
2082
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
1802
2083
|
try {
|
|
1803
|
-
const parsed = JSON.parse(
|
|
2084
|
+
const parsed = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
1804
2085
|
if (isPlainRecord(parsed)) {
|
|
1805
2086
|
return parsed;
|
|
1806
2087
|
}
|
|
@@ -1884,7 +2165,7 @@ function isPlainRecord(candidate) {
|
|
|
1884
2165
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
1885
2166
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
1886
2167
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1887
|
-
const configPath = options.configPath ??
|
|
2168
|
+
const configPath = options.configPath ?? resolve13(projectRoot, ".rig", "task-config.json");
|
|
1888
2169
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
1889
2170
|
const spawnFn = options.spawn ?? spawnSync;
|
|
1890
2171
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -1950,7 +2231,7 @@ async function readSourceAwareTaskStatus(projectRoot, taskId, options = {}) {
|
|
|
1950
2231
|
}
|
|
1951
2232
|
}
|
|
1952
2233
|
function updateSourceAwareTaskConfigTask(projectRoot, taskId, update, options = {}) {
|
|
1953
|
-
const configPath = options.configPath ??
|
|
2234
|
+
const configPath = options.configPath ?? resolve13(projectRoot, ".rig", "task-config.json");
|
|
1954
2235
|
const rawEntry = readRawTaskEntry(configPath, taskId);
|
|
1955
2236
|
if (!rawEntry) {
|
|
1956
2237
|
const configuredFilesPath = readConfiguredFilesTaskSourcePath(projectRoot);
|
|
@@ -2003,10 +2284,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
2003
2284
|
return metadata;
|
|
2004
2285
|
}
|
|
2005
2286
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
2006
|
-
const jsonPath =
|
|
2007
|
-
if (
|
|
2287
|
+
const jsonPath = resolve13(projectRoot, "rig.config.json");
|
|
2288
|
+
if (existsSync12(jsonPath)) {
|
|
2008
2289
|
try {
|
|
2009
|
-
const parsed = JSON.parse(
|
|
2290
|
+
const parsed = JSON.parse(readFileSync9(jsonPath, "utf8"));
|
|
2010
2291
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
2011
2292
|
const source = parsed.taskSource;
|
|
2012
2293
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -2015,12 +2296,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
2015
2296
|
return null;
|
|
2016
2297
|
}
|
|
2017
2298
|
}
|
|
2018
|
-
const tsPath =
|
|
2019
|
-
if (!
|
|
2299
|
+
const tsPath = resolve13(projectRoot, "rig.config.ts");
|
|
2300
|
+
if (!existsSync12(tsPath)) {
|
|
2020
2301
|
return null;
|
|
2021
2302
|
}
|
|
2022
2303
|
try {
|
|
2023
|
-
const source =
|
|
2304
|
+
const source = readFileSync9(tsPath, "utf8");
|
|
2024
2305
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
2025
2306
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
2026
2307
|
if (kind !== "files") {
|
|
@@ -2040,10 +2321,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
2040
2321
|
return isPlainRecord2(entry) ? entry : null;
|
|
2041
2322
|
}
|
|
2042
2323
|
function readRawTaskConfig(configPath) {
|
|
2043
|
-
if (!
|
|
2324
|
+
if (!existsSync12(configPath)) {
|
|
2044
2325
|
return null;
|
|
2045
2326
|
}
|
|
2046
|
-
const parsed = JSON.parse(
|
|
2327
|
+
const parsed = JSON.parse(readFileSync9(configPath, "utf8"));
|
|
2047
2328
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
2048
2329
|
}
|
|
2049
2330
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -2060,16 +2341,16 @@ function writeLegacyTaskStatus(configPath, taskId, status) {
|
|
|
2060
2341
|
return;
|
|
2061
2342
|
}
|
|
2062
2343
|
entry.status = status;
|
|
2063
|
-
|
|
2344
|
+
writeFileSync5(configPath, `${JSON.stringify(rawConfig, null, 2)}
|
|
2064
2345
|
`, "utf8");
|
|
2065
2346
|
}
|
|
2066
2347
|
function updateFileBackedTask(projectRoot, sourcePath, taskId, update) {
|
|
2067
|
-
const directory =
|
|
2348
|
+
const directory = resolve13(projectRoot, sourcePath);
|
|
2068
2349
|
const file = findFileBackedTaskFile(directory, taskId);
|
|
2069
2350
|
if (!file) {
|
|
2070
2351
|
return false;
|
|
2071
2352
|
}
|
|
2072
|
-
const raw = JSON.parse(
|
|
2353
|
+
const raw = JSON.parse(readFileSync9(file, "utf8"));
|
|
2073
2354
|
if (!isPlainRecord2(raw)) {
|
|
2074
2355
|
return false;
|
|
2075
2356
|
}
|
|
@@ -2086,13 +2367,13 @@ function updateFileBackedTask(projectRoot, sourcePath, taskId, update) {
|
|
|
2086
2367
|
{ body: update.comment, createdAt: new Date().toISOString(), source: "rig" }
|
|
2087
2368
|
];
|
|
2088
2369
|
}
|
|
2089
|
-
|
|
2370
|
+
writeFileSync5(file, `${JSON.stringify(raw, null, 2)}
|
|
2090
2371
|
`, "utf8");
|
|
2091
2372
|
return true;
|
|
2092
2373
|
}
|
|
2093
2374
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
2094
|
-
const directory =
|
|
2095
|
-
if (!
|
|
2375
|
+
const directory = resolve13(projectRoot, sourcePath);
|
|
2376
|
+
if (!existsSync12(directory)) {
|
|
2096
2377
|
return [];
|
|
2097
2378
|
}
|
|
2098
2379
|
const tasks = [];
|
|
@@ -2107,11 +2388,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
2107
2388
|
return tasks;
|
|
2108
2389
|
}
|
|
2109
2390
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
2110
|
-
const file = findFileBackedTaskFile(
|
|
2391
|
+
const file = findFileBackedTaskFile(resolve13(projectRoot, sourcePath), taskId);
|
|
2111
2392
|
if (!file) {
|
|
2112
2393
|
return null;
|
|
2113
2394
|
}
|
|
2114
|
-
const raw = JSON.parse(
|
|
2395
|
+
const raw = JSON.parse(readFileSync9(file, "utf8"));
|
|
2115
2396
|
if (!isPlainRecord2(raw)) {
|
|
2116
2397
|
return null;
|
|
2117
2398
|
}
|
|
@@ -2124,7 +2405,7 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
2124
2405
|
};
|
|
2125
2406
|
}
|
|
2126
2407
|
function findFileBackedTaskFile(directory, taskId) {
|
|
2127
|
-
if (!
|
|
2408
|
+
if (!existsSync12(directory)) {
|
|
2128
2409
|
return null;
|
|
2129
2410
|
}
|
|
2130
2411
|
for (const name of readdirSync2(directory)) {
|
|
@@ -2134,7 +2415,7 @@ function findFileBackedTaskFile(directory, taskId) {
|
|
|
2134
2415
|
try {
|
|
2135
2416
|
if (!statSync3(file).isFile())
|
|
2136
2417
|
continue;
|
|
2137
|
-
const raw = JSON.parse(
|
|
2418
|
+
const raw = JSON.parse(readFileSync9(file, "utf8"));
|
|
2138
2419
|
const inferredId = basename4(file).replace(FILE_TASK_PATTERN, "");
|
|
2139
2420
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
2140
2421
|
if (id === taskId) {
|
|
@@ -2327,457 +2608,177 @@ function assertGhSuccess(args, res) {
|
|
|
2327
2608
|
const msg = res.error.message ?? String(res.error);
|
|
2328
2609
|
throw new Error(`gh CLI not available \u2014 install gh (brew install gh / apt install gh): ${msg}`);
|
|
2329
2610
|
}
|
|
2330
|
-
if (res.status !== 0) {
|
|
2331
|
-
throw new Error(`gh ${args.join(" ")} failed (exit ${res.status}): ${res.stderr}`);
|
|
2332
|
-
}
|
|
2333
|
-
}
|
|
2334
|
-
function parseDeps(body) {
|
|
2335
|
-
return parseIssueRefs(body, /^depends-on:\s*([^\n]+)/im);
|
|
2336
|
-
}
|
|
2337
|
-
function parseParents(body) {
|
|
2338
|
-
return parseIssueRefs(body, /^parents?:\s*([^\n]+)/im);
|
|
2339
|
-
}
|
|
2340
|
-
function parseIssueRefs(body, pattern) {
|
|
2341
|
-
const match = body.match(pattern);
|
|
2342
|
-
if (!match)
|
|
2343
|
-
return [];
|
|
2344
|
-
return match[1].split(",").map((value) => value.trim()).map((value) => value.replace(/^#/, "").match(/^(\d+)/)?.[1] ?? "").filter((value) => value.length > 0);
|
|
2345
|
-
}
|
|
2346
|
-
function issueTypeFor(labels) {
|
|
2347
|
-
const typed = labels.find((label) => label.startsWith("type:"));
|
|
2348
|
-
if (typed)
|
|
2349
|
-
return typed.slice("type:".length);
|
|
2350
|
-
if (labels.includes("epic"))
|
|
2351
|
-
return "epic";
|
|
2352
|
-
return "task";
|
|
2353
|
-
}
|
|
2354
|
-
function isPlainRecord2(candidate) {
|
|
2355
|
-
return typeof candidate === "object" && candidate !== null && !Array.isArray(candidate);
|
|
2356
|
-
}
|
|
2357
|
-
|
|
2358
|
-
// packages/runtime/src/control-plane/tasks/source-lifecycle.ts
|
|
2359
|
-
function hasRunnableTaskSource(source) {
|
|
2360
|
-
return Boolean(source && typeof source === "object" && !Array.isArray(source));
|
|
2361
|
-
}
|
|
2362
|
-
function cleanString(value) {
|
|
2363
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
2364
|
-
}
|
|
2365
|
-
function taskIdFromSourceIssueId(value) {
|
|
2366
|
-
const raw = cleanString(value);
|
|
2367
|
-
if (!raw)
|
|
2368
|
-
return null;
|
|
2369
|
-
const issueNumber = raw.match(/#([^#\s]+)$/)?.[1];
|
|
2370
|
-
return issueNumber ?? raw;
|
|
2371
|
-
}
|
|
2372
|
-
function resolveSourceTaskId(taskId, sourceTask) {
|
|
2373
|
-
return cleanString(sourceTask?.id) ?? taskIdFromSourceIssueId(sourceTask?.sourceIssueId) ?? taskIdFromSourceIssueId(sourceTask?.source_issue_id) ?? taskId;
|
|
2374
|
-
}
|
|
2375
|
-
async function getPluginTask(projectRoot, taskId) {
|
|
2376
|
-
const ctx = await buildPluginHostContext(projectRoot);
|
|
2377
|
-
const [source] = ctx?.taskSourceRegistry.list() ?? [];
|
|
2378
|
-
if (!hasRunnableTaskSource(source)) {
|
|
2379
|
-
return ctx ? { configured: false, sourceKind: null, task: null } : null;
|
|
2380
|
-
}
|
|
2381
|
-
const task = source.get ? await source.get(taskId) ?? null : (await source.list()).find((entry) => entry.id === taskId) ?? null;
|
|
2382
|
-
return {
|
|
2383
|
-
configured: true,
|
|
2384
|
-
sourceKind: source.kind,
|
|
2385
|
-
task
|
|
2386
|
-
};
|
|
2387
|
-
}
|
|
2388
|
-
async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
2389
|
-
const pluginResult = await getPluginTask(projectRoot, taskId);
|
|
2390
|
-
if (pluginResult)
|
|
2391
|
-
return pluginResult;
|
|
2392
|
-
const task = await createSourceAwareTaskConfigRecordReader(projectRoot).getTask(taskId);
|
|
2393
|
-
return {
|
|
2394
|
-
configured: false,
|
|
2395
|
-
sourceKind: null,
|
|
2396
|
-
task
|
|
2397
|
-
};
|
|
2398
|
-
}
|
|
2399
|
-
async function updatePluginTaskSourceTask(projectRoot, taskId, update) {
|
|
2400
|
-
const ctx = await buildPluginHostContext(projectRoot);
|
|
2401
|
-
const [source] = ctx?.taskSourceRegistry.list() ?? [];
|
|
2402
|
-
if (!hasRunnableTaskSource(source)) {
|
|
2403
|
-
return ctx ? { taskId, updated: false, source: "none", sourceKind: null, status: null } : null;
|
|
2404
|
-
}
|
|
2405
|
-
if (source.updateTask) {
|
|
2406
|
-
await source.updateTask(taskId, update);
|
|
2407
|
-
} else if (update.status && source.updateStatus) {
|
|
2408
|
-
await source.updateStatus(taskId, update.status);
|
|
2409
|
-
} else {
|
|
2410
|
-
return {
|
|
2411
|
-
taskId,
|
|
2412
|
-
updated: false,
|
|
2413
|
-
source: "plugin",
|
|
2414
|
-
sourceKind: source.kind,
|
|
2415
|
-
status: null
|
|
2416
|
-
};
|
|
2417
|
-
}
|
|
2418
|
-
const status = source.get ? (await source.get(taskId))?.status ?? update.status ?? null : update.status ?? null;
|
|
2419
|
-
return {
|
|
2420
|
-
taskId,
|
|
2421
|
-
updated: true,
|
|
2422
|
-
source: "plugin",
|
|
2423
|
-
sourceKind: source.kind,
|
|
2424
|
-
status
|
|
2425
|
-
};
|
|
2426
|
-
}
|
|
2427
|
-
async function updateConfiguredTaskSourceTask(projectRoot, input) {
|
|
2428
|
-
const taskId = resolveSourceTaskId(input.taskId, input.sourceTask);
|
|
2429
|
-
let pluginResult = null;
|
|
2430
|
-
try {
|
|
2431
|
-
pluginResult = await updatePluginTaskSourceTask(projectRoot, taskId, input.update);
|
|
2432
|
-
} catch (error) {
|
|
2433
|
-
const fallbackUpdated = updateSourceAwareTaskConfigTask(projectRoot, taskId, input.update, {
|
|
2434
|
-
allowLocalTaskConfigStatusFallback: false
|
|
2435
|
-
});
|
|
2436
|
-
if (!fallbackUpdated) {
|
|
2437
|
-
throw error;
|
|
2438
|
-
}
|
|
2439
|
-
return {
|
|
2440
|
-
taskId,
|
|
2441
|
-
updated: true,
|
|
2442
|
-
source: "compat",
|
|
2443
|
-
sourceKind: null,
|
|
2444
|
-
status: await readSourceAwareTaskStatus(projectRoot, taskId)
|
|
2445
|
-
};
|
|
2446
|
-
}
|
|
2447
|
-
if (pluginResult) {
|
|
2448
|
-
return pluginResult;
|
|
2449
|
-
}
|
|
2450
|
-
const updated = updateSourceAwareTaskConfigTask(projectRoot, taskId, input.update);
|
|
2451
|
-
return {
|
|
2452
|
-
taskId,
|
|
2453
|
-
updated,
|
|
2454
|
-
source: updated ? "compat" : "none",
|
|
2455
|
-
sourceKind: null,
|
|
2456
|
-
status: await readSourceAwareTaskStatus(projectRoot, taskId)
|
|
2457
|
-
};
|
|
2458
|
-
}
|
|
2459
|
-
function buildTaskRunLifecycleComment(input) {
|
|
2460
|
-
const lines = [
|
|
2461
|
-
"<!-- rig:status-comment -->",
|
|
2462
|
-
`### Rig status: ${input.status}`,
|
|
2463
|
-
"",
|
|
2464
|
-
input.summary,
|
|
2465
|
-
"",
|
|
2466
|
-
`- Run: ${input.runId}`,
|
|
2467
|
-
`- Status: ${input.status}`
|
|
2468
|
-
];
|
|
2469
|
-
if (input.errorText?.trim()) {
|
|
2470
|
-
lines.push(`- Error: ${input.errorText.trim()}`);
|
|
2471
|
-
}
|
|
2472
|
-
if (input.runtimeWorkspace?.trim()) {
|
|
2473
|
-
lines.push(`- Runtime workspace: ${input.runtimeWorkspace.trim()}`);
|
|
2474
|
-
}
|
|
2475
|
-
if (input.logsDir?.trim()) {
|
|
2476
|
-
lines.push(`- Logs: ${input.logsDir.trim()}`);
|
|
2477
|
-
}
|
|
2478
|
-
if (input.sessionDir?.trim()) {
|
|
2479
|
-
lines.push(`- Session: ${input.sessionDir.trim()}`);
|
|
2480
|
-
}
|
|
2481
|
-
return lines.join(`
|
|
2482
|
-
`);
|
|
2483
|
-
}
|
|
2484
|
-
|
|
2485
|
-
// packages/runtime/src/control-plane/native/task-state.ts
|
|
2486
|
-
import { existsSync as existsSync13, readFileSync as readFileSync10, readdirSync as readdirSync3, statSync as statSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
2487
|
-
import { basename as basename5, resolve as resolve14 } from "path";
|
|
2488
|
-
|
|
2489
|
-
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
2490
|
-
var CANONICAL_TASK_LIFECYCLE_STATUSES = new Set([
|
|
2491
|
-
"draft",
|
|
2492
|
-
"open",
|
|
2493
|
-
"ready",
|
|
2494
|
-
"queued",
|
|
2495
|
-
"in_progress",
|
|
2496
|
-
"under_review",
|
|
2497
|
-
"blocked",
|
|
2498
|
-
"completed",
|
|
2499
|
-
"cancelled"
|
|
2500
|
-
]);
|
|
2501
|
-
// packages/runtime/src/control-plane/native/git-native.ts
|
|
2502
|
-
import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync9, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
2503
|
-
import { tmpdir as tmpdir4 } from "os";
|
|
2504
|
-
import { dirname as dirname7, isAbsolute, resolve as resolve13 } from "path";
|
|
2505
|
-
import { createHash } from "crypto";
|
|
2506
|
-
var sharedGitNativeOutputDir = resolve13(tmpdir4(), "rig-native");
|
|
2507
|
-
var sharedGitNativeOutputPath = resolve13(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
2508
|
-
var trackerCommandUsageProbe = "usage: rig-git fetch-ref <repo-path> <remote> <branch>";
|
|
2509
|
-
function temporaryGitBinaryOutputPath(outputPath) {
|
|
2510
|
-
const suffix2 = process.platform === "win32" ? ".exe" : "";
|
|
2511
|
-
return resolve13(dirname7(outputPath), `.rig-git-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}${suffix2}`);
|
|
2512
|
-
}
|
|
2513
|
-
function publishGitBinary(tempOutputPath, outputPath) {
|
|
2514
|
-
try {
|
|
2515
|
-
renameSync2(tempOutputPath, outputPath);
|
|
2516
|
-
} catch (error) {
|
|
2517
|
-
if (process.platform === "win32" && existsSync12(outputPath)) {
|
|
2518
|
-
rmSync3(outputPath, { force: true });
|
|
2519
|
-
renameSync2(tempOutputPath, outputPath);
|
|
2520
|
-
return;
|
|
2521
|
-
}
|
|
2522
|
-
throw error;
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
2525
|
-
function runtimeRigGitFileName() {
|
|
2526
|
-
return `rig-git${process.platform === "win32" ? ".exe" : ""}`;
|
|
2527
|
-
}
|
|
2528
|
-
function rigGitSourceCandidates() {
|
|
2529
|
-
const execDir = process.execPath?.trim() ? dirname7(process.execPath.trim()) : "";
|
|
2530
|
-
const cwd = process.cwd()?.trim() || "";
|
|
2531
|
-
const projectRoot = process.env.PROJECT_RIG_ROOT?.trim() || "";
|
|
2532
|
-
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || "";
|
|
2533
|
-
const moduleRelativeSource = resolve13(import.meta.dir, "../../../native/rig-git.zig");
|
|
2534
|
-
return [...new Set([
|
|
2535
|
-
process.env.RIG_NATIVE_GIT_SOURCE?.trim() || "",
|
|
2536
|
-
moduleRelativeSource,
|
|
2537
|
-
projectRoot ? resolve13(projectRoot, "packages/runtime/native/rig-git.zig") : "",
|
|
2538
|
-
hostProjectRoot ? resolve13(hostProjectRoot, "packages/runtime/native/rig-git.zig") : "",
|
|
2539
|
-
cwd ? resolve13(cwd, "packages/runtime/native/rig-git.zig") : "",
|
|
2540
|
-
execDir ? resolve13(execDir, "..", "..", "packages/runtime/native/rig-git.zig") : "",
|
|
2541
|
-
execDir ? resolve13(execDir, "..", "native", "rig-git.zig") : ""
|
|
2542
|
-
].filter(Boolean))];
|
|
2543
|
-
}
|
|
2544
|
-
function nativePackageBinaryCandidates(fromDir, fileName) {
|
|
2545
|
-
const candidates = [];
|
|
2546
|
-
let cursor = resolve13(fromDir);
|
|
2547
|
-
for (let index = 0;index < 8; index += 1) {
|
|
2548
|
-
candidates.push(resolve13(cursor, "native", `${process.platform}-${process.arch}`, fileName), resolve13(cursor, "native", `${process.platform}-${process.arch}`, "bin", fileName), resolve13(cursor, "native", fileName), resolve13(cursor, "native", "bin", fileName));
|
|
2549
|
-
const parent = dirname7(cursor);
|
|
2550
|
-
if (parent === cursor)
|
|
2551
|
-
break;
|
|
2552
|
-
cursor = parent;
|
|
2553
|
-
}
|
|
2554
|
-
return candidates;
|
|
2555
|
-
}
|
|
2556
|
-
function rigGitBinaryCandidates() {
|
|
2557
|
-
const execDir = process.execPath?.trim() ? dirname7(process.execPath.trim()) : "";
|
|
2558
|
-
const fileName = runtimeRigGitFileName();
|
|
2559
|
-
const explicit = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
|
|
2560
|
-
return [...new Set([
|
|
2561
|
-
explicit,
|
|
2562
|
-
...nativePackageBinaryCandidates(import.meta.dir, fileName),
|
|
2563
|
-
execDir ? resolve13(execDir, fileName) : "",
|
|
2564
|
-
execDir ? resolve13(execDir, "..", fileName) : "",
|
|
2565
|
-
execDir ? resolve13(execDir, "..", "bin", fileName) : "",
|
|
2566
|
-
sharedGitNativeOutputPath
|
|
2567
|
-
].filter(Boolean))];
|
|
2568
|
-
}
|
|
2569
|
-
function resolveGitSourcePath() {
|
|
2570
|
-
for (const candidate of rigGitSourceCandidates()) {
|
|
2571
|
-
if (candidate && existsSync12(candidate)) {
|
|
2572
|
-
return candidate;
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
return null;
|
|
2576
|
-
}
|
|
2577
|
-
function resolveGitBinaryPath() {
|
|
2578
|
-
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
2579
|
-
return null;
|
|
2580
|
-
}
|
|
2581
|
-
for (const candidate of rigGitBinaryCandidates()) {
|
|
2582
|
-
if (candidate && existsSync12(candidate)) {
|
|
2583
|
-
return candidate;
|
|
2584
|
-
}
|
|
2585
|
-
}
|
|
2586
|
-
return null;
|
|
2587
|
-
}
|
|
2588
|
-
function preferredGitBinaryOutputPath() {
|
|
2589
|
-
const explicit = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
|
|
2590
|
-
return explicit || sharedGitNativeOutputPath;
|
|
2591
|
-
}
|
|
2592
|
-
function binarySupportsTrackerCommandsSync(binaryPath) {
|
|
2593
|
-
try {
|
|
2594
|
-
const probe = Bun.spawnSync([binaryPath, "fetch-ref", "."], {
|
|
2595
|
-
stdout: "pipe",
|
|
2596
|
-
stderr: "pipe"
|
|
2597
|
-
});
|
|
2598
|
-
const stdout = probe.stdout.toString().trim();
|
|
2599
|
-
const stderr = probe.stderr.toString().trim();
|
|
2600
|
-
if (stdout.includes('"error":"unknown command"')) {
|
|
2601
|
-
return false;
|
|
2602
|
-
}
|
|
2603
|
-
return probe.exitCode === 2 && stderr.includes(trackerCommandUsageProbe);
|
|
2604
|
-
} catch {
|
|
2605
|
-
return false;
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2608
|
-
function nativeBuildManifestPath(outputPath) {
|
|
2609
|
-
return `${outputPath}.build-manifest.json`;
|
|
2610
|
-
}
|
|
2611
|
-
function hasMatchingNativeBuildManifestSync(manifestPath, buildKey) {
|
|
2612
|
-
if (!existsSync12(manifestPath)) {
|
|
2613
|
-
return false;
|
|
2614
|
-
}
|
|
2615
|
-
try {
|
|
2616
|
-
const manifest = JSON.parse(readFileSync9(manifestPath, "utf8"));
|
|
2617
|
-
return manifest.version === 1 && manifest.buildKey === buildKey;
|
|
2618
|
-
} catch {
|
|
2619
|
-
return false;
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
function sha256FileSync(path) {
|
|
2623
|
-
return createHash("sha256").update(readFileSync9(path)).digest("hex");
|
|
2624
|
-
}
|
|
2625
|
-
function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath()) {
|
|
2626
|
-
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
2627
|
-
throw new Error("Zig native git is disabled via RIG_DISABLE_ZIG_NATIVE=1");
|
|
2628
|
-
}
|
|
2629
|
-
const sourcePath = resolveGitSourcePath();
|
|
2630
|
-
if (!sourcePath) {
|
|
2631
|
-
const binaryPath = resolveGitBinaryPath();
|
|
2632
|
-
if (binaryPath) {
|
|
2633
|
-
return binaryPath;
|
|
2634
|
-
}
|
|
2635
|
-
throw new Error("rig-git.zig source file not found.");
|
|
2636
|
-
}
|
|
2637
|
-
const zigBinary = Bun.which("zig");
|
|
2638
|
-
if (!zigBinary) {
|
|
2639
|
-
throw new Error("zig is required to build native Rig git tools.");
|
|
2640
|
-
}
|
|
2641
|
-
mkdirSync5(dirname7(outputPath), { recursive: true });
|
|
2642
|
-
const sourceDigest = sha256FileSync(sourcePath);
|
|
2643
|
-
const buildKey = JSON.stringify({
|
|
2644
|
-
version: 1,
|
|
2645
|
-
zigBinary,
|
|
2646
|
-
platform: process.platform,
|
|
2647
|
-
arch: process.arch,
|
|
2648
|
-
sourcePath,
|
|
2649
|
-
sourceDigest
|
|
2650
|
-
});
|
|
2651
|
-
const manifestPath = nativeBuildManifestPath(outputPath);
|
|
2652
|
-
const needsBuild = !existsSync12(outputPath) || !hasMatchingNativeBuildManifestSync(manifestPath, buildKey) || !binarySupportsTrackerCommandsSync(outputPath);
|
|
2653
|
-
if (!needsBuild) {
|
|
2654
|
-
chmodSync(outputPath, 493);
|
|
2655
|
-
return outputPath;
|
|
2656
|
-
}
|
|
2657
|
-
const tempOutputPath = temporaryGitBinaryOutputPath(outputPath);
|
|
2658
|
-
const build = Bun.spawnSync([
|
|
2659
|
-
zigBinary,
|
|
2660
|
-
"build-exe",
|
|
2661
|
-
sourcePath,
|
|
2662
|
-
"-O",
|
|
2663
|
-
"ReleaseFast",
|
|
2664
|
-
`-femit-bin=${tempOutputPath}`
|
|
2665
|
-
], {
|
|
2666
|
-
cwd: dirname7(sourcePath),
|
|
2667
|
-
stdout: "pipe",
|
|
2668
|
-
stderr: "pipe"
|
|
2669
|
-
});
|
|
2670
|
-
if (build.exitCode !== 0 || !existsSync12(tempOutputPath)) {
|
|
2671
|
-
const stderr = build.stderr.toString().trim();
|
|
2672
|
-
const stdout = build.stdout.toString().trim();
|
|
2673
|
-
const details = [stderr, stdout].filter(Boolean).join(`
|
|
2674
|
-
`);
|
|
2675
|
-
throw new Error(`Failed to build native Rig git tools: ${details || `zig exited with code ${build.exitCode}`}`);
|
|
2676
|
-
}
|
|
2677
|
-
chmodSync(tempOutputPath, 493);
|
|
2678
|
-
if (existsSync12(outputPath) && hasMatchingNativeBuildManifestSync(manifestPath, buildKey)) {
|
|
2679
|
-
rmSync3(tempOutputPath, { force: true });
|
|
2680
|
-
chmodSync(outputPath, 493);
|
|
2681
|
-
return outputPath;
|
|
2611
|
+
if (res.status !== 0) {
|
|
2612
|
+
throw new Error(`gh ${args.join(" ")} failed (exit ${res.status}): ${res.stderr}`);
|
|
2682
2613
|
}
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2614
|
+
}
|
|
2615
|
+
function parseDeps(body) {
|
|
2616
|
+
return parseIssueRefs(body, /^depends-on:\s*([^\n]+)/im);
|
|
2617
|
+
}
|
|
2618
|
+
function parseParents(body) {
|
|
2619
|
+
return parseIssueRefs(body, /^parents?:\s*([^\n]+)/im);
|
|
2620
|
+
}
|
|
2621
|
+
function parseIssueRefs(body, pattern) {
|
|
2622
|
+
const match = body.match(pattern);
|
|
2623
|
+
if (!match)
|
|
2624
|
+
return [];
|
|
2625
|
+
return match[1].split(",").map((value) => value.trim()).map((value) => value.replace(/^#/, "").match(/^(\d+)/)?.[1] ?? "").filter((value) => value.length > 0);
|
|
2626
|
+
}
|
|
2627
|
+
function issueTypeFor(labels) {
|
|
2628
|
+
const typed = labels.find((label) => label.startsWith("type:"));
|
|
2629
|
+
if (typed)
|
|
2630
|
+
return typed.slice("type:".length);
|
|
2631
|
+
if (labels.includes("epic"))
|
|
2632
|
+
return "epic";
|
|
2633
|
+
return "task";
|
|
2634
|
+
}
|
|
2635
|
+
function isPlainRecord2(candidate) {
|
|
2636
|
+
return typeof candidate === "object" && candidate !== null && !Array.isArray(candidate);
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
// packages/runtime/src/control-plane/tasks/source-lifecycle.ts
|
|
2640
|
+
function hasRunnableTaskSource(source) {
|
|
2641
|
+
return Boolean(source && typeof source === "object" && !Array.isArray(source));
|
|
2642
|
+
}
|
|
2643
|
+
function cleanString(value) {
|
|
2644
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
2645
|
+
}
|
|
2646
|
+
function taskIdFromSourceIssueId(value) {
|
|
2647
|
+
const raw = cleanString(value);
|
|
2648
|
+
if (!raw)
|
|
2649
|
+
return null;
|
|
2650
|
+
const issueNumber = raw.match(/#([^#\s]+)$/)?.[1];
|
|
2651
|
+
return issueNumber ?? raw;
|
|
2652
|
+
}
|
|
2653
|
+
function resolveSourceTaskId(taskId, sourceTask) {
|
|
2654
|
+
return cleanString(sourceTask?.id) ?? taskIdFromSourceIssueId(sourceTask?.sourceIssueId) ?? taskIdFromSourceIssueId(sourceTask?.source_issue_id) ?? taskId;
|
|
2655
|
+
}
|
|
2656
|
+
async function getPluginTask(projectRoot, taskId) {
|
|
2657
|
+
const ctx = await buildPluginHostContext(projectRoot);
|
|
2658
|
+
const [source] = ctx?.taskSourceRegistry.list() ?? [];
|
|
2659
|
+
if (!hasRunnableTaskSource(source)) {
|
|
2660
|
+
return ctx ? { configured: false, sourceKind: null, task: null } : null;
|
|
2687
2661
|
}
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2662
|
+
const task = source.get ? await source.get(taskId) ?? null : (await source.list()).find((entry) => entry.id === taskId) ?? null;
|
|
2663
|
+
return {
|
|
2664
|
+
configured: true,
|
|
2665
|
+
sourceKind: source.kind,
|
|
2666
|
+
task
|
|
2667
|
+
};
|
|
2691
2668
|
}
|
|
2692
|
-
function
|
|
2693
|
-
|
|
2694
|
-
|
|
2669
|
+
async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
2670
|
+
const pluginResult = await getPluginTask(projectRoot, taskId);
|
|
2671
|
+
if (pluginResult)
|
|
2672
|
+
return pluginResult;
|
|
2673
|
+
const task = await createSourceAwareTaskConfigRecordReader(projectRoot).getTask(taskId);
|
|
2674
|
+
return {
|
|
2675
|
+
configured: false,
|
|
2676
|
+
sourceKind: null,
|
|
2677
|
+
task
|
|
2678
|
+
};
|
|
2679
|
+
}
|
|
2680
|
+
async function updatePluginTaskSourceTask(projectRoot, taskId, update) {
|
|
2681
|
+
const ctx = await buildPluginHostContext(projectRoot);
|
|
2682
|
+
const [source] = ctx?.taskSourceRegistry.list() ?? [];
|
|
2683
|
+
if (!hasRunnableTaskSource(source)) {
|
|
2684
|
+
return ctx ? { taskId, updated: false, source: "none", sourceKind: null, status: null } : null;
|
|
2695
2685
|
}
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
if (
|
|
2699
|
-
|
|
2700
|
-
binaryPath = ensureRigGitBinaryPathSync(preferredGitBinaryOutputPath());
|
|
2701
|
-
} catch (error) {
|
|
2702
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2703
|
-
if (message.includes("rig-git.zig source file not found")) {
|
|
2704
|
-
return { ok: false, error: "rig-git binary not found" };
|
|
2705
|
-
}
|
|
2706
|
-
return { ok: false, error: message };
|
|
2707
|
-
}
|
|
2686
|
+
if (source.updateTask) {
|
|
2687
|
+
await source.updateTask(taskId, update);
|
|
2688
|
+
} else if (update.status && source.updateStatus) {
|
|
2689
|
+
await source.updateStatus(taskId, update.status);
|
|
2708
2690
|
} else {
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
if (message.includes("rig-git.zig source file not found")) {
|
|
2717
|
-
return { ok: false, error: "rig-git binary not found" };
|
|
2718
|
-
}
|
|
2719
|
-
return { ok: false, error: message };
|
|
2720
|
-
}
|
|
2721
|
-
}
|
|
2691
|
+
return {
|
|
2692
|
+
taskId,
|
|
2693
|
+
updated: false,
|
|
2694
|
+
source: "plugin",
|
|
2695
|
+
sourceKind: source.kind,
|
|
2696
|
+
status: null
|
|
2697
|
+
};
|
|
2722
2698
|
}
|
|
2699
|
+
const status = source.get ? (await source.get(taskId))?.status ?? update.status ?? null : update.status ?? null;
|
|
2700
|
+
return {
|
|
2701
|
+
taskId,
|
|
2702
|
+
updated: true,
|
|
2703
|
+
source: "plugin",
|
|
2704
|
+
sourceKind: source.kind,
|
|
2705
|
+
status
|
|
2706
|
+
};
|
|
2707
|
+
}
|
|
2708
|
+
async function updateConfiguredTaskSourceTask(projectRoot, input) {
|
|
2709
|
+
const taskId = resolveSourceTaskId(input.taskId, input.sourceTask);
|
|
2710
|
+
let pluginResult = null;
|
|
2723
2711
|
try {
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2712
|
+
pluginResult = await updatePluginTaskSourceTask(projectRoot, taskId, input.update);
|
|
2713
|
+
} catch (error) {
|
|
2714
|
+
const fallbackUpdated = updateSourceAwareTaskConfigTask(projectRoot, taskId, input.update, {
|
|
2715
|
+
allowLocalTaskConfigStatusFallback: false
|
|
2728
2716
|
});
|
|
2729
|
-
if (
|
|
2730
|
-
|
|
2731
|
-
if (stdoutText) {
|
|
2732
|
-
try {
|
|
2733
|
-
const parsed = JSON.parse(stdoutText);
|
|
2734
|
-
if (!parsed.ok) {
|
|
2735
|
-
return parsed;
|
|
2736
|
-
}
|
|
2737
|
-
} catch {}
|
|
2738
|
-
}
|
|
2739
|
-
const errText = proc.stderr.toString().trim() || `exit code ${proc.exitCode}`;
|
|
2740
|
-
return { ok: false, error: errText };
|
|
2717
|
+
if (!fallbackUpdated) {
|
|
2718
|
+
throw error;
|
|
2741
2719
|
}
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2720
|
+
return {
|
|
2721
|
+
taskId,
|
|
2722
|
+
updated: true,
|
|
2723
|
+
source: "compat",
|
|
2724
|
+
sourceKind: null,
|
|
2725
|
+
status: await readSourceAwareTaskStatus(projectRoot, taskId)
|
|
2726
|
+
};
|
|
2746
2727
|
}
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
const result = runGitNative("branch-name", [repoPath]);
|
|
2750
|
-
if (!result.ok)
|
|
2751
|
-
return null;
|
|
2752
|
-
if ("value" in result && typeof result.value === "string")
|
|
2753
|
-
return result.value;
|
|
2754
|
-
return null;
|
|
2755
|
-
}
|
|
2756
|
-
function nativeChangeCount(repoPath) {
|
|
2757
|
-
const result = runGitNative("change-count", [repoPath]);
|
|
2758
|
-
if (!result.ok)
|
|
2759
|
-
return null;
|
|
2760
|
-
if ("count" in result && typeof result.count === "number")
|
|
2761
|
-
return result.count;
|
|
2762
|
-
return null;
|
|
2763
|
-
}
|
|
2764
|
-
function nativePendingFiles(repoPath) {
|
|
2765
|
-
const result = runGitNative("pending-files", [repoPath]);
|
|
2766
|
-
if (!result.ok)
|
|
2767
|
-
return null;
|
|
2768
|
-
if ("files" in result && Array.isArray(result.files)) {
|
|
2769
|
-
return result.files.map((f) => ({ path: f.path, status: f.status }));
|
|
2728
|
+
if (pluginResult) {
|
|
2729
|
+
return pluginResult;
|
|
2770
2730
|
}
|
|
2771
|
-
|
|
2731
|
+
const updated = updateSourceAwareTaskConfigTask(projectRoot, taskId, input.update);
|
|
2732
|
+
return {
|
|
2733
|
+
taskId,
|
|
2734
|
+
updated,
|
|
2735
|
+
source: updated ? "compat" : "none",
|
|
2736
|
+
sourceKind: null,
|
|
2737
|
+
status: await readSourceAwareTaskStatus(projectRoot, taskId)
|
|
2738
|
+
};
|
|
2772
2739
|
}
|
|
2773
|
-
function
|
|
2774
|
-
const
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2740
|
+
function buildTaskRunLifecycleComment(input) {
|
|
2741
|
+
const lines = [
|
|
2742
|
+
"<!-- rig:status-comment -->",
|
|
2743
|
+
`### Rig status: ${input.status}`,
|
|
2744
|
+
"",
|
|
2745
|
+
input.summary,
|
|
2746
|
+
"",
|
|
2747
|
+
`- Run: ${input.runId}`,
|
|
2748
|
+
`- Status: ${input.status}`
|
|
2749
|
+
];
|
|
2750
|
+
if (input.errorText?.trim()) {
|
|
2751
|
+
lines.push(`- Error: ${input.errorText.trim()}`);
|
|
2752
|
+
}
|
|
2753
|
+
if (input.runtimeWorkspace?.trim()) {
|
|
2754
|
+
lines.push(`- Runtime workspace: ${input.runtimeWorkspace.trim()}`);
|
|
2755
|
+
}
|
|
2756
|
+
if (input.logsDir?.trim()) {
|
|
2757
|
+
lines.push(`- Logs: ${input.logsDir.trim()}`);
|
|
2758
|
+
}
|
|
2759
|
+
if (input.sessionDir?.trim()) {
|
|
2760
|
+
lines.push(`- Session: ${input.sessionDir.trim()}`);
|
|
2761
|
+
}
|
|
2762
|
+
return lines.join(`
|
|
2763
|
+
`);
|
|
2780
2764
|
}
|
|
2765
|
+
|
|
2766
|
+
// packages/runtime/src/control-plane/native/task-state.ts
|
|
2767
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, readdirSync as readdirSync3, statSync as statSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
2768
|
+
import { basename as basename5, resolve as resolve14 } from "path";
|
|
2769
|
+
|
|
2770
|
+
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
2771
|
+
var CANONICAL_TASK_LIFECYCLE_STATUSES = new Set([
|
|
2772
|
+
"draft",
|
|
2773
|
+
"open",
|
|
2774
|
+
"ready",
|
|
2775
|
+
"queued",
|
|
2776
|
+
"in_progress",
|
|
2777
|
+
"under_review",
|
|
2778
|
+
"blocked",
|
|
2779
|
+
"completed",
|
|
2780
|
+
"cancelled"
|
|
2781
|
+
]);
|
|
2781
2782
|
// packages/runtime/src/control-plane/state-sync/reconcile.ts
|
|
2782
2783
|
var STALE_CLAIM_MS = 24 * 60 * 60 * 1000;
|
|
2783
2784
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
@@ -6904,20 +6905,7 @@ function filterTaskChangedFiles(projectRoot, taskId, files, scoped) {
|
|
|
6904
6905
|
if (!taskId) {
|
|
6905
6906
|
return unique(uniqueFiles).sort();
|
|
6906
6907
|
}
|
|
6907
|
-
|
|
6908
|
-
if (!scoped) {
|
|
6909
|
-
return filteredFiles.sort();
|
|
6910
|
-
}
|
|
6911
|
-
const paths = resolveHarnessPaths(projectRoot);
|
|
6912
|
-
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6913
|
-
const scopes = readTaskConfigForInvocation(projectRoot)[taskId]?.scope || [];
|
|
6914
|
-
if (scopes.length === 0) {
|
|
6915
|
-
return [];
|
|
6916
|
-
}
|
|
6917
|
-
return filteredFiles.filter((file) => {
|
|
6918
|
-
const normalized = normalizePathToScope(projectRoot, monorepoRoot || paths.monorepoRoot, file);
|
|
6919
|
-
return scopeMatches(file, scopes) || scopeMatches(normalized, scopes);
|
|
6920
|
-
}).sort();
|
|
6908
|
+
return unique(uniqueFiles).filter((file) => !isGeneratedTaskChangePath(taskId, file)).sort();
|
|
6921
6909
|
}
|
|
6922
6910
|
function resolveTaskMonorepoRoot(projectRoot) {
|
|
6923
6911
|
const runtimeWorkspace = loadRuntimeContextFromEnv()?.workspaceDir || process.env.RIG_TASK_WORKSPACE?.trim();
|
|
@@ -6968,6 +6956,17 @@ function resolveMonorepoBaseCommit(projectRoot, repo) {
|
|
|
6968
6956
|
}
|
|
6969
6957
|
function collectWorkingTreeFiles(projectRoot, repo, baseline) {
|
|
6970
6958
|
const files = new Set;
|
|
6959
|
+
const nativeFiles = nativePendingFiles(repo);
|
|
6960
|
+
if (nativeFiles !== null) {
|
|
6961
|
+
for (const entry of nativeFiles) {
|
|
6962
|
+
const normalized = normalizeChangedFilePath(entry.path);
|
|
6963
|
+
if (!normalized || baseline.has(normalized)) {
|
|
6964
|
+
continue;
|
|
6965
|
+
}
|
|
6966
|
+
files.add(normalized);
|
|
6967
|
+
}
|
|
6968
|
+
return [...files].sort();
|
|
6969
|
+
}
|
|
6971
6970
|
for (const args of [
|
|
6972
6971
|
["diff", "--name-only"],
|
|
6973
6972
|
["diff", "--cached", "--name-only"],
|