ucode-agent 1.7.0 → 1.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ucode-agent",
3
- "version": "1.7.0",
3
+ "version": "1.8.1",
4
4
  "description": "ucode - a terminal coding agent that reads, edits and runs your code, on NVIDIA and Cohere models.",
5
5
  "type": "module",
6
6
  "main": "ucode.js",
@@ -0,0 +1,59 @@
1
+ /**
2
+ * login.js — putting the API key somewhere ucode will always find it.
3
+ *
4
+ * A key in a project's .env is a key you set up again in the next folder, and
5
+ * on the next machine. This writes it once to ~/.ucode/.env, which every
6
+ * project on the machine reads, so setting ucode up somewhere new — a borrowed
7
+ * laptop, a machine you are demonstrating on — is one command.
8
+ *
9
+ * The file is written with owner-only permissions, and the existing contents
10
+ * are kept: a key is replaced in place rather than by rewriting the file.
11
+ */
12
+
13
+ import { promises as fs } from 'node:fs';
14
+ import path from 'node:path';
15
+ import { ENV_FILE } from './provider.js';
16
+
17
+ const NAME = 'OPENROUTER_API_KEY';
18
+
19
+ /** A plausible OpenRouter key, so a typo is caught here and not mid-answer. */
20
+ export function looksLikeKey(key) {
21
+ return typeof key === 'string' && /^sk-[A-Za-z0-9_-]{20,}$/.test(key.trim());
22
+ }
23
+
24
+ /** Put `key` in the machine-wide env file, keeping whatever else is in it. */
25
+ export function withKey(existing, key) {
26
+ const line = `${NAME}=${key}`;
27
+ const lines = String(existing ?? '').split('\n');
28
+ let replaced = false;
29
+ const out = lines.map((l) => {
30
+ if (new RegExp(`^\\s*(?:export\\s+)?${NAME}\\s*=`).test(l)) {
31
+ replaced = true;
32
+ return line;
33
+ }
34
+ return l;
35
+ });
36
+ if (!replaced) {
37
+ if (out.length && out[out.length - 1].trim() !== '') out.push('');
38
+ out.splice(out.length - 1, 0, line);
39
+ }
40
+ return out.join('\n').replace(/\n{3,}/g, '\n\n');
41
+ }
42
+
43
+ export async function saveKey(key) {
44
+ const trimmed = String(key ?? '').trim();
45
+
46
+ if (!trimmed) {
47
+ return ` Usage: ucode login <key>\n\n Get one free at https://openrouter.ai/keys\n It is saved to ${ENV_FILE} and used by every project on this machine.`;
48
+ }
49
+ if (!looksLikeKey(trimmed)) {
50
+ return ` That does not look like an OpenRouter key — they start with "sk-".\n Get one at https://openrouter.ai/keys`;
51
+ }
52
+
53
+ const existing = await fs.readFile(ENV_FILE, 'utf8').catch(() => '');
54
+ await fs.mkdir(path.dirname(ENV_FILE), { recursive: true });
55
+ await fs.writeFile(ENV_FILE, withKey(existing, trimmed), { encoding: 'utf8', mode: 0o600 });
56
+ await fs.chmod(ENV_FILE, 0o600).catch(() => {});
57
+
58
+ return ` Key saved to ${ENV_FILE}\n Every project on this machine will use it. Run ucode anywhere to start.`;
59
+ }