session-orchestrator 3.19.0 → 3.21.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 (158) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.cursor/rules/030-wave-execution.mdc +10 -8
  5. package/CHANGELOG.md +494 -0
  6. package/README.md +16 -11
  7. package/agents/analyst.md +1 -1
  8. package/agents/architect-reviewer.md +1 -1
  9. package/agents/code-implementer.md +4 -2
  10. package/agents/db-specialist.md +1 -1
  11. package/agents/dialectic-deriver.md +1 -1
  12. package/agents/docs-writer.md +1 -1
  13. package/agents/memory-proposal-collector.md +1 -1
  14. package/agents/qa-strategist.md +1 -1
  15. package/agents/security-reviewer.md +1 -1
  16. package/agents/session-reviewer.md +42 -1
  17. package/agents/skill-applied-judge.md +1 -1
  18. package/agents/test-writer.md +1 -1
  19. package/agents/ui-developer.md +1 -1
  20. package/agents/ux-evaluator.md +1 -1
  21. package/commands/release.md +60 -0
  22. package/commands/session.md +6 -2
  23. package/docs/USER-GUIDE.md +1 -1
  24. package/docs/instruction-delivery.md +350 -0
  25. package/docs/migration-v3.md +9 -6
  26. package/docs/persona-panel.md +3 -1
  27. package/docs/scope-collision-guard.md +167 -0
  28. package/docs/session-config-reference.md +1 -41
  29. package/docs/session-config-template.md +0 -23
  30. package/hooks/_lib/guard-source-loader.mjs +304 -91
  31. package/hooks/enforce-commands.mjs +216 -17
  32. package/hooks/enforce-scope.mjs +236 -12
  33. package/hooks/hooks-codex.json +1 -1
  34. package/hooks/hooks.json +11 -1
  35. package/hooks/on-session-end.mjs +52 -5
  36. package/hooks/on-session-start.mjs +7 -4
  37. package/hooks/on-stop.mjs +127 -12
  38. package/hooks/post-bash-write-verify.mjs +8 -32
  39. package/hooks/pre-bash-destructive-guard.mjs +146 -59
  40. package/hooks/pre-bash-sessions-ledger-guard.mjs +493 -66
  41. package/hooks/pre-task-scope-disjoint.mjs +1042 -0
  42. package/package.json +2 -2
  43. package/pi/prompts/release.md +12 -0
  44. package/scripts/autopilot.mjs +3 -1
  45. package/scripts/backfill-learnings-from-vault.mjs +967 -0
  46. package/scripts/emit-session.mjs +45 -40
  47. package/scripts/export-hw-learnings.mjs +61 -2
  48. package/scripts/lib/autopilot/worktree-pipeline.mjs +5 -5
  49. package/scripts/lib/backlog-scan.mjs +106 -15
  50. package/scripts/lib/build-live-signals.mjs +7 -3
  51. package/scripts/lib/ci-status-banner.mjs +207 -23
  52. package/scripts/lib/command-blocker.mjs +322 -62
  53. package/scripts/lib/git-config-drift.mjs +471 -0
  54. package/scripts/lib/hardening.mjs +9 -9
  55. package/scripts/lib/harness-audit/categories/category6.mjs +65 -12
  56. package/scripts/lib/io.mjs +193 -7
  57. package/scripts/lib/learnings/affinity.mjs +434 -0
  58. package/scripts/lib/learnings/candidates.mjs +736 -0
  59. package/scripts/lib/learnings/expiry-sweep.mjs +408 -53
  60. package/scripts/lib/learnings/judgment.mjs +782 -0
  61. package/scripts/lib/learnings/kebab.mjs +128 -0
  62. package/scripts/lib/learnings/select.mjs +704 -0
  63. package/scripts/lib/memory-cleanup-stamp.mjs +132 -8
  64. package/scripts/lib/mirror-issues-banner.mjs +266 -0
  65. package/scripts/lib/named-vault-resolver.mjs +105 -16
  66. package/scripts/lib/peer-cards/schema.mjs +6 -2
  67. package/scripts/lib/reconcile/emitter.mjs +107 -22
  68. package/scripts/lib/reconcile/engine.mjs +9 -15
  69. package/scripts/lib/reconcile/renderer.mjs +141 -25
  70. package/scripts/lib/reconcile/sanitize.mjs +518 -0
  71. package/scripts/lib/reconcile/writer.mjs +134 -1
  72. package/scripts/lib/redact-spans.mjs +89 -0
  73. package/scripts/lib/scope-baseline.mjs +77 -17
  74. package/scripts/lib/scope-gate.mjs +852 -72
  75. package/scripts/lib/secret-masker.mjs +262 -0
  76. package/scripts/lib/session-close-backfill.mjs +2 -2
  77. package/scripts/lib/session-lock.mjs +34 -10
  78. package/scripts/lib/session-record-repair.mjs +551 -0
  79. package/scripts/lib/session-registry.mjs +9 -1
  80. package/scripts/lib/session-schema/serializer.mjs +54 -0
  81. package/scripts/lib/session-schema.mjs +1 -0
  82. package/scripts/lib/session-token-rollup.mjs +68 -6
  83. package/scripts/lib/soul-resolve.mjs +12 -0
  84. package/scripts/lib/state-md/mission-status.mjs +21 -12
  85. package/scripts/lib/tmux-layout/telemetry.mjs +43 -10
  86. package/scripts/lib/tmux-layout/vcs-detector.mjs +108 -4
  87. package/scripts/lib/validate/check-agents.mjs +77 -5
  88. package/scripts/lib/validate/check-banner-parity.mjs +376 -0
  89. package/scripts/lib/validate/check-commands.mjs +2 -20
  90. package/scripts/lib/validate/check-doc-cli-commands.mjs +514 -0
  91. package/scripts/lib/validate/check-guard-requires-parity.mjs +1148 -0
  92. package/scripts/lib/validate/check-hooks-symmetry.mjs +18 -0
  93. package/scripts/lib/validate/check-learning-provenance.mjs +511 -0
  94. package/scripts/lib/validate/check-owner-leakage.mjs +188 -20
  95. package/scripts/lib/validate/check-rules.mjs +31 -5
  96. package/scripts/lib/validate/check-skills.mjs +191 -0
  97. package/scripts/lib/validate/check-test-git-config-target.mjs +665 -0
  98. package/scripts/lib/validate/check-unicode-safety.mjs +22 -2
  99. package/scripts/lib/validate/check-untracked-test-deps.mjs +925 -0
  100. package/scripts/lib/validate/check-unwired-features.mjs +757 -0
  101. package/scripts/lib/validate/check-vcs-repo-flag.mjs +965 -0
  102. package/scripts/lib/validate/frontmatter-block.mjs +61 -0
  103. package/scripts/lib/validate/tier-inference.mjs +46 -8
  104. package/scripts/lib/vault-mirror/namespace.mjs +146 -1
  105. package/scripts/lib/vault-mirror/process.mjs +264 -31
  106. package/scripts/lib/vault-mirror/render-sessions.mjs +115 -4
  107. package/scripts/lib/vault-status/board-writer.mjs +300 -56
  108. package/scripts/lib/vault-status/narrative-mirror.mjs +119 -5
  109. package/scripts/lib/vcs-repo-spec.mjs +500 -19
  110. package/scripts/print-applicable-rules.mjs +170 -7
  111. package/scripts/print-learnings-index.mjs +501 -0
  112. package/scripts/release.mjs +616 -61
  113. package/scripts/repair-invalid-sessions.mjs +209 -0
  114. package/scripts/site-numbers.mjs +1049 -0
  115. package/scripts/sweep-expired-learnings.mjs +192 -32
  116. package/scripts/validate-plugin.mjs +82 -0
  117. package/scripts/validate-wave-scope.mjs +281 -12
  118. package/scripts/vault-mirror.mjs +26 -1
  119. package/skills/_shared/monitor-patterns.md +24 -4
  120. package/skills/_shared/state-ownership.md +17 -0
  121. package/skills/brainstorm/soul.md +47 -1
  122. package/skills/claude-md-drift-check/SKILL.md +9 -1
  123. package/skills/debug/SKILL.md +4 -1
  124. package/skills/discovery/issue-templates.md +4 -4
  125. package/skills/discovery/probes-code.md +2 -2
  126. package/skills/discovery/probes-feature.md +6 -6
  127. package/skills/discovery/probes-infra.md +2 -2
  128. package/skills/discovery/probes-session.md +5 -5
  129. package/skills/dispatcher/SKILL.md +10 -1
  130. package/skills/evolve/SKILL.md +116 -18
  131. package/skills/frontmatter-guard/SKILL.md +9 -1
  132. package/skills/gitlab-ops/SKILL.md +54 -39
  133. package/skills/gitlab-portfolio/SKILL.md +10 -1
  134. package/skills/grill/soul.md +44 -1
  135. package/skills/memory-cleanup/SKILL.md +18 -5
  136. package/skills/npm-publish/SKILL.md +22 -50
  137. package/skills/persona-panel/SKILL.md +3 -1
  138. package/skills/plan/mode-new.md +23 -5
  139. package/skills/plan/soul.md +46 -3
  140. package/skills/repo-audit/SKILL.md +10 -1
  141. package/skills/session-end/SKILL.md +45 -26
  142. package/skills/session-end/metrics-collection.md +1 -1
  143. package/skills/session-end/phase-3-6-tail.md +30 -1
  144. package/skills/session-end/plan-verification.md +1 -5
  145. package/skills/session-end/session-metrics-write.md +6 -10
  146. package/skills/session-plan/SKILL.md +2 -2
  147. package/skills/session-plan/wave-template.md +1 -1
  148. package/skills/session-start/SKILL.md +15 -1
  149. package/skills/session-start/soul.md +41 -1
  150. package/skills/spinout/SKILL.md +5 -1
  151. package/skills/sunset-review/SKILL.md +11 -1
  152. package/skills/tmux-layout/SKILL.md +7 -2
  153. package/skills/vault-mirror/SKILL.md +10 -1
  154. package/skills/vault-sync/SKILL.md +10 -1
  155. package/skills/vault-sync/validator.mjs +55 -6
  156. package/skills/wave-executor/SKILL.md +1 -5
  157. package/skills/wave-executor/wave-loop.md +77 -82
  158. package/scripts/lib/mission-status-schema.mjs +0 -114
