thumbgate 1.37.1 → 1.37.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.
Files changed (47) hide show
  1. package/.agents/skills/article-syndication-pipeline/SKILL.md +37 -0
  2. package/.agents/skills/ci-gha-buildkite-patterns-not-clone/SKILL.md +72 -0
  3. package/.agents/skills/cobble-hot-store-compare-not-clone/SKILL.md +80 -0
  4. package/.agents/skills/colab-compute-honesty-not-clone/SKILL.md +70 -0
  5. package/.agents/skills/comet-session-logger/SKILL.md +59 -0
  6. package/.agents/skills/datadog-llm-obs-compare-not-clone/SKILL.md +75 -0
  7. package/.agents/skills/deeppattern-discipline-honesty-not-clone/SKILL.md +73 -0
  8. package/.agents/skills/thumbgate-board-loop/SKILL.md +72 -0
  9. package/.agents/skills/thumbgate-daily-discoveries/SKILL.md +57 -0
  10. package/.agents/skills/token-shunt-honesty-not-clone/SKILL.md +67 -0
  11. package/.agents/skills/typesafe-typed-questions-not-clone/SKILL.md +86 -0
  12. package/.claude-plugin/plugin.json +1 -1
  13. package/.well-known/mcp/server-card.json +1 -1
  14. package/adapters/claude/.mcp.json +2 -2
  15. package/adapters/forge/forge.yaml +3 -3
  16. package/adapters/future-agi/.mcp.json +1 -1
  17. package/adapters/future-agi/config.toml +1 -1
  18. package/adapters/future-agi/opencode.json +1 -1
  19. package/adapters/herdr/herdr-plugin.toml +2 -2
  20. package/adapters/mcp/server-stdio.js +1 -1
  21. package/adapters/opencode/opencode.json +1 -1
  22. package/bin/cli.js +257 -0
  23. package/config/gate-templates.json +96 -0
  24. package/package.json +55 -12
  25. package/public/blog/2026-09-23-datadog-llm-obs-four-practices.html +42 -0
  26. package/public/index.html +2 -2
  27. package/public/install.html +7 -7
  28. package/public/numbers.html +2 -2
  29. package/scripts/ci-gha-buildkite-patterns.js +393 -0
  30. package/scripts/cli-schema.js +90 -0
  31. package/scripts/cobble-hot-store-split.js +600 -0
  32. package/scripts/colab-compute-honesty.js +281 -0
  33. package/scripts/deeppattern-discipline-honesty.js +431 -0
  34. package/scripts/gates-engine.js +16 -5
  35. package/scripts/install-thumbgate-daily-publish-launchd.sh +83 -0
  36. package/scripts/llm-obs-honesty.js +478 -0
  37. package/scripts/thumbgate-board-loop.js +432 -0
  38. package/scripts/thumbgate-daily-discoveries-publish.js +413 -0
  39. package/scripts/thumbgate-daily-discoveries-publish.sh +18 -0
  40. package/scripts/token-shunt-honesty.js +502 -0
  41. package/scripts/typesafe-typed-questions.js +1138 -0
  42. package/server.json +2 -2
  43. package/skills/article-syndication-pipeline/SKILL.md +37 -0
  44. package/skills/comet-session-logger/SKILL.md +59 -0
  45. package/skills/thumbgate-daily-discoveries/SKILL.md +57 -0
  46. package/src/index.js +10 -0
  47. package/src/integrations/ideabrowser-connector.js +190 -0
package/server.json CHANGED
@@ -8,13 +8,13 @@
8
8
  "source": "github",
9
9
  "url": "https://github.com/IgorGanapolsky/ThumbGate"
10
10
  },
11
- "version": "1.37.1",
11
+ "version": "1.37.3",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "npm",
15
15
  "registryBaseUrl": "https://registry.npmjs.org",
16
16
  "identifier": "thumbgate",
17
- "version": "1.37.1",
17
+ "version": "1.37.3",
18
18
  "runtimeHint": "npx",
