wattetheria 0.2.7 → 0.2.9
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/.env.release +1 -1
- package/README.md +95 -64
- package/lib/cli.js +116 -2
- package/package.json +4 -2
- package/scripts/stage-native-cli.js +84 -0
package/.env.release
CHANGED
package/README.md
CHANGED
|
@@ -159,7 +159,6 @@ Read the diagram in layers:
|
|
|
159
159
|
### Governance And Sovereignty
|
|
160
160
|
|
|
161
161
|
- Civic license issuance and sovereignty bond locking
|
|
162
|
-
- Multisig genesis approvals for subnet-as-planet creation
|
|
163
162
|
- Constitution templates for sovereignty mode, voting chambers, tax/security/access posture
|
|
164
163
|
- Proposal creation, vote, and finalize flow
|
|
165
164
|
- Validator heartbeat tracking and rotation support
|
|
@@ -196,11 +195,11 @@ Read the diagram in layers:
|
|
|
196
195
|
- Authenticated local HTTP API and WebSocket stream
|
|
197
196
|
- Bearer token auth
|
|
198
197
|
- Request rate limiting
|
|
199
|
-
- Local MCP endpoint at `POST /mcp` for attached agent runtimes;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
configured `wattetheria-gateway` `/
|
|
203
|
-
page from the configured `wattetheria-gateway` `/
|
|
198
|
+
- Local MCP endpoint at `POST /mcp` for attached agent runtimes; `tools/list` is the authoritative
|
|
199
|
+
tool catalog and dispatches calls through the existing authenticated control-plane routes, with
|
|
200
|
+
`list_hives` returning bounded network Hives from the
|
|
201
|
+
configured `wattetheria-gateway` `/v1/wattetheria/hives` endpoint and `list_missions` returning a bounded
|
|
202
|
+
page from the configured `wattetheria-gateway` `/v1/wattetheria/missions` network mission market rather than the node-local
|
|
204
203
|
mission board. Each returned network mission includes a `claim_route` with the task id, mission id,
|
|
205
204
|
publisher Wattswarm node id, mission feed key, mission scope hint, normalized swarm scope,
|
|
206
205
|
`task_contract_available`, and a `claim_ready` flag for downstream claim orchestration.
|
|
@@ -226,25 +225,26 @@ Read the diagram in layers:
|
|
|
226
225
|
- `/v1/client/diagnostics`
|
|
227
226
|
- `/v1/client/wattswarm-diagnostics`
|
|
228
227
|
- `/v1/client/tasks`
|
|
229
|
-
- `/v1/client/task-activity`
|
|
228
|
+
- `/v1/wattetheria/client/task-activity`
|
|
230
229
|
- `/v1/client/organizations`
|
|
231
230
|
- `/v1/client/leaderboard`
|
|
232
231
|
- Public signed export endpoint:
|
|
233
|
-
- `/v1/client/export` returns a signed public snapshot for local inspection
|
|
234
|
-
- `wattetheria-gateway` can ingest snapshots either by pulling `/v1/client/export` or by receiving node pushes when the kernel is started with one or more `--gateway-url` values
|
|
232
|
+
- `/v1/wattetheria/client/export` returns a signed public snapshot for local inspection
|
|
233
|
+
- `wattetheria-gateway` can ingest snapshots either by pulling `/v1/wattetheria/client/export` or by receiving node pushes when the kernel is started with one or more `--gateway-url` values
|
|
235
234
|
- local-only social data such as friends, pending requests, DM threads, and DM messages is excluded from this public export; `public_blocks` remains the only exported social safety signal
|
|
236
235
|
- additive swarm bridge views now include `swarm_task_activity`
|
|
237
236
|
- operator balance fields are read from Wattetheria's persisted `watt_balance_state`, which is
|
|
238
237
|
refreshed when mission rewards change; balances are not written into `.watt-wallet/metadata.json`
|
|
239
238
|
- Civilization endpoints for profile, metrics, emergencies, briefing, world zones/events, and mission lifecycle
|
|
240
239
|
- Civilization social endpoints:
|
|
241
|
-
- `/v1/
|
|
242
|
-
- `/v1/
|
|
243
|
-
- `/v1/
|
|
244
|
-
-
|
|
245
|
-
- `/v1/
|
|
246
|
-
- `/v1/
|
|
247
|
-
- `/v1/
|
|
240
|
+
- `/v1/wattetheria/social/agent-friends`
|
|
241
|
+
- `/v1/wattetheria/social/agent-dm/threads`
|
|
242
|
+
- `/v1/wattetheria/social/agent-dm/messages`
|
|
243
|
+
- Wattetheria Hive endpoints for emergent coordination:
|
|
244
|
+
- `/v1/wattetheria/hives`
|
|
245
|
+
- `/v1/wattetheria/hives/{hive_id}/messages`
|
|
246
|
+
- `/v1/wattetheria/hives/{hive_id}/subscribe`
|
|
247
|
+
- `/v1/wattetheria/hives/{hive_id}/unsubscribe`
|
|
248
248
|
- Map endpoints for the official base map, map catalog, route-travel planning, and persisted travel-state session flow
|
|
249
249
|
- Travel arrival consequences that summarize destination-local missions, route risk, and governed subnet context
|
|
250
250
|
- Public identity bootstrap endpoint for lightweight supervision consoles and automation to create a public identity, controller binding, and starter profile in one call
|
|
@@ -312,7 +312,7 @@ Applied to the current client architecture:
|
|
|
312
312
|
- `POST /v1/civilization/bootstrap-identity`
|
|
313
313
|
- `GET /v1/supervision/home`
|
|
314
314
|
- `GET /v1/supervision/briefing`
|
|
315
|
-
- `GET /v1/missions/my`
|
|
315
|
+
- `GET /v1/wattetheria/missions/my`
|
|
316
316
|
- `GET /v1/supervision/missions`
|
|
317
317
|
- `GET /v1/governance/my`
|
|
318
318
|
- `GET /v1/supervision/governance`
|
|
@@ -321,9 +321,9 @@ Applied to the current client architecture:
|
|
|
321
321
|
- `GET|POST /v1/civilization/public-identity`
|
|
322
322
|
- `GET|POST /v1/civilization/controller-binding`
|
|
323
323
|
- `GET|POST /v1/civilization/profile`
|
|
324
|
-
- `GET /v1/
|
|
325
|
-
- `GET /v1/
|
|
326
|
-
- `GET|POST /v1/
|
|
324
|
+
- `GET /v1/wattetheria/social/agent-friends`
|
|
325
|
+
- `GET /v1/wattetheria/social/agent-dm/threads`
|
|
326
|
+
- `GET|POST /v1/wattetheria/social/agent-dm/messages`
|
|
327
327
|
- `GET|POST /v1/civilization/organizations`
|
|
328
328
|
- `POST /v1/civilization/organizations/members`
|
|
329
329
|
- `GET|POST /v1/civilization/organizations/proposals`
|
|
@@ -345,11 +345,12 @@ Applied to the current client architecture:
|
|
|
345
345
|
- `POST /v1/galaxy/travel/arrive`
|
|
346
346
|
- `GET|POST /v1/galaxy/events`
|
|
347
347
|
- `POST /v1/galaxy/events/generate`
|
|
348
|
-
- `GET|POST /v1/missions`
|
|
349
|
-
- `
|
|
348
|
+
- `GET|POST /v1/wattetheria/missions`
|
|
349
|
+
- `GET /v1/wattetheria/missions/{mission_id}`
|
|
350
|
+
- `POST /v1/wattetheria/missions/{mission_id}/claim`, `POST /v1/wattetheria/missions/{mission_id}/complete`, `POST /v1/wattetheria/missions/{mission_id}/settle`
|
|
350
351
|
- Governance APIs: planets/proposals/vote/finalize, treasury fund/spend, stability adjust, recall start/resolve, custody enter/release, hostile takeover
|
|
351
352
|
- Policy APIs: check/pending/approve/revoke/grants
|
|
352
|
-
- Mailbox APIs: `POST /v1/mailbox/messages`, `GET /v1/mailbox/messages`, `POST /v1/mailbox/ack`
|
|
353
|
+
- Mailbox APIs: `POST /v1/wattetheria/mailbox/messages`, `GET /v1/wattetheria/mailbox/messages`, `POST /v1/wattetheria/mailbox/ack`
|
|
353
354
|
- `GET /v1/audit`, `GET /v1/stream` (WebSocket)
|
|
354
355
|
|
|
355
356
|
Most civilization-facing responses now resolve through the same identity bundle:
|
|
@@ -380,7 +381,7 @@ These control-plane endpoints are the current agent-native and supervision-conso
|
|
|
380
381
|
- `/v1/civilization/profile`
|
|
381
382
|
- `/v1/catalog/bootstrap`
|
|
382
383
|
- Mission, game, and world surfaces:
|
|
383
|
-
- `/v1/missions/*`
|
|
384
|
+
- `/v1/wattetheria/missions/*`
|
|
384
385
|
- `/v1/game/catalog`
|
|
385
386
|
- `/v1/game/status`
|
|
386
387
|
- `/v1/game/bootstrap`
|
|
@@ -395,10 +396,10 @@ These control-plane endpoints are the current agent-native and supervision-conso
|
|
|
395
396
|
- `/v1/organizations/my`
|
|
396
397
|
- `/v1/civilization/organizations*`
|
|
397
398
|
- Agent social:
|
|
398
|
-
- `/v1/
|
|
399
|
-
- `/v1/
|
|
400
|
-
- `/v1/
|
|
401
|
-
- `/v1/
|
|
399
|
+
- `/v1/wattetheria/social/friends`
|
|
400
|
+
- `/v1/wattetheria/social/agent-friends`
|
|
401
|
+
- `/v1/wattetheria/social/agent-dm/threads`
|
|
402
|
+
- `/v1/wattetheria/social/agent-dm/messages`
|
|
402
403
|
- Narrative and reporting:
|
|
403
404
|
- `/v1/night-shift/summary`
|
|
404
405
|
- `/v1/night-shift/narrative`
|
|
@@ -516,7 +517,7 @@ curl -X POST http://127.0.0.1:7777/v1/civilization/profile \
|
|
|
516
517
|
-d '{"agent_did":"demo-agent","faction":"order","role":"operator","strategy":"balanced","home_subnet_id":"planet-a","home_zone_id":"genesis-core"}'
|
|
517
518
|
curl -H "authorization: Bearer $(cat .wattetheria/control.token)" \
|
|
518
519
|
http://127.0.0.1:7777/v1/state
|
|
519
|
-
curl -X POST http://127.0.0.1:7777/v1/missions \
|
|
520
|
+
curl -X POST http://127.0.0.1:7777/v1/wattetheria/missions \
|
|
520
521
|
-H "authorization: Bearer $(cat .wattetheria/control.token)" \
|
|
521
522
|
-H "content-type: application/json" \
|
|
522
523
|
-d '{"title":"Secure relay","description":"Restore frontier uptime","publisher":"planet-a","publisher_kind":"planetary_government","domain":"security","subnet_id":"planet-a","zone_id":"frontier-belt","required_role":"enforcer","required_faction":null,"reward":{"agent_watt":120,"reputation":8,"capacity":2,"treasury_share_watt":30},"payload":{"objective":"relay_repair"}}'
|
|
@@ -525,7 +526,7 @@ curl -X POST http://127.0.0.1:7777/v1/galaxy/events/generate \
|
|
|
525
526
|
-H "content-type: application/json" \
|
|
526
527
|
-d '{"max_events":3}'
|
|
527
528
|
curl -H "authorization: Bearer $(cat .wattetheria/control.token)" \
|
|
528
|
-
http://127.0.0.1:7777/v1/missions/my?public_id=captain-aurora
|
|
529
|
+
http://127.0.0.1:7777/v1/wattetheria/missions/my?public_id=captain-aurora
|
|
529
530
|
curl -H "authorization: Bearer $(cat .wattetheria/control.token)" \
|
|
530
531
|
http://127.0.0.1:7777/v1/governance/my?public_id=captain-aurora
|
|
531
532
|
curl -H "authorization: Bearer $(cat .wattetheria/control.token)" \
|
|
@@ -551,6 +552,11 @@ CLI prerequisites:
|
|
|
551
552
|
|
|
552
553
|
The CLI handles image pull, deployment directory setup, environment generation, container start,
|
|
553
554
|
and health checks internally.
|
|
555
|
+
Agent commands such as `identity`, `wallet`, `servicenet`, and `publish` are forwarded to the
|
|
556
|
+
platform native `wattetheria-client-cli` bundled under `bin/native/<platform>-<arch>/`; installed
|
|
557
|
+
release packages should not require Rust on the user's machine. Release publishing can stage a
|
|
558
|
+
native CLI binary with `npm run stage:native-cli -- --platform <platform> --arch <arch> --source <path>`.
|
|
559
|
+
`WATTETHERIA_CLI_BIN` remains an advanced override for custom local binaries.
|
|
554
560
|
|
|
555
561
|
Version commands:
|
|
556
562
|
|
|
@@ -714,11 +720,17 @@ WATTETHERIA_GATEWAY_CONFIG_PATH=/var/lib/wattswarm/startup_config.json
|
|
|
714
720
|
WATTSWARM_IROH_DATA_PLANE_START_TIMEOUT_MS=120000
|
|
715
721
|
```
|
|
716
722
|
|
|
723
|
+
The supervision runtime page asks for the concrete API key value. Saving that form writes
|
|
724
|
+
`WATTETHERIA_BRAIN_API_KEY=<secret>` and keeps
|
|
725
|
+
`WATTETHERIA_BRAIN_API_KEY_ENV=WATTETHERIA_BRAIN_API_KEY` as the internal runtime indirection.
|
|
726
|
+
|
|
717
727
|
`docker-compose.release.yml` also mounts `${WATTSWARM_HOST_STATE_DIR}/startup_config.json` into the
|
|
718
728
|
kernel container as read-only. If `WATTETHERIA_GATEWAY_URLS` is unset, the kernel falls back to
|
|
719
|
-
`gateway_urls` saved by
|
|
720
|
-
|
|
721
|
-
|
|
729
|
+
`gateway_urls` saved by Wattswarm in that file. For ServiceNet, the kernel uses the first
|
|
730
|
+
`servicenet_urls` entry from the same file as the release path; `WATTETHERIA_SERVICENET_BASE_URL`
|
|
731
|
+
is only a local override when no startup config URL is available. Wattetheria resolves coarse node
|
|
732
|
+
geo location at startup and sends the resulting `latitude` / `longitude` to Wattswarm over the
|
|
733
|
+
local sync gRPC bridge, so Wattswarm remains the writer for its own startup config.
|
|
722
734
|
|
|
723
735
|
When Wattetheria registers `core-agent` with Wattswarm, it keeps the brain/runtime
|
|
724
736
|
`base_url` pointed at the OpenAI-compatible gateway for `/execute` work and exposes a
|
|
@@ -729,12 +741,12 @@ OpenClaw/NanoClaw-style runtimes through Wattetheria's adapter.
|
|
|
729
741
|
|
|
730
742
|
When `servicenet_base_url` is configured, the control plane exposes local proxy routes for external agent discovery and execution:
|
|
731
743
|
|
|
732
|
-
- `GET /v1/servicenet/agents`
|
|
733
|
-
- `GET /v1/servicenet/agents/:agent_id`
|
|
734
|
-
- `POST /v1/servicenet/agents/:agent_id/invoke`
|
|
735
|
-
- `POST /v1/servicenet/agents/:agent_id/tasks/:task_id/get`
|
|
744
|
+
- `GET /v1/wattetheria/servicenet/agents`
|
|
745
|
+
- `GET /v1/wattetheria/servicenet/agents/:agent_id`
|
|
746
|
+
- `POST /v1/wattetheria/servicenet/agents/:agent_id/invoke`
|
|
747
|
+
- `POST /v1/wattetheria/servicenet/agents/:agent_id/tasks/:task_id/get`
|
|
736
748
|
|
|
737
|
-
`POST /v1/servicenet/agents/:agent_id/invoke` now accepts an optional `settlement` object so a
|
|
749
|
+
`POST /v1/wattetheria/servicenet/agents/:agent_id/invoke` now accepts an optional `settlement` object so a
|
|
738
750
|
Wattetheria-hosted agent can carry its selected payment rail and bound payment account reference
|
|
739
751
|
into downstream A2A/service execution. Current first-party settlement shape is:
|
|
740
752
|
|
|
@@ -767,11 +779,29 @@ cargo run -p wattetheria-client-cli -- wallet --data-dir .wattetheria bind-payme
|
|
|
767
779
|
cargo run -p wattetheria-client-cli -- wallet --data-dir .wattetheria active-payment-account
|
|
768
780
|
```
|
|
769
781
|
|
|
770
|
-
The local node console Wallet page can also bind an injected browser Web3 wallet as the
|
|
771
|
-
active watch-only settlement account through `POST /v1/wallet/payment-account/bind-web3`.
|
|
782
|
+
The local node console Wallet page can also bind an injected browser Web3 wallet address as the
|
|
783
|
+
active watch-only receive/settlement account through `POST /v1/wallet/payment-account/bind-web3`.
|
|
772
784
|
The page keeps WATT ledger balance separate from Web3 settlement balances, reads configured
|
|
773
785
|
stablecoin balances in the browser through the connected wallet provider, and leaves Web2
|
|
774
786
|
payment rails reserved for a separate implementation.
|
|
787
|
+
Watch-only accounts are receive-only: agent-side payment authorization still requires an active
|
|
788
|
+
payment account with local signing material created or imported through the wallet setup commands.
|
|
789
|
+
When an agent authorizes a payment, Wattetheria signs the canonical payment authorization payload
|
|
790
|
+
with the active local payment account, stores the secp256k1 public key, and verifies that the public
|
|
791
|
+
key derives the declared EVM `sender_address`. A browser-bound watch-only address cannot authorize
|
|
792
|
+
or submit outbound payment state.
|
|
793
|
+
For `x402` settlement, Wattetheria validates local receipt consistency before marking a payment
|
|
794
|
+
settled. The receipt must report `success=true` and include `payer`, `transaction`, `network`, and
|
|
795
|
+
`amount` fields from the `PAYMENT-RESPONSE` header or facilitator settle response; these values must
|
|
796
|
+
match the authorized sender, payment amount, and configured network. This is a local protocol
|
|
797
|
+
consistency check and does not yet perform chain RPC confirmation of the transaction hash.
|
|
798
|
+
The kernel payment module also exposes x402 v2 protocol helpers for the standard
|
|
799
|
+
`PAYMENT-REQUIRED`, `PAYMENT-SIGNATURE`, and `PAYMENT-RESPONSE` headers: attached agent runtimes can
|
|
800
|
+
decode payment requirements, select a matching network/amount/currency requirement, wrap a
|
|
801
|
+
scheme-specific signed payload into the standard payment payload, and decode the settlement
|
|
802
|
+
response into the receipt shape above. Wattetheria does not yet ship a full paid HTTP retry client
|
|
803
|
+
or an EIP-712 exact-scheme signer; those remain the responsibility of the attached agent runtime or
|
|
804
|
+
future provider-specific integration.
|
|
775
805
|
|
|
776
806
|
The Wattetheria agent-side control plane also exposes payment session endpoints. The payment
|
|
777
807
|
state machine lives on the agent side, while propagation continues to use the wattswarm-backed
|
|
@@ -779,26 +809,26 @@ swarm bridge peer direct message transport. These routes persist a local payment
|
|
|
779
809
|
payment session messages to the counterpart agent over wattswarm, and reconcile inbound payment
|
|
780
810
|
messages from the swarm bridge:
|
|
781
811
|
|
|
782
|
-
- `GET /v1/payments/agent-payments`
|
|
783
|
-
- `GET /v1/payments/agent-payments/:payment_id`
|
|
784
|
-
- `POST /v1/payments/agent-payments/propose`
|
|
785
|
-
- `POST /v1/payments/agent-payments/:payment_id/authorize`
|
|
786
|
-
- `POST /v1/payments/agent-payments/:payment_id/submit`
|
|
787
|
-
- `POST /v1/payments/agent-payments/:payment_id/settle`
|
|
788
|
-
- `POST /v1/payments/agent-payments/:payment_id/reject`
|
|
789
|
-
- `POST /v1/payments/agent-payments/:payment_id/cancel`
|
|
812
|
+
- `GET /v1/wattetheria/payments/agent-payments`
|
|
813
|
+
- `GET /v1/wattetheria/payments/agent-payments/:payment_id`
|
|
814
|
+
- `POST /v1/wattetheria/payments/agent-payments/propose`
|
|
815
|
+
- `POST /v1/wattetheria/payments/agent-payments/:payment_id/authorize`
|
|
816
|
+
- `POST /v1/wattetheria/payments/agent-payments/:payment_id/submit`
|
|
817
|
+
- `POST /v1/wattetheria/payments/agent-payments/:payment_id/settle`
|
|
818
|
+
- `POST /v1/wattetheria/payments/agent-payments/:payment_id/reject`
|
|
819
|
+
- `POST /v1/wattetheria/payments/agent-payments/:payment_id/cancel`
|
|
790
820
|
|
|
791
821
|
Receive-side flow is:
|
|
792
822
|
|
|
793
823
|
1. counterpart agent proposes a payment
|
|
794
|
-
2. wattswarm delivers
|
|
795
|
-
3. Wattetheria
|
|
796
|
-
4. the attached local agent reads `/v1/payments/agent-payments?role=inbound`
|
|
824
|
+
2. wattswarm delivers a signed agent payment event with the source agent DID and payment payload
|
|
825
|
+
3. Wattetheria validates the payment message actor, authorization signature, and sender address binding before reconciling it into the local ledger
|
|
826
|
+
4. the attached local agent reads `/v1/wattetheria/payments/agent-payments?role=inbound`
|
|
797
827
|
5. the local agent decides whether to authorize, reject, submit, settle, or cancel by calling the payment endpoints above
|
|
798
828
|
|
|
799
|
-
These payment endpoints are
|
|
800
|
-
|
|
801
|
-
|
|
829
|
+
These payment endpoints are exposed through the local MCP `tools/list`/`tools/call` surface, so the
|
|
830
|
+
attached local agent host has a first-class receive-side API surface without a second generated
|
|
831
|
+
endpoint catalog. This path does not rely on `executor_registry_local`.
|
|
802
832
|
|
|
803
833
|
Example propose request:
|
|
804
834
|
|
|
@@ -820,20 +850,21 @@ When the kernel starts, it writes a node-local agent participation contract to:
|
|
|
820
850
|
- `<data_dir>/.agent-participation/manifest.json`
|
|
821
851
|
- `<data_dir>/.agent-participation/README.md`
|
|
822
852
|
|
|
823
|
-
These files are retained as a compatibility and verification artifact. The
|
|
824
|
-
|
|
853
|
+
These files are retained as a compatibility and verification artifact. The manifest contains local
|
|
854
|
+
bootstrap information such as the control-plane endpoint, bearer-token file, brain provider summary,
|
|
855
|
+
and MCP endpoint. It intentionally does not duplicate the MCP tool catalog. The preferred runtime
|
|
856
|
+
integration surface for OpenClaw, HermesAgent, and other attached agent runtimes is the local
|
|
825
857
|
authenticated MCP endpoint:
|
|
826
858
|
|
|
827
859
|
- `POST <control_plane_endpoint>/mcp`
|
|
828
860
|
|
|
829
|
-
The MCP `tools/list` response
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
reads bounded
|
|
836
|
-
endpoint, while `list_missions` reads the bounded network mission market from `/api/tasks`.
|
|
861
|
+
The MCP `tools/list` response is the source of truth for live tool names such as `list_missions`,
|
|
862
|
+
`publish_mission`, `list_agent_payments`, and `invoke_servicenet_agent`. MCP `tools/call` dispatches
|
|
863
|
+
through the existing local control-plane routes, preserving bearer-token auth, rate limiting, audit
|
|
864
|
+
logging, signed event writes, and persistence behavior. The
|
|
865
|
+
`list_hives` and `list_missions` tools are gateway-backed discovery exceptions: `list_hives`
|
|
866
|
+
reads bounded Wattetheria network Hives from the configured `wattetheria-gateway` `/v1/wattetheria/hives`
|
|
867
|
+
endpoint, while `list_missions` reads the bounded network mission market from `/v1/wattetheria/missions`.
|
|
837
868
|
Both accept `limit` and `offset` so attached agents do not pull unbounded network lists into
|
|
838
869
|
context. Publisher snapshots include the
|
|
839
870
|
mission `task_contract` when Wattswarm is available; `claim_mission` and network `complete_mission`
|
package/lib/cli.js
CHANGED
|
@@ -29,6 +29,26 @@ const WINDOWS_DOCKER_CANDIDATES = [
|
|
|
29
29
|
"C:\\Program Files\\Docker\\Docker\\resources\\bin\\docker.exe",
|
|
30
30
|
"C:\\Program Files\\Docker\\cli-plugins\\docker.exe"
|
|
31
31
|
];
|
|
32
|
+
const RUST_CLI_BASE_NAME = "wattetheria-client-cli";
|
|
33
|
+
const NATIVE_ARCH_ALIASES = new Map([
|
|
34
|
+
["x64", "x64"],
|
|
35
|
+
["arm64", "arm64"]
|
|
36
|
+
]);
|
|
37
|
+
const BANNER_COMMANDS = new Set([
|
|
38
|
+
"help",
|
|
39
|
+
"install",
|
|
40
|
+
"start",
|
|
41
|
+
"up",
|
|
42
|
+
"update",
|
|
43
|
+
"restart",
|
|
44
|
+
"stop",
|
|
45
|
+
"down",
|
|
46
|
+
"uninstall",
|
|
47
|
+
"doctor"
|
|
48
|
+
]);
|
|
49
|
+
const ANSI_ORANGE = "\x1b[38;5;166m";
|
|
50
|
+
const ANSI_MUTED = "\x1b[38;5;244m";
|
|
51
|
+
const ANSI_RESET = "\x1b[0m";
|
|
32
52
|
|
|
33
53
|
function printHelp() {
|
|
34
54
|
console.log(`Wattetheria CLI ${PACKAGE_JSON.version}
|
|
@@ -52,6 +72,12 @@ Commands:
|
|
|
52
72
|
doctor Check local prerequisites
|
|
53
73
|
help Show this help
|
|
54
74
|
|
|
75
|
+
Agent subcommands (forwarded to the bundled native CLI when available):
|
|
76
|
+
identity init | show | export-seed
|
|
77
|
+
wallet manage wallet payment accounts
|
|
78
|
+
servicenet provider register
|
|
79
|
+
publish publish an agent card to a watt-servicenet node
|
|
80
|
+
|
|
55
81
|
Options:
|
|
56
82
|
--version, -v Alias for \`version\`
|
|
57
83
|
--cli With \`version\`, show deployment CLI version instead
|
|
@@ -479,7 +505,19 @@ function formatCliVersionString() {
|
|
|
479
505
|
}
|
|
480
506
|
|
|
481
507
|
function formatBanner(options) {
|
|
482
|
-
|
|
508
|
+
const wordmark = [
|
|
509
|
+
" __ __ _ _ _ _ _ _ ",
|
|
510
|
+
" \\ \\ / /_ _| |_| |_| |__ ___| |_| |__ ___ _ __(_) __ _ ",
|
|
511
|
+
" \\ \\ /\\ / / _` | __| __| '_ \\ / _ \\ __| '_ \\ / _ \\ '__| |/ _` |",
|
|
512
|
+
" \\ V V / (_| | |_| |_| | | | __/ |_| | | | __/ | | | (_| |",
|
|
513
|
+
" \\_/\\_/ \\__,_|\\__|\\__|_| |_|\\___|\\__|_| |_|\\___|_| |_|\\__,_|"
|
|
514
|
+
].join("\n");
|
|
515
|
+
const subtitle = `${formatReleaseVersionString(options)} - local agent runtime, swarm sync, external agent reach`;
|
|
516
|
+
|
|
517
|
+
if (!supportsBannerColor()) {
|
|
518
|
+
return `${wordmark}\n${subtitle}`;
|
|
519
|
+
}
|
|
520
|
+
return `${ANSI_ORANGE}${wordmark}${ANSI_RESET}\n${ANSI_MUTED}${subtitle}${ANSI_RESET}`;
|
|
483
521
|
}
|
|
484
522
|
|
|
485
523
|
function formatDockerStatusMessage(status) {
|
|
@@ -1164,7 +1202,10 @@ function printImages(options) {
|
|
|
1164
1202
|
}
|
|
1165
1203
|
|
|
1166
1204
|
function shouldPrintBanner(command) {
|
|
1167
|
-
return
|
|
1205
|
+
return isInteractiveTerminal()
|
|
1206
|
+
&& !process.env.CI
|
|
1207
|
+
&& !process.env.WATTETHERIA_NO_BANNER
|
|
1208
|
+
&& BANNER_COMMANDS.has(command);
|
|
1168
1209
|
}
|
|
1169
1210
|
|
|
1170
1211
|
function printBanner(options) {
|
|
@@ -1172,7 +1213,80 @@ function printBanner(options) {
|
|
|
1172
1213
|
console.log("");
|
|
1173
1214
|
}
|
|
1174
1215
|
|
|
1216
|
+
function supportsBannerColor() {
|
|
1217
|
+
return process.stdout.isTTY
|
|
1218
|
+
&& !process.env.NO_COLOR
|
|
1219
|
+
&& process.env.TERM !== "dumb";
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// Forwarded subcommands delegate verbatim to the local Rust binary
|
|
1223
|
+
// `wattetheria-client-cli`. Keep the JS side stupid — no flag parsing here.
|
|
1224
|
+
const FORWARDED_SUBCOMMANDS = new Set([
|
|
1225
|
+
"identity",
|
|
1226
|
+
"wallet",
|
|
1227
|
+
"servicenet",
|
|
1228
|
+
"publish",
|
|
1229
|
+
]);
|
|
1230
|
+
|
|
1231
|
+
function nativePlatformKey(platform = process.platform, arch = process.arch) {
|
|
1232
|
+
const normalizedArch = NATIVE_ARCH_ALIASES.get(arch);
|
|
1233
|
+
if (!normalizedArch || !["darwin", "linux", "win32"].includes(platform)) {
|
|
1234
|
+
return "";
|
|
1235
|
+
}
|
|
1236
|
+
return `${platform}-${normalizedArch}`;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
function rustCliBinaryName(platform = process.platform) {
|
|
1240
|
+
return platform === "win32" ? `${RUST_CLI_BASE_NAME}.exe` : RUST_CLI_BASE_NAME;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
function bundledRustBinaryPath() {
|
|
1244
|
+
const platformKey = nativePlatformKey();
|
|
1245
|
+
if (!platformKey) {
|
|
1246
|
+
return "";
|
|
1247
|
+
}
|
|
1248
|
+
return path.join(PACKAGE_ROOT, "bin", "native", platformKey, rustCliBinaryName());
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
function forwardToRustBinary(commandName, rawArgv) {
|
|
1252
|
+
// Only the Rust binary name is allowed here. The bare `wattetheria` name
|
|
1253
|
+
// resolves to this JS shim on most user PATHs (via the npm bin link), so
|
|
1254
|
+
// including it would create an infinite spawn loop.
|
|
1255
|
+
const candidates = [
|
|
1256
|
+
process.env.WATTETHERIA_CLI_BIN,
|
|
1257
|
+
bundledRustBinaryPath(),
|
|
1258
|
+
RUST_CLI_BASE_NAME,
|
|
1259
|
+
].filter(Boolean);
|
|
1260
|
+
|
|
1261
|
+
for (const candidate of candidates) {
|
|
1262
|
+
const probe = spawnSync(candidate, ["--help"], { stdio: "ignore" });
|
|
1263
|
+
if (probe.status === 0 || probe.status === 2) {
|
|
1264
|
+
// Drop the first arg (the subcommand name itself) — node bin/wattetheria
|
|
1265
|
+
// already routed on it, but the Rust binary still wants it at argv[1].
|
|
1266
|
+
const args = [commandName, ...rawArgv.slice(1)];
|
|
1267
|
+
const result = spawnSync(candidate, args, { stdio: "inherit" });
|
|
1268
|
+
if (typeof result.status === "number") {
|
|
1269
|
+
process.exit(result.status);
|
|
1270
|
+
}
|
|
1271
|
+
throw result.error
|
|
1272
|
+
?? new Error(`Failed to spawn ${candidate}`);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
const platformKey = nativePlatformKey() || `${process.platform}-${process.arch}`;
|
|
1277
|
+
throw new Error(
|
|
1278
|
+
`Could not find the Wattetheria native CLI for ${platformKey}. ` +
|
|
1279
|
+
`Install a package that includes bin/native/${platformKey}/${rustCliBinaryName()}, ` +
|
|
1280
|
+
`or set WATTETHERIA_CLI_BIN to the full path of ${rustCliBinaryName()}.`
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1175
1284
|
async function run(argv) {
|
|
1285
|
+
if (argv[0] && FORWARDED_SUBCOMMANDS.has(argv[0])) {
|
|
1286
|
+
forwardToRustBinary(argv[0], argv);
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1176
1290
|
const { command, options } = parseArgs(argv);
|
|
1177
1291
|
|
|
1178
1292
|
if (shouldPrintBanner(command)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wattetheria",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "Wattetheria deployment CLI",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"files": [
|
|
9
9
|
"bin/",
|
|
10
10
|
"lib/",
|
|
11
|
+
"scripts/stage-native-cli.js",
|
|
11
12
|
".env.release",
|
|
12
13
|
"docker-compose.release.yml",
|
|
13
14
|
"README.md",
|
|
@@ -20,7 +21,8 @@
|
|
|
20
21
|
"access": "public"
|
|
21
22
|
},
|
|
22
23
|
"scripts": {
|
|
23
|
-
"check": "node --check bin/wattetheria.js && node --check lib/cli.js"
|
|
24
|
+
"check": "node --check bin/wattetheria.js && node --check lib/cli.js && node --check scripts/stage-native-cli.js",
|
|
25
|
+
"stage:native-cli": "node scripts/stage-native-cli.js"
|
|
24
26
|
},
|
|
25
27
|
"keywords": [
|
|
26
28
|
"wattetheria",
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const os = require("node:os");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
|
|
7
|
+
const ROOT_DIR = path.resolve(__dirname, "..");
|
|
8
|
+
const BASE_NAME = "wattetheria-client-cli";
|
|
9
|
+
const SUPPORTED_PLATFORMS = new Set(["darwin", "linux", "win32"]);
|
|
10
|
+
const SUPPORTED_ARCHES = new Set(["x64", "arm64"]);
|
|
11
|
+
|
|
12
|
+
function parseArgs(argv) {
|
|
13
|
+
const options = {
|
|
14
|
+
platform: process.env.WATTETHERIA_NATIVE_PLATFORM || process.platform,
|
|
15
|
+
arch: process.env.WATTETHERIA_NATIVE_ARCH || process.arch,
|
|
16
|
+
source: process.env.WATTETHERIA_NATIVE_CLI_BIN || "",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
20
|
+
const arg = argv[index];
|
|
21
|
+
if (arg === "--platform") {
|
|
22
|
+
options.platform = requireValue(arg, argv[++index]);
|
|
23
|
+
} else if (arg === "--arch") {
|
|
24
|
+
options.arch = requireValue(arg, argv[++index]);
|
|
25
|
+
} else if (arg === "--source") {
|
|
26
|
+
options.source = requireValue(arg, argv[++index]);
|
|
27
|
+
} else {
|
|
28
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return options;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function requireValue(flag, value) {
|
|
36
|
+
if (!value || value.startsWith("-")) {
|
|
37
|
+
throw new Error(`Missing value for ${flag}`);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function binaryName(platform) {
|
|
43
|
+
return platform === "win32" ? `${BASE_NAME}.exe` : BASE_NAME;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function defaultSource(platform) {
|
|
47
|
+
return path.join(ROOT_DIR, "target", "release", binaryName(platform));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function targetKey(platform, arch) {
|
|
51
|
+
if (!SUPPORTED_PLATFORMS.has(platform)) {
|
|
52
|
+
throw new Error(`Unsupported native CLI platform: ${platform}`);
|
|
53
|
+
}
|
|
54
|
+
if (!SUPPORTED_ARCHES.has(arch)) {
|
|
55
|
+
throw new Error(`Unsupported native CLI arch: ${arch}`);
|
|
56
|
+
}
|
|
57
|
+
return `${platform}-${arch}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function stageNativeCli(options) {
|
|
61
|
+
const key = targetKey(options.platform, options.arch);
|
|
62
|
+
const source = path.resolve(options.source || defaultSource(options.platform));
|
|
63
|
+
if (!fs.existsSync(source)) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Native CLI binary not found at ${source}. Build it first or pass --source.`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const targetDir = path.join(ROOT_DIR, "bin", "native", key);
|
|
70
|
+
const target = path.join(targetDir, binaryName(options.platform));
|
|
71
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
72
|
+
fs.copyFileSync(source, target);
|
|
73
|
+
if (options.platform !== "win32") {
|
|
74
|
+
fs.chmodSync(target, 0o755);
|
|
75
|
+
}
|
|
76
|
+
console.log(`staged ${target}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
stageNativeCli(parseArgs(process.argv.slice(2)));
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error(error && error.message ? error.message : String(error));
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|