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
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the permissions reader — the pure parser + merger behind the
|
|
3
|
+
* studio Permissions page. No disk / env touched: every case feeds raw blocks.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from "bun:test";
|
|
7
|
+
|
|
8
|
+
import { parseRuleString, buildPermissions } from "./permissions";
|
|
9
|
+
|
|
10
|
+
describe("parseRuleString", () => {
|
|
11
|
+
test("splits a tool(pattern) rule", () => {
|
|
12
|
+
expect(parseRuleString("Bash(git *)")).toEqual({ tool: "Bash", pattern: "git *" });
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("handles patterns that themselves contain parens", () => {
|
|
16
|
+
expect(parseRuleString("Bash(echo (hi))")).toEqual({ tool: "Bash", pattern: "echo (hi)" });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("treats a bare rule (no parens) as a tool with an empty pattern", () => {
|
|
20
|
+
expect(parseRuleString("mcp__codegraph__codegraph_search")).toEqual({
|
|
21
|
+
tool: "mcp__codegraph__codegraph_search",
|
|
22
|
+
pattern: "",
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("trims surrounding whitespace", () => {
|
|
27
|
+
expect(parseRuleString(" Read( ~/.ssh/** ) ")).toEqual({ tool: "Read", pattern: "~/.ssh/**" });
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("buildPermissions", () => {
|
|
32
|
+
test("groups by mode and counts each bucket", () => {
|
|
33
|
+
const { rules, counts } = buildPermissions([
|
|
34
|
+
{ label: "user", perms: { allow: ["Read(**)", "Bash(git *)"], ask: ["Bash(rm *)"], deny: ["Bash(sudo *)"] } },
|
|
35
|
+
]);
|
|
36
|
+
expect(counts).toEqual({ allow: 2, ask: 1, deny: 1 });
|
|
37
|
+
expect(rules.find((r) => r.tool === "Bash" && r.pattern === "git *")!.mode).toBe("allow");
|
|
38
|
+
expect(rules.every((r) => r.sources.length === 1 && r.sources[0] === "user")).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("dedupes a rule that appears in two files and merges its sources", () => {
|
|
42
|
+
const { rules, counts } = buildPermissions([
|
|
43
|
+
{ label: "project", perms: { allow: ["Read(**)"] } },
|
|
44
|
+
{ label: "user", perms: { allow: ["Read(**)"] } },
|
|
45
|
+
]);
|
|
46
|
+
expect(counts.allow).toBe(1);
|
|
47
|
+
expect(rules).toHaveLength(1);
|
|
48
|
+
expect(rules[0]!.sources).toEqual(["project", "user"]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("the first-seen defaultMode wins (precedence order)", () => {
|
|
52
|
+
const { defaultMode } = buildPermissions([
|
|
53
|
+
{ label: "project", perms: { defaultMode: "acceptEdits" } },
|
|
54
|
+
{ label: "user", perms: { defaultMode: "auto" } },
|
|
55
|
+
]);
|
|
56
|
+
expect(defaultMode).toBe("acceptEdits");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("ignores null blocks and non-string / empty entries", () => {
|
|
60
|
+
const { rules, counts } = buildPermissions([
|
|
61
|
+
{ label: "managed", perms: null },
|
|
62
|
+
{ label: "user", perms: { allow: ["", " ", "Edit(src/**)"] } },
|
|
63
|
+
]);
|
|
64
|
+
expect(counts.allow).toBe(1);
|
|
65
|
+
expect(rules[0]!.tool).toBe("Edit");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("a tool with allow in one file and deny in another keeps both as distinct rules", () => {
|
|
69
|
+
const { rules, counts } = buildPermissions([
|
|
70
|
+
{ label: "project", perms: { deny: ["Read(.env)"] } },
|
|
71
|
+
{ label: "user", perms: { allow: ["Read(.env)"] } },
|
|
72
|
+
]);
|
|
73
|
+
expect(counts).toEqual({ allow: 1, ask: 0, deny: 1 });
|
|
74
|
+
expect(rules).toHaveLength(2);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read the real Claude Code tool-permission rules (allow / ask / deny) the way
|
|
3
|
+
* Claude Code itself loads them — a union across the managed → project → user
|
|
4
|
+
* settings files. Powers the studio's Permissions page.
|
|
5
|
+
*
|
|
6
|
+
* Read-only: this reflects what's in settings.json, it never mutates it. The
|
|
7
|
+
* pure parser + merger are exported so they're unit-testable without disk.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
11
|
+
import { homedir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
export type PermMode = "allow" | "ask" | "deny";
|
|
15
|
+
|
|
16
|
+
export interface PermRule {
|
|
17
|
+
/** The tool the rule scopes, e.g. "Bash", "Read", or a bare "mcp__x__y". */
|
|
18
|
+
tool: string;
|
|
19
|
+
/** The glob/argument pattern inside the parens, "" for bare tool rules. */
|
|
20
|
+
pattern: string;
|
|
21
|
+
mode: PermMode;
|
|
22
|
+
/** Friendly labels of the settings files this exact rule appears in. */
|
|
23
|
+
sources: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface PermSourceFile { label: string; path: string; present: boolean }
|
|
27
|
+
|
|
28
|
+
export interface PermissionsData {
|
|
29
|
+
rules: PermRule[];
|
|
30
|
+
counts: Record<PermMode, number>;
|
|
31
|
+
/** permissions.defaultMode from the highest-precedence file that sets it. */
|
|
32
|
+
defaultMode: string | null;
|
|
33
|
+
sources: PermSourceFile[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface RawPerms { allow?: string[]; ask?: string[]; deny?: string[]; defaultMode?: string }
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Split a Claude Code rule string into tool + pattern.
|
|
40
|
+
* `Bash(git *)` → { tool: "Bash", pattern: "git *" }
|
|
41
|
+
* `mcp__codegraph__x` → { tool: "mcp__codegraph__x", pattern: "" }
|
|
42
|
+
*/
|
|
43
|
+
export function parseRuleString(raw: string): { tool: string; pattern: string } {
|
|
44
|
+
const m = raw.match(/^\s*([^(]+?)\s*\((.*)\)\s*$/);
|
|
45
|
+
if (m) return { tool: m[1]!.trim(), pattern: m[2]!.trim() };
|
|
46
|
+
return { tool: raw.trim(), pattern: "" };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Merge permission blocks from several settings files (passed highest-priority
|
|
51
|
+
* first) into one deduped, grouped view. A rule appearing in multiple files is
|
|
52
|
+
* listed once with its sources merged; the first-seen `defaultMode` wins.
|
|
53
|
+
*/
|
|
54
|
+
export function buildPermissions(blocks: { label: string; perms: RawPerms | null }[]): {
|
|
55
|
+
rules: PermRule[];
|
|
56
|
+
counts: Record<PermMode, number>;
|
|
57
|
+
defaultMode: string | null;
|
|
58
|
+
} {
|
|
59
|
+
const map = new Map<string, PermRule>();
|
|
60
|
+
let defaultMode: string | null = null;
|
|
61
|
+
for (const { label, perms } of blocks) {
|
|
62
|
+
if (!perms) continue;
|
|
63
|
+
if (perms.defaultMode && !defaultMode) defaultMode = perms.defaultMode;
|
|
64
|
+
for (const mode of ["deny", "ask", "allow"] as const) {
|
|
65
|
+
for (const raw of perms[mode] ?? []) {
|
|
66
|
+
if (typeof raw !== "string" || !raw.trim()) continue;
|
|
67
|
+
const { tool, pattern } = parseRuleString(raw);
|
|
68
|
+
const key = `${mode}|${tool}|${pattern}`;
|
|
69
|
+
const ex = map.get(key);
|
|
70
|
+
if (ex) { if (!ex.sources.includes(label)) ex.sources.push(label); }
|
|
71
|
+
else map.set(key, { tool, pattern, mode, sources: [label] });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const rules = [...map.values()];
|
|
76
|
+
const counts: Record<PermMode, number> = {
|
|
77
|
+
allow: rules.filter((r) => r.mode === "allow").length,
|
|
78
|
+
ask: rules.filter((r) => r.mode === "ask").length,
|
|
79
|
+
deny: rules.filter((r) => r.mode === "deny").length,
|
|
80
|
+
};
|
|
81
|
+
return { rules, counts, defaultMode };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The user's GLOBAL Claude config dir — always ~/.claude, NOT CLAUDE_CONFIG_DIR.
|
|
86
|
+
* cue sets CLAUDE_CONFIG_DIR to a per-profile runtime when it launches the
|
|
87
|
+
* dashboard; honoring it here would surface the materialized runtime defaults
|
|
88
|
+
* (Bash/Read/Write/Edit *) instead of the real global permission rules the user
|
|
89
|
+
* manages. CUE_CLAUDE_HOME stays as a test-injection override.
|
|
90
|
+
*/
|
|
91
|
+
function claudeUserDir(): string {
|
|
92
|
+
return process.env.CUE_CLAUDE_HOME ?? join(homedir(), ".claude");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function readPermsFile(path: string): RawPerms | null {
|
|
96
|
+
try {
|
|
97
|
+
const raw = JSON.parse(readFileSync(path, "utf8")) as { permissions?: RawPerms };
|
|
98
|
+
return raw.permissions ?? null;
|
|
99
|
+
} catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Read every Claude Code settings file that can carry permission rules and
|
|
106
|
+
* fold them into one grouped, deduped view. Missing files degrade silently.
|
|
107
|
+
*/
|
|
108
|
+
export function collectPermissions(): PermissionsData {
|
|
109
|
+
const userDir = claudeUserDir();
|
|
110
|
+
const proj = join(process.cwd(), ".claude");
|
|
111
|
+
// Highest precedence first — matches Claude Code's managed→project→user order.
|
|
112
|
+
const files: PermSourceFile[] = [
|
|
113
|
+
{ label: "managed", path: "/etc/claude-code/managed-settings.json", present: false },
|
|
114
|
+
{ label: "project · local", path: join(proj, "settings.local.json"), present: false },
|
|
115
|
+
{ label: "project", path: join(proj, "settings.json"), present: false },
|
|
116
|
+
{ label: "user · local", path: join(userDir, "settings.local.json"), present: false },
|
|
117
|
+
{ label: "user", path: join(userDir, "settings.json"), present: false },
|
|
118
|
+
];
|
|
119
|
+
const blocks = files.map((f) => {
|
|
120
|
+
f.present = existsSync(f.path);
|
|
121
|
+
return { label: f.label, perms: f.present ? readPermsFile(f.path) : null };
|
|
122
|
+
});
|
|
123
|
+
const { rules, counts, defaultMode } = buildPermissions(blocks);
|
|
124
|
+
return { rules, counts, defaultMode, sources: files };
|
|
125
|
+
}
|