@akagilnc/pi-workflow-roles 0.1.3204-next.0fd96af → 0.1.3236

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/CLAUDE.md CHANGED
@@ -88,4 +88,4 @@ A probe is temporary evidence. After its evidence purpose is disposed, either de
88
88
 
89
89
  ## 修订通道
90
90
 
91
- Soul 与本文件(CLAUDE.md)的修订走陛下直改通道(全文过目直落主线),不走工厂流程,且负持续精进义务;工厂只供修订素材,不拥有动笔权。
91
+ Soul 与本文件的内容修订须经陛下亲自审定,工厂未获授权不得改动。
@@ -376,7 +376,7 @@ __export(archivist_record_entry_exports, {
376
376
  createRecordSession: () => createRecordSession
377
377
  });
378
378
  import { createHash as createHash4 } from "node:crypto";
379
- import { existsSync as existsSync5, readFileSync as readFileSync2, realpathSync as realpathSync2, writeFileSync } from "node:fs";
379
+ import { existsSync as existsSync5, readFileSync as readFileSync2, realpathSync as realpathSync2, writeFileSync as writeFileSync2 } from "node:fs";
380
380
  import { dirname as dirname8, resolve as resolve6, join as join10 } from "node:path";
381
381
  import { SessionManager } from "@earendil-works/pi-coding-agent";
