immune-brain 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -22
- package/README.zh-CN.md +48 -22
- package/package.json +1 -1
- package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
- package/plugins/immune-brain/.pi-extension/imm-canary-enroll.ts +19 -5
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +18 -2
- package/plugins/immune-brain/.pi-extension/runtime-stub.ts +14 -12
- package/plugins/immune-brain/dist/BASELINE.md +8 -2
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +180 -94
- package/plugins/immune-brain/dist/imm-loop.md +6 -1
- package/plugins/immune-brain/dist/imm-planner.md +59 -5
- package/plugins/immune-brain/runtime/assurance/enrollment_git_base.ts +83 -0
- package/plugins/immune-brain/runtime/claude/interaction.ts +1 -0
- package/plugins/immune-brain/runtime/claude/kernel_ports.ts +39 -27
- package/plugins/immune-brain/runtime/claude/mcp_server.ts +1 -0
- package/plugins/immune-brain/runtime/commands/kernel.ts +7 -1
- package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
- package/plugins/immune-brain/skills/BASELINE.md +8 -2
|
@@ -39,7 +39,7 @@ function probeHost(env = process.env, platform = process.platform, hostVersion)
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// plugins/immune-brain/runtime/plugin_version.ts
|
|
42
|
-
var PLUGIN_VERSION = "4.
|
|
42
|
+
var PLUGIN_VERSION = "4.3.0";
|
|
43
43
|
|
|
44
44
|
// plugins/immune-brain/runtime/claude/interaction.ts
|
|
45
45
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -678,7 +678,7 @@ function parseHookStdin(raw) {
|
|
|
678
678
|
// plugins/immune-brain/runtime/claude/kernel_ports.ts
|
|
679
679
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
680
680
|
import { existsSync as existsSync10, readFileSync as readFileSync14, writeFileSync as writeFileSync8 } from "node:fs";
|
|
681
|
-
import { execFileSync as
|
|
681
|
+
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
682
682
|
import { join as join15 } from "node:path";
|
|
683
683
|
|
|
684
684
|
// plugins/immune-brain/runtime/assurance/coordinator.ts
|
|
@@ -7782,11 +7782,84 @@ function enrollCanaryTask(root, input, registry) {
|
|
|
7782
7782
|
}
|
|
7783
7783
|
}
|
|
7784
7784
|
|
|
7785
|
+
// plugins/immune-brain/runtime/assurance/enrollment_git_base.ts
|
|
7786
|
+
import { execFileSync as execFileSync4, spawnSync as spawnSync4 } from "node:child_process";
|
|
7787
|
+
function git2(root, args, input, env = process.env) {
|
|
7788
|
+
return execFileSync4("git", args, { cwd: root, encoding: "utf8", input, env, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
7789
|
+
}
|
|
7790
|
+
function inspectEnrollmentGitBase(root) {
|
|
7791
|
+
if (git2(root, ["rev-parse", "--is-inside-work-tree"]) !== "true")
|
|
7792
|
+
throw new Error("Enrollment requires a Git working tree");
|
|
7793
|
+
try {
|
|
7794
|
+
return { state: "committed", head: readGitHead(root) };
|
|
7795
|
+
} catch {}
|
|
7796
|
+
const branch = git2(root, ["symbolic-ref", "--no-recurse", "HEAD"]);
|
|
7797
|
+
if (!branch.startsWith("refs/heads/"))
|
|
7798
|
+
throw new Error("Enrollment HEAD must name a local branch");
|
|
7799
|
+
const ref = spawnSync4("git", ["show-ref", "--verify", "--quiet", branch], { cwd: root });
|
|
7800
|
+
const symbolic = spawnSync4("git", ["symbolic-ref", "-q", branch], { cwd: root });
|
|
7801
|
+
if (ref.status !== 1 || symbolic.status !== 1)
|
|
7802
|
+
throw new Error("Enrollment Git HEAD is invalid; only an absent branch can be initialized");
|
|
7803
|
+
return { state: "unborn", branch };
|
|
7804
|
+
}
|
|
7805
|
+
function enrollmentGitBaseNotice(base) {
|
|
7806
|
+
return base.state === "unborn" ? `Git: create an empty initial commit on ${base.branch} before Enrollment; staged files and working tree remain unchanged. This commit remains if later Enrollment fails or is cancelled.` : undefined;
|
|
7807
|
+
}
|
|
7808
|
+
function identityEnv(root) {
|
|
7809
|
+
const configured = (key) => {
|
|
7810
|
+
const result = spawnSync4("git", ["config", "--get", key], { cwd: root, encoding: "utf8" });
|
|
7811
|
+
if (result.status !== 0 && result.status !== 1)
|
|
7812
|
+
throw new Error(`Cannot read Git identity: ${key}`);
|
|
7813
|
+
return result.stdout?.trim() ?? "";
|
|
7814
|
+
};
|
|
7815
|
+
const name = configured("user.name") || "Immune-Brain Enrollment";
|
|
7816
|
+
const email = configured("user.email") || "enrollment@immune-brain.local";
|
|
7817
|
+
return {
|
|
7818
|
+
...process.env,
|
|
7819
|
+
GIT_AUTHOR_NAME: process.env.GIT_AUTHOR_NAME || name,
|
|
7820
|
+
GIT_AUTHOR_EMAIL: process.env.GIT_AUTHOR_EMAIL || email,
|
|
7821
|
+
GIT_COMMITTER_NAME: process.env.GIT_COMMITTER_NAME || name,
|
|
7822
|
+
GIT_COMMITTER_EMAIL: process.env.GIT_COMMITTER_EMAIL || email
|
|
7823
|
+
};
|
|
7824
|
+
}
|
|
7825
|
+
function initializeEnrollmentGitBase(root, input, previous, base, signal) {
|
|
7826
|
+
const assertUnchanged = () => {
|
|
7827
|
+
signal?.throwIfAborted();
|
|
7828
|
+
if (!revalidatePiCanary(root, input, previous).unchanged || JSON.stringify(inspectEnrollmentGitBase(root)) !== JSON.stringify(base))
|
|
7829
|
+
throw new Error("Workspace or Git branch changed after confirmation; retry Enrollment");
|
|
7830
|
+
};
|
|
7831
|
+
assertUnchanged();
|
|
7832
|
+
if (base.state === "committed")
|
|
7833
|
+
return previous;
|
|
7834
|
+
return withKernelStoreLock(root, () => {
|
|
7835
|
+
let created;
|
|
7836
|
+
try {
|
|
7837
|
+
assertUnchanged();
|
|
7838
|
+
if (!previous.intent || previous.backend_claim.present || previous.task_record_v3?.present || previous.workspace.current_working !== null)
|
|
7839
|
+
throw new Error("Empty Git base initialization requires an unowned workspace and a tracked TaskIntent");
|
|
7840
|
+
const tree = git2(root, ["hash-object", "-t", "tree", "-w", "--stdin"], "");
|
|
7841
|
+
const commit = git2(root, ["commit-tree", tree, "-m", "chore: initialize empty Enrollment base"], undefined, identityEnv(root));
|
|
7842
|
+
assertUnchanged();
|
|
7843
|
+
git2(root, ["update-ref", "--no-deref", base.branch, commit, "0".repeat(commit.length)]);
|
|
7844
|
+
created = commit;
|
|
7845
|
+
const current = preparePiCanary(root, input);
|
|
7846
|
+
const withoutGit = ({ digest, git_base_head, git_error, ...owners }) => owners;
|
|
7847
|
+
if (git2(root, ["symbolic-ref", "--no-recurse", "HEAD"]) !== base.branch || current.git_base_head !== commit || JSON.stringify(withoutGit(current)) !== JSON.stringify(withoutGit(previous)))
|
|
7848
|
+
throw new Error("Workspace changed during empty Git base initialization; retry Enrollment");
|
|
7849
|
+
return current;
|
|
7850
|
+
} catch (error) {
|
|
7851
|
+
if (created)
|
|
7852
|
+
throw new Error(`${error instanceof Error ? error.message : String(error)}; empty initial commit ${created} remains`);
|
|
7853
|
+
throw error;
|
|
7854
|
+
}
|
|
7855
|
+
});
|
|
7856
|
+
}
|
|
7857
|
+
|
|
7785
7858
|
// plugins/immune-brain/runtime/assurance/qa.ts
|
|
7786
7859
|
import { createHash as createHash17 } from "node:crypto";
|
|
7787
7860
|
|
|
7788
7861
|
// plugins/immune-brain/runtime/assurance/delivery_workspace.ts
|
|
7789
|
-
import { execFileSync as
|
|
7862
|
+
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
7790
7863
|
import { createHash as createHash16 } from "node:crypto";
|
|
7791
7864
|
import { chmodSync as chmodSync2, lstatSync as lstatSync8, mkdirSync as mkdirSync5, mkdtempSync as mkdtempSync2, readdirSync as readdirSync5, readFileSync as readFileSync10, readlinkSync as readlinkSync2, realpathSync as realpathSync9, rmSync as rmSync5 } from "node:fs";
|
|
7792
7865
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
@@ -7833,8 +7906,8 @@ function isolatedGitEnv(extra = {}) {
|
|
|
7833
7906
|
...extra
|
|
7834
7907
|
};
|
|
7835
7908
|
}
|
|
7836
|
-
function
|
|
7837
|
-
return
|
|
7909
|
+
function git3(cwd, args, extra = {}) {
|
|
7910
|
+
return execFileSync5("git", args, {
|
|
7838
7911
|
cwd,
|
|
7839
7912
|
encoding: "utf8",
|
|
7840
7913
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -7898,24 +7971,24 @@ function assertNoEscapingSymlinks(root, dir = root) {
|
|
|
7898
7971
|
function writeDeliveryTree(sourceRoot, snapshot) {
|
|
7899
7972
|
const indexDirectory = mkdtempSync2(join8(tmpdir3(), "imm-delivery-index-"));
|
|
7900
7973
|
try {
|
|
7901
|
-
|
|
7974
|
+
git3(sourceRoot, ["read-tree", snapshot.base_tree], {
|
|
7902
7975
|
GIT_INDEX_FILE: join8(indexDirectory, "index"),
|
|
7903
7976
|
GIT_DIR: join8(sourceRoot, ".git")
|
|
7904
7977
|
});
|
|
7905
7978
|
for (const [path, entry] of Object.entries(snapshot.changed_paths)) {
|
|
7906
7979
|
if (entry.oid && entry.mode) {
|
|
7907
|
-
|
|
7980
|
+
git3(sourceRoot, ["update-index", "--add", "--cacheinfo", `${entry.mode},${entry.oid},${path}`], {
|
|
7908
7981
|
GIT_INDEX_FILE: join8(indexDirectory, "index"),
|
|
7909
7982
|
GIT_DIR: join8(sourceRoot, ".git")
|
|
7910
7983
|
});
|
|
7911
7984
|
} else {
|
|
7912
|
-
|
|
7985
|
+
git3(sourceRoot, ["update-index", "--force-remove", "--", path], {
|
|
7913
7986
|
GIT_INDEX_FILE: join8(indexDirectory, "index"),
|
|
7914
7987
|
GIT_DIR: join8(sourceRoot, ".git")
|
|
7915
7988
|
});
|
|
7916
7989
|
}
|
|
7917
7990
|
}
|
|
7918
|
-
const next =
|
|
7991
|
+
const next = git3(sourceRoot, ["write-tree"], {
|
|
7919
7992
|
GIT_INDEX_FILE: join8(indexDirectory, "index"),
|
|
7920
7993
|
GIT_DIR: join8(sourceRoot, ".git")
|
|
7921
7994
|
});
|
|
@@ -7949,9 +8022,9 @@ function workspaceSeal(root) {
|
|
|
7949
8022
|
function assertDeliveryClean(root, tree, seal, writablePaths = []) {
|
|
7950
8023
|
assertTree(tree);
|
|
7951
8024
|
if (seal === undefined) {
|
|
7952
|
-
if (
|
|
8025
|
+
if (git3(root, ["status", "--porcelain", "--untracked-files=all", "--ignored=matching"]))
|
|
7953
8026
|
throw new DeliveryWorkspaceError("delivery workspace was contaminated");
|
|
7954
|
-
if (
|
|
8027
|
+
if (git3(root, ["rev-parse", "HEAD^{tree}"]) !== tree)
|
|
7955
8028
|
throw new DeliveryWorkspaceError("delivery workspace tree drifted from the frozen identity");
|
|
7956
8029
|
return;
|
|
7957
8030
|
}
|
|
@@ -7989,7 +8062,7 @@ function materializeDeliveryWorkspace(sourceRoot, tree) {
|
|
|
7989
8062
|
const cleanup = () => removeTaskOwnedTree(dest);
|
|
7990
8063
|
try {
|
|
7991
8064
|
mkdirSync5(dest, { recursive: true });
|
|
7992
|
-
const commit =
|
|
8065
|
+
const commit = git3(sourceRoot, ["commit-tree", tree, "-m", `delivery ${tree}`], {
|
|
7993
8066
|
GIT_DIR: join8(sourceRoot, ".git"),
|
|
7994
8067
|
GIT_AUTHOR_NAME: "Immune-Brain Assurance",
|
|
7995
8068
|
GIT_AUTHOR_EMAIL: "assurance@immune-brain.local",
|
|
@@ -8000,10 +8073,10 @@ function materializeDeliveryWorkspace(sourceRoot, tree) {
|
|
|
8000
8073
|
});
|
|
8001
8074
|
if (!GIT_OBJECT_ID4.test(commit))
|
|
8002
8075
|
throw new DeliveryWorkspaceError("delivery commit write failed");
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
const got =
|
|
8076
|
+
git3(dest, ["init", "-q"]);
|
|
8077
|
+
git3(dest, ["fetch", "--depth=1", `file://${resolve9(sourceRoot)}`, `${commit}:refs/heads/delivery`]);
|
|
8078
|
+
git3(dest, ["checkout", "-q", "delivery"]);
|
|
8079
|
+
const got = git3(dest, ["rev-parse", "HEAD^{tree}"]);
|
|
8007
8080
|
if (got !== tree)
|
|
8008
8081
|
throw new DeliveryWorkspaceError("delivery materialization does not match the frozen tree");
|
|
8009
8082
|
assertNoEscapingSymlinks(dest);
|
|
@@ -8372,14 +8445,14 @@ function deriveAuthorizationOperation(input) {
|
|
|
8372
8445
|
}
|
|
8373
8446
|
|
|
8374
8447
|
// plugins/immune-brain/runtime/staged_intent.ts
|
|
8375
|
-
import { execFileSync as
|
|
8448
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
8376
8449
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "node:fs";
|
|
8377
8450
|
import { join as join10 } from "node:path";
|
|
8378
8451
|
function captureStagedIntent(root, relativePath) {
|
|
8379
8452
|
return {
|
|
8380
8453
|
path: relativePath,
|
|
8381
8454
|
bytes: readFileSync11(join10(root, relativePath)),
|
|
8382
|
-
index_state:
|
|
8455
|
+
index_state: execFileSync6("git", ["ls-files", "--stage", "-z", "--", relativePath], {
|
|
8383
8456
|
cwd: root,
|
|
8384
8457
|
stdio: ["ignore", "pipe", "pipe"]
|
|
8385
8458
|
})
|
|
@@ -8387,12 +8460,12 @@ function captureStagedIntent(root, relativePath) {
|
|
|
8387
8460
|
}
|
|
8388
8461
|
function restoreStagedIntent(root, snapshot) {
|
|
8389
8462
|
writeFileSync5(join10(root, snapshot.path), snapshot.bytes);
|
|
8390
|
-
|
|
8463
|
+
execFileSync6("git", ["update-index", "--force-remove", "--", snapshot.path], {
|
|
8391
8464
|
cwd: root,
|
|
8392
8465
|
stdio: ["ignore", "pipe", "pipe"]
|
|
8393
8466
|
});
|
|
8394
8467
|
if (snapshot.index_state.length > 0) {
|
|
8395
|
-
|
|
8468
|
+
execFileSync6("git", ["update-index", "-z", "--index-info"], {
|
|
8396
8469
|
cwd: root,
|
|
8397
8470
|
input: snapshot.index_state,
|
|
8398
8471
|
stdio: ["pipe", "ignore", "pipe"]
|
|
@@ -8402,7 +8475,7 @@ function restoreStagedIntent(root, snapshot) {
|
|
|
8402
8475
|
if (!restoredBytes.equals(snapshot.bytes)) {
|
|
8403
8476
|
throw new Error("failed to restore prior intent bytes");
|
|
8404
8477
|
}
|
|
8405
|
-
const restoredIndex =
|
|
8478
|
+
const restoredIndex = execFileSync6("git", ["ls-files", "--stage", "-z", "--", snapshot.path], {
|
|
8406
8479
|
cwd: root,
|
|
8407
8480
|
stdio: ["ignore", "pipe", "pipe"]
|
|
8408
8481
|
});
|
|
@@ -9709,7 +9782,7 @@ async function revalidatePendingChildBeforeWrite(root, gh, childNumber, childTas
|
|
|
9709
9782
|
import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync13 } from "node:fs";
|
|
9710
9783
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
9711
9784
|
import { join as join12 } from "node:path";
|
|
9712
|
-
import { spawnSync as
|
|
9785
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
9713
9786
|
|
|
9714
9787
|
// plugins/immune-brain/runtime/kernel/batch_authority.ts
|
|
9715
9788
|
import { createHash as createHash18 } from "node:crypto";
|
|
@@ -10486,7 +10559,7 @@ function isOwnBatchClaim(root, existingBatch, taskId, batchBranch) {
|
|
|
10486
10559
|
const currentTaskId = workspaceOwner || (claim?.lifecycle_status === "active" ? claim?.task_id : null);
|
|
10487
10560
|
if (currentTaskId !== taskId || !claim)
|
|
10488
10561
|
return false;
|
|
10489
|
-
const branch =
|
|
10562
|
+
const branch = spawnSync5("git", ["-C", root, "branch", "--show-current"], { encoding: "utf8" }).stdout.trim();
|
|
10490
10563
|
if (branch !== batchBranch)
|
|
10491
10564
|
return false;
|
|
10492
10565
|
const childInBatch = existingBatch.children.find((c) => c.task_id === taskId);
|
|
@@ -10543,7 +10616,7 @@ function authorizedScopeOf(root, taskId, state) {
|
|
|
10543
10616
|
return scope;
|
|
10544
10617
|
}
|
|
10545
10618
|
function porcelainEntries(root) {
|
|
10546
|
-
const statusProc =
|
|
10619
|
+
const statusProc = spawnSync5("git", ["-C", root, "status", "--porcelain=v1", "-z", "--no-renames", "--untracked-files=all"], { encoding: "utf8" });
|
|
10547
10620
|
if (statusProc.status !== 0)
|
|
10548
10621
|
return null;
|
|
10549
10622
|
const entries = [];
|
|
@@ -10674,7 +10747,7 @@ async function projectBatchPreflight(options) {
|
|
|
10674
10747
|
} catch (err) {
|
|
10675
10748
|
return reject("git_head_unreadable", err instanceof Error ? err.message : String(err));
|
|
10676
10749
|
}
|
|
10677
|
-
const branchExists =
|
|
10750
|
+
const branchExists = spawnSync5("git", ["-C", root, "show-ref", "--verify", "--quiet", `refs/heads/${batchBranch}`]);
|
|
10678
10751
|
if (branchExists.status === 0 && !existingBatch)
|
|
10679
10752
|
return reject("branch_already_exists", batchBranch);
|
|
10680
10753
|
const statusEntries = porcelainEntries(root);
|
|
@@ -10859,12 +10932,12 @@ async function authorizeBatch(options) {
|
|
|
10859
10932
|
}
|
|
10860
10933
|
|
|
10861
10934
|
// plugins/immune-brain/runtime/unattended/batch_runner.ts
|
|
10862
|
-
import { spawnSync as
|
|
10935
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
10863
10936
|
import { existsSync as existsSync9 } from "node:fs";
|
|
10864
10937
|
import { join as join14 } from "node:path";
|
|
10865
10938
|
|
|
10866
10939
|
// plugins/immune-brain/runtime/unattended/batch_git.ts
|
|
10867
|
-
import { spawnSync as
|
|
10940
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
10868
10941
|
import { createHash as createHash20, randomUUID as randomUUID8 } from "node:crypto";
|
|
10869
10942
|
import {
|
|
10870
10943
|
constants as constants6,
|
|
@@ -10889,7 +10962,7 @@ var DEFAULT_GIT_ENV = {
|
|
|
10889
10962
|
function runBatchGitPreflight(input) {
|
|
10890
10963
|
const { root, initiative_slug: initiativeSlug, base_head: baseHead } = input;
|
|
10891
10964
|
const branch = `imm/${initiativeSlug}`;
|
|
10892
|
-
const toplevelResult =
|
|
10965
|
+
const toplevelResult = spawnSync6("git", ["-C", root, "rev-parse", "--show-toplevel"], {
|
|
10893
10966
|
encoding: "utf8",
|
|
10894
10967
|
stdio: ["ignore", "pipe", "pipe"]
|
|
10895
10968
|
});
|
|
@@ -10927,7 +11000,7 @@ function runBatchGitPreflight(input) {
|
|
|
10927
11000
|
message: `unsupported index flags (assume-unchanged/skip-worktree) detected: ${flaggedPreflight.join(", ")}`
|
|
10928
11001
|
};
|
|
10929
11002
|
}
|
|
10930
|
-
const statusResult =
|
|
11003
|
+
const statusResult = spawnSync6("git", ["-C", root, "status", "--porcelain", "--untracked-files=all", "--ignore-submodules=none"], {
|
|
10931
11004
|
encoding: "utf8",
|
|
10932
11005
|
stdio: ["ignore", "pipe", "pipe"]
|
|
10933
11006
|
});
|
|
@@ -10945,7 +11018,7 @@ function runBatchGitPreflight(input) {
|
|
|
10945
11018
|
message: "working tree is dirty before batch preflight"
|
|
10946
11019
|
};
|
|
10947
11020
|
}
|
|
10948
|
-
const headResult =
|
|
11021
|
+
const headResult = spawnSync6("git", ["-C", root, "rev-parse", "--verify", "HEAD^{commit}"], {
|
|
10949
11022
|
encoding: "utf8",
|
|
10950
11023
|
stdio: ["ignore", "pipe", "pipe"]
|
|
10951
11024
|
});
|
|
@@ -10956,11 +11029,11 @@ function runBatchGitPreflight(input) {
|
|
|
10956
11029
|
message: "HEAD is uncommitted or not a valid commit"
|
|
10957
11030
|
};
|
|
10958
11031
|
}
|
|
10959
|
-
const branchCheck =
|
|
11032
|
+
const branchCheck = spawnSync6("git", ["-C", root, "show-ref", "--verify", "--quiet", `refs/heads/${branch}`], { stdio: ["ignore", "ignore", "ignore"] });
|
|
10960
11033
|
if (branchCheck.status === 0) {
|
|
10961
11034
|
const settled = findSettledBatchRecord(root, initiativeSlug);
|
|
10962
|
-
const currentBranch =
|
|
10963
|
-
if (findExistingActiveBatch(root, initiativeSlug) === null && settled?.branch === branch && currentBranch.status === 0 && currentBranch.stdout.trim() === branch && headResult.stdout.trim() === baseHead &&
|
|
11035
|
+
const currentBranch = spawnSync6("git", ["-C", root, "symbolic-ref", "--short", "HEAD"], { encoding: "utf8" });
|
|
11036
|
+
if (findExistingActiveBatch(root, initiativeSlug) === null && settled?.branch === branch && currentBranch.status === 0 && currentBranch.stdout.trim() === branch && headResult.stdout.trim() === baseHead && spawnSync6("git", ["-C", root, "merge-base", "--is-ancestor", expectedBatchHead(settled), baseHead]).status === 0)
|
|
10964
11037
|
return { ok: true, branch };
|
|
10965
11038
|
return {
|
|
10966
11039
|
ok: false,
|
|
@@ -10968,25 +11041,25 @@ function runBatchGitPreflight(input) {
|
|
|
10968
11041
|
message: `branch refs/heads/${branch} already exists`
|
|
10969
11042
|
};
|
|
10970
11043
|
}
|
|
10971
|
-
const originalBranchResult =
|
|
11044
|
+
const originalBranchResult = spawnSync6("git", ["-C", root, "symbolic-ref", "--short", "HEAD"], {
|
|
10972
11045
|
encoding: "utf8",
|
|
10973
11046
|
stdio: ["ignore", "pipe", "pipe"]
|
|
10974
11047
|
});
|
|
10975
11048
|
const originalBranch = originalBranchResult.stdout.trim();
|
|
10976
|
-
const checkoutResult =
|
|
11049
|
+
const checkoutResult = spawnSync6("git", ["-C", root, "-c", "core.hooksPath=/dev/null", "checkout", "-b", branch, baseHead], {
|
|
10977
11050
|
encoding: "utf8",
|
|
10978
11051
|
stdio: ["ignore", "pipe", "pipe"],
|
|
10979
11052
|
env: DEFAULT_GIT_ENV
|
|
10980
11053
|
});
|
|
10981
11054
|
if (checkoutResult.status !== 0) {
|
|
10982
11055
|
const stderr = checkoutResult.stderr?.trim() || "";
|
|
10983
|
-
const branchExists = stderr.includes("already exists") ||
|
|
10984
|
-
const currentBranchCheck =
|
|
11056
|
+
const branchExists = stderr.includes("already exists") || spawnSync6("git", ["-C", root, "show-ref", "--verify", "--quiet", `refs/heads/${branch}`]).status === 0;
|
|
11057
|
+
const currentBranchCheck = spawnSync6("git", ["-C", root, "symbolic-ref", "--short", "HEAD"], {
|
|
10985
11058
|
encoding: "utf8",
|
|
10986
11059
|
stdio: ["ignore", "pipe", "pipe"]
|
|
10987
11060
|
}).stdout.trim();
|
|
10988
11061
|
if (currentBranchCheck === branch && originalBranch && originalBranch !== branch) {
|
|
10989
|
-
|
|
11062
|
+
spawnSync6("git", ["-C", root, "-c", "core.hooksPath=/dev/null", "checkout", originalBranch], {
|
|
10990
11063
|
stdio: ["ignore", "ignore", "ignore"]
|
|
10991
11064
|
});
|
|
10992
11065
|
}
|
|
@@ -11009,7 +11082,7 @@ function hasBoundaryWhitespace(path) {
|
|
|
11009
11082
|
return path.split("/").some((segment) => segment.trim() !== segment || segment.length === 0);
|
|
11010
11083
|
}
|
|
11011
11084
|
function getUnsupportedIndexFlags(root) {
|
|
11012
|
-
const result =
|
|
11085
|
+
const result = spawnSync6("git", ["-C", root, "ls-files", "-v", "-z", "--"], {
|
|
11013
11086
|
encoding: "utf8",
|
|
11014
11087
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11015
11088
|
});
|
|
@@ -11043,13 +11116,13 @@ function isPathAllowedForChild(path, taskId, scopeHint) {
|
|
|
11043
11116
|
});
|
|
11044
11117
|
}
|
|
11045
11118
|
function getChangedProjectPaths(root) {
|
|
11046
|
-
const tracked =
|
|
11119
|
+
const tracked = spawnSync6("git", ["-C", root, "diff-index", "--name-only", "-z", "--ignore-submodules=none", "HEAD", "--"], {
|
|
11047
11120
|
encoding: "utf8",
|
|
11048
11121
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11049
11122
|
});
|
|
11050
11123
|
if (tracked.status !== 0)
|
|
11051
11124
|
throw new Error("failed to inspect tracked diff vs HEAD");
|
|
11052
|
-
const untracked =
|
|
11125
|
+
const untracked = spawnSync6("git", ["-C", root, "ls-files", "--others", "--exclude-standard", "-z", "--"], {
|
|
11053
11126
|
encoding: "utf8",
|
|
11054
11127
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11055
11128
|
});
|
|
@@ -11059,7 +11132,7 @@ function getChangedProjectPaths(root) {
|
|
|
11059
11132
|
return [...new Set([...splitZ(tracked.stdout), ...splitZ(untracked.stdout)])];
|
|
11060
11133
|
}
|
|
11061
11134
|
function getStagedProjectPaths(root) {
|
|
11062
|
-
const staged =
|
|
11135
|
+
const staged = spawnSync6("git", ["-C", root, "diff-index", "--cached", "--name-only", "-z", "--ignore-submodules=none", "HEAD", "--"], {
|
|
11063
11136
|
encoding: "utf8",
|
|
11064
11137
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11065
11138
|
});
|
|
@@ -11068,13 +11141,13 @@ function getStagedProjectPaths(root) {
|
|
|
11068
11141
|
return staged.stdout.split("\x00").filter((p) => p.length > 0);
|
|
11069
11142
|
}
|
|
11070
11143
|
function getUnstagedProjectPaths(root) {
|
|
11071
|
-
const diffFiles =
|
|
11144
|
+
const diffFiles = spawnSync6("git", ["-C", root, "diff-files", "--name-only", "-z", "--ignore-submodules=none", "--"], {
|
|
11072
11145
|
encoding: "utf8",
|
|
11073
11146
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11074
11147
|
});
|
|
11075
11148
|
if (diffFiles.status !== 0)
|
|
11076
11149
|
throw new Error("failed to inspect unstaged tracked changes");
|
|
11077
|
-
const untracked =
|
|
11150
|
+
const untracked = spawnSync6("git", ["-C", root, "ls-files", "--others", "--exclude-standard", "-z", "--"], {
|
|
11078
11151
|
encoding: "utf8",
|
|
11079
11152
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11080
11153
|
});
|
|
@@ -11084,7 +11157,7 @@ function getUnstagedProjectPaths(root) {
|
|
|
11084
11157
|
return [...new Set([...splitZ(diffFiles.stdout), ...splitZ(untracked.stdout)])];
|
|
11085
11158
|
}
|
|
11086
11159
|
function getCommittedDeltaPaths(root) {
|
|
11087
|
-
const delta =
|
|
11160
|
+
const delta = spawnSync6("git", ["-C", root, "diff-tree", "--no-commit-id", "--name-only", "-z", "-r", "HEAD~1", "HEAD"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
11088
11161
|
if (delta.status !== 0)
|
|
11089
11162
|
throw new Error("failed to inspect committed tree delta");
|
|
11090
11163
|
return delta.stdout.split("\x00").filter((p) => p.length > 0);
|
|
@@ -11190,7 +11263,7 @@ async function commitBatchChild(input) {
|
|
|
11190
11263
|
const goal = typeof intentSnapshot.goal === "string" ? intentSnapshot.goal : "";
|
|
11191
11264
|
const scopeHint = Array.isArray(intentSnapshot.scope_hint) ? intentSnapshot.scope_hint.filter((s) => typeof s === "string") : [];
|
|
11192
11265
|
if (expectedBranch !== undefined) {
|
|
11193
|
-
const currentBranchResult =
|
|
11266
|
+
const currentBranchResult = spawnSync6("git", ["-C", root, "symbolic-ref", "--short", "HEAD"], {
|
|
11194
11267
|
encoding: "utf8",
|
|
11195
11268
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11196
11269
|
});
|
|
@@ -11199,7 +11272,7 @@ async function commitBatchChild(input) {
|
|
|
11199
11272
|
throw new Error(`batch_head_lineage_broken: current branch ${currentBranch} does not match expected branch ${expectedBranch}`);
|
|
11200
11273
|
}
|
|
11201
11274
|
}
|
|
11202
|
-
const currentHeadResult =
|
|
11275
|
+
const currentHeadResult = spawnSync6("git", ["-C", root, "rev-parse", "HEAD"], {
|
|
11203
11276
|
encoding: "utf8",
|
|
11204
11277
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11205
11278
|
});
|
|
@@ -11218,7 +11291,7 @@ async function commitBatchChild(input) {
|
|
|
11218
11291
|
}
|
|
11219
11292
|
const pathsToStage = getUnstagedProjectPaths(root);
|
|
11220
11293
|
if (pathsToStage.length > 0) {
|
|
11221
|
-
const addResult =
|
|
11294
|
+
const addResult = spawnSync6("git", ["-C", root, "--literal-pathspecs", "add", "-A", "--", ...pathsToStage], {
|
|
11222
11295
|
encoding: "utf8",
|
|
11223
11296
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11224
11297
|
});
|
|
@@ -11233,7 +11306,7 @@ async function commitBatchChild(input) {
|
|
|
11233
11306
|
const staged = getStagedProjectPaths(root);
|
|
11234
11307
|
const stagedOutside = staged.filter((p) => !isPathAllowedForChild(p, taskId, scopeHint));
|
|
11235
11308
|
if (stagedOutside.length > 0) {
|
|
11236
|
-
|
|
11309
|
+
spawnSync6("git", ["-C", root, "reset", "--quiet"], { stdio: ["ignore", "ignore", "ignore"] });
|
|
11237
11310
|
throw new Error("dirty_outside_scope");
|
|
11238
11311
|
}
|
|
11239
11312
|
const record = auditPair.record;
|
|
@@ -11251,7 +11324,7 @@ async function commitBatchChild(input) {
|
|
|
11251
11324
|
|
|
11252
11325
|
Immune-Brain-Batch: ${batchId}
|
|
11253
11326
|
`;
|
|
11254
|
-
const commitResult =
|
|
11327
|
+
const commitResult = spawnSync6("git", ["-C", root, "-c", "core.hooksPath=/dev/null", "commit", "--no-verify", "-F", "-"], {
|
|
11255
11328
|
input: commitMessage,
|
|
11256
11329
|
encoding: "utf8",
|
|
11257
11330
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -11260,7 +11333,7 @@ Immune-Brain-Batch: ${batchId}
|
|
|
11260
11333
|
if (commitResult.status !== 0) {
|
|
11261
11334
|
throw new Error(`commit failed for child ${taskId}: ${commitResult.stderr?.trim() || "git commit failed"}`);
|
|
11262
11335
|
}
|
|
11263
|
-
const newHeadResult =
|
|
11336
|
+
const newHeadResult = spawnSync6("git", ["-C", root, "rev-parse", "HEAD"], {
|
|
11264
11337
|
encoding: "utf8",
|
|
11265
11338
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11266
11339
|
});
|
|
@@ -11268,7 +11341,7 @@ Immune-Brain-Batch: ${batchId}
|
|
|
11268
11341
|
if (newHeadResult.status !== 0 || !newHead || newHead === expectedHead) {
|
|
11269
11342
|
throw new Error("commit_failed");
|
|
11270
11343
|
}
|
|
11271
|
-
const parentsResult =
|
|
11344
|
+
const parentsResult = spawnSync6("git", ["-C", root, "rev-parse", "HEAD^@"], {
|
|
11272
11345
|
encoding: "utf8",
|
|
11273
11346
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11274
11347
|
});
|
|
@@ -11301,7 +11374,7 @@ async function lookupBatchCommit(input) {
|
|
|
11301
11374
|
let candidates = [];
|
|
11302
11375
|
let evidenceBacked = false;
|
|
11303
11376
|
if (evidence && evidence.commit) {
|
|
11304
|
-
const direct =
|
|
11377
|
+
const direct = spawnSync6("git", ["-C", root, "log", "-n", "1", `--format=${FORMAT}`, evidence.commit, "--"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
11305
11378
|
if (direct.status !== 0) {
|
|
11306
11379
|
throw new Error(`failed to inspect batch commit for ${taskId}: ${direct.stderr?.trim() || "git log failed"}`);
|
|
11307
11380
|
}
|
|
@@ -11314,7 +11387,7 @@ async function lookupBatchCommit(input) {
|
|
|
11314
11387
|
}
|
|
11315
11388
|
}
|
|
11316
11389
|
if (!candidates.length) {
|
|
11317
|
-
const result =
|
|
11390
|
+
const result = spawnSync6("git", [
|
|
11318
11391
|
"-C",
|
|
11319
11392
|
root,
|
|
11320
11393
|
"log",
|
|
@@ -11351,7 +11424,7 @@ async function lookupBatchCommit(input) {
|
|
|
11351
11424
|
throw new Error(`batch_head_lineage_broken: adopted commit author ${match.authorName} does not match batch authority ${DEFAULT_GIT_ENV.GIT_AUTHOR_NAME}`);
|
|
11352
11425
|
}
|
|
11353
11426
|
if (expectedBranch !== undefined) {
|
|
11354
|
-
const currentBranchResult =
|
|
11427
|
+
const currentBranchResult = spawnSync6("git", ["-C", root, "symbolic-ref", "--short", "HEAD"], {
|
|
11355
11428
|
encoding: "utf8",
|
|
11356
11429
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11357
11430
|
});
|
|
@@ -11361,7 +11434,7 @@ async function lookupBatchCommit(input) {
|
|
|
11361
11434
|
}
|
|
11362
11435
|
}
|
|
11363
11436
|
if (expectedHead !== undefined) {
|
|
11364
|
-
const currentHeadResult =
|
|
11437
|
+
const currentHeadResult = spawnSync6("git", ["-C", root, "rev-parse", "HEAD"], {
|
|
11365
11438
|
encoding: "utf8",
|
|
11366
11439
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11367
11440
|
});
|
|
@@ -11369,7 +11442,7 @@ async function lookupBatchCommit(input) {
|
|
|
11369
11442
|
if (currentHead !== commit) {
|
|
11370
11443
|
throw new Error(`batch_head_lineage_broken: current HEAD ${currentHead} diverged from adopted commit ${commit}`);
|
|
11371
11444
|
}
|
|
11372
|
-
const parentsResult =
|
|
11445
|
+
const parentsResult = spawnSync6("git", ["-C", root, "rev-parse", `${commit}^@`], {
|
|
11373
11446
|
encoding: "utf8",
|
|
11374
11447
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11375
11448
|
});
|
|
@@ -11387,7 +11460,7 @@ async function lookupBatchCommit(input) {
|
|
|
11387
11460
|
throw new Error(`batch_head_lineage_broken: adopted commit task lifecycle is not done: ${lifecycle}`);
|
|
11388
11461
|
}
|
|
11389
11462
|
const scopeHint = Array.isArray(auditPair.record.intent_snapshot.scope_hint) ? auditPair.record.intent_snapshot.scope_hint.filter((s) => typeof s === "string") : [];
|
|
11390
|
-
const deltaResult =
|
|
11463
|
+
const deltaResult = spawnSync6("git", ["-C", root, "diff-tree", "--no-commit-id", "--name-only", "-z", "-r", expectedHead, commit], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
11391
11464
|
if (deltaResult.status !== 0) {
|
|
11392
11465
|
throw new Error("batch_head_lineage_broken: failed to inspect adopted commit delta");
|
|
11393
11466
|
}
|
|
@@ -11484,14 +11557,14 @@ function externalHeadDriftMessage(root, record) {
|
|
|
11484
11557
|
if (!existsSync9(join14(root, ".git")))
|
|
11485
11558
|
return null;
|
|
11486
11559
|
const head = record.commits.length ? record.commits[record.commits.length - 1] : record.base_head;
|
|
11487
|
-
const headCheck =
|
|
11560
|
+
const headCheck = spawnSync7("git", ["-C", root, "rev-parse", "HEAD"], {
|
|
11488
11561
|
encoding: "utf8",
|
|
11489
11562
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11490
11563
|
});
|
|
11491
11564
|
if (headCheck.status === 0 && headCheck.stdout.trim() && headCheck.stdout.trim() !== head) {
|
|
11492
11565
|
return `batch_head_lineage_broken: current HEAD ${headCheck.stdout.trim()} does not match expected batch head ${head}`;
|
|
11493
11566
|
}
|
|
11494
|
-
const branchCheck =
|
|
11567
|
+
const branchCheck = spawnSync7("git", ["-C", root, "symbolic-ref", "--short", "HEAD"], {
|
|
11495
11568
|
encoding: "utf8",
|
|
11496
11569
|
stdio: ["ignore", "pipe", "pipe"]
|
|
11497
11570
|
});
|
|
@@ -11523,7 +11596,7 @@ async function validatePersistedRun(input, record) {
|
|
|
11523
11596
|
});
|
|
11524
11597
|
if (!evidence || evidence.commit !== child.commit) {
|
|
11525
11598
|
if (evidence === null && typeof child.commit === "string" && child.commit.length > 0 && existsSync9(join14(input.root, ".git"))) {
|
|
11526
|
-
const reach =
|
|
11599
|
+
const reach = spawnSync7("git", ["-C", input.root, "merge-base", "--is-ancestor", child.commit, "HEAD"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
11527
11600
|
if (reach.status !== 0) {
|
|
11528
11601
|
throw new Error(`batch_head_lineage_broken: recorded commit ${child.commit} for ${child.task_id} is no longer reachable from HEAD`);
|
|
11529
11602
|
}
|
|
@@ -12275,10 +12348,10 @@ function stagePlanningArtifactTransition(root, record) {
|
|
|
12275
12348
|
intentArchive,
|
|
12276
12349
|
...specActive ? [specActive, specActive.replace("docs/specs/", "docs/specs/archive/")] : []
|
|
12277
12350
|
];
|
|
12278
|
-
const paths = candidates.filter((path) => existsSync10(join15(root, path)) ||
|
|
12351
|
+
const paths = candidates.filter((path) => existsSync10(join15(root, path)) || execFileSync7("git", ["ls-files", "--cached", "--", path], { cwd: root, encoding: "utf8" }).trim().length > 0);
|
|
12279
12352
|
if (paths.length === 0)
|
|
12280
12353
|
return;
|
|
12281
|
-
|
|
12354
|
+
execFileSync7("git", ["add", "--", ...paths], { cwd: root, stdio: ["ignore", "pipe", "pipe"] });
|
|
12282
12355
|
}
|
|
12283
12356
|
async function mintCapability(registry, input) {
|
|
12284
12357
|
const action = capabilityActionFor({
|
|
@@ -12412,13 +12485,15 @@ class ClaudeRuntime {
|
|
|
12412
12485
|
}
|
|
12413
12486
|
async enroll(taskId, meta) {
|
|
12414
12487
|
const now = new Date().toISOString();
|
|
12415
|
-
|
|
12488
|
+
let preparation = await preparePiCanary(this.cwd, { task_id: taskId, now });
|
|
12416
12489
|
const intent = await readTaskIntentForRecord(this.cwd, taskId);
|
|
12490
|
+
const gitBase = inspectEnrollmentGitBase(this.cwd);
|
|
12417
12491
|
const gate = await this.gate("enroll", { ...meta, taskId }, {
|
|
12418
12492
|
risk: intent.intent.risk,
|
|
12419
12493
|
intentRevision: preparation.intent?.revision,
|
|
12420
12494
|
intentContentHash: preparation.intent?.content_hash,
|
|
12421
|
-
bindingDigest: preparation.digest
|
|
12495
|
+
bindingDigest: preparation.digest,
|
|
12496
|
+
gitBaseNotice: enrollmentGitBaseNotice(gitBase)
|
|
12422
12497
|
});
|
|
12423
12498
|
const { unchanged } = await revalidatePiCanary(this.cwd, { task_id: taskId, now }, preparation);
|
|
12424
12499
|
if (!unchanged)
|
|
@@ -12426,33 +12501,43 @@ class ClaudeRuntime {
|
|
|
12426
12501
|
if (!preparation.intent)
|
|
12427
12502
|
throw new Error("enrollment requires a readable TaskIntent");
|
|
12428
12503
|
throwIfCancelled(meta.signal);
|
|
12429
|
-
|
|
12430
|
-
const
|
|
12431
|
-
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
|
|
12438
|
-
|
|
12439
|
-
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
|
|
12444
|
-
|
|
12445
|
-
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
|
|
12449
|
-
|
|
12450
|
-
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
|
|
12504
|
+
preparation = initializeEnrollmentGitBase(this.cwd, { task_id: taskId, now }, preparation, gitBase, meta.signal);
|
|
12505
|
+
const gitBaseNote = gitBase.state === "unborn" ? `; empty initial commit ${preparation.git_base_head} remains` : "";
|
|
12506
|
+
try {
|
|
12507
|
+
if (!preparation.intent)
|
|
12508
|
+
throw new Error("Enrollment requires a readable TaskIntent");
|
|
12509
|
+
const nonce = enrollmentNonce();
|
|
12510
|
+
const binding = {
|
|
12511
|
+
task_id: taskId,
|
|
12512
|
+
intent_path: preparation.intent.path,
|
|
12513
|
+
intent_revision: preparation.intent.revision,
|
|
12514
|
+
intent_content_hash: preparation.intent.content_hash,
|
|
12515
|
+
preparation_digest: preparation.digest,
|
|
12516
|
+
actor_id: LITERAL_USER_ACTOR_ID,
|
|
12517
|
+
confirmation_ref: gate.confirmation_ref,
|
|
12518
|
+
expires_at: new Date(Date.now() + 10 * 60 * 1000).toISOString(),
|
|
12519
|
+
nonce
|
|
12520
|
+
};
|
|
12521
|
+
const capability = this.enrollmentRegistry.issue(binding);
|
|
12522
|
+
const input = {
|
|
12523
|
+
task_id: taskId,
|
|
12524
|
+
intent_path: binding.intent_path,
|
|
12525
|
+
intent_revision: binding.intent_revision,
|
|
12526
|
+
preparation_digest: binding.preparation_digest,
|
|
12527
|
+
capability,
|
|
12528
|
+
capability_binding: binding,
|
|
12529
|
+
now
|
|
12530
|
+
};
|
|
12531
|
+
const rehearsal = runEnrollmentRehearsal(this.cwd, input, capability, this.enrollmentRegistry);
|
|
12532
|
+
if (!rehearsal.rehearsed || rehearsal.evidence.outcome !== "ready") {
|
|
12533
|
+
throw new Error(`Kernel enrollment rehearsal failed: ${rehearsal.evidence.blockers.join("; ")}`);
|
|
12534
|
+
}
|
|
12535
|
+
return enrollCanaryTask(this.cwd, input, this.enrollmentRegistry);
|
|
12536
|
+
} catch (error) {
|
|
12537
|
+
if (gitBaseNote)
|
|
12538
|
+
throw new Error(`${error instanceof Error ? error.message : String(error)}${gitBaseNote}`);
|
|
12539
|
+
throw error;
|
|
12454
12540
|
}
|
|
12455
|
-
return enrollCanaryTask(this.cwd, input, this.enrollmentRegistry);
|
|
12456
12541
|
}
|
|
12457
12542
|
async advance(taskId, signal) {
|
|
12458
12543
|
return this.withTerminalTracker(taskId, await this.coordinator.advance(taskId, { cwd: this.cwd }, signal));
|
|
@@ -12549,7 +12634,7 @@ class ClaudeRuntime {
|
|
|
12549
12634
|
if (sidecar && nextIntent) {
|
|
12550
12635
|
writeFileSync8(sidecar, `${JSON.stringify(nextIntent, null, 2)}
|
|
12551
12636
|
`);
|
|
12552
|
-
|
|
12637
|
+
execFileSync7("git", ["add", "--", priorIntent.intent_ref.path], { cwd: this.cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
12553
12638
|
const preparedRecord = await readTaskRecord(this.cwd, taskId);
|
|
12554
12639
|
if (!preparedRecord.record) {
|
|
12555
12640
|
throw new NativeAuthorityError("workspace_changed", "TaskRecord changed before the breaking revision digest");
|
|
@@ -12729,7 +12814,7 @@ class ClaudeRuntime {
|
|
|
12729
12814
|
if (priorBytes) {
|
|
12730
12815
|
writeFileSync8(sidecar, `${JSON.stringify(operation.next_intent, null, 2)}
|
|
12731
12816
|
`);
|
|
12732
|
-
|
|
12817
|
+
execFileSync7("git", ["add", "--", priorIntent.intent_ref.path], {
|
|
12733
12818
|
cwd: ctx.cwd,
|
|
12734
12819
|
stdio: ["ignore", "pipe", "pipe"]
|
|
12735
12820
|
});
|
|
@@ -13311,7 +13396,8 @@ ${details.join(`
|
|
|
13311
13396
|
input.risk ? `Risk: ${input.risk}` : null,
|
|
13312
13397
|
input.intentRevision !== undefined ? `Intent revision: ${input.intentRevision}` : null,
|
|
13313
13398
|
input.intentContentHash ? `Intent hash: ${input.intentContentHash}` : null,
|
|
13314
|
-
input.bindingDigest ? `Binding digest: ${input.bindingDigest}` : null
|
|
13399
|
+
input.bindingDigest ? `Binding digest: ${input.bindingDigest}` : null,
|
|
13400
|
+
input.gitBaseNotice
|
|
13315
13401
|
].filter(Boolean);
|
|
13316
13402
|
return {
|
|
13317
13403
|
mode: "form",
|