safeword 0.60.0 → 0.61.0

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.
Files changed (78) hide show
  1. package/dist/{architecture-32CAOL4P.js → architecture-WFRA4ITA.js} +6 -6
  2. package/dist/{check-PO4TEYZQ.js → check-KHWH36AK.js} +10 -10
  3. package/dist/chunk-B6KVKEZA.js +65 -0
  4. package/dist/chunk-B6KVKEZA.js.map +1 -0
  5. package/dist/{chunk-K7QZ6W2K.js → chunk-C4LNUGHF.js} +7 -7
  6. package/dist/{chunk-UIRPUAPO.js → chunk-GEC7AHRF.js} +54 -5
  7. package/dist/chunk-GEC7AHRF.js.map +1 -0
  8. package/dist/{chunk-XDT3W5MH.js → chunk-ILTC7KBQ.js} +66 -27
  9. package/dist/chunk-ILTC7KBQ.js.map +1 -0
  10. package/dist/{chunk-HKX3Z32Y.js → chunk-LBFUREUF.js} +6 -6
  11. package/dist/{chunk-NWCBLTIE.js → chunk-O2ULQPXW.js} +2 -1
  12. package/dist/{chunk-GS3TBFXU.js → chunk-OY7F4YNQ.js} +2 -2
  13. package/dist/chunk-U2GSR4OM.js +144 -0
  14. package/dist/chunk-U2GSR4OM.js.map +1 -0
  15. package/dist/{chunk-MV7VNFO6.js → chunk-XTGWCHWI.js} +8 -8
  16. package/dist/cli.js +38 -18
  17. package/dist/cli.js.map +1 -1
  18. package/dist/{codify-S4DJVZ4R.js → codify-BXBG5XPK.js} +3 -3
  19. package/dist/{diff-43VUWWRJ.js → diff-K3SYBGB7.js} +9 -9
  20. package/dist/github-rest-36XJI5HD.js +78 -0
  21. package/dist/github-rest-36XJI5HD.js.map +1 -0
  22. package/dist/output-7MPCY3U7.js +23 -0
  23. package/dist/{reset-C423HHTK.js → reset-4IGPE6TD.js} +7 -7
  24. package/dist/retro-FCGFUDEA.js +603 -0
  25. package/dist/retro-FCGFUDEA.js.map +1 -0
  26. package/dist/retro-extract-XXZI3DFW.js +30 -0
  27. package/dist/retro-extract-XXZI3DFW.js.map +1 -0
  28. package/dist/{self-report-CQLAESVT.js → self-report-AQZKGDAS.js} +4 -3
  29. package/dist/{self-report-CQLAESVT.js.map → self-report-AQZKGDAS.js.map} +1 -1
  30. package/dist/self-report-XLBFP2NT.js +36 -0
  31. package/dist/self-report-XLBFP2NT.js.map +1 -0
  32. package/dist/{setup-YAIS4ZQA.js → setup-SECXSZ5K.js} +12 -12
  33. package/dist/{sync-config-IUOYVDVQ.js → sync-config-VJFZJATR.js} +3 -3
  34. package/dist/sync-config-VJFZJATR.js.map +1 -0
  35. package/dist/{sync-learnings-XTHHJDPR.js → sync-learnings-BVNUNLPD.js} +3 -3
  36. package/dist/{sync-tickets-IQ4AACIH.js → sync-tickets-4TOJBDHW.js} +3 -3
  37. package/dist/{sync-tracker-2TGUIMAB.js → sync-tracker-U4TKFX4R.js} +7 -7
  38. package/dist/{test-plan-6X56C5JZ.js → test-plan-VMQRP2WF.js} +3 -3
  39. package/dist/{ticket-new-UIOKBXK2.js → ticket-new-PIHZGZGG.js} +5 -5
  40. package/dist/{upgrade-WMWT2WXK.js → upgrade-S5DTXDLC.js} +18 -18
  41. package/package.json +3 -1
  42. package/templates/codex/config.toml +8 -0
  43. package/templates/commands/audit.md +4 -3
  44. package/templates/guides/retro.md +81 -0
  45. package/templates/guides/self-report-filing.md +26 -0
  46. package/templates/hooks/codex/stop.ts +102 -0
  47. package/templates/hooks/cursor/stop.ts +54 -10
  48. package/templates/hooks/lib/jsonl-spool.ts +107 -0
  49. package/templates/hooks/lib/quality-state.ts +10 -0
  50. package/templates/hooks/lib/retro-draft-spool.ts +160 -0
  51. package/templates/hooks/lib/retro-extract.ts +309 -0
  52. package/templates/hooks/lib/retro-nudge.ts +86 -0
  53. package/templates/hooks/lib/retro-trigger.ts +477 -0
  54. package/templates/hooks/lib/self-report.ts +12 -35
  55. package/templates/hooks/prompt-retro-nudge.ts +48 -0
  56. package/templates/hooks/stop-retro.ts +77 -0
  57. package/templates/hooks/write-review-stamp.ts +37 -17
  58. package/templates/skills/audit/SKILL.md +8 -7
  59. package/dist/chunk-UIRPUAPO.js.map +0 -1
  60. package/dist/chunk-XDT3W5MH.js.map +0 -1
  61. /package/dist/{architecture-32CAOL4P.js.map → architecture-WFRA4ITA.js.map} +0 -0
  62. /package/dist/{check-PO4TEYZQ.js.map → check-KHWH36AK.js.map} +0 -0
  63. /package/dist/{chunk-K7QZ6W2K.js.map → chunk-C4LNUGHF.js.map} +0 -0
  64. /package/dist/{chunk-HKX3Z32Y.js.map → chunk-LBFUREUF.js.map} +0 -0
  65. /package/dist/{chunk-NWCBLTIE.js.map → chunk-O2ULQPXW.js.map} +0 -0
  66. /package/dist/{chunk-GS3TBFXU.js.map → chunk-OY7F4YNQ.js.map} +0 -0
  67. /package/dist/{chunk-MV7VNFO6.js.map → chunk-XTGWCHWI.js.map} +0 -0
  68. /package/dist/{codify-S4DJVZ4R.js.map → codify-BXBG5XPK.js.map} +0 -0
  69. /package/dist/{diff-43VUWWRJ.js.map → diff-K3SYBGB7.js.map} +0 -0
  70. /package/dist/{sync-config-IUOYVDVQ.js.map → output-7MPCY3U7.js.map} +0 -0
  71. /package/dist/{reset-C423HHTK.js.map → reset-4IGPE6TD.js.map} +0 -0
  72. /package/dist/{setup-YAIS4ZQA.js.map → setup-SECXSZ5K.js.map} +0 -0
  73. /package/dist/{sync-learnings-XTHHJDPR.js.map → sync-learnings-BVNUNLPD.js.map} +0 -0
  74. /package/dist/{sync-tickets-IQ4AACIH.js.map → sync-tickets-4TOJBDHW.js.map} +0 -0
  75. /package/dist/{sync-tracker-2TGUIMAB.js.map → sync-tracker-U4TKFX4R.js.map} +0 -0
  76. /package/dist/{test-plan-6X56C5JZ.js.map → test-plan-VMQRP2WF.js.map} +0 -0
  77. /package/dist/{ticket-new-UIOKBXK2.js.map → ticket-new-PIHZGZGG.js.map} +0 -0
  78. /package/dist/{upgrade-WMWT2WXK.js.map → upgrade-S5DTXDLC.js.map} +0 -0
