thumbgate 1.4.3 → 1.4.4
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-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/adapters/README.md +1 -1
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +2 -2
- package/adapters/mcp/server-stdio.js +1 -1
- package/adapters/opencode/opencode.json +1 -1
- package/package.json +157 -9
- package/scripts/statusline.sh +1 -0
- package/src/api/server.js +113 -16
- package/src/index.js +3 -0
- package/.claude-plugin/bundle/icon.png +0 -0
- package/.claude-plugin/bundle/icon.svg +0 -18
- package/.claude-plugin/bundle/server/index.js +0 -24
- package/adapters/chatgpt/INSTALL.md +0 -158
- package/adapters/perplexity/.mcp.json +0 -36
- package/adapters/perplexity/config.toml +0 -16
- package/adapters/perplexity/opencode.json +0 -29
- package/bin/memory.sh +0 -64
- package/bin/obsidian-sync.sh +0 -20
- package/plugins/amp-skill/INSTALL.md +0 -52
- package/plugins/amp-skill/SKILL.md +0 -64
- package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +0 -22
- package/plugins/claude-codex-bridge/.mcp.json +0 -14
- package/plugins/claude-codex-bridge/INSTALL.md +0 -43
- package/plugins/claude-codex-bridge/README.md +0 -46
- package/plugins/claude-codex-bridge/scripts/codex-bridge.js +0 -286
- package/plugins/claude-codex-bridge/skills/adversarial-review/SKILL.md +0 -24
- package/plugins/claude-codex-bridge/skills/result/SKILL.md +0 -22
- package/plugins/claude-codex-bridge/skills/review/SKILL.md +0 -28
- package/plugins/claude-codex-bridge/skills/second-pass/SKILL.md +0 -27
- package/plugins/claude-codex-bridge/skills/setup/SKILL.md +0 -21
- package/plugins/claude-codex-bridge/skills/status/SKILL.md +0 -19
- package/plugins/claude-skill/INSTALL.md +0 -55
- package/plugins/claude-skill/SKILL.md +0 -46
- package/plugins/codex-profile/.codex-plugin/plugin.json +0 -43
- package/plugins/codex-profile/.mcp.json +0 -14
- package/plugins/codex-profile/AGENTS.md +0 -20
- package/plugins/codex-profile/INSTALL.md +0 -89
- package/plugins/codex-profile/README.md +0 -61
- package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +0 -23
- package/plugins/cursor-marketplace/CHANGELOG.md +0 -30
- package/plugins/cursor-marketplace/LICENSE +0 -21
- package/plugins/cursor-marketplace/README.md +0 -124
- package/plugins/cursor-marketplace/agents/reliability-reviewer.md +0 -31
- package/plugins/cursor-marketplace/assets/logo-400x400.png +0 -0
- package/plugins/cursor-marketplace/commands/capture-feedback.md +0 -33
- package/plugins/cursor-marketplace/commands/check-gates.md +0 -25
- package/plugins/cursor-marketplace/commands/show-lessons.md +0 -27
- package/plugins/cursor-marketplace/hooks/hooks.json +0 -10
- package/plugins/cursor-marketplace/mcp.json +0 -14
- package/plugins/cursor-marketplace/rules/feedback-capture.mdc +0 -34
- package/plugins/cursor-marketplace/rules/pre-action-gates.mdc +0 -30
- package/plugins/cursor-marketplace/rules/session-continuity.mdc +0 -28
- package/plugins/cursor-marketplace/scripts/gate-check.sh +0 -21
- package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +0 -48
- package/plugins/cursor-marketplace/skills/prevention-rules/SKILL.md +0 -31
- package/plugins/cursor-marketplace/skills/recall-context/SKILL.md +0 -30
- package/plugins/cursor-marketplace/skills/search-lessons/SKILL.md +0 -33
- package/plugins/gemini-extension/INSTALL.md +0 -92
- package/plugins/gemini-extension/gemini_prompt.txt +0 -14
- package/plugins/gemini-extension/tool_contract.json +0 -45
- package/plugins/opencode-profile/INSTALL.md +0 -57
- package/public/assets/instagram-card.png +0 -0
- package/public/assets/tiktok-agent-memory.mp4 +0 -0
- package/public/blog.html +0 -474
- package/public/compare/mem0.html +0 -189
- package/public/compare/speclock.html +0 -180
- package/public/compare.html +0 -310
- package/public/dashboard.html +0 -1100
- package/public/guide.html +0 -317
- package/public/guides/claude-code-prevent-repeated-mistakes.html +0 -161
- package/public/guides/codex-cli-guardrails.html +0 -158
- package/public/guides/cursor-prevent-repeated-mistakes.html +0 -161
- package/public/guides/pre-action-gates.html +0 -162
- package/public/guides/stop-repeated-ai-agent-mistakes.html +0 -159
- package/public/index.html +0 -1225
- package/public/js/buyer-intent.js +0 -252
- package/public/learn/agent-harness-pattern.html +0 -180
- package/public/learn/ai-agent-persistent-memory.html +0 -203
- package/public/learn/learn.css +0 -45
- package/public/learn/mcp-pre-action-gates-explained.html +0 -172
- package/public/learn/stop-ai-agent-force-push.html +0 -134
- package/public/learn/vibe-coding-safety-net.html +0 -142
- package/public/learn.html +0 -274
- package/public/lessons.html +0 -967
- package/public/llm-context.md +0 -156
- package/public/pro.html +0 -1087
- package/public/vercel.json +0 -8
- package/scripts/a2ui-engine.js +0 -73
- package/scripts/adk-consolidator.js +0 -274
- package/scripts/agent-security-hardening.js +0 -225
- package/scripts/ai-search-visibility.js +0 -116
- package/scripts/autonomous-sales-agent.js +0 -39
- package/scripts/autoresearch-runner.js +0 -216
- package/scripts/background-agent-governance.js +0 -229
- package/scripts/behavioral-extraction.js +0 -93
- package/scripts/budget-enforcer.js +0 -173
- package/scripts/budget-guard.js +0 -173
- package/scripts/build-claude-mcpb.js +0 -255
- package/scripts/build-codex-plugin.js +0 -152
- package/scripts/capture-railway-diagnostics.sh +0 -97
- package/scripts/changeset-check.js +0 -372
- package/scripts/check-congruence.js +0 -443
- package/scripts/computer-use-firewall.js +0 -280
- package/scripts/content-engine/linkedin-content-generator.js +0 -154
- package/scripts/content-engine/output/linkedin-memento-validation.md +0 -17
- package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +0 -175
- package/scripts/content-engine/reddit-thread-finder.js +0 -154
- package/scripts/context-engine.js +0 -710
- package/scripts/daily-digest.js +0 -11
- package/scripts/data-governance.js +0 -173
- package/scripts/deploy-gcp.sh +0 -44
- package/scripts/deploy-policy.js +0 -249
- package/scripts/disagreement-mining.js +0 -315
- package/scripts/dpo-optimizer.js +0 -206
- package/scripts/ensure-repo-bootstrap.js +0 -130
- package/scripts/ephemeral-agent-store.js +0 -212
- package/scripts/eval-harness.js +0 -56
- package/scripts/export-kto-pairs.js +0 -309
- package/scripts/export-training.js +0 -446
- package/scripts/feedback-fallback.js +0 -111
- package/scripts/feedback-inbox-read.js +0 -162
- package/scripts/feedback-root-consolidator.js +0 -233
- package/scripts/feedback-to-memory.js +0 -185
- package/scripts/gate-satisfy.js +0 -42
- package/scripts/generate-paperbanana-diagrams.sh +0 -99
- package/scripts/generate-pretool-hook.sh +0 -40
- package/scripts/github-about.js +0 -430
- package/scripts/github-outreach.js +0 -65
- package/scripts/gtm-revenue-loop.js +0 -535
- package/scripts/hallucination-detector.js +0 -226
- package/scripts/hf-papers.js +0 -317
- package/scripts/hook-auto-capture.sh +0 -100
- package/scripts/hook-stop-pr-thread-check.sh +0 -68
- package/scripts/hook-stop-self-score.sh +0 -51
- package/scripts/hook-stop-verify-deploy.sh +0 -31
- package/scripts/hook-verify-before-done.sh +0 -20
- package/scripts/managed-dpo-export.js +0 -91
- package/scripts/markdown-escape.js +0 -12
- package/scripts/marketing-experiment.js +0 -657
- package/scripts/memalign-recall.js +0 -111
- package/scripts/memory-migration.js +0 -296
- package/scripts/meta-policy.js +0 -190
- package/scripts/metered-billing.js +0 -16
- package/scripts/model-tier-router.js +0 -310
- package/scripts/money-watcher.js +0 -218
- package/scripts/multi-hop-recall.js +0 -240
- package/scripts/per-step-scoring.js +0 -163
- package/scripts/perplexity-command-center.js +0 -644
- package/scripts/perplexity-marketing.js +0 -454
- package/scripts/pii-scanner.js +0 -153
- package/scripts/plan-gate.js +0 -154
- package/scripts/post-everywhere.js +0 -341
- package/scripts/post-to-x-retry.sh +0 -22
- package/scripts/post-to-x.js +0 -369
- package/scripts/pr-manager.js +0 -421
- package/scripts/principle-extractor.js +0 -162
- package/scripts/pro-features.js +0 -41
- package/scripts/prompt-dlp.js +0 -222
- package/scripts/prove-adapters.js +0 -860
- package/scripts/prove-attribution.js +0 -361
- package/scripts/prove-automation.js +0 -651
- package/scripts/prove-autoresearch.js +0 -304
- package/scripts/prove-claim-verification.js +0 -277
- package/scripts/prove-cloudflare-sandbox.js +0 -161
- package/scripts/prove-data-pipeline.js +0 -408
- package/scripts/prove-data-quality.js +0 -227
- package/scripts/prove-evolution.js +0 -352
- package/scripts/prove-harnesses.js +0 -287
- package/scripts/prove-intelligence.js +0 -257
- package/scripts/prove-lancedb.js +0 -425
- package/scripts/prove-local-intelligence.js +0 -340
- package/scripts/prove-loop-closure.js +0 -263
- package/scripts/prove-packaged-runtime.js +0 -327
- package/scripts/prove-predictive-insights.js +0 -355
- package/scripts/prove-runtime.js +0 -363
- package/scripts/prove-seo-gsd.js +0 -234
- package/scripts/prove-settings.js +0 -279
- package/scripts/prove-subway-upgrades.js +0 -277
- package/scripts/prove-tessl.js +0 -229
- package/scripts/prove-training-export.js +0 -325
- package/scripts/prove-workflow-contract.js +0 -112
- package/scripts/prove-xmemory.js +0 -332
- package/scripts/publish-decision.js +0 -159
- package/scripts/ralph-loop.js +0 -376
- package/scripts/ralph-mode-ci.js +0 -434
- package/scripts/reddit-dm-outreach.js +0 -192
- package/scripts/reddit-monitor-cron.sh +0 -26
- package/scripts/reminder-engine.js +0 -132
- package/scripts/revenue-status.js +0 -472
- package/scripts/rotate-stripe-webhook-secret.js +0 -314
- package/scripts/schedule-manager.js +0 -249
- package/scripts/self-healing-check.js +0 -193
- package/scripts/session-analyzer.js +0 -533
- package/scripts/shieldcortex-memory-firewall-runner.mjs +0 -53
- package/scripts/skill-exporter.js +0 -260
- package/scripts/skill-materializer.js +0 -134
- package/scripts/skill-packs.js +0 -136
- package/scripts/skill-proposer.js +0 -99
- package/scripts/skill-quality-tracker.js +0 -282
- package/scripts/slow-loop.js +0 -72
- package/scripts/social-analytics/db/marketing-db.js +0 -179
- package/scripts/social-analytics/db/schema.sql +0 -55
- package/scripts/social-analytics/digest.js +0 -256
- package/scripts/social-analytics/engagement-audit.js +0 -185
- package/scripts/social-analytics/generate-instagram-card.js +0 -123
- package/scripts/social-analytics/generate-slides.js +0 -268
- package/scripts/social-analytics/instagram-thumbgate-post.js +0 -111
- package/scripts/social-analytics/install-growth-automation.js +0 -114
- package/scripts/social-analytics/load-env.js +0 -77
- package/scripts/social-analytics/mcp-server.js +0 -289
- package/scripts/social-analytics/normalizer.js +0 -580
- package/scripts/social-analytics/notify.js +0 -162
- package/scripts/social-analytics/poll-all.js +0 -107
- package/scripts/social-analytics/pollers/github.js +0 -195
- package/scripts/social-analytics/pollers/instagram.js +0 -253
- package/scripts/social-analytics/pollers/linkedin.js +0 -340
- package/scripts/social-analytics/pollers/plausible.js +0 -245
- package/scripts/social-analytics/pollers/reddit.js +0 -306
- package/scripts/social-analytics/pollers/threads.js +0 -233
- package/scripts/social-analytics/pollers/tiktok.js +0 -203
- package/scripts/social-analytics/pollers/x.js +0 -227
- package/scripts/social-analytics/pollers/youtube.js +0 -304
- package/scripts/social-analytics/pollers/zernio.js +0 -183
- package/scripts/social-analytics/post-video.js +0 -316
- package/scripts/social-analytics/publish-instagram-thumbgate.js +0 -104
- package/scripts/social-analytics/publish-thumbgate-launch.js +0 -322
- package/scripts/social-analytics/publishers/devto.js +0 -122
- package/scripts/social-analytics/publishers/instagram.js +0 -317
- package/scripts/social-analytics/publishers/linkedin.js +0 -294
- package/scripts/social-analytics/publishers/reddit.js +0 -385
- package/scripts/social-analytics/publishers/threads.js +0 -275
- package/scripts/social-analytics/publishers/tiktok.js +0 -217
- package/scripts/social-analytics/publishers/x.js +0 -259
- package/scripts/social-analytics/publishers/youtube.js +0 -223
- package/scripts/social-analytics/publishers/zernio.js +0 -568
- package/scripts/social-analytics/reconcile-thumbgate-campaign.js +0 -165
- package/scripts/social-analytics/run-digest.js +0 -34
- package/scripts/social-analytics/schedule-thumbgate-campaign.js +0 -275
- package/scripts/social-analytics/store.js +0 -455
- package/scripts/social-analytics/sync-launch-assets.js +0 -185
- package/scripts/social-analytics/utm.js +0 -143
- package/scripts/social-pipeline.js +0 -2626
- package/scripts/social-post-hourly.js +0 -228
- package/scripts/social-quality-gate.js +0 -134
- package/scripts/social-reply-monitor.js +0 -592
- package/scripts/status-dashboard.js +0 -155
- package/scripts/stripe-live-status.js +0 -115
- package/scripts/subagent-profiles.js +0 -79
- package/scripts/sync-branch-protection.js +0 -340
- package/scripts/sync-gh-secrets-from-env.sh +0 -70
- package/scripts/sync-github-about.js +0 -55
- package/scripts/sync-version.js +0 -479
- package/scripts/synthetic-dpo.js +0 -234
- package/scripts/tessl-export.js +0 -369
- package/scripts/test-coverage.js +0 -128
- package/scripts/thumbgate-bench.js +0 -494
- package/scripts/thumbgate_session_start.sh +0 -32
- package/scripts/train_from_feedback.py +0 -929
- package/scripts/validate-feedback.js +0 -581
- package/scripts/verify-obsidian-setup.sh +0 -269
- package/scripts/verify-run.js +0 -269
- package/scripts/weekly-auto-post.js +0 -124
- package/scripts/x-autonomous-marketing.js +0 -139
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Skill Exporter — compiles ThumbGate profiles/policy-bundles into
|
|
6
|
-
* OpenAI Skill definitions and Codex Plugin manifests.
|
|
7
|
-
* Vendor-neutral IR → target format compilation.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const fs = require('node:fs');
|
|
11
|
-
const path = require('node:path');
|
|
12
|
-
|
|
13
|
-
const ROOT = path.join(__dirname, '..');
|
|
14
|
-
const SKILL_SPECS_DIR = path.join(ROOT, 'config', 'skill-specs');
|
|
15
|
-
const POLICY_BUNDLES_DIR = path.join(ROOT, 'config', 'policy-bundles');
|
|
16
|
-
const DIST_DIR = path.join(ROOT, 'dist', 'skills');
|
|
17
|
-
const PKG = require(path.join(ROOT, 'package.json'));
|
|
18
|
-
const { ensureDir } = require('./fs-utils');
|
|
19
|
-
|
|
20
|
-
function readJson(filePath) {
|
|
21
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Load a SkillSpec by name from config/skill-specs/.
|
|
27
|
-
* @param {string} name - spec name (without .json)
|
|
28
|
-
* @returns {object} parsed SkillSpec
|
|
29
|
-
*/
|
|
30
|
-
function loadSkillSpec(name) {
|
|
31
|
-
const specPath = path.join(SKILL_SPECS_DIR, `${name}.json`);
|
|
32
|
-
if (!fs.existsSync(specPath)) {
|
|
33
|
-
throw new Error(`Skill spec not found: ${name} (looked at ${specPath})`);
|
|
34
|
-
}
|
|
35
|
-
return readJson(specPath);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* List all available skill specs in config/skill-specs/.
|
|
40
|
-
* @returns {string[]} spec names (without .json extension)
|
|
41
|
-
*/
|
|
42
|
-
function listAvailableSpecs() {
|
|
43
|
-
if (!fs.existsSync(SKILL_SPECS_DIR)) return [];
|
|
44
|
-
return fs.readdirSync(SKILL_SPECS_DIR)
|
|
45
|
-
.filter((f) => f.endsWith('.json'))
|
|
46
|
-
.map((f) => f.replace(/\.json$/, ''));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Load a policy bundle by bundleId.
|
|
51
|
-
* @param {string} bundleId
|
|
52
|
-
* @returns {object} parsed policy bundle
|
|
53
|
-
*/
|
|
54
|
-
function loadPolicyBundle(bundleId) {
|
|
55
|
-
const bundlePath = path.join(POLICY_BUNDLES_DIR, `${bundleId}.json`);
|
|
56
|
-
if (!fs.existsSync(bundlePath)) return null;
|
|
57
|
-
return readJson(bundlePath);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Build instruction text from a policy bundle and escalation rules.
|
|
62
|
-
* @param {object} bundle - parsed policy bundle
|
|
63
|
-
* @param {string[]} escalationRules
|
|
64
|
-
* @returns {string} instruction text
|
|
65
|
-
*/
|
|
66
|
-
function buildInstructions(bundle, escalationRules) {
|
|
67
|
-
const lines = [];
|
|
68
|
-
lines.push(`Policy: ${bundle.description}`);
|
|
69
|
-
lines.push(`Default MCP Profile: ${bundle.defaultMcpProfile}`);
|
|
70
|
-
lines.push('');
|
|
71
|
-
lines.push('## Approval Gates');
|
|
72
|
-
lines.push(`Required risk levels for approval: ${bundle.approval.requiredRisks.join(', ')}`);
|
|
73
|
-
lines.push('');
|
|
74
|
-
lines.push('## Available Intents');
|
|
75
|
-
for (const intent of bundle.intents) {
|
|
76
|
-
const actions = intent.actions.map((a) => a.name).join(', ');
|
|
77
|
-
lines.push(`- ${intent.id} [${intent.risk}]: ${intent.description} (${actions})`);
|
|
78
|
-
}
|
|
79
|
-
if (escalationRules.length > 0) {
|
|
80
|
-
lines.push('');
|
|
81
|
-
lines.push('## Escalation Rules');
|
|
82
|
-
for (const rule of escalationRules) {
|
|
83
|
-
lines.push(`- ${rule}`);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return lines.join('\n');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Compile a SkillSpec into an OpenAI Skill definition.
|
|
91
|
-
* @param {object} spec - parsed SkillSpec
|
|
92
|
-
* @returns {object} OpenAI Skill JSON
|
|
93
|
-
*/
|
|
94
|
-
function compileToOpenAISkill(spec) {
|
|
95
|
-
const bundle = loadPolicyBundle(spec.policyBundle);
|
|
96
|
-
const instructions = bundle
|
|
97
|
-
? buildInstructions(bundle, spec.escalationRules || [])
|
|
98
|
-
: `Skill: ${spec.description}`;
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
name: spec.name,
|
|
102
|
-
description: spec.description,
|
|
103
|
-
model_class: spec.defaultModelClass,
|
|
104
|
-
instructions,
|
|
105
|
-
scripts: {
|
|
106
|
-
gate_check: `recall --scope ${(spec.memoryScope || []).join(',')} --enforce`,
|
|
107
|
-
recall_injection: `recall --query "{{context}}" --scope ${(spec.memoryScope || []).join(',')}`
|
|
108
|
-
},
|
|
109
|
-
assets: {
|
|
110
|
-
prevention_rules: `config/policy-bundles/${spec.policyBundle}.json`,
|
|
111
|
-
memory_scope: spec.memoryScope || [],
|
|
112
|
-
tools: spec.tools || []
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Compile a SkillSpec into a Codex Plugin manifest.
|
|
119
|
-
* @param {object} spec - parsed SkillSpec
|
|
120
|
-
* @returns {object} { pluginJson, mcpJson, agentsMd }
|
|
121
|
-
*/
|
|
122
|
-
function compileToCodexPlugin(spec) {
|
|
123
|
-
const bundle = loadPolicyBundle(spec.policyBundle);
|
|
124
|
-
const instructions = bundle
|
|
125
|
-
? buildInstructions(bundle, spec.escalationRules || [])
|
|
126
|
-
: `Skill: ${spec.description}`;
|
|
127
|
-
|
|
128
|
-
const pluginJson = {
|
|
129
|
-
name: spec.name,
|
|
130
|
-
version: PKG.version,
|
|
131
|
-
description: spec.description,
|
|
132
|
-
author: {
|
|
133
|
-
name: PKG.author,
|
|
134
|
-
url: 'https://github.com/IgorGanapolsky'
|
|
135
|
-
},
|
|
136
|
-
homepage: PKG.homepage,
|
|
137
|
-
repository: PKG.repository.url.replace(/\.git$/, ''),
|
|
138
|
-
license: PKG.license,
|
|
139
|
-
keywords: ['codex', 'codex-plugin', 'thumbgate', spec.name, ...(spec.memoryScope || [])],
|
|
140
|
-
mcpServers: './.mcp.json',
|
|
141
|
-
interface: {
|
|
142
|
-
displayName: `ThumbGate: ${spec.name}`,
|
|
143
|
-
shortDescription: spec.description,
|
|
144
|
-
longDescription: instructions,
|
|
145
|
-
developerName: PKG.author,
|
|
146
|
-
category: 'Developer Tools',
|
|
147
|
-
capabilities: ['Interactive', 'Write'],
|
|
148
|
-
websiteURL: PKG.homepage,
|
|
149
|
-
brandColor: '#0ea5e9'
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
const mcpJson = {
|
|
154
|
-
mcpServers: {
|
|
155
|
-
thumbgate: {
|
|
156
|
-
command: 'npx',
|
|
157
|
-
args: ['-y', `thumbgate@${PKG.version}`, 'serve'],
|
|
158
|
-
tools: spec.tools || []
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
const agentsMdLines = [
|
|
164
|
-
`# ${spec.name} — ThumbGate Codex Plugin`,
|
|
165
|
-
'',
|
|
166
|
-
'## Trigger',
|
|
167
|
-
'If user gives explicit positive/negative outcome feedback, capture it immediately.',
|
|
168
|
-
'',
|
|
169
|
-
'## Memory Scope',
|
|
170
|
-
...(spec.memoryScope || []).map((s) => `- ${s}`),
|
|
171
|
-
'',
|
|
172
|
-
'## Gating Instructions',
|
|
173
|
-
instructions,
|
|
174
|
-
'',
|
|
175
|
-
'## Session Start',
|
|
176
|
-
'',
|
|
177
|
-
'```bash',
|
|
178
|
-
'npm run feedback:summary',
|
|
179
|
-
'npm run feedback:rules',
|
|
180
|
-
'```',
|
|
181
|
-
'',
|
|
182
|
-
'Use generated rules as hard guardrails to avoid repeated mistakes.'
|
|
183
|
-
];
|
|
184
|
-
|
|
185
|
-
return {
|
|
186
|
-
pluginJson,
|
|
187
|
-
mcpJson,
|
|
188
|
-
agentsMd: agentsMdLines.join('\n')
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Export a skill spec to the given target formats.
|
|
194
|
-
* @param {string} name - spec name
|
|
195
|
-
* @param {string[]} targets - array of 'openai' and/or 'codex'
|
|
196
|
-
* @returns {{ openai?: object, codex?: object, written: string[] }}
|
|
197
|
-
*/
|
|
198
|
-
function exportSkill(name, targets = ['openai', 'codex']) {
|
|
199
|
-
const spec = loadSkillSpec(name);
|
|
200
|
-
const result = { written: [] };
|
|
201
|
-
const outDir = path.join(DIST_DIR, name);
|
|
202
|
-
ensureDir(outDir);
|
|
203
|
-
|
|
204
|
-
if (targets.includes('openai')) {
|
|
205
|
-
const openai = compileToOpenAISkill(spec);
|
|
206
|
-
result.openai = openai;
|
|
207
|
-
const openaiPath = path.join(outDir, 'openai-skill.json');
|
|
208
|
-
fs.writeFileSync(openaiPath, JSON.stringify(openai, null, 2) + '\n');
|
|
209
|
-
result.written.push(openaiPath);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (targets.includes('codex')) {
|
|
213
|
-
const codex = compileToCodexPlugin(spec);
|
|
214
|
-
result.codex = codex;
|
|
215
|
-
const codexDir = path.join(outDir, 'codex');
|
|
216
|
-
ensureDir(path.join(codexDir, '.codex-plugin'));
|
|
217
|
-
|
|
218
|
-
const pluginPath = path.join(codexDir, '.codex-plugin', 'plugin.json');
|
|
219
|
-
fs.writeFileSync(pluginPath, JSON.stringify(codex.pluginJson, null, 2) + '\n');
|
|
220
|
-
result.written.push(pluginPath);
|
|
221
|
-
|
|
222
|
-
const mcpPath = path.join(codexDir, '.mcp.json');
|
|
223
|
-
fs.writeFileSync(mcpPath, JSON.stringify(codex.mcpJson, null, 2) + '\n');
|
|
224
|
-
result.written.push(mcpPath);
|
|
225
|
-
|
|
226
|
-
const agentsPath = path.join(codexDir, 'AGENTS.md');
|
|
227
|
-
fs.writeFileSync(agentsPath, codex.agentsMd + '\n');
|
|
228
|
-
result.written.push(agentsPath);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return result;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
module.exports = { loadSkillSpec, compileToOpenAISkill, compileToCodexPlugin, exportSkill, listAvailableSpecs };
|
|
235
|
-
|
|
236
|
-
/* istanbul ignore next — CLI entry */
|
|
237
|
-
if (require.main === module) {
|
|
238
|
-
const args = process.argv.slice(2);
|
|
239
|
-
const cmd = args[0] || 'list';
|
|
240
|
-
if (cmd === 'list') {
|
|
241
|
-
const specs = listAvailableSpecs();
|
|
242
|
-
console.log('Available skill specs:', specs.join(', '));
|
|
243
|
-
} else if (cmd === 'export') {
|
|
244
|
-
const name = args[1];
|
|
245
|
-
if (!name) { console.error('Usage: skill-exporter.js export <name>'); process.exit(1); }
|
|
246
|
-
const targets = args[2] ? args[2].split(',') : ['openai', 'codex'];
|
|
247
|
-
const result = exportSkill(name, targets);
|
|
248
|
-
console.log(`Exported ${name} → ${result.written.length} files`);
|
|
249
|
-
result.written.forEach((f) => console.log(` ${f}`));
|
|
250
|
-
} else if (cmd === 'export-all') {
|
|
251
|
-
const specs = listAvailableSpecs();
|
|
252
|
-
for (const name of specs) {
|
|
253
|
-
const result = exportSkill(name);
|
|
254
|
-
console.log(`Exported ${name} → ${result.written.length} files`);
|
|
255
|
-
}
|
|
256
|
-
} else {
|
|
257
|
-
console.error(`Unknown command: ${cmd}`);
|
|
258
|
-
process.exit(1);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Skill Materializer (EvoSkill Phase 2)
|
|
4
|
-
*
|
|
5
|
-
* Takes a JSON proposal from Skill Proposer and 'materializes'
|
|
6
|
-
* a functional MCP tool definition + SKILL.md documentation.
|
|
7
|
-
*
|
|
8
|
-
* Ensures every skill has a standardized entry point for the agent.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
const { discoverFeedbackDir } = require('./skill-generator');
|
|
14
|
-
|
|
15
|
-
function materializeSkills(options = {}) {
|
|
16
|
-
const feedbackDir = options.feedbackDir || discoverFeedbackDir();
|
|
17
|
-
const proposalsDir = path.join(feedbackDir, 'skill-proposals');
|
|
18
|
-
const skillsOutDir = options.skillsOutDir || process.env.THUMBGATE_SKILLS_DIR || path.join(process.cwd(), 'skills');
|
|
19
|
-
|
|
20
|
-
if (!fs.existsSync(proposalsDir)) {
|
|
21
|
-
console.log('No proposals directory found.');
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const proposals = fs.readdirSync(proposalsDir)
|
|
26
|
-
.filter(f => f.endsWith('.json'))
|
|
27
|
-
.map(f => JSON.parse(fs.readFileSync(path.join(proposalsDir, f), 'utf-8')));
|
|
28
|
-
|
|
29
|
-
if (proposals.length === 0) {
|
|
30
|
-
console.log('No pending skill proposals.');
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (!fs.existsSync(skillsOutDir)) fs.mkdirSync(skillsOutDir, { recursive: true });
|
|
35
|
-
|
|
36
|
-
const results = [];
|
|
37
|
-
|
|
38
|
-
for (const proposal of proposals) {
|
|
39
|
-
if (proposal.status !== 'pending') continue;
|
|
40
|
-
|
|
41
|
-
const skillName = proposal.suggestedSkill.name;
|
|
42
|
-
const skillDir = path.join(skillsOutDir, skillName);
|
|
43
|
-
if (!fs.existsSync(skillDir)) fs.mkdirSync(skillDir, { recursive: true });
|
|
44
|
-
|
|
45
|
-
// Generate SKILL.md
|
|
46
|
-
const skillMd = generateSkillMarkdown(proposal);
|
|
47
|
-
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), skillMd);
|
|
48
|
-
|
|
49
|
-
// Generate functional tool code (template)
|
|
50
|
-
const toolCode = generateToolCode(proposal);
|
|
51
|
-
fs.writeFileSync(path.join(skillDir, 'tool.js'), toolCode);
|
|
52
|
-
|
|
53
|
-
// Update proposal status
|
|
54
|
-
proposal.status = 'materialized';
|
|
55
|
-
proposal.materializedAt = new Date().toISOString();
|
|
56
|
-
fs.writeFileSync(
|
|
57
|
-
path.join(proposalsDir, `${skillName}.json`),
|
|
58
|
-
JSON.stringify(proposal, null, 2)
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
results.push(skillName);
|
|
62
|
-
console.log(`Materialized skill: ${skillName} -> ${skillDir}`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return results;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function generateSkillMarkdown(proposal) {
|
|
69
|
-
const { suggestedSkill, problem, diagnosis } = proposal;
|
|
70
|
-
return `---
|
|
71
|
-
name: ${suggestedSkill.name}
|
|
72
|
-
description: ${suggestedSkill.description}
|
|
73
|
-
diagnosis: ${diagnosis}
|
|
74
|
-
status: materialized
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
# ${suggestedSkill.name.toUpperCase()} Capability
|
|
78
|
-
|
|
79
|
-
## Problem
|
|
80
|
-
${problem}
|
|
81
|
-
|
|
82
|
-
## Automated Diagnosis
|
|
83
|
-
${diagnosis}
|
|
84
|
-
|
|
85
|
-
## Usage
|
|
86
|
-
The agent should call the \`${suggestedSkill.toolSpec.name}\` tool when tasks involve \`${suggestedSkill.tags.join(', ')}\`.
|
|
87
|
-
`;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function generateToolCode(proposal) {
|
|
91
|
-
const { suggestedSkill } = proposal;
|
|
92
|
-
const toolName = suggestedSkill.toolSpec.name;
|
|
93
|
-
|
|
94
|
-
return `/**
|
|
95
|
-
* Automated Skill: ${suggestedSkill.name}
|
|
96
|
-
* Generated: ${new Date().toISOString()}
|
|
97
|
-
*
|
|
98
|
-
* This tool was materialized by the EvoSkill loop to address:
|
|
99
|
-
* "${proposal.problem}"
|
|
100
|
-
*/
|
|
101
|
-
|
|
102
|
-
const { execSync } = require('child_process');
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* ${suggestedSkill.toolSpec.description}
|
|
106
|
-
*/
|
|
107
|
-
async function ${toolName}(args) {
|
|
108
|
-
const { context } = args;
|
|
109
|
-
|
|
110
|
-
// LOGIC: Materialized code should implement the fix derived from the diagnosis.
|
|
111
|
-
// For now, we provide a structured wrapper that logs intent and applies
|
|
112
|
-
// the suggested corrective action.
|
|
113
|
-
|
|
114
|
-
console.log(\`[EVOSKILL] Executing ${toolName} to resolve: ${proposal.problem}\`);
|
|
115
|
-
|
|
116
|
-
// Corrective action placeholder - in a full loop, this would be LLM-generated code
|
|
117
|
-
// derived from the 'how-to-avoid' fields in memory-log.jsonl.
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
status: 'success',
|
|
121
|
-
appliedFix: \`Automated handling of ${proposal.problem} pattern.\`,
|
|
122
|
-
context: context
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
module.exports = { ${toolName} };
|
|
127
|
-
`;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (require.main === module) {
|
|
131
|
-
materializeSkills();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
module.exports = { materializeSkills };
|
package/scripts/skill-packs.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { registerPreventionRules } = require('./contextfs');
|
|
6
|
-
const SKILL_PACKS_DIR = path.join(__dirname, '..', 'config', 'skill-packs');
|
|
7
|
-
const BUILTIN_PACKS = {
|
|
8
|
-
'stripe-integration': { name: 'stripe-integration', description: 'Stripe API best practices', triggers: ['stripe', 'payment', 'checkout', 'subscription', 'webhook signature'], rules: ['ALWAYS use idempotency keys on PaymentIntent creation to prevent duplicate charges.', 'NEVER log or store raw card numbers — use Stripe tokens or PaymentMethod IDs.', 'ALWAYS verify webhook signatures with stripe.webhooks.constructEvent() before processing.', 'Use Checkout Sessions instead of raw PaymentIntents for new integrations.', 'ALWAYS handle payment_intent.succeeded AND payment_intent.payment_failed webhooks.'], packTemplate: { namespaces: ['memoryError', 'memoryLearning', 'rules'], maxItems: 8, maxChars: 6000, queryPrefix: 'stripe payment checkout webhook idempotency' } },
|
|
9
|
-
'railway-deploy': { name: 'railway-deploy', description: 'Railway deployment best practices', triggers: ['railway', 'deploy', 'dockerfile', 'health check'], rules: ['ALWAYS verify /health endpoint returns new version after deploy.', 'NEVER say "deployed" without curling the health endpoint and showing version match.', 'ALWAYS check Railway build logs for warnings even when deploy succeeds.', 'Use RAILWAY_VOLUME_MOUNT_PATH for persistent data.', 'ALWAYS wait 2-5 minutes after merge before verifying.'], packTemplate: { namespaces: ['memoryError', 'memoryLearning', 'rules'], maxItems: 8, maxChars: 6000, queryPrefix: 'railway deploy health version dockerfile' } },
|
|
10
|
-
'database-migration': { name: 'database-migration', description: 'Database migration best practices', triggers: ['migration', 'prisma', 'sqlite', 'schema', 'alter table'], rules: ['ALWAYS back up the database before running destructive migrations.', 'NEVER drop columns in production without verifying no code references them.', 'ALWAYS run migrations against a test database first.', 'Use reversible migrations — every up() should have a corresponding down().', 'ALWAYS check for pending migrations before deploying new code.'], packTemplate: { namespaces: ['memoryError', 'rules'], maxItems: 6, maxChars: 5000, queryPrefix: 'migration database schema prisma sqlite' } },
|
|
11
|
-
};
|
|
12
|
-
const registry = new Map(); for (const [id, p] of Object.entries(BUILTIN_PACKS)) registry.set(id, p);
|
|
13
|
-
function ensurePacksDir() { if (!fs.existsSync(SKILL_PACKS_DIR)) fs.mkdirSync(SKILL_PACKS_DIR, { recursive: true }); }
|
|
14
|
-
function registerSkillPack(pack) { if (!pack.name) throw new Error('Skill pack requires a name'); if (!Array.isArray(pack.rules) || pack.rules.length === 0) throw new Error('Skill pack requires at least one rule'); const n = { name: pack.name, description: pack.description || '', triggers: Array.isArray(pack.triggers) ? pack.triggers : [], rules: pack.rules, packTemplate: pack.packTemplate || null, registeredAt: new Date().toISOString() }; registry.set(n.name, n); ensurePacksDir(); fs.writeFileSync(path.join(SKILL_PACKS_DIR, `${n.name}.json`), JSON.stringify(n, null, 2) + '\n'); return n; }
|
|
15
|
-
function loadSkillPacksFromDisk() { ensurePacksDir(); for (const f of fs.readdirSync(SKILL_PACKS_DIR).filter((x) => x.endsWith('.json'))) { try { const p = JSON.parse(fs.readFileSync(path.join(SKILL_PACKS_DIR, f), 'utf-8')); if (p.name) registry.set(p.name, p); } catch { /* skip */ } } }
|
|
16
|
-
function listSkillPacks() { loadSkillPacksFromDisk(); return Array.from(registry.values()).map((p) => ({ name: p.name, description: p.description, triggers: p.triggers, ruleCount: p.rules.length, hasPackTemplate: !!p.packTemplate })); }
|
|
17
|
-
function getSkillPack(name) { loadSkillPacksFromDisk(); return registry.get(name) || null; }
|
|
18
|
-
function matchSkillPacks(query) { const tokens = String(query || '').toLowerCase().split(/\s+/).filter(Boolean); if (tokens.length === 0) return []; loadSkillPacksFromDisk(); const scored = []; for (const pack of registry.values()) { let score = 0; for (const trigger of pack.triggers) { for (const t of trigger.toLowerCase().split(/\s+/)) { if (tokens.some((qt) => qt.includes(t) || t.includes(qt))) score += 1; } } if (score > 0) scored.push({ pack, score }); } return scored.sort((a, b) => b.score - a.score).map((s) => s.pack); }
|
|
19
|
-
function installSkillPackRules(name) { const pack = getSkillPack(name); if (!pack) throw new Error(`Skill pack not found: "${name}"`); return registerPreventionRules([`# Skill Pack: ${pack.name}`, '', pack.description || '', '', ...pack.rules.map((r, i) => `${i + 1}. ${r}`)].join('\n'), { skillPack: pack.name }); }
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
// L3 Resource Loading (ADK progressive disclosure)
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
|
|
24
|
-
const RESOURCES_DIR_NAME = 'references';
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Load an L3 resource file for a skill pack.
|
|
28
|
-
* Resources live in config/skill-packs/{pack-name}/references/{filename}.
|
|
29
|
-
*/
|
|
30
|
-
function loadSkillResource(packName, resourceName) {
|
|
31
|
-
const resDir = path.join(SKILL_PACKS_DIR, packName, RESOURCES_DIR_NAME);
|
|
32
|
-
const resPath = path.join(resDir, resourceName);
|
|
33
|
-
if (!fs.existsSync(resPath)) return null;
|
|
34
|
-
return { name: resourceName, path: resPath, content: fs.readFileSync(resPath, 'utf-8'), sizeBytes: fs.statSync(resPath).size };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* List available L3 resources for a skill pack.
|
|
39
|
-
*/
|
|
40
|
-
function listSkillResources(packName) {
|
|
41
|
-
const resDir = path.join(SKILL_PACKS_DIR, packName, RESOURCES_DIR_NAME);
|
|
42
|
-
if (!fs.existsSync(resDir)) return [];
|
|
43
|
-
return fs.readdirSync(resDir).filter((f) => !f.startsWith('.')).map((f) => {
|
|
44
|
-
const fp = path.join(resDir, f);
|
|
45
|
-
return { name: f, sizeBytes: fs.statSync(fp).size };
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Add an L3 resource file to a skill pack.
|
|
51
|
-
*/
|
|
52
|
-
function addSkillResource(packName, resourceName, content) {
|
|
53
|
-
const resDir = path.join(SKILL_PACKS_DIR, packName, RESOURCES_DIR_NAME);
|
|
54
|
-
ensurePacksDir();
|
|
55
|
-
if (!fs.existsSync(resDir)) fs.mkdirSync(resDir, { recursive: true });
|
|
56
|
-
const resPath = path.join(resDir, resourceName);
|
|
57
|
-
fs.writeFileSync(resPath, content);
|
|
58
|
-
return { name: resourceName, path: resPath, sizeBytes: Buffer.byteLength(content) };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
// Skill Factory — agent-driven skill generation
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Auto-generate a skill pack from recurring failure patterns.
|
|
67
|
-
* Uses distilled lessons to propose rules for a new domain.
|
|
68
|
-
*
|
|
69
|
-
* @param {Object} opts
|
|
70
|
-
* @param {string} opts.domain - Domain name (e.g., 'graphql-api')
|
|
71
|
-
* @param {Array} opts.lessons - Array of lesson strings from history distiller
|
|
72
|
-
* @param {string} [opts.description] - Pack description
|
|
73
|
-
* @param {Array} [opts.triggers] - Trigger keywords
|
|
74
|
-
* @returns {Object} The created skill pack
|
|
75
|
-
*/
|
|
76
|
-
function generateSkillPack({ domain, lessons, description, triggers } = {}) {
|
|
77
|
-
if (!domain) throw new Error('Skill factory requires a domain name');
|
|
78
|
-
if (!Array.isArray(lessons) || lessons.length === 0) throw new Error('Skill factory requires at least one lesson');
|
|
79
|
-
|
|
80
|
-
// Convert lessons into NEVER/ALWAYS rules
|
|
81
|
-
const rules = lessons.map((lesson) => {
|
|
82
|
-
const l = String(lesson).trim();
|
|
83
|
-
if (/^(NEVER|ALWAYS|DO NOT|MUST)/i.test(l)) return l;
|
|
84
|
-
if (/fail|error|broke|wrong|bug|crash/i.test(l)) return `NEVER ${l.replace(/^(avoid|don'?t|stop)\s*/i, '').trim()}`;
|
|
85
|
-
return `ALWAYS ${l.replace(/^(repeat|keep|continue)\s*/i, '').trim()}`;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Infer triggers from domain + lesson content
|
|
89
|
-
const inferredTriggers = triggers || [domain, ...domain.split('-').filter((t) => t.length > 2)];
|
|
90
|
-
|
|
91
|
-
return registerSkillPack({
|
|
92
|
-
name: domain,
|
|
93
|
-
description: description || `Auto-generated skill pack for ${domain} from ${lessons.length} lessons`,
|
|
94
|
-
triggers: inferredTriggers,
|
|
95
|
-
rules,
|
|
96
|
-
packTemplate: { namespaces: ['memoryError', 'memoryLearning', 'rules'], maxItems: 8, maxChars: 6000, queryPrefix: inferredTriggers.join(' ') },
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// ---------------------------------------------------------------------------
|
|
101
|
-
// Token-Efficient Progressive Disclosure Metrics
|
|
102
|
-
// ---------------------------------------------------------------------------
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Measure token cost of each disclosure level for a skill pack.
|
|
106
|
-
* Helps agents decide which packs to load.
|
|
107
|
-
*/
|
|
108
|
-
function measureSkillTokens(packName) {
|
|
109
|
-
const pack = getSkillPack(packName);
|
|
110
|
-
if (!pack) return null;
|
|
111
|
-
|
|
112
|
-
// L1: metadata only (~name + description + triggers)
|
|
113
|
-
const l1Text = `${pack.name}: ${pack.description} [${(pack.triggers || []).join(', ')}]`;
|
|
114
|
-
const l1Chars = l1Text.length;
|
|
115
|
-
|
|
116
|
-
// L2: full rules
|
|
117
|
-
const l2Text = pack.rules.join('\n');
|
|
118
|
-
const l2Chars = l2Text.length;
|
|
119
|
-
|
|
120
|
-
// L3: resources
|
|
121
|
-
const resources = listSkillResources(packName);
|
|
122
|
-
const l3Chars = resources.reduce((sum, r) => sum + r.sizeBytes, 0);
|
|
123
|
-
|
|
124
|
-
const totalChars = l1Chars + l2Chars + l3Chars;
|
|
125
|
-
|
|
126
|
-
return {
|
|
127
|
-
packName,
|
|
128
|
-
l1: { chars: l1Chars, estimatedTokens: Math.ceil(l1Chars / 4) },
|
|
129
|
-
l2: { chars: l2Chars, estimatedTokens: Math.ceil(l2Chars / 4), ruleCount: pack.rules.length },
|
|
130
|
-
l3: { chars: l3Chars, estimatedTokens: Math.ceil(l3Chars / 4), resourceCount: resources.length },
|
|
131
|
-
total: { chars: totalChars, estimatedTokens: Math.ceil(totalChars / 4) },
|
|
132
|
-
disclosureSavings: totalChars > 0 ? Math.round((1 - l1Chars / totalChars) * 100) : 0,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
module.exports = { BUILTIN_PACKS, registerSkillPack, listSkillPacks, getSkillPack, matchSkillPacks, installSkillPackRules, SKILL_PACKS_DIR, loadSkillResource, listSkillResources, addSkillResource, generateSkillPack, measureSkillTokens };
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Skill Proposer (EvoSkill Phase 1)
|
|
4
|
-
*
|
|
5
|
-
* Analyzes recurring failure patterns in memory-log.jsonl.
|
|
6
|
-
* Diagnoses the root cause using 'Reasoning' traces and proposes
|
|
7
|
-
* a new functional skill (tool) to solve the capability gap.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
const path = require('path');
|
|
12
|
-
const {
|
|
13
|
-
parseFeedbackFile,
|
|
14
|
-
clusterByTags,
|
|
15
|
-
extractTags,
|
|
16
|
-
discoverFeedbackDir
|
|
17
|
-
} = require('./skill-generator');
|
|
18
|
-
|
|
19
|
-
function proposeSkills(options = {}) {
|
|
20
|
-
const feedbackDir = options.feedbackDir || discoverFeedbackDir();
|
|
21
|
-
const logPath = path.join(feedbackDir, 'memory-log.jsonl');
|
|
22
|
-
const proposalsDir = path.join(feedbackDir, 'skill-proposals');
|
|
23
|
-
|
|
24
|
-
const memories = parseFeedbackFile(logPath);
|
|
25
|
-
const mistakes = memories.filter(m => m.category === 'error' || m.title.startsWith('MISTAKE:'));
|
|
26
|
-
|
|
27
|
-
if (mistakes.length === 0) {
|
|
28
|
-
console.log('No mistakes found in memory log.');
|
|
29
|
-
return [];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Cluster by tags (EvoSkill refinement)
|
|
33
|
-
const clusters = clusterByTags(mistakes, 2);
|
|
34
|
-
const proposals = [];
|
|
35
|
-
|
|
36
|
-
for (const [tagKey, cluster] of clusters) {
|
|
37
|
-
if (cluster.entries.length < 2) continue; // Lower threshold for autonomous discovery
|
|
38
|
-
|
|
39
|
-
console.log(`Analyzing cluster: [${tagKey}] (${cluster.entries.length} evidences)`);
|
|
40
|
-
|
|
41
|
-
// Extract root cause from reasoning traces
|
|
42
|
-
const reasoningTraces = cluster.entries
|
|
43
|
-
.map(e => {
|
|
44
|
-
const match = e.content.match(/Reasoning: (.*)/);
|
|
45
|
-
return match ? match[1] : null;
|
|
46
|
-
})
|
|
47
|
-
.filter(Boolean);
|
|
48
|
-
|
|
49
|
-
const commonProblem = cluster.entries[0].title.replace('MISTAKE: ', '');
|
|
50
|
-
const tags = cluster.tags;
|
|
51
|
-
|
|
52
|
-
const proposal = {
|
|
53
|
-
id: `prop_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
54
|
-
status: 'pending',
|
|
55
|
-
problem: commonProblem,
|
|
56
|
-
diagnosis: reasoningTraces.length > 0 ? reasoningTraces[0] : 'Repeated execution failure in this domain.',
|
|
57
|
-
suggestedSkill: {
|
|
58
|
-
name: `solve-${tags[0]}-${tags[1] || 'logic'}`.toLowerCase().replace(/[^a-z-]/g, ''),
|
|
59
|
-
description: `Automated skill to handle ${tags.join(', ')} patterns efficiently.`,
|
|
60
|
-
tags,
|
|
61
|
-
// Propose a generic tool structure that the Materializer can flesh out
|
|
62
|
-
toolSpec: {
|
|
63
|
-
name: `handle_${tags[0].replace(/-/g, '_')}`,
|
|
64
|
-
description: `Fixes ${commonProblem}`,
|
|
65
|
-
parameters: {
|
|
66
|
-
type: 'object',
|
|
67
|
-
properties: {
|
|
68
|
-
context: { type: 'string', description: 'The current task context' }
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
evidenceIds: cluster.entries.map(e => e.id),
|
|
74
|
-
timestamp: new Date().toISOString()
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
proposals.push(proposal);
|
|
78
|
-
|
|
79
|
-
if (!fs.existsSync(proposalsDir)) fs.mkdirSync(proposalsDir, { recursive: true });
|
|
80
|
-
fs.writeFileSync(
|
|
81
|
-
path.join(proposalsDir, `${proposal.suggestedSkill.name}.json`),
|
|
82
|
-
JSON.stringify(proposal, null, 2)
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return proposals;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (require.main === module) {
|
|
90
|
-
const props = proposeSkills();
|
|
91
|
-
if (props && props.length > 0) {
|
|
92
|
-
const feedbackDir = discoverFeedbackDir();
|
|
93
|
-
const proposalsDir = path.join(feedbackDir, 'skill-proposals');
|
|
94
|
-
console.log(`\nGenerated ${props.length} skill proposals in ${proposalsDir}`);
|
|
95
|
-
props.forEach(p => console.log(` - ${p.suggestedSkill.name}: ${p.problem}`));
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
module.exports = { proposeSkills };
|