clawpowers 1.1.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/LICENSE +44 -0
  3. package/README.md +204 -228
  4. package/SECURITY.md +72 -0
  5. package/dist/index.d.ts +844 -0
  6. package/dist/index.js +2536 -0
  7. package/dist/index.js.map +1 -0
  8. package/package.json +50 -44
  9. package/.claude-plugin/manifest.json +0 -19
  10. package/.codex/INSTALL.md +0 -36
  11. package/.cursor-plugin/manifest.json +0 -21
  12. package/.opencode/INSTALL.md +0 -52
  13. package/ARCHITECTURE.md +0 -69
  14. package/bin/clawpowers.js +0 -625
  15. package/bin/clawpowers.sh +0 -91
  16. package/docs/demo/clawpowers-demo.cast +0 -197
  17. package/docs/demo/clawpowers-demo.gif +0 -0
  18. package/docs/launch-images/25-skills-breakdown.jpg +0 -0
  19. package/docs/launch-images/clawpowers-vs-superpowers.jpg +0 -0
  20. package/docs/launch-images/economic-code-optimization.jpg +0 -0
  21. package/docs/launch-images/native-vs-bridge-2.jpg +0 -0
  22. package/docs/launch-images/native-vs-bridge.jpg +0 -0
  23. package/docs/launch-images/post1-hero-lobster.jpg +0 -0
  24. package/docs/launch-images/post2-dashboard.jpg +0 -0
  25. package/docs/launch-images/post3-superpowers.jpg +0 -0
  26. package/docs/launch-images/post4-before-after.jpg +0 -0
  27. package/docs/launch-images/post5-install-now.jpg +0 -0
  28. package/docs/launch-images/ultimate-stack.jpg +0 -0
  29. package/docs/launch-posts.md +0 -76
  30. package/docs/quickstart-first-transaction.md +0 -204
  31. package/gemini-extension.json +0 -32
  32. package/hooks/session-start +0 -205
  33. package/hooks/session-start.cmd +0 -43
  34. package/hooks/session-start.js +0 -163
  35. package/runtime/demo/README.md +0 -78
  36. package/runtime/demo/x402-mock-server.js +0 -230
  37. package/runtime/feedback/analyze.js +0 -621
  38. package/runtime/feedback/analyze.sh +0 -546
  39. package/runtime/init.js +0 -210
  40. package/runtime/init.sh +0 -178
  41. package/runtime/metrics/collector.js +0 -361
  42. package/runtime/metrics/collector.sh +0 -308
  43. package/runtime/payments/ledger.js +0 -305
  44. package/runtime/payments/ledger.sh +0 -262
  45. package/runtime/payments/pipeline.js +0 -455
  46. package/runtime/persistence/store.js +0 -433
  47. package/runtime/persistence/store.sh +0 -303
  48. package/skill.json +0 -106
  49. package/skills/agent-bounties/SKILL.md +0 -553
  50. package/skills/agent-payments/SKILL.md +0 -479
  51. package/skills/brainstorming/SKILL.md +0 -233
  52. package/skills/content-pipeline/SKILL.md +0 -282
  53. package/skills/cross-project-knowledge/SKILL.md +0 -345
  54. package/skills/dispatching-parallel-agents/SKILL.md +0 -305
  55. package/skills/economic-code-optimization/SKILL.md +0 -265
  56. package/skills/executing-plans/SKILL.md +0 -255
  57. package/skills/finishing-a-development-branch/SKILL.md +0 -260
  58. package/skills/formal-verification-lite/SKILL.md +0 -441
  59. package/skills/learn-how-to-learn/SKILL.md +0 -235
  60. package/skills/market-intelligence/SKILL.md +0 -323
  61. package/skills/meta-skill-evolution/SKILL.md +0 -325
  62. package/skills/prospecting/SKILL.md +0 -454
  63. package/skills/receiving-code-review/SKILL.md +0 -225
  64. package/skills/requesting-code-review/SKILL.md +0 -206
  65. package/skills/security-audit/SKILL.md +0 -353
  66. package/skills/self-healing-code/SKILL.md +0 -369
  67. package/skills/subagent-driven-development/SKILL.md +0 -244
  68. package/skills/systematic-debugging/SKILL.md +0 -355
  69. package/skills/test-driven-development/SKILL.md +0 -416
  70. package/skills/using-clawpowers/SKILL.md +0 -160
  71. package/skills/using-git-worktrees/SKILL.md +0 -261
  72. package/skills/validator/SKILL.md +0 -281
  73. package/skills/verification-before-completion/SKILL.md +0 -254
  74. package/skills/writing-plans/SKILL.md +0 -276
  75. package/skills/writing-skills/SKILL.md +0 -260
