@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.
- package/README.md +12 -1
- package/bin/__tests__/claude-settings.test.js +123 -0
- package/bin/__tests__/codex-ask-guard.test.js +123 -0
- package/bin/__tests__/codex-ask-projection.test.js +51 -0
- package/bin/__tests__/codex-hooks-ownership.test.js +80 -1
- package/bin/__tests__/codex-hooks.test.js +938 -237
- package/bin/__tests__/codex-native-hook-boundaries.test.js +136 -0
- package/bin/__tests__/codex-native.test.js +222 -149
- package/bin/__tests__/codex-projection-parity.test.js +314 -0
- package/bin/__tests__/codex-quiet-hooks.test.js +170 -0
- package/bin/__tests__/codex-research-projection.test.js +70 -0
- package/bin/__tests__/codex-specs-projection.test.js +76 -0
- package/bin/__tests__/develop-contract.test.js +102 -1362
- package/bin/__tests__/docs-sync-on-demand.test.js +25 -20
- package/bin/__tests__/inspect-paths.test.js +183 -0
- package/bin/__tests__/installer-safety.test.js +335 -0
- package/bin/__tests__/legacy-authority-decoupled.test.js +14 -19
- package/bin/__tests__/legacy-hooks-retired.test.js +18 -8
- package/bin/__tests__/omp-bridge.test.js +66 -12
- package/bin/__tests__/omp-hooks.test.js +11 -5
- package/bin/__tests__/orca-session.test.js +7 -0
- package/bin/__tests__/package-inventory.test.js +1 -395
- package/bin/__tests__/privacy-paths.test.js +317 -0
- package/bin/__tests__/spec-narrowing.test.js +30 -134
- package/bin/__tests__/specs-v2-execution-closeout.test.js +0 -372
- package/bin/__tests__/test-runtime-dependency-closure.cjs +1 -2
- package/bin/__tests__/usage-hook-retired.test.js +5 -3
- package/bin/__tests__/validator-grounding.test.js +17 -2929
- package/bin/install.js +25 -0
- package/bin/lib/codex-install.js +134 -12
- package/bin/lib/context.js +1 -1
- package/bin/lib/managed-writer.js +2 -3
- package/bin/phases/claude-runtime.js +91 -25
- package/bin/phases/claude-settings.js +22 -1
- package/bin/phases/codex-hooks.js +96 -33
- package/bin/phases/codex-runtime.js +45 -49
- package/bin/phases/copy-payload.js +11 -28
- package/bin/phases/omp-runtime.js +6 -3
- package/package.json +2 -3
- package/src/claude/CLAUDE.md +4 -0
- package/src/claude/agents/code-auditor.md +9 -6
- package/src/claude/agents/debugger.md +3 -9
- package/src/claude/agents/docs-keeper.md +4 -7
- package/src/claude/agents/git-ops.md +2 -4
- package/src/claude/agents/implementer.md +6 -7
- package/src/claude/agents/inspector.md +2 -0
- package/src/claude/agents/project-manager.md +2 -2
- package/src/claude/agents/spec-maker.md +4 -4
- package/src/claude/agents/test-runner.md +8 -11
- package/src/claude/agents/ui-ux-designer.md +0 -1
- package/src/claude/gitignore +3 -0
- package/src/claude/hooks/__tests__/installed-root.test.js +111 -0
- package/src/claude/hooks/__tests__/precompact.test.js +206 -10
- package/src/claude/hooks/__tests__/privacy-block.test.js +27 -0
- package/src/claude/hooks/__tests__/session-writeenv.test.js +25 -0
- package/src/claude/hooks/__tests__/spec-gate.test.js +311 -340
- package/src/claude/hooks/__tests__/spec-state-touched.test.js +230 -8
- package/src/claude/hooks/__tests__/state.test.js +207 -7
- package/src/claude/hooks/__tests__/update-check.test.js +88 -0
- package/src/claude/hooks/agent.cjs +7 -6
- package/src/claude/hooks/inspect-block.cjs +15 -63
- package/src/claude/hooks/lib/inspect-paths.cjs +304 -0
- package/src/claude/hooks/lib/parser.cjs +1 -1
- package/src/claude/hooks/lib/privacy-command-analysis.cjs +191 -17
- package/src/claude/hooks/lib/privacy-paths.cjs +313 -0
- package/src/claude/hooks/lib/project-root.cjs +15 -0
- package/src/claude/hooks/lib/rules-reservation.cjs +36 -0
- package/src/claude/hooks/lib/spec-touch.cjs +67 -0
- package/src/claude/hooks/lib/update-check.cjs +77 -0
- package/src/claude/hooks/precompact.cjs +8 -15
- package/src/claude/hooks/privacy-block.cjs +23 -205
- package/src/claude/hooks/rules.cjs +6 -28
- package/src/claude/hooks/session.cjs +34 -117
- package/src/claude/hooks/spec-gate.cjs +17 -89
- package/src/claude/hooks/spec-state.cjs +89 -96
- package/src/claude/hooks/state.cjs +96 -51
- package/src/claude/migration-manifest.json +20 -8
- package/src/claude/output-styles/coding-level-0-eli5.md +9 -9
- package/src/claude/output-styles/coding-level-1-junior.md +3 -3
- package/src/claude/output-styles/coding-level-2-mid.md +3 -3
- package/src/claude/output-styles/coding-level-3-senior.md +2 -2
- package/src/claude/output-styles/coding-level-4-lead.md +5 -5
- package/src/claude/output-styles/coding-level-5-god.md +6 -6
- package/src/claude/rules/ai-dev-rules.md +1 -2
- package/src/claude/rules/hook-protocols.md +1 -1
- package/src/claude/rules/workflow.md +1 -1
- package/src/claude/runtime.json +0 -3
- package/src/claude/scripts/generate-skill-catalog.cjs +2 -2
- package/src/claude/scripts/provenance.cjs +14 -0
- package/src/claude/scripts/spec-receipt.cjs +0 -114
- package/src/claude/scripts/spec-resolver.cjs +41 -457
- package/src/claude/scripts/workflow-policy.cjs +3 -1801
- package/src/claude/settings/settings.json +1 -1
- package/src/claude/skills/agent-browser/SKILL.md +1 -1
- package/src/claude/skills/ai-multimodal/scripts/check_setup.py +8 -68
- package/src/claude/skills/ai-multimodal/scripts/gemini_batch_process.py +6 -28
- package/src/claude/skills/chrome-devtools/SKILL.md +14 -31
- package/src/claude/skills/code-review/SKILL.md +25 -108
- package/src/claude/skills/code-review/references/spec-compliance-review.md +4 -7
- package/src/claude/skills/develop/SKILL.md +22 -70
- package/src/claude/skills/develop/references/subagent-patterns.md +0 -6
- package/src/claude/skills/git/SKILL.md +1 -1
- package/src/claude/skills/git/references/worktree-blueprint.md +1 -1
- package/src/claude/skills/research/SKILL.md +24 -55
- package/src/claude/skills/sync/SKILL.md +12 -34
- package/src/claude/skills/sync/references/rebind-and-audit.md +2 -2
- package/src/claude/skills/test/SKILL.md +39 -123
- package/src/claude/skills/test/references/execution-strategy.md +11 -22
- package/src/claude/skills/ui-ux/SKILL.md +1 -1
- package/src/claude/skills/ui-ux-pro-max/SKILL.md +24 -79
- package/src/claude/skills/web-testing/SKILL.md +2 -20
- package/src/codex/AGENTS.md +8 -0
- package/src/codex/hooks/ask-guard.cjs +54 -0
- package/src/codex/hooks/inspect-block.cjs +11 -7
- package/src/codex/hooks/lib/inspect-paths.cjs +1 -199
- package/src/codex/hooks/lib/privacy-paths.cjs +1 -0
- package/src/codex/hooks/lib/privacy-state.cjs +98 -16
- package/src/codex/hooks/lib/rules-reservation.cjs +38 -0
- package/src/codex/hooks/lib/secret-keywords.cjs +1 -0
- package/src/codex/hooks/lib/spec-receipt.cjs +2 -30
- package/src/codex/hooks/lib/spec-session-touch.cjs +100 -0
- package/src/codex/hooks/lib/spec-touch.cjs +3 -0
- package/src/codex/hooks/lib/spec-utils.cjs +6 -45
- package/src/codex/hooks/lib/update-check.cjs +1 -0
- package/src/codex/hooks/precompact.cjs +39 -0
- package/src/codex/hooks/privacy-approval.cjs +28 -17
- package/src/codex/hooks/privacy-block.cjs +9 -215
- package/src/codex/hooks/rules.cjs +4 -30
- package/src/codex/hooks/secret-output-guardrail.cjs +1 -1
- package/src/codex/hooks/session.cjs +47 -11
- package/src/codex/hooks/spec-gate.cjs +32 -74
- package/src/codex/hooks/spec-state.cjs +68 -46
- package/src/codex/hooks/state.cjs +25 -4
- package/src/codex/hooks.json +39 -7
- package/src/codex/rules/hook-protocols.md +13 -6
- package/src/common/AGENTS.md +4 -10
- package/src/omp/extensions/cafekit-bridge.mjs +12 -4
- package/src/omp/hooks/privacy-block.cjs +24 -206
- package/bin/__tests__/change-firewall.semantic-firewall.test.js +0 -2133
- package/bin/__tests__/finalizer-pass-gate.semantic-firewall.test.js +0 -342
- package/bin/__tests__/release-preflight.semantic-firewall.test.js +0 -586
- package/bin/__tests__/review-receipt-c2.semantic-firewall.test.js +0 -378
- package/bin/__tests__/specs-v2-policy-and-scaffold.test.js +0 -665
- package/bin/__tests__/specs-v2-validator-grounder-contract.test.js +0 -1132
- package/src/claude/hooks/lib/context.cjs +0 -527
- package/src/claude/hooks/lib/detect.cjs +0 -474
- package/src/claude/scripts/change-firewall.cjs +0 -1748
- package/src/claude/scripts/spec-authoring-digest.cjs +0 -151
- package/src/claude/scripts/spec-authoring-validation.cjs +0 -126
- package/src/claude/scripts/spec-final-state.cjs +0 -290
- package/src/claude/scripts/spec-ground.cjs +0 -650
- package/src/claude/scripts/spec-readiness.cjs +0 -425
- package/src/claude/scripts/spec-scaffold.cjs +0 -2317
- package/src/claude/scripts/spec-semantic-model.cjs +0 -396
- package/src/claude/scripts/validate-spec-output.cjs +0 -3914
- package/src/claude/skills/code-review/references/verification-gate.md +0 -41
- package/src/claude/skills/specs/templates/design.md +0 -82
- package/src/claude/skills/specs/templates/requirements-init.md +0 -8
- package/src/claude/skills/specs/templates/requirements.md +0 -42
- package/src/claude/skills/specs/templates/spec-state.json +0 -56
- package/src/claude/skills/specs/templates/task.md +0 -47
- 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
|
-
###
|
|
23
|
+
### Packets the runtime no longer reads
|
|
24
24
|
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
-
|
|
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 |
|
|
31
|
+
| Flat state | Old planning state without `plan.md` | Result |
|
|
37
32
|
|---|---|---|
|
|
38
|
-
| valid |
|
|
39
|
-
|
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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**:
|
|
312
|
+
- **Stack**: the target project's stack; `--stack` guidance exists only for `react-native`
|
|
366
313
|
|
|
367
|
-
### Step 2: Generate Design System
|
|
314
|
+
### Step 2: Generate Design System
|
|
368
315
|
|
|
369
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
-
|
|
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
|
|
29
|
+
## Testing Strategy
|
|
30
30
|
|
|
31
|
-
|
|
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
|
-
```
|
package/src/codex/AGENTS.md
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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');
|