cue-ai 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/README.md +82 -33
- package/bin/cue-review-progress +107 -0
- package/bin/cue-review-watch +98 -0
- package/dist/cue.js +7352 -3744
- package/package.json +16 -5
- package/profiles/_types.ts +9 -0
- package/profiles/backend/profile.yaml +2 -0
- package/profiles/blog-writer/profile.yaml +10 -0
- package/profiles/browser/profile.yaml +9 -2
- package/profiles/builder/profile.yaml +3 -6
- package/profiles/career/profile.yaml +13 -2
- package/profiles/claude-api/profile.yaml +1 -1
- package/profiles/commerce/profile.yaml +27 -3
- package/profiles/core/logo.png +0 -0
- package/profiles/core/profile.yaml +62 -2
- package/profiles/dash-merge-test/profile.yaml +109 -0
- package/profiles/designer/profile.yaml +2 -0
- package/profiles/designer-medusa-next/profile.yaml +4 -1
- package/profiles/designer-medusa-vite/profile.yaml +4 -1
- package/profiles/docs-writer/profile.yaml +3 -1
- package/profiles/eu-tender-research/README.md +48 -0
- package/profiles/eu-tender-research/logo.png +0 -0
- package/profiles/eu-tender-research/profile.yaml +108 -0
- package/profiles/finance/logo.png +0 -0
- package/profiles/finance/profile.yaml +46 -0
- package/profiles/frontend/profile.yaml +5 -9
- package/profiles/growth/profile.yaml +2 -3
- package/profiles/gstack/profile.yaml +15 -0
- package/profiles/higgsfield/profile.yaml +3 -0
- package/profiles/hyperframes/logo.png +0 -0
- package/profiles/hyperframes/profile.yaml +59 -0
- package/profiles/improver/profile.yaml +88 -0
- package/profiles/marketing/profile.yaml +0 -3
- package/profiles/medusa-dev/profile.yaml +2 -0
- package/profiles/medusa-next/profile.yaml +2 -3
- package/profiles/medusa-vite/profile.yaml +2 -3
- package/profiles/n8n/logo.png +0 -0
- package/profiles/n8n/profile.yaml +50 -0
- package/profiles/nextjs/profile.yaml +2 -3
- package/profiles/ops/profile.yaml +2 -0
- package/profiles/postizz/profile.yaml +13 -3
- package/profiles/python/profile.yaml +3 -0
- package/profiles/research/profile.yaml +3 -1
- package/profiles/schema.json +10 -0
- package/profiles/secops/profile.yaml +2 -0
- package/profiles/seo/profile.yaml +56 -0
- package/profiles/skill-writer/profile.yaml +8 -0
- package/profiles/ssh/profile.yaml +32 -0
- package/profiles/strapi/logo.png +0 -0
- package/profiles/strapi/profile.yaml +45 -0
- package/profiles/stripe/logo.png +0 -0
- package/profiles/stripe/profile.yaml +1 -0
- package/profiles/supabase/logo.png +0 -0
- package/profiles/supabase/profile.yaml +85 -0
- package/profiles/vercel/logo.png +0 -0
- package/profiles/vercel/profile.yaml +25 -1
- package/profiles/vite/profile.yaml +4 -3
- package/profiles/web-frontend-base/profile.yaml +5 -4
- package/profiles/webshop/profile.yaml +23 -5
- package/profiles/x-growth-bot/profile.yaml +44 -0
- package/resources/icons/generate-icons.py +128 -2
- package/resources/mcps/configs/claude.sanitized.json +42 -0
- package/resources/mcps/configs/codex.sanitized.json +7 -0
- package/resources/skills/skills/career/resume-version-manager/SKILL.md +351 -0
- package/resources/skills/skills/career/salary-negotiation-prep/SKILL.md +378 -0
- package/resources/skills/skills/content/pdf/SKILL.md +2 -0
- package/resources/skills/skills/content/postiz-cards/SKILL.md +48 -0
- package/resources/skills/skills/content/postiz-cards/scripts/analytics.sh +38 -0
- package/resources/skills/skills/content/postiz-cards/scripts/card.sh +42 -0
- package/resources/skills/skills/content/postiz-cards/scripts/lint.py +38 -0
- package/resources/skills/skills/design/headless-gif-demo/SKILL.md +1 -1
- package/resources/skills/skills/design/readme-svg-design/SKILL.md +1 -1
- package/resources/skills/skills/eu-funding/grant-outreach/SKILL.md +70 -0
- package/resources/skills/skills/eu-funding/hu-grant-finder/SKILL.md +114 -0
- package/resources/skills/skills/eu-funding/hu-grant-finder/evals.md +26 -0
- package/resources/skills/skills/eu-funding/ted-tender-search/SKILL.md +80 -0
- package/resources/skills/skills/eu-funding/ted-tender-search/evals.md +26 -0
- package/resources/skills/skills/eu-funding/ted-tender-search/scripts/ted-search.sh +46 -0
- package/resources/skills/skills/event-design/wedding-invitations/SKILL.md +1 -1
- package/resources/skills/skills/github/gx-agents/SKILL.md +96 -0
- package/resources/skills/skills/gstack/design-shotgun/SKILL.md +1 -1
- package/resources/skills/skills/marketing/ab-test-analyzer/SKILL.md +1 -1
- package/resources/skills/skills/marketing/ab-test-setup-and-analysis/SKILL.md +1 -1
- package/resources/skills/skills/marketing/account-structure-review/SKILL.md +1 -1
- package/resources/skills/skills/marketing/ad-copy-variant-generator/SKILL.md +1 -1
- package/resources/skills/skills/marketing/ad-extension-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/ad-spend-allocator/SKILL.md +1 -1
- package/resources/skills/skills/marketing/anomaly-detection/SKILL.md +1 -1
- package/resources/skills/skills/marketing/attribution-model-comparison/SKILL.md +1 -1
- package/resources/skills/skills/marketing/audience-overlap-analysis/SKILL.md +7 -1
- package/resources/skills/skills/marketing/bid-strategy-recommendations/SKILL.md +7 -1
- package/resources/skills/skills/marketing/budget-scenario-planner/SKILL.md +6 -1
- package/resources/skills/skills/marketing/campaign-naming-convention-builder/SKILL.md +7 -1
- package/resources/skills/skills/marketing/channel-mix-optimizer/SKILL.md +7 -1
- package/resources/skills/skills/marketing/client-report-narratives/SKILL.md +6 -1
- package/resources/skills/skills/marketing/competitor-creative-analysis/SKILL.md +1 -1
- package/resources/skills/skills/marketing/competitor-teardown/SKILL.md +1 -1
- package/resources/skills/skills/marketing/content-repurposer/SKILL.md +1 -1
- package/resources/skills/skills/marketing/conversion-path-analysis/SKILL.md +1 -1
- package/resources/skills/skills/marketing/cpa-diagnostics/SKILL.md +1 -1
- package/resources/skills/skills/marketing/creative-fatigue-detection/SKILL.md +1 -1
- package/resources/skills/skills/marketing/day-hour-performance-breakdown/SKILL.md +1 -1
- package/resources/skills/skills/marketing/device-performance-split/SKILL.md +1 -1
- package/resources/skills/skills/marketing/e2e-seo-assistant/SKILL.md +1 -1
- package/resources/skills/skills/marketing/email-sequence-writer/SKILL.md +1 -1
- package/resources/skills/skills/marketing/frequency-cap-recommendations/SKILL.md +1 -1
- package/resources/skills/skills/marketing/geo-performance-analysis/SKILL.md +1 -1
- package/resources/skills/skills/marketing/google-ads-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/icp-research-assistant/SKILL.md +1 -1
- package/resources/skills/skills/marketing/keyword-cannibalization-check/SKILL.md +1 -1
- package/resources/skills/skills/marketing/landing-page-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/landing-page-audit-quick/SKILL.md +1 -1
- package/resources/skills/skills/marketing/linkedin-ads-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/meta-ads-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/pacing-monitor/SKILL.md +1 -1
- package/resources/skills/skills/marketing/performance-benchmarking/SKILL.md +1 -1
- package/resources/skills/skills/marketing/programmatic-seo-builder/SKILL.md +1 -1
- package/resources/skills/skills/marketing/quality-score-breakdown/SKILL.md +1 -1
- package/resources/skills/skills/marketing/reddit-ads-audit/SKILL.md +1 -1
- package/resources/skills/skills/marketing/retargeting-window-analysis/SKILL.md +1 -1
- package/resources/skills/skills/marketing/roas-forecasting/SKILL.md +1 -1
- package/resources/skills/skills/marketing/search-term-mining/SKILL.md +1 -1
- package/resources/skills/skills/marketing/utm-tracking-generator/SKILL.md +1 -1
- package/resources/skills/skills/marketing/wasted-spend-finder/SKILL.md +1 -1
- package/resources/skills/skills/marketing/weekly-account-summary/SKILL.md +1 -1
- package/resources/skills/skills/meta/awesome-list-submit/SKILL.md +4 -4
- package/resources/skills/skills/meta/cue-dashboard/SKILL.md +109 -0
- package/resources/skills/skills/meta/cue-developer/SKILL.md +161 -0
- package/resources/skills/skills/meta/cue-developer/evals/evals.json +57 -0
- package/resources/skills/skills/meta/cue-developer/references/architecture.md +65 -0
- package/resources/skills/skills/meta/cue-developer/references/build_and_test.md +72 -0
- package/resources/skills/skills/meta/cue-developer/references/contributing.md +75 -0
- package/resources/skills/skills/meta/cue-developer/references/conventions.md +57 -0
- package/resources/skills/skills/meta/cue-developer/references/first_time_setup.md +51 -0
- package/resources/skills/skills/meta/cue-developer/references/skill_and_mcp_authoring.md +84 -0
- package/resources/skills/skills/meta/cue-developer/references/troubleshooting.md +42 -0
- package/resources/skills/skills/meta/delegation-check/SKILL.md +148 -0
- package/resources/skills/skills/meta/delegation-check/specs/scan-algorithm.md +125 -0
- package/resources/skills/skills/meta/delegation-check/specs/separation-rules.md +190 -0
- package/resources/skills/skills/meta/focus/SKILL.md +62 -0
- package/resources/skills/skills/meta/help/SKILL.md +1 -1
- package/resources/skills/skills/meta/integrity-tags/SKILL.md +2 -0
- package/resources/skills/skills/meta/next-steps/SKILL.md +124 -0
- package/resources/skills/skills/meta/next-steps/evals/eval-set.json +92 -0
- package/resources/skills/skills/meta/profile-from-docs/SKILL.md +141 -0
- package/resources/skills/skills/meta/ralph-loop/SKILL.md +83 -0
- package/resources/skills/skills/meta/ralph-loop/scripts/loop.sh +73 -0
- package/resources/skills/skills/meta/skill-simplify/SKILL.md +136 -0
- package/resources/skills/skills/meta/skill-simplify/phases/01-analysis.md +173 -0
- package/resources/skills/skills/meta/skill-simplify/phases/02-optimize.md +104 -0
- package/resources/skills/skills/meta/skill-simplify/phases/03-check.md +145 -0
- package/resources/skills/skills/meta/smart-loader/scripts/smart-lookup.sh +13 -4
- package/resources/skills/skills/meta/verify-council/SKILL.md +182 -0
- package/resources/skills/skills/meta/verify-council/references/lane-prompts.md +103 -0
- package/resources/skills/skills/meta/verify-council/references/workflow.js +217 -0
- package/resources/skills/skills/nvidia/aiq-research/SKILL.md +1 -1
- package/resources/skills/skills/nvidia/cuopt-developer/SKILL.md +16 -1
- package/resources/skills/skills/nvidia/cuopt-developer/resources/contributing.md +2 -2
- package/resources/skills/skills/nvidia/cuopt-developer/resources/numerical_debugging.md +128 -0
- package/resources/skills/skills/nvidia/cuopt-developer/resources/python_bindings.md +2 -9
- package/resources/skills/skills/nvidia/cuopt-developer/resources/vrp_skills.md +166 -0
- package/resources/skills/skills/nvidia/cuopt-install/SKILL.md +2 -10
- package/resources/skills/skills/nvidia/cuopt-numerical-optimization-api-c/SKILL.md +3 -23
- package/resources/skills/skills/nvidia/cuopt-numerical-optimization-api-c/resources/examples.md +40 -20
- package/resources/skills/skills/nvidia/cuopt-numerical-optimization-api-python/SKILL.md +5 -1
- package/resources/skills/skills/nvidia/skill-evolution/SKILL.md +4 -5
- package/resources/skills/skills/research/trendradar/SKILL.md +1 -1
- package/resources/skills/skills/ssh/ssh-config/SKILL.md +94 -0
- package/resources/skills/skills/ssh/ssh-copy/SKILL.md +92 -0
- package/resources/skills/skills/ssh/ssh-harden/SKILL.md +108 -0
- package/resources/skills/skills/ssh/ssh-keys/SKILL.md +82 -0
- package/resources/skills/skills/ssh/ssh-paste-image/LICENSE +28 -0
- package/resources/skills/skills/ssh/ssh-paste-image/SKILL.md +149 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/build.sh +29 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/client/go.mod +3 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/client/main.go +79 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/ccimgd.service +12 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/com.ccimgd.plist +20 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/go.mod +3 -0
- package/resources/skills/skills/ssh/ssh-paste-image/scripts/daemon/main.go +98 -0
- package/resources/skills/skills/ssh/ssh-tunnel/SKILL.md +96 -0
- package/resources/skills/skills/strapi/building-with-strapi/SKILL.md +112 -0
- package/resources/skills/skills/strapi/strapi-cli/SKILL.md +93 -0
- package/resources/skills/skills/strapi/strapi-content-api/SKILL.md +115 -0
- package/resources/skills/skills/strapi/strapi-deploy/SKILL.md +89 -0
- package/resources/skills/skills/strapi/strapi-mcp-setup/SKILL.md +101 -0
- package/resources/skills/skills/strapi/strapi-plugins/SKILL.md +97 -0
- package/resources/skills/skills/tools/context7/SKILL.md +101 -0
- package/resources/skills/skills/tools/opensrc/SKILL.md +1 -1
- package/resources/skills/skills/tools/portless/SKILL.md +186 -0
- package/resources/skills/skills/xbot/operate/SKILL.md +229 -0
- package/src/commands/_index.ts +8 -0
- package/src/commands/ai-score.e2e.test.ts +11 -4
- package/src/commands/ai.ts +3 -4
- package/src/commands/auto-detect.ts +1 -1
- package/src/commands/cli.test.ts +1 -2
- package/src/commands/cli.ts +1 -1
- package/src/commands/cloud.ts +1 -1
- package/src/commands/current.ts +1 -4
- package/src/commands/dash.test.ts +110 -0
- package/src/commands/dash.ts +194 -0
- package/src/commands/dashboard.ts +26 -0
- package/src/commands/diff.ts +1 -1
- package/src/commands/discover.test.ts +1 -1
- package/src/commands/discover.ts +90 -40
- package/src/commands/doctor.test.ts +58 -0
- package/src/commands/doctor.ts +79 -3
- package/src/commands/eval-behavior.ts +1 -1
- package/src/commands/eval.ts +2 -2
- package/src/commands/evolve.ts +4 -3
- package/src/commands/failures.test.ts +1 -1
- package/src/commands/features-batch1.test.ts +6 -1
- package/src/commands/icon.ts +1 -5
- package/src/commands/import-profile.ts +1 -1
- package/src/commands/init.ts +50 -7
- package/src/commands/install-sh.e2e.test.ts +65 -0
- package/src/commands/launch-handoff.e2e.test.ts +88 -0
- package/src/commands/launch.e2e.test.ts +8 -1
- package/src/commands/launch.test.ts +29 -0
- package/src/commands/launch.ts +185 -131
- package/src/commands/lock.ts +0 -1
- package/src/commands/marketplace.ts +0 -4
- package/src/commands/materialize.ts +1 -1
- package/src/commands/mem.ts +341 -0
- package/src/commands/optimizer.ts +0 -3
- package/src/commands/playground.ts +1 -2
- package/src/commands/profile-draft-skill.ts +1 -1
- package/src/commands/replay-whatif.ts +1 -6
- package/src/commands/score.ts +2 -2
- package/src/commands/security.test.ts +88 -0
- package/src/commands/security.ts +74 -28
- package/src/commands/shell.test.ts +65 -4
- package/src/commands/shell.ts +67 -7
- package/src/commands/skills-test.ts +0 -1
- package/src/commands/skills.ts +28 -2
- package/src/commands/sources.ts +1 -2
- package/src/commands/status.ts +2 -6
- package/src/commands/submit-profile.ts +1 -1
- package/src/commands/suggest.ts +35 -10
- package/src/commands/trigger-gaps.test.ts +50 -0
- package/src/commands/trigger-gaps.ts +63 -29
- package/src/commands/update.ts +1 -1
- package/src/commands/validate.ts +16 -4
- package/src/commands/watch-live.ts +1 -1
- package/src/commands/workspace.ts +1 -1
- package/src/index.ts +26 -10
- package/src/lib/active-sessions.ts +1 -1
- package/src/lib/agent-adapters.test.ts +100 -0
- package/src/lib/agent-adapters.ts +2 -2
- package/src/lib/analytics.test.ts +88 -0
- package/src/lib/analytics.ts +82 -1
- package/src/lib/auto-detect.test.ts +10 -4
- package/src/lib/auto-detect.ts +19 -23
- package/src/lib/brand-icons.ts +0 -1
- package/src/lib/cache.ts +2 -3
- package/src/lib/claude-mem-env.test.ts +148 -0
- package/src/lib/claude-mem-env.ts +172 -0
- package/src/lib/combo-history.test.ts +53 -0
- package/src/lib/combo-history.ts +83 -0
- package/src/lib/companion-detect.test.ts +108 -0
- package/src/lib/companion-detect.ts +140 -0
- package/src/lib/companion-fetch.ts +4 -6
- package/src/lib/conditional-skills.test.ts +1 -1
- package/src/lib/config-paths.test.ts +53 -0
- package/src/lib/config-paths.ts +33 -0
- package/src/lib/dashboard-server.test.ts +351 -0
- package/src/lib/dashboard-server.ts +1476 -27
- package/src/lib/debug-log.test.ts +66 -0
- package/src/lib/debug-log.ts +45 -0
- package/src/lib/mcp-catalog.test.ts +102 -0
- package/src/lib/mcp-catalog.ts +193 -0
- package/src/lib/pair-suggestions.test.ts +111 -0
- package/src/lib/pair-suggestions.ts +98 -5
- package/src/lib/permissions.test.ts +76 -0
- package/src/lib/permissions.ts +125 -0
- package/src/lib/picker.test.ts +1106 -1
- package/src/lib/picker.ts +1230 -142
- package/src/lib/plugin-discovery.ts +126 -0
- package/src/lib/pr-poster.ts +1 -1
- package/src/lib/pr-throttle.ts +2 -6
- package/src/lib/profile-linter.test.ts +67 -1
- package/src/lib/profile-linter.ts +59 -14
- package/src/lib/profile-loader.test.ts +21 -0
- package/src/lib/profile-loader.ts +22 -3
- package/src/lib/profile-metrics.ts +2 -6
- package/src/lib/profile-names.test.ts +58 -0
- package/src/lib/repos.test.ts +57 -0
- package/src/lib/repos.ts +167 -0
- package/src/lib/resolver-npx.ts +10 -1
- package/src/lib/runtime-materializer.test.ts +200 -3
- package/src/lib/runtime-materializer.ts +129 -20
- package/src/lib/shared-profiles.ts +2 -3
- package/src/lib/skill-clis.test.ts +113 -0
- package/src/lib/skill-clis.ts +232 -0
- package/src/lib/skill-dependencies.ts +9 -1
- package/src/lib/skill-deps.ts +1 -1
- package/src/lib/skill-linter.ts +1 -1
- package/src/lib/skill-quality.ts +0 -1
- package/src/lib/skill-sandbox.test.ts +1 -1
- package/src/lib/skills-lock.test.ts +1 -1
- package/src/lib/telemetry-consent.ts +3 -5
- package/src/lib/telemetry-report.test.ts +2 -2
- package/src/lib/token-budget.ts +111 -0
- package/src/lib/trigger-gaps.test.ts +70 -0
- package/src/lib/trigger-gaps.ts +48 -6
- package/src/lib/tui/data.ts +1 -5
- package/src/lib/workflow-store.ts +150 -0
- package/src/lib/workspace-secrets.ts +0 -4
- package/src/lib/workspaces.ts +1 -1
package/src/index.ts
CHANGED
|
@@ -66,6 +66,7 @@ function printHelp(): void {
|
|
|
66
66
|
["stats", "Profile usage analytics"],
|
|
67
67
|
["scan", "Tree of installed skills/plugins by domain"],
|
|
68
68
|
["why", "Trace why a skill/MCP is loaded"],
|
|
69
|
+
["mem", "Inspect/manage per-profile claude-mem stores"],
|
|
69
70
|
],
|
|
70
71
|
"Launch & Shell": [
|
|
71
72
|
["launch", "Resolve + materialize + exec claude/codex"],
|
|
@@ -154,10 +155,10 @@ function similarity(a: string, b: string): number {
|
|
|
154
155
|
async function checkForUpdate(currentVersion: string): Promise<void> {
|
|
155
156
|
const { existsSync, readFileSync: rf, writeFileSync: wf, mkdirSync } = await import("node:fs");
|
|
156
157
|
const { join } = await import("node:path");
|
|
157
|
-
const {
|
|
158
|
+
const { configDir } = await import("./lib/config-paths");
|
|
158
159
|
|
|
159
|
-
const
|
|
160
|
-
const checkFile = join(
|
|
160
|
+
const cfgDir = configDir();
|
|
161
|
+
const checkFile = join(cfgDir, ".last-update-check");
|
|
161
162
|
|
|
162
163
|
// Only check once per 24 hours
|
|
163
164
|
if (existsSync(checkFile)) {
|
|
@@ -173,7 +174,7 @@ async function checkForUpdate(currentVersion: string): Promise<void> {
|
|
|
173
174
|
if (!latest) return;
|
|
174
175
|
|
|
175
176
|
// Save check timestamp
|
|
176
|
-
mkdirSync(
|
|
177
|
+
mkdirSync(cfgDir, { recursive: true });
|
|
177
178
|
wf(checkFile, String(Date.now()));
|
|
178
179
|
|
|
179
180
|
// Compare versions
|
|
@@ -191,11 +192,12 @@ async function checkForUpdate(currentVersion: string): Promise<void> {
|
|
|
191
192
|
const readline = await import("node:readline");
|
|
192
193
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
193
194
|
const answer = await new Promise<string>((resolve) => {
|
|
194
|
-
rl.question(" Install now? [
|
|
195
|
-
// Auto-
|
|
196
|
-
|
|
195
|
+
rl.question(" Install now? [y/N] ", (a) => { rl.close(); resolve(a); });
|
|
196
|
+
// Auto-decline after 5 seconds — never install a new global without an
|
|
197
|
+
// affirmative y/yes. Walking away from the terminal must be a no-op.
|
|
198
|
+
setTimeout(() => { rl.close(); resolve("n"); }, 5000);
|
|
197
199
|
});
|
|
198
|
-
if (
|
|
200
|
+
if (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
|
|
199
201
|
process.stderr.write(" 📦 Updating...\n");
|
|
200
202
|
const { spawnSync } = await import("node:child_process");
|
|
201
203
|
const result = spawnSync("npm", ["install", "-g", "cue-ai"], { encoding: "utf8", timeout: 60000, stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -213,8 +215,22 @@ async function checkForUpdate(currentVersion: string): Promise<void> {
|
|
|
213
215
|
async function main(argv: string[]): Promise<number> {
|
|
214
216
|
const args = argv.slice(2);
|
|
215
217
|
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
+
// Update check — never during a live agent launch. The `claude`/`codex`
|
|
219
|
+
// shim is `exec cue launch ...`, so running it here would open a readline on
|
|
220
|
+
// the agent's stdin (stealing keystrokes) and could fire a blocking
|
|
221
|
+
// `npm install -g` mid-session. Skip for any command that spawns an agent
|
|
222
|
+
// (`launch`, plus `quick`/`playground`), for trivial or non-interactive
|
|
223
|
+
// invocations, when launching (CUE_LAUNCHING), or in CI.
|
|
224
|
+
const AGENT_LAUNCH_COMMANDS = new Set(["launch", "quick", "playground"]);
|
|
225
|
+
const TRIVIAL_ARGS = new Set(["--version", "-v", "version", "--help", "-h", "help"]);
|
|
226
|
+
const skipUpdateCheck =
|
|
227
|
+
AGENT_LAUNCH_COMMANDS.has(args[0] ?? "") ||
|
|
228
|
+
TRIVIAL_ARGS.has(args[0] ?? "") ||
|
|
229
|
+
process.env.CUE_LAUNCHING === "1" ||
|
|
230
|
+
!!process.env.CI ||
|
|
231
|
+
!process.stdin.isTTY ||
|
|
232
|
+
!process.stdout.isTTY;
|
|
233
|
+
if (!skipUpdateCheck) checkForUpdate(readVersion()).catch(() => {});
|
|
218
234
|
|
|
219
235
|
if (args.length === 0) {
|
|
220
236
|
// Show status dashboard by default (like `git status`)
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* expected; we skip them and keep going.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import { existsSync, readdirSync, readFileSync, readlinkSync,
|
|
25
|
+
import { existsSync, readdirSync, readFileSync, readlinkSync, } from "node:fs";
|
|
26
26
|
import { homedir } from "node:os";
|
|
27
27
|
import { join } from "node:path";
|
|
28
28
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdtempSync, rmSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir, homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
import { ADAPTERS, AGENT_IDS, getAdapter, claudeCode, codex } from "./agent-adapters";
|
|
7
|
+
|
|
8
|
+
describe("agent-adapters registry contract", () => {
|
|
9
|
+
test("every adapter conforms to the AgentAdapter shape", () => {
|
|
10
|
+
for (const [key, a] of Object.entries(ADAPTERS)) {
|
|
11
|
+
expect(typeof a.id, key).toBe("string");
|
|
12
|
+
expect(a.id.length, key).toBeGreaterThan(0);
|
|
13
|
+
expect(typeof a.name, key).toBe("string");
|
|
14
|
+
expect(typeof a.configDir, key).toBe("function");
|
|
15
|
+
expect(typeof a.writeSkills, key).toBe("function");
|
|
16
|
+
expect(typeof a.writeMcps, key).toBe("function");
|
|
17
|
+
expect(typeof a.detectBinary, key).toBe("function");
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("each adapter's id matches its registry key (no copy-paste drift)", () => {
|
|
22
|
+
for (const [key, a] of Object.entries(ADAPTERS)) {
|
|
23
|
+
expect(a.id).toBe(key);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("AGENT_IDS mirrors the registry keys", () => {
|
|
28
|
+
expect([...AGENT_IDS].sort()).toEqual(Object.keys(ADAPTERS).sort());
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("configDir() returns a non-empty absolute path for every adapter", () => {
|
|
32
|
+
for (const [key, a] of Object.entries(ADAPTERS)) {
|
|
33
|
+
const dir = a.configDir();
|
|
34
|
+
expect(dir.length, key).toBeGreaterThan(0);
|
|
35
|
+
expect(dir.startsWith("/"), key).toBe(true);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("getAdapter", () => {
|
|
41
|
+
test("resolves known agent ids to the right adapter", () => {
|
|
42
|
+
expect(getAdapter("claude-code")).toBe(claudeCode);
|
|
43
|
+
expect(getAdapter("codex")).toBe(codex);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("returns null for an unknown id", () => {
|
|
47
|
+
expect(getAdapter("does-not-exist")).toBeNull();
|
|
48
|
+
expect(getAdapter("")).toBeNull();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("configDir env overrides", () => {
|
|
53
|
+
const saved = { claude: process.env.CLAUDE_CONFIG_DIR, codex: process.env.CODEX_HOME };
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
if (saved.claude === undefined) delete process.env.CLAUDE_CONFIG_DIR;
|
|
56
|
+
else process.env.CLAUDE_CONFIG_DIR = saved.claude;
|
|
57
|
+
if (saved.codex === undefined) delete process.env.CODEX_HOME;
|
|
58
|
+
else process.env.CODEX_HOME = saved.codex;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("claude-code honors CLAUDE_CONFIG_DIR, else ~/.claude", () => {
|
|
62
|
+
process.env.CLAUDE_CONFIG_DIR = "/tmp/custom-claude";
|
|
63
|
+
expect(claudeCode.configDir()).toBe("/tmp/custom-claude");
|
|
64
|
+
delete process.env.CLAUDE_CONFIG_DIR;
|
|
65
|
+
expect(claudeCode.configDir()).toBe(join(homedir(), ".claude"));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("codex honors CODEX_HOME, else ~/.codex", () => {
|
|
69
|
+
process.env.CODEX_HOME = "/tmp/custom-codex";
|
|
70
|
+
expect(codex.configDir()).toBe("/tmp/custom-codex");
|
|
71
|
+
delete process.env.CODEX_HOME;
|
|
72
|
+
expect(codex.configDir()).toBe(join(homedir(), ".codex"));
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("writeMcps behavior", () => {
|
|
77
|
+
let dir: string;
|
|
78
|
+
beforeEach(() => {
|
|
79
|
+
dir = mkdtempSync(join(tmpdir(), "cue-adapters-"));
|
|
80
|
+
});
|
|
81
|
+
afterEach(() => {
|
|
82
|
+
rmSync(dir, { recursive: true, force: true });
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("claude-code writes mcpServers into settings.json and preserves existing keys", () => {
|
|
86
|
+
// Pre-existing settings with an unrelated key that must survive the merge.
|
|
87
|
+
writeFileSync(join(dir, "settings.json"), JSON.stringify({ theme: "dark" }));
|
|
88
|
+
claudeCode.writeMcps({ ctx7: { command: "npx", args: ["ctx7"] } }, dir);
|
|
89
|
+
const out = JSON.parse(readFileSync(join(dir, "settings.json"), "utf8"));
|
|
90
|
+
expect(out.theme).toBe("dark");
|
|
91
|
+
expect(out.mcpServers.ctx7).toEqual({ command: "npx", args: ["ctx7"] });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("codex writes a config.toml with an [mcp_servers.<id>] section", () => {
|
|
95
|
+
codex.writeMcps({ ctx7: { command: "npx" } }, dir);
|
|
96
|
+
const toml = readFileSync(join(dir, "config.toml"), "utf8");
|
|
97
|
+
expect(toml).toContain("[mcp_servers.ctx7]");
|
|
98
|
+
expect(toml).toContain('command = "npx"');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* that a specific agent expects.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { writeFileSync, mkdirSync, existsSync, readFileSync,
|
|
9
|
-
import { join,
|
|
8
|
+
import { writeFileSync, mkdirSync, existsSync, readFileSync, } from "node:fs";
|
|
9
|
+
import { join, } from "node:path";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import { spawnSync } from "node:child_process";
|
|
12
12
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
import { computeDailyActivity } from "./analytics";
|
|
7
|
+
|
|
8
|
+
// A fixed "now" so the day-bucket math is deterministic regardless of when the
|
|
9
|
+
// suite runs. 10:00 UTC means the boundary cases below straddle a UTC midnight.
|
|
10
|
+
const NOW = Date.parse("2026-06-03T10:00:00.000Z");
|
|
11
|
+
|
|
12
|
+
let prevXdg: string | undefined;
|
|
13
|
+
let scratch: string;
|
|
14
|
+
|
|
15
|
+
function writeAnalytics(lines: object[]): void {
|
|
16
|
+
writeFileSync(join(scratch, "cue", "analytics.jsonl"), lines.map((l) => JSON.stringify(l)).join("\n") + "\n");
|
|
17
|
+
}
|
|
18
|
+
function writeSessionLog(lines: object[]): void {
|
|
19
|
+
writeFileSync(join(scratch, "cue", "session-log.jsonl"), lines.map((l) => JSON.stringify(l)).join("\n") + "\n");
|
|
20
|
+
}
|
|
21
|
+
function bucket(rows: { date: string; sessions: number }[], date: string): number {
|
|
22
|
+
return rows.find((r) => r.date === date)?.sessions ?? -1;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
prevXdg = process.env.XDG_CONFIG_HOME;
|
|
27
|
+
scratch = mkdtempSync(join(tmpdir(), "cue-analytics-test-"));
|
|
28
|
+
mkdirSync(join(scratch, "cue"), { recursive: true });
|
|
29
|
+
process.env.XDG_CONFIG_HOME = scratch;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
if (prevXdg === undefined) delete process.env.XDG_CONFIG_HOME;
|
|
34
|
+
else process.env.XDG_CONFIG_HOME = prevXdg;
|
|
35
|
+
try { rmSync(scratch, { recursive: true, force: true }); } catch { /* ignore */ }
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("computeDailyActivity", () => {
|
|
39
|
+
test("returns exactly `days` contiguous UTC buckets ending today", () => {
|
|
40
|
+
writeAnalytics([]);
|
|
41
|
+
writeSessionLog([]);
|
|
42
|
+
const out = computeDailyActivity(30, NOW);
|
|
43
|
+
expect(out).toHaveLength(30);
|
|
44
|
+
expect(out[0]!.date).toBe("2026-05-05"); // now - 29 days
|
|
45
|
+
expect(out[29]!.date).toBe("2026-06-03"); // today
|
|
46
|
+
// every bucket present, zero-filled, strictly ascending
|
|
47
|
+
for (let i = 1; i < out.length; i++) {
|
|
48
|
+
expect(out[i]!.date > out[i - 1]!.date).toBe(true);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("counts a session on its own day", () => {
|
|
53
|
+
writeAnalytics([]);
|
|
54
|
+
writeSessionLog([
|
|
55
|
+
{ ts: "2026-05-20T12:00:00.000Z", cwd: "/x", profile: "core", session_id: "S2" },
|
|
56
|
+
]);
|
|
57
|
+
expect(bucket(computeDailyActivity(30, NOW), "2026-05-20")).toBe(1);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Regression for the off-by-one: reading a full `days` span back pulled in the
|
|
61
|
+
// day BEFORE the oldest bucket. A session whose `start` lands there poisoned the
|
|
62
|
+
// dedup set, so its Stop-hook log on the oldest shown day was dropped. With the
|
|
63
|
+
// fix `since` is the oldest bucket's midnight, so the start is simply out of
|
|
64
|
+
// window and the log counts. This bucket is 2 after the fix, 1 before it.
|
|
65
|
+
test("does not drop a session that starts pre-window but logs on the oldest shown day", () => {
|
|
66
|
+
writeAnalytics([
|
|
67
|
+
// out of window after the fix (prior day, 23:00) — must NOT poison dedup
|
|
68
|
+
{ ts: "2026-05-04T23:00:00.000Z", event: "start", profile: "core", cwd: "/x", session_id: "S1" },
|
|
69
|
+
// in window, early on the oldest shown day — proves full-day capture
|
|
70
|
+
{ ts: "2026-05-05T00:30:00.000Z", event: "start", profile: "core", cwd: "/x", session_id: "S3" },
|
|
71
|
+
]);
|
|
72
|
+
writeSessionLog([
|
|
73
|
+
{ ts: "2026-05-05T01:00:00.000Z", cwd: "/x", profile: "core", session_id: "S1" },
|
|
74
|
+
]);
|
|
75
|
+
const out = computeDailyActivity(30, NOW);
|
|
76
|
+
expect(bucket(out, "2026-05-05")).toBe(2); // S1 (via log) + S3 (via start)
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("excludes events before the window entirely", () => {
|
|
80
|
+
writeAnalytics([]);
|
|
81
|
+
writeSessionLog([
|
|
82
|
+
{ ts: "2026-05-04T09:00:00.000Z", cwd: "/x", profile: "core", session_id: "OLD" },
|
|
83
|
+
]);
|
|
84
|
+
const out = computeDailyActivity(30, NOW);
|
|
85
|
+
const total = out.reduce((a, r) => a + r.sessions, 0);
|
|
86
|
+
expect(total).toBe(0);
|
|
87
|
+
});
|
|
88
|
+
});
|
package/src/lib/analytics.ts
CHANGED
|
@@ -69,10 +69,15 @@ function readSessionLog(since?: Date): SessionLogEntry[] {
|
|
|
69
69
|
* - `skill_invoked` (structured `Skill` tool_use): skill, session_id, tool_use_id
|
|
70
70
|
* - `skill_miss` (trigger matched but skill wasn't fired): session_id,
|
|
71
71
|
* prompt_redacted (first 80 chars, secret-masked), matched_skills
|
|
72
|
+
* - `skill_gap` (self-learner — profile-self-improve.sh Stop hook): where the
|
|
73
|
+
* active profile's skills fell short. `source:"hook"` carries cheap friction
|
|
74
|
+
* `signals`; `source:"critic"` carries a critic-agent verdict (`skill`,
|
|
75
|
+
* `gap_type`, `suggestion`, `confidence`). Consumed by `cue profile
|
|
76
|
+
* self-improve`; inert to existing readers.
|
|
72
77
|
*/
|
|
73
78
|
export interface SessionEvent {
|
|
74
79
|
ts: string;
|
|
75
|
-
event: "start" | "end" | "skill_hit" | "skill_invoked" | "skill_miss";
|
|
80
|
+
event: "start" | "end" | "skill_hit" | "skill_invoked" | "skill_miss" | "skill_gap";
|
|
76
81
|
profile?: string;
|
|
77
82
|
agent?: "claude-code" | "codex";
|
|
78
83
|
cwd?: string;
|
|
@@ -82,6 +87,13 @@ export interface SessionEvent {
|
|
|
82
87
|
tool_use_id?: string;
|
|
83
88
|
prompt_redacted?: string;
|
|
84
89
|
matched_skills?: string[];
|
|
90
|
+
// skill_gap variant
|
|
91
|
+
source?: "hook" | "critic";
|
|
92
|
+
signals?: string[];
|
|
93
|
+
gap_type?: "missing-skill" | "weak-description" | "weak-body" | "profile-composition";
|
|
94
|
+
suggestion?: string;
|
|
95
|
+
confidence?: number;
|
|
96
|
+
first_prompt?: string;
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
/**
|
|
@@ -238,6 +250,75 @@ export function computeStats(optsOrSince: Date | ComputeStatsOptions = {}): Prof
|
|
|
238
250
|
.sort((a, b) => b.sessions - a.sessions);
|
|
239
251
|
}
|
|
240
252
|
|
|
253
|
+
export interface DailyActivity {
|
|
254
|
+
/** Calendar day, `YYYY-MM-DD` (UTC). */
|
|
255
|
+
date: string;
|
|
256
|
+
sessions: number;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Sessions per calendar day over the window, gap-filled so a sparkline/area
|
|
261
|
+
* chart is continuous (days with no activity render as 0, not a missing point).
|
|
262
|
+
* Dedupes a session that appears in both the `start` events and the Stop-hook
|
|
263
|
+
* session log by `session_id`, mirroring computeStats' intent.
|
|
264
|
+
*/
|
|
265
|
+
export function computeDailyActivity(sinceDays: number, now: number = Date.now()): DailyActivity[] {
|
|
266
|
+
const days = Math.max(1, Math.floor(sinceDays));
|
|
267
|
+
// Read from the START of the oldest day we actually render a bucket for. Reading
|
|
268
|
+
// a full `days` span back (now - days*day) reaches into the day BEFORE the oldest
|
|
269
|
+
// bucket: those events have no bucket, and worse, their session ids poison the
|
|
270
|
+
// dedup `seen` set, so a session that starts late on that prior day but whose
|
|
271
|
+
// Stop-hook log lands on the oldest shown day is dropped from the chart entirely.
|
|
272
|
+
// Anchoring `since` to the oldest bucket's UTC midnight keeps read and display
|
|
273
|
+
// windows identical.
|
|
274
|
+
const oldestDay = new Date(now - (days - 1) * 86_400_000).toISOString().slice(0, 10);
|
|
275
|
+
const since = new Date(`${oldestDay}T00:00:00.000Z`);
|
|
276
|
+
const counts = new Map<string, number>();
|
|
277
|
+
const seen = new Set<string>();
|
|
278
|
+
const bump = (ts: string, id: string): void => {
|
|
279
|
+
if (seen.has(id)) return;
|
|
280
|
+
seen.add(id);
|
|
281
|
+
const day = ts.slice(0, 10);
|
|
282
|
+
counts.set(day, (counts.get(day) ?? 0) + 1);
|
|
283
|
+
};
|
|
284
|
+
for (const e of readEvents(since)) {
|
|
285
|
+
if (e.event !== "start" || !e.profile) continue;
|
|
286
|
+
bump(e.ts, e.session_id || `start|${e.ts}|${e.cwd ?? ""}`);
|
|
287
|
+
}
|
|
288
|
+
for (const e of readSessionLog(since)) {
|
|
289
|
+
bump(e.ts, e.session_id || `log|${e.ts}|${e.cwd}`);
|
|
290
|
+
}
|
|
291
|
+
const out: DailyActivity[] = [];
|
|
292
|
+
for (let i = days - 1; i >= 0; i--) {
|
|
293
|
+
const key = new Date(now - i * 86_400_000).toISOString().slice(0, 10);
|
|
294
|
+
out.push({ date: key, sessions: counts.get(key) ?? 0 });
|
|
295
|
+
}
|
|
296
|
+
return out;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export interface DurationSummary {
|
|
300
|
+
/** Average length of *ended* sessions, in seconds. */
|
|
301
|
+
avgS: number;
|
|
302
|
+
/** Total tracked session time, in seconds. */
|
|
303
|
+
totalS: number;
|
|
304
|
+
/** How many sessions had a recorded end (the basis for avgS). */
|
|
305
|
+
ended: number;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Aggregate session-duration stats from `end` events (the only ones carrying
|
|
310
|
+
* `duration_s`). Reported separately from session *counts* because many
|
|
311
|
+
* sessions start but never log a clean end — averaging over starts would
|
|
312
|
+
* understate real session length.
|
|
313
|
+
*/
|
|
314
|
+
export function sessionDurationSummary(since?: Date): DurationSummary {
|
|
315
|
+
const ends = readEvents(since).filter(
|
|
316
|
+
(e) => e.event === "end" && typeof e.duration_s === "number",
|
|
317
|
+
);
|
|
318
|
+
const totalS = ends.reduce((a, e) => a + (e.duration_s ?? 0), 0);
|
|
319
|
+
return { avgS: ends.length ? Math.round(totalS / ends.length) : 0, totalS, ended: ends.length };
|
|
320
|
+
}
|
|
321
|
+
|
|
241
322
|
export interface SkillUsageStats {
|
|
242
323
|
skill: string;
|
|
243
324
|
hits: number;
|
|
@@ -24,14 +24,20 @@ describe("detectProfileV2", () => {
|
|
|
24
24
|
expect(rust!.reasons).toContain("Cargo.toml");
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
test("Cargo.toml + src/main.rs → rust-
|
|
27
|
+
test("Cargo.toml + src/main.rs → rust, corroborated above the lone-signal base", () => {
|
|
28
28
|
writeFileSync(join(tmp, "Cargo.toml"), "[package]");
|
|
29
29
|
mkdirSync(join(tmp, "src"));
|
|
30
30
|
writeFileSync(join(tmp, "src/main.rs"), "fn main() {}");
|
|
31
31
|
const results = detectProfileV2(tmp);
|
|
32
|
-
const
|
|
33
|
-
expect(
|
|
34
|
-
expect(
|
|
32
|
+
const rust = results.find(r => r.profile === "rust");
|
|
33
|
+
expect(rust).toBeDefined();
|
|
34
|
+
expect(rust!.reasons).toContain("src/main.rs");
|
|
35
|
+
// Two corroborating signals (Cargo.toml + src/main.rs) lift confidence
|
|
36
|
+
// above the 0.9 lone-signal base, capped at 0.97.
|
|
37
|
+
expect(rust!.confidence).toBeGreaterThan(0.9);
|
|
38
|
+
expect(rust!.confidence).toBeLessThanOrEqual(0.97);
|
|
39
|
+
// `rust-cli` was a phantom profile (no profiles/rust-cli on disk) — gone now.
|
|
40
|
+
expect(results.find(r => r.profile === "rust-cli")).toBeUndefined();
|
|
35
41
|
});
|
|
36
42
|
|
|
37
43
|
test("package.json with next → nextjs 0.9", () => {
|
package/src/lib/auto-detect.ts
CHANGED
|
@@ -12,7 +12,7 @@ interface Signal {
|
|
|
12
12
|
profile: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const SIGNALS: Signal[] = [
|
|
15
|
+
export const SIGNALS: Signal[] = [
|
|
16
16
|
// Frontend / Next.js
|
|
17
17
|
{ file: "next.config.js", weight: 5, profile: "nextjs" },
|
|
18
18
|
{ file: "next.config.ts", weight: 5, profile: "nextjs" },
|
|
@@ -41,15 +41,15 @@ const SIGNALS: Signal[] = [
|
|
|
41
41
|
{ file: ".github/workflows/", weight: 1, profile: "backend" },
|
|
42
42
|
|
|
43
43
|
// Python API
|
|
44
|
-
{ file: "pyproject.toml", weight: 4, profile: "python
|
|
45
|
-
{ file: "setup.py", weight: 3, profile: "python
|
|
46
|
-
{ file: "requirements.txt", weight: 3, profile: "python
|
|
47
|
-
{ file: "app/main.py", weight: 5, profile: "python
|
|
48
|
-
{ file: "main.py", weight: 3, profile: "python
|
|
49
|
-
{ file: "manage.py", weight: 5, profile: "python
|
|
50
|
-
{ file: "uvicorn.ini", weight: 4, profile: "python
|
|
51
|
-
{ file: "alembic.ini", weight: 4, profile: "python
|
|
52
|
-
{ file: ".python-version", weight: 2, profile: "python
|
|
44
|
+
{ file: "pyproject.toml", weight: 4, profile: "python" },
|
|
45
|
+
{ file: "setup.py", weight: 3, profile: "python" },
|
|
46
|
+
{ file: "requirements.txt", weight: 3, profile: "python" },
|
|
47
|
+
{ file: "app/main.py", weight: 5, profile: "python" },
|
|
48
|
+
{ file: "main.py", weight: 3, profile: "python" },
|
|
49
|
+
{ file: "manage.py", weight: 5, profile: "python" },
|
|
50
|
+
{ file: "uvicorn.ini", weight: 4, profile: "python" },
|
|
51
|
+
{ file: "alembic.ini", weight: 4, profile: "python" },
|
|
52
|
+
{ file: ".python-version", weight: 2, profile: "python" },
|
|
53
53
|
|
|
54
54
|
// Rust
|
|
55
55
|
{ file: "Cargo.toml", weight: 5, profile: "rust" },
|
|
@@ -58,10 +58,6 @@ const SIGNALS: Signal[] = [
|
|
|
58
58
|
{ file: "src/lib.rs", weight: 3, profile: "rust" },
|
|
59
59
|
{ file: ".cargo/config.toml", weight: 2, profile: "rust" },
|
|
60
60
|
|
|
61
|
-
// Rust CLI sub-profile
|
|
62
|
-
{ file: "src/main.rs", weight: 3, profile: "rust-cli" },
|
|
63
|
-
{ file: "Cargo.toml", weight: 3, profile: "rust-cli" },
|
|
64
|
-
|
|
65
61
|
// Go API
|
|
66
62
|
{ file: "go.mod", weight: 5, profile: "go-api" },
|
|
67
63
|
{ file: "go.sum", weight: 3, profile: "go-api" },
|
|
@@ -97,9 +93,9 @@ const SIGNALS: Signal[] = [
|
|
|
97
93
|
// Three.js
|
|
98
94
|
{ file: "three.js", weight: 4, profile: "threejs" },
|
|
99
95
|
|
|
100
|
-
//
|
|
101
|
-
{ file: "CLAUDE.md", weight: 2, profile: "
|
|
102
|
-
{ file: ".claude/", weight: 2, profile: "
|
|
96
|
+
// Generic Claude-managed repo → baseline profile
|
|
97
|
+
{ file: "CLAUDE.md", weight: 2, profile: "core" },
|
|
98
|
+
{ file: ".claude/", weight: 2, profile: "core" },
|
|
103
99
|
|
|
104
100
|
// Full (meta)
|
|
105
101
|
{ file: "profiles/", weight: 2, profile: "full" },
|
|
@@ -183,7 +179,7 @@ export function detectProfileV2(cwd: string): DetectionResultV2[] {
|
|
|
183
179
|
// ── Rust ──
|
|
184
180
|
if (ex(cwd, "Cargo.toml")) {
|
|
185
181
|
add("rust", 0.9, "Cargo.toml");
|
|
186
|
-
if (ex(cwd, "src/main.rs")) add("rust
|
|
182
|
+
if (ex(cwd, "src/main.rs")) add("rust", 0.7, "src/main.rs");
|
|
187
183
|
if (ex(cwd, "src/lib.rs")) add("rust", 0.6, "src/lib.rs");
|
|
188
184
|
}
|
|
189
185
|
|
|
@@ -193,10 +189,10 @@ export function detectProfileV2(cwd: string): DetectionResultV2[] {
|
|
|
193
189
|
if (exAny(cwd, ["cmd", "internal"])) add("go-api", 0.4, "cmd/ or internal/");
|
|
194
190
|
|
|
195
191
|
// ── Python ──
|
|
196
|
-
if (ex(cwd, "pyproject.toml")) add("python
|
|
197
|
-
if (ex(cwd, "requirements.txt")) add("python
|
|
198
|
-
if (ex(cwd, "manage.py")) add("python
|
|
199
|
-
if (exAny(cwd, ["alembic.ini", "app/main.py"])) add("python
|
|
192
|
+
if (ex(cwd, "pyproject.toml")) add("python", 0.7, "pyproject.toml");
|
|
193
|
+
if (ex(cwd, "requirements.txt")) add("python", 0.7, "requirements.txt");
|
|
194
|
+
if (ex(cwd, "manage.py")) add("python", 0.8, "manage.py");
|
|
195
|
+
if (exAny(cwd, ["alembic.ini", "app/main.py"])) add("python", 0.6, "alembic.ini or app/main.py");
|
|
200
196
|
|
|
201
197
|
// ── Backend (containers / CI / DB) ──
|
|
202
198
|
if (exAny(cwd, ["docker-compose.yml", "docker-compose.yaml", "Dockerfile"])) {
|
|
@@ -223,7 +219,7 @@ export function detectProfileV2(cwd: string): DetectionResultV2[] {
|
|
|
223
219
|
|
|
224
220
|
// ── Fleet / meta ──
|
|
225
221
|
if (exAny(cwd, [".colony", ".omx", "scripts/codex-fleet"])) add("fleet-control", 0.6, "fleet markers");
|
|
226
|
-
if (exAny(cwd, ["CLAUDE.md", ".claude"])) add("
|
|
222
|
+
if (exAny(cwd, ["CLAUDE.md", ".claude"])) add("core", 0.4, "CLAUDE.md or .claude/");
|
|
227
223
|
if (ex(cwd, "profiles")) add("full", 0.3, "profiles/ dir");
|
|
228
224
|
|
|
229
225
|
// ── package.json deps ──
|
package/src/lib/brand-icons.ts
CHANGED
|
@@ -14,7 +14,6 @@ import { fileURLToPath } from "node:url";
|
|
|
14
14
|
|
|
15
15
|
const REPO_ROOT = process.env.CUE_REPO_ROOT ?? process.env.SOUL_REPO_ROOT ?? resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
16
16
|
const SKILLS_ROOT = join(REPO_ROOT, "resources", "skills", "skills");
|
|
17
|
-
const PROFILES_DIR = join(REPO_ROOT, "profiles");
|
|
18
17
|
const ICONS_DIR = join(REPO_ROOT, "resources", "icons");
|
|
19
18
|
|
|
20
19
|
// Known brand → asset file mappings (skill slug or MCP id → relative icon path)
|
package/src/lib/cache.ts
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSync, utimesSync } from "node:fs";
|
|
20
|
-
import { homedir } from "node:os";
|
|
21
20
|
import { dirname, join, resolve } from "node:path";
|
|
21
|
+
import { cacheDir } from "./config-paths";
|
|
22
22
|
|
|
23
23
|
export interface CacheLayout {
|
|
24
24
|
/**
|
|
@@ -41,8 +41,7 @@ const NPX_SUBDIR = "npx";
|
|
|
41
41
|
function npxRoot(layout: CacheLayout): string {
|
|
42
42
|
if (layout.cacheRoot) return resolve(layout.cacheRoot, NPX_SUBDIR);
|
|
43
43
|
if (layout.repoRoot) return resolve(layout.repoRoot, "profiles", "_cache", NPX_SUBDIR);
|
|
44
|
-
|
|
45
|
-
return join(xdg, "cue", NPX_SUBDIR);
|
|
44
|
+
return join(cacheDir(), NPX_SUBDIR);
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
/** Maximum number of cache entries before LRU eviction kicks in. */
|