@cortexkit/opencode-magic-context 0.31.3 → 0.31.5

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 (99) hide show
  1. package/dist/config/index.d.ts.map +1 -1
  2. package/dist/config/project-security.d.ts +16 -12
  3. package/dist/config/project-security.d.ts.map +1 -1
  4. package/dist/features/magic-context/dreamer/classify-prompt.d.ts +2 -2
  5. package/dist/features/magic-context/dreamer/classify-prompt.d.ts.map +1 -1
  6. package/dist/features/magic-context/dreamer/classify.d.ts +8 -0
  7. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  8. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  9. package/dist/features/magic-context/dreamer/lease.d.ts +1 -0
  10. package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -1
  11. package/dist/features/magic-context/dreamer/manifest-parser.d.ts +7 -0
  12. package/dist/features/magic-context/dreamer/manifest-parser.d.ts.map +1 -0
  13. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts +2 -3
  14. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts.map +1 -1
  15. package/dist/features/magic-context/dreamer/map-memories.d.ts +8 -0
  16. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  17. package/dist/features/magic-context/dreamer/promote-primers.d.ts.map +1 -1
  18. package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts +5 -0
  19. package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/verify-prompt.d.ts +2 -2
  21. package/dist/features/magic-context/dreamer/verify-prompt.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  23. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +4 -0
  24. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
  25. package/dist/features/magic-context/memory/storage-memory.d.ts +12 -0
  26. package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
  27. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  28. package/dist/features/magic-context/message-index.d.ts +6 -0
  29. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  30. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  31. package/dist/features/magic-context/search.d.ts.map +1 -1
  32. package/dist/features/magic-context/smart-notes/capabilities.d.ts +1 -0
  33. package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -1
  34. package/dist/features/magic-context/smart-notes/compiler.d.ts +3 -2
  35. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  36. package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
  37. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts +3 -2
  38. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
  39. package/dist/features/magic-context/smart-notes/schedule.d.ts.map +1 -1
  40. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts +17 -6
  41. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts.map +1 -1
  42. package/dist/features/magic-context/smart-notes/types.d.ts +6 -1
  43. package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -1
  44. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  45. package/dist/features/magic-context/storage-meta-persisted.d.ts +8 -0
  46. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  47. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  48. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  49. package/dist/features/magic-context/storage.d.ts +1 -1
  50. package/dist/features/magic-context/storage.d.ts.map +1 -1
  51. package/dist/features/magic-context/workspaces.d.ts +8 -0
  52. package/dist/features/magic-context/workspaces.d.ts.map +1 -1
  53. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  54. package/dist/hooks/magic-context/compartment-runner.d.ts +2 -0
  55. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  56. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  58. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  59. package/dist/hooks/magic-context/tag-messages.d.ts +1 -0
  60. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  61. package/dist/hooks/magic-context/todo-view.d.ts +27 -2
  62. package/dist/hooks/magic-context/todo-view.d.ts.map +1 -1
  63. package/dist/hooks/magic-context/transform-message-helpers.d.ts +6 -3
  64. package/dist/hooks/magic-context/transform-message-helpers.d.ts.map +1 -1
  65. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts +1 -0
  66. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  67. package/dist/index.js +1039 -331
  68. package/dist/shared/assistant-message-extractor.d.ts +1 -0
  69. package/dist/shared/assistant-message-extractor.d.ts.map +1 -1
  70. package/dist/shared/redaction.d.ts.map +1 -1
  71. package/dist/shared/rpc-notifications.d.ts +21 -16
  72. package/dist/shared/rpc-notifications.d.ts.map +1 -1
  73. package/dist/shared/rpc-server.d.ts +1 -0
  74. package/dist/shared/rpc-server.d.ts.map +1 -1
  75. package/dist/shared/rpc-utils.d.ts +3 -1
  76. package/dist/shared/rpc-utils.d.ts.map +1 -1
  77. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  78. package/dist/tools/ctx-search/tools.d.ts.map +1 -1
  79. package/dist/tools/ctx-search/types.d.ts +1 -1
  80. package/dist/tools/ctx-search/types.d.ts.map +1 -1
  81. package/dist/tui/data/notification-socket.d.ts +1 -0
  82. package/dist/tui/data/notification-socket.d.ts.map +1 -1
  83. package/dist/tui-compiled/badge-contrast.d.ts +46 -0
  84. package/dist/tui-compiled/badge-contrast.d.ts.map +1 -0
  85. package/dist/tui-compiled/data/context-db.d.ts +45 -0
  86. package/dist/tui-compiled/data/context-db.d.ts.map +1 -0
  87. package/dist/tui-compiled/data/notification-socket.d.ts +40 -0
  88. package/dist/tui-compiled/data/notification-socket.d.ts.map +1 -0
  89. package/package.json +3 -2
  90. package/src/shared/assistant-message-extractor.ts +20 -0
  91. package/src/shared/redaction.ts +1 -0
  92. package/src/shared/rpc-client.test.ts +164 -5
  93. package/src/shared/rpc-notifications.ts +73 -21
  94. package/src/shared/rpc-server.ts +69 -18
  95. package/src/shared/rpc-utils.ts +12 -2
  96. package/src/tui/data/notification-socket.test.ts +131 -0
  97. package/src/tui/data/notification-socket.ts +81 -16
  98. package/src/tui/entry.mjs +23 -3
  99. package/src/tui-compiled/data/notification-socket.ts +81 -16
