@haposoft/cafekit 0.18.0 → 0.18.2

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.
Files changed (162) hide show
  1. package/README.md +12 -1
  2. package/bin/__tests__/claude-settings.test.js +123 -0
  3. package/bin/__tests__/codex-ask-guard.test.js +123 -0
  4. package/bin/__tests__/codex-ask-projection.test.js +51 -0
  5. package/bin/__tests__/codex-hooks-ownership.test.js +80 -1
  6. package/bin/__tests__/codex-hooks.test.js +938 -237
  7. package/bin/__tests__/codex-native-hook-boundaries.test.js +136 -0
  8. package/bin/__tests__/codex-native.test.js +222 -149
  9. package/bin/__tests__/codex-projection-parity.test.js +314 -0
  10. package/bin/__tests__/codex-quiet-hooks.test.js +170 -0
  11. package/bin/__tests__/codex-research-projection.test.js +70 -0
  12. package/bin/__tests__/codex-specs-projection.test.js +76 -0
  13. package/bin/__tests__/develop-contract.test.js +102 -1362
  14. package/bin/__tests__/docs-sync-on-demand.test.js +25 -20
  15. package/bin/__tests__/inspect-paths.test.js +183 -0
  16. package/bin/__tests__/installer-safety.test.js +335 -0
  17. package/bin/__tests__/legacy-authority-decoupled.test.js +14 -19
  18. package/bin/__tests__/legacy-hooks-retired.test.js +18 -8
  19. package/bin/__tests__/omp-bridge.test.js +66 -12
  20. package/bin/__tests__/omp-hooks.test.js +11 -5
  21. package/bin/__tests__/orca-session.test.js +7 -0
  22. package/bin/__tests__/package-inventory.test.js +1 -395
  23. package/bin/__tests__/privacy-paths.test.js +317 -0
  24. package/bin/__tests__/spec-narrowing.test.js +30 -134
  25. package/bin/__tests__/specs-v2-execution-closeout.test.js +0 -372
  26. package/bin/__tests__/test-runtime-dependency-closure.cjs +1 -2
  27. package/bin/__tests__/usage-hook-retired.test.js +5 -3
  28. package/bin/__tests__/validator-grounding.test.js +17 -2929
  29. package/bin/install.js +25 -0
  30. package/bin/lib/codex-install.js +134 -12
  31. package/bin/lib/context.js +1 -1
  32. package/bin/lib/managed-writer.js +2 -3
  33. package/bin/phases/claude-runtime.js +91 -25
  34. package/bin/phases/claude-settings.js +22 -1
  35. package/bin/phases/codex-hooks.js +96 -33
  36. package/bin/phases/codex-runtime.js +45 -49
  37. package/bin/phases/copy-payload.js +11 -28
  38. package/bin/phases/omp-runtime.js +6 -3
  39. package/package.json +2 -3
  40. package/src/claude/CLAUDE.md +4 -0
  41. package/src/claude/agents/code-auditor.md +9 -6
  42. package/src/claude/agents/debugger.md +3 -9
  43. package/src/claude/agents/docs-keeper.md +4 -7
  44. package/src/claude/agents/git-ops.md +2 -4
  45. package/src/claude/agents/implementer.md +6 -7
  46. package/src/claude/agents/inspector.md +2 -0
  47. package/src/claude/agents/project-manager.md +2 -2
  48. package/src/claude/agents/spec-maker.md +4 -4
  49. package/src/claude/agents/test-runner.md +8 -11
  50. package/src/claude/agents/ui-ux-designer.md +0 -1
  51. package/src/claude/gitignore +3 -0
  52. package/src/claude/hooks/__tests__/installed-root.test.js +111 -0
  53. package/src/claude/hooks/__tests__/precompact.test.js +206 -10
  54. package/src/claude/hooks/__tests__/privacy-block.test.js +27 -0
  55. package/src/claude/hooks/__tests__/session-writeenv.test.js +25 -0
  56. package/src/claude/hooks/__tests__/spec-gate.test.js +311 -340
  57. package/src/claude/hooks/__tests__/spec-state-touched.test.js +230 -8
  58. package/src/claude/hooks/__tests__/state.test.js +207 -7
  59. package/src/claude/hooks/__tests__/update-check.test.js +88 -0
  60. package/src/claude/hooks/agent.cjs +7 -6
  61. package/src/claude/hooks/inspect-block.cjs +15 -63
  62. package/src/claude/hooks/lib/inspect-paths.cjs +304 -0
  63. package/src/claude/hooks/lib/parser.cjs +1 -1
  64. package/src/claude/hooks/lib/privacy-command-analysis.cjs +191 -17
  65. package/src/claude/hooks/lib/privacy-paths.cjs +313 -0
  66. package/src/claude/hooks/lib/project-root.cjs +15 -0
  67. package/src/claude/hooks/lib/rules-reservation.cjs +36 -0
  68. package/src/claude/hooks/lib/spec-touch.cjs +67 -0
  69. package/src/claude/hooks/lib/update-check.cjs +77 -0
  70. package/src/claude/hooks/precompact.cjs +8 -15
  71. package/src/claude/hooks/privacy-block.cjs +23 -205
  72. package/src/claude/hooks/rules.cjs +6 -28
  73. package/src/claude/hooks/session.cjs +34 -117
  74. package/src/claude/hooks/spec-gate.cjs +17 -89
  75. package/src/claude/hooks/spec-state.cjs +89 -96
  76. package/src/claude/hooks/state.cjs +96 -51
  77. package/src/claude/migration-manifest.json +20 -8
  78. package/src/claude/output-styles/coding-level-0-eli5.md +9 -9
  79. package/src/claude/output-styles/coding-level-1-junior.md +3 -3
  80. package/src/claude/output-styles/coding-level-2-mid.md +3 -3
  81. package/src/claude/output-styles/coding-level-3-senior.md +2 -2
  82. package/src/claude/output-styles/coding-level-4-lead.md +5 -5
  83. package/src/claude/output-styles/coding-level-5-god.md +6 -6
  84. package/src/claude/rules/ai-dev-rules.md +1 -2
  85. package/src/claude/rules/hook-protocols.md +1 -1
  86. package/src/claude/rules/workflow.md +1 -1
  87. package/src/claude/runtime.json +0 -3
  88. package/src/claude/scripts/generate-skill-catalog.cjs +2 -2
  89. package/src/claude/scripts/provenance.cjs +14 -0
  90. package/src/claude/scripts/spec-receipt.cjs +0 -114
  91. package/src/claude/scripts/spec-resolver.cjs +41 -457
  92. package/src/claude/scripts/workflow-policy.cjs +3 -1801
  93. package/src/claude/settings/settings.json +1 -1
  94. package/src/claude/skills/agent-browser/SKILL.md +1 -1
  95. package/src/claude/skills/ai-multimodal/scripts/check_setup.py +8 -68
  96. package/src/claude/skills/ai-multimodal/scripts/gemini_batch_process.py +6 -28
  97. package/src/claude/skills/chrome-devtools/SKILL.md +14 -31
  98. package/src/claude/skills/code-review/SKILL.md +25 -108
  99. package/src/claude/skills/code-review/references/spec-compliance-review.md +4 -7
  100. package/src/claude/skills/develop/SKILL.md +22 -70
  101. package/src/claude/skills/develop/references/subagent-patterns.md +0 -6
  102. package/src/claude/skills/git/SKILL.md +1 -1
  103. package/src/claude/skills/git/references/worktree-blueprint.md +1 -1
  104. package/src/claude/skills/research/SKILL.md +24 -55
  105. package/src/claude/skills/sync/SKILL.md +12 -34
  106. package/src/claude/skills/sync/references/rebind-and-audit.md +2 -2
  107. package/src/claude/skills/test/SKILL.md +39 -123
  108. package/src/claude/skills/test/references/execution-strategy.md +11 -22
  109. package/src/claude/skills/ui-ux/SKILL.md +1 -1
  110. package/src/claude/skills/ui-ux-pro-max/SKILL.md +24 -79
  111. package/src/claude/skills/web-testing/SKILL.md +2 -20
  112. package/src/codex/AGENTS.md +8 -0
  113. package/src/codex/hooks/ask-guard.cjs +54 -0
  114. package/src/codex/hooks/inspect-block.cjs +11 -7
  115. package/src/codex/hooks/lib/inspect-paths.cjs +1 -199
  116. package/src/codex/hooks/lib/privacy-paths.cjs +1 -0
  117. package/src/codex/hooks/lib/privacy-state.cjs +98 -16
  118. package/src/codex/hooks/lib/rules-reservation.cjs +38 -0
  119. package/src/codex/hooks/lib/secret-keywords.cjs +1 -0
  120. package/src/codex/hooks/lib/spec-receipt.cjs +2 -30
  121. package/src/codex/hooks/lib/spec-session-touch.cjs +100 -0
  122. package/src/codex/hooks/lib/spec-touch.cjs +3 -0
  123. package/src/codex/hooks/lib/spec-utils.cjs +6 -45
  124. package/src/codex/hooks/lib/update-check.cjs +1 -0
  125. package/src/codex/hooks/precompact.cjs +39 -0
  126. package/src/codex/hooks/privacy-approval.cjs +28 -17
  127. package/src/codex/hooks/privacy-block.cjs +9 -215
  128. package/src/codex/hooks/rules.cjs +4 -30
  129. package/src/codex/hooks/secret-output-guardrail.cjs +1 -1
  130. package/src/codex/hooks/session.cjs +47 -11
  131. package/src/codex/hooks/spec-gate.cjs +32 -74
  132. package/src/codex/hooks/spec-state.cjs +68 -46
  133. package/src/codex/hooks/state.cjs +25 -4
  134. package/src/codex/hooks.json +39 -7
  135. package/src/codex/rules/hook-protocols.md +13 -6
  136. package/src/common/AGENTS.md +4 -10
  137. package/src/omp/extensions/cafekit-bridge.mjs +12 -4
  138. package/src/omp/hooks/privacy-block.cjs +24 -206
  139. package/bin/__tests__/change-firewall.semantic-firewall.test.js +0 -2133
  140. package/bin/__tests__/finalizer-pass-gate.semantic-firewall.test.js +0 -342
  141. package/bin/__tests__/release-preflight.semantic-firewall.test.js +0 -586
  142. package/bin/__tests__/review-receipt-c2.semantic-firewall.test.js +0 -378
  143. package/bin/__tests__/specs-v2-policy-and-scaffold.test.js +0 -665
  144. package/bin/__tests__/specs-v2-validator-grounder-contract.test.js +0 -1132
  145. package/src/claude/hooks/lib/context.cjs +0 -527
  146. package/src/claude/hooks/lib/detect.cjs +0 -474
  147. package/src/claude/scripts/change-firewall.cjs +0 -1748
  148. package/src/claude/scripts/spec-authoring-digest.cjs +0 -151
  149. package/src/claude/scripts/spec-authoring-validation.cjs +0 -126
  150. package/src/claude/scripts/spec-final-state.cjs +0 -290
  151. package/src/claude/scripts/spec-ground.cjs +0 -650
  152. package/src/claude/scripts/spec-readiness.cjs +0 -425
  153. package/src/claude/scripts/spec-scaffold.cjs +0 -2317
  154. package/src/claude/scripts/spec-semantic-model.cjs +0 -396
  155. package/src/claude/scripts/validate-spec-output.cjs +0 -3914
  156. package/src/claude/skills/code-review/references/verification-gate.md +0 -41
  157. package/src/claude/skills/specs/templates/design.md +0 -82
  158. package/src/claude/skills/specs/templates/requirements-init.md +0 -8
  159. package/src/claude/skills/specs/templates/requirements.md +0 -42
  160. package/src/claude/skills/specs/templates/spec-state.json +0 -56
  161. package/src/claude/skills/specs/templates/task.md +0 -47
  162. package/src/codex/rules/state-sync.md +0 -60