@@ -3,17 +3,17 @@ import {
3
3
  isArchitectureDocumentEnforcementEnabled,
4
4
  resolveGeneratedArchitecturePath
5
5
  } from "./chunk-HI7ANNQI.js";
6
- import {
7
- error,
8
- success,
9
- warn
10
- } from "./chunk-NWCBLTIE.js";
11
6
  import {
12
7
  exists,
13
8
  isDirectory,
14
9
  readFileSafe,
15
10
  readJson
16
11
  } from "./chunk-2KELQTLE.js";
12
+ import {
13
+ error,
14
+ success,
15
+ warn
16
+ } from "./chunk-O2ULQPXW.js";
17
17
 
18
18
  // src/commands/architecture.ts
19
19
  import { execFileSync } from "child_process";
@@ -976,4 +976,4 @@ function architectureCheck(cwd) {
976
976
  export {
977
977
  architecture
978
978
  };
979
- //# sourceMappingURL=architecture-32CAOL4P.js.map
979
+ //# sourceMappingURL=architecture-WFRA4ITA.js.map
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  buildIndexConflictListMessage
3
3
  } from "./chunk-ZESHX2BU.js";
4
- import {
5
- fetchRegistryLatestVersion,
6
- isNewerVersion
7
- } from "./chunk-LRYWFRPD.js";
8
4
  import {
9
5
  checkHealth,
10
6
  reportHealthSummary
11
- } from "./chunk-MV7VNFO6.js";
7
+ } from "./chunk-XTGWCHWI.js";
12
8
  import "./chunk-HWOJR33A.js";
