@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.
- package/CHANGELOG.md +179 -0
- package/LICENSE +21 -0
- package/README.md +189 -0
- package/bin/ukit +30 -0
- package/manifests/platform.full.yaml +1194 -0
- package/package.json +71 -0
- package/scripts/bug/triage.mjs +37 -0
- package/scripts/index/build-index.mjs +35 -0
- package/scripts/index/query-index.mjs +92 -0
- package/scripts/index/refresh-index.mjs +85 -0
- package/scripts/release/verify-release.mjs +56 -0
- package/src/bug/triageBug.js +123 -0
- package/src/cli/adapters.js +148 -0
- package/src/cli/commands/diff.js +51 -0
- package/src/cli/commands/doctor.js +125 -0
- package/src/cli/commands/indexArgs.js +73 -0
- package/src/cli/commands/indexTools.js +509 -0
- package/src/cli/commands/install.js +293 -0
- package/src/cli/commands/memory.js +126 -0
- package/src/cli/commands/status.js +8 -0
- package/src/cli/commands/uninstall.js +51 -0
- package/src/cli/index.js +109 -0
- package/src/context/detectProjectContext.js +49 -0
- package/src/context/detectProviders.js +12 -0
- package/src/core/applyPlan.js +89 -0
- package/src/core/buildPlan.js +228 -0
- package/src/core/compact/index.js +294 -0
- package/src/core/compact/threshold.js +936 -0
- package/src/core/diffPlan.js +73 -0
- package/src/core/ensureGitignore.js +117 -0
- package/src/core/fileOps.js +188 -0
- package/src/core/memory/hygiene.js +160 -0
- package/src/core/memory/index.js +2 -0
- package/src/core/memory/retrieval.js +476 -0
- package/src/core/memory/store.js +202 -0
- package/src/core/metadata.js +132 -0
- package/src/core/migrateLegacy.js +139 -0
- package/src/core/output/index.js +1309 -0
- package/src/core/paths.js +13 -0
- package/src/core/report.js +17 -0
- package/src/core/router/advisor.js +42 -0
- package/src/core/router/index.js +2 -0
- package/src/core/router/router.js +164 -0
- package/src/core/runInstallPipeline.js +365 -0
- package/src/core/runtimeConfig.js +190 -0
- package/src/core/runtimePaths.js +24 -0
- package/src/core/status.js +186 -0
- package/src/core/token/index.js +328 -0
- package/src/core/uninstall.js +246 -0
- package/src/core/validation/confidence.js +89 -0
- package/src/core/validation/index.js +2 -0
- package/src/core/validation/validator.js +165 -0
- package/src/index/buildIndex.js +1392 -0
- package/src/index/gitHooks.js +109 -0
- package/src/index/importResolution.js +377 -0
- package/src/index/languageTools.js +127 -0
- package/src/index/paths.js +27 -0
- package/src/index/queryIndex.js +637 -0
- package/src/index/relatedTests.js +237 -0
- package/src/index/resolveContext.js +345 -0
- package/src/index/routeCatalog.js +258 -0
- package/src/index/taskRouting.js +677 -0
- package/src/index/verificationPlan.js +437 -0
- package/src/manifest/loadManifest.js +22 -0
- package/src/manifest/selectItems.js +78 -0
- package/src/manifest/validateManifest.js +115 -0
- package/src/render/buildVariables.js +39 -0
- package/src/render/renderTemplate.js +44 -0
- package/src/stack/detectStack.js +213 -0
- package/templates/.claude/agents/bug-debugger.md +57 -0
- package/templates/.claude/agents/feature-implementer.md +55 -0
- package/templates/.claude/config/providers.md +25 -0
- package/templates/.claude/hooks/auto-allow-bash.sh +155 -0
- package/templates/.claude/hooks/auto-prune-bash.sh +75 -0
- package/templates/.claude/hooks/block-dangerous.sh +54 -0
- package/templates/.claude/hooks/compress-output.sh +17 -0
- package/templates/.claude/hooks/protect-files.sh +37 -0
- package/templates/.claude/hooks/reinject-context.sh +28 -0
- package/templates/.claude/hooks/session-start.md +13 -0
- package/templates/.claude/hooks/skill-router.sh +1681 -0
- package/templates/.claude/hooks/verification-guard.sh +271 -0
- package/templates/.claude/settings.json +144 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/mce/mc.xsd +75 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/templates/.claude/skills/_shared/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/pack.py +159 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/unpack.py +29 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validate.py +69 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/base.py +951 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/docx.py +274 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/.claude/skills/_shared/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/.claude/skills/backend-api/SKILL.md +26 -0
- package/templates/.claude/skills/canvas-design/LICENSE.txt +202 -0
- package/templates/.claude/skills/canvas-design/SKILL.md +130 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/templates/.claude/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/templates/.claude/skills/code-review/SKILL.md +97 -0
- package/templates/.claude/skills/debugging-toolkit/SKILL.md +156 -0
- package/templates/.claude/skills/delivery/SKILL.md +92 -0
- package/templates/.claude/skills/discover-security/SKILL.md +86 -0
- package/templates/.claude/skills/docker-packaging/SKILL.md +60 -0
- package/templates/.claude/skills/docs-manager/SKILL.md +465 -0
- package/templates/.claude/skills/docs-manager/init-project-docs.sh +70 -0
- package/templates/.claude/skills/docs-manager/templates/README.md.template +50 -0
- package/templates/.claude/skills/docs-manager/templates/agent-roles.md.template +24 -0
- package/templates/.claude/skills/docs-manager/templates/coding-conventions.md.template +28 -0
- package/templates/.claude/skills/docs-manager/templates/memory.md.template +30 -0
- package/templates/.claude/skills/docs-manager/templates/onboarding.md.template +20 -0
- package/templates/.claude/skills/docs-manager/templates/project.md.template +26 -0
- package/templates/.claude/skills/docs-quality/SKILL.md +148 -0
- package/templates/.claude/skills/docx/LICENSE.txt +30 -0
- package/templates/.claude/skills/docx/SKILL.md +197 -0
- package/templates/.claude/skills/docx/docx-js.md +350 -0
- package/templates/.claude/skills/docx/ooxml.md +610 -0
- package/templates/.claude/skills/docx/scripts/__init__.py +1 -0
- package/templates/.claude/skills/docx/scripts/document.py +1276 -0
- package/templates/.claude/skills/docx/scripts/templates/comments.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/templates/.claude/skills/docx/scripts/templates/people.xml +3 -0
- package/templates/.claude/skills/docx/scripts/utilities.py +374 -0
- package/templates/.claude/skills/duraone/SKILL.md +204 -0
- package/templates/.claude/skills/duraone/references/backend.md +636 -0
- package/templates/.claude/skills/duraone/references/frontend.md +1506 -0
- package/templates/.claude/skills/duraone/references/sql.md +631 -0
- package/templates/.claude/skills/duraone/references/workflow.md +520 -0
- package/templates/.claude/skills/executing-plans/SKILL.md +76 -0
- package/templates/.claude/skills/file-organizer/SKILL.md +433 -0
- package/templates/.claude/skills/frontend/SKILL.md +26 -0
- package/templates/.claude/skills/frontend-design/LICENSE.txt +177 -0
- package/templates/.claude/skills/frontend-design/SKILL.md +42 -0
- package/templates/.claude/skills/frontend-vue/SKILL.md +127 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Box.vue +137 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Button.vue +93 -0
- package/templates/.claude/skills/frontend-vue/components/Control/ButtonBar.vue +29 -0
- package/templates/.claude/skills/frontend-vue/components/Control/ButtonFloat.vue +62 -0
- package/templates/.claude/skills/frontend-vue/components/Control/CheckButton.vue +75 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Checkbox.vue +58 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Datetime.vue +148 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Dropdownlist.vue +156 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Input.vue +106 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Label.vue +38 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Master/BoxColumn.vue +24 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/Confirm.vue +33 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/Info.vue +32 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/ModalInfo.vue +39 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Popup/Reject.vue +64 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Tag.vue +82 -0
- package/templates/.claude/skills/frontend-vue/components/Control/Upload.vue +61 -0
- package/templates/.claude/skills/frontend-vue/components/ControlMobile/Dropdownlist.vue +103 -0
- package/templates/.claude/skills/frontend-vue/components/ControlMobile/PagingBar.vue +108 -0
- package/templates/.claude/skills/frontend-vue/components/ControlMobile/UploadImage.vue +137 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/AG.vue +806 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/AntTable.vue +253 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/CustomDropdownEditor.vue +43 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/CustomDropdownEditorEnable.vue +55 -0
- package/templates/.claude/skills/frontend-vue/components/Grid/HtmlTable.vue +40 -0
- package/templates/.claude/skills/frontend-vue/components/PDFViewer.vue +25 -0
- package/templates/.claude/skills/frontend-vue/components/Panel/FormView.vue +309 -0
- package/templates/.claude/skills/frontend-vue/components/Partial/Footer.vue +23 -0
- package/templates/.claude/skills/frontend-vue/components/Partial/Header.vue +265 -0
- package/templates/.claude/skills/frontend-vue/components/Partial/Sidebar.vue +122 -0
- package/templates/.claude/skills/frontend-vue/components/Template.vue +16 -0
- package/templates/.claude/skills/frontend-vue/components/View/Form.vue +89 -0
- package/templates/.claude/skills/frontend-vue/composables/indexDBStore.js +140 -0
- package/templates/.claude/skills/frontend-vue/composables/masterApi.js +362 -0
- package/templates/.claude/skills/frontend-vue/composables/state.js +578 -0
- package/templates/.claude/skills/frontend-vue/composables/useRequest.js +221 -0
- package/templates/.claude/skills/frontend-vue/composables/useSession.js +179 -0
- package/templates/.claude/skills/frontend-vue/composables/useTranslation.js +54 -0
- package/templates/.claude/skills/frontend-vue/composables/useWebSocket.js +257 -0
- package/templates/.claude/skills/frontend-vue/composables/userObj.js +111 -0
- package/templates/.claude/skills/frontend-vue/composables/utils.js +322 -0
- package/templates/.claude/skills/frontend-vue/reference/composables-example.vue +320 -0
- package/templates/.claude/skills/frontend-vue/reference/form-example.vue +183 -0
- package/templates/.claude/skills/frontend-vue/reference/grid-example.vue +147 -0
- package/templates/.claude/skills/frontend-vue/reference/masterdata-example/[id].vue +106 -0
- package/templates/.claude/skills/frontend-vue/reference/masterdata-example/index.vue +58 -0
- package/templates/.claude/skills/frontend-vue/reference/popup-example.vue +159 -0
- package/templates/.claude/skills/pdf/LICENSE.txt +30 -0
- package/templates/.claude/skills/pdf/SKILL.md +294 -0
- package/templates/.claude/skills/pdf/forms.md +205 -0
- package/templates/.claude/skills/pdf/reference.md +612 -0
- package/templates/.claude/skills/pdf/scripts/check_bounding_boxes.py +70 -0
- package/templates/.claude/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
- package/templates/.claude/skills/pdf/scripts/check_fillable_fields.py +12 -0
- package/templates/.claude/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/templates/.claude/skills/pdf/scripts/create_validation_image.py +41 -0
- package/templates/.claude/skills/pdf/scripts/extract_form_field_info.py +152 -0
- package/templates/.claude/skills/pdf/scripts/fill_fillable_fields.py +114 -0
- package/templates/.claude/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/templates/.claude/skills/pdf-processing/SKILL.md +107 -0
- package/templates/.claude/skills/pdf-processing-pro/FORMS.md +610 -0
- package/templates/.claude/skills/pdf-processing-pro/OCR.md +137 -0
- package/templates/.claude/skills/pdf-processing-pro/SKILL.md +296 -0
- package/templates/.claude/skills/pdf-processing-pro/TABLES.md +626 -0
- package/templates/.claude/skills/pdf-processing-pro/scripts/analyze_form.py +307 -0
- package/templates/.claude/skills/postgres/SKILL.md +69 -0
- package/templates/.claude/skills/postgres/reference/fn_get_examples.sql +208 -0
- package/templates/.claude/skills/postgres/reference/fn_rpt_examples.sql +239 -0
- package/templates/.claude/skills/postgres/reference/utility_functions.sql +94 -0
- package/templates/.claude/skills/pptx/LICENSE.txt +30 -0
- package/templates/.claude/skills/pptx/SKILL.md +484 -0
- package/templates/.claude/skills/pptx/html2pptx.md +625 -0
- package/templates/.claude/skills/pptx/ooxml.md +427 -0
- package/templates/.claude/skills/pptx/scripts/html2pptx.js +979 -0
- package/templates/.claude/skills/pptx/scripts/inventory.py +1020 -0
- package/templates/.claude/skills/pptx/scripts/rearrange.py +231 -0
- package/templates/.claude/skills/pptx/scripts/replace.py +385 -0
- package/templates/.claude/skills/pptx/scripts/thumbnail.py +450 -0
- package/templates/.claude/skills/repo-maintenance/SKILL.md +97 -0
- package/templates/.claude/skills/research/EXAMPLES.md +434 -0
- package/templates/.claude/skills/research/REFERENCE.md +399 -0
- package/templates/.claude/skills/research/SKILL.md +136 -0
- package/templates/.claude/skills/root-cause-tracing/SKILL.md +174 -0
- package/templates/.claude/skills/root-cause-tracing/find-polluter.sh +63 -0
- package/templates/.claude/skills/sharing-skills/SKILL.md +194 -0
- package/templates/.claude/skills/sql-optimization-patterns/SKILL.md +493 -0
- package/templates/.claude/skills/subagent-driven-development/SKILL.md +189 -0
- package/templates/.claude/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/templates/.claude/skills/systematic-debugging/SKILL.md +295 -0
- package/templates/.claude/skills/systematic-debugging/test-academic.md +14 -0
- package/templates/.claude/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/templates/.claude/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/templates/.claude/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/templates/.claude/skills/test-driven-development/SKILL.md +364 -0
- package/templates/.claude/skills/testing-anti-patterns/SKILL.md +302 -0
- package/templates/.claude/skills/testing-quality/SKILL.md +97 -0
- package/templates/.claude/skills/verification-before-completion/SKILL.md +139 -0
- package/templates/.claude/skills/webapp-testing/LICENSE.txt +202 -0
- package/templates/.claude/skills/webapp-testing/SKILL.md +96 -0
- package/templates/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
- package/templates/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/templates/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/templates/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
- package/templates/.claude/ukit/index/build-index.mjs +28 -0
- package/templates/.claude/ukit/index/cache-utils.mjs +140 -0
- package/templates/.claude/ukit/index/lib/index-core.mjs +2800 -0
- package/templates/.claude/ukit/index/query-index.mjs +150 -0
- package/templates/.claude/ukit/index/refresh-index.mjs +57 -0
- package/templates/.claude/ukit/index/reset-auto-permissions.mjs +76 -0
- package/templates/.claude/ukit/index/resolve-context.mjs +279 -0
- package/templates/.claude/ukit/index/route-catalog.mjs +258 -0
- package/templates/.claude/ukit/index/route-task.mjs +1994 -0
- package/templates/.claude/ukit/index/triage.mjs +133 -0
- package/templates/.claude/ukit/index/verify-context.mjs +689 -0
- package/templates/.claude/ukit/runtime/compact-threshold.mjs +1013 -0
- package/templates/.claude/ukit/runtime/output-compression.mjs +1340 -0
- package/templates/.claude/ukit/runtime/reinject-context.mjs +874 -0
- package/templates/.claude/ukit/runtime/token-utils.mjs +500 -0
- package/templates/.codex/README.md +83 -0
- package/templates/.codex/settings.json +187 -0
- package/templates/.gitignore +75 -0
- package/templates/AGENTS.md +116 -0
- package/templates/CLAUDE.md +93 -0
- package/templates/adapter-presets/antigravity/README.md +22 -0
- package/templates/adapter-presets/antigravity/rules.md +49 -0
- package/templates/adapter-presets/claude/settings.local.json +42 -0
- package/templates/adapter-presets/codex/settings.local.json +6 -0
- package/templates/adapter-presets/opencode/opencode.template.json +1 -0
- package/templates/docs/BUGFIX.md +20 -0
- package/templates/docs/BUG_INDEX.md +12 -0
- package/templates/docs/BUG_METRICS.md +7 -0
- package/templates/docs/BUG_TEMPLATE.md +13 -0
- package/templates/docs/CODE_MAP.md +35 -0
- package/templates/docs/INSTALL.md +113 -0
- package/templates/docs/MEMORY.md +49 -0
- package/templates/docs/PROJECT.md +50 -0
- package/templates/docs/UKIT_USAGE_GUIDE.md +147 -0
- package/templates/docs/WORKLOG.md +10 -0
- package/templates/ukit/README.md +14 -0
- package/templates/ukit/storage/cache/compact-history.json +3 -0
- package/templates/ukit/storage/cache/compact-pressure.json +1 -0
- package/templates/ukit/storage/cache/output-history.json +3 -0
- package/templates/ukit/storage/cache/prompt-cache.json +3 -0
- package/templates/ukit/storage/config.json +37 -0
- package/templates/ukit/storage/memory/projects/.gitkeep +2 -0
- package/templates/ukit/storage/memory/sessions/.gitkeep +0 -0
- package/templates/ukit/storage/memory/user.json +5 -0
|
@@ -0,0 +1,874 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {
|
|
5
|
+
buildCompactMachineKey,
|
|
6
|
+
buildRuntimePaths,
|
|
7
|
+
compactContextBlock,
|
|
8
|
+
estimateTokenCount,
|
|
9
|
+
readJson,
|
|
10
|
+
readPromptCacheEntry,
|
|
11
|
+
recordCompaction,
|
|
12
|
+
writePromptCacheEntry,
|
|
13
|
+
} from './token-utils.mjs';
|
|
14
|
+
import {
|
|
15
|
+
buildThresholdCompactPlan,
|
|
16
|
+
readCompactPressureState,
|
|
17
|
+
writeThresholdCompactPlan,
|
|
18
|
+
} from './compact-threshold.mjs';
|
|
19
|
+
|
|
20
|
+
const STATE_TTL_MS = 30 * 60 * 1000;
|
|
21
|
+
const STOPWORDS = new Set([
|
|
22
|
+
'the', 'a', 'an', 'and', 'or', 'to', 'for', 'of', 'with', 'in', 'on', 'is', 'are',
|
|
23
|
+
'this', 'that', 'it', 'as', 'by', 'be', 'use', 'using', 'implement', 'fix', 'task',
|
|
24
|
+
'cần', 'và', 'là', 'cho', 'một', 'những', 'dùng',
|
|
25
|
+
]);
|
|
26
|
+
const INLINE_SUMMARY_MAX_SEGMENTS = 5;
|
|
27
|
+
const INLINE_SUMMARY_SIGNAL_PATTERNS = [
|
|
28
|
+
/\b(error|fail(?:ed)?|warning|assertionerror|exception|fatal|deprecated|unmet peer|ignored build scripts)\b/i,
|
|
29
|
+
/(^|\s)(src|app|lib|docs|ukit|\.claude|\.codex|tests?)\//i,
|
|
30
|
+
/^\s*FAIL\b/i,
|
|
31
|
+
/^\s*stderr\s*\|/i,
|
|
32
|
+
/^\s*stdout\s*\|/i,
|
|
33
|
+
];
|
|
34
|
+
const INLINE_SUMMARY_TAIL_PATTERNS = [
|
|
35
|
+
/\b(Test Files|Tests|Packages:|Done in|short test summary info)\b/i,
|
|
36
|
+
/\b(Duration|Start at)\b/i,
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
async function main() {
|
|
40
|
+
const projectRoot = process.env.CLAUDE_PROJECT_DIR && path.isAbsolute(process.env.CLAUDE_PROJECT_DIR)
|
|
41
|
+
? process.env.CLAUDE_PROJECT_DIR
|
|
42
|
+
: process.cwd();
|
|
43
|
+
const config = await loadRuntimeConfig(projectRoot);
|
|
44
|
+
const state = await loadFreshRouteState(projectRoot);
|
|
45
|
+
const compressEnabled = shouldCompress(config);
|
|
46
|
+
const header = '=== PROJECT CONTEXT (post-compaction) ===';
|
|
47
|
+
const footer = '=== END ===';
|
|
48
|
+
|
|
49
|
+
const rawStaticLines = buildStaticGuidanceLines(state, { compact: false });
|
|
50
|
+
const staticLines = buildStaticGuidanceLines(state, { compact: compressEnabled });
|
|
51
|
+
|
|
52
|
+
const dynamicLines = [
|
|
53
|
+
...await buildRouteStateLines(state),
|
|
54
|
+
...await buildPreviousContextLines(projectRoot, state, config),
|
|
55
|
+
...await buildRecentOutputLines(projectRoot, config),
|
|
56
|
+
...await buildResolverHintLines(projectRoot, state),
|
|
57
|
+
...await buildDuraOneHintLines(projectRoot),
|
|
58
|
+
'- If Claude hooks block broad verification, follow the routed targeted order or ask for explicit full-suite confirmation.',
|
|
59
|
+
].filter(Boolean);
|
|
60
|
+
|
|
61
|
+
const rawBodyLines = [...rawStaticLines, ...dynamicLines];
|
|
62
|
+
const bodyLines = [...staticLines, ...dynamicLines];
|
|
63
|
+
const pressureState = await readCompactPressureState(projectRoot, config);
|
|
64
|
+
const anchorLines = dynamicLines.filter((line) => (
|
|
65
|
+
line.startsWith('- Recent routed lane:')
|
|
66
|
+
|| line.startsWith('- Previous context:')
|
|
67
|
+
|| line.startsWith('- Recent command output:')
|
|
68
|
+
|| line.startsWith('- Recent delegation hint:')
|
|
69
|
+
));
|
|
70
|
+
const maxTokens = Math.max(160, Math.min(320, Number(config.memory?.maxInjectionTokens) || 320));
|
|
71
|
+
const thresholdPlan = buildThresholdCompactPlan({
|
|
72
|
+
state: pressureState,
|
|
73
|
+
config,
|
|
74
|
+
routeState: state,
|
|
75
|
+
staticLines,
|
|
76
|
+
dynamicLines,
|
|
77
|
+
maxTokens,
|
|
78
|
+
});
|
|
79
|
+
const requestKey = buildCompactMachineKey('precompact-reinject-v1', {
|
|
80
|
+
maxTokens,
|
|
81
|
+
taskPrompt: String(state?.routingContext?.lastExplicitUserPromptText || state?.routingContext?.promptText || '').trim(),
|
|
82
|
+
targetFile: state?.routingContext?.targetFile || null,
|
|
83
|
+
routeSummary: state?.routeSummary || null,
|
|
84
|
+
activeSkills: Array.isArray(state?.activeSkills) ? state.activeSkills.map((item) => getActiveSkillPath(item)) : [],
|
|
85
|
+
bodyLines: thresholdPlan.active ? thresholdPlan.lines : bodyLines,
|
|
86
|
+
thresholdPhase: thresholdPlan.active ? thresholdPlan.phase : 'monitor',
|
|
87
|
+
estimatedTotalTokens: thresholdPlan.active ? thresholdPlan.estimatedTotalTokens : pressureState.estimatedTotalTokens,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (config.tokenPipeline?.promptCache) {
|
|
91
|
+
const cached = await readPromptCacheEntry(projectRoot, requestKey, { touch: true });
|
|
92
|
+
if (cached?.content) {
|
|
93
|
+
process.stdout.write(String(cached.content));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const rawText = [header, ...rawBodyLines, footer].join('\n');
|
|
99
|
+
const compactedBody = thresholdPlan.active
|
|
100
|
+
? {
|
|
101
|
+
text: thresholdPlan.lines.join('\n'),
|
|
102
|
+
tokensBefore: estimateTokenCount(rawBodyLines.join('\n')),
|
|
103
|
+
tokensAfter: estimateTokenCount(thresholdPlan.lines.join('\n')),
|
|
104
|
+
savedTokens: Math.max(0, estimateTokenCount(rawBodyLines.join('\n')) - estimateTokenCount(thresholdPlan.lines.join('\n'))),
|
|
105
|
+
}
|
|
106
|
+
: (
|
|
107
|
+
compressEnabled
|
|
108
|
+
? compactContextBlock(bodyLines, {
|
|
109
|
+
maxTokens,
|
|
110
|
+
maxLines: 12,
|
|
111
|
+
anchorLines: anchorLines.slice(0, 3),
|
|
112
|
+
maxAnchors: 3,
|
|
113
|
+
})
|
|
114
|
+
: {
|
|
115
|
+
text: bodyLines.join('\n'),
|
|
116
|
+
tokensBefore: estimateTokenCount(bodyLines.join('\n')),
|
|
117
|
+
tokensAfter: estimateTokenCount(bodyLines.join('\n')),
|
|
118
|
+
savedTokens: 0,
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
const compactedLines = compactedBody.text ? compactedBody.text.split(/\r?\n/) : [];
|
|
122
|
+
const output = [header, ...compactedLines, footer].join('\n');
|
|
123
|
+
|
|
124
|
+
if (thresholdPlan.active) {
|
|
125
|
+
await writeThresholdCompactPlan(projectRoot, {
|
|
126
|
+
...thresholdPlan,
|
|
127
|
+
tokensBefore: compactedBody.tokensBefore,
|
|
128
|
+
tokensAfter: compactedBody.tokensAfter,
|
|
129
|
+
savedTokens: compactedBody.savedTokens,
|
|
130
|
+
}, config);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const compactSource = thresholdPlan.active
|
|
134
|
+
? `threshold-${thresholdPlan.phase}-precompact`
|
|
135
|
+
: 'precompact-reinject';
|
|
136
|
+
const rawTokens = estimateTokenCount(rawText);
|
|
137
|
+
const outputTokens = estimateTokenCount(output);
|
|
138
|
+
|
|
139
|
+
if (config.tokenPipeline?.promptCache) {
|
|
140
|
+
await writePromptCacheEntry(projectRoot, {
|
|
141
|
+
requestKey,
|
|
142
|
+
kind: compactSource,
|
|
143
|
+
updatedAt: Date.now(),
|
|
144
|
+
tokensBefore: rawTokens,
|
|
145
|
+
tokensAfter: outputTokens,
|
|
146
|
+
savedTokens: Math.max(0, rawTokens - outputTokens),
|
|
147
|
+
content: output,
|
|
148
|
+
metadata: {
|
|
149
|
+
hasRouteSummary: Boolean(state?.routeSummary),
|
|
150
|
+
hasPreviousContext: dynamicLines.some((line) => line.startsWith('- Previous context:')),
|
|
151
|
+
thresholdPhase: thresholdPlan.active ? thresholdPlan.phase : null,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
await recordCompaction(projectRoot, {
|
|
157
|
+
timestamp: Date.now(),
|
|
158
|
+
source: compactSource,
|
|
159
|
+
tokensBefore: rawTokens,
|
|
160
|
+
tokensAfter: outputTokens,
|
|
161
|
+
savedTokens: Math.max(0, rawTokens - outputTokens),
|
|
162
|
+
metadata: {
|
|
163
|
+
hasRouteSummary: Boolean(state?.routeSummary),
|
|
164
|
+
hasPreviousContext: dynamicLines.some((line) => line.startsWith('- Previous context:')),
|
|
165
|
+
thresholdPhase: thresholdPlan.active ? thresholdPlan.phase : null,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
process.stdout.write(output);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function shouldCompress(config) {
|
|
173
|
+
return Boolean(
|
|
174
|
+
config?.compact?.enabled
|
|
175
|
+
|| config?.tokenPipeline?.inputCompression
|
|
176
|
+
|| config?.tokenPipeline?.outputCompression,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function defaultRuntimeConfig() {
|
|
181
|
+
return {
|
|
182
|
+
compact: {
|
|
183
|
+
enabled: true,
|
|
184
|
+
},
|
|
185
|
+
tokenPipeline: {
|
|
186
|
+
inputCompression: true,
|
|
187
|
+
outputCompression: true,
|
|
188
|
+
promptCache: true,
|
|
189
|
+
},
|
|
190
|
+
memory: {
|
|
191
|
+
enabled: true,
|
|
192
|
+
progressiveRetrieval: true,
|
|
193
|
+
maxInjectionTokens: 320,
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function deepMerge(base, override) {
|
|
199
|
+
if (!override || typeof override !== 'object' || Array.isArray(override)) {
|
|
200
|
+
return override === undefined ? base : override;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const merged = { ...base };
|
|
204
|
+
for (const [key, value] of Object.entries(override)) {
|
|
205
|
+
if (
|
|
206
|
+
value
|
|
207
|
+
&& typeof value === 'object'
|
|
208
|
+
&& !Array.isArray(value)
|
|
209
|
+
&& merged[key]
|
|
210
|
+
&& typeof merged[key] === 'object'
|
|
211
|
+
&& !Array.isArray(merged[key])
|
|
212
|
+
) {
|
|
213
|
+
merged[key] = deepMerge(merged[key], value);
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
merged[key] = value;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return merged;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async function loadRuntimeConfig(projectRoot) {
|
|
224
|
+
const runtimePaths = buildRuntimePaths(projectRoot);
|
|
225
|
+
const raw = await readJson(runtimePaths.configPath, {});
|
|
226
|
+
return deepMerge(defaultRuntimeConfig(), raw && typeof raw === 'object' ? raw : {});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function loadFreshRouteState(projectRoot) {
|
|
230
|
+
const statePath = path.join(projectRoot, '.claude', 'ukit', 'skill-router-state.json');
|
|
231
|
+
const state = await readJson(statePath, {});
|
|
232
|
+
if (typeof state?.ts === 'number' && (Date.now() - state.ts) > STATE_TTL_MS) {
|
|
233
|
+
return {};
|
|
234
|
+
}
|
|
235
|
+
return state && typeof state === 'object' ? state : {};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function unique(values) {
|
|
239
|
+
return [...new Set((values || []).filter(Boolean))];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function deriveCanonicalSkillPath(skillId) {
|
|
243
|
+
const normalized = String(skillId || '').trim();
|
|
244
|
+
if (!normalized) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return `.claude/skills/${normalized}/SKILL.md`;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function getActiveSkillPath(skill = {}) {
|
|
252
|
+
const explicitPath = typeof skill?.path === 'string' ? skill.path.trim() : '';
|
|
253
|
+
if (explicitPath) {
|
|
254
|
+
return explicitPath;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return deriveCanonicalSkillPath(skill?.id);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function summarize(values, limit = 2) {
|
|
261
|
+
const normalized = unique(values);
|
|
262
|
+
return {
|
|
263
|
+
items: normalized.slice(0, limit),
|
|
264
|
+
total: normalized.length,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function normalizeTaskType(taskType) {
|
|
269
|
+
const normalized = String(taskType || '').trim().toLowerCase();
|
|
270
|
+
return ['trivial', 'simple', 'non-trivial'].includes(normalized) ? normalized : '';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function buildStaticGuidanceLines(state = {}, { compact = true } = {}) {
|
|
274
|
+
const taskType = normalizeTaskType(state?.routingContext?.taskType);
|
|
275
|
+
if (!compact) {
|
|
276
|
+
return [
|
|
277
|
+
'- Trivial: act directly; no doc reads.',
|
|
278
|
+
'- Simple: read docs/MEMORY.md; use context resolver for related files.',
|
|
279
|
+
'- Non-trivial: read docs/MEMORY.md + docs/PROJECT.md + docs/CODE_MAP.md.',
|
|
280
|
+
'- WORKLOG: read only for continuation/debugging.',
|
|
281
|
+
'- If confidence is low or the area is high-risk, escalate analysis or ask 1 short clarify question.',
|
|
282
|
+
'- Reuse existing code. Use yarn. Run tests after code changes.',
|
|
283
|
+
'- Scope-based verification: match verify effort to change scope.',
|
|
284
|
+
'- Auto-activate matching project-local skills from prompt + tool/file signals.',
|
|
285
|
+
];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const currentLaneLine = taskType === 'trivial'
|
|
289
|
+
? '- Current lane: trivial => act directly; no doc reads.'
|
|
290
|
+
: (
|
|
291
|
+
taskType === 'simple'
|
|
292
|
+
? '- Current lane: simple => read docs/MEMORY.md; use context resolver for related files.'
|
|
293
|
+
: (
|
|
294
|
+
taskType === 'non-trivial'
|
|
295
|
+
? '- Current lane: non-trivial => read docs/MEMORY.md + docs/PROJECT.md + docs/CODE_MAP.md.'
|
|
296
|
+
: '- Task lanes: trivial=act directly; simple=read docs/MEMORY.md + resolver; non-trivial=read docs/MEMORY.md + docs/PROJECT.md + docs/CODE_MAP.md.'
|
|
297
|
+
)
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
return [
|
|
301
|
+
currentLaneLine,
|
|
302
|
+
'- WORKLOG: read only for continuation/debugging.',
|
|
303
|
+
'- If confidence is low or the area is high-risk, escalate analysis or ask 1 short clarify question.',
|
|
304
|
+
'- Reuse existing code; use yarn; verify after changes with scope-matched effort.',
|
|
305
|
+
'- Auto-activate matching project-local skills from prompt + tool/file signals.',
|
|
306
|
+
];
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function formatSegment(label, summary) {
|
|
310
|
+
const items = summary?.items || [];
|
|
311
|
+
if (items.length === 0) return null;
|
|
312
|
+
const extraCount = Math.max((summary?.total || items.length) - items.length, 0);
|
|
313
|
+
return label + '=' + items.join(',') + (extraCount > 0 ? ',+' + extraCount : '');
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function stripShellQuotes(value) {
|
|
317
|
+
return String(value || '').replace(/^['"]|['"]$/g, '');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function compactHelperHint(command) {
|
|
321
|
+
if (typeof command !== 'string' || !command.trim()) return null;
|
|
322
|
+
|
|
323
|
+
const normalized = command.trim().replace(/\s+/g, ' ');
|
|
324
|
+
const scriptMatch = normalized.match(/^node\s+([^\s]+)(?:\s+(.*))?$/i);
|
|
325
|
+
if (!scriptMatch) return normalized.length > 96 ? normalized.slice(0, 93) + '...' : normalized;
|
|
326
|
+
|
|
327
|
+
const scriptName = scriptMatch[1].split('/').pop() || scriptMatch[1];
|
|
328
|
+
const rest = scriptMatch[2] || '';
|
|
329
|
+
const targetMatch = rest.match(/--target\s+("[^"]+"|'[^']+'|\S+)/);
|
|
330
|
+
const typeMatch = rest.match(/--type\s+(\S+)/);
|
|
331
|
+
const parts = [scriptName];
|
|
332
|
+
if (targetMatch) parts.push('target=' + stripShellQuotes(targetMatch[1]));
|
|
333
|
+
if (typeMatch) parts.push('type=' + typeMatch[1]);
|
|
334
|
+
return parts.join(' ');
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function extractSegment(line, label) {
|
|
338
|
+
if (typeof line !== 'string' || !line.trim()) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const match = line.match(new RegExp(`(?:^|\\|\\s*)${label}=([^|]+)`, 'i'));
|
|
343
|
+
return match ? `${label}=${String(match[1] || '').trim()}` : null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function hasStructuredRouteSummaryField(state, field) {
|
|
347
|
+
return Boolean(
|
|
348
|
+
state?.routeSummary
|
|
349
|
+
&& Object.prototype.hasOwnProperty.call(state.routeSummary, field),
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function derivePolicyMode(state) {
|
|
354
|
+
return hasStructuredRouteSummaryField(state, 'policyMode')
|
|
355
|
+
? (state?.routeSummary?.policyMode || null)
|
|
356
|
+
: (
|
|
357
|
+
state?.verificationRecommendation?.executionPolicy?.policyMode
|
|
358
|
+
|| null
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function deriveHelperHint(state) {
|
|
363
|
+
const hasStructuredNextActionCommand = hasStructuredRouteSummaryField(state, 'nextActionCommand');
|
|
364
|
+
return state?.routeSummary?.helperHint
|
|
365
|
+
|| state?.helpers?.verificationHelperHint
|
|
366
|
+
|| (
|
|
367
|
+
(!hasStructuredNextActionCommand && state?.nextAction?.command)
|
|
368
|
+
? null
|
|
369
|
+
: compactHelperHint(
|
|
370
|
+
(
|
|
371
|
+
hasStructuredRouteSummaryField(state, 'nextActionType')
|
|
372
|
+
? state?.routeSummary?.nextActionType
|
|
373
|
+
: state?.nextAction?.type
|
|
374
|
+
) === 'pull-indexed-context'
|
|
375
|
+
? state?.contextRecommendation?.command
|
|
376
|
+
: state?.verificationRecommendation?.helperCommand,
|
|
377
|
+
)
|
|
378
|
+
)
|
|
379
|
+
|| null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function deriveNextActionSegment(state) {
|
|
383
|
+
const nextActionCommand = hasStructuredRouteSummaryField(state, 'nextActionCommand')
|
|
384
|
+
? (state?.routeSummary?.nextActionCommand || '')
|
|
385
|
+
: (state?.nextAction?.command || '');
|
|
386
|
+
if (nextActionCommand) {
|
|
387
|
+
return `next=${nextActionCommand}`;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const nextActionType = hasStructuredRouteSummaryField(state, 'nextActionType')
|
|
391
|
+
? (state?.routeSummary?.nextActionType || '')
|
|
392
|
+
: (state?.nextAction?.type || '');
|
|
393
|
+
return nextActionType ? `next=${nextActionType}` : null;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function deriveNextActionType(state) {
|
|
397
|
+
return hasStructuredRouteSummaryField(state, 'nextActionType')
|
|
398
|
+
? (state?.routeSummary?.nextActionType || '')
|
|
399
|
+
: (state?.nextAction?.type || '');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function inferTargetSegmentFromHelperHint(helperHint) {
|
|
403
|
+
if (typeof helperHint !== 'string' || !helperHint.trim()) {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const match = helperHint.match(/(?:^|\s)target=([^\s]+)/);
|
|
408
|
+
return match ? `targets=${String(match[1] || '').trim()}` : null;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function buildStructuredRouteLine(state, legacyRouteLine = '') {
|
|
412
|
+
const helperHint = deriveHelperHint(state);
|
|
413
|
+
const policyMode = derivePolicyMode(state);
|
|
414
|
+
const nextActionType = deriveNextActionType(state);
|
|
415
|
+
const hasStructuredPolicyMode = hasStructuredRouteSummaryField(state, 'policyMode');
|
|
416
|
+
const hasStructuredNextAction = hasStructuredRouteSummaryField(state, 'nextActionCommand')
|
|
417
|
+
|| hasStructuredRouteSummaryField(state, 'nextActionType');
|
|
418
|
+
const hasStructuredHelperHint = hasStructuredRouteSummaryField(state, 'helperHint');
|
|
419
|
+
const helperOwnsTarget = typeof helperHint === 'string'
|
|
420
|
+
&& /(?:^|\s)target=([^\s]+)/.test(helperHint);
|
|
421
|
+
const helperFirstLane = helperOwnsTarget && (
|
|
422
|
+
nextActionType === 'pull-indexed-context'
|
|
423
|
+
|| nextActionType === 'ask-user-confirmation'
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
return [
|
|
427
|
+
state?.routingContext?.taskType ? 'task=' + state.routingContext.taskType : null,
|
|
428
|
+
helperFirstLane
|
|
429
|
+
? null
|
|
430
|
+
: (extractSegment(legacyRouteLine, 'targets') || inferTargetSegmentFromHelperHint(helperHint)),
|
|
431
|
+
helperFirstLane ? null : extractSegment(legacyRouteLine, 'tests'),
|
|
432
|
+
helperFirstLane ? null : extractSegment(legacyRouteLine, 'styles'),
|
|
433
|
+
policyMode
|
|
434
|
+
? 'policy=' + policyMode
|
|
435
|
+
: (hasStructuredPolicyMode ? null : extractSegment(legacyRouteLine, 'policy')),
|
|
436
|
+
deriveNextActionSegment(state)
|
|
437
|
+
|| (hasStructuredNextAction ? null : extractSegment(legacyRouteLine, 'next')),
|
|
438
|
+
helperHint
|
|
439
|
+
? 'helper=' + helperHint
|
|
440
|
+
: (hasStructuredHelperHint ? null : extractSegment(legacyRouteLine, 'helper')),
|
|
441
|
+
].filter(Boolean).join(' | ');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function extractDelegateHint(state, routeLine) {
|
|
445
|
+
const explicit = typeof state?.routeSummary?.delegateHint === 'string'
|
|
446
|
+
? state.routeSummary.delegateHint.trim()
|
|
447
|
+
: '';
|
|
448
|
+
if (explicit) {
|
|
449
|
+
return explicit;
|
|
450
|
+
}
|
|
451
|
+
if (hasStructuredRouteSummaryField(state, 'delegateHint')) {
|
|
452
|
+
return '';
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const line = typeof routeLine === 'string' ? routeLine : '';
|
|
456
|
+
const match = line.match(/(?:^|\|\s*)delegate=([^|]+)/i);
|
|
457
|
+
return match ? String(match[1] || '').trim() : '';
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function inferIndexFirstDelegationOrder(state, routeLine) {
|
|
461
|
+
const nextActionType = deriveNextActionType(state);
|
|
462
|
+
if (nextActionType === 'pull-indexed-context') {
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const helperHint = deriveHelperHint(state);
|
|
467
|
+
if (typeof helperHint === 'string' && /^resolve-context\.mjs(?:\s|$)/i.test(helperHint)) {
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return typeof routeLine === 'string' && /(?:^|\|\s*)next=pull-indexed-context(?:\s*\||$)/i.test(routeLine);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function buildLegacyRouteLine(state) {
|
|
475
|
+
const preview = state?.contextRecommendation?.preview || {};
|
|
476
|
+
const nextAction = state?.nextAction || null;
|
|
477
|
+
const policyMode = state?.verificationRecommendation?.executionPolicy?.policyMode || null;
|
|
478
|
+
const helperHint = nextAction?.command
|
|
479
|
+
? null
|
|
480
|
+
: compactHelperHint(
|
|
481
|
+
nextAction?.type === 'pull-indexed-context'
|
|
482
|
+
? state?.contextRecommendation?.command
|
|
483
|
+
: state?.verificationRecommendation?.helperCommand,
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
return [
|
|
487
|
+
state?.routingContext?.taskType ? 'task=' + state.routingContext.taskType : null,
|
|
488
|
+
formatSegment('targets', summarize(preview.primaryTargets || [], 2)),
|
|
489
|
+
formatSegment('tests', summarize(preview.relatedTests || [], 2)),
|
|
490
|
+
formatSegment('styles', summarize(preview.styleFiles || [], 1)),
|
|
491
|
+
policyMode ? 'policy=' + policyMode : null,
|
|
492
|
+
nextAction?.command
|
|
493
|
+
? 'next=' + nextAction.command
|
|
494
|
+
: nextAction?.type
|
|
495
|
+
? 'next=' + nextAction.type
|
|
496
|
+
: null,
|
|
497
|
+
helperHint ? 'helper=' + helperHint : null,
|
|
498
|
+
].filter(Boolean).join(' | ');
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
async function buildRouteStateLines(state) {
|
|
502
|
+
const lines = [];
|
|
503
|
+
const rawSkillPaths = unique(
|
|
504
|
+
Array.isArray(state?.activeSkills) ? state.activeSkills.map((item) => getActiveSkillPath(item)) : [],
|
|
505
|
+
);
|
|
506
|
+
const legacyRouteLine = state?.routeSummary?.line || buildLegacyRouteLine(state);
|
|
507
|
+
const routeLine = buildStructuredRouteLine(state, legacyRouteLine) || legacyRouteLine;
|
|
508
|
+
const delegateHint = extractDelegateHint(state, legacyRouteLine || routeLine);
|
|
509
|
+
const indexFirstDelegationOrder = inferIndexFirstDelegationOrder(state, legacyRouteLine || routeLine);
|
|
510
|
+
const shouldShowSkillSignals = rawSkillPaths.length > 0 && (!routeLine || rawSkillPaths.length > 1);
|
|
511
|
+
const skillPaths = summarize(rawSkillPaths, routeLine ? 1 : 2);
|
|
512
|
+
|
|
513
|
+
if (shouldShowSkillSignals && skillPaths.items.length > 0) {
|
|
514
|
+
lines.push('- Recent skill signals: ' + skillPaths.items.join(', ') + (skillPaths.total > skillPaths.items.length ? ', +' + (skillPaths.total - skillPaths.items.length) + ' more' : ''));
|
|
515
|
+
}
|
|
516
|
+
if (routeLine) {
|
|
517
|
+
lines.push('- Recent routed lane: ' + routeLine);
|
|
518
|
+
}
|
|
519
|
+
if (delegateHint) {
|
|
520
|
+
lines.push('- Recent delegation hint: ' + (indexFirstDelegationOrder
|
|
521
|
+
? `after indexed context, prefer internal lane ${delegateHint}`
|
|
522
|
+
: `prefer internal lane ${delegateHint}`));
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
return lines;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
async function buildRecentOutputLines(projectRoot, config) {
|
|
529
|
+
if (!config?.tokenPipeline?.outputCompression) {
|
|
530
|
+
return [];
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const runtimePaths = buildRuntimePaths(projectRoot);
|
|
534
|
+
const outputHistory = await readJson(runtimePaths.outputHistoryPath, { entries: [] });
|
|
535
|
+
const entries = Array.isArray(outputHistory?.entries) ? outputHistory.entries : [];
|
|
536
|
+
const fresh = entries
|
|
537
|
+
.filter((entry) => typeof entry?.timestamp === 'number' && (Date.now() - entry.timestamp) <= (30 * 60 * 1000))
|
|
538
|
+
.slice(0, 1);
|
|
539
|
+
|
|
540
|
+
if (fresh.length === 0) {
|
|
541
|
+
return [];
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return fresh.map((entry) => `- Recent command output: ${compactInlineSummary(entry.summary)}`);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function compactInlineSummary(summary, { maxSegments = INLINE_SUMMARY_MAX_SEGMENTS } = {}) {
|
|
548
|
+
const lines = unique(
|
|
549
|
+
String(summary || '')
|
|
550
|
+
.split(/\r?\n/)
|
|
551
|
+
.map((line) => line.trim())
|
|
552
|
+
.filter(Boolean),
|
|
553
|
+
);
|
|
554
|
+
if (lines.length === 0) {
|
|
555
|
+
return '';
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (lines.length <= maxSegments) {
|
|
559
|
+
return lines.join(' | ');
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const firstLine = lines[0];
|
|
563
|
+
const middleLines = lines.slice(1, -1);
|
|
564
|
+
const selectedMiddle = [];
|
|
565
|
+
|
|
566
|
+
for (const line of middleLines) {
|
|
567
|
+
if (selectedMiddle.length >= Math.max(0, maxSegments - 2)) {
|
|
568
|
+
break;
|
|
569
|
+
}
|
|
570
|
+
if (!INLINE_SUMMARY_SIGNAL_PATTERNS.some((pattern) => pattern.test(line))) {
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
if (!selectedMiddle.includes(line)) {
|
|
574
|
+
selectedMiddle.push(line);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
for (const line of middleLines) {
|
|
579
|
+
if (selectedMiddle.length >= Math.max(0, maxSegments - 2)) {
|
|
580
|
+
break;
|
|
581
|
+
}
|
|
582
|
+
if (!selectedMiddle.includes(line)) {
|
|
583
|
+
selectedMiddle.push(line);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const tailLine = selectInlineSummaryTail(lines);
|
|
588
|
+
const selected = unique([firstLine, ...selectedMiddle, tailLine]).slice(0, maxSegments);
|
|
589
|
+
const remaining = Math.max(0, lines.length - selected.length);
|
|
590
|
+
return remaining > 0
|
|
591
|
+
? `${selected.join(' | ')} | +${remaining} more`
|
|
592
|
+
: selected.join(' | ');
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function selectInlineSummaryTail(lines = []) {
|
|
596
|
+
for (const pattern of INLINE_SUMMARY_TAIL_PATTERNS) {
|
|
597
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
598
|
+
if (pattern.test(lines[index])) {
|
|
599
|
+
return lines[index];
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
return lines[lines.length - 1] ?? '';
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function routeStateHasExplicitResolverHint(state = {}) {
|
|
608
|
+
const helperHint = String(state?.routeSummary?.helperHint || '').trim();
|
|
609
|
+
if (/resolve-context\.mjs/i.test(helperHint)) {
|
|
610
|
+
return true;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const routeLine = String(state?.routeSummary?.line || '').trim();
|
|
614
|
+
const lineHelperMatch = routeLine.match(/(?:^|\|\s*)helper=([^|]+)/i);
|
|
615
|
+
if (lineHelperMatch && /resolve-context\.mjs/i.test(String(lineHelperMatch[1] || '').trim())) {
|
|
616
|
+
return true;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
return false;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
async function buildResolverHintLines(projectRoot, state = {}) {
|
|
623
|
+
if (routeStateHasExplicitResolverHint(state)) {
|
|
624
|
+
return [];
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
try {
|
|
628
|
+
await fs.access(path.join(projectRoot, '.cache', 'index', 'analogs.json'));
|
|
629
|
+
return [
|
|
630
|
+
'- Context resolver available: node .claude/ukit/index/resolve-context.mjs "<intent>"; use analog retrieval for clone/follow-pattern tasks.',
|
|
631
|
+
];
|
|
632
|
+
} catch {
|
|
633
|
+
return [];
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
async function buildDuraOneHintLines(projectRoot) {
|
|
638
|
+
try {
|
|
639
|
+
await fs.access(path.join(projectRoot, '.claude', 'skills', 'duraone', 'SKILL.md'));
|
|
640
|
+
return ['- DuraOne active: ALWAYS read .claude/skills/duraone/SKILL.md before coding.'];
|
|
641
|
+
} catch {
|
|
642
|
+
return [];
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function normalize(text) {
|
|
647
|
+
return String(text ?? '')
|
|
648
|
+
.toLowerCase()
|
|
649
|
+
.replace(/[^\p{L}\p{N}\s./:_-]/gu, ' ')
|
|
650
|
+
.replace(/\s+/g, ' ')
|
|
651
|
+
.trim();
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function tokenize(text) {
|
|
655
|
+
return normalize(text)
|
|
656
|
+
.split(/\s+/)
|
|
657
|
+
.filter((token) => token && !STOPWORDS.has(token) && token.length > 1);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
function getMemoryTimestamp(item) {
|
|
661
|
+
return item.content?.updatedAt
|
|
662
|
+
?? item.content?.endedAt
|
|
663
|
+
?? item.content?.startedAt
|
|
664
|
+
?? 0;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function buildMemorySegments(item) {
|
|
668
|
+
const content = item.content ?? {};
|
|
669
|
+
if (item.type === 'project') {
|
|
670
|
+
return [
|
|
671
|
+
{ text: content.name, weight: 2 },
|
|
672
|
+
{ text: content.architecture, weight: 3 },
|
|
673
|
+
{ text: (content.techStack ?? []).join(' '), weight: 2 },
|
|
674
|
+
{ text: (content.activeRules ?? []).join(' '), weight: 2 },
|
|
675
|
+
{ text: (content.decisions ?? []).map((decision) => `${decision.what} ${decision.why}`).join(' '), weight: 7 },
|
|
676
|
+
];
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (item.type === 'session') {
|
|
680
|
+
return [
|
|
681
|
+
{ text: content.taskDescription, weight: 4 },
|
|
682
|
+
{ text: content.outcome, weight: 1 },
|
|
683
|
+
{ text: (content.keyActions ?? []).join(' '), weight: 3 },
|
|
684
|
+
{ text: (content.nextSteps ?? []).join(' '), weight: 2 },
|
|
685
|
+
{ text: (content.filesChanged ?? []).join(' '), weight: 1 },
|
|
686
|
+
{ text: (content.decisionsMade ?? []).map((decision) => `${decision.what} ${decision.why}`).join(' '), weight: 4 },
|
|
687
|
+
];
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
return [
|
|
691
|
+
{ text: JSON.stringify(content.preferences ?? {}), weight: 1 },
|
|
692
|
+
{ text: (content.rules ?? []).join(' '), weight: 2 },
|
|
693
|
+
];
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function scoreMemoryItem(item, queryTokens) {
|
|
697
|
+
if (queryTokens.length === 0) {
|
|
698
|
+
return 0;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
let score = 0;
|
|
702
|
+
for (const segment of buildMemorySegments(item)) {
|
|
703
|
+
const segmentTokens = new Set(tokenize(segment.text));
|
|
704
|
+
for (const token of queryTokens) {
|
|
705
|
+
if (segmentTokens.has(token)) {
|
|
706
|
+
score += segment.weight;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
if (score === 0) {
|
|
712
|
+
return 0;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const recencyBonus = getMemoryTimestamp(item) > 0 ? Math.min(1, getMemoryTimestamp(item) / Date.now()) : 0;
|
|
716
|
+
return score + recencyBonus;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
async function readDirectoryJsonItems(dirPath) {
|
|
720
|
+
let entries = [];
|
|
721
|
+
try {
|
|
722
|
+
entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
723
|
+
} catch {
|
|
724
|
+
return [];
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const items = [];
|
|
728
|
+
for (const entry of entries) {
|
|
729
|
+
if (!entry.isFile() || !entry.name.endsWith('.json')) {
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
734
|
+
const content = await readJson(fullPath, null);
|
|
735
|
+
if (content && typeof content === 'object') {
|
|
736
|
+
items.push({
|
|
737
|
+
fileName: entry.name,
|
|
738
|
+
filePath: fullPath,
|
|
739
|
+
content,
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
return items.sort((left, right) => left.fileName.localeCompare(right.fileName));
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
async function detectProjectId(projectRoot) {
|
|
748
|
+
const pkg = await readJson(path.join(projectRoot, 'package.json'), null);
|
|
749
|
+
if (typeof pkg?.name === 'string' && pkg.name.trim()) {
|
|
750
|
+
return pkg.name.trim();
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
return path.basename(projectRoot);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
async function listMemoryItems(projectRoot) {
|
|
757
|
+
const runtimePaths = buildRuntimePaths(projectRoot);
|
|
758
|
+
const userMemory = (await readJson(runtimePaths.userMemoryPath, null)) ?? { preferences: {}, rules: [] };
|
|
759
|
+
const projectMemories = await readDirectoryJsonItems(runtimePaths.projectsDir);
|
|
760
|
+
const sessionMemories = await readDirectoryJsonItems(runtimePaths.sessionsDir);
|
|
761
|
+
|
|
762
|
+
return [
|
|
763
|
+
{
|
|
764
|
+
id: 'user:user',
|
|
765
|
+
type: 'user',
|
|
766
|
+
content: userMemory,
|
|
767
|
+
},
|
|
768
|
+
...projectMemories.map((item) => ({
|
|
769
|
+
id: `project:${item.content.id ?? item.fileName.replace(/\.json$/, '')}`,
|
|
770
|
+
type: 'project',
|
|
771
|
+
content: item.content,
|
|
772
|
+
})),
|
|
773
|
+
...sessionMemories.map((item) => ({
|
|
774
|
+
id: `session:${item.content.id ?? item.fileName.replace(/\.json$/, '')}`,
|
|
775
|
+
type: 'session',
|
|
776
|
+
content: item.content,
|
|
777
|
+
})),
|
|
778
|
+
];
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
function buildPreviousContextSnippet(item) {
|
|
782
|
+
const content = item.content ?? {};
|
|
783
|
+
if (item.type === 'project') {
|
|
784
|
+
const decisions = compactPhraseList((content.decisions ?? []).map((decision) => decision.what), { limit: 1 });
|
|
785
|
+
const rules = compactPhraseList(content.activeRules ?? [], { limit: 1 });
|
|
786
|
+
return `[project] ${content.name ?? content.id ?? 'project'} — decisions: ${decisions || 'n/a'}${rules ? ` — rules: ${rules}` : ''}`;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
if (item.type === 'session') {
|
|
790
|
+
const actions = compactPhraseList(content.keyActions ?? [], { limit: 1 });
|
|
791
|
+
const nextSteps = compactPhraseList(content.nextSteps ?? [], { limit: 1 });
|
|
792
|
+
return `[session] ${content.taskDescription ?? item.id} — outcome: ${content.outcome ?? 'unknown'}${actions ? ` — actions: ${actions}` : ''}${nextSteps ? ` — next: ${nextSteps}` : ''}`;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const rules = compactPhraseList(content.rules ?? [], { limit: 1 });
|
|
796
|
+
return `[user] rules: ${rules || 'n/a'}`;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
function compactPhraseList(values, { limit = 1, fallback = 'n/a' } = {}) {
|
|
800
|
+
const normalized = unique(
|
|
801
|
+
(values ?? [])
|
|
802
|
+
.map((value) => String(value ?? '').trim())
|
|
803
|
+
.filter(Boolean),
|
|
804
|
+
);
|
|
805
|
+
|
|
806
|
+
if (normalized.length === 0) {
|
|
807
|
+
return fallback;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
const shown = normalized.slice(0, limit);
|
|
811
|
+
const remaining = normalized.length - shown.length;
|
|
812
|
+
return remaining > 0
|
|
813
|
+
? `${shown.join('; ')} (+${remaining} more)`
|
|
814
|
+
: shown.join('; ');
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
function readSharedPreviousContextLine(state) {
|
|
818
|
+
const line = typeof state?.previousContext?.line === 'string'
|
|
819
|
+
? state.previousContext.line.trim()
|
|
820
|
+
: '';
|
|
821
|
+
|
|
822
|
+
return line || null;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
async function buildPreviousContextLines(projectRoot, state, config) {
|
|
826
|
+
if (!config?.memory?.enabled || !config?.memory?.progressiveRetrieval) {
|
|
827
|
+
return [];
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
const taskQuery = String(
|
|
831
|
+
state?.routingContext?.lastExplicitUserPromptText
|
|
832
|
+
|| state?.routingContext?.promptText
|
|
833
|
+
|| state?.routingContext?.targetFile
|
|
834
|
+
|| '',
|
|
835
|
+
).trim();
|
|
836
|
+
if (!taskQuery) {
|
|
837
|
+
return [];
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
const sharedPreviousContextLine = readSharedPreviousContextLine(state);
|
|
841
|
+
if (sharedPreviousContextLine) {
|
|
842
|
+
return [`- Previous context: ${sharedPreviousContextLine}`];
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const projectId = await detectProjectId(projectRoot);
|
|
846
|
+
const items = await listMemoryItems(projectRoot);
|
|
847
|
+
const queryTokens = tokenize(taskQuery);
|
|
848
|
+
const rankedItems = items
|
|
849
|
+
.filter((item) => item.type !== 'user')
|
|
850
|
+
.filter((item) => (
|
|
851
|
+
item.type === 'project'
|
|
852
|
+
? (item.content?.id === projectId)
|
|
853
|
+
: (item.type === 'session' ? item.content?.projectId === projectId : true)
|
|
854
|
+
))
|
|
855
|
+
.map((item) => ({ item, score: scoreMemoryItem(item, queryTokens) }))
|
|
856
|
+
.filter((entry) => entry.score > 0)
|
|
857
|
+
.sort((left, right) => (
|
|
858
|
+
right.score - left.score
|
|
859
|
+
|| getMemoryTimestamp(right.item) - getMemoryTimestamp(left.item)
|
|
860
|
+
))
|
|
861
|
+
.slice(0, 2)
|
|
862
|
+
.map((entry) => entry.item);
|
|
863
|
+
|
|
864
|
+
if (rankedItems.length === 0) {
|
|
865
|
+
return [];
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
return [`- Previous context: ${rankedItems.map((item) => buildPreviousContextSnippet(item)).join(' | ')}`];
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
main().catch((error) => {
|
|
872
|
+
console.error('[UKit] Failed to build compact reinject context:', error?.message || String(error));
|
|
873
|
+
process.exitCode = 1;
|
|
874
|
+
});
|