@akagilnc/pi-workflow-roles 0.1.3545 → 0.1.3552

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.
@@ -149,22 +149,26 @@ export async function resolveSeatTicketBinding(
149
149
  }
150
150
 
151
151
  /**
152
- * Shared same-ticket → resume decision (#637).
152
+ * Sole same-ticket → resume decision (#637 / #724).
153
153
  * Looks up the latest retained run for seat+ticket; when found, runs resume with
154
154
  * this summons' materials. Lookup/resume failures propagate (失败诚实) — never
155
- * wash into a fresh mint. Returns undefined only when no prior run exists.
155
+ * wash into a fresh mint. Returns undefined when the caller declared an explicit
156
+ * fresh summons (`ak-role new`) or when no prior run exists; both mint new.
157
+ * freshSummons is required so no seat can drift back into its own skip branch.
156
158
  */
157
159
  export async function tryResumeSameTicketSeatRun<T>(input: {
158
160
  readonly home: string;
159
161
  readonly projectRoot: string;
160
162
  readonly role: RoleRunRecord["role"];
161
163
  readonly ticketNumber: number;
164
+ readonly freshSummons: true | undefined;
162
165
  readonly summons?: SameTicketSummonsMaterials;
163
166
  readonly resume: (
164
167
  runId: string,
165
168
  summons: SameTicketSummonsMaterials | undefined,
166
169
  ) => Promise<T>;
167
170
  }): Promise<T | undefined> {
171
+ if (input.freshSummons === true) return undefined;
168
172
  const previousRunId = await findLatestRunIdForSeatTicket({
169
173
  home: input.home,
170
174
  bookKey: resolveBookKeyFromGit(input.projectRoot),
@@ -1,69 +0,0 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
-
4
- import {
5
- FIXER_BASH_FORBIDDEN_LITERALS,
6
- fixerBashSeatbeltDenyReason,
7
- } from "../fixer-bash-seatbelt.ts";
8
-
9
- /**
10
- * Render the Grok PreToolUse hook script.
11
- * Literals and deny reason come from the single ADR 0008 authority; this file is
12
- * transport-only (stdin event → stdout decision JSON for the Grok hook runner).
13
- */
14
- export function renderGrokBashSeatbeltHookScript(): string {
15
- // Reason templates are baked from the authority so the standalone hook process
16
- // cannot drift from fixerBashSeatbeltDenyReason without editing this render call.
17
- const reasons = Object.fromEntries(
18
- FIXER_BASH_FORBIDDEN_LITERALS.map((literal) => [literal, fixerBashSeatbeltDenyReason(literal)]),
19
- );
20
- return `#!/usr/bin/env node
21
- const LITERALS = ${JSON.stringify([...FIXER_BASH_FORBIDDEN_LITERALS])};
22
- const REASONS = ${JSON.stringify(reasons)};
23
- let raw = "";
24
- process.stdin.setEncoding("utf8");
25
- process.stdin.on("data", (chunk) => { raw += chunk; });
26
- process.stdin.on("end", () => {
27
- let event = {};
28
- try { event = JSON.parse(raw); } catch { /* fail-open on malformed host payload */ }
29
- const input = event && typeof event === "object" ? event.toolInput : undefined;
30
- const command = input && typeof input === "object" && typeof input.command === "string"
31
- ? input.command : undefined;
32
- const matched = typeof command === "string"
33
- ? LITERALS.find((literal) => command.includes(literal))
34
- : undefined;
35
- const decision = matched === undefined
36
- ? { decision: "allow" }
37
- : { decision: "deny", reason: REASONS[matched] };
38
- process.stdout.write(JSON.stringify(decision));
39
- });
40
- `;
41
- }
42
-
43
- /**
44
- * Install the AK bash seatbelt into a controlled Grok home (GROK_HOME root).
45
- * Never writes the operator's private ~/.grok — callers must pass the isolated home.
46
- */
47
- export async function installGrokPreToolUseDeny(controlledHome: string): Promise<void> {
48
- const hooksDir = join(controlledHome, "hooks");
49
- await mkdir(hooksDir, { recursive: true });
50
- const scriptName = "ak-bash-seatbelt.mjs";
51
- const scriptPath = join(hooksDir, scriptName);
52
- await writeFile(scriptPath, renderGrokBashSeatbeltHookScript(), { mode: 0o755 });
53
- await writeFile(join(hooksDir, "ak-bash-seatbelt.json"), `${JSON.stringify({
54
- hooks: {
55
- PreToolUse: [
56
- {
57
- matcher: "Bash|run_terminal_command",
58
- hooks: [
59
- {
60
- type: "command",
61
- command: process.execPath + " " + JSON.stringify(scriptPath),
62
- timeout: 5,
63
- },
64
- ],
65
- },
66
- ],
67
- },
68
- }, null, 2)}\n`);
69
- }