@cortexkit/opencode-magic-context 0.26.0 → 0.27.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 +14 -12
- package/dist/agents/dreamer.d.ts +19 -0
- package/dist/agents/dreamer.d.ts.map +1 -1
- package/dist/agents/hidden-agent-registrations.d.ts +67 -0
- package/dist/agents/hidden-agent-registrations.d.ts.map +1 -0
- package/dist/agents/historian.d.ts +1 -0
- package/dist/agents/historian.d.ts.map +1 -1
- package/dist/agents/permissions.d.ts +15 -44
- package/dist/agents/permissions.d.ts.map +1 -1
- package/dist/agents/smart-note-compiler.d.ts +2 -0
- package/dist/agents/smart-note-compiler.d.ts.map +1 -0
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/migrate-config-location.d.ts +89 -0
- package/dist/config/migrate-config-location.d.ts.map +1 -0
- package/dist/config/migrate-dreamer-v2.d.ts +37 -0
- package/dist/config/migrate-dreamer-v2.d.ts.map +1 -0
- package/dist/config/migrate-experimental.d.ts.map +1 -1
- package/dist/config/project-security.d.ts +3 -0
- package/dist/config/project-security.d.ts.map +1 -1
- package/dist/config/prune-config-leaf.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +584 -60
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/magic-context/compaction-marker.d.ts +9 -3
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts +1 -1
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/classify-prompt.d.ts +50 -0
- package/dist/features/magic-context/dreamer/classify-prompt.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/classify.d.ts +22 -0
- package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/cron.d.ts +72 -0
- package/dist/features/magic-context/dreamer/cron.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +30 -0
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/index.d.ts +1 -3
- package/dist/features/magic-context/dreamer/index.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/lease.d.ts +44 -6
- package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/maintain-docs-protected-enforcement.d.ts +13 -0
- package/dist/features/magic-context/dreamer/maintain-docs-protected-enforcement.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts +36 -0
- package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/map-memories.d.ts +22 -0
- package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/open-opencode-db.d.ts +7 -0
- package/dist/features/magic-context/dreamer/open-opencode-db.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/primer-seed.d.ts +25 -0
- package/dist/features/magic-context/dreamer/primer-seed.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/promote-primers.d.ts +21 -0
- package/dist/features/magic-context/dreamer/promote-primers.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/protected-regions.d.ts +19 -0
- package/dist/features/magic-context/dreamer/protected-regions.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/refresh-primers.d.ts +30 -0
- package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/retrospective-learnings.d.ts +47 -0
- package/dist/features/magic-context/dreamer/retrospective-learnings.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts +48 -0
- package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts +81 -0
- package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +8 -0
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts +82 -0
- package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/task-config.d.ts +28 -0
- package/dist/features/magic-context/dreamer/task-config.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/task-executor.d.ts +49 -0
- package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/task-gates.d.ts +29 -0
- package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/task-prompts.d.ts +37 -6
- package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-registry.d.ts +48 -0
- package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts +88 -0
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/verify-gate.d.ts +43 -0
- package/dist/features/magic-context/dreamer/verify-gate.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/verify-prompt.d.ts +41 -0
- package/dist/features/magic-context/dreamer/verify-prompt.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/verify.d.ts +43 -0
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/search-git-commits.d.ts +2 -0
- package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +4 -4
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/index.d.ts +1 -0
- package/dist/features/magic-context/index.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-cache.d.ts +2 -2
- package/dist/features/magic-context/memory/embedding-cache.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-openai.d.ts +12 -5
- package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts +2 -2
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/index.d.ts +4 -1
- package/dist/features/magic-context/memory/index.d.ts.map +1 -1
- package/dist/features/magic-context/memory/memory-migration.d.ts +1 -0
- package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
- package/dist/features/magic-context/memory/promotion.d.ts +16 -4
- package/dist/features/magic-context/memory/promotion.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +2 -2
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-verifications.d.ts +31 -0
- package/dist/features/magic-context/memory/storage-memory-verifications.d.ts.map +1 -0
- package/dist/features/magic-context/memory/storage-memory.d.ts +12 -1
- package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
- package/dist/features/magic-context/memory/types.d.ts +4 -0
- package/dist/features/magic-context/memory/types.d.ts.map +1 -1
- package/dist/features/magic-context/memory/verification-paths.d.ts +32 -0
- package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -0
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
- package/dist/features/magic-context/primer-clustering.d.ts +29 -0
- package/dist/features/magic-context/primer-clustering.d.ts.map +1 -0
- package/dist/features/magic-context/project-embedding-registry.d.ts +25 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/search.d.ts +12 -2
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/capabilities.d.ts +31 -0
- package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/compiler-prompt.d.ts +2 -0
- package/dist/features/magic-context/smart-notes/compiler-prompt.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/compiler.d.ts +52 -0
- package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/index.d.ts +10 -0
- package/dist/features/magic-context/smart-notes/index.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/runner.d.ts +18 -0
- package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts +22 -0
- package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/schedule.d.ts +9 -0
- package/dist/features/magic-context/smart-notes/schedule.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts +49 -0
- package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/storage.d.ts +27 -0
- package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/types.d.ts +63 -0
- package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -0
- package/dist/features/magic-context/storage-db.d.ts +5 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +8 -4
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +3 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
- package/dist/features/magic-context/storage-notes.d.ts +15 -0
- package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
- package/dist/features/magic-context/storage-primers.d.ts +85 -0
- package/dist/features/magic-context/storage-primers.d.ts.map +1 -0
- package/dist/features/magic-context/storage-tags.d.ts +20 -0
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +2 -1
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/tagger.d.ts +6 -0
- package/dist/features/magic-context/tagger.d.ts.map +1 -1
- package/dist/features/magic-context/tool-owner-backfill.d.ts.map +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts +10 -0
- package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
- package/dist/features/magic-context/types.d.ts +2 -0
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts +5 -0
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +18 -0
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
- package/dist/features/magic-context/v22-deferred-backfill.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/semver.d.ts +9 -0
- package/dist/hooks/auto-update-checker/semver.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +8 -15
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-parser.d.ts +9 -0
- package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-prompt.d.ts +4 -1
- package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts +1 -0
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +8 -0
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-prompt.generated.d.ts +1 -1
- package/dist/hooks/magic-context/historian-prompt.generated.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-state-file.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts +2 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +1 -0
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +0 -3
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/send-session-notification.d.ts +2 -0
- package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +17 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +8 -5
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +0 -2
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17034 -4059
- package/dist/plugin/dream-timer.d.ts +17 -9
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/embedding-bootstrap-helpers.d.ts +1 -1
- package/dist/plugin/embedding-bootstrap-helpers.d.ts.map +1 -1
- package/dist/plugin/embedding-bootstrap.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +211 -0
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/instance-disposal.d.ts +2 -0
- package/dist/plugin/instance-disposal.d.ts.map +1 -0
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/shared/announcement.d.ts +1 -1
- package/dist/shared/announcement.d.ts.map +1 -1
- package/dist/shared/data-path.d.ts +26 -7
- package/dist/shared/data-path.d.ts.map +1 -1
- package/dist/shared/model-suggestion-retry.d.ts +48 -2
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/redaction.d.ts +7 -0
- package/dist/shared/redaction.d.ts.map +1 -0
- package/dist/shared/resolve-fallbacks.d.ts +12 -0
- package/dist/shared/resolve-fallbacks.d.ts.map +1 -1
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/rpc-types.d.ts +2 -0
- package/dist/shared/rpc-types.d.ts.map +1 -1
- package/dist/shared/subagent-runner.d.ts +12 -3
- package/dist/shared/subagent-runner.d.ts.map +1 -1
- package/dist/shared/tui-config.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-memory/types.d.ts.map +1 -1
- package/dist/tools/ctx-memory/verification-recording.d.ts +8 -0
- package/dist/tools/ctx-memory/verification-recording.d.ts.map +1 -0
- package/dist/tools/ctx-search/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/types.d.ts +1 -1
- package/dist/tools/ctx-search/types.d.ts.map +1 -1
- package/dist/tui/data/context-db.d.ts +2 -0
- package/dist/tui/data/context-db.d.ts.map +1 -1
- package/package.json +3 -1
- package/src/shared/announcement.test.ts +20 -0
- package/src/shared/announcement.ts +19 -7
- package/src/shared/data-path.test.ts +70 -6
- package/src/shared/data-path.ts +50 -8
- package/src/shared/model-suggestion-retry.test.ts +79 -2
- package/src/shared/model-suggestion-retry.ts +181 -3
- package/src/shared/redaction.test.ts +84 -0
- package/src/shared/redaction.ts +264 -0
- package/src/shared/resolve-fallbacks.ts +14 -0
- package/src/shared/rpc-server.ts +24 -0
- package/src/shared/rpc-types.ts +2 -0
- package/src/shared/subagent-runner.ts +12 -3
- package/src/shared/tui-config.test.ts +63 -0
- package/src/shared/tui-config.ts +67 -39
- package/src/tui/data/context-db.ts +12 -0
- package/src/tui/index.tsx +87 -17
- package/src/tui/slots/sidebar-content.tsx +4 -0
- package/dist/features/magic-context/dreamer/queue.d.ts +0 -55
- package/dist/features/magic-context/dreamer/queue.d.ts.map +0 -1
- package/dist/features/magic-context/dreamer/runner.d.ts +0 -92
- package/dist/features/magic-context/dreamer/runner.d.ts.map +0 -1
- package/dist/features/magic-context/dreamer/scheduler.d.ts +0 -29
- package/dist/features/magic-context/dreamer/scheduler.d.ts.map +0 -1
- package/dist/features/magic-context/key-files/aft-availability.d.ts +0 -11
- package/dist/features/magic-context/key-files/aft-availability.d.ts.map +0 -1
- package/dist/features/magic-context/key-files/identify-key-files.d.ts +0 -84
- package/dist/features/magic-context/key-files/identify-key-files.d.ts.map +0 -1
- package/dist/features/magic-context/key-files/project-key-files.d.ts +0 -42
- package/dist/features/magic-context/key-files/project-key-files.d.ts.map +0 -1
- package/dist/features/magic-context/key-files/read-history.d.ts +0 -26
- package/dist/features/magic-context/key-files/read-history.d.ts.map +0 -1
- package/dist/features/magic-context/key-files/read-stats.d.ts +0 -18
- package/dist/features/magic-context/key-files/read-stats.d.ts.map +0 -1
- package/dist/features/magic-context/key-files/storage-key-files.d.ts +0 -20
- package/dist/features/magic-context/key-files/storage-key-files.d.ts.map +0 -1
- package/dist/hooks/magic-context/key-files-block.d.ts +0 -27
- package/dist/hooks/magic-context/key-files-block.d.ts.map +0 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from "bun:test";
|
|
2
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
const roots: string[] = [];
|
|
7
|
+
const prevConfigDir = process.env.OPENCODE_CONFIG_DIR;
|
|
8
|
+
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
if (prevConfigDir === undefined) delete process.env.OPENCODE_CONFIG_DIR;
|
|
11
|
+
else process.env.OPENCODE_CONFIG_DIR = prevConfigDir;
|
|
12
|
+
for (const root of roots.splice(0)) {
|
|
13
|
+
rmSync(root, { recursive: true, force: true });
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe("ensureTuiPluginEntry", () => {
|
|
18
|
+
it("preserves tuple dev-path plugin entry and does not add @latest", async () => {
|
|
19
|
+
const root = mkdtempSync(join(tmpdir(), "mc-tui-"));
|
|
20
|
+
roots.push(root);
|
|
21
|
+
process.env.OPENCODE_CONFIG_DIR = root;
|
|
22
|
+
const devPath = "/Work/magic-context/packages/plugin";
|
|
23
|
+
const tuiPath = join(root, "tui.json");
|
|
24
|
+
writeFileSync(
|
|
25
|
+
tuiPath,
|
|
26
|
+
`${JSON.stringify({ plugin: [[devPath, { sidebar: true }], "other-plugin"] }, null, 2)}\n`,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const { ensureTuiPluginEntry } = await import("./tui-config");
|
|
30
|
+
const changed = ensureTuiPluginEntry();
|
|
31
|
+
expect(changed).toBe(false);
|
|
32
|
+
const parsed = JSON.parse(readFileSync(tuiPath, "utf-8")) as { plugin: unknown[] };
|
|
33
|
+
expect(parsed.plugin).toHaveLength(2);
|
|
34
|
+
expect(Array.isArray(parsed.plugin[0])).toBe(true);
|
|
35
|
+
expect((parsed.plugin[0] as unknown[])[0]).toBe(devPath);
|
|
36
|
+
expect(parsed.plugin[1]).toBe("other-plugin");
|
|
37
|
+
expect(existsSync(`${tuiPath}.tmp`)).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("upgrades bare npm name to @latest while preserving tuple options", async () => {
|
|
41
|
+
const root = mkdtempSync(join(tmpdir(), "mc-tui-npm-"));
|
|
42
|
+
roots.push(root);
|
|
43
|
+
process.env.OPENCODE_CONFIG_DIR = root;
|
|
44
|
+
const tuiPath = join(root, "tui.json");
|
|
45
|
+
writeFileSync(
|
|
46
|
+
tuiPath,
|
|
47
|
+
`${JSON.stringify(
|
|
48
|
+
{
|
|
49
|
+
plugin: [["@cortexkit/opencode-magic-context", { enabled: true }]],
|
|
50
|
+
},
|
|
51
|
+
null,
|
|
52
|
+
2,
|
|
53
|
+
)}\n`,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const { ensureTuiPluginEntry } = await import("./tui-config");
|
|
57
|
+
expect(ensureTuiPluginEntry()).toBe(true);
|
|
58
|
+
const parsed = JSON.parse(readFileSync(tuiPath, "utf-8")) as { plugin: unknown[] };
|
|
59
|
+
const entry = parsed.plugin[0] as unknown[];
|
|
60
|
+
expect(entry[0]).toBe("@cortexkit/opencode-magic-context@latest");
|
|
61
|
+
expect(entry[1]).toEqual({ enabled: true });
|
|
62
|
+
});
|
|
63
|
+
});
|
package/src/shared/tui-config.ts
CHANGED
|
@@ -3,7 +3,15 @@
|
|
|
3
3
|
* Called from the server plugin at startup so the TUI sidebar loads on next restart.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
chmodSync,
|
|
8
|
+
existsSync,
|
|
9
|
+
mkdirSync,
|
|
10
|
+
readFileSync,
|
|
11
|
+
renameSync,
|
|
12
|
+
statSync,
|
|
13
|
+
writeFileSync,
|
|
14
|
+
} from "node:fs";
|
|
7
15
|
import { dirname, join } from "node:path";
|
|
8
16
|
import { parse, stringify } from "comment-json";
|
|
9
17
|
import { log } from "./logger";
|
|
@@ -12,27 +20,41 @@ import { getOpenCodeConfigPaths } from "./opencode-config-dir";
|
|
|
12
20
|
const PLUGIN_NAME = "@cortexkit/opencode-magic-context";
|
|
13
21
|
const PLUGIN_ENTRY = `${PLUGIN_NAME}@latest`;
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
return
|
|
23
|
+
function pluginEntryId(entry: unknown): string {
|
|
24
|
+
if (typeof entry === "string") return entry;
|
|
25
|
+
if (Array.isArray(entry) && typeof entry[0] === "string") return entry[0];
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isLocalMagicContextDevEntry(entry: unknown): boolean {
|
|
30
|
+
const id = pluginEntryId(entry);
|
|
31
|
+
if (!id) return false;
|
|
32
|
+
if (id === PLUGIN_NAME || id.startsWith(`${PLUGIN_NAME}@`)) return false;
|
|
33
|
+
const isPath =
|
|
34
|
+
id.startsWith("file://") || id.startsWith("/") || id.startsWith("./") || id.includes("\\");
|
|
35
|
+
if (!isPath) return false;
|
|
36
|
+
return id.includes("opencode-magic-context") || id.includes("magic-context");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isMagicContextPluginEntry(entry: unknown): boolean {
|
|
40
|
+
const id = pluginEntryId(entry);
|
|
41
|
+
if (!id) return false;
|
|
42
|
+
if (id === PLUGIN_NAME || id.startsWith(`${PLUGIN_NAME}@`)) return true;
|
|
43
|
+
return isLocalMagicContextDevEntry(entry);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function writeTuiConfigAtomic(configPath: string, config: Record<string, unknown>): void {
|
|
47
|
+
const body = `${stringify(config, null, 2)}\n`;
|
|
48
|
+
const tmpPath = `${configPath}.tmp`;
|
|
49
|
+
writeFileSync(tmpPath, body);
|
|
50
|
+
try {
|
|
51
|
+
if (statSync(configPath, { throwIfNoEntry: false })?.isFile()) {
|
|
52
|
+
chmodSync(tmpPath, statSync(configPath).mode & 0o777);
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
/* new file */
|
|
56
|
+
}
|
|
57
|
+
renameSync(tmpPath, configPath);
|
|
36
58
|
}
|
|
37
59
|
|
|
38
60
|
function resolveTuiConfigPath(): string {
|
|
@@ -59,35 +81,41 @@ export function ensureTuiPluginEntry(): boolean {
|
|
|
59
81
|
config = (parse(raw) as Record<string, unknown>) ?? {};
|
|
60
82
|
}
|
|
61
83
|
|
|
62
|
-
const plugins = Array.isArray(config.plugin)
|
|
63
|
-
? config.plugin.filter((p): p is string => typeof p === "string")
|
|
64
|
-
: [];
|
|
84
|
+
const plugins: unknown[] = Array.isArray(config.plugin) ? [...config.plugin] : [];
|
|
65
85
|
|
|
66
|
-
const existingIdx = plugins.findIndex(
|
|
86
|
+
const existingIdx = plugins.findIndex(isMagicContextPluginEntry);
|
|
67
87
|
if (existingIdx >= 0) {
|
|
68
88
|
const existing = plugins[existingIdx];
|
|
69
|
-
if (existing
|
|
70
|
-
return false;
|
|
89
|
+
if (isLocalMagicContextDevEntry(existing)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
const id = pluginEntryId(existing);
|
|
93
|
+
if (id === PLUGIN_ENTRY) {
|
|
94
|
+
return false;
|
|
71
95
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
plugins[existingIdx] = PLUGIN_ENTRY;
|
|
96
|
+
if (id === PLUGIN_NAME) {
|
|
97
|
+
if (Array.isArray(existing) && existing.length >= 1) {
|
|
98
|
+
const replacement = [...existing];
|
|
99
|
+
replacement[0] = PLUGIN_ENTRY;
|
|
100
|
+
plugins[existingIdx] = replacement;
|
|
101
|
+
} else {
|
|
102
|
+
plugins[existingIdx] = PLUGIN_ENTRY;
|
|
103
|
+
}
|
|
81
104
|
} else {
|
|
82
105
|
return false;
|
|
83
106
|
}
|
|
84
107
|
} else {
|
|
85
|
-
plugins.
|
|
108
|
+
const hasDev = plugins.some(isLocalMagicContextDevEntry);
|
|
109
|
+
if (!hasDev) {
|
|
110
|
+
plugins.push(PLUGIN_ENTRY);
|
|
111
|
+
} else {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
86
114
|
}
|
|
87
115
|
config.plugin = plugins;
|
|
88
116
|
|
|
89
117
|
mkdirSync(dirname(configPath), { recursive: true });
|
|
90
|
-
|
|
118
|
+
writeTuiConfigAtomic(configPath, config);
|
|
91
119
|
log(`[magic-context] updated TUI plugin entry in ${configPath}`);
|
|
92
120
|
return true;
|
|
93
121
|
} catch (error) {
|
|
@@ -205,6 +205,7 @@ export async function loadStatusDetail(
|
|
|
205
205
|
historyBlockTokens: 0,
|
|
206
206
|
compressionBudget: null,
|
|
207
207
|
compressionUsage: null,
|
|
208
|
+
toastDurationMs: 5000,
|
|
208
209
|
};
|
|
209
210
|
|
|
210
211
|
if (!rpcClient) return emptyDetail;
|
|
@@ -299,6 +300,17 @@ export async function dismissUpgradeReminder(sessionId: string): Promise<boolean
|
|
|
299
300
|
}
|
|
300
301
|
}
|
|
301
302
|
|
|
303
|
+
/** Resolve global toast duration from server config via RPC. */
|
|
304
|
+
export async function loadToastDurationMs(): Promise<number> {
|
|
305
|
+
if (!rpcClient) return 5000;
|
|
306
|
+
try {
|
|
307
|
+
const result = await rpcClient.call<{ toastDurationMs?: number }>("toast-duration", {});
|
|
308
|
+
return typeof result.toastDurationMs === "number" ? result.toastDurationMs : 5000;
|
|
309
|
+
} catch {
|
|
310
|
+
return 5000;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
302
314
|
export interface TuiMessage {
|
|
303
315
|
id: number;
|
|
304
316
|
type: string;
|
package/src/tui/index.tsx
CHANGED
|
@@ -6,7 +6,7 @@ import { createMemo } from "solid-js"
|
|
|
6
6
|
import type { TuiPlugin, TuiPluginApi, TuiThemeCurrent } from "@opencode-ai/plugin/tui"
|
|
7
7
|
import { createSidebarContentSlot, kickRecompProgressRefresh } from "./slots/sidebar-content"
|
|
8
8
|
import packageJson from "../../package.json"
|
|
9
|
-
import { closeRpc, consumeTuiMessages, dismissUpgradeReminder, getAnnouncement, getCompartmentCount, getRpcGeneration, initRpcClient, loadEmbedDetail, loadStatusDetail, markAnnounced, markTuiMessagesHandled, requestRecomp, requestUpgrade, type EmbedDetail, type TuiMessage, type StatusDetail } from "./data/context-db"
|
|
9
|
+
import { closeRpc, consumeTuiMessages, dismissUpgradeReminder, getAnnouncement, getCompartmentCount, getRpcGeneration, initRpcClient, loadEmbedDetail, loadStatusDetail, loadToastDurationMs, markAnnounced, markTuiMessagesHandled, requestRecomp, requestUpgrade, type EmbedDetail, type TuiMessage, type StatusDetail } from "./data/context-db"
|
|
10
10
|
import { formatThresholdPercent } from "../shared/format-threshold"
|
|
11
11
|
import { detectConflicts } from "../shared/conflict-detector"
|
|
12
12
|
import { fixConflicts } from "../shared/conflict-fixer"
|
|
@@ -14,6 +14,48 @@ import { readJsoncFile } from "../shared/jsonc-parser"
|
|
|
14
14
|
import { getOpenCodeConfigPaths } from "../shared/opencode-config-dir"
|
|
15
15
|
|
|
16
16
|
const PLUGIN_NAME = "@cortexkit/opencode-magic-context"
|
|
17
|
+
const DEFAULT_TOAST_DURATION_MS = 5000
|
|
18
|
+
let unifiedToastDurationMs = DEFAULT_TOAST_DURATION_MS
|
|
19
|
+
|
|
20
|
+
async function refreshToastDurationMs(): Promise<void> {
|
|
21
|
+
try {
|
|
22
|
+
const resolved = await loadToastDurationMs()
|
|
23
|
+
if (typeof resolved === "number" && Number.isFinite(resolved)) {
|
|
24
|
+
unifiedToastDurationMs = resolved
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
// Keep the current value; the next poll/startup can retry.
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getToastDurationMs(): number {
|
|
32
|
+
return unifiedToastDurationMs
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function showToast(
|
|
36
|
+
api: TuiPluginApi,
|
|
37
|
+
input: {
|
|
38
|
+
message: string
|
|
39
|
+
variant: "info" | "warning" | "error" | "success"
|
|
40
|
+
durationOverrideMs?: number
|
|
41
|
+
},
|
|
42
|
+
): void {
|
|
43
|
+
const duration =
|
|
44
|
+
typeof input.durationOverrideMs === "number" && Number.isFinite(input.durationOverrideMs)
|
|
45
|
+
? input.durationOverrideMs
|
|
46
|
+
: getToastDurationMs()
|
|
47
|
+
// toast_duration_ms = 0 disables Magic Context toasts entirely. An explicit
|
|
48
|
+
// positive per-call override (e.g. restart-required) still shows; only a
|
|
49
|
+
// non-positive effective duration suppresses the toast.
|
|
50
|
+
if (!(duration > 0)) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
api.ui.toast({
|
|
54
|
+
message: input.message,
|
|
55
|
+
variant: input.variant,
|
|
56
|
+
duration,
|
|
57
|
+
})
|
|
58
|
+
}
|
|
17
59
|
|
|
18
60
|
function ensureParentDir(filePath: string) {
|
|
19
61
|
mkdirSync(dirname(filePath), { recursive: true })
|
|
@@ -97,14 +139,18 @@ function showConflictDialog(api: TuiPluginApi, directory: string, reasons: strin
|
|
|
97
139
|
title="✅ Configuration Fixed"
|
|
98
140
|
message={`${actionSummary}\n\nPlease restart OpenCode for changes to take effect.`}
|
|
99
141
|
onConfirm={() => {
|
|
100
|
-
api
|
|
142
|
+
showToast(api, {
|
|
143
|
+
message: "Restart OpenCode to enable Magic Context",
|
|
144
|
+
variant: "warning",
|
|
145
|
+
durationOverrideMs: 10_000,
|
|
146
|
+
})
|
|
101
147
|
}}
|
|
102
148
|
/>
|
|
103
149
|
))
|
|
104
150
|
}, 50)
|
|
105
151
|
}}
|
|
106
152
|
onCancel={() => {
|
|
107
|
-
api
|
|
153
|
+
showToast(api, { message: "Magic Context remains disabled. Run: npx @cortexkit/opencode-magic-context@latest doctor", variant: "warning" })
|
|
108
154
|
}}
|
|
109
155
|
/>
|
|
110
156
|
))
|
|
@@ -132,7 +178,7 @@ function showTuiSetupDialog(api: TuiPluginApi) {
|
|
|
132
178
|
title="❌ Setup Failed"
|
|
133
179
|
message={'Could not update tui.json automatically. Add the plugin manually:\n\n { "plugin": ["@cortexkit/opencode-magic-context"] }'}
|
|
134
180
|
onConfirm={() => {
|
|
135
|
-
api
|
|
181
|
+
showToast(api, { message: "Add plugin to tui.json manually", variant: "warning" })
|
|
136
182
|
}}
|
|
137
183
|
/>
|
|
138
184
|
))
|
|
@@ -146,14 +192,18 @@ function showTuiSetupDialog(api: TuiPluginApi) {
|
|
|
146
192
|
title="✅ Sidebar Enabled"
|
|
147
193
|
message="tui.json updated with Magic Context plugin.\n\nPlease restart OpenCode to see the sidebar."
|
|
148
194
|
onConfirm={() => {
|
|
149
|
-
api
|
|
195
|
+
showToast(api, {
|
|
196
|
+
message: "Restart OpenCode to see the sidebar",
|
|
197
|
+
variant: "warning",
|
|
198
|
+
durationOverrideMs: 10_000,
|
|
199
|
+
})
|
|
150
200
|
}}
|
|
151
201
|
/>
|
|
152
202
|
))
|
|
153
203
|
}, 50)
|
|
154
204
|
}}
|
|
155
205
|
onCancel={() => {
|
|
156
|
-
api
|
|
206
|
+
showToast(api, { message: "You can add the sidebar later via: npx @cortexkit/opencode-magic-context@latest doctor", variant: "info" })
|
|
157
207
|
}}
|
|
158
208
|
/>
|
|
159
209
|
))
|
|
@@ -203,8 +253,16 @@ const StatusDialog = (props: { api: TuiPluginApi; s: StatusDetail }) => {
|
|
|
203
253
|
const t = () => theme()
|
|
204
254
|
const s = () => props.s
|
|
205
255
|
|
|
256
|
+
// Prefer the RPC-provided model context limit (what the sidebar shows) so the
|
|
257
|
+
// two surfaces never disagree. Fall back to deriving from usage% only when the
|
|
258
|
+
// RPC limit is absent (0) — and that derivation is itself undefined at 0%, so
|
|
259
|
+
// it stays "?" rather than showing a number inconsistent with the sidebar.
|
|
206
260
|
const contextLimit = () =>
|
|
207
|
-
s().
|
|
261
|
+
s().contextLimit > 0
|
|
262
|
+
? s().contextLimit
|
|
263
|
+
: s().usagePercentage > 0
|
|
264
|
+
? Math.round(s().inputTokens / (s().usagePercentage / 100))
|
|
265
|
+
: 0
|
|
208
266
|
|
|
209
267
|
const elapsed = () => (s().lastResponseTime > 0 ? Date.now() - s().lastResponseTime : 0)
|
|
210
268
|
|
|
@@ -450,7 +508,7 @@ function getModelKeyFromMessages(api: TuiPluginApi, sessionId: string): string |
|
|
|
450
508
|
async function showRecompDialog(api: TuiPluginApi, targetSessionId = getSessionId(api)): Promise<boolean> {
|
|
451
509
|
const sessionId = targetSessionId
|
|
452
510
|
if (!sessionId) {
|
|
453
|
-
api
|
|
511
|
+
showToast(api, { message: "No active session", variant: "warning" })
|
|
454
512
|
return false
|
|
455
513
|
}
|
|
456
514
|
|
|
@@ -475,10 +533,10 @@ async function showRecompDialog(api: TuiPluginApi, targetSessionId = getSessionI
|
|
|
475
533
|
onConfirm={() => {
|
|
476
534
|
void requestRecomp(sessionId)
|
|
477
535
|
kickRecompProgressRefresh()
|
|
478
|
-
api
|
|
536
|
+
showToast(api, { message: "Recomp requested — historian will start shortly", variant: "info" })
|
|
479
537
|
}}
|
|
480
538
|
onCancel={() => {
|
|
481
|
-
api
|
|
539
|
+
showToast(api, { message: "Recomp cancelled", variant: "info", durationOverrideMs: 3000 })
|
|
482
540
|
}}
|
|
483
541
|
/>
|
|
484
542
|
))
|
|
@@ -535,12 +593,11 @@ function showUpgradeDialog(
|
|
|
535
593
|
// call fires no message event, so without this the progress
|
|
536
594
|
// bar wouldn't appear until the upgrade finished.
|
|
537
595
|
kickRecompProgressRefresh()
|
|
538
|
-
api
|
|
596
|
+
showToast(api, {
|
|
539
597
|
message: resume
|
|
540
598
|
? "Resuming session upgrade — running in the background"
|
|
541
599
|
: "Session upgrade started — running in the background",
|
|
542
600
|
variant: "info",
|
|
543
|
-
duration: 5000,
|
|
544
601
|
})
|
|
545
602
|
// Dismiss the durable reminder ONLY after the upgrade request
|
|
546
603
|
// actually started. If requestUpgrade() returns false (RPC /
|
|
@@ -558,10 +615,10 @@ function showUpgradeDialog(
|
|
|
558
615
|
// never-upgraded session (dogfood 2026-05-30) relies on THIS
|
|
559
616
|
// being the only place the TUI path stamps.
|
|
560
617
|
void dismissUpgradeReminder(sessionId)
|
|
561
|
-
api
|
|
618
|
+
showToast(api, {
|
|
562
619
|
message: "Upgrade skipped — run /ctx-session-upgrade anytime",
|
|
563
620
|
variant: "info",
|
|
564
|
-
|
|
621
|
+
durationOverrideMs: 4000,
|
|
565
622
|
})
|
|
566
623
|
}}
|
|
567
624
|
/>
|
|
@@ -573,7 +630,7 @@ function showUpgradeDialog(
|
|
|
573
630
|
async function showStatusDialog(api: TuiPluginApi, targetSessionId = getSessionId(api)): Promise<boolean> {
|
|
574
631
|
const sessionId = targetSessionId
|
|
575
632
|
if (!sessionId) {
|
|
576
|
-
api
|
|
633
|
+
showToast(api, { message: "No active session", variant: "warning" })
|
|
577
634
|
return false
|
|
578
635
|
}
|
|
579
636
|
|
|
@@ -793,6 +850,7 @@ const tui: TuiPlugin = async (api, _options, meta) => {
|
|
|
793
850
|
// Initialize RPC client for server communication
|
|
794
851
|
const directory = api.state.path.directory ?? ""
|
|
795
852
|
initRpcClient(directory)
|
|
853
|
+
await refreshToastDurationMs()
|
|
796
854
|
|
|
797
855
|
// Register sidebar slot
|
|
798
856
|
api.slots.register(createSidebarContentSlot(api))
|
|
@@ -830,6 +888,9 @@ const tui: TuiPlugin = async (api, _options, meta) => {
|
|
|
830
888
|
pollInFlight = true
|
|
831
889
|
const pollGeneration = getRpcGeneration()
|
|
832
890
|
void consumeTuiMessages(requestedSessionId).then(async (messages) => {
|
|
891
|
+
if (unifiedToastDurationMs === DEFAULT_TOAST_DURATION_MS) {
|
|
892
|
+
void refreshToastDurationMs()
|
|
893
|
+
}
|
|
833
894
|
// The dialog handlers read the current session when they run. If the
|
|
834
895
|
// user switched routes while the RPC was in flight, drop this whole
|
|
835
896
|
// batch without advancing the cursor; the next poll for the new
|
|
@@ -843,6 +904,12 @@ const tui: TuiPlugin = async (api, _options, meta) => {
|
|
|
843
904
|
const orderedMessages = [...messages].sort((a, b) => a.id - b.id)
|
|
844
905
|
const handledMessageIds = new Set<number>()
|
|
845
906
|
for (const msg of orderedMessages) {
|
|
907
|
+
// A dialog helper earlier in this batch may have awaited; re-check
|
|
908
|
+
// the route before EACH message so a later action/toast in the same
|
|
909
|
+
// batch can't paint into a session the user switched to mid-batch
|
|
910
|
+
// (the pre-batch + pre-ack guards alone don't cover mid-batch awaits).
|
|
911
|
+
if (getRpcGeneration() !== pollGeneration) return
|
|
912
|
+
if (getSessionId(api) !== requestedSessionId) return
|
|
846
913
|
// Drop any action/dialog whose sessionId doesn't match this TUI's
|
|
847
914
|
// active session (session-less/global notifications still apply).
|
|
848
915
|
if (
|
|
@@ -854,10 +921,13 @@ const tui: TuiPlugin = async (api, _options, meta) => {
|
|
|
854
921
|
}
|
|
855
922
|
if (msg.type === "toast") {
|
|
856
923
|
const p = msg.payload
|
|
857
|
-
api
|
|
924
|
+
showToast(api, {
|
|
858
925
|
message: String(p.message ?? ""),
|
|
859
926
|
variant: (p.variant as "info" | "warning" | "error" | "success") ?? "info",
|
|
860
|
-
|
|
927
|
+
durationOverrideMs:
|
|
928
|
+
typeof p.duration === "number" && Number.isFinite(p.duration)
|
|
929
|
+
? p.duration
|
|
930
|
+
: undefined,
|
|
861
931
|
})
|
|
862
932
|
handledMessageIds.add(msg.id)
|
|
863
933
|
} else if (msg.type === "action") {
|
|
@@ -503,6 +503,10 @@ const SidebarContent = (props: {
|
|
|
503
503
|
const directory = props.api.state.path.directory ?? ""
|
|
504
504
|
void loadSidebarSnapshot(sid, directory)
|
|
505
505
|
.then((data) => {
|
|
506
|
+
// Guard against a session switch while this load was in flight:
|
|
507
|
+
// painting session A's snapshot into the now-active session B shows
|
|
508
|
+
// the wrong session's numbers until B's own refresh resolves.
|
|
509
|
+
if (props.sessionID() !== sid) return
|
|
506
510
|
setSnapshot(data)
|
|
507
511
|
try {
|
|
508
512
|
props.api.renderer.requestRender()
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { Database } from "../../../shared/sqlite";
|
|
2
|
-
export interface DreamQueueEntry {
|
|
3
|
-
id: number;
|
|
4
|
-
/** Project identity (e.g. "git:<sha>"), NOT a filesystem path */
|
|
5
|
-
projectIdentity: string;
|
|
6
|
-
reason: string;
|
|
7
|
-
enqueuedAt: number;
|
|
8
|
-
startedAt: number | null;
|
|
9
|
-
}
|
|
10
|
-
export declare function ensureDreamQueueTable(db: Database): void;
|
|
11
|
-
export declare function hasActiveDreamLease(db: Database): boolean;
|
|
12
|
-
/** Enqueue a project for dreaming. Skips if the same project already has any queue entry (queued or running).
|
|
13
|
-
*
|
|
14
|
-
* @param force - When true (e.g. manual /ctx-dream), uses the lease TTL (2 min) as the stale threshold
|
|
15
|
-
* instead of the full 2-hour max-runtime window. This lets users re-trigger dreaming after a crash or
|
|
16
|
-
* restart even when the previous queue entry was started only seconds ago.
|
|
17
|
-
*/
|
|
18
|
-
export declare function enqueueDream(db: Database, projectIdentity: string, reason: string, force?: boolean): DreamQueueEntry | null;
|
|
19
|
-
/** Peek at the next unstarted entry without claiming it.
|
|
20
|
-
*
|
|
21
|
-
* @param projectIdentity - When provided, only matches entries for this project.
|
|
22
|
-
* This is critical for cross-process coexistence: each running OpenCode/Pi
|
|
23
|
-
* process registers exactly one project, so it must only drain entries that
|
|
24
|
-
* belong to it. Without this filter, Pi (running in project A) would dequeue
|
|
25
|
-
* queue entries for project B and try to dream B with Pi's runner — which
|
|
26
|
-
* either spawns `pi` in a directory that doesn't exist (the `git:<sha>`
|
|
27
|
-
* identity string) or, even if it succeeded, runs the wrong harness for that
|
|
28
|
-
* project.
|
|
29
|
-
*/
|
|
30
|
-
export declare function peekQueue(db: Database, projectIdentity?: string): DreamQueueEntry | null;
|
|
31
|
-
/** Claim the next unstarted entry atomically by marking started_at. Returns null if queue is empty.
|
|
32
|
-
*
|
|
33
|
-
* @param projectIdentity - When provided, only dequeues entries for this project.
|
|
34
|
-
* See `peekQueue` for the cross-process coexistence rationale.
|
|
35
|
-
*/
|
|
36
|
-
export declare function dequeueNext(db: Database, projectIdentity?: string): DreamQueueEntry | null;
|
|
37
|
-
/** Remove a completed or failed entry from the queue. */
|
|
38
|
-
export declare function removeDreamEntry(db: Database, id: number): void;
|
|
39
|
-
/** Reset a dequeued entry so it can be retried (e.g., after lease failure). Increments retry_count. */
|
|
40
|
-
export declare function resetDreamEntry(db: Database, id: number): void;
|
|
41
|
-
/** Get the retry count for a queue entry. */
|
|
42
|
-
export declare function getEntryRetryCount(db: Database, id: number): number;
|
|
43
|
-
/**
|
|
44
|
-
* Clear stale started entries (stuck for more than maxAgeMs).
|
|
45
|
-
*
|
|
46
|
-
* Callers MUST gate this on `!hasActiveDreamLease(db)` — a healthy long-running
|
|
47
|
-
* dream can exceed `maxAgeMs` while still renewing its lease, and deleting its
|
|
48
|
-
* own row mid-run is the bug this guard prevents (mirrors the enqueue path).
|
|
49
|
-
*
|
|
50
|
-
* `projectIdentity` scopes the delete to one project. The shared `dream_queue`
|
|
51
|
-
* is cross-process (OpenCode + Pi); a global delete would reap other hosts'
|
|
52
|
-
* still-running rows. Omit only for the legacy "reap any" test path.
|
|
53
|
-
*/
|
|
54
|
-
export declare function clearStaleEntries(db: Database, maxAgeMs: number, projectIdentity?: string): number;
|
|
55
|
-
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/dreamer/queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGvD,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,iEAAiE;IACjE,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAexD;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CASzD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CACxB,EAAE,EAAE,QAAQ,EACZ,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,KAAK,UAAQ,GACd,eAAe,GAAG,IAAI,CAsCxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CA4BxF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAa1F;AAED,yDAAyD;AACzD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAE/D;AAED,uGAAuG;AACvG,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAI9D;AAED,6CAA6C;AAC7C,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAOnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC7B,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,MAAM,EAChB,eAAe,CAAC,EAAE,MAAM,GACzB,MAAM,CAYR"}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import type { DreamingTask } from "../../../config/schema/magic-context";
|
|
2
|
-
import type { PluginContext } from "../../../plugin/types";
|
|
3
|
-
import { Database } from "../../../shared/sqlite";
|
|
4
|
-
interface ExperimentalPinKeyFilesConfig {
|
|
5
|
-
enabled: boolean;
|
|
6
|
-
token_budget: number;
|
|
7
|
-
min_reads: number;
|
|
8
|
-
}
|
|
9
|
-
export declare function registerDreamProjectDirectory(projectIdentity: string, directory: string): void;
|
|
10
|
-
export interface DreamRunResult {
|
|
11
|
-
startedAt: number;
|
|
12
|
-
finishedAt: number;
|
|
13
|
-
holderId: string;
|
|
14
|
-
smartNotesSurfaced: number;
|
|
15
|
-
smartNotesPending: number;
|
|
16
|
-
tasks: {
|
|
17
|
-
name: string;
|
|
18
|
-
durationMs: number;
|
|
19
|
-
result: unknown;
|
|
20
|
-
error?: string;
|
|
21
|
-
}[];
|
|
22
|
-
}
|
|
23
|
-
export declare function runDream(args: {
|
|
24
|
-
db: Database;
|
|
25
|
-
client: PluginContext["client"];
|
|
26
|
-
/** Project identity (e.g. "git:<sha>"), NOT a filesystem path. Used for dream state keys. */
|
|
27
|
-
projectIdentity: string;
|
|
28
|
-
tasks: DreamingTask[];
|
|
29
|
-
taskTimeoutMinutes: number;
|
|
30
|
-
maxRuntimeMinutes: number;
|
|
31
|
-
parentSessionId?: string;
|
|
32
|
-
sessionDirectory?: string;
|
|
33
|
-
experimentalUserMemories?: {
|
|
34
|
-
enabled: boolean;
|
|
35
|
-
promotionThreshold: number;
|
|
36
|
-
};
|
|
37
|
-
experimentalPinKeyFiles?: ExperimentalPinKeyFilesConfig;
|
|
38
|
-
/**
|
|
39
|
-
* Resolved fallback chain for dreamer subagent calls. When the primary
|
|
40
|
-
* `dreamer.model` fails (auth, model-not-found, rate limit, transient
|
|
41
|
-
* network), each entry is tried in order before giving up. Empty/undefined
|
|
42
|
-
* disables fallback iteration (legacy single-suggestion-retry only).
|
|
43
|
-
*
|
|
44
|
-
* Caller (`processDreamQueue` / direct caller) resolves this via
|
|
45
|
-
* `resolveFallbackChain(DREAMER_AGENT, config.dreamer.fallback_models)`.
|
|
46
|
-
*/
|
|
47
|
-
fallbackModels?: readonly string[];
|
|
48
|
-
}): Promise<DreamRunResult>;
|
|
49
|
-
export declare function processDreamQueue(args: {
|
|
50
|
-
db: Database;
|
|
51
|
-
client: PluginContext["client"];
|
|
52
|
-
tasks: DreamingTask[];
|
|
53
|
-
taskTimeoutMinutes: number;
|
|
54
|
-
maxRuntimeMinutes: number;
|
|
55
|
-
experimentalUserMemories?: {
|
|
56
|
-
enabled: boolean;
|
|
57
|
-
promotionThreshold: number;
|
|
58
|
-
};
|
|
59
|
-
experimentalPinKeyFiles?: ExperimentalPinKeyFilesConfig;
|
|
60
|
-
/**
|
|
61
|
-
* Optional project identity filter — when provided, only entries belonging
|
|
62
|
-
* to this project are dequeued. Each running OpenCode/Pi process registers
|
|
63
|
-
* exactly one project, and the host's dreamer client (and `pi` runner, in
|
|
64
|
-
* Pi's case) is project-specific. Without this filter, a Pi process running
|
|
65
|
-
* for project A would dequeue queue entries for project B and try to
|
|
66
|
-
* `posix_spawn 'pi'` in B's `git:<sha>` identity string as a directory,
|
|
67
|
-
* failing with ENOENT every cycle.
|
|
68
|
-
*
|
|
69
|
-
* Callers should pass this whenever they own a single project — both the
|
|
70
|
-
* scheduled timer tick (`sweepProject`) and the `/ctx-dream` command
|
|
71
|
-
* handler. Tests pass `undefined` to keep the legacy "dequeue any" semantics.
|
|
72
|
-
*/
|
|
73
|
-
projectIdentity?: string;
|
|
74
|
-
/**
|
|
75
|
-
* Filesystem directory of the project THIS draining process owns. Because
|
|
76
|
-
* project identity collapses worktrees/clones to one `git:<sha>`, resolving
|
|
77
|
-
* the execution directory from the shared in-memory map can pick a stale
|
|
78
|
-
* sibling checkout ("last-registered wins"). The drain caller always knows
|
|
79
|
-
* its own live directory, so passing it here guarantees the dream runs in a
|
|
80
|
-
* checkout this process actually registered. Paired with projectIdentity
|
|
81
|
-
* (the queue filter), so the dequeued entry is guaranteed to be this
|
|
82
|
-
* project's. Falls back to the map (then the identity string) when omitted.
|
|
83
|
-
*/
|
|
84
|
-
sessionDirectoryOverride?: string;
|
|
85
|
-
/**
|
|
86
|
-
* Resolved Dreamer fallback chain. See `runDream` for semantics. Callers
|
|
87
|
-
* compute via `resolveFallbackChain(DREAMER_AGENT, pluginConfig.dreamer?.fallback_models)`.
|
|
88
|
-
*/
|
|
89
|
-
fallbackModels?: readonly string[];
|
|
90
|
-
}): Promise<DreamRunResult | null>;
|
|
91
|
-
export {};
|
|
92
|
-
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/dreamer/runner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAO3D,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAiClD,UAAU,6BAA6B;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,6BAA6B,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAE9F;AAMD,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE;QACH,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;CACP;AAqED,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACjC,EAAE,EAAE,QAAQ,CAAC;IACb,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,6FAA6F;IAC7F,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,uBAAuB,CAAC,EAAE,6BAA6B,CAAC;IACxD;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,GAAG,OAAO,CAAC,cAAc,CAAC,CAijB1B;AA2OD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC1C,EAAE,EAAE,QAAQ,CAAC;IACb,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wBAAwB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,uBAAuB,CAAC,EAAE,6BAA6B,CAAC;IACxD;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;OASG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC;;;OAGG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAqEjC"}
|