mixdog 0.9.84 → 0.9.86
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/README.md +7 -1
- package/package.json +3 -2
- package/scripts/channel-daemon-stub.mjs +2 -1
- package/src/defaults/agents.json +12 -0
- package/src/defaults/skills/setup/SKILL.md +44 -12
- package/src/help.mjs +40 -9
- package/src/lib/keychain-cjs.cjs +11 -1
- package/src/rules/agent/43-title-agent.md +22 -0
- package/src/rules/shared/01-tool.md +3 -3
- package/src/runtime/agent/orchestrator/mcp/client.mjs +24 -0
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +84 -3
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +30 -3
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +73 -45
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +15 -18
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +38 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +183 -41
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +31 -12
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +170 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +45 -6
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +26 -0
- package/src/runtime/agent/orchestrator/session/token-bpe.mjs +42 -0
- package/src/runtime/agent/orchestrator/session/token-native.mjs +186 -0
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +15 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +20 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +24 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +44 -73
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/lib/pwsh-standby-pool.mjs +286 -0
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +152 -18
- package/src/runtime/agent/orchestrator/tools/token-binary-fetcher.mjs +201 -0
- package/src/runtime/agent/orchestrator/tools/token-manifest.json +5 -0
- package/src/runtime/channels/lib/owned-runtime.mjs +6 -8
- package/src/runtime/channels/lib/parent-bridge.mjs +27 -15
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +3 -3
- package/src/runtime/channels/lib/worker-ipc.mjs +17 -4
- package/src/runtime/media/adapters/gemini-video.mjs +1 -1
- package/src/runtime/media/renditions.mjs +1 -1
- package/src/runtime/media/store.mjs +1 -1
- package/src/runtime/memory/index.mjs +14 -5
- package/src/runtime/memory/lib/agent-ipc.mjs +11 -12
- package/src/runtime/shared/atomic-file.mjs +76 -38
- package/src/runtime/shared/automation-attachments.mjs +3 -3
- package/src/runtime/shared/child-guardian.mjs +15 -5
- package/src/runtime/shared/child-spawn-gate.mjs +6 -12
- package/src/runtime/shared/err-text.mjs +1 -0
- package/src/runtime/shared/resource-admission.mjs +7 -3
- package/src/runtime/shared/safe-ipc-send.mjs +34 -0
- package/src/runtime/shared/turn-snapshot.mjs +0 -3
- package/src/session-runtime/lifecycle-api.mjs +43 -12
- package/src/session-runtime/prewarm.mjs +35 -0
- package/src/session-runtime/remote-control.mjs +8 -47
- package/src/session-runtime/remote-transcript.mjs +3 -7
- package/src/session-runtime/route-preparation.mjs +24 -0
- package/src/session-runtime/runtime-core.mjs +42 -86
- package/src/session-runtime/session-turn-api.mjs +9 -2
- package/src/session-runtime/workflow-agents-api.mjs +3 -0
- package/src/standalone/agent-shard/shard-child.mjs +300 -0
- package/src/standalone/agent-shard/shard-pool.mjs +442 -0
- package/src/standalone/agent-tool.mjs +222 -0
- package/src/standalone/channel-daemon-transport.mjs +126 -185
- package/src/standalone/channel-daemon.mjs +11 -11
- package/src/standalone/channel-worker.mjs +21 -19
- package/src/standalone/memory-runtime-proxy.mjs +98 -23
- package/src/tui/App.jsx +16 -9
- package/src/tui/app/channel-pickers.mjs +3 -8
- package/src/tui/app/route-pickers.mjs +117 -152
- package/src/tui/app/settings-picker.mjs +90 -89
- package/src/tui/app/slash-commands.mjs +7 -7
- package/src/tui/app/slash-dispatch.mjs +23 -58
- package/src/tui/app/theme-effort-pickers.mjs +3 -1
- package/src/tui/components/StatusLine.jsx +1 -1
- package/src/tui/components/tool-execution/ResultBody.jsx +1 -1
- package/src/tui/dist/index.mjs +358 -380
- package/src/tui/engine/live-share.mjs +2 -2
- package/src/tui/engine/session-api-ext.mjs +24 -9
- package/src/tui/engine/session-flow.mjs +20 -10
- package/src/tui/engine/turn.mjs +28 -16
- package/src/tui/engine.mjs +24 -2
- package/src/tui/figures.mjs +0 -1
- package/src/ui/statusline-format.mjs +0 -1
- package/src/hooks/lib/permission-evaluator.cjs +0 -24
- package/src/lib/config-cjs.cjs +0 -61
- package/src/runtime/shared/launcher-control.mjs +0 -258
- package/src/runtime/shared/workspace-router.mjs +0 -259
|
@@ -30,8 +30,6 @@ export function createSettingsPicker({
|
|
|
30
30
|
openAgentsPicker,
|
|
31
31
|
openWorkflowPicker,
|
|
32
32
|
openOutputStylePicker,
|
|
33
|
-
openBridgePicker,
|
|
34
|
-
openToolsPicker,
|
|
35
33
|
openProviderSetupPicker,
|
|
36
34
|
openThemePicker,
|
|
37
35
|
openAutoClearPicker,
|
|
@@ -40,6 +38,7 @@ export function createSettingsPicker({
|
|
|
40
38
|
openPluginsPicker,
|
|
41
39
|
openHooksPicker,
|
|
42
40
|
openSkillsPicker,
|
|
41
|
+
openMemoryCorePicker,
|
|
43
42
|
openUpdatePicker,
|
|
44
43
|
openChannelSettingTypePicker,
|
|
45
44
|
}) {
|
|
@@ -81,8 +80,7 @@ export function createSettingsPicker({
|
|
|
81
80
|
const remoteEnabled = store.isRemoteEnabled?.() === true;
|
|
82
81
|
const remoteRuntimeDescription = channelWorker?.running
|
|
83
82
|
? `runtime running · pid ${channelWorker.pid}`
|
|
84
|
-
: '
|
|
85
|
-
const compactType = compaction.compactType || compaction.type || 'semantic';
|
|
83
|
+
: 'Stopped. Manual ON claims remote from any other session.';
|
|
86
84
|
const compactTypeLabel = 'Fast-track (fixed)';
|
|
87
85
|
const outputStyleLabel = outputStyle?.current?.label || outputStyle?.current?.id || outputStyle?.configured || 'Default';
|
|
88
86
|
const workflowLabel = workflowDisplayName(workflow);
|
|
@@ -223,7 +221,38 @@ export function createSettingsPicker({
|
|
|
223
221
|
}
|
|
224
222
|
openSettingsPicker({ light: true, overrides: { channelBackend: chosen } });
|
|
225
223
|
};
|
|
224
|
+
// Row order groups by concern — routing/model first, then session
|
|
225
|
+
// behavior, integrations, channels/remote, system — and must stay in
|
|
226
|
+
// sync with desktop SETTINGS_ITEMS (tui-parity test, minus system-shell).
|
|
226
227
|
const items = [
|
|
228
|
+
{
|
|
229
|
+
value: 'model',
|
|
230
|
+
label: 'Model',
|
|
231
|
+
meta: displayModelName(state.model, state.provider),
|
|
232
|
+
description: 'Main chat model.',
|
|
233
|
+
_action: 'model',
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
value: 'search',
|
|
237
|
+
label: 'Search model',
|
|
238
|
+
meta: routeModelLabel(store.getSearchRoute?.()),
|
|
239
|
+
description: 'Native search model.',
|
|
240
|
+
_action: 'search',
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
value: 'workflow',
|
|
244
|
+
label: 'Workflow',
|
|
245
|
+
meta: workflowLabel,
|
|
246
|
+
description: 'Active agent routing profile.',
|
|
247
|
+
_action: 'workflow',
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
value: 'output-style',
|
|
251
|
+
label: 'Output style',
|
|
252
|
+
meta: outputStyleLabel,
|
|
253
|
+
description: 'Response tone and format.',
|
|
254
|
+
_action: 'output-style',
|
|
255
|
+
},
|
|
227
256
|
{
|
|
228
257
|
value: 'profile',
|
|
229
258
|
label: 'Profile',
|
|
@@ -238,13 +267,17 @@ export function createSettingsPicker({
|
|
|
238
267
|
_action: 'profile',
|
|
239
268
|
},
|
|
240
269
|
{
|
|
241
|
-
value: '
|
|
242
|
-
label: '
|
|
243
|
-
meta:
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
270
|
+
value: 'theme',
|
|
271
|
+
label: 'Theme',
|
|
272
|
+
meta: (() => {
|
|
273
|
+
try {
|
|
274
|
+
const id = store.getTheme?.();
|
|
275
|
+
const entry = (store.listThemes?.() || []).find((t) => t.id === id);
|
|
276
|
+
return entry?.label || id || 'Default';
|
|
277
|
+
} catch { return 'Default'; }
|
|
278
|
+
})(),
|
|
279
|
+
description: 'TUI color theme.',
|
|
280
|
+
_action: 'theme',
|
|
248
281
|
},
|
|
249
282
|
{
|
|
250
283
|
value: 'autocompact',
|
|
@@ -261,74 +294,22 @@ export function createSettingsPicker({
|
|
|
261
294
|
_action: null,
|
|
262
295
|
},
|
|
263
296
|
{
|
|
264
|
-
value: '
|
|
265
|
-
label: '
|
|
266
|
-
meta:
|
|
267
|
-
description:
|
|
268
|
-
? '
|
|
269
|
-
: '
|
|
270
|
-
_action: '
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
value: 'remote-runtime',
|
|
274
|
-
label: 'Remote Runtime',
|
|
275
|
-
meta: boolLabel(remoteEnabled),
|
|
276
|
-
description: remoteRuntimeDescription,
|
|
277
|
-
_action: 'remote-runtime',
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
value: 'channel-backend',
|
|
281
|
-
label: 'Channel',
|
|
282
|
-
meta: channelBackendLabel,
|
|
283
|
-
description: 'Left/Right or Enter changes channel type (Discord or Telegram).',
|
|
284
|
-
_action: 'channel-backend',
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
value: 'channel-setting',
|
|
288
|
-
label: 'Setting',
|
|
289
|
-
description: 'Configure credentials and main channel/chat for the active type.',
|
|
290
|
-
_action: 'channel-setting',
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
value: 'output-style',
|
|
294
|
-
label: 'Output style',
|
|
295
|
-
meta: outputStyleLabel,
|
|
296
|
-
description: 'Response tone and format.',
|
|
297
|
-
_action: 'output-style',
|
|
298
|
-
},
|
|
299
|
-
{
|
|
300
|
-
value: 'theme',
|
|
301
|
-
label: 'Theme',
|
|
302
|
-
meta: (() => {
|
|
303
|
-
try {
|
|
304
|
-
const id = store.getTheme?.();
|
|
305
|
-
const entry = (store.listThemes?.() || []).find((t) => t.id === id);
|
|
306
|
-
return entry?.label || id || 'Default';
|
|
307
|
-
} catch { return 'Default'; }
|
|
308
|
-
})(),
|
|
309
|
-
description: 'TUI color theme.',
|
|
310
|
-
_action: 'theme',
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
value: 'workflow',
|
|
314
|
-
label: 'Workflow',
|
|
315
|
-
meta: workflowLabel,
|
|
316
|
-
description: 'Active agent routing profile.',
|
|
317
|
-
_action: 'workflow',
|
|
318
|
-
},
|
|
319
|
-
{
|
|
320
|
-
value: 'model',
|
|
321
|
-
label: 'Model',
|
|
322
|
-
meta: displayModelName(state.model, state.provider),
|
|
323
|
-
description: 'Main chat model.',
|
|
324
|
-
_action: 'model',
|
|
297
|
+
value: 'autoclear',
|
|
298
|
+
label: 'Auto-clear',
|
|
299
|
+
meta: autoClearEnabled ? `On (${formatDuration(autoClear.idleMs)})` : 'Off',
|
|
300
|
+
description: autoClearEnabled
|
|
301
|
+
? `Clear idle sessions after ${formatDuration(autoClear.idleMs)}${autoClear.custom ? '' : ` (${autoClear.provider || 'default'} default)`}. Enter for options.`
|
|
302
|
+
: 'Idle auto-clear disabled. Enter for options.',
|
|
303
|
+
_action: 'autoclear',
|
|
325
304
|
},
|
|
326
305
|
{
|
|
327
|
-
value: '
|
|
328
|
-
label: '
|
|
329
|
-
meta:
|
|
330
|
-
description:
|
|
331
|
-
|
|
306
|
+
value: 'memory',
|
|
307
|
+
label: 'Memory',
|
|
308
|
+
meta: boolLabel(memory.enabled !== false),
|
|
309
|
+
description: memory.enabled === false
|
|
310
|
+
? 'Memory off. Core memories stay editable.'
|
|
311
|
+
: 'Session memory and core memories.',
|
|
312
|
+
_action: 'memory',
|
|
332
313
|
},
|
|
333
314
|
{
|
|
334
315
|
value: 'providers',
|
|
@@ -360,6 +341,37 @@ export function createSettingsPicker({
|
|
|
360
341
|
description: `${skills.count || 0} available`,
|
|
361
342
|
_action: 'skills',
|
|
362
343
|
},
|
|
344
|
+
{
|
|
345
|
+
value: 'channels',
|
|
346
|
+
label: 'Channels enabled',
|
|
347
|
+
meta: boolLabel(channels.enabled !== false),
|
|
348
|
+
// Messaging-only toggle: schedules/webhooks run through the automation
|
|
349
|
+
// runtime and no longer depend on this switch (desktop parity).
|
|
350
|
+
description: channels.enabled === false
|
|
351
|
+
? 'Messaging disabled. Schedules and webhooks keep running.'
|
|
352
|
+
: 'Discord and Telegram messaging.',
|
|
353
|
+
_action: 'channels',
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
value: 'channel-backend',
|
|
357
|
+
label: 'Channel',
|
|
358
|
+
meta: channelBackendLabel,
|
|
359
|
+
description: 'Left/Right or Enter changes channel type (Discord or Telegram).',
|
|
360
|
+
_action: 'channel-backend',
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
value: 'channel-setting',
|
|
364
|
+
label: 'Setting',
|
|
365
|
+
description: 'Configure credentials and main channel/chat for the active type.',
|
|
366
|
+
_action: 'channel-setting',
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
value: 'remote-runtime',
|
|
370
|
+
label: 'Remote Runtime',
|
|
371
|
+
meta: boolLabel(remoteEnabled),
|
|
372
|
+
description: remoteRuntimeDescription,
|
|
373
|
+
_action: 'remote-runtime',
|
|
374
|
+
},
|
|
363
375
|
{
|
|
364
376
|
value: 'system-shell',
|
|
365
377
|
label: 'System shell',
|
|
@@ -401,10 +413,6 @@ export function createSettingsPicker({
|
|
|
401
413
|
onLeft: (item) => {
|
|
402
414
|
if (item?._action === 'autoclear') toggleAutoClear();
|
|
403
415
|
else if (item?._action === 'autocompact') applyCompaction({ auto: !(compaction.auto !== false) });
|
|
404
|
-
else if (item?._action === 'compact-type') {
|
|
405
|
-
const nextType = compactType === 'recall-fasttrack' ? 'semantic' : 'recall-fasttrack';
|
|
406
|
-
applyCompaction({ compactType: nextType });
|
|
407
|
-
}
|
|
408
416
|
else if (item?._action === 'channels') applyChannels(!(channels.enabled !== false));
|
|
409
417
|
else if (item?._action === 'remote-runtime') applyRemoteRuntime();
|
|
410
418
|
else if (item?._action === 'channel-backend') cycleChannelBackend(-1);
|
|
@@ -415,10 +423,6 @@ export function createSettingsPicker({
|
|
|
415
423
|
onRight: (item) => {
|
|
416
424
|
if (item?._action === 'autoclear') toggleAutoClear();
|
|
417
425
|
else if (item?._action === 'autocompact') applyCompaction({ auto: !(compaction.auto !== false) });
|
|
418
|
-
else if (item?._action === 'compact-type') {
|
|
419
|
-
const nextType = compactType === 'recall-fasttrack' ? 'semantic' : 'recall-fasttrack';
|
|
420
|
-
applyCompaction({ compactType: nextType });
|
|
421
|
-
}
|
|
422
426
|
else if (item?._action === 'channels') applyChannels(!(channels.enabled !== false));
|
|
423
427
|
else if (item?._action === 'remote-runtime') applyRemoteRuntime();
|
|
424
428
|
else if (item?._action === 'channel-backend') cycleChannelBackend(1);
|
|
@@ -430,10 +434,6 @@ export function createSettingsPicker({
|
|
|
430
434
|
if (item._action === 'autoclear') openAutoClearPicker({ returnTo: openSettingsPicker });
|
|
431
435
|
else if (item._action === 'profile') openProfilePicker({ returnTo: openSettingsPicker });
|
|
432
436
|
else if (item._action === 'autocompact') applyCompaction({ auto: !(compaction.auto !== false) });
|
|
433
|
-
else if (item._action === 'compact-type') {
|
|
434
|
-
const nextType = compactType === 'recall-fasttrack' ? 'semantic' : 'recall-fasttrack';
|
|
435
|
-
applyCompaction({ compactType: nextType });
|
|
436
|
-
}
|
|
437
437
|
else if (item._action === 'channels') applyChannels(!(channels.enabled !== false));
|
|
438
438
|
else if (item._action === 'remote-runtime') applyRemoteRuntime();
|
|
439
439
|
else if (item._action === 'channel-backend') cycleChannelBackend(1);
|
|
@@ -462,6 +462,7 @@ export function createSettingsPicker({
|
|
|
462
462
|
else if (item._action === 'plugins') openPluginsPicker();
|
|
463
463
|
else if (item._action === 'hooks') openHooksPicker();
|
|
464
464
|
else if (item._action === 'skills') openSkillsPicker();
|
|
465
|
+
else if (item._action === 'memory') openMemoryCorePicker({ returnTo: openSettingsPicker });
|
|
465
466
|
else if (item._action === 'system-shell') {
|
|
466
467
|
setPicker(null);
|
|
467
468
|
setSettingsPrompt({
|
|
@@ -5,23 +5,23 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export const SLASH_COMMANDS = [
|
|
7
7
|
{ name: 'clear', usage: '/clear', aliases: ['new'], aliasUsage: ['new'], description: 'Start a fresh chat' },
|
|
8
|
-
{ name: 'project', usage: '/project', aliases: ['projects'], aliasUsage: ['projects'], showAliasUsage: false, description: 'Switch working directory (project)' },
|
|
8
|
+
{ name: 'project', usage: '/project', aliases: ['projects'], aliasUsage: ['projects'], showAliasUsage: false, params: '[path]', description: 'Switch working directory (project)' },
|
|
9
9
|
{ name: 'compact', usage: '/compact', description: 'Compact older conversation context' },
|
|
10
|
-
{ name: 'autoclear', usage: '/autoclear', description: 'Reduce cache-miss cost after long idle gaps' },
|
|
11
|
-
{ name: 'resume', usage: '/resume', description: 'Resume a saved chat' },
|
|
10
|
+
{ name: 'autoclear', usage: '/autoclear', params: '[on|off|duration]', description: 'Reduce cache-miss cost after long idle gaps' },
|
|
11
|
+
{ name: 'resume', usage: '/resume', params: '[id]', description: 'Resume a saved chat' },
|
|
12
12
|
{ name: 'context', usage: '/context', description: 'Show current context surface' },
|
|
13
13
|
{ name: 'usage', usage: '/usage', params: '[refresh]', description: 'Show total provider quota / balance' },
|
|
14
|
-
{ name: 'model', usage: '/model', description: 'Switch model for subsequent turns' },
|
|
14
|
+
{ name: 'model', usage: '/model', params: '[name|refresh]', description: 'Switch model for subsequent turns' },
|
|
15
15
|
{ name: 'search', usage: '/search', description: 'Set the web search provider/model' },
|
|
16
|
-
{ name: 'workflow', usage: '/workflow', description: 'Switch the active workflow' },
|
|
16
|
+
{ name: 'workflow', usage: '/workflow', params: '[name]', description: 'Switch the active workflow' },
|
|
17
17
|
{ name: 'outputstyle', usage: '/OutputStyle', aliases: ['output-style', 'style'], aliasUsage: ['style'], showAliasUsage: false, params: '[name]', description: 'Switch Lead output style' },
|
|
18
18
|
{ name: 'theme', usage: '/theme', params: '[id]', description: 'Change the TUI color theme' },
|
|
19
|
-
{ name: 'agents', usage: '/agents', description: 'Show available workflow agents' },
|
|
19
|
+
{ name: 'agents', usage: '/agents', params: '[refresh]', description: 'Show available workflow agents' },
|
|
20
20
|
{ name: 'effort', usage: '/effort', params: '[level]', description: 'Set reasoning effort for the current model' },
|
|
21
21
|
{ name: 'fast', usage: '/fast', params: '[on|off]', description: 'Toggle Fast mode for the current model' },
|
|
22
22
|
{ name: 'mcp', usage: '/mcp', description: 'Manage MCP servers and tools' },
|
|
23
23
|
{ name: 'skills', usage: '/skills', description: 'Choose a skill for the next request' },
|
|
24
|
-
{ name: 'memory', usage: '/memory', description: 'List and edit core memories' },
|
|
24
|
+
{ name: 'memory', usage: '/memory', params: '[status|core ...]', description: 'List and edit core memories' },
|
|
25
25
|
{ name: 'plugins', usage: '/plugins', description: 'Manage local plugin integrations' },
|
|
26
26
|
{ name: 'hooks', usage: '/hooks', description: 'Manage before-tool hook rules and events' },
|
|
27
27
|
{ name: 'providers', usage: '/providers', description: 'Manage auth, API keys, OAuth, and local endpoints' },
|
|
@@ -9,6 +9,15 @@
|
|
|
9
9
|
* defined later in the App factory zone are passed as lazy getters so their
|
|
10
10
|
* live binding is used at call time.
|
|
11
11
|
*/
|
|
12
|
+
import { presentErrorText } from '../../runtime/shared/err-text.mjs';
|
|
13
|
+
|
|
14
|
+
export function compactFailureNotice(error) {
|
|
15
|
+
if (error == null || String(error).trim() === '') return 'Compact failed.';
|
|
16
|
+
const reason = presentErrorText(error, { surface: 'compact', max: 320 });
|
|
17
|
+
if (!reason || reason === 'Unknown error') return 'Compact failed.';
|
|
18
|
+
return /^compact(?:ion)? failed\b/i.test(reason) ? reason : `Compact failed: ${reason}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
12
21
|
export function createSlashDispatch({
|
|
13
22
|
state,
|
|
14
23
|
store,
|
|
@@ -26,10 +35,8 @@ export function createSlashDispatch({
|
|
|
26
35
|
openThemePicker,
|
|
27
36
|
themeNotice,
|
|
28
37
|
openEffortPicker,
|
|
29
|
-
projectNameFromPath,
|
|
30
38
|
enterProject,
|
|
31
39
|
openProjectPicker,
|
|
32
|
-
openToolsPicker,
|
|
33
40
|
openMcpPicker,
|
|
34
41
|
openSkillsPicker,
|
|
35
42
|
openPluginsPicker,
|
|
@@ -179,24 +186,21 @@ export function createSlashDispatch({
|
|
|
179
186
|
}
|
|
180
187
|
return true;
|
|
181
188
|
}
|
|
182
|
-
case 'effort':
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
189
|
+
case 'effort': {
|
|
190
|
+
// A running turn no longer blocks the switch: the in-flight turn keeps
|
|
191
|
+
// the effort it started with, and the new level applies from the next
|
|
192
|
+
// turn. Same for /fast below.
|
|
193
|
+
const pendingTurn = state.busy ? ' (applies from the next turn)' : '';
|
|
187
194
|
if (!arg) {
|
|
188
195
|
openEffortPicker();
|
|
189
196
|
return true;
|
|
190
197
|
}
|
|
191
198
|
void store.setEffort(arg)
|
|
192
|
-
.then(result => store.pushNotice(result ? `Effort set to ${result}` : 'Effort switch is already running.', result ? 'info' : 'warn'))
|
|
199
|
+
.then(result => store.pushNotice(result ? `Effort set to ${result}${pendingTurn}` : 'Effort switch is already running.', result ? 'info' : 'warn'))
|
|
193
200
|
.catch((e) => store.pushNotice(`Couldn’t switch effort: ${e?.message || e}`, 'error'));
|
|
194
201
|
return true;
|
|
202
|
+
}
|
|
195
203
|
case 'fast': {
|
|
196
|
-
if (state.busy) {
|
|
197
|
-
store.pushNotice('wait for the current turn to finish before /fast', 'warn');
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
204
|
const value = String(arg || '').trim().toLowerCase();
|
|
201
205
|
const setTo = value
|
|
202
206
|
? ['1', 'true', 'yes', 'on', 'enable', 'enabled'].includes(value)
|
|
@@ -216,24 +220,15 @@ export function createSlashDispatch({
|
|
|
216
220
|
store.pushNotice('Fast mode switch is already running.', 'warn');
|
|
217
221
|
return;
|
|
218
222
|
}
|
|
219
|
-
store.pushNotice(
|
|
223
|
+
store.pushNotice(
|
|
224
|
+
`Fast mode ${enabled ? 'on' : 'off'} for ${state.provider}/${state.model}`
|
|
225
|
+
+ (state.busy ? ' (applies from the next turn)' : ''),
|
|
226
|
+
'info',
|
|
227
|
+
);
|
|
220
228
|
})
|
|
221
229
|
.catch((e) => store.pushNotice(`Couldn’t update fast mode: ${e?.message || e}`, 'error'));
|
|
222
230
|
return true;
|
|
223
231
|
}
|
|
224
|
-
case 'cwd': {
|
|
225
|
-
const nextPath = arg.trim();
|
|
226
|
-
if (!nextPath) {
|
|
227
|
-
store.pushNotice(`Project path: ${state.cwd}`, 'info');
|
|
228
|
-
return true;
|
|
229
|
-
}
|
|
230
|
-
try {
|
|
231
|
-
store.setCwd?.(nextPath, { message: `Project set: ${projectNameFromPath(nextPath)}` });
|
|
232
|
-
} catch (e) {
|
|
233
|
-
store.pushNotice(`project switch failed: ${e?.message || e}`, 'error');
|
|
234
|
-
}
|
|
235
|
-
return true;
|
|
236
|
-
}
|
|
237
232
|
case 'project': {
|
|
238
233
|
const target = arg.trim();
|
|
239
234
|
if (target) {
|
|
@@ -243,9 +238,6 @@ export function createSlashDispatch({
|
|
|
243
238
|
openProjectPicker();
|
|
244
239
|
return true;
|
|
245
240
|
}
|
|
246
|
-
case 'tools':
|
|
247
|
-
openToolsPicker(arg.trim());
|
|
248
|
-
return true;
|
|
249
241
|
case 'mcp':
|
|
250
242
|
openMcpPicker();
|
|
251
243
|
return true;
|
|
@@ -270,23 +262,6 @@ export function createSlashDispatch({
|
|
|
270
262
|
// palette, and a typed command answers instead of opening a picker.
|
|
271
263
|
store.pushNotice('Schedules and webhooks are managed in the Mixdog desktop app', 'info');
|
|
272
264
|
return true;
|
|
273
|
-
case 'auth':
|
|
274
|
-
store.pushNotice('/auth moved to /providers', 'info');
|
|
275
|
-
void openProviderSetupPicker();
|
|
276
|
-
return true;
|
|
277
|
-
case 'auth-forget': {
|
|
278
|
-
const providerId = arg.trim();
|
|
279
|
-
if (!providerId) {
|
|
280
|
-
store.pushNotice('usage: /auth-forget <provider>', 'warn');
|
|
281
|
-
return true;
|
|
282
|
-
}
|
|
283
|
-
try {
|
|
284
|
-
store.forgetProviderAuth(providerId);
|
|
285
|
-
} catch (e) {
|
|
286
|
-
store.pushNotice(`auth-forget failed: ${e?.message || e}`, 'error');
|
|
287
|
-
}
|
|
288
|
-
return true;
|
|
289
|
-
}
|
|
290
265
|
case 'memory': {
|
|
291
266
|
if (!arg.trim()) {
|
|
292
267
|
openMemoryCorePicker({ returnTo: null });
|
|
@@ -296,16 +271,6 @@ export function createSlashDispatch({
|
|
|
296
271
|
.catch((e) => store.pushNotice(`memory failed: ${e?.message || e}`, 'error'));
|
|
297
272
|
return true;
|
|
298
273
|
}
|
|
299
|
-
case 'recall': {
|
|
300
|
-
const query = arg.trim();
|
|
301
|
-
if (!query) {
|
|
302
|
-
store.pushNotice('usage: /recall <query>', 'warn');
|
|
303
|
-
return true;
|
|
304
|
-
}
|
|
305
|
-
void store.recall?.(query)
|
|
306
|
-
.catch((e) => store.pushNotice(`recall failed: ${e?.message || e}`, 'error'));
|
|
307
|
-
return true;
|
|
308
|
-
}
|
|
309
274
|
case 'autoclear': {
|
|
310
275
|
const value = arg.trim().toLowerCase();
|
|
311
276
|
if (!value) {
|
|
@@ -345,7 +310,7 @@ export function createSlashDispatch({
|
|
|
345
310
|
return;
|
|
346
311
|
}
|
|
347
312
|
if (r.error) {
|
|
348
|
-
store.pushNotice(
|
|
313
|
+
store.pushNotice(compactFailureNotice(r.error), 'error');
|
|
349
314
|
return;
|
|
350
315
|
}
|
|
351
316
|
if (r.changed === false && r.reason) {
|
|
@@ -358,7 +323,7 @@ export function createSlashDispatch({
|
|
|
358
323
|
}
|
|
359
324
|
store.pushNotice('Compact done.', 'info');
|
|
360
325
|
})
|
|
361
|
-
.catch(() => store.pushNotice(
|
|
326
|
+
.catch((error) => store.pushNotice(compactFailureNotice(error), 'error'));
|
|
362
327
|
return true;
|
|
363
328
|
case 'resume':
|
|
364
329
|
if (state.busy) {
|
|
@@ -140,8 +140,10 @@ export function createThemeEffortPickers({
|
|
|
140
140
|
items: pickerItems,
|
|
141
141
|
onSelect: (value) => {
|
|
142
142
|
setPicker(null);
|
|
143
|
+
// Mid-turn picks are allowed; the running turn keeps its own effort.
|
|
144
|
+
const pendingTurn = state.busy ? ' (applies from the next turn)' : '';
|
|
143
145
|
void store.setEffort(value)
|
|
144
|
-
.then(result => store.pushNotice(result ? `Effort set to ${result}` : 'Effort switch is already running.', result ? 'info' : 'warn'))
|
|
146
|
+
.then(result => store.pushNotice(result ? `Effort set to ${result}${pendingTurn}` : 'Effort switch is already running.', result ? 'info' : 'warn'))
|
|
145
147
|
.catch((e) => store.pushNotice(`Couldn’t switch effort: ${e?.message || e}`, 'error'));
|
|
146
148
|
},
|
|
147
149
|
onCancel: () => {
|
|
@@ -405,7 +405,7 @@ function localBootStatusLine(args = {}) {
|
|
|
405
405
|
return l2 ? `${l1}\n${l2}` : l1;
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
-
|
|
408
|
+
function normalizeStatusLine(text) {
|
|
409
409
|
return normalizeStatuslineAnsi(text, statusColors(), { reset: RESET });
|
|
410
410
|
}
|
|
411
411
|
|
|
@@ -9,7 +9,7 @@ import { theme, RESULT_GUTTER, RESULT_GUTTER_CONT } from '../../theme.mjs';
|
|
|
9
9
|
import { formatExpandedResult, wrapExpandedResultLines } from '../tool-output-format.mjs';
|
|
10
10
|
import { deltaTextParts, fitResultLine } from './text-format.mjs';
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
function renderDeltaText(text) {
|
|
13
13
|
return deltaTextParts(text).map((part, index) => (
|
|
14
14
|
part.color ? <Text key={index} color={part.color}>{part.text}</Text> : part.text
|
|
15
15
|
));
|