@@ -1,455 +0,0 @@
1
- #!/usr/bin/env node
2
- // runtime/payments/pipeline.js — Unified Payment Decision Pipeline
3
- //
4
- // Central gate for ALL skill payment decisions. Any skill that encounters a
5
- // payment boundary (HTTP 402, premium scanner, paid API, x402 endpoint) calls
6
- // evaluatePayment() here instead of making its own policy judgements.
7
- //
8
- // Flow:
9
- // estimate_cost → check_config → check_policy →
10
- // (disabled | dry_run | queued | approved | rejected) → log
11
- //
12
- // Usage (module):
13
- // const { evaluatePayment } = require('./pipeline');
14
- // const result = await evaluatePayment({ skill, reason, amount_usd, asset, chain, recipient, url });
15
- //
16
- // Usage (CLI):
17
- // node pipeline.js evaluate --amount 0.05 --skill security-audit --reason "premium scanner"
18
- // npx clawpowers payments evaluate --amount 0.05 --skill security-audit --reason "premium scanner"
19
- 'use strict';
20
-
21
- const fs = require('fs');
22
- const path = require('path');
23
- const os = require('os');
24
- const { logPaymentDecision } = require('./ledger');
25
-
26
- // ─── Config paths ──────────────────────────────────────────────────────────
27
-
28
- /** Root of the ~/.clawpowers/ runtime directory. */
29
- const CLAWPOWERS_DIR = process.env.CLAWPOWERS_DIR || path.join(os.homedir(), '.clawpowers');
30
-
31
- /** Main config file path. */
32
- const CONFIG_FILE = path.join(CLAWPOWERS_DIR, 'config.json');
33
-
34
- /** Payment ledger path (JSONL — one record per decision). */
35
- const PAYMENTS_LEDGER = path.join(CLAWPOWERS_DIR, 'logs', 'payments.jsonl');
36
-
37
- // ─── Helpers ───────────────────────────────────────────────────────────────
38
-
39
- /**
40
- * Load and parse ~/.clawpowers/config.json.
41
- * Returns an empty object if the file doesn't exist.
42
- *
43
- * @returns {object} Parsed config or {}.
44
- */
45
- function loadConfig() {
46
- try {
47
- if (!fs.existsSync(CONFIG_FILE)) return {};
48
- const raw = fs.readFileSync(CONFIG_FILE, 'utf8');
49
- return JSON.parse(raw);
50
- } catch (err) {
51
- process.stderr.write(`[pipeline] Warning: could not read config: ${err.message}\n`);
52
- return {};
53
- }
54
- }
55
-
56
- /**
57
- * Compute today's total spend (USD) from the payments ledger.
58
- * Only counts entries with action "approved" or "executed" and today's date.
59
- *
60
- * @returns {number} Total USD spent today across all skills and chains.
61
- */
62
- function getTodaySpend() {
63
- try {
64
- if (!fs.existsSync(PAYMENTS_LEDGER)) return 0;
65
- const today = new Date().toISOString().slice(0, 10); // "YYYY-MM-DD"
66
- const lines = fs.readFileSync(PAYMENTS_LEDGER, 'utf8').split('\n');
67
- let total = 0;
68
- for (const line of lines) {
69
- if (!line.trim()) continue;
70
- try {
71
- const r = JSON.parse(line);
72
- if (
73
- r.timestamp &&
74
- r.timestamp.startsWith(today) &&
75
- (r.policy_result === 'approved' || r.policy_result === 'executed')
76
- ) {
77
- total += parseFloat(r.required_amount) || 0;
78
- }
79
- } catch (_) { /* skip malformed */ }
80
- }
81
- return total;
82
- } catch {
83
- return 0;
84
- }
85
- }
86
-
87
- /**
88
- * Check if a recipient address appears in the configured allowlist.
89
- * An empty allowlist means NO recipients are automatically allowed.
90
- *
91
- * @param {string} recipient - Recipient address (0x-prefixed).
92
- * @param {string[]} allowlist - Array of allowed addresses (case-insensitive).
93
- * @returns {boolean} True if allowed or allowlist is not configured.
94
- */
95
- function isAllowlisted(recipient, allowlist) {
96
- // If allowlist is undefined/null → not configured → no automatic allowance
97
- if (!Array.isArray(allowlist)) return false;
98
- // Empty allowlist → nothing allowed
99
- if (allowlist.length === 0) return false;
100
- const lower = (recipient || '').toLowerCase();
101
- return allowlist.some((a) => (a || '').toLowerCase() === lower);
102
- }
103
-
104
- /**
105
- * Returns an ISO 8601 timestamp without milliseconds.
106
- */
107
-
108
- // ─── Core pipeline ─────────────────────────────────────────────────────────
109
-
110
- /**
111
- * Payment Decision Pipeline — evaluate whether a payment should be made.
112
- *
113
- * Called by any skill when it hits a payment boundary. Reads config, checks
114
- * policy limits, and returns a decision with a reason. Always logs the decision
115
- * to the payments ledger regardless of outcome.
116
- *
117
- * ### Decision flow
118
- *
119
- * ```
120
- * payments.enabled === false → "disabled"
121
- * payments.mode === "dry_run" → "dry_run"
122
- * amount > per_tx_limit → "rejected" (hard limit)
123
- * today_spend + amount > daily → "rejected" (daily limit)
124
- * recipient not in allowlist → "queued" (needs approval)
125
- * amount > require_approval_above → "queued" (needs approval)
126
- * all checks pass → "approved"
127
- * ```
128
- *
129
- * @param {object} decision - Payment details.
130
- * @param {string} decision.skill - ClawPowers skill triggering the payment.
131
- * @param {string} decision.reason - Human-readable reason ("HTTP 402", "premium scanner", …).
132
- * @param {number} decision.amount_usd - Estimated cost in USD (decimal).
133
- * @param {string} [decision.asset] - Token/asset symbol (default "USDC").
134
- * @param {string} [decision.chain] - Chain name (default "base").
135
- * @param {string} [decision.recipient] - Payment recipient address.
136
- * @param {string} [decision.url] - URL or service that triggered the boundary.
137
- *
138
- * @returns {{
139
- * action: "disabled"|"dry_run"|"queued"|"approved"|"rejected",
140
- * reason: string,
141
- * logged: boolean,
142
- * amount_usd: number,
143
- * config_used: object
144
- * }} Decision result.
145
- *
146
- * @example
147
- * ```javascript
148
- * const { evaluatePayment } = require('./pipeline');
149
- * const result = await evaluatePayment({
150
- * skill: 'security-audit',
151
- * reason: 'premium scanner API',
152
- * amount_usd: 0.05,
153
- * asset: 'USDC',
154
- * chain: 'base',
155
- * recipient: '0xSCANNER_RECIPIENT',
156
- * });
157
- * if (result.action === 'approved') {
158
- * // proceed with payment
159
- * }
160
- * ```
161
- */
162
- function evaluatePayment(decision) {
163
- const {
164
- skill = 'unknown',
165
- reason = '',
166
- amount_usd = 0,
167
- asset = 'USDC',
168
- chain = 'base',
169
- recipient = '',
170
- url = '',
171
- } = decision;
172
-
173
- // ── 1. Load config ────────────────────────────────────────────────────────
174
- const config = loadConfig();
175
- const payments = config.payments || {};
176
-
177
- // ── 2. payments.enabled === false → disabled ──────────────────────────────
178
- if (payments.enabled === false) {
179
- const result = {
180
- action: 'disabled',
181
- reason: 'Payments disabled in ~/.clawpowers/config.json (payments.enabled = false)',
182
- logged: false,
183
- amount_usd,
184
- config_used: payments,
185
- };
186
- result.logged = _logDecision(skill, url, String(amount_usd), asset, chain, 'disabled', result.reason, false);
187
- return result;
188
- }
189
-
190
- // ── 3. payments.mode === "dry_run" → log what would happen, no payment ────
191
- if (payments.mode === 'dry_run') {
192
- const summary =
193
- `DRY-RUN: skill=${skill} reason="${reason}" would pay ` +
194
- `$${amount_usd.toFixed ? amount_usd.toFixed(4) : amount_usd} ${asset} on ${chain}` +
195
- (url ? ` for ${url}` : '');
196
- console.log(`[pipeline] ${summary}`);
197
-
198
- const result = {
199
- action: 'dry_run',
200
- reason: summary,
201
- logged: false,
202
- amount_usd,
203
- config_used: payments,
204
- };
205
- result.logged = _logDecision(skill, url, String(amount_usd), asset, chain, 'dry_run', reason, true);
206
- return result;
207
- }
208
-
209
- // ── 4. Check per-transaction limit ────────────────────────────────────────
210
- const perTxLimit = typeof payments.per_tx_limit === 'number' ? payments.per_tx_limit : Infinity;
211
- if (amount_usd > perTxLimit) {
212
- const msg = `Amount $${amount_usd} exceeds per_tx_limit $${perTxLimit}`;
213
- const result = {
214
- action: 'rejected',
215
- reason: msg,
216
- logged: false,
217
- amount_usd,
218
- config_used: payments,
219
- };
220
- result.logged = _logDecision(skill, url, String(amount_usd), asset, chain, 'rejected', msg, false);
221
- return result;
222
- }
223
-
224
- // ── 5. Check daily limit ─────────────────────────────────────────────────
225
- const dailyLimit = typeof payments.daily_limit === 'number' ? payments.daily_limit : Infinity;
226
- const todaySpend = getTodaySpend();
227
- if (todaySpend + amount_usd > dailyLimit) {
228
- const msg =
229
- `Daily limit would be exceeded: today=$${todaySpend.toFixed(4)}, ` +
230
- `new=$${amount_usd}, limit=$${dailyLimit}`;
231
- const result = {
232
- action: 'rejected',
233
- reason: msg,
234
- logged: false,
235
- amount_usd,
236
- config_used: payments,
237
- };
238
- result.logged = _logDecision(skill, url, String(amount_usd), asset, chain, 'rejected', msg, false);
239
- return result;
240
- }
241
-
242
- // ── 6. Check recipient allowlist ─────────────────────────────────────────
243
- const allowlist = payments.allowlist; // undefined = not configured
244
- if (recipient && !isAllowlisted(recipient, allowlist)) {
245
- // Not in allowlist — queue for approval unless allowlist is intentionally absent
246
- // (If allowlist key doesn't exist at all, we fall through to approval-above check)
247
- if (Array.isArray(allowlist)) {
248
- const msg = `Recipient ${recipient} is not in payments.allowlist`;
249
- const result = {
250
- action: 'queued',
251
- reason: msg,
252
- logged: false,
253
- amount_usd,
254
- config_used: payments,
255
- };
256
- result.logged = _logDecision(skill, url, String(amount_usd), asset, chain, 'queued', msg, false);
257
- return result;
258
- }
259
- }
260
-
261
- // ── 7. Check require_approval_above threshold ─────────────────────────────
262
- const approvalThreshold = typeof payments.require_approval_above === 'number'
263
- ? payments.require_approval_above
264
- : Infinity;
265
- if (amount_usd > approvalThreshold) {
266
- const msg =
267
- `Amount $${amount_usd} exceeds require_approval_above threshold $${approvalThreshold}`;
268
- const result = {
269
- action: 'queued',
270
- reason: msg,
271
- logged: false,
272
- amount_usd,
273
- config_used: payments,
274
- };
275
- result.logged = _logDecision(skill, url, String(amount_usd), asset, chain, 'queued', msg, false);
276
- return result;
277
- }
278
-
279
- // ── 8. All checks passed → approved ───────────────────────────────────────
280
- const approveMsg = `Payment approved: $${amount_usd} ${asset} on ${chain} for ${skill} (${reason})`;
281
- const result = {
282
- action: 'approved',
283
- reason: approveMsg,
284
- logged: false,
285
- amount_usd,
286
- config_used: payments,
287
- };
288
- result.logged = _logDecision(skill, url, String(amount_usd), asset, chain, 'approved', reason, true);
289
- return result;
290
- }
291
-
292
- /**
293
- * Internal: write decision to the payments ledger via the ledger module.
294
- *
295
- * @param {string} skill
296
- * @param {string} url
297
- * @param {string} required_amount
298
- * @param {string} asset
299
- * @param {string} chain
300
- * @param {string} policy_result
301
- * @param {string} reason
302
- * @param {boolean} would_have_paid
303
- * @returns {boolean} Always true (indicates logging was attempted).
304
- */
305
- function _logDecision(skill, url, required_amount, asset, chain, policy_result, reason, would_have_paid) {
306
- try {
307
- logPaymentDecision({
308
- skill,
309
- type: 'decision',
310
- url,
311
- required_amount,
312
- asset,
313
- chain,
314
- policy_result,
315
- reason,
316
- would_have_paid,
317
- });
318
- return true;
319
- } catch (err) {
320
- process.stderr.write(`[pipeline] Warning: could not write to ledger: ${err.message}\n`);
321
- return false;
322
- }
323
- }
324
-
325
- // ─── CLI ───────────────────────────────────────────────────────────────────
326
-
327
- /**
328
- * Print CLI usage to stdout.
329
- */
330
- function printUsage() {
331
- console.log(`Usage: clawpowers payments evaluate [options]
332
-
333
- Options:
334
- --amount <n> Payment amount in USD (required, decimal, e.g. 0.05)
335
- --skill <name> Skill that triggered the payment (default: "cli")
336
- --reason <text> Reason for the payment (default: "cli test")
337
- --asset <symbol> Token symbol (default: USDC)
338
- --chain <name> Chain name (default: base)
339
- --recipient <addr> Recipient wallet address (optional)
340
- --url <url> URL or service requiring payment (optional)
341
- --json Output raw JSON result
342
-
343
- Examples:
344
- node pipeline.js evaluate --amount 0.05 --skill security-audit --reason "premium scanner"
345
- node pipeline.js evaluate --amount 0.01 --skill prospecting --reason "contact enrichment" --json
346
- npx clawpowers payments evaluate --amount 0.05 --skill agent-payments --reason "x402 API"
347
-
348
- Config file: ~/.clawpowers/config.json
349
- Ledger file: ~/.clawpowers/logs/payments.jsonl`);
350
- }
351
-
352
- /**
353
- * CLI handler for the `evaluate` sub-command.
354
- * Parses --flags and calls evaluatePayment(), printing the result.
355
- *
356
- * @param {string[]} argv - Arguments after "evaluate".
357
- */
358
- function cmdEvaluate(argv) {
359
- const args = {};
360
- for (let i = 0; i < argv.length; i++) {
361
- const flag = argv[i];
362
- const next = argv[i + 1];
363
- switch (flag) {
364
- case '--amount': args.amount_usd = parseFloat(next); i++; break;
365
- case '--skill': args.skill = next; i++; break;
366
- case '--reason': args.reason = next; i++; break;
367
- case '--asset': args.asset = next; i++; break;
368
- case '--chain': args.chain = next; i++; break;
369
- case '--recipient': args.recipient = next; i++; break;
370
- case '--url': args.url = next; i++; break;
371
- case '--json': args._json = true; break;
372
- }
373
- }
374
-
375
- if (args.amount_usd === undefined || isNaN(args.amount_usd)) {
376
- process.stderr.write('Error: --amount is required and must be a number\n\n');
377
- printUsage();
378
- process.exit(1);
379
- }
380
-
381
- const decision = {
382
- skill: args.skill || 'cli',
383
- reason: args.reason || 'cli test',
384
- amount_usd: args.amount_usd,
385
- asset: args.asset || 'USDC',
386
- chain: args.chain || 'base',
387
- recipient: args.recipient || '',
388
- url: args.url || '',
389
- };
390
-
391
- const result = evaluatePayment(decision);
392
-
393
- if (args._json) {
394
- console.log(JSON.stringify(result, null, 2));
395
- } else {
396
- console.log('');
397
- console.log(`Payment Decision Pipeline`);
398
- console.log(`─────────────────────────`);
399
- console.log(` Skill: ${decision.skill}`);
400
- console.log(` Reason: ${decision.reason}`);
401
- console.log(` Amount: $${decision.amount_usd} ${decision.asset} on ${decision.chain}`);
402
- if (decision.url) console.log(` URL: ${decision.url}`);
403
- if (decision.recipient) console.log(` To: ${decision.recipient}`);
404
- console.log('');
405
- console.log(` ► Action: ${result.action.toUpperCase()}`);
406
- console.log(` ► Reason: ${result.reason}`);
407
- console.log(` ► Logged: ${result.logged ? 'yes' : 'no'}`);
408
- console.log('');
409
- }
410
-
411
- // Non-zero exit for rejected/disabled so scripts can branch on exit code
412
- if (result.action === 'rejected') process.exit(2);
413
- if (result.action === 'disabled') process.exit(3);
414
- }
415
-
416
- /**
417
- * Main CLI dispatch.
418
- * @param {string[]} argv
419
- */
420
- function main(argv) {
421
- const [cmd, ...rest] = argv;
422
-
423
- switch (cmd) {
424
- case 'evaluate':
425
- case 'eval':
426
- cmdEvaluate(rest);
427
- break;
428
- case 'help':
429
- case '-h':
430
- case '--help':
431
- printUsage();
432
- break;
433
- case undefined:
434
- case '':
435
- printUsage();
436
- process.exit(1);
437
- break;
438
- default:
439
- process.stderr.write(`Unknown command: ${cmd}\n`);
440
- printUsage();
441
- process.exit(1);
442
- }
443
- }
444
-
445
- // Guard: only run CLI dispatch when invoked directly
446
- if (require.main === module) {
447
- try {
448
- main(process.argv.slice(2));
449
- } catch (err) {
450
- process.stderr.write(`Error: ${err.message}\n`);
451
- process.exit(1);
452
- }
453
- }
454
-
455
- module.exports = { evaluatePayment };