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
|
@@ -48,6 +48,13 @@ export function workspaceSummary(value) {
|
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/** Dedupe key of an imported conversation: a session's `importOrigin.key`,
|
|
52
|
+
* or a summary row's projected `importKey`; null for ordinary sessions. */
|
|
53
|
+
export function importKey(value) {
|
|
54
|
+
const key = typeof value?.importKey === 'string' ? value.importKey : value?.importOrigin?.key;
|
|
55
|
+
return typeof key === 'string' && key.trim() ? key : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
51
58
|
export function desktopSession(value, cwd = '') {
|
|
52
59
|
if (!value || typeof value !== 'object') return null;
|
|
53
60
|
if (value.classification === 'task') return { classification: 'task', projectPath: null };
|
|
@@ -15,18 +15,15 @@ import {
|
|
|
15
15
|
writeJsonAtomicAsync,
|
|
16
16
|
writeJsonAtomicSync,
|
|
17
17
|
} from '../../../shared/atomic-file.mjs';
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
encodeSummaryOps,
|
|
21
|
-
summaryLogPath,
|
|
22
|
-
} from './store-summary-log.mjs';
|
|
23
|
-
import {
|
|
24
|
-
cleanSessionPreview,
|
|
25
|
-
isSessionPreviewNoise,
|
|
26
|
-
sessionMessageText,
|
|
27
|
-
} from '../runtime-core/session-text.mjs';
|
|
18
|
+
import { applySummaryLogText, encodeSummaryOps, summaryLogPath } from './store-summary-log.mjs';
|
|
19
|
+
import { cleanSessionPreview, isSessionPreviewNoise, sessionMessageText } from '../runtime-core/session-text.mjs';
|
|
28
20
|
import { sessionVisibility } from './store-summary-visibility.mjs';
|
|
29
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
importKey,
|
|
23
|
+
isStoredSessionId,
|
|
24
|
+
positiveNumber as _positiveNumber,
|
|
25
|
+
workspaceSummary,
|
|
26
|
+
} from './store-summary-fields.mjs';
|
|
30
27
|
|
|
31
28
|
export const SESSION_SUMMARY_INDEX_VERSION = 2;
|
|
32
29
|
|
|
@@ -209,6 +206,9 @@ export function _sessionSummary(session) {
|
|
|
209
206
|
// Lifecycle provenance for catalog filters: resume-machinery scratch
|
|
210
207
|
// forks (detachedReason='cli-resume') must never surface in Recent.
|
|
211
208
|
detachedReason: session.detachedReason || null,
|
|
209
|
+
// Imported-conversation identity, so "already imported" is answered
|
|
210
|
+
// from summaries without loading sessions.
|
|
211
|
+
importKey: importKey(session),
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
214
|
|
|
@@ -257,6 +257,7 @@ function _normalizeSummaryRow(row) {
|
|
|
257
257
|
storageMtimeMs: _positiveNumber(row.storageMtimeMs, 0),
|
|
258
258
|
storageSize: _positiveNumber(row.storageSize, 0),
|
|
259
259
|
detachedReason: row.detachedReason || null,
|
|
260
|
+
importKey: importKey(row),
|
|
260
261
|
};
|
|
261
262
|
}
|
|
262
263
|
|
|
@@ -354,7 +355,9 @@ function _scheduleSummaryRetry() {
|
|
|
354
355
|
// Defer the flush off the caller's stack: file I/O has no business on the
|
|
355
356
|
// keystroke/session-save path.
|
|
356
357
|
function _scheduleSummaryFlush() {
|
|
357
|
-
|
|
358
|
+
// A scheduled retry will write whatever is pending; a flush in flight
|
|
359
|
+
// schedules one follow-up when it settles. Either way, don't start another.
|
|
360
|
+
if (_summaryFlushScheduled || _summaryRetryTimer || _summaryFlushInflight > 0) return;
|
|
358
361
|
_summaryFlushScheduled = true;
|
|
359
362
|
setImmediate(() => {
|
|
360
363
|
_summaryFlushScheduled = false;
|
|
@@ -365,6 +368,9 @@ function _scheduleSummaryFlush() {
|
|
|
365
368
|
|
|
366
369
|
export function _flushPendingSummaryOps({ sync = false } = {}) {
|
|
367
370
|
if (_pendingUpserts.size === 0 && _pendingRemovals.size === 0) return;
|
|
371
|
+
// One async flush in flight per process; ops queued meanwhile stay pending
|
|
372
|
+
// and are drained by the follow-up flush scheduled when it settles.
|
|
373
|
+
if (!sync && _summaryFlushInflight > 0) return;
|
|
368
374
|
// Snapshot + clear first: ops queued by other callers DURING the flush
|
|
369
375
|
// must not be lost, and a failed flush re-queues only what it took
|
|
370
376
|
// (without clobbering anything newer queued meanwhile).
|
|
@@ -420,6 +426,7 @@ export function _flushPendingSummaryOps({ sync = false } = {}) {
|
|
|
420
426
|
.catch(requeue)
|
|
421
427
|
.finally(() => {
|
|
422
428
|
_summaryFlushInflight--;
|
|
429
|
+
if (_pendingUpserts.size > 0 || _pendingRemovals.size > 0) _scheduleSummaryFlush();
|
|
423
430
|
_notifySummarySettled();
|
|
424
431
|
});
|
|
425
432
|
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// Shared fixture of the ordinary-catalog tests: a scratch data dir, the
|
|
2
|
+
// writers that touch it (index-updating, rename-only, in-place) and a spy on
|
|
3
|
+
// the filesystem work the cold reader does.
|
|
4
|
+
import assert from 'node:assert/strict';
|
|
5
|
+
import fs, {
|
|
6
|
+
appendFileSync,
|
|
7
|
+
mkdirSync,
|
|
8
|
+
mkdtempSync,
|
|
9
|
+
renameSync,
|
|
10
|
+
rmSync,
|
|
11
|
+
statSync,
|
|
12
|
+
unlinkSync,
|
|
13
|
+
writeFileSync,
|
|
14
|
+
} from 'node:fs';
|
|
15
|
+
import fsp from 'node:fs/promises';
|
|
16
|
+
import { syncBuiltinESMExports } from 'node:module';
|
|
17
|
+
import { tmpdir } from 'node:os';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import test from 'node:test';
|
|
20
|
+
|
|
21
|
+
import { encodeSummaryOps } from './store-summary-log.mjs';
|
|
22
|
+
import { listStoredSessionSummaries } from './store-summary-reader.mjs';
|
|
23
|
+
|
|
24
|
+
const roots = [];
|
|
25
|
+
let root = '';
|
|
26
|
+
test.after(() => {
|
|
27
|
+
for (const dir of roots) rmSync(dir, { recursive: true, force: true, maxRetries: 10, retryDelay: 50 });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
/** Point the reader at a fresh data dir with an empty sessions directory. */
|
|
31
|
+
export function useDataDir(prefix) {
|
|
32
|
+
root = mkdtempSync(join(tmpdir(), prefix));
|
|
33
|
+
roots.push(root);
|
|
34
|
+
mkdirSync(join(root, 'sessions'));
|
|
35
|
+
process.env.MIXDOG_DATA_DIR = root;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const sessionsDir = () => join(root, 'sessions');
|
|
39
|
+
export const fileOf = (id) => join(sessionsDir(), `${id}.json`);
|
|
40
|
+
export const indexPath = () => join(root, 'session-summaries.json');
|
|
41
|
+
export const logPath = () => join(root, 'session-summaries.log');
|
|
42
|
+
|
|
43
|
+
const record = (id, text) =>
|
|
44
|
+
JSON.stringify({
|
|
45
|
+
id,
|
|
46
|
+
owner: 'user',
|
|
47
|
+
agent: 'lead',
|
|
48
|
+
closed: false,
|
|
49
|
+
generation: 1,
|
|
50
|
+
updatedAt: 1,
|
|
51
|
+
messages: [{ role: 'user', content: text }],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/** The store's writers replace a record by temp file + rename. */
|
|
55
|
+
export function replace(id, text) {
|
|
56
|
+
writeFileSync(`${fileOf(id)}.tmp`, record(id, text));
|
|
57
|
+
renameSync(`${fileOf(id)}.tmp`, fileOf(id));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A writer outside the store that rewrites the record in place. */
|
|
61
|
+
export const rewriteInPlace = (id, text) => writeFileSync(fileOf(id), record(id, text));
|
|
62
|
+
|
|
63
|
+
/** What the summary index records for the file as it is now; the `indexed:`
|
|
64
|
+
* title tells an index row from a row parsed from the file. */
|
|
65
|
+
export const indexRow = (id, text, fingerprint = statSync(fileOf(id))) => ({
|
|
66
|
+
id,
|
|
67
|
+
owner: 'user',
|
|
68
|
+
agent: 'lead',
|
|
69
|
+
status: 'idle',
|
|
70
|
+
messageCount: 1,
|
|
71
|
+
title: `indexed:${text}`,
|
|
72
|
+
preview: text,
|
|
73
|
+
updatedAt: 1,
|
|
74
|
+
storageMtimeMs: fingerprint.mtimeMs,
|
|
75
|
+
storageSize: fingerprint.size,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export function writeBase(rows) {
|
|
79
|
+
writeFileSync(`${indexPath()}.tmp`, JSON.stringify({ version: 2, rows }));
|
|
80
|
+
renameSync(`${indexPath()}.tmp`, indexPath());
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const appendLog = (upserts, removals = []) => appendFileSync(logPath(), encodeSummaryOps(upserts, removals));
|
|
84
|
+
|
|
85
|
+
/** An index-updating writer: the record, then its summary row. */
|
|
86
|
+
export function saveIndexed(id, text) {
|
|
87
|
+
replace(id, text);
|
|
88
|
+
appendLog([indexRow(id, text)]);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** A namespace change that touches no session. */
|
|
92
|
+
export function touchDirectory() {
|
|
93
|
+
writeFileSync(join(sessionsDir(), 'unrelated.tmp'), '');
|
|
94
|
+
unlinkSync(join(sessionsDir(), 'unrelated.tmp'));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const list = () => listStoredSessionSummaries();
|
|
98
|
+
export const view = (rows = list()) => Object.fromEntries(rows.map((row) => [row.id, `${row.title}|${row.preview}`]));
|
|
99
|
+
|
|
100
|
+
/** The authoritative refresh parses every file, so it agrees with the
|
|
101
|
+
* ordinary catalog on which sessions exist and what they show, not on
|
|
102
|
+
* index-only titles. */
|
|
103
|
+
export function assertMatchesStorage() {
|
|
104
|
+
const previews = (rows) => Object.fromEntries(rows.map((row) => [row.id, row.preview]));
|
|
105
|
+
assert.deepEqual(previews(list()), previews(listStoredSessionSummaries({ refreshFromStorage: true })));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** A directory stamp younger than the racy window is never trusted; wait it
|
|
109
|
+
* out so the following calls exercise the stamp-keyed path. */
|
|
110
|
+
export const settle = () => new Promise((resolve) => setTimeout(resolve, 2_100));
|
|
111
|
+
|
|
112
|
+
/** Counts the filesystem work the reader does; `failing` paths throw EACCES
|
|
113
|
+
* on every call, `failingReads` paths on reads only (a stat still works). */
|
|
114
|
+
export function spyFs(t, failing = new Set(), failingReads = new Set()) {
|
|
115
|
+
const counts = { stats: 0, sessionFileStats: new Set(), readdirs: 0, reads: 0, asyncStats: 0 };
|
|
116
|
+
const original = {
|
|
117
|
+
statSync: fs.statSync,
|
|
118
|
+
readdirSync: fs.readdirSync,
|
|
119
|
+
readFileSync: fs.readFileSync,
|
|
120
|
+
stat: fsp.stat,
|
|
121
|
+
};
|
|
122
|
+
const denied = (path) => {
|
|
123
|
+
if (!failing.has(String(path))) return;
|
|
124
|
+
throw Object.assign(new Error(`EACCES: ${path}`), { code: 'EACCES' });
|
|
125
|
+
};
|
|
126
|
+
fs.statSync = function (path, ...rest) {
|
|
127
|
+
counts.stats++;
|
|
128
|
+
if (String(path).endsWith('.json') && String(path).startsWith(sessionsDir())) {
|
|
129
|
+
counts.sessionFileStats.add(String(path));
|
|
130
|
+
}
|
|
131
|
+
denied(path);
|
|
132
|
+
return original.statSync.call(this, path, ...rest);
|
|
133
|
+
};
|
|
134
|
+
fs.readdirSync = function (...args) {
|
|
135
|
+
counts.readdirs++;
|
|
136
|
+
return original.readdirSync.apply(this, args);
|
|
137
|
+
};
|
|
138
|
+
fs.readFileSync = function (path, ...rest) {
|
|
139
|
+
counts.reads++;
|
|
140
|
+
denied(path);
|
|
141
|
+
if (failingReads.has(String(path))) throw Object.assign(new Error(`EIO: ${path}`), { code: 'EIO' });
|
|
142
|
+
return original.readFileSync.call(this, path, ...rest);
|
|
143
|
+
};
|
|
144
|
+
fsp.stat = async function (path, ...rest) {
|
|
145
|
+
counts.asyncStats++;
|
|
146
|
+
denied(path);
|
|
147
|
+
return original.stat.call(this, path, ...rest);
|
|
148
|
+
};
|
|
149
|
+
syncBuiltinESMExports();
|
|
150
|
+
t.after(() => {
|
|
151
|
+
fs.statSync = original.statSync;
|
|
152
|
+
fs.readdirSync = original.readdirSync;
|
|
153
|
+
fs.readFileSync = original.readFileSync;
|
|
154
|
+
fsp.stat = original.stat;
|
|
155
|
+
syncBuiltinESMExports();
|
|
156
|
+
});
|
|
157
|
+
return counts;
|
|
158
|
+
}
|