ccdesk 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +9 -5
  3. package/dist/core/agent-edit.d.ts +6 -0
  4. package/dist/{server → core}/agent-edit.js +21 -22
  5. package/dist/core/backups.d.ts +19 -0
  6. package/dist/{server → core}/backups.js +37 -45
  7. package/dist/core/core.d.ts +96 -0
  8. package/dist/core/core.js +57 -0
  9. package/dist/core/index.d.ts +22 -0
  10. package/dist/core/index.js +38 -0
  11. package/dist/core/mcp-edit.d.ts +25 -0
  12. package/dist/{server → core}/mcp-edit.js +116 -95
  13. package/dist/core/mutations.d.ts +20 -0
  14. package/dist/{server → core}/mutations.js +8 -15
  15. package/dist/core/open.d.ts +31 -0
  16. package/dist/{server → core}/open.js +39 -12
  17. package/dist/core/parse-edit.d.ts +12 -0
  18. package/dist/core/parse-edit.js +64 -0
  19. package/dist/core/reference.d.ts +3 -0
  20. package/dist/core/reference.js +11 -0
  21. package/dist/core/scan/compare.d.ts +7 -0
  22. package/dist/{server → core}/scan/compare.js +5 -3
  23. package/dist/core/scan/context.d.ts +13 -0
  24. package/dist/{server → core}/scan/context.js +58 -32
  25. package/dist/core/scan/data.d.ts +8 -0
  26. package/dist/core/scan/data.js +18 -0
  27. package/dist/core/scan/env.d.ts +26 -0
  28. package/dist/{server → core}/scan/env.js +10 -3
  29. package/dist/core/scan/files.d.ts +68 -0
  30. package/dist/core/scan/files.js +270 -0
  31. package/dist/core/scan/git.d.ts +14 -0
  32. package/dist/core/scan/git.js +98 -0
  33. package/dist/core/scan/index.d.ts +5 -0
  34. package/dist/{server → core}/scan/index.js +115 -81
  35. package/dist/core/scan/instructions.d.ts +54 -0
  36. package/dist/{server → core}/scan/instructions.js +141 -73
  37. package/dist/core/scan/inventory.d.ts +38 -0
  38. package/dist/{server → core}/scan/inventory.js +134 -115
  39. package/dist/core/scan/mcp.d.ts +28 -0
  40. package/dist/{server → core}/scan/mcp.js +151 -94
  41. package/dist/core/scan/memory.d.ts +8 -0
  42. package/dist/{server → core}/scan/memory.js +8 -8
  43. package/dist/core/scan/path-test.d.ts +9 -0
  44. package/dist/core/scan/path-test.js +156 -0
  45. package/dist/core/scan/permissions.d.ts +31 -0
  46. package/dist/{server → core}/scan/permissions.js +6 -9
  47. package/dist/core/scan/plugins.d.ts +39 -0
  48. package/dist/{server → core}/scan/plugins.js +36 -27
  49. package/dist/core/scan/projects.d.ts +9 -0
  50. package/dist/{server → core}/scan/projects.js +5 -4
  51. package/dist/core/scan/sandbox.d.ts +14 -0
  52. package/dist/{server → core}/scan/sandbox.js +87 -59
  53. package/dist/core/scan/settings.d.ts +35 -0
  54. package/dist/{server → core}/scan/settings.js +88 -92
  55. package/dist/core/scan/tools.d.ts +10 -0
  56. package/dist/{server → core}/scan/tools.js +28 -20
  57. package/dist/core/scan/usage.d.ts +25 -0
  58. package/dist/{server → core}/scan/usage.js +117 -92
  59. package/dist/core/schema.d.ts +8 -0
  60. package/dist/core/schema.js +67 -0
  61. package/dist/core/secrets.d.ts +44 -0
  62. package/dist/core/secrets.js +187 -0
  63. package/dist/core/settings-edit.d.ts +9 -0
  64. package/dist/core/settings-edit.js +216 -0
  65. package/dist/core/watch.d.ts +45 -0
  66. package/dist/{server → core}/watch.js +129 -20
  67. package/dist/core/write.d.ts +119 -0
  68. package/dist/{server → core}/write.js +63 -8
  69. package/dist/server/args.d.ts +32 -0
  70. package/dist/server/args.js +106 -0
  71. package/dist/server/cli.d.ts +2 -0
  72. package/dist/server/cli.js +58 -83
  73. package/dist/server/commands.d.ts +8 -0
  74. package/dist/server/commands.js +39 -0
  75. package/dist/server/server.d.ts +12 -0
  76. package/dist/server/server.js +80 -195
  77. package/dist/server/start.d.ts +13 -0
  78. package/dist/server/start.js +21 -0
  79. package/dist/shared/compare.d.ts +25 -0
  80. package/dist/shared/memory.d.ts +2 -0
  81. package/dist/shared/requests.d.ts +104 -0
  82. package/dist/shared/requests.js +73 -0
  83. package/dist/shared/scopes.d.ts +10 -0
  84. package/dist/shared/settings-catalog.json +2199 -0
  85. package/dist/shared/types.d.ts +530 -0
  86. package/dist/shared/types.js +11 -0
  87. package/dist/ui/assets/index-CH1HoC38.js +60 -0
  88. package/dist/ui/index.html +1 -1
  89. package/dist/view/diff.d.ts +16 -0
  90. package/dist/view/diff.js +85 -0
  91. package/dist/view/format.d.ts +17 -0
  92. package/dist/view/format.js +47 -0
  93. package/dist/view/index.d.ts +11 -0
  94. package/dist/view/index.js +13 -0
  95. package/dist/view/lines.d.ts +9 -0
  96. package/dist/view/lines.js +12 -0
  97. package/dist/view/path-test.d.ts +3 -0
  98. package/dist/view/path-test.js +7 -0
  99. package/dist/view/sections/catalog.d.ts +9 -0
  100. package/dist/view/sections/catalog.js +47 -0
  101. package/dist/view/sections/extensions.d.ts +1 -0
  102. package/dist/view/sections/extensions.js +48 -0
  103. package/dist/view/sections/hooks.d.ts +1 -0
  104. package/dist/view/sections/hooks.js +32 -0
  105. package/dist/view/sections/index.d.ts +6 -0
  106. package/dist/view/sections/index.js +27 -0
  107. package/dist/view/sections/instructions.d.ts +6 -0
  108. package/dist/view/sections/instructions.js +38 -0
  109. package/dist/view/sections/mcp.d.ts +3 -0
  110. package/dist/view/sections/mcp.js +38 -0
  111. package/dist/view/sections/memory.d.ts +1 -0
  112. package/dist/view/sections/memory.js +31 -0
  113. package/dist/view/sections/permissions.d.ts +17 -0
  114. package/dist/view/sections/permissions.js +87 -0
  115. package/dist/view/sections/settings.d.ts +1 -0
  116. package/dist/view/sections/settings.js +33 -0
  117. package/dist/view/sections/tools.d.ts +6 -0
  118. package/dist/view/sections/tools.js +57 -0
  119. package/dist/view/sections/types.d.ts +123 -0
  120. package/dist/view/sections/types.js +10 -0
  121. package/dist/view/settings.d.ts +12 -0
  122. package/dist/view/settings.js +31 -0
  123. package/dist/view/usage.d.ts +8 -0
  124. package/dist/view/usage.js +18 -0
  125. package/package.json +13 -2
  126. package/dist/server/scan/files.js +0 -478
  127. package/dist/server/scan/path-test.js +0 -121
  128. package/dist/server/schema.js +0 -15
  129. package/dist/server/secrets.js +0 -63
  130. package/dist/server/settings-edit.js +0 -221
  131. package/dist/ui/assets/index-XqJwI3k9.js +0 -60
