clawpowers 2.2.6 → 2.2.7
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 +186 -175
- package/COMPATIBILITY.md +48 -13
- package/KNOWN_LIMITATIONS.md +20 -19
- package/LICENSE +44 -44
- package/LICENSING.md +10 -10
- package/README.md +486 -462
- package/SECURITY.md +52 -52
- package/dist/index.d.ts +17 -5
- package/dist/index.js +186 -91
- package/dist/index.js.map +1 -1
- package/native/Cargo.lock +4927 -4927
- package/native/Cargo.toml +73 -73
- package/native/crates/canonical/Cargo.toml +24 -24
- package/native/crates/canonical/src/lib.rs +677 -677
- package/native/crates/compression/Cargo.toml +20 -20
- package/native/crates/compression/benches/compression_bench.rs +42 -42
- package/native/crates/compression/src/lib.rs +393 -393
- package/native/crates/evm-eth/Cargo.toml +13 -13
- package/native/crates/evm-eth/src/lib.rs +105 -105
- package/native/crates/fee/Cargo.toml +15 -15
- package/native/crates/fee/src/lib.rs +281 -281
- package/native/crates/index/Cargo.toml +16 -16
- package/native/crates/index/src/lib.rs +277 -277
- package/native/crates/policy/Cargo.toml +17 -17
- package/native/crates/policy/src/lib.rs +614 -614
- package/native/crates/security/Cargo.toml +22 -22
- package/native/crates/security/src/lib.rs +478 -478
- package/native/crates/tokens/Cargo.toml +13 -13
- package/native/crates/tokens/src/lib.rs +534 -534
- package/native/crates/verification/Cargo.toml +23 -23
- package/native/crates/verification/src/lib.rs +333 -333
- package/native/crates/wallet/Cargo.toml +20 -20
- package/native/crates/wallet/src/lib.rs +261 -261
- package/native/crates/x402/Cargo.toml +30 -30
- package/native/crates/x402/src/lib.rs +423 -423
- package/native/ffi/Cargo.toml +34 -34
- package/native/ffi/build.rs +4 -4
- package/native/ffi/src/lib.rs +352 -352
- package/native/ffi/tests/integration.rs +354 -354
- package/native/pyo3/Cargo.toml +26 -26
- package/native/pyo3/pyproject.toml +16 -16
- package/native/pyo3/src/lib.rs +407 -407
- package/native/pyo3/tests/test_smoke.py +180 -180
- package/native/wasm/Cargo.toml +47 -47
- package/native/wasm/pkg/.gitignore +6 -6
- package/native/wasm/pkg/clawpowers_wasm.d.ts +208 -208
- package/native/wasm/pkg/clawpowers_wasm.js +872 -872
- package/native/wasm/pkg/clawpowers_wasm_bg.wasm.d.ts +40 -40
- package/native/wasm/pkg/package.json +16 -16
- package/native/wasm/pkg-node/clawpowers_wasm.d.ts +143 -143
- package/native/wasm/pkg-node/clawpowers_wasm.js +798 -798
- package/native/wasm/pkg-node/clawpowers_wasm_bg.wasm.d.ts +40 -40
- package/native/wasm/pkg-node/package.json +12 -12
- package/native/wasm/src/lib.rs +433 -433
- package/package.json +12 -8
- package/scripts/build-wasm.mjs +59 -0
- package/scripts/generate_hermes_wrappers.py +211 -0
- package/scripts/hermes_wrapper_overrides.json +184 -0
- package/scripts/run-python-script.mjs +48 -0
- package/scripts/verify-consumer-install.mjs +109 -0
- package/scripts/verify-wasm-artifacts.mjs +25 -2
- package/scripts/verify_hermes_wrappers.py +154 -0
- package/skill.json +1 -1
- package/skills/1password/SKILL.md +34 -0
- package/skills/README.md +44 -0
- package/skills/agent-nexus-2/SKILL.md +34 -0
- package/skills/apple-notes/SKILL.md +34 -0
- package/skills/apple-reminders/SKILL.md +34 -0
- package/skills/autoresearch/SKILL.md +43 -0
- package/skills/bear-notes/SKILL.md +34 -0
- package/skills/blogwatcher/SKILL.md +34 -0
- package/skills/blucli/SKILL.md +34 -0
- package/skills/bluebubbles/SKILL.md +34 -0
- package/skills/business-strategy/SKILL.md +41 -0
- package/skills/camsnap/SKILL.md +34 -0
- package/skills/canvas/SKILL.md +34 -0
- package/skills/clawhub/SKILL.md +34 -0
- package/skills/coding-agent/SKILL.md +34 -0
- package/skills/coding-discipline.skill/SKILL.md +34 -0
- package/skills/content-writer/SKILL.md +41 -0
- package/skills/discord/SKILL.md +34 -0
- package/skills/eightctl/SKILL.md +34 -0
- package/skills/execution-validation.skill/SKILL.md +34 -0
- package/skills/gemini/SKILL.md +34 -0
- package/skills/gh-issues/SKILL.md +34 -0
- package/skills/gifgrep/SKILL.md +34 -0
- package/skills/github/SKILL.md +41 -0
- package/skills/gog/SKILL.md +34 -0
- package/skills/goplaces/SKILL.md +34 -0
- package/skills/healthcheck/SKILL.md +34 -0
- package/skills/himalaya/SKILL.md +34 -0
- package/skills/humanize/SKILL.md +41 -0
- package/skills/imsg/SKILL.md +34 -0
- package/skills/itp/SKILL.md +112 -0
- package/skills/mcporter/SKILL.md +34 -0
- package/skills/model-usage/SKILL.md +34 -0
- package/skills/nano-pdf/SKILL.md +34 -0
- package/skills/node-connect/SKILL.md +34 -0
- package/skills/notion/SKILL.md +34 -0
- package/skills/obsidian/SKILL.md +34 -0
- package/skills/openai-whisper/SKILL.md +34 -0
- package/skills/openai-whisper-api/SKILL.md +34 -0
- package/skills/openhue/SKILL.md +34 -0
- package/skills/oracle/SKILL.md +34 -0
- package/skills/ordercli/SKILL.md +34 -0
- package/skills/peekaboo/SKILL.md +34 -0
- package/skills/polyclaw/SKILL.md +34 -0
- package/skills/prospector/SKILL.md +41 -0
- package/skills/rsi.skill/SKILL.md +34 -0
- package/skills/sag/SKILL.md +34 -0
- package/skills/security/SKILL.md +41 -0
- package/skills/session-logs/SKILL.md +34 -0
- package/skills/sherpa-onnx-tts/SKILL.md +34 -0
- package/skills/skill-creator/SKILL.md +34 -0
- package/skills/slack/SKILL.md +34 -0
- package/skills/songsee/SKILL.md +34 -0
- package/skills/sonoscli/SKILL.md +34 -0
- package/skills/spotify-player/SKILL.md +34 -0
- package/skills/strykr-prism/SKILL.md +41 -0
- package/skills/summarize/SKILL.md +34 -0
- package/skills/taskbridge/SKILL.md +34 -0
- package/skills/things-mac/SKILL.md +34 -0
- package/skills/tmux/SKILL.md +34 -0
- package/skills/trello/SKILL.md +34 -0
- package/skills/validator-agent/SKILL.md +41 -0
- package/skills/video-frames/SKILL.md +34 -0
- package/skills/voice-call/SKILL.md +34 -0
- package/skills/wacli/SKILL.md +34 -0
- package/skills/weather/SKILL.md +34 -0
- package/skills/webmcp-payments/SKILL.md +41 -0
- package/skills/xurl/SKILL.md +34 -0
- package/src/skills/catalog.ts +435 -435
- package/src/skills/executor.ts +56 -56
- package/src/skills/index.ts +3 -3
- package/src/skills/itp/SKILL.md +112 -112
- package/src/skills/loader.ts +262 -193
package/SECURITY.md
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
# Security Policy
|
|
2
|
-
|
|
3
|
-
## Supported Versions
|
|
4
|
-
|
|
5
|
-
| Version | Supported |
|
|
6
|
-
| ------- | --------- |
|
|
7
|
-
| 2.2.x | ✅ |
|
|
8
|
-
| 2.1.x | ✅ |
|
|
9
|
-
| < 2.1.0 | ❌ |
|
|
10
|
-
|
|
11
|
-
## Reporting a Vulnerability
|
|
12
|
-
|
|
13
|
-
Please report security issues privately to **bill@ai-agent-economy.com**.
|
|
14
|
-
|
|
15
|
-
Include:
|
|
16
|
-
- affected version
|
|
17
|
-
- reproduction steps
|
|
18
|
-
- impact assessment
|
|
19
|
-
- whether the issue affects native, WASM, or TypeScript fallback paths
|
|
20
|
-
|
|
21
|
-
Please do not open public GitHub issues for unpatched vulnerabilities.
|
|
22
|
-
|
|
23
|
-
## Response Expectations
|
|
24
|
-
|
|
25
|
-
- initial acknowledgement: within 3 business days
|
|
26
|
-
- severity triage: within 5 business days
|
|
27
|
-
- fix target: depends on impact and exploitability
|
|
28
|
-
|
|
29
|
-
## Scope Notes
|
|
30
|
-
|
|
31
|
-
ClawPowers ships wallet, payment, memory, and RSI primitives. Security-sensitive areas include:
|
|
32
|
-
- private key generation and storage
|
|
33
|
-
- payment policy enforcement
|
|
34
|
-
- x402 header creation and parsing
|
|
35
|
-
- native and WASM crypto fallbacks
|
|
36
|
-
- local file-backed memory stores
|
|
37
|
-
|
|
38
|
-
## Data Handling
|
|
39
|
-
|
|
40
|
-
ClawPowers is designed for local-first operation.
|
|
41
|
-
|
|
42
|
-
- no telemetry is sent by the library itself
|
|
43
|
-
- secrets are not intentionally exfiltrated by package code
|
|
44
|
-
- payment, wallet, and memory data storage behavior depends on the consuming application configuration
|
|
45
|
-
|
|
46
|
-
## Disclosure Policy
|
|
47
|
-
|
|
48
|
-
We prefer coordinated disclosure. After a fix is available, we may publish:
|
|
49
|
-
- affected versions
|
|
50
|
-
- impact summary
|
|
51
|
-
- remediation guidance
|
|
52
|
-
- CVE or advisory references when applicable
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
| Version | Supported |
|
|
6
|
+
| ------- | --------- |
|
|
7
|
+
| 2.2.x | ✅ |
|
|
8
|
+
| 2.1.x | ✅ |
|
|
9
|
+
| < 2.1.0 | ❌ |
|
|
10
|
+
|
|
11
|
+
## Reporting a Vulnerability
|
|
12
|
+
|
|
13
|
+
Please report security issues privately to **bill@ai-agent-economy.com**.
|
|
14
|
+
|
|
15
|
+
Include:
|
|
16
|
+
- affected version
|
|
17
|
+
- reproduction steps
|
|
18
|
+
- impact assessment
|
|
19
|
+
- whether the issue affects native, WASM, or TypeScript fallback paths
|
|
20
|
+
|
|
21
|
+
Please do not open public GitHub issues for unpatched vulnerabilities.
|
|
22
|
+
|
|
23
|
+
## Response Expectations
|
|
24
|
+
|
|
25
|
+
- initial acknowledgement: within 3 business days
|
|
26
|
+
- severity triage: within 5 business days
|
|
27
|
+
- fix target: depends on impact and exploitability
|
|
28
|
+
|
|
29
|
+
## Scope Notes
|
|
30
|
+
|
|
31
|
+
ClawPowers ships wallet, payment, memory, and RSI primitives. Security-sensitive areas include:
|
|
32
|
+
- private key generation and storage
|
|
33
|
+
- payment policy enforcement
|
|
34
|
+
- x402 header creation and parsing
|
|
35
|
+
- native and WASM crypto fallbacks
|
|
36
|
+
- local file-backed memory stores
|
|
37
|
+
|
|
38
|
+
## Data Handling
|
|
39
|
+
|
|
40
|
+
ClawPowers is designed for local-first operation.
|
|
41
|
+
|
|
42
|
+
- no telemetry is sent by the library itself
|
|
43
|
+
- secrets are not intentionally exfiltrated by package code
|
|
44
|
+
- payment, wallet, and memory data storage behavior depends on the consuming application configuration
|
|
45
|
+
|
|
46
|
+
## Disclosure Policy
|
|
47
|
+
|
|
48
|
+
We prefer coordinated disclosure. After a fix is available, we may publish:
|
|
49
|
+
- affected versions
|
|
50
|
+
- impact summary
|
|
51
|
+
- remediation guidance
|
|
52
|
+
- CVE or advisory references when applicable
|
package/dist/index.d.ts
CHANGED
|
@@ -347,7 +347,7 @@ declare function setConfigValue(config: ConfigFile, key: string, value: string):
|
|
|
347
347
|
* Default paths, version, config values, RSI tier boundaries.
|
|
348
348
|
*/
|
|
349
349
|
|
|
350
|
-
declare const VERSION = "2.2.
|
|
350
|
+
declare const VERSION = "2.2.7";
|
|
351
351
|
declare const PACKAGE_NAME = "clawpowers";
|
|
352
352
|
declare const CLAWPOWERS_HOME: string;
|
|
353
353
|
declare const DEFAULT_CONFIG: ConfigFile;
|
|
@@ -1085,14 +1085,26 @@ declare class SkillExecutor {
|
|
|
1085
1085
|
}
|
|
1086
1086
|
|
|
1087
1087
|
interface WalletConfig {
|
|
1088
|
-
readonly chain: 'base' | 'ethereum' | 'polygon';
|
|
1088
|
+
readonly chain: 'base' | 'ethereum' | 'polygon' | 'local';
|
|
1089
1089
|
readonly dataDir: string;
|
|
1090
|
+
/**
|
|
1091
|
+
* Passphrase used to encrypt newly generated/imported wallet key files.
|
|
1092
|
+
* If omitted, ClawPowers generates a high-entropy passphrase and returns it
|
|
1093
|
+
* on the WalletInfo object from generateWallet()/importWallet().
|
|
1094
|
+
*/
|
|
1095
|
+
readonly passphrase?: string;
|
|
1090
1096
|
}
|
|
1091
1097
|
interface WalletInfo {
|
|
1092
1098
|
readonly address: string;
|
|
1093
1099
|
readonly chain: string;
|
|
1094
1100
|
readonly createdAt: string;
|
|
1095
1101
|
readonly keyFile: string;
|
|
1102
|
+
/**
|
|
1103
|
+
* Encryption passphrase for the key file. Present on WalletInfo returned by
|
|
1104
|
+
* generateWallet()/importWallet(); intentionally absent from listWallets()
|
|
1105
|
+
* because the passphrase is never persisted in plaintext.
|
|
1106
|
+
*/
|
|
1107
|
+
readonly passphrase?: string;
|
|
1096
1108
|
}
|
|
1097
1109
|
interface SignedMessage {
|
|
1098
1110
|
readonly message: string;
|
|
@@ -1123,7 +1135,8 @@ declare class WalletManager {
|
|
|
1123
1135
|
|
|
1124
1136
|
/**
|
|
1125
1137
|
* Generate a new Ethereum-compatible wallet.
|
|
1126
|
-
* Private key is encrypted with
|
|
1138
|
+
* Private key is encrypted with config.passphrase or a generated high-entropy passphrase.
|
|
1139
|
+
* The returned WalletInfo includes the passphrase needed for later key-file signing.
|
|
1127
1140
|
*/
|
|
1128
1141
|
declare function generateWallet(config: WalletConfig): Promise<WalletInfo>;
|
|
1129
1142
|
/**
|
|
@@ -1132,8 +1145,7 @@ declare function generateWallet(config: WalletConfig): Promise<WalletInfo>;
|
|
|
1132
1145
|
declare function importWallet(privateKeyHex: string, config: WalletConfig): Promise<WalletInfo>;
|
|
1133
1146
|
/**
|
|
1134
1147
|
* Sign a message using an encrypted key file and passphrase (returns structured result).
|
|
1135
|
-
* Uses secp256k1 ECDSA over Keccak-256(UTF-8 message) when native/WASM tiers provide it
|
|
1136
|
-
* otherwise falls back to HMAC-SHA256 for backward compatibility.
|
|
1148
|
+
* Uses secp256k1 ECDSA over Keccak-256(UTF-8 message) when native/WASM tiers provide it.
|
|
1137
1149
|
*/
|
|
1138
1150
|
declare function signMessage(message: string, keyFile: string, passphrase: string): Promise<SignedMessage>;
|
|
1139
1151
|
/**
|
package/dist/index.js
CHANGED
|
@@ -448,7 +448,7 @@ import { z } from "zod";
|
|
|
448
448
|
// src/constants.ts
|
|
449
449
|
import { join } from "path";
|
|
450
450
|
import { homedir } from "os";
|
|
451
|
-
var VERSION = "2.2.
|
|
451
|
+
var VERSION = "2.2.7";
|
|
452
452
|
var PACKAGE_NAME = "clawpowers";
|
|
453
453
|
var CLAWPOWERS_HOME = join(homedir(), ".clawpowers");
|
|
454
454
|
var CONFIG_PATH = join(CLAWPOWERS_HOME, "config.json");
|
|
@@ -2287,12 +2287,60 @@ var RSIAuditLog = class {
|
|
|
2287
2287
|
|
|
2288
2288
|
// src/rsi/auto-research.ts
|
|
2289
2289
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
2290
|
-
import {
|
|
2291
|
-
import { mkdirSync as mkdirSync2, existsSync as existsSync8, writeFileSync as writeFileSync2 } from "fs";
|
|
2290
|
+
import { execFileSync } from "child_process";
|
|
2291
|
+
import { mkdirSync as mkdirSync2, existsSync as existsSync8, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
2292
2292
|
import { join as join4 } from "path";
|
|
2293
2293
|
import { tmpdir } from "os";
|
|
2294
2294
|
var MIN_CONFIDENCE = 0.3;
|
|
2295
2295
|
var REQUIRED_PASSING_RUNS = 3;
|
|
2296
|
+
function tokenizeWords(value) {
|
|
2297
|
+
const tokens = [];
|
|
2298
|
+
let current = "";
|
|
2299
|
+
for (const char of value.toLowerCase()) {
|
|
2300
|
+
const isAlphaNum = char >= "a" && char <= "z" || char >= "0" && char <= "9";
|
|
2301
|
+
if (isAlphaNum) {
|
|
2302
|
+
current += char;
|
|
2303
|
+
continue;
|
|
2304
|
+
}
|
|
2305
|
+
if (current.length > 3) {
|
|
2306
|
+
tokens.push(current);
|
|
2307
|
+
}
|
|
2308
|
+
current = "";
|
|
2309
|
+
}
|
|
2310
|
+
if (current.length > 3) {
|
|
2311
|
+
tokens.push(current);
|
|
2312
|
+
}
|
|
2313
|
+
return tokens;
|
|
2314
|
+
}
|
|
2315
|
+
function splitSearchTerms(value) {
|
|
2316
|
+
return value.split(" ").map((part) => part.trim()).filter((part) => part.length > 3);
|
|
2317
|
+
}
|
|
2318
|
+
function slugify(value) {
|
|
2319
|
+
let slug = "";
|
|
2320
|
+
let lastWasDash = false;
|
|
2321
|
+
for (const char of value.toLowerCase()) {
|
|
2322
|
+
const isAlphaNum = char >= "a" && char <= "z" || char >= "0" && char <= "9";
|
|
2323
|
+
if (isAlphaNum) {
|
|
2324
|
+
slug += char;
|
|
2325
|
+
lastWasDash = false;
|
|
2326
|
+
continue;
|
|
2327
|
+
}
|
|
2328
|
+
if (!lastWasDash && slug.length > 0) {
|
|
2329
|
+
slug += "-";
|
|
2330
|
+
lastWasDash = true;
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
if (slug.endsWith("-")) {
|
|
2334
|
+
slug = slug.slice(0, -1);
|
|
2335
|
+
}
|
|
2336
|
+
return slug.slice(0, 40);
|
|
2337
|
+
}
|
|
2338
|
+
function sanitizeShellComment(value, maxLength) {
|
|
2339
|
+
return value.replace(/[\r\n]+/g, " ").replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "").slice(0, maxLength);
|
|
2340
|
+
}
|
|
2341
|
+
function shellSingleQuote(value) {
|
|
2342
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
2343
|
+
}
|
|
2296
2344
|
function buildSearchQuery(failure) {
|
|
2297
2345
|
const clean = failure.error.replace(/\x1b\[[0-9;]*m/g, "");
|
|
2298
2346
|
const firstLine = clean.split("\n")[0]?.trim() ?? clean.trim();
|
|
@@ -2318,9 +2366,9 @@ function scoreConfidence(candidate, failure) {
|
|
|
2318
2366
|
break;
|
|
2319
2367
|
}
|
|
2320
2368
|
const failureWords = new Set(
|
|
2321
|
-
failure.taskDescription
|
|
2369
|
+
tokenizeWords(failure.taskDescription)
|
|
2322
2370
|
);
|
|
2323
|
-
const approachWords = candidate.approach
|
|
2371
|
+
const approachWords = tokenizeWords(candidate.approach);
|
|
2324
2372
|
const matches = approachWords.filter((w) => failureWords.has(w)).length;
|
|
2325
2373
|
const overlap = Math.min(matches / Math.max(failureWords.size, 1), 0.25);
|
|
2326
2374
|
base += overlap;
|
|
@@ -2367,7 +2415,7 @@ var AutoResearcher = class {
|
|
|
2367
2415
|
const testScript = this.buildTestScript(candidate, task, sandboxDir);
|
|
2368
2416
|
const scriptPath = join4(sandboxDir, "test.sh");
|
|
2369
2417
|
writeFileSync2(scriptPath, testScript, { mode: 493 });
|
|
2370
|
-
const output =
|
|
2418
|
+
const output = execFileSync("bash", ["./test.sh"], {
|
|
2371
2419
|
cwd: sandboxDir,
|
|
2372
2420
|
timeout: 3e4,
|
|
2373
2421
|
encoding: "utf-8",
|
|
@@ -2389,7 +2437,7 @@ var AutoResearcher = class {
|
|
|
2389
2437
|
};
|
|
2390
2438
|
} finally {
|
|
2391
2439
|
try {
|
|
2392
|
-
|
|
2440
|
+
rmSync(sandboxDir, { recursive: true, force: true });
|
|
2393
2441
|
} catch {
|
|
2394
2442
|
}
|
|
2395
2443
|
}
|
|
@@ -2445,8 +2493,8 @@ var AutoResearcher = class {
|
|
|
2445
2493
|
searchSkillCatalog(failure) {
|
|
2446
2494
|
try {
|
|
2447
2495
|
const { SKILLS_CATALOG: SKILLS_CATALOG2 } = (init_catalog(), __toCommonJS(catalog_exports));
|
|
2448
|
-
const errorTokens = failure.error
|
|
2449
|
-
const taskTokens = failure.taskDescription
|
|
2496
|
+
const errorTokens = tokenizeWords(failure.error);
|
|
2497
|
+
const taskTokens = tokenizeWords(failure.taskDescription);
|
|
2450
2498
|
const relevantTokens = /* @__PURE__ */ new Set([...errorTokens, ...taskTokens]);
|
|
2451
2499
|
return SKILLS_CATALOG2.filter((skill) => {
|
|
2452
2500
|
const haystack = `${skill.name} ${skill.description}`.toLowerCase();
|
|
@@ -2468,16 +2516,16 @@ var AutoResearcher = class {
|
|
|
2468
2516
|
}
|
|
2469
2517
|
async searchNpmRegistry(failure) {
|
|
2470
2518
|
const query = buildSearchQuery(failure);
|
|
2471
|
-
const keywords = query
|
|
2519
|
+
const keywords = splitSearchTerms(query).slice(0, 5);
|
|
2520
|
+
if (keywords.length === 0) {
|
|
2521
|
+
return [];
|
|
2522
|
+
}
|
|
2472
2523
|
try {
|
|
2473
|
-
const raw =
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
2479
|
-
}
|
|
2480
|
-
);
|
|
2524
|
+
const raw = execFileSync("npm", ["search", ...keywords, "--json", "--no-description"], {
|
|
2525
|
+
timeout: 15e3,
|
|
2526
|
+
encoding: "utf-8",
|
|
2527
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
2528
|
+
});
|
|
2481
2529
|
const results = JSON.parse(raw);
|
|
2482
2530
|
return results.slice(0, 3).map((pkg) => {
|
|
2483
2531
|
const base = {
|
|
@@ -2519,9 +2567,9 @@ var AutoResearcher = class {
|
|
|
2519
2567
|
"set -euo pipefail",
|
|
2520
2568
|
"",
|
|
2521
2569
|
"# AutoResearch sandbox test",
|
|
2522
|
-
`# Task: ${task.description
|
|
2570
|
+
`# Task: ${sanitizeShellComment(task.description, 200)}`,
|
|
2523
2571
|
`# Candidate source: ${candidate.source}`,
|
|
2524
|
-
`# Candidate: ${candidate.description
|
|
2572
|
+
`# Candidate: ${sanitizeShellComment(candidate.description, 200)}`,
|
|
2525
2573
|
""
|
|
2526
2574
|
];
|
|
2527
2575
|
if (candidate.source === "npm-registry") {
|
|
@@ -2548,7 +2596,7 @@ var AutoResearcher = class {
|
|
|
2548
2596
|
} else {
|
|
2549
2597
|
const q = buildSearchQuery({ error: candidate.description, taskDescription: task.description, executionSteps: [], skillsUsed: [], attemptCount: 1 });
|
|
2550
2598
|
if (q.trim().length > 0) {
|
|
2551
|
-
lines.push(`echo
|
|
2599
|
+
lines.push(`echo ${shellSingleQuote(`web-search candidate: query is ${q.slice(0, 100)}`)}`);
|
|
2552
2600
|
lines.push("exit 0");
|
|
2553
2601
|
} else {
|
|
2554
2602
|
lines.push('echo "web-search candidate: empty query" >&2');
|
|
@@ -2558,13 +2606,13 @@ var AutoResearcher = class {
|
|
|
2558
2606
|
lines.push("");
|
|
2559
2607
|
lines.push("# Success criteria check");
|
|
2560
2608
|
for (const criterion of task.successCriteria.slice(0, 2)) {
|
|
2561
|
-
lines.push(`echo
|
|
2609
|
+
lines.push(`echo ${shellSingleQuote(`Criterion: ${criterion.slice(0, 100)}`)}`);
|
|
2562
2610
|
}
|
|
2563
2611
|
lines.push('echo "Test passed"');
|
|
2564
2612
|
return lines.join("\n") + "\n";
|
|
2565
2613
|
}
|
|
2566
2614
|
deriveSkillName(candidate) {
|
|
2567
|
-
const slug = candidate.description
|
|
2615
|
+
const slug = slugify(candidate.description);
|
|
2568
2616
|
return `auto-${slug}`;
|
|
2569
2617
|
}
|
|
2570
2618
|
renderSkillMd(def) {
|
|
@@ -2616,12 +2664,66 @@ async function runAutoResearch(failure, task, skillsDir) {
|
|
|
2616
2664
|
// src/skills/loader.ts
|
|
2617
2665
|
import { readdirSync, readFileSync as readFileSync2, existsSync as existsSync9, statSync } from "fs";
|
|
2618
2666
|
import { join as join5 } from "path";
|
|
2667
|
+
function stripQuotes(value) {
|
|
2668
|
+
if (value.length >= 2) {
|
|
2669
|
+
const first = value[0];
|
|
2670
|
+
const last = value[value.length - 1];
|
|
2671
|
+
if (first === '"' && last === '"' || first === "'" && last === "'") {
|
|
2672
|
+
return value.slice(1, -1);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
return value;
|
|
2676
|
+
}
|
|
2677
|
+
function splitYamlKeyValue(line) {
|
|
2678
|
+
const colonIndex = line.indexOf(":");
|
|
2679
|
+
if (colonIndex <= 0) {
|
|
2680
|
+
return null;
|
|
2681
|
+
}
|
|
2682
|
+
const key = line.slice(0, colonIndex).trim();
|
|
2683
|
+
if (!key) {
|
|
2684
|
+
return null;
|
|
2685
|
+
}
|
|
2686
|
+
for (const char of key) {
|
|
2687
|
+
const isAlphaNum = char >= "a" && char <= "z" || char >= "A" && char <= "Z" || char >= "0" && char <= "9" || char === "_";
|
|
2688
|
+
if (!isAlphaNum) {
|
|
2689
|
+
return null;
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
return {
|
|
2693
|
+
key,
|
|
2694
|
+
value: line.slice(colonIndex + 1).trim()
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
function parseInlineArray(value) {
|
|
2698
|
+
if (!value.startsWith("[") || !value.endsWith("]")) {
|
|
2699
|
+
return null;
|
|
2700
|
+
}
|
|
2701
|
+
const inner = value.slice(1, -1).trim();
|
|
2702
|
+
if (!inner) {
|
|
2703
|
+
return [];
|
|
2704
|
+
}
|
|
2705
|
+
return inner.split(",").map((item) => stripQuotes(item.trim())).filter(Boolean);
|
|
2706
|
+
}
|
|
2707
|
+
function parseListItem(line) {
|
|
2708
|
+
if (!line.startsWith("-")) {
|
|
2709
|
+
return null;
|
|
2710
|
+
}
|
|
2711
|
+
const value = line.slice(1).trim();
|
|
2712
|
+
if (!value) {
|
|
2713
|
+
return null;
|
|
2714
|
+
}
|
|
2715
|
+
return stripQuotes(value);
|
|
2716
|
+
}
|
|
2619
2717
|
function parseFrontmatter(content) {
|
|
2620
|
-
const
|
|
2621
|
-
if (!
|
|
2718
|
+
const normalized = content.replace(/\r\n/g, "\n");
|
|
2719
|
+
if (!normalized.startsWith("---\n")) {
|
|
2720
|
+
return {};
|
|
2721
|
+
}
|
|
2722
|
+
const endIndex = normalized.indexOf("\n---", 4);
|
|
2723
|
+
if (endIndex === -1) {
|
|
2622
2724
|
return {};
|
|
2623
2725
|
}
|
|
2624
|
-
const yamlText =
|
|
2726
|
+
const yamlText = normalized.slice(4, endIndex);
|
|
2625
2727
|
const result = {};
|
|
2626
2728
|
const lines = yamlText.split("\n");
|
|
2627
2729
|
let currentKey = "";
|
|
@@ -2631,10 +2733,10 @@ function parseFrontmatter(content) {
|
|
|
2631
2733
|
for (const line of lines) {
|
|
2632
2734
|
const trimmed = line.trim();
|
|
2633
2735
|
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
2634
|
-
const topLevel = line
|
|
2635
|
-
if (topLevel
|
|
2636
|
-
currentKey = topLevel
|
|
2637
|
-
const val = topLevel
|
|
2736
|
+
const topLevel = line === trimmed ? splitYamlKeyValue(trimmed) : null;
|
|
2737
|
+
if (topLevel) {
|
|
2738
|
+
currentKey = topLevel.key;
|
|
2739
|
+
const val = stripQuotes(topLevel.value);
|
|
2638
2740
|
if (currentKey === "name" && val) result.name = val;
|
|
2639
2741
|
if (currentKey === "description" && val) result.description = val;
|
|
2640
2742
|
inRequires = false;
|
|
@@ -2646,31 +2748,30 @@ function parseFrontmatter(content) {
|
|
|
2646
2748
|
continue;
|
|
2647
2749
|
}
|
|
2648
2750
|
if (inRequires) {
|
|
2649
|
-
const reqKey = trimmed
|
|
2650
|
-
if (reqKey
|
|
2651
|
-
requiresKey = reqKey
|
|
2652
|
-
const
|
|
2653
|
-
if (
|
|
2654
|
-
const items = inlineArr[1].split(",").map((s) => s.trim().replace(/^["']|["']$/g, ""));
|
|
2751
|
+
const reqKey = splitYamlKeyValue(trimmed);
|
|
2752
|
+
if (reqKey) {
|
|
2753
|
+
requiresKey = reqKey.key;
|
|
2754
|
+
const items = parseInlineArray(reqKey.value);
|
|
2755
|
+
if (items) {
|
|
2655
2756
|
if (requiresKey === "bins") requires.bins = items;
|
|
2656
2757
|
if (requiresKey === "env") requires.env = items;
|
|
2657
2758
|
if (requiresKey === "config") requires.config = items;
|
|
2658
2759
|
}
|
|
2659
2760
|
continue;
|
|
2660
2761
|
}
|
|
2661
|
-
const listItem = trimmed
|
|
2662
|
-
if (listItem
|
|
2762
|
+
const listItem = parseListItem(trimmed);
|
|
2763
|
+
if (listItem && requiresKey) {
|
|
2663
2764
|
if (requiresKey === "bins") {
|
|
2664
2765
|
requires.bins = requires.bins ?? [];
|
|
2665
|
-
requires.bins.push(listItem
|
|
2766
|
+
requires.bins.push(listItem);
|
|
2666
2767
|
}
|
|
2667
2768
|
if (requiresKey === "env") {
|
|
2668
2769
|
requires.env = requires.env ?? [];
|
|
2669
|
-
requires.env.push(listItem
|
|
2770
|
+
requires.env.push(listItem);
|
|
2670
2771
|
}
|
|
2671
2772
|
if (requiresKey === "config") {
|
|
2672
2773
|
requires.config = requires.config ?? [];
|
|
2673
|
-
requires.config.push(listItem
|
|
2774
|
+
requires.config.push(listItem);
|
|
2674
2775
|
}
|
|
2675
2776
|
}
|
|
2676
2777
|
}
|
|
@@ -2791,6 +2892,7 @@ var SCRYPT_P = 1;
|
|
|
2791
2892
|
var KEY_LENGTH = 32;
|
|
2792
2893
|
var IV_LENGTH = 12;
|
|
2793
2894
|
var AUTH_TAG_LENGTH = 16;
|
|
2895
|
+
var GENERATED_PASSPHRASE_BYTES = 32;
|
|
2794
2896
|
function addressFromKeyMaterial(keyMaterial) {
|
|
2795
2897
|
const digestHex = digestForWalletAddress(keyMaterial);
|
|
2796
2898
|
const hash = Buffer.from(digestHex.replace(/^0x/, ""), "hex");
|
|
@@ -2803,6 +2905,13 @@ function deriveKey(passphrase, salt) {
|
|
|
2803
2905
|
p: SCRYPT_P
|
|
2804
2906
|
});
|
|
2805
2907
|
}
|
|
2908
|
+
function resolvePassphrase(config) {
|
|
2909
|
+
const passphrase = config.passphrase ?? randomBytes2(GENERATED_PASSPHRASE_BYTES).toString("hex");
|
|
2910
|
+
if (passphrase.length === 0) {
|
|
2911
|
+
throw new Error("Wallet passphrase must not be empty");
|
|
2912
|
+
}
|
|
2913
|
+
return passphrase;
|
|
2914
|
+
}
|
|
2806
2915
|
function encryptPrivateKey(privateKey, passphrase) {
|
|
2807
2916
|
const salt = randomBytes2(32);
|
|
2808
2917
|
const key = deriveKey(passphrase, salt);
|
|
@@ -2845,7 +2954,32 @@ async function ensureDir(dir) {
|
|
|
2845
2954
|
await mkdir7(dir, { recursive: true });
|
|
2846
2955
|
}
|
|
2847
2956
|
}
|
|
2957
|
+
async function writeEncryptedWallet(privateKey, address, config, createdAt, passphrase) {
|
|
2958
|
+
const encrypted = encryptPrivateKey(privateKey, passphrase);
|
|
2959
|
+
const keyFileData = {
|
|
2960
|
+
version: 1,
|
|
2961
|
+
address,
|
|
2962
|
+
chain: config.chain,
|
|
2963
|
+
createdAt,
|
|
2964
|
+
crypto: {
|
|
2965
|
+
cipher: "aes-256-gcm",
|
|
2966
|
+
ciphertext: encrypted.ciphertext,
|
|
2967
|
+
iv: encrypted.iv,
|
|
2968
|
+
authTag: encrypted.authTag,
|
|
2969
|
+
salt: encrypted.salt,
|
|
2970
|
+
scryptParams: { N: SCRYPT_N, r: SCRYPT_R, p: SCRYPT_P }
|
|
2971
|
+
}
|
|
2972
|
+
};
|
|
2973
|
+
await ensureDir(config.dataDir);
|
|
2974
|
+
const keyFileName = `${address.slice(2, 10)}-${Date.now()}.json`;
|
|
2975
|
+
const keyFilePath = join6(config.dataDir, keyFileName);
|
|
2976
|
+
await writeFile4(keyFilePath, JSON.stringify(keyFileData, null, 2) + "\n", "utf-8");
|
|
2977
|
+
return keyFilePath;
|
|
2978
|
+
}
|
|
2848
2979
|
async function signMessageFromKeyFile(message, keyFile, passphrase) {
|
|
2980
|
+
if (passphrase.length === 0) {
|
|
2981
|
+
throw new Error("Wallet passphrase must not be empty");
|
|
2982
|
+
}
|
|
2849
2983
|
const content = await readFile7(keyFile, "utf-8");
|
|
2850
2984
|
const keyFileData = JSON.parse(content);
|
|
2851
2985
|
const privateKey = decryptPrivateKey(
|
|
@@ -2866,14 +3000,9 @@ async function signMessageFromKeyFile(message, keyFile, passphrase) {
|
|
|
2866
3000
|
address: keyFileData.address
|
|
2867
3001
|
};
|
|
2868
3002
|
}
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
return {
|
|
2873
|
-
message,
|
|
2874
|
-
signature: "0x" + signature,
|
|
2875
|
-
address: keyFileData.address
|
|
2876
|
-
};
|
|
3003
|
+
throw new Error(
|
|
3004
|
+
`Ethereum signing requires Keccak-256 + secp256k1 (Tier 1 native or Tier 2 WASM). Current active tier is "${getActiveTier()}" which cannot produce a valid EVM signature. Install the native addon or enable the WASM tier before calling signMessage().`
|
|
3005
|
+
);
|
|
2877
3006
|
}
|
|
2878
3007
|
async function signMessageFromPrivateKey(privateKeyHex, message) {
|
|
2879
3008
|
const cleaned = privateKeyHex.replace(/^0x/i, "");
|
|
@@ -2898,31 +3027,14 @@ async function generateWallet(config) {
|
|
|
2898
3027
|
const privateKeyHex = privateKey.toString("hex");
|
|
2899
3028
|
const address = generateAddress(privateKeyHex);
|
|
2900
3029
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2901
|
-
const passphrase =
|
|
2902
|
-
const
|
|
2903
|
-
const keyFileData = {
|
|
2904
|
-
version: 1,
|
|
2905
|
-
address,
|
|
2906
|
-
chain: config.chain,
|
|
2907
|
-
createdAt,
|
|
2908
|
-
crypto: {
|
|
2909
|
-
cipher: "aes-256-gcm",
|
|
2910
|
-
ciphertext: encrypted.ciphertext,
|
|
2911
|
-
iv: encrypted.iv,
|
|
2912
|
-
authTag: encrypted.authTag,
|
|
2913
|
-
salt: encrypted.salt,
|
|
2914
|
-
scryptParams: { N: SCRYPT_N, r: SCRYPT_R, p: SCRYPT_P }
|
|
2915
|
-
}
|
|
2916
|
-
};
|
|
2917
|
-
await ensureDir(config.dataDir);
|
|
2918
|
-
const keyFileName = `${address.slice(2, 10)}-${Date.now()}.json`;
|
|
2919
|
-
const keyFilePath = join6(config.dataDir, keyFileName);
|
|
2920
|
-
await writeFile4(keyFilePath, JSON.stringify(keyFileData, null, 2) + "\n", "utf-8");
|
|
3030
|
+
const passphrase = resolvePassphrase(config);
|
|
3031
|
+
const keyFilePath = await writeEncryptedWallet(privateKey, address, config, createdAt, passphrase);
|
|
2921
3032
|
return {
|
|
2922
3033
|
address,
|
|
2923
3034
|
chain: config.chain,
|
|
2924
3035
|
createdAt,
|
|
2925
|
-
keyFile: keyFilePath
|
|
3036
|
+
keyFile: keyFilePath,
|
|
3037
|
+
passphrase
|
|
2926
3038
|
};
|
|
2927
3039
|
}
|
|
2928
3040
|
async function importWallet(privateKeyHex, config) {
|
|
@@ -2933,31 +3045,14 @@ async function importWallet(privateKeyHex, config) {
|
|
|
2933
3045
|
const privateKey = Buffer.from(cleaned, "hex");
|
|
2934
3046
|
const address = generateAddress(cleaned);
|
|
2935
3047
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2936
|
-
const passphrase =
|
|
2937
|
-
const
|
|
2938
|
-
const keyFileData = {
|
|
2939
|
-
version: 1,
|
|
2940
|
-
address,
|
|
2941
|
-
chain: config.chain,
|
|
2942
|
-
createdAt,
|
|
2943
|
-
crypto: {
|
|
2944
|
-
cipher: "aes-256-gcm",
|
|
2945
|
-
ciphertext: encrypted.ciphertext,
|
|
2946
|
-
iv: encrypted.iv,
|
|
2947
|
-
authTag: encrypted.authTag,
|
|
2948
|
-
salt: encrypted.salt,
|
|
2949
|
-
scryptParams: { N: SCRYPT_N, r: SCRYPT_R, p: SCRYPT_P }
|
|
2950
|
-
}
|
|
2951
|
-
};
|
|
2952
|
-
await ensureDir(config.dataDir);
|
|
2953
|
-
const keyFileName = `${address.slice(2, 10)}-${Date.now()}.json`;
|
|
2954
|
-
const keyFilePath = join6(config.dataDir, keyFileName);
|
|
2955
|
-
await writeFile4(keyFilePath, JSON.stringify(keyFileData, null, 2) + "\n", "utf-8");
|
|
3048
|
+
const passphrase = resolvePassphrase(config);
|
|
3049
|
+
const keyFilePath = await writeEncryptedWallet(privateKey, address, config, createdAt, passphrase);
|
|
2956
3050
|
return {
|
|
2957
3051
|
address,
|
|
2958
3052
|
chain: config.chain,
|
|
2959
3053
|
createdAt,
|
|
2960
|
-
keyFile: keyFilePath
|
|
3054
|
+
keyFile: keyFilePath,
|
|
3055
|
+
passphrase
|
|
2961
3056
|
};
|
|
2962
3057
|
}
|
|
2963
3058
|
async function signMessage(a, b, c) {
|