session-orchestrator 5.1.0 → 5.2.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 (293) hide show
  1. package/.agents/skills/autopilot/SKILL.md +1 -0
  2. package/.agents/skills/bootstrap/SKILL.md +2 -0
  3. package/.agents/skills/brainstorm/SKILL.md +3 -0
  4. package/.agents/skills/close/SKILL.md +17 -0
  5. package/.agents/skills/debug/SKILL.md +2 -0
  6. package/.agents/skills/discovery/SKILL.md +2 -1
  7. package/.agents/skills/dispatcher/SKILL.md +2 -0
  8. package/.agents/skills/eli5/SKILL.md +2 -0
  9. package/.agents/skills/eval/SKILL.md +1 -0
  10. package/.agents/skills/evolve/SKILL.md +2 -1
  11. package/.agents/skills/go/SKILL.md +18 -0
  12. package/.agents/skills/grill/SKILL.md +2 -0
  13. package/.agents/skills/harness-audit/SKILL.md +16 -0
  14. package/.agents/skills/memory-cleanup/SKILL.md +1 -0
  15. package/.agents/skills/persona-panel/SKILL.md +1 -0
  16. package/.agents/skills/plan/SKILL.md +3 -1
  17. package/.agents/skills/portfolio/SKILL.md +17 -0
  18. package/.agents/skills/reconcile/SKILL.md +1 -0
  19. package/.agents/skills/release/SKILL.md +18 -0
  20. package/.agents/skills/repo-audit/SKILL.md +1 -0
  21. package/.agents/skills/spinout/SKILL.md +1 -0
  22. package/.agents/skills/sunset-review/SKILL.md +2 -0
  23. package/.agents/skills/test/SKILL.md +17 -0
  24. package/.agents/skills/ux-grill/SKILL.md +2 -0
  25. package/.claude-plugin/marketplace.json +1 -1
  26. package/.claude-plugin/plugin.json +1 -1
  27. package/.codex-plugin/plugin.json +1 -1
  28. package/.codex-plugin/skills/autopilot/SKILL.md +5 -4
  29. package/.codex-plugin/skills/bootstrap/SKILL.md +8 -4
  30. package/.codex-plugin/skills/brainstorm/SKILL.md +11 -4
  31. package/.codex-plugin/skills/close/SKILL.md +3 -3
  32. package/.codex-plugin/skills/convergence-monitoring/SKILL.md +2 -0
  33. package/.codex-plugin/skills/convergence-monitoring/agents/openai.yaml +5 -0
  34. package/.codex-plugin/skills/debug/SKILL.md +11 -4
  35. package/.codex-plugin/skills/discovery/SKILL.md +8 -4
  36. package/.codex-plugin/skills/dispatcher/SKILL.md +4 -4
  37. package/.codex-plugin/skills/eli5/SKILL.md +9 -4
  38. package/.codex-plugin/skills/eval/SKILL.md +9 -4
  39. package/.codex-plugin/skills/evolve/SKILL.md +9 -4
  40. package/.codex-plugin/skills/go/SKILL.md +3 -3
  41. package/.codex-plugin/skills/grill/SKILL.md +11 -4
  42. package/.codex-plugin/skills/harness-audit/SKILL.md +4 -3
  43. package/.codex-plugin/skills/memory-cleanup/SKILL.md +9 -4
  44. package/.codex-plugin/skills/npm-publish/SKILL.md +2 -0
  45. package/.codex-plugin/skills/npm-publish/agents/openai.yaml +5 -0
  46. package/.codex-plugin/skills/persona-panel/SKILL.md +5 -5
  47. package/.codex-plugin/skills/plan/SKILL.md +8 -4
  48. package/.codex-plugin/skills/portfolio/SKILL.md +3 -3
  49. package/.codex-plugin/skills/reconcile/SKILL.md +9 -4
  50. package/.codex-plugin/skills/release/SKILL.md +3 -3
  51. package/.codex-plugin/skills/repo-audit/SKILL.md +6 -4
  52. package/.codex-plugin/skills/spinout/SKILL.md +4 -4
  53. package/.codex-plugin/skills/sunset-review/SKILL.md +5 -4
  54. package/.codex-plugin/skills/test/SKILL.md +3 -3
  55. package/.codex-plugin/skills/ux-grill/SKILL.md +11 -4
  56. package/.cursor/commands/autopilot.md +4 -4
  57. package/.cursor/commands/bootstrap.md +5 -4
  58. package/.cursor/commands/brainstorm.md +5 -4
  59. package/.cursor/commands/close.md +4 -3
  60. package/.cursor/commands/convergence-monitoring.md +13 -0
  61. package/.cursor/commands/debug.md +4 -4
  62. package/.cursor/commands/discovery.md +4 -4
  63. package/.cursor/commands/dispatcher.md +4 -4
  64. package/.cursor/commands/eli5.md +4 -4
  65. package/.cursor/commands/eval.md +4 -4
  66. package/.cursor/commands/evolve.md +4 -4
  67. package/.cursor/commands/go.md +4 -3
  68. package/.cursor/commands/grill.md +4 -4
  69. package/.cursor/commands/harness-audit.md +3 -3
  70. package/.cursor/commands/memory-cleanup.md +4 -4
  71. package/.cursor/commands/npm-publish.md +13 -0
  72. package/.cursor/commands/persona-panel.md +4 -4
  73. package/.cursor/commands/plan.md +5 -4
  74. package/.cursor/commands/portfolio.md +3 -3
  75. package/.cursor/commands/reconcile.md +4 -4
  76. package/.cursor/commands/release.md +4 -3
  77. package/.cursor/commands/repo-audit.md +4 -4
  78. package/.cursor/commands/spinout.md +4 -4
  79. package/.cursor/commands/sunset-review.md +4 -4
  80. package/.cursor/commands/test.md +3 -3
  81. package/.cursor/commands/ux-grill.md +4 -4
  82. package/.cursor/rules/010-session-workflow.mdc +2 -2
  83. package/.cursor/skills/bootstrap/SKILL.md +1 -0
  84. package/.cursor/skills/close/SKILL.md +13 -0
  85. package/.cursor/skills/debug/SKILL.md +0 -1
  86. package/.cursor/skills/discovery/SKILL.md +0 -1
  87. package/.cursor/skills/dispatcher/SKILL.md +0 -1
  88. package/.cursor/skills/eli5/SKILL.md +0 -1
  89. package/.cursor/skills/evolve/SKILL.md +0 -1
  90. package/.cursor/skills/go/SKILL.md +13 -0
  91. package/.cursor/skills/grill/SKILL.md +0 -1
  92. package/.cursor/skills/harness-audit/SKILL.md +12 -0
  93. package/.cursor/skills/portfolio/SKILL.md +12 -0
  94. package/.cursor/skills/release/SKILL.md +13 -0
  95. package/.cursor/skills/repo-audit/SKILL.md +0 -1
  96. package/.cursor/skills/sunset-review/SKILL.md +0 -1
  97. package/.cursor/skills/test/SKILL.md +12 -0
  98. package/.cursor/skills/ux-grill/SKILL.md +0 -1
  99. package/.cursor-plugin/plugin.json +1 -1
  100. package/.orchestrator/policy/blocked-commands.json +1 -1
  101. package/AGENTS.md +1 -1
  102. package/CHANGELOG.md +61 -0
  103. package/README.md +11 -9
  104. package/commands/session.md +10 -0
  105. package/docs/ci-setup.md +53 -0
  106. package/docs/codex-setup.md +1 -1
  107. package/docs/components.md +11 -6
  108. package/docs/events-schema.md +4 -1
  109. package/docs/install.md +16 -0
  110. package/docs/persona-panel.md +1 -1
  111. package/docs/pi-setup.md +1 -1
  112. package/docs/rule-authoring.md +83 -14
  113. package/docs/scope-collision-guard.md +2 -0
  114. package/docs/session-config-reference.md +6 -4
  115. package/hooks/_lib/hook-import-set.json +46 -6
  116. package/hooks/_lib/subagent-paths.mjs +15 -0
  117. package/hooks/_lib/vcs-create-matcher.mjs +217 -62
  118. package/hooks/hooks-codex.json +1 -1
  119. package/hooks/hooks.json +1 -1
  120. package/hooks/on-session-end.mjs +14 -2
  121. package/hooks/on-stop.mjs +43 -1
  122. package/hooks/post-bash-write-verify.mjs +3 -0
  123. package/hooks/pre-auq-clarity.mjs +3 -0
  124. package/hooks/pre-bash-issue-budget.mjs +103 -17
  125. package/hooks/pre-task-scope-disjoint.mjs +152 -3
  126. package/hooks/skill-invocation-telemetry.mjs +2 -1
  127. package/package.json +2 -1
  128. package/pi/prompts/autopilot.md +3 -3
  129. package/pi/prompts/bootstrap.md +3 -3
  130. package/pi/prompts/brainstorm.md +3 -3
  131. package/pi/prompts/close.md +2 -2
  132. package/pi/prompts/convergence-monitoring.md +11 -0
  133. package/pi/prompts/debug.md +3 -3
  134. package/pi/prompts/discovery.md +3 -3
  135. package/pi/prompts/dispatcher.md +3 -3
  136. package/pi/prompts/eli5.md +3 -3
  137. package/pi/prompts/eval.md +3 -3
  138. package/pi/prompts/evolve.md +3 -3
  139. package/pi/prompts/go.md +2 -2
  140. package/pi/prompts/grill.md +3 -3
  141. package/pi/prompts/harness-audit.md +2 -3
  142. package/pi/prompts/memory-cleanup.md +3 -3
  143. package/pi/prompts/npm-publish.md +11 -0
  144. package/pi/prompts/persona-panel.md +3 -3
  145. package/pi/prompts/plan.md +3 -3
  146. package/pi/prompts/portfolio.md +2 -2
  147. package/pi/prompts/reconcile.md +3 -3
  148. package/pi/prompts/release.md +3 -3
  149. package/pi/prompts/repo-audit.md +3 -4
  150. package/pi/prompts/session.md +1 -1
  151. package/pi/prompts/spinout.md +3 -3
  152. package/pi/prompts/sunset-review.md +3 -3
  153. package/pi/prompts/templates-ack.md +1 -1
  154. package/pi/prompts/test.md +3 -3
  155. package/pi/prompts/ux-grill.md +3 -3
  156. package/scripts/archive-closed-prds.mjs +2 -2
  157. package/scripts/auq-audit.mjs +2 -3
  158. package/scripts/backfill-abandoned-sessions.mjs +57 -3
  159. package/scripts/backfill-evidence-digest.mjs +2 -1
  160. package/scripts/backfill-learnings-from-vault.mjs +2 -2
  161. package/scripts/check-package-manager.mjs +2 -2
  162. package/scripts/ci/assert-vitest-green.mjs +2 -1
  163. package/scripts/emit-session.mjs +2 -3
  164. package/scripts/export-hw-learnings.mjs +2 -1
  165. package/scripts/express-path.mjs +1 -1
  166. package/scripts/gc-stale-worktrees.mjs +2 -1
  167. package/scripts/generate-codex-skills.mjs +48 -4
  168. package/scripts/generate-cursor-adapter.mjs +173 -9
  169. package/scripts/generate-hook-import-set.mjs +12 -27
  170. package/scripts/generate-pi-prompts.mjs +183 -13
  171. package/scripts/github-protection-audit.mjs +2 -3
  172. package/scripts/lib/agent-frontmatter.mjs +23 -1
  173. package/scripts/lib/claude-md-budget-lint.mjs +2 -5
  174. package/scripts/lib/command-blocker.mjs +133 -5
  175. package/scripts/lib/config/drift-check.mjs +19 -0
  176. package/scripts/lib/convergence-monitor.mjs +2 -2
  177. package/scripts/lib/cursor-hook-bridge.mjs +2 -2
  178. package/scripts/lib/description-surface.mjs +2 -5
  179. package/scripts/lib/dispatcher/cli.mjs +2 -1
  180. package/scripts/lib/ecosystem-wizard.mjs +2 -1
  181. package/scripts/lib/fetch-baseline.mjs +3 -8
  182. package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +2 -1
  183. package/scripts/lib/gitlab-portfolio/cli.mjs +2 -1
  184. package/scripts/lib/instruction-budget-guard.mjs +186 -46
  185. package/scripts/lib/is-main-module.mjs +82 -0
  186. package/scripts/lib/locks/index.mjs +32 -25
  187. package/scripts/lib/maintenance-due-banner.mjs +69 -3
  188. package/scripts/lib/peer-discovery.mjs +2 -5
  189. package/scripts/lib/playwright-driver/runner.mjs +2 -1
  190. package/scripts/lib/reconcile/rule-expiry-sweep.mjs +642 -0
  191. package/scripts/lib/rules-sync.mjs +2 -5
  192. package/scripts/lib/scope-echo.mjs +392 -7
  193. package/scripts/lib/session-close-backfill.mjs +58 -6
  194. package/scripts/lib/state-md.mjs +84 -3
  195. package/scripts/lib/sunset/walker.mjs +31 -4
  196. package/scripts/lib/tests-src-ratio.mjs +2 -6
  197. package/scripts/lib/tmux-layout/telemetry-stats.mjs +2 -1
  198. package/scripts/lib/user-invocable-skills.mjs +185 -0
  199. package/scripts/lib/validate/check-banner-parity.mjs +2 -2
  200. package/scripts/lib/validate/check-cursor-adapter.mjs +2 -2
  201. package/scripts/lib/validate/check-dead-bridge.mjs +2 -2
  202. package/scripts/lib/validate/check-doc-cli-commands.mjs +2 -2
  203. package/scripts/lib/validate/check-entry-guard.mjs +366 -0
  204. package/scripts/lib/validate/check-guard-requires-parity.mjs +2 -2
  205. package/scripts/lib/validate/check-hooks-emit-event-guard.mjs +2 -2
  206. package/scripts/lib/validate/check-learning-provenance.mjs +2 -2
  207. package/scripts/lib/validate/check-skill-links.mjs +27 -6
  208. package/scripts/lib/validate/check-skill-script-paths.mjs +2 -2
  209. package/scripts/lib/validate/check-test-git-config-target.mjs +2 -2
  210. package/scripts/lib/validate/check-unicode-safety.mjs +2 -2
  211. package/scripts/lib/validate/check-untracked-test-deps.mjs +2 -2
  212. package/scripts/lib/validate/check-unwired-features.mjs +91 -7
  213. package/scripts/lib/validate/check-validator-registration.mjs +2 -2
  214. package/scripts/lib/validate/check-vcs-repo-flag.mjs +2 -2
  215. package/scripts/lib/validate-vendored-rules.mjs +35 -9
  216. package/scripts/lib/wave-transcript-tail.mjs +2 -2
  217. package/scripts/lock-reaper.mjs +2 -1
  218. package/scripts/materialize-wave-scope.mjs +87 -4
  219. package/scripts/migrate-sessions-jsonl.mjs +2 -1
  220. package/scripts/migrate-vault-paths.mjs +2 -3
  221. package/scripts/release.mjs +80 -35
  222. package/scripts/relocate-vault-corpus.mjs +2 -3
  223. package/scripts/repair-invalid-sessions.mjs +2 -2
  224. package/scripts/session-shape.mjs +2 -2
  225. package/scripts/site-numbers.mjs +35 -11
  226. package/scripts/sweep-expired-rules.mjs +216 -0
  227. package/scripts/validate-plugin.mjs +9 -0
  228. package/scripts/vault-consolidate.mjs +2 -2
  229. package/scripts/vault-mirror.mjs +2 -3
  230. package/scripts/wave-scope-binding.mjs +2 -3
  231. package/skills/_shared/bootstrap-gate.md +1 -1
  232. package/skills/_shared/monitor-patterns.md +1 -1
  233. package/skills/_shared/research-evidence.md +53 -0
  234. package/skills/_shared/state-ownership.md +3 -0
  235. package/skills/autopilot/SKILL.md +58 -4
  236. package/skills/bootstrap/SKILL.md +51 -1
  237. package/skills/brainstorm/SKILL.md +16 -0
  238. package/skills/claude-md-drift-check/checker.mjs +49 -11
  239. package/{commands/close.md → skills/close/SKILL.md} +9 -3
  240. package/skills/debug/SKILL.md +10 -0
  241. package/skills/discovery/SKILL.md +24 -1
  242. package/skills/discovery/probes-session.md +2 -2
  243. package/skills/dispatcher/SKILL.md +38 -7
  244. package/skills/eli5/SKILL.md +11 -0
  245. package/skills/eval/SKILL.md +14 -0
  246. package/skills/evolve/SKILL.md +8 -1
  247. package/skills/evolve/references/evolve-dialectic-mode.md +6 -2
  248. package/{commands/go.md → skills/go/SKILL.md} +9 -1
  249. package/skills/grill/SKILL.md +19 -0
  250. package/{commands/harness-audit.md → skills/harness-audit/SKILL.md} +7 -2
  251. package/skills/hook-development/SKILL.md +46 -41
  252. package/skills/memory-cleanup/SKILL.md +7 -0
  253. package/skills/npm-publish/SKILL.md +1 -1
  254. package/skills/persona-panel/SKILL.md +56 -1
  255. package/skills/persona-panel/persona-format.md +1 -1
  256. package/skills/plan/SKILL.md +28 -1
  257. package/{commands/portfolio.md → skills/portfolio/SKILL.md} +8 -2
  258. package/skills/reconcile/SKILL.md +10 -0
  259. package/{commands/release.md → skills/release/SKILL.md} +16 -2
  260. package/skills/repo-audit/SKILL.md +7 -0
  261. package/skills/session-end/plan-verification.md +2 -2
  262. package/skills/session-plan/SKILL.md +1 -1
  263. package/skills/session-start/SKILL.md +5 -4
  264. package/skills/session-start/phase-8-5-express-path.md +6 -6
  265. package/skills/session-start/references/phase-1-5-session-continuity.md +1 -1
  266. package/skills/session-start/references/phase-2-7-portfolio-snapshot.md +1 -1
  267. package/skills/session-start/references/phase-4-ssot-environment-check.md +4 -3
  268. package/skills/spinout/SKILL.md +12 -1
  269. package/skills/sunset-review/SKILL.md +13 -0
  270. package/{commands/test.md → skills/test/SKILL.md} +10 -4
  271. package/skills/ux-grill/SKILL.md +19 -1
  272. package/skills/wave-executor/SKILL.md +7 -4
  273. package/skills/wave-executor/references/wave-executor-state-init.md +13 -1
  274. package/skills/wave-executor/references/wave-loop-dispatch.md +3 -1
  275. package/skills/wave-executor/references/wave-loop-review.md +17 -1
  276. package/commands/autopilot.md +0 -80
  277. package/commands/bootstrap.md +0 -56
  278. package/commands/brainstorm.md +0 -48
  279. package/commands/debug.md +0 -36
  280. package/commands/discovery.md +0 -32
  281. package/commands/dispatcher.md +0 -59
  282. package/commands/eli5.md +0 -33
  283. package/commands/eval.md +0 -28
  284. package/commands/evolve.md +0 -10
  285. package/commands/grill.md +0 -45
  286. package/commands/memory-cleanup.md +0 -26
  287. package/commands/persona-panel.md +0 -121
  288. package/commands/plan.md +0 -15
  289. package/commands/reconcile.md +0 -23
  290. package/commands/repo-audit.md +0 -24
  291. package/commands/spinout.md +0 -15
  292. package/commands/sunset-review.md +0 -27
  293. package/commands/ux-grill.md +0 -51