13
9
  import "./chunk-XTLCJKGE.js";
14
- import "./chunk-UIRPUAPO.js";
10
+ import {
11
+ fetchRegistryLatestVersion,
12
+ isNewerVersion
13
+ } from "./chunk-LRYWFRPD.js";
14
+ import "./chunk-GEC7AHRF.js";
15
15
  import {
16
16
  detectPackageManager
17
- } from "./chunk-GS3TBFXU.js";
17
+ } from "./chunk-OY7F4YNQ.js";
18
18
  import {
19
19
  syncTickets
20
20
  } from "./chunk-D4UGNHLW.js";
@@ -22,14 +22,14 @@ import "./chunk-NHXVS5FL.js";
22
22
  import "./chunk-HI7ANNQI.js";
23
23
  import "./chunk-CXGL65PS.js";
24
24
  import "./chunk-HSC7TELY.js";
25
+ import "./chunk-2KELQTLE.js";
25
26
  import {
26
27
  header,
27
28
  info,
28
29
  keyValue,
29
30
  success,
30
31
  warn
31
- } from "./chunk-NWCBLTIE.js";
32
- import "./chunk-2KELQTLE.js";
32
+ } from "./chunk-O2ULQPXW.js";
33
33
 
34
34
  // src/commands/check.ts
35
35
  import process from "process";
