mastracode 0.47.2-alpha.2 → 0.48.0-alpha.3
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/CHANGELOG.md +25 -0
- package/dist/cli.cjs +114 -8
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +114 -8
- package/dist/cli.js.map +1 -1
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/tui/command-dispatch.d.ts.map +1 -1
- package/dist/tui/commands/context.d.ts.map +1 -1
- package/dist/tui/commands/factory.d.ts +8 -0
- package/dist/tui/commands/factory.d.ts.map +1 -0
- package/dist/tui/commands/feedback.d.ts.map +1 -1
- package/dist/tui/commands/goal.d.ts.map +1 -1
- package/dist/tui/commands/index.d.ts +1 -0
- package/dist/tui/commands/index.d.ts.map +1 -1
- package/dist/tui/commands/models.d.ts.map +1 -1
- package/dist/tui/commands/om.d.ts.map +1 -1
- package/dist/tui/commands/permissions.d.ts.map +1 -1
- package/dist/tui/commands/prune.d.ts.map +1 -1
- package/dist/tui/commands/resource.d.ts.map +1 -1
- package/dist/tui/commands/skills.d.ts.map +1 -1
- package/dist/tui/commands/subagents.d.ts.map +1 -1
- package/dist/tui/commands/types.d.ts +4 -3
- package/dist/tui/commands/types.d.ts.map +1 -1
- package/dist/tui/commands/workflows.d.ts.map +1 -1
- package/dist/tui/components/help-overlay.d.ts.map +1 -1
- package/dist/tui/components/simple-select.d.ts +4 -0
- package/dist/tui/components/simple-select.d.ts.map +1 -0
- package/dist/tui/display.d.ts.map +1 -1
- package/dist/tui/mastra-tui.d.ts.map +1 -1
- package/dist/tui/model-packs/apply.d.ts +1 -1
- package/dist/tui/model-packs/apply.d.ts.map +1 -1
- package/dist/tui/runtime.d.ts +54 -0
- package/dist/tui/runtime.d.ts.map +1 -0
- package/dist/tui/setup.d.ts.map +1 -1
- package/dist/tui/state.d.ts +22 -3
- package/dist/tui/state.d.ts.map +1 -1
- package/dist/tui/status-line.d.ts.map +1 -1
- package/dist/tui/thread-startup.d.ts.map +1 -1
- package/dist/{tui-B5689bGt.cjs → tui-BpzUjTFI.cjs} +417 -82
- package/dist/tui-BpzUjTFI.cjs.map +1 -0
- package/dist/{tui-CLkPtYAM.js → tui-DCld2CJR.js} +417 -82
- package/dist/tui-DCld2CJR.js.map +1 -0
- package/dist/tui.cjs +1 -1
- package/dist/tui.js +1 -1
- package/package.json +9 -9
- package/dist/tui-B5689bGt.cjs.map +0 -1
- package/dist/tui-CLkPtYAM.js.map +0 -1
|
@@ -20,10 +20,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
20
20
|
enumerable: true
|
|
21
21
|
}) : target, mod));
|
|
22
22
|
//#endregion
|
|
23
|
+
let child_process = require("child_process");
|
|
23
24
|
let fs = require("fs");
|
|
24
25
|
fs = __toESM(fs, 1);
|
|
25
26
|
let _mastra_code_sdk_onboarding_pack_activation = require("@mastra/code-sdk/onboarding/pack-activation");
|
|
26
27
|
let _mastra_code_sdk_onboarding_settings = require("@mastra/code-sdk/onboarding/settings");
|
|
28
|
+
let _mastra_code_sdk_platform_index = require("@mastra/code-sdk/platform/index");
|
|
27
29
|
let _mastra_code_sdk_utils_thread_lock = require("@mastra/code-sdk/utils/thread-lock");
|
|
28
30
|
let _earendil_works_pi_tui = require("@earendil-works/pi-tui");
|
|
29
31
|
let os = require("os");
|
|
@@ -33,7 +35,6 @@ path = __toESM(path, 1);
|
|
|
33
35
|
let _mastra_code_sdk_theme_palette = require("@mastra/code-sdk/theme-palette");
|
|
34
36
|
let chalk = require("chalk");
|
|
35
37
|
chalk = __toESM(chalk, 1);
|
|
36
|
-
let child_process = require("child_process");
|
|
37
38
|
let _mastra_code_sdk_auth_account_rotation_processor = require("@mastra/code-sdk/auth/account-rotation-processor");
|
|
38
39
|
let _mastra_code_sdk_auth_storage = require("@mastra/code-sdk/auth/storage");
|
|
39
40
|
let _mastra_code_sdk_onboarding_index = require("@mastra/code-sdk/onboarding/index");
|
|
@@ -80,6 +81,7 @@ let fs_promises = require("fs/promises");
|
|
|
80
81
|
let _mastra_code_sdk_providers_model_ids = require("@mastra/code-sdk/providers/model-ids");
|
|
81
82
|
let _mastra_stagehand = require("@mastra/stagehand");
|
|
82
83
|
let _mastra_code_sdk_auth_index = require("@mastra/code-sdk/auth/index");
|
|
84
|
+
let _mastra_code_sdk_factory_client = require("@mastra/code-sdk/factory/client");
|
|
83
85
|
let _mastra_core_llm = require("@mastra/core/llm");
|
|
84
86
|
let _mastra_code_sdk_utils_project = require("@mastra/code-sdk/utils/project");
|
|
85
87
|
let _mastra_github_signals = require("@mastra/github-signals");
|
|
@@ -3039,6 +3041,57 @@ function promptForApiKeyIfNeeded(ui, model, authStorage) {
|
|
|
3039
3041
|
});
|
|
3040
3042
|
}
|
|
3041
3043
|
//#endregion
|
|
3044
|
+
//#region src/tui/runtime.ts
|
|
3045
|
+
/**
|
|
3046
|
+
* Returns the in-process runtime for local-only features. The command
|
|
3047
|
+
* dispatcher keeps local-only commands from running in Factory mode, so
|
|
3048
|
+
* reaching this without a local runtime is a bug.
|
|
3049
|
+
*/
|
|
3050
|
+
function requireLocal(state, feature) {
|
|
3051
|
+
if (!state.local) throw new Error(`${feature} is not available in Factory mode`);
|
|
3052
|
+
return state.local;
|
|
3053
|
+
}
|
|
3054
|
+
const LOCAL_ONLY_COMMANDS = /* @__PURE__ */ new Set([
|
|
3055
|
+
"thread:tag-dir",
|
|
3056
|
+
"sandbox",
|
|
3057
|
+
"workflows",
|
|
3058
|
+
"workflow",
|
|
3059
|
+
"skills",
|
|
3060
|
+
"packs",
|
|
3061
|
+
"models",
|
|
3062
|
+
"custom-providers",
|
|
3063
|
+
"subagents",
|
|
3064
|
+
"memory",
|
|
3065
|
+
"om",
|
|
3066
|
+
"knowledge",
|
|
3067
|
+
"voice",
|
|
3068
|
+
"connect",
|
|
3069
|
+
"login",
|
|
3070
|
+
"logout",
|
|
3071
|
+
"context",
|
|
3072
|
+
"ctx",
|
|
3073
|
+
"prune",
|
|
3074
|
+
"resource",
|
|
3075
|
+
"hooks",
|
|
3076
|
+
"mcp",
|
|
3077
|
+
"setup",
|
|
3078
|
+
"browser",
|
|
3079
|
+
"gateway",
|
|
3080
|
+
"memory-gateway",
|
|
3081
|
+
"api-keys",
|
|
3082
|
+
"plugins",
|
|
3083
|
+
"feedback",
|
|
3084
|
+
"observability",
|
|
3085
|
+
"goal",
|
|
3086
|
+
"schedules",
|
|
3087
|
+
"diff",
|
|
3088
|
+
"github",
|
|
3089
|
+
"settings"
|
|
3090
|
+
]);
|
|
3091
|
+
function isLocalOnlyCommand(command) {
|
|
3092
|
+
return LOCAL_ONLY_COMMANDS.has(command) || command.startsWith("goal/") || command.startsWith("skill/");
|
|
3093
|
+
}
|
|
3094
|
+
//#endregion
|
|
3042
3095
|
//#region src/tui/commands/goal.ts
|
|
3043
3096
|
/**
|
|
3044
3097
|
* /goal command — persistent cross-turn goals (Ralph loop).
|
|
@@ -3070,7 +3123,7 @@ async function handleGoalCommand(ctx, args) {
|
|
|
3070
3123
|
ctx.showInfo("No goal to pause.");
|
|
3071
3124
|
return;
|
|
3072
3125
|
}
|
|
3073
|
-
await goalManager.saveToThread(state);
|
|
3126
|
+
await goalManager.saveToThread(requireLocal(state, "/goal"));
|
|
3074
3127
|
ctx.updateStatusLine();
|
|
3075
3128
|
ctx.showInfo(`Goal paused: "${stripControlChars(goal.objective)}" (${goal.turnsUsed}/${goal.maxTurns} turns used). Use /goal resume to continue.`);
|
|
3076
3129
|
return;
|
|
@@ -3090,14 +3143,14 @@ async function handleGoalCommand(ctx, args) {
|
|
|
3090
3143
|
return;
|
|
3091
3144
|
}
|
|
3092
3145
|
goalManager.resume();
|
|
3093
|
-
await goalManager.saveToThread(state);
|
|
3146
|
+
await goalManager.saveToThread(requireLocal(state, "/goal"));
|
|
3094
3147
|
ctx.updateStatusLine();
|
|
3095
3148
|
const resumedGoal = goalManager.getGoal();
|
|
3096
3149
|
try {
|
|
3097
3150
|
await state.session.sendSignal((0, _mastra_code_sdk_goal_signal.createGoalReminderSignal)(resumedGoal)).accepted;
|
|
3098
3151
|
} catch (err) {
|
|
3099
3152
|
goalManager.pause();
|
|
3100
|
-
await goalManager.saveToThread(state);
|
|
3153
|
+
await goalManager.saveToThread(requireLocal(state, "/goal"));
|
|
3101
3154
|
if ((0, _mastra_core_agent_controller.isSessionStartupCancelledError)(err)) {
|
|
3102
3155
|
ctx.showInfo("Interrupted");
|
|
3103
3156
|
return;
|
|
@@ -3108,8 +3161,8 @@ async function handleGoalCommand(ctx, args) {
|
|
|
3108
3161
|
}
|
|
3109
3162
|
if (subCommand === "clear") {
|
|
3110
3163
|
goalManager.clear();
|
|
3111
|
-
if (!await goalManager.deleteFromThread(state)) {
|
|
3112
|
-
if (!await goalManager.loadFromThread(state)) {
|
|
3164
|
+
if (!await goalManager.deleteFromThread(requireLocal(state, "/goal"))) {
|
|
3165
|
+
if (!await goalManager.loadFromThread(requireLocal(state, "/goal"))) {
|
|
3113
3166
|
ctx.updateStatusLine();
|
|
3114
3167
|
ctx.showError("Could not clear the goal; it may still be active. Try /goal clear again.");
|
|
3115
3168
|
return;
|
|
@@ -3205,7 +3258,7 @@ async function showGoalActionModal(ctx) {
|
|
|
3205
3258
|
async function handleJudgeCommand(ctx) {
|
|
3206
3259
|
const defaults = await promptForJudgeDefaults(ctx, "Judge settings unchanged.");
|
|
3207
3260
|
if (!defaults) return;
|
|
3208
|
-
if (await ctx.state.goalManager.updateJudgeDefaults(ctx.state, defaults.judgeModelId, defaults.maxTurns)) {
|
|
3261
|
+
if (await ctx.state.goalManager.updateJudgeDefaults(requireLocal(ctx.state, "/goal"), defaults.judgeModelId, defaults.maxTurns)) {
|
|
3209
3262
|
ctx.showInfo(`Judge defaults set: ${defaults.judgeModelId}, ${defaults.maxTurns} max attempts. Current goal updated.`);
|
|
3210
3263
|
return;
|
|
3211
3264
|
}
|
|
@@ -3305,7 +3358,7 @@ async function setGoal(ctx, objective, judgeModelId, maxTurns) {
|
|
|
3305
3358
|
await state.session.thread.create();
|
|
3306
3359
|
state.pendingNewThread = false;
|
|
3307
3360
|
}
|
|
3308
|
-
goal = await goalManager.setGoal(state, objective, judgeModelId, maxTurns);
|
|
3361
|
+
goal = await goalManager.setGoal(requireLocal(state, "/goal"), objective, judgeModelId, maxTurns);
|
|
3309
3362
|
} catch (error) {
|
|
3310
3363
|
if (shouldPersistToCreatedThread) goalManager.consumePersistOnNextThreadCreate();
|
|
3311
3364
|
throw error;
|
|
@@ -3315,7 +3368,7 @@ async function setGoal(ctx, objective, judgeModelId, maxTurns) {
|
|
|
3315
3368
|
ctx.showError("Failed to set goal.");
|
|
3316
3369
|
return null;
|
|
3317
3370
|
}
|
|
3318
|
-
await goalManager.saveToThread(state);
|
|
3371
|
+
await goalManager.saveToThread(requireLocal(state, "/goal"));
|
|
3319
3372
|
ctx.updateStatusLine();
|
|
3320
3373
|
return goal;
|
|
3321
3374
|
}
|
|
@@ -3332,7 +3385,7 @@ async function sendGoalReminder(ctx, goal, options = {}) {
|
|
|
3332
3385
|
await (options.persistIfIdle ? state.session.sendSignal(signal, { ifIdle: { behavior: "persist" } }) : state.session.sendSignal(signal)).accepted;
|
|
3333
3386
|
} catch (err) {
|
|
3334
3387
|
goalManager.pause();
|
|
3335
|
-
await goalManager.saveToThread(state);
|
|
3388
|
+
await goalManager.saveToThread(requireLocal(state, "/goal"));
|
|
3336
3389
|
if ((0, _mastra_core_agent_controller.isSessionStartupCancelledError)(err)) {
|
|
3337
3390
|
ctx.showInfo("Interrupted");
|
|
3338
3391
|
return;
|
|
@@ -3477,6 +3530,14 @@ function getCommands(modes) {
|
|
|
3477
3530
|
key: "/login",
|
|
3478
3531
|
description: "Sign in with a provider account"
|
|
3479
3532
|
},
|
|
3533
|
+
{
|
|
3534
|
+
key: "/factory",
|
|
3535
|
+
description: "Switch to Factory mode (connects first if needed)"
|
|
3536
|
+
},
|
|
3537
|
+
{
|
|
3538
|
+
key: "/local",
|
|
3539
|
+
description: "Switch from Factory mode back to local mode"
|
|
3540
|
+
},
|
|
3480
3541
|
{
|
|
3481
3542
|
key: "/logout",
|
|
3482
3543
|
description: "Logout from OAuth provider"
|
|
@@ -3824,7 +3885,8 @@ function requestContextForSession(ctx) {
|
|
|
3824
3885
|
*/
|
|
3825
3886
|
async function collectSkillsCatalog(ctx) {
|
|
3826
3887
|
let workspace = ctx.getResolvedWorkspace();
|
|
3827
|
-
|
|
3888
|
+
const local = requireLocal(ctx.state, "/context");
|
|
3889
|
+
if (!workspace && local.controller.hasWorkspace()) workspace = await local.controller.resolveWorkspace({ session: local.session });
|
|
3828
3890
|
if (!workspace?.skills) return void 0;
|
|
3829
3891
|
const listed = await workspace.skills.list();
|
|
3830
3892
|
if (listed.length === 0) return void 0;
|
|
@@ -4461,7 +4523,7 @@ async function handleVoiceCommand(ctx, args = []) {
|
|
|
4461
4523
|
return;
|
|
4462
4524
|
}
|
|
4463
4525
|
if (arg === "status") {
|
|
4464
|
-
await showStatus$
|
|
4526
|
+
await showStatus$2(ctx);
|
|
4465
4527
|
return;
|
|
4466
4528
|
}
|
|
4467
4529
|
await runMenu(ctx);
|
|
@@ -4533,7 +4595,7 @@ function engineLabel(voice) {
|
|
|
4533
4595
|
const entry = (0, _mastra_code_sdk_voice_stt_registry.resolveSTTModel)(voice.provider, voice.model);
|
|
4534
4596
|
return `cloud · ${entry.provider}/${entry.model}`;
|
|
4535
4597
|
}
|
|
4536
|
-
async function showStatus$
|
|
4598
|
+
async function showStatus$2(ctx) {
|
|
4537
4599
|
const voice = (0, _mastra_code_sdk_onboarding_settings.loadSettings)().voice;
|
|
4538
4600
|
const lines = [`Voice input: ${ctx.state.voiceController?.isEnabled() ? "on" : "off"}`, ` Engine: ${engineLabel(voice)}`];
|
|
4539
4601
|
if (voice.engine === "cloud") {
|
|
@@ -4589,7 +4651,7 @@ async function runMenu(ctx) {
|
|
|
4589
4651
|
await chooseModel(ctx);
|
|
4590
4652
|
return;
|
|
4591
4653
|
case "Status":
|
|
4592
|
-
await showStatus$
|
|
4654
|
+
await showStatus$2(ctx);
|
|
4593
4655
|
return;
|
|
4594
4656
|
}
|
|
4595
4657
|
}
|
|
@@ -4871,7 +4933,10 @@ async function handlePermissionsCommand(ctx, args) {
|
|
|
4871
4933
|
async function showPermissions(ctx) {
|
|
4872
4934
|
const { TOOL_CATEGORIES, getToolsForCategory } = await import("@mastra/code-sdk/permissions");
|
|
4873
4935
|
const rules = ctx.state.session.permissions.getRules();
|
|
4874
|
-
const grants = ctx.state.session.getGrants()
|
|
4936
|
+
const grants = ctx.state.local?.session.getGrants() ?? {
|
|
4937
|
+
categories: [],
|
|
4938
|
+
tools: []
|
|
4939
|
+
};
|
|
4875
4940
|
const isYolo = ctx.state.session.state.get()?.yolo === true;
|
|
4876
4941
|
const lines = [];
|
|
4877
4942
|
lines.push("Tool Approval Permissions");
|
|
@@ -5704,8 +5769,9 @@ function showFormattedError(state, event) {
|
|
|
5704
5769
|
}
|
|
5705
5770
|
const lines = [new _earendil_works_pi_tui.Text(theme.fg("error", errorText), 1, 0)];
|
|
5706
5771
|
const isObservationalMemoryError = /observational memory|\bOM (?:observation|reflection)/i.test(error.message);
|
|
5707
|
-
const
|
|
5708
|
-
const
|
|
5772
|
+
const om = state.local?.session.om;
|
|
5773
|
+
const omRole = /reflect/i.test(error.message) ? om?.reflector : om?.observer;
|
|
5774
|
+
const hint = withOMGuidance(state.factory && parsed.type === "auth" ? `Add the provider credential in Factory (${state.factory.url})` : getErrorHint(parsed.type), isObservationalMemoryError ? omRole?.modelId() : void 0);
|
|
5709
5775
|
if (hint) lines.push(new _earendil_works_pi_tui.Text(theme.fg("muted", ` Hint: ${hint}`), 1, 0));
|
|
5710
5776
|
const component = new InfoMessageComponent(lines);
|
|
5711
5777
|
insertChatComponentWithBoundarySpacing(state.chatContainer, component, getInsertIndexBeforePrompt(state));
|
|
@@ -6093,7 +6159,7 @@ async function applyPackToSession(ctx, packId, options = {}) {
|
|
|
6093
6159
|
await ctx.state.session.model.switch(selection.modelId, { ...options.thinkingLevel !== void 0 ? { thinkingLevel: options.thinkingLevel } : {} });
|
|
6094
6160
|
if (!application.isCurrent()) return cancelled();
|
|
6095
6161
|
for (const [agentType, modelId] of Object.entries(selection.subagentModels)) {
|
|
6096
|
-
await ctx.state.session.subagents.model.set({
|
|
6162
|
+
await ctx.state.local?.session.subagents.model.set({
|
|
6097
6163
|
modelId,
|
|
6098
6164
|
agentType
|
|
6099
6165
|
});
|
|
@@ -6125,6 +6191,7 @@ async function resolveActivePackId(ctx, settings) {
|
|
|
6125
6191
|
};
|
|
6126
6192
|
}
|
|
6127
6193
|
async function applyCurrentThreadPack(ctx, options = {}) {
|
|
6194
|
+
if (!ctx.state.local) return { applied: true };
|
|
6128
6195
|
const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
|
|
6129
6196
|
const modeId = options.modeId ?? ctx.state.session.mode.get();
|
|
6130
6197
|
const resolution = options.packId === void 0 ? await resolveActivePackId(ctx, settings) : {
|
|
@@ -6167,6 +6234,7 @@ async function switchModeWithPack(ctx, modeId) {
|
|
|
6167
6234
|
if (!(await applyCurrentThreadPack(ctx, { modeId })).applied) throw new Error("Mode switch was superseded before its model selection completed.");
|
|
6168
6235
|
}
|
|
6169
6236
|
async function reconcilePackAfterModeChange(ctx, modeId) {
|
|
6237
|
+
if (!ctx.state.local) return;
|
|
6170
6238
|
const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
|
|
6171
6239
|
const resolution = await resolveActivePackId(ctx, settings);
|
|
6172
6240
|
if (!resolution?.packId || ctx.state.session.mode.get() !== modeId) return;
|
|
@@ -12232,7 +12300,8 @@ function escapeSkillBoundary(value) {
|
|
|
12232
12300
|
}
|
|
12233
12301
|
async function resolveWorkspace(ctx) {
|
|
12234
12302
|
let workspace = ctx.getResolvedWorkspace();
|
|
12235
|
-
|
|
12303
|
+
const local = requireLocal(ctx.state, "Skills");
|
|
12304
|
+
if (!workspace && local.controller.hasWorkspace()) workspace = await local.controller.resolveWorkspace({ session: local.session });
|
|
12236
12305
|
return workspace;
|
|
12237
12306
|
}
|
|
12238
12307
|
async function handleSkillsCommand(ctx) {
|
|
@@ -12433,8 +12502,8 @@ async function handleCloneCommand(ctx) {
|
|
|
12433
12502
|
//#endregion
|
|
12434
12503
|
//#region src/tui/commands/resource.ts
|
|
12435
12504
|
async function handleResourceCommand(ctx, args) {
|
|
12436
|
-
const { state
|
|
12437
|
-
const { session } = state;
|
|
12505
|
+
const { state } = ctx;
|
|
12506
|
+
const { controller, session } = requireLocal(state, "/resource");
|
|
12438
12507
|
const sub = args[0]?.trim();
|
|
12439
12508
|
const current = session.identity.getResourceId();
|
|
12440
12509
|
const defaultId = session.identity.getDefaultResourceId();
|
|
@@ -12923,7 +12992,7 @@ async function handleThreadsCommand(ctx) {
|
|
|
12923
12992
|
resolve();
|
|
12924
12993
|
return;
|
|
12925
12994
|
}
|
|
12926
|
-
if (thread.resourceId !== currentResourceId) await state.controller.setResourceId(state.session, { resourceId: thread.resourceId });
|
|
12995
|
+
if (state.local && thread.resourceId !== currentResourceId) await state.local.controller.setResourceId(state.local.session, { resourceId: thread.resourceId });
|
|
12927
12996
|
try {
|
|
12928
12997
|
await state.session.thread.switch({ threadId: thread.id });
|
|
12929
12998
|
if (state.options.backgroundToolsEnabled) await state.waitForAgentControllerEvents?.();
|
|
@@ -13280,6 +13349,31 @@ async function handleModelCommand(ctx) {
|
|
|
13280
13349
|
ctx.showInfo("No connected models. Use /connect to add a provider account or API key.");
|
|
13281
13350
|
return;
|
|
13282
13351
|
}
|
|
13352
|
+
if (ctx.state.factory) return new Promise((resolve) => {
|
|
13353
|
+
const selector = new ModelSelectorComponent({
|
|
13354
|
+
tui: ctx.state.ui,
|
|
13355
|
+
models: connected,
|
|
13356
|
+
currentModelId,
|
|
13357
|
+
onSelect: async (model) => {
|
|
13358
|
+
ctx.state.ui.hideOverlay();
|
|
13359
|
+
try {
|
|
13360
|
+
await ctx.state.session.model.switch(model.id);
|
|
13361
|
+
ctx.updateStatusLine();
|
|
13362
|
+
ctx.showInfo(`Switched to ${model.id}`);
|
|
13363
|
+
} catch (error) {
|
|
13364
|
+
ctx.showError(`Failed to switch model: ${error instanceof Error ? error.message : String(error)}`);
|
|
13365
|
+
} finally {
|
|
13366
|
+
resolve();
|
|
13367
|
+
}
|
|
13368
|
+
},
|
|
13369
|
+
onCancel: () => {
|
|
13370
|
+
ctx.state.ui.hideOverlay();
|
|
13371
|
+
resolve();
|
|
13372
|
+
}
|
|
13373
|
+
});
|
|
13374
|
+
showModalOverlay(ctx.state.ui, selector, { maxHeight: "75%" });
|
|
13375
|
+
selector.focused = true;
|
|
13376
|
+
});
|
|
13283
13377
|
const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
|
|
13284
13378
|
const threadId = ctx.state.session.thread.getId?.();
|
|
13285
13379
|
const activePackId = (0, _mastra_code_sdk_onboarding_settings.parseThreadSettings)((threadId ? (await ctx.state.session.thread.list()).find((item) => item.id === threadId) : void 0)?.metadata).activeModelPackId ?? settings.models.activeModelPackId;
|
|
@@ -13776,7 +13870,7 @@ function updateStatusLine(state) {
|
|
|
13776
13870
|
const status = isObserving ? "observing" : "reflecting";
|
|
13777
13871
|
if (state.omStatusLineModel?.status !== status) state.omStatusLineModel = {
|
|
13778
13872
|
status,
|
|
13779
|
-
modelId: getEffectiveOMRoleModelId(state.session, isObserving ? "observer" : "reflector")
|
|
13873
|
+
modelId: state.local ? getEffectiveOMRoleModelId(state.local.session, isObserving ? "observer" : "reflector") : void 0
|
|
13780
13874
|
};
|
|
13781
13875
|
} else state.omStatusLineModel = void 0;
|
|
13782
13876
|
const rawModelId = (isJudging ? state.activeGoalJudge?.modelId : showOMMode ? state.omStatusLineModel?.modelId : state.session.model.get()) ?? "";
|
|
@@ -13842,7 +13936,7 @@ function updateStatusLine(state) {
|
|
|
13842
13936
|
plain: indicator.plain.trimEnd() + pct,
|
|
13843
13937
|
styled: (sweep ? applyGradientSweep(indicator.plain.trimEnd(), sweep.getOffset(), displayState.bufferingMessages ? modeColor ?? theme.getTheme().accent : mastra.blue, sweep.getFadeProgress()) : indicator.styled.trimEnd()) + theme.fg("dim", pct)
|
|
13844
13938
|
} : null;
|
|
13845
|
-
const branch = state.projectInfo.gitBranch;
|
|
13939
|
+
const branch = state.factory?.branch ?? state.projectInfo.gitBranch;
|
|
13846
13940
|
const threadTitle = state.currentThreadTitle && !isGenericTitle(state.currentThreadTitle) ? state.currentThreadTitle : null;
|
|
13847
13941
|
const activeGithubPrSubscriptions = state.activeGithubPrSubscriptions ?? [];
|
|
13848
13942
|
const githubPrLabel = activeGithubPrSubscriptions.length > 0 ? formatGithubPrLabel(state, activeGithubPrSubscriptions) : null;
|
|
@@ -13865,7 +13959,7 @@ function updateStatusLine(state) {
|
|
|
13865
13959
|
plain: branch ? `${path} (${branch})` : path,
|
|
13866
13960
|
styled: theme.fg("muted", path) + (branch ? theme.fg("dim", ` (${branch})`) : "")
|
|
13867
13961
|
});
|
|
13868
|
-
const path = shortPath(state.projectInfo.rootPath ?? process.cwd());
|
|
13962
|
+
const path = state.factory ? `${state.factory.projectName} / ${state.factory.repositorySlug}` : shortPath(state.projectInfo.rootPath ?? process.cwd());
|
|
13869
13963
|
text = (fit === "full" ? [withBranch(path)] : compactPaths(path).map(withBranch)).find((candidate) => fits(candidate.plain)) ?? null;
|
|
13870
13964
|
if (!text && fit === "any" && room >= 10) {
|
|
13871
13965
|
const value = branch ? fits(branch) ? branch : truncateEnd(branch, room) : truncateLastSegment(compactPaths(path).at(-1), room);
|
|
@@ -15417,7 +15511,7 @@ async function showSubagentModelListForScope(ctx, scope, agentType, agentTypeLab
|
|
|
15417
15511
|
ctx.showInfo("No models available. Check your Mastra configuration.");
|
|
15418
15512
|
return;
|
|
15419
15513
|
}
|
|
15420
|
-
const currentSubagentModel = ctx.state.session.subagents.model.get({ agentType });
|
|
15514
|
+
const currentSubagentModel = requireLocal(ctx.state, "/subagents").session.subagents.model.get({ agentType });
|
|
15421
15515
|
const scopeLabel = scope === "global" ? `${agentTypeLabel} · Global` : `${agentTypeLabel} · Thread`;
|
|
15422
15516
|
return new Promise((resolve) => {
|
|
15423
15517
|
const selector = new ModelSelectorComponent({
|
|
@@ -15429,7 +15523,7 @@ async function showSubagentModelListForScope(ctx, scope, agentType, agentTypeLab
|
|
|
15429
15523
|
ctx.state.ui.hideOverlay();
|
|
15430
15524
|
await promptForApiKeyIfNeeded(ctx.state.ui, model, ctx.authStorage);
|
|
15431
15525
|
try {
|
|
15432
|
-
await ctx.state.session.subagents.model.set({
|
|
15526
|
+
await requireLocal(ctx.state, "/subagents").session.subagents.model.set({
|
|
15433
15527
|
modelId: model.id,
|
|
15434
15528
|
agentType
|
|
15435
15529
|
});
|
|
@@ -15868,21 +15962,22 @@ function persistOmCavemanObservations(enabled) {
|
|
|
15868
15962
|
}
|
|
15869
15963
|
async function handleOMCommand(ctx) {
|
|
15870
15964
|
const availableModels = await ctx.state.controller.listAvailableModels();
|
|
15965
|
+
const { session } = requireLocal(ctx.state, "/om");
|
|
15871
15966
|
const agentControllerState = ctx.state.session.state.get();
|
|
15872
|
-
const observerModelId = getEffectiveOMRoleModelId(
|
|
15873
|
-
const reflectorModelId = getEffectiveOMRoleModelId(
|
|
15967
|
+
const observerModelId = getEffectiveOMRoleModelId(session, "observer") ?? "";
|
|
15968
|
+
const reflectorModelId = getEffectiveOMRoleModelId(session, "reflector") ?? "";
|
|
15874
15969
|
const packMemoryModelId = (0, _mastra_code_sdk_agents_model.getActiveRouteMemoryModelId)(agentControllerState, ctx.state.session.thread.getId());
|
|
15875
15970
|
const autoModelId = (0, _mastra_code_sdk_onboarding_packs.resolveAutoOMModelId)(ctx.state.session.model.get() ?? void 0);
|
|
15876
15971
|
const config = {
|
|
15877
|
-
observerModel:
|
|
15972
|
+
observerModel: session.om.observer.model() ?? "auto",
|
|
15878
15973
|
observerModelId,
|
|
15879
15974
|
observerAutoModelId: autoModelId,
|
|
15880
|
-
reflectorModel:
|
|
15975
|
+
reflectorModel: session.om.reflector.model() ?? "auto",
|
|
15881
15976
|
reflectorModelId,
|
|
15882
15977
|
reflectorAutoModelId: autoModelId,
|
|
15883
15978
|
packMemoryModelId,
|
|
15884
|
-
observationThreshold:
|
|
15885
|
-
reflectionThreshold:
|
|
15979
|
+
observationThreshold: session.om.observer.threshold() ?? 3e4,
|
|
15980
|
+
reflectionThreshold: session.om.reflector.threshold() ?? 4e4,
|
|
15886
15981
|
cavemanObservations: agentControllerState?.cavemanObservations ?? false,
|
|
15887
15982
|
observeAttachments: agentControllerState?.observeAttachments ?? "auto"
|
|
15888
15983
|
};
|
|
@@ -15890,25 +15985,25 @@ async function handleOMCommand(ctx) {
|
|
|
15890
15985
|
const settings = new OMSettingsComponent(config, {
|
|
15891
15986
|
onObserverModelChange: async (model) => {
|
|
15892
15987
|
await promptForApiKeyIfNeeded(ctx.state.ui, model, ctx.authStorage);
|
|
15893
|
-
await
|
|
15988
|
+
await session.om.observer.switchModel({ modelId: model.id });
|
|
15894
15989
|
persistOmRoleOverride("observer", model.id);
|
|
15895
15990
|
ctx.showInfo(`Observer model → ${model.id}`);
|
|
15896
15991
|
},
|
|
15897
15992
|
onObserverAuto: async () => {
|
|
15898
|
-
await
|
|
15993
|
+
await session.om.observer.switchModel({ modelId: "auto" });
|
|
15899
15994
|
persistOmRoleAuto("observer");
|
|
15900
|
-
ctx.showInfo(`Observer model → Auto (${getEffectiveOMRoleModelId(
|
|
15995
|
+
ctx.showInfo(`Observer model → Auto (${getEffectiveOMRoleModelId(session, "observer") ?? "unavailable"})`);
|
|
15901
15996
|
},
|
|
15902
15997
|
onReflectorModelChange: async (model) => {
|
|
15903
15998
|
await promptForApiKeyIfNeeded(ctx.state.ui, model, ctx.authStorage);
|
|
15904
|
-
await
|
|
15999
|
+
await session.om.reflector.switchModel({ modelId: model.id });
|
|
15905
16000
|
persistOmRoleOverride("reflector", model.id);
|
|
15906
16001
|
ctx.showInfo(`Reflector model → ${model.id}`);
|
|
15907
16002
|
},
|
|
15908
16003
|
onReflectorAuto: async () => {
|
|
15909
|
-
await
|
|
16004
|
+
await session.om.reflector.switchModel({ modelId: "auto" });
|
|
15910
16005
|
persistOmRoleAuto("reflector");
|
|
15911
|
-
ctx.showInfo(`Reflector model → Auto (${getEffectiveOMRoleModelId(
|
|
16006
|
+
ctx.showInfo(`Reflector model → Auto (${getEffectiveOMRoleModelId(session, "reflector") ?? "unavailable"})`);
|
|
15912
16007
|
},
|
|
15913
16008
|
onObservationThresholdChange: async (value) => {
|
|
15914
16009
|
await ctx.state.session.state.set({ observationThreshold: value });
|
|
@@ -17527,7 +17622,7 @@ function applyBrowserToAgents(ctx, browser, browserSettings, chatModelId) {
|
|
|
17527
17622
|
const modes = ctx.controller.listModes();
|
|
17528
17623
|
let agentControllerState;
|
|
17529
17624
|
for (const mode of modes) resolveModeAgent(mode, agentControllerState ??= ctx.state.session.state.get())?.setBrowser?.(browser);
|
|
17530
|
-
ctx.controller.setBrowser
|
|
17625
|
+
ctx.state.local?.controller.setBrowser(browser);
|
|
17531
17626
|
ctx.state.session.state.set({
|
|
17532
17627
|
[ACTIVE_BROWSER_KEY]: browserSettings ? (0, _mastra_code_sdk_onboarding_settings.toActiveBrowserSettings)(browserSettings) : void 0,
|
|
17533
17628
|
[ACTIVE_BROWSER_MODEL_KEY]: browserSettings?.enabled ? (0, _mastra_code_sdk_onboarding_settings.resolveStagehandModel)(browserSettings, { chatModelId }) : void 0
|
|
@@ -18751,6 +18846,196 @@ async function handleConnectCommand(ctx) {
|
|
|
18751
18846
|
else if (method === "api-key") await handleApiKeysCommand(ctx);
|
|
18752
18847
|
}
|
|
18753
18848
|
//#endregion
|
|
18849
|
+
//#region src/tui/components/simple-select.ts
|
|
18850
|
+
/** Modal single-choice picker. Resolves with the chosen value, or null on cancel. */
|
|
18851
|
+
function promptSelect(tui, title, items) {
|
|
18852
|
+
return new Promise((resolve) => {
|
|
18853
|
+
const container = new _earendil_works_pi_tui.Box(4, 2, (text) => theme.bg("overlayBg", text));
|
|
18854
|
+
container.addChild(new _earendil_works_pi_tui.Text(theme.bold(theme.fg("accent", title)), 0, 0));
|
|
18855
|
+
container.addChild(new _earendil_works_pi_tui.Spacer(1));
|
|
18856
|
+
const selectList = new _earendil_works_pi_tui.SelectList(items, Math.min(items.length, 12), getSelectListTheme());
|
|
18857
|
+
const close = (value) => {
|
|
18858
|
+
tui.hideOverlay();
|
|
18859
|
+
tui.requestRender();
|
|
18860
|
+
resolve(value);
|
|
18861
|
+
};
|
|
18862
|
+
selectList.onSelect = (item) => close(item.value);
|
|
18863
|
+
selectList.onCancel = () => close(null);
|
|
18864
|
+
container.addChild(selectList);
|
|
18865
|
+
container.addChild(new _earendil_works_pi_tui.Spacer(1));
|
|
18866
|
+
container.addChild(new _earendil_works_pi_tui.Text(theme.fg("dim", "↑↓ navigate · Enter select · Esc cancel"), 0, 0));
|
|
18867
|
+
container.handleInput = (data) => selectList.handleInput(data);
|
|
18868
|
+
showModalOverlay(tui, container, {
|
|
18869
|
+
widthPercent: .8,
|
|
18870
|
+
maxHeight: "60%"
|
|
18871
|
+
});
|
|
18872
|
+
});
|
|
18873
|
+
}
|
|
18874
|
+
//#endregion
|
|
18875
|
+
//#region src/tui/commands/factory.ts
|
|
18876
|
+
const USAGE$1 = "Usage: /factory [connect|status|local|disconnect]";
|
|
18877
|
+
/**
|
|
18878
|
+
* `/factory` switches into the saved Factory (connecting first if there is none);
|
|
18879
|
+
* `/factory local` (or `/local`) switches back without forgetting the connection.
|
|
18880
|
+
*/
|
|
18881
|
+
async function handleFactoryCommand(ctx, args) {
|
|
18882
|
+
const sub = args[0];
|
|
18883
|
+
if (sub === "status") return showStatus$1(ctx);
|
|
18884
|
+
if (sub === "disconnect") return disconnect(ctx);
|
|
18885
|
+
if (sub === "local") return switchToLocal(ctx);
|
|
18886
|
+
if (sub === "connect") return connect(ctx);
|
|
18887
|
+
if (sub !== void 0) return ctx.showError(USAGE$1);
|
|
18888
|
+
if (!(0, _mastra_code_sdk_onboarding_settings.loadSettings)().factory) return connect(ctx);
|
|
18889
|
+
if (inFactoryMode(ctx)) return showStatus$1(ctx);
|
|
18890
|
+
return switchToFactory(ctx);
|
|
18891
|
+
}
|
|
18892
|
+
async function handleLocalCommand(ctx) {
|
|
18893
|
+
return switchToLocal(ctx);
|
|
18894
|
+
}
|
|
18895
|
+
function inFactoryMode(ctx) {
|
|
18896
|
+
return !ctx.state.local;
|
|
18897
|
+
}
|
|
18898
|
+
function showStatus$1(ctx) {
|
|
18899
|
+
const factory = (0, _mastra_code_sdk_onboarding_settings.loadSettings)().factory;
|
|
18900
|
+
if (!factory) return ctx.showInfo("Not connected to a Factory. Run /factory to connect.");
|
|
18901
|
+
const where = `${factory.factoryProjectName} / ${factory.repositorySlug} on ${factory.branch} (${factory.projectName} · ${factory.environmentName}, ${factory.url})`;
|
|
18902
|
+
ctx.showInfo(inFactoryMode(ctx) ? `Factory mode: ${where}. Run /local to work locally.` : `Local mode. Saved Factory: ${where}. Run /factory to switch to it.`);
|
|
18903
|
+
}
|
|
18904
|
+
function setActive(active) {
|
|
18905
|
+
const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
|
|
18906
|
+
if (!settings.factory) return;
|
|
18907
|
+
settings.factory = {
|
|
18908
|
+
...settings.factory,
|
|
18909
|
+
active
|
|
18910
|
+
};
|
|
18911
|
+
(0, _mastra_code_sdk_onboarding_settings.saveSettings)(settings);
|
|
18912
|
+
}
|
|
18913
|
+
/** Restart into the mode settings now select, or tell the user to restart when that isn't possible. */
|
|
18914
|
+
async function restartInto(ctx, mode) {
|
|
18915
|
+
const relaunch = ctx.state.options.relaunch;
|
|
18916
|
+
if (!relaunch) return ctx.showInfo(`Restart Mastra Code to switch to ${mode}.`);
|
|
18917
|
+
ctx.showInfo(`Switching to ${mode}…`);
|
|
18918
|
+
await relaunch();
|
|
18919
|
+
}
|
|
18920
|
+
async function switchToFactory(ctx) {
|
|
18921
|
+
setActive(true);
|
|
18922
|
+
await restartInto(ctx, "Factory mode");
|
|
18923
|
+
}
|
|
18924
|
+
async function switchToLocal(ctx) {
|
|
18925
|
+
if (!inFactoryMode(ctx)) {
|
|
18926
|
+
setActive(false);
|
|
18927
|
+
return ctx.showInfo("Already in local mode.");
|
|
18928
|
+
}
|
|
18929
|
+
setActive(false);
|
|
18930
|
+
await restartInto(ctx, "local mode");
|
|
18931
|
+
}
|
|
18932
|
+
async function disconnect(ctx) {
|
|
18933
|
+
const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
|
|
18934
|
+
if (!settings.factory) return ctx.showInfo("Not connected to a Factory.");
|
|
18935
|
+
settings.factory = null;
|
|
18936
|
+
(0, _mastra_code_sdk_onboarding_settings.saveSettings)(settings);
|
|
18937
|
+
if (inFactoryMode(ctx)) return restartInto(ctx, "local mode");
|
|
18938
|
+
ctx.showInfo("Disconnected from Factory.");
|
|
18939
|
+
}
|
|
18940
|
+
async function ensureSession(ctx) {
|
|
18941
|
+
const existing = await (0, _mastra_code_sdk_platform_index.getPlatformSession)();
|
|
18942
|
+
if (existing) return existing;
|
|
18943
|
+
ctx.showInfo("Opening your browser to sign in to Mastra Platform…");
|
|
18944
|
+
try {
|
|
18945
|
+
const creds = await (0, _mastra_code_sdk_platform_index.loginToPlatform)({ onUrl: (url) => ctx.showInfo(`If the browser did not open, visit: ${url}`) });
|
|
18946
|
+
ctx.showInfo(`Signed in as ${creds.user.email}`);
|
|
18947
|
+
return {
|
|
18948
|
+
token: creds.token,
|
|
18949
|
+
orgId: creds.currentOrgId ?? creds.organizationId
|
|
18950
|
+
};
|
|
18951
|
+
} catch (error) {
|
|
18952
|
+
ctx.showError(`Mastra Platform login failed: ${error.message}`);
|
|
18953
|
+
return null;
|
|
18954
|
+
}
|
|
18955
|
+
}
|
|
18956
|
+
async function connect(ctx) {
|
|
18957
|
+
const ui = ctx.state.ui;
|
|
18958
|
+
let session = await ensureSession(ctx);
|
|
18959
|
+
if (!session) return;
|
|
18960
|
+
try {
|
|
18961
|
+
const orgs = await (0, _mastra_code_sdk_platform_index.fetchPlatformOrgs)(session);
|
|
18962
|
+
if (orgs.length > 1) {
|
|
18963
|
+
const orgId = await promptSelect(ui, "Select organization:", orgs.map((org) => ({
|
|
18964
|
+
value: org.id,
|
|
18965
|
+
label: ` ${org.name}`,
|
|
18966
|
+
description: org.id === session.orgId ? "current" : void 0
|
|
18967
|
+
})));
|
|
18968
|
+
if (!orgId) return;
|
|
18969
|
+
session = {
|
|
18970
|
+
...session,
|
|
18971
|
+
orgId
|
|
18972
|
+
};
|
|
18973
|
+
} else if (orgs.length === 1 && orgs[0].id !== session.orgId) session = {
|
|
18974
|
+
...session,
|
|
18975
|
+
orgId: orgs[0].id
|
|
18976
|
+
};
|
|
18977
|
+
const projects = await (0, _mastra_code_sdk_platform_index.fetchPlatformProjects)(session);
|
|
18978
|
+
if (projects.length === 0) return ctx.showError("No projects found in this organization.");
|
|
18979
|
+
const projectId = await promptSelect(ui, "Select project:", projects.map((project) => ({
|
|
18980
|
+
value: project.id,
|
|
18981
|
+
label: ` ${project.name}`
|
|
18982
|
+
})));
|
|
18983
|
+
const project = projects.find((p) => p.id === projectId);
|
|
18984
|
+
if (!project) return;
|
|
18985
|
+
const environments = (await (0, _mastra_code_sdk_platform_index.fetchPlatformEnvironments)(session, project.id)).filter(_mastra_code_sdk_platform_index.resolveFactoryUrl);
|
|
18986
|
+
if (environments.length === 0) return ctx.showError(`${project.name} has no deployed environments. Deploy it with \`mastra deploy\` first.`);
|
|
18987
|
+
const environmentId = environments.length === 1 ? environments[0].id : await promptSelect(ui, "Select environment:", environments.map((env) => ({
|
|
18988
|
+
value: env.id,
|
|
18989
|
+
label: ` ${env.name}`,
|
|
18990
|
+
description: (0, _mastra_code_sdk_platform_index.resolveFactoryUrl)(env)
|
|
18991
|
+
})));
|
|
18992
|
+
const environment = environments.find((env) => env.id === environmentId);
|
|
18993
|
+
if (!environment) return;
|
|
18994
|
+
const address = {
|
|
18995
|
+
url: (0, _mastra_code_sdk_platform_index.resolveFactoryUrl)(environment),
|
|
18996
|
+
session
|
|
18997
|
+
};
|
|
18998
|
+
const factoryProjects = (await (0, _mastra_code_sdk_factory_client.listFactoryProjects)(address)).filter((p) => p.repositories.length > 0);
|
|
18999
|
+
if (factoryProjects.length === 0) return ctx.showError("This Factory has no projects with linked repositories. Link one in the Factory UI first.");
|
|
19000
|
+
const factoryProjectId = factoryProjects.length === 1 ? factoryProjects[0].id : await promptSelect(ui, "Select Factory project:", factoryProjects.map((p) => ({
|
|
19001
|
+
value: p.id,
|
|
19002
|
+
label: ` ${p.name}`
|
|
19003
|
+
})));
|
|
19004
|
+
const factoryProject = factoryProjects.find((p) => p.id === factoryProjectId);
|
|
19005
|
+
if (!factoryProject) return;
|
|
19006
|
+
const repositories = factoryProject.repositories;
|
|
19007
|
+
const projectRepositoryId = repositories.length === 1 ? repositories[0].projectRepositoryId : await promptSelect(ui, "Select repository:", repositories.map((r) => ({
|
|
19008
|
+
value: r.projectRepositoryId,
|
|
19009
|
+
label: ` ${r.slug}`,
|
|
19010
|
+
description: r.branch
|
|
19011
|
+
})));
|
|
19012
|
+
const repository = repositories.find((r) => r.projectRepositoryId === projectRepositoryId);
|
|
19013
|
+
if (!repository) return;
|
|
19014
|
+
const userSession = await (0, _mastra_code_sdk_factory_client.createFactoryUserSession)(address, repository.projectRepositoryId);
|
|
19015
|
+
const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
|
|
19016
|
+
settings.factory = {
|
|
19017
|
+
url: address.url,
|
|
19018
|
+
orgId: session.orgId,
|
|
19019
|
+
projectId: project.id,
|
|
19020
|
+
projectName: project.name,
|
|
19021
|
+
environmentId: environment.id,
|
|
19022
|
+
environmentName: environment.name,
|
|
19023
|
+
factoryProjectId: factoryProject.id,
|
|
19024
|
+
factoryProjectName: factoryProject.name,
|
|
19025
|
+
projectRepositoryId: repository.projectRepositoryId,
|
|
19026
|
+
repositorySlug: repository.slug,
|
|
19027
|
+
sessionId: userSession.sessionId,
|
|
19028
|
+
branch: userSession.branch,
|
|
19029
|
+
active: true
|
|
19030
|
+
};
|
|
19031
|
+
(0, _mastra_code_sdk_onboarding_settings.saveSettings)(settings);
|
|
19032
|
+
ctx.showInfo(`Connected to Factory ${factoryProject.name} / ${repository.slug} — new session on ${userSession.branch} (${address.url}).`);
|
|
19033
|
+
await restartInto(ctx, "Factory mode");
|
|
19034
|
+
} catch (error) {
|
|
19035
|
+
ctx.showError(`Failed to connect to Factory: ${error.message}`);
|
|
19036
|
+
}
|
|
19037
|
+
}
|
|
19038
|
+
//#endregion
|
|
18754
19039
|
//#region src/tui/commands/review.ts
|
|
18755
19040
|
async function handleReviewCommand(ctx, args) {
|
|
18756
19041
|
if (!ctx.state.session.model.hasSelection()) {
|
|
@@ -19505,7 +19790,7 @@ async function handleFeedbackCommand(ctx, args) {
|
|
|
19505
19790
|
ctx.showError("No active session to attach feedback to.");
|
|
19506
19791
|
return;
|
|
19507
19792
|
}
|
|
19508
|
-
const observability = ctx.controller.getMastra()?.observability;
|
|
19793
|
+
const observability = requireLocal(ctx.state, "/feedback").controller.getMastra()?.observability;
|
|
19509
19794
|
if (!observability?.addFeedback) {
|
|
19510
19795
|
ctx.showError("Observability not configured — cannot save feedback.");
|
|
19511
19796
|
return;
|
|
@@ -21098,7 +21383,7 @@ async function handleWorkflowsCommand(ctx, args, rawArgsText) {
|
|
|
21098
21383
|
help(ctx);
|
|
21099
21384
|
return;
|
|
21100
21385
|
}
|
|
21101
|
-
const mastra = ctx.controller.getMastra();
|
|
21386
|
+
const mastra = requireLocal(ctx.state, "/workflows").controller.getMastra();
|
|
21102
21387
|
if (!mastra) {
|
|
21103
21388
|
ctx.showError("Workflows: no Mastra instance attached to this controller.");
|
|
21104
21389
|
return;
|
|
@@ -21247,8 +21532,8 @@ async function handlePruneCommand(ctx, args = []) {
|
|
|
21247
21532
|
];
|
|
21248
21533
|
const quiesceResults = await Promise.allSettled([
|
|
21249
21534
|
ctx.mcpManager?.disconnect(),
|
|
21250
|
-
ctx.controller.getMastra()?.stopWorkers(),
|
|
21251
|
-
ctx.controller.stopIntervals()
|
|
21535
|
+
requireLocal(ctx.state, "/prune").controller.getMastra()?.stopWorkers(),
|
|
21536
|
+
requireLocal(ctx.state, "/prune").controller.stopIntervals()
|
|
21252
21537
|
]);
|
|
21253
21538
|
for (const [i, result] of quiesceResults.entries()) if (result.status === "rejected") log(`Warning: failed to quiesce a background writer (${quiesceSteps[i]}): ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`);
|
|
21254
21539
|
await (0, _mastra_code_sdk_utils_storage_maintenance.runStorageMaintenance)({
|
|
@@ -21391,9 +21676,12 @@ function canRunSlashCommandDuringGoalJudge(command, args) {
|
|
|
21391
21676
|
/**
|
|
21392
21677
|
* Slash command dispatcher: routes command strings to extracted handlers.
|
|
21393
21678
|
*/
|
|
21679
|
+
/** Commands that need the in-process runtime (local agent, storage, auth, workspace, managers). */
|
|
21394
21680
|
const TRACKED_COMMANDS = /* @__PURE__ */ new Set([
|
|
21395
21681
|
"connect",
|
|
21396
21682
|
"login",
|
|
21683
|
+
"factory",
|
|
21684
|
+
"local",
|
|
21397
21685
|
"model",
|
|
21398
21686
|
"models",
|
|
21399
21687
|
"packs",
|
|
@@ -21459,6 +21747,10 @@ async function dispatchSlashCommand(input, state, buildCtx) {
|
|
|
21459
21747
|
}
|
|
21460
21748
|
const ctx = buildCtx();
|
|
21461
21749
|
trackCommand(ctx, command);
|
|
21750
|
+
if (!state.local && isLocalOnlyCommand(command)) {
|
|
21751
|
+
showInfo(state, `/${command} is not available in Factory mode.`);
|
|
21752
|
+
return true;
|
|
21753
|
+
}
|
|
21462
21754
|
if (command.startsWith("goal/")) {
|
|
21463
21755
|
await handleGoalSourceCommand(state, command.slice(5), args, ctx);
|
|
21464
21756
|
return true;
|
|
@@ -21538,6 +21830,12 @@ async function dispatchSlashCommand(input, state, buildCtx) {
|
|
|
21538
21830
|
case "login":
|
|
21539
21831
|
await handleLoginCommand(ctx, "login");
|
|
21540
21832
|
return true;
|
|
21833
|
+
case "factory":
|
|
21834
|
+
await handleFactoryCommand(ctx, args);
|
|
21835
|
+
return true;
|
|
21836
|
+
case "local":
|
|
21837
|
+
await handleLocalCommand(ctx);
|
|
21838
|
+
return true;
|
|
21541
21839
|
case "logout":
|
|
21542
21840
|
await handleLoginCommand(ctx, "logout");
|
|
21543
21841
|
return true;
|
|
@@ -21653,7 +21951,8 @@ async function handleGoalSourceCommand(state, sourceName, args, ctx) {
|
|
|
21653
21951
|
if (goalSkill) {
|
|
21654
21952
|
try {
|
|
21655
21953
|
let workspace = ctx.getResolvedWorkspace();
|
|
21656
|
-
|
|
21954
|
+
const local = requireLocal(state, "Goal skills");
|
|
21955
|
+
if (!workspace && local.controller.hasWorkspace()) workspace = await local.controller.resolveWorkspace({ session: local.session });
|
|
21657
21956
|
const skill = await workspace?.skills?.get(goalSkill.path || goalSkill.name);
|
|
21658
21957
|
if (!skill || skill.metadata?.goal !== true) {
|
|
21659
21958
|
showError(state, `Unknown goal command: ${sourceName}`);
|
|
@@ -24991,6 +25290,11 @@ function createTUIState(options) {
|
|
|
24991
25290
|
result = {
|
|
24992
25291
|
controller: options.controller,
|
|
24993
25292
|
session: options.session,
|
|
25293
|
+
local: options.runtime === "factory" ? void 0 : {
|
|
25294
|
+
controller: options.controller,
|
|
25295
|
+
session: options.session
|
|
25296
|
+
},
|
|
25297
|
+
factory: options.runtime === "factory" ? options.factory : void 0,
|
|
24994
25298
|
options,
|
|
24995
25299
|
hookManager: options.hookManager,
|
|
24996
25300
|
analytics: options.analytics,
|
|
@@ -25364,7 +25668,7 @@ async function dispatchEvent(event, ectx, state) {
|
|
|
25364
25668
|
state.taskToolInsertIndex = -1;
|
|
25365
25669
|
await ectx.renderExistingMessages(isCurrent);
|
|
25366
25670
|
if (!isCurrent()) break;
|
|
25367
|
-
await state.controller.loadOMProgress(state.session, isCurrent);
|
|
25671
|
+
await state.local?.controller.loadOMProgress(state.local.session, isCurrent);
|
|
25368
25672
|
if (!isCurrent()) break;
|
|
25369
25673
|
(0, _mastra_code_sdk_utils_project.getCurrentGitBranchAsync)(state.projectInfo.rootPath).then((freshBranch) => {
|
|
25370
25674
|
if (freshBranch && isCurrent()) {
|
|
@@ -25381,7 +25685,7 @@ async function dispatchEvent(event, ectx, state) {
|
|
|
25381
25685
|
state.activeGithubPrSubscriptions = getGithubPrSubscriptionsFromMetadata(metadata);
|
|
25382
25686
|
state.githubPrPollingActive = false;
|
|
25383
25687
|
state.githubPrGradientAnimator?.stop();
|
|
25384
|
-
await state.goalManager.loadFromThread(state, isCurrent);
|
|
25688
|
+
if (state.local) await state.goalManager.loadFromThread(state.local, isCurrent);
|
|
25385
25689
|
if (!isCurrent()) break;
|
|
25386
25690
|
if (!state.goalManager.getGoal()) state.goalManager.loadFromThreadMetadata(metadata);
|
|
25387
25691
|
}
|
|
@@ -25397,8 +25701,9 @@ async function dispatchEvent(event, ectx, state) {
|
|
|
25397
25701
|
state.activeGithubPrSubscriptions = getGithubPrSubscriptionsFromMetadata(event.thread.metadata);
|
|
25398
25702
|
state.githubPrPollingActive = false;
|
|
25399
25703
|
state.githubPrGradientAnimator?.stop();
|
|
25400
|
-
if (state.goalManager?.consumePersistOnNextThreadCreate() ?? false)
|
|
25401
|
-
|
|
25704
|
+
if (state.goalManager?.consumePersistOnNextThreadCreate() ?? false) {
|
|
25705
|
+
if (state.local) state.goalManager?.saveToThread(state.local).catch(() => {});
|
|
25706
|
+
} else state.goalManager?.loadFromThreadMetadata(event.thread.metadata);
|
|
25402
25707
|
const tState = state.session.state.get();
|
|
25403
25708
|
if (typeof tState?.escapeAsCancel === "boolean") state.editor.escapeEnabled = tState.escapeAsCancel;
|
|
25404
25709
|
if (!await clearThreadState(state, isCurrent)) break;
|
|
@@ -26253,7 +26558,8 @@ async function pauseStoredGoal(state, pausedReason) {
|
|
|
26253
26558
|
const threadId = state.session.thread.getId();
|
|
26254
26559
|
if (!threadId) return;
|
|
26255
26560
|
try {
|
|
26256
|
-
|
|
26561
|
+
if (!state.local) return;
|
|
26562
|
+
const agent = state.local.controller.getCurrentAgent(state.local.session);
|
|
26257
26563
|
if ((await agent.getObjective({ threadId }))?.status !== "active") return;
|
|
26258
26564
|
await agent.updateObjectiveOptions({
|
|
26259
26565
|
threadId,
|
|
@@ -26273,7 +26579,7 @@ function abortActiveGoalJudge(state) {
|
|
|
26273
26579
|
const pausedReason = "Judge evaluation was interrupted.";
|
|
26274
26580
|
if (state.goalManager.getGoal()) {
|
|
26275
26581
|
state.goalManager.pause(pausedReason);
|
|
26276
|
-
state.goalManager.saveToThread(state);
|
|
26582
|
+
if (state.local) state.goalManager.saveToThread(state.local);
|
|
26277
26583
|
} else pauseStoredGoal(state, pausedReason);
|
|
26278
26584
|
state.activeGoalJudge = void 0;
|
|
26279
26585
|
state.ui.requestRender();
|
|
@@ -26282,7 +26588,12 @@ function abortActiveGoalJudge(state) {
|
|
|
26282
26588
|
function buildLayout(state, refreshModelAuthStatus) {
|
|
26283
26589
|
const appName = state.options.appName || "Mastra Code";
|
|
26284
26590
|
const version = state.options.version || "0.1.0";
|
|
26285
|
-
const info = [
|
|
26591
|
+
const info = state.factory ? [
|
|
26592
|
+
`Factory: ${state.factory.projectName}`,
|
|
26593
|
+
`Repository: ${state.factory.repositorySlug}`,
|
|
26594
|
+
`Branch: ${state.factory.branch}`,
|
|
26595
|
+
`URL: ${state.factory.url}`
|
|
26596
|
+
] : [
|
|
26286
26597
|
`Project: ${state.projectInfo.name}`,
|
|
26287
26598
|
`Resource ID: ${state.projectInfo.resourceId}`,
|
|
26288
26599
|
state.projectInfo.gitBranch ? `Branch: ${state.projectInfo.gitBranch}` : null,
|
|
@@ -26448,6 +26759,14 @@ function setupAutocomplete(state) {
|
|
|
26448
26759
|
name: "login",
|
|
26449
26760
|
description: "Sign in with a provider account"
|
|
26450
26761
|
},
|
|
26762
|
+
{
|
|
26763
|
+
name: "factory",
|
|
26764
|
+
description: "Switch to Factory mode, connecting first if needed (connect|status|local|disconnect)"
|
|
26765
|
+
},
|
|
26766
|
+
{
|
|
26767
|
+
name: "local",
|
|
26768
|
+
description: "Switch from Factory mode back to local mode"
|
|
26769
|
+
},
|
|
26451
26770
|
{
|
|
26452
26771
|
name: "skills",
|
|
26453
26772
|
description: "List available skills"
|
|
@@ -26740,8 +27059,9 @@ function setupAutocomplete(state) {
|
|
|
26740
27059
|
name: `goal/${skill.name}`,
|
|
26741
27060
|
description: skill.description ? `Goal skill: ${skill.description}` : `Goal skill: ${skill.name}`
|
|
26742
27061
|
});
|
|
27062
|
+
const available = state.local ? slashCommands : slashCommands.filter((cmd) => !isLocalOnlyCommand(cmd.name));
|
|
26743
27063
|
const fdPath = detectFdPath();
|
|
26744
|
-
state.autocompleteProvider = new _earendil_works_pi_tui.CombinedAutocompleteProvider(
|
|
27064
|
+
state.autocompleteProvider = new _earendil_works_pi_tui.CombinedAutocompleteProvider(available, process.cwd(), fdPath);
|
|
26745
27065
|
state.editor.setAutocompleteProvider(state.autocompleteProvider);
|
|
26746
27066
|
}
|
|
26747
27067
|
async function loadCustomSlashCommands(state) {
|
|
@@ -26765,8 +27085,9 @@ async function loadCustomSlashCommands(state) {
|
|
|
26765
27085
|
*/
|
|
26766
27086
|
async function loadSkillCommands(state) {
|
|
26767
27087
|
try {
|
|
26768
|
-
|
|
26769
|
-
|
|
27088
|
+
const local = state.local;
|
|
27089
|
+
let workspace = local?.controller.getWorkspace() ?? state.workspace;
|
|
27090
|
+
if (!workspace && local?.controller.hasWorkspace()) workspace = await local.controller.resolveWorkspace({ session: local.session });
|
|
26770
27091
|
if (!workspace?.skills) {
|
|
26771
27092
|
state.skillCommands = [];
|
|
26772
27093
|
state.goalSkillCommands = [];
|
|
@@ -27141,26 +27462,29 @@ var SimpleProgressComponent = class extends _earendil_works_pi_tui.Container {
|
|
|
27141
27462
|
* is returned so the caller can tell the user once the UI is ready.
|
|
27142
27463
|
*/
|
|
27143
27464
|
async function resumeThreadOnStartup(state, requestedThreadId) {
|
|
27465
|
+
const local = state.local;
|
|
27466
|
+
if (!local) return resumeFactoryThread(state);
|
|
27467
|
+
const { session, controller } = local;
|
|
27144
27468
|
const currentPath = state.projectInfo.rootPath;
|
|
27145
|
-
const allThreads = await
|
|
27146
|
-
const activeThreadId =
|
|
27469
|
+
const allThreads = await session.thread.list(requestedThreadId ? { allResources: true } : void 0);
|
|
27470
|
+
const activeThreadId = session.thread.getId();
|
|
27147
27471
|
if (requestedThreadId) {
|
|
27148
27472
|
const thread = allThreads.find((candidate) => candidate.id === requestedThreadId);
|
|
27149
27473
|
if (!thread) {
|
|
27150
|
-
await startPendingNewThread(state);
|
|
27474
|
+
await startPendingNewThread(state, local);
|
|
27151
27475
|
return {
|
|
27152
27476
|
kind: "missing",
|
|
27153
27477
|
threadId: requestedThreadId
|
|
27154
27478
|
};
|
|
27155
27479
|
}
|
|
27156
|
-
const originalResourceId =
|
|
27157
|
-
if (thread.resourceId !== originalResourceId) await
|
|
27480
|
+
const originalResourceId = session.identity.getResourceId();
|
|
27481
|
+
if (thread.resourceId !== originalResourceId) await controller.setResourceId(session, { resourceId: thread.resourceId });
|
|
27158
27482
|
if (requestedThreadId !== activeThreadId) try {
|
|
27159
|
-
await
|
|
27483
|
+
await session.thread.switch({ threadId: requestedThreadId });
|
|
27160
27484
|
} catch (error) {
|
|
27161
27485
|
if (!(error instanceof _mastra_code_sdk_utils_thread_lock.ThreadLockError)) throw error;
|
|
27162
|
-
if (
|
|
27163
|
-
await startPendingNewThread(state);
|
|
27486
|
+
if (session.identity.getResourceId() !== originalResourceId) await controller.setResourceId(session, { resourceId: originalResourceId });
|
|
27487
|
+
await startPendingNewThread(state, local);
|
|
27164
27488
|
return {
|
|
27165
27489
|
kind: "locked",
|
|
27166
27490
|
threadId: thread.id,
|
|
@@ -27173,14 +27497,14 @@ async function resumeThreadOnStartup(state, requestedThreadId) {
|
|
|
27173
27497
|
}
|
|
27174
27498
|
const threads = allThreads.filter((thread) => thread.metadata?.projectPath === currentPath);
|
|
27175
27499
|
if (threads.length === 0) {
|
|
27176
|
-
if (await cloneDriftedThread(state)) return;
|
|
27500
|
+
if (await cloneDriftedThread(state, local)) return;
|
|
27177
27501
|
state.pendingNewThread = true;
|
|
27178
27502
|
return;
|
|
27179
27503
|
}
|
|
27180
27504
|
for (const thread of [...threads].sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())) {
|
|
27181
|
-
if (thread.id ===
|
|
27505
|
+
if (thread.id === session.thread.getId()) return;
|
|
27182
27506
|
try {
|
|
27183
|
-
await
|
|
27507
|
+
await session.thread.switch({ threadId: thread.id });
|
|
27184
27508
|
return;
|
|
27185
27509
|
} catch (error) {
|
|
27186
27510
|
if (error instanceof _mastra_code_sdk_utils_thread_lock.ThreadLockError) continue;
|
|
@@ -27189,20 +27513,27 @@ async function resumeThreadOnStartup(state, requestedThreadId) {
|
|
|
27189
27513
|
}
|
|
27190
27514
|
state.pendingNewThread = true;
|
|
27191
27515
|
}
|
|
27516
|
+
/** Factory sessions own their threads, so local project-path tagging and resource IDs don't apply. */
|
|
27517
|
+
async function resumeFactoryThread(state) {
|
|
27518
|
+
if (state.session.thread.getId()) return;
|
|
27519
|
+
const [latest] = (await state.session.thread.list()).sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
|
|
27520
|
+
if (latest) await state.session.thread.switch({ threadId: latest.id });
|
|
27521
|
+
else state.pendingNewThread = true;
|
|
27522
|
+
}
|
|
27192
27523
|
/**
|
|
27193
27524
|
* Leave the session waiting for a new thread. Session creation may already have
|
|
27194
27525
|
* bound the latest project thread; unbind it (and release its lock) so the UI
|
|
27195
27526
|
* and exit hint don't show a thread the user didn't ask for.
|
|
27196
27527
|
*/
|
|
27197
|
-
async function startPendingNewThread(state) {
|
|
27198
|
-
|
|
27199
|
-
await
|
|
27528
|
+
async function startPendingNewThread(state, { session }) {
|
|
27529
|
+
session.thread.cleanupSubscription();
|
|
27530
|
+
await session.thread.clearAndReleaseLock();
|
|
27200
27531
|
state.pendingNewThread = true;
|
|
27201
27532
|
}
|
|
27202
|
-
async function cloneDriftedThread(state) {
|
|
27533
|
+
async function cloneDriftedThread(state, { session }) {
|
|
27203
27534
|
const currentPath = state.projectInfo.rootPath;
|
|
27204
|
-
const currentResourceId =
|
|
27205
|
-
const thread = [...(await
|
|
27535
|
+
const currentResourceId = session.identity.getResourceId();
|
|
27536
|
+
const thread = [...(await session.thread.list({
|
|
27206
27537
|
allResources: true,
|
|
27207
27538
|
metadata: { projectPath: currentPath }
|
|
27208
27539
|
})).filter((thread) => thread.resourceId !== currentResourceId)].sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())[0];
|
|
@@ -27241,7 +27572,7 @@ async function cloneDriftedThread(state) {
|
|
|
27241
27572
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
27242
27573
|
progress.updateStatus("Loading cloned thread...");
|
|
27243
27574
|
state.ui.requestRender();
|
|
27244
|
-
await
|
|
27575
|
+
await session.thread.cloneToCurrentResource({
|
|
27245
27576
|
threadId: thread.id,
|
|
27246
27577
|
expectedResourceId: thread.resourceId,
|
|
27247
27578
|
expectedProjectPath: currentPath
|
|
@@ -27292,7 +27623,7 @@ async function syncInitialThreadState(state) {
|
|
|
27292
27623
|
setCurrentThreadTitle(state, initThread?.title);
|
|
27293
27624
|
state.fallbackStatus = persistedFallbackStatus;
|
|
27294
27625
|
state.activeGithubPrSubscriptions = getGithubPrSubscriptionsFromMetadata(metadata);
|
|
27295
|
-
await state.goalManager.loadFromThread(state);
|
|
27626
|
+
if (state.local) await state.goalManager.loadFromThread(state.local);
|
|
27296
27627
|
if (state.session.thread.getId() !== initThreadId) return;
|
|
27297
27628
|
if (!state.goalManager.getGoal()) state.goalManager.loadFromThreadMetadata(metadata);
|
|
27298
27629
|
}
|
|
@@ -27434,7 +27765,7 @@ var MastraTUI = class MastraTUI {
|
|
|
27434
27765
|
}
|
|
27435
27766
|
async abortBackgroundActivity(activity) {
|
|
27436
27767
|
try {
|
|
27437
|
-
const manager = this.state.controller.getMastra()?.backgroundTaskManager;
|
|
27768
|
+
const manager = this.state.local?.controller.getMastra()?.backgroundTaskManager;
|
|
27438
27769
|
if (!manager) return;
|
|
27439
27770
|
await manager.cancel(activity.taskId);
|
|
27440
27771
|
} catch (error) {
|
|
@@ -27728,8 +28059,11 @@ var MastraTUI = class MastraTUI {
|
|
|
27728
28059
|
}
|
|
27729
28060
|
async init() {
|
|
27730
28061
|
if (this.state.isInitialized) return;
|
|
27731
|
-
|
|
27732
|
-
|
|
28062
|
+
const local = this.state.local;
|
|
28063
|
+
if (local) {
|
|
28064
|
+
await local.controller.init();
|
|
28065
|
+
await local.controller.getMastra()?.startWorkers();
|
|
28066
|
+
}
|
|
27733
28067
|
if (this.state.pluginManager && !this.cleanupPluginReloadListener) this.cleanupPluginReloadListener = this.state.pluginManager.onReload((plugins) => this.refreshPluginRuntimeState(plugins).catch((err) => {
|
|
27734
28068
|
const msg = err instanceof Error ? err.message : String(err);
|
|
27735
28069
|
process.stderr.write(`[plugin runtime refresh] ${msg}\n`);
|
|
@@ -27771,7 +28105,7 @@ var MastraTUI = class MastraTUI {
|
|
|
27771
28105
|
subscribeToAgentController(this.state, (event) => this.handleEvent(event));
|
|
27772
28106
|
if (this.state.options.backgroundToolsEnabled) this.cleanupBackgroundCompletionListener = this.state.options.backgroundCompletionEvents?.subscribe((event) => this.handleBackgroundCompletion(event));
|
|
27773
28107
|
if (this.state.session.state.get()?.escapeAsCancel === false) this.state.editor.escapeEnabled = false;
|
|
27774
|
-
await this.state.controller.loadOMProgress(this.state.session);
|
|
28108
|
+
await this.state.local?.controller.loadOMProgress(this.state.local.session);
|
|
27775
28109
|
await syncInitialThreadState(this.state);
|
|
27776
28110
|
this.state.isInitialized = true;
|
|
27777
28111
|
if (this.state.mcpManager?.hasServers()) this.state.mcpManager.initInBackground().then((result) => {
|
|
@@ -27925,12 +28259,13 @@ var MastraTUI = class MastraTUI {
|
|
|
27925
28259
|
});
|
|
27926
28260
|
}
|
|
27927
28261
|
emitErrorFeedback(errorMessage) {
|
|
27928
|
-
const
|
|
28262
|
+
const local = this.state.local;
|
|
28263
|
+
if (!local) return;
|
|
27929
28264
|
const traceId = this.state.session.run.getTraceId() ?? void 0;
|
|
27930
28265
|
const runId = this.state.session.getCurrentRunId() ?? void 0;
|
|
27931
28266
|
const threadId = this.state.session.thread.getId() ?? void 0;
|
|
27932
28267
|
if (!traceId && !runId && !threadId) return;
|
|
27933
|
-
const observability = controller.getMastra()?.observability;
|
|
28268
|
+
const observability = local.controller.getMastra()?.observability;
|
|
27934
28269
|
if (!observability?.addFeedback) return;
|
|
27935
28270
|
const comment = errorMessage.length > 500 ? errorMessage.slice(0, 500) + "…" : errorMessage;
|
|
27936
28271
|
observability.addFeedback({
|
|
@@ -28161,7 +28496,7 @@ var MastraTUI = class MastraTUI {
|
|
|
28161
28496
|
* Get the workspace, preferring controller-owned workspace over the direct option.
|
|
28162
28497
|
*/
|
|
28163
28498
|
getResolvedWorkspace() {
|
|
28164
|
-
return this.state.controller.getWorkspace() ?? this.state.workspace;
|
|
28499
|
+
return this.state.local?.controller.getWorkspace() ?? this.state.workspace;
|
|
28165
28500
|
}
|
|
28166
28501
|
buildCommandContext() {
|
|
28167
28502
|
return {
|
|
@@ -28604,4 +28939,4 @@ Object.defineProperty(exports, "theme", {
|
|
|
28604
28939
|
}
|
|
28605
28940
|
});
|
|
28606
28941
|
|
|
28607
|
-
//# sourceMappingURL=tui-
|
|
28942
|
+
//# sourceMappingURL=tui-BpzUjTFI.cjs.map
|