@cortexkit/opencode-magic-context 0.42.0 → 0.42.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.
Files changed (70) hide show
  1. package/dist/config/project-security.d.ts +3 -2
  2. package/dist/config/project-security.d.ts.map +1 -1
  3. package/dist/config/schema/magic-context.d.ts +20 -0
  4. package/dist/config/schema/magic-context.d.ts.map +1 -1
  5. package/dist/features/magic-context/compartment-chunk-embedding.d.ts +8 -4
  6. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  7. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  8. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  9. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  10. package/dist/features/magic-context/memory/embedding-identity.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/memory/embedding-model-match.d.ts +41 -0
  13. package/dist/features/magic-context/memory/embedding-model-match.d.ts.map +1 -0
  14. package/dist/features/magic-context/memory/embedding-openai.d.ts +7 -20
  15. package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
  16. package/dist/features/magic-context/memory/embedding-provider.d.ts +2 -2
  17. package/dist/features/magic-context/memory/embedding-provider.d.ts.map +1 -1
  18. package/dist/features/magic-context/memory/embedding-synapse.d.ts +5 -4
  19. package/dist/features/magic-context/memory/embedding-synapse.d.ts.map +1 -1
  20. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  21. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  22. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  24. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/compartment-runner-validation.d.ts +1 -1
  26. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  27. package/dist/hooks/magic-context/embed-session-state.d.ts +1 -1
  28. package/dist/hooks/magic-context/embed-session-state.d.ts.map +1 -1
  29. package/dist/hooks/magic-context/execute-status.d.ts +2 -0
  30. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  31. package/dist/hooks/magic-context/format-embed-failure.d.ts +2 -1
  32. package/dist/hooks/magic-context/format-embed-failure.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/maintenance-authority.d.ts +2 -2
  34. package/dist/hooks/magic-context/maintenance-authority.d.ts.map +1 -1
  35. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  36. package/dist/{index-c9hamh36.js → index-1q9kay7n.js} +534 -120
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +264 -108
  39. package/dist/plugin/embedding-bootstrap-helpers.d.ts.map +1 -1
  40. package/dist/plugin/embedding-routing.d.ts.map +1 -1
  41. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  42. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  43. package/dist/{recomp-orchestrator-3atsasjy.js → recomp-orchestrator-m33b3rk9.js} +1 -1
  44. package/dist/shared/rpc-types.d.ts +10 -0
  45. package/dist/shared/rpc-types.d.ts.map +1 -1
  46. package/dist/shared/status-detail-text.d.ts +3 -1
  47. package/dist/shared/status-detail-text.d.ts.map +1 -1
  48. package/dist/shared/status-summary.d.ts +30 -0
  49. package/dist/shared/status-summary.d.ts.map +1 -0
  50. package/dist/shared/tail-hygiene-status.d.ts +1 -0
  51. package/dist/shared/tail-hygiene-status.d.ts.map +1 -1
  52. package/dist/shared/user-facing-codes.d.ts +191 -0
  53. package/dist/shared/user-facing-codes.d.ts.map +1 -0
  54. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  55. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  56. package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
  57. package/package.json +1 -1
  58. package/src/config/project-security.test.ts +10 -2
  59. package/src/config/project-security.ts +12 -5
  60. package/src/config/schema/magic-context.test.ts +29 -0
  61. package/src/config/schema/magic-context.ts +24 -0
  62. package/src/shared/rpc-types.ts +10 -0
  63. package/src/shared/status-detail-text.test.ts +93 -24
  64. package/src/shared/status-detail-text.ts +9 -2
  65. package/src/shared/status-summary.ts +167 -0
  66. package/src/shared/tail-hygiene-status.ts +8 -0
  67. package/src/shared/user-facing-codes.test.ts +140 -0
  68. package/src/shared/user-facing-codes.ts +276 -0
  69. package/src/tui/index.tsx +41 -8
  70. package/src/tui-compiled/index.tsx +660 -647
