@akagilnc/pi-workflow-roles 0.1.5679 → 0.1.5698
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 +4016 -3944
- package/dist/external-host-turn-loop.js +35 -17
- package/dist/headless-host/production-host.js +3246 -3174
- package/dist/migrate-book-topology.js +129 -100
- package/dist/pi/role-turn-host.js +1 -1
- package/dist/public-cli/main.js +1672 -1621
- package/dist/report-ticket-tool.js +12 -2
- package/dist/role-run-path-rewrite.js +149 -0
- package/dist/role-run-relocation.js +11 -121
- package/dist/run-dossier.js +10 -1
- package/dist/session-identity.js +1 -0
- package/dist/submission-ledger.js +11 -0
- package/package.json +1 -1
- package/resources/navigator-route-playbook.md +2 -12
- package/souls/navigator.md +2 -4
- package/src/acp-host/production-host.ts +1 -0
- package/src/acp-host/role-turn-host.ts +2 -2
- package/src/external-host-turn-loop.ts +36 -22
- package/src/headless-host/production-host.ts +1 -0
- package/src/headless-host/role-turn-host.ts +2 -2
- package/src/pi/role-turn-host.ts +1 -1
- package/src/prepared-role-turn.ts +2 -0
- package/src/report-ticket-tool.ts +12 -2
- package/src/role-envelope.ts +20 -11
- package/src/role-run-path-rewrite.ts +238 -0
- package/src/role-run-relocation.ts +34 -200
- package/src/role-runtime.ts +29 -12
- package/src/run-dossier.ts +11 -1
- package/src/session-identity.ts +1 -0
- package/src/submission-ledger.ts +11 -0
package/dist/public-cli/main.js
CHANGED
|
@@ -839,6 +839,135 @@ var init_activation_ledger_topology = __esm({
|
|
|
839
839
|
}
|
|
840
840
|
});
|
|
841
841
|
|
|
842
|
+
// src/role-run-path-rewrite.ts
|
|
843
|
+
import { sep as sep2 } from "node:path";
|
|
844
|
+
function rewriteRunDirectoryPathValue(value, oldRunDirectory, newRunDirectory) {
|
|
845
|
+
if (typeof value !== "string") return value;
|
|
846
|
+
if (value === oldRunDirectory) return newRunDirectory;
|
|
847
|
+
const prefix = `${oldRunDirectory}${sep2}`;
|
|
848
|
+
if (value.startsWith(prefix)) {
|
|
849
|
+
return `${newRunDirectory}${value.slice(oldRunDirectory.length)}`;
|
|
850
|
+
}
|
|
851
|
+
return value;
|
|
852
|
+
}
|
|
853
|
+
function rewriteRunDirectoryPathValueAgainstRewrites(value, rewrites) {
|
|
854
|
+
if (typeof value !== "string" || rewrites.length === 0) return value;
|
|
855
|
+
let best;
|
|
856
|
+
for (const rewrite of rewrites) {
|
|
857
|
+
if (value === rewrite.oldRunDirectory || value.startsWith(`${rewrite.oldRunDirectory}${sep2}`)) {
|
|
858
|
+
if (best === void 0 || rewrite.oldRunDirectory.length > best.oldRunDirectory.length) {
|
|
859
|
+
best = rewrite;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
if (best === void 0) return value;
|
|
864
|
+
return rewriteRunDirectoryPathValue(
|
|
865
|
+
value,
|
|
866
|
+
best.oldRunDirectory,
|
|
867
|
+
best.newRunDirectory
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
function rewriteRunDirectoryPathFields(record, fields, oldRunDirectory, newRunDirectory) {
|
|
871
|
+
rewriteRunDirectoryPathFieldsAgainstRewrites(record, fields, [
|
|
872
|
+
{ oldRunDirectory, newRunDirectory }
|
|
873
|
+
]);
|
|
874
|
+
}
|
|
875
|
+
function rewriteRunDirectoryPathFieldsAgainstRewrites(record, fields, rewrites) {
|
|
876
|
+
for (const field of fields) {
|
|
877
|
+
if (field in record) {
|
|
878
|
+
record[field] = rewriteRunDirectoryPathValueAgainstRewrites(
|
|
879
|
+
record[field],
|
|
880
|
+
rewrites
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
function rewritePrincipalSessionPaths(principal, oldRunDirectory, newRunDirectory) {
|
|
886
|
+
rewriteRunDirectoryPathFields(
|
|
887
|
+
principal,
|
|
888
|
+
PRINCIPAL_SESSION_PATH_FIELDS,
|
|
889
|
+
oldRunDirectory,
|
|
890
|
+
newRunDirectory
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
function projectTurnRequestLiveRunDirectory(request, newRunDirectory, authority) {
|
|
894
|
+
const old = request.runDirectory;
|
|
895
|
+
if (old === newRunDirectory) return;
|
|
896
|
+
const coords = { ...authority.decode(request.principal) };
|
|
897
|
+
rewritePrincipalSessionPaths(
|
|
898
|
+
coords,
|
|
899
|
+
old,
|
|
900
|
+
newRunDirectory
|
|
901
|
+
);
|
|
902
|
+
const sealed = authority.seal(coords);
|
|
903
|
+
request.runDirectory = newRunDirectory;
|
|
904
|
+
request.principal = sealed;
|
|
905
|
+
}
|
|
906
|
+
function rewriteSourceRunLocator(value, rewrites) {
|
|
907
|
+
if (!isRecord(value)) return;
|
|
908
|
+
rewriteRunDirectoryPathFieldsAgainstRewrites(
|
|
909
|
+
value,
|
|
910
|
+
SOURCE_RUN_LOCATOR_FIELDS,
|
|
911
|
+
rewrites
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
function rewriteSummonsMaterials(value, rewrites) {
|
|
915
|
+
if (!isRecord(value)) return;
|
|
916
|
+
rewriteRunDirectoryPathFieldsAgainstRewrites(
|
|
917
|
+
value,
|
|
918
|
+
SUMMONS_PATH_FIELDS,
|
|
919
|
+
rewrites
|
|
920
|
+
);
|
|
921
|
+
rewriteSourceRunLocator(value.sourceRun, rewrites);
|
|
922
|
+
}
|
|
923
|
+
function rewriteAdmittedRoleRunPage(page, rewrites) {
|
|
924
|
+
rewriteRunDirectoryPathFieldsAgainstRewrites(page, ADMITTED_PAGE_PATH_FIELDS, rewrites);
|
|
925
|
+
rewriteSourceRunLocator(page.sourceRun, rewrites);
|
|
926
|
+
if (isRecord(page.principal)) {
|
|
927
|
+
rewriteRunDirectoryPathFieldsAgainstRewrites(
|
|
928
|
+
page.principal,
|
|
929
|
+
PRINCIPAL_SESSION_PATH_FIELDS,
|
|
930
|
+
rewrites
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
function projectRenderedPagePaths(page, actualRunDirectory) {
|
|
935
|
+
const stored = typeof page.runDirectory === "string" && page.runDirectory.trim() !== "" ? page.runDirectory : void 0;
|
|
936
|
+
if (stored === void 0 || stored === actualRunDirectory) return page;
|
|
937
|
+
const projected = structuredClone(page);
|
|
938
|
+
const rewrites = [
|
|
939
|
+
{ oldRunDirectory: stored, newRunDirectory: actualRunDirectory }
|
|
940
|
+
];
|
|
941
|
+
rewriteAdmittedRoleRunPage(projected, rewrites);
|
|
942
|
+
if (isRecord(projected.currentCourt)) {
|
|
943
|
+
rewriteSummonsMaterials(projected.currentCourt.summons, rewrites);
|
|
944
|
+
}
|
|
945
|
+
return projected;
|
|
946
|
+
}
|
|
947
|
+
var ADMITTED_PAGE_PATH_FIELDS, PRINCIPAL_SESSION_PATH_FIELDS, SOURCE_RUN_LOCATOR_FIELDS, SUMMONS_PATH_FIELDS;
|
|
948
|
+
var init_role_run_path_rewrite = __esm({
|
|
949
|
+
"src/role-run-path-rewrite.ts"() {
|
|
950
|
+
"use strict";
|
|
951
|
+
init_unknown_value();
|
|
952
|
+
ADMITTED_PAGE_PATH_FIELDS = [
|
|
953
|
+
"runDirectory",
|
|
954
|
+
"admittedRequestPath",
|
|
955
|
+
// pre-#1161 pages only
|
|
956
|
+
"sessionDirectory",
|
|
957
|
+
"sessionFile",
|
|
958
|
+
// #1165/#1168: caller file-flag paths stay as given.
|
|
959
|
+
"mergerInputPath",
|
|
960
|
+
"sourceRunPath"
|
|
961
|
+
];
|
|
962
|
+
PRINCIPAL_SESSION_PATH_FIELDS = [
|
|
963
|
+
"sessionDirectory",
|
|
964
|
+
"sessionFile"
|
|
965
|
+
];
|
|
966
|
+
SOURCE_RUN_LOCATOR_FIELDS = ["runDirectory"];
|
|
967
|
+
SUMMONS_PATH_FIELDS = ["sourceRunPath"];
|
|
968
|
+
}
|
|
969
|
+
});
|
|
970
|
+
|
|
842
971
|
// src/run-dossier-files.ts
|
|
843
972
|
var RUN_CURRENT_FILE, RUN_HISTORY_FILE, RUN_LOG_FILE, RUN_STATE_FILE, RUN_HISTORY_KINDS, OFFICER_POINTER_RECORD_KIND, RUN_STATE_KINDS;
|
|
844
973
|
var init_run_dossier_files = __esm({
|
|
@@ -1153,7 +1282,12 @@ function render(runDirectory, history, state, log, unreadable) {
|
|
|
1153
1282
|
const whole = {};
|
|
1154
1283
|
for (const section of ["invocation", "admitted", "runState", "terminal"]) {
|
|
1155
1284
|
const page = lastPayloadOfKind(state, PAGE_ROW_KIND[section]);
|
|
1156
|
-
if (page
|
|
1285
|
+
if (page === void 0) continue;
|
|
1286
|
+
if ((section === "invocation" || section === "admitted" || section === "runState") && isRecord(page)) {
|
|
1287
|
+
whole[section] = projectRenderedPagePaths(page, runDirectory);
|
|
1288
|
+
} else {
|
|
1289
|
+
whole[section] = page;
|
|
1290
|
+
}
|
|
1157
1291
|
}
|
|
1158
1292
|
let latest;
|
|
1159
1293
|
for (const row of history) {
|
|
@@ -1278,6 +1412,7 @@ var init_run_dossier = __esm({
|
|
|
1278
1412
|
"src/run-dossier.ts"() {
|
|
1279
1413
|
"use strict";
|
|
1280
1414
|
init_role_run_placement();
|
|
1415
|
+
init_role_run_path_rewrite();
|
|
1281
1416
|
init_run_dossier_files();
|
|
1282
1417
|
init_sitian_appender();
|
|
1283
1418
|
init_sitian_reader();
|
|
@@ -12742,1248 +12877,848 @@ var init_submission_correctable_error = __esm({
|
|
|
12742
12877
|
}
|
|
12743
12878
|
});
|
|
12744
12879
|
|
|
12745
|
-
// src/
|
|
12746
|
-
|
|
12747
|
-
|
|
12748
|
-
|
|
12749
|
-
|
|
12750
|
-
|
|
12751
|
-
|
|
12752
|
-
|
|
12880
|
+
// src/sha256.ts
|
|
12881
|
+
import { createHash } from "node:crypto";
|
|
12882
|
+
function sha256Hex(bytes) {
|
|
12883
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
12884
|
+
}
|
|
12885
|
+
var init_sha256 = __esm({
|
|
12886
|
+
"src/sha256.ts"() {
|
|
12887
|
+
"use strict";
|
|
12753
12888
|
}
|
|
12754
|
-
|
|
12755
|
-
|
|
12756
|
-
|
|
12757
|
-
|
|
12758
|
-
|
|
12759
|
-
sessionParent
|
|
12760
|
-
}, ledgerHome).recordFile;
|
|
12889
|
+
});
|
|
12890
|
+
|
|
12891
|
+
// src/package-contracts/terminating-tools.ts
|
|
12892
|
+
function isTerminatingToolName(name) {
|
|
12893
|
+
return TERMINATING_TOOL_NAMES.includes(name);
|
|
12761
12894
|
}
|
|
12762
|
-
|
|
12763
|
-
|
|
12764
|
-
|
|
12765
|
-
return { file: void 0, owned: [] };
|
|
12895
|
+
function validateAcceptedDetails(_toolName, details) {
|
|
12896
|
+
if (isRecord(details)) {
|
|
12897
|
+
return details;
|
|
12766
12898
|
}
|
|
12767
|
-
|
|
12899
|
+
return {};
|
|
12900
|
+
}
|
|
12901
|
+
function acceptedFacts(toolName, details) {
|
|
12902
|
+
const record = details;
|
|
12903
|
+
const entry = PACKAGED_ROLE_REGISTRY.find((candidate) => candidate.outputTool === toolName);
|
|
12904
|
+
const legacyRole = LEGACY_REVIEW_OUTPUT_ROLES.get(toolName);
|
|
12905
|
+
const statusKey = legacyRole === "judge" || legacyRole === "countersign" ? `${legacyRole}Status` : entry !== void 0 && "receiptStatusKey" in entry ? entry.receiptStatusKey : "status";
|
|
12906
|
+
const status = typeof record[statusKey] === "string" ? record[statusKey] : void 0;
|
|
12907
|
+
const commitKey = entry !== void 0 && "receiptCommitKey" in entry ? entry.receiptCommitKey : void 0;
|
|
12908
|
+
const commitWhen = entry !== void 0 && "receiptCommitWhen" in entry ? entry.receiptCommitWhen : void 0;
|
|
12909
|
+
const commit = commitKey !== void 0 && status === commitWhen && typeof record[commitKey] === "string" ? record[commitKey] : void 0;
|
|
12768
12910
|
return {
|
|
12769
|
-
|
|
12770
|
-
|
|
12771
|
-
(record) => typeof record.subject === "object" && record.subject !== null && record.subject.runId === runId
|
|
12772
|
-
)
|
|
12911
|
+
...status === void 0 ? {} : { status },
|
|
12912
|
+
...commit === void 0 ? {} : { commit }
|
|
12773
12913
|
};
|
|
12774
12914
|
}
|
|
12775
|
-
|
|
12776
|
-
|
|
12777
|
-
|
|
12778
|
-
|
|
12779
|
-
|
|
12780
|
-
|
|
12781
|
-
|
|
12782
|
-
|
|
12783
|
-
|
|
12915
|
+
var TERMINATING_TOOL_NAMES, AcceptedDetailsContractError;
|
|
12916
|
+
var init_terminating_tools = __esm({
|
|
12917
|
+
"src/package-contracts/terminating-tools.ts"() {
|
|
12918
|
+
"use strict";
|
|
12919
|
+
init_collector_output();
|
|
12920
|
+
init_judge_output();
|
|
12921
|
+
init_reviewer_output();
|
|
12922
|
+
init_packaged_role_registry();
|
|
12923
|
+
init_submission_correctable_error();
|
|
12924
|
+
init_doctor_contracts();
|
|
12925
|
+
init_gatekeeper_output();
|
|
12926
|
+
init_navigator_output();
|
|
12927
|
+
init_auditor_output();
|
|
12928
|
+
init_merger_contracts();
|
|
12929
|
+
init_notary_contracts();
|
|
12930
|
+
init_countersign_contracts();
|
|
12931
|
+
init_gleaner_left_contracts();
|
|
12932
|
+
init_inspector_contracts();
|
|
12933
|
+
init_diarist_contracts();
|
|
12934
|
+
init_secretariat_contracts();
|
|
12935
|
+
init_worker_output();
|
|
12936
|
+
init_unknown_value();
|
|
12937
|
+
TERMINATING_TOOL_NAMES = [.../* @__PURE__ */ new Set([
|
|
12938
|
+
...PACKAGED_ROLE_REGISTRY.map((entry) => entry.outputTool),
|
|
12939
|
+
...LEGACY_REVIEW_OUTPUT_ROLES.keys()
|
|
12940
|
+
])];
|
|
12941
|
+
AcceptedDetailsContractError = class extends CorrectableSubmissionError {
|
|
12942
|
+
code = "accepted_details_contract";
|
|
12943
|
+
constructor(message, options) {
|
|
12944
|
+
super(message, options);
|
|
12945
|
+
this.name = "AcceptedDetailsContractError";
|
|
12946
|
+
}
|
|
12947
|
+
};
|
|
12784
12948
|
}
|
|
12785
|
-
|
|
12786
|
-
|
|
12787
|
-
|
|
12949
|
+
});
|
|
12950
|
+
|
|
12951
|
+
// src/doctor-evidence.ts
|
|
12952
|
+
import { readdir as readdir2, readFile as readFile5, realpath, stat } from "node:fs/promises";
|
|
12953
|
+
import { dirname as dirname7, relative as relative2, resolve as resolve4, sep as sep3 } from "node:path";
|
|
12954
|
+
async function discoverCaseFiles(root) {
|
|
12955
|
+
const found = [];
|
|
12956
|
+
async function walk(dir, depth) {
|
|
12957
|
+
for (const item of await readdir2(dir, { withFileTypes: true })) {
|
|
12958
|
+
const path = resolve4(dir, item.name);
|
|
12959
|
+
if (item.isDirectory()) {
|
|
12960
|
+
await walk(path, depth + 1);
|
|
12961
|
+
} else if (item.isFile() && (item.name.endsWith(".jsonl") && item.name !== "state.jsonl" && !(item.name === "log.jsonl" && depth === 1) || item.name === "log.jsonl" && depth === 1)) found.push(path);
|
|
12962
|
+
}
|
|
12788
12963
|
}
|
|
12789
|
-
|
|
12964
|
+
await walk(root, 0);
|
|
12965
|
+
return found.sort();
|
|
12790
12966
|
}
|
|
12791
|
-
function
|
|
12792
|
-
return
|
|
12967
|
+
function sourceList(count, sources) {
|
|
12968
|
+
return { count, sources: [...new Set(sources)].sort() };
|
|
12793
12969
|
}
|
|
12794
|
-
function
|
|
12795
|
-
|
|
12796
|
-
if (
|
|
12797
|
-
return void 0;
|
|
12970
|
+
function accumulate(metric, value, source) {
|
|
12971
|
+
metric.count += value;
|
|
12972
|
+
if (value) metric.sources.push(source);
|
|
12798
12973
|
}
|
|
12799
|
-
function
|
|
12800
|
-
|
|
12801
|
-
case "accepted":
|
|
12802
|
-
return 4;
|
|
12803
|
-
case "audit-escalation":
|
|
12804
|
-
return 3;
|
|
12805
|
-
case "correctable-rejection":
|
|
12806
|
-
case "infrastructure":
|
|
12807
|
-
return 2;
|
|
12808
|
-
case "candidate":
|
|
12809
|
-
return 1;
|
|
12810
|
-
}
|
|
12974
|
+
function timestamp(row) {
|
|
12975
|
+
return typeof row.timestamp === "string" && Number.isFinite(Date.parse(row.timestamp)) ? row.timestamp : void 0;
|
|
12811
12976
|
}
|
|
12812
|
-
function
|
|
12813
|
-
|
|
12977
|
+
async function stableRunsIdentity(root) {
|
|
12978
|
+
let cursor = root;
|
|
12979
|
+
while (true) {
|
|
12980
|
+
try {
|
|
12981
|
+
const git2 = await stat(resolve4(cursor, ".git"));
|
|
12982
|
+
if (git2.isDirectory() || git2.isFile()) return relative2(cursor, root).split(sep3).join("/");
|
|
12983
|
+
} catch (error) {
|
|
12984
|
+
if (!isMissingPathError(error)) throw error;
|
|
12985
|
+
}
|
|
12986
|
+
const parent = dirname7(cursor);
|
|
12987
|
+
if (parent === cursor) return root;
|
|
12988
|
+
cursor = parent;
|
|
12989
|
+
}
|
|
12814
12990
|
}
|
|
12815
|
-
function
|
|
12816
|
-
const
|
|
12817
|
-
|
|
12818
|
-
|
|
12819
|
-
|
|
12820
|
-
|
|
12821
|
-
|
|
12822
|
-
|
|
12823
|
-
|
|
12824
|
-
|
|
12825
|
-
|
|
12826
|
-
|
|
12827
|
-
|
|
12828
|
-
|
|
12829
|
-
|
|
12830
|
-
|
|
12831
|
-
|
|
12832
|
-
const payload = record.payload;
|
|
12833
|
-
if (typeof payload?.toolCallId !== "string" || payload.toolCallId.length === 0) continue;
|
|
12834
|
-
const role = recordedRole(payload);
|
|
12835
|
-
if (role !== void 0) {
|
|
12836
|
-
roleByCall.set(submissionCallKey(recordAttemptId(record), payload.toolCallId), role);
|
|
12991
|
+
function deriveSession(content, id) {
|
|
12992
|
+
const rows = [];
|
|
12993
|
+
const degradationReasons = [];
|
|
12994
|
+
for (const line2 of content.split("\n")) if (line2.trim()) {
|
|
12995
|
+
try {
|
|
12996
|
+
const row = JSON.parse(line2);
|
|
12997
|
+
if (!isRecord(row)) {
|
|
12998
|
+
degradationReasons.push(`non-object session row in ${id}`);
|
|
12999
|
+
break;
|
|
13000
|
+
}
|
|
13001
|
+
rows.push(row);
|
|
13002
|
+
} catch (error) {
|
|
13003
|
+
if (error instanceof SyntaxError) {
|
|
13004
|
+
degradationReasons.push(`malformed JSON tail in ${id}: ${error.message}`);
|
|
13005
|
+
break;
|
|
13006
|
+
}
|
|
13007
|
+
throw error;
|
|
12837
13008
|
}
|
|
12838
13009
|
}
|
|
12839
|
-
const
|
|
12840
|
-
|
|
12841
|
-
|
|
12842
|
-
|
|
12843
|
-
|
|
12844
|
-
|
|
12845
|
-
|
|
12846
|
-
|
|
12847
|
-
|
|
12848
|
-
|
|
12849
|
-
|
|
12850
|
-
|
|
12851
|
-
|
|
12852
|
-
|
|
12853
|
-
out[existingIndex] = { ...existing, role: row.role };
|
|
12854
|
-
}
|
|
12855
|
-
return;
|
|
13010
|
+
const started = rows.find((row) => row.type === "session");
|
|
13011
|
+
const startedAt = started && timestamp(started);
|
|
13012
|
+
if (!startedAt) degradationReasons.push(`Pi session header is missing: ${id}`);
|
|
13013
|
+
let accepted, observedCommit, turns = 0, calls = 0, tokens = 0;
|
|
13014
|
+
const statuses = [], commits = [];
|
|
13015
|
+
for (const row of rows) {
|
|
13016
|
+
if (row.type === "custom" && row.customType === "ak-role-submission-closure" && isRecord(row.data) && row.data.isError === false && typeof row.data.toolName === "string" && isTerminatingToolName(row.data.toolName)) accepted = row;
|
|
13017
|
+
const message = isRecord(row.message) ? row.message : void 0;
|
|
13018
|
+
if (message?.role === "assistant") {
|
|
13019
|
+
for (const part of Array.isArray(message.content) ? message.content : []) if (isRecord(part) && part.type === "toolCall") calls++;
|
|
13020
|
+
if (typeof message.responseId === "string") {
|
|
13021
|
+
turns++;
|
|
13022
|
+
const usage = isRecord(message.usage) ? message.usage : void 0;
|
|
13023
|
+
if (usage && typeof usage.output === "number") tokens += usage.output;
|
|
12856
13024
|
}
|
|
12857
|
-
indexByCall.set(callKey, out.length);
|
|
12858
13025
|
}
|
|
12859
|
-
|
|
12860
|
-
|
|
12861
|
-
|
|
12862
|
-
|
|
12863
|
-
|
|
12864
|
-
|
|
12865
|
-
|
|
12866
|
-
|
|
12867
|
-
|
|
12868
|
-
|
|
12869
|
-
|
|
12870
|
-
|
|
12871
|
-
|
|
12872
|
-
|
|
12873
|
-
|
|
13026
|
+
if (message?.role === "toolResult" && message.isError !== true && typeof message.toolName === "string" && isTerminatingToolName(message.toolName) && isRecord(message.details)) {
|
|
13027
|
+
let details;
|
|
13028
|
+
try {
|
|
13029
|
+
details = validateAcceptedDetails(message.toolName, message.details);
|
|
13030
|
+
} catch (error) {
|
|
13031
|
+
if (error instanceof AcceptedDetailsContractError) continue;
|
|
13032
|
+
throw error;
|
|
13033
|
+
}
|
|
13034
|
+
const facts = acceptedFacts(message.toolName, details);
|
|
13035
|
+
if (facts.commit && facts.commit !== observedCommit) {
|
|
13036
|
+
commits.push({ source: id, commit: facts.commit });
|
|
13037
|
+
observedCommit = facts.commit;
|
|
13038
|
+
}
|
|
13039
|
+
if (facts.status !== void 0) {
|
|
13040
|
+
statuses.push({ source: id, status: facts.status });
|
|
13041
|
+
}
|
|
12874
13042
|
}
|
|
12875
|
-
if (kind === void 0 || original === void 0 || payload === void 0) continue;
|
|
12876
|
-
const callKey = typeof payload.toolCallId === "string" ? submissionCallKey(recordAttemptId(record), payload.toolCallId) : void 0;
|
|
12877
|
-
const fallback = callKey === void 0 ? void 0 : roleByCall.get(callKey);
|
|
12878
|
-
take(rowFromPayload(kind, payload, original, fallback), callKey);
|
|
12879
13043
|
}
|
|
12880
|
-
|
|
12881
|
-
|
|
12882
|
-
|
|
12883
|
-
const
|
|
12884
|
-
|
|
12885
|
-
|
|
12886
|
-
|
|
12887
|
-
|
|
12888
|
-
|
|
12889
|
-
const { owned } = await readOwnedSubmissionRecords(
|
|
12890
|
-
cwd,
|
|
12891
|
-
runId,
|
|
12892
|
-
home === void 0 ? {} : { home }
|
|
12893
|
-
);
|
|
12894
|
-
return mapOwnedToSubmissionRows(owned.filter((record) => recordAttemptId(record) === attemptId));
|
|
13044
|
+
const acceptedAt = accepted && timestamp(accepted);
|
|
13045
|
+
const final = acceptedAt ? accepted : rows.at(-1);
|
|
13046
|
+
const endedAt = final && timestamp(final);
|
|
13047
|
+
const wall = startedAt && endedAt ? Date.parse(endedAt) - Date.parse(startedAt) : void 0;
|
|
13048
|
+
if (wall !== void 0 && wall < 0) degradationReasons.push(`non-monotonic session timestamps in ${id}`);
|
|
13049
|
+
const degradationReason = degradationReasons.length ? degradationReasons.join("; ") : void 0;
|
|
13050
|
+
const complete = !!acceptedAt && !degradationReason && wall !== void 0 && wall >= 0;
|
|
13051
|
+
const session = complete ? { source: id, startedAt, endedAt, wallMilliseconds: wall, completion: "accepted" } : { source: id, ...startedAt ? { startedAt } : {}, ...endedAt ? { endedAt } : {}, ...wall !== void 0 && wall >= 0 ? { wallMilliseconds: wall } : {}, completion: "incomplete", ...degradationReason ? { degradationReason } : {} };
|
|
13052
|
+
return { session, turns, calls, tokens, statuses, commits };
|
|
12895
13053
|
}
|
|
12896
|
-
async function
|
|
12897
|
-
|
|
13054
|
+
async function loadDoctorCase(runsPath, projectRoot) {
|
|
13055
|
+
const root = await realpath(runsPath);
|
|
13056
|
+
if (projectRoot !== void 0 && !physicallyContainedIn(projectRoot, root)) {
|
|
13057
|
+
throw new Error("doctor --runs escapes the project root");
|
|
13058
|
+
}
|
|
13059
|
+
const match = root.split(sep3).join("/").match(/\/\.ak-roles\/books\/[^/]+\/(?:issues\/)?([1-9]\d*)\/runs$/);
|
|
13060
|
+
if (!match) throw new Error("Doctor case must be an .ak-roles/books/<book>/<n>/runs directory");
|
|
13061
|
+
const evidence = [], sessions = [], statuses = [], commits = [];
|
|
13062
|
+
const turns = { count: 0, sources: [] }, calls = { count: 0, sources: [] }, tokens = { count: 0, sources: [] };
|
|
13063
|
+
for (const path of await discoverCaseFiles(root)) {
|
|
13064
|
+
const id = relative2(root, path).split(sep3).join("/");
|
|
13065
|
+
const bytes = await readFile5(path);
|
|
13066
|
+
const content = bytes.toString("utf8");
|
|
13067
|
+
const kind = id.split("/").length === 2 && id.endsWith("/log.jsonl") ? "log" : "session";
|
|
13068
|
+
evidence.push({ id, kind, byteLength: bytes.byteLength, contentLength: content.length, sha256: sha256Hex(bytes), content });
|
|
13069
|
+
if (kind === "log") continue;
|
|
13070
|
+
const result = deriveSession(content, id);
|
|
13071
|
+
sessions.push(result.session);
|
|
13072
|
+
statuses.push(...result.statuses);
|
|
13073
|
+
commits.push(...result.commits);
|
|
13074
|
+
accumulate(turns, result.turns, id);
|
|
13075
|
+
accumulate(calls, result.calls, id);
|
|
13076
|
+
accumulate(tokens, result.tokens, id);
|
|
13077
|
+
}
|
|
13078
|
+
const runDirs = (await readdir2(root, { withFileTypes: true })).filter((item) => item.isDirectory()).map((item) => item.name).sort();
|
|
13079
|
+
const legs = evidence.filter((entry) => entry.kind === "session").map((entry) => entry.id);
|
|
13080
|
+
const retryDirs = runDirs.filter((name) => /(?:^|[-_])retry(?:[-_]|$)/i.test(name));
|
|
13081
|
+
const rawBytes = evidence.filter((entry) => entry.kind === "session").reduce((sum, entry) => sum + entry.byteLength, 0);
|
|
13082
|
+
const cost = { invocations: sourceList(runDirs.length, runDirs), legs: sourceList(legs.length, legs), modelApiTurns: sourceList(turns.count, turns.sources), outputTokens: sourceList(tokens.count, tokens.sources), toolCalls: sourceList(calls.count, calls.sources), retries: { ...sourceList(retryDirs.length, retryDirs), evidence: "literal run-dir naming" }, statuses, commits, sessions, outputBytes: { ...sourceList(rawBytes, legs), payload: "raw JSONL bytes", providerWireBytes: "unavailable" } };
|
|
13083
|
+
return { version: 1, identity: { issueNumber: Number(match[1]), runsPath: await stableRunsIdentity(root) }, evidence, cost };
|
|
12898
13084
|
}
|
|
12899
|
-
var
|
|
12900
|
-
"src/
|
|
13085
|
+
var init_doctor_evidence = __esm({
|
|
13086
|
+
"src/doctor-evidence.ts"() {
|
|
12901
13087
|
"use strict";
|
|
12902
|
-
|
|
13088
|
+
init_sha256();
|
|
12903
13089
|
init_activation_ledger_topology();
|
|
12904
|
-
|
|
12905
|
-
init_run_terminal_artifacts();
|
|
12906
|
-
init_sitian_facade();
|
|
12907
|
-
init_run_lifecycle();
|
|
12908
|
-
init_submission_correctable_error();
|
|
12909
|
-
init_terminating_infrastructure();
|
|
12910
|
-
init_review_submission();
|
|
13090
|
+
init_terminating_tools();
|
|
12911
13091
|
init_unknown_value();
|
|
12912
13092
|
}
|
|
12913
13093
|
});
|
|
12914
13094
|
|
|
12915
|
-
// src/public-cli/
|
|
12916
|
-
|
|
12917
|
-
|
|
12918
|
-
|
|
12919
|
-
|
|
12920
|
-
|
|
12921
|
-
processCancelSignalName: () => processCancelSignalName
|
|
12922
|
-
});
|
|
12923
|
-
function installProcessCancelHandlers(processRef = process) {
|
|
12924
|
-
const controller = new AbortController();
|
|
12925
|
-
let received;
|
|
12926
|
-
const listeners = /* @__PURE__ */ new Map();
|
|
12927
|
-
for (const sig of CATCHABLE_PROCESS_SIGNALS) {
|
|
12928
|
-
const onSignal = () => {
|
|
12929
|
-
if (received !== void 0) return;
|
|
12930
|
-
received = sig;
|
|
12931
|
-
try {
|
|
12932
|
-
controller.abort(sig);
|
|
12933
|
-
} catch {
|
|
12934
|
-
}
|
|
12935
|
-
};
|
|
12936
|
-
listeners.set(sig, onSignal);
|
|
12937
|
-
processRef.on(sig, onSignal);
|
|
13095
|
+
// src/public-cli/github-remote.ts
|
|
13096
|
+
function ownerRepoFromGitHubRemoteUrl(remoteUrl) {
|
|
13097
|
+
const trimmed = remoteUrl.trim();
|
|
13098
|
+
const scp = /^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i.exec(trimmed);
|
|
13099
|
+
if (scp) {
|
|
13100
|
+
return `${scp[1]}/${stripGitSuffix(scp[2])}`;
|
|
12938
13101
|
}
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
12944
|
-
processRef.off(sig, onSignal);
|
|
12945
|
-
}
|
|
12946
|
-
listeners.clear();
|
|
12947
|
-
}
|
|
12948
|
-
};
|
|
12949
|
-
}
|
|
12950
|
-
function processCancelSignalName(signal) {
|
|
12951
|
-
if (signal === void 0 || signal.aborted !== true) return void 0;
|
|
12952
|
-
const reason = signal.reason;
|
|
12953
|
-
if (reason === "SIGTERM" || reason === "SIGINT" || reason === "SIGHUP") {
|
|
12954
|
-
return reason;
|
|
13102
|
+
const ssh = /^ssh:\/\/git@github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i.exec(
|
|
13103
|
+
trimmed
|
|
13104
|
+
);
|
|
13105
|
+
if (ssh) {
|
|
13106
|
+
return `${ssh[1]}/${stripGitSuffix(ssh[2])}`;
|
|
12955
13107
|
}
|
|
12956
|
-
|
|
13108
|
+
let parsed;
|
|
13109
|
+
try {
|
|
13110
|
+
parsed = new URL(trimmed);
|
|
13111
|
+
} catch {
|
|
13112
|
+
return void 0;
|
|
13113
|
+
}
|
|
13114
|
+
if (!/^github\.com$/i.test(parsed.hostname)) return void 0;
|
|
13115
|
+
if (parsed.search !== "" || parsed.hash !== "") return void 0;
|
|
13116
|
+
const parts = parsed.pathname.split("/").filter((p) => p.length > 0);
|
|
13117
|
+
if (parts.length !== 2) return void 0;
|
|
13118
|
+
return `${parts[0]}/${stripGitSuffix(parts[1])}`;
|
|
12957
13119
|
}
|
|
12958
|
-
function
|
|
12959
|
-
return
|
|
13120
|
+
function stripGitSuffix(name) {
|
|
13121
|
+
return name.toLowerCase().endsWith(".git") ? name.slice(0, -4) : name;
|
|
12960
13122
|
}
|
|
12961
|
-
|
|
12962
|
-
|
|
13123
|
+
var init_github_remote = __esm({
|
|
13124
|
+
"src/public-cli/github-remote.ts"() {
|
|
13125
|
+
"use strict";
|
|
13126
|
+
}
|
|
13127
|
+
});
|
|
13128
|
+
|
|
13129
|
+
// src/git-object-id.ts
|
|
13130
|
+
function isFullGitObjectId(value) {
|
|
13131
|
+
return typeof value === "string" && FULL_GIT_OBJECT_ID_RE.test(value);
|
|
12963
13132
|
}
|
|
12964
|
-
var
|
|
12965
|
-
var
|
|
12966
|
-
"src/
|
|
13133
|
+
var FULL_GIT_OBJECT_ID_RE;
|
|
13134
|
+
var init_git_object_id = __esm({
|
|
13135
|
+
"src/git-object-id.ts"() {
|
|
12967
13136
|
"use strict";
|
|
12968
|
-
|
|
13137
|
+
FULL_GIT_OBJECT_ID_RE = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
|
12969
13138
|
}
|
|
12970
13139
|
});
|
|
12971
13140
|
|
|
12972
|
-
// src/
|
|
12973
|
-
import {
|
|
12974
|
-
|
|
12975
|
-
|
|
12976
|
-
|
|
12977
|
-
|
|
12978
|
-
|
|
12979
|
-
}
|
|
12980
|
-
|
|
12981
|
-
return void 0;
|
|
12982
|
-
}
|
|
12983
|
-
return {
|
|
12984
|
-
toolCallId: payload.toolCallId,
|
|
12985
|
-
durationMs: payload.durationMs,
|
|
12986
|
-
...typeof payload.code === "number" ? { code: payload.code } : {},
|
|
12987
|
-
...typeof payload.stdoutByteLength === "number" ? { stdoutByteLength: payload.stdoutByteLength } : {},
|
|
12988
|
-
recordPointer: pointer
|
|
12989
|
-
};
|
|
13141
|
+
// src/merger-git-state.ts
|
|
13142
|
+
import { execFile } from "node:child_process";
|
|
13143
|
+
import { access, readFile as readFile6 } from "node:fs/promises";
|
|
13144
|
+
import { constants as fsConstants } from "node:fs";
|
|
13145
|
+
import { isAbsolute as isAbsolute3, resolve as resolve5 } from "node:path";
|
|
13146
|
+
import { promisify } from "node:util";
|
|
13147
|
+
async function git(cwd, args) {
|
|
13148
|
+
const { stdout } = await execFileAsync("git", args, { cwd, encoding: "buffer", maxBuffer: 16 * 1024 * 1024 });
|
|
13149
|
+
return new Uint8Array(stdout);
|
|
12990
13150
|
}
|
|
12991
|
-
function
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
|
|
12995
|
-
|
|
12996
|
-
|
|
12997
|
-
|
|
12998
|
-
|
|
13151
|
+
function line(bytes, label) {
|
|
13152
|
+
const value = exactUtf8(bytes, label).trim();
|
|
13153
|
+
if (!value) throw new Error(`${label} is empty`);
|
|
13154
|
+
return value;
|
|
13155
|
+
}
|
|
13156
|
+
async function pathExists(path) {
|
|
13157
|
+
try {
|
|
13158
|
+
await access(path, fsConstants.F_OK);
|
|
13159
|
+
return true;
|
|
13160
|
+
} catch (error) {
|
|
13161
|
+
if (error.code === "ENOENT") return false;
|
|
13162
|
+
throw error;
|
|
12999
13163
|
}
|
|
13000
|
-
return void 0;
|
|
13001
13164
|
}
|
|
13002
|
-
async function
|
|
13003
|
-
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
|
|
13007
|
-
|
|
13008
|
-
|
|
13009
|
-
|
|
13010
|
-
|
|
13011
|
-
|
|
13012
|
-
|
|
13013
|
-
|
|
13014
|
-
if (record.kind !== ENGINE_DETOUR_CALL_KIND) continue;
|
|
13015
|
-
const boundScope = invocationScopeIdOfRecord(record);
|
|
13016
|
-
if (input.invocationScopeId !== void 0 && input.invocationScopeId.length > 0) {
|
|
13017
|
-
if (boundScope !== input.invocationScopeId) continue;
|
|
13018
|
-
} else if (boundScope !== void 0) {
|
|
13019
|
-
continue;
|
|
13020
|
-
}
|
|
13021
|
-
const pointer = {
|
|
13022
|
-
identity: record.identity,
|
|
13023
|
-
recordFile: ENGINE_DETOUR_CALL_RECORD_FILE_RELATIVE,
|
|
13024
|
-
kind: record.kind,
|
|
13025
|
-
level: record.level
|
|
13026
|
-
};
|
|
13027
|
-
const fact = callFactFromSitianPayload(record.payload, pointer);
|
|
13028
|
-
if (fact === void 0) continue;
|
|
13029
|
-
callsByToolCallId.set(fact.toolCallId, fact);
|
|
13165
|
+
async function requireInsideWorkTree(cwd) {
|
|
13166
|
+
const stdout = await git(cwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
13167
|
+
if (exactUtf8(stdout, "Git worktree check").trim() !== "true") throw new Error("Assigned path is not inside a Git work tree");
|
|
13168
|
+
}
|
|
13169
|
+
async function tryResolveCommit(cwd, rev) {
|
|
13170
|
+
let stdout;
|
|
13171
|
+
try {
|
|
13172
|
+
const res = await execFileAsync("git", ["rev-parse", "--verify", "--quiet", `${rev}^{commit}`], { cwd, encoding: "buffer", maxBuffer: 16 * 1024 * 1024 });
|
|
13173
|
+
stdout = new Uint8Array(res.stdout);
|
|
13174
|
+
} catch (error) {
|
|
13175
|
+
if (error.code === 1) return void 0;
|
|
13176
|
+
throw error;
|
|
13030
13177
|
}
|
|
13031
|
-
const
|
|
13032
|
-
|
|
13178
|
+
const oid = line(stdout, `Git ${rev}`);
|
|
13179
|
+
if (!isFullGitObjectId(oid)) throw new Error(`Git ${rev} identity is unavailable or invalid`);
|
|
13180
|
+
return oid;
|
|
13033
13181
|
}
|
|
13034
|
-
function
|
|
13035
|
-
|
|
13182
|
+
async function unmerged(cwd) {
|
|
13183
|
+
const raw = exactUtf8(await git(cwd, ["ls-files", "-u", "-z"]), "Git unmerged index");
|
|
13184
|
+
const paths = /* @__PURE__ */ new Set();
|
|
13185
|
+
for (const row of raw.split("\0")) {
|
|
13186
|
+
if (!row) continue;
|
|
13187
|
+
const tab = row.indexOf(" ");
|
|
13188
|
+
if (tab < 0 || tab === row.length - 1) throw new Error("Git returned a malformed unmerged index row");
|
|
13189
|
+
paths.add(row.slice(tab + 1));
|
|
13190
|
+
}
|
|
13191
|
+
return [...paths].sort((a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)));
|
|
13036
13192
|
}
|
|
13037
|
-
async function
|
|
13038
|
-
const
|
|
13039
|
-
if (
|
|
13040
|
-
|
|
13193
|
+
async function resolveHeadMaterial(cwd) {
|
|
13194
|
+
const commit = await tryResolveCommit(cwd, "HEAD");
|
|
13195
|
+
if (commit !== void 0) return commit;
|
|
13196
|
+
try {
|
|
13197
|
+
await execFileAsync("git", ["rev-parse", "--verify", "--quiet", "HEAD"], { cwd, encoding: "buffer", maxBuffer: 16 * 1024 * 1024 });
|
|
13198
|
+
} catch (error) {
|
|
13199
|
+
if (error.code === 1) return "";
|
|
13200
|
+
throw error;
|
|
13201
|
+
}
|
|
13202
|
+
throw new Error("Git HEAD identity is unavailable or invalid");
|
|
13041
13203
|
}
|
|
13042
|
-
function
|
|
13043
|
-
if (usage === void 0) return outcome;
|
|
13044
|
-
const prior = isRecord(outcome.decisiveFacts) ? outcome.decisiveFacts : {};
|
|
13204
|
+
function createProductionMergerGitState(repositoryRoot = process.cwd()) {
|
|
13045
13205
|
return {
|
|
13046
|
-
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
[
|
|
13206
|
+
async activeMerge() {
|
|
13207
|
+
await requireInsideWorkTree(repositoryRoot);
|
|
13208
|
+
const targetObjectId = await resolveHeadMaterial(repositoryRoot);
|
|
13209
|
+
const mergeHeadReported = line(await git(repositoryRoot, ["rev-parse", "--git-path", "MERGE_HEAD"]), "Git MERGE_HEAD path");
|
|
13210
|
+
const mergeHeadPath = isAbsolute3(mergeHeadReported) ? mergeHeadReported : resolve5(repositoryRoot, mergeHeadReported);
|
|
13211
|
+
let sourceObjectId = "";
|
|
13212
|
+
if (await pathExists(mergeHeadPath)) {
|
|
13213
|
+
const raw = exactUtf8(await readFile6(mergeHeadPath), "Git MERGE_HEAD");
|
|
13214
|
+
const mergeHeads = raw.trim().split(/\r?\n/).map((row) => row.trim()).filter(Boolean);
|
|
13215
|
+
if (mergeHeads.length === 0) throw new Error("Git MERGE_HEAD is empty");
|
|
13216
|
+
if (mergeHeads.length !== 1) throw new Error("Assigned repository does not have one ordinary in-progress merge");
|
|
13217
|
+
const source = mergeHeads[0];
|
|
13218
|
+
if (!isFullGitObjectId(source)) throw new Error("Git MERGE_HEAD identity is unavailable or invalid");
|
|
13219
|
+
const resolved = await tryResolveCommit(repositoryRoot, source);
|
|
13220
|
+
if (resolved === void 0 || targetObjectId !== "" && resolved.length !== targetObjectId.length) {
|
|
13221
|
+
throw new Error("Git MERGE_HEAD identity is unavailable or invalid");
|
|
13222
|
+
}
|
|
13223
|
+
sourceObjectId = resolved;
|
|
13224
|
+
}
|
|
13225
|
+
return { targetObjectId, sourceObjectId, unmergedPaths: await unmerged(repositoryRoot) };
|
|
13050
13226
|
}
|
|
13051
13227
|
};
|
|
13052
13228
|
}
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
13229
|
+
var execFileAsync;
|
|
13230
|
+
var init_merger_git_state = __esm({
|
|
13231
|
+
"src/merger-git-state.ts"() {
|
|
13232
|
+
"use strict";
|
|
13233
|
+
init_exact_utf8();
|
|
13234
|
+
init_git_object_id();
|
|
13235
|
+
execFileAsync = promisify(execFile);
|
|
13059
13236
|
}
|
|
13060
|
-
|
|
13061
|
-
|
|
13237
|
+
});
|
|
13238
|
+
|
|
13239
|
+
// src/session-dialogue.ts
|
|
13240
|
+
var init_session_dialogue = __esm({
|
|
13241
|
+
"src/session-dialogue.ts"() {
|
|
13242
|
+
"use strict";
|
|
13243
|
+
init_unknown_value();
|
|
13062
13244
|
}
|
|
13063
|
-
|
|
13245
|
+
});
|
|
13246
|
+
|
|
13247
|
+
// src/ticket-provenance.ts
|
|
13248
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
13249
|
+
import { join as join11, resolve as resolve6 } from "node:path";
|
|
13250
|
+
function ticketProvenanceSubject(ticketNumber) {
|
|
13251
|
+
if (!isSafePositiveTicketNumber(ticketNumber)) {
|
|
13252
|
+
throw new Error(
|
|
13253
|
+
`ticket-provenance subject requires a positive ticket number, got ${String(ticketNumber)}`
|
|
13254
|
+
);
|
|
13255
|
+
}
|
|
13256
|
+
return String(ticketNumber);
|
|
13064
13257
|
}
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13258
|
+
function ticketProvenanceRecordInput(ticketNumber, cwd, home, runDirectory) {
|
|
13259
|
+
return {
|
|
13260
|
+
level: "event",
|
|
13261
|
+
kind: TICKET_PROVENANCE_KIND,
|
|
13262
|
+
...ticketNumber === null ? {} : { subject: ticketProvenanceSubject(ticketNumber) },
|
|
13263
|
+
...runDirectory === void 0 ? {} : { runDirectory },
|
|
13264
|
+
cwd,
|
|
13265
|
+
...home === void 0 ? {} : { home }
|
|
13266
|
+
};
|
|
13267
|
+
}
|
|
13268
|
+
async function rehomeUnboundTicketProvenance(runDirectory, ticketNumber, cwd, home) {
|
|
13269
|
+
const ticketInput = ticketProvenanceRecordInput(ticketNumber, cwd, home);
|
|
13270
|
+
let history;
|
|
13271
|
+
try {
|
|
13272
|
+
history = await readFile7(join11(runDirectory, RUN_HISTORY_FILE), "utf8");
|
|
13273
|
+
} catch (error) {
|
|
13274
|
+
if (errnoCode(error) === "ENOENT") return;
|
|
13275
|
+
throw error;
|
|
13276
|
+
}
|
|
13277
|
+
const block = history.split("\n").flatMap((line2, index) => {
|
|
13278
|
+
const decoded = decodeSitianRecordLine(line2, index + 1);
|
|
13279
|
+
if (decoded === void 0 || !decoded.ok) return [];
|
|
13280
|
+
if (decoded.record.kind !== TICKET_PROVENANCE_KIND) return [];
|
|
13281
|
+
return [`${line2}
|
|
13282
|
+
`];
|
|
13283
|
+
}).join("");
|
|
13284
|
+
if (block !== "") appendSitianRecordBlock(ticketInput, block);
|
|
13285
|
+
}
|
|
13286
|
+
var init_ticket_provenance = __esm({
|
|
13287
|
+
"src/ticket-provenance.ts"() {
|
|
13068
13288
|
"use strict";
|
|
13069
|
-
|
|
13289
|
+
init_activation_ledger_topology();
|
|
13290
|
+
init_ledger_session_read();
|
|
13291
|
+
init_run_ticket_number();
|
|
13070
13292
|
init_role_run_placement();
|
|
13071
|
-
|
|
13293
|
+
init_run_dossier_files();
|
|
13294
|
+
init_session_dialogue();
|
|
13072
13295
|
init_sitian_facade();
|
|
13296
|
+
init_sitian_reader();
|
|
13297
|
+
init_ticket_provenance_contracts();
|
|
13073
13298
|
init_unknown_value();
|
|
13074
|
-
ENGINE_DETOUR_CALL_KIND = "engine-detour-call";
|
|
13075
|
-
ENGINE_DETOUR_TOOL_USAGE_FACT_KEY = "engineDetourToolUsage";
|
|
13076
|
-
ENGINE_DETOUR_CALL_RECORD_FILE_RELATIVE = RUN_LOG_FILE;
|
|
13077
13299
|
}
|
|
13078
13300
|
});
|
|
13079
13301
|
|
|
13080
|
-
// src/
|
|
13081
|
-
import {
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
return "sessionManager" in value;
|
|
13302
|
+
// src/uuidv7.ts
|
|
13303
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
13304
|
+
function isUuidV7(value) {
|
|
13305
|
+
return typeof value === "string" && UUIDV7.test(value);
|
|
13085
13306
|
}
|
|
13086
|
-
function
|
|
13087
|
-
|
|
13088
|
-
|
|
13307
|
+
function uuidv7(now = Date.now()) {
|
|
13308
|
+
const b = randomBytes2(16);
|
|
13309
|
+
let n = BigInt(now);
|
|
13310
|
+
for (let i = 5; i >= 0; i--) {
|
|
13311
|
+
b[i] = Number(n & 255n);
|
|
13312
|
+
n >>= 8n;
|
|
13089
13313
|
}
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13314
|
+
b[6] = b[6] & 15 | 112;
|
|
13315
|
+
b[8] = b[8] & 63 | 128;
|
|
13316
|
+
const h = b.toString("hex");
|
|
13317
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
|
|
13093
13318
|
}
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13319
|
+
var UUIDV7;
|
|
13320
|
+
var init_uuidv7 = __esm({
|
|
13321
|
+
"src/uuidv7.ts"() {
|
|
13322
|
+
"use strict";
|
|
13323
|
+
UUIDV7 = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
13098
13324
|
}
|
|
13099
|
-
|
|
13325
|
+
});
|
|
13326
|
+
|
|
13327
|
+
// src/notary-source-run.ts
|
|
13328
|
+
import { dirname as dirname8, isAbsolute as isAbsolute4, join as join12, resolve as resolve7, basename as basename7 } from "node:path";
|
|
13329
|
+
import { lstat as lstat2, realpath as realpath2 } from "node:fs/promises";
|
|
13330
|
+
async function readRetainedIdentity(runDirectory) {
|
|
13100
13331
|
try {
|
|
13101
|
-
|
|
13102
|
-
|
|
13103
|
-
|
|
13104
|
-
|
|
13105
|
-
|
|
13332
|
+
return await readRoleRunIdentity(runDirectory);
|
|
13333
|
+
} catch (error) {
|
|
13334
|
+
if (!(error instanceof TypeError || error instanceof SyntaxError)) throw error;
|
|
13335
|
+
throw new NotarySourceRunError("notary --source-run has invalid retained run-state identity", {
|
|
13336
|
+
cause: error
|
|
13337
|
+
});
|
|
13106
13338
|
}
|
|
13107
|
-
return { status: "ok", runDirectory };
|
|
13108
13339
|
}
|
|
13109
|
-
function
|
|
13110
|
-
|
|
13111
|
-
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13340
|
+
async function requireRunDirectory(candidate, display) {
|
|
13341
|
+
let real;
|
|
13342
|
+
try {
|
|
13343
|
+
real = await realpath2(candidate);
|
|
13344
|
+
} catch (error) {
|
|
13345
|
+
throw new NotarySourceRunError(
|
|
13346
|
+
`notary --source-run is not a readable run directory: ${display}`,
|
|
13347
|
+
{ cause: error }
|
|
13348
|
+
);
|
|
13115
13349
|
}
|
|
13116
|
-
|
|
13117
|
-
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
throw new
|
|
13350
|
+
let stat2;
|
|
13351
|
+
try {
|
|
13352
|
+
stat2 = await lstat2(real);
|
|
13353
|
+
} catch (error) {
|
|
13354
|
+
throw new NotarySourceRunError(
|
|
13355
|
+
`notary --source-run is not a readable run directory: ${display}`,
|
|
13356
|
+
{ cause: error }
|
|
13357
|
+
);
|
|
13121
13358
|
}
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
|
|
13125
|
-
|
|
13126
|
-
"use strict";
|
|
13127
|
-
init_host_contracts();
|
|
13128
|
-
init_unknown_value();
|
|
13129
|
-
AUDIT_RUN_DIR_ENV = "AK_ROLE_RUN_DIR";
|
|
13130
|
-
DOCTOR_CANDIDATE_ENTRY_TYPE = "ak_doctor_audit_candidate";
|
|
13131
|
-
AuditMaterialsUnavailableError = class extends Error {
|
|
13132
|
-
observation;
|
|
13133
|
-
candidate;
|
|
13134
|
-
constructor(observation) {
|
|
13135
|
-
const detail = observation.kind === "missing-subject" ? `${observation.kind}:${observation.subject}` : observation.kind;
|
|
13136
|
-
super(`Audit materials unavailable: ${detail}`);
|
|
13137
|
-
this.name = "AuditMaterialsUnavailableError";
|
|
13138
|
-
this.observation = observation;
|
|
13139
|
-
this.candidate = void 0;
|
|
13140
|
-
}
|
|
13141
|
-
};
|
|
13359
|
+
if (!stat2.isDirectory()) {
|
|
13360
|
+
throw new NotarySourceRunError(
|
|
13361
|
+
`notary --source-run must be a run directory: ${display}`
|
|
13362
|
+
);
|
|
13142
13363
|
}
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
|
|
13147
|
-
|
|
13148
|
-
return createHash("sha256").update(bytes).digest("hex");
|
|
13149
|
-
}
|
|
13150
|
-
var init_sha256 = __esm({
|
|
13151
|
-
"src/sha256.ts"() {
|
|
13152
|
-
"use strict";
|
|
13364
|
+
const identity = parseRunLeaf(basename7(real));
|
|
13365
|
+
if (identity === void 0) {
|
|
13366
|
+
throw new NotarySourceRunError(
|
|
13367
|
+
`notary --source-run must be named <runId>@<role>: ${basename7(real)}`
|
|
13368
|
+
);
|
|
13153
13369
|
}
|
|
13154
|
-
|
|
13155
|
-
|
|
13156
|
-
// src/package-contracts/terminating-tools.ts
|
|
13157
|
-
function isTerminatingToolName(name) {
|
|
13158
|
-
return TERMINATING_TOOL_NAMES.includes(name);
|
|
13370
|
+
return real;
|
|
13159
13371
|
}
|
|
13160
|
-
function
|
|
13161
|
-
|
|
13162
|
-
|
|
13372
|
+
async function resolveNotarySourceRunLocator(options) {
|
|
13373
|
+
const raw = options.sourceRun.trim();
|
|
13374
|
+
if (raw === "") {
|
|
13375
|
+
throw new NotarySourceRunError("notary --source-run requires a run locator");
|
|
13376
|
+
}
|
|
13377
|
+
const ledgerHome = resolveActivationLedgerHome(options.home);
|
|
13378
|
+
const bookKey = resolveBookKeyFromGit(options.projectRoot);
|
|
13379
|
+
const bookDirectory = activationBookDirectory(ledgerHome, bookKey);
|
|
13380
|
+
const bookRunsRoot = join12(bookDirectory, "runs");
|
|
13381
|
+
let candidate;
|
|
13382
|
+
const bare = parseRunLeaf(raw);
|
|
13383
|
+
if (bare !== void 0 && !raw.includes("/") && !raw.includes("\\")) {
|
|
13384
|
+
candidate = await findRunDirectoryById(options.home, bare.runId, bookKey, bare.role) ?? join12(bookRunsRoot, formatRunLeaf(bare.runId, bare.role));
|
|
13385
|
+
} else {
|
|
13386
|
+
candidate = isAbsolute4(raw) ? raw : resolve7(options.projectRoot, raw);
|
|
13387
|
+
const identity2 = parseRunLeaf(basename7(candidate));
|
|
13388
|
+
const subjectDirectory = dirname8(dirname8(candidate));
|
|
13389
|
+
const isLegacyUnboundLocator = identity2 !== void 0 && basename7(dirname8(candidate)) === "runs" && basename7(subjectDirectory) === "unbound" && resolve7(dirname8(subjectDirectory)) === resolve7(bookDirectory);
|
|
13390
|
+
if (isLegacyUnboundLocator) {
|
|
13391
|
+
candidate = await findRunDirectoryById(
|
|
13392
|
+
options.home,
|
|
13393
|
+
identity2.runId,
|
|
13394
|
+
bookKey,
|
|
13395
|
+
identity2.role
|
|
13396
|
+
) ?? candidate;
|
|
13397
|
+
}
|
|
13398
|
+
}
|
|
13399
|
+
const real = await requireRunDirectory(candidate, raw);
|
|
13400
|
+
const identity = parseRunLeaf(basename7(real));
|
|
13401
|
+
const bookIdentity = physicalPathIdentity(bookDirectory);
|
|
13402
|
+
const parentIdentity = physicalPathIdentity(dirname8(real));
|
|
13403
|
+
const subjectBookIdentity = physicalPathIdentity(dirname8(dirname8(dirname8(real))));
|
|
13404
|
+
if (parentIdentity !== physicalPathIdentity(bookRunsRoot) && !(basename7(dirname8(real)) === "runs" && subjectBookIdentity === bookIdentity)) {
|
|
13405
|
+
throw new NotarySourceRunError(
|
|
13406
|
+
"notary --source-run must resolve to a retained run under the project machine-ledger book"
|
|
13407
|
+
);
|
|
13408
|
+
}
|
|
13409
|
+
const runState = await readRetainedIdentity(real);
|
|
13410
|
+
if (runState === void 0) {
|
|
13411
|
+
throw new NotarySourceRunError(
|
|
13412
|
+
"notary --source-run lacks retained run-state identity"
|
|
13413
|
+
);
|
|
13414
|
+
}
|
|
13415
|
+
if (runState.runId !== identity.runId || runState.role !== identity.role) {
|
|
13416
|
+
throw new NotarySourceRunError(
|
|
13417
|
+
"notary --source-run retained identity does not match directory name"
|
|
13418
|
+
);
|
|
13419
|
+
}
|
|
13420
|
+
if (runState.bookKey !== bookKey) {
|
|
13421
|
+
throw new NotarySourceRunError(
|
|
13422
|
+
"notary --source-run retained book binding does not match project case"
|
|
13423
|
+
);
|
|
13424
|
+
}
|
|
13425
|
+
if (physicalPathIdentity(runState.runDirectory) !== physicalPathIdentity(real)) {
|
|
13426
|
+
throw new NotarySourceRunError(
|
|
13427
|
+
"notary --source-run retained runDirectory does not match locator path"
|
|
13428
|
+
);
|
|
13163
13429
|
}
|
|
13164
|
-
return {};
|
|
13165
|
-
}
|
|
13166
|
-
function acceptedFacts(toolName, details) {
|
|
13167
|
-
const record = details;
|
|
13168
|
-
const entry = PACKAGED_ROLE_REGISTRY.find((candidate) => candidate.outputTool === toolName);
|
|
13169
|
-
const legacyRole = LEGACY_REVIEW_OUTPUT_ROLES.get(toolName);
|
|
13170
|
-
const statusKey = legacyRole === "judge" || legacyRole === "countersign" ? `${legacyRole}Status` : entry !== void 0 && "receiptStatusKey" in entry ? entry.receiptStatusKey : "status";
|
|
13171
|
-
const status = typeof record[statusKey] === "string" ? record[statusKey] : void 0;
|
|
13172
|
-
const commitKey = entry !== void 0 && "receiptCommitKey" in entry ? entry.receiptCommitKey : void 0;
|
|
13173
|
-
const commitWhen = entry !== void 0 && "receiptCommitWhen" in entry ? entry.receiptCommitWhen : void 0;
|
|
13174
|
-
const commit = commitKey !== void 0 && status === commitWhen && typeof record[commitKey] === "string" ? record[commitKey] : void 0;
|
|
13175
13430
|
return {
|
|
13176
|
-
|
|
13177
|
-
|
|
13431
|
+
runDirectory: real,
|
|
13432
|
+
runId: identity.runId,
|
|
13433
|
+
role: identity.role
|
|
13178
13434
|
};
|
|
13179
13435
|
}
|
|
13180
|
-
var
|
|
13181
|
-
var
|
|
13182
|
-
"src/
|
|
13436
|
+
var NotarySourceRunError;
|
|
13437
|
+
var init_notary_source_run = __esm({
|
|
13438
|
+
"src/notary-source-run.ts"() {
|
|
13183
13439
|
"use strict";
|
|
13184
|
-
|
|
13185
|
-
|
|
13186
|
-
|
|
13187
|
-
|
|
13188
|
-
|
|
13189
|
-
init_doctor_contracts();
|
|
13190
|
-
init_gatekeeper_output();
|
|
13191
|
-
init_navigator_output();
|
|
13192
|
-
init_auditor_output();
|
|
13193
|
-
init_merger_contracts();
|
|
13194
|
-
init_notary_contracts();
|
|
13195
|
-
init_countersign_contracts();
|
|
13196
|
-
init_gleaner_left_contracts();
|
|
13197
|
-
init_inspector_contracts();
|
|
13198
|
-
init_diarist_contracts();
|
|
13199
|
-
init_secretariat_contracts();
|
|
13200
|
-
init_worker_output();
|
|
13201
|
-
init_unknown_value();
|
|
13202
|
-
TERMINATING_TOOL_NAMES = [.../* @__PURE__ */ new Set([
|
|
13203
|
-
...PACKAGED_ROLE_REGISTRY.map((entry) => entry.outputTool),
|
|
13204
|
-
...LEGACY_REVIEW_OUTPUT_ROLES.keys()
|
|
13205
|
-
])];
|
|
13206
|
-
AcceptedDetailsContractError = class extends CorrectableSubmissionError {
|
|
13207
|
-
code = "accepted_details_contract";
|
|
13440
|
+
init_activation_ledger_git();
|
|
13441
|
+
init_activation_ledger_topology();
|
|
13442
|
+
init_run_lifecycle();
|
|
13443
|
+
init_role_run_placement();
|
|
13444
|
+
NotarySourceRunError = class extends Error {
|
|
13208
13445
|
constructor(message, options) {
|
|
13209
13446
|
super(message, options);
|
|
13210
|
-
this.name = "
|
|
13447
|
+
this.name = "NotarySourceRunError";
|
|
13211
13448
|
}
|
|
13212
13449
|
};
|
|
13213
13450
|
}
|
|
13214
13451
|
});
|
|
13215
13452
|
|
|
13216
|
-
// src/
|
|
13217
|
-
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
|
|
13222
|
-
for (const item of await readdir2(dir, { withFileTypes: true })) {
|
|
13223
|
-
const path = resolve5(dir, item.name);
|
|
13224
|
-
if (item.isDirectory()) {
|
|
13225
|
-
await walk(path, depth + 1);
|
|
13226
|
-
} else if (item.isFile() && (item.name.endsWith(".jsonl") && item.name !== "state.jsonl" && !(item.name === "log.jsonl" && depth === 1) || item.name === "log.jsonl" && depth === 1)) found.push(path);
|
|
13227
|
-
}
|
|
13453
|
+
// src/public-cli/option-definitions.ts
|
|
13454
|
+
function resolveAnalystMode(presentOptionIds) {
|
|
13455
|
+
const selected = /* @__PURE__ */ new Set();
|
|
13456
|
+
for (const def of optionsForOwner("analyst")) {
|
|
13457
|
+
if (def.selectsMode === void 0) continue;
|
|
13458
|
+
if (presentOptionIds.has(def.id)) selected.add(def.selectsMode);
|
|
13228
13459
|
}
|
|
13229
|
-
|
|
13230
|
-
|
|
13231
|
-
|
|
13232
|
-
|
|
13233
|
-
return
|
|
13234
|
-
}
|
|
13235
|
-
function accumulate(metric, value, source) {
|
|
13236
|
-
metric.count += value;
|
|
13237
|
-
if (value) metric.sources.push(source);
|
|
13238
|
-
}
|
|
13239
|
-
function timestamp(row) {
|
|
13240
|
-
return typeof row.timestamp === "string" && Number.isFinite(Date.parse(row.timestamp)) ? row.timestamp : void 0;
|
|
13460
|
+
if (selected.size === 0) return ANALYST_DEFAULT_MODE;
|
|
13461
|
+
if (selected.has("cohort")) return "cohort";
|
|
13462
|
+
if (selected.has("sweep")) return "sweep";
|
|
13463
|
+
if (selected.has("issue")) return "issue";
|
|
13464
|
+
return ANALYST_DEFAULT_MODE;
|
|
13241
13465
|
}
|
|
13242
|
-
|
|
13243
|
-
|
|
13244
|
-
|
|
13245
|
-
|
|
13246
|
-
|
|
13247
|
-
|
|
13248
|
-
|
|
13249
|
-
if (
|
|
13466
|
+
function evaluateAnalystModeOptionContract(mode, counts) {
|
|
13467
|
+
const definitions = optionsForOwner("analyst");
|
|
13468
|
+
const byId = new Map(definitions.map((def) => [def.id, def]));
|
|
13469
|
+
for (const def of definitions) {
|
|
13470
|
+
const count = counts.get(def.id) ?? 0;
|
|
13471
|
+
if (count === 0 || def.exclusiveWith === void 0) continue;
|
|
13472
|
+
for (const otherId of def.exclusiveWith) {
|
|
13473
|
+
if ((counts.get(otherId) ?? 0) === 0) continue;
|
|
13474
|
+
const other = byId.get(otherId);
|
|
13475
|
+
return {
|
|
13476
|
+
ok: false,
|
|
13477
|
+
message: `analyst accepts only one of ${def.canonical} / ${other?.canonical ?? otherId}`
|
|
13478
|
+
};
|
|
13250
13479
|
}
|
|
13251
|
-
const parent = dirname7(cursor);
|
|
13252
|
-
if (parent === cursor) return root;
|
|
13253
|
-
cursor = parent;
|
|
13254
13480
|
}
|
|
13255
|
-
|
|
13256
|
-
|
|
13257
|
-
|
|
13258
|
-
|
|
13259
|
-
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
break;
|
|
13265
|
-
}
|
|
13266
|
-
rows.push(row);
|
|
13267
|
-
} catch (error) {
|
|
13268
|
-
if (error instanceof SyntaxError) {
|
|
13269
|
-
degradationReasons.push(`malformed JSON tail in ${id}: ${error.message}`);
|
|
13270
|
-
break;
|
|
13481
|
+
for (const def of definitions) {
|
|
13482
|
+
const count = counts.get(def.id) ?? 0;
|
|
13483
|
+
if (count === 0) continue;
|
|
13484
|
+
if (def.modes !== void 0 && !def.modes.includes(mode)) {
|
|
13485
|
+
if (mode === "sweep") {
|
|
13486
|
+
return {
|
|
13487
|
+
ok: false,
|
|
13488
|
+
message: `analyst sweep --attach cannot combine with ${def.canonical}`
|
|
13489
|
+
};
|
|
13271
13490
|
}
|
|
13272
|
-
|
|
13491
|
+
return {
|
|
13492
|
+
ok: false,
|
|
13493
|
+
message: `analyst ${mode} does not accept ${def.canonical}`
|
|
13494
|
+
};
|
|
13495
|
+
}
|
|
13496
|
+
const max = def.maxCountByMode?.[mode];
|
|
13497
|
+
if (max !== void 0 && count > max) {
|
|
13498
|
+
return {
|
|
13499
|
+
ok: false,
|
|
13500
|
+
message: max === 1 ? `analyst ${mode} accepts at most one ${def.canonical}` : `analyst ${mode} accepts at most ${max} ${def.canonical}`
|
|
13501
|
+
};
|
|
13273
13502
|
}
|
|
13274
13503
|
}
|
|
13275
|
-
const
|
|
13276
|
-
const
|
|
13277
|
-
|
|
13278
|
-
|
|
13279
|
-
|
|
13280
|
-
|
|
13281
|
-
|
|
13282
|
-
|
|
13283
|
-
|
|
13284
|
-
|
|
13285
|
-
|
|
13286
|
-
|
|
13287
|
-
const usage = isRecord(message.usage) ? message.usage : void 0;
|
|
13288
|
-
if (usage && typeof usage.output === "number") tokens += usage.output;
|
|
13289
|
-
}
|
|
13504
|
+
const missingRequired = [];
|
|
13505
|
+
for (const def of definitions) {
|
|
13506
|
+
if (def.requiredInModes === void 0) continue;
|
|
13507
|
+
if (!def.requiredInModes.includes(mode)) continue;
|
|
13508
|
+
if ((counts.get(def.id) ?? 0) === 0) missingRequired.push(def);
|
|
13509
|
+
}
|
|
13510
|
+
if (missingRequired.length > 0) {
|
|
13511
|
+
if (mode === "cohort") {
|
|
13512
|
+
return {
|
|
13513
|
+
ok: false,
|
|
13514
|
+
message: "usage: ak-role analyst --cohort --group-a-label <L> --group-a-issues <N|book:N[,...]> --group-b-label <L> --group-b-issues <N|book:N[,...]>"
|
|
13515
|
+
};
|
|
13290
13516
|
}
|
|
13291
|
-
|
|
13292
|
-
|
|
13293
|
-
|
|
13294
|
-
|
|
13295
|
-
|
|
13296
|
-
|
|
13297
|
-
|
|
13298
|
-
|
|
13299
|
-
|
|
13300
|
-
|
|
13301
|
-
|
|
13302
|
-
|
|
13303
|
-
|
|
13304
|
-
|
|
13305
|
-
statuses.push({ source: id, status: facts.status });
|
|
13306
|
-
}
|
|
13517
|
+
return {
|
|
13518
|
+
ok: false,
|
|
13519
|
+
message: `usage: ak-role analyst ${mode} requires ${missingRequired.map((def) => def.canonical).join(" ")}`
|
|
13520
|
+
};
|
|
13521
|
+
}
|
|
13522
|
+
for (const rule of ANALYST_REQUIRE_ANY_OF) {
|
|
13523
|
+
if (rule.mode !== mode) continue;
|
|
13524
|
+
const hit = rule.optionIds.some((id) => (counts.get(id) ?? 0) > 0);
|
|
13525
|
+
if (hit) continue;
|
|
13526
|
+
if (mode === "issue") {
|
|
13527
|
+
return {
|
|
13528
|
+
ok: false,
|
|
13529
|
+
message: "usage: ak-role analyst ([--ticket <N>] | [sweep] --attach <sweep.json> | --cohort ...)"
|
|
13530
|
+
};
|
|
13307
13531
|
}
|
|
13532
|
+
const flags = rule.optionIds.map((id) => byId.get(id)?.canonical ?? id).join(" | ");
|
|
13533
|
+
return {
|
|
13534
|
+
ok: false,
|
|
13535
|
+
message: `usage: ak-role analyst ${mode} requires one of ${flags}`
|
|
13536
|
+
};
|
|
13308
13537
|
}
|
|
13309
|
-
|
|
13310
|
-
const final = acceptedAt ? accepted : rows.at(-1);
|
|
13311
|
-
const endedAt = final && timestamp(final);
|
|
13312
|
-
const wall = startedAt && endedAt ? Date.parse(endedAt) - Date.parse(startedAt) : void 0;
|
|
13313
|
-
if (wall !== void 0 && wall < 0) degradationReasons.push(`non-monotonic session timestamps in ${id}`);
|
|
13314
|
-
const degradationReason = degradationReasons.length ? degradationReasons.join("; ") : void 0;
|
|
13315
|
-
const complete = !!acceptedAt && !degradationReason && wall !== void 0 && wall >= 0;
|
|
13316
|
-
const session = complete ? { source: id, startedAt, endedAt, wallMilliseconds: wall, completion: "accepted" } : { source: id, ...startedAt ? { startedAt } : {}, ...endedAt ? { endedAt } : {}, ...wall !== void 0 && wall >= 0 ? { wallMilliseconds: wall } : {}, completion: "incomplete", ...degradationReason ? { degradationReason } : {} };
|
|
13317
|
-
return { session, turns, calls, tokens, statuses, commits };
|
|
13538
|
+
return { ok: true };
|
|
13318
13539
|
}
|
|
13319
|
-
|
|
13320
|
-
|
|
13321
|
-
if (projectRoot !== void 0 && !physicallyContainedIn(projectRoot, root)) {
|
|
13322
|
-
throw new Error("doctor --runs escapes the project root");
|
|
13323
|
-
}
|
|
13324
|
-
const match = root.split(sep2).join("/").match(/\/\.ak-roles\/books\/[^/]+\/(?:issues\/)?([1-9]\d*)\/runs$/);
|
|
13325
|
-
if (!match) throw new Error("Doctor case must be an .ak-roles/books/<book>/<n>/runs directory");
|
|
13326
|
-
const evidence = [], sessions = [], statuses = [], commits = [];
|
|
13327
|
-
const turns = { count: 0, sources: [] }, calls = { count: 0, sources: [] }, tokens = { count: 0, sources: [] };
|
|
13328
|
-
for (const path of await discoverCaseFiles(root)) {
|
|
13329
|
-
const id = relative2(root, path).split(sep2).join("/");
|
|
13330
|
-
const bytes = await readFile5(path);
|
|
13331
|
-
const content = bytes.toString("utf8");
|
|
13332
|
-
const kind = id.split("/").length === 2 && id.endsWith("/log.jsonl") ? "log" : "session";
|
|
13333
|
-
evidence.push({ id, kind, byteLength: bytes.byteLength, contentLength: content.length, sha256: sha256Hex(bytes), content });
|
|
13334
|
-
if (kind === "log") continue;
|
|
13335
|
-
const result = deriveSession(content, id);
|
|
13336
|
-
sessions.push(result.session);
|
|
13337
|
-
statuses.push(...result.statuses);
|
|
13338
|
-
commits.push(...result.commits);
|
|
13339
|
-
accumulate(turns, result.turns, id);
|
|
13340
|
-
accumulate(calls, result.calls, id);
|
|
13341
|
-
accumulate(tokens, result.tokens, id);
|
|
13342
|
-
}
|
|
13343
|
-
const runDirs = (await readdir2(root, { withFileTypes: true })).filter((item) => item.isDirectory()).map((item) => item.name).sort();
|
|
13344
|
-
const legs = evidence.filter((entry) => entry.kind === "session").map((entry) => entry.id);
|
|
13345
|
-
const retryDirs = runDirs.filter((name) => /(?:^|[-_])retry(?:[-_]|$)/i.test(name));
|
|
13346
|
-
const rawBytes = evidence.filter((entry) => entry.kind === "session").reduce((sum, entry) => sum + entry.byteLength, 0);
|
|
13347
|
-
const cost = { invocations: sourceList(runDirs.length, runDirs), legs: sourceList(legs.length, legs), modelApiTurns: sourceList(turns.count, turns.sources), outputTokens: sourceList(tokens.count, tokens.sources), toolCalls: sourceList(calls.count, calls.sources), retries: { ...sourceList(retryDirs.length, retryDirs), evidence: "literal run-dir naming" }, statuses, commits, sessions, outputBytes: { ...sourceList(rawBytes, legs), payload: "raw JSONL bytes", providerWireBytes: "unavailable" } };
|
|
13348
|
-
return { version: 1, identity: { issueNumber: Number(match[1]), runsPath: await stableRunsIdentity(root) }, evidence, cost };
|
|
13540
|
+
function bindOwner(owner, semantics) {
|
|
13541
|
+
return { ...semantics, owner };
|
|
13349
13542
|
}
|
|
13350
|
-
|
|
13351
|
-
|
|
13352
|
-
|
|
13353
|
-
|
|
13354
|
-
|
|
13355
|
-
init_terminating_tools();
|
|
13356
|
-
init_unknown_value();
|
|
13357
|
-
}
|
|
13358
|
-
});
|
|
13359
|
-
|
|
13360
|
-
// src/public-cli/github-remote.ts
|
|
13361
|
-
function ownerRepoFromGitHubRemoteUrl(remoteUrl) {
|
|
13362
|
-
const trimmed = remoteUrl.trim();
|
|
13363
|
-
const scp = /^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i.exec(trimmed);
|
|
13364
|
-
if (scp) {
|
|
13365
|
-
return `${scp[1]}/${stripGitSuffix(scp[2])}`;
|
|
13366
|
-
}
|
|
13367
|
-
const ssh = /^ssh:\/\/git@github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i.exec(
|
|
13368
|
-
trimmed
|
|
13369
|
-
);
|
|
13370
|
-
if (ssh) {
|
|
13371
|
-
return `${ssh[1]}/${stripGitSuffix(ssh[2])}`;
|
|
13372
|
-
}
|
|
13373
|
-
let parsed;
|
|
13374
|
-
try {
|
|
13375
|
-
parsed = new URL(trimmed);
|
|
13376
|
-
} catch {
|
|
13377
|
-
return void 0;
|
|
13378
|
-
}
|
|
13379
|
-
if (!/^github\.com$/i.test(parsed.hostname)) return void 0;
|
|
13380
|
-
if (parsed.search !== "" || parsed.hash !== "") return void 0;
|
|
13381
|
-
const parts = parsed.pathname.split("/").filter((p) => p.length > 0);
|
|
13382
|
-
if (parts.length !== 2) return void 0;
|
|
13383
|
-
return `${parts[0]}/${stripGitSuffix(parts[1])}`;
|
|
13543
|
+
function projectAndAttach(owner) {
|
|
13544
|
+
return [
|
|
13545
|
+
bindOwner(owner, SHARED_PROJECT_SEMANTICS),
|
|
13546
|
+
bindOwner(owner, SHARED_ATTACH_SEMANTICS)
|
|
13547
|
+
];
|
|
13384
13548
|
}
|
|
13385
|
-
function
|
|
13386
|
-
return
|
|
13549
|
+
function seatOptionRows(role) {
|
|
13550
|
+
return SEAT_OPTION_ROWS[role] ?? projectAndAttach(role);
|
|
13387
13551
|
}
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
|
|
13552
|
+
function publicOptionTable() {
|
|
13553
|
+
const roles = {};
|
|
13554
|
+
for (const role of PUBLIC_CALLABLE_ROLES) {
|
|
13555
|
+
roles[role] = seatOptionRows(role);
|
|
13391
13556
|
}
|
|
13392
|
-
}
|
|
13393
|
-
|
|
13394
|
-
// src/git-object-id.ts
|
|
13395
|
-
function isFullGitObjectId(value) {
|
|
13396
|
-
return typeof value === "string" && FULL_GIT_OBJECT_ID_RE.test(value);
|
|
13557
|
+
return { global: GLOBAL_OPTIONS, ...roles, analyst: ANALYST_OPTIONS };
|
|
13397
13558
|
}
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
"src/git-object-id.ts"() {
|
|
13401
|
-
"use strict";
|
|
13402
|
-
FULL_GIT_OBJECT_ID_RE = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
|
13403
|
-
}
|
|
13404
|
-
});
|
|
13405
|
-
|
|
13406
|
-
// src/merger-git-state.ts
|
|
13407
|
-
import { execFile } from "node:child_process";
|
|
13408
|
-
import { access, readFile as readFile6 } from "node:fs/promises";
|
|
13409
|
-
import { constants as fsConstants } from "node:fs";
|
|
13410
|
-
import { isAbsolute as isAbsolute3, resolve as resolve6 } from "node:path";
|
|
13411
|
-
import { promisify } from "node:util";
|
|
13412
|
-
async function git(cwd, args) {
|
|
13413
|
-
const { stdout } = await execFileAsync("git", args, { cwd, encoding: "buffer", maxBuffer: 16 * 1024 * 1024 });
|
|
13414
|
-
return new Uint8Array(stdout);
|
|
13559
|
+
function optionsForOwner(owner) {
|
|
13560
|
+
return PUBLIC_OPTION_TABLE[owner];
|
|
13415
13561
|
}
|
|
13416
|
-
function
|
|
13417
|
-
|
|
13418
|
-
|
|
13419
|
-
return value;
|
|
13562
|
+
function dashedSpellings(def) {
|
|
13563
|
+
if (def.form !== "option") return [];
|
|
13564
|
+
return [def.canonical, ...def.aliases];
|
|
13420
13565
|
}
|
|
13421
|
-
|
|
13422
|
-
|
|
13423
|
-
|
|
13424
|
-
|
|
13425
|
-
|
|
13426
|
-
|
|
13427
|
-
|
|
13566
|
+
function matchDashedOption(token, definitions) {
|
|
13567
|
+
if (!token.startsWith("-") || token === "-") return void 0;
|
|
13568
|
+
for (const def of definitions) {
|
|
13569
|
+
if (def.form !== "option") continue;
|
|
13570
|
+
for (const spelling of dashedSpellings(def)) {
|
|
13571
|
+
if (token === spelling) {
|
|
13572
|
+
return { def };
|
|
13573
|
+
}
|
|
13574
|
+
if (def.valueMetavar !== null && token.startsWith(`${spelling}=`)) {
|
|
13575
|
+
return { def, inlineValue: token.slice(spelling.length + 1) };
|
|
13576
|
+
}
|
|
13577
|
+
}
|
|
13428
13578
|
}
|
|
13579
|
+
return void 0;
|
|
13429
13580
|
}
|
|
13430
|
-
|
|
13431
|
-
const
|
|
13432
|
-
if (
|
|
13581
|
+
function takeDashedOption(tokens, definitions) {
|
|
13582
|
+
const token = tokens[0];
|
|
13583
|
+
if (token === void 0) return void 0;
|
|
13584
|
+
const matched = matchDashedOption(token, definitions);
|
|
13585
|
+
if (matched === void 0) return void 0;
|
|
13586
|
+
tokens.shift();
|
|
13587
|
+
if (matched.def.valueMetavar === null) {
|
|
13588
|
+
return { def: matched.def, value: void 0 };
|
|
13589
|
+
}
|
|
13590
|
+
if (matched.inlineValue !== void 0) {
|
|
13591
|
+
return { def: matched.def, value: matched.inlineValue };
|
|
13592
|
+
}
|
|
13593
|
+
return { def: matched.def, value: tokens.shift() };
|
|
13433
13594
|
}
|
|
13434
|
-
|
|
13435
|
-
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
if (error.code === 1) return void 0;
|
|
13441
|
-
throw error;
|
|
13442
|
-
}
|
|
13443
|
-
const oid = line(stdout, `Git ${rev}`);
|
|
13444
|
-
if (!isFullGitObjectId(oid)) throw new Error(`Git ${rev} identity is unavailable or invalid`);
|
|
13445
|
-
return oid;
|
|
13446
|
-
}
|
|
13447
|
-
async function unmerged(cwd) {
|
|
13448
|
-
const raw = exactUtf8(await git(cwd, ["ls-files", "-u", "-z"]), "Git unmerged index");
|
|
13449
|
-
const paths = /* @__PURE__ */ new Set();
|
|
13450
|
-
for (const row of raw.split("\0")) {
|
|
13451
|
-
if (!row) continue;
|
|
13452
|
-
const tab = row.indexOf(" ");
|
|
13453
|
-
if (tab < 0 || tab === row.length - 1) throw new Error("Git returned a malformed unmerged index row");
|
|
13454
|
-
paths.add(row.slice(tab + 1));
|
|
13455
|
-
}
|
|
13456
|
-
return [...paths].sort((a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)));
|
|
13457
|
-
}
|
|
13458
|
-
async function resolveHeadMaterial(cwd) {
|
|
13459
|
-
const commit = await tryResolveCommit(cwd, "HEAD");
|
|
13460
|
-
if (commit !== void 0) return commit;
|
|
13461
|
-
try {
|
|
13462
|
-
await execFileAsync("git", ["rev-parse", "--verify", "--quiet", "HEAD"], { cwd, encoding: "buffer", maxBuffer: 16 * 1024 * 1024 });
|
|
13463
|
-
} catch (error) {
|
|
13464
|
-
if (error.code === 1) return "";
|
|
13465
|
-
throw error;
|
|
13595
|
+
function matchPositionalOption(token, definitions) {
|
|
13596
|
+
for (const def of definitions) {
|
|
13597
|
+
if (def.form !== "positional") continue;
|
|
13598
|
+
if (def.canonical === token || def.aliases.includes(token)) {
|
|
13599
|
+
return def;
|
|
13600
|
+
}
|
|
13466
13601
|
}
|
|
13467
|
-
|
|
13602
|
+
return void 0;
|
|
13468
13603
|
}
|
|
13469
|
-
function
|
|
13604
|
+
function createTypedOptionConsumer(definitions) {
|
|
13605
|
+
const counts = /* @__PURE__ */ new Map();
|
|
13606
|
+
const note = (def) => {
|
|
13607
|
+
const next = (counts.get(def.id) ?? 0) + 1;
|
|
13608
|
+
counts.set(def.id, next);
|
|
13609
|
+
if (next > 1 && !def.repeatable) {
|
|
13610
|
+
throw new CliUsageError(`${def.canonical} cannot be repeated`);
|
|
13611
|
+
}
|
|
13612
|
+
};
|
|
13470
13613
|
return {
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
|
|
13474
|
-
|
|
13475
|
-
|
|
13476
|
-
|
|
13477
|
-
|
|
13478
|
-
|
|
13479
|
-
|
|
13480
|
-
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
13486
|
-
|
|
13487
|
-
|
|
13488
|
-
|
|
13614
|
+
takeDashed(tokens) {
|
|
13615
|
+
const taken = takeDashedOption(tokens, definitions);
|
|
13616
|
+
if (taken === void 0) return void 0;
|
|
13617
|
+
note(taken.def);
|
|
13618
|
+
return taken;
|
|
13619
|
+
},
|
|
13620
|
+
takePositional(token) {
|
|
13621
|
+
const def = matchPositionalOption(token, definitions);
|
|
13622
|
+
if (def === void 0) return void 0;
|
|
13623
|
+
note(def);
|
|
13624
|
+
return def;
|
|
13625
|
+
},
|
|
13626
|
+
consumeLeadingPhase(positional) {
|
|
13627
|
+
const phaseDef = definitions.find(
|
|
13628
|
+
(def) => def.id === "phase" && def.form === "positional"
|
|
13629
|
+
);
|
|
13630
|
+
const defaultPhase = phaseDef?.defaultValue === "plan" || phaseDef?.defaultValue === "apply" ? phaseDef.defaultValue : "apply";
|
|
13631
|
+
if (phaseDef === void 0 || positional.length === 0) {
|
|
13632
|
+
return defaultPhase;
|
|
13633
|
+
}
|
|
13634
|
+
const token = positional[0];
|
|
13635
|
+
if (!phaseDef.aliases.includes(token) && phaseDef.canonical !== token) {
|
|
13636
|
+
return defaultPhase;
|
|
13637
|
+
}
|
|
13638
|
+
positional.shift();
|
|
13639
|
+
note(phaseDef);
|
|
13640
|
+
if (token !== "plan" && token !== "apply") {
|
|
13641
|
+
throw new CliUsageError(`invalid phase token: ${token}`);
|
|
13642
|
+
}
|
|
13643
|
+
return token;
|
|
13644
|
+
},
|
|
13645
|
+
count(id) {
|
|
13646
|
+
return counts.get(id) ?? 0;
|
|
13647
|
+
},
|
|
13648
|
+
assertRequired() {
|
|
13649
|
+
for (const def of definitions) {
|
|
13650
|
+
if (!def.required) continue;
|
|
13651
|
+
if ((counts.get(def.id) ?? 0) > 0) continue;
|
|
13652
|
+
const suffix = def.valueMetavar === null ? "" : ` <${def.valueMetavar}>`;
|
|
13653
|
+
throw new CliUsageError(
|
|
13654
|
+
`${def.owner} requires ${def.canonical}${suffix}`
|
|
13655
|
+
);
|
|
13489
13656
|
}
|
|
13490
|
-
return { targetObjectId, sourceObjectId, unmergedPaths: await unmerged(repositoryRoot) };
|
|
13491
13657
|
}
|
|
13492
13658
|
};
|
|
13493
13659
|
}
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
13509
|
-
|
|
13510
|
-
}
|
|
13511
|
-
|
|
13512
|
-
|
|
13513
|
-
import { readFile as readFile7 } from "node:fs/promises";
|
|
13514
|
-
import { join as join11, resolve as resolve7 } from "node:path";
|
|
13515
|
-
function ticketProvenanceSubject(ticketNumber) {
|
|
13516
|
-
if (!isSafePositiveTicketNumber(ticketNumber)) {
|
|
13517
|
-
throw new Error(
|
|
13518
|
-
`ticket-provenance subject requires a positive ticket number, got ${String(ticketNumber)}`
|
|
13519
|
-
);
|
|
13520
|
-
}
|
|
13521
|
-
return String(ticketNumber);
|
|
13660
|
+
function projectOwnerOptions(owner) {
|
|
13661
|
+
return optionsForOwner(owner).map((def) => ({
|
|
13662
|
+
id: def.id,
|
|
13663
|
+
owner: def.owner,
|
|
13664
|
+
canonical: def.canonical,
|
|
13665
|
+
aliases: def.aliases,
|
|
13666
|
+
valueMetavar: def.valueMetavar,
|
|
13667
|
+
required: def.required,
|
|
13668
|
+
repeatable: def.repeatable,
|
|
13669
|
+
...def.defaultValue === void 0 ? {} : { defaultValue: def.defaultValue },
|
|
13670
|
+
form: def.form,
|
|
13671
|
+
...def.phases === void 0 ? {} : { phases: def.phases },
|
|
13672
|
+
...def.modes === void 0 ? {} : { modes: def.modes },
|
|
13673
|
+
...def.requiredInModes === void 0 ? {} : { requiredInModes: def.requiredInModes },
|
|
13674
|
+
...def.exclusiveWith === void 0 ? {} : { exclusiveWith: def.exclusiveWith },
|
|
13675
|
+
...def.maxCountByMode === void 0 ? {} : { maxCountByMode: def.maxCountByMode },
|
|
13676
|
+
...def.selectsMode === void 0 ? {} : { selectsMode: def.selectsMode },
|
|
13677
|
+
description: def.description
|
|
13678
|
+
}));
|
|
13522
13679
|
}
|
|
13523
|
-
function
|
|
13680
|
+
function projectCommandHelp(topic) {
|
|
13681
|
+
if (!(topic in PUBLIC_COMMAND_HELP)) return void 0;
|
|
13682
|
+
const facts = PUBLIC_COMMAND_HELP[topic];
|
|
13524
13683
|
return {
|
|
13525
|
-
|
|
13526
|
-
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
cwd,
|
|
13530
|
-
...home === void 0 ? {} : { home }
|
|
13684
|
+
command: facts.command,
|
|
13685
|
+
summary: facts.summary,
|
|
13686
|
+
usage: [...facts.usage],
|
|
13687
|
+
examples: [...facts.examples]
|
|
13531
13688
|
};
|
|
13532
13689
|
}
|
|
13533
|
-
|
|
13534
|
-
const
|
|
13535
|
-
|
|
13536
|
-
|
|
13537
|
-
|
|
13538
|
-
|
|
13539
|
-
|
|
13540
|
-
|
|
13541
|
-
|
|
13542
|
-
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
init_session_dialogue();
|
|
13560
|
-
init_sitian_facade();
|
|
13561
|
-
init_sitian_reader();
|
|
13562
|
-
init_ticket_provenance_contracts();
|
|
13563
|
-
init_unknown_value();
|
|
13564
|
-
}
|
|
13565
|
-
});
|
|
13566
|
-
|
|
13567
|
-
// src/uuidv7.ts
|
|
13568
|
-
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
13569
|
-
function isUuidV7(value) {
|
|
13570
|
-
return typeof value === "string" && UUIDV7.test(value);
|
|
13571
|
-
}
|
|
13572
|
-
function uuidv7(now = Date.now()) {
|
|
13573
|
-
const b = randomBytes2(16);
|
|
13574
|
-
let n = BigInt(now);
|
|
13575
|
-
for (let i = 5; i >= 0; i--) {
|
|
13576
|
-
b[i] = Number(n & 255n);
|
|
13577
|
-
n >>= 8n;
|
|
13690
|
+
function renderHumanOwnerOptionLines(owner, locale2 = "en") {
|
|
13691
|
+
const lines = [];
|
|
13692
|
+
for (const opt of projectOwnerOptions(owner)) {
|
|
13693
|
+
let spelling = opt.canonical;
|
|
13694
|
+
if (opt.valueMetavar !== null) {
|
|
13695
|
+
spelling = `${spelling} <${opt.valueMetavar}>`;
|
|
13696
|
+
}
|
|
13697
|
+
if (opt.aliases.length > 0) {
|
|
13698
|
+
const aliasHint = opt.aliases.join(", ");
|
|
13699
|
+
if (opt.form === "positional") {
|
|
13700
|
+
spelling = opt.aliases.join("|");
|
|
13701
|
+
} else {
|
|
13702
|
+
spelling = `${spelling} (${aliasHint})`;
|
|
13703
|
+
}
|
|
13704
|
+
}
|
|
13705
|
+
const tags = [];
|
|
13706
|
+
if (opt.required) tags.push("required");
|
|
13707
|
+
if (opt.requiredInModes !== void 0) {
|
|
13708
|
+
tags.push(`required:${opt.requiredInModes.join("|")}`);
|
|
13709
|
+
}
|
|
13710
|
+
if (opt.repeatable) tags.push("repeatable");
|
|
13711
|
+
if (opt.defaultValue !== void 0) tags.push(`default=${opt.defaultValue}`);
|
|
13712
|
+
if (opt.form === "positional") tags.push("positional");
|
|
13713
|
+
const tagText = tags.length === 0 ? "" : ` [${tags.join(", ")}]`;
|
|
13714
|
+
const desc = locale2 === "zh" ? opt.description.zh : opt.description.en;
|
|
13715
|
+
lines.push(` ${spelling}${tagText} ${desc}`);
|
|
13578
13716
|
}
|
|
13579
|
-
|
|
13580
|
-
b[8] = b[8] & 63 | 128;
|
|
13581
|
-
const h = b.toString("hex");
|
|
13582
|
-
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
|
|
13717
|
+
return lines;
|
|
13583
13718
|
}
|
|
13584
|
-
var
|
|
13585
|
-
var
|
|
13586
|
-
"src/
|
|
13587
|
-
"use strict";
|
|
13588
|
-
UUIDV7 = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
13589
|
-
}
|
|
13590
|
-
});
|
|
13591
|
-
|
|
13592
|
-
// src/notary-source-run.ts
|
|
13593
|
-
import { dirname as dirname8, isAbsolute as isAbsolute4, join as join12, resolve as resolve8, basename as basename7 } from "node:path";
|
|
13594
|
-
import { lstat as lstat2, realpath as realpath2 } from "node:fs/promises";
|
|
13595
|
-
async function readRetainedIdentity(runDirectory) {
|
|
13596
|
-
try {
|
|
13597
|
-
return await readRoleRunIdentity(runDirectory);
|
|
13598
|
-
} catch (error) {
|
|
13599
|
-
if (!(error instanceof TypeError || error instanceof SyntaxError)) throw error;
|
|
13600
|
-
throw new NotarySourceRunError("notary --source-run has invalid retained run-state identity", {
|
|
13601
|
-
cause: error
|
|
13602
|
-
});
|
|
13603
|
-
}
|
|
13604
|
-
}
|
|
13605
|
-
async function requireRunDirectory(candidate, display) {
|
|
13606
|
-
let real;
|
|
13607
|
-
try {
|
|
13608
|
-
real = await realpath2(candidate);
|
|
13609
|
-
} catch (error) {
|
|
13610
|
-
throw new NotarySourceRunError(
|
|
13611
|
-
`notary --source-run is not a readable run directory: ${display}`,
|
|
13612
|
-
{ cause: error }
|
|
13613
|
-
);
|
|
13614
|
-
}
|
|
13615
|
-
let stat2;
|
|
13616
|
-
try {
|
|
13617
|
-
stat2 = await lstat2(real);
|
|
13618
|
-
} catch (error) {
|
|
13619
|
-
throw new NotarySourceRunError(
|
|
13620
|
-
`notary --source-run is not a readable run directory: ${display}`,
|
|
13621
|
-
{ cause: error }
|
|
13622
|
-
);
|
|
13623
|
-
}
|
|
13624
|
-
if (!stat2.isDirectory()) {
|
|
13625
|
-
throw new NotarySourceRunError(
|
|
13626
|
-
`notary --source-run must be a run directory: ${display}`
|
|
13627
|
-
);
|
|
13628
|
-
}
|
|
13629
|
-
const identity = parseRunLeaf(basename7(real));
|
|
13630
|
-
if (identity === void 0) {
|
|
13631
|
-
throw new NotarySourceRunError(
|
|
13632
|
-
`notary --source-run must be named <runId>@<role>: ${basename7(real)}`
|
|
13633
|
-
);
|
|
13634
|
-
}
|
|
13635
|
-
return real;
|
|
13636
|
-
}
|
|
13637
|
-
async function resolveNotarySourceRunLocator(options) {
|
|
13638
|
-
const raw = options.sourceRun.trim();
|
|
13639
|
-
if (raw === "") {
|
|
13640
|
-
throw new NotarySourceRunError("notary --source-run requires a run locator");
|
|
13641
|
-
}
|
|
13642
|
-
const ledgerHome = resolveActivationLedgerHome(options.home);
|
|
13643
|
-
const bookKey = resolveBookKeyFromGit(options.projectRoot);
|
|
13644
|
-
const bookDirectory = activationBookDirectory(ledgerHome, bookKey);
|
|
13645
|
-
const bookRunsRoot = join12(bookDirectory, "runs");
|
|
13646
|
-
let candidate;
|
|
13647
|
-
const bare = parseRunLeaf(raw);
|
|
13648
|
-
if (bare !== void 0 && !raw.includes("/") && !raw.includes("\\")) {
|
|
13649
|
-
candidate = await findRunDirectoryById(options.home, bare.runId, bookKey, bare.role) ?? join12(bookRunsRoot, formatRunLeaf(bare.runId, bare.role));
|
|
13650
|
-
} else {
|
|
13651
|
-
candidate = isAbsolute4(raw) ? raw : resolve8(options.projectRoot, raw);
|
|
13652
|
-
const identity2 = parseRunLeaf(basename7(candidate));
|
|
13653
|
-
const subjectDirectory = dirname8(dirname8(candidate));
|
|
13654
|
-
const isLegacyUnboundLocator = identity2 !== void 0 && basename7(dirname8(candidate)) === "runs" && basename7(subjectDirectory) === "unbound" && resolve8(dirname8(subjectDirectory)) === resolve8(bookDirectory);
|
|
13655
|
-
if (isLegacyUnboundLocator) {
|
|
13656
|
-
candidate = await findRunDirectoryById(
|
|
13657
|
-
options.home,
|
|
13658
|
-
identity2.runId,
|
|
13659
|
-
bookKey,
|
|
13660
|
-
identity2.role
|
|
13661
|
-
) ?? candidate;
|
|
13662
|
-
}
|
|
13663
|
-
}
|
|
13664
|
-
const real = await requireRunDirectory(candidate, raw);
|
|
13665
|
-
const identity = parseRunLeaf(basename7(real));
|
|
13666
|
-
const bookIdentity = physicalPathIdentity(bookDirectory);
|
|
13667
|
-
const parentIdentity = physicalPathIdentity(dirname8(real));
|
|
13668
|
-
const subjectBookIdentity = physicalPathIdentity(dirname8(dirname8(dirname8(real))));
|
|
13669
|
-
if (parentIdentity !== physicalPathIdentity(bookRunsRoot) && !(basename7(dirname8(real)) === "runs" && subjectBookIdentity === bookIdentity)) {
|
|
13670
|
-
throw new NotarySourceRunError(
|
|
13671
|
-
"notary --source-run must resolve to a retained run under the project machine-ledger book"
|
|
13672
|
-
);
|
|
13673
|
-
}
|
|
13674
|
-
const runState = await readRetainedIdentity(real);
|
|
13675
|
-
if (runState === void 0) {
|
|
13676
|
-
throw new NotarySourceRunError(
|
|
13677
|
-
"notary --source-run lacks retained run-state identity"
|
|
13678
|
-
);
|
|
13679
|
-
}
|
|
13680
|
-
if (runState.runId !== identity.runId || runState.role !== identity.role) {
|
|
13681
|
-
throw new NotarySourceRunError(
|
|
13682
|
-
"notary --source-run retained identity does not match directory name"
|
|
13683
|
-
);
|
|
13684
|
-
}
|
|
13685
|
-
if (runState.bookKey !== bookKey) {
|
|
13686
|
-
throw new NotarySourceRunError(
|
|
13687
|
-
"notary --source-run retained book binding does not match project case"
|
|
13688
|
-
);
|
|
13689
|
-
}
|
|
13690
|
-
if (physicalPathIdentity(runState.runDirectory) !== physicalPathIdentity(real)) {
|
|
13691
|
-
throw new NotarySourceRunError(
|
|
13692
|
-
"notary --source-run retained runDirectory does not match locator path"
|
|
13693
|
-
);
|
|
13694
|
-
}
|
|
13695
|
-
return {
|
|
13696
|
-
runDirectory: real,
|
|
13697
|
-
runId: identity.runId,
|
|
13698
|
-
role: identity.role
|
|
13699
|
-
};
|
|
13700
|
-
}
|
|
13701
|
-
var NotarySourceRunError;
|
|
13702
|
-
var init_notary_source_run = __esm({
|
|
13703
|
-
"src/notary-source-run.ts"() {
|
|
13704
|
-
"use strict";
|
|
13705
|
-
init_activation_ledger_git();
|
|
13706
|
-
init_activation_ledger_topology();
|
|
13707
|
-
init_run_lifecycle();
|
|
13708
|
-
init_role_run_placement();
|
|
13709
|
-
NotarySourceRunError = class extends Error {
|
|
13710
|
-
constructor(message, options) {
|
|
13711
|
-
super(message, options);
|
|
13712
|
-
this.name = "NotarySourceRunError";
|
|
13713
|
-
}
|
|
13714
|
-
};
|
|
13715
|
-
}
|
|
13716
|
-
});
|
|
13717
|
-
|
|
13718
|
-
// src/public-cli/option-definitions.ts
|
|
13719
|
-
function resolveAnalystMode(presentOptionIds) {
|
|
13720
|
-
const selected = /* @__PURE__ */ new Set();
|
|
13721
|
-
for (const def of optionsForOwner("analyst")) {
|
|
13722
|
-
if (def.selectsMode === void 0) continue;
|
|
13723
|
-
if (presentOptionIds.has(def.id)) selected.add(def.selectsMode);
|
|
13724
|
-
}
|
|
13725
|
-
if (selected.size === 0) return ANALYST_DEFAULT_MODE;
|
|
13726
|
-
if (selected.has("cohort")) return "cohort";
|
|
13727
|
-
if (selected.has("sweep")) return "sweep";
|
|
13728
|
-
if (selected.has("issue")) return "issue";
|
|
13729
|
-
return ANALYST_DEFAULT_MODE;
|
|
13730
|
-
}
|
|
13731
|
-
function evaluateAnalystModeOptionContract(mode, counts) {
|
|
13732
|
-
const definitions = optionsForOwner("analyst");
|
|
13733
|
-
const byId = new Map(definitions.map((def) => [def.id, def]));
|
|
13734
|
-
for (const def of definitions) {
|
|
13735
|
-
const count = counts.get(def.id) ?? 0;
|
|
13736
|
-
if (count === 0 || def.exclusiveWith === void 0) continue;
|
|
13737
|
-
for (const otherId of def.exclusiveWith) {
|
|
13738
|
-
if ((counts.get(otherId) ?? 0) === 0) continue;
|
|
13739
|
-
const other = byId.get(otherId);
|
|
13740
|
-
return {
|
|
13741
|
-
ok: false,
|
|
13742
|
-
message: `analyst accepts only one of ${def.canonical} / ${other?.canonical ?? otherId}`
|
|
13743
|
-
};
|
|
13744
|
-
}
|
|
13745
|
-
}
|
|
13746
|
-
for (const def of definitions) {
|
|
13747
|
-
const count = counts.get(def.id) ?? 0;
|
|
13748
|
-
if (count === 0) continue;
|
|
13749
|
-
if (def.modes !== void 0 && !def.modes.includes(mode)) {
|
|
13750
|
-
if (mode === "sweep") {
|
|
13751
|
-
return {
|
|
13752
|
-
ok: false,
|
|
13753
|
-
message: `analyst sweep --attach cannot combine with ${def.canonical}`
|
|
13754
|
-
};
|
|
13755
|
-
}
|
|
13756
|
-
return {
|
|
13757
|
-
ok: false,
|
|
13758
|
-
message: `analyst ${mode} does not accept ${def.canonical}`
|
|
13759
|
-
};
|
|
13760
|
-
}
|
|
13761
|
-
const max = def.maxCountByMode?.[mode];
|
|
13762
|
-
if (max !== void 0 && count > max) {
|
|
13763
|
-
return {
|
|
13764
|
-
ok: false,
|
|
13765
|
-
message: max === 1 ? `analyst ${mode} accepts at most one ${def.canonical}` : `analyst ${mode} accepts at most ${max} ${def.canonical}`
|
|
13766
|
-
};
|
|
13767
|
-
}
|
|
13768
|
-
}
|
|
13769
|
-
const missingRequired = [];
|
|
13770
|
-
for (const def of definitions) {
|
|
13771
|
-
if (def.requiredInModes === void 0) continue;
|
|
13772
|
-
if (!def.requiredInModes.includes(mode)) continue;
|
|
13773
|
-
if ((counts.get(def.id) ?? 0) === 0) missingRequired.push(def);
|
|
13774
|
-
}
|
|
13775
|
-
if (missingRequired.length > 0) {
|
|
13776
|
-
if (mode === "cohort") {
|
|
13777
|
-
return {
|
|
13778
|
-
ok: false,
|
|
13779
|
-
message: "usage: ak-role analyst --cohort --group-a-label <L> --group-a-issues <N|book:N[,...]> --group-b-label <L> --group-b-issues <N|book:N[,...]>"
|
|
13780
|
-
};
|
|
13781
|
-
}
|
|
13782
|
-
return {
|
|
13783
|
-
ok: false,
|
|
13784
|
-
message: `usage: ak-role analyst ${mode} requires ${missingRequired.map((def) => def.canonical).join(" ")}`
|
|
13785
|
-
};
|
|
13786
|
-
}
|
|
13787
|
-
for (const rule of ANALYST_REQUIRE_ANY_OF) {
|
|
13788
|
-
if (rule.mode !== mode) continue;
|
|
13789
|
-
const hit = rule.optionIds.some((id) => (counts.get(id) ?? 0) > 0);
|
|
13790
|
-
if (hit) continue;
|
|
13791
|
-
if (mode === "issue") {
|
|
13792
|
-
return {
|
|
13793
|
-
ok: false,
|
|
13794
|
-
message: "usage: ak-role analyst ([--ticket <N>] | [sweep] --attach <sweep.json> | --cohort ...)"
|
|
13795
|
-
};
|
|
13796
|
-
}
|
|
13797
|
-
const flags = rule.optionIds.map((id) => byId.get(id)?.canonical ?? id).join(" | ");
|
|
13798
|
-
return {
|
|
13799
|
-
ok: false,
|
|
13800
|
-
message: `usage: ak-role analyst ${mode} requires one of ${flags}`
|
|
13801
|
-
};
|
|
13802
|
-
}
|
|
13803
|
-
return { ok: true };
|
|
13804
|
-
}
|
|
13805
|
-
function bindOwner(owner, semantics) {
|
|
13806
|
-
return { ...semantics, owner };
|
|
13807
|
-
}
|
|
13808
|
-
function projectAndAttach(owner) {
|
|
13809
|
-
return [
|
|
13810
|
-
bindOwner(owner, SHARED_PROJECT_SEMANTICS),
|
|
13811
|
-
bindOwner(owner, SHARED_ATTACH_SEMANTICS)
|
|
13812
|
-
];
|
|
13813
|
-
}
|
|
13814
|
-
function seatOptionRows(role) {
|
|
13815
|
-
return SEAT_OPTION_ROWS[role] ?? projectAndAttach(role);
|
|
13816
|
-
}
|
|
13817
|
-
function publicOptionTable() {
|
|
13818
|
-
const roles = {};
|
|
13819
|
-
for (const role of PUBLIC_CALLABLE_ROLES) {
|
|
13820
|
-
roles[role] = seatOptionRows(role);
|
|
13821
|
-
}
|
|
13822
|
-
return { global: GLOBAL_OPTIONS, ...roles, analyst: ANALYST_OPTIONS };
|
|
13823
|
-
}
|
|
13824
|
-
function optionsForOwner(owner) {
|
|
13825
|
-
return PUBLIC_OPTION_TABLE[owner];
|
|
13826
|
-
}
|
|
13827
|
-
function dashedSpellings(def) {
|
|
13828
|
-
if (def.form !== "option") return [];
|
|
13829
|
-
return [def.canonical, ...def.aliases];
|
|
13830
|
-
}
|
|
13831
|
-
function matchDashedOption(token, definitions) {
|
|
13832
|
-
if (!token.startsWith("-") || token === "-") return void 0;
|
|
13833
|
-
for (const def of definitions) {
|
|
13834
|
-
if (def.form !== "option") continue;
|
|
13835
|
-
for (const spelling of dashedSpellings(def)) {
|
|
13836
|
-
if (token === spelling) {
|
|
13837
|
-
return { def };
|
|
13838
|
-
}
|
|
13839
|
-
if (def.valueMetavar !== null && token.startsWith(`${spelling}=`)) {
|
|
13840
|
-
return { def, inlineValue: token.slice(spelling.length + 1) };
|
|
13841
|
-
}
|
|
13842
|
-
}
|
|
13843
|
-
}
|
|
13844
|
-
return void 0;
|
|
13845
|
-
}
|
|
13846
|
-
function takeDashedOption(tokens, definitions) {
|
|
13847
|
-
const token = tokens[0];
|
|
13848
|
-
if (token === void 0) return void 0;
|
|
13849
|
-
const matched = matchDashedOption(token, definitions);
|
|
13850
|
-
if (matched === void 0) return void 0;
|
|
13851
|
-
tokens.shift();
|
|
13852
|
-
if (matched.def.valueMetavar === null) {
|
|
13853
|
-
return { def: matched.def, value: void 0 };
|
|
13854
|
-
}
|
|
13855
|
-
if (matched.inlineValue !== void 0) {
|
|
13856
|
-
return { def: matched.def, value: matched.inlineValue };
|
|
13857
|
-
}
|
|
13858
|
-
return { def: matched.def, value: tokens.shift() };
|
|
13859
|
-
}
|
|
13860
|
-
function matchPositionalOption(token, definitions) {
|
|
13861
|
-
for (const def of definitions) {
|
|
13862
|
-
if (def.form !== "positional") continue;
|
|
13863
|
-
if (def.canonical === token || def.aliases.includes(token)) {
|
|
13864
|
-
return def;
|
|
13865
|
-
}
|
|
13866
|
-
}
|
|
13867
|
-
return void 0;
|
|
13868
|
-
}
|
|
13869
|
-
function createTypedOptionConsumer(definitions) {
|
|
13870
|
-
const counts = /* @__PURE__ */ new Map();
|
|
13871
|
-
const note = (def) => {
|
|
13872
|
-
const next = (counts.get(def.id) ?? 0) + 1;
|
|
13873
|
-
counts.set(def.id, next);
|
|
13874
|
-
if (next > 1 && !def.repeatable) {
|
|
13875
|
-
throw new CliUsageError(`${def.canonical} cannot be repeated`);
|
|
13876
|
-
}
|
|
13877
|
-
};
|
|
13878
|
-
return {
|
|
13879
|
-
takeDashed(tokens) {
|
|
13880
|
-
const taken = takeDashedOption(tokens, definitions);
|
|
13881
|
-
if (taken === void 0) return void 0;
|
|
13882
|
-
note(taken.def);
|
|
13883
|
-
return taken;
|
|
13884
|
-
},
|
|
13885
|
-
takePositional(token) {
|
|
13886
|
-
const def = matchPositionalOption(token, definitions);
|
|
13887
|
-
if (def === void 0) return void 0;
|
|
13888
|
-
note(def);
|
|
13889
|
-
return def;
|
|
13890
|
-
},
|
|
13891
|
-
consumeLeadingPhase(positional) {
|
|
13892
|
-
const phaseDef = definitions.find(
|
|
13893
|
-
(def) => def.id === "phase" && def.form === "positional"
|
|
13894
|
-
);
|
|
13895
|
-
const defaultPhase = phaseDef?.defaultValue === "plan" || phaseDef?.defaultValue === "apply" ? phaseDef.defaultValue : "apply";
|
|
13896
|
-
if (phaseDef === void 0 || positional.length === 0) {
|
|
13897
|
-
return defaultPhase;
|
|
13898
|
-
}
|
|
13899
|
-
const token = positional[0];
|
|
13900
|
-
if (!phaseDef.aliases.includes(token) && phaseDef.canonical !== token) {
|
|
13901
|
-
return defaultPhase;
|
|
13902
|
-
}
|
|
13903
|
-
positional.shift();
|
|
13904
|
-
note(phaseDef);
|
|
13905
|
-
if (token !== "plan" && token !== "apply") {
|
|
13906
|
-
throw new CliUsageError(`invalid phase token: ${token}`);
|
|
13907
|
-
}
|
|
13908
|
-
return token;
|
|
13909
|
-
},
|
|
13910
|
-
count(id) {
|
|
13911
|
-
return counts.get(id) ?? 0;
|
|
13912
|
-
},
|
|
13913
|
-
assertRequired() {
|
|
13914
|
-
for (const def of definitions) {
|
|
13915
|
-
if (!def.required) continue;
|
|
13916
|
-
if ((counts.get(def.id) ?? 0) > 0) continue;
|
|
13917
|
-
const suffix = def.valueMetavar === null ? "" : ` <${def.valueMetavar}>`;
|
|
13918
|
-
throw new CliUsageError(
|
|
13919
|
-
`${def.owner} requires ${def.canonical}${suffix}`
|
|
13920
|
-
);
|
|
13921
|
-
}
|
|
13922
|
-
}
|
|
13923
|
-
};
|
|
13924
|
-
}
|
|
13925
|
-
function projectOwnerOptions(owner) {
|
|
13926
|
-
return optionsForOwner(owner).map((def) => ({
|
|
13927
|
-
id: def.id,
|
|
13928
|
-
owner: def.owner,
|
|
13929
|
-
canonical: def.canonical,
|
|
13930
|
-
aliases: def.aliases,
|
|
13931
|
-
valueMetavar: def.valueMetavar,
|
|
13932
|
-
required: def.required,
|
|
13933
|
-
repeatable: def.repeatable,
|
|
13934
|
-
...def.defaultValue === void 0 ? {} : { defaultValue: def.defaultValue },
|
|
13935
|
-
form: def.form,
|
|
13936
|
-
...def.phases === void 0 ? {} : { phases: def.phases },
|
|
13937
|
-
...def.modes === void 0 ? {} : { modes: def.modes },
|
|
13938
|
-
...def.requiredInModes === void 0 ? {} : { requiredInModes: def.requiredInModes },
|
|
13939
|
-
...def.exclusiveWith === void 0 ? {} : { exclusiveWith: def.exclusiveWith },
|
|
13940
|
-
...def.maxCountByMode === void 0 ? {} : { maxCountByMode: def.maxCountByMode },
|
|
13941
|
-
...def.selectsMode === void 0 ? {} : { selectsMode: def.selectsMode },
|
|
13942
|
-
description: def.description
|
|
13943
|
-
}));
|
|
13944
|
-
}
|
|
13945
|
-
function projectCommandHelp(topic) {
|
|
13946
|
-
if (!(topic in PUBLIC_COMMAND_HELP)) return void 0;
|
|
13947
|
-
const facts = PUBLIC_COMMAND_HELP[topic];
|
|
13948
|
-
return {
|
|
13949
|
-
command: facts.command,
|
|
13950
|
-
summary: facts.summary,
|
|
13951
|
-
usage: [...facts.usage],
|
|
13952
|
-
examples: [...facts.examples]
|
|
13953
|
-
};
|
|
13954
|
-
}
|
|
13955
|
-
function renderHumanOwnerOptionLines(owner, locale2 = "en") {
|
|
13956
|
-
const lines = [];
|
|
13957
|
-
for (const opt of projectOwnerOptions(owner)) {
|
|
13958
|
-
let spelling = opt.canonical;
|
|
13959
|
-
if (opt.valueMetavar !== null) {
|
|
13960
|
-
spelling = `${spelling} <${opt.valueMetavar}>`;
|
|
13961
|
-
}
|
|
13962
|
-
if (opt.aliases.length > 0) {
|
|
13963
|
-
const aliasHint = opt.aliases.join(", ");
|
|
13964
|
-
if (opt.form === "positional") {
|
|
13965
|
-
spelling = opt.aliases.join("|");
|
|
13966
|
-
} else {
|
|
13967
|
-
spelling = `${spelling} (${aliasHint})`;
|
|
13968
|
-
}
|
|
13969
|
-
}
|
|
13970
|
-
const tags = [];
|
|
13971
|
-
if (opt.required) tags.push("required");
|
|
13972
|
-
if (opt.requiredInModes !== void 0) {
|
|
13973
|
-
tags.push(`required:${opt.requiredInModes.join("|")}`);
|
|
13974
|
-
}
|
|
13975
|
-
if (opt.repeatable) tags.push("repeatable");
|
|
13976
|
-
if (opt.defaultValue !== void 0) tags.push(`default=${opt.defaultValue}`);
|
|
13977
|
-
if (opt.form === "positional") tags.push("positional");
|
|
13978
|
-
const tagText = tags.length === 0 ? "" : ` [${tags.join(", ")}]`;
|
|
13979
|
-
const desc = locale2 === "zh" ? opt.description.zh : opt.description.en;
|
|
13980
|
-
lines.push(` ${spelling}${tagText} ${desc}`);
|
|
13981
|
-
}
|
|
13982
|
-
return lines;
|
|
13983
|
-
}
|
|
13984
|
-
var ANALYST_REQUIRE_ANY_OF, ANALYST_DEFAULT_MODE, REJECTED_PUBLIC_SPELLINGS, GLOBAL_OPTIONS, SHARED_PROJECT_SEMANTICS, SHARED_ATTACH_SEMANTICS, SHARED_PHASE_SEMANTICS, GLEANER_LEFT_OPTIONS, AUDITOR_OPTIONS, CODER_OPTIONS, FIXER_OPTIONS, REVIEWER_OPTIONS, COLLECTOR_OPTIONS, DOCTOR_OPTIONS, NOTARY_OPTIONS, INSPECTOR_OPTIONS, MERGER_OPTIONS, ANALYST_OPTIONS, SEAT_OPTION_ROWS, PUBLIC_OPTION_TABLE, PUBLIC_ROLE_OPTION_OWNERS, PUBLIC_NAVIGATOR_HELP_NOTE, TOP_LEVEL_HELP, ROLE_COMMAND_HELP, SUPPORT_COMMAND_HELP, PUBLIC_COMMAND_HELP;
|
|
13985
|
-
var init_option_definitions = __esm({
|
|
13986
|
-
"src/public-cli/option-definitions.ts"() {
|
|
13719
|
+
var ANALYST_REQUIRE_ANY_OF, ANALYST_DEFAULT_MODE, REJECTED_PUBLIC_SPELLINGS, GLOBAL_OPTIONS, SHARED_PROJECT_SEMANTICS, SHARED_ATTACH_SEMANTICS, SHARED_PHASE_SEMANTICS, GLEANER_LEFT_OPTIONS, AUDITOR_OPTIONS, CODER_OPTIONS, FIXER_OPTIONS, REVIEWER_OPTIONS, COLLECTOR_OPTIONS, DOCTOR_OPTIONS, NOTARY_OPTIONS, INSPECTOR_OPTIONS, MERGER_OPTIONS, ANALYST_OPTIONS, SEAT_OPTION_ROWS, PUBLIC_OPTION_TABLE, PUBLIC_ROLE_OPTION_OWNERS, PUBLIC_NAVIGATOR_HELP_NOTE, TOP_LEVEL_HELP, ROLE_COMMAND_HELP, SUPPORT_COMMAND_HELP, PUBLIC_COMMAND_HELP;
|
|
13720
|
+
var init_option_definitions = __esm({
|
|
13721
|
+
"src/public-cli/option-definitions.ts"() {
|
|
13987
13722
|
"use strict";
|
|
13988
13723
|
init_cli_errors();
|
|
13989
13724
|
init_registry();
|
|
@@ -14769,14 +14504,14 @@ var init_option_definitions = __esm({
|
|
|
14769
14504
|
|
|
14770
14505
|
// src/public-cli/invocation.ts
|
|
14771
14506
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
14772
|
-
import { existsSync as
|
|
14507
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
14773
14508
|
import {
|
|
14774
14509
|
readFile as readFile8,
|
|
14775
14510
|
realpath as realpath3,
|
|
14776
14511
|
rename,
|
|
14777
14512
|
writeFile as writeFile2
|
|
14778
14513
|
} from "node:fs/promises";
|
|
14779
|
-
import { dirname as dirname9, isAbsolute as isAbsolute5, join as join13, resolve as
|
|
14514
|
+
import { dirname as dirname9, isAbsolute as isAbsolute5, join as join13, resolve as resolve8 } from "node:path";
|
|
14780
14515
|
function normalizeAdmittedAttachment(raw) {
|
|
14781
14516
|
if (typeof raw !== "object" || raw === null) return void 0;
|
|
14782
14517
|
const record = raw;
|
|
@@ -14930,7 +14665,7 @@ async function relocateAdmittedRunToTicket(admitted, authority, heldLease) {
|
|
|
14930
14665
|
for (const childRunId of Array.isArray(childRunIds) ? childRunIds : []) {
|
|
14931
14666
|
if (typeof childRunId !== "string") continue;
|
|
14932
14667
|
const childDirectory = join13(dirname9(oldRunDirectory), formatRunLeaf(childRunId, "diarist"));
|
|
14933
|
-
if (!
|
|
14668
|
+
if (!existsSync2(childDirectory)) continue;
|
|
14934
14669
|
const childTarget = roleRunPlacement(ledgerHome, {
|
|
14935
14670
|
bookKey: admitted.bookKey,
|
|
14936
14671
|
subject: { ticketNumber: admitted.ticketNumber },
|
|
@@ -15362,7 +15097,7 @@ async function admitPublicRole(role, parsed, env, override) {
|
|
|
15362
15097
|
}
|
|
15363
15098
|
case "collect-target": {
|
|
15364
15099
|
const explicitPrNumber = parsed.prNumber;
|
|
15365
|
-
const projectRoot =
|
|
15100
|
+
const projectRoot = resolve8(parsed.project ?? shared.cwd);
|
|
15366
15101
|
let repository;
|
|
15367
15102
|
if (parsed.repo !== void 0) {
|
|
15368
15103
|
try {
|
|
@@ -15450,7 +15185,7 @@ async function admitPublicRole(role, parsed, env, override) {
|
|
|
15450
15185
|
});
|
|
15451
15186
|
}
|
|
15452
15187
|
case "source-locator": {
|
|
15453
|
-
const projectRoot =
|
|
15188
|
+
const projectRoot = resolve8(parsed.project ?? shared.cwd);
|
|
15454
15189
|
let sourceRun = override?.resolvedSourceRun;
|
|
15455
15190
|
if (sourceRun === void 0) {
|
|
15456
15191
|
try {
|
|
@@ -15526,7 +15261,7 @@ async function admitPublicRole(role, parsed, env, override) {
|
|
|
15526
15261
|
if (instruction.trim() === "") {
|
|
15527
15262
|
throw new CliUsageError("merger requires a nonblank task instruction");
|
|
15528
15263
|
}
|
|
15529
|
-
const projectRoot =
|
|
15264
|
+
const projectRoot = resolve8(parsed.project ?? shared.cwd);
|
|
15530
15265
|
const derived = await deriveMergerEnvelopeFromActiveMerge(
|
|
15531
15266
|
projectRoot,
|
|
15532
15267
|
createProductionMergerGitState(projectRoot)
|
|
@@ -15582,7 +15317,7 @@ function admissionSubject(ticketNumber) {
|
|
|
15582
15317
|
return { ticketNumber: fields.ticketNumber };
|
|
15583
15318
|
}
|
|
15584
15319
|
async function placeRoleAdmission(options) {
|
|
15585
|
-
const projectRoot =
|
|
15320
|
+
const projectRoot = resolve8(options.project ?? options.cwd);
|
|
15586
15321
|
const runId = options.runId ?? (options.createRunId ?? uuidv7)();
|
|
15587
15322
|
const ticketFields = ticketAdmissionFields(options.assertedTicketNumber);
|
|
15588
15323
|
const {
|
|
@@ -15729,394 +15464,822 @@ function buildInstructionTransportPrompt(admitted) {
|
|
|
15729
15464
|
}
|
|
15730
15465
|
return lines.join("\n");
|
|
15731
15466
|
}
|
|
15732
|
-
return appendCallerFileFlagPaths(
|
|
15733
|
-
admitted.instruction,
|
|
15734
|
-
admitted.attachments,
|
|
15735
|
-
admitted.requestManifestPath,
|
|
15736
|
-
admitted.prerequisitesPath
|
|
15737
|
-
);
|
|
15467
|
+
return appendCallerFileFlagPaths(
|
|
15468
|
+
admitted.instruction,
|
|
15469
|
+
admitted.attachments,
|
|
15470
|
+
admitted.requestManifestPath,
|
|
15471
|
+
admitted.prerequisitesPath
|
|
15472
|
+
);
|
|
15473
|
+
}
|
|
15474
|
+
async function materializeCountersignInvocation(admitted, options) {
|
|
15475
|
+
const placed = await placeRoleAdmission({
|
|
15476
|
+
role: "countersign",
|
|
15477
|
+
home: options.home,
|
|
15478
|
+
principalAuthority: options.principalAuthority,
|
|
15479
|
+
cwd: admitted.projectRoot,
|
|
15480
|
+
attachmentPaths: options.attachmentPaths,
|
|
15481
|
+
runId: admitted.runId,
|
|
15482
|
+
...options.ticketNumber === void 0 ? {} : { assertedTicketNumber: options.ticketNumber }
|
|
15483
|
+
});
|
|
15484
|
+
const placement = placed;
|
|
15485
|
+
admitted.runDirectory = placement.runDirectory;
|
|
15486
|
+
admitted.principal = placement.principal;
|
|
15487
|
+
const ticketFields = ticketAdmissionFields(options.ticketNumber);
|
|
15488
|
+
if (ticketFields.ticketNumber !== void 0) {
|
|
15489
|
+
admitted.ticketNumber = ticketFields.ticketNumber;
|
|
15490
|
+
}
|
|
15491
|
+
admitted.attachments = placement.attachments;
|
|
15492
|
+
writeAdmittedRequestPersistence(admitted.runDirectory, admitted, {
|
|
15493
|
+
sessionDirectory: placement.sessionDirectory,
|
|
15494
|
+
sessionFile: placement.sessionFile
|
|
15495
|
+
});
|
|
15496
|
+
await writeRoleInvocationLedger(
|
|
15497
|
+
{ ...admitted, sessionDirectory: placement.sessionDirectory, sessionFile: placement.sessionFile },
|
|
15498
|
+
admitted.role,
|
|
15499
|
+
options.model
|
|
15500
|
+
);
|
|
15501
|
+
}
|
|
15502
|
+
function parsePositivePrOption(raw) {
|
|
15503
|
+
if (raw === void 0 || raw.trim() === "") throw new CliUsageError("--pr requires a positive pull request number");
|
|
15504
|
+
try {
|
|
15505
|
+
return parseCollectorPrNumber(raw);
|
|
15506
|
+
} catch (error) {
|
|
15507
|
+
throw new CliUsageError(errorText(error), { cause: error });
|
|
15508
|
+
}
|
|
15509
|
+
}
|
|
15510
|
+
function parseRepoOption(raw) {
|
|
15511
|
+
if (raw === void 0 || raw.trim() === "") throw new CliUsageError("--repo requires owner/repo");
|
|
15512
|
+
return raw;
|
|
15513
|
+
}
|
|
15514
|
+
function resolveGitHubRemoteRepository(projectRoot) {
|
|
15515
|
+
let remoteUrl;
|
|
15516
|
+
try {
|
|
15517
|
+
remoteUrl = execFileSync2("git", ["remote", "get-url", "origin"], {
|
|
15518
|
+
cwd: projectRoot,
|
|
15519
|
+
encoding: "utf8",
|
|
15520
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
15521
|
+
}).trim();
|
|
15522
|
+
} catch (error) {
|
|
15523
|
+
if (isGitRemoteMissing(error)) {
|
|
15524
|
+
throw new CliUsageError(
|
|
15525
|
+
"collector requires a github.com origin remote or an explicit --repo owner/repo",
|
|
15526
|
+
{ cause: error }
|
|
15527
|
+
);
|
|
15528
|
+
}
|
|
15529
|
+
throw new Error("collector git failed: cannot read origin remote URL", {
|
|
15530
|
+
cause: error instanceof Error ? error : new Error(String(error))
|
|
15531
|
+
});
|
|
15532
|
+
}
|
|
15533
|
+
if (remoteUrl.length === 0) {
|
|
15534
|
+
throw new CliUsageError(
|
|
15535
|
+
"collector requires a github.com origin remote or an explicit --repo owner/repo"
|
|
15536
|
+
);
|
|
15537
|
+
}
|
|
15538
|
+
const ownerRepo = ownerRepoFromGitHubRemoteUrl(remoteUrl);
|
|
15539
|
+
if (ownerRepo === void 0) {
|
|
15540
|
+
throw new CliUsageError(
|
|
15541
|
+
`collector origin remote must be a github.com owner/repo URL, got ${remoteUrl}`
|
|
15542
|
+
);
|
|
15543
|
+
}
|
|
15544
|
+
try {
|
|
15545
|
+
return parseCollectorRepository(ownerRepo);
|
|
15546
|
+
} catch (error) {
|
|
15547
|
+
const detail = errorText(error);
|
|
15548
|
+
throw new CliUsageError(detail, { cause: error });
|
|
15549
|
+
}
|
|
15550
|
+
}
|
|
15551
|
+
function isGitRemoteMissing(error) {
|
|
15552
|
+
if (typeof error !== "object" || error === null) return false;
|
|
15553
|
+
const status = error.status;
|
|
15554
|
+
return status === 2;
|
|
15555
|
+
}
|
|
15556
|
+
function parseDoctorIssueNumber(raw) {
|
|
15557
|
+
return rejectUnlessTicketNumber(
|
|
15558
|
+
raw,
|
|
15559
|
+
`doctor --issue must be a positive integer, got ${raw}`
|
|
15560
|
+
);
|
|
15561
|
+
}
|
|
15562
|
+
async function resolveDoctorCaseRunsPath(options) {
|
|
15563
|
+
const ledgerHome = resolveActivationLedgerHome(options.home);
|
|
15564
|
+
const defaultRuns = join13(
|
|
15565
|
+
activationBookDirectory(ledgerHome, options.bookKey),
|
|
15566
|
+
String(options.issueNumber),
|
|
15567
|
+
"runs"
|
|
15568
|
+
);
|
|
15569
|
+
if (options.runs === void 0) {
|
|
15570
|
+
return defaultRuns;
|
|
15571
|
+
}
|
|
15572
|
+
const raw = options.runs.trim();
|
|
15573
|
+
if (raw === "") {
|
|
15574
|
+
throw new CliUsageError("doctor --runs requires a path");
|
|
15575
|
+
}
|
|
15576
|
+
if (isAbsolute5(raw)) {
|
|
15577
|
+
throw new CliUsageError(
|
|
15578
|
+
"doctor --runs must be a project-relative path"
|
|
15579
|
+
);
|
|
15580
|
+
}
|
|
15581
|
+
const resolved = resolve8(options.projectRoot, raw);
|
|
15582
|
+
if (resolved !== options.projectRoot && !pathContainedIn(options.projectRoot, resolved)) {
|
|
15583
|
+
throw new CliUsageError(
|
|
15584
|
+
"doctor --runs escapes the project root"
|
|
15585
|
+
);
|
|
15586
|
+
}
|
|
15587
|
+
let real;
|
|
15588
|
+
try {
|
|
15589
|
+
real = await realpath3(resolved);
|
|
15590
|
+
} catch (error) {
|
|
15591
|
+
const detail = errorText(error);
|
|
15592
|
+
throw new CliUsageError(
|
|
15593
|
+
`doctor --runs is not a readable retained runs root: ${detail}`,
|
|
15594
|
+
{ cause: error }
|
|
15595
|
+
);
|
|
15596
|
+
}
|
|
15597
|
+
return real;
|
|
15598
|
+
}
|
|
15599
|
+
function buildReviewerSkillArgProjection(admitted) {
|
|
15600
|
+
return [
|
|
15601
|
+
`--base ${admitted.baseRevision}`,
|
|
15602
|
+
`--lens ${admitted.lens}`,
|
|
15603
|
+
...admitted.authorityRefs.map((ref) => `--authority ${ref}`)
|
|
15604
|
+
].join(" ");
|
|
15605
|
+
}
|
|
15606
|
+
function mergerMaterialFromUtf8(text) {
|
|
15607
|
+
const bytes = Buffer.from(text, "utf8");
|
|
15608
|
+
return Object.freeze({
|
|
15609
|
+
bytesBase64: bytes.toString("base64"),
|
|
15610
|
+
sha256: sha256Hex(bytes)
|
|
15611
|
+
});
|
|
15612
|
+
}
|
|
15613
|
+
async function deriveMergerEnvelopeFromActiveMerge(projectRoot, gitState = createProductionMergerGitState(projectRoot)) {
|
|
15614
|
+
const state = await gitState.activeMerge();
|
|
15615
|
+
const expectedConflictPaths = Object.freeze([...state.unmergedPaths]);
|
|
15616
|
+
const resolutionScope = Object.freeze([...state.unmergedPaths]);
|
|
15617
|
+
return Object.freeze({
|
|
15618
|
+
targetObjectId: state.targetObjectId,
|
|
15619
|
+
sourceObjectId: state.sourceObjectId,
|
|
15620
|
+
expectedConflictPaths,
|
|
15621
|
+
resolutionScope
|
|
15622
|
+
});
|
|
15623
|
+
}
|
|
15624
|
+
function parseAnalystTicketNumber(raw, flag = "--ticket") {
|
|
15625
|
+
return rejectUnlessTicketNumber(
|
|
15626
|
+
raw,
|
|
15627
|
+
`analyst ${flag} must be a positive integer, got ${raw}`
|
|
15628
|
+
);
|
|
15629
|
+
}
|
|
15630
|
+
function parseAnalystCohortIssueToken(raw, flag) {
|
|
15631
|
+
const trimmed = raw.trim();
|
|
15632
|
+
if (trimmed === "") {
|
|
15633
|
+
throw new CliUsageError(
|
|
15634
|
+
`${flag} requires a comma-separated list of N or book:N`
|
|
15635
|
+
);
|
|
15636
|
+
}
|
|
15637
|
+
const sep5 = trimmed.lastIndexOf(":");
|
|
15638
|
+
if (sep5 > 0) {
|
|
15639
|
+
const rhs = trimmed.slice(sep5 + 1);
|
|
15640
|
+
if (parseTicketNumber(rhs) !== void 0) {
|
|
15641
|
+
const bookKey = trimmed.slice(0, sep5);
|
|
15642
|
+
if (bookKey.trim() === "") {
|
|
15643
|
+
throw new CliUsageError(
|
|
15644
|
+
`${flag} book:N requires a non-empty book key, got ${raw}`
|
|
15645
|
+
);
|
|
15646
|
+
}
|
|
15647
|
+
return {
|
|
15648
|
+
kind: "book-qualified",
|
|
15649
|
+
bookKey,
|
|
15650
|
+
issueNumber: parseAnalystTicketNumber(rhs, flag)
|
|
15651
|
+
};
|
|
15652
|
+
}
|
|
15653
|
+
}
|
|
15654
|
+
return {
|
|
15655
|
+
kind: "bare",
|
|
15656
|
+
issueNumber: parseAnalystTicketNumber(trimmed, flag)
|
|
15657
|
+
};
|
|
15658
|
+
}
|
|
15659
|
+
function splitAnalystCohortIssueListParts(raw) {
|
|
15660
|
+
const parts = [];
|
|
15661
|
+
let current = "";
|
|
15662
|
+
let escaped = false;
|
|
15663
|
+
for (const ch of raw) {
|
|
15664
|
+
if (escaped) {
|
|
15665
|
+
current += ch === "," || ch === "\\" ? ch : `\\${ch}`;
|
|
15666
|
+
escaped = false;
|
|
15667
|
+
continue;
|
|
15668
|
+
}
|
|
15669
|
+
if (ch === "\\") {
|
|
15670
|
+
escaped = true;
|
|
15671
|
+
continue;
|
|
15672
|
+
}
|
|
15673
|
+
if (ch === ",") {
|
|
15674
|
+
parts.push(current);
|
|
15675
|
+
current = "";
|
|
15676
|
+
continue;
|
|
15677
|
+
}
|
|
15678
|
+
current += ch;
|
|
15679
|
+
}
|
|
15680
|
+
parts.push(escaped ? `${current}\\` : current);
|
|
15681
|
+
return parts;
|
|
15738
15682
|
}
|
|
15739
|
-
|
|
15740
|
-
const
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
attachmentPaths: options.attachmentPaths,
|
|
15746
|
-
runId: admitted.runId,
|
|
15747
|
-
...options.ticketNumber === void 0 ? {} : { assertedTicketNumber: options.ticketNumber }
|
|
15748
|
-
});
|
|
15749
|
-
const placement = placed;
|
|
15750
|
-
admitted.runDirectory = placement.runDirectory;
|
|
15751
|
-
admitted.principal = placement.principal;
|
|
15752
|
-
const ticketFields = ticketAdmissionFields(options.ticketNumber);
|
|
15753
|
-
if (ticketFields.ticketNumber !== void 0) {
|
|
15754
|
-
admitted.ticketNumber = ticketFields.ticketNumber;
|
|
15683
|
+
function parseAnalystCohortIssueTokenList(raw, flag) {
|
|
15684
|
+
const trimmed = raw.trim();
|
|
15685
|
+
if (trimmed === "") {
|
|
15686
|
+
throw new CliUsageError(
|
|
15687
|
+
`${flag} requires a comma-separated list of N or book:N`
|
|
15688
|
+
);
|
|
15755
15689
|
}
|
|
15756
|
-
|
|
15757
|
-
|
|
15758
|
-
sessionDirectory: placement.sessionDirectory,
|
|
15759
|
-
sessionFile: placement.sessionFile
|
|
15760
|
-
});
|
|
15761
|
-
await writeRoleInvocationLedger(
|
|
15762
|
-
{ ...admitted, sessionDirectory: placement.sessionDirectory, sessionFile: placement.sessionFile },
|
|
15763
|
-
admitted.role,
|
|
15764
|
-
options.model
|
|
15690
|
+
const parts = splitAnalystCohortIssueListParts(trimmed).map(
|
|
15691
|
+
(part) => part.trim()
|
|
15765
15692
|
);
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
return parseCollectorPrNumber(raw);
|
|
15771
|
-
} catch (error) {
|
|
15772
|
-
throw new CliUsageError(errorText(error), { cause: error });
|
|
15693
|
+
if (parts.some((part) => part === "")) {
|
|
15694
|
+
throw new CliUsageError(
|
|
15695
|
+
`${flag} requires a comma-separated list of N or book:N`
|
|
15696
|
+
);
|
|
15773
15697
|
}
|
|
15698
|
+
return parts.map((part) => parseAnalystCohortIssueToken(part, flag));
|
|
15774
15699
|
}
|
|
15775
|
-
function
|
|
15776
|
-
if (
|
|
15777
|
-
|
|
15700
|
+
function requireOptionValue(flag, value, what) {
|
|
15701
|
+
if (value === void 0 || value.trim() === "") {
|
|
15702
|
+
throw new CliUsageError(`${flag} requires ${what}`);
|
|
15703
|
+
}
|
|
15704
|
+
return value;
|
|
15778
15705
|
}
|
|
15779
|
-
function
|
|
15780
|
-
|
|
15781
|
-
|
|
15782
|
-
|
|
15783
|
-
|
|
15784
|
-
|
|
15785
|
-
|
|
15786
|
-
|
|
15787
|
-
}
|
|
15788
|
-
|
|
15789
|
-
|
|
15790
|
-
|
|
15791
|
-
|
|
15792
|
-
|
|
15706
|
+
function parseAnalystArgv(args) {
|
|
15707
|
+
const valueLists = /* @__PURE__ */ new Map();
|
|
15708
|
+
const definitions = roleOptions("analyst");
|
|
15709
|
+
const options = createTypedOptionConsumer(definitions);
|
|
15710
|
+
const pushValue = (id, value) => {
|
|
15711
|
+
const existing = valueLists.get(id);
|
|
15712
|
+
if (existing === void 0) valueLists.set(id, [value]);
|
|
15713
|
+
else existing.push(value);
|
|
15714
|
+
};
|
|
15715
|
+
scanPublicArgv(args, options, {
|
|
15716
|
+
onDashed(taken) {
|
|
15717
|
+
if (taken.def.valueMetavar === null) {
|
|
15718
|
+
pushValue(taken.def.id, "");
|
|
15719
|
+
return;
|
|
15720
|
+
}
|
|
15721
|
+
if (taken.def.id === "ticket") {
|
|
15722
|
+
if (taken.value === void 0 || taken.value.trim() === "") {
|
|
15723
|
+
throw new CliUsageError("analyst --ticket requires a positive integer");
|
|
15724
|
+
}
|
|
15725
|
+
pushValue("ticket", taken.value);
|
|
15726
|
+
return;
|
|
15727
|
+
}
|
|
15728
|
+
if (taken.def.id === "attach") {
|
|
15729
|
+
pushValue(
|
|
15730
|
+
"attach",
|
|
15731
|
+
requireProvidedOptionValue(taken.def.canonical, taken.value)
|
|
15732
|
+
);
|
|
15733
|
+
return;
|
|
15734
|
+
}
|
|
15735
|
+
if (taken.def.id === "group-a-label" || taken.def.id === "group-b-label") {
|
|
15736
|
+
pushValue(
|
|
15737
|
+
taken.def.id,
|
|
15738
|
+
requireOptionValue(taken.def.canonical, taken.value, "a label")
|
|
15739
|
+
);
|
|
15740
|
+
return;
|
|
15741
|
+
}
|
|
15742
|
+
if (taken.def.id === "group-a-issues" || taken.def.id === "group-b-issues") {
|
|
15743
|
+
pushValue(
|
|
15744
|
+
taken.def.id,
|
|
15745
|
+
requireOptionValue(
|
|
15746
|
+
taken.def.canonical,
|
|
15747
|
+
taken.value,
|
|
15748
|
+
"a comma-separated list of N or book:N"
|
|
15749
|
+
)
|
|
15750
|
+
);
|
|
15751
|
+
return;
|
|
15752
|
+
}
|
|
15753
|
+
throw new CliUsageError(`unknown analyst option: ${taken.def.canonical}`);
|
|
15754
|
+
},
|
|
15755
|
+
onBare(token) {
|
|
15756
|
+
if (isRejectedPublicSpelling("analyst", token)) {
|
|
15757
|
+
if (token === "--project-root" || token.startsWith("--project-root=")) {
|
|
15758
|
+
throw new CliUsageError(
|
|
15759
|
+
"analyst no longer accepts --project-root (deleted); use bare call for whole book or --ticket N (cwd git common-dir selects the book)"
|
|
15760
|
+
);
|
|
15761
|
+
}
|
|
15762
|
+
if (token === "--model-groups" || token.startsWith("--model-groups=")) {
|
|
15763
|
+
throw new CliUsageError(
|
|
15764
|
+
"analyst --model-groups public CLI face is disabled; input face is being redesigned for multi-issue comparison (see follow-up ticket)"
|
|
15765
|
+
);
|
|
15766
|
+
}
|
|
15767
|
+
throw new CliUsageError(`unknown analyst option: ${token}`);
|
|
15768
|
+
}
|
|
15769
|
+
if (token.startsWith("-") && token !== "-") {
|
|
15770
|
+
throw new CliUsageError(`unknown analyst option: ${token}`);
|
|
15771
|
+
}
|
|
15772
|
+
const positional = options.takePositional(token);
|
|
15773
|
+
if (positional !== void 0) {
|
|
15774
|
+
pushValue(positional.id, "");
|
|
15775
|
+
return;
|
|
15776
|
+
}
|
|
15777
|
+
throw new CliUsageError(`unexpected analyst argument: ${token}`);
|
|
15778
|
+
},
|
|
15779
|
+
onDoubleDash(rest) {
|
|
15780
|
+
if (rest.length > 0) {
|
|
15781
|
+
throw new CliUsageError(`unexpected analyst argument: ${rest[0]}`);
|
|
15782
|
+
}
|
|
15793
15783
|
}
|
|
15794
|
-
|
|
15795
|
-
|
|
15796
|
-
|
|
15784
|
+
});
|
|
15785
|
+
const counts = /* @__PURE__ */ new Map();
|
|
15786
|
+
for (const [id, values] of valueLists) {
|
|
15787
|
+
counts.set(id, values.length);
|
|
15797
15788
|
}
|
|
15798
|
-
|
|
15799
|
-
|
|
15800
|
-
|
|
15801
|
-
|
|
15789
|
+
options.assertRequired();
|
|
15790
|
+
const mode = resolveAnalystMode(new Set(counts.keys()));
|
|
15791
|
+
const verdict = evaluateAnalystModeOptionContract(mode, counts);
|
|
15792
|
+
if (!verdict.ok) {
|
|
15793
|
+
throw new CliUsageError(verdict.message);
|
|
15802
15794
|
}
|
|
15803
|
-
|
|
15804
|
-
|
|
15805
|
-
|
|
15806
|
-
|
|
15795
|
+
if (mode === "cohort") {
|
|
15796
|
+
const groupALabel = valueLists.get("group-a-label")[0];
|
|
15797
|
+
const groupAIssuesRaw = valueLists.get("group-a-issues")[0];
|
|
15798
|
+
const groupBLabel = valueLists.get("group-b-label")[0];
|
|
15799
|
+
const groupBIssuesRaw = valueLists.get("group-b-issues")[0];
|
|
15800
|
+
return {
|
|
15801
|
+
query: "cohort",
|
|
15802
|
+
groups: [
|
|
15803
|
+
{
|
|
15804
|
+
groupLabel: groupALabel,
|
|
15805
|
+
issues: parseAnalystCohortIssueTokenList(
|
|
15806
|
+
groupAIssuesRaw,
|
|
15807
|
+
"--group-a-issues"
|
|
15808
|
+
)
|
|
15809
|
+
},
|
|
15810
|
+
{
|
|
15811
|
+
groupLabel: groupBLabel,
|
|
15812
|
+
issues: parseAnalystCohortIssueTokenList(
|
|
15813
|
+
groupBIssuesRaw,
|
|
15814
|
+
"--group-b-issues"
|
|
15815
|
+
)
|
|
15816
|
+
}
|
|
15817
|
+
]
|
|
15818
|
+
};
|
|
15819
|
+
}
|
|
15820
|
+
if (mode === "sweep") {
|
|
15821
|
+
return {
|
|
15822
|
+
query: "sweep",
|
|
15823
|
+
attachmentPaths: valueLists.get("attach") ?? []
|
|
15824
|
+
};
|
|
15825
|
+
}
|
|
15826
|
+
const ticketRaw = valueLists.get("ticket")?.[0];
|
|
15827
|
+
return {
|
|
15828
|
+
query: "issue",
|
|
15829
|
+
...ticketRaw === void 0 ? {} : { ticket: parseAnalystTicketNumber(ticketRaw) }
|
|
15830
|
+
};
|
|
15831
|
+
}
|
|
15832
|
+
var init_invocation = __esm({
|
|
15833
|
+
"src/public-cli/invocation.ts"() {
|
|
15834
|
+
"use strict";
|
|
15835
|
+
init_activation_ledger_topology();
|
|
15836
|
+
init_activation_ledger_git();
|
|
15837
|
+
init_role_run_placement();
|
|
15838
|
+
init_packaged_role_registry();
|
|
15839
|
+
init_run_ticket_number();
|
|
15840
|
+
init_role_run_relocation();
|
|
15841
|
+
init_run_dossier();
|
|
15842
|
+
init_doctor_evidence();
|
|
15843
|
+
init_collector_config();
|
|
15844
|
+
init_github_remote();
|
|
15845
|
+
init_merger_git_state();
|
|
15846
|
+
init_merger_contracts();
|
|
15847
|
+
init_sha256();
|
|
15848
|
+
init_ticket_provenance();
|
|
15849
|
+
init_uuidv7();
|
|
15850
|
+
init_notary_contracts();
|
|
15851
|
+
init_notary_source_run();
|
|
15852
|
+
init_cli_errors();
|
|
15853
|
+
init_option_definitions();
|
|
15854
|
+
init_unknown_value();
|
|
15855
|
+
}
|
|
15856
|
+
});
|
|
15857
|
+
|
|
15858
|
+
// src/report-ticket-tool.ts
|
|
15859
|
+
var reportTicketArgsSchema, MISSING_TICKET_REASK_MATERIAL;
|
|
15860
|
+
var init_report_ticket_tool = __esm({
|
|
15861
|
+
"src/report-ticket-tool.ts"() {
|
|
15862
|
+
"use strict";
|
|
15863
|
+
init_build();
|
|
15864
|
+
init_host_contracts();
|
|
15865
|
+
init_durable_principal();
|
|
15866
|
+
init_invocation();
|
|
15867
|
+
init_role_run_placement();
|
|
15868
|
+
init_role_run_path_rewrite();
|
|
15869
|
+
init_run_dossier();
|
|
15870
|
+
init_run_ticket_number();
|
|
15871
|
+
init_unknown_value();
|
|
15872
|
+
reportTicketArgsSchema = typebox_exports.Object(
|
|
15873
|
+
{
|
|
15874
|
+
ticketNumber: typebox_exports.Unknown({
|
|
15875
|
+
description: "\u672C\u7968\u53F7\uFF08\u6B63\u6574\u6570\u3001\u6570\u5B57\u4E32\u6216\u524D\u5BFC #N\uFF09\u3002\u5DF2\u77E5\u7968\u53F7\u65F6\u5F00\u5DE5\u5373\u62A5\uFF1B\u5C1A\u65E0\u7968\u53F7\u65F6\u4E0D\u8981\u8C03\u7528\u3002"
|
|
15876
|
+
})
|
|
15877
|
+
},
|
|
15878
|
+
{ additionalProperties: true }
|
|
15807
15879
|
);
|
|
15880
|
+
MISSING_TICKET_REASK_MATERIAL = "resources/missing-ticket-reask.md";
|
|
15808
15881
|
}
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
|
|
15812
|
-
|
|
15813
|
-
|
|
15882
|
+
});
|
|
15883
|
+
|
|
15884
|
+
// src/submission-ledger.ts
|
|
15885
|
+
async function submissionRecordFile(cwd, runId, scope) {
|
|
15886
|
+
const ledgerHome = resolveActivationLedgerHome(scope.home);
|
|
15887
|
+
let sessionParent = scope.sessionParent;
|
|
15888
|
+
if (sessionParent === void 0) {
|
|
15889
|
+
const discoveredRun = await findRunDirectoryById(scope.home, runId);
|
|
15890
|
+
if (discoveredRun === void 0) return void 0;
|
|
15891
|
+
sessionParent = sessionFileOf(discoveredRun);
|
|
15814
15892
|
}
|
|
15893
|
+
return resolveSitianRecordPathInLedger({
|
|
15894
|
+
level: "event",
|
|
15895
|
+
kind: "candidate",
|
|
15896
|
+
subject: { runId },
|
|
15897
|
+
cwd,
|
|
15898
|
+
sessionParent
|
|
15899
|
+
}, ledgerHome).recordFile;
|
|
15815
15900
|
}
|
|
15816
|
-
function
|
|
15817
|
-
|
|
15818
|
-
|
|
15819
|
-
|
|
15901
|
+
async function readOwnedSubmissionRecords(cwd, runId, scope = {}) {
|
|
15902
|
+
const file = await submissionRecordFile(cwd, runId, scope);
|
|
15903
|
+
if (file === void 0) {
|
|
15904
|
+
return { file: void 0, owned: [] };
|
|
15905
|
+
}
|
|
15906
|
+
const { records } = await readSitianRecords(file);
|
|
15907
|
+
return {
|
|
15908
|
+
file,
|
|
15909
|
+
owned: records.filter(
|
|
15910
|
+
(record) => typeof record.subject === "object" && record.subject !== null && record.subject.runId === runId
|
|
15911
|
+
)
|
|
15912
|
+
};
|
|
15820
15913
|
}
|
|
15821
|
-
function
|
|
15822
|
-
return
|
|
15823
|
-
|
|
15824
|
-
|
|
15825
|
-
);
|
|
15914
|
+
function resolveReadScope(homeOrScope) {
|
|
15915
|
+
if (homeOrScope === void 0) return {};
|
|
15916
|
+
if (typeof homeOrScope === "string") return { home: homeOrScope };
|
|
15917
|
+
return homeOrScope;
|
|
15826
15918
|
}
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
String(options.issueNumber),
|
|
15832
|
-
"runs"
|
|
15833
|
-
);
|
|
15834
|
-
if (options.runs === void 0) {
|
|
15835
|
-
return defaultRuns;
|
|
15836
|
-
}
|
|
15837
|
-
const raw = options.runs.trim();
|
|
15838
|
-
if (raw === "") {
|
|
15839
|
-
throw new CliUsageError("doctor --runs requires a path");
|
|
15840
|
-
}
|
|
15841
|
-
if (isAbsolute5(raw)) {
|
|
15842
|
-
throw new CliUsageError(
|
|
15843
|
-
"doctor --runs must be a project-relative path"
|
|
15844
|
-
);
|
|
15919
|
+
function recordAttemptId(record) {
|
|
15920
|
+
if (typeof record.subject === "object" && record.subject !== null) {
|
|
15921
|
+
const fromSubject = record.subject.attemptId;
|
|
15922
|
+
if (typeof fromSubject === "string" && fromSubject.length > 0) return fromSubject;
|
|
15845
15923
|
}
|
|
15846
|
-
|
|
15847
|
-
|
|
15848
|
-
|
|
15849
|
-
"doctor --runs escapes the project root"
|
|
15850
|
-
);
|
|
15924
|
+
if (typeof record.payload === "object" && record.payload !== null) {
|
|
15925
|
+
const fromPayload = record.payload.attemptId;
|
|
15926
|
+
if (typeof fromPayload === "string" && fromPayload.length > 0) return fromPayload;
|
|
15851
15927
|
}
|
|
15852
|
-
|
|
15853
|
-
|
|
15854
|
-
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15928
|
+
return void 0;
|
|
15929
|
+
}
|
|
15930
|
+
function isTerminalRoleName(value) {
|
|
15931
|
+
return typeof value === "string" && value.length > 0;
|
|
15932
|
+
}
|
|
15933
|
+
function recordedRole(payload) {
|
|
15934
|
+
if (isTerminalRoleName(payload.role)) return payload.role;
|
|
15935
|
+
if (isTerminalRoleName(payload.projection?.role)) return payload.projection.role;
|
|
15936
|
+
return void 0;
|
|
15937
|
+
}
|
|
15938
|
+
function rowRank(kind) {
|
|
15939
|
+
switch (kind) {
|
|
15940
|
+
case "accepted":
|
|
15941
|
+
return 4;
|
|
15942
|
+
case "audit-escalation":
|
|
15943
|
+
return 3;
|
|
15944
|
+
case "correctable-rejection":
|
|
15945
|
+
case "infrastructure":
|
|
15946
|
+
return 2;
|
|
15947
|
+
case "candidate":
|
|
15948
|
+
return 1;
|
|
15861
15949
|
}
|
|
15862
|
-
return real;
|
|
15863
15950
|
}
|
|
15864
|
-
function
|
|
15865
|
-
return
|
|
15866
|
-
`--base ${admitted.baseRevision}`,
|
|
15867
|
-
`--lens ${admitted.lens}`,
|
|
15868
|
-
...admitted.authorityRefs.map((ref) => `--authority ${ref}`)
|
|
15869
|
-
].join(" ");
|
|
15951
|
+
function submissionCallKey(attemptId, toolCallId) {
|
|
15952
|
+
return `${attemptId ?? ""}\0${toolCallId}`;
|
|
15870
15953
|
}
|
|
15871
|
-
function
|
|
15872
|
-
const
|
|
15873
|
-
return
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
|
|
15954
|
+
function rowFromPayload(kind, payload, accepted, roleFallback) {
|
|
15955
|
+
const role = recordedRole(payload) ?? roleFallback;
|
|
15956
|
+
return {
|
|
15957
|
+
...role === void 0 ? {} : { role },
|
|
15958
|
+
kind,
|
|
15959
|
+
accepted,
|
|
15960
|
+
...Object.hasOwn(payload, "auditReceipt") ? { auditReceipt: payload.auditReceipt } : {},
|
|
15961
|
+
...Object.hasOwn(payload, "auditOfficer") ? { auditOfficer: payload.auditOfficer } : {},
|
|
15962
|
+
...typeof payload.toolCallId === "string" && payload.toolCallId.length > 0 ? { toolCallId: payload.toolCallId } : {}
|
|
15963
|
+
};
|
|
15877
15964
|
}
|
|
15878
|
-
|
|
15879
|
-
const
|
|
15880
|
-
const
|
|
15881
|
-
const
|
|
15882
|
-
|
|
15883
|
-
|
|
15884
|
-
|
|
15885
|
-
|
|
15886
|
-
|
|
15887
|
-
|
|
15965
|
+
function mapOwnedToSubmissionRows(owned) {
|
|
15966
|
+
const scoped = owned;
|
|
15967
|
+
const out = [];
|
|
15968
|
+
const indexByCall = /* @__PURE__ */ new Map();
|
|
15969
|
+
const roleByCall = /* @__PURE__ */ new Map();
|
|
15970
|
+
for (const record of scoped) {
|
|
15971
|
+
const payload = record.payload;
|
|
15972
|
+
if (typeof payload?.toolCallId !== "string" || payload.toolCallId.length === 0) continue;
|
|
15973
|
+
const role = recordedRole(payload);
|
|
15974
|
+
if (role !== void 0) {
|
|
15975
|
+
roleByCall.set(submissionCallKey(recordAttemptId(record), payload.toolCallId), role);
|
|
15976
|
+
}
|
|
15977
|
+
}
|
|
15978
|
+
const take = (row, callKey) => {
|
|
15979
|
+
const toolCallId = row.toolCallId;
|
|
15980
|
+
if (toolCallId !== void 0 && callKey !== void 0) {
|
|
15981
|
+
const existingIndex = indexByCall.get(callKey);
|
|
15982
|
+
if (existingIndex !== void 0) {
|
|
15983
|
+
const existing = out[existingIndex];
|
|
15984
|
+
if (rowRank(row.kind) >= rowRank(existing.kind)) {
|
|
15985
|
+
out[existingIndex] = {
|
|
15986
|
+
...row,
|
|
15987
|
+
toolCallId,
|
|
15988
|
+
// Keep a previously recovered role when the upgraded row still omits it.
|
|
15989
|
+
...row.role === void 0 && existing.role !== void 0 ? { role: existing.role } : {}
|
|
15990
|
+
};
|
|
15991
|
+
} else if (existing.role === void 0 && row.role !== void 0) {
|
|
15992
|
+
out[existingIndex] = { ...existing, role: row.role };
|
|
15993
|
+
}
|
|
15994
|
+
return;
|
|
15995
|
+
}
|
|
15996
|
+
indexByCall.set(callKey, out.length);
|
|
15997
|
+
}
|
|
15998
|
+
out.push(row);
|
|
15999
|
+
};
|
|
16000
|
+
for (const record of scoped) {
|
|
16001
|
+
const payload = record.payload;
|
|
16002
|
+
let kind;
|
|
16003
|
+
let original;
|
|
16004
|
+
if (record.kind === "candidate" && payload?.type === "candidate") {
|
|
16005
|
+
kind = "candidate";
|
|
16006
|
+
original = payload.params;
|
|
16007
|
+
} else if (record.kind === "sealed" && payload?.type === "sealed") {
|
|
16008
|
+
kind = "accepted";
|
|
16009
|
+
original = payload.accepted;
|
|
16010
|
+
} else if (record.kind === "outcome" && payload?.type === "outcome") {
|
|
16011
|
+
kind = payload.outcome === "audit-escalation" ? "audit-escalation" : payload.outcome === "correctable-rejection" ? "correctable-rejection" : payload.outcome === "infrastructure" ? "infrastructure" : void 0;
|
|
16012
|
+
original = payload.accepted;
|
|
16013
|
+
}
|
|
16014
|
+
if (kind === void 0 || original === void 0 || payload === void 0) continue;
|
|
16015
|
+
const callKey = typeof payload.toolCallId === "string" ? submissionCallKey(recordAttemptId(record), payload.toolCallId) : void 0;
|
|
16016
|
+
const fallback = callKey === void 0 ? void 0 : roleByCall.get(callKey);
|
|
16017
|
+
take(rowFromPayload(kind, payload, original, fallback), callKey);
|
|
16018
|
+
}
|
|
16019
|
+
return out;
|
|
15888
16020
|
}
|
|
15889
|
-
function
|
|
15890
|
-
|
|
15891
|
-
|
|
15892
|
-
|
|
16021
|
+
async function readRecordedSubmissionRows(cwd, runId, homeOrScope) {
|
|
16022
|
+
const scope = resolveReadScope(homeOrScope);
|
|
16023
|
+
const { owned } = await readOwnedSubmissionRecords(cwd, runId, scope);
|
|
16024
|
+
return mapOwnedToSubmissionRows(owned);
|
|
16025
|
+
}
|
|
16026
|
+
async function readAttemptScopedSubmissionRows(cwd, runId, attemptId, home) {
|
|
16027
|
+
if (attemptId.length === 0) return [];
|
|
16028
|
+
const { owned } = await readOwnedSubmissionRecords(
|
|
16029
|
+
cwd,
|
|
16030
|
+
runId,
|
|
16031
|
+
home === void 0 ? {} : { home }
|
|
15893
16032
|
);
|
|
16033
|
+
return mapOwnedToSubmissionRows(owned.filter((record) => recordAttemptId(record) === attemptId));
|
|
15894
16034
|
}
|
|
15895
|
-
function
|
|
15896
|
-
|
|
15897
|
-
|
|
15898
|
-
|
|
15899
|
-
|
|
15900
|
-
|
|
16035
|
+
async function readRecordedSubmissions(cwd, runId, homeOrScope) {
|
|
16036
|
+
return (await readRecordedSubmissionRows(cwd, runId, homeOrScope)).map((row) => row.accepted);
|
|
16037
|
+
}
|
|
16038
|
+
var init_submission_ledger = __esm({
|
|
16039
|
+
"src/submission-ledger.ts"() {
|
|
16040
|
+
"use strict";
|
|
16041
|
+
init_role_run_placement();
|
|
16042
|
+
init_activation_ledger_topology();
|
|
16043
|
+
init_host_contracts();
|
|
16044
|
+
init_run_terminal_artifacts();
|
|
16045
|
+
init_sitian_facade();
|
|
16046
|
+
init_run_lifecycle();
|
|
16047
|
+
init_submission_correctable_error();
|
|
16048
|
+
init_terminating_infrastructure();
|
|
16049
|
+
init_report_ticket_tool();
|
|
16050
|
+
init_review_submission();
|
|
16051
|
+
init_run_ticket_number();
|
|
16052
|
+
init_unknown_value();
|
|
15901
16053
|
}
|
|
15902
|
-
|
|
15903
|
-
|
|
15904
|
-
|
|
15905
|
-
|
|
15906
|
-
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
|
|
15910
|
-
|
|
16054
|
+
});
|
|
16055
|
+
|
|
16056
|
+
// src/public-cli/process-cancel.ts
|
|
16057
|
+
var process_cancel_exports = {};
|
|
16058
|
+
__export(process_cancel_exports, {
|
|
16059
|
+
childSignalDeathDiagnostic: () => childSignalDeathDiagnostic,
|
|
16060
|
+
installProcessCancelHandlers: () => installProcessCancelHandlers,
|
|
16061
|
+
processCancelDiagnostic: () => processCancelDiagnostic,
|
|
16062
|
+
processCancelSignalName: () => processCancelSignalName
|
|
16063
|
+
});
|
|
16064
|
+
function installProcessCancelHandlers(processRef = process) {
|
|
16065
|
+
const controller = new AbortController();
|
|
16066
|
+
let received;
|
|
16067
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
16068
|
+
for (const sig of CATCHABLE_PROCESS_SIGNALS) {
|
|
16069
|
+
const onSignal = () => {
|
|
16070
|
+
if (received !== void 0) return;
|
|
16071
|
+
received = sig;
|
|
16072
|
+
try {
|
|
16073
|
+
controller.abort(sig);
|
|
16074
|
+
} catch {
|
|
15911
16075
|
}
|
|
15912
|
-
|
|
15913
|
-
|
|
15914
|
-
|
|
15915
|
-
issueNumber: parseAnalystTicketNumber(rhs, flag)
|
|
15916
|
-
};
|
|
15917
|
-
}
|
|
16076
|
+
};
|
|
16077
|
+
listeners.set(sig, onSignal);
|
|
16078
|
+
processRef.on(sig, onSignal);
|
|
15918
16079
|
}
|
|
15919
16080
|
return {
|
|
15920
|
-
|
|
15921
|
-
|
|
16081
|
+
signal: controller.signal,
|
|
16082
|
+
receivedSignal: () => received,
|
|
16083
|
+
dispose() {
|
|
16084
|
+
for (const [sig, onSignal] of listeners) {
|
|
16085
|
+
processRef.off(sig, onSignal);
|
|
16086
|
+
}
|
|
16087
|
+
listeners.clear();
|
|
16088
|
+
}
|
|
15922
16089
|
};
|
|
15923
16090
|
}
|
|
15924
|
-
function
|
|
15925
|
-
|
|
15926
|
-
|
|
15927
|
-
|
|
15928
|
-
|
|
15929
|
-
if (escaped) {
|
|
15930
|
-
current += ch === "," || ch === "\\" ? ch : `\\${ch}`;
|
|
15931
|
-
escaped = false;
|
|
15932
|
-
continue;
|
|
15933
|
-
}
|
|
15934
|
-
if (ch === "\\") {
|
|
15935
|
-
escaped = true;
|
|
15936
|
-
continue;
|
|
15937
|
-
}
|
|
15938
|
-
if (ch === ",") {
|
|
15939
|
-
parts.push(current);
|
|
15940
|
-
current = "";
|
|
15941
|
-
continue;
|
|
15942
|
-
}
|
|
15943
|
-
current += ch;
|
|
16091
|
+
function processCancelSignalName(signal) {
|
|
16092
|
+
if (signal === void 0 || signal.aborted !== true) return void 0;
|
|
16093
|
+
const reason = signal.reason;
|
|
16094
|
+
if (reason === "SIGTERM" || reason === "SIGINT" || reason === "SIGHUP") {
|
|
16095
|
+
return reason;
|
|
15944
16096
|
}
|
|
15945
|
-
|
|
15946
|
-
return parts;
|
|
16097
|
+
return void 0;
|
|
15947
16098
|
}
|
|
15948
|
-
function
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
16099
|
+
function processCancelDiagnostic(signalName) {
|
|
16100
|
+
return `ak-role terminated by ${signalName}`;
|
|
16101
|
+
}
|
|
16102
|
+
function childSignalDeathDiagnostic(signal) {
|
|
16103
|
+
return `role run was killed by ${signal}`;
|
|
16104
|
+
}
|
|
16105
|
+
var CATCHABLE_PROCESS_SIGNALS;
|
|
16106
|
+
var init_process_cancel = __esm({
|
|
16107
|
+
"src/public-cli/process-cancel.ts"() {
|
|
16108
|
+
"use strict";
|
|
16109
|
+
CATCHABLE_PROCESS_SIGNALS = ["SIGTERM", "SIGINT", "SIGHUP"];
|
|
15954
16110
|
}
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
16111
|
+
});
|
|
16112
|
+
|
|
16113
|
+
// src/engine-detour-usage.ts
|
|
16114
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
16115
|
+
function callFactFromSitianPayload(payload, pointer) {
|
|
16116
|
+
if (!isRecord(payload)) return void 0;
|
|
16117
|
+
if (payload.tool !== ENGINE_DETOUR_TOOL_NAME) return void 0;
|
|
16118
|
+
if (typeof payload.toolCallId !== "string" || payload.toolCallId.length === 0) {
|
|
16119
|
+
return void 0;
|
|
15962
16120
|
}
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
function requireOptionValue(flag, value, what) {
|
|
15966
|
-
if (value === void 0 || value.trim() === "") {
|
|
15967
|
-
throw new CliUsageError(`${flag} requires ${what}`);
|
|
16121
|
+
if (typeof payload.durationMs !== "number" || !Number.isFinite(payload.durationMs)) {
|
|
16122
|
+
return void 0;
|
|
15968
16123
|
}
|
|
15969
|
-
return
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
|
|
15974
|
-
|
|
15975
|
-
const pushValue = (id, value) => {
|
|
15976
|
-
const existing = valueLists.get(id);
|
|
15977
|
-
if (existing === void 0) valueLists.set(id, [value]);
|
|
15978
|
-
else existing.push(value);
|
|
16124
|
+
return {
|
|
16125
|
+
toolCallId: payload.toolCallId,
|
|
16126
|
+
durationMs: payload.durationMs,
|
|
16127
|
+
...typeof payload.code === "number" ? { code: payload.code } : {},
|
|
16128
|
+
...typeof payload.stdoutByteLength === "number" ? { stdoutByteLength: payload.stdoutByteLength } : {},
|
|
16129
|
+
recordPointer: pointer
|
|
15979
16130
|
};
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
}
|
|
15986
|
-
if (taken.def.id === "ticket") {
|
|
15987
|
-
if (taken.value === void 0 || taken.value.trim() === "") {
|
|
15988
|
-
throw new CliUsageError("analyst --ticket requires a positive integer");
|
|
15989
|
-
}
|
|
15990
|
-
pushValue("ticket", taken.value);
|
|
15991
|
-
return;
|
|
15992
|
-
}
|
|
15993
|
-
if (taken.def.id === "attach") {
|
|
15994
|
-
pushValue(
|
|
15995
|
-
"attach",
|
|
15996
|
-
requireProvidedOptionValue(taken.def.canonical, taken.value)
|
|
15997
|
-
);
|
|
15998
|
-
return;
|
|
15999
|
-
}
|
|
16000
|
-
if (taken.def.id === "group-a-label" || taken.def.id === "group-b-label") {
|
|
16001
|
-
pushValue(
|
|
16002
|
-
taken.def.id,
|
|
16003
|
-
requireOptionValue(taken.def.canonical, taken.value, "a label")
|
|
16004
|
-
);
|
|
16005
|
-
return;
|
|
16006
|
-
}
|
|
16007
|
-
if (taken.def.id === "group-a-issues" || taken.def.id === "group-b-issues") {
|
|
16008
|
-
pushValue(
|
|
16009
|
-
taken.def.id,
|
|
16010
|
-
requireOptionValue(
|
|
16011
|
-
taken.def.canonical,
|
|
16012
|
-
taken.value,
|
|
16013
|
-
"a comma-separated list of N or book:N"
|
|
16014
|
-
)
|
|
16015
|
-
);
|
|
16016
|
-
return;
|
|
16017
|
-
}
|
|
16018
|
-
throw new CliUsageError(`unknown analyst option: ${taken.def.canonical}`);
|
|
16019
|
-
},
|
|
16020
|
-
onBare(token) {
|
|
16021
|
-
if (isRejectedPublicSpelling("analyst", token)) {
|
|
16022
|
-
if (token === "--project-root" || token.startsWith("--project-root=")) {
|
|
16023
|
-
throw new CliUsageError(
|
|
16024
|
-
"analyst no longer accepts --project-root (deleted); use bare call for whole book or --ticket N (cwd git common-dir selects the book)"
|
|
16025
|
-
);
|
|
16026
|
-
}
|
|
16027
|
-
if (token === "--model-groups" || token.startsWith("--model-groups=")) {
|
|
16028
|
-
throw new CliUsageError(
|
|
16029
|
-
"analyst --model-groups public CLI face is disabled; input face is being redesigned for multi-issue comparison (see follow-up ticket)"
|
|
16030
|
-
);
|
|
16031
|
-
}
|
|
16032
|
-
throw new CliUsageError(`unknown analyst option: ${token}`);
|
|
16033
|
-
}
|
|
16034
|
-
if (token.startsWith("-") && token !== "-") {
|
|
16035
|
-
throw new CliUsageError(`unknown analyst option: ${token}`);
|
|
16036
|
-
}
|
|
16037
|
-
const positional = options.takePositional(token);
|
|
16038
|
-
if (positional !== void 0) {
|
|
16039
|
-
pushValue(positional.id, "");
|
|
16040
|
-
return;
|
|
16041
|
-
}
|
|
16042
|
-
throw new CliUsageError(`unexpected analyst argument: ${token}`);
|
|
16043
|
-
},
|
|
16044
|
-
onDoubleDash(rest) {
|
|
16045
|
-
if (rest.length > 0) {
|
|
16046
|
-
throw new CliUsageError(`unexpected analyst argument: ${rest[0]}`);
|
|
16047
|
-
}
|
|
16048
|
-
}
|
|
16049
|
-
});
|
|
16050
|
-
const counts = /* @__PURE__ */ new Map();
|
|
16051
|
-
for (const [id, values] of valueLists) {
|
|
16052
|
-
counts.set(id, values.length);
|
|
16053
|
-
}
|
|
16054
|
-
options.assertRequired();
|
|
16055
|
-
const mode = resolveAnalystMode(new Set(counts.keys()));
|
|
16056
|
-
const verdict = evaluateAnalystModeOptionContract(mode, counts);
|
|
16057
|
-
if (!verdict.ok) {
|
|
16058
|
-
throw new CliUsageError(verdict.message);
|
|
16131
|
+
}
|
|
16132
|
+
function invocationScopeIdOfRecord(record) {
|
|
16133
|
+
if (isRecord(record.subject)) {
|
|
16134
|
+
const fromSubject = record.subject.invocationScopeId;
|
|
16135
|
+
if (typeof fromSubject === "string" && fromSubject.length > 0) return fromSubject;
|
|
16059
16136
|
}
|
|
16060
|
-
if (
|
|
16061
|
-
const
|
|
16062
|
-
|
|
16063
|
-
const groupBLabel = valueLists.get("group-b-label")[0];
|
|
16064
|
-
const groupBIssuesRaw = valueLists.get("group-b-issues")[0];
|
|
16065
|
-
return {
|
|
16066
|
-
query: "cohort",
|
|
16067
|
-
groups: [
|
|
16068
|
-
{
|
|
16069
|
-
groupLabel: groupALabel,
|
|
16070
|
-
issues: parseAnalystCohortIssueTokenList(
|
|
16071
|
-
groupAIssuesRaw,
|
|
16072
|
-
"--group-a-issues"
|
|
16073
|
-
)
|
|
16074
|
-
},
|
|
16075
|
-
{
|
|
16076
|
-
groupLabel: groupBLabel,
|
|
16077
|
-
issues: parseAnalystCohortIssueTokenList(
|
|
16078
|
-
groupBIssuesRaw,
|
|
16079
|
-
"--group-b-issues"
|
|
16080
|
-
)
|
|
16081
|
-
}
|
|
16082
|
-
]
|
|
16083
|
-
};
|
|
16137
|
+
if (isRecord(record.payload)) {
|
|
16138
|
+
const fromPayload = record.payload.invocationScopeId;
|
|
16139
|
+
if (typeof fromPayload === "string" && fromPayload.length > 0) return fromPayload;
|
|
16084
16140
|
}
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16141
|
+
return void 0;
|
|
16142
|
+
}
|
|
16143
|
+
async function readEngineDetourToolUsage(input) {
|
|
16144
|
+
if (!input.engineMounted) return void 0;
|
|
16145
|
+
const { recordFile } = resolveSitianRecordPath({
|
|
16146
|
+
level: "event",
|
|
16147
|
+
kind: ENGINE_DETOUR_CALL_KIND,
|
|
16148
|
+
sessionParent: input.sessionParent,
|
|
16149
|
+
...input.home === void 0 ? {} : { home: input.home },
|
|
16150
|
+
...input.cwd === void 0 ? {} : { cwd: input.cwd }
|
|
16151
|
+
});
|
|
16152
|
+
const { records } = await readSitianRecords(recordFile);
|
|
16153
|
+
const callsByToolCallId = /* @__PURE__ */ new Map();
|
|
16154
|
+
for (const record of records) {
|
|
16155
|
+
if (record.kind !== ENGINE_DETOUR_CALL_KIND) continue;
|
|
16156
|
+
const boundScope = invocationScopeIdOfRecord(record);
|
|
16157
|
+
if (input.invocationScopeId !== void 0 && input.invocationScopeId.length > 0) {
|
|
16158
|
+
if (boundScope !== input.invocationScopeId) continue;
|
|
16159
|
+
} else if (boundScope !== void 0) {
|
|
16160
|
+
continue;
|
|
16161
|
+
}
|
|
16162
|
+
const pointer = {
|
|
16163
|
+
identity: record.identity,
|
|
16164
|
+
recordFile: ENGINE_DETOUR_CALL_RECORD_FILE_RELATIVE,
|
|
16165
|
+
kind: record.kind,
|
|
16166
|
+
level: record.level
|
|
16089
16167
|
};
|
|
16168
|
+
const fact = callFactFromSitianPayload(record.payload, pointer);
|
|
16169
|
+
if (fact === void 0) continue;
|
|
16170
|
+
callsByToolCallId.set(fact.toolCallId, fact);
|
|
16090
16171
|
}
|
|
16091
|
-
const
|
|
16172
|
+
const calls = Array.from(callsByToolCallId.values());
|
|
16173
|
+
return { callCount: calls.length, calls };
|
|
16174
|
+
}
|
|
16175
|
+
function readInvocationRecord(runDirectory) {
|
|
16176
|
+
return readPageSync(runDirectory, "invocation");
|
|
16177
|
+
}
|
|
16178
|
+
async function readInvocationEngineMounted(runDirectory) {
|
|
16179
|
+
const raw = readInvocationRecord(runDirectory);
|
|
16180
|
+
if (raw === void 0) return false;
|
|
16181
|
+
return typeof raw.engine === "string" && raw.engine.trim() !== "";
|
|
16182
|
+
}
|
|
16183
|
+
function withEngineDetourToolUsageFact(outcome, usage) {
|
|
16184
|
+
if (usage === void 0) return outcome;
|
|
16185
|
+
const prior = isRecord(outcome.decisiveFacts) ? outcome.decisiveFacts : {};
|
|
16092
16186
|
return {
|
|
16093
|
-
|
|
16094
|
-
|
|
16187
|
+
...outcome,
|
|
16188
|
+
decisiveFacts: {
|
|
16189
|
+
...prior,
|
|
16190
|
+
[ENGINE_DETOUR_TOOL_USAGE_FACT_KEY]: usage
|
|
16191
|
+
}
|
|
16095
16192
|
};
|
|
16096
16193
|
}
|
|
16097
|
-
|
|
16098
|
-
|
|
16194
|
+
function mintEngineDetourInvocationScope(_input) {
|
|
16195
|
+
return randomUUID3();
|
|
16196
|
+
}
|
|
16197
|
+
function withEngineDetourInvocationScope(request, invocationScopeId) {
|
|
16198
|
+
if (invocationScopeId === void 0 || invocationScopeId.length === 0) {
|
|
16199
|
+
return request;
|
|
16200
|
+
}
|
|
16201
|
+
if (typeof request.invocationScopeId === "string" && request.invocationScopeId.length > 0) {
|
|
16202
|
+
return request;
|
|
16203
|
+
}
|
|
16204
|
+
return { ...request, invocationScopeId };
|
|
16205
|
+
}
|
|
16206
|
+
var ENGINE_DETOUR_CALL_KIND, ENGINE_DETOUR_TOOL_USAGE_FACT_KEY, ENGINE_DETOUR_CALL_RECORD_FILE_RELATIVE;
|
|
16207
|
+
var init_engine_detour_usage = __esm({
|
|
16208
|
+
"src/engine-detour-usage.ts"() {
|
|
16099
16209
|
"use strict";
|
|
16100
|
-
init_activation_ledger_topology();
|
|
16101
|
-
init_activation_ledger_git();
|
|
16102
|
-
init_role_run_placement();
|
|
16103
|
-
init_packaged_role_registry();
|
|
16104
|
-
init_run_ticket_number();
|
|
16105
|
-
init_role_run_relocation();
|
|
16106
16210
|
init_run_dossier();
|
|
16107
|
-
|
|
16108
|
-
|
|
16109
|
-
|
|
16110
|
-
|
|
16111
|
-
|
|
16112
|
-
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
|
|
16116
|
-
|
|
16117
|
-
|
|
16118
|
-
|
|
16211
|
+
init_role_run_placement();
|
|
16212
|
+
init_engine_detour();
|
|
16213
|
+
init_sitian_facade();
|
|
16214
|
+
init_unknown_value();
|
|
16215
|
+
ENGINE_DETOUR_CALL_KIND = "engine-detour-call";
|
|
16216
|
+
ENGINE_DETOUR_TOOL_USAGE_FACT_KEY = "engineDetourToolUsage";
|
|
16217
|
+
ENGINE_DETOUR_CALL_RECORD_FILE_RELATIVE = RUN_LOG_FILE;
|
|
16218
|
+
}
|
|
16219
|
+
});
|
|
16220
|
+
|
|
16221
|
+
// src/dossier-resolution.ts
|
|
16222
|
+
import { existsSync as existsSync3, statSync as statSync5 } from "node:fs";
|
|
16223
|
+
import { resolve as resolve9 } from "node:path";
|
|
16224
|
+
function isHostContext(value) {
|
|
16225
|
+
return "sessionManager" in value;
|
|
16226
|
+
}
|
|
16227
|
+
function dossierPointerFrom(source) {
|
|
16228
|
+
if (source !== void 0 && isHostContext(source)) {
|
|
16229
|
+
return runDirectoryFromHostContext(source);
|
|
16230
|
+
}
|
|
16231
|
+
const env = source ?? process.env;
|
|
16232
|
+
const raw = env[AUDIT_RUN_DIR_ENV];
|
|
16233
|
+
return typeof raw === "string" && raw.trim() !== "" ? raw : void 0;
|
|
16234
|
+
}
|
|
16235
|
+
function resolveAuditDossier(source) {
|
|
16236
|
+
const raw = dossierPointerFrom(source);
|
|
16237
|
+
if (raw === void 0) {
|
|
16238
|
+
return { status: "ok" };
|
|
16239
|
+
}
|
|
16240
|
+
const runDirectory = resolve9(raw);
|
|
16241
|
+
try {
|
|
16242
|
+
if (!existsSync3(runDirectory) || !statSync5(runDirectory).isDirectory()) {
|
|
16243
|
+
return { status: "incomplete", observation: { kind: "missing-dossier" } };
|
|
16244
|
+
}
|
|
16245
|
+
} catch {
|
|
16246
|
+
return { status: "incomplete", observation: { kind: "missing-dossier" } };
|
|
16247
|
+
}
|
|
16248
|
+
return { status: "ok", runDirectory };
|
|
16249
|
+
}
|
|
16250
|
+
function readDoctorAuditSubjects(context) {
|
|
16251
|
+
const entries = context.sessionManager.getEntries?.() ?? [];
|
|
16252
|
+
for (const entry of entries) {
|
|
16253
|
+
if (isRecord(entry) && entry.type === "custom" && entry.customType === DOCTOR_CANDIDATE_ENTRY_TYPE) {
|
|
16254
|
+
return { status: "ok" };
|
|
16255
|
+
}
|
|
16256
|
+
}
|
|
16257
|
+
return { status: "incomplete", observation: { kind: "missing-subject", subject: "candidate-testimony" } };
|
|
16258
|
+
}
|
|
16259
|
+
function requireAuditMaterials(resolution) {
|
|
16260
|
+
if (resolution.status === "incomplete") {
|
|
16261
|
+
throw new AuditMaterialsUnavailableError(resolution.observation);
|
|
16262
|
+
}
|
|
16263
|
+
}
|
|
16264
|
+
var AUDIT_RUN_DIR_ENV, DOCTOR_CANDIDATE_ENTRY_TYPE, AuditMaterialsUnavailableError;
|
|
16265
|
+
var init_dossier_resolution = __esm({
|
|
16266
|
+
"src/dossier-resolution.ts"() {
|
|
16267
|
+
"use strict";
|
|
16268
|
+
init_host_contracts();
|
|
16119
16269
|
init_unknown_value();
|
|
16270
|
+
AUDIT_RUN_DIR_ENV = "AK_ROLE_RUN_DIR";
|
|
16271
|
+
DOCTOR_CANDIDATE_ENTRY_TYPE = "ak_doctor_audit_candidate";
|
|
16272
|
+
AuditMaterialsUnavailableError = class extends Error {
|
|
16273
|
+
observation;
|
|
16274
|
+
candidate;
|
|
16275
|
+
constructor(observation) {
|
|
16276
|
+
const detail = observation.kind === "missing-subject" ? `${observation.kind}:${observation.subject}` : observation.kind;
|
|
16277
|
+
super(`Audit materials unavailable: ${detail}`);
|
|
16278
|
+
this.name = "AuditMaterialsUnavailableError";
|
|
16279
|
+
this.observation = observation;
|
|
16280
|
+
this.candidate = void 0;
|
|
16281
|
+
}
|
|
16282
|
+
};
|
|
16120
16283
|
}
|
|
16121
16284
|
});
|
|
16122
16285
|
|
|
@@ -17381,7 +17544,7 @@ async function resolveLiveRunDirectoryPath(recordedPath, home) {
|
|
|
17381
17544
|
parsed.role
|
|
17382
17545
|
);
|
|
17383
17546
|
}
|
|
17384
|
-
async function syncTurnRequestLivePlacement(request) {
|
|
17547
|
+
async function syncTurnRequestLivePlacement(request, authority) {
|
|
17385
17548
|
const live = await resolveLiveRunDirectoryPath(request.runDirectory, request.home);
|
|
17386
17549
|
if (live === void 0) {
|
|
17387
17550
|
const parsed = parseRunLeaf(basename8(request.runDirectory));
|
|
@@ -17390,35 +17553,41 @@ async function syncTurnRequestLivePlacement(request) {
|
|
|
17390
17553
|
);
|
|
17391
17554
|
}
|
|
17392
17555
|
if (live !== request.runDirectory) {
|
|
17393
|
-
projectTurnRequestLiveRunDirectory(
|
|
17394
|
-
request,
|
|
17395
|
-
live
|
|
17396
|
-
);
|
|
17556
|
+
projectTurnRequestLiveRunDirectory(request, live, authority);
|
|
17397
17557
|
}
|
|
17398
17558
|
return live;
|
|
17399
17559
|
}
|
|
17400
|
-
async function trySyncTurnRequestLivePlacement(request) {
|
|
17401
|
-
try {
|
|
17402
|
-
return { runDirectory: await syncTurnRequestLivePlacement(request) };
|
|
17403
|
-
} catch (resolveError) {
|
|
17404
|
-
return { resolveError };
|
|
17405
|
-
}
|
|
17406
|
-
}
|
|
17407
17560
|
async function retainPackageFaultBesideLivePlacement(request, input) {
|
|
17408
|
-
|
|
17409
|
-
if (
|
|
17410
|
-
const resolveDiagnostic = `live run path resolve failed beside fault: ${describeErrorIdentity(live.resolveError)}`;
|
|
17561
|
+
let runDirectory = request.runDirectory;
|
|
17562
|
+
if (!existsSync4(runDirectory)) {
|
|
17411
17563
|
try {
|
|
17412
|
-
|
|
17564
|
+
const found = await resolveLiveRunDirectoryPath(request.runDirectory, request.home);
|
|
17565
|
+
if (found === void 0) {
|
|
17566
|
+
const resolveDiagnostic = `live run path resolve failed beside fault: admitted run missing under ${request.home}`;
|
|
17567
|
+
try {
|
|
17568
|
+
process.stderr.write(`${input.diagnostic}
|
|
17413
17569
|
`);
|
|
17414
|
-
|
|
17570
|
+
process.stderr.write(`${resolveDiagnostic}
|
|
17415
17571
|
`);
|
|
17416
|
-
|
|
17572
|
+
} catch {
|
|
17573
|
+
}
|
|
17574
|
+
return;
|
|
17575
|
+
}
|
|
17576
|
+
runDirectory = found;
|
|
17577
|
+
} catch (resolveError) {
|
|
17578
|
+
const resolveDiagnostic = `live run path resolve failed beside fault: ${describeErrorIdentity(resolveError)}`;
|
|
17579
|
+
try {
|
|
17580
|
+
process.stderr.write(`${input.diagnostic}
|
|
17581
|
+
`);
|
|
17582
|
+
process.stderr.write(`${resolveDiagnostic}
|
|
17583
|
+
`);
|
|
17584
|
+
} catch {
|
|
17585
|
+
}
|
|
17586
|
+
return;
|
|
17417
17587
|
}
|
|
17418
|
-
return;
|
|
17419
17588
|
}
|
|
17420
17589
|
await retainPackageFault({
|
|
17421
|
-
runDirectory
|
|
17590
|
+
runDirectory,
|
|
17422
17591
|
diagnostic: input.diagnostic,
|
|
17423
17592
|
...Object.hasOwn(input, "error") ? { error: input.error } : {}
|
|
17424
17593
|
});
|
|
@@ -17442,6 +17611,7 @@ import { dirname as dirname10, join as join14 } from "node:path";
|
|
|
17442
17611
|
function createSessionIdentityAuthority(authority, hostName) {
|
|
17443
17612
|
const runDirectoryOf = (principal) => dirname10(authority.decode(principal).sessionDirectory);
|
|
17444
17613
|
return {
|
|
17614
|
+
principalAuthority: authority,
|
|
17445
17615
|
resolveSessionFile(principal) {
|
|
17446
17616
|
return authority.decode(principal).sessionFile;
|
|
17447
17617
|
},
|
|
@@ -17806,7 +17976,7 @@ function createPiRoleTurnHost(config) {
|
|
|
17806
17976
|
...request.signal === void 0 ? {} : { signal: request.signal }
|
|
17807
17977
|
});
|
|
17808
17978
|
try {
|
|
17809
|
-
await syncTurnRequestLivePlacement(request);
|
|
17979
|
+
await syncTurnRequestLivePlacement(request, config.principalAuthority);
|
|
17810
17980
|
const { sessionFile, sessionDirectory } = config.principalAuthority.decode(request.principal);
|
|
17811
17981
|
const sessionId = await readPiSessionHeaderId(sessionFile);
|
|
17812
17982
|
if (sessionId !== void 0) {
|
|
@@ -18114,31 +18284,6 @@ var init_role_seat_runtime = __esm({
|
|
|
18114
18284
|
}
|
|
18115
18285
|
});
|
|
18116
18286
|
|
|
18117
|
-
// src/report-ticket-tool.ts
|
|
18118
|
-
var reportTicketArgsSchema, MISSING_TICKET_REASK_MATERIAL;
|
|
18119
|
-
var init_report_ticket_tool = __esm({
|
|
18120
|
-
"src/report-ticket-tool.ts"() {
|
|
18121
|
-
"use strict";
|
|
18122
|
-
init_build();
|
|
18123
|
-
init_host_contracts();
|
|
18124
|
-
init_durable_principal();
|
|
18125
|
-
init_invocation();
|
|
18126
|
-
init_role_run_placement();
|
|
18127
|
-
init_run_dossier();
|
|
18128
|
-
init_run_ticket_number();
|
|
18129
|
-
init_unknown_value();
|
|
18130
|
-
reportTicketArgsSchema = typebox_exports.Object(
|
|
18131
|
-
{
|
|
18132
|
-
ticketNumber: typebox_exports.Unknown({
|
|
18133
|
-
description: "\u672C\u7968\u53F7\uFF08\u6B63\u6574\u6570\u3001\u6570\u5B57\u4E32\u6216\u524D\u5BFC #N\uFF09\u3002\u5DF2\u77E5\u7968\u53F7\u65F6\u5F00\u5DE5\u5373\u62A5\uFF1B\u5C1A\u65E0\u7968\u53F7\u65F6\u4E0D\u8981\u8C03\u7528\u3002"
|
|
18134
|
-
})
|
|
18135
|
-
},
|
|
18136
|
-
{ additionalProperties: true }
|
|
18137
|
-
);
|
|
18138
|
-
MISSING_TICKET_REASK_MATERIAL = "resources/missing-ticket-reask.md";
|
|
18139
|
-
}
|
|
18140
|
-
});
|
|
18141
|
-
|
|
18142
18287
|
// src/session-opening-materials.ts
|
|
18143
18288
|
import { existsSync as existsSync8 } from "node:fs";
|
|
18144
18289
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
@@ -21025,16 +21170,7 @@ var init_compliance_transport = __esm({
|
|
|
21025
21170
|
});
|
|
21026
21171
|
|
|
21027
21172
|
// src/role-run-relocation.ts
|
|
21028
|
-
import { dirname as dirname14, join as join22
|
|
21029
|
-
function rewriteRunDirectoryPathValue(value, oldRunDirectory, newRunDirectory) {
|
|
21030
|
-
if (typeof value !== "string") return value;
|
|
21031
|
-
if (value === oldRunDirectory) return newRunDirectory;
|
|
21032
|
-
const prefix = `${oldRunDirectory}${sep4}`;
|
|
21033
|
-
if (value.startsWith(prefix)) {
|
|
21034
|
-
return `${newRunDirectory}${value.slice(oldRunDirectory.length)}`;
|
|
21035
|
-
}
|
|
21036
|
-
return value;
|
|
21037
|
-
}
|
|
21173
|
+
import { dirname as dirname14, join as join22 } from "node:path";
|
|
21038
21174
|
async function retainedRunPathsMatch(recordedPath, currentPath, currentRunDirectory) {
|
|
21039
21175
|
if (recordedPath === currentPath) return true;
|
|
21040
21176
|
if (typeof recordedPath !== "string") return false;
|
|
@@ -21062,102 +21198,17 @@ async function retainedRunPathsMatch(recordedPath, currentPath, currentRunDirect
|
|
|
21062
21198
|
}
|
|
21063
21199
|
return false;
|
|
21064
21200
|
}
|
|
21065
|
-
function rewriteRunDirectoryPathValueAgainstRewrites(value, rewrites) {
|
|
21066
|
-
if (typeof value !== "string" || rewrites.length === 0) return value;
|
|
21067
|
-
let best;
|
|
21068
|
-
for (const rewrite of rewrites) {
|
|
21069
|
-
if (value === rewrite.oldRunDirectory || value.startsWith(`${rewrite.oldRunDirectory}${sep4}`)) {
|
|
21070
|
-
if (best === void 0 || rewrite.oldRunDirectory.length > best.oldRunDirectory.length) {
|
|
21071
|
-
best = rewrite;
|
|
21072
|
-
}
|
|
21073
|
-
}
|
|
21074
|
-
}
|
|
21075
|
-
if (best === void 0) return value;
|
|
21076
|
-
return rewriteRunDirectoryPathValue(
|
|
21077
|
-
value,
|
|
21078
|
-
best.oldRunDirectory,
|
|
21079
|
-
best.newRunDirectory
|
|
21080
|
-
);
|
|
21081
|
-
}
|
|
21082
|
-
function rewriteRunDirectoryPathFields(record, fields, oldRunDirectory, newRunDirectory) {
|
|
21083
|
-
rewriteRunDirectoryPathFieldsAgainstRewrites(record, fields, [
|
|
21084
|
-
{ oldRunDirectory, newRunDirectory }
|
|
21085
|
-
]);
|
|
21086
|
-
}
|
|
21087
|
-
function rewritePrincipalSessionPaths(principal, oldRunDirectory, newRunDirectory) {
|
|
21088
|
-
rewriteRunDirectoryPathFields(
|
|
21089
|
-
principal,
|
|
21090
|
-
PRINCIPAL_SESSION_PATH_FIELDS,
|
|
21091
|
-
oldRunDirectory,
|
|
21092
|
-
newRunDirectory
|
|
21093
|
-
);
|
|
21094
|
-
}
|
|
21095
|
-
function projectTurnRequestLiveRunDirectory(request, newRunDirectory) {
|
|
21096
|
-
const old = request.runDirectory;
|
|
21097
|
-
if (old === newRunDirectory) return;
|
|
21098
|
-
request.runDirectory = newRunDirectory;
|
|
21099
|
-
rewritePrincipalSessionPaths(
|
|
21100
|
-
request.principal,
|
|
21101
|
-
old,
|
|
21102
|
-
newRunDirectory
|
|
21103
|
-
);
|
|
21104
|
-
}
|
|
21105
|
-
function rewriteRunDirectoryPathFieldsAgainstRewrites(record, fields, rewrites) {
|
|
21106
|
-
for (const field of fields) {
|
|
21107
|
-
if (field in record) {
|
|
21108
|
-
record[field] = rewriteRunDirectoryPathValueAgainstRewrites(
|
|
21109
|
-
record[field],
|
|
21110
|
-
rewrites
|
|
21111
|
-
);
|
|
21112
|
-
}
|
|
21113
|
-
}
|
|
21114
|
-
}
|
|
21115
|
-
function rewriteSourceRunLocator(value, rewrites) {
|
|
21116
|
-
if (!isRecord(value)) return;
|
|
21117
|
-
rewriteRunDirectoryPathFieldsAgainstRewrites(
|
|
21118
|
-
value,
|
|
21119
|
-
SOURCE_RUN_LOCATOR_FIELDS,
|
|
21120
|
-
rewrites
|
|
21121
|
-
);
|
|
21122
|
-
}
|
|
21123
|
-
function rewriteAdmittedRoleRunPage(page, rewrites) {
|
|
21124
|
-
rewriteRunDirectoryPathFieldsAgainstRewrites(page, ADMITTED_PAGE_FIELDS, rewrites);
|
|
21125
|
-
rewriteSourceRunLocator(page.sourceRun, rewrites);
|
|
21126
|
-
if (isRecord(page.principal)) {
|
|
21127
|
-
rewriteRunDirectoryPathFieldsAgainstRewrites(
|
|
21128
|
-
page.principal,
|
|
21129
|
-
PRINCIPAL_SESSION_PATH_FIELDS,
|
|
21130
|
-
rewrites
|
|
21131
|
-
);
|
|
21132
|
-
}
|
|
21133
|
-
}
|
|
21134
|
-
var ADMITTED_PAGE_FIELDS, PRINCIPAL_SESSION_PATH_FIELDS, SOURCE_RUN_LOCATOR_FIELDS;
|
|
21135
21201
|
var init_role_run_relocation = __esm({
|
|
21136
21202
|
"src/role-run-relocation.ts"() {
|
|
21137
21203
|
"use strict";
|
|
21138
21204
|
init_activation_ledger_topology();
|
|
21205
|
+
init_compliance_transport();
|
|
21139
21206
|
init_run_lifecycle();
|
|
21140
21207
|
init_role_run_placement();
|
|
21141
|
-
|
|
21208
|
+
init_role_run_path_rewrite();
|
|
21142
21209
|
init_run_dossier();
|
|
21143
21210
|
init_unknown_value();
|
|
21144
|
-
|
|
21145
|
-
"runDirectory",
|
|
21146
|
-
"admittedRequestPath",
|
|
21147
|
-
// pre-#1161 pages only
|
|
21148
|
-
"sessionDirectory",
|
|
21149
|
-
"sessionFile",
|
|
21150
|
-
// #1165/#1168: caller file-flag paths (requestManifestPath, prerequisitesPath)
|
|
21151
|
-
// stay as given. Obsolete copy fields (taskPath/packetPath) are not rewritten —
|
|
21152
|
-
// stock volumes keep their bytes; live relocate no longer maintains them.
|
|
21153
|
-
"mergerInputPath",
|
|
21154
|
-
"sourceRunPath"
|
|
21155
|
-
];
|
|
21156
|
-
PRINCIPAL_SESSION_PATH_FIELDS = [
|
|
21157
|
-
"sessionDirectory",
|
|
21158
|
-
"sessionFile"
|
|
21159
|
-
];
|
|
21160
|
-
SOURCE_RUN_LOCATOR_FIELDS = ["runDirectory"];
|
|
21211
|
+
init_role_run_path_rewrite();
|
|
21161
21212
|
}
|
|
21162
21213
|
});
|
|
21163
21214
|
|