@akagilnc/pi-workflow-roles 0.1.3826 → 0.1.3837
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/production-host.js +88 -81
- package/dist/canonical-skill-binding.js +0 -3
- package/dist/headless-host/production-host.js +86 -79
- package/dist/pi/adapter.js +11 -0
- package/dist/pi/role-turn-host.js +25 -2
- package/dist/public-cli/invocation.js +4 -5
- package/dist/public-cli/main.js +50 -38
- package/dist/role-runtime.js +4 -7
- package/dist/worker-role.js +14 -12
- package/package.json +1 -1
- package/src/acp-host/role-envelope.ts +13 -14
- package/src/acp-host/role-turn-host.ts +1 -1
- package/src/canonical-skill-binding.ts +4 -4
- package/src/host-contracts.ts +6 -0
- package/src/package-resources/method-skill-binding.ts +0 -3
- package/src/pi/adapter.ts +13 -0
- package/src/pi/role-turn-host.ts +29 -2
- package/src/public-cli/invocation.ts +4 -5
- package/src/role-runtime.ts +7 -7
- package/src/worker-role.ts +14 -13
package/dist/public-cli/main.js
CHANGED
|
@@ -16584,7 +16584,7 @@ var init_sitian_facade = __esm({
|
|
|
16584
16584
|
import { execFile, spawn } from "node:child_process";
|
|
16585
16585
|
import { constants } from "node:fs";
|
|
16586
16586
|
import { access, appendFile, readFile as readFile3, realpath } from "node:fs/promises";
|
|
16587
|
-
import { delimiter as delimiter2, isAbsolute as isAbsolute3, join as join10, resolve as resolve4 } from "node:path";
|
|
16587
|
+
import { basename as basename4, delimiter as delimiter2, dirname as dirname6, isAbsolute as isAbsolute3, join as join10, resolve as resolve4 } from "node:path";
|
|
16588
16588
|
import { platform } from "node:process";
|
|
16589
16589
|
import { promisify } from "node:util";
|
|
16590
16590
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
@@ -16692,12 +16692,26 @@ function buildMethodArgs(methods) {
|
|
|
16692
16692
|
}
|
|
16693
16693
|
return skillArgs;
|
|
16694
16694
|
}
|
|
16695
|
+
function applyPiNativeSkillInvocation(methods, prompt) {
|
|
16696
|
+
const skills = methods.filter((method) => method.kind === "skill");
|
|
16697
|
+
if (skills.length !== 1) return prompt;
|
|
16698
|
+
const name = basename4(dirname6(skills[0].path));
|
|
16699
|
+
if (name.length === 0) return prompt;
|
|
16700
|
+
const token = `/skill:${name}`;
|
|
16701
|
+
const trimmed = prompt.trimStart();
|
|
16702
|
+
if (trimmed === token || trimmed.startsWith(`${token} `) || trimmed.startsWith(`${token}
|
|
16703
|
+
`)) {
|
|
16704
|
+
return prompt;
|
|
16705
|
+
}
|
|
16706
|
+
return prompt.length === 0 ? token : `${token} ${prompt}`;
|
|
16707
|
+
}
|
|
16695
16708
|
function buildPiTurnExtraArgs(request, authority, extraPiArgs = []) {
|
|
16696
16709
|
const { sessionFile, sessionDirectory } = authority.decode(request.principal);
|
|
16697
|
-
const
|
|
16710
|
+
const rawPrompt = request.continuation.kind === "initial" || request.continuation.kind === "resume" ? request.continuation.prompt : (() => {
|
|
16698
16711
|
const _exhaustive = request.continuation;
|
|
16699
16712
|
return _exhaustive;
|
|
16700
16713
|
})();
|
|
16714
|
+
const prompt = applyPiNativeSkillInvocation(request.methods, rawPrompt);
|
|
16701
16715
|
return [
|
|
16702
16716
|
"--no-skills",
|
|
16703
16717
|
...buildMethodArgs(request.methods),
|
|
@@ -17173,7 +17187,7 @@ var init_terminating_tools = __esm({
|
|
|
17173
17187
|
|
|
17174
17188
|
// src/doctor-evidence.ts
|
|
17175
17189
|
import { readdir, readFile as readFile5, realpath as realpath2, stat } from "node:fs/promises";
|
|
17176
|
-
import { dirname as
|
|
17190
|
+
import { dirname as dirname7, relative as relative2, resolve as resolve5, sep as sep2 } from "node:path";
|
|
17177
17191
|
function record2(value) {
|
|
17178
17192
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17179
17193
|
}
|
|
@@ -17212,7 +17226,7 @@ async function stableRunsIdentity(root) {
|
|
|
17212
17226
|
} catch (error) {
|
|
17213
17227
|
if (!isMissingPathError(error)) throw error;
|
|
17214
17228
|
}
|
|
17215
|
-
const parent =
|
|
17229
|
+
const parent = dirname7(cursor);
|
|
17216
17230
|
if (parent === cursor) return root;
|
|
17217
17231
|
cursor = parent;
|
|
17218
17232
|
}
|
|
@@ -19025,7 +19039,7 @@ __export(notary_source_run_exports, {
|
|
|
19025
19039
|
loadNotarySourceRunLocator: () => loadNotarySourceRunLocator,
|
|
19026
19040
|
resolveNotarySourceRunLocator: () => resolveNotarySourceRunLocator
|
|
19027
19041
|
});
|
|
19028
|
-
import { dirname as
|
|
19042
|
+
import { dirname as dirname8, isAbsolute as isAbsolute5, join as join14, resolve as resolve6, basename as basename5 } from "node:path";
|
|
19029
19043
|
import { lstat as lstat2, realpath as realpath3 } from "node:fs/promises";
|
|
19030
19044
|
function parseRunDirectoryName(name) {
|
|
19031
19045
|
const match = RUN_DIR_NAME.exec(name);
|
|
@@ -19056,10 +19070,10 @@ async function requireRunDirectory(candidate, display) {
|
|
|
19056
19070
|
`notary --source-run must be a run directory: ${display}`
|
|
19057
19071
|
);
|
|
19058
19072
|
}
|
|
19059
|
-
const identity = parseRunDirectoryName(
|
|
19073
|
+
const identity = parseRunDirectoryName(basename5(real));
|
|
19060
19074
|
if (identity === void 0) {
|
|
19061
19075
|
throw new NotarySourceRunError(
|
|
19062
|
-
`notary --source-run must be named <runId>@<role>: ${
|
|
19076
|
+
`notary --source-run must be named <runId>@<role>: ${basename5(real)}`
|
|
19063
19077
|
);
|
|
19064
19078
|
}
|
|
19065
19079
|
return real;
|
|
@@ -19080,9 +19094,9 @@ async function resolveNotarySourceRunLocator(options) {
|
|
|
19080
19094
|
candidate = isAbsolute5(raw) ? raw : resolve6(options.projectRoot, raw);
|
|
19081
19095
|
}
|
|
19082
19096
|
const real = await requireRunDirectory(candidate, raw);
|
|
19083
|
-
const identity = parseRunDirectoryName(
|
|
19097
|
+
const identity = parseRunDirectoryName(basename5(real));
|
|
19084
19098
|
const runsRootIdentity = physicalPathIdentity(bookRunsRoot);
|
|
19085
|
-
const parentIdentity = physicalPathIdentity(
|
|
19099
|
+
const parentIdentity = physicalPathIdentity(dirname8(real));
|
|
19086
19100
|
if (parentIdentity !== runsRootIdentity) {
|
|
19087
19101
|
throw new NotarySourceRunError(
|
|
19088
19102
|
"notary --source-run must resolve to a retained run under the project machine-ledger book"
|
|
@@ -19117,7 +19131,7 @@ async function resolveNotarySourceRunLocator(options) {
|
|
|
19117
19131
|
}
|
|
19118
19132
|
async function loadNotarySourceRunLocator(path) {
|
|
19119
19133
|
const real = await requireRunDirectory(path, path);
|
|
19120
|
-
const identity = parseRunDirectoryName(
|
|
19134
|
+
const identity = parseRunDirectoryName(basename5(real));
|
|
19121
19135
|
const runState = await readRoleRunIdentity(real);
|
|
19122
19136
|
if (runState === void 0) {
|
|
19123
19137
|
throw new NotarySourceRunError(
|
|
@@ -20215,7 +20229,7 @@ import {
|
|
|
20215
20229
|
realpath as realpath4,
|
|
20216
20230
|
writeFile as writeFile4
|
|
20217
20231
|
} from "node:fs/promises";
|
|
20218
|
-
import { basename as
|
|
20232
|
+
import { basename as basename6, isAbsolute as isAbsolute6, join as join15, resolve as resolve7, sep as sep3 } from "node:path";
|
|
20219
20233
|
function issueAdmissionPlacement(authority, request) {
|
|
20220
20234
|
const principal = authority.issue(request);
|
|
20221
20235
|
const { sessionDirectory, sessionFile } = authority.decode(principal);
|
|
@@ -20609,7 +20623,7 @@ async function freezeRegularFileAttachment(sourcePath, destinationDir, index) {
|
|
|
20609
20623
|
);
|
|
20610
20624
|
}
|
|
20611
20625
|
const bytes = await readFile9(absolute);
|
|
20612
|
-
const name = `${String(index).padStart(2, "0")}-${
|
|
20626
|
+
const name = `${String(index).padStart(2, "0")}-${basename6(absolute)}`;
|
|
20613
20627
|
const frozenPath = join15(destinationDir, name);
|
|
20614
20628
|
await writeFile4(frozenPath, bytes);
|
|
20615
20629
|
return {
|
|
@@ -22044,9 +22058,7 @@ async function admitMergerInvocation(options) {
|
|
|
22044
22058
|
};
|
|
22045
22059
|
}
|
|
22046
22060
|
function buildMergerTransportPrompt(admitted, engineMaterial) {
|
|
22047
|
-
const lines = [
|
|
22048
|
-
`/skill:resolving-merge-conflicts ${admitted.instruction}`
|
|
22049
|
-
];
|
|
22061
|
+
const lines = [admitted.instruction];
|
|
22050
22062
|
if (admitted.attachments.length > 0) {
|
|
22051
22063
|
lines.push("");
|
|
22052
22064
|
lines.push("\u5DF2\u53D7\u7406\u9644\u4EF6\uFF08\u51BB\u7ED3\u5FEB\u7167\u8DEF\u5F84\uFF09\uFF1A");
|
|
@@ -23054,7 +23066,7 @@ var init_analyst_gate_cycles_read = __esm({
|
|
|
23054
23066
|
|
|
23055
23067
|
// src/run-terminal-artifacts.ts
|
|
23056
23068
|
import { readdir as readdir4, readFile as readFile12 } from "node:fs/promises";
|
|
23057
|
-
import { basename as
|
|
23069
|
+
import { basename as basename7, dirname as dirname9, join as join18 } from "node:path";
|
|
23058
23070
|
function isMissingPathError2(error) {
|
|
23059
23071
|
return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
|
|
23060
23072
|
}
|
|
@@ -23135,7 +23147,7 @@ async function listUniqueErrorFallbackPaths(directories) {
|
|
|
23135
23147
|
return found;
|
|
23136
23148
|
}
|
|
23137
23149
|
function runIdFromRunDirectory(runDirectory) {
|
|
23138
|
-
const name =
|
|
23150
|
+
const name = basename7(runDirectory);
|
|
23139
23151
|
const at = name.lastIndexOf("@");
|
|
23140
23152
|
if (at <= 0 || at === name.length - 1) return void 0;
|
|
23141
23153
|
return name.slice(0, at);
|
|
@@ -23161,7 +23173,7 @@ async function readRunTerminalArtifact(runDirectory) {
|
|
|
23161
23173
|
if (read3 !== void 0) return read3;
|
|
23162
23174
|
}
|
|
23163
23175
|
const expectedRunId = runIdFromRunDirectory(runDirectory);
|
|
23164
|
-
for (const path of await listUniqueErrorFallbackPaths([
|
|
23176
|
+
for (const path of await listUniqueErrorFallbackPaths([dirname9(runDirectory)])) {
|
|
23165
23177
|
const read3 = await readTerminalArtifactAtPath(path, "error.json");
|
|
23166
23178
|
if (read3 === void 0) continue;
|
|
23167
23179
|
if (read3.status === "present") {
|
|
@@ -23292,15 +23304,15 @@ var init_submission_ledger = __esm({
|
|
|
23292
23304
|
// src/session-opening-materials.ts
|
|
23293
23305
|
import { existsSync as existsSync7 } from "node:fs";
|
|
23294
23306
|
import { readFile as readFile13 } from "node:fs/promises";
|
|
23295
|
-
import { dirname as
|
|
23307
|
+
import { dirname as dirname10, join as join19 } from "node:path";
|
|
23296
23308
|
import { fileURLToPath, pathToFileURL as pathToFileURL3 } from "node:url";
|
|
23297
23309
|
function resolvePackageRootDir(moduleUrl = import.meta.url) {
|
|
23298
|
-
let dir =
|
|
23310
|
+
let dir = dirname10(fileURLToPath(moduleUrl));
|
|
23299
23311
|
for (let i = 0; i < 8; i += 1) {
|
|
23300
23312
|
if (existsSync7(join19(dir, "package.json")) && existsSync7(join19(dir, "souls"))) {
|
|
23301
23313
|
return dir;
|
|
23302
23314
|
}
|
|
23303
|
-
const parent =
|
|
23315
|
+
const parent = dirname10(dir);
|
|
23304
23316
|
if (parent === dir) break;
|
|
23305
23317
|
dir = parent;
|
|
23306
23318
|
}
|
|
@@ -23964,7 +23976,7 @@ var init_terminal = __esm({
|
|
|
23964
23976
|
// src/public-cli/settlement.ts
|
|
23965
23977
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
23966
23978
|
import { appendFile as appendFile2, readFile as readFile15, readdir as readdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
23967
|
-
import { dirname as
|
|
23979
|
+
import { dirname as dirname11, join as join21 } from "node:path";
|
|
23968
23980
|
function sealedLedgerHome(admitted) {
|
|
23969
23981
|
return homeFromRunDirectory(admitted.runDirectory);
|
|
23970
23982
|
}
|
|
@@ -24358,7 +24370,7 @@ async function readSitianRetainedAuditorProviderStop(sessionFile) {
|
|
|
24358
24370
|
kind: "auditor",
|
|
24359
24371
|
sessionParent: sessionFile,
|
|
24360
24372
|
// Path is driven by sessionParent when under ledger home; cwd is a fallback only.
|
|
24361
|
-
cwd:
|
|
24373
|
+
cwd: dirname11(sessionFile)
|
|
24362
24374
|
});
|
|
24363
24375
|
const { records: records2 } = await readSitianRecords(recordFile);
|
|
24364
24376
|
for (let i = records2.length - 1; i >= 0; i -= 1) {
|
|
@@ -24384,7 +24396,7 @@ async function readSessionProviderStop(sessionFile) {
|
|
|
24384
24396
|
}
|
|
24385
24397
|
}
|
|
24386
24398
|
async function readBoundEvidenceChildKnownFailure(sessionFile) {
|
|
24387
|
-
const childDirectory = join21(
|
|
24399
|
+
const childDirectory = join21(dirname11(sessionFile), "evidence-children");
|
|
24388
24400
|
let names;
|
|
24389
24401
|
try {
|
|
24390
24402
|
names = await readdir5(childDirectory);
|
|
@@ -24449,7 +24461,7 @@ async function loadBoundAuditorVolumes(sessionFile) {
|
|
|
24449
24461
|
latestParentUserIndex = i;
|
|
24450
24462
|
break;
|
|
24451
24463
|
}
|
|
24452
|
-
const childDirectories = [join21(
|
|
24464
|
+
const childDirectories = [join21(dirname11(sessionFile), "auditor-roles")];
|
|
24453
24465
|
const valid = [];
|
|
24454
24466
|
let sawAnyDirectory = false;
|
|
24455
24467
|
for (const childDirectory of childDirectories) {
|
|
@@ -26023,7 +26035,7 @@ function publicationAttemptFromError(path, error) {
|
|
|
26023
26035
|
}
|
|
26024
26036
|
function uniqueFailureFallbackDirs(runDirectory, baseDir) {
|
|
26025
26037
|
const dirs = [];
|
|
26026
|
-
for (const dir of [baseDir, runDirectory,
|
|
26038
|
+
for (const dir of [baseDir, runDirectory, dirname11(runDirectory)]) {
|
|
26027
26039
|
if (!dirs.includes(dir)) dirs.push(dir);
|
|
26028
26040
|
}
|
|
26029
26041
|
return dirs;
|
|
@@ -26479,7 +26491,7 @@ var init_case_dossier_delivery = __esm({
|
|
|
26479
26491
|
|
|
26480
26492
|
// src/host-transition-prior-native.ts
|
|
26481
26493
|
import { access as access2, readdir as readdir6 } from "node:fs/promises";
|
|
26482
|
-
import { dirname as
|
|
26494
|
+
import { dirname as dirname12, join as join23 } from "node:path";
|
|
26483
26495
|
function isEnoent2(error) {
|
|
26484
26496
|
return typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
26485
26497
|
}
|
|
@@ -26493,7 +26505,7 @@ async function listPiNativeRecordPaths(sessionFile) {
|
|
|
26493
26505
|
}
|
|
26494
26506
|
}
|
|
26495
26507
|
async function listSitianRecordPaths(sessionParent) {
|
|
26496
|
-
const sessionRoot =
|
|
26508
|
+
const sessionRoot = dirname12(sessionParent);
|
|
26497
26509
|
let entries;
|
|
26498
26510
|
try {
|
|
26499
26511
|
entries = await readdir6(sessionRoot, { withFileTypes: true });
|
|
@@ -29875,9 +29887,9 @@ var init_analyst_book_key = __esm({
|
|
|
29875
29887
|
// src/atomic-write.ts
|
|
29876
29888
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
29877
29889
|
import { rename, rm, writeFile as writeFile8 } from "node:fs/promises";
|
|
29878
|
-
import { dirname as
|
|
29890
|
+
import { dirname as dirname13, join as join27 } from "node:path";
|
|
29879
29891
|
async function writeFileAtomically(destination, contents) {
|
|
29880
|
-
const parent =
|
|
29892
|
+
const parent = dirname13(destination);
|
|
29881
29893
|
const temporary = join27(parent, `.atomic-write-${randomUUID6()}.tmp`);
|
|
29882
29894
|
try {
|
|
29883
29895
|
await writeFile8(temporary, contents);
|
|
@@ -29895,7 +29907,7 @@ var init_atomic_write = __esm({
|
|
|
29895
29907
|
|
|
29896
29908
|
// src/analyst-index.ts
|
|
29897
29909
|
import { open as open3, readFile as readFile17, unlink as unlink4 } from "node:fs/promises";
|
|
29898
|
-
import { dirname as
|
|
29910
|
+
import { dirname as dirname14, join as join28 } from "node:path";
|
|
29899
29911
|
function sleep(ms) {
|
|
29900
29912
|
return new Promise((resolve11) => {
|
|
29901
29913
|
setTimeout(resolve11, ms);
|
|
@@ -29903,8 +29915,8 @@ function sleep(ms) {
|
|
|
29903
29915
|
}
|
|
29904
29916
|
async function withAnalystLibraryIndexLock(ledgerHome, fn) {
|
|
29905
29917
|
const indexPath = analystLibraryIndexPath(ledgerHome);
|
|
29906
|
-
ensureRealDirectoryTree(ledgerHome,
|
|
29907
|
-
const lockPath = join28(
|
|
29918
|
+
ensureRealDirectoryTree(ledgerHome, dirname14(indexPath));
|
|
29919
|
+
const lockPath = join28(dirname14(indexPath), LIBRARY_INDEX_LOCK_NAME);
|
|
29908
29920
|
assertLedgerFileInsideHome(lockPath, ledgerHome);
|
|
29909
29921
|
const startedAt = Date.now();
|
|
29910
29922
|
while (true) {
|
|
@@ -30040,7 +30052,7 @@ async function readAnalystLibraryIndexPage(ledgerHome) {
|
|
|
30040
30052
|
}
|
|
30041
30053
|
async function writeAnalystLibraryIndexPage(ledgerHome, page) {
|
|
30042
30054
|
const path = analystLibraryIndexPath(ledgerHome);
|
|
30043
|
-
ensureRealDirectoryTree(ledgerHome,
|
|
30055
|
+
ensureRealDirectoryTree(ledgerHome, dirname14(path));
|
|
30044
30056
|
assertLedgerFileInsideHome(path, ledgerHome);
|
|
30045
30057
|
await writeFileAtomically(path, `${JSON.stringify(page, null, 2)}
|
|
30046
30058
|
`);
|
|
@@ -31417,7 +31429,7 @@ var init_analyst_metric_family = __esm({
|
|
|
31417
31429
|
|
|
31418
31430
|
// src/analyst-page.ts
|
|
31419
31431
|
import { createHash as createHash5 } from "node:crypto";
|
|
31420
|
-
import { dirname as
|
|
31432
|
+
import { dirname as dirname15, join as join30 } from "node:path";
|
|
31421
31433
|
function analystIssuePageKey(address) {
|
|
31422
31434
|
const parts = ["book", address.bookKey];
|
|
31423
31435
|
if (address.issueNumber !== void 0) {
|
|
@@ -31547,7 +31559,7 @@ async function buildAnalystIssueMetricsPage(input) {
|
|
|
31547
31559
|
}
|
|
31548
31560
|
async function writeAnalystIssueMetricsPage(ledgerHome, page) {
|
|
31549
31561
|
const path = analystIssuePagePath(ledgerHome, analystIssuePageAddressFromPage(page));
|
|
31550
|
-
ensureRealDirectoryTree(ledgerHome,
|
|
31562
|
+
ensureRealDirectoryTree(ledgerHome, dirname15(path));
|
|
31551
31563
|
assertLedgerFileInsideHome(path, ledgerHome);
|
|
31552
31564
|
await writeFileAtomically(path, `${JSON.stringify(page, null, 2)}
|
|
31553
31565
|
`);
|
|
@@ -33065,7 +33077,7 @@ var init_cli = __esm({
|
|
|
33065
33077
|
|
|
33066
33078
|
// src/public-cli/main.ts
|
|
33067
33079
|
import { existsSync as existsSync8 } from "node:fs";
|
|
33068
|
-
import { dirname as
|
|
33080
|
+
import { dirname as dirname16, join as join32 } from "node:path";
|
|
33069
33081
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
33070
33082
|
|
|
33071
33083
|
// src/public-cli/host-pi-runtime.ts
|
|
@@ -33152,7 +33164,7 @@ function linkPackage(packageRoot2, name, targetDir) {
|
|
|
33152
33164
|
}
|
|
33153
33165
|
|
|
33154
33166
|
// src/public-cli/main.ts
|
|
33155
|
-
var here =
|
|
33167
|
+
var here = dirname16(fileURLToPath2(import.meta.url));
|
|
33156
33168
|
function resolvePackageRoot(binDir) {
|
|
33157
33169
|
const canonical = join32(binDir, "..", "..");
|
|
33158
33170
|
if (existsSync8(join32(canonical, "package.json"))) {
|
package/dist/role-runtime.js
CHANGED
|
@@ -748,17 +748,14 @@ export function createRoleRuntimeExtension(dependencies) {
|
|
|
748
748
|
const role = roleHost.getFlag(ROLE_FLAG.name);
|
|
749
749
|
if (role !== undefined && !admitted)
|
|
750
750
|
return { action: "handled" };
|
|
751
|
-
//
|
|
751
|
+
// Reviewer: recover original request; Pi argv may already carry native form.
|
|
752
752
|
if (role === "reviewer"
|
|
753
753
|
&& admitted
|
|
754
754
|
&& activeReviewerParent !== undefined
|
|
755
755
|
&& reviewerOriginalRequest === undefined) {
|
|
756
|
-
reviewerOriginalRequest =
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
text: activeReviewerParent.skillBinding.invocation(event.text),
|
|
760
|
-
...(event.images === undefined ? {} : { images: event.images }),
|
|
761
|
-
};
|
|
756
|
+
reviewerOriginalRequest =
|
|
757
|
+
roleHost.capabilities?.skillOriginalRequest?.(activeReviewerParent.skillBinding.name, event.text) ?? event.text;
|
|
758
|
+
return { action: "continue" };
|
|
762
759
|
}
|
|
763
760
|
return { action: "continue" };
|
|
764
761
|
});
|
package/dist/worker-role.js
CHANGED
|
@@ -227,6 +227,12 @@ export function createCoderRoleRuntime(pi, dependencies, hostActions) {
|
|
|
227
227
|
});
|
|
228
228
|
return {
|
|
229
229
|
async activate(ctx) {
|
|
230
|
+
// Each activation owns its own Skill capture state; prior-session flags must
|
|
231
|
+
// not authorize a later apply completed (same RoleHost, sequential activate).
|
|
232
|
+
tddInvocationInjected = false;
|
|
233
|
+
originalRequest = undefined;
|
|
234
|
+
expansionPending = false;
|
|
235
|
+
expansionCaptured = false;
|
|
230
236
|
soul = (await dependencies.loadSoul()).trim();
|
|
231
237
|
if (soul.length === 0)
|
|
232
238
|
throw new Error("Coder soul is empty");
|
|
@@ -303,18 +309,14 @@ export function createCoderRoleRuntime(pi, dependencies, hostActions) {
|
|
|
303
309
|
}
|
|
304
310
|
tddInvocationInjected = true;
|
|
305
311
|
expansionPending = true;
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return {
|
|
314
|
-
action: "transform",
|
|
315
|
-
text: binding?.invocation(event.text) ?? `/skill:tdd ${event.text}`,
|
|
316
|
-
...(event.images === undefined ? {} : { images: event.images }),
|
|
317
|
-
};
|
|
312
|
+
// Original request via host capability when Pi argv already carries native form;
|
|
313
|
+
// non-pi keeps plain original bytes (no consumer trim; #822 r3 / reviewer-aligned).
|
|
314
|
+
// Role never emits or parses `/skill:` (ADR 0082).
|
|
315
|
+
originalRequest = binding === undefined
|
|
316
|
+
? event.text
|
|
317
|
+
: (pi.capabilities?.skillOriginalRequest?.(binding.name, event.text)
|
|
318
|
+
?? event.text);
|
|
319
|
+
return { action: "continue" };
|
|
318
320
|
});
|
|
319
321
|
pi.on("before_agent_start", (event, ctx) => {
|
|
320
322
|
if (soul === undefined)
|
package/package.json
CHANGED
|
@@ -41,27 +41,26 @@ type RpcRequest = { readonly id: number; readonly token: string; readonly method
|
|
|
41
41
|
type ToolCallParams = { readonly name?: unknown; readonly arguments?: unknown };
|
|
42
42
|
type ContentPart = { type: "text"; text: string } | { type: "image"; data: string; mimeType: string };
|
|
43
43
|
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
/** Build host-side Skill expansion evidence from pre-read RoleTurnRequest.methods. */
|
|
44
|
+
/**
|
|
45
|
+
* Build host-side Skill expansion evidence from pre-read RoleTurnRequest.methods.
|
|
46
|
+
* Non-pi hosts never parse Pi `/skill:` syntax (ADR 0082 `pi-no-privilege`);
|
|
47
|
+
* a single bound method treats the plain prompt as the preserved user message.
|
|
48
|
+
* Pi-native slash forms stay inside `src/pi/` only.
|
|
49
|
+
*/
|
|
52
50
|
export function buildAcpSkillExpansion(
|
|
53
51
|
methodSkills: ReadonlyMap<string, { readonly path: string; readonly body: string }>,
|
|
54
52
|
prompt: string,
|
|
55
53
|
): HostSkillExpansionEvidence | undefined {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
if (methodSkills.size !== 1) return undefined;
|
|
55
|
+
const entry = methodSkills.entries().next().value;
|
|
56
|
+
if (entry === undefined) return undefined;
|
|
57
|
+
const [name, method] = entry;
|
|
60
58
|
return Object.freeze({
|
|
61
|
-
name
|
|
59
|
+
name,
|
|
62
60
|
location: method.path,
|
|
63
61
|
content: `References are relative to ${dirname(method.path)}.\n\n${method.body}`,
|
|
64
|
-
|
|
62
|
+
// Non-pi typed chain keeps original task bytes (ticket #822 r3); no consumer trim.
|
|
63
|
+
userMessage: prompt,
|
|
65
64
|
});
|
|
66
65
|
}
|
|
67
66
|
|
|
@@ -26,7 +26,7 @@ export type AcpPreparedTurn = Readonly<{
|
|
|
26
26
|
* send path — never a test-only parallel face.
|
|
27
27
|
*/
|
|
28
28
|
systemPrompt: { readonly body: string; readonly materials: readonly unknown[] };
|
|
29
|
-
/** Effective user prompt after host-side input
|
|
29
|
+
/** Effective user prompt after host-side input handling (host-neutral; no Pi `/skill:` syntax). */
|
|
30
30
|
prompt: string;
|
|
31
31
|
/**
|
|
32
32
|
* Host abort signal armed only by typed infrastructure failure (envelope
|
|
@@ -25,7 +25,10 @@ export type CanonicalSkillEvidence<Name extends CanonicalSkillName = CanonicalSk
|
|
|
25
25
|
export type CanonicalSkillBinding<Name extends CanonicalSkillName = CanonicalSkillName> = Readonly<{
|
|
26
26
|
name: Name;
|
|
27
27
|
snapshot: CanonicalSkillSnapshot;
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Accept host expansion evidence when name/location/content match the binding
|
|
30
|
+
* and userMessage equals the captured original request (ADR 0032).
|
|
31
|
+
*/
|
|
29
32
|
captureExpansion(
|
|
30
33
|
evidence: HostSkillExpansionEvidence | undefined,
|
|
31
34
|
originalRequest: string,
|
|
@@ -100,9 +103,6 @@ export async function loadCanonicalSkillBinding(
|
|
|
100
103
|
const binding: CanonicalSkillBinding<typeof name> = {
|
|
101
104
|
name,
|
|
102
105
|
snapshot,
|
|
103
|
-
invocation(originalRequest) {
|
|
104
|
-
return `/skill:${name} ${originalRequest}`;
|
|
105
|
-
},
|
|
106
106
|
captureExpansion(evidence, originalRequest) {
|
|
107
107
|
return captureCanonicalSkillExpansion(
|
|
108
108
|
name,
|
package/src/host-contracts.ts
CHANGED
|
@@ -321,6 +321,12 @@ export type HostSkillExpansionEvidence = Readonly<{
|
|
|
321
321
|
/** Host capability declaration (contract verb ④). */
|
|
322
322
|
export type HostCapabilityDeclaration = Readonly<{
|
|
323
323
|
skillExpansion(prompt: string): HostSkillExpansionEvidence | undefined;
|
|
324
|
+
/**
|
|
325
|
+
* Pi-only: recover the plain original request from a native skill turn text
|
|
326
|
+
* (argv may already carry `/skill:<name>` from the Pi adapter). Absent on
|
|
327
|
+
* non-pi hosts so role body never parses Pi slash syntax (ADR 0082).
|
|
328
|
+
*/
|
|
329
|
+
skillOriginalRequest?(name: string, text: string): string;
|
|
324
330
|
}>;
|
|
325
331
|
|
|
326
332
|
/** Host-owned effects used by the shared activation envelope. */
|
|
@@ -46,9 +46,6 @@ export async function loadPackagedCanonicalSkillBinding<
|
|
|
46
46
|
const binding: CanonicalSkillBinding<Name> = {
|
|
47
47
|
name,
|
|
48
48
|
snapshot,
|
|
49
|
-
invocation(originalRequest) {
|
|
50
|
-
return `/skill:${name} ${originalRequest}`;
|
|
51
|
-
},
|
|
52
49
|
captureExpansion(evidence, originalRequest) {
|
|
53
50
|
return captureCanonicalSkillExpansion(
|
|
54
51
|
name,
|
package/src/pi/adapter.ts
CHANGED
|
@@ -157,6 +157,19 @@ export function createPiRoleHostAdapter(
|
|
|
157
157
|
userMessage,
|
|
158
158
|
});
|
|
159
159
|
},
|
|
160
|
+
/** Recover plain original request from Pi-native `/skill:` turn text (ADR 0082). */
|
|
161
|
+
skillOriginalRequest(name, text) {
|
|
162
|
+
const token = `/skill:${name}`;
|
|
163
|
+
const trimmed = text.trimStart();
|
|
164
|
+
if (
|
|
165
|
+
trimmed === token
|
|
166
|
+
|| trimmed.startsWith(`${token} `)
|
|
167
|
+
|| trimmed.startsWith(`${token}\n`)
|
|
168
|
+
) {
|
|
169
|
+
return text.slice(text.indexOf(token) + token.length).trim();
|
|
170
|
+
}
|
|
171
|
+
return text.trim();
|
|
172
|
+
},
|
|
160
173
|
},
|
|
161
174
|
registerFlag: (name, definition) => pi.registerFlag(name, definition),
|
|
162
175
|
getFlag: (name) => pi.getFlag(name),
|
package/src/pi/role-turn-host.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { execFile, spawn } from "node:child_process";
|
|
7
7
|
import { constants } from "node:fs";
|
|
8
8
|
import { access, appendFile, readFile, realpath } from "node:fs/promises";
|
|
9
|
-
import { delimiter, isAbsolute, join, resolve } from "node:path";
|
|
9
|
+
import { basename, delimiter, dirname, isAbsolute, join, resolve } from "node:path";
|
|
10
10
|
import { platform } from "node:process";
|
|
11
11
|
import { promisify } from "node:util";
|
|
12
12
|
import { randomUUID } from "node:crypto";
|
|
@@ -167,9 +167,35 @@ function buildMethodArgs(methods: readonly MethodBinding[]): string[] {
|
|
|
167
167
|
return skillArgs;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Pi-native `/skill:<name>` for a single forced method (ADR 0082 `pi-no-privilege`).
|
|
172
|
+
* Driven by typed RoleTurnRequest.methods — middle-layer decision, Pi-only syntax.
|
|
173
|
+
* Zero/many methods leave the prompt alone (Fixer optional pair stays `--skill` only).
|
|
174
|
+
*/
|
|
175
|
+
export function applyPiNativeSkillInvocation(
|
|
176
|
+
methods: readonly MethodBinding[],
|
|
177
|
+
prompt: string,
|
|
178
|
+
): string {
|
|
179
|
+
const skills = methods.filter((method) => method.kind === "skill");
|
|
180
|
+
if (skills.length !== 1) return prompt;
|
|
181
|
+
const name = basename(dirname(skills[0]!.path));
|
|
182
|
+
if (name.length === 0) return prompt;
|
|
183
|
+
const token = `/skill:${name}`;
|
|
184
|
+
const trimmed = prompt.trimStart();
|
|
185
|
+
if (
|
|
186
|
+
trimmed === token
|
|
187
|
+
|| trimmed.startsWith(`${token} `)
|
|
188
|
+
|| trimmed.startsWith(`${token}\n`)
|
|
189
|
+
) {
|
|
190
|
+
return prompt;
|
|
191
|
+
}
|
|
192
|
+
return prompt.length === 0 ? token : `${token} ${prompt}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
170
195
|
/**
|
|
171
196
|
* Translate a closed RoleTurnRequest into Pi argv after `--no-extensions -e entry`.
|
|
172
197
|
* Controlled session constants and session coordinates are adapter-internal.
|
|
198
|
+
* Single forced method → Pi-native `/skill:` on the argv prompt (coder/reviewer/merger).
|
|
173
199
|
*/
|
|
174
200
|
export function buildPiTurnExtraArgs(
|
|
175
201
|
request: RoleTurnRequest,
|
|
@@ -177,13 +203,14 @@ export function buildPiTurnExtraArgs(
|
|
|
177
203
|
extraPiArgs: readonly string[] = [],
|
|
178
204
|
): string[] {
|
|
179
205
|
const { sessionFile, sessionDirectory } = authority.decode(request.principal);
|
|
180
|
-
const
|
|
206
|
+
const rawPrompt =
|
|
181
207
|
request.continuation.kind === "initial" || request.continuation.kind === "resume"
|
|
182
208
|
? request.continuation.prompt
|
|
183
209
|
: (() => {
|
|
184
210
|
const _exhaustive: never = request.continuation;
|
|
185
211
|
return _exhaustive;
|
|
186
212
|
})();
|
|
213
|
+
const prompt = applyPiNativeSkillInvocation(request.methods, rawPrompt);
|
|
187
214
|
return [
|
|
188
215
|
"--no-skills",
|
|
189
216
|
...buildMethodArgs(request.methods),
|
|
@@ -3071,16 +3071,15 @@ export async function admitMergerInvocation(
|
|
|
3071
3071
|
}
|
|
3072
3072
|
|
|
3073
3073
|
/**
|
|
3074
|
-
* Build the
|
|
3075
|
-
*
|
|
3074
|
+
* Build the host-neutral prompt transport for an admitted Merger request.
|
|
3075
|
+
* Method material binds on RoleTurnRequest.methods; Pi-native `/skill:` form
|
|
3076
|
+
* is adapter-internal only (ADR 0082).
|
|
3076
3077
|
*/
|
|
3077
3078
|
export function buildMergerTransportPrompt(
|
|
3078
3079
|
admitted: AdmittedMergerInvocation,
|
|
3079
3080
|
engineMaterial?: EngineSessionMaterial,
|
|
3080
3081
|
): string {
|
|
3081
|
-
const lines: string[] = [
|
|
3082
|
-
`/skill:resolving-merge-conflicts ${admitted.instruction}`,
|
|
3083
|
-
];
|
|
3082
|
+
const lines: string[] = [admitted.instruction];
|
|
3084
3083
|
if (admitted.attachments.length > 0) {
|
|
3085
3084
|
lines.push("");
|
|
3086
3085
|
lines.push("已受理附件(冻结快照路径):");
|
package/src/role-runtime.ts
CHANGED
|
@@ -1227,19 +1227,19 @@ export function createRoleRuntimeExtension(
|
|
|
1227
1227
|
roleHost.on("input", (event) => {
|
|
1228
1228
|
const role = roleHost.getFlag(ROLE_FLAG.name);
|
|
1229
1229
|
if (role !== undefined && !admitted) return { action: "handled" as const };
|
|
1230
|
-
//
|
|
1230
|
+
// Reviewer: recover original request; Pi argv may already carry native form.
|
|
1231
1231
|
if (
|
|
1232
1232
|
role === "reviewer"
|
|
1233
1233
|
&& admitted
|
|
1234
1234
|
&& activeReviewerParent !== undefined
|
|
1235
1235
|
&& reviewerOriginalRequest === undefined
|
|
1236
1236
|
) {
|
|
1237
|
-
reviewerOriginalRequest =
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
};
|
|
1237
|
+
reviewerOriginalRequest =
|
|
1238
|
+
roleHost.capabilities?.skillOriginalRequest?.(
|
|
1239
|
+
activeReviewerParent.skillBinding.name,
|
|
1240
|
+
event.text,
|
|
1241
|
+
) ?? event.text;
|
|
1242
|
+
return { action: "continue" as const };
|
|
1243
1243
|
}
|
|
1244
1244
|
return { action: "continue" as const };
|
|
1245
1245
|
});
|
package/src/worker-role.ts
CHANGED
|
@@ -347,6 +347,12 @@ export function createCoderRoleRuntime(
|
|
|
347
347
|
|
|
348
348
|
return {
|
|
349
349
|
async activate(ctx) {
|
|
350
|
+
// Each activation owns its own Skill capture state; prior-session flags must
|
|
351
|
+
// not authorize a later apply completed (same RoleHost, sequential activate).
|
|
352
|
+
tddInvocationInjected = false;
|
|
353
|
+
originalRequest = undefined;
|
|
354
|
+
expansionPending = false;
|
|
355
|
+
expansionCaptured = false;
|
|
350
356
|
soul = (await dependencies.loadSoul()).trim();
|
|
351
357
|
if (soul.length === 0) throw new Error("Coder soul is empty");
|
|
352
358
|
const selectedPhase = pi.getFlag("ak-coder-phase");
|
|
@@ -433,19 +439,14 @@ export function createCoderRoleRuntime(
|
|
|
433
439
|
}
|
|
434
440
|
tddInvocationInjected = true;
|
|
435
441
|
expansionPending = true;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
return {
|
|
445
|
-
action: "transform" as const,
|
|
446
|
-
text: binding?.invocation(event.text) ?? `/skill:tdd ${event.text}`,
|
|
447
|
-
...(event.images === undefined ? {} : { images: event.images }),
|
|
448
|
-
};
|
|
442
|
+
// Original request via host capability when Pi argv already carries native form;
|
|
443
|
+
// non-pi keeps plain original bytes (no consumer trim; #822 r3 / reviewer-aligned).
|
|
444
|
+
// Role never emits or parses `/skill:` (ADR 0082).
|
|
445
|
+
originalRequest = binding === undefined
|
|
446
|
+
? event.text
|
|
447
|
+
: (pi.capabilities?.skillOriginalRequest?.(binding.name, event.text)
|
|
448
|
+
?? event.text);
|
|
449
|
+
return { action: "continue" as const };
|
|
449
450
|
});
|
|
450
451
|
pi.on("before_agent_start", (event, ctx) => {
|
|
451
452
|
if (soul === undefined) throw new Error("将作监职分未装载");
|