clawpowers 1.1.4 → 2.2.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/CHANGELOG.md +126 -0
- package/COMPATIBILITY.md +13 -0
- package/KNOWN_LIMITATIONS.md +19 -0
- package/LICENSE +44 -0
- package/LICENSING.md +10 -0
- package/README.md +378 -210
- package/SECURITY.md +52 -0
- package/dist/index.d.ts +1477 -0
- package/dist/index.js +3464 -0
- package/dist/index.js.map +1 -0
- package/native/Cargo.lock +4863 -0
- package/native/Cargo.toml +73 -0
- package/native/crates/canonical/Cargo.toml +24 -0
- package/native/crates/canonical/src/lib.rs +673 -0
- package/native/crates/compression/Cargo.toml +20 -0
- package/native/crates/compression/benches/compression_bench.rs +42 -0
- package/native/crates/compression/src/lib.rs +393 -0
- package/native/crates/evm-eth/Cargo.toml +13 -0
- package/native/crates/evm-eth/src/lib.rs +105 -0
- package/native/crates/fee/Cargo.toml +15 -0
- package/native/crates/fee/src/lib.rs +281 -0
- package/native/crates/index/Cargo.toml +16 -0
- package/native/crates/index/src/lib.rs +277 -0
- package/native/crates/policy/Cargo.toml +17 -0
- package/native/crates/policy/src/lib.rs +614 -0
- package/native/crates/security/Cargo.toml +22 -0
- package/native/crates/security/src/lib.rs +478 -0
- package/native/crates/tokens/Cargo.toml +13 -0
- package/native/crates/tokens/src/lib.rs +534 -0
- package/native/crates/verification/Cargo.toml +23 -0
- package/native/crates/verification/src/lib.rs +333 -0
- package/native/crates/wallet/Cargo.toml +20 -0
- package/native/crates/wallet/src/lib.rs +261 -0
- package/native/crates/x402/Cargo.toml +30 -0
- package/native/crates/x402/src/lib.rs +423 -0
- package/native/ffi/Cargo.toml +34 -0
- package/native/ffi/build.rs +4 -0
- package/native/ffi/index.node +0 -0
- package/native/ffi/src/lib.rs +352 -0
- package/native/ffi/tests/integration.rs +354 -0
- package/native/pyo3/Cargo.toml +26 -0
- package/native/pyo3/pyproject.toml +16 -0
- package/native/pyo3/src/lib.rs +407 -0
- package/native/pyo3/tests/test_smoke.py +180 -0
- package/native/wasm/Cargo.toml +44 -0
- package/native/wasm/pkg/.gitignore +6 -0
- package/native/wasm/pkg/clawpowers_wasm.d.ts +208 -0
- package/native/wasm/pkg/clawpowers_wasm.js +872 -0
- package/native/wasm/pkg/clawpowers_wasm_bg.wasm +0 -0
- package/native/wasm/pkg/clawpowers_wasm_bg.wasm.d.ts +40 -0
- package/native/wasm/pkg/package.json +17 -0
- package/native/wasm/pkg-node/.gitignore +6 -0
- package/native/wasm/pkg-node/clawpowers_wasm.d.ts +143 -0
- package/native/wasm/pkg-node/clawpowers_wasm.js +798 -0
- package/native/wasm/pkg-node/clawpowers_wasm_bg.wasm +0 -0
- package/native/wasm/pkg-node/clawpowers_wasm_bg.wasm.d.ts +40 -0
- package/native/wasm/pkg-node/package.json +13 -0
- package/native/wasm/src/lib.rs +433 -0
- package/package.json +71 -44
- package/src/skills/catalog.ts +435 -0
- package/src/skills/executor.ts +56 -0
- package/src/skills/index.ts +3 -0
- package/src/skills/itp/SKILL.md +112 -0
- package/src/skills/loader.ts +193 -0
- package/.claude-plugin/manifest.json +0 -19
- package/.codex/INSTALL.md +0 -36
- package/.cursor-plugin/manifest.json +0 -21
- package/.opencode/INSTALL.md +0 -52
- package/ARCHITECTURE.md +0 -69
- package/bin/clawpowers.js +0 -625
- package/bin/clawpowers.sh +0 -91
- package/docs/demo/clawpowers-demo.cast +0 -197
- package/docs/demo/clawpowers-demo.gif +0 -0
- package/docs/launch-images/25-skills-breakdown.jpg +0 -0
- package/docs/launch-images/clawpowers-vs-superpowers.jpg +0 -0
- package/docs/launch-images/economic-code-optimization.jpg +0 -0
- package/docs/launch-images/native-vs-bridge-2.jpg +0 -0
- package/docs/launch-images/native-vs-bridge.jpg +0 -0
- package/docs/launch-images/post1-hero-lobster.jpg +0 -0
- package/docs/launch-images/post2-dashboard.jpg +0 -0
- package/docs/launch-images/post3-superpowers.jpg +0 -0
- package/docs/launch-images/post4-before-after.jpg +0 -0
- package/docs/launch-images/post5-install-now.jpg +0 -0
- package/docs/launch-images/ultimate-stack.jpg +0 -0
- package/docs/launch-posts.md +0 -76
- package/docs/quickstart-first-transaction.md +0 -204
- package/gemini-extension.json +0 -32
- package/hooks/session-start +0 -205
- package/hooks/session-start.cmd +0 -43
- package/hooks/session-start.js +0 -163
- package/runtime/demo/README.md +0 -78
- package/runtime/demo/x402-mock-server.js +0 -230
- package/runtime/feedback/analyze.js +0 -621
- package/runtime/feedback/analyze.sh +0 -546
- package/runtime/init.js +0 -210
- package/runtime/init.sh +0 -178
- package/runtime/metrics/collector.js +0 -361
- package/runtime/metrics/collector.sh +0 -308
- package/runtime/payments/ledger.js +0 -305
- package/runtime/payments/ledger.sh +0 -262
- package/runtime/payments/pipeline.js +0 -455
- package/runtime/persistence/store.js +0 -433
- package/runtime/persistence/store.sh +0 -303
- package/skill.json +0 -106
- package/skills/agent-bounties/SKILL.md +0 -553
- package/skills/agent-payments/SKILL.md +0 -479
- package/skills/brainstorming/SKILL.md +0 -233
- package/skills/content-pipeline/SKILL.md +0 -282
- package/skills/cross-project-knowledge/SKILL.md +0 -345
- package/skills/dispatching-parallel-agents/SKILL.md +0 -305
- package/skills/economic-code-optimization/SKILL.md +0 -265
- package/skills/executing-plans/SKILL.md +0 -255
- package/skills/finishing-a-development-branch/SKILL.md +0 -260
- package/skills/formal-verification-lite/SKILL.md +0 -441
- package/skills/learn-how-to-learn/SKILL.md +0 -235
- package/skills/market-intelligence/SKILL.md +0 -323
- package/skills/meta-skill-evolution/SKILL.md +0 -325
- package/skills/prospecting/SKILL.md +0 -454
- package/skills/receiving-code-review/SKILL.md +0 -225
- package/skills/requesting-code-review/SKILL.md +0 -206
- package/skills/security-audit/SKILL.md +0 -353
- package/skills/self-healing-code/SKILL.md +0 -369
- package/skills/subagent-driven-development/SKILL.md +0 -244
- package/skills/systematic-debugging/SKILL.md +0 -355
- package/skills/test-driven-development/SKILL.md +0 -416
- package/skills/using-clawpowers/SKILL.md +0 -160
- package/skills/using-git-worktrees/SKILL.md +0 -261
- package/skills/validator/SKILL.md +0 -281
- package/skills/verification-before-completion/SKILL.md +0 -254
- package/skills/writing-plans/SKILL.md +0 -276
- package/skills/writing-skills/SKILL.md +0 -260
|
Binary file
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const __wbg_wasmcanonicalstore_free: (a: number, b: number) => void;
|
|
5
|
+
export const approximateDistance: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
6
|
+
export const calculateFee: (a: number, b: number, c: number, d: number, e: number, f: bigint, g: number, h: bigint) => [number, number, number, number];
|
|
7
|
+
export const compressVector: (a: number, b: number, c: number) => [number, number, number, number];
|
|
8
|
+
export const computeKeccak256: (a: number, b: number) => [number, number];
|
|
9
|
+
export const computeSha256: (a: number, b: number) => [number, number];
|
|
10
|
+
export const decompressVector: (a: number, b: number, c: number) => [number, number, number, number];
|
|
11
|
+
export const deriveEthereumAddress: (a: number, b: number) => [number, number, number, number];
|
|
12
|
+
export const derivePublicKey: (a: number, b: number) => [number, number, number, number];
|
|
13
|
+
export const evaluateWriteFirewall: (a: number, b: number) => [number, number, number, number];
|
|
14
|
+
export const getAvailableModules: () => [number, number];
|
|
15
|
+
export const getDefaultTokenRegistry: () => [number, number, number, number];
|
|
16
|
+
export const getVersion: () => [number, number];
|
|
17
|
+
export const signEcdsa: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|
|
18
|
+
export const tokenAmountAdd: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|
|
19
|
+
export const tokenAmountFromHuman: (a: number, b: number) => [number, number, number, number];
|
|
20
|
+
export const tokenAmountMulBps: (a: number, b: number, c: bigint) => [number, number, number, number];
|
|
21
|
+
export const tokenAmountSub: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|
|
22
|
+
export const tokenAmountToHuman: (a: number, b: number) => [number, number, number];
|
|
23
|
+
export const verifyEcdsa: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
|
|
24
|
+
export const wasmcanonicalstore_exportJson: (a: number) => [number, number, number, number];
|
|
25
|
+
export const wasmcanonicalstore_get: (a: number, b: number, c: number) => [number, number, number, number];
|
|
26
|
+
export const wasmcanonicalstore_getByHash: (a: number, b: number, c: number) => [number, number, number, number];
|
|
27
|
+
export const wasmcanonicalstore_importJson: (a: number, b: number, c: number) => [number, number, number];
|
|
28
|
+
export const wasmcanonicalstore_insert: (a: number, b: number, c: number) => [number, number, number, number];
|
|
29
|
+
export const wasmcanonicalstore_new: () => [number, number, number];
|
|
30
|
+
export const wasmcanonicalstore_queryNamespace: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|
|
31
|
+
export const wasmcanonicalstore_softDelete: (a: number, b: number, c: number) => [number, number, number];
|
|
32
|
+
export const wasmcanonicalstore_verifyIntegrity: (a: number, b: number, c: number) => [number, number, number];
|
|
33
|
+
export const __wbindgen_exn_store: (a: number) => void;
|
|
34
|
+
export const __externref_table_alloc: () => number;
|
|
35
|
+
export const __wbindgen_externrefs: WebAssembly.Table;
|
|
36
|
+
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
37
|
+
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
38
|
+
export const __externref_table_dealloc: (a: number) => void;
|
|
39
|
+
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
|
40
|
+
export const __wbindgen_start: () => void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clawpowers-wasm",
|
|
3
|
+
"description": "WASM bindings for ClawPowers core — tokens, fees, policy, compression, index, canonical, verification, security",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"license": "BUSL-1.1",
|
|
6
|
+
"files": [
|
|
7
|
+
"clawpowers_wasm_bg.wasm",
|
|
8
|
+
"clawpowers_wasm.js",
|
|
9
|
+
"clawpowers_wasm.d.ts"
|
|
10
|
+
],
|
|
11
|
+
"main": "clawpowers_wasm.js",
|
|
12
|
+
"types": "clawpowers_wasm.d.ts"
|
|
13
|
+
}
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
//! WASM bindings for ClawPowers core.
|
|
2
|
+
//!
|
|
3
|
+
//! Exposes the following modules via `wasm-bindgen`:
|
|
4
|
+
//!
|
|
5
|
+
//! - **tokens** — Token registry, token amounts, decimal math
|
|
6
|
+
//! - **fee** — Fee schedule calculation
|
|
7
|
+
//! - **policy** — Spending policy engine
|
|
8
|
+
//! - **compression** — TurboQuant vector compression
|
|
9
|
+
//! - **index** — In-memory vector index
|
|
10
|
+
//! - **canonical** — Canonical record store (in-memory backend for WASM)
|
|
11
|
+
//! - **verification** — Record verification pipeline
|
|
12
|
+
//! - **security** — Write firewall and audit log
|
|
13
|
+
//!
|
|
14
|
+
//! **NOT included (falls back to TypeScript):**
|
|
15
|
+
//! - **wallet** — Uses `alloy-signer-local` which depends on native crypto
|
|
16
|
+
//! primitives that are not fully WASM-compatible without significant patching.
|
|
17
|
+
//! The TypeScript fallback uses `ethers.js` / `viem` for equivalent functionality.
|
|
18
|
+
//! - **x402** — Uses `reqwest` with `tokio` runtime; in WASM, HTTP is handled
|
|
19
|
+
//! natively by `fetch()` in the TypeScript layer.
|
|
20
|
+
|
|
21
|
+
use wasm_bindgen::prelude::*;
|
|
22
|
+
|
|
23
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
24
|
+
// Tokens
|
|
25
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
26
|
+
|
|
27
|
+
/// Create a TokenAmount from a human-readable f64 value and decimal count.
|
|
28
|
+
/// Returns JSON: `{"raw": "...", "decimals": N}`
|
|
29
|
+
#[wasm_bindgen(js_name = "tokenAmountFromHuman")]
|
|
30
|
+
pub fn token_amount_from_human(human: f64, decimals: u8) -> Result<String, JsError> {
|
|
31
|
+
let amount = clawpowers_tokens::TokenAmount::from_human(human, decimals);
|
|
32
|
+
Ok(serde_json::to_string(&amount)?)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Convert a TokenAmount JSON back to a human-readable f64.
|
|
36
|
+
#[wasm_bindgen(js_name = "tokenAmountToHuman")]
|
|
37
|
+
pub fn token_amount_to_human(json: &str) -> Result<f64, JsError> {
|
|
38
|
+
let amount: clawpowers_tokens::TokenAmount = serde_json::from_str(json)?;
|
|
39
|
+
Ok(amount.to_human())
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Add two TokenAmount JSONs. Returns the sum as JSON.
|
|
43
|
+
#[wasm_bindgen(js_name = "tokenAmountAdd")]
|
|
44
|
+
pub fn token_amount_add(a_json: &str, b_json: &str) -> Result<String, JsError> {
|
|
45
|
+
let a: clawpowers_tokens::TokenAmount = serde_json::from_str(a_json)?;
|
|
46
|
+
let b: clawpowers_tokens::TokenAmount = serde_json::from_str(b_json)?;
|
|
47
|
+
let result = a.add(&b).map_err(|e| JsError::new(&e.to_string()))?;
|
|
48
|
+
Ok(serde_json::to_string(&result)?)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// Subtract two TokenAmount JSONs. Returns the difference as JSON.
|
|
52
|
+
#[wasm_bindgen(js_name = "tokenAmountSub")]
|
|
53
|
+
pub fn token_amount_sub(a_json: &str, b_json: &str) -> Result<String, JsError> {
|
|
54
|
+
let a: clawpowers_tokens::TokenAmount = serde_json::from_str(a_json)?;
|
|
55
|
+
let b: clawpowers_tokens::TokenAmount = serde_json::from_str(b_json)?;
|
|
56
|
+
let result = a.sub(&b).map_err(|e| JsError::new(&e.to_string()))?;
|
|
57
|
+
Ok(serde_json::to_string(&result)?)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// Multiply a TokenAmount by basis points. Returns result as JSON.
|
|
61
|
+
#[wasm_bindgen(js_name = "tokenAmountMulBps")]
|
|
62
|
+
pub fn token_amount_mul_bps(json: &str, bps: u64) -> Result<String, JsError> {
|
|
63
|
+
let amount: clawpowers_tokens::TokenAmount = serde_json::from_str(json)?;
|
|
64
|
+
let result = amount
|
|
65
|
+
.checked_mul_bps(bps)
|
|
66
|
+
.ok_or_else(|| JsError::new("overflow in checked_mul_bps"))?;
|
|
67
|
+
Ok(serde_json::to_string(&result)?)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// Get the default token registry as JSON.
|
|
71
|
+
#[wasm_bindgen(js_name = "getDefaultTokenRegistry")]
|
|
72
|
+
pub fn get_default_token_registry() -> Result<String, JsError> {
|
|
73
|
+
let registry = clawpowers_tokens::TokenRegistry::default();
|
|
74
|
+
let tokens: Vec<_> = registry.iter().collect();
|
|
75
|
+
Ok(serde_json::to_string(&tokens)?)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
79
|
+
// Fee
|
|
80
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
81
|
+
|
|
82
|
+
/// Calculate a transaction fee.
|
|
83
|
+
/// Returns JSON: `{"gross_amount": ..., "fee_amount": ..., "net_amount": ...}`
|
|
84
|
+
#[wasm_bindgen(js_name = "calculateFee")]
|
|
85
|
+
pub fn calculate_fee(
|
|
86
|
+
amount_json: &str,
|
|
87
|
+
fee_type: &str,
|
|
88
|
+
tx_fee_bps: Option<u64>,
|
|
89
|
+
swap_fee_bps: Option<u64>,
|
|
90
|
+
) -> Result<String, JsError> {
|
|
91
|
+
let amount: clawpowers_tokens::TokenAmount = serde_json::from_str(amount_json)?;
|
|
92
|
+
|
|
93
|
+
let fee_type = match fee_type {
|
|
94
|
+
"transaction" => clawpowers_fee::FeeType::Transaction,
|
|
95
|
+
"swap" => clawpowers_fee::FeeType::Swap,
|
|
96
|
+
s if s.starts_with("custom:") => {
|
|
97
|
+
let bps: u64 = s[7..]
|
|
98
|
+
.parse()
|
|
99
|
+
.map_err(|_| JsError::new("invalid custom bps"))?;
|
|
100
|
+
clawpowers_fee::FeeType::Custom(bps)
|
|
101
|
+
}
|
|
102
|
+
_ => return Err(JsError::new("fee_type must be 'transaction', 'swap', or 'custom:N'")),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
let schedule = clawpowers_fee::FeeSchedule::new(
|
|
106
|
+
tx_fee_bps.unwrap_or(clawpowers_fee::DEFAULT_TX_FEE_BPS),
|
|
107
|
+
swap_fee_bps.unwrap_or(clawpowers_fee::DEFAULT_SWAP_FEE_BPS),
|
|
108
|
+
alloy_primitives::Address::ZERO,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
let calc = schedule
|
|
112
|
+
.calculate(amount, fee_type)
|
|
113
|
+
.map_err(|e| JsError::new(&e.to_string()))?;
|
|
114
|
+
|
|
115
|
+
let result = serde_json::json!({
|
|
116
|
+
"gross_amount": calc.gross_amount.to_human(),
|
|
117
|
+
"fee_amount": calc.fee_amount.to_human(),
|
|
118
|
+
"net_amount": calc.net_amount.to_human(),
|
|
119
|
+
});
|
|
120
|
+
Ok(serde_json::to_string(&result)?)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
124
|
+
// Compression
|
|
125
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
126
|
+
|
|
127
|
+
/// Compress a float32 vector. Input: JSON array of f32. Output: CompressedVector JSON.
|
|
128
|
+
#[wasm_bindgen(js_name = "compressVector")]
|
|
129
|
+
pub fn compress_vector(vector_json: &str, dimensions: usize) -> Result<String, JsError> {
|
|
130
|
+
let vector: Vec<f32> = serde_json::from_str(vector_json)?;
|
|
131
|
+
let config = clawpowers_compression::CompressionConfig {
|
|
132
|
+
dimensions,
|
|
133
|
+
quantization_bits: 8,
|
|
134
|
+
rotation_seed: 0xDEAD_BEEF_CAFE_1234,
|
|
135
|
+
};
|
|
136
|
+
let compressor = clawpowers_compression::TurboCompressor::new(config);
|
|
137
|
+
let compressed = compressor
|
|
138
|
+
.compress(&vector)
|
|
139
|
+
.map_err(|e| JsError::new(&e.to_string()))?;
|
|
140
|
+
Ok(serde_json::to_string(&compressed)?)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// Decompress a CompressedVector JSON back to a float32 array JSON.
|
|
144
|
+
#[wasm_bindgen(js_name = "decompressVector")]
|
|
145
|
+
pub fn decompress_vector(compressed_json: &str, dimensions: usize) -> Result<String, JsError> {
|
|
146
|
+
let compressed: clawpowers_compression::CompressedVector =
|
|
147
|
+
serde_json::from_str(compressed_json)?;
|
|
148
|
+
let config = clawpowers_compression::CompressionConfig {
|
|
149
|
+
dimensions,
|
|
150
|
+
quantization_bits: 8,
|
|
151
|
+
rotation_seed: 0xDEAD_BEEF_CAFE_1234,
|
|
152
|
+
};
|
|
153
|
+
let compressor = clawpowers_compression::TurboCompressor::new(config);
|
|
154
|
+
let vector = compressor
|
|
155
|
+
.decompress(&compressed)
|
|
156
|
+
.map_err(|e| JsError::new(&e.to_string()))?;
|
|
157
|
+
Ok(serde_json::to_string(&vector)?)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/// Compute approximate distance between two CompressedVector JSONs.
|
|
161
|
+
#[wasm_bindgen(js_name = "approximateDistance")]
|
|
162
|
+
pub fn approximate_distance(
|
|
163
|
+
a_json: &str,
|
|
164
|
+
b_json: &str,
|
|
165
|
+
dimensions: usize,
|
|
166
|
+
) -> Result<f32, JsError> {
|
|
167
|
+
let a: clawpowers_compression::CompressedVector = serde_json::from_str(a_json)?;
|
|
168
|
+
let b: clawpowers_compression::CompressedVector = serde_json::from_str(b_json)?;
|
|
169
|
+
let config = clawpowers_compression::CompressionConfig {
|
|
170
|
+
dimensions,
|
|
171
|
+
quantization_bits: 8,
|
|
172
|
+
rotation_seed: 0xDEAD_BEEF_CAFE_1234,
|
|
173
|
+
};
|
|
174
|
+
let compressor = clawpowers_compression::TurboCompressor::new(config);
|
|
175
|
+
let dist = compressor
|
|
176
|
+
.approximate_distance(&a, &b)
|
|
177
|
+
.map_err(|e| JsError::new(&e.to_string()))?;
|
|
178
|
+
Ok(dist)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/// Compute SHA-256 hash of content string.
|
|
182
|
+
#[wasm_bindgen(js_name = "computeSha256")]
|
|
183
|
+
pub fn compute_sha256(content: &str) -> String {
|
|
184
|
+
clawpowers_canonical::compute_sha256(content)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/// Compute Keccak-256 hash of raw bytes (EVM-compatible). Returns `0x` + 64 hex chars.
|
|
188
|
+
#[wasm_bindgen(js_name = "computeKeccak256")]
|
|
189
|
+
pub fn compute_keccak256(bytes: &[u8]) -> String {
|
|
190
|
+
let h = alloy_primitives::keccak256(bytes);
|
|
191
|
+
format!("0x{:x}", h)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/// Ethereum address from 32-byte secp256k1 private key (`0x` + 20 bytes, EIP-55 checksum).
|
|
195
|
+
#[wasm_bindgen(js_name = "deriveEthereumAddress")]
|
|
196
|
+
pub fn derive_ethereum_address_wasm(private_key: &[u8]) -> Result<String, JsError> {
|
|
197
|
+
clawpowers_evm_eth::derive_ethereum_address(private_key).map_err(|e| JsError::new(&e))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/// Uncompressed public key: 64 bytes (x || y), no `0x04` prefix.
|
|
201
|
+
#[wasm_bindgen(js_name = "derivePublicKey")]
|
|
202
|
+
pub fn derive_public_key_wasm(private_key: &[u8]) -> Result<Vec<u8>, JsError> {
|
|
203
|
+
clawpowers_evm_eth::derive_public_key(private_key).map_err(|e| JsError::new(&e))
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/// ECDSA sign 32-byte message hash → 65 bytes (r || s || recovery_id).
|
|
207
|
+
#[wasm_bindgen(js_name = "signEcdsa")]
|
|
208
|
+
pub fn sign_ecdsa_wasm(private_key: &[u8], message_hash: &[u8]) -> Result<Vec<u8>, JsError> {
|
|
209
|
+
clawpowers_evm_eth::sign_ecdsa(private_key, message_hash).map_err(|e| JsError::new(&e))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
#[wasm_bindgen(js_name = "verifyEcdsa")]
|
|
213
|
+
pub fn verify_ecdsa_wasm(
|
|
214
|
+
public_key: &[u8],
|
|
215
|
+
message_hash: &[u8],
|
|
216
|
+
signature: &[u8],
|
|
217
|
+
) -> Result<bool, JsError> {
|
|
218
|
+
clawpowers_evm_eth::verify_ecdsa(public_key, message_hash, signature).map_err(|e| JsError::new(&e))
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
222
|
+
// Canonical Store
|
|
223
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
224
|
+
|
|
225
|
+
/// Opaque handle to an in-memory CanonicalStore.
|
|
226
|
+
#[wasm_bindgen]
|
|
227
|
+
pub struct WasmCanonicalStore {
|
|
228
|
+
inner: clawpowers_canonical::CanonicalStore,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
#[wasm_bindgen]
|
|
232
|
+
impl WasmCanonicalStore {
|
|
233
|
+
/// Create a new in-memory canonical store.
|
|
234
|
+
#[wasm_bindgen(constructor)]
|
|
235
|
+
pub fn new() -> Result<WasmCanonicalStore, JsError> {
|
|
236
|
+
let store = clawpowers_canonical::CanonicalStore::in_memory()
|
|
237
|
+
.map_err(|e| JsError::new(&e.to_string()))?;
|
|
238
|
+
Ok(Self { inner: store })
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/// Insert a record. Input: JSON with {namespace, content, metadata, provenance}.
|
|
242
|
+
/// Returns the record UUID as a string.
|
|
243
|
+
pub fn insert(&self, json: &str) -> Result<String, JsError> {
|
|
244
|
+
#[derive(serde::Deserialize)]
|
|
245
|
+
struct InsertInput {
|
|
246
|
+
namespace: String,
|
|
247
|
+
content: String,
|
|
248
|
+
#[serde(default)]
|
|
249
|
+
metadata: serde_json::Value,
|
|
250
|
+
#[serde(default = "default_provenance")]
|
|
251
|
+
provenance: String,
|
|
252
|
+
}
|
|
253
|
+
fn default_provenance() -> String {
|
|
254
|
+
"wasm".to_string()
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let input: InsertInput = serde_json::from_str(json)?;
|
|
258
|
+
let record = clawpowers_canonical::CanonicalRecord::new(
|
|
259
|
+
input.namespace,
|
|
260
|
+
input.content,
|
|
261
|
+
None,
|
|
262
|
+
input.metadata,
|
|
263
|
+
input.provenance,
|
|
264
|
+
);
|
|
265
|
+
let id = self
|
|
266
|
+
.inner
|
|
267
|
+
.insert(&record)
|
|
268
|
+
.map_err(|e| JsError::new(&e.to_string()))?;
|
|
269
|
+
Ok(id.to_string())
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/// Get a record by UUID. Returns JSON or null.
|
|
273
|
+
pub fn get(&self, id: &str) -> Result<Option<String>, JsError> {
|
|
274
|
+
let uuid = uuid::Uuid::parse_str(id).map_err(|e| JsError::new(&e.to_string()))?;
|
|
275
|
+
let record = self
|
|
276
|
+
.inner
|
|
277
|
+
.get(&uuid)
|
|
278
|
+
.map_err(|e| JsError::new(&e.to_string()))?;
|
|
279
|
+
match record {
|
|
280
|
+
Some(r) => Ok(Some(serde_json::to_string(&r)?)),
|
|
281
|
+
None => Ok(None),
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/// Get a record by content hash. Returns JSON or null.
|
|
286
|
+
#[wasm_bindgen(js_name = "getByHash")]
|
|
287
|
+
pub fn get_by_hash(&self, hash: &str) -> Result<Option<String>, JsError> {
|
|
288
|
+
let record = self
|
|
289
|
+
.inner
|
|
290
|
+
.get_by_hash(hash)
|
|
291
|
+
.map_err(|e| JsError::new(&e.to_string()))?;
|
|
292
|
+
match record {
|
|
293
|
+
Some(r) => Ok(Some(serde_json::to_string(&r)?)),
|
|
294
|
+
None => Ok(None),
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/// Query records by namespace. Returns JSON array.
|
|
299
|
+
#[wasm_bindgen(js_name = "queryNamespace")]
|
|
300
|
+
pub fn query_namespace(&self, namespace: &str, limit: usize) -> Result<String, JsError> {
|
|
301
|
+
let records = self
|
|
302
|
+
.inner
|
|
303
|
+
.query_namespace(namespace, limit)
|
|
304
|
+
.map_err(|e| JsError::new(&e.to_string()))?;
|
|
305
|
+
Ok(serde_json::to_string(&records)?)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/// Soft-delete a record. Returns true if the record existed.
|
|
309
|
+
#[wasm_bindgen(js_name = "softDelete")]
|
|
310
|
+
pub fn soft_delete(&self, id: &str) -> Result<bool, JsError> {
|
|
311
|
+
let uuid = uuid::Uuid::parse_str(id).map_err(|e| JsError::new(&e.to_string()))?;
|
|
312
|
+
self.inner
|
|
313
|
+
.soft_delete(&uuid)
|
|
314
|
+
.map_err(|e| JsError::new(&e.to_string()))
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/// Verify record integrity. Returns true if hash matches.
|
|
318
|
+
#[wasm_bindgen(js_name = "verifyIntegrity")]
|
|
319
|
+
pub fn verify_integrity(&self, id: &str) -> Result<bool, JsError> {
|
|
320
|
+
let uuid = uuid::Uuid::parse_str(id).map_err(|e| JsError::new(&e.to_string()))?;
|
|
321
|
+
self.inner
|
|
322
|
+
.verify_integrity(&uuid)
|
|
323
|
+
.map_err(|e| JsError::new(&e.to_string()))
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/// Export all records as JSON for IndexedDB persistence.
|
|
327
|
+
#[wasm_bindgen(js_name = "exportJson")]
|
|
328
|
+
pub fn export_json(&self) -> Result<String, JsError> {
|
|
329
|
+
self.inner
|
|
330
|
+
.export_json()
|
|
331
|
+
.map_err(|e| JsError::new(&e.to_string()))
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/// Import records from JSON (e.g., loaded from IndexedDB).
|
|
335
|
+
#[wasm_bindgen(js_name = "importJson")]
|
|
336
|
+
pub fn import_json(&self, json: &str) -> Result<usize, JsError> {
|
|
337
|
+
self.inner
|
|
338
|
+
.import_json(json)
|
|
339
|
+
.map_err(|e| JsError::new(&e.to_string()))
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
344
|
+
// Security — Write Firewall
|
|
345
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
346
|
+
|
|
347
|
+
/// Evaluate a write request against a firewall.
|
|
348
|
+
/// Input JSON: {namespace, content, trust_level, source, allowed_namespaces?, blocked_patterns?, max_content_length?}
|
|
349
|
+
/// Returns JSON: {"decision": "allow"|"deny"|"sanitize", "reason"?: ..., "sanitized"?: ...}
|
|
350
|
+
#[wasm_bindgen(js_name = "evaluateWriteFirewall")]
|
|
351
|
+
pub fn evaluate_write_firewall(json: &str) -> Result<String, JsError> {
|
|
352
|
+
#[derive(serde::Deserialize)]
|
|
353
|
+
struct Input {
|
|
354
|
+
namespace: String,
|
|
355
|
+
content: String,
|
|
356
|
+
trust_level: String,
|
|
357
|
+
source: String,
|
|
358
|
+
#[serde(default)]
|
|
359
|
+
allowed_namespaces: Vec<String>,
|
|
360
|
+
#[serde(default)]
|
|
361
|
+
blocked_patterns: Vec<String>,
|
|
362
|
+
max_content_length: Option<usize>,
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
let input: Input = serde_json::from_str(json)?;
|
|
366
|
+
|
|
367
|
+
let trust = match input.trust_level.as_str() {
|
|
368
|
+
"system" => clawpowers_security::TrustLevel::System,
|
|
369
|
+
"agent" => clawpowers_security::TrustLevel::Agent,
|
|
370
|
+
"external" => clawpowers_security::TrustLevel::External,
|
|
371
|
+
_ => clawpowers_security::TrustLevel::Untrusted,
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
let mut firewall = clawpowers_security::WriteFirewall::new(input.allowed_namespaces);
|
|
375
|
+
firewall.blocked_patterns = input.blocked_patterns;
|
|
376
|
+
if let Some(max) = input.max_content_length {
|
|
377
|
+
firewall.max_content_length = max;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
let request = clawpowers_security::WriteRequest {
|
|
381
|
+
namespace: input.namespace,
|
|
382
|
+
content: input.content,
|
|
383
|
+
trust_level: trust,
|
|
384
|
+
source: input.source,
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
let decision = firewall.evaluate(&request);
|
|
388
|
+
let result = match decision {
|
|
389
|
+
clawpowers_security::FirewallDecision::Allow => {
|
|
390
|
+
serde_json::json!({"decision": "allow"})
|
|
391
|
+
}
|
|
392
|
+
clawpowers_security::FirewallDecision::Deny(reason) => {
|
|
393
|
+
serde_json::json!({"decision": "deny", "reason": reason})
|
|
394
|
+
}
|
|
395
|
+
clawpowers_security::FirewallDecision::Sanitize(original, sanitized) => {
|
|
396
|
+
serde_json::json!({"decision": "sanitize", "original": original, "sanitized": sanitized})
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
Ok(serde_json::to_string(&result)?)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
403
|
+
// Version info
|
|
404
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
405
|
+
|
|
406
|
+
/// Returns the version and build info.
|
|
407
|
+
#[wasm_bindgen(js_name = "getVersion")]
|
|
408
|
+
pub fn get_version() -> String {
|
|
409
|
+
format!(
|
|
410
|
+
"clawpowers-wasm v{} ({})",
|
|
411
|
+
env!("CARGO_PKG_VERSION"),
|
|
412
|
+
if cfg!(debug_assertions) {
|
|
413
|
+
"debug"
|
|
414
|
+
} else {
|
|
415
|
+
"release"
|
|
416
|
+
}
|
|
417
|
+
)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/// Returns a list of modules available in this WASM build.
|
|
421
|
+
#[wasm_bindgen(js_name = "getAvailableModules")]
|
|
422
|
+
pub fn get_available_modules() -> String {
|
|
423
|
+
serde_json::to_string(&vec![
|
|
424
|
+
"tokens",
|
|
425
|
+
"fee",
|
|
426
|
+
"compression",
|
|
427
|
+
"canonical",
|
|
428
|
+
"verification",
|
|
429
|
+
"security",
|
|
430
|
+
"index",
|
|
431
|
+
])
|
|
432
|
+
.unwrap_or_default()
|
|
433
|
+
}
|
package/package.json
CHANGED
|
@@ -1,59 +1,86 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawpowers",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
"
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "Skills library for AI agents — payments, memory, RSI, wallet. Drop-in capability layer for any agent framework.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"src/skills",
|
|
18
|
+
"native/Cargo.toml",
|
|
19
|
+
"native/Cargo.lock",
|
|
20
|
+
"native/crates",
|
|
21
|
+
"native/ffi",
|
|
22
|
+
"native/wasm",
|
|
23
|
+
"native/wasm/pkg",
|
|
24
|
+
"native/wasm/pkg-node",
|
|
25
|
+
"native/pyo3",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"CHANGELOG.md",
|
|
29
|
+
"SECURITY.md",
|
|
30
|
+
"COMPATIBILITY.md",
|
|
31
|
+
"KNOWN_LIMITATIONS.md",
|
|
32
|
+
"LICENSING.md"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build:native": "cd native && cargo build --release --workspace || echo 'Rust not installed - using WASM/TS fallback'",
|
|
36
|
+
"build:wasm": "cd native/wasm && wasm-pack build --target nodejs --out-dir pkg-node || true",
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest",
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"lint": "eslint src tests benchmarks",
|
|
42
|
+
"verify:pack": "npm pack --dry-run",
|
|
43
|
+
"clean": "rm -rf dist",
|
|
44
|
+
"prepublishOnly": "npm run build",
|
|
45
|
+
"prepack": "npm run build"
|
|
11
46
|
},
|
|
12
47
|
"keywords": [
|
|
13
48
|
"ai-agent",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"cursor",
|
|
18
|
-
"codex",
|
|
19
|
-
"opencode",
|
|
20
|
-
"gemini",
|
|
49
|
+
"payments",
|
|
50
|
+
"x402",
|
|
51
|
+
"memory",
|
|
21
52
|
"rsi",
|
|
22
53
|
"self-improvement",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
54
|
+
"wallet",
|
|
55
|
+
"skills",
|
|
56
|
+
"langchain",
|
|
57
|
+
"claude",
|
|
58
|
+
"elizaos"
|
|
27
59
|
],
|
|
28
|
-
"
|
|
29
|
-
|
|
60
|
+
"author": "AI Agent Economy <bill@ai-agent-economy.com>",
|
|
61
|
+
"license": "BSL-1.1",
|
|
62
|
+
"repository": {
|
|
63
|
+
"type": "git",
|
|
64
|
+
"url": "https://github.com/up2itnow0822/ClawPowers-Skills"
|
|
30
65
|
},
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"test": "bash tests/run_all.sh",
|
|
34
|
-
"lint": "eslint bin/ runtime/"
|
|
66
|
+
"bugs": {
|
|
67
|
+
"url": "https://github.com/up2itnow0822/ClawPowers-Skills/issues"
|
|
35
68
|
},
|
|
36
|
-
"
|
|
37
|
-
"bin/",
|
|
38
|
-
"skills/",
|
|
39
|
-
"runtime/",
|
|
40
|
-
"hooks/",
|
|
41
|
-
"plugins/",
|
|
42
|
-
".claude-plugin/",
|
|
43
|
-
".cursor-plugin/",
|
|
44
|
-
".codex/",
|
|
45
|
-
".opencode/",
|
|
46
|
-
"gemini-extension.json",
|
|
47
|
-
"skill.json",
|
|
48
|
-
"README.md",
|
|
49
|
-
"ARCHITECTURE.md",
|
|
50
|
-
"docs/"
|
|
51
|
-
],
|
|
69
|
+
"homepage": "https://github.com/up2itnow0822/ClawPowers-Skills#readme",
|
|
52
70
|
"engines": {
|
|
53
|
-
"node": ">=
|
|
71
|
+
"node": ">=20.0.0"
|
|
72
|
+
},
|
|
73
|
+
"dependencies": {
|
|
74
|
+
"zod": "^3.23.0"
|
|
54
75
|
},
|
|
55
76
|
"devDependencies": {
|
|
56
|
-
"
|
|
57
|
-
"
|
|
77
|
+
"@types/node": "^25.5.0",
|
|
78
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
79
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
80
|
+
"eslint": "^9.0.0",
|
|
81
|
+
"globals": "^15.0.0",
|
|
82
|
+
"tsup": "^8.0.0",
|
|
83
|
+
"typescript": "^5.5.0",
|
|
84
|
+
"vitest": "^2.0.0"
|
|
58
85
|
}
|
|
59
86
|
}
|