@akagilnc/pi-workflow-roles 0.1.3556 → 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
package/dist/public-cli/main.js
CHANGED
|
@@ -15385,6 +15385,48 @@ var init_institutional_resolution = __esm({
|
|
|
15385
15385
|
}
|
|
15386
15386
|
});
|
|
15387
15387
|
|
|
15388
|
+
// src/host-descriptions.ts
|
|
15389
|
+
function lookupHostDescription(host) {
|
|
15390
|
+
return Object.hasOwn(HOST_DESCRIPTIONS, host) ? HOST_DESCRIPTIONS[host] : void 0;
|
|
15391
|
+
}
|
|
15392
|
+
function packagedExternalHostNames() {
|
|
15393
|
+
return Object.keys(HOST_DESCRIPTIONS);
|
|
15394
|
+
}
|
|
15395
|
+
function assertRegisteredHostName(host) {
|
|
15396
|
+
if (host === DEFAULT_ROLE_TURN_HOST || lookupHostDescription(host) !== void 0) {
|
|
15397
|
+
return host;
|
|
15398
|
+
}
|
|
15399
|
+
throw new Error(`unregistered host: ${host}`);
|
|
15400
|
+
}
|
|
15401
|
+
var PRIVATE_COMPAT_ENV, DEFAULT_ROLE_TURN_HOST, HOST_DESCRIPTIONS;
|
|
15402
|
+
var init_host_descriptions = __esm({
|
|
15403
|
+
"src/host-descriptions.ts"() {
|
|
15404
|
+
"use strict";
|
|
15405
|
+
PRIVATE_COMPAT_ENV = Object.fromEntries(
|
|
15406
|
+
["CLAUDE", "CURSOR", "CODEX"].flatMap((vendor) => ["SKILLS", "RULES", "AGENTS", "MCPS", "HOOKS", "SESSIONS"].map((kind) => [`GROK_${vendor}_${kind}_ENABLED`, "false"]))
|
|
15407
|
+
);
|
|
15408
|
+
DEFAULT_ROLE_TURN_HOST = "pi";
|
|
15409
|
+
HOST_DESCRIPTIONS = Object.freeze({
|
|
15410
|
+
/** Operator home `~/.grok`, native session/load resume, `agent [--model X] stdio`. */
|
|
15411
|
+
"grok-build": Object.freeze({
|
|
15412
|
+
binaryFromHome: Object.freeze([".grok", "bin", "grok"]),
|
|
15413
|
+
argv: Object.freeze({
|
|
15414
|
+
prefix: Object.freeze(["agent"]),
|
|
15415
|
+
suffix: Object.freeze(["stdio"]),
|
|
15416
|
+
modelFlag: "--model"
|
|
15417
|
+
}),
|
|
15418
|
+
boundResume: "session/load",
|
|
15419
|
+
sessionBindingFile: "grok-acp-session.json",
|
|
15420
|
+
childEnv: Object.freeze({
|
|
15421
|
+
...PRIVATE_COMPAT_ENV,
|
|
15422
|
+
GROK_MEMORY: "0",
|
|
15423
|
+
GROK_SUBAGENTS: "0"
|
|
15424
|
+
})
|
|
15425
|
+
})
|
|
15426
|
+
});
|
|
15427
|
+
}
|
|
15428
|
+
});
|
|
15429
|
+
|
|
15388
15430
|
// src/public-cli/config.ts
|
|
15389
15431
|
import { mkdir, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
15390
15432
|
import { dirname as dirname4, join as join6 } from "node:path";
|
|
@@ -15468,7 +15510,8 @@ function setPersistentSeatHost(config, seat, host) {
|
|
|
15468
15510
|
}
|
|
15469
15511
|
return { ...config, seats: { ...config.seats, [seat]: rest } };
|
|
15470
15512
|
}
|
|
15471
|
-
|
|
15513
|
+
const registered = assertRegisteredHostName(host);
|
|
15514
|
+
return { ...config, seats: { ...config.seats, [seat]: { ...previous, host: registered } } };
|
|
15472
15515
|
}
|
|
15473
15516
|
function setPersistentSeatEngine(config, seat, engine) {
|
|
15474
15517
|
const previous = config.seats[seat];
|
|
@@ -15513,14 +15556,25 @@ function setAutoResumeLimit(config, limit) {
|
|
|
15513
15556
|
function validatePublicCliConfigAxes(config, _packageRoot) {
|
|
15514
15557
|
for (const seat of Object.keys(config.seats)) {
|
|
15515
15558
|
const row = config.seats[seat];
|
|
15516
|
-
if (row?.engine
|
|
15517
|
-
|
|
15518
|
-
|
|
15519
|
-
|
|
15520
|
-
|
|
15521
|
-
|
|
15522
|
-
|
|
15523
|
-
|
|
15559
|
+
if (row?.engine !== void 0) {
|
|
15560
|
+
try {
|
|
15561
|
+
assertLegalEngineName(row.engine);
|
|
15562
|
+
} catch (error) {
|
|
15563
|
+
throw new Error(
|
|
15564
|
+
`config seat ${seat} engine is illegal: ${row.engine}`,
|
|
15565
|
+
{ cause: error }
|
|
15566
|
+
);
|
|
15567
|
+
}
|
|
15568
|
+
}
|
|
15569
|
+
if (row?.host !== void 0) {
|
|
15570
|
+
try {
|
|
15571
|
+
assertRegisteredHostName(row.host);
|
|
15572
|
+
} catch (error) {
|
|
15573
|
+
throw new Error(
|
|
15574
|
+
`config seat ${seat} host is unregistered: ${row.host}`,
|
|
15575
|
+
{ cause: error }
|
|
15576
|
+
);
|
|
15577
|
+
}
|
|
15524
15578
|
}
|
|
15525
15579
|
}
|
|
15526
15580
|
}
|
|
@@ -15667,7 +15721,7 @@ function attachHostAxis(seat, config, invocation) {
|
|
|
15667
15721
|
if (invocation?.host !== void 0) return { ...seat, host: invocation.host, hostSource: "invocation" };
|
|
15668
15722
|
const persistent = config.seats[seat.seat]?.host;
|
|
15669
15723
|
if (persistent !== void 0) return { ...seat, host: persistent, hostSource: "persistent" };
|
|
15670
|
-
return { ...seat, host:
|
|
15724
|
+
return { ...seat, host: DEFAULT_ROLE_TURN_HOST, hostSource: "default" };
|
|
15671
15725
|
}
|
|
15672
15726
|
function attachEngineAxis(seat, config, invocation) {
|
|
15673
15727
|
if (!isPublicCallableRole(seat.seat)) {
|
|
@@ -15788,6 +15842,7 @@ var GATE_OFFICER_SEATS;
|
|
|
15788
15842
|
var init_config2 = __esm({
|
|
15789
15843
|
"src/public-cli/config.ts"() {
|
|
15790
15844
|
"use strict";
|
|
15845
|
+
init_host_descriptions();
|
|
15791
15846
|
init_engine_material();
|
|
15792
15847
|
init_institutional_resolution();
|
|
15793
15848
|
init_registry2();
|
|
@@ -15817,21 +15872,27 @@ var init_cli_errors = __esm({
|
|
|
15817
15872
|
}
|
|
15818
15873
|
});
|
|
15819
15874
|
|
|
15820
|
-
// src/public-cli/load-production-
|
|
15875
|
+
// src/public-cli/load-production-acp-host.ts
|
|
15821
15876
|
import { existsSync as existsSync3 } from "node:fs";
|
|
15822
15877
|
import { join as join7 } from "node:path";
|
|
15823
15878
|
import { pathToFileURL } from "node:url";
|
|
15824
|
-
async function
|
|
15825
|
-
const
|
|
15826
|
-
|
|
15879
|
+
async function loadProductionAcpHostFactory(packageRoot2, host) {
|
|
15880
|
+
const description = lookupHostDescription(host);
|
|
15881
|
+
if (description === void 0) {
|
|
15882
|
+
throw new Error(`unregistered host: ${host}`);
|
|
15883
|
+
}
|
|
15884
|
+
const built = join7(packageRoot2, "dist/acp-host/production-host.js");
|
|
15885
|
+
const source = join7(packageRoot2, "src/acp-host/production-host.ts");
|
|
15827
15886
|
const target = existsSync3(built) ? built : source;
|
|
15828
15887
|
const href = pathToFileURL(target).href;
|
|
15829
15888
|
const mod = await import(href);
|
|
15830
|
-
|
|
15889
|
+
const create = mod.createProductionAcpRoleTurnHost;
|
|
15890
|
+
return (options) => create({ ...options, description });
|
|
15831
15891
|
}
|
|
15832
|
-
var
|
|
15833
|
-
"src/public-cli/load-production-
|
|
15892
|
+
var init_load_production_acp_host = __esm({
|
|
15893
|
+
"src/public-cli/load-production-acp-host.ts"() {
|
|
15834
15894
|
"use strict";
|
|
15895
|
+
init_host_descriptions();
|
|
15835
15896
|
}
|
|
15836
15897
|
});
|
|
15837
15898
|
|
|
@@ -16548,7 +16609,7 @@ function createPiRoleTurnHost(config) {
|
|
|
16548
16609
|
return {
|
|
16549
16610
|
async executeTurn(request) {
|
|
16550
16611
|
let turnRequest = request;
|
|
16551
|
-
const paths = request.hostTransition?.
|
|
16612
|
+
const paths = request.hostTransition?.priorNativeKind === "sitian" ? request.hostTransition.priorNativePaths : void 0;
|
|
16552
16613
|
if (request.continuation.kind === "resume" && paths !== void 0 && paths.length > 0) {
|
|
16553
16614
|
turnRequest = {
|
|
16554
16615
|
...request,
|
|
@@ -27915,9 +27976,6 @@ var init_turn_request = __esm({
|
|
|
27915
27976
|
// src/host-transition-prior-native.ts
|
|
27916
27977
|
import { access as access2, readdir as readdir6 } from "node:fs/promises";
|
|
27917
27978
|
import { dirname as dirname11, join as join26 } from "node:path";
|
|
27918
|
-
function isKnownRoleTurnHost(value) {
|
|
27919
|
-
return KNOWN_ROLE_TURN_HOSTS.includes(value);
|
|
27920
|
-
}
|
|
27921
27979
|
function isEnoent2(error) {
|
|
27922
27980
|
return typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
27923
27981
|
}
|
|
@@ -27955,27 +28013,20 @@ async function listSitianRecordPaths(sessionParent) {
|
|
|
27955
28013
|
}
|
|
27956
28014
|
async function projectHostTransitionPriorNative(input) {
|
|
27957
28015
|
if (input.previousHost === input.liveHost) return void 0;
|
|
27958
|
-
if (!isKnownRoleTurnHost(input.previousHost) || !isKnownRoleTurnHost(input.liveHost)) {
|
|
27959
|
-
return void 0;
|
|
27960
|
-
}
|
|
27961
28016
|
if (input.previousHost === "pi") {
|
|
27962
|
-
const paths2 = await listPiNativeRecordPaths(input.piSessionFile);
|
|
27963
28017
|
return {
|
|
27964
|
-
|
|
27965
|
-
priorNativePaths:
|
|
28018
|
+
priorNativeKind: "pi-native",
|
|
28019
|
+
priorNativePaths: await listPiNativeRecordPaths(input.piSessionFile)
|
|
27966
28020
|
};
|
|
27967
28021
|
}
|
|
27968
|
-
const paths = await listSitianRecordPaths(input.piSessionFile);
|
|
27969
28022
|
return {
|
|
27970
|
-
|
|
27971
|
-
priorNativePaths:
|
|
28023
|
+
priorNativeKind: "sitian",
|
|
28024
|
+
priorNativePaths: await listSitianRecordPaths(input.piSessionFile)
|
|
27972
28025
|
};
|
|
27973
28026
|
}
|
|
27974
|
-
var KNOWN_ROLE_TURN_HOSTS;
|
|
27975
28027
|
var init_host_transition_prior_native = __esm({
|
|
27976
28028
|
"src/host-transition-prior-native.ts"() {
|
|
27977
28029
|
"use strict";
|
|
27978
|
-
KNOWN_ROLE_TURN_HOSTS = ["pi", "grok-build"];
|
|
27979
28030
|
}
|
|
27980
28031
|
});
|
|
27981
28032
|
|
|
@@ -33012,15 +33063,15 @@ function resolveRoleTurnHost(env, options) {
|
|
|
33012
33063
|
});
|
|
33013
33064
|
const adapters = env.hostAdapters ?? [
|
|
33014
33065
|
{ name: "pi", create: () => ({ ok: true, host: piHost }) },
|
|
33015
|
-
{
|
|
33016
|
-
name
|
|
33066
|
+
...packagedExternalHostNames().map((name) => ({
|
|
33067
|
+
name,
|
|
33017
33068
|
create: () => {
|
|
33018
33069
|
let hostPromise;
|
|
33019
33070
|
return {
|
|
33020
33071
|
ok: true,
|
|
33021
33072
|
host: {
|
|
33022
33073
|
executeTurn: async (request) => {
|
|
33023
|
-
hostPromise ??=
|
|
33074
|
+
hostPromise ??= loadProductionAcpHostFactory(env.packageRoot, name).then(
|
|
33024
33075
|
(create) => create({
|
|
33025
33076
|
packageRoot: env.packageRoot,
|
|
33026
33077
|
principalAuthority: options.principalAuthority
|
|
@@ -33031,7 +33082,7 @@ function resolveRoleTurnHost(env, options) {
|
|
|
33031
33082
|
}
|
|
33032
33083
|
};
|
|
33033
33084
|
}
|
|
33034
|
-
}
|
|
33085
|
+
}))
|
|
33035
33086
|
];
|
|
33036
33087
|
const hostName = options.seat.host;
|
|
33037
33088
|
const adapter = adapters.find((candidate) => candidate.name === hostName);
|
|
@@ -33961,7 +34012,8 @@ var init_cli = __esm({
|
|
|
33961
34012
|
init_config2();
|
|
33962
34013
|
init_registry2();
|
|
33963
34014
|
init_cli_errors();
|
|
33964
|
-
|
|
34015
|
+
init_host_descriptions();
|
|
34016
|
+
init_load_production_acp_host();
|
|
33965
34017
|
init_role_turn_host();
|
|
33966
34018
|
init_invocation();
|
|
33967
34019
|
init_option_definitions();
|
package/package.json
CHANGED
|
@@ -88,16 +88,16 @@ export async function buildPublicAkRoleBin(
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
|
-
* Deferred
|
|
92
|
-
* root selects
|
|
93
|
-
* packages:"external" so optional peers resolve
|
|
91
|
+
* Deferred generic ACP production host artifact. Loaded only when the composition
|
|
92
|
+
* root selects an external host row — keeps role-runtime / peer edges out of the
|
|
93
|
+
* public bin. packages:"external" so optional peers resolve at selection.
|
|
94
94
|
*/
|
|
95
|
-
export async function
|
|
96
|
-
outfile = "dist/
|
|
95
|
+
export async function buildAcpProductionHost(
|
|
96
|
+
outfile = "dist/acp-host/production-host.js",
|
|
97
97
|
) {
|
|
98
98
|
await mkdir(dirname(outfile), { recursive: true });
|
|
99
99
|
await build({
|
|
100
|
-
entryPoints: ["src/
|
|
100
|
+
entryPoints: ["src/acp-host/production-host.ts"],
|
|
101
101
|
outfile,
|
|
102
102
|
format: "esm",
|
|
103
103
|
platform: "node",
|
|
@@ -108,7 +108,7 @@ export async function buildGrokProductionHost(
|
|
|
108
108
|
});
|
|
109
109
|
// role-envelope resolves ./mcp-relay.mjs from import.meta.url — keep it beside the bundle.
|
|
110
110
|
await copyFile(
|
|
111
|
-
resolve("src/
|
|
111
|
+
resolve("src/acp-host/mcp-relay.mjs"),
|
|
112
112
|
join(dirname(outfile), "mcp-relay.mjs"),
|
|
113
113
|
);
|
|
114
114
|
}
|
|
@@ -137,7 +137,7 @@ export async function buildPackageArtifacts() {
|
|
|
137
137
|
);
|
|
138
138
|
}
|
|
139
139
|
await buildPublicAkRoleBin();
|
|
140
|
-
await
|
|
140
|
+
await buildAcpProductionHost();
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
const isMain =
|
|
@@ -0,0 +1,43 @@
|
|
|
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
|
+
|
|
8
|
+
export type AcpHostDescription = Readonly<{
|
|
9
|
+
/** Binary path segments relative to the operator home. */
|
|
10
|
+
binaryFromHome: readonly string[];
|
|
11
|
+
argv: Readonly<{
|
|
12
|
+
prefix: readonly string[];
|
|
13
|
+
suffix: readonly string[];
|
|
14
|
+
modelFlag?: string;
|
|
15
|
+
thinkingFlag?: string;
|
|
16
|
+
}>;
|
|
17
|
+
/** Which verb a bound resume uses; "session/new" hosts always mint + bind. */
|
|
18
|
+
boundResume: "session/load" | "session/new";
|
|
19
|
+
/** Durable ACP binding filename written beside the session principal. */
|
|
20
|
+
sessionBindingFile: string;
|
|
21
|
+
childEnv: Readonly<Record<string, string>>;
|
|
22
|
+
}>;
|
|
23
|
+
|
|
24
|
+
/** Absolute agent binary for one operator home. */
|
|
25
|
+
export function resolveAcpBinary(description: AcpHostDescription, operatorHome: string): string {
|
|
26
|
+
return join(operatorHome, ...description.binaryFromHome);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Stdio argv: prefix, optional model/thinking flag pairs, suffix. */
|
|
30
|
+
export function acpStdioArgs(
|
|
31
|
+
description: AcpHostDescription,
|
|
32
|
+
model?: { readonly model?: string; readonly thinking?: string },
|
|
33
|
+
): string[] {
|
|
34
|
+
const { prefix, suffix, modelFlag, thinkingFlag } = description.argv;
|
|
35
|
+
const pair = (flag: string | undefined, value: string | undefined): string[] =>
|
|
36
|
+
flag === undefined || value === undefined ? [] : [flag, value];
|
|
37
|
+
return [
|
|
38
|
+
...prefix,
|
|
39
|
+
...pair(modelFlag, model?.model),
|
|
40
|
+
...pair(thinkingFlag, model?.thinking),
|
|
41
|
+
...suffix,
|
|
42
|
+
];
|
|
43
|
+
}
|
|
@@ -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);
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Production composition for the
|
|
3
|
-
* Owns injectables around the S6 true adapter; does not alter
|
|
2
|
+
* Production composition for the generic ACP RoleTurnHost adapter (#732).
|
|
3
|
+
* Owns injectables around the S6 true adapter; does not alter adapter behavior.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* factory does not create a run-scoped
|
|
7
|
-
* does not copy or scrub
|
|
5
|
+
* The agent runs against the operator home and its credentials in place. The
|
|
6
|
+
* factory does not create a run-scoped agent home, does not rewrite HOME, and
|
|
7
|
+
* does not copy or scrub credentials. Sitian records on the run are the dossier.
|
|
8
8
|
*/
|
|
9
9
|
import { readFile } from "node:fs/promises";
|
|
10
|
-
import { join } from "node:path";
|
|
11
10
|
import { fileURLToPath } from "node:url";
|
|
12
11
|
|
|
13
12
|
import { loadCanonicalSkillBinding as loadHomeCanonicalSkillBinding } from "../canonical-skill-binding.ts";
|
|
@@ -25,35 +24,23 @@ import { createPerDispatchReviewerAgent } from "../reviewer-agent.ts";
|
|
|
25
24
|
import { formatNavigatorRoleHelp, type RoleRuntimeDependencies } from "../role-runtime.ts";
|
|
26
25
|
import { createReviewerPinnedGitReader } from "../reviewer-pinned-git.ts";
|
|
27
26
|
import { loadGatekeeperSessionMaterials, loadMainRoleSessionMaterials } from "../session-opening-materials.ts";
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} from "./role-turn-host.ts";
|
|
33
|
-
import { createGrokSessionIdentityAuthority } from "./session-identity.ts";
|
|
27
|
+
import { acpStdioArgs, resolveAcpBinary, type AcpHostDescription } from "./description.ts";
|
|
28
|
+
import { createComposedAcpRoleTurnHost } from "./role-envelope.ts";
|
|
29
|
+
import { connectAcpStdio } from "./role-turn-host.ts";
|
|
30
|
+
import { createAcpSessionIdentityAuthority } from "./session-identity.ts";
|
|
34
31
|
|
|
35
|
-
export type
|
|
32
|
+
export type ProductionAcpHostOptions = Readonly<{
|
|
36
33
|
packageRoot: string;
|
|
37
34
|
principalAuthority: DurablePrincipalAuthority;
|
|
35
|
+
description: AcpHostDescription;
|
|
38
36
|
}>;
|
|
39
37
|
|
|
40
|
-
function resolveGrokBinary(operatorHome: string): string {
|
|
41
|
-
return join(operatorHome, ".grok", "bin", "grok");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function childEnv(packageRoot: string): NodeJS.ProcessEnv {
|
|
45
|
-
return {
|
|
46
|
-
...controlledGrokChildEnv(process.env),
|
|
47
|
-
AK_PACKAGE_ROOT: packageRoot,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
38
|
const navigatorRoutePlaybookPath = fileURLToPath(
|
|
52
39
|
new URL("../../resources/navigator-route-playbook.md", import.meta.url),
|
|
53
40
|
);
|
|
54
41
|
|
|
55
|
-
/** Host-neutral packaged role runtime deps for the
|
|
56
|
-
export function
|
|
42
|
+
/** Host-neutral packaged role runtime deps for the ACP parent-process envelope. */
|
|
43
|
+
export function createAcpRoleRuntimeDependencies(packageRoot: string): RoleRuntimeDependencies {
|
|
57
44
|
const judgeAuditor = createPiJudgeAuditor();
|
|
58
45
|
const doctorAuditor = createPiDoctorAuditor();
|
|
59
46
|
const reviewerAgent = createPerDispatchReviewerAgent({ packageRoot });
|
|
@@ -119,22 +106,28 @@ export function createGrokRoleRuntimeDependencies(packageRoot: string): RoleRunt
|
|
|
119
106
|
}
|
|
120
107
|
|
|
121
108
|
/**
|
|
122
|
-
* Assemble
|
|
123
|
-
*
|
|
109
|
+
* Assemble a production ACP RoleTurnHost from the S6 true adapter for one host
|
|
110
|
+
* description. Agent subprocesses inherit the operator home; the run directory
|
|
111
|
+
* is sitian-only.
|
|
124
112
|
*/
|
|
125
|
-
export function
|
|
126
|
-
const { packageRoot, principalAuthority } = options;
|
|
127
|
-
const env =
|
|
113
|
+
export function createProductionAcpRoleTurnHost(options: ProductionAcpHostOptions): RoleTurnHost {
|
|
114
|
+
const { packageRoot, principalAuthority, description } = options;
|
|
115
|
+
const env: NodeJS.ProcessEnv = {
|
|
116
|
+
...process.env,
|
|
117
|
+
...description.childEnv,
|
|
118
|
+
AK_PACKAGE_ROOT: packageRoot,
|
|
119
|
+
};
|
|
128
120
|
|
|
129
|
-
return
|
|
130
|
-
sessionIdentity:
|
|
131
|
-
|
|
121
|
+
return createComposedAcpRoleTurnHost({
|
|
122
|
+
sessionIdentity: createAcpSessionIdentityAuthority(principalAuthority, description.sessionBindingFile),
|
|
123
|
+
boundResume: description.boundResume,
|
|
124
|
+
roleRuntimeDependencies: createAcpRoleRuntimeDependencies(packageRoot),
|
|
132
125
|
async connect(request) {
|
|
133
|
-
return
|
|
134
|
-
binary:
|
|
126
|
+
return connectAcpStdio({
|
|
127
|
+
binary: resolveAcpBinary(description, request.home),
|
|
128
|
+
args: acpStdioArgs(description, request.model),
|
|
135
129
|
cwd: request.cwd,
|
|
136
130
|
env,
|
|
137
|
-
...(request.model === undefined ? {} : { model: request.model.model }),
|
|
138
131
|
});
|
|
139
132
|
},
|
|
140
133
|
});
|
|
@@ -22,9 +22,9 @@ import {
|
|
|
22
22
|
type RoleRuntimeDependencies,
|
|
23
23
|
} from "../role-runtime.ts";
|
|
24
24
|
import {
|
|
25
|
-
|
|
26
|
-
type
|
|
27
|
-
type
|
|
25
|
+
createAcpRoleTurnHost,
|
|
26
|
+
type AcpPreparedTurn,
|
|
27
|
+
type AcpRoleTurnHostConfig,
|
|
28
28
|
} from "./role-turn-host.ts";
|
|
29
29
|
import {
|
|
30
30
|
GatekeeperDecisionError,
|
|
@@ -51,7 +51,7 @@ export function parseCanonicalSkillInvocation(prompt: string): { readonly name:
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/** Build host-side Skill expansion evidence from pre-read RoleTurnRequest.methods. */
|
|
54
|
-
export function
|
|
54
|
+
export function buildAcpSkillExpansion(
|
|
55
55
|
methodSkills: ReadonlyMap<string, { readonly path: string; readonly body: string }>,
|
|
56
56
|
prompt: string,
|
|
57
57
|
): HostSkillExpansionEvidence | undefined {
|
|
@@ -67,7 +67,7 @@ export function buildGrokSkillExpansion(
|
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
export function
|
|
70
|
+
export function projectAcpActivationFlags(request: RoleTurnRequest): Map<string, boolean | string> {
|
|
71
71
|
const activation = request.activation;
|
|
72
72
|
const flags = new Map<string, boolean | string>([["ak-role", activation.role]]);
|
|
73
73
|
const inputFlag = packagedRoleInputFlag(activation.role);
|
|
@@ -114,25 +114,25 @@ async function listen(server: Server, path: string): Promise<void> {
|
|
|
114
114
|
* Build one AK-owned MCP projection from the shared eight-seat envelope.
|
|
115
115
|
* The child process is a protocol relay only; all tools execute in this process.
|
|
116
116
|
*/
|
|
117
|
-
export function
|
|
118
|
-
config: Omit<
|
|
117
|
+
export function createComposedAcpRoleTurnHost(
|
|
118
|
+
config: Omit<AcpRoleTurnHostConfig, "prepare"> & {
|
|
119
119
|
readonly roleRuntimeDependencies: RoleRuntimeDependencies;
|
|
120
120
|
readonly socketPath?: (request: RoleTurnRequest) => string;
|
|
121
121
|
},
|
|
122
122
|
) {
|
|
123
|
-
return
|
|
123
|
+
return createAcpRoleTurnHost({
|
|
124
124
|
...config,
|
|
125
|
-
prepare: (request) =>
|
|
125
|
+
prepare: (request) => prepareAcpRoleEnvelope({
|
|
126
126
|
request,
|
|
127
127
|
dependencies: config.roleRuntimeDependencies,
|
|
128
128
|
// Same durable-principal path settlement uses for isAvailable (#617 DK-4 layout).
|
|
129
129
|
sessionFile: config.sessionIdentity.resolveSessionFile(request.principal),
|
|
130
|
-
socketPath: config.socketPath?.(request) ?? `/tmp/ak-
|
|
130
|
+
socketPath: config.socketPath?.(request) ?? `/tmp/ak-acp-mcp-${randomUUID()}.sock`,
|
|
131
131
|
}),
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
export async function
|
|
135
|
+
export async function prepareAcpRoleEnvelope(options: {
|
|
136
136
|
readonly request: RoleTurnRequest;
|
|
137
137
|
readonly dependencies: RoleRuntimeDependencies;
|
|
138
138
|
readonly socketPath: string;
|
|
@@ -142,9 +142,9 @@ export async function prepareGrokRoleEnvelope(options: {
|
|
|
142
142
|
* isAvailable and envelope mint the same file. Tests may omit → runDirectory default.
|
|
143
143
|
*/
|
|
144
144
|
readonly sessionFile?: string;
|
|
145
|
-
}): Promise<
|
|
145
|
+
}): Promise<AcpPreparedTurn> {
|
|
146
146
|
const { request } = options;
|
|
147
|
-
const flags =
|
|
147
|
+
const flags = projectAcpActivationFlags(request);
|
|
148
148
|
const tools = new Map<string, HostToolDefinition>();
|
|
149
149
|
const handlers = new Map<string, Handler[]>();
|
|
150
150
|
const calls: Array<{ toolCallId: string; toolName: string }> = [];
|
|
@@ -169,7 +169,7 @@ export async function prepareGrokRoleEnvelope(options: {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
// Durable principal file for isAvailable / resumable settlement (public-cli).
|
|
172
|
-
// #617 DK-4: header layout only — never
|
|
172
|
+
// #617 DK-4: header layout only — never host conversation/tool writeback into Pi JSONL.
|
|
173
173
|
let sessionFile = options.sessionFile ?? join(request.runDirectory, "session", "session.jsonl");
|
|
174
174
|
await mkdir(dirname(sessionFile), { recursive: true });
|
|
175
175
|
if (request.continuation.kind !== "resume") {
|
|
@@ -235,16 +235,16 @@ export async function prepareGrokRoleEnvelope(options: {
|
|
|
235
235
|
deliverSubmissionRejection(value) { rejection = value; },
|
|
236
236
|
capabilities: {
|
|
237
237
|
skillExpansion(prompt): HostSkillExpansionEvidence | undefined {
|
|
238
|
-
return
|
|
238
|
+
return buildAcpSkillExpansion(methodSkills, prompt);
|
|
239
239
|
},
|
|
240
240
|
},
|
|
241
241
|
registerFlag(name, definition) { if (!flags.has(name) && definition.default !== undefined) flags.set(name, definition.default); },
|
|
242
242
|
getFlag(name) { return flags.get(name); },
|
|
243
243
|
registerTool(tool) { tools.set(tool.name, tool); },
|
|
244
|
-
// The real AK-owned surface only;
|
|
244
|
+
// The real AK-owned surface only; the host builtin surface is host-side and
|
|
245
245
|
// observable after session/new, never echoed back into role-requested names.
|
|
246
246
|
getAllTools() { return [...tools.keys()].map((name) => ({ name })); },
|
|
247
|
-
//
|
|
247
|
+
// The host receives tool choice as role guidance; every tool registered for the
|
|
248
248
|
// seat remains reachable through MCP.
|
|
249
249
|
setActiveTools(names) { preferredTools = [...names]; },
|
|
250
250
|
getActiveTools() { return [...preferredTools]; },
|
|
@@ -580,13 +580,13 @@ export async function prepareGrokRoleEnvelope(options: {
|
|
|
580
580
|
}
|
|
581
581
|
if (cleanupFailures.length === 1) throw cleanupFailures[0];
|
|
582
582
|
if (cleanupFailures.length > 1) {
|
|
583
|
-
throw new AggregateError(cleanupFailures, "
|
|
583
|
+
throw new AggregateError(cleanupFailures, "ACP envelope dispose cleanup failures", {
|
|
584
584
|
cause: cleanupFailures[0],
|
|
585
585
|
});
|
|
586
586
|
}
|
|
587
587
|
};
|
|
588
588
|
|
|
589
|
-
const closeRound:
|
|
589
|
+
const closeRound: AcpPreparedTurn["closeRound"] = async () => {
|
|
590
590
|
// Typed round boundary: hand the complete call list to the shared ledger once.
|
|
591
591
|
if (calls.length > 0) {
|
|
592
592
|
const roundCalls = [...calls];
|
|
@@ -606,7 +606,7 @@ export async function prepareGrokRoleEnvelope(options: {
|
|
|
606
606
|
}
|
|
607
607
|
if (closure !== undefined) {
|
|
608
608
|
// Pi flushes navigator attendance on agent_settled; session/prompt
|
|
609
|
-
// resolution is
|
|
609
|
+
// resolution is the ACP host equivalent round boundary.
|
|
610
610
|
await emit("agent_settled", {});
|
|
611
611
|
return { accepted: true as const };
|
|
612
612
|
}
|
|
@@ -674,8 +674,8 @@ export async function prepareGrokRoleEnvelope(options: {
|
|
|
674
674
|
command: process.execPath,
|
|
675
675
|
args: [relay],
|
|
676
676
|
env: [
|
|
677
|
-
{ name: "
|
|
678
|
-
{ name: "
|
|
677
|
+
{ name: "AK_ACP_MCP_SOCKET", value: options.socketPath },
|
|
678
|
+
{ name: "AK_ACP_MCP_TOKEN", value: token },
|
|
679
679
|
],
|
|
680
680
|
}],
|
|
681
681
|
systemPrompt: { body: systemPromptBody, materials: readingMaterials },
|
|
@@ -693,7 +693,7 @@ export async function prepareGrokRoleEnvelope(options: {
|
|
|
693
693
|
} catch (cleanupFailure) {
|
|
694
694
|
throw new AggregateError(
|
|
695
695
|
[error, cleanupFailure],
|
|
696
|
-
"
|
|
696
|
+
"prepareAcpRoleEnvelope activation failed and its dispose cleanup also failed",
|
|
697
697
|
{ cause: error },
|
|
698
698
|
);
|
|
699
699
|
}
|