mixdog 1.2.0 → 1.2.1
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 -5
- package/package.json +1 -1
- package/src/defaults/shipped-history.json +4 -0
- package/src/defaults/skills/pptx/SKILL.md +6 -6
- package/src/defaults/skills/pptx/references/review.md +6 -4
- package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
- package/src/defaults/skills/setup/references/actions.md +13 -3
- package/src/defaults/skills/visualize/SKILL.md +12 -9
- package/src/rules/shared/60-verification.md +3 -1
- package/src/rules/shared/70-delivery.md +4 -2
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
- package/src/runtime/agent/orchestrator/config.mjs +10 -4
- package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +86 -8
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +5 -1
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +65 -7
- package/src/runtime/agent/orchestrator/mcp/client.mjs +128 -44
- package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
- package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +108 -17
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +19 -11
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +444 -0
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +41 -28
- package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +9 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
- package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +267 -84
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +268 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
- package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +6 -4
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +17 -4
- package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +817 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +19 -12
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
- package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +21 -2
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
- package/src/runtime/attachments/store.d.mts +3 -0
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
- package/src/runtime/channels/lib/worker-main.mjs +17 -14
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
- package/src/runtime/effort-judge/judge-client.mjs +56 -18
- package/src/runtime/memory/lib/memory.mjs +1 -1
- package/src/runtime/memory/lib/session-ingest.mjs +2 -2
- package/src/runtime/shared/atomic-file.mjs +25 -4
- package/src/runtime/shared/extension-scopes.mjs +5 -3
- package/src/runtime/shared/file-lock.mjs +37 -11
- package/src/runtime/shared/llm/anthropic-effort.mjs +14 -0
- package/src/runtime/shared/llm/model-catalog.mjs +0 -12
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +6 -0
- package/src/runtime/shared/plugin-manifest.mjs +18 -9
- package/src/runtime/shared/pristine-execution-contract.json +9 -2
- package/src/runtime/shared/pristine-execution.mjs +28 -4
- package/src/runtime/shared/provider-accounts.mjs +124 -20
- package/src/runtime/shared/provider-api-key.mjs +12 -0
- package/src/runtime/shared/shell-display.mjs +9 -3
- package/src/runtime/shared/skill-mentions.d.mts +10 -0
- package/src/runtime/shared/skill-mentions.mjs +133 -0
- package/src/runtime/shared/skill-script-runtime.mjs +264 -0
- package/src/runtime/shared/tool-primitives.mjs +35 -2
- package/src/runtime/shared/turn-worktree-snapshot.mjs +25 -5
- package/src/runtime/shared/worker-requests.mjs +15 -2
- package/src/session-runtime/automation-agents.mjs +8 -2
- package/src/session-runtime/boot/apis.mjs +55 -0
- package/src/session-runtime/boot/config.mjs +5 -2
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +29 -18
- package/src/session-runtime/conversation-import/discovery.mjs +698 -0
- package/src/session-runtime/conversation-import/service.mjs +369 -0
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
- package/src/session-runtime/mcp-glue/connect.mjs +57 -10
- package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +115 -30
- package/src/session-runtime/mcp-glue.mjs +22 -2
- package/src/session-runtime/new-session-config.mjs +3 -2
- package/src/session-runtime/notification-bus.mjs +9 -2
- package/src/session-runtime/provider-auth/accounts.mjs +33 -15
- package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
- package/src/session-runtime/provider-readiness.mjs +16 -10
- package/src/session-runtime/resource-extension-sync.mjs +20 -5
- package/src/session-runtime/resource-mcp-api.mjs +101 -77
- package/src/session-runtime/resource-plugins-api.mjs +29 -41
- package/src/session-runtime/resource-scope-decorate.mjs +6 -8
- package/src/session-runtime/resource-skills-api.mjs +23 -2
- package/src/session-runtime/schedule-session-run.mjs +1 -1
- package/src/session-runtime/services/channel-session-router.mjs +4 -1
- package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
- package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
- package/src/session-runtime/services/provider-admin.mjs +64 -18
- package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
- package/src/session-runtime/setup-tool/executor.mjs +12 -1
- package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
- package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
- package/src/session-runtime/skills-api.mjs +7 -3
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/webhook-session-run.mjs +16 -4
- package/src/skill-script-entry.mjs +36 -0
- package/src/standalone/daemon-stored-session-views.mjs +11 -3
- package/src/standalone/daemon.mjs +41 -4
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +6 -1
- package/src/tui/App.jsx +9 -1
- package/src/tui/app/app-view/floating-panel.jsx +9 -1
- package/src/tui/app/app-view.jsx +6 -0
- package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
- package/src/tui/app/model-options.mjs +2 -0
- package/src/tui/app/skill-mention-palette.mjs +88 -0
- package/src/tui/app/slash-palette.mjs +23 -7
- package/src/tui/app/transcript-row-estimate.mjs +11 -3
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
- package/src/tui/app/use-prompt-state.mjs +5 -0
- package/src/tui/components/Message.jsx +22 -1
- package/src/tui/components/PromptInput.jsx +21 -3
- package/src/tui/components/SlashCommandPalette.jsx +12 -3
- package/src/tui/components/TranscriptItem.jsx +9 -1
- package/src/tui/components/prompt-input/key-handler.mjs +21 -8
- package/src/tui/components/user-message-skills.mjs +38 -0
- package/src/tui/dist/index.mjs +507 -171
- package/src/tui/session/queue-helpers.mjs +7 -2
- package/src/tui/session/session-api/extensions.mjs +4 -2
- package/src/tui/session/session-api/settings.mjs +7 -0
- package/src/tui/session/session-flow/drain.mjs +14 -4
- package/src/tui/session/tui-steering-persist.mjs +25 -9
- package/src/tui/session/turn.mjs +17 -0
- package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
- package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { selectedSkillName } from '../../../shared/skill-selection.mjs';
|
|
3
|
+
import { mentionedSkillNames, skillMentionCandidates } from '../../../shared/skill-mentions.mjs';
|
|
4
|
+
import { isAttachmentReference } from '../../../attachments/store.mjs';
|
|
5
|
+
import { collectPromptSkillsCached } from '../context/collect.mjs';
|
|
3
6
|
import { executeTool } from './loop/tool-exec.mjs';
|
|
7
|
+
import { preDispatchDenyForSession } from './loop/pre-dispatch-deny.mjs';
|
|
4
8
|
import { parseNativeToolSearchPayload } from './loop/tool-helpers.mjs';
|
|
5
9
|
import { normalizeToolEnvelope } from './tool-envelope.mjs';
|
|
6
10
|
import { throwIfAborted } from '../../../shared/abort-race.mjs';
|
|
@@ -20,19 +24,91 @@ function nativeDefinitionsPresent(native, messages) {
|
|
|
20
24
|
);
|
|
21
25
|
}
|
|
22
26
|
|
|
27
|
+
// At most this many skills are prepared for one user turn; further selections
|
|
28
|
+
// stay prose.
|
|
29
|
+
const MAX_EXPLICIT_SKILLS = 5;
|
|
30
|
+
const LOADED_SKILL_RE = /^Loaded (?:built-in )?skill: /;
|
|
31
|
+
|
|
32
|
+
// The user's own typed text: plain strings and text parts, never attachment
|
|
33
|
+
// references (file contents the user attached, not words they typed).
|
|
34
|
+
function userPromptText(prompt) {
|
|
35
|
+
if (typeof prompt === 'string') return prompt;
|
|
36
|
+
if (!Array.isArray(prompt)) return '';
|
|
37
|
+
return prompt
|
|
38
|
+
.map((part) => {
|
|
39
|
+
if (typeof part === 'string') return part;
|
|
40
|
+
if (part?.type === 'text' && typeof part.text === 'string' && !isAttachmentReference(part)) return part.text;
|
|
41
|
+
return '';
|
|
42
|
+
})
|
|
43
|
+
.join('\n');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The skills a prompt explicitly selects: the leading `Skill: "name"` header,
|
|
47
|
+
* then every inline `$name`, each only when it names a skill enabled and in
|
|
48
|
+
* scope for `cwd`, in first-mention order, deduplicated and capped. */
|
|
49
|
+
export function explicitSkillNames(prompt, cwd) {
|
|
50
|
+
const header = selectedSkillName(prompt);
|
|
51
|
+
const text = userPromptText(prompt);
|
|
52
|
+
if (!header && !skillMentionCandidates(text).length) return [];
|
|
53
|
+
const available = new Set(collectPromptSkillsCached(cwd).map((skill) => skill.name));
|
|
54
|
+
const isSkill = (name) => available.has(name);
|
|
55
|
+
const names = header && isSkill(header) ? [header] : [];
|
|
56
|
+
for (const name of mentionedSkillNames(text, isSkill)) {
|
|
57
|
+
if (!names.includes(name)) names.push(name);
|
|
58
|
+
}
|
|
59
|
+
return names.slice(0, MAX_EXPLICIT_SKILLS);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Stamps the skills a user turn actually loaded on its transcript metadata,
|
|
63
|
+
* where the live row, the persisted transcript and restore all read it.
|
|
64
|
+
* The stamped message REPLACES `message` in `messages` (returned): the
|
|
65
|
+
* session store ships reference-identical messages as an append-only delta,
|
|
66
|
+
* so an in-place edit of a user message an earlier save already sent would
|
|
67
|
+
* never reach disk. */
|
|
68
|
+
export function recordAppliedSkills(messages, message, names) {
|
|
69
|
+
if (!message || !Array.isArray(names) || !names.length) return message;
|
|
70
|
+
const meta = message.meta && typeof message.meta === 'object' ? message.meta : {};
|
|
71
|
+
const transcript = meta.transcript && typeof meta.transcript === 'object' ? meta.transcript : {};
|
|
72
|
+
const stamped = { ...message, meta: { ...meta, transcript: { ...transcript, appliedSkills: [...names] } } };
|
|
73
|
+
const index = Array.isArray(messages) ? messages.indexOf(message) : -1;
|
|
74
|
+
if (index >= 0) messages[index] = stamped;
|
|
75
|
+
return stamped;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Tells the host which skills a user turn loaded; a host callback failure
|
|
79
|
+
* never fails the turn. */
|
|
80
|
+
export function notifySkillsApplied(onSkillsApplied, applied, message) {
|
|
81
|
+
if (!applied.length) return;
|
|
82
|
+
try {
|
|
83
|
+
onSkillsApplied?.(applied, { messageId: message?.meta?.transcript?.messageId || null });
|
|
84
|
+
} catch {
|
|
85
|
+
/* best-effort host callback */
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
23
89
|
// Called before the first model request for a real user turn. This performs the
|
|
24
90
|
// same policy-checked Skill operation, without asking the model to request it.
|
|
25
91
|
// Native schemas still travel as a properly paired loader execution, never as
|
|
26
|
-
// new eager definitions or an orphan tool_search_output.
|
|
92
|
+
// new eager definitions or an orphan tool_search_output. Returns the names of
|
|
93
|
+
// the skills that loaded successfully, in selection order.
|
|
94
|
+
// `selection`, when given (even empty), is the turn's TRUSTED selection input
|
|
95
|
+
// and the only text skills are selected from: a host whose model-visible
|
|
96
|
+
// prompt carries external data (webhook payloads) passes just the
|
|
97
|
+
// operator-authored part, so nothing inside the data can load a skill.
|
|
27
98
|
export async function prepareExplicitSkills(
|
|
28
99
|
prompt,
|
|
29
100
|
messages,
|
|
30
101
|
session,
|
|
31
|
-
{ cwd = session?.cwd, signal, execute = executeTool } = {}
|
|
102
|
+
{ cwd = session?.cwd, signal, execute = executeTool, selection } = {}
|
|
32
103
|
) {
|
|
33
104
|
throwIfAborted(signal);
|
|
34
|
-
const
|
|
35
|
-
|
|
105
|
+
const applied = [];
|
|
106
|
+
// A session that cannot call Skill (schema allowlist, denied tools, read-only
|
|
107
|
+
// surface — the dispatcher's own gate) has nothing to select: preparing would
|
|
108
|
+
// only push a refused-tool reminder into history on every matching turn.
|
|
109
|
+
if (preDispatchDenyForSession(session, { name: 'Skill' })) return applied;
|
|
110
|
+
const source = selection === undefined || selection === null ? prompt : selection;
|
|
111
|
+
for (const name of explicitSkillNames(source, cwd)) {
|
|
36
112
|
const id = `skill-selection-${randomUUID()}`;
|
|
37
113
|
const args = { name };
|
|
38
114
|
const raw = await execute('Skill', args, cwd, session?.id, session, { signal, toolCallId: id });
|
|
@@ -55,6 +131,8 @@ export async function prepareExplicitSkills(
|
|
|
55
131
|
});
|
|
56
132
|
}
|
|
57
133
|
messages.push(...envelope.newMessages);
|
|
134
|
+
if (LOADED_SKILL_RE.test(String(summary))) applied.push(name);
|
|
135
|
+
throwIfAborted(signal);
|
|
58
136
|
}
|
|
59
|
-
|
|
137
|
+
return applied;
|
|
60
138
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provenance of messages carried over from another app's conversation
|
|
3
|
+
* (conversation-import). Their text is prose someone wrote elsewhere: it may
|
|
4
|
+
* look like a runtime reminder, a task envelope or a compaction summary, but
|
|
5
|
+
* restore and the model wire treat it as plain user/assistant text. Leaf, no IO.
|
|
6
|
+
*/
|
|
7
|
+
export const IMPORTED_MESSAGE_SOURCE = 'import';
|
|
8
|
+
|
|
9
|
+
export function isImportedMessage(message) {
|
|
10
|
+
return message?.meta?.source === IMPORTED_MESSAGE_SOURCE;
|
|
11
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// (signature + stub) and the edit-progress classification.
|
|
3
3
|
// Pure string/signature helpers; the loop body only wires state + messages.
|
|
4
4
|
// No provider/manager coupling.
|
|
5
|
+
import { knownMcpToolIdentity } from '../../../../shared/tool-primitives.mjs';
|
|
5
6
|
|
|
6
7
|
// Deterministic, key-sorted stringify for cross-turn call signatures (recursive,
|
|
7
8
|
// unlike tool-classify's top-level-only _canonicalArgs).
|
|
@@ -43,7 +44,7 @@ const NON_PROGRESS_TOOLS = new Set(['Skill', 'recall', 'agent', 'task', 'cwd', '
|
|
|
43
44
|
// not in the meta/non-progress set. apply_patch and shell/bash always count.
|
|
44
45
|
export function isEditProgressTool(name, isEager) {
|
|
45
46
|
if (isEager) return false;
|
|
46
|
-
const bare = name?.startsWith('mcp__') ? name.split('__').pop() : name;
|
|
47
|
+
const bare = name?.startsWith('mcp__') ? knownMcpToolIdentity(name)?.tool || name.split('__').pop() : name;
|
|
47
48
|
if (bare === 'apply_patch' || bare === 'shell' || bare === 'bash' || bare === 'bash_session') return true;
|
|
48
49
|
return !NON_PROGRESS_TOOLS.has(bare);
|
|
49
50
|
}
|
|
@@ -146,7 +146,7 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
|
|
|
146
146
|
messages,
|
|
147
147
|
opts,
|
|
148
148
|
sessionId,
|
|
149
|
-
onSkillPrompt: (content) => state.pendingSkillPrompts.push(content),
|
|
149
|
+
onSkillPrompt: (content, message) => state.pendingSkillPrompts.push({ content, message }),
|
|
150
150
|
});
|
|
151
151
|
// Bounded recovery for provider turns that returned no client tool calls
|
|
152
152
|
// (max-output ladder, refusal retry, provider continuation, empty-turn
|
|
@@ -34,8 +34,9 @@ export function createNoToolTurnResolver({
|
|
|
34
34
|
refusalRetryUsed: false,
|
|
35
35
|
emptyNudgeStreak: 0,
|
|
36
36
|
// Structured provider continuation signals honored this turn. Diagnostic
|
|
37
|
-
// only
|
|
38
|
-
//
|
|
37
|
+
// only: the loop has no iteration cap, so this count bounds nothing. A
|
|
38
|
+
// text-only continuation runaway is bounded by continuationsSinceToolBatch
|
|
39
|
+
// below; continuations interleaved with tool batches are not limited.
|
|
39
40
|
providerContinuationCount: 0,
|
|
40
41
|
// Continuations since the last executed tool batch — bounds the text-only
|
|
41
42
|
// continuation runaway (see PROVIDER_CONTINUATION_NO_TOOL_LIMIT).
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { traceCacheBreak } from '../../cache-break-trace.mjs';
|
|
7
7
|
import { resolveLiveToolCwd } from './tool-exec.mjs';
|
|
8
|
-
import { prepareExplicitSkills } from '../explicit-skills.mjs';
|
|
8
|
+
import { notifySkillsApplied, prepareExplicitSkills, recordAppliedSkills } from '../explicit-skills.mjs';
|
|
9
9
|
import { addUsage, usageDeltaEvent } from './usage.mjs';
|
|
10
10
|
import { prepareProviderRequest } from './request-boundary.mjs';
|
|
11
11
|
import { projectProviderRequest } from './request-projection.mjs';
|
|
@@ -44,10 +44,13 @@ export async function beginIteration(state) {
|
|
|
44
44
|
// policy-checked selection before the next provider snapshot instead of
|
|
45
45
|
// starting detached work from a drain callback.
|
|
46
46
|
while (state.pendingSkillPrompts.length) {
|
|
47
|
-
|
|
47
|
+
const { content, message: queued } = state.pendingSkillPrompts.shift();
|
|
48
|
+
const applied = await prepareExplicitSkills(content, messages, sessionRef, {
|
|
48
49
|
cwd: state.cwd,
|
|
49
50
|
signal: opts.signal,
|
|
50
51
|
});
|
|
52
|
+
const message = recordAppliedSkills(messages, queued, applied);
|
|
53
|
+
notifySkillsApplied(opts.onSkillsApplied, applied, message);
|
|
51
54
|
}
|
|
52
55
|
const boundary = await prepareProviderRequest({
|
|
53
56
|
provider,
|
|
@@ -263,8 +266,7 @@ function traceActualCacheMiss(state, sent, response, { previousGuardState, previ
|
|
|
263
266
|
const ttlMs = MESSAGES_CACHE_TTL_MS[sessionRef.providerCacheOpts?.cacheStrategy?.messages];
|
|
264
267
|
const idleMs = sent.sendStartedAt - previousSendAt;
|
|
265
268
|
const requestPrefixChanged =
|
|
266
|
-
!!previousGuardState &&
|
|
267
|
-
previousGuardState.requestPrefixHash !== sent.prefixGuardCandidate?.requestPrefixHash;
|
|
269
|
+
!!previousGuardState && previousGuardState.requestPrefixHash !== sent.prefixGuardCandidate?.requestPrefixHash;
|
|
268
270
|
if (
|
|
269
271
|
baseline > 0 &&
|
|
270
272
|
ttlMs &&
|
|
@@ -156,7 +156,7 @@ function injectSteeringEntry(merged, { messages, opts, stage, onSkillPrompt }) {
|
|
|
156
156
|
const notification = merged.mode === 'task-notification';
|
|
157
157
|
const execution =
|
|
158
158
|
notification && merged.execution && typeof merged.execution === 'object' ? { ...merged.execution } : null;
|
|
159
|
-
|
|
159
|
+
const message = {
|
|
160
160
|
role: 'user',
|
|
161
161
|
content: merged.content,
|
|
162
162
|
meta: {
|
|
@@ -165,8 +165,9 @@ function injectSteeringEntry(merged, { messages, opts, stage, onSkillPrompt }) {
|
|
|
165
165
|
...(submissionIds.length ? { submissionIds } : {}),
|
|
166
166
|
transcript: steeringTranscriptMeta,
|
|
167
167
|
},
|
|
168
|
-
}
|
|
169
|
-
|
|
168
|
+
};
|
|
169
|
+
messages.push(message);
|
|
170
|
+
if (!notification) onSkillPrompt(merged.content, message);
|
|
170
171
|
const text = merged.text || steeringContentText(merged.content);
|
|
171
172
|
try {
|
|
172
173
|
opts.onSteerMessage?.(text, {
|
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
filterSkillsExcludingDisabled,
|
|
13
13
|
isSkillDisabled,
|
|
14
14
|
skillMissingFeature,
|
|
15
|
+
skillOutsideScope,
|
|
16
|
+
skillOutsideScopeError,
|
|
15
17
|
} from '../../context/collect.mjs';
|
|
16
18
|
|
|
17
19
|
// Eager-dispatch: tools with readOnlyHint:true in their declaration are safe
|
|
@@ -96,6 +98,7 @@ export function viewSkill(cwd, name, session = null) {
|
|
|
96
98
|
return `Error: skill "${skillName}" needs the ${missingFeature} built-in feature, which is not installed or is switched off in Extensions → Plugin → Built-in`;
|
|
97
99
|
}
|
|
98
100
|
if (isSkillDisabled(skillName)) return `Error: skill "${skillName}" is disabled`;
|
|
101
|
+
if (skillOutsideScope(skillName, cwd)) return skillOutsideScopeError(skillName);
|
|
99
102
|
const res = loadSkillResource(skillName, cwd);
|
|
100
103
|
if (!res) return `Error: skill "${skillName}" not found`;
|
|
101
104
|
// Return the general tool envelope: the model-visible tool_result is the
|
|
@@ -12,6 +12,17 @@ import {
|
|
|
12
12
|
|
|
13
13
|
const SYNTHETIC_PROMPT_SOURCES = ['goal-continuation', 'goal-closeout'];
|
|
14
14
|
|
|
15
|
+
// A caller-declared prompt source the runtime trusts as provenance of the
|
|
16
|
+
// initial prompt: Goal turns are runtime-synthetic; a task notification (an
|
|
17
|
+
// idle-drained completion, an automation run's agent results) is stored like
|
|
18
|
+
// one the steering/queue drains inject, never as the user speaking — so none
|
|
19
|
+
// of these run explicit skill selection.
|
|
20
|
+
function initialPromptSourceFor(promptSource) {
|
|
21
|
+
if (SYNTHETIC_PROMPT_SOURCES.includes(promptSource)) return { source: promptSource, synthetic: true };
|
|
22
|
+
if (promptSource === PENDING_MODE_TASK_NOTIFICATION) return { source: promptSource };
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
15
26
|
/** Prompt provenance for a drained queue turn: the source plus its execution when one exists. */
|
|
16
27
|
const promptSourceFields = (source, execution) => {
|
|
17
28
|
if (!source) return null;
|
|
@@ -42,9 +53,7 @@ export function createAskPromptQueue({ sessionId, promptSource }) {
|
|
|
42
53
|
// Local FIFO of follow-up prompts drained from the pending-message queue
|
|
43
54
|
// after each turn — keeps queued `agent type=send` messages in order.
|
|
44
55
|
const tail = [];
|
|
45
|
-
let initialPromptSource =
|
|
46
|
-
? { source: promptSource, synthetic: true }
|
|
47
|
-
: null;
|
|
56
|
+
let initialPromptSource = initialPromptSourceFor(promptSource);
|
|
48
57
|
|
|
49
58
|
/** The next turn's input — prompt, caller context, consumed queue entries
|
|
50
59
|
* and provenance — or null when nothing model-visible is left to run. */
|
|
@@ -148,7 +148,9 @@ export async function askSession(sessionId, prompt, context, onToolCall, cwdOver
|
|
|
148
148
|
// queued send always lands AFTER the in-flight prompt here, ordering is
|
|
149
149
|
// preserved and the spawn/connecting startup race disappears.
|
|
150
150
|
for (;;) {
|
|
151
|
-
|
|
151
|
+
// `skillSelection` (askOpts) is the trusted selection input of the
|
|
152
|
+
// caller's own prompt only; drained follow-up turns never inherit it.
|
|
153
|
+
const input = queue.nextTurn({ prompt, context, explicitPrefetch, skillSelection: askOpts.skillSelection });
|
|
152
154
|
if (!input) {
|
|
153
155
|
void takeoverHydration.then((count) => {
|
|
154
156
|
if (count <= 0) return;
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
// model declares effort levels (the effort is sent with each request).
|
|
9
9
|
import { readSection } from '../../../../shared/config.mjs';
|
|
10
10
|
import { autoEffortModel, turnEffortConfigurationMode } from '../../providers/effort-configuration.mjs';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
autoEffortApplicable,
|
|
13
|
+
autoEffortBase,
|
|
14
|
+
normalizeAutoEffortMode,
|
|
15
|
+
resolveAutoEffort,
|
|
16
|
+
} from '../../providers/auto-effort.mjs';
|
|
12
17
|
import { builtinFeatureActive } from '../../runtime-core/builtin-features.mjs';
|
|
13
18
|
import { effortOptionsFor } from '../../runtime-core/effort.mjs';
|
|
14
19
|
import { effortJudgeSupportsSteps, judgeTurn, recordEffortDecision } from '../../../../effort-judge/judge-client.mjs';
|
|
@@ -78,12 +83,6 @@ export async function resolveTurnAutoEffort({ sessionId, session, provider, inpu
|
|
|
78
83
|
if (!turnEffortConfigurationMode(session, provider)) return null;
|
|
79
84
|
const chosen = String(session.effort || '').toLowerCase();
|
|
80
85
|
const base = autoEffortBase(chosen);
|
|
81
|
-
// The previous user request shows the work a short follow-up continues.
|
|
82
|
-
const judged = await judgeTurn({
|
|
83
|
-
request,
|
|
84
|
-
prev: lastText(session.messages, 'assistant'),
|
|
85
|
-
prevRequest: lastText(session.messages, 'user'),
|
|
86
|
-
});
|
|
87
86
|
const record = {
|
|
88
87
|
at: new Date().toISOString(),
|
|
89
88
|
sessionId,
|
|
@@ -94,15 +93,24 @@ export async function resolveTurnAutoEffort({ sessionId, session, provider, inpu
|
|
|
94
93
|
base,
|
|
95
94
|
requestChars: request.length,
|
|
96
95
|
};
|
|
96
|
+
const options = effortOptionsFor(session.provider, autoEffortModel(session.provider, provider, session.model));
|
|
97
|
+
// No judged outcome can apply when the base is off the model's ladder, so
|
|
98
|
+
// the judge is not asked (in observe mode too: nothing would be logged).
|
|
99
|
+
if (!autoEffortApplicable({ base, options })) {
|
|
100
|
+
recordEffortDecision({ ...record, skipped: 'default-outside-auto-range' });
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
// The previous user request shows the work a short follow-up continues.
|
|
104
|
+
const judged = await judgeTurn({
|
|
105
|
+
request,
|
|
106
|
+
prev: lastText(session.messages, 'assistant'),
|
|
107
|
+
prevRequest: lastText(session.messages, 'user'),
|
|
108
|
+
});
|
|
97
109
|
if (!judged.probs) {
|
|
98
110
|
recordEffortDecision({ ...record, skipped: judged.skipped });
|
|
99
111
|
return null;
|
|
100
112
|
}
|
|
101
|
-
const resolved = resolveAutoEffort({
|
|
102
|
-
base,
|
|
103
|
-
options: effortOptionsFor(session.provider, autoEffortModel(session.provider, provider, session.model)),
|
|
104
|
-
probs: judged.probs,
|
|
105
|
-
});
|
|
113
|
+
const resolved = resolveAutoEffort({ base, options, probs: judged.probs });
|
|
106
114
|
recordEffortDecision({
|
|
107
115
|
...record,
|
|
108
116
|
...(resolved || { skipped: 'default-outside-auto-range' }),
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// (runAskAgentLoop). Provider-not-available and trim failures throw here so
|
|
6
6
|
// the caller marks the session errored instead of leaving stage='connecting'.
|
|
7
7
|
import { getProvider } from '../../providers/registry.mjs';
|
|
8
|
-
import { prepareExplicitSkills } from '../explicit-skills.mjs';
|
|
8
|
+
import { notifySkillsApplied, prepareExplicitSkills, recordAppliedSkills } from '../explicit-skills.mjs';
|
|
9
9
|
import { prepareTurnEffortConfiguration } from '../../providers/effort-configuration.mjs';
|
|
10
10
|
import { resolveTurnAutoEffort, turnStepAutoEffort } from './ask-turn-auto-effort.mjs';
|
|
11
11
|
import { saveSessionAsync } from '../store.mjs';
|
|
@@ -151,9 +151,16 @@ export async function runAskAgentLoop({
|
|
|
151
151
|
}
|
|
152
152
|
try {
|
|
153
153
|
if (!input.promptSource) {
|
|
154
|
-
await prepareExplicitSkills(input.prompt, outgoing, session, {
|
|
154
|
+
const applied = await prepareExplicitSkills(input.prompt, outgoing, session, {
|
|
155
|
+
cwd: effectiveCwd,
|
|
156
|
+
signal: turnSignal,
|
|
157
|
+
selection: input.skillSelection,
|
|
158
|
+
});
|
|
159
|
+
// The user turn message sits right after the history it was built on.
|
|
160
|
+
const userMessage = recordAppliedSkills(outgoing, outgoing[prepared.beforeCount - 1], applied);
|
|
155
161
|
session.messages = filterModelVisibleSessionMessages(outgoing);
|
|
156
162
|
checkpoint.schedule(true);
|
|
163
|
+
notifySkillsApplied(askOpts?.onSkillsApplied, applied, userMessage);
|
|
157
164
|
}
|
|
158
165
|
return await _api_call_with_interrupt(sessionId, (signal) =>
|
|
159
166
|
agentLoop(
|
|
@@ -152,6 +152,10 @@ export function buildAgentLoopOptions({
|
|
|
152
152
|
checkpoint.schedule(true);
|
|
153
153
|
relay(askOpts?.onSteerMessage, text, detail);
|
|
154
154
|
},
|
|
155
|
+
onSkillsApplied: (names, detail) => {
|
|
156
|
+
checkpoint.schedule(true);
|
|
157
|
+
relay(askOpts?.onSkillsApplied, names, detail);
|
|
158
|
+
},
|
|
155
159
|
notifyFn: optionalFn(askOpts?.notifyFn),
|
|
156
160
|
// Same projection compaction uses, so a session presents one identity on
|
|
157
161
|
// every request it makes.
|
|
@@ -158,6 +158,14 @@ export function lateDeliveryText(text, entry, now = Date.now()) {
|
|
|
158
158
|
return `[late delivery: queued ${age} ago, before the current session owner started]\n${value}`;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
// A non-completion entry may be queued explicitly as a task notification (a
|
|
162
|
+
// runtime/channel notice, never the user typing): the mode survives
|
|
163
|
+
// normalization and the durable spool so the drain stores it as one and it
|
|
164
|
+
// never drives explicit skill selection.
|
|
165
|
+
function explicitModeField(entry) {
|
|
166
|
+
return entry?.mode === PENDING_MODE_TASK_NOTIFICATION ? { mode: PENDING_MODE_TASK_NOTIFICATION } : {};
|
|
167
|
+
}
|
|
168
|
+
|
|
161
169
|
export function normalizePendingMessageEntry(entry) {
|
|
162
170
|
if (typeof entry === 'string') {
|
|
163
171
|
const text = entry.trim();
|
|
@@ -173,7 +181,10 @@ export function normalizePendingMessageEntry(entry) {
|
|
|
173
181
|
id: pendingMessageId(entry),
|
|
174
182
|
enqueuedAt: Number(entry.enqueuedAt) || Date.now(),
|
|
175
183
|
};
|
|
176
|
-
const entryOptions =
|
|
184
|
+
const entryOptions = {
|
|
185
|
+
...(entry.options && typeof entry.options === 'object' ? { options: entry.options } : {}),
|
|
186
|
+
...explicitModeField(entry),
|
|
187
|
+
};
|
|
177
188
|
const marker =
|
|
178
189
|
entry.notificationKind === COMPLETION_NOTIFICATION_KIND
|
|
179
190
|
? {
|
|
@@ -259,26 +270,28 @@ function normalizePersistedEntryBase(entry) {
|
|
|
259
270
|
}
|
|
260
271
|
: null;
|
|
261
272
|
}
|
|
273
|
+
const mode = explicitModeField(entry);
|
|
262
274
|
if (typeof entry.message === 'string') {
|
|
263
275
|
const message = entry.message.trim();
|
|
264
|
-
return message ? { id, message, enqueuedAt } : null;
|
|
276
|
+
return message ? { id, message, ...mode, enqueuedAt } : null;
|
|
265
277
|
}
|
|
266
278
|
if (Object.hasOwn(entry, 'content')) {
|
|
267
279
|
const normalized = normalizePendingMessageEntry(entry);
|
|
268
280
|
if (!normalized) return null;
|
|
269
281
|
if (typeof normalized.content === 'string' && !normalized.options) {
|
|
270
|
-
return { id, message: normalized.text || normalized.content, enqueuedAt };
|
|
282
|
+
return { id, message: normalized.text || normalized.content, ...mode, enqueuedAt };
|
|
271
283
|
}
|
|
272
284
|
return {
|
|
273
285
|
id,
|
|
274
286
|
content: normalized.content,
|
|
275
287
|
text: normalized.text,
|
|
276
288
|
...(normalized.options ? { options: normalized.options } : {}),
|
|
289
|
+
...mode,
|
|
277
290
|
enqueuedAt,
|
|
278
291
|
};
|
|
279
292
|
}
|
|
280
293
|
const text = pendingMessageText(entry);
|
|
281
|
-
return text ? { id, message: text, enqueuedAt } : null;
|
|
294
|
+
return text ? { id, message: text, ...mode, enqueuedAt } : null;
|
|
282
295
|
}
|
|
283
296
|
|
|
284
297
|
export function modelVisiblePendingMessages(messages) {
|
|
@@ -72,7 +72,6 @@ export {
|
|
|
72
72
|
// attach-on-resume guard) — resolved through the manager facade so the
|
|
73
73
|
// session-runtime turn API reaches it as mgr.publishSessionPresence.
|
|
74
74
|
export { publishSessionPresence, deleteSessionPresence } from './store.mjs';
|
|
75
|
-
export { isInternalRuntimeNotificationText as _isInternalRuntimeNotificationText } from './manager/prompt-utils.mjs';
|
|
76
75
|
|
|
77
76
|
// ── Usage-metrics surface — re-exported unchanged so loop.mjs / smoke scripts
|
|
78
77
|
// keep resolving these through the facade. ────────────────────────────────
|
|
@@ -408,9 +408,10 @@ function adoptCompactedTranscript(ctx, run) {
|
|
|
408
408
|
// providerState so the next send starts a fresh chain.
|
|
409
409
|
ctx.providerState = undefined;
|
|
410
410
|
ctx.providerStateCleared = true;
|
|
411
|
-
// Compaction
|
|
412
|
-
//
|
|
413
|
-
//
|
|
411
|
+
// Compaction starts a new loop epoch: the iteration counter restarts at 0
|
|
412
|
+
// so iteration indices (traces, usage metrics, cross-turn dedup windows)
|
|
413
|
+
// count from the compacted transcript. The counter bounds nothing — the
|
|
414
|
+
// loop has no iteration cap.
|
|
414
415
|
ctx.iterations = 0;
|
|
415
416
|
// New loop epoch so persistIterationMetrics idempotency keys do not
|
|
416
417
|
// collide when iteration indices restart at 1 (incl. iter 1 → iter 1).
|
|
@@ -30,6 +30,7 @@ import { _saveAsyncQueued, _saveWorkerPending } from './save-worker.mjs';
|
|
|
30
30
|
import { STORED_SESSION_UNREADABLE, _ensureLifecycleFields, _storedSessionFromFile } from './serialize.mjs';
|
|
31
31
|
import { _savePending } from './pending-saves.mjs';
|
|
32
32
|
import { isOrdinarySession } from '../store-summary-visibility.mjs';
|
|
33
|
+
import { closeSessionCatalogDb } from '../catalog-db/index.mjs';
|
|
33
34
|
|
|
34
35
|
// Disk mtime of the summary index when the in-memory cache was last refreshed
|
|
35
36
|
// from it — the cross-process staleness detector.
|
|
@@ -145,8 +146,9 @@ function scheduleSessionSummaryIndexRebuild() {
|
|
|
145
146
|
|
|
146
147
|
/**
|
|
147
148
|
* Resolves once no summary-index writer of this process is running: the
|
|
148
|
-
* background rebuild worker a cold listing (or sweep) spawned has exited
|
|
149
|
-
* every queued index mutation has landed
|
|
149
|
+
* background rebuild worker a cold listing (or sweep) spawned has exited,
|
|
150
|
+
* every queued index mutation has landed and the session catalog DB is
|
|
151
|
+
* closed. Both write the index, its lock and
|
|
150
152
|
* temp files into the data dir after the listing/sweep/save that caused them
|
|
151
153
|
* has returned, so an owner that removes or switches the data dir awaits this
|
|
152
154
|
* first.
|
|
@@ -159,6 +161,8 @@ export async function settleSessionSummaryIndex() {
|
|
|
159
161
|
await new Promise((resolve) => worker.once('exit', resolve));
|
|
160
162
|
}
|
|
161
163
|
await settleSummaryIndexWrites();
|
|
164
|
+
// The daemon's session catalog DB holds its file, WAL and lock open.
|
|
165
|
+
await closeSessionCatalogDb();
|
|
162
166
|
}
|
|
163
167
|
|
|
164
168
|
export function listStoredSessionSummaries(options = {}) {
|
|
@@ -11,6 +11,9 @@ import {
|
|
|
11
11
|
_removeSessionSummary,
|
|
12
12
|
_pruneSummaryIndexIds,
|
|
13
13
|
} from '../store-summary-index.mjs';
|
|
14
|
+
// In the daemon, ids whose file a write just changed are hinted to the
|
|
15
|
+
// session catalog DB (a no-op in any other process).
|
|
16
|
+
import { hintSessionCatalogStorage } from '../catalog-db/index.mjs';
|
|
14
17
|
|
|
15
18
|
// Listing is much hotter than writing, especially while the desktop session
|
|
16
19
|
// browser is open. Keep the compact sidecar in memory after the first read;
|
|
@@ -142,16 +145,19 @@ export function _queueSessionSummaryUpsertRow(row, version = null) {
|
|
|
142
145
|
_invalidateSummaryRowsView();
|
|
143
146
|
}
|
|
144
147
|
_upsertSessionSummaryRow(durableRow);
|
|
148
|
+
hintSessionCatalogStorage([row.id]);
|
|
145
149
|
}
|
|
146
150
|
|
|
147
151
|
export function _queueSessionSummaryRemoval(id) {
|
|
148
152
|
_uncacheSessionSummary(id);
|
|
149
153
|
_removeSessionSummary(id);
|
|
154
|
+
hintSessionCatalogStorage([id]);
|
|
150
155
|
}
|
|
151
156
|
|
|
152
157
|
export function _queueSummaryIndexPrune(ids) {
|
|
153
158
|
for (const id of ids) _uncacheSessionSummary(id);
|
|
154
159
|
_pruneSummaryIndexIds(ids);
|
|
160
|
+
hintSessionCatalogStorage(ids);
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
// ── Incremental storage scan ────────────────────────────────────────────────
|