@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,307 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Analyze PDF form fields and structure.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python analyze_form.py input.pdf [--output fields.json] [--verbose]
|
|
7
|
+
|
|
8
|
+
Returns:
|
|
9
|
+
JSON with all form fields, types, positions, and metadata
|
|
10
|
+
|
|
11
|
+
Exit codes:
|
|
12
|
+
0 - Success
|
|
13
|
+
1 - File not found
|
|
14
|
+
2 - Invalid PDF
|
|
15
|
+
3 - Processing error
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import sys
|
|
19
|
+
import json
|
|
20
|
+
import logging
|
|
21
|
+
import argparse
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Dict, List, Optional, Any
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
from pypdf import PdfReader
|
|
27
|
+
except ImportError:
|
|
28
|
+
print("Error: pypdf not installed. Run: pip install pypdf", file=sys.stderr)
|
|
29
|
+
sys.exit(3)
|
|
30
|
+
|
|
31
|
+
# Configure logging
|
|
32
|
+
logging.basicConfig(
|
|
33
|
+
level=logging.INFO,
|
|
34
|
+
format='%(asctime)s - %(levelname)s - %(message)s'
|
|
35
|
+
)
|
|
36
|
+
logger = logging.getLogger(__name__)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class FormField:
|
|
40
|
+
"""Represents a PDF form field."""
|
|
41
|
+
|
|
42
|
+
def __init__(self, name: str, field_dict: Dict[str, Any]):
|
|
43
|
+
self.name = name
|
|
44
|
+
self.raw_data = field_dict
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def field_type(self) -> str:
|
|
48
|
+
"""Get field type."""
|
|
49
|
+
ft = self.raw_data.get('/FT', '')
|
|
50
|
+
type_map = {
|
|
51
|
+
'/Tx': 'text',
|
|
52
|
+
'/Btn': 'button', # checkbox or radio
|
|
53
|
+
'/Ch': 'choice', # dropdown or list
|
|
54
|
+
'/Sig': 'signature'
|
|
55
|
+
}
|
|
56
|
+
return type_map.get(ft, 'unknown')
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def value(self) -> Optional[str]:
|
|
60
|
+
"""Get current field value."""
|
|
61
|
+
val = self.raw_data.get('/V')
|
|
62
|
+
return str(val) if val else None
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def default_value(self) -> Optional[str]:
|
|
66
|
+
"""Get default field value."""
|
|
67
|
+
dv = self.raw_data.get('/DV')
|
|
68
|
+
return str(dv) if dv else None
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def is_required(self) -> bool:
|
|
72
|
+
"""Check if field is required."""
|
|
73
|
+
flags = self.raw_data.get('/Ff', 0)
|
|
74
|
+
# Bit 2 indicates required
|
|
75
|
+
return bool(flags & 2)
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def is_readonly(self) -> bool:
|
|
79
|
+
"""Check if field is read-only."""
|
|
80
|
+
flags = self.raw_data.get('/Ff', 0)
|
|
81
|
+
# Bit 1 indicates read-only
|
|
82
|
+
return bool(flags & 1)
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def options(self) -> List[str]:
|
|
86
|
+
"""Get options for choice fields."""
|
|
87
|
+
if self.field_type != 'choice':
|
|
88
|
+
return []
|
|
89
|
+
|
|
90
|
+
opts = self.raw_data.get('/Opt', [])
|
|
91
|
+
if isinstance(opts, list):
|
|
92
|
+
return [str(opt) for opt in opts]
|
|
93
|
+
return []
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def max_length(self) -> Optional[int]:
|
|
97
|
+
"""Get max length for text fields."""
|
|
98
|
+
if self.field_type == 'text':
|
|
99
|
+
return self.raw_data.get('/MaxLen')
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def rect(self) -> Optional[List[float]]:
|
|
104
|
+
"""Get field position and size [x0, y0, x1, y1]."""
|
|
105
|
+
return self.raw_data.get('/Rect')
|
|
106
|
+
|
|
107
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
108
|
+
"""Convert to dictionary."""
|
|
109
|
+
result = {
|
|
110
|
+
'name': self.name,
|
|
111
|
+
'type': self.field_type,
|
|
112
|
+
'required': self.is_required,
|
|
113
|
+
'readonly': self.is_readonly
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if self.value is not None:
|
|
117
|
+
result['value'] = self.value
|
|
118
|
+
|
|
119
|
+
if self.default_value is not None:
|
|
120
|
+
result['default_value'] = self.default_value
|
|
121
|
+
|
|
122
|
+
if self.options:
|
|
123
|
+
result['options'] = self.options
|
|
124
|
+
|
|
125
|
+
if self.max_length is not None:
|
|
126
|
+
result['max_length'] = self.max_length
|
|
127
|
+
|
|
128
|
+
if self.rect:
|
|
129
|
+
result['position'] = {
|
|
130
|
+
'x0': float(self.rect[0]),
|
|
131
|
+
'y0': float(self.rect[1]),
|
|
132
|
+
'x1': float(self.rect[2]),
|
|
133
|
+
'y1': float(self.rect[3]),
|
|
134
|
+
'width': float(self.rect[2] - self.rect[0]),
|
|
135
|
+
'height': float(self.rect[3] - self.rect[1])
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return result
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class PDFFormAnalyzer:
|
|
142
|
+
"""Analyzes PDF forms and extracts field information."""
|
|
143
|
+
|
|
144
|
+
def __init__(self, pdf_path: str):
|
|
145
|
+
self.pdf_path = Path(pdf_path)
|
|
146
|
+
self.reader: Optional[PdfReader] = None
|
|
147
|
+
self._validate_file()
|
|
148
|
+
|
|
149
|
+
def _validate_file(self) -> None:
|
|
150
|
+
"""Validate PDF file exists and is readable."""
|
|
151
|
+
if not self.pdf_path.exists():
|
|
152
|
+
logger.error(f"PDF not found: {self.pdf_path}")
|
|
153
|
+
raise FileNotFoundError(f"PDF not found: {self.pdf_path}")
|
|
154
|
+
|
|
155
|
+
if not self.pdf_path.is_file():
|
|
156
|
+
logger.error(f"Not a file: {self.pdf_path}")
|
|
157
|
+
raise ValueError(f"Not a file: {self.pdf_path}")
|
|
158
|
+
|
|
159
|
+
if self.pdf_path.suffix.lower() != '.pdf':
|
|
160
|
+
logger.error(f"Not a PDF file: {self.pdf_path}")
|
|
161
|
+
raise ValueError(f"Not a PDF file: {self.pdf_path}")
|
|
162
|
+
|
|
163
|
+
def analyze(self) -> Dict[str, Dict[str, Any]]:
|
|
164
|
+
"""
|
|
165
|
+
Analyze PDF and extract all form fields.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Dictionary mapping field names to field information
|
|
169
|
+
"""
|
|
170
|
+
try:
|
|
171
|
+
self.reader = PdfReader(str(self.pdf_path))
|
|
172
|
+
|
|
173
|
+
if not self.reader.pages:
|
|
174
|
+
logger.warning("PDF has no pages")
|
|
175
|
+
return {}
|
|
176
|
+
|
|
177
|
+
logger.info(f"Analyzing PDF with {len(self.reader.pages)} pages")
|
|
178
|
+
|
|
179
|
+
# Get form fields
|
|
180
|
+
raw_fields = self.reader.get_fields()
|
|
181
|
+
|
|
182
|
+
if not raw_fields:
|
|
183
|
+
logger.warning("PDF has no form fields")
|
|
184
|
+
return {}
|
|
185
|
+
|
|
186
|
+
logger.info(f"Found {len(raw_fields)} form fields")
|
|
187
|
+
|
|
188
|
+
# Process fields
|
|
189
|
+
fields = {}
|
|
190
|
+
for field_name, field_dict in raw_fields.items():
|
|
191
|
+
try:
|
|
192
|
+
field = FormField(field_name, field_dict)
|
|
193
|
+
fields[field_name] = field.to_dict()
|
|
194
|
+
except Exception as e:
|
|
195
|
+
logger.warning(f"Error processing field {field_name}: {e}")
|
|
196
|
+
continue
|
|
197
|
+
|
|
198
|
+
return fields
|
|
199
|
+
|
|
200
|
+
except Exception as e:
|
|
201
|
+
logger.error(f"Error analyzing PDF: {e}")
|
|
202
|
+
raise
|
|
203
|
+
|
|
204
|
+
def get_summary(self) -> Dict[str, Any]:
|
|
205
|
+
"""Get summary statistics."""
|
|
206
|
+
fields = self.analyze()
|
|
207
|
+
|
|
208
|
+
summary = {
|
|
209
|
+
'total_fields': len(fields),
|
|
210
|
+
'field_types': {},
|
|
211
|
+
'required_fields': [],
|
|
212
|
+
'readonly_fields': [],
|
|
213
|
+
'fields_with_values': []
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
for field_name, field_data in fields.items():
|
|
217
|
+
# Count by type
|
|
218
|
+
field_type = field_data['type']
|
|
219
|
+
summary['field_types'][field_type] = summary['field_types'].get(field_type, 0) + 1
|
|
220
|
+
|
|
221
|
+
# Required fields
|
|
222
|
+
if field_data.get('required'):
|
|
223
|
+
summary['required_fields'].append(field_name)
|
|
224
|
+
|
|
225
|
+
# Read-only fields
|
|
226
|
+
if field_data.get('readonly'):
|
|
227
|
+
summary['readonly_fields'].append(field_name)
|
|
228
|
+
|
|
229
|
+
# Fields with values
|
|
230
|
+
if field_data.get('value'):
|
|
231
|
+
summary['fields_with_values'].append(field_name)
|
|
232
|
+
|
|
233
|
+
return summary
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def main():
|
|
237
|
+
"""Main entry point."""
|
|
238
|
+
parser = argparse.ArgumentParser(
|
|
239
|
+
description='Analyze PDF form fields',
|
|
240
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
241
|
+
epilog='''
|
|
242
|
+
Examples:
|
|
243
|
+
%(prog)s form.pdf
|
|
244
|
+
%(prog)s form.pdf --output fields.json
|
|
245
|
+
%(prog)s form.pdf --output fields.json --verbose
|
|
246
|
+
%(prog)s form.pdf --summary
|
|
247
|
+
|
|
248
|
+
Exit codes:
|
|
249
|
+
0 - Success
|
|
250
|
+
1 - File not found
|
|
251
|
+
2 - Invalid PDF
|
|
252
|
+
3 - Processing error
|
|
253
|
+
'''
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
parser.add_argument('input', help='Input PDF file')
|
|
257
|
+
parser.add_argument('--output', '-o', help='Output JSON file (default: stdout)')
|
|
258
|
+
parser.add_argument('--summary', '-s', action='store_true', help='Show summary only')
|
|
259
|
+
parser.add_argument('--verbose', '-v', action='store_true', help='Verbose output')
|
|
260
|
+
|
|
261
|
+
args = parser.parse_args()
|
|
262
|
+
|
|
263
|
+
# Set log level
|
|
264
|
+
if args.verbose:
|
|
265
|
+
logger.setLevel(logging.DEBUG)
|
|
266
|
+
else:
|
|
267
|
+
logger.setLevel(logging.WARNING)
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
# Analyze form
|
|
271
|
+
analyzer = PDFFormAnalyzer(args.input)
|
|
272
|
+
|
|
273
|
+
if args.summary:
|
|
274
|
+
result = analyzer.get_summary()
|
|
275
|
+
else:
|
|
276
|
+
result = analyzer.analyze()
|
|
277
|
+
|
|
278
|
+
# Output
|
|
279
|
+
json_output = json.dumps(result, indent=2)
|
|
280
|
+
|
|
281
|
+
if args.output:
|
|
282
|
+
with open(args.output, 'w', encoding='utf-8') as f:
|
|
283
|
+
f.write(json_output)
|
|
284
|
+
logger.info(f"Saved to {args.output}")
|
|
285
|
+
else:
|
|
286
|
+
print(json_output)
|
|
287
|
+
|
|
288
|
+
return 0
|
|
289
|
+
|
|
290
|
+
except FileNotFoundError:
|
|
291
|
+
logger.error(f"File not found: {args.input}")
|
|
292
|
+
return 1
|
|
293
|
+
|
|
294
|
+
except ValueError as e:
|
|
295
|
+
logger.error(f"Invalid input: {e}")
|
|
296
|
+
return 2
|
|
297
|
+
|
|
298
|
+
except Exception as e:
|
|
299
|
+
logger.error(f"Error: {e}")
|
|
300
|
+
if args.verbose:
|
|
301
|
+
import traceback
|
|
302
|
+
traceback.print_exc()
|
|
303
|
+
return 3
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
if __name__ == '__main__':
|
|
307
|
+
sys.exit(main())
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: postgres
|
|
3
|
+
description: PostgreSQL conventions and patterns for UKit SQL work.
|
|
4
|
+
enabledByDefault: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# PostgreSQL Skill Pack
|
|
8
|
+
|
|
9
|
+
Enabled: false
|
|
10
|
+
|
|
11
|
+
AI suggests SQL only. User runs via psql. Read reference files for full examples:
|
|
12
|
+
- `reference/fn_rpt_examples.sql` - Report function patterns
|
|
13
|
+
- `reference/fn_get_examples.sql` - Get functions with permissions
|
|
14
|
+
- `reference/utility_functions.sql` - Utility functions & table templates
|
|
15
|
+
|
|
16
|
+
## Data Types (ONLY 3)
|
|
17
|
+
|
|
18
|
+
| Type | Use for |
|
|
19
|
+
|------|---------|
|
|
20
|
+
| `VARCHAR` | Text, dates, timestamps, JSON, UUIDs |
|
|
21
|
+
| `NUMERIC` | Numbers (`NUMERIC(16,2)` for money) |
|
|
22
|
+
| `BOOLEAN` | True/false |
|
|
23
|
+
|
|
24
|
+
**NEVER use:** DATE, TIMESTAMP, INTEGER, BIGINT, JSON, JSONB, UUID, TEXT
|
|
25
|
+
|
|
26
|
+
## Naming
|
|
27
|
+
|
|
28
|
+
| Object | Pattern | Example |
|
|
29
|
+
|--------|---------|---------|
|
|
30
|
+
| Table | `snake_case` | `users` |
|
|
31
|
+
| PK | `id_<table>` | `id_users` |
|
|
32
|
+
| View | `v_<name>` | `v_billing` |
|
|
33
|
+
| Function | `fn_<name>` | `fn_get_users` |
|
|
34
|
+
| Report fn | `fn_rpt_<name>` | `fn_rpt_billing` |
|
|
35
|
+
| Index | `idx_{table}_{cols}` | `idx_orders_user_id` |
|
|
36
|
+
|
|
37
|
+
## Mandatory Workflow
|
|
38
|
+
|
|
39
|
+
1. **Query structure first** (`\d schema.table` or `information_schema`)
|
|
40
|
+
2. **Check if view exists** (`\dv schema.*`)
|
|
41
|
+
3. View exists → `CREATE FUNCTION RETURNS SETOF view_name`
|
|
42
|
+
4. View missing → Create view first, then function
|
|
43
|
+
|
|
44
|
+
**NEVER:** Use `RETURNS TABLE`, create views inside functions, skip `DROP FUNCTION IF EXISTS`
|
|
45
|
+
|
|
46
|
+
## Function Pattern (Preferred)
|
|
47
|
+
|
|
48
|
+
```sql
|
|
49
|
+
DROP FUNCTION IF EXISTS schema.fn_rpt_name;
|
|
50
|
+
CREATE OR REPLACE FUNCTION schema.fn_rpt_name()
|
|
51
|
+
RETURNS SETOF schema.v_report_name
|
|
52
|
+
AS $$
|
|
53
|
+
BEGIN
|
|
54
|
+
RETURN QUERY SELECT * FROM schema.v_report_name ORDER BY created_on DESC;
|
|
55
|
+
END;
|
|
56
|
+
$$ LANGUAGE plpgsql;
|
|
57
|
+
|
|
58
|
+
SELECT * FROM schema.fn_rpt_name();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Key Rules
|
|
62
|
+
|
|
63
|
+
- `DROP` before `CREATE`. Explicit casts (`::VARCHAR`, `::NUMERIC(16,2)`)
|
|
64
|
+
- Declare + initialize variables. NULL checks for flags.
|
|
65
|
+
- `ORDER BY` in RETURN QUERY. Alias all tables. Test query after function.
|
|
66
|
+
- `CASE WHEN`: `(CASE WHEN cond THEN TRUE ELSE FALSE END) AS col`
|
|
67
|
+
- JSONB: `jsonb_array_elements_text(col::jsonb)`, `(t.detail::jsonb -> 0 ->>'key')::VARCHAR`
|
|
68
|
+
- Indexes for WHERE/JOIN/ORDER columns. `EXPLAIN ANALYZE` on large tables.
|
|
69
|
+
- Parameterized queries only. No `SELECT *` in app code.
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
-- =============================================
|
|
2
|
+
-- GET FUNCTION EXAMPLES
|
|
3
|
+
-- Pattern: fn_get_<name> - Returns SETOF view
|
|
4
|
+
-- With user permissions and computed columns
|
|
5
|
+
-- =============================================
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-- =============================================
|
|
9
|
+
-- Example 1: Get with Role-based Permissions
|
|
10
|
+
-- Pattern: Single role check + permission table lookup
|
|
11
|
+
-- =============================================
|
|
12
|
+
|
|
13
|
+
DROP FUNCTION IF EXISTS qas.fn_get_collect_point;
|
|
14
|
+
CREATE OR REPLACE FUNCTION qas.fn_get_collect_point(_username VARCHAR)
|
|
15
|
+
RETURNS SETOF qas.v_collect_point
|
|
16
|
+
AS
|
|
17
|
+
$$
|
|
18
|
+
DECLARE
|
|
19
|
+
v_role VARCHAR;
|
|
20
|
+
v_is_admin1 BOOLEAN := FALSE;
|
|
21
|
+
v_is_admin2 BOOLEAN := FALSE;
|
|
22
|
+
t_can_edit_after_approved BOOLEAN := FALSE;
|
|
23
|
+
BEGIN
|
|
24
|
+
-- Get user role
|
|
25
|
+
SELECT usergroup INTO v_role FROM qas.user WHERE username = _username;
|
|
26
|
+
|
|
27
|
+
-- Check admin roles
|
|
28
|
+
IF v_role LIKE '%Collect Point Admin 1%' THEN
|
|
29
|
+
v_is_admin1 = TRUE;
|
|
30
|
+
END IF;
|
|
31
|
+
|
|
32
|
+
IF v_role LIKE '%Collect Point Admin 2%' THEN
|
|
33
|
+
v_is_admin2 = TRUE;
|
|
34
|
+
END IF;
|
|
35
|
+
|
|
36
|
+
-- Get permission from permission table
|
|
37
|
+
SELECT can_edit_after_approved INTO t_can_edit_after_approved
|
|
38
|
+
FROM qas.permission
|
|
39
|
+
WHERE usergroup IN (SELECT jsonb_array_elements_text(v_role::jsonb))
|
|
40
|
+
AND menu = 'Collect Point'
|
|
41
|
+
AND can_edit_after_approved IS TRUE;
|
|
42
|
+
|
|
43
|
+
-- NULL check
|
|
44
|
+
IF t_can_edit_after_approved IS NULL THEN
|
|
45
|
+
t_can_edit_after_approved = FALSE;
|
|
46
|
+
END IF;
|
|
47
|
+
|
|
48
|
+
RETURN QUERY
|
|
49
|
+
SELECT c.id_collect_point,
|
|
50
|
+
c.running_no,
|
|
51
|
+
c.receipt_no,
|
|
52
|
+
c.date_receipt,
|
|
53
|
+
c.date_of_upload,
|
|
54
|
+
c.stamp_product,
|
|
55
|
+
c.status,
|
|
56
|
+
c.history,
|
|
57
|
+
c.created_on,
|
|
58
|
+
c.username,
|
|
59
|
+
c.remark,
|
|
60
|
+
c.remark_admin2,
|
|
61
|
+
c.attach_file,
|
|
62
|
+
c.attach_image,
|
|
63
|
+
c.id_sub_dealer,
|
|
64
|
+
c.name_of_store,
|
|
65
|
+
c.crm_user_id,
|
|
66
|
+
c.sub_dealer_province,
|
|
67
|
+
c.store_region,
|
|
68
|
+
c.id_dealer,
|
|
69
|
+
c.name_of_seller,
|
|
70
|
+
c.region1_salesrep,
|
|
71
|
+
c.region3_division,
|
|
72
|
+
c.customer_code,
|
|
73
|
+
c.total_point,
|
|
74
|
+
c.total_amount,
|
|
75
|
+
-- Computed permission columns
|
|
76
|
+
(CASE WHEN (v_is_admin1 AND c.status = 'DRAFT') OR (v_is_admin2 AND c.status = 'DRAFT1') THEN TRUE ELSE FALSE END) AS can_edit_quantity,
|
|
77
|
+
(CASE WHEN v_is_admin2 AND c.status = 'DRAFT1' THEN TRUE ELSE FALSE END) AS can_edit_multiplier,
|
|
78
|
+
(CASE WHEN (v_is_admin1 AND c.status = 'DRAFT') OR (v_is_admin2 AND c.status = 'DRAFT1') THEN TRUE ELSE FALSE END) AS can_save,
|
|
79
|
+
t_can_edit_after_approved AS can_edit_after_approved,
|
|
80
|
+
c.detail,
|
|
81
|
+
c.approved_date,
|
|
82
|
+
c.approved_by
|
|
83
|
+
FROM qas.v_collect_point c
|
|
84
|
+
ORDER BY c.created_on DESC;
|
|
85
|
+
END;
|
|
86
|
+
$$ LANGUAGE plpgsql;
|
|
87
|
+
|
|
88
|
+
SELECT * FROM qas.fn_get_collect_point('khoaln@scg.com');
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
-- =============================================
|
|
92
|
+
-- Example 2: Get with Multiple Permission Flags
|
|
93
|
+
-- Pattern: Permission table + role-based overrides + JSONB access
|
|
94
|
+
-- =============================================
|
|
95
|
+
|
|
96
|
+
DROP FUNCTION IF EXISTS qas.fn_get_review_transaction_4_not_eligible;
|
|
97
|
+
CREATE OR REPLACE FUNCTION qas.fn_get_review_transaction_4_not_eligible(_username VARCHAR)
|
|
98
|
+
RETURNS SETOF qas.v_review_transaction
|
|
99
|
+
AS
|
|
100
|
+
$$
|
|
101
|
+
DECLARE
|
|
102
|
+
t_usergroup VARCHAR;
|
|
103
|
+
t_can_edit_after_approved BOOLEAN := FALSE;
|
|
104
|
+
t_can_reject BOOLEAN := FALSE;
|
|
105
|
+
t_can_not_eligible BOOLEAN := FALSE;
|
|
106
|
+
t_can_confirm BOOLEAN := FALSE;
|
|
107
|
+
t_can_approve BOOLEAN := FALSE;
|
|
108
|
+
t_can_save BOOLEAN := FALSE;
|
|
109
|
+
BEGIN
|
|
110
|
+
-- Get user group
|
|
111
|
+
SELECT usergroup INTO t_usergroup FROM qas.user WHERE username = _username;
|
|
112
|
+
|
|
113
|
+
-- Get base permission
|
|
114
|
+
SELECT can_edit_after_approved INTO t_can_edit_after_approved
|
|
115
|
+
FROM qas.permission
|
|
116
|
+
WHERE usergroup IN (SELECT jsonb_array_elements_text(t_usergroup::jsonb))
|
|
117
|
+
AND menu = 'Collect Point'
|
|
118
|
+
AND can_edit_after_approved IS TRUE;
|
|
119
|
+
|
|
120
|
+
IF t_can_edit_after_approved IS NULL THEN
|
|
121
|
+
t_can_edit_after_approved = FALSE;
|
|
122
|
+
END IF;
|
|
123
|
+
|
|
124
|
+
-- Role-based permission overrides
|
|
125
|
+
IF t_usergroup LIKE '%"Collect Point Admin 1"%' THEN
|
|
126
|
+
t_can_edit_after_approved = FALSE;
|
|
127
|
+
t_can_reject = TRUE;
|
|
128
|
+
t_can_not_eligible = FALSE;
|
|
129
|
+
t_can_confirm = TRUE;
|
|
130
|
+
t_can_approve = FALSE;
|
|
131
|
+
END IF;
|
|
132
|
+
|
|
133
|
+
IF t_usergroup LIKE '%"Collect Point Admin 2"%' THEN
|
|
134
|
+
t_can_edit_after_approved = FALSE;
|
|
135
|
+
t_can_reject = TRUE;
|
|
136
|
+
t_can_not_eligible = FALSE;
|
|
137
|
+
t_can_confirm = FALSE;
|
|
138
|
+
t_can_approve = TRUE;
|
|
139
|
+
END IF;
|
|
140
|
+
|
|
141
|
+
RETURN QUERY
|
|
142
|
+
SELECT t.id_review_transaction,
|
|
143
|
+
t.running_no,
|
|
144
|
+
t.image_name,
|
|
145
|
+
t.image_name_show,
|
|
146
|
+
t.user_id,
|
|
147
|
+
t.ref_id,
|
|
148
|
+
t.last_name,
|
|
149
|
+
t.first_name,
|
|
150
|
+
t.id_sub_dealer,
|
|
151
|
+
t.name_of_store,
|
|
152
|
+
t.post_code,
|
|
153
|
+
t.sub_dealer_province,
|
|
154
|
+
t.store_region,
|
|
155
|
+
t.address,
|
|
156
|
+
t.survey_date,
|
|
157
|
+
t.date_of_upload,
|
|
158
|
+
-- JSONB access with fallback
|
|
159
|
+
(CASE
|
|
160
|
+
WHEN t.doc_date <> '' THEN t.doc_date
|
|
161
|
+
ELSE (CASE
|
|
162
|
+
WHEN (t.detail::jsonb -> 0 ->> 'doc_date')::VARCHAR <> ''
|
|
163
|
+
THEN (t.detail::jsonb -> 0 ->> 'doc_date')::VARCHAR
|
|
164
|
+
ELSE ''
|
|
165
|
+
END)
|
|
166
|
+
END) AS doc_date,
|
|
167
|
+
t.detail,
|
|
168
|
+
t.is_confirm,
|
|
169
|
+
t.confirm_user,
|
|
170
|
+
t.confirm_time,
|
|
171
|
+
t.is_reject,
|
|
172
|
+
t.reject_by,
|
|
173
|
+
t.reject_time,
|
|
174
|
+
t.reject_reason,
|
|
175
|
+
t.not_eligible,
|
|
176
|
+
t.not_eligible_username,
|
|
177
|
+
t.not_eligible_time,
|
|
178
|
+
t.is_approved,
|
|
179
|
+
t.approved_by,
|
|
180
|
+
t.approved_time,
|
|
181
|
+
-- Permission flags
|
|
182
|
+
t_can_edit_after_approved AS can_edit_after_approved,
|
|
183
|
+
t_can_reject AS can_reject,
|
|
184
|
+
t_can_not_eligible AS can_not_eligible,
|
|
185
|
+
t_can_confirm AS can_confirm,
|
|
186
|
+
t_can_approve AS can_approve,
|
|
187
|
+
(CASE WHEN t_can_edit_after_approved AND is_reject IS TRUE THEN TRUE ELSE FALSE END) AS can_save,
|
|
188
|
+
t.doc_number,
|
|
189
|
+
t.doc_number_show,
|
|
190
|
+
t.customer_id,
|
|
191
|
+
t.dealer_code,
|
|
192
|
+
t.dealer_name,
|
|
193
|
+
t.username,
|
|
194
|
+
t.created_on,
|
|
195
|
+
t.total_get_point,
|
|
196
|
+
t.total_get_point_amount,
|
|
197
|
+
t.status,
|
|
198
|
+
t.last_changed_time,
|
|
199
|
+
t.history,
|
|
200
|
+
t.remark
|
|
201
|
+
FROM qas.v_review_transaction t
|
|
202
|
+
WHERE t.not_eligible = TRUE
|
|
203
|
+
ORDER BY t.last_changed_time DESC;
|
|
204
|
+
END;
|
|
205
|
+
$$ LANGUAGE plpgsql;
|
|
206
|
+
|
|
207
|
+
SELECT * FROM qas.fn_get_review_transaction_4_not_eligible('hungdq@scg.com')
|
|
208
|
+
WHERE id_review_transaction = '6639d394-4576-4013-a8b0-8e40cbab9c6d';
|