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.
Files changed (310) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +82 -33
  3. package/bin/cue-review-progress +107 -0
  4. package/bin/cue-review-watch +98 -0
  5. package/dist/cue.js +7352 -3744
  6. package/package.json +16 -5
  7. package/profiles/_types.ts +9 -0
  8. package/profiles/backend/profile.yaml +2 -0
  9. package/profiles/blog-writer/profile.yaml +10 -0
  10. package/profiles/browser/profile.yaml +9 -2
  11. package/profiles/builder/profile.yaml +3 -6
  12. package/profiles/career/profile.yaml +13 -2
  13. package/profiles/claude-api/profile.yaml +1 -1
  14. package/profiles/commerce/profile.yaml +27 -3
  15. package/profiles/core/logo.png +0 -0
  16. package/profiles/core/profile.yaml +62 -2
  17. package/profiles/dash-merge-test/profile.yaml +109 -0
  18. package/profiles/designer/profile.yaml +2 -0
  19. package/profiles/designer-medusa-next/profile.yaml +4 -1
  20. package/profiles/designer-medusa-vite/profile.yaml +4 -1
  21. package/profiles/docs-writer/profile.yaml +3 -1
  22. package/profiles/eu-tender-research/README.md +48 -0
  23. package/profiles/eu-tender-research/logo.png +0 -0
  24. package/profiles/eu-tender-research/profile.yaml +108 -0
  25. package/profiles/finance/logo.png +0 -0
  26. package/profiles/finance/profile.yaml +46 -0
  27. package/profiles/frontend/profile.yaml +5 -9
  28. package/profiles/growth/profile.yaml +2 -3
  29. package/profiles/gstack/profile.yaml +15 -0
  30. package/profiles/higgsfield/profile.yaml +3 -0
  31. package/profiles/hyperframes/logo.png +0 -0
  32. package/profiles/hyperframes/profile.yaml +59 -0
  33. package/profiles/improver/profile.yaml +88 -0
  34. package/profiles/marketing/profile.yaml +0 -3
  35. package/profiles/medusa-dev/profile.yaml +2 -0
  36. package/profiles/medusa-next/profile.yaml +2 -3
  37. package/profiles/medusa-vite/profile.yaml +2 -3
  38. package/profiles/n8n/logo.png +0 -0
  39. package/profiles/n8n/profile.yaml +50 -0
  40. package/profiles/nextjs/profile.yaml +2 -3
  41. package/profiles/ops/profile.yaml +2 -0
  42. package/profiles/postizz/profile.yaml +13 -3
  43. package/profiles/python/profile.yaml +3 -0
  44. package/profiles/research/profile.yaml +3 -1
  45. package/profiles/schema.json +10 -0
  46. package/profiles/secops/profile.yaml +2 -0
  47. package/profiles/seo/profile.yaml +56 -0
  48. package/profiles/skill-writer/profile.yaml +8 -0
  49. package/profiles/ssh/profile.yaml +32 -0
  50. package/profiles/strapi/logo.png +0 -0
  51. package/profiles/strapi/profile.yaml +45 -0
  52. package/profiles/stripe/logo.png +0 -0
  53. package/profiles/stripe/profile.yaml +1 -0
  54. package/profiles/supabase/logo.png +0 -0
  55. package/profiles/supabase/profile.yaml +85 -0
  56. package/profiles/vercel/logo.png +0 -0
  57. package/profiles/vercel/profile.yaml +25 -1
  58. package/profiles/vite/profile.yaml +4 -3
  59. package/profiles/web-frontend-base/profile.yaml +5 -4
  60. package/profiles/webshop/profile.yaml +23 -5
  61. package/profiles/x-growth-bot/profile.yaml +44 -0
  62. package/resources/icons/generate-icons.py +128 -2
  63. package/resources/mcps/configs/claude.sanitized.json +42 -0
  64. package/resources/mcps/configs/codex.sanitized.json +7 -0
  65. package/resources/skills/skills/career/resume-version-manager/SKILL.md +351 -0
  66. package/resources/skills/skills/career/salary-negotiation-prep/SKILL.md +378 -0
  67. package/resources/skills/skills/content/pdf/SKILL.md +2 -0
  68. package/resources/skills/skills/content/postiz-cards/SKILL.md +48 -0
  69. package/resources/skills/skills/content/postiz-cards/scripts/analytics.sh +38 -0
  70. package/resources/skills/skills/content/postiz-cards/scripts/card.sh +42 -0
  71. package/resources/skills/skills/content/postiz-cards/scripts/lint.py +38 -0
  72. package/resources/skills/skills/design/headless-gif-demo/SKILL.md +1 -1
  73. package/resources/skills/skills/design/readme-svg-design/SKILL.md +1 -1
  74. package/resources/skills/skills/eu-funding/grant-outreach/SKILL.md +70 -0
  75. package/resources/skills/skills/eu-funding/hu-grant-finder/SKILL.md +114 -0
  76. package/resources/skills/skills/eu-funding/hu-grant-finder/evals.md +26 -0
  77. package/resources/skills/skills/eu-funding/ted-tender-search/SKILL.md +80 -0
  78. package/resources/skills/skills/eu-funding/ted-tender-search/evals.md +26 -0
  79. package/resources/skills/skills/eu-funding/ted-tender-search/scripts/ted-search.sh +46 -0
  80. package/resources/skills/skills/event-design/wedding-invitations/SKILL.md +1 -1
  81. package/resources/skills/skills/github/gx-agents/SKILL.md +96 -0
  82. package/resources/skills/skills/gstack/design-shotgun/SKILL.md +1 -1
  83. package/resources/skills/skills/marketing/ab-test-analyzer/SKILL.md +1 -1
  84. package/resources/skills/skills/marketing/ab-test-setup-and-analysis/SKILL.md +1 -1
  85. package/resources/skills/skills/marketing/account-structure-review/SKILL.md +1 -1
  86. package/resources/skills/skills/marketing/ad-copy-variant-generator/SKILL.md +1 -1
  87. package/resources/skills/skills/marketing/ad-extension-audit/SKILL.md +1 -1
  88. package/resources/skills/skills/marketing/ad-spend-allocator/SKILL.md +1 -1
  89. package/resources/skills/skills/marketing/anomaly-detection/SKILL.md +1 -1
  90. package/resources/skills/skills/marketing/attribution-model-comparison/SKILL.md +1 -1
  91. package/resources/skills/skills/marketing/audience-overlap-analysis/SKILL.md +7 -1
  92. package/resources/skills/skills/marketing/bid-strategy-recommendations/SKILL.md +7 -1
  93. package/resources/skills/skills/marketing/budget-scenario-planner/SKILL.md +6 -1
  94. package/resources/skills/skills/marketing/campaign-naming-convention-builder/SKILL.md +7 -1
  95. package/resources/skills/skills/marketing/channel-mix-optimizer/SKILL.md +7 -1
  96. package/resources/skills/skills/marketing/client-report-narratives/SKILL.md +6 -1
  97. package/resources/skills/skills/marketing/competitor-creative-analysis/SKILL.md +1 -1
  98. package/resources/skills/skills/marketing/competitor-teardown/SKILL.md +1 -1
  99. package/resources/skills/skills/marketing/content-repurposer/SKILL.md +1 -1
  100. package/resources/skills/skills/marketing/conversion-path-analysis/SKILL.md +1 -1
  101. package/resources/skills/skills/marketing/cpa-diagnostics/SKILL.md +1 -1
  102. package/resources/skills/skills/marketing/creative-fatigue-detection/SKILL.md +1 -1
  103. package/resources/skills/skills/marketing/day-hour-performance-breakdown/SKILL.md +1 -1
  104. package/resources/skills/skills/marketing/device-performance-split/SKILL.md +1 -1
  105. package/resources/skills/skills/marketing/e2e-seo-assistant/SKILL.md +1 -1
  106. package/resources/skills/skills/marketing/email-sequence-writer/SKILL.md +1 -1
  107. package/resources/skills/skills/marketing/frequency-cap-recommendations/SKILL.md +1 -1
  108. package/resources/skills/skills/marketing/geo-performance-analysis/SKILL.md +1 -1
  109. package/resources/skills/skills/marketing/google-ads-audit/SKILL.md +1 -1
  110. package/resources/skills/skills/marketing/icp-research-assistant/SKILL.md +1 -1
  111. package/resources/skills/skills/marketing/keyword-cannibalization-check/SKILL.md +1 -1
  112. package/resources/skills/skills/marketing/landing-page-audit/SKILL.md +1 -1
  113. package/resources/skills/skills/marketing/landing-page-audit-quick/SKILL.md +1 -1
  114. package/resources/skills/skills/marketing/linkedin-ads-audit/SKILL.md +1 -1
  115. package/resources/skills/skills/marketing/meta-ads-audit/SKILL.md +1 -1
  116. package/resources/skills/skills/marketing/pacing-monitor/SKILL.md +1 -1
  117. package/resources/skills/skills/marketing/performance-benchmarking/SKILL.md +1 -1
  118. package/resources/skills/skills/marketing/programmatic-seo-builder/SKILL.md +1 -1
  119. package/resources/skills/skills/marketing/quality-score-breakdown/SKILL.md +1 -1
  120. package/resources/skills/skills/marketing/reddit-ads-audit/SKILL.md +1 -1
  121. package/resources/skills/skills/marketing/retargeting-window-analysis/SKILL.md +1 -1
  122. package/resources/skills/skills/marketing/roas-forecasting/SKILL.md +1 -1
  123. package/resources/skills/skills/marketing/search-term-mining/SKILL.md +1 -1
  124. package/resources/skills/skills/marketing/utm-tracking-generator/SKILL.md +1 -1
  125. package/resources/skills/skills/marketing/wasted-spend-finder/SKILL.md +1 -1
  126. package/resources/skills/skills/marketing/weekly-account-summary/SKILL.md +1 -1
  127. package/resources/skills/skills/meta/awesome-list-submit/SKILL.md +4 -4
  128. package/resources/skills/skills/meta/cue-dashboard/SKILL.md +109 -0
  129. package/resources/skills/skills/meta/cue-developer/SKILL.md +161 -0
  130. package/resources/skills/skills/meta/cue-developer/evals/evals.json +57 -0
  131. package/resources/skills/skills/meta/cue-developer/references/architecture.md +65 -0
  132. package/resources/skills/skills/meta/cue-developer/references/build_and_test.md +72 -0
  133. package/resources/skills/skills/meta/cue-developer/references/contributing.md +75 -0
  134. package/resources/skills/skills/meta/cue-developer/references/conventions.md +57 -0
  135. package/resources/skills/skills/meta/cue-developer/references/first_time_setup.md +51 -0
  136. package/resources/skills/skills/meta/cue-developer/references/skill_and_mcp_authoring.md +84 -0
  137. package/resources/skills/skills/meta/cue-developer/references/troubleshooting.md +42 -0
  138. package/resources/skills/skills/meta/delegation-check/SKILL.md +148 -0
  139. package/resources/skills/skills/meta/delegation-check/specs/scan-algorithm.md +125 -0
  140. package/resources/skills/skills/meta/delegation-check/specs/separation-rules.md +190 -0
  141. package/resources/skills/skills/meta/focus/SKILL.md +62 -0
  142. package/resources/skills/skills/meta/help/SKILL.md +1 -1
  143. package/resources/skills/skills/meta/integrity-tags/SKILL.md +2 -0
  144. package/resources/skills/skills/meta/next-steps/SKILL.md +124 -0
  145. package/resources/skills/skills/meta/next-steps/evals/eval-set.json +92 -0
  146. package/resources/skills/skills/meta/profile-from-docs/SKILL.md +141 -0
  147. package/resources/skills/skills/meta/ralph-loop/SKILL.md +83 -0
  148. package/resources/skills/skills/meta/ralph-loop/scripts/loop.sh +73 -0
  149. package/resources/skills/skills/meta/skill-simplify/SKILL.md +136 -0
  150. package/resources/skills/skills/meta/skill-simplify/phases/01-analysis.md +173 -0
  151. package/resources/skills/skills/meta/skill-simplify/phases/02-optimize.md +104 -0
  152. package/resources/skills/skills/meta/skill-simplify/phases/03-check.md +145 -0
  153. package/resources/skills/skills/meta/smart-loader/scripts/smart-lookup.sh +13 -4
  154. package/resources/skills/skills/meta/verify-council/SKILL.md +182 -0
  155. package/resources/skills/skills/meta/verify-council/references/lane-prompts.md +103 -0
  156. package/resources/skills/skills/meta/verify-council/references/workflow.js +217 -0
  157. package/resources/skills/skills/nvidia/aiq-research/SKILL.md +1 -1
  158. package/resources/skills/skills/nvidia/cuopt-developer/SKILL.md +16 -1
  159. package/resources/skills/skills/nvidia/cuopt-developer/resources/contributing.md +2 -2
  160. package/resources/skills/skills/nvidia/cuopt-developer/resources/numerical_debugging.md +128 -0
  161. package/resources/skills/skills/nvidia/cuopt-developer/resources/python_bindings.md +2 -9
  162. package/resources/skills/skills/nvidia/cuopt-developer/resources/vrp_skills.md +166 -0
  163. package/resources/skills/skills/nvidia/cuopt-install/SKILL.md +2 -10
  164. package/resources/skills/skills/nvidia/cuopt-numerical-optimization-api-c/SKILL.md +3 -23
  165. package/resources/skills/skills/nvidia/cuopt-numerical-optimization-api-c/resources/examples.md +40 -20
  166. package/resources/skills/skills/nvidia/cuopt-numerical-optimization-api-python/SKILL.md +5 -1
  167. package/resources/skills/skills/nvidia/skill-evolution/SKILL.md +4 -5
  168. package/resources/skills/skills/research/trendradar/SKILL.md +1 -1
  169. package/resources/skills/skills/ssh/ssh-config/SKILL.md +94 -0
  170. package/resources/skills/skills/ssh/ssh-copy/SKILL.md +92 -0
  171. package/resources/skills/skills/ssh/ssh-harden/SKILL.md +108 -0
  172. package/resources/skills/skills/ssh/ssh-keys/SKILL.md +82 -0
  173. package/resources/skills/skills/ssh/ssh-paste-image/LICENSE +28 -0
  174. package/resources/skills/skills/ssh/ssh-paste-image/SKILL.md +149 -0
  175. package/resources/skills/skills/ssh/ssh-paste-image/scripts/build.sh +29 -0
  176. package/resources/skills/skills/ssh/ssh-paste-image/scripts/client/go.mod +3 -0
  177. package/resources/skills/skills/ssh/ssh-paste-image/scripts/client/main.go +79 -0
  178. package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/ccimgd.service +12 -0
  179. package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/com.ccimgd.plist +20 -0
  180. package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/go.mod +3 -0
  181. package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/main.go +98 -0
  182. package/resources/skills/skills/ssh/ssh-tunnel/SKILL.md +96 -0
  183. package/resources/skills/skills/strapi/building-with-strapi/SKILL.md +112 -0
  184. package/resources/skills/skills/strapi/strapi-cli/SKILL.md +93 -0
  185. package/resources/skills/skills/strapi/strapi-content-api/SKILL.md +115 -0
  186. package/resources/skills/skills/strapi/strapi-deploy/SKILL.md +89 -0
  187. package/resources/skills/skills/strapi/strapi-mcp-setup/SKILL.md +101 -0
  188. package/resources/skills/skills/strapi/strapi-plugins/SKILL.md +97 -0
  189. package/resources/skills/skills/tools/context7/SKILL.md +101 -0
  190. package/resources/skills/skills/tools/opensrc/SKILL.md +1 -1
  191. package/resources/skills/skills/tools/portless/SKILL.md +186 -0
  192. package/resources/skills/skills/xbot/operate/SKILL.md +229 -0
  193. package/src/commands/_index.ts +8 -0
  194. package/src/commands/ai-score.e2e.test.ts +11 -4
  195. package/src/commands/ai.ts +3 -4
  196. package/src/commands/auto-detect.ts +1 -1
  197. package/src/commands/cli.test.ts +1 -2
  198. package/src/commands/cli.ts +1 -1
  199. package/src/commands/cloud.ts +1 -1
  200. package/src/commands/current.ts +1 -4
  201. package/src/commands/dash.test.ts +110 -0
  202. package/src/commands/dash.ts +194 -0
  203. package/src/commands/dashboard.ts +26 -0
  204. package/src/commands/diff.ts +1 -1
  205. package/src/commands/discover.test.ts +1 -1
  206. package/src/commands/discover.ts +90 -40
  207. package/src/commands/doctor.test.ts +58 -0
  208. package/src/commands/doctor.ts +79 -3
  209. package/src/commands/eval-behavior.ts +1 -1
  210. package/src/commands/eval.ts +2 -2
  211. package/src/commands/evolve.ts +4 -3
  212. package/src/commands/failures.test.ts +1 -1
  213. package/src/commands/features-batch1.test.ts +6 -1
  214. package/src/commands/icon.ts +1 -5
  215. package/src/commands/import-profile.ts +1 -1
  216. package/src/commands/init.ts +50 -7
  217. package/src/commands/install-sh.e2e.test.ts +65 -0
  218. package/src/commands/launch-handoff.e2e.test.ts +88 -0
  219. package/src/commands/launch.e2e.test.ts +8 -1
  220. package/src/commands/launch.test.ts +29 -0
  221. package/src/commands/launch.ts +185 -131
  222. package/src/commands/lock.ts +0 -1
  223. package/src/commands/marketplace.ts +0 -4
  224. package/src/commands/materialize.ts +1 -1
  225. package/src/commands/mem.ts +341 -0
  226. package/src/commands/optimizer.ts +0 -3
  227. package/src/commands/playground.ts +1 -2
  228. package/src/commands/profile-draft-skill.ts +1 -1
  229. package/src/commands/replay-whatif.ts +1 -6
  230. package/src/commands/score.ts +2 -2
  231. package/src/commands/security.test.ts +88 -0
  232. package/src/commands/security.ts +74 -28
  233. package/src/commands/shell.test.ts +65 -4
  234. package/src/commands/shell.ts +67 -7
  235. package/src/commands/skills-test.ts +0 -1
  236. package/src/commands/skills.ts +28 -2
  237. package/src/commands/sources.ts +1 -2
  238. package/src/commands/status.ts +2 -6
  239. package/src/commands/submit-profile.ts +1 -1
  240. package/src/commands/suggest.ts +35 -10
  241. package/src/commands/trigger-gaps.test.ts +50 -0
  242. package/src/commands/trigger-gaps.ts +63 -29
  243. package/src/commands/update.ts +1 -1
  244. package/src/commands/validate.ts +16 -4
  245. package/src/commands/watch-live.ts +1 -1
  246. package/src/commands/workspace.ts +1 -1
  247. package/src/index.ts +26 -10
  248. package/src/lib/active-sessions.ts +1 -1
  249. package/src/lib/agent-adapters.test.ts +100 -0
  250. package/src/lib/agent-adapters.ts +2 -2
  251. package/src/lib/analytics.test.ts +88 -0
  252. package/src/lib/analytics.ts +82 -1
  253. package/src/lib/auto-detect.test.ts +10 -4
  254. package/src/lib/auto-detect.ts +19 -23
  255. package/src/lib/brand-icons.ts +0 -1
  256. package/src/lib/cache.ts +2 -3
  257. package/src/lib/claude-mem-env.test.ts +148 -0
  258. package/src/lib/claude-mem-env.ts +172 -0
  259. package/src/lib/combo-history.test.ts +53 -0
  260. package/src/lib/combo-history.ts +83 -0
  261. package/src/lib/companion-detect.test.ts +108 -0
  262. package/src/lib/companion-detect.ts +140 -0
  263. package/src/lib/companion-fetch.ts +4 -6
  264. package/src/lib/conditional-skills.test.ts +1 -1
  265. package/src/lib/config-paths.test.ts +53 -0
  266. package/src/lib/config-paths.ts +33 -0
  267. package/src/lib/dashboard-server.test.ts +351 -0
  268. package/src/lib/dashboard-server.ts +1476 -27
  269. package/src/lib/debug-log.test.ts +66 -0
  270. package/src/lib/debug-log.ts +45 -0
  271. package/src/lib/mcp-catalog.test.ts +102 -0
  272. package/src/lib/mcp-catalog.ts +193 -0
  273. package/src/lib/pair-suggestions.test.ts +111 -0
  274. package/src/lib/pair-suggestions.ts +98 -5
  275. package/src/lib/permissions.test.ts +76 -0
  276. package/src/lib/permissions.ts +125 -0
  277. package/src/lib/picker.test.ts +1106 -1
  278. package/src/lib/picker.ts +1230 -142
  279. package/src/lib/plugin-discovery.ts +126 -0
  280. package/src/lib/pr-poster.ts +1 -1
  281. package/src/lib/pr-throttle.ts +2 -6
  282. package/src/lib/profile-linter.test.ts +67 -1
  283. package/src/lib/profile-linter.ts +59 -14
  284. package/src/lib/profile-loader.test.ts +21 -0
  285. package/src/lib/profile-loader.ts +22 -3
  286. package/src/lib/profile-metrics.ts +2 -6
  287. package/src/lib/profile-names.test.ts +58 -0
  288. package/src/lib/repos.test.ts +57 -0
  289. package/src/lib/repos.ts +167 -0
  290. package/src/lib/resolver-npx.ts +10 -1
  291. package/src/lib/runtime-materializer.test.ts +200 -3
  292. package/src/lib/runtime-materializer.ts +129 -20
  293. package/src/lib/shared-profiles.ts +2 -3
  294. package/src/lib/skill-clis.test.ts +113 -0
  295. package/src/lib/skill-clis.ts +232 -0
  296. package/src/lib/skill-dependencies.ts +9 -1
  297. package/src/lib/skill-deps.ts +1 -1
  298. package/src/lib/skill-linter.ts +1 -1
  299. package/src/lib/skill-quality.ts +0 -1
  300. package/src/lib/skill-sandbox.test.ts +1 -1
  301. package/src/lib/skills-lock.test.ts +1 -1
  302. package/src/lib/telemetry-consent.ts +3 -5
  303. package/src/lib/telemetry-report.test.ts +2 -2
  304. package/src/lib/token-budget.ts +111 -0
  305. package/src/lib/trigger-gaps.test.ts +70 -0
  306. package/src/lib/trigger-gaps.ts +48 -6
  307. package/src/lib/tui/data.ts +1 -5
  308. package/src/lib/workflow-store.ts +150 -0
  309. package/src/lib/workspace-secrets.ts +0 -4
  310. package/src/lib/workspaces.ts +1 -1
