heyspex 0.1.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 (104) hide show
  1. package/README.md +157 -0
  2. package/bin/hs.mjs +1028 -0
  3. package/bin/postinstall.mjs +88 -0
  4. package/dev-factory/lib/fleet-readiness.mjs +274 -0
  5. package/dev-factory/lib/fleet-state.mjs +250 -0
  6. package/dev-factory/lib/sufficiency-score.mjs +441 -0
  7. package/dist/cli/hs-check.mjs +747 -0
  8. package/dist/cli/hs-claim.mjs +541 -0
  9. package/dist/cli/hs-connect.mjs +3436 -0
  10. package/dist/cli/hs-defer.mjs +8455 -0
  11. package/dist/cli/hs-env.mjs +36845 -0
  12. package/dist/cli/hs-init.mjs +1145 -0
  13. package/dist/cli/hs-install.mjs +1390 -0
  14. package/dist/cli/hs-join.mjs +38553 -0
  15. package/dist/cli/hs-vault-pull.mjs +7782 -0
  16. package/dist/cli/hs-vault.mjs +4166 -0
  17. package/dist/cli/hs-workspace.mjs +2898 -0
  18. package/dist/cli-templates/customer-vault/specs/entity-model.md +1735 -0
  19. package/dist/cli-templates/customer-vault/specs/protocols/canonical-frontmatter-templates.md +531 -0
  20. package/dist/cli-templates/customer-vault/specs/protocols/memory-protocol.md +48 -0
  21. package/dist/cli-templates/customer-vault/specs/protocols/spec-hierarchy.md +548 -0
  22. package/docs/mcp-client-config.md +200 -0
  23. package/package.json +124 -0
  24. package/scripts/check-mcp-freshness.mjs +379 -0
  25. package/scripts/dev-server-status.mjs +722 -0
  26. package/scripts/gateway-skills-lib.mjs +421 -0
  27. package/scripts/lib/console-url-resolver.mjs +152 -0
  28. package/scripts/lib/dev-mode.mjs +369 -0
  29. package/scripts/lib/hs-link.mjs +154 -0
  30. package/scripts/lib/hs-source-commit.mjs +207 -0
  31. package/scripts/lib/hs-source-log.mjs +366 -0
  32. package/scripts/lib/hs-source-preflight.mjs +402 -0
  33. package/scripts/lib/hs-source-push.mjs +307 -0
  34. package/scripts/lib/hs-source-secret-scan.mjs +263 -0
  35. package/scripts/lib/standalone-doctor.mjs +89 -0
  36. package/scripts/vault-id-lib.mjs +173 -0
  37. package/vendor/heyspex-mcp/alignment-gate.mjs +1347 -0
  38. package/vendor/heyspex-mcp/blocker-resolver.mjs +891 -0
  39. package/vendor/heyspex-mcp/breakdown-ladder.mjs +309 -0
  40. package/vendor/heyspex-mcp/breakdown-source.mjs +236 -0
  41. package/vendor/heyspex-mcp/breakdown-writer.mjs +524 -0
  42. package/vendor/heyspex-mcp/brief-observability.mjs +67 -0
  43. package/vendor/heyspex-mcp/canvas-inbox.mjs +130 -0
  44. package/vendor/heyspex-mcp/capture-active-rehydrate.mjs +76 -0
  45. package/vendor/heyspex-mcp/capture-buffer-patches.mjs +147 -0
  46. package/vendor/heyspex-mcp/capture-channel.mjs +577 -0
  47. package/vendor/heyspex-mcp/capture-console-client.mjs +290 -0
  48. package/vendor/heyspex-mcp/capture-focus.mjs +1366 -0
  49. package/vendor/heyspex-mcp/capture-kind-suggest.mjs +121 -0
  50. package/vendor/heyspex-mcp/capture-outbox.mjs +239 -0
  51. package/vendor/heyspex-mcp/capture-stage-gate.mjs +160 -0
  52. package/vendor/heyspex-mcp/cli.mjs +15754 -0
  53. package/vendor/heyspex-mcp/config-settings.mjs +419 -0
  54. package/vendor/heyspex-mcp/console-fetch.mjs +342 -0
  55. package/vendor/heyspex-mcp/defer-spec.mjs +527 -0
  56. package/vendor/heyspex-mcp/deferred-reclaim.mjs +284 -0
  57. package/vendor/heyspex-mcp/design-tools.mjs +449 -0
  58. package/vendor/heyspex-mcp/dev-factory-bridge.mjs +66 -0
  59. package/vendor/heyspex-mcp/diagnose-skeleton.mjs +114 -0
  60. package/vendor/heyspex-mcp/fleet-queue-tools.mjs +241 -0
  61. package/vendor/heyspex-mcp/hooks-engine.mjs +399 -0
  62. package/vendor/heyspex-mcp/login-handoff.mjs +438 -0
  63. package/vendor/heyspex-mcp/mcp-subprocess.mjs +136 -0
  64. package/vendor/heyspex-mcp/mvp-mode.mjs +101 -0
  65. package/vendor/heyspex-mcp/next-resolution.mjs +240 -0
  66. package/vendor/heyspex-mcp/next-review.mjs +548 -0
  67. package/vendor/heyspex-mcp/peer-presence.mjs +430 -0
  68. package/vendor/heyspex-mcp/plan-ground-conflicts.mjs +321 -0
  69. package/vendor/heyspex-mcp/plan-ground.mjs +2001 -0
  70. package/vendor/heyspex-mcp/plan-ingest.mjs +476 -0
  71. package/vendor/heyspex-mcp/plan-push.mjs +1826 -0
  72. package/vendor/heyspex-mcp/plan-review.mjs +1419 -0
  73. package/vendor/heyspex-mcp/preflight-gate.mjs +0 -0
  74. package/vendor/heyspex-mcp/procedure-tools.mjs +970 -0
  75. package/vendor/heyspex-mcp/promote-capture.mjs +1280 -0
  76. package/vendor/heyspex-mcp/promote-diagnose.mjs +187 -0
  77. package/vendor/heyspex-mcp/promote-research-to-diagnose.mjs +338 -0
  78. package/vendor/heyspex-mcp/promote-research.mjs +1553 -0
  79. package/vendor/heyspex-mcp/promotion-helpers.mjs +280 -0
  80. package/vendor/heyspex-mcp/read-path.mjs +138 -0
  81. package/vendor/heyspex-mcp/recipe-tools.mjs +258 -0
  82. package/vendor/heyspex-mcp/regen-tasks.mjs +326 -0
  83. package/vendor/heyspex-mcp/register-spec.mjs +417 -0
  84. package/vendor/heyspex-mcp/research-focus.mjs +476 -0
  85. package/vendor/heyspex-mcp/research-tools.mjs +109 -0
  86. package/vendor/heyspex-mcp/research-type-suggest.mjs +112 -0
  87. package/vendor/heyspex-mcp/resolution-focus.mjs +45 -0
  88. package/vendor/heyspex-mcp/review-focus.mjs +55 -0
  89. package/vendor/heyspex-mcp/review-rollup.mjs +47 -0
  90. package/vendor/heyspex-mcp/run-front.mjs +60 -0
  91. package/vendor/heyspex-mcp/scheduler.mjs +813 -0
  92. package/vendor/heyspex-mcp/seat-identity.mjs +281 -0
  93. package/vendor/heyspex-mcp/settings-tools.mjs +119 -0
  94. package/vendor/heyspex-mcp/spec-id-lib.mjs +790 -0
  95. package/vendor/heyspex-mcp/split-research.mjs +832 -0
  96. package/vendor/heyspex-mcp/submit-for-review.mjs +190 -0
  97. package/vendor/heyspex-mcp/summary-contract.mjs +162 -0
  98. package/vendor/heyspex-mcp/test-helpers.mjs +43 -0
  99. package/vendor/heyspex-mcp/validate-linkage.mjs +574 -0
  100. package/vendor/heyspex-mcp/vault-resolve.mjs +297 -0
  101. package/vendor/heyspex-mcp/vault-settings.mjs +87 -0
  102. package/vendor/heyspex-mcp/verify-reproduction.mjs +314 -0
  103. package/vendor/heyspex-mcp/why-now.mjs +64 -0
  104. package/vendor/heyspex-mcp/yaml-scalar.mjs +34 -0
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Shared vault ID allocation (ESM) — mirrors spex-console/src/lib/vault-id.ts.
3
+ * Used by validate-vault-ids.mjs and vendor/heyspex-mcp.
4
+ *
5
+ * Family-first ([[HS-EPIC-DLE3]] / [[HS-MIL-KY1F]]): minted ids are
6
+ * `HS-<familyKey>-<TYPE>`. Occupancy detection is dual-read (it normalizes ids of
7
+ * EITHER ordering to the canonical family-first form via `parseSpecId`), so
8
+ * suffix-collision detection keeps working while the vault is mid-migration.
9
+ */
10
+
11
+ import { parseSpecId, FILE_KEY_RE, fileKeyFromBasename, KNOWN_TYPE_LABELS } from '../vendor/heyspex-mcp/spec-id-lib.mjs';
12
+
13
+ export const VAULT_ID_CHARSET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
14
+ export const VAULT_ID_MIN_SUFFIX_LENGTH = 4;
15
+
16
+ /** Per-file FILE KEY length (owner ruling 2026-07-10) — see spec-id-lib.mjs FILE_KEY_RE. */
17
+ export const FILE_KEY_LENGTH = 4;
18
+ export { FILE_KEY_RE, fileKeyFromBasename };
19
+
20
+ // Legacy type-first id matchers. Retained for backward compatibility; new code
21
+ // should parse ids via `parseSpecId` (dual-read) rather than these.
22
+ export const TASK_ID_RE = /^HS-TASK-([A-Z0-9]{4,})$/;
23
+ export const EPIC_ID_RE = /^HS-EPIC-(\d{4}|[A-Z0-9]{4,})$/;
24
+ export const RESEARCH_ID_RE = /^HS-RES-(\d{3}|[A-Z0-9]{4,})$/;
25
+ export const CAPTURE_ID_RE = /^HS-CAP-([A-Z0-9]{4,})$/;
26
+ export const DIAGNOSE_ID_RE = /^HS-DIAG-([A-Z0-9]{4,})$/;
27
+
28
+ // The type label each random-keyed kind mints. (Slug-only kinds — memory,
29
+ // protocol, pillar, ADR — have no family key and are out of scope for the flip.)
30
+ const KIND_TYPE_LABEL = {
31
+ task: 'TASK',
32
+ epic: 'EPIC',
33
+ research: 'RES',
34
+ capture: 'CAP',
35
+ diagnose: 'DIAG',
36
+ };
37
+ const TYPE_LABEL_KIND = {
38
+ TASK: 'task',
39
+ EPIC: 'epic',
40
+ RES: 'research',
41
+ CAP: 'capture',
42
+ DIAG: 'diagnose',
43
+ };
44
+
45
+ const BUCKETS = {
46
+ task: 'tasks',
47
+ epic: 'epics',
48
+ research: 'research',
49
+ capture: 'captures',
50
+ diagnose: 'diagnoses',
51
+ };
52
+
53
+ function randomSuffix(length, charset, randomUnit) {
54
+ let out = '';
55
+ for (let i = 0; i < length; i++) {
56
+ const idx = Math.floor(randomUnit() * charset.length);
57
+ out += charset[Math.min(idx, charset.length - 1)];
58
+ }
59
+ return out;
60
+ }
61
+
62
+ function capacity(charset, length) {
63
+ return charset.length ** length;
64
+ }
65
+
66
+ function suffixLengthForId(kind, id) {
67
+ const p = parseSpecId(id);
68
+ return p && p.typeLabel === KIND_TYPE_LABEL[kind] ? p.familyKey.length : null;
69
+ }
70
+
71
+ function countIdsAtSuffixLength(kind, occupied, length) {
72
+ let n = 0;
73
+ for (const id of occupied) {
74
+ if (suffixLengthForId(kind, id) === length) n++;
75
+ }
76
+ return n;
77
+ }
78
+
79
+ export function allocateRandomVaultId(kind, occupied, options = {}) {
80
+ const charset = options.charset ?? VAULT_ID_CHARSET;
81
+ const randomUnit = options.randomUnit ?? (() => Math.random());
82
+ let length = options.minLength ?? VAULT_ID_MIN_SUFFIX_LENGTH;
83
+ const typeLabel = KIND_TYPE_LABEL[kind];
84
+
85
+ while (true) {
86
+ const usedAtLength = countIdsAtSuffixLength(kind, occupied, length);
87
+ if (usedAtLength >= capacity(charset, length)) {
88
+ length++;
89
+ continue;
90
+ }
91
+ const remaining = capacity(charset, length) - usedAtLength;
92
+ const maxAttempts = Math.min(remaining, 10_000);
93
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
94
+ const suffix = randomSuffix(length, charset, randomUnit);
95
+ // A suffix equal to a type label would corrupt era detection (closed-set
96
+ // type-label position is the era discriminator) — never mint one.
97
+ if (KNOWN_TYPE_LABELS.has(suffix)) continue;
98
+ const id = `HS-${suffix}-${typeLabel}`; // family-first
99
+ // Compare against the canonical form so a suffix already taken in EITHER
100
+ // ordering still counts as occupied during the migration grace window.
101
+ if (!occupied.has(id)) return id;
102
+ }
103
+ length++;
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Allocate a per-file FILE KEY unique against `occupied` (vault-wide): 4 chars,
109
+ * at least one letter (all-digit rejected). Auto-extends on exhaustion.
110
+ * Mirror: spex-console/src/lib/vault-id.ts `allocateFileKey`.
111
+ */
112
+ export function allocateFileKey(occupied, options = {}) {
113
+ const charset = options.charset ?? VAULT_ID_CHARSET;
114
+ const randomUnit = options.randomUnit ?? (() => Math.random());
115
+ let length = options.minLength ?? FILE_KEY_LENGTH;
116
+
117
+ while (true) {
118
+ const maxAttempts = Math.min(capacity(charset, length), 10_000);
119
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
120
+ const key = randomSuffix(length, charset, randomUnit);
121
+ if (!FILE_KEY_RE.test(key)) continue; // all-digit — never minted
122
+ // Never mint a key equal to a type label — era detection keys on
123
+ // closed-set type-label position ([[HS-SJOT-AEP1-DIAG]]).
124
+ if (KNOWN_TYPE_LABELS.has(key)) continue;
125
+ if (!occupied.has(key)) return key;
126
+ }
127
+ length++;
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Every occupied file key across loaded specs (frontmatter `file_id:` SSOT +
133
+ * basename token), for `allocateFileKey`'s vault-wide uniqueness check.
134
+ * PRECISE (file keys only) — cross-namespace mint safety ([[HS-SJOT-AEP1-DIAG]])
135
+ * is a call-site concern: union this with the occupied FAMILY keys before
136
+ * allocating, as vault.ts and spec-id-lib.mjs's mint helpers do.
137
+ */
138
+ export function collectOccupiedFileKeysFromSpecs(specs) {
139
+ const occupied = new Set();
140
+ for (const s of specs) {
141
+ if (s.file_id && FILE_KEY_RE.test(String(s.file_id))) occupied.add(String(s.file_id));
142
+ if (s.fileId && FILE_KEY_RE.test(String(s.fileId))) occupied.add(String(s.fileId));
143
+ const fromBasename = s.basename ? fileKeyFromBasename(s.basename) : null;
144
+ if (fromBasename) occupied.add(fromBasename);
145
+ }
146
+ return occupied;
147
+ }
148
+
149
+ export function collectOccupiedIdsFromSpecs(specs) {
150
+ const tasks = new Set();
151
+ const epics = new Set();
152
+ const research = new Set();
153
+ const captures = new Set();
154
+ const diagnoses = new Set();
155
+ const sets = { tasks, epics, research, captures, diagnoses };
156
+
157
+ // Normalize an id or basename of EITHER ordering to its canonical family-first
158
+ // id and bucket it by type. Non-managed kinds (memory/protocol/…) parse to a
159
+ // type label not in TYPE_LABEL_KIND and are skipped.
160
+ const add = (value) => {
161
+ const p = parseSpecId(value);
162
+ if (!p) return;
163
+ const kind = TYPE_LABEL_KIND[p.typeLabel];
164
+ if (!kind) return;
165
+ sets[BUCKETS[kind]].add(`HS-${p.familyKey}-${p.typeLabel}`);
166
+ };
167
+
168
+ for (const s of specs) {
169
+ add(s.id);
170
+ add(s.basename);
171
+ }
172
+ return { tasks, epics, research, captures, diagnoses };
173
+ }