dsh-continual-evolve 0.11.0 → 0.12.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 (154) hide show
  1. package/README.md +35 -115
  2. package/README.zh.md +26 -93
  3. package/cordis.patch.yml +2 -2
  4. package/lib/index.d.ts +44 -225
  5. package/lib/index.js +30 -239
  6. package/lib/memory-guide.d.ts +13 -14
  7. package/lib/memory-guide.js +32 -21
  8. package/lib/memory-section.d.ts +77 -0
  9. package/lib/memory-section.js +189 -0
  10. package/package.json +2 -17
  11. package/lib/apply.d.ts +0 -22
  12. package/lib/apply.js +0 -157
  13. package/lib/approval.d.ts +0 -73
  14. package/lib/approval.js +0 -127
  15. package/lib/audit-log.d.ts +0 -19
  16. package/lib/audit-log.js +0 -52
  17. package/lib/auto.d.ts +0 -236
  18. package/lib/auto.js +0 -773
  19. package/lib/autocase.d.ts +0 -38
  20. package/lib/autocase.js +0 -76
  21. package/lib/benchmark-command.d.ts +0 -9
  22. package/lib/benchmark-command.js +0 -357
  23. package/lib/benchmark.d.ts +0 -151
  24. package/lib/benchmark.js +0 -250
  25. package/lib/command-util.d.ts +0 -70
  26. package/lib/command-util.js +0 -123
  27. package/lib/command.d.ts +0 -13
  28. package/lib/command.js +0 -134
  29. package/lib/consolidate.d.ts +0 -90
  30. package/lib/consolidate.js +0 -180
  31. package/lib/copy.d.ts +0 -37
  32. package/lib/copy.js +0 -58
  33. package/lib/declines.d.ts +0 -103
  34. package/lib/declines.js +0 -179
  35. package/lib/evaluate.d.ts +0 -74
  36. package/lib/evaluate.js +0 -271
  37. package/lib/evolve-event.d.ts +0 -40
  38. package/lib/evolve-event.js +0 -60
  39. package/lib/extraction-phase.d.ts +0 -132
  40. package/lib/extraction-phase.js +0 -236
  41. package/lib/failures.d.ts +0 -42
  42. package/lib/failures.js +0 -171
  43. package/lib/fate.d.ts +0 -130
  44. package/lib/fate.js +0 -350
  45. package/lib/goal-command.d.ts +0 -7
  46. package/lib/goal-command.js +0 -37
  47. package/lib/goal.d.ts +0 -72
  48. package/lib/goal.js +0 -72
  49. package/lib/inject.d.ts +0 -90
  50. package/lib/inject.js +0 -164
  51. package/lib/injection-caps.d.ts +0 -4
  52. package/lib/injection-caps.js +0 -4
  53. package/lib/injection-directory.d.ts +0 -29
  54. package/lib/injection-directory.js +0 -78
  55. package/lib/injection-rank.d.ts +0 -85
  56. package/lib/injection-rank.js +0 -161
  57. package/lib/listener.d.ts +0 -45
  58. package/lib/listener.js +0 -199
  59. package/lib/llm-text.d.ts +0 -104
  60. package/lib/llm-text.js +0 -140
  61. package/lib/logfile.d.ts +0 -71
  62. package/lib/logfile.js +0 -159
  63. package/lib/maintenance-commands.d.ts +0 -23
  64. package/lib/maintenance-commands.js +0 -136
  65. package/lib/memory-agent.d.ts +0 -93
  66. package/lib/memory-agent.js +0 -300
  67. package/lib/memory-apply.d.ts +0 -44
  68. package/lib/memory-apply.js +0 -202
  69. package/lib/memory-benchmark.d.ts +0 -76
  70. package/lib/memory-benchmark.js +0 -170
  71. package/lib/memory-index.d.ts +0 -114
  72. package/lib/memory-index.js +0 -197
  73. package/lib/memory-manifest.d.ts +0 -16
  74. package/lib/memory-manifest.js +0 -70
  75. package/lib/message-source.d.ts +0 -23
  76. package/lib/message-source.js +0 -12
  77. package/lib/mount-command.d.ts +0 -10
  78. package/lib/mount-command.js +0 -48
  79. package/lib/mount.d.ts +0 -42
  80. package/lib/mount.js +0 -212
  81. package/lib/notify.d.ts +0 -48
  82. package/lib/notify.js +0 -57
  83. package/lib/plan-command.d.ts +0 -12
  84. package/lib/plan-command.js +0 -38
  85. package/lib/plan.d.ts +0 -16
  86. package/lib/plan.js +0 -126
  87. package/lib/planner.d.ts +0 -61
  88. package/lib/planner.js +0 -144
  89. package/lib/pool.d.ts +0 -7
  90. package/lib/pool.js +0 -25
  91. package/lib/prefix-cache.d.ts +0 -79
  92. package/lib/prefix-cache.js +0 -168
  93. package/lib/project.d.ts +0 -28
  94. package/lib/project.js +0 -66
  95. package/lib/projection.d.ts +0 -22
  96. package/lib/projection.js +0 -112
  97. package/lib/promotion.d.ts +0 -94
  98. package/lib/promotion.js +0 -171
  99. package/lib/recall.d.ts +0 -85
  100. package/lib/recall.js +0 -142
  101. package/lib/record-language.d.ts +0 -85
  102. package/lib/record-language.js +0 -152
  103. package/lib/render.d.ts +0 -13
  104. package/lib/render.js +0 -80
  105. package/lib/review-scheduler.d.ts +0 -38
  106. package/lib/review-scheduler.js +0 -183
  107. package/lib/review.d.ts +0 -60
  108. package/lib/review.js +0 -145
  109. package/lib/rollback.d.ts +0 -9
  110. package/lib/rollback.js +0 -68
  111. package/lib/rubric.d.ts +0 -29
  112. package/lib/rubric.js +0 -119
  113. package/lib/runtime-commands.d.ts +0 -14
  114. package/lib/runtime-commands.js +0 -115
  115. package/lib/runtime.d.ts +0 -24
  116. package/lib/runtime.js +0 -87
  117. package/lib/score.d.ts +0 -64
  118. package/lib/score.js +0 -191
  119. package/lib/search.d.ts +0 -83
  120. package/lib/search.js +0 -136
  121. package/lib/service.d.ts +0 -63
  122. package/lib/service.js +0 -253
  123. package/lib/skill-render.d.ts +0 -23
  124. package/lib/skill-render.js +0 -69
  125. package/lib/skill.d.ts +0 -15
  126. package/lib/skill.js +0 -80
  127. package/lib/skillquality.d.ts +0 -85
  128. package/lib/skillquality.js +0 -320
  129. package/lib/source.d.ts +0 -30
  130. package/lib/source.js +0 -43
  131. package/lib/state.d.ts +0 -26
  132. package/lib/state.js +0 -151
  133. package/lib/store.d.ts +0 -61
  134. package/lib/store.js +0 -164
  135. package/lib/token-usage.d.ts +0 -68
  136. package/lib/token-usage.js +0 -211
  137. package/lib/tool.d.ts +0 -34
  138. package/lib/tool.js +0 -320
  139. package/lib/turn-snapshot.d.ts +0 -78
  140. package/lib/turn-snapshot.js +0 -252
  141. package/lib/types.d.ts +0 -218
  142. package/lib/types.js +0 -133
  143. package/lib/usage.d.ts +0 -36
  144. package/lib/usage.js +0 -98
  145. package/lib/validate.d.ts +0 -28
  146. package/lib/validate.js +0 -181
  147. package/lib/wrapup-candidates.d.ts +0 -127
  148. package/lib/wrapup-candidates.js +0 -161
  149. package/lib/wrapup-command.d.ts +0 -10
  150. package/lib/wrapup-command.js +0 -243
  151. package/lib/wrapup-proposals.d.ts +0 -101
  152. package/lib/wrapup-proposals.js +0 -281
  153. package/lib/wrapup.d.ts +0 -56
  154. package/lib/wrapup.js +0 -105
