mixdog 0.9.85 → 0.9.87
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 +4 -3
- 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/agent-trace-format.mjs +4 -2
- 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/oauth-usage.mjs +125 -16
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -2
- 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/tool-helpers.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +135 -9
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +31 -12
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +4 -0
- 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/manager.mjs +3 -0
- 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 +9 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +24 -0
- package/src/runtime/agent/orchestrator/tools/env-scrub.mjs +8 -0
- 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/patch-tool-defs.mjs +4 -3
- 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 +26 -0
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +3 -3
- 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/lib/memory-action-handlers.mjs +4 -1
- package/src/runtime/memory/tool-defs.mjs +19 -3
- package/src/runtime/shared/atomic-file.mjs +25 -14
- 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/resource-admission.mjs +7 -3
- package/src/runtime/shared/turn-snapshot.mjs +0 -3
- package/src/session-runtime/lifecycle-api.mjs +49 -9
- package/src/session-runtime/prewarm.mjs +35 -0
- package/src/session-runtime/provider-auth-api.mjs +8 -0
- package/src/session-runtime/provider-usage.mjs +30 -5
- 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 +286 -548
- package/src/session-runtime/session-lifecycle.mjs +378 -0
- 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 +443 -0
- package/src/standalone/agent-tool/job-views.mjs +329 -0
- package/src/standalone/agent-tool/spawn-flow.mjs +629 -0
- package/src/standalone/agent-tool/tag-registry.mjs +340 -0
- package/src/standalone/agent-tool.mjs +112 -941
- package/src/standalone/channel-daemon-transport.mjs +126 -185
- package/src/standalone/channel-daemon.mjs +9 -10
- package/src/standalone/usage-dashboard.mjs +23 -1
- package/src/tui/App.jsx +362 -2569
- package/src/tui/app/app-view.jsx +504 -0
- package/src/tui/app/channel-pickers.mjs +3 -8
- package/src/tui/app/create-app-pickers.mjs +313 -0
- package/src/tui/app/prompt-submit.mjs +501 -0
- package/src/tui/app/route-pickers.mjs +117 -152
- package/src/tui/app/settings-picker.mjs +90 -89
- package/src/tui/app/shell-layout.mjs +563 -0
- package/src/tui/app/slash-commands.mjs +7 -7
- package/src/tui/app/slash-dispatch.mjs +0 -45
- package/src/tui/app/usage-context-panels.mjs +288 -0
- package/src/tui/app/use-copy-selection.mjs +56 -0
- package/src/tui/app/use-global-key-input.mjs +151 -0
- package/src/tui/app/use-pasted-buffers.mjs +115 -0
- package/src/tui/app/use-prompt-draft-flow.mjs +167 -0
- package/src/tui/app/use-prompt-hint.mjs +58 -0
- package/src/tui/app/use-prompt-queue-history.mjs +100 -0
- package/src/tui/app/use-terminal-chrome.mjs +72 -0
- package/src/tui/app/use-transcript-activity.mjs +131 -0
- package/src/tui/app/use-welcome-prompt-hint.mjs +96 -0
- package/src/tui/components/StatusLine.jsx +1 -1
- package/src/tui/components/tool-execution/ResultBody.jsx +1 -1
- package/src/tui/dist/index.mjs +9857 -9159
- package/src/tui/engine/session-api-ext.mjs +47 -9
- package/src/tui/engine.mjs +7 -1
- 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
|
@@ -27,7 +27,6 @@ export function createRoutePickers({
|
|
|
27
27
|
setContextPanel,
|
|
28
28
|
closeUsagePanel,
|
|
29
29
|
clean,
|
|
30
|
-
copyToClipboard,
|
|
31
30
|
routeLabel,
|
|
32
31
|
agentModelParts,
|
|
33
32
|
agentModelProfile,
|
|
@@ -158,28 +157,134 @@ export function createRoutePickers({
|
|
|
158
157
|
closeUsagePanel();
|
|
159
158
|
setPicker({
|
|
160
159
|
title: 'Workflow',
|
|
161
|
-
description: '
|
|
162
|
-
help: returnTo ? '↑/↓ Select · Enter
|
|
160
|
+
description: 'Active workflow and its agents.',
|
|
161
|
+
help: returnTo ? '↑/↓ Select · Enter Open · Esc Settings' : '↑/↓ Select · Enter Open · Esc Back',
|
|
163
162
|
labelWidth: 18,
|
|
163
|
+
initialIndex: Math.max(0, items.findIndex((item) => item.value === (options.initialWorkflowId || ''))),
|
|
164
164
|
items,
|
|
165
165
|
onSelect: (_value, item) => {
|
|
166
166
|
const workflow = item?._workflow;
|
|
167
167
|
if (!workflow) return;
|
|
168
|
+
// Depth mirrors the system model: a workflow pack owns the agent set
|
|
169
|
+
// it delegates to, so Enter opens the pack (activate + its agents)
|
|
170
|
+
// instead of switching immediately.
|
|
171
|
+
openWorkflowDetailPicker(workflow.id, { returnTo });
|
|
172
|
+
},
|
|
173
|
+
onCancel: () => {
|
|
168
174
|
setPicker(null);
|
|
169
|
-
|
|
170
|
-
|
|
175
|
+
if (returnTo) returnTo();
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Workflow detail: activation row plus the agents this pack delegates to
|
|
181
|
+
// (route editing inline). Packs without an `agents:` key delegate to all
|
|
182
|
+
// fixed agents; a configured-but-empty list means Lead works alone.
|
|
183
|
+
const openWorkflowDetailPicker = (workflowId, options = {}) => {
|
|
184
|
+
const returnTo = typeof options.returnTo === 'function' ? options.returnTo : null;
|
|
185
|
+
let workflows = [];
|
|
186
|
+
try {
|
|
187
|
+
workflows = store.listWorkflows?.() || [];
|
|
188
|
+
} catch (e) {
|
|
189
|
+
store.pushNotice(`could not list workflows: ${e?.message || e}`, 'error');
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const workflow = workflows.find((item) => item.id === workflowId);
|
|
193
|
+
if (!workflow) {
|
|
194
|
+
store.pushNotice(`workflow "${workflowId}" not found`, 'warn');
|
|
195
|
+
openWorkflowPicker({ returnTo });
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
let agents = [];
|
|
199
|
+
try {
|
|
200
|
+
agents = store.listAgents?.() || [];
|
|
201
|
+
} catch (e) {
|
|
202
|
+
store.pushNotice(`could not list agents: ${e?.message || e}`, 'error');
|
|
203
|
+
agents = [];
|
|
204
|
+
}
|
|
205
|
+
const packAgents = workflow.agentsConfigured === true
|
|
206
|
+
? (workflow.agents || [])
|
|
207
|
+
.map((id) => agents.find((agent) => agent.id === id) || { id, label: id, route: null, description: '' })
|
|
208
|
+
: agents.filter((agent) => agent.custom !== true);
|
|
209
|
+
const routeOverrides = options.routeOverrides && typeof options.routeOverrides === 'object' ? options.routeOverrides : {};
|
|
210
|
+
const items = [
|
|
211
|
+
{
|
|
212
|
+
value: '__activate',
|
|
213
|
+
label: workflow.active ? 'Active' : 'Activate',
|
|
214
|
+
marker: workflow.active ? '✓' : '',
|
|
215
|
+
markerColor: theme.success,
|
|
216
|
+
description: workflow.active
|
|
217
|
+
? 'This workflow is active.'
|
|
218
|
+
: 'Make this the active workflow.',
|
|
219
|
+
},
|
|
220
|
+
...(packAgents.length
|
|
221
|
+
? packAgents.map((agent) => ({
|
|
222
|
+
value: agent.id,
|
|
223
|
+
label: agent.label,
|
|
224
|
+
metaParts: agentModelParts(routeOverrides[agent.id] || agent.route),
|
|
225
|
+
description: agent.description || agent.definition?.description || '',
|
|
226
|
+
_agent: agent,
|
|
227
|
+
}))
|
|
228
|
+
: [{
|
|
229
|
+
value: '__lead-only',
|
|
230
|
+
label: 'Lead only',
|
|
231
|
+
description: 'This workflow delegates to no agents.',
|
|
232
|
+
}]),
|
|
233
|
+
];
|
|
234
|
+
setPicker({
|
|
235
|
+
title: workflow.name,
|
|
236
|
+
description: workflow.description || 'Workflow activation and agents.',
|
|
237
|
+
help: '↑/↓ Select · Enter Choose · Esc Back',
|
|
238
|
+
indexMode: 'always',
|
|
239
|
+
labelWidth: 18,
|
|
240
|
+
metaWidth: 33,
|
|
241
|
+
initialIndex: Math.max(0, items.findIndex((item) => item.value === (options.initialValue || '__activate'))),
|
|
242
|
+
items,
|
|
243
|
+
onSelect: (_value, item) => {
|
|
244
|
+
if (item?.value === '__activate') {
|
|
245
|
+
if (workflow.active) {
|
|
246
|
+
store.pushNotice(`${workflow.name} is already the active workflow`, 'info');
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
setPicker(null);
|
|
250
|
+
void store.setWorkflow?.(workflow.id)
|
|
251
|
+
.then((result) => {
|
|
252
|
+
if (!result) {
|
|
253
|
+
store.pushNotice('Workflow switch is already running.', 'warn');
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
store.pushNotice(workflowSwitchNotice(result), 'info');
|
|
257
|
+
openWorkflowPicker({ returnTo, initialWorkflowId: workflow.id });
|
|
258
|
+
})
|
|
259
|
+
.catch((e) => store.pushNotice(`Couldn’t switch workflow: ${e?.message || e}`, 'error'));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const agent = item?._agent;
|
|
263
|
+
if (!agent) return;
|
|
264
|
+
void openModelPicker({
|
|
265
|
+
title: `${agent.label} Model`,
|
|
266
|
+
providerDescription: 'Choose a provider for this agent.',
|
|
267
|
+
currentRoute: agent.route || null,
|
|
268
|
+
returnTo: () => openWorkflowDetailPicker(workflow.id, { returnTo, initialValue: agent.id }),
|
|
269
|
+
onImmediateSelect: (routeInput) => {
|
|
270
|
+
openWorkflowDetailPicker(workflow.id, {
|
|
271
|
+
returnTo,
|
|
272
|
+
routeOverrides: { [agent.id]: routeInput },
|
|
273
|
+
initialValue: agent.id,
|
|
274
|
+
});
|
|
275
|
+
},
|
|
276
|
+
onSelectRoute: async (routeInput) => {
|
|
277
|
+
const result = await store.setAgentRoute?.(agent.id, routeInput);
|
|
171
278
|
if (!result) {
|
|
172
|
-
store.pushNotice('
|
|
279
|
+
store.pushNotice('Agent model save is already running.', 'warn');
|
|
173
280
|
return;
|
|
174
281
|
}
|
|
175
|
-
store.pushNotice(
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
.catch((e) => store.pushNotice(`Couldn’t switch workflow: ${e?.message || e}`, 'error'));
|
|
282
|
+
store.pushNotice(`${agent.label} model set to ${agentModelProfile(result)}`, 'info');
|
|
283
|
+
},
|
|
284
|
+
});
|
|
179
285
|
},
|
|
180
286
|
onCancel: () => {
|
|
181
|
-
|
|
182
|
-
if (returnTo) returnTo();
|
|
287
|
+
openWorkflowPicker({ returnTo, initialWorkflowId: workflow.id });
|
|
183
288
|
},
|
|
184
289
|
});
|
|
185
290
|
};
|
|
@@ -274,150 +379,10 @@ export function createRoutePickers({
|
|
|
274
379
|
});
|
|
275
380
|
};
|
|
276
381
|
|
|
277
|
-
const openBridgePicker = () => {
|
|
278
|
-
setProviderPrompt(null);
|
|
279
|
-
setChannelPrompt(null);
|
|
280
|
-
setHookPrompt(null);
|
|
281
|
-
setSettingsPrompt(null);
|
|
282
|
-
setPicker({
|
|
283
|
-
title: 'Agent Tasks',
|
|
284
|
-
description: 'Inspect or clean up background agent tasks.',
|
|
285
|
-
items: [
|
|
286
|
-
{
|
|
287
|
-
value: 'list',
|
|
288
|
-
label: 'List agents/tasks',
|
|
289
|
-
description: 'show active agents and async tasks',
|
|
290
|
-
_action: 'control',
|
|
291
|
-
_args: { type: 'list' },
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
value: 'cleanup',
|
|
295
|
-
label: 'Cleanup finished tasks',
|
|
296
|
-
description: 'remove completed agent task records',
|
|
297
|
-
_action: 'control',
|
|
298
|
-
_args: { type: 'cleanup' },
|
|
299
|
-
},
|
|
300
|
-
],
|
|
301
|
-
onSelect: (_value, item) => {
|
|
302
|
-
setPicker(null);
|
|
303
|
-
if (item._action === 'control') {
|
|
304
|
-
void store.agentControl?.(item._args)
|
|
305
|
-
.catch((e) => store.pushNotice(`agent failed: ${e?.message || e}`, 'error'));
|
|
306
|
-
}
|
|
307
|
-
},
|
|
308
|
-
onCancel: () => {
|
|
309
|
-
setPicker(null);
|
|
310
|
-
},
|
|
311
|
-
});
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
const openToolsPicker = (query = '') => {
|
|
315
|
-
let status;
|
|
316
|
-
try {
|
|
317
|
-
status = store.toolsStatus?.(query) || { tools: [] };
|
|
318
|
-
} catch (e) {
|
|
319
|
-
store.pushNotice(`tools status failed: ${e?.message || e}`, 'error');
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
const tools = status.tools || [];
|
|
323
|
-
const items = [
|
|
324
|
-
{
|
|
325
|
-
value: 'summary',
|
|
326
|
-
label: 'Tool surface',
|
|
327
|
-
description: `${status.activeCount || 0}/${status.count || 0} active · mode ${status.mode || state.toolMode}`,
|
|
328
|
-
_action: 'summary',
|
|
329
|
-
},
|
|
330
|
-
...(tools.length ? tools.map((tool) => ({
|
|
331
|
-
value: tool.name,
|
|
332
|
-
label: tool.name,
|
|
333
|
-
marker: tool.active ? '●' : '○',
|
|
334
|
-
markerColor: tool.active ? theme.success : theme.inactive,
|
|
335
|
-
description: `${tool.kind || 'tool'} · usage ${tool.usage || 0}${tool.description ? ` · ${tool.description}` : ''}`,
|
|
336
|
-
_action: tool.active ? 'tool' : 'enable',
|
|
337
|
-
_tool: tool,
|
|
338
|
-
})) : [{
|
|
339
|
-
value: 'empty',
|
|
340
|
-
label: 'No tools',
|
|
341
|
-
description: query ? `no matches for "${query}"` : 'tool catalog is empty',
|
|
342
|
-
_action: 'noop',
|
|
343
|
-
}]),
|
|
344
|
-
];
|
|
345
|
-
setProviderPrompt(null);
|
|
346
|
-
setChannelPrompt(null);
|
|
347
|
-
setHookPrompt(null);
|
|
348
|
-
setSettingsPrompt(null);
|
|
349
|
-
setPicker({
|
|
350
|
-
title: query ? `Tools · ${query}` : 'Tools',
|
|
351
|
-
description: 'Browse active and deferred tools.',
|
|
352
|
-
items,
|
|
353
|
-
onSelect: (_value, item) => {
|
|
354
|
-
setPicker(null);
|
|
355
|
-
if (item._action === 'summary') {
|
|
356
|
-
store.pushNotice([
|
|
357
|
-
`mode: ${status.mode || state.toolMode}`,
|
|
358
|
-
`active: ${status.activeCount || 0}/${status.count || 0}`,
|
|
359
|
-
`active tools: ${(status.activeTools || []).join(', ') || '(none)'}`,
|
|
360
|
-
].join('\n'), 'info');
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
if (item._action === 'enable') {
|
|
364
|
-
store.selectTools?.([item._tool.name]);
|
|
365
|
-
void openToolsPicker(query);
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
if (item._action === 'tool') {
|
|
369
|
-
const tool = item._tool;
|
|
370
|
-
setPicker({
|
|
371
|
-
title: `Tool · ${tool.name}`,
|
|
372
|
-
description: 'Tool details and quick actions.',
|
|
373
|
-
items: [
|
|
374
|
-
{
|
|
375
|
-
value: 'info',
|
|
376
|
-
label: 'Tool info',
|
|
377
|
-
description: `${tool.kind || 'tool'} · ${tool.active ? 'active' : 'deferred'}`,
|
|
378
|
-
_action: 'info',
|
|
379
|
-
},
|
|
380
|
-
{
|
|
381
|
-
value: 'copy-name',
|
|
382
|
-
label: 'Copy name',
|
|
383
|
-
description: tool.name,
|
|
384
|
-
_action: 'copy-name',
|
|
385
|
-
},
|
|
386
|
-
],
|
|
387
|
-
onSelect: (_detailValue, detail) => {
|
|
388
|
-
setPicker(null);
|
|
389
|
-
if (detail._action === 'info') {
|
|
390
|
-
store.pushNotice([
|
|
391
|
-
tool.name,
|
|
392
|
-
`kind: ${tool.kind || 'tool'}`,
|
|
393
|
-
`state: ${tool.active ? 'active' : 'deferred'}`,
|
|
394
|
-
`usage: ${tool.usage || 0}`,
|
|
395
|
-
tool.description || '',
|
|
396
|
-
].filter(Boolean).join('\n'), 'info');
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
if (detail._action === 'copy-name') {
|
|
400
|
-
void copyToClipboard(tool.name)
|
|
401
|
-
.then(() => store.pushNotice(`copied tool name: ${tool.name}`, 'plain'))
|
|
402
|
-
.catch((e) => store.pushNotice(`copy failed: ${e?.message || e}`, 'error'));
|
|
403
|
-
}
|
|
404
|
-
},
|
|
405
|
-
onCancel: () => openToolsPicker(query),
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
},
|
|
409
|
-
onCancel: () => {
|
|
410
|
-
setPicker(null);
|
|
411
|
-
},
|
|
412
|
-
});
|
|
413
|
-
};
|
|
414
|
-
|
|
415
382
|
return {
|
|
416
383
|
openSearchPicker,
|
|
417
384
|
openAgentsPicker,
|
|
418
385
|
openWorkflowPicker,
|
|
419
386
|
openOutputStylePicker,
|
|
420
|
-
openBridgePicker,
|
|
421
|
-
openToolsPicker,
|
|
422
387
|
};
|
|
423
388
|
}
|
|
@@ -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({
|