@@ -125,4 +125,4 @@ async function check(options) {
125
125
  export {
126
126
  check
127
127
  };
128
- //# sourceMappingURL=check-PO4TEYZQ.js.map
128
+ //# sourceMappingURL=check-KHWH36AK.js.map
@@ -0,0 +1,65 @@
1
+ // templates/hooks/lib/jsonl-spool.ts
2
+ import { appendFileSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
3
+ import nodePath from "path";
4
+ function* iterateJsonlEntries(text) {
5
+ for (const line of text.split("\n")) {
6
+ if (line.trim().length === 0) continue;
7
+ let value;
8
+ try {
9
+ value = JSON.parse(line);
10
+ } catch {
11
+ continue;
12
+ }
13
+ yield value;
14
+ }
15
+ }
16
+ function countJsonlRecords(filePath) {
17
+ try {
18
+ return readFileSync(filePath, "utf8").split("\n").filter((line) => line.trim().length > 0).length;
19
+ } catch {
20
+ return 0;
21
+ }
22
+ }
23
+ function readJsonlRecords(filePath, parse) {
24
+ let raw;
25
+ try {
26
+ raw = readFileSync(filePath, "utf8");
27
+ } catch {
28
+ return [];
29
+ }
30
+ const records = [];
31
+ for (const value of iterateJsonlEntries(raw)) {
32
+ try {
33
+ const record = parse(value);
34
+ if (record !== void 0) records.push(record);
35
+ } catch {
36
+ }
37
+ }
38
+ return records;
39
+ }
40
+ function appendJsonlRecords(filePath, lines, cap) {
41
+ try {
42
+ const room = cap - countJsonlRecords(filePath);
43
+ if (room <= 0) return;
44
+ const toWrite = lines.slice(0, room);
45
+ if (toWrite.length === 0) return;
46
+ mkdirSync(nodePath.dirname(filePath), { recursive: true });
47
+ appendFileSync(filePath, `${toWrite.join("\n")}
48
+ `);
49
+ } catch {
50
+ }
51
+ }
52
+ function atomicWriteFile(file, contents) {
53
+ const temporary = `${file}.${process.pid}.tmp`;
54
+ mkdirSync(nodePath.dirname(file), { recursive: true });
55
+ writeFileSync(temporary, contents);
56
+ renameSync(temporary, file);
57
+ }
58
+
59
+ export {
60
+ iterateJsonlEntries,
61
+ readJsonlRecords,
62
+ appendJsonlRecords,
63
+ atomicWriteFile
64
+ };
65
+ //# sourceMappingURL=chunk-B6KVKEZA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../templates/hooks/lib/jsonl-spool.ts"],"sourcesContent":["// Per-session JSONL spool I/O — the shared machinery under the self-report spool\n// (lib/self-report.ts) and the retro draft spool (lib/retro-draft-spool.ts).\n//\n// Both persist sanitized, per-session records to `.safeword/<dir>/<session>.jsonl`\n// and had their own copy of: count non-blank lines, read-and-skip-torn-lines,\n// cap-aware append, and atomic (temp+rename) rewrite. That machinery is\n// correctness-sensitive (torn-tolerance, fail-open, whole-or-nothing writes), so it\n// lives here ONCE. Callers keep what genuinely differs — the subdir, the filename\n// sanitizer, the record schema (parse/serialize), and the cap value — and pass a\n// resolved file path in.\n//\n// Self-contained (node:* only) so the CLI's src/ and the customer-repo hooks can\n// both run it, like the two spools it backs.\n\nimport { appendFileSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport nodePath from 'node:path';\n\n/**\n * Yield the JSON-parsed value of each non-blank JSONL line in `text`, skipping any\n * blank or torn (unparseable) line — never throws. The single home for the\n * split / skip-blank / parse-or-skip skeleton shared by the spool reader here and\n * the transcript scanners (retro-trigger's counters, retro-extract's digest);\n * callers supply only their per-entry handling.\n */\nexport function* iterateJsonlEntries(text: string): Generator<unknown> {\n for (const line of text.split('\\n')) {\n if (line.trim().length === 0) continue;\n let value: unknown;\n try {\n value = JSON.parse(line);\n } catch {\n continue; // skip a torn/malformed JSONL line\n }\n yield value;\n }\n}\n\n/** Count non-blank JSONL records in a spool file (0 when absent/unreadable). */\nexport function countJsonlRecords(filePath: string): number {\n try {\n return readFileSync(filePath, 'utf8')\n .split('\\n')\n .filter(line => line.trim().length > 0).length;\n } catch {\n return 0;\n }\n}\n\n/**\n * Read every JSONL line, JSON.parse it, and map it through `parse` — skipping any\n * blank, torn (unparseable), or rejected (`parse` → undefined) line. Fail-open: a\n * missing or unreadable file yields `[]`, never a throw, so a filing/read path never\n * crashes on a bad spool.\n */\nexport function readJsonlRecords<T>(\n filePath: string,\n parse: (value: unknown) => T | undefined,\n): T[] {\n let raw: string;\n try {\n raw = readFileSync(filePath, 'utf8');\n } catch {\n return [];\n }\n const records: T[] = [];\n for (const value of iterateJsonlEntries(raw)) {\n try {\n const record = parse(value);\n if (record !== undefined) records.push(record);\n } catch {\n // a parse callback that rejects a malformed record is skipped, not fatal\n }\n }\n return records;\n}\n\n/**\n * Append pre-serialized JSONL lines, capped: once the file already holds `cap`\n * records, drop the overflow rather than growing unbounded (bounds a crash-looping\n * or runaway session). BEST-EFFORT — never throws, so a spool-write failure can't\n * break the host path that called it.\n */\nexport function appendJsonlRecords(filePath: string, lines: readonly string[], cap: number): void {\n try {\n const room = cap - countJsonlRecords(filePath);\n if (room <= 0) return;\n const toWrite = lines.slice(0, room);\n if (toWrite.length === 0) return;\n mkdirSync(nodePath.dirname(filePath), { recursive: true });\n appendFileSync(filePath, `${toWrite.join('\\n')}\\n`);\n } catch {\n // Self-observation must never break the host. Swallow.\n }\n}\n\n/**\n * Write `contents` to `file` atomically: write a pid-unique temp sibling, then\n * rename onto the target, so a concurrent reader sees the whole old or whole new\n * file — never a half-written one. Creates the parent dir. Throws on I/O error;\n * callers that must stay fail-open wrap it in their own try/catch.\n */\nexport function atomicWriteFile(file: string, contents: string): void {\n const temporary = `${file}.${process.pid}.tmp`;\n mkdirSync(nodePath.dirname(file), { recursive: true });\n writeFileSync(temporary, contents);\n renameSync(temporary, file);\n}\n"],"mappings":";AAcA,SAAS,gBAAgB,WAAW,cAAc,YAAY,qBAAqB;AACnF,OAAO,cAAc;AASd,UAAU,oBAAoB,MAAkC;AACrE,aAAW,QAAQ,KAAK,MAAM,IAAI,GAAG;AACnC,QAAI,KAAK,KAAK,EAAE,WAAW,EAAG;AAC9B,QAAI;AACJ,QAAI;AACF,cAAQ,KAAK,MAAM,IAAI;AAAA,IACzB,QAAQ;AACN;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAGO,SAAS,kBAAkB,UAA0B;AAC1D,MAAI;AACF,WAAO,aAAa,UAAU,MAAM,EACjC,MAAM,IAAI,EACV,OAAO,UAAQ,KAAK,KAAK,EAAE,SAAS,CAAC,EAAE;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQO,SAAS,iBACd,UACA,OACK;AACL,MAAI;AACJ,MAAI;AACF,UAAM,aAAa,UAAU,MAAM;AAAA,EACrC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,QAAM,UAAe,CAAC;AACtB,aAAW,SAAS,oBAAoB,GAAG,GAAG;AAC5C,QAAI;AACF,YAAM,SAAS,MAAM,KAAK;AAC1B,UAAI,WAAW,OAAW,SAAQ,KAAK,MAAM;AAAA,IAC/C,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAQO,SAAS,mBAAmB,UAAkB,OAA0B,KAAmB;AAChG,MAAI;AACF,UAAM,OAAO,MAAM,kBAAkB,QAAQ;AAC7C,QAAI,QAAQ,EAAG;AACf,UAAM,UAAU,MAAM,MAAM,GAAG,IAAI;AACnC,QAAI,QAAQ,WAAW,EAAG;AAC1B,cAAU,SAAS,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AACzD,mBAAe,UAAU,GAAG,QAAQ,KAAK,IAAI,CAAC;AAAA,CAAI;AAAA,EACpD,QAAQ;AAAA,EAER;AACF;AAQO,SAAS,gBAAgB,MAAc,UAAwB;AACpE,QAAM,YAAY,GAAG,IAAI,IAAI,QAAQ,GAAG;AACxC,YAAU,SAAS,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AACrD,gBAAc,WAAW,QAAQ;AACjC,aAAW,WAAW,IAAI;AAC5B;","names":[]}
@@ -4,20 +4,20 @@ import {
4
4
  detectLanguages,
5
5
  isGitRepo,
6
6
  isPackInstalled
7
- } from "./chunk-UIRPUAPO.js";
7
+ } from "./chunk-GEC7AHRF.js";
8
8
  import {
9
9
  SAFEWORD_PEER_DEPENDENCIES
10
10
  } from "./chunk-HSC7TELY.js";
11
+ import {
12
+ exists,
13
+ readJson
14
+ } from "./chunk-2KELQTLE.js";
11
15
  import {
12
16
  info,
13
17
  listItem,
14
18
  success,
15
19
  warn
16
- } from "./chunk-NWCBLTIE.js";
17
- import {
18
- exists,
19
- readJson
20
- } from "./chunk-2KELQTLE.js";
20
+ } from "./chunk-O2ULQPXW.js";
21
21
 
