@nforma.ai/nforma 0.2.1 → 0.29.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 (193) hide show
  1. package/README.md +2 -2
  2. package/agents/{qgsd-codebase-mapper.md → nf-codebase-mapper.md} +1 -1
  3. package/agents/{qgsd-debugger.md → nf-debugger.md} +3 -3
  4. package/agents/{qgsd-executor.md → nf-executor.md} +14 -14
  5. package/agents/{qgsd-integration-checker.md → nf-integration-checker.md} +1 -1
  6. package/agents/{qgsd-phase-researcher.md → nf-phase-researcher.md} +6 -6
  7. package/agents/{qgsd-plan-checker.md → nf-plan-checker.md} +9 -9
  8. package/agents/{qgsd-planner.md → nf-planner.md} +9 -9
  9. package/agents/{qgsd-project-researcher.md → nf-project-researcher.md} +2 -2
  10. package/agents/{qgsd-quorum-orchestrator.md → nf-quorum-orchestrator.md} +33 -33
  11. package/agents/{qgsd-quorum-slot-worker.md → nf-quorum-slot-worker.md} +3 -3
  12. package/agents/{qgsd-quorum-synthesizer.md → nf-quorum-synthesizer.md} +3 -3
  13. package/agents/{qgsd-quorum-test-worker.md → nf-quorum-test-worker.md} +1 -1
  14. package/agents/{qgsd-quorum-worker.md → nf-quorum-worker.md} +6 -6
  15. package/agents/{qgsd-research-synthesizer.md → nf-research-synthesizer.md} +5 -5
  16. package/agents/{qgsd-roadmapper.md → nf-roadmapper.md} +3 -3
  17. package/agents/{qgsd-verifier.md → nf-verifier.md} +8 -8
  18. package/bin/accept-debug-invariant.cjs +2 -2
  19. package/bin/account-manager.cjs +10 -10
  20. package/bin/aggregate-requirements.cjs +1 -1
  21. package/bin/analyze-assumptions.cjs +3 -3
  22. package/bin/analyze-state-space.cjs +14 -14
  23. package/bin/assumption-register.cjs +146 -0
  24. package/bin/attribute-trace-divergence.cjs +1 -1
  25. package/bin/auth-drivers/gh-cli.cjs +1 -1
  26. package/bin/auth-drivers/pool.cjs +1 -1
  27. package/bin/autoClosePtoF.cjs +3 -3
  28. package/bin/budget-tracker.cjs +77 -0
  29. package/bin/build-layer-manifest.cjs +153 -0
  30. package/bin/call-quorum-slot.cjs +3 -3
  31. package/bin/ccr-secure-config.cjs +5 -5
  32. package/bin/check-bundled-sdks.cjs +1 -1
  33. package/bin/check-mcp-health.cjs +1 -1
  34. package/bin/check-provider-health.cjs +6 -6
  35. package/bin/check-spec-sync.cjs +26 -26
  36. package/bin/check-trace-schema-drift.cjs +5 -5
  37. package/bin/conformance-schema.cjs +2 -2
  38. package/bin/cross-layer-dashboard.cjs +297 -0
  39. package/bin/design-impact.cjs +377 -0
  40. package/bin/detect-coverage-gaps.cjs +7 -7
  41. package/bin/failure-mode-catalog.cjs +227 -0
  42. package/bin/failure-taxonomy.cjs +177 -0
  43. package/bin/formal-scope-scan.cjs +179 -0
  44. package/bin/gate-a-grounding.cjs +334 -0
  45. package/bin/gate-b-abstraction.cjs +243 -0
  46. package/bin/gate-c-validation.cjs +166 -0
  47. package/bin/generate-formal-specs.cjs +17 -17
  48. package/bin/generate-petri-net.cjs +3 -3
  49. package/bin/generate-tla-cfg.cjs +5 -5
  50. package/bin/git-heatmap.cjs +571 -0
  51. package/bin/harness-diagnostic.cjs +326 -0
  52. package/bin/hazard-model.cjs +261 -0
  53. package/bin/install-formal-tools.cjs +1 -1
  54. package/bin/install.js +184 -139
  55. package/bin/instrumentation-map.cjs +178 -0
  56. package/bin/invariant-catalog.cjs +437 -0
  57. package/bin/issue-classifier.cjs +2 -2
  58. package/bin/load-baseline-requirements.cjs +4 -4
  59. package/bin/manage-agents-core.cjs +32 -32
  60. package/bin/migrate-to-slots.cjs +39 -39
  61. package/bin/mismatch-register.cjs +217 -0
  62. package/bin/nForma.cjs +176 -81
  63. package/bin/{qgsd-solve.cjs → nf-solve.cjs} +327 -14
  64. package/bin/observe-config.cjs +8 -0
  65. package/bin/observe-debt-writer.cjs +1 -1
  66. package/bin/observe-handler-deps.cjs +356 -0
  67. package/bin/observe-handler-grafana.cjs +2 -17
  68. package/bin/observe-handler-internal.cjs +5 -5
  69. package/bin/observe-handler-logstash.cjs +2 -17
  70. package/bin/observe-handler-prometheus.cjs +2 -17
  71. package/bin/observe-handler-upstream.cjs +251 -0
  72. package/bin/observe-handlers.cjs +12 -33
  73. package/bin/observe-render.cjs +68 -22
  74. package/bin/observe-utils.cjs +37 -0
  75. package/bin/observed-fsm.cjs +324 -0
  76. package/bin/planning-paths.cjs +6 -0
  77. package/bin/polyrepo.cjs +1 -1
  78. package/bin/probe-quorum-slots.cjs +1 -1
  79. package/bin/promote-gate-maturity.cjs +274 -0
  80. package/bin/promote-model.cjs +1 -1
  81. package/bin/propose-debug-invariants.cjs +1 -1
  82. package/bin/quorum-cache.cjs +144 -0
  83. package/bin/quorum-consensus-gate.cjs +1 -1
  84. package/bin/quorum-preflight.cjs +89 -0
  85. package/bin/quorum-slot-dispatch.cjs +6 -6
  86. package/bin/requirements-core.cjs +1 -1
  87. package/bin/review-mcp-logs.cjs +1 -1
  88. package/bin/risk-heatmap.cjs +151 -0
  89. package/bin/run-account-manager-tlc.cjs +4 -4
  90. package/bin/run-account-pool-alloy.cjs +2 -2
  91. package/bin/run-alloy.cjs +2 -2
  92. package/bin/run-audit-alloy.cjs +2 -2
  93. package/bin/run-breaker-tlc.cjs +3 -3
  94. package/bin/run-formal-check.cjs +9 -9
  95. package/bin/run-formal-verify.cjs +30 -9
  96. package/bin/run-installer-alloy.cjs +2 -2
  97. package/bin/run-oscillation-tlc.cjs +4 -4
  98. package/bin/run-phase-tlc.cjs +1 -1
  99. package/bin/run-protocol-tlc.cjs +4 -4
  100. package/bin/run-quorum-composition-alloy.cjs +2 -2
  101. package/bin/run-sensitivity-sweep.cjs +2 -2
  102. package/bin/run-stop-hook-tlc.cjs +3 -3
  103. package/bin/run-tlc.cjs +21 -21
  104. package/bin/run-transcript-alloy.cjs +2 -2
  105. package/bin/secrets.cjs +5 -5
  106. package/bin/security-sweep.cjs +238 -0
  107. package/bin/sensitivity-report.cjs +3 -3
  108. package/bin/set-secret.cjs +5 -5
  109. package/bin/setup-telemetry-cron.sh +3 -3
  110. package/bin/stall-detector.cjs +126 -0
  111. package/bin/state-candidates.cjs +206 -0
  112. package/bin/sync-baseline-requirements.cjs +1 -1
  113. package/bin/telemetry-collector.cjs +1 -1
  114. package/bin/test-changed.cjs +111 -0
  115. package/bin/test-recipe-gen.cjs +250 -0
  116. package/bin/trace-corpus-stats.cjs +211 -0
  117. package/bin/unified-mcp-server.mjs +3 -3
  118. package/bin/update-scoreboard.cjs +1 -1
  119. package/bin/validate-memory.cjs +2 -2
  120. package/bin/validate-traces.cjs +10 -10
  121. package/bin/verify-quorum-health.cjs +66 -5
  122. package/bin/xstate-to-tla.cjs +4 -4
  123. package/bin/xstate-trace-walker.cjs +3 -3
  124. package/commands/{qgsd → nf}/add-phase.md +3 -3
  125. package/commands/{qgsd → nf}/add-requirement.md +3 -3
  126. package/commands/{qgsd → nf}/add-todo.md +3 -3
  127. package/commands/{qgsd → nf}/audit-milestone.md +4 -4
  128. package/commands/{qgsd → nf}/check-todos.md +3 -3
  129. package/commands/{qgsd → nf}/cleanup.md +3 -3
  130. package/commands/{qgsd → nf}/close-formal-gaps.md +2 -2
  131. package/commands/{qgsd → nf}/complete-milestone.md +9 -9
  132. package/commands/{qgsd → nf}/debug.md +9 -9
  133. package/commands/{qgsd → nf}/discuss-phase.md +3 -3
  134. package/commands/{qgsd → nf}/execute-phase.md +15 -15
  135. package/commands/{qgsd → nf}/fix-tests.md +3 -3
  136. package/commands/{qgsd → nf}/formal-test-sync.md +1 -1
  137. package/commands/{qgsd → nf}/health.md +3 -3
  138. package/commands/{qgsd → nf}/help.md +3 -3
  139. package/commands/{qgsd → nf}/insert-phase.md +3 -3
  140. package/commands/nf/join-discord.md +18 -0
  141. package/commands/{qgsd → nf}/list-phase-assumptions.md +2 -2
  142. package/commands/{qgsd → nf}/map-codebase.md +7 -7
  143. package/commands/{qgsd → nf}/map-requirements.md +3 -3
  144. package/commands/{qgsd → nf}/mcp-restart.md +3 -3
  145. package/commands/{qgsd → nf}/mcp-set-model.md +8 -8
  146. package/commands/{qgsd → nf}/mcp-setup.md +63 -63
  147. package/commands/{qgsd → nf}/mcp-status.md +3 -3
  148. package/commands/{qgsd → nf}/mcp-update.md +7 -7
  149. package/commands/{qgsd → nf}/new-milestone.md +8 -8
  150. package/commands/{qgsd → nf}/new-project.md +8 -8
  151. package/commands/{qgsd → nf}/observe.md +49 -16
  152. package/commands/{qgsd → nf}/pause-work.md +3 -3
  153. package/commands/{qgsd → nf}/plan-milestone-gaps.md +5 -5
  154. package/commands/{qgsd → nf}/plan-phase.md +6 -6
  155. package/commands/{qgsd → nf}/polyrepo.md +2 -2
  156. package/commands/{qgsd → nf}/progress.md +3 -3
  157. package/commands/{qgsd → nf}/queue.md +2 -2
  158. package/commands/{qgsd → nf}/quick.md +8 -8
  159. package/commands/{qgsd → nf}/quorum-test.md +10 -10
  160. package/commands/{qgsd → nf}/quorum.md +36 -86
  161. package/commands/{qgsd → nf}/reapply-patches.md +2 -2
  162. package/commands/{qgsd → nf}/remove-phase.md +3 -3
  163. package/commands/{qgsd → nf}/research-phase.md +12 -12
  164. package/commands/{qgsd → nf}/resume-work.md +3 -3
  165. package/commands/nf/review-requirements.md +31 -0
  166. package/commands/{qgsd → nf}/set-profile.md +3 -3
  167. package/commands/{qgsd → nf}/settings.md +6 -6
  168. package/commands/{qgsd → nf}/solve.md +35 -35
  169. package/commands/{qgsd → nf}/sync-baselines.md +4 -4
  170. package/commands/{qgsd → nf}/triage.md +10 -10
  171. package/commands/{qgsd → nf}/update.md +3 -3
  172. package/commands/{qgsd → nf}/verify-work.md +5 -5
  173. package/hooks/dist/config-loader.js +188 -32
  174. package/hooks/dist/conformance-schema.cjs +2 -2
  175. package/hooks/dist/gsd-context-monitor.js +118 -13
  176. package/hooks/dist/{qgsd-check-update.js → nf-check-update.js} +5 -5
  177. package/hooks/dist/{qgsd-circuit-breaker.js → nf-circuit-breaker.js} +35 -24
  178. package/hooks/dist/{qgsd-precompact.js → nf-precompact.js} +13 -13
  179. package/hooks/dist/{qgsd-prompt.js → nf-prompt.js} +110 -33
  180. package/hooks/dist/nf-session-start.js +185 -0
  181. package/hooks/dist/{qgsd-slot-correlator.js → nf-slot-correlator.js} +13 -5
  182. package/hooks/dist/{qgsd-spec-regen.js → nf-spec-regen.js} +17 -8
  183. package/hooks/dist/{qgsd-statusline.js → nf-statusline.js} +12 -3
  184. package/hooks/dist/{qgsd-stop.js → nf-stop.js} +152 -18
  185. package/hooks/dist/{qgsd-token-collector.js → nf-token-collector.js} +12 -4
  186. package/hooks/dist/unified-mcp-server.mjs +2 -2
  187. package/package.json +6 -4
  188. package/scripts/build-hooks.js +13 -6
  189. package/scripts/secret-audit.sh +1 -1
  190. package/scripts/verify-hooks-sync.cjs +90 -0
  191. package/templates/{qgsd.json → nf.json} +4 -4
  192. package/commands/qgsd/join-discord.md +0 -18
  193. package/hooks/dist/qgsd-session-start.js +0 -122
