@ngockhoale/ukit 1.1.6

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 (344) hide show
  1. package/CHANGELOG.md +179 -0
  2. package/LICENSE +21 -0
  3. package/README.md +189 -0
  4. package/bin/ukit +30 -0
  5. package/manifests/platform.full.yaml +1194 -0
  6. package/package.json +71 -0
  7. package/scripts/bug/triage.mjs +37 -0
  8. package/scripts/index/build-index.mjs +35 -0
  9. package/scripts/index/query-index.mjs +92 -0
  10. package/scripts/index/refresh-index.mjs +85 -0
  11. package/scripts/release/verify-release.mjs +56 -0
  12. package/src/bug/triageBug.js +123 -0
  13. package/src/cli/adapters.js +148 -0
  14. package/src/cli/commands/diff.js +51 -0
  15. package/src/cli/commands/doctor.js +125 -0
  16. package/src/cli/commands/indexArgs.js +73 -0
  17. package/src/cli/commands/indexTools.js +509 -0
  18. package/src/cli/commands/install.js +293 -0
  19. package/src/cli/commands/memory.js +126 -0
  20. package/src/cli/commands/status.js +8 -0
  21. package/src/cli/commands/uninstall.js +51 -0
  22. package/src/cli/index.js +109 -0
  23. package/src/context/detectProjectContext.js +49 -0
  24. package/src/context/detectProviders.js +12 -0
  25. package/src/core/applyPlan.js +89 -0
  26. package/src/core/buildPlan.js +228 -0
  27. package/src/core/compact/index.js +294 -0
  28. package/src/core/compact/threshold.js +936 -0
  29. package/src/core/diffPlan.js +73 -0
  30. package/src/core/ensureGitignore.js +117 -0
  31. package/src/core/fileOps.js +188 -0
  32. package/src/core/memory/hygiene.js +160 -0
  33. package/src/core/memory/index.js +2 -0
  34. package/src/core/memory/retrieval.js +476 -0
  35. package/src/core/memory/store.js +202 -0
  36. package/src/core/metadata.js +132 -0
  37. package/src/core/migrateLegacy.js +139 -0
  38. package/src/core/output/index.js +1309 -0
  39. package/src/core/paths.js +13 -0
  40. package/src/core/report.js +17 -0
  41. package/src/core/router/advisor.js +42 -0
  42. package/src/core/router/index.js +2 -0
  43. package/src/core/router/router.js +164 -0
  44. package/src/core/runInstallPipeline.js +365 -0
  45. package/src/core/runtimeConfig.js +190 -0
  46. package/src/core/runtimePaths.js +24 -0
  47. package/src/core/status.js +186 -0
  48. package/src/core/token/index.js +328 -0
  49. package/src/core/uninstall.js +246 -0
  50. package/src/core/validation/confidence.js +89 -0
  51. package/src/core/validation/index.js +2 -0
  52. package/src/core/validation/validator.js +165 -0
  53. package/src/index/buildIndex.js +1392 -0
  54. package/src/index/gitHooks.js +109 -0
  55. package/src/index/importResolution.js +377 -0
  56. package/src/index/languageTools.js +127 -0
  57. package/src/index/paths.js +27 -0
  58. package/src/index/queryIndex.js +637 -0
  59. package/src/index/relatedTests.js +237 -0
  60. package/src/index/resolveContext.js +345 -0
  61. package/src/index/routeCatalog.js +258 -0
  62. package/src/index/taskRouting.js +677 -0
  63. package/src/index/verificationPlan.js +437 -0
  64. package/src/manifest/loadManifest.js +22 -0
  65. package/src/manifest/selectItems.js +78 -0
  66. package/src/manifest/validateManifest.js +115 -0
  67. package/src/render/buildVariables.js +39 -0
  68. package/src/render/renderTemplate.js +44 -0
  69. package/src/stack/detectStack.js +213 -0
  70. package/templates/.claude/agents/bug-debugger.md +57 -0
  71. package/templates/.claude/agents/feature-implementer.md +55 -0
  72. package/templates/.claude/config/providers.md +25 -0
  73. package/templates/.claude/hooks/auto-allow-bash.sh +155 -0
  74. package/templates/.claude/hooks/auto-prune-bash.sh +75 -0
  75. package/templates/.claude/hooks/block-dangerous.sh +54 -0
  76. package/templates/.claude/hooks/compress-output.sh +17 -0
  77. package/templates/.claude/hooks/protect-files.sh +37 -0
  78. package/templates/.claude/hooks/reinject-context.sh +28 -0
  79. package/templates/.claude/hooks/session-start.md +13 -0
  80. package/templates/.claude/hooks/skill-router.sh +1681 -0
  81. package/templates/.claude/hooks/verification-guard.sh +271 -0
  82. package/templates/.claude/settings.json +144 -0
  83. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  84. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  85. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  86. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  87. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  88. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  89. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  90. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  91. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  92. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  93. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  94. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  95. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  96. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  97. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  98. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  99. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  100. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  101. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  102. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  103. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  104. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  105. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  106. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  107. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  108. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  109. package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  110. package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  111. package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  112. package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  113. package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  114. package/templates/.claude/skills/_shared/ooxml/schemas/mce/mc.xsd +75 -0
  115. package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  116. package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  117. package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  118. package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  119. package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  120. package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  121. package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  122. package/templates/.claude/skills/_shared/ooxml/scripts/pack.py +159 -0
  123. package/templates/.claude/skills/_shared/ooxml/scripts/unpack.py +29 -0
  124. package/templates/.claude/skills/_shared/ooxml/scripts/validate.py +69 -0
  125. package/templates/.claude/skills/_shared/ooxml/scripts/validation/__init__.py +15 -0
  126. package/templates/.claude/skills/_shared/ooxml/scripts/validation/base.py +951 -0
  127. package/templates/.claude/skills/_shared/ooxml/scripts/validation/docx.py +274 -0
  128. package/templates/.claude/skills/_shared/ooxml/scripts/validation/pptx.py +315 -0
  129. package/templates/.claude/skills/_shared/ooxml/scripts/validation/redlining.py +279 -0
  130. package/templates/.claude/skills/backend-api/SKILL.md +26 -0
  131. package/templates/.claude/skills/canvas-design/LICENSE.txt +202 -0
  132. package/templates/.claude/skills/canvas-design/SKILL.md +130 -0
  133. package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  134. package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
  135. package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  136. package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  137. package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  138. package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  139. package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
  140. package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  141. package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  142. package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  143. package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  144. package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
  145. package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  146. package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  147. package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  148. package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  149. package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
  150. package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  151. package/templates/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
  152. package/templates/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  153. package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  154. package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
  155. package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  156. package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  157. package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
  158. package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  159. package/templates/.claude/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
  160. package/templates/.claude/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  161. package/templates/.claude/skills/code-review/SKILL.md +97 -0
  162. package/templates/.claude/skills/debugging-toolkit/SKILL.md +156 -0
  163. package/templates/.claude/skills/delivery/SKILL.md +92 -0
  164. package/templates/.claude/skills/discover-security/SKILL.md +86 -0
  165. package/templates/.claude/skills/docker-packaging/SKILL.md +60 -0
  166. package/templates/.claude/skills/docs-manager/SKILL.md +465 -0
  167. package/templates/.claude/skills/docs-manager/init-project-docs.sh +70 -0
  168. package/templates/.claude/skills/docs-manager/templates/README.md.template +50 -0
  169. package/templates/.claude/skills/docs-manager/templates/agent-roles.md.template +24 -0
  170. package/templates/.claude/skills/docs-manager/templates/coding-conventions.md.template +28 -0
  171. package/templates/.claude/skills/docs-manager/templates/memory.md.template +30 -0
  172. package/templates/.claude/skills/docs-manager/templates/onboarding.md.template +20 -0
  173. package/templates/.claude/skills/docs-manager/templates/project.md.template +26 -0
  174. package/templates/.claude/skills/docs-quality/SKILL.md +148 -0
  175. package/templates/.claude/skills/docx/LICENSE.txt +30 -0
  176. package/templates/.claude/skills/docx/SKILL.md +197 -0
  177. package/templates/.claude/skills/docx/docx-js.md +350 -0
  178. package/templates/.claude/skills/docx/ooxml.md +610 -0
  179. package/templates/.claude/skills/docx/scripts/__init__.py +1 -0
  180. package/templates/.claude/skills/docx/scripts/document.py +1276 -0
  181. package/templates/.claude/skills/docx/scripts/templates/comments.xml +3 -0
  182. package/templates/.claude/skills/docx/scripts/templates/commentsExtended.xml +3 -0
  183. package/templates/.claude/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  184. package/templates/.claude/skills/docx/scripts/templates/commentsIds.xml +3 -0
  185. package/templates/.claude/skills/docx/scripts/templates/people.xml +3 -0
  186. package/templates/.claude/skills/docx/scripts/utilities.py +374 -0
  187. package/templates/.claude/skills/duraone/SKILL.md +204 -0
  188. package/templates/.claude/skills/duraone/references/backend.md +636 -0
  189. package/templates/.claude/skills/duraone/references/frontend.md +1506 -0
  190. package/templates/.claude/skills/duraone/references/sql.md +631 -0
  191. package/templates/.claude/skills/duraone/references/workflow.md +520 -0
  192. package/templates/.claude/skills/executing-plans/SKILL.md +76 -0
  193. package/templates/.claude/skills/file-organizer/SKILL.md +433 -0
  194. package/templates/.claude/skills/frontend/SKILL.md +26 -0
  195. package/templates/.claude/skills/frontend-design/LICENSE.txt +177 -0
  196. package/templates/.claude/skills/frontend-design/SKILL.md +42 -0
  197. package/templates/.claude/skills/frontend-vue/SKILL.md +127 -0
  198. package/templates/.claude/skills/frontend-vue/components/Control/Box.vue +137 -0
  199. package/templates/.claude/skills/frontend-vue/components/Control/Button.vue +93 -0
  200. package/templates/.claude/skills/frontend-vue/components/Control/ButtonBar.vue +29 -0
  201. package/templates/.claude/skills/frontend-vue/components/Control/ButtonFloat.vue +62 -0
  202. package/templates/.claude/skills/frontend-vue/components/Control/CheckButton.vue +75 -0
  203. package/templates/.claude/skills/frontend-vue/components/Control/Checkbox.vue +58 -0
  204. package/templates/.claude/skills/frontend-vue/components/Control/Datetime.vue +148 -0
  205. package/templates/.claude/skills/frontend-vue/components/Control/Dropdownlist.vue +156 -0
  206. package/templates/.claude/skills/frontend-vue/components/Control/Input.vue +106 -0
  207. package/templates/.claude/skills/frontend-vue/components/Control/Label.vue +38 -0
  208. package/templates/.claude/skills/frontend-vue/components/Control/Master/BoxColumn.vue +24 -0
  209. package/templates/.claude/skills/frontend-vue/components/Control/Popup/Confirm.vue +33 -0
  210. package/templates/.claude/skills/frontend-vue/components/Control/Popup/Info.vue +32 -0
  211. package/templates/.claude/skills/frontend-vue/components/Control/Popup/ModalInfo.vue +39 -0
  212. package/templates/.claude/skills/frontend-vue/components/Control/Popup/Reject.vue +64 -0
  213. package/templates/.claude/skills/frontend-vue/components/Control/Tag.vue +82 -0
  214. package/templates/.claude/skills/frontend-vue/components/Control/Upload.vue +61 -0
  215. package/templates/.claude/skills/frontend-vue/components/ControlMobile/Dropdownlist.vue +103 -0
  216. package/templates/.claude/skills/frontend-vue/components/ControlMobile/PagingBar.vue +108 -0
  217. package/templates/.claude/skills/frontend-vue/components/ControlMobile/UploadImage.vue +137 -0
  218. package/templates/.claude/skills/frontend-vue/components/Grid/AG.vue +806 -0
  219. package/templates/.claude/skills/frontend-vue/components/Grid/AntTable.vue +253 -0
  220. package/templates/.claude/skills/frontend-vue/components/Grid/CustomDropdownEditor.vue +43 -0
  221. package/templates/.claude/skills/frontend-vue/components/Grid/CustomDropdownEditorEnable.vue +55 -0
  222. package/templates/.claude/skills/frontend-vue/components/Grid/HtmlTable.vue +40 -0
  223. package/templates/.claude/skills/frontend-vue/components/PDFViewer.vue +25 -0
  224. package/templates/.claude/skills/frontend-vue/components/Panel/FormView.vue +309 -0
  225. package/templates/.claude/skills/frontend-vue/components/Partial/Footer.vue +23 -0
  226. package/templates/.claude/skills/frontend-vue/components/Partial/Header.vue +265 -0
  227. package/templates/.claude/skills/frontend-vue/components/Partial/Sidebar.vue +122 -0
  228. package/templates/.claude/skills/frontend-vue/components/Template.vue +16 -0
  229. package/templates/.claude/skills/frontend-vue/components/View/Form.vue +89 -0
  230. package/templates/.claude/skills/frontend-vue/composables/indexDBStore.js +140 -0
  231. package/templates/.claude/skills/frontend-vue/composables/masterApi.js +362 -0
  232. package/templates/.claude/skills/frontend-vue/composables/state.js +578 -0
  233. package/templates/.claude/skills/frontend-vue/composables/useRequest.js +221 -0
  234. package/templates/.claude/skills/frontend-vue/composables/useSession.js +179 -0
  235. package/templates/.claude/skills/frontend-vue/composables/useTranslation.js +54 -0
  236. package/templates/.claude/skills/frontend-vue/composables/useWebSocket.js +257 -0
  237. package/templates/.claude/skills/frontend-vue/composables/userObj.js +111 -0
  238. package/templates/.claude/skills/frontend-vue/composables/utils.js +322 -0
  239. package/templates/.claude/skills/frontend-vue/reference/composables-example.vue +320 -0
  240. package/templates/.claude/skills/frontend-vue/reference/form-example.vue +183 -0
  241. package/templates/.claude/skills/frontend-vue/reference/grid-example.vue +147 -0
  242. package/templates/.claude/skills/frontend-vue/reference/masterdata-example/[id].vue +106 -0
  243. package/templates/.claude/skills/frontend-vue/reference/masterdata-example/index.vue +58 -0
  244. package/templates/.claude/skills/frontend-vue/reference/popup-example.vue +159 -0
  245. package/templates/.claude/skills/pdf/LICENSE.txt +30 -0
  246. package/templates/.claude/skills/pdf/SKILL.md +294 -0
  247. package/templates/.claude/skills/pdf/forms.md +205 -0
  248. package/templates/.claude/skills/pdf/reference.md +612 -0
  249. package/templates/.claude/skills/pdf/scripts/check_bounding_boxes.py +70 -0
  250. package/templates/.claude/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
  251. package/templates/.claude/skills/pdf/scripts/check_fillable_fields.py +12 -0
  252. package/templates/.claude/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
  253. package/templates/.claude/skills/pdf/scripts/create_validation_image.py +41 -0
  254. package/templates/.claude/skills/pdf/scripts/extract_form_field_info.py +152 -0
  255. package/templates/.claude/skills/pdf/scripts/fill_fillable_fields.py +114 -0
  256. package/templates/.claude/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  257. package/templates/.claude/skills/pdf-processing/SKILL.md +107 -0
  258. package/templates/.claude/skills/pdf-processing-pro/FORMS.md +610 -0
  259. package/templates/.claude/skills/pdf-processing-pro/OCR.md +137 -0
  260. package/templates/.claude/skills/pdf-processing-pro/SKILL.md +296 -0
  261. package/templates/.claude/skills/pdf-processing-pro/TABLES.md +626 -0
  262. package/templates/.claude/skills/pdf-processing-pro/scripts/analyze_form.py +307 -0
  263. package/templates/.claude/skills/postgres/SKILL.md +69 -0
  264. package/templates/.claude/skills/postgres/reference/fn_get_examples.sql +208 -0
  265. package/templates/.claude/skills/postgres/reference/fn_rpt_examples.sql +239 -0
  266. package/templates/.claude/skills/postgres/reference/utility_functions.sql +94 -0
  267. package/templates/.claude/skills/pptx/LICENSE.txt +30 -0
  268. package/templates/.claude/skills/pptx/SKILL.md +484 -0
  269. package/templates/.claude/skills/pptx/html2pptx.md +625 -0
  270. package/templates/.claude/skills/pptx/ooxml.md +427 -0
  271. package/templates/.claude/skills/pptx/scripts/html2pptx.js +979 -0
  272. package/templates/.claude/skills/pptx/scripts/inventory.py +1020 -0
  273. package/templates/.claude/skills/pptx/scripts/rearrange.py +231 -0
  274. package/templates/.claude/skills/pptx/scripts/replace.py +385 -0
  275. package/templates/.claude/skills/pptx/scripts/thumbnail.py +450 -0
  276. package/templates/.claude/skills/repo-maintenance/SKILL.md +97 -0
  277. package/templates/.claude/skills/research/EXAMPLES.md +434 -0
  278. package/templates/.claude/skills/research/REFERENCE.md +399 -0
  279. package/templates/.claude/skills/research/SKILL.md +136 -0
  280. package/templates/.claude/skills/root-cause-tracing/SKILL.md +174 -0
  281. package/templates/.claude/skills/root-cause-tracing/find-polluter.sh +63 -0
  282. package/templates/.claude/skills/sharing-skills/SKILL.md +194 -0
  283. package/templates/.claude/skills/sql-optimization-patterns/SKILL.md +493 -0
  284. package/templates/.claude/skills/subagent-driven-development/SKILL.md +189 -0
  285. package/templates/.claude/skills/systematic-debugging/CREATION-LOG.md +119 -0
  286. package/templates/.claude/skills/systematic-debugging/SKILL.md +295 -0
  287. package/templates/.claude/skills/systematic-debugging/test-academic.md +14 -0
  288. package/templates/.claude/skills/systematic-debugging/test-pressure-1.md +58 -0
  289. package/templates/.claude/skills/systematic-debugging/test-pressure-2.md +68 -0
  290. package/templates/.claude/skills/systematic-debugging/test-pressure-3.md +69 -0
  291. package/templates/.claude/skills/test-driven-development/SKILL.md +364 -0
  292. package/templates/.claude/skills/testing-anti-patterns/SKILL.md +302 -0
  293. package/templates/.claude/skills/testing-quality/SKILL.md +97 -0
  294. package/templates/.claude/skills/verification-before-completion/SKILL.md +139 -0
  295. package/templates/.claude/skills/webapp-testing/LICENSE.txt +202 -0
  296. package/templates/.claude/skills/webapp-testing/SKILL.md +96 -0
  297. package/templates/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
  298. package/templates/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
  299. package/templates/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
  300. package/templates/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
  301. package/templates/.claude/ukit/index/build-index.mjs +28 -0
  302. package/templates/.claude/ukit/index/cache-utils.mjs +140 -0
  303. package/templates/.claude/ukit/index/lib/index-core.mjs +2800 -0
  304. package/templates/.claude/ukit/index/query-index.mjs +150 -0
  305. package/templates/.claude/ukit/index/refresh-index.mjs +57 -0
  306. package/templates/.claude/ukit/index/reset-auto-permissions.mjs +76 -0
  307. package/templates/.claude/ukit/index/resolve-context.mjs +279 -0
  308. package/templates/.claude/ukit/index/route-catalog.mjs +258 -0
  309. package/templates/.claude/ukit/index/route-task.mjs +1994 -0
  310. package/templates/.claude/ukit/index/triage.mjs +133 -0
  311. package/templates/.claude/ukit/index/verify-context.mjs +689 -0
  312. package/templates/.claude/ukit/runtime/compact-threshold.mjs +1013 -0
  313. package/templates/.claude/ukit/runtime/output-compression.mjs +1340 -0
  314. package/templates/.claude/ukit/runtime/reinject-context.mjs +874 -0
  315. package/templates/.claude/ukit/runtime/token-utils.mjs +500 -0
  316. package/templates/.codex/README.md +83 -0
  317. package/templates/.codex/settings.json +187 -0
  318. package/templates/.gitignore +75 -0
  319. package/templates/AGENTS.md +116 -0
  320. package/templates/CLAUDE.md +93 -0
  321. package/templates/adapter-presets/antigravity/README.md +22 -0
  322. package/templates/adapter-presets/antigravity/rules.md +49 -0
  323. package/templates/adapter-presets/claude/settings.local.json +42 -0
  324. package/templates/adapter-presets/codex/settings.local.json +6 -0
  325. package/templates/adapter-presets/opencode/opencode.template.json +1 -0
  326. package/templates/docs/BUGFIX.md +20 -0
  327. package/templates/docs/BUG_INDEX.md +12 -0
  328. package/templates/docs/BUG_METRICS.md +7 -0
  329. package/templates/docs/BUG_TEMPLATE.md +13 -0
  330. package/templates/docs/CODE_MAP.md +35 -0
  331. package/templates/docs/INSTALL.md +113 -0
  332. package/templates/docs/MEMORY.md +49 -0
  333. package/templates/docs/PROJECT.md +50 -0
  334. package/templates/docs/UKIT_USAGE_GUIDE.md +147 -0
  335. package/templates/docs/WORKLOG.md +10 -0
  336. package/templates/ukit/README.md +14 -0
  337. package/templates/ukit/storage/cache/compact-history.json +3 -0
  338. package/templates/ukit/storage/cache/compact-pressure.json +1 -0
  339. package/templates/ukit/storage/cache/output-history.json +3 -0
  340. package/templates/ukit/storage/cache/prompt-cache.json +3 -0
  341. package/templates/ukit/storage/config.json +37 -0
  342. package/templates/ukit/storage/memory/projects/.gitkeep +2 -0
  343. package/templates/ukit/storage/memory/sessions/.gitkeep +0 -0
  344. package/templates/ukit/storage/memory/user.json +5 -0