@@ -51,9 +51,21 @@ let opts: NotificationSocketOptions | null = null;
51
51
  /** Generation of the rpc client at connect time; a dispose/reinit bumps it and
52
52
  * invalidates an in-flight socket so its late callbacks are ignored. */
53
53
  let connectGeneration = 0;
54
- /** Highest handled notification id (sent in hello so a reconnect re-delivers the
55
- * unhandled backlog; sent in ack so the server prunes the queue). */
56
- let lastHandledId = 0;
54
+
55
+ const GLOBAL_CURSOR_KEY = "global";
56
+ const SESSION_CURSOR_PREFIX = "session:";
57
+ const MAX_DEDUPED_NOTIFICATION_IDS = 500;
58
+
59
+ /**
60
+ * Notification ids are process-global, but acknowledgement cursors are scoped. A
61
+ * high id consumed in session A must not become the prune watermark for session B;
62
+ * global notifications also carry their own cursor so they cannot skip session
63
+ * backlog. The id set de-dupes at-least-once re-delivery when a reconnect sends
64
+ * a session cursor that is intentionally lower than the global cursor.
65
+ */
66
+ const lastHandledIdByCursor = new Map<string, number>();
67
+ const handledNotificationIds = new Set<number>();
68
+ const handledNotificationIdOrder: number[] = [];
57
69
 
58
70
  /** Open the persistent notification socket. Idempotent: a second call while open
59
71
  * is a no-op. Reconnects on its own after any drop. */
@@ -118,8 +130,10 @@ async function connect(): Promise<void> {
118
130
 
119
131
  let ws: WebSocket;
120
132
  try {
121
- ws = new WebSocket(`ws://127.0.0.1:${endpoint.port}/ws`);
133
+ const tokenQuery = `?token=${encodeURIComponent(endpoint.token ?? "")}`;
134
+ ws = new WebSocket(`ws://127.0.0.1:${endpoint.port}/ws${tokenQuery}`);
122
135
  } catch {
136
+ client.reset();
123
137
  scheduleReconnect();
124
138
  return;
125
139
  }
@@ -137,6 +151,7 @@ async function connect(): Promise<void> {
137
151
  });
138
152
 
139
153
  const onDown = () => {
154
+ client.reset();
140
155
  if (socket === ws) {
141
156
  socket = null;
142
157
  helloedSession = null;
@@ -155,7 +170,8 @@ function sendHello(ws: WebSocket, token: string | null): void {
155
170
  type: "hello",
156
171
  token: token ?? "",
157
172
  sessionId,
158
- lastReceivedId: lastHandledId,
173
+ lastReceivedId: cursorForKey(cursorKeyForSession(sessionId)),
174
+ globalLastReceivedId: cursorForKey(GLOBAL_CURSOR_KEY),
159
175
  }),
160
176
  );
161
177
  }
@@ -180,6 +196,11 @@ async function handleSocketMessage(ws: WebSocket, raw: string): Promise<void> {
180
196
  // session, or a later switch back, should still get it). Just skip.
181
197
  return;
182
198
  }
