@base44-preview/cli 0.1.15-pr.630.c53fe4d → 0.1.15-pr.630.e926db5
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 +688 -57
- package/dist/cli/index.js.map +15 -13
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -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
|
|
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
|
}
|
|
@@ -270037,7 +270041,25 @@ var RESULT_LINE_MAX = 110;
|
|
|
270037
270041
|
var DIFF_LINES_MAX = 12;
|
|
270038
270042
|
var ERROR_LINES_MAX = 8;
|
|
270039
270043
|
function renderEntry(entry, options = {}) {
|
|
270040
|
-
|
|
270044
|
+
if (typeof entry === "string")
|
|
270045
|
+
return entry;
|
|
270046
|
+
if ("running" in entry)
|
|
270047
|
+
return runningLine(entry.running, entry.startedAt);
|
|
270048
|
+
return eventLine(entry.event, entry.elapsedMs, options) ?? "";
|
|
270049
|
+
}
|
|
270050
|
+
var RUNNING_DOT = "#E86B3C";
|
|
270051
|
+
var PULSE_MS = 500;
|
|
270052
|
+
function runningLine(event, startedAt, now = Date.now()) {
|
|
270053
|
+
const lit = Math.floor(now / PULSE_MS) % 2 === 0;
|
|
270054
|
+
const dot = lit ? source_default.hex(RUNNING_DOT)("●") : source_default.dim("●");
|
|
270055
|
+
const alias = toolAlias(event.name);
|
|
270056
|
+
const title = source_default.bold(event.label || alias);
|
|
270057
|
+
const inline = !event.label && event.summary ? ` ${source_default.dim(event.summary)}` : "";
|
|
270058
|
+
const seconds = Math.round((now - startedAt) / 1000);
|
|
270059
|
+
const took = seconds >= 3 ? ` ${source_default.dim(`· ${seconds}s`)}` : "";
|
|
270060
|
+
const detail = event.label && event.summary ? `
|
|
270061
|
+
${source_default.dim(`└ ${alias}: ${event.summary}`)}` : "";
|
|
270062
|
+
return `${dot} ${title}${inline}${took}${detail}`;
|
|
270041
270063
|
}
|
|
270042
270064
|
function fold2(lines, max, options) {
|
|
270043
270065
|
if (options.verbose || lines.length <= max)
|
|
@@ -270137,7 +270159,7 @@ function eventLine(event, elapsedMs, options = {}) {
|
|
|
270137
270159
|
return null;
|
|
270138
270160
|
case "waiting": {
|
|
270139
270161
|
const what = event.label || toolAlias(event.name);
|
|
270140
|
-
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"})`);
|
|
270141
270163
|
}
|
|
270142
270164
|
case "tool_end": {
|
|
270143
270165
|
const alias = toolAlias(event.name);
|
|
@@ -270186,6 +270208,14 @@ ${indent(shown)}`;
|
|
|
270186
270208
|
}
|
|
270187
270209
|
}
|
|
270188
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
|
+
}
|
|
270189
270219
|
var MUSINGS = [
|
|
270190
270220
|
"Shmoozing",
|
|
270191
270221
|
"Shmoogling",
|
|
@@ -270249,7 +270279,7 @@ function createTurnStream(interactive, write = (text) => process.stdout.write(te
|
|
|
270249
270279
|
return;
|
|
270250
270280
|
const lines = [
|
|
270251
270281
|
...footer.length ? ["", ...footer] : [],
|
|
270252
|
-
source_default.dim(`${FRAMES[frame]} ${statusLabel()}`)
|
|
270282
|
+
running.size === 0 ? `${source_default.magenta(shimmer())} ${source_default.dim(statusLabel())}` : source_default.dim(`${FRAMES[frame]} ${statusLabel()}`)
|
|
270253
270283
|
];
|
|
270254
270284
|
write(lines.join(`
|
|
270255
270285
|
`));
|
|
@@ -270325,6 +270355,10 @@ var CreatedAppSchema = object({
|
|
|
270325
270355
|
name: string2().nullish(),
|
|
270326
270356
|
imported_repo_url: string2().nullish()
|
|
270327
270357
|
});
|
|
270358
|
+
var WixCreatedAppSchema = object({
|
|
270359
|
+
app_id: string2().min(1),
|
|
270360
|
+
client_creation_id: string2().min(1)
|
|
270361
|
+
});
|
|
270328
270362
|
var AppStateSchema = object({
|
|
270329
270363
|
id: string2(),
|
|
270330
270364
|
app_type: string2().nullish(),
|
|
@@ -270364,7 +270398,8 @@ var ConversationMessageSchema = object({
|
|
|
270364
270398
|
name: string2(),
|
|
270365
270399
|
arguments_string: string2().nullish(),
|
|
270366
270400
|
status: string2().nullish(),
|
|
270367
|
-
results: unknown().nullish()
|
|
270401
|
+
results: unknown().nullish(),
|
|
270402
|
+
waiting_on: object({ kind: string2().nullish() }).nullish()
|
|
270368
270403
|
})).nullish()
|
|
270369
270404
|
});
|
|
270370
270405
|
var FullConversationSchema = object({
|
|
@@ -270381,6 +270416,24 @@ function parseOrThrow(schema, payload, what) {
|
|
|
270381
270416
|
function branchScope(branchId) {
|
|
270382
270417
|
return branchId ? { branch_id: branchId } : {};
|
|
270383
270418
|
}
|
|
270419
|
+
async function createWixLaunchedApp(options) {
|
|
270420
|
+
let response;
|
|
270421
|
+
try {
|
|
270422
|
+
response = await base44Client.post("api/wix/create-app", {
|
|
270423
|
+
timeout: false,
|
|
270424
|
+
context: { __redactBody: true },
|
|
270425
|
+
json: {
|
|
270426
|
+
prompt: options.prompt,
|
|
270427
|
+
signed_instance: options.signedInstance,
|
|
270428
|
+
...options.wixClientId ? { wix_client_id: options.wixClientId } : {}
|
|
270429
|
+
}
|
|
270430
|
+
});
|
|
270431
|
+
} catch (error) {
|
|
270432
|
+
throw await ApiError.fromHttpError(error, "creating app via Wix launch");
|
|
270433
|
+
}
|
|
270434
|
+
const created = parseOrThrow(WixCreatedAppSchema, await response.json(), "app");
|
|
270435
|
+
return { id: created.app_id, client_creation_id: created.client_creation_id };
|
|
270436
|
+
}
|
|
270384
270437
|
async function createApp(options) {
|
|
270385
270438
|
let response;
|
|
270386
270439
|
try {
|
|
@@ -270438,6 +270491,25 @@ async function getAppState(appId) {
|
|
|
270438
270491
|
}
|
|
270439
270492
|
return parseOrThrow(AppStateSchema, await response.json(), "app status");
|
|
270440
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
|
+
}
|
|
270441
270513
|
async function sendTurn(content, branchId) {
|
|
270442
270514
|
let response;
|
|
270443
270515
|
try {
|
|
@@ -270526,7 +270598,15 @@ async function createAndLinkApp(options) {
|
|
|
270526
270598
|
if (await appConfigExists(targetDir)) {
|
|
270527
270599
|
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.`);
|
|
270528
270600
|
}
|
|
270529
|
-
|
|
270601
|
+
let clientCreationId;
|
|
270602
|
+
const created = options.wixInstance ? await createWixLaunchedApp({
|
|
270603
|
+
prompt: options.prompt ?? "",
|
|
270604
|
+
signedInstance: options.wixInstance.signedInstance,
|
|
270605
|
+
wixClientId: options.wixInstance.wixClientId
|
|
270606
|
+
}).then((c) => {
|
|
270607
|
+
clientCreationId = c.client_creation_id;
|
|
270608
|
+
return c;
|
|
270609
|
+
}) : options.importRepo ? await createImportedApp({
|
|
270530
270610
|
appName: name,
|
|
270531
270611
|
repoUrl: options.importRepo,
|
|
270532
270612
|
sourceMode: options.mode ?? "direct",
|
|
@@ -270550,7 +270630,8 @@ async function createAndLinkApp(options) {
|
|
|
270550
270630
|
repoUrl: created.imported_repo_url ?? undefined,
|
|
270551
270631
|
dirName,
|
|
270552
270632
|
targetDir,
|
|
270553
|
-
here
|
|
270633
|
+
here,
|
|
270634
|
+
...clientCreationId ? { clientCreationId } : {}
|
|
270554
270635
|
};
|
|
270555
270636
|
}
|
|
270556
270637
|
function repoLabel(url) {
|
|
@@ -270902,6 +270983,12 @@ function getSendCommand() {
|
|
|
270902
270983
|
// src/cli/commands/builder/new.ts
|
|
270903
270984
|
var POLL_TIMEOUT_MS = 20 * 60000;
|
|
270904
270985
|
var MODES = ["direct", "fork", "copy"];
|
|
270986
|
+
async function readStdin2() {
|
|
270987
|
+
const chunks = [];
|
|
270988
|
+
for await (const chunk of process.stdin)
|
|
270989
|
+
chunks.push(chunk);
|
|
270990
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
270991
|
+
}
|
|
270905
270992
|
async function newAction({ log, runTask, jsonMode }, prompt, options) {
|
|
270906
270993
|
if (options.mode && !MODES.includes(options.mode)) {
|
|
270907
270994
|
throw new InvalidInputError("--mode must be direct, fork, or copy.");
|
|
@@ -270909,6 +270996,20 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
|
|
|
270909
270996
|
if ((options.mode || options.repoName || options.fromBranch) && !options.import) {
|
|
270910
270997
|
throw new InvalidInputError("--mode, --repo-name and --from-branch apply only with --import <repo>.");
|
|
270911
270998
|
}
|
|
270999
|
+
if (options.wixInstance && options.import) {
|
|
271000
|
+
throw new InvalidInputError("--wix-instance and --import are exclusive.");
|
|
271001
|
+
}
|
|
271002
|
+
if (options.wixClientId && !options.wixInstance) {
|
|
271003
|
+
throw new InvalidInputError("--wix-client-id applies only with --wix-instance.");
|
|
271004
|
+
}
|
|
271005
|
+
const signedInstance = options.wixInstance ? (options.wixInstance === "-" ? await readStdin2() : options.wixInstance).trim() : undefined;
|
|
271006
|
+
if (options.wixInstance && !signedInstance) {
|
|
271007
|
+
throw new InvalidInputError("--wix-instance is empty.");
|
|
271008
|
+
}
|
|
271009
|
+
const wixInstance = signedInstance ? { signedInstance, wixClientId: options.wixClientId?.trim() || undefined } : undefined;
|
|
271010
|
+
if (wixInstance && !prompt) {
|
|
271011
|
+
throw new InvalidInputError("--wix-instance needs the prompt argument: what the agent should build.");
|
|
271012
|
+
}
|
|
270912
271013
|
if (!prompt && !options.import) {
|
|
270913
271014
|
throw new InvalidInputError('Describe the app ("<prompt>") or pass --import <repo>.');
|
|
270914
271015
|
}
|
|
@@ -270925,7 +271026,8 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
|
|
|
270925
271026
|
mode: options.mode,
|
|
270926
271027
|
repoName: options.repoName,
|
|
270927
271028
|
fromBranch: options.fromBranch,
|
|
270928
|
-
path: options.path
|
|
271029
|
+
path: options.path,
|
|
271030
|
+
wixInstance
|
|
270929
271031
|
}));
|
|
270930
271032
|
} catch (error) {
|
|
270931
271033
|
for (const line of await githubReauthLines(error) ?? [])
|
|
@@ -270939,11 +271041,15 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
|
|
|
270939
271041
|
repo_url: app.repoUrl ?? null,
|
|
270940
271042
|
editor_url: app.editorUrl,
|
|
270941
271043
|
dir: app.dirName,
|
|
270942
|
-
path: app.targetDir
|
|
271044
|
+
path: app.targetDir,
|
|
271045
|
+
...app.clientCreationId ? { client_creation_id: app.clientCreationId } : {}
|
|
270943
271046
|
});
|
|
270944
271047
|
} else if (!jsonMode) {
|
|
270945
271048
|
if (app.repoUrl)
|
|
270946
271049
|
log.message(source_default.dim(`repo ${app.repoUrl}`));
|
|
271050
|
+
if (app.clientCreationId) {
|
|
271051
|
+
log.message(source_default.dim("wix launched — connector connected before the first turn"));
|
|
271052
|
+
}
|
|
270947
271053
|
log.message(source_default.dim(`editor ${app.editorUrl}`));
|
|
270948
271054
|
log.message(source_default.dim(`linked ${app.here ? "./ (this directory)" : `./${app.dirName}`}`));
|
|
270949
271055
|
}
|
|
@@ -270994,7 +271100,8 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
|
|
|
270994
271100
|
preview_url: previewUrl ?? null,
|
|
270995
271101
|
dir: app.dirName,
|
|
270996
271102
|
path: app.targetDir,
|
|
270997
|
-
status: finalState ?? "created"
|
|
271103
|
+
status: finalState ?? "created",
|
|
271104
|
+
...app.clientCreationId ? { client_creation_id: app.clientCreationId } : {}
|
|
270998
271105
|
})}
|
|
270999
271106
|
`
|
|
271000
271107
|
};
|
|
@@ -271019,7 +271126,7 @@ async function newAction({ log, runTask, jsonMode }, prompt, options) {
|
|
|
271019
271126
|
}
|
|
271020
271127
|
function getNewCommand() {
|
|
271021
271128
|
const command = new Base44Command("new", { requireAppContext: false });
|
|
271022
|
-
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").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);
|
|
271129
|
+
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("--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);
|
|
271023
271130
|
return command;
|
|
271024
271131
|
}
|
|
271025
271132
|
|
|
@@ -276214,6 +276321,393 @@ function createPasteFriendlyStdin(real) {
|
|
|
276214
276321
|
return proxy;
|
|
276215
276322
|
}
|
|
276216
276323
|
|
|
276324
|
+
// src/core/resources/apps/pending.ts
|
|
276325
|
+
var CHOICE_TOOLS = new Set([
|
|
276326
|
+
"ask_clarifying_questions",
|
|
276327
|
+
"ask_plan_questions"
|
|
276328
|
+
]);
|
|
276329
|
+
var SECRET_TOOLS = new Set(["set_secrets"]);
|
|
276330
|
+
var PERMISSION_TOOLS = new Set(["request_agent_tool_permissions"]);
|
|
276331
|
+
var BROWSER_TOOLS = new Set([
|
|
276332
|
+
"connect_github_account",
|
|
276333
|
+
"request_oauth_authorization",
|
|
276334
|
+
"register_workspace_connector",
|
|
276335
|
+
"configure_psp_credentials",
|
|
276336
|
+
"plaid_connect"
|
|
276337
|
+
]);
|
|
276338
|
+
var str2 = (v) => typeof v === "string" && v.trim() ? v.trim() : undefined;
|
|
276339
|
+
function parseArgs(raw) {
|
|
276340
|
+
try {
|
|
276341
|
+
const parsed = JSON.parse(raw ?? "");
|
|
276342
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
276343
|
+
} catch {
|
|
276344
|
+
return {};
|
|
276345
|
+
}
|
|
276346
|
+
}
|
|
276347
|
+
function questionsFrom(args) {
|
|
276348
|
+
const raw = Array.isArray(args.questions) ? args.questions : [];
|
|
276349
|
+
return raw.flatMap((q) => {
|
|
276350
|
+
if (!q || typeof q !== "object")
|
|
276351
|
+
return [];
|
|
276352
|
+
const item = q;
|
|
276353
|
+
const question = str2(item.question);
|
|
276354
|
+
if (!question)
|
|
276355
|
+
return [];
|
|
276356
|
+
const options = (Array.isArray(item.options) ? item.options : []).flatMap((o) => {
|
|
276357
|
+
const opt = o;
|
|
276358
|
+
const label = str2(opt?.label);
|
|
276359
|
+
return label ? [{ label, description: str2(opt.description) }] : [];
|
|
276360
|
+
});
|
|
276361
|
+
return [
|
|
276362
|
+
{
|
|
276363
|
+
question,
|
|
276364
|
+
description: str2(item.description),
|
|
276365
|
+
options,
|
|
276366
|
+
multiSelect: item.multi_select === true
|
|
276367
|
+
}
|
|
276368
|
+
];
|
|
276369
|
+
});
|
|
276370
|
+
}
|
|
276371
|
+
function secretsFrom(args) {
|
|
276372
|
+
const raw = Array.isArray(args.secrets_schema) ? args.secrets_schema : [];
|
|
276373
|
+
return raw.flatMap((s) => {
|
|
276374
|
+
const item = s;
|
|
276375
|
+
const name = str2(item?.secretName) ?? str2(item?.name);
|
|
276376
|
+
return name ? [{ name, description: str2(item.description) }] : [];
|
|
276377
|
+
});
|
|
276378
|
+
}
|
|
276379
|
+
function permissionKey(row) {
|
|
276380
|
+
switch (row.type) {
|
|
276381
|
+
case "entity":
|
|
276382
|
+
return row.entity_name ? `entity:${row.entity_name}` : null;
|
|
276383
|
+
case "backend_function":
|
|
276384
|
+
return row.function_name ? `backend_function:${row.function_name}` : null;
|
|
276385
|
+
case "app_user_connector":
|
|
276386
|
+
return row.connector_id ? `app_user_connector:${row.connector_id}` : null;
|
|
276387
|
+
default:
|
|
276388
|
+
return null;
|
|
276389
|
+
}
|
|
276390
|
+
}
|
|
276391
|
+
function permissionsFrom(args) {
|
|
276392
|
+
const raw = Array.isArray(args.requested_permissions) ? args.requested_permissions : [];
|
|
276393
|
+
return raw.flatMap((r) => {
|
|
276394
|
+
const row = r;
|
|
276395
|
+
const key = permissionKey(row);
|
|
276396
|
+
if (!key)
|
|
276397
|
+
return [];
|
|
276398
|
+
const ops = Array.isArray(row.allowed_operations) ? ` (${row.allowed_operations.join(", ")})` : "";
|
|
276399
|
+
const target = str2(row.entity_name) ?? str2(row.function_name) ?? str2(row.connector_name) ?? key;
|
|
276400
|
+
return [
|
|
276401
|
+
{ key, label: `${row.type}: ${target}${ops}`, reason: str2(row.reason) }
|
|
276402
|
+
];
|
|
276403
|
+
});
|
|
276404
|
+
}
|
|
276405
|
+
function guardFrom(results) {
|
|
276406
|
+
const value = typeof results === "string" ? (() => {
|
|
276407
|
+
try {
|
|
276408
|
+
return JSON.parse(results);
|
|
276409
|
+
} catch {
|
|
276410
|
+
return null;
|
|
276411
|
+
}
|
|
276412
|
+
})() : results;
|
|
276413
|
+
if (!value || typeof value !== "object")
|
|
276414
|
+
return null;
|
|
276415
|
+
const g = value;
|
|
276416
|
+
if (!str2(g.guard))
|
|
276417
|
+
return null;
|
|
276418
|
+
return { title: `${g.guard}: needs your approval`, detail: str2(g.reason) };
|
|
276419
|
+
}
|
|
276420
|
+
function humanize(tool) {
|
|
276421
|
+
return tool.replace(/_/g, " ");
|
|
276422
|
+
}
|
|
276423
|
+
function pendingInputs(messages) {
|
|
276424
|
+
const out = [];
|
|
276425
|
+
for (const message of messages) {
|
|
276426
|
+
for (const call of message.tool_calls ?? []) {
|
|
276427
|
+
if (call.status !== "waiting_for_user_input")
|
|
276428
|
+
continue;
|
|
276429
|
+
const args = parseArgs(call.arguments_string);
|
|
276430
|
+
const base = {
|
|
276431
|
+
toolCallId: call.id,
|
|
276432
|
+
messageId: message.id,
|
|
276433
|
+
tool: call.name
|
|
276434
|
+
};
|
|
276435
|
+
const summary = str2(args.summary);
|
|
276436
|
+
if (CHOICE_TOOLS.has(call.name)) {
|
|
276437
|
+
out.push({
|
|
276438
|
+
...base,
|
|
276439
|
+
kind: "choice",
|
|
276440
|
+
title: summary ?? "The agent has a few questions",
|
|
276441
|
+
questions: questionsFrom(args)
|
|
276442
|
+
});
|
|
276443
|
+
} else if (SECRET_TOOLS.has(call.name)) {
|
|
276444
|
+
out.push({
|
|
276445
|
+
...base,
|
|
276446
|
+
kind: "secrets",
|
|
276447
|
+
title: summary ?? "The agent needs secrets",
|
|
276448
|
+
secrets: secretsFrom(args)
|
|
276449
|
+
});
|
|
276450
|
+
} else if (PERMISSION_TOOLS.has(call.name)) {
|
|
276451
|
+
out.push({
|
|
276452
|
+
...base,
|
|
276453
|
+
kind: "permissions",
|
|
276454
|
+
title: summary ?? "Grant the app's agent these permissions?",
|
|
276455
|
+
detail: str2(args.reason),
|
|
276456
|
+
permissions: permissionsFrom(args)
|
|
276457
|
+
});
|
|
276458
|
+
} else if (BROWSER_TOOLS.has(call.name)) {
|
|
276459
|
+
out.push({
|
|
276460
|
+
...base,
|
|
276461
|
+
kind: "browser",
|
|
276462
|
+
title: summary ?? humanize(call.name),
|
|
276463
|
+
detail: str2(args.reason)
|
|
276464
|
+
});
|
|
276465
|
+
} else {
|
|
276466
|
+
const guard = guardFrom(call.results);
|
|
276467
|
+
const integration = str2(args.integration_type);
|
|
276468
|
+
out.push({
|
|
276469
|
+
...base,
|
|
276470
|
+
kind: "approval",
|
|
276471
|
+
title: guard?.title ?? (integration ? `Enable ${integration}?` : summary ?? `${humanize(call.name)}?`),
|
|
276472
|
+
detail: guard?.detail ?? (integration ? summary : undefined)
|
|
276473
|
+
});
|
|
276474
|
+
}
|
|
276475
|
+
}
|
|
276476
|
+
}
|
|
276477
|
+
return out;
|
|
276478
|
+
}
|
|
276479
|
+
function choiceAnswers(questions, selections) {
|
|
276480
|
+
const answers = questions.flatMap((q, index) => {
|
|
276481
|
+
const sel = selections[index];
|
|
276482
|
+
if (!sel || sel.labels.length === 0 && !sel.customText)
|
|
276483
|
+
return [];
|
|
276484
|
+
const answer = { question_index: index };
|
|
276485
|
+
if (q.multiSelect) {
|
|
276486
|
+
if (sel.labels.length)
|
|
276487
|
+
answer.selected_labels = sel.labels;
|
|
276488
|
+
} else if (sel.labels[0]) {
|
|
276489
|
+
answer.selected_label = sel.labels[0];
|
|
276490
|
+
}
|
|
276491
|
+
if (sel.customText)
|
|
276492
|
+
answer.custom_text = sel.customText;
|
|
276493
|
+
return [answer];
|
|
276494
|
+
});
|
|
276495
|
+
return { answers };
|
|
276496
|
+
}
|
|
276497
|
+
|
|
276498
|
+
// src/cli/commands/code/pending-card.ts
|
|
276499
|
+
function openCard(pending) {
|
|
276500
|
+
return {
|
|
276501
|
+
pending,
|
|
276502
|
+
step: 0,
|
|
276503
|
+
cursor: 0,
|
|
276504
|
+
selections: (pending.questions ?? []).map(() => ({ labels: [] })),
|
|
276505
|
+
granted: new Set((pending.permissions ?? []).map((p) => p.key)),
|
|
276506
|
+
typing: pending.kind === "secrets" ? "secret" : null,
|
|
276507
|
+
secretValues: {}
|
|
276508
|
+
};
|
|
276509
|
+
}
|
|
276510
|
+
var done = (action, input = {}) => ({ state: null, submit: { action, input } });
|
|
276511
|
+
var later = { state: null, dismissed: true };
|
|
276512
|
+
function choiceRows(state) {
|
|
276513
|
+
return (state.pending.questions?.[state.step]?.options.length ?? 0) + 1;
|
|
276514
|
+
}
|
|
276515
|
+
function advanceChoice(state) {
|
|
276516
|
+
const questions = state.pending.questions ?? [];
|
|
276517
|
+
if (state.step + 1 < questions.length) {
|
|
276518
|
+
return {
|
|
276519
|
+
state: { ...state, step: state.step + 1, cursor: 0, typing: null }
|
|
276520
|
+
};
|
|
276521
|
+
}
|
|
276522
|
+
return done("approved", choiceAnswers(questions, state.selections));
|
|
276523
|
+
}
|
|
276524
|
+
function choiceKey(state, key) {
|
|
276525
|
+
const question = state.pending.questions?.[state.step];
|
|
276526
|
+
if (!question)
|
|
276527
|
+
return done("approved", { answers: [] });
|
|
276528
|
+
const rows = choiceRows(state);
|
|
276529
|
+
const custom = state.cursor === rows - 1;
|
|
276530
|
+
const sel = state.selections[state.step] ?? { labels: [] };
|
|
276531
|
+
const setSel = (next) => {
|
|
276532
|
+
const selections = [...state.selections];
|
|
276533
|
+
selections[state.step] = next;
|
|
276534
|
+
return { ...state, selections };
|
|
276535
|
+
};
|
|
276536
|
+
switch (key) {
|
|
276537
|
+
case "up":
|
|
276538
|
+
return { state: { ...state, cursor: (state.cursor - 1 + rows) % rows } };
|
|
276539
|
+
case "down":
|
|
276540
|
+
return { state: { ...state, cursor: (state.cursor + 1) % rows } };
|
|
276541
|
+
case "space": {
|
|
276542
|
+
if (custom)
|
|
276543
|
+
return { state: { ...state, typing: "custom" } };
|
|
276544
|
+
const label = question.options[state.cursor].label;
|
|
276545
|
+
const labels = question.multiSelect ? sel.labels.includes(label) ? sel.labels.filter((l) => l !== label) : [...sel.labels, label] : [label];
|
|
276546
|
+
return { state: setSel({ ...sel, labels }) };
|
|
276547
|
+
}
|
|
276548
|
+
case "enter": {
|
|
276549
|
+
if (custom)
|
|
276550
|
+
return { state: { ...state, typing: "custom" } };
|
|
276551
|
+
if (question.multiSelect) {
|
|
276552
|
+
if (sel.labels.length === 0 && !sel.customText)
|
|
276553
|
+
return { state };
|
|
276554
|
+
return advanceChoice(state);
|
|
276555
|
+
}
|
|
276556
|
+
const label = question.options[state.cursor].label;
|
|
276557
|
+
return advanceChoice(setSel({ labels: [label] }));
|
|
276558
|
+
}
|
|
276559
|
+
case "s":
|
|
276560
|
+
return done("approved", { answers: [] });
|
|
276561
|
+
case "escape":
|
|
276562
|
+
return later;
|
|
276563
|
+
default:
|
|
276564
|
+
return { state };
|
|
276565
|
+
}
|
|
276566
|
+
}
|
|
276567
|
+
function permissionsKey(state, key) {
|
|
276568
|
+
const rows = state.pending.permissions ?? [];
|
|
276569
|
+
switch (key) {
|
|
276570
|
+
case "up":
|
|
276571
|
+
return {
|
|
276572
|
+
state: {
|
|
276573
|
+
...state,
|
|
276574
|
+
cursor: (state.cursor - 1 + rows.length) % rows.length
|
|
276575
|
+
}
|
|
276576
|
+
};
|
|
276577
|
+
case "down":
|
|
276578
|
+
return { state: { ...state, cursor: (state.cursor + 1) % rows.length } };
|
|
276579
|
+
case "space": {
|
|
276580
|
+
const k = rows[state.cursor]?.key;
|
|
276581
|
+
if (!k)
|
|
276582
|
+
return { state };
|
|
276583
|
+
const granted = new Set(state.granted);
|
|
276584
|
+
if (granted.has(k))
|
|
276585
|
+
granted.delete(k);
|
|
276586
|
+
else
|
|
276587
|
+
granted.add(k);
|
|
276588
|
+
return { state: { ...state, granted } };
|
|
276589
|
+
}
|
|
276590
|
+
case "enter":
|
|
276591
|
+
case "y":
|
|
276592
|
+
return done("approved", {
|
|
276593
|
+
approved_permission_keys: rows.map((r) => r.key).filter((k) => state.granted.has(k))
|
|
276594
|
+
});
|
|
276595
|
+
case "n":
|
|
276596
|
+
return done("rejected");
|
|
276597
|
+
case "escape":
|
|
276598
|
+
return later;
|
|
276599
|
+
default:
|
|
276600
|
+
return { state };
|
|
276601
|
+
}
|
|
276602
|
+
}
|
|
276603
|
+
function cardKey(state, key) {
|
|
276604
|
+
if (state.typing) {
|
|
276605
|
+
if (key === "escape") {
|
|
276606
|
+
return state.typing === "secret" ? later : { state: { ...state, typing: null } };
|
|
276607
|
+
}
|
|
276608
|
+
return { state };
|
|
276609
|
+
}
|
|
276610
|
+
switch (state.pending.kind) {
|
|
276611
|
+
case "choice":
|
|
276612
|
+
return choiceKey(state, key);
|
|
276613
|
+
case "permissions":
|
|
276614
|
+
return permissionsKey(state, key);
|
|
276615
|
+
default:
|
|
276616
|
+
if (key === "y" || key === "enter")
|
|
276617
|
+
return done("approved");
|
|
276618
|
+
if (key === "n")
|
|
276619
|
+
return done("rejected");
|
|
276620
|
+
if (key === "escape")
|
|
276621
|
+
return later;
|
|
276622
|
+
return { state };
|
|
276623
|
+
}
|
|
276624
|
+
}
|
|
276625
|
+
function cardText(state, text) {
|
|
276626
|
+
const value = text.trim();
|
|
276627
|
+
if (state.typing === "custom") {
|
|
276628
|
+
if (!value)
|
|
276629
|
+
return { state: { ...state, typing: null } };
|
|
276630
|
+
const selections = [...state.selections];
|
|
276631
|
+
const current = selections[state.step] ?? { labels: [] };
|
|
276632
|
+
selections[state.step] = { ...current, customText: value };
|
|
276633
|
+
return advanceChoice({ ...state, selections, typing: null });
|
|
276634
|
+
}
|
|
276635
|
+
if (state.typing === "secret") {
|
|
276636
|
+
const fields = state.pending.secrets ?? [];
|
|
276637
|
+
const field = fields[state.step];
|
|
276638
|
+
if (!field || !value)
|
|
276639
|
+
return { state };
|
|
276640
|
+
const secretValues = { ...state.secretValues, [field.name]: value };
|
|
276641
|
+
if (state.step + 1 < fields.length) {
|
|
276642
|
+
return { state: { ...state, secretValues, step: state.step + 1 } };
|
|
276643
|
+
}
|
|
276644
|
+
return done("approved", { secrets: secretValues });
|
|
276645
|
+
}
|
|
276646
|
+
return { state };
|
|
276647
|
+
}
|
|
276648
|
+
function cardLines(state) {
|
|
276649
|
+
const p = state.pending;
|
|
276650
|
+
const head = [source_default.bold(`⏸ ${p.title}`)];
|
|
276651
|
+
if (p.detail)
|
|
276652
|
+
head.push(source_default.dim(` ${p.detail}`));
|
|
276653
|
+
switch (p.kind) {
|
|
276654
|
+
case "choice": {
|
|
276655
|
+
const q = p.questions?.[state.step];
|
|
276656
|
+
if (!q)
|
|
276657
|
+
return [...head, source_default.dim(" (no questions) · Enter to continue")];
|
|
276658
|
+
const total = p.questions?.length ?? 1;
|
|
276659
|
+
const sel = state.selections[state.step] ?? { labels: [] };
|
|
276660
|
+
const rows = q.options.map((o, i) => {
|
|
276661
|
+
const on = sel.labels.includes(o.label);
|
|
276662
|
+
const mark = q.multiSelect ? on ? "☑" : "☐" : on ? "●" : "○";
|
|
276663
|
+
const text = `${state.cursor === i ? "▸" : " "} ${mark} ${o.label}${o.description ? source_default.dim(` — ${o.description}`) : ""}`;
|
|
276664
|
+
return state.cursor === i ? source_default.cyan(text) : text;
|
|
276665
|
+
});
|
|
276666
|
+
const customRow = `${state.cursor === q.options.length ? "▸" : " "} ✎ something else${sel.customText ? source_default.dim(` — ${sel.customText}`) : ""}`;
|
|
276667
|
+
rows.push(state.cursor === q.options.length ? source_default.cyan(customRow) : customRow);
|
|
276668
|
+
return [
|
|
276669
|
+
...head,
|
|
276670
|
+
` ${source_default.bold(q.question)} ${source_default.dim(`(${state.step + 1}/${total})`)}`,
|
|
276671
|
+
...q.description ? [source_default.dim(` ${q.description}`)] : [],
|
|
276672
|
+
...rows.map((r) => ` ${r}`),
|
|
276673
|
+
source_default.dim(q.multiSelect ? " ↑↓ move · space toggle · Enter next · s skip all · Esc later" : " ↑↓ move · Enter choose · s skip all · Esc later")
|
|
276674
|
+
];
|
|
276675
|
+
}
|
|
276676
|
+
case "permissions": {
|
|
276677
|
+
const rows = (p.permissions ?? []).map((r, i) => {
|
|
276678
|
+
const text = `${state.cursor === i ? "▸" : " "} ${state.granted.has(r.key) ? "☑" : "☐"} ${r.label}${r.reason ? source_default.dim(` — ${r.reason}`) : ""}`;
|
|
276679
|
+
return ` ${state.cursor === i ? source_default.cyan(text) : text}`;
|
|
276680
|
+
});
|
|
276681
|
+
return [
|
|
276682
|
+
...head,
|
|
276683
|
+
...rows,
|
|
276684
|
+
source_default.dim(" space toggle · Enter grant ticked · n reject all · Esc later")
|
|
276685
|
+
];
|
|
276686
|
+
}
|
|
276687
|
+
case "secrets": {
|
|
276688
|
+
const fields = p.secrets ?? [];
|
|
276689
|
+
const rows = fields.map((f, i) => {
|
|
276690
|
+
const filled = f.name in state.secretValues;
|
|
276691
|
+
const mark = filled ? source_default.green("✓") : i === state.step ? "▸" : "○";
|
|
276692
|
+
return ` ${mark} ${f.name}${f.description ? source_default.dim(` — ${f.description}`) : ""}`;
|
|
276693
|
+
});
|
|
276694
|
+
return [
|
|
276695
|
+
...head,
|
|
276696
|
+
...rows,
|
|
276697
|
+
source_default.dim(" type the value below (hidden) · Enter next · Esc later")
|
|
276698
|
+
];
|
|
276699
|
+
}
|
|
276700
|
+
case "browser":
|
|
276701
|
+
return [
|
|
276702
|
+
...head,
|
|
276703
|
+
source_default.dim(" finish this step in the editor (footer link), then press y"),
|
|
276704
|
+
source_default.dim(" y continue · n reject · Esc later")
|
|
276705
|
+
];
|
|
276706
|
+
default:
|
|
276707
|
+
return [...head, source_default.dim(" y approve · n reject · Esc later")];
|
|
276708
|
+
}
|
|
276709
|
+
}
|
|
276710
|
+
|
|
276217
276711
|
// src/cli/commands/code/session-engine.ts
|
|
276218
276712
|
var POLL_MS = 1000;
|
|
276219
276713
|
function createSessionEngine(options) {
|
|
@@ -276233,6 +276727,28 @@ function createSessionEngine(options) {
|
|
|
276233
276727
|
let awaitingTurn = options.awaitingTurnLabel ?? null;
|
|
276234
276728
|
const awaitingSince = Date.now();
|
|
276235
276729
|
let lastEventAt = Date.now();
|
|
276730
|
+
let pending = [];
|
|
276731
|
+
const answered = new Set;
|
|
276732
|
+
const answer = (p, action, input = {}) => {
|
|
276733
|
+
answered.add(p.toolCallId);
|
|
276734
|
+
pending = pending.filter((x) => x.toolCallId !== p.toolCallId);
|
|
276735
|
+
const verb = action === "rejected" ? source_default.red("✗ rejected") : Object.keys(input).length ? source_default.green("→ answered") : source_default.green("✓ approved");
|
|
276736
|
+
options.onLine(`${verb} ${source_default.dim("—")} ${p.title}`);
|
|
276737
|
+
pendingSubmitAt = Date.now();
|
|
276738
|
+
sendsInFlight++;
|
|
276739
|
+
answerToolCall({ toolCallId: p.toolCallId, messageId: p.messageId, action, input }, options.branchId).catch((error) => {
|
|
276740
|
+
const status = error instanceof ApiError ? error.statusCode : undefined;
|
|
276741
|
+
const edgeDrop = status === 502 || status === 503 || status === 504 || /timeout|gateway/i.test(error instanceof Error ? error.message : "");
|
|
276742
|
+
if (edgeDrop && (turnStartedAt != null || pendingSubmitAt == null)) {
|
|
276743
|
+
return;
|
|
276744
|
+
}
|
|
276745
|
+
answered.delete(p.toolCallId);
|
|
276746
|
+
pendingSubmitAt = null;
|
|
276747
|
+
options.onLine(source_default.red(`✗ answer failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
276748
|
+
}).finally(() => {
|
|
276749
|
+
sendsInFlight--;
|
|
276750
|
+
});
|
|
276751
|
+
};
|
|
276236
276752
|
const submit = (raw) => {
|
|
276237
276753
|
const typed = raw.trim();
|
|
276238
276754
|
if (!typed)
|
|
@@ -276273,15 +276789,23 @@ function createSessionEngine(options) {
|
|
|
276273
276789
|
return;
|
|
276274
276790
|
}
|
|
276275
276791
|
const events = diffConversation(diffState, messages);
|
|
276792
|
+
const waiting = pendingInputs(messages);
|
|
276793
|
+
for (const id of answered) {
|
|
276794
|
+
if (!waiting.some((w) => w.toolCallId === id))
|
|
276795
|
+
answered.delete(id);
|
|
276796
|
+
}
|
|
276797
|
+
pending = waiting.filter((w) => !answered.has(w.toolCallId));
|
|
276276
276798
|
if (!prime) {
|
|
276277
276799
|
for (const event of events) {
|
|
276278
276800
|
if (event.kind === "tool_start") {
|
|
276801
|
+
const startedAt = Date.now();
|
|
276279
276802
|
running.set(event.id, {
|
|
276280
276803
|
alias: toolAlias(event.name),
|
|
276281
276804
|
label: event.label,
|
|
276282
276805
|
summary: event.summary,
|
|
276283
|
-
startedAt
|
|
276806
|
+
startedAt
|
|
276284
276807
|
});
|
|
276808
|
+
options.onLine({ running: event, startedAt });
|
|
276285
276809
|
continue;
|
|
276286
276810
|
}
|
|
276287
276811
|
if (event.kind === "tool_end") {
|
|
@@ -276294,7 +276818,9 @@ function createSessionEngine(options) {
|
|
|
276294
276818
|
});
|
|
276295
276819
|
continue;
|
|
276296
276820
|
}
|
|
276297
|
-
const line = eventLine(event
|
|
276821
|
+
const line = eventLine(event, undefined, {
|
|
276822
|
+
waitingHint: "answer in the card below"
|
|
276823
|
+
});
|
|
276298
276824
|
if (line != null) {
|
|
276299
276825
|
lastEventAt = Date.now();
|
|
276300
276826
|
options.onLine(line);
|
|
@@ -276361,6 +276887,7 @@ function createSessionEngine(options) {
|
|
|
276361
276887
|
});
|
|
276362
276888
|
},
|
|
276363
276889
|
submit,
|
|
276890
|
+
answer,
|
|
276364
276891
|
status() {
|
|
276365
276892
|
let phase = "idle";
|
|
276366
276893
|
if (awaitingTurn != null)
|
|
@@ -276383,7 +276910,8 @@ function createSessionEngine(options) {
|
|
|
276383
276910
|
turnStartedAt,
|
|
276384
276911
|
runningTool,
|
|
276385
276912
|
lastTurnMs,
|
|
276386
|
-
lastTurnOk
|
|
276913
|
+
lastTurnOk,
|
|
276914
|
+
pending
|
|
276387
276915
|
};
|
|
276388
276916
|
},
|
|
276389
276917
|
turnRunning() {
|
|
@@ -276415,6 +276943,17 @@ function exitAltScreen() {
|
|
|
276415
276943
|
altScreenActive = false;
|
|
276416
276944
|
process.stdout.write("\x1B[?1007l\x1B[?1049l");
|
|
276417
276945
|
}
|
|
276946
|
+
function withEntry(items, entry) {
|
|
276947
|
+
if (typeof entry !== "string" && "event" in entry) {
|
|
276948
|
+
const i = items.findIndex((e) => typeof e !== "string" && ("running" in e) && e.running.id === entry.event.id);
|
|
276949
|
+
if (i >= 0) {
|
|
276950
|
+
const next = [...items];
|
|
276951
|
+
next[i] = entry;
|
|
276952
|
+
return next;
|
|
276953
|
+
}
|
|
276954
|
+
}
|
|
276955
|
+
return [...items, entry];
|
|
276956
|
+
}
|
|
276418
276957
|
function statusText(status, musingSeed) {
|
|
276419
276958
|
const frame = FRAMES2[Math.floor(Date.now() / 120) % FRAMES2.length];
|
|
276420
276959
|
switch (status.phase) {
|
|
@@ -276422,15 +276961,8 @@ function statusText(status, musingSeed) {
|
|
|
276422
276961
|
return source_default.dim(`${frame} ${status.awaitingLabel} (${formatDuration2(Date.now() - status.awaitingSince)})`);
|
|
276423
276962
|
case "running": {
|
|
276424
276963
|
const turnFor = formatDuration2(Date.now() - (status.turnStartedAt ?? Date.now()));
|
|
276425
|
-
const tool = status.runningTool;
|
|
276426
|
-
if (tool) {
|
|
276427
|
-
const toolFor = Math.round((Date.now() - tool.startedAt) / 1000);
|
|
276428
|
-
const others = tool.others > 0 ? ` (+${tool.others})` : "";
|
|
276429
|
-
const what = tool.label || `${tool.alias}${tool.summary ? ` ${tool.summary}` : ""}`;
|
|
276430
|
-
return source_default.dim(`${frame} ${what}${others} · ${toolFor}s (turn ${turnFor})`);
|
|
276431
|
-
}
|
|
276432
276964
|
const quiet = status.quietForMs > 60000 ? " · a long private step — details render in the editor" : "";
|
|
276433
|
-
return `${source_default.magenta(
|
|
276965
|
+
return `${source_default.magenta(shimmer())} ${source_default.dim(`${idleMusing(musingSeed)} (${turnFor})${quiet}`)}`;
|
|
276434
276966
|
}
|
|
276435
276967
|
case "sending":
|
|
276436
276968
|
return source_default.dim(`${frame} sending…`);
|
|
@@ -276451,10 +276983,12 @@ function SessionView({ engine, footer, subscribe }) {
|
|
|
276451
276983
|
const [musingSeed] = import_react23.useState(() => Math.floor(Math.random() * 97));
|
|
276452
276984
|
const [currentModel, setCurrentModel] = import_react23.useState(null);
|
|
276453
276985
|
const [pickerIndex, setPickerIndex] = import_react23.useState(null);
|
|
276986
|
+
const [card, setCard] = import_react23.useState(null);
|
|
276987
|
+
const dismissedRef = import_react23.useRef(new Set);
|
|
276454
276988
|
const maxScrollRef = import_react23.useRef(0);
|
|
276455
276989
|
const meIdRef = import_react23.useRef(null);
|
|
276456
|
-
const emit = (entry) => setItems((h) =>
|
|
276457
|
-
import_react23.useEffect(() => subscribe((entry) => setItems((h) =>
|
|
276990
|
+
const emit = (entry) => setItems((h) => withEntry(h, entry));
|
|
276991
|
+
import_react23.useEffect(() => subscribe((entry) => setItems((h) => withEntry(h, entry))), [subscribe]);
|
|
276458
276992
|
import_react23.useEffect(() => {
|
|
276459
276993
|
const timer = setInterval(tick, 120);
|
|
276460
276994
|
return () => clearInterval(timer);
|
|
@@ -276496,6 +277030,29 @@ function SessionView({ engine, footer, subscribe }) {
|
|
|
276496
277030
|
emit(source_default.red(` /model: ${error instanceof Error ? error.message : String(error)}`));
|
|
276497
277031
|
}
|
|
276498
277032
|
};
|
|
277033
|
+
const applyCard = (outcome) => {
|
|
277034
|
+
if (outcome.submit && card) {
|
|
277035
|
+
engine.answer(card.pending, outcome.submit.action, outcome.submit.input);
|
|
277036
|
+
}
|
|
277037
|
+
if (outcome.dismissed && card) {
|
|
277038
|
+
dismissedRef.current.add(card.pending.toolCallId);
|
|
277039
|
+
}
|
|
277040
|
+
setCard(outcome.state);
|
|
277041
|
+
};
|
|
277042
|
+
const pending = engine.status().pending;
|
|
277043
|
+
import_react23.useEffect(() => {
|
|
277044
|
+
if (card) {
|
|
277045
|
+
if (!pending.some((p) => p.toolCallId === card.pending.toolCallId)) {
|
|
277046
|
+
setCard(null);
|
|
277047
|
+
}
|
|
277048
|
+
return;
|
|
277049
|
+
}
|
|
277050
|
+
if (pickerIndex !== null)
|
|
277051
|
+
return;
|
|
277052
|
+
const next = pending.find((p) => !dismissedRef.current.has(p.toolCallId));
|
|
277053
|
+
if (next)
|
|
277054
|
+
setCard(openCard(next));
|
|
277055
|
+
}, [pending, card, pickerIndex]);
|
|
276499
277056
|
use_input_default((char, key) => {
|
|
276500
277057
|
if (pickerIndex !== null) {
|
|
276501
277058
|
if (key.upArrow)
|
|
@@ -276511,6 +277068,23 @@ function SessionView({ engine, footer, subscribe }) {
|
|
|
276511
277068
|
}
|
|
276512
277069
|
return;
|
|
276513
277070
|
}
|
|
277071
|
+
if (key.tab && !card) {
|
|
277072
|
+
const next = pending.find((p) => dismissedRef.current.has(p.toolCallId));
|
|
277073
|
+
if (next) {
|
|
277074
|
+
dismissedRef.current.delete(next.toolCallId);
|
|
277075
|
+
setCard(openCard(next));
|
|
277076
|
+
}
|
|
277077
|
+
return;
|
|
277078
|
+
}
|
|
277079
|
+
if (card) {
|
|
277080
|
+
const mapped = key.upArrow ? "up" : key.downArrow ? "down" : key.return ? "enter" : key.escape ? "escape" : char === " " ? "space" : char === "y" || char === "n" || char === "s" ? char : null;
|
|
277081
|
+
if (card.typing && mapped !== "escape")
|
|
277082
|
+
return;
|
|
277083
|
+
if (mapped)
|
|
277084
|
+
applyCard(cardKey(card, mapped));
|
|
277085
|
+
if (mapped || !card.typing)
|
|
277086
|
+
return;
|
|
277087
|
+
}
|
|
276514
277088
|
if (key.ctrl && char === "c") {
|
|
276515
277089
|
if (input)
|
|
276516
277090
|
setInput("");
|
|
@@ -276555,7 +277129,9 @@ function SessionView({ engine, footer, subscribe }) {
|
|
|
276555
277129
|
const innerWidth = Math.max(10, width - 4);
|
|
276556
277130
|
const inputRows = Math.max(1, Math.ceil((input.length + 3) / innerWidth));
|
|
276557
277131
|
const pickerOpen = pickerIndex !== null;
|
|
276558
|
-
const
|
|
277132
|
+
const cardOpen = card !== null && !card.typing;
|
|
277133
|
+
const cardRows = card ? cardLines(card).length : 0;
|
|
277134
|
+
const inputBlockHeight = pickerOpen ? MODELS.length + 3 : cardOpen ? cardRows + 2 : inputRows + 2 + (card?.typing ? 1 : 0);
|
|
276559
277135
|
const widgetHeight = inputBlockHeight + 3 + (footer.length ? 1 : 0);
|
|
276560
277136
|
const viewHeight = Math.max(3, rows - widgetHeight - 1);
|
|
276561
277137
|
const lines = items.flatMap((item) => hardWrapAnsi(`${renderEntry(item, { verbose, foldHint: "Ctrl+O to expand" })}
|
|
@@ -276606,29 +277182,64 @@ function SessionView({ engine, footer, subscribe }) {
|
|
|
276606
277182
|
}, m.name, false, undefined, this);
|
|
276607
277183
|
})
|
|
276608
277184
|
]
|
|
276609
|
-
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
277185
|
+
}, undefined, true, undefined, this) : cardOpen && card ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
277186
|
+
flexDirection: "column",
|
|
277187
|
+
borderStyle: "round",
|
|
277188
|
+
borderColor: "yellow",
|
|
277189
|
+
paddingX: 1,
|
|
277190
|
+
width,
|
|
277191
|
+
children: cardLines(card).map((line, i) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
277192
|
+
wrap: "truncate-end",
|
|
277193
|
+
children: line
|
|
277194
|
+
}, i, false, undefined, this))
|
|
277195
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
277196
|
+
flexDirection: "column",
|
|
276610
277197
|
borderStyle: "round",
|
|
276611
|
-
borderColor: "gray",
|
|
277198
|
+
borderColor: card?.typing ? "yellow" : "gray",
|
|
276612
277199
|
paddingX: 1,
|
|
276613
277200
|
width,
|
|
276614
277201
|
children: [
|
|
276615
|
-
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
276616
|
-
|
|
276617
|
-
children:
|
|
276618
|
-
|
|
276619
|
-
|
|
276620
|
-
|
|
276621
|
-
|
|
276622
|
-
|
|
276623
|
-
|
|
276624
|
-
|
|
276625
|
-
|
|
276626
|
-
|
|
276627
|
-
|
|
276628
|
-
|
|
276629
|
-
|
|
276630
|
-
|
|
276631
|
-
|
|
277202
|
+
card?.typing === "secret" && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
277203
|
+
wrap: "truncate-end",
|
|
277204
|
+
children: [
|
|
277205
|
+
source_default.bold(card.pending.secrets?.[card.step]?.name ?? "secret"),
|
|
277206
|
+
source_default.dim(" — value is hidden · Enter to save · Esc to cancel")
|
|
277207
|
+
]
|
|
277208
|
+
}, undefined, true, undefined, this),
|
|
277209
|
+
card?.typing === "custom" && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
277210
|
+
wrap: "truncate-end",
|
|
277211
|
+
children: [
|
|
277212
|
+
source_default.bold(card.pending.questions?.[card.step]?.question ?? ""),
|
|
277213
|
+
source_default.dim(" — your own answer · Enter to save · Esc to go back")
|
|
277214
|
+
]
|
|
277215
|
+
}, undefined, true, undefined, this),
|
|
277216
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
277217
|
+
children: [
|
|
277218
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
277219
|
+
color: "cyan",
|
|
277220
|
+
children: "❯ "
|
|
277221
|
+
}, undefined, false, undefined, this),
|
|
277222
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(build_default, {
|
|
277223
|
+
value: input,
|
|
277224
|
+
onChange: setInput,
|
|
277225
|
+
mask: card?.typing === "secret" ? "•" : undefined,
|
|
277226
|
+
onSubmit: (value) => {
|
|
277227
|
+
if (card?.typing) {
|
|
277228
|
+
applyCard(cardText(card, value));
|
|
277229
|
+
setInput("");
|
|
277230
|
+
return;
|
|
277231
|
+
}
|
|
277232
|
+
const trimmed = value.trim();
|
|
277233
|
+
if (trimmed === "/model" || trimmed.startsWith("/model ")) {
|
|
277234
|
+
runModelSlash(trimmed.slice("/model".length).trim());
|
|
277235
|
+
} else if (trimmed) {
|
|
277236
|
+
engine.submit(value);
|
|
277237
|
+
}
|
|
277238
|
+
setInput("");
|
|
277239
|
+
}
|
|
277240
|
+
}, undefined, false, undefined, this)
|
|
277241
|
+
]
|
|
277242
|
+
}, undefined, true, undefined, this)
|
|
276632
277243
|
]
|
|
276633
277244
|
}, undefined, true, undefined, this),
|
|
276634
277245
|
footer.length > 0 && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
@@ -276642,7 +277253,7 @@ function SessionView({ engine, footer, subscribe }) {
|
|
|
276642
277253
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
276643
277254
|
dimColor: true,
|
|
276644
277255
|
wrap: "truncate-end",
|
|
276645
|
-
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"
|
|
277256
|
+
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"
|
|
276646
277257
|
}, undefined, false, undefined, this)
|
|
276647
277258
|
]
|
|
276648
277259
|
}, undefined, true, undefined, this);
|
|
@@ -276767,6 +277378,7 @@ async function runGenesisSession(options) {
|
|
|
276767
277378
|
runningTool: null,
|
|
276768
277379
|
lastTurnMs: null,
|
|
276769
277380
|
lastTurnOk: true,
|
|
277381
|
+
pending: [],
|
|
276770
277382
|
quietForMs: 0
|
|
276771
277383
|
};
|
|
276772
277384
|
const genesis = {
|
|
@@ -276822,6 +277434,9 @@ async function runGenesisSession(options) {
|
|
|
276822
277434
|
}
|
|
276823
277435
|
return IDLE_STATUS;
|
|
276824
277436
|
},
|
|
277437
|
+
answer(p, action, input) {
|
|
277438
|
+
inner?.answer(p, action, input);
|
|
277439
|
+
},
|
|
276825
277440
|
turnRunning() {
|
|
276826
277441
|
return inner?.turnRunning() ?? creating;
|
|
276827
277442
|
}
|
|
@@ -276854,10 +277469,10 @@ async function runGenesisSession(options) {
|
|
|
276854
277469
|
|
|
276855
277470
|
// src/cli/commands/code/index.ts
|
|
276856
277471
|
var BRAND_ORANGE2 = "#E86B3C";
|
|
276857
|
-
async function bootstrapApp(prompt, footer, emit, onCreated, importRepo, path) {
|
|
277472
|
+
async function bootstrapApp(prompt, footer, emit, onCreated, importRepo, path, wixInstance) {
|
|
276858
277473
|
let app;
|
|
276859
277474
|
try {
|
|
276860
|
-
app = await createAndLinkApp({ prompt, importRepo, path });
|
|
277475
|
+
app = await createAndLinkApp({ prompt, importRepo, path, wixInstance });
|
|
276861
277476
|
} catch (error) {
|
|
276862
277477
|
for (const line of await githubReauthLines(error) ?? [])
|
|
276863
277478
|
emit(line);
|
|
@@ -276904,8 +277519,8 @@ async function codeAction({ log }, options, appId) {
|
|
|
276904
277519
|
linked = true;
|
|
276905
277520
|
} catch {}
|
|
276906
277521
|
if (linked) {
|
|
276907
|
-
if (options.import || options.path) {
|
|
276908
|
-
throw new InvalidInputError("--import and --
|
|
277522
|
+
if (options.import || options.path || options.wixInstance) {
|
|
277523
|
+
throw new InvalidInputError("--import, --path and --wix-instance create a new app; run them outside a linked project, without --app-id.");
|
|
276909
277524
|
}
|
|
276910
277525
|
const { id, projectRoot } = getAppContext();
|
|
276911
277526
|
const state = await assertBuilderApp(id);
|
|
@@ -276928,16 +277543,25 @@ async function codeAction({ log }, options, appId) {
|
|
|
276928
277543
|
outroMessage: `Session closed. Resume with \`base44 code --app-id ${id}\`.`
|
|
276929
277544
|
};
|
|
276930
277545
|
}
|
|
277546
|
+
if (options.wixInstance && options.import) {
|
|
277547
|
+
throw new InvalidInputError("--wix-instance and --import are exclusive.");
|
|
277548
|
+
}
|
|
277549
|
+
const wixInstance = options.wixInstance?.trim() ? {
|
|
277550
|
+
signedInstance: options.wixInstance.trim(),
|
|
277551
|
+
wixClientId: options.wixClientId?.trim() || undefined
|
|
277552
|
+
} : undefined;
|
|
276931
277553
|
let created;
|
|
276932
|
-
const footer = [
|
|
277554
|
+
const footer = [
|
|
277555
|
+
chip(options.import ? repoLabel(options.import) : wixInstance ? "web app · wix" : "web app")
|
|
277556
|
+
];
|
|
276933
277557
|
await runGenesisSession({
|
|
276934
277558
|
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",
|
|
276935
277559
|
creatingLabel: options.import ? "importing the repository" : "creating your app",
|
|
276936
|
-
modeLabel: options.import ? `Repository — ${repoLabel(options.import)}` : "Web app — Base44 template + builder agent",
|
|
277560
|
+
modeLabel: options.import ? `Repository — ${repoLabel(options.import)}` : wixInstance ? "Web app — Wix launch (connector connected first)" : "Web app — Base44 template + builder agent",
|
|
276937
277561
|
footer,
|
|
276938
277562
|
createApp: (prompt, emit) => bootstrapApp(prompt, footer, emit, (app) => {
|
|
276939
277563
|
created = app;
|
|
276940
|
-
}, options.import, options.path)
|
|
277564
|
+
}, options.import, options.path, wixInstance)
|
|
276941
277565
|
});
|
|
276942
277566
|
if (!created) {
|
|
276943
277567
|
return { outroMessage: "Session closed. No app was created." };
|
|
@@ -276949,7 +277573,7 @@ async function codeAction({ log }, options, appId) {
|
|
|
276949
277573
|
}
|
|
276950
277574
|
function getCodeCommand() {
|
|
276951
277575
|
const command = new Base44Command("code", { requireAppContext: false });
|
|
276952
|
-
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>)").action((ctx, options) => codeAction(ctx, options, command.optsWithGlobals().appId));
|
|
277576
|
+
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));
|
|
276953
277577
|
return command;
|
|
276954
277578
|
}
|
|
276955
277579
|
|
|
@@ -284332,7 +284956,7 @@ async function runScript(options) {
|
|
|
284332
284956
|
}
|
|
284333
284957
|
}
|
|
284334
284958
|
// src/cli/commands/exec.ts
|
|
284335
|
-
function
|
|
284959
|
+
function readStdin3() {
|
|
284336
284960
|
return new Promise((resolve, reject) => {
|
|
284337
284961
|
let data = "";
|
|
284338
284962
|
process.stdin.setEncoding("utf-8");
|
|
@@ -284376,7 +285000,7 @@ async function execAction({ app, isNonInteractive }, options) {
|
|
|
284376
285000
|
if (!isNonInteractive) {
|
|
284377
285001
|
throw noInputError;
|
|
284378
285002
|
}
|
|
284379
|
-
const code = await
|
|
285003
|
+
const code = await readStdin3();
|
|
284380
285004
|
if (!code.trim()) {
|
|
284381
285005
|
throw noInputError;
|
|
284382
285006
|
}
|
|
@@ -288557,6 +289181,13 @@ function getFullCommandName(command) {
|
|
|
288557
289181
|
}
|
|
288558
289182
|
return parts.join(" ");
|
|
288559
289183
|
}
|
|
289184
|
+
var SENSITIVE_OPTION = /secret|token|password|launch|instance|key$/i;
|
|
289185
|
+
function redactSensitiveOptions(options) {
|
|
289186
|
+
return Object.fromEntries(Object.entries(options).map(([k, v]) => [
|
|
289187
|
+
k,
|
|
289188
|
+
SENSITIVE_OPTION.test(k) && v != null && v !== false ? "[redacted]" : v
|
|
289189
|
+
]));
|
|
289190
|
+
}
|
|
288560
289191
|
function addCommandInfoToErrorReporter(program, errorReporter) {
|
|
288561
289192
|
program.hook("preAction", (_, actionCommand) => {
|
|
288562
289193
|
const fullCommandName = getFullCommandName(actionCommand);
|
|
@@ -288564,7 +289195,7 @@ function addCommandInfoToErrorReporter(program, errorReporter) {
|
|
|
288564
289195
|
command: {
|
|
288565
289196
|
name: fullCommandName,
|
|
288566
289197
|
args: actionCommand.args,
|
|
288567
|
-
options: actionCommand.opts()
|
|
289198
|
+
options: redactSensitiveOptions(actionCommand.opts())
|
|
288568
289199
|
}
|
|
288569
289200
|
});
|
|
288570
289201
|
});
|
|
@@ -288611,4 +289242,4 @@ export {
|
|
|
288611
289242
|
runCLI
|
|
288612
289243
|
};
|
|
288613
289244
|
|
|
288614
|
-
//# debugId=
|
|
289245
|
+
//# debugId=F9AF4FAF927903AE64756E2164756E21
|