@thirdfy/agent-cli 0.2.39 → 0.2.40
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
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.2.40] - 2026-07-27
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- EarnClaw runtime Polymarket write gate: when `EARNCLAW_RUNTIME_ID` or `THIRDFY_EXECUTION_RUNTIME_ID` is set, `place_polymarket_order` / `place_prediction_order` require `idempotencyKey` starting with `earnclaw:<runtimeId>`. Blocks bare CLI/dashboard tool buys on managed Hermes machines. MCP parity in `thirdfy-mcp` **0.0.83**.
|
|
12
|
+
|
|
7
13
|
## [0.2.39] - 2026-07-27
|
|
8
14
|
|
|
9
15
|
### Changed
|
package/README.md
CHANGED
|
@@ -40,13 +40,11 @@ Run without global install:
|
|
|
40
40
|
npx @thirdfy/agent-cli --help
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
## What's new in v0.2.
|
|
43
|
+
## What's new in v0.2.40
|
|
44
|
+
- EarnClaw machines: Polymarket place orders require an `earnclaw:<runtimeId>…` idempotency key (blocks ad-hoc CLI/dashboard buys).
|
|
45
|
+
- Pack execute-gate and operator exits already set this key; bare tool writes fail closed.
|
|
46
|
+
- See [CHANGELOG.md](./CHANGELOG.md) for older versions.
|
|
44
47
|
|
|
45
|
-
- Morpho hints: Base MetaMorpho V1 writes on `8453`; Robinhood Vault V2 on `4663` is discoverable read-only until `maxDeposit > 0`. Prefer `depositPlan` from `get_earn_opportunities`.
|
|
46
|
-
- Updated [`docs/providers/earn-morpho.md`](./docs/providers/earn-morpho.md) for GraphQL discovery and V1 vs V2 behavior.
|
|
47
|
-
- Pairs with `thirdfy-mcp` **0.0.82** and Thirdfy API develop (Morpho GraphQL integration).
|
|
48
|
-
|
|
49
|
-
Older versions: see [CHANGELOG.md](./CHANGELOG.md) and [GitHub Releases](https://github.com/thirdfy/agent-cli/releases).
|
|
50
48
|
|
|
51
49
|
## Quick start
|
|
52
50
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createCliError } from '../../core/envelope.mjs';
|
|
2
|
+
|
|
3
|
+
function readUuid(value) {
|
|
4
|
+
const trimmed = String(value || '').trim();
|
|
5
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(trimmed)
|
|
6
|
+
? trimmed
|
|
7
|
+
: undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const POLYMARKET_PLACE_ACTIONS = new Set([
|
|
11
|
+
'place_polymarket_order',
|
|
12
|
+
'place-polymarket-order',
|
|
13
|
+
'place_prediction_order',
|
|
14
|
+
'place-prediction-order',
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
export function resolveEarnclawRuntimeId(env = process.env) {
|
|
18
|
+
const runtimeId = readUuid(env.THIRDFY_EXECUTION_RUNTIME_ID)
|
|
19
|
+
|| readUuid(env.EARNCLAW_RUNTIME_ID);
|
|
20
|
+
return runtimeId ? runtimeId.toLowerCase() : '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function normalizePolymarketPlaceAction(action) {
|
|
24
|
+
return String(action || '')
|
|
25
|
+
.trim()
|
|
26
|
+
.toLowerCase()
|
|
27
|
+
.replace(/_/g, '-');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function isPolymarketPlaceAction(action) {
|
|
31
|
+
const key = String(action || '').trim().toLowerCase();
|
|
32
|
+
if (POLYMARKET_PLACE_ACTIONS.has(key)) return true;
|
|
33
|
+
return normalizePolymarketPlaceAction(key) === 'place-polymarket-order'
|
|
34
|
+
|| normalizePolymarketPlaceAction(key) === 'place-prediction-order';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* On EarnClaw-managed Hermes machines, ad-hoc CLI/MCP/dashboard tool calls can
|
|
39
|
+
* place Polymarket orders without pack execute-gate. Require an earnclaw-scoped
|
|
40
|
+
* idempotency key so only adapter/operator keys pass.
|
|
41
|
+
*/
|
|
42
|
+
export function assertEarnclawPolymarketWriteIdempotency({
|
|
43
|
+
action,
|
|
44
|
+
idempotencyKey,
|
|
45
|
+
paramsIdempotencyKey,
|
|
46
|
+
env = process.env,
|
|
47
|
+
} = {}) {
|
|
48
|
+
if (!isPolymarketPlaceAction(action)) return null;
|
|
49
|
+
const runtimeId = resolveEarnclawRuntimeId(env);
|
|
50
|
+
if (!runtimeId) return null;
|
|
51
|
+
|
|
52
|
+
const prefix = `earnclaw:${runtimeId}`;
|
|
53
|
+
const keys = [idempotencyKey, paramsIdempotencyKey]
|
|
54
|
+
.map((key) => String(key || '').trim())
|
|
55
|
+
.filter(Boolean);
|
|
56
|
+
if (keys.some((key) => key.toLowerCase().startsWith(prefix))) return null;
|
|
57
|
+
|
|
58
|
+
throw createCliError(
|
|
59
|
+
'EARNCLAW_PM_IDEMPOTENCY_REQUIRED',
|
|
60
|
+
`EarnClaw runtime ${runtimeId} requires Polymarket place orders to use idempotencyKey starting with "${prefix}". ` +
|
|
61
|
+
'Pack execute-gate and operator exits set this automatically. Bare CLI/dashboard tool writes are blocked.',
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -3,6 +3,7 @@ import { requireFlag, parseJsonFlag } from '../../core/args.mjs';
|
|
|
3
3
|
import { loadProfileConfig } from '../../core/context.mjs';
|
|
4
4
|
import { createCliError } from '../../core/envelope.mjs';
|
|
5
5
|
import { normalizeRunMode, normalizeManagedRunMode, normalizeHybridWalletMode } from '../../core/runMode.mjs';
|
|
6
|
+
import { assertEarnclawPolymarketWriteIdempotency } from './earnclawRuntimeWriteGate.mjs';
|
|
6
7
|
export function createExecutionPayloads({ getPreparedParams, rawUnitsToDecimalString }) {
|
|
7
8
|
function buildBuildTxPayload(flags, resolvedAction) {
|
|
8
9
|
const runMode = String(flags.runMode || '').trim().toLowerCase() || 'self';
|
|
@@ -125,6 +126,11 @@ function buildManagedExecutePayload(flags, options) {
|
|
|
125
126
|
} else if (flags.idempotencyKey) {
|
|
126
127
|
payload.executionIdempotencyKey = String(flags.idempotencyKey);
|
|
127
128
|
}
|
|
129
|
+
assertEarnclawPolymarketWriteIdempotency({
|
|
130
|
+
action: payload.action,
|
|
131
|
+
idempotencyKey: payload.executionIdempotencyKey,
|
|
132
|
+
paramsIdempotencyKey: managedParams?.idempotencyKey,
|
|
133
|
+
});
|
|
128
134
|
return payload;
|
|
129
135
|
}
|
|
130
136
|
|
|
@@ -171,6 +177,13 @@ function buildIntentPayload(flags, options) {
|
|
|
171
177
|
} else if (flags.idempotencyKey) {
|
|
172
178
|
payload.idempotencyKey = String(flags.idempotencyKey);
|
|
173
179
|
}
|
|
180
|
+
if (!options.validationOnly) {
|
|
181
|
+
assertEarnclawPolymarketWriteIdempotency({
|
|
182
|
+
action: payload.action,
|
|
183
|
+
idempotencyKey: payload.idempotencyKey,
|
|
184
|
+
paramsIdempotencyKey: payload.params?.idempotencyKey,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
174
187
|
return payload;
|
|
175
188
|
}
|
|
176
189
|
|