@@ -1,19 +1,18 @@
1
1
  /**
2
- * The persistent-memory guide injected as part of the `evolve:memory-index`
3
- * system-prompt section (evolve v2, change two).
2
+ * The persistent-memory guide injected as part of the memory section.
4
3
  *
5
- * This text is the write-path half of the v2 plan: it teaches the model when a
6
- * durable memory is worth creating, which recall type it belongs to, what body
7
- * structure each type owes, and that the main session may write directly with
8
- * `evolve_add` instead of waiting for the background pipeline.
4
+ * This text is the write-path half of the ZCode-aligned design: it teaches
5
+ * the model when a durable memory is worth creating, which type it belongs
6
+ * to, what body structure each type owes, and that memories are plain
7
+ * markdown files written directly with the native file tools — the plugin
8
+ * registers no tools and no commands.
9
9
  *
10
- * Provenance: `docs/research/evolve-v2-passive-read-write-plan.md` §改动二
11
- * (Chinese full text, adapted from ZCode's persistent-memory prompt). Kept in
12
- * its own module so the wording is a single home — `memory-index.ts` only
13
- * composes it with the `<memories>` block.
10
+ * Provenance: the when_to_save taxonomy is adapted from ZCode's persistent-
11
+ * memory prompt (introduced here in evolve v2); the write-path wording now
12
+ * targets native file operations on `<workspace>/.evolve/memory/`.
14
13
  */