19
19
  "runtimeArguments": [
20
20
  {
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: article-syndication-pipeline
3
+ description: Technical article syndication pipeline for cross-posting Dev.to articles to CoderLegion and other developer platforms with canonical URL preservation, UTM parameter attribution, and contributor onboarding compliance.
4
+ ---
5
+
6
+ # ✍️ Article Syndication & Contributor Pipeline
7
+
8
+ This skill guides the autonomous syndication of ThumbGate technical discoveries, security postmortems, and engineering deep dives across developer platforms (Dev.to, CoderLegion, Hashnode, Medium).
9
+
10
+ ---
11
+
12
+ ## 🎯 Architecture & Operating Directives
13
+
14
+ 1. **Canonical SEO Integrity:**
15
+ - Always preserve the primary origin as the canonical URL (e.g. `https://dev.to/igorganapolsky/...`).
16
+ - Syndicated copies on CoderLegion or elsewhere must link back to avoid search engine duplicate-content penalties.
17
+ 2. **First-Party Revenue Attribution:**
18
+ - All inbound links to `thumbgate.ai` must include UTM campaign tags (`utm_source=coderlegion`, `utm_medium=community`, `utm_campaign=guest-post`).
19
+ - Conversion links (Pro license checkout) must route through `/go/pro` (`https://thumbgate.ai/go/pro?utm_source=...`) to ensure server-side redirect logging.
20
+ 3. **CoderLegion Contributor Compliance:**
21
+ - URL import endpoint: `https://coderlegion.com/import-post`.
22
+ - Supports 2 imported Dev.to articles with full attribution.
23
+ - Contributor checklist: `https://coderlegion.com/guest-blog-checklists`.
24
+ - All imported posts undergo editorial review before appearing on the main feed.
25
+
26
+ ---
27
+
28
+ ## 🛠️ Step-by-Step Workflow
29
+
30
+ 1. **Verify Original Article:**
31
+ Verify original URL exists, returns HTTP 200, and has correct canonical tags.
32
+ 2. **Fetch via Platform Parser:**
33
+ Submit `import_url` to `https://coderlegion.com/import-post`.
34
+ 3. **Review & Confirm Metadata:**
35
+ Confirm title, tags (`ai`, `security`, `architecture`, `opensource`), and backlink to canonical source.
36
+ 4. **Publish & Track:**
37
+ Submit publication step and record post URL in session log and Comet browser tab.
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: comet-session-logger
3
+ description: Live session logger and observability dashboard driver for Comet browser. Ensures every PR, deployment status check, CoderLegion/Dev.to publication, and Railway production health metric is actively logged and visualized in Comet tabs.
4
+ ---
5
+
6
+ # ☄️ Comet Session Logger & Visual HUD
7
+
8
+ This skill governs the automated logging, tab orchestration, and visual tracking of all ThumbGate agentic tasks inside the **Comet** browser on macOS.
9
+
10
+ ---
11
+
12
+ ## 🎯 Purpose & Directives
13
+
14
+ 1. **CEO Visual Observability:** The CEO monitors agent progress via open tabs in Comet. Every major milestone must be reflected in Comet tabs without disrupting existing work.
15
+ 2. **Deterministic Tab Management:** Uses macOS AppleScript (`osascript`) to inspect, activate, create, or update Comet tabs.
16
+ 3. **Fail-Safe & Non-Destructive:** Never closes existing tabs; always reuses matching URLs or opens clean dedicated monitoring tabs.
17
+
18
+ ---
19
+
20
+ ## 🧭 Standard Tab Targets
21
+
22
+ | Surface | Target URL | Trigger Milestone |
23
+ |---------|------------|-------------------|
24
+ | **Pull Requests** | `https://github.com/IgorGanapolsky/ThumbGate/pull/<NUM>` | After creating or advancing a PR |
25
+ | **CI / Checks** | `https://github.com/IgorGanapolsky/ThumbGate/actions` | During workflow verification |
26
+ | **Production Health** | `https://thumbgate-production.up.railway.app/health` | After deployment gate verification |
27
+ | **Railway Console** | `https://railway.com/project/thumbgate-production` | When inspecting infrastructure |
28
+ | **CoderLegion** | `https://coderlegion.com/import-post` | When onboarding or syndicating articles |
29
+ | **Dev.to Dashboard** | `https://dev.to/dashboard` | When tracking article reach & analytics |
30
+
31
+ ---
32
+
33
+ ## 🛠️ AppleScript Orchestration Helpers
34
+
35
+ ```bash
36
+ # Check existing Comet tabs
37
+ osascript -e '
38
+ tell application "Comet"
39
+ set outList to ""
40
+ repeat with w in windows
41
+ repeat with t in tabs of w
42
+ set outList to outList & (URL of t) & " | " & (title of t) & linefeed
43
+ end repeat
44
+ end repeat
45
+ return outList
46
+ end tell'
47
+
48
+ # Open or focus a specific URL in Comet
49
+ open_comet_url() {
50
+ local target_url="$1"
51
+ osascript -e "
52
+ tell application \"Comet\"
53
+ activate
54
+ tell front window
55
+ make new tab with properties {URL:\"${target_url}\"}
56
+ end tell
57
+ end tell"
58
+ }
59
+ ```
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: thumbgate-daily-discoveries
3
+ description: Autonomous daily publishing engine and monitoring skill for ThumbGate news and technical discoveries. Generates high-density engineering posts with full UTM attribution, synchronizes to Obsidian, schedules dual cron/launchd runs at 9:00 AM EST, and tracks publication ledgers.
4
+ ---
5
+
6
+ # 📰 ThumbGate Daily Technical Discoveries & News Engine
7
+
8
+ This skill automates the daily harvesting, synthesis, UTM attribution, and multi-channel publication of ThumbGate engineering discoveries and release news.
9
+
10
+ ---
11
+
12
+ ## 🎯 Architecture & Operating Principles
13
+
14
+ 1. **Daily Cadence (9:00 AM EST):** Runs once per calendar day. Avoids spam while establishing consistent technical authority.
15
+ 2. **Dual Scheduling Redundancy:**
16
+ - Primary: macOS crontab (`0 9 * * * /bin/bash scripts/thumbgate-daily-discoveries-publish.sh ...`)
17
+ - Fallback: macOS LaunchAgent (`~/Library/LaunchAgents/com.thumbgate.daily-publish.plist`)
18
+ - Note: GitHub Actions `schedule:` is strictly limited to `codeql.yml` per repo hygiene tests.
19
+ 3. **Full UTM Attribution & Tracked Redirects:**
20
+ - All outbound links to `thumbgate.ai` must use `buildUTMLink` from `scripts/social-analytics/utm.js`.
21
+ - Outbound pro/checkout links must route through `/go/pro` (`serveTrackedLinkRedirect` in `src/api/server.js`) to capture first-party funnel telemetry.
22
+ 4. **Multi-Surface Staging & Sync:**
23
+ - Staged locally at `docs/marketing/daily-discoveries/YYYY-MM-DD-<slug>.md`.
24
+ - Synchronized to the CEO's Obsidian Vault at `~/Documents/Igor/Research/Daily-Discoveries/`.
25
+ - Logged idempotently to `.thumbgate/daily-discoveries-ledger.jsonl`.
26
+ - Dispatches to Dev.to / Zernio if API keys are configured.
27
+
28
+ ---
29
+
30
+ ## 🛠️ CLI Commands & Usage
31
+
32
+ ```bash
33
+ # Preview today's technical discovery without making mutations or network calls
34
+ node scripts/thumbgate-daily-discoveries-publish.js --dry-run
35
+
36
+ # Output structured JSON report
37
+ node scripts/thumbgate-daily-discoveries-publish.js --json
38
+
39
+ # Force publish/restage today's discovery even if already logged in ledger
40
+ node scripts/thumbgate-daily-discoveries-publish.js --force
41
+
42
+ # Shell wrapper (used by crontab / launchd)
43
+ ./scripts/thumbgate-daily-discoveries-publish.sh
44
+
45
+ # Run test suite
46
+ node --test tests/thumbgate-daily-discoveries-publish.test.js
47
+ ```
48
+
49
+ ---
50
+
51
+ ## 📋 Pre-Flight Verification Checklist
52
+
53
+ - [ ] Verify `node --test tests/thumbgate-daily-discoveries-publish.test.js` passes.
54
+ - [ ] Verify outbound links contain valid UTM parameters (`utm_source=daily_discoveries`, `utm_campaign=daily_technical_discoveries`).
55
+ - [ ] Verify `launchctl list | grep thumbgate` reports exit code 0.
56
+ - [ ] Verify `crontab -l | grep thumbgate` contains the 9:00 AM daily trigger.
57
+ - [ ] Check `.thumbgate/daily-discoveries-ledger.jsonl` for recent execution receipts.
package/src/index.js CHANGED
@@ -12,6 +12,12 @@ const {
12
12
  isNamedIdentity,
13
13
  } = require('./hermes-platform-protocol');
14
14
  const { HermesSyncPlane } = require('./hermes-sync-plane');
15
+ const {
16
+ IdeaBrowserConnector,
17
+ ToolTier,
18
+ DEFAULT_READ_ONLY_TOOLS,
19
+ DEFAULT_MUTATING_TOOLS,
20
+ } = require('./integrations/ideabrowser-connector');
15
21
 
16
22
  // The package entry point is the production surface for `thumbgate`.
17
23
  // The hosted-Hermes identity/lifecycle/approval gates are exported here so
@@ -29,4 +35,8 @@ module.exports = Object.assign({}, feedbackLoop, {
29
35
  THREAD_MODES,
30
36
  FORBIDDEN_IDENTITIES,
31
37
  isNamedIdentity,
38
+ IdeaBrowserConnector,
39
+ ToolTier,
40
+ DEFAULT_READ_ONLY_TOOLS,
41
+ DEFAULT_MUTATING_TOOLS,
32
42
  });
@@ -0,0 +1,190 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * ideabrowser-connector.js — IdeaBrowser Agent Connector & Governance Diode.
5
+ *
6
+ * Implements a hardened IdeaBrowser connector for ThumbGate without credential
7
+ * leakage, classifying all actions into read-only or mutating tiers. Closes #3823.
8
+ *
9
+ * Security & Governance Invariants:
10
+ * 1. Zero Plaintext Credentials:
11
+ * - Connector tokens/secrets must never be stored in tracked repository files.
12
+ * - Resolve credentials via authenticated environment variables (IDEABROWSER_API_KEY)
13
+ * or macOS Keychain lookup.
14
+ * 2. Strict Tool Classification:
15
+ * - read-only: Information gathering, DOM inspection, status query, screenshot, URL retrieval. Allowed by default.
16
+ * - mutating: Form submission, button click, file upload, state mutation, purchasing, external navigation.
17
+ * - Fail-Closed on Provider Drift: Unknown tools default immediately to mutating.
18
+ * 3. Pre-Action Interdiction:
19
+ * - Emits an interdiction event before executing any mutating tool.
20
+ * - Hard-blocks unauthorized mutating operations when fail-closed mode is set.
21
+ */
22
+
23
+ const { EventEmitter } = require('node:events');
24
+ const { redactSecrets, redactSecretsDeep } = require('../../scripts/secret-redaction');
25
+
26
+ const ToolTier = Object.freeze({
27
+ READ_ONLY: 'read-only',
28
+ MUTATING: 'mutating',
29
+ });
30
+
31
+ const DEFAULT_READ_ONLY_TOOLS = new Set([
32
+ 'get_page_content',
33
+ 'get_dom_tree',
34
+ 'get_url',
35
+ 'inspect_element',
36
+ 'take_screenshot',
37
+ 'get_status',
38
+ 'search_page',
39
+ 'list_tabs',
40
+ 'read_console_logs',
41
+ ]);
42
+
43
+ const DEFAULT_MUTATING_TOOLS = new Set([
44
+ 'click_element',
45
+ 'fill_form',
46
+ 'submit_form',
47
+ 'navigate_url',
48
+ 'upload_file',
49
+ 'execute_script',
50
+ 'purchase_item',
51
+ 'close_tab',
52
+ 'press_key',
53
+ ]);
54
+
55
+ class IdeaBrowserConnector extends EventEmitter {
56
+ constructor(options = {}) {
57
+ super();
58
+ this.apiKey = options.apiKey || process.env.IDEABROWSER_API_KEY || null;
59
+ this.baseUrl = options.baseUrl || 'https://api.ideabrowser.com/v1';
60
+ this.failClosed = options.failClosed !== false;
61
+ this.allowedDomains = Array.isArray(options.allowedDomains)
62
+ ? new Set(options.allowedDomains)
63
+ : null;
64
+ this.toolRegistry = new Map();
65
+
66
+ // Seed default known tools
67
+ for (const tool of DEFAULT_READ_ONLY_TOOLS) {
68
+ this.toolRegistry.set(tool, {
69
+ tier: ToolTier.READ_ONLY,
70
+ handler: options.handlers?.[tool] || (async (params) => ({ tool, params, status: 'ok' })),
71
+ });
72
+ }
73
+
74
+ for (const tool of DEFAULT_MUTATING_TOOLS) {
75
+ this.toolRegistry.set(tool, {
76
+ tier: ToolTier.MUTATING,
77
+ handler: options.handlers?.[tool] || (async (params) => ({ tool, params, status: 'ok' })),
78
+ });
79
+ }
80
+ }
81
+
82
+ getCredentials() {
83
+ if (this.apiKey) {
84
+ return {
85
+ hasKey: true,
86
+ source: 'env_or_options',
87
+ maskedKey: redactSecrets(this.apiKey),
88
+ };
89
+ }
90
+ return {
91
+ hasKey: false,
92
+ source: 'none',
93
+ maskedKey: null,
94
+ };
95
+ }
96
+
97
+ registerTool(name, handler, tier = ToolTier.MUTATING) {
98
+ if (!name || typeof name !== 'string') {
99
+ throw new Error('Tool name must be a non-empty string.');
100
+ }
101
+ if (typeof handler !== 'function') {
102
+ throw new Error('Tool handler must be a function.');
103
+ }
104
+ const resolvedTier = tier === ToolTier.READ_ONLY ? ToolTier.READ_ONLY : ToolTier.MUTATING;
105
+ this.toolRegistry.set(name, { handler, tier: resolvedTier });
106
+ }
107
+
108
+ classifyTool(name) {
109
+ const entry = this.toolRegistry.get(name);
110
+ if (entry) {
111
+ return entry.tier;
112
+ }
113
+ // Fail closed on drift: Unknown tools are classified as mutating
114
+ return this.failClosed ? ToolTier.MUTATING : ToolTier.READ_ONLY;
115
+ }
116
+
117
+ isAllowedDomain(urlOrDomain) {
118
+ if (!this.allowedDomains) {
119
+ return true;
120
+ }
121
+ if (this.allowedDomains.size === 0) return false;
122
+ if (!urlOrDomain) return false;
123
+ try {
124
+ const parsed = urlOrDomain.startsWith('http')
125
+ ? new URL(urlOrDomain)
126
+ : new URL(`https://${urlOrDomain}`);
127
+ return this.allowedDomains.has(parsed.hostname);
128
+ } catch {
129
+ return this.allowedDomains.has(urlOrDomain);
130
+ }
131
+ }
132
+
133
+ async executeTool(name, params = {}, context = {}) {
134
+ const tier = this.classifyTool(name);
135
+ const entry = this.toolRegistry.get(name);
136
+
137
+ if (tier === ToolTier.MUTATING) {
138
+ const targetUrl = params.url || params.target || context.url;
139
+ if (targetUrl && !this.isAllowedDomain(targetUrl)) {
140
+ let domainOnly = targetUrl;
141
+ try {
142
+ const parsed = targetUrl.startsWith('http')
143
+ ? new URL(targetUrl)
144
+ : new URL(`https://${targetUrl}`);
145
+ domainOnly = parsed.origin;
146
+ } catch {
147
+ domainOnly = redactSecrets(targetUrl);
148
+ }
149
+ const error = new Error(`Domain not allowed for mutating tool "${name}": ${domainOnly}`);
150
+ error.code = 'DOMAIN_INTERDICTED';
151
+ this.emit('interdict', {
152
+ name,
153
+ params: redactSecretsDeep(params),
154
+ context: redactSecretsDeep(context),
155
+ reason: redactSecrets(error.message),
156
+ });
157
+ if (this.failClosed) {
158
+ throw error;
159
+ }
160
+ }
161
+
162
+ this.emit('interdict', {
163
+ name,
164
+ params: redactSecretsDeep(params),
165
+ context: redactSecretsDeep(context),
166
+ });
167
+
168
+ if (context.blocked === true) {
169
+ if (this.failClosed) {
170
+ const error = new Error(`Execution of mutating tool "${name}" blocked by pre-action gate.`);
171
+ error.code = 'GATE_INTERDICTED';
172
+ throw error;
173
+ }
174
+ }
175
+ }
176
+
177
+ if (!entry) {
178
+ throw new Error(`IdeaBrowser tool "${name}" not found.`);
179
+ }
180
+
181
+ return await entry.handler(params);
182
+ }
183
+ }
184
+
185
+ module.exports = {
186
+ ToolTier,
187
+ IdeaBrowserConnector,
188
+ DEFAULT_READ_ONLY_TOOLS,
189
+ DEFAULT_MUTATING_TOOLS,
190
+ };