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.
Files changed (278) hide show
  1. package/CHANGELOG.md +4 -3
  2. package/README.md +148 -170
  3. package/bin/cue-learnings +30 -4
  4. package/bin/cue-review-progress +0 -0
  5. package/bin/cue-review-watch +0 -0
  6. package/dist/cue.js +4328 -3108
  7. package/package.json +1 -1
  8. package/plugins/cue/commands/cue-switch.md +1 -1
  9. package/plugins/cue/commands/cue.md +1 -1
  10. package/profiles/backend/profile.yaml +4 -0
  11. package/profiles/browser/profile.yaml +4 -0
  12. package/profiles/career/profile.yaml +2 -13
  13. package/profiles/commerce/profile.yaml +0 -2
  14. package/profiles/coolify/profile.yaml +0 -1
  15. package/profiles/core/profile.yaml +78 -11
  16. package/profiles/dash-merge-test/profile.yaml +6 -1
  17. package/profiles/designer/profile.yaml +9 -1
  18. package/profiles/dropshipping/profile.yaml +69 -0
  19. package/profiles/frontend/profile.yaml +4 -0
  20. package/profiles/google-ads/profile.yaml +34 -0
  21. package/profiles/google-analytics/profile.yaml +34 -0
  22. package/profiles/google-drive/profile.yaml +34 -0
  23. package/profiles/gstack/profile.yaml +117 -29
  24. package/profiles/marketing/profile.yaml +0 -1
  25. package/profiles/media/README.md +70 -0
  26. package/profiles/media/profile.yaml +104 -0
  27. package/profiles/nano-banana/profile.yaml +52 -0
  28. package/profiles/ops/profile.yaml +1 -2
  29. package/profiles/secops/profile.yaml +3 -0
  30. package/profiles/skill-writer/profile.yaml +15 -0
  31. package/profiles/video/profile.yaml +3 -0
  32. package/profiles/web-frontend-base/profile.yaml +6 -0
  33. package/profiles/webshop/profile.yaml +0 -1
  34. package/profiles/webshop-google/profile.yaml +1 -0
  35. package/profiles/x-growth-bot/profile.yaml +2 -0
  36. package/resources/icons/generate-icons.py +2 -128
  37. package/resources/mcps/configs/claude.sanitized.json +88 -20
  38. package/resources/mcps/configs/claude_runtime.sanitized.json +40 -1
  39. package/resources/mcps/configs/codex.sanitized.json +29 -0
  40. package/resources/skills/skills/career/job-hunter/LICENSE +21 -0
  41. package/resources/skills/skills/career/job-hunter/README.md +323 -0
  42. package/resources/skills/skills/career/job-hunter/SKILL.md +91 -0
  43. package/resources/skills/skills/career/job-hunter/agents/README.md +96 -0
  44. package/resources/skills/skills/career/job-hunter/agents/apply-assessment-prep.md +195 -0
  45. package/resources/skills/skills/career/job-hunter/agents/apply-ats-scan.md +155 -0
  46. package/resources/skills/skills/career/job-hunter/agents/apply-bias-audit.md +224 -0
  47. package/resources/skills/skills/career/job-hunter/agents/apply-cover-letter.md +69 -0
  48. package/resources/skills/skills/career/job-hunter/agents/apply-decode-jd.md +117 -0
  49. package/resources/skills/skills/career/job-hunter/agents/apply-fit-score.md +183 -0
  50. package/resources/skills/skills/career/job-hunter/agents/apply-linkedin-audit.md +74 -0
  51. package/resources/skills/skills/career/job-hunter/agents/apply-linkedin-scrape.md +255 -0
  52. package/resources/skills/skills/career/job-hunter/agents/apply-portfolio-brief.md +123 -0
  53. package/resources/skills/skills/career/job-hunter/agents/apply-reality-check.md +164 -0
  54. package/resources/skills/skills/career/job-hunter/agents/apply-reference-prep.md +150 -0
  55. package/resources/skills/skills/career/job-hunter/agents/apply-rejection-analysis.md +172 -0
  56. package/resources/skills/skills/career/job-hunter/agents/apply-resume.md +70 -0
  57. package/resources/skills/skills/career/job-hunter/agents/apply-skills-gap-filler.md +109 -0
  58. package/resources/skills/skills/career/job-hunter/agents/career-internal.md +94 -0
  59. package/resources/skills/skills/career/job-hunter/agents/career-linkedin-content.md +173 -0
  60. package/resources/skills/skills/career/job-hunter/agents/career-linkedin-scanner.md +262 -0
  61. package/resources/skills/skills/career/job-hunter/agents/career-network-message.md +108 -0
  62. package/resources/skills/skills/career/job-hunter/agents/career-promote.md +102 -0
  63. package/resources/skills/skills/career/job-hunter/agents/career-review.md +71 -0
  64. package/resources/skills/skills/career/job-hunter/agents/interview-debrief.md +117 -0
  65. package/resources/skills/skills/career/job-hunter/agents/interview-mock.md +171 -0
  66. package/resources/skills/skills/career/job-hunter/agents/interview-panel-decoder.md +152 -0
  67. package/resources/skills/skills/career/job-hunter/agents/interview-prep.md +184 -0
  68. package/resources/skills/skills/career/job-hunter/agents/interview-question-bank.md +133 -0
  69. package/resources/skills/skills/career/job-hunter/agents/interview-research.md +148 -0
  70. package/resources/skills/skills/career/job-hunter/agents/offer-compare.md +117 -0
  71. package/resources/skills/skills/career/job-hunter/agents/offer-counteroffer.md +144 -0
  72. package/resources/skills/skills/career/job-hunter/agents/offer-deadline-manager.md +148 -0
  73. package/resources/skills/skills/career/job-hunter/agents/offer-negotiate.md +126 -0
  74. package/resources/skills/skills/career/job-hunter/agents/offer-schedule.md +99 -0
  75. package/resources/skills/skills/career/job-hunter/agents/offer-thankyou.md +80 -0
  76. package/resources/skills/skills/career/job-hunter/agents/search-company-research.md +146 -0
  77. package/resources/skills/skills/career/job-hunter/agents/search-follow-up.md +129 -0
  78. package/resources/skills/skills/career/job-hunter/agents/search-ghost-job-detector.md +152 -0
  79. package/resources/skills/skills/career/job-hunter/agents/search-inbox-scan.md +193 -0
  80. package/resources/skills/skills/career/job-hunter/agents/search-interview-scorecard.md +164 -0
  81. package/resources/skills/skills/career/job-hunter/agents/search-jobs.md +149 -0
  82. package/resources/skills/skills/career/job-hunter/agents/search-momentum-check.md +194 -0
  83. package/resources/skills/skills/career/job-hunter/agents/search-outreach.md +85 -0
  84. package/resources/skills/skills/career/job-hunter/agents/search-referral-finder.md +124 -0
  85. package/resources/skills/skills/career/job-hunter/agents/search-salary.md +96 -0
  86. package/resources/skills/skills/career/job-hunter/agents/search-send-email.md +109 -0
  87. package/resources/skills/skills/career/job-hunter/agents/search-tracker-update.md +127 -0
  88. package/resources/skills/skills/career/job-hunter/inputs/README.md +26 -0
  89. package/resources/skills/skills/career/job-hunter/inputs/apply-linkedin-url.txt +8 -0
  90. package/resources/skills/skills/career/job-hunter/inputs/interview-context.md +24 -0
  91. package/resources/skills/skills/career/job-hunter/inputs/job-description.md +20 -0
  92. package/resources/skills/skills/career/job-hunter/inputs/job-search-criteria.md +36 -0
  93. package/resources/skills/skills/career/job-hunter/inputs/my-linkedin.md +24 -0
  94. package/resources/skills/skills/career/job-hunter/inputs/my-resume.md +28 -0
  95. package/resources/skills/skills/career/job-hunter/inputs/search-outreach-target.md +24 -0
  96. package/resources/skills/skills/career/job-hunter/rules/README.md +37 -0
  97. package/resources/skills/skills/career/job-hunter/rules/writing-rules.md +81 -0
  98. package/resources/skills/skills/design/banana/SKILL.md +375 -0
  99. package/resources/skills/skills/design/banana/references/cost-tracking.md +47 -0
  100. package/resources/skills/skills/design/banana/references/gemini-models.md +236 -0
  101. package/resources/skills/skills/design/banana/references/mcp-tools.md +145 -0
  102. package/resources/skills/skills/design/banana/references/post-processing.md +192 -0
  103. package/resources/skills/skills/design/banana/references/presets.md +69 -0
  104. package/resources/skills/skills/design/banana/references/prompt-engineering.md +481 -0
  105. package/resources/skills/skills/design/banana/scripts/batch.py +97 -0
  106. package/resources/skills/skills/design/banana/scripts/cost_tracker.py +191 -0
  107. package/resources/skills/skills/design/banana/scripts/edit.py +159 -0
  108. package/resources/skills/skills/design/banana/scripts/generate.py +168 -0
  109. package/resources/skills/skills/design/banana/scripts/presets.py +154 -0
  110. package/resources/skills/skills/design/banana/scripts/setup_mcp.py +151 -0
  111. package/resources/skills/skills/design/banana/scripts/validate_setup.py +133 -0
  112. package/resources/skills/skills/gstack/ship/SKILL.md +13 -0
  113. package/resources/skills/skills/media/3d-logo-animation/SKILL.md +59 -0
  114. package/resources/skills/skills/media/action-figure-generator/SKILL.md +48 -0
  115. package/resources/skills/skills/media/ad-creative/SKILL.md +79 -0
  116. package/resources/skills/skills/media/ai-clipping/SKILL.md +194 -0
  117. package/resources/skills/skills/media/ai-clipping/scripts/run-ai-clipping.sh +200 -0
  118. package/resources/skills/skills/media/ai-fight-scene/SKILL.md +132 -0
  119. package/resources/skills/skills/media/amazon-product-listing/SKILL.md +68 -0
  120. package/resources/skills/skills/media/animal-video-generator/SKILL.md +59 -0
  121. package/resources/skills/skills/media/award-ceremony-video/SKILL.md +87 -0
  122. package/resources/skills/skills/media/blog-header/SKILL.md +61 -0
  123. package/resources/skills/skills/media/brand-kit/SKILL.md +72 -0
  124. package/resources/skills/skills/media/brochures/SKILL.md +65 -0
  125. package/resources/skills/skills/media/cartoon-dance-animation/SKILL.md +62 -0
  126. package/resources/skills/skills/media/character-story-video/SKILL.md +84 -0
  127. package/resources/skills/skills/media/chibi-collage-effect/SKILL.md +63 -0
  128. package/resources/skills/skills/media/cinema-director/SKILL.md +93 -0
  129. package/resources/skills/skills/media/cinema-director/scripts/generate-film.sh +78 -0
  130. package/resources/skills/skills/media/color-analysis-board/SKILL.md +71 -0
  131. package/resources/skills/skills/media/core-edit/SKILL.md +48 -0
  132. package/resources/skills/skills/media/core-edit/edit-image.sh +54 -0
  133. package/resources/skills/skills/media/core-edit/enhance-image.sh +191 -0
  134. package/resources/skills/skills/media/core-edit/lipsync.sh +144 -0
  135. package/resources/skills/skills/media/core-edit/video-effects.sh +193 -0
  136. package/resources/skills/skills/media/core-media/SKILL.md +49 -0
  137. package/resources/skills/skills/media/core-media/create-music.sh +169 -0
  138. package/resources/skills/skills/media/core-media/generate-image.sh +161 -0
  139. package/resources/skills/skills/media/core-media/generate-video.sh +137 -0
  140. package/resources/skills/skills/media/core-media/image-to-video.sh +228 -0
  141. package/resources/skills/skills/media/core-media/schema_data.json +18708 -0
  142. package/resources/skills/skills/media/core-media/upload.sh +41 -0
  143. package/resources/skills/skills/media/core-platform/SKILL.md +41 -0
  144. package/resources/skills/skills/media/core-platform/check-result.sh +37 -0
  145. package/resources/skills/skills/media/core-platform/setup.sh +31 -0
  146. package/resources/skills/skills/media/couple-grid-creator/SKILL.md +47 -0
  147. package/resources/skills/skills/media/design-guide/SKILL.md +73 -0
  148. package/resources/skills/skills/media/drone-style-video/SKILL.md +61 -0
  149. package/resources/skills/skills/media/fashion-try-on/SKILL.md +61 -0
  150. package/resources/skills/skills/media/floor-plan-rendering/SKILL.md +56 -0
  151. package/resources/skills/skills/media/freeze-effect-video/SKILL.md +100 -0
  152. package/resources/skills/skills/media/giant-product-showcase/SKILL.md +61 -0
  153. package/resources/skills/skills/media/instagram-post/SKILL.md +58 -0
  154. package/resources/skills/skills/media/interior-design/SKILL.md +61 -0
  155. package/resources/skills/skills/media/interior-design-visualizer/SKILL.md +57 -0
  156. package/resources/skills/skills/media/jewelry-product-video/SKILL.md +61 -0
  157. package/resources/skills/skills/media/kdenlive/SKILL.md +106 -0
  158. package/resources/skills/skills/media/kdenlive/scripts/assemble.sh +57 -0
  159. package/resources/skills/skills/media/kdenlive/scripts/common.sh +30 -0
  160. package/resources/skills/skills/media/kdenlive/scripts/inspect.sh +19 -0
  161. package/resources/skills/skills/media/kdenlive/scripts/reframe.sh +22 -0
  162. package/resources/skills/skills/media/kdenlive/scripts/render.sh +16 -0
  163. package/resources/skills/skills/media/kdenlive/scripts/title-card.sh +25 -0
  164. package/resources/skills/skills/media/keyboard-art-maker/SKILL.md +44 -0
  165. package/resources/skills/skills/media/logo-branding/SKILL.md +70 -0
  166. package/resources/skills/skills/media/logo-creator/SKILL.md +80 -0
  167. package/resources/skills/skills/media/logo-creator/scripts/create-logo.sh +38 -0
  168. package/resources/skills/skills/media/logo-generator/SKILL.md +56 -0
  169. package/resources/skills/skills/media/multi-angle-reshoot/SKILL.md +70 -0
  170. package/resources/skills/skills/media/multi-angle-shots/SKILL.md +73 -0
  171. package/resources/skills/skills/media/music-video/SKILL.md +61 -0
  172. package/resources/skills/skills/media/nano-banana/SKILL.md +80 -0
  173. package/resources/skills/skills/media/nano-banana/scripts/generate-nano-art.sh +54 -0
  174. package/resources/skills/skills/media/one-shot-video/SKILL.md +56 -0
  175. package/resources/skills/skills/media/photo-pack-generator/SKILL.md +205 -0
  176. package/resources/skills/skills/media/photo-pack-generator/scripts/generate-pack.sh +241 -0
  177. package/resources/skills/skills/media/product-ad-cinematic/SKILL.md +78 -0
  178. package/resources/skills/skills/media/product-campaign/SKILL.md +76 -0
  179. package/resources/skills/skills/media/product-showcase-video/SKILL.md +60 -0
  180. package/resources/skills/skills/media/product-video-ad-maker/SKILL.md +59 -0
  181. package/resources/skills/skills/media/rednote-cover/SKILL.md +57 -0
  182. package/resources/skills/skills/media/seedance-2/SKILL.md +632 -0
  183. package/resources/skills/skills/media/seedance-2/scripts/generate-seedance.sh +701 -0
  184. package/resources/skills/skills/media/selfie-with-celebrities/SKILL.md +64 -0
  185. package/resources/skills/skills/media/social-media-video/SKILL.md +277 -0
  186. package/resources/skills/skills/media/social-media-video/scripts/run-social-video.sh +316 -0
  187. package/resources/skills/skills/media/social-pack/SKILL.md +58 -0
  188. package/resources/skills/skills/media/storyboard/SKILL.md +57 -0
  189. package/resources/skills/skills/media/storyboard-to-cooking-video/SKILL.md +143 -0
  190. package/resources/skills/skills/media/talking-baby-video/SKILL.md +57 -0
  191. package/resources/skills/skills/media/ugc-ads-workflow/SKILL.md +70 -0
  192. package/resources/skills/skills/media/ugc-lifestyle-try-on/SKILL.md +65 -0
  193. package/resources/skills/skills/media/ugc-video-factory/SKILL.md +134 -0
  194. package/resources/skills/skills/media/ui-design/SKILL.md +81 -0
  195. package/resources/skills/skills/media/ui-design/scripts/generate-mockup.sh +49 -0
  196. package/resources/skills/skills/media/url-to-design/SKILL.md +61 -0
  197. package/resources/skills/skills/media/workflow/SKILL.md +197 -0
  198. package/resources/skills/skills/media/workflow/scripts/discover-workflow.sh +18 -0
  199. package/resources/skills/skills/media/workflow/scripts/generate-workflow.sh +33 -0
  200. package/resources/skills/skills/media/workflow/scripts/interactive-run.sh +16 -0
  201. package/resources/skills/skills/media/workflow/scripts/list-workflows.sh +20 -0
  202. package/resources/skills/skills/media/workflow/scripts/run-workflow.sh +34 -0
  203. package/resources/skills/skills/media/youtube-shorts/SKILL.md +173 -0
  204. package/resources/skills/skills/media/youtube-shorts/scripts/run-youtube-shorts.sh +141 -0
  205. package/resources/skills/skills/media/youtube-thumbnail/SKILL.md +66 -0
  206. package/resources/skills/skills/meta/cue-developer/references/architecture.md +2 -2
  207. package/resources/skills/skills/meta/cue-usage/SKILL.md +1 -1
  208. package/resources/skills/skills/meta/profile-fit-monitor/SKILL.md +2 -2
  209. package/resources/skills/skills/meta/profile-optimizer/SKILL.md +1 -1
  210. package/resources/skills/skills/meta/profile-suggest/SKILL.md +7 -7
  211. package/resources/skills/skills/meta/profile-summon/SKILL.md +159 -0
  212. package/resources/skills/skills/meta/profile-summon/evals/evals.json +53 -0
  213. package/resources/skills/skills/meta/save-profile/SKILL.md +1 -1
  214. package/resources/skills/skills/meta/skill-reviewer/SKILL.md +3 -0
  215. package/resources/skills/skills/meta/skill-reviewer/references/tdd-for-skills.md +55 -0
  216. package/resources/skills/skills/research/find-skills/SKILL.md +1 -1
  217. package/resources/skills/skills/review/code-review-deep/SKILL.md +20 -0
  218. package/resources/skills/skills/security/trivy-scan/SKILL.md +139 -0
  219. package/resources/skills/skills/security/trivy-scan/scripts/ensure-trivy.sh +21 -0
  220. package/resources/skills/skills/tools/ccusage/SKILL.md +142 -0
  221. package/src/commands/_index.ts +8 -0
  222. package/src/commands/ai.ts +2 -2
  223. package/src/commands/auto-detect.test.ts +74 -0
  224. package/src/commands/auto-detect.ts +9 -7
  225. package/src/commands/cli.test.ts +20 -4
  226. package/src/commands/cli.ts +36 -20
  227. package/src/commands/create-profile.ts +2 -2
  228. package/src/commands/debug.ts +2 -2
  229. package/src/commands/discover.ts +14 -4
  230. package/src/commands/export-docker.ts +1 -1
  231. package/src/commands/features-batch1.test.ts +1 -1
  232. package/src/commands/gates.ts +1 -1
  233. package/src/commands/import-profile.ts +1 -1
  234. package/src/commands/init.ts +15 -11
  235. package/src/commands/install.test.ts +192 -0
  236. package/src/commands/install.ts +610 -0
  237. package/src/commands/launch-handoff.e2e.test.ts +33 -1
  238. package/src/commands/launch.e2e.test.ts +15 -10
  239. package/src/commands/launch.ts +73 -116
  240. package/src/commands/materialize.ts +2 -2
  241. package/src/commands/prune.ts +1 -1
  242. package/src/commands/security-audit.ts +1 -1
  243. package/src/commands/shell.ts +7 -7
  244. package/src/commands/skill-report.ts +1 -1
  245. package/src/commands/skills.ts +3 -3
  246. package/src/commands/snapshot.ts +2 -2
  247. package/src/commands/summon.test.ts +116 -0
  248. package/src/commands/summon.ts +338 -0
  249. package/src/commands/trigger-gaps.ts +1 -1
  250. package/src/commands/use.ts +47 -3
  251. package/src/commands/watch-live.ts +5 -5
  252. package/src/commands/watch.ts +8 -8
  253. package/src/index.ts +2 -0
  254. package/src/lib/active-sessions.test.ts +3 -3
  255. package/src/lib/active-sessions.ts +4 -4
  256. package/src/lib/auto-detect.test.ts +172 -8
  257. package/src/lib/auto-detect.ts +191 -136
  258. package/src/lib/codex-persona-parity.test.ts +58 -0
  259. package/src/lib/companion-detect.test.ts +43 -1
  260. package/src/lib/companion-detect.ts +35 -0
  261. package/src/lib/credentials-sync.test.ts +121 -1
  262. package/src/lib/credentials-sync.ts +95 -1
  263. package/src/lib/cwd-resolver.test.ts +8 -8
  264. package/src/lib/cwd-resolver.ts +2 -2
  265. package/src/lib/dashboard-merge.test.ts +9 -4
  266. package/src/lib/dashboard-server.ts +1 -1
  267. package/src/lib/picker.test.ts +1 -1
  268. package/src/lib/picker.ts +5 -5
  269. package/src/lib/profile-merge.test.ts +8 -0
  270. package/src/lib/profile-names.test.ts +3 -3
  271. package/src/lib/runtime-install.ts +166 -0
  272. package/src/lib/runtime-materializer.test.ts +137 -0
  273. package/src/lib/runtime-materializer.ts +105 -2
  274. package/src/lib/skill-router.test.ts +38 -0
  275. package/src/lib/skill-router.ts +65 -4
  276. package/profiles/eu-tender-research/README.md +0 -48
  277. package/profiles/eu-tender-research/logo.png +0 -0
  278. package/profiles/eu-tender-research/profile.yaml +0 -108
@@ -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-profile, inheritance chain)
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-profile or pass a profile name")}\n\n`);
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;
@@ -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-profile` file). Returns undefined if none. */
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-profile");
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(", ")}]
@@ -108,7 +108,7 @@ COPY resources/ /app/resources/
108
108
  WORKDIR /app
109
109
 
110
110
  # Pin profile
111
- RUN echo "${profileName}" > .cue-profile
111
+ RUN echo "${profileName}" > .cue.profile
112
112
 
113
113
  # Pre-materialize runtime
114
114
  RUN cue use ${profileName} || true
@@ -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-profile in cwd, should fail gracefully
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([]));
@@ -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-profile");
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-profile\n`);
89
+ process.stdout.write(` Pin with: echo ${name} > .cue.profile\n`);
90
90
  return 0;
91
91
  }
92
92
 
@@ -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-profile`, offer to install discovered gems.
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 { detectProfile } from "../lib/auto-detect";
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-profile is pinned to a directory:",
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: "recommended minimal base plus skill management",
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+skill-writer",
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+skill-writer",
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 = detectProfile(cwd);
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.signals.join(", ")}`,
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-profile"), (name as string) + "\n");
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-profile"), (choice as string) + "\n");
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
+ });