@@ -0,0 +1,128 @@
1
+ /**
2
+ * learnings/kebab.mjs — the slug primitive behind every `learning_key`, and
3
+ * {@link learningKeyOf}, the whole-key derivation built on it.
4
+ *
5
+ * `learning_key` is not a stored field. It is DERIVED as
6
+ * `` `${type}/${kebab(title || subject)}` `` and is the logical identity the
7
+ * whole dedupe/idempotency layer keys on (`reconcile/idempotency.mjs` calls it
8
+ * "THE logical dedupe key"). That makes this a contract, not a formatting
9
+ * helper: two callers that derive differently do not produce two ugly slugs,
10
+ * they FORK the key space — the same learning renders under two identities,
11
+ * dedupe stops firing, and both halves look correct in isolation.
12
+ *
13
+ * Before this module existed there were four copies of `kebab` plus one inline
14
+ * expression, none exported, none shared (two of the four landed on the same
15
+ * day, from two different authors, each of whom flagged the duplication in
16
+ * their own report). They agreed on every reachable input — verified, not
17
+ * assumed — so consolidating here changed no existing key. See the byte-identity
18
+ * proof pinned in `tests/scripts/lib/learnings/kebab.test.mjs`.
19
+ *
20
+ * Consolidating the primitive left the SECOND half of the problem open, and it
21
+ * is the half that bites: what each call site FED the primitive. Four sites
22
+ * derived `${type}/…` verbatim while the writer (`reconcile/emitter.mjs`) alone
23
+ * derived `${kebab(type)}/…` — a divergence invisible while every live `type`
24
+ * is kebab-identical, and silent in BOTH directions the moment one is not.
25
+ * {@link learningKeyOf} exists so there is one derivation to agree with rather
26
+ * than five to keep in sync.
27
+ *
28
+ * ## Why this file lives under `learnings/` and not under `reconcile/`
29
+ *
30
+ * Dependency direction, measured rather than presumed (2026-08-13, HEAD
31
+ * 5d59e62): `grep -rn "from '../learnings/" scripts/lib/reconcile/` reports 6
32
+ * import edges across 4 files (`eligibility.mjs`, `engine.mjs` ×2,
33
+ * `emitter.mjs` ×2, `renderer.mjs` — three of them pulling THIS module, three
34
+ * pulling `learnings/schema.mjs`), and the reverse grep
35
+ * `from '../reconcile/'` over `scripts/lib/learnings/` reports 0. A primitive
36
+ * shared by both packages therefore belongs on the `learnings/` side; placing
37
+ * it under `reconcile/` would invert an edge and introduce a cycle.
38
+ *
39
+ * Deliberately NOT re-exported from the `scripts/lib/learnings.mjs` barrel —
40
+ * `surface.mjs` and `affinity.mjs` set that precedent: consumers import the
41
+ * leaf directly, so the barrel stays the historical schema/io/filters surface.
42
+ *
43
+ * ## What this module is NOT
44
+ *
45
+ * Not a general-purpose slugifier. Vault note ids, tag segments, and rule
46
+ * filenames have their own slug rules with their own length caps and charset
47
+ * contracts (`vault-mirror/utils.mjs`, `vault-archive.mjs`). Do not route those
48
+ * through here — a shared slugifier across unrelated identity spaces is how a
49
+ * cap added for one consumer silently re-keys another.
50
+ *
51
+ * Pure, stdlib-only, no imports, no clock, no fs.
52
+ */
53
+
54
+ /**
55
+ * Slugify a string into the stable kebab-case token used for learning keys.
56
+ *
57
+ * Lowercases, collapses every run of non-`[a-z0-9]` characters into a single
58
+ * `-`, and trims leading/trailing `-`.
59
+ *
60
+ * Three properties callers depend on:
61
+ *
62
+ * 1. **Total** — never throws. Non-string input is coerced via `String()`,
63
+ * so `null`/`undefined`/numbers yield `"null"`/`"undefined"`/`"12345"`
64
+ * rather than a `TypeError`. Callers pass values typed `unknown` at
65
+ * their trust boundary; a throw there would abort a reconcile run.
66
+ * 2. **Lossy on non-ASCII** — German umlauts and em-dashes in the corpus are
67
+ * collapsed to `-` (`"Größe"` → `"gr-e"`), NOT transliterated. Ugly, and
68
+ * deliberately frozen: every stamped key in `.claude/rules/*.md` and in
69
+ * `.orchestrator/runtime/reconcile-candidates.jsonl` was minted this way.
70
+ * Adding transliteration would re-key the entire corpus.
71
+ * 3. **May return the empty string** — an all-symbol input (`"!!!"`) yields
72
+ * `""`. `reconcile/renderer.mjs::deriveSlug` branches on exactly that to
73
+ * fall back to its hash suffix, so an "always return something non-empty"
74
+ * change here would silently disable that branch.
75
+ *
76
+ * @param {unknown} s Value to slugify; coerced with `String()`.
77
+ * @returns {string} Kebab token; `''` when the input holds no `[a-z0-9]`.
78
+ */
79
+ export function kebab(s) {
80
+ return String(s)
81
+ .toLowerCase()
82
+ .replace(/[^a-z0-9]+/g, '-')
83
+ .replace(/^-+|-+$/g, '');
84
+ }
85
+
86
+ /**
87
+ * THE derivation of a learning's logical key: `` `${type}/${kebab(title || subject)}` ``.
88
+ *
89
+ * One rule, four decisions, each of which was a divergence between call sites
90
+ * before this function existed:
91
+ *
92
+ * 1. **The TYPE half is verbatim (trimmed), never kebab'd.** The subject half
93
+ * is prose and must be slugged; the type half is an enum token a reader
94
+ * parses BACK OUT of the key — `backfill-learnings-from-vault.mjs` uses
95
+ * `learning_key.split('/')[0]` as the reconstructed `type` and
96
+ * cross-checks it against the vault note's type. Kebabbing it would make
97
+ * that half lossy, which is precisely the fidelity downgrade the backfill
98
+ * labels `derived:learning-key-slug (original prose not recoverable)` for
99
+ * the subject half. Frontmatter safety does not need it either: the key
100
+ * becomes an unquoted `learning-key:` scalar, and `reconcile/renderer.mjs`
101
+ * already asserts `LEARNING_KEY_RE` (`/^[a-z0-9/-]+$/`) on the whole value
102
+ * before rendering — an unsafe type is REJECTED loudly there rather than
103
+ * silently re-keyed here.
104
+ * 2. **`title` wins over `subject`**, and a whitespace-only `title` falls
105
+ * through to `subject` rather than yielding an empty slug.
106
+ * 3. **`null`, not a throw, for an unkeyable record.** Readers scan corpora
107
+ * that contain shape-foreign lines; an unkeyable record simply does not
108
+ * participate in key resolution. Writers that need a string check for
109
+ * `null` and reject the record with their own auditable reason.
110
+ * 4. **An empty slug is unkeyable, not a key.** `kebab('!!!')` is `''`, and
111
+ * `` `anti-pattern/` `` is not an identity — it is a bucket every
112
+ * all-symbol-subject record of that type would collide in.
113
+ *
114
+ * @param {unknown} record A learning record (or anything; non-records yield `null`).
115
+ * @returns {string|null} `` `${type}/${slug}` ``, or `null` when unkeyable.
116
+ */
117
+ export function learningKeyOf(record) {
118
+ if (record === null || typeof record !== 'object' || Array.isArray(record)) return null;
119
+ const rec = /** @type {Record<string, unknown>} */ (record);
120
+ const type = typeof rec.type === 'string' ? rec.type.trim() : '';
121
+ const titleOrSubject =
122
+ (typeof rec.title === 'string' && rec.title.trim() !== '' ? rec.title : '') ||
123
+ (typeof rec.subject === 'string' && rec.subject.trim() !== '' ? rec.subject : '');
124
+ if (type === '' || titleOrSubject === '') return null;
125
+ const slug = kebab(titleOrSubject);
126
+ if (slug === '') return null;
127
+ return `${type}/${slug}`;
128
+ }