@@ -0,0 +1,276 @@
1
+ import type { EmbeddingFailureClass } from "../features/magic-context/memory/embedding-failure";
2
+ import type { PromptFailureClass } from "./model-suggestion-retry";
3
+
4
+ export const USER_FACING_FAILURES = {
5
+ historian_unavailable: {
6
+ code: "MC-H01",
7
+ sentence: "History compression could not finish this turn.",
8
+ action: "It will retry automatically.",
9
+ },
10
+ recomp_unavailable: {
11
+ code: "MC-R01",
12
+ sentence: "History compression could not be rebuilt.",
13
+ action: "Run /ctx-recomp again.",
14
+ },
15
+ dream_provider_timeout: {
16
+ code: "MC-D01",
17
+ sentence: "Memory maintenance took too long to respond.",
18
+ action: "Run /ctx-dream again.",
19
+ },
20
+ dream_provider_error: {
21
+ code: "MC-D02",
22
+ sentence: "Memory maintenance could not reach its model.",
23
+ action: "Check the model connection, then run /ctx-dream again.",
24
+ },
25
+ dream_empty_completion: {
26
+ code: "MC-D03",
27
+ sentence: "Memory maintenance received no usable response.",
28
+ action: "Run /ctx-dream again.",
29
+ },
30
+ dream_no_models: {
31
+ code: "MC-D04",
32
+ sentence: "Memory maintenance has no model available.",
33
+ action: "Check the model settings, then run /ctx-dream again.",
34
+ },
35
+ dream_child_aborted: {
36
+ code: "MC-D05",
37
+ sentence: "Memory maintenance was interrupted.",
38
+ action: "Run /ctx-dream again.",
39
+ },
40
+ dream_parse_failed: {
41
+ code: "MC-D06",
42
+ sentence: "Memory maintenance could not use the model response.",
43
+ action: "Run /ctx-dream again.",
44
+ },
45
+ dream_unknown: {
46
+ code: "MC-D07",
47
+ sentence: "Memory maintenance could not finish.",
48
+ action: "Run /ctx-dream again.",
49
+ },
50
+ embedding_substitution_rejected: {
51
+ code: "MC-E01",
52
+ sentence: "Search indexing could not use the selected model.",
53
+ action: "Check the embedding model setting, then run /ctx-embed start again.",
54
+ },
55
+ embedding_http_error: {
56
+ code: "MC-E02",
57
+ sentence: "The search indexing provider refused the request.",
58
+ action: "Check the provider connection and credentials, then run /ctx-embed start again.",
59
+ },
60
+ embedding_transport_error: {
61
+ code: "MC-E03",
62
+ sentence: "Search indexing could not reach its provider.",
63
+ action: "Check the connection, then run /ctx-embed start again.",
64
+ },
65
+ embedding_invalid_envelope: {
66
+ code: "MC-E04",
67
+ sentence: "Search indexing received an unsupported response.",
68
+ action: "Check the embedding endpoint, then run /ctx-embed start again.",
69
+ },
70
+ embedding_empty_result: {
71
+ code: "MC-E05",
72
+ sentence: "Search indexing received no usable result.",
73
+ action: "Run /ctx-embed start again.",
74
+ },
75
+ embedding_certification_refusal: {
76
+ code: "MC-E06",
77
+ sentence: "Search indexing is not ready for this provider.",
78
+ action: "Finish the provider setup, or set a fallback provider in the embedding settings, then run /ctx-embed start again.",
79
+ },
80
+ embedding_credential_required: {
81
+ code: "MC-E07",
82
+ sentence: "Search indexing needs provider credentials.",
83
+ action: "Sign in to the provider, then run /ctx-embed start again.",
84
+ },
85
+ embedding_local_binding_missing: {
86
+ code: "MC-E08",
87
+ sentence: "Local search indexing is unavailable on this system.",
88
+ action: "Run `npx @cortexkit/magic-context doctor`, then retry.",
89
+ },
90
+ embedding_local_fs_unavailable: {
91
+ code: "MC-E09",
92
+ sentence: "Local search indexing cannot save its model files.",
93
+ action: "Update or reinstall Magic Context, then retry.",
94
+ },
95
+ embedding_local_download_failure: {
96
+ code: "MC-E10",
97
+ sentence: "Local search indexing could not download its model.",
98
+ action: "Check the network connection, then retry.",
99
+ },
100
+ embedding_local_runtime_error: {
101
+ code: "MC-E11",
102
+ sentence: "Local search indexing could not start.",
103
+ action: "Run `npx @cortexkit/magic-context doctor`, then retry.",
104
+ },
105
+ embedding_unavailable: {
106
+ code: "MC-E12",
107
+ sentence: "Search indexing could not finish.",
108
+ action: "Run /ctx-embed start again.",
109
+ },
110
+ status_unavailable: {
111
+ code: "MC-S01",
112
+ sentence: "Magic Context status is temporarily unavailable.",
113
+ action: "Retry /ctx-status in a moment.",
114
+ },
115
+ transform_update_failed: {
116
+ code: "MC-S02",
117
+ sentence: "The last context update did not finish.",
118
+ action: "Send another message to retry.",
119
+ },
120
+ configuration_warning: {
121
+ code: "MC-S03",
122
+ sentence: "Some configuration settings could not be applied.",
123
+ action: "Fix the configuration warning shown in /ctx-status diagnostics, then restart.",
124
+ },
125
+ status_log_unavailable: {
126
+ code: "MC-S04",
127
+ sentence: "Some diagnostic details could not be saved.",
128
+ action: "Retry /ctx-status in a moment.",
129
+ },
130
+ memory_writes_paused: {
131
+ code: "MC-C01",
132
+ sentence: "Memory writes are paused while the engine syncs.",
133
+ action: "Retry in a moment.",
134
+ },
135
+ memory_access_unavailable: {
136
+ code: "MC-C02",
137
+ sentence: "Memory access is temporarily unavailable.",
138
+ action: "Retry in a moment.",
139
+ },
140
+ note_changes_paused: {
141
+ code: "MC-C03",
142
+ sentence: "Note changes are paused while the engine syncs.",
143
+ action: "Retry in a moment.",
144
+ },
145
+ note_access_unavailable: {
146
+ code: "MC-C04",
147
+ sentence: "Notes are temporarily unavailable.",
148
+ action: "Retry in a moment.",
149
+ },
150
+ context_cleanup_paused: {
151
+ code: "MC-C05",
152
+ sentence: "Context cleanup is paused while the engine syncs.",
153
+ action: "Retry in a moment.",
154
+ },
155
+ partial_history_unavailable: {
156
+ code: "MC-C06",
157
+ sentence: "Partial history compression is not available in the current mode.",
158
+ action: "Run /ctx-recomp without a range.",
159
+ },
160
+ session_upgrade_unavailable: {
161
+ code: "MC-C07",
162
+ sentence: "Session upgrade is not available in the current mode.",
163
+ action: "Run /ctx-recomp instead.",
164
+ },
165
+ smart_note_conditions_unavailable: {
166
+ code: "MC-C08",
167
+ sentence: "Conditional notes are not available in the current mode.",
168
+ action: "Save a regular note without a condition.",
169
+ },
170
+ history_compression_paused: {
171
+ code: "MC-C09",
172
+ sentence: "History compression is paused while the engine syncs.",
173
+ action: "Retry in a moment.",
174
+ },
175
+ context_service_unavailable: {
176
+ code: "MC-C10",
177
+ sentence: "Magic Context is temporarily unavailable.",
178
+ action: "Retry in a moment.",
179
+ },
180
+ } as const;
181
+
182
+ export type UserFacingFailureKey = keyof typeof USER_FACING_FAILURES;
183
+
184
+ export type UserFacingTextStyle = "markdown" | "plain";
185
+
186
+ export function renderUserFacingFailure(
187
+ key: UserFacingFailureKey,
188
+ style: UserFacingTextStyle = "markdown",
189
+ ): string {
190
+ const failure = USER_FACING_FAILURES[key];
191
+ const action = style === "plain" ? failure.action.replaceAll("`", "") : failure.action;
192
+ return `${failure.sentence} ${action} (${failure.code})`;
193
+ }
194
+
195
+ export function userFacingFailureCode(key: UserFacingFailureKey): string {
196
+ return USER_FACING_FAILURES[key].code;
197
+ }
198
+
199
+ export type CapabilityRefusal =
200
+ | "memory_write"
201
+ | "memory_access"
202
+ | "note_change"
203
+ | "note_access"
204
+ | "context_cleanup"
205
+ | "partial_history"
206
+ | "session_upgrade"
207
+ | "smart_note_condition"
208
+ | "history_compression"
209
+ | "context_service";
210
+
211
+ const CAPABILITY_FAILURES: Record<CapabilityRefusal, UserFacingFailureKey> = {
212
+ memory_write: "memory_writes_paused",
213
+ memory_access: "memory_access_unavailable",
214
+ note_change: "note_changes_paused",
215
+ note_access: "note_access_unavailable",
216
+ context_cleanup: "context_cleanup_paused",
217
+ partial_history: "partial_history_unavailable",
218
+ session_upgrade: "session_upgrade_unavailable",
219
+ smart_note_condition: "smart_note_conditions_unavailable",
220
+ history_compression: "history_compression_paused",
221
+ context_service: "context_service_unavailable",
222
+ };
223
+
224
+ export function renderCapabilityRefusal(capability: CapabilityRefusal): string {
225
+ return renderUserFacingFailure(CAPABILITY_FAILURES[capability]);
226
+ }
227
+
228
+ export function capabilityRefusalCode(capability: CapabilityRefusal): string {
229
+ return userFacingFailureCode(CAPABILITY_FAILURES[capability]);
230
+ }
231
+
232
+ const DREAM_FAILURE_KEYS = {
233
+ provider_timeout: "dream_provider_timeout",
234
+ provider_error: "dream_provider_error",
235
+ empty_completion: "dream_empty_completion",
236
+ no_models: "dream_no_models",
237
+ child_aborted: "dream_child_aborted",
238
+ parse_failed: "dream_parse_failed",
239
+ unknown: "dream_unknown",
240
+ } as const satisfies Record<PromptFailureClass, UserFacingFailureKey>;
241
+
242
+ const EMBEDDING_FAILURE_KEYS = {
243
+ substitution_rejected: "embedding_substitution_rejected",
244
+ http_error: "embedding_http_error",
245
+ transport_error: "embedding_transport_error",
246
+ invalid_envelope: "embedding_invalid_envelope",
247
+ empty_result: "embedding_empty_result",
248
+ certification_refusal: "embedding_certification_refusal",
249
+ credential_required: "embedding_credential_required",
250
+ local_binding_missing: "embedding_local_binding_missing",
251
+ local_fs_unavailable: "embedding_local_fs_unavailable",
252
+ local_download_failure: "embedding_local_download_failure",
253
+ local_runtime_error: "embedding_local_runtime_error",
254
+ } as const satisfies Record<EmbeddingFailureClass, UserFacingFailureKey>;
255
+
256
+ export function renderDreamFailure(
257
+ failureClass: PromptFailureClass,
258
+ style: UserFacingTextStyle = "markdown",
259
+ ): string {
260
+ return renderUserFacingFailure(DREAM_FAILURE_KEYS[failureClass], style);
261
+ }
262
+
263
+ export function dreamFailureCode(failureClass: PromptFailureClass): string {
264
+ return userFacingFailureCode(DREAM_FAILURE_KEYS[failureClass]);
265
+ }
266
+
267
+ export function renderEmbeddingFailure(
268
+ failureClass: EmbeddingFailureClass,
269
+ style: UserFacingTextStyle = "markdown",
270
+ ): string {
271
+ return renderUserFacingFailure(EMBEDDING_FAILURE_KEYS[failureClass], style);
272
+ }
273
+
274
+ export function embeddingFailureCode(failureClass: EmbeddingFailureClass): string {
275
+ return userFacingFailureCode(EMBEDDING_FAILURE_KEYS[failureClass]);
276
+ }
package/src/tui/index.tsx CHANGED
@@ -1,7 +1,9 @@
1
1
  /** @jsxImportSource @opentui/solid */