@@ -45,10 +45,40 @@ export interface ComputeGapsInput {
45
45
  * triggers (e.g. `"go"`) matching every prompt. Default 4.
46
46
  */
47
47
  minTriggerLength?: number;
48
+ /**
49
+ * A bare single-word trigger (e.g. "help", "analyze") that isn't a
50
+ * slash-command only counts as a match when the prompt is at most this many
51
+ * characters — i.e. the word plausibly *is* the request, not a substring of a
52
+ * longer unrelated prompt. Multi-word and slash-command triggers match at any
53
+ * length. Default 80.
54
+ */
55
+ weakTriggerMaxPromptChars?: number;
48
56
  /** Cap on returned rows (sorted by gap DESC). Default 10. */
49
57
  limit?: number;
50
58
  }
51
59
 
60
+ const DEFAULT_MIN_TRIGGER_LENGTH = 4;
61
+ const DEFAULT_WEAK_TRIGGER_MAX_PROMPT_CHARS = 80;
62
+
63
+ /** A trigger is "weak" when it's a single bare word (no spaces) and not a
64
+ * slash-command — these are the ones that drown the metric in substring noise
65
+ * ("help" inside "help me", "analyze" inside "reanalyze"). */
66
+ function isWeakTrigger(triggerLower: string): boolean {
67
+ return !/\s/.test(triggerLower) && !triggerLower.startsWith("/");
68
+ }
69
+
70
+ /**
71
+ * Compile a trigger into a word-boundary matcher. Plain `String.includes` (the
72
+ * old behavior) matched "analyze" inside "reanalyze" and "help" inside
73
+ * "helpful"; `\b` doesn't work for triggers with leading punctuation
74
+ * ("/caveman") or internal hyphens ("agent-to-agent"), so we anchor on
75
+ * alphanumeric look-arounds instead: the trigger must not abut a word char.
76
+ */
77
+ function compileTrigger(triggerLower: string): RegExp {
78
+ const escaped = triggerLower.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
79
+ return new RegExp(`(?<![a-z0-9_])${escaped}(?![a-z0-9_])`);
80
+ }
81
+
52
82
  /**
53
83
  * Compute the per-skill gap table. Designed for "user mostly says these
54
84
  * things, here's which skills should fire but aren't" — not a high-precision
@@ -56,22 +86,34 @@ export interface ComputeGapsInput {
56
86
  * surface real problems when the gap count is large.
57
87
  */
