thumbgate 1.3.0 → 1.4.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 (146) hide show
  1. package/.claude-plugin/marketplace.json +32 -13
  2. package/.claude-plugin/plugin.json +15 -2
  3. package/.well-known/llms.txt +60 -0
  4. package/.well-known/mcp/server-card.json +1 -1
  5. package/README.md +109 -20
  6. package/adapters/README.md +1 -1
  7. package/adapters/chatgpt/openapi.yaml +168 -0
  8. package/adapters/claude/.mcp.json +2 -2
  9. package/adapters/codex/config.toml +2 -2
  10. package/adapters/mcp/server-stdio.js +84 -1
  11. package/adapters/opencode/opencode.json +1 -1
  12. package/bin/cli.js +200 -13
  13. package/bin/postinstall.js +8 -2
  14. package/config/budget.json +18 -0
  15. package/config/gates/code-edit.json +61 -0
  16. package/config/gates/db-write.json +61 -0
  17. package/config/gates/default.json +154 -3
  18. package/config/gates/deploy.json +61 -0
  19. package/config/github-about.json +2 -1
  20. package/config/merge-quality-checks.json +23 -0
  21. package/openapi/openapi.yaml +168 -0
  22. package/package.json +42 -10
  23. package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +1 -1
  24. package/plugins/claude-codex-bridge/.mcp.json +1 -1
  25. package/plugins/claude-codex-bridge/scripts/codex-bridge.js +1 -3
  26. package/plugins/codex-profile/.codex-plugin/plugin.json +1 -1
  27. package/plugins/codex-profile/.mcp.json +1 -1
  28. package/plugins/codex-profile/INSTALL.md +27 -4
  29. package/plugins/codex-profile/README.md +33 -9
  30. package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +1 -1
  31. package/plugins/opencode-profile/INSTALL.md +1 -1
  32. package/public/blog.html +73 -0
  33. package/public/compare/mem0.html +189 -0
  34. package/public/compare/speclock.html +180 -0
  35. package/public/compare.html +10 -2
  36. package/public/guide.html +2 -2
  37. package/public/guides/claude-code-prevent-repeated-mistakes.html +161 -0
  38. package/public/guides/codex-cli-guardrails.html +158 -0
  39. package/public/guides/cursor-prevent-repeated-mistakes.html +161 -0
  40. package/public/guides/pre-action-gates.html +162 -0
  41. package/public/guides/stop-repeated-ai-agent-mistakes.html +159 -0
  42. package/public/index.html +136 -50
  43. package/public/lessons.html +33 -24
  44. package/public/llm-context.md +140 -0
  45. package/public/pro.html +24 -22
  46. package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
  47. package/scripts/access-anomaly-detector.js +1 -1
  48. package/scripts/adk-consolidator.js +1 -5
  49. package/scripts/agent-security-hardening.js +4 -6
  50. package/scripts/agentic-data-pipeline.js +1 -3
  51. package/scripts/async-job-runner.js +1 -5
  52. package/scripts/audit-trail.js +1 -5
  53. package/scripts/background-agent-governance.js +2 -10
  54. package/scripts/billing.js +2 -16
  55. package/scripts/budget-enforcer.js +173 -0
  56. package/scripts/build-codex-plugin.js +152 -0
  57. package/scripts/check-congruence.js +132 -14
  58. package/scripts/commercial-offer.js +5 -7
  59. package/scripts/content-engine/linkedin-content-generator.js +154 -0
  60. package/scripts/content-engine/output/linkedin-memento-validation.md +17 -0
  61. package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +175 -0
  62. package/scripts/content-engine/reddit-thread-finder.js +154 -0
  63. package/scripts/context-engine.js +21 -6
  64. package/scripts/contextfs.js +1 -21
  65. package/scripts/dashboard.js +20 -0
  66. package/scripts/decision-journal.js +341 -0
  67. package/scripts/delegation-runtime.js +1 -5
  68. package/scripts/distribution-surfaces.js +26 -0
  69. package/scripts/document-intake.js +927 -0
  70. package/scripts/ephemeral-agent-store.js +1 -8
  71. package/scripts/evolution-state.js +1 -5
  72. package/scripts/experiment-tracker.js +1 -5
  73. package/scripts/export-databricks-bundle.js +1 -5
  74. package/scripts/export-hf-dataset.js +1 -5
  75. package/scripts/export-training.js +1 -5
  76. package/scripts/feedback-attribution.js +1 -16
  77. package/scripts/feedback-history-distiller.js +1 -16
  78. package/scripts/feedback-loop.js +1 -5
  79. package/scripts/feedback-root-consolidator.js +2 -21
  80. package/scripts/feedback-session.js +49 -0
  81. package/scripts/feedback-to-rules.js +188 -28
  82. package/scripts/filesystem-search.js +1 -9
  83. package/scripts/fs-utils.js +104 -0
  84. package/scripts/gates-engine.js +149 -4
  85. package/scripts/github-about.js +32 -8
  86. package/scripts/gtm-revenue-loop.js +1 -5
  87. package/scripts/harness-selector.js +148 -0
  88. package/scripts/hosted-job-launcher.js +1 -5
  89. package/scripts/hybrid-feedback-context.js +7 -33
  90. package/scripts/intervention-policy.js +58 -1
  91. package/scripts/lesson-db.js +3 -18
  92. package/scripts/lesson-inference.js +194 -16
  93. package/scripts/lesson-retrieval.js +60 -24
  94. package/scripts/llm-client.js +59 -0
  95. package/scripts/managed-lesson-agent.js +183 -0
  96. package/scripts/marketing-experiment.js +8 -22
  97. package/scripts/meta-agent-loop.js +624 -0
  98. package/scripts/metered-billing.js +1 -1
  99. package/scripts/money-watcher.js +1 -4
  100. package/scripts/obsidian-export.js +1 -5
  101. package/scripts/operational-integrity.js +15 -3
  102. package/scripts/org-dashboard.js +6 -1
  103. package/scripts/per-step-scoring.js +2 -4
  104. package/scripts/pr-manager.js +201 -19
  105. package/scripts/pro-features.js +3 -2
  106. package/scripts/prompt-dlp.js +3 -3
  107. package/scripts/prove-adapters.js +1 -5
  108. package/scripts/prove-attribution.js +1 -5
  109. package/scripts/prove-automation.js +1 -3
  110. package/scripts/prove-cloudflare-sandbox.js +1 -3
  111. package/scripts/prove-data-pipeline.js +1 -3
  112. package/scripts/prove-intelligence.js +1 -3
  113. package/scripts/prove-lancedb.js +1 -5
  114. package/scripts/prove-local-intelligence.js +1 -3
  115. package/scripts/prove-packaged-runtime.js +75 -9
  116. package/scripts/prove-predictive-insights.js +1 -3
  117. package/scripts/prove-training-export.js +1 -3
  118. package/scripts/prove-workflow-contract.js +1 -5
  119. package/scripts/rate-limiter.js +3 -1
  120. package/scripts/reddit-dm-outreach.js +14 -4
  121. package/scripts/schedule-manager.js +3 -5
  122. package/scripts/security-scanner.js +448 -0
  123. package/scripts/self-distill-agent.js +579 -0
  124. package/scripts/semantic-dedup.js +115 -0
  125. package/scripts/skill-exporter.js +1 -3
  126. package/scripts/skill-generator.js +1 -5
  127. package/scripts/social-analytics/engagement-audit.js +1 -18
  128. package/scripts/social-analytics/pollers/linkedin.js +26 -16
  129. package/scripts/social-analytics/publishers/linkedin.js +1 -1
  130. package/scripts/social-analytics/publishers/zernio.js +51 -0
  131. package/scripts/social-pipeline.js +1 -3
  132. package/scripts/social-post-hourly.js +47 -4
  133. package/scripts/statusline-links.js +6 -5
  134. package/scripts/statusline.sh +29 -153
  135. package/scripts/sync-branch-protection.js +340 -0
  136. package/scripts/tessl-export.js +1 -3
  137. package/scripts/thumbgate-search.js +32 -1
  138. package/scripts/tool-kpi-tracker.js +1 -1
  139. package/scripts/tool-registry.js +106 -2
  140. package/scripts/vector-store.js +1 -5
  141. package/scripts/weekly-auto-post.js +1 -1
  142. package/scripts/workflow-sentinel.js +91 -0
  143. package/skills/thumbgate/SKILL.md +1 -1
  144. package/src/api/server.js +273 -4
  145. package/scripts/social-analytics/db/social-analytics.db-shm +0 -0
  146. /package/scripts/social-analytics/db/{social-analytics.db-wal → analytics.sqlite} +0 -0
