@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,44 @@
|
|
|
1
|
+
const TOKEN_PATTERN = /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g;
|
|
2
|
+
|
|
3
|
+
function flattenObject(input, prefix = '', output = {}) {
|
|
4
|
+
if (input === null || input === undefined) {
|
|
5
|
+
return output;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (typeof input !== 'object' || Array.isArray(input)) {
|
|
9
|
+
output[prefix] = input;
|
|
10
|
+
return output;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
for (const [key, value] of Object.entries(input)) {
|
|
14
|
+
const nextKey = prefix ? `${prefix}.${key}` : key;
|
|
15
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
16
|
+
flattenObject(value, nextKey, output);
|
|
17
|
+
} else {
|
|
18
|
+
output[nextKey] = value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return output;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function renderTemplateString(templateString, variables) {
|
|
26
|
+
const flattened = flattenObject(variables);
|
|
27
|
+
|
|
28
|
+
return templateString.replace(TOKEN_PATTERN, (fullMatch, token) => {
|
|
29
|
+
if (!(token in flattened)) {
|
|
30
|
+
return fullMatch;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const value = flattened[token];
|
|
34
|
+
if (value === undefined || value === null) {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (typeof value === 'boolean') {
|
|
39
|
+
return value ? 'true' : 'false';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return String(value);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { pathExists, readJsonIfExists } from '../core/fileOps.js';
|
|
4
|
+
|
|
5
|
+
const FRONTEND_DEPENDENCIES = ['react', 'vue', 'nuxt', 'next', 'svelte', '@angular/core', 'vite'];
|
|
6
|
+
const BACKEND_API_DEPENDENCIES = ['express', 'fastify', '@nestjs/core', 'koa', 'hapi', 'hono'];
|
|
7
|
+
const POSTGRES_DEPENDENCIES = ['pg', 'postgres', 'prisma', 'typeorm', 'sequelize', 'drizzle-orm', 'knex'];
|
|
8
|
+
const TESTING_DEPENDENCIES = ['jest', 'vitest', 'mocha', 'jasmine', '@playwright/test', 'cypress', '@testing-library/react'];
|
|
9
|
+
const REACT_NATIVE_DEPENDENCIES = ['react-native', 'expo', '@expo/cli', '@react-native-community/cli'];
|
|
10
|
+
const DURAONE_SCAN_IGNORE_DIRS = new Set([
|
|
11
|
+
'.cache',
|
|
12
|
+
'.claude',
|
|
13
|
+
'.codex',
|
|
14
|
+
'.git',
|
|
15
|
+
'build',
|
|
16
|
+
'coverage',
|
|
17
|
+
'dist',
|
|
18
|
+
'node_modules',
|
|
19
|
+
]);
|
|
20
|
+
const DURAONE_SCAN_MAX_DEPTH = 3;
|
|
21
|
+
|
|
22
|
+
function collectDependencySet(packageJson) {
|
|
23
|
+
const dependencies = packageJson?.dependencies ?? {};
|
|
24
|
+
const devDependencies = packageJson?.devDependencies ?? {};
|
|
25
|
+
return new Set([...Object.keys(dependencies), ...Object.keys(devDependencies)]);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function collectDependencySignals(dependencySet, names) {
|
|
29
|
+
return names.filter((name) => dependencySet.has(name));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function detectTypeScriptFromPackageJson(packageJson, dependencySet) {
|
|
33
|
+
// explicit typescript dep or ts-specific config in scripts
|
|
34
|
+
if (dependencySet.has('typescript')) return true;
|
|
35
|
+
const scripts = packageJson?.scripts ?? {};
|
|
36
|
+
return Object.values(scripts).some((s) => typeof s === 'string' && (s.includes('tsc') || s.includes('ts-node')));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function detectNuxt(projectRoot) {
|
|
40
|
+
// nuxt.config.ts/js is the canonical marker; also check .nuxt build dir
|
|
41
|
+
const [hasConfigTs, hasConfigJs, hasNuxtDir] = await Promise.all([
|
|
42
|
+
pathExists(path.join(projectRoot, 'nuxt.config.ts')),
|
|
43
|
+
pathExists(path.join(projectRoot, 'nuxt.config.js')),
|
|
44
|
+
pathExists(path.join(projectRoot, '.nuxt')),
|
|
45
|
+
]);
|
|
46
|
+
return hasConfigTs || hasConfigJs || hasNuxtDir;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function detectFlutter(projectRoot) {
|
|
50
|
+
// Flutter projects always have pubspec.yaml with a flutter dependency
|
|
51
|
+
const pubspecPath = path.join(projectRoot, 'pubspec.yaml');
|
|
52
|
+
if (!(await pathExists(pubspecPath))) return false;
|
|
53
|
+
// Confirm it's actually a Flutter project (not just plain Dart)
|
|
54
|
+
const [hasMainDart, hasAndroid, hasIos] = await Promise.all([
|
|
55
|
+
pathExists(path.join(projectRoot, 'lib', 'main.dart')),
|
|
56
|
+
pathExists(path.join(projectRoot, 'android')),
|
|
57
|
+
pathExists(path.join(projectRoot, 'ios')),
|
|
58
|
+
]);
|
|
59
|
+
return hasMainDart || hasAndroid || hasIos;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function detectMonorepo(projectRoot, packageJson) {
|
|
63
|
+
// yarn/npm workspaces, lerna, nx, turborepo, pnpm-workspace
|
|
64
|
+
if (Array.isArray(packageJson?.workspaces) && packageJson.workspaces.length > 0) return true;
|
|
65
|
+
if (typeof packageJson?.workspaces === 'object' && Array.isArray(packageJson.workspaces?.packages)) return true;
|
|
66
|
+
const markers = ['lerna.json', 'nx.json', 'pnpm-workspace.yaml', 'turbo.json'];
|
|
67
|
+
const checks = await Promise.all(markers.map((f) => pathExists(path.join(projectRoot, f))));
|
|
68
|
+
return checks.some(Boolean);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function pushUnique(target, value) {
|
|
72
|
+
if (!target.includes(value)) {
|
|
73
|
+
target.push(value);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function safeReadDir(dirPath) {
|
|
78
|
+
try {
|
|
79
|
+
return await fs.readdir(dirPath, { withFileTypes: true });
|
|
80
|
+
} catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function detectDuraOne(projectRoot) {
|
|
86
|
+
const signals = [];
|
|
87
|
+
|
|
88
|
+
async function scanCandidateParents(currentAbsDir, currentRelDir = '', depth = 0) {
|
|
89
|
+
const entries = await safeReadDir(currentAbsDir);
|
|
90
|
+
const directoryNames = new Set(
|
|
91
|
+
entries
|
|
92
|
+
.filter((entry) => entry.isDirectory())
|
|
93
|
+
.map((entry) => entry.name),
|
|
94
|
+
);
|
|
95
|
+
const prefix = currentRelDir ? `${currentRelDir}/` : '';
|
|
96
|
+
|
|
97
|
+
if (directoryNames.has('FE_DuraOne')) pushUnique(signals, `${prefix}FE_DuraOne`);
|
|
98
|
+
if (directoryNames.has('BE_DuraOne')) pushUnique(signals, `${prefix}BE_DuraOne`);
|
|
99
|
+
if (directoryNames.has('SQL')) {
|
|
100
|
+
const hasSqlRoot = await pathExists(path.join(currentAbsDir, 'SQL', 'duraone'));
|
|
101
|
+
if (hasSqlRoot) {
|
|
102
|
+
pushUnique(signals, `${prefix}SQL/duraone`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (depth >= DURAONE_SCAN_MAX_DEPTH) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const childDirs = entries.filter((entry) => (
|
|
111
|
+
entry.isDirectory()
|
|
112
|
+
&& !DURAONE_SCAN_IGNORE_DIRS.has(entry.name)
|
|
113
|
+
&& entry.name !== 'FE_DuraOne'
|
|
114
|
+
&& entry.name !== 'BE_DuraOne'
|
|
115
|
+
&& entry.name !== 'SQL'
|
|
116
|
+
));
|
|
117
|
+
|
|
118
|
+
await Promise.all(
|
|
119
|
+
childDirs.map((entry) => scanCandidateParents(
|
|
120
|
+
path.join(currentAbsDir, entry.name),
|
|
121
|
+
currentRelDir ? `${currentRelDir}/${entry.name}` : entry.name,
|
|
122
|
+
depth + 1,
|
|
123
|
+
)),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await scanCandidateParents(projectRoot);
|
|
128
|
+
|
|
129
|
+
return signals;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function detectStack(projectRoot) {
|
|
133
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
134
|
+
const packageJson = await readJsonIfExists(packageJsonPath);
|
|
135
|
+
const dependencySet = collectDependencySet(packageJson);
|
|
136
|
+
|
|
137
|
+
const frontendSignals = collectDependencySignals(dependencySet, FRONTEND_DEPENDENCIES);
|
|
138
|
+
const backendApiSignals = collectDependencySignals(dependencySet, BACKEND_API_DEPENDENCIES);
|
|
139
|
+
const postgresSignals = collectDependencySignals(dependencySet, POSTGRES_DEPENDENCIES);
|
|
140
|
+
const testingSignals = collectDependencySignals(dependencySet, TESTING_DEPENDENCIES);
|
|
141
|
+
const reactNativeSignals = collectDependencySignals(dependencySet, REACT_NATIVE_DEPENDENCIES);
|
|
142
|
+
|
|
143
|
+
// Run all file-system checks in parallel
|
|
144
|
+
const [
|
|
145
|
+
hasPrismaSchema,
|
|
146
|
+
hasSrcPages,
|
|
147
|
+
hasSrcApi,
|
|
148
|
+
hasTsConfig,
|
|
149
|
+
hasDockerfile,
|
|
150
|
+
hasDockerCompose,
|
|
151
|
+
hasGitDir,
|
|
152
|
+
isMonorepo,
|
|
153
|
+
isFlutter,
|
|
154
|
+
isNuxt,
|
|
155
|
+
duraoneSignals,
|
|
156
|
+
] = await Promise.all([
|
|
157
|
+
pathExists(path.join(projectRoot, 'prisma', 'schema.prisma')),
|
|
158
|
+
pathExists(path.join(projectRoot, 'src', 'pages')),
|
|
159
|
+
pathExists(path.join(projectRoot, 'src', 'api')),
|
|
160
|
+
pathExists(path.join(projectRoot, 'tsconfig.json')),
|
|
161
|
+
pathExists(path.join(projectRoot, 'Dockerfile')),
|
|
162
|
+
pathExists(path.join(projectRoot, 'docker-compose.yml')).then(
|
|
163
|
+
(a) => a || pathExists(path.join(projectRoot, 'docker-compose.yaml')),
|
|
164
|
+
),
|
|
165
|
+
pathExists(path.join(projectRoot, '.git')),
|
|
166
|
+
detectMonorepo(projectRoot, packageJson),
|
|
167
|
+
detectFlutter(projectRoot),
|
|
168
|
+
detectNuxt(projectRoot),
|
|
169
|
+
detectDuraOne(projectRoot),
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
if (hasPrismaSchema) postgresSignals.push('prisma/schema.prisma');
|
|
173
|
+
if (hasSrcPages) frontendSignals.push('src/pages');
|
|
174
|
+
if (hasSrcApi) backendApiSignals.push('src/api');
|
|
175
|
+
if (isNuxt) frontendSignals.push('nuxt');
|
|
176
|
+
|
|
177
|
+
const isTypeScript = hasTsConfig || detectTypeScriptFromPackageJson(packageJson, dependencySet);
|
|
178
|
+
|
|
179
|
+
const flags = {
|
|
180
|
+
frontend: frontendSignals.length > 0,
|
|
181
|
+
backendApi: backendApiSignals.length > 0,
|
|
182
|
+
postgres: postgresSignals.length > 0,
|
|
183
|
+
typescript: isTypeScript,
|
|
184
|
+
testing: testingSignals.length > 0,
|
|
185
|
+
nuxt: isNuxt,
|
|
186
|
+
next: dependencySet.has('next'),
|
|
187
|
+
flutter: isFlutter,
|
|
188
|
+
reactNative: reactNativeSignals.length > 0,
|
|
189
|
+
duraone: duraoneSignals.length > 0,
|
|
190
|
+
docker: hasDockerfile || hasDockerCompose,
|
|
191
|
+
monorepo: isMonorepo,
|
|
192
|
+
git: hasGitDir,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const detectedPacks = ['core'];
|
|
196
|
+
if (flags.frontend) detectedPacks.push('frontend');
|
|
197
|
+
if (flags.backendApi) detectedPacks.push('backend-api');
|
|
198
|
+
if (flags.postgres) detectedPacks.push('postgres');
|
|
199
|
+
if (flags.duraone) detectedPacks.push('duraone');
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
detectedPacks,
|
|
203
|
+
flags,
|
|
204
|
+
signals: {
|
|
205
|
+
frontend: frontendSignals,
|
|
206
|
+
backendApi: backendApiSignals,
|
|
207
|
+
postgres: postgresSignals,
|
|
208
|
+
testing: testingSignals,
|
|
209
|
+
reactNative: reactNativeSignals,
|
|
210
|
+
duraone: duraoneSignals,
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bug-debugger
|
|
3
|
+
description: "Debugging specialist for reproducible errors, failing tests, and unexpected behavior. Use proactively when investigation will involve noisy logs, stack traces, or a self-contained reproduce-trace-fix-verify loop. Do not use for trivial obvious fixes or broad architecture ideation."
|
|
4
|
+
model: inherit
|
|
5
|
+
color: red
|
|
6
|
+
tools: ["Read", "Grep", "Glob", "Bash", "Edit", "TodoWrite"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Systematic debugging — understand before fixing.
|
|
10
|
+
|
|
11
|
+
## Workflow
|
|
12
|
+
|
|
13
|
+
### 1. Reproduce (required)
|
|
14
|
+
|
|
15
|
+
- Run the failing command/action
|
|
16
|
+
- Capture exact error message and stack trace
|
|
17
|
+
- If not reproducible → document conditions and ask user
|
|
18
|
+
|
|
19
|
+
### 2. Trace Root Cause
|
|
20
|
+
|
|
21
|
+
- Read error location and surrounding code
|
|
22
|
+
- Trace data flow: input → processing → failure point
|
|
23
|
+
- Identify: is this a logic error, state error, or integration error?
|
|
24
|
+
|
|
25
|
+
### 3. Fix
|
|
26
|
+
|
|
27
|
+
- Apply smallest reliable fix at the root cause
|
|
28
|
+
- Do NOT patch symptoms — fix the cause
|
|
29
|
+
|
|
30
|
+
### 4. Verify
|
|
31
|
+
|
|
32
|
+
- Re-run the original failing command → must pass
|
|
33
|
+
- Run related tests: `yarn test [relevant-file]`
|
|
34
|
+
- Check no regression in adjacent functionality
|
|
35
|
+
|
|
36
|
+
### 5. Report
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
STATUS: DONE | BLOCKED | PARTIAL
|
|
40
|
+
SUMMARY: [1-2 sentences — root cause and fix]
|
|
41
|
+
ROOT_CAUSE: [what caused the bug]
|
|
42
|
+
FILES_CHANGED:
|
|
43
|
+
- [file path]: [what changed]
|
|
44
|
+
VERIFIED: [original failing command now passes + test output]
|
|
45
|
+
ISSUES: [any remaining risks or edge cases, or "none"]
|
|
46
|
+
NEXT: [follow-up needed, or "nothing — bug fixed"]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Rules
|
|
50
|
+
|
|
51
|
+
- Don't patch blindly — confirm root cause with evidence
|
|
52
|
+
- For bug triage, use graduated doc budget:
|
|
53
|
+
- obvious/simple bug: `docs/MEMORY.md` only
|
|
54
|
+
- non-trivial bug: `docs/MEMORY.md` + `docs/PROJECT.md` + `docs/CODE_MAP.md`
|
|
55
|
+
- read `docs/WORKLOG.md` only recent relevant entries
|
|
56
|
+
- Keep fix scope minimal — no drive-by refactors
|
|
57
|
+
- If root cause is unclear after 5 minutes of tracing → ask user for more context
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: feature-implementer
|
|
3
|
+
description: "Implementation specialist for clear, self-contained coding tasks. Use proactively when the approach is clear and the work can be completed in a bounded pass with a concise summary. Do not use for trivial one-file tweaks or tightly coupled exploratory work."
|
|
4
|
+
model: inherit
|
|
5
|
+
color: green
|
|
6
|
+
tools: ["Read", "Edit", "Write", "Grep", "Glob", "Bash", "TodoWrite"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Implement requested behavior with minimal scope drift.
|
|
10
|
+
|
|
11
|
+
## Workflow
|
|
12
|
+
|
|
13
|
+
### 1. Understand (< 30 seconds)
|
|
14
|
+
|
|
15
|
+
- Infer intent directly from user request (build/test/docs flow)
|
|
16
|
+
- Apply graduated doc budget:
|
|
17
|
+
- trivial: no docs
|
|
18
|
+
- simple: `docs/MEMORY.md` only
|
|
19
|
+
- non-trivial: `docs/MEMORY.md` + `docs/PROJECT.md` + `docs/CODE_MAP.md`
|
|
20
|
+
- Identify target files and existing patterns
|
|
21
|
+
- If confidence is low or risk is high, ask one short clarifying question before deeper analysis
|
|
22
|
+
|
|
23
|
+
### 2. Plan Approach (< 1 minute)
|
|
24
|
+
|
|
25
|
+
- List files to create/modify (max diff)
|
|
26
|
+
- Implement directly
|
|
27
|
+
|
|
28
|
+
### 3. Implement
|
|
29
|
+
|
|
30
|
+
- Smallest correct change set
|
|
31
|
+
- Reuse existing code before creating new
|
|
32
|
+
- No unrelated changes or speculative refactors
|
|
33
|
+
- Follow project conventions (check `.claude/skills/` for patterns)
|
|
34
|
+
|
|
35
|
+
### 4. Verify
|
|
36
|
+
|
|
37
|
+
- Run existing tests if touched behavior has coverage: `yarn test` or project-specific
|
|
38
|
+
- For SQL changes: verify with `EXPLAIN ANALYZE` on non-trivial queries
|
|
39
|
+
- Check no lint errors introduced
|
|
40
|
+
|
|
41
|
+
### 5. Report
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
STATUS: DONE | BLOCKED | PARTIAL
|
|
45
|
+
SUMMARY: [1-2 sentences of what was implemented]
|
|
46
|
+
FILES_CHANGED:
|
|
47
|
+
- [file path]: [what changed]
|
|
48
|
+
VERIFIED: [test output / manual check result]
|
|
49
|
+
ISSUES: [any problems or edge cases, or "none"]
|
|
50
|
+
NEXT: [follow-up needed, or "nothing — task complete"]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Rules
|
|
54
|
+
|
|
55
|
+
- Add/update tests only when touched behavior already has coverage
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Model Provider
|
|
2
|
+
|
|
3
|
+
Provider: **UNIC**
|
|
4
|
+
|
|
5
|
+
## Endpoints
|
|
6
|
+
|
|
7
|
+
| Protocol | Base URL |
|
|
8
|
+
|---|---|
|
|
9
|
+
| OpenAI-compatible | `https://openai.unicjsc.com` |
|
|
10
|
+
| Anthropic-compatible | `https://anthropic.unicjsc.com` |
|
|
11
|
+
|
|
12
|
+
## API Key
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
anh-khoa-rat-dep-trai
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Available Models
|
|
19
|
+
|
|
20
|
+
| Model | Use case |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `unic-code` | Code generation and editing |
|
|
23
|
+
| `unic-smart` | Complex reasoning and analysis |
|
|
24
|
+
| `unic-fast` | Quick responses, low latency |
|
|
25
|
+
| `unic-ask` | General Q&A and conversation |
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PreToolUse hook: auto-add Bash(<binary>:*) allow rules for frequently used commands.
|
|
3
|
+
# Optimized: fast-path grep to skip Node.js when rule already exists.
|
|
4
|
+
|
|
5
|
+
INPUT=$(cat)
|
|
6
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
7
|
+
|
|
8
|
+
if [ -z "$COMMAND" ]; then
|
|
9
|
+
exit 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
BIN=""
|
|
13
|
+
for token in $COMMAND; do
|
|
14
|
+
case "$token" in
|
|
15
|
+
*=*) continue ;;
|
|
16
|
+
time|command|env) continue ;;
|
|
17
|
+
'|'|'||'|'&&'|';') break ;;
|
|
18
|
+
esac
|
|
19
|
+
BIN="$token"
|
|
20
|
+
break
|
|
21
|
+
done
|
|
22
|
+
|
|
23
|
+
if [ -z "$BIN" ]; then
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
if [[ ! "$BIN" =~ ^[a-zA-Z0-9._/-]+$ ]]; then
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
BIN_BASENAME=$(basename "$BIN")
|
|
32
|
+
|
|
33
|
+
if [[ "$BIN" =~ ^(rm|sudo|dd|mkfs|shutdown|reboot|halt|poweroff|chown|killall|pkill)$ ]]; then
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if [[ "$BIN_BASENAME" =~ ^(bash|sh|zsh|fish|dash|ksh|node|nodejs|bun|deno|python|python3|python2|ruby|perl|php|pwsh|powershell|cmd|wscript|cscript|osascript)$ ]]; then
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
42
|
+
SETTINGS_LOCAL="$PROJECT_ROOT/.claude/settings.local.json"
|
|
43
|
+
USAGE_FILE="$PROJECT_ROOT/.claude/ukit/permission-usage.json"
|
|
44
|
+
AUDIT_FILE="$PROJECT_ROOT/.claude/ukit/permission-audit.log"
|
|
45
|
+
RULE="Bash(${BIN}:*)"
|
|
46
|
+
NOW_UTC=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
47
|
+
MAX_RULES="${CLAUDE_AUTO_ALLOW_MAX_RULES:-150}"
|
|
48
|
+
|
|
49
|
+
# Fast path: if rule already exists in allow list, just update usage and exit
|
|
50
|
+
if [ -f "$SETTINGS_LOCAL" ] && grep -Fq -- "\"$RULE\"" "$SETTINGS_LOCAL" 2>/dev/null; then
|
|
51
|
+
# Only update usage timestamp (lighter than full Node.js logic)
|
|
52
|
+
node -e '
|
|
53
|
+
const fs = require("fs");
|
|
54
|
+
const usagePath = process.argv[1];
|
|
55
|
+
const rule = process.argv[2];
|
|
56
|
+
const nowUtc = process.argv[3];
|
|
57
|
+
if (!fs.existsSync(usagePath)) {
|
|
58
|
+
fs.mkdirSync(require("path").dirname(usagePath), { recursive: true });
|
|
59
|
+
fs.writeFileSync(usagePath, "{}");
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const usage = JSON.parse(fs.readFileSync(usagePath, "utf8"));
|
|
63
|
+
if (!usage.managedRules) usage.managedRules = {};
|
|
64
|
+
const prev = usage.managedRules[rule] || {};
|
|
65
|
+
usage.managedRules[rule] = { firstSeen: prev.firstSeen || nowUtc, lastSeen: nowUtc };
|
|
66
|
+
fs.writeFileSync(usagePath, JSON.stringify(usage, null, 2) + "\n");
|
|
67
|
+
} catch {}
|
|
68
|
+
' "$USAGE_FILE" "$RULE" "$NOW_UTC" >/dev/null 2>&1 || true
|
|
69
|
+
exit 0
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Slow path: rule is new, need full Node.js processing
|
|
73
|
+
node -e '
|
|
74
|
+
const fs = require("fs");
|
|
75
|
+
const path = require("path");
|
|
76
|
+
|
|
77
|
+
const settingsPath = process.argv[1];
|
|
78
|
+
const usagePath = process.argv[2];
|
|
79
|
+
const auditPath = process.argv[3];
|
|
80
|
+
const rule = process.argv[4];
|
|
81
|
+
const nowUtc = process.argv[5];
|
|
82
|
+
const maxRules = Math.max(1, Number(process.argv[6]) || 150);
|
|
83
|
+
|
|
84
|
+
function readJson(filePath, fallback) {
|
|
85
|
+
if (!fs.existsSync(filePath)) return fallback;
|
|
86
|
+
try {
|
|
87
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
88
|
+
} catch {
|
|
89
|
+
return fallback;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function appendAudit(event, payload) {
|
|
94
|
+
fs.appendFileSync(auditPath, JSON.stringify({ ts: nowUtc, event, ...payload }) + "\n");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const settingsDir = path.dirname(settingsPath);
|
|
98
|
+
const usageDir = path.dirname(usagePath);
|
|
99
|
+
fs.mkdirSync(settingsDir, { recursive: true });
|
|
100
|
+
fs.mkdirSync(usageDir, { recursive: true });
|
|
101
|
+
|
|
102
|
+
const settings = readJson(settingsPath, {});
|
|
103
|
+
if (!settings.permissions || typeof settings.permissions !== "object") {
|
|
104
|
+
settings.permissions = {};
|
|
105
|
+
}
|
|
106
|
+
if (!Array.isArray(settings.permissions.allow)) {
|
|
107
|
+
settings.permissions.allow = [];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const usage = readJson(usagePath, {});
|
|
111
|
+
if (!usage.managedRules || typeof usage.managedRules !== "object") {
|
|
112
|
+
usage.managedRules = {};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const allow = settings.permissions.allow;
|
|
116
|
+
let changed = false;
|
|
117
|
+
|
|
118
|
+
if (!allow.includes(rule)) {
|
|
119
|
+
allow.push(rule);
|
|
120
|
+
changed = true;
|
|
121
|
+
appendAudit("auto_add", { rule });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const prevMeta = usage.managedRules[rule] || {};
|
|
125
|
+
usage.managedRules[rule] = {
|
|
126
|
+
firstSeen: prevMeta.firstSeen || nowUtc,
|
|
127
|
+
lastSeen: nowUtc,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const managedSorted = Object.entries(usage.managedRules).sort((a, b) => {
|
|
131
|
+
const ta = Date.parse(a[1]?.lastSeen || "") || 0;
|
|
132
|
+
const tb = Date.parse(b[1]?.lastSeen || "") || 0;
|
|
133
|
+
return tb - ta;
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (managedSorted.length > maxRules) {
|
|
137
|
+
const evict = managedSorted.slice(maxRules);
|
|
138
|
+
for (const [evictRule] of evict) {
|
|
139
|
+
delete usage.managedRules[evictRule];
|
|
140
|
+
const idx = allow.indexOf(evictRule);
|
|
141
|
+
if (idx !== -1) {
|
|
142
|
+
allow.splice(idx, 1);
|
|
143
|
+
changed = true;
|
|
144
|
+
}
|
|
145
|
+
appendAudit("auto_prune_cap", { rule: evictRule, maxRules });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (changed) {
|
|
150
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
151
|
+
}
|
|
152
|
+
fs.writeFileSync(usagePath, JSON.stringify(usage, null, 2) + "\n");
|
|
153
|
+
' "$SETTINGS_LOCAL" "$USAGE_FILE" "$AUDIT_FILE" "$RULE" "$NOW_UTC" "$MAX_RULES" >/dev/null 2>&1 || true
|
|
154
|
+
|
|
155
|
+
exit 0
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SessionStart hook: prune stale Bash auto-allow rules from settings.local.json.
|
|
3
|
+
|
|
4
|
+
PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
5
|
+
SETTINGS_LOCAL="$PROJECT_ROOT/.claude/settings.local.json"
|
|
6
|
+
USAGE_FILE="$PROJECT_ROOT/.claude/ukit/permission-usage.json"
|
|
7
|
+
AUDIT_FILE="$PROJECT_ROOT/.claude/ukit/permission-audit.log"
|
|
8
|
+
TTL_DAYS="${CLAUDE_AUTO_ALLOW_TTL_DAYS:-30}"
|
|
9
|
+
|
|
10
|
+
if [ ! -f "$SETTINGS_LOCAL" ] || [ ! -f "$USAGE_FILE" ]; then
|
|
11
|
+
exit 0
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
NOW_UTC=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
15
|
+
|
|
16
|
+
node -e '
|
|
17
|
+
const fs = require("fs");
|
|
18
|
+
|
|
19
|
+
const settingsPath = process.argv[1];
|
|
20
|
+
const usagePath = process.argv[2];
|
|
21
|
+
const auditPath = process.argv[3];
|
|
22
|
+
const ttlDays = Math.max(1, Number(process.argv[4]) || 30);
|
|
23
|
+
const nowUtc = process.argv[5];
|
|
24
|
+
const cutoff = Date.now() - ttlDays * 24 * 60 * 60 * 1000;
|
|
25
|
+
|
|
26
|
+
function readJson(filePath) {
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function appendAudit(event, payload) {
|
|
35
|
+
fs.appendFileSync(auditPath, JSON.stringify({ ts: nowUtc, event, ...payload }) + "\n");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const settings = readJson(settingsPath);
|
|
39
|
+
const usage = readJson(usagePath);
|
|
40
|
+
if (!settings || !usage) process.exit(0);
|
|
41
|
+
if (!settings.permissions || typeof settings.permissions !== "object") process.exit(0);
|
|
42
|
+
if (!Array.isArray(settings.permissions.allow)) process.exit(0);
|
|
43
|
+
if (!usage.managedRules || typeof usage.managedRules !== "object") process.exit(0);
|
|
44
|
+
|
|
45
|
+
const allow = settings.permissions.allow;
|
|
46
|
+
let changedSettings = false;
|
|
47
|
+
let prunedCount = 0;
|
|
48
|
+
|
|
49
|
+
for (const [rule, meta] of Object.entries(usage.managedRules)) {
|
|
50
|
+
const lastSeen = Date.parse(meta?.lastSeen || "");
|
|
51
|
+
if (!Number.isFinite(lastSeen) || lastSeen >= cutoff) continue;
|
|
52
|
+
|
|
53
|
+
const idx = allow.indexOf(rule);
|
|
54
|
+
if (idx !== -1) {
|
|
55
|
+
allow.splice(idx, 1);
|
|
56
|
+
changedSettings = true;
|
|
57
|
+
}
|
|
58
|
+
delete usage.managedRules[rule];
|
|
59
|
+
prunedCount += 1;
|
|
60
|
+
appendAudit("auto_prune_ttl", { rule, ttlDays });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
usage.lastPruneAt = nowUtc;
|
|
64
|
+
|
|
65
|
+
if (changedSettings) {
|
|
66
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
67
|
+
}
|
|
68
|
+
fs.writeFileSync(usagePath, JSON.stringify(usage, null, 2) + "\n");
|
|
69
|
+
|
|
70
|
+
if (prunedCount > 0) {
|
|
71
|
+
appendAudit("auto_prune_summary", { prunedCount, ttlDays });
|
|
72
|
+
}
|
|
73
|
+
' "$SETTINGS_LOCAL" "$USAGE_FILE" "$AUDIT_FILE" "$TTL_DAYS" "$NOW_UTC" >/dev/null 2>&1 || true
|
|
74
|
+
|
|
75
|
+
exit 0
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PreToolUse hook: Block dangerous bash commands
|
|
3
|
+
# Matched on: Bash
|
|
4
|
+
|
|
5
|
+
INPUT=$(cat)
|
|
6
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
|
|
7
|
+
|
|
8
|
+
if [ -z "$COMMAND" ]; then
|
|
9
|
+
exit 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# Dangerous patterns to block
|
|
13
|
+
DANGEROUS_PATTERNS=(
|
|
14
|
+
"rm -rf /"
|
|
15
|
+
"rm -rf ~"
|
|
16
|
+
"rm -rf \\.?\\.([[:space:]]|$)"
|
|
17
|
+
"git push --force"
|
|
18
|
+
"git push -f "
|
|
19
|
+
"git reset --hard"
|
|
20
|
+
"git clean -fd"
|
|
21
|
+
"git checkout \."
|
|
22
|
+
"git restore \."
|
|
23
|
+
"> /dev/sda"
|
|
24
|
+
"mkfs\."
|
|
25
|
+
":(){ :|:& };:"
|
|
26
|
+
"dd if=/dev/"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
|
|
30
|
+
if echo "$COMMAND" | grep -qE "$pattern"; then
|
|
31
|
+
echo "BLOCKED: Dangerous command detected matching pattern '$pattern'. This command could cause irreversible damage. Ask the user to run it manually if truly needed." >&2
|
|
32
|
+
exit 2
|
|
33
|
+
fi
|
|
34
|
+
done
|
|
35
|
+
|
|
36
|
+
# Handle rm commands: allow safe cleanup targets, block risky recursive force-deletes
|
|
37
|
+
if echo "$COMMAND" | grep -qE "(^|[;&|[:space:]])rm([[:space:]]|$)"; then
|
|
38
|
+
if echo "$COMMAND" | grep -qE "rm\s+(-[a-zA-Z]*r[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*r|--recursive\s+--force|--force\s+--recursive|--recursive\s+-f|-f\s+--recursive)"; then
|
|
39
|
+
SAFE_DELETE_REGEX='(^|[[:space:]])(\./)?(dist|build|coverage|\.next|\.nuxt|\.turbo|tmp|temp|\.cache|node_modules)(/|[[:space:]]|$)'
|
|
40
|
+
UNSAFE_TARGET_REGEX='(^|[[:space:]])(/|~|\.\.?($|/)|\.($|/))'
|
|
41
|
+
|
|
42
|
+
if echo "$COMMAND" | grep -qE "$UNSAFE_TARGET_REGEX"; then
|
|
43
|
+
echo "BLOCKED: Unsafe delete target detected. Refusing recursive force-delete." >&2
|
|
44
|
+
exit 2
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
if ! echo "$COMMAND" | grep -qE "$SAFE_DELETE_REGEX"; then
|
|
48
|
+
echo "BLOCKED: 'rm -rf' is only auto-allowed for safe cleanup targets (dist/build/coverage/.next/.nuxt/.turbo/tmp/.cache/node_modules)." >&2
|
|
49
|
+
exit 2
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
exit 0
|