@akagilnc/pi-workflow-roles 0.1.3558 → 0.1.3565
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/acp-host/description.js +21 -0
- package/dist/{grok → acp-host}/mcp-relay.mjs +5 -5
- package/dist/{grok → acp-host}/production-host.js +111 -108
- package/dist/host-descriptions.js +34 -0
- package/dist/public-cli/config.js +23 -10
- package/dist/public-cli/main.js +89 -37
- package/package.json +1 -1
- package/scripts/build-package.mjs +8 -8
- package/src/acp-host/description.ts +43 -0
- package/src/{grok → acp-host}/mcp-relay.mjs +5 -5
- package/src/{grok → acp-host}/production-host.ts +30 -37
- package/src/{grok → acp-host}/role-envelope.ts +23 -23
- package/src/{grok → acp-host}/role-turn-host.ts +46 -81
- package/src/{grok → acp-host}/session-identity.ts +7 -7
- package/src/host-contracts.ts +5 -3
- package/src/host-descriptions.ts +51 -0
- package/src/host-transition-prior-native.ts +12 -24
- package/src/pi/role-turn-host.ts +2 -1
- package/src/public-cli/cli.ts +10 -9
- package/src/public-cli/config.ts +24 -11
- package/src/public-cli/load-production-acp-host.ts +52 -0
- package/src/public-cli/post-admission.ts +1 -1
- package/src/public-cli/load-production-grok-host.ts +0 -35
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One ACP host description. Every host-specific value the generic ACP adapter
|
|
3
|
+
* needs — binary location, argv shape, resume verb, binding filename, child env
|
|
4
|
+
* — is data here; the lifecycle in role-turn-host.ts stays one copy (#732).
|
|
5
|
+
*/
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
/** Absolute agent binary for one operator home. */
|
|
8
|
+
export function resolveAcpBinary(description, operatorHome) {
|
|
9
|
+
return join(operatorHome, ...description.binaryFromHome);
|
|
10
|
+
}
|
|
11
|
+
/** Stdio argv: prefix, optional model/thinking flag pairs, suffix. */
|
|
12
|
+
export function acpStdioArgs(description, model) {
|
|
13
|
+
const { prefix, suffix, modelFlag, thinkingFlag } = description.argv;
|
|
14
|
+
const pair = (flag, value) => flag === undefined || value === undefined ? [] : [flag, value];
|
|
15
|
+
return [
|
|
16
|
+
...prefix,
|
|
17
|
+
...pair(modelFlag, model?.model),
|
|
18
|
+
...pair(thinkingFlag, model?.thinking),
|
|
19
|
+
...suffix,
|
|
20
|
+
];
|
|
21
|
+
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { connect } from "node:net";
|
|
3
3
|
import { createInterface } from "node:readline";
|
|
4
4
|
|
|
5
|
-
const socketPath = process.env.
|
|
6
|
-
const token = process.env.
|
|
7
|
-
if (!socketPath || !token) throw new Error("AK
|
|
5
|
+
const socketPath = process.env.AK_ACP_MCP_SOCKET;
|
|
6
|
+
const token = process.env.AK_ACP_MCP_TOKEN;
|
|
7
|
+
if (!socketPath || !token) throw new Error("AK ACP MCP relay identity is missing");
|
|
8
8
|
|
|
9
9
|
const upstream = connect(socketPath);
|
|
10
10
|
const waiters = new Map();
|
|
@@ -45,7 +45,7 @@ upstream.on("error", (error) => settle(error));
|
|
|
45
45
|
upstream.on("close", () => {
|
|
46
46
|
// Shutdown may already be requested (stdin EOF) while an RPC is still
|
|
47
47
|
// in flight. Outstanding waiters must still settle, or drain never ends.
|
|
48
|
-
if (!exiting) settle(new Error("AK
|
|
48
|
+
if (!exiting) settle(new Error("AK ACP MCP upstream closed"));
|
|
49
49
|
maybeExit();
|
|
50
50
|
});
|
|
51
51
|
createInterface({ input: upstream }).on("line", (line) => {
|
|
@@ -56,7 +56,7 @@ createInterface({ input: upstream }).on("line", (line) => {
|
|
|
56
56
|
if (waiter === undefined) return;
|
|
57
57
|
waiters.delete(message.id);
|
|
58
58
|
if (message.error !== undefined) {
|
|
59
|
-
const error = new Error(typeof message.error.message === "string" ? message.error.message : "AK
|
|
59
|
+
const error = new Error(typeof message.error.message === "string" ? message.error.message : "AK ACP MCP relay failure");
|
|
60
60
|
error.code = message.error.code;
|
|
61
61
|
error.cause = message.error;
|
|
62
62
|
waiter.reject(error);
|
|
@@ -1238,9 +1238,8 @@ var init_in_process_session = __esm({
|
|
|
1238
1238
|
}
|
|
1239
1239
|
});
|
|
1240
1240
|
|
|
1241
|
-
// src/
|
|
1241
|
+
// src/acp-host/production-host.ts
|
|
1242
1242
|
import { readFile as readFile15 } from "node:fs/promises";
|
|
1243
|
-
import { join as join24 } from "node:path";
|
|
1244
1243
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1245
1244
|
|
|
1246
1245
|
// src/canonical-skill-binding.ts
|
|
@@ -3696,6 +3695,29 @@ function appendEngineSessionMaterial(lines, engineMaterial) {
|
|
|
3696
3695
|
return out;
|
|
3697
3696
|
}
|
|
3698
3697
|
|
|
3698
|
+
// src/host-descriptions.ts
|
|
3699
|
+
var PRIVATE_COMPAT_ENV = Object.fromEntries(
|
|
3700
|
+
["CLAUDE", "CURSOR", "CODEX"].flatMap((vendor) => ["SKILLS", "RULES", "AGENTS", "MCPS", "HOOKS", "SESSIONS"].map((kind) => [`GROK_${vendor}_${kind}_ENABLED`, "false"]))
|
|
3701
|
+
);
|
|
3702
|
+
var HOST_DESCRIPTIONS = Object.freeze({
|
|
3703
|
+
/** Operator home `~/.grok`, native session/load resume, `agent [--model X] stdio`. */
|
|
3704
|
+
"grok-build": Object.freeze({
|
|
3705
|
+
binaryFromHome: Object.freeze([".grok", "bin", "grok"]),
|
|
3706
|
+
argv: Object.freeze({
|
|
3707
|
+
prefix: Object.freeze(["agent"]),
|
|
3708
|
+
suffix: Object.freeze(["stdio"]),
|
|
3709
|
+
modelFlag: "--model"
|
|
3710
|
+
}),
|
|
3711
|
+
boundResume: "session/load",
|
|
3712
|
+
sessionBindingFile: "grok-acp-session.json",
|
|
3713
|
+
childEnv: Object.freeze({
|
|
3714
|
+
...PRIVATE_COMPAT_ENV,
|
|
3715
|
+
GROK_MEMORY: "0",
|
|
3716
|
+
GROK_SUBAGENTS: "0"
|
|
3717
|
+
})
|
|
3718
|
+
})
|
|
3719
|
+
});
|
|
3720
|
+
|
|
3699
3721
|
// src/institutional-resolution.ts
|
|
3700
3722
|
import { readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
|
|
3701
3723
|
import { join as join7 } from "node:path";
|
|
@@ -13564,14 +13586,30 @@ function createRoleRuntimeExtension(dependencies) {
|
|
|
13564
13586
|
};
|
|
13565
13587
|
}
|
|
13566
13588
|
|
|
13567
|
-
// src/
|
|
13589
|
+
// src/acp-host/description.ts
|
|
13590
|
+
import { join as join22 } from "node:path";
|
|
13591
|
+
function resolveAcpBinary(description, operatorHome) {
|
|
13592
|
+
return join22(operatorHome, ...description.binaryFromHome);
|
|
13593
|
+
}
|
|
13594
|
+
function acpStdioArgs(description, model) {
|
|
13595
|
+
const { prefix, suffix, modelFlag, thinkingFlag } = description.argv;
|
|
13596
|
+
const pair = (flag, value) => flag === void 0 || value === void 0 ? [] : [flag, value];
|
|
13597
|
+
return [
|
|
13598
|
+
...prefix,
|
|
13599
|
+
...pair(modelFlag, model?.model),
|
|
13600
|
+
...pair(thinkingFlag, model?.thinking),
|
|
13601
|
+
...suffix
|
|
13602
|
+
];
|
|
13603
|
+
}
|
|
13604
|
+
|
|
13605
|
+
// src/acp-host/role-envelope.ts
|
|
13568
13606
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
13569
13607
|
import { mkdir as mkdir3, readFile as readFile13, writeFile as writeFile7 } from "node:fs/promises";
|
|
13570
13608
|
import { createServer } from "node:net";
|
|
13571
|
-
import { basename as basename7, dirname as dirname15, join as
|
|
13609
|
+
import { basename as basename7, dirname as dirname15, join as join23 } from "node:path";
|
|
13572
13610
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
13573
13611
|
|
|
13574
|
-
// src/
|
|
13612
|
+
// src/acp-host/role-turn-host.ts
|
|
13575
13613
|
import { spawn as spawn4 } from "node:child_process";
|
|
13576
13614
|
import { createInterface } from "node:readline";
|
|
13577
13615
|
|
|
@@ -13581,8 +13619,8 @@ function renderAgentStartMaterials(body, materials) {
|
|
|
13581
13619
|
return [body, ...materials.map((material) => JSON.stringify(material))].join("\n\n");
|
|
13582
13620
|
}
|
|
13583
13621
|
|
|
13584
|
-
// src/
|
|
13585
|
-
function
|
|
13622
|
+
// src/acp-host/role-turn-host.ts
|
|
13623
|
+
function renderAcpSystemPromptOverride(authority) {
|
|
13586
13624
|
return renderAgentStartMaterials(authority.body, authority.materials);
|
|
13587
13625
|
}
|
|
13588
13626
|
function failure(cause, name, code, details) {
|
|
@@ -13598,19 +13636,13 @@ function failure(cause, name, code, details) {
|
|
|
13598
13636
|
};
|
|
13599
13637
|
}
|
|
13600
13638
|
function hostAbortedError() {
|
|
13601
|
-
return Object.assign(new Error("
|
|
13639
|
+
return Object.assign(new Error("ACP host aborted"), { code: "host-aborted" });
|
|
13602
13640
|
}
|
|
13603
13641
|
function acpError(code, message, cause) {
|
|
13604
13642
|
return Object.assign(new Error(message, cause === void 0 ? void 0 : { cause }), { code });
|
|
13605
13643
|
}
|
|
13606
|
-
function
|
|
13607
|
-
const
|
|
13608
|
-
"agent",
|
|
13609
|
-
...options.model === void 0 ? [] : ["--model", options.model],
|
|
13610
|
-
"stdio"
|
|
13611
|
-
];
|
|
13612
|
-
const env = options.toolset === void 0 ? options.env : { ...options.env, GROK_CONFIG: JSON.stringify({ toolset: options.toolset }) };
|
|
13613
|
-
const child = spawn4(options.binary, args, { cwd: options.cwd, env, stdio: ["pipe", "pipe", "pipe"] });
|
|
13644
|
+
function connectAcpStdio(options) {
|
|
13645
|
+
const child = spawn4(options.binary, [...options.args], { cwd: options.cwd, env: options.env, stdio: ["pipe", "pipe", "pipe"] });
|
|
13614
13646
|
const pending = /* @__PURE__ */ new Map();
|
|
13615
13647
|
const notificationHandlers = [];
|
|
13616
13648
|
if (options.onNotification !== void 0) notificationHandlers.push(options.onNotification);
|
|
@@ -13633,13 +13665,13 @@ function connectGrokAcpStdio(options) {
|
|
|
13633
13665
|
child.stderr.setEncoding("utf8").on("data", (chunk) => {
|
|
13634
13666
|
stderr += chunk;
|
|
13635
13667
|
});
|
|
13636
|
-
child.on("error", (error) => settleClosed(acpError("acp-process-error", `
|
|
13668
|
+
child.on("error", (error) => settleClosed(acpError("acp-process-error", `ACP process error: ${error.message}`, error)));
|
|
13637
13669
|
createInterface({ input: child.stdout }).on("line", (line2) => {
|
|
13638
13670
|
let message;
|
|
13639
13671
|
try {
|
|
13640
13672
|
message = JSON.parse(line2);
|
|
13641
13673
|
} catch (error) {
|
|
13642
|
-
terminate(acpError("acp-invalid-json", `Invalid
|
|
13674
|
+
terminate(acpError("acp-invalid-json", `Invalid ACP JSON: ${String(error)}`, error));
|
|
13643
13675
|
return;
|
|
13644
13676
|
}
|
|
13645
13677
|
if (typeof message.method === "string") {
|
|
@@ -13647,13 +13679,13 @@ function connectGrokAcpStdio(options) {
|
|
|
13647
13679
|
for (const handler of notificationHandlers) handler(message.method, params);
|
|
13648
13680
|
if (typeof message.id === "number") {
|
|
13649
13681
|
if (message.method !== "session/request_permission") {
|
|
13650
|
-
terminate(acpError("acp-unsupported-client-request", `Unsupported
|
|
13682
|
+
terminate(acpError("acp-unsupported-client-request", `Unsupported ACP client request: ${message.method}`));
|
|
13651
13683
|
return;
|
|
13652
13684
|
}
|
|
13653
13685
|
const choices = Array.isArray(params.options) ? params.options : [];
|
|
13654
13686
|
const selected = choices.find((value) => typeof value === "object" && value !== null && value.kind === "allow_once");
|
|
13655
13687
|
if (typeof selected?.optionId !== "string") {
|
|
13656
|
-
terminate(acpError("acp-permission-missing-allow-once", "
|
|
13688
|
+
terminate(acpError("acp-permission-missing-allow-once", "ACP permission request omitted allow_once"));
|
|
13657
13689
|
return;
|
|
13658
13690
|
}
|
|
13659
13691
|
child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id: message.id, result: { outcome: { outcome: "selected", optionId: selected.optionId } } })}
|
|
@@ -13665,13 +13697,13 @@ function connectGrokAcpStdio(options) {
|
|
|
13665
13697
|
const waiter = pending.get(message.id);
|
|
13666
13698
|
if (waiter === void 0) return;
|
|
13667
13699
|
pending.delete(message.id);
|
|
13668
|
-
if (message.error !== void 0) waiter.reject(acpError("acp-upstream-error", `
|
|
13700
|
+
if (message.error !== void 0) waiter.reject(acpError("acp-upstream-error", `ACP error: ${JSON.stringify(message.error)}`));
|
|
13669
13701
|
else waiter.resolve(message.result ?? {});
|
|
13670
13702
|
});
|
|
13671
|
-
child.on("close", (code) => settleClosed(acpError("acp-closed", `
|
|
13703
|
+
child.on("close", (code) => settleClosed(acpError("acp-closed", `ACP closed (${String(code)}): ${stderr}`)));
|
|
13672
13704
|
return Promise.resolve({
|
|
13673
13705
|
request(method, params) {
|
|
13674
|
-
if (closed) return Promise.reject(terminalError ?? acpError("acp-connection-closed", "
|
|
13706
|
+
if (closed) return Promise.reject(terminalError ?? acpError("acp-connection-closed", "ACP connection is closed"));
|
|
13675
13707
|
const id = ++nextId;
|
|
13676
13708
|
return new Promise((resolve17, reject) => {
|
|
13677
13709
|
pending.set(id, { resolve: resolve17, reject });
|
|
@@ -13681,12 +13713,12 @@ function connectGrokAcpStdio(options) {
|
|
|
13681
13713
|
const waiter = pending.get(id);
|
|
13682
13714
|
if (waiter === void 0) return;
|
|
13683
13715
|
pending.delete(id);
|
|
13684
|
-
waiter.reject(acpError("acp-write-failed", `
|
|
13716
|
+
waiter.reject(acpError("acp-write-failed", `ACP write failed: ${error.message}`, error));
|
|
13685
13717
|
});
|
|
13686
13718
|
});
|
|
13687
13719
|
},
|
|
13688
13720
|
notify(method, params) {
|
|
13689
|
-
if (closed) throw terminalError ?? acpError("acp-connection-closed", "
|
|
13721
|
+
if (closed) throw terminalError ?? acpError("acp-connection-closed", "ACP connection is closed");
|
|
13690
13722
|
child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", method, params })}
|
|
13691
13723
|
`);
|
|
13692
13724
|
},
|
|
@@ -13695,14 +13727,14 @@ function connectGrokAcpStdio(options) {
|
|
|
13695
13727
|
},
|
|
13696
13728
|
async close() {
|
|
13697
13729
|
if (closed) return;
|
|
13698
|
-
settleClosed(acpError("acp-connection-closed", "
|
|
13730
|
+
settleClosed(acpError("acp-connection-closed", "ACP connection is closed"));
|
|
13699
13731
|
child.stdin.end();
|
|
13700
13732
|
child.kill("SIGTERM");
|
|
13701
13733
|
await new Promise((resolve17) => child.once("close", () => resolve17()));
|
|
13702
13734
|
}
|
|
13703
13735
|
});
|
|
13704
13736
|
}
|
|
13705
|
-
function
|
|
13737
|
+
function createAcpRoleTurnHost(config) {
|
|
13706
13738
|
let serial = Promise.resolve();
|
|
13707
13739
|
return {
|
|
13708
13740
|
executeTurn(request) {
|
|
@@ -13714,7 +13746,7 @@ function createGrokRoleTurnHost(config) {
|
|
|
13714
13746
|
let accepted = false;
|
|
13715
13747
|
try {
|
|
13716
13748
|
if (prepared.mcpServers.length === 0) {
|
|
13717
|
-
return failure("activation", "
|
|
13749
|
+
return failure("activation", "UncontrolledAcpSession", "ak-config-missing");
|
|
13718
13750
|
}
|
|
13719
13751
|
connection = await config.connect(request);
|
|
13720
13752
|
const initialized = await connection.request("initialize", {
|
|
@@ -13725,49 +13757,36 @@ function createGrokRoleTurnHost(config) {
|
|
|
13725
13757
|
const modelState = initializeMeta?.modelState;
|
|
13726
13758
|
const availableModels = Array.isArray(modelState?.availableModels) ? modelState.availableModels : void 0;
|
|
13727
13759
|
if (request.model !== void 0 && availableModels !== void 0 && !availableModels.some((entry) => typeof entry === "object" && entry !== null && entry.modelId === request.model?.model)) {
|
|
13728
|
-
return failure("activation", "
|
|
13760
|
+
return failure("activation", "AcpHostModelMismatch", "host-model-mismatch", {
|
|
13729
13761
|
provider: request.model.provider,
|
|
13730
13762
|
model: request.model.model
|
|
13731
13763
|
});
|
|
13732
13764
|
}
|
|
13733
|
-
const priorNativePaths = continuation.kind === "resume"
|
|
13734
|
-
if (continuation.kind === "resume") {
|
|
13765
|
+
const priorNativePaths = continuation.kind === "resume" ? request.hostTransition?.priorNativePaths : void 0;
|
|
13766
|
+
if (continuation.kind === "resume" && config.boundResume === "session/load") {
|
|
13735
13767
|
const boundSessionId = await config.sessionIdentity.load(request.principal);
|
|
13736
13768
|
if (boundSessionId !== void 0 && boundSessionId !== "") {
|
|
13737
13769
|
const loaded = await connection.request("session/load", {
|
|
13738
13770
|
sessionId: boundSessionId,
|
|
13739
13771
|
cwd: request.cwd,
|
|
13740
13772
|
mcpServers: prepared.mcpServers,
|
|
13741
|
-
_meta: { systemPromptOverride:
|
|
13773
|
+
_meta: { systemPromptOverride: renderAcpSystemPromptOverride(prepared.systemPrompt), yoloMode: false }
|
|
13742
13774
|
});
|
|
13743
13775
|
sessionId = typeof loaded.sessionId === "string" && loaded.sessionId !== "" ? loaded.sessionId : boundSessionId;
|
|
13744
|
-
} else {
|
|
13745
|
-
const session = await connection.request(
|
|
13746
|
-
"session/new",
|
|
13747
|
-
{
|
|
13748
|
-
cwd: request.cwd,
|
|
13749
|
-
mcpServers: prepared.mcpServers,
|
|
13750
|
-
_meta: { systemPromptOverride: renderGrokSystemPromptOverride(prepared.systemPrompt), yoloMode: false }
|
|
13751
|
-
}
|
|
13752
|
-
);
|
|
13753
|
-
sessionId = typeof session.sessionId === "string" ? session.sessionId : void 0;
|
|
13754
|
-
if (sessionId === void 0 || sessionId === "") {
|
|
13755
|
-
return failure("session", "GrokAcpSessionFailure", "session-id-missing");
|
|
13756
|
-
}
|
|
13757
|
-
await config.sessionIdentity.bind(request.principal, sessionId);
|
|
13758
13776
|
}
|
|
13759
|
-
}
|
|
13777
|
+
}
|
|
13778
|
+
if (sessionId === void 0) {
|
|
13760
13779
|
const session = await connection.request(
|
|
13761
13780
|
"session/new",
|
|
13762
13781
|
{
|
|
13763
13782
|
cwd: request.cwd,
|
|
13764
13783
|
mcpServers: prepared.mcpServers,
|
|
13765
|
-
_meta: { systemPromptOverride:
|
|
13784
|
+
_meta: { systemPromptOverride: renderAcpSystemPromptOverride(prepared.systemPrompt), yoloMode: false }
|
|
13766
13785
|
}
|
|
13767
13786
|
);
|
|
13768
13787
|
sessionId = typeof session.sessionId === "string" ? session.sessionId : void 0;
|
|
13769
13788
|
if (sessionId === void 0 || sessionId === "") {
|
|
13770
|
-
return failure("session", "
|
|
13789
|
+
return failure("session", "AcpSessionFailure", "session-id-missing");
|
|
13771
13790
|
}
|
|
13772
13791
|
await config.sessionIdentity.bind(request.principal, sessionId);
|
|
13773
13792
|
}
|
|
@@ -13828,7 +13847,7 @@ ${priorNativePaths.join("\n")}` : prepared.prompt;
|
|
|
13828
13847
|
throw error;
|
|
13829
13848
|
}
|
|
13830
13849
|
if (result2.stopReason === "refusal") {
|
|
13831
|
-
return failure("output", "
|
|
13850
|
+
return failure("output", "AcpRefusal", "refusal", { sessionId });
|
|
13832
13851
|
}
|
|
13833
13852
|
const closure = await prepared.closeRound();
|
|
13834
13853
|
if (closure.accepted) {
|
|
@@ -13841,7 +13860,7 @@ ${priorNativePaths.join("\n")}` : prepared.prompt;
|
|
|
13841
13860
|
}
|
|
13842
13861
|
prompt = `The prior terminal submission was rejected (${closure.retry.code}). Resubmit it as the sole terminal tool call. Rejected call ids: ${closure.retry.toolCallIds.join(", ") || "none"}.`;
|
|
13843
13862
|
}
|
|
13844
|
-
return failure("output", "
|
|
13863
|
+
return failure("output", "AcpRoundLimit", "round-retry-limit", { sessionId });
|
|
13845
13864
|
} finally {
|
|
13846
13865
|
if (connection !== void 0) {
|
|
13847
13866
|
if (sessionId !== void 0 && !accepted) {
|
|
@@ -13866,25 +13885,14 @@ ${priorNativePaths.join("\n")}` : prepared.prompt;
|
|
|
13866
13885
|
}
|
|
13867
13886
|
};
|
|
13868
13887
|
}
|
|
13869
|
-
var PRIVATE_COMPAT_ENV = Object.fromEntries(
|
|
13870
|
-
["CLAUDE", "CURSOR", "CODEX"].flatMap((vendor) => ["SKILLS", "RULES", "AGENTS", "MCPS", "HOOKS", "SESSIONS"].map((kind) => [`GROK_${vendor}_${kind}_ENABLED`, "false"]))
|
|
13871
|
-
);
|
|
13872
|
-
function controlledGrokChildEnv(base) {
|
|
13873
|
-
return {
|
|
13874
|
-
...base,
|
|
13875
|
-
...PRIVATE_COMPAT_ENV,
|
|
13876
|
-
GROK_MEMORY: "0",
|
|
13877
|
-
GROK_SUBAGENTS: "0"
|
|
13878
|
-
};
|
|
13879
|
-
}
|
|
13880
13888
|
|
|
13881
|
-
// src/
|
|
13889
|
+
// src/acp-host/role-envelope.ts
|
|
13882
13890
|
function parseCanonicalSkillInvocation(prompt) {
|
|
13883
13891
|
const match = /^\/skill:([A-Za-z0-9_-]+)(?:\s+([\s\S]*))?$/s.exec(prompt.trim());
|
|
13884
13892
|
if (match === null) return void 0;
|
|
13885
13893
|
return { name: match[1], userMessage: (match[2] ?? "").trim() };
|
|
13886
13894
|
}
|
|
13887
|
-
function
|
|
13895
|
+
function buildAcpSkillExpansion(methodSkills, prompt) {
|
|
13888
13896
|
const parsed = parseCanonicalSkillInvocation(prompt);
|
|
13889
13897
|
if (parsed === void 0) return void 0;
|
|
13890
13898
|
const method = methodSkills.get(parsed.name);
|
|
@@ -13898,7 +13906,7 @@ ${method.body}`,
|
|
|
13898
13906
|
userMessage: parsed.userMessage
|
|
13899
13907
|
});
|
|
13900
13908
|
}
|
|
13901
|
-
function
|
|
13909
|
+
function projectAcpActivationFlags(request) {
|
|
13902
13910
|
const activation = request.activation;
|
|
13903
13911
|
const flags = /* @__PURE__ */ new Map([["ak-role", activation.role]]);
|
|
13904
13912
|
const inputFlag = packagedRoleInputFlag(activation.role);
|
|
@@ -13936,21 +13944,21 @@ async function listen(server, path) {
|
|
|
13936
13944
|
});
|
|
13937
13945
|
});
|
|
13938
13946
|
}
|
|
13939
|
-
function
|
|
13940
|
-
return
|
|
13947
|
+
function createComposedAcpRoleTurnHost(config) {
|
|
13948
|
+
return createAcpRoleTurnHost({
|
|
13941
13949
|
...config,
|
|
13942
|
-
prepare: (request) =>
|
|
13950
|
+
prepare: (request) => prepareAcpRoleEnvelope({
|
|
13943
13951
|
request,
|
|
13944
13952
|
dependencies: config.roleRuntimeDependencies,
|
|
13945
13953
|
// Same durable-principal path settlement uses for isAvailable (#617 DK-4 layout).
|
|
13946
13954
|
sessionFile: config.sessionIdentity.resolveSessionFile(request.principal),
|
|
13947
|
-
socketPath: config.socketPath?.(request) ?? `/tmp/ak-
|
|
13955
|
+
socketPath: config.socketPath?.(request) ?? `/tmp/ak-acp-mcp-${randomUUID2()}.sock`
|
|
13948
13956
|
})
|
|
13949
13957
|
});
|
|
13950
13958
|
}
|
|
13951
|
-
async function
|
|
13959
|
+
async function prepareAcpRoleEnvelope(options) {
|
|
13952
13960
|
const { request } = options;
|
|
13953
|
-
const flags =
|
|
13961
|
+
const flags = projectAcpActivationFlags(request);
|
|
13954
13962
|
const tools = /* @__PURE__ */ new Map();
|
|
13955
13963
|
const handlers = /* @__PURE__ */ new Map();
|
|
13956
13964
|
const calls = [];
|
|
@@ -13969,7 +13977,7 @@ async function prepareGrokRoleEnvelope(options) {
|
|
|
13969
13977
|
const raw = await readFile13(method.path, "utf8");
|
|
13970
13978
|
methodSkills.set(name, { path: method.path, body: stripSkillFrontmatter(raw).trim() });
|
|
13971
13979
|
}
|
|
13972
|
-
let sessionFile = options.sessionFile ??
|
|
13980
|
+
let sessionFile = options.sessionFile ?? join23(request.runDirectory, "session", "session.jsonl");
|
|
13973
13981
|
await mkdir3(dirname15(sessionFile), { recursive: true });
|
|
13974
13982
|
if (request.continuation.kind !== "resume") {
|
|
13975
13983
|
try {
|
|
@@ -14034,7 +14042,7 @@ async function prepareGrokRoleEnvelope(options) {
|
|
|
14034
14042
|
},
|
|
14035
14043
|
capabilities: {
|
|
14036
14044
|
skillExpansion(prompt) {
|
|
14037
|
-
return
|
|
14045
|
+
return buildAcpSkillExpansion(methodSkills, prompt);
|
|
14038
14046
|
}
|
|
14039
14047
|
},
|
|
14040
14048
|
registerFlag(name, definition) {
|
|
@@ -14046,12 +14054,12 @@ async function prepareGrokRoleEnvelope(options) {
|
|
|
14046
14054
|
registerTool(tool2) {
|
|
14047
14055
|
tools.set(tool2.name, tool2);
|
|
14048
14056
|
},
|
|
14049
|
-
// The real AK-owned surface only;
|
|
14057
|
+
// The real AK-owned surface only; the host builtin surface is host-side and
|
|
14050
14058
|
// observable after session/new, never echoed back into role-requested names.
|
|
14051
14059
|
getAllTools() {
|
|
14052
14060
|
return [...tools.keys()].map((name) => ({ name }));
|
|
14053
14061
|
},
|
|
14054
|
-
//
|
|
14062
|
+
// The host receives tool choice as role guidance; every tool registered for the
|
|
14055
14063
|
// seat remains reachable through MCP.
|
|
14056
14064
|
setActiveTools(names) {
|
|
14057
14065
|
preferredTools = [...names];
|
|
@@ -14333,7 +14341,7 @@ async function prepareGrokRoleEnvelope(options) {
|
|
|
14333
14341
|
}
|
|
14334
14342
|
if (cleanupFailures.length === 1) throw cleanupFailures[0];
|
|
14335
14343
|
if (cleanupFailures.length > 1) {
|
|
14336
|
-
throw new AggregateError(cleanupFailures, "
|
|
14344
|
+
throw new AggregateError(cleanupFailures, "ACP envelope dispose cleanup failures", {
|
|
14337
14345
|
cause: cleanupFailures[0]
|
|
14338
14346
|
});
|
|
14339
14347
|
}
|
|
@@ -14410,8 +14418,8 @@ async function prepareGrokRoleEnvelope(options) {
|
|
|
14410
14418
|
command: process.execPath,
|
|
14411
14419
|
args: [relay],
|
|
14412
14420
|
env: [
|
|
14413
|
-
{ name: "
|
|
14414
|
-
{ name: "
|
|
14421
|
+
{ name: "AK_ACP_MCP_SOCKET", value: options.socketPath },
|
|
14422
|
+
{ name: "AK_ACP_MCP_TOKEN", value: token }
|
|
14415
14423
|
]
|
|
14416
14424
|
}],
|
|
14417
14425
|
systemPrompt: { body: systemPromptBody, materials: readingMaterials },
|
|
@@ -14426,7 +14434,7 @@ async function prepareGrokRoleEnvelope(options) {
|
|
|
14426
14434
|
} catch (cleanupFailure) {
|
|
14427
14435
|
throw new AggregateError(
|
|
14428
14436
|
[error, cleanupFailure],
|
|
14429
|
-
"
|
|
14437
|
+
"prepareAcpRoleEnvelope activation failed and its dispose cleanup also failed",
|
|
14430
14438
|
{ cause: error }
|
|
14431
14439
|
);
|
|
14432
14440
|
}
|
|
@@ -14434,12 +14442,11 @@ async function prepareGrokRoleEnvelope(options) {
|
|
|
14434
14442
|
}
|
|
14435
14443
|
}
|
|
14436
14444
|
|
|
14437
|
-
// src/
|
|
14445
|
+
// src/acp-host/session-identity.ts
|
|
14438
14446
|
import { mkdir as mkdir4, readFile as readFile14, rename, writeFile as writeFile8 } from "node:fs/promises";
|
|
14439
|
-
import { dirname as dirname16, join as
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
const bindingPath = (principal) => join23(authority.decode(principal).sessionDirectory, GROK_ACP_SESSION_BINDING);
|
|
14447
|
+
import { dirname as dirname16, join as join24 } from "node:path";
|
|
14448
|
+
function createAcpSessionIdentityAuthority(authority, sessionBindingFile) {
|
|
14449
|
+
const bindingPath = (principal) => join24(authority.decode(principal).sessionDirectory, sessionBindingFile);
|
|
14443
14450
|
return {
|
|
14444
14451
|
resolveSessionFile(principal) {
|
|
14445
14452
|
return authority.decode(principal).sessionFile;
|
|
@@ -14448,7 +14455,7 @@ function createGrokSessionIdentityAuthority(authority) {
|
|
|
14448
14455
|
try {
|
|
14449
14456
|
const value = JSON.parse(await readFile14(bindingPath(principal), "utf8"));
|
|
14450
14457
|
if (typeof value !== "object" || value === null || typeof value.sessionId !== "string") {
|
|
14451
|
-
throw new Error("durable
|
|
14458
|
+
throw new Error("durable ACP session binding is invalid");
|
|
14452
14459
|
}
|
|
14453
14460
|
return value.sessionId;
|
|
14454
14461
|
} catch (error) {
|
|
@@ -14467,20 +14474,11 @@ function createGrokSessionIdentityAuthority(authority) {
|
|
|
14467
14474
|
};
|
|
14468
14475
|
}
|
|
14469
14476
|
|
|
14470
|
-
// src/
|
|
14471
|
-
function resolveGrokBinary(operatorHome) {
|
|
14472
|
-
return join24(operatorHome, ".grok", "bin", "grok");
|
|
14473
|
-
}
|
|
14474
|
-
function childEnv(packageRoot) {
|
|
14475
|
-
return {
|
|
14476
|
-
...controlledGrokChildEnv(process.env),
|
|
14477
|
-
AK_PACKAGE_ROOT: packageRoot
|
|
14478
|
-
};
|
|
14479
|
-
}
|
|
14477
|
+
// src/acp-host/production-host.ts
|
|
14480
14478
|
var navigatorRoutePlaybookPath = fileURLToPath3(
|
|
14481
14479
|
new URL("../../resources/navigator-route-playbook.md", import.meta.url)
|
|
14482
14480
|
);
|
|
14483
|
-
function
|
|
14481
|
+
function createAcpRoleRuntimeDependencies(packageRoot) {
|
|
14484
14482
|
const judgeAuditor = createPiJudgeAuditor();
|
|
14485
14483
|
const doctorAuditor = createPiDoctorAuditor();
|
|
14486
14484
|
const reviewerAgent = createPerDispatchReviewerAgent({ packageRoot });
|
|
@@ -14544,23 +14542,28 @@ function createGrokRoleRuntimeDependencies(packageRoot) {
|
|
|
14544
14542
|
})
|
|
14545
14543
|
};
|
|
14546
14544
|
}
|
|
14547
|
-
function
|
|
14548
|
-
const { packageRoot, principalAuthority } = options;
|
|
14549
|
-
const env =
|
|
14550
|
-
|
|
14551
|
-
|
|
14552
|
-
|
|
14545
|
+
function createProductionAcpRoleTurnHost(options) {
|
|
14546
|
+
const { packageRoot, principalAuthority, description } = options;
|
|
14547
|
+
const env = {
|
|
14548
|
+
...process.env,
|
|
14549
|
+
...description.childEnv,
|
|
14550
|
+
AK_PACKAGE_ROOT: packageRoot
|
|
14551
|
+
};
|
|
14552
|
+
return createComposedAcpRoleTurnHost({
|
|
14553
|
+
sessionIdentity: createAcpSessionIdentityAuthority(principalAuthority, description.sessionBindingFile),
|
|
14554
|
+
boundResume: description.boundResume,
|
|
14555
|
+
roleRuntimeDependencies: createAcpRoleRuntimeDependencies(packageRoot),
|
|
14553
14556
|
async connect(request) {
|
|
14554
|
-
return
|
|
14555
|
-
binary:
|
|
14557
|
+
return connectAcpStdio({
|
|
14558
|
+
binary: resolveAcpBinary(description, request.home),
|
|
14559
|
+
args: acpStdioArgs(description, request.model),
|
|
14556
14560
|
cwd: request.cwd,
|
|
14557
|
-
env
|
|
14558
|
-
...request.model === void 0 ? {} : { model: request.model.model }
|
|
14561
|
+
env
|
|
14559
14562
|
});
|
|
14560
14563
|
}
|
|
14561
14564
|
});
|
|
14562
14565
|
}
|
|
14563
14566
|
export {
|
|
14564
|
-
|
|
14565
|
-
|
|
14567
|
+
createAcpRoleRuntimeDependencies,
|
|
14568
|
+
createProductionAcpRoleTurnHost
|
|
14566
14569
|
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Grok CLI reads vendor-private compat surfaces unless each is disabled by name. */
|
|
2
|
+
const PRIVATE_COMPAT_ENV = Object.fromEntries(["CLAUDE", "CURSOR", "CODEX"].flatMap((vendor) => ["SKILLS", "RULES", "AGENTS", "MCPS", "HOOKS", "SESSIONS"].map((kind) => [`GROK_${vendor}_${kind}_ENABLED`, "false"])));
|
|
3
|
+
export const DEFAULT_ROLE_TURN_HOST = "pi";
|
|
4
|
+
export const HOST_DESCRIPTIONS = Object.freeze({
|
|
5
|
+
/** Operator home `~/.grok`, native session/load resume, `agent [--model X] stdio`. */
|
|
6
|
+
"grok-build": Object.freeze({
|
|
7
|
+
binaryFromHome: Object.freeze([".grok", "bin", "grok"]),
|
|
8
|
+
argv: Object.freeze({
|
|
9
|
+
prefix: Object.freeze(["agent"]),
|
|
10
|
+
suffix: Object.freeze(["stdio"]),
|
|
11
|
+
modelFlag: "--model",
|
|
12
|
+
}),
|
|
13
|
+
boundResume: "session/load",
|
|
14
|
+
sessionBindingFile: "grok-acp-session.json",
|
|
15
|
+
childEnv: Object.freeze({
|
|
16
|
+
...PRIVATE_COMPAT_ENV,
|
|
17
|
+
GROK_MEMORY: "0",
|
|
18
|
+
GROK_SUBAGENTS: "0",
|
|
19
|
+
}),
|
|
20
|
+
}),
|
|
21
|
+
});
|
|
22
|
+
export function lookupHostDescription(host) {
|
|
23
|
+
return Object.hasOwn(HOST_DESCRIPTIONS, host) ? HOST_DESCRIPTIONS[host] : undefined;
|
|
24
|
+
}
|
|
25
|
+
export function packagedExternalHostNames() {
|
|
26
|
+
return Object.keys(HOST_DESCRIPTIONS);
|
|
27
|
+
}
|
|
28
|
+
/** Legal persistent/invocation host: default pi, or a table key. */
|
|
29
|
+
export function assertRegisteredHostName(host) {
|
|
30
|
+
if (host === DEFAULT_ROLE_TURN_HOST || lookupHostDescription(host) !== undefined) {
|
|
31
|
+
return host;
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`unregistered host: ${host}`);
|
|
34
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
+
import { assertRegisteredHostName, DEFAULT_ROLE_TURN_HOST } from "../host-descriptions.js";
|
|
3
4
|
import { assertLegalEngineName } from "../package-resources/engine-material.js";
|
|
4
5
|
import { resolveConfiguredProvinceOfficer } from "../institutional-resolution.js";
|
|
5
6
|
import {
|
|
@@ -95,7 +96,8 @@ function setPersistentSeatHost(config, seat, host) {
|
|
|
95
96
|
}
|
|
96
97
|
return { ...config, seats: { ...config.seats, [seat]: rest } };
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
+
const registered = assertRegisteredHostName(host);
|
|
100
|
+
return { ...config, seats: { ...config.seats, [seat]: { ...previous, host: registered } } };
|
|
99
101
|
}
|
|
100
102
|
function setPersistentSeatEngine(config, seat, engine) {
|
|
101
103
|
const previous = config.seats[seat];
|
|
@@ -140,14 +142,25 @@ function setAutoResumeLimit(config, limit) {
|
|
|
140
142
|
function validatePublicCliConfigAxes(config, _packageRoot) {
|
|
141
143
|
for (const seat of Object.keys(config.seats)) {
|
|
142
144
|
const row = config.seats[seat];
|
|
143
|
-
if (row?.engine
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
145
|
+
if (row?.engine !== void 0) {
|
|
146
|
+
try {
|
|
147
|
+
assertLegalEngineName(row.engine);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`config seat ${seat} engine is illegal: ${row.engine}`,
|
|
151
|
+
{ cause: error }
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (row?.host !== void 0) {
|
|
156
|
+
try {
|
|
157
|
+
assertRegisteredHostName(row.host);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`config seat ${seat} host is unregistered: ${row.host}`,
|
|
161
|
+
{ cause: error }
|
|
162
|
+
);
|
|
163
|
+
}
|
|
151
164
|
}
|
|
152
165
|
}
|
|
153
166
|
}
|
|
@@ -304,7 +317,7 @@ function attachHostAxis(seat, config, invocation) {
|
|
|
304
317
|
if (invocation?.host !== void 0) return { ...seat, host: invocation.host, hostSource: "invocation" };
|
|
305
318
|
const persistent = config.seats[seat.seat]?.host;
|
|
306
319
|
if (persistent !== void 0) return { ...seat, host: persistent, hostSource: "persistent" };
|
|
307
|
-
return { ...seat, host:
|
|
320
|
+
return { ...seat, host: DEFAULT_ROLE_TURN_HOST, hostSource: "default" };
|
|
308
321
|
}
|
|
309
322
|
function attachEngineAxis(seat, config, invocation) {
|
|
310
323
|
if (!isPublicCallableRole(seat.seat)) {
|