@@ -0,0 +1,175 @@
1
+ # LinkedIn Content: ThumbGate Gates (2026-04-09)
2
+
3
+ Generated from: `config/gates/default.json`
4
+ Gate count in config: 25
5
+ Posts generated: 7
6
+
7
+ ---
8
+
9
+ ## Post 1: Local Only Git Writes
10
+
11
+ 🚨 Your AI agents are running without guardrails.
12
+
13
+ Blocks git writes when local-only mode is active, preventing accidental remote pushes during development.
14
+
15
+ The problem? AI agents run autonomously. A single unchecked operation—a force-push, an unapproved deploy, a dependency injection—can unwind days of work in seconds. Traditional CI won't catch it. Your human reviewer might miss it.
16
+
17
+ The solution? **Gate `local-only-git-writes`** in ThumbGate stops high-risk operations *before* they execute. No second chances. Just prevention.
18
+
19
+ This isn't about slowing down. It's about building trust in autonomous systems. Every gate is a rule learned from real failures.
20
+
21
+ 🔒 Install ThumbGate today:
22
+ ```bash
23
+ npx thumbgate@latest init
24
+ ```
25
+
26
+ Then add this gate to your config and sleep better.
27
+
28
+ #AIGovernance #DevTools #AgentSafety #EngineeringTeams
29
+
30
+ ---
31
+
32
+
33
+ ## Post 2: Gh Pr Create Restricted
34
+
35
+ ⚠️ One missing gate. One catastrophic mistake.
36
+
37
+ Restricts PR creation to explicitly approved workflows, preventing unvetted code changes.
38
+
39
+ The problem? AI agents run autonomously. A single unchecked operation—a force-push, an unapproved deploy, a dependency injection—can unwind days of work in seconds. Traditional CI won't catch it. Your human reviewer might miss it.
40
+
41
+ The solution? **Gate `gh-pr-create-restricted`** in ThumbGate stops high-risk operations *before* they execute. No second chances. Just prevention.
42
+
43
+ This isn't about slowing down. It's about building trust in autonomous systems. Every gate is a rule learned from real failures.
44
+
45
+ 🔒 Install ThumbGate today:
46
+ ```bash
47
+ npx thumbgate@latest init
48
+ ```
49
+
50
+ Then add this gate to your config and sleep better.
51
+
52
+ #AIGovernance #DevTools #AgentSafety #EngineeringTeams
53
+
54
+ ---
55
+
56
+
57
+ ## Post 3: Env File Edit
58
+
59
+ 🛡️ Even the best engineers miss edge cases.
60
+
61
+ Warns when editing .env files—catches accidental token deletion.
62
+
63
+ The problem? AI agents run autonomously. A single unchecked operation—a force-push, an unapproved deploy, a dependency injection—can unwind days of work in seconds. Traditional CI won't catch it. Your human reviewer might miss it.
64
+
65
+ The solution? **Gate `env-file-edit`** in ThumbGate stops high-risk operations *before* they execute. No second chances. Just prevention.
66
+
67
+ This isn't about slowing down. It's about building trust in autonomous systems. Every gate is a rule learned from real failures.
68
+
69
+ 🔒 Install ThumbGate today:
70
+ ```bash
71
+ npx thumbgate@latest init
72
+ ```
73
+
74
+ Then add this gate to your config and sleep better.
75
+
76
+ #AIGovernance #DevTools #AgentSafety #EngineeringTeams
77
+
78
+ ---
79
+
80
+
81
+ ## Post 4: Style Violation Log
82
+
83
+ 💥 Your deployment pipeline has a blind spot.
84
+
85
+ Protects your workflow by style audit mode active. action recorded for review but allowed to proceed.
86
+
87
+ The problem? AI agents run autonomously. A single unchecked operation—a force-push, an unapproved deploy, a dependency injection—can unwind days of work in seconds. Traditional CI won't catch it. Your human reviewer might miss it.
88
+
89
+ The solution? **Gate `style-violation-log`** in ThumbGate stops high-risk operations *before* they execute. No second chances. Just prevention.
90
+
91
+ This isn't about slowing down. It's about building trust in autonomous systems. Every gate is a rule learned from real failures.
92
+
93
+ 🔒 Install ThumbGate today:
94
+ ```bash
95
+ npx thumbgate@latest init
96
+ ```
97
+
98
+ Then add this gate to your config and sleep better.
99
+
100
+ #AIGovernance #DevTools #AgentSafety #EngineeringTeams
101
+
102
+ ---
103
+
104
+
105
+ ## Post 5: Loop Abuse Prevention
106
+
107
+ 🔓 Git operations—unguarded by default.
108
+
109
+ Protects your workflow by high-risk command detected inside a loop. scheduled tasks must not perform egress or destructive writes without explicit approval.
110
+
111
+ The problem? AI agents run autonomously. A single unchecked operation—a force-push, an unapproved deploy, a dependency injection—can unwind days of work in seconds. Traditional CI won't catch it. Your human reviewer might miss it.
112
+
113
+ The solution? **Gate `loop-abuse-prevention`** in ThumbGate stops high-risk operations *before* they execute. No second chances. Just prevention.
114
+
115
+ This isn't about slowing down. It's about building trust in autonomous systems. Every gate is a rule learned from real failures.
116
+
117
+ 🔒 Install ThumbGate today:
118
+ ```bash
119
+ npx thumbgate@latest init
120
+ ```
121
+
122
+ Then add this gate to your config and sleep better.
123
+
124
+ #AIGovernance #DevTools #AgentSafety #EngineeringTeams
125
+
126
+ ---
127
+
128
+
129
+ ## Post 6: Release Readiness Required
130
+
131
+ 🎯 Prevention beats firefighting.
132
+
133
+ Ensures releases only happen from releasable mainline commits with version alignment.
134
+
135
+ The problem? AI agents run autonomously. A single unchecked operation—a force-push, an unapproved deploy, a dependency injection—can unwind days of work in seconds. Traditional CI won't catch it. Your human reviewer might miss it.
136
+
137
+ The solution? **Gate `release-readiness-required`** in ThumbGate stops high-risk operations *before* they execute. No second chances. Just prevention.
138
+
139
+ This isn't about slowing down. It's about building trust in autonomous systems. Every gate is a rule learned from real failures.
140
+
141
+ 🔒 Install ThumbGate today:
142
+ ```bash
143
+ npx thumbgate@latest init
144
+ ```
145
+
146
+ Then add this gate to your config and sleep better.
147
+
148
+ #AIGovernance #DevTools #AgentSafety #EngineeringTeams
149
+
150
+ ---
151
+
152
+
153
+ ## Post 7: Protected Branch Push
154
+
155
+ ⏱️ How fast can your agent destroy a month of work?
156
+
157
+ Prevents direct pushes to main/develop. All changes flow through PR review.
158
+
159
+ The problem? AI agents run autonomously. A single unchecked operation—a force-push, an unapproved deploy, a dependency injection—can unwind days of work in seconds. Traditional CI won't catch it. Your human reviewer might miss it.
160
+
161
+ The solution? **Gate `protected-branch-push`** in ThumbGate stops high-risk operations *before* they execute. No second chances. Just prevention.
162
+
163
+ This isn't about slowing down. It's about building trust in autonomous systems. Every gate is a rule learned from real failures.
164
+
165
+ 🔒 Install ThumbGate today:
166
+ ```bash
167
+ npx thumbgate@latest init
168
+ ```
169
+
170
+ Then add this gate to your config and sleep better.
171
+
172
+ #AIGovernance #DevTools #AgentSafety #EngineeringTeams
173
+
174
+ ---
175
+
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Reddit Thread Finder for ThumbGate Engagement
4
+ *
5
+ * Add to package.json:
6
+ * "content:reddit": "node scripts/content-engine/reddit-thread-finder.js"
7
+ * "content:reddit:dry": "node scripts/content-engine/reddit-thread-finder.js --dry-run"
8
+ * "content:reddit:limit": "node scripts/content-engine/reddit-thread-finder.js --limit 20"
9
+ */
10
+
11
+ const https = require('https');
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ const SUBREDDITS = [
16
+ 'ChatGPTCoding', 'ClaudeAI', 'cursor', 'devops',
17
+ 'SoftwareEngineering', 'ExperiencedDevs', 'MachineLearning', 'LocalLLaMA'
18
+ ];
19
+
20
+ const KEYWORDS = [
21
+ 'agent broke', 'agent deleted', 'force push', 'prevent AI from',
22
+ 'guardrails', 'agent governance', 'coding agent mistakes'
23
+ ];
24
+
25
+ const USER_AGENT = 'script:thumbgate-content:v1.0';
26
+ const DELAY = 2000; // ms between requests
27
+ const DEFAULT_LIMIT = 10;
28
+
29
+ let dryRun = false;
30
+ let outputLimit = DEFAULT_LIMIT;
31
+
32
+ process.argv.slice(2).forEach(arg => {
33
+ if (arg === '--dry-run') dryRun = true;
34
+ if (arg.startsWith('--limit')) outputLimit = parseInt(arg.split('=')[1] || arg.split(' ')[1], 10);
35
+ });
36
+
37
+ function fetchReddit(url) {
38
+ return new Promise((resolve, reject) => {
39
+ const req = https.get(url, { headers: { 'User-Agent': USER_AGENT } }, res => {
40
+ let data = '';
41
+ res.on('data', chunk => data += chunk);
42
+ res.on('end', () => {
43
+ try {
44
+ resolve(JSON.parse(data));
45
+ } catch (e) {
46
+ reject(e);
47
+ }
48
+ });
49
+ });
50
+ req.on('error', reject);
51
+ });
52
+ }
53
+
54
+ async function searchSubreddit(sub, keyword) {
55
+ const url = `https://www.reddit.com/r/${sub}/search.json?q=${encodeURIComponent(keyword)}&sort=new&t=week&limit=5`;
56
+ try {
57
+ const data = await fetchReddit(url);
58
+ return (data.data?.children || []).map(post => ({
59
+ id: post.data.id,
60
+ title: post.data.title,
61
+ url: `https://reddit.com${post.data.permalink}`,
62
+ subreddit: post.data.subreddit,
63
+ score: post.data.score,
64
+ numComments: post.data.num_comments,
65
+ created: post.data.created_utc,
66
+ selftext: post.data.selftext
67
+ }));
68
+ } catch (err) {
69
+ console.error(`Error searching ${sub} for "${keyword}": ${err.message}`);
70
+ return [];
71
+ }
72
+ }
73
+
74
+ function scoreThread(thread) {
75
+ const now = Math.floor(Date.now() / 1000);
76
+ const ageHours = (now - thread.created) / 3600;
77
+ const recencyScore = Math.max(0, 1 - ageHours / 168); // 0-1 over a week
78
+ const upvoteScore = Math.log(Math.max(1, thread.score)) / Math.log(100);
79
+ const commentScore = Math.log(Math.max(1, thread.numComments)) / Math.log(100);
80
+
81
+ return (recencyScore * 0.5) + (upvoteScore * 0.3) + (commentScore * 0.2);
82
+ }
83
+
84
+ function generateReply(thread) {
85
+ const context = thread.selftext.substring(0, 200);
86
+ return `
87
+ **ThumbGate can help prevent this.** Our pre-action gates catch agent mistakes before they happen:
88
+ - Stop force pushes on protected branches
89
+ - Prevent deletions of critical files
90
+ - Verify AI actions before execution
91
+ - Capture lessons from failures to block similar mistakes
92
+
93
+ Learn more: https://thumbgate-production.up.railway.app/dashboard
94
+ `;
95
+ }
96
+
97
+ async function main() {
98
+ console.log(`[${new Date().toISOString()}] Starting Reddit thread finder...`);
99
+
100
+ const threads = {};
101
+ let requestCount = 0;
102
+
103
+ for (const sub of SUBREDDITS) {
104
+ for (const keyword of KEYWORDS) {
105
+ if (requestCount > 0) await new Promise(r => setTimeout(r, DELAY));
106
+
107
+ console.log(` Searching r/${sub} for "${keyword}"...`);
108
+ const results = await searchSubreddit(sub, keyword);
109
+
110
+ results.forEach(thread => {
111
+ if (!threads[thread.id]) {
112
+ threads[thread.id] = thread;
113
+ }
114
+ });
115
+ requestCount++;
116
+ }
117
+ }
118
+
119
+ const sorted = Object.values(threads)
120
+ .sort((a, b) => scoreThread(b) - scoreThread(a))
121
+ .slice(0, outputLimit);
122
+
123
+ const date = new Date().toISOString().split('T')[0];
124
+ const outputDir = path.join(__dirname, 'output');
125
+
126
+ if (!fs.existsSync(outputDir)) {
127
+ fs.mkdirSync(outputDir, { recursive: true });
128
+ }
129
+
130
+ let markdown = `# Reddit Threads - ${date}\n\nFound ${sorted.length} high-relevance threads.\n\n`;
131
+
132
+ sorted.forEach((thread, idx) => {
133
+ const score = scoreThread(thread);
134
+ markdown += `## ${idx + 1}. ${thread.title}\n`;
135
+ markdown += `**r/${thread.subreddit}** | [Link](${thread.url}) | Score: ${thread.score} | Comments: ${thread.numComments}\n`;
136
+ markdown += `**Relevance Score:** ${score.toFixed(2)}\n\n`;
137
+
138
+ if (!dryRun) {
139
+ markdown += `**Suggested Reply:**\n${generateReply(thread)}\n\n`;
140
+ }
141
+ markdown += '---\n\n';
142
+ });
143
+
144
+ const outputFile = path.join(outputDir, `reddit-threads-${date}.md`);
145
+ fs.writeFileSync(outputFile, markdown);
146
+
147
+ console.log(`\n✅ Generated ${sorted.length} threads to ${outputFile}`);
148
+ if (dryRun) console.log(' (--dry-run: no reply suggestions included)');
149
+ }
150
+
151
+ main().catch(err => {
152
+ console.error('❌ Fatal error:', err.message);
153
+ process.exit(1);
154
+ });
@@ -20,6 +20,7 @@ const fs = require('fs');
20
20
  const path = require('path');
