@cortexkit/opencode-magic-context 0.5.2 → 0.6.0

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.
Files changed (73) hide show
  1. package/README.md +18 -2
  2. package/dist/cli/doctor.d.ts.map +1 -1
  3. package/dist/cli.js +14 -0
  4. package/dist/config/schema/magic-context.d.ts +21 -0
  5. package/dist/config/schema/magic-context.d.ts.map +1 -1
  6. package/dist/features/magic-context/compaction-marker.d.ts +72 -0
  7. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -0
  8. package/dist/features/magic-context/dreamer/runner.d.ts +8 -0
  9. package/dist/features/magic-context/dreamer/runner.d.ts.map +1 -1
  10. package/dist/features/magic-context/dreamer/scheduler.d.ts.map +1 -1
  11. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  12. package/dist/features/magic-context/migrations.d.ts +8 -0
  13. package/dist/features/magic-context/migrations.d.ts.map +1 -0
  14. package/dist/features/magic-context/plugin-messages.d.ts +75 -0
  15. package/dist/features/magic-context/plugin-messages.d.ts.map +1 -0
  16. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  17. package/dist/features/magic-context/storage-meta-persisted.d.ts +10 -0
  18. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  19. package/dist/features/magic-context/storage-notes.d.ts +51 -5
  20. package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
  21. package/dist/features/magic-context/storage.d.ts +1 -2
  22. package/dist/features/magic-context/storage.d.ts.map +1 -1
  23. package/dist/features/magic-context/user-memory/review-user-memories.d.ts +20 -0
  24. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -0
  25. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +33 -0
  26. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -0
  27. package/dist/hooks/magic-context/command-handler.d.ts +4 -0
  28. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  29. package/dist/hooks/magic-context/compaction-marker-manager.d.ts +27 -0
  30. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -0
  31. package/dist/hooks/magic-context/compartment-parser.d.ts +1 -0
  32. package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/compartment-prompt.d.ts +4 -1
  34. package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
  35. package/dist/hooks/magic-context/compartment-runner-compressor.d.ts.map +1 -1
  36. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  38. package/dist/hooks/magic-context/compartment-runner-types.d.ts +5 -0
  39. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  41. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  42. package/dist/hooks/magic-context/hook.d.ts +7 -0
  43. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  44. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/system-prompt-hash.d.ts +2 -0
  48. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  49. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +4 -0
  50. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  51. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  52. package/dist/hooks/magic-context/transform.d.ts +2 -0
  53. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +1228 -149
  56. package/dist/plugin/dream-timer.d.ts +4 -0
  57. package/dist/plugin/dream-timer.d.ts.map +1 -1
  58. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  59. package/dist/plugin/tui-action-consumer.d.ts +13 -0
  60. package/dist/plugin/tui-action-consumer.d.ts.map +1 -0
  61. package/dist/tools/ctx-note/constants.d.ts +1 -1
  62. package/dist/tools/ctx-note/constants.d.ts.map +1 -1
  63. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  64. package/dist/tools/ctx-note/types.d.ts +3 -1
  65. package/dist/tools/ctx-note/types.d.ts.map +1 -1
  66. package/dist/tui/data/context-db.d.ts +20 -0
  67. package/dist/tui/data/context-db.d.ts.map +1 -1
  68. package/package.json +1 -1
  69. package/src/tui/data/context-db.ts +114 -6
  70. package/src/tui/index.tsx +77 -2
  71. package/src/tui/slots/sidebar-content.tsx +3 -2
  72. package/dist/features/magic-context/storage-smart-notes.d.ts +0 -24
  73. package/dist/features/magic-context/storage-smart-notes.d.ts.map +0 -1
@@ -13,5 +13,9 @@ export declare function startDreamScheduleTimer(args: {
13
13
  dreamerConfig?: DreamerConfig;
14
14
  embeddingConfig: EmbeddingConfig;
15
15
  memoryEnabled: boolean;
16
+ experimentalUserMemories?: {
17
+ enabled: boolean;
18
+ promotionThreshold: number;
19
+ };
16
20
  }): (() => void) | undefined;
17
21
  //# sourceMappingURL=dream-timer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dream-timer.d.ts","sourceRoot":"","sources":["../../src/plugin/dream-timer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAMrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,OAAO,CAAC;CAC1B,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CA6D3B"}