@@ -20,27 +20,20 @@ marker. Resolve all accepted paths inside the target feature directory.
20
20
  marker, malformed or duplicate task fields, symlink, directory, device, or
21
21
  other nonregular flat marker returns `BLOCKED`.
22
22
 
23
- ### Legacy markers
23
+ ### Packets the runtime no longer reads
24
24
 
25
- - Legacy markers are `spec.json`, nested legacy tasks, or separate legacy
26
- receipts. Detect them even when orphaned or broken.
27
- - Legacy is selected only when a regular schema-valid `spec.json` has one
28
- consistent identity and registry resolving every contained nested task and
29
- receipt, and no flat marker exists.
30
- - Orphan nested tasks/receipts, absent or schema-invalid root, conflicting
31
- identities, symlinks, nonregular markers, or unresolved/out-of-root entries
32
- return `BLOCKED`.
25
+ - A packet directory with no `plan.md` that holds the old JSON planning state is not
26
+ read by CafeKit. Return `BLOCKED` and name it; never migrate it while testing.
27
+ - Other files beside a valid `plan.md` do not change its classification.
33
28
 
34
29
  ### Precedence truth table
35
30
 
36
- | Flat state | Legacy state | Result |
31
+ | Flat state | Old planning state without `plan.md` | Result |
37
32
  |---|---|---|