@@ -0,0 +1,82 @@
1
+ /**
2
+ * is-main-module.mjs — the one entry-guard predicate, symlink-safe.
3
+ *
4
+ * ## The incident class
5
+ *
6
+ * An ESM module that wants to run `main()` only when invoked as a CLI has to
7
+ * compare "the module I am" against "the script Node was told to run". The two
8
+ * sides are NOT the same kind of path:
9
+ *
10
+ * - `import.meta.url` is resolved by Node to the module's **realpath**.
11
+ * - `process.argv[1]` is the path **as typed on the command line**.
12
+ *
13
+ * With a symlink anywhere in the invocation path — a `node_modules/.bin/` shim,
14
+ * a `~/bin/foo -> /repo/scripts/foo.mjs` convenience link, a plugin directory
15
+ * symlinked into `~/.claude/plugins/`, or `/tmp` itself (on macOS `/tmp` is a
16
+ * symlink to `/private/tmp`) — the two strings differ and the guard is FALSE.
17
+ *
18
+ * The failure is silent and total: `main()` never runs, nothing is printed, and
19
+ * the process exits 0. Every caller — a hook, a CI job, an npm script, an
20
+ * operator — reads that as success. This is the single worst shape a defect can
21
+ * have in this repo, which is why the predicate is centralised here instead of
22
+ * being re-typed per file.
23
+ *
24
+ * ## The textual variants this replaces
25
+ *
26
+ * Measured 2026-09-16 @ ca214376 over the 50 files swept for #1371, the guard
27
+ * had been hand-written in 15 distinct textual forms (measured by extracting the
28
+ * guard expression from every file at HEAD), collapsing into four
29
+ * semantic variants — all four wrong in the same way:
30
+ *
31
+ * V1 import.meta.url === `file://${process.argv[1]}`
32
+ * (also breaks on any space or non-ASCII char in the path — no escaping)
33
+ * V2 import.meta.url === pathToFileURL(process.argv[1] ?? '').href
34
+ * V3 resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url))
35
+ * / resolve(process.argv[1]) === resolve(__filename)
36
+ * V4 fileURLToPath(import.meta.url) === process.argv[1]
37
+ *
38
+ * V2/V3 fix the `undefined`-argv and relative-path cases; none of them resolve
39
+ * symlinks, because only `realpath` does.
40
+ *
41
+ * ## Non-goal: Windows drive-letter / case folding
42
+ *
43
+ * `realpathSync.native` delegates to the OS, so on NTFS it canonicalises the
44
+ * stored casing of every path component and the two sides agree. Where the
45
+ * realpath call FAILS (deleted path, permission error) the fallback is a raw
46
+ * string compare, which on Windows can be case-sensitive against a
47
+ * case-insensitive filesystem. That residual case is deliberately out of scope:
48
+ * this repo runs on macOS and Linux CI, and a case-only mismatch degrades to
49
+ * today's behaviour rather than to something worse.
50
+ *
51
+ * @module scripts/lib/is-main-module
52
+ */
53
+
54
+ import { realpathSync } from 'node:fs';
55
+ import { fileURLToPath } from 'node:url';
56
+
57
+ /**
58
+ * Whether the module identified by `importMetaUrl` is the script Node was
59
+ * invoked with.
60
+ *
61
+ * Symlink-safe: both sides are canonicalised via `realpathSync.native` before
62
+ * comparison, so an invocation through a symlink (shim, `~/bin` link, `/tmp` on
63
+ * macOS) still matches. When either path cannot be realpath'd — it was deleted
64
+ * between spawn and this call, or is unreadable — the comparison degrades to a
65
+ * raw string compare rather than throwing, because an entry guard must never be
66
+ * the thing that crashes an import.
67
+ *
68
+ * @param {string} importMetaUrl the calling module's `import.meta.url`
69
+ * @param {string | undefined} [argv1] the invoked script path; defaults to
70
+ * `process.argv[1]`, which is `undefined` under `node -e`, the REPL and some
71
+ * dynamic-import contexts — those return `false`
72
+ * @returns {boolean} true when this module IS the entrypoint
73
+ */
74
+ export function isMainModule(importMetaUrl, argv1 = process.argv[1]) {
75
+ if (!argv1) return false;
76
+ const self = fileURLToPath(importMetaUrl);
77
+ try {
78
+ return realpathSync.native(argv1) === realpathSync.native(self);
79
+ } catch {
80
+ return argv1 === self;
81
+ }
82
+ }
@@ -1,31 +1,38 @@
1
1
  /**
2
- * locks/index.mjs — convenience barrel for the short-lived lock protocols split
3
- * out of session-lock.mjs in #630 (A1 barrel-preserving split).
2
+ * locks/index.mjs — DEPRECATED convenience barrel for the lock protocols
3
+ * split out of session-lock.mjs in #630 (A1 barrel-preserving split).
4
4
  *
5
- * Re-exports both protocol modules so a consumer can `import { withStateMdLock,
6
- * withStagingFenceLock } from '@lib/locks/index.mjs'` in one statement. This is
7
- * a nice-to-have: session-lock.mjs remains the canonical barrel that preserves
8
- * the original 22-symbol import surface, and the two protocol modules are also
9
- * importable directly.
5
+ * @deprecated since 5.2.0, removed in 6.0.0. Import directly from
6
+ * `./state-md-lock.mjs` / `./staging-fence-lock.mjs`, or from
7
+ * `scripts/lib/session-lock.mjs` for the canonical 22-symbol barrel that
8
+ * preserves the original import surface for all its importers.
10
9
  *
11
- * Pure re-export leaf — imports only the two sibling modules, never
12
- * session-lock.mjs, so there is no import cycle.
10
+ * This file shipped in 5.1.0 with zero in-repo importers and was deleted in
11
+ * dd05e0f8 (`check-unwired-features` S4: no hook, npm script, CI job or husky
12
+ * stage reached it, and it named symbols — not modules — so it did not qualify
13
+ * for the pure `export *` exemption that shape gets). Restored here as a
14
+ * one-cycle deprecation shim (`.claude/rules/development.md` § Package Lifecycle
15
+ * & Versioning) because `package.json` carries no `exports` map: every packed
16
+ * file under `scripts/lib/` is public, so a consumer that deep-imported this
17
+ * path before the deletion has no compile error to warn it, only a runtime
18
+ * "module not found" — a shim buys that consumer one minor cycle to migrate
19
+ * before 6.0.0 removes the path outright.
20
+ *
21
+ * Deliberately the `export *` form with ZERO named exports (matches the
22
+ * `scripts/lib/autopilot-telemetry.mjs` precedent): a named-export re-export
23
+ * barrel is exactly the shape `check-unwired-features.mjs` S4 flags as an
24
+ * unreachable library module (condition 4 in `collectUnreachableLibraryModules`
25
+ * requires named exports before a re-export shim over live code enters that
26
+ * census) — that flag is what got this file deleted the first time. A star
27
+ * re-export names no symbol, so the shim reads as `exports: []` and stays
28
+ * invisible to that census while its target modules stay reachable through it.
13
29
  */
