@thirdfy/agent-cli 0.1.7 → 0.1.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/CHANGELOG.md +61 -0
- package/README.md +66 -0
- package/bin/thirdfy-agent.mjs +332 -89
- package/package.json +7 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@thirdfy/agent-cli` are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Self preflight routing for swap-like actions:** `preflight --run-mode self` now selects the validation route by action capability. When an action advertises `supportsExecuteIntent=false` and `supportsBuildTx=true`, preflight uses `build-tx` directly instead of forcing execute-intent validation.
|
|
10
|
+
|
|
11
|
+
## [0.1.8] - 2026-04-07
|
|
12
|
+
|
|
13
|
+
**npm:** [`@thirdfy/agent-cli@0.1.8`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.8)
|
|
14
|
+
**Git tag:** `v0.1.8`
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **Managed custodial lifecycle validation:** Added CLI E2E path for managed wallet delegation parity (`e2e:managed:delegation:parity`) and integrated coverage into production certification flow.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Self execution diagnostics:** `doctor self` is now routed as an offline/local command and no longer depends on capabilities negotiation.
|
|
23
|
+
- **Managed wallet command routing:** Removed thin wrapper indirection and wired `managed wallet init/grant` directly to delegation custodial handlers.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **Effect check payload safety:** Hardened relaxed-mode effect-check fallback so warning payload shape remains deterministic in edge paths.
|
|
28
|
+
- **Managed wallet integration test contract:** Validation-only detection now correctly uses `executionLane === 'validation_only'`, with explicit auth env isolation for deterministic header assertions.
|
|
29
|
+
|
|
30
|
+
## [0.1.7] - 2026-04-05
|
|
31
|
+
|
|
32
|
+
**npm:** [`@thirdfy/agent-cli@0.1.7`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.7)
|
|
33
|
+
**Git tag:** [`v0.1.7`](https://github.com/thirdfy/agent-cli/releases/tag/v0.1.7)
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **Login and local config:** `thirdfy-agent login`, `logout` (including `logout --all` for local clear plus owner-session revoke when applicable), `whoami`, and `config set` / `config show` with defaults persisted under `~/.thirdfy/config.json`. Credential precedence remains: CLI flags, then environment variables, then saved config (see README).
|
|
38
|
+
- **Custodial delegation (MetaMask-compatible path):** `delegation init-custodial` and `delegation custodial-grant` alongside the existing `delegation create` / `delegation activate` lifecycle.
|
|
39
|
+
- **Delegation operator ergonomics:** `delegation show` as an alias for `delegation status`; expanded delegation inspection and parity-focused behavior for automation.
|
|
40
|
+
- **E2E / certification:** Delegation parity and production certification scripts (`e2e:self:delegation:parity`, `e2e:delegation:prod:certify`) and related gates documented in internal runbooks.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- **`delegation redeem`:** Respects the effective run mode (flag / env / profile) when building the execution path.
|
|
45
|
+
- **Swap amount handling:** Clearer separation between *missing* and *ambiguous* amount-unit errors; stricter validation of human-form amounts (including excess precision) and decimals handling for `amountInHuman` flows.
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- **Config and bootstrap:** Safer bootstrap output, tighter validation, preserved config semantics on upgrade paths, and `config set` rejects prototype-path keys to avoid confusing or unsafe key shapes.
|
|
50
|
+
- **Login / token handling:** Stricter verification of token shape after login and safer config cloning for delegation-related routing.
|
|
51
|
+
- **E2E:** Session-auth paths keep a dev-mock wallet fallback where intended so local and CI simulations stay stable.
|
|
52
|
+
|
|
53
|
+
### Tooling
|
|
54
|
+
|
|
55
|
+
- **Release workflow:** When a version is already published to npm, CI skips `npm publish` so tag-based runs can still create or align GitHub releases without duplicate-publish failures.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## [0.1.6] - 2026-03-30
|
|
60
|
+
|
|
61
|
+
Prior release; see [git compare `v0.1.6...v0.1.7`](https://github.com/thirdfy/agent-cli/compare/v0.1.6...v0.1.7) for the full commit list.
|
package/README.md
CHANGED
|
@@ -33,6 +33,13 @@ Run without global install:
|
|
|
33
33
|
npx @thirdfy/agent-cli --help
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
## What's new in 0.1.8
|
|
37
|
+
|
|
38
|
+
- Managed custodial lifecycle parity validation is now first-class in CLI E2E/certification.
|
|
39
|
+
- `doctor self` runs as a local diagnostic command without capabilities negotiation.
|
|
40
|
+
- Self-exec effect-check fallback payloads are hardened for deterministic automation parsing.
|
|
41
|
+
- Managed wallet aliases (`managed wallet init/grant`) are wired directly to custodial delegation handlers.
|
|
42
|
+
|
|
36
43
|
## Quick start
|
|
37
44
|
|
|
38
45
|
```bash
|
|
@@ -101,6 +108,9 @@ thirdfy-agent agent register --owner-session-token "$THIRDFY_OWNER_SESSION_TOKEN
|
|
|
101
108
|
- `run` auto-generates `idempotencyKey` by default when not provided.
|
|
102
109
|
- For deterministic retries across workers/restarts, pass your own stable `--idempotency-key`.
|
|
103
110
|
- `preflight` does not force idempotency keys.
|
|
111
|
+
- `preflight --run-mode self` is capability-aware:
|
|
112
|
+
- if an action supports execute-intent validation, CLI uses `executionLane=validation_only` before building tx;
|
|
113
|
+
- if an action advertises `supportsExecuteIntent=false` and `supportsBuildTx=true`, CLI routes preflight directly to `build-tx`.
|
|
104
114
|
|
|
105
115
|
## Run modes and profiles
|
|
106
116
|
|
|
@@ -110,6 +120,12 @@ thirdfy-agent agent register --owner-session-token "$THIRDFY_OWNER_SESSION_TOKEN
|
|
|
110
120
|
- `--run-mode self` -> self-custody rail (`build-tx` flow; default for `profile=personal`)
|
|
111
121
|
- `--run-mode hybrid` -> self-custody + governance mirror metadata (default for `profile=builder`)
|
|
112
122
|
|
|
123
|
+
| Goal | Recommended mode | Why |
|
|
124
|
+
| --- | --- | --- |
|
|
125
|
+
| BYOW signing and local custody | `self` | Keeps signing and broadcast on your wallet path. |
|
|
126
|
+
| Managed delegated execution | `thirdfy` | Uses delegated governance rail for hosted execution. |
|
|
127
|
+
| Self execution plus governance mirror checks | `hybrid` | Preserves local execution while emitting managed-lane mirrors. |
|
|
128
|
+
|
|
113
129
|
Auth expectations by mode:
|
|
114
130
|
|
|
115
131
|
- `self`: requires execution identity (`agentApiKey`) today; keyless self lane is blocked with deterministic `SELF_OPEN_DISABLED`.
|
|
@@ -133,6 +149,41 @@ thirdfy-agent whoami --json
|
|
|
133
149
|
|
|
134
150
|
`profile use --profile <name>` resets run mode to that profile default unless `--run-mode` is explicitly provided.
|
|
135
151
|
|
|
152
|
+
### One-command self execution (BYOW)
|
|
153
|
+
|
|
154
|
+
Use `--broadcast` with `run --run-mode self` to keep one deterministic command for build/sign/send:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
thirdfy-agent run \
|
|
158
|
+
--agent-api-key "$AGENT_API_KEY" \
|
|
159
|
+
--run-mode self \
|
|
160
|
+
--broadcast \
|
|
161
|
+
--action swap \
|
|
162
|
+
--params '{"tokenIn":"0x...","tokenOut":"0x...","amountInRaw":"1000000","chainId":8453}' \
|
|
163
|
+
--json
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The default `run --run-mode self` behavior is still unsigned-only (advanced users can sign externally).
|
|
167
|
+
|
|
168
|
+
Self lane effect-check controls:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# strict: fail if no observable token delta
|
|
172
|
+
thirdfy-agent self-exec ... --effect-check strict --json
|
|
173
|
+
|
|
174
|
+
# relaxed (default): retry/read balances, warn on mismatch, do not false-fail the tx
|
|
175
|
+
thirdfy-agent self-exec ... --effect-check relaxed --json
|
|
176
|
+
|
|
177
|
+
# off: skip post-trade token-delta verification
|
|
178
|
+
thirdfy-agent self-exec ... --effect-check off --json
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Signer diagnostics:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
thirdfy-agent doctor self --json
|
|
185
|
+
```
|
|
186
|
+
|
|
136
187
|
## Swap amount contract (agent-safe)
|
|
137
188
|
|
|
138
189
|
For `--action swap`, CLI enforces an explicit amount unit contract:
|
|
@@ -251,6 +302,16 @@ The CLI keeps compatibility with legacy `delegation create` + `delegation activa
|
|
|
251
302
|
|
|
252
303
|
`delegation show` is a direct alias to `delegation status` for gator-style operator ergonomics.
|
|
253
304
|
|
|
305
|
+
Managed easy-wallet command group:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
thirdfy-agent managed wallet init --auth-token "$THIRDFY_AUTH_TOKEN" --json
|
|
309
|
+
# or: --owner-session-token "$THIRDFY_OWNER_SESSION_TOKEN"
|
|
310
|
+
thirdfy-agent managed wallet grant --auth-token "$THIRDFY_AUTH_TOKEN" --agent-key "0xYOUR_AGENT_KEY" --token-address "0x..." --max-usd-per-day 250 --json
|
|
311
|
+
# or: --owner-session-token "$THIRDFY_OWNER_SESSION_TOKEN"
|
|
312
|
+
thirdfy-agent managed run --agent-api-key "$AGENT_API_KEY" --run-mode thirdfy --action swap --params '{"tokenIn":"0x...","tokenOut":"0x...","amountInRaw":"1000000"}' --json
|
|
313
|
+
```
|
|
314
|
+
|
|
254
315
|
## More docs
|
|
255
316
|
|
|
256
317
|
- OpenClaw CLI onboarding flow:
|
|
@@ -264,11 +325,16 @@ The CLI keeps compatibility with legacy `delegation create` + `delegation activa
|
|
|
264
325
|
npm run validate:cli-contract-schemas
|
|
265
326
|
npm test
|
|
266
327
|
npm run smoke:cli
|
|
328
|
+
npm run e2e:managed:delegation:parity
|
|
267
329
|
```
|
|
268
330
|
|
|
269
331
|
## Release
|
|
270
332
|
|
|
333
|
+
Version history and user-facing notes: [CHANGELOG.md](./CHANGELOG.md) (for example [0.1.7](https://github.com/thirdfy/agent-cli/releases/tag/v0.1.7) — login/config UX, custodial delegation helpers, swap and config hardening).
|
|
334
|
+
|
|
271
335
|
```bash
|
|
272
336
|
npm version patch
|
|
273
337
|
npm publish --access public
|
|
274
338
|
```
|
|
339
|
+
|
|
340
|
+
After publishing, push the matching tag (for example `v0.1.7`) so the [Release workflow](.github/workflows/release.yml) can create a GitHub release. If the package version is already on npm, the workflow skips republishing and still creates the release when triggered by a tag.
|
package/bin/thirdfy-agent.mjs
CHANGED
|
@@ -19,6 +19,7 @@ const DEFAULT_API_BASE = 'https://api.thirdfy.com';
|
|
|
19
19
|
const DEFAULT_TIMEOUT_MS = 30000;
|
|
20
20
|
const DEFAULT_CATALOG_CACHE_TTL_MS = 60_000;
|
|
21
21
|
const RUN_MODES = ['thirdfy', 'self', 'hybrid'];
|
|
22
|
+
const EFFECT_CHECK_MODES = ['strict', 'relaxed', 'off'];
|
|
22
23
|
const PROFILE_DEFAULTS = {
|
|
23
24
|
personal: 'self',
|
|
24
25
|
builder: 'hybrid',
|
|
@@ -118,6 +119,9 @@ async function main() {
|
|
|
118
119
|
case 'whoami':
|
|
119
120
|
await commandProfileShow(context, subFlags);
|
|
120
121
|
return;
|
|
122
|
+
case 'doctor self':
|
|
123
|
+
await commandDoctorSelf(context, subFlags);
|
|
124
|
+
return;
|
|
121
125
|
default:
|
|
122
126
|
break;
|
|
123
127
|
}
|
|
@@ -125,6 +129,9 @@ async function main() {
|
|
|
125
129
|
const capabilities = await negotiateCapabilities(context);
|
|
126
130
|
|
|
127
131
|
switch (commandKey) {
|
|
132
|
+
case 'managed run':
|
|
133
|
+
await commandManagedRun(context, subFlags, capabilities);
|
|
134
|
+
return;
|
|
128
135
|
case 'jeff trade':
|
|
129
136
|
await commandRun(context, subFlags, capabilities);
|
|
130
137
|
return;
|
|
@@ -201,6 +208,14 @@ async function main() {
|
|
|
201
208
|
await commandAgentAuthVerify(context, subFlags, capabilities);
|
|
202
209
|
return;
|
|
203
210
|
}
|
|
211
|
+
if (commandKey3 === 'managed wallet init') {
|
|
212
|
+
await commandDelegationInitCustodial(context, subFlags, capabilities);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (commandKey3 === 'managed wallet grant') {
|
|
216
|
+
await commandDelegationCustodialGrant(context, subFlags, capabilities);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
204
219
|
|
|
205
220
|
const rootCommand = parsed.positionals[0];
|
|
206
221
|
switch (rootCommand) {
|
|
@@ -502,7 +517,7 @@ async function commandPreflight(ctx, flags, capabilities) {
|
|
|
502
517
|
prepareActionParamsForFlags(flags, resolved.resolvedAction);
|
|
503
518
|
const runMode = getEffectiveRunMode(ctx, flags);
|
|
504
519
|
enforceChainCompatibility(capabilities, flags, runMode);
|
|
505
|
-
const backendResult = await runPreflightByMode(runMode, ctx, flags, resolved
|
|
520
|
+
const backendResult = await runPreflightByMode(runMode, ctx, flags, resolved);
|
|
506
521
|
const normalized = backendResult.normalized;
|
|
507
522
|
printEnvelope({
|
|
508
523
|
success: normalized.success,
|
|
@@ -514,6 +529,7 @@ async function commandPreflight(ctx, flags, capabilities) {
|
|
|
514
529
|
catalog: flags.catalog || null,
|
|
515
530
|
requestedAction: resolved.requestedAction,
|
|
516
531
|
resolvedAction: resolved.resolvedAction,
|
|
532
|
+
preflightRoute: backendResult.route,
|
|
517
533
|
runMode,
|
|
518
534
|
profile: ctx.profile || null,
|
|
519
535
|
swapInput: flags.__swapInput || null,
|
|
@@ -533,6 +549,26 @@ async function commandRun(ctx, flags, capabilities) {
|
|
|
533
549
|
skipPreflight,
|
|
534
550
|
});
|
|
535
551
|
const normalized = backendResult.normalized;
|
|
552
|
+
if (runMode === 'self' && parseBooleanFlag(flags.broadcast, false) && normalized?.success) {
|
|
553
|
+
const executed = await performSelfBroadcast(ctx, flags, resolved.resolvedAction, normalized);
|
|
554
|
+
printEnvelope({
|
|
555
|
+
success: true,
|
|
556
|
+
code: 'SELF_EXECUTED',
|
|
557
|
+
message: 'Self-custody execution completed',
|
|
558
|
+
data: executed,
|
|
559
|
+
meta: {
|
|
560
|
+
apiBase: ctx.apiBase,
|
|
561
|
+
requestedAction: resolved.requestedAction,
|
|
562
|
+
resolvedAction: resolved.resolvedAction,
|
|
563
|
+
runMode,
|
|
564
|
+
profile: ctx.profile || null,
|
|
565
|
+
skippedPreflight: skipPreflight,
|
|
566
|
+
swapInput: flags.__swapInput || null,
|
|
567
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
568
|
+
},
|
|
569
|
+
});
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
536
572
|
printEnvelope({
|
|
537
573
|
success: normalized.success,
|
|
538
574
|
code: backendResult.code,
|
|
@@ -1194,108 +1230,124 @@ async function commandSelfExec(ctx, flags, capabilities) {
|
|
|
1194
1230
|
process.exit(1);
|
|
1195
1231
|
}
|
|
1196
1232
|
|
|
1197
|
-
const
|
|
1198
|
-
if (!txd?.to || !txd?.data) {
|
|
1199
|
-
printEnvelope({
|
|
1200
|
-
success: false,
|
|
1201
|
-
code: 'SELF_UNSIGNED_TX_MISSING',
|
|
1202
|
-
message: 'Self execution did not return a valid unsigned transaction',
|
|
1203
|
-
data: selfResult || {},
|
|
1204
|
-
meta: {
|
|
1205
|
-
apiBase: ctx.apiBase,
|
|
1206
|
-
runMode: 'self',
|
|
1207
|
-
resolvedAction: resolved.resolvedAction,
|
|
1208
|
-
},
|
|
1209
|
-
});
|
|
1210
|
-
process.exit(1);
|
|
1211
|
-
}
|
|
1233
|
+
const executed = await performSelfBroadcast(ctx, flags, resolved.resolvedAction, selfResult);
|
|
1212
1234
|
|
|
1213
|
-
|
|
1235
|
+
printEnvelope({
|
|
1236
|
+
success: true,
|
|
1237
|
+
code: 'SELF_EXECUTED',
|
|
1238
|
+
message: 'Self-custody execution completed',
|
|
1239
|
+
data: executed,
|
|
1240
|
+
meta: {
|
|
1241
|
+
apiBase: ctx.apiBase,
|
|
1242
|
+
runMode: 'self',
|
|
1243
|
+
resolvedAction: resolved.resolvedAction,
|
|
1244
|
+
swapInput: flags.__swapInput || null,
|
|
1245
|
+
},
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
async function commandDoctorSelf(ctx, flags) {
|
|
1214
1250
|
const walletAddress = String(flags.walletAddress || process.env.MARKET_MAKER_WALLET_ADDRESS || '').trim();
|
|
1215
1251
|
const owsWalletName = String(flags.owsWalletName || process.env.OWS_WALLET_NAME || '').trim();
|
|
1216
|
-
const rpcUrl = String(
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
throw createCliError('SIGNING_FAILED', 'Missing --ows-wallet-name (or OWS_WALLET_NAME) for self-exec signing.');
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
const params = getPreparedParams(flags);
|
|
1225
|
-
const effectTokenIn = String(flags.effectTokenIn || params.tokenIn || '').trim();
|
|
1226
|
-
const effectTokenOut = String(flags.effectTokenOut || params.tokenOut || '').trim();
|
|
1252
|
+
const rpcUrl = String(
|
|
1253
|
+
flags.rpcUrl || process.env.BASE_RPC_URL || process.env.BASE_RPC_HTTP_URL || process.env.RPC_URL || 'https://mainnet.base.org'
|
|
1254
|
+
).trim();
|
|
1255
|
+
const passphrasePresent = Boolean(String(process.env.OWS_PASSPHRASE || process.env.OWS_API_KEY || '').trim());
|
|
1256
|
+
const checks = [];
|
|
1227
1257
|
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1258
|
+
checks.push({
|
|
1259
|
+
name: 'wallet-address',
|
|
1260
|
+
ok: Boolean(walletAddress),
|
|
1261
|
+
detail: walletAddress || 'missing --wallet-address / MARKET_MAKER_WALLET_ADDRESS',
|
|
1262
|
+
});
|
|
1263
|
+
checks.push({
|
|
1264
|
+
name: 'ows-wallet-name',
|
|
1265
|
+
ok: Boolean(owsWalletName),
|
|
1266
|
+
detail: owsWalletName || 'missing --ows-wallet-name / OWS_WALLET_NAME',
|
|
1267
|
+
});
|
|
1268
|
+
checks.push({
|
|
1269
|
+
name: 'ows-passphrase',
|
|
1270
|
+
ok: passphrasePresent,
|
|
1271
|
+
detail: passphrasePresent ? 'present' : 'missing OWS_PASSPHRASE (or OWS_API_KEY fallback)',
|
|
1272
|
+
});
|
|
1232
1273
|
|
|
1233
|
-
let submission;
|
|
1234
1274
|
try {
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
chainId,
|
|
1238
|
-
walletAddress,
|
|
1239
|
-
owsWalletName,
|
|
1240
|
-
rpcUrl,
|
|
1241
|
-
});
|
|
1275
|
+
resolveOwsBinary();
|
|
1276
|
+
checks.push({ name: 'ows-binary', ok: true, detail: 'found' });
|
|
1242
1277
|
} catch (error) {
|
|
1243
|
-
|
|
1278
|
+
checks.push({ name: 'ows-binary', ok: false, detail: error?.message || 'not found' });
|
|
1244
1279
|
}
|
|
1245
1280
|
|
|
1246
|
-
let receipt;
|
|
1247
1281
|
try {
|
|
1248
|
-
|
|
1282
|
+
await loadEthers();
|
|
1283
|
+
checks.push({ name: 'ethers-runtime', ok: true, detail: 'loaded' });
|
|
1249
1284
|
} catch (error) {
|
|
1250
|
-
|
|
1251
|
-
}
|
|
1252
|
-
const status = Number(receipt?.status ?? 0);
|
|
1253
|
-
if (status !== 1) {
|
|
1254
|
-
throw createCliError('BROADCAST_FAILED', 'Transaction receipt status is not success', {
|
|
1255
|
-
receiptStatus: receipt?.status ?? null,
|
|
1256
|
-
txHash: submission.sent.hash,
|
|
1257
|
-
});
|
|
1285
|
+
checks.push({ name: 'ethers-runtime', ok: false, detail: error?.message || 'missing ethers dependency' });
|
|
1258
1286
|
}
|
|
1259
1287
|
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
const
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
checked: true,
|
|
1268
|
-
hasEffect,
|
|
1269
|
-
inDeltaRaw,
|
|
1270
|
-
outDeltaRaw,
|
|
1271
|
-
};
|
|
1272
|
-
if (!hasEffect) {
|
|
1273
|
-
throw createCliError('EFFECT_CHECK_FAILED', 'Transaction mined but did not produce observable token effect.', {
|
|
1274
|
-
txHash: submission.sent.hash,
|
|
1275
|
-
effectCheck,
|
|
1276
|
-
});
|
|
1277
|
-
}
|
|
1288
|
+
try {
|
|
1289
|
+
const ethers = await loadEthers();
|
|
1290
|
+
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
1291
|
+
const block = await provider.getBlockNumber();
|
|
1292
|
+
checks.push({ name: 'rpc-connectivity', ok: Number.isFinite(block), detail: `latestBlock=${block}` });
|
|
1293
|
+
} catch (error) {
|
|
1294
|
+
checks.push({ name: 'rpc-connectivity', ok: false, detail: error?.message || 'rpc check failed' });
|
|
1278
1295
|
}
|
|
1279
1296
|
|
|
1297
|
+
const ok = checks.every((entry) => entry.ok);
|
|
1280
1298
|
printEnvelope({
|
|
1281
|
-
success:
|
|
1282
|
-
code: '
|
|
1283
|
-
message: 'Self
|
|
1299
|
+
success: ok,
|
|
1300
|
+
code: ok ? 'DOCTOR_SELF_OK' : 'DOCTOR_SELF_FAILED',
|
|
1301
|
+
message: ok ? 'Self lane signer diagnostics passed' : 'Self lane signer diagnostics found blocking issues',
|
|
1284
1302
|
data: {
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
effectCheck,
|
|
1303
|
+
checks,
|
|
1304
|
+
hints: [
|
|
1305
|
+
'For one-command self execution use: thirdfy-agent run --run-mode self --broadcast ...',
|
|
1306
|
+
'Set --effect-check strict|relaxed|off to control post-trade effect validation behavior.',
|
|
1307
|
+
],
|
|
1291
1308
|
},
|
|
1292
1309
|
meta: {
|
|
1293
1310
|
apiBase: ctx.apiBase,
|
|
1294
1311
|
runMode: 'self',
|
|
1312
|
+
rpcUrl,
|
|
1313
|
+
},
|
|
1314
|
+
});
|
|
1315
|
+
if (!ok) process.exit(1);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
async function commandManagedRun(ctx, flags, capabilities) {
|
|
1319
|
+
const mode = normalizeManagedRunMode(flags.runMode || 'thirdfy');
|
|
1320
|
+
const managedFlags = { ...flags, runMode: mode };
|
|
1321
|
+
const resolved = await resolveActionSelection(ctx, managedFlags);
|
|
1322
|
+
prepareActionParamsForFlags(managedFlags, resolved.resolvedAction);
|
|
1323
|
+
enforceChainCompatibility(capabilities, managedFlags, mode);
|
|
1324
|
+
const skipPreflight = Boolean(managedFlags.skipPreflight);
|
|
1325
|
+
const backendResult = await runExecutionByMode(mode, ctx, managedFlags, resolved, {
|
|
1326
|
+
skipPreflight,
|
|
1327
|
+
});
|
|
1328
|
+
const normalized = backendResult.normalized;
|
|
1329
|
+
printEnvelope({
|
|
1330
|
+
success: normalized.success,
|
|
1331
|
+
code: normalized.success ? 'MANAGED_RUN_QUEUED' : backendResult.code,
|
|
1332
|
+
message: normalized.success
|
|
1333
|
+
? mode === 'hybrid'
|
|
1334
|
+
? 'Managed easy-wallet hybrid execution prepared'
|
|
1335
|
+
: 'Managed easy-wallet execution queued'
|
|
1336
|
+
: backendResult.message,
|
|
1337
|
+
data: normalized,
|
|
1338
|
+
meta: {
|
|
1339
|
+
apiBase: ctx.apiBase,
|
|
1340
|
+
requestedAction: resolved.requestedAction,
|
|
1295
1341
|
resolvedAction: resolved.resolvedAction,
|
|
1296
|
-
|
|
1342
|
+
lane: 'managed_easy_wallet',
|
|
1343
|
+
runMode: mode,
|
|
1344
|
+
skippedPreflight: skipPreflight,
|
|
1345
|
+
profile: ctx.profile || null,
|
|
1346
|
+
swapInput: managedFlags.__swapInput || null,
|
|
1347
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
1297
1348
|
},
|
|
1298
1349
|
});
|
|
1350
|
+
if (!normalized.success) process.exit(1);
|
|
1299
1351
|
}
|
|
1300
1352
|
|
|
1301
1353
|
async function commandProfileInit(ctx, flags) {
|
|
@@ -1543,6 +1595,14 @@ function normalizeRunMode(value) {
|
|
|
1543
1595
|
throw new Error(`Unsupported --run-mode "${value}". Supported: ${RUN_MODES.join(', ')}`);
|
|
1544
1596
|
}
|
|
1545
1597
|
|
|
1598
|
+
function normalizeManagedRunMode(value) {
|
|
1599
|
+
const mode = normalizeRunMode(value || 'thirdfy');
|
|
1600
|
+
if (mode === 'self') {
|
|
1601
|
+
throw new Error('Managed lane does not support run-mode=self. Use thirdfy or hybrid.');
|
|
1602
|
+
}
|
|
1603
|
+
return mode;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1546
1606
|
function getProfileConfigPath() {
|
|
1547
1607
|
return path.join(os.homedir(), '.thirdfy', 'config.json');
|
|
1548
1608
|
}
|
|
@@ -1651,13 +1711,22 @@ function enforceChainCompatibility(capabilities, flags, runMode) {
|
|
|
1651
1711
|
}
|
|
1652
1712
|
}
|
|
1653
1713
|
|
|
1654
|
-
|
|
1714
|
+
function shouldUseBuildTxPreflight(runMode, resolved) {
|
|
1715
|
+
if (runMode !== 'self') return false;
|
|
1716
|
+
const meta = resolved?.resolvedActionMeta || null;
|
|
1717
|
+
if (!meta || typeof meta !== 'object') return false;
|
|
1718
|
+
return meta.supportsExecuteIntent === false && meta.supportsBuildTx === true;
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
async function runPreflightByMode(runMode, ctx, flags, resolved) {
|
|
1722
|
+
const resolvedAction = resolved.resolvedAction;
|
|
1655
1723
|
if (runMode === 'self') {
|
|
1724
|
+
const route = shouldUseBuildTxPreflight(runMode, resolved) ? 'build_tx' : 'execute_intent_validation';
|
|
1656
1725
|
const normalized = await executeSelfRun(
|
|
1657
1726
|
ctx,
|
|
1658
1727
|
flags,
|
|
1659
1728
|
{ resolvedAction },
|
|
1660
|
-
{ skipPreflight:
|
|
1729
|
+
{ skipPreflight: route === 'build_tx' }
|
|
1661
1730
|
);
|
|
1662
1731
|
const blockedByGovernance = !normalized.success && Boolean(normalized.preflightBlocked);
|
|
1663
1732
|
return {
|
|
@@ -1666,6 +1735,7 @@ async function runPreflightByMode(runMode, ctx, flags, resolvedAction) {
|
|
|
1666
1735
|
: normalized.success
|
|
1667
1736
|
? 'Self preflight completed (unsigned transaction ready)'
|
|
1668
1737
|
: 'Self preflight failed',
|
|
1738
|
+
route,
|
|
1669
1739
|
normalized,
|
|
1670
1740
|
};
|
|
1671
1741
|
}
|
|
@@ -1686,6 +1756,7 @@ async function runPreflightByMode(runMode, ctx, flags, resolvedAction) {
|
|
|
1686
1756
|
: runMode === 'hybrid'
|
|
1687
1757
|
? 'Hybrid mirror preflight failed'
|
|
1688
1758
|
: 'Preflight failed',
|
|
1759
|
+
route: 'execute_intent_validation',
|
|
1689
1760
|
normalized,
|
|
1690
1761
|
};
|
|
1691
1762
|
}
|
|
@@ -1947,18 +2018,19 @@ async function resolveActionSelection(ctx, flags) {
|
|
|
1947
2018
|
.map((action) => ({
|
|
1948
2019
|
key: getActionKey(action),
|
|
1949
2020
|
aliases: getActionAliases(action),
|
|
2021
|
+
action,
|
|
1950
2022
|
}))
|
|
1951
2023
|
.filter((entry) => entry.key);
|
|
1952
2024
|
|
|
1953
2025
|
if (!keyed.length) {
|
|
1954
|
-
return { requestedAction, resolvedAction: requestedAction };
|
|
2026
|
+
return { requestedAction, resolvedAction: requestedAction, resolvedActionMeta: null };
|
|
1955
2027
|
}
|
|
1956
2028
|
|
|
1957
2029
|
// Prefer direct action id matches over alias matches.
|
|
1958
2030
|
// This keeps UX simple for commands like `--action swap` when another action aliases to "swap".
|
|
1959
2031
|
const exactKey = keyed.filter((entry) => entry.key.toLowerCase() === requestedLower);
|
|
1960
2032
|
if (exactKey.length === 1) {
|
|
1961
|
-
return { requestedAction, resolvedAction: exactKey[0].key };
|
|
2033
|
+
return { requestedAction, resolvedAction: exactKey[0].key, resolvedActionMeta: exactKey[0].action || null };
|
|
1962
2034
|
}
|
|
1963
2035
|
if (exactKey.length > 1) {
|
|
1964
2036
|
throw new Error(
|
|
@@ -1970,7 +2042,7 @@ async function resolveActionSelection(ctx, flags) {
|
|
|
1970
2042
|
|
|
1971
2043
|
const exactAlias = keyed.filter((entry) => entry.aliases.some((a) => a.toLowerCase() === requestedLower));
|
|
1972
2044
|
if (exactAlias.length === 1) {
|
|
1973
|
-
return { requestedAction, resolvedAction: exactAlias[0].key };
|
|
2045
|
+
return { requestedAction, resolvedAction: exactAlias[0].key, resolvedActionMeta: exactAlias[0].action || null };
|
|
1974
2046
|
}
|
|
1975
2047
|
if (exactAlias.length > 1) {
|
|
1976
2048
|
throw new Error(
|
|
@@ -1986,7 +2058,7 @@ async function resolveActionSelection(ctx, flags) {
|
|
|
1986
2058
|
entry.aliases.some((a) => a.toLowerCase().includes(requestedLower))
|
|
1987
2059
|
);
|
|
1988
2060
|
if (fuzzy.length === 1) {
|
|
1989
|
-
return { requestedAction, resolvedAction: fuzzy[0].key };
|
|
2061
|
+
return { requestedAction, resolvedAction: fuzzy[0].key, resolvedActionMeta: fuzzy[0].action || null };
|
|
1990
2062
|
}
|
|
1991
2063
|
if (fuzzy.length > 1) {
|
|
1992
2064
|
throw new Error(
|
|
@@ -2048,6 +2120,171 @@ function resolveUnsignedTx(result) {
|
|
|
2048
2120
|
return null;
|
|
2049
2121
|
}
|
|
2050
2122
|
|
|
2123
|
+
function parseBooleanFlag(value, defaultValue = false) {
|
|
2124
|
+
if (value === undefined || value === null) return defaultValue;
|
|
2125
|
+
if (typeof value === 'boolean') return value;
|
|
2126
|
+
const normalized = String(value).trim().toLowerCase();
|
|
2127
|
+
if (!normalized) return defaultValue;
|
|
2128
|
+
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
|
|
2129
|
+
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
|
|
2130
|
+
return defaultValue;
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
function normalizeEffectCheckMode(value) {
|
|
2134
|
+
const normalized = String(value || '').trim().toLowerCase();
|
|
2135
|
+
if (!normalized) return 'relaxed';
|
|
2136
|
+
if (EFFECT_CHECK_MODES.includes(normalized)) return normalized;
|
|
2137
|
+
throw createCliError(
|
|
2138
|
+
'EFFECT_CHECK_MODE_INVALID',
|
|
2139
|
+
`Unsupported --effect-check "${value}". Supported: ${EFFECT_CHECK_MODES.join(', ')}.`
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
async function sleepMs(ms) {
|
|
2144
|
+
const delay = Number(ms || 0);
|
|
2145
|
+
if (!Number.isFinite(delay) || delay <= 0) return;
|
|
2146
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
async function resolveEffectCheckResult({
|
|
2150
|
+
mode,
|
|
2151
|
+
rpcUrl,
|
|
2152
|
+
walletAddress,
|
|
2153
|
+
tokenIn,
|
|
2154
|
+
tokenOut,
|
|
2155
|
+
balancesBefore,
|
|
2156
|
+
retries,
|
|
2157
|
+
waitMs,
|
|
2158
|
+
}) {
|
|
2159
|
+
const baseResult = {
|
|
2160
|
+
checked: true,
|
|
2161
|
+
mode,
|
|
2162
|
+
hasEffect: false,
|
|
2163
|
+
inDeltaRaw: '0',
|
|
2164
|
+
outDeltaRaw: '0',
|
|
2165
|
+
attempts: 0,
|
|
2166
|
+
retries: Math.max(0, Number(retries || 0)),
|
|
2167
|
+
};
|
|
2168
|
+
if (mode === 'off') {
|
|
2169
|
+
return { checked: false, mode, hasEffect: null, inDeltaRaw: null, outDeltaRaw: null, reason: 'disabled' };
|
|
2170
|
+
}
|
|
2171
|
+
if (!tokenIn || !tokenOut || !balancesBefore) {
|
|
2172
|
+
return { checked: false, mode, hasEffect: null, inDeltaRaw: null, outDeltaRaw: null, reason: 'token_pair_missing' };
|
|
2173
|
+
}
|
|
2174
|
+
const maxAttempts = Math.max(1, Number(retries || 0) + 1);
|
|
2175
|
+
let last = null;
|
|
2176
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
2177
|
+
const balancesAfter = await readEffectBalances(rpcUrl, walletAddress, tokenIn, tokenOut);
|
|
2178
|
+
const inDeltaRaw = (BigInt(balancesBefore.tokenIn) - BigInt(balancesAfter.tokenIn)).toString();
|
|
2179
|
+
const outDeltaRaw = (BigInt(balancesAfter.tokenOut) - BigInt(balancesBefore.tokenOut)).toString();
|
|
2180
|
+
const hasEffect = BigInt(inDeltaRaw) > 0n || BigInt(outDeltaRaw) > 0n;
|
|
2181
|
+
last = {
|
|
2182
|
+
checked: true,
|
|
2183
|
+
mode,
|
|
2184
|
+
hasEffect,
|
|
2185
|
+
inDeltaRaw,
|
|
2186
|
+
outDeltaRaw,
|
|
2187
|
+
attempts: attempt,
|
|
2188
|
+
retries: maxAttempts - 1,
|
|
2189
|
+
};
|
|
2190
|
+
if (hasEffect) return last;
|
|
2191
|
+
if (attempt < maxAttempts) await sleepMs(waitMs);
|
|
2192
|
+
}
|
|
2193
|
+
return {
|
|
2194
|
+
...(last || baseResult),
|
|
2195
|
+
warning: 'No balance delta observed after retries; treating as non-fatal in relaxed mode.',
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
async function performSelfBroadcast(ctx, flags, resolvedAction, selfResult) {
|
|
2200
|
+
const txd = resolveUnsignedTx(selfResult);
|
|
2201
|
+
if (!txd?.to || !txd?.data) {
|
|
2202
|
+
throw createCliError('SELF_UNSIGNED_TX_MISSING', 'Self execution did not return a valid unsigned transaction');
|
|
2203
|
+
}
|
|
2204
|
+
const chainId = Number(txd.chainId || flags.chainId || 8453);
|
|
2205
|
+
const walletAddress = String(flags.walletAddress || process.env.MARKET_MAKER_WALLET_ADDRESS || '').trim();
|
|
2206
|
+
const owsWalletName = String(flags.owsWalletName || process.env.OWS_WALLET_NAME || '').trim();
|
|
2207
|
+
const rpcUrl = String(
|
|
2208
|
+
flags.rpcUrl || process.env.BASE_RPC_URL || process.env.BASE_RPC_HTTP_URL || process.env.RPC_URL || 'https://mainnet.base.org'
|
|
2209
|
+
).trim();
|
|
2210
|
+
if (!walletAddress) {
|
|
2211
|
+
throw createCliError('SIGNING_FAILED', 'Missing --wallet-address (or MARKET_MAKER_WALLET_ADDRESS) for self-exec signing.');
|
|
2212
|
+
}
|
|
2213
|
+
if (!owsWalletName) {
|
|
2214
|
+
throw createCliError('SIGNING_FAILED', 'Missing --ows-wallet-name (or OWS_WALLET_NAME) for self-exec signing.');
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
const params = getPreparedParams(flags);
|
|
2218
|
+
const effectTokenIn = String(flags.effectTokenIn || params.tokenIn || '').trim();
|
|
2219
|
+
const effectTokenOut = String(flags.effectTokenOut || params.tokenOut || '').trim();
|
|
2220
|
+
const effectMode = normalizeEffectCheckMode(flags.effectCheck || process.env.THIRDFY_EFFECT_CHECK || 'relaxed');
|
|
2221
|
+
const effectRetries = Number(flags.effectCheckRetries || process.env.THIRDFY_EFFECT_CHECK_RETRIES || 2);
|
|
2222
|
+
const effectWaitMs = Number(flags.effectCheckWaitMs || process.env.THIRDFY_EFFECT_CHECK_WAIT_MS || 1200);
|
|
2223
|
+
|
|
2224
|
+
let balancesBefore = null;
|
|
2225
|
+
if (effectMode !== 'off' && effectTokenIn && effectTokenOut) {
|
|
2226
|
+
balancesBefore = await readEffectBalances(rpcUrl, walletAddress, effectTokenIn, effectTokenOut);
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
let submission;
|
|
2230
|
+
try {
|
|
2231
|
+
submission = await signAndBroadcastWithOws({
|
|
2232
|
+
txd,
|
|
2233
|
+
chainId,
|
|
2234
|
+
walletAddress,
|
|
2235
|
+
owsWalletName,
|
|
2236
|
+
rpcUrl,
|
|
2237
|
+
});
|
|
2238
|
+
} catch (error) {
|
|
2239
|
+
throw createCliError('SIGNING_FAILED', error?.message || 'OWS signing failed');
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
let receipt;
|
|
2243
|
+
try {
|
|
2244
|
+
receipt = await submission.sent.wait();
|
|
2245
|
+
} catch (error) {
|
|
2246
|
+
throw createCliError('BROADCAST_FAILED', error?.message || 'Broadcast wait failed');
|
|
2247
|
+
}
|
|
2248
|
+
const status = Number(receipt?.status ?? 0);
|
|
2249
|
+
if (status !== 1) {
|
|
2250
|
+
throw createCliError('BROADCAST_FAILED', 'Transaction receipt status is not success', {
|
|
2251
|
+
receiptStatus: receipt?.status ?? null,
|
|
2252
|
+
txHash: submission.sent.hash,
|
|
2253
|
+
});
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
const effectCheck = await resolveEffectCheckResult({
|
|
2257
|
+
mode: effectMode,
|
|
2258
|
+
rpcUrl,
|
|
2259
|
+
walletAddress,
|
|
2260
|
+
tokenIn: effectTokenIn,
|
|
2261
|
+
tokenOut: effectTokenOut,
|
|
2262
|
+
balancesBefore,
|
|
2263
|
+
retries: effectRetries,
|
|
2264
|
+
waitMs: effectWaitMs,
|
|
2265
|
+
});
|
|
2266
|
+
if (effectCheck.checked && !effectCheck.hasEffect && effectMode === 'strict') {
|
|
2267
|
+
throw createCliError('EFFECT_CHECK_FAILED', 'Transaction mined but did not produce observable token effect.', {
|
|
2268
|
+
txHash: submission.sent.hash,
|
|
2269
|
+
effectCheck,
|
|
2270
|
+
mode: effectMode,
|
|
2271
|
+
});
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
return {
|
|
2275
|
+
txHash: submission.sent.hash,
|
|
2276
|
+
chainId,
|
|
2277
|
+
blockNumber: receipt?.blockNumber ?? null,
|
|
2278
|
+
status: receipt?.status ?? null,
|
|
2279
|
+
unsignedTx: txd,
|
|
2280
|
+
effectCheck,
|
|
2281
|
+
lane: 'self',
|
|
2282
|
+
signer: 'ows',
|
|
2283
|
+
resolvedAction,
|
|
2284
|
+
apiBase: ctx.apiBase,
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2051
2288
|
async function loadEthers() {
|
|
2052
2289
|
const candidates = ['ethers', path.join(process.cwd(), 'node_modules', 'ethers')];
|
|
2053
2290
|
for (const candidate of candidates) {
|
|
@@ -2242,8 +2479,8 @@ Core commands:
|
|
|
2242
2479
|
thirdfy-agent catalogs list [--json]
|
|
2243
2480
|
thirdfy-agent actions [--catalog <id>] [--provider <id>] [--agent-api-key <key>] [--chain-id <id>] [--run-mode <mode>] [--json]
|
|
2244
2481
|
thirdfy-agent delegation create --auth-token <token> --agent-key <key> --owner-address <addr> --token-address <addr> --max-usd-per-day <usd> [--session-account-address <addr>] [--json]
|
|
2245
|
-
thirdfy-agent delegation init-custodial --auth-token <token> [--chain-id <id>] [--json]
|
|
2246
|
-
thirdfy-agent delegation custodial-grant --auth-token <token> --agent-key <key> --token-address <addr> --max-usd-per-day <usd> [--chain-id <id>] [--period-duration <sec>] [--expiry-seconds <sec>] [--json]
|
|
2482
|
+
thirdfy-agent delegation init-custodial [--auth-token <token> | --owner-session-token <token>] [--chain-id <id>] [--json]
|
|
2483
|
+
thirdfy-agent delegation custodial-grant [--auth-token <token> | --owner-session-token <token>] --agent-key <key> --token-address <addr> --max-usd-per-day <usd> [--chain-id <id>] [--period-duration <sec>] [--expiry-seconds <sec>] [--json]
|
|
2247
2484
|
thirdfy-agent delegation activate --auth-token <token> --agent-key <key> --wallet-address <addr> --session-account-address <addr> --delegation-manager <addr> --delegation <json> --signature <hex> [--json]
|
|
2248
2485
|
thirdfy-agent delegation status --auth-token <token> --agent-key <key> [--verify] [--json]
|
|
2249
2486
|
thirdfy-agent delegation show --auth-token <token> --agent-key <key> [--verify] [--json]
|
|
@@ -2251,6 +2488,9 @@ Core commands:
|
|
|
2251
2488
|
thirdfy-agent delegation balance --auth-token <token> --agent-key <key> [--chain-id <id>] [--json]
|
|
2252
2489
|
thirdfy-agent delegation revoke --auth-token <token> --agent-key <key> [--reason <text>] [--chain-id <id>] [--json]
|
|
2253
2490
|
thirdfy-agent delegation redeem --agent-api-key <key> --action <id> --params <json> [--run-mode thirdfy|hybrid] [--estimated-amount-usd <usd>] [--json]
|
|
2491
|
+
thirdfy-agent managed wallet init [--auth-token <token> | --owner-session-token <token>] [--chain-id <id>] [--json]
|
|
2492
|
+
thirdfy-agent managed wallet grant [--auth-token <token> | --owner-session-token <token>] --agent-key <key> --token-address <addr> --max-usd-per-day <usd> [--chain-id <id>] [--period-duration <sec>] [--expiry-seconds <sec>] [--json]
|
|
2493
|
+
thirdfy-agent managed run --agent-api-key <key> --action <id> --params <json> [--run-mode thirdfy|hybrid] [--idempotency-key <key>] [--json]
|
|
2254
2494
|
thirdfy-agent credentials upsert --auth-token <token> --venue <id> --api-key <key> --api-secret <secret> [--json]
|
|
2255
2495
|
thirdfy-agent credentials status --auth-token <token> [--venue <id>] [--json]
|
|
2256
2496
|
thirdfy-agent agent auth challenge --agent-key <key> [--wallet-address <addr>] [--chain-id <id>] [--json]
|
|
@@ -2260,8 +2500,9 @@ Core commands:
|
|
|
2260
2500
|
thirdfy-agent agent key rotate [--agent-key <key>] [--auth-token <token> | --owner-session-token <token>] [--json]
|
|
2261
2501
|
thirdfy-agent agent key revoke [--agent-key <key>] [--auth-token <token> | --owner-session-token <token>] [--json]
|
|
2262
2502
|
thirdfy-agent preflight --agent-api-key <key> --action <id> --params <json> [--run-mode <mode>] [--json]
|
|
2263
|
-
thirdfy-agent run --agent-api-key <key> --action <id> --params <json> [--run-mode <mode>] [--idempotency-key <key>] [--json]
|
|
2264
|
-
thirdfy-agent self-exec --agent-api-key <key> --action <id> --params <json> --wallet-address <addr> --ows-wallet-name <name> [--rpc-url <url>] [--json]
|
|
2503
|
+
thirdfy-agent run --agent-api-key <key> --action <id> --params <json> [--run-mode <mode>] [--broadcast] [--idempotency-key <key>] [--json]
|
|
2504
|
+
thirdfy-agent self-exec --agent-api-key <key> --action <id> --params <json> --wallet-address <addr> --ows-wallet-name <name> [--rpc-url <url>] [--effect-check strict|relaxed|off] [--json]
|
|
2505
|
+
thirdfy-agent doctor self [--wallet-address <addr>] [--ows-wallet-name <name>] [--rpc-url <url>] [--json]
|
|
2265
2506
|
thirdfy-agent jeff preflight --agent-api-key <key> --action <id> --params <json> [--run-mode <mode>] [--json]
|
|
2266
2507
|
thirdfy-agent jeff trade --agent-api-key <key> --action <id> --params <json> [--run-mode <mode>] [--json]
|
|
2267
2508
|
thirdfy-agent jeff status --intent-id <id> [--json]
|
|
@@ -2276,6 +2517,8 @@ Global flags:
|
|
|
2276
2517
|
--env <file> load env vars from file
|
|
2277
2518
|
--timeout <ms> request timeout
|
|
2278
2519
|
--params <json> for swap: exactly one of {amountInRaw} or {amountInHuman + tokenInDecimals}
|
|
2520
|
+
--broadcast with run --run-mode self, sign and broadcast using OWS
|
|
2521
|
+
--effect-check <mode> self-exec check mode: strict | relaxed | off (default: relaxed)
|
|
2279
2522
|
--owner-session-token <token> owner session token (or THIRDFY_OWNER_SESSION_TOKEN)
|
|
2280
2523
|
--json stable machine-readable output
|
|
2281
2524
|
--verbose print adapter diagnostics
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thirdfy/agent-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Thirdfy Agent CLI for onboarding, governance preflight, execute-intent, and status polling.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"src/contracts/cli/schemas/",
|
|
13
13
|
"scripts/validate-cli-contract-schemas.mjs",
|
|
14
14
|
"README.md",
|
|
15
|
+
"CHANGELOG.md",
|
|
15
16
|
"LICENSE"
|
|
16
17
|
],
|
|
17
18
|
"scripts": {
|
|
@@ -25,6 +26,7 @@
|
|
|
25
26
|
"e2e:delegation:lifecycle": "node ./scripts/e2e/delegation-lifecycle.mjs",
|
|
26
27
|
"e2e:delegation:commands": "node ./scripts/e2e/delegation-command-parity.mjs",
|
|
27
28
|
"e2e:self:delegation:parity": "node ./scripts/e2e/self-delegation-parity.mjs",
|
|
29
|
+
"e2e:managed:delegation:parity": "node ./scripts/e2e/managed-custodial-lifecycle.mjs",
|
|
28
30
|
"e2e:delegation:prod:certify": "node ./scripts/e2e/prod-delegation-certify.mjs",
|
|
29
31
|
"e2e:report:last": "node ./scripts/e2e/report-last.mjs",
|
|
30
32
|
"smoke:cli": "node ./bin/thirdfy-agent.mjs --help && node ./bin/thirdfy-agent.mjs --version --json",
|
|
@@ -48,5 +50,8 @@
|
|
|
48
50
|
"bugs": {
|
|
49
51
|
"url": "https://github.com/thirdfy/agent-cli/issues"
|
|
50
52
|
},
|
|
51
|
-
"homepage": "https://github.com/thirdfy/agent-cli#readme"
|
|
53
|
+
"homepage": "https://github.com/thirdfy/agent-cli#readme",
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"ethers": "^6.16.0"
|
|
56
|
+
}
|
|
52
57
|
}
|