15
- /** Heading and framing before the `<memories>` block. */
16
- export declare const MEMORY_GUIDE_INTRO = "# \u6301\u4E45\u8BB0\u5FC6\n\n\u4F60\u6709\u4E00\u4E2A\u8DE8\u4F1A\u8BDD\u7684\u6301\u4E45\u8BB0\u5FC6\u7CFB\u7EDF\u3002\u4EE5\u4E0B\u662F\u5F53\u524D\u8BB0\u5FC6\uFF08\u5DF2\u76F4\u63A5\u6CE8\u5165\uFF0C\u65E0\u9700\u67E5\u8BE2\u5373\u53EF\u4F7F\u7528\uFF1B\u9700\u8981\u68C0\u7D22\u5B8C\u6574\u5185\u5BB9\u6216\u786E\u8BA4\u662F\u5426\u6709\u76F8\u5173\u8BB0\u5FC6\u65F6\uFF0C\u8C03\u7528 evolve_recall\uFF09\u3002\u672C\u4F1A\u8BDD\u5185\u53EF\u4EE5\u76F4\u63A5\u7528 evolve_add \u843D\u76D8\uFF0C\u4E0D\u5FC5\u7B49\u540E\u53F0\u6D41\u7A0B\u2014\u2014\u9ED8\u8BA4\u5199 local\uFF0C\u53EA\u6709\u7A33\u5B9A\u7684\u8DE8\u9879\u76EE\u6559\u8BAD\u624D\u5199 global\uFF08global \u5199\u5165\u4F1A\u5F39\u4EBA\u5DE5\u6279\u51C6\uFF09\u3002";
17
- /** The when_to_save / how_to_use rules and maintenance discipline. */
18
- export declare const MEMORY_GUIDE_RULES = "## \u4F55\u65F6\u5199\u5165\u8BB0\u5FC6\n\n\u7528\u6237\u660E\u786E\u8981\u6C42\u8BB0\u4F4F\u65F6\uFF0C\u7ACB\u5373\u5B58\u4E3A\u6700\u5408\u9002\u7684\u7C7B\u578B\uFF1B\u8981\u6C42\u5FD8\u8BB0\u65F6\uFF0C\u627E\u5230\u5E76\u5220\u9664\u76F8\u5173\u6761\u76EE\u3002\n\u9664\u6B64\u4E4B\u5916\uFF0C\u5728\u5BF9\u8BDD\u4E2D\u81EA\u7136\u9047\u5230\u4EE5\u4E0B\u4FE1\u53F7\u65F6\u4E3B\u52A8\u5199\u5165\u3002\u5B58\u4E4B\u524D\u5148\u8FC7\u4E00\u9053\u7B5B\u5B50\uFF1A\n**\u80FD\u4ECE\u4EE3\u7801\u3001git \u5386\u53F2\u3001\u4ED3\u5E93\u6587\u4EF6\u91CC\u91CD\u65B0\u63A8\u5BFC\u51FA\u6765\u7684\u4E8B\u5B9E\u4E0D\u5B58**\u2014\u2014\u53EA\u5B58\u91CD\u63A8\u5BFC\u4E0D\u51FA\u6765\u7684\n\u80CC\u666F\u3001\u51B3\u7B56\u548C\u504F\u597D\u3002\u76F8\u5BF9\u65E5\u671F\u4E00\u5F8B\u8F6C\u6210\u7EDD\u5BF9\u65E5\u671F\uFF08\"\u5468\u56DB\"\u2192\"2026-10-08\"\uFF09\uFF0C\u5426\u5219\u672A\u6765\n\u7684\u4F1A\u8BDD\u65E0\u6CD5\u89E3\u8BFB\u3002\u4E00\u6761\u4E8B\u5B9E\u4E00\u4E2A\u6761\u76EE\uFF1B\u4E0D\u786E\u5B9A\u503C\u4E0D\u503C\u5F97\u5B58\u65F6\uFF0C\u95EE\u81EA\u5DF1\"\u8FD9\u6761\u7684\u4FE1\u606F\u91CF\n\u662F\u5426\u5728'\u4E3A\u4EC0\u4E48'\u91CC\uFF0C\u800C\u4E0D\u5728'\u662F\u4EC0\u4E48'\u91CC\"\u3002\n\n<type name=\"user\">\n <when_to_save>\u5F97\u77E5\u7528\u6237\u7684\u89D2\u8272\u3001\u6280\u672F\u6808\u3001\u7ECF\u9A8C\u6C34\u5E73\u3001\u504F\u597D\u6216\u77E5\u8BC6\u80CC\u666F\u7684\u4EFB\u4F55\u7EC6\u8282\u65F6\u3002\n \u4F8B\u5982\u7528\u6237\u81EA\u8FF0\"\u6211\u662F\u6570\u636E\u79D1\u5B66\u5BB6\uFF0C\u5728\u67E5\u65E5\u5FD7\u7CFB\u7EDF\"\u2014\u2014\u5B58\uFF1A\u7528\u6237\u662F\u6570\u636E\u79D1\u5B66\u5BB6\uFF0C\n \u5F53\u524D\u5173\u6CE8\u53EF\u89C2\u6D4B\u6027/\u65E5\u5FD7\u3002</when_to_save>\n <how_to_use>\u540E\u7EED\u89E3\u91CA\u548C\u5EFA\u8BAE\u6309\u7528\u6237\u7684\u80CC\u666F\u5B9A\u5236\u6DF1\u6D45\u4E0E\u7C7B\u6BD4\uFF1B\u5BF9\u8D44\u6DF1\u5DE5\u7A0B\u5E08\n \u4E0D\u89E3\u91CA\u57FA\u7840\u6982\u5FF5\uFF0C\u5BF9\u67D0\u9886\u57DF\u7684\u65B0\u624B\u7528\u5176\u719F\u6089\u9886\u57DF\u7684\u7C7B\u6BD4\u5207\u5165\u3002</how_to_use>\n</type>\n\n<type name=\"feedback\">\n <when_to_save>\u4E24\u6761\u4FE1\u53F7\uFF0C\u7F3A\u4E00\u4E0D\u53EF\uFF1A\n \uFF081\uFF09\u7EA0\u6B63\u2014\u2014\u7528\u6237\u8BF4\"\u4E0D\u662F\u8FD9\u6837\"\"\u522B\"\"\u505C\u4E0B\"\u65F6\uFF0C\u5B58\u88AB\u7EA0\u6B63\u7684\u505A\u6CD5\u4E0E\u6B63\u786E\u505A\u6CD5\uFF1B\n \uFF082\uFF09\u786E\u8BA4\u2014\u2014\u8FD9\u662F\u66F4\u5B89\u9759\u3001\u66F4\u5BB9\u6613\u6F0F\u7684\u4FE1\u53F7\uFF1A\u7528\u6237\u63A5\u53D7\u4E86\u4F60\u4E0D\u5BFB\u5E38\u7684\u9009\u62E9\u800C\u6CA1\u6709\u5F02\u8BAE\uFF0C\n \u6216\u660E\u786E\u8BF4\"\u5BF9\uFF0C\u5C31\u8FD9\u6837\"\"\u4FDD\u6301\u8FD9\u6837\"\u3002\u786E\u8BA4\u8FC7\u7684\u5224\u65AD\u662F\u5DF2\u9A8C\u8BC1\u7684\u65B9\u6CD5\u8BBA\uFF0C\u53EA\u5B58\u7EA0\u9519\n \u4F1A\u8BA9\u4F60\u7684\u884C\u4E3A\u8D8A\u6765\u8D8A\u4FDD\u5B88\u3001\u504F\u79BB\u7528\u6237\u5DF2\u8BA4\u53EF\u7684\u8DEF\u3002\n \u4F8B\uFF1A\"\u6D4B\u8BD5\u522B mock \u6570\u636E\u5E93\uFF0C\u4E0A\u6B21 mock \u8FC7\u4E86\u7EBF\u4E0A\u8FC1\u79FB\u6302\u4E86\"\u2014\u2014\u5B58\u89C4\u5219\u5E76\u5E26\u4E0A\u4E8B\u6545\u539F\u56E0\u3002\n \u4F8B\uFF1A\"\u7ED3\u5C3E\u4E0D\u7528\u603B\u7ED3\uFF0Cdiff \u6211\u81EA\u5DF1\u4F1A\u770B\"\u2014\u2014\u5B58\uFF1A\u8BE5\u7528\u6237\u4E0D\u8981\u5C3E\u968F\u6027\u603B\u7ED3\u3002</when_to_save>\n <how_to_use>\u8BA9\u7528\u6237\u4E0D\u5FC5\u628A\u540C\u4E00\u6761\u6307\u5BFC\u8BF4\u7B2C\u4E8C\u904D\u3002</how_to_use>\n <body_structure>\u89C4\u5219\u5148\u884C\uFF0C\u968F\u540E\u5FC5\u5E26\u4E24\u884C\uFF1A**Why:**\uFF08\u7528\u6237\u7ED9\u7684\u7406\u7531\uFF0C\u5E38\u662F\u67D0\u6B21\n \u4E8B\u6545\u6216\u5F3A\u504F\u597D\u2014\u2014\u77E5\u9053\u4E3A\u4EC0\u4E48\u624D\u80FD\u5224\u65AD\u8FB9\u7F18\u60C5\u51B5\u8BE5\u4E0D\u8BE5\u7834\u4F8B\uFF09\u548C **How to apply:**\n \uFF08\u4F55\u65F6\u4F55\u5730\u751F\u6548\uFF09\u3002feedback \u7C7B\u578B\u7F3A\u8FD9\u4E24\u884C\u89C6\u4E3A\u4E0D\u5B8C\u6574\u3002</body_structure>\n</type>\n\n<type name=\"project\">\n <when_to_save>\u5F97\u77E5\u8FDB\u884C\u4E2D\u7684\u5DE5\u4F5C\u3001\u76EE\u6807\u3001\u51B3\u7B56\u3001\u622A\u6B62\u671F\u6216\u4E8B\u6545\u7684\u80CC\u666F\u52A8\u673A\u65F6\u2014\u2014\n \u51E1\u662F\"\u8C01\u5728\u505A\u4EC0\u4E48\u3001\u4E3A\u4EC0\u4E48\u3001\u5230\u4EC0\u4E48\u65F6\u5019\"\u4E14\u65E0\u6CD5\u4ECE\u4EE3\u7801\u6216 git \u63A8\u5BFC\u7684\u4FE1\u606F\u3002\n \u8FD9\u7C7B\u8BB0\u5FC6\u8870\u51CF\u5FEB\uFF0C\u72B6\u6001\u53D8\u5316\u65F6\u66F4\u65B0\u5B83\uFF0C\u522B\u5806\u53E0\u65B0\u6761\u76EE\u3002</when_to_save>\n <how_to_use>\u7528\u5B83\u8865\u5168\u8BF7\u6C42\u80CC\u540E\u7684\u4E0A\u4E0B\u6587\u4E0E\u52A8\u673A\uFF0C\u8BA9\u5EFA\u8BAE\u8D34\u4F4F\u771F\u5B9E\u7EA6\u675F\u3002\n \u4F8B\uFF1A\"\u5468\u56DB\u8D77\u51BB\u7ED3\u5408\u5E76\"\u2014\u2014\u5B58\uFF1A2026-03-05 \u8D77\u51BB\u7ED3\u5408\u5E76\uFF0C\u975E\u5173\u952E PR \u63D0\u524D\u6807\u8BB0\u3002</how_to_use>\n <body_structure>\u4E8B\u5B9E/\u51B3\u7B56\u5148\u884C + **Why:**\uFF08\u52A8\u673A\uFF1A\u7EA6\u675F\u3001deadline\u3001\u5E72\u7CFB\u4EBA\u8981\u6C42\uFF09\n + **How to apply:**\uFF08\u8FD9\u6761\u5982\u4F55\u5F71\u54CD\u540E\u7EED\u5EFA\u8BAE\uFF09\u3002</body_structure>\n</type>\n\n<type name=\"reference\">\n <when_to_save>\u7528\u6237\u63D0\u5230\u672A\u6765\u4F1A\u7528\u5230\u7684\u5916\u90E8\u8D44\u6E90\u6307\u9488\uFF1AURL\u3001\u4EEA\u8868\u76D8\u3001\u5DE5\u5355\u3001\n \u6587\u6863\u4F4D\u7F6E\u3002</when_to_save>\n <how_to_use>\u9700\u8981\u65F6\u76F4\u63A5\u53D6\u7528\uFF0C\u4E0D\u91CD\u65B0\u68C0\u7D22\u3002</how_to_use>\n</type>\n\n## \u5982\u4F55\u7EF4\u62A4\n\n- \u66F4\u65B0\u4F18\u5148\u4E8E\u65B0\u5EFA\uFF1A\u72B6\u6001\u53D8\u4E86\u6539\u539F\u6761\u76EE\uFF0C\u4E0D\u53E6\u8D77\u4E00\u6761\uFF08\u65B0\u65E7\u5E76\u5B58\u6BD4\u6CA1\u6709\u8BB0\u5FC6\u66F4\u7CDF\uFF09\u3002\n- \u6BCF\u6761\u7684 description \u662F\u7ED9\u672A\u6765\u4F1A\u8BDD\u7684\u76F8\u5173\u6027 hook\u2014\u2014\u5199\"\u51B3\u5B9A\u4E86\u4E00\u6761\u8BB0\u5FC6\u4F1A\u4E0D\u4F1A\n \u88AB\u60F3\u8D77\"\u7684\u4E00\u53E5\u8BDD\uFF0C\u4E0D\u5199\u6D41\u6C34\u8D26\u3002\n- [[\u540D\u5B57]] \u4E92\u76F8\u5F15\u7528\u76F8\u5173\u8BB0\u5FC6\uFF1B\u5F15\u7528\u8FD8\u4E0D\u5B58\u5728\u7684\u540D\u5B57\u662F\u5408\u6CD5\u7684\uFF0C\u5B83\u6807\u8BB0\"\u503C\u5F97\u5C06\u6765\u8865\u5199\"\u3002";
14
+ /** Heading and framing before the `<memories>` block. Takes the absolute memory dir. */
15
+ export declare function memoryGuideIntro(memoryDir: string): string;
16
+ /** The file format, when_to_save / how_to_use rules, and maintenance discipline. */
17
+ export declare const MEMORY_GUIDE_RULES = "## \u8BB0\u5FC6\u6587\u4EF6\u7684\u683C\u5F0F\n\n---\nname: <\u77ED\u6A2A\u7EBF\u5C0F\u5199\u6807\u8BC6>\ndescription: <\u4E00\u53E5\u8BDD\u76F8\u5173\u6027\u94A9\u5B50\u2014\u2014\u51B3\u5B9A\u672A\u6765\u4F1A\u8BDD\u4F1A\u4E0D\u4F1A\u60F3\u8D77\u8FD9\u6761\u8BB0\u5FC6>\nmetadata:\n type: user | feedback | project | reference\n---\n\n<\u6B63\u6587>\n\n## \u4F55\u65F6\u5199\u5165\u8BB0\u5FC6\n\n\u7528\u6237\u660E\u786E\u8981\u6C42\u8BB0\u4F4F\u65F6\uFF0C\u7ACB\u5373\u5B58\u4E3A\u6700\u5408\u9002\u7684\u7C7B\u578B\uFF1B\u8981\u6C42\u5FD8\u8BB0\u65F6\uFF0C\u627E\u5230\u5E76\u5220\u9664\u76F8\u5173\u6587\u4EF6\u4E0E\u7D22\u5F15\u884C\u3002\n\u9664\u6B64\u4E4B\u5916\uFF0C\u5728\u5BF9\u8BDD\u4E2D\u81EA\u7136\u9047\u5230\u4EE5\u4E0B\u4FE1\u53F7\u65F6\u4E3B\u52A8\u5199\u5165\u3002\u5B58\u4E4B\u524D\u5148\u8FC7\u4E00\u9053\u7B5B\u5B50\uFF1A\n**\u80FD\u4ECE\u4EE3\u7801\u3001git \u5386\u53F2\u3001\u4ED3\u5E93\u6587\u4EF6\u91CC\u91CD\u65B0\u63A8\u5BFC\u51FA\u6765\u7684\u4E8B\u5B9E\u4E0D\u5B58**\u2014\u2014\u53EA\u5B58\u91CD\u63A8\u5BFC\u4E0D\u51FA\u6765\u7684\n\u80CC\u666F\u3001\u51B3\u7B56\u548C\u504F\u597D\u3002\u76F8\u5BF9\u65E5\u671F\u4E00\u5F8B\u8F6C\u6210\u7EDD\u5BF9\u65E5\u671F\uFF08\"\u5468\u56DB\"\u2192\"2026-10-08\"\uFF09\uFF0C\u5426\u5219\u672A\u6765\n\u7684\u4F1A\u8BDD\u65E0\u6CD5\u89E3\u8BFB\u3002\u4E00\u6761\u4E8B\u5B9E\u4E00\u4E2A\u6587\u4EF6\uFF1B\u4E0D\u786E\u5B9A\u503C\u4E0D\u503C\u5F97\u5B58\u65F6\uFF0C\u95EE\u81EA\u5DF1\"\u8FD9\u6761\u7684\u4FE1\u606F\u91CF\n\u662F\u5426\u5728'\u4E3A\u4EC0\u4E48'\u91CC\uFF0C\u800C\u4E0D\u5728'\u662F\u4EC0\u4E48'\u91CC\"\u3002\n\n<type name=\"user\">\n <when_to_save>\u5F97\u77E5\u7528\u6237\u7684\u89D2\u8272\u3001\u6280\u672F\u6808\u3001\u7ECF\u9A8C\u6C34\u5E73\u3001\u504F\u597D\u6216\u77E5\u8BC6\u80CC\u666F\u7684\u4EFB\u4F55\u7EC6\u8282\u65F6\u3002\n \u4F8B\u5982\u7528\u6237\u81EA\u8FF0\"\u6211\u662F\u6570\u636E\u79D1\u5B66\u5BB6\uFF0C\u5728\u67E5\u65E5\u5FD7\u7CFB\u7EDF\"\u2014\u2014\u5B58\uFF1A\u7528\u6237\u662F\u6570\u636E\u79D1\u5B66\u5BB6\uFF0C\n \u5F53\u524D\u5173\u6CE8\u53EF\u89C2\u6D4B\u6027/\u65E5\u5FD7\u3002</when_to_save>\n <how_to_use>\u540E\u7EED\u89E3\u91CA\u548C\u5EFA\u8BAE\u6309\u7528\u6237\u7684\u80CC\u666F\u5B9A\u5236\u6DF1\u6D45\u4E0E\u7C7B\u6BD4\uFF1B\u5BF9\u8D44\u6DF1\u5DE5\u7A0B\u5E08\n \u4E0D\u89E3\u91CA\u57FA\u7840\u6982\u5FF5\uFF0C\u5BF9\u67D0\u9886\u57DF\u7684\u65B0\u624B\u7528\u5176\u719F\u6089\u9886\u57DF\u7684\u7C7B\u6BD4\u5207\u5165\u3002</how_to_use>\n</type>\n\n<type name=\"feedback\">\n <when_to_save>\u4E24\u6761\u4FE1\u53F7\uFF0C\u7F3A\u4E00\u4E0D\u53EF\uFF1A\n \uFF081\uFF09\u7EA0\u6B63\u2014\u2014\u7528\u6237\u8BF4\"\u4E0D\u662F\u8FD9\u6837\"\"\u522B\"\"\u505C\u4E0B\"\u65F6\uFF0C\u5B58\u88AB\u7EA0\u6B63\u7684\u505A\u6CD5\u4E0E\u6B63\u786E\u505A\u6CD5\uFF1B\n \uFF082\uFF09\u786E\u8BA4\u2014\u2014\u8FD9\u662F\u66F4\u5B89\u9759\u3001\u66F4\u5BB9\u6613\u6F0F\u7684\u4FE1\u53F7\uFF1A\u7528\u6237\u63A5\u53D7\u4E86\u4F60\u4E0D\u5BFB\u5E38\u7684\u9009\u62E9\u800C\u6CA1\u6709\u5F02\u8BAE\uFF0C\n \u6216\u660E\u786E\u8BF4\"\u5BF9\uFF0C\u5C31\u8FD9\u6837\"\"\u4FDD\u6301\u8FD9\u6837\"\u3002\u786E\u8BA4\u8FC7\u7684\u5224\u65AD\u662F\u5DF2\u9A8C\u8BC1\u7684\u65B9\u6CD5\u8BBA\uFF0C\u53EA\u5B58\u7EA0\u9519\n \u4F1A\u8BA9\u4F60\u7684\u884C\u4E3A\u8D8A\u6765\u8D8A\u4FDD\u5B88\u3001\u504F\u79BB\u7528\u6237\u5DF2\u8BA4\u53EF\u7684\u8DEF\u3002\n \u4F8B\uFF1A\"\u6D4B\u8BD5\u522B mock \u6570\u636E\u5E93\uFF0C\u4E0A\u6B21 mock \u8FC7\u4E86\u7EBF\u4E0A\u8FC1\u79FB\u6302\u4E86\"\u2014\u2014\u5B58\u89C4\u5219\u5E76\u5E26\u4E0A\u4E8B\u6545\u539F\u56E0\u3002\n \u4F8B\uFF1A\"\u7ED3\u5C3E\u4E0D\u7528\u603B\u7ED3\uFF0Cdiff \u6211\u81EA\u5DF1\u4F1A\u770B\"\u2014\u2014\u5B58\uFF1A\u8BE5\u7528\u6237\u4E0D\u8981\u5C3E\u968F\u6027\u603B\u7ED3\u3002</when_to_save>\n <how_to_use>\u8BA9\u7528\u6237\u4E0D\u5FC5\u628A\u540C\u4E00\u6761\u6307\u5BFC\u8BF4\u7B2C\u4E8C\u904D\u3002</how_to_use>\n <body_structure>\u89C4\u5219\u5148\u884C\uFF0C\u968F\u540E\u5FC5\u5E26\u4E24\u884C\uFF1A**Why:**\uFF08\u7528\u6237\u7ED9\u7684\u7406\u7531\uFF0C\u5E38\u662F\u67D0\u6B21\n \u4E8B\u6545\u6216\u5F3A\u504F\u597D\u2014\u2014\u77E5\u9053\u4E3A\u4EC0\u4E48\u624D\u80FD\u5224\u65AD\u8FB9\u7F18\u60C5\u51B5\u8BE5\u4E0D\u8BE5\u7834\u4F8B\uFF09\u548C **How to apply:**\n \uFF08\u4F55\u65F6\u4F55\u5730\u751F\u6548\uFF09\u3002feedback \u7C7B\u578B\u7F3A\u8FD9\u4E24\u884C\u89C6\u4E3A\u4E0D\u5B8C\u6574\u3002</body_structure>\n</type>\n\n<type name=\"project\">\n <when_to_save>\u5F97\u77E5\u8FDB\u884C\u4E2D\u7684\u5DE5\u4F5C\u3001\u76EE\u6807\u3001\u51B3\u7B56\u3001\u622A\u6B62\u671F\u6216\u4E8B\u6545\u7684\u80CC\u666F\u52A8\u673A\u65F6\u2014\u2014\n \u51E1\u662F\"\u8C01\u5728\u505A\u4EC0\u4E48\u3001\u4E3A\u4EC0\u4E48\u3001\u5230\u4EC0\u4E48\u65F6\u5019\"\u4E14\u65E0\u6CD5\u4ECE\u4EE3\u7801\u6216 git \u63A8\u5BFC\u7684\u4FE1\u606F\u3002\n \u8FD9\u7C7B\u8BB0\u5FC6\u8870\u51CF\u5FEB\uFF0C\u72B6\u6001\u53D8\u5316\u65F6\u66F4\u65B0\u5B83\uFF0C\u522B\u5806\u53E0\u65B0\u6587\u4EF6\u3002</when_to_save>\n <how_to_use>\u7528\u5B83\u8865\u5168\u8BF7\u6C42\u80CC\u540E\u7684\u4E0A\u4E0B\u6587\u4E0E\u52A8\u673A\uFF0C\u8BA9\u5EFA\u8BAE\u8D34\u4F4F\u771F\u5B9E\u7EA6\u675F\u3002\n \u4F8B\uFF1A\"\u5468\u56DB\u8D77\u51BB\u7ED3\u5408\u5E76\"\u2014\u2014\u5B58\uFF1A2026-03-05 \u8D77\u51BB\u7ED3\u5408\u5E76\uFF0C\u975E\u5173\u952E PR \u63D0\u524D\u6807\u8BB0\u3002</how_to_use>\n <body_structure>\u4E8B\u5B9E/\u51B3\u7B56\u5148\u884C + **Why:**\uFF08\u52A8\u673A\uFF1A\u7EA6\u675F\u3001deadline\u3001\u5E72\u7CFB\u4EBA\u8981\u6C42\uFF09\n + **How to apply:**\uFF08\u8FD9\u6761\u5982\u4F55\u5F71\u54CD\u540E\u7EED\u5EFA\u8BAE\uFF09\u3002</body_structure>\n</type>\n\n<type name=\"reference\">\n <when_to_save>\u7528\u6237\u63D0\u5230\u672A\u6765\u4F1A\u7528\u5230\u7684\u5916\u90E8\u8D44\u6E90\u6307\u9488\uFF1AURL\u3001\u4EEA\u8868\u76D8\u3001\u5DE5\u5355\u3001\n \u6587\u6863\u4F4D\u7F6E\u3002</when_to_save>\n <how_to_use>\u9700\u8981\u65F6\u76F4\u63A5\u53D6\u7528\uFF0C\u4E0D\u91CD\u65B0\u68C0\u7D22\u3002</how_to_use>\n</type>\n\n## \u5982\u4F55\u7EF4\u62A4\n\n- \u5199\u5B8C\u8BB0\u5FC6\u6587\u4EF6\u540E\u7ACB\u5373\u5728 MEMORY.md \u8FFD\u52A0\u6216\u66F4\u65B0\u4E00\u884C\u7D22\u5F15\uFF1A`- [\u6807\u9898](\u6587\u4EF6\u540D.md) \u2014 \u94A9\u5B50`\uFF1B\u72B6\u6001\u53D8\u5316\u65F6\u539F\u6587\u4E0E\u7D22\u5F15\u884C\u4E00\u8D77\u6539\uFF0C\u522B\u8BA9\u7D22\u5F15\u8BF4\u8C0E\u3002\n- \u66F4\u65B0\u4F18\u5148\u4E8E\u65B0\u5EFA\uFF1A\u72B6\u6001\u53D8\u4E86\u6539\u539F\u6587\u4EF6\uFF0C\u4E0D\u53E6\u8D77\u4E00\u6761\uFF08\u65B0\u65E7\u5E76\u5B58\u6BD4\u6CA1\u6709\u8BB0\u5FC6\u66F4\u7CDF\uFF09\u3002\n- [[\u540D\u5B57]] \u4E92\u76F8\u5F15\u7528\u76F8\u5173\u8BB0\u5FC6\uFF1B\u5F15\u7528\u8FD8\u4E0D\u5B58\u5728\u7684\u540D\u5B57\u662F\u5408\u6CD5\u7684\uFF0C\u5B83\u6807\u8BB0\"\u503C\u5F97\u5C06\u6765\u8865\u5199\"\u3002";
19
18
  //# sourceMappingURL=memory-guide.d.ts.map