21
21
  const crypto = require('crypto');
22
22
  const { constructContextPack } = require('./contextfs');
23
+ const { ensureDir } = require('./fs-utils');
23
24
 
24
25
  // ---------------------------------------------------------------------------
25
26
  // Default paths
@@ -75,11 +76,6 @@ const TOOL_CONSOLIDATION = {
75
76
  // Utility: ensure directory exists
76
77
  // ---------------------------------------------------------------------------
77
78
 
78
- function ensureDir(dirPath) {
79
- if (!fs.existsSync(dirPath)) {
80
- fs.mkdirSync(dirPath, { recursive: true });
81
- }
82
- }
83
79
 
84
80
  // ---------------------------------------------------------------------------
85
81
  // Knowledge Bundle Builder
@@ -649,10 +645,29 @@ function compactContext(entries, anchors, opts) {
649
645
  return true;
650
646
  });
651
647
 
648
+ // Stage 6: Global token budget — drop entries (oldest first) until total chars fit
649
+ let finalStage = 5;
650
+ const totalMaxChars = typeof options.totalMaxChars === 'number' ? options.totalMaxChars : null;
651
+ if (totalMaxChars !== null) {
652
+ let budget = totalMaxChars;
653
+ const budgeted = [];
654
+ // Iterate newest-first so most recent entries are preserved
655
+ for (let i = working.length - 1; i >= 0; i--) {
656
+ const entrySize = JSON.stringify(working[i]).length;
657
+ if (budget - entrySize < 0) break;
658
+ budget -= entrySize;
659
+ budgeted.unshift(working[i]);
660
+ }
661
+ if (budgeted.length < working.length) {
662
+ working = budgeted;
663
+ finalStage = 6;
664
+ }
665
+ }
666
+
652
667
  const removedCount = initial - working.length;