58
88
  export function computeTriggerGaps(input: ComputeGapsInput): TriggerGapRow[] {
59
- const minLen = input.minTriggerLength ?? 4;
89
+ const minLen = input.minTriggerLength ?? DEFAULT_MIN_TRIGGER_LENGTH;
60
90
  const limit = input.limit ?? 10;
61
- const promptsLower = input.userPrompts.map((p) => p.toLowerCase());
91
+ const weakMaxChars = input.weakTriggerMaxPromptChars ?? DEFAULT_WEAK_TRIGGER_MAX_PROMPT_CHARS;
92
+ // Keep each prompt's length alongside its lowercased text for the weak-trigger
93
+ // proportion check.
94
+ const prompts = input.userPrompts.map((p) => ({ text: p.toLowerCase(), len: p.length }));
62
95
 
63
96
  const rows: TriggerGapRow[] = [];
64
97
  for (const skill of input.skills) {
65
- const triggers = (skill.triggers ?? []).filter((t) => t.length >= minLen);
98
+ // Precompile each trigger's word-boundary matcher once (15k+ prompts × N
99
+ // triggers per skill — compiling per prompt would be wasteful).
100
+ const triggers = (skill.triggers ?? [])
101
+ .filter((t) => t.length >= minLen)
102
+ .map((t) => {
103
+ const lower = t.toLowerCase();
104
+ return { raw: t, re: compileTrigger(lower), weak: isWeakTrigger(lower) };
105
+ });
66
106
  if (triggers.length === 0) continue;
67
107
 
68
108
  let matched = 0;
69
109
  const samples = new Set<string>();
70
- for (const prompt of promptsLower) {
110
+ for (const prompt of prompts) {
71
111
  for (const t of triggers) {
72
- if (prompt.includes(t.toLowerCase())) {
112
+ // A bare single word only counts when it dominates a short prompt.
113
+ if (t.weak && prompt.len > weakMaxChars) continue;
114
+ if (t.re.test(prompt.text)) {
73
115
  matched++;
74
- if (samples.size < 3) samples.add(t);
116
+ if (samples.size < 3) samples.add(t.raw);
75
117
  break;
76
118
  }
77
119
  }
@@ -12,6 +12,7 @@ import { existsSync } from "node:fs";
12
12
  import { readFile } from "node:fs/promises";
13
13
  import { dirname, join, resolve } from "node:path";
14
14
  import { fileURLToPath } from "node:url";
15
+ import { configDir } from "../config-paths";
15
16
 
16
17
  import { listProfiles, loadProfile } from "../profile-loader";
17
18
  import { resolveProfileForCwd } from "../cwd-resolver";
@@ -43,11 +44,6 @@ function repoRoot(): string {
43
44
  return resolve(here, "..", "..", "..");
44
45
  }
45
46
 
46
- function configDir(): string {
47
- return process.env.XDG_CONFIG_HOME
48
- ? join(process.env.XDG_CONFIG_HOME, "cue")
49
- : join(homedir(), ".config", "cue");
50
- }
51
47
 
52
48
  function skillsRoot(): string {
53
49
  return join(repoRoot(), "resources", "skills", "skills");
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Cue workflow store — the on-disk format + CRUD for visually-authored
3
+ * Claude Code workflows (the n8n-style canvas in cue studio).
4
+ *
5
+ * A workflow is a DAG of cue primitives (skills, commands, subagents, MCP
6
+ * tools) saved as resources/workflows/<name>.json. The shape is deliberately
7
+ * React-Flow-compatible (nodes carry id + position, edges carry source/target
8
+ * + handles) so the studio canvas can load/save with no translation layer.
9
+ *
10
+ * This module is pure storage + validation; execution lives in a separate
11
+ * runtime (M4). Read-only callers (list/load) never throw; writes validate the
12
+ * name and shape and throw WorkflowError on bad input.
13
+ */
14
+
15
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
16
+ import { join, resolve } from "node:path";
17
+
18
+ const REPO_ROOT = resolve(new URL(import.meta.url).pathname, "..", "..", "..");
19
+
20
+ /** Where workflow JSON lives. Honors the same env override as profiles. */
21
+ export function workflowsDir(): string {
22
+ return process.env.CUE_WORKFLOWS_DIR ?? join(REPO_ROOT, "resources", "workflows");
23
+ }
24
+
25
+ export type WorkflowNodeKind =
26
+ | "trigger" // entry point (manual / on-message / cron) — no cue ref
27
+ | "skill" // a cue skill, e.g. "meta/analyze"
28
+ | "command" // a slash command, e.g. "goal"
29
+ | "subagent" // a delegatable specialist
30
+ | "mcp" // an MCP tool call, e.g. lightpanda.goto
31
+ | "note"; // a free-text sticky, no execution
32
+
33
+ export interface WorkflowNode {
34
+ /** Unique within the workflow (React Flow node id). */
35
+ id: string;
36
+ kind: WorkflowNodeKind;
37
+ /** The cue primitive this node invokes (skill id / command / subagent / "mcp:tool"). Empty for trigger/note. */
38
+ ref: string;
39
+ /** Display label on the canvas. */
40
+ label: string;
41
+ position: { x: number; y: number };
42
+ /** Per-node params: prompt, args, the chosen MCP tool, etc. */
43
+ config?: Record<string, unknown>;
44
+ }
45
+
46
+ export interface WorkflowEdge {
47
+ id: string;
48
+ source: string;
49
+ target: string;
50
+ sourceHandle?: string | null;
51
+ targetHandle?: string | null;
52
+ }
53
+
54
+ export interface CueWorkflow {
55
+ version: 1;
56
+ /** Slug, equal to the filename stem. */
57
+ name: string;
58
+ title: string;
59
+ description: string;
60
+ nodes: WorkflowNode[];
61
+ edges: WorkflowEdge[];
62
+ createdAt?: string;
63
+ updatedAt?: string;
64
+ }
65
+
66
+ export interface WorkflowSummary {
67
+ name: string;
68
+ title: string;
69
+ description: string;
70
+ nodeCount: number;
71
+ edgeCount: number;
72
+ updatedAt: string | null;
73
+ }
74
+
75
+ export class WorkflowError extends Error {}
76
+
77
+ const NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
78
+
79
+ /** Validate a workflow name: slug only, no path traversal. */
80
+ export function assertValidName(name: string): void {
81
+ if (!NAME_RE.test(name) || name.includes("..") || name.length > 64) {
82
+ throw new WorkflowError(`invalid workflow name: ${name}`);
83
+ }
84
+ }
85
+
86
+ function readJson<T>(path: string): T | null {
87
+ try {
88
+ return JSON.parse(readFileSync(path, "utf8")) as T;
89
+ } catch {
90
+ return null;
91
+ }
92
+ }
93
+
94
+ /** Every saved workflow, newest-updated first. Never throws. */
95
+ export function listWorkflows(): WorkflowSummary[] {
96
+ const dir = workflowsDir();
97
+ if (!existsSync(dir)) return [];
98
+ const out: WorkflowSummary[] = [];
99
+ for (const f of readdirSync(dir)) {
100
+ if (!f.endsWith(".json")) continue;
101
+ const wf = readJson<CueWorkflow>(join(dir, f));
102
+ if (!wf || typeof wf.name !== "string") continue;
103
+ out.push({
104
+ name: wf.name,
105
+ title: wf.title ?? wf.name,
106
+ description: wf.description ?? "",
107
+ nodeCount: Array.isArray(wf.nodes) ? wf.nodes.length : 0,
108
+ edgeCount: Array.isArray(wf.edges) ? wf.edges.length : 0,
109
+ updatedAt: wf.updatedAt ?? null,
110
+ });
111
+ }
112
+ return out.sort((a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? ""));
113
+ }
114
+
115
+ /** Load one workflow by name, or null when absent/corrupt. */
116
+ export function loadWorkflow(name: string): CueWorkflow | null {
117
+ assertValidName(name);
118
+ return readJson<CueWorkflow>(join(workflowsDir(), `${name}.json`));
119
+ }
120
+
121
+ /**
122
+ * Validate + persist a workflow. `nowIso` is injected (the dashboard server
123
+ * stamps it) so this module stays free of wall-clock calls. Returns the saved
124
+ * doc with timestamps applied.
125
+ */
126
+ export function saveWorkflow(input: unknown, nowIso: string): CueWorkflow {
127
+ const wf = input as Partial<CueWorkflow>;
128
+ if (!wf || typeof wf !== "object") throw new WorkflowError("workflow must be an object");
129
+ if (typeof wf.name !== "string") throw new WorkflowError("workflow.name is required");
130
+ assertValidName(wf.name);
131
+ if (!Array.isArray(wf.nodes)) throw new WorkflowError("workflow.nodes must be an array");
132
+ if (!Array.isArray(wf.edges)) throw new WorkflowError("workflow.edges must be an array");
133
+
134
+ const dir = workflowsDir();
135
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
136
+ const existing = loadWorkflow(wf.name);
137
+
138
+ const doc: CueWorkflow = {
139
+ version: 1,
140
+ name: wf.name,
141
+ title: wf.title ?? wf.name,
142
+ description: wf.description ?? "",
143
+ nodes: wf.nodes as WorkflowNode[],
144
+ edges: wf.edges as WorkflowEdge[],
145
+ createdAt: existing?.createdAt ?? nowIso,
146
+ updatedAt: nowIso,
147
+ };
148
+ writeFileSync(join(dir, `${wf.name}.json`), JSON.stringify(doc, null, 2) + "\n");
149
+ return doc;
150
+ }
@@ -25,10 +25,6 @@ function storePath(): string {
25
25
  return join(secretsDir(), "workspace-secrets.json.age");
26
26
  }
27
27
 
28
- function plainStorePath(): string {
29
- return join(secretsDir(), "workspace-secrets.json");
30
- }
31
-
32
28
  function hasAge(): boolean {
33
29
  try {
34
30
  execSync("which age", { stdio: "pipe" });
@@ -7,7 +7,7 @@
7
7
  * or via `cue workspace <name>`.
8
8
  */
9
9
 
10
- import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from "node:fs";
10
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, } from "node:fs";
11
11
  import { join, dirname } from "node:path";
12
12
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
13
13