@0xgeorgemathew/zcode 0.3.1 → 0.3.2
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 +2 -2
- package/lib/commands/doctor.js +1 -1
- package/lib/isolation.js +51 -1
- package/lib/key.js +10 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -213,9 +213,9 @@ Event types on the way in:
|
|
|
213
213
|
|
|
214
214
|
## Under the hood
|
|
215
215
|
|
|
216
|
-
**Key handling.** `ZAI_API_KEY` env var, or `zcode login` which stores it at `~/.zcode/credentials.json` (mode 600). The key is never printed or logged. The only file it ever lands in is the scratch provider config, which the engine requires to register the provider.
|
|
216
|
+
**Key handling.** `ZAI_API_KEY` env var, or `zcode login` which stores it at `~/.zcode-cli/credentials.json` (mode 600). The key is never printed or logged. The only file it ever lands in is the scratch provider config, which the engine requires to register the provider.
|
|
217
217
|
|
|
218
|
-
**Isolation.** The engine runs with `HOME` pointed at a scratch copy
|
|
218
|
+
**Isolation.** This package's own state lives under `~/.zcode-cli` (never under `~/.zcode`, which belongs to the desktop app; if an older 0.3.x left files there, they are migrated out automatically on first run). The engine runs with `HOME` pointed at a scratch copy we own (`~/.zcode-cli/home`, mode 700, mtime-cached). Your live `~/.zcode`, which the desktop app is using right now, is never written to. Your OAuth `credentials.json` is deliberately never copied. The scratch keeps exactly the `zai-api` provider rule with your key, your agents, and your skills.
|
|
219
219
|
|
|
220
220
|
**Yolo mode.** Sessions run with auto-approved tool side effects, matching the engine's own headless default; `--cwd` is the declared blast radius. A headless run that requests interactive user input fails fast with exit 5 rather than hanging.
|
|
221
221
|
|
package/lib/commands/doctor.js
CHANGED
|
@@ -85,7 +85,7 @@ module.exports = async function doctor(parsed) {
|
|
|
85
85
|
(isolation.stamp && typeof isolation.stamp.skillsCopied === 'number'
|
|
86
86
|
? isolation.stamp.skillsCopied
|
|
87
87
|
: 0) || 0,
|
|
88
|
-
mcpServersInherited: Object.keys(effectiveMcpServers({})).length,
|
|
88
|
+
mcpServersInherited: Object.keys(effectiveMcpServers({ inherit: true })).length,
|
|
89
89
|
experimental:
|
|
90
90
|
isolation.mode === 'synthesized'
|
|
91
91
|
? 'synthesized config path is unproven; copy a real ~/.zcode/v2 or verify once on a clean HOME'
|
package/lib/isolation.js
CHANGED
|
@@ -226,13 +226,62 @@ function buildScratch(home, key) {
|
|
|
226
226
|
|
|
227
227
|
// --- public API -------------------------------------------------------------
|
|
228
228
|
|
|
229
|
+
// Root of zcode's own state. MUST NOT be ~/.zcode: that is the desktop
|
|
230
|
+
// app's live directory (0.3.0/0.3.1 regression — the package rename made
|
|
231
|
+
// rootDir collide with it, so login/scratch files landed inside the live
|
|
232
|
+
// config). Ours is ~/.zcode-cli.
|
|
229
233
|
function rootDir(env = process.env) {
|
|
230
|
-
return env.ZAI_CODE_HOME || path.join(os.homedir(), '.zcode');
|
|
234
|
+
return env.ZAI_CODE_HOME || path.join(os.homedir(), '.zcode-cli');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// The only file/dir names this package ever creates at its root.
|
|
238
|
+
// migrateRoot moves exactly these out of legacy locations and never
|
|
239
|
+
// touches anything else.
|
|
240
|
+
const OUR_ARTIFACTS = ['credentials.json', 'build-stamp.json', 'injected-skills.json', 'home'];
|
|
241
|
+
|
|
242
|
+
// 0.3.2 migration: vacate our artifacts from (a) the live ~/.zcode, where
|
|
243
|
+
// 0.3.0/0.3.1 wrongly wrote them, and (b) the pre-rename ~/.zai-code root,
|
|
244
|
+
// into the new ~/.zcode-cli root. Idempotent; never writes or deletes
|
|
245
|
+
// anything else in the live directory.
|
|
246
|
+
function migrateRoot(env = process.env) {
|
|
247
|
+
const root = rootDir(env);
|
|
248
|
+
try {
|
|
249
|
+
fs.mkdirSync(root, { recursive: true });
|
|
250
|
+
} catch {
|
|
251
|
+
return; // unwritable home — leave everything as-is; ensureIsolation surfaces it
|
|
252
|
+
}
|
|
253
|
+
const sources = [
|
|
254
|
+
LIVE_ZCODE, // live dir: move ours out, keep everything else
|
|
255
|
+
path.join(os.homedir(), '.zai-code'), // pre-rename root: wholly ours
|
|
256
|
+
];
|
|
257
|
+
for (const dir of sources) {
|
|
258
|
+
let entries;
|
|
259
|
+
try {
|
|
260
|
+
entries = new Set(fs.readdirSync(dir));
|
|
261
|
+
} catch {
|
|
262
|
+
continue; // nothing to migrate from this source
|
|
263
|
+
}
|
|
264
|
+
for (const name of OUR_ARTIFACTS) {
|
|
265
|
+
if (!entries.has(name)) continue;
|
|
266
|
+
const src = path.join(dir, name);
|
|
267
|
+
const dest = path.join(root, name);
|
|
268
|
+
try {
|
|
269
|
+
if (fs.existsSync(dest)) {
|
|
270
|
+
fs.rmSync(src, { recursive: true, force: true });
|
|
271
|
+
} else {
|
|
272
|
+
fs.renameSync(src, dest);
|
|
273
|
+
}
|
|
274
|
+
} catch {
|
|
275
|
+
/* keep going; a missing artifact just rebuilds */
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
231
279
|
}
|
|
232
280
|
|
|
233
281
|
// Ensures the scratch HOME exists and is current. Returns
|
|
234
282
|
// {root, home, mode, built, stamp}.
|
|
235
283
|
function ensureIsolation(key, { fresh = false, env = process.env } = {}) {
|
|
284
|
+
migrateRoot(env);
|
|
236
285
|
const root = rootDir(env);
|
|
237
286
|
fs.mkdirSync(root, { recursive: true });
|
|
238
287
|
fs.chmodSync(root, 0o700);
|
|
@@ -307,6 +356,7 @@ module.exports = {
|
|
|
307
356
|
ensureIsolation,
|
|
308
357
|
engineEnv,
|
|
309
358
|
rootDir,
|
|
359
|
+
migrateRoot,
|
|
310
360
|
keySha256,
|
|
311
361
|
LIVE_ZCODE,
|
|
312
362
|
LIVE_V2,
|
package/lib/key.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
// API key resolution (DESIGN §5): ZAI_API_KEY env →
|
|
3
|
-
// ({"apiKey":"…"}, mode 600, written by
|
|
4
|
-
// printed, logged, or echoed by anything
|
|
2
|
+
// API key resolution (DESIGN §5): ZAI_API_KEY env →
|
|
3
|
+
// ~/.zcode-cli/credentials.json ({"apiKey":"…"}, mode 600, written by
|
|
4
|
+
// `zcode login`). The key is never printed, logged, or echoed by anything
|
|
5
|
+
// in this package.
|
|
5
6
|
const fs = require('node:fs');
|
|
6
7
|
const path = require('node:path');
|
|
7
8
|
const os = require('node:os');
|
|
9
|
+
const { migrateRoot } = require('./isolation.js');
|
|
8
10
|
|
|
9
11
|
// Root of zcode's own state (scratch HOME lives under <root>/home).
|
|
12
|
+
// MUST NOT be ~/.zcode — that is the desktop app's live directory the
|
|
13
|
+
// engine itself owns (0.3.0/0.3.1 regression: the rename made the CLI
|
|
14
|
+
// write credentials and the scratch HOME straight into it).
|
|
10
15
|
function rootDir(env = process.env) {
|
|
11
|
-
return env.ZAI_CODE_HOME || path.join(os.homedir(), '.zcode');
|
|
16
|
+
return env.ZAI_CODE_HOME || path.join(os.homedir(), '.zcode-cli');
|
|
12
17
|
}
|
|
13
18
|
|
|
14
19
|
function credentialsPath(env = process.env) {
|
|
@@ -41,6 +46,7 @@ function readCredentialsKey(file) {
|
|
|
41
46
|
// Sources, in order: ZAI_API_KEY (non-empty) → credentials.json.
|
|
42
47
|
// Throws NoKeyError when neither holds a key.
|
|
43
48
|
function resolveKey(env = process.env) {
|
|
49
|
+
migrateRoot(env); // 0.3.2: vacate our artifacts out of the live ~/.zcode first
|
|
44
50
|
const fromEnv = (env.ZAI_API_KEY || '').trim();
|
|
45
51
|
if (fromEnv) return fromEnv;
|
|
46
52
|
const fromFile = readCredentialsKey(credentialsPath(env));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xgeorgemathew/zcode",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Headless GLM-5.3 / GLM-5.3-Flash coding CLI for agents: streaming thinking, subagents, MCP servers, skills, session continuity. Wraps the ZCode engine. Zero dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|