ccdesk 0.1.0 → 0.2.1
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 +86 -0
- package/README.md +84 -67
- package/dist/server/agent-edit.js +77 -0
- package/dist/server/backups.js +129 -52
- package/dist/server/cli.js +21 -8
- package/dist/server/mcp-edit.js +263 -0
- package/dist/server/mutations.js +8 -3
- package/dist/server/scan/compare.js +34 -0
- package/dist/server/scan/context.js +6 -5
- package/dist/server/scan/env.js +8 -3
- package/dist/server/scan/files.js +118 -30
- package/dist/server/scan/index.js +29 -15
- package/dist/server/scan/instructions.js +11 -7
- package/dist/server/scan/inventory.js +134 -42
- package/dist/server/scan/mcp.js +88 -30
- package/dist/server/scan/memory.js +8 -9
- package/dist/server/scan/path-test.js +32 -10
- package/dist/server/scan/permissions.js +22 -6
- package/dist/server/scan/plugins.js +18 -11
- package/dist/server/scan/projects.js +7 -6
- package/dist/server/scan/sandbox.js +161 -0
- package/dist/server/scan/settings.js +33 -20
- package/dist/server/scan/tools.js +7 -3
- package/dist/server/scan/usage.js +119 -46
- package/dist/server/schema.js +15 -0
- package/dist/server/secrets.js +63 -0
- package/dist/server/server.js +222 -128
- package/dist/server/settings-edit.js +90 -21
- package/dist/server/watch.js +52 -10
- package/dist/server/write.js +58 -20
- package/dist/shared/compare.js +1 -0
- package/dist/shared/hook-events.json +35 -0
- package/dist/shared/mcp-server.schema.json +25 -0
- package/dist/shared/memory.js +4 -0
- package/dist/shared/scopes.js +3 -1
- package/dist/shared/types.js +1 -1
- package/dist/ui/assets/hanken-grotesk-cyrillic-ext-wght-normal-D_UHSL_T.woff2 +0 -0
- package/dist/ui/assets/index-D5XqP5c_.css +1 -0
- package/dist/ui/assets/index-XqJwI3k9.js +60 -0
- package/dist/ui/assets/jetbrains-mono-cyrillic-ext-wght-normal-EocZY2iu.woff2 +0 -0
- package/dist/ui/index.html +2 -2
- package/package.json +10 -4
- package/dist/ui/assets/index-BM4K7hSO.css +0 -1
- package/dist/ui/assets/index-CN3vkVjv.js +0 -45
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,91 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.1](https://github.com/ayagmar/ccdesk/compare/v0.2.0...v0.2.1) (2026-10-12)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **ui:** add a text size control and raise the default sizes ([1a9fe82](https://github.com/ayagmar/ccdesk/commit/1a9fe82b35cc4743936b7bf3c7a6d4244c86779a)), references [#root](https://github.com/ayagmar/ccdesk/issues/root)
|
|
8
|
+
* **ui:** open the docs from the ccdesk logo ([834986a](https://github.com/ayagmar/ccdesk/commit/834986a40df7801e6b4cf12588fd69f65411458a))
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* **ui:** keep the section links on one row with the larger text ([f349f19](https://github.com/ayagmar/ccdesk/commit/f349f19c5e81ba3c498ff9f0751f4e3d5d99ade1))
|
|
13
|
+
|
|
14
|
+
## [0.2.0](https://github.com/ayagmar/ccdesk/compare/v0.1.0...v0.2.0) (2026-10-12)
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* **agents:** create, change and delete subagent files ([1d8d011](https://github.com/ayagmar/ccdesk/commit/1d8d011c93c08dc8435ad304f5061378e8c4c1b7)), references [sub-agents#supported-frontmatter-fields](https://github.com/sub-agents/issues/supported-frontmatter-fields)
|
|
19
|
+
* **cli:** add --config-dir to read another Claude folder ([777712a](https://github.com/ayagmar/ccdesk/commit/777712aeb91da62f3f323292c8050b600ff59f5a))
|
|
20
|
+
* compare the settings of two directories ([9ec5e56](https://github.com/ayagmar/ccdesk/commit/9ec5e56b0d4f1cfc85b48accaea00ac59cf592c2))
|
|
21
|
+
* describe a claude -p or SDK session as well as an interactive one ([45c0ad1](https://github.com/ayagmar/ccdesk/commit/45c0ad180c1a26074d151375f99b80ddb20dd99e)), references [permissions#what-runs-before-you-trust-a-folder](https://github.com/permissions/issues/what-runs-before-you-trust-a-folder) [#when-your-local-settings-file-needs-trust](https://github.com/ayagmar/ccdesk/issues/when-your-local-settings-file-needs-trust) [hooks#workspace-trust](https://github.com/hooks/issues/workspace-trust)
|
|
22
|
+
* **hooks:** add, change and remove hooks in settings files ([7307b6b](https://github.com/ayagmar/ccdesk/commit/7307b6b1f3b7baa1ced8db4be6695e8456c87ef8))
|
|
23
|
+
* list claude mcp edits in Recent changes ([bfc153c](https://github.com/ayagmar/ccdesk/commit/bfc153c5f3489143d73c2cfcc75a5fc2c1175e93))
|
|
24
|
+
* **mcp:** add, change and remove MCP servers ([40f88a6](https://github.com/ayagmar/ccdesk/commit/40f88a6cce41f4c04d3816dfbd540cb2435482e9))
|
|
25
|
+
* **mcp:** check server entries against a schema of the documented fields ([3bfac6c](https://github.com/ayagmar/ccdesk/commit/3bfac6c884c07c03430fd896fe5ec2ba558cbc43))
|
|
26
|
+
* **mcp:** say what approved, rejected or holds a .mcp.json server ([1a42288](https://github.com/ayagmar/ccdesk/commit/1a4228880a81a24468caebab84aa27e85fdbde62))
|
|
27
|
+
* **site:** add the documentation site with llms.txt ([25148e4](https://github.com/ayagmar/ccdesk/commit/25148e43f4f5190c000f0e3f4aaeb98872c9ef53))
|
|
28
|
+
* **site:** capture frames for a video with screenshots --video ([e754f1f](https://github.com/ayagmar/ccdesk/commit/e754f1fd910834044158ca3c2125d706e3ca5d1c))
|
|
29
|
+
* **site:** light up each scope's rows in the hero screenshot ([af20413](https://github.com/ayagmar/ccdesk/commit/af204130ea0e1eee8cd428ba7a67df10bb0a6ffa))
|
|
30
|
+
* **site:** open each landing page question to the rows that answer it ([29d6815](https://github.com/ayagmar/ccdesk/commit/29d6815b628e68751d9de91d10c07a5805d27bc1))
|
|
31
|
+
* **site:** open screenshots in place, add motion and load faster ([340ee81](https://github.com/ayagmar/ccdesk/commit/340ee817449d06910fbc3ae3f6f2003c804014d9))
|
|
32
|
+
* **ui:** say that the page describes an interactive session ([c618a77](https://github.com/ayagmar/ccdesk/commit/c618a776a1313d44f8b88c05c9a660e64e55bb38))
|
|
33
|
+
* undo a change that created its file by removing the file ([e6297e3](https://github.com/ayagmar/ccdesk/commit/e6297e35296b0c2a9f4fd222bfff71f78216211e))
|
|
34
|
+
|
|
35
|
+
### Bug Fixes
|
|
36
|
+
|
|
37
|
+
* **agents:** save a new agent typed as reviewer.md as reviewer.md, not reviewer.md.md ([2d07508](https://github.com/ayagmar/ccdesk/commit/2d07508eeb50dd9fff98e9816e58c1eaa25abc21))
|
|
38
|
+
* **backups:** record restored memories and restore halfway deletes ([3bfcbcf](https://github.com/ayagmar/ccdesk/commit/3bfcbcfd487956dd9eddd9f7252c9093887f95d9))
|
|
39
|
+
* hide keys in MCP server args ([922475c](https://github.com/ayagmar/ccdesk/commit/922475c067b313f75aee2332f01066bc4739ab55))
|
|
40
|
+
* **hooks:** hide the user name, password and query of an http hook's URL ([8b40d25](https://github.com/ayagmar/ccdesk/commit/8b40d25867ca6cbf76164a27584a15309803bb44))
|
|
41
|
+
* **instructions:** head your user CLAUDE.md as ~/.claude/CLAUDE.md, not .claude/CLAUDE.md ([683b1c8](https://github.com/ayagmar/ccdesk/commit/683b1c88bd244f1b033b3f546f7944599a0327de))
|
|
42
|
+
* **instructions:** say why a linked rule with paths does not load ([922788d](https://github.com/ayagmar/ccdesk/commit/922788d34fdc9333679d8792eb1865aa70acd831))
|
|
43
|
+
* match what Claude Code loads and keep hidden values out of edits ([9997c26](https://github.com/ayagmar/ccdesk/commit/9997c2652be271f1c6b3326f84218cfbe27f031d))
|
|
44
|
+
* **mcp:** count a "use all servers" answer to the .mcp.json prompt ([3008f9c](https://github.com/ayagmar/ccdesk/commit/3008f9c9792174d2334ce641555167962b7f67e3))
|
|
45
|
+
* **mcp:** hide a server's secrets in claude's own error message ([2b7882b](https://github.com/ayagmar/ccdesk/commit/2b7882b5e1df3d3540c06a5c8d7c559ec6ce4328))
|
|
46
|
+
* **mcp:** pass names safely to claude mcp and keep servers when it fails ([69b9353](https://github.com/ayagmar/ccdesk/commit/69b9353be3ecd96de2c29ed91183bfce0dfc6274))
|
|
47
|
+
* **mcp:** read and add local servers under the repository root only ([c536737](https://github.com/ayagmar/ccdesk/commit/c536737a8e8d05946d43b0bbe74364a890141cd8))
|
|
48
|
+
* **memory:** remove a [[name]] index line when its memory is deleted ([a08fbdf](https://github.com/ayagmar/ccdesk/commit/a08fbdf899c17e958c0ac98678d44e4b9b259dd5))
|
|
49
|
+
* **memory:** stop flagging a 200-line MEMORY.md that ends in a newline as cut off ([07a670b](https://github.com/ayagmar/ccdesk/commit/07a670b209593d315e7850e6145e8443b5c01554))
|
|
50
|
+
* **permissions:** say that ccdesk reads commands and addresses to match rules ([ca60592](https://github.com/ayagmar/ccdesk/commit/ca605920235512d041b03b0fbea57c4967f1ac70))
|
|
51
|
+
* **readme:** link each screenshot to its full-size image ([18837fc](https://github.com/ayagmar/ccdesk/commit/18837fc055aede576926f15d90b031c3b6a19fa9))
|
|
52
|
+
* **scan:** hold back settings-file hooks until the folder is trusted ([ab9ea97](https://github.com/ayagmar/ccdesk/commit/ab9ea973e153b343530ae5c945b8f71a28dd7895)), references [hooks#workspace-trust](https://github.com/hooks/issues/workspace-trust)
|
|
53
|
+
* **scan:** name plugin skills and commands with their plugin ([43d178a](https://github.com/ayagmar/ccdesk/commit/43d178a0f14c9479b576c6260eea1541f5fb6d53)), references [skills#how-a-skill-gets-its-command-name](https://github.com/skills/issues/how-a-skill-gets-its-command-name) [plugins-reference#name](https://github.com/plugins-reference/issues/name)
|
|
54
|
+
* **server:** put a file back when ccdesk cannot read it while removing it ([bfa4931](https://github.com/ayagmar/ccdesk/commit/bfa49318dc4df99605cc570e004cf6ed0b41543e))
|
|
55
|
+
* **server:** refuse a hard link to the credentials file ([8689378](https://github.com/ayagmar/ccdesk/commit/86893788ee20e1c0fc53464306167a5329968d6e))
|
|
56
|
+
* **server:** refuse a restore that would change hidden keys in args ([5ab6b40](https://github.com/ayagmar/ccdesk/commit/5ab6b409db633d82ac2cea37833639eff1d88c8d))
|
|
57
|
+
* **server:** refuse to save a file that has other hard links ([4fe7445](https://github.com/ayagmar/ccdesk/commit/4fe7445daba710babba8e5bc3826060389857f24))
|
|
58
|
+
* **server:** stop on SIGTERM and answer a malformed URL with 400 ([a519fcb](https://github.com/ayagmar/ccdesk/commit/a519fcb7b0f34c21ac35b81b606ec0bc350119d6))
|
|
59
|
+
* **server:** watch what a scan read even when the watch starts after it ([554a3d5](https://github.com/ayagmar/ccdesk/commit/554a3d58e9361c209313d258f665b54a09792757))
|
|
60
|
+
* **settings:** leave out sandbox fields Claude Code ignores from a file ([97bf3a9](https://github.com/ayagmar/ccdesk/commit/97bf3a95407a21682b0579482bd558071698f40a))
|
|
61
|
+
* **settings:** say why a value that may only tighten a key is ignored ([6e01ce8](https://github.com/ayagmar/ccdesk/commit/6e01ce882f08d3a34d1a2725f5371852e6c5b9ce))
|
|
62
|
+
* **settings:** show a value set only in the older local file in the details ([57cbc45](https://github.com/ayagmar/ccdesk/commit/57cbc453449eb1b3562062817091f8baa449ccef))
|
|
63
|
+
* **site:** draw the GitHub icon in the text colour ([f8dce1c](https://github.com/ayagmar/ccdesk/commit/f8dce1c184b98ed168e3f516f040ce22269a4dd3))
|
|
64
|
+
* **site:** line the header search up with the landing page's wider column ([95a1762](https://github.com/ayagmar/ccdesk/commit/95a176252a28e8f98253bd816212af0f8f54111e))
|
|
65
|
+
* **site:** name the app section each landing page question is answered in ([977a65c](https://github.com/ayagmar/ccdesk/commit/977a65c41b43fe03320a9181cbb02e1011c3be64))
|
|
66
|
+
* **tools:** list a whole-Bash rule under Monitor, whose commands it covers ([52e09b5](https://github.com/ayagmar/ccdesk/commit/52e09b5ead6570c620d0ef9ba9ba5cb8a880ac28))
|
|
67
|
+
* **tools:** show a failed count as unknown instead of counting forever ([b7b628d](https://github.com/ayagmar/ccdesk/commit/b7b628d2d6d672a245d9940d51edcfbc42f29f3a))
|
|
68
|
+
* **ui:** give the session switch its own line so the directory name keeps its room ([c43db64](https://github.com/ayagmar/ccdesk/commit/c43db642f6d980f8efea19387d09f11d3082272c))
|
|
69
|
+
* **ui:** give the tables the room until a row is picked and keep the directory name whole ([8059bea](https://github.com/ayagmar/ccdesk/commit/8059bea410755683637338814413fcc7f1b7844a))
|
|
70
|
+
* **ui:** keep an edited draft when the file changes underneath it ([5f72626](https://github.com/ayagmar/ccdesk/commit/5f726268c96160ba703fcec684fd420b0c7a9d3d))
|
|
71
|
+
* **ui:** keep the save toast above sticky table headers ([711c670](https://github.com/ayagmar/ccdesk/commit/711c6706fa276511ebe4968f05d105f7244722cf))
|
|
72
|
+
* **ui:** line up the columns on Recent changes ([112e732](https://github.com/ayagmar/ccdesk/commit/112e732a3eb776ce121e479538521c2f078551cc))
|
|
73
|
+
* **ui:** offer no undo for a change that created its file ([8103ddc](https://github.com/ayagmar/ccdesk/commit/8103ddc8c78ac323039a778be83c3d89f830851a))
|
|
74
|
+
* **ui:** offer only settings files that exist here when adding a rule or hook ([34bc591](https://github.com/ayagmar/ccdesk/commit/34bc5914cd23d87da8b2574bf7e4a5402a1571f8))
|
|
75
|
+
* **ui:** say that claude mcp edits pass values on claude's command line ([06d971e](https://github.com/ayagmar/ccdesk/commit/06d971e3ff9c7af693bbf9b1d9226b82dcf16100))
|
|
76
|
+
* **ui:** ship the small font files instead of inlining them past the CSP ([166ad6a](https://github.com/ayagmar/ccdesk/commit/166ad6a29df96b5df8c6b043e6ed23654226e978))
|
|
77
|
+
* **usage:** answer a stopped count even while one of its reads hangs ([9495017](https://github.com/ayagmar/ccdesk/commit/9495017641d050f15ba33d19e13db0b2fc9c0ed9))
|
|
78
|
+
* **usage:** stop tool-call counts nobody waits for or that run too long ([cc89847](https://github.com/ayagmar/ccdesk/commit/cc898474b3588c5a64c38fca1635e9bed20f1a27))
|
|
79
|
+
|
|
80
|
+
### Performance Improvements
|
|
81
|
+
|
|
82
|
+
* **server:** cap the usage cache and keep only what matching reads ([6e5eeea](https://github.com/ayagmar/ccdesk/commit/6e5eeea66ce209c9598a417540ae0eb3415986b9))
|
|
83
|
+
* **server:** reuse a current scan for the path tester ([cb48481](https://github.com/ayagmar/ccdesk/commit/cb484810daa5a5469cef5688d740ba7a418a3756))
|
|
84
|
+
|
|
85
|
+
### Reverts
|
|
86
|
+
|
|
87
|
+
* **site:** drop screenshots --video ([0009af4](https://github.com/ayagmar/ccdesk/commit/0009af451f02da3a2d41847e1ce21fbda2d6e892))
|
|
88
|
+
|
|
3
89
|
## 0.1.0 (2026-10-11)
|
|
4
90
|
|
|
5
91
|
### Features
|
package/README.md
CHANGED
|
@@ -7,108 +7,125 @@
|
|
|
7
7
|
|
|
8
8
|
[](https://www.npmjs.com/package/ccdesk)
|
|
9
9
|
[](https://github.com/ayagmar/ccdesk/actions/workflows/ci.yml)
|
|
10
|
-
[](package.json)
|
|
11
|
-
[](LICENSE)
|
|
10
|
+
[](https://github.com/ayagmar/ccdesk/blob/master/package.json)
|
|
11
|
+
[](https://github.com/ayagmar/ccdesk/blob/master/LICENSE)
|
|
12
12
|
|
|
13
|
-
See and change everything
|
|
13
|
+
See and change everything Claude Code loads on your machine: instruction files, settings, permissions, hooks, MCP servers, subagents, skills, plugins and auto memory.
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
16
|
npx ccdesk
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
ccdesk opens in your browser on the directory you ran it from
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
ccdesk
|
|
19
|
+
Each piece lives in its own file, at one of six scopes: managed, user, project, local, auto memory or a plugin. ccdesk opens in your browser on the directory you ran it from, lists everything that applies there in the order Claude Code loads it, and names the file behind each piece. When something is wrong, change it on the same page: you review the diff first, and every edit has a backup and an undo. It is not a session viewer or a usage dashboard.
|
|
20
|
+
|
|
21
|
+
**Docs:** [ayagmar.github.io/ccdesk](https://ayagmar.github.io/ccdesk/)
|
|
22
|
+
|
|
23
|
+
<a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/directory-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/directory-dark.webp" /><img alt="ccdesk on a made-up project: the load order across the top, then instruction files and settings, each marked with the scope it comes from" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/directory-light.webp" /></picture></a>
|
|
24
|
+
|
|
25
|
+
## Questions it answers
|
|
26
|
+
|
|
27
|
+
- Why does Claude ask me before every `git push` here? ([Permissions](https://ayagmar.github.io/ccdesk/permissions/))
|
|
28
|
+
- Which model does this repository use, and which file set it? ([Settings](https://ayagmar.github.io/ccdesk/settings/))
|
|
29
|
+
- Is my `AGENTS.md` loaded at all? ([Instructions](https://ayagmar.github.io/ccdesk/instructions/))
|
|
30
|
+
- How much context does my config take before I type anything? ([What Claude sees](https://ayagmar.github.io/ccdesk/what-claude-sees/))
|
|
31
|
+
- What do I keep approving by hand, and which allow rules have I stopped needing? ([Permissions](https://ayagmar.github.io/ccdesk/permissions/#suggested-rules))
|
|
32
|
+
- Which project MCP servers still wait for approval? ([MCP servers](https://ayagmar.github.io/ccdesk/mcp-servers/))
|
|
33
|
+
|
|
34
|
+
## What it covers
|
|
35
|
+
|
|
36
|
+
| | What you see | What you can change | Docs |
|
|
37
|
+
| --- | --- | --- | --- |
|
|
38
|
+
| **Instructions** | Every `CLAUDE.md`, `AGENTS.md` and `.claude/rules/*.md` that applies, in load order, with why a file is skipped and who else sees it | Open it in your editor | [Instructions](https://ayagmar.github.io/ccdesk/instructions/) |
|
|
39
|
+
| **Settings** | The value Claude Code ends up using for each key, the file it comes from, and the values it overrides | Set or remove any documented key in user, project or local settings, picked from the schema | [Settings](https://ayagmar.github.io/ccdesk/settings/) |
|
|
40
|
+
| **Permissions** | Every allow, ask and deny rule, which ones never take effect, and allow rules that covered no call | Add, move or remove rules; accept allow rules suggested from the calls you approved | [Permissions](https://ayagmar.github.io/ccdesk/permissions/) |
|
|
41
|
+
| **Built-in tools** | What happens when Claude reaches for each tool here, and how often it did | Turn a tool off with a deny rule, or back on | [Tool usage](https://ayagmar.github.io/ccdesk/tool-usage/) |
|
|
42
|
+
| **Hooks** | Every hook with its scope, and the ones that are turned off | Add, change or remove hooks in user, project or local settings | [Hooks](https://ayagmar.github.io/ccdesk/hooks/) |
|
|
43
|
+
| **MCP servers** | Every server, and the ones waiting for approval, off, rejected or overridden | Add, change or remove servers in `.mcp.json`, or through `claude mcp` for user and local ones | [MCP servers](https://ayagmar.github.io/ccdesk/mcp-servers/) |
|
|
44
|
+
| **Subagents** | Every agent from managed, project, user and plugin folders, and which definition wins | Create, change or delete agent files | [Subagents](https://ayagmar.github.io/ccdesk/subagents/) |
|
|
45
|
+
| **Skills and plugins** | Skills, commands, output styles and plugins, by scope | Open them in your editor | [Skills and plugins](https://ayagmar.github.io/ccdesk/skills-and-plugins/) |
|
|
46
|
+
| **Memory** | Auto memory for the directory, with memories missing from `MEMORY.md`, broken links and duplicates flagged | Delete a memory and its index line, fix the index | [Memory](https://ayagmar.github.io/ccdesk/memory/) |
|
|
47
|
+
| **What Claude sees** | What your config puts in context when a session starts, with sizes and estimated tokens | | [What Claude sees](https://ayagmar.github.io/ccdesk/what-claude-sees/) |
|
|
48
|
+
|
|
49
|
+
<table>
|
|
50
|
+
<tr>
|
|
51
|
+
<td width="50%"><a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/permissions-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/permissions-dark.webp" /><img alt="The permissions table with rules from user, project and local settings, and three suggested allow rules" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/permissions-light.webp" /></picture></a></td>
|
|
52
|
+
<td width="50%"><a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/context-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/context-dark.webp" /><img alt="What Claude sees: instruction files, memory and skill listing in load order, with sizes and token estimates" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/context-light.webp" /></picture></a></td>
|
|
53
|
+
</tr>
|
|
54
|
+
<tr>
|
|
55
|
+
<td>Permissions, with allow rules suggested from the calls you approved</td>
|
|
56
|
+
<td>What Claude sees when a session starts here</td>
|
|
57
|
+
</tr>
|
|
58
|
+
<tr>
|
|
59
|
+
<td><a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/memory-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/memory-dark.webp" /><img alt="Auto memory for a directory, with checks on the MEMORY.md index" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/memory-light.webp" /></picture></a></td>
|
|
60
|
+
<td><a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/changes-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/changes-dark.webp" /><img alt="Recent changes: every edit ccdesk made, each one restorable" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/changes-light.webp" /></picture></a></td>
|
|
61
|
+
</tr>
|
|
62
|
+
<tr>
|
|
63
|
+
<td>Auto memory and its index</td>
|
|
64
|
+
<td>Every change ccdesk made, ready to restore</td>
|
|
65
|
+
</tr>
|
|
66
|
+
</table>
|
|
67
|
+
|
|
68
|
+
## How changes are made
|
|
69
|
+
|
|
70
|
+
<a href="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/review-dark.webp"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/review-dark.webp" /><img align="right" width="300" alt="Changing the model setting: the files that set it, the value Claude Code uses, and the diff to project settings before saving" src="https://raw.githubusercontent.com/ayagmar/ccdesk/master/site/src/assets/screenshots/review-light.webp" /></picture></a>
|
|
71
|
+
|
|
72
|
+
- You see the exact diff before anything is written, and Save writes exactly that diff. If the file changed in the meantime, ccdesk asks you to review again.
|
|
73
|
+
- Settings and hooks are checked against Claude Code's settings schema. Other keys in the file stay as they are.
|
|
74
|
+
- The old file is backed up to `~/.claude/backups/ccdesk/` first. Undo is one click, and **Recent changes** can restore any earlier edit.
|
|
75
|
+
- A settings file that is a symlink, such as one in a dotfiles repository, is written through and stays a link.
|
|
76
|
+
- A file with other hard links is not saved: replacing it would split it from its other names. Edit it in your editor.
|
|
77
|
+
- ccdesk never writes `~/.claude.json`. User and local MCP server changes go through Claude Code's own `claude mcp` command, so they need `claude` on your PATH.
|
|
78
|
+
|
|
79
|
+
Details: [Recent changes, backups and undo](https://ayagmar.github.io/ccdesk/recent-changes/)
|
|
80
|
+
|
|
81
|
+
<br clear="right" />
|
|
61
82
|
|
|
62
83
|
## Keyboard
|
|
63
84
|
|
|
64
85
|
| Key | Action |
|
|
65
86
|
| --- | --- |
|
|
66
87
|
| `j` / `k` | Next / previous row |
|
|
67
|
-
| `1
|
|
88
|
+
| `1` to `9` | Jump to a section |
|
|
68
89
|
| `/` | Filter rows |
|
|
69
|
-
| `Ctrl K` / `⌘ K` | Jump to any directory, file, setting
|
|
90
|
+
| `Ctrl K` / `⌘ K` | Jump to any directory, file, setting, rule or memory |
|
|
70
91
|
| `Esc` | Close details |
|
|
71
92
|
|
|
93
|
+
More in [Reading the interface](https://ayagmar.github.io/ccdesk/interface/).
|
|
94
|
+
|
|
72
95
|
## Options
|
|
73
96
|
|
|
74
97
|
```
|
|
75
98
|
npx ccdesk [options]
|
|
76
99
|
|
|
77
|
-
--port <n>
|
|
78
|
-
--no-open
|
|
79
|
-
-
|
|
100
|
+
--port <n> Port to listen on (default: a free port)
|
|
101
|
+
--no-open Print the URL instead of opening a browser
|
|
102
|
+
--config-dir <path> Claude folder to read, as CLAUDE_CONFIG_DIR sets it for Claude Code
|
|
103
|
+
(wins over $CLAUDE_CONFIG_DIR)
|
|
104
|
+
-h, --help Show this help
|
|
80
105
|
```
|
|
81
106
|
|
|
82
|
-
ccdesk reads `~/.claude`, or `$CLAUDE_CONFIG_DIR` when it is set.
|
|
107
|
+
ccdesk reads `~/.claude` and `~/.claude.json`, or `$CLAUDE_CONFIG_DIR` when it is set, as Claude Code does. To look at another profile without exporting the variable, pass `--config-dir <path>`. Edits made in another editor or by Claude show up within a second. Requires Node.js 22.19 or newer. See [Platform notes](https://ayagmar.github.io/ccdesk/platforms/) for Windows, macOS and WSL.
|
|
83
108
|
|
|
84
109
|
## Privacy and safety
|
|
85
110
|
|
|
86
|
-
- The server listens on `127.0.0.1` only
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
- Backups can hold settings with secrets, so their folders and files are readable only by you.
|
|
92
|
-
- Markdown is rendered without raw HTML, so an `AGENTS.md` from a cloned repo cannot run script in the page.
|
|
93
|
-
|
|
94
|
-
## Settings schema
|
|
111
|
+
- The server listens on `127.0.0.1` only, and every API call needs a token generated for that run. Nothing leaves your machine.
|
|
112
|
+
- Values under `env` and `headers`, and keys in an MCP server's `args` (after flags such as `--token` or `--api-key`, or starting like `sk-` or `ghp_`), are hidden everywhere in the UI, diffs included, and ccdesk refuses any edit that would change them.
|
|
113
|
+
- ccdesk never reads `~/.claude/.credentials.json`.
|
|
114
|
+
- From your transcripts, only counts and rule patterns (a command's program and subcommand, a fetch's domain) reach the page, never commands or file contents.
|
|
115
|
+
- Backups are readable only by you on Linux and macOS.
|
|
95
116
|
|
|
96
|
-
The
|
|
117
|
+
The full list is in [Safety and privacy](https://ayagmar.github.io/ccdesk/safety-and-privacy/).
|
|
97
118
|
|
|
98
119
|
## Development
|
|
99
120
|
|
|
100
121
|
```sh
|
|
101
122
|
pnpm install
|
|
102
123
|
pnpm dev # API on 127.0.0.1:4319
|
|
103
|
-
pnpm dev:ui # UI with hot reload on
|
|
124
|
+
pnpm dev:ui # UI with hot reload on localhost:4320
|
|
104
125
|
pnpm check # typecheck, lint, format, tests, build
|
|
105
|
-
pnpm schema # regenerate src/shared/settings.schema.json
|
|
106
|
-
pnpm scopes # regenerate src/shared/settings-scopes.json from the settings reference
|
|
107
|
-
pnpm tools # regenerate src/shared/builtin-tools.json from the tools reference
|
|
108
|
-
pnpm docs:fingerprints # fingerprint the docs sections the code cites; prints the ones that changed
|
|
109
126
|
```
|
|
110
127
|
|
|
111
|
-
Tests never touch your real `~/.claude
|
|
128
|
+
Tests never touch your real `~/.claude`; each one builds a throwaway home directory. The settings schema, scopes and built-in tools are generated from [`@anthropic-ai/claude-agent-sdk`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk) and Claude Code's docs, and a daily workflow opens a pull request when they change. [Contributing](https://ayagmar.github.io/ccdesk/contributing/) covers the generators, the docs site and releases.
|
|
112
129
|
|
|
113
130
|
## License
|
|
114
131
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { join, resolve } from "node:path";
|
|
2
|
+
import {} from "../shared/types.js";
|
|
3
|
+
import {} from "./scan/env.js";
|
|
4
|
+
import { gitRoot, revisionOf, shownText } from "./scan/files.js";
|
|
5
|
+
import { scanDirectory } from "./scan/index.js";
|
|
6
|
+
import { agentProblems } from "./scan/inventory.js";
|
|
7
|
+
import { RefusedError, readIfExists, recordChange, removeExactly, serially, StaleError, writeAtomic, } from "./write.js";
|
|
8
|
+
/** The file an edit changes: an agent the scan shows here, or a new one in your or the project's folder. */
|
|
9
|
+
async function targetOf(env, edit) {
|
|
10
|
+
const dir = resolve(edit.dir);
|
|
11
|
+
if (edit.path !== undefined) {
|
|
12
|
+
const agent = (await scanDirectory(env, dir)).inventory.agents.find((a) => a.path === edit.path);
|
|
13
|
+
if (!agent)
|
|
14
|
+
throw new RefusedError("That agent is no longer here; review it again.");
|
|
15
|
+
if (agent.scope !== "user" && agent.scope !== "project")
|
|
16
|
+
throw new RefusedError(agent.scope === "plugin"
|
|
17
|
+
? "This agent comes with its plugin; change it in the plugin."
|
|
18
|
+
: "Managed agents are set by your organisation.");
|
|
19
|
+
return agent.path;
|
|
20
|
+
}
|
|
21
|
+
if (!edit.create)
|
|
22
|
+
throw new RefusedError("An agent edit needs the agent or where a new one goes.");
|
|
23
|
+
const { scope } = edit.create;
|
|
24
|
+
// The folder gives the .md; a name typed with it would otherwise end in .md.md.
|
|
25
|
+
const file = edit.create.file.replace(/\.md$/i, "");
|
|
26
|
+
if (!/^[\w][\w.-]*$/.test(file))
|
|
27
|
+
throw new RefusedError("A file name has letters, digits, '.', '-' or '_', and no folders.");
|
|
28
|
+
const folder = scope === "user"
|
|
29
|
+
? join(env.claudeDir, "agents")
|
|
30
|
+
: join((await gitRoot(dir)) ?? dir, ".claude", "agents");
|
|
31
|
+
return join(folder, `${file}.md`);
|
|
32
|
+
}
|
|
33
|
+
async function plan(env, edit) {
|
|
34
|
+
const path = await targetOf(env, edit);
|
|
35
|
+
const raw = await readIfExists(env, path);
|
|
36
|
+
if (!edit.path && raw !== null)
|
|
37
|
+
throw new RefusedError(`${path} already exists; open that agent to change it.`);
|
|
38
|
+
const before = shownText(raw);
|
|
39
|
+
// The page shows the file with env, header and URL values hidden, so a changed file written back
|
|
40
|
+
// from it would lose them; it can still be deleted, as a whole.
|
|
41
|
+
if (edit.text !== null && before !== raw)
|
|
42
|
+
throw new RefusedError(`${path} has env, header or URL values ccdesk does not show; edit it in your editor instead.`);
|
|
43
|
+
const errors = edit.text === null ? [] : agentProblems(edit.text);
|
|
44
|
+
return {
|
|
45
|
+
path,
|
|
46
|
+
raw,
|
|
47
|
+
preview: {
|
|
48
|
+
path,
|
|
49
|
+
before,
|
|
50
|
+
after: errors.length > 0 ? (before ?? "") : (shownText(edit.text) ?? ""),
|
|
51
|
+
revision: revisionOf(raw),
|
|
52
|
+
reformats: false,
|
|
53
|
+
errors,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export async function previewAgentEdit(env, edit) {
|
|
58
|
+
return (await plan(env, edit)).preview;
|
|
59
|
+
}
|
|
60
|
+
/** Writes or deletes an agent file, backed up first, only while it is as reviewed. */
|
|
61
|
+
export function saveAgentEdit(env, edit, expectedRevision) {
|
|
62
|
+
return serially(async () => {
|
|
63
|
+
const { path, raw, preview } = await plan(env, edit);
|
|
64
|
+
if (preview.errors.length > 0)
|
|
65
|
+
throw new RefusedError(preview.errors.join(" "));
|
|
66
|
+
if (preview.revision !== expectedRevision)
|
|
67
|
+
throw new RefusedError("The agent changed since you reviewed this; review it again.");
|
|
68
|
+
const { text } = edit;
|
|
69
|
+
return recordChange(env, { kind: "agent", target: path, before: raw }, async () => {
|
|
70
|
+
if (text !== null)
|
|
71
|
+
await writeAtomic(env, path, text, expectedRevision);
|
|
72
|
+
else if (!(await removeExactly(path, expectedRevision)))
|
|
73
|
+
throw new StaleError(`${path} changed while ccdesk deleted it; nothing was deleted.`);
|
|
74
|
+
return { target: path, revision: revisionOf(text) };
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|