14
30
 
15
- export {
16
- STATE_LOCK_PATH,
17
- DEFAULT_STATE_LOCK_TIMEOUT_MS,
18
- STATE_LOCK_POLL_MS,
19
- acquireStateLock,
20
- releaseStateLock,
21
- withStateMdLock,
22
- } from './state-md-lock.mjs';
31
+ console.warn(
32
+ '[deprecated] scripts/lib/locks/index.mjs is deprecated since 5.2.0 and will be removed in 6.0.0 — ' +
33
+ "import from './state-md-lock.mjs' / './staging-fence-lock.mjs' directly, or from " +
34
+ 'scripts/lib/session-lock.mjs for the canonical surface.',
35
+ );
23
36
 
24
- export {
25
- STAGING_FENCE_LOCK_PATH,
26
- DEFAULT_STAGING_FENCE_LOCK_TIMEOUT_MS,
27
- STAGING_FENCE_LOCK_POLL_MS,
28
- acquireStagingFenceLock,
29
- releaseStagingFenceLock,
30
- withStagingFenceLock,
31
- } from './staging-fence-lock.mjs';
37
+ export * from './state-md-lock.mjs';
38
+ export * from './staging-fence-lock.mjs';
@@ -20,7 +20,7 @@
20
20
  * ## Design constraints it is written against
