@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,125 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Tests for inject_pending_self_audit.sh
|
|
3
|
+
|
|
4
|
+
set -u
|
|
5
|
+
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
HOOK="$SCRIPT_DIR/../inject_pending_self_audit.sh"
|
|
8
|
+
[ -x "$HOOK" ] || { echo "FATAL: hook not executable"; exit 1; }
|
|
9
|
+
|
|
10
|
+
PASS=0; FAIL=0; FAILED=""
|
|
11
|
+
|
|
12
|
+
setup_proj() {
|
|
13
|
+
TMP_PROJ=$(mktemp -d)
|
|
14
|
+
mkdir -p "$TMP_PROJ/.claude/hooks" "$TMP_PROJ/.claude/logs"
|
|
15
|
+
echo 'log_hook_fire() { :; }' > "$TMP_PROJ/.claude/hooks/_log-fire.sh"
|
|
16
|
+
export CLAUDE_PROJECT_DIR="$TMP_PROJ"
|
|
17
|
+
}
|
|
18
|
+
teardown_proj() {
|
|
19
|
+
rm -rf "$TMP_PROJ"
|
|
20
|
+
unset CLAUDE_PROJECT_DIR
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
run_hook() {
|
|
24
|
+
STDOUT=$(echo '{}' | bash "$HOOK" 2>&1)
|
|
25
|
+
EXIT=$?
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# ── Test 1: 無 log file → silent ──
|
|
29
|
+
echo "Test 1: no log files → silent exit 0"
|
|
30
|
+
setup_proj
|
|
31
|
+
run_hook
|
|
32
|
+
if [ "$EXIT" = "0" ] && [ -z "$STDOUT" ]; then
|
|
33
|
+
echo " PASS Test 1"; PASS=$((PASS+1))
|
|
34
|
+
else
|
|
35
|
+
echo " FAIL Test 1 (exit=$EXIT, output=${STDOUT:0:200})"
|
|
36
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 1"
|
|
37
|
+
fi
|
|
38
|
+
teardown_proj
|
|
39
|
+
|
|
40
|
+
# ── Test 2: 有 warnings → inject additionalContext ──
|
|
41
|
+
echo "Test 2: warning log present → inject"
|
|
42
|
+
setup_proj
|
|
43
|
+
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
44
|
+
printf '{"ts":"%s","warnings":"\\n • Test warning A\\n • Test warning B"}\n' "$NOW" \
|
|
45
|
+
> "$TMP_PROJ/.claude/logs/self-audit-warnings.jsonl"
|
|
46
|
+
run_hook
|
|
47
|
+
if [ "$EXIT" = "0" ] && echo "$STDOUT" | grep -q "Test warning A" && echo "$STDOUT" | grep -q "additionalContext"; then
|
|
48
|
+
echo " PASS Test 2"; PASS=$((PASS+1))
|
|
49
|
+
else
|
|
50
|
+
echo " FAIL Test 2 (exit=$EXIT)"
|
|
51
|
+
echo " output=${STDOUT:0:200}"
|
|
52
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 2"
|
|
53
|
+
fi
|
|
54
|
+
teardown_proj
|
|
55
|
+
|
|
56
|
+
# ── Test 3: dedup 同 warning → 顯示 [×N] ──
|
|
57
|
+
echo "Test 3: duplicate warnings → dedup count"
|
|
58
|
+
setup_proj
|
|
59
|
+
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
60
|
+
for i in 1 2 3; do
|
|
61
|
+
printf '{"ts":"%s","warnings":"\\n • Same warning"}\n' "$NOW" \
|
|
62
|
+
>> "$TMP_PROJ/.claude/logs/self-audit-warnings.jsonl"
|
|
63
|
+
done
|
|
64
|
+
run_hook
|
|
65
|
+
if echo "$STDOUT" | grep -q '\[×3\]'; then
|
|
66
|
+
echo " PASS Test 3"; PASS=$((PASS+1))
|
|
67
|
+
else
|
|
68
|
+
echo " FAIL Test 3 — dedup [×3] missing"
|
|
69
|
+
echo " output=${STDOUT:0:300}"
|
|
70
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 3"
|
|
71
|
+
fi
|
|
72
|
+
teardown_proj
|
|
73
|
+
|
|
74
|
+
# ── Test 4: LAST_TS 過濾舊條目 ──
|
|
75
|
+
echo "Test 4: LAST_TS filter — old entry skipped"
|
|
76
|
+
setup_proj
|
|
77
|
+
OLD=$(date -u -v-48H +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d '48 hours ago' +%Y-%m-%dT%H:%M:%SZ)
|
|
78
|
+
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
79
|
+
RECENT=$(date -u -v-1H +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)
|
|
80
|
+
echo "$NOW" > "$TMP_PROJ/.claude/logs/last-inject-ts.txt"
|
|
81
|
+
printf '{"ts":"%s","warnings":"\\n • Old warning(should skip)"}\n' "$OLD" \
|
|
82
|
+
> "$TMP_PROJ/.claude/logs/self-audit-warnings.jsonl"
|
|
83
|
+
printf '{"ts":"%s","warnings":"\\n • Recent warning(also skip,因 < NOW)"}\n' "$RECENT" \
|
|
84
|
+
>> "$TMP_PROJ/.claude/logs/self-audit-warnings.jsonl"
|
|
85
|
+
run_hook
|
|
86
|
+
if [ "$EXIT" = "0" ] && [ -z "$STDOUT" ]; then
|
|
87
|
+
echo " PASS Test 4"; PASS=$((PASS+1))
|
|
88
|
+
else
|
|
89
|
+
echo " FAIL Test 4 — should be silent (LAST_TS=NOW)"
|
|
90
|
+
echo " output=${STDOUT:0:200}"
|
|
91
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 4"
|
|
92
|
+
fi
|
|
93
|
+
teardown_proj
|
|
94
|
+
|
|
95
|
+
# ── Test 5: size cap — 超過 3KB truncate ──
|
|
96
|
+
echo "Test 5: large input → truncate ≤ 3.5KB"
|
|
97
|
+
setup_proj
|
|
98
|
+
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
99
|
+
# 產 50 條不同 warning
|
|
100
|
+
for i in $(seq 1 50); do
|
|
101
|
+
printf '{"ts":"%s","warnings":"\\n • Warning number %d with some padding text to fill space and exceed cap eventually"}\n' "$NOW" "$i" \
|
|
102
|
+
>> "$TMP_PROJ/.claude/logs/self-audit-warnings.jsonl"
|
|
103
|
+
done
|
|
104
|
+
run_hook
|
|
105
|
+
LEN=${#STDOUT}
|
|
106
|
+
if [ "$LEN" -lt 3800 ] && echo "$STDOUT" | grep -q "additionalContext"; then
|
|
107
|
+
echo " PASS Test 5 (size=$LEN bytes,有 truncate 提示)"
|
|
108
|
+
PASS=$((PASS+1))
|
|
109
|
+
else
|
|
110
|
+
echo " FAIL Test 5 — size=$LEN bytes(預期 < 3800)"
|
|
111
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 5"
|
|
112
|
+
fi
|
|
113
|
+
teardown_proj
|
|
114
|
+
|
|
115
|
+
# ── Summary ──
|
|
116
|
+
echo ""
|
|
117
|
+
echo "── Summary ──"
|
|
118
|
+
echo "PASS: $PASS / $(($PASS+$FAIL))"
|
|
119
|
+
if [ "$FAIL" -gt 0 ]; then
|
|
120
|
+
echo "FAIL: $FAIL"
|
|
121
|
+
printf "$FAILED\n"
|
|
122
|
+
exit 1
|
|
123
|
+
fi
|
|
124
|
+
echo "✅ All passed"
|
|
125
|
+
exit 0
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Smoke test for log_governance_fires.sh
|
|
3
|
+
set -u
|
|
4
|
+
HOOK="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../log_governance_fires.sh"
|
|
5
|
+
[ -x "$HOOK" ] || { echo "FATAL"; exit 1; }
|
|
6
|
+
PASS=0
|
|
7
|
+
echo "Test 1: empty payload → no crash"
|
|
8
|
+
STDOUT=$(echo '{}' | bash "$HOOK" 2>&1); EXIT=$?
|
|
9
|
+
[ "$EXIT" -le 1 ] && { echo " PASS exit=$EXIT"; PASS=1; } || { echo " FAIL exit=$EXIT"; exit 1; }
|
|
10
|
+
echo "Results: $PASS PASS, 0 FAIL"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
HOOK="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../log_skill_invokes.sh"
|
|
3
|
+
[ -x "$HOOK" ] || { echo "FATAL"; exit 1; }
|
|
4
|
+
echo "Test 1: empty payload → no crash"
|
|
5
|
+
STDOUT=$(echo '{"tool_name":"Skill"}' | bash "$HOOK" 2>&1); EXIT=$?
|
|
6
|
+
[ "$EXIT" -le 1 ] && echo " PASS" || { echo " FAIL"; exit 1; }
|
|
7
|
+
echo "Results: 1 PASS, 0 FAIL"
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Tests for post_edit_dispatcher.sh (orchestrator)
|
|
3
|
+
#
|
|
4
|
+
# orchestrator smoke test only — lib hook detailed tests are separate.
|
|
5
|
+
# Dispatcher fans out stdin to 9 lib/_*.sh helpers (PostToolUse Write|Edit|MultiEdit),
|
|
6
|
+
# aggregates their JSON additionalContext, prints ONE JSON output, exit 0 (non-blocking).
|
|
7
|
+
#
|
|
8
|
+
# Smoke checks:
|
|
9
|
+
# (a) bash -n syntax OK
|
|
10
|
+
# (b) JSON input → exit 0(non-blocking,no matter helper outcome)
|
|
11
|
+
# (c) Empty / malformed stdin → still exit 0
|
|
12
|
+
# (d) Helper aggregation:if any helper emits additionalContext, dispatcher includes it
|
|
13
|
+
# in stdout JSON;若全 helper silent → dispatcher 也 silent(no stdout)。
|
|
14
|
+
|
|
15
|
+
set -u
|
|
16
|
+
|
|
17
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
HOOK="$SCRIPT_DIR/../post_edit_dispatcher.sh"
|
|
19
|
+
|
|
20
|
+
if [ ! -f "$HOOK" ]; then echo "FATAL: hook not found: $HOOK"; exit 1; fi
|
|
21
|
+
|
|
22
|
+
PASS=0
|
|
23
|
+
FAIL=0
|
|
24
|
+
FAILED_TESTS=""
|
|
25
|
+
|
|
26
|
+
run_hook_stdin() {
|
|
27
|
+
local payload="$1"
|
|
28
|
+
STDOUT=$(mktemp); STDERR=$(mktemp)
|
|
29
|
+
set +e
|
|
30
|
+
printf '%s' "$payload" | bash "$HOOK" >"$STDOUT" 2>"$STDERR"
|
|
31
|
+
EXIT=$?
|
|
32
|
+
set -e
|
|
33
|
+
STDOUT_TEXT=$(cat "$STDOUT")
|
|
34
|
+
STDERR_TEXT=$(cat "$STDERR")
|
|
35
|
+
rm -f "$STDOUT" "$STDERR"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
expect_exit0() {
|
|
39
|
+
local name="$1"
|
|
40
|
+
if [ "$EXIT" = "0" ]; then
|
|
41
|
+
echo " PASS $name"; PASS=$((PASS+1))
|
|
42
|
+
else
|
|
43
|
+
echo " FAIL $name (expected exit 0, got $EXIT)"
|
|
44
|
+
echo " --- stdout ---"; echo "$STDOUT_TEXT" | sed 's/^/ /'; echo " --- end ---"
|
|
45
|
+
echo " --- stderr ---"; echo "$STDERR_TEXT" | sed 's/^/ /'; echo " --- end ---"
|
|
46
|
+
FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"
|
|
47
|
+
fi
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
echo "=== post_edit_dispatcher tests (orchestrator smoke) ==="
|
|
51
|
+
|
|
52
|
+
# 1. bash -n syntax check
|
|
53
|
+
set +e
|
|
54
|
+
bash -n "$HOOK" 2>/dev/null
|
|
55
|
+
SYNTAX=$?
|
|
56
|
+
set -e
|
|
57
|
+
if [ "$SYNTAX" = "0" ]; then
|
|
58
|
+
echo " PASS 1. bash -n syntax OK"; PASS=$((PASS+1))
|
|
59
|
+
else
|
|
60
|
+
echo " FAIL 1. bash -n syntax check"
|
|
61
|
+
FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - 1. syntax"
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# 2. Valid JSON input (out-of-scope file) → exit 0
|
|
65
|
+
PAYLOAD=$(jq -n '{tool_name: "Write", tool_input: {file_path: "/tmp/out-of-scope.txt", content: "noop"}}')
|
|
66
|
+
run_hook_stdin "$PAYLOAD"
|
|
67
|
+
expect_exit0 "2. valid JSON input → exit 0"
|
|
68
|
+
|
|
69
|
+
# 3. Empty stdin → exit 0 (dispatcher reads `cat 2>/dev/null || echo "{}"`)
|
|
70
|
+
run_hook_stdin ""
|
|
71
|
+
expect_exit0 "3. empty stdin → exit 0"
|
|
72
|
+
|
|
73
|
+
# 4. Malformed JSON → still exit 0 (helpers handle their own jq errors silently)
|
|
74
|
+
run_hook_stdin "not-valid-json{{{"
|
|
75
|
+
expect_exit0 "4. malformed JSON stdin → exit 0"
|
|
76
|
+
|
|
77
|
+
# 5. tsx file path (in-scope for some helpers) → exit 0, may emit JSON to stdout
|
|
78
|
+
PAYLOAD_TSX=$(jq -n '{tool_name: "Edit", tool_input: {file_path: "/tmp/foo.tsx", new_string: "const x = 1;"}}')
|
|
79
|
+
run_hook_stdin "$PAYLOAD_TSX"
|
|
80
|
+
expect_exit0 "5. tsx Edit payload → exit 0 (non-blocking)"
|
|
81
|
+
|
|
82
|
+
# 6. If stdout non-empty, must be valid JSON with hookSpecificOutput
|
|
83
|
+
# (only assert when stdout is non-empty — many tsx inputs may yield no warnings)
|
|
84
|
+
if [ -n "$STDOUT_TEXT" ]; then
|
|
85
|
+
set +e
|
|
86
|
+
echo "$STDOUT_TEXT" | jq -e '.hookSpecificOutput.additionalContext' >/dev/null 2>&1
|
|
87
|
+
JSON_OK=$?
|
|
88
|
+
set -e
|
|
89
|
+
if [ "$JSON_OK" = "0" ]; then
|
|
90
|
+
echo " PASS 6. when stdout non-empty, valid JSON with hookSpecificOutput"
|
|
91
|
+
PASS=$((PASS+1))
|
|
92
|
+
else
|
|
93
|
+
echo " FAIL 6. stdout was non-empty but not valid hookSpecificOutput JSON"
|
|
94
|
+
echo " --- stdout ---"; echo "$STDOUT_TEXT" | sed 's/^/ /'; echo " --- end ---"
|
|
95
|
+
FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - 6. stdout JSON shape"
|
|
96
|
+
fi
|
|
97
|
+
else
|
|
98
|
+
echo " PASS 6. stdout silent (all helpers in-scope returned empty) — JSON shape n/a"
|
|
99
|
+
PASS=$((PASS+1))
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
echo ""
|
|
103
|
+
echo "=== Summary ==="
|
|
104
|
+
echo "Passed: $PASS / $((PASS + FAIL))"
|
|
105
|
+
if [ "$FAIL" -gt 0 ]; then
|
|
106
|
+
echo "Failed:$FAILED_TESTS"
|
|
107
|
+
exit 1
|
|
108
|
+
fi
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Tests for session_start_governance_check.sh
|
|
3
|
+
#
|
|
4
|
+
# Scenarios:
|
|
5
|
+
# 1. healthy project — silent (no reminders)
|
|
6
|
+
# 2. CLAUDE.md > 800 (soft) — REMINDERS fire
|
|
7
|
+
# 3. CLAUDE.md > 1000 (hard) — BLOCKERS fire
|
|
8
|
+
# 4. corrections > 40 (hard) — BLOCKERS fire
|
|
9
|
+
# 5. fire-weighted gap (G7) — surfaces hot hook without test
|
|
10
|
+
|
|
11
|
+
set -u
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
HOOK="$SCRIPT_DIR/../session_start_governance_check.sh"
|
|
15
|
+
[ -x "$HOOK" ] || { echo "FATAL: hook not executable"; exit 1; }
|
|
16
|
+
|
|
17
|
+
PASS=0; FAIL=0; FAILED=""
|
|
18
|
+
|
|
19
|
+
setup_proj() {
|
|
20
|
+
TMP_PROJ=$(mktemp -d)
|
|
21
|
+
# 2026-05-08 fix:test isolation — empty memory dir 強制 hook 走 PROJECT_DIR scope,
|
|
22
|
+
# 不退回 $HOME harness SSOT(避免測試環境讀真實 user memory count 觸發 false blocker)
|
|
23
|
+
mkdir -p "$TMP_PROJ/.claude/logs" "$TMP_PROJ/.claude/hooks/tests" "$TMP_PROJ/.claude/memory"
|
|
24
|
+
# NOTE: deliberately NOT creating benchmarks dir(absent dir = no warning,
|
|
25
|
+
# creating an empty one = "never fetched" warning fires)
|
|
26
|
+
echo 'log_hook_fire() { :; }' > "$TMP_PROJ/.claude/hooks/_log-fire.sh"
|
|
27
|
+
# 5-line healthy CLAUDE.md
|
|
28
|
+
printf '%s\n' a b c d e > "$TMP_PROJ/CLAUDE.md"
|
|
29
|
+
# init git for last-prune check (no commits → -1)
|
|
30
|
+
( cd "$TMP_PROJ" && git init -q && git -c commit.gpgsign=false -c user.name=test -c user.email=t@t.com commit --allow-empty -m "init" -q ) 2>/dev/null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
teardown_proj() { rm -rf "$TMP_PROJ"; }
|
|
34
|
+
|
|
35
|
+
run_hook() {
|
|
36
|
+
STDOUT=$(mktemp)
|
|
37
|
+
set +e; CLAUDE_PROJECT_DIR="$TMP_PROJ" bash "$HOOK" < /dev/null > "$STDOUT" 2>&1; EXIT=$?; set -e
|
|
38
|
+
STDOUT_TEXT=$(cat "$STDOUT"); rm -f "$STDOUT"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Test 1: healthy project → silent
|
|
42
|
+
echo "Test 1: healthy project silent"
|
|
43
|
+
setup_proj
|
|
44
|
+
run_hook
|
|
45
|
+
if [ "$EXIT" = "0" ] && [ -z "$STDOUT_TEXT" ]; then
|
|
46
|
+
echo " PASS Test 1 healthy silent"; PASS=$((PASS+1))
|
|
47
|
+
else
|
|
48
|
+
echo " FAIL Test 1 (exit=$EXIT, output='$STDOUT_TEXT')"
|
|
49
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 1"
|
|
50
|
+
fi
|
|
51
|
+
teardown_proj
|
|
52
|
+
|
|
53
|
+
# Test 2: CLAUDE.md > 600 (strong-warn) → REMINDERS only(2026-04-26 tightened)
|
|
54
|
+
echo "Test 2: CLAUDE.md strong-warn threshold (601)"
|
|
55
|
+
setup_proj
|
|
56
|
+
yes '.' | head -650 > "$TMP_PROJ/CLAUDE.md"
|
|
57
|
+
run_hook
|
|
58
|
+
if [ "$EXIT" = "0" ] && [ -z "$STDOUT_TEXT" ]; then
|
|
59
|
+
echo " PASS Test 2 silent on soft (601 lines, noise reduction 2026-04-26)"; PASS=$((PASS+1))
|
|
60
|
+
else
|
|
61
|
+
echo " FAIL Test 2 (output: $STDOUT_TEXT)"
|
|
62
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 2"
|
|
63
|
+
fi
|
|
64
|
+
teardown_proj
|
|
65
|
+
|
|
66
|
+
# Test 3: CLAUDE.md > 800 (transition cap breach) → BLOCKERS(2026-04-26 tightened)
|
|
67
|
+
echo "Test 3: CLAUDE.md transition cap breach (801)"
|
|
68
|
+
setup_proj
|
|
69
|
+
yes '.' | head -850 > "$TMP_PROJ/CLAUDE.md"
|
|
70
|
+
run_hook
|
|
71
|
+
if [ "$EXIT" = "0" ] && echo "$STDOUT_TEXT" | grep -q "BLOCKER" && echo "$STDOUT_TEXT" | grep -qE "(hard|transition) cap 800 (breached|exceeded)"; then
|
|
72
|
+
echo " PASS Test 3 hard-cap 800 BLOCKER"; PASS=$((PASS+1))
|
|
73
|
+
else
|
|
74
|
+
echo " FAIL Test 3 (output: $STDOUT_TEXT)"
|
|
75
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 3"
|
|
76
|
+
fi
|
|
77
|
+
teardown_proj
|
|
78
|
+
|
|
79
|
+
# Test 4: corrections > 40 (hard) → BLOCKERS
|
|
80
|
+
echo "Test 4: corrections hard threshold"
|
|
81
|
+
setup_proj
|
|
82
|
+
yes '{}' | head -45 > "$TMP_PROJ/.claude/logs/user-corrections.jsonl"
|
|
83
|
+
run_hook
|
|
84
|
+
if [ "$EXIT" = "0" ] && echo "$STDOUT_TEXT" | grep -q "BLOCKER" && echo "$STDOUT_TEXT" | grep -q "HARD THRESHOLD 40"; then
|
|
85
|
+
echo " PASS Test 4 corrections hard BLOCKER"; PASS=$((PASS+1))
|
|
86
|
+
else
|
|
87
|
+
echo " FAIL Test 4 (output: $STDOUT_TEXT)"
|
|
88
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 4"
|
|
89
|
+
fi
|
|
90
|
+
teardown_proj
|
|
91
|
+
|
|
92
|
+
# Test 5: fire-weighted gap (G7)
|
|
93
|
+
echo "Test 5: fire-weighted gap"
|
|
94
|
+
setup_proj
|
|
95
|
+
# Generate 150 fire entries for hook 'foo'
|
|
96
|
+
for i in $(seq 1 150); do
|
|
97
|
+
echo '{"hook":"foo.sh"}'
|
|
98
|
+
done > "$TMP_PROJ/.claude/logs/hook-fires-per-hook.jsonl"
|
|
99
|
+
# foo has no test (tests dir is empty)
|
|
100
|
+
run_hook
|
|
101
|
+
if [ "$EXIT" = "0" ] && [ -z "$STDOUT_TEXT" ]; then
|
|
102
|
+
echo " PASS Test 5 silent on soft fire-weighted gap (noise reduction)"; PASS=$((PASS+1))
|
|
103
|
+
else
|
|
104
|
+
echo " FAIL Test 5 (output: $STDOUT_TEXT)"
|
|
105
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 5"
|
|
106
|
+
fi
|
|
107
|
+
teardown_proj
|
|
108
|
+
|
|
109
|
+
# Test 6: Hook count > 26 (soft prune trigger) — auto-prune fires
|
|
110
|
+
echo "Test 6: hook count 27 → soft prune trigger"
|
|
111
|
+
setup_proj
|
|
112
|
+
# Create 27 fake hooks(超過 soft 26)
|
|
113
|
+
for i in $(seq 1 27); do
|
|
114
|
+
: > "$TMP_PROJ/.claude/hooks/check_fake_${i}.sh"
|
|
115
|
+
done
|
|
116
|
+
run_hook
|
|
117
|
+
if [ "$EXIT" = "0" ] && echo "$STDOUT_TEXT" | grep -qE "(Auto-prune triggers|Hook count)"; then
|
|
118
|
+
echo " PASS Test 6 hook count soft trigger"; PASS=$((PASS+1))
|
|
119
|
+
else
|
|
120
|
+
echo " FAIL Test 6 (output: ${STDOUT_TEXT:0:200})"
|
|
121
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 6"
|
|
122
|
+
fi
|
|
123
|
+
teardown_proj
|
|
124
|
+
|
|
125
|
+
# Test 7: Hook count > hard cap → BLOCKER
|
|
126
|
+
echo "Test 7: hook count 41 → hard BLOCKER (cap raised to 40 2026-05-18)"
|
|
127
|
+
setup_proj
|
|
128
|
+
for i in $(seq 1 41); do
|
|
129
|
+
: > "$TMP_PROJ/.claude/hooks/check_fake_${i}.sh"
|
|
130
|
+
done
|
|
131
|
+
run_hook
|
|
132
|
+
if [ "$EXIT" = "0" ] && echo "$STDOUT_TEXT" | grep -q "BLOCKER" && echo "$STDOUT_TEXT" | grep -qE "hard (30|35|40)"; then
|
|
133
|
+
echo " PASS Test 7 hook count hard BLOCKER"; PASS=$((PASS+1))
|
|
134
|
+
else
|
|
135
|
+
echo " FAIL Test 7 (output: ${STDOUT_TEXT:0:200})"
|
|
136
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 7"
|
|
137
|
+
fi
|
|
138
|
+
teardown_proj
|
|
139
|
+
|
|
140
|
+
echo ""
|
|
141
|
+
echo "════ Results: $PASS PASS, $FAIL FAIL ════"
|
|
142
|
+
[ "$FAIL" -gt 0 ] && { printf "Failed:%b\n" "$FAILED"; exit 1; }
|
|
143
|
+
exit 0
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Tests for stop_capture_metrics.sh
|
|
3
|
+
#
|
|
4
|
+
# Scenarios:
|
|
5
|
+
# 1. fresh project(no prior snapshot)→ writes entry
|
|
6
|
+
# 2. recent snapshot(< 24h)→ skips
|
|
7
|
+
# 3. old snapshot(> 24h)→ writes new entry
|
|
8
|
+
|
|
9
|
+
set -u
|
|
10
|
+
|
|
11
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
|
+
# Cluster B merge(2026-05-10):stop_capture_metrics.sh fold 進
|
|
13
|
+
# stop_passive_logging.sh dispatcher R3。Test 走 dispatcher。
|
|
14
|
+
HOOK="$SCRIPT_DIR/../stop_passive_logging.sh"
|
|
15
|
+
[ -x "$HOOK" ] || { echo "FATAL: hook not executable"; exit 1; }
|
|
16
|
+
|
|
17
|
+
PASS=0; FAIL=0; FAILED=""
|
|
18
|
+
|
|
19
|
+
# Use isolated temp project dir per test to avoid touching real metric file
|
|
20
|
+
setup_temp_proj() {
|
|
21
|
+
TMP_PROJ=$(mktemp -d)
|
|
22
|
+
mkdir -p "$TMP_PROJ/.claude/logs" "$TMP_PROJ/.claude/hooks" "$TMP_PROJ/.claude/skills"
|
|
23
|
+
# CLAUDE.md fixture
|
|
24
|
+
printf '%s\n' line1 line2 line3 > "$TMP_PROJ/CLAUDE.md"
|
|
25
|
+
# 2 dummy hooks(non-test)
|
|
26
|
+
touch "$TMP_PROJ/.claude/hooks/foo.sh" "$TMP_PROJ/.claude/hooks/bar.sh"
|
|
27
|
+
# 1 skill
|
|
28
|
+
mkdir "$TMP_PROJ/.claude/skills/baz"
|
|
29
|
+
# Need _log-fire.sh stub(hook sources it)
|
|
30
|
+
echo 'log_hook_fire() { :; }' > "$TMP_PROJ/.claude/hooks/_log-fire.sh"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
teardown_temp_proj() {
|
|
34
|
+
rm -rf "$TMP_PROJ"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Test 1: fresh project → writes entry
|
|
38
|
+
echo "Test 1: fresh project(no prior snapshot)"
|
|
39
|
+
setup_temp_proj
|
|
40
|
+
CLAUDE_PROJECT_DIR="$TMP_PROJ" bash "$HOOK"
|
|
41
|
+
EXIT=$?
|
|
42
|
+
LINES=$(wc -l < "$TMP_PROJ/.claude/logs/metric-snapshots.jsonl" 2>/dev/null | tr -d ' ' || echo 0)
|
|
43
|
+
if [ "$EXIT" = "0" ] && [ "$LINES" = "1" ]; then
|
|
44
|
+
echo " PASS Test 1 fresh project writes entry"
|
|
45
|
+
PASS=$((PASS+1))
|
|
46
|
+
else
|
|
47
|
+
echo " FAIL Test 1 (exit=$EXIT, lines=$LINES, expected exit=0, lines=1)"
|
|
48
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 1"
|
|
49
|
+
fi
|
|
50
|
+
teardown_temp_proj
|
|
51
|
+
|
|
52
|
+
# Test 2: recent snapshot(< 24h)→ skip
|
|
53
|
+
echo "Test 2: recent snapshot skip"
|
|
54
|
+
setup_temp_proj
|
|
55
|
+
NOW_ISO=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
56
|
+
echo "{\"ts\":\"$NOW_ISO\",\"tag\":\"prior\",\"claude_md_lines\":1}" > "$TMP_PROJ/.claude/logs/metric-snapshots.jsonl"
|
|
57
|
+
CLAUDE_PROJECT_DIR="$TMP_PROJ" bash "$HOOK"
|
|
58
|
+
EXIT=$?
|
|
59
|
+
LINES=$(wc -l < "$TMP_PROJ/.claude/logs/metric-snapshots.jsonl" | tr -d ' ')
|
|
60
|
+
if [ "$EXIT" = "0" ] && [ "$LINES" = "1" ]; then
|
|
61
|
+
echo " PASS Test 2 recent snapshot dedup skip"
|
|
62
|
+
PASS=$((PASS+1))
|
|
63
|
+
else
|
|
64
|
+
echo " FAIL Test 2 (exit=$EXIT, lines=$LINES, expected dedup keep 1 line)"
|
|
65
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 2"
|
|
66
|
+
fi
|
|
67
|
+
teardown_temp_proj
|
|
68
|
+
|
|
69
|
+
# Test 3: old snapshot(> 24h)→ append
|
|
70
|
+
echo "Test 3: old snapshot triggers new entry"
|
|
71
|
+
setup_temp_proj
|
|
72
|
+
echo '{"ts":"2026-04-20T00:00:00Z","tag":"prior","claude_md_lines":1}' > "$TMP_PROJ/.claude/logs/metric-snapshots.jsonl"
|
|
73
|
+
CLAUDE_PROJECT_DIR="$TMP_PROJ" bash "$HOOK"
|
|
74
|
+
EXIT=$?
|
|
75
|
+
LINES=$(wc -l < "$TMP_PROJ/.claude/logs/metric-snapshots.jsonl" | tr -d ' ')
|
|
76
|
+
if [ "$EXIT" = "0" ] && [ "$LINES" = "2" ]; then
|
|
77
|
+
# Verify new entry has expected fields
|
|
78
|
+
LATEST=$(tail -1 "$TMP_PROJ/.claude/logs/metric-snapshots.jsonl")
|
|
79
|
+
if echo "$LATEST" | jq -e '.untested_hooks != null and .corrections_pending != null and .claude_md_lines == 3' > /dev/null 2>&1; then
|
|
80
|
+
echo " PASS Test 3 old snapshot triggers new(schema correct)"
|
|
81
|
+
PASS=$((PASS+1))
|
|
82
|
+
else
|
|
83
|
+
echo " FAIL Test 3 schema check (latest=$LATEST)"
|
|
84
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 3 schema"
|
|
85
|
+
fi
|
|
86
|
+
else
|
|
87
|
+
echo " FAIL Test 3 (exit=$EXIT, lines=$LINES, expected exit=0, lines=2)"
|
|
88
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 3"
|
|
89
|
+
fi
|
|
90
|
+
teardown_temp_proj
|
|
91
|
+
|
|
92
|
+
echo ""
|
|
93
|
+
echo "════ Results: $PASS PASS, $FAIL FAIL ════"
|
|
94
|
+
[ "$FAIL" -gt 0 ] && { printf "Failed:%b\n" "$FAILED"; exit 1; }
|
|
95
|
+
exit 0
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Tests for stop_governance_drift_check.sh
|
|
3
|
+
#
|
|
4
|
+
# Verifies:
|
|
5
|
+
# 1. Silent exit when no commits / no governance edits
|
|
6
|
+
# 2. Inject warning when CLAUDE.md over thresholds
|
|
7
|
+
# 3. Inject warning when foundational SSOT spec over cap
|
|
8
|
+
# 4. Update last-head pointer
|
|
9
|
+
|
|
10
|
+
set -u
|
|
11
|
+
|
|
12
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
+
# Cluster B merge(2026-05-10):stop_governance_drift_check.sh fold 進 stop_passive_logging.sh dispatcher R4。
|
|
14
|
+
HOOK="$SCRIPT_DIR/../stop_passive_logging.sh"
|
|
15
|
+
|
|
16
|
+
if [ ! -x "$HOOK" ]; then
|
|
17
|
+
echo "FATAL: hook not executable: $HOOK"
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
PASS=0
|
|
22
|
+
FAIL=0
|
|
23
|
+
FAILED=""
|
|
24
|
+
|
|
25
|
+
# Each test in own temp project to avoid cross-contamination
|
|
26
|
+
setup_proj() {
|
|
27
|
+
TMP_PROJ=$(mktemp -d)
|
|
28
|
+
cd "$TMP_PROJ" || exit 1
|
|
29
|
+
git init --quiet
|
|
30
|
+
git config user.email "test@test"
|
|
31
|
+
git config user.name "Test"
|
|
32
|
+
git config commit.gpgsign false
|
|
33
|
+
echo "x" > a.txt
|
|
34
|
+
git add a.txt
|
|
35
|
+
git commit -q -m "init"
|
|
36
|
+
mkdir -p .claude/logs .claude/hooks src/design-system/tokens/color
|
|
37
|
+
ln -s "$SCRIPT_DIR/../_log-fire.sh" .claude/hooks/_log-fire.sh
|
|
38
|
+
export CLAUDE_PROJECT_DIR="$TMP_PROJ"
|
|
39
|
+
}
|
|
40
|
+
teardown_proj() { cd /; rm -rf "$TMP_PROJ"; }
|
|
41
|
+
|
|
42
|
+
run_hook() {
|
|
43
|
+
STDOUT=$(bash "$HOOK" 2>&1)
|
|
44
|
+
EXIT=$?
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# ── Test 1: no commits, no edits → silent exit 0 ─────────────────────────────
|
|
48
|
+
echo "Test 1: no changes → silent"
|
|
49
|
+
setup_proj
|
|
50
|
+
echo "$(git rev-parse HEAD)" > .claude/logs/.stop-drift-last-head
|
|
51
|
+
run_hook
|
|
52
|
+
if [ "$EXIT" = "0" ] && [ -z "$STDOUT" ]; then
|
|
53
|
+
echo " PASS Test 1 silent on no changes"; PASS=$((PASS+1))
|
|
54
|
+
else
|
|
55
|
+
echo " FAIL Test 1 (exit=$EXIT, output=${STDOUT:0:100})"
|
|
56
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 1"
|
|
57
|
+
fi
|
|
58
|
+
teardown_proj
|
|
59
|
+
|
|
60
|
+
# ── Test 2: CLAUDE.md > 800 + new commit → BLOCKER warning ────────────────────
|
|
61
|
+
echo ""
|
|
62
|
+
echo "Test 2: CLAUDE.md > 800 with commit → warning injected"
|
|
63
|
+
setup_proj
|
|
64
|
+
PRE_HEAD=$(git rev-parse HEAD)
|
|
65
|
+
echo "$PRE_HEAD" > .claude/logs/.stop-drift-last-head
|
|
66
|
+
yes '.' | head -850 > CLAUDE.md
|
|
67
|
+
git add CLAUDE.md
|
|
68
|
+
git commit -q -m "huge"
|
|
69
|
+
run_hook
|
|
70
|
+
LOG="$TMP_PROJ/.claude/logs/governance-drift.jsonl"
|
|
71
|
+
if [ "$EXIT" = "0" ] && [ -f "$LOG" ] && grep -q "transition cap" "$LOG"; then
|
|
72
|
+
echo " PASS Test 2 transition-cap warn injected"; PASS=$((PASS+1))
|
|
73
|
+
else
|
|
74
|
+
echo " FAIL Test 2 (exit=$EXIT, output=${STDOUT:0:200})"
|
|
75
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 2"
|
|
76
|
+
fi
|
|
77
|
+
teardown_proj
|
|
78
|
+
|
|
79
|
+
# ── Test 3: CLAUDE.md > 600 strong-warn ──────────────────────────────────────
|
|
80
|
+
echo ""
|
|
81
|
+
echo "Test 3: CLAUDE.md > 600 strong-warn"
|
|
82
|
+
setup_proj
|
|
83
|
+
PRE_HEAD=$(git rev-parse HEAD)
|
|
84
|
+
echo "$PRE_HEAD" > .claude/logs/.stop-drift-last-head
|
|
85
|
+
yes '.' | head -650 > CLAUDE.md
|
|
86
|
+
git add CLAUDE.md
|
|
87
|
+
git commit -q -m "warn"
|
|
88
|
+
run_hook
|
|
89
|
+
LOG="$TMP_PROJ/.claude/logs/governance-drift.jsonl"
|
|
90
|
+
if [ "$EXIT" = "0" ] && [ -f "$LOG" ] && grep -q "strong-warn" "$LOG"; then
|
|
91
|
+
echo " PASS Test 3 strong-warn injected"; PASS=$((PASS+1))
|
|
92
|
+
else
|
|
93
|
+
echo " FAIL Test 3 (exit=$EXIT, output=${STDOUT:0:200})"
|
|
94
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 3"
|
|
95
|
+
fi
|
|
96
|
+
teardown_proj
|
|
97
|
+
|
|
98
|
+
# ── Test 4: governance edit detected via diff(no commit yet)→ warning ──────
|
|
99
|
+
echo ""
|
|
100
|
+
echo "Test 4: unstaged CLAUDE.md edit > 600 → warning"
|
|
101
|
+
setup_proj
|
|
102
|
+
echo "init" > CLAUDE.md
|
|
103
|
+
git add CLAUDE.md
|
|
104
|
+
git commit -q -m "init claude.md"
|
|
105
|
+
echo "$(git rev-parse HEAD)" > .claude/logs/.stop-drift-last-head
|
|
106
|
+
yes '.' | head -650 > CLAUDE.md
|
|
107
|
+
run_hook
|
|
108
|
+
LOG="$TMP_PROJ/.claude/logs/governance-drift.jsonl"
|
|
109
|
+
if [ "$EXIT" = "0" ] && [ -f "$LOG" ] && grep -q "strong-warn" "$LOG"; then
|
|
110
|
+
echo " PASS Test 4 unstaged edit warning"; PASS=$((PASS+1))
|
|
111
|
+
else
|
|
112
|
+
echo " FAIL Test 4 (exit=$EXIT, output=${STDOUT:0:200})"
|
|
113
|
+
FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 4"
|
|
114
|
+
fi
|
|
115
|
+
teardown_proj
|
|
116
|
+
|
|
117
|
+
# ── Summary ──────────────────────────────────────────────────────────────────
|
|
118
|
+
echo ""
|
|
119
|
+
echo "════════════════════════════════════════"
|
|
120
|
+
echo " Results: $PASS PASS, $FAIL FAIL"
|
|
121
|
+
echo "════════════════════════════════════════"
|
|
122
|
+
if [ "$FAIL" -gt 0 ]; then
|
|
123
|
+
printf "Failed:%b\n" "$FAILED"; exit 1
|
|
124
|
+
fi
|
|
125
|
+
exit 0
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Smoke test for stop_harvest_corrections.sh
|
|
3
|
+
set -u
|
|
4
|
+
# Cluster B merge(2026-05-10):stop_harvest_corrections.sh fold 進 stop_passive_logging.sh dispatcher R2。
|
|
5
|
+
HOOK="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../stop_passive_logging.sh"
|
|
6
|
+
[ -x "$HOOK" ] || { echo "FATAL"; exit 1; }
|
|
7
|
+
echo "Test 1: minimal payload → no crash"
|
|
8
|
+
STDOUT=$(echo '{}' | bash "$HOOK" 2>&1); EXIT=$?
|
|
9
|
+
[ "$EXIT" -le 2 ] && echo " PASS exit=$EXIT" || { echo " FAIL exit=$EXIT out=${STDOUT:0:100}"; exit 1; }
|
|
10
|
+
echo "Results: 1 PASS, 0 FAIL"
|