@monoes/monomindcli 2.0.3 → 2.1.3
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/.claude/helpers/control-start.cjs +13 -20
- package/.claude/helpers/event-logger.cjs +109 -6
- package/.claude/helpers/graphify-freshen.cjs +19 -17
- package/.claude/helpers/handlers/agent-start-handler.cjs +60 -28
- package/.claude/helpers/handlers/capture-handler.cjs +99 -28
- package/.claude/helpers/handlers/edit-handler.cjs +27 -9
- package/.claude/helpers/handlers/gates-handler.cjs +18 -9
- package/.claude/helpers/handlers/loops-status-handler.cjs +1 -1
- package/.claude/helpers/handlers/route-handler.cjs +33 -4
- package/.claude/helpers/handlers/session-handler.cjs +75 -45
- package/.claude/helpers/handlers/session-restore-handler.cjs +0 -12
- package/.claude/helpers/handlers/task-handler.cjs +53 -22
- package/.claude/helpers/hook-handler.cjs +75 -4
- package/.claude/helpers/intelligence.cjs +94 -15
- package/.claude/helpers/session.cjs +6 -1
- package/.claude/helpers/statusline.cjs +10 -10
- package/.claude/helpers/token-tracker.cjs +3 -3
- package/.claude/helpers/utils/agent-registrations.cjs +41 -0
- package/.claude/helpers/utils/fs-helpers.cjs +183 -0
- package/.claude/helpers/utils/micro-agents.cjs +10 -6
- package/.claude/helpers/utils/monograph.cjs +73 -2
- package/.claude/helpers/utils/telemetry.cjs +35 -19
- package/README.md +74 -92
- package/bin/cli.js +10 -1
- package/dist/src/agents/registry-builder.js.map +1 -1
- package/dist/src/browser/dashboard/server.js.map +1 -1
- package/dist/src/browser/workflow/engine.d.ts.map +1 -1
- package/dist/src/browser/workflow/engine.js.map +1 -1
- package/dist/src/browser/workflow/store.d.ts +2 -2
- package/dist/src/browser/workflow/store.d.ts.map +1 -1
- package/dist/src/browser/workflow/store.js.map +1 -1
- package/dist/src/capabilities/manager.d.ts.map +1 -1
- package/dist/src/capabilities/watcher.d.ts.map +1 -1
- package/dist/src/commands/agent-lifecycle.js.map +1 -1
- package/dist/src/commands/agent-ops.d.ts.map +1 -1
- package/dist/src/commands/agent-ops.js +9 -15
- package/dist/src/commands/agent-ops.js.map +1 -1
- package/dist/src/commands/agent.d.ts.map +1 -1
- package/dist/src/commands/analyze-ast.js.map +1 -1
- package/dist/src/commands/analyze.d.ts.map +1 -1
- package/dist/src/commands/analyze.js.map +1 -1
- package/dist/src/commands/autopilot.d.ts.map +1 -1
- package/dist/src/commands/browse-action.d.ts.map +1 -1
- package/dist/src/commands/browse-action.js.map +1 -1
- package/dist/src/commands/browse-platform.d.ts.map +1 -1
- package/dist/src/commands/browse-workflow.d.ts.map +1 -1
- package/dist/src/commands/browse.d.ts +1 -1
- package/dist/src/commands/browse.d.ts.map +1 -1
- package/dist/src/commands/cleanup.d.ts.map +1 -1
- package/dist/src/commands/cleanup.js +20 -4
- package/dist/src/commands/cleanup.js.map +1 -1
- package/dist/src/commands/completions.d.ts.map +1 -1
- package/dist/src/commands/completions.js +66 -261
- package/dist/src/commands/completions.js.map +1 -1
- package/dist/src/commands/config.d.ts.map +1 -1
- package/dist/src/commands/crash-reporting.d.ts.map +1 -1
- package/dist/src/commands/design-detect.d.ts.map +1 -1
- package/dist/src/commands/design-palette.d.ts.map +1 -1
- package/dist/src/commands/doc.d.ts.map +1 -1
- package/dist/src/commands/doctor-env-checks.d.ts.map +1 -1
- package/dist/src/commands/doctor-env-checks.js +5 -0
- package/dist/src/commands/doctor-env-checks.js.map +1 -1
- package/dist/src/commands/doctor-project-checks.js.map +1 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +7 -2
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/guidance.d.ts.map +1 -1
- package/dist/src/commands/hooks-workers.d.ts.map +1 -1
- package/dist/src/commands/hooks-workers.js +7 -0
- package/dist/src/commands/hooks-workers.js.map +1 -1
- package/dist/src/commands/hooks.d.ts.map +1 -1
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +3 -0
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/mcp.d.ts.map +1 -1
- package/dist/src/commands/mcp.js +11 -6
- package/dist/src/commands/mcp.js.map +1 -1
- package/dist/src/commands/memory-admin.d.ts.map +1 -1
- package/dist/src/commands/memory-admin.js +12 -6
- package/dist/src/commands/memory-admin.js.map +1 -1
- package/dist/src/commands/memory-transfer.d.ts.map +1 -1
- package/dist/src/commands/memory-transfer.js +6 -13
- package/dist/src/commands/memory-transfer.js.map +1 -1
- package/dist/src/commands/memory.d.ts.map +1 -1
- package/dist/src/commands/monograph.d.ts.map +1 -1
- package/dist/src/commands/monograph.js +3 -3
- package/dist/src/commands/monograph.js.map +1 -1
- package/dist/src/commands/org.d.ts +3 -1
- package/dist/src/commands/org.d.ts.map +1 -1
- package/dist/src/commands/org.js +321 -127
- package/dist/src/commands/org.js.map +1 -1
- package/dist/src/commands/performance.d.ts.map +1 -1
- package/dist/src/commands/platforms.d.ts +1 -1
- package/dist/src/commands/platforms.d.ts.map +1 -1
- package/dist/src/commands/providers.d.ts.map +1 -1
- package/dist/src/commands/report-crash.d.ts.map +1 -1
- package/dist/src/commands/route.d.ts.map +1 -1
- package/dist/src/commands/search-universal.d.ts.map +1 -1
- package/dist/src/commands/security.d.ts.map +1 -1
- package/dist/src/commands/session.d.ts.map +1 -1
- package/dist/src/commands/start.d.ts.map +1 -1
- package/dist/src/commands/start.js +142 -37
- package/dist/src/commands/start.js.map +1 -1
- package/dist/src/commands/status.d.ts.map +1 -1
- package/dist/src/commands/swarm.d.ts.map +1 -1
- package/dist/src/commands/task.d.ts.map +1 -1
- package/dist/src/commands/tokens.d.ts.map +1 -1
- package/dist/src/commands/tokens.js +21 -3
- package/dist/src/commands/tokens.js.map +1 -1
- package/dist/src/commands/transfer-store.d.ts.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/config-adapter.d.ts.map +1 -1
- package/dist/src/config-adapter.js +37 -17
- package/dist/src/config-adapter.js.map +1 -1
- package/dist/src/consensus/audit-writer.d.ts.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +64 -28
- package/dist/src/index.js.map +1 -1
- package/dist/src/init/claudemd-generator.d.ts.map +1 -1
- package/dist/src/init/claudemd-generator.js +44 -11
- package/dist/src/init/claudemd-generator.js.map +1 -1
- package/dist/src/init/executor.d.ts.map +1 -1
- package/dist/src/init/executor.js +93 -55
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/mcp-generator.js.map +1 -1
- package/dist/src/mcp-client.d.ts +8 -3
- package/dist/src/mcp-client.d.ts.map +1 -1
- package/dist/src/mcp-client.js +37 -3
- package/dist/src/mcp-client.js.map +1 -1
- package/dist/src/mcp-server.d.ts.map +1 -1
- package/dist/src/mcp-server.js +8 -2
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/mcp-tools/agent-tools.d.ts +20 -0
- package/dist/src/mcp-tools/agent-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/agent-tools.js +10 -5
- package/dist/src/mcp-tools/agent-tools.js.map +1 -1
- package/dist/src/mcp-tools/analyze-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/auto-install.d.ts +8 -8
- package/dist/src/mcp-tools/auto-install.d.ts.map +1 -1
- package/dist/src/mcp-tools/auto-install.js.map +1 -1
- package/dist/src/mcp-tools/browser-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/browser-tools.js.map +1 -1
- package/dist/src/mcp-tools/claims-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/coherence/causal-infer.d.ts.map +1 -1
- package/dist/src/mcp-tools/coherence/causal-infer.js.map +1 -1
- package/dist/src/mcp-tools/coherence/coherence-check.d.ts.map +1 -1
- package/dist/src/mcp-tools/coherence/consensus-verify.d.ts.map +1 -1
- package/dist/src/mcp-tools/coherence/memory-gate.d.ts.map +1 -1
- package/dist/src/mcp-tools/coherence/quantum-topology.d.ts.map +1 -1
- package/dist/src/mcp-tools/coherence/spectral-analyze.d.ts.map +1 -1
- package/dist/src/mcp-tools/coherence/spectral-analyze.js.map +1 -1
- package/dist/src/mcp-tools/coherence/types.d.ts +31 -31
- package/dist/src/mcp-tools/embeddings-tools.js.map +1 -1
- package/dist/src/mcp-tools/github-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/github-tools.js +30 -8
- package/dist/src/mcp-tools/github-tools.js.map +1 -1
- package/dist/src/mcp-tools/graphify-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/graphify-tools.js +11 -2
- package/dist/src/mcp-tools/graphify-tools.js.map +1 -1
- package/dist/src/mcp-tools/guidance-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/guidance-tools.js.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.js +56 -35
- package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
- package/dist/src/mcp-tools/hooks-embedding.js.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/knowledge-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/knowledge-tools.js +9 -1
- package/dist/src/mcp-tools/knowledge-tools.js.map +1 -1
- package/dist/src/mcp-tools/monograph-compat.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph-compat.js +56 -14
- package/dist/src/mcp-tools/monograph-compat.js.map +1 -1
- package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph-tools.js +88 -41
- package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
- package/dist/src/mcp-tools/neural-tools.js.map +1 -1
- package/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +36 -36
- package/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts.map +1 -1
- package/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
- package/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts.map +1 -1
- package/dist/src/mcp-tools/security-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/security-tools.js.map +1 -1
- package/dist/src/mcp-tools/swarm-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/swarm-tools.js +6 -4
- package/dist/src/mcp-tools/swarm-tools.js.map +1 -1
- package/dist/src/mcp-tools/system-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/system-tools.js +4 -4
- package/dist/src/mcp-tools/system-tools.js.map +1 -1
- package/dist/src/mcp-tools/transfer-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/types.d.ts +20 -0
- package/dist/src/mcp-tools/types.d.ts.map +1 -1
- package/dist/src/mcp-tools/types.js +36 -1
- package/dist/src/mcp-tools/types.js.map +1 -1
- package/dist/src/memory/ewc-consolidation.d.ts +12 -0
- package/dist/src/memory/ewc-consolidation.d.ts.map +1 -1
- package/dist/src/memory/ewc-consolidation.js.map +1 -1
- package/dist/src/memory/hnsw-operations.d.ts +13 -1
- package/dist/src/memory/hnsw-operations.d.ts.map +1 -1
- package/dist/src/memory/hnsw-operations.js +66 -14
- package/dist/src/memory/hnsw-operations.js.map +1 -1
- package/dist/src/memory/intelligence.d.ts.map +1 -1
- package/dist/src/memory/intelligence.js +99 -3
- package/dist/src/memory/intelligence.js.map +1 -1
- package/dist/src/memory/memory-bridge.d.ts +7 -0
- package/dist/src/memory/memory-bridge.d.ts.map +1 -1
- package/dist/src/memory/memory-bridge.js +20 -0
- package/dist/src/memory/memory-bridge.js.map +1 -1
- package/dist/src/memory/memory-initializer.d.ts.map +1 -1
- package/dist/src/memory/sona-optimizer.d.ts +12 -0
- package/dist/src/memory/sona-optimizer.d.ts.map +1 -1
- package/dist/src/memory/sona-optimizer.js.map +1 -1
- package/dist/src/monovector/coverage-router.js.map +1 -1
- package/dist/src/monovector/coverage-tools.d.ts.map +1 -1
- package/dist/src/monovector/diff-classifier.d.ts.map +1 -1
- package/dist/src/monovector/diff-classifier.js.map +1 -1
- package/dist/src/monovector/init-state.js.map +1 -1
- package/dist/src/observability/replay-reader.d.ts.map +1 -1
- package/dist/src/orgrt/broker.d.ts +26 -0
- package/dist/src/orgrt/broker.d.ts.map +1 -0
- package/dist/src/orgrt/broker.js +73 -0
- package/dist/src/orgrt/broker.js.map +1 -0
- package/dist/src/orgrt/bus.d.ts +5 -1
- package/dist/src/orgrt/bus.d.ts.map +1 -1
- package/dist/src/orgrt/bus.js +5 -1
- package/dist/src/orgrt/bus.js.map +1 -1
- package/dist/src/orgrt/daemon.d.ts +46 -0
- package/dist/src/orgrt/daemon.d.ts.map +1 -1
- package/dist/src/orgrt/daemon.js +201 -18
- package/dist/src/orgrt/daemon.js.map +1 -1
- package/dist/src/orgrt/forwarder.d.ts +10 -5
- package/dist/src/orgrt/forwarder.d.ts.map +1 -1
- package/dist/src/orgrt/forwarder.js +138 -8
- package/dist/src/orgrt/forwarder.js.map +1 -1
- package/dist/src/orgrt/inbox.d.ts +11 -0
- package/dist/src/orgrt/inbox.d.ts.map +1 -0
- package/dist/src/orgrt/inbox.js +56 -0
- package/dist/src/orgrt/inbox.js.map +1 -0
- package/dist/src/orgrt/mailbox.d.ts.map +1 -1
- package/dist/src/orgrt/policy.d.ts +5 -1
- package/dist/src/orgrt/policy.d.ts.map +1 -1
- package/dist/src/orgrt/policy.js +58 -5
- package/dist/src/orgrt/policy.js.map +1 -1
- package/dist/src/orgrt/provider.d.ts.map +1 -1
- package/dist/src/orgrt/provider.js +1 -0
- package/dist/src/orgrt/provider.js.map +1 -1
- package/dist/src/orgrt/scheduler.d.ts +13 -0
- package/dist/src/orgrt/scheduler.d.ts.map +1 -0
- package/dist/src/orgrt/scheduler.js +48 -0
- package/dist/src/orgrt/scheduler.js.map +1 -0
- package/dist/src/orgrt/server.d.ts +9 -0
- package/dist/src/orgrt/server.d.ts.map +1 -0
- package/dist/src/orgrt/server.js +39 -0
- package/dist/src/orgrt/server.js.map +1 -0
- package/dist/src/orgrt/session.d.ts +10 -1
- package/dist/src/orgrt/session.d.ts.map +1 -1
- package/dist/src/orgrt/session.js +24 -1
- package/dist/src/orgrt/session.js.map +1 -1
- package/dist/src/orgrt/test-loop.d.ts +12 -0
- package/dist/src/orgrt/test-loop.d.ts.map +1 -0
- package/dist/src/orgrt/test-loop.js +108 -0
- package/dist/src/orgrt/test-loop.js.map +1 -0
- package/dist/src/orgrt/types.d.ts +52 -52
- package/dist/src/output.d.ts +29 -29
- package/dist/src/output.d.ts.map +1 -1
- package/dist/src/output.js +22 -7
- package/dist/src/output.js.map +1 -1
- package/dist/src/parser.d.ts +32 -0
- package/dist/src/parser.d.ts.map +1 -1
- package/dist/src/parser.js +130 -5
- package/dist/src/parser.js.map +1 -1
- package/dist/src/pricing/model-pricing.d.ts.map +1 -1
- package/dist/src/production/circuit-breaker.d.ts.map +1 -1
- package/dist/src/production/circuit-breaker.js.map +1 -1
- package/dist/src/production/error-handler.d.ts.map +1 -1
- package/dist/src/production/error-handler.js.map +1 -1
- package/dist/src/production/monitoring.d.ts.map +1 -1
- package/dist/src/production/monitoring.js.map +1 -1
- package/dist/src/production/rate-limiter.d.ts.map +1 -1
- package/dist/src/production/rate-limiter.js.map +1 -1
- package/dist/src/production/retry.d.ts.map +1 -1
- package/dist/src/production/retry.js.map +1 -1
- package/dist/src/prompt.d.ts.map +1 -1
- package/dist/src/prompt.js.map +1 -1
- package/dist/src/routing/embed-worker.js +13 -1
- package/dist/src/routing/embed-worker.js.map +1 -1
- package/dist/src/routing/llm-caller.js.map +1 -1
- package/dist/src/routing/route-layer-factory.d.ts.map +1 -1
- package/dist/src/routing/route-layer-factory.js +31 -0
- package/dist/src/routing/route-layer-factory.js.map +1 -1
- package/dist/src/services/config-file-manager.d.ts +21 -0
- package/dist/src/services/config-file-manager.d.ts.map +1 -1
- package/dist/src/services/config-file-manager.js +60 -7
- package/dist/src/services/config-file-manager.js.map +1 -1
- package/dist/src/services/crash-reporter.d.ts.map +1 -1
- package/dist/src/services/crash-reporter.js +2 -1
- package/dist/src/services/crash-reporter.js.map +1 -1
- package/dist/src/suggest.d.ts.map +1 -1
- package/dist/src/suggest.js.map +1 -1
- package/dist/src/transfer/export.js.map +1 -1
- package/dist/src/transfer/ipfs/client.js.map +1 -1
- package/dist/src/transfer/ipfs/upload.js.map +1 -1
- package/dist/src/transfer/models/seraphine.d.ts.map +1 -1
- package/dist/src/transfer/storage/gcs.js.map +1 -1
- package/dist/src/transfer/store/discovery.d.ts.map +1 -1
- package/dist/src/transfer/store/discovery.js.map +1 -1
- package/dist/src/transfer/store/download.d.ts.map +1 -1
- package/dist/src/transfer/store/download.js.map +1 -1
- package/dist/src/transfer/store/index.d.ts.map +1 -1
- package/dist/src/transfer/store/index.js.map +1 -1
- package/dist/src/transfer/store/publish.d.ts.map +1 -1
- package/dist/src/transfer/store/publish.js.map +1 -1
- package/dist/src/transfer/store/search.js.map +1 -1
- package/dist/src/types.d.ts +2 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/ui/dashboard.html +243 -49
- package/dist/src/ui/orgs-files.js +192 -0
- package/dist/src/ui/orgs.html +79 -11
- package/dist/src/ui/server.mjs +346 -139
- package/dist/src/update/checker.js.map +1 -1
- package/dist/src/update/rate-limiter.js.map +1 -1
- package/dist/src/utils/input-guards.d.ts +9 -0
- package/dist/src/utils/input-guards.d.ts.map +1 -1
- package/dist/src/utils/input-guards.js +39 -5
- package/dist/src/utils/input-guards.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -15
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @monomind/guidance package it mirrored has been removed.
|
|
7
7
|
*
|
|
8
8
|
* Gates enforced at runtime:
|
|
9
|
-
* pre-bash → destructive-ops (
|
|
9
|
+
* pre-bash → destructive-ops (hard block; no confirm-and-proceed path exists)
|
|
10
10
|
* pre-write → secrets (block)
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -32,8 +32,13 @@ const SECRET_PATTERNS = [
|
|
|
32
32
|
/(?:api[_-]?key|apikey)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
|
|
33
33
|
/(?:secret|password|passwd|pwd)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
|
|
34
34
|
/(?:token|bearer)\s*[:=]\s*['"][^'"]{10,}['"]/gi,
|
|
35
|
+
// Unquoted variants — env-style KEY equals value with no surrounding
|
|
36
|
+
// quotes (the single most common real leak pattern; the quoted patterns
|
|
37
|
+
// above never match a bare assignment in a shell export or .env file).
|
|
38
|
+
/(?:api[_-]?key|apikey|token|secret|password|passwd|pwd)\s*[:=]\s*[^\s'"]{8,}/gi,
|
|
35
39
|
/-----BEGIN (?:RSA |EC |DSA )?PRIVATE KEY-----/g,
|
|
36
|
-
/sk-[a-zA-Z0-
|
|
40
|
+
/sk-ant-[a-zA-Z0-9_-]{20,}/g,
|
|
41
|
+
/sk-[a-zA-Z0-9_-]{20,}/g,
|
|
37
42
|
/ghp_[a-zA-Z0-9]{36}/g,
|
|
38
43
|
/npm_[a-zA-Z0-9]{36}/g,
|
|
39
44
|
/AKIA[0-9A-Z]{16}/g,
|
|
@@ -55,7 +60,7 @@ function checkDestructive(command) {
|
|
|
55
60
|
return {
|
|
56
61
|
triggered: true,
|
|
57
62
|
matched: match[0],
|
|
58
|
-
reason: `Destructive operation
|
|
63
|
+
reason: `Destructive operation blocked: "${match[0]}". This hook always blocks (Claude Code's PreToolUse protocol has no confirm-and-proceed path) — there is no way to run this exact command after confirming. If it's genuinely intended, use a non-destructive equivalent instead (e.g. move the target aside, or scope the operation more narrowly).`,
|
|
59
64
|
};
|
|
60
65
|
}
|
|
61
66
|
}
|
|
@@ -92,11 +97,14 @@ function handlePreBash(hCtx) {
|
|
|
92
97
|
|
|
93
98
|
var result = checkDestructive(cmd);
|
|
94
99
|
if (result.triggered) {
|
|
95
|
-
//
|
|
96
|
-
|
|
100
|
+
// Set exit code 2 to block, and write the reason to STDERR — per Claude
|
|
101
|
+
// Code's PreToolUse hook protocol, stdout JSON is only parsed when exit
|
|
102
|
+
// code is 0; at exit code 2 the caller reads the block reason from
|
|
103
|
+
// stderr instead, so putting it on stdout here would make it invisible.
|
|
104
|
+
process.stderr.write(JSON.stringify({
|
|
97
105
|
decision: 'block',
|
|
98
106
|
reason: '[gates] ' + result.reason,
|
|
99
|
-
}));
|
|
107
|
+
}) + '\n');
|
|
100
108
|
process.exitCode = 2;
|
|
101
109
|
}
|
|
102
110
|
}
|
|
@@ -120,11 +128,12 @@ function handlePreWrite(hCtx) {
|
|
|
120
128
|
|
|
121
129
|
var result = checkSecrets(content);
|
|
122
130
|
if (result.triggered) {
|
|
123
|
-
//
|
|
124
|
-
|
|
131
|
+
// Set exit code 2 to block, and write the reason to STDERR — see the
|
|
132
|
+
// matching comment in handlePreBash for why stdout is the wrong stream.
|
|
133
|
+
process.stderr.write(JSON.stringify({
|
|
125
134
|
decision: 'block',
|
|
126
135
|
reason: '[gates] ' + result.reason,
|
|
127
|
-
}));
|
|
136
|
+
}) + '\n');
|
|
128
137
|
process.exitCode = 2;
|
|
129
138
|
}
|
|
130
139
|
}
|
|
@@ -10,7 +10,7 @@ module.exports = {
|
|
|
10
10
|
var loopsDir = path.join(CWD, '.monomind', 'loops');
|
|
11
11
|
if (!fs.existsSync(loopsDir)) { console.log('No loops directory.'); return; }
|
|
12
12
|
var files = fs.readdirSync(loopsDir).filter(function(f) {
|
|
13
|
-
return f.endsWith('.json') && !f.includes('-hil') && !f.endsWith('.stop');
|
|
13
|
+
return f.endsWith('.json') && !f.includes('-hil') && !f.endsWith('.stop') && !f.startsWith('._');
|
|
14
14
|
}).slice(0, 200); // cap to prevent DoS via many files
|
|
15
15
|
var STALE_MS = 6 * 60 * 60 * 1000;
|
|
16
16
|
var now = Date.now();
|
|
@@ -299,6 +299,35 @@ module.exports = {
|
|
|
299
299
|
console.log('[CODEBASE] Graph index ' + mapData.graphStaleness.commitsBehind + ' commits behind HEAD — run monograph build');
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
|
+
// Graph gate connectivity nudge — the pre-search/pre-bash gate
|
|
303
|
+
// (utils/monograph.cjs _graphGateShouldBlock) hard-blocks the first
|
|
304
|
+
// Grep/Glob/bash-grep-or-find call each session until a real
|
|
305
|
+
// monograph_query/monograph_suggest call fires. If that block was
|
|
306
|
+
// never followed by a real graph call, the monomind MCP server is
|
|
307
|
+
// most likely not connected this session (config present but
|
|
308
|
+
// unapproved/not started) — surface it once so the user can fix the
|
|
309
|
+
// actual cause instead of the gate silently degrading to a no-op.
|
|
310
|
+
var graphGateFile = path.join(CWD, '.monomind', 'graph-gate-state.json');
|
|
311
|
+
var mcpWarnFile = path.join(CWD, '.monomind', 'mcp-not-connected-warned.json');
|
|
312
|
+
if (fs.existsSync(graphGateFile) && fs.statSync(graphGateFile).size < 4096) {
|
|
313
|
+
var gateState = JSON.parse(fs.readFileSync(graphGateFile, 'utf-8'));
|
|
314
|
+
var gateSessId = String((hCtx.hookInput && (hCtx.hookInput.sessionId || hCtx.hookInput.session_id)) || '');
|
|
315
|
+
if (gateState && gateState.sessionId === gateSessId && gateState.blockedOnce && !gateState.queried) {
|
|
316
|
+
var alreadyWarnedMcp = false;
|
|
317
|
+
if (fs.existsSync(mcpWarnFile)) {
|
|
318
|
+
try {
|
|
319
|
+
var mcpWarnData = JSON.parse(fs.readFileSync(mcpWarnFile, 'utf-8'));
|
|
320
|
+
if (mcpWarnData && mcpWarnData.sessionId === gateSessId) alreadyWarnedMcp = true;
|
|
321
|
+
} catch (e) { /* corrupt — warn again to be safe */ }
|
|
322
|
+
}
|
|
323
|
+
if (!alreadyWarnedMcp) {
|
|
324
|
+
console.log('[MCP] The graph gate blocked a search but no monograph_query/monograph_suggest call followed — the monomind MCP server is likely not connected this session. Run `claude mcp add monomind -- npx monomind@latest mcp start` (then restart), or approve the .mcp.json trust prompt if one is pending.');
|
|
325
|
+
try {
|
|
326
|
+
fs.writeFileSync(mcpWarnFile, JSON.stringify({ sessionId: gateSessId, warnedAt: new Date().toISOString() }));
|
|
327
|
+
} catch (e) { /* non-fatal */ }
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
302
331
|
// Deep dive findings (god nodes, high-degree files from background analysis)
|
|
303
332
|
var deepdiveFile = path.join(metricsDir, 'deepdive.json');
|
|
304
333
|
if (fs.existsSync(deepdiveFile) && fs.statSync(deepdiveFile).size < 32768) {
|
|
@@ -327,15 +356,15 @@ module.exports = {
|
|
|
327
356
|
}
|
|
328
357
|
}
|
|
329
358
|
}
|
|
330
|
-
// Performance metrics (
|
|
359
|
+
// Performance metrics (optimize worker — a one-shot process, not a daemon)
|
|
331
360
|
var perfFile = path.join(metricsDir, 'performance.json');
|
|
332
361
|
if (fs.existsSync(perfFile) && fs.statSync(perfFile).size < 32768) {
|
|
333
362
|
var perfData = JSON.parse(fs.readFileSync(perfFile, 'utf-8'));
|
|
334
|
-
if (perfData && perfData.
|
|
335
|
-
var rssBytes = perfData.
|
|
363
|
+
if (perfData && perfData.workerProcessMemoryUsage) {
|
|
364
|
+
var rssBytes = perfData.workerProcessMemoryUsage.rss || 0;
|
|
336
365
|
var rssMB = Math.round(rssBytes / (1024 * 1024));
|
|
337
366
|
if (rssMB > 512) {
|
|
338
|
-
console.log('[PERF]
|
|
367
|
+
console.log('[PERF] optimize worker RSS ' + rssMB + 'MB (>512MB threshold) at last run — reflects that one-shot process, not a persistent daemon');
|
|
339
368
|
}
|
|
340
369
|
}
|
|
341
370
|
}
|
|
@@ -41,34 +41,46 @@ module.exports = {
|
|
|
41
41
|
if (fs.existsSync(lastRoutePath) && (function() { try { return fs.statSync(lastRoutePath).size <= MAX_ROUTE; } catch(_) { return false; } }())) {
|
|
42
42
|
var lastRoute = JSON.parse(fs.readFileSync(lastRoutePath, 'utf-8'));
|
|
43
43
|
|
|
44
|
-
// Derive sessionSuccess
|
|
44
|
+
// Derive sessionSuccess. A commit alone is not proof of success — a
|
|
45
|
+
// session can commit a partial fix and then hit repeated failures —
|
|
46
|
+
// so recent intelligence-outcomes are checked FIRST and can veto a
|
|
47
|
+
// commit-based "true" when they show a majority of failures.
|
|
45
48
|
try {
|
|
46
49
|
var execSync = require('child_process').execSync;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
|
|
51
|
+
var outcomesSignal = null; // majority success/failure from intelligence-outcomes, if any
|
|
52
|
+
var outcomesPath = path.join(CWD, '.monomind', 'data', 'intelligence-outcomes.jsonl');
|
|
53
|
+
var MAX_OUTCOMES = 512 * 1024;
|
|
54
|
+
if (fs.existsSync(outcomesPath) && (function() { try { return fs.statSync(outcomesPath).size <= MAX_OUTCOMES; } catch(_) { return false; } }())) {
|
|
55
|
+
var windowMs = 30 * 60 * 1000;
|
|
56
|
+
var cutoff = Date.now() - windowMs;
|
|
57
|
+
var outcomeLines = fs.readFileSync(outcomesPath, 'utf-8').trim().split('\n').filter(Boolean);
|
|
58
|
+
var recent = outcomeLines.map(function(l) {
|
|
59
|
+
try { return JSON.parse(l); } catch { return null; }
|
|
60
|
+
}).filter(function(e) { return e && e.ts && e.ts >= cutoff; });
|
|
61
|
+
if (recent.length > 0) {
|
|
62
|
+
var failures = recent.filter(function(e) { return e.success === false; }).length;
|
|
63
|
+
outcomesSignal = failures / recent.length < 0.5;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (outcomesSignal === false) {
|
|
68
|
+
// Recent tool/command outcomes were majority failures — this
|
|
69
|
+
// overrides a commit, since committing doesn't undo those failures.
|
|
70
|
+
sessionSuccess = false;
|
|
50
71
|
} else {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
var
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
var cutoff = Date.now() - windowMs;
|
|
61
|
-
var outcomeLines = fs.readFileSync(outcomesPath, 'utf-8').trim().split('\n').filter(Boolean);
|
|
62
|
-
var recent = outcomeLines.map(function(l) {
|
|
63
|
-
try { return JSON.parse(l); } catch { return null; }
|
|
64
|
-
}).filter(function(e) { return e && e.ts && e.ts >= cutoff; });
|
|
65
|
-
if (recent.length > 0) {
|
|
66
|
-
var failures = recent.filter(function(e) { return e.success === false; }).length;
|
|
67
|
-
sessionSuccess = failures / recent.length < 0.5;
|
|
68
|
-
}
|
|
72
|
+
var recentCommits = execSync('git log --oneline --since="30 minutes ago" 2>/dev/null || true', { cwd: CWD, timeout: 3000, encoding: 'utf-8' }).trim();
|
|
73
|
+
if (recentCommits.length > 0) {
|
|
74
|
+
sessionSuccess = true;
|
|
75
|
+
} else {
|
|
76
|
+
// No commits — check if files were modified (work in progress, not failure)
|
|
77
|
+
var gitStatus = execSync('git diff --name-only 2>/dev/null || true', { cwd: CWD, timeout: 3000, encoding: 'utf-8' }).trim();
|
|
78
|
+
// Modified files = probably still working; no changes at all = exploration or failure
|
|
79
|
+
if (gitStatus.length === 0 && outcomesSignal !== null) {
|
|
80
|
+
sessionSuccess = outcomesSignal;
|
|
69
81
|
}
|
|
82
|
+
// else: modified files exist, or no evidence either way (leave null)
|
|
70
83
|
}
|
|
71
|
-
// else: modified files exist — work in progress, not evidence either way (leave null)
|
|
72
84
|
}
|
|
73
85
|
} catch (e) { /* non-critical — leave null (no evidence) */ }
|
|
74
86
|
|
|
@@ -89,17 +101,48 @@ module.exports = {
|
|
|
89
101
|
// Only write the success flag when derived from actual evidence (commits, outcomes)
|
|
90
102
|
if (typeof sessionSuccess === 'boolean') feedbackEntry.intelligenceFeedback = sessionSuccess;
|
|
91
103
|
fs.appendFileSync(feedbackPath, JSON.stringify(feedbackEntry) + '\n', 'utf-8');
|
|
92
|
-
// Rotate: keep last 1000 lines to prevent unbounded growth
|
|
104
|
+
// Rotate: keep last 1000 lines to prevent unbounded growth.
|
|
93
105
|
try {
|
|
94
106
|
var MAX_FEEDBACK = 512 * 1024; // 512 KiB
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
107
|
+
var feedbackStat = fs.existsSync(feedbackPath) ? fs.statSync(feedbackPath) : null;
|
|
108
|
+
if (feedbackStat && feedbackStat.size > MAX_FEEDBACK) {
|
|
109
|
+
// Emergency tail-trim: the file is too large to comfortably read+split
|
|
110
|
+
// in full, so seek to a byte offset near the end, read only that tail,
|
|
111
|
+
// drop the first (possibly partial) line, and keep the rest — instead
|
|
112
|
+
// of the previous behavior which threw here and skipped trimming
|
|
113
|
+
// entirely, leaving the file to grow forever and permanently disabling
|
|
114
|
+
// consumers (router.cjs, route-handler.cjs) that bail out on oversized
|
|
115
|
+
// files.
|
|
116
|
+
var TAIL_BYTES = 256 * 1024; // ~256 KiB of tail content
|
|
117
|
+
var fd = fs.openSync(feedbackPath, 'r');
|
|
118
|
+
try {
|
|
119
|
+
var readSize = Math.min(TAIL_BYTES, feedbackStat.size);
|
|
120
|
+
var startOffset = feedbackStat.size - readSize;
|
|
121
|
+
var buf = Buffer.alloc(readSize);
|
|
122
|
+
fs.readSync(fd, buf, 0, readSize, startOffset);
|
|
123
|
+
var tailRaw = buf.toString('utf-8');
|
|
124
|
+
var tailLines = tailRaw.split('\n');
|
|
125
|
+
// Drop the first line if we didn't start at byte 0 — it's likely partial.
|
|
126
|
+
if (startOffset > 0) tailLines.shift();
|
|
127
|
+
var validTailLines = tailLines.filter(function(l) {
|
|
128
|
+
if (!l) return false;
|
|
129
|
+
try { JSON.parse(l); return true; } catch (eParse) { return false; }
|
|
130
|
+
});
|
|
131
|
+
var trimmedTail = validTailLines.slice(-1000);
|
|
132
|
+
var tmpFeedbackPath = feedbackPath + '.' + process.pid + '.tmp';
|
|
133
|
+
fs.writeFileSync(tmpFeedbackPath, trimmedTail.join('\n') + (trimmedTail.length > 0 ? '\n' : ''), 'utf-8');
|
|
134
|
+
fs.renameSync(tmpFeedbackPath, feedbackPath);
|
|
135
|
+
} finally {
|
|
136
|
+
fs.closeSync(fd);
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
var raw = fs.readFileSync(feedbackPath, 'utf-8');
|
|
140
|
+
var lines = raw.split('\n').filter(Boolean);
|
|
141
|
+
if (lines.length > 1000) {
|
|
142
|
+
var tmpFeedbackPath2 = feedbackPath + '.' + process.pid + '.tmp';
|
|
143
|
+
fs.writeFileSync(tmpFeedbackPath2, lines.slice(-1000).join('\n') + '\n', 'utf-8');
|
|
144
|
+
fs.renameSync(tmpFeedbackPath2, feedbackPath);
|
|
145
|
+
}
|
|
103
146
|
}
|
|
104
147
|
} catch (e2) { /* rotation is best-effort */ }
|
|
105
148
|
}
|
|
@@ -141,19 +184,6 @@ module.exports = {
|
|
|
141
184
|
|
|
142
185
|
// Memory Palace tombstone writes removed — redundant with raw session JSONL
|
|
143
186
|
|
|
144
|
-
// ── Context Persistence Auto-Archive ─────────────────────────────────
|
|
145
|
-
// Archive conversation context so it survives compaction and new sessions
|
|
146
|
-
try {
|
|
147
|
-
var cpHook = await import('file://' + path.join(__dirname, '..', 'context-persistence-hook.mjs'));
|
|
148
|
-
if (cpHook && cpHook.archive) {
|
|
149
|
-
await hCtx.runWithTimeout(function() { return cpHook.archive(); }, 'context-persistence.archive()');
|
|
150
|
-
console.log('[CONTEXT_PERSIST] Session transcript archived');
|
|
151
|
-
} else if (cpHook && cpHook.default && cpHook.default.archive) {
|
|
152
|
-
await hCtx.runWithTimeout(function() { return cpHook.default.archive(); }, 'context-persistence.archive()');
|
|
153
|
-
console.log('[CONTEXT_PERSIST] Session transcript archived');
|
|
154
|
-
}
|
|
155
|
-
} catch (e) { /* non-fatal — context-persistence may not export archive() */ }
|
|
156
|
-
|
|
157
187
|
// ── Auto-populate: write session episode for every session ─────
|
|
158
188
|
// Even solo sessions (no subagents) produce an episode so the
|
|
159
189
|
// route handler can surface relevant past sessions.
|
|
@@ -206,18 +206,6 @@ module.exports = {
|
|
|
206
206
|
}
|
|
207
207
|
} catch (e) { /* non-fatal — hooks workers unavailable */ }
|
|
208
208
|
|
|
209
|
-
// Context Persistence Auto-Restore
|
|
210
|
-
try {
|
|
211
|
-
var cpHook = await import('file://' + path.join(helpersDir, 'context-persistence-hook.mjs'));
|
|
212
|
-
var restoreFn = (cpHook && cpHook.restore) || (cpHook && cpHook.default && cpHook.default.restore);
|
|
213
|
-
if (restoreFn) {
|
|
214
|
-
var restored = await runWithTimeout(function() { return restoreFn(); }, 'context-persistence.restore()');
|
|
215
|
-
if (restored && restored.turns > 0) {
|
|
216
|
-
console.log('[CONTEXT_RESTORED] ' + restored.turns + ' turns from previous session');
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
} catch (e) { /* non-fatal */ }
|
|
220
|
-
|
|
221
209
|
// AgentKnowledgeBase — preload shared knowledge context on session restore.
|
|
222
210
|
try {
|
|
223
211
|
var knowledgeDir = path.join(CWD, '.monomind', 'knowledge');
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const fs = require('fs');
|
|
8
|
+
const { purgeStaleRegistrations } = require('../utils/agent-registrations.cjs');
|
|
9
|
+
const { atomicWriteFileSync, withLock } = require('../utils/fs-helpers.cjs');
|
|
8
10
|
|
|
9
11
|
module.exports = {
|
|
10
12
|
handlePreTask: async function(hCtx) {
|
|
@@ -50,36 +52,65 @@ module.exports = {
|
|
|
50
52
|
intelligence.feedback(taskSuccess);
|
|
51
53
|
} catch (e) { /* non-fatal */ }
|
|
52
54
|
}
|
|
53
|
-
// Each TeammateIdle/TaskCompleted = one agent done → remove
|
|
55
|
+
// Each TeammateIdle/TaskCompleted = one agent done → remove its registration.
|
|
54
56
|
const regDir = path.join(CWD, '.monomind', 'agents', 'registrations');
|
|
55
57
|
try {
|
|
56
58
|
if (fs.existsSync(regDir)) {
|
|
57
59
|
const files = fs.readdirSync(regDir).filter(f => f.endsWith('.json'));
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
// P3-15: post-task (TeammateIdle/TaskCompleted) also fires for the MAIN
|
|
61
|
+
// session's own tasks — e.g. the team lead completing a self-assigned
|
|
62
|
+
// TaskList item — which never wrote an agent-start registration in the
|
|
63
|
+
// first place. Blindly popping the oldest registration on EVERY
|
|
64
|
+
// post-task event therefore deregistered an unrelated, still-running
|
|
65
|
+
// agent whenever the lead (not a subagent) finished a task, silently
|
|
66
|
+
// drifting the count negative-equivalent (undercounting active agents).
|
|
67
|
+
//
|
|
68
|
+
// Registrations now carry an `agentType` (agent-start-handler.cjs), and
|
|
69
|
+
// this hook's payload may carry the same identifying field under one of
|
|
70
|
+
// several possible names — mirroring the precedence agent-start-handler
|
|
71
|
+
// already uses to derive it. If this event carries NO such field at
|
|
72
|
+
// all, there's no evidence it corresponds to a real agent completion
|
|
73
|
+
// (as opposed to the main session's own task), so we skip touching
|
|
74
|
+
// registrations entirely rather than guessing via FIFO. When the field
|
|
75
|
+
// IS present, prefer removing the registration recorded with the SAME
|
|
76
|
+
// type; fall back to oldest-of-all only if no type match is found
|
|
77
|
+
// (e.g. a legacy registration written before this fix, with no
|
|
78
|
+
// agentType stored).
|
|
79
|
+
const completingType = hookInput.subagent_type || hookInput.agentType || hookInput.agent_type
|
|
80
|
+
|| hookInput.agentSlug || hookInput.agent_slug || '';
|
|
81
|
+
if (files.length > 0 && completingType) {
|
|
60
82
|
const sorted = files
|
|
61
|
-
.map(f =>
|
|
83
|
+
.map(f => {
|
|
84
|
+
let mtime = 0, agentType = null;
|
|
85
|
+
try { mtime = fs.statSync(path.join(regDir, f)).mtimeMs; } catch { /* ignore */ }
|
|
86
|
+
try { agentType = JSON.parse(fs.readFileSync(path.join(regDir, f), 'utf-8')).agentType || null; } catch { /* ignore */ }
|
|
87
|
+
return { f, mtime, agentType };
|
|
88
|
+
})
|
|
62
89
|
.sort((a, b) => a.mtime - b.mtime);
|
|
63
|
-
|
|
90
|
+
const typeMatch = sorted.find(r => r.agentType === completingType);
|
|
91
|
+
const toRemove = typeMatch || sorted[0];
|
|
92
|
+
try { fs.unlinkSync(path.join(regDir, toRemove.f)); } catch { /* ignore */ }
|
|
64
93
|
}
|
|
65
|
-
// Also purge any stragglers older than 30 min
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
94
|
+
// Also purge any stragglers older than 30 min (shared with agent-start-handler.cjs)
|
|
95
|
+
const remaining = purgeStaleRegistrations(regDir) || 0;
|
|
96
|
+
// P2-21: shares a lock with agent-start-handler.cjs's swarm-activity.json
|
|
97
|
+
// writer (same path + '.lock') so the read-prevLastActive-then-write
|
|
98
|
+
// cycle can't race with that handler's concurrent write and silently
|
|
99
|
+
// drop whichever one wrote last — see that file for full rationale.
|
|
71
100
|
const _actPath = path.join(CWD, '.monomind', 'metrics', 'swarm-activity.json');
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
101
|
+
withLock(_actPath + '.lock', function() {
|
|
102
|
+
let _prevLastActive = 0;
|
|
103
|
+
try { var _actSt = fs.statSync(_actPath); if (_actSt.size < 65536) { _prevLastActive = (JSON.parse(fs.readFileSync(_actPath, 'utf-8'))?.swarm?.lastActive) || 0; } } catch { /* ignore */ }
|
|
104
|
+
atomicWriteFileSync(_actPath, JSON.stringify({
|
|
105
|
+
timestamp: new Date().toISOString(),
|
|
106
|
+
swarm: {
|
|
107
|
+
active: remaining > 0,
|
|
108
|
+
agent_count: remaining,
|
|
109
|
+
coordination_active: remaining > 0,
|
|
110
|
+
lastActive: Math.max(remaining, _prevLastActive), // preserve peak across completion
|
|
111
|
+
},
|
|
112
|
+
}));
|
|
113
|
+
}, 5000);
|
|
83
114
|
}
|
|
84
115
|
} catch (e) { /* non-fatal */ }
|
|
85
116
|
|
|
@@ -55,6 +55,7 @@ const {
|
|
|
55
55
|
getMonographSuggestions, getMonographNeighbors,
|
|
56
56
|
_recordGraphTelemetry, _injectCompactGraphMap,
|
|
57
57
|
_findAffectedTests, _maybeRebuildMonograph,
|
|
58
|
+
_graphGateShouldBlock, _graphGateMarkQueried,
|
|
58
59
|
} = monograph;
|
|
59
60
|
|
|
60
61
|
const {
|
|
@@ -136,9 +137,49 @@ async function _ensureHooksModule() {
|
|
|
136
137
|
_hooksModule = null; // not built — bridge stays a fail-soft no-op
|
|
137
138
|
}
|
|
138
139
|
}
|
|
140
|
+
if (!_hooksModule) _warnHooksBridgeUnavailable();
|
|
139
141
|
return _hooksModule;
|
|
140
142
|
}
|
|
141
143
|
|
|
144
|
+
// ── Visible one-time warning when the @monomind/hooks bridge fully fails ───
|
|
145
|
+
// Both load paths above (bare specifier + dev-repo file:// fallback) failed:
|
|
146
|
+
// the 15 background workers (metrics, security scan, DDD tracking, etc.) are
|
|
147
|
+
// unavailable for the rest of this session. This is almost always because
|
|
148
|
+
// @monomind/hooks was never resolvable from npm (it ships with
|
|
149
|
+
// optionalDependencies:"*", which npm silently skips) — NOT a problem with
|
|
150
|
+
// the user's own project setup. Historically this failed completely
|
|
151
|
+
// silently (see docs/AUDIT-BACKLOG.md P1-1), burning debugging time on the
|
|
152
|
+
// wrong target. Warned once per session (file-marker keyed by session id,
|
|
153
|
+
// same pattern as the once-per-day update check below) since every hook
|
|
154
|
+
// event is its own fresh `node` process and would otherwise spam this on
|
|
155
|
+
// every single tool call.
|
|
156
|
+
function _warnHooksBridgeUnavailable() {
|
|
157
|
+
try {
|
|
158
|
+
var sessId = String((hookInput && (hookInput.sessionId || hookInput.session_id)) || '');
|
|
159
|
+
var flagFile = path.join(CWD, '.monomind', 'hooks-bridge-warned.json');
|
|
160
|
+
var alreadyWarned = false;
|
|
161
|
+
if (sessId && fs.existsSync(flagFile)) {
|
|
162
|
+
try {
|
|
163
|
+
var flagData = JSON.parse(fs.readFileSync(flagFile, 'utf-8'));
|
|
164
|
+
if (flagData && flagData.sessionId === sessId) alreadyWarned = true;
|
|
165
|
+
} catch (e) { /* corrupt/unreadable flag file — warn again to be safe */ }
|
|
166
|
+
}
|
|
167
|
+
if (alreadyWarned) return;
|
|
168
|
+
process.stderr.write(
|
|
169
|
+
'[WARN] @monomind/hooks could not be loaded (bare specifier and dev-repo fallback both failed) — ' +
|
|
170
|
+
'background workers (metrics, security scan, DDD tracking, etc.) are unavailable this session. ' +
|
|
171
|
+
'This is not a problem with your project configuration — the package is not resolvable via npm ' +
|
|
172
|
+
'from this install. See docs/AUDIT-BACKLOG.md P1-1 or https://github.com/monoes/monomind/issues.\n'
|
|
173
|
+
);
|
|
174
|
+
if (sessId) {
|
|
175
|
+
try {
|
|
176
|
+
fs.mkdirSync(path.join(CWD, '.monomind'), { recursive: true });
|
|
177
|
+
fs.writeFileSync(flagFile, JSON.stringify({ sessionId: sessId, warnedAt: new Date().toISOString() }), 'utf-8');
|
|
178
|
+
} catch (e) { /* non-fatal — worst case we warn again next event */ }
|
|
179
|
+
}
|
|
180
|
+
} catch (e) { /* never let the warning itself break a hook event */ }
|
|
181
|
+
}
|
|
182
|
+
|
|
142
183
|
// ── Intelligence timeout protection (fixes #1530, #1531) ───────────────────
|
|
143
184
|
var INTELLIGENCE_TIMEOUT_MS = 1500;
|
|
144
185
|
function runWithTimeout(fn, label) {
|
|
@@ -351,11 +392,33 @@ const handlers = {
|
|
|
351
392
|
h.handle(hCtx);
|
|
352
393
|
},
|
|
353
394
|
|
|
354
|
-
'pre-bash': () => {
|
|
395
|
+
'pre-bash': async () => {
|
|
396
|
+
// SECURITY GATE FIRST — destructive-ops enforcement must never be
|
|
397
|
+
// starved by the slower enrichment work below (monograph hint lookups).
|
|
398
|
+
// Previously this ran LAST, after up to 10 monograph SQLite strategies,
|
|
399
|
+
// AND was fired without awaiting its promise — meaning the block
|
|
400
|
+
// decision (process.exitCode) could still be unset when the process
|
|
401
|
+
// exited under the global 5s safety timer (see main()'s
|
|
402
|
+
// `process.exit(0)`), i.e. the gate could fail OPEN under time
|
|
403
|
+
// pressure. Awaiting it first guarantees the block/allow decision is
|
|
404
|
+
// computed and set before any enrichment work even starts.
|
|
405
|
+
var gates = require('./handlers/gates-handler.cjs');
|
|
406
|
+
await gates.handlePreBash(hCtx);
|
|
407
|
+
if (process.exitCode === 2) return; // blocked — skip enrichment entirely
|
|
408
|
+
|
|
355
409
|
var cmd = (hCtx.toolInput && (hCtx.toolInput.command || hCtx.toolInput.cmd)) || '';
|
|
356
410
|
var isGrep = /\b(?:grep|rg|ag)\b/.test(cmd);
|
|
357
411
|
var isFind = /\b(?:find|fd)\b/.test(cmd) && !isGrep;
|
|
358
412
|
if (isGrep || isFind) {
|
|
413
|
+
var sessIdGate = String((hCtx.hookInput && (hCtx.hookInput.sessionId || hCtx.hookInput.session_id)) || '');
|
|
414
|
+
if (_graphGateShouldBlock(sessIdGate)) {
|
|
415
|
+
process.stderr.write(JSON.stringify({
|
|
416
|
+
decision: 'block',
|
|
417
|
+
reason: '[graph-gate] Call mcp__monomind__monograph_query or monograph_suggest before grep/rg/find for code exploration (CLAUDE.md). This blocks once per session — after your first monograph call (or this one warning), Bash grep/find work normally for the rest of the session.',
|
|
418
|
+
}) + '\n');
|
|
419
|
+
process.exitCode = 2;
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
359
422
|
var graphAssisted = false;
|
|
360
423
|
if (_isGraphFresh()) {
|
|
361
424
|
try {
|
|
@@ -596,9 +659,6 @@ const handlers = {
|
|
|
596
659
|
else if (isGrep) _recordGraphTelemetry('bash_grep_call');
|
|
597
660
|
else _recordGraphTelemetry('bash_find_call');
|
|
598
661
|
}
|
|
599
|
-
// Enforcement gate: destructive operations
|
|
600
|
-
var gates = require('./handlers/gates-handler.cjs');
|
|
601
|
-
gates.handlePreBash(hCtx);
|
|
602
662
|
},
|
|
603
663
|
|
|
604
664
|
'pre-write': () => {
|
|
@@ -609,6 +669,15 @@ const handlers = {
|
|
|
609
669
|
|
|
610
670
|
'pre-search': () => {
|
|
611
671
|
var tool = hCtx.toolName || '';
|
|
672
|
+
var sessIdGate = String((hCtx.hookInput && (hCtx.hookInput.sessionId || hCtx.hookInput.session_id)) || '');
|
|
673
|
+
if (_graphGateShouldBlock(sessIdGate)) {
|
|
674
|
+
process.stderr.write(JSON.stringify({
|
|
675
|
+
decision: 'block',
|
|
676
|
+
reason: '[graph-gate] Call mcp__monomind__monograph_query or monograph_suggest before ' + (tool || 'Grep/Glob') + ' for code exploration (CLAUDE.md). This blocks once per session — after your first monograph call (or this one warning), search tools work normally for the rest of the session.',
|
|
677
|
+
}) + '\n');
|
|
678
|
+
process.exitCode = 2;
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
612
681
|
var graphResolved = false;
|
|
613
682
|
try {
|
|
614
683
|
var grepPattern = (typeof toolInput === 'object' && toolInput !== null)
|
|
@@ -767,6 +836,8 @@ const handlers = {
|
|
|
767
836
|
'post-graph-tool': () => {
|
|
768
837
|
// Record monograph MCP tool calls as graph wins
|
|
769
838
|
_recordGraphTelemetry('monograph_call');
|
|
839
|
+
var sessIdGate = String((hCtx.hookInput && (hCtx.hookInput.sessionId || hCtx.hookInput.session_id)) || '');
|
|
840
|
+
_graphGateMarkQueried(sessIdGate);
|
|
770
841
|
},
|
|
771
842
|
|
|
772
843
|
'graph-status': () => {
|