382
382
  function readCurrentSession(sessionDir) {
@@ -397,7 +397,7 @@ function readCurrentSession(sessionDir) {
397
397
  function writeCurrentSession(sessionDir, sessionFile) {
398
398
  const ledger = join10(sessionDir, CURRENT_SESSION_LEDGER);
399
399
  try {
400
- writeFileSync(ledger, `${JSON.stringify({ sessionFile })}
400
+ writeFileSync2(ledger, `${JSON.stringify({ sessionFile })}
401
401
  `, { flag: "wx" });
402
402
  } catch (error) {
403
403
  throw new ActivationLedgerError(
@@ -477,7 +477,7 @@ function createRecordSession(options) {
477
477
  if (file !== void 0 && !existsSync5(file)) {
478
478
  const header = session.getHeader();
479
479
  if (header !== null && header.type === "session") {
480
- writeFileSync(file, `${JSON.stringify(header)}
480
+ writeFileSync2(file, `${JSON.stringify(header)}
481
481
  `, { flag: "wx" });
482
482
  session.setSessionFile(file);
483
483
  }
@@ -1104,6 +1104,9 @@ async function openPiInstitutionalSession(options) {
1104
1104
  };
1105
1105
  if (options.signal?.aborted) abortSession();
1106
1106
  else options.signal?.addEventListener("abort", abortSession, { once: true });
1107
+ const assistantCountBefore = session.messages.filter(
1108
+ (message) => message.role === "assistant"
1109
+ ).length;
1107
1110
  let promptError;
1108
1111
  try {
1109
1112
  await session.prompt(text);
@@ -1124,7 +1127,10 @@ async function openPiInstitutionalSession(options) {
1124
1127
  });
1125
1128
  }
1126
1129
  }
1127
- if (promptError !== void 0 && lastAssistant === void 0) {
1130
+ const producedAssistant = session.messages.filter(
1131
+ (message) => message.role === "assistant"
1132
+ ).length > assistantCountBefore;
1133
+ if (promptError !== void 0 && !producedAssistant) {
1128
1134
  throw promptError;
1129
1135
  }
1130
1136
  return {
@@ -1148,18 +1154,30 @@ async function openPiInstitutionalSession(options) {
1148
1154
  if (closed) return;
1149
1155
  closed = true;
1150
1156
  listeners.clear();
1157
+ const cleanupFailures = [];
1151
1158
  try {
1152
1159
  unsubscribeSession();
1153
- } finally {
1160
+ } catch (error) {
1161
+ cleanupFailures.push(error);
1162
+ }
1163
+ try {
1154
1164
  session.dispose();
1165
+ } catch (error) {
1166
+ cleanupFailures.push(error);
1155
1167
  }
1156
1168
  if (scratchDir !== void 0) {
1157
1169
  try {
1158
1170
  await rm2(scratchDir, { recursive: true, force: true });
1159
1171
  } catch (error) {
1160
- throw error;
1172
+ cleanupFailures.push(error);
1161
1173
  }
1162
1174
  }
1175
+ if (cleanupFailures.length === 1) throw cleanupFailures[0];
1176
+ if (cleanupFailures.length > 1) {
1177
+ throw new AggregateError(cleanupFailures, `${label} close cleanup failures`, {
1178
+ cause: cleanupFailures[0]
1179
+ });
1180
+ }
1163
1181
  }
1164
1182
  };
1165
1183
  return {
@@ -2769,6 +2787,7 @@ var PUBLIC_ROLE_RECORDS = [
2769
2787
  {
2770
2788
  role: "reviewer",
2771
2789
  phases: [null],
2790
+ bareCommand: false,
2772
2791
  outputTool: REVIEWER_OUTPUT_TOOL_NAME,
2773
2792
  inputFlag: void 0,
2774
2793
  phaseFlag: void 0,
@@ -2784,6 +2803,7 @@ var PUBLIC_ROLE_RECORDS = [
2784
2803
  {
2785
2804
  role: "collector",
2786
2805
  phases: [null],
2806
+ bareCommand: false,
2787
2807
  outputTool: COLLECTOR_OUTPUT_TOOL,
2788
2808
  inputFlag: void 0,
2789
2809
  phaseFlag: void 0,
@@ -2793,6 +2813,7 @@ var PUBLIC_ROLE_RECORDS = [
2793
2813
  {
2794
2814
  role: "doctor",
2795
2815
  phases: [null],
2816
+ bareCommand: false,
2796
2817
  outputTool: DOCTOR_OUTPUT_TOOL_NAME,
2797
2818
  inputFlag: "ak-doctor-case",
2798
2819
  phaseFlag: void 0,
@@ -2811,6 +2832,7 @@ var PUBLIC_ROLE_RECORDS = [
2811
2832
  {
2812
2833
  role: "notary",
2813
2834
  phases: [null],
2835
+ bareCommand: false,
2814
2836
  outputTool: NOTARY_OUTPUT_TOOL_NAME,
2815
2837
  inputFlag: "ak-notary-source-run",
2816
2838
  phaseFlag: void 0,
@@ -2829,6 +2851,7 @@ var PUBLIC_ROLE_RECORDS = [
2829
2851
  {
2830
2852
  role: "gleaner-left",
2831
2853
  phases: [null],
2854
+ bareCommand: false,
2832
2855
  outputTool: GLEANER_LEFT_OUTPUT_TOOL_NAME,
2833
2856
  inputFlag: void 0,
2834
2857
  phaseFlag: void 0,
@@ -2946,7 +2969,13 @@ import "@earendil-works/pi-ai";
2946
2969
  init_activation_ledger_git();
2947
2970
  init_activation_ledger_topology();
2948
2971
  import { createHash as createHash3, randomUUID } from "node:crypto";
2949
- import { appendFileSync, existsSync as existsSync2, readFileSync } from "node:fs";
2972
+ import {
2973
+ appendFileSync,
2974
+ existsSync as existsSync2,
2975
+ readFileSync,
2976
+ unlinkSync,
2977
+ writeFileSync
2978
+ } from "node:fs";
2950
2979
  import { basename as basename3, dirname as dirname6, join as join4, resolve as resolve5 } from "node:path";
2951
2980
 
2952
2981
  // src/sitian-contracts.ts
@@ -2968,6 +2997,123 @@ var SitianInfrastructureError = class extends Error {
2968
2997
  function isRecord5(value) {
2969
2998
  return typeof value === "object" && value !== null && !Array.isArray(value);
2970
2999
  }
3000
+ function errorCodeOf(error) {
3001
+ return error.code;
3002
+ }
3003
+ function identityClaimPath(recordFile, identity) {
3004
+ const digest = createHash3("sha256").update(identity, "utf8").digest("hex");
3005
+ return `${recordFile}.id-${digest}`;
3006
+ }
3007
+ function createExclusiveFile(path, contents) {
3008
+ writeFileSync(path, contents, { encoding: "utf8", flag: "wx" });
3009
+ }
3010
+ function sealTornTail(recordFile) {
3011
+ if (!existsSync2(recordFile)) return;
3012
+ const buffer = readFileSync(recordFile);
3013
+ if (buffer.length > 0 && buffer[buffer.length - 1] !== 10) {
3014
+ appendFileSync(recordFile, "\n", "utf8");
3015
+ }
3016
+ }
3017
+ function findIdentityPointer(recordFile, identity, kind, level) {
3018
+ if (!existsSync2(recordFile)) return void 0;
3019
+ const text = readFileSync(recordFile, "utf8");
3020
+ for (const line2 of text.split("\n")) {
3021
+ const trimmed = line2.trim();
3022
+ if (!trimmed) continue;
3023
+ try {
3024
+ const parsed = JSON.parse(trimmed);
3025
+ if (isRecord5(parsed) && parsed.identity === identity) {
3026
+ return { identity, recordFile, kind, level };
3027
+ }
3028
+ } catch {
3029
+ }
3030
+ }
3031
+ return void 0;
3032
+ }
3033
+ function unlinkAbsentOk(path) {
3034
+ try {
3035
+ unlinkSync(path);
3036
+ return void 0;
3037
+ } catch (error) {
3038
+ if (errorCodeOf(error) === "ENOENT") return void 0;
3039
+ return error instanceof Error ? error : new Error(errorText(error));
3040
+ }
3041
+ }
3042
+ function appendWithIdentityClaim(recordFile, record4, row) {
3043
+ sealTornTail(recordFile);
3044
+ const claimPath = identityClaimPath(recordFile, record4.identity);
3045
+ const existing = findIdentityPointer(
3046
+ recordFile,
3047
+ record4.identity,
3048
+ record4.kind,
3049
+ record4.level
3050
+ );
3051
+ if (existing !== void 0) {
3052
+ unlinkAbsentOk(claimPath);
3053
+ return existing;
3054
+ }
3055
+ try {
3056
+ createExclusiveFile(claimPath, "");
3057
+ } catch (error) {
3058
+ if (errorCodeOf(error) !== "EEXIST") throw error;
3059
+ sealTornTail(recordFile);
3060
+ const published = findIdentityPointer(
3061
+ recordFile,
3062
+ record4.identity,
3063
+ record4.kind,
3064
+ record4.level
3065
+ );
3066
+ if (published !== void 0) {
3067
+ unlinkAbsentOk(claimPath);
3068
+ return published;
3069
+ }
3070
+ throw new SitianInfrastructureError(
3071
+ `Sitian identity claim at ${claimPath} already exists for identity ${record4.identity}`,
3072
+ { cause: error }
3073
+ );
3074
+ }
3075
+ let primaryFailure;
3076
+ let result2;
3077
+ let cleanupFailure;
3078
+ try {
3079
+ sealTornTail(recordFile);
3080
+ const raced = findIdentityPointer(
3081
+ recordFile,
3082
+ record4.identity,
3083
+ record4.kind,
3084
+ record4.level
3085
+ );
3086
+ if (raced !== void 0) {
3087
+ result2 = raced;
3088
+ } else {
3089
+ appendFileSync(recordFile, row, "utf8");
3090
+ result2 = {
3091
+ identity: record4.identity,
3092
+ recordFile,
3093
+ kind: record4.kind,
3094
+ level: record4.level
3095
+ };
3096
+ }
3097
+ } catch (error) {
3098
+ primaryFailure = error;
3099
+ } finally {
3100
+ cleanupFailure = unlinkAbsentOk(claimPath);
3101
+ }
3102
+ if (primaryFailure !== void 0) {
3103
+ if (primaryFailure instanceof SitianInfrastructureError) throw primaryFailure;
3104
+ throw new SitianInfrastructureError(
3105
+ `Sitian appender persistence failure: ${errorText(primaryFailure)}`,
3106
+ { cause: primaryFailure }
3107
+ );
3108
+ }
3109
+ if (cleanupFailure !== void 0) {
3110
+ throw new SitianInfrastructureError(
3111
+ `Sitian identity claim at ${claimPath} could not be released after append for identity ${record4.identity}: ${errorText(cleanupFailure)}`,
3112
+ { cause: cleanupFailure }
3113
+ );
3114
+ }
3115
+ return result2;
3116
+ }
2971
3117
  var S4_SUBMISSION_LEDGER_KINDS = /* @__PURE__ */ new Set([
2972
3118
  "candidate",
2973
3119
  "roundContext",
@@ -3040,40 +3186,9 @@ function appendSitianRecord(input) {
3040
3186
  ...input.raw === void 0 ? {} : { raw: input.raw },
3041
3187
  ...input.usage === void 0 ? {} : { usage: input.usage }
3042
3188
  };
3043
- if (existsSync2(recordFile)) {
3044
- const buffer = readFileSync(recordFile);
3045
- if (buffer.length > 0) {
3046
- if (buffer[buffer.length - 1] !== 10) {
3047
- appendFileSync(recordFile, "\n", "utf8");
3048
- }
3049
- const text = readFileSync(recordFile, "utf8");
3050
- for (const line2 of text.split("\n")) {
3051
- const trimmed = line2.trim();
3052
- if (!trimmed) continue;
3053
- try {
3054
- const parsed = JSON.parse(trimmed);
3055
- if (isRecord5(parsed) && parsed.identity === identity) {
3056
- return {
3057
- identity,
3058
- recordFile,
3059
- kind: record4.kind,
3060
- level: record4.level
3061
- };
3062
- }
3063
- } catch {
3064
- }
3065
- }
3066
- }
3067
- }
3068
3189
  const row = `${JSON.stringify(record4)}
3069
3190
  `;
3070
- appendFileSync(recordFile, row, "utf8");
3071
- return {
3072
- identity,
3073
- recordFile,
3074
- kind: record4.kind,
3075
- level: record4.level
3076
- };
3191
+ return appendWithIdentityClaim(recordFile, record4, row);
3077
3192
  } catch (error) {
3078
3193
  if (error instanceof SitianInfrastructureError) throw error;
3079
3194
  throw new SitianInfrastructureError(
@@ -5457,9 +5572,16 @@ init_activation_ledger_topology();
5457
5572
  var PUBLIC_CALLABLE_ROLES2 = new Set(
5458
5573
  PACKAGED_ROLE_REGISTRY.map((entry) => entry.role)
5459
5574
  );
5575
+ function isPublicCallableRole2(role) {
5576
+ return PUBLIC_CALLABLE_ROLES2.has(role);
5577
+ }
5460
5578
  function renderPublicAkRoleCommand(target) {
5461
- if (!PUBLIC_CALLABLE_ROLES2.has(target.role)) return void 0;
5579
+ if (!isPublicCallableRole2(target.role)) return void 0;
5462
5580
  const role = target.role;
5581
+ const metadata = packagedRoleMetadata(role);
5582
+ if (metadata !== void 0 && "bareCommand" in metadata && metadata.bareCommand === false) {
5583
+ return void 0;
5584
+ }
5463
5585
  if (target.phase === null || target.phase === void 0) {
5464
5586
  return `ak-role ${role}`;
5465
5587
  }
@@ -7511,7 +7633,7 @@ function stringEnum(values, options = {}) {
7511
7633
  }
7512
7634
 
7513
7635
  // src/public-cli/reviewer-dispatch-rejection.ts
7514
- import { writeFileSync as writeFileSync2 } from "node:fs";
7636
+ import { writeFileSync as writeFileSync3 } from "node:fs";
7515
7637
  import { join as join19 } from "node:path";
7516
7638
 
7517
7639
  // src/adr-path-refs.ts
@@ -8114,7 +8236,7 @@ function reviewerDispatchRejectionPath(runDirectory) {
8114
8236
  return join19(runDirectory, REVIEWER_DISPATCH_REJECTION_FILE);
8115
8237
  }
8116
8238
  function recordReviewerDispatchRejectionSync(runDirectory, rejection) {
8117
- writeFileSync2(
8239
+ writeFileSync3(
8118
8240
  reviewerDispatchRejectionPath(runDirectory),
8119
8241
  `${JSON.stringify(rejection)}
8120
8242
  `,
@@ -8409,7 +8531,7 @@ import {
8409
8531
  lstatSync as lstatSync2,
8410
8532
  realpathSync as realpathSync3,
8411
8533
  statSync as statSync3,
8412
- writeFileSync as writeFileSync3
8534
+ writeFileSync as writeFileSync4
8413
8535
  } from "node:fs";
8414
8536
  import { isAbsolute as isAbsolute5, resolve as resolve14 } from "node:path";
8415
8537
  var ActivationSessionFileMissingError = class extends Error {
@@ -8430,7 +8552,7 @@ function materializeDeferredSessionFile(sessionManager, resolvedFile) {
8430
8552
  throw new ActivationSessionFileMissingError(resolvedFile);
8431
8553
  }
8432
8554
  try {
8433
- writeFileSync3(resolvedFile, `${JSON.stringify(header)}
8555
+ writeFileSync4(resolvedFile, `${JSON.stringify(header)}
8434
8556
  `, { flag: "wx" });
8435
8557
  } catch (error) {
8436
8558
  if (errnoCode(error) !== "EEXIST") {
@@ -13913,15 +14035,31 @@ async function prepareGrokRoleEnvelope(options) {
13913
14035
  const dispose = async () => {
13914
14036
  if (disposed) return;
13915
14037
  disposed = true;
14038
+ const cleanupFailures = [];
13916
14039
  try {
13917
14040
  await emit("session_shutdown", {});
14041
+ } catch (error) {
14042
+ cleanupFailures.push(error);
14043
+ }
14044
+ try {
14045
+ restoreAkRoleRunDir();
14046
+ } catch (error) {
14047
+ cleanupFailures.push(error);
14048
+ }
14049
+ try {
13918
14050
  const closeAll = server.closeAllConnections;
13919
14051
  if (typeof closeAll === "function") closeAll.call(server);
13920
14052
  await new Promise((resolve17, reject) => {
13921
14053
  server.close((error) => error ? reject(error) : resolve17());
13922
14054
  });
13923
- } finally {
13924
- restoreAkRoleRunDir();
14055
+ } catch (error) {
14056
+ cleanupFailures.push(error);
14057
+ }
14058
+ if (cleanupFailures.length === 1) throw cleanupFailures[0];
14059
+ if (cleanupFailures.length > 1) {
14060
+ throw new AggregateError(cleanupFailures, "Grok envelope dispose cleanup failures", {
14061
+ cause: cleanupFailures[0]
14062
+ });
13925
14063
  }
13926
14064
  };
13927
14065
  const closeRound = async () => {
@@ -66,6 +66,7 @@ const PUBLIC_ROLE_RECORDS = [
66
66
  {
67
67
  role: "reviewer",
68
68
  phases: [null],
69
+ bareCommand: false,
69
70
  outputTool: REVIEWER_OUTPUT_TOOL_NAME,
70
71
  inputFlag: void 0,
71
72
  phaseFlag: void 0,
@@ -81,6 +82,7 @@ const PUBLIC_ROLE_RECORDS = [
81
82
  {
82
83
  role: "collector",
83
84
  phases: [null],
85
+ bareCommand: false,
84
86
  outputTool: COLLECTOR_OUTPUT_TOOL,
85
87
  inputFlag: void 0,
86
88
  phaseFlag: void 0,
@@ -90,6 +92,7 @@ const PUBLIC_ROLE_RECORDS = [
90
92
  {
91
93
  role: "doctor",
92
94
  phases: [null],
95
+ bareCommand: false,
93
96
  outputTool: DOCTOR_OUTPUT_TOOL_NAME,
94
97
  inputFlag: "ak-doctor-case",
95
98
  phaseFlag: void 0,
@@ -108,6 +111,7 @@ const PUBLIC_ROLE_RECORDS = [
108
111
  {
109
112
  role: "notary",
110
113
  phases: [null],
114
+ bareCommand: false,
111
115
  outputTool: NOTARY_OUTPUT_TOOL_NAME,
112
116
  inputFlag: "ak-notary-source-run",
113
117
  phaseFlag: void 0,
@@ -126,6 +130,7 @@ const PUBLIC_ROLE_RECORDS = [
126
130
  {
127
131
  role: "gleaner-left",
128
132
  phases: [null],
133
+ bareCommand: false,
129
134
  outputTool: GLEANER_LEFT_OUTPUT_TOOL_NAME,
130
135
  inputFlag: void 0,
131
136
  phaseFlag: void 0,
@@ -541,6 +541,9 @@ async function openPiInstitutionalSession(options) {
541
541
  };
542
542
  if (options.signal?.aborted) abortSession();
543
543
  else options.signal?.addEventListener("abort", abortSession, { once: true });
544
+ const assistantCountBefore = session.messages.filter(
545
+ (message) => message.role === "assistant"
546
+ ).length;
544
547
  let promptError;
545
548
  try {
546
549
  await session.prompt(text);
@@ -561,7 +564,10 @@ async function openPiInstitutionalSession(options) {
561
564
  });
562
565
  }
563
566
  }
564
- if (promptError !== void 0 && lastAssistant === void 0) {
567
+ const producedAssistant = session.messages.filter(
568
+ (message) => message.role === "assistant"
569
+ ).length > assistantCountBefore;
570
+ if (promptError !== void 0 && !producedAssistant) {
565
571
  throw promptError;
566
572
  }
567
573
  return {
@@ -585,18 +591,30 @@ async function openPiInstitutionalSession(options) {
585
591
  if (closed) return;
586
592
  closed = true;
587
593
  listeners.clear();
594
+ const cleanupFailures = [];
588
595
  try {
589
596
  unsubscribeSession();
590
- } finally {
597
+ } catch (error) {
598
+ cleanupFailures.push(error);
599
+ }
600
+ try {
591
601
  session.dispose();
602
+ } catch (error) {
603
+ cleanupFailures.push(error);
592
604
  }
593
605
  if (scratchDir !== void 0) {
594
606
  try {
595
607
  await rm(scratchDir, { recursive: true, force: true });
596
608
  } catch (error) {
597
- throw error;
609
+ cleanupFailures.push(error);
598
610
  }
599
611
  }
612
+ if (cleanupFailures.length === 1) throw cleanupFailures[0];
613
+ if (cleanupFailures.length > 1) {
614
+ throw new AggregateError(cleanupFailures, `${label} close cleanup failures`, {
615
+ cause: cleanupFailures[0]
616
+ });
617
+ }
600
618
  }
601
619
  };
602
620
  return {