@buffbirb/unclaude 1.0.0
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/LICENSE +21 -0
- package/README.md +121 -0
- package/dist/cli.js +101 -0
- package/dist/common.js +526 -0
- package/dist/install.js +688 -0
- package/dist/uninstall.js +595 -0
- package/package.json +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 aisetup author
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# unclaude
|
|
2
|
+
|
|
3
|
+
An opinionated AI project setup script with a TUI and CLI.
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
Do you make VSCode your commit author? Do you write "sent from my dell xps" in your PRs? If not, then maybe you take issue with AI agents leaving their dirty footprints all over your git history. A simple change to `.claude/settings.json` will patch your local setup, but cloud agents need a wider array of fixes.
|
|
8
|
+
|
|
9
|
+
I also added a few broadly useful tools to cut tokens and leverage SDD, which I have been adding in nearly every project lately. You can pick only what you need.
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
Recommended for local installs, launch the TUI:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npx unclaude
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Recommended for cloud pre-session installs, run in CLI mode:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npx unclaude install --git-user "Your Name" --git-email "you@example.com"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If the cloud agent doesn't support pre-session scripts, run locally with `.gitignore` disabled and commit to the repo.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
| Feature | What it does |
|
|
30
|
+
|---|---|
|
|
31
|
+
| **Stop Telemetry** | Exports `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` in `~/.airc` |
|
|
32
|
+
| **Agent config for git commits** | Sets `attribution: { commit: '', pr: '' }` in Claude Code `settings.json` |
|
|
33
|
+
| **Git pre-commit hook for git commits** | Installs a `commit-msg` git hook that strips `🤖 Generated with Claude Code`, `Co-Authored-By: Claude`, session URLs, and lone `---` separators |
|
|
34
|
+
| **Agent SessionStart hook for git commits** | Registers a Claude Code `SessionStart` hook that installs a bash `commit-msg` hook in `.git/hooks` at the start of every session |
|
|
35
|
+
| **Agent SessionStart hook for git branches** | Registers a Claude Code `SessionStart` hook that renames `claude/*` or `claude-*` branches to a custom prefix (or removes the prefix) |
|
|
36
|
+
| **GitHub Action for PR body** | Writes a workflow that strips Claude attribution from PR bodies server-side on `opened`/`edited` |
|
|
37
|
+
| **Agent md file for all git ops** | Appends attribution rules to `CLAUDE.md` (Claude Code) or `AGENTS.md` (OpenCode) |
|
|
38
|
+
| **LSP** | Enables `ENABLE_LSP_TOOL` in Claude Code settings; installs clangd-lsp / swift-lsp plugins; adds clangd to `~/.airc` PATH; enables LSP in OpenCode config |
|
|
39
|
+
| **Headroom** | Installs headroom via uv; writes `hclaude` and `hopencode` wrapper scripts to `/usr/local/bin`; adds a `headroom_start` function to `~/.airc` |
|
|
40
|
+
| **OpenSpec** | Installs `@fission-ai/openspec` globally via npm; optionally runs `openspec init` in the current directory |
|
|
41
|
+
|
|
42
|
+
### Feature matrix
|
|
43
|
+
|
|
44
|
+
| Feature | Agents | Scope |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| Stop Telemetry | Claude Code | Global |
|
|
47
|
+
| Agent config for git commits | Claude Code | Global, Project |
|
|
48
|
+
| Git pre-commit hook for git commits¹ | Claude Code, OpenCode | Project |
|
|
49
|
+
| Agent SessionStart hook for git commits | Claude Code | Project |
|
|
50
|
+
| Agent SessionStart hook for git branches | Claude Code | Project |
|
|
51
|
+
| GitHub Action for PR body | Claude Code, OpenCode | Project |
|
|
52
|
+
| Agent md file for all git ops | Claude Code, OpenCode | Global, Project |
|
|
53
|
+
| LSP | Claude Code, OpenCode | Global |
|
|
54
|
+
| Headroom | Claude Code, OpenCode | Global |
|
|
55
|
+
| OpenSpec | Claude Code, OpenCode | Global (install), Project (init) |
|
|
56
|
+
|
|
57
|
+
¹ Git pre-commit hook can be set globally, but it's intentionally restricted to project-scope in this installer.
|
|
58
|
+
|
|
59
|
+
### Personalization
|
|
60
|
+
|
|
61
|
+
If you select certain features, a second screen asks whether to personalize the setup to your identity.
|
|
62
|
+
|
|
63
|
+
| Field | Purpose |
|
|
64
|
+
|---|---|
|
|
65
|
+
| **Git user** | Your `user.name` (prefilled from `git config --global user.name`). Used by the **Agent SessionStart hook for git commits** and **Agent md file for all git ops**. |
|
|
66
|
+
| **Git email** | Your `user.email` (prefilled from `git config --global user.email`). Used by the **Agent SessionStart hook for git commits** and **Agent md file for all git ops**. |
|
|
67
|
+
| **Branch prefix** | Prepended to renamed `claude/*` branches (e.g., `username/foo`). Used by the **Agent SessionStart hook for git branches**. |
|
|
68
|
+
|
|
69
|
+
This is most useful in **managed cloud environments** (e.g., Claude Code Web) where the AI does not have access to your local git configuration. By embedding your identity, commits and branch metadata are authored under your name rather than an AI-generated default.
|
|
70
|
+
|
|
71
|
+
> **Note:** Commits will still show as **unverified** on GitHub / GitLab because most cloud providers do not offer a secure place to store a GPG or SSH signing key.
|
|
72
|
+
|
|
73
|
+
### Git Settings
|
|
74
|
+
|
|
75
|
+
Currently only `.gitignore` is amended with a section covering generated attribution-related files.
|
|
76
|
+
|
|
77
|
+
## CLI arguments
|
|
78
|
+
|
|
79
|
+
Running with no arguments launches the interactive TUI. Pass a subcommand for non-interactive use:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
unclaude install [--agents <list>] [--scopes <list>] [--features <list>] [--gitignore]
|
|
83
|
+
[--git-user <name>] [--git-email <email>] [--branch-prefix <prefix>]
|
|
84
|
+
unclaude uninstall [--agents <list>] [--scopes <list>] [--features <list>] [--gitignore]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Each list option takes a comma-separated value. Omitting a list option defaults to all valid values.
|
|
88
|
+
|
|
89
|
+
| Option | Description |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `--agents` | `claudeCode`, `openCode` |
|
|
92
|
+
| `--scopes` | `global`, `project` |
|
|
93
|
+
| `--features` | `stopTelemetry`, `stopAttributionConfig`, `stopAttributionHook`, `stripCommitAttribution`, `renameClaudeBranch`, `stripPrAttribution`, `agentMdFile`, `lsp`, `headroom`, `openspec` |
|
|
94
|
+
| `--no-gitignore` | Skip adding generated project-scope files to `.gitignore` (default: adds them) |
|
|
95
|
+
| `--git-user` | Your `user.name` — embedded in hooks and agent md files |
|
|
96
|
+
| `--git-email` | Your `user.email` — embedded in hooks and agent md files |
|
|
97
|
+
| `--branch-prefix` | Prefix for renamed `claude/*` branches (e.g. `username`) |
|
|
98
|
+
|
|
99
|
+
**Examples**
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
# Install default features (no TUI)
|
|
103
|
+
unclaude install
|
|
104
|
+
|
|
105
|
+
# Install only telemetry suppression, globally
|
|
106
|
+
unclaude install --features stopTelemetry
|
|
107
|
+
|
|
108
|
+
# Uninstall LSP for Claude Code only
|
|
109
|
+
unclaude uninstall --features lsp --agents claudeCode
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Development
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
npm install
|
|
116
|
+
npm run dev # run (tsx, no build step)
|
|
117
|
+
npm run build # compile → dist/
|
|
118
|
+
npm publish # builds automatically via prepublishOnly
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Requires Node ≥ 18 and tsx (`npm install` handles dev dependencies).
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { render } from 'ink';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { App } from './install.js';
|
|
6
|
+
import { runInstall } from './install.js';
|
|
7
|
+
import { runUninstall } from './uninstall.js';
|
|
8
|
+
import { FEATURE_ORDER, DEFAULT_FEATURES, addGitignoreEntries, removeGitignoreEntries } from './common.js';
|
|
9
|
+
const AGENTS = ['claudeCode', 'openCode'];
|
|
10
|
+
const SCOPES = ['global', 'project'];
|
|
11
|
+
const FEATURES = FEATURE_ORDER;
|
|
12
|
+
function parseList(val, valid) {
|
|
13
|
+
const items = val.split(',').map(s => s.trim());
|
|
14
|
+
for (const item of items) {
|
|
15
|
+
if (!valid.includes(item)) {
|
|
16
|
+
throw new Error(`Invalid value "${item}". Valid: ${valid.join(', ')}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return new Set(items);
|
|
20
|
+
}
|
|
21
|
+
function buildSelection(opts) {
|
|
22
|
+
const features = opts.features
|
|
23
|
+
? parseList(opts.features, FEATURES)
|
|
24
|
+
: new Set(DEFAULT_FEATURES);
|
|
25
|
+
return {
|
|
26
|
+
agents: opts.agents ? parseList(opts.agents, AGENTS) : new Set(AGENTS),
|
|
27
|
+
scopes: opts.scopes ? parseList(opts.scopes, SCOPES) : new Set(SCOPES),
|
|
28
|
+
features,
|
|
29
|
+
lspLanguages: features.has('lsp') ? new Set(['cpp', 'swift']) : new Set(),
|
|
30
|
+
gitSettings: new Set(['gitignore']),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function consoleUpdateStep(id, update) {
|
|
34
|
+
if (update.status) {
|
|
35
|
+
const status = update.status === 'running' ? '...' : update.status === 'done' ? ' ✓' : update.status === 'error' ? ' ✗' : '';
|
|
36
|
+
console.log(`[${id}]${status}`);
|
|
37
|
+
}
|
|
38
|
+
if (update.line) {
|
|
39
|
+
console.log(` ${update.line}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const program = new Command();
|
|
43
|
+
program
|
|
44
|
+
.command('install')
|
|
45
|
+
.description('non-interactive install')
|
|
46
|
+
.option('--agents <list>', `comma-separated agents (default: all) — ${AGENTS.join(', ')}`)
|
|
47
|
+
.option('--scopes <list>', `comma-separated scopes (default: all) — ${SCOPES.join(', ')}`)
|
|
48
|
+
.option('--features <list>', `comma-separated features (default: all) — ${FEATURES.join(', ')}`)
|
|
49
|
+
.option('--no-gitignore', 'skip adding generated project-scope files to .gitignore')
|
|
50
|
+
.option('--git-user <name>', 'git user.name to embed in hooks and agent md files')
|
|
51
|
+
.option('--git-email <email>', 'git user.email to embed in hooks and agent md files')
|
|
52
|
+
.option('--branch-prefix <prefix>', 'prefix for renamed claude/* branches')
|
|
53
|
+
.action((opts, cmd) => {
|
|
54
|
+
let selection;
|
|
55
|
+
try {
|
|
56
|
+
selection = buildSelection(opts);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
cmd.error(String(e instanceof Error ? e.message : e));
|
|
60
|
+
}
|
|
61
|
+
const personalize = !!(opts.gitUser || opts.gitEmail || opts.branchPrefix);
|
|
62
|
+
const formState = { personalize, gitUser: opts.gitUser ?? '', gitEmail: opts.gitEmail ?? '', branchPrefix: opts.branchPrefix ?? '' };
|
|
63
|
+
runInstall(selection, formState, consoleUpdateStep)
|
|
64
|
+
.then(() => {
|
|
65
|
+
if (opts.gitignore)
|
|
66
|
+
addGitignoreEntries(selection.features);
|
|
67
|
+
console.log('Install complete.');
|
|
68
|
+
process.exit(0);
|
|
69
|
+
})
|
|
70
|
+
.catch((e) => { console.error(e); process.exit(1); });
|
|
71
|
+
});
|
|
72
|
+
program
|
|
73
|
+
.command('uninstall')
|
|
74
|
+
.description('non-interactive uninstall')
|
|
75
|
+
.option('--agents <list>', `comma-separated agents (default: all) — ${AGENTS.join(', ')}`)
|
|
76
|
+
.option('--scopes <list>', `comma-separated scopes (default: all) — ${SCOPES.join(', ')}`)
|
|
77
|
+
.option('--features <list>', `comma-separated features (default: all) — ${FEATURES.join(', ')}`)
|
|
78
|
+
.option('--no-gitignore', 'skip removing generated project-scope files from .gitignore')
|
|
79
|
+
.action((opts, cmd) => {
|
|
80
|
+
let selection;
|
|
81
|
+
try {
|
|
82
|
+
selection = buildSelection(opts);
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
cmd.error(String(e instanceof Error ? e.message : e));
|
|
86
|
+
}
|
|
87
|
+
runUninstall(selection, consoleUpdateStep)
|
|
88
|
+
.then(() => {
|
|
89
|
+
if (opts.gitignore)
|
|
90
|
+
removeGitignoreEntries();
|
|
91
|
+
console.log('Uninstall complete.');
|
|
92
|
+
process.exit(0);
|
|
93
|
+
})
|
|
94
|
+
.catch((e) => { console.error(e); process.exit(1); });
|
|
95
|
+
});
|
|
96
|
+
if (process.argv.length <= 2) {
|
|
97
|
+
render(_jsx(App, {}));
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
program.parse();
|
|
101
|
+
}
|