38
- | valid | absent | process-first |
39
- | absent | valid | legacy adapter |
33
+ | valid | any | process-first |
34
+ | invalid | any | `BLOCKED` |
35
+ | absent | present | `BLOCKED`: unsupported, move the work to a `plan.md` packet |
40
36
  | absent | absent | ordinary non-Spec scope |
41
- | any marker | any marker | `BLOCKED` mixed state |
42
- | invalid | absent | `BLOCKED` |
43
- | absent | invalid | `BLOCKED` |
44
37
 
45
38
  Do not infer that an invalid marker is absent. Testing never repairs, migrates,
46
39
  renames, deletes, or chooses between conflicting packet identities.
@@ -181,7 +174,7 @@ packet failed classification after the repository had a commit:
181
174
  },
182
175
  "proof_level": "source",
183
176
  "expected": "both Named probes pass under `node --test test/login.test.js`",
184
- "observed": "BLOCKED before execution: specs/user-auth also holds spec.json, a legacy marker",
177
+ "observed": "BLOCKED before execution: specs/user-auth/task-01-login.md is a symlink",
185
178
  "reachability": {
186
179
  "status": "BLOCKED",
187
180
  "evidence": [
@@ -287,9 +280,5 @@ Do not paste verbose raw output, full JSON, credentials, PII, or screenshots int
287
280
  the report. Do not write a report file during proof. Process-first Status and
288
281
  inline `## Receipt` remain controller-only.
289
282
 
290
- ## Legacy workflow compatibility
291
-
292
- After a valid legacy route, preserve its v2.1 task/receipt adapter and existing
293
- proof rules. Separate legacy receipts remain legacy-only. Never search for or
294
- create a separate receipt for a process-first task, and never copy a legacy
295
- receipt into a flat task.
283
+ Proof for a process-first task lives only in its inline `## Receipt`; never
284
+ search for or create a receipt file beside it.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: cf:ui-ux
3
- description: "Build, review, or redesign an in-app screen (dashboard, list, table, form, settings, modal) the way a designer works: brief, 2–3 wireframes, the user picks, then build with the project's own components and measure the page with a browser probe. Other routes on request: review an existing UI ('xem giúp', 'review', 'nhìn rối', 'what's wrong'), rebuild keeping the brand ('giữ brand', 'keep the brand'), rebuild in the skill's own style ('bỏ style cũ'), refactor keeping the look ('chuyển sang Tailwind'), build right away ('dựng luôn', 'just build it'), design system first ('UI kit', 'component library'), a simple logo ('làm logo', 'design a logo'), or fix one component. Triggers: 'dựng màn', 'thiết kế', 'làm UI cho đẹp', 'làm lại UX', 'build a page', 'design this screen', 'redesign', 'make it look good', 'ecommerce', 'ui-ux', 'evon'. Landing pages, storefronts and blogs are not covered (it still builds them, with a warning)."
3
+ description: "Build, review, or redesign an in-app screen (dashboard, list, table, form, settings, modal) the way a designer works: brief, 2–3 wireframes, the user picks, then build with the project's own components and measure the page with a browser probe. On request it also reviews an existing UI, rebuilds with or without the current brand, refactors styling while keeping the look, builds immediately without wireframes, builds a design system or component kit first, makes a simple logo, or fixes one component, for Vietnamese or English requests ('dựng màn', 'thiết kế', 'làm UI cho đẹp', 'làm lại UX', 'xem giúp', 'nhìn rối', 'giữ brand', 'bỏ style cũ', 'dựng luôn', 'làm logo', 'build a page', 'redesign', 'ui-ux', 'evon'). Landing pages, storefronts and blogs are not covered (it still builds them, with a warning)."
4
4
  license: MIT
5
5
  user-invocable: true
6
6
  when_to_use: "Invoke to build, review, or redesign an app screen with wireframes and a measured probe; for palette, font, or UX-guideline lookups use cf:ui-ux-pro-max."
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: cf:ui-ux-pro-max
3
- description: "UI/UX design intelligence for web and mobile. Includes 50+ styles, 161 color palettes, 57 font pairings, 161 product types, 99 UX guidelines, and 25 chart types across 10 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn/ui, and HTML/CSS). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, and check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, and mobile app. Elements: button, modal, navbar, sidebar, card, table, form, and chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, and flat design. Topics: color systems, accessibility, animation, layout, typography, font pairing, spacing, interaction states, shadow, and gradient. Integrations: shadcn/ui MCP for component search and examples."
3
+ description: "Searchable UI/UX lookup database for web and mobile products: 50+ visual styles, 161 color palettes, 57 font pairings, 161 product types with reasoning rules, 99 UX guidelines, 25 chart types, Google Fonts, and React Native stack guidance. Use to pick or justify a palette, font pairing, visual style, chart type, or UX guideline for a product type. It does not build, review, or redesign screens; that is cf:ui-ux, which can consult this skill for lookups."
4
4
  user-invocable: true
5
5
  when_to_use: "Invoke to look up color palettes, font pairings, product-type styles, or UX guidelines; to build or review a screen use cf:ui-ux."
6
6
  category: frontend
@@ -11,45 +11,13 @@ metadata:
11
11
  ---
12
12
  # UI/UX Pro Max - Design Intelligence
13
13
 
14
- Comprehensive design guide for web and mobile applications. Contains 50+ styles, 161 color palettes, 57 font pairings, 161 product types with reasoning rules, 99 UX guidelines, and 25 chart types across 10 technology stacks. Searchable database with priority-based recommendations.
14
+ Searchable design database for web and mobile products: 50+ styles, 161 color palettes, 57 font pairings, 161 product types with reasoning rules, 99 UX guidelines, 25 chart types, and stack guidance for React Native only.
15
15
 
16
16
  ## When to Apply
17
17
 
18
- This Skill should be used when the task involves **UI structure, visual design decisions, interaction patterns, or user experience quality control**.
18
+ Use this skill to look something up: a palette, font pairing, or visual style for a product type, a chart type, or the UX guideline that applies to a pattern.
19
19
 
20
- ### Must Use
21
-
22
- This Skill must be invoked in the following situations:
23
-
24
- - Designing new pages (Landing Page, Dashboard, Admin, SaaS, Mobile App)
25
- - Creating or refactoring UI components (buttons, modals, forms, tables, charts, etc.)
26
- - Choosing color schemes, typography systems, spacing standards, or layout systems
27
- - Reviewing UI code for user experience, accessibility, or visual consistency
28
- - Implementing navigation structures, animations, or responsive behavior
29
- - Making product-level design decisions (style, information hierarchy, brand expression)
30
- - Improving perceived quality, clarity, or usability of interfaces
31
-
32
- ### Recommended
33
-
34
- This Skill is recommended in the following situations:
35
-
36
- - UI looks "not professional enough" but the reason is unclear
37
- - Receiving feedback on usability or experience
38
- - Pre-launch UI quality optimization
39
- - Aligning cross-platform design (Web / iOS / Android)
40
- - Building design systems or reusable component libraries
41
-
42
- ### Skip
43
-
44
- This Skill is not needed in the following situations:
45
-
46
- - Pure backend logic development
47
- - Only involving API or database design
48
- - Performance optimization unrelated to the interface
49
- - Infrastructure or DevOps work
50
- - Non-visual scripts or automation tasks
51
-
52
- **Decision criteria**: If the task will change how a feature **looks, feels, moves, or is interacted with**, this Skill should be used.
20
+ Building, reviewing, or redesigning a screen belongs to `cf:ui-ux`, which follows the project's own components and measures the page; it can call this skill when it needs a lookup. Backend, API, infrastructure, and non-visual work need neither skill.
53
21
 
54
22
  ## Rule Categories by Priority
55
23
 
@@ -313,28 +281,7 @@ Search specific domains using the CLI tool below.
313
281
 
314
282
  ## Prerequisites
315
283
 
316
- Check if Python is installed:
317
-
318
- ```bash
319
- python3 --version || python --version
320
- ```
321
-
322
- If Python is not installed, install it based on user's OS:
323
-
324
- **macOS:**
325
- ```bash
326
- brew install python3
327
- ```
328
-
329
- **Ubuntu/Debian:**
330
- ```bash
331
- sudo apt update && sudo apt install python3
332
- ```
333
-
334
- **Windows:**
335
- ```powershell
336
- winget install Python.Python.3.12
337
- ```
284
+ Run `search.py` from the project root with `python3 .claude/skills/ui-ux-pro-max/scripts/search.py` (Windows: `python .claude\skills\ui-ux-pro-max\scripts\search.py`). It uses only the Python standard library, so no venv or extra install is needed.
338
285
 
339
286
  ---
340
287
 
@@ -362,14 +309,14 @@ Extract key information from user request:
362
309
  - **Product type**: Entertainment (social, video, music, gaming), Tool (scanner, editor, converter), Productivity (task manager, notes, calendar), or hybrid
363
310
  - **Target audience**: C-end consumer users; consider age group, usage context (commute, leisure, work)
364
311
  - **Style keywords**: playful, vibrant, minimal, dark mode, content-first, immersive, etc.
365
- - **Stack**: React Native (this project's only tech stack)
312
+ - **Stack**: the target project's stack; `--stack` guidance exists only for `react-native`
366
313
 
367
- ### Step 2: Generate Design System (REQUIRED)
314
+ ### Step 2: Generate Design System
368
315
 
369
- **Always start with `--design-system`** to get comprehensive recommendations with reasoning:
316
+ Start with `--design-system` when choosing a whole direction (style, palette, type) for a new product or page; for a single lookup go straight to Step 3:
370
317
 
371
318
  ```bash
372
- python3 skills/ui-ux-pro-max/scripts/search.py "<product_type> <industry> <keywords>" --design-system [-p "Project Name"]
319
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "<product_type> <industry> <keywords>" --design-system [-p "Project Name"]
373
320
  ```
374
321
 
375
322
  This command:
@@ -380,7 +327,7 @@ This command:
380
327
 
381
328
  **Example:**
382
329
  ```bash
383
- python3 skills/ui-ux-pro-max/scripts/search.py "beauty spa wellness service" --design-system -p "Serenity Spa"
330
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "beauty spa wellness service" --design-system -p "Serenity Spa"
384
331
  ```
385
332
 
386
333
  ### Step 2b: Persist Design System (Master + Overrides Pattern)
@@ -388,7 +335,7 @@ python3 skills/ui-ux-pro-max/scripts/search.py "beauty spa wellness service" --d
388
335
  To save the design system for **hierarchical retrieval across sessions**, add `--persist`:
389
336
 
390
337
  ```bash
391
- python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name"
338
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name"
392
339
  ```
393
340
 
394
341
  This creates:
@@ -397,7 +344,7 @@ This creates:
397
344
 
398
345
  **With page-specific override:**
399
346
  ```bash
400
- python3 skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name" --page "dashboard"
347
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "<query>" --design-system --persist -p "Project Name" --page "dashboard"
401
348
  ```
402
349
 
403
350
  This also creates:
@@ -422,7 +369,7 @@ Now, generate the code...
422
369
  After getting the design system, use domain searches to get additional details:
423
370
 
424
371
  ```bash
425
- python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --domain <domain> [-n <max_results>]
372
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "<keyword>" --domain <domain> [-n <max_results>]
426
373
  ```
427
374
 
428
375
  **When to use detailed searches:**
@@ -440,14 +387,13 @@ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --domain <domain> [-n
440
387
  | Landing structure | `landing` | `--domain landing "hero social-proof"` |
441
388
  | React Native perf | `react` | `--domain react "rerender memo list"` |
442
389
  | App interface a11y | `web` | `--domain web "accessibilityLabel touch safe-areas"` |
443
- | AI prompt / CSS keywords | `prompt` | `--domain prompt "minimalism"` |
444
390
 
445
- ### Step 4: Stack Guidelines (React Native)
391
+ ### Step 4: Stack Guidelines (React Native projects only)
446
392
 
447
- Get React Native implementation-specific best practices:
393
+ For a React Native project, get implementation-specific best practices:
448
394
 
449
395
  ```bash
450
- python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
396
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
451
397
  ```
452
398
 
453
399
  ---
@@ -468,7 +414,6 @@ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
468
414
  | `google-fonts` | Individual Google Fonts lookup | sans serif, monospace, japanese, variable font, popular |
469
415
  | `react` | React/Next.js performance | waterfall, bundle, suspense, memo, rerender, cache |
470
416
  | `web` | App interface guidelines (iOS/Android/React Native) | accessibilityLabel, touch targets, safe areas, Dynamic Type |
471
- | `prompt` | AI prompts, CSS keywords | (style name) |
472
417
 
473
418
  ### Available Stacks
474
419
 
@@ -488,10 +433,10 @@ python3 skills/ui-ux-pro-max/scripts/search.py "<keyword>" --stack react-native
488
433
  - Style keywords: modern, minimal, content-first, dark mode
489
434
  - Stack: React Native
490
435
 
491
- ### Step 2: Generate Design System (REQUIRED)
436
+ ### Step 2: Generate Design System
492
437
 
493
438
  ```bash
494
- python3 skills/ui-ux-pro-max/scripts/search.py "AI search tool modern minimal" --design-system -p "AI Search"
439
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "AI search tool modern minimal" --design-system -p "AI Search"
495
440
  ```
496
441
 
497
442
  **Output:** Complete design system with pattern, style, colors, typography, effects, and anti-patterns.
@@ -500,16 +445,16 @@ python3 skills/ui-ux-pro-max/scripts/search.py "AI search tool modern minimal" -
500
445
 
501
446
  ```bash
502
447
  # Get style options for a modern tool product
503
- python3 skills/ui-ux-pro-max/scripts/search.py "minimalism dark mode" --domain style
448
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "minimalism dark mode" --domain style
504
449
 
505
450
  # Get UX best practices for search interaction and loading
506
- python3 skills/ui-ux-pro-max/scripts/search.py "search loading animation" --domain ux
451
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "search loading animation" --domain ux
507
452
  ```
508
453
 
509
454
  ### Step 4: Stack Guidelines
510
455
 
511
456
  ```bash
512
- python3 skills/ui-ux-pro-max/scripts/search.py "list performance navigation" --stack react-native
457
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "list performance navigation" --stack react-native
513
458
  ```
514
459
 
515
460
  **Then:** Synthesize design system + detailed searches and implement the design.
@@ -522,10 +467,10 @@ The `--design-system` flag supports two output formats:
522
467
 
523
468
  ```bash
524
469
  # ASCII box (default) - best for terminal display
525
- python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system
470
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system
526
471
 
527
472
  # Markdown - best for documentation
528
- python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system -f markdown
473
+ python3 .claude/skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system -f markdown
529
474
  ```
530
475
 
531
476
  ---
@@ -537,7 +482,7 @@ python3 skills/ui-ux-pro-max/scripts/search.py "fintech crypto" --design-system
537
482
  - Use **multi-dimensional keywords** — combine product + industry + tone + density: `"entertainment social vibrant content-dense"` not just `"app"`
538
483
  - Try different keywords for the same need: `"playful neon"` → `"vibrant dark"` → `"content-first minimal"`
539
484
  - Use `--design-system` first for full recommendations, then `--domain` to deep-dive any dimension you're unsure about
540
- - Always add `--stack react-native` for implementation-specific guidance
485
+ - Add `--stack react-native` only when the target project is React Native
541
486
 
542
487
  ### Common Sticking Points
543
488
 
@@ -26,15 +26,9 @@ npx @axe-core/cli https://example.com # Accessibility
26
26
  npx lighthouse https://example.com # Performance
27
27
  ```
28
28
 
29
- ## Testing Strategy (Choose Your Model)
29
+ ## Testing Strategy
30
30
 
31
- | Model | Structure | Best For |
32
- |-------|-----------|----------|
33
- | Pyramid | Unit 70% > Integration 20% > E2E 10% | Monoliths |
34
- | Trophy | Integration-heavy | Modern SPAs |
35
- | Honeycomb | Contract-centric | Microservices |
36
-
37
- → `./references/testing-pyramid-strategy.md`
31
+ Choosing between pyramid, trophy, and honeycomb: `./references/testing-pyramid-strategy.md`
38
32
 
39
33
  ## Reference Documentation
40
34
 
@@ -88,15 +82,3 @@ node ./scripts/analyze-test-results.js \
88
82
  --output markdown
89
83
  ```
90
84
  Parses Playwright/Vitest/JUnit results into unified summary.
91
-
92
- ## CI/CD Integration
93
-
94
- ```yaml
95
- jobs:
96
- test:
97
- steps:
98
- - run: npm run test:unit # Gate 1: Fast fail
99
- - run: npm run test:e2e # Gate 2: After unit pass
100
- - run: npm run test:a11y # Accessibility
101
- - run: npx lhci autorun # Performance
102
- ```
@@ -1,5 +1,9 @@
1
1
  ## Codex runtime
2
2
 
3
+ Project notes (commands, files to leave unchanged, slow or expensive operations)
4
+ belong in the root AGENTS.md after the CAFEKIT CORE END marker; Codex reads
5
+ AGENTS.md directly.
6
+
3
7
  - Repository instructions live in `AGENTS.md`.
4
8
  - CafeKit skills live in `.agents/skills/`; invoke them as `$cf-<name>` or browse with `/skills`. Edit skills in the project, not in a global skills directory.
5
9
  - Run Python skill scripts with the project venv:
@@ -7,6 +11,10 @@
7
11
  - Windows: `.agents\\skills\\.venv\\Scripts\\python.exe scripts\\<script>.py`
8
12
  - CafeKit agents live in `.codex/agents/*.toml` and are auto-discovered after the repository is trusted.
9
13
  - Runtime support lives in `.codex/rules/`, `.codex/scripts/`, `.codex/references/`, and `.codex/runtime.json`.
14
+ - Read `.codex/rules/workflow.md` before planning or implementing changes.
15
+ - Follow `.codex/rules/ai-dev-rules.md` while writing or reviewing code.
16
+ - Consult `.codex/rules/orchestrator.md` when delegating work or seeking specialist counsel.
17
+ - Read `.codex/rules/manage-docs.md` when updating project documentation.
10
18
  - For skill selection, read `.codex/rules/skill-workflow-routing.md` and
11
19
  `.codex/rules/skill-domain-routing.md`. When capability presence is uncertain,
12
20
  run `node .codex/scripts/generate-skill-catalog.cjs --skills`; its Codex-bound
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const crypto = require('node:crypto');
5
+ const fs = require('node:fs');
6
+ const os = require('node:os');
7
+ const path = require('node:path');
8
+ const { atomicWrite, getHookContext, logCrash, readPayload } = require('./lib/hook-context.cjs');
9
+
10
+ const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex');
11
+
12
+ try {
13
+ const data = readPayload();
14
+ if (!['UserPromptSubmit', 'PreToolUse'].includes(data.hook_event_name)) process.exit(0);
15
+ if (typeof data.session_id !== 'string' || !data.session_id.trim()) {
16
+ throw new Error('missing session ID');
17
+ }
18
+ const { projectRoot } = getHookContext(data);
19
+ const sessionHash = sha256(data.session_id);
20
+ const root = process.env.CAFEKIT_ASK_GUARD_DIR
21
+ || path.join(os.tmpdir(), 'cafekit-ask-guard', sha256(projectRoot));
22
+ const directory = path.join(path.resolve(root), sessionHash);
23
+ const flag = path.join(directory, 'state.json');
24
+
25
+ if (data.hook_event_name === 'UserPromptSubmit') {
26
+ const active = /^(\$cf-ask|\/cf:ask)(?=\s|$)/.test(String(data.prompt || '').trim());
27
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
28
+ atomicWrite(flag, `${JSON.stringify({ active })}\n`);
29
+ process.exit(0);
30
+ }
31
+ // The live probe exposed this native edit separately from its enclosing exec.
32
+ // Shell commands and child sessions are outside this guard's scope.
33
+ if (data.tool_name !== 'apply_patch') process.exit(0);
34
+ let state;
35
+ try {
36
+ state = JSON.parse(fs.readFileSync(flag, 'utf8'));
37
+ } catch (error) {
38
+ if (error.code === 'ENOENT') process.exit(0);
39
+ throw error;
40
+ }
41
+ if (typeof state?.active !== 'boolean') throw new Error('invalid session flag');
42
+ if (!state.active) process.exit(0);
43
+
44
+ fs.appendFileSync(path.join(directory, 'denials.jsonl'), `${JSON.stringify({
45
+ timestamp: new Date().toISOString(),
46
+ session_id_sha256: sessionHash,
47
+ tool_name: 'apply_patch'
48
+ })}\n`, { mode: 0o600 });
49
+ process.stderr.write('This ask session answers only. Run $cf-fix to change files.\n');
50
+ process.exit(2);
51
+ } catch {
52
+ // Do not log exception text: malformed payloads can contain private input.
53
+ logCrash('ask-guard', new Error('Ask guard could not read or persist session state; allowing the call.'));
54
+ }
@@ -2,13 +2,14 @@
2
2
  'use strict';
3
3
 
4
4
  const {
5
- getHookContext,
5
+ PROJECT_ROOT,
6
6
  logCrash,
7
- readPayload
7
+ readPayload,
8
+ readRuntime,
9
+ resolveSessionCwd
8
10
  } = require('./lib/hook-context.cjs');
9
- const { BLOCKED_DIRS, inspectInput } = require('./lib/inspect-paths.cjs');
10
11
 
11
- function denyPath(requested, blocked) {
12
+ function denyPath(requested, blocked, BLOCKED_DIRS) {
12
13
  process.stderr.write(
13
14
  `SCOPE LIMIT EXCEEDED: Directory "${blocked}/" is explicitly forbidden\n`
14
15
  + `Requested Path: ${requested}\n`
@@ -18,12 +19,15 @@ function denyPath(requested, blocked) {
18
19
  }
19
20
 
20
21
  try {
22
+ const { BLOCKED_DIRS, inspectInput } = require('./lib/inspect-paths.cjs');
21
23
  const payload = readPayload();
22
24
  if (!payload) process.exit(0);
23
- const { runtime } = getHookContext(payload);
25
+ const projectRoot = PROJECT_ROOT;
26
+ const runtime = readRuntime(PROJECT_ROOT);
27
+ const sessionCwd = resolveSessionCwd(payload);
24
28
  if (runtime.scout?.enabled === false || runtime.inspect?.enabled === false) process.exit(0);
25
29
 
26
- const result = inspectInput(payload.tool_input || {});
30
+ const result = inspectInput(payload.tool_name || '', payload.tool_input || {}, { cwd: sessionCwd, projectRoot });
27
31
  if (result.broadGlob) {
28
32
  process.stderr.write(
29
33
  `SCOPE LIMIT EXCEEDED: Glob pattern is excessively broad\n`
@@ -33,7 +37,7 @@ try {
33
37
  process.exit(2);
34
38
  }
35
39
  if (result.blockedPath) {
36
- denyPath(result.blockedPath.requested, result.blockedPath.blocked);
40
+ denyPath(result.blockedPath.requested, result.blockedPath.blocked, BLOCKED_DIRS);
37
41
  }
38
42
  } catch (error) {
39
43
  logCrash('inspect-block', error);
@@ -1,199 +1 @@
1
- 'use strict';
2
-
3
- const BLOCKED_DIRS = new Set([
4
- 'node_modules', 'dist', 'build', '.next', '.nuxt', '.output',
5
- '__pycache__', '.venv', 'venv', 'vendor', 'target',
6
- '.git', 'coverage', '.nyc_output'
7
- ]);
8
- const BROAD_GLOBS = [/^\*\*\/\*$/, /^\*\*\.\w+$/, /^\*\*\/\*\.\w+$/];
9
- const PATH_KEYS = new RegExp(
10
- '^(?:file_?paths?|paths?|search_?paths?|'
11
- + '(?:source|target|destination)_?paths?|dirs?|director(?:y|ies)|'
12
- + 'folders?|cwd|root|locations?|uris?)$',
13
- 'i'
14
- );
15
- const GLOB_KEYS = /(?:^|_)(?:glob|globs|pattern|patterns)$/i;
16
- function clean(value) {
17
- return String(value || '').trim().replace(/^['"`]+|['"`,:]+$/g, '');
18
- }
19
- function blockedSegment(value) {
20
- return clean(value)
21
- .replace(/\\/g, '/')
22
- .split('/')
23
- .find((segment) => BLOCKED_DIRS.has(segment));
24
- }
25
- function isBroadGlob(value) {
26
- const candidate = clean(value);
27
- return BROAD_GLOBS.some((rule) => rule.test(candidate));
28
- }
29
- function collectStructured(value, key, paths, globs) {
30
- if (typeof value === 'string') {
31
- if (PATH_KEYS.test(key)) paths.push(value);
32
- if (GLOB_KEYS.test(key)) globs.push(value);
33
- return;
34
- }
35
- if (Array.isArray(value)) {
36
- if (PATH_KEYS.test(key)) paths.push(...value.filter((item) => typeof item === 'string'));
37
- if (GLOB_KEYS.test(key)) globs.push(...value.filter((item) => typeof item === 'string'));
38
- for (const item of value) collectStructured(item, '', paths, globs);
39
- return;
40
- }
41
- if (!value || typeof value !== 'object') return;
42
- for (const [childKey, child] of Object.entries(value)) {
43
- collectStructured(child, childKey, paths, globs);
44
- }
45
- }
46
- function shellTokens(command) {
47
- const tokens = [];
48
- let token = '';
49
- let quote = '';
50
- for (let index = 0; index < command.length; index += 1) {
51
- const char = command[index];
52
- if (quote) {
53
- if (char === quote) quote = '';
54
- else if (char === '\\' && quote === '"' && index + 1 < command.length) {
55
- token += command[index += 1];
56
- } else token += char;
57
- continue;
58
- }
59
- if (char === '"' || char === "'") {
60
- quote = char;
61
- } else if (char === '\n') {
62
- if (token) tokens.push(token);
63
- token = '';
64
- tokens.push('|');
65
- } else if (/\s/.test(char)) {
66
- if (token) tokens.push(token);
67
- token = '';
68
- } else if (';&|'.includes(char)) {
69
- if (token) tokens.push(token);
70
- token = '';
71
- const pair = command.slice(index, index + 2);
72
- if (pair === '&&' || pair === '||') index += 1;
73
- tokens.push('|');
74
- } else {
75
- token += char;
76
- }
77
- }
78
- if (token) tokens.push(token);
79
- return tokens;
80
- }
81
- function commandGroups(command) {
82
- const groups = [[]];
83
- for (const token of shellTokens(command)) {
84
- if (token === '|') groups.push([]);
85
- else groups[groups.length - 1].push(clean(token));
86
- }
87
- return groups.filter((group) => group.length);
88
- }
89
-
90
- function positional(tokens, optionsWithValue = new Set()) {
91
- const out = [];
92
- for (let index = 1; index < tokens.length; index += 1) {
93
- const token = tokens[index];
94
- if (optionsWithValue.has(token)) index += 1;
95
- else if (!token.startsWith('-') || token === '-') out.push(token);
96
- }
97
- return out;
98
- }
99
-
100
- function readerOptionPaths(name, tokens) {
101
- if (!['rg', 'grep', 'sed'].includes(name)) return [];
102
- const paths = [];
103
- for (let index = 1; index < tokens.length; index += 1) {
104
- const token = tokens[index];
105
- if (token === '-f' || token === '--file') {
106
- if (tokens[index + 1]) paths.push(tokens[index + 1]);
107
- index += 1;
108
- } else if (token.startsWith('--file=')) {
109
- paths.push(token.slice('--file='.length));
110
- }
111
- }
112
- return paths;
113
- }
114
-
115
- function findRoots(tokens) {
116
- const roots = [];
117
- let index = 1;
118
- while (['-H', '-L', '-P'].includes(tokens[index]) || /^-O\d+$/.test(tokens[index] || '')) {
119
- index += 1;
120
- }
121
- if (tokens[index] === '-D') index += 2;
122
- if (tokens[index] === '--') index += 1;
123
- for (; index < tokens.length; index += 1) {
124
- const token = tokens[index];
125
- if (token.startsWith('-') || ['!', '(', ')'].includes(token)) break;
126
- roots.push(token);
127
- }
128
- return roots;
129
- }
130
-
131
- function commandPaths(group, globs) {
132
- const commandIndex = group.findIndex((token) => (
133
- token && !/^[A-Za-z_][A-Za-z0-9_]*=/.test(token)
134
- ));
135
- if (commandIndex < 0) return [];
136
- const tokens = group.slice(commandIndex);
137
- while (['sudo', 'env', 'time', 'command'].includes(tokens[0])) tokens.shift();
138
- if (!tokens.length) return [];
139
- const name = tokens[0].replace(/\\/g, '/').split('/').pop();
140
- const optionPaths = readerOptionPaths(name, tokens);
141
-
142
- for (let index = 1; index < tokens.length; index += 1) {
143
- const token = tokens[index];
144
- if (token === '-g' || token === '--glob' || token === '--iglob') {
145
- if (tokens[index + 1]) globs.push(tokens[index + 1]);
146
- } else if (/^--(?:i?glob)=/.test(token)) {
147
- globs.push(token.slice(token.indexOf('=') + 1));
148
- }
149
- }
150
-
151
- if (name === 'rg' || name === 'grep') {
152
- const values = positional(tokens, new Set([
153
- '-e', '--regexp', '-f', '--file', '-g', '--glob', '--iglob',
154
- '-t', '--type', '-T', '--type-not'
155
- ]));
156
- const explicitPattern = tokens.some((token) => token === '-e' || token === '--regexp');
157
- const fileMode = tokens.includes('--files');
158
- return [...optionPaths, ...(explicitPattern || fileMode ? values : values.slice(1))];
159
- }
160
- if (name === 'sed') {
161
- const values = positional(tokens, new Set(['-e', '--expression', '-f', '--file']));
162
- const explicitScript = tokens.some((token) => (
163
- ['-e', '--expression', '-f', '--file'].includes(token)
164
- ));
165
- return [...optionPaths, ...(explicitScript ? values : values.slice(1))];
166
- }
167
- if (name === 'find') return findRoots(tokens);
168
- if (['cat', 'head', 'tail', 'ls', 'wc', 'du', 'tree', 'file', 'stat', 'cd', 'pushd', 'source', '.'].includes(name)) {
169
- return positional(tokens, new Set(['-n', '--lines', '-c', '--bytes']));
170
- }
171
- return tokens.filter((token) => (
172
- /^(?:\.{0,2}[\\/]|~[\\/])/.test(token)
173
- || (token.includes('/') && blockedSegment(token))
174
- ));
175
- }
176
-
177
- function inspectInput(input) {
178
- const paths = [];
179
- const globs = [];
180
- collectStructured(input, '', paths, globs);
181
- const command = typeof input?.command === 'string'
182
- ? input.command
183
- : typeof input?.cmd === 'string' ? input.cmd : '';
184
- for (const group of commandGroups(command)) {
185
- paths.push(...commandPaths(group, globs));
186
- }
187
- return {
188
- broadGlob: globs.find(isBroadGlob),
189
- blockedPath: paths.map((requested) => ({
190
- requested,
191
- blocked: blockedSegment(requested)
192
- })).find((result) => result.blocked)
193
- };
194
- }
195
-
196
- module.exports = {
197
- BLOCKED_DIRS,
198
- inspectInput
199
- };
1
+ module.exports = require('../../../claude/hooks/lib/inspect-paths.cjs');
@@ -0,0 +1 @@
1
+ module.exports = require('../../../claude/hooks/lib/privacy-paths.cjs');