@cortexkit/opencode-magic-context 0.8.3 → 0.8.4
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 +17 -7
- package/dist/cli.js +2 -2
- package/dist/features/builtin-commands/commands.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +62246 -61171
- package/dist/plugin/rpc-handlers.d.ts +11 -0
- package/dist/plugin/rpc-handlers.d.ts.map +1 -0
- package/dist/shared/conflict-detector.d.ts +0 -4
- package/dist/shared/conflict-detector.d.ts.map +1 -1
- package/dist/shared/rpc-client.d.ts +16 -0
- package/dist/shared/rpc-client.d.ts.map +1 -0
- package/dist/shared/rpc-notifications.d.ts +21 -0
- package/dist/shared/rpc-notifications.d.ts.map +1 -0
- package/dist/shared/rpc-server.d.ts +17 -0
- package/dist/shared/rpc-server.d.ts.map +1 -0
- package/dist/shared/rpc-types.d.ts +59 -0
- package/dist/shared/rpc-types.d.ts.map +1 -0
- package/dist/shared/rpc-utils.d.ts +8 -0
- package/dist/shared/rpc-utils.d.ts.map +1 -0
- package/dist/tui/data/context-db.d.ts +17 -69
- package/dist/tui/data/context-db.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/conflict-detector.ts +1 -17
- package/src/shared/rpc-client.ts +123 -0
- package/src/shared/rpc-notifications.ts +44 -0
- package/src/shared/rpc-server.ts +136 -0
- package/src/shared/rpc-types.ts +58 -0
- package/src/shared/rpc-utils.ts +16 -0
- package/src/tui/data/context-db.ts +99 -625
- package/src/tui/index.tsx +53 -55
- package/src/tui/slots/sidebar-content.tsx +8 -7
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 } from "./slots/sidebar-content"
|
|
8
8
|
import packageJson from "../../package.json"
|
|
9
|
-
import {
|
|
9
|
+
import { closeRpc, consumeTuiMessages, getCompartmentCount, initRpcClient, loadStatusDetail, requestRecomp, type StatusDetail } from "./data/context-db"
|
|
10
10
|
import { detectConflicts } from "../shared/conflict-detector"
|
|
11
11
|
import { fixConflicts } from "../shared/conflict-fixer"
|
|
12
12
|
import { readJsoncFile } from "../shared/jsonc-parser"
|
|
@@ -103,7 +103,7 @@ function showConflictDialog(api: TuiPluginApi, directory: string, reasons: strin
|
|
|
103
103
|
}, 50)
|
|
104
104
|
}}
|
|
105
105
|
onCancel={() => {
|
|
106
|
-
api.ui.toast({ message: "Magic Context remains disabled. Run: bunx @cortexkit/opencode-magic-context doctor", variant: "warning", duration: 5000 })
|
|
106
|
+
api.ui.toast({ message: "Magic Context remains disabled. Run: bunx @cortexkit/opencode-magic-context@latest doctor", variant: "warning", duration: 5000 })
|
|
107
107
|
}}
|
|
108
108
|
/>
|
|
109
109
|
))
|
|
@@ -152,7 +152,7 @@ function showTuiSetupDialog(api: TuiPluginApi) {
|
|
|
152
152
|
}, 50)
|
|
153
153
|
}}
|
|
154
154
|
onCancel={() => {
|
|
155
|
-
api.ui.toast({ message: "You can add the sidebar later via: bunx @cortexkit/opencode-magic-context doctor", variant: "info", duration: 5000 })
|
|
155
|
+
api.ui.toast({ message: "You can add the sidebar later via: bunx @cortexkit/opencode-magic-context@latest doctor", variant: "info", duration: 5000 })
|
|
156
156
|
}}
|
|
157
157
|
/>
|
|
158
158
|
))
|
|
@@ -407,27 +407,28 @@ function showRecompDialog(api: TuiPluginApi) {
|
|
|
407
407
|
return
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
410
|
+
void getCompartmentCount(sessionId).then((count) => {
|
|
411
|
+
api.ui.dialog.replace(() => (
|
|
412
|
+
<api.ui.DialogConfirm
|
|
413
|
+
title="⚠️ Recomp Confirmation"
|
|
414
|
+
message={[
|
|
415
|
+
`You have ${count} compartments.`,
|
|
416
|
+
"",
|
|
417
|
+
"Recomp will regenerate all compartments and facts from raw history.",
|
|
418
|
+
"This may take a long time and consume significant tokens.",
|
|
419
|
+
"",
|
|
420
|
+
"Proceed?",
|
|
421
|
+
].join("\n")}
|
|
422
|
+
onConfirm={() => {
|
|
423
|
+
void requestRecomp(sessionId)
|
|
424
|
+
api.ui.toast({ message: "Recomp requested — historian will start shortly", variant: "info", duration: 5000 })
|
|
425
|
+
}}
|
|
426
|
+
onCancel={() => {
|
|
427
|
+
api.ui.toast({ message: "Recomp cancelled", variant: "info", duration: 3000 })
|
|
428
|
+
}}
|
|
429
|
+
/>
|
|
430
|
+
))
|
|
431
|
+
})
|
|
431
432
|
}
|
|
432
433
|
|
|
433
434
|
function showStatusDialog(api: TuiPluginApi) {
|
|
@@ -439,22 +440,28 @@ function showStatusDialog(api: TuiPluginApi) {
|
|
|
439
440
|
|
|
440
441
|
const directory = api.state.path.directory ?? ""
|
|
441
442
|
const modelKey = getModelKeyFromMessages(api, sessionId)
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
443
|
+
void loadStatusDetail(sessionId, directory, modelKey).then((detail) => {
|
|
444
|
+
api.ui.dialog.replace(() => <StatusDialog api={api} s={detail} />)
|
|
445
|
+
})
|
|
445
446
|
}
|
|
446
447
|
|
|
447
448
|
const tui: TuiPlugin = async (api, _options, meta) => {
|
|
449
|
+
// Initialize RPC client for server communication
|
|
450
|
+
const directory = api.state.path.directory ?? ""
|
|
451
|
+
initRpcClient(directory)
|
|
452
|
+
|
|
448
453
|
// Register sidebar slot
|
|
449
454
|
api.slots.register(createSidebarContentSlot(api))
|
|
450
455
|
|
|
451
|
-
// Register TUI command palette entries
|
|
456
|
+
// Register TUI command palette entries (no slash field — slash commands
|
|
457
|
+
// are registered server-side so there's only one /ctx-* registration).
|
|
458
|
+
// The server detects TUI mode and sends dialog requests via RPC instead
|
|
459
|
+
// of sendIgnoredMessage.
|
|
452
460
|
api.command.register(() => [
|
|
453
461
|
{
|
|
454
462
|
title: "Magic Context: Status",
|
|
455
463
|
value: "magic-context.status",
|
|
456
464
|
category: "Magic Context",
|
|
457
|
-
slash: { name: "ctx-status" },
|
|
458
465
|
onSelect() {
|
|
459
466
|
showStatusDialog(api)
|
|
460
467
|
},
|
|
@@ -463,17 +470,16 @@ const tui: TuiPlugin = async (api, _options, meta) => {
|
|
|
463
470
|
title: "Magic Context: Recomp",
|
|
464
471
|
value: "magic-context.recomp",
|
|
465
472
|
category: "Magic Context",
|
|
466
|
-
slash: { name: "ctx-recomp" },
|
|
467
473
|
onSelect() {
|
|
468
474
|
showRecompDialog(api)
|
|
469
475
|
},
|
|
470
476
|
},
|
|
471
477
|
])
|
|
472
478
|
|
|
473
|
-
// Poll for server→TUI messages
|
|
479
|
+
// Poll for server→TUI messages: toasts and dialog requests.
|
|
480
|
+
// Single poller because consumeTuiMessages() is destructive (deletes consumed rows).
|
|
474
481
|
const messagePoller = setInterval(() => {
|
|
475
|
-
|
|
476
|
-
const messages = consumeTuiMessages()
|
|
482
|
+
void consumeTuiMessages().then((messages) => {
|
|
477
483
|
for (const msg of messages) {
|
|
478
484
|
if (msg.type === "toast") {
|
|
479
485
|
const p = msg.payload
|
|
@@ -482,43 +488,35 @@ const tui: TuiPlugin = async (api, _options, meta) => {
|
|
|
482
488
|
variant: (p.variant as "info" | "warning" | "error" | "success") ?? "info",
|
|
483
489
|
duration: typeof p.duration === "number" ? p.duration : 5000,
|
|
484
490
|
})
|
|
485
|
-
} else if (msg.type === "
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
onConfirm={() => {
|
|
493
|
-
sendMessageToServer("dialog_result", { id: dialogId, confirmed: true }, msg.sessionId ?? undefined)
|
|
494
|
-
}}
|
|
495
|
-
onCancel={() => {
|
|
496
|
-
sendMessageToServer("dialog_result", { id: dialogId, confirmed: false }, msg.sessionId ?? undefined)
|
|
497
|
-
}}
|
|
498
|
-
/>
|
|
499
|
-
))
|
|
491
|
+
} else if (msg.type === "action") {
|
|
492
|
+
const action = msg.payload?.action
|
|
493
|
+
if (action === "show-status-dialog") {
|
|
494
|
+
showStatusDialog(api)
|
|
495
|
+
} else if (action === "show-recomp-dialog") {
|
|
496
|
+
showRecompDialog(api)
|
|
497
|
+
}
|
|
500
498
|
}
|
|
501
499
|
}
|
|
502
|
-
}
|
|
500
|
+
}).catch(() => {
|
|
503
501
|
// Intentional: message polling should never crash the TUI
|
|
504
|
-
}
|
|
505
|
-
},
|
|
502
|
+
})
|
|
503
|
+
}, 500)
|
|
506
504
|
|
|
507
505
|
// Clean up on dispose
|
|
508
506
|
api.lifecycle.onDispose(() => {
|
|
509
507
|
clearInterval(messagePoller)
|
|
510
|
-
|
|
508
|
+
closeRpc()
|
|
511
509
|
})
|
|
512
510
|
|
|
513
|
-
const directory = api.state.path.directory ?? ""
|
|
514
511
|
const conflictResult = detectConflicts(directory)
|
|
515
512
|
if (conflictResult.hasConflict) {
|
|
516
513
|
showConflictDialog(api, directory, conflictResult.reasons, conflictResult.conflicts)
|
|
517
514
|
return
|
|
518
515
|
}
|
|
519
516
|
|
|
520
|
-
// Note: tui.json
|
|
521
|
-
// if
|
|
517
|
+
// Note: if TUI plugin is loaded, tui.json already has our entry.
|
|
518
|
+
// But if the user added it manually and later removes it, or if they
|
|
519
|
+
// use setup/doctor which handles tui.json, this code is already running.
|
|
522
520
|
}
|
|
523
521
|
|
|
524
522
|
const id = "opencode-magic-context"
|
|
@@ -231,13 +231,14 @@ const SidebarContent = (props: {
|
|
|
231
231
|
const sid = props.sessionID()
|
|
232
232
|
if (!sid) return
|
|
233
233
|
const directory = props.api.state.path.directory ?? ""
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
234
|
+
void loadSidebarSnapshot(sid, directory).then((data) => {
|
|
235
|
+
setSnapshot(data)
|
|
236
|
+
try {
|
|
237
|
+
props.api.renderer.requestRender()
|
|
238
|
+
} catch {
|
|
239
|
+
// Ignore render errors
|
|
240
|
+
}
|
|
241
|
+
})
|
|
241
242
|
}
|
|
242
243
|
|
|
243
244
|
const scheduleRefresh = () => {
|