@@ -104,7 +104,7 @@ function buildSlotTools(provider) {
104
104
  // Universal: identity
105
105
  tools.push({
106
106
  name: 'identity',
107
- description: 'Get server identity: name, version, active LLM model, and MCP server name. Used by QGSD to fingerprint the active quorum team.',
107
+ description: 'Get server identity: name, version, active LLM model, and MCP server name. Used by nForma to fingerprint the active quorum team.',
108
108
  inputSchema: NO_ARGS_SCHEMA,
109
109
  });
110
110
 
@@ -501,7 +501,7 @@ function buildIdentityResult(provider) {
501
501
  model,
502
502
  display_provider: provider.display_provider ?? null,
503
503
  provider: provider.description,
504
- install_method: 'qgsd-monorepo',
504
+ install_method: 'nf-monorepo',
505
505
  });
506
506
  }
507
507
 
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "@nforma.ai/nforma",
3
- "version": "0.2.1",
3
+ "version": "0.29.0",
4
4
  "description": "nForma — Quorum Gets Shit Done. Multi-model quorum enforcement for GSD planning commands via Claude Code hooks.",
5
5
  "bin": {
6
6
  "nforma": "bin/install.js",
7
- "qgsd": "bin/install.js",
8
7
  "get-shit-done-cc": "bin/install.js"
9
8
  },