21
21
  *
22
22
  * - **HR-101 (a signal may only warn if it is rare).** Nothing is due ⇒ the
23
- * probe is SILENT. Six independent signals are ANDed with a cooldown, not
23
+ * probe is SILENT. Seven independent signals are ANDed with a cooldown, not
24
24
  * ORed into a permanent warning: a repo that ran `/session housekeeping`
25
25
  * within the last {@link HOUSEKEEPING_COOLDOWN_DAYS} days says nothing at
26
26
  * all, because the operator already did the thing the banner would ask for.
@@ -33,7 +33,7 @@
33
33
  * an existing module constant. Same posture as `reconcile-nudge-banner.mjs`
34
34
  * and `loop-readiness-banner.mjs`: an advisory banner needs no switch.
35
35
  *
36
- * ## The six signals
36
+ * ## The seven signals
37
37
  *
38
38
  * | id | due when | source |
39
39
  * |-------------------|-----------------------------------------------------------------------|--------|
@@ -43,6 +43,20 @@
43
43
  * | `dialectic` | `shouldDispatchAutoDialectic().trigger === true` | `auto-dialectic.mjs` |
44
44
  * | `memory-cleanup` | `shouldDispatchAutoDream().trigger === true` | `auto-dream.mjs` |
45
45
  * | `pending-sidecar` | a pending dream/dialectic proposal younger than 14 days is unapplied | `.orchestrator/*-pending*.md` |
