web3skill 0.1.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 (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +127 -0
  3. package/dist/archives/web3-audit-orchestrator.skill +0 -0
  4. package/dist/archives/web3-audit-reporting.skill +0 -0
  5. package/dist/archives/web3-fuzzing-and-invariants.skill +0 -0
  6. package/dist/archives/web3-native-operator.skill +0 -0
  7. package/dist/archives/web3-repo-heuristics.skill +0 -0
  8. package/dist/archives/web3-research-and-market-intel.skill +0 -0
  9. package/dist/archives/web3-risk-gate.skill +0 -0
  10. package/dist/archives/web3-service-orchestrator.skill +0 -0
  11. package/dist/archives/web3-static-analysis-runner.skill +0 -0
  12. package/dist/archives/web3-trace-and-state-analysis.skill +0 -0
  13. package/dist/archives/web3-transaction-simulator.skill +0 -0
  14. package/dist/archives/web3-wallet-operator.skill +0 -0
  15. package/dist/manifest.json +170 -0
  16. package/dist/skills/web3-audit-orchestrator/SKILL.md +79 -0
  17. package/dist/skills/web3-audit-orchestrator/references/ADAPTER_CONSUMPTION_MAP.md +15 -0
  18. package/dist/skills/web3-audit-orchestrator/references/OUTPUT_TEMPLATE.md +52 -0
  19. package/dist/skills/web3-audit-orchestrator/references/REVIEW_STATE_MACHINE.md +25 -0
  20. package/dist/skills/web3-audit-orchestrator/scripts/render_audit_review.py +95 -0
  21. package/dist/skills/web3-audit-reporting/SKILL.md +77 -0
  22. package/dist/skills/web3-audit-reporting/references/FINDING_TEMPLATE.md +54 -0
  23. package/dist/skills/web3-audit-reporting/references/REPORT_TEMPLATE.md +58 -0
  24. package/dist/skills/web3-audit-reporting/references/RETEST_TEMPLATE.md +35 -0
  25. package/dist/skills/web3-audit-reporting/references/SEVERITY_RUBRIC.md +75 -0
  26. package/dist/skills/web3-fuzzing-and-invariants/SKILL.md +68 -0
  27. package/dist/skills/web3-fuzzing-and-invariants/references/ADAPTER_CONSUMPTION_MAP.md +14 -0
  28. package/dist/skills/web3-fuzzing-and-invariants/references/OUTPUT_TEMPLATE.md +40 -0
  29. package/dist/skills/web3-fuzzing-and-invariants/references/READINESS_AND_FAILURES.md +25 -0
  30. package/dist/skills/web3-fuzzing-and-invariants/scripts/render_fuzz_summary.py +64 -0
  31. package/dist/skills/web3-native-operator/SKILL.md +218 -0
  32. package/dist/skills/web3-native-operator/references/EXECUTION_BUNDLE_TEMPLATE.md +47 -0
  33. package/dist/skills/web3-native-operator/references/OPERATOR_BUNDLE_TEMPLATE.md +39 -0
  34. package/dist/skills/web3-native-operator/references/POSTTRADE_FOLLOWUP_BUNDLE_TEMPLATE.md +35 -0
  35. package/dist/skills/web3-native-operator/references/POSTTRADE_WATCH_TEMPLATE.md +34 -0
  36. package/dist/skills/web3-native-operator/references/PRETRADE_PACKET_TEMPLATE.md +34 -0
  37. package/dist/skills/web3-native-operator/references/ROUTE_RECIPES.md +140 -0
  38. package/dist/skills/web3-native-operator/references/ROUTING_STATE_MACHINE.md +73 -0
  39. package/dist/skills/web3-native-operator/references/WATCH_CRON_REQUEST_TEMPLATE.md +26 -0
  40. package/dist/skills/web3-native-operator/references/WATCH_FOLLOWUP_BUNDLE_TEMPLATE.md +35 -0
  41. package/dist/skills/web3-native-operator/references/WATCH_HEARTBEAT_TEMPLATE.md +31 -0
  42. package/dist/skills/web3-native-operator/scripts/apply_followup_bundle_to_heartbeat.py +118 -0
  43. package/dist/skills/web3-native-operator/scripts/render_execution_bundle.py +259 -0
  44. package/dist/skills/web3-native-operator/scripts/render_operator_bundle.py +800 -0
  45. package/dist/skills/web3-native-operator/scripts/render_posttrade_followup_bundle.py +118 -0
  46. package/dist/skills/web3-native-operator/scripts/render_posttrade_watch_status.py +125 -0
  47. package/dist/skills/web3-native-operator/scripts/render_pretrade_packet.py +205 -0
  48. package/dist/skills/web3-native-operator/scripts/render_watch_cron_request.py +88 -0
  49. package/dist/skills/web3-native-operator/scripts/render_watch_followup_bundle.py +118 -0
  50. package/dist/skills/web3-native-operator/scripts/render_watch_heartbeat.py +52 -0
  51. package/dist/skills/web3-repo-heuristics/SKILL.md +37 -0
  52. package/dist/skills/web3-repo-heuristics/references/FOUNDRY.md +49 -0
  53. package/dist/skills/web3-repo-heuristics/references/HARDHAT.md +47 -0
  54. package/dist/skills/web3-repo-heuristics/references/VYPER.md +26 -0
  55. package/dist/skills/web3-research-and-market-intel/SKILL.md +138 -0
  56. package/dist/skills/web3-research-and-market-intel/references/ADAPTER_CONSUMPTION_MAP.md +66 -0
  57. package/dist/skills/web3-research-and-market-intel/references/EVIDENCE_QUALITY.md +27 -0
  58. package/dist/skills/web3-research-and-market-intel/references/OUTPUT_TEMPLATE.md +37 -0
  59. package/dist/skills/web3-research-and-market-intel/references/PORTFOLIO_STATUS_TEMPLATE.md +51 -0
  60. package/dist/skills/web3-research-and-market-intel/references/WATCH_STATUS_TEMPLATE.md +39 -0
  61. package/dist/skills/web3-research-and-market-intel/scripts/render_portfolio_status.py +85 -0
  62. package/dist/skills/web3-research-and-market-intel/scripts/render_research_brief.py +58 -0
  63. package/dist/skills/web3-research-and-market-intel/scripts/render_watch_status.py +70 -0
  64. package/dist/skills/web3-risk-gate/SKILL.md +100 -0
  65. package/dist/skills/web3-risk-gate/references/OUTPUT_TEMPLATE.md +72 -0
  66. package/dist/skills/web3-risk-gate/references/SIGNAL_TAXONOMY.md +34 -0
  67. package/dist/skills/web3-risk-gate/scripts/merge_risk_gate_blocks.py +189 -0
  68. package/dist/skills/web3-service-orchestrator/SKILL.md +34 -0
  69. package/dist/skills/web3-static-analysis-runner/SKILL.md +76 -0
  70. package/dist/skills/web3-static-analysis-runner/references/ADAPTER_CONSUMPTION_MAP.md +13 -0
  71. package/dist/skills/web3-static-analysis-runner/references/OUTPUT_TEMPLATE.md +45 -0
  72. package/dist/skills/web3-static-analysis-runner/references/TRIAGE_BUCKETS.md +16 -0
  73. package/dist/skills/web3-static-analysis-runner/scripts/render_static_analysis_summary.py +64 -0
  74. package/dist/skills/web3-trace-and-state-analysis/SKILL.md +74 -0
  75. package/dist/skills/web3-trace-and-state-analysis/references/ADAPTER_CONSUMPTION_MAP.md +27 -0
  76. package/dist/skills/web3-trace-and-state-analysis/references/OUTPUT_TEMPLATE.md +63 -0
  77. package/dist/skills/web3-trace-and-state-analysis/references/TRACE_BACKEND_PREFLIGHT.md +47 -0
  78. package/dist/skills/web3-trace-and-state-analysis/scripts/render_trace_summary.py +99 -0
  79. package/dist/skills/web3-transaction-simulator/SKILL.md +83 -0
  80. package/dist/skills/web3-transaction-simulator/references/OUTPUT_TEMPLATE.md +86 -0
  81. package/dist/skills/web3-transaction-simulator/references/STATUS_AND_FAILURES.md +49 -0
  82. package/dist/skills/web3-transaction-simulator/scripts/merge_simulation_blocks.py +198 -0
  83. package/dist/skills/web3-wallet-operator/SKILL.md +52 -0
  84. package/dist/skills/web3-wallet-operator/references/ACTION_RECIPES.md +56 -0
  85. package/dist/skills/web3-wallet-operator/references/OUTPUT_TEMPLATE.md +43 -0
  86. package/dist/skills/web3-wallet-operator/scripts/render_wallet_operation_plan.py +101 -0
  87. package/index.js +50 -0
  88. package/package.json +36 -0
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env python3
2
+ """Merge multiple normalized simulation blocks into one conservative result."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ from pathlib import Path
9
+ import sys
10
+
11
+
12
+ READINESS_ORDER = {
13
+ "ready": 0,
14
+ "needs-confirmation": 1,
15
+ "blocked": 2,
16
+ }
17
+
18
+
19
+ def build_parser() -> argparse.ArgumentParser:
20
+ parser = argparse.ArgumentParser(description="Merge multiple simulation payloads into one block.")
21
+ parser.add_argument(
22
+ "--input-file",
23
+ action="append",
24
+ required=True,
25
+ help="Path to a JSON file containing a simulation payload or '-' for stdin",
26
+ )
27
+ return parser
28
+
29
+
30
+ def load_payload(path: str) -> dict[str, object]:
31
+ if path == "-":
32
+ return json.load(sys.stdin)
33
+ return json.loads(Path(path).read_text(encoding="utf-8"))
34
+
35
+
36
+ def extract_simulation(payload: dict[str, object]) -> dict[str, object]:
37
+ simulation = payload.get("simulation")
38
+ if isinstance(simulation, dict):
39
+ return simulation
40
+ if {"status", "action", "venue", "readiness"}.issubset(payload):
41
+ return payload
42
+ raise ValueError("input payload does not contain simulation")
43
+
44
+
45
+ def merge_scalar(current: str, new_value: str, field_name: str) -> str:
46
+ if not new_value:
47
+ return current
48
+ if not current:
49
+ return new_value
50
+ if current != new_value:
51
+ raise ValueError(f"conflicting {field_name}: {current} vs {new_value}")
52
+ return current
53
+
54
+
55
+ def merge_mapping(current: dict[str, object], new_value: dict[str, object], field_name: str) -> dict[str, object]:
56
+ merged = dict(current)
57
+ for key, value in new_value.items():
58
+ if key in merged and merged[key] != value:
59
+ raise ValueError(f"conflicting {field_name}.{key}: {merged[key]} vs {value}")
60
+ merged[key] = value
61
+ return merged
62
+
63
+
64
+ def dedupe_items(items: list[dict[str, object]]) -> list[dict[str, object]]:
65
+ seen: set[str] = set()
66
+ deduped: list[dict[str, object]] = []
67
+ for item in items:
68
+ key = json.dumps(item, sort_keys=True, ensure_ascii=False)
69
+ if key in seen:
70
+ continue
71
+ seen.add(key)
72
+ deduped.append(item)
73
+ return deduped
74
+
75
+
76
+ def dedupe_strings(items: list[str]) -> list[str]:
77
+ seen: set[str] = set()
78
+ deduped: list[str] = []
79
+ for item in items:
80
+ if item in seen:
81
+ continue
82
+ seen.add(item)
83
+ deduped.append(item)
84
+ return deduped
85
+
86
+
87
+ def choose_status(statuses: list[str]) -> str:
88
+ if any(status == "FAIL" for status in statuses):
89
+ return "FAIL"
90
+ if any(status == "WARN" for status in statuses):
91
+ return "WARN"
92
+ if any(status == "NO_SIMULATION" for status in statuses):
93
+ return "WARN" if any(status == "PASS" for status in statuses) else "NO_SIMULATION"
94
+ return "PASS"
95
+
96
+
97
+ def choose_readiness(readiness_values: list[str]) -> str:
98
+ if not readiness_values:
99
+ return "needs-confirmation"
100
+ return max(readiness_values, key=lambda item: READINESS_ORDER[item])
101
+
102
+
103
+ def default_next_steps(status: str, readiness: str) -> list[str]:
104
+ if status == "FAIL" or readiness == "blocked":
105
+ return ["stop", "adjust params or route before retrying"]
106
+ if status == "NO_SIMULATION":
107
+ return ["gather missing simulation backend", "investigate route before execution"]
108
+ if status == "WARN" or readiness == "needs-confirmation":
109
+ return ["adjust params", "rerun simulation"]
110
+ return ["proceed after confirmation"]
111
+
112
+
113
+ def merge_payloads(payloads: list[dict[str, object]]) -> dict[str, object]:
114
+ action = ""
115
+ venue = ""
116
+ chain = ""
117
+ route: dict[str, object] = {}
118
+ expected_result: dict[str, object] = {}
119
+ preconditions: list[dict[str, object]] = []
120
+ failure_modes: list[dict[str, object]] = []
121
+ evidence: list[dict[str, object]] = []
122
+ next_steps: list[str] = []
123
+ statuses: list[str] = []
124
+ readiness_values: list[str] = []
125
+
126
+ for payload in payloads:
127
+ simulation = extract_simulation(payload)
128
+ action = merge_scalar(action, str(simulation.get("action", "")), "action")
129
+ venue = merge_scalar(venue, str(simulation.get("venue", "")), "venue")
130
+ chain = merge_scalar(chain, str(simulation.get("chain", "")), "chain")
131
+
132
+ status = str(simulation.get("status", "NO_SIMULATION"))
133
+ readiness = str(simulation.get("readiness", "needs-confirmation"))
134
+ if readiness not in READINESS_ORDER:
135
+ raise ValueError(f"unsupported readiness value: {readiness}")
136
+ statuses.append(status)
137
+ readiness_values.append(readiness)
138
+
139
+ route_value = simulation.get("route", {})
140
+ if isinstance(route_value, dict):
141
+ route = merge_mapping(route, route_value, "route")
142
+ expected_result_value = simulation.get("expected_result", {})
143
+ if isinstance(expected_result_value, dict):
144
+ expected_result = merge_mapping(expected_result, expected_result_value, "expected_result")
145
+
146
+ preconditions_value = simulation.get("preconditions", [])
147
+ if isinstance(preconditions_value, list):
148
+ preconditions.extend(item for item in preconditions_value if isinstance(item, dict))
149
+ failure_modes_value = simulation.get("failure_modes", [])
150
+ if isinstance(failure_modes_value, list):
151
+ failure_modes.extend(item for item in failure_modes_value if isinstance(item, dict))
152
+ evidence_value = simulation.get("evidence", [])
153
+ if isinstance(evidence_value, list):
154
+ evidence.extend(item for item in evidence_value if isinstance(item, dict))
155
+ next_step_value = simulation.get("next_step", [])
156
+ if isinstance(next_step_value, list):
157
+ next_steps.extend(str(item) for item in next_step_value if isinstance(item, str))
158
+
159
+ status = choose_status(statuses)
160
+ readiness = choose_readiness(readiness_values)
161
+ preconditions = dedupe_items(preconditions)
162
+ failure_modes = dedupe_items(failure_modes)
163
+ evidence = dedupe_items(evidence)
164
+ next_steps = dedupe_strings(next_steps) or default_next_steps(status, readiness)
165
+
166
+ payload: dict[str, object] = {
167
+ "simulation": {
168
+ "version": 1,
169
+ "status": status,
170
+ "action": action,
171
+ "venue": venue,
172
+ "chain": chain,
173
+ "readiness": readiness,
174
+ "route": route,
175
+ "next_step": next_steps,
176
+ "evidence": evidence,
177
+ }
178
+ }
179
+ if preconditions:
180
+ payload["simulation"]["preconditions"] = preconditions
181
+ if expected_result:
182
+ payload["simulation"]["expected_result"] = expected_result
183
+ if failure_modes:
184
+ payload["simulation"]["failure_modes"] = failure_modes
185
+ return payload
186
+
187
+
188
+ def main() -> int:
189
+ args = build_parser().parse_args()
190
+ payloads = [load_payload(path) for path in args.input_file]
191
+ merged = merge_payloads(payloads)
192
+ json.dump(merged, sys.stdout, ensure_ascii=False, indent=2)
193
+ sys.stdout.write("\n")
194
+ return 0
195
+
196
+
197
+ if __name__ == "__main__":
198
+ raise SystemExit(main())
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: web3-wallet-operator
3
+ description: Wallet-first routing layer for bot-driven Web3 wallet use. Use when the user wants to inspect a wallet, transfer tokens, approve or revoke allowances, prepare a swap, or run MetaMask delegation flows through the bot. It classifies wallet intent first, then routes to the operator, risk gate, simulator, portfolio adapters, or MetaMask wallet tooling.
4
+ always: true
5
+ ---
6
+
7
+ # Web3 Wallet Operator
8
+
9
+ Use this skill when the user's frame is "use my wallet" rather than "analyze this protocol".
10
+
11
+ ## Wallet-First Contract
12
+
13
+ - Never ask for seed phrases, mnemonics, raw private keys, exported keystores, or screenshots of wallet secrets.
14
+ - Prefer existing wallet connections, exchange credentials, or wallet-native signing flows.
15
+ - Any chain write still needs explicit user confirmation.
16
+ - Treat MetaMask as one optional wallet entrance, not the default control plane.
17
+
18
+ ## Intent Classes
19
+
20
+ - `portfolio`: inspect balances, positions, exposure, counterparties, or wallet activity
21
+ - `transfer`: send native token or ERC-20 token to a receiver
22
+ - `approve`: grant allowance or permission to a spender/router
23
+ - `revoke`: clear or reduce an existing allowance or delegation
24
+ - `swap`: buy, sell, or route a token through a DEX
25
+ - `delegation`: MetaMask wallet-side EIP-7702 or ERC-7710 flow
26
+
27
+ ## Routing Contract
28
+
29
+ 1. Classify wallet intent before reading downstream skills.
30
+ 2. Read [references/ACTION_RECIPES.md](references/ACTION_RECIPES.md) for the route map.
31
+ 3. If the runtime needs a stable machine-consumable handoff, emit `wallet_operation_plan` with [scripts/render_wallet_operation_plan.py](scripts/render_wallet_operation_plan.py) and follow [references/OUTPUT_TEMPLATE.md](references/OUTPUT_TEMPLATE.md).
32
+ 4. Route by intent:
33
+ - `portfolio` -> `web3-research-and-market-intel`, then `debank` or `query-address-info`
34
+ - `transfer`, `approve`, `revoke`, `swap` -> `web3-native-operator`
35
+ - `delegation` -> `metamask-gator-cli`
36
+ 5. Do not prefer `metamask-smart-accounts-kit` unless the task changes into app-side wallet integration or SDK development.
37
+
38
+ ## Minimum Inputs
39
+
40
+ - active wallet or account scope
41
+ - chain
42
+ - asset/token
43
+ - amount and units
44
+ - receiver, spender, router, or delegation target
45
+ - whether the user wants read-only planning or confirmed execution
46
+
47
+ ## Guardrails
48
+
49
+ - For `transfer`, `approve`, `revoke`, and `swap`, the downstream flow still must pass `web3-risk-gate` and `web3-transaction-simulator` before execution.
50
+ - If wallet context is missing, stop and ask for the minimum safe parameters instead of guessing.
51
+ - If the operation is MetaMask-specific and wallet-side, keep the flow in `metamask-gator-cli`.
52
+ - If the request is really portfolio intelligence instead of execution, prefer wallet state adapters over venue execution tools.
@@ -0,0 +1,56 @@
1
+ # Web3 Wallet Operator Recipes
2
+
3
+ Use these recipes when the user starts from a wallet intent.
4
+
5
+ ## Portfolio Review
6
+
7
+ 1. Normalize the request as `portfolio`.
8
+ 2. Route to `web3-research-and-market-intel`.
9
+ 3. Prefer:
10
+ - `debank` for wallet-level portfolio and protocol positions
11
+ - `query-address-info` for chain-scoped address holdings
12
+ 4. Emit a stable `portfolio_status` block before monitoring or follow-up.
13
+
14
+ ## Transfer
15
+
16
+ 1. Normalize the request as `transfer`.
17
+ 2. Route to `web3-native-operator`.
18
+ 3. Downstream checks must include:
19
+ - `web3-risk-gate`
20
+ - `web3-transaction-simulator`
21
+ 4. Treat receiver screening, blacklist risk, gas sufficiency, and token transfer behavior as mandatory checks before execution.
22
+
23
+ ## Approve Or Revoke
24
+
25
+ 1. Normalize the request as `approve` or `revoke`.
26
+ 2. Route to `web3-native-operator`.
27
+ 3. Downstream checks must include:
28
+ - `web3-risk-gate`
29
+ - `web3-transaction-simulator`
30
+ 4. Highlight spender identity, allowance scope, expiry, and whether a safer exact-amount approval exists.
31
+
32
+ ## Swap
33
+
34
+ 1. Normalize the request as `swap`.
35
+ 2. Route to `web3-native-operator`.
36
+ 3. Downstream flow should use:
37
+ - `web3-risk-gate`
38
+ - `web3-transaction-simulator`
39
+ - `swap-planner`, `token-swap`, or other venue adapters only after the gate and simulation are acceptable
40
+ 4. If token safety is unclear, keep the flow in pretrade investigation instead of implying execution readiness.
41
+
42
+ ## MetaMask Delegation
43
+
44
+ 1. Normalize the request as `delegation`.
45
+ 2. Route to `metamask-gator-cli`.
46
+ 3. Require wallet-side context:
47
+ - target profile
48
+ - chain / RPC
49
+ - delegation scope or redeem action
50
+ 4. Do not route to `metamask-smart-accounts-kit` unless the task turns into app-side integration work.
51
+
52
+ ## Global Guardrails
53
+
54
+ - Never request seed phrases or private keys.
55
+ - Never skip confirmation on chain writes.
56
+ - Never imply wallet safety if risk gating or simulation is unavailable.
@@ -0,0 +1,43 @@
1
+ # Wallet Operation Plan Template
2
+
3
+ Use this stable payload when the runtime needs a deterministic wallet-intent handoff.
4
+
5
+ ```json
6
+ {
7
+ "wallet_operation_plan": {
8
+ "version": 1,
9
+ "intent": "transfer",
10
+ "wallet_entry": "generic",
11
+ "account_scope": "active-wallet",
12
+ "execution_class": "write",
13
+ "mode": "confirm_then_execute",
14
+ "chain": "base",
15
+ "asset": "USDC",
16
+ "amount": "50",
17
+ "target": "0xreceiver",
18
+ "next_skill": "web3-native-operator",
19
+ "downstream_checks": [
20
+ "web3-risk-gate",
21
+ "web3-transaction-simulator"
22
+ ],
23
+ "recommended_adapters": [
24
+ "gas-tracker"
25
+ ],
26
+ "requires_user_confirmation": true,
27
+ "notes": [
28
+ "screen receiver before write",
29
+ "verify wallet balance covers value and gas"
30
+ ]
31
+ }
32
+ }
33
+ ```
34
+
35
+ ## Field Notes
36
+
37
+ - `intent`: `portfolio | transfer | approve | revoke | swap | delegation`
38
+ - `wallet_entry`: `generic | metamask-gator-cli | venue`
39
+ - `execution_class`: `read | write`
40
+ - `mode`: `read-only | confirm_then_execute`
41
+ - `next_skill`: immediate next routing target
42
+ - `downstream_checks`: builtin control skills that still must run
43
+ - `recommended_adapters`: profile adapters or wallet tools likely to be used next
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env python3
2
+ """Render a stable wallet-operation routing payload."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import sys
9
+
10
+
11
+ INTENTS = ("portfolio", "transfer", "approve", "revoke", "swap", "delegation")
12
+
13
+
14
+ def build_parser() -> argparse.ArgumentParser:
15
+ parser = argparse.ArgumentParser(description="Render a wallet_operation_plan payload.")
16
+ parser.add_argument("--intent", choices=INTENTS, required=True)
17
+ parser.add_argument("--wallet-entry", choices=("generic", "metamask-gator-cli", "venue"), default="generic")
18
+ parser.add_argument("--account-scope", default="active-wallet")
19
+ parser.add_argument("--chain", default="")
20
+ parser.add_argument("--asset", default="")
21
+ parser.add_argument("--amount", default="")
22
+ parser.add_argument("--target", default="")
23
+ parser.add_argument("--mode", choices=("read-only", "confirm_then_execute"), default="read-only")
24
+ return parser
25
+
26
+
27
+ def route_for_intent(intent: str) -> tuple[str, str, list[str], list[str], list[str], bool]:
28
+ if intent == "portfolio":
29
+ return (
30
+ "read",
31
+ "web3-research-and-market-intel",
32
+ [],
33
+ ["debank", "query-address-info"],
34
+ ["normalize wallet state before monitoring"],
35
+ False,
36
+ )
37
+ if intent == "delegation":
38
+ return (
39
+ "write",
40
+ "metamask-gator-cli",
41
+ [],
42
+ ["metamask-gator-cli"],
43
+ ["use MetaMask wallet-side tooling instead of app-side SDK guidance"],
44
+ True,
45
+ )
46
+
47
+ notes = [
48
+ "route through the Web3 control plane before any wallet write",
49
+ "risk and simulation must pass before execution",
50
+ ]
51
+ adapters = ["gas-tracker"]
52
+ if intent == "swap":
53
+ adapters.extend(["swap-planner", "token-swap"])
54
+ notes.append("prefer swap-specific adapters only after safety checks are acceptable")
55
+ if intent in {"approve", "revoke"}:
56
+ notes.append("review spender scope and allowance delta explicitly")
57
+ if intent == "transfer":
58
+ notes.append("screen receiver and confirm wallet balance plus gas coverage")
59
+
60
+ return (
61
+ "write",
62
+ "web3-native-operator",
63
+ ["web3-risk-gate", "web3-transaction-simulator"],
64
+ adapters,
65
+ notes,
66
+ True,
67
+ )
68
+
69
+
70
+ def main() -> int:
71
+ args = build_parser().parse_args()
72
+ execution_class, next_skill, downstream_checks, adapters, notes, requires_confirmation = route_for_intent(
73
+ args.intent
74
+ )
75
+
76
+ payload = {
77
+ "wallet_operation_plan": {
78
+ "version": 1,
79
+ "intent": args.intent,
80
+ "wallet_entry": args.wallet_entry,
81
+ "account_scope": args.account_scope,
82
+ "execution_class": execution_class,
83
+ "mode": args.mode,
84
+ "chain": args.chain,
85
+ "asset": args.asset,
86
+ "amount": args.amount,
87
+ "target": args.target,
88
+ "next_skill": next_skill,
89
+ "downstream_checks": downstream_checks,
90
+ "recommended_adapters": adapters,
91
+ "requires_user_confirmation": requires_confirmation,
92
+ "notes": notes,
93
+ }
94
+ }
95
+ json.dump(payload, sys.stdout, ensure_ascii=False, indent=2)
96
+ sys.stdout.write("\n")
97
+ return 0
98
+
99
+
100
+ if __name__ == "__main__":
101
+ raise SystemExit(main())
package/index.js ADDED
@@ -0,0 +1,50 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const packageRoot = dirname(fileURLToPath(import.meta.url));
6
+ const manifestPath = join(packageRoot, "dist", "manifest.json");
7
+
8
+ let manifestCache;
9
+
10
+ function clone(value) {
11
+ return JSON.parse(JSON.stringify(value));
12
+ }
13
+
14
+ function loadManifest() {
15
+ if (!manifestCache) {
16
+ manifestCache = JSON.parse(readFileSync(manifestPath, "utf8"));
17
+ }
18
+ return manifestCache;
19
+ }
20
+
21
+ function getSkill(skillName) {
22
+ const skill = loadManifest().skills.find((entry) => entry.name === skillName);
23
+ if (!skill) {
24
+ throw new Error(`Unknown skill: ${skillName}`);
25
+ }
26
+ return skill;
27
+ }
28
+
29
+ export function getManifest() {
30
+ return clone(loadManifest());
31
+ }
32
+
33
+ export function listSkills() {
34
+ return loadManifest().skills.map((skill) => skill.name);
35
+ }
36
+
37
+ export function getSkillDir(skillName) {
38
+ return join(packageRoot, getSkill(skillName).paths.directory);
39
+ }
40
+
41
+ export function getSkillArchive(skillName) {
42
+ return join(packageRoot, getSkill(skillName).paths.archive);
43
+ }
44
+
45
+ export default {
46
+ getManifest,
47
+ listSkills,
48
+ getSkillDir,
49
+ getSkillArchive
50
+ };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "web3skill",
3
+ "version": "0.1.0",
4
+ "description": "Bundled Web3 nanobot skills with raw folders, metadata manifest, and packaged .skill archives.",
5
+ "type": "module",
6
+ "main": "./index.js",
7
+ "exports": {
8
+ ".": "./index.js",
9
+ "./manifest.json": "./dist/manifest.json"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "index.js",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "scripts": {
18
+ "build": "node ./scripts/build.mjs",
19
+ "prepack": "npm run build",
20
+ "pack:check": "npm pack --dry-run"
21
+ },
22
+ "keywords": [
23
+ "agent",
24
+ "ai",
25
+ "nanobot",
26
+ "skill",
27
+ "web3"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "license": "MIT",
33
+ "engines": {
34
+ "node": ">=20.0.0"
35
+ }
36
+ }