mixdog 0.9.2 → 0.9.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/package.json +2 -1
- package/scripts/anthropic-maxtokens-test.mjs +119 -0
- package/scripts/build-tui.mjs +13 -1
- package/scripts/explore-bench.mjs +124 -0
- package/scripts/hook-bus-test.mjs +191 -0
- package/scripts/path-suffix-test.mjs +57 -0
- package/scripts/recall-bench.mjs +207 -0
- package/scripts/tool-smoke.mjs +7 -4
- package/src/agents/debugger/AGENT.md +2 -2
- package/src/agents/heavy-worker/AGENT.md +20 -11
- package/src/agents/reviewer/AGENT.md +2 -2
- package/src/agents/worker/AGENT.md +17 -11
- package/src/mixdog-session-runtime.mjs +424 -1812
- package/src/repl.mjs +5 -5
- package/src/rules/agent/30-explorer.md +8 -11
- package/src/rules/lead/lead-tool.md +9 -5
- package/src/rules/shared/01-tool.md +11 -5
- package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
- package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +22 -68
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +46 -7
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +7 -5
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +33 -23
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +31 -14
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
- package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +262 -0
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
- package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
- package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/loop.mjs +169 -918
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +227 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +137 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +65 -1032
- package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.test.mjs +162 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +5 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +50 -39
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +497 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1192 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
- package/src/runtime/agent/orchestrator/tools/patch.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
- package/src/runtime/channels/index.mjs +14 -233
- package/src/runtime/channels/lib/boot-profile.mjs +23 -0
- package/src/runtime/channels/lib/crash-log.mjs +106 -0
- package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
- package/src/runtime/channels/lib/output-forwarder.mjs +8 -0
- package/src/runtime/channels/lib/telegram-format.mjs +19 -22
- package/src/runtime/channels/lib/whisper-language.mjs +42 -0
- package/src/runtime/memory/index.mjs +314 -359
- package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
- package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
- package/src/runtime/memory/lib/http-wire.mjs +57 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +56 -3
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
- package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
- package/src/runtime/memory/lib/memory.mjs +20 -0
- package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
- package/src/runtime/memory/lib/recall-format.mjs +183 -0
- package/src/runtime/memory/tool-defs.mjs +4 -4
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/background-tasks.mjs +2 -3
- package/src/runtime/shared/buffered-appender.mjs +149 -0
- package/src/runtime/shared/task-notification-envelope.mjs +98 -0
- package/src/runtime/shared/task-notification-envelope.test.mjs +107 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -2
- package/src/runtime/shared/transcript-writer.mjs +29 -2
- package/src/session-runtime/config-helpers.mjs +209 -0
- package/src/session-runtime/effort.mjs +128 -0
- package/src/session-runtime/fs-utils.mjs +10 -0
- package/src/session-runtime/model-capabilities.mjs +130 -0
- package/src/session-runtime/output-styles.mjs +124 -0
- package/src/session-runtime/plugin-mcp.mjs +114 -0
- package/src/session-runtime/session-text.mjs +100 -0
- package/src/session-runtime/statusline-route.mjs +35 -0
- package/src/session-runtime/tool-catalog.mjs +720 -0
- package/src/session-runtime/workflow.mjs +358 -0
- package/src/standalone/agent-tool.mjs +49 -10
- package/src/standalone/channel-worker.mjs +3 -2
- package/src/standalone/explore-tool.mjs +10 -3
- package/src/standalone/hook-bus.mjs +165 -8
- package/src/standalone/opencode-go-login.mjs +121 -0
- package/src/standalone/provider-admin.mjs +14 -3
- package/src/tui/App.jsx +884 -143
- package/src/tui/components/PromptInput.jsx +272 -15
- package/src/tui/components/ToolExecution.jsx +20 -10
- package/src/tui/components/tool-output-format.mjs +2 -2
- package/src/tui/dist/index.mjs +1771 -1947
- package/src/tui/engine/agent-envelope.mjs +296 -0
- package/src/tui/engine/boot-profile.mjs +21 -0
- package/src/tui/engine/labels.mjs +67 -0
- package/src/tui/engine/notice-text.mjs +112 -0
- package/src/tui/engine/queue-helpers.mjs +161 -0
- package/src/tui/engine/session-stats.mjs +46 -0
- package/src/tui/engine/tool-call-fields.mjs +23 -0
- package/src/tui/engine/tool-result-text.mjs +126 -0
- package/src/tui/engine.mjs +311 -851
- package/src/tui/input-editing.mjs +58 -8
- package/src/tui/input-editing.selection.test.mjs +75 -0
- package/src/tui/keyboard-protocol.mjs +2 -2
- package/src/tui/lib/voice-recorder.mjs +35 -19
- package/src/tui/markdown/format-token.mjs +7 -8
- package/src/tui/markdown/format-token.test.mjs +3 -3
- package/src/tui/paste-attachments.mjs +38 -0
- package/src/tui/paste-fix.test.mjs +119 -0
- package/src/tui/themes/base.mjs +2 -2
- package/src/tui/themes/kanagawa.mjs +4 -4
- package/src/tui/themes/teal.mjs +4 -5
- package/src/tui/themes/utils.mjs +1 -1
- package/src/ui/statusline.mjs +49 -0
- package/src/workflows/default/WORKFLOW.md +16 -9
- package/src/workflows/sequential/WORKFLOW.md +16 -11
- package/src/workflows/solo/WORKFLOW.md +5 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Plugin/project MCP server discovery + normalization, and skill-file counting.
|
|
2
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
3
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
4
|
+
import { clean } from './session-text.mjs';
|
|
5
|
+
import { readJsonSafe } from './fs-utils.mjs';
|
|
6
|
+
|
|
7
|
+
// Project-local MCP ingress: read `.mcp.json` from the project root and return
|
|
8
|
+
// a cleaned { name: cfg } map. Best-effort — never throws. Accepts either the
|
|
9
|
+
// standard `{ mcpServers: {...} }` shape or a bare name->cfg map. Self-ref
|
|
10
|
+
// servers (`mixdog` / `trib-plugin`) are stripped for parity with loadConfig.
|
|
11
|
+
// Inputs are not mutated.
|
|
12
|
+
export function readProjectMcpServers(cwd) {
|
|
13
|
+
const path = join(cwd || '.', '.mcp.json');
|
|
14
|
+
if (!existsSync(path)) return {};
|
|
15
|
+
let raw;
|
|
16
|
+
try {
|
|
17
|
+
raw = JSON.parse(readFileSync(path, 'utf8'));
|
|
18
|
+
} catch (error) {
|
|
19
|
+
process.stderr.write(`[mcp-client] Ignoring unparseable .mcp.json at ${path}: ${error?.message || String(error)}\n`);
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return {};
|
|
23
|
+
const map = raw.mcpServers && typeof raw.mcpServers === 'object' && !Array.isArray(raw.mcpServers)
|
|
24
|
+
? raw.mcpServers
|
|
25
|
+
: raw;
|
|
26
|
+
if (!map || typeof map !== 'object' || Array.isArray(map)) return {};
|
|
27
|
+
const out = {};
|
|
28
|
+
for (const [name, cfg] of Object.entries(map)) {
|
|
29
|
+
const key = clean(name);
|
|
30
|
+
if (!key) continue;
|
|
31
|
+
const lower = key.toLowerCase();
|
|
32
|
+
if (lower === 'mixdog' || lower === 'trib-plugin') continue;
|
|
33
|
+
if (!cfg || typeof cfg !== 'object' || Array.isArray(cfg)) continue;
|
|
34
|
+
// stdio entries (command + no url) spawn relative to the process launch
|
|
35
|
+
// dir, but mixdog tracks the project dir in memory (no process.chdir).
|
|
36
|
+
// Anchor their cwd to the .mcp.json directory: default when absent, resolve
|
|
37
|
+
// relative values against it, keep absolute values as-is.
|
|
38
|
+
const isStdio = typeof cfg.command === 'string' && cfg.command !== '' && !cfg.url;
|
|
39
|
+
if (isStdio) {
|
|
40
|
+
out[key] = { ...cfg, cwd: typeof cfg.cwd === 'string' && cfg.cwd ? resolve(cwd, cfg.cwd) : resolve(cwd) };
|
|
41
|
+
} else {
|
|
42
|
+
out[key] = cfg;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function countSkillFiles(root) {
|
|
49
|
+
const skillsDir = join(root, 'skills');
|
|
50
|
+
if (!existsSync(skillsDir)) return 0;
|
|
51
|
+
let count = 0;
|
|
52
|
+
const walk = (dir) => {
|
|
53
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
54
|
+
const full = join(dir, entry.name);
|
|
55
|
+
if (entry.isDirectory()) walk(full);
|
|
56
|
+
else if (/^(SKILL|skill)\.md$/i.test(entry.name) || entry.name.toLowerCase().endsWith('.md')) count += 1;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
try { walk(skillsDir); } catch { return count; }
|
|
60
|
+
return count;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function mcpScriptForPlugin(root) {
|
|
64
|
+
const candidates = [
|
|
65
|
+
'.mcp.json',
|
|
66
|
+
'scripts/run-mcp.mjs',
|
|
67
|
+
'mcp/server.mjs',
|
|
68
|
+
'server.mjs',
|
|
69
|
+
];
|
|
70
|
+
return candidates.find((rel) => existsSync(join(root, rel))) || null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function substitutePluginRootTokens(value, root) {
|
|
74
|
+
if (typeof value !== 'string') return value;
|
|
75
|
+
return value
|
|
76
|
+
.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, root)
|
|
77
|
+
.replace(/\$\{CODEX_PLUGIN_ROOT\}/g, root);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function substitutePluginRootTokensDeep(value, root) {
|
|
81
|
+
if (typeof value === 'string') return substitutePluginRootTokens(value, root);
|
|
82
|
+
if (Array.isArray(value)) return value.map((v) => substitutePluginRootTokensDeep(v, root));
|
|
83
|
+
if (value && typeof value === 'object') {
|
|
84
|
+
const out = {};
|
|
85
|
+
for (const [k, v] of Object.entries(value)) out[k] = substitutePluginRootTokensDeep(v, root);
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function normalizePluginMcpServerConfig(cfg, root) {
|
|
92
|
+
const substituted = substitutePluginRootTokensDeep(cfg, root) || {};
|
|
93
|
+
const out = { ...substituted };
|
|
94
|
+
if (typeof out.cwd === 'string' && out.cwd) {
|
|
95
|
+
out.cwd = isAbsolute(out.cwd) ? out.cwd : join(root, out.cwd);
|
|
96
|
+
} else {
|
|
97
|
+
out.cwd = root;
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function pluginManifest(root) {
|
|
103
|
+
return readJsonSafe(join(root, '.codex-plugin', 'plugin.json'))
|
|
104
|
+
|| readJsonSafe(join(root, 'plugin.json'))
|
|
105
|
+
|| {};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function pluginMcpServerName(plugin = {}) {
|
|
109
|
+
const base = clean(plugin.name || plugin.title || 'plugin')
|
|
110
|
+
.toLowerCase()
|
|
111
|
+
.replace(/[^a-z0-9_.-]+/g, '-')
|
|
112
|
+
.replace(/^-+|-+$/g, '');
|
|
113
|
+
return base ? `plugin-${base}` : 'plugin-mcp';
|
|
114
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Session message/preview text helpers. Pure, no runtime-closure deps.
|
|
2
|
+
|
|
3
|
+
export function sessionMessageText(content) {
|
|
4
|
+
if (content == null) return '';
|
|
5
|
+
if (typeof content === 'string') return content;
|
|
6
|
+
const parts = Array.isArray(content)
|
|
7
|
+
? content
|
|
8
|
+
: (content && typeof content === 'object' && Array.isArray(content.content) ? content.content : null);
|
|
9
|
+
if (parts) {
|
|
10
|
+
return parts.map((part) => {
|
|
11
|
+
if (typeof part === 'string') return part;
|
|
12
|
+
return part?.text ?? '';
|
|
13
|
+
}).filter(Boolean).join('\n');
|
|
14
|
+
}
|
|
15
|
+
if (typeof content === 'object' && typeof content.text === 'string') return content.text;
|
|
16
|
+
try { return JSON.stringify(content); } catch { return String(content); }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function messageContextText(message) {
|
|
20
|
+
if (!message || typeof message !== 'object') return '';
|
|
21
|
+
let text = sessionMessageText(message.content);
|
|
22
|
+
if (message.role === 'assistant' && Array.isArray(message.toolCalls) && message.toolCalls.length) {
|
|
23
|
+
try { text += `\n${JSON.stringify(message.toolCalls)}`; }
|
|
24
|
+
catch { text += `\n[${message.toolCalls.length} tool calls]`; }
|
|
25
|
+
}
|
|
26
|
+
if (message.role === 'tool' && message.toolCallId) text += `\n${message.toolCallId}`;
|
|
27
|
+
return text;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function isSessionPreviewNoise(text) {
|
|
31
|
+
const value = String(text || '').trim();
|
|
32
|
+
return !value
|
|
33
|
+
|| value.startsWith('<system-reminder>')
|
|
34
|
+
|| value.startsWith('</system-reminder>')
|
|
35
|
+
|| /^#\s*permission\b/i.test(value)
|
|
36
|
+
|| /^permission:\s*/i.test(value)
|
|
37
|
+
|| /^cwd:\s*/i.test(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function cleanSessionPreview(text) {
|
|
41
|
+
return String(text || '')
|
|
42
|
+
.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, ' ')
|
|
43
|
+
.replace(/\s+/g, ' ')
|
|
44
|
+
.trim()
|
|
45
|
+
.slice(0, 160);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function clean(value) {
|
|
49
|
+
return String(value ?? '').trim();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function hasOwn(obj, key) {
|
|
53
|
+
return Object.prototype.hasOwnProperty.call(obj || {}, key);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function toolResponseText(result) {
|
|
57
|
+
if (result && typeof result === 'object' && Array.isArray(result.content)) {
|
|
58
|
+
return result.content
|
|
59
|
+
.map((part) => (part?.type === 'text' ? part.text || '' : JSON.stringify(part)))
|
|
60
|
+
.join('\n');
|
|
61
|
+
}
|
|
62
|
+
if (typeof result === 'string') return result;
|
|
63
|
+
return JSON.stringify(result, null, 2);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function isEmptyRecallText(value) {
|
|
67
|
+
const text = String(value || '').trim();
|
|
68
|
+
return !text || /^\(?no results\)?$/i.test(text) || /^\(?empty memory result\)?$/i.test(text);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function currentSessionRecallRows(session, query, { limit = 10 } = {}) {
|
|
72
|
+
const messages = Array.isArray(session?.messages) ? session.messages : [];
|
|
73
|
+
if (!messages.length) return '(no results)';
|
|
74
|
+
const terms = [...new Set(String(query || '').toLowerCase().match(/[\p{L}\p{N}_./:-]{2,}/gu) || [])]
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.slice(0, 16);
|
|
77
|
+
const max = Math.max(1, Math.min(100, Number(limit) || 10));
|
|
78
|
+
const rows = [];
|
|
79
|
+
for (let i = messages.length - 1; i >= 0 && rows.length < max; i -= 1) {
|
|
80
|
+
const m = messages[i];
|
|
81
|
+
if (!m || (m.role !== 'user' && m.role !== 'assistant' && m.role !== 'tool')) continue;
|
|
82
|
+
const text = messageContextText(m).replace(/\s+/g, ' ').trim();
|
|
83
|
+
if (!text) continue;
|
|
84
|
+
if (terms.length && !terms.some((term) => text.toLowerCase().includes(term))) continue;
|
|
85
|
+
rows.push(`[session:${i + 1}] ${m.role}: ${text.slice(0, 1000)}`);
|
|
86
|
+
}
|
|
87
|
+
return rows.length ? rows.join('\n') : '(no results)';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function sessionHasConversationMessages(activeSession) {
|
|
91
|
+
const messages = Array.isArray(activeSession?.messages) ? activeSession.messages : [];
|
|
92
|
+
return messages.some((message) => {
|
|
93
|
+
const role = message?.role;
|
|
94
|
+
if (role !== 'user' && role !== 'assistant' && role !== 'tool') return false;
|
|
95
|
+
const text = sessionMessageText(message.content).trim();
|
|
96
|
+
if (!text && role !== 'assistant') return false;
|
|
97
|
+
if (role === 'user' && isSessionPreviewNoise(text)) return false;
|
|
98
|
+
return true;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Statusline route serialization. Pure helpers.
|
|
2
|
+
import { clean, hasOwn } from './session-text.mjs';
|
|
3
|
+
|
|
4
|
+
export function routeForStatusline(route) {
|
|
5
|
+
const out = {
|
|
6
|
+
mode: 'fixed',
|
|
7
|
+
defaultProvider: route.provider,
|
|
8
|
+
defaultModel: route.model,
|
|
9
|
+
};
|
|
10
|
+
const preset = route.preset || {};
|
|
11
|
+
if (preset.id) out.presetId = preset.id;
|
|
12
|
+
if (preset.name) out.presetName = preset.name;
|
|
13
|
+
// Prefer the preset's curated label, then the route's resolved model display
|
|
14
|
+
// (set by refreshRouteEffort from the live/offline catalog). Without the
|
|
15
|
+
// route fallback, a preset-less direct model (e.g. claude-fable-5) reaches
|
|
16
|
+
// the statusline with no display and renders as the raw id.
|
|
17
|
+
const modelDisplay = clean(preset.modelDisplay) || clean(route.modelDisplay);
|
|
18
|
+
if (modelDisplay) out.modelDisplay = modelDisplay;
|
|
19
|
+
if (route.fast === true || route.fast === false) out.fast = route.fast;
|
|
20
|
+
else if (preset.fast === true || preset.fast === false) out.fast = preset.fast;
|
|
21
|
+
if (route.effectiveEffort) {
|
|
22
|
+
out.effort = route.effectiveEffort;
|
|
23
|
+
out.displayEffort = route.effectiveEffort;
|
|
24
|
+
} else if (hasOwn(route, 'effort')) {
|
|
25
|
+
delete out.effort;
|
|
26
|
+
delete out.displayEffort;
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function writeStatuslineRoute(statusRoutes, session, route) {
|
|
32
|
+
if (!session?.id || !route) return;
|
|
33
|
+
const clientHostPid = session?.clientHostPid || process.pid;
|
|
34
|
+
statusRoutes?.writeGatewaySessionRoute?.(session.id, routeForStatusline(route), { clientHostPid });
|
|
35
|
+
}
|