@bnbagent/studio-cli 0.0.6-alpha.3 → 0.0.6-alpha.5
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 +26 -0
- package/dist/{_twak-5XQMOFUC.js → _twak-4XF4H5PL.js} +1 -1
- package/dist/bag.js +983 -870
- package/dist/{chunk-7RAKL4AS.js → chunk-RO726HJG.js} +12 -9
- package/dist/{chunk-A7NAGZHR.js → chunk-VEOOFDSF.js} +76 -17
- package/dist/{deployCli-264UE6KB.js → deployCli-EEK75T67.js} +4 -2
- package/package.json +3 -2
- package/skills/references/bnbagent-studio-buying-via-8183.md +13 -5
- package/skills/references/bnbagent-studio-extending-signing.md +4 -1
- package/skills/references/bnbagent-studio-operating.md +3 -2
- package/skills/references/bnbagent-studio-scaffolding-agent.md +16 -12
- package/skills/references/bnbagent-studio-selling-via-b402.md +94 -54
- package/skills/references/bnbagent-studio-use-aws-agentcore.md +5 -2
- package/skills/references/bnbagent-studio-using-altana-wallet.md +1 -1
- package/skills/references/bnbagent-studio-using-twak-wallet.md +15 -12
package/dist/bag.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
B402_DEVELOPER_ACCOUNT_URL,
|
|
4
|
+
B402_PAID_ONBOARDING_GUIDANCE,
|
|
3
5
|
B402_RUNTIME_KEYS,
|
|
4
6
|
CliExit,
|
|
5
7
|
DEFAULT_B402_PRICE_USD,
|
|
@@ -42,7 +44,7 @@ import {
|
|
|
42
44
|
x402SellerIsFree,
|
|
43
45
|
x402SellerPricingState,
|
|
44
46
|
x402SellerUsesB402
|
|
45
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-VEOOFDSF.js";
|
|
46
48
|
import {
|
|
47
49
|
TWAK_CLI_MIN_VERSION,
|
|
48
50
|
TWAK_CLI_VERSION,
|
|
@@ -55,7 +57,7 @@ import {
|
|
|
55
57
|
twakVersionBelowFloor,
|
|
56
58
|
twakWalletFile,
|
|
57
59
|
whichTwak
|
|
58
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-RO726HJG.js";
|
|
59
61
|
import {
|
|
60
62
|
validateAgentcoreName
|
|
61
63
|
} from "./chunk-U7IDQ3K5.js";
|
|
@@ -104,7 +106,7 @@ import {
|
|
|
104
106
|
var CAMPAIGN_DOC_URL = "https://www.bnbchain.org/en/blog/bnb-agent-studio-is-live-on-bnb-chain-ai-agents-from-one-prompt";
|
|
105
107
|
var CAMPAIGN_CHECK_TIMEOUT_MS = 6e3;
|
|
106
108
|
async function fetchCampaignActive() {
|
|
107
|
-
const { bnbPlatformApiUrl: bnbPlatformApiUrl2 } = await import("./deployCli-
|
|
109
|
+
const { bnbPlatformApiUrl: bnbPlatformApiUrl2 } = await import("./deployCli-EEK75T67.js");
|
|
108
110
|
const controller = new AbortController();
|
|
109
111
|
const timer = setTimeout(() => controller.abort(), CAMPAIGN_CHECK_TIMEOUT_MS);
|
|
110
112
|
try {
|
|
@@ -2552,7 +2554,7 @@ function cmdListKeys(projectRoot) {
|
|
|
2552
2554
|
import * as fs37 from "fs";
|
|
2553
2555
|
import * as path37 from "path";
|
|
2554
2556
|
import {
|
|
2555
|
-
envLocalPath as
|
|
2557
|
+
envLocalPath as envLocalPath16,
|
|
2556
2558
|
findStudioWorkspaceRoot as findStudioWorkspaceRoot3,
|
|
2557
2559
|
findSubProjectRoot as findSubProjectRoot16,
|
|
2558
2560
|
loadStudioToml as loadStudioToml20
|
|
@@ -2987,24 +2989,24 @@ function hasIpfsEndpointFinding(result) {
|
|
|
2987
2989
|
}
|
|
2988
2990
|
|
|
2989
2991
|
// src/cli/_deploy/cognitoCdk.ts
|
|
2990
|
-
import * as
|
|
2991
|
-
import * as
|
|
2992
|
-
import { envLocalPath as
|
|
2992
|
+
import * as fs27 from "fs";
|
|
2993
|
+
import * as path26 from "path";
|
|
2994
|
+
import { envLocalPath as envLocalPath13 } from "@bnbagent/studio-runtime/config";
|
|
2993
2995
|
|
|
2994
2996
|
// src/cli/_deploy/secrets.ts
|
|
2995
|
-
import * as
|
|
2996
|
-
import * as
|
|
2997
|
+
import * as fs26 from "fs";
|
|
2998
|
+
import * as path25 from "path";
|
|
2997
2999
|
import {
|
|
2998
|
-
envLocalPath as
|
|
2999
|
-
findSubProjectRoot as
|
|
3000
|
-
loadStudioToml as
|
|
3000
|
+
envLocalPath as envLocalPath12,
|
|
3001
|
+
findSubProjectRoot as findSubProjectRoot8,
|
|
3002
|
+
loadStudioToml as loadStudioToml13
|
|
3001
3003
|
} from "@bnbagent/studio-runtime/config";
|
|
3002
3004
|
|
|
3003
3005
|
// src/cli/dev.ts
|
|
3004
|
-
import * as
|
|
3005
|
-
import * as
|
|
3006
|
-
import * as
|
|
3007
|
-
import { loadStudioToml as
|
|
3006
|
+
import * as fs24 from "fs";
|
|
3007
|
+
import * as os5 from "os";
|
|
3008
|
+
import * as path23 from "path";
|
|
3009
|
+
import { loadStudioToml as loadStudioToml11 } from "@bnbagent/studio-runtime/config";
|
|
3008
3010
|
import { getNetwork as getNetwork7 } from "@bnbagent/studio-runtime/networks";
|
|
3009
3011
|
import { writePrivate as writePrivate2 } from "@bnbagent/studio-runtime/secretWrite";
|
|
3010
3012
|
import { Option as Option3 } from "commander";
|
|
@@ -3078,6 +3080,20 @@ function migrateEnvLocal(start) {
|
|
|
3078
3080
|
} catch {
|
|
3079
3081
|
}
|
|
3080
3082
|
}
|
|
3083
|
+
var KEYSTORE_WALLET_KINDS = /* @__PURE__ */ new Set(["evm-local", "altana"]);
|
|
3084
|
+
function readWalletKind(agentRoot2) {
|
|
3085
|
+
try {
|
|
3086
|
+
const wallet = loadStudioToml5(path11.join(agentRoot2, "studio.toml")).wallet;
|
|
3087
|
+
if (wallet !== null && typeof wallet === "object") {
|
|
3088
|
+
const kind = wallet.kind;
|
|
3089
|
+
if (typeof kind === "string" && kind.trim()) {
|
|
3090
|
+
return kind.trim();
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
} catch {
|
|
3094
|
+
}
|
|
3095
|
+
return "evm-local";
|
|
3096
|
+
}
|
|
3081
3097
|
function resolveKeystoreDir(agentRoot2) {
|
|
3082
3098
|
let rel = ".studio/wallets";
|
|
3083
3099
|
try {
|
|
@@ -3110,6 +3126,9 @@ function migrateKeystoreOutOfCodelocation(start) {
|
|
|
3110
3126
|
}
|
|
3111
3127
|
fs12.rmSync(stash, { recursive: true, force: true });
|
|
3112
3128
|
}
|
|
3129
|
+
if (!KEYSTORE_WALLET_KINDS.has(readWalletKind(agentRoot2))) {
|
|
3130
|
+
return;
|
|
3131
|
+
}
|
|
3113
3132
|
const src = resolveKeystoreDir(agentRoot2);
|
|
3114
3133
|
const srcReal = realpathOr(src);
|
|
3115
3134
|
const agentReal = realpathOr(agentRoot2);
|
|
@@ -3173,25 +3192,274 @@ function relocateKeys(src, target, label) {
|
|
|
3173
3192
|
return true;
|
|
3174
3193
|
}
|
|
3175
3194
|
|
|
3195
|
+
// src/cli/_twakContractTargets.ts
|
|
3196
|
+
import { resolveNetwork } from "@bnbagent/sdk";
|
|
3197
|
+
var CONTRACT_OVERRIDES = [
|
|
3198
|
+
["ERC8004_REGISTRY_ADDRESS", "registryContract"],
|
|
3199
|
+
["ERC8183_COMMERCE_ADDRESS", "commerceContract"],
|
|
3200
|
+
["ERC8183_ROUTER_ADDRESS", "routerContract"],
|
|
3201
|
+
["ERC8183_POLICY_ADDRESS", "policyContract"]
|
|
3202
|
+
];
|
|
3203
|
+
function twakCustomContractOverrides(networkName, env = process.env) {
|
|
3204
|
+
let network;
|
|
3205
|
+
try {
|
|
3206
|
+
network = resolveNetwork(networkName);
|
|
3207
|
+
} catch {
|
|
3208
|
+
return [];
|
|
3209
|
+
}
|
|
3210
|
+
const erc8183 = erc8183ContractOverrideState(env);
|
|
3211
|
+
const out = [];
|
|
3212
|
+
for (const [envKey, field] of CONTRACT_OVERRIDES) {
|
|
3213
|
+
if (envKey.startsWith("ERC8183_") && erc8183.mode !== "custom") {
|
|
3214
|
+
continue;
|
|
3215
|
+
}
|
|
3216
|
+
const configured = env[envKey]?.trim() ?? "";
|
|
3217
|
+
if (!/^0x[0-9a-fA-F]{40}$/u.test(configured)) {
|
|
3218
|
+
continue;
|
|
3219
|
+
}
|
|
3220
|
+
const canonical = network[field];
|
|
3221
|
+
if (configured.toLowerCase() !== canonical.toLowerCase()) {
|
|
3222
|
+
out.push({ envKey, configured, canonical });
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
return out;
|
|
3226
|
+
}
|
|
3227
|
+
function twakUnsupportedContractOverrides(networkName, env = process.env) {
|
|
3228
|
+
return twakCustomContractOverrides(networkName, env).filter(
|
|
3229
|
+
(item) => item.envKey.startsWith("ERC8183_")
|
|
3230
|
+
);
|
|
3231
|
+
}
|
|
3232
|
+
|
|
3176
3233
|
// src/cli/init.ts
|
|
3177
|
-
import * as
|
|
3178
|
-
import * as
|
|
3179
|
-
import * as
|
|
3234
|
+
import * as fs23 from "fs";
|
|
3235
|
+
import * as os4 from "os";
|
|
3236
|
+
import * as path22 from "path";
|
|
3180
3237
|
import { getNetwork as getNetwork6 } from "@bnbagent/studio-runtime/networks";
|
|
3181
3238
|
import { ensureTwakKeychain } from "@bnbagent/studio-runtime/wallet";
|
|
3182
3239
|
import { Option as Option2 } from "commander";
|
|
3183
3240
|
import { parse as parseToml } from "smol-toml";
|
|
3184
3241
|
|
|
3185
|
-
// src/cli/
|
|
3242
|
+
// src/cli/_deploy/providers.ts
|
|
3186
3243
|
import * as fs13 from "fs";
|
|
3187
3244
|
import * as path12 from "path";
|
|
3245
|
+
import {
|
|
3246
|
+
findSubProjectRoot as findSubProjectRoot6,
|
|
3247
|
+
findWorkspaceRoot as findWorkspaceRoot4,
|
|
3248
|
+
loadStudioToml as loadStudioToml6
|
|
3249
|
+
} from "@bnbagent/studio-runtime/config";
|
|
3250
|
+
var PROVIDER_TARGETS = {
|
|
3251
|
+
bnb: "bnb/trial",
|
|
3252
|
+
aws: "aws/agentcore",
|
|
3253
|
+
azure: "azure/foundry"
|
|
3254
|
+
};
|
|
3255
|
+
var PROVIDER_LABELS = {
|
|
3256
|
+
bnb: "BNB Chain Trial",
|
|
3257
|
+
aws: "AWS AgentCore",
|
|
3258
|
+
azure: "Azure Foundry"
|
|
3259
|
+
};
|
|
3260
|
+
var PROVIDER_MENU_ORDER = [
|
|
3261
|
+
"bnb",
|
|
3262
|
+
"aws",
|
|
3263
|
+
"azure"
|
|
3264
|
+
];
|
|
3265
|
+
var PROVIDER_SHORT_LABELS = {
|
|
3266
|
+
bnb: "BNB",
|
|
3267
|
+
aws: "AWS",
|
|
3268
|
+
azure: "Azure"
|
|
3269
|
+
};
|
|
3270
|
+
function providerDigit(provider) {
|
|
3271
|
+
return PROVIDER_MENU_ORDER.indexOf(provider) + 1;
|
|
3272
|
+
}
|
|
3273
|
+
var ADVERTISED_PROVIDERS = ["bnb", "aws"];
|
|
3274
|
+
var ADVERTISED_PROVIDERS_HELP = ADVERTISED_PROVIDERS.join("|");
|
|
3275
|
+
function tableOf3(data, key) {
|
|
3276
|
+
const value = data[key];
|
|
3277
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
3278
|
+
}
|
|
3279
|
+
function text(value) {
|
|
3280
|
+
if (typeof value !== "string") return null;
|
|
3281
|
+
const clean = value.trim();
|
|
3282
|
+
return clean || null;
|
|
3283
|
+
}
|
|
3284
|
+
function descriptorName(workspaceRoot) {
|
|
3285
|
+
try {
|
|
3286
|
+
const data = JSON.parse(
|
|
3287
|
+
fs13.readFileSync(
|
|
3288
|
+
path12.join(workspaceRoot, "agentcore", "agentcore.json"),
|
|
3289
|
+
"utf-8"
|
|
3290
|
+
)
|
|
3291
|
+
);
|
|
3292
|
+
return text(data.name);
|
|
3293
|
+
} catch {
|
|
3294
|
+
return null;
|
|
3295
|
+
}
|
|
3296
|
+
}
|
|
3297
|
+
function discoverRecordedDeployments(root) {
|
|
3298
|
+
const workspaceRoot = findWorkspaceRoot4(root) ?? path12.resolve(root);
|
|
3299
|
+
const agentRoot2 = findSubProjectRoot6("agent", workspaceRoot);
|
|
3300
|
+
if (agentRoot2 === null) return [];
|
|
3301
|
+
let config;
|
|
3302
|
+
try {
|
|
3303
|
+
config = loadStudioToml6(path12.join(agentRoot2, "studio.toml"));
|
|
3304
|
+
} catch {
|
|
3305
|
+
return [];
|
|
3306
|
+
}
|
|
3307
|
+
const projectName2 = descriptorName(workspaceRoot) ?? text(tableOf3(config, "project").name) ?? path12.basename(workspaceRoot);
|
|
3308
|
+
const deploy = tableOf3(config, "deploy");
|
|
3309
|
+
const platform = tableOf3(deploy, "platform");
|
|
3310
|
+
const azure = tableOf3(config, "azure");
|
|
3311
|
+
const runtime = text(tableOf3(config, "stack").runtime) ?? "agentcore";
|
|
3312
|
+
const found = [];
|
|
3313
|
+
const bnbId = text(platform.deployment_id);
|
|
3314
|
+
const bnbEndpoint = text(platform.invoke_url);
|
|
3315
|
+
if (bnbId || bnbEndpoint || text(platform.last_deploy_at)) {
|
|
3316
|
+
found.push({
|
|
3317
|
+
provider: "bnb",
|
|
3318
|
+
target: PROVIDER_TARGETS.bnb,
|
|
3319
|
+
name: text(platform.slug) ?? projectName2,
|
|
3320
|
+
deploymentId: bnbId,
|
|
3321
|
+
endpoint: bnbEndpoint,
|
|
3322
|
+
status: "active"
|
|
3323
|
+
});
|
|
3324
|
+
}
|
|
3325
|
+
const awsArn = text(deploy.runtime_arn);
|
|
3326
|
+
const awsEndpoint = text(deploy.invoke_url);
|
|
3327
|
+
const legacyAwsTimestamp = Boolean(text(deploy.last_deploy_at)) && runtime !== "azure-foundry" && text(deploy.destination) !== "platform";
|
|
3328
|
+
if (awsArn || awsEndpoint || text(deploy.provider) === "aws" || legacyAwsTimestamp) {
|
|
3329
|
+
found.push({
|
|
3330
|
+
provider: "aws",
|
|
3331
|
+
target: PROVIDER_TARGETS.aws,
|
|
3332
|
+
name: projectName2,
|
|
3333
|
+
deploymentId: awsArn,
|
|
3334
|
+
endpoint: awsEndpoint,
|
|
3335
|
+
status: "active"
|
|
3336
|
+
});
|
|
3337
|
+
}
|
|
3338
|
+
const azureEndpoint = text(azure.agent_endpoint);
|
|
3339
|
+
const azureDeploymentId = text(azure.deployment_id);
|
|
3340
|
+
if (azureEndpoint || azureDeploymentId || text(azure.last_deploy_at)) {
|
|
3341
|
+
found.push({
|
|
3342
|
+
provider: "azure",
|
|
3343
|
+
target: PROVIDER_TARGETS.azure,
|
|
3344
|
+
name: text(azure.agent_name) ?? projectName2,
|
|
3345
|
+
deploymentId: azureDeploymentId,
|
|
3346
|
+
endpoint: azureEndpoint,
|
|
3347
|
+
status: "active"
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3350
|
+
return found;
|
|
3351
|
+
}
|
|
3352
|
+
function unavailableProvidersForProject(root) {
|
|
3353
|
+
const workspaceRoot = findWorkspaceRoot4(root) ?? path12.resolve(root);
|
|
3354
|
+
const agentRoot2 = findSubProjectRoot6("agent", workspaceRoot);
|
|
3355
|
+
if (agentRoot2 === null) return {};
|
|
3356
|
+
let runtime = "agentcore";
|
|
3357
|
+
let azureProtocolUnsupported = false;
|
|
3358
|
+
try {
|
|
3359
|
+
const cfg = loadStudioToml6(path12.join(agentRoot2, "studio.toml"));
|
|
3360
|
+
runtime = text(tableOf3(cfg, "stack").runtime) ?? "agentcore";
|
|
3361
|
+
const faces = stackFaces(tableOf3(cfg, "stack"), tableOf3(cfg, "payments"));
|
|
3362
|
+
azureProtocolUnsupported = !hasA2aFace(faces) || hasMcpFace(faces);
|
|
3363
|
+
} catch {
|
|
3364
|
+
return {};
|
|
3365
|
+
}
|
|
3366
|
+
if (runtime === "azure-foundry") {
|
|
3367
|
+
const reason = "this project uses a different container adapter; scaffold an agentcore project before selecting this provider";
|
|
3368
|
+
return {
|
|
3369
|
+
bnb: reason,
|
|
3370
|
+
aws: reason,
|
|
3371
|
+
...azureProtocolUnsupported ? {
|
|
3372
|
+
azure: "Azure Foundry deploy currently supports A2A projects only; use an A2A azure-foundry scaffold or AgentCore for MCP"
|
|
3373
|
+
} : {}
|
|
3374
|
+
};
|
|
3375
|
+
}
|
|
3376
|
+
return {
|
|
3377
|
+
azure: "this project uses the agentcore adapter; scaffold with --runtime azure-foundry before selecting Azure"
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
function selected(provider, deployments) {
|
|
3381
|
+
const active = deployments.filter((d) => d.status === "active");
|
|
3382
|
+
return {
|
|
3383
|
+
kind: "selected",
|
|
3384
|
+
provider,
|
|
3385
|
+
operation: active.some((d) => d.provider === provider) ? "update" : "create",
|
|
3386
|
+
hasOtherActive: active.some((d) => d.provider !== provider)
|
|
3387
|
+
};
|
|
3388
|
+
}
|
|
3389
|
+
function trialExpired(trial) {
|
|
3390
|
+
return trial.state.toLowerCase() === "expired";
|
|
3391
|
+
}
|
|
3392
|
+
function unavailableReason(opts, provider) {
|
|
3393
|
+
if (provider === "bnb" && trialExpired(opts.trial)) {
|
|
3394
|
+
return "the 48h trial has expired";
|
|
3395
|
+
}
|
|
3396
|
+
return opts.unavailable?.[provider] ?? null;
|
|
3397
|
+
}
|
|
3398
|
+
function providerPromptHint() {
|
|
3399
|
+
return PROVIDER_MENU_ORDER.filter((p) => ADVERTISED_PROVIDERS.includes(p)).map((p) => `${providerDigit(p)}=${PROVIDER_SHORT_LABELS[p]}`).join(", ");
|
|
3400
|
+
}
|
|
3401
|
+
async function promptProvider(opts) {
|
|
3402
|
+
for (; ; ) {
|
|
3403
|
+
const answer = (await opts.prompt(`Provider [${providerPromptHint()}]: `)).trim().toLowerCase();
|
|
3404
|
+
const provider = answer === "1" || answer === "bnb" ? "bnb" : answer === "2" || answer === "aws" ? "aws" : answer === "3" || answer === "azure" ? "azure" : null;
|
|
3405
|
+
if (provider === null) {
|
|
3406
|
+
if (answer === "" || answer === "q" || answer === "cancel") {
|
|
3407
|
+
return { kind: "cancelled", exitCode: 1 };
|
|
3408
|
+
}
|
|
3409
|
+
continue;
|
|
3410
|
+
}
|
|
3411
|
+
if (unavailableReason(opts, provider)) {
|
|
3412
|
+
continue;
|
|
3413
|
+
}
|
|
3414
|
+
return selected(provider, opts.deployments);
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
async function selectDeployProvider(opts) {
|
|
3418
|
+
if (opts.requested) {
|
|
3419
|
+
const reason = unavailableReason(opts, opts.requested);
|
|
3420
|
+
if (reason) {
|
|
3421
|
+
return {
|
|
3422
|
+
kind: "unavailable",
|
|
3423
|
+
provider: opts.requested,
|
|
3424
|
+
reason,
|
|
3425
|
+
exitCode: 2
|
|
3426
|
+
};
|
|
3427
|
+
}
|
|
3428
|
+
return selected(opts.requested, opts.deployments);
|
|
3429
|
+
}
|
|
3430
|
+
if (!opts.interactive) {
|
|
3431
|
+
return { kind: "selection_required", exitCode: 2 };
|
|
3432
|
+
}
|
|
3433
|
+
const active = opts.deployments.filter((d) => d.status === "active");
|
|
3434
|
+
const activeDeployment = active[0];
|
|
3435
|
+
if (active.length === 1 && activeDeployment) {
|
|
3436
|
+
if (unavailableReason(opts, activeDeployment.provider)) {
|
|
3437
|
+
return promptProvider(opts);
|
|
3438
|
+
}
|
|
3439
|
+
const answer = (await opts.prompt(
|
|
3440
|
+
`Update the existing ${PROVIDER_LABELS[activeDeployment.provider]} deployment? [1=update, 2=another provider, 3=cancel]: `
|
|
3441
|
+
)).trim().toLowerCase();
|
|
3442
|
+
if (answer === "1" || answer === "update" || answer === "yes") {
|
|
3443
|
+
return selected(activeDeployment.provider, opts.deployments);
|
|
3444
|
+
}
|
|
3445
|
+
if (answer === "2" || answer === "another") {
|
|
3446
|
+
return promptProvider(opts);
|
|
3447
|
+
}
|
|
3448
|
+
return { kind: "cancelled", exitCode: 1 };
|
|
3449
|
+
}
|
|
3450
|
+
return promptProvider(opts);
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
// src/cli/_packageMetadata.ts
|
|
3454
|
+
import * as fs14 from "fs";
|
|
3455
|
+
import * as path13 from "path";
|
|
3188
3456
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3189
3457
|
function packageRoot() {
|
|
3190
|
-
let dir =
|
|
3458
|
+
let dir = path13.dirname(fileURLToPath2(import.meta.url));
|
|
3191
3459
|
for (; ; ) {
|
|
3192
|
-
const packageJson =
|
|
3193
|
-
if (
|
|
3194
|
-
const parent =
|
|
3460
|
+
const packageJson = path13.join(dir, "package.json");
|
|
3461
|
+
if (fs14.existsSync(packageJson)) return dir;
|
|
3462
|
+
const parent = path13.dirname(dir);
|
|
3195
3463
|
if (parent === dir) {
|
|
3196
3464
|
throw new Error("cannot locate the studio-cli package root");
|
|
3197
3465
|
}
|
|
@@ -3202,8 +3470,8 @@ function pnpmVersion() {
|
|
|
3202
3470
|
if ("10.24.0") {
|
|
3203
3471
|
return "10.24.0";
|
|
3204
3472
|
}
|
|
3205
|
-
const file =
|
|
3206
|
-
const pkg = JSON.parse(
|
|
3473
|
+
const file = path13.join(packageRoot(), "package.json");
|
|
3474
|
+
const pkg = JSON.parse(fs14.readFileSync(file, "utf-8"));
|
|
3207
3475
|
const value = String(pkg.packageManager ?? "");
|
|
3208
3476
|
const match = /^pnpm@(.+)$/u.exec(value);
|
|
3209
3477
|
if (!match?.[1]) {
|
|
@@ -3216,67 +3484,27 @@ function pnpmVersion() {
|
|
|
3216
3484
|
|
|
3217
3485
|
// src/cli/_runtime/azureFoundry.ts
|
|
3218
3486
|
import * as crypto2 from "crypto";
|
|
3219
|
-
import * as
|
|
3220
|
-
import * as
|
|
3487
|
+
import * as fs17 from "fs";
|
|
3488
|
+
import * as path16 from "path";
|
|
3221
3489
|
import {
|
|
3222
3490
|
findStudioWorkspaceRoot,
|
|
3223
|
-
findSubProjectRoot as
|
|
3224
|
-
loadStudioToml as
|
|
3491
|
+
findSubProjectRoot as findSubProjectRoot7,
|
|
3492
|
+
loadStudioToml as loadStudioToml7
|
|
3225
3493
|
} from "@bnbagent/studio-runtime/config";
|
|
3226
3494
|
import { resolveProviderConfig } from "@bnbagent/studio-runtime/llm";
|
|
3227
3495
|
|
|
3228
3496
|
// src/cli/_deploy/checks/twak.ts
|
|
3229
|
-
import * as
|
|
3230
|
-
import * as
|
|
3497
|
+
import * as fs15 from "fs";
|
|
3498
|
+
import * as path14 from "path";
|
|
3231
3499
|
import { envLocalPath as envLocalPath7 } from "@bnbagent/studio-runtime/config";
|
|
3232
3500
|
import { resolveTwakHome } from "@bnbagent/studio-runtime/wallet";
|
|
3233
|
-
|
|
3234
|
-
// src/cli/_twakContractTargets.ts
|
|
3235
|
-
import { resolveNetwork } from "@bnbagent/sdk";
|
|
3236
|
-
var CONTRACT_OVERRIDES = [
|
|
3237
|
-
["ERC8004_REGISTRY_ADDRESS", "registryContract"],
|
|
3238
|
-
["ERC8183_COMMERCE_ADDRESS", "commerceContract"],
|
|
3239
|
-
["ERC8183_ROUTER_ADDRESS", "routerContract"],
|
|
3240
|
-
["ERC8183_POLICY_ADDRESS", "policyContract"]
|
|
3241
|
-
];
|
|
3242
|
-
function twakCustomContractOverrides(networkName, env = process.env) {
|
|
3243
|
-
let network;
|
|
3244
|
-
try {
|
|
3245
|
-
network = resolveNetwork(networkName);
|
|
3246
|
-
} catch {
|
|
3247
|
-
return [];
|
|
3248
|
-
}
|
|
3249
|
-
const erc8183 = erc8183ContractOverrideState(env);
|
|
3250
|
-
const out = [];
|
|
3251
|
-
for (const [envKey, field] of CONTRACT_OVERRIDES) {
|
|
3252
|
-
if (envKey.startsWith("ERC8183_") && erc8183.mode !== "custom") {
|
|
3253
|
-
continue;
|
|
3254
|
-
}
|
|
3255
|
-
const configured = env[envKey]?.trim() ?? "";
|
|
3256
|
-
if (!/^0x[0-9a-fA-F]{40}$/u.test(configured)) {
|
|
3257
|
-
continue;
|
|
3258
|
-
}
|
|
3259
|
-
const canonical = network[field];
|
|
3260
|
-
if (configured.toLowerCase() !== canonical.toLowerCase()) {
|
|
3261
|
-
out.push({ envKey, configured, canonical });
|
|
3262
|
-
}
|
|
3263
|
-
}
|
|
3264
|
-
return out;
|
|
3265
|
-
}
|
|
3266
|
-
function twakUnsupportedContractOverrides(networkName, env = process.env) {
|
|
3267
|
-
return twakCustomContractOverrides(networkName, env).filter(
|
|
3268
|
-
(item) => item.envKey.startsWith("ERC8183_")
|
|
3269
|
-
);
|
|
3270
|
-
}
|
|
3271
|
-
|
|
3272
|
-
// src/cli/_deploy/checks/twak.ts
|
|
3273
|
-
var AGENTCORE_DESCRIPTOR = path13.join("agentcore", "agentcore.json");
|
|
3501
|
+
var AGENTCORE_DESCRIPTOR = path14.join("agentcore", "agentcore.json");
|
|
3274
3502
|
function isTwak(data) {
|
|
3275
3503
|
return tableOf2(data, "wallet").kind === "twak";
|
|
3276
3504
|
}
|
|
3277
3505
|
function isFile4(p) {
|
|
3278
3506
|
try {
|
|
3279
|
-
return
|
|
3507
|
+
return fs15.statSync(p).isFile();
|
|
3280
3508
|
} catch {
|
|
3281
3509
|
return false;
|
|
3282
3510
|
}
|
|
@@ -3289,13 +3517,13 @@ async function checkTwakRequiresContainer(root, target) {
|
|
|
3289
3517
|
if (!isTwak(data)) {
|
|
3290
3518
|
return [];
|
|
3291
3519
|
}
|
|
3292
|
-
const descriptor =
|
|
3520
|
+
const descriptor = path14.join(root, AGENTCORE_DESCRIPTOR);
|
|
3293
3521
|
if (!isFile4(descriptor)) {
|
|
3294
3522
|
return [];
|
|
3295
3523
|
}
|
|
3296
3524
|
let cfg;
|
|
3297
3525
|
try {
|
|
3298
|
-
cfg = JSON.parse(
|
|
3526
|
+
cfg = JSON.parse(fs15.readFileSync(descriptor, "utf-8"));
|
|
3299
3527
|
} catch {
|
|
3300
3528
|
return [];
|
|
3301
3529
|
}
|
|
@@ -3318,7 +3546,7 @@ async function checkTwakRequiresContainer(root, target) {
|
|
|
3318
3546
|
}
|
|
3319
3547
|
];
|
|
3320
3548
|
}
|
|
3321
|
-
const dockerfile =
|
|
3549
|
+
const dockerfile = path14.join(agentRootOf(root), "Dockerfile");
|
|
3322
3550
|
if (!isFile4(dockerfile)) {
|
|
3323
3551
|
return [
|
|
3324
3552
|
{
|
|
@@ -3405,7 +3633,7 @@ async function checkTwakWalletExists(root, _target) {
|
|
|
3405
3633
|
if (!isFile4(walletFile)) {
|
|
3406
3634
|
let createCmd = "twak wallet create --password <pw> --no-keychain";
|
|
3407
3635
|
if (walletCfg.twak_home) {
|
|
3408
|
-
createCmd = `HOME=${
|
|
3636
|
+
createCmd = `HOME=${path14.dirname(path14.dirname(walletFile))} ${createCmd}`;
|
|
3409
3637
|
}
|
|
3410
3638
|
return [
|
|
3411
3639
|
{
|
|
@@ -3527,8 +3755,8 @@ async function checkTwakCredentialsAvailable(root, _target) {
|
|
|
3527
3755
|
}
|
|
3528
3756
|
const agentRoot2 = agentRootOf(root);
|
|
3529
3757
|
const walletCfg = tableOf2(data, "wallet");
|
|
3530
|
-
const credentialsFile =
|
|
3531
|
-
|
|
3758
|
+
const credentialsFile = path14.join(
|
|
3759
|
+
path14.dirname(twakWalletFile(walletCfg, agentRoot2)),
|
|
3532
3760
|
"credentials.json"
|
|
3533
3761
|
);
|
|
3534
3762
|
const envLocal = envLocalPath7(agentRoot2);
|
|
@@ -3550,21 +3778,21 @@ async function checkTwakCredentialsAvailable(root, _target) {
|
|
|
3550
3778
|
}
|
|
3551
3779
|
|
|
3552
3780
|
// src/cli/_deploy/fixes.ts
|
|
3553
|
-
import * as
|
|
3554
|
-
import * as
|
|
3781
|
+
import * as fs16 from "fs";
|
|
3782
|
+
import * as path15 from "path";
|
|
3555
3783
|
import { envLocalPath as envLocalPath8 } from "@bnbagent/studio-runtime/config";
|
|
3556
3784
|
function fixGitignore(root) {
|
|
3557
|
-
const ws =
|
|
3558
|
-
const gi =
|
|
3785
|
+
const ws = path15.dirname(path15.dirname(envLocalPath8(root)));
|
|
3786
|
+
const gi = path15.join(ws, ".gitignore");
|
|
3559
3787
|
const required = [".studio/"];
|
|
3560
3788
|
let exists = false;
|
|
3561
3789
|
try {
|
|
3562
|
-
exists =
|
|
3790
|
+
exists = fs16.statSync(gi).isFile();
|
|
3563
3791
|
} catch {
|
|
3564
3792
|
exists = false;
|
|
3565
3793
|
}
|
|
3566
3794
|
if (!exists) {
|
|
3567
|
-
|
|
3795
|
+
fs16.writeFileSync(gi, `${required.join("\n")}
|
|
3568
3796
|
`, "utf-8");
|
|
3569
3797
|
return {
|
|
3570
3798
|
name: "fix-gitignore",
|
|
@@ -3572,7 +3800,7 @@ function fixGitignore(root) {
|
|
|
3572
3800
|
message: `created .gitignore with ${required.length} entries`
|
|
3573
3801
|
};
|
|
3574
3802
|
}
|
|
3575
|
-
let text2 =
|
|
3803
|
+
let text2 = fs16.readFileSync(gi, "utf-8");
|
|
3576
3804
|
const existing = new Set(text2.split(/\r?\n/).map((l) => l.trim()));
|
|
3577
3805
|
const appended = required.filter((r) => !existing.has(r));
|
|
3578
3806
|
if (appended.length === 0) {
|
|
@@ -3587,7 +3815,7 @@ function fixGitignore(root) {
|
|
|
3587
3815
|
}
|
|
3588
3816
|
text2 += `${appended.join("\n")}
|
|
3589
3817
|
`;
|
|
3590
|
-
|
|
3818
|
+
fs16.writeFileSync(gi, text2, "utf-8");
|
|
3591
3819
|
return {
|
|
3592
3820
|
name: "fix-gitignore",
|
|
3593
3821
|
changed: true,
|
|
@@ -3595,10 +3823,10 @@ function fixGitignore(root) {
|
|
|
3595
3823
|
};
|
|
3596
3824
|
}
|
|
3597
3825
|
function patchTomlKv(tomlPath, section, key, value) {
|
|
3598
|
-
const text2 =
|
|
3826
|
+
const text2 = fs16.readFileSync(tomlPath, "utf-8");
|
|
3599
3827
|
const updated = updateSection(text2, section, { [key]: value });
|
|
3600
3828
|
if (updated !== text2) {
|
|
3601
|
-
|
|
3829
|
+
fs16.writeFileSync(tomlPath, updated, "utf-8");
|
|
3602
3830
|
}
|
|
3603
3831
|
}
|
|
3604
3832
|
|
|
@@ -3631,12 +3859,12 @@ var HOSTED_AGENT_REGIONS = /* @__PURE__ */ new Set([
|
|
|
3631
3859
|
]);
|
|
3632
3860
|
function isFile5(p) {
|
|
3633
3861
|
try {
|
|
3634
|
-
return
|
|
3862
|
+
return fs17.statSync(p).isFile();
|
|
3635
3863
|
} catch {
|
|
3636
3864
|
return false;
|
|
3637
3865
|
}
|
|
3638
3866
|
}
|
|
3639
|
-
function
|
|
3867
|
+
function tableOf4(cfg, key) {
|
|
3640
3868
|
const v = cfg[key];
|
|
3641
3869
|
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
3642
3870
|
}
|
|
@@ -3644,26 +3872,26 @@ function deployWorkspaceRoot(root) {
|
|
|
3644
3872
|
return findStudioWorkspaceRoot(root) ?? root;
|
|
3645
3873
|
}
|
|
3646
3874
|
function loadStudioCfg(workspaceRoot) {
|
|
3647
|
-
const agentRoot2 =
|
|
3875
|
+
const agentRoot2 = findSubProjectRoot7("agent", workspaceRoot);
|
|
3648
3876
|
if (agentRoot2 === null) {
|
|
3649
3877
|
return {};
|
|
3650
3878
|
}
|
|
3651
|
-
const tomlPath =
|
|
3879
|
+
const tomlPath = path16.join(agentRoot2, "studio.toml");
|
|
3652
3880
|
if (!isFile5(tomlPath)) {
|
|
3653
3881
|
return {};
|
|
3654
3882
|
}
|
|
3655
3883
|
try {
|
|
3656
|
-
return
|
|
3884
|
+
return loadStudioToml7(tomlPath);
|
|
3657
3885
|
} catch {
|
|
3658
3886
|
return {};
|
|
3659
3887
|
}
|
|
3660
3888
|
}
|
|
3661
3889
|
function recordAzureDeployment(root, data, endpoint) {
|
|
3662
|
-
const agentRoot2 =
|
|
3890
|
+
const agentRoot2 = findSubProjectRoot7("agent", deployWorkspaceRoot(root));
|
|
3663
3891
|
if (agentRoot2 === null) return;
|
|
3664
|
-
const tomlPath =
|
|
3892
|
+
const tomlPath = path16.join(agentRoot2, "studio.toml");
|
|
3665
3893
|
try {
|
|
3666
|
-
const name = String(data.id ??
|
|
3894
|
+
const name = String(data.id ?? tableOf4(data, "record").id ?? "").trim();
|
|
3667
3895
|
if (name) {
|
|
3668
3896
|
patchTomlKv(tomlPath, "azure", "agent_name", name);
|
|
3669
3897
|
patchTomlKv(tomlPath, "azure", "deployment_id", name);
|
|
@@ -3677,9 +3905,9 @@ function recordAzureDeployment(root, data, endpoint) {
|
|
|
3677
3905
|
}
|
|
3678
3906
|
}
|
|
3679
3907
|
function clearAzureEndpoint(root) {
|
|
3680
|
-
const agentRoot2 =
|
|
3908
|
+
const agentRoot2 = findSubProjectRoot7("agent", deployWorkspaceRoot(root));
|
|
3681
3909
|
if (agentRoot2 === null) return;
|
|
3682
|
-
const tomlPath =
|
|
3910
|
+
const tomlPath = path16.join(agentRoot2, "studio.toml");
|
|
3683
3911
|
try {
|
|
3684
3912
|
for (const key of [
|
|
3685
3913
|
"agent_endpoint",
|
|
@@ -3706,7 +3934,7 @@ function collectAzureSecretPayload(root) {
|
|
|
3706
3934
|
const payload = collectRuntimeSecrets(root);
|
|
3707
3935
|
try {
|
|
3708
3936
|
const providerCfg = resolveProviderConfig(
|
|
3709
|
-
|
|
3937
|
+
tableOf4(loadStudioCfg(root), "llm")
|
|
3710
3938
|
);
|
|
3711
3939
|
if (providerCfg.baseUrl) {
|
|
3712
3940
|
payload[LLM_BASE_URL_ENV] = providerCfg.baseUrl;
|
|
@@ -3723,7 +3951,7 @@ function stripLeadingDdash(args) {
|
|
|
3723
3951
|
return args[0] === "--" ? [...args.slice(1)] : [...args];
|
|
3724
3952
|
}
|
|
3725
3953
|
function recordOf(data) {
|
|
3726
|
-
return
|
|
3954
|
+
return tableOf4(data, "record");
|
|
3727
3955
|
}
|
|
3728
3956
|
async function deployAzureFoundry(opts) {
|
|
3729
3957
|
const root = opts.projectRoot;
|
|
@@ -3798,7 +4026,7 @@ async function destroyAzureFoundry(opts) {
|
|
|
3798
4026
|
const extra = opts.purge ? " --purge" : "";
|
|
3799
4027
|
printOut("=== bag deploy destroy \u2014 teardown plan (dry-run) ===\n");
|
|
3800
4028
|
printOut(
|
|
3801
|
-
`project: ${
|
|
4029
|
+
`project: ${path16.basename(workspaceRoot)} (runtime: azure-foundry)
|
|
3802
4030
|
`
|
|
3803
4031
|
);
|
|
3804
4032
|
printOut("--- Agent (Foundry Hosted Agent) ---");
|
|
@@ -3837,11 +4065,11 @@ async function destroyAzureFoundry(opts) {
|
|
|
3837
4065
|
}
|
|
3838
4066
|
var OPENAI_COMPATIBLE_PROVIDERS = ["openai", "openrouter", "pieverse-llm"];
|
|
3839
4067
|
function agentTomlPath(root) {
|
|
3840
|
-
const agentRoot2 =
|
|
4068
|
+
const agentRoot2 = findSubProjectRoot7("agent", root);
|
|
3841
4069
|
if (agentRoot2 === null) {
|
|
3842
4070
|
return null;
|
|
3843
4071
|
}
|
|
3844
|
-
const tomlPath =
|
|
4072
|
+
const tomlPath = path16.join(agentRoot2, "studio.toml");
|
|
3845
4073
|
return isFile5(tomlPath) ? tomlPath : null;
|
|
3846
4074
|
}
|
|
3847
4075
|
function checkAzureBlock(root) {
|
|
@@ -3851,7 +4079,7 @@ function checkAzureBlock(root) {
|
|
|
3851
4079
|
}
|
|
3852
4080
|
let cfg;
|
|
3853
4081
|
try {
|
|
3854
|
-
cfg =
|
|
4082
|
+
cfg = loadStudioToml7(tomlPath);
|
|
3855
4083
|
} catch {
|
|
3856
4084
|
return null;
|
|
3857
4085
|
}
|
|
@@ -3865,7 +4093,7 @@ var checkStackRuntimeAzure = async (root, _target) => {
|
|
|
3865
4093
|
}
|
|
3866
4094
|
let cfg;
|
|
3867
4095
|
try {
|
|
3868
|
-
cfg =
|
|
4096
|
+
cfg = loadStudioToml7(tomlPath);
|
|
3869
4097
|
} catch (exc) {
|
|
3870
4098
|
return [
|
|
3871
4099
|
{
|
|
@@ -3875,7 +4103,7 @@ var checkStackRuntimeAzure = async (root, _target) => {
|
|
|
3875
4103
|
}
|
|
3876
4104
|
];
|
|
3877
4105
|
}
|
|
3878
|
-
const runtime = String(
|
|
4106
|
+
const runtime = String(tableOf4(cfg, "stack").runtime ?? "").trim();
|
|
3879
4107
|
if (runtime !== "azure-foundry") {
|
|
3880
4108
|
return [
|
|
3881
4109
|
{
|
|
@@ -3957,13 +4185,13 @@ var checkAccountEqualsSubdomain = async (root, _target) => {
|
|
|
3957
4185
|
return [];
|
|
3958
4186
|
};
|
|
3959
4187
|
var checkEntrypointAndDockerfile = async (root, _target) => {
|
|
3960
|
-
const agentRoot2 =
|
|
4188
|
+
const agentRoot2 = findSubProjectRoot7("agent", root);
|
|
3961
4189
|
if (agentRoot2 === null) {
|
|
3962
4190
|
return [];
|
|
3963
4191
|
}
|
|
3964
4192
|
const findings = [];
|
|
3965
4193
|
const cfg = loadStudioCfg(deployWorkspaceRoot(root));
|
|
3966
|
-
const faces = stackFaces(
|
|
4194
|
+
const faces = stackFaces(tableOf4(cfg, "stack"), tableOf4(cfg, "payments"));
|
|
3967
4195
|
if (!hasA2aFace(faces) || hasMcpFace(faces)) {
|
|
3968
4196
|
return [
|
|
3969
4197
|
{
|
|
@@ -3975,7 +4203,7 @@ var checkEntrypointAndDockerfile = async (root, _target) => {
|
|
|
3975
4203
|
];
|
|
3976
4204
|
}
|
|
3977
4205
|
const entry = "src/foundryMain.ts";
|
|
3978
|
-
if (!isFile5(
|
|
4206
|
+
if (!isFile5(path16.join(agentRoot2, entry))) {
|
|
3979
4207
|
findings.push({
|
|
3980
4208
|
level: "CRITICAL",
|
|
3981
4209
|
name: "azure_agent_entrypoint",
|
|
@@ -3983,7 +4211,7 @@ var checkEntrypointAndDockerfile = async (root, _target) => {
|
|
|
3983
4211
|
details: { entrypoint: entry }
|
|
3984
4212
|
});
|
|
3985
4213
|
}
|
|
3986
|
-
if (!isFile5(
|
|
4214
|
+
if (!isFile5(path16.join(agentRoot2, "Dockerfile"))) {
|
|
3987
4215
|
findings.push({
|
|
3988
4216
|
level: "CRITICAL",
|
|
3989
4217
|
name: "azure_dockerfile_present",
|
|
@@ -3999,7 +4227,7 @@ var checkLlmExternalProviderReady = async (root, _target) => {
|
|
|
3999
4227
|
}
|
|
4000
4228
|
let cfg;
|
|
4001
4229
|
try {
|
|
4002
|
-
cfg =
|
|
4230
|
+
cfg = loadStudioToml7(tomlPath);
|
|
4003
4231
|
} catch {
|
|
4004
4232
|
return [];
|
|
4005
4233
|
}
|
|
@@ -4033,13 +4261,13 @@ var azureFoundryChecks = [
|
|
|
4033
4261
|
];
|
|
4034
4262
|
|
|
4035
4263
|
// src/cli/llm.ts
|
|
4036
|
-
import * as
|
|
4037
|
-
import * as
|
|
4264
|
+
import * as fs18 from "fs";
|
|
4265
|
+
import * as path17 from "path";
|
|
4038
4266
|
import { query as auditQuery, auditedOp } from "@bnbagent/studio-runtime/audit";
|
|
4039
4267
|
import {
|
|
4040
4268
|
envLocalPath as envLocalPath9,
|
|
4041
4269
|
findProjectRoot as findProjectRoot2,
|
|
4042
|
-
loadStudioToml as
|
|
4270
|
+
loadStudioToml as loadStudioToml8
|
|
4043
4271
|
} from "@bnbagent/studio-runtime/config";
|
|
4044
4272
|
import {
|
|
4045
4273
|
pieverseKeyHash,
|
|
@@ -4076,12 +4304,12 @@ function isErrorNamed(exc, name) {
|
|
|
4076
4304
|
function errMessage(exc) {
|
|
4077
4305
|
return exc instanceof Error ? exc.message : String(exc);
|
|
4078
4306
|
}
|
|
4079
|
-
function
|
|
4307
|
+
function tableOf5(cfg, key) {
|
|
4080
4308
|
const v = cfg[key];
|
|
4081
4309
|
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
4082
4310
|
}
|
|
4083
4311
|
function ensurePieverseProvider(cfg) {
|
|
4084
|
-
const provider =
|
|
4312
|
+
const provider = tableOf5(cfg, "llm").provider;
|
|
4085
4313
|
if (provider !== "pieverse-llm") {
|
|
4086
4314
|
const shown = provider === void 0 || provider === null ? "None" : `'${String(provider)}'`;
|
|
4087
4315
|
throw new PieverseCliError(
|
|
@@ -4090,7 +4318,7 @@ function ensurePieverseProvider(cfg) {
|
|
|
4090
4318
|
}
|
|
4091
4319
|
}
|
|
4092
4320
|
function loadPieverseConfig(cfg) {
|
|
4093
|
-
return { ...
|
|
4321
|
+
return { ...tableOf5(tableOf5(cfg, "llm"), "pieverse") };
|
|
4094
4322
|
}
|
|
4095
4323
|
function resolvePieverseNetwork(cfg, networkOverride) {
|
|
4096
4324
|
if (networkOverride) {
|
|
@@ -4100,7 +4328,7 @@ function resolvePieverseNetwork(cfg, networkOverride) {
|
|
|
4100
4328
|
if (pvCfg.network) {
|
|
4101
4329
|
return String(pvCfg.network);
|
|
4102
4330
|
}
|
|
4103
|
-
const projectDefault =
|
|
4331
|
+
const projectDefault = tableOf5(cfg, "network").default;
|
|
4104
4332
|
return projectDefault ? String(projectDefault) : "bsc-mainnet";
|
|
4105
4333
|
}
|
|
4106
4334
|
function printUBalanceShortfall(walletAddress, currentRaw, neededRaw, neededUsd, networkName) {
|
|
@@ -4149,7 +4377,7 @@ var API_KEY_ENV = {
|
|
|
4149
4377
|
// uses AWS credentials chain, no single env var
|
|
4150
4378
|
};
|
|
4151
4379
|
var PIEVERSE_ENV_KEY = "PIEVERSE_LLM_API_KEY";
|
|
4152
|
-
function
|
|
4380
|
+
function tableOf6(cfg, key) {
|
|
4153
4381
|
const v = cfg[key];
|
|
4154
4382
|
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
4155
4383
|
}
|
|
@@ -4238,8 +4466,8 @@ function registerLlm(program) {
|
|
|
4238
4466
|
);
|
|
4239
4467
|
}
|
|
4240
4468
|
function loadLlmCfg(providerOverride) {
|
|
4241
|
-
const cfg =
|
|
4242
|
-
const llmCfg = { ...
|
|
4469
|
+
const cfg = loadStudioToml8();
|
|
4470
|
+
const llmCfg = { ...tableOf6(cfg, "llm") };
|
|
4243
4471
|
if (providerOverride) {
|
|
4244
4472
|
llmCfg.provider = providerOverride;
|
|
4245
4473
|
}
|
|
@@ -4309,7 +4537,7 @@ function loadFullCfg() {
|
|
|
4309
4537
|
}
|
|
4310
4538
|
let cfg;
|
|
4311
4539
|
try {
|
|
4312
|
-
cfg =
|
|
4540
|
+
cfg = loadStudioToml8(path17.join(root, "studio.toml"));
|
|
4313
4541
|
} catch (exc) {
|
|
4314
4542
|
printErr(`error: failed to parse studio.toml: ${errMessage(exc)}`);
|
|
4315
4543
|
return null;
|
|
@@ -4350,7 +4578,7 @@ function requirePieverse(cfg) {
|
|
|
4350
4578
|
}
|
|
4351
4579
|
function expectedRecipientOf(cfg) {
|
|
4352
4580
|
return String(
|
|
4353
|
-
|
|
4581
|
+
tableOf6(tableOf6(cfg, "payments"), "x402").expected_recipient ?? ""
|
|
4354
4582
|
).trim();
|
|
4355
4583
|
}
|
|
4356
4584
|
function printAllocateDeferred(amountUsd, keyHash, exc) {
|
|
@@ -4392,7 +4620,8 @@ async function cmdActivate(opts) {
|
|
|
4392
4620
|
}
|
|
4393
4621
|
const pvCfg = loadPieverseConfig(cfg);
|
|
4394
4622
|
let existingHash = pvCfg.key_hash ? String(pvCfg.key_hash) : null;
|
|
4395
|
-
const
|
|
4623
|
+
const envFileValue = getEnvVar(envLocalPath9(root), PIEVERSE_ENV_KEY);
|
|
4624
|
+
const existingEnv = envFileValue || process.env[PIEVERSE_ENV_KEY];
|
|
4396
4625
|
if (!existingHash && existingEnv) {
|
|
4397
4626
|
const derivedHash = pieverseKeyHash(existingEnv);
|
|
4398
4627
|
printOut(
|
|
@@ -4401,11 +4630,15 @@ async function cmdActivate(opts) {
|
|
|
4401
4630
|
try {
|
|
4402
4631
|
await withSiweRetry(wallet, (token) => inspectKey(token, derivedHash));
|
|
4403
4632
|
} catch (exc) {
|
|
4633
|
+
const sources = [
|
|
4634
|
+
envFileValue ? `.studio/.env.local (a ${PIEVERSE_ENV_KEY}= line)` : "",
|
|
4635
|
+
process.env[PIEVERSE_ENV_KEY] ? "the shell environment" : ""
|
|
4636
|
+
].filter(Boolean).join(" and ");
|
|
4404
4637
|
printErr(
|
|
4405
4638
|
`error: ${PIEVERSE_ENV_KEY} already exists but its derived key_hash could not be verified: ${errMessage(
|
|
4406
4639
|
exc
|
|
4407
4640
|
)}
|
|
4408
|
-
The existing key was kept and no new key was created.
|
|
4641
|
+
The existing key was kept and no new key was created. The key comes from ${sources}; \`bag\` reads both, so clear every source \u2014 remove the ${PIEVERSE_ENV_KEY}= line from .studio/.env.local AND \`unset ${PIEVERSE_ENV_KEY}\` in the shell \u2014 then re-run \`bag llm activate\` to mint a fresh key. (\`bag llm rotate\` replaces a key that is still valid in Pieverse; it cannot recover this one.)`
|
|
4409
4642
|
);
|
|
4410
4643
|
return 2;
|
|
4411
4644
|
}
|
|
@@ -4646,9 +4879,9 @@ Retry: re-run \`bag llm activate\` \u2014 key_hash is saved so it will pick up w
|
|
|
4646
4879
|
return 0;
|
|
4647
4880
|
}
|
|
4648
4881
|
function updateStudioTomlSection(root, section, updates) {
|
|
4649
|
-
const tomlPath =
|
|
4650
|
-
const text2 =
|
|
4651
|
-
|
|
4882
|
+
const tomlPath = path17.join(root, "studio.toml");
|
|
4883
|
+
const text2 = fs18.readFileSync(tomlPath, "utf-8");
|
|
4884
|
+
fs18.writeFileSync(tomlPath, updateSection(text2, section, updates), "utf-8");
|
|
4652
4885
|
}
|
|
4653
4886
|
function cumulativeTopupsUsd() {
|
|
4654
4887
|
let total = 0;
|
|
@@ -4739,8 +4972,8 @@ async function cmdStatus(full) {
|
|
|
4739
4972
|
const remainingRaw = info.remaining_usd;
|
|
4740
4973
|
const remaining = remainingRaw === void 0 || remainingRaw === null ? null : Number(remainingRaw);
|
|
4741
4974
|
const balanceStr = remaining === null ? "unknown (Pieverse inspect endpoint did not return balance field)" : `$${remaining.toFixed(4)}`;
|
|
4742
|
-
const llmCfg =
|
|
4743
|
-
const policy = pieversePolicyFromToml(
|
|
4975
|
+
const llmCfg = tableOf6(cfg, "llm");
|
|
4976
|
+
const policy = pieversePolicyFromToml(tableOf6(llmCfg, "auto_renew"));
|
|
4744
4977
|
printOut("provider: pieverse-llm");
|
|
4745
4978
|
const model = llmCfg.model ? String(llmCfg.model) : null;
|
|
4746
4979
|
printOut(`model: ${model ?? "(unset \u2014 provider default)"}`);
|
|
@@ -4844,9 +5077,9 @@ function autoRenewStatus() {
|
|
|
4844
5077
|
}
|
|
4845
5078
|
const [cfg] = loaded;
|
|
4846
5079
|
const llmPolicy = pieversePolicyFromToml(
|
|
4847
|
-
|
|
5080
|
+
tableOf6(tableOf6(cfg, "llm"), "auto_renew")
|
|
4848
5081
|
);
|
|
4849
|
-
const budgetPolicy = policyFromToml(
|
|
5082
|
+
const budgetPolicy = policyFromToml(tableOf6(cfg, "budget"));
|
|
4850
5083
|
printOut("auto-renew status (two independent tiers):");
|
|
4851
5084
|
printOut("");
|
|
4852
5085
|
printOut(
|
|
@@ -5197,8 +5430,8 @@ function normalizeNodeDeps(deps) {
|
|
|
5197
5430
|
}
|
|
5198
5431
|
|
|
5199
5432
|
// src/cli/recipes/loader.ts
|
|
5200
|
-
import * as
|
|
5201
|
-
import * as
|
|
5433
|
+
import * as fs19 from "fs";
|
|
5434
|
+
import * as path18 from "path";
|
|
5202
5435
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
5203
5436
|
import { parse as parse5 } from "smol-toml";
|
|
5204
5437
|
var PLACEHOLDER_RE = /\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g;
|
|
@@ -5207,12 +5440,12 @@ function bundledRecipesRoot() {
|
|
|
5207
5440
|
if (override) {
|
|
5208
5441
|
return override;
|
|
5209
5442
|
}
|
|
5210
|
-
let dir =
|
|
5443
|
+
let dir = path18.dirname(fileURLToPath3(import.meta.url));
|
|
5211
5444
|
for (; ; ) {
|
|
5212
|
-
if (
|
|
5213
|
-
return
|
|
5445
|
+
if (fs19.existsSync(path18.join(dir, "package.json"))) {
|
|
5446
|
+
return path18.join(dir, "recipes");
|
|
5214
5447
|
}
|
|
5215
|
-
const parent =
|
|
5448
|
+
const parent = path18.dirname(dir);
|
|
5216
5449
|
if (parent === dir) {
|
|
5217
5450
|
throw new Error("cannot locate the studio-cli package root");
|
|
5218
5451
|
}
|
|
@@ -5236,24 +5469,24 @@ function defaultMode(recipe) {
|
|
|
5236
5469
|
}
|
|
5237
5470
|
function listRecipes(root) {
|
|
5238
5471
|
const base = root ?? bundledRecipesRoot();
|
|
5239
|
-
if (!
|
|
5472
|
+
if (!fs19.existsSync(base)) {
|
|
5240
5473
|
return [];
|
|
5241
5474
|
}
|
|
5242
|
-
return
|
|
5243
|
-
(name) => !name.startsWith("_") &&
|
|
5475
|
+
return fs19.readdirSync(base).filter(
|
|
5476
|
+
(name) => !name.startsWith("_") && fs19.existsSync(path18.join(base, name, "recipe.toml")) && fs19.statSync(path18.join(base, name)).isDirectory()
|
|
5244
5477
|
).sort();
|
|
5245
5478
|
}
|
|
5246
5479
|
var RecipeModeError = class extends Error {
|
|
5247
5480
|
};
|
|
5248
5481
|
function loadRecipe(name, opts = {}) {
|
|
5249
5482
|
const base = opts.root ?? bundledRecipesRoot();
|
|
5250
|
-
const recipeDir =
|
|
5251
|
-
const tomlPath =
|
|
5252
|
-
if (!
|
|
5483
|
+
const recipeDir = path18.join(base, name);
|
|
5484
|
+
const tomlPath = path18.join(recipeDir, "recipe.toml");
|
|
5485
|
+
if (!fs19.existsSync(tomlPath) || !fs19.statSync(tomlPath).isFile()) {
|
|
5253
5486
|
throw new Error(`Recipe '${name}' not found at ${tomlPath}`);
|
|
5254
5487
|
}
|
|
5255
|
-
const metadata = parse5(
|
|
5256
|
-
const allFiles = collectTemplateFiles(
|
|
5488
|
+
const metadata = parse5(fs19.readFileSync(tomlPath, "utf-8"));
|
|
5489
|
+
const allFiles = collectTemplateFiles(path18.join(recipeDir, "code"));
|
|
5257
5490
|
const modesMeta = metaTable(metadata, "modes");
|
|
5258
5491
|
const mode = opts.mode ?? null;
|
|
5259
5492
|
if (Object.keys(modesMeta).length === 0) {
|
|
@@ -5300,22 +5533,22 @@ function modeFiles(modesMeta, modeName) {
|
|
|
5300
5533
|
return Array.isArray(files) ? files.filter((f) => typeof f === "string") : [];
|
|
5301
5534
|
}
|
|
5302
5535
|
function collectTemplateFiles(codeDir) {
|
|
5303
|
-
if (!
|
|
5536
|
+
if (!fs19.existsSync(codeDir) || !fs19.statSync(codeDir).isDirectory()) {
|
|
5304
5537
|
return [];
|
|
5305
5538
|
}
|
|
5306
5539
|
const out = [];
|
|
5307
5540
|
const walk = (dir) => {
|
|
5308
|
-
for (const name of
|
|
5309
|
-
const full =
|
|
5310
|
-
if (
|
|
5541
|
+
for (const name of fs19.readdirSync(dir).sort()) {
|
|
5542
|
+
const full = path18.join(dir, name);
|
|
5543
|
+
if (fs19.statSync(full).isDirectory()) {
|
|
5311
5544
|
walk(full);
|
|
5312
5545
|
} else {
|
|
5313
|
-
const rel =
|
|
5546
|
+
const rel = path18.relative(codeDir, full);
|
|
5314
5547
|
const target = rel.endsWith(".tmpl") ? rel.slice(0, -".tmpl".length) : rel;
|
|
5315
5548
|
out.push({
|
|
5316
5549
|
// Recipes use forward slashes regardless of host OS.
|
|
5317
|
-
targetPath: target.split(
|
|
5318
|
-
content:
|
|
5550
|
+
targetPath: target.split(path18.sep).join("/"),
|
|
5551
|
+
content: fs19.readFileSync(full, "utf-8")
|
|
5319
5552
|
});
|
|
5320
5553
|
}
|
|
5321
5554
|
}
|
|
@@ -5382,9 +5615,9 @@ function renderRecipe(recipe, opts = {}) {
|
|
|
5382
5615
|
|
|
5383
5616
|
// src/cli/skillsInstaller.ts
|
|
5384
5617
|
import * as crypto3 from "crypto";
|
|
5385
|
-
import * as
|
|
5618
|
+
import * as fs20 from "fs";
|
|
5386
5619
|
import * as os2 from "os";
|
|
5387
|
-
import * as
|
|
5620
|
+
import * as path19 from "path";
|
|
5388
5621
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
5389
5622
|
var SUPPORTED_TARGETS = ["claude-code", "cursor"];
|
|
5390
5623
|
var SUPPORTED_SCOPES = ["user", "project"];
|
|
@@ -5431,14 +5664,14 @@ var HIDDEN_SKILL_NAMES = /* @__PURE__ */ new Set([
|
|
|
5431
5664
|
]);
|
|
5432
5665
|
function isDir3(p) {
|
|
5433
5666
|
try {
|
|
5434
|
-
return
|
|
5667
|
+
return fs20.statSync(p).isDirectory();
|
|
5435
5668
|
} catch {
|
|
5436
5669
|
return false;
|
|
5437
5670
|
}
|
|
5438
5671
|
}
|
|
5439
5672
|
function isFile6(p) {
|
|
5440
5673
|
try {
|
|
5441
|
-
return
|
|
5674
|
+
return fs20.statSync(p).isFile();
|
|
5442
5675
|
} catch {
|
|
5443
5676
|
return false;
|
|
5444
5677
|
}
|
|
@@ -5448,15 +5681,15 @@ function sha256(text2) {
|
|
|
5448
5681
|
}
|
|
5449
5682
|
function resolveSkillsSource() {
|
|
5450
5683
|
const pkgRoot = packageRoot2();
|
|
5451
|
-
return pkgRoot !== null ?
|
|
5684
|
+
return pkgRoot !== null ? path19.join(pkgRoot, "skills") : path19.join(path19.dirname(fileURLToPath4(import.meta.url)), "skills");
|
|
5452
5685
|
}
|
|
5453
5686
|
function packageRoot2() {
|
|
5454
|
-
let dir =
|
|
5687
|
+
let dir = path19.dirname(fileURLToPath4(import.meta.url));
|
|
5455
5688
|
for (; ; ) {
|
|
5456
|
-
if (
|
|
5689
|
+
if (fs20.existsSync(path19.join(dir, "package.json"))) {
|
|
5457
5690
|
return dir;
|
|
5458
5691
|
}
|
|
5459
|
-
const parent =
|
|
5692
|
+
const parent = path19.dirname(dir);
|
|
5460
5693
|
if (parent === dir) {
|
|
5461
5694
|
return null;
|
|
5462
5695
|
}
|
|
@@ -5468,18 +5701,18 @@ function listSourceSkills(source) {
|
|
|
5468
5701
|
if (!isDir3(source)) {
|
|
5469
5702
|
return [];
|
|
5470
5703
|
}
|
|
5471
|
-
return
|
|
5472
|
-
(name) => name.endsWith(".md") && !name.startsWith("_") && !HIDDEN_SKILL_NAMES.has(stem(name)) && isFile6(
|
|
5473
|
-
).sort().map((name) =>
|
|
5704
|
+
return fs20.readdirSync(source).filter(
|
|
5705
|
+
(name) => name.endsWith(".md") && !name.startsWith("_") && !HIDDEN_SKILL_NAMES.has(stem(name)) && isFile6(path19.join(source, name))
|
|
5706
|
+
).sort().map((name) => path19.join(source, name));
|
|
5474
5707
|
}
|
|
5475
5708
|
function listSourceReferences(source) {
|
|
5476
|
-
const refs =
|
|
5709
|
+
const refs = path19.join(source, "references");
|
|
5477
5710
|
if (!isDir3(refs)) {
|
|
5478
5711
|
return [];
|
|
5479
5712
|
}
|
|
5480
|
-
return
|
|
5481
|
-
(name) => name.endsWith(".md") && !name.startsWith("_") && !HIDDEN_SKILL_NAMES.has(stem(name)) && isFile6(
|
|
5482
|
-
).sort().map((name) =>
|
|
5713
|
+
return fs20.readdirSync(refs).filter(
|
|
5714
|
+
(name) => name.endsWith(".md") && !name.startsWith("_") && !HIDDEN_SKILL_NAMES.has(stem(name)) && isFile6(path19.join(refs, name))
|
|
5715
|
+
).sort().map((name) => path19.join(refs, name));
|
|
5483
5716
|
}
|
|
5484
5717
|
function stem(fileName) {
|
|
5485
5718
|
return fileName.replace(/\.[^.]+$/, "");
|
|
@@ -5487,15 +5720,15 @@ function stem(fileName) {
|
|
|
5487
5720
|
function whichSync(name) {
|
|
5488
5721
|
const pathEnv = process.env.PATH ?? "";
|
|
5489
5722
|
const exts = process.platform === "win32" ? ["", ".cmd", ".exe", ".bat"] : [""];
|
|
5490
|
-
for (const dir of pathEnv.split(
|
|
5723
|
+
for (const dir of pathEnv.split(path19.delimiter)) {
|
|
5491
5724
|
if (!dir) {
|
|
5492
5725
|
continue;
|
|
5493
5726
|
}
|
|
5494
5727
|
for (const ext of exts) {
|
|
5495
|
-
const candidate =
|
|
5728
|
+
const candidate = path19.join(dir, name + ext);
|
|
5496
5729
|
try {
|
|
5497
|
-
|
|
5498
|
-
if (
|
|
5730
|
+
fs20.accessSync(candidate, fs20.constants.X_OK);
|
|
5731
|
+
if (fs20.statSync(candidate).isFile()) {
|
|
5499
5732
|
return candidate;
|
|
5500
5733
|
}
|
|
5501
5734
|
} catch {
|
|
@@ -5506,14 +5739,14 @@ function whichSync(name) {
|
|
|
5506
5739
|
}
|
|
5507
5740
|
function claudeCodeInstalled(opts = {}) {
|
|
5508
5741
|
const home = opts.home ?? os2.homedir();
|
|
5509
|
-
if (isDir3(
|
|
5742
|
+
if (isDir3(path19.join(home, ".claude"))) {
|
|
5510
5743
|
return true;
|
|
5511
5744
|
}
|
|
5512
5745
|
return (opts.which ?? whichSync)("claude") !== null;
|
|
5513
5746
|
}
|
|
5514
5747
|
function cursorInstalled(opts = {}) {
|
|
5515
5748
|
const home = opts.home ?? os2.homedir();
|
|
5516
|
-
if (isDir3(
|
|
5749
|
+
if (isDir3(path19.join(home, ".cursor"))) {
|
|
5517
5750
|
return true;
|
|
5518
5751
|
}
|
|
5519
5752
|
return (opts.which ?? whichSync)("cursor") !== null;
|
|
@@ -5536,9 +5769,9 @@ function anySkillsInstalled(opts = {}) {
|
|
|
5536
5769
|
for (const target of detectTargets(opts)) {
|
|
5537
5770
|
const tdir = resolveTargetDir({ target, scope: "user", home: opts.home });
|
|
5538
5771
|
for (const skill of sources) {
|
|
5539
|
-
const name = stem(
|
|
5540
|
-
const rel = target === "claude-code" ?
|
|
5541
|
-
if (isFile6(
|
|
5772
|
+
const name = stem(path19.basename(skill));
|
|
5773
|
+
const rel = target === "claude-code" ? path19.join(name, "SKILL.md") : `${name}.mdc`;
|
|
5774
|
+
if (isFile6(path19.join(tdir, rel))) {
|
|
5542
5775
|
return true;
|
|
5543
5776
|
}
|
|
5544
5777
|
}
|
|
@@ -5563,7 +5796,7 @@ function resolveTargetDir(opts) {
|
|
|
5563
5796
|
}
|
|
5564
5797
|
const base = scope === "user" ? opts.home ?? os2.homedir() : opts.projectRoot ?? process.cwd();
|
|
5565
5798
|
const [d1, d2] = TARGET_SUBDIR[target];
|
|
5566
|
-
return
|
|
5799
|
+
return path19.join(base, d1, d2);
|
|
5567
5800
|
}
|
|
5568
5801
|
function splitFrontmatter(text2) {
|
|
5569
5802
|
const lines = text2.split("\n");
|
|
@@ -5621,16 +5854,16 @@ function iterRenderedPayloads(src, target) {
|
|
|
5621
5854
|
for (const skill of listSourceSkills(src)) {
|
|
5622
5855
|
payloads.push(
|
|
5623
5856
|
renderSkillPayload(
|
|
5624
|
-
|
|
5625
|
-
stem(
|
|
5857
|
+
fs20.readFileSync(skill, "utf-8"),
|
|
5858
|
+
stem(path19.basename(skill)),
|
|
5626
5859
|
target
|
|
5627
5860
|
)
|
|
5628
5861
|
);
|
|
5629
5862
|
}
|
|
5630
5863
|
for (const ref of listSourceReferences(src)) {
|
|
5631
5864
|
payloads.push([
|
|
5632
|
-
`${ROUTER_SKILL_NAME}/references/${
|
|
5633
|
-
|
|
5865
|
+
`${ROUTER_SKILL_NAME}/references/${path19.basename(ref)}`,
|
|
5866
|
+
fs20.readFileSync(ref, "utf-8")
|
|
5634
5867
|
]);
|
|
5635
5868
|
}
|
|
5636
5869
|
return payloads;
|
|
@@ -5642,7 +5875,7 @@ function packageVersion() {
|
|
|
5642
5875
|
return "unknown";
|
|
5643
5876
|
}
|
|
5644
5877
|
const pkg = JSON.parse(
|
|
5645
|
-
|
|
5878
|
+
fs20.readFileSync(path19.join(root, "package.json"), "utf-8")
|
|
5646
5879
|
);
|
|
5647
5880
|
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
5648
5881
|
} catch {
|
|
@@ -5661,11 +5894,11 @@ function contentKey(payloads) {
|
|
|
5661
5894
|
return h.digest("hex");
|
|
5662
5895
|
}
|
|
5663
5896
|
function metaPath(tdir) {
|
|
5664
|
-
return
|
|
5897
|
+
return path19.join(tdir, ROUTER_SKILL_NAME, META_FILENAME);
|
|
5665
5898
|
}
|
|
5666
5899
|
function loadMeta(tdir) {
|
|
5667
5900
|
try {
|
|
5668
|
-
const data = JSON.parse(
|
|
5901
|
+
const data = JSON.parse(fs20.readFileSync(metaPath(tdir), "utf-8"));
|
|
5669
5902
|
return data !== null && typeof data === "object" && !Array.isArray(data) ? data : null;
|
|
5670
5903
|
} catch {
|
|
5671
5904
|
return null;
|
|
@@ -5682,15 +5915,15 @@ function writeMeta(tdir, payloads) {
|
|
|
5682
5915
|
package_version: packageVersion()
|
|
5683
5916
|
};
|
|
5684
5917
|
const p = metaPath(tdir);
|
|
5685
|
-
|
|
5686
|
-
|
|
5918
|
+
fs20.mkdirSync(path19.dirname(p), { recursive: true });
|
|
5919
|
+
fs20.writeFileSync(p, `${JSON.stringify(meta, null, 2)}
|
|
5687
5920
|
`);
|
|
5688
5921
|
}
|
|
5689
5922
|
function installedMarker(tdir, target) {
|
|
5690
5923
|
if (target === "cursor") {
|
|
5691
|
-
return
|
|
5924
|
+
return path19.join(tdir, `${ROUTER_SKILL_NAME}.mdc`);
|
|
5692
5925
|
}
|
|
5693
|
-
return
|
|
5926
|
+
return path19.join(tdir, ROUTER_SKILL_NAME, "SKILL.md");
|
|
5694
5927
|
}
|
|
5695
5928
|
function syncInstalledSkills(opts = {}) {
|
|
5696
5929
|
const src = opts.source ?? SKILLS_SOURCE;
|
|
@@ -5727,15 +5960,15 @@ function syncOneDir(tdir, payloads) {
|
|
|
5727
5960
|
const wrote = [];
|
|
5728
5961
|
const keptEdited = [];
|
|
5729
5962
|
for (const [rel, content] of payloads) {
|
|
5730
|
-
const dest =
|
|
5963
|
+
const dest = path19.join(tdir, rel);
|
|
5731
5964
|
const newHash = sha256(content);
|
|
5732
|
-
const cur = isFile6(dest) ? sha256(
|
|
5965
|
+
const cur = isFile6(dest) ? sha256(fs20.readFileSync(dest, "utf-8")) : null;
|
|
5733
5966
|
if (cur === newHash) {
|
|
5734
5967
|
continue;
|
|
5735
5968
|
}
|
|
5736
5969
|
if (cur === null || cur === recordedFiles[rel]) {
|
|
5737
|
-
|
|
5738
|
-
|
|
5970
|
+
fs20.mkdirSync(path19.dirname(dest), { recursive: true });
|
|
5971
|
+
fs20.writeFileSync(dest, content);
|
|
5739
5972
|
wrote.push(rel);
|
|
5740
5973
|
} else {
|
|
5741
5974
|
keptEdited.push(rel);
|
|
@@ -5746,15 +5979,15 @@ function syncOneDir(tdir, payloads) {
|
|
|
5746
5979
|
if (shipped.has(rel)) {
|
|
5747
5980
|
continue;
|
|
5748
5981
|
}
|
|
5749
|
-
const dest =
|
|
5982
|
+
const dest = path19.join(tdir, rel);
|
|
5750
5983
|
try {
|
|
5751
|
-
if (isFile6(dest) && sha256(
|
|
5752
|
-
|
|
5984
|
+
if (isFile6(dest) && sha256(fs20.readFileSync(dest, "utf-8")) === recorded) {
|
|
5985
|
+
fs20.unlinkSync(dest);
|
|
5753
5986
|
wrote.push(`removed ${rel}`);
|
|
5754
|
-
let parent =
|
|
5755
|
-
while (parent !== tdir && isDir3(parent) &&
|
|
5756
|
-
|
|
5757
|
-
parent =
|
|
5987
|
+
let parent = path19.dirname(dest);
|
|
5988
|
+
while (parent !== tdir && isDir3(parent) && fs20.readdirSync(parent).length === 0) {
|
|
5989
|
+
fs20.rmdirSync(parent);
|
|
5990
|
+
parent = path19.dirname(parent);
|
|
5758
5991
|
}
|
|
5759
5992
|
}
|
|
5760
5993
|
} catch {
|
|
@@ -5784,45 +6017,45 @@ function installSkills(opts) {
|
|
|
5784
6017
|
projectRoot: opts.projectRoot,
|
|
5785
6018
|
home: opts.home
|
|
5786
6019
|
});
|
|
5787
|
-
|
|
6020
|
+
fs20.mkdirSync(tdir, { recursive: true });
|
|
5788
6021
|
const installed = [];
|
|
5789
6022
|
const skipped = [];
|
|
5790
6023
|
for (const skill of skillFiles) {
|
|
5791
|
-
const skillName = stem(
|
|
5792
|
-
const srcText =
|
|
6024
|
+
const skillName = stem(path19.basename(skill));
|
|
6025
|
+
const srcText = fs20.readFileSync(skill, "utf-8");
|
|
5793
6026
|
const [relPath, content] = renderSkillPayload(srcText, skillName, target);
|
|
5794
|
-
const dest =
|
|
5795
|
-
|
|
5796
|
-
if (isFile6(dest) && sha256(
|
|
6027
|
+
const dest = path19.join(tdir, relPath);
|
|
6028
|
+
fs20.mkdirSync(path19.dirname(dest), { recursive: true });
|
|
6029
|
+
if (isFile6(dest) && sha256(fs20.readFileSync(dest, "utf-8")) === sha256(content)) {
|
|
5797
6030
|
skipped.push(skillName);
|
|
5798
6031
|
} else {
|
|
5799
|
-
|
|
6032
|
+
fs20.writeFileSync(dest, content);
|
|
5800
6033
|
installed.push(skillName);
|
|
5801
6034
|
}
|
|
5802
6035
|
if (target === "claude-code") {
|
|
5803
|
-
const legacyFlat =
|
|
6036
|
+
const legacyFlat = path19.join(tdir, path19.basename(skill));
|
|
5804
6037
|
if (isFile6(legacyFlat)) {
|
|
5805
|
-
|
|
6038
|
+
fs20.unlinkSync(legacyFlat);
|
|
5806
6039
|
}
|
|
5807
6040
|
}
|
|
5808
6041
|
}
|
|
5809
6042
|
for (const ref of listSourceReferences(src)) {
|
|
5810
|
-
const rel = `${ROUTER_SKILL_NAME}/references/${
|
|
5811
|
-
const dest =
|
|
5812
|
-
|
|
5813
|
-
const content =
|
|
5814
|
-
if (isFile6(dest) && sha256(
|
|
6043
|
+
const rel = `${ROUTER_SKILL_NAME}/references/${path19.basename(ref)}`;
|
|
6044
|
+
const dest = path19.join(tdir, rel);
|
|
6045
|
+
fs20.mkdirSync(path19.dirname(dest), { recursive: true });
|
|
6046
|
+
const content = fs20.readFileSync(ref, "utf-8");
|
|
6047
|
+
if (isFile6(dest) && sha256(fs20.readFileSync(dest, "utf-8")) === sha256(content)) {
|
|
5815
6048
|
skipped.push(rel);
|
|
5816
6049
|
} else {
|
|
5817
|
-
|
|
6050
|
+
fs20.writeFileSync(dest, content);
|
|
5818
6051
|
installed.push(rel);
|
|
5819
6052
|
}
|
|
5820
6053
|
}
|
|
5821
|
-
if (isDir3(
|
|
6054
|
+
if (isDir3(path19.join(tdir, ROUTER_SKILL_NAME))) {
|
|
5822
6055
|
writeMeta(tdir, iterRenderedPayloads(src, target));
|
|
5823
6056
|
}
|
|
5824
|
-
const legacy = target === "claude-code" ? LEGACY_SKILL_NAMES.filter((name) => isDir3(
|
|
5825
|
-
(name) => isFile6(
|
|
6057
|
+
const legacy = target === "claude-code" ? LEGACY_SKILL_NAMES.filter((name) => isDir3(path19.join(tdir, name))) : LEGACY_SKILL_NAMES.filter(
|
|
6058
|
+
(name) => isFile6(path19.join(tdir, `${name}.mdc`))
|
|
5826
6059
|
);
|
|
5827
6060
|
return {
|
|
5828
6061
|
target,
|
|
@@ -5848,18 +6081,20 @@ function acceptChoices(option, accepted, advertised) {
|
|
|
5848
6081
|
}
|
|
5849
6082
|
|
|
5850
6083
|
// src/cli/wallet.ts
|
|
5851
|
-
import * as
|
|
5852
|
-
import * as
|
|
6084
|
+
import * as fs22 from "fs";
|
|
6085
|
+
import * as os3 from "os";
|
|
6086
|
+
import * as path21 from "path";
|
|
5853
6087
|
import { EVMWalletProvider, SigningPolicy } from "@bnbagent/sdk";
|
|
5854
6088
|
import {
|
|
6089
|
+
envLocalPath as envLocalPath10,
|
|
5855
6090
|
findProjectRoot as findProjectRoot3,
|
|
5856
|
-
loadStudioToml as
|
|
6091
|
+
loadStudioToml as loadStudioToml10
|
|
5857
6092
|
} from "@bnbagent/studio-runtime/config";
|
|
5858
6093
|
import { buildPolicy, buildWallet } from "@bnbagent/studio-runtime/wallet";
|
|
5859
6094
|
|
|
5860
6095
|
// src/cli/walletSession.ts
|
|
5861
|
-
import * as
|
|
5862
|
-
import * as
|
|
6096
|
+
import * as fs21 from "fs";
|
|
6097
|
+
import * as path20 from "path";
|
|
5863
6098
|
import { AltanaWalletProvider } from "@bnbagent/sdk";
|
|
5864
6099
|
import { getAddress as deployedAddresses } from "@bnbagent/sdk/networks";
|
|
5865
6100
|
import {
|
|
@@ -5868,7 +6103,7 @@ import {
|
|
|
5868
6103
|
serializeSession
|
|
5869
6104
|
} from "@bnbagent/sdk/wallets";
|
|
5870
6105
|
import { auditedOp as auditedOp2 } from "@bnbagent/studio-runtime/audit";
|
|
5871
|
-
import { loadStudioToml as
|
|
6106
|
+
import { loadStudioToml as loadStudioToml9 } from "@bnbagent/studio-runtime/config";
|
|
5872
6107
|
import { getNetwork as getNetwork5, toRaw as toRaw2 } from "@bnbagent/studio-runtime/networks";
|
|
5873
6108
|
import { writePrivate } from "@bnbagent/studio-runtime/secretWrite";
|
|
5874
6109
|
import {
|
|
@@ -5878,18 +6113,18 @@ import {
|
|
|
5878
6113
|
var defaultAdminFactory = (opts) => AltanaWalletProvider.adminFromKeystore(opts);
|
|
5879
6114
|
var adminFactory = defaultAdminFactory;
|
|
5880
6115
|
var sessionDeserializer = deserializeSession;
|
|
5881
|
-
function
|
|
6116
|
+
function tableOf7(value) {
|
|
5882
6117
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
5883
6118
|
}
|
|
5884
6119
|
function loadContext(projectRoot) {
|
|
5885
|
-
const cfg =
|
|
5886
|
-
const walletCfg =
|
|
6120
|
+
const cfg = loadStudioToml9(path20.join(projectRoot, "studio.toml"));
|
|
6121
|
+
const walletCfg = tableOf7(cfg.wallet);
|
|
5887
6122
|
if (String(walletCfg.kind ?? "evm-local") !== "altana") {
|
|
5888
6123
|
throw new Error(
|
|
5889
6124
|
`wallet session commands require [wallet].kind='altana' (got ${JSON.stringify(walletCfg.kind ?? "evm-local")}).`
|
|
5890
6125
|
);
|
|
5891
6126
|
}
|
|
5892
|
-
const networkName = String(
|
|
6127
|
+
const networkName = String(tableOf7(cfg.network).default ?? "bsc-testnet");
|
|
5893
6128
|
const altanaNetwork = ALTANA_NETWORK_BY_STUDIO[networkName];
|
|
5894
6129
|
if (altanaNetwork === void 0) {
|
|
5895
6130
|
throw new Error(
|
|
@@ -5904,7 +6139,7 @@ function loadContext(projectRoot) {
|
|
|
5904
6139
|
}
|
|
5905
6140
|
const resolvePath = (value, fallback) => {
|
|
5906
6141
|
const configured = String(value ?? fallback);
|
|
5907
|
-
return
|
|
6142
|
+
return path20.isAbsolute(configured) ? configured : path20.join(projectRoot, configured);
|
|
5908
6143
|
};
|
|
5909
6144
|
return {
|
|
5910
6145
|
projectRoot,
|
|
@@ -5952,8 +6187,8 @@ function parseSessionEnvelope(serialized) {
|
|
|
5952
6187
|
`invalid Altana session JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
5953
6188
|
);
|
|
5954
6189
|
}
|
|
5955
|
-
const record =
|
|
5956
|
-
if (record.version !== 1 || typeof record.walletAddress !== "string" || typeof record.publicKey !== "string" || !record.publicKey.startsWith("0x") || typeof record.expiry !== "number" || Object.keys(
|
|
6190
|
+
const record = tableOf7(parsed);
|
|
6191
|
+
if (record.version !== 1 || typeof record.walletAddress !== "string" || typeof record.publicKey !== "string" || !record.publicKey.startsWith("0x") || typeof record.expiry !== "number" || Object.keys(tableOf7(record.permissions)).length === 0) {
|
|
5957
6192
|
throw new Error(
|
|
5958
6193
|
"invalid Altana session envelope (expected version/walletAddress/publicKey/expiry/permissions)."
|
|
5959
6194
|
);
|
|
@@ -5962,13 +6197,13 @@ function parseSessionEnvelope(serialized) {
|
|
|
5962
6197
|
walletAddress: record.walletAddress,
|
|
5963
6198
|
publicKey: record.publicKey,
|
|
5964
6199
|
expiry: record.expiry,
|
|
5965
|
-
permissions:
|
|
6200
|
+
permissions: tableOf7(record.permissions)
|
|
5966
6201
|
};
|
|
5967
6202
|
}
|
|
5968
6203
|
function readSession(ctx) {
|
|
5969
6204
|
let serialized;
|
|
5970
6205
|
try {
|
|
5971
|
-
serialized =
|
|
6206
|
+
serialized = fs21.readFileSync(ctx.sessionFile, "utf8");
|
|
5972
6207
|
} catch {
|
|
5973
6208
|
throw new Error(
|
|
5974
6209
|
`no Altana session file at ${ctx.sessionFile} \u2014 run \`bag wallet session grant\`.`
|
|
@@ -5977,8 +6212,8 @@ function readSession(ctx) {
|
|
|
5977
6212
|
return { serialized, envelope: parseSessionEnvelope(serialized) };
|
|
5978
6213
|
}
|
|
5979
6214
|
function writeSession(ctx, session) {
|
|
5980
|
-
|
|
5981
|
-
|
|
6215
|
+
fs21.mkdirSync(path20.dirname(ctx.sessionFile), { recursive: true, mode: 448 });
|
|
6216
|
+
fs21.chmodSync(path20.dirname(ctx.sessionFile), 448);
|
|
5982
6217
|
writePrivate(ctx.sessionFile, serializeSession(session));
|
|
5983
6218
|
}
|
|
5984
6219
|
function sessionKeyFingerprint(publicKey) {
|
|
@@ -6089,7 +6324,7 @@ async function cmdSessionGrant(opts) {
|
|
|
6089
6324
|
"--budget-u"
|
|
6090
6325
|
);
|
|
6091
6326
|
let existing = null;
|
|
6092
|
-
if (
|
|
6327
|
+
if (fs21.existsSync(ctx.sessionFile)) {
|
|
6093
6328
|
existing = readSession(ctx).envelope;
|
|
6094
6329
|
if (!opts.force) {
|
|
6095
6330
|
throw new Error(
|
|
@@ -6171,8 +6406,8 @@ function cmdSessionStatus(projectRootArg) {
|
|
|
6171
6406
|
const spend = envelope.permissions.spend;
|
|
6172
6407
|
if (Array.isArray(spend)) {
|
|
6173
6408
|
for (const [index, cap] of spend.entries()) {
|
|
6174
|
-
const record =
|
|
6175
|
-
const encoded =
|
|
6409
|
+
const record = tableOf7(cap);
|
|
6410
|
+
const encoded = tableOf7(record.limit).$bigint;
|
|
6176
6411
|
const limit = typeof encoded === "string" ? encoded : String(record.limit);
|
|
6177
6412
|
printOut(
|
|
6178
6413
|
`spend[${index}]: limit=${limit} period=${String(record.period ?? "day")} token=${String(record.token ?? "native")}`
|
|
@@ -6207,7 +6442,7 @@ async function cmdSessionRevoke(opts) {
|
|
|
6207
6442
|
await admin.revokeSession(envelope.publicKey);
|
|
6208
6443
|
}
|
|
6209
6444
|
);
|
|
6210
|
-
|
|
6445
|
+
fs21.unlinkSync(ctx.sessionFile);
|
|
6211
6446
|
printErr(`\u2713 Altana session revoked and removed: ${ctx.sessionFile}`);
|
|
6212
6447
|
return 0;
|
|
6213
6448
|
}
|
|
@@ -6331,8 +6566,8 @@ var ProjectRootNotFound = class extends Error {
|
|
|
6331
6566
|
};
|
|
6332
6567
|
function resolveWalletProjectRoot(argRoot) {
|
|
6333
6568
|
if (argRoot != null) {
|
|
6334
|
-
const root2 =
|
|
6335
|
-
if (!isFile7(
|
|
6569
|
+
const root2 = path21.resolve(argRoot);
|
|
6570
|
+
if (!isFile7(path21.join(root2, "studio.toml"))) {
|
|
6336
6571
|
throw new ProjectRootNotFound(
|
|
6337
6572
|
`No studio.toml found under --project-root ${root2}`
|
|
6338
6573
|
);
|
|
@@ -6349,13 +6584,13 @@ function resolveWalletProjectRoot(argRoot) {
|
|
|
6349
6584
|
}
|
|
6350
6585
|
function isFile7(p) {
|
|
6351
6586
|
try {
|
|
6352
|
-
return
|
|
6587
|
+
return fs22.statSync(p).isFile();
|
|
6353
6588
|
} catch {
|
|
6354
6589
|
return false;
|
|
6355
6590
|
}
|
|
6356
6591
|
}
|
|
6357
6592
|
function loadWalletCfg(projectRoot) {
|
|
6358
|
-
const data =
|
|
6593
|
+
const data = loadStudioToml10(path21.join(projectRoot, "studio.toml"));
|
|
6359
6594
|
const wallet = data.wallet;
|
|
6360
6595
|
return wallet !== null && typeof wallet === "object" && !Array.isArray(wallet) ? wallet : {};
|
|
6361
6596
|
}
|
|
@@ -6365,7 +6600,7 @@ function walletKind(walletCfg) {
|
|
|
6365
6600
|
function projectNetwork(projectRoot) {
|
|
6366
6601
|
let data;
|
|
6367
6602
|
try {
|
|
6368
|
-
data =
|
|
6603
|
+
data = loadStudioToml10(path21.join(projectRoot, "studio.toml"));
|
|
6369
6604
|
} catch {
|
|
6370
6605
|
return "bsc-testnet";
|
|
6371
6606
|
}
|
|
@@ -6387,13 +6622,29 @@ function requirePassword2() {
|
|
|
6387
6622
|
}
|
|
6388
6623
|
return pw;
|
|
6389
6624
|
}
|
|
6625
|
+
function requireDurablePassword(projectRoot) {
|
|
6626
|
+
const password = requirePassword2();
|
|
6627
|
+
const envPath = envLocalPath10(projectRoot);
|
|
6628
|
+
const persisted = getEnvVar(envPath, PASSWORD_ENV2);
|
|
6629
|
+
if (!persisted) {
|
|
6630
|
+
throw new Error(
|
|
6631
|
+
`refusing to create a keystore with an unpersisted ${PASSWORD_ENV2}. Edit ${envPath}, set ${PASSWORD_ENV2} there, and retry; do not pass wallet passwords on the command line.`
|
|
6632
|
+
);
|
|
6633
|
+
}
|
|
6634
|
+
if (persisted !== password) {
|
|
6635
|
+
throw new Error(
|
|
6636
|
+
`refusing to create a keystore because the active ${PASSWORD_ENV2} does not match ${envPath}. Make the durable file value authoritative before retrying.`
|
|
6637
|
+
);
|
|
6638
|
+
}
|
|
6639
|
+
return password;
|
|
6640
|
+
}
|
|
6390
6641
|
function persistAddress(projectRoot, address) {
|
|
6391
|
-
const tomlPath =
|
|
6642
|
+
const tomlPath = path21.join(projectRoot, "studio.toml");
|
|
6392
6643
|
if (!isFile7(tomlPath)) {
|
|
6393
6644
|
return;
|
|
6394
6645
|
}
|
|
6395
|
-
const text2 =
|
|
6396
|
-
|
|
6646
|
+
const text2 = fs22.readFileSync(tomlPath, "utf-8");
|
|
6647
|
+
fs22.writeFileSync(
|
|
6397
6648
|
tomlPath,
|
|
6398
6649
|
updateSection(text2, "wallet", { address }),
|
|
6399
6650
|
"utf-8"
|
|
@@ -6409,7 +6660,7 @@ function resolveKeystoreDir2(projectRoot, cliOverride, walletCfg) {
|
|
|
6409
6660
|
} else {
|
|
6410
6661
|
d = ".studio/wallets";
|
|
6411
6662
|
}
|
|
6412
|
-
return
|
|
6663
|
+
return path21.isAbsolute(d) ? d : path21.join(projectRoot, d);
|
|
6413
6664
|
}
|
|
6414
6665
|
async function resolvePrivateKeyArg(raw) {
|
|
6415
6666
|
if (raw === void 0 || raw === false) {
|
|
@@ -6442,7 +6693,7 @@ function registerWallet(program) {
|
|
|
6442
6693
|
)
|
|
6443
6694
|
);
|
|
6444
6695
|
p.command("twak-init").description(
|
|
6445
|
-
"Create the project's twak wallet
|
|
6696
|
+
"Create the project's twak wallet without YOU typing the password on a command line (wallet.kind=twak): wraps `twak wallet create --no-keychain` reading the password from stdin / a 0600 file / a hidden prompt, seeds the NaaS credentials, then adopts the address like `bag wallet new`. twak requires --password on its own argv, so the value does reach that short-lived child process."
|
|
6446
6697
|
).option(
|
|
6447
6698
|
"--password-stdin",
|
|
6448
6699
|
'Read the wallet password from stdin (CI: `printf %s "$PW" | bag wallet twak-init --password-stdin`).'
|
|
@@ -6524,7 +6775,7 @@ async function cmdNew(opts) {
|
|
|
6524
6775
|
projectRoot = process.cwd();
|
|
6525
6776
|
}
|
|
6526
6777
|
let walletCfg = {};
|
|
6527
|
-
if (isFile7(
|
|
6778
|
+
if (isFile7(path21.join(projectRoot, "studio.toml"))) {
|
|
6528
6779
|
walletCfg = loadWalletCfg(projectRoot);
|
|
6529
6780
|
}
|
|
6530
6781
|
const kind = walletKind(walletCfg);
|
|
@@ -6532,13 +6783,13 @@ async function cmdNew(opts) {
|
|
|
6532
6783
|
return cmdNewTwak(projectRoot, walletCfg);
|
|
6533
6784
|
}
|
|
6534
6785
|
const privateKey = await resolvePrivateKeyArg(opts.privateKey);
|
|
6535
|
-
const password =
|
|
6786
|
+
const password = requireDurablePassword(projectRoot);
|
|
6536
6787
|
const keystoreDir = resolveKeystoreDir2(
|
|
6537
6788
|
projectRoot,
|
|
6538
6789
|
opts.keystoreDir,
|
|
6539
6790
|
walletCfg
|
|
6540
6791
|
);
|
|
6541
|
-
|
|
6792
|
+
fs22.mkdirSync(keystoreDir, { recursive: true });
|
|
6542
6793
|
const provider = new EVMWalletProvider({
|
|
6543
6794
|
password,
|
|
6544
6795
|
...privateKey !== null ? { privateKey } : {},
|
|
@@ -6566,7 +6817,7 @@ Install it (Node >=22): npm install -g @trustwallet/cli@${TWAK_CLI_VERSION}`
|
|
|
6566
6817
|
let createCmd = "twak wallet create --password <your-password> --no-keychain";
|
|
6567
6818
|
let setupCmd = "twak setup";
|
|
6568
6819
|
if (walletCfg.twak_home) {
|
|
6569
|
-
const home =
|
|
6820
|
+
const home = path21.dirname(path21.dirname(walletFile));
|
|
6570
6821
|
createCmd = `HOME=${home} ${createCmd}`;
|
|
6571
6822
|
setupCmd = `HOME=${home} ${setupCmd}`;
|
|
6572
6823
|
}
|
|
@@ -6591,16 +6842,39 @@ Install it (Node >=22): npm install -g @trustwallet/cli@${TWAK_CLI_VERSION}`
|
|
|
6591
6842
|
persistAddress(projectRoot, address);
|
|
6592
6843
|
return 0;
|
|
6593
6844
|
}
|
|
6845
|
+
function ensureTwakCredentials(walletFile, homeDir) {
|
|
6846
|
+
const twakDir = path21.dirname(walletFile);
|
|
6847
|
+
const target = path21.join(twakDir, "credentials.json");
|
|
6848
|
+
if (isFile7(target)) {
|
|
6849
|
+
return true;
|
|
6850
|
+
}
|
|
6851
|
+
const machine = path21.join(os3.homedir(), ".twak", "credentials.json");
|
|
6852
|
+
if (path21.resolve(machine) === path21.resolve(target) || !isFile7(machine)) {
|
|
6853
|
+
printErr(
|
|
6854
|
+
`error: no Trust Wallet NaaS credentials for this wallet home \u2014 ${target} is missing. Get an Access ID + HMAC secret from https://portal.trustwallet.com/dashboard/apps, run \`HOME=${homeDir} twak setup\` once, then re-run this command.`
|
|
6855
|
+
);
|
|
6856
|
+
return false;
|
|
6857
|
+
}
|
|
6858
|
+
fs22.mkdirSync(twakDir, { recursive: true });
|
|
6859
|
+
fs22.writeFileSync(target, fs22.readFileSync(machine, "utf-8"), { mode: 384 });
|
|
6860
|
+
try {
|
|
6861
|
+
fs22.chmodSync(twakDir, 448);
|
|
6862
|
+
fs22.chmodSync(target, 384);
|
|
6863
|
+
} catch {
|
|
6864
|
+
}
|
|
6865
|
+
printErr(`note: copied NaaS credentials from ${machine} into ${twakDir}.`);
|
|
6866
|
+
return true;
|
|
6867
|
+
}
|
|
6594
6868
|
async function resolveTwakInitPassword(opts) {
|
|
6595
6869
|
if (opts.passwordStdin && opts.passwordFile) {
|
|
6596
6870
|
printErr("error: pass exactly one of --password-stdin or --password-file.");
|
|
6597
6871
|
throw new CliExit(2);
|
|
6598
6872
|
}
|
|
6599
6873
|
if (opts.passwordFile) {
|
|
6600
|
-
const file =
|
|
6874
|
+
const file = path21.resolve(opts.passwordFile);
|
|
6601
6875
|
let mode;
|
|
6602
6876
|
try {
|
|
6603
|
-
mode =
|
|
6877
|
+
mode = fs22.statSync(file).mode;
|
|
6604
6878
|
} catch {
|
|
6605
6879
|
printErr(`error: cannot read --password-file ${file}.`);
|
|
6606
6880
|
throw new CliExit(2);
|
|
@@ -6611,7 +6885,7 @@ async function resolveTwakInitPassword(opts) {
|
|
|
6611
6885
|
);
|
|
6612
6886
|
throw new CliExit(2);
|
|
6613
6887
|
}
|
|
6614
|
-
const password = (
|
|
6888
|
+
const password = (fs22.readFileSync(file, "utf-8").split(/\r?\n/)[0] ?? "").trim();
|
|
6615
6889
|
if (!password) {
|
|
6616
6890
|
printErr(`error: --password-file ${file} is empty.`);
|
|
6617
6891
|
throw new CliExit(2);
|
|
@@ -6671,11 +6945,14 @@ Install it (Node >=22): npm install -g @trustwallet/cli@${TWAK_CLI_VERSION}`
|
|
|
6671
6945
|
return 1;
|
|
6672
6946
|
}
|
|
6673
6947
|
const password = await resolveTwakInitPassword(opts);
|
|
6674
|
-
const homeDir =
|
|
6675
|
-
|
|
6948
|
+
const homeDir = path21.dirname(path21.dirname(walletFile));
|
|
6949
|
+
fs22.mkdirSync(homeDir, { recursive: true });
|
|
6950
|
+
if (!ensureTwakCredentials(walletFile, homeDir)) {
|
|
6951
|
+
return 1;
|
|
6952
|
+
}
|
|
6676
6953
|
const create = await runCapture(
|
|
6677
6954
|
"twak",
|
|
6678
|
-
["wallet", "create", "--no-keychain"],
|
|
6955
|
+
["wallet", "create", "--password", password, "--no-keychain"],
|
|
6679
6956
|
{
|
|
6680
6957
|
env: {
|
|
6681
6958
|
...process.env,
|
|
@@ -6683,8 +6960,8 @@ Install it (Node >=22): npm install -g @trustwallet/cli@${TWAK_CLI_VERSION}`
|
|
|
6683
6960
|
TWAK_WALLET_PASSWORD: password,
|
|
6684
6961
|
TWAK_NONINTERACTIVE: "1"
|
|
6685
6962
|
},
|
|
6686
|
-
// A prompting twak build reads these lines; an env-reading one
|
|
6687
|
-
//
|
|
6963
|
+
// A prompting twak build reads these lines; an env-reading one ignores
|
|
6964
|
+
// them. Both channels are kept alongside the required argv flag.
|
|
6688
6965
|
input: `${password}
|
|
6689
6966
|
${password}
|
|
6690
6967
|
`,
|
|
@@ -6695,8 +6972,8 @@ ${password}
|
|
|
6695
6972
|
const detail = `${create.stderr}
|
|
6696
6973
|
${create.stdout}`.trim();
|
|
6697
6974
|
printErr(
|
|
6698
|
-
`error: \`twak wallet create --no-keychain\`
|
|
6699
|
-
${detail}` :
|
|
6975
|
+
detail ? `error: \`twak wallet create --no-keychain\` failed:
|
|
6976
|
+
${detail}` : `error: \`twak wallet create --no-keychain\` did not produce ${walletFile}.`
|
|
6700
6977
|
);
|
|
6701
6978
|
if (/no api credentials/i.test(detail)) {
|
|
6702
6979
|
printErr(
|
|
@@ -6706,14 +6983,14 @@ ${detail}` : "."}`
|
|
|
6706
6983
|
return 1;
|
|
6707
6984
|
}
|
|
6708
6985
|
try {
|
|
6709
|
-
|
|
6986
|
+
fs22.chmodSync(walletFile, 384);
|
|
6710
6987
|
} catch {
|
|
6711
6988
|
}
|
|
6712
6989
|
if (!process.env.TWAK_WALLET_PASSWORD) {
|
|
6713
6990
|
process.env.TWAK_WALLET_PASSWORD = password;
|
|
6714
6991
|
}
|
|
6715
6992
|
printErr(
|
|
6716
|
-
`\u2713 twak wallet created under ${
|
|
6993
|
+
`\u2713 twak wallet created under ${path21.dirname(walletFile)} (no keychain)`
|
|
6717
6994
|
);
|
|
6718
6995
|
printErr(
|
|
6719
6996
|
"next: persist TWAK_WALLET_PASSWORD in .studio/.env.local so deploys and non-interactive signing can unlock it."
|
|
@@ -6750,7 +7027,7 @@ function cmdShow5(projectRootArg) {
|
|
|
6750
7027
|
...walletCfg.address ? { address: String(walletCfg.address) } : {}
|
|
6751
7028
|
});
|
|
6752
7029
|
const address = provider.address;
|
|
6753
|
-
const keystorePath =
|
|
7030
|
+
const keystorePath = path21.join(keystoreDir, `${address}.json`);
|
|
6754
7031
|
printOut(`address: ${address}`);
|
|
6755
7032
|
printOut(`source: ${kind}`);
|
|
6756
7033
|
printOut(`keystore_dir: ${keystoreDir}`);
|
|
@@ -6759,14 +7036,14 @@ function cmdShow5(projectRootArg) {
|
|
|
6759
7036
|
const configured = String(
|
|
6760
7037
|
walletCfg.session_file ?? ".studio/wallets/altana-session.json"
|
|
6761
7038
|
);
|
|
6762
|
-
const sessionFile =
|
|
7039
|
+
const sessionFile = path21.isAbsolute(configured) ? configured : path21.join(projectRoot, configured);
|
|
6763
7040
|
printOut(`session_file: ${sessionFile}`);
|
|
6764
7041
|
if (!isFile7(sessionFile)) {
|
|
6765
7042
|
printOut("session_status: missing (run `bag wallet session grant`)");
|
|
6766
7043
|
} else {
|
|
6767
7044
|
let envelope;
|
|
6768
7045
|
try {
|
|
6769
|
-
envelope = JSON.parse(
|
|
7046
|
+
envelope = JSON.parse(fs22.readFileSync(sessionFile, "utf8"));
|
|
6770
7047
|
} catch {
|
|
6771
7048
|
throw new Error(`invalid Altana session JSON at ${sessionFile}`);
|
|
6772
7049
|
}
|
|
@@ -6792,7 +7069,7 @@ function cmdList2(projectRootArg) {
|
|
|
6792
7069
|
const keystoreDir = resolveKeystoreDir2(projectRoot, null, walletCfg);
|
|
6793
7070
|
let entries;
|
|
6794
7071
|
try {
|
|
6795
|
-
entries =
|
|
7072
|
+
entries = fs22.readdirSync(keystoreDir).sort();
|
|
6796
7073
|
} catch {
|
|
6797
7074
|
return 0;
|
|
6798
7075
|
}
|
|
@@ -6804,7 +7081,7 @@ function cmdList2(projectRootArg) {
|
|
|
6804
7081
|
let data;
|
|
6805
7082
|
try {
|
|
6806
7083
|
data = JSON.parse(
|
|
6807
|
-
|
|
7084
|
+
fs22.readFileSync(path21.join(keystoreDir, child), "utf-8")
|
|
6808
7085
|
);
|
|
6809
7086
|
} catch {
|
|
6810
7087
|
continue;
|
|
@@ -6855,7 +7132,7 @@ async function cmdSign(msg, projectRootArg) {
|
|
|
6855
7132
|
}
|
|
6856
7133
|
async function cmdBalance(opts) {
|
|
6857
7134
|
const projectRoot = resolveWalletProjectRoot(opts.projectRoot);
|
|
6858
|
-
const data =
|
|
7135
|
+
const data = loadStudioToml10(path21.join(projectRoot, "studio.toml"));
|
|
6859
7136
|
const walletCfg = data.wallet !== null && typeof data.wallet === "object" ? data.wallet : {};
|
|
6860
7137
|
let address;
|
|
6861
7138
|
const kind = walletKind(walletCfg);
|
|
@@ -6982,10 +7259,10 @@ var PROVIDER_KEY_ENV = {
|
|
|
6982
7259
|
"pieverse-llm": "PIEVERSE_LLM_API_KEY"
|
|
6983
7260
|
};
|
|
6984
7261
|
function renderAgentcoreProject(target, name) {
|
|
6985
|
-
const acDir =
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
7262
|
+
const acDir = path22.join(target, "agentcore");
|
|
7263
|
+
fs23.mkdirSync(acDir, { recursive: true });
|
|
7264
|
+
fs23.writeFileSync(
|
|
7265
|
+
path22.join(acDir, "agentcore.json"),
|
|
6989
7266
|
`${JSON.stringify(
|
|
6990
7267
|
{
|
|
6991
7268
|
$schema: "https://schema.agentcore.aws.dev/v1/agentcore.json",
|
|
@@ -6999,7 +7276,7 @@ function renderAgentcoreProject(target, name) {
|
|
|
6999
7276
|
)}
|
|
7000
7277
|
`
|
|
7001
7278
|
);
|
|
7002
|
-
|
|
7279
|
+
fs23.writeFileSync(path22.join(acDir, "aws-targets.json"), "[]\n");
|
|
7003
7280
|
}
|
|
7004
7281
|
var AGENTS_MD_MARKER = "# bnbagent-studio additions (ERC-8183 seller)";
|
|
7005
7282
|
var AGENTS_MD_STUDIO_SECTION = `
|
|
@@ -7023,17 +7300,16 @@ every intent to the right playbook via its references.
|
|
|
7023
7300
|
under a deploy codeLocation). It lives at the workspace root precisely so
|
|
7024
7301
|
that no packaging path can bundle it into an artifact. Never print, log,
|
|
7025
7302
|
or export private key material.
|
|
7026
|
-
2. **Never commit secrets.** The \`.env.local\` file (API keys
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
WALLET_PASSWORD
|
|
7030
|
-
disk.
|
|
7303
|
+
2. **Never commit secrets.** The \`.env.local\` file (API keys and wallet
|
|
7304
|
+
unlock passwords) is gitignored \u2014 keep it that way; never echo its values
|
|
7305
|
+
into code, logs, argv, or chat. For evm-local and Altana projects, set
|
|
7306
|
+
WALLET_PASSWORD in that owner-only file before creating the keystore.
|
|
7031
7307
|
3. **Signing is fixed entrypoint code.** Never expose wallet signing as an
|
|
7032
7308
|
LLM-callable tool, and keep MCP tools read-only. All on-chain signing
|
|
7033
7309
|
lives in \`src/signing.ts\`.
|
|
7034
7310
|
4. **The quote path is deterministic** (fixed list price, clamp + sign).
|
|
7035
7311
|
Never put an LLM in the quote path.
|
|
7036
|
-
5. **Deploy with \`bag deploy --provider
|
|
7312
|
+
5. **Deploy with \`bag deploy --provider ${ADVERTISED_PROVIDERS_HELP}\`.** Every deploy or
|
|
7037
7313
|
redeploy requires a visible provider choice. Studio runs its local business
|
|
7038
7314
|
gates, then delegates cloud credentials, secrets, packaging and lifecycle
|
|
7039
7315
|
calls to the pinned bnbagent-deploy CLI. Do not bypass this boundary with
|
|
@@ -7044,30 +7320,30 @@ every intent to the right playbook via its references.
|
|
|
7044
7320
|
and state the tradeoff.
|
|
7045
7321
|
`;
|
|
7046
7322
|
function appendAgentsMdStudioSection(target) {
|
|
7047
|
-
const agentsMd =
|
|
7323
|
+
const agentsMd = path22.join(target, "AGENTS.md");
|
|
7048
7324
|
let existing = "";
|
|
7049
7325
|
try {
|
|
7050
|
-
existing =
|
|
7326
|
+
existing = fs23.readFileSync(agentsMd, "utf-8");
|
|
7051
7327
|
} catch {
|
|
7052
7328
|
existing = "";
|
|
7053
7329
|
}
|
|
7054
7330
|
if (existing.includes(AGENTS_MD_MARKER)) {
|
|
7055
7331
|
return;
|
|
7056
7332
|
}
|
|
7057
|
-
|
|
7333
|
+
fs23.writeFileSync(
|
|
7058
7334
|
agentsMd,
|
|
7059
7335
|
`${existing.replace(/\n+$/, "")}
|
|
7060
7336
|
${AGENTS_MD_STUDIO_SECTION}`
|
|
7061
7337
|
);
|
|
7062
7338
|
}
|
|
7063
7339
|
function seedAwsTargets(target) {
|
|
7064
|
-
const p =
|
|
7340
|
+
const p = path22.join(target, "agentcore", "aws-targets.json");
|
|
7065
7341
|
if (!isFile8(p)) {
|
|
7066
7342
|
return;
|
|
7067
7343
|
}
|
|
7068
7344
|
let data;
|
|
7069
7345
|
try {
|
|
7070
|
-
data = JSON.parse(
|
|
7346
|
+
data = JSON.parse(fs23.readFileSync(p, "utf-8"));
|
|
7071
7347
|
} catch {
|
|
7072
7348
|
return;
|
|
7073
7349
|
}
|
|
@@ -7078,7 +7354,7 @@ function seedAwsTargets(target) {
|
|
|
7078
7354
|
{ name: "default", account: AWS_ACCOUNT_PLACEHOLDER, region: "us-east-1" }
|
|
7079
7355
|
];
|
|
7080
7356
|
try {
|
|
7081
|
-
|
|
7357
|
+
fs23.writeFileSync(p, `${JSON.stringify(skeleton, null, 2)}
|
|
7082
7358
|
`);
|
|
7083
7359
|
} catch {
|
|
7084
7360
|
return;
|
|
@@ -7101,13 +7377,13 @@ function registerAgentcoreRuntime(target, name, opts = {}) {
|
|
|
7101
7377
|
const protocol = nativeProtocolOf(faces);
|
|
7102
7378
|
const stem2 = entryStemOf(faces);
|
|
7103
7379
|
const isContainer = opts.packaging === "container" || walletKind2 === "twak";
|
|
7104
|
-
const cfgPath =
|
|
7380
|
+
const cfgPath = path22.join(target, "agentcore", "agentcore.json");
|
|
7105
7381
|
if (!isFile8(cfgPath)) {
|
|
7106
7382
|
return;
|
|
7107
7383
|
}
|
|
7108
7384
|
let cfg;
|
|
7109
7385
|
try {
|
|
7110
|
-
const parsed = JSON.parse(
|
|
7386
|
+
const parsed = JSON.parse(fs23.readFileSync(cfgPath, "utf-8"));
|
|
7111
7387
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
7112
7388
|
return;
|
|
7113
7389
|
}
|
|
@@ -7146,7 +7422,7 @@ function registerAgentcoreRuntime(target, name, opts = {}) {
|
|
|
7146
7422
|
runtimes.push(runtime);
|
|
7147
7423
|
cfg.runtimes = runtimes;
|
|
7148
7424
|
try {
|
|
7149
|
-
|
|
7425
|
+
fs23.writeFileSync(cfgPath, `${JSON.stringify(cfg, null, 2)}
|
|
7150
7426
|
`);
|
|
7151
7427
|
} catch {
|
|
7152
7428
|
return;
|
|
@@ -7283,12 +7559,12 @@ function registerInit(program) {
|
|
|
7283
7559
|
);
|
|
7284
7560
|
}
|
|
7285
7561
|
function enclosingProjectRoot(start) {
|
|
7286
|
-
let current =
|
|
7562
|
+
let current = path22.resolve(start);
|
|
7287
7563
|
for (; ; ) {
|
|
7288
|
-
if (isFile8(
|
|
7564
|
+
if (isFile8(path22.join(current, APP_DIR, AGENT_PKG, "studio.toml"))) {
|
|
7289
7565
|
return current;
|
|
7290
7566
|
}
|
|
7291
|
-
const parent =
|
|
7567
|
+
const parent = path22.dirname(current);
|
|
7292
7568
|
if (parent === current) {
|
|
7293
7569
|
return null;
|
|
7294
7570
|
}
|
|
@@ -7296,8 +7572,8 @@ function enclosingProjectRoot(start) {
|
|
|
7296
7572
|
}
|
|
7297
7573
|
}
|
|
7298
7574
|
async function cmdInit(nameArg, opts) {
|
|
7299
|
-
const target =
|
|
7300
|
-
let projectName2 =
|
|
7575
|
+
const target = path22.resolve(process.cwd(), nameArg);
|
|
7576
|
+
let projectName2 = path22.basename(target);
|
|
7301
7577
|
if (!projectName2) {
|
|
7302
7578
|
printErr(
|
|
7303
7579
|
`error: cannot derive a project name from '${nameArg}' (path has no basename).`
|
|
@@ -7382,15 +7658,15 @@ async function cmdInit(nameArg, opts) {
|
|
|
7382
7658
|
return 2;
|
|
7383
7659
|
}
|
|
7384
7660
|
}
|
|
7385
|
-
const enclosing = enclosingProjectRoot(
|
|
7661
|
+
const enclosing = enclosingProjectRoot(path22.dirname(target));
|
|
7386
7662
|
if (enclosing !== null) {
|
|
7387
7663
|
printErr(
|
|
7388
|
-
`error: ${
|
|
7389
|
-
\`bag init\` resolves the new project relative to the current directory, so running it here would nest a second scaffold inside ${
|
|
7664
|
+
`error: ${path22.dirname(target)} is inside an existing bag project (${enclosing}).
|
|
7665
|
+
\`bag init\` resolves the new project relative to the current directory, so running it here would nest a second scaffold inside ${path22.basename(enclosing)}/. cd to a directory OUTSIDE any project and retry.`
|
|
7390
7666
|
);
|
|
7391
7667
|
return 2;
|
|
7392
7668
|
}
|
|
7393
|
-
if (
|
|
7669
|
+
if (fs23.existsSync(target) && !opts.force) {
|
|
7394
7670
|
printErr(`error: ${target} already exists. Use --force to overwrite.`);
|
|
7395
7671
|
return 2;
|
|
7396
7672
|
}
|
|
@@ -7421,8 +7697,8 @@ async function cmdInit(nameArg, opts) {
|
|
|
7421
7697
|
);
|
|
7422
7698
|
return 2;
|
|
7423
7699
|
}
|
|
7424
|
-
if (
|
|
7425
|
-
|
|
7700
|
+
if (fs23.existsSync(target)) {
|
|
7701
|
+
fs23.rmSync(target, { recursive: true, force: true });
|
|
7426
7702
|
}
|
|
7427
7703
|
if (destination === "platform") {
|
|
7428
7704
|
printCampaignIntro();
|
|
@@ -7467,7 +7743,7 @@ async function cmdInit(nameArg, opts) {
|
|
|
7467
7743
|
}
|
|
7468
7744
|
}
|
|
7469
7745
|
try {
|
|
7470
|
-
|
|
7746
|
+
fs23.mkdirSync(target, { recursive: true });
|
|
7471
7747
|
if (runtime === "agentcore") {
|
|
7472
7748
|
renderAgentcoreProject(target, projectName2);
|
|
7473
7749
|
}
|
|
@@ -7483,7 +7759,7 @@ async function cmdInit(nameArg, opts) {
|
|
|
7483
7759
|
printErr(
|
|
7484
7760
|
`error: the b402 seller rail supports wallet.kind evm-local or twak only; '${walletKind2}' cannot act as the b402 payout wallet. Re-run with --rails 8183 or a supported --wallet-kind.`
|
|
7485
7761
|
);
|
|
7486
|
-
|
|
7762
|
+
fs23.rmSync(target, { recursive: true, force: true });
|
|
7487
7763
|
return 2;
|
|
7488
7764
|
}
|
|
7489
7765
|
const ides = resolveEmitIdes(opts.ide);
|
|
@@ -7526,9 +7802,9 @@ async function cmdInit(nameArg, opts) {
|
|
|
7526
7802
|
});
|
|
7527
7803
|
seedAwsTargets(target);
|
|
7528
7804
|
}
|
|
7529
|
-
const agentDir =
|
|
7530
|
-
|
|
7531
|
-
|
|
7805
|
+
const agentDir = path22.join(target, APP_DIR, AGENT_PKG);
|
|
7806
|
+
fs23.mkdirSync(path22.join(agentDir, "vendor"), { recursive: true });
|
|
7807
|
+
fs23.writeFileSync(path22.join(agentDir, "vendor", ".gitkeep"), "");
|
|
7532
7808
|
const skipInstall = opts.install === false || opts.venv === false;
|
|
7533
7809
|
let provisioned = false;
|
|
7534
7810
|
let installFailed = false;
|
|
@@ -7657,64 +7933,64 @@ function derivePackaging(walletKind2, destination, platformArtifact2 = "zip", ru
|
|
|
7657
7933
|
}
|
|
7658
7934
|
function scaffold(target, name, o) {
|
|
7659
7935
|
const packageManagerVersion = pnpmVersion();
|
|
7660
|
-
|
|
7661
|
-
|
|
7936
|
+
fs23.writeFileSync(
|
|
7937
|
+
path22.join(target, "package.json"),
|
|
7662
7938
|
renderWorkspacePackageJson(name, packageManagerVersion)
|
|
7663
7939
|
);
|
|
7664
|
-
|
|
7665
|
-
|
|
7940
|
+
fs23.writeFileSync(
|
|
7941
|
+
path22.join(target, "pnpm-workspace.yaml"),
|
|
7666
7942
|
renderPnpmWorkspaceYaml()
|
|
7667
7943
|
);
|
|
7668
|
-
|
|
7669
|
-
if (!isFile8(
|
|
7670
|
-
|
|
7671
|
-
|
|
7944
|
+
fs23.writeFileSync(path22.join(target, ".gitignore"), renderWorkspaceGitignore());
|
|
7945
|
+
if (!isFile8(path22.join(target, "README.md"))) {
|
|
7946
|
+
fs23.writeFileSync(
|
|
7947
|
+
path22.join(target, "README.md"),
|
|
7672
7948
|
renderWorkspaceReadme(name, o.destination)
|
|
7673
7949
|
);
|
|
7674
7950
|
}
|
|
7675
7951
|
appendAgentsMdStudioSection(target);
|
|
7676
|
-
const appRoot =
|
|
7677
|
-
|
|
7678
|
-
const agentRoot2 =
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7952
|
+
const appRoot = path22.join(target, APP_DIR);
|
|
7953
|
+
fs23.mkdirSync(appRoot, { recursive: true });
|
|
7954
|
+
const agentRoot2 = path22.join(appRoot, AGENT_PKG);
|
|
7955
|
+
fs23.mkdirSync(agentRoot2, { recursive: true });
|
|
7956
|
+
fs23.writeFileSync(
|
|
7957
|
+
path22.join(agentRoot2, "pnpm-workspace.yaml"),
|
|
7682
7958
|
renderAgentPnpmWorkspaceYaml()
|
|
7683
7959
|
);
|
|
7684
7960
|
if (o.walletKind === "evm-local" || o.walletKind === "altana") {
|
|
7685
|
-
|
|
7961
|
+
fs23.mkdirSync(path22.join(target, ".studio", "wallets"), { recursive: true });
|
|
7686
7962
|
} else if (o.walletKind === "twak") {
|
|
7687
7963
|
let homeDir;
|
|
7688
7964
|
let label;
|
|
7689
7965
|
if (o.twakHome === void 0 || o.twakHome === DEDICATED_TWAK_HOME_REL) {
|
|
7690
|
-
homeDir =
|
|
7966
|
+
homeDir = path22.join(target, ".studio", "twak");
|
|
7691
7967
|
label = ".studio/twak";
|
|
7692
7968
|
} else {
|
|
7693
|
-
homeDir =
|
|
7969
|
+
homeDir = path22.isAbsolute(o.twakHome) ? o.twakHome : path22.resolve(agentRoot2, o.twakHome);
|
|
7694
7970
|
label = o.twakHome;
|
|
7695
7971
|
}
|
|
7696
|
-
|
|
7972
|
+
fs23.mkdirSync(homeDir, { recursive: true });
|
|
7697
7973
|
if (ensureTwakKeychain(homeDir)) {
|
|
7698
7974
|
printOut(
|
|
7699
7975
|
`\u2713 isolated twak keychain ready under ${label} (macOS) \u2014 no manual \`security\` setup needed`
|
|
7700
7976
|
);
|
|
7701
7977
|
}
|
|
7702
7978
|
}
|
|
7703
|
-
|
|
7704
|
-
|
|
7979
|
+
fs23.writeFileSync(
|
|
7980
|
+
path22.join(agentRoot2, "package.json"),
|
|
7705
7981
|
renderAgentPackageJson(name, o.runtime, o.provider, o.faces, o.walletKind)
|
|
7706
7982
|
);
|
|
7707
|
-
|
|
7708
|
-
|
|
7983
|
+
fs23.writeFileSync(
|
|
7984
|
+
path22.join(agentRoot2, "tsconfig.json"),
|
|
7709
7985
|
renderAgentTsconfig()
|
|
7710
7986
|
);
|
|
7711
|
-
|
|
7712
|
-
|
|
7987
|
+
fs23.writeFileSync(
|
|
7988
|
+
path22.join(agentRoot2, "studio.toml"),
|
|
7713
7989
|
renderAgentStudioToml(name, o)
|
|
7714
7990
|
);
|
|
7715
|
-
const envLocal =
|
|
7716
|
-
|
|
7717
|
-
|
|
7991
|
+
const envLocal = path22.join(target, ".studio", ".env.local");
|
|
7992
|
+
fs23.mkdirSync(path22.dirname(envLocal), { recursive: true });
|
|
7993
|
+
fs23.writeFileSync(
|
|
7718
7994
|
envLocal,
|
|
7719
7995
|
renderAgentEnvLocal(
|
|
7720
7996
|
o.provider,
|
|
@@ -7725,9 +8001,9 @@ function scaffold(target, name, o) {
|
|
|
7725
8001
|
o.network
|
|
7726
8002
|
)
|
|
7727
8003
|
);
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
8004
|
+
fs23.writeFileSync(path22.join(agentRoot2, ".gitignore"), renderAgentGitignore());
|
|
8005
|
+
fs23.writeFileSync(
|
|
8006
|
+
path22.join(agentRoot2, "README.md"),
|
|
7731
8007
|
renderAgentReadme(name, o.faces, o.destination)
|
|
7732
8008
|
);
|
|
7733
8009
|
const packaging = derivePackaging(
|
|
@@ -7763,18 +8039,18 @@ function emitRecipe(base, name, opts = {}) {
|
|
|
7763
8039
|
const recipe = loadRecipe(name, { mode: opts.mode ?? null });
|
|
7764
8040
|
for (const rf of recipe.files) {
|
|
7765
8041
|
const targetPath = substitutePlaceholders(rf.targetPath, opts.context);
|
|
7766
|
-
const basename16 =
|
|
7767
|
-
const dst = basename16 === "Dockerfile" || basename16 === ".dockerignore" ?
|
|
7768
|
-
|
|
7769
|
-
|
|
8042
|
+
const basename16 = path22.posix.basename(targetPath);
|
|
8043
|
+
const dst = basename16 === "Dockerfile" || basename16 === ".dockerignore" ? path22.join(base, basename16) : path22.join(base, targetPath);
|
|
8044
|
+
fs23.mkdirSync(path22.dirname(dst), { recursive: true });
|
|
8045
|
+
fs23.writeFileSync(dst, substitutePlaceholders(rf.content, opts.context));
|
|
7770
8046
|
}
|
|
7771
8047
|
}
|
|
7772
8048
|
function readRecipeNodeDeps(recipeName, group) {
|
|
7773
|
-
const tomlPath =
|
|
8049
|
+
const tomlPath = path22.join(bundledRecipesRoot(), recipeName, "recipe.toml");
|
|
7774
8050
|
if (!isFile8(tomlPath)) {
|
|
7775
8051
|
return [];
|
|
7776
8052
|
}
|
|
7777
|
-
const meta = parseToml(
|
|
8053
|
+
const meta = parseToml(fs23.readFileSync(tomlPath, "utf-8"));
|
|
7778
8054
|
const depsSection = meta.dependencies !== null && typeof meta.dependencies === "object" ? meta.dependencies : {};
|
|
7779
8055
|
const collect = (v) => Array.isArray(v) ? v.filter((d) => typeof d === "string") : [];
|
|
7780
8056
|
const deps = collect(depsSection.node);
|
|
@@ -8223,7 +8499,13 @@ function renderAgentEnvLocal(provider, storageProvider, walletKind2, rails, b402
|
|
|
8223
8499
|
lines.push(
|
|
8224
8500
|
"",
|
|
8225
8501
|
"# B402 merchant credentials (issued per environment after manual approval).",
|
|
8226
|
-
free ? "# FREE price 0 does not use these credentials; leave them empty until switching to PAID." : "# PAID
|
|
8502
|
+
free ? "# FREE price 0 does not use these credentials; leave them empty until switching to PAID." : "# PAID: create the agent wallet first, then apply for a separate merchant",
|
|
8503
|
+
...free ? [] : [
|
|
8504
|
+
"# for that exact wallet and environment. Never reuse merchant credentials",
|
|
8505
|
+
"# across wallets.",
|
|
8506
|
+
`# Apply: ${B402_DEVELOPER_ACCOUNT_URL}`,
|
|
8507
|
+
"# PAID requires all four; all absent = dormant, partial = boot error."
|
|
8508
|
+
],
|
|
8227
8509
|
`B402_BASE_URL=${baseUrl}`,
|
|
8228
8510
|
"B402_CLIENT_ID=",
|
|
8229
8511
|
"B402_ACCESS_TOKEN=",
|
|
@@ -8301,7 +8583,7 @@ It auto-loads \`.studio/.env.local\` \u2014 no need to \`source\` it.
|
|
|
8301
8583
|
## Deploy (managed platform \u2014 48h testnet trial)
|
|
8302
8584
|
|
|
8303
8585
|
\`\`\`bash
|
|
8304
|
-
bag platform login # GitHub device flow (~/.
|
|
8586
|
+
bag platform login # GitHub device flow (~/.bnbagent-deploy/bnb/session.json)
|
|
8305
8587
|
# From the workspace root:
|
|
8306
8588
|
bag deploy --provider bnb # explicit 48h trial provider
|
|
8307
8589
|
\`\`\`
|
|
@@ -8353,7 +8635,7 @@ bag deploy --provider aws
|
|
|
8353
8635
|
`;
|
|
8354
8636
|
}
|
|
8355
8637
|
function emitProviderSkills(target, provider, ides) {
|
|
8356
|
-
const skillDir =
|
|
8638
|
+
const skillDir = path22.join(
|
|
8357
8639
|
bundledRecipesRoot(),
|
|
8358
8640
|
"providers",
|
|
8359
8641
|
provider,
|
|
@@ -8363,34 +8645,34 @@ function emitProviderSkills(target, provider, ides) {
|
|
|
8363
8645
|
return;
|
|
8364
8646
|
}
|
|
8365
8647
|
let emittedCursor = false;
|
|
8366
|
-
for (const md of
|
|
8367
|
-
const srcText =
|
|
8648
|
+
for (const md of fs23.readdirSync(skillDir).filter((n) => n.endsWith(".md")).sort()) {
|
|
8649
|
+
const srcText = fs23.readFileSync(path22.join(skillDir, md), "utf-8");
|
|
8368
8650
|
const stem2 = md.replace(/\.md$/, "");
|
|
8369
8651
|
for (const ide of ides) {
|
|
8370
8652
|
const [relPath, content] = renderSkillPayload(srcText, stem2, ide);
|
|
8371
|
-
const base = ide === "claude-code" ?
|
|
8372
|
-
const dst =
|
|
8373
|
-
|
|
8374
|
-
|
|
8653
|
+
const base = ide === "claude-code" ? path22.join(target, ".claude", "skills") : path22.join(target, ".cursor", "rules");
|
|
8654
|
+
const dst = path22.join(base, relPath);
|
|
8655
|
+
fs23.mkdirSync(path22.dirname(dst), { recursive: true });
|
|
8656
|
+
fs23.writeFileSync(dst, content);
|
|
8375
8657
|
if (ide === "cursor") {
|
|
8376
8658
|
emittedCursor = true;
|
|
8377
8659
|
}
|
|
8378
8660
|
}
|
|
8379
8661
|
}
|
|
8380
8662
|
if (emittedCursor) {
|
|
8381
|
-
ensureCursorGitignore(
|
|
8663
|
+
ensureCursorGitignore(path22.join(target, ".gitignore"));
|
|
8382
8664
|
}
|
|
8383
8665
|
}
|
|
8384
8666
|
function ensureCursorGitignore(gitignore) {
|
|
8385
8667
|
if (!isFile8(gitignore)) {
|
|
8386
8668
|
return;
|
|
8387
8669
|
}
|
|
8388
|
-
const text2 =
|
|
8670
|
+
const text2 = fs23.readFileSync(gitignore, "utf-8");
|
|
8389
8671
|
if (text2.includes(".cursor/rules/")) {
|
|
8390
8672
|
return;
|
|
8391
8673
|
}
|
|
8392
8674
|
const addition = "\n# Cursor rules emitted at init (regeneratable via `bag skills install --target cursor`).\n.cursor/rules/\n";
|
|
8393
|
-
|
|
8675
|
+
fs23.writeFileSync(gitignore, `${text2.replace(/\n+$/, "")}
|
|
8394
8676
|
${addition}`);
|
|
8395
8677
|
}
|
|
8396
8678
|
async function resolveWalletKind(flagValue, isTty) {
|
|
@@ -8572,7 +8854,7 @@ function readWalletAddress(studioToml) {
|
|
|
8572
8854
|
return null;
|
|
8573
8855
|
}
|
|
8574
8856
|
try {
|
|
8575
|
-
const data = parseToml(
|
|
8857
|
+
const data = parseToml(fs23.readFileSync(studioToml, "utf-8"));
|
|
8576
8858
|
const wallet = data.wallet;
|
|
8577
8859
|
if (wallet !== null && typeof wallet === "object") {
|
|
8578
8860
|
const addr = wallet.address;
|
|
@@ -8675,7 +8957,9 @@ async function runOnboarding(o) {
|
|
|
8675
8957
|
if (password === null) {
|
|
8676
8958
|
return false;
|
|
8677
8959
|
}
|
|
8678
|
-
const agentRoot2 =
|
|
8960
|
+
const agentRoot2 = path22.join(o.workspaceRoot, APP_DIR, AGENT_PKG);
|
|
8961
|
+
const { envLocalPath: envLocalPath19 } = await import("@bnbagent/studio-runtime/config");
|
|
8962
|
+
setEnvVar(envLocalPath19(agentRoot2), "WALLET_PASSWORD", password);
|
|
8679
8963
|
const savedCwd = process.cwd();
|
|
8680
8964
|
const savedPw = process.env.WALLET_PASSWORD;
|
|
8681
8965
|
let address = null;
|
|
@@ -8701,7 +8985,7 @@ async function runOnboarding(o) {
|
|
|
8701
8985
|
);
|
|
8702
8986
|
return false;
|
|
8703
8987
|
}
|
|
8704
|
-
address = readWalletAddress(
|
|
8988
|
+
address = readWalletAddress(path22.join(agentRoot2, "studio.toml"));
|
|
8705
8989
|
if (o.walletKind !== "altana" || o.provider !== "pieverse-llm") {
|
|
8706
8990
|
await onboardProviderActivation(agentRoot2, o.provider, o.model);
|
|
8707
8991
|
}
|
|
@@ -8714,8 +8998,7 @@ async function runOnboarding(o) {
|
|
|
8714
8998
|
}
|
|
8715
8999
|
}
|
|
8716
9000
|
if (o.storageProvider !== "local") {
|
|
8717
|
-
|
|
8718
|
-
await onboardIpfsKey(envLocalPath18(agentRoot2), o.ipfsKey);
|
|
9001
|
+
await onboardIpfsKey(envLocalPath19(agentRoot2), o.ipfsKey);
|
|
8719
9002
|
}
|
|
8720
9003
|
if (address) {
|
|
8721
9004
|
await printFaucetHint(o.network, address);
|
|
@@ -8731,9 +9014,9 @@ async function onboardProviderActivation(agentRoot2, provider, model) {
|
|
|
8731
9014
|
if (provider === "pieverse-llm") {
|
|
8732
9015
|
const chosenModel = model ?? await promptPieverseModel();
|
|
8733
9016
|
if (model === void 0) {
|
|
8734
|
-
const tomlPath =
|
|
8735
|
-
const text2 =
|
|
8736
|
-
|
|
9017
|
+
const tomlPath = path22.join(agentRoot2, "studio.toml");
|
|
9018
|
+
const text2 = fs23.readFileSync(tomlPath, "utf-8");
|
|
9019
|
+
fs23.writeFileSync(
|
|
8737
9020
|
tomlPath,
|
|
8738
9021
|
updateSection(text2, "llm", { model: chosenModel })
|
|
8739
9022
|
);
|
|
@@ -8769,45 +9052,50 @@ set ${keyEnv}= in .studio/.env.local before running \`bag dev\`.`
|
|
|
8769
9052
|
}
|
|
8770
9053
|
}
|
|
8771
9054
|
async function runOnboardingTwak(o) {
|
|
8772
|
-
const agentRoot2 =
|
|
8773
|
-
const studioToml =
|
|
9055
|
+
const agentRoot2 = path22.join(o.workspaceRoot, APP_DIR, AGENT_PKG);
|
|
9056
|
+
const studioToml = path22.join(agentRoot2, "studio.toml");
|
|
8774
9057
|
if (await whichTwak() === null) {
|
|
8775
9058
|
printErr(
|
|
8776
9059
|
`
|
|
8777
9060
|
wallet.kind = 'twak' but the \`twak\` CLI is not on PATH. Install it (Node >=22):
|
|
8778
9061
|
npm install -g @trustwallet/cli@${TWAK_CLI_VERSION}
|
|
8779
|
-
then create the project-dedicated wallet
|
|
8780
|
-
|
|
8781
|
-
|
|
9062
|
+
then set up NaaS credentials once and create the project-dedicated wallet
|
|
9063
|
+
(\`bag wallet twak-init\` runs \`twak wallet create --password \u2026 --no-keychain\` for
|
|
9064
|
+
you, so you never type the password on a command line, and adopts the address):
|
|
9065
|
+
HOME=$PWD/.studio/twak twak setup
|
|
9066
|
+
cd app/agent && bag wallet twak-init && bag llm activate`
|
|
8782
9067
|
);
|
|
8783
9068
|
return false;
|
|
8784
9069
|
}
|
|
8785
9070
|
let walletCfg = {};
|
|
8786
9071
|
try {
|
|
8787
|
-
const data = parseToml(
|
|
9072
|
+
const data = parseToml(fs23.readFileSync(studioToml, "utf-8"));
|
|
8788
9073
|
if (data.wallet !== null && typeof data.wallet === "object") {
|
|
8789
9074
|
walletCfg = data.wallet;
|
|
8790
9075
|
}
|
|
8791
9076
|
} catch {
|
|
8792
9077
|
walletCfg = {};
|
|
8793
9078
|
}
|
|
8794
|
-
const { twakWalletFile: twakWalletFile2 } = await import("./_twak-
|
|
9079
|
+
const { twakWalletFile: twakWalletFile2 } = await import("./_twak-4XF4H5PL.js");
|
|
8795
9080
|
let projectWallet = twakWalletFile2(walletCfg, agentRoot2);
|
|
8796
|
-
const machineWallet =
|
|
9081
|
+
const machineWallet = path22.join(os4.homedir(), ".twak", "wallet.json");
|
|
8797
9082
|
if (!o.twakHomePinned && isFile8(machineWallet) && realpathIfExists(projectWallet) !== realpathIfExists(machineWallet)) {
|
|
8798
9083
|
if (await promptUseMachineTwakWallet(machineWallet)) {
|
|
8799
9084
|
projectWallet = adoptMachineTwakWallet(machineWallet, o.workspaceRoot);
|
|
8800
9085
|
}
|
|
8801
9086
|
}
|
|
8802
9087
|
if (!isFile8(projectWallet)) {
|
|
8803
|
-
const homeDir =
|
|
9088
|
+
const homeDir = path22.dirname(path22.dirname(projectWallet));
|
|
8804
9089
|
try {
|
|
8805
|
-
|
|
9090
|
+
fs23.mkdirSync(homeDir, { recursive: true });
|
|
8806
9091
|
} catch {
|
|
8807
9092
|
}
|
|
8808
9093
|
printErr(
|
|
8809
9094
|
`
|
|
8810
|
-
No twak wallet at this project's dedicated home yet. Create it ONCE
|
|
9095
|
+
No twak wallet at this project's dedicated home yet. Create it ONCE \u2014 let studio source the password so you never type it on a command line:
|
|
9096
|
+
cd app/agent && bag wallet twak-init # hidden prompt (CI: --password-stdin / --password-file)
|
|
9097
|
+
or do it yourself:
|
|
9098
|
+
HOME=${homeDir} twak setup
|
|
8811
9099
|
HOME=${homeDir} twak wallet create --password <your-password> --no-keychain
|
|
8812
9100
|
then finish onboarding:
|
|
8813
9101
|
cd app/agent && bag wallet new && bag llm activate
|
|
@@ -8844,8 +9132,8 @@ Guide: the bnbagent-studio-using-twak-wallet.md reference (installed by \`bag sk
|
|
|
8844
9132
|
process.chdir(savedCwd);
|
|
8845
9133
|
}
|
|
8846
9134
|
if (o.storageProvider !== "local") {
|
|
8847
|
-
const { envLocalPath:
|
|
8848
|
-
await onboardIpfsKey(
|
|
9135
|
+
const { envLocalPath: envLocalPath19 } = await import("@bnbagent/studio-runtime/config");
|
|
9136
|
+
await onboardIpfsKey(envLocalPath19(agentRoot2), o.ipfsKey);
|
|
8849
9137
|
}
|
|
8850
9138
|
if (address) {
|
|
8851
9139
|
await printFaucetHint(o.network, address);
|
|
@@ -8854,9 +9142,9 @@ Guide: the bnbagent-studio-using-twak-wallet.md reference (installed by \`bag sk
|
|
|
8854
9142
|
}
|
|
8855
9143
|
function realpathIfExists(p) {
|
|
8856
9144
|
try {
|
|
8857
|
-
return
|
|
9145
|
+
return fs23.realpathSync(p);
|
|
8858
9146
|
} catch {
|
|
8859
|
-
return
|
|
9147
|
+
return path22.resolve(p);
|
|
8860
9148
|
}
|
|
8861
9149
|
}
|
|
8862
9150
|
async function promptUseMachineTwakWallet(machineWallet) {
|
|
@@ -8869,39 +9157,39 @@ Found an existing twak wallet: ${machineWallet}`);
|
|
|
8869
9157
|
return answer === "y" || answer === "yes";
|
|
8870
9158
|
}
|
|
8871
9159
|
function adoptMachineTwakWallet(machineWallet, workspaceRoot) {
|
|
8872
|
-
const homeDir =
|
|
8873
|
-
const twakDir =
|
|
8874
|
-
|
|
9160
|
+
const homeDir = path22.join(workspaceRoot, ".studio", "twak");
|
|
9161
|
+
const twakDir = path22.join(homeDir, ".twak");
|
|
9162
|
+
fs23.mkdirSync(twakDir, { recursive: true });
|
|
8875
9163
|
try {
|
|
8876
|
-
|
|
8877
|
-
|
|
9164
|
+
fs23.chmodSync(homeDir, 448);
|
|
9165
|
+
fs23.chmodSync(twakDir, 448);
|
|
8878
9166
|
} catch {
|
|
8879
9167
|
}
|
|
8880
9168
|
for (const name of ["wallet.json", "credentials.json"]) {
|
|
8881
|
-
const src =
|
|
9169
|
+
const src = path22.join(path22.dirname(machineWallet), name);
|
|
8882
9170
|
if (isFile8(src)) {
|
|
8883
|
-
const dst =
|
|
8884
|
-
|
|
8885
|
-
|
|
9171
|
+
const dst = path22.join(twakDir, name);
|
|
9172
|
+
fs23.writeFileSync(dst, fs23.readFileSync(src, "utf-8"), { mode: 384 });
|
|
9173
|
+
fs23.chmodSync(dst, 384);
|
|
8886
9174
|
}
|
|
8887
9175
|
}
|
|
8888
|
-
return
|
|
9176
|
+
return path22.join(twakDir, "wallet.json");
|
|
8889
9177
|
}
|
|
8890
9178
|
function normalizeTwakHome(raw) {
|
|
8891
|
-
const expanded = raw.startsWith("~") ?
|
|
8892
|
-
if (!
|
|
9179
|
+
const expanded = raw.startsWith("~") ? path22.join(os4.homedir(), raw.slice(1)) : raw;
|
|
9180
|
+
if (!path22.isAbsolute(expanded)) {
|
|
8893
9181
|
return { home: raw };
|
|
8894
9182
|
}
|
|
8895
9183
|
const isFile19 = (p) => {
|
|
8896
9184
|
try {
|
|
8897
|
-
return
|
|
9185
|
+
return fs23.statSync(p).isFile();
|
|
8898
9186
|
} catch {
|
|
8899
9187
|
return false;
|
|
8900
9188
|
}
|
|
8901
9189
|
};
|
|
8902
|
-
if (
|
|
8903
|
-
const parent =
|
|
8904
|
-
if (isFile19(
|
|
9190
|
+
if (path22.basename(expanded) === ".twak") {
|
|
9191
|
+
const parent = path22.dirname(expanded);
|
|
9192
|
+
if (isFile19(path22.join(expanded, "wallet.json"))) {
|
|
8905
9193
|
return {
|
|
8906
9194
|
home: parent,
|
|
8907
9195
|
note: `note: --twak-home points at the .twak wallet directory itself; using its parent '${parent}' as the wallet home (the runtime resolves <twak_home>/.twak/wallet.json).`
|
|
@@ -8911,15 +9199,15 @@ function normalizeTwakHome(raw) {
|
|
|
8911
9199
|
error: `error: --twak-home must name the HOME-STYLE PARENT directory (the one that contains .twak/wallet.json), not a .twak directory itself. '${raw}' holds no wallet.json, so it cannot be auto-corrected \u2014 pass '${parent}' to adopt an existing wallet, or omit --twak-home to use the project-dedicated .studio/twak.`
|
|
8912
9200
|
};
|
|
8913
9201
|
}
|
|
8914
|
-
if (isFile19(
|
|
9202
|
+
if (isFile19(path22.join(expanded, "wallet.json")) && !isFile19(path22.join(expanded, ".twak", "wallet.json"))) {
|
|
8915
9203
|
return {
|
|
8916
|
-
error: `error: --twak-home '${raw}' looks like a twak WALLET directory (it contains wallet.json directly). Pass its parent '${
|
|
9204
|
+
error: `error: --twak-home '${raw}' looks like a twak WALLET directory (it contains wallet.json directly). Pass its parent '${path22.dirname(expanded)}' instead \u2014 the runtime resolves <twak_home>/.twak/wallet.json.`
|
|
8917
9205
|
};
|
|
8918
9206
|
}
|
|
8919
|
-
if (!isFile19(
|
|
9207
|
+
if (!isFile19(path22.join(expanded, ".twak", "wallet.json"))) {
|
|
8920
9208
|
return {
|
|
8921
9209
|
home: raw,
|
|
8922
|
-
note: `note: no wallet found at ${
|
|
9210
|
+
note: `note: no wallet found at ${path22.join(raw, ".twak", "wallet.json")} \u2014 treating --twak-home as a NEW project wallet home; \`bag wallet new\` will guide wallet creation.`
|
|
8923
9211
|
};
|
|
8924
9212
|
}
|
|
8925
9213
|
return { home: raw };
|
|
@@ -8929,8 +9217,8 @@ function twakHomeIsMainHome(twakHome) {
|
|
|
8929
9217
|
return false;
|
|
8930
9218
|
}
|
|
8931
9219
|
try {
|
|
8932
|
-
const expanded = twakHome.startsWith("~") ?
|
|
8933
|
-
return realpathIfExists(expanded) === realpathIfExists(
|
|
9220
|
+
const expanded = twakHome.startsWith("~") ? path22.join(os4.homedir(), twakHome.slice(1)) : twakHome;
|
|
9221
|
+
return realpathIfExists(expanded) === realpathIfExists(os4.homedir());
|
|
8934
9222
|
} catch {
|
|
8935
9223
|
return false;
|
|
8936
9224
|
}
|
|
@@ -8990,9 +9278,10 @@ function printTwakNotice(destination = "self") {
|
|
|
8990
9278
|
NOTE \u2014 wallet.kind = "twak" (Trust Wallet Agent Kit, CLI >= ${TWAK_CLI_VERSION}):
|
|
8991
9279
|
\xB7 GAS: x402 payments (e.g. Pieverse topup) are GASLESS on both networks, and
|
|
8992
9280
|
ERC-8004 registry writes (register / update) are gas-sponsored on both.
|
|
8993
|
-
ERC-8183 fund / settle are gas-sponsored on TESTNET
|
|
8994
|
-
|
|
8995
|
-
|
|
9281
|
+
ERC-8183 fund / settle are gas-sponsored on TESTNET for the canonical
|
|
9282
|
+
contracts (custom contract sponsorship depends on the paymaster policy \u2014
|
|
9283
|
+
keep fallback tBNB) but SELF-PAY on MAINNET \u2014 keep a little BNB there.
|
|
9284
|
+
Fund only a few days of U spend: hot wallet.
|
|
8996
9285
|
${deployLine}
|
|
8997
9286
|
Prefer the default local keystore instead? re-run with --wallet-kind evm-local.`
|
|
8998
9287
|
);
|
|
@@ -9078,11 +9367,11 @@ function entrypointHint(faces) {
|
|
|
9078
9367
|
return "app/agent/src/main.ts + executor.ts = A2A entrypoint (build your value here)";
|
|
9079
9368
|
}
|
|
9080
9369
|
function hasVendoredTarballs(agentDir) {
|
|
9081
|
-
const vendor =
|
|
9370
|
+
const vendor = path22.join(agentDir, "vendor");
|
|
9082
9371
|
if (!isDir4(vendor)) {
|
|
9083
9372
|
return false;
|
|
9084
9373
|
}
|
|
9085
|
-
return
|
|
9374
|
+
return fs23.readdirSync(vendor).some((n) => n.endsWith(".tgz"));
|
|
9086
9375
|
}
|
|
9087
9376
|
function printCompactNextSteps(name, o = {}) {
|
|
9088
9377
|
const faces = o.faces ?? normalizeProtocolFaces(o.protocol ?? "A2A");
|
|
@@ -9105,7 +9394,7 @@ function printCompactNextSteps(name, o = {}) {
|
|
|
9105
9394
|
);
|
|
9106
9395
|
} else {
|
|
9107
9396
|
printOut(
|
|
9108
|
-
"
|
|
9397
|
+
" # WALLET_PASSWORD is stored in .studio/.env.local (0600); never pass it on argv"
|
|
9109
9398
|
);
|
|
9110
9399
|
}
|
|
9111
9400
|
if (walletKind2 === "altana") {
|
|
@@ -9229,9 +9518,9 @@ function printNextSteps(name, provider, o = {}) {
|
|
|
9229
9518
|
);
|
|
9230
9519
|
} else if (walletKind2 === "altana") {
|
|
9231
9520
|
printOut(
|
|
9232
|
-
" # 1. create the encrypted Altana admin keystore
|
|
9521
|
+
" # 1. set WALLET_PASSWORD in .studio/.env.local (0600), then create the encrypted Altana admin keystore"
|
|
9233
9522
|
);
|
|
9234
|
-
printOut("
|
|
9523
|
+
printOut(" # bag auto-loads it; never pass it on argv");
|
|
9235
9524
|
printOut(" (cd app/agent && bag wallet new)");
|
|
9236
9525
|
printOut(
|
|
9237
9526
|
" # 2. fund the printed address with ~0.6 tBNB for bootstrap/registration + U, then grant one bounded runtime session"
|
|
@@ -9242,11 +9531,10 @@ function printNextSteps(name, provider, o = {}) {
|
|
|
9242
9531
|
);
|
|
9243
9532
|
} else {
|
|
9244
9533
|
printOut(
|
|
9245
|
-
" # 1.
|
|
9534
|
+
" # 1. edit .studio/.env.local and set WALLET_PASSWORD (encrypts the keystore + signs all on-chain ops)"
|
|
9246
9535
|
);
|
|
9247
|
-
printOut(" export WALLET_PASSWORD=<your-password>");
|
|
9248
9536
|
printOut(
|
|
9249
|
-
" # bag
|
|
9537
|
+
" # bag auto-loads it from the owner-only file; never pass it on argv"
|
|
9250
9538
|
);
|
|
9251
9539
|
printOut("");
|
|
9252
9540
|
printOut(" # 2. generate the agent's EOA wallet (the SOLE signer key)");
|
|
@@ -9337,7 +9625,7 @@ function loadTomlSafe(p) {
|
|
|
9337
9625
|
return {};
|
|
9338
9626
|
}
|
|
9339
9627
|
try {
|
|
9340
|
-
return parseToml(
|
|
9628
|
+
return parseToml(fs23.readFileSync(p, "utf-8"));
|
|
9341
9629
|
} catch {
|
|
9342
9630
|
return {};
|
|
9343
9631
|
}
|
|
@@ -9357,7 +9645,7 @@ function weiToU(raw) {
|
|
|
9357
9645
|
}
|
|
9358
9646
|
}
|
|
9359
9647
|
function printConfigSummary(agentRoot2) {
|
|
9360
|
-
const agent = loadTomlSafe(
|
|
9648
|
+
const agent = loadTomlSafe(path22.join(agentRoot2, "studio.toml"));
|
|
9361
9649
|
if (Object.keys(agent).length === 0) {
|
|
9362
9650
|
return;
|
|
9363
9651
|
}
|
|
@@ -9537,8 +9825,9 @@ function printConfigSummary(agentRoot2) {
|
|
|
9537
9825
|
);
|
|
9538
9826
|
}
|
|
9539
9827
|
if (hasX402Seller && !isFreeX402) {
|
|
9828
|
+
todo.push(`PAID /x402 onboarding \u2014 ${B402_PAID_ONBOARDING_GUIDANCE}`);
|
|
9540
9829
|
todo.push(
|
|
9541
|
-
"B402_BASE_URL / CLIENT_ID / ACCESS_TOKEN / private key
|
|
9830
|
+
"then set B402_BASE_URL / CLIENT_ID / ACCESS_TOKEN / private key"
|
|
9542
9831
|
);
|
|
9543
9832
|
}
|
|
9544
9833
|
if (storageKind2 === "local") {
|
|
@@ -9556,14 +9845,14 @@ function printConfigSummary(agentRoot2) {
|
|
|
9556
9845
|
}
|
|
9557
9846
|
function isFile8(p) {
|
|
9558
9847
|
try {
|
|
9559
|
-
return
|
|
9848
|
+
return fs23.statSync(p).isFile();
|
|
9560
9849
|
} catch {
|
|
9561
9850
|
return false;
|
|
9562
9851
|
}
|
|
9563
9852
|
}
|
|
9564
9853
|
function isDir4(p) {
|
|
9565
9854
|
try {
|
|
9566
|
-
return
|
|
9855
|
+
return fs23.statSync(p).isDirectory();
|
|
9567
9856
|
} catch {
|
|
9568
9857
|
return false;
|
|
9569
9858
|
}
|
|
@@ -9573,11 +9862,12 @@ function isDir4(p) {
|
|
|
9573
9862
|
var DEFAULT_AGENT_HOST = "127.0.0.1";
|
|
9574
9863
|
var AGENTCORE_BIN = "agentcore";
|
|
9575
9864
|
var RUNTIME_AGENTCORE = "agentcore";
|
|
9865
|
+
var RUNTIME_AZURE_FOUNDRY = "azure-foundry";
|
|
9576
9866
|
var MIN_NODE_MAJOR = 22;
|
|
9577
9867
|
var CONTAINER_RUNTIMES = ["docker", "podman", "finch"];
|
|
9578
9868
|
function isFile9(p) {
|
|
9579
9869
|
try {
|
|
9580
|
-
return
|
|
9870
|
+
return fs24.statSync(p).isFile();
|
|
9581
9871
|
} catch {
|
|
9582
9872
|
return false;
|
|
9583
9873
|
}
|
|
@@ -9609,8 +9899,8 @@ async function nodeMajor() {
|
|
|
9609
9899
|
return /^\d+$/.test(head) ? Number.parseInt(head, 10) : null;
|
|
9610
9900
|
}
|
|
9611
9901
|
function workspaceBase(root) {
|
|
9612
|
-
for (const base of [
|
|
9613
|
-
if (isFile9(
|
|
9902
|
+
for (const base of [path23.join(root, "app"), root]) {
|
|
9903
|
+
if (isFile9(path23.join(base, "agent", "studio.toml"))) {
|
|
9614
9904
|
return base;
|
|
9615
9905
|
}
|
|
9616
9906
|
}
|
|
@@ -9618,7 +9908,7 @@ function workspaceBase(root) {
|
|
|
9618
9908
|
}
|
|
9619
9909
|
function resolveWorkspaceRoot(argRoot) {
|
|
9620
9910
|
if (argRoot !== null) {
|
|
9621
|
-
const root =
|
|
9911
|
+
const root = path23.resolve(argRoot);
|
|
9622
9912
|
const base = workspaceBase(root);
|
|
9623
9913
|
if (base === null) {
|
|
9624
9914
|
printErr(
|
|
@@ -9628,13 +9918,13 @@ function resolveWorkspaceRoot(argRoot) {
|
|
|
9628
9918
|
}
|
|
9629
9919
|
return base;
|
|
9630
9920
|
}
|
|
9631
|
-
let current =
|
|
9921
|
+
let current = path23.resolve(process.cwd());
|
|
9632
9922
|
for (; ; ) {
|
|
9633
9923
|
const base = workspaceBase(current);
|
|
9634
9924
|
if (base !== null) {
|
|
9635
9925
|
return base;
|
|
9636
9926
|
}
|
|
9637
|
-
const parent =
|
|
9927
|
+
const parent = path23.dirname(current);
|
|
9638
9928
|
if (parent === current) {
|
|
9639
9929
|
break;
|
|
9640
9930
|
}
|
|
@@ -9647,24 +9937,24 @@ function resolveWorkspaceRoot(argRoot) {
|
|
|
9647
9937
|
}
|
|
9648
9938
|
function loadAgentToml2(workspaceRoot) {
|
|
9649
9939
|
try {
|
|
9650
|
-
return
|
|
9651
|
-
|
|
9940
|
+
return loadStudioToml11(
|
|
9941
|
+
path23.join(workspaceRoot, "agent", "studio.toml")
|
|
9652
9942
|
);
|
|
9653
9943
|
} catch {
|
|
9654
9944
|
return {};
|
|
9655
9945
|
}
|
|
9656
9946
|
}
|
|
9657
|
-
function
|
|
9947
|
+
function tableOf8(data, key) {
|
|
9658
9948
|
const v = data[key];
|
|
9659
9949
|
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
9660
9950
|
}
|
|
9661
9951
|
function agentRuntime(workspaceRoot) {
|
|
9662
|
-
const runtime =
|
|
9952
|
+
const runtime = tableOf8(loadAgentToml2(workspaceRoot), "stack").runtime;
|
|
9663
9953
|
return typeof runtime === "string" && runtime.trim() ? runtime.trim() : RUNTIME_AGENTCORE;
|
|
9664
9954
|
}
|
|
9665
9955
|
function agentFaces(workspaceRoot) {
|
|
9666
9956
|
const cfg = loadAgentToml2(workspaceRoot);
|
|
9667
|
-
return stackFaces(
|
|
9957
|
+
return stackFaces(tableOf8(cfg, "stack"), tableOf8(cfg, "payments"));
|
|
9668
9958
|
}
|
|
9669
9959
|
function localEntryFile(faces) {
|
|
9670
9960
|
return `src/${entryStemOf(faces)}.ts`;
|
|
@@ -9675,36 +9965,46 @@ function defaultAgentPort(faces) {
|
|
|
9675
9965
|
function storageKind(agentDir) {
|
|
9676
9966
|
let data;
|
|
9677
9967
|
try {
|
|
9678
|
-
data =
|
|
9968
|
+
data = loadStudioToml11(path23.join(agentDir, "studio.toml"));
|
|
9679
9969
|
} catch {
|
|
9680
9970
|
return "local";
|
|
9681
9971
|
}
|
|
9682
|
-
const kind =
|
|
9972
|
+
const kind = tableOf8(data, "storage").kind;
|
|
9683
9973
|
return typeof kind === "string" && kind.trim() ? kind.trim() : "local";
|
|
9684
9974
|
}
|
|
9975
|
+
function networkNameOf(agentDir) {
|
|
9976
|
+
let data;
|
|
9977
|
+
try {
|
|
9978
|
+
data = loadStudioToml11(path23.join(agentDir, "studio.toml"));
|
|
9979
|
+
} catch {
|
|
9980
|
+
return "bsc-testnet";
|
|
9981
|
+
}
|
|
9982
|
+
const name = tableOf8(data, "network").default;
|
|
9983
|
+
return typeof name === "string" && name.trim() ? name.trim() : "bsc-testnet";
|
|
9984
|
+
}
|
|
9685
9985
|
function walletKindOf(agentDir) {
|
|
9686
9986
|
let data;
|
|
9687
9987
|
try {
|
|
9688
|
-
data =
|
|
9988
|
+
data = loadStudioToml11(path23.join(agentDir, "studio.toml"));
|
|
9689
9989
|
} catch {
|
|
9690
9990
|
return "evm-local";
|
|
9691
9991
|
}
|
|
9692
|
-
const kind =
|
|
9992
|
+
const kind = tableOf8(data, "wallet").kind;
|
|
9693
9993
|
return typeof kind === "string" && kind.trim() ? kind.trim() : "evm-local";
|
|
9694
9994
|
}
|
|
9695
9995
|
function altanaSessionForRuntime(agentDir) {
|
|
9696
|
-
const cfg =
|
|
9697
|
-
const wallet =
|
|
9996
|
+
const cfg = loadStudioToml11(path23.join(agentDir, "studio.toml"));
|
|
9997
|
+
const wallet = tableOf8(cfg, "wallet");
|
|
9698
9998
|
const configured = String(
|
|
9699
9999
|
wallet.session_file ?? ".studio/wallets/altana-session.json"
|
|
9700
10000
|
);
|
|
9701
|
-
const sessionFile =
|
|
10001
|
+
const sessionFile = path23.isAbsolute(configured) ? configured : path23.join(agentDir, configured);
|
|
9702
10002
|
if (!isFile9(sessionFile)) {
|
|
9703
10003
|
throw new Error(
|
|
9704
10004
|
`no Altana session at ${sessionFile} \u2014 run \`bag wallet session grant\` first.`
|
|
9705
10005
|
);
|
|
9706
10006
|
}
|
|
9707
|
-
const serialized =
|
|
10007
|
+
const serialized = fs24.readFileSync(sessionFile, "utf8");
|
|
9708
10008
|
let envelope;
|
|
9709
10009
|
try {
|
|
9710
10010
|
envelope = JSON.parse(serialized);
|
|
@@ -9736,7 +10036,7 @@ function loadEnvFileForDev(p) {
|
|
|
9736
10036
|
if (!isFile9(p)) {
|
|
9737
10037
|
return;
|
|
9738
10038
|
}
|
|
9739
|
-
for (const line of
|
|
10039
|
+
for (const line of fs24.readFileSync(p, "utf-8").split(/\r?\n/)) {
|
|
9740
10040
|
if (!line || line.trimStart().startsWith("#")) {
|
|
9741
10041
|
continue;
|
|
9742
10042
|
}
|
|
@@ -9757,20 +10057,20 @@ function ensureStoragePath(projectRoot) {
|
|
|
9757
10057
|
const raw = process.env.STORAGE_LOCAL_PATH;
|
|
9758
10058
|
let resolved;
|
|
9759
10059
|
if (raw) {
|
|
9760
|
-
resolved =
|
|
9761
|
-
raw.startsWith("~") ?
|
|
10060
|
+
resolved = path23.resolve(
|
|
10061
|
+
raw.startsWith("~") ? path23.join(os5.homedir(), raw.slice(1)) : raw
|
|
9762
10062
|
);
|
|
9763
10063
|
} else {
|
|
9764
|
-
resolved =
|
|
9765
|
-
|
|
9766
|
-
|
|
10064
|
+
resolved = path23.resolve(
|
|
10065
|
+
path23.join(
|
|
10066
|
+
os5.homedir(),
|
|
9767
10067
|
".bag",
|
|
9768
10068
|
"deliverables",
|
|
9769
|
-
|
|
10069
|
+
path23.basename(projectRoot)
|
|
9770
10070
|
)
|
|
9771
10071
|
);
|
|
9772
10072
|
}
|
|
9773
|
-
|
|
10073
|
+
fs24.mkdirSync(resolved, { recursive: true });
|
|
9774
10074
|
process.env.STORAGE_LOCAL_PATH = resolved;
|
|
9775
10075
|
}
|
|
9776
10076
|
function ipfsPreflight(agentDir) {
|
|
@@ -9785,12 +10085,12 @@ function ipfsPreflight(agentDir) {
|
|
|
9785
10085
|
function runtimeEnvKeys(agentDir) {
|
|
9786
10086
|
let cfg = {};
|
|
9787
10087
|
try {
|
|
9788
|
-
cfg =
|
|
10088
|
+
cfg = loadStudioToml11(path23.join(agentDir, "studio.toml"));
|
|
9789
10089
|
} catch {
|
|
9790
10090
|
cfg = {};
|
|
9791
10091
|
}
|
|
9792
10092
|
const resolvable = (key) => Boolean(process.env[key]);
|
|
9793
|
-
const kind =
|
|
10093
|
+
const kind = tableOf8(cfg, "wallet").kind;
|
|
9794
10094
|
let keys;
|
|
9795
10095
|
if (kind === "twak") {
|
|
9796
10096
|
keys = ["TWAK_WALLET_PASSWORD"];
|
|
@@ -9804,12 +10104,12 @@ function runtimeEnvKeys(agentDir) {
|
|
|
9804
10104
|
} else {
|
|
9805
10105
|
keys = ["WALLET_PASSWORD"];
|
|
9806
10106
|
}
|
|
9807
|
-
const provider =
|
|
10107
|
+
const provider = tableOf8(cfg, "llm").provider;
|
|
9808
10108
|
const providerKey = typeof provider === "string" ? PROVIDER_KEY_ENV[provider] : null;
|
|
9809
10109
|
if (providerKey) {
|
|
9810
10110
|
keys.push(providerKey);
|
|
9811
10111
|
}
|
|
9812
|
-
const sk = String(
|
|
10112
|
+
const sk = String(tableOf8(cfg, "storage").kind ?? "local").toLowerCase();
|
|
9813
10113
|
if (sk === "ipfs") {
|
|
9814
10114
|
keys.push("STORAGE_API_URL");
|
|
9815
10115
|
if (resolvable("STORAGE_API_KEY")) {
|
|
@@ -9824,7 +10124,7 @@ function runtimeEnvKeys(agentDir) {
|
|
|
9824
10124
|
if (resolvable(key)) keys.push(key);
|
|
9825
10125
|
}
|
|
9826
10126
|
}
|
|
9827
|
-
const runtime = String(
|
|
10127
|
+
const runtime = String(tableOf8(cfg, "stack").runtime ?? "agentcore");
|
|
9828
10128
|
if (runtime === "agentcore" && x402SellerUsesB402(cfg)) {
|
|
9829
10129
|
for (const key of B402_RUNTIME_KEYS) {
|
|
9830
10130
|
if (resolvable(key)) keys.push(key);
|
|
@@ -9842,8 +10142,8 @@ function compactJson(text2) {
|
|
|
9842
10142
|
function readTwakFiles(agentDir) {
|
|
9843
10143
|
let walletCfg = {};
|
|
9844
10144
|
try {
|
|
9845
|
-
walletCfg =
|
|
9846
|
-
|
|
10145
|
+
walletCfg = tableOf8(
|
|
10146
|
+
loadStudioToml11(path23.join(agentDir, "studio.toml")),
|
|
9847
10147
|
"wallet"
|
|
9848
10148
|
);
|
|
9849
10149
|
} catch {
|
|
@@ -9851,9 +10151,9 @@ function readTwakFiles(agentDir) {
|
|
|
9851
10151
|
}
|
|
9852
10152
|
const twakDir = twakHomeDir(walletCfg, agentDir);
|
|
9853
10153
|
const read = (name) => {
|
|
9854
|
-
const p =
|
|
10154
|
+
const p = path23.join(twakDir, name);
|
|
9855
10155
|
try {
|
|
9856
|
-
return
|
|
10156
|
+
return fs24.readFileSync(p, "utf-8");
|
|
9857
10157
|
} catch {
|
|
9858
10158
|
return null;
|
|
9859
10159
|
}
|
|
@@ -9861,19 +10161,19 @@ function readTwakFiles(agentDir) {
|
|
|
9861
10161
|
return [read("wallet.json"), read("credentials.json")];
|
|
9862
10162
|
}
|
|
9863
10163
|
function ensureAgentcoreEnvGitignored(agentcoreDir) {
|
|
9864
|
-
const gi =
|
|
10164
|
+
const gi = path23.join(agentcoreDir, ".gitignore");
|
|
9865
10165
|
const entry = ".env.local";
|
|
9866
10166
|
if (isFile9(gi)) {
|
|
9867
|
-
const text2 =
|
|
10167
|
+
const text2 = fs24.readFileSync(gi, "utf-8");
|
|
9868
10168
|
const lines = new Set(text2.split("\n").map((l) => l.trim()));
|
|
9869
10169
|
if (lines.has(entry)) {
|
|
9870
10170
|
return;
|
|
9871
10171
|
}
|
|
9872
10172
|
const sep6 = text2.endsWith("\n") || text2 === "" ? "" : "\n";
|
|
9873
|
-
|
|
10173
|
+
fs24.writeFileSync(gi, `${text2}${sep6}${entry}
|
|
9874
10174
|
`);
|
|
9875
10175
|
} else {
|
|
9876
|
-
|
|
10176
|
+
fs24.writeFileSync(gi, `${entry}
|
|
9877
10177
|
`);
|
|
9878
10178
|
}
|
|
9879
10179
|
}
|
|
@@ -9896,8 +10196,8 @@ function writeAgentcoreEnvLocal(agentcoreRoot, agentDir) {
|
|
|
9896
10196
|
} else if (walletKindOf(agentDir) === "altana") {
|
|
9897
10197
|
bundle.ALTANA_SESSION = altanaSessionForRuntime(agentDir);
|
|
9898
10198
|
}
|
|
9899
|
-
const envPath =
|
|
9900
|
-
const prior = isFile9(envPath) ?
|
|
10199
|
+
const envPath = path23.join(agentcoreRoot, "agentcore", ".env.local");
|
|
10200
|
+
const prior = isFile9(envPath) ? fs24.readFileSync(envPath, "utf-8") : "";
|
|
9901
10201
|
const merged = {};
|
|
9902
10202
|
for (const line of prior.split("\n")) {
|
|
9903
10203
|
if (!line || line.trimStart().startsWith("#")) {
|
|
@@ -9912,14 +10212,14 @@ function writeAgentcoreEnvLocal(agentcoreRoot, agentDir) {
|
|
|
9912
10212
|
Object.assign(merged, bundle);
|
|
9913
10213
|
const content = Object.entries(merged).map(([k, v]) => `${k}=${v}
|
|
9914
10214
|
`).join("");
|
|
9915
|
-
|
|
9916
|
-
ensureAgentcoreEnvGitignored(
|
|
10215
|
+
fs24.mkdirSync(path23.dirname(envPath), { recursive: true });
|
|
10216
|
+
ensureAgentcoreEnvGitignored(path23.dirname(envPath));
|
|
9917
10217
|
writePrivate2(envPath, content);
|
|
9918
10218
|
return [envPath, content !== prior];
|
|
9919
10219
|
}
|
|
9920
10220
|
function agentcoreProjectRoot2(workspaceRoot) {
|
|
9921
|
-
for (const candidate of [
|
|
9922
|
-
if (isFile9(
|
|
10221
|
+
for (const candidate of [path23.dirname(workspaceRoot), workspaceRoot]) {
|
|
10222
|
+
if (isFile9(path23.join(candidate, "agentcore", "agentcore.json"))) {
|
|
9923
10223
|
return candidate;
|
|
9924
10224
|
}
|
|
9925
10225
|
}
|
|
@@ -9928,8 +10228,8 @@ function agentcoreProjectRoot2(workspaceRoot) {
|
|
|
9928
10228
|
function loadAgentcoreConfig(projectRoot) {
|
|
9929
10229
|
try {
|
|
9930
10230
|
const cfg = JSON.parse(
|
|
9931
|
-
|
|
9932
|
-
|
|
10231
|
+
fs24.readFileSync(
|
|
10232
|
+
path23.join(projectRoot, "agentcore", "agentcore.json"),
|
|
9933
10233
|
"utf-8"
|
|
9934
10234
|
)
|
|
9935
10235
|
);
|
|
@@ -10019,11 +10319,11 @@ async function cmdDev(opts) {
|
|
|
10019
10319
|
if (workspaceRoot === null) {
|
|
10020
10320
|
return 2;
|
|
10021
10321
|
}
|
|
10022
|
-
const agentDir =
|
|
10322
|
+
const agentDir = path23.join(workspaceRoot, "agent");
|
|
10023
10323
|
migrateEnvLocal(agentDir);
|
|
10024
10324
|
migrateKeystoreOutOfCodelocation(agentDir);
|
|
10025
|
-
const { envLocalPath:
|
|
10026
|
-
loadEnvFileForDev(
|
|
10325
|
+
const { envLocalPath: envLocalPath19 } = await import("@bnbagent/studio-runtime/config");
|
|
10326
|
+
loadEnvFileForDev(envLocalPath19(agentDir));
|
|
10027
10327
|
ensureStoragePath(workspaceRoot);
|
|
10028
10328
|
const ipfsErr = ipfsPreflight(agentDir);
|
|
10029
10329
|
if (ipfsErr !== null) {
|
|
@@ -10055,7 +10355,7 @@ async function cmdDev(opts) {
|
|
|
10055
10355
|
const runtime = agentRuntime(workspaceRoot);
|
|
10056
10356
|
const container = Boolean(opts.container);
|
|
10057
10357
|
const entryFile = localEntryFile(faces);
|
|
10058
|
-
const agentFile =
|
|
10358
|
+
const agentFile = path23.join(agentDir, entryFile);
|
|
10059
10359
|
if (!isFile9(agentFile)) {
|
|
10060
10360
|
printErr(
|
|
10061
10361
|
`error: Agent entrypoint file ${agentFile} does not exist. [stack] faces = [${faces.join(", ")}], so the entrypoint is ${entryFile} (A2A/X402-only \u2192 src/main.ts, MCP \u2192 src/mcpMain.ts, A2A+MCP \u2192 src/dualMain.ts). Run \`bag init\` to scaffold the workspace.`
|
|
@@ -10069,6 +10369,17 @@ async function cmdDev(opts) {
|
|
|
10069
10369
|
);
|
|
10070
10370
|
return 2;
|
|
10071
10371
|
}
|
|
10372
|
+
if (walletKind2 === "twak") {
|
|
10373
|
+
const unsupported = twakUnsupportedContractOverrides(
|
|
10374
|
+
networkNameOf(agentDir)
|
|
10375
|
+
);
|
|
10376
|
+
if (unsupported.length > 0) {
|
|
10377
|
+
const keys = unsupported.map((item) => item.envKey).join(", ");
|
|
10378
|
+
printErr(
|
|
10379
|
+
`warning: wallet.kind='twak' cannot use the selected custom ERC-8183 targets (${keys}): twak v0.20.0 has no Commerce/Router/Policy address option, so on-chain 8183 writes (submit/fund/settle) will fail against this stack. Use wallet.kind='evm-local' for custom ERC-8183 contracts, or remove the overrides and use the canonical stack. ERC8004_REGISTRY_ADDRESS is supported.`
|
|
10380
|
+
);
|
|
10381
|
+
}
|
|
10382
|
+
}
|
|
10072
10383
|
if (await devPortInUse(agentPort)) {
|
|
10073
10384
|
printErr(
|
|
10074
10385
|
`error: port ${agentPort} is already in use on 127.0.0.1 (another \`bag dev\`?). Stop it or pass --port <other>.`
|
|
@@ -10123,7 +10434,7 @@ Switch to Node \u226522 so it wins on PATH, then reopen the shell and retry. Ver
|
|
|
10123
10434
|
}
|
|
10124
10435
|
let launch;
|
|
10125
10436
|
if (runtime === RUNTIME_AGENTCORE && container) {
|
|
10126
|
-
const root =
|
|
10437
|
+
const root = path23.resolve(agentcoreRoot);
|
|
10127
10438
|
try {
|
|
10128
10439
|
const vendored = await vendorLocalTarballs(agentDir);
|
|
10129
10440
|
if (vendored.length > 0) {
|
|
@@ -10138,7 +10449,7 @@ Switch to Node \u226522 so it wins on PATH, then reopen the shell and retry. Ver
|
|
|
10138
10449
|
}
|
|
10139
10450
|
const [envPath, changed] = writeAgentcoreEnvLocal(root, agentDir);
|
|
10140
10451
|
printOut(
|
|
10141
|
-
`bag dev: wrote ${
|
|
10452
|
+
`bag dev: wrote ${path23.relative(root, envPath)} (runtime secrets + materialized wallet for the container).`
|
|
10142
10453
|
);
|
|
10143
10454
|
if (changed && process.env.BAG_DEV_ENV_WARNED !== "1") {
|
|
10144
10455
|
printErr(
|
|
@@ -10186,6 +10497,11 @@ Switch to Node \u226522 so it wins on PATH, then reopen the shell and retry. Ver
|
|
|
10186
10497
|
printOut(
|
|
10187
10498
|
`bag dev: starting Agent in-process (\`tsx ${args.join(" ")}\` on :${agentPort}, no Docker \u2014 the entrypoint self-serves; cwd=${agentDir}, runner=${runner2})`
|
|
10188
10499
|
);
|
|
10500
|
+
if (runtime === RUNTIME_AZURE_FOUNDRY) {
|
|
10501
|
+
printOut(
|
|
10502
|
+
"bag dev: azure-foundry serves this local A2A/MCP entrypoint in-process; src/foundryMain.ts is the deploy-only Foundry host (the entrypoint `bag doctor` reports) and never runs here."
|
|
10503
|
+
);
|
|
10504
|
+
}
|
|
10189
10505
|
launch = () => runStream(runner2, args, { cwd: agentDir, env });
|
|
10190
10506
|
}
|
|
10191
10507
|
const banner = networkBanner(agentDir);
|
|
@@ -10210,7 +10526,7 @@ Switch to Node \u226522 so it wins on PATH, then reopen the shell and retry. Ver
|
|
|
10210
10526
|
}
|
|
10211
10527
|
if (hasX402Face(faces)) {
|
|
10212
10528
|
const free = x402SellerIsFree(
|
|
10213
|
-
|
|
10529
|
+
loadStudioToml11(path23.join(agentDir, "studio.toml"))
|
|
10214
10530
|
);
|
|
10215
10531
|
printOut(
|
|
10216
10532
|
free ? `bag dev: x402 seller at http://localhost:${agentPort}/x402 (FREE \u2014 anonymous passthrough; B402 bypassed)` : `bag dev: x402 seller at http://localhost:${agentPort}/x402 (PAID \u2014 active when B402 credentials are configured)`
|
|
@@ -10221,8 +10537,8 @@ Switch to Node \u226522 so it wins on PATH, then reopen the shell and retry. Ver
|
|
|
10221
10537
|
}
|
|
10222
10538
|
function tsxRunner(agentDir, workspaceBaseDir) {
|
|
10223
10539
|
const bin = process.platform === "win32" ? "tsx.cmd" : "tsx";
|
|
10224
|
-
for (const dir of [agentDir,
|
|
10225
|
-
const candidate =
|
|
10540
|
+
for (const dir of [agentDir, path23.dirname(workspaceBaseDir)]) {
|
|
10541
|
+
const candidate = path23.join(dir, "node_modules", ".bin", bin);
|
|
10226
10542
|
if (isFile9(candidate)) {
|
|
10227
10543
|
return candidate;
|
|
10228
10544
|
}
|
|
@@ -10232,11 +10548,11 @@ function tsxRunner(agentDir, workspaceBaseDir) {
|
|
|
10232
10548
|
function networkBanner(agentDir) {
|
|
10233
10549
|
let data;
|
|
10234
10550
|
try {
|
|
10235
|
-
data =
|
|
10551
|
+
data = loadStudioToml11(path23.join(agentDir, "studio.toml"));
|
|
10236
10552
|
} catch {
|
|
10237
10553
|
return null;
|
|
10238
10554
|
}
|
|
10239
|
-
const name =
|
|
10555
|
+
const name = tableOf8(data, "network").default;
|
|
10240
10556
|
if (typeof name !== "string" || !name.trim()) {
|
|
10241
10557
|
return null;
|
|
10242
10558
|
}
|
|
@@ -10249,34 +10565,34 @@ function networkBanner(agentDir) {
|
|
|
10249
10565
|
}
|
|
10250
10566
|
|
|
10251
10567
|
// src/cli/_deploy/checks/critical.ts
|
|
10252
|
-
import * as
|
|
10568
|
+
import * as fs25 from "fs";
|
|
10253
10569
|
import { createRequire } from "module";
|
|
10254
|
-
import * as
|
|
10255
|
-
import { envLocalPath as
|
|
10570
|
+
import * as path24 from "path";
|
|
10571
|
+
import { envLocalPath as envLocalPath11, loadStudioToml as loadStudioToml12 } from "@bnbagent/studio-runtime/config";
|
|
10256
10572
|
import { pieverseKeyHash as pieverseKeyHash2 } from "@bnbagent/studio-runtime/llm";
|
|
10257
10573
|
var AGENTCORE_DESCRIPTOR2 = "agentcore/agentcore.json";
|
|
10258
10574
|
function isFile10(p) {
|
|
10259
10575
|
try {
|
|
10260
|
-
return
|
|
10576
|
+
return fs25.statSync(p).isFile();
|
|
10261
10577
|
} catch {
|
|
10262
10578
|
return false;
|
|
10263
10579
|
}
|
|
10264
10580
|
}
|
|
10265
10581
|
function isDir5(p) {
|
|
10266
10582
|
try {
|
|
10267
|
-
return
|
|
10583
|
+
return fs25.statSync(p).isDirectory();
|
|
10268
10584
|
} catch {
|
|
10269
10585
|
return false;
|
|
10270
10586
|
}
|
|
10271
10587
|
}
|
|
10272
10588
|
function keystoreDirOf(root, data) {
|
|
10273
10589
|
const rel = String(tableOf2(data, "wallet").keystore_dir ?? ".studio/wallets");
|
|
10274
|
-
const dir =
|
|
10275
|
-
return
|
|
10590
|
+
const dir = path24.isAbsolute(rel) ? rel : path24.join(agentRootOf(root), rel);
|
|
10591
|
+
return path24.resolve(dir);
|
|
10276
10592
|
}
|
|
10277
10593
|
function keystoreJsonFiles2(dir) {
|
|
10278
10594
|
try {
|
|
10279
|
-
return
|
|
10595
|
+
return fs25.readdirSync(dir).filter((n) => n.endsWith(".json")).sort();
|
|
10280
10596
|
} catch {
|
|
10281
10597
|
return [];
|
|
10282
10598
|
}
|
|
@@ -10284,11 +10600,11 @@ function keystoreJsonFiles2(dir) {
|
|
|
10284
10600
|
function runtimeEnvKeys2(agentRoot2) {
|
|
10285
10601
|
let cfg = {};
|
|
10286
10602
|
try {
|
|
10287
|
-
cfg =
|
|
10603
|
+
cfg = loadStudioToml12(path24.join(agentRoot2, "studio.toml"));
|
|
10288
10604
|
} catch {
|
|
10289
10605
|
cfg = {};
|
|
10290
10606
|
}
|
|
10291
|
-
const resolvable = (key) => Boolean(process.env[key] || getEnvVar(
|
|
10607
|
+
const resolvable = (key) => Boolean(process.env[key] || getEnvVar(envLocalPath11(agentRoot2), key));
|
|
10292
10608
|
const walletKind2 = tableOf2(cfg, "wallet").kind ?? "evm-local";
|
|
10293
10609
|
let keys;
|
|
10294
10610
|
if (walletKind2 === "twak") {
|
|
@@ -10338,7 +10654,7 @@ async function checkAgentcoreJsonPresent(root, target) {
|
|
|
10338
10654
|
if (target !== "agentcore") {
|
|
10339
10655
|
return [];
|
|
10340
10656
|
}
|
|
10341
|
-
const descriptor =
|
|
10657
|
+
const descriptor = path24.join(root, AGENTCORE_DESCRIPTOR2);
|
|
10342
10658
|
if (isFile10(descriptor)) {
|
|
10343
10659
|
return [];
|
|
10344
10660
|
}
|
|
@@ -10355,10 +10671,10 @@ async function checkAgentcoreAuthorizerKeyLegacy(root, target) {
|
|
|
10355
10671
|
if (target !== "agentcore") {
|
|
10356
10672
|
return [];
|
|
10357
10673
|
}
|
|
10358
|
-
const descriptor =
|
|
10674
|
+
const descriptor = path24.join(root, AGENTCORE_DESCRIPTOR2);
|
|
10359
10675
|
let data;
|
|
10360
10676
|
try {
|
|
10361
|
-
data = JSON.parse(
|
|
10677
|
+
data = JSON.parse(fs25.readFileSync(descriptor, "utf-8"));
|
|
10362
10678
|
} catch {
|
|
10363
10679
|
return [];
|
|
10364
10680
|
}
|
|
@@ -10398,10 +10714,10 @@ async function checkAgentPackagePresent(root, target) {
|
|
|
10398
10714
|
sourceEntries.push("src/mcpMain.ts");
|
|
10399
10715
|
}
|
|
10400
10716
|
const missingSource = sourceEntries.find(
|
|
10401
|
-
(entry) => !isFile10(
|
|
10717
|
+
(entry) => !isFile10(path24.join(agentRoot2, entry))
|
|
10402
10718
|
);
|
|
10403
10719
|
if (missingSource !== void 0) {
|
|
10404
|
-
const epPath =
|
|
10720
|
+
const epPath = path24.join(agentRoot2, missingSource);
|
|
10405
10721
|
return [
|
|
10406
10722
|
{
|
|
10407
10723
|
level: Level.CRITICAL,
|
|
@@ -10416,10 +10732,10 @@ async function checkAgentPackagePresent(root, target) {
|
|
|
10416
10732
|
distEntries.push("dist/mcpMain.js");
|
|
10417
10733
|
}
|
|
10418
10734
|
const missingDist = distEntries.find(
|
|
10419
|
-
(entry) => !isFile10(
|
|
10735
|
+
(entry) => !isFile10(path24.join(agentRoot2, entry))
|
|
10420
10736
|
);
|
|
10421
10737
|
if (missingDist !== void 0) {
|
|
10422
|
-
const distPath =
|
|
10738
|
+
const distPath = path24.join(agentRoot2, missingDist);
|
|
10423
10739
|
return [
|
|
10424
10740
|
{
|
|
10425
10741
|
level: Level.WARNING,
|
|
@@ -10444,8 +10760,8 @@ async function checkKeystoreNotInsideAgent(root, target) {
|
|
|
10444
10760
|
if (!isDir5(keystoreDir) || keystoreJsonFiles2(keystoreDir).length === 0) {
|
|
10445
10761
|
return [];
|
|
10446
10762
|
}
|
|
10447
|
-
const agentDir =
|
|
10448
|
-
const inside2 = keystoreDir === agentDir || keystoreDir.startsWith(agentDir +
|
|
10763
|
+
const agentDir = path24.resolve(agentRootOf(root));
|
|
10764
|
+
const inside2 = keystoreDir === agentDir || keystoreDir.startsWith(agentDir + path24.sep);
|
|
10449
10765
|
if (!inside2) {
|
|
10450
10766
|
return [];
|
|
10451
10767
|
}
|
|
@@ -10453,7 +10769,7 @@ async function checkKeystoreNotInsideAgent(root, target) {
|
|
|
10453
10769
|
{
|
|
10454
10770
|
level: Level.WARNING,
|
|
10455
10771
|
name: "keystore_not_inside_agent",
|
|
10456
|
-
message: `keystore dir ${keystoreDir} is INSIDE the deploy codeLocation (${agentDir}) \u2014 a legacy layout. \`bag
|
|
10772
|
+
message: `keystore dir ${keystoreDir} is INSIDE the deploy codeLocation (${agentDir}) \u2014 a legacy layout. \`bag dev\` and \`bag deploy\` auto-migrate it to <workspace>/.studio/wallets (and repoint [wallet].keystore_dir). Fix: run \`bag dev\` once, or move it manually and set [wallet].keystore_dir = "../../.studio/wallets".`,
|
|
10457
10773
|
details: { keystore_dir: keystoreDir, agent_dir: agentDir }
|
|
10458
10774
|
}
|
|
10459
10775
|
];
|
|
@@ -10521,18 +10837,18 @@ async function checkLlmProviderKeySet(root, _target) {
|
|
|
10521
10837
|
function gitignoreLines(p) {
|
|
10522
10838
|
try {
|
|
10523
10839
|
return new Set(
|
|
10524
|
-
|
|
10840
|
+
fs25.readFileSync(p, "utf-8").split(/\r?\n/).map((l) => l.trim())
|
|
10525
10841
|
);
|
|
10526
10842
|
} catch {
|
|
10527
10843
|
return null;
|
|
10528
10844
|
}
|
|
10529
10845
|
}
|
|
10530
10846
|
function agentcoreEnvLocalIgnored(ws) {
|
|
10531
|
-
const wsLines = gitignoreLines(
|
|
10847
|
+
const wsLines = gitignoreLines(path24.join(ws, ".gitignore"));
|
|
10532
10848
|
if (wsLines?.has("agentcore/.env.local")) {
|
|
10533
10849
|
return true;
|
|
10534
10850
|
}
|
|
10535
|
-
const acLines = gitignoreLines(
|
|
10851
|
+
const acLines = gitignoreLines(path24.join(ws, "agentcore", ".gitignore"));
|
|
10536
10852
|
return acLines?.has(".env.local") ?? false;
|
|
10537
10853
|
}
|
|
10538
10854
|
function studioIgnored(lines) {
|
|
@@ -10543,8 +10859,8 @@ function studioIgnored(lines) {
|
|
|
10543
10859
|
}
|
|
10544
10860
|
async function checkGitignoreExcludesSecrets(root, _target) {
|
|
10545
10861
|
const out = [];
|
|
10546
|
-
const ws =
|
|
10547
|
-
const gi =
|
|
10862
|
+
const ws = path24.dirname(path24.dirname(envLocalPath11(root)));
|
|
10863
|
+
const gi = path24.join(ws, ".gitignore");
|
|
10548
10864
|
const lines = gitignoreLines(gi);
|
|
10549
10865
|
if (lines === null) {
|
|
10550
10866
|
return [
|
|
@@ -10566,7 +10882,7 @@ async function checkGitignoreExcludesSecrets(root, _target) {
|
|
|
10566
10882
|
details: { missing: [".studio/"] }
|
|
10567
10883
|
});
|
|
10568
10884
|
}
|
|
10569
|
-
if (isDir5(
|
|
10885
|
+
if (isDir5(path24.join(ws, "agentcore")) && !agentcoreEnvLocalIgnored(ws)) {
|
|
10570
10886
|
out.push({
|
|
10571
10887
|
level: Level.CRITICAL,
|
|
10572
10888
|
name: "gitignore_excludes_secrets",
|
|
@@ -10583,16 +10899,16 @@ function installedRuntimeVersion() {
|
|
|
10583
10899
|
}
|
|
10584
10900
|
try {
|
|
10585
10901
|
const entry = require2.resolve("@bnbagent/studio-runtime");
|
|
10586
|
-
let dir =
|
|
10902
|
+
let dir = path24.dirname(entry);
|
|
10587
10903
|
for (let i = 0; i < 10; i++) {
|
|
10588
|
-
const pkgPath =
|
|
10904
|
+
const pkgPath = path24.join(dir, "package.json");
|
|
10589
10905
|
if (isFile10(pkgPath)) {
|
|
10590
|
-
const pkg = JSON.parse(
|
|
10906
|
+
const pkg = JSON.parse(fs25.readFileSync(pkgPath, "utf-8"));
|
|
10591
10907
|
if (pkg.name === "@bnbagent/studio-runtime") {
|
|
10592
10908
|
return typeof pkg.version === "string" ? pkg.version : null;
|
|
10593
10909
|
}
|
|
10594
10910
|
}
|
|
10595
|
-
const parent =
|
|
10911
|
+
const parent = path24.dirname(dir);
|
|
10596
10912
|
if (parent === dir) {
|
|
10597
10913
|
break;
|
|
10598
10914
|
}
|
|
@@ -10649,7 +10965,7 @@ async function checkPieverseKeyHash(root, _target) {
|
|
|
10649
10965
|
];
|
|
10650
10966
|
}
|
|
10651
10967
|
const agentRoot2 = agentRootOf(root);
|
|
10652
|
-
const apiKey = getEnvVar(
|
|
10968
|
+
const apiKey = getEnvVar(envLocalPath11(agentRoot2), "PIEVERSE_LLM_API_KEY") || process.env.PIEVERSE_LLM_API_KEY;
|
|
10653
10969
|
if (!apiKey) return [];
|
|
10654
10970
|
const configured = String(pvCfg.key_hash).trim().toLowerCase().replace(/^0x/u, "");
|
|
10655
10971
|
const actual = pieverseKeyHash2(apiKey);
|
|
@@ -10822,7 +11138,7 @@ function x402SellerRailChecks(agentRoot2, cfg, target) {
|
|
|
10822
11138
|
out.push({
|
|
10823
11139
|
level: Level.CRITICAL,
|
|
10824
11140
|
name: "x402_credentials_partial",
|
|
10825
|
-
message:
|
|
11141
|
+
message: `B402 credentials are only partially configured. Set BASE_URL, CLIENT_ID, ACCESS_TOKEN, and exactly one private-key form before deploy. Confirm they were issued for this exact agent wallet and environment; never reuse them across wallets. Apply: ${B402_DEVELOPER_ACCOUNT_URL}`,
|
|
10826
11142
|
details: { present: credentials.presentKeys }
|
|
10827
11143
|
});
|
|
10828
11144
|
}
|
|
@@ -10838,7 +11154,7 @@ function x402SellerRailChecks(agentRoot2, cfg, target) {
|
|
|
10838
11154
|
out.push({
|
|
10839
11155
|
level: rails.erc8183 ? Level.WARNING : Level.CRITICAL,
|
|
10840
11156
|
name: "x402_credentials_missing",
|
|
10841
|
-
message:
|
|
11157
|
+
message: `The x402 seller rail is enabled but all B402 credentials are absent, so it will start dormant. ${B402_PAID_ONBOARDING_GUIDANCE}`,
|
|
10842
11158
|
details: {}
|
|
10843
11159
|
});
|
|
10844
11160
|
}
|
|
@@ -10876,9 +11192,9 @@ function x402SellerRailChecks(agentRoot2, cfg, target) {
|
|
|
10876
11192
|
details: { destination, target, stackRuntime: stackRuntime2 }
|
|
10877
11193
|
});
|
|
10878
11194
|
}
|
|
10879
|
-
const dockerfile =
|
|
11195
|
+
const dockerfile = path24.join(agentRoot2, "Dockerfile");
|
|
10880
11196
|
if (rails.x402 && isFile10(dockerfile)) {
|
|
10881
|
-
const source =
|
|
11197
|
+
const source = fs25.readFileSync(dockerfile, "utf8");
|
|
10882
11198
|
if (!/^\s*FROM\s+node:22(?:[.-]|\s|$)/im.test(source)) {
|
|
10883
11199
|
out.push({
|
|
10884
11200
|
level: Level.WARNING,
|
|
@@ -10951,10 +11267,10 @@ async function checkDeployCliRunnable(_root, target) {
|
|
|
10951
11267
|
];
|
|
10952
11268
|
}
|
|
10953
11269
|
function agentcoreEnvVars(root) {
|
|
10954
|
-
const descriptor =
|
|
11270
|
+
const descriptor = path24.join(root, AGENTCORE_DESCRIPTOR2);
|
|
10955
11271
|
let data;
|
|
10956
11272
|
try {
|
|
10957
|
-
data = JSON.parse(
|
|
11273
|
+
data = JSON.parse(fs25.readFileSync(descriptor, "utf-8"));
|
|
10958
11274
|
} catch {
|
|
10959
11275
|
return [];
|
|
10960
11276
|
}
|
|
@@ -10999,7 +11315,7 @@ async function checkRuntimeSecretsInjected(root, target) {
|
|
|
10999
11315
|
}
|
|
11000
11316
|
const missing = needed.filter((k) => !present[k]);
|
|
11001
11317
|
if (missing.length > 0) {
|
|
11002
|
-
const envLocal =
|
|
11318
|
+
const envLocal = envLocalPath11(root);
|
|
11003
11319
|
const recoverable = missing.filter(
|
|
11004
11320
|
(k) => Boolean(process.env[k] || getEnvVar(envLocal, k))
|
|
11005
11321
|
);
|
|
@@ -11036,7 +11352,7 @@ async function checkRuntimeSecretsInjected(root, target) {
|
|
|
11036
11352
|
}
|
|
11037
11353
|
];
|
|
11038
11354
|
}
|
|
11039
|
-
const lines = gitignoreLines(
|
|
11355
|
+
const lines = gitignoreLines(path24.join(root, ".gitignore"));
|
|
11040
11356
|
let tracked = true;
|
|
11041
11357
|
if (lines !== null) {
|
|
11042
11358
|
for (const p of ["agentcore/agentcore.json", "agentcore/", "/agentcore/"]) {
|
|
@@ -11061,7 +11377,7 @@ async function checkAwsTargetsPopulated(root, target) {
|
|
|
11061
11377
|
if (target !== "agentcore") {
|
|
11062
11378
|
return [];
|
|
11063
11379
|
}
|
|
11064
|
-
const p =
|
|
11380
|
+
const p = path24.join(root, "agentcore", "aws-targets.json");
|
|
11065
11381
|
const [account, region] = readAwsTarget(root);
|
|
11066
11382
|
if (account && region) {
|
|
11067
11383
|
return [];
|
|
@@ -11108,44 +11424,44 @@ var TWAK_WALLET_JSON_ENV = "TWAK_WALLET_JSON";
|
|
|
11108
11424
|
var TWAK_CREDENTIALS_JSON_ENV = "TWAK_CREDENTIALS_JSON";
|
|
11109
11425
|
function isFile11(p) {
|
|
11110
11426
|
try {
|
|
11111
|
-
return
|
|
11427
|
+
return fs26.statSync(p).isFile();
|
|
11112
11428
|
} catch {
|
|
11113
11429
|
return false;
|
|
11114
11430
|
}
|
|
11115
11431
|
}
|
|
11116
11432
|
function loadTomlOr(agentRoot2) {
|
|
11117
11433
|
try {
|
|
11118
|
-
return
|
|
11434
|
+
return loadStudioToml13(path25.join(agentRoot2, "studio.toml"));
|
|
11119
11435
|
} catch {
|
|
11120
11436
|
return {};
|
|
11121
11437
|
}
|
|
11122
11438
|
}
|
|
11123
|
-
function
|
|
11439
|
+
function tableOf9(cfg, key) {
|
|
11124
11440
|
const v = cfg[key];
|
|
11125
11441
|
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
11126
11442
|
}
|
|
11127
11443
|
function deployWalletKind(agentRoot2) {
|
|
11128
|
-
const kind =
|
|
11444
|
+
const kind = tableOf9(loadTomlOr(agentRoot2), "wallet").kind;
|
|
11129
11445
|
return kind ? String(kind) : "evm-local";
|
|
11130
11446
|
}
|
|
11131
11447
|
function resolveKeystoreDir3(agentRoot2) {
|
|
11132
11448
|
const rel = String(
|
|
11133
|
-
|
|
11449
|
+
tableOf9(loadTomlOr(agentRoot2), "wallet").keystore_dir ?? ".studio/wallets"
|
|
11134
11450
|
);
|
|
11135
|
-
return
|
|
11451
|
+
return path25.resolve(path25.isAbsolute(rel) ? rel : path25.join(agentRoot2, rel));
|
|
11136
11452
|
}
|
|
11137
11453
|
function readKeystoreJson(agentRoot2) {
|
|
11138
11454
|
const keystoreDir = resolveKeystoreDir3(agentRoot2);
|
|
11139
11455
|
let names;
|
|
11140
11456
|
try {
|
|
11141
|
-
names =
|
|
11457
|
+
names = fs26.readdirSync(keystoreDir).filter((n) => n.endsWith(".json")).sort();
|
|
11142
11458
|
} catch {
|
|
11143
11459
|
return null;
|
|
11144
11460
|
}
|
|
11145
11461
|
if (names.length === 0) {
|
|
11146
11462
|
return null;
|
|
11147
11463
|
}
|
|
11148
|
-
const address =
|
|
11464
|
+
const address = tableOf9(loadTomlOr(agentRoot2), "wallet").address;
|
|
11149
11465
|
let chosen = null;
|
|
11150
11466
|
if (typeof address === "string" && address) {
|
|
11151
11467
|
for (const n of names) {
|
|
@@ -11160,9 +11476,9 @@ function readKeystoreJson(agentRoot2) {
|
|
|
11160
11476
|
);
|
|
11161
11477
|
}
|
|
11162
11478
|
}
|
|
11163
|
-
const file =
|
|
11479
|
+
const file = path25.join(keystoreDir, chosen ?? names[0]);
|
|
11164
11480
|
try {
|
|
11165
|
-
return
|
|
11481
|
+
return fs26.readFileSync(file, "utf-8");
|
|
11166
11482
|
} catch {
|
|
11167
11483
|
return null;
|
|
11168
11484
|
}
|
|
@@ -11170,11 +11486,11 @@ function readKeystoreJson(agentRoot2) {
|
|
|
11170
11486
|
function readEnvLocal(agentRoot2) {
|
|
11171
11487
|
const values = {};
|
|
11172
11488
|
try {
|
|
11173
|
-
const file =
|
|
11489
|
+
const file = envLocalPath12(agentRoot2);
|
|
11174
11490
|
if (!isFile11(file)) {
|
|
11175
11491
|
return values;
|
|
11176
11492
|
}
|
|
11177
|
-
for (const rawLine of
|
|
11493
|
+
for (const rawLine of fs26.readFileSync(file, "utf-8").split(/\r?\n/)) {
|
|
11178
11494
|
const line = rawLine.trim();
|
|
11179
11495
|
if (!line || line.startsWith("#")) {
|
|
11180
11496
|
continue;
|
|
@@ -11195,7 +11511,7 @@ function readEnvLocal(agentRoot2) {
|
|
|
11195
11511
|
return values;
|
|
11196
11512
|
}
|
|
11197
11513
|
function collectRuntimeSecretsDetailed(root) {
|
|
11198
|
-
const agentRoot2 =
|
|
11514
|
+
const agentRoot2 = findSubProjectRoot8("agent", root) ?? root;
|
|
11199
11515
|
if (deployWalletKind(agentRoot2) === "altana") {
|
|
11200
11516
|
throw new Error(
|
|
11201
11517
|
"Altana deployment is deferred: refusing to collect either the admin keystore or runtime session for a deploy target."
|
|
@@ -11262,12 +11578,12 @@ var SCOPE_NAME = "invoke";
|
|
|
11262
11578
|
var SCOPE = `${RESOURCE_SERVER_ID}/${SCOPE_NAME}`;
|
|
11263
11579
|
var COGNITO_OUTPUTS_FILE = "agentcore/cognito/cdk-outputs.json";
|
|
11264
11580
|
function emitNextSteps(result) {
|
|
11265
|
-
return `\u2713 wrote Cognito CDK app to ${
|
|
11266
|
-
- ${
|
|
11267
|
-
- ${
|
|
11581
|
+
return `\u2713 wrote Cognito CDK app to ${path26.dirname(result.appPath)}
|
|
11582
|
+
- ${path26.basename(result.appPath)} (CognitoStack: user pool + resource server + M2M client)
|
|
11583
|
+
- ${path26.basename(result.readmePath)} (deploy + wiring instructions)
|
|
11268
11584
|
|
|
11269
11585
|
Next steps:
|
|
11270
|
-
1. cd ${
|
|
11586
|
+
1. cd ${path26.dirname(result.appPath)}
|
|
11271
11587
|
2. npm install # aws-cdk-lib + constructs + the cdk CLI (local)
|
|
11272
11588
|
3. npx cdk deploy --outputs-file cdk-outputs.json # YOU run this (the only AWS step)
|
|
11273
11589
|
4. bag deploy provision-cognito --wire # studio reads cdk-outputs.json \u2192
|
|
@@ -11458,26 +11774,26 @@ function emitCognitoCdk(workspaceRoot, opts = {}) {
|
|
|
11458
11774
|
regionHint = null;
|
|
11459
11775
|
}
|
|
11460
11776
|
}
|
|
11461
|
-
const outDir =
|
|
11462
|
-
|
|
11463
|
-
const appPath =
|
|
11464
|
-
const readmePath =
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11777
|
+
const outDir = path26.join(workspaceRoot, COGNITO_DIR);
|
|
11778
|
+
fs27.mkdirSync(outDir, { recursive: true });
|
|
11779
|
+
const appPath = path26.join(outDir, "app.ts");
|
|
11780
|
+
const readmePath = path26.join(outDir, "README.md");
|
|
11781
|
+
fs27.writeFileSync(appPath, appTs(regionHint), "utf-8");
|
|
11782
|
+
fs27.writeFileSync(path26.join(outDir, "cdk.json"), cdkJson(), "utf-8");
|
|
11783
|
+
fs27.writeFileSync(
|
|
11784
|
+
path26.join(outDir, "package.json"),
|
|
11469
11785
|
cognitoPackageJson(),
|
|
11470
11786
|
"utf-8"
|
|
11471
11787
|
);
|
|
11472
|
-
|
|
11788
|
+
fs27.writeFileSync(readmePath, readme(), "utf-8");
|
|
11473
11789
|
return { appPath, readmePath };
|
|
11474
11790
|
}
|
|
11475
11791
|
function wireSummary(r) {
|
|
11476
11792
|
return `\u2713 wired Cognito authorizer from the CDK outputs (no AWS call \u2014 read a local file):
|
|
11477
|
-
- ${
|
|
11793
|
+
- ${path26.basename(r.agentcoreJson)}: authorizerConfiguration.customJwtAuthorizer
|
|
11478
11794
|
discoveryUrl = ${r.discoveryUrl}
|
|
11479
11795
|
allowedClients = [${r.clientId}]
|
|
11480
|
-
- ${
|
|
11796
|
+
- ${path26.basename(r.agentcoreJson)}: envVars[] OAUTH_TOKEN_URL + OAUTH_SCOPE (reach the runtime so the agent card advertises oauth2)
|
|
11481
11797
|
- ${r.envLocal}: same pair, for local \`bag dev\`
|
|
11482
11798
|
\u2192 \`bag deploy prepare\` W9 will now pass; deploy when ready.`;
|
|
11483
11799
|
}
|
|
@@ -11510,8 +11826,8 @@ function upsertDescriptorEnvvars(cfg, values) {
|
|
|
11510
11826
|
function upsertEnv(envLocal, values) {
|
|
11511
11827
|
let lines = [];
|
|
11512
11828
|
try {
|
|
11513
|
-
if (
|
|
11514
|
-
lines =
|
|
11829
|
+
if (fs27.statSync(envLocal).isFile()) {
|
|
11830
|
+
lines = fs27.readFileSync(envLocal, "utf-8").split(/\r?\n/);
|
|
11515
11831
|
if (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
11516
11832
|
lines.pop();
|
|
11517
11833
|
}
|
|
@@ -11530,19 +11846,19 @@ function upsertEnv(envLocal, values) {
|
|
|
11530
11846
|
lines.push(repl);
|
|
11531
11847
|
}
|
|
11532
11848
|
}
|
|
11533
|
-
|
|
11534
|
-
|
|
11849
|
+
fs27.mkdirSync(path26.dirname(envLocal), { recursive: true });
|
|
11850
|
+
fs27.writeFileSync(envLocal, `${lines.join("\n")}
|
|
11535
11851
|
`, {
|
|
11536
11852
|
encoding: "utf-8",
|
|
11537
11853
|
mode: 384
|
|
11538
11854
|
});
|
|
11539
|
-
|
|
11855
|
+
fs27.chmodSync(envLocal, 384);
|
|
11540
11856
|
}
|
|
11541
11857
|
function wireCognitoOutputs(workspaceRoot, outputsFile = null) {
|
|
11542
|
-
const outPath = outputsFile ??
|
|
11858
|
+
const outPath = outputsFile ?? path26.join(workspaceRoot, COGNITO_OUTPUTS_FILE);
|
|
11543
11859
|
let exists = false;
|
|
11544
11860
|
try {
|
|
11545
|
-
exists =
|
|
11861
|
+
exists = fs27.statSync(outPath).isFile();
|
|
11546
11862
|
} catch {
|
|
11547
11863
|
exists = false;
|
|
11548
11864
|
}
|
|
@@ -11552,7 +11868,7 @@ function wireCognitoOutputs(workspaceRoot, outputsFile = null) {
|
|
|
11552
11868
|
);
|
|
11553
11869
|
}
|
|
11554
11870
|
const outs = flattenCdkOutputs(
|
|
11555
|
-
JSON.parse(
|
|
11871
|
+
JSON.parse(fs27.readFileSync(outPath, "utf-8"))
|
|
11556
11872
|
);
|
|
11557
11873
|
for (const key of ["DiscoveryUrl", "AppClientId", "TokenUrl", "Scope"]) {
|
|
11558
11874
|
if (outs[key] === void 0) {
|
|
@@ -11565,8 +11881,8 @@ function wireCognitoOutputs(workspaceRoot, outputsFile = null) {
|
|
|
11565
11881
|
const clientId = String(outs.AppClientId);
|
|
11566
11882
|
const tokenUrl = String(outs.TokenUrl);
|
|
11567
11883
|
const scope = String(outs.Scope);
|
|
11568
|
-
const acj =
|
|
11569
|
-
const cfg = JSON.parse(
|
|
11884
|
+
const acj = path26.join(workspaceRoot, "agentcore", "agentcore.json");
|
|
11885
|
+
const cfg = JSON.parse(fs27.readFileSync(acj, "utf-8"));
|
|
11570
11886
|
const runtimes = cfg.runtimes;
|
|
11571
11887
|
if (!Array.isArray(runtimes) || runtimes.length === 0) {
|
|
11572
11888
|
throw new Error(
|
|
@@ -11589,9 +11905,9 @@ function wireCognitoOutputs(workspaceRoot, outputsFile = null) {
|
|
|
11589
11905
|
OAUTH_TOKEN_URL: tokenUrl,
|
|
11590
11906
|
OAUTH_SCOPE: scope
|
|
11591
11907
|
});
|
|
11592
|
-
|
|
11908
|
+
fs27.writeFileSync(acj, `${JSON.stringify(cfg, null, 2)}
|
|
11593
11909
|
`, "utf-8");
|
|
11594
|
-
const envLocal =
|
|
11910
|
+
const envLocal = envLocalPath13(workspaceRoot);
|
|
11595
11911
|
upsertEnv(envLocal, { OAUTH_TOKEN_URL: tokenUrl, OAUTH_SCOPE: scope });
|
|
11596
11912
|
return {
|
|
11597
11913
|
discoveryUrl: discovery,
|
|
@@ -11604,41 +11920,41 @@ function wireCognitoOutputs(workspaceRoot, outputsFile = null) {
|
|
|
11604
11920
|
}
|
|
11605
11921
|
|
|
11606
11922
|
// src/cli/_deploy/destroy.ts
|
|
11607
|
-
import * as
|
|
11608
|
-
import * as
|
|
11609
|
-
import { findSubProjectRoot as
|
|
11923
|
+
import * as fs29 from "fs";
|
|
11924
|
+
import * as path28 from "path";
|
|
11925
|
+
import { findSubProjectRoot as findSubProjectRoot10 } from "@bnbagent/studio-runtime/config";
|
|
11610
11926
|
|
|
11611
11927
|
// src/cli/_deploy/status.ts
|
|
11612
|
-
import * as
|
|
11613
|
-
import * as
|
|
11928
|
+
import * as fs28 from "fs";
|
|
11929
|
+
import * as path27 from "path";
|
|
11614
11930
|
import {
|
|
11615
11931
|
APP_DIR as APP_DIR2,
|
|
11616
|
-
findSubProjectRoot as
|
|
11617
|
-
findWorkspaceRoot as
|
|
11618
|
-
loadStudioToml as
|
|
11932
|
+
findSubProjectRoot as findSubProjectRoot9,
|
|
11933
|
+
findWorkspaceRoot as findWorkspaceRoot5,
|
|
11934
|
+
loadStudioToml as loadStudioToml14
|
|
11619
11935
|
} from "@bnbagent/studio-runtime/config";
|
|
11620
11936
|
function loadToml(p) {
|
|
11621
11937
|
try {
|
|
11622
|
-
return
|
|
11938
|
+
return loadStudioToml14(p);
|
|
11623
11939
|
} catch {
|
|
11624
11940
|
return {};
|
|
11625
11941
|
}
|
|
11626
11942
|
}
|
|
11627
11943
|
function projectName(workspaceRoot) {
|
|
11628
|
-
const descriptor =
|
|
11944
|
+
const descriptor = path27.join(workspaceRoot, "agentcore", "agentcore.json");
|
|
11629
11945
|
try {
|
|
11630
|
-
const data = JSON.parse(
|
|
11946
|
+
const data = JSON.parse(fs28.readFileSync(descriptor, "utf-8"));
|
|
11631
11947
|
if (data !== null && typeof data === "object" && data.name) {
|
|
11632
11948
|
return String(data.name);
|
|
11633
11949
|
}
|
|
11634
11950
|
} catch {
|
|
11635
11951
|
}
|
|
11636
|
-
return
|
|
11952
|
+
return path27.basename(workspaceRoot);
|
|
11637
11953
|
}
|
|
11638
11954
|
async function runStatus(opts = {}) {
|
|
11639
|
-
const start = opts.projectRoot ?
|
|
11640
|
-
const agentRoot2 =
|
|
11641
|
-
const agentData = agentRoot2 !== null ? loadToml(
|
|
11955
|
+
const start = opts.projectRoot ? path27.resolve(opts.projectRoot) : void 0;
|
|
11956
|
+
const agentRoot2 = findSubProjectRoot9("agent", start);
|
|
11957
|
+
const agentData = agentRoot2 !== null ? loadToml(path27.join(agentRoot2, "studio.toml")) : {};
|
|
11642
11958
|
const deployRaw = agentData.deploy;
|
|
11643
11959
|
const deploy = deployRaw !== null && typeof deployRaw === "object" && !Array.isArray(deployRaw) ? { ...deployRaw } : {};
|
|
11644
11960
|
const runtimeArn = deploy.runtime_arn ? String(deploy.runtime_arn) : null;
|
|
@@ -11651,8 +11967,8 @@ async function runStatus(opts = {}) {
|
|
|
11651
11967
|
}
|
|
11652
11968
|
const onchainEndpoint = identity.endpoint ? String(identity.endpoint) : null;
|
|
11653
11969
|
const agentReachable = null;
|
|
11654
|
-
const workspaceBase2 =
|
|
11655
|
-
const workspaceRoot = workspaceBase2 !== null &&
|
|
11970
|
+
const workspaceBase2 = findWorkspaceRoot5(start) ?? (agentRoot2 !== null ? path27.dirname(agentRoot2) : null);
|
|
11971
|
+
const workspaceRoot = workspaceBase2 !== null && path27.basename(workspaceBase2) === APP_DIR2 ? path27.dirname(workspaceBase2) : workspaceBase2;
|
|
11656
11972
|
let region = null;
|
|
11657
11973
|
let account = null;
|
|
11658
11974
|
let secretId = null;
|
|
@@ -11716,13 +12032,13 @@ function printInvariants() {
|
|
|
11716
12032
|
);
|
|
11717
12033
|
}
|
|
11718
12034
|
function nullRecordedState(workspaceRoot) {
|
|
11719
|
-
const agentRoot2 =
|
|
12035
|
+
const agentRoot2 = findSubProjectRoot10("agent", workspaceRoot);
|
|
11720
12036
|
if (agentRoot2 === null) {
|
|
11721
12037
|
return;
|
|
11722
12038
|
}
|
|
11723
|
-
const ap =
|
|
12039
|
+
const ap = path28.join(agentRoot2, "studio.toml");
|
|
11724
12040
|
try {
|
|
11725
|
-
if (!
|
|
12041
|
+
if (!fs29.statSync(ap).isFile()) {
|
|
11726
12042
|
return;
|
|
11727
12043
|
}
|
|
11728
12044
|
} catch {
|
|
@@ -11786,19 +12102,19 @@ async function runDestroy(opts) {
|
|
|
11786
12102
|
}
|
|
11787
12103
|
|
|
11788
12104
|
// src/cli/_deploy/packaging.ts
|
|
11789
|
-
import * as
|
|
11790
|
-
import * as
|
|
12105
|
+
import * as fs30 from "fs";
|
|
12106
|
+
import * as path29 from "path";
|
|
11791
12107
|
import {
|
|
11792
|
-
findSubProjectRoot as
|
|
11793
|
-
loadStudioToml as
|
|
12108
|
+
findSubProjectRoot as findSubProjectRoot11,
|
|
12109
|
+
loadStudioToml as loadStudioToml15
|
|
11794
12110
|
} from "@bnbagent/studio-runtime/config";
|
|
11795
12111
|
function agentRootOf2(root) {
|
|
11796
|
-
return
|
|
12112
|
+
return findSubProjectRoot11("agent", root);
|
|
11797
12113
|
}
|
|
11798
12114
|
function agentTable(agentRoot2, key) {
|
|
11799
|
-
const tomlPath =
|
|
12115
|
+
const tomlPath = path29.join(agentRoot2, "studio.toml");
|
|
11800
12116
|
try {
|
|
11801
|
-
if (!
|
|
12117
|
+
if (!fs30.statSync(tomlPath).isFile()) {
|
|
11802
12118
|
return {};
|
|
11803
12119
|
}
|
|
11804
12120
|
} catch {
|
|
@@ -11806,7 +12122,7 @@ function agentTable(agentRoot2, key) {
|
|
|
11806
12122
|
}
|
|
11807
12123
|
let cfg;
|
|
11808
12124
|
try {
|
|
11809
|
-
cfg =
|
|
12125
|
+
cfg = loadStudioToml15(tomlPath);
|
|
11810
12126
|
} catch {
|
|
11811
12127
|
return {};
|
|
11812
12128
|
}
|
|
@@ -11865,10 +12181,10 @@ function checkPackagingDrift(root, destination, walletKind2, force) {
|
|
|
11865
12181
|
);
|
|
11866
12182
|
return 1;
|
|
11867
12183
|
}
|
|
11868
|
-
const dockerfile =
|
|
12184
|
+
const dockerfile = path29.join(agentRoot2, "Dockerfile");
|
|
11869
12185
|
let dockerfilePresent = false;
|
|
11870
12186
|
try {
|
|
11871
|
-
dockerfilePresent =
|
|
12187
|
+
dockerfilePresent = fs30.statSync(dockerfile).isFile();
|
|
11872
12188
|
} catch {
|
|
11873
12189
|
dockerfilePresent = false;
|
|
11874
12190
|
}
|
|
@@ -11909,7 +12225,7 @@ function deployWalletKindSafe(root) {
|
|
|
11909
12225
|
}
|
|
11910
12226
|
let cfg;
|
|
11911
12227
|
try {
|
|
11912
|
-
cfg =
|
|
12228
|
+
cfg = loadStudioToml15(path29.join(agentRoot2, "studio.toml"));
|
|
11913
12229
|
} catch {
|
|
11914
12230
|
return "evm-local";
|
|
11915
12231
|
}
|
|
@@ -11922,22 +12238,22 @@ function deployWalletKindSafe(root) {
|
|
|
11922
12238
|
import { findStudioWorkspaceRoot as findStudioWorkspaceRoot2 } from "@bnbagent/studio-runtime/config";
|
|
11923
12239
|
|
|
11924
12240
|
// src/cli/_deploy/checks/blocked.ts
|
|
11925
|
-
import * as
|
|
11926
|
-
import * as
|
|
12241
|
+
import * as fs31 from "fs";
|
|
12242
|
+
import * as path30 from "path";
|
|
11927
12243
|
import {
|
|
11928
|
-
findSubProjectRoot as
|
|
11929
|
-
loadStudioToml as
|
|
12244
|
+
findSubProjectRoot as findSubProjectRoot12,
|
|
12245
|
+
loadStudioToml as loadStudioToml16
|
|
11930
12246
|
} from "@bnbagent/studio-runtime/config";
|
|
11931
12247
|
function isFile12(p) {
|
|
11932
12248
|
try {
|
|
11933
|
-
return
|
|
12249
|
+
return fs31.statSync(p).isFile();
|
|
11934
12250
|
} catch {
|
|
11935
12251
|
return false;
|
|
11936
12252
|
}
|
|
11937
12253
|
}
|
|
11938
12254
|
function isDir6(p) {
|
|
11939
12255
|
try {
|
|
11940
|
-
return
|
|
12256
|
+
return fs31.statSync(p).isDirectory();
|
|
11941
12257
|
} catch {
|
|
11942
12258
|
return false;
|
|
11943
12259
|
}
|
|
@@ -11945,10 +12261,10 @@ function isDir6(p) {
|
|
|
11945
12261
|
async function checkStudioTomlPresent(root, _target) {
|
|
11946
12262
|
const out = [];
|
|
11947
12263
|
const layers = {
|
|
11948
|
-
agent:
|
|
12264
|
+
agent: findSubProjectRoot12("agent", root)
|
|
11949
12265
|
};
|
|
11950
12266
|
for (const [side, subRoot] of Object.entries(layers)) {
|
|
11951
|
-
const tomlPath = subRoot === null ? null :
|
|
12267
|
+
const tomlPath = subRoot === null ? null : path30.join(subRoot, "studio.toml");
|
|
11952
12268
|
if (tomlPath === null || !isFile12(tomlPath)) {
|
|
11953
12269
|
out.push({
|
|
11954
12270
|
level: Level.BLOCKED,
|
|
@@ -11959,7 +12275,7 @@ async function checkStudioTomlPresent(root, _target) {
|
|
|
11959
12275
|
continue;
|
|
11960
12276
|
}
|
|
11961
12277
|
try {
|
|
11962
|
-
|
|
12278
|
+
loadStudioToml16(tomlPath);
|
|
11963
12279
|
} catch (exc) {
|
|
11964
12280
|
const msg = exc instanceof Error ? exc.message : String(exc);
|
|
11965
12281
|
out.push({
|
|
@@ -11973,8 +12289,8 @@ async function checkStudioTomlPresent(root, _target) {
|
|
|
11973
12289
|
return out;
|
|
11974
12290
|
}
|
|
11975
12291
|
async function checkCwdIsProjectRoot(root, _target) {
|
|
11976
|
-
const cwd =
|
|
11977
|
-
const rr =
|
|
12292
|
+
const cwd = path30.resolve(process.cwd());
|
|
12293
|
+
const rr = path30.resolve(root);
|
|
11978
12294
|
if (cwd !== rr) {
|
|
11979
12295
|
return [
|
|
11980
12296
|
{
|
|
@@ -11988,7 +12304,7 @@ async function checkCwdIsProjectRoot(root, _target) {
|
|
|
11988
12304
|
return [];
|
|
11989
12305
|
}
|
|
11990
12306
|
async function checkNoSecretInGitHistory(root, _target) {
|
|
11991
|
-
if (!isDir6(
|
|
12307
|
+
if (!isDir6(path30.join(root, ".git"))) {
|
|
11992
12308
|
return [];
|
|
11993
12309
|
}
|
|
11994
12310
|
const needles = [".env.local", "WALLET_PASSWORD"];
|
|
@@ -12026,8 +12342,8 @@ var allChecks2 = [
|
|
|
12026
12342
|
];
|
|
12027
12343
|
|
|
12028
12344
|
// src/cli/_deploy/checks/info.ts
|
|
12029
|
-
import * as
|
|
12030
|
-
import * as
|
|
12345
|
+
import * as fs32 from "fs";
|
|
12346
|
+
import * as path31 from "path";
|
|
12031
12347
|
async function checkPreviousDeployStatus(root, _target) {
|
|
12032
12348
|
const deploy = tableOf2(loadAgentToml(root), "deploy");
|
|
12033
12349
|
const last = deploy.last_deploy_at;
|
|
@@ -12051,10 +12367,10 @@ async function checkPreviousDeployStatus(root, _target) {
|
|
|
12051
12367
|
];
|
|
12052
12368
|
}
|
|
12053
12369
|
async function checkInstalledRecipesList(root, _target) {
|
|
12054
|
-
const manifest =
|
|
12370
|
+
const manifest = path31.join(root, ".studio", "recipes", "manifest.json");
|
|
12055
12371
|
let exists = false;
|
|
12056
12372
|
try {
|
|
12057
|
-
exists =
|
|
12373
|
+
exists = fs32.statSync(manifest).isFile();
|
|
12058
12374
|
} catch {
|
|
12059
12375
|
exists = false;
|
|
12060
12376
|
}
|
|
@@ -12070,7 +12386,7 @@ async function checkInstalledRecipesList(root, _target) {
|
|
|
12070
12386
|
}
|
|
12071
12387
|
let data;
|
|
12072
12388
|
try {
|
|
12073
|
-
data = JSON.parse(
|
|
12389
|
+
data = JSON.parse(fs32.readFileSync(manifest, "utf-8"));
|
|
12074
12390
|
} catch {
|
|
12075
12391
|
return [
|
|
12076
12392
|
{
|
|
@@ -12173,26 +12489,26 @@ var allChecks3 = [
|
|
|
12173
12489
|
];
|
|
12174
12490
|
|
|
12175
12491
|
// src/cli/_deploy/checks/platform.ts
|
|
12176
|
-
import * as
|
|
12177
|
-
import * as
|
|
12492
|
+
import * as fs34 from "fs";
|
|
12493
|
+
import * as path33 from "path";
|
|
12178
12494
|
import {
|
|
12179
|
-
findSubProjectRoot as
|
|
12180
|
-
loadStudioToml as
|
|
12495
|
+
findSubProjectRoot as findSubProjectRoot13,
|
|
12496
|
+
loadStudioToml as loadStudioToml17
|
|
12181
12497
|
} from "@bnbagent/studio-runtime/config";
|
|
12182
12498
|
import { BSC_TESTNET_FAUCET_URLS } from "@bnbagent/studio-runtime/networks";
|
|
12183
12499
|
|
|
12184
12500
|
// src/cli/_deploy/checks/warning.ts
|
|
12185
12501
|
import * as crypto4 from "crypto";
|
|
12186
|
-
import * as
|
|
12187
|
-
import * as
|
|
12188
|
-
import { envLocalPath as
|
|
12502
|
+
import * as fs33 from "fs";
|
|
12503
|
+
import * as path32 from "path";
|
|
12504
|
+
import { envLocalPath as envLocalPath14 } from "@bnbagent/studio-runtime/config";
|
|
12189
12505
|
import { show } from "@bnbagent/studio-runtime/erc8004";
|
|
12190
12506
|
import { getNetwork as getNetwork8 } from "@bnbagent/studio-runtime/networks";
|
|
12191
12507
|
import * as walletRt3 from "@bnbagent/studio-runtime/wallet";
|
|
12192
12508
|
var TBNB_MIN_WEI = 7n * 10n ** 15n;
|
|
12193
12509
|
function isFile13(p) {
|
|
12194
12510
|
try {
|
|
12195
|
-
return
|
|
12511
|
+
return fs33.statSync(p).isFile();
|
|
12196
12512
|
} catch {
|
|
12197
12513
|
return false;
|
|
12198
12514
|
}
|
|
@@ -12330,7 +12646,7 @@ async function checkNetworkMatchesChainId(root, _target) {
|
|
|
12330
12646
|
return [];
|
|
12331
12647
|
}
|
|
12332
12648
|
async function checkRpcUrlSetForRuntime(root, _target) {
|
|
12333
|
-
const envLocal =
|
|
12649
|
+
const envLocal = envLocalPath14(root);
|
|
12334
12650
|
if (getEnvVar(envLocal, "RPC_URL")) {
|
|
12335
12651
|
return [];
|
|
12336
12652
|
}
|
|
@@ -12350,10 +12666,10 @@ async function checkRpcUrlSetForRuntime(root, _target) {
|
|
|
12350
12666
|
];
|
|
12351
12667
|
}
|
|
12352
12668
|
async function checkInstalledRecipesUnchanged(root, _target) {
|
|
12353
|
-
const manifest =
|
|
12669
|
+
const manifest = path32.join(root, ".studio", "recipes", "manifest.json");
|
|
12354
12670
|
let data;
|
|
12355
12671
|
try {
|
|
12356
|
-
data = JSON.parse(
|
|
12672
|
+
data = JSON.parse(fs33.readFileSync(manifest, "utf-8"));
|
|
12357
12673
|
} catch {
|
|
12358
12674
|
return [];
|
|
12359
12675
|
}
|
|
@@ -12368,11 +12684,11 @@ async function checkInstalledRecipesUnchanged(root, _target) {
|
|
|
12368
12684
|
if (!rel || !expected || typeof rel !== "string") {
|
|
12369
12685
|
continue;
|
|
12370
12686
|
}
|
|
12371
|
-
const p =
|
|
12687
|
+
const p = path32.join(root, rel);
|
|
12372
12688
|
if (!isFile13(p)) {
|
|
12373
12689
|
continue;
|
|
12374
12690
|
}
|
|
12375
|
-
const actual = crypto4.createHash("sha256").update(
|
|
12691
|
+
const actual = crypto4.createHash("sha256").update(fs33.readFileSync(p)).digest("hex");
|
|
12376
12692
|
if (actual !== expected) {
|
|
12377
12693
|
stale.push(rel);
|
|
12378
12694
|
}
|
|
@@ -12390,10 +12706,10 @@ async function checkInstalledRecipesUnchanged(root, _target) {
|
|
|
12390
12706
|
return [];
|
|
12391
12707
|
}
|
|
12392
12708
|
function agentcoreAuthorizer(root) {
|
|
12393
|
-
const descriptor =
|
|
12709
|
+
const descriptor = path32.join(root, "agentcore", "agentcore.json");
|
|
12394
12710
|
let data;
|
|
12395
12711
|
try {
|
|
12396
|
-
data = JSON.parse(
|
|
12712
|
+
data = JSON.parse(fs33.readFileSync(descriptor, "utf-8"));
|
|
12397
12713
|
} catch {
|
|
12398
12714
|
return null;
|
|
12399
12715
|
}
|
|
@@ -12471,39 +12787,39 @@ var allChecks4 = [
|
|
|
12471
12787
|
|
|
12472
12788
|
// src/cli/_deploy/checks/platform.ts
|
|
12473
12789
|
var SLUG_RE = /^[a-z][a-z0-9-]{1,40}$/;
|
|
12474
|
-
function
|
|
12790
|
+
function tableOf10(data, key) {
|
|
12475
12791
|
const value = data[key];
|
|
12476
12792
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
12477
12793
|
}
|
|
12478
12794
|
function agentRoot(root) {
|
|
12479
|
-
return
|
|
12795
|
+
return findSubProjectRoot13("agent", root) ?? path33.join(root, "app", "agent");
|
|
12480
12796
|
}
|
|
12481
12797
|
function loadAgent(root) {
|
|
12482
12798
|
try {
|
|
12483
|
-
return
|
|
12799
|
+
return loadStudioToml17(path33.join(agentRoot(root), "studio.toml"));
|
|
12484
12800
|
} catch {
|
|
12485
12801
|
return {};
|
|
12486
12802
|
}
|
|
12487
12803
|
}
|
|
12488
12804
|
function platformArtifact(data) {
|
|
12489
|
-
const walletKind2 = String(
|
|
12805
|
+
const walletKind2 = String(tableOf10(data, "wallet").kind ?? "evm-local").trim().toLowerCase();
|
|
12490
12806
|
if (walletKind2 === "twak") return "container";
|
|
12491
|
-
const deploy =
|
|
12807
|
+
const deploy = tableOf10(data, "deploy");
|
|
12492
12808
|
const explicit = String(deploy.platform_artifact ?? "").toLowerCase();
|
|
12493
12809
|
if (explicit) return explicit;
|
|
12494
12810
|
return String(deploy.packaging ?? "").toLowerCase() === "container" ? "container" : "zip";
|
|
12495
12811
|
}
|
|
12496
12812
|
var checkPlatformEntrypointPresent = async (root, _target) => {
|
|
12497
12813
|
const data = loadAgent(root);
|
|
12498
|
-
const faces = stackFaces(
|
|
12814
|
+
const faces = stackFaces(tableOf10(data, "stack"), tableOf10(data, "payments"));
|
|
12499
12815
|
const stem2 = entryStemOf(faces);
|
|
12500
12816
|
const filenames = [`${stem2}.ts`];
|
|
12501
12817
|
if (stem2 === "dualMain") filenames.push("mcpMain.ts");
|
|
12502
12818
|
const filename = filenames.find(
|
|
12503
|
-
(candidate) => !
|
|
12819
|
+
(candidate) => !fs34.existsSync(path33.join(agentRoot(root), "src", candidate))
|
|
12504
12820
|
);
|
|
12505
12821
|
if (filename === void 0) return [];
|
|
12506
|
-
const expected =
|
|
12822
|
+
const expected = path33.join(agentRoot(root), "src", filename);
|
|
12507
12823
|
return [
|
|
12508
12824
|
{
|
|
12509
12825
|
level: Level.CRITICAL,
|
|
@@ -12515,20 +12831,20 @@ var checkPlatformEntrypointPresent = async (root, _target) => {
|
|
|
12515
12831
|
};
|
|
12516
12832
|
var checkPlatformKeystoreNotInArtifact = async (root, _target) => {
|
|
12517
12833
|
const data = loadAgent(root);
|
|
12518
|
-
const wallet =
|
|
12834
|
+
const wallet = tableOf10(data, "wallet");
|
|
12519
12835
|
if (String(wallet.kind ?? "evm-local") === "twak") return [];
|
|
12520
|
-
const agent =
|
|
12836
|
+
const agent = path33.resolve(agentRoot(root));
|
|
12521
12837
|
const configured = String(wallet.keystore_dir ?? ".studio/wallets");
|
|
12522
|
-
const keystore =
|
|
12838
|
+
const keystore = path33.resolve(agent, configured);
|
|
12523
12839
|
let jsonFiles;
|
|
12524
12840
|
try {
|
|
12525
|
-
jsonFiles =
|
|
12841
|
+
jsonFiles = fs34.readdirSync(keystore).filter((name) => name.endsWith(".json"));
|
|
12526
12842
|
} catch {
|
|
12527
12843
|
return [];
|
|
12528
12844
|
}
|
|
12529
12845
|
if (jsonFiles.length === 0) return [];
|
|
12530
|
-
const rel =
|
|
12531
|
-
if (rel.startsWith("..") ||
|
|
12846
|
+
const rel = path33.relative(agent, keystore);
|
|
12847
|
+
if (rel.startsWith("..") || path33.isAbsolute(rel)) return [];
|
|
12532
12848
|
return [
|
|
12533
12849
|
{
|
|
12534
12850
|
level: Level.CRITICAL,
|
|
@@ -12539,7 +12855,7 @@ var checkPlatformKeystoreNotInArtifact = async (root, _target) => {
|
|
|
12539
12855
|
];
|
|
12540
12856
|
};
|
|
12541
12857
|
var checkPlatformTestnetOnly = async (root, _target) => {
|
|
12542
|
-
const network = String(
|
|
12858
|
+
const network = String(tableOf10(loadAgent(root), "network").default ?? "").trim().toLowerCase();
|
|
12543
12859
|
if (!network || network === "bsc-testnet") return [];
|
|
12544
12860
|
return [
|
|
12545
12861
|
{
|
|
@@ -12552,7 +12868,7 @@ var checkPlatformTestnetOnly = async (root, _target) => {
|
|
|
12552
12868
|
];
|
|
12553
12869
|
};
|
|
12554
12870
|
var checkPlatformSlugValid = async (root, _target) => {
|
|
12555
|
-
const platform =
|
|
12871
|
+
const platform = tableOf10(tableOf10(loadAgent(root), "deploy"), "platform");
|
|
12556
12872
|
const slug = String(platform.slug ?? "").trim();
|
|
12557
12873
|
if (!slug || SLUG_RE.test(slug)) return [];
|
|
12558
12874
|
return [
|
|
@@ -12610,7 +12926,7 @@ var checkPlatformStorageEndpoint = async (root, _target) => {
|
|
|
12610
12926
|
};
|
|
12611
12927
|
var checkPlatformMcpSyncTimeout = async (root, _target) => {
|
|
12612
12928
|
const data = loadAgent(root);
|
|
12613
|
-
const faces = stackFaces(
|
|
12929
|
+
const faces = stackFaces(tableOf10(data, "stack"), tableOf10(data, "payments"));
|
|
12614
12930
|
if (!hasMcpFace(faces)) return [];
|
|
12615
12931
|
const dual = hasA2aFace(faces);
|
|
12616
12932
|
return [
|
|
@@ -12623,8 +12939,8 @@ var checkPlatformMcpSyncTimeout = async (root, _target) => {
|
|
|
12623
12939
|
];
|
|
12624
12940
|
};
|
|
12625
12941
|
var checkPlatformX402MerchantsMainnet = async (root, _target) => {
|
|
12626
|
-
const merchants =
|
|
12627
|
-
|
|
12942
|
+
const merchants = tableOf10(
|
|
12943
|
+
tableOf10(tableOf10(loadAgent(root), "payments"), "x402"),
|
|
12628
12944
|
"merchants"
|
|
12629
12945
|
);
|
|
12630
12946
|
const names = Object.keys(merchants).sort();
|
|
@@ -12753,217 +13069,6 @@ async function runProducers(producers, root, target) {
|
|
|
12753
13069
|
return out;
|
|
12754
13070
|
}
|
|
12755
13071
|
|
|
12756
|
-
// src/cli/_deploy/providers.ts
|
|
12757
|
-
import * as fs34 from "fs";
|
|
12758
|
-
import * as path33 from "path";
|
|
12759
|
-
import {
|
|
12760
|
-
findSubProjectRoot as findSubProjectRoot13,
|
|
12761
|
-
findWorkspaceRoot as findWorkspaceRoot5,
|
|
12762
|
-
loadStudioToml as loadStudioToml17
|
|
12763
|
-
} from "@bnbagent/studio-runtime/config";
|
|
12764
|
-
var PROVIDER_TARGETS = {
|
|
12765
|
-
bnb: "bnb/trial",
|
|
12766
|
-
aws: "aws/agentcore",
|
|
12767
|
-
azure: "azure/foundry"
|
|
12768
|
-
};
|
|
12769
|
-
var PROVIDER_LABELS = {
|
|
12770
|
-
bnb: "BNB Chain Trial",
|
|
12771
|
-
aws: "AWS AgentCore",
|
|
12772
|
-
azure: "Azure Foundry"
|
|
12773
|
-
};
|
|
12774
|
-
var PROVIDER_MENU_ORDER = [
|
|
12775
|
-
"bnb",
|
|
12776
|
-
"aws",
|
|
12777
|
-
"azure"
|
|
12778
|
-
];
|
|
12779
|
-
var PROVIDER_SHORT_LABELS = {
|
|
12780
|
-
bnb: "BNB",
|
|
12781
|
-
aws: "AWS",
|
|
12782
|
-
azure: "Azure"
|
|
12783
|
-
};
|
|
12784
|
-
function providerDigit(provider) {
|
|
12785
|
-
return PROVIDER_MENU_ORDER.indexOf(provider) + 1;
|
|
12786
|
-
}
|
|
12787
|
-
var ADVERTISED_PROVIDERS = ["bnb", "aws"];
|
|
12788
|
-
var ADVERTISED_PROVIDERS_HELP = ADVERTISED_PROVIDERS.join("|");
|
|
12789
|
-
function tableOf10(data, key) {
|
|
12790
|
-
const value = data[key];
|
|
12791
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
12792
|
-
}
|
|
12793
|
-
function text(value) {
|
|
12794
|
-
if (typeof value !== "string") return null;
|
|
12795
|
-
const clean = value.trim();
|
|
12796
|
-
return clean || null;
|
|
12797
|
-
}
|
|
12798
|
-
function descriptorName(workspaceRoot) {
|
|
12799
|
-
try {
|
|
12800
|
-
const data = JSON.parse(
|
|
12801
|
-
fs34.readFileSync(
|
|
12802
|
-
path33.join(workspaceRoot, "agentcore", "agentcore.json"),
|
|
12803
|
-
"utf-8"
|
|
12804
|
-
)
|
|
12805
|
-
);
|
|
12806
|
-
return text(data.name);
|
|
12807
|
-
} catch {
|
|
12808
|
-
return null;
|
|
12809
|
-
}
|
|
12810
|
-
}
|
|
12811
|
-
function discoverRecordedDeployments(root) {
|
|
12812
|
-
const workspaceRoot = findWorkspaceRoot5(root) ?? path33.resolve(root);
|
|
12813
|
-
const agentRoot2 = findSubProjectRoot13("agent", workspaceRoot);
|
|
12814
|
-
if (agentRoot2 === null) return [];
|
|
12815
|
-
let config;
|
|
12816
|
-
try {
|
|
12817
|
-
config = loadStudioToml17(path33.join(agentRoot2, "studio.toml"));
|
|
12818
|
-
} catch {
|
|
12819
|
-
return [];
|
|
12820
|
-
}
|
|
12821
|
-
const projectName2 = descriptorName(workspaceRoot) ?? text(tableOf10(config, "project").name) ?? path33.basename(workspaceRoot);
|
|
12822
|
-
const deploy = tableOf10(config, "deploy");
|
|
12823
|
-
const platform = tableOf10(deploy, "platform");
|
|
12824
|
-
const azure = tableOf10(config, "azure");
|
|
12825
|
-
const runtime = text(tableOf10(config, "stack").runtime) ?? "agentcore";
|
|
12826
|
-
const found = [];
|
|
12827
|
-
const bnbId = text(platform.deployment_id);
|
|
12828
|
-
const bnbEndpoint = text(platform.invoke_url);
|
|
12829
|
-
if (bnbId || bnbEndpoint || text(platform.last_deploy_at)) {
|
|
12830
|
-
found.push({
|
|
12831
|
-
provider: "bnb",
|
|
12832
|
-
target: PROVIDER_TARGETS.bnb,
|
|
12833
|
-
name: text(platform.slug) ?? projectName2,
|
|
12834
|
-
deploymentId: bnbId,
|
|
12835
|
-
endpoint: bnbEndpoint,
|
|
12836
|
-
status: "active"
|
|
12837
|
-
});
|
|
12838
|
-
}
|
|
12839
|
-
const awsArn = text(deploy.runtime_arn);
|
|
12840
|
-
const awsEndpoint = text(deploy.invoke_url);
|
|
12841
|
-
const legacyAwsTimestamp = Boolean(text(deploy.last_deploy_at)) && runtime !== "azure-foundry" && text(deploy.destination) !== "platform";
|
|
12842
|
-
if (awsArn || awsEndpoint || text(deploy.provider) === "aws" || legacyAwsTimestamp) {
|
|
12843
|
-
found.push({
|
|
12844
|
-
provider: "aws",
|
|
12845
|
-
target: PROVIDER_TARGETS.aws,
|
|
12846
|
-
name: projectName2,
|
|
12847
|
-
deploymentId: awsArn,
|
|
12848
|
-
endpoint: awsEndpoint,
|
|
12849
|
-
status: "active"
|
|
12850
|
-
});
|
|
12851
|
-
}
|
|
12852
|
-
const azureEndpoint = text(azure.agent_endpoint);
|
|
12853
|
-
const azureDeploymentId = text(azure.deployment_id);
|
|
12854
|
-
if (azureEndpoint || azureDeploymentId || text(azure.last_deploy_at)) {
|
|
12855
|
-
found.push({
|
|
12856
|
-
provider: "azure",
|
|
12857
|
-
target: PROVIDER_TARGETS.azure,
|
|
12858
|
-
name: text(azure.agent_name) ?? projectName2,
|
|
12859
|
-
deploymentId: azureDeploymentId,
|
|
12860
|
-
endpoint: azureEndpoint,
|
|
12861
|
-
status: "active"
|
|
12862
|
-
});
|
|
12863
|
-
}
|
|
12864
|
-
return found;
|
|
12865
|
-
}
|
|
12866
|
-
function unavailableProvidersForProject(root) {
|
|
12867
|
-
const workspaceRoot = findWorkspaceRoot5(root) ?? path33.resolve(root);
|
|
12868
|
-
const agentRoot2 = findSubProjectRoot13("agent", workspaceRoot);
|
|
12869
|
-
if (agentRoot2 === null) return {};
|
|
12870
|
-
let runtime = "agentcore";
|
|
12871
|
-
let azureProtocolUnsupported = false;
|
|
12872
|
-
try {
|
|
12873
|
-
const cfg = loadStudioToml17(path33.join(agentRoot2, "studio.toml"));
|
|
12874
|
-
runtime = text(tableOf10(cfg, "stack").runtime) ?? "agentcore";
|
|
12875
|
-
const faces = stackFaces(tableOf10(cfg, "stack"), tableOf10(cfg, "payments"));
|
|
12876
|
-
azureProtocolUnsupported = !hasA2aFace(faces) || hasMcpFace(faces);
|
|
12877
|
-
} catch {
|
|
12878
|
-
return {};
|
|
12879
|
-
}
|
|
12880
|
-
if (runtime === "azure-foundry") {
|
|
12881
|
-
const reason = "this project uses a different container adapter; scaffold an agentcore project before selecting BNB or AWS";
|
|
12882
|
-
return {
|
|
12883
|
-
bnb: reason,
|
|
12884
|
-
aws: reason,
|
|
12885
|
-
...azureProtocolUnsupported ? {
|
|
12886
|
-
azure: "Azure Foundry deploy currently supports A2A projects only; use an A2A azure-foundry scaffold or AgentCore for MCP"
|
|
12887
|
-
} : {}
|
|
12888
|
-
};
|
|
12889
|
-
}
|
|
12890
|
-
return {
|
|
12891
|
-
azure: "this project uses the agentcore adapter; scaffold with --runtime azure-foundry before selecting Azure"
|
|
12892
|
-
};
|
|
12893
|
-
}
|
|
12894
|
-
function selected(provider, deployments) {
|
|
12895
|
-
const active = deployments.filter((d) => d.status === "active");
|
|
12896
|
-
return {
|
|
12897
|
-
kind: "selected",
|
|
12898
|
-
provider,
|
|
12899
|
-
operation: active.some((d) => d.provider === provider) ? "update" : "create",
|
|
12900
|
-
hasOtherActive: active.some((d) => d.provider !== provider)
|
|
12901
|
-
};
|
|
12902
|
-
}
|
|
12903
|
-
function trialExpired(trial) {
|
|
12904
|
-
return trial.state.toLowerCase() === "expired";
|
|
12905
|
-
}
|
|
12906
|
-
function unavailableReason(opts, provider) {
|
|
12907
|
-
if (provider === "bnb" && trialExpired(opts.trial)) {
|
|
12908
|
-
return "the 48h trial has expired";
|
|
12909
|
-
}
|
|
12910
|
-
return opts.unavailable?.[provider] ?? null;
|
|
12911
|
-
}
|
|
12912
|
-
function providerPromptHint() {
|
|
12913
|
-
return PROVIDER_MENU_ORDER.filter((p) => ADVERTISED_PROVIDERS.includes(p)).map((p) => `${providerDigit(p)}=${PROVIDER_SHORT_LABELS[p]}`).join(", ");
|
|
12914
|
-
}
|
|
12915
|
-
async function promptProvider(opts) {
|
|
12916
|
-
for (; ; ) {
|
|
12917
|
-
const answer = (await opts.prompt(`Provider [${providerPromptHint()}]: `)).trim().toLowerCase();
|
|
12918
|
-
const provider = answer === "1" || answer === "bnb" ? "bnb" : answer === "2" || answer === "aws" ? "aws" : answer === "3" || answer === "azure" ? "azure" : null;
|
|
12919
|
-
if (provider === null) {
|
|
12920
|
-
if (answer === "" || answer === "q" || answer === "cancel") {
|
|
12921
|
-
return { kind: "cancelled", exitCode: 1 };
|
|
12922
|
-
}
|
|
12923
|
-
continue;
|
|
12924
|
-
}
|
|
12925
|
-
if (unavailableReason(opts, provider)) {
|
|
12926
|
-
continue;
|
|
12927
|
-
}
|
|
12928
|
-
return selected(provider, opts.deployments);
|
|
12929
|
-
}
|
|
12930
|
-
}
|
|
12931
|
-
async function selectDeployProvider(opts) {
|
|
12932
|
-
if (opts.requested) {
|
|
12933
|
-
const reason = unavailableReason(opts, opts.requested);
|
|
12934
|
-
if (reason) {
|
|
12935
|
-
return {
|
|
12936
|
-
kind: "unavailable",
|
|
12937
|
-
provider: opts.requested,
|
|
12938
|
-
reason,
|
|
12939
|
-
exitCode: 2
|
|
12940
|
-
};
|
|
12941
|
-
}
|
|
12942
|
-
return selected(opts.requested, opts.deployments);
|
|
12943
|
-
}
|
|
12944
|
-
if (!opts.interactive) {
|
|
12945
|
-
return { kind: "selection_required", exitCode: 2 };
|
|
12946
|
-
}
|
|
12947
|
-
const active = opts.deployments.filter((d) => d.status === "active");
|
|
12948
|
-
const activeDeployment = active[0];
|
|
12949
|
-
if (active.length === 1 && activeDeployment) {
|
|
12950
|
-
if (unavailableReason(opts, activeDeployment.provider)) {
|
|
12951
|
-
return promptProvider(opts);
|
|
12952
|
-
}
|
|
12953
|
-
const answer = (await opts.prompt(
|
|
12954
|
-
`Update the existing ${PROVIDER_LABELS[activeDeployment.provider]} deployment? [1=update, 2=another provider, 3=cancel]: `
|
|
12955
|
-
)).trim().toLowerCase();
|
|
12956
|
-
if (answer === "1" || answer === "update" || answer === "yes") {
|
|
12957
|
-
return selected(activeDeployment.provider, opts.deployments);
|
|
12958
|
-
}
|
|
12959
|
-
if (answer === "2" || answer === "another") {
|
|
12960
|
-
return promptProvider(opts);
|
|
12961
|
-
}
|
|
12962
|
-
return { kind: "cancelled", exitCode: 1 };
|
|
12963
|
-
}
|
|
12964
|
-
return promptProvider(opts);
|
|
12965
|
-
}
|
|
12966
|
-
|
|
12967
13072
|
// src/cli/_deploy/verify.ts
|
|
12968
13073
|
import * as path35 from "path";
|
|
12969
13074
|
import {
|
|
@@ -13321,7 +13426,7 @@ async function runVerify(opts) {
|
|
|
13321
13426
|
import * as fs36 from "fs";
|
|
13322
13427
|
import * as path36 from "path";
|
|
13323
13428
|
import {
|
|
13324
|
-
envLocalPath as
|
|
13429
|
+
envLocalPath as envLocalPath15,
|
|
13325
13430
|
findSubProjectRoot as findSubProjectRoot15,
|
|
13326
13431
|
findWorkspaceRoot as findWorkspaceRoot6,
|
|
13327
13432
|
loadStudioToml as loadStudioToml19
|
|
@@ -13971,7 +14076,7 @@ function persistDeploySummary(root, text2) {
|
|
|
13971
14076
|
return null;
|
|
13972
14077
|
}
|
|
13973
14078
|
const p = path36.join(
|
|
13974
|
-
path36.dirname(
|
|
14079
|
+
path36.dirname(envLocalPath15(root)),
|
|
13975
14080
|
"last-deploy-summary.txt"
|
|
13976
14081
|
);
|
|
13977
14082
|
fs36.mkdirSync(path36.dirname(p), { recursive: true });
|
|
@@ -14184,7 +14289,7 @@ function loadAgentCfg2(root) {
|
|
|
14184
14289
|
function registerDeploy(program) {
|
|
14185
14290
|
program.enablePositionalOptions();
|
|
14186
14291
|
const p = program.command("deploy").description(
|
|
14187
|
-
|
|
14292
|
+
`Deploy the agent after explicitly selecting a provider (${ADVERTISED_PROVIDERS_HELP}); lifecycle subcommands inspect recorded deployments.`
|
|
14188
14293
|
);
|
|
14189
14294
|
const runtimeOption = () => acceptChoices(
|
|
14190
14295
|
new Option4(
|
|
@@ -14205,7 +14310,7 @@ function registerDeploy(program) {
|
|
|
14205
14310
|
const providerOption = () => acceptChoices(
|
|
14206
14311
|
new Option4(
|
|
14207
14312
|
"--provider <provider>",
|
|
14208
|
-
|
|
14313
|
+
`Provider: ${ADVERTISED_PROVIDERS_HELP}. Required for non-interactive deploy; lifecycle commands need it only when multiple records exist.`
|
|
14209
14314
|
),
|
|
14210
14315
|
// Unadvertised providers stay parseable (see ADVERTISED_PROVIDERS).
|
|
14211
14316
|
PROVIDER_MENU_ORDER,
|
|
@@ -14363,7 +14468,8 @@ function applyProjectRoot(projectRoot, requireToml = true) {
|
|
|
14363
14468
|
return null;
|
|
14364
14469
|
}
|
|
14365
14470
|
function resolveProjectRoot2(_projectRoot) {
|
|
14366
|
-
|
|
14471
|
+
const cwd = path37.resolve(process.cwd());
|
|
14472
|
+
return findStudioWorkspaceRoot3(cwd) ?? cwd;
|
|
14367
14473
|
}
|
|
14368
14474
|
function deployWorkspaceRoot2(root) {
|
|
14369
14475
|
return findStudioWorkspaceRoot3(root) ?? root;
|
|
@@ -14600,10 +14706,10 @@ function writeAgentDeployState(workspaceRoot, arn, record = {}, destination = "s
|
|
|
14600
14706
|
patchTomlKv(tomlPath, "deploy", "oauth_discovery_url", discoveryUrl);
|
|
14601
14707
|
}
|
|
14602
14708
|
if (tokenUrl) {
|
|
14603
|
-
setEnvVar(
|
|
14709
|
+
setEnvVar(envLocalPath16(agentRoot2), "OAUTH_TOKEN_URL", tokenUrl);
|
|
14604
14710
|
}
|
|
14605
14711
|
if (scope) {
|
|
14606
|
-
setEnvVar(
|
|
14712
|
+
setEnvVar(envLocalPath16(agentRoot2), "OAUTH_SCOPE", scope);
|
|
14607
14713
|
}
|
|
14608
14714
|
if (persistedPackaging(agentRoot2) === null) {
|
|
14609
14715
|
patchTomlKv(
|
|
@@ -15325,7 +15431,7 @@ function persistDeploySummary2(root, text2) {
|
|
|
15325
15431
|
return null;
|
|
15326
15432
|
}
|
|
15327
15433
|
const p = path37.join(
|
|
15328
|
-
path37.dirname(
|
|
15434
|
+
path37.dirname(envLocalPath16(root)),
|
|
15329
15435
|
"last-deploy-summary.txt"
|
|
15330
15436
|
);
|
|
15331
15437
|
fs37.mkdirSync(path37.dirname(p), { recursive: true });
|
|
@@ -15842,7 +15948,7 @@ import * as fs38 from "fs";
|
|
|
15842
15948
|
import * as path38 from "path";
|
|
15843
15949
|
import { EVMWalletProvider as EVMWalletProvider2 } from "@bnbagent/sdk";
|
|
15844
15950
|
import {
|
|
15845
|
-
envLocalPath as
|
|
15951
|
+
envLocalPath as envLocalPath17,
|
|
15846
15952
|
findProjectRoot as findProjectRoot4,
|
|
15847
15953
|
findStudioWorkspaceRoot as findStudioWorkspaceRoot4,
|
|
15848
15954
|
loadStudioToml as loadStudioToml21
|
|
@@ -15982,7 +16088,7 @@ function resolveProjectRoot3(argRoot) {
|
|
|
15982
16088
|
}
|
|
15983
16089
|
function runCheckEnv(projectRoot) {
|
|
15984
16090
|
const agentDir = workspaceLayers(projectRoot) ?? path38.join(projectRoot, "agent");
|
|
15985
|
-
const envPath =
|
|
16091
|
+
const envPath = envLocalPath17(agentDir);
|
|
15986
16092
|
printOut(`bag doctor --check-env: ${envPath}`);
|
|
15987
16093
|
if (!isFile16(envPath)) {
|
|
15988
16094
|
printOut(` (no ${path38.basename(envPath)} found \u2014 nothing to report)`);
|
|
@@ -16062,7 +16168,8 @@ function checkAppMain(projectRootArg) {
|
|
|
16062
16168
|
}
|
|
16063
16169
|
];
|
|
16064
16170
|
}
|
|
16065
|
-
|
|
16171
|
+
const detail = runtime === "azure-foundry" ? `${entrypoint} (deploy entrypoint; \`bag dev\` serves src/main.ts or src/mcpMain.ts locally)` : entrypoint;
|
|
16172
|
+
return [{ name: "agent entrypoint", status: PASS, detail }];
|
|
16066
16173
|
}
|
|
16067
16174
|
function checkAgentcoreName(projectRoot) {
|
|
16068
16175
|
let cfgPath = null;
|
|
@@ -16395,7 +16502,7 @@ async function checkLlm(data, projectRoot) {
|
|
|
16395
16502
|
}
|
|
16396
16503
|
];
|
|
16397
16504
|
}
|
|
16398
|
-
const keyValue = getEnvVar(
|
|
16505
|
+
const keyValue = getEnvVar(envLocalPath17(projectRoot), keyEnv) || process.env[keyEnv];
|
|
16399
16506
|
const out = [];
|
|
16400
16507
|
if (keyValue) {
|
|
16401
16508
|
out.push({
|
|
@@ -16734,7 +16841,7 @@ function checkX402Seller(data, agentRoot2) {
|
|
|
16734
16841
|
out.push({
|
|
16735
16842
|
name: "x402 credentials",
|
|
16736
16843
|
status: credentials.any ? FAIL : fallbackStatus,
|
|
16737
|
-
detail: credentials.any ?
|
|
16844
|
+
detail: credentials.any ? `B402 credentials are partial; set BASE_URL, CLIENT_ID, ACCESS_TOKEN, and exactly one private-key form. Confirm they were issued for this exact agent wallet and environment; never reuse them across wallets. Apply: ${B402_DEVELOPER_ACCOUNT_URL}` : `PAID mode needs the four B402 merchant credentials; without them the rail starts dormant. ${B402_PAID_ONBOARDING_GUIDANCE}`
|
|
16738
16845
|
});
|
|
16739
16846
|
}
|
|
16740
16847
|
if (runtime !== "agentcore") {
|
|
@@ -18101,7 +18208,7 @@ async function cmdSettle(jobId, opts) {
|
|
|
18101
18208
|
|
|
18102
18209
|
// src/cli/skills.ts
|
|
18103
18210
|
import * as fs41 from "fs";
|
|
18104
|
-
import * as
|
|
18211
|
+
import * as os6 from "os";
|
|
18105
18212
|
import * as path42 from "path";
|
|
18106
18213
|
import { Option as Option7 } from "commander";
|
|
18107
18214
|
function registerSkills(program) {
|
|
@@ -18421,7 +18528,7 @@ function isFile17(p) {
|
|
|
18421
18528
|
}
|
|
18422
18529
|
function findInstalledSkills(knownNames) {
|
|
18423
18530
|
const found = [];
|
|
18424
|
-
const home =
|
|
18531
|
+
const home = os6.homedir();
|
|
18425
18532
|
const cwd = process.cwd();
|
|
18426
18533
|
const roots = [];
|
|
18427
18534
|
const addRoot = (root) => {
|
|
@@ -19141,7 +19248,7 @@ import * as fs44 from "fs";
|
|
|
19141
19248
|
import * as path46 from "path";
|
|
19142
19249
|
import { auditedOp as auditedOp4 } from "@bnbagent/studio-runtime/audit";
|
|
19143
19250
|
import {
|
|
19144
|
-
envLocalPath as
|
|
19251
|
+
envLocalPath as envLocalPath18,
|
|
19145
19252
|
findProjectRoot as findProjectRoot6,
|
|
19146
19253
|
loadStudioToml as loadStudioToml24
|
|
19147
19254
|
} from "@bnbagent/studio-runtime/config";
|
|
@@ -19405,7 +19512,7 @@ async function cmdSellInit(priceFlag) {
|
|
|
19405
19512
|
"utf8"
|
|
19406
19513
|
);
|
|
19407
19514
|
}
|
|
19408
|
-
const envPath =
|
|
19515
|
+
const envPath = envLocalPath18(root);
|
|
19409
19516
|
for (const key of B402_ENV_KEYS) {
|
|
19410
19517
|
const existing = getEnvVar(envPath, key);
|
|
19411
19518
|
if (key === "B402_BASE_URL" && !free && resolveNetwork3(cfg).toLowerCase() === "bsc-testnet" && !process.env.B402_BASE_URL && !existing) {
|
|
@@ -19417,6 +19524,9 @@ async function cmdSellInit(priceFlag) {
|
|
|
19417
19524
|
printOut(
|
|
19418
19525
|
free ? "\u2713 x402 seller config is ready in FREE mode; B402 credentials are not required." : "\u2713 x402 seller config and B402 placeholders are ready for PAID mode."
|
|
19419
19526
|
);
|
|
19527
|
+
if (!free) {
|
|
19528
|
+
printOut(`Next: ${B402_PAID_ONBOARDING_GUIDANCE}`);
|
|
19529
|
+
}
|
|
19420
19530
|
if (free) {
|
|
19421
19531
|
printErr(
|
|
19422
19532
|
"warning: /x402 is an anonymous FREE endpoint; B402 verify/settle and payment audit are bypassed."
|
|
@@ -19479,6 +19589,9 @@ async function cmdSellStatus(probe) {
|
|
|
19479
19589
|
for (const [key, isSet] of Object.entries(presence)) {
|
|
19480
19590
|
printOut(` ${key}: ${isSet ? "set" : "absent"}`);
|
|
19481
19591
|
}
|
|
19592
|
+
if (policy.enabled && !free && !credentialsComplete) {
|
|
19593
|
+
printOut(`Onboarding: ${B402_PAID_ONBOARDING_GUIDANCE}`);
|
|
19594
|
+
}
|
|
19482
19595
|
if (!probe) {
|
|
19483
19596
|
printOut("B402 probe: skipped (--no-probe)");
|
|
19484
19597
|
return 0;
|
|
@@ -19920,12 +20033,12 @@ function buildProgram() {
|
|
|
19920
20033
|
return program;
|
|
19921
20034
|
}
|
|
19922
20035
|
function cliVersion() {
|
|
19923
|
-
return "0.0.6-alpha.
|
|
20036
|
+
return "0.0.6-alpha.5";
|
|
19924
20037
|
}
|
|
19925
20038
|
|
|
19926
20039
|
// src/cli/updateCheck.ts
|
|
19927
20040
|
import * as fs45 from "fs";
|
|
19928
|
-
import * as
|
|
20041
|
+
import * as os7 from "os";
|
|
19929
20042
|
import * as path47 from "path";
|
|
19930
20043
|
var PACKAGE = "@bnbagent/studio-cli";
|
|
19931
20044
|
var REGISTRY_LATEST_URL = `https://registry.npmjs.org/${PACKAGE}/latest`;
|
|
@@ -19989,7 +20102,7 @@ async function maybePrintUpdateNudge(opts = {}) {
|
|
|
19989
20102
|
if (!isTty()) {
|
|
19990
20103
|
return;
|
|
19991
20104
|
}
|
|
19992
|
-
const home = opts.home ??
|
|
20105
|
+
const home = opts.home ?? os7.homedir();
|
|
19993
20106
|
const state = loadCache(home);
|
|
19994
20107
|
const now = Date.now() / 1e3;
|
|
19995
20108
|
if (now - Number(state.checked_at ?? 0) < CHECK_INTERVAL_SECONDS) {
|