heyspex 0.2.6 → 0.2.7

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 (85) hide show
  1. package/bin/hs.mjs +85 -25
  2. package/bin/spexcode.mjs +31 -0
  3. package/dev-factory/lib/local-firecrawl.mjs +294 -0
  4. package/dev-factory/lib/seat-context.mjs +20 -4
  5. package/dev-factory/model-catalog.json +222 -222
  6. package/dev-factory/spexcrawl/firecrawl-cli.mjs +755 -0
  7. package/dist/cli/hs-connect.mjs +20 -2
  8. package/dist/cli/hs-defer.mjs +19 -1
  9. package/dist/cli/hs-index-rebuild.mjs +19 -1
  10. package/dist/cli/hs-index-reconcile.mjs +19 -1
  11. package/dist/cli/hs-init.mjs +2 -2
  12. package/dist/cli/hs-install.mjs +2 -2
  13. package/dist/cli/hs-join.mjs +20 -2
  14. package/dist/cli/hs-next-launch.mjs +89 -10
  15. package/dist/cli/hs-spawn.mjs +27 -1
  16. package/dist/cli/hs-vault-pull.mjs +19 -1
  17. package/dist/cli/hs-vault-push.mjs +19 -1
  18. package/dist/cli/hs-vault.mjs +21 -7
  19. package/dist/cli/hs-workspace.mjs +19 -1
  20. package/dist/cli-templates/customer-vault/specs/entity-model.md +1728 -1728
  21. package/dist/cli-templates/customer-vault/specs/protocols/canonical-frontmatter-templates.md +464 -464
  22. package/dist/cli-templates/customer-vault/specs/protocols/destructive-action-checklist.md +122 -122
  23. package/dist/cli-templates/customer-vault/specs/protocols/memory-protocol.md +46 -46
  24. package/dist/cli-templates/customer-vault/specs/protocols/spec-hierarchy.md +530 -530
  25. package/dist/cli-templates/customer-vault/specs/protocols/spec-summary-authoring.md +83 -83
  26. package/dist/cli-templates/harness-commands/claude/hs-backfill.md +28 -28
  27. package/dist/cli-templates/harness-commands/claude/hs-capture.md +62 -62
  28. package/dist/cli-templates/harness-commands/claude/hs-defer.md +29 -29
  29. package/dist/cli-templates/harness-commands/claude/hs-ground.md +30 -30
  30. package/dist/cli-templates/harness-commands/claude/hs-next.md +29 -29
  31. package/dist/cli-templates/harness-commands/claude/hs-promote.md +70 -70
  32. package/dist/cli-templates/harness-commands/claude/hs-push.md +35 -35
  33. package/dist/cli-templates/harness-commands/claude/hs-qc.md +27 -27
  34. package/dist/cli-templates/harness-commands/claude/hs-res.md +20 -8
  35. package/dist/cli-templates/harness-commands/claude/hs-resolve.md +23 -23
  36. package/dist/cli-templates/harness-commands/claude/hs-view.md +28 -28
  37. package/dist/cli-templates/harness-commands/claude/kill-ports.md +32 -32
  38. package/dist/cli-templates/harness-commands/claude/prototype.md +91 -91
  39. package/dist/cli-templates/harness-commands/cursor/hs-backfill.md +22 -22
  40. package/dist/cli-templates/harness-commands/cursor/hs-capture.md +56 -56
  41. package/dist/cli-templates/harness-commands/cursor/hs-defer.md +23 -23
  42. package/dist/cli-templates/harness-commands/cursor/hs-ground.md +24 -24
  43. package/dist/cli-templates/harness-commands/cursor/hs-next.md +23 -23
  44. package/dist/cli-templates/harness-commands/cursor/hs-promote.md +64 -64
  45. package/dist/cli-templates/harness-commands/cursor/hs-push.md +29 -29
  46. package/dist/cli-templates/harness-commands/cursor/hs-qc.md +21 -21
  47. package/dist/cli-templates/harness-commands/cursor/hs-res.md +20 -8
  48. package/dist/cli-templates/harness-commands/cursor/hs-resolve.md +17 -17
  49. package/dist/cli-templates/harness-commands/cursor/hs-view.md +23 -23
  50. package/dist/cli-templates/harness-commands/cursor/kill-ports.md +26 -26
  51. package/dist/cli-templates/harness-commands/cursor/prototype.md +86 -86
  52. package/docs/copilot-plugin-install.md +7 -0
  53. package/docs/mcp-client-config.md +6 -0
  54. package/package.json +7 -2
  55. package/plugins/heyspex/README.md +6 -0
  56. package/plugins/heyspex/bin/launch-mcp.mjs +17 -0
  57. package/plugins/heyspex/hooks/hooks.json +418 -418
  58. package/scripts/claude-hooks/_intent-classifier-semantic.mjs +2 -2
  59. package/scripts/hs-companion.mjs +38 -8
  60. package/scripts/lib/companion-install.mjs +768 -0
  61. package/scripts/lib/customer-kit.mjs +5 -3
  62. package/scripts/lib/hs-companion-settings.mjs +1 -0
  63. package/scripts/lib/hs-source-push.mjs +386 -386
  64. package/spexharness/doctrine/baseline/SPEXCODE-DOCTRINE.baseline.json +29 -29
  65. package/spexharness/src/adapters/copilot-models.mjs +179 -0
  66. package/spexharness/src/adapters/harness-detect.mjs +148 -0
  67. package/spexharness/src/gates/directive-obligation-gate.decide.mjs +132 -132
  68. package/spexharness/src/gates/vault-write-tier-guard.decide.mjs +153 -125
  69. package/spexharness/src/seat-context.mjs +10 -5
  70. package/spexharness/src/session-bootstrap.mjs +6 -3
  71. package/vendor/heyspex-mcp/cli.mjs +6 -1
  72. package/vendor/heyspex-mcp/config-seed.yaml +15 -15
  73. package/vendor/heyspex-mcp/dev-factory-overlay.mjs +142 -0
  74. package/vendor/heyspex-mcp/memory-tools.mjs +523 -523
  75. package/vendor/heyspex-mcp/on-deck-scheduler.mjs +1708 -1708
  76. package/vendor/heyspex-mcp/procedure-handlers.mjs +327 -327
  77. package/vendor/heyspex-mcp/procedure-tools.mjs +1209 -1181
  78. package/vendor/heyspex-mcp/research-tools.mjs +22 -2
  79. package/vendor/heyspex-mcp/seat-assign-cli.mjs +242 -0
  80. package/vendor/heyspex-mcp/seat-assignment-rules.mjs +96 -0
  81. package/vendor/heyspex-mcp/seat-assignments-client.mjs +265 -0
  82. package/vendor/heyspex-mcp/seat-defaults-cli.mjs +45 -0
  83. package/vendor/heyspex-mcp/seat-defaults.mjs +232 -0
  84. package/vendor/heyspex-mcp/seat-identity.mjs +171 -0
  85. package/vendor/heyspex-mcp/vault-io.mjs +720 -720
