@akagilnc/pi-workflow-roles 0.1.4800 → 0.1.4870
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 +19434 -18218
- package/dist/analyst-book-key.js +63 -0
- package/dist/analyst-cohort.js +167 -0
- package/dist/analyst-entry.js +320 -0
- package/dist/analyst-index.js +247 -0
- package/dist/analyst-ledger.js +561 -0
- package/dist/analyst-median.js +16 -0
- package/dist/analyst-metric-families/acceptance-success-rework.js +249 -0
- package/dist/analyst-metric-families/b2-frame-buckets-actions.js +189 -0
- package/dist/analyst-metric-families/gate-cycles.js +77 -0
- package/dist/analyst-metric-families/leg-wall-clock.js +56 -0
- package/dist/analyst-metric-families/round-timeline.js +126 -0
- package/dist/analyst-metric-families.js +23 -0
- package/dist/analyst-metric-family.js +11 -0
- package/dist/analyst-model-groups.js +135 -0
- package/dist/analyst-page.js +182 -0
- package/dist/atomic-write.js +23 -0
- package/dist/auditor-soul.js +1 -1
- package/dist/countersign-contracts.js +0 -2
- package/dist/diarist-contracts.js +0 -1
- package/dist/doctor-contracts.js +2 -2
- package/dist/gatekeeper-role.js +15 -16
- package/dist/gleaner-left-contracts.js +0 -2
- package/dist/headless-host/production-host.js +16967 -15749
- package/dist/host-contracts.js +0 -4
- package/dist/inspector-contracts.js +0 -2
- package/dist/institutional-resolution.js +4 -2
- package/dist/merger-contracts.js +0 -2
- package/dist/migrate-book-topology.js +3908 -3089
- package/dist/navigator-public-session.js +4 -3
- package/dist/notary-contracts.js +0 -2
- package/dist/package-contracts/auditor-output.js +0 -1
- package/dist/package-contracts/collector-output.js +0 -2
- package/dist/package-contracts/fixer-output.js +0 -2
- package/dist/package-contracts/gatekeeper-output.js +0 -2
- package/dist/package-contracts/judge-output.js +0 -2
- package/dist/package-contracts/navigator-output.js +0 -2
- package/dist/package-contracts/reviewer-output.js +0 -2
- package/dist/package-contracts/terminating-tools.js +32 -92
- package/dist/package-contracts/worker-output.js +0 -4
- package/dist/packaged-role-registry.js +518 -36
- package/dist/pi/role-turn-host.js +2 -1
- package/dist/public-cli/analyst-run.js +185 -0
- package/dist/public-cli/cli.js +885 -0
- package/dist/public-cli/config.js +12 -9
- package/dist/public-cli/countersign-run.js +4 -311
- package/dist/public-cli/instruction-seat-run.js +628 -158
- package/dist/public-cli/invocation.js +806 -1550
- package/dist/public-cli/main.js +6962 -9882
- package/dist/public-cli/option-definitions.js +51 -99
- package/dist/public-cli/post-admission.js +30 -2
- package/dist/public-cli/run-lifecycle.js +234 -353
- package/dist/public-cli/seat-ticket-binding.js +6 -0
- package/dist/public-cli/settlement.js +261 -675
- package/dist/public-cli/turn-request.js +76 -0
- package/dist/public-role-summons.js +38 -112
- package/dist/role-activation-flags.js +23 -45
- package/dist/secretariat-contracts.js +0 -2
- package/dist/session-identity.js +17 -8
- package/dist/session-opening-materials.js +3 -2
- package/extensions/role-runtime.ts +6 -80
- package/package.json +1 -1
- package/souls/coder.md +1 -2
- package/src/acp-host/role-turn-host.ts +4 -1
- package/src/analyst-metric-families/acceptance-success-rework.ts +3 -2
- package/src/auditor-role.ts +1 -2
- package/src/auditor-soul.ts +1 -1
- package/src/collector-role.ts +2 -2
- package/src/countersign-contracts.ts +0 -1
- package/src/countersign-role.ts +1 -1
- package/src/diarist-contracts.ts +0 -1
- package/src/diarist-role.ts +0 -1
- package/src/doctor-auditor.ts +1 -2
- package/src/doctor-contracts.ts +1 -1
- package/src/doctor-role.ts +3 -2
- package/src/external-host-turn-loop.ts +1 -1
- package/src/factory-board.ts +10 -7
- package/src/gatekeeper-role.ts +16 -10
- package/src/gleaner-left-contracts.ts +0 -1
- package/src/gleaner-left-role.ts +0 -1
- package/src/headless-host/role-turn-host.ts +7 -1
- package/src/host-contracts.ts +10 -6
- package/src/inspector-contracts.ts +0 -1
- package/src/inspector-role.ts +0 -2
- package/src/institutional-resolution.ts +6 -4
- package/src/judge-role.ts +3 -3
- package/src/merger-contracts.ts +0 -1
- package/src/merger-role.ts +2 -2
- package/src/navigator-public-session.ts +7 -6
- package/src/navigator-work-context.ts +6 -8
- package/src/notary-contracts.ts +0 -1
- package/src/notary-role.ts +2 -3
- package/src/package-contracts/auditor-output.ts +0 -1
- package/src/package-contracts/collector-output.ts +0 -1
- package/src/package-contracts/fixer-output.ts +0 -1
- package/src/package-contracts/gatekeeper-output.ts +0 -1
- package/src/package-contracts/judge-output.ts +0 -1
- package/src/package-contracts/navigator-output.ts +0 -1
- package/src/package-contracts/reviewer-output.ts +0 -1
- package/src/package-contracts/terminating-tools.ts +27 -99
- package/src/package-contracts/worker-output.ts +0 -2
- package/src/packaged-role-registry.ts +604 -35
- package/src/pi/role-turn-host.ts +2 -1
- package/src/public-cli/cli.ts +64 -259
- package/src/public-cli/config.ts +18 -10
- package/src/public-cli/countersign-run.ts +14 -449
- package/src/public-cli/instruction-seat-run.ts +758 -277
- package/src/public-cli/invocation.ts +1097 -2051
- package/src/public-cli/option-definitions.ts +62 -127
- package/src/public-cli/post-admission.ts +47 -2
- package/src/public-cli/run-lifecycle.ts +303 -613
- package/src/public-cli/seat-ticket-binding.ts +6 -0
- package/src/public-cli/settlement.ts +399 -1185
- package/src/public-cli/turn-request.ts +92 -1
- package/src/public-role-summons.ts +44 -128
- package/src/reviewer-role.ts +3 -2
- package/src/role-activation-flags.ts +20 -41
- package/src/role-runtime-dependencies.ts +25 -26
- package/src/role-runtime.ts +121 -232
- package/src/secretariat-contracts.ts +0 -1
- package/src/secretariat-role.ts +0 -2
- package/src/session-identity.ts +23 -8
- package/src/session-opening-materials.ts +2 -1
- package/src/worker-role.ts +3 -4
- package/dist/doctor-auditor.js +0 -25
- package/dist/public-cli/diarist-run.js +0 -130
- package/dist/public-cli/doctor-run.js +0 -87
- package/dist/public-cli/inspector-run.js +0 -151
- package/dist/public-cli/judge-run.js +0 -114
- package/dist/public-cli/notary-run.js +0 -174
- package/dist/public-cli/reviewer-run.js +0 -339
- package/src/public-cli/coder-run.ts +0 -255
- package/src/public-cli/collector-run.ts +0 -189
- package/src/public-cli/diarist-run.ts +0 -233
- package/src/public-cli/doctor-run.ts +0 -167
- package/src/public-cli/fixer-run.ts +0 -265
- package/src/public-cli/gleaner-left-run.ts +0 -167
- package/src/public-cli/inspector-run.ts +0 -261
- package/src/public-cli/judge-run.ts +0 -196
- package/src/public-cli/merger-run.ts +0 -294
- package/src/public-cli/notary-run.ts +0 -279
- package/src/public-cli/reviewer-run.ts +0 -480
- package/src/public-cli/secretariat-run.ts +0 -265
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyst library index page (ADR 0068 / PRD #298 output ②).
|
|
3
|
+
*
|
|
4
|
+
* Sweep mode maintains one self-sufficient row per issue:
|
|
5
|
+
* 完全耗时 / 排除后改动行数 / 耗时每千行 / 末次活动时间戳.
|
|
6
|
+
* Rows carry their own sort keys — readers choose order (Story 6/8).
|
|
7
|
+
*
|
|
8
|
+
* #399 D9: retained solely for cohort (and sweep producers that feed it).
|
|
9
|
+
* Ticket CLI query path must not read this index (no bootstrap prerequisite).
|
|
10
|
+
* Row address includes book identity so cross-book same ticket numbers do not merge (D5).
|
|
11
|
+
* C2 joins cohort groups by (bookKey, issueNumber) → page reference. Missing row =
|
|
12
|
+
* typed vacancy entry — never silent skip, never live recompute.
|
|
13
|
+
* #412: bare cohort issue numbers resolve inside one book; no cross-book silent find.
|
|
14
|
+
* Legacy rows lacking bookKey heal via the single shared projectRoot→bookKey rule
|
|
15
|
+
* (git common-dir when resolvable, else `root:<identity>`) on read/ingest (F1/F3).
|
|
16
|
+
*
|
|
17
|
+
* Multi-process issue/sweep writers coordinate the whole read→upsert→write
|
|
18
|
+
* on one exclusive lock next to the index (atomic rename still prevents torn
|
|
19
|
+
* JSON; the lock prevents lost-update across concurrent CLI processes).
|
|
20
|
+
*/
|
|
21
|
+
import { open, readFile, unlink } from "node:fs/promises";
|
|
22
|
+
import { dirname, join } from "node:path";
|
|
23
|
+
import { writeFileAtomically } from "./atomic-write.js";
|
|
24
|
+
import { assertLedgerFileInsideHome, ensureRealDirectoryTree, physicalPathIdentity, } from "./activation-ledger-topology.js";
|
|
25
|
+
import { resolveAnalystBookKey } from "./analyst-book-key.js";
|
|
26
|
+
const LIBRARY_INDEX_LOCK_NAME = ".library-index.lock";
|
|
27
|
+
const LIBRARY_INDEX_LOCK_TIMEOUT_MS = 30_000;
|
|
28
|
+
const LIBRARY_INDEX_LOCK_RETRY_MS = 15;
|
|
29
|
+
function sleep(ms) {
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
setTimeout(resolve, ms);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Exclusive create lock for the library-index read→upsert→write critical section.
|
|
36
|
+
* Same-directory sibling of the index file; not a second index and not a daemon.
|
|
37
|
+
*/
|
|
38
|
+
async function withAnalystLibraryIndexLock(ledgerHome, fn) {
|
|
39
|
+
const indexPath = analystLibraryIndexPath(ledgerHome);
|
|
40
|
+
ensureRealDirectoryTree(ledgerHome, dirname(indexPath));
|
|
41
|
+
const lockPath = join(dirname(indexPath), LIBRARY_INDEX_LOCK_NAME);
|
|
42
|
+
assertLedgerFileInsideHome(lockPath, ledgerHome);
|
|
43
|
+
const startedAt = Date.now();
|
|
44
|
+
while (true) {
|
|
45
|
+
try {
|
|
46
|
+
const handle = await open(lockPath, "wx");
|
|
47
|
+
try {
|
|
48
|
+
await handle.writeFile(`${process.pid}\n`, "utf8");
|
|
49
|
+
return await fn();
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
await handle.close().catch(() => undefined);
|
|
53
|
+
await unlink(lockPath).catch(() => undefined);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
const code = error instanceof Error && "code" in error
|
|
58
|
+
? error.code
|
|
59
|
+
: undefined;
|
|
60
|
+
if (code !== "EEXIST")
|
|
61
|
+
throw error;
|
|
62
|
+
if (Date.now() - startedAt > LIBRARY_INDEX_LOCK_TIMEOUT_MS) {
|
|
63
|
+
throw new Error(`analyst library-index lock timeout after ${LIBRARY_INDEX_LOCK_TIMEOUT_MS}ms: ${lockPath}`);
|
|
64
|
+
}
|
|
65
|
+
await sleep(LIBRARY_INDEX_LOCK_RETRY_MS);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function analystLibraryIndexPath(ledgerHome) {
|
|
70
|
+
return join(ledgerHome, "analyst", "library-index.json");
|
|
71
|
+
}
|
|
72
|
+
export function rowFromIssueMetricsPage(page) {
|
|
73
|
+
return {
|
|
74
|
+
bookKey: page.bookKey,
|
|
75
|
+
projectRoot: page.projectRoot,
|
|
76
|
+
// exactOptionalPropertyTypes: only materialize when page carries it.
|
|
77
|
+
...(page.issueNumber === undefined ? {} : { issueNumber: page.issueNumber }),
|
|
78
|
+
totalElapsedMs: page.totalElapsedMs,
|
|
79
|
+
changedLines: page.changedLines,
|
|
80
|
+
msPerKLines: page.msPerKLines,
|
|
81
|
+
lastActivityAt: page.lastActivityAt,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* #412 F1/F3: pre-#399 library-index rows omit bookKey. Heal with the single
|
|
86
|
+
* shared projectRoot→bookKey rule (#399 / ADR 0048) — the same rule the
|
|
87
|
+
* issue/sweep path uses, never a second resolver.
|
|
88
|
+
*/
|
|
89
|
+
export function normalizeAnalystLibraryIndexRow(row) {
|
|
90
|
+
const rawBook = row.bookKey;
|
|
91
|
+
if (typeof rawBook === "string" && rawBook !== "") {
|
|
92
|
+
if (rawBook === row.bookKey)
|
|
93
|
+
return row;
|
|
94
|
+
return { ...row, bookKey: rawBook };
|
|
95
|
+
}
|
|
96
|
+
const projectRoot = physicalPathIdentity(row.projectRoot);
|
|
97
|
+
return { ...row, projectRoot, bookKey: resolveAnalystBookKey(projectRoot) };
|
|
98
|
+
}
|
|
99
|
+
function sortRows(rows) {
|
|
100
|
+
// Stable book → projectRoot sort (C1 listing). Cohort join is by (book, issue) find,
|
|
101
|
+
// not row order — issueNumber secondary keeps C2 rows deterministic too.
|
|
102
|
+
return [...rows].sort((a, b) => {
|
|
103
|
+
const byBook = a.bookKey.localeCompare(b.bookKey);
|
|
104
|
+
if (byBook !== 0)
|
|
105
|
+
return byBook;
|
|
106
|
+
const byRoot = a.projectRoot.localeCompare(b.projectRoot);
|
|
107
|
+
if (byRoot !== 0)
|
|
108
|
+
return byRoot;
|
|
109
|
+
const aNum = a.issueNumber;
|
|
110
|
+
const bNum = b.issueNumber;
|
|
111
|
+
if (aNum === undefined && bNum === undefined)
|
|
112
|
+
return 0;
|
|
113
|
+
if (aNum === undefined)
|
|
114
|
+
return 1;
|
|
115
|
+
if (bNum === undefined)
|
|
116
|
+
return -1;
|
|
117
|
+
return aNum - bNum;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/** Build a fresh index from the given rows (stable projectRoot, then issueNumber). */
|
|
121
|
+
export function buildAnalystLibraryIndexPage(rows) {
|
|
122
|
+
return {
|
|
123
|
+
kind: "analyst-library-index",
|
|
124
|
+
rows: sortRows(rows.map(normalizeAnalystLibraryIndexRow)),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Look up the index row for (bookKey, issueNumber).
|
|
129
|
+
* #412: no cross-book silent scan — caller supplies the book (cwd book or book:N).
|
|
130
|
+
* Absence is a lawful cohort vacancy signal — not an error.
|
|
131
|
+
*/
|
|
132
|
+
export function findAnalystLibraryIndexRow(index, issueNumber, bookKey) {
|
|
133
|
+
if (index === undefined)
|
|
134
|
+
return undefined;
|
|
135
|
+
return index.rows.find((row) => row.issueNumber === issueNumber && row.bookKey === bookKey);
|
|
136
|
+
}
|
|
137
|
+
/** Row map key: book + root keeps cross-book same-ticket rows distinct (D5). */
|
|
138
|
+
function indexRowKey(row) {
|
|
139
|
+
return `${row.bookKey}\0${row.projectRoot}`;
|
|
140
|
+
}
|
|
141
|
+
/** Within one book, issueNumber stays unique for cohort join. */
|
|
142
|
+
function issueBookKey(bookKey, issueNumber) {
|
|
143
|
+
return `${bookKey}\0${issueNumber}`;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Upsert issue rows into an existing index (or empty).
|
|
147
|
+
* - One row per (bookKey, projectRoot) — re-sweep overwrites that issue's row only (C1).
|
|
148
|
+
* - When issueNumber is present, unique per (bookKey, issueNumber) — re-issue
|
|
149
|
+
* overwrites that number's row only within the book (C2; D5 cross-book safe).
|
|
150
|
+
*/
|
|
151
|
+
export function upsertAnalystLibraryIndexRows(existing, upserts) {
|
|
152
|
+
const byKey = new Map();
|
|
153
|
+
const keyByIssue = new Map();
|
|
154
|
+
const ingest = (row) => {
|
|
155
|
+
row = normalizeAnalystLibraryIndexRow(row);
|
|
156
|
+
const key = indexRowKey(row);
|
|
157
|
+
// C2 uniqueness within book: one row per issueNumber — drop prior if number moved.
|
|
158
|
+
if (row.issueNumber !== undefined) {
|
|
159
|
+
const issueKey = issueBookKey(row.bookKey, row.issueNumber);
|
|
160
|
+
const priorKey = keyByIssue.get(issueKey);
|
|
161
|
+
if (priorKey !== undefined && priorKey !== key) {
|
|
162
|
+
byKey.delete(priorKey);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// C1 uniqueness: one row per (book, projectRoot) — drop prior issue map if root reused.
|
|
166
|
+
const prior = byKey.get(key);
|
|
167
|
+
if (prior !== undefined
|
|
168
|
+
&& prior.issueNumber !== undefined
|
|
169
|
+
&& prior.issueNumber !== row.issueNumber) {
|
|
170
|
+
keyByIssue.delete(issueBookKey(prior.bookKey, prior.issueNumber));
|
|
171
|
+
}
|
|
172
|
+
byKey.set(key, row);
|
|
173
|
+
if (row.issueNumber !== undefined) {
|
|
174
|
+
keyByIssue.set(issueBookKey(row.bookKey, row.issueNumber), key);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
if (existing !== undefined) {
|
|
178
|
+
for (const row of existing.rows) {
|
|
179
|
+
ingest(row);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
for (const row of upserts) {
|
|
183
|
+
ingest(row);
|
|
184
|
+
}
|
|
185
|
+
return buildAnalystLibraryIndexPage([...byKey.values()]);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Read existing library index, or undefined when absent.
|
|
189
|
+
* Single typed producer writes this file — JSON.parse failure is loud; a
|
|
190
|
+
* syntactically valid but malformed shape (null / non-object / rows not an
|
|
191
|
+
* array) is rejected at this sole read boundary with the file path and real
|
|
192
|
+
* shape, so no type assertion lets garbage reach consumers (#413 r2 U1).
|
|
193
|
+
*/
|
|
194
|
+
export async function readAnalystLibraryIndexPage(ledgerHome) {
|
|
195
|
+
const path = analystLibraryIndexPath(ledgerHome);
|
|
196
|
+
let raw;
|
|
197
|
+
try {
|
|
198
|
+
raw = await readFile(path, "utf8");
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
if (error instanceof Error
|
|
202
|
+
&& "code" in error
|
|
203
|
+
&& (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
const parsed = JSON.parse(raw);
|
|
209
|
+
if (parsed === null
|
|
210
|
+
|| typeof parsed !== "object"
|
|
211
|
+
|| !Array.isArray(parsed.rows)) {
|
|
212
|
+
const shape = parsed === null
|
|
213
|
+
? "null"
|
|
214
|
+
: typeof parsed !== "object"
|
|
215
|
+
? typeof parsed
|
|
216
|
+
: `object with non-array rows (${typeof parsed.rows})`;
|
|
217
|
+
throw new Error(`analyst library-index at ${path} is malformed (${shape}; expected an index page with a rows array) — rejected at the read boundary`);
|
|
218
|
+
}
|
|
219
|
+
// Heal legacy rows at the read boundary so every consumer sees defined bookKey.
|
|
220
|
+
return buildAnalystLibraryIndexPage(parsed.rows);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Atomically replace the library index page.
|
|
224
|
+
* Directory creation goes through ledger home physical containment.
|
|
225
|
+
* Prefer {@link mergeAnalystLibraryIndexRows} for multi-writer updates — bare
|
|
226
|
+
* write has no read→merge coordination.
|
|
227
|
+
*/
|
|
228
|
+
export async function writeAnalystLibraryIndexPage(ledgerHome, page) {
|
|
229
|
+
const path = analystLibraryIndexPath(ledgerHome);
|
|
230
|
+
ensureRealDirectoryTree(ledgerHome, dirname(path));
|
|
231
|
+
assertLedgerFileInsideHome(path, ledgerHome);
|
|
232
|
+
await writeFileAtomically(path, `${JSON.stringify(page, null, 2)}\n`);
|
|
233
|
+
return path;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Sole multi-writer coordination seam for library-index updates.
|
|
237
|
+
* Holds one exclusive lock across read → upsert → atomic write so concurrent
|
|
238
|
+
* issue/sweep CLI processes cannot drop each other's new rows.
|
|
239
|
+
*/
|
|
240
|
+
export async function mergeAnalystLibraryIndexRows(ledgerHome, upserts) {
|
|
241
|
+
return withAnalystLibraryIndexLock(ledgerHome, async () => {
|
|
242
|
+
const existing = await readAnalystLibraryIndexPage(ledgerHome);
|
|
243
|
+
const index = upsertAnalystLibraryIndexRows(existing, upserts);
|
|
244
|
+
const indexPath = await writeAnalystLibraryIndexPage(ledgerHome, index);
|
|
245
|
+
return { index, indexPath };
|
|
246
|
+
});
|
|
247
|
+
}
|