@bnbagent/studio-cli 0.0.11 → 0.0.12-alpha.1
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/LICENSE +201 -0
- package/dist/_agentcoreName-DZDWEYD3.js +0 -0
- package/dist/_twak-4XF4H5PL.js +0 -0
- package/dist/bag.js +254 -23
- package/dist/{chunk-VGSWNATS.js → chunk-AT2UYK5U.js} +2 -2
- package/dist/chunk-RO726HJG.js +0 -0
- package/dist/chunk-U7IDQ3K5.js +0 -0
- package/dist/{deployCli-4ATY3SUP.js → deployCli-LBDK2B4U.js} +1 -1
- package/package.json +12 -13
- package/recipes/agent/recipe.toml +1 -1
- package/recipes/runtimes/agentcore/recipe.toml +1 -1
- package/recipes/runtimes/azure-foundry/recipe.toml +1 -1
- package/recipes/wallet/recipe.toml +6 -1
- package/recipes/x402-buyer/recipe.toml +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of tracking or otherwise improving the Work,
|
|
59
|
+
but excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for describing the origin of the Work and
|
|
141
|
+
reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Support. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or support.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of "Purpose" be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2026 BNB Chain Studio
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
200
|
+
implied. See the License for the specific language governing
|
|
201
|
+
permissions and limitations under the License.
|
|
File without changes
|
package/dist/_twak-4XF4H5PL.js
CHANGED
|
File without changes
|
package/dist/bag.js
CHANGED
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
x402SellerIsFree,
|
|
53
53
|
x402SellerPricingState,
|
|
54
54
|
x402SellerUsesB402
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-AT2UYK5U.js";
|
|
56
56
|
import {
|
|
57
57
|
TWAK_CLI_MIN_VERSION,
|
|
58
58
|
TWAK_CLI_VERSION,
|
|
@@ -230,7 +230,7 @@ import {
|
|
|
230
230
|
var CAMPAIGN_DOC_URL = "https://www.bnbchain.org/en/blog/bnb-agent-studio-is-live-on-bnb-chain-ai-agents-from-one-prompt";
|
|
231
231
|
var CAMPAIGN_CHECK_TIMEOUT_MS = 6e3;
|
|
232
232
|
async function fetchCampaignActive() {
|
|
233
|
-
const { bnbPlatformApiUrl: bnbPlatformApiUrl2 } = await import("./deployCli-
|
|
233
|
+
const { bnbPlatformApiUrl: bnbPlatformApiUrl2 } = await import("./deployCli-LBDK2B4U.js");
|
|
234
234
|
const controller = new AbortController();
|
|
235
235
|
const timer = setTimeout(() => controller.abort(), CAMPAIGN_CHECK_TIMEOUT_MS);
|
|
236
236
|
try {
|
|
@@ -2937,7 +2937,7 @@ function canBuildWallet(root, data) {
|
|
|
2937
2937
|
const cfg = data ?? loadAgentToml(root);
|
|
2938
2938
|
const walletCfg = tableOf2(cfg, "wallet");
|
|
2939
2939
|
const kind = walletCfg.kind;
|
|
2940
|
-
if (kind === "twak" || kind === "altana") {
|
|
2940
|
+
if (kind === "twak" || kind === "altana" || kind === "turnkey") {
|
|
2941
2941
|
return false;
|
|
2942
2942
|
}
|
|
2943
2943
|
if (!process.env.WALLET_PASSWORD) {
|
|
@@ -2955,7 +2955,7 @@ function canBuildWallet(root, data) {
|
|
|
2955
2955
|
function walletAddressForChecks(root, data) {
|
|
2956
2956
|
const cfg = data ?? loadAgentToml(root);
|
|
2957
2957
|
const walletCfg = tableOf2(cfg, "wallet");
|
|
2958
|
-
if (walletCfg.kind === "twak" || walletCfg.kind === "altana") {
|
|
2958
|
+
if (walletCfg.kind === "twak" || walletCfg.kind === "altana" || walletCfg.kind === "turnkey") {
|
|
2959
2959
|
const addr = String(walletCfg.address ?? "").trim();
|
|
2960
2960
|
return addr || null;
|
|
2961
2961
|
}
|
|
@@ -6587,6 +6587,7 @@ import {
|
|
|
6587
6587
|
} from "@bnbagent/studio-runtime/config";
|
|
6588
6588
|
import { tbnbFaucetHint as tbnbFaucetHint2 } from "@bnbagent/studio-runtime/networks";
|
|
6589
6589
|
import { buildPolicy, buildWallet } from "@bnbagent/studio-runtime/wallet";
|
|
6590
|
+
import { getAddress as toChecksumAddress } from "viem";
|
|
6590
6591
|
|
|
6591
6592
|
// src/cli/walletSession.ts
|
|
6592
6593
|
import * as fs21 from "fs";
|
|
@@ -7318,6 +7319,9 @@ async function cmdNew(opts) {
|
|
|
7318
7319
|
if (kind === "twak") {
|
|
7319
7320
|
return cmdNewTwak(projectRoot, walletCfg);
|
|
7320
7321
|
}
|
|
7322
|
+
if (kind === "turnkey") {
|
|
7323
|
+
return cmdNewTurnkey(projectRoot);
|
|
7324
|
+
}
|
|
7321
7325
|
const privateKey = await resolvePrivateKeyArg(opts.privateKey);
|
|
7322
7326
|
const password = requireDurablePassword(projectRoot);
|
|
7323
7327
|
const keystoreDir = resolveKeystoreDir2(
|
|
@@ -7381,6 +7385,27 @@ Install it (Node >=22): npm install -g @trustwallet/cli@${TWAK_CLI_VERSION}`
|
|
|
7381
7385
|
printNextAfterNew(projectRoot, address);
|
|
7382
7386
|
return 0;
|
|
7383
7387
|
}
|
|
7388
|
+
function cmdNewTurnkey(projectRoot) {
|
|
7389
|
+
const signWith = String(process.env.TURNKEY_SIGN_WITH ?? "").trim();
|
|
7390
|
+
if (signWith === "") {
|
|
7391
|
+
printErr(
|
|
7392
|
+
"error: TURNKEY_SIGN_WITH is not set (wallet.kind = 'turnkey').\nCreate a wallet account in the Turnkey dashboard, set the TURNKEY_* credentials in .studio/.env.local (bag auto-loads it), then re-run `bag wallet new` to adopt + anchor the address."
|
|
7393
|
+
);
|
|
7394
|
+
return 1;
|
|
7395
|
+
}
|
|
7396
|
+
let address;
|
|
7397
|
+
try {
|
|
7398
|
+
address = toChecksumAddress(signWith);
|
|
7399
|
+
} catch {
|
|
7400
|
+
printErr(
|
|
7401
|
+
`error: TURNKEY_SIGN_WITH must be the wallet account's Ethereum address (0x + 40 hex chars), not a Turnkey wallet id \u2014 copy it from the dashboard wallet-account view. Got: '${signWith}'`
|
|
7402
|
+
);
|
|
7403
|
+
return 1;
|
|
7404
|
+
}
|
|
7405
|
+
printOut(address);
|
|
7406
|
+
persistAddress(projectRoot, address);
|
|
7407
|
+
return 0;
|
|
7408
|
+
}
|
|
7384
7409
|
function ensureTwakCredentials(walletFile, homeDir) {
|
|
7385
7410
|
const twakDir = path21.dirname(walletFile);
|
|
7386
7411
|
const target = path21.join(twakDir, "credentials.json");
|
|
@@ -7558,6 +7583,33 @@ function cmdShow5(projectRootArg2) {
|
|
|
7558
7583
|
);
|
|
7559
7584
|
return 0;
|
|
7560
7585
|
}
|
|
7586
|
+
if (kind === "turnkey") {
|
|
7587
|
+
const anchored = String(walletCfg.address ?? "").trim();
|
|
7588
|
+
const signWith = String(process.env.TURNKEY_SIGN_WITH ?? "").trim();
|
|
7589
|
+
const address2 = anchored || signWith;
|
|
7590
|
+
if (!address2) {
|
|
7591
|
+
throw new Error(
|
|
7592
|
+
"cannot resolve the Turnkey wallet address: no [wallet].address is anchored in studio.toml and TURNKEY_SIGN_WITH is not set \u2014 fill .studio/.env.local, then run `bag wallet new`."
|
|
7593
|
+
);
|
|
7594
|
+
}
|
|
7595
|
+
const requiredEnv = [
|
|
7596
|
+
"TURNKEY_API_PUBLIC_KEY",
|
|
7597
|
+
"TURNKEY_API_PRIVATE_KEY",
|
|
7598
|
+
"TURNKEY_ORG_ID",
|
|
7599
|
+
"TURNKEY_SIGN_WITH"
|
|
7600
|
+
];
|
|
7601
|
+
const present = requiredEnv.filter((key) => process.env[key]).length;
|
|
7602
|
+
const baseUrl = process.env.TURNKEY_API_BASE_URL || "https://api.turnkey.com";
|
|
7603
|
+
printOut(`address: ${address2}`);
|
|
7604
|
+
printOut("source: turnkey");
|
|
7605
|
+
printOut(
|
|
7606
|
+
`key_location: remote:turnkey (${baseUrl}; key held in AWS Nitro enclave, never leaves)`
|
|
7607
|
+
);
|
|
7608
|
+
printOut(
|
|
7609
|
+
`credentials: ${present}/${requiredEnv.length} TURNKEY_* env vars set`
|
|
7610
|
+
);
|
|
7611
|
+
return 0;
|
|
7612
|
+
}
|
|
7561
7613
|
const password = requirePassword2();
|
|
7562
7614
|
const keystoreDir = resolveKeystoreDir2(projectRoot, null, walletCfg);
|
|
7563
7615
|
const provider = new EVMWalletProvider({
|
|
@@ -7650,7 +7702,14 @@ async function cmdSign(msg, projectRootArg2) {
|
|
|
7650
7702
|
);
|
|
7651
7703
|
}
|
|
7652
7704
|
let provider;
|
|
7653
|
-
if (kind === "
|
|
7705
|
+
if (kind === "turnkey") {
|
|
7706
|
+
printErr(
|
|
7707
|
+
"note: Turnkey signatures are billed (free tier 25/month at 1 req/s; pay-as-you-go $0.10 each)."
|
|
7708
|
+
);
|
|
7709
|
+
provider = buildWallet(walletCfg, projectRoot, {
|
|
7710
|
+
network: projectNetwork(projectRoot)
|
|
7711
|
+
});
|
|
7712
|
+
} else if (kind === "twak") {
|
|
7654
7713
|
provider = twakProvider(projectRoot, walletCfg);
|
|
7655
7714
|
} else {
|
|
7656
7715
|
const password = requirePassword2();
|
|
@@ -7675,10 +7734,10 @@ async function cmdBalance(opts) {
|
|
|
7675
7734
|
const walletCfg = data.wallet !== null && typeof data.wallet === "object" ? data.wallet : {};
|
|
7676
7735
|
let address;
|
|
7677
7736
|
const kind = walletKind(walletCfg);
|
|
7678
|
-
if (kind === "twak" || kind === "altana") {
|
|
7737
|
+
if (kind === "twak" || kind === "altana" || kind === "turnkey") {
|
|
7679
7738
|
address = String(walletCfg.address ?? "").trim();
|
|
7680
7739
|
if (!address) {
|
|
7681
|
-
const nextStep = kind === "twak" ? "(adopts the twak wallet's address) first." : "to create the Altana admin keystore first.";
|
|
7740
|
+
const nextStep = kind === "twak" ? "(adopts the twak wallet's address) first." : kind === "turnkey" ? "(set TURNKEY_SIGN_WITH in .studio/.env.local first \u2014 `bag wallet new` adopts it)." : "to create the Altana admin keystore first.";
|
|
7682
7741
|
throw new Error(
|
|
7683
7742
|
`no [wallet].address anchored in studio.toml \u2014 run bag wallet new ${nextStep}`
|
|
7684
7743
|
);
|
|
@@ -8068,8 +8127,8 @@ function registerInit(program) {
|
|
|
8068
8127
|
).addOption(
|
|
8069
8128
|
new Option2(
|
|
8070
8129
|
"--wallet-kind <kind>",
|
|
8071
|
-
"Wallet backend for the Agent (default: evm-local = encrypted local keystore at the workspace root .studio/wallets/; CodeZip deploy). altana \u2014 encrypted local admin keystore plus a bounded runtime session; deploys ship ONLY the session (ALTANA_SESSION secret). twak \u2014 FULLY SUPPORTED, opt in: Trust Wallet Agent Kit CLI, self-custody encrypted mnemonic in a PROJECT-DEDICATED home (.studio/twak); deploys as a container image."
|
|
8072
|
-
).choices(["twak", "evm-local", "altana"])
|
|
8130
|
+
"Wallet backend for the Agent (default: evm-local = encrypted local keystore at the workspace root .studio/wallets/; CodeZip deploy). altana \u2014 encrypted local admin keystore plus a bounded runtime session; deploys ship ONLY the session (ALTANA_SESSION secret). twak \u2014 FULLY SUPPORTED, opt in: Trust Wallet Agent Kit CLI, self-custody encrypted mnemonic in a PROJECT-DEDICATED home (.studio/twak); deploys as a container image. turnkey \u2014 remote signer: the key lives in Turnkey's AWS Nitro enclave and the Agent signs via TURNKEY_* API credentials; CodeZip deploy; every successful signature is billed."
|
|
8131
|
+
).choices(["twak", "evm-local", "altana", "turnkey"])
|
|
8073
8132
|
).option(
|
|
8074
8133
|
"--twak-home <path>",
|
|
8075
8134
|
"twak only: point this project at an EXISTING twak wallet home (the HOME-STYLE PARENT dir that contains .twak/wallet.json \u2014 NOT the .twak dir itself; a .twak path holding a wallet is auto-corrected to its parent) instead of the dedicated .studio/twak. Written to [wallet].twak_home."
|
|
@@ -8382,9 +8441,9 @@ async function cmdInitFlow(nameArg, opts) {
|
|
|
8382
8441
|
}
|
|
8383
8442
|
const budgetFlag = opts.enableAutoTopup ? "enable" : opts.autoTopup === false ? "disable" : null;
|
|
8384
8443
|
const budgetChoice = walletKind2 === "altana" && llmProvider !== "pieverse-llm" && budgetFlag === null ? null : await resolveBudgetChoice(budgetFlag);
|
|
8385
|
-
if ((rails === "b402" || rails === "both") && x402SellerPricingState({ price_usd: b402Price }).kind === "paid" && !["evm-local", "twak"].includes(walletKind2)) {
|
|
8444
|
+
if ((rails === "b402" || rails === "both") && x402SellerPricingState({ price_usd: b402Price }).kind === "paid" && !["evm-local", "twak", "turnkey"].includes(walletKind2)) {
|
|
8386
8445
|
printErr(
|
|
8387
|
-
`error: the b402 seller rail supports wallet.kind evm-local or
|
|
8446
|
+
`error: the b402 seller rail supports wallet.kind evm-local, twak or turnkey only; '${walletKind2}' cannot act as the b402 payout wallet. Re-run with --rails 8183 or a supported --wallet-kind.`
|
|
8388
8447
|
);
|
|
8389
8448
|
fs23.rmSync(target, { recursive: true, force: true });
|
|
8390
8449
|
return 2;
|
|
@@ -8481,6 +8540,8 @@ async function cmdInitFlow(nameArg, opts) {
|
|
|
8481
8540
|
}
|
|
8482
8541
|
} else if (walletKind2 === "altana") {
|
|
8483
8542
|
printAltanaNotice();
|
|
8543
|
+
} else if (walletKind2 === "turnkey") {
|
|
8544
|
+
printTurnkeyNotice();
|
|
8484
8545
|
} else {
|
|
8485
8546
|
printEvmLocalNotice(
|
|
8486
8547
|
derivePackaging(walletKind2, destination, platformArtifact2, runtime)
|
|
@@ -8717,6 +8778,9 @@ function computeAgentNodeDeps(runtime, provider, protocols = "A2A", walletKind2
|
|
|
8717
8778
|
if (walletKind2 === "altana") {
|
|
8718
8779
|
raw.push(...readRecipeNodeDeps("wallet", "altana"));
|
|
8719
8780
|
}
|
|
8781
|
+
if (walletKind2 === "turnkey") {
|
|
8782
|
+
raw.push(...readRecipeNodeDeps("wallet", "turnkey"));
|
|
8783
|
+
}
|
|
8720
8784
|
const out = {};
|
|
8721
8785
|
const core = splitDep(coreRequirement());
|
|
8722
8786
|
for (const dep of raw) {
|
|
@@ -8890,6 +8954,18 @@ kind = "altana"
|
|
|
8890
8954
|
keystore_dir = "../../.studio/wallets"
|
|
8891
8955
|
session_file = "../../.studio/wallets/altana-session.json"
|
|
8892
8956
|
# address = "0x..." # filled by \`bag wallet new\`; session must match it`;
|
|
8957
|
+
}
|
|
8958
|
+
if (walletKind2 === "turnkey") {
|
|
8959
|
+
return `[wallet]
|
|
8960
|
+
# Turnkey remote signer. The key is generated and held in Turnkey's AWS Nitro
|
|
8961
|
+
# enclave \u2014 no key material ever exists in this project or its deploys. The
|
|
8962
|
+
# Agent signs via the Turnkey API using the TURNKEY_* credentials in
|
|
8963
|
+
# .studio/.env.local. Billing: every successful signature is billed (free
|
|
8964
|
+
# tier: 25 signatures/month at 1 request/second; pay-as-you-go $0.10 each).
|
|
8965
|
+
# PRODUCTION: use a NON-ROOT API user restricted by an explicit ALLOW
|
|
8966
|
+
# policy \u2014 a root user's API key bypasses ALL Turnkey server-side policies.
|
|
8967
|
+
kind = "turnkey"
|
|
8968
|
+
# address = "0x..." # filled by \`bag wallet new\` (adopts TURNKEY_SIGN_WITH)`;
|
|
8893
8969
|
}
|
|
8894
8970
|
return `[wallet]
|
|
8895
8971
|
# Local keystore signer. The Agent is the SOLE key-holder/signer.
|
|
@@ -9088,6 +9164,23 @@ function renderAgentEnvLocal(provider, storageProvider, walletKind2, rails, b402
|
|
|
9088
9164
|
"# TWAK_ACCESS_ID=",
|
|
9089
9165
|
"# TWAK_HMAC_SECRET="
|
|
9090
9166
|
);
|
|
9167
|
+
} else if (walletKind2 === "turnkey") {
|
|
9168
|
+
lines.push(
|
|
9169
|
+
"",
|
|
9170
|
+
"# Turnkey API credentials (dashboard \u2192 API keys). The P-256 API key",
|
|
9171
|
+
"# pair authenticates this Agent to the enclave; the wallet's signing",
|
|
9172
|
+
"# key never leaves Turnkey. Use a NON-ROOT API user + explicit ALLOW",
|
|
9173
|
+
"# policy in production (root keys bypass all Turnkey policies).",
|
|
9174
|
+
"TURNKEY_API_PUBLIC_KEY=",
|
|
9175
|
+
"TURNKEY_API_PRIVATE_KEY=",
|
|
9176
|
+
"# Organization id (dashboard \u2192 settings):",
|
|
9177
|
+
"TURNKEY_ORG_ID=",
|
|
9178
|
+
"# Account to sign with \u2014 MUST be the 0x Ethereum ADDRESS itself, not",
|
|
9179
|
+
"# a Turnkey wallet id. `bag wallet new` anchors it into studio.toml.",
|
|
9180
|
+
"TURNKEY_SIGN_WITH=",
|
|
9181
|
+
"# Optional API host override (default https://api.turnkey.com):",
|
|
9182
|
+
"# TURNKEY_API_BASE_URL="
|
|
9183
|
+
);
|
|
9091
9184
|
} else if (walletKind2 === "evm-local" || walletKind2 === "altana") {
|
|
9092
9185
|
lines.push(
|
|
9093
9186
|
"",
|
|
@@ -9202,7 +9295,7 @@ entrypoint code in \`src/signing.ts\` \u2014 never an LLM-callable tool.
|
|
|
9202
9295
|
${mode === "both" ? filesBoth : mode === "mcp" ? filesMcp : filesA2a}
|
|
9203
9296
|
${shared}
|
|
9204
9297
|
- \`.env.local\` \u2014 Agent secrets; on deploy they are sent to the **operator's**
|
|
9205
|
-
Secrets Manager (the scoped, consented commitment-#2 exception). ${walletKind2 === "altana" ? "Only the\n bounded session ships (as `ALTANA_SESSION`); tighten it with\n `bag wallet session grant --force` \u2014 do not create a new wallet." : "Use a\n THROWAWAY testnet wallet \u2014 `(cd app/agent && bag wallet new)`."}
|
|
9298
|
+
Secrets Manager (the scoped, consented commitment-#2 exception). ${walletKind2 === "altana" ? "Only the\n bounded session ships (as `ALTANA_SESSION`); tighten it with\n `bag wallet session grant --force` \u2014 do not create a new wallet." : walletKind2 === "turnkey" ? "No key\n material exists locally \u2014 only the TURNKEY_* API credentials ship; the\n signing key stays in Turnkey's enclave. Fund the TURNKEY_SIGN_WITH\n address with a little tBNB; every successful signature is billed." : "Use a\n THROWAWAY testnet wallet \u2014 `(cd app/agent && bag wallet new)`."}
|
|
9206
9299
|
|
|
9207
9300
|
## Run locally
|
|
9208
9301
|
|
|
@@ -9311,12 +9404,12 @@ function ensureCursorGitignore(gitignore) {
|
|
|
9311
9404
|
${addition}`);
|
|
9312
9405
|
}
|
|
9313
9406
|
async function resolveWalletKind(flagValue, isTty) {
|
|
9314
|
-
if (flagValue === "evm-local" || flagValue === "twak" || flagValue === "altana") {
|
|
9407
|
+
if (flagValue === "evm-local" || flagValue === "twak" || flagValue === "altana" || flagValue === "turnkey") {
|
|
9315
9408
|
return flagValue;
|
|
9316
9409
|
}
|
|
9317
9410
|
if (!isTty) {
|
|
9318
9411
|
printErr(
|
|
9319
|
-
"info: wallet backend defaulting to 'evm-local' (non-interactive). To choose explicitly, re-run with --wallet-kind evm-local or --wallet-kind twak or --wallet-kind
|
|
9412
|
+
"info: wallet backend defaulting to 'evm-local' (non-interactive). To choose explicitly, re-run with --wallet-kind evm-local or --wallet-kind twak, --wallet-kind altana or --wallet-kind turnkey."
|
|
9320
9413
|
);
|
|
9321
9414
|
return "evm-local";
|
|
9322
9415
|
}
|
|
@@ -9330,9 +9423,13 @@ async function resolveWalletKind(flagValue, isTty) {
|
|
|
9330
9423
|
printOut(
|
|
9331
9424
|
" 3. altana \u2014 bounded session signer; incompatible with pieverse-llm and paid b402 selling"
|
|
9332
9425
|
);
|
|
9333
|
-
|
|
9426
|
+
printOut(
|
|
9427
|
+
" 4. turnkey \u2014 remote signer; key held in Turnkey's AWS Nitro enclave; billable signatures"
|
|
9428
|
+
);
|
|
9429
|
+
const answer = (await promptUser("Wallet backend [1-4, Enter = evm-local]: ")).trim().toLowerCase();
|
|
9334
9430
|
if (answer === "2" || answer === "twak") return "twak";
|
|
9335
9431
|
if (answer === "3" || answer === "altana") return "altana";
|
|
9432
|
+
if (answer === "4" || answer === "turnkey") return "turnkey";
|
|
9336
9433
|
if (answer !== "" && answer !== "1" && answer !== "evm-local") {
|
|
9337
9434
|
printErr(`hint: unknown wallet backend '${answer}' \u2014 using evm-local.`);
|
|
9338
9435
|
}
|
|
@@ -9614,6 +9711,12 @@ async function runOnboarding(o) {
|
|
|
9614
9711
|
if (o.walletKind === "twak") {
|
|
9615
9712
|
return runOnboardingTwak(o);
|
|
9616
9713
|
}
|
|
9714
|
+
if (o.walletKind === "turnkey") {
|
|
9715
|
+
printOut(
|
|
9716
|
+
"turnkey onboarding: no local key is created. Fill the TURNKEY_* credentials in .studio/.env.local (Turnkey dashboard \u2192 API keys / settings / wallet account), then run `(cd app/agent && bag wallet new)` to adopt + anchor the signing address."
|
|
9717
|
+
);
|
|
9718
|
+
return false;
|
|
9719
|
+
}
|
|
9617
9720
|
const password = await promptPassword();
|
|
9618
9721
|
if (password === null) {
|
|
9619
9722
|
return false;
|
|
@@ -9983,7 +10086,33 @@ NOTE \u2014 wallet.kind = "altana" (bounded runtime session):
|
|
|
9983
10086
|
\`bag wallet session grant --force\` and redeploy.`
|
|
9984
10087
|
);
|
|
9985
10088
|
}
|
|
10089
|
+
function printTurnkeyNotice() {
|
|
10090
|
+
printOut(
|
|
10091
|
+
`
|
|
10092
|
+
NOTE \u2014 wallet.kind = "turnkey" (remote signer, keys in Turnkey's AWS Nitro enclave):
|
|
10093
|
+
\xB7 WALLET: no key material exists locally \u2014 the Agent signs via the TURNKEY_*
|
|
10094
|
+
API credentials in .studio/.env.local (dashboard \u2192 API keys). Set them,
|
|
10095
|
+
then run \`(cd app/agent && bag wallet new)\` to adopt + anchor the address.
|
|
10096
|
+
\xB7 BILLING: every successful signature is billed (free tier: 25/month at
|
|
10097
|
+
1 request/second; pay-as-you-go $0.10 each) \u2014 budget accordingly.
|
|
10098
|
+
\xB7 PRODUCTION: use a NON-ROOT API user restricted by an explicit ALLOW policy;
|
|
10099
|
+
a root user's API key bypasses ALL Turnkey server-side policies.`
|
|
10100
|
+
);
|
|
10101
|
+
}
|
|
9986
10102
|
function printPlatformWalletSuggestion(walletKind2) {
|
|
10103
|
+
if (walletKind2 === "turnkey") {
|
|
10104
|
+
printOut(
|
|
10105
|
+
`
|
|
10106
|
+
NOTE \u2014 destination = "platform" (48h TESTNET TRIAL on the BNB Chain managed platform):
|
|
10107
|
+
\xB7 This is a sandbox, not a production seller \u2014 the runtime is auto-reclaimed at 48h.
|
|
10108
|
+
\xB7 To sign, ONLY the TURNKEY_* API credentials are transmitted to the operator's
|
|
10109
|
+
Secrets Manager on deploy \u2014 the signing key never leaves Turnkey's enclave.
|
|
10110
|
+
\xB7 Want a smaller blast radius? Use a NON-ROOT API user whose ALLOW policy
|
|
10111
|
+
covers only this Agent's operations, and revoke it from the Turnkey
|
|
10112
|
+
dashboard when the trial ends.`
|
|
10113
|
+
);
|
|
10114
|
+
return;
|
|
10115
|
+
}
|
|
9987
10116
|
if (walletKind2 === "altana") {
|
|
9988
10117
|
printOut(
|
|
9989
10118
|
`
|
|
@@ -10214,6 +10343,17 @@ function printNextSteps(name, provider, o = {}) {
|
|
|
10214
10343
|
printOut(
|
|
10215
10344
|
" (cd app/agent && bag wallet session status) # local, secret-free summary"
|
|
10216
10345
|
);
|
|
10346
|
+
} else if (walletKind2 === "turnkey") {
|
|
10347
|
+
printOut(
|
|
10348
|
+
" # 1. edit .studio/.env.local and set the TURNKEY_* credentials (Turnkey dashboard \u2192 API keys / settings / wallet account)"
|
|
10349
|
+
);
|
|
10350
|
+
printOut(
|
|
10351
|
+
" # use a NON-ROOT API user + explicit ALLOW policy; TURNKEY_SIGN_WITH is the 0x ADDRESS, not a wallet id"
|
|
10352
|
+
);
|
|
10353
|
+
printOut(
|
|
10354
|
+
" # 2. adopt + anchor the Turnkey address (no local key is created):"
|
|
10355
|
+
);
|
|
10356
|
+
printOut(" (cd app/agent && bag wallet new)");
|
|
10217
10357
|
} else {
|
|
10218
10358
|
printOut(
|
|
10219
10359
|
" # 1. edit .studio/.env.local and set WALLET_PASSWORD (encrypts the keystore + signs all on-chain ops)"
|
|
@@ -10437,6 +10577,10 @@ function printConfigSummary(agentRoot2) {
|
|
|
10437
10577
|
".studio/wallets/altana-session.json"
|
|
10438
10578
|
)}`
|
|
10439
10579
|
);
|
|
10580
|
+
} else if (walletKind2 === "turnkey") {
|
|
10581
|
+
printOut(
|
|
10582
|
+
" wallet : Turnkey remote signer (key in AWS Nitro enclave; TURNKEY_* credentials in .studio/.env.local) \u2014 the sole signer; receives your $U"
|
|
10583
|
+
);
|
|
10440
10584
|
} else {
|
|
10441
10585
|
printOut(
|
|
10442
10586
|
` wallet : local keystore (${shown(
|
|
@@ -10557,6 +10701,16 @@ function runtimeEnvKeysCore(cfg, resolvable) {
|
|
|
10557
10701
|
}
|
|
10558
10702
|
} else if (walletKind2 === "altana") {
|
|
10559
10703
|
keys = [];
|
|
10704
|
+
} else if (walletKind2 === "turnkey") {
|
|
10705
|
+
keys = [
|
|
10706
|
+
"TURNKEY_API_PUBLIC_KEY",
|
|
10707
|
+
"TURNKEY_API_PRIVATE_KEY",
|
|
10708
|
+
"TURNKEY_ORG_ID",
|
|
10709
|
+
"TURNKEY_SIGN_WITH"
|
|
10710
|
+
];
|
|
10711
|
+
if (resolvable("TURNKEY_API_BASE_URL")) {
|
|
10712
|
+
keys.push("TURNKEY_API_BASE_URL");
|
|
10713
|
+
}
|
|
10560
10714
|
} else {
|
|
10561
10715
|
keys = ["WALLET_PASSWORD"];
|
|
10562
10716
|
}
|
|
@@ -11081,10 +11235,17 @@ async function cmdDev(opts) {
|
|
|
11081
11235
|
);
|
|
11082
11236
|
return 2;
|
|
11083
11237
|
}
|
|
11084
|
-
const
|
|
11085
|
-
|
|
11238
|
+
const requiredWalletEnv = walletKind2 === "twak" ? ["TWAK_WALLET_PASSWORD"] : walletKind2 === "altana" ? [] : walletKind2 === "turnkey" ? [
|
|
11239
|
+
"TURNKEY_API_PUBLIC_KEY",
|
|
11240
|
+
"TURNKEY_API_PRIVATE_KEY",
|
|
11241
|
+
"TURNKEY_ORG_ID",
|
|
11242
|
+
"TURNKEY_SIGN_WITH"
|
|
11243
|
+
] : ["WALLET_PASSWORD"];
|
|
11244
|
+
const missingWalletEnv = requiredWalletEnv.filter((key) => !process.env[key]);
|
|
11245
|
+
if (missingWalletEnv.length > 0) {
|
|
11246
|
+
const plural = missingWalletEnv.length > 1 ? "vars are" : "var is";
|
|
11086
11247
|
printErr(
|
|
11087
|
-
`error: ${
|
|
11248
|
+
`error: ${missingWalletEnv.join(", ")} env ${plural} required to run \`bag dev\` with wallet.kind='${walletKind2}' (the Agent is the sole signer). Set ${missingWalletEnv.length > 1 ? "them" : "it"} in .studio/.env.local or your shell.`
|
|
11088
11249
|
);
|
|
11089
11250
|
return 2;
|
|
11090
11251
|
}
|
|
@@ -12353,7 +12514,7 @@ function collectRuntimeSecretsDetailed(root) {
|
|
|
12353
12514
|
sources[KEYSTORE_JSON_ENV] = "wallet-file";
|
|
12354
12515
|
}
|
|
12355
12516
|
}
|
|
12356
|
-
if (walletKind2 !== "altana" && !(KEYSTORE_JSON_ENV in payload) && !(TWAK_WALLET_JSON_ENV in payload)) {
|
|
12517
|
+
if (walletKind2 !== "altana" && walletKind2 !== "turnkey" && !(KEYSTORE_JSON_ENV in payload) && !(TWAK_WALLET_JSON_ENV in payload)) {
|
|
12357
12518
|
printErr(
|
|
12358
12519
|
`WARNING: no wallet signing material found (${KEYSTORE_JSON_ENV} for evm-local / ${TWAK_WALLET_JSON_ENV} for twak). The deployed runtime won't be able to sign quotes or deliveries. Create/adopt a wallet first (e.g. \`bag wallet new\`) and redeploy.`
|
|
12359
12520
|
);
|
|
@@ -17438,7 +17599,8 @@ var SECRET_ENV_KEYS = [
|
|
|
17438
17599
|
"PIEVERSE_LLM_API_KEY",
|
|
17439
17600
|
"STORAGE_API_KEY",
|
|
17440
17601
|
"TWAK_ACCESS_ID",
|
|
17441
|
-
"TWAK_HMAC_SECRET"
|
|
17602
|
+
"TWAK_HMAC_SECRET",
|
|
17603
|
+
"TURNKEY_API_PRIVATE_KEY"
|
|
17442
17604
|
];
|
|
17443
17605
|
function tableOf14(cfg, key) {
|
|
17444
17606
|
const v = cfg[key];
|
|
@@ -17685,6 +17847,9 @@ async function checkWallet(projectRoot, data) {
|
|
|
17685
17847
|
if (walletCfg.kind === "altana") {
|
|
17686
17848
|
return checkWalletAltana(walletCfg, projectRoot, data);
|
|
17687
17849
|
}
|
|
17850
|
+
if (walletCfg.kind === "turnkey") {
|
|
17851
|
+
return checkWalletTurnkey(walletCfg);
|
|
17852
|
+
}
|
|
17688
17853
|
if (!isLocalEvmWallet(walletCfg)) {
|
|
17689
17854
|
return [
|
|
17690
17855
|
{
|
|
@@ -17738,6 +17903,58 @@ async function checkWallet(projectRoot, data) {
|
|
|
17738
17903
|
}
|
|
17739
17904
|
return out;
|
|
17740
17905
|
}
|
|
17906
|
+
var TURNKEY_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
17907
|
+
var TURNKEY_REQUIRED_ENV = [
|
|
17908
|
+
"TURNKEY_API_PUBLIC_KEY",
|
|
17909
|
+
"TURNKEY_API_PRIVATE_KEY",
|
|
17910
|
+
"TURNKEY_ORG_ID",
|
|
17911
|
+
"TURNKEY_SIGN_WITH"
|
|
17912
|
+
];
|
|
17913
|
+
function checkWalletTurnkey(walletCfg) {
|
|
17914
|
+
const out = [];
|
|
17915
|
+
const missing = TURNKEY_REQUIRED_ENV.filter((key) => !process.env[key]);
|
|
17916
|
+
out.push(
|
|
17917
|
+
missing.length === 0 ? {
|
|
17918
|
+
name: "[wallet] turnkey credentials",
|
|
17919
|
+
status: PASS,
|
|
17920
|
+
detail: "API key pair + org id + sign-with address set; reminder: production should use a non-root API user with an explicit ALLOW policy (root keys bypass all Turnkey policies)"
|
|
17921
|
+
} : {
|
|
17922
|
+
name: "[wallet] turnkey credentials",
|
|
17923
|
+
status: FAIL,
|
|
17924
|
+
detail: `missing: ${missing.join(", ")} \u2014 set them in .studio/.env.local (Turnkey dashboard \u2192 API keys / settings / wallet account)`
|
|
17925
|
+
}
|
|
17926
|
+
);
|
|
17927
|
+
const signWith = String(process.env.TURNKEY_SIGN_WITH ?? "").trim();
|
|
17928
|
+
if (signWith !== "" && !TURNKEY_ADDRESS_RE.test(signWith)) {
|
|
17929
|
+
out.push({
|
|
17930
|
+
name: "TURNKEY_SIGN_WITH format",
|
|
17931
|
+
status: FAIL,
|
|
17932
|
+
detail: "must be the wallet account's Ethereum address (0x + 40 hex chars), not a Turnkey wallet id \u2014 copy it from the dashboard wallet-account view"
|
|
17933
|
+
});
|
|
17934
|
+
}
|
|
17935
|
+
const anchored = String(walletCfg.address ?? "").trim();
|
|
17936
|
+
if (anchored === "") {
|
|
17937
|
+
out.push({
|
|
17938
|
+
name: "[wallet] address anchor",
|
|
17939
|
+
status: WARN,
|
|
17940
|
+
detail: "no [wallet].address \u2014 run `bag wallet new` to adopt TURNKEY_SIGN_WITH"
|
|
17941
|
+
});
|
|
17942
|
+
} else if (signWith !== "" && TURNKEY_ADDRESS_RE.test(signWith)) {
|
|
17943
|
+
const matches = anchored.toLowerCase() === signWith.toLowerCase();
|
|
17944
|
+
out.push(
|
|
17945
|
+
matches ? {
|
|
17946
|
+
name: "[wallet] address anchor",
|
|
17947
|
+
status: PASS,
|
|
17948
|
+
detail: `${anchored} matches TURNKEY_SIGN_WITH`
|
|
17949
|
+
} : {
|
|
17950
|
+
name: "[wallet] address anchor",
|
|
17951
|
+
status: FAIL,
|
|
17952
|
+
detail: `[wallet].address ${anchored} does not match TURNKEY_SIGN_WITH ${signWith} \u2014 stale anchor or different Turnkey credentials; fix .studio/.env.local, then re-run \`bag wallet new\``
|
|
17953
|
+
}
|
|
17954
|
+
);
|
|
17955
|
+
}
|
|
17956
|
+
return out;
|
|
17957
|
+
}
|
|
17741
17958
|
function checkWalletAltana(walletCfg, projectRoot, data) {
|
|
17742
17959
|
const out = [];
|
|
17743
17960
|
const contracts = erc8183ContractOverrideState(
|
|
@@ -17930,6 +18147,20 @@ function checkPassword(data) {
|
|
|
17930
18147
|
}
|
|
17931
18148
|
];
|
|
17932
18149
|
}
|
|
18150
|
+
if (walletKind2 === "turnkey") {
|
|
18151
|
+
const missing = TURNKEY_REQUIRED_ENV.filter((key) => !process.env[key]);
|
|
18152
|
+
return [
|
|
18153
|
+
missing.length === 0 ? {
|
|
18154
|
+
name: "TURNKEY_* env",
|
|
18155
|
+
status: PASS,
|
|
18156
|
+
detail: "all Turnkey credentials set (WALLET_PASSWORD is not used for this kind)"
|
|
18157
|
+
} : {
|
|
18158
|
+
name: "TURNKEY_* env",
|
|
18159
|
+
status: WARN,
|
|
18160
|
+
detail: `missing: ${missing.join(", ")} \u2014 signing will fail (set in .studio/.env.local)`
|
|
18161
|
+
}
|
|
18162
|
+
];
|
|
18163
|
+
}
|
|
17933
18164
|
if (process.env.WALLET_PASSWORD) {
|
|
17934
18165
|
return [{ name: "WALLET_PASSWORD env", status: PASS, detail: "set" }];
|
|
17935
18166
|
}
|
|
@@ -18298,11 +18529,11 @@ function checkX402Seller(data, agentRoot2) {
|
|
|
18298
18529
|
}
|
|
18299
18530
|
];
|
|
18300
18531
|
const walletKind2 = String(tableOf14(data, "wallet").kind ?? "evm-local");
|
|
18301
|
-
if (!["evm-local", "twak"].includes(walletKind2)) {
|
|
18532
|
+
if (!["evm-local", "twak", "turnkey"].includes(walletKind2)) {
|
|
18302
18533
|
out.push({
|
|
18303
18534
|
name: "x402 payout wallet",
|
|
18304
18535
|
status: FAIL,
|
|
18305
|
-
detail: `PAID B402 supports evm-local or
|
|
18536
|
+
detail: `PAID B402 supports evm-local, twak or turnkey, not ${walletKind2}.`
|
|
18306
18537
|
});
|
|
18307
18538
|
}
|
|
18308
18539
|
const credentials = b402Credentials(agentRoot2);
|
|
@@ -18376,7 +18607,7 @@ function checkStorage(data) {
|
|
|
18376
18607
|
}
|
|
18377
18608
|
function balanceAddress(projectRoot, data) {
|
|
18378
18609
|
const walletCfg = tableOf14(data, "wallet");
|
|
18379
|
-
if (walletCfg.kind === "twak" || walletCfg.kind === "altana") {
|
|
18610
|
+
if (walletCfg.kind === "twak" || walletCfg.kind === "altana" || walletCfg.kind === "turnkey") {
|
|
18380
18611
|
const addr = String(walletCfg.address ?? "").trim();
|
|
18381
18612
|
return addr || null;
|
|
18382
18613
|
}
|
|
@@ -686,8 +686,8 @@ function packageRoot() {
|
|
|
686
686
|
}
|
|
687
687
|
}
|
|
688
688
|
function studioCliVersion() {
|
|
689
|
-
if ("0.0.
|
|
690
|
-
return "0.0.
|
|
689
|
+
if ("0.0.12-alpha.1") {
|
|
690
|
+
return "0.0.12-alpha.1";
|
|
691
691
|
}
|
|
692
692
|
const file = path3.join(packageRoot(), "package.json");
|
|
693
693
|
const pkg = JSON.parse(fs3.readFileSync(file, "utf-8"));
|
package/dist/chunk-RO726HJG.js
CHANGED
|
File without changes
|
package/dist/chunk-U7IDQ3K5.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bnbagent/studio-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12-alpha.1",
|
|
4
4
|
"description": "Skills-first toolkit and bag CLI for BNB Chain seller agents: ERC-8004 identity, ERC-8183 escrowed commerce, and x402 payments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bnb-chain",
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
"directory": "packages/studio-cli"
|
|
26
26
|
},
|
|
27
27
|
"type": "module",
|
|
28
|
-
"packageManager": "pnpm@10.24.0",
|
|
29
28
|
"engines": {
|
|
30
29
|
"node": ">=22"
|
|
31
30
|
},
|
|
@@ -42,16 +41,8 @@
|
|
|
42
41
|
"bin": {
|
|
43
42
|
"bag": "./dist/bag.js"
|
|
44
43
|
},
|
|
45
|
-
"scripts": {
|
|
46
|
-
"build": "tsup",
|
|
47
|
-
"test": "vitest run",
|
|
48
|
-
"lint": "biome check src tests",
|
|
49
|
-
"typecheck": "tsc --noEmit",
|
|
50
|
-
"check": "pnpm typecheck && pnpm lint && pnpm test && pnpm build"
|
|
51
|
-
},
|
|
52
44
|
"dependencies": {
|
|
53
|
-
"@bnbagent/sdk": "0.5.
|
|
54
|
-
"@bnbagent/studio-runtime": "0.0.11",
|
|
45
|
+
"@bnbagent/sdk": "0.5.1-alpha.2",
|
|
55
46
|
"ai": "^7.0.29",
|
|
56
47
|
"archiver": "^8.0.0",
|
|
57
48
|
"commander": "^15.0.0",
|
|
@@ -62,7 +53,8 @@
|
|
|
62
53
|
"smol-toml": "^1.3.0",
|
|
63
54
|
"tar": "^7.4.0",
|
|
64
55
|
"viem": "^2.54.0",
|
|
65
|
-
"yaml": "^2.9.0"
|
|
56
|
+
"yaml": "^2.9.0",
|
|
57
|
+
"@bnbagent/studio-runtime": "0.0.12-alpha.1"
|
|
66
58
|
},
|
|
67
59
|
"devDependencies": {
|
|
68
60
|
"@a2a-js/sdk": "^0.3.14",
|
|
@@ -78,5 +70,12 @@
|
|
|
78
70
|
"typescript": "^5.5.0",
|
|
79
71
|
"vitest": "^2.0.0",
|
|
80
72
|
"zod": "^3.25.76"
|
|
73
|
+
},
|
|
74
|
+
"scripts": {
|
|
75
|
+
"build": "tsup",
|
|
76
|
+
"test": "vitest run",
|
|
77
|
+
"lint": "biome check src tests",
|
|
78
|
+
"typecheck": "tsc --noEmit",
|
|
79
|
+
"check": "pnpm typecheck && pnpm lint && pnpm test && pnpm build"
|
|
81
80
|
}
|
|
82
|
-
}
|
|
81
|
+
}
|
|
@@ -11,7 +11,7 @@ node = [
|
|
|
11
11
|
# neutral. The agent project's serving deps (@a2a-js/sdk / MCP SDK / ai)
|
|
12
12
|
# come from the runtimes/<R>/ recipe selected at `bag init` time.
|
|
13
13
|
"@bnbagent/studio-runtime",
|
|
14
|
-
"@bnbagent/sdk@0.5.
|
|
14
|
+
"@bnbagent/sdk@0.5.1-alpha.2",
|
|
15
15
|
]
|
|
16
16
|
|
|
17
17
|
[env]
|
|
@@ -32,7 +32,7 @@ node = [
|
|
|
32
32
|
# BNBAGENT_RUNTIME_SECRET_ID is set (default secretsmanager mode + platform).
|
|
33
33
|
"@aws-sdk/client-secrets-manager@^3.600.0",
|
|
34
34
|
"@bnbagent/studio-runtime",
|
|
35
|
-
"@bnbagent/sdk@0.5.
|
|
35
|
+
"@bnbagent/sdk@0.5.1-alpha.2",
|
|
36
36
|
# The LLM work hook (generateText + tools) and the model factory.
|
|
37
37
|
"ai@^7.0.29",
|
|
38
38
|
# Tool input schemas (AI SDK tools + MCP registerTool).
|
|
@@ -29,7 +29,7 @@ node = [
|
|
|
29
29
|
# on either cloud.
|
|
30
30
|
"@aws-sdk/client-secrets-manager@^3.600.0",
|
|
31
31
|
"@bnbagent/studio-runtime",
|
|
32
|
-
"@bnbagent/sdk@0.5.
|
|
32
|
+
"@bnbagent/sdk@0.5.1-alpha.2",
|
|
33
33
|
# The LLM work hook (generateText + tools) and the model factory
|
|
34
34
|
# (model.ts buildModel — studio.toml [llm] + the provider key env).
|
|
35
35
|
"ai@^7.0.29",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[recipe]
|
|
2
2
|
name = "wallet"
|
|
3
|
-
description = "Configures the agent's wallet: 'evm-local' (default encrypted keystore), 'twak' (Trust Wallet Agent Kit CLI),
|
|
3
|
+
description = "Configures the agent's wallet: 'evm-local' (default encrypted keystore), 'twak' (Trust Wallet Agent Kit CLI), 'altana' (encrypted admin keystore plus one bounded runtime session), or 'turnkey' (remote signer; the key lives in Turnkey's AWS Nitro enclave)."
|
|
4
4
|
|
|
5
5
|
[dependencies]
|
|
6
6
|
node = ["@bnbagent/studio-runtime"]
|
|
@@ -8,10 +8,15 @@ node = ["@bnbagent/studio-runtime"]
|
|
|
8
8
|
[dependencies.altana]
|
|
9
9
|
node = ["@altananetwork/sdk@0.5.1"]
|
|
10
10
|
|
|
11
|
+
[dependencies.turnkey]
|
|
12
|
+
node = ["@turnkey/sdk-server@8.1.0", "@turnkey/viem@0.14.34"]
|
|
13
|
+
|
|
11
14
|
[env]
|
|
12
15
|
# kind='twak': the twak CLI reads the unlock password from the environment —
|
|
13
16
|
# it never goes on a command line.
|
|
14
17
|
TWAK_WALLET_PASSWORD = "unlocks ~/.twak/wallet.json (twak kind); set in .studio/.env.local"
|
|
18
|
+
# kind='turnkey': P-256 API credential; the signing key never leaves Turnkey's enclave.
|
|
19
|
+
TURNKEY_API_PRIVATE_KEY = "Turnkey P-256 API private key (turnkey kind); set in .studio/.env.local"
|
|
15
20
|
# kind='evm-local' (the `bag init` default) or kind='altana' admin operations:
|
|
16
21
|
WALLET_PASSWORD = "set to a strong password (>= 12 chars); encrypts .studio/wallets/<addr>.json (runtime never receives it for altana)"
|
|
17
22
|
|