@cortexkit/opencode-magic-context 0.24.1 → 0.25.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 (93) hide show
  1. package/README.md +4 -2
  2. package/dist/agents/magic-context-prompt.d.ts.map +1 -1
  3. package/dist/features/magic-context/compartment-chunk-embedding.d.ts +8 -0
  4. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  5. package/dist/features/magic-context/memory/embedding-local.d.ts +4 -0
  6. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  7. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +6 -0
  8. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
  9. package/dist/features/magic-context/project-embedding-registry.d.ts +38 -0
  10. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  11. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  12. package/dist/features/magic-context/storage-meta-session.d.ts +1 -0
  13. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  14. package/dist/features/magic-context/storage-meta-shared.d.ts +2 -1
  15. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  16. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  17. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  18. package/dist/features/magic-context/storage-tags.d.ts +10 -0
  19. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  20. package/dist/features/magic-context/storage.d.ts +2 -2
  21. package/dist/features/magic-context/storage.d.ts.map +1 -1
  22. package/dist/features/magic-context/types.d.ts +1 -0
  23. package/dist/features/magic-context/types.d.ts.map +1 -1
  24. package/dist/hooks/magic-context/apply-operations.d.ts +3 -25
  25. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  26. package/dist/hooks/magic-context/caveman-cleanup.d.ts +1 -0
  27. package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -1
  28. package/dist/hooks/magic-context/channel2-delivery.d.ts +2 -0
  29. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  30. package/dist/hooks/magic-context/command-handler.d.ts +7 -5
  31. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  32. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +7 -2
  33. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  34. package/dist/hooks/magic-context/embed-session-state.d.ts +14 -0
  35. package/dist/hooks/magic-context/embed-session-state.d.ts.map +1 -0
  36. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/format-embed-status.d.ts +9 -0
  38. package/dist/hooks/magic-context/format-embed-status.d.ts.map +1 -0
  39. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +1 -0
  40. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  41. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  42. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  44. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts +1 -1
  45. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/strip-content.d.ts +0 -1
  47. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  48. package/dist/hooks/magic-context/tag-content-primitives.d.ts +2 -0
  49. package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -1
  50. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  51. package/dist/hooks/magic-context/tool-drop-target.d.ts +1 -1
  52. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  53. package/dist/hooks/magic-context/tool-reclaim.d.ts +12 -0
  54. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -0
  55. package/dist/hooks/magic-context/transform-operations.d.ts +1 -1
  56. package/dist/hooks/magic-context/transform-operations.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  58. package/dist/hooks/magic-context/transform.d.ts +2 -0
  59. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +1103 -408
  62. package/dist/plugin/conflict-warning-hook.d.ts.map +1 -1
  63. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  64. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  65. package/dist/shared/announcement.d.ts +1 -1
  66. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  67. package/dist/shared/rpc-types.d.ts +20 -0
  68. package/dist/shared/rpc-types.d.ts.map +1 -1
  69. package/dist/shared/sqlite.d.ts +5 -1
  70. package/dist/shared/sqlite.d.ts.map +1 -1
  71. package/dist/tools/ctx-expand/constants.d.ts +1 -1
  72. package/dist/tools/ctx-expand/constants.d.ts.map +1 -1
  73. package/dist/tools/ctx-expand/render.d.ts +43 -0
  74. package/dist/tools/ctx-expand/render.d.ts.map +1 -0
  75. package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
  76. package/dist/tools/ctx-expand/types.d.ts +6 -2
  77. package/dist/tools/ctx-expand/types.d.ts.map +1 -1
  78. package/dist/tools/ctx-reduce/constants.d.ts +1 -1
  79. package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
  80. package/dist/tui/data/context-db.d.ts +4 -2
  81. package/dist/tui/data/context-db.d.ts.map +1 -1
  82. package/package.json +1 -1
  83. package/src/shared/announcement.ts +6 -6
  84. package/src/shared/model-suggestion-retry.test.ts +61 -1
  85. package/src/shared/model-suggestion-retry.ts +22 -0
  86. package/src/shared/rpc-types.ts +11 -0
  87. package/src/shared/sqlite-bind-style.test.ts +82 -0
  88. package/src/shared/sqlite.ts +30 -1
  89. package/src/shared/tag-transcript.test.ts +3 -1
  90. package/src/shared/tag-transcript.ts +19 -17
  91. package/src/tui/data/context-db.ts +34 -2
  92. package/src/tui/index.tsx +58 -4
  93. package/src/tui/slots/sidebar-content.tsx +7 -2