@@ -1,29 +1,41 @@
1
1
  /**
2
- * The persistent-memory guide injected as part of the `evolve:memory-index`
3
- * system-prompt section (evolve v2, change two).
2
+ * The persistent-memory guide injected as part of the memory section.
4
3
  *
5
- * This text is the write-path half of the v2 plan: it teaches the model when a
6
- * durable memory is worth creating, which recall type it belongs to, what body
7
- * structure each type owes, and that the main session may write directly with
8
- * `evolve_add` instead of waiting for the background pipeline.
4
+ * This text is the write-path half of the ZCode-aligned design: it teaches
5
+ * the model when a durable memory is worth creating, which type it belongs
6
+ * to, what body structure each type owes, and that memories are plain
7
+ * markdown files written directly with the native file tools — the plugin
8
+ * registers no tools and no commands.
9
9
  *
10
- * Provenance: `docs/research/evolve-v2-passive-read-write-plan.md` §改动二
11
- * (Chinese full text, adapted from ZCode's persistent-memory prompt). Kept in
12
- * its own module so the wording is a single home — `memory-index.ts` only
13
- * composes it with the `<memories>` block.
10
+ * Provenance: the when_to_save taxonomy is adapted from ZCode's persistent-
11
+ * memory prompt (introduced here in evolve v2); the write-path wording now
12
+ * targets native file operations on `<workspace>/.evolve/memory/`.
14
13
  */
