openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
228 lines (227 loc) • 7.42 kB
JavaScript
import { r as WizardNavigationError } from "./prompts-DLsO8MlU.js";
//#region src/wizard/navigation-prompter.ts
const basePrompterByNavigationPrompter = /* @__PURE__ */ new WeakMap();
function unwrapNavigationPrompter(prompter) {
let current = prompter;
let base = basePrompterByNavigationPrompter.get(current);
while (base) {
current = base;
base = basePrompterByNavigationPrompter.get(current);
}
return current;
}
function inertProgress() {
return {
update: () => {},
stop: () => {}
};
}
function stableKey(value) {
if (value === void 0) return "undefined";
try {
return JSON.stringify(value);
} catch {
return Object.prototype.toString.call(value);
}
}
function optionSignature(options) {
return stableKey(options.map((option) => [stableKey(option.value), option.label]));
}
function buildPromptSignature(kind, params) {
return stableKey({
kind,
message: params.message,
options: params.options ? optionSignature(params.options) : void 0,
layout: params.layout
});
}
function applyNavigation(params, navigation) {
return {
...params,
navigation
};
}
var WizardPromptNavigator = class {
constructor(base, options = {}) {
this.base = base;
this.options = options;
this.cursor = 0;
this.restartRequested = false;
this.boundaryBackRequested = false;
this.backNavigationDisabled = false;
this.records = [];
this.prompter = {
intro: async (title) => {
if (!this.shouldSuppressOutput()) await this.base.intro(title);
},
outro: async (message) => {
if (!this.shouldSuppressOutput()) await this.base.outro(message);
},
note: async (message, title) => {
if (!this.shouldSuppressOutput()) await this.base.note(message, title);
},
...this.base.deviceCode ? { deviceCode: async (params) => {
if (!this.shouldSuppressOutput()) await this.base.deviceCode?.(params);
} } : {},
plain: async (message) => {
if (!this.shouldSuppressOutput()) await this.base.plain?.(message);
},
select: async (params) => await this.prompt({
kind: "select",
params,
signature: buildPromptSignature("select", params),
cacheAnswer: true,
withInitial: (nextParams, answer) => ({
...nextParams,
initialValue: answer
}),
call: (nextParams) => this.base.select(nextParams)
}),
multiselect: async (params) => await this.prompt({
kind: "multiselect",
params,
signature: buildPromptSignature("multiselect", params),
cacheAnswer: true,
withInitial: (nextParams, answer) => ({
...nextParams,
initialValues: Array.isArray(answer) ? answer : nextParams.initialValues
}),
call: (nextParams) => this.base.multiselect(nextParams)
}),
text: async (params) => await this.prompt({
kind: "text",
params,
signature: buildPromptSignature("text", params),
cacheAnswer: params.sensitive !== true,
withInitial: (nextParams, answer) => ({
...nextParams,
initialValue: typeof answer === "string" ? answer : nextParams.initialValue
}),
call: (nextParams) => this.base.text(nextParams)
}),
confirm: async (params) => await this.prompt({
kind: "confirm",
params,
signature: buildPromptSignature("confirm", params),
cacheAnswer: true,
withInitial: (nextParams, answer) => ({
...nextParams,
initialValue: typeof answer === "boolean" ? answer : nextParams.initialValue
}),
call: (nextParams) => this.base.confirm(nextParams)
}),
progress: (label) => this.shouldSuppressOutput() ? inertProgress() : this.base.progress(label),
...this.base.openUrl ? { openUrl: async (url) => {
if (!this.shouldSuppressOutput()) await this.base.openUrl?.(url);
} } : {},
disableBackNavigation: () => {
this.backNavigationDisabled = true;
this.targetIndex = void 0;
}
};
basePrompterByNavigationPrompter.set(this.prompter, unwrapNavigationPrompter(base));
}
beginPass() {
this.cursor = 0;
this.restartRequested = false;
this.boundaryBackRequested = false;
}
hasRestartRequest() {
return this.restartRequested;
}
hasBoundaryBackRequest() {
return this.boundaryBackRequested;
}
shouldSuppressOutput() {
return this.targetIndex !== void 0 && this.cursor <= this.targetIndex;
}
matchingRecord(index, kind, signature) {
const record = this.records[index];
if (!record) return;
if (record.kind === kind && record.signature === signature) return record;
this.records.splice(index);
if (this.targetIndex !== void 0 && index < this.targetIndex) this.targetIndex = void 0;
}
remember(index, request, answer) {
if (!request.cacheAnswer) {
this.records[index] = void 0;
this.records.splice(index + 1);
return;
}
const answerKey = stableKey(answer);
const previous = this.records[index];
this.records[index] = {
kind: request.kind,
signature: request.signature,
answer,
answerKey
};
if (!previous || previous.answerKey !== answerKey || previous.signature !== request.signature) this.records.splice(index + 1);
}
async prompt(request) {
const index = this.cursor;
const record = this.matchingRecord(index, request.kind, request.signature);
if (this.targetIndex !== void 0 && index < this.targetIndex && record) {
this.cursor = index + 1;
return record.answer;
}
const paramsWithNavigation = applyNavigation(record ? request.withInitial(request.params, record.answer) : request.params, {
canGoBack: !this.backNavigationDisabled && (index > 0 || this.options.allowBackFromStart === true),
canGoForward: record !== void 0
});
try {
const answer = await request.call(paramsWithNavigation);
this.remember(index, request, answer);
this.cursor = index + 1;
if (this.targetIndex !== void 0 && index >= this.targetIndex) this.targetIndex = void 0;
return answer;
} catch (error) {
if (error instanceof WizardNavigationError) {
if (error.direction === "forward" && record) {
this.cursor = index + 1;
this.targetIndex = void 0;
return record.answer;
}
if (error.direction === "back" && !this.backNavigationDisabled && index === 0 && this.options.allowBackFromStart === true) this.boundaryBackRequested = true;
if (error.direction === "back" && !this.backNavigationDisabled && index > 0) {
this.targetIndex = index - 1;
this.restartRequested = true;
}
}
throw error;
}
}
};
async function runWizardWithPromptNavigationScope(basePrompter, runner) {
const navigator = new WizardPromptNavigator(unwrapNavigationPrompter(basePrompter), { allowBackFromStart: true });
while (true) {
navigator.beginPass();
try {
return {
status: "completed",
value: await runner(navigator.prompter)
};
} catch (error) {
if (error instanceof WizardNavigationError && error.direction === "back") {
if (navigator.hasRestartRequest()) continue;
if (navigator.hasBoundaryBackRequest()) return { status: "back" };
}
throw error;
}
}
}
async function runWizardWithPromptNavigation(basePrompter, runner) {
const navigator = new WizardPromptNavigator(basePrompter);
while (true) {
navigator.beginPass();
try {
await runner(navigator.prompter);
return;
} catch (error) {
if (error instanceof WizardNavigationError && error.direction === "back" && navigator.hasRestartRequest()) continue;
throw error;
}
}
}
//#endregion
export { runWizardWithPromptNavigationScope as n, runWizardWithPromptNavigation as t };