@reppo/cli 0.4.0 → 0.6.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.
- package/README.md +6 -2
- package/dist/api/agents.d.ts +45 -0
- package/dist/api/agents.d.ts.map +1 -0
- package/dist/api/agents.js +115 -0
- package/dist/api/agents.js.map +1 -0
- package/dist/bin.js +3 -1
- package/dist/bin.js.map +1 -1
- package/dist/chain/receipt.d.ts +14 -0
- package/dist/chain/receipt.d.ts.map +1 -0
- package/dist/chain/receipt.js +14 -0
- package/dist/chain/receipt.js.map +1 -0
- package/dist/commands/approve.d.ts +12 -0
- package/dist/commands/approve.d.ts.map +1 -0
- package/dist/commands/approve.js +224 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/claim-emissions.d.ts.map +1 -1
- package/dist/commands/claim-emissions.js +27 -6
- package/dist/commands/claim-emissions.js.map +1 -1
- package/dist/commands/extend-lock.d.ts.map +1 -1
- package/dist/commands/extend-lock.js +46 -6
- package/dist/commands/extend-lock.js.map +1 -1
- package/dist/commands/grant-access.d.ts.map +1 -1
- package/dist/commands/grant-access.js +38 -6
- package/dist/commands/grant-access.js.map +1 -1
- package/dist/commands/lock.d.ts.map +1 -1
- package/dist/commands/lock.js +43 -6
- package/dist/commands/lock.js.map +1 -1
- package/dist/commands/mint-pod.d.ts +25 -0
- package/dist/commands/mint-pod.d.ts.map +1 -1
- package/dist/commands/mint-pod.js +234 -11
- package/dist/commands/mint-pod.js.map +1 -1
- package/dist/commands/unlock.d.ts.map +1 -1
- package/dist/commands/unlock.js +39 -6
- package/dist/commands/unlock.js.map +1 -1
- package/dist/commands/vote.d.ts.map +1 -1
- package/dist/commands/vote.js +35 -6
- package/dist/commands/vote.js.map +1 -1
- package/dist/commands/write-cache.d.ts +20 -0
- package/dist/commands/write-cache.d.ts.map +1 -0
- package/dist/commands/write-cache.js +52 -0
- package/dist/commands/write-cache.js.map +1 -0
- package/dist/config/load.d.ts +11 -0
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +3 -0
- package/dist/config/load.js.map +1 -1
- package/dist/state/idempotency.d.ts +2 -1
- package/dist/state/idempotency.d.ts.map +1 -1
- package/dist/state/idempotency.js +29 -8
- package/dist/state/idempotency.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { TransactionReceiptNotFoundError } from 'viem';
|
|
2
|
+
import { markConfirmed, markFailed } from '../state/idempotency.js';
|
|
3
|
+
import { cliError, emit } from '../output/format.js';
|
|
4
|
+
export function basescanTxUrl(network, tx) {
|
|
5
|
+
return network === 'mainnet'
|
|
6
|
+
? `https://basescan.org/tx/${tx}`
|
|
7
|
+
: `https://sepolia.basescan.org/tx/${tx}`;
|
|
8
|
+
}
|
|
9
|
+
export async function reconcileSubmittedCache(publicClient, network, key, command, args, txHash, buildResult, submittedResult = {}) {
|
|
10
|
+
let receipt;
|
|
11
|
+
try {
|
|
12
|
+
receipt = await publicClient.getTransactionReceipt({ hash: txHash });
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
if (err instanceof TransactionReceiptNotFoundError)
|
|
16
|
+
return null;
|
|
17
|
+
throw err;
|
|
18
|
+
}
|
|
19
|
+
if (receipt.status === 'reverted') {
|
|
20
|
+
await markFailed(key, command, args, 'TX_REVERTED', txHash);
|
|
21
|
+
throw cliError('TX_REVERTED', `Tx reverted on-chain: ${txHash}`, `Inspect ${basescanTxUrl(network, txHash)}`);
|
|
22
|
+
}
|
|
23
|
+
const result = {
|
|
24
|
+
...submittedResult,
|
|
25
|
+
...await buildResult(receipt),
|
|
26
|
+
txHash,
|
|
27
|
+
block: receipt.blockNumber.toString(),
|
|
28
|
+
basescanUrl: basescanTxUrl(network, txHash),
|
|
29
|
+
};
|
|
30
|
+
await markConfirmed(key, command, args, result, txHash);
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
export async function handleSubmittedCacheDecision(decision, opts) {
|
|
34
|
+
const txHash = decision.txHash;
|
|
35
|
+
if (!txHash) {
|
|
36
|
+
emit({ ...decision.result, idempotent: true, status: 'submitted' }, ['(cached, submitted) tx hash missing from cache']);
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
if (opts.idempotencyKey) {
|
|
40
|
+
const reconciled = await reconcileSubmittedCache(opts.publicClient, opts.network, opts.idempotencyKey, opts.command, opts.args, txHash, opts.buildResult, decision.result);
|
|
41
|
+
if (reconciled) {
|
|
42
|
+
emit({ ...reconciled, idempotent: true, status: 'confirmed' }, [`(cached, reconciled to confirmed) tx: ${basescanTxUrl(opts.network, txHash)}`]);
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
emit({ ...decision.result, idempotent: true, status: 'submitted' }, [
|
|
47
|
+
`(cached, submitted but not confirmed yet) tx: ${txHash}`,
|
|
48
|
+
'Re-run after the tx confirms, or check the explorer.',
|
|
49
|
+
]);
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=write-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-cache.js","sourceRoot":"","sources":["../../src/commands/write-cache.ts"],"names":[],"mappings":"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"}
|
package/dist/config/load.d.ts
CHANGED
|
@@ -12,6 +12,17 @@ export interface Config {
|
|
|
12
12
|
apiKey: string | undefined;
|
|
13
13
|
privateKey: `0x${string}` | undefined;
|
|
14
14
|
voterPrivateKey: `0x${string}` | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Agent identity for the reppo.ai/api/v1/agents/{id}/pods metadata POST
|
|
17
|
+
* (Phase 2 of mint-pod). `agentId` + `agentApiKey` come from
|
|
18
|
+
* `reppo register-agent`. `agentApiKey` falls back to REPPO_API_KEY so an
|
|
19
|
+
* operator with a single key set keeps working; prefer REPPO_AGENT_API_KEY
|
|
20
|
+
* when the agent key and the api.reppo.xyz wallet-auth key differ.
|
|
21
|
+
*/
|
|
22
|
+
agentId: string | undefined;
|
|
23
|
+
agentApiKey: string | undefined;
|
|
24
|
+
/** Pinata JWT for pinning datasets to IPFS (mint-pod `--dataset`). */
|
|
25
|
+
pinataJwt: string | undefined;
|
|
15
26
|
}
|
|
16
27
|
export declare function loadConfig(overrides?: {
|
|
17
28
|
network?: Network;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B;;;;;OAKG;IACH,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,UAAU,EAAE,KAAK,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,eAAe,EAAE,KAAK,MAAM,EAAE,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B;;;;;OAKG;IACH,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,UAAU,EAAE,KAAK,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,eAAe,EAAE,KAAK,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3C;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,sEAAsE;IACtE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAmCD,wBAAgB,UAAU,CAAC,SAAS,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAuCxE"}
|
package/dist/config/load.js
CHANGED
|
@@ -61,6 +61,9 @@ export function loadConfig(overrides = {}) {
|
|
|
61
61
|
apiKey: process.env.REPPO_API_KEY,
|
|
62
62
|
privateKey: normalizePk(process.env.REPPO_PRIVATE_KEY),
|
|
63
63
|
voterPrivateKey: normalizePk(process.env.REPPO_VOTER_PRIVATE_KEY),
|
|
64
|
+
agentId: process.env.REPPO_AGENT_ID,
|
|
65
|
+
agentApiKey: process.env.REPPO_AGENT_API_KEY ?? process.env.REPPO_API_KEY,
|
|
66
|
+
pinataJwt: process.env.PINATA_JWT,
|
|
64
67
|
};
|
|
65
68
|
}
|
|
66
69
|
//# sourceMappingURL=load.js.map
|
package/dist/config/load.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type IdempotencyEntry, type IdempotencyStatus } from './db.js';
|
|
2
2
|
export type { IdempotencyEntry, IdempotencyStatus };
|
|
3
|
+
export declare const PENDING_STALE_MS: number;
|
|
3
4
|
/**
|
|
4
5
|
* Decision returned by `peekIdempotent` so write commands can decide what
|
|
5
6
|
* to do *before* spending gas:
|
|
@@ -52,7 +53,7 @@ export declare function getIdempotent(key: string, command: string, args: Record
|
|
|
52
53
|
*/
|
|
53
54
|
export declare function peekIdempotent<R>(key: string | undefined, command: string, args: Record<string, unknown>, isDryRun: boolean): Promise<CacheDecision<R>>;
|
|
54
55
|
export declare function begin(key: string, command: string, args: Record<string, unknown>): Promise<void>;
|
|
55
|
-
export declare function markSubmitted(key: string, command: string, args: Record<string, unknown>, txHash: string): Promise<void>;
|
|
56
|
+
export declare function markSubmitted(key: string, command: string, args: Record<string, unknown>, txHash: string, result?: Record<string, unknown>): Promise<void>;
|
|
56
57
|
export declare function markConfirmed(key: string, command: string, args: Record<string, unknown>, result: Record<string, unknown>, txHash: string): Promise<void>;
|
|
57
58
|
/**
|
|
58
59
|
* Mark an idempotency entry as failed. Pass `txHash` when the failure
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../../src/state/idempotency.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../../src/state/idempotency.ts"],"names":[],"mappings":"AA2CA,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACvB,MAAM,SAAS,CAAC;AAGjB,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,CAAC;AAEpD,eAAO,MAAM,gBAAgB,QAAiB,CAAC;AAE/C;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IACvB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAEnE;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAcrE;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA8BlC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAkC3B;AAED,wBAAsB,KAAK,CACzB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,MAAM,GAAG,IAAW,GAC3B,OAAO,CAAC,IAAI,CAAC,CAWf"}
|
|
@@ -15,18 +15,35 @@
|
|
|
15
15
|
* rejected with `IDEMPOTENCY_ARGS_MISMATCH` instead of silently
|
|
16
16
|
* returning the wrong cached result.
|
|
17
17
|
*
|
|
18
|
-
* Callers should pattern-match `
|
|
18
|
+
* Callers should pattern-match `peekIdempotent(key, command, args, isDryRun)`
|
|
19
19
|
* BEFORE doing work:
|
|
20
20
|
* - null → fresh, proceed
|
|
21
21
|
* - 'confirmed' → return cached result
|
|
22
|
-
* - 'submitted' →
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
22
|
+
* - 'submitted' → a tx was broadcast but never confirmed locally (a
|
|
23
|
+
* receipt timeout or a crash between submit and confirm).
|
|
24
|
+
* On retry the caller reconciles via
|
|
25
|
+
* `handleSubmittedCacheDecision`: poll the receipt and, if
|
|
26
|
+
* the tx landed, promote 'submitted' → 'confirmed' and
|
|
27
|
+
* return the result; otherwise return the cached txHash so
|
|
28
|
+
* the agent can keep polling. The entry intentionally
|
|
29
|
+
* stays 'submitted' on timeout so the next retry can finish
|
|
30
|
+
* the reconcile — it is NOT re-broadcast.
|
|
31
|
+
* - 'pending' → another invocation is mid-flight; refuse with
|
|
32
|
+
* IDEMPOTENCY_IN_FLIGHT — UNLESS the entry is older than
|
|
33
|
+
* PENDING_STALE_MS (10 min). A stale 'pending' means the
|
|
34
|
+
* prior run crashed BEFORE submitting (begin ran, markSubmitted
|
|
35
|
+
* did not), so nothing was broadcast under this key and it is
|
|
36
|
+
* safe to proceed.
|
|
37
|
+
* - 'failed' → if a txHash was recorded, refuse with
|
|
38
|
+
* IDEMPOTENCY_FAILED_AFTER_BROADCAST (re-broadcasting under
|
|
39
|
+
* the same key would pay gas for a second doomed attempt;
|
|
40
|
+
* use a fresh key). A pre-submit failure (no txHash) is safe
|
|
41
|
+
* to retry under the same key → proceed.
|
|
26
42
|
*/
|
|
27
43
|
import { createHash } from 'node:crypto';
|
|
28
44
|
import { getIdempotent as readEntry, upsertIdempotent, } from './db.js';
|
|
29
45
|
import { cliError } from '../output/format.js';
|
|
46
|
+
export const PENDING_STALE_MS = 10 * 60 * 1000;
|
|
30
47
|
/**
|
|
31
48
|
* SHA-256 of the canonicalized JSON of the args object. Object keys are
|
|
32
49
|
* sorted so {a:1,b:2} and {b:2,a:1} fingerprint identically; bigints
|
|
@@ -102,8 +119,12 @@ export async function peekIdempotent(key, command, args, isDryRun) {
|
|
|
102
119
|
return { kind: 'return-confirmed', result: cached.result, txHash: cached.txHash };
|
|
103
120
|
case 'submitted':
|
|
104
121
|
return { kind: 'return-submitted', result: cached.result, txHash: cached.txHash };
|
|
105
|
-
case 'pending':
|
|
122
|
+
case 'pending': {
|
|
123
|
+
if (Date.now() - cached.updatedAt > PENDING_STALE_MS) {
|
|
124
|
+
return { kind: 'proceed' };
|
|
125
|
+
}
|
|
106
126
|
throw cliError('IDEMPOTENCY_IN_FLIGHT', `Idempotency key "${key}" is in 'pending' state — another invocation is mid-flight.`, 'Wait for the in-flight invocation to finish, or use a fresh key.');
|
|
127
|
+
}
|
|
107
128
|
case 'failed':
|
|
108
129
|
if (cached.txHash) {
|
|
109
130
|
throw cliError('IDEMPOTENCY_FAILED_AFTER_BROADCAST', `Idempotency key "${key}" previously broadcast tx ${cached.txHash} which failed. ` +
|
|
@@ -126,13 +147,13 @@ export async function begin(key, command, args) {
|
|
|
126
147
|
updatedAt: now,
|
|
127
148
|
});
|
|
128
149
|
}
|
|
129
|
-
export async function markSubmitted(key, command, args, txHash) {
|
|
150
|
+
export async function markSubmitted(key, command, args, txHash, result = {}) {
|
|
130
151
|
const now = Date.now();
|
|
131
152
|
await upsertIdempotent(key, {
|
|
132
153
|
command,
|
|
133
154
|
argsFingerprint: fingerprintArgs(args),
|
|
134
155
|
status: 'submitted',
|
|
135
|
-
result: { txHash },
|
|
156
|
+
result: { ...result, txHash },
|
|
136
157
|
txHash,
|
|
137
158
|
createdAt: now,
|
|
138
159
|
updatedAt: now,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../../src/state/idempotency.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../../src/state/idempotency.ts"],"names":[],"mappings":"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"}
|