@akagilnc/pi-workflow-roles 0.1.2521 → 0.1.2653-next.71811ca
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 +129 -39
- package/README.zh-CN.md +128 -39
- package/dist/activation-ledger-topology.js +1 -1
- package/dist/archivist-record-entry.js +47 -26
- package/dist/auditor-dossier-tool.js +3 -1
- package/dist/compliance-transport.js +17 -26
- package/dist/doctor-contracts.js +1 -2
- package/dist/dossier-resolution.js +4 -8
- package/dist/engine-detour-tool.js +33 -8
- package/dist/engine-detour.js +1 -0
- package/dist/evidence-child-executor.js +277 -424
- package/dist/host-contracts.js +22 -0
- package/dist/institutional-resolution.js +88 -0
- package/dist/merger-contracts.js +1 -2
- package/dist/navigator-attendance.js +16 -0
- package/dist/notary-contracts.js +2 -3
- package/dist/package-contracts/fixer-output.js +1 -2
- package/dist/packaged-role-registry.js +102 -9
- package/dist/pi/in-process-session.js +671 -0
- package/dist/public-cli/config.js +7 -5
- package/dist/public-cli/main.js +3767 -4113
- package/dist/reviewer-child-executor.js +6 -1
- package/dist/session-opening-materials.js +10 -38
- package/dist/sitian-appender.js +146 -0
- package/dist/sitian-contracts.js +21 -0
- package/dist/sitian-facade.js +15 -0
- package/dist/sitian-reader.js +52 -0
- package/extensions/role-runtime.ts +9 -7
- package/package.json +5 -5
- package/resources/engines/cursor.md +12 -26
- package/resources/engines/hermes.md +2 -23
- package/resources/engines/opus.md +1 -16
- package/resources/navigator-route-playbook.md +2 -2
- package/scripts/build-package.mjs +0 -1
- package/souls/quality-law.md +1 -1
- package/src/activation-ledger-topology.ts +1 -1
- package/src/archivist-record-entry.ts +57 -45
- package/src/auditor-dossier-tool.ts +4 -2
- package/src/canonical-skill-binding.ts +37 -27
- package/src/collector-role.ts +11 -20
- package/src/collector-tool-schemas.ts +1 -4
- package/src/compliance-transport.ts +19 -44
- package/src/doctor-auditor.ts +1 -5
- package/src/doctor-contracts.ts +1 -4
- package/src/doctor-role.ts +31 -8
- package/src/dossier-resolution.ts +8 -8
- package/src/engine-detour-tool.ts +48 -19
- package/src/engine-detour.ts +3 -0
- package/src/evidence-child-executor.ts +277 -485
- package/src/factory-board.ts +3 -3
- package/src/gatekeeper-role.ts +21 -10
- package/src/host-contracts.ts +386 -0
- package/src/in-process-session.ts +1 -115
- package/src/institutional-resolution.ts +135 -0
- package/src/judge-auditor.ts +1 -5
- package/src/judge-role.ts +37 -51
- package/src/merger-contracts.ts +1 -4
- package/src/merger-role.ts +7 -11
- package/src/navigator-attendance.ts +20 -1
- package/src/notary-contracts.ts +8 -11
- package/src/notary-role.ts +7 -23
- package/src/notary-source-run.ts +4 -3
- package/src/package-contracts/fixer-output.ts +1 -4
- package/src/package-resources/method-skill-binding.ts +10 -34
- package/src/packaged-role-registry.ts +122 -12
- package/src/pi/adapter.ts +192 -0
- package/src/pi/durable-principal.ts +98 -0
- package/src/pi/in-process-session.ts +819 -0
- package/src/pi/known-failure.ts +77 -0
- package/src/pi/pi-normalization.ts +284 -0
- package/src/pi/role-turn-host.ts +459 -0
- package/src/public-cli/auto-resume.ts +42 -44
- package/src/public-cli/cli.ts +171 -257
- package/src/public-cli/coder-run.ts +115 -433
- package/src/public-cli/collector-run.ts +62 -314
- package/src/public-cli/config.ts +7 -5
- package/src/public-cli/doctor-run.ts +41 -52
- package/src/public-cli/fixer-run.ts +122 -427
- package/src/public-cli/invocation.ts +287 -96
- package/src/public-cli/judge-run.ts +92 -422
- package/src/public-cli/merger-run.ts +167 -429
- package/src/public-cli/notary-run.ts +41 -47
- package/src/public-cli/option-definitions.ts +136 -3
- package/src/public-cli/post-admission.ts +497 -0
- package/src/public-cli/public-run-credentials.ts +4 -4
- package/src/public-cli/reviewer-dispatch-rejection.ts +106 -0
- package/src/public-cli/reviewer-run.ts +132 -449
- package/src/public-cli/run-lifecycle.ts +339 -327
- package/src/public-cli/settlement.ts +251 -134
- package/src/public-cli/terminal.ts +3 -9
- package/src/public-cli/turn-request.ts +87 -0
- package/src/reviewer-child-executor.ts +9 -1
- package/src/reviewer-role.ts +11 -20
- package/src/role-runtime.ts +129 -78
- package/src/session-opening-materials.ts +25 -39
- package/src/sitian-appender.ts +171 -0
- package/src/sitian-contracts.ts +106 -0
- package/src/sitian-facade.ts +18 -0
- package/src/sitian-reader.ts +62 -0
- package/src/worker-role.ts +42 -40
- package/src/worker-submission-gates.ts +33 -0
- package/dist/archivist-role-run-coordinates.js +0 -28
- package/dist/package-contracts/terminating-infrastructure.js +0 -90
- package/resources/engines/sonnet.md +0 -27
- package/resources/engines/zcode.md +0 -63
- package/src/archivist-role-run-coordinates.ts +0 -45
- package/src/package-contracts/terminating-infrastructure.ts +0 -132
- package/src/public-cli/explicit-internal.ts +0 -427
- package/src/public-cli/one-shot-dispatch.ts +0 -300
|
@@ -15,7 +15,12 @@ export function projectSharedChildFailure(error) {
|
|
|
15
15
|
/** Reviewer policy adapter over the shared evidence-child lifecycle seam. */
|
|
16
16
|
export async function executeReviewerChild(workspace, leg, context, options = {}) {
|
|
17
17
|
try {
|
|
18
|
-
return await executeEvidenceChild(workspace, leg.prompt, context,
|
|
18
|
+
return await executeEvidenceChild(workspace, leg.prompt, context, {
|
|
19
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
20
|
+
...(options.credentialScratchParent === undefined ? {} : { credentialScratchParent: options.credentialScratchParent }),
|
|
21
|
+
...(options.runDirectory === undefined ? {} : { runDirectory: options.runDirectory }),
|
|
22
|
+
...(options.packageRoot === undefined ? {} : { packageRoot: options.packageRoot }),
|
|
23
|
+
});
|
|
19
24
|
}
|
|
20
25
|
catch (error) {
|
|
21
26
|
throw projectSharedChildFailure(error);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Session opening materials (#443)
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* main roles and gatekeeper family share joinPackageMaterials here.
|
|
2
|
+
* Session opening materials (#443 / #524). Missing files fail as native readFile
|
|
3
|
+
* errors. Main-role materials derive from PUBLIC_ROLE_RECORDS; gatekeeper seats
|
|
4
|
+
* stay independent except notary (shared NOTARY_SESSION_MATERIALS). Navigator is
|
|
5
|
+
* name-only here, not a public role record. Auditor composition stays in
|
|
6
|
+
* loadAuditorSoul; loaders share joinPackageMaterials.
|
|
8
7
|
*/
|
|
9
8
|
import { readFile } from "node:fs/promises";
|
|
10
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { NOTARY_SESSION_MATERIALS, PUBLIC_ROLE_RECORDS, } from "./packaged-role-registry.js";
|
|
11
11
|
const packageRootUrl = new URL("..", import.meta.url);
|
|
12
12
|
/** Self-locate one package-relative material. Native I/O errors propagate. */
|
|
13
13
|
export async function readPackageMaterial(relativePath) {
|
|
@@ -21,43 +21,15 @@ export async function joinPackageMaterials(relativePaths) {
|
|
|
21
21
|
}
|
|
22
22
|
return chunks.join("\n\n");
|
|
23
23
|
}
|
|
24
|
-
/**
|
|
24
|
+
/** Derived projection: public records + navigator name-only materials. */
|
|
25
25
|
export const MAIN_ROLE_SESSION_MATERIALS = {
|
|
26
|
-
|
|
27
|
-
"CLAUDE.md",
|
|
28
|
-
"souls/judge.md",
|
|
29
|
-
"souls/audit-law.md",
|
|
30
|
-
"souls/quality-law.md",
|
|
31
|
-
"souls/judge-output-guide.md",
|
|
32
|
-
],
|
|
33
|
-
fixer: [
|
|
34
|
-
"CLAUDE.md",
|
|
35
|
-
"souls/fixer.md",
|
|
36
|
-
"souls/quality-law.md",
|
|
37
|
-
"souls/fixer-output-guide.md",
|
|
38
|
-
],
|
|
39
|
-
coder: [
|
|
40
|
-
"CLAUDE.md",
|
|
41
|
-
"souls/coder.md",
|
|
42
|
-
"souls/quality-law.md",
|
|
43
|
-
"souls/coder-output-guide.md",
|
|
44
|
-
],
|
|
45
|
-
reviewer: [
|
|
46
|
-
"CLAUDE.md",
|
|
47
|
-
"souls/reviewer.md",
|
|
48
|
-
"souls/audit-law.md",
|
|
49
|
-
"souls/quality-law.md",
|
|
50
|
-
],
|
|
51
|
-
collector: ["CLAUDE.md", "souls/collector.md"],
|
|
52
|
-
doctor: ["CLAUDE.md", "souls/doctor.md"],
|
|
53
|
-
merger: ["CLAUDE.md", "souls/merger.md"],
|
|
54
|
-
notary: ["CLAUDE.md", "souls/notary.md", "souls/gate-output-guide.md"],
|
|
26
|
+
...Object.fromEntries(PUBLIC_ROLE_RECORDS.map((record) => [record.role, record.sessionMaterials])),
|
|
55
27
|
navigator: ["CLAUDE.md", "souls/navigator.md"],
|
|
56
28
|
};
|
|
57
29
|
export function loadMainRoleSessionMaterials(role) {
|
|
58
30
|
return joinPackageMaterials(MAIN_ROLE_SESSION_MATERIALS[role]);
|
|
59
31
|
}
|
|
60
|
-
/** Gatekeeper province
|
|
32
|
+
/** Gatekeeper province; notary reuses the public notary materials definition. */
|
|
61
33
|
export const GATEKEEPER_SESSION_MATERIALS = {
|
|
62
34
|
gatekeeper: [
|
|
63
35
|
"CLAUDE.md",
|
|
@@ -71,7 +43,7 @@ export const GATEKEEPER_SESSION_MATERIALS = {
|
|
|
71
43
|
"souls/quality-law.md",
|
|
72
44
|
"souls/gate-output-guide.md",
|
|
73
45
|
],
|
|
74
|
-
notary:
|
|
46
|
+
notary: NOTARY_SESSION_MATERIALS,
|
|
75
47
|
};
|
|
76
48
|
export function loadGatekeeperSessionMaterials(role) {
|
|
77
49
|
return joinPackageMaterials(GATEKEEPER_SESSION_MATERIALS[role]);
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sitian Appender kernel (ADR 0065).
|
|
3
|
+
* Computes destination automatically from ledger topology without destination parameters.
|
|
4
|
+
* Owns volume open, torn-tail recovery, entry-level idempotency, and commit boundary.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
7
|
+
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
9
|
+
import { resolveBookKeyFromGit } from "./activation-ledger-git.js";
|
|
10
|
+
import { activationBookDirectory, ensureRealDirectoryTree, errorText, physicallyContainedIn, resolveActivationLedgerHome, } from "./activation-ledger-topology.js";
|
|
11
|
+
import { SitianInfrastructureError, } from "./sitian-contracts.js";
|
|
12
|
+
function isRecord(value) {
|
|
13
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
/** Authorized S4 submission ledger kinds that share a common run submission volume. */
|
|
16
|
+
export const S4_SUBMISSION_LEDGER_KINDS = new Set([
|
|
17
|
+
"candidate",
|
|
18
|
+
"batchContext",
|
|
19
|
+
"outcome",
|
|
20
|
+
"sealed",
|
|
21
|
+
"post-seal-anomaly",
|
|
22
|
+
]);
|
|
23
|
+
/** Compute the volume partition key for directory placement. */
|
|
24
|
+
export function resolveSitianVolumeCategory(kind) {
|
|
25
|
+
if (S4_SUBMISSION_LEDGER_KINDS.has(kind)) {
|
|
26
|
+
return "submission-ledger";
|
|
27
|
+
}
|
|
28
|
+
return kind;
|
|
29
|
+
}
|
|
30
|
+
function safeBookKey(cwd) {
|
|
31
|
+
try {
|
|
32
|
+
return resolveBookKeyFromGit(cwd);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return basename(resolve(cwd)) || "default";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Compute the destination directory and record file from ledger topology (ADR 0065). */
|
|
39
|
+
export function resolveSitianRecordPath(input) {
|
|
40
|
+
const cwd = input.cwd ?? process.cwd();
|
|
41
|
+
const ledgerHome = resolveActivationLedgerHome();
|
|
42
|
+
const category = resolveSitianVolumeCategory(input.kind);
|
|
43
|
+
let sessionDir;
|
|
44
|
+
if (input.sessionParent !== undefined && input.sessionParent.length > 0 && physicallyContainedIn(ledgerHome, input.sessionParent)) {
|
|
45
|
+
sessionDir = join(dirname(input.sessionParent), category);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const bookKey = safeBookKey(cwd);
|
|
49
|
+
const bookDir = activationBookDirectory(ledgerHome, bookKey);
|
|
50
|
+
if (input.subject !== undefined) {
|
|
51
|
+
let subjectStr;
|
|
52
|
+
if (typeof input.subject === "string") {
|
|
53
|
+
subjectStr = input.subject;
|
|
54
|
+
}
|
|
55
|
+
else if (typeof input.subject.runId === "string" && input.subject.runId.length > 0) {
|
|
56
|
+
subjectStr = input.subject.runId;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
subjectStr = JSON.stringify(input.subject);
|
|
60
|
+
}
|
|
61
|
+
const digest = createHash("sha256").update(subjectStr).digest("hex").slice(0, 32);
|
|
62
|
+
sessionDir = join(bookDir, category, digest);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
sessionDir = join(bookDir, category);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const recordFile = join(sessionDir, "records.jsonl");
|
|
69
|
+
return { sessionDir, recordFile, ledgerHome };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Appends a canonical record to its self-computed volume under the Sitian contract.
|
|
73
|
+
* - Idempotency: checks volume by deterministic canonical identity; returns existing pointer on hit.
|
|
74
|
+
* - Torn-tail recovery: checks file tail; un-terminated trailing bytes are sealed with a newline and re-parsed.
|
|
75
|
+
* Substate a (valid JSON): committed on recovery, returns existing pointer.
|
|
76
|
+
* Substate b (malformed): preserved as bad line, check misses, appends new row.
|
|
77
|
+
* - Commit point: full JSON string ending with newline.
|
|
78
|
+
*/
|
|
79
|
+
export function appendSitianRecord(input) {
|
|
80
|
+
try {
|
|
81
|
+
const { sessionDir, recordFile, ledgerHome } = resolveSitianRecordPath(input);
|
|
82
|
+
ensureRealDirectoryTree(ledgerHome, sessionDir);
|
|
83
|
+
const identity = input.identity ?? randomUUID();
|
|
84
|
+
const timestamp = input.timestamp ?? new Date().toISOString();
|
|
85
|
+
const host = input.host ?? "pi";
|
|
86
|
+
const record = {
|
|
87
|
+
level: input.level,
|
|
88
|
+
kind: input.kind,
|
|
89
|
+
identity,
|
|
90
|
+
...(input.subject === undefined ? {} : { subject: input.subject }),
|
|
91
|
+
...(input.sessionParent === undefined ? {} : { sessionParent: input.sessionParent }),
|
|
92
|
+
...(input.priorEventId === undefined ? {} : { priorEventId: input.priorEventId }),
|
|
93
|
+
timestamp,
|
|
94
|
+
host,
|
|
95
|
+
...(input.source === undefined ? {} : { source: input.source }),
|
|
96
|
+
...(input.payload === undefined ? {} : { payload: input.payload }),
|
|
97
|
+
...(input.raw === undefined ? {} : { raw: input.raw }),
|
|
98
|
+
...(input.usage === undefined ? {} : { usage: input.usage }),
|
|
99
|
+
};
|
|
100
|
+
if (existsSync(recordFile)) {
|
|
101
|
+
const buffer = readFileSync(recordFile);
|
|
102
|
+
if (buffer.length > 0) {
|
|
103
|
+
// Torn-tail check: if last byte is not newline, seal the fragment with \n
|
|
104
|
+
if (buffer[buffer.length - 1] !== 0x0a) {
|
|
105
|
+
appendFileSync(recordFile, "\n", "utf8");
|
|
106
|
+
}
|
|
107
|
+
// Self-check volume by canonical identity
|
|
108
|
+
const text = readFileSync(recordFile, "utf8");
|
|
109
|
+
for (const line of text.split("\n")) {
|
|
110
|
+
const trimmed = line.trim();
|
|
111
|
+
if (!trimmed)
|
|
112
|
+
continue;
|
|
113
|
+
try {
|
|
114
|
+
const parsed = JSON.parse(trimmed);
|
|
115
|
+
if (isRecord(parsed) && parsed.identity === identity) {
|
|
116
|
+
// Existing record found (or substate a recovered record) -> return existing pointer
|
|
117
|
+
return {
|
|
118
|
+
identity,
|
|
119
|
+
recordFile,
|
|
120
|
+
kind: record.kind,
|
|
121
|
+
level: record.level,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Malformed lines (including substate b preserved bad lines) are ignored during self-check
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Not found -> append new canonical row terminating with newline
|
|
132
|
+
const row = `${JSON.stringify(record)}\n`;
|
|
133
|
+
appendFileSync(recordFile, row, "utf8");
|
|
134
|
+
return {
|
|
135
|
+
identity,
|
|
136
|
+
recordFile,
|
|
137
|
+
kind: record.kind,
|
|
138
|
+
level: record.level,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (error instanceof SitianInfrastructureError)
|
|
143
|
+
throw error;
|
|
144
|
+
throw new SitianInfrastructureError(`Sitian appender persistence failure: ${errorText(error)}`, { cause: error });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sitian (司天台) canonical contracts, Layout schema, and pointer definitions.
|
|
3
|
+
* ADR 0065 single record entry + ADR 0068 Taishi analysis.
|
|
4
|
+
*/
|
|
5
|
+
/** Lift direct-cause fs errno onto a wrap error (no chain walk). */
|
|
6
|
+
export function attachDirectErrnoCode(error, cause) {
|
|
7
|
+
if (cause === null || typeof cause !== "object" || !("code" in cause))
|
|
8
|
+
return;
|
|
9
|
+
const code = cause.code;
|
|
10
|
+
if (typeof code === "string")
|
|
11
|
+
error.code = code;
|
|
12
|
+
}
|
|
13
|
+
/** Typed infrastructure error for real ledger persistence / IO failures. */
|
|
14
|
+
export class SitianInfrastructureError extends Error {
|
|
15
|
+
knownCause = "session";
|
|
16
|
+
constructor(message, options) {
|
|
17
|
+
super(message, options);
|
|
18
|
+
this.name = "SitianInfrastructureError";
|
|
19
|
+
attachDirectErrnoCode(this, options?.cause);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sitian Facade (司天门面) — Sole entrypoint for record reporting across all producers.
|
|
3
|
+
* ADR 0065 single record entry, #520 r8.
|
|
4
|
+
*/
|
|
5
|
+
import { appendSitianRecord } from "./sitian-appender.js";
|
|
6
|
+
export * from "./sitian-contracts.js";
|
|
7
|
+
export * from "./sitian-appender.js";
|
|
8
|
+
export * from "./sitian-reader.js";
|
|
9
|
+
/**
|
|
10
|
+
* Sole write API for Sitian canonical records.
|
|
11
|
+
* Returns typed RecordPointer with durable record identity and readable file location.
|
|
12
|
+
*/
|
|
13
|
+
export function sitianReport(input) {
|
|
14
|
+
return appendSitianRecord(input);
|
|
15
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sitian Reader kernel (ADR 0068 / #520 r8).
|
|
3
|
+
* Sole authoritative read path for canonical Sitian records.
|
|
4
|
+
* Traversal contract:
|
|
5
|
+
* - Malformed lines are exposed as typed malformed diagnostics and traversal continues.
|
|
6
|
+
* - Zero whitewashing, zero deduplication.
|
|
7
|
+
* - Canonical rows after malformed lines are always reachable.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { readFile } from "node:fs/promises";
|
|
11
|
+
function isRecord(value) {
|
|
12
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
/** Read a Sitian record volume with full traversal and non-destructive diagnostics. */
|
|
15
|
+
export async function readSitianRecords(recordFile) {
|
|
16
|
+
if (!existsSync(recordFile)) {
|
|
17
|
+
return { records: [], diagnostics: [] };
|
|
18
|
+
}
|
|
19
|
+
const text = await readFile(recordFile, "utf8");
|
|
20
|
+
const lines = text.split("\n");
|
|
21
|
+
const records = [];
|
|
22
|
+
const diagnostics = [];
|
|
23
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
24
|
+
const line = lines[index];
|
|
25
|
+
if (!line.trim())
|
|
26
|
+
continue;
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(line);
|
|
29
|
+
if (isRecord(parsed)) {
|
|
30
|
+
records.push(parsed);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const typeDesc = parsed === null ? "null" : Array.isArray(parsed) ? "array" : typeof parsed;
|
|
34
|
+
diagnostics.push({
|
|
35
|
+
kind: "malformed",
|
|
36
|
+
line: index + 1,
|
|
37
|
+
raw: line,
|
|
38
|
+
error: `expected JSON object, got ${typeDesc}`,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
diagnostics.push({
|
|
44
|
+
kind: "malformed",
|
|
45
|
+
line: index + 1,
|
|
46
|
+
raw: line,
|
|
47
|
+
error: error instanceof Error ? error.message : String(error),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { records, diagnostics };
|
|
52
|
+
}
|
|
@@ -4,6 +4,7 @@ import { resolve } from "node:path";
|
|
|
4
4
|
|
|
5
5
|
import { loadDoctorCase } from "../src/doctor-evidence.ts";
|
|
6
6
|
import { loadNotarySourceRunLocator } from "../src/notary-source-run.ts";
|
|
7
|
+
import { createPiRoleHostAdapter, toPiContext } from "../src/pi/adapter.ts";
|
|
7
8
|
import { loadAdmittedJudgeRequest } from "../src/public-cli/invocation.ts";
|
|
8
9
|
|
|
9
10
|
import {
|
|
@@ -243,6 +244,7 @@ export async function loadNavigatorWorkContext(
|
|
|
243
244
|
|
|
244
245
|
export default function roleRuntime(pi: ExtensionAPI): void {
|
|
245
246
|
const reviewerAgent = createReviewerAgentRunner({ packageRoot });
|
|
247
|
+
const piHostAdapter = createPiRoleHostAdapter(pi, { transcriptFromContext });
|
|
246
248
|
registerNavigatorModelCommand(pi);
|
|
247
249
|
const navigatorSessionFactory = createNativeNavigatorSessionFactory();
|
|
248
250
|
// #351: static provider list from extension setting (default ["kimi-coding"]).
|
|
@@ -263,13 +265,13 @@ export default function roleRuntime(pi: ExtensionAPI): void {
|
|
|
263
265
|
collectorPackageExtensionPath: extensionPath,
|
|
264
266
|
loadDoctorSoul: () => loadMainRoleSessionMaterials("doctor"),
|
|
265
267
|
loadDoctorCase,
|
|
266
|
-
auditDoctorCompliance: createPiDoctorAuditor(),
|
|
268
|
+
auditDoctorCompliance: (options) => createPiDoctorAuditor()({ ...options, context: toPiContext(options.context) }),
|
|
267
269
|
loadNotarySoul: () => loadMainRoleSessionMaterials("notary"),
|
|
268
270
|
loadNotarySourceRun: loadNotarySourceRunLocator,
|
|
269
|
-
loadNavigatorWorkContext: (options) => loadNavigatorWorkContext(pi, options),
|
|
271
|
+
loadNavigatorWorkContext: (options) => loadNavigatorWorkContext(pi, { ...options, context: toPiContext(options.context) }),
|
|
270
272
|
createNavigatorAttendance: (options) => {
|
|
271
273
|
return createNavigatorAttendance({
|
|
272
|
-
context: options.context,
|
|
274
|
+
context: toPiContext(options.context),
|
|
273
275
|
role: options.role,
|
|
274
276
|
phase: options.phase,
|
|
275
277
|
subjectKey: options.subjectKey,
|
|
@@ -301,9 +303,9 @@ export default function roleRuntime(pi: ExtensionAPI): void {
|
|
|
301
303
|
}
|
|
302
304
|
return loadHomeCanonicalSkillBinding(name);
|
|
303
305
|
},
|
|
304
|
-
runReviewerDispatch: (dispatch, options) => reviewerAgent.run(dispatch, options),
|
|
306
|
+
runReviewerDispatch: (dispatch, options) => reviewerAgent.run(dispatch, { ...options, context: toPiContext(options.context) }),
|
|
305
307
|
shutdownReviewerAgent: () => reviewerAgent.shutdown(),
|
|
306
|
-
transcriptFromContext,
|
|
307
|
-
auditSoulCompliance: createPiJudgeAuditor(),
|
|
308
|
-
})(pi);
|
|
308
|
+
transcriptFromContext: (context) => context.transcript?.() ?? "",
|
|
309
|
+
auditSoulCompliance: (options) => createPiJudgeAuditor()({ ...options, context: toPiContext(options.context) }),
|
|
310
|
+
}, piHostAdapter)(pi);
|
|
309
311
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akagilnc/pi-workflow-roles",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2653-next.71811ca",
|
|
4
4
|
"description": "Soul-bound workflow roles for Pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,11 +42,11 @@
|
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "tsx scripts/generate-tool-execution-observation-schema.ts && tsc -p tsconfig.build.json && node scripts/build-package.mjs",
|
|
44
44
|
"prepack": "npm run build",
|
|
45
|
-
"test": "node --import tsx --
|
|
46
|
-
"test:fast": "node --import tsx --
|
|
47
|
-
"test:integration": "node --import tsx --
|
|
45
|
+
"test": "node --import tsx --test test/unit/**/*.test.ts test/contract/**/*.test.ts",
|
|
46
|
+
"test:fast": "node --import tsx --test test/unit/**/*.test.ts test/contract/**/*.test.ts",
|
|
47
|
+
"test:integration": "node --import tsx --test test/unit/**/*.test.ts test/contract/**/*.test.ts test/integration/**/*.test.ts",
|
|
48
48
|
"test:all": "node scripts/run-test-all.mjs",
|
|
49
|
-
"test:adjudication": "node --import tsx --
|
|
49
|
+
"test:adjudication": "node --import tsx --test test/adjudication/**/*.test.ts",
|
|
50
50
|
"typecheck": "tsc --noEmit"
|
|
51
51
|
},
|
|
52
52
|
"pi": {
|
|
@@ -7,40 +7,26 @@ Before invoking the engine, read `../engine-dispatch.md`, resolving that path
|
|
|
7
7
|
relative to this note. This note only covers this engine's CLI technical
|
|
8
8
|
parameters.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Invocation examples (local Cursor Agent CLI)
|
|
11
11
|
|
|
12
|
-
The machine entrypoint is
|
|
13
|
-
|
|
14
|
-
→ grok 1.0.5, a different product billed to grok.com Build) — its flags
|
|
15
|
-
differ and it fails labor invocations (`--force` unknown; billing 402 when
|
|
16
|
-
the Grok Build balance is exhausted).
|
|
17
|
-
|
|
18
|
-
## Invocation (local Cursor Agent CLI)
|
|
19
|
-
|
|
20
|
-
Run from the role project root. Non-interactive print mode; `-f/--force`
|
|
21
|
-
allows command execution headlessly; `-p` prints responses for scripts:
|
|
12
|
+
The machine entrypoint is `agent` (also exposed as `cursor-agent`). Run from the
|
|
13
|
+
role project root. Non-interactive print mode:
|
|
22
14
|
|
|
23
15
|
```bash
|
|
24
|
-
|
|
16
|
+
agent -p --force --output-format text "YOUR_LABOR_PROMPT"
|
|
25
17
|
```
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
id itself (e.g. `cursor-grok-4.6-low`, `cursor-grok-4.6-medium`,
|
|
29
|
-
`cursor-grok-4.6-high`, plus `-fast` variants); some models also accept a
|
|
30
|
-
bracket override form (`'claude-opus-4-8[context=1m,effort=high]'` — see
|
|
31
|
-
`cursor-agent --help`).
|
|
32
|
-
- Owner pool directive 2026-08-28: default labor model = `cursor-grok-4.6-low`.
|
|
33
|
-
- Stream JSON events for long labor: `--output-format stream-json`.
|
|
19
|
+
Choose a model explicitly when the seat needs a known Cursor model id:
|
|
34
20
|
|
|
35
|
-
|
|
36
|
-
|
|
21
|
+
```bash
|
|
22
|
+
agent -p --force --model grok-4.5 --output-format text "YOUR_LABOR_PROMPT"
|
|
23
|
+
```
|
|
37
24
|
|
|
38
|
-
|
|
25
|
+
Stream JSON events for long labor:
|
|
39
26
|
|
|
40
27
|
```bash
|
|
41
|
-
|
|
28
|
+
agent -p --force --output-format stream-json "YOUR_LABOR_PROMPT"
|
|
42
29
|
```
|
|
43
30
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
`-f` flag (or `--trust`) is missing.
|
|
31
|
+
Prefer `agent --help` on the host over any remembered flag set. Do not wrap this
|
|
32
|
+
engine behind `ak-role` flags.
|
|
@@ -33,16 +33,8 @@ hermes -z "YOUR_LABOR_PROMPT" --in /path/to/project --no-restore-cwd \
|
|
|
33
33
|
- `--usage-file PATH` (works with `-z` only) writes a JSON spend report
|
|
34
34
|
(`estimated_cost_usd`, token counts, model, provider, `completed`/`failed`)
|
|
35
35
|
**even when the run fails** — attach it to the leg's receipt for accounting.
|
|
36
|
-
- Long prompts
|
|
37
|
-
|
|
38
|
-
result is one argv entry; file content is not re-parsed by the shell.
|
|
39
|
-
Smoke-verified 2026-08-28: clean final-response-only stdout.
|
|
40
|
-
- `--query-file PATH` belongs to the `hermes chat` subcommand only (mutually
|
|
41
|
-
exclusive with its `-q`); it is NOT a top-level flag and does NOT combine
|
|
42
|
-
with `-z` — `hermes -z --query-file ...` fails with
|
|
43
|
-
`-z/--oneshot: expected one argument` (incident: Ming #1585 fixer leg,
|
|
44
|
-
2026-08-28). `hermes chat --query-file` also prints a session summary
|
|
45
|
-
instead of the bare final response, so it is unfit for labor pipelines.
|
|
36
|
+
- Long or untrusted prompts: `--query-file PATH` reads the prompt from a file
|
|
37
|
+
verbatim ("nothing is shell-interpreted"); mutually exclusive with `-q`.
|
|
46
38
|
- Model/provider default comes from host `~/.hermes/config.yaml`
|
|
47
39
|
(owner-selected; verified 2026-08-28: `poolside/laguna-s-2.1:free` on Nous
|
|
48
40
|
Portal). Override with `-m provider/model` + `--provider` only when the
|
|
@@ -58,23 +50,10 @@ hermes -z "YOUR_LABOR_PROMPT" --in /path/to/project --no-restore-cwd \
|
|
|
58
50
|
intermediate steps on stdout (unlike `-z`) — use when a labor run needs its
|
|
59
51
|
steps inspected.
|
|
60
52
|
|
|
61
|
-
## Measured constraints (host, 2026-08-28)
|
|
62
|
-
|
|
63
|
-
- The Nous free tier (`poolside/laguna-s-2.1:free`) rate-limits concurrent
|
|
64
|
-
labor calls on one account. Measured: with ~5 factory legs dispatching
|
|
65
|
-
simultaneously, losing legs saw sustained HTTP 429 across 9-29 detour
|
|
66
|
-
attempts while the 1-2 winners completed normally (Ming_LLM books runs
|
|
67
|
-
01a046ec-*/01a046f4-*, 14:55-15:04 window).
|
|
68
|
-
No concurrency ceiling has been measured beyond this observation; policy on
|
|
69
|
-
concurrency and retries is the dispatcher's call, not this note's.
|
|
70
|
-
|
|
71
53
|
## Smoke test (run before first labor leg of a session)
|
|
72
54
|
|
|
73
55
|
```bash
|
|
74
56
|
hermes -z "Reply with exactly one word: OK" --no-restore-cwd
|
|
75
|
-
# long-prompt form used by labor legs:
|
|
76
|
-
printf 'Reply with exactly one word: OK' > /tmp/smoke.txt
|
|
77
|
-
hermes -z "$(cat /tmp/smoke.txt)" --no-restore-cwd
|
|
78
57
|
```
|
|
79
58
|
|
|
80
59
|
Expected: stdout is exactly `OK`, exit code 0. Verified 2026-08-28 on this
|
|
@@ -18,12 +18,7 @@ requires `--verbose` — without it the CLI exits immediately with
|
|
|
18
18
|
Include `--verbose` in stream-json argv. Measured with separate fd redirects
|
|
19
19
|
(`1>` / `2>`): NDJSON event rows land on stdout (including intermediate
|
|
20
20
|
`system` / `assistant` activity and a final `type:"result"` row); stderr is
|
|
21
|
-
empty on the success path
|
|
22
|
-
data (e.g. a shell test without redirection): then a benign
|
|
23
|
-
`Warning: no stdin data received in 3s, proceeding without it` lands on stderr
|
|
24
|
-
after a 3-second wait (host-verified 2026-08-28); redirect `< /dev/null` in
|
|
25
|
-
shell tests. The packaged detour tool spawns engines with stdin ignored
|
|
26
|
-
(`/dev/null`), which avoids this path:
|
|
21
|
+
empty on the success path:
|
|
27
22
|
|
|
28
23
|
```bash
|
|
29
24
|
claude -p --verbose --output-format=stream-json "YOUR_LABOR_PROMPT"
|
|
@@ -41,15 +36,5 @@ Use `--output-format=stream-json` (choices measured on this host: `text`, `json`
|
|
|
41
36
|
works; take the labor body from the final `result` event's `result` field,
|
|
42
37
|
not from intermediate stream rows.
|
|
43
38
|
|
|
44
|
-
## Headless permissions
|
|
45
|
-
|
|
46
|
-
`--dangerously-skip-permissions` is required in headless labor: the CLI's
|
|
47
|
-
permission prompts cannot be answered without a TTY and are auto-denied. In
|
|
48
|
-
particular, reading any path outside the project root — such as frozen
|
|
49
|
-
attachments under `~/.ak-roles/books/<book>/runs/<run>/attachments/` — is
|
|
50
|
-
refused without the flag ("The read was not permitted — I don't have access to
|
|
51
|
-
that file outside the current worktree") and succeeds with it (host-verified
|
|
52
|
-
2026-08-28, both directions).
|
|
53
|
-
|
|
54
39
|
Prefer `claude --help` on the host over any remembered flag set. Do not wrap this
|
|
55
40
|
engine behind `ak-role` flags.
|
package/souls/quality-law.md
CHANGED
|
@@ -28,7 +28,7 @@ export class ActivationLedgerError extends Error {
|
|
|
28
28
|
* homes would split the family and can write into a consumer repository.
|
|
29
29
|
* Process home must already be absolute; relative HOME is rejected before any write.
|
|
30
30
|
*/
|
|
31
|
-
export function resolveActivationLedgerHome(home: () => string = homedir): string {
|
|
31
|
+
export function resolveActivationLedgerHome(home: () => string = () => process.env.HOME ?? homedir()): string {
|
|
32
32
|
const processHome = home();
|
|
33
33
|
if (typeof processHome !== "string" || processHome.length === 0 || !isAbsolute(processHome)) {
|
|
34
34
|
throw new ActivationLedgerError(
|