@botiverse/raft-daemon 0.63.5 → 0.63.6

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/dist/cli/index.js CHANGED
@@ -956,6 +956,58 @@ function delay(ms) {
956
956
  return new Promise((resolve) => setTimeout(resolve, ms));
957
957
  }
958
958
 
959
+ // src/core/browserHandoff.ts
960
+ import { spawn } from "child_process";
961
+ function canInstallEnterToOpenUrl(input) {
962
+ const tty = input;
963
+ return Boolean(tty?.isTTY === true && typeof tty.on === "function" && typeof tty.off === "function");
964
+ }
965
+ function openUrlInBrowser(url2) {
966
+ const platform = process.platform;
967
+ let command;
968
+ let args;
969
+ if (platform === "darwin") {
970
+ command = "open";
971
+ args = [url2];
972
+ } else if (platform === "win32") {
973
+ command = "cmd";
974
+ args = ["/c", "start", "", url2];
975
+ } else {
976
+ command = "xdg-open";
977
+ args = [url2];
978
+ }
979
+ const child = spawn(command, args, {
980
+ detached: true,
981
+ stdio: "ignore",
982
+ windowsHide: true
983
+ });
984
+ child.on("error", () => {
985
+ });
986
+ child.unref();
987
+ }
988
+ function installEnterToOpenUrl(options) {
989
+ if (!canInstallEnterToOpenUrl(options.input)) return () => {
990
+ };
991
+ const input = options.input;
992
+ const openUrl = options.openUrl ?? openUrlInBrowser;
993
+ let active = true;
994
+ const cleanup = () => {
995
+ if (!active) return;
996
+ active = false;
997
+ input.off("data", onData);
998
+ input.pause?.();
999
+ };
1000
+ const onData = (chunk) => {
1001
+ const text = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
1002
+ if (!text.includes("\n") && !text.includes("\r")) return;
1003
+ cleanup();
1004
+ openUrl(options.url);
1005
+ };
1006
+ input.on("data", onData);
1007
+ input.resume?.();
1008
+ return cleanup;
1009
+ }
1010
+
959
1011
  // src/commands/agent/list.ts
