setclaw 1.2.1 → 1.3.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/README.md +29 -1
- package/bin/setclaw.js +232 -106
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,6 +65,23 @@ npm i -g setclaw
|
|
|
65
65
|
setclaw <your-quatarly-api-key>
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
### What it does
|
|
69
|
+
|
|
70
|
+
- ✔ Backs up your current env vars and Factory config to `~/.setclaw/backup.json`
|
|
71
|
+
- ✔ Adds all 11 models to Factory AI Droid
|
|
72
|
+
- ✔ Sets env vars **system-wide** (all users) — falls back to current user if no admin rights
|
|
73
|
+
- ✔ Works on Windows, macOS, and Linux
|
|
74
|
+
|
|
75
|
+
### Restore Original Settings
|
|
76
|
+
|
|
77
|
+
Made a mistake or want to undo everything?
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
setclaw --restore
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This removes all env vars setclaw set and restores your original Factory config from the backup.
|
|
84
|
+
|
|
68
85
|
---
|
|
69
86
|
|
|
70
87
|
## Using Claude Code
|
|
@@ -157,7 +174,18 @@ Then create an account at [app.factory.ai](https://app.factory.ai), run `droid`
|
|
|
157
174
|
<details>
|
|
158
175
|
<summary><b>Can I run it again with a different API key?</b></summary>
|
|
159
176
|
|
|
160
|
-
Yes. Just run `npx setclaw@latest <new-key>` again — it updates existing models and env vars without creating duplicates. A backup
|
|
177
|
+
Yes. Just run `npx setclaw@latest <new-key>` or `setclaw <new-key>` again — it updates existing models and env vars without creating duplicates. A fresh backup is saved before every run.
|
|
178
|
+
|
|
179
|
+
</details>
|
|
180
|
+
|
|
181
|
+
<details>
|
|
182
|
+
<summary><b>How do I restore my original settings?</b></summary>
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
setclaw --restore
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
This reverts all env vars to their pre-setclaw values and restores your original Factory config from `~/.setclaw/backup.json`.
|
|
161
189
|
|
|
162
190
|
</details>
|
|
163
191
|
|
package/bin/setclaw.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* setclaw — BOA & Quatarly setup for Claude Code & Factory
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* setclaw <API_KEY>
|
|
8
|
-
*
|
|
9
|
-
* setclaw
|
|
7
|
+
* setclaw <API_KEY> — setup with key
|
|
8
|
+
* setclaw — interactive prompt
|
|
9
|
+
* setclaw --restore — restore original env vars & Factory config
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { readFileSync, writeFileSync, copyFileSync, appendFileSync, existsSync, rmSync, mkdirSync } from "fs";
|
|
@@ -20,29 +20,30 @@ import { createInterface } from "readline";
|
|
|
20
20
|
function ask(question) {
|
|
21
21
|
const rl = createInterface({ input: process.stdin, output: process.stderr, terminal: true });
|
|
22
22
|
return new Promise((resolve) =>
|
|
23
|
-
rl.question(question, (answer) => {
|
|
24
|
-
rl.close();
|
|
25
|
-
resolve(answer.trim());
|
|
26
|
-
})
|
|
23
|
+
rl.question(question, (answer) => { rl.close(); resolve(answer.trim()); })
|
|
27
24
|
);
|
|
28
25
|
}
|
|
29
26
|
|
|
30
|
-
const out
|
|
31
|
-
const err
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
27
|
+
const out = (msg = "") => process.stdout.write(msg + "\n");
|
|
28
|
+
const err = (msg = "") => process.stderr.write(msg + "\n");
|
|
29
|
+
const log = (msg) => err(`\x1b[36m>\x1b[0m ${msg}`);
|
|
30
|
+
const ok = (msg) => err(`\x1b[32m✔\x1b[0m ${msg}`);
|
|
31
|
+
const warn = (msg) => err(`\x1b[33m!\x1b[0m ${msg}`);
|
|
32
|
+
const fail = (msg) => err(`\x1b[31m✖\x1b[0m ${msg}`);
|
|
33
|
+
|
|
34
|
+
const OS = platform();
|
|
35
|
+
const HOME = homedir();
|
|
36
|
+
const BACKUP_DIR = join(HOME, ".setclaw");
|
|
37
|
+
const MARKER_FILE = join(BACKUP_DIR, "pending");
|
|
38
|
+
const BACKUP_FILE = join(BACKUP_DIR, "backup.json");
|
|
39
|
+
|
|
40
|
+
const VAR_KEYS = [
|
|
41
|
+
"ANTHROPIC_BASE_URL",
|
|
42
|
+
"ANTHROPIC_AUTH_TOKEN",
|
|
43
|
+
"ANTHROPIC_DEFAULT_HAIKU_MODEL",
|
|
44
|
+
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
45
|
+
"ANTHROPIC_DEFAULT_OPUS_MODEL",
|
|
46
|
+
];
|
|
46
47
|
|
|
47
48
|
// ─── Banner ──────────────────────────────────────────────────────────
|
|
48
49
|
|
|
@@ -51,11 +52,93 @@ out("\x1b[1m setclaw\x1b[0m — BOA & Quatarly setup for Claude Code & Factory"
|
|
|
51
52
|
out(" \x1b[2m─────────────────────────────────────────────────\x1b[0m");
|
|
52
53
|
out("");
|
|
53
54
|
|
|
54
|
-
// ───
|
|
55
|
+
// ─── Arg parsing ─────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
const args = process.argv.slice(2);
|
|
58
|
+
const restore = args.includes("--restore");
|
|
59
|
+
|
|
60
|
+
// Only treat an arg as API key if it doesn't start with - and looks like a key
|
|
61
|
+
const keyArg = args.find(a => !a.startsWith("-") && a.length > 8);
|
|
62
|
+
const apiKey = !restore ? (process.env.QUATARLY_API_KEY || keyArg) : null;
|
|
63
|
+
|
|
64
|
+
// ─── First-run detection ──────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
const isNpx = (process.env.npm_execpath || "").includes("npx") || process.argv[1].includes("_npx");
|
|
67
|
+
const isFirstRun = !isNpx && existsSync(MARKER_FILE);
|
|
68
|
+
|
|
69
|
+
// ════════════════════════════════════════════════════════════════════
|
|
70
|
+
// RESTORE MODE
|
|
71
|
+
// ════════════════════════════════════════════════════════════════════
|
|
72
|
+
|
|
73
|
+
if (restore) {
|
|
74
|
+
if (!existsSync(BACKUP_FILE)) {
|
|
75
|
+
fail("No backup found. Nothing to restore.");
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const backup = JSON.parse(readFileSync(BACKUP_FILE, "utf-8"));
|
|
80
|
+
log("Restoring original environment variables...");
|
|
81
|
+
|
|
82
|
+
if (OS === "win32") {
|
|
83
|
+
for (const key of VAR_KEYS) {
|
|
84
|
+
if (backup.env[key] !== undefined) {
|
|
85
|
+
// Restore to both user and system
|
|
86
|
+
try {
|
|
87
|
+
execSync(`reg add "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment" /v "${key}" /t REG_SZ /d "${backup.env[key]}" /f`, { stdio: "ignore" });
|
|
88
|
+
} catch {}
|
|
89
|
+
execSync(`reg add "HKCU\\Environment" /v "${key}" /t REG_SZ /d "${backup.env[key]}" /f`, { stdio: "ignore" });
|
|
90
|
+
ok(`Restored ${key} = ${backup.env[key] || "(empty)"}`);
|
|
91
|
+
} else {
|
|
92
|
+
// Was not set before — delete it
|
|
93
|
+
try {
|
|
94
|
+
execSync(`reg delete "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment" /v "${key}" /f`, { stdio: "ignore" });
|
|
95
|
+
} catch {}
|
|
96
|
+
try {
|
|
97
|
+
execSync(`reg delete "HKCU\\Environment" /v "${key}" /f`, { stdio: "ignore" });
|
|
98
|
+
} catch {}
|
|
99
|
+
ok(`Removed ${key} (was not set before)`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
// Remove setclaw block from all rc files
|
|
104
|
+
const marker = "# --- Quatarly / Claude Code env ---";
|
|
105
|
+
const endMarker = "# --- end Quatarly ---";
|
|
106
|
+
const rcFiles = ["/etc/environment", "/etc/zshenv", "/etc/bash.bashrc",
|
|
107
|
+
join(HOME, ".bashrc"), join(HOME, ".zshrc")];
|
|
108
|
+
for (const rc of rcFiles) {
|
|
109
|
+
if (!existsSync(rc)) continue;
|
|
110
|
+
const content = readFileSync(rc, "utf-8");
|
|
111
|
+
if (!content.includes(marker)) continue;
|
|
112
|
+
const regex = new RegExp(
|
|
113
|
+
`\\n?${marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${endMarker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n?`, "g"
|
|
114
|
+
);
|
|
115
|
+
writeFileSync(rc, content.replace(regex, ""), "utf-8");
|
|
116
|
+
ok(`Cleaned ${rc}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Restore Factory settings
|
|
121
|
+
const factoryPath = join(HOME, ".factory", "settings.json");
|
|
122
|
+
if (backup.factory && existsSync(factoryPath)) {
|
|
123
|
+
log("Restoring Factory settings...");
|
|
124
|
+
writeFileSync(factoryPath, JSON.stringify(backup.factory, null, 2), "utf-8");
|
|
125
|
+
ok("Factory settings restored.");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Clean up backup
|
|
129
|
+
try { rmSync(BACKUP_FILE); } catch {}
|
|
130
|
+
|
|
131
|
+
out("");
|
|
132
|
+
ok("Restore complete! Open a new terminal to apply changes.");
|
|
133
|
+
out("");
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
55
136
|
|
|
56
|
-
|
|
137
|
+
// ════════════════════════════════════════════════════════════════════
|
|
138
|
+
// SETUP MODE
|
|
139
|
+
// ════════════════════════════════════════════════════════════════════
|
|
57
140
|
|
|
58
|
-
//
|
|
141
|
+
// First-run gate
|
|
59
142
|
if (!apiKey && isFirstRun) {
|
|
60
143
|
out(" \x1b[33m⚡ Setup required!\x1b[0m Run with your Quatarly API key:");
|
|
61
144
|
out("");
|
|
@@ -66,32 +149,59 @@ if (!apiKey && isFirstRun) {
|
|
|
66
149
|
process.exit(0);
|
|
67
150
|
}
|
|
68
151
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
152
|
+
let key = apiKey;
|
|
153
|
+
if (!key) {
|
|
154
|
+
try { key = await ask(" Enter your Quatarly API key: "); }
|
|
155
|
+
catch (e) { fail(e.message); process.exit(1); }
|
|
156
|
+
}
|
|
157
|
+
if (!key) { fail("API key cannot be empty."); process.exit(1); }
|
|
158
|
+
|
|
159
|
+
err("");
|
|
160
|
+
|
|
161
|
+
// ─── Backup current state ─────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
mkdirSync(BACKUP_DIR, { recursive: true });
|
|
164
|
+
|
|
165
|
+
const backup = { env: {}, factory: null };
|
|
166
|
+
|
|
167
|
+
if (OS === "win32") {
|
|
168
|
+
for (const k of VAR_KEYS) {
|
|
169
|
+
try {
|
|
170
|
+
const val = execSync(`reg query "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment" /v "${k}" 2>nul`, { encoding: "utf-8" });
|
|
171
|
+
const match = val.match(/REG_SZ\s+(.+)/);
|
|
172
|
+
backup.env[k] = match ? match[1].trim() : "";
|
|
173
|
+
} catch {
|
|
174
|
+
// Also try HKCU
|
|
175
|
+
try {
|
|
176
|
+
const val = execSync(`reg query "HKCU\\Environment" /v "${k}" 2>nul`, { encoding: "utf-8" });
|
|
177
|
+
const match = val.match(/REG_SZ\s+(.+)/);
|
|
178
|
+
backup.env[k] = match ? match[1].trim() : "";
|
|
179
|
+
} catch {
|
|
180
|
+
backup.env[k] = undefined; // Was not set
|
|
181
|
+
}
|
|
182
|
+
}
|
|
75
183
|
}
|
|
76
184
|
}
|
|
77
185
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
186
|
+
// Backup Factory settings
|
|
187
|
+
const factoryPath = join(HOME, ".factory", "settings.json");
|
|
188
|
+
if (existsSync(factoryPath)) {
|
|
189
|
+
let raw = readFileSync(factoryPath, "utf-8");
|
|
190
|
+
if (raw.charCodeAt(0) === 0xfeff) raw = raw.slice(1);
|
|
191
|
+
backup.factory = JSON.parse(raw.trim() || "{}");
|
|
81
192
|
}
|
|
82
193
|
|
|
83
|
-
|
|
194
|
+
writeFileSync(BACKUP_FILE, JSON.stringify(backup, null, 2), "utf-8");
|
|
195
|
+
ok(`Backup saved to ${BACKUP_FILE}`);
|
|
84
196
|
|
|
85
197
|
// ─── Step 1: Add models to Factory ──────────────────────────────────
|
|
86
198
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (existsSync(settingsPath)) {
|
|
199
|
+
if (existsSync(factoryPath)) {
|
|
90
200
|
log("Adding models to Factory...");
|
|
91
201
|
|
|
92
|
-
copyFileSync(
|
|
202
|
+
copyFileSync(factoryPath, `${factoryPath}.backup`);
|
|
93
203
|
|
|
94
|
-
let raw = readFileSync(
|
|
204
|
+
let raw = readFileSync(factoryPath, "utf-8");
|
|
95
205
|
if (raw.charCodeAt(0) === 0xfeff) raw = raw.slice(1);
|
|
96
206
|
const settings = JSON.parse(raw.trim() || "{}");
|
|
97
207
|
|
|
@@ -109,120 +219,136 @@ if (existsSync(settingsPath)) {
|
|
|
109
219
|
{ model: "gpt-5.3-codex", baseUrl: "https://api.quatarly.cloud/v1", provider: "openai" },
|
|
110
220
|
];
|
|
111
221
|
|
|
112
|
-
const existing
|
|
222
|
+
const existing = settings.customModels || [];
|
|
113
223
|
const existingNames = new Set(existing.map((m) => m.model));
|
|
114
|
-
let maxIndex
|
|
115
|
-
let nextIndex
|
|
116
|
-
|
|
117
|
-
let added = 0;
|
|
118
|
-
let updated = 0;
|
|
224
|
+
let maxIndex = existing.reduce((max, m) => Math.max(max, m.index ?? -1), -1);
|
|
225
|
+
let nextIndex = maxIndex + 1;
|
|
226
|
+
let added = 0, updated = 0;
|
|
119
227
|
|
|
120
228
|
for (const m of newModels) {
|
|
121
229
|
if (existingNames.has(m.model)) {
|
|
122
230
|
for (const e of existing) {
|
|
123
|
-
if (e.model === m.model) {
|
|
124
|
-
e.apiKey = apiKey;
|
|
125
|
-
e.baseUrl = m.baseUrl;
|
|
126
|
-
e.provider = m.provider;
|
|
127
|
-
}
|
|
231
|
+
if (e.model === m.model) { e.apiKey = key; e.baseUrl = m.baseUrl; e.provider = m.provider; }
|
|
128
232
|
}
|
|
129
233
|
updated++;
|
|
130
234
|
} else {
|
|
131
|
-
existing.push({
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
index: nextIndex,
|
|
135
|
-
baseUrl: m.baseUrl,
|
|
136
|
-
apiKey,
|
|
137
|
-
displayName: m.model,
|
|
138
|
-
noImageSupport: false,
|
|
139
|
-
provider: m.provider,
|
|
140
|
-
});
|
|
141
|
-
nextIndex++;
|
|
142
|
-
added++;
|
|
235
|
+
existing.push({ model: m.model, id: `custom:${m.model}-${nextIndex}`, index: nextIndex,
|
|
236
|
+
baseUrl: m.baseUrl, apiKey: key, displayName: m.model, noImageSupport: false, provider: m.provider });
|
|
237
|
+
nextIndex++; added++;
|
|
143
238
|
}
|
|
144
239
|
}
|
|
145
240
|
|
|
146
241
|
settings.customModels = existing;
|
|
147
|
-
writeFileSync(
|
|
148
|
-
|
|
149
|
-
success(`Factory: ${added} models added, ${updated} updated (${existing.length} total)`);
|
|
150
|
-
success(`Backup saved to ${settingsPath}.backup`);
|
|
242
|
+
writeFileSync(factoryPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
243
|
+
ok(`Factory: ${added} added, ${updated} updated (${existing.length} total)`);
|
|
151
244
|
} else {
|
|
152
|
-
warn(
|
|
245
|
+
warn("Factory settings not found — skipped.");
|
|
153
246
|
}
|
|
154
247
|
|
|
155
|
-
// ─── Step 2: Set
|
|
248
|
+
// ─── Step 2: Set env vars (system-wide, fallback to user) ─────────────
|
|
156
249
|
|
|
157
|
-
log("Setting
|
|
250
|
+
log("Setting environment variables system-wide...");
|
|
158
251
|
|
|
159
252
|
const vars = {
|
|
160
253
|
ANTHROPIC_BASE_URL: "https://api.quatarly.cloud/",
|
|
161
|
-
ANTHROPIC_AUTH_TOKEN:
|
|
254
|
+
ANTHROPIC_AUTH_TOKEN: key,
|
|
162
255
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: "claude-haiku-4-5-20251001",
|
|
163
256
|
ANTHROPIC_DEFAULT_SONNET_MODEL: "claude-sonnet-4-6-20250929",
|
|
164
257
|
ANTHROPIC_DEFAULT_OPUS_MODEL: "claude-opus-4-6-thinking",
|
|
165
258
|
};
|
|
166
259
|
|
|
167
|
-
|
|
260
|
+
if (OS === "win32") {
|
|
261
|
+
let usedSystem = false;
|
|
168
262
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
263
|
+
// Try HKLM (system-wide, requires admin)
|
|
264
|
+
try {
|
|
265
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
266
|
+
execSync(
|
|
267
|
+
`reg add "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment" /v "${k}" /t REG_SZ /d "${v}" /f`,
|
|
268
|
+
{ stdio: "ignore" }
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
usedSystem = true;
|
|
272
|
+
ok("Env vars written system-wide (HKLM — all users).");
|
|
273
|
+
} catch {
|
|
274
|
+
// No admin — fall back to HKCU
|
|
275
|
+
warn("No admin rights — setting for current user only (HKCU).");
|
|
276
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
277
|
+
execSync(`reg add "HKCU\\Environment" /v "${k}" /t REG_SZ /d "${v}" /f`, { stdio: "ignore" });
|
|
278
|
+
}
|
|
279
|
+
ok("Env vars written to HKCU\\Environment.");
|
|
174
280
|
}
|
|
175
|
-
|
|
281
|
+
|
|
282
|
+
// Broadcast WM_SETTINGCHANGE so open apps pick up the change without reboot
|
|
283
|
+
try {
|
|
284
|
+
execSync(
|
|
285
|
+
`powershell -NoProfile -Command "[System.Environment]::SetEnvironmentVariable('_setclaw_refresh', $null, 'Machine')" 2>nul`,
|
|
286
|
+
{ stdio: "ignore" }
|
|
287
|
+
);
|
|
288
|
+
} catch {}
|
|
289
|
+
|
|
176
290
|
} else {
|
|
177
|
-
const marker
|
|
291
|
+
const marker = "# --- Quatarly / Claude Code env ---";
|
|
178
292
|
const endMarker = "# --- end Quatarly ---";
|
|
179
|
-
const block =
|
|
180
|
-
"",
|
|
181
|
-
marker,
|
|
182
|
-
...Object.entries(vars).map(([k, v]) => `export ${k}="${v}"`),
|
|
183
|
-
endMarker,
|
|
184
|
-
"",
|
|
185
|
-
].join("\n");
|
|
293
|
+
const block = ["", marker, ...Object.entries(vars).map(([k, v]) => `export ${k}="${v}"`), endMarker, ""].join("\n");
|
|
186
294
|
|
|
187
|
-
|
|
188
|
-
const
|
|
295
|
+
// Try system-wide files first
|
|
296
|
+
const systemFiles = OS === "darwin"
|
|
297
|
+
? ["/etc/zshenv", "/etc/bashrc"]
|
|
298
|
+
: ["/etc/environment", "/etc/bash.bashrc", "/etc/zshenv"];
|
|
189
299
|
|
|
190
|
-
|
|
191
|
-
|
|
300
|
+
const userFiles = [join(HOME, ".bashrc"), join(HOME, ".zshrc")];
|
|
301
|
+
let written = [];
|
|
192
302
|
|
|
303
|
+
const writeToRc = (rc) => {
|
|
304
|
+
if (!existsSync(rc)) return false;
|
|
193
305
|
const content = readFileSync(rc, "utf-8");
|
|
194
306
|
if (content.includes(marker)) {
|
|
195
307
|
const regex = new RegExp(
|
|
196
|
-
`\\n?${marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${endMarker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n?`,
|
|
197
|
-
"g"
|
|
308
|
+
`\\n?${marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${endMarker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n?`, "g"
|
|
198
309
|
);
|
|
199
310
|
writeFileSync(rc, content.replace(regex, block), "utf-8");
|
|
200
311
|
} else {
|
|
201
312
|
appendFileSync(rc, block, "utf-8");
|
|
202
313
|
}
|
|
203
|
-
|
|
314
|
+
return true;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// Try system-wide
|
|
318
|
+
let systemOk = false;
|
|
319
|
+
for (const rc of systemFiles) {
|
|
320
|
+
try {
|
|
321
|
+
if (writeToRc(rc)) { written.push(rc); systemOk = true; }
|
|
322
|
+
} catch {}
|
|
204
323
|
}
|
|
205
324
|
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
325
|
+
if (systemOk) {
|
|
326
|
+
ok(`Env vars written system-wide: ${written.join(", ")}`);
|
|
327
|
+
} else {
|
|
328
|
+
warn("No write access to system files — writing to user profile.");
|
|
329
|
+
for (const rc of userFiles) {
|
|
330
|
+
if (writeToRc(rc)) written.push(rc);
|
|
331
|
+
}
|
|
332
|
+
if (written.length === 0) {
|
|
333
|
+
appendFileSync(join(HOME, ".bashrc"), block, "utf-8");
|
|
334
|
+
written.push(join(HOME, ".bashrc"));
|
|
335
|
+
}
|
|
336
|
+
ok(`Env vars written to: ${written.join(", ")}`);
|
|
210
337
|
}
|
|
211
|
-
|
|
212
|
-
success(`Env vars written to: ${written.join(", ")}`);
|
|
213
338
|
}
|
|
214
339
|
|
|
215
340
|
// ─── Done ────────────────────────────────────────────────────────────
|
|
216
341
|
|
|
217
|
-
|
|
218
|
-
try { rmSync(markerFile); } catch {}
|
|
342
|
+
try { rmSync(MARKER_FILE); } catch {}
|
|
219
343
|
|
|
220
344
|
out("");
|
|
221
345
|
out(" \x1b[1mEnvironment variables set:\x1b[0m");
|
|
222
|
-
for (const [
|
|
223
|
-
const display =
|
|
224
|
-
out(` ${
|
|
346
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
347
|
+
const display = k === "ANTHROPIC_AUTH_TOKEN" ? v.slice(0, 8) + "..." : v;
|
|
348
|
+
out(` ${k} = ${display}`);
|
|
225
349
|
}
|
|
226
350
|
out("");
|
|
227
|
-
|
|
351
|
+
ok("All done! Open a new terminal, then launch Claude Code.");
|
|
352
|
+
out("");
|
|
353
|
+
out(" \x1b[2mTo restore original settings: setclaw --restore\x1b[0m");
|
|
228
354
|
out("");
|