@@ -1,15 +1,15 @@
1
- # .heyspex/config.yaml — HeySpex workflow settings for this vault.
2
- # Seeded by `hs init` (ADR-0009 §1: the file lives at the VAULT root and is git-tracked).
3
- # Field reference: specs/protocols/agent-settings-protocol.md. Change values with
4
- # `hs settings set <key> <value>` or heyspex_settings_set — never by hand.
5
-
6
- mvp_mode:
7
- enabled: true
8
- review_grain: epic
9
- review_backlog_never_blocks: true
10
-
11
- pricing_tier:
12
- tier: free
13
-
14
- agent_behaviors:
15
- ask_forgiveness_not_permission: true
1
+ # .heyspex/config.yaml — HeySpex workflow settings for this vault.
2
+ # Seeded by `hs init` (ADR-0009 §1: the file lives at the VAULT root and is git-tracked).
3
+ # Field reference: specs/protocols/agent-settings-protocol.md. Change values with
4
+ # `hs settings set <key> <value>` or heyspex_settings_set — never by hand.
5
+
6
+ mvp_mode:
7
+ enabled: true
8
+ review_grain: epic
9
+ review_backlog_never_blocks: true
10
+
11
+ pricing_tier:
12
+ tier: free
13
+
14
+ agent_behaviors:
15
+ ask_forgiveness_not_permission: true
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ // dev-factory-overlay.mjs — the ONE gate that decides whether the owner's personal
3
+ // dev-factory overlay may load ([[HS-R475-C86Z-TASK-load-the-owner-dev-factory-overlay-only]],
4
+ // epic [[HS-9JMD-C86Z-EPIC-owner-dev-factory-isolation]], research
5
+ // [[HS-RXJO-C86Z-RES-spexfleet-per-user-seat-assignment-with]] §Owner dev-factory isolation).
6
+ //
7
+ // The overlay is the owner's own fleet configuration under `<repo>/dev-factory/`:
8
+ // routing-table.json (which model fills which purpose), seats.json (the seat roster and
9
+ // each seat's fill), budget-config.json (per-company spend caps). It must never be read,
10
+ // inherited or overwritten by another HeySpex developer. It loads only when ALL hold:
11
+ //
12
+ // 1. switch — `HEYSPEX_DEV_FACTORY` is not "0" (the owner's off switch);
13
+ // 2. checkout — the root is a heyspex-app SOURCE checkout: package.json name "heyspex",
14
+ // a `.git` entry (dir, or file for a worktree), a `dev-factory/` dir, and
15
+ // not under `node_modules/` (an installed package is never a checkout);
16
+ // 3. account — when the overlay declares its owners (`dev-factory/overlay-owner.json`
17
+ // `{ "account_ids": [...] }`), the signed-in account (HS_ACCOUNT_ID, else
18
+ // the credentials store's current account) is one of them. Signed out is
19
+ // allowed (not another user; the owner's offline fleet machines keep
20
+ // running). No declaration = no account check (back-compat).
21
+ //
22
+ // An explicit `HS_DEV_FACTORY_ROOT` naming this root's dev-factory dir is the caller's own
23
+ // opt-in (test fixtures, the owner's coordinator) and skips check 2 — it never skips 1 or 3.
24
+ // The console's builder gate (`guardOwnerFactoryRead`) is the account check for HTTP callers.
25
+ //
26
+ // Plain Node ESM, builtins + ./credentials.mjs only, never throws. Packaged (vendor glob) so
27
+ // every packaged reader can call it; a packaged install always resolves "closed" at check 2.
28
+ //
29
+ // node vendor/heyspex-mcp/dev-factory-overlay.mjs # prints the verdict JSON
30
+ // node vendor/heyspex-mcp/dev-factory-overlay.mjs --assert-open # exit 1 unless open, and
31
+ // # proves the files still load
32
+
33
+ import { existsSync, readFileSync } from 'node:fs';
34
+ import path from 'node:path';
35
+ import { fileURLToPath } from 'node:url';
36
+
37
+ import { readCurrentAccountId } from './credentials.mjs';
38
+
39
+ export const DEV_FACTORY_SWITCH_ENV = 'HEYSPEX_DEV_FACTORY';
40
+ export const OVERLAY_OWNER_FILE = 'overlay-owner.json';
41
+ /** The overlay files this gate guards, relative to `<root>/dev-factory/`. */
42
+ export const OVERLAY_FILES = Object.freeze(['routing-table.json', 'seats.json', 'budget-config.json']);
43
+
44
+ const norm = (p) => path.resolve(String(p)).replaceAll('\\', '/').replace(/\/+$/, '').toLowerCase();
45
+
46
+ function readJsonOrNull(file) {
47
+ try {
48
+ return JSON.parse(readFileSync(file, 'utf8'));
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
53
+
54
+ /** True when `root` is a heyspex-app source checkout (see header check 2). Never throws. */
55
+ export function isHeyspexSourceCheckout(root) {
56
+ try {
57
+ if (!root) return false;
58
+ const abs = path.resolve(String(root));
59
+ if (/[\\/]node_modules([\\/]|$)/i.test(abs)) return false;
60
+ if (!existsSync(path.join(abs, '.git'))) return false;
61
+ if (!existsSync(path.join(abs, 'dev-factory'))) return false;
62
+ const pkg = readJsonOrNull(path.join(abs, 'package.json'));
63
+ return pkg?.name === 'heyspex';
64
+ } catch {
65
+ return false;
66
+ }
67
+ }
68
+
69
+ /** The account ids `dev-factory/overlay-owner.json` declares as the overlay's owners ([] = undeclared). */
70
+ export function declaredOverlayOwners(root) {
71
+ const doc = root ? readJsonOrNull(path.join(String(root), 'dev-factory', OVERLAY_OWNER_FILE)) : null;
72
+ const ids = Array.isArray(doc?.account_ids) ? doc.account_ids : [];
73
+ return ids.filter((id) => typeof id === 'string' && id.trim()).map((id) => id.trim());
74
+ }
75
+
76
+ /**
77
+ * The full verdict. `root` is the REPO root (the directory that holds `dev-factory/`).
78
+ * @param {{ root: string, env?: Record<string, string|undefined>, accountId?: string|null }} opts
79
+ * `accountId` — injected signed-in account (tests); read from env/credentials otherwise.
80
+ * @returns {{ open: boolean, reason: string, root: string|null, accountId: string|null, owners: string[] }}
81
+ */
82
+ export function devFactoryOverlayVerdict({ root, env = process.env, accountId } = {}) {
83
+ const out = (open, reason, extra = {}) => ({ open, reason, root: root ? path.resolve(String(root)) : null, accountId: null, owners: [], ...extra });
84
+ try {
85
+ if (!root) return out(false, 'no-root');
86
+ if (String(env?.[DEV_FACTORY_SWITCH_ENV] ?? '').trim() === '0') return out(false, 'disabled');
87
+
88
+ const override = env?.HS_DEV_FACTORY_ROOT;
89
+ const optedIn = Boolean(override) && norm(override) === norm(path.join(String(root), 'dev-factory'));
90
+ if (!optedIn && !isHeyspexSourceCheckout(root)) return out(false, 'not-source-checkout');
91
+
92
+ const owners = declaredOverlayOwners(root);
93
+ const who =
94
+ accountId !== undefined
95
+ ? accountId
96
+ : (env?.HS_ACCOUNT_ID && String(env.HS_ACCOUNT_ID).trim()) || safeCurrentAccountId();
97
+ if (owners.length > 0 && who && !owners.includes(who)) {
98
+ return out(false, 'not-owner-account', { accountId: who, owners });
99
+ }
100
+ const reason = optedIn ? 'override' : owners.length === 0 ? 'owner-undeclared' : who ? 'owner' : 'signed-out';
101
+ return out(true, reason, { accountId: who ?? null, owners });
102
+ } catch {
103
+ return out(false, 'error');
104
+ }
105
+ }
106
+
107
+ function safeCurrentAccountId() {
108
+ try {
109
+ return readCurrentAccountId() ?? null;
110
+ } catch {
111
+ return null;
112
+ }
113
+ }
114
+
115
+ /** Boolean form of {@link devFactoryOverlayVerdict}. */
116
+ export function isDevFactoryOverlayOpen(root, opts = {}) {
117
+ return devFactoryOverlayVerdict({ ...opts, root }).open;
118
+ }
119
+
120
+ /**
121
+ * Same verdict, keyed by the dev-factory DIRECTORY (what the console's
122
+ * `resolveDevFactoryRoot()` returns) instead of the repo root.
123
+ */
124
+ export function isDevFactoryDirOverlayOpen(devFactoryDir, opts = {}) {
125
+ if (!devFactoryDir) return false;
126
+ return isDevFactoryOverlayOpen(path.dirname(path.resolve(String(devFactoryDir))), opts);
127
+ }
128
+
129
+ // ── CLI ──────────────────────────────────────────────────────────────────────
130
+ const self = fileURLToPath(import.meta.url);
131
+ if (process.argv[1] && path.resolve(process.argv[1]) === self) {
132
+ const root = path.resolve(path.dirname(self), '..', '..');
133
+ const verdict = devFactoryOverlayVerdict({ root });
134
+ const loads = Object.fromEntries(
135
+ OVERLAY_FILES.map((f) => [f, readJsonOrNull(path.join(root, 'dev-factory', f)) !== null]),
136
+ );
137
+ console.log(JSON.stringify({ ...verdict, loads }, null, 2));
138
+ if (process.argv.includes('--assert-open')) {
139
+ const ok = verdict.open && loads['routing-table.json'] && loads['seats.json'];
140
+ process.exit(ok ? 0 : 1);
141
+ }
142
+ }