2
2
  // @ts-nocheck
3
- import { createMemo } from "solid-js"
3
+ import { createMemo, createSignal } from "solid-js"
4
4
  import type { TuiPlugin, TuiPluginApi, TuiThemeCurrent } from "@opencode-ai/plugin/tui"
5
+ import { renderUserStatusSummary, statusSummaryFromDetail } from "../shared/status-summary"
6
+ import { renderUserFacingFailure, userFacingFailureCode } from '../shared/user-facing-codes';
5
7
  import {
6
8
  createSidebarContentSlot,
7
9
  kickRecompProgressRefresh,
@@ -138,10 +140,13 @@ const R = (props: { t: TuiThemeCurrent; l: string; v: string; fg?: string }) =>
138
140
  </box>
139
141
  )
140
142
 
141
- const StatusDialog = (props: { api: TuiPluginApi; s: StatusDetail }) => {
143
+ const StatusDialog = (props: { api: TuiPluginApi; s: StatusDetail; diagnostics?: boolean }) => {
142
144
  const theme = createMemo(() => (props.api as any).theme.current)
145
+ const [diagnostics, setDiagnostics] = createSignal(props.diagnostics === true)
143
146
  const t = () => theme()
144
147
  const s = () => props.s
148
+ const summaryLines = () =>
149
+ renderUserStatusSummary(statusSummaryFromDetail(s()), "plain").split("\n").slice(1)
145
150
  const compactionOff = () => s().compaction_enabled === false
146
151
 
147
152
  // Prefer the RPC-provided model context limit (what the sidebar shows) so the
@@ -230,6 +235,21 @@ const StatusDialog = (props: { api: TuiPluginApi; s: StatusDetail }) => {
230
235
  <text fg={t().textMuted}>v{packageJson.version}</text>
231
236
  </box>
232
237
 
238
+ <box
239
+ width="100%"
240
+ justifyContent="flex-end"
241
+ onMouseDown={() => setDiagnostics(!diagnostics())}
242
+ >
243
+ <text fg={diagnostics() ? t().accent : t().textMuted}>
244
+ {diagnostics() ? "[x]" : "[ ]"} Diagnostics
245
+ </text>
246
+ </box>
247
+
248
+ {!diagnostics() ? (
249
+ <box flexDirection="column" width="100%">
250
+ {summaryLines().map((line) => <text>{line}</text>)}
251
+ </box>
252
+ ) : (<>
233
253
  {s().configParseFailures.map((failure) => (
234
254
  <text fg={t().error}>{formatConfigParseStatusLine(failure)}</text>
235
255
  ))}
@@ -438,7 +458,7 @@ const StatusDialog = (props: { api: TuiPluginApi; s: StatusDetail }) => {
438
458
  {/* Error (full width, conditional) */}
439
459
  {s().lastTransformError && (
440
460
  <box marginTop={1} width="100%">
441
- <text fg={t().error}>⚠ {s().lastTransformError}</text>
461
+ <text fg={t().error}>{renderUserFacingFailure("transform_update_failed")}</text>
442
462
  </box>
443
463
  )}
444
464
 
@@ -451,12 +471,13 @@ const StatusDialog = (props: { api: TuiPluginApi; s: StatusDetail }) => {
451
471
  fg={(s().loggerDiagnostics?.swallowedWriteCount ?? 0) > 0 ? t().error : t().textMuted}
452
472
  />
453
473
  {s().loggerDiagnostics?.lastErrorMessage && (
454
- <R t={t()} l="Last error" v={s().loggerDiagnostics.lastErrorMessage} fg={t().error} />
474
+ <R t={t()} l="Warning" v={renderUserFacingFailure("status_unavailable")} fg={t().error} />
455
475
  )}
456
476
  {s().loggerDiagnostics?.lastErrorTime && (
457
477
  <R t={t()} l="Last error time" v={s().loggerDiagnostics.lastErrorTime} fg={t().textMuted} />
458
478
  )}
459
479
  </box>
480
+ </>)}
460
481
 
461
482
  {/* Footer */}
462
483
  <box marginTop={1} justifyContent="flex-end" width="100%">
@@ -617,7 +638,11 @@ function showUpgradeDialog(
617
638
  return true
618
639
  }
619
640
 
620
- async function showStatusDialog(api: TuiPluginApi, targetSessionId = getSessionId(api)): Promise<boolean> {
641
+ async function showStatusDialog(
642
+ api: TuiPluginApi,
643
+ targetSessionId = getSessionId(api),
644
+ initialDiagnostics = false,
645
+ ): Promise<boolean> {
621
646
  const sessionId = targetSessionId
622
647
  if (!sessionId) {
623
648
  showToast(api, { message: "No active session", variant: "warning" })
@@ -629,14 +654,19 @@ async function showStatusDialog(api: TuiPluginApi, targetSessionId = getSessionI
629
654
  const result = await loadStatusDetail(sessionId, directory, modelKey)
630
655
  if (getSessionId(api) !== sessionId) return false
631
656
  if (!result.ok) {
657
+ console.error(
658
+ `[magic-context] status unavailable code=${userFacingFailureCode("status_unavailable")}: ${result.error}`,
659
+ )
632
660
  showToast(api, {
633
- message: `Status unavailable: ${result.error}`,
661
+ message: renderUserFacingFailure("status_unavailable"),
634
662
  variant: "warning",
635
663
  })
636
664
  return false
637
665
  }
638
666
 
639
- api.ui.dialog.replace(() => <StatusDialog api={api} s={result.detail} />)
667
+ api.ui.dialog.replace(() => (
668
+ <StatusDialog api={api} s={result.detail} diagnostics={initialDiagnostics} />
669
+ ))
640
670
  return true
641
671
  }
642
672
 
@@ -1125,7 +1155,10 @@ const tui: TuiPlugin = async (api, _options, meta) => {
1125
1155
  const stillActive = () =>
1126
1156
  getRpcGeneration() === generation && getSessionId(api) === requestedSessionId
1127
1157
  if (action === "show-status-dialog") {
1128
- return stillActive() && (await showStatusDialog(api, requestedSessionId))
1158
+ return (
1159
+ stillActive() &&
1160
+ (await showStatusDialog(api, requestedSessionId, n.payload?.diagnostics === true))
1161
+ )
1129
1162
  }
1130
1163
  if (action === "show-recomp-dialog") {
1131
1164
  return stillActive() && (await showRecompDialog(api, requestedSessionId))