199
+ if (handledNotificationIds.has(notification.id)) {
200
+ sendAck(ws, notification);
201
+ return;
202
+ }
203
+
183
204
  let consumed = false;
184
205
  try {
185
206
  consumed = await Promise.resolve(opts?.onNotification(notification) ?? false);
@@ -188,17 +209,13 @@ async function handleSocketMessage(ws: WebSocket, raw: string): Promise<void> {
188
209
  }
189
210
  // A dispose/reinit during an awaited dialog handler invalidates this socket.
190
211
  if (socket !== ws || getRpcGeneration() !== connectGeneration) return;
191
- if (consumed && notification.id > lastHandledId) {
192
- lastHandledId = notification.id;
193
- // Ack so the server prunes the queue during this long-lived connection.
194
- // (The id also rides the next reconnect hello via lastReceivedId, so a
195
- // dropped ack just re-delivers an already-consumed item, which the
196
- // handlers are idempotent against.)
197
- try {
198
- ws.send(JSON.stringify({ type: "ack", lastReceivedId: lastHandledId }));
199
- } catch {
200
- // best-effort; reconnect hello re-syncs via lastReceivedId
201
- }
212
+ if (consumed) {
213
+ rememberHandledId(notification.id);
214
+ advanceCursor(notificationCursorKey(notification), notification.id);
215
+ // Ack only the notification's own cursor scope. A dropped ack is safe:
216
+ // the next hello sends the same per-scope cursors and duplicates are
217
+ // ignored locally.
218
+ sendAck(ws, notification);
202
219
  }
203
220
  return;
204
221
  }
@@ -214,6 +231,54 @@ async function handleSocketMessage(ws: WebSocket, raw: string): Promise<void> {
214
231
  }
215
232
  }
216
233
 
234
+ function cursorKeyForSession(sessionId: string | null | undefined): string {
235
+ return sessionId ? `${SESSION_CURSOR_PREFIX}${sessionId}` : GLOBAL_CURSOR_KEY;
236
+ }
237
+
238
+ function notificationCursorKey(notification: SocketNotification): string {
239
+ return notification.sessionId
240
+ ? `${SESSION_CURSOR_PREFIX}${notification.sessionId}`
241
+ : GLOBAL_CURSOR_KEY;
242
+ }
243
+
244
+ function cursorForKey(key: string): number {
245
+ return lastHandledIdByCursor.get(key) ?? 0;
246
+ }
247
+
248
+ function advanceCursor(key: string, id: number): void {
249
+ if (id > cursorForKey(key)) lastHandledIdByCursor.set(key, id);
250
+ }
251
+
252
+ function rememberHandledId(id: number): void {
253
+ if (handledNotificationIds.has(id)) return;
254
+ handledNotificationIds.add(id);
255
+ handledNotificationIdOrder.push(id);
256
+ while (handledNotificationIdOrder.length > MAX_DEDUPED_NOTIFICATION_IDS) {
257
+ const evicted = handledNotificationIdOrder.shift();
258
+ if (evicted !== undefined) handledNotificationIds.delete(evicted);
259
+ }
260
+ }
261
+
262
+ function sendAck(ws: WebSocket, notification: SocketNotification): void {
263
+ const lastReceivedId = cursorForKey(notificationCursorKey(notification));
264
+ const ack = notification.sessionId
265
+ ? { type: "ack", sessionId: notification.sessionId, lastReceivedId }
266
+ : { type: "ack", ackScope: "global", lastReceivedId };
267
+ try {
268
+ ws.send(JSON.stringify(ack));
269
+ } catch {
270
+ // best-effort; reconnect hello re-syncs via per-scope cursors
271
+ }
272
+ }
273
+
274
+ export function _resetNotificationSocketStateForTesting(): void {
275
+ stopNotificationSocket();
276
+ opts = null;
277
+ lastHandledIdByCursor.clear();
278
+ handledNotificationIds.clear();
279
+ handledNotificationIdOrder.length = 0;
280
+ }
281
+
217
282
  /** Cheap session-change watcher: re-scope the socket only when the active session
218
283
  * actually changes. Reads a property; no network at idle. */
219
284
  function watchSession(): void {