@base44-preview/cli 0.1.15-pr.630.ab1ebad → 0.1.15-pr.630.b3bc283

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
@@ -49330,9 +49330,9 @@ var require_websocket_server = __commonJS(function(exports, module) {
49330
49330
  });
49331
49331
 
49332
49332
  // ../../node_modules/ws/wrapper.mjs
49333
- var import_stream5, import_extension, import_permessage_deflate, import_receiver, import_sender, import_subprotocol, import_websocket, import_websocket_server, wrapper_default;
49333
+ var import_stream6, import_extension, import_permessage_deflate, import_receiver, import_sender, import_subprotocol, import_websocket, import_websocket_server, wrapper_default;
49334
49334
  var init_wrapper = __esm(() => {
49335
- import_stream5 = __toESM(require_stream5(), 1);
49335
+ import_stream6 = __toESM(require_stream5(), 1);
49336
49336
  import_extension = __toESM(require_extension(), 1);
49337
49337
  import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
49338
49338
  import_receiver = __toESM(require_receiver(), 1);
@@ -142409,7 +142409,7 @@ function parse42(toml, { maxDepth = 1000, integersAsBigInt } = {}) {
142409
142409
  }
142410
142410
  return res;
142411
142411
  }
142412
- async function readFile5(file) {
142412
+ async function readFile6(file) {
142413
142413
  if (isUrlString(file)) {
142414
142414
  file = new URL(file);
142415
142415
  }
@@ -156203,7 +156203,7 @@ ${codeblock}`, options8);
156203
156203
  "\\": "\\"
156204
156204
  };
156205
156205
  KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
156206
- read_file_default = readFile5;
156206
+ read_file_default = readFile6;
156207
156207
  loadConfigFromPackageJson = process.versions.bun ? async function loadConfigFromBunPackageJson(file) {
156208
156208
  const { prettier } = await readBunPackageJson(file);
156209
156209
  return prettier;
@@ -268401,6 +268401,10 @@ async function captureRequestBody(request, options) {
268401
268401
  if (request.body == null) {
268402
268402
  return;
268403
268403
  }
268404
+ if (options.context.__redactBody) {
268405
+ options.context.__requestBody = "[redacted]";
268406
+ return;
268407
+ }
268404
268408
  try {
268405
268409
  const cloned = request.clone();
268406
268410
  const text = await cloned.text();
@@ -269956,7 +269960,7 @@ async function saveBuilderModel(userId, modelId) {
269956
269960
  });
269957
269961
  } catch (error) {
269958
269962
  if (error instanceof HTTPError && error.response.status === 400) {
269959
- throw new InvalidInputError("This account can't pick a builder model yet — enable the PER_USER_BUILDER_MODEL_SELECTION flag for it in PostHog, or the model isn't available in this workspace.");
269963
+ throw new InvalidInputError("This account can't pick a builder model yet, or the model isn't available in this workspace. Ask your workspace admin to enable model selection.");
269960
269964
  }
269961
269965
  throw await ApiError.fromHttpError(error, "saving your model choice");
269962
269966
  }
@@ -270006,7 +270010,7 @@ function getModelCommand() {
270006
270010
  }
270007
270011
 
270008
270012
  // src/cli/commands/builder/shared.ts
270009
- import { mkdir as mkdir3, writeFile as writeFile2 } from "node:fs/promises";
270013
+ import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
270010
270014
  import { basename as basename6, join as join25, relative as relative6, resolve as resolve8 } from "node:path";
270011
270015
 
270012
270016
  // src/cli/commands/code/render.ts
@@ -270155,7 +270159,7 @@ function eventLine(event, elapsedMs, options = {}) {
270155
270159
  return null;
270156
270160
  case "waiting": {
270157
270161
  const what = event.label || toolAlias(event.name);
270158
- return source_default.yellow(`⏸ ${what} — needs your input (answer in the editor)`);
270162
+ return source_default.yellow(`⏸ ${what} — needs your input (${options.waitingHint ?? "answer in the editor"})`);
270159
270163
  }
270160
270164
  case "tool_end": {
270161
270165
  const alias = toolAlias(event.name);
@@ -270204,6 +270208,14 @@ ${indent(shown)}`;
270204
270208
  }
270205
270209
  }
270206
270210
  var FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
270211
+ var SHIMMER = ["·", "✢", "✳", "✶", "✻", "✽"];
270212
+ var SHIMMER_STEP_MS = 120;
270213
+ function shimmer(now = Date.now()) {
270214
+ const period = SHIMMER.length * 2 - 2;
270215
+ const step = Math.floor(now / SHIMMER_STEP_MS) % period;
270216
+ const index = step < SHIMMER.length ? step : period - step;
270217
+ return SHIMMER[index];
270218
+ }
270207
270219
  var MUSINGS = [
270208
270220
  "Shmoozing",
270209
270221
  "Shmoogling",
@@ -270267,7 +270279,7 @@ function createTurnStream(interactive, write = (text) => process.stdout.write(te
270267
270279
  return;
270268
270280
  const lines = [
270269
270281
  ...footer.length ? ["", ...footer] : [],
270270
- source_default.dim(`${FRAMES[frame]} ${statusLabel()}`)
270282
+ running.size === 0 ? `${source_default.magenta(shimmer())} ${source_default.dim(statusLabel())}` : source_default.dim(`${FRAMES[frame]} ${statusLabel()}`)
270271
270283
  ];
270272
270284
  write(lines.join(`
270273
270285
  `));
@@ -270386,7 +270398,8 @@ var ConversationMessageSchema = object({
270386
270398
  name: string2(),
270387
270399
  arguments_string: string2().nullish(),
270388
270400
  status: string2().nullish(),
270389
- results: unknown().nullish()
270401
+ results: unknown().nullish(),
270402
+ waiting_on: object({ kind: string2().nullish() }).nullish()
270390
270403
  })).nullish()
270391
270404
  });
270392
270405
  var FullConversationSchema = object({
@@ -270408,6 +270421,7 @@ async function createWixLaunchedApp(options) {
270408
270421
  try {
270409
270422
  response = await base44Client.post("api/wix/create-app", {
270410
270423
  timeout: false,
270424
+ context: { __redactBody: true },
270411
270425
  json: {
270412
270426
  prompt: options.prompt,
270413
270427
  signed_instance: options.signedInstance,
@@ -270477,6 +270491,25 @@ async function getAppState(appId) {
270477
270491
  }
270478
270492
  return parseOrThrow(AppStateSchema, await response.json(), "app status");
270479
270493
  }
270494
+ async function answerToolCall(options, branchId) {
270495
+ let response;
270496
+ try {
270497
+ response = await getAppClient().post("chat/submit-tool-call-input", {
270498
+ timeout: false,
270499
+ context: { __redactBody: true },
270500
+ searchParams: branchScope(branchId),
270501
+ json: {
270502
+ tool_call_id: options.toolCallId,
270503
+ action: options.action,
270504
+ extra_user_input: options.input ?? {},
270505
+ ...options.messageId ? { message_id: options.messageId } : {}
270506
+ }
270507
+ });
270508
+ } catch (error) {
270509
+ throw await ApiError.fromHttpError(error, "answering the agent");
270510
+ }
270511
+ return parseOrThrow(ChatTurnSchema, await response.json(), "chat turn");
270512
+ }
270480
270513
  async function sendTurn(content, branchId) {
270481
270514
  let response;
270482
270515
  try {
@@ -270531,6 +270564,234 @@ async function getPreviewUrl() {
270531
270564
  return /^https?:\/\//.test(url) ? url : `https://${url}`;
270532
270565
  }
270533
270566
 
270567
+ // src/core/resources/apps/pending.ts
270568
+ var CHOICE_TOOLS = new Set([
270569
+ "ask_clarifying_questions",
270570
+ "ask_plan_questions"
270571
+ ]);
270572
+ var SECRET_TOOLS = new Set(["set_secrets"]);
270573
+ var LIST_CHOICE_TOOLS = {
270574
+ select_payment_provider: {
270575
+ key: "providers",
270576
+ question: "Which payment provider?",
270577
+ answer: "provider"
270578
+ }
270579
+ };
270580
+ var PERMISSION_TOOLS = new Set(["request_agent_tool_permissions"]);
270581
+ var CREDENTIALS_TOOLS = new Set(["register_workspace_connector"]);
270582
+ var BROWSER_TOOLS = new Set([
270583
+ "connect_github_account",
270584
+ "request_oauth_authorization",
270585
+ "configure_psp_credentials",
270586
+ "plaid_connect"
270587
+ ]);
270588
+ var str2 = (v) => typeof v === "string" && v.trim() ? v.trim() : undefined;
270589
+ function parseArgs(raw) {
270590
+ try {
270591
+ const parsed = JSON.parse(raw ?? "");
270592
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
270593
+ } catch {
270594
+ return {};
270595
+ }
270596
+ }
270597
+ function questionsFrom(args) {
270598
+ const raw = Array.isArray(args.questions) ? args.questions : [];
270599
+ return raw.flatMap((q) => {
270600
+ if (!q || typeof q !== "object")
270601
+ return [];
270602
+ const item = q;
270603
+ const question = str2(item.question);
270604
+ if (!question)
270605
+ return [];
270606
+ const options = (Array.isArray(item.options) ? item.options : []).flatMap((o) => {
270607
+ const opt = o;
270608
+ const label = str2(opt?.label);
270609
+ return label ? [{ label, description: str2(opt.description) }] : [];
270610
+ });
270611
+ return [
270612
+ {
270613
+ question,
270614
+ description: str2(item.description),
270615
+ options,
270616
+ multiSelect: item.multi_select === true
270617
+ }
270618
+ ];
270619
+ });
270620
+ }
270621
+ function secretsFrom(args) {
270622
+ const raw = Array.isArray(args.secrets_schema) ? args.secrets_schema : [];
270623
+ return raw.flatMap((s) => {
270624
+ const item = s;
270625
+ const name = str2(item?.secretName) ?? str2(item?.name);
270626
+ return name ? [{ name, description: str2(item.description) }] : [];
270627
+ });
270628
+ }
270629
+ function permissionKey(row) {
270630
+ switch (row.type) {
270631
+ case "entity":
270632
+ return row.entity_name ? `entity:${row.entity_name}` : null;
270633
+ case "backend_function":
270634
+ return row.function_name ? `backend_function:${row.function_name}` : null;
270635
+ case "app_user_connector":
270636
+ return row.connector_id ? `app_user_connector:${row.connector_id}` : null;
270637
+ default:
270638
+ return null;
270639
+ }
270640
+ }
270641
+ function permissionsFrom(args) {
270642
+ const raw = Array.isArray(args.requested_permissions) ? args.requested_permissions : [];
270643
+ return raw.flatMap((r) => {
270644
+ const row = r;
270645
+ const key = permissionKey(row);
270646
+ if (!key)
270647
+ return [];
270648
+ const ops = Array.isArray(row.allowed_operations) ? ` (${row.allowed_operations.join(", ")})` : "";
270649
+ const target = str2(row.entity_name) ?? str2(row.function_name) ?? str2(row.connector_name) ?? key;
270650
+ return [
270651
+ { key, label: `${row.type}: ${target}${ops}`, reason: str2(row.reason) }
270652
+ ];
270653
+ });
270654
+ }
270655
+ function guardFrom(results) {
270656
+ const value = typeof results === "string" ? (() => {
270657
+ try {
270658
+ return JSON.parse(results);
270659
+ } catch {
270660
+ return null;
270661
+ }
270662
+ })() : results;
270663
+ if (!value || typeof value !== "object")
270664
+ return null;
270665
+ const g = value;
270666
+ if (!str2(g.guard))
270667
+ return null;
270668
+ return { title: `${g.guard}: needs your approval`, detail: str2(g.reason) };
270669
+ }
270670
+ function humanize(tool) {
270671
+ return tool.replace(/_/g, " ");
270672
+ }
270673
+ function pendingInputs(messages) {
270674
+ const out = [];
270675
+ for (const message of messages) {
270676
+ for (const call of message.tool_calls ?? []) {
270677
+ if (call.status !== "waiting_for_user_input")
270678
+ continue;
270679
+ const args = parseArgs(call.arguments_string);
270680
+ const base = {
270681
+ toolCallId: call.id,
270682
+ messageId: message.id,
270683
+ tool: call.name
270684
+ };
270685
+ const summary = str2(args.summary);
270686
+ if (CHOICE_TOOLS.has(call.name)) {
270687
+ out.push({
270688
+ ...base,
270689
+ kind: "choice",
270690
+ title: summary ?? "The agent has a few questions",
270691
+ questions: questionsFrom(args)
270692
+ });
270693
+ } else if (SECRET_TOOLS.has(call.name)) {
270694
+ out.push({
270695
+ ...base,
270696
+ kind: "secrets",
270697
+ title: summary ?? "The agent needs secrets",
270698
+ secrets: secretsFrom(args)
270699
+ });
270700
+ } else if (PERMISSION_TOOLS.has(call.name)) {
270701
+ out.push({
270702
+ ...base,
270703
+ kind: "permissions",
270704
+ title: summary ?? "Grant the app's agent these permissions?",
270705
+ detail: str2(args.reason),
270706
+ permissions: permissionsFrom(args)
270707
+ });
270708
+ } else if (LIST_CHOICE_TOOLS[call.name]) {
270709
+ const spec = LIST_CHOICE_TOOLS[call.name];
270710
+ const raw = Array.isArray(args[spec.key]) ? args[spec.key] : [];
270711
+ const options = raw.flatMap((o) => {
270712
+ const label = typeof o === "string" ? o : str2(o?.label);
270713
+ return label ? [{ label }] : [];
270714
+ });
270715
+ out.push({
270716
+ ...base,
270717
+ kind: "choice",
270718
+ title: summary ?? spec.question,
270719
+ detail: str2(args.reason),
270720
+ questions: [{ question: spec.question, options, multiSelect: false }],
270721
+ answerKey: spec.answer
270722
+ });
270723
+ } else if (CREDENTIALS_TOOLS.has(call.name)) {
270724
+ const integration = str2(args.integration_type) ?? "connector";
270725
+ out.push({
270726
+ ...base,
270727
+ kind: "credentials",
270728
+ title: summary ?? `Register ${integration} credentials for this workspace`,
270729
+ detail: str2(args.description),
270730
+ credentials: {
270731
+ integrationType: integration,
270732
+ suggestedName: str2(args.name),
270733
+ scopes: Array.isArray(args.scopes) ? args.scopes.filter((x) => typeof x === "string") : []
270734
+ }
270735
+ });
270736
+ } else if (BROWSER_TOOLS.has(call.name)) {
270737
+ const integration = str2(args.integration_type);
270738
+ out.push({
270739
+ ...base,
270740
+ kind: "browser",
270741
+ title: summary ?? (call.name === "connect_github_account" ? "Connect your GitHub account" : integration ? `Authorize ${integration}` : humanize(call.name)),
270742
+ detail: str2(args.reason),
270743
+ browser: call.name === "connect_github_account" ? { flow: "github" } : {
270744
+ flow: "connector",
270745
+ integrationType: integration,
270746
+ connectorId: str2(args.connector_id),
270747
+ scopes: Array.isArray(args.scopes) ? args.scopes.filter((x) => typeof x === "string") : undefined,
270748
+ forceReconnect: args.force_reconnect === true
270749
+ }
270750
+ });
270751
+ } else if (call.waiting_on?.kind === "choice" || call.waiting_on?.kind === "input") {
270752
+ out.push({
270753
+ ...base,
270754
+ kind: "unknown",
270755
+ title: summary ?? humanize(call.name),
270756
+ detail: str2(args.reason)
270757
+ });
270758
+ } else {
270759
+ const guard = guardFrom(call.results);
270760
+ const integration = str2(args.integration_type);
270761
+ out.push({
270762
+ ...base,
270763
+ kind: "approval",
270764
+ title: guard?.title ?? (integration ? `Enable ${integration}?` : summary ?? `${humanize(call.name)}?`),
270765
+ detail: guard?.detail ?? (integration ? summary : undefined)
270766
+ });
270767
+ }
270768
+ }
270769
+ }
270770
+ return out;
270771
+ }
270772
+ function choiceAnswers(questions, selections, answerKey) {
270773
+ if (answerKey) {
270774
+ const first = selections[0];
270775
+ return { [answerKey]: first?.labels[0] ?? first?.customText ?? "" };
270776
+ }
270777
+ const answers = questions.flatMap((q, index) => {
270778
+ const sel = selections[index];
270779
+ if (!sel || sel.labels.length === 0 && !sel.customText)
270780
+ return [];
270781
+ const answer = { question_index: index };
270782
+ if (q.multiSelect) {
270783
+ if (sel.labels.length)
270784
+ answer.selected_labels = sel.labels;
270785
+ } else if (sel.labels[0]) {
270786
+ answer.selected_label = sel.labels[0];
270787
+ }
270788
+ if (sel.customText)
270789
+ answer.custom_text = sel.customText;
270790
+ return [answer];
270791
+ });
270792
+ return { answers };
270793
+ }
270794
+
270534
270795
  // src/cli/commands/builder/shared.ts
270535
270796
  var APP_NAME_RE = /^[A-Za-z0-9._-]+$/;
270536
270797
  var NAME_STOPWORDS = new Set("a an the and or of for with to in on that this its it my our your me".split(" "));
@@ -270549,32 +270810,12 @@ function inventAppName(prompt) {
270549
270810
  function repoBasename(repoUrl) {
270550
270811
  return repoUrl.replace(/\/+$/, "").replace(/\.git$/, "").split("/").pop() ?? "app";
270551
270812
  }
270552
- function parseWixLaunchUrl(raw) {
270553
- let url;
270554
- try {
270555
- url = new URL(raw.trim());
270556
- } catch {
270557
- throw new InvalidInputError("--wix-launch expects the full launch URL.");
270558
- }
270559
- const fragment = new URLSearchParams(url.hash.replace(/^#/, ""));
270560
- const signedInstance = fragment.get("wix-signed-instance")?.trim();
270561
- if (!signedInstance) {
270562
- throw new InvalidInputError("The launch URL has no #wix-signed-instance — copy the whole URL the funnel printed.");
270563
- }
270564
- const prompt = url.searchParams.get("prompt")?.trim();
270565
- const wixClientId = fragment.get("wix-client-id")?.trim();
270566
- return {
270567
- ...prompt ? { prompt } : {},
270568
- signedInstance,
270569
- ...wixClientId ? { wixClientId } : {}
270570
- };
270571
- }
270572
270813
  async function createAndLinkApp(options) {
270573
270814
  if (options.name && !APP_NAME_RE.test(options.name)) {
270574
270815
  throw new InvalidInputError("The name becomes a directory — letters, digits, dots, dashes and underscores only.");
270575
270816
  }
270576
270817
  const cwd = process.cwd();
270577
- const fallbackName = () => options.importRepo ? repoBasename(options.importRepo) : inventAppName(options.prompt ?? options.wixLaunch?.prompt);
270818
+ const fallbackName = () => options.importRepo ? repoBasename(options.importRepo) : inventAppName(options.prompt);
270578
270819
  const chosenDir = options.path ? resolve8(cwd, options.path) : await isDirEmpty(cwd) ? cwd : undefined;
270579
270820
  const dirBase = chosenDir ? basename6(chosenDir) : undefined;
270580
270821
  const name = options.name ?? (dirBase && APP_NAME_RE.test(dirBase) ? dirBase : fallbackName());
@@ -270586,10 +270827,10 @@ async function createAndLinkApp(options) {
270586
270827
  throw new InvalidInputError(here ? "This directory is already linked to a Base44 app. Run `base44 code` here to keep building it, or pass --path for a new one." : `./${dirName} is already linked to a Base44 app. Pick another name or --path.`);
270587
270828
  }
270588
270829
  let clientCreationId;
270589
- const created = options.wixLaunch ? await createWixLaunchedApp({
270590
- prompt: options.prompt ?? options.wixLaunch.prompt ?? "",
270591
- signedInstance: options.wixLaunch.signedInstance,
270592
- wixClientId: options.wixLaunch.wixClientId
270830
+ const created = options.wixInstance ? await createWixLaunchedApp({
270831
+ prompt: options.prompt ?? "",
270832
+ signedInstance: options.wixInstance.signedInstance,
270833
+ wixClientId: options.wixInstance.wixClientId
270593
270834
  }).then((c) => {
270594
270835
  clientCreationId = c.client_creation_id;
270595
270836
  return c;
@@ -270650,6 +270891,147 @@ async function assertBuilderApp(appId) {
270650
270891
  }
270651
270892
  return state;
270652
270893
  }
270894
+ function pendingSummary(pending) {
270895
+ return pending.map((p) => ({
270896
+ id: p.toolCallId,
270897
+ kind: p.kind,
270898
+ tool: p.tool,
270899
+ title: p.title,
270900
+ ...p.detail ? { detail: p.detail } : {},
270901
+ ...p.questions ? { questions: p.questions } : {},
270902
+ ...p.answerKey ? { answer_key: p.answerKey } : {},
270903
+ ...p.secrets ? { secrets: p.secrets.map((x) => x.name) } : {},
270904
+ ...p.permissions ? { permissions: p.permissions } : {},
270905
+ ...p.browser ? { browser: p.browser } : {}
270906
+ }));
270907
+ }
270908
+ function hasAnswer(f) {
270909
+ return Boolean(f.approve || f.reject || f.skip || f.choose?.length || f.other || f.grant || f.secret?.length || f.input || f.connectorName);
270910
+ }
270911
+ async function secretValue(spec, readStdin) {
270912
+ const eq = spec.indexOf("=");
270913
+ if (eq <= 0) {
270914
+ throw new InvalidInputError(`--secret expects NAME=env:VAR, NAME=file:PATH or NAME=- (got "${spec}").`);
270915
+ }
270916
+ const name = spec.slice(0, eq);
270917
+ const source = spec.slice(eq + 1);
270918
+ if (source === "-")
270919
+ return [name, (await readStdin()).trim()];
270920
+ if (source.startsWith("env:")) {
270921
+ const v = process.env[source.slice(4)];
270922
+ if (!v) {
270923
+ throw new InvalidInputError(`--secret ${name}: environment variable ${source.slice(4)} is empty.`);
270924
+ }
270925
+ return [name, v];
270926
+ }
270927
+ if (source.startsWith("file:")) {
270928
+ return [name, (await readFile4(source.slice(5), "utf8")).trim()];
270929
+ }
270930
+ throw new InvalidInputError(`--secret ${name}: pass the value as env:VAR, file:PATH or - (stdin), never as plain text.`);
270931
+ }
270932
+ async function buildAnswer(pending, f, readStdin) {
270933
+ if (f.reject)
270934
+ return { action: "rejected", input: {} };
270935
+ if (f.input) {
270936
+ try {
270937
+ return {
270938
+ action: "approved",
270939
+ input: JSON.parse(f.input)
270940
+ };
270941
+ } catch {
270942
+ throw new InvalidInputError("--input must be a JSON object.");
270943
+ }
270944
+ }
270945
+ switch (pending.kind) {
270946
+ case "choice": {
270947
+ if (f.skip)
270948
+ return { action: "approved", input: { answers: [] } };
270949
+ const questions = pending.questions ?? [];
270950
+ if (!f.choose?.length && !f.other) {
270951
+ throw new InvalidInputError("This is a question: answer with --choose <label> per question (comma-separate for multi-select), --other <text>, or --skip.");
270952
+ }
270953
+ const selections = questions.map((q, i) => {
270954
+ const raw = f.choose?.[i];
270955
+ const labels = raw ? raw.split(",").map((x) => x.trim()).filter(Boolean) : [];
270956
+ for (const l of labels) {
270957
+ if (!q.options.some((o) => o.label === l)) {
270958
+ throw new InvalidInputError(`"${l}" is not an option for "${q.question}". Options: ${q.options.map((o) => o.label).join(", ")}.`);
270959
+ }
270960
+ }
270961
+ return {
270962
+ labels,
270963
+ ...i === questions.length - 1 && f.other ? { customText: f.other } : {}
270964
+ };
270965
+ });
270966
+ return {
270967
+ action: "approved",
270968
+ input: choiceAnswers(questions, selections, pending.answerKey)
270969
+ };
270970
+ }
270971
+ case "permissions": {
270972
+ if (!f.approve && !f.grant) {
270973
+ throw new InvalidInputError("This asks for permissions: --grant key1,key2 (or --approve for all, --reject).");
270974
+ }
270975
+ const all = (pending.permissions ?? []).map((p) => p.key);
270976
+ const keys = f.grant ? f.grant.split(",").map((x) => x.trim()).filter(Boolean) : all;
270977
+ for (const k of keys) {
270978
+ if (!all.includes(k)) {
270979
+ throw new InvalidInputError(`Unknown permission key "${k}". Keys: ${all.join(", ")}.`);
270980
+ }
270981
+ }
270982
+ return { action: "approved", input: { approved_permission_keys: keys } };
270983
+ }
270984
+ case "secrets": {
270985
+ const names = (pending.secrets ?? []).map((x) => x.name);
270986
+ if (!f.secret?.length) {
270987
+ throw new InvalidInputError(`This asks for secrets: --secret NAME=env:VAR for each of ${names.join(", ")}.`);
270988
+ }
270989
+ const values = {};
270990
+ for (const spec of f.secret) {
270991
+ const [name, value] = await secretValue(spec, readStdin);
270992
+ if (!names.includes(name)) {
270993
+ throw new InvalidInputError(`"${name}" is not one of the requested secrets: ${names.join(", ")}.`);
270994
+ }
270995
+ values[name] = value;
270996
+ }
270997
+ const missing = names.filter((n) => !(n in values));
270998
+ if (missing.length) {
270999
+ throw new InvalidInputError(`Missing --secret for: ${missing.join(", ")}.`);
271000
+ }
271001
+ return { action: "approved", input: { secrets: values } };
271002
+ }
271003
+ case "credentials": {
271004
+ const name = f.connectorName ?? pending.credentials?.suggestedName;
271005
+ if (!name) {
271006
+ throw new InvalidInputError("This registers a workspace connector: --connector-name <name> [--client-id <id> --client-secret env:VAR] (omit both to use Base44's credentials).");
271007
+ }
271008
+ const scopes = pending.credentials?.scopes ?? [];
271009
+ if (!f.clientId && !f.clientSecret) {
271010
+ return {
271011
+ action: "approved",
271012
+ input: { name, credential_source: "base44", scopes }
271013
+ };
271014
+ }
271015
+ if (!f.clientId || !f.clientSecret) {
271016
+ throw new InvalidInputError("Own credentials need both --client-id and --client-secret.");
271017
+ }
271018
+ const [, secret] = await secretValue(`client_secret=${f.clientSecret}`, readStdin);
271019
+ return {
271020
+ action: "approved",
271021
+ input: { name, client_id: f.clientId, client_secret: secret, scopes }
271022
+ };
271023
+ }
271024
+ case "browser":
271025
+ throw new InvalidInputError("This step needs a browser: finish the authorization in the editor (or run `base44 code`, which opens the link and waits), then answer with --approve.");
271026
+ case "unknown":
271027
+ throw new InvalidInputError("This question needs the editor — answer it there, or --reject.");
271028
+ default:
271029
+ if (!f.approve) {
271030
+ throw new InvalidInputError("This is an approval: --approve or --reject.");
271031
+ }
271032
+ return { action: "approved", input: {} };
271033
+ }
271034
+ }
270653
271035
  function nextStepsLines(app) {
270654
271036
  const cd = app.here ? "" : `cd ${app.dirName} && `;
270655
271037
  return [
@@ -270804,7 +271186,8 @@ function diffConversation(state, messages) {
270804
271186
  kind: "waiting",
270805
271187
  id: tool.id,
270806
271188
  name: tool.name,
270807
- label: labelTense(meta.label, "running")
271189
+ label: labelTense(meta.label, "running"),
271190
+ pending: pendingInputs([message]).find((p) => p.toolCallId === tool.id)
270808
271191
  });
270809
271192
  }
270810
271193
  if (TOOL_SETTLED.has(status) && !progress.settledTools.has(tool.id)) {
@@ -270892,6 +271275,228 @@ async function streamConversationUntilSettled(onEvent, options = {}) {
270892
271275
  return "timeout";
270893
271276
  }
270894
271277
 
271278
+ // src/cli/commands/code/session-engine.ts
271279
+ var POLL_MS = 1000;
271280
+ function isConnectionDrop(error) {
271281
+ const status = error instanceof ApiError ? error.statusCode : undefined;
271282
+ if (status === 502 || status === 503 || status === 504)
271283
+ return true;
271284
+ if (status != null)
271285
+ return false;
271286
+ const text = [
271287
+ error instanceof Error ? error.message : String(error),
271288
+ error instanceof Error ? String(error.cause ?? "") : ""
271289
+ ].join(" ");
271290
+ return /timeout|gateway|fetch failed|ECONNRESET|ECONNREFUSED|socket hang up|network|aborted|UND_ERR/i.test(text);
271291
+ }
271292
+ function createSessionEngine(options) {
271293
+ const running = new Map;
271294
+ const diffState = newStreamState();
271295
+ let stopped = false;
271296
+ let polling = false;
271297
+ let pollStartedAt = 0;
271298
+ let timer = null;
271299
+ let sendsInFlight = 0;
271300
+ let activeTurnId = null;
271301
+ let turnStartedAt = null;
271302
+ let pendingSubmitAt = null;
271303
+ let lastTurnMs = null;
271304
+ let lastTurnOk = true;
271305
+ let settledCount = 0;
271306
+ let awaitingTurn = options.awaitingTurnLabel ?? null;
271307
+ const awaitingSince = Date.now();
271308
+ let lastEventAt = Date.now();
271309
+ let pending = [];
271310
+ const answered = new Set;
271311
+ const answer = (p, action, input = {}) => {
271312
+ answered.add(p.toolCallId);
271313
+ pending = pending.filter((x) => x.toolCallId !== p.toolCallId);
271314
+ const verb = action === "rejected" ? source_default.red("✗ rejected") : Object.keys(input).length ? source_default.green("→ answered") : source_default.green("✓ approved");
271315
+ options.onLine(`${verb} ${source_default.dim("—")} ${p.title}`);
271316
+ pendingSubmitAt = Date.now();
271317
+ sendsInFlight++;
271318
+ answerToolCall({ toolCallId: p.toolCallId, messageId: p.messageId, action, input }, options.branchId).catch((error) => {
271319
+ if (isConnectionDrop(error) && (turnStartedAt != null || pendingSubmitAt == null)) {
271320
+ return;
271321
+ }
271322
+ answered.delete(p.toolCallId);
271323
+ pendingSubmitAt = null;
271324
+ options.onLine(source_default.red(`✗ answer failed: ${error instanceof Error ? error.message : String(error)}`));
271325
+ }).finally(() => {
271326
+ sendsInFlight--;
271327
+ });
271328
+ };
271329
+ const submit = (raw) => {
271330
+ const typed = raw.trim();
271331
+ if (!typed)
271332
+ return;
271333
+ const text = typed;
271334
+ options.onLine(`${source_default.cyan("❯")} ${source_default.bold(typed)}`);
271335
+ pendingSubmitAt = Date.now();
271336
+ const submitTurnId = activeTurnId;
271337
+ sendsInFlight++;
271338
+ sendTurn(text, options.branchId).then((turn) => {
271339
+ if (turn.queued) {
271340
+ options.onLine(source_default.dim("· queued — runs after the current turn"));
271341
+ }
271342
+ }).catch((error) => {
271343
+ const delivered = activeTurnId !== submitTurnId || turnStartedAt != null || pendingSubmitAt == null;
271344
+ if (isConnectionDrop(error) && delivered)
271345
+ return;
271346
+ pendingSubmitAt = null;
271347
+ const message = error instanceof Error ? error.message : String(error);
271348
+ options.onLine(source_default.red(`✗ send failed: ${message}`));
271349
+ }).finally(() => {
271350
+ sendsInFlight--;
271351
+ });
271352
+ };
271353
+ const poll = async (prime) => {
271354
+ const STUCK_POLL_MS = 45000;
271355
+ if (polling && Date.now() - pollStartedAt < STUCK_POLL_MS)
271356
+ return;
271357
+ polling = true;
271358
+ pollStartedAt = Date.now();
271359
+ try {
271360
+ let messages;
271361
+ try {
271362
+ messages = await getFullConversation(30, options.branchId);
271363
+ } catch {
271364
+ return;
271365
+ }
271366
+ const events = diffConversation(diffState, messages);
271367
+ const waiting = pendingInputs(messages);
271368
+ for (const id of answered) {
271369
+ if (!waiting.some((w) => w.toolCallId === id))
271370
+ answered.delete(id);
271371
+ }
271372
+ pending = waiting.filter((w) => !answered.has(w.toolCallId));
271373
+ if (!prime) {
271374
+ for (const event of events) {
271375
+ if (event.kind === "tool_start") {
271376
+ const startedAt = Date.now();
271377
+ running.set(event.id, {
271378
+ alias: toolAlias(event.name),
271379
+ label: event.label,
271380
+ summary: event.summary,
271381
+ startedAt
271382
+ });
271383
+ options.onLine({ running: event, startedAt });
271384
+ continue;
271385
+ }
271386
+ if (event.kind === "tool_end") {
271387
+ const started = running.get(event.id)?.startedAt;
271388
+ running.delete(event.id);
271389
+ lastEventAt = Date.now();
271390
+ options.onLine({
271391
+ event,
271392
+ elapsedMs: started != null ? Date.now() - started : undefined
271393
+ });
271394
+ continue;
271395
+ }
271396
+ if (event.kind === "waiting" && answered.has(event.id))
271397
+ continue;
271398
+ const line = eventLine(event, undefined, {
271399
+ waitingHint: "answer in the card below"
271400
+ });
271401
+ if (line != null) {
271402
+ lastEventAt = Date.now();
271403
+ options.onLine(line);
271404
+ }
271405
+ }
271406
+ }
271407
+ const turn = newestUserTurn(messages);
271408
+ if (!turn)
271409
+ return;
271410
+ const kickoffDetection = awaitingTurn != null && activeTurnId === null;
271411
+ awaitingTurn = null;
271412
+ if (turn.id !== activeTurnId) {
271413
+ activeTurnId = turn.id;
271414
+ if (!turn.settled) {
271415
+ turnStartedAt = pendingSubmitAt ?? (kickoffDetection ? awaitingSince : Date.now());
271416
+ pendingSubmitAt = null;
271417
+ running.clear();
271418
+ } else if (prime) {
271419
+ turnStartedAt = null;
271420
+ }
271421
+ }
271422
+ if (turn.settled && turnStartedAt != null && turn.id === activeTurnId) {
271423
+ const durationMs = Date.now() - turnStartedAt;
271424
+ turnStartedAt = null;
271425
+ running.clear();
271426
+ lastTurnMs = durationMs;
271427
+ const ok = !turn.backendStatus?.startsWith("error");
271428
+ lastTurnOk = ok;
271429
+ options.onLine(ok ? source_default.dim(`— turn finished · ${formatDuration2(durationMs)}`) : source_default.red(turn.backendStatus === "error_paywall" ? `— the workspace is out of credits; nothing ran · ${formatDuration2(durationMs)}` : `— turn failed (${turn.backendStatus ?? "unknown"}) · ${formatDuration2(durationMs)}`));
271430
+ const info = {
271431
+ turnIndex: settledCount++,
271432
+ ok,
271433
+ backendStatus: turn.backendStatus,
271434
+ durationMs
271435
+ };
271436
+ try {
271437
+ await options.onTurnSettled?.(info);
271438
+ } catch {}
271439
+ }
271440
+ } finally {
271441
+ polling = false;
271442
+ }
271443
+ };
271444
+ return {
271445
+ async start(primeFirstPoll) {
271446
+ await poll(primeFirstPoll);
271447
+ timer = setInterval(() => {
271448
+ if (!stopped)
271449
+ poll(false);
271450
+ }, POLL_MS);
271451
+ timer.unref?.();
271452
+ },
271453
+ stop() {
271454
+ stopped = true;
271455
+ if (timer)
271456
+ clearInterval(timer);
271457
+ },
271458
+ stopTurn() {
271459
+ if (turnStartedAt == null && sendsInFlight === 0 && pendingSubmitAt == null)
271460
+ return;
271461
+ options.onLine(source_default.dim("· stopping…"));
271462
+ stopTurn(options.branchId).catch((error) => {
271463
+ options.onLine(source_default.red(` stop failed: ${error instanceof Error ? error.message : String(error)}`));
271464
+ });
271465
+ },
271466
+ submit,
271467
+ answer,
271468
+ status() {
271469
+ let phase = "idle";
271470
+ if (awaitingTurn != null)
271471
+ phase = "awaiting";
271472
+ else if (turnStartedAt != null)
271473
+ phase = "running";
271474
+ else if (sendsInFlight > 0 || pendingSubmitAt != null)
271475
+ phase = "sending";
271476
+ let runningTool = null;
271477
+ if (running.size > 0) {
271478
+ const newest = [...running.values()].at(-1);
271479
+ runningTool = { ...newest, others: running.size - 1 };
271480
+ }
271481
+ return {
271482
+ phase,
271483
+ awaitingLabel: awaitingTurn ?? undefined,
271484
+ idleHint: options.idleHint,
271485
+ quietForMs: Date.now() - lastEventAt,
271486
+ awaitingSince,
271487
+ turnStartedAt,
271488
+ runningTool,
271489
+ lastTurnMs,
271490
+ lastTurnOk,
271491
+ pending
271492
+ };
271493
+ },
271494
+ turnRunning() {
271495
+ return turnStartedAt != null;
271496
+ }
271497
+ };
271498
+ }
271499
+
270895
271500
  // src/cli/commands/builder/send.ts
270896
271501
  function lastAssistantReply(turn) {
270897
271502
  const messages = turn.conversation?.messages ?? [];
@@ -270907,70 +271512,183 @@ function ndjsonWriter() {
270907
271512
  return (record) => process.stdout.write(`${JSON.stringify(record)}
270908
271513
  `);
270909
271514
  }
271515
+ async function readStdin2() {
271516
+ const chunks = [];
271517
+ for await (const chunk of process.stdin)
271518
+ chunks.push(chunk);
271519
+ return Buffer.concat(chunks).toString("utf8");
271520
+ }
271521
+ function turnResult(turn, pending) {
271522
+ if (turn.queued)
271523
+ return { queued: true };
271524
+ const base = {
271525
+ status: pending.length ? "waiting" : turn.status?.state ?? "ready",
271526
+ error_source: turn.status?.error_source ?? null,
271527
+ reply: lastAssistantReply(turn) ?? null
271528
+ };
271529
+ return pending.length ? { ...base, pending: pendingSummary(pending) } : base;
271530
+ }
271531
+ async function applyPolicy(pending, options, branchId, onEvent) {
271532
+ let current = pending;
271533
+ for (let round = 0;round < 10 && current.length; round++) {
271534
+ const target = current.find((p) => options.autoApprove && (p.kind === "approval" || p.kind === "permissions") || options.skipQuestions && p.kind === "choice");
271535
+ if (!target)
271536
+ break;
271537
+ const input = target.kind === "permissions" ? {
271538
+ approved_permission_keys: (target.permissions ?? []).map((p) => p.key)
271539
+ } : target.kind === "choice" ? { answers: [] } : {};
271540
+ await streamConversationDuring(() => answerToolCall({
271541
+ toolCallId: target.toolCallId,
271542
+ messageId: target.messageId,
271543
+ action: "approved",
271544
+ input
271545
+ }, branchId), onEvent, { branchId });
271546
+ current = pendingInputs(await getFullConversation(30, branchId));
271547
+ }
271548
+ return current;
271549
+ }
270910
271550
  async function sendAction(ctx, message, options) {
270911
271551
  if (options.streamJson && ctx.jsonMode) {
270912
271552
  throw new InvalidInputError("--stream-json and --json are exclusive.");
270913
271553
  }
271554
+ const answering = hasAnswer(options);
271555
+ if (answering && message) {
271556
+ throw new InvalidInputError("Either send a message or answer the pending question (--approve / --choose / …), not both.");
271557
+ }
271558
+ if (!answering && !message) {
271559
+ throw new InvalidInputError('Send a message ("<message>") or answer what the agent asked (--approve, --reject, --choose, --grant, --secret, --skip, --input).');
271560
+ }
270914
271561
  if (ctx.app)
270915
271562
  await assertBuilderApp(ctx.app.id);
270916
271563
  const branchId = await resolveBranchId(ctx);
271564
+ const pendingBefore = pendingInputs(await getFullConversation(30, branchId).catch(() => []));
271565
+ let start;
271566
+ if (answering) {
271567
+ if (pendingBefore.length === 0) {
271568
+ throw new InvalidInputError("Nothing is waiting for an answer — send a message instead.");
271569
+ }
271570
+ const target = options.id ? pendingBefore.find((p) => p.toolCallId === options.id) : pendingBefore.length === 1 ? pendingBefore[0] : undefined;
271571
+ if (!target) {
271572
+ throw new InvalidInputError(options.id ? `No pending call with id ${options.id}. Pending: ${pendingBefore.map((p) => p.toolCallId).join(", ")}.` : `Several calls are waiting — pick one with --id: ${pendingBefore.map((p) => `${p.toolCallId} (${p.kind}: ${p.title})`).join("; ")}.`);
271573
+ }
271574
+ const answer = await buildAnswer(target, options, readStdin2);
271575
+ start = () => answerToolCall({
271576
+ toolCallId: target.toolCallId,
271577
+ messageId: target.messageId,
271578
+ action: answer.action,
271579
+ input: answer.input
271580
+ }, branchId);
271581
+ } else {
271582
+ if (pendingBefore.length) {
271583
+ const record = {
271584
+ status: "waiting",
271585
+ pending: pendingSummary(pendingBefore)
271586
+ };
271587
+ if (options.streamJson) {
271588
+ ndjsonWriter()({ type: "result", ...record });
271589
+ return {};
271590
+ }
271591
+ if (ctx.jsonMode)
271592
+ return { stdout: `${JSON.stringify(record)}
271593
+ ` };
271594
+ throw new InvalidInputError(`The agent is waiting on you before it can take a message: ${pendingBefore.map((p) => `${p.title} (${p.kind})`).join("; ")}. Answer with --approve / --choose / --grant / --secret, or --reject.`);
271595
+ }
271596
+ const text = message;
271597
+ start = () => sendTurn(text, branchId);
271598
+ }
271599
+ const startOrRecover = async () => {
271600
+ try {
271601
+ return await start();
271602
+ } catch (error) {
271603
+ if (!isConnectionDrop(error))
271604
+ throw error;
271605
+ const settled = await streamConversationUntilSettled(() => {
271606
+ return;
271607
+ }, {
271608
+ branchId,
271609
+ timeoutMs: 20 * 60000
271610
+ });
271611
+ const state = await getAppState(ctx.app?.id);
271612
+ return {
271613
+ status: {
271614
+ state: settled === "timeout" ? "processing" : state.status?.state ?? "ready",
271615
+ error_source: state.status?.error_source ?? null
271616
+ },
271617
+ conversation: {
271618
+ messages: (await getFullConversation(5, branchId).catch(() => [])).filter((m) => !m.hidden).map((m) => ({ role: m.role, content: m.content }))
271619
+ }
271620
+ };
271621
+ }
271622
+ };
271623
+ const finish = async (turn, onEvent) => {
271624
+ let pending = turn.queued ? [] : pendingInputs(await getFullConversation(30, branchId).catch(() => []));
271625
+ if (pending.length && (options.autoApprove || options.skipQuestions)) {
271626
+ pending = await applyPolicy(pending, options, branchId, onEvent);
271627
+ }
271628
+ return turnResult(turn, pending);
271629
+ };
270917
271630
  if (options.streamJson) {
270918
271631
  const write = ndjsonWriter();
270919
- const turn = await streamConversationDuring(() => sendTurn(message, branchId), ({ kind, ...event }) => write({ type: kind, ...event }), { branchId });
270920
- write({
270921
- type: "result",
270922
- queued: turn.queued === true,
270923
- status: turn.status?.state ?? "ready",
270924
- error_source: turn.status?.error_source ?? null,
270925
- reply: lastAssistantReply(turn) ?? null
271632
+ const onEvent = ({ kind, ...event }) => write({ type: kind, ...event });
271633
+ const turn = await streamConversationDuring(startOrRecover, onEvent, {
271634
+ branchId
270926
271635
  });
271636
+ const result = await finish(turn, onEvent);
271637
+ write({ type: "result", queued: result.queued === true, ...result });
270927
271638
  return {};
270928
271639
  }
270929
271640
  if (ctx.jsonMode) {
270930
- const turn = await ctx.runTask("Agent working (a turn can take minutes)", () => sendTurn(message, branchId));
270931
- if (turn.queued)
270932
- return { stdout: `${JSON.stringify({ queued: true })}
270933
- ` };
271641
+ const turn = await ctx.runTask("Agent working (a turn can take minutes)", startOrRecover);
270934
271642
  return {
270935
- stdout: `${JSON.stringify({
270936
- status: turn.status?.state ?? "ready",
270937
- error_source: turn.status?.error_source ?? null,
270938
- reply: lastAssistantReply(turn) ?? null
270939
- })}
271643
+ stdout: `${JSON.stringify(await finish(turn, () => {
271644
+ return;
271645
+ }))}
270940
271646
  `
270941
271647
  };
270942
271648
  }
270943
271649
  const stream = createTurnStream(process.stdout.isTTY === true, undefined, {
270944
271650
  verbose: options.verbose
270945
271651
  });
270946
- let turn;
271652
+ let result;
270947
271653
  try {
270948
- turn = await streamConversationDuring(() => sendTurn(message, branchId), stream.onEvent, { branchId });
271654
+ const turn = await streamConversationDuring(startOrRecover, stream.onEvent, {
271655
+ branchId
271656
+ });
271657
+ result = await finish(turn, stream.onEvent);
270949
271658
  } finally {
270950
271659
  stream.stop();
270951
271660
  }
270952
- if (turn.queued) {
271661
+ if (result.queued === true) {
270953
271662
  return {
270954
271663
  outroMessage: "The agent is busy with an earlier message — yours was queued and runs next."
270955
271664
  };
270956
271665
  }
270957
- if (turn.status?.state === "error") {
271666
+ if (result.status === "waiting") {
271667
+ for (const p of result.pending) {
271668
+ ctx.log.message(` ⏸ ${p.title} (${p.kind})`);
271669
+ }
270958
271670
  return {
270959
- outroMessage: `Turn failed (${turn.status.error_source ?? "unknown"}) see the editor for details.`
271671
+ outroMessage: "The agent is waiting on you. Answer with `base44 builder send --approve` (or --choose, --grant, --secret, --reject), or open `base44 code`."
271672
+ };
271673
+ }
271674
+ if (result.status === "error") {
271675
+ return {
271676
+ outroMessage: result.error_source === "paywall" ? "The workspace is out of credits — nothing ran." : `Turn failed (${result.error_source ?? "unknown"}) — see the editor for details.`
270960
271677
  };
270961
271678
  }
270962
271679
  return { outroMessage: "Turn finished." };
270963
271680
  }
271681
+ var collect = (v, acc = []) => [...acc, v];
270964
271682
  function getSendCommand() {
270965
271683
  const command = new Base44Command("send", { supportsBranch: true });
270966
- command.description("Send the agent one message and stream the turn until it finishes").argument("<message>", "What you want the agent to do").option("--verbose", "Show every tool result in full (no folding)").option("--stream-json", "Emit each stream event as a JSON line as it happens, then a final result line").action(sendAction);
271684
+ command.description('Send the agent one message and stream the turn until it finishes — or answer what it asked (--approve, --choose, …). A result with status "waiting" lists what the agent needs; the next send answers it.').argument("[message]", "What you want the agent to do").option("--approve", "Approve the pending call (permissions: grant all)").option("--reject", "Reject the pending call").option("--skip", "Skip the pending questions; the agent decides").option("--choose <label>", "Answer a question by option label; repeat per question, comma-separate for multi-select", collect).option("--other <text>", "Free-text answer for the last question").option("--grant <keys>", "Permission keys to grant, comma-separated").option("--secret <NAME=source>", "A requested secret from env:VAR, file:PATH or - (stdin); repeat per secret", collect).option("--connector-name <name>", "Register a workspace connector under this name (Base44's credentials unless --client-id/--client-secret are given)").option("--client-id <id>", "Your own OAuth app's client id").option("--client-secret <source>", "Your own OAuth app's client secret from env:VAR, file:PATH or - (stdin)").option("--input <json>", "Raw extra_user_input for the pending call").option("--id <tool-call-id>", "Which pending call to answer when several wait").option("--auto-approve", "Policy: approve approval-kind pauses (never secrets or browser steps)").option("--skip-questions", "Policy: skip clarifying questions; the agent decides").option("--verbose", "Show every tool result in full (no folding)").option("--stream-json", "Emit each stream event as a JSON line as it happens, then a final result line").action(sendAction);
270967
271685
  return command;
270968
271686
  }
270969
271687
 
270970
271688
  // src/cli/commands/builder/new.ts
270971
271689
  var POLL_TIMEOUT_MS = 20 * 60000;
270972
271690
  var MODES = ["direct", "fork", "copy"];
270973
- async function readStdin2() {
271691
+ async function readStdin3() {
270974
271692
  const chunks = [];
270975
271693
  for await (const chunk of process.stdin)
270976
271694
  chunks.push(chunk);
@@ -270983,15 +271701,22 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
270983
271701
  if ((options.mode || options.repoName || options.fromBranch) && !options.import) {
270984
271702
  throw new InvalidInputError("--mode, --repo-name and --from-branch apply only with --import <repo>.");
270985
271703
  }
270986
- if (options.wixLaunch && options.import) {
270987
- throw new InvalidInputError("--wix-launch and --import are exclusive.");
271704
+ if (options.wixInstance && options.import) {
271705
+ throw new InvalidInputError("--wix-instance and --import are exclusive.");
271706
+ }
271707
+ if (options.wixClientId && !options.wixInstance) {
271708
+ throw new InvalidInputError("--wix-client-id applies only with --wix-instance.");
271709
+ }
271710
+ const signedInstance = options.wixInstance ? (options.wixInstance === "-" ? await readStdin3() : options.wixInstance).trim() : undefined;
271711
+ if (options.wixInstance && !signedInstance) {
271712
+ throw new InvalidInputError("--wix-instance is empty.");
270988
271713
  }
270989
- const wixLaunch = options.wixLaunch ? parseWixLaunchUrl(options.wixLaunch === "-" ? await readStdin2() : options.wixLaunch) : undefined;
270990
- if (wixLaunch && !prompt && !wixLaunch.prompt) {
270991
- throw new InvalidInputError("The launch URL has no ?prompt= pass the prompt as the argument.");
271714
+ const wixInstance = signedInstance ? { signedInstance, wixClientId: options.wixClientId?.trim() || undefined } : undefined;
271715
+ if (wixInstance && !prompt) {
271716
+ throw new InvalidInputError("--wix-instance needs the prompt argument: what the agent should build.");
270992
271717
  }
270993
- if (!prompt && !options.import && !wixLaunch) {
270994
- throw new InvalidInputError('Describe the app ("<prompt>") or pass --import <repo> / --wix-launch <url>.');
271718
+ if (!prompt && !options.import) {
271719
+ throw new InvalidInputError('Describe the app ("<prompt>") or pass --import <repo>.');
270995
271720
  }
270996
271721
  if (options.streamJson && jsonMode) {
270997
271722
  throw new InvalidInputError("--stream-json and --json are exclusive.");
@@ -271007,7 +271732,7 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
271007
271732
  repoName: options.repoName,
271008
271733
  fromBranch: options.fromBranch,
271009
271734
  path: options.path,
271010
- wixLaunch
271735
+ wixInstance
271011
271736
  }));
271012
271737
  } catch (error) {
271013
271738
  for (const line of await githubReauthLines(error) ?? [])
@@ -271035,6 +271760,7 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
271035
271760
  }
271036
271761
  let finalState;
271037
271762
  let previewUrl;
271763
+ let pending = [];
271038
271764
  const startedAt = Date.now();
271039
271765
  if (prompt) {
271040
271766
  const branchId = await resolveActiveBranchId().catch(() => {
@@ -271053,6 +271779,20 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
271053
271779
  stream.onEvent(event);
271054
271780
  }, { branchId, timeoutMs: POLL_TIMEOUT_MS });
271055
271781
  finalState = settled === "timeout" ? "processing" : (await getAppState(app.id)).status?.state ?? "ready";
271782
+ if (settled === "settled") {
271783
+ pending = pendingInputs(await getFullConversation(30, branchId).catch(() => []));
271784
+ if (pending.length && (options.autoApprove || options.skipQuestions)) {
271785
+ pending = await applyPolicy(pending, options, branchId, (event) => {
271786
+ if (ndjson) {
271787
+ const { kind, ...rest } = event;
271788
+ ndjson({ type: kind, ...rest });
271789
+ } else if (!jsonMode)
271790
+ stream.onEvent(event);
271791
+ });
271792
+ }
271793
+ if (pending.length)
271794
+ finalState = "waiting";
271795
+ }
271056
271796
  if (finalState === "ready") {
271057
271797
  previewUrl = await getPreviewUrl().catch(() => {
271058
271798
  return;
@@ -271067,7 +271807,8 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
271067
271807
  type: "result",
271068
271808
  id: app.id,
271069
271809
  preview_url: previewUrl ?? null,
271070
- status: finalState ?? "created"
271810
+ status: finalState ?? "created",
271811
+ ...pending.length ? { pending: pendingSummary(pending) } : {}
271071
271812
  });
271072
271813
  return {};
271073
271814
  }
@@ -271081,6 +271822,7 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
271081
271822
  dir: app.dirName,
271082
271823
  path: app.targetDir,
271083
271824
  status: finalState ?? "created",
271825
+ ...pending.length ? { pending: pendingSummary(pending) } : {},
271084
271826
  ...app.clientCreationId ? { client_creation_id: app.clientCreationId } : {}
271085
271827
  })}
271086
271828
  `
@@ -271090,6 +271832,13 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
271090
271832
  log.message(`preview ${previewUrl}`);
271091
271833
  for (const line of nextStepsLines(app))
271092
271834
  log.message(line);
271835
+ if (finalState === "waiting") {
271836
+ for (const p of pending)
271837
+ log.message(` ⏸ ${p.title} (${p.kind})`);
271838
+ return {
271839
+ outroMessage: "The agent is waiting on you. Answer with `base44 builder send --approve` (or --choose, --grant, --secret), or open `base44 code`."
271840
+ };
271841
+ }
271093
271842
  if (finalState === "error") {
271094
271843
  return {
271095
271844
  outroMessage: `The first build reported an error — open the editor for details.`
@@ -271106,29 +271855,43 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
271106
271855
  }
271107
271856
  function getNewCommand() {
271108
271857
  const command = new Base44Command("new", { requireAppContext: false });
271109
- command.description("Create an app and start building: from a prompt (the Base44 template), or over an existing GitHub repo with --import").argument("[prompt]", "What to build; the first agent turn starts immediately").option("--import <repo>", "Build over an existing GitHub repository instead of the template").option("--mode <mode>", "How to import: direct, fork, or copy (default: direct)").option("--name <name>", "Directory and app name (invented when omitted)").option("--path <dir>", "Directory to link (default: the current directory when empty, else ./<name>)").option("--repo-name <name>", "Name for the new GitHub repo when forking/copying").option("--from-branch <name>", "Import a specific branch of the repo").addOption(new Option2("--wix-launch <url>", `Create through a Wix launch URL (the funnel's ?prompt= and #wix-signed-instance); "-" reads it from stdin. A prompt argument is what the agent runs instead of the URL's`).env("BASE44_WIX_LAUNCH_URL")).option("--verbose", "Show every tool result in full (no folding)").option("--stream-json", "Emit each stream event as a JSON line as it happens, then a final result line").action(newAction);
271858
+ command.description("Create an app and start building: from a prompt (the Base44 template), or over an existing GitHub repo with --import").argument("[prompt]", "What to build; the first agent turn starts immediately").option("--import <repo>", "Build over an existing GitHub repository instead of the template").option("--mode <mode>", "How to import: direct, fork, or copy (default: direct)").option("--name <name>", "Directory and app name (invented when omitted)").option("--path <dir>", "Directory to link (default: the current directory when empty, else ./<name>)").option("--repo-name <name>", "Name for the new GitHub repo when forking/copying").option("--from-branch <name>", "Import a specific branch of the repo").addOption(new Option2("--wix-instance <token>", 'Create through the Wix route with this signed instance (the Wix connector is connected before the first turn); "-" reads the token from stdin').env("BASE44_WIX_INSTANCE")).option("--wix-client-id <id>", "The companion OAuth app's client id, when the Wix launch has one").option("--auto-approve", "Policy: approve approval-kind pauses in the first build (never secrets or browser steps)").option("--skip-questions", "Policy: skip clarifying questions; the agent decides").option("--verbose", "Show every tool result in full (no folding)").option("--stream-json", "Emit each stream event as a JSON line as it happens, then a final result line").action(newAction);
271110
271859
  return command;
271111
271860
  }
271112
271861
 
271113
271862
  // src/cli/commands/builder/status.ts
271114
271863
  async function statusAction(ctx) {
271115
271864
  const id = ctx.app?.id;
271116
- const app = await ctx.runTask("Reading app status", () => getAppState(id));
271117
- const state = app.status?.state ?? "ready";
271865
+ const branchId = await resolveBranchId(ctx);
271866
+ const [app, messages] = await ctx.runTask("Reading app status", () => Promise.all([
271867
+ getAppState(id),
271868
+ getFullConversation(30, branchId).catch(() => [])
271869
+ ]));
271870
+ const pending = pendingInputs(messages);
271871
+ const state = pending.length ? "waiting" : app.status?.state ?? "ready";
271118
271872
  if (ctx.jsonMode) {
271119
271873
  return {
271120
- stdout: `${JSON.stringify({ id: app.id, state, message: app.status?.message ?? null })}
271874
+ stdout: `${JSON.stringify({
271875
+ id: app.id,
271876
+ state,
271877
+ message: app.status?.message ?? null,
271878
+ ...pending.length ? { pending: pendingSummary(pending) } : {}
271879
+ })}
271121
271880
  `
271122
271881
  };
271123
271882
  }
271124
271883
  ctx.log.message(`State: ${state}`);
271125
271884
  if (app.status?.message)
271126
271885
  ctx.log.message(`Note: ${app.status.message}`);
271127
- return { outroMessage: "Status read." };
271886
+ for (const p of pending)
271887
+ ctx.log.message(` ⏸ ${p.title} (${p.kind})`);
271888
+ return {
271889
+ outroMessage: pending.length ? "The agent is waiting on you — `base44 builder send --approve` (or --choose, --grant, --secret) answers it." : "Status read."
271890
+ };
271128
271891
  }
271129
271892
  function getStatusCommand() {
271130
- const command = new Base44Command("status");
271131
- command.description("Show whether the app is building, ready, or errored").action(statusAction);
271893
+ const command = new Base44Command("status", { supportsBranch: true });
271894
+ command.description("Show whether the app is building, ready, errored — or waiting on you, and for what").action(statusAction);
271132
271895
  return command;
271133
271896
  }
271134
271897
 
@@ -276112,6 +276875,612 @@ function TextInput({ value: originalValue, placeholder = "", focus = true, mask,
276112
276875
  }
276113
276876
  var build_default = TextInput;
276114
276877
 
276878
+ // ../../node_modules/open/index.js
276879
+ import process30 from "node:process";
276880
+ import path16 from "node:path";
276881
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
276882
+ import childProcess3 from "node:child_process";
276883
+ import fs20, { constants as fsConstants2 } from "node:fs/promises";
276884
+
276885
+ // ../../node_modules/wsl-utils/index.js
276886
+ import { promisify as promisify6 } from "node:util";
276887
+ import childProcess2 from "node:child_process";
276888
+ import fs19, { constants as fsConstants } from "node:fs/promises";
276889
+
276890
+ // ../../node_modules/is-wsl/index.js
276891
+ import process24 from "node:process";
276892
+ import os4 from "node:os";
276893
+ import fs18 from "node:fs";
276894
+
276895
+ // ../../node_modules/is-inside-container/index.js
276896
+ import fs17 from "node:fs";
276897
+
276898
+ // ../../node_modules/is-docker/index.js
276899
+ import fs16 from "node:fs";
276900
+ var isDockerCached;
276901
+ function hasDockerEnv() {
276902
+ try {
276903
+ fs16.statSync("/.dockerenv");
276904
+ return true;
276905
+ } catch {
276906
+ return false;
276907
+ }
276908
+ }
276909
+ function hasDockerCGroup() {
276910
+ try {
276911
+ return fs16.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
276912
+ } catch {
276913
+ return false;
276914
+ }
276915
+ }
276916
+ function isDocker() {
276917
+ if (isDockerCached === undefined) {
276918
+ isDockerCached = hasDockerEnv() || hasDockerCGroup();
276919
+ }
276920
+ return isDockerCached;
276921
+ }
276922
+
276923
+ // ../../node_modules/is-inside-container/index.js
276924
+ var cachedResult;
276925
+ var hasContainerEnv = () => {
276926
+ try {
276927
+ fs17.statSync("/run/.containerenv");
276928
+ return true;
276929
+ } catch {
276930
+ return false;
276931
+ }
276932
+ };
276933
+ function isInsideContainer() {
276934
+ if (cachedResult === undefined) {
276935
+ cachedResult = hasContainerEnv() || isDocker();
276936
+ }
276937
+ return cachedResult;
276938
+ }
276939
+
276940
+ // ../../node_modules/is-wsl/index.js
276941
+ var isWsl = () => {
276942
+ if (process24.platform !== "linux") {
276943
+ return false;
276944
+ }
276945
+ if (os4.release().toLowerCase().includes("microsoft")) {
276946
+ if (isInsideContainer()) {
276947
+ return false;
276948
+ }
276949
+ return true;
276950
+ }
276951
+ try {
276952
+ return fs18.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
276953
+ } catch {
276954
+ return false;
276955
+ }
276956
+ };
276957
+ var is_wsl_default = process24.env.__IS_WSL_TEST__ ? isWsl : isWsl();
276958
+
276959
+ // ../../node_modules/powershell-utils/index.js
276960
+ import process25 from "node:process";
276961
+ import { Buffer as Buffer7 } from "node:buffer";
276962
+ import { promisify as promisify5 } from "node:util";
276963
+ import childProcess from "node:child_process";
276964
+ var execFile = promisify5(childProcess.execFile);
276965
+ var powerShellPath = () => `${process25.env.SYSTEMROOT || process25.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
276966
+ var executePowerShell = async (command, options = {}) => {
276967
+ const {
276968
+ powerShellPath: psPath,
276969
+ ...execFileOptions
276970
+ } = options;
276971
+ const encodedCommand = executePowerShell.encodeCommand(command);
276972
+ return execFile(psPath ?? powerShellPath(), [
276973
+ ...executePowerShell.argumentsPrefix,
276974
+ encodedCommand
276975
+ ], {
276976
+ encoding: "utf8",
276977
+ ...execFileOptions
276978
+ });
276979
+ };
276980
+ executePowerShell.argumentsPrefix = [
276981
+ "-NoProfile",
276982
+ "-NonInteractive",
276983
+ "-ExecutionPolicy",
276984
+ "Bypass",
276985
+ "-EncodedCommand"
276986
+ ];
276987
+ executePowerShell.encodeCommand = (command) => Buffer7.from(command, "utf16le").toString("base64");
276988
+ executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
276989
+
276990
+ // ../../node_modules/wsl-utils/utilities.js
276991
+ function parseMountPointFromConfig(content) {
276992
+ for (const line of content.split(`
276993
+ `)) {
276994
+ if (/^\s*#/.test(line)) {
276995
+ continue;
276996
+ }
276997
+ const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
276998
+ if (!match) {
276999
+ continue;
277000
+ }
277001
+ return match.groups.mountPoint.trim().replaceAll(/^["']|["']$/g, "");
277002
+ }
277003
+ }
277004
+
277005
+ // ../../node_modules/wsl-utils/index.js
277006
+ var execFile2 = promisify6(childProcess2.execFile);
277007
+ var wslDrivesMountPoint = (() => {
277008
+ const defaultMountPoint = "/mnt/";
277009
+ let mountPoint;
277010
+ return async function() {
277011
+ if (mountPoint) {
277012
+ return mountPoint;
277013
+ }
277014
+ const configFilePath = "/etc/wsl.conf";
277015
+ let isConfigFileExists = false;
277016
+ try {
277017
+ await fs19.access(configFilePath, fsConstants.F_OK);
277018
+ isConfigFileExists = true;
277019
+ } catch {}
277020
+ if (!isConfigFileExists) {
277021
+ return defaultMountPoint;
277022
+ }
277023
+ const configContent = await fs19.readFile(configFilePath, { encoding: "utf8" });
277024
+ const parsedMountPoint = parseMountPointFromConfig(configContent);
277025
+ if (parsedMountPoint === undefined) {
277026
+ return defaultMountPoint;
277027
+ }
277028
+ mountPoint = parsedMountPoint;
277029
+ mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
277030
+ return mountPoint;
277031
+ };
277032
+ })();
277033
+ var powerShellPathFromWsl = async () => {
277034
+ const mountPoint = await wslDrivesMountPoint();
277035
+ return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
277036
+ };
277037
+ var powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
277038
+ var canAccessPowerShellPromise;
277039
+ var canAccessPowerShell = async () => {
277040
+ canAccessPowerShellPromise ??= (async () => {
277041
+ try {
277042
+ const psPath = await powerShellPath2();
277043
+ await fs19.access(psPath, fsConstants.X_OK);
277044
+ return true;
277045
+ } catch {
277046
+ return false;
277047
+ }
277048
+ })();
277049
+ return canAccessPowerShellPromise;
277050
+ };
277051
+ var wslDefaultBrowser = async () => {
277052
+ const psPath = await powerShellPath2();
277053
+ const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
277054
+ const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
277055
+ return stdout.trim();
277056
+ };
277057
+ var convertWslPathToWindows = async (path) => {
277058
+ if (/^[a-z]+:\/\//i.test(path)) {
277059
+ return path;
277060
+ }
277061
+ try {
277062
+ const { stdout } = await execFile2("wslpath", ["-aw", path], { encoding: "utf8" });
277063
+ return stdout.trim();
277064
+ } catch {
277065
+ return path;
277066
+ }
277067
+ };
277068
+
277069
+ // ../../node_modules/define-lazy-prop/index.js
277070
+ function defineLazyProperty(object, propertyName, valueGetter) {
277071
+ const define2 = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
277072
+ Object.defineProperty(object, propertyName, {
277073
+ configurable: true,
277074
+ enumerable: true,
277075
+ get() {
277076
+ const result = valueGetter();
277077
+ define2(result);
277078
+ return result;
277079
+ },
277080
+ set(value) {
277081
+ define2(value);
277082
+ }
277083
+ });
277084
+ return object;
277085
+ }
277086
+
277087
+ // ../../node_modules/default-browser/index.js
277088
+ import { promisify as promisify10 } from "node:util";
277089
+ import process28 from "node:process";
277090
+ import { execFile as execFile6 } from "node:child_process";
277091
+
277092
+ // ../../node_modules/default-browser-id/index.js
277093
+ import { promisify as promisify7 } from "node:util";
277094
+ import process26 from "node:process";
277095
+ import { execFile as execFile3 } from "node:child_process";
277096
+ var execFileAsync = promisify7(execFile3);
277097
+ async function defaultBrowserId() {
277098
+ if (process26.platform !== "darwin") {
277099
+ throw new Error("macOS only");
277100
+ }
277101
+ const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
277102
+ const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
277103
+ const browserId = match?.groups.id ?? "com.apple.Safari";
277104
+ if (browserId === "com.apple.safari") {
277105
+ return "com.apple.Safari";
277106
+ }
277107
+ return browserId;
277108
+ }
277109
+
277110
+ // ../../node_modules/run-applescript/index.js
277111
+ import process27 from "node:process";
277112
+ import { promisify as promisify8 } from "node:util";
277113
+ import { execFile as execFile4, execFileSync } from "node:child_process";
277114
+ var execFileAsync2 = promisify8(execFile4);
277115
+ async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
277116
+ if (process27.platform !== "darwin") {
277117
+ throw new Error("macOS only");
277118
+ }
277119
+ const outputArguments = humanReadableOutput ? [] : ["-ss"];
277120
+ const execOptions = {};
277121
+ if (signal) {
277122
+ execOptions.signal = signal;
277123
+ }
277124
+ const { stdout } = await execFileAsync2("osascript", ["-e", script, outputArguments], execOptions);
277125
+ return stdout.trim();
277126
+ }
277127
+
277128
+ // ../../node_modules/bundle-name/index.js
277129
+ async function bundleName(bundleId) {
277130
+ return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
277131
+ tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
277132
+ }
277133
+
277134
+ // ../../node_modules/default-browser/windows.js
277135
+ import { promisify as promisify9 } from "node:util";
277136
+ import { execFile as execFile5 } from "node:child_process";
277137
+ var execFileAsync3 = promisify9(execFile5);
277138
+ var windowsBrowserProgIds = {
277139
+ MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
277140
+ MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
277141
+ MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
277142
+ AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
277143
+ ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
277144
+ ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
277145
+ ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
277146
+ ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
277147
+ BraveHTML: { name: "Brave", id: "com.brave.Browser" },
277148
+ BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
277149
+ BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
277150
+ BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
277151
+ FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
277152
+ OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
277153
+ VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
277154
+ "IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
277155
+ };
277156
+ var _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
277157
+
277158
+ class UnknownBrowserError extends Error {
277159
+ }
277160
+ async function defaultBrowser(_execFileAsync = execFileAsync3) {
277161
+ const { stdout } = await _execFileAsync("reg", [
277162
+ "QUERY",
277163
+ " HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
277164
+ "/v",
277165
+ "ProgId"
277166
+ ]);
277167
+ const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
277168
+ if (!match) {
277169
+ throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
277170
+ }
277171
+ const { id } = match.groups;
277172
+ const dotIndex = id.lastIndexOf(".");
277173
+ const hyphenIndex = id.lastIndexOf("-");
277174
+ const baseIdByDot = dotIndex === -1 ? undefined : id.slice(0, dotIndex);
277175
+ const baseIdByHyphen = hyphenIndex === -1 ? undefined : id.slice(0, hyphenIndex);
277176
+ return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? { name: id, id };
277177
+ }
277178
+
277179
+ // ../../node_modules/default-browser/index.js
277180
+ var execFileAsync4 = promisify10(execFile6);
277181
+ var titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
277182
+ async function defaultBrowser2() {
277183
+ if (process28.platform === "darwin") {
277184
+ const id = await defaultBrowserId();
277185
+ const name = await bundleName(id);
277186
+ return { name, id };
277187
+ }
277188
+ if (process28.platform === "linux") {
277189
+ const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
277190
+ const id = stdout.trim();
277191
+ const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
277192
+ return { name, id };
277193
+ }
277194
+ if (process28.platform === "win32") {
277195
+ return defaultBrowser();
277196
+ }
277197
+ throw new Error("Only macOS, Linux, and Windows are supported");
277198
+ }
277199
+
277200
+ // ../../node_modules/is-in-ssh/index.js
277201
+ import process29 from "node:process";
277202
+ var isInSsh = Boolean(process29.env.SSH_CONNECTION || process29.env.SSH_CLIENT || process29.env.SSH_TTY);
277203
+ var is_in_ssh_default = isInSsh;
277204
+
277205
+ // ../../node_modules/open/index.js
277206
+ var fallbackAttemptSymbol = Symbol("fallbackAttempt");
277207
+ var __dirname2 = import.meta.url ? path16.dirname(fileURLToPath4(import.meta.url)) : "";
277208
+ var localXdgOpenPath = path16.join(__dirname2, "xdg-open");
277209
+ var { platform: platform7, arch } = process30;
277210
+ var tryEachApp = async (apps, opener) => {
277211
+ if (apps.length === 0) {
277212
+ return;
277213
+ }
277214
+ const errors = [];
277215
+ for (const app of apps) {
277216
+ try {
277217
+ return await opener(app);
277218
+ } catch (error) {
277219
+ errors.push(error);
277220
+ }
277221
+ }
277222
+ throw new AggregateError(errors, "Failed to open in all supported apps");
277223
+ };
277224
+ var baseOpen = async (options) => {
277225
+ options = {
277226
+ wait: false,
277227
+ background: false,
277228
+ newInstance: false,
277229
+ allowNonzeroExitCode: false,
277230
+ ...options
277231
+ };
277232
+ const isFallbackAttempt = options[fallbackAttemptSymbol] === true;
277233
+ delete options[fallbackAttemptSymbol];
277234
+ if (Array.isArray(options.app)) {
277235
+ return tryEachApp(options.app, (singleApp) => baseOpen({
277236
+ ...options,
277237
+ app: singleApp,
277238
+ [fallbackAttemptSymbol]: true
277239
+ }));
277240
+ }
277241
+ let { name: app, arguments: appArguments = [] } = options.app ?? {};
277242
+ appArguments = [...appArguments];
277243
+ if (Array.isArray(app)) {
277244
+ return tryEachApp(app, (appName) => baseOpen({
277245
+ ...options,
277246
+ app: {
277247
+ name: appName,
277248
+ arguments: appArguments
277249
+ },
277250
+ [fallbackAttemptSymbol]: true
277251
+ }));
277252
+ }
277253
+ if (app === "browser" || app === "browserPrivate") {
277254
+ const ids = {
277255
+ "com.google.chrome": "chrome",
277256
+ "google-chrome.desktop": "chrome",
277257
+ "com.brave.browser": "brave",
277258
+ "org.mozilla.firefox": "firefox",
277259
+ "firefox.desktop": "firefox",
277260
+ "com.microsoft.msedge": "edge",
277261
+ "com.microsoft.edge": "edge",
277262
+ "com.microsoft.edgemac": "edge",
277263
+ "microsoft-edge.desktop": "edge",
277264
+ "com.apple.safari": "safari"
277265
+ };
277266
+ const flags = {
277267
+ chrome: "--incognito",
277268
+ brave: "--incognito",
277269
+ firefox: "--private-window",
277270
+ edge: "--inPrivate"
277271
+ };
277272
+ let browser;
277273
+ if (is_wsl_default) {
277274
+ const progId = await wslDefaultBrowser();
277275
+ const browserInfo = _windowsBrowserProgIdMap.get(progId);
277276
+ browser = browserInfo ?? {};
277277
+ } else {
277278
+ browser = await defaultBrowser2();
277279
+ }
277280
+ if (browser.id in ids) {
277281
+ const browserName = ids[browser.id.toLowerCase()];
277282
+ if (app === "browserPrivate") {
277283
+ if (browserName === "safari") {
277284
+ throw new Error("Safari doesn't support opening in private mode via command line");
277285
+ }
277286
+ appArguments.push(flags[browserName]);
277287
+ }
277288
+ return baseOpen({
277289
+ ...options,
277290
+ app: {
277291
+ name: apps[browserName],
277292
+ arguments: appArguments
277293
+ }
277294
+ });
277295
+ }
277296
+ throw new Error(`${browser.name} is not supported as a default browser`);
277297
+ }
277298
+ let command;
277299
+ const cliArguments = [];
277300
+ const childProcessOptions = {};
277301
+ let shouldUseWindowsInWsl = false;
277302
+ if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
277303
+ shouldUseWindowsInWsl = await canAccessPowerShell();
277304
+ }
277305
+ if (platform7 === "darwin") {
277306
+ command = "open";
277307
+ if (options.wait) {
277308
+ cliArguments.push("--wait-apps");
277309
+ }
277310
+ if (options.background) {
277311
+ cliArguments.push("--background");
277312
+ }
277313
+ if (options.newInstance) {
277314
+ cliArguments.push("--new");
277315
+ }
277316
+ if (app) {
277317
+ cliArguments.push("-a", app);
277318
+ }
277319
+ } else if (platform7 === "win32" || shouldUseWindowsInWsl) {
277320
+ command = await powerShellPath2();
277321
+ cliArguments.push(...executePowerShell.argumentsPrefix);
277322
+ if (!is_wsl_default) {
277323
+ childProcessOptions.windowsVerbatimArguments = true;
277324
+ }
277325
+ if (is_wsl_default && options.target) {
277326
+ options.target = await convertWslPathToWindows(options.target);
277327
+ }
277328
+ const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
277329
+ if (options.wait) {
277330
+ encodedArguments.push("-Wait");
277331
+ }
277332
+ if (app) {
277333
+ encodedArguments.push(executePowerShell.escapeArgument(app));
277334
+ if (options.target) {
277335
+ appArguments.push(options.target);
277336
+ }
277337
+ } else if (options.target) {
277338
+ encodedArguments.push(executePowerShell.escapeArgument(options.target));
277339
+ }
277340
+ if (appArguments.length > 0) {
277341
+ appArguments = appArguments.map((argument) => executePowerShell.escapeArgument(argument));
277342
+ encodedArguments.push("-ArgumentList", appArguments.join(","));
277343
+ }
277344
+ options.target = executePowerShell.encodeCommand(encodedArguments.join(" "));
277345
+ if (!options.wait) {
277346
+ childProcessOptions.stdio = "ignore";
277347
+ }
277348
+ } else {
277349
+ if (app) {
277350
+ command = app;
277351
+ } else {
277352
+ const isBundled = !__dirname2 || __dirname2 === "/";
277353
+ let exeLocalXdgOpen = false;
277354
+ try {
277355
+ await fs20.access(localXdgOpenPath, fsConstants2.X_OK);
277356
+ exeLocalXdgOpen = true;
277357
+ } catch {}
277358
+ const useSystemXdgOpen = process30.versions.electron ?? (platform7 === "android" || isBundled || !exeLocalXdgOpen);
277359
+ command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
277360
+ }
277361
+ if (appArguments.length > 0) {
277362
+ cliArguments.push(...appArguments);
277363
+ }
277364
+ if (!options.wait) {
277365
+ childProcessOptions.stdio = "ignore";
277366
+ childProcessOptions.detached = true;
277367
+ }
277368
+ }
277369
+ if (platform7 === "darwin" && appArguments.length > 0) {
277370
+ cliArguments.push("--args", ...appArguments);
277371
+ }
277372
+ if (options.target) {
277373
+ cliArguments.push(options.target);
277374
+ }
277375
+ const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
277376
+ if (options.wait) {
277377
+ return new Promise((resolve, reject) => {
277378
+ subprocess.once("error", reject);
277379
+ subprocess.once("close", (exitCode) => {
277380
+ if (!options.allowNonzeroExitCode && exitCode !== 0) {
277381
+ reject(new Error(`Exited with code ${exitCode}`));
277382
+ return;
277383
+ }
277384
+ resolve(subprocess);
277385
+ });
277386
+ });
277387
+ }
277388
+ if (isFallbackAttempt) {
277389
+ return new Promise((resolve, reject) => {
277390
+ subprocess.once("error", reject);
277391
+ subprocess.once("spawn", () => {
277392
+ subprocess.once("close", (exitCode) => {
277393
+ subprocess.off("error", reject);
277394
+ if (exitCode !== 0) {
277395
+ reject(new Error(`Exited with code ${exitCode}`));
277396
+ return;
277397
+ }
277398
+ subprocess.unref();
277399
+ resolve(subprocess);
277400
+ });
277401
+ });
277402
+ });
277403
+ }
277404
+ subprocess.unref();
277405
+ return new Promise((resolve, reject) => {
277406
+ subprocess.once("error", reject);
277407
+ subprocess.once("spawn", () => {
277408
+ subprocess.off("error", reject);
277409
+ resolve(subprocess);
277410
+ });
277411
+ });
277412
+ };
277413
+ var open = (target, options) => {
277414
+ if (typeof target !== "string") {
277415
+ throw new TypeError("Expected a `target`");
277416
+ }
277417
+ return baseOpen({
277418
+ ...options,
277419
+ target
277420
+ });
277421
+ };
277422
+ function detectArchBinary(binary) {
277423
+ if (typeof binary === "string" || Array.isArray(binary)) {
277424
+ return binary;
277425
+ }
277426
+ const { [arch]: archBinary } = binary;
277427
+ if (!archBinary) {
277428
+ throw new Error(`${arch} is not supported`);
277429
+ }
277430
+ return archBinary;
277431
+ }
277432
+ function detectPlatformBinary({ [platform7]: platformBinary }, { wsl } = {}) {
277433
+ if (wsl && is_wsl_default) {
277434
+ return detectArchBinary(wsl);
277435
+ }
277436
+ if (!platformBinary) {
277437
+ throw new Error(`${platform7} is not supported`);
277438
+ }
277439
+ return detectArchBinary(platformBinary);
277440
+ }
277441
+ var apps = {
277442
+ browser: "browser",
277443
+ browserPrivate: "browserPrivate"
277444
+ };
277445
+ defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
277446
+ darwin: "google chrome",
277447
+ win32: "chrome",
277448
+ linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
277449
+ }, {
277450
+ wsl: {
277451
+ ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
277452
+ x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
277453
+ }
277454
+ }));
277455
+ defineLazyProperty(apps, "brave", () => detectPlatformBinary({
277456
+ darwin: "brave browser",
277457
+ win32: "brave",
277458
+ linux: ["brave-browser", "brave"]
277459
+ }, {
277460
+ wsl: {
277461
+ ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
277462
+ x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
277463
+ }
277464
+ }));
277465
+ defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
277466
+ darwin: "firefox",
277467
+ win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
277468
+ linux: "firefox"
277469
+ }, {
277470
+ wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
277471
+ }));
277472
+ defineLazyProperty(apps, "edge", () => detectPlatformBinary({
277473
+ darwin: "microsoft edge",
277474
+ win32: "msedge",
277475
+ linux: ["microsoft-edge", "microsoft-edge-dev"]
277476
+ }, {
277477
+ wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
277478
+ }));
277479
+ defineLazyProperty(apps, "safari", () => detectPlatformBinary({
277480
+ darwin: "Safari"
277481
+ }));
277482
+ var open_default = open;
277483
+
276115
277484
  // src/cli/commands/code/session.tsx
276116
277485
  var import_react23 = __toESM(require_react(), 1);
276117
277486
 
@@ -276301,185 +277670,413 @@ function createPasteFriendlyStdin(real) {
276301
277670
  return proxy;
276302
277671
  }
276303
277672
 
276304
- // src/cli/commands/code/session-engine.ts
276305
- var POLL_MS = 1000;
276306
- function createSessionEngine(options) {
276307
- const running = new Map;
276308
- const diffState = newStreamState();
276309
- let stopped = false;
276310
- let polling = false;
276311
- let pollStartedAt = 0;
276312
- let timer = null;
276313
- let sendsInFlight = 0;
276314
- let activeTurnId = null;
276315
- let turnStartedAt = null;
276316
- let pendingSubmitAt = null;
276317
- let lastTurnMs = null;
276318
- let lastTurnOk = true;
276319
- let settledCount = 0;
276320
- let awaitingTurn = options.awaitingTurnLabel ?? null;
276321
- const awaitingSince = Date.now();
276322
- let lastEventAt = Date.now();
276323
- const submit = (raw) => {
276324
- const typed = raw.trim();
276325
- if (!typed)
276326
- return;
276327
- const text = typed;
276328
- options.onLine(`${source_default.cyan("❯")} ${source_default.bold(typed)}`);
276329
- pendingSubmitAt = Date.now();
276330
- const submitTurnId = activeTurnId;
276331
- sendsInFlight++;
276332
- sendTurn(text, options.branchId).then((turn) => {
276333
- if (turn.queued) {
276334
- options.onLine(source_default.dim("· queued — runs after the current turn"));
276335
- }
276336
- }).catch((error) => {
276337
- const delivered = activeTurnId !== submitTurnId || turnStartedAt != null || pendingSubmitAt == null;
276338
- const status = error instanceof ApiError ? error.statusCode : undefined;
276339
- const edgeDrop = status === 502 || status === 503 || status === 504 || /timeout|gateway/i.test(error instanceof Error ? error.message : "");
276340
- if (edgeDrop && delivered)
276341
- return;
276342
- pendingSubmitAt = null;
276343
- const message = error instanceof Error ? error.message : String(error);
276344
- options.onLine(source_default.red(`✗ send failed: ${message}`));
276345
- }).finally(() => {
276346
- sendsInFlight--;
276347
- });
276348
- };
276349
- const poll = async (prime) => {
276350
- const STUCK_POLL_MS = 45000;
276351
- if (polling && Date.now() - pollStartedAt < STUCK_POLL_MS)
276352
- return;
276353
- polling = true;
276354
- pollStartedAt = Date.now();
276355
- try {
276356
- let messages;
276357
- try {
276358
- messages = await getFullConversation(30, options.branchId);
276359
- } catch {
276360
- return;
276361
- }
276362
- const events = diffConversation(diffState, messages);
276363
- if (!prime) {
276364
- for (const event of events) {
276365
- if (event.kind === "tool_start") {
276366
- const startedAt = Date.now();
276367
- running.set(event.id, {
276368
- alias: toolAlias(event.name),
276369
- label: event.label,
276370
- summary: event.summary,
276371
- startedAt
276372
- });
276373
- options.onLine({ running: event, startedAt });
276374
- continue;
276375
- }
276376
- if (event.kind === "tool_end") {
276377
- const started = running.get(event.id)?.startedAt;
276378
- running.delete(event.id);
276379
- lastEventAt = Date.now();
276380
- options.onLine({
276381
- event,
276382
- elapsedMs: started != null ? Date.now() - started : undefined
276383
- });
276384
- continue;
276385
- }
276386
- const line = eventLine(event);
276387
- if (line != null) {
276388
- lastEventAt = Date.now();
276389
- options.onLine(line);
276390
- }
277673
+ // src/cli/commands/code/pending-card.ts
277674
+ function openCard(pending) {
277675
+ return {
277676
+ pending,
277677
+ step: 0,
277678
+ cursor: 0,
277679
+ selections: (pending.questions ?? []).map(() => ({ labels: [] })),
277680
+ granted: new Set((pending.permissions ?? []).map((p) => p.key)),
277681
+ typing: pending.kind === "secrets" ? "secret" : pending.kind === "credentials" ? "cred-name" : null,
277682
+ ...pending.kind === "credentials" ? { cred: { name: pending.credentials?.suggestedName } } : {},
277683
+ secretValues: {},
277684
+ ...pending.kind === "browser" ? { browser: { status: "idle" } } : {}
277685
+ };
277686
+ }
277687
+ var done = (action, input = {}) => ({ state: null, submit: { action, input } });
277688
+ var later = { state: null, dismissed: true };
277689
+ function choiceRows(state) {
277690
+ return (state.pending.questions?.[state.step]?.options.length ?? 0) + 1;
277691
+ }
277692
+ function advanceChoice(state) {
277693
+ const questions = state.pending.questions ?? [];
277694
+ if (state.step + 1 < questions.length) {
277695
+ return {
277696
+ state: { ...state, step: state.step + 1, cursor: 0, typing: null }
277697
+ };
277698
+ }
277699
+ return done("approved", choiceAnswers(questions, state.selections, state.pending.answerKey));
277700
+ }
277701
+ function choiceKey(state, key) {
277702
+ const question = state.pending.questions?.[state.step];
277703
+ if (!question)
277704
+ return done("approved", { answers: [] });
277705
+ const rows = choiceRows(state);
277706
+ const custom = state.cursor === rows - 1;
277707
+ const sel = state.selections[state.step] ?? { labels: [] };
277708
+ const setSel = (next) => {
277709
+ const selections = [...state.selections];
277710
+ selections[state.step] = next;
277711
+ return { ...state, selections };
277712
+ };
277713
+ switch (key) {
277714
+ case "up":
277715
+ return { state: { ...state, cursor: (state.cursor - 1 + rows) % rows } };
277716
+ case "down":
277717
+ return { state: { ...state, cursor: (state.cursor + 1) % rows } };
277718
+ case "space": {
277719
+ if (custom)
277720
+ return { state: { ...state, typing: "custom" } };
277721
+ const label = question.options[state.cursor].label;
277722
+ const labels = question.multiSelect ? sel.labels.includes(label) ? sel.labels.filter((l) => l !== label) : [...sel.labels, label] : [label];
277723
+ return { state: setSel({ ...sel, labels }) };
277724
+ }
277725
+ case "enter": {
277726
+ if (custom)
277727
+ return { state: { ...state, typing: "custom" } };
277728
+ if (question.multiSelect) {
277729
+ if (sel.labels.length === 0 && !sel.customText)
277730
+ return { state };
277731
+ return advanceChoice(state);
277732
+ }
277733
+ const label = question.options[state.cursor].label;
277734
+ return advanceChoice(setSel({ labels: [label] }));
277735
+ }
277736
+ case "s":
277737
+ return done("approved", { answers: [] });
277738
+ case "escape":
277739
+ return later;
277740
+ default:
277741
+ return { state };
277742
+ }
277743
+ }
277744
+ function permissionsKey(state, key) {
277745
+ const rows = state.pending.permissions ?? [];
277746
+ switch (key) {
277747
+ case "up":
277748
+ return {
277749
+ state: {
277750
+ ...state,
277751
+ cursor: (state.cursor - 1 + rows.length) % rows.length
276391
277752
  }
276392
- }
276393
- const turn = newestUserTurn(messages);
276394
- if (!turn)
276395
- return;
276396
- const kickoffDetection = awaitingTurn != null && activeTurnId === null;
276397
- awaitingTurn = null;
276398
- if (turn.id !== activeTurnId) {
276399
- activeTurnId = turn.id;
276400
- if (!turn.settled) {
276401
- turnStartedAt = pendingSubmitAt ?? (kickoffDetection ? awaitingSince : Date.now());
276402
- pendingSubmitAt = null;
276403
- running.clear();
276404
- } else if (prime) {
276405
- turnStartedAt = null;
277753
+ };
277754
+ case "down":
277755
+ return { state: { ...state, cursor: (state.cursor + 1) % rows.length } };
277756
+ case "space": {
277757
+ const k = rows[state.cursor]?.key;
277758
+ if (!k)
277759
+ return { state };
277760
+ const granted = new Set(state.granted);
277761
+ if (granted.has(k))
277762
+ granted.delete(k);
277763
+ else
277764
+ granted.add(k);
277765
+ return { state: { ...state, granted } };
277766
+ }
277767
+ case "enter":
277768
+ case "y":
277769
+ return done("approved", {
277770
+ approved_permission_keys: rows.map((r) => r.key).filter((k) => state.granted.has(k))
277771
+ });
277772
+ case "n":
277773
+ return done("rejected");
277774
+ case "escape":
277775
+ return later;
277776
+ default:
277777
+ return { state };
277778
+ }
277779
+ }
277780
+ function cardKey(state, key) {
277781
+ if (state.typing) {
277782
+ if (key === "escape") {
277783
+ return state.typing === "secret" || state.typing === "cred-secret" ? later : state.typing === "custom" ? { state: { ...state, typing: null } } : later;
277784
+ }
277785
+ return { state };
277786
+ }
277787
+ switch (state.pending.kind) {
277788
+ case "choice":
277789
+ return choiceKey(state, key);
277790
+ case "permissions":
277791
+ return permissionsKey(state, key);
277792
+ case "browser": {
277793
+ const status = state.browser?.status ?? "idle";
277794
+ if (key === "n")
277795
+ return done("rejected");
277796
+ if (key === "escape")
277797
+ return later;
277798
+ if (key === "y" || key === "enter") {
277799
+ if (status === "active") {
277800
+ return done("approved", state.browser?.connectionId ? { connection_id: state.browser.connectionId } : {});
277801
+ }
277802
+ if (status !== "waiting") {
277803
+ return {
277804
+ state: {
277805
+ ...state,
277806
+ browser: { ...state.browser, status: "waiting" }
277807
+ },
277808
+ startBrowser: true
277809
+ };
276406
277810
  }
276407
277811
  }
276408
- if (turn.settled && turnStartedAt != null && turn.id === activeTurnId) {
276409
- const durationMs = Date.now() - turnStartedAt;
276410
- turnStartedAt = null;
276411
- running.clear();
276412
- lastTurnMs = durationMs;
276413
- const ok = !turn.backendStatus?.startsWith("error");
276414
- lastTurnOk = ok;
276415
- options.onLine(ok ? source_default.dim(`— turn finished · ${formatDuration2(durationMs)}`) : source_default.red(`— turn failed (${turn.backendStatus ?? "unknown"}) · ${formatDuration2(durationMs)}`));
276416
- const info = {
276417
- turnIndex: settledCount++,
276418
- ok,
276419
- backendStatus: turn.backendStatus,
276420
- durationMs
277812
+ return { state };
277813
+ }
277814
+ case "credentials": {
277815
+ if (key === "n")
277816
+ return done("rejected");
277817
+ if (key === "escape")
277818
+ return later;
277819
+ if (key === "y") {
277820
+ return {
277821
+ state: {
277822
+ ...state,
277823
+ cred: { ...state.cred, source: "own" },
277824
+ typing: "cred-id"
277825
+ }
276421
277826
  };
276422
- try {
276423
- await options.onTurnSettled?.(info);
276424
- } catch {}
276425
277827
  }
276426
- } finally {
276427
- polling = false;
277828
+ if (key === "b") {
277829
+ return done("approved", {
277830
+ name: state.cred?.name ?? "",
277831
+ credential_source: "base44",
277832
+ scopes: state.pending.credentials?.scopes ?? []
277833
+ });
277834
+ }
277835
+ return { state };
276428
277836
  }
276429
- };
277837
+ case "unknown":
277838
+ if (key === "n")
277839
+ return done("rejected");
277840
+ if (key === "escape")
277841
+ return later;
277842
+ return { state };
277843
+ default:
277844
+ if (key === "y" || key === "enter")
277845
+ return done("approved");
277846
+ if (key === "n")
277847
+ return done("rejected");
277848
+ if (key === "escape")
277849
+ return later;
277850
+ return { state };
277851
+ }
277852
+ }
277853
+ function browserUpdate(state, update) {
276430
277854
  return {
276431
- async start(primeFirstPoll) {
276432
- await poll(primeFirstPoll);
276433
- timer = setInterval(() => {
276434
- if (!stopped)
276435
- poll(false);
276436
- }, POLL_MS);
276437
- timer.unref?.();
276438
- },
276439
- stop() {
276440
- stopped = true;
276441
- if (timer)
276442
- clearInterval(timer);
276443
- },
276444
- stopTurn() {
276445
- if (turnStartedAt == null && sendsInFlight === 0 && pendingSubmitAt == null)
276446
- return;
276447
- options.onLine(source_default.dim("· stopping…"));
276448
- stopTurn(options.branchId).catch((error) => {
276449
- options.onLine(source_default.red(` stop failed: ${error instanceof Error ? error.message : String(error)}`));
277855
+ ...state,
277856
+ browser: {
277857
+ url: update.url ?? state.browser?.url,
277858
+ connectionId: update.connectionId ?? state.browser?.connectionId,
277859
+ status: update.status
277860
+ }
277861
+ };
277862
+ }
277863
+ function cardText(state, text) {
277864
+ const value = text.trim();
277865
+ if (state.typing === "custom") {
277866
+ if (!value)
277867
+ return { state: { ...state, typing: null } };
277868
+ const selections = [...state.selections];
277869
+ const current = selections[state.step] ?? { labels: [] };
277870
+ selections[state.step] = { ...current, customText: value };
277871
+ return advanceChoice({ ...state, selections, typing: null });
277872
+ }
277873
+ if (state.typing === "cred-name") {
277874
+ const name = value || state.cred?.name || "";
277875
+ if (!name)
277876
+ return { state };
277877
+ return { state: { ...state, cred: { ...state.cred, name }, typing: null } };
277878
+ }
277879
+ if (state.typing === "cred-id") {
277880
+ if (!value)
277881
+ return { state };
277882
+ return {
277883
+ state: {
277884
+ ...state,
277885
+ cred: { ...state.cred, clientId: value },
277886
+ typing: "cred-secret"
277887
+ }
277888
+ };
277889
+ }
277890
+ if (state.typing === "cred-secret") {
277891
+ if (!value)
277892
+ return { state };
277893
+ const scopes = state.pending.credentials?.scopes ?? [];
277894
+ return done("approved", {
277895
+ name: state.cred?.name ?? "",
277896
+ client_id: state.cred?.clientId ?? "",
277897
+ client_secret: value,
277898
+ scopes
277899
+ });
277900
+ }
277901
+ if (state.typing === "secret") {
277902
+ const fields = state.pending.secrets ?? [];
277903
+ const field = fields[state.step];
277904
+ if (!field || !value)
277905
+ return { state };
277906
+ const secretValues = { ...state.secretValues, [field.name]: value };
277907
+ if (state.step + 1 < fields.length) {
277908
+ return { state: { ...state, secretValues, step: state.step + 1 } };
277909
+ }
277910
+ return done("approved", { secrets: secretValues });
277911
+ }
277912
+ return { state };
277913
+ }
277914
+ function cardLines(state) {
277915
+ const p = state.pending;
277916
+ const head = [source_default.bold(`⏸ ${p.title}`)];
277917
+ if (p.detail)
277918
+ head.push(source_default.dim(` ${p.detail}`));
277919
+ switch (p.kind) {
277920
+ case "choice": {
277921
+ const q = p.questions?.[state.step];
277922
+ if (!q)
277923
+ return [...head, source_default.dim(" (no questions) · Enter to continue")];
277924
+ const total = p.questions?.length ?? 1;
277925
+ const sel = state.selections[state.step] ?? { labels: [] };
277926
+ const rows = q.options.map((o, i) => {
277927
+ const on = sel.labels.includes(o.label);
277928
+ const mark = q.multiSelect ? on ? "☑" : "☐" : on ? "●" : "○";
277929
+ const text = `${state.cursor === i ? "▸" : " "} ${mark} ${o.label}${o.description ? source_default.dim(` — ${o.description}`) : ""}`;
277930
+ return state.cursor === i ? source_default.cyan(text) : text;
276450
277931
  });
276451
- },
276452
- submit,
276453
- status() {
276454
- let phase = "idle";
276455
- if (awaitingTurn != null)
276456
- phase = "awaiting";
276457
- else if (turnStartedAt != null)
276458
- phase = "running";
276459
- else if (sendsInFlight > 0 || pendingSubmitAt != null)
276460
- phase = "sending";
276461
- let runningTool = null;
276462
- if (running.size > 0) {
276463
- const newest = [...running.values()].at(-1);
276464
- runningTool = { ...newest, others: running.size - 1 };
277932
+ const customRow = `${state.cursor === q.options.length ? "▸" : " "} ✎ something else${sel.customText ? source_default.dim(` — ${sel.customText}`) : ""}`;
277933
+ rows.push(state.cursor === q.options.length ? source_default.cyan(customRow) : customRow);
277934
+ return [
277935
+ ...head,
277936
+ ` ${source_default.bold(q.question)} ${source_default.dim(`(${state.step + 1}/${total})`)}`,
277937
+ ...q.description ? [source_default.dim(` ${q.description}`)] : [],
277938
+ ...rows.map((r) => ` ${r}`),
277939
+ source_default.dim(q.multiSelect ? " ↑↓ move · space toggle · Enter next · s skip all · Esc later" : " ↑↓ move · Enter choose · s skip all · Esc later")
277940
+ ];
277941
+ }
277942
+ case "permissions": {
277943
+ const rows = (p.permissions ?? []).map((r, i) => {
277944
+ const text = `${state.cursor === i ? "▸" : " "} ${state.granted.has(r.key) ? "☑" : "☐"} ${r.label}${r.reason ? source_default.dim(` — ${r.reason}`) : ""}`;
277945
+ return ` ${state.cursor === i ? source_default.cyan(text) : text}`;
277946
+ });
277947
+ return [
277948
+ ...head,
277949
+ ...rows,
277950
+ source_default.dim(" space toggle · Enter grant ticked · n reject all · Esc later")
277951
+ ];
277952
+ }
277953
+ case "secrets": {
277954
+ const fields = p.secrets ?? [];
277955
+ const rows = fields.map((f, i) => {
277956
+ const filled = f.name in state.secretValues;
277957
+ const mark = filled ? source_default.green("✓") : i === state.step ? "▸" : "○";
277958
+ return ` ${mark} ${f.name}${f.description ? source_default.dim(` — ${f.description}`) : ""}`;
277959
+ });
277960
+ return [
277961
+ ...head,
277962
+ ...rows,
277963
+ source_default.dim(" type the value below (hidden) · Enter next · Esc later")
277964
+ ];
277965
+ }
277966
+ case "browser": {
277967
+ const b = state.browser ?? { status: "idle" };
277968
+ const link = b.url ? [` ${source_default.cyan(b.url)}`] : [];
277969
+ switch (b.status) {
277970
+ case "waiting":
277971
+ return [
277972
+ ...head,
277973
+ source_default.dim(" opened in your browser — or use the link:"),
277974
+ ...link,
277975
+ source_default.dim(" waiting for the authorization to complete… · n reject · Esc later")
277976
+ ];
277977
+ case "active":
277978
+ return [
277979
+ ...head,
277980
+ source_default.green(" ✓ connected"),
277981
+ source_default.dim(" y continue · n reject")
277982
+ ];
277983
+ case "failed":
277984
+ return [
277985
+ ...head,
277986
+ source_default.red(" ✗ authorization failed"),
277987
+ source_default.dim(" y try again · n reject · Esc later")
277988
+ ];
277989
+ case "timeout":
277990
+ return [
277991
+ ...head,
277992
+ source_default.yellow(" ⏱ no response yet"),
277993
+ ...link,
277994
+ source_default.dim(" y try again · n reject · Esc later")
277995
+ ];
277996
+ default:
277997
+ return [
277998
+ ...head,
277999
+ source_default.dim(" y open the authorization link · n reject · Esc later")
278000
+ ];
276465
278001
  }
276466
- return {
276467
- phase,
276468
- awaitingLabel: awaitingTurn ?? undefined,
276469
- idleHint: options.idleHint,
276470
- quietForMs: Date.now() - lastEventAt,
276471
- awaitingSince,
276472
- turnStartedAt,
276473
- runningTool,
276474
- lastTurnMs,
276475
- lastTurnOk
276476
- };
276477
- },
276478
- turnRunning() {
276479
- return turnStartedAt != null;
276480
278002
  }
278003
+ case "credentials": {
278004
+ const c = state.cred ?? {};
278005
+ const scopes = state.pending.credentials?.scopes ?? [];
278006
+ return [
278007
+ ...head,
278008
+ ` ${c.name ? source_default.green("✓") : "▸"} name${c.name ? source_default.dim(` — ${c.name}`) : ""}`,
278009
+ ` ${c.source ? source_default.green("✓") : c.name ? "▸" : "○"} credentials${c.source === "own" ? source_default.dim(" — your own OAuth app") : c.source === "base44" ? source_default.dim(" — Base44's") : ""}`,
278010
+ ...c.source === "own" ? [
278011
+ ` ${c.clientId ? source_default.green("✓") : "▸"} client id${c.clientId ? source_default.dim(` — ${c.clientId}`) : ""}`,
278012
+ ` ${"▸"} client secret ${source_default.dim("(hidden)")}`
278013
+ ] : [],
278014
+ ...scopes.length ? [source_default.dim(` scopes: ${scopes.join(", ")}`)] : [],
278015
+ source_default.dim(!c.name ? " type the connector name below · Enter · Esc later" : !c.source ? " b use Base44's credentials · y enter your own client id + secret · n reject · Esc later" : " type the value below · Enter next · Esc cancel")
278016
+ ];
278017
+ }
278018
+ case "unknown":
278019
+ return [
278020
+ ...head,
278021
+ source_default.yellow(" this question needs the editor — answer it there and the session continues"),
278022
+ source_default.dim(" n reject · Esc later")
278023
+ ];
278024
+ default:
278025
+ return [...head, source_default.dim(" y approve · n reject · Esc later")];
278026
+ }
278027
+ }
278028
+
278029
+ // src/core/resources/apps/connections.ts
278030
+ var InitiateSchema = object({
278031
+ redirect_url: string2().nullish(),
278032
+ connection_id: string2().nullish(),
278033
+ integration_type: string2().nullish()
278034
+ });
278035
+ async function startConnectorOAuth(options) {
278036
+ let response;
278037
+ try {
278038
+ response = await getAppClient().post("external-auth/initiate", {
278039
+ json: {
278040
+ integration_type: options.integrationType,
278041
+ scopes: options.scopes ?? null,
278042
+ connector_id: options.connectorId ?? null,
278043
+ force_reconnect: options.forceReconnect === true
278044
+ }
278045
+ });
278046
+ } catch (error) {
278047
+ throw await ApiError.fromHttpError(error, "starting connector authorization");
278048
+ }
278049
+ const parsed = InitiateSchema.parse(await response.json());
278050
+ if (!parsed.redirect_url || !parsed.connection_id) {
278051
+ throw new ApiError("The connector did not return an authorization link.");
278052
+ }
278053
+ return {
278054
+ url: parsed.redirect_url,
278055
+ connectionId: parsed.connection_id,
278056
+ integrationType: parsed.integration_type ?? options.integrationType
276481
278057
  };
276482
278058
  }
278059
+ async function waitForConnectorOAuth(started, options = {}) {
278060
+ const deadline = Date.now() + (options.timeoutMs ?? 10 * 60000);
278061
+ const interval = options.intervalMs ?? 3000;
278062
+ while (Date.now() < deadline && !options.signal?.aborted) {
278063
+ const status = await getOAuthStatus(started.integrationType, started.connectionId).catch(() => null);
278064
+ if (status?.status === "ACTIVE" || status?.status === "FAILED") {
278065
+ return status.status;
278066
+ }
278067
+ await new Promise((r) => setTimeout(r, interval));
278068
+ }
278069
+ return "PENDING";
278070
+ }
278071
+ var GithubStatusSchema = object({ connected: boolean2() });
278072
+ async function githubConnected() {
278073
+ try {
278074
+ const response = await base44Client.get("api/github/oauth/status");
278075
+ return GithubStatusSchema.parse(await response.json()).connected;
278076
+ } catch {
278077
+ return false;
278078
+ }
278079
+ }
276483
278080
 
276484
278081
  // src/cli/commands/code/session.tsx
276485
278082
  var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
@@ -276523,7 +278120,7 @@ function statusText(status, musingSeed) {
276523
278120
  case "running": {
276524
278121
  const turnFor = formatDuration2(Date.now() - (status.turnStartedAt ?? Date.now()));
276525
278122
  const quiet = status.quietForMs > 60000 ? " · a long private step — details render in the editor" : "";
276526
- return `${source_default.magenta("✻")} ${source_default.dim(`${idleMusing(musingSeed)} (${turnFor})${quiet}`)}`;
278123
+ return `${source_default.magenta(shimmer())} ${source_default.dim(`${idleMusing(musingSeed)} (${turnFor})${quiet}`)}`;
276527
278124
  }
276528
278125
  case "sending":
276529
278126
  return source_default.dim(`${frame} sending…`);
@@ -276544,6 +278141,8 @@ function SessionView({ engine, footer, subscribe }) {
276544
278141
  const [musingSeed] = import_react23.useState(() => Math.floor(Math.random() * 97));
276545
278142
  const [currentModel, setCurrentModel] = import_react23.useState(null);
276546
278143
  const [pickerIndex, setPickerIndex] = import_react23.useState(null);
278144
+ const [card, setCard] = import_react23.useState(null);
278145
+ const dismissedRef = import_react23.useRef(new Set);
276547
278146
  const maxScrollRef = import_react23.useRef(0);
276548
278147
  const meIdRef = import_react23.useRef(null);
276549
278148
  const emit = (entry) => setItems((h) => withEntry(h, entry));
@@ -276589,6 +278188,84 @@ function SessionView({ engine, footer, subscribe }) {
276589
278188
  emit(source_default.red(` /model: ${error instanceof Error ? error.message : String(error)}`));
276590
278189
  }
276591
278190
  };
278191
+ const browserRunRef = import_react23.useRef(null);
278192
+ const runBrowserStep = async (state) => {
278193
+ browserRunRef.current?.abort();
278194
+ const run = new AbortController;
278195
+ browserRunRef.current = run;
278196
+ const step = state.pending.browser;
278197
+ try {
278198
+ let url;
278199
+ let connectionId;
278200
+ let wait;
278201
+ if (step?.flow === "github") {
278202
+ url = await startGithubReauth();
278203
+ wait = async () => {
278204
+ const deadline = Date.now() + 10 * 60000;
278205
+ while (Date.now() < deadline && !run.signal.aborted) {
278206
+ if (await githubConnected())
278207
+ return "ACTIVE";
278208
+ await new Promise((r) => setTimeout(r, 3000));
278209
+ }
278210
+ return "PENDING";
278211
+ };
278212
+ } else {
278213
+ const started = await startConnectorOAuth({
278214
+ integrationType: step?.integrationType ?? "",
278215
+ scopes: step?.scopes,
278216
+ connectorId: step?.connectorId,
278217
+ forceReconnect: step?.forceReconnect
278218
+ });
278219
+ url = started.url;
278220
+ connectionId = started.connectionId;
278221
+ wait = () => waitForConnectorOAuth(started, { signal: run.signal });
278222
+ }
278223
+ setCard((c) => c ? browserUpdate(c, { url, connectionId, status: "waiting" }) : c);
278224
+ emit(source_default.dim(` authorization link: ${url}`));
278225
+ await open_default(url).catch(() => {
278226
+ return;
278227
+ });
278228
+ const outcome = await wait();
278229
+ if (run.signal.aborted)
278230
+ return;
278231
+ setCard((c) => c ? browserUpdate(c, {
278232
+ status: outcome === "ACTIVE" ? "active" : outcome === "FAILED" ? "failed" : "timeout"
278233
+ }) : c);
278234
+ } catch (error) {
278235
+ if (run.signal.aborted)
278236
+ return;
278237
+ emit(source_default.red(` authorization failed to start: ${error instanceof Error ? error.message : String(error)}`));
278238
+ setCard((c) => c ? browserUpdate(c, { status: "failed" }) : c);
278239
+ }
278240
+ };
278241
+ const applyCard = (outcome) => {
278242
+ if (outcome.submit && card) {
278243
+ browserRunRef.current?.abort();
278244
+ engine.answer(card.pending, outcome.submit.action, outcome.submit.input);
278245
+ }
278246
+ if (outcome.dismissed && card) {
278247
+ browserRunRef.current?.abort();
278248
+ dismissedRef.current.add(card.pending.toolCallId);
278249
+ }
278250
+ setCard(outcome.state);
278251
+ if (outcome.startBrowser && outcome.state) {
278252
+ runBrowserStep(outcome.state);
278253
+ }
278254
+ };
278255
+ const pending = engine.status().pending;
278256
+ import_react23.useEffect(() => {
278257
+ if (card) {
278258
+ if (!pending.some((p) => p.toolCallId === card.pending.toolCallId)) {
278259
+ setCard(null);
278260
+ }
278261
+ return;
278262
+ }
278263
+ if (pickerIndex !== null)
278264
+ return;
278265
+ const next = pending.find((p) => !dismissedRef.current.has(p.toolCallId));
278266
+ if (next)
278267
+ setCard(openCard(next));
278268
+ }, [pending, card, pickerIndex]);
276592
278269
  use_input_default((char, key) => {
276593
278270
  if (pickerIndex !== null) {
276594
278271
  if (key.upArrow)
@@ -276604,6 +278281,23 @@ function SessionView({ engine, footer, subscribe }) {
276604
278281
  }
276605
278282
  return;
276606
278283
  }
278284
+ if (key.tab && !card) {
278285
+ const next = pending.find((p) => dismissedRef.current.has(p.toolCallId));
278286
+ if (next) {
278287
+ dismissedRef.current.delete(next.toolCallId);
278288
+ setCard(openCard(next));
278289
+ }
278290
+ return;
278291
+ }
278292
+ if (card) {
278293
+ const mapped = key.upArrow ? "up" : key.downArrow ? "down" : key.return ? "enter" : key.escape ? "escape" : char === " " ? "space" : char === "y" || char === "n" || char === "s" || char === "b" ? char : null;
278294
+ if (card.typing && mapped !== "escape")
278295
+ return;
278296
+ if (mapped)
278297
+ applyCard(cardKey(card, mapped));
278298
+ if (mapped || !card.typing)
278299
+ return;
278300
+ }
276607
278301
  if (key.ctrl && char === "c") {
276608
278302
  if (input)
276609
278303
  setInput("");
@@ -276648,8 +278342,12 @@ function SessionView({ engine, footer, subscribe }) {
276648
278342
  const innerWidth = Math.max(10, width - 4);
276649
278343
  const inputRows = Math.max(1, Math.ceil((input.length + 3) / innerWidth));
276650
278344
  const pickerOpen = pickerIndex !== null;
276651
- const inputBlockHeight = pickerOpen ? MODELS.length + 3 : inputRows + 2;
276652
- const widgetHeight = inputBlockHeight + 3 + (footer.length ? 1 : 0);
278345
+ const cardOpen = card !== null && !card.typing;
278346
+ const cardRows = card ? cardLines(card).length : 0;
278347
+ const inputBlockHeight = pickerOpen ? MODELS.length + 3 : cardOpen ? cardRows + 2 : inputRows + 2 + (card?.typing ? 1 : 0);
278348
+ const footerText = footer.length ? ` ${footer.join(source_default.dim(" · "))}` : "";
278349
+ const footerRows = footer.length ? hardWrapAnsi(footerText, Math.max(10, columns)).length : 0;
278350
+ const widgetHeight = inputBlockHeight + 3 + footerRows;
276653
278351
  const viewHeight = Math.max(3, rows - widgetHeight - 1);
276654
278352
  const lines = items.flatMap((item) => hardWrapAnsi(`${renderEntry(item, { verbose, foldHint: "Ctrl+O to expand" })}
276655
278353
  `, columns));
@@ -276699,35 +278397,91 @@ function SessionView({ engine, footer, subscribe }) {
276699
278397
  }, m.name, false, undefined, this);
276700
278398
  })
276701
278399
  ]
276702
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
278400
+ }, undefined, true, undefined, this) : cardOpen && card ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
278401
+ flexDirection: "column",
276703
278402
  borderStyle: "round",
276704
- borderColor: "gray",
278403
+ borderColor: "yellow",
278404
+ paddingX: 1,
278405
+ width,
278406
+ children: cardLines(card).map((line, i) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
278407
+ wrap: "truncate-end",
278408
+ children: line
278409
+ }, i, false, undefined, this))
278410
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
278411
+ flexDirection: "column",
278412
+ borderStyle: "round",
278413
+ borderColor: card?.typing ? "yellow" : "gray",
276705
278414
  paddingX: 1,
276706
278415
  width,
276707
278416
  children: [
276708
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
276709
- color: "cyan",
276710
- children: "❯ "
276711
- }, undefined, false, undefined, this),
276712
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(build_default, {
276713
- value: input,
276714
- onChange: setInput,
276715
- onSubmit: (value) => {
276716
- const trimmed = value.trim();
276717
- if (trimmed === "/model" || trimmed.startsWith("/model ")) {
276718
- runModelSlash(trimmed.slice("/model".length).trim());
276719
- } else if (trimmed) {
276720
- engine.submit(value);
276721
- }
276722
- setInput("");
276723
- }
276724
- }, undefined, false, undefined, this)
278417
+ card?.typing === "secret" && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
278418
+ wrap: "truncate-end",
278419
+ children: [
278420
+ source_default.bold(card.pending.secrets?.[card.step]?.name ?? "secret"),
278421
+ source_default.dim(" — value is hidden · Enter to save · Esc to cancel")
278422
+ ]
278423
+ }, undefined, true, undefined, this),
278424
+ card?.typing === "cred-name" && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
278425
+ wrap: "truncate-end",
278426
+ children: [
278427
+ source_default.bold("connector name"),
278428
+ source_default.dim(card.cred?.name ? ` — Enter keeps "${card.cred.name}" · Esc later` : " — Enter to save · Esc later")
278429
+ ]
278430
+ }, undefined, true, undefined, this),
278431
+ card?.typing === "cred-id" && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
278432
+ wrap: "truncate-end",
278433
+ children: [
278434
+ source_default.bold("client id"),
278435
+ source_default.dim(" — Enter to save · Esc cancel")
278436
+ ]
278437
+ }, undefined, true, undefined, this),
278438
+ card?.typing === "cred-secret" && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
278439
+ wrap: "truncate-end",
278440
+ children: [
278441
+ source_default.bold("client secret"),
278442
+ source_default.dim(" — value is hidden · Enter to register · Esc cancel")
278443
+ ]
278444
+ }, undefined, true, undefined, this),
278445
+ card?.typing === "custom" && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
278446
+ wrap: "truncate-end",
278447
+ children: [
278448
+ source_default.bold(card.pending.questions?.[card.step]?.question ?? ""),
278449
+ source_default.dim(" — your own answer · Enter to save · Esc to go back")
278450
+ ]
278451
+ }, undefined, true, undefined, this),
278452
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
278453
+ children: [
278454
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
278455
+ color: "cyan",
278456
+ children: "❯ "
278457
+ }, undefined, false, undefined, this),
278458
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(build_default, {
278459
+ value: input,
278460
+ onChange: setInput,
278461
+ mask: card?.typing === "secret" || card?.typing === "cred-secret" ? "•" : undefined,
278462
+ onSubmit: (value) => {
278463
+ if (card?.typing) {
278464
+ applyCard(cardText(card, value));
278465
+ setInput("");
278466
+ return;
278467
+ }
278468
+ const trimmed = value.trim();
278469
+ if (trimmed === "/model" || trimmed.startsWith("/model ")) {
278470
+ runModelSlash(trimmed.slice("/model".length).trim());
278471
+ } else if (trimmed) {
278472
+ engine.submit(value);
278473
+ }
278474
+ setInput("");
278475
+ }
278476
+ }, undefined, false, undefined, this)
278477
+ ]
278478
+ }, undefined, true, undefined, this)
276725
278479
  ]
276726
278480
  }, undefined, true, undefined, this),
276727
- footer.length > 0 && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
278481
+ footer.length > 0 && hardWrapAnsi(footerText, Math.max(10, columns)).map((row, i) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
276728
278482
  wrap: "truncate-end",
276729
- children: ` ${footer.join(source_default.dim(" · "))}`
276730
- }, undefined, false, undefined, this),
278483
+ children: row
278484
+ }, i, false, undefined, this)),
276731
278485
  /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
276732
278486
  wrap: "truncate-end",
276733
278487
  children: ` ${source_default.dim("model")} ${source_default.hex(BRAND_ORANGE)(displayName(currentModel))}`
@@ -276735,7 +278489,7 @@ function SessionView({ engine, footer, subscribe }) {
276735
278489
  /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
276736
278490
  dimColor: true,
276737
278491
  wrap: "truncate-end",
276738
- children: pickerOpen ? " ↑↓ to move · Enter to select · Esc to cancel" : engine.turnRunning() ? " Esc to stop · type to queue · scroll to read · Ctrl+O to expand · Ctrl+C to exit" : " Enter to send · /model to switch model · Esc for live · Ctrl+O to expand · Ctrl+C to exit"
278492
+ children: pickerOpen ? " ↑↓ to move · Enter to select · Esc to cancel" : cardOpen ? " the agent is waiting on you · answer above, or Esc for later" : pending.length > 0 && !card ? ` ⏸ ${pending[0].title} — Tab to answer · Ctrl+C to exit` : engine.turnRunning() ? " Esc to stop · type to queue · scroll to read · Ctrl+O to expand · Ctrl+C to exit" : " Enter to send · /model to switch model · Esc for live · Ctrl+O to expand · Ctrl+C to exit"
276739
278493
  }, undefined, false, undefined, this)
276740
278494
  ]
276741
278495
  }, undefined, true, undefined, this);
@@ -276860,6 +278614,7 @@ async function runGenesisSession(options) {
276860
278614
  runningTool: null,
276861
278615
  lastTurnMs: null,
276862
278616
  lastTurnOk: true,
278617
+ pending: [],
276863
278618
  quietForMs: 0
276864
278619
  };
276865
278620
  const genesis = {
@@ -276915,6 +278670,9 @@ async function runGenesisSession(options) {
276915
278670
  }
276916
278671
  return IDLE_STATUS;
276917
278672
  },
278673
+ answer(p, action, input) {
278674
+ inner?.answer(p, action, input);
278675
+ },
276918
278676
  turnRunning() {
276919
278677
  return inner?.turnRunning() ?? creating;
276920
278678
  }
@@ -276947,10 +278705,10 @@ async function runGenesisSession(options) {
276947
278705
 
276948
278706
  // src/cli/commands/code/index.ts
276949
278707
  var BRAND_ORANGE2 = "#E86B3C";
276950
- async function bootstrapApp(prompt, footer, emit, onCreated, importRepo, path, wixLaunch) {
278708
+ async function bootstrapApp(prompt, footer, emit, onCreated, importRepo, path, wixInstance) {
276951
278709
  let app;
276952
278710
  try {
276953
- app = await createAndLinkApp({ prompt, importRepo, path, wixLaunch });
278711
+ app = await createAndLinkApp({ prompt, importRepo, path, wixInstance });
276954
278712
  } catch (error) {
276955
278713
  for (const line of await githubReauthLines(error) ?? [])
276956
278714
  emit(line);
@@ -276997,8 +278755,8 @@ async function codeAction({ log }, options, appId) {
276997
278755
  linked = true;
276998
278756
  } catch {}
276999
278757
  if (linked) {
277000
- if (options.import || options.path || options.wixLaunch) {
277001
- throw new InvalidInputError("--import, --path and --wix-launch create a new app; run them outside a linked project, without --app-id.");
278758
+ if (options.import || options.path || options.wixInstance) {
278759
+ throw new InvalidInputError("--import, --path and --wix-instance create a new app; run them outside a linked project, without --app-id.");
277002
278760
  }
277003
278761
  const { id, projectRoot } = getAppContext();
277004
278762
  const state = await assertBuilderApp(id);
@@ -277021,22 +278779,25 @@ async function codeAction({ log }, options, appId) {
277021
278779
  outroMessage: `Session closed. Resume with \`base44 code --app-id ${id}\`.`
277022
278780
  };
277023
278781
  }
277024
- if (options.wixLaunch && options.import) {
277025
- throw new InvalidInputError("--wix-launch and --import are exclusive.");
278782
+ if (options.wixInstance && options.import) {
278783
+ throw new InvalidInputError("--wix-instance and --import are exclusive.");
277026
278784
  }
277027
- const wixLaunch = options.wixLaunch ? parseWixLaunchUrl(options.wixLaunch) : undefined;
278785
+ const wixInstance = options.wixInstance?.trim() ? {
278786
+ signedInstance: options.wixInstance.trim(),
278787
+ wixClientId: options.wixClientId?.trim() || undefined
278788
+ } : undefined;
277028
278789
  let created;
277029
278790
  const footer = [
277030
- chip(options.import ? repoLabel(options.import) : wixLaunch ? "web app · wix" : "web app")
278791
+ chip(options.import ? repoLabel(options.import) : wixInstance ? "web app · wix" : "web app")
277031
278792
  ];
277032
278793
  await runGenesisSession({
277033
278794
  idleHint: options.import ? "describe what to build over the repository" : "describe the app you want to build · have one already? base44 code --app-id <id>, or base44 link",
277034
278795
  creatingLabel: options.import ? "importing the repository" : "creating your app",
277035
- modeLabel: options.import ? `Repository — ${repoLabel(options.import)}` : wixLaunch ? "Web app — Wix launch (connector connected first)" : "Web app — Base44 template + builder agent",
278796
+ modeLabel: options.import ? `Repository — ${repoLabel(options.import)}` : wixInstance ? "Web app — Wix launch (connector connected first)" : "Web app — Base44 template + builder agent",
277036
278797
  footer,
277037
278798
  createApp: (prompt, emit) => bootstrapApp(prompt, footer, emit, (app) => {
277038
278799
  created = app;
277039
- }, options.import, options.path, wixLaunch)
278800
+ }, options.import, options.path, wixInstance)
277040
278801
  });
277041
278802
  if (!created) {
277042
278803
  return { outroMessage: "Session closed. No app was created." };
@@ -277048,616 +278809,10 @@ async function codeAction({ log }, options, appId) {
277048
278809
  }
277049
278810
  function getCodeCommand() {
277050
278811
  const command = new Base44Command("code", { requireAppContext: false });
277051
- command.description("Open Base44 Code, an interactive builder session. In a linked directory (or with --app-id <id>) it opens that app; anywhere else your first prompt creates one (--import <repo> to build over your own repository). Attach a directory to an existing app with base44 link.").option("--import <repo>", "Build over an existing GitHub repository instead of the Base44 template").option("--path <dir>", "Directory to link the new app to (default: the current directory when empty, else ./<name>)").option("--wix-launch <url>", "Create the new app through a Wix launch URL (your first prompt is what the agent runs)").action((ctx, options) => codeAction(ctx, options, command.optsWithGlobals().appId));
278812
+ command.description("Open Base44 Code, an interactive builder session. In a linked directory (or with --app-id <id>) it opens that app; anywhere else your first prompt creates one (--import <repo> to build over your own repository). Attach a directory to an existing app with base44 link.").option("--import <repo>", "Build over an existing GitHub repository instead of the Base44 template").option("--path <dir>", "Directory to link the new app to (default: the current directory when empty, else ./<name>)").option("--wix-instance <token>", "Create the new app through the Wix route with this signed instance (your first prompt is what the agent runs)").option("--wix-client-id <id>", "The companion OAuth app's client id").action((ctx, options) => codeAction(ctx, options, command.optsWithGlobals().appId));
277052
278813
  return command;
277053
278814
  }
277054
278815
 
277055
- // ../../node_modules/open/index.js
277056
- import process30 from "node:process";
277057
- import path16 from "node:path";
277058
- import { fileURLToPath as fileURLToPath4 } from "node:url";
277059
- import childProcess3 from "node:child_process";
277060
- import fs20, { constants as fsConstants2 } from "node:fs/promises";
277061
-
277062
- // ../../node_modules/wsl-utils/index.js
277063
- import { promisify as promisify6 } from "node:util";
277064
- import childProcess2 from "node:child_process";
277065
- import fs19, { constants as fsConstants } from "node:fs/promises";
277066
-
277067
- // ../../node_modules/is-wsl/index.js
277068
- import process24 from "node:process";
277069
- import os4 from "node:os";
277070
- import fs18 from "node:fs";
277071
-
277072
- // ../../node_modules/is-inside-container/index.js
277073
- import fs17 from "node:fs";
277074
-
277075
- // ../../node_modules/is-docker/index.js
277076
- import fs16 from "node:fs";
277077
- var isDockerCached;
277078
- function hasDockerEnv() {
277079
- try {
277080
- fs16.statSync("/.dockerenv");
277081
- return true;
277082
- } catch {
277083
- return false;
277084
- }
277085
- }
277086
- function hasDockerCGroup() {
277087
- try {
277088
- return fs16.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
277089
- } catch {
277090
- return false;
277091
- }
277092
- }
277093
- function isDocker() {
277094
- if (isDockerCached === undefined) {
277095
- isDockerCached = hasDockerEnv() || hasDockerCGroup();
277096
- }
277097
- return isDockerCached;
277098
- }
277099
-
277100
- // ../../node_modules/is-inside-container/index.js
277101
- var cachedResult;
277102
- var hasContainerEnv = () => {
277103
- try {
277104
- fs17.statSync("/run/.containerenv");
277105
- return true;
277106
- } catch {
277107
- return false;
277108
- }
277109
- };
277110
- function isInsideContainer() {
277111
- if (cachedResult === undefined) {
277112
- cachedResult = hasContainerEnv() || isDocker();
277113
- }
277114
- return cachedResult;
277115
- }
277116
-
277117
- // ../../node_modules/is-wsl/index.js
277118
- var isWsl = () => {
277119
- if (process24.platform !== "linux") {
277120
- return false;
277121
- }
277122
- if (os4.release().toLowerCase().includes("microsoft")) {
277123
- if (isInsideContainer()) {
277124
- return false;
277125
- }
277126
- return true;
277127
- }
277128
- try {
277129
- return fs18.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
277130
- } catch {
277131
- return false;
277132
- }
277133
- };
277134
- var is_wsl_default = process24.env.__IS_WSL_TEST__ ? isWsl : isWsl();
277135
-
277136
- // ../../node_modules/powershell-utils/index.js
277137
- import process25 from "node:process";
277138
- import { Buffer as Buffer7 } from "node:buffer";
277139
- import { promisify as promisify5 } from "node:util";
277140
- import childProcess from "node:child_process";
277141
- var execFile = promisify5(childProcess.execFile);
277142
- var powerShellPath = () => `${process25.env.SYSTEMROOT || process25.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
277143
- var executePowerShell = async (command, options = {}) => {
277144
- const {
277145
- powerShellPath: psPath,
277146
- ...execFileOptions
277147
- } = options;
277148
- const encodedCommand = executePowerShell.encodeCommand(command);
277149
- return execFile(psPath ?? powerShellPath(), [
277150
- ...executePowerShell.argumentsPrefix,
277151
- encodedCommand
277152
- ], {
277153
- encoding: "utf8",
277154
- ...execFileOptions
277155
- });
277156
- };
277157
- executePowerShell.argumentsPrefix = [
277158
- "-NoProfile",
277159
- "-NonInteractive",
277160
- "-ExecutionPolicy",
277161
- "Bypass",
277162
- "-EncodedCommand"
277163
- ];
277164
- executePowerShell.encodeCommand = (command) => Buffer7.from(command, "utf16le").toString("base64");
277165
- executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
277166
-
277167
- // ../../node_modules/wsl-utils/utilities.js
277168
- function parseMountPointFromConfig(content) {
277169
- for (const line of content.split(`
277170
- `)) {
277171
- if (/^\s*#/.test(line)) {
277172
- continue;
277173
- }
277174
- const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
277175
- if (!match) {
277176
- continue;
277177
- }
277178
- return match.groups.mountPoint.trim().replaceAll(/^["']|["']$/g, "");
277179
- }
277180
- }
277181
-
277182
- // ../../node_modules/wsl-utils/index.js
277183
- var execFile2 = promisify6(childProcess2.execFile);
277184
- var wslDrivesMountPoint = (() => {
277185
- const defaultMountPoint = "/mnt/";
277186
- let mountPoint;
277187
- return async function() {
277188
- if (mountPoint) {
277189
- return mountPoint;
277190
- }
277191
- const configFilePath = "/etc/wsl.conf";
277192
- let isConfigFileExists = false;
277193
- try {
277194
- await fs19.access(configFilePath, fsConstants.F_OK);
277195
- isConfigFileExists = true;
277196
- } catch {}
277197
- if (!isConfigFileExists) {
277198
- return defaultMountPoint;
277199
- }
277200
- const configContent = await fs19.readFile(configFilePath, { encoding: "utf8" });
277201
- const parsedMountPoint = parseMountPointFromConfig(configContent);
277202
- if (parsedMountPoint === undefined) {
277203
- return defaultMountPoint;
277204
- }
277205
- mountPoint = parsedMountPoint;
277206
- mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
277207
- return mountPoint;
277208
- };
277209
- })();
277210
- var powerShellPathFromWsl = async () => {
277211
- const mountPoint = await wslDrivesMountPoint();
277212
- return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
277213
- };
277214
- var powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
277215
- var canAccessPowerShellPromise;
277216
- var canAccessPowerShell = async () => {
277217
- canAccessPowerShellPromise ??= (async () => {
277218
- try {
277219
- const psPath = await powerShellPath2();
277220
- await fs19.access(psPath, fsConstants.X_OK);
277221
- return true;
277222
- } catch {
277223
- return false;
277224
- }
277225
- })();
277226
- return canAccessPowerShellPromise;
277227
- };
277228
- var wslDefaultBrowser = async () => {
277229
- const psPath = await powerShellPath2();
277230
- const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
277231
- const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
277232
- return stdout.trim();
277233
- };
277234
- var convertWslPathToWindows = async (path) => {
277235
- if (/^[a-z]+:\/\//i.test(path)) {
277236
- return path;
277237
- }
277238
- try {
277239
- const { stdout } = await execFile2("wslpath", ["-aw", path], { encoding: "utf8" });
277240
- return stdout.trim();
277241
- } catch {
277242
- return path;
277243
- }
277244
- };
277245
-
277246
- // ../../node_modules/define-lazy-prop/index.js
277247
- function defineLazyProperty(object, propertyName, valueGetter) {
277248
- const define2 = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
277249
- Object.defineProperty(object, propertyName, {
277250
- configurable: true,
277251
- enumerable: true,
277252
- get() {
277253
- const result = valueGetter();
277254
- define2(result);
277255
- return result;
277256
- },
277257
- set(value) {
277258
- define2(value);
277259
- }
277260
- });
277261
- return object;
277262
- }
277263
-
277264
- // ../../node_modules/default-browser/index.js
277265
- import { promisify as promisify10 } from "node:util";
277266
- import process28 from "node:process";
277267
- import { execFile as execFile6 } from "node:child_process";
277268
-
277269
- // ../../node_modules/default-browser-id/index.js
277270
- import { promisify as promisify7 } from "node:util";
277271
- import process26 from "node:process";
277272
- import { execFile as execFile3 } from "node:child_process";
277273
- var execFileAsync = promisify7(execFile3);
277274
- async function defaultBrowserId() {
277275
- if (process26.platform !== "darwin") {
277276
- throw new Error("macOS only");
277277
- }
277278
- const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
277279
- const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
277280
- const browserId = match?.groups.id ?? "com.apple.Safari";
277281
- if (browserId === "com.apple.safari") {
277282
- return "com.apple.Safari";
277283
- }
277284
- return browserId;
277285
- }
277286
-
277287
- // ../../node_modules/run-applescript/index.js
277288
- import process27 from "node:process";
277289
- import { promisify as promisify8 } from "node:util";
277290
- import { execFile as execFile4, execFileSync } from "node:child_process";
277291
- var execFileAsync2 = promisify8(execFile4);
277292
- async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
277293
- if (process27.platform !== "darwin") {
277294
- throw new Error("macOS only");
277295
- }
277296
- const outputArguments = humanReadableOutput ? [] : ["-ss"];
277297
- const execOptions = {};
277298
- if (signal) {
277299
- execOptions.signal = signal;
277300
- }
277301
- const { stdout } = await execFileAsync2("osascript", ["-e", script, outputArguments], execOptions);
277302
- return stdout.trim();
277303
- }
277304
-
277305
- // ../../node_modules/bundle-name/index.js
277306
- async function bundleName(bundleId) {
277307
- return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
277308
- tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
277309
- }
277310
-
277311
- // ../../node_modules/default-browser/windows.js
277312
- import { promisify as promisify9 } from "node:util";
277313
- import { execFile as execFile5 } from "node:child_process";
277314
- var execFileAsync3 = promisify9(execFile5);
277315
- var windowsBrowserProgIds = {
277316
- MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
277317
- MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
277318
- MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
277319
- AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
277320
- ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
277321
- ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
277322
- ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
277323
- ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
277324
- BraveHTML: { name: "Brave", id: "com.brave.Browser" },
277325
- BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
277326
- BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
277327
- BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
277328
- FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
277329
- OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
277330
- VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
277331
- "IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
277332
- };
277333
- var _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
277334
-
277335
- class UnknownBrowserError extends Error {
277336
- }
277337
- async function defaultBrowser(_execFileAsync = execFileAsync3) {
277338
- const { stdout } = await _execFileAsync("reg", [
277339
- "QUERY",
277340
- " HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
277341
- "/v",
277342
- "ProgId"
277343
- ]);
277344
- const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
277345
- if (!match) {
277346
- throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
277347
- }
277348
- const { id } = match.groups;
277349
- const dotIndex = id.lastIndexOf(".");
277350
- const hyphenIndex = id.lastIndexOf("-");
277351
- const baseIdByDot = dotIndex === -1 ? undefined : id.slice(0, dotIndex);
277352
- const baseIdByHyphen = hyphenIndex === -1 ? undefined : id.slice(0, hyphenIndex);
277353
- return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? { name: id, id };
277354
- }
277355
-
277356
- // ../../node_modules/default-browser/index.js
277357
- var execFileAsync4 = promisify10(execFile6);
277358
- var titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
277359
- async function defaultBrowser2() {
277360
- if (process28.platform === "darwin") {
277361
- const id = await defaultBrowserId();
277362
- const name = await bundleName(id);
277363
- return { name, id };
277364
- }
277365
- if (process28.platform === "linux") {
277366
- const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
277367
- const id = stdout.trim();
277368
- const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
277369
- return { name, id };
277370
- }
277371
- if (process28.platform === "win32") {
277372
- return defaultBrowser();
277373
- }
277374
- throw new Error("Only macOS, Linux, and Windows are supported");
277375
- }
277376
-
277377
- // ../../node_modules/is-in-ssh/index.js
277378
- import process29 from "node:process";
277379
- var isInSsh = Boolean(process29.env.SSH_CONNECTION || process29.env.SSH_CLIENT || process29.env.SSH_TTY);
277380
- var is_in_ssh_default = isInSsh;
277381
-
277382
- // ../../node_modules/open/index.js
277383
- var fallbackAttemptSymbol = Symbol("fallbackAttempt");
277384
- var __dirname2 = import.meta.url ? path16.dirname(fileURLToPath4(import.meta.url)) : "";
277385
- var localXdgOpenPath = path16.join(__dirname2, "xdg-open");
277386
- var { platform: platform7, arch } = process30;
277387
- var tryEachApp = async (apps, opener) => {
277388
- if (apps.length === 0) {
277389
- return;
277390
- }
277391
- const errors = [];
277392
- for (const app of apps) {
277393
- try {
277394
- return await opener(app);
277395
- } catch (error) {
277396
- errors.push(error);
277397
- }
277398
- }
277399
- throw new AggregateError(errors, "Failed to open in all supported apps");
277400
- };
277401
- var baseOpen = async (options) => {
277402
- options = {
277403
- wait: false,
277404
- background: false,
277405
- newInstance: false,
277406
- allowNonzeroExitCode: false,
277407
- ...options
277408
- };
277409
- const isFallbackAttempt = options[fallbackAttemptSymbol] === true;
277410
- delete options[fallbackAttemptSymbol];
277411
- if (Array.isArray(options.app)) {
277412
- return tryEachApp(options.app, (singleApp) => baseOpen({
277413
- ...options,
277414
- app: singleApp,
277415
- [fallbackAttemptSymbol]: true
277416
- }));
277417
- }
277418
- let { name: app, arguments: appArguments = [] } = options.app ?? {};
277419
- appArguments = [...appArguments];
277420
- if (Array.isArray(app)) {
277421
- return tryEachApp(app, (appName) => baseOpen({
277422
- ...options,
277423
- app: {
277424
- name: appName,
277425
- arguments: appArguments
277426
- },
277427
- [fallbackAttemptSymbol]: true
277428
- }));
277429
- }
277430
- if (app === "browser" || app === "browserPrivate") {
277431
- const ids = {
277432
- "com.google.chrome": "chrome",
277433
- "google-chrome.desktop": "chrome",
277434
- "com.brave.browser": "brave",
277435
- "org.mozilla.firefox": "firefox",
277436
- "firefox.desktop": "firefox",
277437
- "com.microsoft.msedge": "edge",
277438
- "com.microsoft.edge": "edge",
277439
- "com.microsoft.edgemac": "edge",
277440
- "microsoft-edge.desktop": "edge",
277441
- "com.apple.safari": "safari"
277442
- };
277443
- const flags = {
277444
- chrome: "--incognito",
277445
- brave: "--incognito",
277446
- firefox: "--private-window",
277447
- edge: "--inPrivate"
277448
- };
277449
- let browser;
277450
- if (is_wsl_default) {
277451
- const progId = await wslDefaultBrowser();
277452
- const browserInfo = _windowsBrowserProgIdMap.get(progId);
277453
- browser = browserInfo ?? {};
277454
- } else {
277455
- browser = await defaultBrowser2();
277456
- }
277457
- if (browser.id in ids) {
277458
- const browserName = ids[browser.id.toLowerCase()];
277459
- if (app === "browserPrivate") {
277460
- if (browserName === "safari") {
277461
- throw new Error("Safari doesn't support opening in private mode via command line");
277462
- }
277463
- appArguments.push(flags[browserName]);
277464
- }
277465
- return baseOpen({
277466
- ...options,
277467
- app: {
277468
- name: apps[browserName],
277469
- arguments: appArguments
277470
- }
277471
- });
277472
- }
277473
- throw new Error(`${browser.name} is not supported as a default browser`);
277474
- }
277475
- let command;
277476
- const cliArguments = [];
277477
- const childProcessOptions = {};
277478
- let shouldUseWindowsInWsl = false;
277479
- if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
277480
- shouldUseWindowsInWsl = await canAccessPowerShell();
277481
- }
277482
- if (platform7 === "darwin") {
277483
- command = "open";
277484
- if (options.wait) {
277485
- cliArguments.push("--wait-apps");
277486
- }
277487
- if (options.background) {
277488
- cliArguments.push("--background");
277489
- }
277490
- if (options.newInstance) {
277491
- cliArguments.push("--new");
277492
- }
277493
- if (app) {
277494
- cliArguments.push("-a", app);
277495
- }
277496
- } else if (platform7 === "win32" || shouldUseWindowsInWsl) {
277497
- command = await powerShellPath2();
277498
- cliArguments.push(...executePowerShell.argumentsPrefix);
277499
- if (!is_wsl_default) {
277500
- childProcessOptions.windowsVerbatimArguments = true;
277501
- }
277502
- if (is_wsl_default && options.target) {
277503
- options.target = await convertWslPathToWindows(options.target);
277504
- }
277505
- const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
277506
- if (options.wait) {
277507
- encodedArguments.push("-Wait");
277508
- }
277509
- if (app) {
277510
- encodedArguments.push(executePowerShell.escapeArgument(app));
277511
- if (options.target) {
277512
- appArguments.push(options.target);
277513
- }
277514
- } else if (options.target) {
277515
- encodedArguments.push(executePowerShell.escapeArgument(options.target));
277516
- }
277517
- if (appArguments.length > 0) {
277518
- appArguments = appArguments.map((argument) => executePowerShell.escapeArgument(argument));
277519
- encodedArguments.push("-ArgumentList", appArguments.join(","));
277520
- }
277521
- options.target = executePowerShell.encodeCommand(encodedArguments.join(" "));
277522
- if (!options.wait) {
277523
- childProcessOptions.stdio = "ignore";
277524
- }
277525
- } else {
277526
- if (app) {
277527
- command = app;
277528
- } else {
277529
- const isBundled = !__dirname2 || __dirname2 === "/";
277530
- let exeLocalXdgOpen = false;
277531
- try {
277532
- await fs20.access(localXdgOpenPath, fsConstants2.X_OK);
277533
- exeLocalXdgOpen = true;
277534
- } catch {}
277535
- const useSystemXdgOpen = process30.versions.electron ?? (platform7 === "android" || isBundled || !exeLocalXdgOpen);
277536
- command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
277537
- }
277538
- if (appArguments.length > 0) {
277539
- cliArguments.push(...appArguments);
277540
- }
277541
- if (!options.wait) {
277542
- childProcessOptions.stdio = "ignore";
277543
- childProcessOptions.detached = true;
277544
- }
277545
- }
277546
- if (platform7 === "darwin" && appArguments.length > 0) {
277547
- cliArguments.push("--args", ...appArguments);
277548
- }
277549
- if (options.target) {
277550
- cliArguments.push(options.target);
277551
- }
277552
- const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
277553
- if (options.wait) {
277554
- return new Promise((resolve, reject) => {
277555
- subprocess.once("error", reject);
277556
- subprocess.once("close", (exitCode) => {
277557
- if (!options.allowNonzeroExitCode && exitCode !== 0) {
277558
- reject(new Error(`Exited with code ${exitCode}`));
277559
- return;
277560
- }
277561
- resolve(subprocess);
277562
- });
277563
- });
277564
- }
277565
- if (isFallbackAttempt) {
277566
- return new Promise((resolve, reject) => {
277567
- subprocess.once("error", reject);
277568
- subprocess.once("spawn", () => {
277569
- subprocess.once("close", (exitCode) => {
277570
- subprocess.off("error", reject);
277571
- if (exitCode !== 0) {
277572
- reject(new Error(`Exited with code ${exitCode}`));
277573
- return;
277574
- }
277575
- subprocess.unref();
277576
- resolve(subprocess);
277577
- });
277578
- });
277579
- });
277580
- }
277581
- subprocess.unref();
277582
- return new Promise((resolve, reject) => {
277583
- subprocess.once("error", reject);
277584
- subprocess.once("spawn", () => {
277585
- subprocess.off("error", reject);
277586
- resolve(subprocess);
277587
- });
277588
- });
277589
- };
277590
- var open = (target, options) => {
277591
- if (typeof target !== "string") {
277592
- throw new TypeError("Expected a `target`");
277593
- }
277594
- return baseOpen({
277595
- ...options,
277596
- target
277597
- });
277598
- };
277599
- function detectArchBinary(binary) {
277600
- if (typeof binary === "string" || Array.isArray(binary)) {
277601
- return binary;
277602
- }
277603
- const { [arch]: archBinary } = binary;
277604
- if (!archBinary) {
277605
- throw new Error(`${arch} is not supported`);
277606
- }
277607
- return archBinary;
277608
- }
277609
- function detectPlatformBinary({ [platform7]: platformBinary }, { wsl } = {}) {
277610
- if (wsl && is_wsl_default) {
277611
- return detectArchBinary(wsl);
277612
- }
277613
- if (!platformBinary) {
277614
- throw new Error(`${platform7} is not supported`);
277615
- }
277616
- return detectArchBinary(platformBinary);
277617
- }
277618
- var apps = {
277619
- browser: "browser",
277620
- browserPrivate: "browserPrivate"
277621
- };
277622
- defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
277623
- darwin: "google chrome",
277624
- win32: "chrome",
277625
- linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
277626
- }, {
277627
- wsl: {
277628
- ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
277629
- x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
277630
- }
277631
- }));
277632
- defineLazyProperty(apps, "brave", () => detectPlatformBinary({
277633
- darwin: "brave browser",
277634
- win32: "brave",
277635
- linux: ["brave-browser", "brave"]
277636
- }, {
277637
- wsl: {
277638
- ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
277639
- x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
277640
- }
277641
- }));
277642
- defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
277643
- darwin: "firefox",
277644
- win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
277645
- linux: "firefox"
277646
- }, {
277647
- wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
277648
- }));
277649
- defineLazyProperty(apps, "edge", () => detectPlatformBinary({
277650
- darwin: "microsoft edge",
277651
- win32: "msedge",
277652
- linux: ["microsoft-edge", "microsoft-edge-dev"]
277653
- }, {
277654
- wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
277655
- }));
277656
- defineLazyProperty(apps, "safari", () => detectPlatformBinary({
277657
- darwin: "Safari"
277658
- }));
277659
- var open_default = open;
277660
-
277661
278816
  // src/cli/commands/connectors/oauth-prompt.ts
277662
278817
  var POLL_INTERVAL_MS = 2000;
277663
278818
  var POLL_TIMEOUT_MS2 = 2 * 60 * 1000;
@@ -279425,7 +280580,7 @@ async function callTool(appId, tool, payload, schema, context, timeout = 60000)
279425
280580
  function listDirectory(appId, params) {
279426
280581
  return callTool(appId, "list_directory", { ...params }, ListDirectoryResponseSchema, "listing directory");
279427
280582
  }
279428
- function readFile4(appId, params) {
280583
+ function readFile5(appId, params) {
279429
280584
  return callTool(appId, "read_file", { ...params }, ReadFileResponseSchema, "reading file");
279430
280585
  }
279431
280586
  function writeFile3(appId, params) {
@@ -279580,7 +280735,7 @@ async function readFileAction({ runTask, branchId }, paths, options) {
279580
280735
  const { id: appId } = getAppContext();
279581
280736
  const offset = parsePositiveInt(options.offset, "--offset");
279582
280737
  const limit = parsePositiveInt(options.limit, "--limit");
279583
- const result = await runTask("Reading file", () => readFile4(appId, { paths, offset, limit, branch_id: branchId }));
280738
+ const result = await runTask("Reading file", () => readFile5(appId, { paths, offset, limit, branch_id: branchId }));
279584
280739
  return { outroMessage: "Read file", stdout: toJsonStdout(result) };
279585
280740
  }
279586
280741
  function getSandboxReadFileCommand() {
@@ -284431,7 +285586,7 @@ async function runScript(options) {
284431
285586
  }
284432
285587
  }
284433
285588
  // src/cli/commands/exec.ts
284434
- function readStdin3() {
285589
+ function readStdin4() {
284435
285590
  return new Promise((resolve, reject) => {
284436
285591
  let data = "";
284437
285592
  process.stdin.setEncoding("utf-8");
@@ -284475,7 +285630,7 @@ async function execAction({ app, isNonInteractive }, options) {
284475
285630
  if (!isNonInteractive) {
284476
285631
  throw noInputError;
284477
285632
  }
284478
- const code = await readStdin3();
285633
+ const code = await readStdin4();
284479
285634
  if (!code.trim()) {
284480
285635
  throw noInputError;
284481
285636
  }
@@ -288656,6 +289811,13 @@ function getFullCommandName(command) {
288656
289811
  }
288657
289812
  return parts.join(" ");
288658
289813
  }
289814
+ var SENSITIVE_OPTION = /secret|token|password|launch|instance|key$/i;
289815
+ function redactSensitiveOptions(options) {
289816
+ return Object.fromEntries(Object.entries(options).map(([k, v]) => [
289817
+ k,
289818
+ SENSITIVE_OPTION.test(k) && v != null && v !== false ? "[redacted]" : v
289819
+ ]));
289820
+ }
288659
289821
  function addCommandInfoToErrorReporter(program, errorReporter) {
288660
289822
  program.hook("preAction", (_, actionCommand) => {
288661
289823
  const fullCommandName = getFullCommandName(actionCommand);
@@ -288663,7 +289825,7 @@ function addCommandInfoToErrorReporter(program, errorReporter) {
288663
289825
  command: {
288664
289826
  name: fullCommandName,
288665
289827
  args: actionCommand.args,
288666
- options: actionCommand.opts()
289828
+ options: redactSensitiveOptions(actionCommand.opts())
288667
289829
  }
288668
289830
  });
288669
289831
  });
@@ -288710,4 +289872,4 @@ export {
288710
289872
  runCLI
288711
289873
  };
288712
289874
 
288713
- //# debugId=9A8433398282BCF064756E2164756E21
289875
+ //# debugId=C63258896EE6B31064756E2164756E21