46
+ * | `generated-rules-expiring` | a machine-generated rule is expired or expires within {@link GENERATED_RULE_EXPIRY_HORIZON_DAYS} days | `instruction-budget-guard.mjs` |
47
+ *
48
+ * ### Why the expiry alarm is HERE and not in the test suite (#1372 follow-up)
49
+ *
50
+ * The invariant "no generated rule file sits expired in `.claude/rules/`" was
51
+ * first written as a vitest case comparing `expires-at` against TODAY. That is
52
+ * a calendar time-bomb in a BLOCKING gate: with nothing committed and nothing
53
+ * broken, `npm test` — pre-push hook and CI alike — turns red on the morning
54
+ * after the earliest date and blocks every unrelated hotfix, while the repair
55
+ * (consolidate the file, move its provenance pairs, delete it) is a human
56
+ * decision no test run can take. HR-101/HR-105: a signal must fire when
57
+ * something CHANGED, at a moment the operator can act, and be repairable by the
58
+ * thing that fires it. Session start, recommending `/session housekeeping`, is
59
+ * that moment; the predicate itself is still tested, against an INJECTED clock.
46
60
  *
47
61
  * Only SIDE-EFFECT-FREE signal functions are called — never a variant that
48
62
  * advances `.orchestrator/dialectic-last-run`, because a probe that writes the
