thumbgate 1.4.3 → 1.4.5
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/llms.txt +12 -8
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +18 -8
- 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/config/github-about.json +2 -2
- package/package.json +158 -10
- package/scripts/billing.js +5 -2
- 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
package/scripts/prove-tessl.js
DELETED
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const os = require('os');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
|
|
8
|
-
const {
|
|
9
|
-
exportTiles,
|
|
10
|
-
loadTileConfig,
|
|
11
|
-
verifyTiles,
|
|
12
|
-
} = require('./tessl-export');
|
|
13
|
-
|
|
14
|
-
const ROOT = path.join(__dirname, '..');
|
|
15
|
-
|
|
16
|
-
function resolveProofPaths() {
|
|
17
|
-
const proofDir = process.env.THUMBGATE_PROOF_DIR || path.join(ROOT, 'proof');
|
|
18
|
-
return {
|
|
19
|
-
proofDir,
|
|
20
|
-
reportJson: path.join(proofDir, 'tessl-report.json'),
|
|
21
|
-
reportMd: path.join(proofDir, 'tessl-report.md'),
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async function run() {
|
|
26
|
-
const { proofDir, reportJson, reportMd } = resolveProofPaths();
|
|
27
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'thumbgate-tessl-proof-'));
|
|
28
|
-
const results = { passed: 0, failed: 0, requirements: {} };
|
|
29
|
-
|
|
30
|
-
const checks = [
|
|
31
|
-
{
|
|
32
|
-
id: 'TESSL-01',
|
|
33
|
-
desc: 'tile config tracks only high-ROI first-party skills',
|
|
34
|
-
fn: () => {
|
|
35
|
-
const config = loadTileConfig();
|
|
36
|
-
const tileNames = config.tiles.map((tile) => tile.tileName);
|
|
37
|
-
|
|
38
|
-
if (config.defaultWorkspace !== 'thumbgate') {
|
|
39
|
-
throw new Error('Default Tessl workspace must stay thumbgate');
|
|
40
|
-
}
|
|
41
|
-
if (tileNames.length !== 2) {
|
|
42
|
-
throw new Error('Expected exactly two first-party Tessl tiles');
|
|
43
|
-
}
|
|
44
|
-
if (!tileNames.includes('agent-memory') || !tileNames.includes('thumbgate-feedback')) {
|
|
45
|
-
throw new Error('High-ROI ThumbGate tiles missing from config');
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
id: 'TESSL-02',
|
|
51
|
-
desc: 'export writes tile.json, index.md, and copied skills for every configured tile',
|
|
52
|
-
fn: () => {
|
|
53
|
-
const exported = exportTiles({ outDir: tempDir });
|
|
54
|
-
|
|
55
|
-
if (exported.length !== 2) {
|
|
56
|
-
throw new Error('Expected two exported Tessl tiles');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
for (const tile of exported) {
|
|
60
|
-
for (const relativePath of ['tile.json', 'index.md']) {
|
|
61
|
-
const fullPath = path.join(tile.directory, relativePath);
|
|
62
|
-
if (!fs.existsSync(fullPath)) {
|
|
63
|
-
throw new Error(`Missing exported asset ${relativePath} for ${tile.tileName}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
for (const skillName of tile.skills) {
|
|
67
|
-
const skillPath = path.join(tile.directory, 'skills', skillName, 'SKILL.md');
|
|
68
|
-
if (!fs.existsSync(skillPath)) {
|
|
69
|
-
throw new Error(`Missing exported skill ${skillName}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
id: 'TESSL-03',
|
|
77
|
-
desc: 'workspace override produces publishable workspace/tile names without mutating source config',
|
|
78
|
-
fn: () => {
|
|
79
|
-
const overridden = exportTiles({
|
|
80
|
-
outDir: tempDir,
|
|
81
|
-
workspace: 'igorganapolsky',
|
|
82
|
-
});
|
|
83
|
-
const manifest = JSON.parse(
|
|
84
|
-
fs.readFileSync(path.join(overridden[0].directory, 'tile.json'), 'utf8')
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
if (!manifest.name.startsWith('igorganapolsky/')) {
|
|
88
|
-
throw new Error('Workspace override did not flow into tile manifest');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const config = loadTileConfig();
|
|
92
|
-
if (config.defaultWorkspace !== 'thumbgate') {
|
|
93
|
-
throw new Error('Source config mutated during export');
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
id: 'TESSL-04',
|
|
99
|
-
desc: 'generated docs include install guidance plus proof pack links',
|
|
100
|
-
fn: () => {
|
|
101
|
-
exportTiles({ outDir: tempDir });
|
|
102
|
-
const docs = fs.readFileSync(path.join(tempDir, 'agent-memory', 'index.md'), 'utf8');
|
|
103
|
-
|
|
104
|
-
if (!docs.includes('tessl install thumbgate/agent-memory')) {
|
|
105
|
-
throw new Error('Install command missing from generated docs');
|
|
106
|
-
}
|
|
107
|
-
if (!docs.includes('VERIFICATION_EVIDENCE.md')) {
|
|
108
|
-
throw new Error('Verification evidence link missing from generated docs');
|
|
109
|
-
}
|
|
110
|
-
if (!docs.includes('proof/compatibility/report.json')) {
|
|
111
|
-
throw new Error('Compatibility proof link missing from generated docs');
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
id: 'TESSL-05',
|
|
117
|
-
desc: 'skill verification command succeeds against the canonical skills',
|
|
118
|
-
fn: () => {
|
|
119
|
-
const result = verifyTiles();
|
|
120
|
-
|
|
121
|
-
if (!result.ok || result.tileCount !== 2) {
|
|
122
|
-
throw new Error('Tessl skill verification did not pass');
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
id: 'TESSL-06',
|
|
128
|
-
desc: 'publish workflow validates and exports before secret-gated Tessl publish',
|
|
129
|
-
fn: () => {
|
|
130
|
-
const workflow = fs.readFileSync(
|
|
131
|
-
path.join(ROOT, '.github', 'workflows', 'publish-tessl.yml'),
|
|
132
|
-
'utf8'
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
if (!/npm run tessl:verify/.test(workflow)) {
|
|
136
|
-
throw new Error('Workflow must verify Tessl tiles before publish');
|
|
137
|
-
}
|
|
138
|
-
if (!/npm run tessl:export -- --out-dir=.artifacts\/tessl/.test(workflow)) {
|
|
139
|
-
throw new Error('Workflow must export Tessl tiles before publish');
|
|
140
|
-
}
|
|
141
|
-
if (!/Plan Tessl publish action/.test(workflow)) {
|
|
142
|
-
throw new Error('Workflow must plan Tessl publish before publish matrix runs');
|
|
143
|
-
}
|
|
144
|
-
if (!/TESSL_API_TOKEN:\s*\$\{\{\s*secrets\.TESSL_API_TOKEN\s*\}\}/.test(workflow)) {
|
|
145
|
-
throw new Error('Workflow gate must source TESSL_API_TOKEN from secrets');
|
|
146
|
-
}
|
|
147
|
-
if (!/if:\s*\$\{\{\s*needs\.plan_publish\.outputs\.should_publish == 'true'\s*\}\}/.test(workflow)) {
|
|
148
|
-
throw new Error('Workflow publish job must be gated on the plan_publish output');
|
|
149
|
-
}
|
|
150
|
-
if (!/uses:\s*tesslio\/publish@main/.test(workflow)) {
|
|
151
|
-
throw new Error('Workflow must use the official Tessl publish action');
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
];
|
|
156
|
-
|
|
157
|
-
console.log('Tessl Distribution - Proof Gate\n');
|
|
158
|
-
console.log('Checking requirements:\n');
|
|
159
|
-
|
|
160
|
-
for (const check of checks) {
|
|
161
|
-
try {
|
|
162
|
-
await check.fn();
|
|
163
|
-
results.passed++;
|
|
164
|
-
results.requirements[check.id] = { status: 'pass', desc: check.desc };
|
|
165
|
-
console.log(` PASS ${check.id}: ${check.desc}`);
|
|
166
|
-
} catch (error) {
|
|
167
|
-
results.failed++;
|
|
168
|
-
results.requirements[check.id] = {
|
|
169
|
-
status: 'fail',
|
|
170
|
-
desc: check.desc,
|
|
171
|
-
error: error.message,
|
|
172
|
-
};
|
|
173
|
-
console.error(` FAIL ${check.id}: ${error.message}`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
178
|
-
fs.mkdirSync(proofDir, { recursive: true });
|
|
179
|
-
|
|
180
|
-
const report = {
|
|
181
|
-
phase: '12-tessl-distribution',
|
|
182
|
-
generatedAt: new Date().toISOString(),
|
|
183
|
-
passed: results.passed,
|
|
184
|
-
failed: results.failed,
|
|
185
|
-
total: checks.length,
|
|
186
|
-
requirements: results.requirements,
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
fs.writeFileSync(reportJson, JSON.stringify(report, null, 2) + '\n');
|
|
190
|
-
|
|
191
|
-
const markdown = [
|
|
192
|
-
'# Tessl Distribution Proof Report',
|
|
193
|
-
'',
|
|
194
|
-
`Generated: ${report.generatedAt}`,
|
|
195
|
-
`Result: ${results.passed}/${checks.length} passed`,
|
|
196
|
-
'',
|
|
197
|
-
'## Requirements',
|
|
198
|
-
'',
|
|
199
|
-
...Object.entries(results.requirements).map(([id, requirement]) => {
|
|
200
|
-
const checkbox = requirement.status === 'pass' ? '[x]' : '[ ]';
|
|
201
|
-
const errorLine = requirement.error ? `\n - Error: \`${requirement.error}\`` : '';
|
|
202
|
-
return `- ${checkbox} **${id}**: ${requirement.desc}${errorLine}`;
|
|
203
|
-
}),
|
|
204
|
-
'',
|
|
205
|
-
`${results.passed} passed, ${results.failed} failed`,
|
|
206
|
-
'',
|
|
207
|
-
].join('\n');
|
|
208
|
-
|
|
209
|
-
fs.writeFileSync(reportMd, `${markdown}\n`);
|
|
210
|
-
|
|
211
|
-
console.log(`\nResult: ${results.passed} passed, ${results.failed} failed`);
|
|
212
|
-
console.log(`Report: ${reportJson}`);
|
|
213
|
-
|
|
214
|
-
if (results.failed > 0) {
|
|
215
|
-
process.exitCode = 1;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (require.main === module) {
|
|
220
|
-
run().catch((error) => {
|
|
221
|
-
console.error(error.message || String(error));
|
|
222
|
-
process.exit(1);
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
module.exports = {
|
|
227
|
-
resolveProofPaths,
|
|
228
|
-
run,
|
|
229
|
-
};
|
|
@@ -1,325 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* prove-training-export.js
|
|
4
|
-
*
|
|
5
|
-
* Smoke-test gate for Phase 10: Training Export
|
|
6
|
-
* Verifies all export formats + DPO validation gate work end-to-end.
|
|
7
|
-
* Writes machine-readable JSON + human-readable markdown to proof/.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
'use strict';
|
|
11
|
-
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const os = require('os');
|
|
14
|
-
const path = require('path');
|
|
15
|
-
const { execSync } = require('child_process');
|
|
16
|
-
const { ensureDir } = require('./fs-utils');
|
|
17
|
-
|
|
18
|
-
const ROOT = path.join(__dirname, '..');
|
|
19
|
-
function getProofDir() {
|
|
20
|
-
return process.env.THUMBGATE_PROOF_DIR || path.join(ROOT, 'proof');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
function runTests() {
|
|
25
|
-
try {
|
|
26
|
-
const output = execSync('node --test tests/training-export.test.js', {
|
|
27
|
-
cwd: ROOT,
|
|
28
|
-
encoding: 'utf-8',
|
|
29
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
30
|
-
});
|
|
31
|
-
return output;
|
|
32
|
-
} catch (err) {
|
|
33
|
-
return err.stdout || err.stderr || String(err);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function parseTestOutput(output) {
|
|
38
|
-
const passMatch = output.match(/ℹ pass (\d+)/);
|
|
39
|
-
const failMatch = output.match(/ℹ fail (\d+)/);
|
|
40
|
-
const passed = passMatch ? parseInt(passMatch[1], 10) : 0;
|
|
41
|
-
const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
42
|
-
return { passed, failed };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function makeFeedbackEntry(overrides) {
|
|
46
|
-
return {
|
|
47
|
-
id: `fb_${Date.now()}_test`,
|
|
48
|
-
timestamp: new Date().toISOString(),
|
|
49
|
-
signal: 'positive',
|
|
50
|
-
feedback: 'up',
|
|
51
|
-
reward: 1,
|
|
52
|
-
context: 'Test context for smoke test',
|
|
53
|
-
tags: ['testing'],
|
|
54
|
-
richContext: { domain: 'testing', outcomeCategory: 'quick-success' },
|
|
55
|
-
...overrides,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// ---------------------------------------------------------------------------
|
|
60
|
-
// Smoke test: PyTorch JSON export (XPRT-01)
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
function smokePyTorchExport() {
|
|
63
|
-
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'prove-xprt1-'));
|
|
64
|
-
try {
|
|
65
|
-
delete require.cache[require.resolve('./export-training.js')];
|
|
66
|
-
const m = require('./export-training.js');
|
|
67
|
-
|
|
68
|
-
fs.mkdirSync(path.join(tmpDir, 'training-data'), { recursive: true });
|
|
69
|
-
|
|
70
|
-
const entries = [
|
|
71
|
-
makeFeedbackEntry({ context: 'Implemented TDD correctly' }),
|
|
72
|
-
makeFeedbackEntry({ signal: 'negative', feedback: 'down', reward: -1, context: 'Skipped validation' }),
|
|
73
|
-
];
|
|
74
|
-
fs.writeFileSync(
|
|
75
|
-
path.join(tmpDir, 'feedback-log.jsonl'),
|
|
76
|
-
entries.map((e) => JSON.stringify(e)).join('\n')
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
const outPath = path.join(tmpDir, 'pytorch.json');
|
|
80
|
-
const result = m.exportPyTorchJSON(tmpDir, outPath);
|
|
81
|
-
|
|
82
|
-
if (!fs.existsSync(result.outputPath)) throw new Error('Output file not created');
|
|
83
|
-
const data = JSON.parse(fs.readFileSync(result.outputPath, 'utf-8'));
|
|
84
|
-
if (!data.metadata) throw new Error('Missing metadata');
|
|
85
|
-
if (data.metadata.format !== 'pytorch-dpo') throw new Error('Wrong format');
|
|
86
|
-
if (!Array.isArray(data.pairs)) throw new Error('Missing pairs array');
|
|
87
|
-
if (!Array.isArray(data.sequences)) throw new Error('Missing sequences array');
|
|
88
|
-
|
|
89
|
-
// Verify pair structure when pairs exist
|
|
90
|
-
if (data.pairs.length > 0) {
|
|
91
|
-
const pair = data.pairs[0];
|
|
92
|
-
if (!('prompt' in pair)) throw new Error('pair missing prompt');
|
|
93
|
-
if (!('chosen' in pair)) throw new Error('pair missing chosen');
|
|
94
|
-
if (!('rejected' in pair)) throw new Error('pair missing rejected');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return { passed: true, pairCount: result.pairCount, format: data.metadata.format };
|
|
98
|
-
} catch (err) {
|
|
99
|
-
return { passed: false, error: err.message };
|
|
100
|
-
} finally {
|
|
101
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// ---------------------------------------------------------------------------
|
|
106
|
-
// Smoke test: CSV export (XPRT-02)
|
|
107
|
-
// ---------------------------------------------------------------------------
|
|
108
|
-
function smokeCsvExport() {
|
|
109
|
-
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'prove-xprt2-'));
|
|
110
|
-
try {
|
|
111
|
-
delete require.cache[require.resolve('./export-training.js')];
|
|
112
|
-
const m = require('./export-training.js');
|
|
113
|
-
|
|
114
|
-
fs.mkdirSync(path.join(tmpDir, 'training-data'), { recursive: true });
|
|
115
|
-
|
|
116
|
-
const entries = [
|
|
117
|
-
makeFeedbackEntry({ context: 'Works great' }),
|
|
118
|
-
makeFeedbackEntry({ signal: 'negative', feedback: 'down', reward: -1, context: 'Has issues' }),
|
|
119
|
-
];
|
|
120
|
-
fs.writeFileSync(
|
|
121
|
-
path.join(tmpDir, 'feedback-log.jsonl'),
|
|
122
|
-
entries.map((e) => JSON.stringify(e)).join('\n')
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
const outPath = path.join(tmpDir, 'summary.csv');
|
|
126
|
-
const result = m.exportCSV(tmpDir, outPath);
|
|
127
|
-
|
|
128
|
-
if (!fs.existsSync(result.outputPath)) throw new Error('CSV not created');
|
|
129
|
-
const csv = fs.readFileSync(result.outputPath, 'utf-8');
|
|
130
|
-
const lines = csv.split('\n');
|
|
131
|
-
const headers = lines[0].split(',');
|
|
132
|
-
|
|
133
|
-
const required = ['id', 'timestamp', 'signal', 'reward', 'context'];
|
|
134
|
-
for (const h of required) {
|
|
135
|
-
if (!headers.includes(h)) throw new Error(`CSV missing column: ${h}`);
|
|
136
|
-
}
|
|
137
|
-
if (result.rowCount !== 2) throw new Error(`Expected 2 rows, got ${result.rowCount}`);
|
|
138
|
-
|
|
139
|
-
return { passed: true, rowCount: result.rowCount, headers };
|
|
140
|
-
} catch (err) {
|
|
141
|
-
return { passed: false, error: err.message };
|
|
142
|
-
} finally {
|
|
143
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// ---------------------------------------------------------------------------
|
|
148
|
-
// Smoke test: Action analysis (XPRT-03)
|
|
149
|
-
// ---------------------------------------------------------------------------
|
|
150
|
-
function smokeActionAnalysis() {
|
|
151
|
-
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'prove-xprt3-'));
|
|
152
|
-
try {
|
|
153
|
-
delete require.cache[require.resolve('./export-training.js')];
|
|
154
|
-
const m = require('./export-training.js');
|
|
155
|
-
|
|
156
|
-
fs.mkdirSync(path.join(tmpDir, 'training-data'), { recursive: true });
|
|
157
|
-
fs.writeFileSync(path.join(tmpDir, 'feedback-log.jsonl'), '');
|
|
158
|
-
|
|
159
|
-
const outPath = path.join(tmpDir, 'actions.json');
|
|
160
|
-
const { report } = m.exportActionAnalysis(tmpDir, outPath);
|
|
161
|
-
|
|
162
|
-
if (!report.summary) throw new Error('Missing summary');
|
|
163
|
-
if (!report.actionPatterns) throw new Error('Missing actionPatterns');
|
|
164
|
-
if (!Array.isArray(report.topFailureModes)) throw new Error('Missing topFailureModes');
|
|
165
|
-
if (!Array.isArray(report.recommendations)) throw new Error('Missing recommendations');
|
|
166
|
-
|
|
167
|
-
return { passed: true, fields: Object.keys(report) };
|
|
168
|
-
} catch (err) {
|
|
169
|
-
return { passed: false, error: err.message };
|
|
170
|
-
} finally {
|
|
171
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// ---------------------------------------------------------------------------
|
|
176
|
-
// Smoke test: validateMemoryStructure gate (XPRT-04)
|
|
177
|
-
// ---------------------------------------------------------------------------
|
|
178
|
-
function smokeValidateMemoryStructure() {
|
|
179
|
-
try {
|
|
180
|
-
delete require.cache[require.resolve('./export-training.js')];
|
|
181
|
-
const m = require('./export-training.js');
|
|
182
|
-
|
|
183
|
-
// Valid entry
|
|
184
|
-
const valid = m.validateMemoryStructure({
|
|
185
|
-
title: 'SUCCESS: Test passed',
|
|
186
|
-
content: 'The implementation was correct and tests verified.',
|
|
187
|
-
category: 'learning',
|
|
188
|
-
tags: ['testing'],
|
|
189
|
-
});
|
|
190
|
-
if (!valid.valid) throw new Error('Valid entry rejected: ' + valid.issues.join(', '));
|
|
191
|
-
|
|
192
|
-
// Missing 'chosen' in DPO export
|
|
193
|
-
const missingChosen = m.validateMemoryStructure({
|
|
194
|
-
title: 'PREFERENCE: Good vs bad',
|
|
195
|
-
content: 'Comparison of approaches.',
|
|
196
|
-
category: 'preference',
|
|
197
|
-
tags: ['arch'],
|
|
198
|
-
_dpoExport: true,
|
|
199
|
-
prompt: 'Which approach?',
|
|
200
|
-
// chosen is missing
|
|
201
|
-
rejected: 'The bad approach',
|
|
202
|
-
});
|
|
203
|
-
if (missingChosen.valid) throw new Error('Should have rejected missing chosen field');
|
|
204
|
-
if (!missingChosen.issues.some((i) => i.includes('chosen'))) {
|
|
205
|
-
throw new Error('Issue should mention chosen field');
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return {
|
|
209
|
-
passed: true,
|
|
210
|
-
validEntryAccepted: valid.valid,
|
|
211
|
-
missingChosenRejected: !missingChosen.valid,
|
|
212
|
-
missingChosenIssues: missingChosen.issues,
|
|
213
|
-
};
|
|
214
|
-
} catch (err) {
|
|
215
|
-
return { passed: false, error: err.message };
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// ---------------------------------------------------------------------------
|
|
220
|
-
// Main
|
|
221
|
-
// ---------------------------------------------------------------------------
|
|
222
|
-
async function main() {
|
|
223
|
-
console.log('Running Phase 10: Training Export proof gate...\n');
|
|
224
|
-
|
|
225
|
-
const testOutput = runTests();
|
|
226
|
-
const { passed: testsPassed, failed: testsFailed } = parseTestOutput(testOutput);
|
|
227
|
-
|
|
228
|
-
const pytorch = smokePyTorchExport();
|
|
229
|
-
const csv = smokeCsvExport();
|
|
230
|
-
const actions = smokeActionAnalysis();
|
|
231
|
-
const gate = smokeValidateMemoryStructure();
|
|
232
|
-
|
|
233
|
-
const allPassed = testsFailed === 0 && pytorch.passed && csv.passed && actions.passed && gate.passed;
|
|
234
|
-
|
|
235
|
-
const report = {
|
|
236
|
-
phase: 10,
|
|
237
|
-
name: 'Training Export',
|
|
238
|
-
requirements: ['XPRT-01', 'XPRT-02', 'XPRT-03', 'XPRT-04', 'XPRT-05'],
|
|
239
|
-
generatedAt: new Date().toISOString(),
|
|
240
|
-
testResults: {
|
|
241
|
-
passed: testsPassed,
|
|
242
|
-
failed: testsFailed,
|
|
243
|
-
suiteFile: 'tests/training-export.test.js',
|
|
244
|
-
},
|
|
245
|
-
smokeTests: {
|
|
246
|
-
pytorchExport: pytorch,
|
|
247
|
-
csvExport: csv,
|
|
248
|
-
actionAnalysis: actions,
|
|
249
|
-
validateMemoryStructure: gate,
|
|
250
|
-
},
|
|
251
|
-
overallPassed: allPassed,
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
const proofDir = getProofDir();
|
|
255
|
-
ensureDir(proofDir);
|
|
256
|
-
const jsonPath = path.join(proofDir, 'training-export-report.json');
|
|
257
|
-
const mdPath = path.join(proofDir, 'training-export-report.md');
|
|
258
|
-
|
|
259
|
-
fs.writeFileSync(jsonPath, JSON.stringify(report, null, 2));
|
|
260
|
-
|
|
261
|
-
const status = allPassed ? 'PASSED' : 'FAILED';
|
|
262
|
-
const md = `# Phase 10: Training Export — Proof Report
|
|
263
|
-
|
|
264
|
-
**Status:** ${status}
|
|
265
|
-
**Generated:** ${report.generatedAt}
|
|
266
|
-
**Requirements:** ${report.requirements.join(', ')}
|
|
267
|
-
|
|
268
|
-
## Test Results
|
|
269
|
-
|
|
270
|
-
| Suite | Passed | Failed |
|
|
271
|
-
|-------|--------|--------|
|
|
272
|
-
| training-export.test.js | ${testsPassed} | ${testsFailed} |
|
|
273
|
-
|
|
274
|
-
## Smoke Tests
|
|
275
|
-
|
|
276
|
-
### PyTorch JSON Export (XPRT-01)
|
|
277
|
-
- Passed: ${pytorch.passed}
|
|
278
|
-
${pytorch.passed ? `- Pair count: ${pytorch.pairCount}\n- Format: ${pytorch.format}` : `- Error: ${pytorch.error}`}
|
|
279
|
-
|
|
280
|
-
### CSV Summary Export (XPRT-02)
|
|
281
|
-
- Passed: ${csv.passed}
|
|
282
|
-
${csv.passed ? `- Row count: ${csv.rowCount}\n- Headers: ${csv.headers ? csv.headers.join(', ') : 'N/A'}` : `- Error: ${csv.error}`}
|
|
283
|
-
|
|
284
|
-
### Action Analysis Report (XPRT-03)
|
|
285
|
-
- Passed: ${actions.passed}
|
|
286
|
-
${actions.passed ? `- Report fields: ${actions.fields ? actions.fields.join(', ') : 'N/A'}` : `- Error: ${actions.error}`}
|
|
287
|
-
|
|
288
|
-
### DPO Export Gate — validateMemoryStructure (XPRT-04)
|
|
289
|
-
- Passed: ${gate.passed}
|
|
290
|
-
${gate.passed ? `- Valid entry accepted: ${gate.validEntryAccepted}\n- Missing 'chosen' field rejected: ${gate.missingChosenRejected}` : `- Error: ${gate.error}`}
|
|
291
|
-
|
|
292
|
-
## Requirements Coverage
|
|
293
|
-
|
|
294
|
-
| Requirement | Description | Status |
|
|
295
|
-
|-------------|-------------|--------|
|
|
296
|
-
| XPRT-01 | PyTorch JSON export with prompt/chosen/rejected pairs | ${pytorch.passed ? 'PASS' : 'FAIL'} |
|
|
297
|
-
| XPRT-02 | CSV summary export with correct headers and escaping | ${csv.passed ? 'PASS' : 'FAIL'} |
|
|
298
|
-
| XPRT-03 | Action analysis report from feedback sequences | ${actions.passed ? 'PASS' : 'FAIL'} |
|
|
299
|
-
| XPRT-04 | validateMemoryStructure() gates DPO export | ${gate.passed ? 'PASS' : 'FAIL'} |
|
|
300
|
-
| XPRT-05 | All export features have unit tests (${testsPassed} tests, ${testsFailed} failures) | ${testsFailed === 0 ? 'PASS' : 'FAIL'} |
|
|
301
|
-
|
|
302
|
-
## Files Created
|
|
303
|
-
|
|
304
|
-
- \`scripts/export-training.js\` — PyTorch JSON, CSV, action analysis exports + validateMemoryStructure gate
|
|
305
|
-
- \`tests/training-export.test.js\` — ${testsPassed} unit tests covering all formats, gate rejection, edge cases
|
|
306
|
-
- \`scripts/prove-training-export.js\` — This proof gate script
|
|
307
|
-
`;
|
|
308
|
-
|
|
309
|
-
fs.writeFileSync(mdPath, md);
|
|
310
|
-
|
|
311
|
-
console.log(`Status: ${status}`);
|
|
312
|
-
console.log(`Tests: ${testsPassed} passed, ${testsFailed} failed`);
|
|
313
|
-
console.log(`PyTorch smoke: ${pytorch.passed ? 'PASS' : 'FAIL'}`);
|
|
314
|
-
console.log(`CSV smoke: ${csv.passed ? 'PASS' : 'FAIL'}`);
|
|
315
|
-
console.log(`Action analysis smoke: ${actions.passed ? 'PASS' : 'FAIL'}`);
|
|
316
|
-
console.log(`validateMemoryStructure gate: ${gate.passed ? 'PASS' : 'FAIL'}`);
|
|
317
|
-
console.log(`\nReport written to: ${mdPath}`);
|
|
318
|
-
|
|
319
|
-
process.exit(allPassed ? 0 : 1);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
main().catch((err) => {
|
|
323
|
-
console.error('prove-training-export failed:', err.message);
|
|
324
|
-
process.exit(1);
|
|
325
|
-
});
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const fs = require('node:fs');
|
|
3
|
-
const path = require('node:path');
|
|
4
|
-
const { ensureDir } = require('./fs-utils');
|
|
5
|
-
const {
|
|
6
|
-
runWorkflowContractValidation,
|
|
7
|
-
} = require('./validate-workflow-contract');
|
|
8
|
-
|
|
9
|
-
const PROJECT_ROOT = path.join(__dirname, '..');
|
|
10
|
-
const DEFAULT_PROOF_DIR = path.join(PROJECT_ROOT, 'proof', 'workflow-contract');
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
function toMarkdown(report) {
|
|
14
|
-
const lines = [
|
|
15
|
-
'# Workflow Contract Proof Report',
|
|
16
|
-
'',
|
|
17
|
-
`Generated: ${report.generatedAt}`,
|
|
18
|
-
'',
|
|
19
|
-
`Summary: ${report.summary.passed} passed, ${report.summary.failed} failed`,
|
|
20
|
-
'',
|
|
21
|
-
'## Validated Files',
|
|
22
|
-
'',
|
|
23
|
-
...Object.values(report.files).map((filePath) => `- \`${filePath}\``),
|
|
24
|
-
'',
|
|
25
|
-
'## Checks',
|
|
26
|
-
'',
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
report.checks.forEach((check) => {
|
|
30
|
-
lines.push(`- ${check.name}: ${check.passed ? 'PASS' : 'FAIL'}`);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
if (report.issues.length > 0) {
|
|
34
|
-
lines.push('');
|
|
35
|
-
lines.push('## Issues');
|
|
36
|
-
lines.push('');
|
|
37
|
-
report.issues.forEach((issue) => {
|
|
38
|
-
lines.push(`- ${issue}`);
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return `${lines.join('\n')}\n`;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function runWorkflowContractProof(options = {}) {
|
|
46
|
-
const proofDir = options.proofDir || process.env.THUMBGATE_WORKFLOW_CONTRACT_PROOF_DIR || DEFAULT_PROOF_DIR;
|
|
47
|
-
const writeArtifacts = options.writeArtifacts !== false;
|
|
48
|
-
const validation = runWorkflowContractValidation({ projectRoot: options.projectRoot || PROJECT_ROOT });
|
|
49
|
-
|
|
50
|
-
const report = {
|
|
51
|
-
generatedAt: validation.generatedAt,
|
|
52
|
-
files: validation.files,
|
|
53
|
-
checks: [
|
|
54
|
-
{
|
|
55
|
-
name: 'workflow.contract.complete',
|
|
56
|
-
passed: validation.ok,
|
|
57
|
-
details: {
|
|
58
|
-
headingsFound: validation.details.workflow ? validation.details.workflow.headingsFound : [],
|
|
59
|
-
proofCommandsFound: validation.details.workflow ? validation.details.workflow.proofCommandsFound : [],
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
name: 'issue.template.complete',
|
|
64
|
-
passed: validation.ok,
|
|
65
|
-
details: {
|
|
66
|
-
fieldIdsFound: validation.details.issueTemplate ? validation.details.issueTemplate.fieldIdsFound : [],
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: 'pull_request.template.complete',
|
|
71
|
-
passed: validation.ok,
|
|
72
|
-
details: {
|
|
73
|
-
sectionsFound: validation.details.pullRequestTemplate ? validation.details.pullRequestTemplate.sectionsFound : [],
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
name: 'readme.links.contracts',
|
|
78
|
-
passed: validation.ok,
|
|
79
|
-
details: validation.details.readme || {},
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
issues: validation.issues.slice(),
|
|
83
|
-
summary: {
|
|
84
|
-
passed: validation.ok ? 4 : 0,
|
|
85
|
-
failed: validation.ok ? 0 : 4,
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
if (writeArtifacts) {
|
|
90
|
-
ensureDir(proofDir);
|
|
91
|
-
fs.writeFileSync(path.join(proofDir, 'report.json'), JSON.stringify(report, null, 2));
|
|
92
|
-
fs.writeFileSync(path.join(proofDir, 'report.md'), toMarkdown(report));
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return report;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (require.main === module) {
|
|
99
|
-
const report = runWorkflowContractProof();
|
|
100
|
-
if (report.summary.failed > 0) {
|
|
101
|
-
console.error(toMarkdown(report));
|
|
102
|
-
process.exit(1);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
console.log(toMarkdown(report));
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
module.exports = {
|
|
109
|
-
DEFAULT_PROOF_DIR,
|
|
110
|
-
runWorkflowContractProof,
|
|
111
|
-
toMarkdown,
|
|
112
|
-
};
|