15
- /** Heading and framing before the `<memories>` block. */
16
- export const MEMORY_GUIDE_INTRO = `# 持久记忆
14
+ /** Heading and framing before the `<memories>` block. Takes the absolute memory dir. */
15
+ export function memoryGuideIntro(memoryDir) {
16
+ return `# 持久记忆
17
17
 
18
- 你有一个跨会话的持久记忆系统。以下是当前记忆(已直接注入,无需查询即可使用;需要检索完整内容或确认是否有相关记忆时,调用 evolve_recall)。本会话内可以直接用 evolve_add 落盘,不必等后台流程——默认写 local,只有稳定的跨项目教训才写 global(global 写入会弹人工批准)。`;
19
- /** The when_to_save / how_to_use rules and maintenance discipline. */
20
- export const MEMORY_GUIDE_RULES = `## 何时写入记忆
18
+ 你有一个跨会话的持久记忆系统,存放在 \`${memoryDir}/\`:一事一文,\`MEMORY.md\` 是索引,其内容已注入在下方。没有专用命令或工具——直接用你的文件读写工具查看、新建、修改、删除记忆文件,并在同一会话内顺手落盘。`;
19
+ }
20
+ /** The file format, when_to_save / how_to_use rules, and maintenance discipline. */
21
+ export const MEMORY_GUIDE_RULES = `## 记忆文件的格式
21
22
 
22
- 用户明确要求记住时,立即存为最合适的类型;要求忘记时,找到并删除相关条目。
23
+ ---
24
+ name: <短横线小写标识>
25
+ description: <一句话相关性钩子——决定未来会话会不会想起这条记忆>
26
+ metadata:
27
+ type: user | feedback | project | reference
28
+ ---
29
+
30
+ <正文>
31
+
32
+ ## 何时写入记忆
33
+
34
+ 用户明确要求记住时,立即存为最合适的类型;要求忘记时,找到并删除相关文件与索引行。
23
35
  除此之外,在对话中自然遇到以下信号时主动写入。存之前先过一道筛子:
24
36
  **能从代码、git 历史、仓库文件里重新推导出来的事实不存**——只存重推导不出来的
25
37
  背景、决策和偏好。相对日期一律转成绝对日期("周四"→"2026-10-08"),否则未来
26
- 的会话无法解读。一条事实一个条目;不确定值不值得存时,问自己"这条的信息量
38
+ 的会话无法解读。一条事实一个文件;不确定值不值得存时,问自己"这条的信息量
27
39
  是否在'为什么'里,而不在'是什么'里"。
28
40
 
29
41
  <type name="user">
@@ -51,7 +63,7 @@ export const MEMORY_GUIDE_RULES = `## 何时写入记忆
51
63
  <type name="project">
52
64
  <when_to_save>得知进行中的工作、目标、决策、截止期或事故的背景动机时——
53
65
  凡是"谁在做什么、为什么、到什么时候"且无法从代码或 git 推导的信息。
54
- 这类记忆衰减快,状态变化时更新它,别堆叠新条目。</when_to_save>
66
+ 这类记忆衰减快,状态变化时更新它,别堆叠新文件。</when_to_save>
55
67
  <how_to_use>用它补全请求背后的上下文与动机,让建议贴住真实约束。
56
68
  例:"周四起冻结合并"——存:2026-03-05 起冻结合并,非关键 PR 提前标记。</how_to_use>