@@ -66,13 +80,32 @@ import { shouldDispatchAutoDream } from './auto-dream.mjs';
66
80
  import { resolveMemoryDir } from './memory-paths.mjs';
67
81
  import { readCanonicalSessions } from './sessions-canonical.mjs';
68
82
  import { filterRealSessions } from './session-schema.mjs';
83
+ import {
84
+ daysUntilGeneratedRuleExpiry,
85
+ listMachineGeneratedRules,
86
+ } from './instruction-budget-guard.mjs';
69
87
 
70
88
  /**
71
89
  * How many signals this probe knows about. The banner denominator is this
72
90
  * number MINUS the signals a kill-switch skipped on this host — see the
73
91
  * `skipped` array in {@link computeMaintenanceDue}'s result.
74
92
  */
75
- export const MAINTENANCE_TOTAL_SIGNALS = 6;
93
+ export const MAINTENANCE_TOTAL_SIGNALS = 7;
94
+
95
+ /**
96
+ * How far ahead the `generated-rules-expiring` signal looks.
97
+ *
98
+ * NAMED CEILING (BV-004): 7 days is one week of sessions — long enough that the
99
+ * operator meets the warning before the loader silently starts dropping the
100
+ * rule, short enough that it is not standing noise (HR-104: a signal that is
101
+ * essentially always present is no signal). On this repo's corpus at
102
+ * 2026-09-16 the earliest `expires-at` was 14 days out, so the row is silent.
103
+ *
104
+ * REVISIT TRIGGER: if the row is due on more than ~1 session start in 10, the
105
+ * horizon is measuring the reconcile engine's 30-day default TTL rather than an
106
+ * overdue consolidation — re-aim it (HR-101), never widen it.
107
+ */
108
+ export const GENERATED_RULE_EXPIRY_HORIZON_DAYS = 7;
76
109
 