22
22
  // src/packs/install.ts
23
23
  function installPack(packId, cwd) {
@@ -546,4 +546,4 @@ export {
546
546
  getEslintPeerMismatchWarning,
547
547
  maybeAutoPatchOrNudge
548
548
  };
549
- //# sourceMappingURL=chunk-K7QZ6W2K.js.map
549
+ //# sourceMappingURL=chunk-C4LNUGHF.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  MCP_SERVERS
3
- } from "./chunk-GS3TBFXU.js";
3
+ } from "./chunk-OY7F4YNQ.js";
4
4
  import {
5
5
  NAMESPACE_ROOT_LEGACY,
6
6
  readConfiguredPath,
@@ -2226,6 +2226,9 @@ function hook(command) {
2226
2226
  function asyncRewakeHook(command) {
2227
2227
  return { hooks: [{ type: "command", command, asyncRewake: true }] };
2228
2228
  }
2229
+ function asyncHook(command) {
2230
+ return { hooks: [{ type: "command", command, async: true }] };
2231
+ }
2229
2232
  function matchedHook(matcher, command) {
2230
2233
  return { matcher, hooks: [{ type: "command", command }] };
2231
2234
  }
@@ -2252,12 +2255,18 @@ var SETTINGS_HOOKS = {
2252
2255
  ],
2253
2256
  UserPromptSubmit: [
2254
2257
  hook(`bun ${HOOKS_DIR}/prompt-timestamp.ts`),
2255
- hook(`bun ${HOOKS_DIR}/prompt-questions.ts`)
2258
+ hook(`bun ${HOOKS_DIR}/prompt-questions.ts`),
2259
+ // Cloud-retro filing nudge (BNGK9W): when the async Stop hook spooled unfiled
2260
+ // drafts (REST 401 in cloud), surface one factual line so the agent files them.
2261
+ hook(`bun ${HOOKS_DIR}/prompt-retro-nudge.ts`)
2256
2262
  ],
2257
2263
  Stop: [
2258
2264
  hook(`bun ${HOOKS_DIR}/stop-quality.ts`),
2259
2265
  hook(`bun ${HOOKS_DIR}/stop-reentry.ts`),
2260
- hook(`bun ${HOOKS_DIR}/stop-self-report.ts`)
2266
+ hook(`bun ${HOOKS_DIR}/stop-self-report.ts`),
2267
+ // Invisible retro (ZFGWS1): async so repeated delta fires never block Stop and
2268
+ // run fully in the background; the inner spawnSync stays sync within that tree.
2269
+ asyncHook(`bun ${HOOKS_DIR}/stop-retro.ts`)
2261
2270
  ],
2262
2271
  PreToolUse: [
2263
2272
  matchedHook("Bash", `bun ${HOOKS_DIR}/pre-tool-dependency-readiness.ts`),
@@ -2934,6 +2943,15 @@ command = 'bun "$(git rev-parse --show-toplevel)/.safeword/hooks/codex/pre-tool-
2934
2943
  timeout = 30
2935
2944
  statusMessage = "Checking safeword PreToolUse gates"
2936
2945
  `;
2946
+ var CODEX_STOP_HOOK_PATCH = `
2947
+ [[hooks.Stop]]
2948
+
2949
+ [[hooks.Stop.hooks]]
2950
+ type = "command"
2951
+ command = 'bun "$(git rev-parse --show-toplevel)/.safeword/hooks/codex/stop.ts"'
2952
+ timeout = 30
2953
+ statusMessage = "Checking safeword Stop nudges"
2954
+ `;
2937
2955
  var CODEX_POST_TOOL_SKILL_NUDGE_HOOK_PATCH = `
2938
2956
  [[hooks.PostToolUse]]
2939
2957
  matcher = "^(apply_patch|Edit|Write|MultiEdit|NotebookEdit)$"
@@ -3077,6 +3095,9 @@ var SAFEWORD_SCHEMA = {
3077
3095
  preservedDirs: [
3078
3096
  ".safeword-project/learnings",
3079
3097
  ".safeword/logs",
3098
+ // Runtime cloud-filing spool (BNGK9W) — per-session drafts + nudge markers the
3099
+ // retro writes at runtime; user/runtime data the schema does not own.
3100
+ ".safeword/retro-drafts",
3080
3101
  ".safeword-project/tickets",
3081
3102
  ".safeword-project/tickets/completed",
3082
3103
  ".safeword-project/tmp"
@@ -3258,7 +3279,12 @@ var SAFEWORD_SCHEMA = {
3258
3279
  template: "hooks/lib/dependency-readiness.ts"
3259
3280
  },
3260
3281
  ".safeword/hooks/lib/done-gate.ts": { template: "hooks/lib/done-gate.ts" },
3282
+ ".safeword/hooks/lib/jsonl-spool.ts": { template: "hooks/lib/jsonl-spool.ts" },
3261
3283
  ".safeword/hooks/lib/namespace-root.ts": { template: "hooks/lib/namespace-root.ts" },
3284
+ ".safeword/hooks/lib/retro-draft-spool.ts": { template: "hooks/lib/retro-draft-spool.ts" },
3285
+ ".safeword/hooks/lib/retro-extract.ts": { template: "hooks/lib/retro-extract.ts" },
3286
+ ".safeword/hooks/lib/retro-nudge.ts": { template: "hooks/lib/retro-nudge.ts" },
3287
+ ".safeword/hooks/lib/retro-trigger.ts": { template: "hooks/lib/retro-trigger.ts" },
3262
3288
  ".safeword/hooks/lib/self-report.ts": { template: "hooks/lib/self-report.ts" },
3263
3289
  ".safeword/hooks/lib/skill-invocation-log.ts": {
3264
3290
  template: "hooks/lib/skill-invocation-log.ts"
@@ -3329,6 +3355,9 @@ var SAFEWORD_SCHEMA = {
3329
3355
  ".safeword/hooks/prompt-questions.ts": {
3330
3356
  template: "hooks/prompt-questions.ts"
3331
3357
  },
3358
+ ".safeword/hooks/prompt-retro-nudge.ts": {
3359
+ template: "hooks/prompt-retro-nudge.ts"
3360
+ },
3332
3361
  ".safeword/hooks/post-tool-lint.ts": {
3333
3362
  template: "hooks/post-tool-lint.ts"
3334
3363
  },
@@ -3356,6 +3385,9 @@ var SAFEWORD_SCHEMA = {
3356
3385
  ".safeword/hooks/codex/pre-tool-quality-helpers.ts": {
3357
3386
  template: "hooks/codex/pre-tool-quality-helpers.ts"
3358
3387
  },
3388
+ ".safeword/hooks/codex/stop.ts": {
3389
+ template: "hooks/codex/stop.ts"
3390
+ },
3359
3391
  ".safeword/hooks/codex/post-tool-skill-nudge.ts": {
3360
3392
  template: "hooks/codex/post-tool-skill-nudge.ts"
3361
3393
  },
@@ -3382,6 +3414,7 @@ var SAFEWORD_SCHEMA = {
3382
3414
  },
3383
3415
  ".safeword/hooks/stop-quality.ts": { template: "hooks/stop-quality.ts" },
3384
3416
  ".safeword/hooks/stop-reentry.ts": { template: "hooks/stop-reentry.ts" },
3417
+ ".safeword/hooks/stop-retro.ts": { template: "hooks/stop-retro.ts" },
3385
3418
  ".safeword/hooks/stop-self-report.ts": { template: "hooks/stop-self-report.ts" },
3386
3419
  ".safeword/hooks/session-start-reentry.ts": {
3387
3420
  template: "hooks/session-start-reentry.ts"
@@ -3399,6 +3432,9 @@ var SAFEWORD_SCHEMA = {
3399
3432
  ".safeword/guides/self-report-filing.md": {
3400
3433
  template: "guides/self-report-filing.md"
3401
3434
  },
3435
+ ".safeword/guides/retro.md": {
3436
+ template: "guides/retro.md"
3437
+ },
3402
3438
  ".safeword/guides/cold-start-check.md": {
3403
3439
  template: "guides/cold-start-check.md"
3404
3440
  },
@@ -3778,10 +3814,23 @@ ${managedPrettierPaths(ctx).join("\n")}
3778
3814
  unpatchContent: [
3779
3815
  CODEX_SESSION_START_HOOK_PATCH,
3780
3816
  CODEX_LEGACY_CONTEXT_SESSION_START_HOOK_PATCH,
3781
- CODEX_PRE_TOOL_QUALITY_HOOK_PATCH
3817
+ CODEX_PRE_TOOL_QUALITY_HOOK_PATCH,
3818
+ CODEX_STOP_HOOK_PATCH
3782
3819
  ],
3783
3820
  removeFileIfContentEquals: [CODEX_CONFIG_SCAFFOLD_WITHOUT_HOOKS]
3784
3821
  },
3822
+ // Codex Stop hook retrofit (53DQJZ): add-if-missing, guarded to safeword
3823
+ // scaffolds. Marker is the adapter path so an existing entry suppresses the
3824
+ // append. Uninstall cleanup is owned by the primary patch's unpatchContent.
3825
+ {
3826
+ operation: "append",
3827
+ content: CODEX_STOP_HOOK_PATCH,
3828
+ marker: ".safeword/hooks/codex/stop.ts",
3829
+ applyWhenContentIncludes: [
3830
+ "# Safeword Codex project configuration.",
3831
+ ".safeword/hooks/codex/pre-tool-quality.ts"
3832
+ ]
3833
+ },
3785
3834
  // Migrate existing installs (auto-upgrade-codex follow-up to #433): swap the
3786
3835
  // legacy context-only SessionStart hook for the auto-upgrade dispatcher.
3787
3836
  // Codex runs same-event hooks concurrently with no ordering, so this must
@@ -4166,4 +4215,4 @@ export {
4166
4215
  untrackIgnoredFiles,
4167
4216
  createProjectContext
4168
4217
  };
4169
- //# sourceMappingURL=chunk-UIRPUAPO.js.map
4218
+ //# sourceMappingURL=chunk-GEC7AHRF.js.map