57
69
  <body_structure>事实/决策先行 + **Why:**(动机:约束、deadline、干系人要求)
@@ -66,8 +78,7 @@ export const MEMORY_GUIDE_RULES = `## 何时写入记忆
66
78
 
67
79
  ## 如何维护
68
80
 
69
- - 更新优先于新建:状态变了改原条目,不另起一条(新旧并存比没有记忆更糟)。
70
- - 每条的 description 是给未来会话的相关性 hook——写"决定了一条记忆会不会
71
- 被想起"的一句话,不写流水账。
81
+ - 写完记忆文件后立即在 MEMORY.md 追加或更新一行索引:\`- [标题](文件名.md) — 钩子\`;状态变化时原文与索引行一起改,别让索引说谎。
82
+ - 更新优先于新建:状态变了改原文件,不另起一条(新旧并存比没有记忆更糟)。
72
83
  - [[名字]] 互相引用相关记忆;引用还不存在的名字是合法的,它标记"值得将来补写"。`;
73
84
  //# sourceMappingURL=memory-guide.js.map
@@ -0,0 +1,77 @@
1
+ /** Name of the injected section (unique — duplicate names throw upstream). */
2
+ export declare const MEMORY_SECTION_NAME = "evolve:memory-index";
3
+ /** Default prompt-section order (empty 1–499 slot; upstream named slots start at 500). */
4
+ export declare const DEFAULT_MEMORY_SECTION_ORDER = 400;
5
+ /** Default hard character budget for the injected index. */
6
+ export declare const DEFAULT_MAX_CHARS = 6000;
7
+ /** Sessions whose frozen section text is kept before LRU eviction. */
8
+ export declare const DEFAULT_FROZEN_SESSIONS = 32;
9
+ /** The assembling agent's validated absolute cwd, or undefined when absent. */
10
+ export declare function cwdOf(agent: unknown): string | undefined;
11
+ /** Absolute memory directory for a workspace root. */
12
+ export declare function memoryDirFor(cwd: string): string;
13
+ /**
14
+ * Ensure `.evolve/` is ignored when the workspace is a git repository, so
15
+ * the memory store never shows up in git status. Best-effort hygiene: a
16
+ * non-git workspace (no `.git` entry at the cwd) is left untouched — no
17
+ * `.gitignore` is created — and any write failure is swallowed.
18
+ */
19
+ export declare function ensureGitIgnored(cwd: string): void;
20
+ /**
21
+ * Ensure the store exists (creating the directory and a starter index on
22
+ * first use), then return the trimmed index text. Any filesystem failure
23
+ * degrades to "" — injection must never break an assembly.
24
+ */
25
+ export declare function readMemoryIndex(dir: string, bootstrap?: boolean): string;
26
+ /** What fitting the index into the budget produced. */
27
+ export interface IndexFit {
28
+ /** Index text actually shown (possibly truncated to a line boundary). */
29
+ text: string;
30
+ /** Characters dropped by the budget, 0 when the index fit whole. */
31
+ dropped: number;
32
+ }
33
+ /**
34
+ * Whole-line-preserving truncation of the index to `maxChars` characters.
35
+ * Only index rows that fit whole are shown — a partial markdown row would
36
+ * corrupt the line the model reads. When not even one row fits, `text` is
37
+ * "" and `dropped` carries the full length.
38
+ */
39
+ export declare function fitIndex(index: string, maxChars: number): IndexFit;
40
+ /** Options for {@link memorySectionText}. */
41
+ export interface MemorySectionOptions {
42
+ /** Hard character budget for the injected index (default 6000). */
43
+ maxChars?: number;
44
+ /** Include the when_to_save guide (default true). */
45
+ guide?: boolean;
46
+ /** Skip store bootstrap (tests). */
47
+ bootstrap?: boolean;
48
+ }
49
+ /**
50
+ * Compose the full memory section for one assembling agent: the guide
51
+ * wrapped around the budget-bounded index, with the absolute store path
52
+ * handed out so the model can read and write the files directly. With the
53
+ * guide off and an empty index the result is "" — the prompt renderer then
54
+ * drops the section, so an empty workspace costs zero tokens.
55
+ */
56
+ export declare function memorySectionText(agent: unknown, opts?: MemorySectionOptions): string;
57
+ /** A per-session frozen view of the memory section text. */
58
+ export interface FrozenMemorySection {
59
+ /**
60
+ * The section text for this agent: built on first use per agent id and
61
+ * reused byte-for-byte afterwards. An agent without an id is rebuilt on
62
+ * every call (nothing to key the cache on).
63
+ */
64
+ textFor(agent: unknown, build: (agent: unknown) => string): string;
65
+ /** Sessions currently frozen (test/observability hook). */
66
+ size(): number;
67
+ /** Drop every frozen session (tests; a restart rebuilds naturally). */
68
+ clear(): void;
69
+ }
70
+ /**
71
+ * Freeze the section text per agent id. The frozen value is what keeps the
72
+ * system prompt stable across a session's assemblies (prompt-cache guard);
73
+ * bounded by `maxSessions` with insertion-order (LRU) eviction, so a
74
+ * long-lived process cannot grow without limit.
75
+ */
76
+ export declare function createFrozenMemorySection(maxSessions?: number): FrozenMemorySection;
77
+ //# sourceMappingURL=memory-section.d.ts.map
@@ -0,0 +1,189 @@
1
+ /**
2
+ * The whole runtime of the plugin after the 2026-10-04 ZCode-alignment
3
+ * teardown: the session-start memory section.
4
+ *
5
+ * The store is plain markdown inside the workspace — `<cwd>/.evolve/memory/`
6
+ * with a `MEMORY.md` index and one file per fact — so the model reads and
7
+ * writes it with its native file tools (DSH fences only out-of-workspace
8
+ * writes; dot-directories inside the workspace pass both ways). This module
9
+ * hands out the absolute path, injects the index content, and wraps the
10
+ * when-to-save guide around it. There are no tools, no scopes, and no
11
+ * governance: the files are the store, and a bad memory is a visible file
12
+ * the user deletes.
13
+ *
14
+ * Session-freeze contract (the prompt-cache guard): the section is computed
15
+ * once per agent id and reused byte-for-byte afterwards, so the system
16
+ * prompt stays stable within a session and cache reads keep hitting. A
17
+ * memory written mid-session becomes visible in the NEXT session; the model
18
+ * can always read the directory directly for the immediate need.
19
+ */
20
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
21
+ import { isAbsolute, join, resolve } from "node:path";
22
+ import { MEMORY_GUIDE_RULES, memoryGuideIntro } from "./memory-guide.js";
23
+ /** Name of the injected section (unique — duplicate names throw upstream). */
24
+ export const MEMORY_SECTION_NAME = "evolve:memory-index";
25
+ /** Default prompt-section order (empty 1–499 slot; upstream named slots start at 500). */
26
+ export const DEFAULT_MEMORY_SECTION_ORDER = 400;
27
+ /** Default hard character budget for the injected index. */
28
+ export const DEFAULT_MAX_CHARS = 6000;
29
+ /** Sessions whose frozen section text is kept before LRU eviction. */
30
+ export const DEFAULT_FROZEN_SESSIONS = 32;
31
+ const MEMORY_DIR_SEGMENTS = [".evolve", "memory"];
32
+ const INDEX_FILE = "MEMORY.md";
33
+ /** Starter index written on first use; the model maintains every line after. */
34
+ const STARTER_INDEX = "# 记忆索引\n\n<!-- 一行一条:- [标题](文件名.md) — 一句话相关性钩子;写新记忆后在此追加一行 -->\n";
35
+ /** Appended to the workspace .gitignore on bootstrap (git workspaces only). */
36
+ const GITIGNORE_ENTRY = "# workspace memory (dsh-continual-evolve)\n.evolve/\n";
37
+ /** The assembling agent's validated absolute cwd, or undefined when absent. */
38
+ export function cwdOf(agent) {
39
+ try {
40
+ const header = agent?.session?.header;
41
+ const raw = header?.cwd ?? header?.meta?.cwd;
42
+ if (typeof raw !== "string" || raw.trim().length === 0) {
43
+ return undefined;
44
+ }
45
+ const cwd = raw.trim();
46
+ if (!isAbsolute(cwd)) {
47
+ return undefined;
48
+ }
49
+ return resolve(cwd);
50
+ }
51
+ catch {
52
+ return undefined;
53
+ }
54
+ }
55
+ /** Absolute memory directory for a workspace root. */
56
+ export function memoryDirFor(cwd) {
57
+ return join(resolve(cwd), ...MEMORY_DIR_SEGMENTS);
58
+ }
59
+ /**
60
+ * Ensure `.evolve/` is ignored when the workspace is a git repository, so
61
+ * the memory store never shows up in git status. Best-effort hygiene: a
62
+ * non-git workspace (no `.git` entry at the cwd) is left untouched — no
63
+ * `.gitignore` is created — and any write failure is swallowed.
64
+ */
65
+ export function ensureGitIgnored(cwd) {
66
+ try {
67
+ if (!existsSync(join(cwd, ".git"))) {
68
+ return;
69
+ }
70
+ const gitignore = join(cwd, ".gitignore");
71
+ const existing = existsSync(gitignore) ? readFileSync(gitignore, "utf8") : "";
72
+ if (existing.split("\n").some((line) => line.trim() === ".evolve/")) {
73
+ return;
74
+ }
75
+ const prefix = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
76
+ writeFileSync(gitignore, `${existing}${prefix}${GITIGNORE_ENTRY}`, "utf8");
77
+ }
78
+ catch {
79
+ // Never blocks the store; worst case is a visible .evolve/ in git status.
80
+ }
81
+ }
82
+ /**
83
+ * Ensure the store exists (creating the directory and a starter index on
84
+ * first use), then return the trimmed index text. Any filesystem failure
85
+ * degrades to "" — injection must never break an assembly.
86
+ */
87
+ export function readMemoryIndex(dir, bootstrap = true) {
88
+ try {
89
+ if (bootstrap && !existsSync(dir)) {
90
+ mkdirSync(dir, { recursive: true });
91
+ writeFileSync(join(dir, INDEX_FILE), STARTER_INDEX, "utf8");
92
+ ensureGitIgnored(resolve(dir, "..", ".."));
93
+ }
94
+ return readFileSync(join(dir, INDEX_FILE), "utf8").trim();
95
+ }
96
+ catch {
97
+ return "";
98
+ }
99
+ }
100
+ /**
101
+ * Whole-line-preserving truncation of the index to `maxChars` characters.
102
+ * Only index rows that fit whole are shown — a partial markdown row would
103
+ * corrupt the line the model reads. When not even one row fits, `text` is
104
+ * "" and `dropped` carries the full length.
105
+ */
106
+ export function fitIndex(index, maxChars) {
107
+ const budget = Math.max(0, maxChars);
108
+ if (index.length <= budget) {
109
+ return { text: index, dropped: 0 };
110
+ }
111
+ const cut = index.slice(0, budget);
112
+ const lastLine = cut.lastIndexOf("\n");
113
+ if (lastLine <= 0) {
114
+ return { text: "", dropped: index.length };
115
+ }
116
+ const text = cut.slice(0, lastLine);
117
+ return { text, dropped: index.length - text.length };
118
+ }
119
+ /**
120
+ * Compose the full memory section for one assembling agent: the guide
121
+ * wrapped around the budget-bounded index, with the absolute store path
122
+ * handed out so the model can read and write the files directly. With the
123
+ * guide off and an empty index the result is "" — the prompt renderer then
124
+ * drops the section, so an empty workspace costs zero tokens.
125
+ */
126
+ export function memorySectionText(agent, opts) {
127
+ const guide = opts?.guide ?? true;
128
+ const maxChars = opts?.maxChars ?? DEFAULT_MAX_CHARS;
129
+ const cwd = cwdOf(agent);
130
+ if (!cwd) {
131
+ return "";
132
+ }
133
+ const dir = memoryDirFor(cwd);
134
+ const index = readMemoryIndex(dir, opts?.bootstrap ?? true);
135
+ const { text, dropped } = fitIndex(index, maxChars);
136
+ const parts = [];
137
+ if (index.length === 0) {
138
+ parts.push("<memories>\n(暂无记忆)\n</memories>");
139
+ }
140
+ else if (text.length > 0) {
141
+ parts.push(`<memories>\n${text}\n</memories>`);
142
+ if (dropped > 0) {
143
+ parts.push(`(索引超出 ${maxChars} 字符预算,已截断——其余记忆直接读取 \`${dir}/\` 目录)`);
144
+ }
145
+ }
146
+ else {
147
+ parts.push(`(索引超出 ${maxChars} 字符预算,一行都放不下——记忆直接读取 \`${dir}/\` 目录)`);
148
+ }
149
+ if (!guide) {
150
+ return index.length === 0 ? "" : parts.join("\n\n");
151
+ }
152
+ return [memoryGuideIntro(dir), ...parts, MEMORY_GUIDE_RULES].join("\n\n");
153
+ }
154
+ /**
155
+ * Freeze the section text per agent id. The frozen value is what keeps the
156
+ * system prompt stable across a session's assemblies (prompt-cache guard);
157
+ * bounded by `maxSessions` with insertion-order (LRU) eviction, so a
158
+ * long-lived process cannot grow without limit.
159
+ */
160
+ export function createFrozenMemorySection(maxSessions = DEFAULT_FROZEN_SESSIONS) {
161
+ const limit = Math.max(1, maxSessions);
162
+ const frozen = new Map();
163
+ return {
164
+ textFor(agent, build) {
165
+ const id = agent?.id;
166
+ const key = typeof id === "string" && id.length > 0 ? id : undefined;
167
+ if (key === undefined) {
168
+ return build(agent);
169
+ }
170
+ const cached = frozen.get(key);
171
+ if (cached !== undefined) {
172
+ return cached;
173
+ }
174
+ const text = build(agent);
175
+ frozen.set(key, text);
176
+ while (frozen.size > limit) {
177
+ const oldest = frozen.keys().next();
178
+ if (oldest.done === true) {
179
+ break;
180
+ }
181
+ frozen.delete(oldest.value);
182
+ }
183
+ return text;
184
+ },
185
+ size: () => frozen.size,
186
+ clear: () => frozen.clear(),
187
+ };
188
+ }
189
+ //# sourceMappingURL=memory-section.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-continual-evolve",
3
- "version": "0.11.0",
4
- "description": "Continual self-evolution plugin for DeepSeek Harness: versioned, auditable, rollback-safe harness state (prompt notes, memories, skills, subagent specs) refined from session trajectories.",
3
+ "version": "0.12.0",
4
+ "description": "ZCode-style workspace memory for DeepSeek Harness: a per-workspace markdown store (<workspace>/.evolve/memory/) with session-start index injection — the model reads and writes the files with its native tools.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -19,10 +19,6 @@
19
19
  "types": "./lib/index.d.ts",
