@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.
- package/README.md +2 -2
- package/agents/{qgsd-codebase-mapper.md → nf-codebase-mapper.md} +1 -1
- package/agents/{qgsd-debugger.md → nf-debugger.md} +3 -3
- package/agents/{qgsd-executor.md → nf-executor.md} +14 -14
- package/agents/{qgsd-integration-checker.md → nf-integration-checker.md} +1 -1
- package/agents/{qgsd-phase-researcher.md → nf-phase-researcher.md} +6 -6
- package/agents/{qgsd-plan-checker.md → nf-plan-checker.md} +9 -9
- package/agents/{qgsd-planner.md → nf-planner.md} +9 -9
- package/agents/{qgsd-project-researcher.md → nf-project-researcher.md} +2 -2
- package/agents/{qgsd-quorum-orchestrator.md → nf-quorum-orchestrator.md} +33 -33
- package/agents/{qgsd-quorum-slot-worker.md → nf-quorum-slot-worker.md} +3 -3
- package/agents/{qgsd-quorum-synthesizer.md → nf-quorum-synthesizer.md} +3 -3
- package/agents/{qgsd-quorum-test-worker.md → nf-quorum-test-worker.md} +1 -1
- package/agents/{qgsd-quorum-worker.md → nf-quorum-worker.md} +6 -6
- package/agents/{qgsd-research-synthesizer.md → nf-research-synthesizer.md} +5 -5
- package/agents/{qgsd-roadmapper.md → nf-roadmapper.md} +3 -3
- package/agents/{qgsd-verifier.md → nf-verifier.md} +8 -8
- package/bin/accept-debug-invariant.cjs +2 -2
- package/bin/account-manager.cjs +10 -10
- package/bin/aggregate-requirements.cjs +1 -1
- package/bin/analyze-assumptions.cjs +3 -3
- package/bin/analyze-state-space.cjs +14 -14
- package/bin/assumption-register.cjs +146 -0
- package/bin/attribute-trace-divergence.cjs +1 -1
- package/bin/auth-drivers/gh-cli.cjs +1 -1
- package/bin/auth-drivers/pool.cjs +1 -1
- package/bin/autoClosePtoF.cjs +3 -3
- package/bin/budget-tracker.cjs +77 -0
- package/bin/build-layer-manifest.cjs +153 -0
- package/bin/call-quorum-slot.cjs +3 -3
- package/bin/ccr-secure-config.cjs +5 -5
- package/bin/check-bundled-sdks.cjs +1 -1
- package/bin/check-mcp-health.cjs +1 -1
- package/bin/check-provider-health.cjs +6 -6
- package/bin/check-spec-sync.cjs +26 -26
- package/bin/check-trace-schema-drift.cjs +5 -5
- package/bin/conformance-schema.cjs +2 -2
- package/bin/cross-layer-dashboard.cjs +297 -0
- package/bin/design-impact.cjs +377 -0
- package/bin/detect-coverage-gaps.cjs +7 -7
- package/bin/failure-mode-catalog.cjs +227 -0
- package/bin/failure-taxonomy.cjs +177 -0
- package/bin/formal-scope-scan.cjs +179 -0
- package/bin/gate-a-grounding.cjs +334 -0
- package/bin/gate-b-abstraction.cjs +243 -0
- package/bin/gate-c-validation.cjs +166 -0
- package/bin/generate-formal-specs.cjs +17 -17
- package/bin/generate-petri-net.cjs +3 -3
- package/bin/generate-tla-cfg.cjs +5 -5
- package/bin/git-heatmap.cjs +571 -0
- package/bin/harness-diagnostic.cjs +326 -0
- package/bin/hazard-model.cjs +261 -0
- package/bin/install-formal-tools.cjs +1 -1
- package/bin/install.js +184 -139
- package/bin/instrumentation-map.cjs +178 -0
- package/bin/invariant-catalog.cjs +437 -0
- package/bin/issue-classifier.cjs +2 -2
- package/bin/load-baseline-requirements.cjs +4 -4
- package/bin/manage-agents-core.cjs +32 -32
- package/bin/migrate-to-slots.cjs +39 -39
- package/bin/mismatch-register.cjs +217 -0
- package/bin/nForma.cjs +176 -81
- package/bin/{qgsd-solve.cjs → nf-solve.cjs} +327 -14
- package/bin/observe-config.cjs +8 -0
- package/bin/observe-debt-writer.cjs +1 -1
- package/bin/observe-handler-deps.cjs +356 -0
- package/bin/observe-handler-grafana.cjs +2 -17
- package/bin/observe-handler-internal.cjs +5 -5
- package/bin/observe-handler-logstash.cjs +2 -17
- package/bin/observe-handler-prometheus.cjs +2 -17
- package/bin/observe-handler-upstream.cjs +251 -0
- package/bin/observe-handlers.cjs +12 -33
- package/bin/observe-render.cjs +68 -22
- package/bin/observe-utils.cjs +37 -0
- package/bin/observed-fsm.cjs +324 -0
- package/bin/planning-paths.cjs +6 -0
- package/bin/polyrepo.cjs +1 -1
- package/bin/probe-quorum-slots.cjs +1 -1
- package/bin/promote-gate-maturity.cjs +274 -0
- package/bin/promote-model.cjs +1 -1
- package/bin/propose-debug-invariants.cjs +1 -1
- package/bin/quorum-cache.cjs +144 -0
- package/bin/quorum-consensus-gate.cjs +1 -1
- package/bin/quorum-preflight.cjs +89 -0
- package/bin/quorum-slot-dispatch.cjs +6 -6
- package/bin/requirements-core.cjs +1 -1
- package/bin/review-mcp-logs.cjs +1 -1
- package/bin/risk-heatmap.cjs +151 -0
- package/bin/run-account-manager-tlc.cjs +4 -4
- package/bin/run-account-pool-alloy.cjs +2 -2
- package/bin/run-alloy.cjs +2 -2
- package/bin/run-audit-alloy.cjs +2 -2
- package/bin/run-breaker-tlc.cjs +3 -3
- package/bin/run-formal-check.cjs +9 -9
- package/bin/run-formal-verify.cjs +30 -9
- package/bin/run-installer-alloy.cjs +2 -2
- package/bin/run-oscillation-tlc.cjs +4 -4
- package/bin/run-phase-tlc.cjs +1 -1
- package/bin/run-protocol-tlc.cjs +4 -4
- package/bin/run-quorum-composition-alloy.cjs +2 -2
- package/bin/run-sensitivity-sweep.cjs +2 -2
- package/bin/run-stop-hook-tlc.cjs +3 -3
- package/bin/run-tlc.cjs +21 -21
- package/bin/run-transcript-alloy.cjs +2 -2
- package/bin/secrets.cjs +5 -5
- package/bin/security-sweep.cjs +238 -0
- package/bin/sensitivity-report.cjs +3 -3
- package/bin/set-secret.cjs +5 -5
- package/bin/setup-telemetry-cron.sh +3 -3
- package/bin/stall-detector.cjs +126 -0
- package/bin/state-candidates.cjs +206 -0
- package/bin/sync-baseline-requirements.cjs +1 -1
- package/bin/telemetry-collector.cjs +1 -1
- package/bin/test-changed.cjs +111 -0
- package/bin/test-recipe-gen.cjs +250 -0
- package/bin/trace-corpus-stats.cjs +211 -0
- package/bin/unified-mcp-server.mjs +3 -3
- package/bin/update-scoreboard.cjs +1 -1
- package/bin/validate-memory.cjs +2 -2
- package/bin/validate-traces.cjs +10 -10
- package/bin/verify-quorum-health.cjs +66 -5
- package/bin/xstate-to-tla.cjs +4 -4
- package/bin/xstate-trace-walker.cjs +3 -3
- package/commands/{qgsd → nf}/add-phase.md +3 -3
- package/commands/{qgsd → nf}/add-requirement.md +3 -3
- package/commands/{qgsd → nf}/add-todo.md +3 -3
- package/commands/{qgsd → nf}/audit-milestone.md +4 -4
- package/commands/{qgsd → nf}/check-todos.md +3 -3
- package/commands/{qgsd → nf}/cleanup.md +3 -3
- package/commands/{qgsd → nf}/close-formal-gaps.md +2 -2
- package/commands/{qgsd → nf}/complete-milestone.md +9 -9
- package/commands/{qgsd → nf}/debug.md +9 -9
- package/commands/{qgsd → nf}/discuss-phase.md +3 -3
- package/commands/{qgsd → nf}/execute-phase.md +15 -15
- package/commands/{qgsd → nf}/fix-tests.md +3 -3
- package/commands/{qgsd → nf}/formal-test-sync.md +1 -1
- package/commands/{qgsd → nf}/health.md +3 -3
- package/commands/{qgsd → nf}/help.md +3 -3
- package/commands/{qgsd → nf}/insert-phase.md +3 -3
- package/commands/nf/join-discord.md +18 -0
- package/commands/{qgsd → nf}/list-phase-assumptions.md +2 -2
- package/commands/{qgsd → nf}/map-codebase.md +7 -7
- package/commands/{qgsd → nf}/map-requirements.md +3 -3
- package/commands/{qgsd → nf}/mcp-restart.md +3 -3
- package/commands/{qgsd → nf}/mcp-set-model.md +8 -8
- package/commands/{qgsd → nf}/mcp-setup.md +63 -63
- package/commands/{qgsd → nf}/mcp-status.md +3 -3
- package/commands/{qgsd → nf}/mcp-update.md +7 -7
- package/commands/{qgsd → nf}/new-milestone.md +8 -8
- package/commands/{qgsd → nf}/new-project.md +8 -8
- package/commands/{qgsd → nf}/observe.md +49 -16
- package/commands/{qgsd → nf}/pause-work.md +3 -3
- package/commands/{qgsd → nf}/plan-milestone-gaps.md +5 -5
- package/commands/{qgsd → nf}/plan-phase.md +6 -6
- package/commands/{qgsd → nf}/polyrepo.md +2 -2
- package/commands/{qgsd → nf}/progress.md +3 -3
- package/commands/{qgsd → nf}/queue.md +2 -2
- package/commands/{qgsd → nf}/quick.md +8 -8
- package/commands/{qgsd → nf}/quorum-test.md +10 -10
- package/commands/{qgsd → nf}/quorum.md +36 -86
- package/commands/{qgsd → nf}/reapply-patches.md +2 -2
- package/commands/{qgsd → nf}/remove-phase.md +3 -3
- package/commands/{qgsd → nf}/research-phase.md +12 -12
- package/commands/{qgsd → nf}/resume-work.md +3 -3
- package/commands/nf/review-requirements.md +31 -0
- package/commands/{qgsd → nf}/set-profile.md +3 -3
- package/commands/{qgsd → nf}/settings.md +6 -6
- package/commands/{qgsd → nf}/solve.md +35 -35
- package/commands/{qgsd → nf}/sync-baselines.md +4 -4
- package/commands/{qgsd → nf}/triage.md +10 -10
- package/commands/{qgsd → nf}/update.md +3 -3
- package/commands/{qgsd → nf}/verify-work.md +5 -5
- package/hooks/dist/config-loader.js +188 -32
- package/hooks/dist/conformance-schema.cjs +2 -2
- package/hooks/dist/gsd-context-monitor.js +118 -13
- package/hooks/dist/{qgsd-check-update.js → nf-check-update.js} +5 -5
- package/hooks/dist/{qgsd-circuit-breaker.js → nf-circuit-breaker.js} +35 -24
- package/hooks/dist/{qgsd-precompact.js → nf-precompact.js} +13 -13
- package/hooks/dist/{qgsd-prompt.js → nf-prompt.js} +110 -33
- package/hooks/dist/nf-session-start.js +185 -0
- package/hooks/dist/{qgsd-slot-correlator.js → nf-slot-correlator.js} +13 -5
- package/hooks/dist/{qgsd-spec-regen.js → nf-spec-regen.js} +17 -8
- package/hooks/dist/{qgsd-statusline.js → nf-statusline.js} +12 -3
- package/hooks/dist/{qgsd-stop.js → nf-stop.js} +152 -18
- package/hooks/dist/{qgsd-token-collector.js → nf-token-collector.js} +12 -4
- package/hooks/dist/unified-mcp-server.mjs +2 -2
- package/package.json +6 -4
- package/scripts/build-hooks.js +13 -6
- package/scripts/secret-audit.sh +1 -1
- package/scripts/verify-hooks-sync.cjs +90 -0
- package/templates/{qgsd.json → nf.json} +4 -4
- package/commands/qgsd/join-discord.md +0 -18
- 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
|
|
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: '
|
|
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.
|
|
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/
|
|
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:
|
|
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
|
}
|
package/scripts/build-hooks.js
CHANGED
|
@@ -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
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
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() {
|
package/scripts/secret-audit.sh
CHANGED
|
@@ -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
|
-
"
|
|
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/
|
|
18
|
-
" .claude/
|
|
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/
|
|
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
|
-
})();
|