settld 0.2.1 → 0.2.3

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.
@@ -13,10 +13,13 @@ import { bootstrapWalletProvider } from "../../src/core/wallet-provider-bootstra
13
13
  import { extractBootstrapMcpEnv, loadHostConfigHelper, runWizard } from "./wizard.mjs";
14
14
  import { SUPPORTED_HOSTS } from "./host-config.mjs";
15
15
  import { defaultSessionPath, readSavedSession } from "./session-store.mjs";
16
+ import { runLogin } from "./login.mjs";
17
+ import { runWalletCli } from "../wallet/cli.mjs";
16
18
 
17
19
  const WALLET_MODES = new Set(["managed", "byo", "none"]);
18
20
  const WALLET_PROVIDERS = new Set(["circle"]);
19
21
  const WALLET_BOOTSTRAP_MODES = new Set(["auto", "local", "remote"]);
22
+ const SETUP_MODES = new Set(["quick", "advanced"]);
20
23
  const FORMAT_OPTIONS = new Set(["text", "json"]);
21
24
  const HOST_BINARY_HINTS = Object.freeze({
22
25
  codex: "codex",
@@ -38,6 +41,7 @@ const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
38
41
  const REPO_ROOT = path.resolve(SCRIPT_DIR, "..", "..");
39
42
  const SETTLD_BIN = path.join(REPO_ROOT, "bin", "settld.js");
40
43
  const PROFILE_FINGERPRINT_REGEX = /^[0-9a-f]{64}$/;
44
+ const DEFAULT_PUBLIC_BASE_URL = "https://api.settld.work";
41
45
  const ANSI_RESET = "\u001b[0m";
42
46
  const ANSI_BOLD = "\u001b[1m";
43
47
  const ANSI_DIM = "\u001b[2m";
@@ -54,6 +58,10 @@ function usage() {
54
58
  "",
55
59
  "flags:",
56
60
  " --non-interactive Disable prompts; require explicit flags",
61
+ " --quick Quick setup mode (default for interactive)",
62
+ " --advanced Advanced setup mode (shows all prompts)",
63
+ " --guided-next Run guided fund + first paid check after setup (default in quick mode)",
64
+ " --skip-guided-next Skip guided post-setup actions",
57
65
  ` --host <${SUPPORTED_HOSTS.join("|")}> Host target (default: auto-detect, fallback openclaw)`,
58
66
  " --base-url <url> Settld API base URL (or SETTLD_BASE_URL)",
59
67
  " --tenant-id <id> Settld tenant ID (or SETTLD_TENANT_ID)",
@@ -109,6 +117,8 @@ function parseWalletEnvAssignment(raw) {
109
117
  function parseArgs(argv) {
110
118
  const out = {
111
119
  nonInteractive: false,
120
+ setupMode: null,
121
+ guidedNext: null,
112
122
  host: null,
113
123
  baseUrl: null,
114
124
  tenantId: null,
@@ -149,6 +159,22 @@ function parseArgs(argv) {
149
159
  out.nonInteractive = true;
150
160
  continue;
151
161
  }
162
+ if (arg === "--quick") {
163
+ out.setupMode = "quick";
164
+ continue;
165
+ }
166
+ if (arg === "--advanced") {
167
+ out.setupMode = "advanced";
168
+ continue;
169
+ }
170
+ if (arg === "--guided-next") {
171
+ out.guidedNext = true;
172
+ continue;
173
+ }
174
+ if (arg === "--skip-guided-next") {
175
+ out.guidedNext = false;
176
+ continue;
177
+ }
152
178
  if (arg === "--skip-profile-apply") {
153
179
  out.skipProfileApply = true;
154
180
  continue;
@@ -310,6 +336,9 @@ function parseArgs(argv) {
310
336
  if (out.host && !SUPPORTED_HOSTS.includes(out.host)) {
311
337
  throw new Error(`--host must be one of: ${SUPPORTED_HOSTS.join(", ")}`);
312
338
  }
339
+ if (out.setupMode && !SETUP_MODES.has(out.setupMode)) {
340
+ throw new Error("--quick or --advanced are the supported setup modes");
341
+ }
313
342
  if (!WALLET_MODES.has(out.walletMode)) throw new Error("--wallet-mode must be managed|byo|none");
314
343
  if (!WALLET_PROVIDERS.has(out.walletProvider)) throw new Error(`--wallet-provider must be one of: ${[...WALLET_PROVIDERS].join(", ")}`);
315
344
  if (!WALLET_BOOTSTRAP_MODES.has(out.walletBootstrap)) throw new Error("--wallet-bootstrap must be auto|local|remote");
@@ -865,6 +894,144 @@ function buildHostNextSteps({ host, installedHosts }) {
865
894
  return steps;
866
895
  }
867
896
 
897
+ function runMcpPaidCallProbe({ env, timeoutMs = 45_000 } = {}) {
898
+ const args = [
899
+ path.join("scripts", "mcp", "probe.mjs"),
900
+ "--call",
901
+ "settld.weather_current_paid",
902
+ JSON.stringify({ city: "Chicago", unit: "f" }),
903
+ "--timeout-ms",
904
+ String(timeoutMs)
905
+ ];
906
+ const result = spawnSync(process.execPath, args, {
907
+ cwd: REPO_ROOT,
908
+ env: { ...process.env, ...(env ?? {}) },
909
+ encoding: "utf8",
910
+ timeout: timeoutMs + 5000,
911
+ maxBuffer: 4 * 1024 * 1024,
912
+ stdio: ["ignore", "pipe", "pipe"]
913
+ });
914
+ const stdoutText = String(result.stdout ?? "");
915
+ const stderrText = String(result.stderr ?? "");
916
+ const sawToolError = /"isError"\s*:\s*true/.test(stdoutText);
917
+ const sawToolSuccess = /"isError"\s*:\s*false/.test(stdoutText);
918
+ const ok = Number(result.status) === 0 && sawToolSuccess && !sawToolError;
919
+ return {
920
+ ok,
921
+ exitCode: typeof result.status === "number" ? result.status : 1,
922
+ stdout: stdoutText,
923
+ stderr: stderrText
924
+ };
925
+ }
926
+
927
+ async function runGuidedQuickFlow({
928
+ enabled = false,
929
+ walletMode = "none",
930
+ normalizedBaseUrl,
931
+ tenantId,
932
+ sessionFile,
933
+ sessionCookie = "",
934
+ mergedEnv = {},
935
+ runtimeEnv = process.env,
936
+ stdin = process.stdin,
937
+ stdout = process.stdout,
938
+ runWalletCliImpl = runWalletCli
939
+ } = {}) {
940
+ const summary = {
941
+ enabled: Boolean(enabled),
942
+ ran: false,
943
+ walletFund: null,
944
+ walletBalanceWatch: null,
945
+ firstPaidCall: null,
946
+ warnings: []
947
+ };
948
+ if (!summary.enabled) return summary;
949
+ if (!stdin?.isTTY || !stdout?.isTTY) {
950
+ summary.warnings.push("guided quick flow skipped (non-interactive terminal)");
951
+ return summary;
952
+ }
953
+
954
+ const actionEnv = {
955
+ ...runtimeEnv,
956
+ ...mergedEnv,
957
+ SETTLD_BASE_URL: normalizedBaseUrl,
958
+ SETTLD_TENANT_ID: tenantId,
959
+ ...(sessionCookie ? { SETTLD_SESSION_COOKIE: sessionCookie } : {})
960
+ };
961
+ summary.ran = true;
962
+
963
+ if (walletMode !== "none") {
964
+ try {
965
+ const fundResult = await runWalletCliImpl({
966
+ argv: ["fund", "--open", "--base-url", normalizedBaseUrl, "--tenant-id", tenantId, "--session-file", sessionFile, "--format", "json"],
967
+ env: actionEnv,
968
+ stdin,
969
+ stdout
970
+ });
971
+ summary.walletFund = {
972
+ ok: true,
973
+ method: String(fundResult?.method ?? "").trim() || null
974
+ };
975
+ } catch (err) {
976
+ summary.walletFund = {
977
+ ok: false,
978
+ error: err?.message ?? String(err ?? "")
979
+ };
980
+ summary.warnings.push("wallet funding did not complete during guided flow");
981
+ }
982
+
983
+ try {
984
+ const watchResult = await runWalletCliImpl({
985
+ argv: [
986
+ "balance",
987
+ "--watch",
988
+ "--min-usdc",
989
+ "1",
990
+ "--timeout-seconds",
991
+ "300",
992
+ "--interval-seconds",
993
+ "5",
994
+ "--base-url",
995
+ normalizedBaseUrl,
996
+ "--tenant-id",
997
+ tenantId,
998
+ "--session-file",
999
+ sessionFile,
1000
+ "--format",
1001
+ "json"
1002
+ ],
1003
+ env: actionEnv,
1004
+ stdin,
1005
+ stdout
1006
+ });
1007
+ summary.walletBalanceWatch = {
1008
+ ok: Boolean(watchResult?.ok),
1009
+ satisfied: Boolean(watchResult?.watch?.satisfied)
1010
+ };
1011
+ } catch (err) {
1012
+ summary.walletBalanceWatch = {
1013
+ ok: false,
1014
+ error: err?.message ?? String(err ?? "")
1015
+ };
1016
+ summary.warnings.push("wallet balance watch did not reach target within timeout");
1017
+ }
1018
+ }
1019
+
1020
+ const paidProbe = runMcpPaidCallProbe({ env: actionEnv });
1021
+ if (paidProbe.ok) {
1022
+ summary.firstPaidCall = { ok: true };
1023
+ } else {
1024
+ summary.firstPaidCall = {
1025
+ ok: false,
1026
+ exitCode: paidProbe.exitCode,
1027
+ error: paidProbe.stderr || "paid call returned tool error"
1028
+ };
1029
+ summary.warnings.push("first paid call probe failed");
1030
+ }
1031
+
1032
+ return summary;
1033
+ }
1034
+
868
1035
  function resolveByoWalletEnv({ walletProvider, walletEnvRows, runtimeEnv }) {
869
1036
  const env = {};
870
1037
  for (const row of walletEnvRows ?? []) env[row.key] = row.value;
@@ -1028,16 +1195,21 @@ async function resolveRuntimeConfig({
1028
1195
  runtimeEnv,
1029
1196
  stdin = process.stdin,
1030
1197
  stdout = process.stdout,
1031
- detectInstalledHostsImpl = detectInstalledHosts
1198
+ detectInstalledHostsImpl = detectInstalledHosts,
1199
+ fetchImpl = fetch,
1200
+ runLoginImpl = runLogin,
1201
+ readSavedSessionImpl = readSavedSession
1032
1202
  }) {
1033
1203
  const sessionFile = String(args.sessionFile ?? runtimeEnv.SETTLD_SESSION_FILE ?? defaultSessionPath()).trim();
1034
- const savedSession = await readSavedSession({ sessionPath: sessionFile });
1204
+ const savedSession = await readSavedSessionImpl({ sessionPath: sessionFile });
1035
1205
  const installedHosts = detectInstalledHostsImpl();
1036
1206
  const defaultHost = selectDefaultHost({
1037
1207
  explicitHost: args.host ? String(args.host).toLowerCase() : "",
1038
1208
  installedHosts
1039
1209
  });
1040
1210
  const out = {
1211
+ setupMode: args.setupMode ?? "quick",
1212
+ guidedNext: args.guidedNext,
1041
1213
  host: args.host ?? defaultHost,
1042
1214
  walletMode: args.walletMode,
1043
1215
  baseUrl: String(args.baseUrl ?? runtimeEnv.SETTLD_BASE_URL ?? "").trim(),
@@ -1071,6 +1243,9 @@ async function resolveRuntimeConfig({
1071
1243
  }
1072
1244
 
1073
1245
  if (args.nonInteractive) {
1246
+ if (!out.setupMode) out.setupMode = "quick";
1247
+ if (!SETUP_MODES.has(out.setupMode)) throw new Error("--quick or --advanced are the supported setup modes");
1248
+ if (out.guidedNext === null || out.guidedNext === undefined) out.guidedNext = false;
1074
1249
  if (!SUPPORTED_HOSTS.includes(out.host)) throw new Error(`--host must be one of: ${SUPPORTED_HOSTS.join(", ")}`);
1075
1250
  if (!out.baseUrl) throw new Error("--base-url is required");
1076
1251
  if (!out.tenantId) throw new Error("--tenant-id is required");
@@ -1105,6 +1280,24 @@ async function resolveRuntimeConfig({
1105
1280
  }
1106
1281
  stdout.write("\n");
1107
1282
 
1283
+ if (!out.setupMode || !SETUP_MODES.has(out.setupMode)) {
1284
+ out.setupMode = "quick";
1285
+ }
1286
+ out.setupMode = await promptSelect(
1287
+ rl,
1288
+ stdin,
1289
+ stdout,
1290
+ "Setup mode",
1291
+ [
1292
+ { value: "quick", label: "quick", hint: "Recommended: minimal prompts and guided next steps" },
1293
+ { value: "advanced", label: "advanced", hint: "Full control over all setup options" }
1294
+ ],
1295
+ { defaultValue: out.setupMode, color }
1296
+ );
1297
+ if (out.guidedNext === null || out.guidedNext === undefined) {
1298
+ out.guidedNext = out.setupMode === "quick";
1299
+ }
1300
+
1108
1301
  const hostPromptDefault = out.host && SUPPORTED_HOSTS.includes(out.host) ? out.host : defaultHost;
1109
1302
  const hostOptions = SUPPORTED_HOSTS.map((host) => ({
1110
1303
  value: host,
@@ -1133,68 +1326,100 @@ async function resolveRuntimeConfig({
1133
1326
  { defaultValue: out.walletMode, color }
1134
1327
  );
1135
1328
 
1136
- if (!out.baseUrl) {
1137
- out.baseUrl = await promptLine(rl, "Settld base URL", { defaultValue: "https://api.settld.work" });
1138
- }
1139
- if (!out.tenantId) {
1140
- out.tenantId = await promptLine(rl, "Tenant ID", { defaultValue: "tenant_default" });
1141
- }
1329
+ if (!out.baseUrl) out.baseUrl = DEFAULT_PUBLIC_BASE_URL;
1142
1330
  if (!out.settldApiKey) {
1143
- const canUseSavedSession =
1144
- Boolean(out.sessionCookie) &&
1145
- (!savedSession ||
1146
- (normalizeHttpUrl(out.baseUrl) === normalizeHttpUrl(savedSession?.baseUrl) &&
1147
- String(out.tenantId ?? "").trim() === String(savedSession?.tenantId ?? "").trim()));
1148
- const keyOptions = [];
1149
- if (canUseSavedSession) {
1150
- keyOptions.push({
1151
- value: "session",
1152
- label: "Use saved login session",
1153
- hint: `Reuse ${out.sessionFile} to mint runtime key`
1154
- });
1155
- }
1156
- keyOptions.push(
1157
- { value: "bootstrap", label: "Generate during setup", hint: "Use onboarding bootstrap API key" },
1158
- { value: "manual", label: "Paste existing key", hint: "Use an existing tenant API key" }
1159
- );
1160
- const keyMode = await promptSelect(
1161
- rl,
1162
- stdin,
1163
- stdout,
1164
- "How should setup get your Settld API key?",
1165
- keyOptions,
1166
- { defaultValue: canUseSavedSession ? "session" : "bootstrap", color }
1167
- );
1168
- if (keyMode === "bootstrap") {
1169
- if (!out.bootstrapApiKey) {
1170
- out.bootstrapApiKey = await promptSecretLine(rl, mutableOutput, stdout, "Onboarding bootstrap API key");
1331
+ while (!out.settldApiKey) {
1332
+ const canUseSavedSession =
1333
+ Boolean(out.sessionCookie) &&
1334
+ (!savedSession ||
1335
+ (normalizeHttpUrl(out.baseUrl) === normalizeHttpUrl(savedSession?.baseUrl) &&
1336
+ (!out.tenantId || String(out.tenantId ?? "").trim() === String(savedSession?.tenantId ?? "").trim())));
1337
+ const keyOptions = [];
1338
+ if (canUseSavedSession) {
1339
+ keyOptions.push({
1340
+ value: "session",
1341
+ label: "Use saved login session",
1342
+ hint: `Reuse ${out.sessionFile} to mint runtime key`
1343
+ });
1344
+ } else {
1345
+ keyOptions.push({
1346
+ value: "login",
1347
+ label: "Login / create tenant (recommended)",
1348
+ hint: "OTP sign-in; no API key required"
1349
+ });
1350
+ }
1351
+ keyOptions.push(
1352
+ { value: "bootstrap", label: "Generate during setup", hint: "Use onboarding bootstrap API key" },
1353
+ { value: "manual", label: "Paste existing key", hint: "Use an existing tenant API key" }
1354
+ );
1355
+ const keyMode = await promptSelect(
1356
+ rl,
1357
+ stdin,
1358
+ stdout,
1359
+ "How should setup get your Settld API key?",
1360
+ keyOptions,
1361
+ { defaultValue: canUseSavedSession ? "session" : "login", color }
1362
+ );
1363
+ if (keyMode === "login") {
1364
+ await runLoginImpl({
1365
+ argv: ["--base-url", out.baseUrl, "--session-file", out.sessionFile],
1366
+ stdin,
1367
+ stdout,
1368
+ fetchImpl
1369
+ });
1370
+ const refreshedSession = await readSavedSessionImpl({ sessionPath: out.sessionFile });
1371
+ if (!refreshedSession) throw new Error("login did not produce a saved session");
1372
+ out.baseUrl = String(refreshedSession.baseUrl ?? out.baseUrl).trim() || out.baseUrl;
1373
+ out.tenantId = String(refreshedSession.tenantId ?? out.tenantId).trim();
1374
+ out.sessionCookie = String(refreshedSession.cookie ?? out.sessionCookie).trim();
1375
+ if (savedSession) {
1376
+ savedSession.baseUrl = refreshedSession.baseUrl;
1377
+ savedSession.tenantId = refreshedSession.tenantId;
1378
+ savedSession.cookie = refreshedSession.cookie;
1379
+ }
1380
+ continue;
1171
1381
  }
1172
- if (!out.bootstrapKeyId) {
1173
- out.bootstrapKeyId = await promptLine(rl, "Generated key ID (optional)", { required: false });
1382
+ if (keyMode === "bootstrap") {
1383
+ if (!out.bootstrapApiKey) {
1384
+ out.bootstrapApiKey = await promptSecretLine(rl, mutableOutput, stdout, "Onboarding bootstrap API key");
1385
+ }
1386
+ if (!out.bootstrapKeyId) {
1387
+ out.bootstrapKeyId = await promptLine(rl, "Generated key ID (optional)", { required: false });
1388
+ }
1389
+ if (!out.bootstrapScopes) {
1390
+ out.bootstrapScopes = await promptLine(rl, "Generated key scopes CSV (optional)", { required: false });
1391
+ }
1392
+ break;
1174
1393
  }
1175
- if (!out.bootstrapScopes) {
1176
- out.bootstrapScopes = await promptLine(rl, "Generated key scopes CSV (optional)", { required: false });
1394
+ if (keyMode === "manual") {
1395
+ out.settldApiKey = await promptSecretLine(rl, mutableOutput, stdout, "Settld API key");
1396
+ break;
1177
1397
  }
1178
- } else if (keyMode === "manual") {
1179
- out.settldApiKey = await promptSecretLine(rl, mutableOutput, stdout, "Settld API key");
1180
- } else {
1181
1398
  out.bootstrapApiKey = "";
1399
+ break;
1182
1400
  }
1183
1401
  }
1402
+ if (!out.tenantId) {
1403
+ out.tenantId = await promptLine(rl, "Tenant ID", { defaultValue: "tenant_default" });
1404
+ }
1184
1405
 
1185
1406
  if (out.walletMode === "managed") {
1186
- out.walletBootstrap = await promptSelect(
1187
- rl,
1188
- stdin,
1189
- stdout,
1190
- "Managed wallet bootstrap",
1191
- [
1192
- { value: "auto", label: "auto", hint: "Use local Circle key when present, else remote bootstrap" },
1193
- { value: "local", label: "local", hint: "Always use local Circle API key flow" },
1194
- { value: "remote", label: "remote", hint: "Always use tenant onboarding endpoint" }
1195
- ],
1196
- { defaultValue: out.walletBootstrap || "auto", color }
1197
- );
1407
+ if (out.setupMode === "quick") {
1408
+ out.walletBootstrap = out.walletBootstrap || "auto";
1409
+ } else {
1410
+ out.walletBootstrap = await promptSelect(
1411
+ rl,
1412
+ stdin,
1413
+ stdout,
1414
+ "Managed wallet bootstrap",
1415
+ [
1416
+ { value: "auto", label: "auto", hint: "Use local Circle key when present, else remote bootstrap" },
1417
+ { value: "local", label: "local", hint: "Always use local Circle API key flow" },
1418
+ { value: "remote", label: "remote", hint: "Always use tenant onboarding endpoint" }
1419
+ ],
1420
+ { defaultValue: out.walletBootstrap || "auto", color }
1421
+ );
1422
+ }
1198
1423
  if (out.walletBootstrap === "local" && !out.circleApiKey) {
1199
1424
  out.circleApiKey = await promptSecretLine(rl, mutableOutput, stdout, "Circle API key");
1200
1425
  }
@@ -1220,6 +1445,9 @@ async function resolveRuntimeConfig({
1220
1445
  out.smoke = false;
1221
1446
  out.skipProfileApply = true;
1222
1447
  out.dryRun = true;
1448
+ out.guidedNext = false;
1449
+ } else if (out.setupMode === "quick") {
1450
+ out.profileId = out.profileId || "engineering-spend";
1223
1451
  } else {
1224
1452
  out.preflight = await promptBooleanChoice(
1225
1453
  rl,
@@ -1296,7 +1524,10 @@ export async function runOnboard({
1296
1524
  requestRuntimeBootstrapMcpEnvImpl = requestRuntimeBootstrapMcpEnv,
1297
1525
  requestRemoteWalletBootstrapImpl = requestRemoteWalletBootstrap,
1298
1526
  runPreflightChecksImpl = runPreflightChecks,
1299
- detectInstalledHostsImpl = detectInstalledHosts
1527
+ detectInstalledHostsImpl = detectInstalledHosts,
1528
+ runLoginImpl = runLogin,
1529
+ readSavedSessionImpl = readSavedSession,
1530
+ runWalletCliImpl = runWalletCli
1300
1531
  } = {}) {
1301
1532
  const args = parseArgs(argv);
1302
1533
  if (args.help) {
@@ -1305,7 +1536,7 @@ export async function runOnboard({
1305
1536
  }
1306
1537
 
1307
1538
  const showSteps = args.format !== "json";
1308
- const totalSteps = args.preflightOnly ? 4 : 5;
1539
+ const totalSteps = args.preflightOnly ? 4 : 6;
1309
1540
  let step = 1;
1310
1541
 
1311
1542
  if (showSteps) printStep(stdout, step, totalSteps, "Resolve setup configuration");
@@ -1314,7 +1545,10 @@ export async function runOnboard({
1314
1545
  runtimeEnv,
1315
1546
  stdin,
1316
1547
  stdout,
1317
- detectInstalledHostsImpl
1548
+ detectInstalledHostsImpl,
1549
+ fetchImpl,
1550
+ runLoginImpl,
1551
+ readSavedSessionImpl
1318
1552
  });
1319
1553
  step += 1;
1320
1554
  const normalizedBaseUrl = normalizeHttpUrl(mustString(config.baseUrl, "SETTLD_BASE_URL / --base-url"));
@@ -1453,6 +1687,12 @@ export async function runOnboard({
1453
1687
  lines.push(`Settld: ${normalizedBaseUrl} (tenant=${tenantId})`);
1454
1688
  lines.push(`Wallet mode: ${config.walletMode}`);
1455
1689
  lines.push(`Wallet bootstrap mode: ${walletBootstrapMode}`);
1690
+ if (config.walletMode !== "none") {
1691
+ lines.push("Wallet next steps:");
1692
+ lines.push("- settld wallet status");
1693
+ lines.push("- settld wallet fund --method transfer");
1694
+ lines.push("- settld wallet balance --watch --min-usdc 1");
1695
+ }
1456
1696
  if (args.outEnv) lines.push(`Wrote env file: ${args.outEnv}`);
1457
1697
  if (args.reportPath) lines.push(`Wrote report: ${args.reportPath}`);
1458
1698
  lines.push("");
@@ -1506,9 +1746,27 @@ export async function runOnboard({
1506
1746
  await fs.writeFile(args.outEnv, toEnvFileText(mergedEnv), "utf8");
1507
1747
  }
1508
1748
 
1749
+ if (showSteps) printStep(stdout, step, totalSteps, "Guided next steps");
1750
+ const guided = await runGuidedQuickFlow({
1751
+ enabled: Boolean(config.setupMode === "quick" && config.guidedNext),
1752
+ walletMode: config.walletMode,
1753
+ normalizedBaseUrl,
1754
+ tenantId,
1755
+ sessionFile: config.sessionFile,
1756
+ sessionCookie: config.sessionCookie,
1757
+ mergedEnv,
1758
+ runtimeEnv,
1759
+ stdin,
1760
+ stdout,
1761
+ runWalletCliImpl
1762
+ });
1763
+ step += 1;
1764
+
1509
1765
  if (showSteps) printStep(stdout, step, totalSteps, "Finalize output");
1510
1766
  const payload = {
1511
1767
  ok: true,
1768
+ setupMode: config.setupMode,
1769
+ guided,
1512
1770
  host: config.host,
1513
1771
  wallet: {
1514
1772
  mode: config.walletMode,
@@ -1540,6 +1798,7 @@ export async function runOnboard({
1540
1798
  lines.push("Settld onboard complete.");
1541
1799
  lines.push(`Host: ${config.host}`);
1542
1800
  lines.push(`Settld: ${normalizedBaseUrl} (tenant=${tenantId})`);
1801
+ lines.push(`Setup mode: ${config.setupMode}`);
1543
1802
  lines.push(`Preflight: ${config.preflight ? "passed" : "skipped"}`);
1544
1803
  lines.push(`Wallet mode: ${config.walletMode}`);
1545
1804
  lines.push(`Wallet bootstrap mode: ${walletBootstrapMode}`);
@@ -1547,6 +1806,18 @@ export async function runOnboard({
1547
1806
  if (wallet?.wallets?.escrow?.walletId) lines.push(`Escrow wallet: ${wallet.wallets.escrow.walletId}`);
1548
1807
  if (wallet?.tokenIdUsdc) lines.push(`USDC token id: ${wallet.tokenIdUsdc}`);
1549
1808
  if (args.outEnv) lines.push(`Wrote env file: ${args.outEnv}`);
1809
+ if (guided?.enabled) {
1810
+ lines.push("");
1811
+ lines.push("Guided quick flow:");
1812
+ if (guided.ran) {
1813
+ lines.push(`- wallet fund: ${guided.walletFund?.ok ? "ok" : "not completed"}`);
1814
+ lines.push(`- wallet balance watch: ${guided.walletBalanceWatch?.ok ? "ok" : "not completed"}`);
1815
+ lines.push(`- first paid call: ${guided.firstPaidCall?.ok ? "ok" : "failed"}`);
1816
+ } else {
1817
+ lines.push("- skipped");
1818
+ }
1819
+ for (const warning of guided.warnings ?? []) lines.push(`- warning: ${warning}`);
1820
+ }
1550
1821
  lines.push("");
1551
1822
  lines.push("Combined exports:");
1552
1823
  lines.push(toExportText(mergedEnv));
@@ -1557,6 +1828,14 @@ export async function runOnboard({
1557
1828
  lines.push(`${step}. ${row}`);
1558
1829
  step += 1;
1559
1830
  }
1831
+ if (config.walletMode !== "none") {
1832
+ lines.push(`${step}. Run \`settld wallet status\` to confirm wallet wiring.`);
1833
+ step += 1;
1834
+ lines.push(`${step}. Fund with \`settld wallet fund --method transfer\` (or \`--method card --open\` if hosted links are configured).`);
1835
+ step += 1;
1836
+ lines.push(`${step}. Confirm funds: \`settld wallet balance --watch --min-usdc 1\`.`);
1837
+ step += 1;
1838
+ }
1560
1839
  lines.push(`${step}. Run \`npm run mcp:probe\` for an immediate health check.`);
1561
1840
  stdout.write(`${lines.join("\n")}\n`);
1562
1841
  }
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- if [ ! -x ".vercel-venv/bin/mkdocs" ]; then
5
- echo "MkDocs venv not found; running install step first..."
4
+ if ! python3 -m mkdocs --version >/dev/null 2>&1; then
5
+ echo "MkDocs not found; running install step first..."
6
6
  bash scripts/vercel/install-mkdocs.sh
7
7
  fi
8
8
 
9
- .vercel-venv/bin/mkdocs build --strict --config-file mkdocs.yml
9
+ python3 -m mkdocs build --strict --config-file mkdocs.yml
@@ -5,6 +5,9 @@ set -euo pipefail
5
5
  # - exit 0 => skip deployment
6
6
  # - exit 1 => continue with deployment
7
7
 
8
+ REPO_ROOT="$(git rev-parse --show-toplevel)"
9
+ cd "$REPO_ROOT"
10
+
8
11
  if ! git rev-parse --verify HEAD^ >/dev/null 2>&1; then
9
12
  # No parent commit context available; build to stay safe.
10
13
  exit 1
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- python3 -m venv .vercel-venv
5
- .vercel-venv/bin/python -m pip install --upgrade pip setuptools wheel
6
- .vercel-venv/bin/pip install mkdocs mkdocs-material
4
+ python3 -m pip install --break-system-packages --upgrade pip setuptools wheel
5
+ python3 -m pip install --break-system-packages mkdocs mkdocs-material