77
110
  /**
78
111
  * Active-learning floor for the `evolve` signal. Deliberately the SAME number
@@ -391,6 +424,39 @@ export async function computeMaintenanceDue(opts = {}) {
391
424
  undeterminable.push('pending-sidecar');
392
425
  }
393
426
 
427
+ // --- generated-rules-expiring (S7) ---------------------------------------
428
+ // The predicate and the population both come from `instruction-budget-guard`,
429
+ // which is where the generated corpus is DEFINED (its byte ceiling judges the
430
+ // same set). A local re-implementation would be a second definition of
431
+ // "machine-generated" that agrees only until one of the two is edited.
432
+ try {
433
+ const listed = listMachineGeneratedRules({ repoRoot });
434
+ if (!listed.ok) {
435
+ // The directory is there but unreadable — not knowing is not clean.
436
+ undeterminable.push('generated-rules-expiring');
437
+ } else {
438
+ const expiring = listed.rules
439
+ .map((r) => ({ ...r, days: daysUntilGeneratedRuleExpiry({ meta: r.meta, now }) }))
440
+ .filter((r) => r.days !== null && r.days <= GENERATED_RULE_EXPIRY_HORIZON_DAYS)
441
+ .sort((a, b) => a.days - b.days);
442
+ if (expiring.length > 0) {
443
+ // HR-106: name the files and the dates the verdict was computed from —
444
+ // the operator has to open exactly those files to repair this.
445
+ // HR-106 again, one step further: name the REPAIR, not only the
446
+ // finding. The sweep (#1377) is the mechanical half — prose out, the
447
+ // provenance pair kept as `markers only` — and an operator who is told
448
+ // only which files expired has to rediscover that the command exists.
449
+ markDue(
450
+ 'generated-rules-expiring',
451
+ `${expiring.map((r) => `${r.file} ${r.expiresAt}`).join(', ')} → ` +
452
+ 'node scripts/sweep-expired-rules.mjs (dry-run first)',
453
+ );
454
+ }
455
+ }
456
+ } catch {
457
+ undeterminable.push('generated-rules-expiring');
458
+ }
459
+
394
460
  return {
395
461
  due,
396
462
  // HR-106: the denominator counts the signals this host actually EVALUATED.
@@ -68,6 +68,7 @@ import { readLock, isLockLive, LOCK_PATH } from './session-lock.mjs';
68
68
  import { checkPeerStateMd } from './state-md-peer-guard.mjs';
69
69
  import { listWorktreesChecked } from './worktree/listing.mjs';
70
70
  import { parseSessionId } from './session-id.mjs';
71
+ import { isMainModule } from './is-main-module.mjs';
71
72
 
72
73
  /** Closed enum of provenance sources. */