653
668
  return {
654
669
  entries: [...anchorEntries, ...working],
655
- stage: 5,
670
+ stage: finalStage,
656
671
  removedCount,
657
672
  compacted: removedCount > 0,
658
673
  };
@@ -12,6 +12,7 @@ const fs = require('fs');
12
12
  const path = require('path');
13
13
  const crypto = require('crypto');
14
14
  const { resolveFeedbackDir } = require('./feedback-paths');
15
+ const { ensureDir, readJsonl } = require('./fs-utils');
15
16
  const {
16
17
  retrieveHierarchicalDocuments,
17
18
  shouldUseHierarchicalRetrieval,
@@ -99,11 +100,6 @@ const PACK_TEMPLATES = {
99
100
  },
100
101
  };
101
102
 
102
- function ensureDir(dirPath) {
103
- if (!fs.existsSync(dirPath)) {
104
- fs.mkdirSync(dirPath, { recursive: true });
105
- }
106
- }
107
103
 
108
104
  function ensureContextFs() {
109
105
  Object.values(NAMESPACES).forEach((subPath) => {
@@ -140,22 +136,6 @@ function appendJsonl(filePath, payload) {
140
136
  fs.appendFileSync(filePath, `${JSON.stringify(payload)}\n`);
141
137
  }
142
138
 
143
- function readJsonl(filePath) {
144
- if (!fs.existsSync(filePath)) return [];
145
- const raw = fs.readFileSync(filePath, 'utf-8').trim();
146
- if (!raw) return [];
147
- return raw
148
- .split('\n')
149
- .map((line) => {
150
- try {
151
- return JSON.parse(line);
152
- } catch {
153
- return null;
154
- }
155
- })
156
- .filter(Boolean);
157
- }
158
-
159
139
  function listJsonFiles(dirPath) {
160
140
  if (!fs.existsSync(dirPath)) return [];
161
141
  const files = fs.readdirSync(dirPath, { withFileTypes: true });
@@ -21,6 +21,7 @@ const { getSettingsStatus } = require('./settings-hierarchy');
21
21
  const { summarizeWorkflowRuns } = require('./workflow-runs');
22
22
  const { searchLessons } = require('./lesson-search');
23
23
  const { getInterventionPolicySummary } = require('./intervention-policy');
24
+ const { computeDecisionMetrics } = require('./decision-journal');
24
25
 
25
26
  const PROJECT_ROOT = path.join(__dirname, '..');
26
27
  const DEFAULT_GATES_PATH = path.join(PROJECT_ROOT, 'config', 'gates', 'default.json');
@@ -787,6 +788,7 @@ function generateDashboard(feedbackDir, options = {}) {
787
788
  const readiness = generateAgentReadinessReport({ projectRoot: PROJECT_ROOT });
788
789
  const harness = computeHarnessOverview(feedbackDir, entries);
789
790
  const interventionPolicy = getInterventionPolicySummary(feedbackDir);
791
+ const decisions = computeDecisionMetrics(feedbackDir);
790
792
  const settingsStatus = getSettingsStatus({ projectRoot: PROJECT_ROOT });
791
793
  settingsStatus.routingPreview = {
792
794
  dashboardTool: routeProfile({
@@ -820,6 +822,13 @@ function generateDashboard(feedbackDir, options = {}) {
820
822
  lessonEffectiveness: { rate: totalNeg > 0 ? Math.round((autoGates / totalNeg) * 10000) / 100 : 0, totalNegative: totalNeg, autoGatesCreated: autoGates },
821
823
  errorTrend: { direction: lastWeekNeg > 0 ? (negRecent.length < lastWeekNeg ? 'improving' : negRecent.length > lastWeekNeg ? 'worsening' : 'stable') : (negRecent.length > 0 ? 'new-errors' : 'clean'), thisWeek: negRecent.length, lastWeek: lastWeekNeg },
822
824
  weeklyActivity: { positive: posRecent.length, negative: negRecent.length, total: recentEntries.length },
825
+ decisionLoop: {
826
+ fastPathRate: decisions.fastPathRate,
827
+ overrideRate: decisions.overrideRate,
828
+ rollbackRate: decisions.rollbackRate,
829
+ medianLatencyMs: decisions.medianLatencyMs,
830
+ resolvedCount: decisions.resolvedCount,
831
+ },
823
832
  };
824
833
 
825
834
  const team = generateOrgDashboard({
@@ -857,6 +866,7 @@ function generateDashboard(feedbackDir, options = {}) {
857
866
  instrumentation,
858
867
  readiness,
859
868
  interventionPolicy,
869
+ decisions,
860
870
  settingsStatus,
861
871
  team,
862
872
  templateLibrary,
@@ -886,6 +896,7 @@ function printDashboard(data) {
886
896
  instrumentation,
887
897
  readiness,
888
898
  interventionPolicy,
899
+ decisions,
889
900
  settingsStatus,
890
901
  team,
891
902
  templateLibrary,
@@ -945,6 +956,14 @@ function printDashboard(data) {
945
956
  console.log(` Top Deny Signal : ${interventionPolicy.topTokens.deny[0].token}`);
946
957
  }
947
958
 
959
+ console.log('');
960
+ console.log('🧭 Decision Loop');
961
+ console.log(` Evaluations : ${decisions.evaluationCount}`);
962
+ console.log(` Fast Path : ${Math.round((decisions.fastPathRate || 0) * 100)}%`);
963
+ console.log(` Override Rate : ${Math.round((decisions.overrideRate || 0) * 100)}%`);
964
+ console.log(` Rollback Rate : ${Math.round((decisions.rollbackRate || 0) * 100)}%`);
965
+ console.log(` Median Latency : ${Math.round((decisions.medianLatencyMs || 0) / 1000)}s`);
966
+
948
967
  console.log('');
949
968
  console.log('🎯 North Star');
950
969
  console.log(` Weekly Proof Runs: ${analytics.northStar.weeklyActiveProofBackedWorkflowRuns}`);
@@ -1120,6 +1139,7 @@ module.exports = {
1120
1139
  generateDashboard,
1121
1140
  printDashboard,
1122
1141
  computeApprovalStats,
1142
+ computeDecisionMetrics,
1123
1143
  computeGateStats,
1124
1144
  computePreventionImpact,
1125
1145
  computeSessionTrend,