thumbgate 1.14.1 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +6 -6
- package/.claude-plugin/plugin.json +3 -3
- package/.well-known/llms.txt +5 -5
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +60 -35
- package/adapters/chatgpt/openapi.yaml +118 -2
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/mcp/server-stdio.js +217 -84
- package/adapters/opencode/opencode.json +1 -1
- package/bench/prompt-eval-suite.json +5 -1
- package/bin/cli.js +211 -8
- package/config/enforcement.json +59 -7
- package/config/evals/agent-safety-eval.json +338 -22
- package/config/gates/default.json +33 -0
- package/config/gates/routine.json +43 -0
- package/config/github-about.json +3 -3
- package/config/mcp-allowlists.json +4 -0
- package/config/merge-quality-checks.json +2 -1
- package/config/model-candidates.json +131 -0
- package/openapi/openapi.yaml +118 -2
- package/package.json +70 -51
- package/public/blog.html +7 -7
- package/public/codex-plugin.html +13 -7
- package/public/compare.html +29 -23
- package/public/dashboard.html +105 -12
- package/public/guide.html +28 -28
- package/public/index.html +233 -97
- package/public/learn.html +87 -20
- package/public/lessons.html +26 -2
- package/public/numbers.html +271 -0
- package/public/pro.html +89 -19
- package/scripts/agent-audit-trace.js +55 -0
- package/scripts/agent-memory-lifecycle.js +96 -0
- package/scripts/agent-readiness-plan.js +118 -0
- package/scripts/agentic-data-pipeline.js +21 -1
- package/scripts/agents-sdk-sandbox-plan.js +57 -0
- package/scripts/ai-org-governance.js +98 -0
- package/scripts/ai-search-distribution.js +43 -0
- package/scripts/artifact-agent-plan.js +81 -0
- package/scripts/billing.js +27 -8
- package/scripts/cli-feedback.js +2 -1
- package/scripts/cli-schema.js +60 -5
- package/scripts/code-mode-mcp-plan.js +71 -0
- package/scripts/commercial-offer.js +1 -1
- package/scripts/context-engine.js +1 -2
- package/scripts/context-manager.js +4 -1
- package/scripts/contextfs.js +214 -32
- package/scripts/dashboard-render-spec.js +1 -1
- package/scripts/dashboard.js +275 -9
- package/scripts/decision-journal.js +13 -3
- package/scripts/document-workflow-governance.js +62 -0
- package/scripts/enterprise-agent-rollout.js +34 -0
- package/scripts/experience-replay-governance.js +69 -0
- package/scripts/export-hf-dataset.js +1 -1
- package/scripts/feedback-loop.js +141 -9
- package/scripts/feedback-to-rules.js +17 -23
- package/scripts/gates-engine.js +4 -6
- package/scripts/growth-campaigns.js +49 -0
- package/scripts/harness-selector.js +145 -1
- package/scripts/hybrid-supervisor-agent.js +64 -0
- package/scripts/inference-cache-policy.js +72 -0
- package/scripts/inference-economics.js +53 -0
- package/scripts/internal-agent-bootstrap.js +12 -2
- package/scripts/knowledge-layer-plan.js +108 -0
- package/scripts/lesson-canonical.js +181 -0
- package/scripts/lesson-db.js +71 -10
- package/scripts/lesson-inference.js +183 -44
- package/scripts/lesson-search.js +4 -1
- package/scripts/lesson-synthesis.js +23 -2
- package/scripts/llm-client.js +157 -26
- package/scripts/mailer/resend-mailer.js +112 -1
- package/scripts/mcp-transport-strategy.js +66 -0
- package/scripts/memory-store-governance.js +60 -0
- package/scripts/meta-agent-loop.js +7 -13
- package/scripts/model-access-eligibility.js +38 -0
- package/scripts/model-migration-readiness.js +55 -0
- package/scripts/native-messaging-audit.js +514 -0
- package/scripts/operational-integrity.js +96 -3
- package/scripts/otel-declarative-config.js +56 -0
- package/scripts/perplexity-client.js +1 -1
- package/scripts/post-training-governance.js +34 -0
- package/scripts/pr-manager.js +47 -7
- package/scripts/private-core-boundary.js +72 -0
- package/scripts/production-agent-readiness.js +40 -0
- package/scripts/profile-router.js +16 -1
- package/scripts/prompt-eval.js +564 -32
- package/scripts/prompt-programs.js +93 -0
- package/scripts/provider-action-normalizer.js +585 -0
- package/scripts/rule-validator.js +285 -0
- package/scripts/scaling-law-claims.js +60 -0
- package/scripts/security-scanner.js +1 -1
- package/scripts/self-distill-agent.js +7 -32
- package/scripts/seo-gsd.js +400 -43
- package/scripts/skill-rag-router.js +53 -0
- package/scripts/spec-gate.js +1 -1
- package/scripts/student-consistent-training.js +73 -0
- package/scripts/synthetic-data-provenance.js +98 -0
- package/scripts/task-context-result.js +81 -0
- package/scripts/telemetry-analytics.js +149 -0
- package/scripts/thompson-sampling.js +2 -2
- package/scripts/token-savings.js +7 -6
- package/scripts/token-tco.js +46 -0
- package/scripts/tool-registry.js +75 -3
- package/scripts/verification-loop.js +10 -1
- package/scripts/verifier-scoring.js +71 -0
- package/scripts/workflow-sentinel.js +284 -28
- package/scripts/workspace-agent-routines.js +118 -0
- package/skills/thumbgate/SKILL.md +1 -1
- package/src/api/server.js +434 -120
- package/.claude-plugin/README.md +0 -170
- package/adapters/README.md +0 -12
- package/scripts/analytics-report.js +0 -328
- package/scripts/autonomous-workflow.js +0 -377
- package/scripts/billing-setup.js +0 -109
- package/scripts/creator-campaigns.js +0 -239
- package/scripts/cross-encoder-reranker.js +0 -235
- package/scripts/daemon-manager.js +0 -108
- package/scripts/decision-trace.js +0 -354
- package/scripts/delegation-runtime.js +0 -896
- package/scripts/dispatch-brief.js +0 -159
- package/scripts/distribution-surfaces.js +0 -110
- package/scripts/feedback-history-distiller.js +0 -382
- package/scripts/funnel-analytics.js +0 -35
- package/scripts/history-distiller.js +0 -200
- package/scripts/hosted-job-launcher.js +0 -256
- package/scripts/intent-router.js +0 -392
- package/scripts/lesson-reranker.js +0 -263
- package/scripts/lesson-retrieval.js +0 -148
- package/scripts/managed-lesson-agent.js +0 -183
- package/scripts/operational-dashboard.js +0 -103
- package/scripts/operational-summary.js +0 -129
- package/scripts/operator-artifacts.js +0 -608
- package/scripts/optimize-context.js +0 -17
- package/scripts/org-dashboard.js +0 -206
- package/scripts/partner-orchestration.js +0 -146
- package/scripts/predictive-insights.js +0 -356
- package/scripts/pulse.js +0 -80
- package/scripts/reflector-agent.js +0 -221
- package/scripts/sales-pipeline.js +0 -681
- package/scripts/session-episode-store.js +0 -329
- package/scripts/session-health-sensor.js +0 -242
- package/scripts/session-report.js +0 -120
- package/scripts/swarm-coordinator.js +0 -81
- package/scripts/tool-kpi-tracker.js +0 -12
- package/scripts/webhook-delivery.js +0 -62
- package/scripts/workflow-sprint-intake.js +0 -475
- package/skills/agent-memory/SKILL.md +0 -97
- package/skills/solve-architecture-autonomy/SKILL.md +0 -17
- package/skills/solve-architecture-autonomy/tool.js +0 -33
- package/skills/thumbgate-feedback/SKILL.md +0 -49
|
@@ -1,377 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const fs = require('node:fs');
|
|
5
|
-
const path = require('node:path');
|
|
6
|
-
|
|
7
|
-
const { ensureDir } = require('./fs-utils');
|
|
8
|
-
const {
|
|
9
|
-
executeJob,
|
|
10
|
-
readJobState,
|
|
11
|
-
resumeJob,
|
|
12
|
-
} = require('./async-job-runner');
|
|
13
|
-
const {
|
|
14
|
-
createCheckpoint,
|
|
15
|
-
advanceCheckpoint,
|
|
16
|
-
loadCheckpoint,
|
|
17
|
-
saveCheckpoint,
|
|
18
|
-
} = require('./workflow-gate-checkpoint');
|
|
19
|
-
const { appendWorkflowRun } = require('./workflow-runs');
|
|
20
|
-
|
|
21
|
-
function normalizeText(value) {
|
|
22
|
-
if (value === undefined || value === null) return '';
|
|
23
|
-
return String(value).trim();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function slugify(value, fallback = 'workflow') {
|
|
27
|
-
// Avoid any `-+` quantifier in an edge-anchored regex (Sonar javascript:S5852
|
|
28
|
-
// still flags even the anchored form). Strip edge dashes with a linear scan.
|
|
29
|
-
const collapsed = normalizeText(value).toLowerCase().replace(/[^a-z0-9]+/g, '-');
|
|
30
|
-
let start = 0;
|
|
31
|
-
let end = collapsed.length;
|
|
32
|
-
while (start < end && collapsed.charCodeAt(start) === 45) start += 1;
|
|
33
|
-
while (end > start && collapsed.charCodeAt(end - 1) === 45) end -= 1;
|
|
34
|
-
const normalized = collapsed.slice(start, end);
|
|
35
|
-
return normalized || fallback;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function getWorkflowPaths(workflowId, cwd = process.cwd()) {
|
|
39
|
-
const rootDir = path.join(cwd, '.thumbgate', 'autonomous-workflows', workflowId);
|
|
40
|
-
return {
|
|
41
|
-
rootDir,
|
|
42
|
-
checkpointPath: path.join(rootDir, 'checkpoint.json'),
|
|
43
|
-
reportJsonPath: path.join(rootDir, 'report.json'),
|
|
44
|
-
reportMdPath: path.join(rootDir, 'report.md'),
|
|
45
|
-
planPath: path.join(rootDir, 'plan.json'),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function normalizePlan(input, workflowId) {
|
|
50
|
-
if (Array.isArray(input)) {
|
|
51
|
-
return {
|
|
52
|
-
workflowId,
|
|
53
|
-
summary: input.map((step) => normalizeText(step)).filter(Boolean).join(' | ') || 'Execution plan ready',
|
|
54
|
-
steps: input
|
|
55
|
-
.map((step, index) => ({
|
|
56
|
-
id: `step_${index + 1}`,
|
|
57
|
-
description: normalizeText(step),
|
|
58
|
-
}))
|
|
59
|
-
.filter((step) => step.description),
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (input && typeof input === 'object') {
|
|
64
|
-
const steps = Array.isArray(input.steps)
|
|
65
|
-
? input.steps
|
|
66
|
-
.map((step, index) => {
|
|
67
|
-
if (typeof step === 'string') {
|
|
68
|
-
return {
|
|
69
|
-
id: `step_${index + 1}`,
|
|
70
|
-
description: normalizeText(step),
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (step && typeof step === 'object') {
|
|
75
|
-
return {
|
|
76
|
-
id: normalizeText(step.id) || `step_${index + 1}`,
|
|
77
|
-
description: normalizeText(step.description || step.summary || step.name),
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return null;
|
|
82
|
-
})
|
|
83
|
-
.filter(Boolean)
|
|
84
|
-
: [];
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
workflowId,
|
|
88
|
-
summary: normalizeText(input.summary) || steps.map((step) => step.description).join(' | ') || 'Execution plan ready',
|
|
89
|
-
steps,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const summary = normalizeText(input) || 'Execution plan ready';
|
|
94
|
-
return {
|
|
95
|
-
workflowId,
|
|
96
|
-
summary,
|
|
97
|
-
steps: summary ? [{ id: 'step_1', description: summary }] : [],
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function buildDefaultPlan(spec, workflowId) {
|
|
102
|
-
const executionSteps = Array.isArray(spec.stages)
|
|
103
|
-
? spec.stages.map((stage, index) => normalizeText(stage && (stage.name || stage.context || stage.command)) || `Stage ${index + 1}`)
|
|
104
|
-
: [];
|
|
105
|
-
|
|
106
|
-
return normalizePlan({
|
|
107
|
-
summary: normalizeText(spec.planSummary) || `Run ${executionSteps.length || 0} execution stage(s) and verify output`,
|
|
108
|
-
steps: [
|
|
109
|
-
{ id: 'intent', description: normalizeText(spec.intent) || 'Intent captured' },
|
|
110
|
-
{ id: 'plan', description: 'Execution plan generated' },
|
|
111
|
-
...executionSteps.map((description, index) => ({
|
|
112
|
-
id: `execute_${index + 1}`,
|
|
113
|
-
description,
|
|
114
|
-
})),
|
|
115
|
-
{ id: 'verify', description: 'Verification loop completed' },
|
|
116
|
-
{ id: 'report', description: 'Evidence-backed report recorded' },
|
|
117
|
-
],
|
|
118
|
-
workflowId,
|
|
119
|
-
}, workflowId);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function resolvePlan(spec, workflowId) {
|
|
123
|
-
if (typeof spec.plan === 'function') {
|
|
124
|
-
return normalizePlan(spec.plan(spec), workflowId);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (spec.plan) {
|
|
128
|
-
return normalizePlan(spec.plan, workflowId);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return buildDefaultPlan(spec, workflowId);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function buildExecutionJob(spec, workflowId, paths, plan) {
|
|
135
|
-
return {
|
|
136
|
-
id: spec.jobId || `${workflowId}-execution`,
|
|
137
|
-
tags: Array.isArray(spec.tags) ? spec.tags : [],
|
|
138
|
-
skill: spec.skill || 'autonomous-workflow',
|
|
139
|
-
partnerProfile: spec.partnerProfile || null,
|
|
140
|
-
verificationMode: spec.verificationMode === 'none' ? 'none' : 'standard',
|
|
141
|
-
autoImprove: spec.autoImprove !== false,
|
|
142
|
-
recordFeedback: spec.recordFeedback !== false,
|
|
143
|
-
stages: Array.isArray(spec.stages) ? spec.stages : [],
|
|
144
|
-
metadata: {
|
|
145
|
-
workflowId,
|
|
146
|
-
planSummary: plan.summary,
|
|
147
|
-
workflowRoot: paths.rootDir,
|
|
148
|
-
},
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function writeWorkflowPlan(paths, plan) {
|
|
153
|
-
ensureDir(paths.rootDir);
|
|
154
|
-
fs.writeFileSync(paths.planPath, `${JSON.stringify(plan, null, 2)}\n`, 'utf8');
|
|
155
|
-
return paths.planPath;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function collectEvidenceArtifacts(paths, executionResult, extraArtifacts = []) {
|
|
159
|
-
return [
|
|
160
|
-
paths.checkpointPath,
|
|
161
|
-
paths.planPath,
|
|
162
|
-
paths.reportJsonPath,
|
|
163
|
-
paths.reportMdPath,
|
|
164
|
-
executionResult && executionResult.jobStatePath ? executionResult.jobStatePath : null,
|
|
165
|
-
...extraArtifacts,
|
|
166
|
-
].filter(Boolean);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function writeWorkflowReport(paths, report) {
|
|
170
|
-
ensureDir(paths.rootDir);
|
|
171
|
-
fs.writeFileSync(paths.reportJsonPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
|
|
172
|
-
|
|
173
|
-
const markdown = [
|
|
174
|
-
`# ${report.workflowName}`,
|
|
175
|
-
'',
|
|
176
|
-
`- Workflow ID: ${report.workflowId}`,
|
|
177
|
-
`- Status: ${report.status}`,
|
|
178
|
-
`- Intent: ${report.intent}`,
|
|
179
|
-
`- Verification accepted: ${report.verification ? String(report.verification.accepted) : 'skipped'}`,
|
|
180
|
-
`- Evidence artifacts: ${report.evidenceArtifacts.length}`,
|
|
181
|
-
'',
|
|
182
|
-
'## Plan',
|
|
183
|
-
'',
|
|
184
|
-
report.plan.summary,
|
|
185
|
-
'',
|
|
186
|
-
...report.plan.steps.map((step) => `- ${step.id}: ${step.description}`),
|
|
187
|
-
'',
|
|
188
|
-
'## Execution',
|
|
189
|
-
'',
|
|
190
|
-
...report.execution.stageHistory.map((stage) => `- ${stage.name} @ ${stage.completedAt}`),
|
|
191
|
-
'',
|
|
192
|
-
'## Evidence Artifacts',
|
|
193
|
-
'',
|
|
194
|
-
...report.evidenceArtifacts.map((artifact) => `- ${artifact}`),
|
|
195
|
-
].join('\n');
|
|
196
|
-
|
|
197
|
-
fs.writeFileSync(paths.reportMdPath, `${markdown}\n`, 'utf8');
|
|
198
|
-
return {
|
|
199
|
-
json: paths.reportJsonPath,
|
|
200
|
-
markdown: paths.reportMdPath,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function recordAutonomousWorkflowRun(spec, report, evidenceArtifacts, feedbackDir) {
|
|
205
|
-
const proofBacked = report.status === 'completed'
|
|
206
|
-
&& (!report.verification || report.verification.accepted)
|
|
207
|
-
&& evidenceArtifacts.length > 0;
|
|
208
|
-
|
|
209
|
-
return appendWorkflowRun({
|
|
210
|
-
workflowId: report.workflowId,
|
|
211
|
-
workflowName: report.workflowName,
|
|
212
|
-
owner: spec.owner || 'automation',
|
|
213
|
-
runtime: 'node',
|
|
214
|
-
status: report.status,
|
|
215
|
-
customerType: spec.customerType || 'internal_dogfood',
|
|
216
|
-
teamId: spec.teamId || null,
|
|
217
|
-
reviewed: proofBacked,
|
|
218
|
-
reviewedBy: proofBacked ? (spec.reviewedBy || 'automation') : null,
|
|
219
|
-
proofBacked,
|
|
220
|
-
proofArtifacts: evidenceArtifacts,
|
|
221
|
-
source: spec.source || 'autonomous-workflow',
|
|
222
|
-
metadata: {
|
|
223
|
-
intent: report.intent,
|
|
224
|
-
planSummary: report.plan.summary,
|
|
225
|
-
verificationAttempts: report.verification ? report.verification.attempts : 0,
|
|
226
|
-
executionJobId: report.execution.jobId,
|
|
227
|
-
},
|
|
228
|
-
}, feedbackDir);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function runAutonomousWorkflow(spec = {}, options = {}) {
|
|
232
|
-
const cwd = options.cwd || process.cwd();
|
|
233
|
-
const workflowId = normalizeText(spec.workflowId) || slugify(spec.name || spec.intent, 'autonomous-workflow');
|
|
234
|
-
const workflowName = normalizeText(spec.name) || `Autonomous workflow ${workflowId}`;
|
|
235
|
-
const intent = normalizeText(spec.intent) || 'Intent not provided';
|
|
236
|
-
const paths = getWorkflowPaths(workflowId, cwd);
|
|
237
|
-
const plan = resolvePlan(spec, workflowId);
|
|
238
|
-
|
|
239
|
-
writeWorkflowPlan(paths, plan);
|
|
240
|
-
|
|
241
|
-
let checkpoint = createCheckpoint({
|
|
242
|
-
workflowId,
|
|
243
|
-
phase: 'intent',
|
|
244
|
-
status: 'running',
|
|
245
|
-
intent: { summary: intent },
|
|
246
|
-
plan,
|
|
247
|
-
evidence: [paths.planPath],
|
|
248
|
-
metadata: {
|
|
249
|
-
workflowName,
|
|
250
|
-
},
|
|
251
|
-
});
|
|
252
|
-
saveCheckpoint(checkpoint, paths.checkpointPath);
|
|
253
|
-
|
|
254
|
-
checkpoint = advanceCheckpoint(checkpoint, {
|
|
255
|
-
phase: 'plan',
|
|
256
|
-
status: 'running',
|
|
257
|
-
plan,
|
|
258
|
-
evidence: [paths.planPath],
|
|
259
|
-
});
|
|
260
|
-
saveCheckpoint(checkpoint, paths.checkpointPath);
|
|
261
|
-
|
|
262
|
-
const job = buildExecutionJob(spec, workflowId, paths, plan);
|
|
263
|
-
const executionResult = options.resume === true
|
|
264
|
-
? resumeJob(job.id, job)
|
|
265
|
-
: executeJob(job);
|
|
266
|
-
const jobState = readJobState(job.id);
|
|
267
|
-
|
|
268
|
-
checkpoint = advanceCheckpoint(checkpoint, {
|
|
269
|
-
phase: 'verify',
|
|
270
|
-
status: executionResult.status,
|
|
271
|
-
evidence: jobState && jobState.verification ? [paths.checkpointPath] : [],
|
|
272
|
-
metadata: {
|
|
273
|
-
executionJobId: job.id,
|
|
274
|
-
executionStatus: executionResult.status,
|
|
275
|
-
},
|
|
276
|
-
});
|
|
277
|
-
saveCheckpoint(checkpoint, paths.checkpointPath);
|
|
278
|
-
|
|
279
|
-
const report = {
|
|
280
|
-
workflowId,
|
|
281
|
-
workflowName,
|
|
282
|
-
status: executionResult.status,
|
|
283
|
-
intent,
|
|
284
|
-
plan,
|
|
285
|
-
execution: {
|
|
286
|
-
jobId: job.id,
|
|
287
|
-
status: executionResult.status,
|
|
288
|
-
stageHistory: Array.isArray(jobState && jobState.stageHistory) ? jobState.stageHistory : [],
|
|
289
|
-
checkpointCount: Array.isArray(jobState && jobState.checkpoints) ? jobState.checkpoints.length : 0,
|
|
290
|
-
currentContext: jobState && jobState.currentContext ? jobState.currentContext : '',
|
|
291
|
-
jobStatePath: jobState ? path.join(getFeedbackDir(options.feedbackDir), 'jobs', job.id, 'state.json') : null,
|
|
292
|
-
},
|
|
293
|
-
verification: executionResult.phases ? executionResult.phases.verification : null,
|
|
294
|
-
phases: executionResult.phases || null,
|
|
295
|
-
timestamp: new Date().toISOString(),
|
|
296
|
-
evidenceArtifacts: [],
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
const evidenceArtifacts = collectEvidenceArtifacts(paths, report.execution, spec.proofArtifacts);
|
|
300
|
-
report.evidenceArtifacts = evidenceArtifacts;
|
|
301
|
-
|
|
302
|
-
checkpoint = advanceCheckpoint(checkpoint, {
|
|
303
|
-
phase: 'report',
|
|
304
|
-
status: executionResult.status,
|
|
305
|
-
report: {
|
|
306
|
-
status: report.status,
|
|
307
|
-
generatedAt: report.timestamp,
|
|
308
|
-
},
|
|
309
|
-
evidence: evidenceArtifacts,
|
|
310
|
-
});
|
|
311
|
-
saveCheckpoint(checkpoint, paths.checkpointPath);
|
|
312
|
-
|
|
313
|
-
writeWorkflowReport(paths, report);
|
|
314
|
-
report.workflowRun = recordAutonomousWorkflowRun(spec, report, evidenceArtifacts, options.feedbackDir);
|
|
315
|
-
fs.writeFileSync(paths.reportJsonPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
|
|
316
|
-
|
|
317
|
-
return report;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
function getFeedbackDir(feedbackDir) {
|
|
321
|
-
if (feedbackDir) return feedbackDir;
|
|
322
|
-
return process.env.THUMBGATE_FEEDBACK_DIR || path.join(process.cwd(), '.thumbgate');
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
function resumeAutonomousWorkflow(spec = {}, options = {}) {
|
|
326
|
-
return runAutonomousWorkflow(spec, { ...options, resume: true });
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
function readWorkflowReport(workflowId, options = {}) {
|
|
330
|
-
const paths = getWorkflowPaths(workflowId, options.cwd || process.cwd());
|
|
331
|
-
if (!fs.existsSync(paths.reportJsonPath)) return null;
|
|
332
|
-
return JSON.parse(fs.readFileSync(paths.reportJsonPath, 'utf8'));
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function isCliInvocation(argv = process.argv) {
|
|
336
|
-
const invokedPath = argv[1];
|
|
337
|
-
return invokedPath ? path.resolve(invokedPath) === __filename : false;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
function parseArgs(argv = process.argv.slice(2)) {
|
|
341
|
-
const args = {};
|
|
342
|
-
for (const arg of argv) {
|
|
343
|
-
if (!arg.startsWith('--')) continue;
|
|
344
|
-
const [key, ...rest] = arg.slice(2).split('=');
|
|
345
|
-
args[key] = rest.length > 0 ? rest.join('=') : true;
|
|
346
|
-
}
|
|
347
|
-
return args;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
if (isCliInvocation()) {
|
|
351
|
-
const args = parseArgs();
|
|
352
|
-
if (!args.file) {
|
|
353
|
-
console.error('Usage: node scripts/autonomous-workflow.js --file=workflow.json [--resume]');
|
|
354
|
-
process.exit(1);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
const specPath = path.resolve(args.file);
|
|
358
|
-
const spec = JSON.parse(fs.readFileSync(specPath, 'utf8'));
|
|
359
|
-
const report = args.resume ? resumeAutonomousWorkflow(spec) : runAutonomousWorkflow(spec);
|
|
360
|
-
console.log(JSON.stringify(report, null, 2));
|
|
361
|
-
process.exit(report.status === 'completed' ? 0 : 1);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
module.exports = {
|
|
365
|
-
buildDefaultPlan,
|
|
366
|
-
collectEvidenceArtifacts,
|
|
367
|
-
getWorkflowPaths,
|
|
368
|
-
normalizePlan,
|
|
369
|
-
parseArgs,
|
|
370
|
-
readWorkflowReport,
|
|
371
|
-
recordAutonomousWorkflowRun,
|
|
372
|
-
resumeAutonomousWorkflow,
|
|
373
|
-
runAutonomousWorkflow,
|
|
374
|
-
slugify,
|
|
375
|
-
writeWorkflowPlan,
|
|
376
|
-
writeWorkflowReport,
|
|
377
|
-
};
|
package/scripts/billing-setup.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* billing-setup.js — Wire up hosted billing for the CFO dashboard
|
|
6
|
-
*
|
|
7
|
-
* Generates a THUMBGATE_OPERATOR_KEY and stores it locally so that
|
|
8
|
-
* `node bin/cli.js cfo --today` pulls live revenue from the production server.
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* node scripts/billing-setup.js
|
|
12
|
-
*
|
|
13
|
-
* After running, set the printed key on Railway:
|
|
14
|
-
* railway variables set THUMBGATE_OPERATOR_KEY=<key>
|
|
15
|
-
* Then redeploy (or let Railway auto-deploy).
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const crypto = require('node:crypto');
|
|
19
|
-
const fs = require('node:fs');
|
|
20
|
-
const path = require('node:path');
|
|
21
|
-
const os = require('node:os');
|
|
22
|
-
|
|
23
|
-
const LOCAL_CONFIG_PATH = path.join(os.homedir(), '.config', 'thumbgate', 'operator.json');
|
|
24
|
-
const PROD_URL = 'https://thumbgate-production.up.railway.app';
|
|
25
|
-
|
|
26
|
-
function generateOperatorKey() {
|
|
27
|
-
return `tg_op_${crypto.randomBytes(20).toString('hex')}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function loadExistingConfig() {
|
|
31
|
-
try {
|
|
32
|
-
const raw = fs.readFileSync(LOCAL_CONFIG_PATH, 'utf8');
|
|
33
|
-
return JSON.parse(raw);
|
|
34
|
-
} catch {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function saveConfig(config) {
|
|
40
|
-
const dir = path.dirname(LOCAL_CONFIG_PATH);
|
|
41
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
42
|
-
fs.writeFileSync(LOCAL_CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function verifyEndpoint(baseUrl, key) {
|
|
46
|
-
try {
|
|
47
|
-
const url = new URL('/v1/billing/summary?window=today', baseUrl);
|
|
48
|
-
const res = await fetch(url, {
|
|
49
|
-
method: 'GET',
|
|
50
|
-
headers: { authorization: `Bearer ${key}`, accept: 'application/json' },
|
|
51
|
-
});
|
|
52
|
-
return { status: res.status, ok: res.ok };
|
|
53
|
-
} catch (err) {
|
|
54
|
-
return { status: null, ok: false, error: err.message };
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async function main() {
|
|
59
|
-
const existing = loadExistingConfig();
|
|
60
|
-
|
|
61
|
-
if (existing && existing.operatorKey && existing.baseUrl) {
|
|
62
|
-
console.log('\n✓ Operator config already exists at', LOCAL_CONFIG_PATH);
|
|
63
|
-
console.log(' Base URL :', existing.baseUrl);
|
|
64
|
-
console.log(' Operator key:', existing.operatorKey);
|
|
65
|
-
console.log('\nTo regenerate, delete the file and re-run this script.');
|
|
66
|
-
|
|
67
|
-
// Set env for this process so the verify check works
|
|
68
|
-
process.env.THUMBGATE_OPERATOR_KEY = existing.operatorKey;
|
|
69
|
-
process.env.THUMBGATE_BILLING_API_BASE_URL = existing.baseUrl;
|
|
70
|
-
|
|
71
|
-
const check = await verifyEndpoint(existing.baseUrl, existing.operatorKey);
|
|
72
|
-
if (check.ok) {
|
|
73
|
-
console.log('\n✓ Production endpoint responds OK — hosted billing is active.');
|
|
74
|
-
} else if (check.status === 403) {
|
|
75
|
-
console.log('\n⚠ Production endpoint returned 403 — the operator key is not yet set on Railway.');
|
|
76
|
-
console.log('\nSet it now:\n');
|
|
77
|
-
console.log(` railway variables set THUMBGATE_OPERATOR_KEY=${existing.operatorKey}`);
|
|
78
|
-
console.log('\nThen redeploy (Railway will pick it up automatically).');
|
|
79
|
-
} else {
|
|
80
|
-
console.log(`\n⚠ Endpoint check returned status ${check.status || 'error'}: ${check.error || ''}`);
|
|
81
|
-
}
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const key = generateOperatorKey();
|
|
86
|
-
const config = {
|
|
87
|
-
operatorKey: key,
|
|
88
|
-
baseUrl: process.env.THUMBGATE_BILLING_API_BASE_URL || PROD_URL,
|
|
89
|
-
createdAt: new Date().toISOString(),
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
saveConfig(config);
|
|
93
|
-
|
|
94
|
-
console.log('\n✓ Operator key generated and saved to', LOCAL_CONFIG_PATH);
|
|
95
|
-
console.log('\n──────────────────────────────────────────────────────');
|
|
96
|
-
console.log(' THUMBGATE_OPERATOR_KEY =', key);
|
|
97
|
-
console.log('──────────────────────────────────────────────────────');
|
|
98
|
-
console.log('\nSet this key on Railway (one-time):');
|
|
99
|
-
console.log('\n railway variables set THUMBGATE_OPERATOR_KEY=' + key);
|
|
100
|
-
console.log('\nOr paste it into the Railway dashboard under Variables.');
|
|
101
|
-
console.log('\nAfter Railway redeploys, run:\n');
|
|
102
|
-
console.log(' node bin/cli.js cfo --today\n');
|
|
103
|
-
console.log('The CFO dashboard will use live production billing data.');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
main().catch((err) => {
|
|
107
|
-
console.error('billing-setup error:', err.message);
|
|
108
|
-
process.exit(1);
|
|
109
|
-
});
|