73
74
  const SOURCE_DISCOVERED = 'discovered'; // lock + registry unified (irreversibly merged upstream)
@@ -901,11 +902,7 @@ async function _cliMain(argv) {
901
902
  }
902
903
 
903
904
  const __filename = fileURLToPath(import.meta.url);
904
- const _isCliMain =
905
- typeof process !== 'undefined'
906
- && process.argv[1] !== null
907
- && process.argv[1] !== undefined
908
- && path.resolve(process.argv[1]) === path.resolve(__filename);
905
+ const _isCliMain =isMainModule(import.meta.url);
909
906
 
910
907
  // Called WITHOUT `await` on purpose: a top-level await would make this module
911
908
  // async for every importer, and `_cliMain` cannot reject (all paths are caught
@@ -32,6 +32,7 @@ import path from 'node:path';
32
32
  import { parseArgs } from 'node:util';
33
33
  import { getProfile, loadProfiles, validateProfile } from '../profiles/registry.mjs';
34
34
  import { validatePathInsideProject } from '../path-utils.mjs';
35
+ import { isMainModule } from '../is-main-module.mjs';
35
36
 
36
37
  // ---------------------------------------------------------------------------
37
38
  // Path resolution helper
@@ -349,7 +350,7 @@ export default async function run(opts = {}) {
349
350
  // CLI entry-point
350
351
  // ---------------------------------------------------------------------------
351
352
 
352
- if (import.meta.url === `file://${process.argv[1]}`) {
353
+ if (isMainModule(import.meta.url)) {
353
354
  run().catch((err) => {
354
355
  console.error(`runner: unhandled error — ${err.message}`);
355
356
  process.exit(2);