cue-ai 0.9.2 → 0.9.3
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 +4 -3
- package/README.md +148 -170
- package/bin/cue-learnings +30 -4
- package/bin/cue-review-progress +0 -0
- package/bin/cue-review-watch +0 -0
- package/dist/cue.js +4328 -3108
- package/package.json +1 -1
- package/plugins/cue/commands/cue-switch.md +1 -1
- package/plugins/cue/commands/cue.md +1 -1
- package/profiles/backend/profile.yaml +4 -0
- package/profiles/browser/profile.yaml +4 -0
- package/profiles/career/profile.yaml +2 -13
- package/profiles/commerce/profile.yaml +0 -2
- package/profiles/coolify/profile.yaml +0 -1
- package/profiles/core/profile.yaml +78 -11
- package/profiles/dash-merge-test/profile.yaml +6 -1
- package/profiles/designer/profile.yaml +9 -1
- package/profiles/dropshipping/profile.yaml +69 -0
- package/profiles/frontend/profile.yaml +4 -0
- package/profiles/google-ads/profile.yaml +34 -0
- package/profiles/google-analytics/profile.yaml +34 -0
- package/profiles/google-drive/profile.yaml +34 -0
- package/profiles/gstack/profile.yaml +117 -29
- package/profiles/marketing/profile.yaml +0 -1
- package/profiles/media/README.md +70 -0
- package/profiles/media/profile.yaml +104 -0
- package/profiles/nano-banana/profile.yaml +52 -0
- package/profiles/ops/profile.yaml +1 -2
- package/profiles/secops/profile.yaml +3 -0
- package/profiles/skill-writer/profile.yaml +15 -0
- package/profiles/video/profile.yaml +3 -0
- package/profiles/web-frontend-base/profile.yaml +6 -0
- package/profiles/webshop/profile.yaml +0 -1
- package/profiles/webshop-google/profile.yaml +1 -0
- package/profiles/x-growth-bot/profile.yaml +2 -0
- package/resources/icons/generate-icons.py +2 -128
- package/resources/mcps/configs/claude.sanitized.json +88 -20
- package/resources/mcps/configs/claude_runtime.sanitized.json +40 -1
- package/resources/mcps/configs/codex.sanitized.json +29 -0
- package/resources/skills/skills/career/job-hunter/LICENSE +21 -0
- package/resources/skills/skills/career/job-hunter/README.md +323 -0
- package/resources/skills/skills/career/job-hunter/SKILL.md +91 -0
- package/resources/skills/skills/career/job-hunter/agents/README.md +96 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-assessment-prep.md +195 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-ats-scan.md +155 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-bias-audit.md +224 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-cover-letter.md +69 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-decode-jd.md +117 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-fit-score.md +183 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-linkedin-audit.md +74 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-linkedin-scrape.md +255 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-portfolio-brief.md +123 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-reality-check.md +164 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-reference-prep.md +150 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-rejection-analysis.md +172 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-resume.md +70 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-skills-gap-filler.md +109 -0
- package/resources/skills/skills/career/job-hunter/agents/career-internal.md +94 -0
- package/resources/skills/skills/career/job-hunter/agents/career-linkedin-content.md +173 -0
- package/resources/skills/skills/career/job-hunter/agents/career-linkedin-scanner.md +262 -0
- package/resources/skills/skills/career/job-hunter/agents/career-network-message.md +108 -0
- package/resources/skills/skills/career/job-hunter/agents/career-promote.md +102 -0
- package/resources/skills/skills/career/job-hunter/agents/career-review.md +71 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-debrief.md +117 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-mock.md +171 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-panel-decoder.md +152 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-prep.md +184 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-question-bank.md +133 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-research.md +148 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-compare.md +117 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-counteroffer.md +144 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-deadline-manager.md +148 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-negotiate.md +126 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-schedule.md +99 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-thankyou.md +80 -0
- package/resources/skills/skills/career/job-hunter/agents/search-company-research.md +146 -0
- package/resources/skills/skills/career/job-hunter/agents/search-follow-up.md +129 -0
- package/resources/skills/skills/career/job-hunter/agents/search-ghost-job-detector.md +152 -0
- package/resources/skills/skills/career/job-hunter/agents/search-inbox-scan.md +193 -0
- package/resources/skills/skills/career/job-hunter/agents/search-interview-scorecard.md +164 -0
- package/resources/skills/skills/career/job-hunter/agents/search-jobs.md +149 -0
- package/resources/skills/skills/career/job-hunter/agents/search-momentum-check.md +194 -0
- package/resources/skills/skills/career/job-hunter/agents/search-outreach.md +85 -0
- package/resources/skills/skills/career/job-hunter/agents/search-referral-finder.md +124 -0
- package/resources/skills/skills/career/job-hunter/agents/search-salary.md +96 -0
- package/resources/skills/skills/career/job-hunter/agents/search-send-email.md +109 -0
- package/resources/skills/skills/career/job-hunter/agents/search-tracker-update.md +127 -0
- package/resources/skills/skills/career/job-hunter/inputs/README.md +26 -0
- package/resources/skills/skills/career/job-hunter/inputs/apply-linkedin-url.txt +8 -0
- package/resources/skills/skills/career/job-hunter/inputs/interview-context.md +24 -0
- package/resources/skills/skills/career/job-hunter/inputs/job-description.md +20 -0
- package/resources/skills/skills/career/job-hunter/inputs/job-search-criteria.md +36 -0
- package/resources/skills/skills/career/job-hunter/inputs/my-linkedin.md +24 -0
- package/resources/skills/skills/career/job-hunter/inputs/my-resume.md +28 -0
- package/resources/skills/skills/career/job-hunter/inputs/search-outreach-target.md +24 -0
- package/resources/skills/skills/career/job-hunter/rules/README.md +37 -0
- package/resources/skills/skills/career/job-hunter/rules/writing-rules.md +81 -0
- package/resources/skills/skills/design/banana/SKILL.md +375 -0
- package/resources/skills/skills/design/banana/references/cost-tracking.md +47 -0
- package/resources/skills/skills/design/banana/references/gemini-models.md +236 -0
- package/resources/skills/skills/design/banana/references/mcp-tools.md +145 -0
- package/resources/skills/skills/design/banana/references/post-processing.md +192 -0
- package/resources/skills/skills/design/banana/references/presets.md +69 -0
- package/resources/skills/skills/design/banana/references/prompt-engineering.md +481 -0
- package/resources/skills/skills/design/banana/scripts/batch.py +97 -0
- package/resources/skills/skills/design/banana/scripts/cost_tracker.py +191 -0
- package/resources/skills/skills/design/banana/scripts/edit.py +159 -0
- package/resources/skills/skills/design/banana/scripts/generate.py +168 -0
- package/resources/skills/skills/design/banana/scripts/presets.py +154 -0
- package/resources/skills/skills/design/banana/scripts/setup_mcp.py +151 -0
- package/resources/skills/skills/design/banana/scripts/validate_setup.py +133 -0
- package/resources/skills/skills/gstack/ship/SKILL.md +13 -0
- package/resources/skills/skills/media/3d-logo-animation/SKILL.md +59 -0
- package/resources/skills/skills/media/action-figure-generator/SKILL.md +48 -0
- package/resources/skills/skills/media/ad-creative/SKILL.md +79 -0
- package/resources/skills/skills/media/ai-clipping/SKILL.md +194 -0
- package/resources/skills/skills/media/ai-clipping/scripts/run-ai-clipping.sh +200 -0
- package/resources/skills/skills/media/ai-fight-scene/SKILL.md +132 -0
- package/resources/skills/skills/media/amazon-product-listing/SKILL.md +68 -0
- package/resources/skills/skills/media/animal-video-generator/SKILL.md +59 -0
- package/resources/skills/skills/media/award-ceremony-video/SKILL.md +87 -0
- package/resources/skills/skills/media/blog-header/SKILL.md +61 -0
- package/resources/skills/skills/media/brand-kit/SKILL.md +72 -0
- package/resources/skills/skills/media/brochures/SKILL.md +65 -0
- package/resources/skills/skills/media/cartoon-dance-animation/SKILL.md +62 -0
- package/resources/skills/skills/media/character-story-video/SKILL.md +84 -0
- package/resources/skills/skills/media/chibi-collage-effect/SKILL.md +63 -0
- package/resources/skills/skills/media/cinema-director/SKILL.md +93 -0
- package/resources/skills/skills/media/cinema-director/scripts/generate-film.sh +78 -0
- package/resources/skills/skills/media/color-analysis-board/SKILL.md +71 -0
- package/resources/skills/skills/media/core-edit/SKILL.md +48 -0
- package/resources/skills/skills/media/core-edit/edit-image.sh +54 -0
- package/resources/skills/skills/media/core-edit/enhance-image.sh +191 -0
- package/resources/skills/skills/media/core-edit/lipsync.sh +144 -0
- package/resources/skills/skills/media/core-edit/video-effects.sh +193 -0
- package/resources/skills/skills/media/core-media/SKILL.md +49 -0
- package/resources/skills/skills/media/core-media/create-music.sh +169 -0
- package/resources/skills/skills/media/core-media/generate-image.sh +161 -0
- package/resources/skills/skills/media/core-media/generate-video.sh +137 -0
- package/resources/skills/skills/media/core-media/image-to-video.sh +228 -0
- package/resources/skills/skills/media/core-media/schema_data.json +18708 -0
- package/resources/skills/skills/media/core-media/upload.sh +41 -0
- package/resources/skills/skills/media/core-platform/SKILL.md +41 -0
- package/resources/skills/skills/media/core-platform/check-result.sh +37 -0
- package/resources/skills/skills/media/core-platform/setup.sh +31 -0
- package/resources/skills/skills/media/couple-grid-creator/SKILL.md +47 -0
- package/resources/skills/skills/media/design-guide/SKILL.md +73 -0
- package/resources/skills/skills/media/drone-style-video/SKILL.md +61 -0
- package/resources/skills/skills/media/fashion-try-on/SKILL.md +61 -0
- package/resources/skills/skills/media/floor-plan-rendering/SKILL.md +56 -0
- package/resources/skills/skills/media/freeze-effect-video/SKILL.md +100 -0
- package/resources/skills/skills/media/giant-product-showcase/SKILL.md +61 -0
- package/resources/skills/skills/media/instagram-post/SKILL.md +58 -0
- package/resources/skills/skills/media/interior-design/SKILL.md +61 -0
- package/resources/skills/skills/media/interior-design-visualizer/SKILL.md +57 -0
- package/resources/skills/skills/media/jewelry-product-video/SKILL.md +61 -0
- package/resources/skills/skills/media/kdenlive/SKILL.md +106 -0
- package/resources/skills/skills/media/kdenlive/scripts/assemble.sh +57 -0
- package/resources/skills/skills/media/kdenlive/scripts/common.sh +30 -0
- package/resources/skills/skills/media/kdenlive/scripts/inspect.sh +19 -0
- package/resources/skills/skills/media/kdenlive/scripts/reframe.sh +22 -0
- package/resources/skills/skills/media/kdenlive/scripts/render.sh +16 -0
- package/resources/skills/skills/media/kdenlive/scripts/title-card.sh +25 -0
- package/resources/skills/skills/media/keyboard-art-maker/SKILL.md +44 -0
- package/resources/skills/skills/media/logo-branding/SKILL.md +70 -0
- package/resources/skills/skills/media/logo-creator/SKILL.md +80 -0
- package/resources/skills/skills/media/logo-creator/scripts/create-logo.sh +38 -0
- package/resources/skills/skills/media/logo-generator/SKILL.md +56 -0
- package/resources/skills/skills/media/multi-angle-reshoot/SKILL.md +70 -0
- package/resources/skills/skills/media/multi-angle-shots/SKILL.md +73 -0
- package/resources/skills/skills/media/music-video/SKILL.md +61 -0
- package/resources/skills/skills/media/nano-banana/SKILL.md +80 -0
- package/resources/skills/skills/media/nano-banana/scripts/generate-nano-art.sh +54 -0
- package/resources/skills/skills/media/one-shot-video/SKILL.md +56 -0
- package/resources/skills/skills/media/photo-pack-generator/SKILL.md +205 -0
- package/resources/skills/skills/media/photo-pack-generator/scripts/generate-pack.sh +241 -0
- package/resources/skills/skills/media/product-ad-cinematic/SKILL.md +78 -0
- package/resources/skills/skills/media/product-campaign/SKILL.md +76 -0
- package/resources/skills/skills/media/product-showcase-video/SKILL.md +60 -0
- package/resources/skills/skills/media/product-video-ad-maker/SKILL.md +59 -0
- package/resources/skills/skills/media/rednote-cover/SKILL.md +57 -0
- package/resources/skills/skills/media/seedance-2/SKILL.md +632 -0
- package/resources/skills/skills/media/seedance-2/scripts/generate-seedance.sh +701 -0
- package/resources/skills/skills/media/selfie-with-celebrities/SKILL.md +64 -0
- package/resources/skills/skills/media/social-media-video/SKILL.md +277 -0
- package/resources/skills/skills/media/social-media-video/scripts/run-social-video.sh +316 -0
- package/resources/skills/skills/media/social-pack/SKILL.md +58 -0
- package/resources/skills/skills/media/storyboard/SKILL.md +57 -0
- package/resources/skills/skills/media/storyboard-to-cooking-video/SKILL.md +143 -0
- package/resources/skills/skills/media/talking-baby-video/SKILL.md +57 -0
- package/resources/skills/skills/media/ugc-ads-workflow/SKILL.md +70 -0
- package/resources/skills/skills/media/ugc-lifestyle-try-on/SKILL.md +65 -0
- package/resources/skills/skills/media/ugc-video-factory/SKILL.md +134 -0
- package/resources/skills/skills/media/ui-design/SKILL.md +81 -0
- package/resources/skills/skills/media/ui-design/scripts/generate-mockup.sh +49 -0
- package/resources/skills/skills/media/url-to-design/SKILL.md +61 -0
- package/resources/skills/skills/media/workflow/SKILL.md +197 -0
- package/resources/skills/skills/media/workflow/scripts/discover-workflow.sh +18 -0
- package/resources/skills/skills/media/workflow/scripts/generate-workflow.sh +33 -0
- package/resources/skills/skills/media/workflow/scripts/interactive-run.sh +16 -0
- package/resources/skills/skills/media/workflow/scripts/list-workflows.sh +20 -0
- package/resources/skills/skills/media/workflow/scripts/run-workflow.sh +34 -0
- package/resources/skills/skills/media/youtube-shorts/SKILL.md +173 -0
- package/resources/skills/skills/media/youtube-shorts/scripts/run-youtube-shorts.sh +141 -0
- package/resources/skills/skills/media/youtube-thumbnail/SKILL.md +66 -0
- package/resources/skills/skills/meta/cue-developer/references/architecture.md +2 -2
- package/resources/skills/skills/meta/cue-usage/SKILL.md +1 -1
- package/resources/skills/skills/meta/profile-fit-monitor/SKILL.md +2 -2
- package/resources/skills/skills/meta/profile-optimizer/SKILL.md +1 -1
- package/resources/skills/skills/meta/profile-suggest/SKILL.md +7 -7
- package/resources/skills/skills/meta/profile-summon/SKILL.md +159 -0
- package/resources/skills/skills/meta/profile-summon/evals/evals.json +53 -0
- package/resources/skills/skills/meta/save-profile/SKILL.md +1 -1
- package/resources/skills/skills/meta/skill-reviewer/SKILL.md +3 -0
- package/resources/skills/skills/meta/skill-reviewer/references/tdd-for-skills.md +55 -0
- package/resources/skills/skills/research/find-skills/SKILL.md +1 -1
- package/resources/skills/skills/review/code-review-deep/SKILL.md +20 -0
- package/resources/skills/skills/security/trivy-scan/SKILL.md +139 -0
- package/resources/skills/skills/security/trivy-scan/scripts/ensure-trivy.sh +21 -0
- package/resources/skills/skills/tools/ccusage/SKILL.md +142 -0
- package/src/commands/_index.ts +8 -0
- package/src/commands/ai.ts +2 -2
- package/src/commands/auto-detect.test.ts +74 -0
- package/src/commands/auto-detect.ts +9 -7
- package/src/commands/cli.test.ts +20 -4
- package/src/commands/cli.ts +36 -20
- package/src/commands/create-profile.ts +2 -2
- package/src/commands/debug.ts +2 -2
- package/src/commands/discover.ts +14 -4
- package/src/commands/export-docker.ts +1 -1
- package/src/commands/features-batch1.test.ts +1 -1
- package/src/commands/gates.ts +1 -1
- package/src/commands/import-profile.ts +1 -1
- package/src/commands/init.ts +15 -11
- package/src/commands/install.test.ts +192 -0
- package/src/commands/install.ts +610 -0
- package/src/commands/launch-handoff.e2e.test.ts +33 -1
- package/src/commands/launch.e2e.test.ts +15 -10
- package/src/commands/launch.ts +73 -116
- package/src/commands/materialize.ts +2 -2
- package/src/commands/prune.ts +1 -1
- package/src/commands/security-audit.ts +1 -1
- package/src/commands/shell.ts +7 -7
- package/src/commands/skill-report.ts +1 -1
- package/src/commands/skills.ts +3 -3
- package/src/commands/snapshot.ts +2 -2
- package/src/commands/summon.test.ts +116 -0
- package/src/commands/summon.ts +338 -0
- package/src/commands/trigger-gaps.ts +1 -1
- package/src/commands/use.ts +47 -3
- package/src/commands/watch-live.ts +5 -5
- package/src/commands/watch.ts +8 -8
- package/src/index.ts +2 -0
- package/src/lib/active-sessions.test.ts +3 -3
- package/src/lib/active-sessions.ts +4 -4
- package/src/lib/auto-detect.test.ts +172 -8
- package/src/lib/auto-detect.ts +191 -136
- package/src/lib/codex-persona-parity.test.ts +58 -0
- package/src/lib/companion-detect.test.ts +43 -1
- package/src/lib/companion-detect.ts +35 -0
- package/src/lib/credentials-sync.test.ts +121 -1
- package/src/lib/credentials-sync.ts +95 -1
- package/src/lib/cwd-resolver.test.ts +8 -8
- package/src/lib/cwd-resolver.ts +2 -2
- package/src/lib/dashboard-merge.test.ts +9 -4
- package/src/lib/dashboard-server.ts +1 -1
- package/src/lib/picker.test.ts +1 -1
- package/src/lib/picker.ts +5 -5
- package/src/lib/profile-merge.test.ts +8 -0
- package/src/lib/profile-names.test.ts +3 -3
- package/src/lib/runtime-install.ts +166 -0
- package/src/lib/runtime-materializer.test.ts +137 -0
- package/src/lib/runtime-materializer.ts +105 -2
- package/src/lib/skill-router.test.ts +38 -0
- package/src/lib/skill-router.ts +65 -4
- package/profiles/eu-tender-research/README.md +0 -48
- package/profiles/eu-tender-research/logo.png +0 -0
- package/profiles/eu-tender-research/profile.yaml +0 -108
package/src/commands/debug.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `cue debug [profile]` — trace why skills/MCPs aren't loading.
|
|
3
3
|
*
|
|
4
4
|
* Walks the full resolution chain and reports at each step:
|
|
5
|
-
* - Profile resolution (which .cue
|
|
5
|
+
* - Profile resolution (which .cue.profile, inheritance chain)
|
|
6
6
|
* - Skill resolution (found/missing, path, size)
|
|
7
7
|
* - MCP resolution (in registry or not, env vars set)
|
|
8
8
|
* - Plugin resolution (installed or not)
|
|
@@ -45,7 +45,7 @@ export async function run(args: string[]): Promise<number> {
|
|
|
45
45
|
const resolved = await resolveProfileForCwd({ cwd, homeDir: homedir(), configDir: join(homedir(), ".config", "cue") });
|
|
46
46
|
if (resolved.source === "none") {
|
|
47
47
|
process.stdout.write(` ${red("✗")} No profile found for ${cwd}\n`);
|
|
48
|
-
process.stdout.write(` ${dim("Fix: echo <profile> > .cue
|
|
48
|
+
process.stdout.write(` ${dim("Fix: echo <profile> > .cue.profile or pass a profile name")}\n\n`);
|
|
49
49
|
return 1;
|
|
50
50
|
}
|
|
51
51
|
profileName = (resolved as any).profile;
|
package/src/commands/discover.ts
CHANGED
|
@@ -455,9 +455,9 @@ export function getInstalledIn(gem: GemRepo, profilesDir = join(REPO_ROOT, "prof
|
|
|
455
455
|
return hits;
|
|
456
456
|
}
|
|
457
457
|
|
|
458
|
-
/** Detect active profile from cwd (`.cue
|
|
458
|
+
/** Detect active profile from cwd (`.cue.profile` file). Returns undefined if none. */
|
|
459
459
|
export function getActiveProfile(cwd: string = process.cwd()): string | undefined {
|
|
460
|
-
const f = join(cwd, ".cue
|
|
460
|
+
const f = join(cwd, ".cue.profile");
|
|
461
461
|
if (!existsSync(f)) return undefined;
|
|
462
462
|
try {
|
|
463
463
|
const s = readFileSync(f, "utf8").trim();
|
|
@@ -1177,12 +1177,22 @@ ${cards}
|
|
|
1177
1177
|
// names), and so the repo's authors get a backlink from cue.dev.
|
|
1178
1178
|
// ---------------------------------------------------------------------------
|
|
1179
1179
|
|
|
1180
|
+
/**
|
|
1181
|
+
* Escape a string for a double-quoted YAML scalar in generated frontmatter.
|
|
1182
|
+
* Repo descriptions routinely contain `"` and `\` (e.g. `Tell Claude "deploy this"`),
|
|
1183
|
+
* which break Jekyll's YAML parser if interpolated raw — failing the landing build.
|
|
1184
|
+
* Escapes backslash + double-quote and collapses newlines to spaces.
|
|
1185
|
+
*/
|
|
1186
|
+
function yamlStr(s: string): string {
|
|
1187
|
+
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/[\r\n]+/g, " ");
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1180
1190
|
function buildRepoPage(gem: GemRepo, updated: string): string {
|
|
1181
1191
|
const icon = tierIcon(gem.gem_score);
|
|
1182
1192
|
const profileLinks = gem.suggested_profiles.map((p) => `[${p}](../${p}.md)`).join(", ") || "_(no profile match)_";
|
|
1183
1193
|
return `---
|
|
1184
|
-
title: "${gem.full_name} — Claude Code skill discovered by cue"
|
|
1185
|
-
description: "${(gem.description || `Claude Code skill from ${gem.full_name}`).slice(0, 160)}"
|
|
1194
|
+
title: "${yamlStr(`${gem.full_name} — Claude Code skill discovered by cue`)}"
|
|
1195
|
+
description: "${yamlStr((gem.description || `Claude Code skill from ${gem.full_name}`).slice(0, 160))}"
|
|
1186
1196
|
layout: page
|
|
1187
1197
|
updated: ${updated.split("T")[0]}
|
|
1188
1198
|
tags: [claude-code, skill, ${gem.suggested_profiles.join(", ")}]
|
|
@@ -54,7 +54,7 @@ describe("cue suggest", () => {
|
|
|
54
54
|
|
|
55
55
|
test("returns 1 with no active profile", async () => {
|
|
56
56
|
const { run } = await import("./suggest");
|
|
57
|
-
// Without a .cue
|
|
57
|
+
// Without a .cue.profile in cwd, should fail gracefully
|
|
58
58
|
const origCwd = process.cwd();
|
|
59
59
|
process.chdir(tmp);
|
|
60
60
|
const { code, stderr } = await capture(() => run([]));
|
package/src/commands/gates.ts
CHANGED
|
@@ -85,7 +85,7 @@ function helpText(): string {
|
|
|
85
85
|
function resolveActiveProfile(explicit: string | null): string | null {
|
|
86
86
|
if (explicit) return explicit;
|
|
87
87
|
// Pinned to cwd?
|
|
88
|
-
const pin = join(process.cwd(), ".cue
|
|
88
|
+
const pin = join(process.cwd(), ".cue.profile");
|
|
89
89
|
if (existsSync(pin)) {
|
|
90
90
|
try {
|
|
91
91
|
const txt = readFileSync(pin, "utf8").trim().split("\n")[0]?.trim();
|
|
@@ -86,7 +86,7 @@ async function cmdImport(args: string[]): Promise<number> {
|
|
|
86
86
|
|
|
87
87
|
process.stdout.write(`✅ Imported profile "${name}" to profiles/${name}/\n`);
|
|
88
88
|
process.stdout.write(` Activate with: cue use ${name}\n`);
|
|
89
|
-
process.stdout.write(` Pin with: echo ${name} > .cue
|
|
89
|
+
process.stdout.write(` Pin with: echo ${name} > .cue.profile\n`);
|
|
90
90
|
return 0;
|
|
91
91
|
}
|
|
92
92
|
|
package/src/commands/init.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* default-profile composite, opts into local analytics, and marks
|
|
7
7
|
* `.onboarded` so subsequent `cue init` calls skip straight to phase 2.
|
|
8
8
|
* 2. **Per-directory pinning** (always): scan cwd, suggest the best
|
|
9
|
-
* profile, write `.cue
|
|
9
|
+
* profile, write `.cue.profile`, offer to install discovered gems.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { spawnSync } from "node:child_process";
|
|
@@ -14,7 +14,7 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
|
14
14
|
import { dirname, join } from "node:path";
|
|
15
15
|
import * as p from "@clack/prompts";
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { detectProfileV2 } from "../lib/auto-detect";
|
|
18
18
|
import { scanProject } from "../lib/project-scanner";
|
|
19
19
|
import { listProfiles } from "../lib/profile-loader";
|
|
20
20
|
import { getCachedGemsForProfile, autoInstallClis } from "./discover";
|
|
@@ -61,18 +61,22 @@ export async function runGlobalOnboarding(): Promise<boolean> {
|
|
|
61
61
|
|
|
62
62
|
// Step 1: default-profile composite.
|
|
63
63
|
const defaultPick = await p.select<string>({
|
|
64
|
-
message: "Default profile — loads when no .cue
|
|
64
|
+
message: "Default profile — loads when no .cue.profile is pinned to a directory:",
|
|
65
65
|
options: [
|
|
66
|
+
{
|
|
67
|
+
value: "core",
|
|
68
|
+
label: "core only",
|
|
69
|
+
hint: "recommended - smallest default context",
|
|
70
|
+
},
|
|
66
71
|
{
|
|
67
72
|
value: "core+skill-writer",
|
|
68
73
|
label: "core + skill-writer",
|
|
69
|
-
hint: "
|
|
74
|
+
hint: "optional - add skill management when needed",
|
|
70
75
|
},
|
|
71
|
-
{ value: "core", label: "core only", hint: "smallest — just the base" },
|
|
72
76
|
{ value: "__custom", label: "Custom…", hint: "type a +-separated composite" },
|
|
73
77
|
{ value: "__skip", label: "Skip for now", hint: "falls back to plain `core`" },
|
|
74
78
|
],
|
|
75
|
-
initialValue: "core
|
|
79
|
+
initialValue: "core",
|
|
76
80
|
});
|
|
77
81
|
if (p.isCancel(defaultPick)) return false;
|
|
78
82
|
|
|
@@ -80,7 +84,7 @@ export async function runGlobalOnboarding(): Promise<boolean> {
|
|
|
80
84
|
if (defaultPick === "__custom") {
|
|
81
85
|
const custom = await p.text({
|
|
82
86
|
message: "Composite (e.g., core+skill-writer+backend):",
|
|
83
|
-
placeholder: "core
|
|
87
|
+
placeholder: "core",
|
|
84
88
|
validate: (v) => {
|
|
85
89
|
const parts = (v ?? "").split("+").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
86
90
|
if (parts.length === 0) return "Must contain at least one profile name";
|
|
@@ -244,7 +248,7 @@ export async function run(args: string[]): Promise<number> {
|
|
|
244
248
|
}
|
|
245
249
|
|
|
246
250
|
// Score
|
|
247
|
-
const suggestions =
|
|
251
|
+
const suggestions = detectProfileV2(cwd);
|
|
248
252
|
const allProfiles = await listProfiles();
|
|
249
253
|
|
|
250
254
|
// Present options
|
|
@@ -255,7 +259,7 @@ export async function run(args: string[]): Promise<number> {
|
|
|
255
259
|
options.push({
|
|
256
260
|
value: s.profile,
|
|
257
261
|
label: s.profile,
|
|
258
|
-
hint: `${s.confidence}% match — ${s.
|
|
262
|
+
hint: `${Math.round(s.confidence * 100)}% match — ${s.reasons.join(", ")}`,
|
|
259
263
|
});
|
|
260
264
|
}
|
|
261
265
|
|
|
@@ -303,7 +307,7 @@ export async function run(args: string[]): Promise<number> {
|
|
|
303
307
|
const { run: createProfile } = await import("./create-profile");
|
|
304
308
|
await createProfile([name as string, "--description", desc as string, "--icon", "🔧"]);
|
|
305
309
|
|
|
306
|
-
writeFileSync(join(cwd, ".cue
|
|
310
|
+
writeFileSync(join(cwd, ".cue.profile"), (name as string) + "\n");
|
|
307
311
|
await offerDiscoverGems(name as string);
|
|
308
312
|
await ensureShim();
|
|
309
313
|
p.outro(`✅ Created profile "${name}" and pinned to this directory.`);
|
|
@@ -311,7 +315,7 @@ export async function run(args: string[]): Promise<number> {
|
|
|
311
315
|
}
|
|
312
316
|
|
|
313
317
|
// Pin the chosen profile
|
|
314
|
-
writeFileSync(join(cwd, ".cue
|
|
318
|
+
writeFileSync(join(cwd, ".cue.profile"), (choice as string) + "\n");
|
|
315
319
|
await offerDiscoverGems(choice as string);
|
|
316
320
|
await ensureShim();
|
|
317
321
|
p.outro(`✅ Pinned "${choice}" to this directory. Next \`claude\` launch will use it.`);
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `cue install`. The command defaults to dry-run, so these never
|
|
3
|
+
* write real runtimes or execute package managers.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
7
|
+
import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
|
|
11
|
+
import { run as installRun } from "./install";
|
|
12
|
+
|
|
13
|
+
async function capture<T>(fn: () => Promise<T>): Promise<{ stdout: string; stderr: string; value: T }> {
|
|
14
|
+
const origOut = process.stdout.write.bind(process.stdout);
|
|
15
|
+
const origErr = process.stderr.write.bind(process.stderr);
|
|
16
|
+
let stdout = "";
|
|
17
|
+
let stderr = "";
|
|
18
|
+
(process.stdout as any).write = (c: string | Uint8Array) => { stdout += String(c); return true; };
|
|
19
|
+
(process.stderr as any).write = (c: string | Uint8Array) => { stderr += String(c); return true; };
|
|
20
|
+
try {
|
|
21
|
+
const value = await fn();
|
|
22
|
+
return { stdout, stderr, value };
|
|
23
|
+
} finally {
|
|
24
|
+
(process.stdout as any).write = origOut;
|
|
25
|
+
(process.stderr as any).write = origErr;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const envKeys = ["XDG_CONFIG_HOME", "CUE_PROFILES_DIR", "SOUL_PROFILES_DIR"] as const;
|
|
30
|
+
const oldEnv = new Map<string, string | undefined>();
|
|
31
|
+
for (const key of envKeys) oldEnv.set(key, process.env[key]);
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
for (const key of envKeys) {
|
|
35
|
+
const value = oldEnv.get(key);
|
|
36
|
+
if (value === undefined) delete process.env[key];
|
|
37
|
+
else process.env[key] = value;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("cue install", () => {
|
|
42
|
+
test("dry-run JSON plans Claude and Codex runtimes for an explicit profile", async () => {
|
|
43
|
+
const root = mkdtempSync(join(tmpdir(), "cue-install-test-"));
|
|
44
|
+
process.env.XDG_CONFIG_HOME = root;
|
|
45
|
+
try {
|
|
46
|
+
const { stdout, value } = await capture(() => installRun(["core", "--json"]));
|
|
47
|
+
expect(value).toBe(0);
|
|
48
|
+
const out = JSON.parse(stdout) as {
|
|
49
|
+
dryRun: boolean;
|
|
50
|
+
profiles: string[];
|
|
51
|
+
agents: string[];
|
|
52
|
+
actions: Array<{ profile: string; agent: string; targetDir: string; status: string }>;
|
|
53
|
+
};
|
|
54
|
+
expect(out.dryRun).toBe(true);
|
|
55
|
+
expect(out.profiles).toEqual(["core"]);
|
|
56
|
+
expect(out.agents).toEqual(["claude-code", "codex"]);
|
|
57
|
+
expect(out.actions.map((a) => [a.profile, a.agent, a.status])).toEqual([
|
|
58
|
+
["core", "claude-code", "planned"],
|
|
59
|
+
["core", "codex", "planned"],
|
|
60
|
+
]);
|
|
61
|
+
expect(out.actions[0]!.targetDir).toContain(join(root, "cue", "runtime", "core"));
|
|
62
|
+
} finally {
|
|
63
|
+
rmSync(root, { recursive: true, force: true });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("--all-profiles uses the configured profile directory in dry-run", async () => {
|
|
68
|
+
const root = mkdtempSync(join(tmpdir(), "cue-install-test-"));
|
|
69
|
+
const profiles = join(root, "profiles");
|
|
70
|
+
mkdirSync(join(profiles, "alpha"), { recursive: true });
|
|
71
|
+
mkdirSync(join(profiles, "beta"), { recursive: true });
|
|
72
|
+
writeFileSync(join(profiles, "alpha", "profile.yaml"), "name: alpha\ndescription: Alpha profile\n");
|
|
73
|
+
writeFileSync(join(profiles, "beta", "profile.yaml"), "name: beta\ndescription: Beta profile\n");
|
|
74
|
+
process.env.CUE_PROFILES_DIR = profiles;
|
|
75
|
+
process.env.XDG_CONFIG_HOME = root;
|
|
76
|
+
try {
|
|
77
|
+
const { stdout, value } = await capture(() => installRun(["--all-profiles", "--agents", "claude", "--json"]));
|
|
78
|
+
expect(value).toBe(0);
|
|
79
|
+
const out = JSON.parse(stdout) as {
|
|
80
|
+
profiles: string[];
|
|
81
|
+
agents: string[];
|
|
82
|
+
actions: Array<{ profile: string; agent: string; status: string }>;
|
|
83
|
+
};
|
|
84
|
+
expect(out.profiles).toEqual(["alpha", "beta"]);
|
|
85
|
+
expect(out.agents).toEqual(["claude-code"]);
|
|
86
|
+
expect(out.actions).toHaveLength(2);
|
|
87
|
+
expect(out.actions.every((a) => a.status === "planned")).toBe(true);
|
|
88
|
+
} finally {
|
|
89
|
+
rmSync(root, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("--with-clis --json includes CLI plans without executing installers", async () => {
|
|
94
|
+
const root = mkdtempSync(join(tmpdir(), "cue-install-test-"));
|
|
95
|
+
process.env.XDG_CONFIG_HOME = root;
|
|
96
|
+
try {
|
|
97
|
+
const { stdout, value } = await capture(() => installRun(["core", "--with-clis", "--json"]));
|
|
98
|
+
expect(value).toBe(0);
|
|
99
|
+
const out = JSON.parse(stdout) as {
|
|
100
|
+
dryRun: boolean;
|
|
101
|
+
cliResults: Array<{ profile: string; code: number; plan?: { plans?: unknown[]; text?: string } }>;
|
|
102
|
+
};
|
|
103
|
+
expect(out.dryRun).toBe(true);
|
|
104
|
+
expect(out.cliResults).toHaveLength(1);
|
|
105
|
+
expect(out.cliResults[0]!.profile).toBe("core");
|
|
106
|
+
expect(out.cliResults[0]!.code).toBe(0);
|
|
107
|
+
expect(out.cliResults[0]!.plan?.plans || out.cliResults[0]!.plan?.text).toBeTruthy();
|
|
108
|
+
} finally {
|
|
109
|
+
rmSync(root, { recursive: true, force: true });
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("external agents require explicit scope and stay dry-run by default", async () => {
|
|
114
|
+
const root = mkdtempSync(join(tmpdir(), "cue-install-test-"));
|
|
115
|
+
const target = join(root, "target");
|
|
116
|
+
process.env.XDG_CONFIG_HOME = root;
|
|
117
|
+
try {
|
|
118
|
+
const { stdout, value } = await capture(() => installRun(["core", "--agents", "cursor", "--dir", target, "--json"]));
|
|
119
|
+
expect(value).toBe(0);
|
|
120
|
+
const out = JSON.parse(stdout) as {
|
|
121
|
+
dryRun: boolean;
|
|
122
|
+
agents: string[];
|
|
123
|
+
actions: Array<{ agent: string; targetDir: string; status: string }>;
|
|
124
|
+
};
|
|
125
|
+
expect(out.dryRun).toBe(true);
|
|
126
|
+
expect(out.agents).toEqual(["cursor"]);
|
|
127
|
+
expect(out.actions[0]).toMatchObject({ agent: "cursor", targetDir: target, status: "planned" });
|
|
128
|
+
} finally {
|
|
129
|
+
rmSync(root, { recursive: true, force: true });
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("doctor JSON reports profile runtime checks", async () => {
|
|
134
|
+
const root = mkdtempSync(join(tmpdir(), "cue-install-test-"));
|
|
135
|
+
process.env.XDG_CONFIG_HOME = root;
|
|
136
|
+
try {
|
|
137
|
+
const { stdout } = await capture(() => installRun(["doctor", "core", "--json"]));
|
|
138
|
+
const out = JSON.parse(stdout) as { reports: Array<{ profile: string; agent: string; missingMcps: string[] }> };
|
|
139
|
+
expect(out.reports.length).toBeGreaterThan(0);
|
|
140
|
+
expect(out.reports[0]!.profile).toBe("core");
|
|
141
|
+
} finally {
|
|
142
|
+
rmSync(root, { recursive: true, force: true });
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("repo installer dry-run describes clone without network", async () => {
|
|
147
|
+
const root = mkdtempSync(join(tmpdir(), "cue-install-test-"));
|
|
148
|
+
process.env.XDG_CONFIG_HOME = root;
|
|
149
|
+
try {
|
|
150
|
+
const { stdout, value } = await capture(() => installRun(["repo", "garrytan/gstack", "--profile", "maker", "--json"]));
|
|
151
|
+
expect(value).toBe(0);
|
|
152
|
+
const out = JSON.parse(stdout) as { dryRun: boolean; repo: string; profile: string; discoveredSkills: string[] };
|
|
153
|
+
expect(out.dryRun).toBe(true);
|
|
154
|
+
expect(out.repo).toBe("garrytan/gstack");
|
|
155
|
+
expect(out.profile).toBe("maker");
|
|
156
|
+
expect(out.discoveredSkills).toEqual([]);
|
|
157
|
+
} finally {
|
|
158
|
+
rmSync(root, { recursive: true, force: true });
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("repo installer accepts flags before the repo argument", async () => {
|
|
163
|
+
const root = mkdtempSync(join(tmpdir(), "cue-install-test-"));
|
|
164
|
+
process.env.XDG_CONFIG_HOME = root;
|
|
165
|
+
try {
|
|
166
|
+
const { stdout, value } = await capture(() => installRun(["repo", "--profile", "maker", "garrytan/gstack", "--json"]));
|
|
167
|
+
expect(value).toBe(0);
|
|
168
|
+
const out = JSON.parse(stdout) as { repo: string; profile: string };
|
|
169
|
+
expect(out.repo).toBe("garrytan/gstack");
|
|
170
|
+
expect(out.profile).toBe("maker");
|
|
171
|
+
} finally {
|
|
172
|
+
rmSync(root, { recursive: true, force: true });
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("missing profile context returns a usage-level error", async () => {
|
|
177
|
+
const cwd = process.cwd();
|
|
178
|
+
const dir = mkdtempSync(join(tmpdir(), "cue-install-cwd-"));
|
|
179
|
+
const configRoot = mkdtempSync(join(tmpdir(), "cue-install-empty-config-"));
|
|
180
|
+
try {
|
|
181
|
+
process.env.XDG_CONFIG_HOME = configRoot;
|
|
182
|
+
process.chdir(dir);
|
|
183
|
+
const { stderr, value } = await capture(() => installRun(["--json"]));
|
|
184
|
+
expect(value).toBe(1);
|
|
185
|
+
expect(stderr).toContain("no active profile");
|
|
186
|
+
} finally {
|
|
187
|
+
process.chdir(cwd);
|
|
188
|
+
rmSync(dir, { recursive: true, force: true });
|
|
189
|
+
rmSync(configRoot, { recursive: true, force: true });
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|