@qijenchen/design-system 0.1.0-beta.10 → 0.1.0-beta.13
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/CLAUDE.md +201 -0
- package/README.md +7 -15
- package/cli-init.mjs +90 -0
- package/ds-canonical/commands/README.md +26 -0
- package/ds-canonical/commands/gov-status.md +79 -0
- package/ds-canonical/hooks/README.md +145 -0
- package/ds-canonical/hooks/_log-fire.sh +44 -0
- package/ds-canonical/hooks/block_prototype_imports.py +111 -0
- package/ds-canonical/hooks/check_app_shell_primary_header_consistency.sh +68 -0
- package/ds-canonical/hooks/check_audit_post_report_validator.sh +88 -0
- package/ds-canonical/hooks/check_audit_sample_escape.sh +73 -0
- package/ds-canonical/hooks/check_benchmark_citation.sh +106 -0
- package/ds-canonical/hooks/check_canonical_propagation.sh +189 -0
- package/ds-canonical/hooks/check_chrome_header_handcraft.sh +70 -0
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +83 -0
- package/ds-canonical/hooks/check_codex_collab_5step.sh +108 -0
- package/ds-canonical/hooks/check_datatable_invariants.sh +117 -0
- package/ds-canonical/hooks/check_dim_count_drift.sh +72 -0
- package/ds-canonical/hooks/check_field_controls_contracts.sh +110 -0
- package/ds-canonical/hooks/check_field_family_invariants.sh +205 -0
- package/ds-canonical/hooks/check_file_size_budget.sh +60 -0
- package/ds-canonical/hooks/check_header_with_tabs_border.sh +87 -0
- package/ds-canonical/hooks/check_main_branch_workbench.sh +93 -0
- package/ds-canonical/hooks/check_naming_and_abstraction.sh +165 -0
- package/ds-canonical/hooks/check_opacity_token_usage.sh +149 -0
- package/ds-canonical/hooks/check_pattern_invariants.sh +194 -0
- package/ds-canonical/hooks/check_peoplepicker_ssot_drift.sh +56 -0
- package/ds-canonical/hooks/check_pixel_quantified_audit.sh +53 -0
- package/ds-canonical/hooks/check_propose_plain_chinese.sh +74 -0
- package/ds-canonical/hooks/check_propose_pre_grep_verify.sh +70 -0
- package/ds-canonical/hooks/check_select_all_canonical.sh +58 -0
- package/ds-canonical/hooks/check_solo_workflow.sh +258 -0
- package/ds-canonical/hooks/check_spec_class_drift.sh +88 -0
- package/ds-canonical/hooks/check_story_invariants.sh +612 -0
- package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +105 -0
- package/ds-canonical/hooks/check_tab_lg_chrome_header_equal.sh +66 -0
- package/ds-canonical/hooks/check_wrapper_primitive_schema_drift.sh +104 -0
- package/ds-canonical/hooks/enforce_home_charter.sh +44 -0
- package/ds-canonical/hooks/inject_pending_self_audit.sh +204 -0
- package/ds-canonical/hooks/lib/_approval_re.sh +33 -0
- package/ds-canonical/hooks/lib/_code_quality.sh +73 -0
- package/ds-canonical/hooks/lib/_cva_default_sync.sh +69 -0
- package/ds-canonical/hooks/lib/_governance_coverage_check.sh +49 -0
- package/ds-canonical/hooks/lib/_hardcoded_strings.sh +163 -0
- package/ds-canonical/hooks/lib/_layout_space_canonical.sh +56 -0
- package/ds-canonical/hooks/lib/_overlay_handcraft.sh +141 -0
- package/ds-canonical/hooks/lib/_person_data_richness.sh +42 -0
- package/ds-canonical/hooks/lib/_story_compile_drift.sh +48 -0
- package/ds-canonical/hooks/lib/_token_hygiene.sh +95 -0
- package/ds-canonical/hooks/log_governance_fires.sh +50 -0
- package/ds-canonical/hooks/log_skill_invokes.sh +41 -0
- package/ds-canonical/hooks/post_edit_dispatcher.sh +62 -0
- package/ds-canonical/hooks/retired/check_anatomy_section_numbering.sh +106 -0
- package/ds-canonical/hooks/retired/check_avatar_hovercard.sh +90 -0
- package/ds-canonical/hooks/retired/check_button_icon_literal.sh.retired-2026-04-28 +38 -0
- package/ds-canonical/hooks/retired/check_container_breathing.sh +142 -0
- package/ds-canonical/hooks/retired/check_governance_compliance.sh +61 -0
- package/ds-canonical/hooks/retired/check_icon_only_padding_formula.sh +104 -0
- package/ds-canonical/hooks/retired/check_item_content_primitive.sh +150 -0
- package/ds-canonical/hooks/retired/check_item_list_gap.sh +153 -0
- package/ds-canonical/hooks/retired/check_sideoffset_canonical.sh +65 -0
- package/ds-canonical/hooks/retired/check_spec_iteration_tag.sh +87 -0
- package/ds-canonical/hooks/retired/check_ssot_consultation.sh +88 -0
- package/ds-canonical/hooks/retired/check_sync_update.sh +20 -0
- package/ds-canonical/hooks/retired/check_third_party_dom_verified.sh +95 -0
- package/ds-canonical/hooks/retired/enforce_home_charter.sh +125 -0
- package/ds-canonical/hooks/retired/post_edit_canonical_interrogate.sh +109 -0
- package/ds-canonical/hooks/retired/pre_edit_spec_check.sh +68 -0
- package/ds-canonical/hooks/retired/pre_new_component_spec.sh +39 -0
- package/ds-canonical/hooks/retired/pre_write_subsumption_check.sh +112 -0
- package/ds-canonical/hooks/retired/stop_meta_self_audit.sh.retired-2026-05-13 +76 -0
- package/ds-canonical/hooks/retired/tests/test_check_anatomy_section_numbering.sh +14 -0
- package/ds-canonical/hooks/retired/tests/test_check_avatar_hovercard.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_container_breathing.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_governance_compliance.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_icon_only_padding_formula.sh +79 -0
- package/ds-canonical/hooks/retired/tests/test_check_item_content_primitive.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_item_list_gap.sh +163 -0
- package/ds-canonical/hooks/retired/tests/test_check_sideoffset_canonical.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_spec_iteration_tag.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_ssot_consultation.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_sync_update.sh +14 -0
- package/ds-canonical/hooks/retired/tests/test_check_third_party_dom_verified.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_enforce_home_charter.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_pre_edit_spec_check.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_pre_new_component_spec.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_pre_write_subsumption_check.sh +63 -0
- package/ds-canonical/hooks/session_start_governance_check.sh +263 -0
- package/ds-canonical/hooks/stop_passive_logging.sh +322 -0
- package/ds-canonical/hooks/stop_self_audit.sh +450 -0
- package/ds-canonical/hooks/tests/KNOWN-BROKEN.md +15 -0
- package/ds-canonical/hooks/tests/run-all.sh +76 -0
- package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +143 -0
- package/ds-canonical/hooks/tests/test_check_app_shell_primary_header_consistency.sh +140 -0
- package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +115 -0
- package/ds-canonical/hooks/tests/test_check_audit_sample_escape.sh +93 -0
- package/ds-canonical/hooks/tests/test_check_benchmark_citation.sh +115 -0
- package/ds-canonical/hooks/tests/test_check_canonical_propagation.sh +133 -0
- package/ds-canonical/hooks/tests/test_check_chrome_header_handcraft.sh +123 -0
- package/ds-canonical/hooks/tests/test_check_code_quality.sh +15 -0
- package/ds-canonical/hooks/tests/test_check_codex_collab_5step.sh +96 -0
- package/ds-canonical/hooks/tests/test_check_cva_default_sync.sh +15 -0
- package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +122 -0
- package/ds-canonical/hooks/tests/test_check_dim_count_drift.sh +98 -0
- package/ds-canonical/hooks/tests/test_check_field_controls_contracts.sh +126 -0
- package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +194 -0
- package/ds-canonical/hooks/tests/test_check_file_size_budget.sh +32 -0
- package/ds-canonical/hooks/tests/test_check_hardcoded_strings.sh +14 -0
- package/ds-canonical/hooks/tests/test_check_header_with_tabs_border.sh +110 -0
- package/ds-canonical/hooks/tests/test_check_layout_space_canonical.sh +73 -0
- package/ds-canonical/hooks/tests/test_check_main_branch_workbench.sh +147 -0
- package/ds-canonical/hooks/tests/test_check_naming_and_abstraction.sh +136 -0
- package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +110 -0
- package/ds-canonical/hooks/tests/test_check_overlay_handcraft.sh +126 -0
- package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +148 -0
- package/ds-canonical/hooks/tests/test_check_peoplepicker_ssot_drift.sh +108 -0
- package/ds-canonical/hooks/tests/test_check_person_data_richness.sh +58 -0
- package/ds-canonical/hooks/tests/test_check_pixel_quantified_audit.sh +142 -0
- package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +126 -0
- package/ds-canonical/hooks/tests/test_check_propose_pre_grep_verify.sh +117 -0
- package/ds-canonical/hooks/tests/test_check_select_all_canonical.sh +125 -0
- package/ds-canonical/hooks/tests/test_check_solo_workflow.sh +201 -0
- package/ds-canonical/hooks/tests/test_check_spec_class_drift.sh +135 -0
- package/ds-canonical/hooks/tests/test_check_story_anatomy.sh.broken +197 -0
- package/ds-canonical/hooks/tests/test_check_story_category.sh.broken +187 -0
- package/ds-canonical/hooks/tests/test_check_story_compile_drift.sh +15 -0
- package/ds-canonical/hooks/tests/test_check_story_invariants.sh +209 -0
- package/ds-canonical/hooks/tests/test_check_story_name_jargon.sh.broken +53 -0
- package/ds-canonical/hooks/tests/test_check_story_slot_split.sh +156 -0
- package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +176 -0
- package/ds-canonical/hooks/tests/test_check_tab_lg_chrome_header_equal.sh +138 -0
- package/ds-canonical/hooks/tests/test_check_token_hygiene.sh +21 -0
- package/ds-canonical/hooks/tests/test_check_wrapper_primitive_schema_drift.sh +169 -0
- package/ds-canonical/hooks/tests/test_enforce_home_charter.sh +77 -0
- package/ds-canonical/hooks/tests/test_inject_pending_self_audit.sh +125 -0
- package/ds-canonical/hooks/tests/test_log_governance_fires.sh +10 -0
- package/ds-canonical/hooks/tests/test_log_skill_invokes.sh +7 -0
- package/ds-canonical/hooks/tests/test_post_edit_dispatcher.sh +108 -0
- package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +143 -0
- package/ds-canonical/hooks/tests/test_stop_capture_metrics.sh +95 -0
- package/ds-canonical/hooks/tests/test_stop_governance_drift_check.sh.broken +125 -0
- package/ds-canonical/hooks/tests/test_stop_harvest_corrections.sh +10 -0
- package/ds-canonical/hooks/tests/test_stop_passive_logging.sh +100 -0
- package/ds-canonical/hooks/tests/test_stop_self_audit.sh +76 -0
- package/ds-canonical/hooks/tests/test_stop_tsc_sanity.sh +10 -0
- package/ds-canonical/references/README.md +43 -0
- package/ds-canonical/references/audit-coverage-vs-24-checklist.md +74 -0
- package/ds-canonical/references/build-ui-canonicals.md +69 -0
- package/ds-canonical/references/cva-patterns.md +41 -0
- package/ds-canonical/references/drag-canonical.md +331 -0
- package/ds-canonical/references/item-anatomy-recipe.md +225 -0
- package/ds-canonical/references/naming-conventions.md +56 -0
- package/ds-canonical/references/principle-dim-map.json +515 -0
- package/ds-canonical/references/props-naming.md +45 -0
- package/ds-canonical/references/spec-rules.md +58 -0
- package/ds-canonical/references/ssot-consultation.md +63 -0
- package/ds-canonical/references/ssot-index.md +40 -0
- package/ds-canonical/references/story-baseline-registry.json +79 -0
- package/ds-canonical/references/structural-token-retention.md +42 -0
- package/ds-canonical/references/tailwind-gotchas.md +87 -0
- package/ds-canonical/references/ui-dev-rules.md +60 -0
- package/ds-canonical/rules/README.md +34 -0
- package/ds-canonical/rules/meta-patterns.md +87 -0
- package/ds-canonical/rules/self-verify.md +53 -0
- package/ds-canonical/rules/spec-rules.md +25 -0
- package/ds-canonical/rules/story-rules.md +56 -0
- package/ds-canonical/rules/ui-development.md +87 -0
- package/ds-canonical/skills/README.md +88 -0
- package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +181 -0
- package/ds-canonical/skills/code-quality-audit/SKILL.md +63 -0
- package/ds-canonical/skills/codex-collab/SKILL.md +249 -0
- package/ds-canonical/skills/codex-collab/references/brief-template.md +48 -0
- package/ds-canonical/skills/codex-collab/references/transport.md +58 -0
- package/ds-canonical/skills/codify-corrections/SKILL.md +184 -0
- package/ds-canonical/skills/codify-principle/SKILL.md +151 -0
- package/ds-canonical/skills/component-quality-gate/SKILL.md +102 -0
- package/ds-canonical/skills/component-quality-gate/references/checklist.md +79 -0
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +247 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +123 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +165 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +91 -0
- package/ds-canonical/skills/delivery-handoff/SKILL.md +229 -0
- package/ds-canonical/skills/delivery-handoff/references/flow-diagram.md +180 -0
- package/ds-canonical/skills/delivery-handoff/references/handoff-template.md +177 -0
- package/ds-canonical/skills/delivery-handoff/references/inventory-checklist.md +196 -0
- package/ds-canonical/skills/design-system-audit/SKILL.md +343 -0
- package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +1260 -0
- package/ds-canonical/skills/design-system-audit/references/checkpoints.md +240 -0
- package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +240 -0
- package/ds-canonical/skills/design-system-audit/references/principle-audit-protocol.md +364 -0
- package/ds-canonical/skills/design-system-audit/references/rule-placement.md +175 -0
- package/ds-canonical/skills/design-system-audit/references/spec-template.md +66 -0
- package/ds-canonical/skills/ensure-canonical/SKILL.md +196 -0
- package/ds-canonical/skills/governance-health/SKILL.md +146 -0
- package/ds-canonical/skills/knowledge-prune/SKILL.md +303 -0
- package/ds-canonical/skills/new-component/SKILL.md +170 -0
- package/ds-canonical/skills/new-component/references/new-component-checklist.md +85 -0
- package/ds-canonical/skills/performance-audit/SKILL.md +107 -0
- package/ds-canonical/skills/product-ui-audit/SKILL.md +230 -0
- package/ds-canonical/skills/product-ui-audit/references/audit-checks.md +246 -0
- package/ds-canonical/skills/product-ui-audit/references/common-misuses.md +329 -0
- package/ds-canonical/skills/product-ui-audit/references/report-template.md +159 -0
- package/ds-canonical/skills/propose-options/SKILL.md +177 -0
- package/ds-canonical/skills/prototype/SKILL.md +244 -0
- package/ds-canonical/skills/prototype/references/audit-checks.md +37 -0
- package/ds-canonical/skills/prototype/references/benchmark-sources.md +94 -0
- package/ds-canonical/skills/prototype/references/checkpoints.md +191 -0
- package/ds-canonical/skills/prototype/references/evaluation-matrix.md +141 -0
- package/ds-canonical/skills/prototype/references/ooux-template.md +198 -0
- package/ds-canonical/skills/prototype/references/proposal-template.md +229 -0
- package/ds-canonical/skills/scan-similar-bugs/SKILL.md +198 -0
- package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +159 -0
- package/ds-canonical/skills/story-writing/SKILL.md +122 -0
- package/ds-canonical/skills/story-writing/references/anatomy-standard.md +217 -0
- package/ds-canonical/skills/story-writing/references/category-templates.md +174 -0
- package/ds-canonical/skills/story-writing/references/example-selection.md +70 -0
- package/ds-canonical/skills/story-writing/references/self-check.md +20 -0
- package/ds-canonical/skills/ux-audit/SKILL.md +130 -0
- package/ds-canonical/skills/visual-audit/SKILL.md +245 -0
- package/ds-canonical/skills/visual-audit/output/.gitkeep +0 -0
- package/ds-canonical/skills/visual-audit/references/audit-architecture.md +100 -0
- package/ds-canonical/skills/visual-audit/references/visual-checklist.md +297 -0
- package/ds-canonical/skills/visual-audit/references/world-class-benchmarks.md +198 -0
- package/package.json +9 -5
- package/src/components/Accordion/accordion.spec.md +114 -0
- package/src/components/Alert/alert.spec.md +197 -0
- package/src/components/AppShell/app-shell.spec.md +331 -0
- package/src/components/AspectRatio/aspect-ratio.spec.md +134 -0
- package/src/components/Avatar/avatar.spec.md +329 -0
- package/src/components/Badge/badge.spec.md +380 -0
- package/src/components/Breadcrumb/breadcrumb.spec.md +257 -0
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +210 -0
- package/src/components/Button/button.spec.md +460 -0
- package/src/components/Calendar/calendar.spec.md +242 -0
- package/src/components/Carousel/carousel.spec.md +253 -0
- package/src/components/Chart/chart.spec.md +155 -0
- package/src/components/Checkbox/checkbox.spec.md +344 -0
- package/src/components/Chip/chip.spec.md +237 -0
- package/src/components/CircularProgress/circular-progress.spec.md +268 -0
- package/src/components/Coachmark/coachmark.spec.md +230 -0
- package/src/components/Combobox/combobox.spec.md +180 -0
- package/src/components/Command/command.spec.md +171 -0
- package/src/components/DataTable/data-table.spec.md +525 -0
- package/src/components/DateGrid/date-grid.spec.md +215 -0
- package/src/components/DatePicker/date-picker.spec.md +334 -0
- package/src/components/DescriptionList/description-list.spec.md +214 -0
- package/src/components/Dialog/dialog.spec.md +202 -0
- package/src/components/DropdownMenu/dropdown-menu.spec.md +250 -0
- package/src/components/Empty/empty.spec.md +214 -0
- package/src/components/Field/field-controls.spec.md +338 -0
- package/src/components/Field/field.spec.md +438 -0
- package/src/components/Field/form-validation.spec.md +152 -0
- package/src/components/FieldControlGroup/field-control-group.spec.md +176 -0
- package/src/components/FileItem/file-item.spec.md +467 -0
- package/src/components/FileUpload/file-upload.spec.md +123 -0
- package/src/components/FileViewer/file-viewer.spec.md +373 -0
- package/src/components/HoverCard/hover-card.spec.md +157 -0
- package/src/components/Input/input.spec.md +193 -0
- package/src/components/LinkInput/link-input.spec.md +130 -0
- package/src/components/Menu/menu-item.spec.md +290 -0
- package/src/components/NameCard/name-card.spec.md +171 -0
- package/src/components/Notice/notice.spec.md +149 -0
- package/src/components/NumberInput/number-input.spec.md +126 -0
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +120 -0
- package/src/components/PeoplePicker/people-picker.spec.md +263 -0
- package/src/components/Popover/popover.spec.md +198 -0
- package/src/components/ProgressBar/progress-bar.spec.md +232 -0
- package/src/components/RadioGroup/radio-group.spec.md +141 -0
- package/src/components/Rating/rating.spec.md +208 -0
- package/src/components/ScrollArea/scroll-area.spec.md +145 -0
- package/src/components/SegmentedControl/segmented-control.spec.md +295 -0
- package/src/components/Select/select.spec.md +299 -0
- package/src/components/SelectMenu/select-menu.spec.md +220 -0
- package/src/components/SelectionControl/selection-item.spec.md +128 -0
- package/src/components/Separator/separator.spec.md +109 -0
- package/src/components/Sheet/sheet.spec.md +148 -0
- package/src/components/Sidebar/sidebar.spec.md +713 -0
- package/src/components/Skeleton/skeleton.spec.md +104 -0
- package/src/components/Slider/slider.spec.md +353 -0
- package/src/components/Steps/steps.spec.md +465 -0
- package/src/components/Switch/switch.spec.md +215 -0
- package/src/components/Tabs/tabs.spec.md +314 -0
- package/src/components/Tag/tag.spec.md +282 -0
- package/src/components/Textarea/textarea.spec.md +151 -0
- package/src/components/TimePicker/time-picker.spec.md +279 -0
- package/src/components/Toast/toast.spec.md +177 -0
- package/src/components/Tooltip/tooltip.spec.md +139 -0
- package/src/components/TreeView/tree-view.spec.md +374 -0
- package/src/patterns/action-bar/action-bar.spec.md +458 -0
- package/src/patterns/element-anatomy/element-anatomy.spec.md +215 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +315 -0
- package/src/patterns/element-anatomy/item-anatomy.spec.md +1042 -0
- package/src/patterns/header-canonical/header-canonical.spec.md +285 -0
- package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +191 -0
- package/src/patterns/overlay-surface/overlay-surface.spec.md +428 -0
- package/src/patterns/resize-handle/resize-handle.spec.md +109 -0
- package/src/tokens/color/color.spec.md +804 -0
- package/src/tokens/density/density.spec.md +127 -0
- package/src/tokens/elevation/elevation.spec.md +81 -0
- package/src/tokens/layoutSpace/layoutSpace.spec.md +314 -0
- package/src/tokens/motion/motion.spec.md +97 -0
- package/src/tokens/opacity/opacity.spec.md +78 -0
- package/src/tokens/orphan-tokens.spec.md +117 -0
- package/src/tokens/radius/radius.spec.md +123 -0
- package/src/tokens/typography/typography.spec.md +202 -0
- package/src/tokens/uiSize/uiSize.spec.md +438 -0
- package/src/styles/preset.css +0 -31
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# check_substantive_edit_approval_preflight.sh — Pre-action gate for substantive design edits.
|
|
3
|
+
#
|
|
4
|
+
# Purpose: PRE-flight 偵測 packages/design-system/src/**.{tsx,ts,css} edit + last 5 user msgs 無
|
|
5
|
+
# approval keyword → SOFT inject context warning。
|
|
6
|
+
#
|
|
7
|
+
# 對比 stop_self_audit.sh post-action BLOCKER:本 hook 是 PRE-action soft warn,
|
|
8
|
+
# 讓 AI 看到 context 後 self-decide(propose-only OR cite approval verbatim),
|
|
9
|
+
# 避免「edit → stop hook BLOCKER → revert」waste cycle(user 抓 2026-05-12 anti-pattern)。
|
|
10
|
+
#
|
|
11
|
+
# 對齊 Option 3 hybrid(M32 split 後 (f) ship gate 的 PRE-flight 補位):
|
|
12
|
+
# - PreToolUse soft warn = info inject(本 hook)
|
|
13
|
+
# - Stop hook BLOCKER = enforcement(stop_self_audit.sh Mechanism 4)
|
|
14
|
+
# - AI inline self-statement = discipline(M31 Layer A/C marker + 本 hook context)
|
|
15
|
+
#
|
|
16
|
+
# Why pre-action soft instead of hard BLOCK:false-positive 風險(legit bug fix 可能撞)+
|
|
17
|
+
# inject info 比 reject 更尊重 AI judgment + 配合 existing stop hook backstop。
|
|
18
|
+
#
|
|
19
|
+
# 對齊:CLAUDE.md `# 稽核 canonical` Audit-vs-execute 分權 + M31 Layer A/C + M32(f) ship gate。
|
|
20
|
+
|
|
21
|
+
source "$(dirname "$0")/_log-fire.sh" 2>/dev/null && log_hook_fire
|
|
22
|
+
|
|
23
|
+
set -uo pipefail
|
|
24
|
+
INPUT=$(cat 2>/dev/null || echo "{}")
|
|
25
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name // ""' 2>/dev/null)
|
|
26
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""' 2>/dev/null)
|
|
27
|
+
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // ""' 2>/dev/null)
|
|
28
|
+
EVENT=$(echo "$INPUT" | jq -r '.hook_event_name // ""' 2>/dev/null)
|
|
29
|
+
|
|
30
|
+
# Only PreToolUse for Edit|Write|MultiEdit
|
|
31
|
+
[ "$EVENT" != "PreToolUse" ] && exit 0
|
|
32
|
+
case "$TOOL" in Edit|Write|MultiEdit) ;; *) exit 0 ;; esac
|
|
33
|
+
|
|
34
|
+
# Substantive scope:packages/design-system/src/**.{tsx,ts,css} only
|
|
35
|
+
case "$FILE_PATH" in
|
|
36
|
+
*/packages/design-system/src/*.tsx|*/packages/design-system/src/*.ts|*/packages/design-system/src/*.css) ;;
|
|
37
|
+
*) exit 0 ;;
|
|
38
|
+
esac
|
|
39
|
+
|
|
40
|
+
# Allowlist:storybook config / scripts / tests 等非 production code
|
|
41
|
+
case "$FILE_PATH" in
|
|
42
|
+
*.stories.tsx|*.test.ts|*.spec.ts) exit 0 ;;
|
|
43
|
+
esac
|
|
44
|
+
|
|
45
|
+
[ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ] && exit 0
|
|
46
|
+
|
|
47
|
+
# Scan last 5 真 user msgs(transcript role=user 且 content 非 tool_result)
|
|
48
|
+
RECENT_USER_MSGS=$(tail -200 "$TRANSCRIPT_PATH" 2>/dev/null | \
|
|
49
|
+
jq -r 'select(.message.role=="user") |
|
|
50
|
+
.message.content // empty |
|
|
51
|
+
if type=="string" then .
|
|
52
|
+
else (.[]? | select(.type != "tool_result") | .text // empty)
|
|
53
|
+
end' 2>/dev/null | tail -5)
|
|
54
|
+
|
|
55
|
+
# Approval keywords(對齊 stop_self_audit.sh:172)+ 2026-05-15 升 numbered directive
|
|
56
|
+
# (`#1 A` / `#1 ship` 等)+ 「照建議」/「照共識」/「照我的」等 reference style approval
|
|
57
|
+
# 2026-05-21 M34 fix(per user verbatim「都給我做到好」approval blocked by 妳/決策N coverage gap):
|
|
58
|
+
# (a) 加「妳」變體(`照妳`= `照你` 文書通用 variant)
|
|
59
|
+
# (b) 加「決策[一二三四五六七八九十1-9]」numbered directive(eg.「決策一改…」「決策3做」)
|
|
60
|
+
# (c) 加「做到好」/「都做」/「全做」auto-approve 變體
|
|
61
|
+
APPROVAL_RE='(同意|採用|採納|拍板|拍\s*[A-Z0-9]|可以|改成|改為|執行|上吧|push|implement|go ahead|approved|OK|好|沒問題|做一做|就做|做吧|做完|全部做完|做到完|做到好|都做|全做|馬不停蹄|建議做|ship|合 main|^#[0-9]+|照你|照妳|照建議|照共識|照我的|按照|決策[一二三四五六七八九十1-9]|[A-Z][0-9]+\s*(做|改|修)|先\s*[A-Z][0-9]+)'
|
|
62
|
+
HAS_APPROVAL=$(echo "$RECENT_USER_MSGS" | grep -cE "$APPROVAL_RE" 2>/dev/null)
|
|
63
|
+
HAS_APPROVAL=${HAS_APPROVAL:-0}
|
|
64
|
+
|
|
65
|
+
# Substantive-discuss keywords(若 user 在 discuss mode → 提示 propose-only)
|
|
66
|
+
DISCUSS_RE='(propose|提案|建議|討論|比稿|看法|思考|評估|要不要|該不該|是否|怎麼想)'
|
|
67
|
+
HAS_DISCUSS=$(echo "$RECENT_USER_MSGS" | grep -cE "$DISCUSS_RE" 2>/dev/null)
|
|
68
|
+
HAS_DISCUSS=${HAS_DISCUSS:-0}
|
|
69
|
+
|
|
70
|
+
# Approval present → silent pass
|
|
71
|
+
if [ "$HAS_APPROVAL" -gt 0 ]; then
|
|
72
|
+
exit 0
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# 2026-05-15 upgrade per user verbatim:「上述的問題請你務必確實確保永遠他媽不要再給我犯了」
|
|
76
|
+
# (memory/feedback_ship_then_revert_anti_pattern.md SSOT)
|
|
77
|
+
# Soft warn → P0 BLOCKER on packages/design-system/src/**/*.tsx production substantive without approval。
|
|
78
|
+
# Override env var:CLAUDE_BYPASS_DESIGN_APPROVAL=1(audit-logged below)
|
|
79
|
+
REL_PATH=${FILE_PATH#*/my-project/}
|
|
80
|
+
|
|
81
|
+
if [ "${CLAUDE_BYPASS_DESIGN_APPROVAL:-0}" = "1" ]; then
|
|
82
|
+
# Audit log override
|
|
83
|
+
mkdir -p "$(dirname "$0")/../logs" 2>/dev/null
|
|
84
|
+
printf '{"ts":"%s","event":"design-approval-bypass","file":"%s","tool":"%s"}\n' \
|
|
85
|
+
"$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$REL_PATH" "$TOOL" \
|
|
86
|
+
>> "$(dirname "$0")/../logs/approval-bypass.jsonl" 2>/dev/null || true
|
|
87
|
+
exit 0
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# BLOCKER:stderr + exit 2 = halt PreToolUse(Edit/Write/MultiEdit)
|
|
91
|
+
echo "🚨 BLOCKER: Pre-action gate(check_substantive_edit_approval_preflight,2026-05-15 P0 升級)" >&2
|
|
92
|
+
echo " - 目標: ${REL_PATH}" >&2
|
|
93
|
+
echo " - 範圍: packages/design-system/src production code(substantive SSOT change)" >&2
|
|
94
|
+
echo " - 近 5 條 user msg approval keyword: ${HAS_APPROVAL} 次 / discuss keyword: ${HAS_DISCUSS} 次" >&2
|
|
95
|
+
echo "" >&2
|
|
96
|
+
echo "→ SSOT-affecting UI/UX edit without verbatim approval = ship-then-revert anti-pattern" >&2
|
|
97
|
+
echo " (memory/feedback_ship_then_revert_anti_pattern.md SSOT)" >&2
|
|
98
|
+
echo "" >&2
|
|
99
|
+
echo "修法 — 2 選 1:" >&2
|
|
100
|
+
echo " (a) Convert to propose-only:列 option + 4-Q 自檢 + 等 user 拍板,撤回 edit" >&2
|
|
101
|
+
echo " (b) Cite user approval verbatim quote 在 commit message + reply,然後設" >&2
|
|
102
|
+
echo " \`CLAUDE_BYPASS_DESIGN_APPROVAL=1\` env var 跑 edit(audit-logged)" >&2
|
|
103
|
+
echo "" >&2
|
|
104
|
+
echo "「user echo hypothesis」≠「user approve」— M4 sub-check enforces。" >&2
|
|
105
|
+
exit 2
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# Header canonical W3 Token alignment enforcement(per header-canonical.spec.md W3):
|
|
4
|
+
# --tab-height-lg(uiSize.css)與 --chrome-header-height(globals.css)必像素相等。
|
|
5
|
+
# 兩 token scope 不同(uiSize 是 component-size reset / chrome-header-height 是 app-density)
|
|
6
|
+
# 不該 CSS alias(綁死兩個不同 scope)— 改用 assert: parse 兩檔 md/lg 值對等。
|
|
7
|
+
#
|
|
8
|
+
# PreToolUse(Edit / Write)hook —— 編輯 `packages/design-system/src/tokens/uiSize/uiSize.css` 或
|
|
9
|
+
# `src/globals.css` 時 assert 兩值仍相等。動一方未同步 = BLOCKER。
|
|
10
|
+
#
|
|
11
|
+
# 對齊 M31 codex 比稿 Step 5「保留 duplicated literals + audit hook assert equality」decision。
|
|
12
|
+
|
|
13
|
+
source "$(dirname "$0")/_log-fire.sh" 2>/dev/null && log_hook_fire
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
INPUT=$(cat)
|
|
18
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name // ""')
|
|
19
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
|
|
20
|
+
|
|
21
|
+
case "$TOOL" in
|
|
22
|
+
Edit|Write|MultiEdit) ;;
|
|
23
|
+
*) exit 0 ;;
|
|
24
|
+
esac
|
|
25
|
+
|
|
26
|
+
case "$FILE_PATH" in
|
|
27
|
+
*/packages/design-system/src/tokens/uiSize/uiSize.css|*/src/globals.css) ;;
|
|
28
|
+
*) exit 0 ;;
|
|
29
|
+
esac
|
|
30
|
+
|
|
31
|
+
PROJECT_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
32
|
+
UISIZE_CSS="$PROJECT_ROOT/packages/design-system/src/tokens/uiSize/uiSize.css"
|
|
33
|
+
GLOBALS_CSS="$PROJECT_ROOT/src/globals.css"
|
|
34
|
+
|
|
35
|
+
# Extract value of --tab-height-lg in md context(default :root block)
|
|
36
|
+
TAB_LG_MD=$(grep -oE '\--tab-height-lg:[[:space:]]*[0-9.]+rem' "$UISIZE_CSS" | head -1 | grep -oE '[0-9.]+')
|
|
37
|
+
# Extract --tab-height-lg in lg density override(2nd occurrence)
|
|
38
|
+
TAB_LG_LG=$(grep -oE '\--tab-height-lg:[[:space:]]*[0-9.]+rem' "$UISIZE_CSS" | sed -n '2p' | grep -oE '[0-9.]+')
|
|
39
|
+
|
|
40
|
+
# Extract --chrome-header-height md(1st occurrence)
|
|
41
|
+
CH_MD=$(grep -oE '\--chrome-header-height:[[:space:]]*[0-9.]+rem' "$GLOBALS_CSS" | head -1 | grep -oE '[0-9.]+')
|
|
42
|
+
# Extract --chrome-header-height lg(2nd occurrence in lg override)
|
|
43
|
+
CH_LG=$(grep -oE '\--chrome-header-height:[[:space:]]*[0-9.]+rem' "$GLOBALS_CSS" | sed -n '2p' | grep -oE '[0-9.]+')
|
|
44
|
+
|
|
45
|
+
ERRORS=()
|
|
46
|
+
|
|
47
|
+
if [ "$TAB_LG_MD" != "$CH_MD" ]; then
|
|
48
|
+
ERRORS+=("md: --tab-height-lg=$TAB_LG_MD rem ≠ --chrome-header-height=$CH_MD rem")
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if [ "$TAB_LG_LG" != "$CH_LG" ]; then
|
|
52
|
+
ERRORS+=("lg: --tab-height-lg=$TAB_LG_LG rem ≠ --chrome-header-height=$CH_LG rem")
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
56
|
+
printf '🚨 TAB_LG vs CHROME_HEADER_HEIGHT EQUAL BLOCKER(header-canonical.spec.md W3):\n' >&2
|
|
57
|
+
for E in "${ERRORS[@]}"; do
|
|
58
|
+
printf ' • %s\n' "$E" >&2
|
|
59
|
+
done
|
|
60
|
+
printf '\n 動一方必同步另一方(兩 token 像素相等是「lg tabs 取代 chrome header」SSOT linkage 鐵證)\n' >&2
|
|
61
|
+
printf ' SSOT: packages/design-system/src/patterns/header-canonical/header-canonical.spec.md W3\n' >&2
|
|
62
|
+
printf ' 修方向: 改 uiSize.css 的 --tab-height-lg OR globals.css 的 --chrome-header-height 讓兩邊相等\n' >&2
|
|
63
|
+
exit 2
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
exit 0
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# M30 機械強制:wrapper-vs-primitive schema unify invariant。
|
|
4
|
+
#
|
|
5
|
+
# PreToolUse(Edit / Write)hook —— 編輯 `packages/design-system/src/components/**/*.tsx` 時掃:
|
|
6
|
+
# (a) 檢查同 file 是否 declare `export interface XxxOption` 同名於其他 file
|
|
7
|
+
# (b) 若同名且未 `extends XxxOption from primitive`/`extends YyyOption` → BLOCKER
|
|
8
|
+
# (c) 若 wrapper 用 `SelectMenuOption`(import from SelectMenu)但內部 `menuOptions` mapping
|
|
9
|
+
# 未 forward `avatar` / `description` / `disabled`(只 forward value+label)→ WARN
|
|
10
|
+
#
|
|
11
|
+
# Bug 史(2026-05-10):
|
|
12
|
+
# `Select.SelectOption` Issue 4 補 avatar / description / disabled,但 `Combobox.SelectOption`
|
|
13
|
+
# 是同名 weak schema `{ value, label }`。TypeScript 不抓(不同 file 同名各 export);consumer
|
|
14
|
+
# import 哪個版本看 import path 決定 → drift。PeoplePicker multi-mode dropdown 漏 avatar。
|
|
15
|
+
#
|
|
16
|
+
# Allow escape:
|
|
17
|
+
# 檔頭 `// @wrapper-schema-allow: <reason>` 整檔豁免(legacy migration 過渡期)。
|
|
18
|
+
|
|
19
|
+
source "$(dirname "$0")/_log-fire.sh" 2>/dev/null && log_hook_fire
|
|
20
|
+
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
INPUT=$(cat)
|
|
24
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name // ""')
|
|
25
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
|
|
26
|
+
|
|
27
|
+
case "$TOOL" in
|
|
28
|
+
Edit|Write|MultiEdit) ;;
|
|
29
|
+
*) exit 0 ;;
|
|
30
|
+
esac
|
|
31
|
+
|
|
32
|
+
case "$FILE_PATH" in
|
|
33
|
+
*/packages/design-system/src/components/**/*.tsx) ;;
|
|
34
|
+
*) exit 0 ;;
|
|
35
|
+
esac
|
|
36
|
+
|
|
37
|
+
NEW_CONTENT=$(echo "$INPUT" | jq -r '
|
|
38
|
+
if .tool_input.new_string then .tool_input.new_string
|
|
39
|
+
elif .tool_input.content then .tool_input.content
|
|
40
|
+
else "" end
|
|
41
|
+
')
|
|
42
|
+
|
|
43
|
+
# Allow escape
|
|
44
|
+
if echo "$NEW_CONTENT" | grep -qE '@wrapper-schema-allow:'; then
|
|
45
|
+
exit 0
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Check 1: new file declares `export interface XxxOption {` ?
|
|
49
|
+
DECLARES=$(echo "$NEW_CONTENT" | grep -oE 'export interface [A-Z][a-zA-Z]*Option\b[^{]*\{' || true)
|
|
50
|
+
if [ -z "$DECLARES" ]; then
|
|
51
|
+
exit 0
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# For each declared OptionLike interface, check if same name declared elsewhere
|
|
55
|
+
DS_COMPONENTS_DIR="$(dirname "$0")/../../packages/design-system/src/components"
|
|
56
|
+
|
|
57
|
+
# normalize FILE_PATH relative to project for self-skip
|
|
58
|
+
SELF_BASENAME="$(basename "$FILE_PATH")"
|
|
59
|
+
|
|
60
|
+
WARNINGS=()
|
|
61
|
+
BLOCKERS=()
|
|
62
|
+
|
|
63
|
+
while IFS= read -r decl; do
|
|
64
|
+
IFACE_NAME=$(echo "$decl" | grep -oE '[A-Z][a-zA-Z]*Option' | head -1)
|
|
65
|
+
[ -z "$IFACE_NAME" ] && continue
|
|
66
|
+
# Skip if extends another OptionLike interface(M30 compliant)
|
|
67
|
+
if echo "$NEW_CONTENT" | grep -qE "interface $IFACE_NAME\b.*extends [A-Z][a-zA-Z]*Option"; then
|
|
68
|
+
continue
|
|
69
|
+
fi
|
|
70
|
+
# Find other files declaring same name(skip self by basename — imperfect but Edit context is single-file)
|
|
71
|
+
OTHER_DECLS=$(grep -rlE "export interface $IFACE_NAME\b" "$DS_COMPONENTS_DIR" 2>/dev/null | grep -v "/$SELF_BASENAME$" || true)
|
|
72
|
+
if [ -n "$OTHER_DECLS" ]; then
|
|
73
|
+
BLOCKERS+=("M30 schema drift: \`$IFACE_NAME\` declared in this file (no extends) + also in: $(echo "$OTHER_DECLS" | head -3 | xargs -n1 basename | tr '\n' ',' | sed 's/,$//')")
|
|
74
|
+
fi
|
|
75
|
+
done <<< "$DECLARES"
|
|
76
|
+
|
|
77
|
+
# Check 2: imports SelectMenuOption but menuOptions mapping drops fields(WARN)
|
|
78
|
+
if echo "$NEW_CONTENT" | grep -qE 'import.*SelectMenuOption.*from.*SelectMenu'; then
|
|
79
|
+
# Look for `menuOptions: SelectMenuOption[]` mapping that misses fields
|
|
80
|
+
MAP_BLOCK=$(echo "$NEW_CONTENT" | grep -A5 -E 'menuOptions.*SelectMenuOption\[\]' | head -30)
|
|
81
|
+
if [ -n "$MAP_BLOCK" ]; then
|
|
82
|
+
# Heuristic: should forward at least `avatar` OR `description` OR `disabled` field
|
|
83
|
+
if ! echo "$MAP_BLOCK" | grep -qE '(avatar|description|disabled)'; then
|
|
84
|
+
WARNINGS+=("M30 schema partial-forward: \`menuOptions\` mapping seems to drop avatar/description/disabled. Forward 全 SelectMenuOption surface or annotate \`// @wrapper-schema-allow: <reason>\`.")
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Output
|
|
90
|
+
if [ ${#BLOCKERS[@]} -gt 0 ]; then
|
|
91
|
+
echo "🚨 M30 wrapper-vs-primitive schema drift BLOCKER:" >&2
|
|
92
|
+
for b in "${BLOCKERS[@]}"; do echo " • $b" >&2; done
|
|
93
|
+
echo "" >&2
|
|
94
|
+
echo "Fix: declare \`interface $IFACE_NAME extends <PrimitiveSSoT>\` (e.g. \`extends SelectMenuOption\`)" >&2
|
|
95
|
+
echo " 詳 .claude/rules/meta-patterns.md M30 + Polaris ChoiceList / Material Autocomplete idiom" >&2
|
|
96
|
+
exit 2
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
if [ ${#WARNINGS[@]} -gt 0 ]; then
|
|
100
|
+
echo "⚠️ M30 wrapper schema forward warning:" >&2
|
|
101
|
+
for w in "${WARNINGS[@]}"; do echo " • $w" >&2; done
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
exit 0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PreToolUse Write hook: gate new files in classification dirs.
|
|
3
|
+
# 確保新檔放對 home(8-home flowchart canonical)。
|
|
4
|
+
#
|
|
5
|
+
# Silent on pass(2026-04-26 noise reduction):only fire if charter README
|
|
6
|
+
# missing OR file-name pattern violates dir convention(no charter inject).
|
|
7
|
+
|
|
8
|
+
source "$(dirname "$0")/_log-fire.sh" 2>/dev/null && log_hook_fire
|
|
9
|
+
|
|
10
|
+
set -uo pipefail
|
|
11
|
+
|
|
12
|
+
INPUT=$(cat 2>/dev/null || echo "{}")
|
|
13
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name // ""' 2>/dev/null)
|
|
14
|
+
[ "$TOOL" = "Write" ] || exit 0
|
|
15
|
+
|
|
16
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""' 2>/dev/null)
|
|
17
|
+
[ -n "$FILE_PATH" ] && [ ! -e "$FILE_PATH" ] || exit 0 # only NEW files
|
|
18
|
+
|
|
19
|
+
# Classification dirs requiring charter
|
|
20
|
+
DIRS=(.claude/hooks .claude/skills .claude/agents .claude/commands .claude/rules packages/design-system/src/components packages/design-system/src/patterns packages/design-system/src/tokens)
|
|
21
|
+
|
|
22
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
23
|
+
REL=$(echo "$FILE_PATH" | sed "s|$PROJECT_DIR/||")
|
|
24
|
+
|
|
25
|
+
for d in "${DIRS[@]}"; do
|
|
26
|
+
case "$REL" in
|
|
27
|
+
"$d"/*)
|
|
28
|
+
# Charter README itself escape(2026-05-17 chicken-and-egg fix):
|
|
29
|
+
# 不能擋 README 本身建立(否則 charter 永遠無法被 init)
|
|
30
|
+
case "$REL" in "$d"/README.md) exit 0 ;; esac
|
|
31
|
+
CHARTER="$PROJECT_DIR/$d/README.md"
|
|
32
|
+
if [ ! -f "$CHARTER" ]; then
|
|
33
|
+
# P0:charter missing → block via stderr + exit 2
|
|
34
|
+
echo "❌ Charter missing for $d/. Create $CHARTER first per # 治理 canonical 8-home flowchart." >&2
|
|
35
|
+
exit 2
|
|
36
|
+
fi
|
|
37
|
+
# Charter exists → silent pass(content placement is AI's responsibility,
|
|
38
|
+
# audit Dim 19 periodic verify;no per-write nag)
|
|
39
|
+
exit 0
|
|
40
|
+
;;
|
|
41
|
+
esac
|
|
42
|
+
done
|
|
43
|
+
|
|
44
|
+
exit 0
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
# UserPromptSubmit hook: 把上 turn Stop hook 累積的 warnings inject 到 next turn additionalContext.
|
|
4
|
+
#
|
|
5
|
+
# 修補 known issue:Stop hook silent-log 沒 inject → AI 看不到 self-audit warnings → reactive 模式持續。
|
|
6
|
+
# 對齊 CLAUDE.md M14 / M20「auto-inject corrective prompt」原意。
|
|
7
|
+
#
|
|
8
|
+
# Reads:
|
|
9
|
+
# .claude/logs/self-audit-warnings.jsonl(stop_self_audit 寫入,behavioral check)
|
|
10
|
+
# .claude/logs/score-history.jsonl(stop_meta_self_audit 寫入,infra-score regression)
|
|
11
|
+
# State:
|
|
12
|
+
# .claude/logs/last-inject-ts.txt — 上次 inject 的 timestamp
|
|
13
|
+
#
|
|
14
|
+
# Logic:
|
|
15
|
+
# 1. 讀 LAST_TS,撈兩個 log 中 ts > LAST_TS 的條目
|
|
16
|
+
# 2. 有條目 → format 成 additionalContext,inject 給 AI
|
|
17
|
+
# 3. 不論有無條目,更新 LAST_TS = NOW(避免 stuck on 舊 warnings)
|
|
18
|
+
|
|
19
|
+
source "$(dirname "$0")/_log-fire.sh" 2>/dev/null && log_hook_fire
|
|
20
|
+
|
|
21
|
+
set -uo pipefail
|
|
22
|
+
|
|
23
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
24
|
+
cd "$PROJECT_DIR" || exit 0
|
|
25
|
+
|
|
26
|
+
LAST_TS_FILE=".claude/logs/last-inject-ts.txt"
|
|
27
|
+
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
28
|
+
# Default LAST_TS: 30 分鐘前(防呆 — session cutoff,老 warning 自動 expire 避免 echo)
|
|
29
|
+
# 之前 24h 太寬,session 跨 hour 仍 inject 老 warning。30m sliding window 讓 fresh
|
|
30
|
+
# warning 進 inject,old warning 自動老化。Cross-platform GNU + BSD date。
|
|
31
|
+
DEFAULT_AGO=$(date -u -d '30 minutes ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || \
|
|
32
|
+
date -u -v-30M +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || \
|
|
33
|
+
date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || \
|
|
34
|
+
echo "1970-01-01T00:00:00Z")
|
|
35
|
+
LAST_TS="$DEFAULT_AGO"
|
|
36
|
+
if [ -f "$LAST_TS_FILE" ]; then
|
|
37
|
+
STORED=$(cat "$LAST_TS_FILE" 2>/dev/null)
|
|
38
|
+
# 用 stored OR 30m-ago 較新者(避免被重置成 1970)
|
|
39
|
+
[ -n "$STORED" ] && [[ "$STORED" > "$LAST_TS" ]] && LAST_TS="$STORED"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# ── Acknowledge detection(防呆)──────────────────────────────────────────
|
|
43
|
+
# 若 last user msg(transcript)含 acknowledge keyword,stop inject 該類 warning
|
|
44
|
+
# 這 turn — 表示 user 已 see + 接受該 warning,持續 inject 是 spam。
|
|
45
|
+
ACK_DETECTED=0
|
|
46
|
+
TRANSCRIPT_PATH=$(echo "${1:-}" | jq -r '.transcript_path // ""' 2>/dev/null || echo "")
|
|
47
|
+
if [ -z "$TRANSCRIPT_PATH" ]; then
|
|
48
|
+
# UserPromptSubmit hook 從 stdin JSON 讀 transcript_path
|
|
49
|
+
TRANSCRIPT_PATH=$(cat 2>/dev/null | jq -r '.transcript_path // ""' 2>/dev/null || echo "")
|
|
50
|
+
fi
|
|
51
|
+
if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
|
|
52
|
+
LAST_USER=$(tail -50 "$TRANSCRIPT_PATH" 2>/dev/null | \
|
|
53
|
+
jq -r 'select(.message.role=="user") | .message.content // empty | if type=="string" then . else (.[]? | .text // empty) end' 2>/dev/null | tail -3)
|
|
54
|
+
ACK_RE='(收到|知道了|了解|acknowledged|ok 撤回|不用再 inject|停止 inject|skip warning|不要再警告)'
|
|
55
|
+
if echo "$LAST_USER" | grep -qiE "$ACK_RE"; then
|
|
56
|
+
ACK_DETECTED=1
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# ── Aggregate warnings 去重 + 計數(extract_warnings_dedup helper)─────────
|
|
61
|
+
# Reads stdin JSONL, filters by ts > LAST_TS, extracts .warnings, dedups bullet lines, prepends count.
|
|
62
|
+
extract_warnings_dedup() {
|
|
63
|
+
awk -v cutoff="$LAST_TS" '
|
|
64
|
+
BEGIN { in_str=0; for(k in seen) delete seen[k]; for(k in count) delete count[k]; n=0 }
|
|
65
|
+
{
|
|
66
|
+
# crude jsonl ts extract
|
|
67
|
+
if (match($0, /"ts":"[^"]+"/)) {
|
|
68
|
+
ts=substr($0, RSTART+6, RLENGTH-7)
|
|
69
|
+
if (ts <= cutoff) next
|
|
70
|
+
}
|
|
71
|
+
# extract warnings field(may contain \n escape)
|
|
72
|
+
if (match($0, /"warnings":"[^"]*"/)) {
|
|
73
|
+
w=substr($0, RSTART+12, RLENGTH-13)
|
|
74
|
+
# split by \\n
|
|
75
|
+
nlines=split(w, lines, "\\\\n")
|
|
76
|
+
for (i=1; i<=nlines; i++) {
|
|
77
|
+
line=lines[i]
|
|
78
|
+
gsub(/^[[:space:]]+/, "", line)
|
|
79
|
+
# strip leading "• " from source(避免 double bullet)
|
|
80
|
+
gsub(/^•[[:space:]]*/, "", line)
|
|
81
|
+
if (line == "") continue
|
|
82
|
+
if (!(line in seen)) {
|
|
83
|
+
seen[line] = 1
|
|
84
|
+
count[line] = 1
|
|
85
|
+
order[++n] = line
|
|
86
|
+
} else {
|
|
87
|
+
count[line]++
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
END {
|
|
93
|
+
for (i=1; i<=n; i++) {
|
|
94
|
+
l = order[i]
|
|
95
|
+
c = count[l]
|
|
96
|
+
if (c > 1) printf " • [×%d] %s\n", c, l
|
|
97
|
+
else printf " • %s\n", l
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
'
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
WARNINGS_BEHAVIORAL=""
|
|
104
|
+
WARNINGS_SCORE=""
|
|
105
|
+
LATEST_SCORE=""
|
|
106
|
+
|
|
107
|
+
# ── Read behavioral warnings since LAST_TS ─────────────────────────────────
|
|
108
|
+
if [ -f .claude/logs/self-audit-warnings.jsonl ]; then
|
|
109
|
+
WARNINGS_BEHAVIORAL=$(extract_warnings_dedup < .claude/logs/self-audit-warnings.jsonl)
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# ── Read infra-score warnings since LAST_TS ─────────────────────────────────
|
|
113
|
+
if [ -f .claude/logs/score-history.jsonl ]; then
|
|
114
|
+
WARNINGS_SCORE=$(extract_warnings_dedup < .claude/logs/score-history.jsonl)
|
|
115
|
+
# Latest score(取 file 最後一行 ts > cutoff 的)
|
|
116
|
+
LATEST_SCORE=$(awk -v cutoff="$LAST_TS" '
|
|
117
|
+
{
|
|
118
|
+
if (match($0, /"ts":"[^"]+"/)) {
|
|
119
|
+
ts=substr($0, RSTART+6, RLENGTH-7)
|
|
120
|
+
if (ts <= cutoff) next
|
|
121
|
+
}
|
|
122
|
+
if (match($0, /"score":[0-9]+/)) {
|
|
123
|
+
s=substr($0, RSTART+8, RLENGTH-8)
|
|
124
|
+
last_s=s
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
END { print last_s }
|
|
128
|
+
' .claude/logs/score-history.jsonl)
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# Update LAST_TS regardless(若 inject 失敗,下 turn 會重看到 — 但 jq 出錯就靜默)
|
|
132
|
+
mkdir -p .claude/logs 2>/dev/null
|
|
133
|
+
echo "$NOW" > "$LAST_TS_FILE"
|
|
134
|
+
|
|
135
|
+
# Silent exit if nothing accumulated
|
|
136
|
+
if [ -z "$WARNINGS_BEHAVIORAL" ] && [ -z "$WARNINGS_SCORE" ]; then
|
|
137
|
+
exit 0
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
# 防呆 layer 2:user 已 acknowledge → silent skip inject 本 turn
|
|
141
|
+
if [ "$ACK_DETECTED" = "1" ]; then
|
|
142
|
+
exit 0
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# ── Format additionalContext ────────────────────────────────────────────────
|
|
146
|
+
CTX_PARTS=""
|
|
147
|
+
if [ -n "$WARNINGS_BEHAVIORAL" ]; then
|
|
148
|
+
CTX_PARTS="${CTX_PARTS}## Behavioral self-audit(stop_self_audit):
|
|
149
|
+
${WARNINGS_BEHAVIORAL}
|
|
150
|
+
|
|
151
|
+
"
|
|
152
|
+
fi
|
|
153
|
+
if [ -n "$WARNINGS_SCORE" ]; then
|
|
154
|
+
SCORE_LABEL=""
|
|
155
|
+
[ -n "$LATEST_SCORE" ] && SCORE_LABEL=" current=${LATEST_SCORE}/100"
|
|
156
|
+
CTX_PARTS="${CTX_PARTS}## Infra-score audit(stop_meta_self_audit,${SCORE_LABEL}):
|
|
157
|
+
${WARNINGS_SCORE}
|
|
158
|
+
|
|
159
|
+
"
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# ── 偵測 directive 觸發類型,加 explicit 指示 ─────────────────────────────
|
|
163
|
+
DIRECTIVE=""
|
|
164
|
+
if echo "${WARNINGS_BEHAVIORAL}${WARNINGS_SCORE}" | grep -q "trigger-phrase 累計"; then
|
|
165
|
+
DIRECTIVE="${DIRECTIVE}
|
|
166
|
+
🚨 **DIRECTIVE — M19 trigger phrase auto-pipeline 啟動**:
|
|
167
|
+
當 user 反覆問「確保 / 一定 / 不會 / 是否能 / 永遠 / 是否符合原則」之類問題時(本 case 已累計多次),你**必須立刻 invoke \`/ensure-canonical\` skill** 跑 5-layer pipeline,不可只給 verbal 答覆 / 不可只 quote score / 不可只「下次承諾」。
|
|
168
|
+
不確定主題 → 就用最近 user 提到的關鍵字當 ensure-canonical args。"
|
|
169
|
+
fi
|
|
170
|
+
if echo "${WARNINGS_BEHAVIORAL}${WARNINGS_SCORE}" | grep -q "Topic.*repeated"; then
|
|
171
|
+
DIRECTIVE="${DIRECTIVE}
|
|
172
|
+
🚨 **DIRECTIVE — M10 proactive exhaustive scan**:
|
|
173
|
+
Topic 重複表示 prior turns 落地不徹底。**必須 grep DS-wide 同 pattern 批量修**(不只 user 點到的那個 case),否則持續 reactive。"
|
|
174
|
+
fi
|
|
175
|
+
if echo "${WARNINGS_BEHAVIORAL}${WARNINGS_SCORE}" | grep -q "Claim-verify gap"; then
|
|
176
|
+
DIRECTIVE="${DIRECTIVE}
|
|
177
|
+
🚨 **DIRECTIVE — Claim-verify gap**:
|
|
178
|
+
你說 done / verified / 通過 但本 turn 沒跑 \`tsc -b\` / hook test / score script。**現在立刻跑驗證**或在回答中明撤回 claim。"
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
ADDITIONAL_CONTEXT=$(printf '⚠️ 來自上 turn(s) 的 governance self-audit warnings — M14/M20 auto-inject:
|
|
182
|
+
|
|
183
|
+
%s%s
|
|
184
|
+
|
|
185
|
+
→ 這些是 stop hook 偵測到、應該主動處理的事項。在你回答 user prompt 前先處理(grep / fix / invoke skill / 跑驗證),不要等 user 提醒。' "$CTX_PARTS" "$DIRECTIVE")
|
|
186
|
+
|
|
187
|
+
# Safety cap:max 3KB(避免 inject context 過大)
|
|
188
|
+
MAX_LEN=3000
|
|
189
|
+
CTX_LEN=${#ADDITIONAL_CONTEXT}
|
|
190
|
+
if [ "$CTX_LEN" -gt "$MAX_LEN" ]; then
|
|
191
|
+
ADDITIONAL_CONTEXT="${ADDITIONAL_CONTEXT:0:$MAX_LEN}
|
|
192
|
+
|
|
193
|
+
[truncated — 原 ${CTX_LEN}B,顯示前 ${MAX_LEN}B。如要看全文 grep .claude/logs/self-audit-warnings.jsonl + score-history.jsonl]"
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
# Output JSON for Claude Code to inject
|
|
197
|
+
jq -n --arg ctx "$ADDITIONAL_CONTEXT" '{
|
|
198
|
+
hookSpecificOutput: {
|
|
199
|
+
hookEventName: "UserPromptSubmit",
|
|
200
|
+
additionalContext: $ctx
|
|
201
|
+
}
|
|
202
|
+
}'
|
|
203
|
+
|
|
204
|
+
exit 0
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SSOT approval keyword regex(M17 + M34,2026-05-18 codify per audit GAP 6)
|
|
3
|
+
#
|
|
4
|
+
# Used by:
|
|
5
|
+
# - check_substantive_edit_approval_preflight.sh(pre-flight Edit/Write production)
|
|
6
|
+
# - stop_self_audit.sh Mechanism 4(post-flight codex-design ship verify)
|
|
7
|
+
# - check_solo_workflow.sh R3(push main trigger detect)
|
|
8
|
+
#
|
|
9
|
+
# Background:GAP 6 audit(2026-05-18) found approval regex duplicated 3 places + drift:
|
|
10
|
+
# preflight 已加 `#[N] A` numbered directive + 照建議 / 照共識 reference-style
|
|
11
|
+
# 但 stop_self_audit / solo_workflow 沒 sync。
|
|
12
|
+
# 抽出 single SSOT,source from all consumers,確保未來 update 自動 propagate。
|
|
13
|
+
|
|
14
|
+
# 完整 approval keyword regex(extended POSIX)
|
|
15
|
+
#
|
|
16
|
+
# 涵蓋:
|
|
17
|
+
# (1) 明確同意:同意 / 採用 / 採納 / 拍板 / 可以 / OK / 好 / approved / approve / 沒問題
|
|
18
|
+
# (2) 動作指令:改成 / 改為 / 執行 / 上吧 / push / implement / go ahead / ship / 上 main
|
|
19
|
+
# (3) 大批做:做一做 / 就做 / 做吧 / 做完 / 全部做完 / 做到完 / 馬不停蹄 / 全部照建議做
|
|
20
|
+
# (4) 建議認可:建議做 / 照你建議 / 照建議 / 照共識 / 照我的 / 按照(代詞 reference)
|
|
21
|
+
# (5) Numbered directive:#1 A / #2 B / 1. B / 2. A 類 user 點選 option
|
|
22
|
+
# (6) 合 main trigger(R3 solo workflow specific):合進去 / 合 main / merge / 上 main
|
|
23
|
+
# (7) Past-tense 認可:好了 / OK 了 / 可以了 / 沒問題了 / 同意了 / 拍板了
|
|
24
|
+
# 2026-05-18 syntactic fix:加 closing `)` 收尾(原 `grep: parentheses not balanced`
|
|
25
|
+
# 錯誤造成 hook silent fail-closed BLOCKER。純語法 bug,**不** widen 偵測 scope —
|
|
26
|
+
# 既有 keyword list 不動。
|
|
27
|
+
export APPROVAL_KEYWORD_RE='(同意|採用|採納|拍板|可以|改成|改為|執行|上吧|push|implement|go ahead|approved|approve|OK|好|沒問題|做一做|就做|做吧|做完|全部做完|做到完|馬不停蹄|全部照建議做|建議做|照你建議|照建議|照共識|照我的|按照|合進去|合\s*main|merge|上\s*main|ship|好了|OK\s*了|可以了|沒問題了|同意了|拍板了|#[0-9]+\s*[A-Za-z]|^[0-9]+\.\s*[A-Za-z])'
|
|
28
|
+
|
|
29
|
+
# Helper:check input string contains approval keyword
|
|
30
|
+
# Usage: if has_approval "$user_msg"; then ...
|
|
31
|
+
has_approval() {
|
|
32
|
+
echo "$1" | grep -qE "$APPROVAL_KEYWORD_RE"
|
|
33
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PostToolUse hook: lightweight code quality check on tsx/ts edit.
|
|
3
|
+
# Only runs the 2 fastest checks:
|
|
4
|
+
# 1. `any` usage without `// any-allow:` escape hatch
|
|
5
|
+
# 2. tsx file-size P0 (> 800 transition cap)
|
|
6
|
+
#
|
|
7
|
+
# Full audit (dead export / circular / long function) — use `/code-quality-audit` skill.
|
|
8
|
+
|
|
9
|
+
# Per-hook fire logging(enables /knowledge-prune D2 dead-hook detection)
|
|
10
|
+
source "$(dirname "$0")/../_log-fire.sh" 2>/dev/null && log_hook_fire
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
FILE_PATH=$(jq -r '.tool_input.file_path // empty')
|
|
15
|
+
|
|
16
|
+
# Scope: only src/ .tsx / .ts files (not stories, not specs)
|
|
17
|
+
if ! echo "$FILE_PATH" | grep -qE 'src/.*\.tsx?$'; then
|
|
18
|
+
exit 0
|
|
19
|
+
fi
|
|
20
|
+
if echo "$FILE_PATH" | grep -qE '\.(stories|anatomy\.stories|principles\.stories)\.tsx$'; then
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
if [ ! -f "$FILE_PATH" ]; then
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
VIOLATIONS=""
|
|
28
|
+
|
|
29
|
+
# ── Check 1: `any` usage ────────────────────────────────────────────────────
|
|
30
|
+
# Flag `: any` / `as any` / `<any>` / `any[]` / `Record<X, any>`
|
|
31
|
+
# Skip lines with `any-allow` OR previous line with `any-allow`.
|
|
32
|
+
ANY_HITS=$(perl -ne '
|
|
33
|
+
BEGIN { our $prev_allow = 0; }
|
|
34
|
+
my $has_allow = /any-allow/;
|
|
35
|
+
my $line = $_;
|
|
36
|
+
if (!$prev_allow && !$has_allow) {
|
|
37
|
+
next if m{^\s*//};
|
|
38
|
+
next if m{^\s*\*};
|
|
39
|
+
next if m{/\* ?@ts-};
|
|
40
|
+
# Patterns
|
|
41
|
+
if (/:\s*any\b/ || /\bas\s+any\b/ || /<any>/ || /\bany\[\]/ || /Record<[^,]+,\s*any>/) {
|
|
42
|
+
# String literal FPs
|
|
43
|
+
unless (/[\x27"](any|many)[\x27"]/i) {
|
|
44
|
+
print "$.:$line";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
$prev_allow = $has_allow;
|
|
49
|
+
' "$FILE_PATH" 2>/dev/null | head -5)
|
|
50
|
+
|
|
51
|
+
if [ -n "$ANY_HITS" ]; then
|
|
52
|
+
VIOLATIONS="${VIOLATIONS}\n⚠️ TypeScript \`any\` usage(無 \`// any-allow: {rationale}\`):\n${ANY_HITS}\n 修法:改 proper type;真沒辦法(e.g. 3rd-party 類型外部化)→ 在同行或上一行加 \`// any-allow: {具體 rationale}\`"
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# ── Check 2: tsx file size ──────────────────────────────────────────────────
|
|
56
|
+
if echo "$FILE_PATH" | grep -qE '\.tsx$'; then
|
|
57
|
+
LINES=$(wc -l < "$FILE_PATH" | tr -d ' ')
|
|
58
|
+
# Exemption marker in top 20 lines: `// code-quality-allow: file-size {rationale}`
|
|
59
|
+
EXEMPT=$(head -20 "$FILE_PATH" | grep -cE 'code-quality-allow:\s*file-size' || true)
|
|
60
|
+
if [ "$LINES" -gt 800 ] && [ "$EXEMPT" -eq 0 ]; then
|
|
61
|
+
VIOLATIONS="${VIOLATIONS}\n⚠️ tsx file-size P0:${LINES} 行 > 800 transition cap(budget 500)。架構性拆分考慮:分 sub-component tsx(e.g. sidebar.tsx → sidebar.tsx + sidebar-menu.tsx + sidebar-group.tsx)。若係 foundational composite(Sidebar/TreeView 等),tsx 頂部加 \`// code-quality-allow: file-size {rationale}\` 明文豁免。"
|
|
62
|
+
fi
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# ── Emit warning ─────────────────────────────────────────────────────────
|
|
66
|
+
if [ -n "$VIOLATIONS" ]; then
|
|
67
|
+
ESCAPED=$(printf "%b" "$VIOLATIONS" | jq -Rs .)
|
|
68
|
+
cat <<EOJSON
|
|
69
|
+
{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"Code quality lite check(full audit via /code-quality-audit):${ESCAPED}"}}
|
|
70
|
+
EOJSON
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
exit 0
|