@buffbirb/unclaude 1.0.1 → 1.0.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.
package/README.md CHANGED
@@ -13,13 +13,13 @@ I also added a few broadly useful tools to cut tokens and leverage SDD, which I
13
13
  Recommended for local installs, launch the TUI:
14
14
 
15
15
  ```sh
16
- npx unclaude
16
+ npx @buffbirb/unclaude
17
17
  ```
18
18
 
19
19
  Recommended for cloud pre-session installs, run in CLI mode:
20
20
 
21
21
  ```sh
22
- npx unclaude install --git-user "Your Name" --git-email "you@example.com"
22
+ npx @buffbirb/unclaude install --git-user "Your Name" --git-email "you@example.com"
23
23
  ```
24
24
 
25
25
  If the cloud agent doesn't support pre-session scripts, run locally with `.gitignore` disabled and commit to the repo.
package/dist/cli.js CHANGED
@@ -5,6 +5,8 @@ import { Command } from 'commander';
5
5
  import { App } from './install.js';
6
6
  import { runInstall } from './install.js';
7
7
  import { runUninstall } from './uninstall.js';
8
+ import { writeFileSync, appendFileSync } from 'fs';
9
+ import { resolve } from 'path';
8
10
  import { FEATURE_ORDER, DEFAULT_FEATURES, addGitignoreEntries, removeGitignoreEntries } from './common.js';
9
11
  const AGENTS = ['claudeCode', 'openCode'];
10
12
  const SCOPES = ['global', 'project'];
@@ -39,6 +41,20 @@ function consoleUpdateStep(id, update) {
39
41
  console.log(` ${update.line}`);
40
42
  }
41
43
  }
44
+ function makeUpdateStep(logPath) {
45
+ if (logPath)
46
+ writeFileSync(logPath, '');
47
+ return (id, update) => {
48
+ consoleUpdateStep(id, update);
49
+ if (!logPath)
50
+ return;
51
+ const ts = new Date().toISOString();
52
+ if (update.status)
53
+ appendFileSync(logPath, `${ts} [${id}] ${update.status}\n`);
54
+ if (update.line)
55
+ appendFileSync(logPath, `${ts} [${id}] ${update.line}\n`);
56
+ };
57
+ }
42
58
  const program = new Command();
43
59
  program
44
60
  .command('install')
@@ -50,6 +66,7 @@ program
50
66
  .option('--git-user <name>', 'git user.name to embed in hooks and agent md files')
51
67
  .option('--git-email <email>', 'git user.email to embed in hooks and agent md files')
52
68
  .option('--branch-prefix <prefix>', 'prefix for renamed claude/* branches')
69
+ .option('--debug', 'write timestamped log to unclaude-debug.log')
53
70
  .action((opts, cmd) => {
54
71
  let selection;
55
72
  try {
@@ -58,16 +75,22 @@ program
58
75
  catch (e) {
59
76
  cmd.error(String(e instanceof Error ? e.message : e));
60
77
  }
78
+ const logPath = opts.debug ? resolve('unclaude-debug.log') : false;
61
79
  const personalize = !!(opts.gitUser || opts.gitEmail || opts.branchPrefix);
62
80
  const formState = { personalize, gitUser: opts.gitUser ?? '', gitEmail: opts.gitEmail ?? '', branchPrefix: opts.branchPrefix ?? '' };
63
- runInstall(selection, formState, consoleUpdateStep)
81
+ runInstall(selection, formState, makeUpdateStep(logPath))
64
82
  .then(() => {
65
83
  if (opts.gitignore)
66
84
  addGitignoreEntries(selection.features);
67
85
  console.log('Install complete.');
68
- process.exit(0);
86
+ process.exitCode = 0;
69
87
  })
70
- .catch((e) => { console.error(e); process.exit(1); });
88
+ .catch((e) => {
89
+ if (logPath)
90
+ appendFileSync(logPath, `${new Date().toISOString()} ERROR: ${e}\n`);
91
+ console.error(e);
92
+ process.exitCode = 1;
93
+ });
71
94
  });
72
95
  program
73
96
  .command('uninstall')
@@ -76,6 +99,7 @@ program
76
99
  .option('--scopes <list>', `comma-separated scopes (default: all) — ${SCOPES.join(', ')}`)
77
100
  .option('--features <list>', `comma-separated features (default: all) — ${FEATURES.join(', ')}`)
78
101
  .option('--no-gitignore', 'skip removing generated project-scope files from .gitignore')
102
+ .option('--debug', 'write timestamped log to unclaude-debug.log')
79
103
  .action((opts, cmd) => {
80
104
  let selection;
81
105
  try {
@@ -84,14 +108,20 @@ program
84
108
  catch (e) {
85
109
  cmd.error(String(e instanceof Error ? e.message : e));
86
110
  }
87
- runUninstall(selection, consoleUpdateStep)
111
+ const logPath = opts.debug ? resolve('unclaude-debug.log') : false;
112
+ runUninstall(selection, makeUpdateStep(logPath))
88
113
  .then(() => {
89
114
  if (opts.gitignore)
90
115
  removeGitignoreEntries();
91
116
  console.log('Uninstall complete.');
92
- process.exit(0);
117
+ process.exitCode = 0;
93
118
  })
94
- .catch((e) => { console.error(e); process.exit(1); });
119
+ .catch((e) => {
120
+ if (logPath)
121
+ appendFileSync(logPath, `${new Date().toISOString()} ERROR: ${e}\n`);
122
+ console.error(e);
123
+ process.exitCode = 1;
124
+ });
95
125
  });
96
126
  if (process.argv.length <= 2) {
97
127
  render(_jsx(App, {}));
package/dist/install.js CHANGED
@@ -246,9 +246,12 @@ export async function runInstall(selection, formState, updateStep) {
246
246
  }
247
247
  else {
248
248
  scopes.delete('project');
249
+ if (scopes.size === 0) {
250
+ throw new Error('Project scope requested but no git repo found in cwd or any subdirectory with a .git dir touched in the last 120s.');
251
+ }
249
252
  }
250
253
  }
251
- const scopeOk = (feat) => scopes.size === 0 || FEATURE_SCOPES[feat].some(s => scopes.has(s));
254
+ const scopeOk = (feat) => FEATURE_SCOPES[feat].some(s => scopes.has(s));
252
255
  const tasks = [];
253
256
  if (features.has('headroom') && scopeOk('headroom'))
254
257
  tasks.push(['headroom', () => installHeadroom(l => updateStep('headroom', { line: l }))]);
package/dist/uninstall.js CHANGED
@@ -286,7 +286,7 @@ async function uninstallOpenspec(scopes, onLine) {
286
286
  // ── Orchestrator ──────────────────────────────────────────────────────────────
287
287
  export async function runUninstall(selection, updateStep) {
288
288
  const { features, scopes, agents, lspLanguages } = selection;
289
- const scopeOk = (feat) => scopes.size === 0 || FEATURE_SCOPES[feat].some(s => scopes.has(s));
289
+ const scopeOk = (feat) => FEATURE_SCOPES[feat].some(s => scopes.has(s));
290
290
  const tasks = [];
291
291
  if (features.has('headroom') && scopeOk('headroom'))
292
292
  tasks.push(['headroom', () => uninstallHeadroom(l => updateStep('headroom', { line: l }))]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buffbirb/unclaude",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "An opinionated AI dev tool setup script with a terminal UI. Configure privacy, code intelligence, and tool wrappers for Claude Code and OpenCode.",
5
5
  "type": "module",
6
6
  "keywords": [