1
+ {"version":3,"file":"dream-timer.d.ts","sourceRoot":"","sources":["../../src/plugin/dream-timer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAMrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,wBAAwB,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAqE3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-session-hooks.d.ts","sourceRoot":"","sources":["../../../src/plugin/hooks/create-session-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAU7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;CAC1C;;;;;;qBA2CA,CAAC;;;;;;;;;;;;qBARc,CAAN;mBAAiB,CAAC;;;;;0BAQysU,CAAC;;;;;;EADruU"}
1
+ {"version":3,"file":"create-session-hooks.d.ts","sourceRoot":"","sources":["../../../src/plugin/hooks/create-session-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAU7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;CAC1C;;;;;;qBA4C+R,CAAC;;;;;;;;;;;;qBATjR,CAAN;mBAAiB,CAAC;;;;;0BASwtW,CAAC;;;;;;EADpvW"}
@@ -0,0 +1,13 @@
1
+ import type { MagicContextConfig } from "../config/schema/magic-context";
2
+ import type { PluginContext } from "./types";
3
+ /**
4
+ * Start a server-side consumer that polls plugin_messages for TUI→server
5
+ * action messages and dispatches them. Currently handles:
6
+ * - { command: "recomp" } — executes /ctx-recomp for the given session
7
+ */
8
+ export declare function startTuiActionConsumer(args: {
9
+ client: PluginContext["client"];
10
+ directory: string;
11
+ config: MagicContextConfig;
12
+ }): (() => void) | undefined;
13
+ //# sourceMappingURL=tui-action-consumer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-action-consumer.d.ts","sourceRoot":"","sources":["../../src/plugin/tui-action-consumer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAMzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAQ7C;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;CAC9B,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CA+D3B"}
@@ -1,2 +1,2 @@
1
- export declare const CTX_NOTE_DESCRIPTION = "Save or inspect durable session notes that persist for this session.\nUse this for short goals, constraints, decisions, or reminders worth carrying forward.\n\nActions:\n- `write`: Append one note. Optionally provide `surface_condition` to create a smart note.\n- `read`: Show current notes (session notes + ready smart notes).\n- `clear`: Remove all session notes.\n- `dismiss`: Dismiss a ready smart note by `note_id`.\n\n**Smart Notes**: When `surface_condition` is provided with `write`, the note becomes a project-scoped smart note.\nThe dreamer evaluates smart note conditions during nightly runs and surfaces them when conditions are met.\nExample: `ctx_note(action=\"write\", content=\"Implement X because Y\", surface_condition=\"When PR #42 is merged in this repo\")`\n\nHistorian reads these notes, deduplicates them, and rewrites the remaining useful notes over time.";
1
+ export declare const CTX_NOTE_DESCRIPTION = "Save or inspect durable session notes that persist for this session.\nUse this for short goals, constraints, decisions, or reminders worth carrying forward.\n\nActions:\n- `write`: Append one note. Optionally provide `surface_condition` to create a smart note.\n- `read`: Show current notes. Defaults to active session notes + ready smart notes; use `filter` to inspect all, pending, ready, active, or dismissed notes.\n- `dismiss`: Dismiss a note by `note_id`.\n- `update`: Update a note by `note_id`.\n\n**Smart Notes**: When `surface_condition` is provided with `write`, the note becomes a project-scoped smart note.\nThe dreamer evaluates smart note conditions during nightly runs and surfaces them when conditions are met.\nExample: `ctx_note(action=\"write\", content=\"Implement X because Y\", surface_condition=\"When PR #42 is merged in this repo\")`\n\nHistorian reads these notes, deduplicates them, and rewrites the remaining useful notes over time.";
2
2
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-note/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,o3BAakE,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-note/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,s8BAakE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-note/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAchE,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,QAAQ,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAkHD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAIxF"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-note/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAchE,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,QAAQ,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAkND,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAIxF"}
@@ -1,7 +1,9 @@
1
+ export type CtxNoteReadFilter = "all" | "active" | "pending" | "ready" | "dismissed";
1
2
  export interface CtxNoteArgs {
2
- action?: "write" | "read" | "clear" | "dismiss";
3
+ action?: "write" | "read" | "dismiss" | "update";
3
4
  content?: string;
4
5
  surface_condition?: string;
6
+ filter?: CtxNoteReadFilter;
5
7
  note_id?: number;
6
8
  }
7
9
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-note/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IACxB,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-note/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,CAAC;AAErF,MAAM,WAAW,WAAW;IACxB,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -51,4 +51,24 @@ export interface StatusDetail extends SidebarSnapshot {
51
51
  export declare function closeDb(): void;
52
52
  export declare function loadSidebarSnapshot(sessionId: string, directory: string): SidebarSnapshot;
53
53
  export declare function loadStatusDetail(sessionId: string, directory: string, modelKey?: string): StatusDetail;
54
+ /**
55
+ * Get compartment count for a session (used by recomp confirmation dialog).
56
+ */
57
+ export declare function getCompartmentCount(sessionId: string): number;
58
+ /**
59
+ * Consume pending server→TUI messages from the plugin_messages table.
60
+ * Returns consumed messages and marks them as consumed.
61
+ */
62
+ export interface TuiMessage {
63
+ id: number;
64
+ type: string;
65
+ payload: Record<string, unknown>;
66
+ sessionId: string | null;
67
+ createdAt: number;
68
+ }
69
+ export declare function consumeTuiMessages(): TuiMessage[];
70
+ /**
71
+ * Send a message from TUI to server via plugin_messages.
72
+ */
73
+ export declare function sendMessageToServer(type: string, payload: Record<string, unknown>, sessionId?: string): boolean;
54
74
  //# sourceMappingURL=context-db.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-db.d.ts","sourceRoot":"","sources":["../../../src/tui/data/context-db.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAE/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,MAAM,WAAW,YAAa,SAAQ,eAAe;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAExD,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;IAEtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;IAEvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AA+BD,wBAAgB,OAAO,IAAI,IAAI,CAU9B;AA+BD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,CAuNzF;AAED,wBAAgB,gBAAgB,CAC5B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAClB,YAAY,CAmMd"}
1
+ {"version":3,"file":"context-db.d.ts","sourceRoot":"","sources":["../../../src/tui/data/context-db.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAE/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,sEAAsE;AACtE,MAAM,WAAW,YAAa,SAAQ,eAAe;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAExD,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;IAEtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;IAEvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AA+BD,wBAAgB,OAAO,IAAI,IAAI,CAU9B;AA+BD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,CAuNzF;AAED,wBAAgB,gBAAgB,CAC5B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAClB,YAAY,CAmMd;AAyCD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAW7D;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,kBAAkB,IAAI,UAAU,EAAE,CAoDjD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAiBT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/opencode-magic-context",
3
- "version": "0.5.2",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",
@@ -70,11 +70,11 @@ function getDb(): Database | null {
70
70
  return cachedDb;
71
71
  }
72
72
  try {
73
- // Open without readonly flag — WAL-mode DBs need read-write access to the
74
- // -shm file even for read-only queries. We never write from the TUI process.
73
+ // Open read-write: WAL-mode DBs need write access to the -shm file,
74
+ // and the TUI writes to plugin_messages for the message bus.
75
75
  cachedDb = new Database(targetPath);
76
76
  cachedDb.exec("PRAGMA journal_mode = WAL");
77
- cachedDb.exec("PRAGMA query_only = ON");
77
+ cachedDb.exec("PRAGMA busy_timeout = 3000");
78
78
  dbPath = targetPath;
79
79
  return cachedDb;
80
80
  } catch (err) {
@@ -233,7 +233,7 @@ export function loadSidebarSnapshot(sessionId: string, directory: string): Sideb
233
233
  try {
234
234
  const noteRow = db
235
235
  .query<{ count: number }, [string]>(
236
- `SELECT COUNT(*) as count FROM notes WHERE session_id = ?`,
236
+ `SELECT COUNT(*) as count FROM notes WHERE session_id = ? AND type = 'session' AND status = 'active'`,
237
237
  )
238
238
  .get(sessionId);
239
239
  sessionNoteCount = noteRow?.count ?? 0;
@@ -247,12 +247,12 @@ export function loadSidebarSnapshot(sessionId: string, directory: string): Sideb
247
247
  try {
248
248
  const smartRow = db
249
249
  .query<{ count: number }, [string]>(
250
- `SELECT COUNT(*) as count FROM smart_notes WHERE project_path = ? AND status = 'ready'`,
250
+ `SELECT COUNT(*) as count FROM notes WHERE project_path = ? AND type = 'smart' AND status = 'ready'`,
251
251
  )
252
252
  .get(projectIdentity);
253
253
  readySmartNoteCount = smartRow?.count ?? 0;
254
254
  } catch {
255
- // smart_notes table may not exist
255
+ // notes table may not exist
256
256
  }
257
257
  }
258
258
 
@@ -582,3 +582,111 @@ function readMagicContextConfig(directory: string): Record<string, unknown> | nu
582
582
  }
583
583
  return null;
584
584
  }
585
+
586
+ /**
587
+ * Get compartment count for a session (used by recomp confirmation dialog).
588
+ */
589
+ export function getCompartmentCount(sessionId: string): number {
590
+ const db = getDb();
591
+ if (!db) return 0;
592
+ try {
593
+ const row = db
594
+ .prepare("SELECT COUNT(*) as count FROM compartments WHERE session_id = ?")
595
+ .get(sessionId) as { count: number } | null;
596
+ return row?.count ?? 0;
597
+ } catch {
598
+ return 0;
599
+ }
600
+ }
601
+
602
+ /**
603
+ * Consume pending server→TUI messages from the plugin_messages table.
604
+ * Returns consumed messages and marks them as consumed.
605
+ */
606
+ export interface TuiMessage {
607
+ id: number;
608
+ type: string;
609
+ payload: Record<string, unknown>;
610
+ sessionId: string | null;
611
+ createdAt: number;
612
+ }
613
+
614
+ export function consumeTuiMessages(): TuiMessage[] {
615
+ const db = getDb();
616
+ if (!db) return [];
617
+
618
+ try {
619
+ // Check if plugin_messages table exists (migration may not have run yet)
620
+ const tableCheck = db
621
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='plugin_messages'")
622
+ .get();
623
+ if (!tableCheck) return [];
624
+
625
+ const now = Date.now();
626
+ const rows = db
627
+ .prepare(
628
+ "SELECT id, type, payload, session_id, created_at FROM plugin_messages WHERE direction = 'server_to_tui' AND consumed_at IS NULL ORDER BY created_at ASC",
629
+ )
630
+ .all() as Array<{
631
+ id: number;
632
+ type: string;
633
+ payload: string;
634
+ session_id: string | null;
635
+ created_at: number;
636
+ }>;
637
+
638
+ if (rows.length === 0) return [];
639
+
640
+ const ids = rows.map((r) => r.id);
641
+ db.prepare(
642
+ `UPDATE plugin_messages SET consumed_at = ? WHERE id IN (${ids.map(() => "?").join(",")})`,
643
+ ).run(now, ...ids);
644
+
645
+ // Cleanup old messages
646
+ db.prepare("DELETE FROM plugin_messages WHERE created_at < ?").run(now - 5 * 60 * 1000);
647
+
648
+ return rows.map((r) => {
649
+ let payload: Record<string, unknown> = {};
650
+ try {
651
+ payload = JSON.parse(r.payload);
652
+ } catch {
653
+ // Intentional: malformed payload treated as empty
654
+ }
655
+ return {
656
+ id: r.id,
657
+ type: r.type,
658
+ payload,
659
+ sessionId: r.session_id,
660
+ createdAt: r.created_at,
661
+ };
662
+ });
663
+ } catch {
664
+ return [];
665
+ }
666
+ }
667
+
668
+ /**
669
+ * Send a message from TUI to server via plugin_messages.
670
+ */
671
+ export function sendMessageToServer(
672
+ type: string,
673
+ payload: Record<string, unknown>,
674
+ sessionId?: string,
675
+ ): boolean {
676
+ const db = getDb();
677
+ if (!db) return false;
678
+
679
+ try {
680
+ const tableCheck = db
681
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='plugin_messages'")
682
+ .get();
683
+ if (!tableCheck) return false;
684
+
685
+ db.prepare(
686
+ "INSERT INTO plugin_messages (direction, type, payload, session_id, created_at) VALUES (?, ?, ?, ?, ?)",
687
+ ).run("tui_to_server", type, JSON.stringify(payload), sessionId ?? null, Date.now());
688
+ return true;
689
+ } catch {
690
+ return false;
691
+ }
692
+ }
package/src/tui/index.tsx CHANGED
@@ -5,7 +5,8 @@ import { dirname, join } from "node:path"
5
5
  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
- import { closeDb, loadStatusDetail, type StatusDetail } from "./data/context-db"
8
+ import packageJson from "../../package.json"
9
+ import { closeDb, consumeTuiMessages, getCompartmentCount, loadStatusDetail, sendMessageToServer, type StatusDetail } from "./data/context-db"
9
10
  import { detectConflicts } from "../shared/conflict-detector"
10
11
  import { fixConflicts } from "../shared/conflict-fixer"
11
12
  import { readJsoncFile } from "../shared/jsonc-parser"
@@ -278,7 +279,7 @@ const StatusDialog = (props: { api: TuiPluginApi; s: StatusDetail }) => {
278
279
  {/* Title */}
279
280
  <box justifyContent="center" width="100%" marginBottom={1}>
280
281
  <text fg={t().accent}>
281
- <b>⚡ Magic Context Status</b>
282
+ <b>⚡ Magic Context Status</b> <text fg={t().textMuted}>v{packageJson.version}</text>
282
283
  </text>
283
284
  </box>
284
285
 
@@ -406,6 +407,36 @@ function getModelKeyFromMessages(api: TuiPluginApi, sessionId: string): string |
406
407
  return undefined
407
408
  }
408
409
 
410
+ function showRecompDialog(api: TuiPluginApi) {
411
+ const sessionId = getSessionId(api)
412
+ if (!sessionId) {
413
+ api.ui.toast({ message: "No active session", variant: "warning" })
414
+ return
415
+ }
416
+
417
+ const count = getCompartmentCount(sessionId)
418
+ api.ui.dialog.replace(() => (
419
+ <api.ui.DialogConfirm
420
+ title="⚠️ Recomp Confirmation"
421
+ message={[
422
+ `You have ${count} compartments.`,
423
+ "",
424
+ "Recomp will regenerate all compartments and facts from raw history.",
425
+ "This may take a long time and consume significant tokens.",
426
+ "",
427
+ "Proceed?",
428
+ ].join("\n")}
429
+ onConfirm={() => {
430
+ sendMessageToServer("action", { command: "recomp" }, sessionId)
431
+ api.ui.toast({ message: "Recomp requested — historian will start shortly", variant: "info", duration: 5000 })
432
+ }}
433
+ onCancel={() => {
434
+ api.ui.toast({ message: "Recomp cancelled", variant: "info", duration: 3000 })
435
+ }}
436
+ />
437
+ ))
438
+ }
439
+
409
440
  function showStatusDialog(api: TuiPluginApi) {
410
441
  const sessionId = getSessionId(api)
411
442
  if (!sessionId) {
@@ -435,10 +466,54 @@ const tui: TuiPlugin = async (api, _options, meta) => {
435
466
  showStatusDialog(api)
436
467
  },
437
468
  },
469
+ {
470
+ title: "Magic Context: Recomp",
471
+ value: "magic-context.recomp",
472
+ category: "Magic Context",
473
+ slash: { name: "ctx-recomp" },
474
+ onSelect() {
475
+ showRecompDialog(api)
476
+ },
477
+ },
438
478
  ])
439
479
 
480
+ // Poll for server→TUI messages (toasts, dialogs) every 2 seconds
481
+ const messagePoller = setInterval(() => {
482
+ try {
483
+ const messages = consumeTuiMessages()
484
+ for (const msg of messages) {
485
+ if (msg.type === "toast") {
486
+ const p = msg.payload
487
+ api.ui.toast({
488
+ message: String(p.message ?? ""),
489
+ variant: (p.variant as "info" | "warning" | "error" | "success") ?? "info",
490
+ duration: typeof p.duration === "number" ? p.duration : 5000,
491
+ })
492
+ } else if (msg.type === "dialog_confirm") {
493
+ const p = msg.payload
494
+ const dialogId = String(p.id ?? "")
495
+ api.ui.dialog.replace(() => (
496
+ <api.ui.DialogConfirm
497
+ title={String(p.title ?? "Confirm")}
498
+ message={String(p.message ?? "")}
499
+ onConfirm={() => {
500
+ sendMessageToServer("dialog_result", { id: dialogId, confirmed: true }, msg.sessionId ?? undefined)
501
+ }}
502
+ onCancel={() => {
503
+ sendMessageToServer("dialog_result", { id: dialogId, confirmed: false }, msg.sessionId ?? undefined)
504
+ }}
505
+ />
506
+ ))
507
+ }
508
+ }
509
+ } catch {
510
+ // Intentional: message polling should never crash the TUI
511
+ }
512
+ }, 2000)
513
+
440
514
  // Clean up on dispose
441
515
  api.lifecycle.onDispose(() => {
516
+ clearInterval(messagePoller)
442
517
  closeDb()
443
518
  })
444
519
 
@@ -1,6 +1,7 @@
1
1
  /** @jsxImportSource @opentui/solid */
2
2
  import { createEffect, createMemo, createSignal, on, onCleanup } from "solid-js"
3
3
  import type { TuiSlotPlugin, TuiPluginApi, TuiThemeCurrent } from "@opencode-ai/plugin/tui"
4
+ import packageJson from "../../../package.json"
4
5
  import { loadSidebarSnapshot, type SidebarSnapshot } from "../data/context-db"
5
6
 
6
7
  const SINGLE_BORDER = { type: "single" } as any
@@ -303,10 +304,10 @@ const SidebarContent = (props: {
303
304
  <box flexDirection="row" justifyContent="space-between" alignItems="center">
304
305
  <box paddingLeft={1} paddingRight={1} backgroundColor={props.theme.accent}>
305
306
  <text fg={props.theme.background}>
306
- <b>Magic CTX</b>
307
+ <b>Magic Context</b>
307
308
  </text>
308
309
  </box>
309
- <text fg={props.theme.success}>active</text>
310
+ <text fg={props.theme.textMuted}>v{packageJson.version}</text>
310
311
  </box>
311
312
 
312
313
  {/* Token breakdown bar */}
@@ -1,24 +0,0 @@
1
- import type { Database } from "bun:sqlite";
2
- export type SmartNoteStatus = "pending" | "ready" | "dismissed";
3
- export interface SmartNote {
4
- id: number;
5
- projectPath: string;
6
- content: string;
7
- surfaceCondition: string;
8
- status: SmartNoteStatus;
9
- createdSessionId: string | null;
10
- createdAt: number;
11
- updatedAt: number;
12
- lastCheckedAt: number | null;
13
- readyAt: number | null;
14
- readyReason: string | null;
15
- }
16
- export declare function addSmartNote(db: Database, projectPath: string, content: string, surfaceCondition: string, sessionId?: string): SmartNote;
17
- export declare function getSmartNotes(db: Database, projectPath: string, status?: SmartNoteStatus): SmartNote[];
18
- export declare function getPendingSmartNotes(db: Database, projectPath: string): SmartNote[];
19
- export declare function getReadySmartNotes(db: Database, projectPath: string): SmartNote[];
20
- export declare function markSmartNoteReady(db: Database, noteId: number, readyReason?: string): void;
21
- export declare function markSmartNoteChecked(db: Database, noteId: number): void;
22
- export declare function dismissSmartNote(db: Database, noteId: number): boolean;
23
- export declare function deleteSmartNote(db: Database, noteId: number): boolean;
24
- //# sourceMappingURL=storage-smart-notes.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storage-smart-notes.d.ts","sourceRoot":"","sources":["../../../src/features/magic-context/storage-smart-notes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,CAAC;AAEhE,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,eAAe,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAiDD,wBAAgB,YAAY,CACxB,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,EACxB,SAAS,CAAC,EAAE,MAAM,GACnB,SAAS,CAWX;AAED,wBAAgB,aAAa,CACzB,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,eAAe,GACzB,SAAS,EAAE,CAMb;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,CAEnF;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,CAEjF;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAK3F;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAOvE;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAKtE;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAGrE"}