@@ -0,0 +1,476 @@
1
+ import { compactContextBlock, recordCompaction } from '../compact/index.js';
2
+ import { readCompactPressureState } from '../compact/threshold.js';
3
+ import {
4
+ buildCompactMachineKey,
5
+ readPromptCacheEntry,
6
+ writePromptCacheEntry,
7
+ } from '../token/index.js';
8
+ import { listMemoryItems } from './store.js';
9
+
10
+ const STOPWORDS = new Set([
11
+ 'the', 'a', 'an', 'and', 'or', 'to', 'for', 'of', 'with', 'in', 'on', 'is', 'are',
12
+ 'this', 'that', 'it', 'as', 'by', 'be', 'use', 'using', 'implement', 'fix', 'task',
13
+ 'cần', 'và', 'là', 'cho', 'một', 'những', 'dùng',
14
+ ]);
15
+
16
+ function normalize(text) {
17
+ return String(text ?? '')
18
+ .toLowerCase()
19
+ .replace(/[^\p{L}\p{N}\s./:_-]/gu, ' ')
20
+ .replace(/\s+/g, ' ')
21
+ .trim();
22
+ }
23
+
24
+ function tokenize(text) {
25
+ return normalize(text)
26
+ .split(/\s+/)
27
+ .filter((token) => token && !STOPWORDS.has(token) && token.length > 1);
28
+ }
29
+
30
+ function compactPhraseList(values, { limit = 1, fallback = 'n/a' } = {}) {
31
+ const normalized = [...new Set(
32
+ (values ?? [])
33
+ .map((value) => String(value ?? '').trim())
34
+ .filter(Boolean),
35
+ )];
36
+
37
+ if (normalized.length === 0) {
38
+ return fallback;
39
+ }
40
+
41
+ const shown = normalized.slice(0, limit);
42
+ const remaining = normalized.length - shown.length;
43
+ return remaining > 0
44
+ ? `${shown.join('; ')} (+${remaining} more)`
45
+ : shown.join('; ');
46
+ }
47
+
48
+ function buildSegments(item) {
49
+ const content = item.content ?? {};
50
+
51
+ if (item.type === 'user') {
52
+ return [
53
+ { text: item.summary, weight: 2 },
54
+ { text: JSON.stringify(content.preferences ?? {}), weight: 1 },
55
+ { text: (content.rules ?? []).join(' '), weight: 2 },
56
+ ];
57
+ }
58
+
59
+ if (item.type === 'project') {
60
+ return [
61
+ { text: item.summary, weight: 2 },
62
+ { text: content.name, weight: 2 },
63
+ { text: content.architecture, weight: 3 },
64
+ { text: (content.techStack ?? []).join(' '), weight: 2 },
65
+ { text: (content.activeRules ?? []).join(' '), weight: 2 },
66
+ { text: (content.conventions ?? []).join(' '), weight: 1 },
67
+ { text: (content.decisions ?? []).map((decision) => `${decision.what} ${decision.why}`).join(' '), weight: 7 },
68
+ ];
69
+ }
70
+
71
+ return [
72
+ { text: item.summary, weight: 2 },
73
+ { text: content.taskDescription, weight: 4 },
74
+ { text: content.outcome, weight: 1 },
75
+ { text: (content.keyActions ?? []).join(' '), weight: 3 },
76
+ { text: (content.nextSteps ?? []).join(' '), weight: 2 },
77
+ { text: (content.filesChanged ?? []).join(' '), weight: 1 },
78
+ { text: (content.decisionsMade ?? []).map((decision) => `${decision.what} ${decision.why}`).join(' '), weight: 4 },
79
+ ];
80
+ }
81
+
82
+ function getTimestamp(item) {
83
+ return item.content?.updatedAt
84
+ ?? item.content?.endedAt
85
+ ?? item.content?.startedAt
86
+ ?? 0;
87
+ }
88
+
89
+ function summarizeForSearch(item) {
90
+ const content = item.content ?? {};
91
+
92
+ if (item.type === 'project') {
93
+ const decisions = (content.decisions ?? []).map((decision) => decision.what).slice(0, 3).join('; ');
94
+ return decisions ? `${item.summary} — ${decisions}` : item.summary;
95
+ }
96
+
97
+ if (item.type === 'session') {
98
+ const actions = (content.keyActions ?? []).slice(0, 2).join('; ');
99
+ return actions ? `${item.summary} — ${actions}` : item.summary;
100
+ }
101
+
102
+ return item.summary;
103
+ }
104
+
105
+ function scoreItem(item, queryTokens) {
106
+ if (queryTokens.length === 0) {
107
+ return 1;
108
+ }
109
+
110
+ let score = 0;
111
+ const segments = buildSegments(item);
112
+
113
+ for (const segment of segments) {
114
+ const segmentTokens = new Set(tokenize(segment.text));
115
+ for (const token of queryTokens) {
116
+ if (segmentTokens.has(token)) {
117
+ score += segment.weight;
118
+ }
119
+ }
120
+ }
121
+
122
+ if (score === 0) {
123
+ return 0;
124
+ }
125
+
126
+ const recencyBonus = getTimestamp(item) > 0 ? Math.min(1, getTimestamp(item) / Date.now()) : 0;
127
+ return score + recencyBonus;
128
+ }
129
+
130
+ function withinScope(item, scope, projectId) {
131
+ if (scope !== 'all' && item.type !== scope) {
132
+ return false;
133
+ }
134
+
135
+ if (!projectId) {
136
+ return true;
137
+ }
138
+
139
+ if (item.type === 'project') {
140
+ return item.content?.id === projectId;
141
+ }
142
+
143
+ if (item.type === 'session') {
144
+ return item.content?.projectId === projectId;
145
+ }
146
+
147
+ return true;
148
+ }
149
+
150
+ function buildSearchResult(item, relevanceScore) {
151
+ return {
152
+ id: item.id,
153
+ summary: summarizeForSearch(item),
154
+ relevanceScore,
155
+ source: item.type,
156
+ timestamp: getTimestamp(item),
157
+ sourcePath: item.sourcePath,
158
+ };
159
+ }
160
+
161
+ export async function search(query, scope = 'all', limit = 10, { projectRoot, projectId } = {}) {
162
+ const items = await listMemoryItems(projectRoot);
163
+ const queryTokens = tokenize(query);
164
+
165
+ return items
166
+ .filter((item) => withinScope(item, scope, projectId))
167
+ .map((item) => ({
168
+ item,
169
+ score: scoreItem(item, queryTokens),
170
+ }))
171
+ .filter((entry) => entry.score > 0)
172
+ .sort((left, right) => (
173
+ right.score - left.score
174
+ || getTimestamp(right.item) - getTimestamp(left.item)
175
+ || right.item.summary.localeCompare(left.item.summary)
176
+ ))
177
+ .slice(0, limit)
178
+ .map((entry) => buildSearchResult(entry.item, entry.score));
179
+ }
180
+
181
+ function findRelatedItemIds(targetItem, allItems) {
182
+ if (targetItem.type === 'session') {
183
+ const projectId = targetItem.content?.projectId;
184
+ return allItems
185
+ .filter((item) => item.id !== targetItem.id)
186
+ .filter((item) => (
187
+ (item.type === 'project' && item.content?.id === projectId)
188
+ || (item.type === 'session' && item.content?.projectId === projectId)
189
+ ))
190
+ .map((item) => item.id)
191
+ .slice(0, 5);
192
+ }
193
+
194
+ if (targetItem.type === 'project') {
195
+ const projectId = targetItem.content?.id;
196
+ return allItems
197
+ .filter((item) => item.id !== targetItem.id)
198
+ .filter((item) => item.type === 'session' && item.content?.projectId === projectId)
199
+ .map((item) => item.id)
200
+ .slice(0, 5);
201
+ }
202
+
203
+ return allItems
204
+ .filter((item) => item.id !== targetItem.id && item.type !== 'user')
205
+ .map((item) => item.id)
206
+ .slice(0, 5);
207
+ }
208
+
209
+ export async function expand(id, { projectRoot } = {}) {
210
+ const items = await listMemoryItems(projectRoot);
211
+ const target = items.find((item) => item.id === id);
212
+ if (!target) {
213
+ return { id, fullContent: '', relatedItems: [] };
214
+ }
215
+
216
+ return {
217
+ id: target.id,
218
+ fullContent: JSON.stringify(target.content, null, 2),
219
+ relatedItems: findRelatedItemIds(target, items),
220
+ };
221
+ }
222
+
223
+ function buildDetailedInjectionSnippet(item) {
224
+ const content = item.content ?? {};
225
+ if (item.type === 'project') {
226
+ const decisions = compactPhraseList(
227
+ (content.decisions ?? []).map((decision) => `${decision.what} (${decision.why ?? 'no reason'})`),
228
+ { limit: 2 },
229
+ );
230
+ const rules = compactPhraseList(content.activeRules ?? [], { limit: 2 });
231
+ const stack = (content.techStack ?? []).slice(0, 3).join(', ');
232
+ return `${content.name ?? content.id ?? 'Project'} — architecture: ${content.architecture ?? 'n/a'} — stack: ${stack || 'n/a'} — decisions: ${decisions || 'n/a'}${rules ? ` — rules: ${rules}` : ''}`;
233
+ }
234
+
235
+ if (item.type === 'session') {
236
+ const actions = compactPhraseList(content.keyActions ?? [], { limit: 2 });
237
+ const nextSteps = compactPhraseList(content.nextSteps ?? [], { limit: 1 });
238
+ const files = (content.filesChanged ?? []).slice(0, 3).join(', ');
239
+ return `${content.taskDescription ?? item.id} — outcome: ${content.outcome ?? 'unknown'}${actions ? ` — actions: ${actions}` : ''}${files ? ` — files: ${files}` : ''}${nextSteps ? ` — next: ${nextSteps}` : ''}`;
240
+ }
241
+
242
+ return `User memory — rules: ${(content.rules ?? []).slice(0, 3).join('; ') || 'n/a'} — preferences: ${JSON.stringify(content.preferences ?? {})}`;
243
+ }
244
+
245
+ function buildInjectionSnippet(item) {
246
+ const content = item.content ?? {};
247
+ if (item.type === 'project') {
248
+ const decisions = compactPhraseList((content.decisions ?? []).map((decision) => decision.what), { limit: 1 });
249
+ const rules = compactPhraseList(content.activeRules ?? [], { limit: 1 });
250
+ return `project=${content.name ?? content.id ?? 'Project'}: decisions=${decisions || 'n/a'}${rules ? `: rules=${rules}` : ''}`;
251
+ }
252
+
253
+ if (item.type === 'session') {
254
+ const actions = compactPhraseList(content.keyActions ?? [], { limit: 1 });
255
+ const nextSteps = compactPhraseList(content.nextSteps ?? [], { limit: 1 });
256
+ return `session=${content.taskDescription ?? item.id}: outcome=${content.outcome ?? 'unknown'}${actions ? `: actions=${actions}` : ''}${nextSteps ? `: next=${nextSteps}` : ''}`;
257
+ }
258
+
259
+ return `user-rules=${(content.rules ?? []).slice(0, 3).join('; ') || 'n/a'}`;
260
+ }
261
+
262
+ function normalizePressurePhase(phase) {
263
+ const normalized = String(phase ?? '').trim().toLowerCase();
264
+ return ['monitor', 'soft', 'hard'].includes(normalized) ? normalized : 'monitor';
265
+ }
266
+
267
+ function resolveRecallPressurePlan({
268
+ maxTokens = 1000,
269
+ limit = 5,
270
+ pressureState = null,
271
+ } = {}) {
272
+ const phase = normalizePressurePhase(pressureState?.phase);
273
+ if (phase === 'hard') {
274
+ return {
275
+ phase,
276
+ maxTokens: Math.min(maxTokens, Math.max(96, Math.round(maxTokens * 0.72))),
277
+ limit: Math.max(1, Math.min(limit, 3)),
278
+ includeUserMemory: false,
279
+ };
280
+ }
281
+
282
+ if (phase === 'soft') {
283
+ return {
284
+ phase,
285
+ maxTokens: Math.min(maxTokens, Math.max(112, Math.round(maxTokens * 0.88))),
286
+ limit: Math.max(1, Math.min(limit, 4)),
287
+ includeUserMemory: true,
288
+ };
289
+ }
290
+
291
+ return {
292
+ phase,
293
+ maxTokens,
294
+ limit: Math.max(1, limit),
295
+ includeUserMemory: true,
296
+ };
297
+ }
298
+
299
+ function isProjectAnchor(item, projectId) {
300
+ return Boolean(item && item.type === 'project' && (!projectId || item.content?.id === projectId));
301
+ }
302
+
303
+ function isSessionAnchor(item, projectId) {
304
+ return Boolean(item && item.type === 'session' && (!projectId || item.content?.projectId === projectId));
305
+ }
306
+
307
+ function dedupeItemsById(items) {
308
+ const seen = new Set();
309
+ const unique = [];
310
+ for (const item of items ?? []) {
311
+ if (!item?.id || seen.has(item.id)) {
312
+ continue;
313
+ }
314
+ seen.add(item.id);
315
+ unique.push(item);
316
+ }
317
+ return unique;
318
+ }
319
+
320
+ function selectContextItems({
321
+ items = [],
322
+ rankedItems = [],
323
+ projectId,
324
+ limit = 5,
325
+ includeUserMemory = true,
326
+ allowProjectFallback = false,
327
+ } = {}) {
328
+ const itemById = new Map(items.map((item) => [item.id, item]));
329
+ const rankedSelection = rankedItems
330
+ .map((entry) => itemById.get(entry.id))
331
+ .filter(Boolean)
332
+ .filter((item) => includeUserMemory || item.type !== 'user');
333
+ if (rankedSelection.length === 0 && !allowProjectFallback) {
334
+ return [];
335
+ }
336
+ const projectAnchor = projectId
337
+ ? items.find((item) => item.type === 'project' && item.content?.id === projectId)
338
+ : rankedSelection.find((item) => item.type === 'project');
339
+ const prioritized = dedupeItemsById([
340
+ rankedSelection.length > 0 || allowProjectFallback ? projectAnchor : null,
341
+ ...rankedSelection.filter((item) => isSessionAnchor(item, projectId)),
342
+ ...rankedSelection.filter((item) => isProjectAnchor(item, projectId) && item.id !== projectAnchor?.id),
343
+ ...rankedSelection.filter((item) => item.type !== 'session' && item.type !== 'project'),
344
+ ]);
345
+
346
+ return prioritized.slice(0, Math.max(1, limit));
347
+ }
348
+
349
+ function buildContextRequestKey({
350
+ currentTask,
351
+ projectId,
352
+ maxTokens,
353
+ limit,
354
+ inputCompression,
355
+ selectedItems,
356
+ pressurePhase,
357
+ }) {
358
+ return buildCompactMachineKey('memory-recall-v1', {
359
+ currentTask: normalize(currentTask),
360
+ projectId: projectId ?? null,
361
+ maxTokens,
362
+ limit,
363
+ inputCompression,
364
+ pressurePhase,
365
+ items: selectedItems.map((item) => ({
366
+ id: item.id,
367
+ timestamp: getTimestamp(item),
368
+ })),
369
+ });
370
+ }
371
+
372
+ export async function getContextInjection(
373
+ currentTask,
374
+ projectId,
375
+ {
376
+ projectRoot,
377
+ maxTokens = 1000,
378
+ limit = 5,
379
+ promptCache = false,
380
+ inputCompression = true,
381
+ } = {},
382
+ ) {
383
+ const items = await listMemoryItems(projectRoot);
384
+ const pressureState = await readCompactPressureState(projectRoot);
385
+ const recallPlan = resolveRecallPressurePlan({
386
+ maxTokens,
387
+ limit,
388
+ pressureState,
389
+ });
390
+ const rankedItems = await search(currentTask, 'all', Math.max(limit * 3, 8), { projectRoot, projectId });
391
+ const selectedItems = selectContextItems({
392
+ items,
393
+ rankedItems,
394
+ projectId,
395
+ limit: recallPlan.limit,
396
+ includeUserMemory: recallPlan.includeUserMemory,
397
+ allowProjectFallback: !String(currentTask ?? '').trim(),
398
+ });
399
+
400
+ if (selectedItems.length === 0) {
401
+ return '';
402
+ }
403
+
404
+ const requestKey = buildContextRequestKey({
405
+ currentTask,
406
+ projectId,
407
+ maxTokens: recallPlan.maxTokens,
408
+ limit: recallPlan.limit,
409
+ inputCompression,
410
+ selectedItems,
411
+ pressurePhase: recallPlan.phase,
412
+ });
413
+
414
+ if (promptCache) {
415
+ const cached = await readPromptCacheEntry(projectRoot, requestKey, { touch: true });
416
+ if (cached?.content) {
417
+ return cached.content;
418
+ }
419
+ }
420
+
421
+ const rawBodyLines = selectedItems.map((item) => `- [${item.type}] ${buildDetailedInjectionSnippet(item)}`);
422
+ const bodyLines = selectedItems.map((item) => `- ${buildInjectionSnippet(item)}`);
423
+ const rawLines = ['## Previous Context', ...rawBodyLines];
424
+ const rawText = rawLines.join('\n');
425
+ const conciseText = ['## Previous Context', ...bodyLines].join('\n');
426
+ const compacted = inputCompression
427
+ ? compactContextBlock(bodyLines, {
428
+ header: '## Previous Context',
429
+ maxTokens: recallPlan.maxTokens,
430
+ maxLines: Math.max(4, recallPlan.limit + 2),
431
+ anchorLines: bodyLines.slice(0, 2),
432
+ maxAnchors: 2,
433
+ })
434
+ : {
435
+ text: conciseText,
436
+ tokensBefore: 0,
437
+ tokensAfter: 0,
438
+ savedTokens: 0,
439
+ };
440
+
441
+ const output = compacted.text || conciseText;
442
+
443
+ if (promptCache) {
444
+ await writePromptCacheEntry(projectRoot, {
445
+ requestKey,
446
+ kind: 'memory-recall',
447
+ updatedAt: Date.now(),
448
+ tokensBefore: compacted.tokensBefore,
449
+ tokensAfter: compacted.tokensAfter,
450
+ savedTokens: compacted.savedTokens,
451
+ content: output,
452
+ metadata: {
453
+ projectId,
454
+ limit: recallPlan.limit,
455
+ pressurePhase: recallPlan.phase,
456
+ selectedIds: selectedItems.map((item) => item.id),
457
+ },
458
+ });
459
+ }
460
+
461
+ if (inputCompression) {
462
+ await recordCompaction(projectRoot, {
463
+ source: 'memory-recall',
464
+ beforeText: rawText,
465
+ afterText: output,
466
+ metadata: {
467
+ projectId,
468
+ limit: recallPlan.limit,
469
+ pressurePhase: recallPlan.phase,
470
+ selectedIds: selectedItems.map((item) => item.id),
471
+ },
472
+ });
473
+ }
474
+
475
+ return output;
476
+ }
@@ -0,0 +1,202 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { buildRuntimePaths } from '../runtimePaths.js';
4
+ import { readJsonIfExists, writeJson } from '../fileOps.js';
5
+
6
+ function defaultUserMemory() {
7
+ return {
8
+ preferences: {},
9
+ rules: [],
10
+ updatedAt: Date.now(),
11
+ };
12
+ }
13
+
14
+ async function readDirectoryJsonItems(dirPath) {
15
+ let entries = [];
16
+ try {
17
+ entries = await fs.readdir(dirPath, { withFileTypes: true });
18
+ } catch {
19
+ return [];
20
+ }
21
+
22
+ const items = [];
23
+ for (const entry of entries) {
24
+ if (!entry.isFile() || !entry.name.endsWith('.json')) {
25
+ continue;
26
+ }
27
+
28
+ const fullPath = path.join(dirPath, entry.name);
29
+ const content = await readJsonIfExists(fullPath);
30
+ if (content) {
31
+ items.push({
32
+ fileName: entry.name,
33
+ filePath: fullPath,
34
+ content,
35
+ });
36
+ }
37
+ }
38
+
39
+ return items.sort((left, right) => left.fileName.localeCompare(right.fileName));
40
+ }
41
+
42
+ function summarizeUserMemory(userMemory) {
43
+ const preferenceCount = Object.keys(userMemory.preferences ?? {}).length;
44
+ const ruleCount = Array.isArray(userMemory.rules) ? userMemory.rules.length : 0;
45
+ return `${preferenceCount} preferences, ${ruleCount} rules`;
46
+ }
47
+
48
+ function summarizeProjectMemory(projectMemory) {
49
+ const decisionCount = Array.isArray(projectMemory.decisions) ? projectMemory.decisions.length : 0;
50
+ const techStack = Array.isArray(projectMemory.techStack) ? projectMemory.techStack.join(', ') : '';
51
+ return `${projectMemory.name ?? projectMemory.id ?? 'project'} — ${decisionCount} decisions${techStack ? ` — ${techStack}` : ''}`;
52
+ }
53
+
54
+ function summarizeSessionMemory(sessionMemory) {
55
+ const task = sessionMemory.taskDescription ?? sessionMemory.id ?? 'session';
56
+ const outcome = sessionMemory.outcome ?? 'unknown';
57
+ return `${task} — ${outcome}`;
58
+ }
59
+
60
+ function createSearchableText(type, content) {
61
+ if (type === 'user') {
62
+ return [
63
+ JSON.stringify(content.preferences ?? {}),
64
+ ...(content.rules ?? []),
65
+ ].join('\n');
66
+ }
67
+
68
+ if (type === 'project') {
69
+ return [
70
+ content.name,
71
+ content.architecture,
72
+ ...(content.techStack ?? []),
73
+ ...(content.activeRules ?? []),
74
+ ...(content.conventions ?? []),
75
+ ...((content.decisions ?? []).flatMap((decision) => [decision.what, decision.why])),
76
+ ].filter(Boolean).join('\n');
77
+ }
78
+
79
+ return [
80
+ content.taskDescription,
81
+ content.outcome,
82
+ ...(content.keyActions ?? []),
83
+ ...(content.nextSteps ?? []),
84
+ ...(content.filesChanged ?? []),
85
+ ].filter(Boolean).join('\n');
86
+ }
87
+
88
+ function computeRelevance(searchableText, query) {
89
+ if (!query) {
90
+ return 1;
91
+ }
92
+
93
+ const haystack = searchableText.toLowerCase();
94
+ const needle = query.toLowerCase();
95
+ if (!haystack.includes(needle)) {
96
+ return 0;
97
+ }
98
+
99
+ const parts = needle.split(/\s+/).filter(Boolean);
100
+ let score = 1;
101
+ for (const part of parts) {
102
+ if (haystack.includes(part)) {
103
+ score += 1;
104
+ }
105
+ }
106
+
107
+ return score;
108
+ }
109
+
110
+ export async function exportMemory(projectRoot) {
111
+ const runtimePaths = buildRuntimePaths(projectRoot);
112
+ const user = (await readJsonIfExists(runtimePaths.userMemoryPath)) ?? defaultUserMemory();
113
+ const projects = (await readDirectoryJsonItems(runtimePaths.projectsDir)).map((item) => item.content);
114
+ const sessions = (await readDirectoryJsonItems(runtimePaths.sessionsDir)).map((item) => item.content);
115
+
116
+ return { user, projects, sessions };
117
+ }
118
+
119
+ export async function listMemoryItems(projectRoot) {
120
+ const runtimePaths = buildRuntimePaths(projectRoot);
121
+ const userMemory = (await readJsonIfExists(runtimePaths.userMemoryPath)) ?? defaultUserMemory();
122
+ const projectMemories = await readDirectoryJsonItems(runtimePaths.projectsDir);
123
+ const sessionMemories = await readDirectoryJsonItems(runtimePaths.sessionsDir);
124
+
125
+ return [
126
+ {
127
+ id: 'user:user',
128
+ type: 'user',
129
+ summary: summarizeUserMemory(userMemory),
130
+ searchableText: createSearchableText('user', userMemory),
131
+ sourcePath: runtimePaths.userMemoryPath,
132
+ content: userMemory,
133
+ },
134
+ ...projectMemories.map((item) => ({
135
+ id: `project:${item.content.id ?? item.fileName.replace(/\.json$/, '')}`,
136
+ type: 'project',
137
+ summary: summarizeProjectMemory(item.content),
138
+ searchableText: createSearchableText('project', item.content),
139
+ sourcePath: item.filePath,
140
+ content: item.content,
141
+ })),
142
+ ...sessionMemories.map((item) => ({
143
+ id: `session:${item.content.id ?? item.fileName.replace(/\.json$/, '')}`,
144
+ type: 'session',
145
+ summary: summarizeSessionMemory(item.content),
146
+ searchableText: createSearchableText('session', item.content),
147
+ sourcePath: item.filePath,
148
+ content: item.content,
149
+ })),
150
+ ];
151
+ }
152
+
153
+ export async function searchMemoryItems(projectRoot, query, { limit = 10 } = {}) {
154
+ const items = await listMemoryItems(projectRoot);
155
+ return items
156
+ .map((item) => ({
157
+ ...item,
158
+ relevanceScore: computeRelevance(`${item.summary}\n${item.searchableText}`, query),
159
+ }))
160
+ .filter((item) => item.relevanceScore > 0)
161
+ .sort((left, right) => right.relevanceScore - left.relevanceScore)
162
+ .slice(0, limit);
163
+ }
164
+
165
+ export async function forgetMemoryItem(projectRoot, memoryId) {
166
+ const runtimePaths = buildRuntimePaths(projectRoot);
167
+ if (memoryId === 'user:user' || memoryId === 'user') {
168
+ await writeJson(runtimePaths.userMemoryPath, defaultUserMemory());
169
+ return { removed: true, type: 'user', path: runtimePaths.userMemoryPath };
170
+ }
171
+
172
+ const [type, rawId] = String(memoryId).split(':');
173
+ if (!type || !rawId) {
174
+ return { removed: false, type: null, path: null };
175
+ }
176
+
177
+ const baseDir = type === 'project'
178
+ ? runtimePaths.projectsDir
179
+ : type === 'session'
180
+ ? runtimePaths.sessionsDir
181
+ : null;
182
+ if (!baseDir) {
183
+ return { removed: false, type: null, path: null };
184
+ }
185
+
186
+ const targetPath = path.join(baseDir, `${rawId}.json`);
187
+ try {
188
+ await fs.unlink(targetPath);
189
+ return { removed: true, type, path: targetPath };
190
+ } catch {
191
+ return { removed: false, type, path: targetPath };
192
+ }
193
+ }
194
+
195
+ export async function countMemoryItems(projectRoot) {
196
+ const exported = await exportMemory(projectRoot);
197
+ return {
198
+ projectCount: exported.projects.length,
199
+ sessionCount: exported.sessions.length,
200
+ userCount: Object.keys(exported.user.preferences ?? {}).length + (exported.user.rules ?? []).length,
201
+ };
202
+ }