@@ -0,0 +1,87 @@
1
+ import {} from "../../shared/types.js";
2
+ import { suggestedRules } from "../usage.js";
3
+ import { defineSection } from "./types.js";
4
+ export function isSuggested(row) {
5
+ return "suggested" in row;
6
+ }
7
+ /**
8
+ * An allow rule in effect that covered none of the calls counted here. Ask rules are not flagged:
9
+ * they guard calls, so one that never fired is no reason to remove it.
10
+ */
11
+ export function unused(rule, usage) {
12
+ return (rule.kind === "rule" &&
13
+ rule.list === "allow" &&
14
+ rule.inEffect &&
15
+ !rule.decidedBy &&
16
+ (usage?.sessions ?? 0) > 0 &&
17
+ usage?.matches[rule.rule] === 0);
18
+ }
19
+ const LIST_ORDER = ["deny", "ask", "allow"];
20
+ /** Rules in the order Claude Code checks their lists, then other settings, then suggestions. */
21
+ function listRank(row) {
22
+ if (isSuggested(row))
23
+ return 4;
24
+ return row.item.kind === "rule" ? LIST_ORDER.indexOf(row.item.list) : 3;
25
+ }
26
+ /** A row as words: its list and rule, or the setting and its value. */
27
+ function words(row) {
28
+ if (isSuggested(row))
29
+ return `suggested allow ${row.item.rule}`;
30
+ const { item } = row;
31
+ return item.kind === "rule" ? `${item.list} ${item.rule}` : `${item.kind} ${item.value}`;
32
+ }
33
+ export const permissions = defineSection({
34
+ id: "permissions",
35
+ title: "Permissions",
36
+ rows: (view) => {
37
+ const ids = new Set();
38
+ const set = view.permissions.map((item) => {
39
+ // Keyed by content so a selection survives a refresh; a repeated entry gets a suffix.
40
+ const base = `perm:${item.scope}:${item.kind === "rule" ? `${item.list}:${item.rule}` : `${item.kind}:${item.value}`}`;
41
+ let id = base;
42
+ for (let n = 2; ids.has(id); n++)
43
+ id = `${base}#${n}`;
44
+ ids.add(id);
45
+ return { id, section: "permissions", line: item.scope, item };
46
+ });
47
+ const suggested = suggestedRules(view).map((item) => ({
48
+ id: `perm:suggested:${item.rule}`,
49
+ section: "permissions",
50
+ line: null,
51
+ item,
52
+ suggested: true,
53
+ }));
54
+ return [...set, ...suggested];
55
+ },
56
+ columns: [
57
+ { label: "", sort: (r) => (isSuggested(r) ? "~" : r.item.scope) },
58
+ {
59
+ label: "List",
60
+ sort: listRank,
61
+ },
62
+ {
63
+ label: "Rule",
64
+ sort: (r) => ("rule" in r.item ? r.item.rule : r.item.value),
65
+ },
66
+ { label: "Outcome" },
67
+ ],
68
+ empty: () => "No settings file sets permissions here, so Claude asks before using tools that need it.",
69
+ dimmed: (row) => !isSuggested(row) &&
70
+ (!row.item.inEffect || (row.item.kind === "rule" && row.item.decidedBy !== undefined)),
71
+ text: (row) => `permission ${words(row)}`,
72
+ label: words,
73
+ heading: (row) => {
74
+ if ("rule" in row.item)
75
+ return row.item.rule;
76
+ return row.item.kind === "defaultMode" ? "Default permission mode" : "Extra folder";
77
+ },
78
+ facet: {
79
+ label: "Filter permissions by list",
80
+ of: (row) => {
81
+ if (isSuggested(row))
82
+ return "suggested";
83
+ return row.item.kind === "rule" ? row.item.list : "other";
84
+ },
85
+ order: () => ["deny", "ask", "allow", "other", "suggested"],
86
+ },
87
+ });
@@ -0,0 +1 @@
1
+ export declare const settings: import("./types.ts").ViewSection<import("./types.ts").Row>;
@@ -0,0 +1,33 @@
1
+ import { HIGHEST_FIRST } from "../../shared/scopes.js";
2
+ import {} from "../../shared/types.js";
3
+ import {} from "../lines.js";
4
+ import { defineSection } from "./types.js";
5
+ export const settings = defineSection({
6
+ id: "settings",
7
+ title: "Settings",
8
+ rows: (view) => view.effective.map((item) => {
9
+ const lines = item.from;
10
+ return {
11
+ id: `set:${item.key}`,
12
+ section: "settings",
13
+ line: lines[lines.length - 1] ?? "user",
14
+ item,
15
+ lines,
16
+ };
17
+ }),
18
+ columns: [
19
+ { label: "", sort: (r) => HIGHEST_FIRST.indexOf((r.item.from[0] ?? "user")) },
20
+ { label: "Key", sort: (r) => r.item.key },
21
+ { label: "Value" },
22
+ { label: "Overrides" },
23
+ ],
24
+ empty: () => "No settings files set anything here.",
25
+ // The Overrides column only earns its space when some value beats or merges with another file.
26
+ tableClass: (rows) => rows.some((r) => r.item.merged || r.item.overridden.length > 0 || r.item.ignored.length > 0)
27
+ ? ""
28
+ : "no-overrides",
29
+ dimmed: (row) => row.item.from.length === 0,
30
+ text: (row) => `${row.item.key} ${JSON.stringify(row.item.value)}`,
31
+ label: (row) => `setting ${row.item.key}`,
32
+ heading: (row) => row.item.key,
33
+ });
@@ -0,0 +1,6 @@
1
+ import { type BuiltinTool, type Usage } from "../../shared/types.ts";
2
+ /** Calls counted here: undefined while counting, null when the transcripts could not be read. */
3
+ export declare function callsOf(usage: Usage | null | undefined, name: string): number | null | undefined;
4
+ /** What happens when Claude wants the tool, in Manual mode. */
5
+ export declare function outcome(tool: BuiltinTool): string;
6
+ export declare const tools: import("./types.ts").ViewSection<import("./types.ts").Row>;
@@ -0,0 +1,57 @@
1
+ import {} from "../../shared/types.js";
2
+ import { defineSection } from "./types.js";
3
+ /** Calls counted here: undefined while counting, null when the transcripts could not be read. */
4
+ export function callsOf(usage, name) {
5
+ if (!usage)
6
+ return usage;
7
+ return usage.tools.find((t) => t.tool === name)?.calls ?? 0;
8
+ }
9
+ /** What happens when Claude wants the tool, in Manual mode. */
10
+ export function outcome(tool) {
11
+ switch (tool.verdict) {
12
+ case "denied":
13
+ return "removed";
14
+ case "asks":
15
+ return "asks every time";
16
+ case "allowed":
17
+ return "runs without asking";
18
+ case "default":
19
+ return tool.asks ? "asks first" : "no approval needed";
20
+ }
21
+ }
22
+ export const tools = defineSection({
23
+ id: "tools",
24
+ title: "Built-in tools",
25
+ short: "Tools",
26
+ rows: (view) => view.tools.map((item) => ({
27
+ id: `tool:${item.name}`,
28
+ section: "tools",
29
+ line: item.decidedBy?.scope ?? null,
30
+ item,
31
+ calls: callsOf(view.usage, item.name),
32
+ })),
33
+ columns: [
34
+ { label: "" },
35
+ { label: "Tool", sort: (r) => r.item.name },
36
+ { label: "Outcome", sort: (r) => outcome(r.item) },
37
+ { label: "Rules and hooks", sort: (r) => r.item.scoped.length + r.item.hooks },
38
+ { label: "Used", sort: (r) => r.calls ?? -1 },
39
+ { label: "Description" },
40
+ ],
41
+ empty: () => "ccdesk has no list of built-in tools.",
42
+ dimmed: (row) => row.item.verdict === "denied",
43
+ text: (row) => `tool ${row.item.name} ${outcome(row.item)} ${row.item.description}`,
44
+ label: (row) => `tool ${row.item.name}`,
45
+ heading: (row) => row.item.name,
46
+ facet: {
47
+ label: "Filter tools by outcome",
48
+ of: (row) => outcome(row.item),
49
+ order: () => [
50
+ "removed",
51
+ "asks every time",
52
+ "asks first",
53
+ "runs without asking",
54
+ "no approval needed",
55
+ ],
56
+ },
57
+ });
@@ -0,0 +1,123 @@
1
+ import { type Approval, type BuiltinTool, type CatalogSetting, type DirectoryView, type EffectiveSetting, type Entry, type Hook, type Instruction, type McpServer, type Memory, type Permission, type Plugin, type Reference } from "../../shared/types.ts";
2
+ import { type Formatter } from "../format.ts";
3
+ import { type Line } from "../lines.ts";
4
+ export type EntryKind = "agent" | "skill" | "command" | "output style";
5
+ /** One table row; `id` stays the same across reloads so a selection survives them. */
6
+ export type Row = {
7
+ id: string;
8
+ section: "instructions";
9
+ line: Line;
10
+ item: Instruction;
11
+ order: number;
12
+ } | {
13
+ id: string;
14
+ section: "settings";
15
+ line: Line;
16
+ item: EffectiveSetting;
17
+ lines: Line[];
18
+ } | {
19
+ id: string;
20
+ section: "permissions";
21
+ line: Line;
22
+ item: Permission;
23
+ }
24
+ /** Calls you approved by hand that an allow rule not yet in any file would cover. */
25
+ | {
26
+ id: string;
27
+ section: "permissions";
28
+ line: null;
29
+ item: Approval;
30
+ suggested: true;
31
+ }
32
+ /** A tool no rule names as a whole belongs to no scope. */
33
+ | {
34
+ id: string;
35
+ section: "tools";
36
+ line: Line | null;
37
+ item: BuiltinTool;
38
+ /** Calls in the sessions started here; undefined while counting, null if counting failed. */
39
+ calls: number | null | undefined;
40
+ } | {
41
+ id: string;
42
+ section: "memory";
43
+ line: Line;
44
+ item: Memory;
45
+ } | {
46
+ id: string;
47
+ section: "hooks";
48
+ line: Line;
49
+ item: Hook;
50
+ } | {
51
+ id: string;
52
+ section: "mcp";
53
+ line: Line;
54
+ item: McpServer;
55
+ }
56
+ /** A documented setting; its line is the file that sets it here, if any. */
57
+ | {
58
+ id: string;
59
+ section: "catalog";
60
+ line: Line | null;
61
+ item: CatalogSetting;
62
+ set?: EffectiveSetting;
63
+ } | {
64
+ id: string;
65
+ section: "extensions";
66
+ line: Line;
67
+ item: Entry;
68
+ kind: EntryKind;
69
+ } | {
70
+ id: string;
71
+ section: "extensions";
72
+ line: Line;
73
+ item: Plugin;
74
+ kind: "plugin";
75
+ };
76
+ export type SectionId = Row["section"];
77
+ export type RowOf<S extends SectionId> = Extract<Row, {
78
+ section: S;
79
+ }>;
80
+ /** What sections need besides the directory: how to show paths, and Claude Code's settings data. */
81
+ export interface ViewContext {
82
+ format: Formatter;
83
+ /** From `REFERENCE` in the core, or `/api/reference` in the page. */
84
+ reference: Reference;
85
+ }
86
+ export interface Column<R> {
87
+ label: string;
88
+ /** Sort key; columns without one cannot be sorted. */
89
+ sort?: (row: R) => string | number;
90
+ }
91
+ /** Rows of one section narrowed by a value, such as memory by type. */
92
+ export interface Facet<R> {
93
+ label: string;
94
+ of: (row: R) => string;
95
+ /** The order values are offered in; values not listed come after, by name. */
96
+ order?: (context: ViewContext) => string[];
97
+ }
98
+ /** How one kind of row is listed: its rows, columns and the text that names them. */
99
+ export interface ViewSection<R extends Row> {
100
+ id: R["section"];
101
+ title: string;
102
+ /** A shorter title for the section index, when the title is long. */
103
+ short?: string;
104
+ rows: (view: DirectoryView, context: ViewContext) => R[];
105
+ columns: Column<R>[];
106
+ empty: (view: DirectoryView) => string;
107
+ /** Rows that exist but do not take effect are drawn faded. */
108
+ dimmed?: (row: R) => boolean;
109
+ /** Text the filter box and the palette search. */
110
+ text: (row: R) => string;
111
+ /** One line naming the row in the palette. */
112
+ label: (row: R, context: ViewContext) => string;
113
+ /** The inspector's heading for a row. */
114
+ heading: (row: R, context: ViewContext) => string;
115
+ facet?: Facet<R>;
116
+ /** An extra class for the table, from the rows on it. */
117
+ tableClass?: (rows: R[]) => string;
118
+ }
119
+ /**
120
+ * Lets the registry hold every section in one list. Sound because a row is only ever handed to
121
+ * the section that made it, looked up by `row.section`.
122
+ */
123
+ export declare function defineSection<R extends Row>(section: ViewSection<R>): ViewSection<Row>;
@@ -0,0 +1,10 @@
1
+ import {} from "../../shared/types.js";
2
+ import {} from "../format.js";
3
+ import {} from "../lines.js";
4
+ /**
5
+ * Lets the registry hold every section in one list. Sound because a row is only ever handed to
6
+ * the section that made it, looked up by `row.section`.
7
+ */
8
+ export function defineSection(section) {
9
+ return section;
10
+ }
@@ -0,0 +1,12 @@
1
+ import { type SettingSchema } from "../shared/types.ts";
2
+ /** How a setting is edited: typed controls where the schema allows it, JSON otherwise. */
3
+ export type FieldKind = "boolean" | "enum" | "number" | "string" | "lines" | "json";
4
+ export declare function fieldKind(property: SettingSchema | undefined): FieldKind;
5
+ /**
6
+ * The string values a settings reference type lists, such as theme's "dark" and "light": offered as
7
+ * choices where the schema allows any string. In a bulleted list only the value opening each bullet
8
+ * counts, since the explanations quote other values. Inline, only a list the type states is taken
9
+ * ("one of", "the string"), up to a ";" or "such as", so examples and remarks are not;
10
+ * placeholders like "custom:<slug>" are left out.
11
+ */
12
+ export declare function valuesIn(type: string): string[];
@@ -0,0 +1,31 @@
1
+ import {} from "../shared/types.js";
2
+ export function fieldKind(property) {
3
+ if (!property)
4
+ return "json";
5
+ if (property.enum?.every((v) => typeof v === "string"))
6
+ return "enum";
7
+ if (property.type === "boolean")
8
+ return "boolean";
9
+ if (property.type === "number" || property.type === "integer")
10
+ return "number";
11
+ if (property.type === "string")
12
+ return "string";
13
+ if (property.type === "array" && property.items?.type === "string" && !property.items.enum)
14
+ return "lines";
15
+ return "json";
16
+ }
17
+ /**
18
+ * The string values a settings reference type lists, such as theme's "dark" and "light": offered as
19
+ * choices where the schema allows any string. In a bulleted list only the value opening each bullet
20
+ * counts, since the explanations quote other values. Inline, only a list the type states is taken
21
+ * ("one of", "the string"), up to a ";" or "such as", so examples and remarks are not;
22
+ * placeholders like "custom:<slug>" are left out.
23
+ */
24
+ export function valuesIn(type) {
25
+ const bullets = [...type.matchAll(/^\* `"([^"`<>]+)"`/gm)].map((m) => m[1] ?? "");
26
+ const clause = (type.split("\n")[0] ?? "").split(/;| such as /)[0] ?? "";
27
+ const inline = /one of|the string|^string, `"/.test(clause)
28
+ ? [...clause.matchAll(/`"([^"`<>]+)"`/g)].map((m) => m[1] ?? "")
29
+ : [];
30
+ return [...new Set((bullets.length > 0 ? bullets : inline).filter(Boolean))];
31
+ }
@@ -0,0 +1,8 @@
1
+ import { type DirectoryView, type Usage } from "../shared/types.ts";
2
+ /** "the 12 sessions started in this repository since 3 Oct", for sentences about counted calls. */
3
+ export declare function sessionsHere(usage: Usage): string;
4
+ /**
5
+ * Suggested allow rules, most approved first. The server leaves out rules that would change
6
+ * nothing; this also drops one saved since the counts were taken, until they are taken again.
7
+ */
8
+ export declare function suggestedRules(view: DirectoryView): Usage["approvals"];
@@ -0,0 +1,18 @@
1
+ import {} from "../shared/types.js";
2
+ import { plural } from "./format.js";
3
+ /** "the 12 sessions started in this repository since 3 Oct", for sentences about counted calls. */
4
+ export function sessionsHere(usage) {
5
+ const since = usage.since
6
+ ? ` since ${new Date(usage.since).toLocaleDateString(undefined, { day: "numeric", month: "short" })}`
7
+ : "";
8
+ const where = usage.repository ? "in this repository" : "here";
9
+ return `${usage.sessions === 1 ? "the session" : `the ${plural(usage.sessions, "session")}`} started ${where}${since}`;
10
+ }
11
+ /**
12
+ * Suggested allow rules, most approved first. The server leaves out rules that would change
13
+ * nothing; this also drops one saved since the counts were taken, until they are taken again.
14
+ */
15
+ export function suggestedRules(view) {
16
+ const decided = new Set(view.permissions.flatMap((p) => (p.kind === "rule" && p.inEffect ? [p.rule] : [])));
17
+ return (view.usage?.approvals ?? []).filter((a) => !decided.has(a.rule));
18
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccdesk",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "See and change everything Claude Code loads on your machine: instruction files, settings, permissions, hooks, MCP servers, subagents, skills, plugins and auto memory",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -30,6 +30,17 @@
30
30
  "bin": {
31
31
  "ccdesk": "dist/server/cli.js"
32
32
  },
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/core/index.d.ts",
36
+ "default": "./dist/core/index.js"
37
+ },
38
+ "./view": {
39
+ "types": "./dist/view/index.d.ts",
40
+ "default": "./dist/view/index.js"
41
+ },
42
+ "./package.json": "./package.json"
43
+ },
33
44
  "files": [
34
45
  "dist/",
35
46
  "README.md",
@@ -62,7 +73,7 @@
62
73
  "access": "public"
63
74
  },
64
75
  "dependencies": {
65
- "ajv": "8.20.0",
76
+ "typebox": "1.3.36",
66
77
  "yaml": "2.9.1"
67
78
  },
68
79
  "devDependencies": {