@akagilnc/pi-workflow-roles 0.1.4444 → 0.1.4489
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 +2 -0
- package/README.zh-CN.md +2 -0
- package/dist/acp-host/description.js +2 -3
- package/dist/acp-host/production-host.js +140 -107
- package/dist/auditor-soul.js +8 -1
- package/dist/headless-host/description.js +3 -3
- package/dist/headless-host/production-host.js +147 -76
- package/dist/host-descriptions.js +3 -18
- package/dist/method-host-plugin/.claude-plugin/plugin.json +5 -0
- package/dist/method-host-plugin/skills/ak-cross-m-review/CONTEXT.md +48 -0
- package/dist/method-host-plugin/skills/ak-cross-m-review/LICENSE +21 -0
- package/dist/method-host-plugin/skills/ak-cross-m-review/SKILL.md +170 -0
- package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-completeness.md +118 -0
- package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-reviewer.md +128 -0
- package/dist/method-host-plugin/skills/ak-cross-m-review/provenance.json +41 -0
- package/dist/method-host-plugin/skills/diagnosing-bugs/SKILL.md +134 -0
- package/dist/method-host-plugin/skills/diagnosing-bugs/agents/openai.yaml +3 -0
- package/dist/method-host-plugin/skills/diagnosing-bugs/provenance.json +31 -0
- package/dist/method-host-plugin/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/dist/method-host-plugin/skills/resolving-merge-conflicts/SKILL.md +14 -0
- package/dist/method-host-plugin/skills/resolving-merge-conflicts/agents/openai.yaml +3 -0
- package/dist/method-host-plugin/skills/resolving-merge-conflicts/provenance.json +26 -0
- package/dist/method-host-plugin/skills/tdd/SKILL.md +38 -0
- package/dist/method-host-plugin/skills/tdd/agents/openai.yaml +3 -0
- package/dist/method-host-plugin/skills/tdd/mocking.md +59 -0
- package/dist/method-host-plugin/skills/tdd/provenance.json +36 -0
- package/dist/method-host-plugin/skills/tdd/tests.md +77 -0
- package/dist/public-cli/main.js +14 -21
- package/dist/session-opening-materials.js +17 -5
- package/extensions/role-runtime.ts +16 -6
- package/package.json +1 -1
- package/resources/method-host-plugin/.claude-plugin/plugin.json +5 -0
- package/scripts/build-package.mjs +6 -1
- package/src/acp-host/description.ts +2 -4
- package/src/acp-host/production-host.ts +0 -1
- package/src/auditor-soul.ts +10 -1
- package/src/headless-host/description.ts +4 -3
- package/src/headless-host/role-turn-host.ts +27 -4
- package/src/host-descriptions.ts +3 -23
- package/src/host-native-method.ts +67 -0
- package/src/role-envelope.ts +17 -47
- package/src/role-runtime-dependencies.ts +17 -2
- package/src/role-runtime.ts +12 -7
- package/src/session-opening-materials.ts +27 -11
package/dist/auditor-soul.js
CHANGED
|
@@ -66,9 +66,16 @@ export async function loadAuditorSoul(role) {
|
|
|
66
66
|
if (soul.trim().length === 0) {
|
|
67
67
|
throw new Error(`The ${role} auditor Soul is blank`);
|
|
68
68
|
}
|
|
69
|
-
return
|
|
69
|
+
return soul;
|
|
70
|
+
}
|
|
71
|
+
export function loadAuditorReferenceMaterials(role) {
|
|
72
|
+
const soulPath = auditorSoulRelativePath(role);
|
|
73
|
+
return joinPackageMaterials(AUDITOR_SESSION_MATERIALS[role].filter((path) => path !== soulPath));
|
|
70
74
|
}
|
|
71
75
|
/** Runtime loader: subject input decides which soul file to assemble. */
|
|
72
76
|
export async function loadAuditorSoulFromSubjectInput(raw) {
|
|
73
77
|
return loadAuditorSoul(resolveAuditorSubject(raw));
|
|
74
78
|
}
|
|
79
|
+
export function loadAuditorReferenceMaterialsFromSubjectInput(raw) {
|
|
80
|
+
return loadAuditorReferenceMaterials(resolveAuditorSubject(raw));
|
|
81
|
+
}
|
|
@@ -30,6 +30,8 @@ export function headlessTurnArgs(options) {
|
|
|
30
30
|
description.jsonSchemaFlag,
|
|
31
31
|
JSON.stringify(options.jsonSchema),
|
|
32
32
|
];
|
|
33
|
+
if (options.pluginDir)
|
|
34
|
+
args.push("--plugin-dir", options.pluginDir);
|
|
33
35
|
if (options.mcpConfigPath !== undefined && options.mcpConfigPath !== "") {
|
|
34
36
|
args.push(description.mcpConfigFlag, options.mcpConfigPath);
|
|
35
37
|
}
|
|
@@ -321,9 +323,7 @@ export function codexTurnArgs(options) {
|
|
|
321
323
|
}
|
|
322
324
|
// JSONL event stream: thread_id + final agent_message + turn.completed/failed.
|
|
323
325
|
args.push("--json");
|
|
324
|
-
// Operator config/
|
|
325
|
-
// Project/system config and AGENTS.md have no official suppression switch.
|
|
326
|
-
args.push("--ignore-user-config", "--ignore-rules");
|
|
326
|
+
// Operator config/skills stay open (#922 host-native-loader). Auth uses CODEX_HOME.
|
|
327
327
|
const roots = (options.writableRoots ?? []).filter((root) => root !== "");
|
|
328
328
|
if (roots.length > 0) {
|
|
329
329
|
// Resume has no --add-dir; the config key keeps extra roots available on both paths.
|
|
@@ -1559,10 +1559,10 @@ __export(session_assistant_usage_exports, {
|
|
|
1559
1559
|
});
|
|
1560
1560
|
import { join as join5 } from "node:path";
|
|
1561
1561
|
async function readAssistantUsageFromSessionFile(sessionFile) {
|
|
1562
|
-
const { readFile:
|
|
1562
|
+
const { readFile: readFile23 } = await import("node:fs/promises");
|
|
1563
1563
|
let text;
|
|
1564
1564
|
try {
|
|
1565
|
-
text = await
|
|
1565
|
+
text = await readFile23(sessionFile, "utf8");
|
|
1566
1566
|
} catch (error) {
|
|
1567
1567
|
if (error?.code === "ENOENT") return void 0;
|
|
1568
1568
|
throw error;
|
|
@@ -3801,13 +3801,10 @@ function assertRegisteredHostName(host) {
|
|
|
3801
3801
|
}
|
|
3802
3802
|
throw new Error(`unregistered host: ${host}`);
|
|
3803
3803
|
}
|
|
3804
|
-
var
|
|
3804
|
+
var DEFAULT_ROLE_TURN_HOST, HOST_DESCRIPTIONS, HEADLESS_HOST_DESCRIPTIONS;
|
|
3805
3805
|
var init_host_descriptions = __esm({
|
|
3806
3806
|
"src/host-descriptions.ts"() {
|
|
3807
3807
|
"use strict";
|
|
3808
|
-
PRIVATE_COMPAT_ENV = Object.fromEntries(
|
|
3809
|
-
["CLAUDE", "CURSOR", "CODEX"].flatMap((vendor) => ["SKILLS", "RULES", "AGENTS", "MCPS", "HOOKS", "SESSIONS"].map((kind) => [`GROK_${vendor}_${kind}_ENABLED`, "false"]))
|
|
3810
|
-
);
|
|
3811
3808
|
DEFAULT_ROLE_TURN_HOST = "pi";
|
|
3812
3809
|
HOST_DESCRIPTIONS = Object.freeze({
|
|
3813
3810
|
/** Operator home `~/.grok`, native session/load resume, `agent [--model X] stdio`. */
|
|
@@ -3820,12 +3817,7 @@ var init_host_descriptions = __esm({
|
|
|
3820
3817
|
}),
|
|
3821
3818
|
modelPassing: "argv",
|
|
3822
3819
|
boundResume: "session/load",
|
|
3823
|
-
sessionBindingFile: "grok-acp-session.json"
|
|
3824
|
-
childEnv: Object.freeze({
|
|
3825
|
-
...PRIVATE_COMPAT_ENV,
|
|
3826
|
-
GROK_MEMORY: "0",
|
|
3827
|
-
GROK_SUBAGENTS: "0"
|
|
3828
|
-
})
|
|
3820
|
+
sessionBindingFile: "grok-acp-session.json"
|
|
3829
3821
|
}),
|
|
3830
3822
|
/**
|
|
3831
3823
|
* Operator home `~/.hermes`, native session/load resume, `acp` subcommand.
|
|
@@ -3844,7 +3836,6 @@ var init_host_descriptions = __esm({
|
|
|
3844
3836
|
modelPassing: "set_model",
|
|
3845
3837
|
boundResume: "session/load",
|
|
3846
3838
|
sessionBindingFile: "hermes-acp-session.json",
|
|
3847
|
-
childEnv: Object.freeze({}),
|
|
3848
3839
|
seatProfileSoul: Object.freeze({
|
|
3849
3840
|
flag: "-p",
|
|
3850
3841
|
namePrefix: "ak-",
|
|
@@ -3865,12 +3856,7 @@ var init_host_descriptions = __esm({
|
|
|
3865
3856
|
// Intermediate assistant/tool/system events require verbose with stream-json.
|
|
3866
3857
|
"--verbose",
|
|
3867
3858
|
"--permission-mode",
|
|
3868
|
-
"bypassPermissions"
|
|
3869
|
-
// Empty sources: no user/project/local operator surface (envelope owns materials).
|
|
3870
|
-
"--setting-sources",
|
|
3871
|
-
"",
|
|
3872
|
-
// With adapter-supplied --mcp-config only (AK relay); drops operator + claude.ai MCP.
|
|
3873
|
-
"--strict-mcp-config"
|
|
3859
|
+
"bypassPermissions"
|
|
3874
3860
|
]),
|
|
3875
3861
|
promptFlag: "-p",
|
|
3876
3862
|
modelFlag: "--model",
|
|
@@ -10765,10 +10751,10 @@ function pairGateRounds(volumes) {
|
|
|
10765
10751
|
return rounds.sort((a, b) => a.officerStartedAt.localeCompare(b.officerStartedAt)).map((round, index) => ({ ...round, roundIndex: index + 1 }));
|
|
10766
10752
|
}
|
|
10767
10753
|
async function resolveOfficerSessionFromPointerFile(pointerPath) {
|
|
10768
|
-
const { readFile:
|
|
10754
|
+
const { readFile: readFile23 } = await import("node:fs/promises");
|
|
10769
10755
|
let raw;
|
|
10770
10756
|
try {
|
|
10771
|
-
raw = JSON.parse(await
|
|
10757
|
+
raw = JSON.parse(await readFile23(pointerPath, "utf8"));
|
|
10772
10758
|
} catch (error) {
|
|
10773
10759
|
throw new Error(
|
|
10774
10760
|
`direct officer run pointer unreadable in ${pointerPath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -11369,16 +11355,27 @@ async function readPackageMaterial(relativePath) {
|
|
|
11369
11355
|
}
|
|
11370
11356
|
async function joinPackageMaterials(relativePaths) {
|
|
11371
11357
|
const chunks = [];
|
|
11372
|
-
for (const relativePath of relativePaths)
|
|
11373
|
-
chunks.push(await readPackageMaterial(relativePath));
|
|
11374
|
-
}
|
|
11358
|
+
for (const relativePath of relativePaths) chunks.push(await readPackageMaterial(relativePath));
|
|
11375
11359
|
return chunks.join("\n\n");
|
|
11376
11360
|
}
|
|
11361
|
+
function roleSoulPath(role, materials) {
|
|
11362
|
+
const suffix = `/souls/${role}.md`;
|
|
11363
|
+
const path = materials.find((candidate) => `/${candidate}`.endsWith(suffix));
|
|
11364
|
+
if (path === void 0) throw new Error(`session materials omit the ${role} Soul`);
|
|
11365
|
+
return path;
|
|
11366
|
+
}
|
|
11367
|
+
async function loadSeparatedSessionPart(role, materials, part) {
|
|
11368
|
+
const soul = roleSoulPath(role, materials);
|
|
11369
|
+
return part === "soul" ? readPackageMaterial(soul) : joinPackageMaterials(materials.filter((path) => path !== soul));
|
|
11370
|
+
}
|
|
11377
11371
|
function loadMainRoleSessionMaterials(role) {
|
|
11378
|
-
return
|
|
11372
|
+
return loadSeparatedSessionPart(role, MAIN_ROLE_SESSION_MATERIALS[role], "soul");
|
|
11373
|
+
}
|
|
11374
|
+
function loadMainRoleReferenceMaterials(role) {
|
|
11375
|
+
return loadSeparatedSessionPart(role, MAIN_ROLE_SESSION_MATERIALS[role], "references");
|
|
11379
11376
|
}
|
|
11380
11377
|
function loadGatekeeperSessionMaterials(role) {
|
|
11381
|
-
return
|
|
11378
|
+
return loadSeparatedSessionPart(role, GATEKEEPER_SESSION_MATERIALS[role], "soul");
|
|
11382
11379
|
}
|
|
11383
11380
|
var packageRootUrl, MAIN_ROLE_SESSION_MATERIALS, GATEKEEPER_SESSION_MATERIALS;
|
|
11384
11381
|
var init_session_opening_materials = __esm({
|
|
@@ -11408,6 +11405,8 @@ __export(auditor_soul_exports, {
|
|
|
11408
11405
|
AUDITOR_SESSION_MATERIALS: () => AUDITOR_SESSION_MATERIALS,
|
|
11409
11406
|
AUDITOR_SOUL_ROLES: () => AUDITOR_SOUL_ROLES,
|
|
11410
11407
|
isAuditorSoulRole: () => isAuditorSoulRole,
|
|
11408
|
+
loadAuditorReferenceMaterials: () => loadAuditorReferenceMaterials,
|
|
11409
|
+
loadAuditorReferenceMaterialsFromSubjectInput: () => loadAuditorReferenceMaterialsFromSubjectInput,
|
|
11411
11410
|
loadAuditorSoul: () => loadAuditorSoul,
|
|
11412
11411
|
loadAuditorSoulFromSubjectInput: () => loadAuditorSoulFromSubjectInput,
|
|
11413
11412
|
resolveAuditorSubject: () => resolveAuditorSubject
|
|
@@ -11434,11 +11433,18 @@ async function loadAuditorSoul(role) {
|
|
|
11434
11433
|
if (soul.trim().length === 0) {
|
|
11435
11434
|
throw new Error(`The ${role} auditor Soul is blank`);
|
|
11436
11435
|
}
|
|
11437
|
-
return
|
|
11436
|
+
return soul;
|
|
11437
|
+
}
|
|
11438
|
+
function loadAuditorReferenceMaterials(role) {
|
|
11439
|
+
const soulPath = auditorSoulRelativePath(role);
|
|
11440
|
+
return joinPackageMaterials(AUDITOR_SESSION_MATERIALS[role].filter((path) => path !== soulPath));
|
|
11438
11441
|
}
|
|
11439
11442
|
async function loadAuditorSoulFromSubjectInput(raw) {
|
|
11440
11443
|
return loadAuditorSoul(resolveAuditorSubject(raw));
|
|
11441
11444
|
}
|
|
11445
|
+
function loadAuditorReferenceMaterialsFromSubjectInput(raw) {
|
|
11446
|
+
return loadAuditorReferenceMaterials(resolveAuditorSubject(raw));
|
|
11447
|
+
}
|
|
11442
11448
|
var AUDITOR_SOUL_ROLES, AK_ROLE_AUDITOR_SUBJECT_ENV, AK_ROLE_AUDITOR_SOURCE_RUN_ENV, AUDITOR_SESSION_MATERIALS;
|
|
11443
11449
|
var init_auditor_soul = __esm({
|
|
11444
11450
|
"src/auditor-soul.ts"() {
|
|
@@ -25266,6 +25272,7 @@ function createRoleRuntimeExtension(dependencies) {
|
|
|
25266
25272
|
});
|
|
25267
25273
|
let admitted = false;
|
|
25268
25274
|
let selectedRole;
|
|
25275
|
+
let roleReferenceMaterials = "";
|
|
25269
25276
|
let activeReviewerParent;
|
|
25270
25277
|
let reviewerOriginalRequest;
|
|
25271
25278
|
let reviewerExpansionCaptured = false;
|
|
@@ -25359,10 +25366,10 @@ function createRoleRuntimeExtension(dependencies) {
|
|
|
25359
25366
|
activeReviewerParent.skillBinding.name,
|
|
25360
25367
|
text
|
|
25361
25368
|
) ?? text;
|
|
25362
|
-
return text === event.text ? { action: "continue" } : { action: "transform", text };
|
|
25363
25369
|
}
|
|
25364
|
-
return
|
|
25370
|
+
return { action: "continue" };
|
|
25365
25371
|
});
|
|
25372
|
+
roleHost.on("before_agent_start", () => roleReferenceMaterials === "" ? void 0 : { readingMaterial: { kind: "role-reference-materials", content: roleReferenceMaterials } });
|
|
25366
25373
|
roleHost.on("before_agent_start", async (event, ctx) => {
|
|
25367
25374
|
const role = roleHost.getFlag(ROLE_FLAG.name);
|
|
25368
25375
|
const prompt = event.prompt;
|
|
@@ -25928,6 +25935,7 @@ function createRoleRuntimeExtension(dependencies) {
|
|
|
25928
25935
|
}
|
|
25929
25936
|
admitted = false;
|
|
25930
25937
|
selectedRole = void 0;
|
|
25938
|
+
roleReferenceMaterials = "";
|
|
25931
25939
|
activeReviewerParent = void 0;
|
|
25932
25940
|
reviewerOriginalRequest = void 0;
|
|
25933
25941
|
reviewerExpansionCaptured = false;
|
|
@@ -26062,6 +26070,7 @@ function createRoleRuntimeExtension(dependencies) {
|
|
|
26062
26070
|
}
|
|
26063
26071
|
}
|
|
26064
26072
|
await executeActivationStage(entry.role, activationStage(entry.role, runtime), { clock, writeTrace });
|
|
26073
|
+
roleReferenceMaterials = await dependencies.loadRoleReferenceMaterials?.(entry.role) ?? "";
|
|
26065
26074
|
if (!engineDetourRegistered) {
|
|
26066
26075
|
engineDetourRegistered = registerEngineDetourTool(roleHost, hostActions);
|
|
26067
26076
|
}
|
|
@@ -26101,11 +26110,15 @@ var navigatorRoutePlaybookPath = fileURLToPath2(
|
|
|
26101
26110
|
var collectorHandbookSeedPath = fileURLToPath2(
|
|
26102
26111
|
new URL("../resources/collector-bot-handbook.md", import.meta.url)
|
|
26103
26112
|
);
|
|
26113
|
+
function loadPackagedRoleReferenceMaterials(role) {
|
|
26114
|
+
return role === "auditor" ? loadAuditorReferenceMaterialsFromSubjectInput() : loadMainRoleReferenceMaterials(role);
|
|
26115
|
+
}
|
|
26104
26116
|
function createRoleRuntimeDependencies(packageRoot) {
|
|
26105
26117
|
const doctorAuditor = createPiDoctorAuditor();
|
|
26106
26118
|
const navigatorSessionFactory = createNativeNavigatorSessionFactory();
|
|
26107
26119
|
return {
|
|
26108
26120
|
packageRoot,
|
|
26121
|
+
loadRoleReferenceMaterials: loadPackagedRoleReferenceMaterials,
|
|
26109
26122
|
loadJudgeSoul: () => loadMainRoleSessionMaterials("judge"),
|
|
26110
26123
|
loadFixerSoul: () => loadMainRoleSessionMaterials("fixer"),
|
|
26111
26124
|
loadFixPacket: (path) => readFile22(path, "utf8"),
|
|
@@ -26166,9 +26179,9 @@ function createRoleRuntimeDependencies(packageRoot) {
|
|
|
26166
26179
|
// src/role-envelope.ts
|
|
26167
26180
|
init_engine_detour();
|
|
26168
26181
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
26169
|
-
import { mkdir as
|
|
26182
|
+
import { mkdir as mkdir6, writeFile as writeFile12 } from "node:fs/promises";
|
|
26170
26183
|
import { createServer } from "node:net";
|
|
26171
|
-
import {
|
|
26184
|
+
import { dirname as dirname24, join as join41 } from "node:path";
|
|
26172
26185
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
26173
26186
|
|
|
26174
26187
|
// src/gatekeeper-pass-envelope.ts
|
|
@@ -26253,25 +26266,68 @@ async function requireGatekeeperPass(options) {
|
|
|
26253
26266
|
}
|
|
26254
26267
|
}
|
|
26255
26268
|
|
|
26269
|
+
// src/host-native-method.ts
|
|
26270
|
+
import { lstat as lstat7, mkdir as mkdir5, readlink, realpath as realpath7, symlink } from "node:fs/promises";
|
|
26271
|
+
import { basename as basename9, dirname as dirname23, join as join40 } from "node:path";
|
|
26272
|
+
var HOST_METHOD_PLUGIN_NAME = "ak-methods";
|
|
26273
|
+
var packagedMethodsDir = (root) => join40(root, "resources", "methods");
|
|
26274
|
+
var packagedMethodPluginDir = (root) => join40(root, "dist", "method-host-plugin");
|
|
26275
|
+
function hostMethodSkills(methods) {
|
|
26276
|
+
return Object.freeze(methods.flatMap((method) => {
|
|
26277
|
+
if (method.kind !== "skill") return [];
|
|
26278
|
+
const name = basename9(dirname23(method.path));
|
|
26279
|
+
return name ? [Object.freeze({ name })] : [];
|
|
26280
|
+
}));
|
|
26281
|
+
}
|
|
26282
|
+
var alreadyPrefixed = (prompt, token) => {
|
|
26283
|
+
const text = prompt.trimStart();
|
|
26284
|
+
return text === token || text.startsWith(`${token} `) || text.startsWith(`${token}
|
|
26285
|
+
`);
|
|
26286
|
+
};
|
|
26287
|
+
function prefixMethodInvocation(token, prompt) {
|
|
26288
|
+
if (alreadyPrefixed(prompt, token)) return prompt;
|
|
26289
|
+
return prompt ? `${token} ${prompt}` : token;
|
|
26290
|
+
}
|
|
26291
|
+
function applyClaudeSkillInvocation(methods, prompt) {
|
|
26292
|
+
const skills = hostMethodSkills(methods);
|
|
26293
|
+
if (skills.length !== 1) return prompt;
|
|
26294
|
+
return prefixMethodInvocation(`/${HOST_METHOD_PLUGIN_NAME}:${skills[0].name}`, prompt);
|
|
26295
|
+
}
|
|
26296
|
+
function applyCodexSkillInvocation(methods, prompt) {
|
|
26297
|
+
return hostMethodSkills(methods).reduceRight(
|
|
26298
|
+
(invocation, skill) => prefixMethodInvocation(`$${skill.name}`, invocation),
|
|
26299
|
+
prompt
|
|
26300
|
+
);
|
|
26301
|
+
}
|
|
26302
|
+
async function installWorkspaceMethodSkills(cwd, packageRoot) {
|
|
26303
|
+
const target = await realpath7(packagedMethodsDir(packageRoot));
|
|
26304
|
+
const link = join40(cwd, ".agents", "skills");
|
|
26305
|
+
try {
|
|
26306
|
+
const stat2 = await lstat7(link);
|
|
26307
|
+
if (!stat2.isSymbolicLink() || await realpath7(link) !== target) {
|
|
26308
|
+
const detail = stat2.isSymbolicLink() ? `symlink to ${await readlink(link)}` : "non-symlink entry";
|
|
26309
|
+
throw new Error(`workspace method catalog conflict at ${link}: ${detail}`);
|
|
26310
|
+
}
|
|
26311
|
+
return;
|
|
26312
|
+
} catch (error) {
|
|
26313
|
+
if (error.code !== "ENOENT") throw error;
|
|
26314
|
+
}
|
|
26315
|
+
await mkdir5(dirname23(link), { recursive: true });
|
|
26316
|
+
try {
|
|
26317
|
+
await symlink(target, link);
|
|
26318
|
+
} catch (error) {
|
|
26319
|
+
if (error.code !== "EEXIST") throw error;
|
|
26320
|
+
if (await realpath7(link).catch(() => "") !== target) {
|
|
26321
|
+
throw new Error(`workspace method catalog conflict at ${link}`);
|
|
26322
|
+
}
|
|
26323
|
+
}
|
|
26324
|
+
}
|
|
26325
|
+
|
|
26256
26326
|
// src/role-envelope.ts
|
|
26257
26327
|
init_packaged_role_registry();
|
|
26258
|
-
init_method_skill();
|
|
26259
26328
|
init_role_activation_flags();
|
|
26260
26329
|
init_submission_correctable_error();
|
|
26261
26330
|
init_navigator_invocation_identity();
|
|
26262
|
-
function buildSkillExpansion(methodSkills, prompt) {
|
|
26263
|
-
if (methodSkills.size !== 1) return void 0;
|
|
26264
|
-
const entry = methodSkills.entries().next().value;
|
|
26265
|
-
if (entry === void 0) return void 0;
|
|
26266
|
-
const [name, method] = entry;
|
|
26267
|
-
return Object.freeze({
|
|
26268
|
-
name,
|
|
26269
|
-
location: method.path,
|
|
26270
|
-
content: method.body,
|
|
26271
|
-
// Non-pi typed chain keeps original task bytes (ticket #822 r3); no consumer trim.
|
|
26272
|
-
userMessage: prompt
|
|
26273
|
-
});
|
|
26274
|
-
}
|
|
26275
26331
|
async function listen(server, path) {
|
|
26276
26332
|
await new Promise((resolve21, reject) => {
|
|
26277
26333
|
server.once("error", reject);
|
|
@@ -26306,21 +26362,14 @@ async function prepareRoleEnvelope(options) {
|
|
|
26306
26362
|
const calls = [];
|
|
26307
26363
|
const customEntries = [];
|
|
26308
26364
|
const sessionEntries = [];
|
|
26309
|
-
const methodSkills = /* @__PURE__ */ new Map();
|
|
26310
26365
|
let preferredTools = [];
|
|
26311
26366
|
let rejection;
|
|
26312
26367
|
let infrastructureRoundFailure;
|
|
26313
26368
|
const hostAbort = new AbortController();
|
|
26314
26369
|
const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID8();
|
|
26315
|
-
await
|
|
26316
|
-
|
|
26317
|
-
|
|
26318
|
-
const name = basename9(dirname23(method.path));
|
|
26319
|
-
const raw = await readFile23(method.path, "utf8");
|
|
26320
|
-
methodSkills.set(name, { path: method.path, body: stripSkillFrontmatter(raw).trim() });
|
|
26321
|
-
}
|
|
26322
|
-
let sessionFile = options.sessionFile ?? join40(request.runDirectory, "session", "session.jsonl");
|
|
26323
|
-
await mkdir5(dirname23(sessionFile), { recursive: true });
|
|
26370
|
+
await mkdir6(request.runDirectory, { recursive: true });
|
|
26371
|
+
let sessionFile = options.sessionFile ?? join41(request.runDirectory, "session", "session.jsonl");
|
|
26372
|
+
await mkdir6(dirname24(sessionFile), { recursive: true });
|
|
26324
26373
|
if (request.continuation.kind !== "resume") {
|
|
26325
26374
|
try {
|
|
26326
26375
|
await writeFile12(
|
|
@@ -26351,7 +26400,7 @@ async function prepareRoleEnvelope(options) {
|
|
|
26351
26400
|
getLeafEntry: () => sessionEntries.at(-1),
|
|
26352
26401
|
getLeafId: () => runId,
|
|
26353
26402
|
getEntries: () => sessionEntries,
|
|
26354
|
-
getSessionDir: () =>
|
|
26403
|
+
getSessionDir: () => dirname24(sessionFile),
|
|
26355
26404
|
getSessionFile: () => sessionFile,
|
|
26356
26405
|
getHeader: () => ({ type: "session", id: runId }),
|
|
26357
26406
|
setSessionFile(path) {
|
|
@@ -26386,8 +26435,9 @@ async function prepareRoleEnvelope(options) {
|
|
|
26386
26435
|
deliverSubmissionRejection(_value) {
|
|
26387
26436
|
},
|
|
26388
26437
|
capabilities: {
|
|
26389
|
-
|
|
26390
|
-
|
|
26438
|
+
// #922: native loaders own expansion; package does not pre-read bodies (ADR 0032).
|
|
26439
|
+
skillExpansion() {
|
|
26440
|
+
return void 0;
|
|
26391
26441
|
}
|
|
26392
26442
|
},
|
|
26393
26443
|
registerFlag(name, definition) {
|
|
@@ -26726,10 +26776,9 @@ async function prepareRoleEnvelope(options) {
|
|
|
26726
26776
|
message: { role: "user", content: prompt }
|
|
26727
26777
|
});
|
|
26728
26778
|
}
|
|
26729
|
-
const methodPrompt = (await Promise.all(request.methods.map(({ path }) => readFile23(path, "utf8")))).join("\n\n");
|
|
26730
26779
|
const promptResults = await emit("before_agent_start", {
|
|
26731
26780
|
prompt,
|
|
26732
|
-
systemPrompt:
|
|
26781
|
+
systemPrompt: "",
|
|
26733
26782
|
systemPromptOptions: {}
|
|
26734
26783
|
});
|
|
26735
26784
|
const systemPromptParts = promptResults.flatMap((value) => {
|
|
@@ -26737,7 +26786,7 @@ async function prepareRoleEnvelope(options) {
|
|
|
26737
26786
|
if (!("systemPrompt" in value) || typeof value.systemPrompt !== "string") return [];
|
|
26738
26787
|
return [value.systemPrompt];
|
|
26739
26788
|
});
|
|
26740
|
-
const systemPromptBody = systemPromptParts.
|
|
26789
|
+
const systemPromptBody = systemPromptParts.join("\n\n");
|
|
26741
26790
|
const readingMaterials = [];
|
|
26742
26791
|
for (const value of promptResults) {
|
|
26743
26792
|
if (typeof value !== "object" || value === null) continue;
|
|
@@ -26750,6 +26799,13 @@ async function prepareRoleEnvelope(options) {
|
|
|
26750
26799
|
throw new Error(`terminating tool not registered after activation: ${terminatingToolName}`);
|
|
26751
26800
|
}
|
|
26752
26801
|
const jsonSchema = terminatingToolJsonSchema(terminating.parameters);
|
|
26802
|
+
if (request.host === "codex" && hostMethodSkills(request.methods).length > 0) {
|
|
26803
|
+
const packageRoot = options.dependencies.packageRoot;
|
|
26804
|
+
if (typeof packageRoot !== "string" || packageRoot === "") {
|
|
26805
|
+
throw new Error("codex project Skill catalog requires packageRoot");
|
|
26806
|
+
}
|
|
26807
|
+
await installWorkspaceMethodSkills(request.cwd, packageRoot);
|
|
26808
|
+
}
|
|
26753
26809
|
return {
|
|
26754
26810
|
mcpServers: [{
|
|
26755
26811
|
name: `ak-${request.activation.role}`,
|
|
@@ -26787,7 +26843,7 @@ async function prepareRoleEnvelope(options) {
|
|
|
26787
26843
|
init_session_identity();
|
|
26788
26844
|
|
|
26789
26845
|
// src/headless-host/description.ts
|
|
26790
|
-
import { join as
|
|
26846
|
+
import { join as join42 } from "node:path";
|
|
26791
26847
|
function isClaudePrintDescription(description) {
|
|
26792
26848
|
return description.protocol === "claude-print";
|
|
26793
26849
|
}
|
|
@@ -26795,7 +26851,7 @@ function isCodexExecDescription(description) {
|
|
|
26795
26851
|
return description.protocol === "codex-exec";
|
|
26796
26852
|
}
|
|
26797
26853
|
function resolveHeadlessBinary(description, operatorHome) {
|
|
26798
|
-
return
|
|
26854
|
+
return join42(operatorHome, ...description.binaryFromHome);
|
|
26799
26855
|
}
|
|
26800
26856
|
function headlessTurnArgs(options) {
|
|
26801
26857
|
const { description } = options;
|
|
@@ -26807,6 +26863,7 @@ function headlessTurnArgs(options) {
|
|
|
26807
26863
|
description.jsonSchemaFlag,
|
|
26808
26864
|
JSON.stringify(options.jsonSchema)
|
|
26809
26865
|
];
|
|
26866
|
+
if (options.pluginDir) args.push("--plugin-dir", options.pluginDir);
|
|
26810
26867
|
if (options.mcpConfigPath !== void 0 && options.mcpConfigPath !== "") {
|
|
26811
26868
|
args.push(description.mcpConfigFlag, options.mcpConfigPath);
|
|
26812
26869
|
}
|
|
@@ -27003,7 +27060,6 @@ function codexTurnArgs(options) {
|
|
|
27003
27060
|
args.push("resume", options.session.id);
|
|
27004
27061
|
}
|
|
27005
27062
|
args.push("--json");
|
|
27006
|
-
args.push("--ignore-user-config", "--ignore-rules");
|
|
27007
27063
|
const roots = (options.writableRoots ?? []).filter((root) => root !== "");
|
|
27008
27064
|
if (roots.length > 0) {
|
|
27009
27065
|
args.push(
|
|
@@ -27051,7 +27107,7 @@ import { spawn as spawn4, spawnSync } from "node:child_process";
|
|
|
27051
27107
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
27052
27108
|
import { existsSync as existsSync13 } from "node:fs";
|
|
27053
27109
|
import { writeFile as writeFile13 } from "node:fs/promises";
|
|
27054
|
-
import { dirname as
|
|
27110
|
+
import { dirname as dirname25, isAbsolute as isAbsolute11, join as join43, resolve as resolve20 } from "node:path";
|
|
27055
27111
|
|
|
27056
27112
|
// src/external-host-turn-loop.ts
|
|
27057
27113
|
init_host_contracts();
|
|
@@ -27270,8 +27326,8 @@ function formatCodexFailurePayload(payload) {
|
|
|
27270
27326
|
function cwdIsGitWorkTree(cwd) {
|
|
27271
27327
|
let dir = cwd;
|
|
27272
27328
|
for (; ; ) {
|
|
27273
|
-
if (existsSync13(
|
|
27274
|
-
const parent =
|
|
27329
|
+
if (existsSync13(join43(dir, ".git"))) return true;
|
|
27330
|
+
const parent = dirname25(dir);
|
|
27275
27331
|
if (parent === dir) return false;
|
|
27276
27332
|
dir = parent;
|
|
27277
27333
|
}
|
|
@@ -27460,7 +27516,8 @@ function buildTurnArgs(options) {
|
|
|
27460
27516
|
mcpConfigPath: options.mcpConfigPath,
|
|
27461
27517
|
...options.model === void 0 ? {} : { model: options.model },
|
|
27462
27518
|
...options.effort === void 0 ? {} : { effort: options.effort },
|
|
27463
|
-
session: { kind: options.sessionKind, id: options.sessionId }
|
|
27519
|
+
session: { kind: options.sessionKind, id: options.sessionId },
|
|
27520
|
+
...options.pluginDir === void 0 ? {} : { pluginDir: options.pluginDir }
|
|
27464
27521
|
});
|
|
27465
27522
|
}
|
|
27466
27523
|
function createHeadlessRoleTurnHost(config) {
|
|
@@ -27477,23 +27534,36 @@ function createHeadlessRoleTurnHost(config) {
|
|
|
27477
27534
|
await config.sessionIdentity.bind(request.principal, sessionId);
|
|
27478
27535
|
}
|
|
27479
27536
|
const env = { ...process.env, ...config.env ?? {} };
|
|
27480
|
-
const systemPromptPath =
|
|
27537
|
+
const systemPromptPath = join43(request.runDirectory, "headless-system-prompt.txt");
|
|
27481
27538
|
await writeFile13(systemPromptPath, systemPrompt, "utf8");
|
|
27482
27539
|
let mcpConfigPath;
|
|
27483
27540
|
let outputSchemaPath;
|
|
27541
|
+
let pluginDir;
|
|
27542
|
+
let applyMethodPrompt = codex ? (prompt) => applyCodexSkillInvocation(request.methods, prompt) : (prompt) => prompt;
|
|
27484
27543
|
if (codex) {
|
|
27485
|
-
outputSchemaPath =
|
|
27486
|
-
|
|
27487
|
-
|
|
27488
|
-
|
|
27544
|
+
outputSchemaPath = join43(request.runDirectory, "headless-output-schema.json");
|
|
27545
|
+
await writeFile13(
|
|
27546
|
+
outputSchemaPath,
|
|
27547
|
+
`${JSON.stringify(closeJsonSchemaForCodex(prepared.jsonSchema), null, 2)}
|
|
27548
|
+
`,
|
|
27549
|
+
"utf8"
|
|
27550
|
+
);
|
|
27489
27551
|
} else {
|
|
27490
|
-
mcpConfigPath =
|
|
27552
|
+
mcpConfigPath = join43(request.runDirectory, "headless-mcp-config.json");
|
|
27491
27553
|
await writeFile13(
|
|
27492
27554
|
mcpConfigPath,
|
|
27493
27555
|
`${JSON.stringify(headlessMcpConfigDocument(prepared.mcpServers), null, 2)}
|
|
27494
27556
|
`,
|
|
27495
27557
|
"utf8"
|
|
27496
27558
|
);
|
|
27559
|
+
if (hostMethodSkills(request.methods).length > 0) {
|
|
27560
|
+
const packageRoot = env.AK_PACKAGE_ROOT ?? process.env.AK_PACKAGE_ROOT;
|
|
27561
|
+
if (typeof packageRoot !== "string" || packageRoot === "") {
|
|
27562
|
+
throw new Error("claude method plugin-dir requires AK_PACKAGE_ROOT");
|
|
27563
|
+
}
|
|
27564
|
+
pluginDir = packagedMethodPluginDir(packageRoot);
|
|
27565
|
+
applyMethodPrompt = (prompt) => applyClaudeSkillInvocation(request.methods, prompt);
|
|
27566
|
+
}
|
|
27497
27567
|
}
|
|
27498
27568
|
const sessionParent = config.sessionIdentity.resolveSessionFile(request.principal);
|
|
27499
27569
|
outcome = await driveExternalRoleTurnRounds(prepared, request, {
|
|
@@ -27518,7 +27588,8 @@ function createHeadlessRoleTurnHost(config) {
|
|
|
27518
27588
|
sessionId,
|
|
27519
27589
|
sessionKind,
|
|
27520
27590
|
cwd: request.cwd,
|
|
27521
|
-
...gitCommonDir === void 0 ? {} : { writableRoots: [gitCommonDir] }
|
|
27591
|
+
...gitCommonDir === void 0 ? {} : { writableRoots: [gitCommonDir] },
|
|
27592
|
+
...pluginDir === void 0 ? {} : { pluginDir }
|
|
27522
27593
|
});
|
|
27523
27594
|
} catch (error) {
|
|
27524
27595
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -27535,7 +27606,7 @@ function createHeadlessRoleTurnHost(config) {
|
|
|
27535
27606
|
args,
|
|
27536
27607
|
cwd: request.cwd,
|
|
27537
27608
|
env,
|
|
27538
|
-
stdin: prompt,
|
|
27609
|
+
stdin: applyMethodPrompt(prompt),
|
|
27539
27610
|
...abortSignal === void 0 ? {} : { signal: abortSignal },
|
|
27540
27611
|
...request.timeoutMs === void 0 ? {} : { timeoutMs: request.timeoutMs },
|
|
27541
27612
|
onStdoutLine(line2) {
|
|
@@ -1,5 +1,3 @@
|
|
|
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
1
|
export const DEFAULT_ROLE_TURN_HOST = "pi";
|
|
4
2
|
export const HOST_DESCRIPTIONS = Object.freeze({
|
|
5
3
|
/** Operator home `~/.grok`, native session/load resume, `agent [--model X] stdio`. */
|
|
@@ -13,11 +11,6 @@ export const HOST_DESCRIPTIONS = Object.freeze({
|
|
|
13
11
|
modelPassing: "argv",
|
|
14
12
|
boundResume: "session/load",
|
|
15
13
|
sessionBindingFile: "grok-acp-session.json",
|
|
16
|
-
childEnv: Object.freeze({
|
|
17
|
-
...PRIVATE_COMPAT_ENV,
|
|
18
|
-
GROK_MEMORY: "0",
|
|
19
|
-
GROK_SUBAGENTS: "0",
|
|
20
|
-
}),
|
|
21
14
|
}),
|
|
22
15
|
/**
|
|
23
16
|
* Operator home `~/.hermes`, native session/load resume, `acp` subcommand.
|
|
@@ -36,7 +29,6 @@ export const HOST_DESCRIPTIONS = Object.freeze({
|
|
|
36
29
|
modelPassing: "set_model",
|
|
37
30
|
boundResume: "session/load",
|
|
38
31
|
sessionBindingFile: "hermes-acp-session.json",
|
|
39
|
-
childEnv: Object.freeze({}),
|
|
40
32
|
seatProfileSoul: Object.freeze({
|
|
41
33
|
flag: "-p",
|
|
42
34
|
namePrefix: "ak-",
|
|
@@ -49,12 +41,9 @@ export const HOST_DESCRIPTIONS = Object.freeze({
|
|
|
49
41
|
* Headless CLI family (#645 / #646). Claude print-mode is the first row;
|
|
50
42
|
* codex exec (#646) adds another. Protocol-specific argv/parse live in
|
|
51
43
|
* headless-host helpers (#752 per-host impl).
|
|
52
|
-
* Claude fixedArgs: print mode,
|
|
53
|
-
*
|
|
54
|
-
* (#
|
|
55
|
-
* user/project/local CLAUDE.md/hooks/skills (role envelope is delivered via
|
|
56
|
-
* `--system-prompt` wholesale replace). `--strict-mcp-config` with no
|
|
57
|
-
* `--mcp-config` drops operator MCP + claude.ai connectors.
|
|
44
|
+
* Claude fixedArgs: print mode, full permissions. stream-json + verbose: live
|
|
45
|
+
* host events for sitian records (#811); result is last line. Forced methods
|
|
46
|
+
* ride `--plugin-dir` (#922); operator skill/setting surfaces stay open.
|
|
58
47
|
*/
|
|
59
48
|
export const HEADLESS_HOST_DESCRIPTIONS = Object.freeze({
|
|
60
49
|
"claude": Object.freeze({
|
|
@@ -67,10 +56,6 @@ export const HEADLESS_HOST_DESCRIPTIONS = Object.freeze({
|
|
|
67
56
|
// Intermediate assistant/tool/system events require verbose with stream-json.
|
|
68
57
|
"--verbose",
|
|
69
58
|
"--permission-mode", "bypassPermissions",
|
|
70
|
-
// Empty sources: no user/project/local operator surface (envelope owns materials).
|
|
71
|
-
"--setting-sources", "",
|
|
72
|
-
// With adapter-supplied --mcp-config only (AK relay); drops operator + claude.ai MCP.
|
|
73
|
-
"--strict-mcp-config",
|
|
74
59
|
]),
|
|
75
60
|
promptFlag: "-p",
|
|
76
61
|
modelFlag: "--model",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# ak-cross-m-review
|
|
2
|
+
|
|
3
|
+
Local, pre-PR review gate: two independent lenses against a pinned diff, one verdict each; a single lens runs in the invoking session, `all` runs both as parallel sub-agent legs. `SKILL.md` plus the selected lens prompt is the complete active authority; this file is vocabulary only.
|
|
4
|
+
|
|
5
|
+
## Language
|
|
6
|
+
|
|
7
|
+
**Fixed target**:
|
|
8
|
+
The pinned base-to-HEAD snapshot under review, resolved to two literal SHAs
|
|
9
|
+
before anything is dispatched.
|
|
10
|
+
_Avoid_: range, worktree diff, working changes
|
|
11
|
+
|
|
12
|
+
**Authority set**:
|
|
13
|
+
The ordered sources that govern the review — user decisions first, then
|
|
14
|
+
ratified ADRs / specs, then repository contracts.
|
|
15
|
+
_Avoid_: spec (alone), reference docs
|
|
16
|
+
|
|
17
|
+
**Lens**:
|
|
18
|
+
One review question with its own prompt file — `completeness` (was the
|
|
19
|
+
authority delivered?) or `correctness` (is what exists right?).
|
|
20
|
+
_Avoid_: axis, gate, mode, pass
|
|
21
|
+
|
|
22
|
+
**Leg**:
|
|
23
|
+
One independent sub-agent running exactly one lens inside an independent copy of the target at `PRE_HEAD`, dispatched only by `all`; the copy is provided by the harness when it can, otherwise created by the caller. A single-lens invocation has no leg: the invoking session applies the lens itself.
|
|
24
|
+
_Avoid_: panel, member, reviewer squad, vendor leg
|
|
25
|
+
|
|
26
|
+
**Candidate**:
|
|
27
|
+
An evidence-backed claim a leg submits for judgment; never a verdict.
|
|
28
|
+
_Avoid_: finding (before judgment), vote
|
|
29
|
+
|
|
30
|
+
**Judge**:
|
|
31
|
+
The invoking session, which verifies each candidate against the fixed target
|
|
32
|
+
and authority set and disposes it as live or refuted.
|
|
33
|
+
_Avoid_: orchestrator, runner, merger
|
|
34
|
+
|
|
35
|
+
**Verdict**:
|
|
36
|
+
The single terminal line a lens ends with, labelled by lens
|
|
37
|
+
(`CMR-VERDICT: completeness=…` / `CMR-VERDICT: correctness=…`).
|
|
38
|
+
_Avoid_: gate result, concur, convergence
|
|
39
|
+
|
|
40
|
+
**Preset**:
|
|
41
|
+
A named wrapper skill that invokes the engine with one lens and returns its
|
|
42
|
+
report unchanged.
|
|
43
|
+
_Avoid_: gate skill, entry point
|
|
44
|
+
|
|
45
|
+
**Review only**:
|
|
46
|
+
The outcome boundary — the invocation reports and stops; the caller owns every
|
|
47
|
+
repair, commit, retry, and later review.
|
|
48
|
+
_Avoid_: read-only (that is a filesystem property, not this boundary)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Akagi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|