10
9
  "files": [
@@ -14,6 +13,7 @@
14
13
  "get-shit-done",
15
14
  "agents",
16
15
  "hooks/dist",
16
+ "!hooks/dist/*.test.*",
17
17
  "scripts",
18
18
  "!scripts/generate-logo-svg.js",
19
19
  "!scripts/generate-terminal-svg.js",
@@ -70,7 +70,7 @@
70
70
  "scripts": {
71
71
  "postinstall": "node scripts/postinstall.js",
72
72
  "build:hooks": "node scripts/build-hooks.js",
73
- "build:machines": "npx tsup src/machines/qgsd-workflow.machine.ts --format cjs --out-dir dist/machines --no-splitting --tsconfig tsconfig.formal.json",
73
+ "build:machines": "npx tsup src/machines/nf-workflow.machine.ts --format cjs --out-dir dist/machines --no-splitting --tsconfig tsconfig.formal.json",
74
74
  "generate-terminal": "node scripts/generate-terminal-svg.js",
75
75
  "generate-logo": "node scripts/generate-logo-svg.js",
76
76
  "generate-assets": "npm run generate-terminal && npm run generate-logo",
@@ -88,7 +88,9 @@
88
88
  "secrets:audit": "detect-secrets audit .secrets.baseline",
89
89
  "secrets:history": "bash scripts/secret-audit.sh",
90
90
  "test": "npm run test:ci && npm run test:formal",
91
- "test:ci": "node scripts/lint-isolation.js && node --test hooks/qgsd-precompact.test.js hooks/gsd-context-monitor.test.js hooks/qgsd-session-start.test.js bin/conformance-schema.test.cjs bin/resolve-cli.test.cjs bin/secrets.test.cjs bin/verify-quorum-health.test.cjs hooks/qgsd-stop.test.js hooks/config-loader.test.js qgsd-core/bin/gsd-tools.test.cjs hooks/qgsd-circuit-breaker.test.js hooks/qgsd-prompt.test.js bin/update-scoreboard.test.cjs hooks/qgsd-statusline.test.js bin/review-mcp-logs.test.cjs bin/migrate-to-slots.test.cjs bin/validate-traces.test.cjs bin/write-check-result.test.cjs bin/check-results-exit.test.cjs bin/check-trace-redaction.test.cjs bin/check-trace-schema-drift.test.cjs bin/qgsd.test.cjs bin/set-secret.test.cjs bin/issue-classifier.test.cjs bin/generate-tla-cfg.test.cjs bin/ccr-secure-config.test.cjs bin/gsd-quorum-slot-worker-improvements.test.cjs bin/quorum-improvements-signal.test.cjs bin/claude-md-references.test.cjs hooks/qgsd-spec-regen.test.js bin/propose-debug-invariants.test.cjs bin/aggregate-requirements.test.cjs bin/validate-requirements-haiku.test.cjs bin/call-quorum-slot-retry.test.cjs bin/provider-mapping.test.cjs",
91
+ "test:changed": "node bin/test-changed.cjs",
92
+ "test:ci": "node scripts/lint-isolation.js && node scripts/verify-hooks-sync.cjs && node --test hooks/nf-precompact.test.js hooks/gsd-context-monitor.test.js hooks/nf-session-start.test.js bin/conformance-schema.test.cjs bin/resolve-cli.test.cjs bin/secrets.test.cjs bin/verify-quorum-health.test.cjs hooks/nf-stop.test.js hooks/config-loader.test.js core/bin/gsd-tools.test.cjs hooks/nf-circuit-breaker.test.js hooks/nf-prompt.test.js bin/update-scoreboard.test.cjs hooks/nf-statusline.test.js bin/review-mcp-logs.test.cjs bin/migrate-to-slots.test.cjs bin/validate-traces.test.cjs bin/write-check-result.test.cjs bin/check-results-exit.test.cjs bin/check-trace-redaction.test.cjs bin/check-trace-schema-drift.test.cjs bin/nForma.test.cjs bin/set-secret.test.cjs bin/issue-classifier.test.cjs bin/generate-tla-cfg.test.cjs bin/ccr-secure-config.test.cjs bin/gsd-quorum-slot-worker-improvements.test.cjs bin/quorum-improvements-signal.test.cjs bin/claude-md-references.test.cjs hooks/nf-spec-regen.test.js bin/propose-debug-invariants.test.cjs bin/aggregate-requirements.test.cjs bin/validate-requirements-haiku.test.cjs bin/call-quorum-slot-retry.test.cjs bin/provider-mapping.test.cjs",
93
+ "test:install": "node --test test/install-virgin.test.cjs",
92
94
  "test:formal": "node --test bin/run-tlc.test.cjs bin/run-alloy.test.cjs bin/export-prism-constants.test.cjs bin/generate-petri-net.test.cjs bin/run-breaker-tlc.test.cjs bin/run-oscillation-tlc.test.cjs bin/run-protocol-tlc.test.cjs bin/run-audit-alloy.test.cjs bin/run-transcript-alloy.test.cjs bin/run-installer-alloy.test.cjs bin/run-formal-verify.test.cjs bin/xstate-to-tla.test.cjs bin/run-account-manager-tlc.test.cjs bin/run-account-pool-alloy.test.cjs bin/run-oauth-rotation-prism.test.cjs bin/run-prism.test.cjs bin/check-spec-sync.test.cjs bin/sensitivity-sweep-feedback.test.cjs bin/roadmapper-formal-integration.test.cjs bin/test-formal-integration.test.cjs test/alloy-headless.test.cjs",
93
95
  "prepare": "husky"
94
96
  }
@@ -11,12 +11,19 @@ const DIST_DIR = path.join(HOOKS_DIR, 'dist');
11
11
 
12
12
  // Hooks to copy (pure Node.js, no bundling needed)
13
13
  const HOOKS_TO_COPY = [
14
- 'qgsd-check-update.js',
15
- 'qgsd-statusline.js',
16
- 'qgsd-prompt.js', // QGSD: UserPromptSubmit quorum injection hook
17
- 'qgsd-stop.js', // QGSD: Stop quorum verification gate
18
- 'config-loader.js', // QGSD: shared config loader (required by qgsd-prompt.js and qgsd-stop.js)
19
- 'qgsd-circuit-breaker.js', // QGSD: PreToolUse oscillation detection and state persistence
14
+ 'nf-check-update.js',
15
+ 'nf-statusline.js',
16
+ 'nf-prompt.js', // nForma: UserPromptSubmit quorum injection hook
17
+ 'nf-stop.js', // nForma: Stop quorum verification gate
18
+ 'nf-circuit-breaker.js', // nForma: PreToolUse oscillation detection and state persistence
19
+ 'nf-session-start.js', // nForma: SessionStart hook
20
+ 'nf-precompact.js', // nForma: PreCompact hook
21
+ 'nf-spec-regen.js', // nForma: PostToolUse spec regeneration
22
+ 'nf-token-collector.js', // nForma: SubagentStop token collection
23
+ 'nf-slot-correlator.js', // nForma: SubagentStart slot correlation
24
+ 'gsd-context-monitor.js', // nForma: PostToolUse context monitoring
25
+ 'config-loader.js', // shared config loader (required by multiple hooks)
26
+ 'conformance-schema.cjs', // shared conformance schema (required by nf-prompt, nf-stop, nf-circuit-breaker)
20
27
  ];
21
28
 
22
29
  function build() {
@@ -5,7 +5,7 @@
5
5
 
6
6
  set -euo pipefail
7
7
 
8
- echo "=== QGSD Full-History Secret Audit ==="
8
+ echo "=== nForma Full-History Secret Audit ==="
9
9
  echo ""
10
10
 
11
11
  # --- Gitleaks full-history scan ---
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CI guard: verifies that every hook registered by the installer has a
4
+ * corresponding entry in the build-hooks HOOKS_TO_COPY list, and that
5
+ * every require('./...') dependency inside those hooks is also included.
6
+ *
7
+ * Exits non-zero on drift so the test suite catches it early.
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ const ROOT = path.resolve(__dirname, '..');
16
+ const INSTALL_JS = path.join(ROOT, 'bin', 'install.js');
17
+ const BUILD_HOOKS_JS = path.join(ROOT, 'scripts', 'build-hooks.js');
18
+ const HOOKS_DIR = path.join(ROOT, 'hooks');
19
+
20
+ // --- Extract HOOKS_TO_COPY from build-hooks.js ---
21
+ function getHooksToCopy() {
22
+ const src = fs.readFileSync(BUILD_HOOKS_JS, 'utf8');
23
+ const match = src.match(/HOOKS_TO_COPY\s*=\s*\[([\s\S]*?)\]/);
24
+ if (!match) throw new Error('Could not parse HOOKS_TO_COPY from build-hooks.js');
25
+ const entries = [];
26
+ for (const m of match[1].matchAll(/'([^']+)'/g)) {
27
+ entries.push(m[1]);
28
+ }
29
+ return new Set(entries);
30
+ }
31
+
32
+ // --- Extract hook filenames registered by the installer via buildHookCommand() ---
33
+ function getInstallerHooks() {
34
+ const src = fs.readFileSync(INSTALL_JS, 'utf8');
35
+ const hooks = new Set();
36
+ for (const m of src.matchAll(/buildHookCommand\(\s*\w+\s*,\s*'([^']+)'\s*\)/g)) {
37
+ hooks.add(m[1]);
38
+ }
39
+ return hooks;
40
+ }
41
+
42
+ // --- Extract local require('./...') dependencies from a hook source file ---
43
+ function getLocalRequires(filePath) {
44
+ const src = fs.readFileSync(filePath, 'utf8');
45
+ const deps = new Set();
46
+ for (const m of src.matchAll(/require\(\s*'\.\/([^']+)'\s*\)/g)) {
47
+ let dep = m[1];
48
+ // Node resolves require('./config-loader') to './config-loader.js'
49
+ // Normalize to match HOOKS_TO_COPY entries which include extensions
50
+ if (!path.extname(dep)) dep += '.js';
51
+ deps.add(dep);
52
+ }
53
+ return deps;
54
+ }
55
+
56
+ // --- Main ---
57
+ const hooksToCopy = getHooksToCopy();
58
+ const installerHooks = getInstallerHooks();
59
+ const errors = [];
60
+
61
+ // 1. Every hook registered by the installer must be in HOOKS_TO_COPY
62
+ for (const hook of installerHooks) {
63
+ if (!hooksToCopy.has(hook)) {
64
+ errors.push(`MISSING from HOOKS_TO_COPY: '${hook}' (registered in installer via buildHookCommand)`);
65
+ }
66
+ }
67
+
68
+ // 2. Every local require() dependency of copied hooks must also be in HOOKS_TO_COPY
69
+ for (const hook of hooksToCopy) {
70
+ const hookPath = path.join(HOOKS_DIR, hook);
71
+ if (!fs.existsSync(hookPath)) {
72
+ errors.push(`HOOKS_TO_COPY entry '${hook}' does not exist at ${hookPath}`);
73
+ continue;
74
+ }
75
+ const deps = getLocalRequires(hookPath);
76
+ for (const dep of deps) {
77
+ if (!hooksToCopy.has(dep)) {
78
+ errors.push(`MISSING from HOOKS_TO_COPY: '${dep}' (required by ${hook})`);
79
+ }
80
+ }
81
+ }
82
+
83
+ if (errors.length > 0) {
84
+ console.error('hooks-sync verification FAILED:\n');
85
+ for (const e of errors) console.error(` - ${e}`);
86
+ console.error('\nFix: update HOOKS_TO_COPY in scripts/build-hooks.js');
87
+ process.exit(1);
88
+ } else {
89
+ console.log(`hooks-sync OK: ${hooksToCopy.size} hooks in build list, ${installerHooks.size} registered by installer`);
90
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "_comment": [
3
- "QGSD Quorum Config — generated by QGSD installer. Safe to edit.",
3
+ "nForma Quorum Config — generated by nForma installer. Safe to edit.",
4
4
  "",
5
5
  "quorum_commands: GSD planning commands that require quorum before Claude delivers output.",
6
6
  " Add or remove command names to control which /gsd: commands are gated.",
@@ -14,11 +14,11 @@
14
14
  "fail_mode: 'open' (default) — unavailable models are skipped, quorum passes with available models.",
15
15
  " 'closed' is reserved for future use.",
16
16
  "",
17
- "Config layering: ~/.claude/qgsd.json (global) is loaded first.",
18
- " .claude/qgsd.json in the project directory overrides global values (project takes precedence).",
17
+ "Config layering: ~/.claude/nf.json (global) is loaded first.",
18
+ " .claude/nf.json in the project directory overrides global values (project takes precedence).",
19
19
  " Merge is SHALLOW: if a project config sets required_models, it entirely replaces global required_models.",
20
20
  " To add a model to the global list, copy the full required_models from global and add your entry.",
21
- " Create .claude/qgsd.json in a project to restrict quorum to fewer models or different commands.",
21
+ " Create .claude/nf.json in a project to restrict quorum to fewer models or different commands.",
22
22
  "",
23
23
  "circuit_breaker config uses the SAME shallow merge: a project config with only oscillation_depth set",
24
24
  " entirely replaces the global circuit_breaker object. commit_window falls back to DEFAULT (6), NOT the global value.",
@@ -1,18 +0,0 @@
1
- ---
2
- name: qgsd:join-discord
3
- description: Join the QGSD Discord community
4
- ---
5
-
6
- <objective>
7
- Display the Discord invite link for the QGSD community server.
8
- </objective>
9
-
10
- <output>
11
- # Join the QGSD Discord
12
-
13
- Connect with other QGSD users, get help, share what you're building, and stay updated.
14
-
15
- **Server link:** https://discord.com/servers/1474810068636663886
16
-
17
- Click the link or paste it into your browser to join.
18
- </output>
@@ -1,122 +0,0 @@
1
- #!/usr/bin/env node
2
- // hooks/qgsd-session-start.js
3
- // SessionStart hook — syncs QGSD keychain secrets into ~/.claude.json
4
- // on every session start so mcpServers env blocks always reflect current keychain state.
5
- //
6
- // Runs synchronously (hook expects process to exit) — uses async IIFE with catch.
7
-
8
- 'use strict';
9
-
10
- const path = require('path');
11
- const os = require('os');
12
- const fs = require('fs');
13
-
14
- // ─── Stdin accumulation (for hook input JSON containing cwd) ─────────────────
15
- let _stdinRaw = '';
16
- process.stdin.setEncoding('utf8');
17
- process.stdin.on('data', c => _stdinRaw += c);
18
-
19
- let _stdinReady;
20
- const _stdinPromise = new Promise(resolve => { _stdinReady = resolve; });
21
- process.stdin.on('end', () => _stdinReady());
22
-
23
- // Locate secrets.cjs — try installed global path first, then local dev path.
24
- //
25
- // IMPORTANT: install.js copies bin/*.cjs to ~/.claude/qgsd-bin/ (not ~/.claude/qgsd/bin/).
26
- // See bin/install.js line ~1679: binDest = path.join(targetDir, 'qgsd-bin')
27
- // where targetDir = os.homedir() + '/.claude'.
28
- function findSecrets() {
29
- const candidates = [
30
- path.join(os.homedir(), '.claude', 'qgsd-bin', 'secrets.cjs'), // installed path
31
- path.join(__dirname, '..', 'bin', 'secrets.cjs'), // local dev path
32
- ];
33
- for (const p of candidates) {
34
- try {
35
- return require(p);
36
- } catch (_) {}
37
- }
38
- return null;
39
- }
40
-
41
- (async () => {
42
- // Resolve project cwd from hook input JSON
43
- await _stdinPromise;
44
- let _hookCwd = process.cwd();
45
- try { _hookCwd = JSON.parse(_stdinRaw).cwd || process.cwd(); } catch (_) {}
46
-
47
- const secrets = findSecrets();
48
- if (!secrets) {
49
- // silently skip — QGSD may not be installed yet or keytar absent
50
- process.exit(0);
51
- }
52
- try {
53
- await secrets.syncToClaudeJson(secrets.SERVICE);
54
- } catch (e) {
55
- // Non-fatal — write to stderr for debug logs, but never block session start
56
- process.stderr.write('[qgsd-session-start] sync error: ' + e.message + '\n');
57
- }
58
-
59
- // Populate CCR config from keytar (fail-silent — CCR may not be installed)
60
- try {
61
- const { execFileSync } = require('child_process');
62
- const nodeFsRef = require('fs');
63
- const ccrCandidates = [
64
- path.join(os.homedir(), '.claude', 'qgsd-bin', 'ccr-secure-config.cjs'),
65
- path.join(__dirname, '..', 'bin', 'ccr-secure-config.cjs'),
66
- ];
67
- let ccrConfigPath = null;
68
- for (const p of ccrCandidates) {
69
- if (nodeFsRef.existsSync(p)) { ccrConfigPath = p; break; }
70
- }
71
- if (ccrConfigPath) {
72
- execFileSync(process.execPath, [ccrConfigPath], { stdio: 'pipe', timeout: 10000 });
73
- }
74
- } catch (e) {
75
- process.stderr.write('[qgsd-session-start] CCR config error: ' + e.message + '\n');
76
- }
77
-
78
- // Telemetry surfacing — inject top unsurfaced issue as additionalContext
79
- // Guard: only active when running inside the QGSD dev repo itself
80
- try {
81
- const pkgPath = path.join(_hookCwd, 'package.json');
82
- const isQgsdRepo = fs.existsSync(pkgPath) &&
83
- JSON.parse(fs.readFileSync(pkgPath, 'utf8')).name === 'qgsd';
84
- const fixesPath = path.join(_hookCwd, '.planning', 'telemetry', 'pending-fixes.json');
85
- if (isQgsdRepo && fs.existsSync(fixesPath)) {
86
- const fixes = JSON.parse(fs.readFileSync(fixesPath, 'utf8'));
87
- const issue = (fixes.issues || []).find(i => !i.surfaced && i.priority >= 50);
88
- if (issue) {
89
- issue.surfaced = true;
90
- issue.surfacedAt = new Date().toISOString();
91
- fs.writeFileSync(fixesPath, JSON.stringify(fixes, null, 2), 'utf8');
92
- const ctx = 'Telemetry alert [priority=' + issue.priority + ']: ' + issue.description + '\nSuggested fix: ' + issue.action;
93
- process.stdout.write(JSON.stringify({
94
- hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: ctx }
95
- }));
96
- }
97
- }
98
- } catch (_) {}
99
-
100
- // Memory staleness check — warn about outdated MEMORY.md entries
101
- try {
102
- const validateMemoryCandidates = [
103
- path.join(os.homedir(), '.claude', 'qgsd-bin', 'validate-memory.cjs'),
104
- path.join(__dirname, '..', 'bin', 'validate-memory.cjs'),
105
- ];
106
- let validateMemoryMod = null;
107
- for (const p of validateMemoryCandidates) {
108
- try { validateMemoryMod = require(p); break; } catch (_) {}
109
- }
110
- if (validateMemoryMod) {
111
- const { findings } = validateMemoryMod.validateMemory({ cwd: _hookCwd, quiet: true });
112
- if (findings.length > 0) {
113
- const summary = findings
114
- .map(f => '[memory-check] ' + f.message)
115
- .join('\n');
116
- process.stderr.write(summary + '\n');
117
- }
118
- }
119
- } catch (_) {}
120
-
121
- process.exit(0);
122
- })();