@akagilnc/pi-workflow-roles 0.1.1756 → 0.1.1764

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.
@@ -15321,20 +15321,50 @@ async function writeRoleInvocationLedger(source, role) {
15321
15321
  "utf8"
15322
15322
  );
15323
15323
  }
15324
- async function recordLaunchedPiIdentity(runDirectory, identity) {
15324
+ async function mergeInvocationIdentityPage(runDirectory, fields) {
15325
15325
  const ledgerPath = join4(runDirectory, "invocation.json");
15326
15326
  const current = JSON.parse(await readFile4(ledgerPath, "utf8"));
15327
15327
  await writeFile2(
15328
15328
  ledgerPath,
15329
15329
  `${JSON.stringify({
15330
15330
  ...current,
15331
- piExecutable: identity.executable,
15332
- piVersion: identity.version
15331
+ ...fields
15333
15332
  }, null, 2)}
15334
15333
  `,
15335
15334
  "utf8"
15336
15335
  );
15337
15336
  }
15337
+ async function recordLaunchedPiIdentity(runDirectory, identity) {
15338
+ await mergeInvocationIdentityPage(runDirectory, {
15339
+ piExecutable: identity.executable,
15340
+ piVersion: identity.version
15341
+ });
15342
+ }
15343
+ async function observeLaunchedRolePackageIdentity(packageRoot2, selectedRoleEntry) {
15344
+ const rolePackageRoot = packageRoot2;
15345
+ const raw = JSON.parse(
15346
+ await readFile4(join4(rolePackageRoot, "package.json"), "utf8")
15347
+ );
15348
+ if (typeof raw.version !== "string" || raw.version.trim() === "") {
15349
+ throw new Error(
15350
+ `role package.json at ${rolePackageRoot} does not declare a nonblank version`
15351
+ );
15352
+ }
15353
+ return {
15354
+ roleEntry: selectedRoleEntry,
15355
+ rolePackageRoot,
15356
+ rolePackageVersion: raw.version,
15357
+ entryMode: "public-cli"
15358
+ };
15359
+ }
15360
+ async function recordLaunchedRolePackageIdentity(runDirectory, identity) {
15361
+ await mergeInvocationIdentityPage(runDirectory, {
15362
+ roleEntry: identity.roleEntry,
15363
+ rolePackageRoot: identity.rolePackageRoot,
15364
+ rolePackageVersion: identity.rolePackageVersion,
15365
+ entryMode: identity.entryMode
15366
+ });
15367
+ }
15338
15368
  function requireOptionPath(flag, value) {
15339
15369
  if (value === void 0 || value.trim() === "") {
15340
15370
  throw new CliUsageError(
@@ -16698,13 +16728,8 @@ import { promisify as promisify2 } from "node:util";
16698
16728
  function resolveInternalRoleEntrypoint(packageRoot2) {
16699
16729
  return join5(packageRoot2, INTERNAL_ROLE_ENTRYPOINT_RELATIVE);
16700
16730
  }
16701
- function buildExplicitInternalActivationArgs(packageRoot2, extraArgs = []) {
16702
- return [
16703
- "--no-extensions",
16704
- "-e",
16705
- resolveInternalRoleEntrypoint(packageRoot2),
16706
- ...extraArgs
16707
- ];
16731
+ function buildExplicitInternalActivationArgs(selectedRoleEntry, extraArgs = []) {
16732
+ return ["--no-extensions", "-e", selectedRoleEntry, ...extraArgs];
16708
16733
  }
16709
16734
  function knownFailureFromProviderStop(input) {
16710
16735
  if (input.stopReason !== "error") return void 0;
@@ -16750,20 +16775,31 @@ async function selectedPiIdentity(command, cwd, env) {
16750
16775
  return { executable, version };
16751
16776
  }
16752
16777
  async function runExplicitInternalActivation(options) {
16778
+ const roleEntry = await realpath3(
16779
+ resolveInternalRoleEntrypoint(options.packageRoot)
16780
+ );
16753
16781
  const args = buildExplicitInternalActivationArgs(
16754
- options.packageRoot,
16782
+ roleEntry,
16755
16783
  options.extraArgs ?? []
16756
16784
  );
16757
16785
  const runner = options.runner ?? defaultExplicitInternalPiRunner;
16786
+ const env = {
16787
+ ...process.env,
16788
+ ...options.env,
16789
+ HOME: options.home,
16790
+ PI_CODING_AGENT_DIR: options.agentDir
16791
+ };
16792
+ const runDirectory = env.AK_ROLE_RUN_DIR;
16793
+ if (typeof runDirectory === "string" && runDirectory !== "") {
16794
+ await recordLaunchedRolePackageIdentity(
16795
+ runDirectory,
16796
+ await observeLaunchedRolePackageIdentity(options.packageRoot, roleEntry)
16797
+ );
16798
+ }
16758
16799
  return await runner(args, {
16759
16800
  cwd: options.cwd,
16760
16801
  ...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs },
16761
- env: {
16762
- ...process.env,
16763
- ...options.env,
16764
- HOME: options.home,
16765
- PI_CODING_AGENT_DIR: options.agentDir
16766
- }
16802
+ env
16767
16803
  });
16768
16804
  }
16769
16805
  var execFileAsync2, defaultExplicitInternalPiRunner;
@@ -23117,6 +23153,7 @@ __export(cli_exports, {
23117
23153
  resolveInternalRoleEntrypoint: () => resolveInternalRoleEntrypoint,
23118
23154
  runAkRole: () => runAkRole
23119
23155
  });
23156
+ import { realpath as realpath5 } from "node:fs/promises";
23120
23157
  import { homedir as homedir3 } from "node:os";
23121
23158
  import { join as join16 } from "node:path";
23122
23159
  function defaultIo() {
@@ -23310,6 +23347,7 @@ async function runAkRole(argv, env) {
23310
23347
  const io = env.io ?? defaultIo();
23311
23348
  const home = resolveHome(env);
23312
23349
  try {
23350
+ env = { ...env, packageRoot: await realpath5(env.packageRoot) };
23313
23351
  const parsed = parseArgv(argv);
23314
23352
  if (parsed.help || parsed.command === void 0 || parsed.command === "help") {
23315
23353
  if (parsed.command === "help" && parsed.args[0] !== void 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.1756",
3
+ "version": "0.1.1764",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
package/souls/judge.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  你是大理寺。卷由别人提交,你只负责逐条审理、裁决和判断是否收敛;不承担施工,
4
4
  不提交变更。可为取证运行验证,即使产生可逆的工作树副作用;落判前恢复开庭基线并
5
- 如实记载。
5
+ 如实记载。此类取证不构成污点,不得据此自设回避、复判等法外程序。
6
6
 
7
7
  ## 证据
8
8
 
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Public ak-role CLI dispatcher (roles / config / layered help / Judge run).
3
3
  */
4
+ import { realpath } from "node:fs/promises";
4
5
  import { homedir } from "node:os";
5
6
  import { join } from "node:path";
6
7
 
@@ -352,6 +353,9 @@ export async function runAkRole(
352
353
  const home = resolveHome(env);
353
354
 
354
355
  try {
356
+ // Select the installed package identity once, before any role-owned Skill,
357
+ // runtime entry, activation argv, or invocation provenance is derived.
358
+ env = { ...env, packageRoot: await realpath(env.packageRoot) };
355
359
  const parsed = parseArgv(argv);
356
360
 
357
361
  if (
@@ -10,7 +10,11 @@ import { delimiter, isAbsolute, join, resolve } from "node:path";
10
10
  import { platform } from "node:process";
11
11
  import { promisify } from "node:util";
12
12
 
13
- import { recordLaunchedPiIdentity } from "./invocation.ts";
13
+ import {
14
+ observeLaunchedRolePackageIdentity,
15
+ recordLaunchedPiIdentity,
16
+ recordLaunchedRolePackageIdentity,
17
+ } from "./invocation.ts";
14
18
  import { INTERNAL_ROLE_ENTRYPOINT_RELATIVE } from "./registry.ts";
15
19
  import type { ControlledFailureCause } from "./terminal.ts";
16
20
 
@@ -23,15 +27,10 @@ export function resolveInternalRoleEntrypoint(packageRoot: string): string {
23
27
  * Ordinary Pi package auto-registration does not include this entrypoint (ADR 0052).
24
28
  */
25
29
  export function buildExplicitInternalActivationArgs(
26
- packageRoot: string,
30
+ selectedRoleEntry: string,
27
31
  extraArgs: readonly string[] = [],
28
32
  ): string[] {
29
- return [
30
- "--no-extensions",
31
- "-e",
32
- resolveInternalRoleEntrypoint(packageRoot),
33
- ...extraArgs,
34
- ];
33
+ return ["--no-extensions", "-e", selectedRoleEntry, ...extraArgs];
35
34
  }
36
35
 
37
36
  /** Production-owned typed failure carried on a resolved runner result. */
@@ -246,20 +245,34 @@ export async function runExplicitInternalActivation(options: {
246
245
  timeoutMs?: number | undefined;
247
246
  runner?: ExplicitInternalPiRunner;
248
247
  }): Promise<ExplicitInternalPiResult> {
248
+ const roleEntry = await realpath(
249
+ resolveInternalRoleEntrypoint(options.packageRoot),
250
+ );
249
251
  const args = buildExplicitInternalActivationArgs(
250
- options.packageRoot,
252
+ roleEntry,
251
253
  options.extraArgs ?? [],
252
254
  );
253
255
  const runner = options.runner ?? defaultExplicitInternalPiRunner;
256
+ const env: NodeJS.ProcessEnv = {
257
+ ...process.env,
258
+ ...options.env,
259
+ HOME: options.home,
260
+ PI_CODING_AGENT_DIR: options.agentDir,
261
+ };
262
+ // Package provenance is known at the public CLI seam before Pi starts — write it
263
+ // onto the existing invocation page so runs remain attributable even when the
264
+ // child runner is injected or Pi identity recording never fires.
265
+ const runDirectory = env.AK_ROLE_RUN_DIR;
266
+ if (typeof runDirectory === "string" && runDirectory !== "") {
267
+ await recordLaunchedRolePackageIdentity(
268
+ runDirectory,
269
+ await observeLaunchedRolePackageIdentity(options.packageRoot, roleEntry),
270
+ );
271
+ }
254
272
  return await runner(args, {
255
273
  cwd: options.cwd,
256
274
  ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
257
- env: {
258
- ...process.env,
259
- ...options.env,
260
- HOME: options.home,
261
- PI_CODING_AGENT_DIR: options.agentDir,
262
- },
275
+ env,
263
276
  });
264
277
  }
265
278
 
@@ -188,10 +188,10 @@ async function writeRoleInvocationLedger(
188
188
  );
189
189
  }
190
190
 
191
- /** Add the identity returned by the production Pi launch seam to its existing ledger page. */
192
- export async function recordLaunchedPiIdentity(
191
+ /** Merge observed launch-time fields into the single existing invocation.json identity page. */
192
+ async function mergeInvocationIdentityPage(
193
193
  runDirectory: string,
194
- identity: { executable: string; version: string },
194
+ fields: Record<string, unknown>,
195
195
  ): Promise<void> {
196
196
  const ledgerPath = join(runDirectory, "invocation.json");
197
197
  const current = JSON.parse(await readFile(ledgerPath, "utf8")) as Record<string, unknown>;
@@ -199,13 +199,73 @@ export async function recordLaunchedPiIdentity(
199
199
  ledgerPath,
200
200
  `${JSON.stringify({
201
201
  ...current,
202
- piExecutable: identity.executable,
203
- piVersion: identity.version,
202
+ ...fields,
204
203
  }, null, 2)}\n`,
205
204
  "utf8",
206
205
  );
207
206
  }
208
207
 
208
+ /** Add the identity returned by the production Pi launch seam to its existing ledger page. */
209
+ export async function recordLaunchedPiIdentity(
210
+ runDirectory: string,
211
+ identity: { executable: string; version: string },
212
+ ): Promise<void> {
213
+ await mergeInvocationIdentityPage(runDirectory, {
214
+ piExecutable: identity.executable,
215
+ piVersion: identity.version,
216
+ });
217
+ }
218
+
219
+ /**
220
+ * Observed role-package launch provenance written onto the same invocation.json page.
221
+ * Values are field observations from the public CLI activation seam — never fixed schema markers.
222
+ */
223
+ export type LaunchedRolePackageIdentity = {
224
+ /** Canonical absolute path of the selected Internal role entry (extensions/role-runtime.ts). */
225
+ readonly roleEntry: string;
226
+ /** Canonical absolute package root that owns the entry and bin. */
227
+ readonly rolePackageRoot: string;
228
+ /** package.json version of that root as read at launch. */
229
+ readonly rolePackageVersion: string;
230
+ /** How this process crossed into the role runtime (ADR 0052 public CLI). */
231
+ readonly entryMode: "public-cli";
232
+ };
233
+
234
+ /** Read the package root that is about to serve this public run (observed values only). */
235
+ export async function observeLaunchedRolePackageIdentity(
236
+ packageRoot: string,
237
+ selectedRoleEntry: string,
238
+ ): Promise<LaunchedRolePackageIdentity> {
239
+ const rolePackageRoot = packageRoot;
240
+ const raw = JSON.parse(
241
+ await readFile(join(rolePackageRoot, "package.json"), "utf8"),
242
+ ) as { version?: unknown };
243
+ if (typeof raw.version !== "string" || raw.version.trim() === "") {
244
+ throw new Error(
245
+ `role package.json at ${rolePackageRoot} does not declare a nonblank version`,
246
+ );
247
+ }
248
+ return {
249
+ roleEntry: selectedRoleEntry,
250
+ rolePackageRoot,
251
+ rolePackageVersion: raw.version,
252
+ entryMode: "public-cli",
253
+ };
254
+ }
255
+
256
+ /** Add the role-package identity resolved at the public launch seam to its existing ledger page. */
257
+ export async function recordLaunchedRolePackageIdentity(
258
+ runDirectory: string,
259
+ identity: LaunchedRolePackageIdentity,
260
+ ): Promise<void> {
261
+ await mergeInvocationIdentityPage(runDirectory, {
262
+ roleEntry: identity.roleEntry,
263
+ rolePackageRoot: identity.rolePackageRoot,
264
+ rolePackageVersion: identity.rolePackageVersion,
265
+ entryMode: identity.entryMode,
266
+ });
267
+ }
268
+
209
269
  export type ParseJudgeArgvResult = {
210
270
  instruction: string;
211
271
  attachmentPaths: string[];