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/commands/launch.ts
CHANGED
|
@@ -13,19 +13,30 @@
|
|
|
13
13
|
|
|
14
14
|
import { spawn } from "node:child_process";
|
|
15
15
|
import { readFile } from "node:fs/promises";
|
|
16
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
16
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
17
17
|
import { basename, join, resolve } from "node:path";
|
|
18
18
|
import { homedir } from "node:os";
|
|
19
|
+
import { configDir } from "../lib/config-paths";
|
|
20
|
+
import { debug } from "../lib/debug-log";
|
|
21
|
+
import {
|
|
22
|
+
computeTokenBreakdown,
|
|
23
|
+
splitSkillBytes,
|
|
24
|
+
tokenLevelEmoji,
|
|
25
|
+
type SkillTokens,
|
|
26
|
+
type TokenBreakdown,
|
|
27
|
+
} from "../lib/token-budget";
|
|
19
28
|
|
|
20
29
|
import { loadProfile, listProfiles, listFeaturedProfiles, parseProfileSelector } from "../lib/profile-loader";
|
|
21
30
|
import { resolveProfileForCwd } from "../lib/cwd-resolver";
|
|
22
|
-
import { DIVIDER_PREFIX, runPicker, type PickerOption } from "../lib/picker";
|
|
31
|
+
import { DIVIDER_PREFIX, runPicker, type PickerOption, type ProfileTally } from "../lib/picker";
|
|
23
32
|
import { materializeRuntime, type McpServerConfig } from "../lib/runtime-materializer";
|
|
24
33
|
import { resolveLocalSkill, listAllSkillIds } from "../lib/resolver-local";
|
|
25
34
|
import { detectKittyTerminal, kittyPlaceholderLabel, transmitKittyImage } from "../lib/kitty-image";
|
|
26
35
|
import { computeStats } from "../lib/analytics";
|
|
27
36
|
import { detectProfileV2, type DetectionResultV2 } from "../lib/auto-detect";
|
|
37
|
+
import { detectCompanions, type CompanionSignal } from "../lib/companion-detect";
|
|
28
38
|
import type { ResolvedProfile } from "../../profiles/_types";
|
|
39
|
+
import type { ProfileAffinity, UniversalSuggestion } from "../lib/pair-suggestions";
|
|
29
40
|
import { hasWorkspaces, getActiveWorkspace, computeOverrides, resolveWorkspaceForCwd } from "../lib/workspaces";
|
|
30
41
|
|
|
31
42
|
// ---------------------------------------------------------------------------
|
|
@@ -120,15 +131,6 @@ async function applyWorkspaceOverrides(profile: ResolvedProfile): Promise<Resolv
|
|
|
120
131
|
return result;
|
|
121
132
|
}
|
|
122
133
|
|
|
123
|
-
// ---------------------------------------------------------------------------
|
|
124
|
-
// Config dir helper
|
|
125
|
-
// ---------------------------------------------------------------------------
|
|
126
|
-
|
|
127
|
-
function configDir(): string {
|
|
128
|
-
return process.env.XDG_CONFIG_HOME
|
|
129
|
-
? join(process.env.XDG_CONFIG_HOME, "cue")
|
|
130
|
-
: join(homedir(), ".config", "cue");
|
|
131
|
-
}
|
|
132
134
|
|
|
133
135
|
// ---------------------------------------------------------------------------
|
|
134
136
|
// Exec helper — spawn with inherited stdio so interactive sessions work
|
|
@@ -301,6 +303,7 @@ async function expandWildcards(profile: ResolvedProfile): Promise<void> {
|
|
|
301
303
|
* Colors are emitted only when stdout is a TTY and `NO_COLOR` is unset.
|
|
302
304
|
*/
|
|
303
305
|
const LIST_TRUNCATE = 8;
|
|
306
|
+
const BREAKDOWN_MAX = 6; // per-profile skill breakdown cap before "+N more"
|
|
304
307
|
const COMMANDS_PER_LINE = 4;
|
|
305
308
|
const LABEL_WIDTH = 10; // "commands " — keep visually aligned
|
|
306
309
|
|
|
@@ -320,10 +323,16 @@ export function formatProfileSummary(
|
|
|
320
323
|
const breakdown = npxCount > 0 ? ` (${localCount} local, ${npxCount} npx)` : "";
|
|
321
324
|
let line = `${label("skills")}${c.yellow(String(totalSkills))}${c.dim(breakdown)}`;
|
|
322
325
|
if (parts && parts.length > 1) {
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
326
|
+
const segs = parts.map(
|
|
327
|
+
(p) => `${p.icon ? `${p.icon} ` : ""}${p.name}:${p.skills.local.length + p.skills.npx.length}`,
|
|
328
|
+
);
|
|
329
|
+
// Cap the per-profile breakdown so a fat composite doesn't wrap into a
|
|
330
|
+
// multi-line wall — the headline total already carries the full picture.
|
|
331
|
+
const shown =
|
|
332
|
+
segs.length > BREAKDOWN_MAX
|
|
333
|
+
? `${segs.slice(0, BREAKDOWN_MAX).join(" + ")} +${segs.length - BREAKDOWN_MAX} more`
|
|
334
|
+
: segs.join(" + ");
|
|
335
|
+
line += ` ${c.dim("←")} ${c.dim(shown)}`;
|
|
327
336
|
}
|
|
328
337
|
lines.push(line);
|
|
329
338
|
if (localCount >= 5) {
|
|
@@ -409,106 +418,16 @@ function colorFns() {
|
|
|
409
418
|
// at the call site that supplies them with real file measurements.
|
|
410
419
|
// ---------------------------------------------------------------------------
|
|
411
420
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
/** Sum of body tokens — the ceiling if every skill activates this session. */
|
|
423
|
-
maxIfAllActivate: number;
|
|
424
|
-
/** Skill count for the header line. */
|
|
425
|
-
totalSkills: number;
|
|
426
|
-
/**
|
|
427
|
-
* Per-profile attribution of `alwaysOn` for composite selectors (length > 1).
|
|
428
|
-
* Each skill is credited to the first part that declares it, so per-part
|
|
429
|
-
* numbers sum to `alwaysOn` (no double-counting from overlap). Empty for
|
|
430
|
-
* single-part profiles. `icon` carries the part's emoji when declared.
|
|
431
|
-
*/
|
|
432
|
-
byProfile: { name: string; icon?: string; tokens: number; skillCount: number }[];
|
|
433
|
-
/** Skills sorted by body size, descending — for the "heaviest if activated" hint. */
|
|
434
|
-
heaviestBodies: { id: string; tokens: number }[];
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
export function computeTokenBreakdown(
|
|
438
|
-
profile: ResolvedProfile,
|
|
439
|
-
parts: ResolvedProfile[] | undefined,
|
|
440
|
-
tokensForSkill: (id: string) => SkillTokens,
|
|
441
|
-
): TokenBreakdown {
|
|
442
|
-
let alwaysOn = 0;
|
|
443
|
-
let maxIfAllActivate = 0;
|
|
444
|
-
const heaviestBodies: { id: string; tokens: number }[] = [];
|
|
445
|
-
for (const s of profile.skills.local) {
|
|
446
|
-
const { frontmatter, body } = tokensForSkill(s.id);
|
|
447
|
-
alwaysOn += frontmatter;
|
|
448
|
-
maxIfAllActivate += body;
|
|
449
|
-
if (body > 0) heaviestBodies.push({ id: s.id, tokens: body });
|
|
450
|
-
}
|
|
451
|
-
heaviestBodies.sort((a, b) => b.tokens - a.tokens);
|
|
452
|
-
|
|
453
|
-
const byProfile: TokenBreakdown["byProfile"] = [];
|
|
454
|
-
if (parts && parts.length > 1) {
|
|
455
|
-
const credited = new Set<string>();
|
|
456
|
-
for (const part of parts) {
|
|
457
|
-
let pTokens = 0;
|
|
458
|
-
let pCount = 0;
|
|
459
|
-
for (const s of part.skills.local) {
|
|
460
|
-
if (credited.has(s.id)) continue;
|
|
461
|
-
credited.add(s.id);
|
|
462
|
-
const { frontmatter } = tokensForSkill(s.id);
|
|
463
|
-
if (frontmatter > 0) {
|
|
464
|
-
pTokens += frontmatter;
|
|
465
|
-
pCount += 1;
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
byProfile.push({ name: part.name, icon: part.icon, tokens: pTokens, skillCount: pCount });
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
return {
|
|
473
|
-
alwaysOn,
|
|
474
|
-
maxIfAllActivate,
|
|
475
|
-
totalSkills: profile.skills.local.length,
|
|
476
|
-
byProfile,
|
|
477
|
-
heaviestBodies,
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* Extract frontmatter byte length from a SKILL.md string. Returns
|
|
483
|
-
* `{ frontmatter, body }` byte counts. Falls back to a token count of zero
|
|
484
|
-
* when the file lacks the leading `---` block (still legal but rare).
|
|
485
|
-
*/
|
|
486
|
-
export function splitSkillBytes(source: string): { frontmatter: number; body: number } {
|
|
487
|
-
if (!source.startsWith("---\n") && !source.startsWith("---\r\n")) {
|
|
488
|
-
return { frontmatter: 0, body: source.length };
|
|
489
|
-
}
|
|
490
|
-
// Find the closing `---` on its own line. Search starts after the opener.
|
|
491
|
-
const closer = source.indexOf("\n---", 4);
|
|
492
|
-
if (closer === -1) {
|
|
493
|
-
return { frontmatter: source.length, body: 0 };
|
|
494
|
-
}
|
|
495
|
-
// Include the closing `---\n` in the frontmatter block.
|
|
496
|
-
const fmEnd = source.indexOf("\n", closer + 1);
|
|
497
|
-
const cut = fmEnd === -1 ? source.length : fmEnd + 1;
|
|
498
|
-
return { frontmatter: cut, body: source.length - cut };
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* Map an always-on token count to the bands we color in the CLI banner and
|
|
503
|
-
* the tmux pane-border badge. Single source of truth so the two displays
|
|
504
|
-
* never drift apart on threshold values.
|
|
505
|
-
*/
|
|
506
|
-
export function tokenLevelEmoji(alwaysOn: number): "🔴" | "🟠" | "🟡" | "🟢" {
|
|
507
|
-
return alwaysOn > 15000 ? "🔴"
|
|
508
|
-
: alwaysOn > 10000 ? "🟠"
|
|
509
|
-
: alwaysOn > 5000 ? "🟡"
|
|
510
|
-
: "🟢";
|
|
511
|
-
}
|
|
421
|
+
// Token-budget math (SkillTokens, TokenBreakdown, computeTokenBreakdown,
|
|
422
|
+
// splitSkillBytes, tokenLevelEmoji) moved to lib/token-budget.ts. Re-exported
|
|
423
|
+
// here so existing importers of these from "./launch" keep resolving.
|
|
424
|
+
export {
|
|
425
|
+
computeTokenBreakdown,
|
|
426
|
+
splitSkillBytes,
|
|
427
|
+
tokenLevelEmoji,
|
|
428
|
+
type SkillTokens,
|
|
429
|
+
type TokenBreakdown,
|
|
430
|
+
} from "../lib/token-budget";
|
|
512
431
|
|
|
513
432
|
/** Format the token-overhead block. Returns `[]` under the 2K always-on floor. */
|
|
514
433
|
export function formatTokenWarning(b: TokenBreakdown): string[] {
|
|
@@ -691,6 +610,28 @@ export const SUGGESTED_MIN_CONFIDENCE = 0.5;
|
|
|
691
610
|
*/
|
|
692
611
|
export const SUGGESTED_AUTO_PICK_CONFIDENCE = 0.7;
|
|
693
612
|
|
|
613
|
+
/**
|
|
614
|
+
* Registered postizz brand folder names (dir basenames under
|
|
615
|
+
* profiles/postizz/brands), used by the combine companion detector to suggest
|
|
616
|
+
* postizz when the cwd is a brand dir. Best-effort: missing dir → empty set.
|
|
617
|
+
* Resolves the profiles root exactly like listProfileOptions does.
|
|
618
|
+
*/
|
|
619
|
+
function listPostizzBrands(): Set<string> {
|
|
620
|
+
try {
|
|
621
|
+
const profilesRoot =
|
|
622
|
+
process.env.CUE_PROFILES_DIR ??
|
|
623
|
+
process.env.SOUL_PROFILES_DIR ??
|
|
624
|
+
join(resolve(new URL(import.meta.url).pathname, "..", "..", ".."), "profiles");
|
|
625
|
+
return new Set(
|
|
626
|
+
readdirSync(join(profilesRoot, "postizz", "brands"), { withFileTypes: true })
|
|
627
|
+
.filter((d) => d.isDirectory())
|
|
628
|
+
.map((d) => d.name),
|
|
629
|
+
);
|
|
630
|
+
} catch {
|
|
631
|
+
return new Set();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
694
635
|
// Recent now answers "what were the last N profiles I picked," not "what do
|
|
695
636
|
// I pick most often." It sorts strictly by lastUsed timestamp and applies no
|
|
696
637
|
// session-count floor — a single deliberate pick yesterday belongs in Recent
|
|
@@ -801,9 +742,17 @@ function makeSelectorOption(selector: string, allProfileOpts: PickerOption[]): P
|
|
|
801
742
|
// synthesize a self-describing row for; a bare unknown name is a stale or
|
|
802
743
|
// deleted profile and is dropped (undefined) so it never shows in the picker.
|
|
803
744
|
if (!selector.includes("+")) return undefined;
|
|
745
|
+
// Reuse each part's own option label so the combined row carries every part's
|
|
746
|
+
// icon — emoji or kitty image placeholder — e.g. "📈 improver + 🔒 secops + 🐻
|
|
747
|
+
// builder" instead of bare "improver + secops + builder". Parts with no
|
|
748
|
+
// resolved option (stale) fall back to the bare name.
|
|
749
|
+
const label = selector
|
|
750
|
+
.split("+")
|
|
751
|
+
.map((part) => allProfileOpts.find((o) => o.value === part)?.label ?? part)
|
|
752
|
+
.join(" + ");
|
|
804
753
|
return {
|
|
805
754
|
value: selector,
|
|
806
|
-
label
|
|
755
|
+
label,
|
|
807
756
|
hint: "stacked profile",
|
|
808
757
|
};
|
|
809
758
|
}
|
|
@@ -966,7 +915,7 @@ export function getDefaultSelector(
|
|
|
966
915
|
.map((s) => s.trim())
|
|
967
916
|
.map((s) => s.replace(/#.*$/, "").trim())
|
|
968
917
|
.filter((s) => s.length > 0 && s !== "core");
|
|
969
|
-
} catch { /*
|
|
918
|
+
} catch (err) { debug("launch:default-profile", err); /* missing → core only */ }
|
|
970
919
|
// Dedupe while preserving order.
|
|
971
920
|
const seen = new Set<string>(["core"]);
|
|
972
921
|
const parts = ["core"];
|
|
@@ -1027,8 +976,9 @@ async function listProfileOptions(pinnedProfile?: string): Promise<PickerOption[
|
|
|
1027
976
|
const label = warning ? `${nameLabel}${warning.labelSuffix}` : nameLabel;
|
|
1028
977
|
const hint = warning ? warning.hint : p.description;
|
|
1029
978
|
const recommends = p.recommends.filter((r) => r !== name && knownNames.has(r));
|
|
979
|
+
const autoSelect = p.autoSelect.filter((r) => r !== name && knownNames.has(r));
|
|
1030
980
|
const conflicts = p.conflicts.filter((c) => c !== name && knownNames.has(c));
|
|
1031
|
-
opts.push({ value: name, label, hint, recommends, conflicts });
|
|
981
|
+
opts.push({ value: name, label, hint, recommends, autoSelect, conflicts });
|
|
1032
982
|
} catch {
|
|
1033
983
|
opts.push({ value: name, label: name, hint: "" });
|
|
1034
984
|
}
|
|
@@ -1152,7 +1102,7 @@ async function loadMcpRegistry(agent: "claude-code" | "codex"): Promise<Record<s
|
|
|
1152
1102
|
for (const [k, v] of Object.entries(raw.servers ?? {})) {
|
|
1153
1103
|
merged[k] = v;
|
|
1154
1104
|
}
|
|
1155
|
-
} catch {
|
|
1105
|
+
} catch (err) { debug("launch:master-config", err); /* keep runtime fallbacks */ }
|
|
1156
1106
|
|
|
1157
1107
|
return merged;
|
|
1158
1108
|
}
|
|
@@ -1301,7 +1251,7 @@ async function resolveClaudeCredentialsSource(): Promise<string> {
|
|
|
1301
1251
|
`▸ cue: refreshed source credentials from a sibling runtime (rotated refresh-token healed)\n`,
|
|
1302
1252
|
);
|
|
1303
1253
|
}
|
|
1304
|
-
} catch {
|
|
1254
|
+
} catch (err) { debug("launch:runtime-heal", err); /* best-effort — never blocks launch */ }
|
|
1305
1255
|
return picked;
|
|
1306
1256
|
}
|
|
1307
1257
|
|
|
@@ -1414,7 +1364,6 @@ export async function run(args: string[]): Promise<number> {
|
|
|
1414
1364
|
const ok = await runGlobalOnboarding();
|
|
1415
1365
|
if (ok) {
|
|
1416
1366
|
try {
|
|
1417
|
-
const { configDir } = await import("../lib/telemetry-consent");
|
|
1418
1367
|
mkdirSync(configDir(), { recursive: true });
|
|
1419
1368
|
writeFileSync(marker, new Date().toISOString() + "\n");
|
|
1420
1369
|
} catch { /* non-fatal */ }
|
|
@@ -1428,32 +1377,108 @@ export async function run(args: string[]): Promise<number> {
|
|
|
1428
1377
|
// The picker pre-checks empirical partners in the combine multiselect.
|
|
1429
1378
|
// Best-effort: any failure (missing log, malformed lines) yields empty.
|
|
1430
1379
|
let pairSuggestions: Map<string, string[]> | undefined;
|
|
1380
|
+
// Affinity map (own-pick + co-occurrence counts) is mined once here and
|
|
1381
|
+
// reused by the cross-profile frequency suggestions below.
|
|
1382
|
+
let affinity: Map<string, ProfileAffinity> = new Map();
|
|
1431
1383
|
try {
|
|
1432
1384
|
const { computeAffinityMap, suggestionsByProfile } = await import("../lib/pair-suggestions");
|
|
1433
|
-
|
|
1434
|
-
|
|
1385
|
+
affinity = computeAffinityMap();
|
|
1386
|
+
// Surface a partner after a *single* prior combo: these now render
|
|
1387
|
+
// unchecked + hinted ("you paired these before"), so a low bar is a gentle
|
|
1388
|
+
// recommendation, not an auto-pin. (The stricter defaults still apply to
|
|
1389
|
+
// `cue suggest-pairs`, which reports rather than pre-fills.)
|
|
1390
|
+
const sug = suggestionsByProfile(affinity, { minCount: 1, minAffinity: 0, limit: 6 });
|
|
1435
1391
|
pairSuggestions = new Map();
|
|
1436
1392
|
for (const [name, partners] of sug) {
|
|
1437
1393
|
pairSuggestions.set(name, partners.map((p) => p.name));
|
|
1438
1394
|
}
|
|
1439
|
-
} catch {
|
|
1395
|
+
} catch (err) { debug("launch:pair-suggestions", err); }
|
|
1396
|
+
// Installed profile names, computed ONCE and shared by the autodetect +
|
|
1397
|
+
// companion passes below (both filter their detections to known profiles).
|
|
1398
|
+
// Previously each pass re-walked listProfiles() independently.
|
|
1399
|
+
let knownProfileNames = new Set<string>();
|
|
1400
|
+
try {
|
|
1401
|
+
knownProfileNames = new Set(await listProfiles());
|
|
1402
|
+
} catch (err) { debug("launch:list-profiles", err); }
|
|
1440
1403
|
// Cwd autodetect signals, forwarded to runPicker so it can offer a
|
|
1441
1404
|
// "switch to <X>?" nudge when the user picks a profile that conflicts
|
|
1442
1405
|
// with what the directory actually looks like (e.g. picking medusa-next
|
|
1443
1406
|
// in a vite.config.ts project).
|
|
1444
1407
|
let detected: ReadonlyArray<{ name: string; reasons: string[]; confidence: number }> = [];
|
|
1445
1408
|
try {
|
|
1446
|
-
const knownProfileNames = new Set(await listProfiles());
|
|
1447
1409
|
detected = detectProfileV2(cwd)
|
|
1448
1410
|
.filter((d) => knownProfileNames.has(d.profile))
|
|
1449
1411
|
.map((d) => ({ name: d.profile, reasons: d.reasons, confidence: d.confidence }));
|
|
1450
|
-
} catch {
|
|
1412
|
+
} catch (err) { debug("launch:autodetect", err); }
|
|
1413
|
+
// Content-aware combine companions: scan the cwd for asset/draft/brand
|
|
1414
|
+
// signals and feed matching profiles into the combine multiselect.
|
|
1415
|
+
let companions: CompanionSignal[] = [];
|
|
1416
|
+
try {
|
|
1417
|
+
companions = detectCompanions({ cwd, knownProfiles: knownProfileNames, brands: listPostizzBrands() });
|
|
1418
|
+
} catch (err) { debug("launch:companions", err); }
|
|
1419
|
+
// Cross-profile combine suggestions offered under every primary: the curated
|
|
1420
|
+
// `_featured.yaml` set (improver, secops, builder, …) plus the profiles the
|
|
1421
|
+
// user picks most often (from the affinity map above). Offered unchecked.
|
|
1422
|
+
let universalSuggestions: UniversalSuggestion[] = [];
|
|
1423
|
+
try {
|
|
1424
|
+
const { buildUniversalSuggestions } = await import("../lib/pair-suggestions");
|
|
1425
|
+
const featured = await listFeaturedProfiles();
|
|
1426
|
+
universalSuggestions = buildUniversalSuggestions({ featured, affinity, known: knownProfileNames });
|
|
1427
|
+
} catch (err) { debug("launch:universal-suggestions", err); }
|
|
1428
|
+
// Per-profile resource tally for the combine multiselect's live preview +
|
|
1429
|
+
// per-row hints. Memoized so each offered profile loads at most once.
|
|
1430
|
+
// A shared skill-token reader feeds the always-on estimate (frontmatter
|
|
1431
|
+
// bytes ÷4 ≈ tokens) — same approximation as the post-launch overhead
|
|
1432
|
+
// banner below, so the picker's heads-up and the banner agree.
|
|
1433
|
+
const { readFileSync: readSkillFile } = await import("node:fs");
|
|
1434
|
+
const skillsRootForTally = join(
|
|
1435
|
+
process.env.CUE_REPO_ROOT ?? resolve(new URL(import.meta.url).pathname, "..", "..", ".."),
|
|
1436
|
+
"resources", "skills", "skills",
|
|
1437
|
+
);
|
|
1438
|
+
const skillTokenCache = new Map<string, SkillTokens>();
|
|
1439
|
+
const tokensForSkill = (id: string): SkillTokens => {
|
|
1440
|
+
const c = skillTokenCache.get(id);
|
|
1441
|
+
if (c) return c;
|
|
1442
|
+
let result: SkillTokens = { frontmatter: 0, body: 0 };
|
|
1443
|
+
try {
|
|
1444
|
+
const { frontmatter, body } = splitSkillBytes(readSkillFile(join(skillsRootForTally, id, "SKILL.md"), "utf8"));
|
|
1445
|
+
result = { frontmatter: Math.ceil(frontmatter / 4), body: Math.ceil(body / 4) };
|
|
1446
|
+
} catch { /* skill missing on disk → counts as 0 */ }
|
|
1447
|
+
skillTokenCache.set(id, result);
|
|
1448
|
+
return result;
|
|
1449
|
+
};
|
|
1450
|
+
const tallyCache = new Map<string, ProfileTally>();
|
|
1451
|
+
const resourceTally = async (value: string): Promise<ProfileTally> => {
|
|
1452
|
+
const hit = tallyCache.get(value);
|
|
1453
|
+
if (hit) return hit;
|
|
1454
|
+
const prof = await loadProfile(value);
|
|
1455
|
+
await expandWildcards(prof);
|
|
1456
|
+
const tally: ProfileTally = {
|
|
1457
|
+
// Skills mirror the headline count: one entry per local skill + one per
|
|
1458
|
+
// npx repo (an npx ref bundles several skills under one repo).
|
|
1459
|
+
skills: [
|
|
1460
|
+
...prof.skills.local.map((s) => `local:${s.id}`),
|
|
1461
|
+
...prof.skills.npx.map((n) => `npx:${n.repo}`),
|
|
1462
|
+
],
|
|
1463
|
+
mcps: prof.mcps.map((m) => m.id),
|
|
1464
|
+
plugins: prof.plugins.map((pl) => pl.id),
|
|
1465
|
+
commands: (prof.commands ?? []).slice(),
|
|
1466
|
+
// This profile's own always-on frontmatter cost (parts=undefined → just
|
|
1467
|
+
// its own skills). The picker sums these across the selection.
|
|
1468
|
+
alwaysOn: computeTokenBreakdown(prof, undefined, tokensForSkill).alwaysOn,
|
|
1469
|
+
};
|
|
1470
|
+
tallyCache.set(value, tally);
|
|
1471
|
+
return tally;
|
|
1472
|
+
};
|
|
1451
1473
|
const picked = await runPicker({
|
|
1452
1474
|
cwd,
|
|
1453
1475
|
options,
|
|
1454
1476
|
noPin: isAccountAlias,
|
|
1455
1477
|
pairSuggestions,
|
|
1456
1478
|
detected,
|
|
1479
|
+
companions,
|
|
1480
|
+
universalSuggestions,
|
|
1481
|
+
resourceTally,
|
|
1457
1482
|
details: async (name) => {
|
|
1458
1483
|
const loaded = await loadProfile(name);
|
|
1459
1484
|
await expandWildcards(loaded);
|
|
@@ -1562,7 +1587,7 @@ export async function run(args: string[]): Promise<number> {
|
|
|
1562
1587
|
try { await rmFile(hashPath, { force: true }); } catch { /* ok */ }
|
|
1563
1588
|
process.stderr.write(`[cue] profile changed, rebuilding runtime...\n`);
|
|
1564
1589
|
}
|
|
1565
|
-
} catch { /* fail-open —
|
|
1590
|
+
} catch (err) { debug("launch:staleness", err); /* fail-open — never blocks launch */ }
|
|
1566
1591
|
}
|
|
1567
1592
|
|
|
1568
1593
|
// --subset / CUE_SMART_SUBSET: ask claude --print which skills are relevant
|
|
@@ -1702,6 +1727,16 @@ export async function run(args: string[]): Promise<number> {
|
|
|
1702
1727
|
CUE_LAUNCHING: "1",
|
|
1703
1728
|
};
|
|
1704
1729
|
|
|
1730
|
+
// Per-profile claude-mem memory: point the (cue-managed) claude-mem plugin at
|
|
1731
|
+
// an isolated, SQLite-only store + its own worker/server ports so one profile's
|
|
1732
|
+
// memory never bleeds into another's. Best-effort — a failure here must never
|
|
1733
|
+
// block the launch. Opt out with CUE_CLAUDE_MEM_ISOLATE=0. See lib/claude-mem-env.ts.
|
|
1734
|
+
try {
|
|
1735
|
+
const { resolveClaudeMemEnv } = await import("../lib/claude-mem-env");
|
|
1736
|
+
const memEnv = resolveClaudeMemEnv(profileName, { existingEnv: process.env });
|
|
1737
|
+
if (memEnv) Object.assign(childEnv, memEnv);
|
|
1738
|
+
} catch { /* non-fatal — memory isolation is an enhancement, not a gate */ }
|
|
1739
|
+
|
|
1705
1740
|
if (parsed.dryRun) {
|
|
1706
1741
|
process.stdout.write(
|
|
1707
1742
|
JSON.stringify(
|
|
@@ -1711,7 +1746,13 @@ export async function run(args: string[]): Promise<number> {
|
|
|
1711
1746
|
runtimeDir: runtime.runtimeDir,
|
|
1712
1747
|
rebuilt: runtime.rebuilt,
|
|
1713
1748
|
hash: runtime.hash,
|
|
1714
|
-
env: {
|
|
1749
|
+
env: {
|
|
1750
|
+
[envKey]: childEnv[envKey],
|
|
1751
|
+
CLAUDE_MEM_DATA_DIR: childEnv.CLAUDE_MEM_DATA_DIR,
|
|
1752
|
+
CLAUDE_MEM_CHROMA_ENABLED: childEnv.CLAUDE_MEM_CHROMA_ENABLED,
|
|
1753
|
+
CLAUDE_MEM_WORKER_PORT: childEnv.CLAUDE_MEM_WORKER_PORT,
|
|
1754
|
+
CLAUDE_MEM_SERVER_PORT: childEnv.CLAUDE_MEM_SERVER_PORT,
|
|
1755
|
+
},
|
|
1715
1756
|
command: [parsed.agent, ...parsed.passthrough],
|
|
1716
1757
|
},
|
|
1717
1758
|
null,
|
|
@@ -1815,13 +1856,26 @@ export async function run(args: string[]): Promise<number> {
|
|
|
1815
1856
|
const duration_s = Math.round((Date.now() - new Date(startTs).getTime()) / 1000);
|
|
1816
1857
|
recordEvent({ ts: new Date().toISOString(), event: "end", profile: profileName, agent: agentKind, cwd: process.cwd(), duration_s });
|
|
1817
1858
|
} catch { /* best-effort */ }
|
|
1818
|
-
// Sync refreshed credentials back to source so next launch has valid tokens
|
|
1859
|
+
// Sync refreshed credentials back to source so next launch has valid tokens.
|
|
1860
|
+
// Freshness guard (mirrors the materializer's preserve step at
|
|
1861
|
+
// runtime-materializer.ts:704): write back ONLY when the runtime token is
|
|
1862
|
+
// strictly newer than source. Without it, a stale runtime — e.g. a sibling
|
|
1863
|
+
// profile rotated the shared source mid-session — would drag a dead, rotated
|
|
1864
|
+
// token over a live one and force a re-login. Anthropic rotates the refresh
|
|
1865
|
+
// token on every refresh, so the highest expiresAt holds the live token.
|
|
1866
|
+
// Must stay synchronous: process.on("exit") handlers cannot await.
|
|
1819
1867
|
if (credentialsSource) {
|
|
1820
1868
|
try {
|
|
1821
|
-
const { copyFileSync, existsSync: ex } = require("node:fs");
|
|
1869
|
+
const { copyFileSync, readFileSync: rf, existsSync: ex } = require("node:fs");
|
|
1822
1870
|
const runtimeCreds = join(runtime.runtimeDir, ".credentials.json");
|
|
1823
1871
|
const sourceCreds = join(credentialsSource, ".credentials.json");
|
|
1824
|
-
|
|
1872
|
+
const expiresAt = (p: string): number => {
|
|
1873
|
+
try {
|
|
1874
|
+
const v = JSON.parse(rf(p, "utf8"))?.claudeAiOauth?.expiresAt;
|
|
1875
|
+
return typeof v === "number" ? v : 0;
|
|
1876
|
+
} catch { return 0; }
|
|
1877
|
+
};
|
|
1878
|
+
if (ex(runtimeCreds) && expiresAt(runtimeCreds) > expiresAt(sourceCreds)) {
|
|
1825
1879
|
copyFileSync(runtimeCreds, sourceCreds);
|
|
1826
1880
|
}
|
|
1827
1881
|
} catch { /* best-effort */ }
|
package/src/commands/lock.ts
CHANGED
|
@@ -26,7 +26,6 @@ export function isProfileLocked(profileName: string): { locked: boolean; by?: st
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export async function run(args: string[]): Promise<number> {
|
|
29
|
-
const sub = args[0]; // "lock" or "unlock" (routed from _index.ts)
|
|
30
29
|
// When called as `cue lock <profile>`, args = ["<profile>", ...]
|
|
31
30
|
// The command name is already stripped by the router
|
|
32
31
|
const profileName = args.find(a => !a.startsWith("-"));
|
|
@@ -819,10 +819,6 @@ async function cmdPrPreview(repo: string, json: boolean): Promise<number> {
|
|
|
819
819
|
return { path, before, after: fixed, fixedRules, leftover: afterDiags };
|
|
820
820
|
});
|
|
821
821
|
|
|
822
|
-
// Build one combined PR body (per-file sections)
|
|
823
|
-
const allFixed = reports.flatMap((r) => r.fixedRules.map((rule) => ({ path: r.path, rule })));
|
|
824
|
-
const allLeftover = reports.flatMap((r) => r.leftover.map((d) => ({ path: r.path, ...d })));
|
|
825
|
-
|
|
826
822
|
// PR body: passes every file so the diff blocks come out per-file.
|
|
827
823
|
const primary = reports.find((r) => r.fixedRules.length > 0) ?? reports[0]!;
|
|
828
824
|
const allFixedRulesPrev = [...new Set(reports.flatMap((r) => r.fixedRules))];
|
|
@@ -18,7 +18,7 @@ import { fileURLToPath } from "node:url";
|
|
|
18
18
|
|
|
19
19
|
import { loadProfile } from "../lib/profile-loader";
|
|
20
20
|
import { resolveActiveProfile } from "../lib/cwd-resolver";
|
|
21
|
-
import { getAdapter, AGENT_IDS,
|
|
21
|
+
import { getAdapter, AGENT_IDS, } from "../lib/agent-adapters";
|
|
22
22
|
|
|
23
23
|
const REPO_ROOT = process.env.CUE_REPO_ROOT ?? process.env.SOUL_REPO_ROOT ?? resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
24
24
|
const SKILLS_ROOT = join(REPO_ROOT, "resources", "skills", "skills");
|