20
20
  "default": "./lib/index.js"
21
21
  },
22
- "./types": {
23
- "types": "./lib/types.d.ts",
24
- "default": "./lib/types.js"
25
- },
26
22
  "./package.json": "./package.json"
27
23
  },
28
24
  "files": [
@@ -51,7 +47,6 @@
51
47
  "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.scripts.json --noEmit",
52
48
  "test": "vitest run",
53
49
  "test:coverage": "vitest run --coverage",
54
- "coverage:gaps": "tsx scripts/coverage-gaps.ts",
55
50
  "test:watch": "vitest",
56
51
  "lint": "oxlint src test",
57
52
  "clean": "rm -rf lib",
@@ -60,19 +55,9 @@
60
55
  "check:governance": "tsx scripts/verify-governance.ts"
61
56
  },
62
57
  "peerDependencies": {
63
- "@deepseek-ai/cordis": "^4.0.1",
64
- "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.6 || ^0.1.7-rc.1 || ^0.2.0-rc.1",
65
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.7-rc.1 || ^0.2.0-rc.1",
66
- "@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.1.7-rc.1 || ^0.2.0-rc.1",
67
58
  "@deepseek-ai/schemastery": "^3.18.1"
68
59
  },
69
60
  "devDependencies": {
70
- "@deepseek-ai/cordis": "4.0.4",
71
- "@deepseek-ai/dsh-agent": "0.2.0-rc.2",
72
- "@deepseek-ai/dsh-commands": "0.2.0-rc.2",
73
- "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
74
- "@deepseek-ai/dsh-llm": "0.2.0-rc.2",
75
- "@deepseek-ai/dsh-tools": "0.2.0-rc.2",
76
61
  "@deepseek-ai/schemastery": "3.18.4",
77
62
  "@types/node": "^22.10.0",
78
63
  "@vitest/coverage-v8": "^3.2.0",
package/lib/apply.d.ts DELETED
@@ -1,22 +0,0 @@
1
- /**
2
- * The apply pass: turn a validated proposal into state changes with full
3
- * per-edit accounting. Every failure is recorded per edit — a bad edit never
4
- * invalidates the whole proposal — and optimistic-concurrency checks reject
5
- * edits whose target entry changed while planning was in flight.
6
- */
7
- import type { EntrySource, HarnessScope, HarnessState, RefinementProposal, RefinementResult } from "./types.js";
8
- export interface ApplyOptions {
9
- id: string;
10
- scope?: HarnessScope;
11
- rollbackOf?: string;
12
- /** State captured before planning; used to reject conflicting edits. */
13
- baselineState?: HarnessState;
14
- /**
15
- * Trajectory citation stamped into newly created entries' metadata
16
- * (sourceSession + sourceSeqs); updates keep whatever the entry already
17
- * carries. Omitted entirely when the caller cannot determine it.
18
- */
19
- source?: EntrySource;
20
- }
21
- export declare function applyRefinementProposal(state: HarnessState, proposal: RefinementProposal, options: ApplyOptions): RefinementResult;
22
- //# sourceMappingURL=apply.d.ts.map
package/lib/apply.js DELETED
@@ -1,157 +0,0 @@
1
- import { SOURCE_SESSION_KEY, SOURCE_SEQS_KEY, ARCHIVED_AT_KEY, cloneEntry, isArchived, slug } from "./types.js";
2
- import { entryChangedSince } from "./state.js";
3
- import { validateEdit } from "./validate.js";
4
- export function applyRefinementProposal(state, proposal, options) {
5
- const appliedEdits = [];
6
- const touched = new Set();
7
- const now = new Date().toISOString();
8
- for (const edit of proposal.edits) {
9
- // Store-prefix hygiene: planner edits are written against the MERGED
10
- // view, where colliding project/local ids carry a `project:` /
11
- // `local:` / `global:` prefix. A CREATE must never bake that view
12
- // prefix into a permanent id (observed: global entries literally
13
- // named "local:handoff_todo_…").
14
- // Non-create edits address existing entries: the literal id wins —
15
- // legacy stores contain entries whose literal id carries a colon
16
- // prefix, and stripping unconditionally would resolve them to a
17
- // sibling that does not exist ("entry not found", forcing file-level
18
- // surgery). Only when the literal id is absent does the stripped
19
- // form serve as the merged-view fallback.
20
- // (Review audit 2026-08-28 S7 origin; literal-first fix 2026-09-24.)
21
- const strippedId = edit.id?.replace(/^(?:local|project|global):/, "");
22
- const requestedId = edit.action === "create"
23
- ? strippedId
24
- : edit.id !== undefined && state.entries[edit.kind]?.[edit.id] !== undefined
25
- ? edit.id
26
- : edit.id && strippedId;
27
- const computedId = requestedId ?? (edit.action === "create" ? slug(edit.title ?? edit.kind, edit.kind) : undefined);
28
- const id = computedId ?? "";
29
- // Unknown kinds fail per-edit — a malformed proposal must never crash
30
- // the whole pass (review audit 2026-08-28 S1).
31
- const records = state.entries[edit.kind];
32
- if (!records) {
33
- appliedEdits.push({ ...edit, id, applied: false, error: `unsupported kind ${String(edit.kind)}` });
34
- continue;
35
- }
36
- const before = cloneEntry(records[id]);
37
- const entryKey = `${edit.kind}:${id}`;
38
- if (options.baselineState && !touched.has(entryKey) && entryChangedSince(options.baselineState, state, edit.kind, id)) {
39
- appliedEdits.push({
40
- ...edit,
41
- id,
42
- ...(before ? { before } : {}),
43
- applied: false,
44
- error: "entry changed during planning",
45
- });
46
- continue;
47
- }
48
- // Validation sees the current entry so update rules can distinguish
49
- // "carrying the persisted value" from "changing it" (skill_kind).
50
- const validationError = validateEdit(edit, computedId, options.scope, before);
51
- if (validationError) {
52
- appliedEdits.push({ ...edit, id, applied: false, error: validationError });
53
- continue;
54
- }
55
- if (edit.action === "delete") {
56
- if (!before) {
57
- appliedEdits.push({ ...edit, id, applied: false, error: "entry not found" });
58
- continue;
59
- }
60
- delete records[id];
61
- touched.add(entryKey);
62
- appliedEdits.push({ ...edit, id, before, applied: true });
63
- continue;
64
- }
65
- if (edit.action === "archive") {
66
- // Archive hides an entry from injection but never deletes it:
67
- // metadata.archivedAt is stamped through the normal apply path, so
68
- // the edit gets a before/after snapshot, a version bump, and a
69
- // rollback inverse like any other edit (restoring the snapshot
70
- // clears the stamp). Idempotency is explicit: re-archiving an
71
- // already-archived entry is an error, not a silent no-op.
72
- if (!before) {
73
- appliedEdits.push({ ...edit, id, applied: false, error: "entry not found" });
74
- continue;
75
- }
76
- if (isArchived(before)) {
77
- appliedEdits.push({ ...edit, id, before, applied: false, error: "entry already archived" });
78
- continue;
79
- }
80
- const after = {
81
- ...before,
82
- metadata: { ...before.metadata, [ARCHIVED_AT_KEY]: now },
83
- updated_at: now,
84
- version: before.version + 1,
85
- };
86
- records[id] = after;
87
- touched.add(entryKey);
88
- appliedEdits.push({ ...edit, id, before, after: cloneEntry(after) ?? after, applied: true });
89
- continue;
90
- }
91
- if (edit.action === "create" && before) {
92
- appliedEdits.push({ ...edit, id, before, applied: false, error: "entry already exists" });
93
- continue;
94
- }
95
- if (edit.action === "update" && !before) {
96
- appliedEdits.push({ ...edit, id, applied: false, error: "entry not found" });
97
- continue;
98
- }
99
- // Trajectory citation: stamped on create (the distillation moment),
100
- // never re-stamped on update (the entry keeps its original source).
101
- // Model-supplied metadata wins on key collision.
102
- const sourceMetadata = !before && options.source
103
- ? {
104
- [SOURCE_SESSION_KEY]: options.source.sessionId,
105
- ...(options.source.seqs && options.source.seqs.length > 0
106
- ? { [SOURCE_SEQS_KEY]: options.source.seqs }
107
- : {}),
108
- }
109
- : {};
110
- const skillKind = edit.skill_kind ?? before?.skill_kind;
111
- const after = {
112
- id,
113
- kind: edit.kind,
114
- title: edit.title ?? before?.title ?? id,
115
- content: edit.content ?? before?.content ?? "",
116
- path: edit.path ?? before?.path ?? "general",
117
- scope: before?.scope ?? options.scope ?? "local",
118
- reference: edit.reference ?? before?.reference ?? {},
119
- arguments: edit.arguments ?? before?.arguments ?? {},
120
- ...(skillKind !== undefined ? { skill_kind: skillKind } : {}),
121
- metadata: { ...sourceMetadata, ...(edit.metadata ?? before?.metadata ?? {}) },
122
- source: "evolve",
123
- created_at: before?.created_at ?? now,
124
- updated_at: now,
125
- version: before ? before.version + 1 : 1,
126
- };
127
- records[id] = after;
128
- touched.add(entryKey);
129
- appliedEdits.push({
130
- ...edit,
131
- id,
132
- ...(before ? { before } : {}),
133
- after: cloneEntry(after) ?? after,
134
- applied: true,
135
- });
136
- }
137
- const changes = appliedEdits.filter((edit) => edit.applied).map((edit) => `${edit.action} ${edit.kind}:${edit.id}`);
138
- state.refinements.push({
139
- id: options.id,
140
- trigger: proposal.summary,
141
- changes,
142
- evidence: proposal.rationale,
143
- outcome: proposal.expectedOutcome,
144
- created_at: now,
145
- });
146
- return {
147
- id: options.id,
148
- summary: proposal.summary,
149
- rationale: proposal.rationale,
150
- expectedOutcome: proposal.expectedOutcome,
151
- appliedEdits,
152
- harnessStatePath: "",
153
- ...(options.rollbackOf ? { rollbackOf: options.rollbackOf } : {}),
154
- ...(options.scope ? { scope: options.scope } : {}),
155
- };
156
- }
157
- //# sourceMappingURL=apply.js.map