@thirdfy/agent-cli 0.1.8 → 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 +4 -0
- package/README.md +16 -0
- package/bin/thirdfy-agent.mjs +20 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,10 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
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
|
+
|
|
7
11
|
## [0.1.8] - 2026-04-07
|
|
8
12
|
|
|
9
13
|
**npm:** [`@thirdfy/agent-cli@0.1.8`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.8)
|
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`.
|
package/bin/thirdfy-agent.mjs
CHANGED
|
@@ -517,7 +517,7 @@ async function commandPreflight(ctx, flags, capabilities) {
|
|
|
517
517
|
prepareActionParamsForFlags(flags, resolved.resolvedAction);
|
|
518
518
|
const runMode = getEffectiveRunMode(ctx, flags);
|
|
519
519
|
enforceChainCompatibility(capabilities, flags, runMode);
|
|
520
|
-
const backendResult = await runPreflightByMode(runMode, ctx, flags, resolved
|
|
520
|
+
const backendResult = await runPreflightByMode(runMode, ctx, flags, resolved);
|
|
521
521
|
const normalized = backendResult.normalized;
|
|
522
522
|
printEnvelope({
|
|
523
523
|
success: normalized.success,
|
|
@@ -529,6 +529,7 @@ async function commandPreflight(ctx, flags, capabilities) {
|
|
|
529
529
|
catalog: flags.catalog || null,
|
|
530
530
|
requestedAction: resolved.requestedAction,
|
|
531
531
|
resolvedAction: resolved.resolvedAction,
|
|
532
|
+
preflightRoute: backendResult.route,
|
|
532
533
|
runMode,
|
|
533
534
|
profile: ctx.profile || null,
|
|
534
535
|
swapInput: flags.__swapInput || null,
|
|
@@ -1710,13 +1711,22 @@ function enforceChainCompatibility(capabilities, flags, runMode) {
|
|
|
1710
1711
|
}
|
|
1711
1712
|
}
|
|
1712
1713
|
|
|
1713
|
-
|
|
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;
|
|
1714
1723
|
if (runMode === 'self') {
|
|
1724
|
+
const route = shouldUseBuildTxPreflight(runMode, resolved) ? 'build_tx' : 'execute_intent_validation';
|
|
1715
1725
|
const normalized = await executeSelfRun(
|
|
1716
1726
|
ctx,
|
|
1717
1727
|
flags,
|
|
1718
1728
|
{ resolvedAction },
|
|
1719
|
-
{ skipPreflight:
|
|
1729
|
+
{ skipPreflight: route === 'build_tx' }
|
|
1720
1730
|
);
|
|
1721
1731
|
const blockedByGovernance = !normalized.success && Boolean(normalized.preflightBlocked);
|
|
1722
1732
|
return {
|
|
@@ -1725,6 +1735,7 @@ async function runPreflightByMode(runMode, ctx, flags, resolvedAction) {
|
|
|
1725
1735
|
: normalized.success
|
|
1726
1736
|
? 'Self preflight completed (unsigned transaction ready)'
|
|
1727
1737
|
: 'Self preflight failed',
|
|
1738
|
+
route,
|
|
1728
1739
|
normalized,
|
|
1729
1740
|
};
|
|
1730
1741
|
}
|
|
@@ -1745,6 +1756,7 @@ async function runPreflightByMode(runMode, ctx, flags, resolvedAction) {
|
|
|
1745
1756
|
: runMode === 'hybrid'
|
|
1746
1757
|
? 'Hybrid mirror preflight failed'
|
|
1747
1758
|
: 'Preflight failed',
|
|
1759
|
+
route: 'execute_intent_validation',
|
|
1748
1760
|
normalized,
|
|
1749
1761
|
};
|
|
1750
1762
|
}
|
|
@@ -2006,18 +2018,19 @@ async function resolveActionSelection(ctx, flags) {
|
|
|
2006
2018
|
.map((action) => ({
|
|
2007
2019
|
key: getActionKey(action),
|
|
2008
2020
|
aliases: getActionAliases(action),
|
|
2021
|
+
action,
|
|
2009
2022
|
}))
|
|
2010
2023
|
.filter((entry) => entry.key);
|
|
2011
2024
|
|
|
2012
2025
|
if (!keyed.length) {
|
|
2013
|
-
return { requestedAction, resolvedAction: requestedAction };
|
|
2026
|
+
return { requestedAction, resolvedAction: requestedAction, resolvedActionMeta: null };
|
|
2014
2027
|
}
|
|
2015
2028
|
|
|
2016
2029
|
// Prefer direct action id matches over alias matches.
|
|
2017
2030
|
// This keeps UX simple for commands like `--action swap` when another action aliases to "swap".
|
|
2018
2031
|
const exactKey = keyed.filter((entry) => entry.key.toLowerCase() === requestedLower);
|
|
2019
2032
|
if (exactKey.length === 1) {
|
|
2020
|
-
return { requestedAction, resolvedAction: exactKey[0].key };
|
|
2033
|
+
return { requestedAction, resolvedAction: exactKey[0].key, resolvedActionMeta: exactKey[0].action || null };
|
|
2021
2034
|
}
|
|
2022
2035
|
if (exactKey.length > 1) {
|
|
2023
2036
|
throw new Error(
|
|
@@ -2029,7 +2042,7 @@ async function resolveActionSelection(ctx, flags) {
|
|
|
2029
2042
|
|
|
2030
2043
|
const exactAlias = keyed.filter((entry) => entry.aliases.some((a) => a.toLowerCase() === requestedLower));
|
|
2031
2044
|
if (exactAlias.length === 1) {
|
|
2032
|
-
return { requestedAction, resolvedAction: exactAlias[0].key };
|
|
2045
|
+
return { requestedAction, resolvedAction: exactAlias[0].key, resolvedActionMeta: exactAlias[0].action || null };
|
|
2033
2046
|
}
|
|
2034
2047
|
if (exactAlias.length > 1) {
|
|
2035
2048
|
throw new Error(
|
|
@@ -2045,7 +2058,7 @@ async function resolveActionSelection(ctx, flags) {
|
|
|
2045
2058
|
entry.aliases.some((a) => a.toLowerCase().includes(requestedLower))
|
|
2046
2059
|
);
|
|
2047
2060
|
if (fuzzy.length === 1) {
|
|
2048
|
-
return { requestedAction, resolvedAction: fuzzy[0].key };
|
|
2061
|
+
return { requestedAction, resolvedAction: fuzzy[0].key, resolvedActionMeta: fuzzy[0].action || null };
|
|
2049
2062
|
}
|
|
2050
2063
|
if (fuzzy.length > 1) {
|
|
2051
2064
|
throw new Error(
|