miladyai 2.0.0-alpha.27
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/_virtual/_rolldown/runtime.js +7 -0
- package/dist/actions/emote.js +64 -0
- package/dist/actions/restart.js +81 -0
- package/dist/actions/send-message.js +152 -0
- package/dist/agent-admin-routes.js +82 -0
- package/dist/agent-lifecycle-routes.js +79 -0
- package/dist/agent-transfer-routes.js +102 -0
- package/dist/api/agent-admin-routes.js +82 -0
- package/dist/api/agent-lifecycle-routes.js +79 -0
- package/dist/api/agent-transfer-routes.js +102 -0
- package/dist/api/apps-hyperscape-routes.js +58 -0
- package/dist/api/apps-routes.js +114 -0
- package/dist/api/auth-routes.js +56 -0
- package/dist/api/autonomy-routes.js +44 -0
- package/dist/api/bug-report-routes.js +111 -0
- package/dist/api/character-routes.js +195 -0
- package/dist/api/cloud-routes.js +330 -0
- package/dist/api/cloud-status-routes.js +155 -0
- package/dist/api/compat-utils.js +111 -0
- package/dist/api/database.js +735 -0
- package/dist/api/diagnostics-routes.js +205 -0
- package/dist/api/drop-service.js +134 -0
- package/dist/api/early-logs.js +86 -0
- package/dist/api/http-helpers.js +131 -0
- package/dist/api/knowledge-routes.js +534 -0
- package/dist/api/memory-bounds.js +71 -0
- package/dist/api/models-routes.js +28 -0
- package/dist/api/og-tracker.js +36 -0
- package/dist/api/permissions-routes.js +109 -0
- package/dist/api/plugin-validation.js +198 -0
- package/dist/api/provider-switch-config.js +41 -0
- package/dist/api/registry-routes.js +86 -0
- package/dist/api/registry-service.js +164 -0
- package/dist/api/sandbox-routes.js +1112 -0
- package/dist/api/server.js +7949 -0
- package/dist/api/subscription-routes.js +172 -0
- package/dist/api/terminal-run-limits.js +24 -0
- package/dist/api/training-routes.js +158 -0
- package/dist/api/trajectory-routes.js +300 -0
- package/dist/api/trigger-routes.js +246 -0
- package/dist/api/twitter-verify.js +134 -0
- package/dist/api/tx-service.js +108 -0
- package/dist/api/wallet-routes.js +266 -0
- package/dist/api/wallet.js +568 -0
- package/dist/api/whatsapp-routes.js +182 -0
- package/dist/api/zip-utils.js +109 -0
- package/dist/apps-hyperscape-routes.js +58 -0
- package/dist/apps-routes.js +114 -0
- package/dist/ascii.js +20 -0
- package/dist/auth/anthropic.js +44 -0
- package/dist/auth/apply-stealth.js +41 -0
- package/dist/auth/claude-code-stealth.js +78 -0
- package/dist/auth/credentials.js +156 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/openai-codex.js +66 -0
- package/dist/auth/types.js +9 -0
- package/dist/auth-routes.js +56 -0
- package/dist/autonomy-routes.js +44 -0
- package/dist/bug-report-routes.js +111 -0
- package/dist/build-info.json +6 -0
- package/dist/character-routes.js +195 -0
- package/dist/cli/argv.js +63 -0
- package/dist/cli/banner.js +34 -0
- package/dist/cli/cli-name.js +21 -0
- package/dist/cli/cli-utils.js +16 -0
- package/dist/cli/git-commit.js +78 -0
- package/dist/cli/parse-duration.js +15 -0
- package/dist/cli/plugins-cli.js +590 -0
- package/dist/cli/profile-utils.js +9 -0
- package/dist/cli/profile.js +95 -0
- package/dist/cli/program/build-program.js +17 -0
- package/dist/cli/program/command-registry.js +23 -0
- package/dist/cli/program/help.js +47 -0
- package/dist/cli/program/preaction.js +33 -0
- package/dist/cli/program/register.config.js +106 -0
- package/dist/cli/program/register.configure.js +20 -0
- package/dist/cli/program/register.dashboard.js +124 -0
- package/dist/cli/program/register.models.js +23 -0
- package/dist/cli/program/register.setup.js +36 -0
- package/dist/cli/program/register.start.js +22 -0
- package/dist/cli/program/register.subclis.js +70 -0
- package/dist/cli/program/register.tui.js +163 -0
- package/dist/cli/program/register.update.js +154 -0
- package/dist/cli/program.js +3 -0
- package/dist/cli/run-main.js +37 -0
- package/dist/cli/version.js +7 -0
- package/dist/cloud/validate-url.js +93 -0
- package/dist/cloud-routes.js +330 -0
- package/dist/cloud-status-routes.js +155 -0
- package/dist/compat-utils.js +111 -0
- package/dist/config/config.js +69 -0
- package/dist/config/env-vars.js +19 -0
- package/dist/config/includes.js +121 -0
- package/dist/config/object-utils.js +7 -0
- package/dist/config/paths.js +38 -0
- package/dist/config/plugin-auto-enable.js +231 -0
- package/dist/config/schema.js +864 -0
- package/dist/config/telegram-custom-commands.js +76 -0
- package/dist/config/zod-schema.agent-runtime.js +519 -0
- package/dist/config/zod-schema.core.js +538 -0
- package/dist/config/zod-schema.hooks.js +103 -0
- package/dist/config/zod-schema.js +488 -0
- package/dist/config/zod-schema.providers-core.js +785 -0
- package/dist/config/zod-schema.session.js +73 -0
- package/dist/core-plugins.js +37 -0
- package/dist/custom-actions.js +250 -0
- package/dist/database.js +735 -0
- package/dist/diagnostics/integration-observability.js +57 -0
- package/dist/diagnostics-routes.js +205 -0
- package/dist/drop-service.js +134 -0
- package/dist/early-logs.js +24 -0
- package/dist/eliza.js +2061 -0
- package/dist/emotes/catalog.js +271 -0
- package/dist/entry.js +40 -0
- package/dist/hooks/discovery.js +167 -0
- package/dist/hooks/eligibility.js +64 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/loader.js +147 -0
- package/dist/hooks/registry.js +55 -0
- package/dist/http-helpers.js +131 -0
- package/dist/index.js +49 -0
- package/dist/knowledge-routes.js +534 -0
- package/dist/memory-bounds.js +71 -0
- package/dist/milady-plugin.js +90 -0
- package/dist/models-routes.js +28 -0
- package/dist/onboarding-names.js +78 -0
- package/dist/onboarding-presets.js +922 -0
- package/dist/package.json +1 -0
- package/dist/permissions-routes.js +109 -0
- package/dist/plugin-validation.js +107 -0
- package/dist/plugins/whatsapp/actions.js +91 -0
- package/dist/plugins/whatsapp/index.js +16 -0
- package/dist/plugins/whatsapp/service.js +270 -0
- package/dist/provider-switch-config.js +41 -0
- package/dist/providers/admin-trust.js +46 -0
- package/dist/providers/autonomous-state.js +101 -0
- package/dist/providers/session-bridge.js +86 -0
- package/dist/providers/session-utils.js +36 -0
- package/dist/providers/simple-mode.js +50 -0
- package/dist/providers/ui-catalog.js +15 -0
- package/dist/providers/workspace-provider.js +93 -0
- package/dist/providers/workspace.js +348 -0
- package/dist/registry-routes.js +86 -0
- package/dist/registry-service.js +164 -0
- package/dist/restart.js +40 -0
- package/dist/runtime/core-plugins.js +37 -0
- package/dist/runtime/custom-actions.js +250 -0
- package/dist/runtime/eliza.js +2061 -0
- package/dist/runtime/embedding-manager-support.js +185 -0
- package/dist/runtime/embedding-manager.js +193 -0
- package/dist/runtime/embedding-presets.js +54 -0
- package/dist/runtime/embedding-state.js +8 -0
- package/dist/runtime/milady-plugin.js +90 -0
- package/dist/runtime/onboarding-names.js +78 -0
- package/dist/runtime/restart.js +40 -0
- package/dist/runtime/version.js +7 -0
- package/dist/sandbox-routes.js +1112 -0
- package/dist/security/audit-log.js +149 -0
- package/dist/security/network-policy.js +70 -0
- package/dist/server.js +7949 -0
- package/dist/services/agent-export.js +559 -0
- package/dist/services/app-manager.js +389 -0
- package/dist/services/browser-capture.js +86 -0
- package/dist/services/fallback-training-service.js +128 -0
- package/dist/services/mcp-marketplace.js +134 -0
- package/dist/services/plugin-installer.js +396 -0
- package/dist/services/plugin-manager-types.js +15 -0
- package/dist/services/registry-client-app-meta.js +144 -0
- package/dist/services/registry-client-endpoints.js +166 -0
- package/dist/services/registry-client-local.js +271 -0
- package/dist/services/registry-client-network.js +93 -0
- package/dist/services/registry-client-queries.js +70 -0
- package/dist/services/registry-client.js +157 -0
- package/dist/services/sandbox-engine.js +511 -0
- package/dist/services/sandbox-manager.js +297 -0
- package/dist/services/self-updater.js +175 -0
- package/dist/services/skill-catalog-client.js +119 -0
- package/dist/services/skill-marketplace.js +521 -0
- package/dist/services/stream-manager.js +236 -0
- package/dist/services/update-checker.js +121 -0
- package/dist/services/update-notifier.js +29 -0
- package/dist/services/version-compat.js +78 -0
- package/dist/services/whatsapp-pairing.js +196 -0
- package/dist/shared/ui-catalog-prompt.js +728 -0
- package/dist/subscription-routes.js +172 -0
- package/dist/terminal/links.js +19 -0
- package/dist/terminal/palette.js +14 -0
- package/dist/terminal/theme.js +25 -0
- package/dist/terminal-run-limits.js +24 -0
- package/dist/training-routes.js +158 -0
- package/dist/trajectory-routes.js +300 -0
- package/dist/trigger-routes.js +246 -0
- package/dist/triggers/action.js +218 -0
- package/dist/triggers/runtime.js +281 -0
- package/dist/triggers/scheduling.js +295 -0
- package/dist/triggers/types.js +5 -0
- package/dist/tui/components/assistant-message.js +76 -0
- package/dist/tui/components/chat-editor.js +34 -0
- package/dist/tui/components/embeddings-overlay.js +46 -0
- package/dist/tui/components/footer.js +60 -0
- package/dist/tui/components/index.js +15 -0
- package/dist/tui/components/modal-frame.js +45 -0
- package/dist/tui/components/modal-style.js +15 -0
- package/dist/tui/components/model-selector.js +70 -0
- package/dist/tui/components/pinned-chat-layout.js +46 -0
- package/dist/tui/components/plugins-endpoints-tab.js +196 -0
- package/dist/tui/components/plugins-installed-tab-view.js +69 -0
- package/dist/tui/components/plugins-installed-tab.js +319 -0
- package/dist/tui/components/plugins-overlay-catalog.js +81 -0
- package/dist/tui/components/plugins-overlay-data-api.js +21 -0
- package/dist/tui/components/plugins-overlay-data-shared.js +20 -0
- package/dist/tui/components/plugins-overlay-data.js +323 -0
- package/dist/tui/components/plugins-overlay.js +117 -0
- package/dist/tui/components/plugins-store-tab.js +148 -0
- package/dist/tui/components/settings-overlay.js +61 -0
- package/dist/tui/components/status-bar.js +64 -0
- package/dist/tui/components/tool-execution.js +68 -0
- package/dist/tui/components/user-message.js +22 -0
- package/dist/tui/eliza-tui-bridge.js +606 -0
- package/dist/tui/index.js +370 -0
- package/dist/tui/modal-presets.js +33 -0
- package/dist/tui/model-spec.js +46 -0
- package/dist/tui/sse-parser.js +78 -0
- package/dist/tui/theme.js +110 -0
- package/dist/tui/titlebar-spinner.js +62 -0
- package/dist/tui/tui-app.js +311 -0
- package/dist/tui/ws-client.js +215 -0
- package/dist/twitter-verify.js +134 -0
- package/dist/tx-service.js +108 -0
- package/dist/utils/exec-safety.js +17 -0
- package/dist/utils/globals.js +20 -0
- package/dist/utils/milady-root.js +61 -0
- package/dist/utils/number-parsing.js +37 -0
- package/dist/version-resolver.js +37 -0
- package/dist/version.js +7 -0
- package/dist/wallet-routes.js +266 -0
- package/dist/wallet.js +568 -0
- package/dist/whatsapp-routes.js +182 -0
- package/dist/zip-utils.js +109 -0
- package/milady.mjs +14 -0
- package/package.json +111 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { loadMiladyConfig, saveMiladyConfig } from "../config/config.js";
|
|
2
|
+
import { DEFAULT_MODELS_DIR, ensureModel } from "../runtime/embedding-manager-support.js";
|
|
3
|
+
import { EMBEDDING_PRESETS } from "../runtime/embedding-presets.js";
|
|
4
|
+
import { MiladyEmbeddingManager } from "../runtime/embedding-manager.js";
|
|
5
|
+
import { getEmbeddingState } from "../runtime/embedding-state.js";
|
|
6
|
+
import { ElizaTUIBridge } from "./eliza-tui-bridge.js";
|
|
7
|
+
import { resolveTuiModelSpec } from "./model-spec.js";
|
|
8
|
+
import { MiladyTUI } from "./tui-app.js";
|
|
9
|
+
import process from "node:process";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { stringToUuid } from "@elizaos/core";
|
|
12
|
+
import fs from "node:fs";
|
|
13
|
+
import { createPiCredentialProvider, getPiModel, parseModelSpec, registerPiAiModelHandler } from "@elizaos/plugin-pi-ai";
|
|
14
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
15
|
+
|
|
16
|
+
//#region src/tui/index.ts
|
|
17
|
+
function formatDownloadSize(mb) {
|
|
18
|
+
return mb >= 1e3 ? `${(mb / 1e3).toFixed(1)}GB` : `${mb}MB`;
|
|
19
|
+
}
|
|
20
|
+
function isModelDownloaded(filename) {
|
|
21
|
+
return fs.existsSync(path.join(DEFAULT_MODELS_DIR, filename));
|
|
22
|
+
}
|
|
23
|
+
const VALID_TIERS = new Set([
|
|
24
|
+
"fallback",
|
|
25
|
+
"standard",
|
|
26
|
+
"performance"
|
|
27
|
+
]);
|
|
28
|
+
function getEmbeddingOptions() {
|
|
29
|
+
const state = getEmbeddingState();
|
|
30
|
+
if (!state) return [];
|
|
31
|
+
return [
|
|
32
|
+
"fallback",
|
|
33
|
+
"standard",
|
|
34
|
+
"performance"
|
|
35
|
+
].map((tier) => {
|
|
36
|
+
const preset = EMBEDDING_PRESETS[tier];
|
|
37
|
+
return {
|
|
38
|
+
tier,
|
|
39
|
+
label: preset.label,
|
|
40
|
+
dimensions: preset.dimensions,
|
|
41
|
+
downloaded: isModelDownloaded(preset.model),
|
|
42
|
+
active: state.preset?.tier === tier
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async function switchEmbeddingTier(tier, tui) {
|
|
47
|
+
const state = getEmbeddingState();
|
|
48
|
+
if (!state) {
|
|
49
|
+
tui.addToChatContainer(new Text("Embedding manager not available.", 1, 0));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const preset = EMBEDDING_PRESETS[tier];
|
|
53
|
+
if (state.preset?.tier === tier) {
|
|
54
|
+
tui.addToChatContainer(new Text(`Already using ${preset.label} (${preset.model})`, 1, 0));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (preset.dimensions !== state.dimensions) tui.addToChatContainer(new Text(`⚠ Dimensions changing (${state.dimensions} → ${preset.dimensions}). Existing memory embeddings will be re-indexed on next access.`, 1, 0));
|
|
58
|
+
if (!isModelDownloaded(preset.model)) {
|
|
59
|
+
tui.addToChatContainer(new Text(`Downloading ${preset.model} (${formatDownloadSize(preset.downloadSizeMB)})…`, 1, 0));
|
|
60
|
+
try {
|
|
61
|
+
await ensureModel(DEFAULT_MODELS_DIR, preset.modelRepo, preset.model);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
64
|
+
tui.addToChatContainer(new Text(`Download failed: ${msg}`, 1, 0));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
await state.manager.dispose();
|
|
70
|
+
} catch {}
|
|
71
|
+
state.manager = new MiladyEmbeddingManager({
|
|
72
|
+
model: preset.model,
|
|
73
|
+
modelRepo: preset.modelRepo,
|
|
74
|
+
dimensions: preset.dimensions,
|
|
75
|
+
gpuLayers: preset.gpuLayers
|
|
76
|
+
});
|
|
77
|
+
state.preset = preset;
|
|
78
|
+
state.dimensions = preset.dimensions;
|
|
79
|
+
try {
|
|
80
|
+
const cfg = loadMiladyConfig();
|
|
81
|
+
cfg.embedding = {
|
|
82
|
+
...cfg.embedding,
|
|
83
|
+
model: preset.model,
|
|
84
|
+
modelRepo: preset.modelRepo,
|
|
85
|
+
dimensions: preset.dimensions,
|
|
86
|
+
gpuLayers: preset.gpuLayers
|
|
87
|
+
};
|
|
88
|
+
saveMiladyConfig(cfg);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
91
|
+
tui.addToChatContainer(new Text(`Warning: could not save config: ${msg}`, 1, 0));
|
|
92
|
+
}
|
|
93
|
+
tui.addToChatContainer(new Text(`Switched embedding model to ${preset.label} (${preset.model}, ${preset.dimensions} dims)`, 1, 0));
|
|
94
|
+
}
|
|
95
|
+
function createApiModeRuntimeStub(agentName) {
|
|
96
|
+
const noopAsync = async () => {};
|
|
97
|
+
return {
|
|
98
|
+
agentId: stringToUuid(`milady-tui-api:${agentName}`),
|
|
99
|
+
character: { name: agentName },
|
|
100
|
+
getSetting: () => void 0,
|
|
101
|
+
setSetting: () => {},
|
|
102
|
+
registerEvent: () => {},
|
|
103
|
+
ensureWorldExists: noopAsync,
|
|
104
|
+
ensureRoomExists: noopAsync,
|
|
105
|
+
ensureConnection: noopAsync,
|
|
106
|
+
stop: noopAsync
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async function launchTUI(runtime, options = {}) {
|
|
110
|
+
const apiMode = Boolean(options.apiBaseUrl);
|
|
111
|
+
const piCreds = await createPiCredentialProvider();
|
|
112
|
+
const miladyConfig = loadMiladyConfig();
|
|
113
|
+
const fallbackAgentName = miladyConfig.agents?.list?.[0]?.name ?? "milady";
|
|
114
|
+
if (!runtime && !apiMode) throw new Error("Runtime is required when API mode is not configured");
|
|
115
|
+
const runtimeRef = runtime ?? createApiModeRuntimeStub(fallbackAgentName);
|
|
116
|
+
const configPrimaryModel = miladyConfig.agents?.defaults?.model?.primary;
|
|
117
|
+
const configEnv = miladyConfig.env;
|
|
118
|
+
const configPiAiModelSpec = configEnv?.vars?.PI_AI_MODEL_SPEC ?? (typeof configEnv?.PI_AI_MODEL_SPEC === "string" ? configEnv.PI_AI_MODEL_SPEC : void 0);
|
|
119
|
+
const runtimeModelProvider = runtimeRef.getSetting("MODEL_PROVIDER");
|
|
120
|
+
const { provider, id } = parseModelSpec(resolveTuiModelSpec({
|
|
121
|
+
modelOverride: options.modelOverride,
|
|
122
|
+
configPrimaryModelSpec: configPrimaryModel,
|
|
123
|
+
configPiAiModelSpec,
|
|
124
|
+
runtimeModelSpec: runtimeModelProvider,
|
|
125
|
+
piDefaultModelSpec: await piCreds.getDefaultModelSpec(),
|
|
126
|
+
hasCredentials: (provider) => piCreds.hasCredentials(provider)
|
|
127
|
+
}));
|
|
128
|
+
const largeModel = getPiModel(provider, id);
|
|
129
|
+
const smallModel = largeModel;
|
|
130
|
+
const tui = new MiladyTUI({
|
|
131
|
+
runtime: runtimeRef,
|
|
132
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
133
|
+
modelRegistry: { authStorage: {
|
|
134
|
+
getApiKey: (provider) => piCreds.getApiKey(provider),
|
|
135
|
+
get: async (_provider) => void 0
|
|
136
|
+
} }
|
|
137
|
+
});
|
|
138
|
+
const bridge = new ElizaTUIBridge(runtimeRef, tui, {
|
|
139
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
140
|
+
apiToken: options.apiToken
|
|
141
|
+
});
|
|
142
|
+
const controller = apiMode ? null : registerPiAiModelHandler(runtimeRef, {
|
|
143
|
+
largeModel,
|
|
144
|
+
smallModel,
|
|
145
|
+
onStreamEvent: (event) => bridge.onStreamEvent(event),
|
|
146
|
+
getAbortSignal: () => bridge.getAbortSignal(),
|
|
147
|
+
priority: 2e4,
|
|
148
|
+
getApiKey: (p) => piCreds.getApiKey(p)
|
|
149
|
+
});
|
|
150
|
+
if (controller) tui.getStatusBar().update({
|
|
151
|
+
modelId: controller.getLargeModel().id,
|
|
152
|
+
modelProvider: controller.getLargeModel().provider
|
|
153
|
+
});
|
|
154
|
+
else tui.getStatusBar().update({
|
|
155
|
+
modelId: "backend",
|
|
156
|
+
modelProvider: "api"
|
|
157
|
+
});
|
|
158
|
+
const switchModel = (model) => {
|
|
159
|
+
if (!controller) {
|
|
160
|
+
tui.addToChatContainer(new Text("Model switching is managed by the connected API runtime in API mode.", 1, 0));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
controller.setLargeModel(model);
|
|
164
|
+
controller.setSmallModel(model);
|
|
165
|
+
runtimeRef.setSetting("MODEL_PROVIDER", `${model.provider}/${model.id}`);
|
|
166
|
+
tui.getStatusBar().update({
|
|
167
|
+
modelId: model.id,
|
|
168
|
+
modelProvider: model.provider
|
|
169
|
+
});
|
|
170
|
+
if (!piCreds.hasCredentials(model.provider)) tui.addToChatContainer(new Text(`Warning: no credentials found for provider "${model.provider}" (neither Milady env nor pi auth). Model calls may fail.`, 1, 0));
|
|
171
|
+
tui.addToChatContainer(new Text(`Switched model to ${model.provider}/${model.id}`, 1, 0));
|
|
172
|
+
};
|
|
173
|
+
tui.setOnSubmit(async (text) => {
|
|
174
|
+
if (text.startsWith("/")) {
|
|
175
|
+
const [cmdRaw, ...args] = text.slice(1).trim().split(/\s+/);
|
|
176
|
+
const cmd = (cmdRaw ?? "").toLowerCase();
|
|
177
|
+
const argText = args.join(" ").trim();
|
|
178
|
+
try {
|
|
179
|
+
if (cmd === "model" || cmd === "models") {
|
|
180
|
+
if (apiMode) {
|
|
181
|
+
tui.addToChatContainer(new Text("Model selection is managed by the connected API runtime in API mode.", 1, 0));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (!argText) {
|
|
185
|
+
tui.openModelSelector();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const { provider: p, id: m } = parseModelSpec(argText);
|
|
189
|
+
switchModel(getPiModel(p, m));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (cmd === "embeddings") {
|
|
193
|
+
if (apiMode) {
|
|
194
|
+
tui.addToChatContainer(new Text("Embedding controls are only available in local runtime mode.", 1, 0));
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (!argText) {
|
|
198
|
+
tui.openEmbeddings();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const tier = argText.toLowerCase();
|
|
202
|
+
if (!VALID_TIERS.has(tier)) {
|
|
203
|
+
tui.addToChatContainer(new Text(`Unknown tier "${argText}". Use: fallback, standard, or performance`, 1, 0));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
await switchEmbeddingTier(tier, tui);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (cmd === "knowledge" || cmd === "ctx") {
|
|
210
|
+
if (apiMode) {
|
|
211
|
+
tui.addToChatContainer(new Text("Knowledge enrichment settings are managed by the connected API runtime in API mode.", 1, 0));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const cfg = loadMiladyConfig();
|
|
215
|
+
const ctxEnabled = cfg.knowledge?.contextualEnrichment === true;
|
|
216
|
+
if (!argText) {
|
|
217
|
+
const embState = getEmbeddingState();
|
|
218
|
+
const embModel = embState?.preset ? `${embState.preset.model} (local, ${embState.preset.dimensions}d)` : "unknown";
|
|
219
|
+
if (ctxEnabled) {
|
|
220
|
+
const lm = controller?.getLargeModel();
|
|
221
|
+
const cloudModel = lm ? `${lm.provider}/${lm.id} (via pi-ai)` : "unknown (controller unavailable)";
|
|
222
|
+
tui.addToChatContainer(new Text([
|
|
223
|
+
"Knowledge Enrichment: ON",
|
|
224
|
+
` Cloud model: ${cloudModel}`,
|
|
225
|
+
` Embedding model: ${embModel}`,
|
|
226
|
+
` Docs path: ${cfg.knowledge?.docsPath ?? "./docs"}`
|
|
227
|
+
].join("\n"), 1, 0));
|
|
228
|
+
} else tui.addToChatContainer(new Text([
|
|
229
|
+
"Knowledge Enrichment: OFF",
|
|
230
|
+
` Embedding model: ${embModel}`,
|
|
231
|
+
" Enable with: /knowledge on"
|
|
232
|
+
].join("\n"), 1, 0));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const action = argText.toLowerCase();
|
|
236
|
+
if (action === "on") {
|
|
237
|
+
if (ctxEnabled) {
|
|
238
|
+
tui.addToChatContainer(new Text("Knowledge enrichment is already enabled.", 1, 0));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
cfg.knowledge = {
|
|
242
|
+
...cfg.knowledge,
|
|
243
|
+
contextualEnrichment: true
|
|
244
|
+
};
|
|
245
|
+
try {
|
|
246
|
+
saveMiladyConfig(cfg);
|
|
247
|
+
} catch (err) {
|
|
248
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
249
|
+
tui.addToChatContainer(new Text(`Could not save config: ${msg}`, 1, 0));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
runtimeRef.setSetting("CTX_KNOWLEDGE_ENABLED", "true");
|
|
253
|
+
tui.addToChatContainer(new Text("Knowledge enrichment enabled. Takes effect on next document ingestion.\nDocument text will be sent to your cloud provider for enrichment; embeddings stay local.", 1, 0));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (action === "off") {
|
|
257
|
+
if (!ctxEnabled) {
|
|
258
|
+
tui.addToChatContainer(new Text("Knowledge enrichment is already disabled.", 1, 0));
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
cfg.knowledge = {
|
|
262
|
+
...cfg.knowledge,
|
|
263
|
+
contextualEnrichment: false
|
|
264
|
+
};
|
|
265
|
+
try {
|
|
266
|
+
saveMiladyConfig(cfg);
|
|
267
|
+
} catch (err) {
|
|
268
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
269
|
+
tui.addToChatContainer(new Text(`Could not save config: ${msg}`, 1, 0));
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
runtimeRef.setSetting("CTX_KNOWLEDGE_ENABLED", null);
|
|
273
|
+
tui.addToChatContainer(new Text("Knowledge enrichment disabled. Existing enriched chunks are not affected.", 1, 0));
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
tui.addToChatContainer(new Text("Usage: /knowledge [on|off] — toggle contextual enrichment", 1, 0));
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (cmd === "help") {
|
|
280
|
+
tui.addToChatContainer(new Text([
|
|
281
|
+
"Commands:",
|
|
282
|
+
" /model open model selector",
|
|
283
|
+
" /model <p/id> switch model (e.g. anthropic/claude-sonnet-4-20250514)",
|
|
284
|
+
" /embeddings open embedding model popup",
|
|
285
|
+
" /embeddings <t> switch embedding (fallback|standard|performance)",
|
|
286
|
+
" /knowledge show knowledge enrichment status",
|
|
287
|
+
" /knowledge on enable contextual enrichment (cloud LLM + local embeddings)",
|
|
288
|
+
" /knowledge off disable contextual enrichment",
|
|
289
|
+
" /clear clear chat",
|
|
290
|
+
" /settings open settings panel",
|
|
291
|
+
" /plugins open plugin manager",
|
|
292
|
+
" /exit quit"
|
|
293
|
+
].join("\n"), 1, 0));
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (cmd === "clear") {
|
|
297
|
+
tui.clearChat();
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (cmd === "settings") {
|
|
301
|
+
tui.openSettings();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (cmd === "plugins") {
|
|
305
|
+
tui.openPlugins();
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (cmd === "exit" || cmd === "quit") {
|
|
309
|
+
bridge.dispose();
|
|
310
|
+
await tui.stop();
|
|
311
|
+
await runtimeRef.stop();
|
|
312
|
+
process.exit(0);
|
|
313
|
+
}
|
|
314
|
+
tui.addToChatContainer(new Text(`Unknown command: /${cmd}. Try /help`, 1, 0));
|
|
315
|
+
return;
|
|
316
|
+
} catch (err) {
|
|
317
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
318
|
+
tui.addToChatContainer(new Text(`Command error: ${msg}`, 1, 0));
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
await bridge.handleUserInput(text);
|
|
323
|
+
});
|
|
324
|
+
tui.setOnToggleToolExpand((expanded) => bridge.setToolOutputExpanded(expanded));
|
|
325
|
+
tui.setOnToggleThinking((enabled) => bridge.setShowThinking(enabled));
|
|
326
|
+
tui.setOnCtrlC(() => {
|
|
327
|
+
if (bridge.getIsProcessing()) {
|
|
328
|
+
bridge.abortInFlight();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
(async () => {
|
|
332
|
+
try {
|
|
333
|
+
bridge.dispose();
|
|
334
|
+
await tui.stop();
|
|
335
|
+
} finally {
|
|
336
|
+
await runtimeRef.stop();
|
|
337
|
+
process.exit(0);
|
|
338
|
+
}
|
|
339
|
+
})();
|
|
340
|
+
});
|
|
341
|
+
if (!apiMode && controller) {
|
|
342
|
+
tui.setModelSelectorHandlers({
|
|
343
|
+
getCurrentModel: () => controller.getLargeModel(),
|
|
344
|
+
hasCredentials: (provider) => piCreds.hasCredentials(provider),
|
|
345
|
+
onSelectModel: (model) => {
|
|
346
|
+
try {
|
|
347
|
+
switchModel(model);
|
|
348
|
+
} catch (err) {
|
|
349
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
350
|
+
tui.addToChatContainer(new Text(`Model switch error: ${msg}`, 1, 0));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
tui.setEmbeddingHandlers({
|
|
355
|
+
getOptions: () => getEmbeddingOptions(),
|
|
356
|
+
onSelectTier: async (tier) => {
|
|
357
|
+
await switchEmbeddingTier(tier, tui);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
await bridge.initialize();
|
|
362
|
+
try {
|
|
363
|
+
await tui.start();
|
|
364
|
+
} finally {
|
|
365
|
+
bridge.dispose();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
//#endregion
|
|
370
|
+
export { launchTUI };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/tui/modal-presets.ts
|
|
2
|
+
/**
|
|
3
|
+
* Shared popup sizing presets for a consistent overlay rhythm.
|
|
4
|
+
*/
|
|
5
|
+
const MODAL_PRESETS = {
|
|
6
|
+
compact: {
|
|
7
|
+
anchor: "center",
|
|
8
|
+
width: "50%",
|
|
9
|
+
maxHeight: "50%",
|
|
10
|
+
margin: 2
|
|
11
|
+
},
|
|
12
|
+
standard: {
|
|
13
|
+
anchor: "center",
|
|
14
|
+
width: "60%",
|
|
15
|
+
maxHeight: "70%",
|
|
16
|
+
margin: 2
|
|
17
|
+
},
|
|
18
|
+
wide: {
|
|
19
|
+
anchor: "center",
|
|
20
|
+
width: "80%",
|
|
21
|
+
maxHeight: "85%",
|
|
22
|
+
margin: 2
|
|
23
|
+
},
|
|
24
|
+
xwide: {
|
|
25
|
+
anchor: "center",
|
|
26
|
+
width: "90%",
|
|
27
|
+
maxHeight: "80%",
|
|
28
|
+
margin: 2
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { MODAL_PRESETS };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { DEFAULT_PI_MODEL_SPEC, parseModelSpec } from "@elizaos/plugin-pi-ai";
|
|
2
|
+
|
|
3
|
+
//#region src/tui/model-spec.ts
|
|
4
|
+
function toValidModelSpec(spec) {
|
|
5
|
+
if (!spec) return void 0;
|
|
6
|
+
const normalized = spec.trim();
|
|
7
|
+
if (!normalized) return void 0;
|
|
8
|
+
try {
|
|
9
|
+
parseModelSpec(normalized);
|
|
10
|
+
return normalized;
|
|
11
|
+
} catch {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Select the model spec used by the TUI pi-ai bridge.
|
|
17
|
+
*
|
|
18
|
+
* Priority:
|
|
19
|
+
* 1) explicit CLI override (--model)
|
|
20
|
+
* 2) milady config primary model (agents.defaults.model.primary)
|
|
21
|
+
* 3) milady config PI_AI_MODEL_SPEC
|
|
22
|
+
* 4) runtime MODEL_PROVIDER
|
|
23
|
+
* 5) pi settings default (settings.json)
|
|
24
|
+
* 6) built-in safe default
|
|
25
|
+
*
|
|
26
|
+
* Candidate specs are only used when credentials exist for the provider.
|
|
27
|
+
*/
|
|
28
|
+
function resolveTuiModelSpec(params) {
|
|
29
|
+
const defaultSpec = toValidModelSpec(params.piDefaultModelSpec) ?? DEFAULT_PI_MODEL_SPEC;
|
|
30
|
+
const candidates = [
|
|
31
|
+
params.modelOverride,
|
|
32
|
+
params.configPrimaryModelSpec,
|
|
33
|
+
params.configPiAiModelSpec,
|
|
34
|
+
params.runtimeModelSpec
|
|
35
|
+
];
|
|
36
|
+
for (const candidate of candidates) {
|
|
37
|
+
const spec = toValidModelSpec(candidate);
|
|
38
|
+
if (!spec) continue;
|
|
39
|
+
const { provider } = parseModelSpec(spec);
|
|
40
|
+
if (params.hasCredentials(provider)) return spec;
|
|
41
|
+
}
|
|
42
|
+
return defaultSpec;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
export { resolveTuiModelSpec };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//#region src/tui/sse-parser.ts
|
|
2
|
+
/**
|
|
3
|
+
* Find the next SSE event boundary in the buffer.
|
|
4
|
+
* Supports both LF (\n\n) and CRLF (\r\n\r\n) framing.
|
|
5
|
+
*/
|
|
6
|
+
function findSseEventBreak(buffer) {
|
|
7
|
+
const lfBreak = buffer.indexOf("\n\n");
|
|
8
|
+
const crlfBreak = buffer.indexOf("\r\n\r\n");
|
|
9
|
+
if (lfBreak === -1 && crlfBreak === -1) return null;
|
|
10
|
+
if (lfBreak === -1) return {
|
|
11
|
+
index: crlfBreak,
|
|
12
|
+
length: 4
|
|
13
|
+
};
|
|
14
|
+
if (crlfBreak === -1) return {
|
|
15
|
+
index: lfBreak,
|
|
16
|
+
length: 2
|
|
17
|
+
};
|
|
18
|
+
return lfBreak < crlfBreak ? {
|
|
19
|
+
index: lfBreak,
|
|
20
|
+
length: 2
|
|
21
|
+
} : {
|
|
22
|
+
index: crlfBreak,
|
|
23
|
+
length: 4
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Split a chunk buffer into complete SSE raw events + the remaining tail.
|
|
28
|
+
*/
|
|
29
|
+
function drainSseEvents(buffer) {
|
|
30
|
+
const events = [];
|
|
31
|
+
let remaining = buffer;
|
|
32
|
+
let eventBreak = findSseEventBreak(remaining);
|
|
33
|
+
while (eventBreak) {
|
|
34
|
+
events.push(remaining.slice(0, eventBreak.index));
|
|
35
|
+
remaining = remaining.slice(eventBreak.index + eventBreak.length);
|
|
36
|
+
eventBreak = findSseEventBreak(remaining);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
events,
|
|
40
|
+
remaining
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Extract `data:` payloads from one raw SSE event block.
|
|
45
|
+
*/
|
|
46
|
+
function extractSseDataPayloads(rawEvent) {
|
|
47
|
+
const payloads = [];
|
|
48
|
+
for (const line of rawEvent.split(/\r?\n/)) {
|
|
49
|
+
if (!line.startsWith("data:")) continue;
|
|
50
|
+
const payload = line.slice(5).trim();
|
|
51
|
+
if (!payload) continue;
|
|
52
|
+
payloads.push(payload);
|
|
53
|
+
}
|
|
54
|
+
return payloads;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Parse JSON payload for conversation streaming events.
|
|
58
|
+
*/
|
|
59
|
+
function parseConversationStreamPayload(payload) {
|
|
60
|
+
let parsed;
|
|
61
|
+
try {
|
|
62
|
+
parsed = JSON.parse(payload);
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
67
|
+
const record = parsed;
|
|
68
|
+
return {
|
|
69
|
+
type: typeof record.type === "string" ? record.type : void 0,
|
|
70
|
+
text: typeof record.text === "string" ? record.text : void 0,
|
|
71
|
+
fullText: typeof record.fullText === "string" ? record.fullText : void 0,
|
|
72
|
+
agentName: typeof record.agentName === "string" ? record.agentName : void 0,
|
|
73
|
+
message: typeof record.message === "string" ? record.message : void 0
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
export { drainSseEvents, extractSseDataPayloads, parseConversationStreamPayload };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { highlight, supportsLanguage } from "cli-highlight";
|
|
3
|
+
|
|
4
|
+
//#region src/tui/theme.ts
|
|
5
|
+
const ACCENT = "#E879F9";
|
|
6
|
+
const ACCENT_DIM = "#A855F7";
|
|
7
|
+
const MUTED = "#808080";
|
|
8
|
+
const DIM = "#666666";
|
|
9
|
+
const SUCCESS = "#b5bd68";
|
|
10
|
+
const ERROR = "#cc6666";
|
|
11
|
+
const WARNING = "#FBBF24";
|
|
12
|
+
const INFO = "#60A5FA";
|
|
13
|
+
const USER_MSG_BG = "#2D1B3D";
|
|
14
|
+
const TOOL_PENDING_BG = "#282832";
|
|
15
|
+
const TOOL_SUCCESS_BG = "#283228";
|
|
16
|
+
const TOOL_ERROR_BG = "#3c2828";
|
|
17
|
+
const MD_HEADING = "#f0c674";
|
|
18
|
+
const MD_LINK = "#81a2be";
|
|
19
|
+
const MD_CODE = ACCENT;
|
|
20
|
+
const MD_CODE_BLOCK = SUCCESS;
|
|
21
|
+
const SYN_COMMENT = "#6A9955";
|
|
22
|
+
const SYN_KEYWORD = "#C586C0";
|
|
23
|
+
const SYN_FUNCTION = "#DCDCAA";
|
|
24
|
+
const SYN_VARIABLE = "#9CDCFE";
|
|
25
|
+
const SYN_STRING = "#CE9178";
|
|
26
|
+
const SYN_NUMBER = "#B5CEA8";
|
|
27
|
+
const SYN_TYPE = "#4EC9B0";
|
|
28
|
+
const SYN_OPERATOR = "#D4D4D4";
|
|
29
|
+
const SYN_PUNCTUATION = "#808080";
|
|
30
|
+
const hex = (value) => chalk.hex(value);
|
|
31
|
+
const bg = (value) => chalk.bgHex(value);
|
|
32
|
+
/** cli-highlight theme mapped to Milady's palette. */
|
|
33
|
+
const cliHighlightTheme = {
|
|
34
|
+
keyword: (s) => hex(SYN_KEYWORD)(s),
|
|
35
|
+
built_in: (s) => hex(SYN_TYPE)(s),
|
|
36
|
+
literal: (s) => hex(SYN_NUMBER)(s),
|
|
37
|
+
number: (s) => hex(SYN_NUMBER)(s),
|
|
38
|
+
string: (s) => hex(SYN_STRING)(s),
|
|
39
|
+
comment: (s) => hex(SYN_COMMENT)(s),
|
|
40
|
+
function: (s) => hex(SYN_FUNCTION)(s),
|
|
41
|
+
title: (s) => hex(SYN_FUNCTION)(s),
|
|
42
|
+
class: (s) => hex(SYN_TYPE)(s),
|
|
43
|
+
type: (s) => hex(SYN_TYPE)(s),
|
|
44
|
+
attr: (s) => hex(SYN_VARIABLE)(s),
|
|
45
|
+
variable: (s) => hex(SYN_VARIABLE)(s),
|
|
46
|
+
params: (s) => hex(SYN_VARIABLE)(s),
|
|
47
|
+
operator: (s) => hex(SYN_OPERATOR)(s),
|
|
48
|
+
punctuation: (s) => hex(SYN_PUNCTUATION)(s)
|
|
49
|
+
};
|
|
50
|
+
const miladySelectListTheme = {
|
|
51
|
+
selectedPrefix: (text) => hex(ACCENT)(text),
|
|
52
|
+
selectedText: (text) => chalk.bold(hex(ACCENT)(text)),
|
|
53
|
+
description: (text) => hex(MUTED)(text),
|
|
54
|
+
scrollInfo: (text) => hex(MUTED)(text),
|
|
55
|
+
noMatch: (text) => hex(MUTED)(text)
|
|
56
|
+
};
|
|
57
|
+
const miladyEditorTheme = {
|
|
58
|
+
borderColor: (text) => hex(DIM)(text),
|
|
59
|
+
selectList: miladySelectListTheme
|
|
60
|
+
};
|
|
61
|
+
const miladyMarkdownTheme = {
|
|
62
|
+
heading: (text) => chalk.bold(hex(MD_HEADING)(text)),
|
|
63
|
+
link: (text) => hex(MD_LINK)(text),
|
|
64
|
+
linkUrl: (text) => hex(DIM)(text),
|
|
65
|
+
code: (text) => hex(MD_CODE)(text),
|
|
66
|
+
codeBlock: (text) => hex(MD_CODE_BLOCK)(text),
|
|
67
|
+
codeBlockBorder: (text) => hex(MUTED)(text),
|
|
68
|
+
quote: (text) => hex(MUTED)(text),
|
|
69
|
+
quoteBorder: (text) => hex(MUTED)(text),
|
|
70
|
+
hr: (text) => hex(MUTED)(text),
|
|
71
|
+
listBullet: (text) => hex(ACCENT_DIM)(text),
|
|
72
|
+
bold: (text) => chalk.bold(text),
|
|
73
|
+
italic: (text) => chalk.italic(hex(ACCENT_DIM)(text)),
|
|
74
|
+
strikethrough: (text) => chalk.strikethrough(text),
|
|
75
|
+
underline: (text) => chalk.underline(text),
|
|
76
|
+
highlightCode: (code, lang) => {
|
|
77
|
+
const validLang = lang && supportsLanguage(lang) ? lang : void 0;
|
|
78
|
+
try {
|
|
79
|
+
return highlight(code, {
|
|
80
|
+
language: validLang,
|
|
81
|
+
ignoreIllegals: true,
|
|
82
|
+
theme: cliHighlightTheme
|
|
83
|
+
}).split("\n");
|
|
84
|
+
} catch {
|
|
85
|
+
return code.split("\n").map((line) => hex(MD_CODE_BLOCK)(line));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const tuiTheme = {
|
|
90
|
+
accent: (text) => hex(ACCENT)(text),
|
|
91
|
+
accentDim: (text) => hex(ACCENT_DIM)(text),
|
|
92
|
+
muted: (text) => hex(MUTED)(text),
|
|
93
|
+
dim: (text) => hex(DIM)(text),
|
|
94
|
+
success: (text) => hex(SUCCESS)(text),
|
|
95
|
+
error: (text) => hex(ERROR)(text),
|
|
96
|
+
warning: (text) => hex(WARNING)(text),
|
|
97
|
+
info: (text) => hex(INFO)(text),
|
|
98
|
+
bold: (text) => chalk.bold(text),
|
|
99
|
+
italic: (text) => chalk.italic(text),
|
|
100
|
+
userMsgBg: (text) => bg(USER_MSG_BG)(text),
|
|
101
|
+
toolPendingBg: (text) => bg(TOOL_PENDING_BG)(text),
|
|
102
|
+
toolSuccessBg: (text) => bg(TOOL_SUCCESS_BG)(text),
|
|
103
|
+
toolErrorBg: (text) => bg(TOOL_ERROR_BG)(text),
|
|
104
|
+
markdown: miladyMarkdownTheme,
|
|
105
|
+
editor: miladyEditorTheme,
|
|
106
|
+
selectList: miladySelectListTheme
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
//#endregion
|
|
110
|
+
export { miladyMarkdownTheme, tuiTheme };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
//#region src/tui/titlebar-spinner.ts
|
|
4
|
+
const BRAILLE_FRAMES = [
|
|
5
|
+
"⠋",
|
|
6
|
+
"⠙",
|
|
7
|
+
"⠹",
|
|
8
|
+
"⠸",
|
|
9
|
+
"⠼",
|
|
10
|
+
"⠴",
|
|
11
|
+
"⠦",
|
|
12
|
+
"⠧",
|
|
13
|
+
"⠇",
|
|
14
|
+
"⠏"
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Lightweight titlebar spinner used by the Milady TUI while a request is in
|
|
18
|
+
* flight.
|
|
19
|
+
*/
|
|
20
|
+
var TitlebarSpinner = class {
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.timer = null;
|
|
24
|
+
this.frameIndex = 0;
|
|
25
|
+
this.baseTitle = getDefaultTitle();
|
|
26
|
+
}
|
|
27
|
+
setBaseTitle(title) {
|
|
28
|
+
this.baseTitle = title.trim() || getDefaultTitle();
|
|
29
|
+
if (!this.timer) this.applyTitle(this.baseTitle);
|
|
30
|
+
}
|
|
31
|
+
start() {
|
|
32
|
+
this.stop();
|
|
33
|
+
const intervalMs = this.options.intervalMs ?? 80;
|
|
34
|
+
this.timer = setInterval(() => {
|
|
35
|
+
const frame = BRAILLE_FRAMES[this.frameIndex % BRAILLE_FRAMES.length] ?? "⠋";
|
|
36
|
+
this.applyTitle(`${frame} ${this.baseTitle}`);
|
|
37
|
+
this.frameIndex += 1;
|
|
38
|
+
}, intervalMs);
|
|
39
|
+
}
|
|
40
|
+
stop() {
|
|
41
|
+
if (this.timer) {
|
|
42
|
+
clearInterval(this.timer);
|
|
43
|
+
this.timer = null;
|
|
44
|
+
}
|
|
45
|
+
this.frameIndex = 0;
|
|
46
|
+
this.applyTitle(this.baseTitle);
|
|
47
|
+
}
|
|
48
|
+
dispose() {
|
|
49
|
+
this.stop();
|
|
50
|
+
}
|
|
51
|
+
applyTitle(title) {
|
|
52
|
+
try {
|
|
53
|
+
this.options.setTitle(title);
|
|
54
|
+
} catch {}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
function getDefaultTitle() {
|
|
58
|
+
return `milady - ${path.basename(process.cwd())}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
export { TitlebarSpinner };
|