@@ -1 +1 @@
1
- {"version":3,"file":"conflict-warning-hook.d.ts","sourceRoot":"","sources":["../../src/plugin/conflict-warning-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAsLlE;;GAEG;AACH,wBAAsB,mBAAmB,CACrC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,cAAc,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqDf;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CACzC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAwHf;AAkCD;;;GAGG;AACH,wBAAsB,wBAAwB,CAC1C,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAsEf;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CACxC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CACzC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,EAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACpC,OAAO,CAAC,IAAI,CAAC,CAkEf"}
1
+ {"version":3,"file":"conflict-warning-hook.d.ts","sourceRoot":"","sources":["../../src/plugin/conflict-warning-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAsLlE;;GAEG;AACH,wBAAsB,mBAAmB,CACrC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,cAAc,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqDf;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CACzC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAwHf;AAkCD;;;GAGG;AACH,wBAAsB,wBAAwB,CAC1C,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAsEf;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CACxC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CACzC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,EAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACpC,OAAO,CAAC,IAAI,CAAC,CAkFf"}
@@ -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;AAO7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;IACvC,gBAAgB,EAAE,gBAAgB,CAAC;CACtC;;;;;;qBAuDizK,CAAC;;;;;;;;;;;;qBAA93D,CAAC;mBAAyB,CAAC;iBAAuB,CAAC;iBAAuB,CAAC;0BAAc,CAAC;uBAAiB,CAAC;;;;;;0BAA+05B,CAAC;;;;;;EADh3gC"}
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;AAO7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;IACvC,gBAAgB,EAAE,gBAAgB,CAAC;CACtC;;;;;;qBAuDizK,CAAC;;;;;;;;;;;;qBAA93D,CAAC;mBAAyB,CAAC;iBAAuB,CAAC;iBAAuB,CAAC;0BAAc,CAAC;uBAAiB,CAAC;;;;;;0BAAsilC,CAAC;;;;;;EADvksC"}
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-handlers.d.ts","sourceRoot":"","sources":["../../src/plugin/rpc-handlers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEzE,OAAO,EACH,KAAK,eAAe,IAAI,QAAQ,EAGnC,MAAM,mCAAmC,CAAC;AAY3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAqBlF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA0FzE,wBAAgB,oBAAoB,CAChC,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,qBAAqB,CAAC,EAAE,MAAM,EAK9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,eAAe,CA2VjB;AAED,wBAAgB,iBAAiB,CAC7B,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,qBAAqB,CAAC,EAAE,MAAM,GAC/B,YAAY,CA+Jd;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,SAAS,EAAE,qBAAqB,EAChC,IAAI,EAAE;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,gBAAgB,CAAC;CACtC,GACF,IAAI,CAgON"}
1
+ {"version":3,"file":"rpc-handlers.d.ts","sourceRoot":"","sources":["../../src/plugin/rpc-handlers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGzE,OAAO,EACH,KAAK,eAAe,IAAI,QAAQ,EAGnC,MAAM,mCAAmC,CAAC;AAc3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAqBlF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAe,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA0FtF,wBAAgB,oBAAoB,CAChC,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,qBAAqB,CAAC,EAAE,MAAM,EAK9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,eAAe,CA2VjB;AAED,wBAAgB,iBAAiB,CAC7B,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,qBAAqB,CAAC,EAAE,MAAM,GAC/B,YAAY,CA+Jd;AA4BD;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,SAAS,EAAE,qBAAqB,EAChC,IAAI,EAAE;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,gBAAgB,CAAC;CACtC,GACF,IAAI,CAgPN"}
@@ -18,7 +18,7 @@
18
18
  * Bump only when there are user-visible changes worth a startup dialog.
19
19
  * Does NOT need to match the published package version.
20
20
  */
21
- export declare const ANNOUNCEMENT_VERSION = "0.24.0";
21
+ export declare const ANNOUNCEMENT_VERSION = "0.25.0";
22
22
  /**
23
23
  * Short, user-facing bullet strings. Keep each line ~80 chars or shorter so the
24
24
  * TUI dialog renders cleanly without horizontal scroll on a typical terminal.
@@ -1 +1 @@
1
- {"version":3,"file":"model-suggestion-retry.d.ts","sourceRoot":"","sources":["../../src/shared/model-suggestion-retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAM7D,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEtD,KAAK,UAAU,GAAG;IACd,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B,CAAC;AAEF,KAAK,UAAU,GAAG;IACd,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,WAAW,kBAAkB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACtB;AAiBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CA4C/E;AAuID;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kCAAkC,CACpD,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,kBAAuB,GACjC,OAAO,CAAC,IAAI,CAAC,CAgFf"}
1
+ {"version":3,"file":"model-suggestion-retry.d.ts","sourceRoot":"","sources":["../../src/shared/model-suggestion-retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAM7D,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEtD,KAAK,UAAU,GAAG;IACd,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B,CAAC;AAEF,KAAK,UAAU,GAAG;IACd,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,WAAW,kBAAkB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACtB;AAiBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CA4C/E;AA6JD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kCAAkC,CACpD,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,kBAAuB,GACjC,OAAO,CAAC,IAAI,CAAC,CAgFf"}
@@ -123,6 +123,26 @@ export interface StatusDetail extends SidebarSnapshot {
123
123
  compressionBudget: number | null;
124
124
  compressionUsage: string | null;
125
125
  }
126
+ /** Embedding coverage for `/ctx-embed` status (mirrors getEmbeddingCoverageStatus). */
127
+ export interface EmbedDetail {
128
+ enabled: boolean;
129
+ model: string;
130
+ provider: string;
131
+ session: {
132
+ embedded: number;
133
+ total: number;
134
+ };
135
+ memories: {
136
+ embedded: number;
137
+ total: number;
138
+ };
139
+ commits: {
140
+ embedded: number;
141
+ total: number;
142
+ gitEnabled: boolean;
143
+ };
144
+ statusText: string;
145
+ }
126
146
  export interface RpcNotificationMessage {
127
147
  id: number;
128
148
  type: string;
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-types.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rpc-types.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-types.ts"],"names":[],"mappings":"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"}
@@ -25,12 +25,16 @@
25
25
  * - db.transaction(fn) → wrapped function ← shimmed for node:sqlite
26
26
  * - db.close()
27
27
  *
28
- * The two backend differences we bridge for node:sqlite:
28
+ * The three backend differences we bridge for node:sqlite:
29
29
  * 1. node:sqlite has no `db.transaction(fn)` helper — we add a savepoint-aware
30
30
  * shim (below) that matches better-sqlite3/bun semantics.
31
31
  * 2. node:sqlite's constructor option is `readOnly` (camel-case), not
32
32
  * better-sqlite3/bun's `readonly` — we translate it so call sites are
33
33
  * unchanged.
34
+ * 3. node:sqlite reads a lone array bind arg (`.run([a,b])`) as NAMED params
35
+ * and throws `Unknown named parameter '0'`; bun binds it positionally. We
36
+ * normalize it in the `prepare()` override (below) so the bind surface is
37
+ * identical (issue #151 / Pi /ctx-dream).
34
38
  * Everything else (named params with bare keys, ATTACH under defensive mode,
35
39
  * `run()` → {changes,lastInsertRowid}) is identical and was verified directly.
36
40
  */
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/shared/sqlite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAMH,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAgGhD,eAAO,MAAM,QAAQ,EAAE,OAAO,aAA4B,CAAC;AAE3D,+DAA+D;AAC/D,MAAM,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC"}
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/shared/sqlite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAMH,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAyHhD,eAAO,MAAM,QAAQ,EAAE,OAAO,aAA4B,CAAC;AAE3D,+DAA+D;AAC/D,MAAM,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC"}
@@ -1,3 +1,3 @@
1
- export declare const CTX_EXPAND_DESCRIPTION = "Recover the original conversation from your compacted history.\n\nOlder parts of this session are summarized into <compartment> blocks inside <session-history> \u2014 e.g. <compartment start=\"120\" end=\"245\" title=\"Fixed tagger collision\">. Each one replaces the raw messages in that ordinal range with a summary. When the summary isn't enough \u2014 you need exact wording, a specific value, an error message, or the reasoning behind a decision \u2014 expand the range:\n\nctx_expand(start=120, end=245) \u2190 the compartment's own start/end attributes\n\nReturns the raw transcript as [N] U:/A: lines, capped at ~15K tokens; an oversized range returns the head and tells you where to continue. Also works with ordinals from ctx_search message results \u2014 expand a window around a hit (e.g. start=N-10, end=N+5). Ranges after the last compartment are your live tail \u2014 already visible in context, not expandable.";
1
+ export declare const CTX_EXPAND_DESCRIPTION = "Recover the original conversation from your compacted history.\n\nOlder parts of this session are summarized into <compartment> blocks inside <session-history> \u2014 e.g. <compartment start=\"120\" end=\"245\" title=\"Fixed tagger collision\">. Each one replaces the raw messages in that ordinal range with a summary. When the summary isn't enough \u2014 you need exact wording, a specific value, an error message, or the reasoning behind a decision \u2014 expand the range:\n\nctx_expand(start=120, end=245) \u2190 the compartment's own start/end attributes\n\nReturns the raw transcript as [N] U:/A: lines, capped at ~15K tokens; an oversized range returns the head and tells you where to continue. Also works with ordinals from ctx_search message results \u2014 expand a window around a hit (e.g. start=N-10, end=N+5). Ranges after the last compartment are your live tail \u2014 already visible in context, not expandable.\n\nTwo recovery modes for finer detail:\n- ctx_expand(start=120, end=245, verbose=true) \u2014 lists each message SEPARATELY with its ordinal [N] and a per-part preview (each tool call shown with its output size). Use this to find the exact message or tool call you want, then recover it in full by ordinal.\n- ctx_expand(message=138) \u2014 returns the FULL untruncated content of the message at that ordinal: every text part, and every tool call's complete input + output, read from stored history. This is the cheap way to get back a tool output you dropped with ctx_reduce \u2014 the original is still in storage even though the wire shows [dropped \u00A7N\u00A7]. If the message was deleted from history (session prune/revert), it says so.";
2
2
  export declare const CTX_EXPAND_TOKEN_BUDGET = 15000;
3
3
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-expand/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,o6BAM+T,CAAC;AAEnW,eAAO,MAAM,uBAAuB,QAAS,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-expand/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,6oDAU6X,CAAC;AAEja,eAAO,MAAM,uBAAuB,QAAS,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Verbose / by-id rendering for ctx_expand.
3
+ *
4
+ * The default ctx_expand range view returns a CONDENSED digest (turns merged,
5
+ * tool calls collapsed to `TC: name(arg)`). These two renderers add the recovery
6
+ * modes:
7
+ *
8
+ * - `renderVerboseRange`: every message shown SEPARATELY with its message id
9
+ * and a per-part preview, so the agent can see exactly what's in a range and
10
+ * pick the id of a specific message/tool call to recover in full.
11
+ * - `renderMessageById`: the FULL untruncated content of one message (any
12
+ * role) — every text part, and every tool call's complete input + output —
13
+ * read straight from the harness's stored history (opencode.db / Pi JSONL).
14
+ * This is the cheap way back from a `ctx_reduce` drop: the wire placeholder
15
+ * is `[dropped §N§]`, but the original output still lives in storage until
16
+ * the row is genuinely deleted (session prune/revert), in which case we say
17
+ * so rather than re-running the tool (which could now give a different
18
+ * answer).
19
+ *
20
+ * Both read through the shared provider-aware helpers, so Pi works by registering
21
+ * its `RawMessageProvider` for the call exactly like the range view does.
22
+ */
23
+ /**
24
+ * Full untruncated recovery of one message by its ORDINAL — the same `[N]`
25
+ * identifier the agent already uses everywhere (compartment start/end, ctx_search
26
+ * hits, the verbose range view). Returns a "deleted" message when no message sits
27
+ * at that ordinal (pruned/reverted or wrong ordinal).
28
+ */
29
+ export declare function renderMessageByOrdinal(sessionId: string, ordinal: number): string;
30
+ export interface VerboseRangeResult {
31
+ text: string;
32
+ /** Last ordinal actually rendered (for the continuation hint). */
33
+ lastOrdinal: number;
34
+ /** True when the budget cut the range short. */
35
+ truncated: boolean;
36
+ }
37
+ /**
38
+ * Verbose range view: every message in [start, end] shown separately, with its
39
+ * id and a per-part preview, bounded by `tokenBudget`. The agent reads the ids
40
+ * here and recovers any one message in full with ctx_expand(id=...).
41
+ */
42
+ export declare function renderVerboseRange(sessionId: string, start: number, end: number, tokenBudget: number): VerboseRangeResult;
43
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-expand/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAoLH;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAkBjF;AAED,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,SAAS,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,GACpB,kBAAkB,CA0BpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-expand/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAEhE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAK5E,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,eAAe,CAAC;CACvB;AAkED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAI5F"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-expand/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAEhE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAM5E,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,eAAe,CAAC;CACvB;AA8GD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAI5F"}
@@ -1,5 +1,9 @@
1
1
  export interface CtxExpandArgs {
2
- start: number;
3
- end: number;
2
+ start?: number;
3
+ end?: number;
4
+ /** Verbose range view: each message + tool call shown separately, with ordinals. */
5
+ verbose?: boolean;
6
+ /** Full untruncated recovery of one message (any role) by its ordinal. */
7
+ message?: number;
4
8
  }
5
9
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-expand/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACf"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-expand/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -1,2 +1,2 @@
1
- export declare const CTX_REDUCE_DESCRIPTION = "Reduce context by dropping tagged content you no longer need.\nUse \u00A7N\u00A7 identifiers visible in conversation. The `drop` param accepts ranges: \"3-5\", \"1,2,9\", \"1-5,8\".\n\nCRITICAL RULES:\n- NEVER blanket-drop large ranges (e.g., \"1-50\"). Always review what each tag contains first.\n- Only drop tool outputs you have already processed and no longer need.\n- Protected tags are accepted but deferred until they leave the last protected range.\n- Keep recent context \u2014 only reduce OLD content that is no longer relevant to current work.\n- Dropped content is gone forever.";
1
+ export declare const CTX_REDUCE_DESCRIPTION = "Mark spent tagged content as discardable to reclaim context space. This is NOT an immediate delete. Use \u00A7N\u00A7 identifiers visible in the conversation. The `drop` param accepts ranges: \"3-5\", \"1,2,9\", \"1-5,8\".\n\nHow it works:\n- Marking QUEUES content for release. It stays fully visible to you until context space is actually needed \u2014 which may be as soon as the next turn if you are already under pressure, or many turns later if not. So mark spent outputs as soon as you finish with them; don't hoard the call for the end of the turn.\n- The newest tags are protected: marking one just queues it until it ages out of the recent window, so marking recent output is harmless.\n- When content is finally released it becomes a short placeholder, and re-running the tool is the only way to get it back. So mark only what you are genuinely DONE with \u2014 the test is \"have I extracted what I need from this?\", not \"is it safe / do I have time before it drops?\".\n\nMark discardable once processed: large outputs you've summarized, repeated or redundant dumps, data written to disk, status/log output that only confirmed an expected state.\nKeep: user messages, unresolved errors, raw evidence you haven't extracted yet, and outputs whose exact wording may matter later.\nNever blanket-mark large ranges (e.g. \"1-50\") \u2014 review what each tag holds first.";
2
2
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-reduce/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,olBAQA,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-reduce/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,02CASoD,CAAC"}
@@ -1,5 +1,5 @@
1
- import type { SidebarSnapshot, StatusDetail } from "../../shared/rpc-types";
2
- export type { SidebarSnapshot, StatusDetail };
1
+ import type { EmbedDetail, SidebarSnapshot, StatusDetail } from "../../shared/rpc-types";
2
+ export type { EmbedDetail, SidebarSnapshot, StatusDetail };
3
3
  /** Initialize the RPC client. Call once on TUI startup. */
4
4
  export declare function initRpcClient(directory: string): void;
5
5
  export declare function getRpcGeneration(): number;
@@ -9,6 +9,8 @@ export declare function closeRpc(): void;
9
9
  export declare function loadSidebarSnapshot(sessionId: string, directory: string): Promise<SidebarSnapshot>;
10
10
  /** Fetch full status detail from the server via RPC. */
11
11
  export declare function loadStatusDetail(sessionId: string, directory: string, modelKey?: string): Promise<StatusDetail>;
12
+ /** Fetch embedding coverage status for `/ctx-embed` via RPC. */
13
+ export declare function loadEmbedDetail(sessionId: string, directory: string): Promise<EmbedDetail>;
12
14
  /** Get compartment count via RPC. */
13
15
  export declare function getCompartmentCount(sessionId: string): Promise<number>;
14
16
  /** Send recomp request to server via RPC. */
@@ -1 +1 @@
1
- {"version":3,"file":"context-db.d.ts","sourceRoot":"","sources":["../../../src/tui/data/context-db.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA0B,eAAe,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEpG,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AAe9C,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAOrD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,+BAA+B;AAC/B,wBAAgB,QAAQ,IAAI,IAAI,CAO/B;AA4FD,sDAAsD;AACtD,wBAAsB,mBAAmB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CA4B1B;AAED,wDAAwD;AACxD,wBAAsB,gBAAgB,CAClC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CAyCvB;AAED,qCAAqC;AACrC,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ5E;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQvE;AAED;mFACmF;AACnF,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQxE;AAED;;iDAEiD;AACjD,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUhF;AAED,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,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAkBrE;AAED,wEAAwE;AACxE,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAQtD;AAED,yDAAyD;AACzD,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAyBjF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAWtF"}
1
+ {"version":3,"file":"context-db.d.ts","sourceRoot":"","sources":["../../../src/tui/data/context-db.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACR,WAAW,EAEX,eAAe,EACf,YAAY,EACf,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AAe3D,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAOrD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,+BAA+B;AAC/B,wBAAgB,QAAQ,IAAI,IAAI,CAO/B;AA4FD,sDAAsD;AACtD,wBAAsB,mBAAmB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CA4B1B;AAED,wDAAwD;AACxD,wBAAsB,gBAAgB,CAClC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CAyCvB;AAYD,gEAAgE;AAChE,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAchG;AAED,qCAAqC;AACrC,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ5E;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQvE;AAED;mFACmF;AACnF,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQxE;AAED;;iDAEiD;AACjD,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUhF;AAED,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,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAkBrE;AAED,wEAAwE;AACxE,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAQtD;AAED,yDAAyD;AACzD,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAyBjF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAWtF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/opencode-magic-context",
3
- "version": "0.24.1",
3
+ "version": "0.25.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",
@@ -23,18 +23,18 @@ import { getMagicContextStorageDir } from "./data-path";
23
23
  * Bump only when there are user-visible changes worth a startup dialog.
24
24
  * Does NOT need to match the published package version.
25
25
  */
26
- export const ANNOUNCEMENT_VERSION = "0.24.0";
26
+ export const ANNOUNCEMENT_VERSION = "0.25.0";
27
27
 
28
28
  /**
29
29
  * Short, user-facing bullet strings. Keep each line ~80 chars or shorter so the
30
30
  * TUI dialog renders cleanly without horizontal scroll on a typical terminal.
31
31
  */
32
32
  export const ANNOUNCEMENT_FEATURES: ReadonlyArray<string> = [
33
- "Searchable session history: ctx_search can now find older discussion by meaning, not just keywords. New history is embedded automatically to backfill an EXISTING session's older history, run /ctx-embed-history once (it works in the background).",
34
- "Cross-project workspaces: group related repos and share project memories across them, with per-category control over what's shared. Set them up in the dashboard's Workspaces panel.",
35
- "Pi: fixed sessions overflowing the model context while still showing moderate usage Pi now sheds context before a tool-heavy turn overflows.",
36
- "Fewer prompt-cache busts: doc edits, processed screenshots, and a rebuild-then-bust-again case no longer re-bill large prompt prefixes.",
37
- "Setup wizard now lists your actual models with type-ahead instead of fixed recommendations, and explains the historian/dreamer roles (issue #144). Plus a GitHub Copilot tool-pairing fix (#135).",
33
+ "Old tool output is now reclaimed automatically: once a file read / search / command output has gone a full execute cycle unused, it's dropped on the next one no need to call ctx_reduce for stale results.",
34
+ "Recover anything that was dropped: ctx_expand({ message: N }) returns a dropped message's full content (every tool call's input + output) from storage. ctx_expand({ start, end, verbose: true }) lists a range message-by-message to find it.",
35
+ "Searchable history made reliable: /ctx-embed shows embedding coverage and runs a resilient backfill (retries transient failures, no longer bails on the first hiccup); the active session now auto-embeds in the background. ctx_reduce guidance also reframed as deferred + recoverable so models trim spent output earlier.",
36
+ "Pi: fixed /ctx-dream (was failing with 'Unknown named parameter') and local-embedding load failures on Windows/Desktop (#151, #128).",
37
+ "Runaway background agents on weak/local models are now capped and force-stopped (#154, #152). Plus several prompt-cache busts removed.",
38
38
  ];
39
39
 
40
40
  /**
@@ -7,10 +7,11 @@ type PromptCall = {
7
7
  signal?: AbortSignal;
8
8
  };
9
9
 
10
- function createClient(prompt: ReturnType<typeof mock>) {
10
+ function createClient(prompt: ReturnType<typeof mock>, abort?: ReturnType<typeof mock>) {
11
11
  return {
12
12
  session: {
13
13
  prompt,
14
+ abort: abort ?? mock(async () => ({})),
14
15
  },
15
16
  } as never;
16
17
  }
@@ -164,6 +165,65 @@ describe("promptSyncWithModelSuggestionRetry", () => {
164
165
  expect(prompt).toHaveBeenCalledTimes(1);
165
166
  });
166
167
 
168
+ // #154: our timeout must force-stop the child's SERVER-SIDE run loop via
169
+ // session.abort — cancelling our client fetch alone leaves the child looping
170
+ // the LLM past the timeout (uncancellable, only dies on process exit).
171
+ test("timeout fires session.abort on the child session", async () => {
172
+ // A prompt that respects the AbortController by hanging until aborted,
173
+ // then throwing — mirrors a real in-flight request our timeout cancels.
174
+ const prompt = mock((opts: { signal?: AbortSignal }) => {
175
+ return new Promise((_resolve, reject) => {
176
+ opts.signal?.addEventListener("abort", () => reject(new Error("aborted")));
177
+ });
178
+ });
179
+ const abort = mock(async () => ({}));
180
+ const client = createClient(prompt as never, abort);
181
+
182
+ await expect(
183
+ promptSyncWithModelSuggestionRetry(client, createArgs(), { timeoutMs: 20 }),
184
+ ).rejects.toThrow(/timed out/);
185
+ expect(abort).toHaveBeenCalledTimes(1);
186
+ expect((abort.mock.calls[0]?.[0] as { path: { id: string } }).path.id).toBe("ses-test");
187
+ });
188
+
189
+ // External abort (e.g. dreamer lease loss) mid-flight must also stop the
190
+ // server-side loop, not just our fetch.
191
+ test("external abort fires session.abort on the child session", async () => {
192
+ const controller = new AbortController();
193
+ const prompt = mock((opts: { signal?: AbortSignal }) => {
194
+ return new Promise((_resolve, reject) => {
195
+ opts.signal?.addEventListener("abort", () => reject(new Error("aborted")));
196
+ });
197
+ });
198
+ const abort = mock(async () => ({}));
199
+ const client = createClient(prompt as never, abort);
200
+
201
+ setTimeout(() => controller.abort(), 10);
202
+ await expect(
203
+ promptSyncWithModelSuggestionRetry(client, createArgs(), { signal: controller.signal }),
204
+ ).rejects.toThrow(/aborted by external signal/);
205
+ expect(abort).toHaveBeenCalledTimes(1);
206
+ expect((abort.mock.calls[0]?.[0] as { path: { id: string } }).path.id).toBe("ses-test");
207
+ });
208
+
209
+ // A failing session.abort must not mask the original timeout/abort error.
210
+ test("session.abort failure does not mask the timeout error", async () => {
211
+ const prompt = mock((opts: { signal?: AbortSignal }) => {
212
+ return new Promise((_resolve, reject) => {
213
+ opts.signal?.addEventListener("abort", () => reject(new Error("aborted")));
214
+ });
215
+ });
216
+ const abort = mock(async () => {
217
+ throw new Error("abort endpoint 500");
218
+ });
219
+ const client = createClient(prompt as never, abort);
220
+
221
+ await expect(
222
+ promptSyncWithModelSuggestionRetry(client, createArgs(), { timeoutMs: 20 }),
223
+ ).rejects.toThrow(/timed out/);
224
+ expect(abort).toHaveBeenCalledTimes(1);
225
+ });
226
+
167
227
  test("suggestion retry within attempt succeeds", async () => {
168
228
  const suggestionError = new Error("model not found");
169
229
  suggestionError.name = "ProviderModelNotFoundError";
@@ -143,9 +143,17 @@ async function promptWithTimeout(
143
143
  } as Parameters<typeof client.session.prompt>[0]);
144
144
  } catch (error) {
145
145
  if (signal?.aborted) {
146
+ // External abort (e.g. dreamer lease loss): the child run loop is an
147
+ // independent SERVER-SIDE fiber — cancelling our client fetch alone
148
+ // leaves it looping the LLM forever (issue #154). Force-stop it.
149
+ await abortChildRun(client, args.path.id);
146
150
  throw new Error("prompt aborted by external signal");
147
151
  }
148
152
  if (controller.signal.aborted) {
153
+ // Our timeout fired. Same problem: abort the server-side run loop, not
154
+ // just our fetch, or the child keeps re-calling the LLM past the
155
+ // timeout (uncancellable by the user's ESC — issue #154).
156
+ await abortChildRun(client, args.path.id);
149
157
  throw new Error(`prompt timed out after ${timeoutMs}ms`);
150
158
  }
151
159
  throw error;
@@ -155,6 +163,20 @@ async function promptWithTimeout(
155
163
  }
156
164
  }
157
165
 
166
+ /**
167
+ * Force-stop a spawned child session's server-side run loop. `controller.abort()`
168
+ * on the prompt signal only cancels OUR client fetch; the run loop is a separate
169
+ * instance-scoped fiber that `POST /session/{id}/abort` interrupts. Best-effort —
170
+ * a failure here must not mask the original timeout/abort error.
171
+ */
172
+ async function abortChildRun(client: Client, sessionId: string): Promise<void> {
173
+ try {
174
+ await client.session.abort({ path: { id: sessionId } });
175
+ } catch (error) {
176
+ log(`[model-retry] child session abort failed for ${sessionId}: ${String(error)}`);
177
+ }
178
+ }
179
+
158
180
  /**
159
181
  * Returns true if the error indicates a NON-RETRYABLE condition where iterating
160
182
  * to a fallback model would be pointless or harmful:
@@ -123,6 +123,17 @@ export interface StatusDetail extends SidebarSnapshot {
123
123
  compressionUsage: string | null;
124
124
  }
125
125
 
126
+ /** Embedding coverage for `/ctx-embed` status (mirrors getEmbeddingCoverageStatus). */
127
+ export interface EmbedDetail {
128
+ enabled: boolean;
129
+ model: string;
130
+ provider: string;
131
+ session: { embedded: number; total: number };
132
+ memories: { embedded: number; total: number };
133
+ commits: { embedded: number; total: number; gitEnabled: boolean };
134
+ statusText: string;
135
+ }
136
+
126
137
  export interface RpcNotificationMessage {
127
138
  id: number;
128
139
  type: string;
@@ -0,0 +1,82 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
3
+ import { join } from "node:path";
4
+
5
+ /**
6
+ * Guard: SQLite statement binds must use SPREAD positional args
7
+ * (`stmt.run(a, b)`), never the ARRAY form (`stmt.run([a, b])`).
8
+ *
9
+ * Why this is a CI guard, not just a style preference: bun:sqlite (OpenCode)
10
+ * binds a lone array positionally, but node:sqlite (Pi, OpenCode Desktop) reads
11
+ * it as NAMED params ("0","1") and throws `Unknown named parameter '0'`. An
12
+ * array-form bind therefore passes every OpenCode/Bun test yet breaks Pi/Desktop
13
+ * silently — exactly how issue #151 (/ctx-dream) shipped. The sqlite.ts
14
+ * chokepoint now normalizes array binds for node:sqlite so it can no longer
15
+ * CRASH, but the array form is still discouraged: it relies on the shim, reads
16
+ * inconsistently with the rest of the codebase (all spread), and the guard
17
+ * catches it at PR time so the shim stays a safety net, not a crutch.
18
+ */
19
+
20
+ // Scan EVERY package's src, not just plugin's. pi-plugin and cli have no
21
+ // sqlite.ts of their own — they run on the shared chokepoint — so an array-form
22
+ // bind written in their code would break under node:sqlite (Pi/Desktop) exactly
23
+ // like #151, and the plugin-only scan would never see it. Roots are resolved
24
+ // relative to plugin/src so the guard works from the plugin package.
25
+ const PLUGIN_SRC = join(import.meta.dir, "..");
26
+ const SCAN_ROOTS = [
27
+ PLUGIN_SRC,
28
+ join(PLUGIN_SRC, "../../pi-plugin/src"),
29
+ join(PLUGIN_SRC, "../../cli/src"),
30
+ ].filter((dir) => existsSync(dir));
31
+ // The chokepoint itself documents the pattern in prose/comments; the guard's own
32
+ // source mentions it; allow those two (relative to whichever root contains them).
33
+ const ALLOWED = new Set(["shared/sqlite.ts", "shared/sqlite-bind-style.test.ts"]);
34
+ // `stmt.run([` / `.get([` / `.all([` — but `.all([` also matches Promise.all([.
35
+ const BIND_PATTERN = /\.(run|get|all)\(\[/;
36
+
37
+ function collectTsFiles(dir: string, acc: string[] = []): string[] {
38
+ for (const entry of readdirSync(dir)) {
39
+ const full = join(dir, entry);
40
+ const st = statSync(full);
41
+ if (st.isDirectory()) {
42
+ collectTsFiles(full, acc);
43
+ } else if (entry.endsWith(".ts") && !entry.endsWith(".test.ts")) {
44
+ acc.push(full);
45
+ }
46
+ }
47
+ return acc;
48
+ }
49
+
50
+ describe("sqlite bind style", () => {
51
+ it("uses spread positional binds, never the array form", () => {
52
+ const violations: string[] = [];
53
+ for (const root of SCAN_ROOTS) {
54
+ for (const file of collectTsFiles(root)) {
55
+ const rel = file.slice(root.length + 1);
56
+ if (ALLOWED.has(rel)) continue;
57
+ const lines = readFileSync(file, "utf8").split("\n");
58
+ lines.forEach((line, i) => {
59
+ if (!BIND_PATTERN.test(line)) return;
60
+ // Promise.all([...]) is not a SQLite statement bind.
61
+ if (line.includes("Promise.all(")) return;
62
+ // Skip comment lines.
63
+ const trimmed = line.trim();
64
+ if (trimmed.startsWith("//") || trimmed.startsWith("*")) return;
65
+ // Disambiguate which package the hit is in.
66
+ const pkg = root.includes("pi-plugin")
67
+ ? "pi-plugin"
68
+ : root.includes("cli")
69
+ ? "cli"
70
+ : "plugin";
71
+ violations.push(`${pkg}/${rel}:${i + 1} ${trimmed}`);
72
+ });
73
+ }
74
+ }
75
+ expect(
76
+ violations,
77
+ `Array-form SQLite binds found — use spread positional .run(a, b) ` +
78
+ `instead of .run([a, b]) (breaks under node:sqlite on Pi/Desktop):\n` +
79
+ violations.join("\n"),
80
+ ).toEqual([]);
81
+ });
82
+ });
@@ -25,12 +25,16 @@
25
25
  * - db.transaction(fn) → wrapped function ← shimmed for node:sqlite
26
26
  * - db.close()
27
27
  *
28
- * The two backend differences we bridge for node:sqlite:
28
+ * The three backend differences we bridge for node:sqlite:
29
29
  * 1. node:sqlite has no `db.transaction(fn)` helper — we add a savepoint-aware
30
30
  * shim (below) that matches better-sqlite3/bun semantics.
31
31
  * 2. node:sqlite's constructor option is `readOnly` (camel-case), not
32
32
  * better-sqlite3/bun's `readonly` — we translate it so call sites are
33
33
  * unchanged.
34
+ * 3. node:sqlite reads a lone array bind arg (`.run([a,b])`) as NAMED params
35
+ * and throws `Unknown named parameter '0'`; bun binds it positionally. We
36
+ * normalize it in the `prepare()` override (below) so the bind surface is
37
+ * identical (issue #151 / Pi /ctx-dream).
34
38
  * Everything else (named params with bare keys, ATTACH under defensive mode,
35
39
  * `run()` → {changes,lastInsertRowid}) is identical and was verified directly.
36
40
  */
@@ -104,6 +108,31 @@ function buildNodeSqliteDatabaseClass(DatabaseSync: any): typeof BetterSqlite3 {
104
108
  super(typeof filename === "string" ? filename : ":memory:", translated);
105
109
  }
106
110
 
111
+ // Normalize a single ARRAY bind arg to spread positional, matching
112
+ // bun:sqlite. bun's `.run([a,b])` binds positionally; node:sqlite instead
113
+ // reads a lone array as NAMED params with keys "0","1" and throws
114
+ // `Unknown named parameter '0'`. That divergence let an array-form bind
115
+ // (e.g. `.run([x, y])`) silently work on OpenCode/Bun yet break Pi and
116
+ // OpenCode Desktop (both node:sqlite) — issue #151 (/ctx-dream). Wrapping
117
+ // every prepared statement here keeps the two backends' bind surface
118
+ // truly identical so this whole class is impossible regardless of how a
119
+ // call site writes its bind. Named-object binds (`.run({k:v})`), no-arg
120
+ // calls, and already-spread positional args are passed through unchanged;
121
+ // the normalization only triggers on the exact 1-array shape. Overhead
122
+ // measured at ~12ns/call against real node:sqlite (negligible).
123
+ // biome-ignore lint/suspicious/noExplicitAny: node:sqlite StatementSync has no shipped types here.
124
+ prepare(sql: string): any {
125
+ const stmt = super.prepare(sql);
126
+ for (const method of ["run", "get", "all"] as const) {
127
+ const original = stmt[method].bind(stmt);
128
+ stmt[method] = (...args: unknown[]): unknown =>
129
+ args.length === 1 && Array.isArray(args[0])
130
+ ? original(...args[0])
131
+ : original(...args);
132
+ }
133
+ return stmt;
134
+ }
135
+
107
136
  // biome-ignore lint/suspicious/noExplicitAny: mirrors better-sqlite3's generic transaction(fn) signature.
108
137
  transaction<F extends (...args: any[]) => any>(fn: F): F {
109
138
  // biome-ignore lint/suspicious/noExplicitAny: faithful pass-through of this/args to fn.
@@ -203,7 +203,9 @@ describe("tagTranscript tool aggregation", () => {
203
203
  result = targets.get(tag ?? -1)?.truncate?.();
204
204
  }).not.toThrow();
205
205
  expect(result).toBe("truncated");
206
- expect(toolUse.getText()).toBe("[truncated]");
206
+ // Skeleton-drop now renders the one canonical placeholder, not a
207
+ // separate "[truncated]" vocabulary.
208
+ expect(toolUse.getText()).toBe(`[dropped \u00a7${tag}\u00a7]`);
207
209
  });
208
210
 
209
211
  it("drops every contiguous folded tool_result block for the paired callId", () => {