@akagilnc/pi-workflow-roles 0.1.3545 → 0.1.3552
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/grok/production-host.js +36 -430
- package/dist/public-cli/main.js +60 -46
- package/dist/public-cli/registry.js +2 -1
- package/package.json +1 -1
- package/src/doctor-evidence.ts +1 -8
- package/src/grok/production-host.ts +13 -216
- package/src/grok/role-turn-host.ts +4 -358
- package/src/host-transition-prior-native.ts +23 -32
- package/src/public-cli/cli.ts +33 -4
- package/src/public-cli/countersign-run.ts +1 -0
- package/src/public-cli/inspector-run.ts +1 -0
- package/src/public-cli/notary-run.ts +1 -0
- package/src/public-cli/option-definitions.ts +11 -0
- package/src/public-cli/post-admission.ts +5 -1
- package/src/public-cli/registry.ts +1 -0
- package/src/public-cli/seat-ticket-binding.ts +6 -2
- package/src/grok/bash-seatbelt.ts +0 -69
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ ak-role judge --attach ./plan.md "Review this plan." > result.txt
|
|
|
40
40
|
|
|
41
41
|
Exit status reports lifecycle honesty, not business success: every lawful typed result (including `audit_escalation`) exits zero; a failure without a lawful result exits nonzero, and its Terminal carries the Error Artifact ref and original cause instead of a fabricated receipt.
|
|
42
42
|
|
|
43
|
-
`ak-role resume <runId> [message]` reopens that run under the **current seat table** for model / host / engine — the same resolution as starting a new leg (`--flag` → persistent seat → package default). Standard chain after a role `escalate`s: take the owner ruling and feed it back with `ak-role resume <runId> "<ruling>"` so the same run continues to a terminal. `[message]` applies only to seats that accept caller instruction: for those seats the optional `message` after `runId` is passed through unchanged as the continuation prompt (opaque: not parsed as flags); omit it to use the package resume envelope. Notary/符宝郎 must omit `message` and derives evidence from the existing source-run/dossier binding. Global `--model` / `--host` / `--engine` override the table for that resume only. On a real host switch (live seat host differs from the previous invocation host), prior native records of the previous host are delivered once as context to the target host; same-host resume does not re-inject. Each host writes only its native volume (Pi: `session/session.jsonl
|
|
43
|
+
`ak-role resume <runId> [message]` reopens that run under the **current seat table** for model / host / engine — the same resolution as starting a new leg (`--flag` → persistent seat → package default). Standard chain after a role `escalate`s: take the owner ruling and feed it back with `ak-role resume <runId> "<ruling>"` so the same run continues to a terminal. `[message]` applies only to seats that accept caller instruction: for those seats the optional `message` after `runId` is passed through unchanged as the continuation prompt (opaque: not parsed as flags); omit it to use the package resume envelope. Notary/符宝郎 must omit `message` and derives evidence from the existing source-run/dossier binding. Global `--model` / `--host` / `--engine` override the table for that resume only. On a real host switch (live seat host differs from the previous invocation host), prior native records of the previous host are delivered once as context to the target host; same-host resume does not re-inject. Each host writes only its native volume (Pi: `session/session.jsonl`; Grok CLI journals stay in the operator grok home, factory dossier is sitian records on the run), with unified ledger entries recorded in 司天台 (Sitian). Whether to resume is the caller's decision: the command does not require a typed HTTP 429 or a `resumable` state. Unknown run IDs and missing session principals are rejected. Every callable role accepts manual resume; Countersign and Gleaner-Left gained it in #599, Collector, Doctor, Notary, and Inspector in #633.
|
|
44
44
|
|
|
45
45
|
Judge, coder, fixer, reviewer, and merger also retry a non-lawful LLM call in place (same `runId` and session) up to `autoResumeLimit` times. Unset defaults to 2; `ak-role config set-auto-resume-limit <N>` writes the ceiling (`0` disables). Lawful typed terminals (`accepted`, `audit_escalation`, `no_receipt`) stop immediately. Manual `ak-role resume` stays available.
|
|
46
46
|
|
package/README.zh-CN.md
CHANGED
|
@@ -38,7 +38,7 @@ ak-role judge --attach ./plan.md "Review this plan." > result.txt
|
|
|
38
38
|
|
|
39
39
|
退出码报的是生命周期诚实,不是业务成败:一切合法 typed 终态(含 `audit_escalation`)退出零;无合法终态的失败退出非零,其 Terminal 携带 Error Artifact 引用与原始原因,不伪造回执。
|
|
40
40
|
|
|
41
|
-
`ak-role resume <runId> [message]` 按**现行席位表**的 model / host / engine 续跑该次运行——与新起角色腿同一解析(调用旗 → 席位持久 → 包默认)。角色 `escalate`(直通御前)后拿到 owner 裁定,标准续跑是 `ak-role resume <runId> "<裁定>"`——把裁定喂回同一 run,角色继续走到终局。`[message]` 只适用于接收 caller instruction 的席位:对这些席位,`runId` 后可选的 `message` 原样作为续跑 prompt(opaque:不进全局旗标语法);省略则用包自带 resume envelope。Notary/符宝郎必须省略 `message`,仅从既有 source-run/案卷绑定自取证。全局 `--model` / `--host` / `--engine` 仅覆盖本次 resume。真实换宿主时(现行席位 host 与上一次 invocation host 不同),将前序宿主原生卷宗一次性作为 context 交付目标宿主;同宿主续跑不重复注入。各宿主仅直写自身原生卷宗(Pi:`session/session.jsonl
|
|
41
|
+
`ak-role resume <runId> [message]` 按**现行席位表**的 model / host / engine 续跑该次运行——与新起角色腿同一解析(调用旗 → 席位持久 → 包默认)。角色 `escalate`(直通御前)后拿到 owner 裁定,标准续跑是 `ak-role resume <runId> "<裁定>"`——把裁定喂回同一 run,角色继续走到终局。`[message]` 只适用于接收 caller instruction 的席位:对这些席位,`runId` 后可选的 `message` 原样作为续跑 prompt(opaque:不进全局旗标语法);省略则用包自带 resume envelope。Notary/符宝郎必须省略 `message`,仅从既有 source-run/案卷绑定自取证。全局 `--model` / `--host` / `--engine` 仅覆盖本次 resume。真实换宿主时(现行席位 host 与上一次 invocation host 不同),将前序宿主原生卷宗一次性作为 context 交付目标宿主;同宿主续跑不重复注入。各宿主仅直写自身原生卷宗(Pi:`session/session.jsonl`;Grok CLI 原始会话留在操作员 grok 家,工厂卷宗为该 run 的司天台记录),统一账目归入司天台。要不要续跑由调用者决定:不再要求 typed HTTP 429,也不要求 `resumable` 状态。未知 run ID、session 主体不在则拒绝。所有可调用角色均可手动 resume:给事中、左拾遗始于 #599,通进司、太医署、符宝郎、察院始于 #633。
|
|
42
42
|
|
|
43
43
|
大理寺、将作监、修内司、御史台、校书郎在单次调用内对非 lawful LLM 终态原地续跑(同一 `runId` 与 session),次数上限为 `autoResumeLimit`。缺键默认 2;`ak-role config set-auto-resume-limit <N>` 写入(`0` 关闭自动续)。lawful typed 终态(`accepted` / `audit_escalation` / `no_receipt`)立即停止。手动 `ak-role resume` 仍可用。
|
|
44
44
|
|
|
@@ -1239,8 +1239,8 @@ var init_in_process_session = __esm({
|
|
|
1239
1239
|
});
|
|
1240
1240
|
|
|
1241
1241
|
// src/grok/production-host.ts
|
|
1242
|
-
import { readFile as readFile15
|
|
1243
|
-
import { join as
|
|
1242
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
1243
|
+
import { join as join24 } from "node:path";
|
|
1244
1244
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1245
1245
|
|
|
1246
1246
|
// src/canonical-skill-binding.ts
|
|
@@ -5284,14 +5284,12 @@ function acceptedFacts(toolName, details) {
|
|
|
5284
5284
|
function record2(value) {
|
|
5285
5285
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5286
5286
|
}
|
|
5287
|
-
var GROK_HOME_DIR_NAME = "grok-home";
|
|
5288
5287
|
async function discoverCaseFiles(root) {
|
|
5289
5288
|
const found = [];
|
|
5290
5289
|
async function walk(dir, depth) {
|
|
5291
5290
|
for (const item of await readdir(dir, { withFileTypes: true })) {
|
|
5292
5291
|
const path = resolve8(dir, item.name);
|
|
5293
5292
|
if (item.isDirectory()) {
|
|
5294
|
-
if (item.name === GROK_HOME_DIR_NAME) continue;
|
|
5295
5293
|
await walk(path, depth + 1);
|
|
5296
5294
|
} else if (item.isFile() && (item.name.endsWith(".jsonl") || item.name === "stderr.log" && depth === 1)) found.push(path);
|
|
5297
5295
|
}
|
|
@@ -6954,6 +6952,16 @@ var SUPPORT_COMMAND_HELP = {
|
|
|
6954
6952
|
"ak-role --host grok-build resume 01abc\u2026",
|
|
6955
6953
|
"ak-role --engine agy resume 01abc\u2026"
|
|
6956
6954
|
]
|
|
6955
|
+
},
|
|
6956
|
+
new: {
|
|
6957
|
+
command: "new",
|
|
6958
|
+
summary: "Explicit fresh summons: same role options as a direct call, but always mint a new run (skip same-ticket auto-resume). Caller chooses new vs resume; no overflow judgment.",
|
|
6959
|
+
usage: ["ak-role new <role> [options] \u2026"],
|
|
6960
|
+
examples: [
|
|
6961
|
+
'ak-role new countersign --attach ./ticket.md "\u88C1\uFF1A\u672C\u7968 #708 \u662F\u5426\u8DB3\u4EE5\u5F00\u5DE5\u3002"',
|
|
6962
|
+
"ak-role new notary --source-run 01abc\u2026@countersign",
|
|
6963
|
+
"ak-role --host grok-build new inspector --attach ./change.patch"
|
|
6964
|
+
]
|
|
6957
6965
|
}
|
|
6958
6966
|
};
|
|
6959
6967
|
var PUBLIC_COMMAND_HELP = {
|
|
@@ -13558,17 +13566,14 @@ function createRoleRuntimeExtension(dependencies) {
|
|
|
13558
13566
|
|
|
13559
13567
|
// src/grok/role-envelope.ts
|
|
13560
13568
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
13561
|
-
import { mkdir as
|
|
13569
|
+
import { mkdir as mkdir3, readFile as readFile13, writeFile as writeFile7 } from "node:fs/promises";
|
|
13562
13570
|
import { createServer } from "node:net";
|
|
13563
|
-
import { basename as
|
|
13571
|
+
import { basename as basename7, dirname as dirname15, join as join22 } from "node:path";
|
|
13564
13572
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
13565
13573
|
|
|
13566
13574
|
// src/grok/role-turn-host.ts
|
|
13567
|
-
import {
|
|
13568
|
-
import { copyFile, lstat as lstat3, mkdir as mkdir4, open as open2, realpath as realpath7, rm as rm5 } from "node:fs/promises";
|
|
13569
|
-
import { basename as basename7, dirname as dirname15, isAbsolute as isAbsolute7, join as join23, relative as pathRelative } from "node:path";
|
|
13575
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
13570
13576
|
import { createInterface } from "node:readline";
|
|
13571
|
-
import { promisify as promisify3 } from "node:util";
|
|
13572
13577
|
|
|
13573
13578
|
// src/agent-start-materials.ts
|
|
13574
13579
|
function renderAgentStartMaterials(body, materials) {
|
|
@@ -13576,60 +13581,6 @@ function renderAgentStartMaterials(body, materials) {
|
|
|
13576
13581
|
return [body, ...materials.map((material) => JSON.stringify(material))].join("\n\n");
|
|
13577
13582
|
}
|
|
13578
13583
|
|
|
13579
|
-
// src/grok/bash-seatbelt.ts
|
|
13580
|
-
import { mkdir as mkdir3, writeFile as writeFile7 } from "node:fs/promises";
|
|
13581
|
-
import { join as join22 } from "node:path";
|
|
13582
|
-
function renderGrokBashSeatbeltHookScript() {
|
|
13583
|
-
const reasons = Object.fromEntries(
|
|
13584
|
-
FIXER_BASH_FORBIDDEN_LITERALS.map((literal) => [literal, fixerBashSeatbeltDenyReason(literal)])
|
|
13585
|
-
);
|
|
13586
|
-
return `#!/usr/bin/env node
|
|
13587
|
-
const LITERALS = ${JSON.stringify([...FIXER_BASH_FORBIDDEN_LITERALS])};
|
|
13588
|
-
const REASONS = ${JSON.stringify(reasons)};
|
|
13589
|
-
let raw = "";
|
|
13590
|
-
process.stdin.setEncoding("utf8");
|
|
13591
|
-
process.stdin.on("data", (chunk) => { raw += chunk; });
|
|
13592
|
-
process.stdin.on("end", () => {
|
|
13593
|
-
let event = {};
|
|
13594
|
-
try { event = JSON.parse(raw); } catch { /* fail-open on malformed host payload */ }
|
|
13595
|
-
const input = event && typeof event === "object" ? event.toolInput : undefined;
|
|
13596
|
-
const command = input && typeof input === "object" && typeof input.command === "string"
|
|
13597
|
-
? input.command : undefined;
|
|
13598
|
-
const matched = typeof command === "string"
|
|
13599
|
-
? LITERALS.find((literal) => command.includes(literal))
|
|
13600
|
-
: undefined;
|
|
13601
|
-
const decision = matched === undefined
|
|
13602
|
-
? { decision: "allow" }
|
|
13603
|
-
: { decision: "deny", reason: REASONS[matched] };
|
|
13604
|
-
process.stdout.write(JSON.stringify(decision));
|
|
13605
|
-
});
|
|
13606
|
-
`;
|
|
13607
|
-
}
|
|
13608
|
-
async function installGrokPreToolUseDeny(controlledHome) {
|
|
13609
|
-
const hooksDir = join22(controlledHome, "hooks");
|
|
13610
|
-
await mkdir3(hooksDir, { recursive: true });
|
|
13611
|
-
const scriptName = "ak-bash-seatbelt.mjs";
|
|
13612
|
-
const scriptPath = join22(hooksDir, scriptName);
|
|
13613
|
-
await writeFile7(scriptPath, renderGrokBashSeatbeltHookScript(), { mode: 493 });
|
|
13614
|
-
await writeFile7(join22(hooksDir, "ak-bash-seatbelt.json"), `${JSON.stringify({
|
|
13615
|
-
hooks: {
|
|
13616
|
-
PreToolUse: [
|
|
13617
|
-
{
|
|
13618
|
-
matcher: "Bash|run_terminal_command",
|
|
13619
|
-
hooks: [
|
|
13620
|
-
{
|
|
13621
|
-
type: "command",
|
|
13622
|
-
command: process.execPath + " " + JSON.stringify(scriptPath),
|
|
13623
|
-
timeout: 5
|
|
13624
|
-
}
|
|
13625
|
-
]
|
|
13626
|
-
}
|
|
13627
|
-
]
|
|
13628
|
-
}
|
|
13629
|
-
}, null, 2)}
|
|
13630
|
-
`);
|
|
13631
|
-
}
|
|
13632
|
-
|
|
13633
13584
|
// src/grok/role-turn-host.ts
|
|
13634
13585
|
function renderGrokSystemPromptOverride(authority) {
|
|
13635
13586
|
return renderAgentStartMaterials(authority.body, authority.materials);
|
|
@@ -13756,12 +13707,6 @@ function createGrokRoleTurnHost(config) {
|
|
|
13756
13707
|
return {
|
|
13757
13708
|
executeTurn(request) {
|
|
13758
13709
|
const execution = serial.then(async () => {
|
|
13759
|
-
const inspected = await config.inspect(request);
|
|
13760
|
-
if (inspected.privateActive.length !== 0) {
|
|
13761
|
-
return failure("activation", "UncontrolledGrokSession", "private-config-active", {
|
|
13762
|
-
privateActive: [...inspected.privateActive]
|
|
13763
|
-
});
|
|
13764
|
-
}
|
|
13765
13710
|
const continuation = request.continuation;
|
|
13766
13711
|
const prepared = await config.prepare(request);
|
|
13767
13712
|
let connection;
|
|
@@ -13777,15 +13722,6 @@ function createGrokRoleTurnHost(config) {
|
|
|
13777
13722
|
clientCapabilities: {}
|
|
13778
13723
|
});
|
|
13779
13724
|
const initializeMeta = initialized._meta;
|
|
13780
|
-
const hookMeta = initialized._meta;
|
|
13781
|
-
const hookCapability = hookMeta?.["x.ai/hooks"];
|
|
13782
|
-
const canDeny = Array.isArray(hookCapability?.blockingEvents) && hookCapability.blockingEvents.includes("pre_tool_use") && Array.isArray(hookCapability.decisions) && hookCapability.decisions.includes("deny");
|
|
13783
|
-
let preToolUseDeny = false;
|
|
13784
|
-
if (canDeny && request.activation.role === "fixer") {
|
|
13785
|
-
await installGrokPreToolUseDeny(request.home);
|
|
13786
|
-
preToolUseDeny = true;
|
|
13787
|
-
}
|
|
13788
|
-
await config.recordCapabilities(request, { nativeToolNarrowing: false, preToolUseDeny });
|
|
13789
13725
|
const modelState = initializeMeta?.modelState;
|
|
13790
13726
|
const availableModels = Array.isArray(modelState?.availableModels) ? modelState.availableModels : void 0;
|
|
13791
13727
|
if (request.model !== void 0 && availableModels !== void 0 && !availableModels.some((entry) => typeof entry === "object" && entry !== null && entry.modelId === request.model?.model)) {
|
|
@@ -13933,222 +13869,10 @@ ${priorNativePaths.join("\n")}` : prepared.prompt;
|
|
|
13933
13869
|
var PRIVATE_COMPAT_ENV = Object.fromEntries(
|
|
13934
13870
|
["CLAUDE", "CURSOR", "CODEX"].flatMap((vendor) => ["SKILLS", "RULES", "AGENTS", "MCPS", "HOOKS", "SESSIONS"].map((kind) => [`GROK_${vendor}_${kind}_ENABLED`, "false"]))
|
|
13935
13871
|
);
|
|
13936
|
-
|
|
13937
|
-
function errnoCode2(error) {
|
|
13938
|
-
if (typeof error !== "object" || error === null || !("code" in error)) return void 0;
|
|
13939
|
-
const code = error.code;
|
|
13940
|
-
return typeof code === "string" ? code : void 0;
|
|
13941
|
-
}
|
|
13942
|
-
async function realpathIfPresent(path) {
|
|
13943
|
-
try {
|
|
13944
|
-
return await realpath7(path);
|
|
13945
|
-
} catch (error) {
|
|
13946
|
-
if (errnoCode2(error) === "ENOENT") return void 0;
|
|
13947
|
-
throw error;
|
|
13948
|
-
}
|
|
13949
|
-
}
|
|
13950
|
-
async function worktreeFilePresence(path) {
|
|
13951
|
-
try {
|
|
13952
|
-
const handle = await open2(path, "r");
|
|
13953
|
-
await handle.close();
|
|
13954
|
-
return "present";
|
|
13955
|
-
} catch (error) {
|
|
13956
|
-
if (errnoCode2(error) === "ENOENT") return "absent";
|
|
13957
|
-
throw error;
|
|
13958
|
-
}
|
|
13959
|
-
}
|
|
13960
|
-
async function resolveHeadTreePath(topLevel, relativePath) {
|
|
13961
|
-
const { stdout: exactOut } = await execFileAsync3(
|
|
13962
|
-
"git",
|
|
13963
|
-
["ls-tree", "--name-only", "HEAD", "--", relativePath],
|
|
13964
|
-
{ cwd: topLevel, encoding: "utf8" }
|
|
13965
|
-
);
|
|
13966
|
-
const exactHits = exactOut.split("\n").map((name) => name.trim()).filter((name) => name !== "");
|
|
13967
|
-
if (exactHits.includes(relativePath)) return relativePath;
|
|
13968
|
-
const parent = dirname15(relativePath);
|
|
13969
|
-
const leaf = basename7(relativePath);
|
|
13970
|
-
if (parent !== ".") {
|
|
13971
|
-
const { stdout: parentOut } = await execFileAsync3(
|
|
13972
|
-
"git",
|
|
13973
|
-
["ls-tree", "--name-only", "HEAD", "--", parent],
|
|
13974
|
-
{ cwd: topLevel, encoding: "utf8" }
|
|
13975
|
-
);
|
|
13976
|
-
const parentHits = parentOut.split("\n").map((name) => name.trim()).filter((name) => name !== "");
|
|
13977
|
-
if (!parentHits.includes(parent)) return void 0;
|
|
13978
|
-
}
|
|
13979
|
-
const { stdout: listing } = parent === "." ? await execFileAsync3("git", ["ls-tree", "--name-only", "HEAD"], {
|
|
13980
|
-
cwd: topLevel,
|
|
13981
|
-
encoding: "utf8"
|
|
13982
|
-
}) : await execFileAsync3("git", ["ls-tree", "--name-only", `HEAD:${parent}`], {
|
|
13983
|
-
cwd: topLevel,
|
|
13984
|
-
encoding: "utf8"
|
|
13985
|
-
});
|
|
13986
|
-
const needle = leaf.toLowerCase();
|
|
13987
|
-
const hits = listing.split("\n").map((name) => name.trim()).filter((name) => name !== "" && basename7(name).toLowerCase() === needle).map((name) => parent === "." ? basename7(name) : join23(parent, basename7(name)));
|
|
13988
|
-
return hits.length === 1 ? hits[0] : void 0;
|
|
13989
|
-
}
|
|
13990
|
-
async function isHeadMatchedProjectInstruction(repositoryCwd, absolutePath) {
|
|
13991
|
-
if (absolutePath === "" || absolutePath.includes("\0")) return false;
|
|
13992
|
-
const { stdout: topLevelOut } = await execFileAsync3("git", ["rev-parse", "--show-toplevel"], {
|
|
13993
|
-
cwd: repositoryCwd,
|
|
13994
|
-
encoding: "utf8"
|
|
13995
|
-
});
|
|
13996
|
-
await execFileAsync3("git", ["rev-parse", "--verify", "HEAD"], {
|
|
13997
|
-
cwd: repositoryCwd,
|
|
13998
|
-
encoding: "utf8"
|
|
13999
|
-
});
|
|
14000
|
-
const topLevel = await realpath7(topLevelOut.trim());
|
|
14001
|
-
const parent = await realpathIfPresent(dirname15(absolutePath));
|
|
14002
|
-
if (parent === void 0) return false;
|
|
14003
|
-
const leaf = basename7(absolutePath);
|
|
14004
|
-
if (leaf === "" || leaf === "." || leaf === "..") return false;
|
|
14005
|
-
const candidate = join23(parent, leaf);
|
|
14006
|
-
const relative3 = pathRelative(topLevel, candidate);
|
|
14007
|
-
if (relative3 === "" || relative3.startsWith("..") || isAbsolute7(relative3) || relative3.includes("\0")) {
|
|
14008
|
-
return false;
|
|
14009
|
-
}
|
|
14010
|
-
const headRel = await resolveHeadTreePath(topLevel, relative3);
|
|
14011
|
-
if (headRel === void 0) return false;
|
|
14012
|
-
const headFile = join23(topLevel, headRel);
|
|
14013
|
-
const { stdout: headBlobOut } = await execFileAsync3(
|
|
14014
|
-
"git",
|
|
14015
|
-
["rev-parse", "--verify", `HEAD:${headRel}`],
|
|
14016
|
-
{ cwd: topLevel, encoding: "utf8" }
|
|
14017
|
-
);
|
|
14018
|
-
const headBlob = headBlobOut.trim();
|
|
14019
|
-
let hashTarget = candidate;
|
|
14020
|
-
const candidatePresence = await worktreeFilePresence(candidate);
|
|
14021
|
-
if (candidatePresence === "absent") {
|
|
14022
|
-
if (candidate === headFile) return false;
|
|
14023
|
-
const headPresence = await worktreeFilePresence(headFile);
|
|
14024
|
-
if (headPresence === "absent") return false;
|
|
14025
|
-
hashTarget = headFile;
|
|
14026
|
-
}
|
|
14027
|
-
const { stdout } = await execFileAsync3("git", ["hash-object", "--", hashTarget], {
|
|
14028
|
-
cwd: topLevel,
|
|
14029
|
-
encoding: "utf8"
|
|
14030
|
-
});
|
|
14031
|
-
return headBlob === stdout.trim();
|
|
14032
|
-
}
|
|
14033
|
-
function inspectItemPath(value) {
|
|
14034
|
-
if (typeof value.source?.path === "string") return value.source.path;
|
|
14035
|
-
if (typeof value.path === "string") return value.path;
|
|
14036
|
-
return "";
|
|
14037
|
-
}
|
|
14038
|
-
function isInspectItemActive(value) {
|
|
14039
|
-
return value.disabled !== true && value.enabled !== false && value.compatibilityStatus !== "disabled";
|
|
14040
|
-
}
|
|
14041
|
-
function listActiveProjectInstructionPaths(document) {
|
|
14042
|
-
const items = document.projectInstructions;
|
|
14043
|
-
if (!Array.isArray(items)) return [];
|
|
14044
|
-
const paths = [];
|
|
14045
|
-
for (const value of items) {
|
|
14046
|
-
if (!isInspectItemActive(value)) continue;
|
|
14047
|
-
const path = inspectItemPath(value);
|
|
14048
|
-
if (path !== "") paths.push(path);
|
|
14049
|
-
}
|
|
14050
|
-
return paths;
|
|
14051
|
-
}
|
|
14052
|
-
function classifyGrokInspection(document, packageRoot, options = {}) {
|
|
14053
|
-
const privateActive = /* @__PURE__ */ new Set();
|
|
14054
|
-
const akActive = /* @__PURE__ */ new Set();
|
|
14055
|
-
const headMatched = options.headMatchedProjectInstructionPaths ?? /* @__PURE__ */ new Set();
|
|
14056
|
-
const externalCompat = document.externalCompat;
|
|
14057
|
-
if (Array.isArray(externalCompat?.cells)) {
|
|
14058
|
-
for (const cell of externalCompat.cells) {
|
|
14059
|
-
if (cell.enabled !== true) continue;
|
|
14060
|
-
privateActive.add(`externalCompat:${String(cell.vendor)}:${String(cell.surface)}`);
|
|
14061
|
-
}
|
|
14062
|
-
}
|
|
14063
|
-
for (const section of ["skills", "agents", "plugins", "mcpServers", "hooks", "projectInstructions"]) {
|
|
14064
|
-
const items = document[section];
|
|
14065
|
-
if (!Array.isArray(items)) continue;
|
|
14066
|
-
for (const value of items) {
|
|
14067
|
-
if (!isInspectItemActive(value)) continue;
|
|
14068
|
-
const sourceType = value.source?.type;
|
|
14069
|
-
const path = inspectItemPath(value);
|
|
14070
|
-
const identity = `${section}:${typeof value.name === "string" ? value.name : path}`;
|
|
14071
|
-
if (sourceType === "builtin" || sourceType === "bundled") continue;
|
|
14072
|
-
if (path === packageRoot || path.startsWith(`${packageRoot}/`)) akActive.add(identity);
|
|
14073
|
-
else if (section === "projectInstructions" && headMatched.has(path)) continue;
|
|
14074
|
-
else privateActive.add(identity);
|
|
14075
|
-
}
|
|
14076
|
-
}
|
|
14077
|
-
return { privateActive: [...privateActive].sort(), akActive: [...akActive].sort() };
|
|
14078
|
-
}
|
|
14079
|
-
var AK_BASH_SEATBELT_HOOK_FILES = ["ak-bash-seatbelt.json", "ak-bash-seatbelt.mjs"];
|
|
14080
|
-
function isMissingPathError2(error) {
|
|
14081
|
-
return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
|
|
14082
|
-
}
|
|
14083
|
-
async function assertControlledGrokHomeIsRealDirectory(controlledHome) {
|
|
14084
|
-
let st;
|
|
14085
|
-
try {
|
|
14086
|
-
st = await lstat3(controlledHome);
|
|
14087
|
-
} catch (error) {
|
|
14088
|
-
if (isMissingPathError2(error)) return;
|
|
14089
|
-
throw error;
|
|
14090
|
-
}
|
|
14091
|
-
if (st.isSymbolicLink()) {
|
|
14092
|
-
throw new Error(`controlled grok home must not be a symlink: ${controlledHome}`);
|
|
14093
|
-
}
|
|
14094
|
-
if (!st.isDirectory()) {
|
|
14095
|
-
throw new Error(`controlled grok home must be a real directory: ${controlledHome}`);
|
|
14096
|
-
}
|
|
14097
|
-
}
|
|
14098
|
-
async function assertControlledGrokAuthIsNotSymlink(authPath) {
|
|
14099
|
-
let st;
|
|
14100
|
-
try {
|
|
14101
|
-
st = await lstat3(authPath);
|
|
14102
|
-
} catch (error) {
|
|
14103
|
-
if (isMissingPathError2(error)) return;
|
|
14104
|
-
throw error;
|
|
14105
|
-
}
|
|
14106
|
-
if (st.isSymbolicLink()) {
|
|
14107
|
-
throw new Error(`controlled grok auth must not be a symlink: ${authPath}`);
|
|
14108
|
-
}
|
|
14109
|
-
}
|
|
14110
|
-
async function scrubAkBashSeatbeltHooks(controlledHome) {
|
|
14111
|
-
const hooksDir = join23(controlledHome, "hooks");
|
|
14112
|
-
for (const name of AK_BASH_SEATBELT_HOOK_FILES) {
|
|
14113
|
-
await rm5(join23(hooksDir, name), { force: true });
|
|
14114
|
-
}
|
|
14115
|
-
}
|
|
14116
|
-
async function prepareControlledGrokHome(sourceHome, controlledHome) {
|
|
14117
|
-
await assertControlledGrokHomeIsRealDirectory(controlledHome);
|
|
14118
|
-
await mkdir4(controlledHome, { recursive: true, mode: 448 });
|
|
14119
|
-
await assertControlledGrokHomeIsRealDirectory(controlledHome);
|
|
14120
|
-
const authPath = join23(controlledHome, "auth.json");
|
|
14121
|
-
await assertControlledGrokAuthIsNotSymlink(authPath);
|
|
14122
|
-
await rm5(authPath, { force: true });
|
|
14123
|
-
await scrubAkBashSeatbeltHooks(controlledHome);
|
|
14124
|
-
await copyFile(join23(sourceHome, ".grok", "auth.json"), authPath);
|
|
14125
|
-
}
|
|
14126
|
-
async function inspectControlledGrok(options) {
|
|
14127
|
-
const { stdout } = await execFileAsync3(options.binary, ["inspect", "--json"], {
|
|
14128
|
-
cwd: options.cwd,
|
|
14129
|
-
env: options.env,
|
|
14130
|
-
encoding: "utf8"
|
|
14131
|
-
});
|
|
14132
|
-
const document = JSON.parse(stdout);
|
|
14133
|
-
if (typeof document !== "object" || document === null || Array.isArray(document)) {
|
|
14134
|
-
throw new Error("Grok structured inspection did not return an object");
|
|
14135
|
-
}
|
|
14136
|
-
const record4 = document;
|
|
14137
|
-
const headMatchedProjectInstructionPaths = /* @__PURE__ */ new Set();
|
|
14138
|
-
for (const path of listActiveProjectInstructionPaths(record4)) {
|
|
14139
|
-
if (path === options.packageRoot || path.startsWith(`${options.packageRoot}/`)) continue;
|
|
14140
|
-
if (await isHeadMatchedProjectInstruction(options.cwd, path)) {
|
|
14141
|
-
headMatchedProjectInstructionPaths.add(path);
|
|
14142
|
-
}
|
|
14143
|
-
}
|
|
14144
|
-
return classifyGrokInspection(record4, options.packageRoot, { headMatchedProjectInstructionPaths });
|
|
14145
|
-
}
|
|
14146
|
-
function controlledGrokChildEnv(base, grokHome) {
|
|
13872
|
+
function controlledGrokChildEnv(base) {
|
|
14147
13873
|
return {
|
|
14148
13874
|
...base,
|
|
14149
13875
|
...PRIVATE_COMPAT_ENV,
|
|
14150
|
-
HOME: grokHome,
|
|
14151
|
-
GROK_HOME: grokHome,
|
|
14152
13876
|
GROK_MEMORY: "0",
|
|
14153
13877
|
GROK_SUBAGENTS: "0"
|
|
14154
13878
|
};
|
|
@@ -14168,7 +13892,7 @@ function buildGrokSkillExpansion(methodSkills, prompt) {
|
|
|
14168
13892
|
return Object.freeze({
|
|
14169
13893
|
name: parsed.name,
|
|
14170
13894
|
location: method.path,
|
|
14171
|
-
content: `References are relative to ${
|
|
13895
|
+
content: `References are relative to ${dirname15(method.path)}.
|
|
14172
13896
|
|
|
14173
13897
|
${method.body}`,
|
|
14174
13898
|
userMessage: parsed.userMessage
|
|
@@ -14238,18 +13962,18 @@ async function prepareGrokRoleEnvelope(options) {
|
|
|
14238
13962
|
let infrastructureRoundFailure;
|
|
14239
13963
|
const hostAbort = new AbortController();
|
|
14240
13964
|
const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID2();
|
|
14241
|
-
await
|
|
13965
|
+
await mkdir3(request.runDirectory, { recursive: true });
|
|
14242
13966
|
for (const method of request.methods) {
|
|
14243
13967
|
if (method.kind !== "skill") continue;
|
|
14244
|
-
const name =
|
|
13968
|
+
const name = basename7(dirname15(method.path));
|
|
14245
13969
|
const raw = await readFile13(method.path, "utf8");
|
|
14246
13970
|
methodSkills.set(name, { path: method.path, body: stripSkillFrontmatter(raw).trim() });
|
|
14247
13971
|
}
|
|
14248
|
-
let sessionFile = options.sessionFile ??
|
|
14249
|
-
await
|
|
13972
|
+
let sessionFile = options.sessionFile ?? join22(request.runDirectory, "session", "session.jsonl");
|
|
13973
|
+
await mkdir3(dirname15(sessionFile), { recursive: true });
|
|
14250
13974
|
if (request.continuation.kind !== "resume") {
|
|
14251
13975
|
try {
|
|
14252
|
-
await
|
|
13976
|
+
await writeFile7(
|
|
14253
13977
|
sessionFile,
|
|
14254
13978
|
`${JSON.stringify({
|
|
14255
13979
|
type: "session",
|
|
@@ -14273,7 +13997,7 @@ async function prepareGrokRoleEnvelope(options) {
|
|
|
14273
13997
|
getLeafEntry: () => sessionEntries.at(-1),
|
|
14274
13998
|
getLeafId: () => runId,
|
|
14275
13999
|
getEntries: () => sessionEntries,
|
|
14276
|
-
getSessionDir: () =>
|
|
14000
|
+
getSessionDir: () => dirname15(sessionFile),
|
|
14277
14001
|
getSessionFile: () => sessionFile,
|
|
14278
14002
|
getHeader: () => ({ type: "session", id: runId }),
|
|
14279
14003
|
setSessionFile(path) {
|
|
@@ -14711,11 +14435,11 @@ async function prepareGrokRoleEnvelope(options) {
|
|
|
14711
14435
|
}
|
|
14712
14436
|
|
|
14713
14437
|
// src/grok/session-identity.ts
|
|
14714
|
-
import { mkdir as
|
|
14715
|
-
import { dirname as
|
|
14438
|
+
import { mkdir as mkdir4, readFile as readFile14, rename, writeFile as writeFile8 } from "node:fs/promises";
|
|
14439
|
+
import { dirname as dirname16, join as join23 } from "node:path";
|
|
14716
14440
|
var GROK_ACP_SESSION_BINDING = "grok-acp-session.json";
|
|
14717
14441
|
function createGrokSessionIdentityAuthority(authority) {
|
|
14718
|
-
const bindingPath = (principal) =>
|
|
14442
|
+
const bindingPath = (principal) => join23(authority.decode(principal).sessionDirectory, GROK_ACP_SESSION_BINDING);
|
|
14719
14443
|
return {
|
|
14720
14444
|
resolveSessionFile(principal) {
|
|
14721
14445
|
return authority.decode(principal).sessionFile;
|
|
@@ -14734,9 +14458,9 @@ function createGrokSessionIdentityAuthority(authority) {
|
|
|
14734
14458
|
},
|
|
14735
14459
|
async bind(principal, sessionId) {
|
|
14736
14460
|
const target = bindingPath(principal);
|
|
14737
|
-
await
|
|
14461
|
+
await mkdir4(dirname16(target), { recursive: true });
|
|
14738
14462
|
const temporary = `${target}.${process.pid}.tmp`;
|
|
14739
|
-
await
|
|
14463
|
+
await writeFile8(temporary, `${JSON.stringify({ sessionId })}
|
|
14740
14464
|
`, { encoding: "utf8", mode: 384 });
|
|
14741
14465
|
await rename(temporary, target);
|
|
14742
14466
|
}
|
|
@@ -14745,79 +14469,14 @@ function createGrokSessionIdentityAuthority(authority) {
|
|
|
14745
14469
|
|
|
14746
14470
|
// src/grok/production-host.ts
|
|
14747
14471
|
function resolveGrokBinary(operatorHome) {
|
|
14748
|
-
return
|
|
14749
|
-
}
|
|
14750
|
-
var NO_PRODUCTION_GROK_PRIMARY_FAILURE = {
|
|
14751
|
-
present: false
|
|
14752
|
-
};
|
|
14753
|
-
async function settleProductionGrokHomeCleanup(controlledHome, primaryFailure, concurrentMessage) {
|
|
14754
|
-
try {
|
|
14755
|
-
await assertControlledGrokHomeIsRealDirectory(controlledHome);
|
|
14756
|
-
const authPath = join26(controlledHome, "auth.json");
|
|
14757
|
-
await assertControlledGrokAuthIsNotSymlink(authPath);
|
|
14758
|
-
await rm6(authPath, { force: true });
|
|
14759
|
-
await scrubAkBashSeatbeltHooks(controlledHome);
|
|
14760
|
-
} catch (cleanupFailure) {
|
|
14761
|
-
if (primaryFailure.present) {
|
|
14762
|
-
throw new AggregateError([primaryFailure.value, cleanupFailure], concurrentMessage, {
|
|
14763
|
-
cause: primaryFailure.value
|
|
14764
|
-
});
|
|
14765
|
-
}
|
|
14766
|
-
throw cleanupFailure;
|
|
14767
|
-
}
|
|
14768
|
-
if (primaryFailure.present) {
|
|
14769
|
-
throw primaryFailure.value;
|
|
14770
|
-
}
|
|
14771
|
-
}
|
|
14772
|
-
async function openProductionGrokHome(runDirectory, operatorHome) {
|
|
14773
|
-
const controlledHome = join26(runDirectory, "grok-home");
|
|
14774
|
-
try {
|
|
14775
|
-
await prepareControlledGrokHome(operatorHome, controlledHome);
|
|
14776
|
-
return controlledHome;
|
|
14777
|
-
} catch (error) {
|
|
14778
|
-
await settleProductionGrokHomeCleanup(
|
|
14779
|
-
controlledHome,
|
|
14780
|
-
{ present: true, value: error },
|
|
14781
|
-
"production grok home open failed and its cleanup also failed"
|
|
14782
|
-
);
|
|
14783
|
-
throw error;
|
|
14784
|
-
}
|
|
14472
|
+
return join24(operatorHome, ".grok", "bin", "grok");
|
|
14785
14473
|
}
|
|
14786
|
-
function childEnv(
|
|
14474
|
+
function childEnv(packageRoot) {
|
|
14787
14475
|
return {
|
|
14788
|
-
...controlledGrokChildEnv(process.env
|
|
14476
|
+
...controlledGrokChildEnv(process.env),
|
|
14789
14477
|
AK_PACKAGE_ROOT: packageRoot
|
|
14790
14478
|
};
|
|
14791
14479
|
}
|
|
14792
|
-
async function bindProductionGrokIsolation(runDirectory, operatorHome, packageRoot) {
|
|
14793
|
-
const controlledHome = await openProductionGrokHome(runDirectory, operatorHome);
|
|
14794
|
-
return {
|
|
14795
|
-
operatorHome,
|
|
14796
|
-
controlledHome,
|
|
14797
|
-
binary: resolveGrokBinary(operatorHome),
|
|
14798
|
-
env: childEnv(controlledHome, packageRoot)
|
|
14799
|
-
};
|
|
14800
|
-
}
|
|
14801
|
-
async function withProductionGrokIsolation(runDirectory, operatorHome, packageRoot, run) {
|
|
14802
|
-
let binding;
|
|
14803
|
-
let primaryFailure = NO_PRODUCTION_GROK_PRIMARY_FAILURE;
|
|
14804
|
-
let value;
|
|
14805
|
-
try {
|
|
14806
|
-
binding = await bindProductionGrokIsolation(runDirectory, operatorHome, packageRoot);
|
|
14807
|
-
value = await run(binding);
|
|
14808
|
-
} catch (error) {
|
|
14809
|
-
primaryFailure = { present: true, value: error };
|
|
14810
|
-
}
|
|
14811
|
-
if (binding !== void 0) {
|
|
14812
|
-
await settleProductionGrokHomeCleanup(
|
|
14813
|
-
binding.controlledHome,
|
|
14814
|
-
primaryFailure,
|
|
14815
|
-
"production grok isolation turn and cleanup failed"
|
|
14816
|
-
);
|
|
14817
|
-
}
|
|
14818
|
-
if (primaryFailure.present) throw primaryFailure.value;
|
|
14819
|
-
return value;
|
|
14820
|
-
}
|
|
14821
14480
|
var navigatorRoutePlaybookPath = fileURLToPath3(
|
|
14822
14481
|
new URL("../../resources/navigator-route-playbook.md", import.meta.url)
|
|
14823
14482
|
);
|
|
@@ -14885,76 +14544,23 @@ function createGrokRoleRuntimeDependencies(packageRoot) {
|
|
|
14885
14544
|
})
|
|
14886
14545
|
};
|
|
14887
14546
|
}
|
|
14888
|
-
async function recordGrokCapabilities(request, declaration) {
|
|
14889
|
-
await writeFile10(
|
|
14890
|
-
join26(request.runDirectory, "grok-capabilities.json"),
|
|
14891
|
-
`${JSON.stringify(declaration)}
|
|
14892
|
-
`,
|
|
14893
|
-
"utf8"
|
|
14894
|
-
);
|
|
14895
|
-
}
|
|
14896
14547
|
function createProductionGrokRoleTurnHost(options) {
|
|
14897
14548
|
const { packageRoot, principalAuthority } = options;
|
|
14898
|
-
|
|
14899
|
-
|
|
14900
|
-
const inner = createComposedGrokRoleTurnHost({
|
|
14549
|
+
const env = childEnv(packageRoot);
|
|
14550
|
+
return createComposedGrokRoleTurnHost({
|
|
14901
14551
|
sessionIdentity: createGrokSessionIdentityAuthority(principalAuthority),
|
|
14902
14552
|
roleRuntimeDependencies: createGrokRoleRuntimeDependencies(packageRoot),
|
|
14903
|
-
recordCapabilities: recordGrokCapabilities,
|
|
14904
|
-
async inspect(request) {
|
|
14905
|
-
if (turn === void 0) {
|
|
14906
|
-
throw new Error("production grok inspect requires an active isolated turn");
|
|
14907
|
-
}
|
|
14908
|
-
return inspectControlledGrok({
|
|
14909
|
-
binary: turn.binary,
|
|
14910
|
-
cwd: request.cwd,
|
|
14911
|
-
env: turn.env,
|
|
14912
|
-
packageRoot
|
|
14913
|
-
});
|
|
14914
|
-
},
|
|
14915
14553
|
async connect(request) {
|
|
14916
|
-
if (turn === void 0) {
|
|
14917
|
-
throw new Error("production grok connect requires an active isolated turn");
|
|
14918
|
-
}
|
|
14919
14554
|
return connectGrokAcpStdio({
|
|
14920
|
-
binary:
|
|
14555
|
+
binary: resolveGrokBinary(request.home),
|
|
14921
14556
|
cwd: request.cwd,
|
|
14922
|
-
env
|
|
14557
|
+
env,
|
|
14923
14558
|
...request.model === void 0 ? {} : { model: request.model.model }
|
|
14924
14559
|
});
|
|
14925
14560
|
}
|
|
14926
14561
|
});
|
|
14927
|
-
return {
|
|
14928
|
-
executeTurn(request) {
|
|
14929
|
-
const execution = serial.then(
|
|
14930
|
-
() => withProductionGrokIsolation(
|
|
14931
|
-
request.runDirectory,
|
|
14932
|
-
request.home,
|
|
14933
|
-
packageRoot,
|
|
14934
|
-
async (binding) => {
|
|
14935
|
-
turn = binding;
|
|
14936
|
-
try {
|
|
14937
|
-
return await inner.executeTurn({ ...request, home: binding.controlledHome });
|
|
14938
|
-
} finally {
|
|
14939
|
-
turn = void 0;
|
|
14940
|
-
}
|
|
14941
|
-
}
|
|
14942
|
-
)
|
|
14943
|
-
);
|
|
14944
|
-
serial = execution.then(
|
|
14945
|
-
() => void 0,
|
|
14946
|
-
() => void 0
|
|
14947
|
-
);
|
|
14948
|
-
return execution;
|
|
14949
|
-
}
|
|
14950
|
-
};
|
|
14951
14562
|
}
|
|
14952
14563
|
export {
|
|
14953
|
-
NO_PRODUCTION_GROK_PRIMARY_FAILURE,
|
|
14954
|
-
bindProductionGrokIsolation,
|
|
14955
14564
|
createGrokRoleRuntimeDependencies,
|
|
14956
|
-
createProductionGrokRoleTurnHost
|
|
14957
|
-
openProductionGrokHome,
|
|
14958
|
-
settleProductionGrokHomeCleanup,
|
|
14959
|
-
withProductionGrokIsolation
|
|
14565
|
+
createProductionGrokRoleTurnHost
|
|
14960
14566
|
};
|