cue-ai 0.9.0 → 0.9.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/CHANGELOG.md +40 -0
- package/README.md +82 -33
- package/bin/cue-review-progress +107 -0
- package/bin/cue-review-watch +98 -0
- package/dist/cue.js +7352 -3744
- package/package.json +16 -5
- package/profiles/_types.ts +9 -0
- package/profiles/backend/profile.yaml +2 -0
- package/profiles/blog-writer/profile.yaml +10 -0
- package/profiles/browser/profile.yaml +9 -2
- package/profiles/builder/profile.yaml +3 -6
- package/profiles/career/profile.yaml +13 -2
- package/profiles/claude-api/profile.yaml +1 -1
- package/profiles/commerce/profile.yaml +27 -3
- package/profiles/core/logo.png +0 -0
- package/profiles/core/profile.yaml +62 -2
- package/profiles/dash-merge-test/profile.yaml +109 -0
- package/profiles/designer/profile.yaml +2 -0
- package/profiles/designer-medusa-next/profile.yaml +4 -1
- package/profiles/designer-medusa-vite/profile.yaml +4 -1
- package/profiles/docs-writer/profile.yaml +3 -1
- package/profiles/eu-tender-research/README.md +48 -0
- package/profiles/eu-tender-research/logo.png +0 -0
- package/profiles/eu-tender-research/profile.yaml +108 -0
- package/profiles/finance/logo.png +0 -0
- package/profiles/finance/profile.yaml +46 -0
- package/profiles/frontend/profile.yaml +5 -9
- package/profiles/growth/profile.yaml +2 -3
- package/profiles/gstack/profile.yaml +15 -0
- package/profiles/higgsfield/profile.yaml +3 -0
- package/profiles/hyperframes/logo.png +0 -0
- package/profiles/hyperframes/profile.yaml +59 -0
- package/profiles/improver/profile.yaml +88 -0
- package/profiles/marketing/profile.yaml +0 -3
- package/profiles/medusa-dev/profile.yaml +2 -0
- package/profiles/medusa-next/profile.yaml +2 -3
- package/profiles/medusa-vite/profile.yaml +2 -3
- package/profiles/n8n/logo.png +0 -0
- package/profiles/n8n/profile.yaml +50 -0
- package/profiles/nextjs/profile.yaml +2 -3
- package/profiles/ops/profile.yaml +2 -0
- package/profiles/postizz/profile.yaml +13 -3
- package/profiles/python/profile.yaml +3 -0
- package/profiles/research/profile.yaml +3 -1
- package/profiles/schema.json +10 -0
- package/profiles/secops/profile.yaml +2 -0
- package/profiles/seo/profile.yaml +56 -0
- package/profiles/skill-writer/profile.yaml +8 -0
- package/profiles/ssh/profile.yaml +32 -0
- package/profiles/strapi/logo.png +0 -0
- package/profiles/strapi/profile.yaml +45 -0
- package/profiles/stripe/logo.png +0 -0
- package/profiles/stripe/profile.yaml +1 -0
- package/profiles/supabase/logo.png +0 -0
- package/profiles/supabase/profile.yaml +85 -0
- package/profiles/vercel/logo.png +0 -0
- package/profiles/vercel/profile.yaml +25 -1
- package/profiles/vite/profile.yaml +4 -3
- package/profiles/web-frontend-base/profile.yaml +5 -4
- package/profiles/webshop/profile.yaml +23 -5
- package/profiles/x-growth-bot/profile.yaml +44 -0
- package/resources/icons/generate-icons.py +128 -2
- package/resources/mcps/configs/claude.sanitized.json +42 -0
- package/resources/mcps/configs/codex.sanitized.json +7 -0
- package/resources/skills/skills/career/resume-version-manager/SKILL.md +351 -0
- package/resources/skills/skills/career/salary-negotiation-prep/SKILL.md +378 -0
- package/resources/skills/skills/content/pdf/SKILL.md +2 -0
- package/resources/skills/skills/content/postiz-cards/SKILL.md +48 -0
- package/resources/skills/skills/content/postiz-cards/scripts/analytics.sh +38 -0
- package/resources/skills/skills/content/postiz-cards/scripts/card.sh +42 -0
- package/resources/skills/skills/content/postiz-cards/scripts/lint.py +38 -0
- package/resources/skills/skills/design/headless-gif-demo/SKILL.md +1 -1
- package/resources/skills/skills/design/readme-svg-design/SKILL.md +1 -1
- package/resources/skills/skills/eu-funding/grant-outreach/SKILL.md +70 -0
- package/resources/skills/skills/eu-funding/hu-grant-finder/SKILL.md +114 -0
- package/resources/skills/skills/eu-funding/hu-grant-finder/evals.md +26 -0
- package/resources/skills/skills/eu-funding/ted-tender-search/SKILL.md +80 -0
- package/resources/skills/skills/eu-funding/ted-tender-search/evals.md +26 -0
- package/resources/skills/skills/eu-funding/ted-tender-search/scripts/ted-search.sh +46 -0
- package/resources/skills/skills/event-design/wedding-invitations/SKILL.md +1 -1
- package/resources/skills/skills/github/gx-agents/SKILL.md +96 -0
- package/resources/skills/skills/gstack/design-shotgun/SKILL.md +1 -1
- package/resources/skills/skills/marketing/ab-test-analyzer/SKILL.md +1 -1
- package/resources/skills/skills/marketing/ab-test-setup-and-analysis/SKILL.md +1 -1
- package/resources/skills/skills/marketing/account-structure-review/SKILL.md +1 -1
- package/resources/skills/skills/marketing/ad-copy-variant-generator/SKILL.md +1 -1
- package/resources/skills/skills/marketing/ad-extension-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/ad-spend-allocator/SKILL.md +1 -1
- package/resources/skills/skills/marketing/anomaly-detection/SKILL.md +1 -1
- package/resources/skills/skills/marketing/attribution-model-comparison/SKILL.md +1 -1
- package/resources/skills/skills/marketing/audience-overlap-analysis/SKILL.md +7 -1
- package/resources/skills/skills/marketing/bid-strategy-recommendations/SKILL.md +7 -1
- package/resources/skills/skills/marketing/budget-scenario-planner/SKILL.md +6 -1
- package/resources/skills/skills/marketing/campaign-naming-convention-builder/SKILL.md +7 -1
- package/resources/skills/skills/marketing/channel-mix-optimizer/SKILL.md +7 -1
- package/resources/skills/skills/marketing/client-report-narratives/SKILL.md +6 -1
- package/resources/skills/skills/marketing/competitor-creative-analysis/SKILL.md +1 -1
- package/resources/skills/skills/marketing/competitor-teardown/SKILL.md +1 -1
- package/resources/skills/skills/marketing/content-repurposer/SKILL.md +1 -1
- package/resources/skills/skills/marketing/conversion-path-analysis/SKILL.md +1 -1
- package/resources/skills/skills/marketing/cpa-diagnostics/SKILL.md +1 -1
- package/resources/skills/skills/marketing/creative-fatigue-detection/SKILL.md +1 -1
- package/resources/skills/skills/marketing/day-hour-performance-breakdown/SKILL.md +1 -1
- package/resources/skills/skills/marketing/device-performance-split/SKILL.md +1 -1
- package/resources/skills/skills/marketing/e2e-seo-assistant/SKILL.md +1 -1
- package/resources/skills/skills/marketing/email-sequence-writer/SKILL.md +1 -1
- package/resources/skills/skills/marketing/frequency-cap-recommendations/SKILL.md +1 -1
- package/resources/skills/skills/marketing/geo-performance-analysis/SKILL.md +1 -1
- package/resources/skills/skills/marketing/google-ads-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/icp-research-assistant/SKILL.md +1 -1
- package/resources/skills/skills/marketing/keyword-cannibalization-check/SKILL.md +1 -1
- package/resources/skills/skills/marketing/landing-page-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/landing-page-audit-quick/SKILL.md +1 -1
- package/resources/skills/skills/marketing/linkedin-ads-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/meta-ads-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/pacing-monitor/SKILL.md +1 -1
- package/resources/skills/skills/marketing/performance-benchmarking/SKILL.md +1 -1
- package/resources/skills/skills/marketing/programmatic-seo-builder/SKILL.md +1 -1
- package/resources/skills/skills/marketing/quality-score-breakdown/SKILL.md +1 -1
- package/resources/skills/skills/marketing/reddit-ads-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/retargeting-window-analysis/SKILL.md +1 -1
- package/resources/skills/skills/marketing/roas-forecasting/SKILL.md +1 -1
- package/resources/skills/skills/marketing/search-term-mining/SKILL.md +1 -1
- package/resources/skills/skills/marketing/utm-tracking-generator/SKILL.md +1 -1
- package/resources/skills/skills/marketing/wasted-spend-finder/SKILL.md +1 -1
- package/resources/skills/skills/marketing/weekly-account-summary/SKILL.md +1 -1
- package/resources/skills/skills/meta/awesome-list-submit/SKILL.md +4 -4
- package/resources/skills/skills/meta/cue-dashboard/SKILL.md +109 -0
- package/resources/skills/skills/meta/cue-developer/SKILL.md +161 -0
- package/resources/skills/skills/meta/cue-developer/evals/evals.json +57 -0
- package/resources/skills/skills/meta/cue-developer/references/architecture.md +65 -0
- package/resources/skills/skills/meta/cue-developer/references/build_and_test.md +72 -0
- package/resources/skills/skills/meta/cue-developer/references/contributing.md +75 -0
- package/resources/skills/skills/meta/cue-developer/references/conventions.md +57 -0
- package/resources/skills/skills/meta/cue-developer/references/first_time_setup.md +51 -0
- package/resources/skills/skills/meta/cue-developer/references/skill_and_mcp_authoring.md +84 -0
- package/resources/skills/skills/meta/cue-developer/references/troubleshooting.md +42 -0
- package/resources/skills/skills/meta/delegation-check/SKILL.md +148 -0
- package/resources/skills/skills/meta/delegation-check/specs/scan-algorithm.md +125 -0
- package/resources/skills/skills/meta/delegation-check/specs/separation-rules.md +190 -0
- package/resources/skills/skills/meta/focus/SKILL.md +62 -0
- package/resources/skills/skills/meta/help/SKILL.md +1 -1
- package/resources/skills/skills/meta/integrity-tags/SKILL.md +2 -0
- package/resources/skills/skills/meta/next-steps/SKILL.md +124 -0
- package/resources/skills/skills/meta/next-steps/evals/eval-set.json +92 -0
- package/resources/skills/skills/meta/profile-from-docs/SKILL.md +141 -0
- package/resources/skills/skills/meta/ralph-loop/SKILL.md +83 -0
- package/resources/skills/skills/meta/ralph-loop/scripts/loop.sh +73 -0
- package/resources/skills/skills/meta/skill-simplify/SKILL.md +136 -0
- package/resources/skills/skills/meta/skill-simplify/phases/01-analysis.md +173 -0
- package/resources/skills/skills/meta/skill-simplify/phases/02-optimize.md +104 -0
- package/resources/skills/skills/meta/skill-simplify/phases/03-check.md +145 -0
- package/resources/skills/skills/meta/smart-loader/scripts/smart-lookup.sh +13 -4
- package/resources/skills/skills/meta/verify-council/SKILL.md +182 -0
- package/resources/skills/skills/meta/verify-council/references/lane-prompts.md +103 -0
- package/resources/skills/skills/meta/verify-council/references/workflow.js +217 -0
- package/resources/skills/skills/nvidia/aiq-research/SKILL.md +1 -1
- package/resources/skills/skills/nvidia/cuopt-developer/SKILL.md +16 -1
- package/resources/skills/skills/nvidia/cuopt-developer/resources/contributing.md +2 -2
- package/resources/skills/skills/nvidia/cuopt-developer/resources/numerical_debugging.md +128 -0
- package/resources/skills/skills/nvidia/cuopt-developer/resources/python_bindings.md +2 -9
- package/resources/skills/skills/nvidia/cuopt-developer/resources/vrp_skills.md +166 -0
- package/resources/skills/skills/nvidia/cuopt-install/SKILL.md +2 -10
- package/resources/skills/skills/nvidia/cuopt-numerical-optimization-api-c/SKILL.md +3 -23
- package/resources/skills/skills/nvidia/cuopt-numerical-optimization-api-c/resources/examples.md +40 -20
- package/resources/skills/skills/nvidia/cuopt-numerical-optimization-api-python/SKILL.md +5 -1
- package/resources/skills/skills/nvidia/skill-evolution/SKILL.md +4 -5
- package/resources/skills/skills/research/trendradar/SKILL.md +1 -1
- package/resources/skills/skills/ssh/ssh-config/SKILL.md +94 -0
- package/resources/skills/skills/ssh/ssh-copy/SKILL.md +92 -0
- package/resources/skills/skills/ssh/ssh-harden/SKILL.md +108 -0
- package/resources/skills/skills/ssh/ssh-keys/SKILL.md +82 -0
- package/resources/skills/skills/ssh/ssh-paste-image/LICENSE +28 -0
- package/resources/skills/skills/ssh/ssh-paste-image/SKILL.md +149 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/build.sh +29 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/client/go.mod +3 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/client/main.go +79 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/ccimgd.service +12 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/com.ccimgd.plist +20 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/go.mod +3 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/main.go +98 -0
- package/resources/skills/skills/ssh/ssh-tunnel/SKILL.md +96 -0
- package/resources/skills/skills/strapi/building-with-strapi/SKILL.md +112 -0
- package/resources/skills/skills/strapi/strapi-cli/SKILL.md +93 -0
- package/resources/skills/skills/strapi/strapi-content-api/SKILL.md +115 -0
- package/resources/skills/skills/strapi/strapi-deploy/SKILL.md +89 -0
- package/resources/skills/skills/strapi/strapi-mcp-setup/SKILL.md +101 -0
- package/resources/skills/skills/strapi/strapi-plugins/SKILL.md +97 -0
- package/resources/skills/skills/tools/context7/SKILL.md +101 -0
- package/resources/skills/skills/tools/opensrc/SKILL.md +1 -1
- package/resources/skills/skills/tools/portless/SKILL.md +186 -0
- package/resources/skills/skills/xbot/operate/SKILL.md +229 -0
- package/src/commands/_index.ts +8 -0
- package/src/commands/ai-score.e2e.test.ts +11 -4
- package/src/commands/ai.ts +3 -4
- package/src/commands/auto-detect.ts +1 -1
- package/src/commands/cli.test.ts +1 -2
- package/src/commands/cli.ts +1 -1
- package/src/commands/cloud.ts +1 -1
- package/src/commands/current.ts +1 -4
- package/src/commands/dash.test.ts +110 -0
- package/src/commands/dash.ts +194 -0
- package/src/commands/dashboard.ts +26 -0
- package/src/commands/diff.ts +1 -1
- package/src/commands/discover.test.ts +1 -1
- package/src/commands/discover.ts +90 -40
- package/src/commands/doctor.test.ts +58 -0
- package/src/commands/doctor.ts +79 -3
- package/src/commands/eval-behavior.ts +1 -1
- package/src/commands/eval.ts +2 -2
- package/src/commands/evolve.ts +4 -3
- package/src/commands/failures.test.ts +1 -1
- package/src/commands/features-batch1.test.ts +6 -1
- package/src/commands/icon.ts +1 -5
- package/src/commands/import-profile.ts +1 -1
- package/src/commands/init.ts +50 -7
- package/src/commands/install-sh.e2e.test.ts +65 -0
- package/src/commands/launch-handoff.e2e.test.ts +88 -0
- package/src/commands/launch.e2e.test.ts +8 -1
- package/src/commands/launch.test.ts +29 -0
- package/src/commands/launch.ts +185 -131
- package/src/commands/lock.ts +0 -1
- package/src/commands/marketplace.ts +0 -4
- package/src/commands/materialize.ts +1 -1
- package/src/commands/mem.ts +341 -0
- package/src/commands/optimizer.ts +0 -3
- package/src/commands/playground.ts +1 -2
- package/src/commands/profile-draft-skill.ts +1 -1
- package/src/commands/replay-whatif.ts +1 -6
- package/src/commands/score.ts +2 -2
- package/src/commands/security.test.ts +88 -0
- package/src/commands/security.ts +74 -28
- package/src/commands/shell.test.ts +65 -4
- package/src/commands/shell.ts +67 -7
- package/src/commands/skills-test.ts +0 -1
- package/src/commands/skills.ts +28 -2
- package/src/commands/sources.ts +1 -2
- package/src/commands/status.ts +2 -6
- package/src/commands/submit-profile.ts +1 -1
- package/src/commands/suggest.ts +35 -10
- package/src/commands/trigger-gaps.test.ts +50 -0
- package/src/commands/trigger-gaps.ts +63 -29
- package/src/commands/update.ts +1 -1
- package/src/commands/validate.ts +16 -4
- package/src/commands/watch-live.ts +1 -1
- package/src/commands/workspace.ts +1 -1
- package/src/index.ts +26 -10
- package/src/lib/active-sessions.ts +1 -1
- package/src/lib/agent-adapters.test.ts +100 -0
- package/src/lib/agent-adapters.ts +2 -2
- package/src/lib/analytics.test.ts +88 -0
- package/src/lib/analytics.ts +82 -1
- package/src/lib/auto-detect.test.ts +10 -4
- package/src/lib/auto-detect.ts +19 -23
- package/src/lib/brand-icons.ts +0 -1
- package/src/lib/cache.ts +2 -3
- package/src/lib/claude-mem-env.test.ts +148 -0
- package/src/lib/claude-mem-env.ts +172 -0
- package/src/lib/combo-history.test.ts +53 -0
- package/src/lib/combo-history.ts +83 -0
- package/src/lib/companion-detect.test.ts +108 -0
- package/src/lib/companion-detect.ts +140 -0
- package/src/lib/companion-fetch.ts +4 -6
- package/src/lib/conditional-skills.test.ts +1 -1
- package/src/lib/config-paths.test.ts +53 -0
- package/src/lib/config-paths.ts +33 -0
- package/src/lib/dashboard-server.test.ts +351 -0
- package/src/lib/dashboard-server.ts +1476 -27
- package/src/lib/debug-log.test.ts +66 -0
- package/src/lib/debug-log.ts +45 -0
- package/src/lib/mcp-catalog.test.ts +102 -0
- package/src/lib/mcp-catalog.ts +193 -0
- package/src/lib/pair-suggestions.test.ts +111 -0
- package/src/lib/pair-suggestions.ts +98 -5
- package/src/lib/permissions.test.ts +76 -0
- package/src/lib/permissions.ts +125 -0
- package/src/lib/picker.test.ts +1106 -1
- package/src/lib/picker.ts +1230 -142
- package/src/lib/plugin-discovery.ts +126 -0
- package/src/lib/pr-poster.ts +1 -1
- package/src/lib/pr-throttle.ts +2 -6
- package/src/lib/profile-linter.test.ts +67 -1
- package/src/lib/profile-linter.ts +59 -14
- package/src/lib/profile-loader.test.ts +21 -0
- package/src/lib/profile-loader.ts +22 -3
- package/src/lib/profile-metrics.ts +2 -6
- package/src/lib/profile-names.test.ts +58 -0
- package/src/lib/repos.test.ts +57 -0
- package/src/lib/repos.ts +167 -0
- package/src/lib/resolver-npx.ts +10 -1
- package/src/lib/runtime-materializer.test.ts +200 -3
- package/src/lib/runtime-materializer.ts +129 -20
- package/src/lib/shared-profiles.ts +2 -3
- package/src/lib/skill-clis.test.ts +113 -0
- package/src/lib/skill-clis.ts +232 -0
- package/src/lib/skill-dependencies.ts +9 -1
- package/src/lib/skill-deps.ts +1 -1
- package/src/lib/skill-linter.ts +1 -1
- package/src/lib/skill-quality.ts +0 -1
- package/src/lib/skill-sandbox.test.ts +1 -1
- package/src/lib/skills-lock.test.ts +1 -1
- package/src/lib/telemetry-consent.ts +3 -5
- package/src/lib/telemetry-report.test.ts +2 -2
- package/src/lib/token-budget.ts +111 -0
- package/src/lib/trigger-gaps.test.ts +70 -0
- package/src/lib/trigger-gaps.ts +48 -6
- package/src/lib/tui/data.ts +1 -5
- package/src/lib/workflow-store.ts +150 -0
- package/src/lib/workspace-secrets.ts +0 -4
- package/src/lib/workspaces.ts +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ssh-paste-image
|
|
3
|
+
description: >-
|
|
4
|
+
Use when the user wants to paste a local clipboard image into Claude Code
|
|
5
|
+
running over SSH, says "paste image over ssh", "can't paste images on the
|
|
6
|
+
remote", "send screenshot to remote claude", or "/paste-image".
|
|
7
|
+
tags: [ssh, clipboard, image, remote, paste]
|
|
8
|
+
category: ssh
|
|
9
|
+
triggers: ["paste image over ssh", "can't paste images on the remote", "/paste-image", "send screenshot to remote claude", "paste clipboard image remote"]
|
|
10
|
+
allowed-tools: Bash(ccimg:*), Bash(go:*), Bash(systemctl:*), Bash(launchctl:*), Bash(scp:*), Read
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# SSH paste-image
|
|
14
|
+
|
|
15
|
+
Claude Code can't paste a clipboard image when you run it over SSH: the clipboard
|
|
16
|
+
lives on your local machine, the agent runs on the remote host. This skill bridges
|
|
17
|
+
the gap. A tiny daemon on your local machine reads the clipboard and serves the
|
|
18
|
+
PNG; a client on the remote pulls it through the SSH connection and writes a temp
|
|
19
|
+
file the agent can `Read`. The daemon and client are vendored under `scripts/`
|
|
20
|
+
(Go source, MIT, from AlexZeitler/claude-ssh-image-skill).
|
|
21
|
+
|
|
22
|
+
## When to activate
|
|
23
|
+
|
|
24
|
+
- The user is in a Claude Code session on a remote SSH host and wants to share an image.
|
|
25
|
+
- The user says "paste image over ssh", "I can't paste a screenshot on the server", "/paste-image", or "send this image to the remote session".
|
|
26
|
+
- A task on the remote needs an image the user has on their local clipboard (a screenshot, a design, an error photo).
|
|
27
|
+
|
|
28
|
+
Do NOT use this for local sessions (paste works natively) or for copying image files that already exist on the remote (use `ssh-copy`).
|
|
29
|
+
|
|
30
|
+
## How it works
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Local Machine Remote Server (SSH)
|
|
34
|
+
┌──────────────────────┐ ┌──────────────────────────┐
|
|
35
|
+
│ Clipboard (PNG) │ │ Claude Code │
|
|
36
|
+
│ │ │ │ │ │
|
|
37
|
+
│ ▼ │ │ ▼ │
|
|
38
|
+
│ ccimgd (Port 9998) │◄────────────────│ ssh-paste-image skill │
|
|
39
|
+
│ - wl-paste/xclip │ SSH Reverse │ - TCP request to ccimgd │
|
|
40
|
+
│ - returns base64 │ Tunnel │ - receives base64 image │
|
|
41
|
+
│ image in response │ (Port 9998) │ - saves a temp PNG │
|
|
42
|
+
│ │ │ - Read → agent sees it │
|
|
43
|
+
└──────────────────────┘ └──────────────────────────┘
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
1. The skill runs `ccimg` on the remote, which opens a TCP request to `127.0.0.1:9998`.
|
|
47
|
+
2. That port is forwarded over the SSH reverse tunnel to the local `ccimgd`.
|
|
48
|
+
3. `ccimgd` reads the clipboard PNG (`wl-paste` on Wayland, `xclip` on X11, `pngpaste` on macOS) and returns base64 JSON.
|
|
49
|
+
4. `ccimg` decodes it, writes `/tmp/clipboard-<pid>.png`, and prints the path.
|
|
50
|
+
5. The skill uses `Read` on that path so the agent sees the image.
|
|
51
|
+
|
|
52
|
+
## Prerequisites
|
|
53
|
+
|
|
54
|
+
- **Build (anywhere with Go):** `go` 1.26+ for `bash scripts/build.sh`.
|
|
55
|
+
- **Local machine, Linux Wayland:** `wl-paste` from `wl-clipboard` (apt: `sudo apt install -y wl-clipboard`).
|
|
56
|
+
- **Local machine, Linux X11:** `xclip` (apt: `sudo apt install -y xclip`).
|
|
57
|
+
- **Local machine, macOS:** `pngpaste` (brew: `brew install pngpaste`).
|
|
58
|
+
- **Remote host:** Claude Code, plus the `ccimg` client binary (installed in step 3 below).
|
|
59
|
+
|
|
60
|
+
## Setup (one time)
|
|
61
|
+
|
|
62
|
+
### 1. Build the binaries
|
|
63
|
+
|
|
64
|
+
From this skill's directory (where this SKILL.md lives):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
bash scripts/build.sh
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This writes static binaries for linux/amd64, linux/arm64, darwin/amd64, darwin/arm64 into `scripts/daemon/` and `scripts/client/`.
|
|
71
|
+
|
|
72
|
+
### 2. Install the daemon on your LOCAL machine
|
|
73
|
+
|
|
74
|
+
Linux (systemd user service):
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
cp scripts/daemon/ccimgd-linux-amd64 ~/.local/bin/ccimgd # or -linux-arm64
|
|
78
|
+
cp scripts/daemon/ccimgd.service ~/.config/systemd/user/
|
|
79
|
+
systemctl --user daemon-reload
|
|
80
|
+
systemctl --user enable --now ccimgd
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
macOS (launchd agent):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
cp scripts/daemon/ccimgd-darwin-arm64 /usr/local/bin/ccimgd # or -darwin-amd64 on Intel
|
|
87
|
+
cp scripts/daemon/com.ccimgd.plist ~/Library/LaunchAgents/
|
|
88
|
+
launchctl load ~/Library/LaunchAgents/com.ccimgd.plist
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3. Install the client on the REMOTE host
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
scp scripts/client/ccimg-linux-amd64 your-server:~/.local/bin/ccimg # match the server arch
|
|
95
|
+
ssh your-server 'chmod +x ~/.local/bin/ccimg'
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
To skip the per-call permission prompt, add to the remote `~/.claude/settings.json`:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{ "permissions": { "allow": ["Bash(ccimg)"] } }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 4. Open the SSH reverse tunnel
|
|
105
|
+
|
|
106
|
+
Connect with port 9998 forwarded back to your local daemon:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
ssh -R 9998:localhost:9998 your-server
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Or make it permanent in `~/.ssh/config` (see the `ssh-tunnel` skill for the pattern):
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
Host your-server
|
|
116
|
+
RemoteForward 9998 localhost:9998
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Usage
|
|
120
|
+
|
|
121
|
+
On the remote session, copy an image to your LOCAL clipboard, then run the client and read the file it prints:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
ccimg
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Then `Read` the printed path (for example `/tmp/clipboard-12345.png`). The agent now sees the image.
|
|
128
|
+
|
|
129
|
+
## Example
|
|
130
|
+
|
|
131
|
+
> User (in an SSH Claude Code session): "here's the broken layout, /paste-image"
|
|
132
|
+
|
|
133
|
+
1. Run `ccimg` with Bash. It prints `/tmp/clipboard-4821.png`.
|
|
134
|
+
2. `Read` `/tmp/clipboard-4821.png`.
|
|
135
|
+
3. The screenshot renders in the session and you can act on it.
|
|
136
|
+
|
|
137
|
+
If `ccimg` prints `Failed to connect to ccimgd`, the reverse tunnel is not up (reconnect with `-R 9998:localhost:9998`). If it prints `Clipboard is empty or does not contain an image`, copy an image first (a file copy is not an image).
|
|
138
|
+
|
|
139
|
+
## Rules
|
|
140
|
+
|
|
141
|
+
- The reverse tunnel (`-R 9998:localhost:9998`) is required. No tunnel, no image. This is the most common failure.
|
|
142
|
+
- `ccimgd` reads an IMAGE on the clipboard, not a file path. Copy the picture itself (screenshot tools do this).
|
|
143
|
+
- Port 9998 is chosen so it can run alongside sshimg.nvim (port 9999) on the same machine.
|
|
144
|
+
- The image crosses the existing SSH channel as base64. Nothing extra is exposed to the network.
|
|
145
|
+
- Rebuild and reinstall both binaries after editing the Go source; the daemon and client must agree on the protocol.
|
|
146
|
+
|
|
147
|
+
## Credits
|
|
148
|
+
|
|
149
|
+
Daemon and client vendored from [claude-ssh-image-skill](https://github.com/AlexZeitler/claude-ssh-image-skill) by Alexander Zeitler, MIT licensed. See `LICENSE`. The `build.sh` adds a linux/arm64 target; the Go sources are otherwise unchanged.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
cd "$(dirname "$0")"
|
|
5
|
+
|
|
6
|
+
# Faithful to upstream, plus linux/arm64 for ARM servers (Graviton, Hetzner ARM,
|
|
7
|
+
# Raspberry Pi). Each target is a static, CGO-free binary.
|
|
8
|
+
platforms=(
|
|
9
|
+
"linux/amd64"
|
|
10
|
+
"linux/arm64"
|
|
11
|
+
"darwin/amd64"
|
|
12
|
+
"darwin/arm64"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
for platform in "${platforms[@]}"; do
|
|
16
|
+
os="${platform%/*}"
|
|
17
|
+
arch="${platform#*/}"
|
|
18
|
+
suffix="${os}-${arch}"
|
|
19
|
+
|
|
20
|
+
echo "Building for ${os}/${arch}..."
|
|
21
|
+
|
|
22
|
+
echo " ccimgd-${suffix}"
|
|
23
|
+
(cd daemon && CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" go build -o "ccimgd-${suffix}" .)
|
|
24
|
+
|
|
25
|
+
echo " ccimg-${suffix}"
|
|
26
|
+
(cd client && CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" go build -o "ccimg-${suffix}" .)
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
echo "Done."
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/base64"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"fmt"
|
|
7
|
+
"net"
|
|
8
|
+
"os"
|
|
9
|
+
"path/filepath"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
const (
|
|
13
|
+
host = "127.0.0.1"
|
|
14
|
+
port = "9998"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
type response struct {
|
|
18
|
+
OK bool `json:"ok"`
|
|
19
|
+
Image string `json:"image"`
|
|
20
|
+
Error string `json:"error"`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
func main() {
|
|
24
|
+
conn, err := net.Dial("tcp", net.JoinHostPort(host, port))
|
|
25
|
+
if err != nil {
|
|
26
|
+
fmt.Fprintf(os.Stderr, "Failed to connect to ccimgd: %v\n", err)
|
|
27
|
+
os.Exit(1)
|
|
28
|
+
}
|
|
29
|
+
defer conn.Close()
|
|
30
|
+
|
|
31
|
+
_, err = conn.Write([]byte("{}\n"))
|
|
32
|
+
if err != nil {
|
|
33
|
+
fmt.Fprintf(os.Stderr, "Failed to send request: %v\n", err)
|
|
34
|
+
os.Exit(1)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var buf []byte
|
|
38
|
+
tmp := make([]byte, 65536)
|
|
39
|
+
for {
|
|
40
|
+
n, err := conn.Read(tmp)
|
|
41
|
+
if n > 0 {
|
|
42
|
+
buf = append(buf, tmp[:n]...)
|
|
43
|
+
}
|
|
44
|
+
if err != nil {
|
|
45
|
+
break
|
|
46
|
+
}
|
|
47
|
+
for _, b := range tmp[:n] {
|
|
48
|
+
if b == '\n' {
|
|
49
|
+
goto done
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
done:
|
|
54
|
+
|
|
55
|
+
var resp response
|
|
56
|
+
if err := json.Unmarshal(buf, &resp); err != nil {
|
|
57
|
+
fmt.Fprintf(os.Stderr, "Failed to parse response: %v\n", err)
|
|
58
|
+
os.Exit(1)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if !resp.OK {
|
|
62
|
+
fmt.Fprintf(os.Stderr, "Error: %s\n", resp.Error)
|
|
63
|
+
os.Exit(1)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
imgData, err := base64.StdEncoding.DecodeString(resp.Image)
|
|
67
|
+
if err != nil {
|
|
68
|
+
fmt.Fprintf(os.Stderr, "Failed to decode image: %v\n", err)
|
|
69
|
+
os.Exit(1)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
tmpFile := filepath.Join(os.TempDir(), fmt.Sprintf("clipboard-%d.png", os.Getpid()))
|
|
73
|
+
if err := os.WriteFile(tmpFile, imgData, 0644); err != nil {
|
|
74
|
+
fmt.Fprintf(os.Stderr, "Failed to write image: %v\n", err)
|
|
75
|
+
os.Exit(1)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fmt.Println(tmpFile)
|
|
79
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>com.ccimgd</string>
|
|
7
|
+
<key>ProgramArguments</key>
|
|
8
|
+
<array>
|
|
9
|
+
<string>/usr/local/bin/ccimgd</string>
|
|
10
|
+
</array>
|
|
11
|
+
<key>RunAtLoad</key>
|
|
12
|
+
<true/>
|
|
13
|
+
<key>KeepAlive</key>
|
|
14
|
+
<true/>
|
|
15
|
+
<key>StandardOutPath</key>
|
|
16
|
+
<string>/tmp/ccimgd.log</string>
|
|
17
|
+
<key>StandardErrorPath</key>
|
|
18
|
+
<string>/tmp/ccimgd.log</string>
|
|
19
|
+
</dict>
|
|
20
|
+
</plist>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/base64"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"fmt"
|
|
7
|
+
"net"
|
|
8
|
+
"os"
|
|
9
|
+
"os/exec"
|
|
10
|
+
"os/signal"
|
|
11
|
+
"runtime"
|
|
12
|
+
"syscall"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
const (
|
|
16
|
+
host = "127.0.0.1"
|
|
17
|
+
port = "9998"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
type response struct {
|
|
21
|
+
OK bool `json:"ok"`
|
|
22
|
+
Image string `json:"image,omitempty"`
|
|
23
|
+
Error string `json:"error,omitempty"`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func getClipboardImage() ([]byte, error) {
|
|
27
|
+
var cmd *exec.Cmd
|
|
28
|
+
switch {
|
|
29
|
+
case runtime.GOOS == "darwin":
|
|
30
|
+
cmd = exec.Command("pngpaste", "-")
|
|
31
|
+
case os.Getenv("WAYLAND_DISPLAY") != "":
|
|
32
|
+
cmd = exec.Command("wl-paste", "--type", "image/png")
|
|
33
|
+
default:
|
|
34
|
+
cmd = exec.Command("xclip", "-selection", "clipboard", "-target", "image/png", "-o")
|
|
35
|
+
}
|
|
36
|
+
out, err := cmd.Output()
|
|
37
|
+
if err != nil || len(out) == 0 {
|
|
38
|
+
return nil, fmt.Errorf("Clipboard is empty or does not contain an image")
|
|
39
|
+
}
|
|
40
|
+
return out, nil
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
func handleConn(conn net.Conn) {
|
|
44
|
+
defer conn.Close()
|
|
45
|
+
|
|
46
|
+
buf := make([]byte, 4096)
|
|
47
|
+
for {
|
|
48
|
+
n, err := conn.Read(buf)
|
|
49
|
+
if err != nil || n == 0 {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
for _, b := range buf[:n] {
|
|
53
|
+
if b == '\n' {
|
|
54
|
+
goto ready
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
ready:
|
|
59
|
+
|
|
60
|
+
var resp response
|
|
61
|
+
imgData, err := getClipboardImage()
|
|
62
|
+
if err != nil {
|
|
63
|
+
resp = response{OK: false, Error: err.Error()}
|
|
64
|
+
} else {
|
|
65
|
+
resp = response{OK: true, Image: base64.StdEncoding.EncodeToString(imgData)}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
data, _ := json.Marshal(resp)
|
|
69
|
+
data = append(data, '\n')
|
|
70
|
+
conn.Write(data)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func main() {
|
|
74
|
+
listener, err := net.Listen("tcp", net.JoinHostPort(host, port))
|
|
75
|
+
if err != nil {
|
|
76
|
+
fmt.Fprintf(os.Stderr, "Failed to listen: %v\n", err)
|
|
77
|
+
os.Exit(1)
|
|
78
|
+
}
|
|
79
|
+
defer listener.Close()
|
|
80
|
+
|
|
81
|
+
fmt.Printf("ccimgd listening on %s:%s\n", host, port)
|
|
82
|
+
|
|
83
|
+
sig := make(chan os.Signal, 1)
|
|
84
|
+
signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
|
|
85
|
+
go func() {
|
|
86
|
+
<-sig
|
|
87
|
+
listener.Close()
|
|
88
|
+
os.Exit(0)
|
|
89
|
+
}()
|
|
90
|
+
|
|
91
|
+
for {
|
|
92
|
+
conn, err := listener.Accept()
|
|
93
|
+
if err != nil {
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
handleConn(conn)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ssh-tunnel
|
|
3
|
+
description: >-
|
|
4
|
+
Use when the user wants SSH port forwarding: a local tunnel (-L) to reach a
|
|
5
|
+
remote service, a reverse tunnel (-R) to expose a local one, or a dynamic
|
|
6
|
+
SOCKS proxy (-D). Triggers: "ssh tunnel", "forward a port", "reverse tunnel".
|
|
7
|
+
tags: [ssh, tunnel, port-forwarding, socks]
|
|
8
|
+
category: ssh
|
|
9
|
+
triggers: ["ssh tunnel", "forward a port", "reverse tunnel", "socks proxy", "port forward over ssh", "ssh -L", "ssh -R"]
|
|
10
|
+
allowed-tools: Bash(ssh:*), Bash(autossh:*)
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# SSH tunnel
|
|
14
|
+
|
|
15
|
+
SSH can forward TCP ports across the encrypted connection. Three directions cover
|
|
16
|
+
almost every case: pull a remote service to your machine (`-L`), push a local
|
|
17
|
+
service to the remote (`-R`), or send all traffic through the host as a proxy
|
|
18
|
+
(`-D`). This skill picks the right flag and keeps the tunnel alive.
|
|
19
|
+
|
|
20
|
+
## When to activate
|
|
21
|
+
|
|
22
|
+
- The user wants to reach a remote-only service (a database, an admin UI) from their laptop.
|
|
23
|
+
- The user wants a remote host to reach a service running on their laptop (the paste-image daemon, a local API).
|
|
24
|
+
- The user wants to browse through a remote host as a SOCKS proxy.
|
|
25
|
+
- The user says "tunnel a port", "port forward over ssh", or "reverse tunnel".
|
|
26
|
+
|
|
27
|
+
## Steps
|
|
28
|
+
|
|
29
|
+
### Local forward (-L): reach a remote service locally
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
ssh -L 5432:localhost:5432 user@dbhost
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Now `localhost:5432` on your machine reaches the database bound to `localhost:5432` on `dbhost`. The pattern is `-L <local_port>:<target_host>:<target_port>`, where the target is resolved FROM the remote side.
|
|
36
|
+
|
|
37
|
+
### Reverse forward (-R): expose a local service on the remote
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
ssh -R 9998:localhost:9998 user@server
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Now `localhost:9998` on `server` reaches port 9998 on your machine. This is exactly what the `ssh-paste-image` skill needs. To let other remote hosts (not just localhost) use it, set `GatewayPorts yes` in the server's sshd config.
|
|
44
|
+
|
|
45
|
+
### Dynamic proxy (-D): SOCKS through the host
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
ssh -D 1080 user@host
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Point a browser or tool at SOCKS5 `localhost:1080` to route its traffic through `host`.
|
|
52
|
+
|
|
53
|
+
### Run a tunnel with no shell, in the background
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ssh -fN -L 5432:localhost:5432 user@dbhost
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`-N` means no remote command, `-f` backgrounds after auth. Find and stop it with `pgrep -af 'ssh -fN'` then `kill <pid>`.
|
|
60
|
+
|
|
61
|
+
### Make it permanent in ~/.ssh/config
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Host dbhost
|
|
65
|
+
HostName db.example.com
|
|
66
|
+
User app
|
|
67
|
+
LocalForward 5432 localhost:5432
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Auto-reconnecting tunnel
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
autossh -M 0 -fN -L 5432:localhost:5432 user@dbhost
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`autossh` restarts the tunnel if it drops. Pair with `ServerAliveInterval` from the `ssh-config` skill.
|
|
77
|
+
|
|
78
|
+
## Prerequisites
|
|
79
|
+
|
|
80
|
+
- `ssh` (OpenSSH client). apt: `sudo apt install -y openssh-client`.
|
|
81
|
+
- `autossh` for auto-reconnect (optional). apt: `sudo apt install -y autossh` · brew: `brew install autossh`.
|
|
82
|
+
|
|
83
|
+
## Example
|
|
84
|
+
|
|
85
|
+
> User: "I need to hit the staging Postgres on the bastion from my laptop with psql."
|
|
86
|
+
|
|
87
|
+
1. `ssh -fN -L 5432:localhost:5432 user@bastion`.
|
|
88
|
+
2. `psql -h localhost -p 5432 -U app staging` connects through the tunnel.
|
|
89
|
+
3. To make it stick, add a `LocalForward 5432 localhost:5432` line to the `Host bastion` block.
|
|
90
|
+
|
|
91
|
+
## Rules
|
|
92
|
+
|
|
93
|
+
- `-L` resolves the target from the REMOTE side; `-R` resolves it from YOUR side. Mixing these two up is the usual reason a tunnel "does nothing".
|
|
94
|
+
- Reverse forwards reach only `localhost` on the server unless `GatewayPorts yes` is set in sshd.
|
|
95
|
+
- A privileged local port (<1024) needs root; pick a high port instead.
|
|
96
|
+
- Background tunnels (`-fN`) are easy to forget. Track them with `pgrep -af ssh` and stop them when done.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: building-with-strapi
|
|
3
|
+
description: 'Use when building a Strapi v5 backend: project structure, content-types, components, dynamic zones, the Content-Type Builder, and Document Service queries in custom code.'
|
|
4
|
+
tags: [strapi, cms, content-types, document-service, backend]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Building With Strapi
|
|
8
|
+
|
|
9
|
+
Model content and customize the backend of a Strapi v5 project.
|
|
10
|
+
|
|
11
|
+
## Use This Skill For
|
|
12
|
+
|
|
13
|
+
- Understanding the project layout and where code lives
|
|
14
|
+
- Creating content-types, components, and dynamic zones
|
|
15
|
+
- Querying and mutating content from custom code via the Document Service
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
- A running Strapi v5 project in dev mode (`npm run develop`). See
|
|
20
|
+
`strapi-cli` to scaffold one.
|
|
21
|
+
- Content-Type Builder only works in `develop` mode (it writes schema files
|
|
22
|
+
and restarts the server).
|
|
23
|
+
|
|
24
|
+
## Project Structure
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
my-strapi-project/
|
|
28
|
+
├── config/ server.ts, database.ts, admin.ts, api.ts, plugins.ts, middlewares.ts
|
|
29
|
+
├── src/
|
|
30
|
+
│ ├── api/<name>/ content-types/, controllers/, services/, routes/
|
|
31
|
+
│ ├── components/ reusable field groups
|
|
32
|
+
│ ├── extensions/ overrides for installed plugins
|
|
33
|
+
│ ├── plugins/ local plugins
|
|
34
|
+
│ └── index.ts register() / bootstrap() lifecycle
|
|
35
|
+
├── database/migrations/
|
|
36
|
+
└── public/uploads/ media library files
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Each entry under `src/api/<name>/` is one content-type with its schema,
|
|
40
|
+
controller, service, and routes.
|
|
41
|
+
|
|
42
|
+
## Modeling Content
|
|
43
|
+
|
|
44
|
+
Build content-types in the admin **Content-Type Builder**
|
|
45
|
+
(`/admin/plugins/content-type-builder`):
|
|
46
|
+
|
|
47
|
+
- **Collection type**: many entries (e.g. `restaurant` → `/api/restaurants`).
|
|
48
|
+
- **Single type**: one entry (e.g. `homepage` → `/api/homepage`).
|
|
49
|
+
- **Component**: a reusable group of fields embedded in types.
|
|
50
|
+
- **Dynamic zone**: a slot that accepts a chosen list of components per entry.
|
|
51
|
+
|
|
52
|
+
The builder writes `schema.json` files under
|
|
53
|
+
`src/api/<name>/content-types/`. Commit those; they are your schema source
|
|
54
|
+
of truth.
|
|
55
|
+
|
|
56
|
+
## documentId, Not id
|
|
57
|
+
|
|
58
|
+
Strapi 5 identifies every entry by a 24-character `documentId`, stable across
|
|
59
|
+
locales and draft/published versions. The numeric `id` is a physical record
|
|
60
|
+
detail and may disappear in future versions.
|
|
61
|
+
|
|
62
|
+
- Query and relate by `documentId`.
|
|
63
|
+
- Treat `id` as legacy; do not hardcode it in clients or relations.
|
|
64
|
+
|
|
65
|
+
## Document Service API (in custom code)
|
|
66
|
+
|
|
67
|
+
Inside controllers, services, and plugins, use the Document Service. It sits
|
|
68
|
+
above the Query Engine and understands components, dynamic zones, draft &
|
|
69
|
+
publish, and i18n.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// list (nothing populates by default — ask for it)
|
|
73
|
+
const articles = await strapi.documents('api::article.article').findMany({
|
|
74
|
+
filters: { title: { $containsi: 'strapi' } },
|
|
75
|
+
populate: { cover: true, author: { fields: ['name'] } },
|
|
76
|
+
sort: 'publishedAt:desc',
|
|
77
|
+
status: 'published',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// fetch one by documentId
|
|
81
|
+
const one = await strapi.documents('api::article.article').findOne({
|
|
82
|
+
documentId,
|
|
83
|
+
populate: ['cover'],
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// create / update / delete
|
|
87
|
+
const created = await strapi.documents('api::article.article').create({ data });
|
|
88
|
+
await strapi.documents('api::article.article').update({ documentId, data });
|
|
89
|
+
await strapi.documents('api::article.article').delete({ documentId });
|
|
90
|
+
|
|
91
|
+
// draft & publish (when enabled on the type)
|
|
92
|
+
await strapi.documents('api::article.article').publish({ documentId });
|
|
93
|
+
await strapi.documents('api::article.article').unpublish({ documentId });
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Need raw DB access below the content model? Drop to the Query Engine
|
|
97
|
+
(`strapi.db.query(...)`), but prefer the Document Service for anything that
|
|
98
|
+
touches components, dynamic zones, or publication state.
|
|
99
|
+
|
|
100
|
+
## Rules
|
|
101
|
+
|
|
102
|
+
- Model in `develop`; the builder is disabled in `start`.
|
|
103
|
+
- Always pass `populate`/`fields` explicitly; defaults return top-level
|
|
104
|
+
scalars only.
|
|
105
|
+
- Use the Document Service over the removed Entity Service path and over raw
|
|
106
|
+
Query Engine unless you specifically need lower-level access.
|
|
107
|
+
- Commit `schema.json` files; they define the data model.
|
|
108
|
+
|
|
109
|
+
## Next Step
|
|
110
|
+
|
|
111
|
+
Expose this content over HTTP with `strapi-content-api`, or package custom
|
|
112
|
+
features as a plugin with `strapi-plugins`.
|