960
1012
  function describeListResult(reason, serverUrl) {
961
1013
  switch (reason) {
@@ -981,15 +1033,25 @@ var agentListCommand = defineCommand(
981
1033
  throw cliError("INVALID_ARG", "--server is required");
982
1034
  }
983
1035
  let userSession;
1036
+ let cleanupEnterToOpen;
984
1037
  try {
985
1038
  userSession = await runDeviceCodeLogin({
986
1039
  serverUrl: options.server,
987
1040
  ...options.clientName ? { clientName: options.clientName } : {},
988
- onUserAction: ({ verificationUri, userCode, expiresInSeconds }) => {
1041
+ onUserAction: ({ verificationUri, verificationUriComplete, userCode, expiresInSeconds }) => {
1042
+ const enterOpensBrowser = canInstallEnterToOpenUrl(ctx.io.stdin);
1043
+ const url2 = verificationUriComplete ?? verificationUri;
989
1044
  ctx.io.stderr.write(
990
- `Open ${verificationUri} in your browser, enter code ${userCode} (expires in ~${Math.max(0, Math.floor(expiresInSeconds / 60))}m).
1045
+ (enterOpensBrowser ? `Press Enter to open the browser authorization URL: ${url2}
1046
+ ` : `Open this browser authorization URL: ${url2}
1047
+ `) + (verificationUriComplete ? ` Code is pre-filled. Approve the login in the browser; this command will continue automatically.
1048
+ ` : ` Enter code ${userCode} and approve the login in the browser; this command will continue automatically.
1049
+ `) + ` Expires in ~${Math.max(0, Math.floor(expiresInSeconds / 60))}m.
991
1050
  `
992
1051
  );
1052
+ if (enterOpensBrowser) {
1053
+ cleanupEnterToOpen = installEnterToOpenUrl({ input: ctx.io.stdin, url: url2 });
1054
+ }
993
1055
  }
994
1056
  });
995
1057
  } catch (err) {
@@ -997,6 +1059,8 @@ var agentListCommand = defineCommand(
997
1059
  throw cliError(err.code, err.message, { cause: err });
998
1060
  }
999
1061
  throw err;
1062
+ } finally {
1063
+ cleanupEnterToOpen?.();
1000
1064
  }
1001
1065
  const res = await undiciFetch(
1002
1066
  `${options.server.replace(/\/+$/, "")}/api/agents/manageable`,
@@ -1091,16 +1155,26 @@ var agentLoginCommand = defineCommand(
1091
1155
  const idempotent = await handleExistingCredential(ctx, options, paths);
1092
1156
  if (idempotent === "handled") return;
1093
1157
  let userSession;
1158
+ let cleanupEnterToOpen;
1094
1159
  try {
1095
1160
  userSession = await runDeviceCodeLogin({
1096
1161
  serverUrl: options.server,
1097
1162
  ...options.clientName ? { clientName: options.clientName } : {},
1098
1163
  onUserAction: (action) => {
1099
- ctx.io.stderr.write(formatVerificationHandoff(action));
1164
+ const enterOpensBrowser = canInstallEnterToOpenUrl(ctx.io.stdin);
1165
+ ctx.io.stderr.write(formatVerificationHandoff(action, { enterOpensBrowser }));
1166
+ if (enterOpensBrowser) {
1167
+ cleanupEnterToOpen = installEnterToOpenUrl({
1168
+ input: ctx.io.stdin,
1169
+ url: action.verificationUriComplete ?? action.verificationUri
1170
+ });
1171
+ }
1100
1172
  }
1101
1173
  });
1102
1174
  } catch (err) {
1103
1175
  throw asCliError(err);
1176
+ } finally {
1177
+ cleanupEnterToOpen?.();
1104
1178
  }
1105
1179
  await mintAndPersist(ctx, options, userSession.accessToken, paths);
1106
1180
  }
@@ -1299,14 +1373,19 @@ Next (if you are the agent): run \`raft manual get raft-cli-overview\`, then use
1299
1373
  `
1300
1374
  );
1301
1375
  }
1302
- function formatVerificationHandoff(action) {
1376
+ function formatVerificationHandoff(action, options) {
1303
1377
  const mins = Math.max(0, Math.floor(action.expiresInSeconds / 60));
1378
+ const url2 = action.verificationUriComplete ?? action.verificationUri;
1379
+ const openLine = options.enterOpensBrowser ? `Press Enter to open the browser authorization URL: ${url2}
1380
+ ` : `Open this browser authorization URL: ${url2}
1381
+ `;
1304
1382
  if (action.verificationUriComplete) {
1305
- return `Open this link to approve (code pre-filled): ${action.verificationUriComplete}
1383
+ return openLine + ` Code is pre-filled. Approve the login in the browser; this command will continue automatically.
1306
1384
  Expires in ~${mins}m.
1307
1385
  `;
1308
1386
  }
1309
- return `Open ${action.verificationUri} in your browser, enter code ${action.userCode} (expires in ~${mins}m).
1387
+ return openLine + ` Enter code ${action.userCode} and approve the login in the browser; this command will continue automatically.
1388
+ Expires in ~${mins}m.
1310
1389
  `;
1311
1390
  }
1312
1391
  function formatStartHandoff(authorization, options, paths) {
@@ -1316,10 +1395,12 @@ function formatStartHandoff(authorization, options, paths) {
1316
1395
  out += `Login started for profile '${paths.profileSlug}'. Ask the user to approve in a browser:
1317
1396
  `;
1318
1397
  if (authorization.verificationUriComplete) {
1319
- out += ` Open this link (code pre-filled): ${authorization.verificationUriComplete}
1398
+ out += ` Browser authorization URL (code pre-filled): ${authorization.verificationUriComplete}
1320
1399
  `;
1321
1400
  } else {
1322
- out += ` Open ${authorization.verificationUri} and enter code ${authorization.userCode}.
1401
+ out += ` Browser authorization URL: ${authorization.verificationUri}
1402
+ `;
1403
+ out += ` Enter code ${authorization.userCode} and approve the login.
1323
1404
  `;
1324
1405
  }
1325
1406
  out += ` Code expires in ~${mins}m.
@@ -1483,6 +1564,72 @@ function makeIsMember(members) {
1483
1564
  return (value) => typeof value === "string" && set2.has(value);
1484
1565
  }
1485
1566
 
1567
+ // ../shared/src/generated/runtimeProviderDisplayNames.ts
1568
+ var RUNTIME_PROVIDER_DISPLAY_NAMES = {
1569
+ "anthropic": "Anthropic",
1570
+ "deepseek": "DeepSeek",
1571
+ "fusecode": "FuseCode",
1572
+ "google": "Google",
1573
+ "openai": "OpenAI",
1574
+ "opencode": "OpenCode",
1575
+ "opencode-go": "OpenCode Go",
1576
+ "openrouter": "OpenRouter"
1577
+ };
1578
+
1579
+ // ../shared/src/runtimeProviderDisplay.ts
1580
+ function getRuntimeProviderDisplayName(providerId) {
1581
+ return RUNTIME_PROVIDER_DISPLAY_NAMES[providerId] ?? humanizeRuntimeProviderSegment(providerId);
1582
+ }
1583
+ function formatRuntimeProviderModelLabel(modelId) {
1584
+ const separatorIndex = modelId.indexOf("/");
1585
+ if (separatorIndex <= 0 || separatorIndex === modelId.length - 1) return modelId;
1586
+ const providerId = modelId.slice(0, separatorIndex);
1587
+ const modelName = modelId.slice(separatorIndex + 1);
1588
+ const providerLabel = getRuntimeProviderDisplayName(providerId);
1589
+ const modelParts = modelName.split("/");
1590
+ const modelLabel = humanizeRuntimeProviderSegment(modelParts[modelParts.length - 1] || modelName);
1591
+ if (modelParts.length === 1) return `${modelLabel} \xB7 ${providerLabel}`;
1592
+ const upstreamLabel = modelParts.slice(0, -1).map(getRuntimeProviderDisplayName).join(" / ");
1593
+ return `${modelLabel} \xB7 ${upstreamLabel} via ${providerLabel}`;
1594
+ }
1595
+ function humanizeRuntimeProviderSegment(value) {
1596
+ return value.replace(/\[(\d+)m\]/gi, "-$1m").split(/[-_/]/).filter(Boolean).map(formatRuntimeProviderLabelToken).join(" ");
1597
+ }
1598
+ function formatRuntimeProviderLabelToken(token) {
1599
+ const normalized = token.toLowerCase();
1600
+ const specialCases = {
1601
+ ai: "AI",
1602
+ api: "API",
1603
+ chatgpt: "ChatGPT",
1604
+ claude: "Claude",
1605
+ codestral: "Codestral",
1606
+ deepseek: "DeepSeek",
1607
+ flash: "Flash",
1608
+ free: "Free",
1609
+ gemini: "Gemini",
1610
+ glm: "GLM",
1611
+ gpt: "GPT",
1612
+ hy3: "HY3",
1613
+ kimi: "Kimi",
1614
+ minimax: "MiniMax",
1615
+ nano: "Nano",
1616
+ nemotron: "Nemotron",
1617
+ omni: "Omni",
1618
+ opus: "Opus",
1619
+ pro: "Pro",
1620
+ sonnet: "Sonnet",
1621
+ super: "Super"
1622
+ };
1623
+ if (specialCases[normalized]) return specialCases[normalized];
1624
+ if (normalized === "b" || normalized === "m") return normalized.toUpperCase();
1625
+ if (/^v\d+(\.\d+)?$/.test(normalized)) return normalized.toUpperCase();
1626
+ if (/^\d+m$/i.test(token)) return token.toUpperCase();
1627
+ if (/^\d+[bk]$/i.test(token)) return token.toUpperCase();
1628
+ if (/^m\d+(\.\d+)?$/i.test(token)) return token.toUpperCase();
1629
+ if (/^\d/.test(token)) return token;
1630
+ return normalized.charAt(0).toUpperCase() + normalized.slice(1);
1631
+ }
1632
+
1486
1633
  // ../shared/src/slockRefs.ts
1487
1634
  var SLOCK_REF_CHANNEL_NAME_PATTERN = String.raw`[\p{L}\p{N}_-]+`;
1488
1635
  var SLOCK_REF_USER_NAME_PATTERN = SLOCK_REF_CHANNEL_NAME_PATTERN;
@@ -15443,11 +15590,36 @@ var integrationApproveAgentLoginOperationSchema = external_exports.object({
15443
15590
  scopes: external_exports.array(external_exports.string().trim().min(1).max(120)).max(64),
15444
15591
  draftHint: draftHintSchema
15445
15592
  });
15593
+ var integrationAppDraftFieldsSchema = external_exports.object({
15594
+ name: external_exports.string().trim().min(1).max(120).optional(),
15595
+ description: external_exports.string().trim().max(1e3).optional(),
15596
+ homepageUrl: external_exports.string().trim().max(2e3).optional(),
15597
+ returnUrl: external_exports.string().trim().max(2e3).optional(),
15598
+ agentManifestUrl: external_exports.string().trim().max(2e3).optional()
15599
+ });
15600
+ var integrationRegisterAppOperationSchema = integrationAppDraftFieldsSchema.extend({
15601
+ type: external_exports.literal("integration:register_app"),
15602
+ name: external_exports.string().trim().min(1).max(120),
15603
+ clientKey: external_exports.string().trim().min(1).max(120),
15604
+ returnUrl: external_exports.string().trim().min(1).max(2e3),
15605
+ scopes: external_exports.array(external_exports.string().trim().min(1).max(120)).max(64).default([]),
15606
+ unsafeDemoUrlOverride: external_exports.boolean().optional(),
15607
+ draftHint: draftHintSchema
15608
+ });
15609
+ var integrationUpdateAppRegistrationOperationSchema = integrationAppDraftFieldsSchema.extend({
15610
+ type: external_exports.literal("integration:update_app_registration"),
15611
+ clientKey: external_exports.string().trim().min(1).max(120),
15612
+ scopes: external_exports.array(external_exports.string().trim().min(1).max(120)).max(64).optional(),
15613
+ unsafeDemoUrlOverride: external_exports.boolean().optional(),
15614
+ draftHint: draftHintSchema
15615
+ });
15446
15616
  var actionCardActionSchema = external_exports.discriminatedUnion("type", [
15447
15617
  channelCreateOperationSchema,
15448
15618
  agentCreateOperationSchema,
15449
15619
  channelAddMemberOperationSchema,
15450
- integrationApproveAgentLoginOperationSchema
15620
+ integrationApproveAgentLoginOperationSchema,
15621
+ integrationRegisterAppOperationSchema,
15622
+ integrationUpdateAppRegistrationOperationSchema
15451
15623
  ]);
15452
15624
  function validateActionCardAction(action) {
15453
15625
  if (action.type === "agent:create") {
@@ -15461,6 +15633,12 @@ function validateActionCardAction(action) {
15461
15633
  return "channel:add_member must include at least one human or agent";
15462
15634
  }
15463
15635
  }
15636
+ if (action.type === "integration:update_app_registration") {
15637
+ const hasMetadataPatch = action.name !== void 0 || action.description !== void 0 || action.homepageUrl !== void 0 || action.returnUrl !== void 0 || action.agentManifestUrl !== void 0 || action.scopes !== void 0;
15638
+ if (!hasMetadataPatch) {
15639
+ return "integration:update_app_registration must include at least one field to update";
15640
+ }
15641
+ }
15464
15642
  return null;
15465
15643
  }
15466
15644
 
@@ -15818,9 +15996,9 @@ var RUNTIME_MODELS = {
15818
15996
  ],
15819
15997
  opencode: [
15820
15998
  { id: "default", label: "Configured Default / Auto", verified: "suggestion_only" },
15821
- { id: "deepseek/deepseek-v4-pro", label: "DeepSeek V4 Pro (OpenCode)", verified: "suggestion_only" },
15822
- { id: "openrouter/anthropic/claude-opus-4.5", label: "Claude Opus 4.5 via OpenRouter", verified: "suggestion_only" },
15823
- { id: "fusecode/opus[1m]", label: "Opus 1M via FuseCode", verified: "suggestion_only" }
15999
+ { id: "deepseek/deepseek-v4-pro", label: formatRuntimeProviderModelLabel("deepseek/deepseek-v4-pro"), verified: "suggestion_only" },
16000
+ { id: "openrouter/anthropic/claude-opus-4.5", label: formatRuntimeProviderModelLabel("openrouter/anthropic/claude-opus-4.5"), verified: "suggestion_only" },
16001
+ { id: "fusecode/opus[1m]", label: formatRuntimeProviderModelLabel("fusecode/opus[1m]"), verified: "suggestion_only" }
15824
16002
  ],
15825
16003
  pi: [
15826
16004
  { id: "default", label: "Configured Default / Auto", verified: "suggestion_only" }
@@ -15854,6 +16032,11 @@ var CONTROLLED_RUNTIME_ENV_KEYS = {
15854
16032
  // this list in sync as new providers are added.
15855
16033
  pi: Object.values(PI_BUILTIN_PROVIDER_ENV_KEYS)
15856
16034
  };
16035
+ var PRO_SEAT_MONTHLY_USD = 10;
16036
+ var PRO_AGENT_SEAT_BLOCK_SIZE = 10;
16037
+ var PRO_AGENT_SEAT_FRACTION = 1 / PRO_AGENT_SEAT_BLOCK_SIZE;
16038
+ var PRO_SEAT_ANNUAL_MONTHLY_USD = 8.8;
16039
+ var PRO_PACK_AGENT_SEATS = PRO_AGENT_SEAT_BLOCK_SIZE;
15857
16040
  var PLAN_CONFIG = {
15858
16041
  free: {
15859
16042
  displayName: "Free",
@@ -15880,9 +16063,9 @@ var PLAN_CONFIG = {
15880
16063
  },
15881
16064
  pro: {
15882
16065
  displayName: "Pro",
15883
- limits: { maxMachines: -1, maxAgents: 10, maxChannels: -1, messageHistoryDays: -1, includedAgents: 10 },
16066
+ limits: { maxMachines: -1, maxAgents: PRO_PACK_AGENT_SEATS, maxChannels: -1, messageHistoryDays: -1, includedAgents: PRO_PACK_AGENT_SEATS },
15884
16067
  comingSoon: false,
15885
- price: 20,
16068
+ price: PRO_SEAT_MONTHLY_USD,
15886
16069
  extraAgentPrice: 0
15887
16070
  }
15888
16071
  };
@@ -15892,8 +16075,8 @@ var DISPLAY_PLAN_CONFIG = {
15892
16075
  displayName: "Pro",
15893
16076
  limits: { maxMachines: -1, maxAgents: -1, maxChannels: -1, messageHistoryDays: -1, includedAgents: -1 },
15894
16077
  comingSoon: false,
15895
- price: 20,
15896
- priceCadence: "/ seat pack / month",
16078
+ price: PRO_SEAT_MONTHLY_USD,
16079
+ priceCadence: "/ seat / month",
15897
16080
  extraAgentPrice: 0,
15898
16081
  displayFeatures: [
15899
16082
  "Everything in Free",
@@ -15903,7 +16086,7 @@ var DISPLAY_PLAN_CONFIG = {
15903
16086
  "More professional features coming soon"
15904
16087
  ],
15905
16088
  displayDescription: "For builders and teams scaling agent collaboration.",
15906
- displayNote: "$17.60 / seat pack / month when billed yearly"
16089
+ displayNote: `$${PRO_SEAT_ANNUAL_MONTHLY_USD.toFixed(2)} / seat / month when billed yearly. Each human uses 1 seat; each agent uses ${PRO_AGENT_SEAT_FRACTION} seat.`
15907
16090
  },
15908
16091
  enterprise: {
15909
16092
  displayName: "Enterprise",
@@ -17237,7 +17420,7 @@ var actionPrepareCommand = defineCommand(
17237
17420
  options: [
17238
17421
  {
17239
17422
  flags: "--target <target>",
17240
- description: "Channel/DM/thread target to post the card. Same format as raft message send: '#channel', 'dm:@peer', '#channel:shortid'"
17423
+ description: "Channel/DM/thread target to post the card. Same format as raft message send: '#channel', 'dm:@peer', '#channel:shortid', 'dm:@peer:shortid'"
17241
17424
  }
17242
17425
  ]
17243
17426
  },
@@ -19103,8 +19286,10 @@ var attachmentUploadCommand = defineCommand(
19103
19286
  form
19104
19287
  );
19105
19288
  if (!res.ok) {
19106
- const code = res.status >= 500 ? "SERVER_5XX" : "UPLOAD_FAILED";
19107
- throw cliError(code, res.error ?? `HTTP ${res.status}`);
19289
+ const code = res.errorCode ?? (res.status >= 500 ? "SERVER_5XX" : "UPLOAD_FAILED");
19290
+ throw cliError(code, res.error ?? `HTTP ${res.status}`, {
19291
+ suggestedNextAction: res.suggestedNextAction ?? void 0
19292
+ });
19108
19293
  }
19109
19294
  const d = res.data;
19110
19295
  writeText(ctx.io, `File uploaded: ${d.filename} (${(d.sizeBytes / 1024).toFixed(1)}KB)
@@ -20525,6 +20710,131 @@ function registerIntegrationEnvCommand(parent, runtimeOptions = {}) {
20525
20710
  registerCliCommand(parent, integrationEnvCommand, runtimeOptions);
20526
20711
  }
20527
20712
 
20713
+ // src/commands/integration/app.ts
20714
+ function normalizeScopes2(raw) {
20715
+ if (!raw || raw.length === 0) return void 0;
20716
+ const scopes = Array.from(new Set(
20717
+ raw.flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean)
20718
+ )).sort();
20719
+ if (scopes.length === 0) {
20720
+ throw cliError("INVALID_ARG", "--scope must include at least one non-empty scope");
20721
+ }
20722
+ return scopes;
20723
+ }
20724
+ function requiredTrimmed(value, flag) {
20725
+ const trimmed = value?.trim() ?? "";
20726
+ if (!trimmed) throw cliError("INVALID_ARG", `${flag} is required`);
20727
+ return trimmed;
20728
+ }
20729
+ function optionalTrimmed(value) {
20730
+ return value?.trim() || void 0;
20731
+ }
20732
+ function formatAppPrepare(data) {
20733
+ const lines = [
20734
+ `Integration app ${data.mode} card prepared`,
20735
+ `client key: ${data.action.clientKey}`,
20736
+ `card: ${data.actionCardMessageId}`,
20737
+ `target: ${data.target}`
20738
+ ];
20739
+ if (data.action.name) lines.push(`name: ${data.action.name}`);
20740
+ if (data.action.homepageUrl) lines.push(`app URL: ${data.action.homepageUrl}`);
20741
+ if (data.action.returnUrl) lines.push(`redirect URL: ${data.action.returnUrl}`);
20742
+ if (data.action.agentManifestUrl) lines.push(`agent manifest: ${data.action.agentManifestUrl}`);
20743
+ if (data.action.scopes) lines.push(`scopes: ${data.action.scopes.length > 0 ? data.action.scopes.join(", ") : "-"}`);
20744
+ if (data.action.unsafeDemoUrlOverride) lines.push("unsafe demo URL override: requested");
20745
+ lines.push("next: ask a server owner/admin to review and execute the action card");
20746
+ lines.push("secret: not stored in the card; after owner/admin execution, the requester agent receives a private one-time handoff");
20747
+ return lines.join("\n");
20748
+ }
20749
+ async function prepareApp(mode, ctx, opts) {
20750
+ const target = requiredTrimmed(opts.target, "--target");
20751
+ const clientKey = requiredTrimmed(opts.clientKey, "--client-key");
20752
+ const scopes = normalizeScopes2([...opts.scope ?? [], ...opts.scopes ?? []]);
20753
+ const agentContext = ctx.loadAgentContext();
20754
+ const client = ctx.createApiClient(agentContext);
20755
+ const body = {
20756
+ mode,
20757
+ target,
20758
+ clientKey,
20759
+ name: optionalTrimmed(opts.name),
20760
+ description: optionalTrimmed(opts.description),
20761
+ homepageUrl: optionalTrimmed(opts.homepageUrl) ?? optionalTrimmed(opts.appUrl),
20762
+ returnUrl: optionalTrimmed(opts.redirectUrl),
20763
+ agentManifestUrl: optionalTrimmed(opts.agentManifestUrl),
20764
+ scopes,
20765
+ unsafeDemoUrlOverride: opts.unsafeDemoUrlOverride === true
20766
+ };
20767
+ if (mode === "register") {
20768
+ requiredTrimmed(body.name, "--name");
20769
+ requiredTrimmed(body.returnUrl, "--redirect-url");
20770
+ }
20771
+ const res = await client.request(
20772
+ "POST",
20773
+ `/internal/agent/${encodeURIComponent(agentContext.agentId)}/integrations/app/prepare`,
20774
+ body
20775
+ );
20776
+ if (!res.ok || !res.data) {
20777
+ const code = res.status >= 500 ? "SERVER_5XX" : "INTEGRATION_APP_PREPARE_FAILED";
20778
+ throw cliError(code, res.error ?? `HTTP ${res.status}`);
20779
+ }
20780
+ if (opts.json) {
20781
+ writeJson(ctx.io, { ok: true, data: res.data });
20782
+ return;
20783
+ }
20784
+ writeText(ctx.io, `${formatAppPrepare(res.data)}
20785
+ `);
20786
+ }
20787
+ var sharedOptions = [
20788
+ { flags: "--client-key <key>", description: "Stable app client key / OAuth client_id to reserve or update" },
20789
+ { flags: "--name <name>", description: "App display name" },
20790
+ { flags: "--redirect-url <url>", description: "OAuth redirect/callback URL" },
20791
+ { flags: "--app-url <url>", description: "App homepage URL" },
20792
+ { flags: "--homepage-url <url>", description: "App homepage URL (alias-friendly explicit name)" },
20793
+ { flags: "--description <text>", description: "App description" },
20794
+ { flags: "--agent-manifest-url <url>", description: "Optional agent behavior manifest URL" },
20795
+ {
20796
+ flags: "--scope <scope>",
20797
+ description: "Requested/displayed scope; can be repeated or comma-separated",
20798
+ parse: (value, previous = []) => {
20799
+ previous.push(value);
20800
+ return previous;
20801
+ }
20802
+ },
20803
+ {
20804
+ flags: "--scopes <scopes>",
20805
+ description: "Requested/displayed scopes; alias for --scope, comma-separated",
20806
+ parse: (value, previous = []) => {
20807
+ previous.push(value);
20808
+ return previous;
20809
+ }
20810
+ },
20811
+ { flags: "--unsafe-demo-url-override", description: "Explicitly mark localhost/private URL use as an unsafe demo override" },
20812
+ { flags: "--target <target>", description: "Channel/DM/thread target to post the human action card" },
20813
+ { flags: "--json", description: "Emit machine-readable JSON" }
20814
+ ];
20815
+ var integrationAppPrepareRegisterCommand = defineCommand(
20816
+ {
20817
+ name: "register",
20818
+ description: "Prepare a third-party app registration action card for a human owner/admin to commit",
20819
+ options: sharedOptions
20820
+ },
20821
+ async (ctx, opts) => prepareApp("register", ctx, opts)
20822
+ );
20823
+ var integrationAppPrepareUpdateCommand = defineCommand(
20824
+ {
20825
+ name: "update",
20826
+ description: "Prepare a third-party app registration update action card for a human owner/admin to commit",
20827
+ options: sharedOptions
20828
+ },
20829
+ async (ctx, opts) => prepareApp("update", ctx, opts)
20830
+ );
20831
+ function registerIntegrationAppCommands(parent, runtimeOptions = {}) {
20832
+ const appCmd = parent.command("app").description("Third-party app registration preparation");
20833
+ const prepareCmd = appCmd.command("prepare").description("Prepare app registration/update action cards");
20834
+ registerCliCommand(prepareCmd, integrationAppPrepareRegisterCommand, runtimeOptions);
20835
+ registerCliCommand(prepareCmd, integrationAppPrepareUpdateCommand, runtimeOptions);
20836
+ }
20837
+
20528
20838
  // src/commands/reminder/_format.ts
20529
20839
  var MODIFY_HINT = "(to modify: snooze/update/cancel; raft reminder --help)";
20530
20840
  function formatReminder(r) {
@@ -20981,6 +21291,7 @@ var integrationCmd = program.command("integration").description("Third-party ser
20981
21291
  registerIntegrationListCommand(integrationCmd);
20982
21292
  registerIntegrationLoginCommand(integrationCmd);
20983
21293
  registerIntegrationEnvCommand(integrationCmd);
21294
+ registerIntegrationAppCommands(integrationCmd);
20984
21295
  var reminderCmd = program.command("reminder").description("Reminder operations");
20985
21296
  registerReminderScheduleCommand(reminderCmd);
20986
21297
  registerReminderListCommand(reminderCmd);
package/dist/core.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  runBundledSlockCli,
12
12
  scanWorkspaceDirectories,
13
13
  subscribeDaemonLogs
14
- } from "./chunk-DZ25KV6L.js";
14
+ } from "./chunk-DUWRNQQE.js";
15
15
  export {
16
16
  DAEMON_CLI_USAGE,
17
17
  DaemonCore,