@0xgeorgemathew/zcode 0.3.0 → 0.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.
@@ -92,6 +92,8 @@ module.exports = async function run(parsed) {
92
92
  if (flags.includeReasoning) result.reasoning = turn.reasoningText;
93
93
  process.stdout.write(JSON.stringify(result) + '\n');
94
94
  } else {
95
+ if (!streamedText.trim()) process.stdout.write(turn.response);
96
+ process.stdout.write('\n');
95
97
  reporter.footer({
96
98
  model: turn.engineModel || flags.model,
97
99
  effort: turn.engineReasoningLevel || flags.effort,
@@ -99,8 +101,6 @@ module.exports = async function run(parsed) {
99
101
  durationMs: turn.durationMs,
100
102
  sessionId: turn.sessionId,
101
103
  });
102
- if (!streamedText.trim()) process.stdout.write(turn.response);
103
- process.stdout.write('\n');
104
104
  }
105
105
  client.kill();
106
106
  process.exit(0);
package/lib/engine.js CHANGED
@@ -31,20 +31,50 @@ class BuiltinConfigNotFoundError extends Error {
31
31
  }
32
32
  }
33
33
 
34
+ // Our own wrapper's real path. The engine resolver must never resolve to
35
+ // itself: `npm install -g` puts a `zcode` symlink on PATH, and before the
36
+ // 0.3.1 fix the PATH probe grabbed it as "the engine" (0.3.0 regression:
37
+ // every command then exited 4 probing <prefix>/config/provider/…).
38
+ const SELF_BIN_PATH = (() => {
39
+ try {
40
+ return fs.realpathSync(path.join(__dirname, '..', 'bin', 'zcode.js'));
41
+ } catch {
42
+ return null;
43
+ }
44
+ })();
45
+
46
+ function isSelf(candidate) {
47
+ if (!SELF_BIN_PATH) return false;
48
+ try {
49
+ return fs.realpathSync(candidate) === SELF_BIN_PATH;
50
+ } catch {
51
+ return false;
52
+ }
53
+ }
54
+
34
55
  // Resolves a candidate that is either the zcode.cjs file itself or a
35
- // directory containing it. Returns an absolute file path or null.
36
- function resolveCandidate(candidate) {
56
+ // directory containing it. strictFile (default true for everything except
57
+ // an explicit ZAI_CODE_ENGINE): a bare file is only accepted when it is
58
+ // literally named zcode.cjs — the engine bundle — so wrappers and launchers
59
+ // named `zcode` never pass. Our own binary is always rejected.
60
+ function resolveCandidate(candidate, { strictFile = true } = {}) {
61
+ if (isSelf(candidate)) return null;
37
62
  let st;
38
63
  try {
39
64
  st = fs.statSync(candidate);
40
65
  } catch {
41
66
  return null;
42
67
  }
43
- if (st.isFile()) return path.resolve(candidate);
68
+ if (st.isFile()) {
69
+ if (strictFile && path.basename(candidate) !== 'zcode.cjs') return null;
70
+ return path.resolve(candidate);
71
+ }
44
72
  if (st.isDirectory()) {
45
73
  const inner = path.join(candidate, 'zcode.cjs');
46
74
  try {
47
- if (fs.statSync(inner).isFile()) return path.resolve(inner);
75
+ if (fs.statSync(inner).isFile() && !isSelf(inner)) {
76
+ return path.resolve(inner);
77
+ }
48
78
  } catch {
49
79
  /* not there */
50
80
  }
@@ -66,20 +96,25 @@ function whichOnPath(bin, envPath) {
66
96
  return null;
67
97
  }
68
98
 
69
- // First hit wins (DESIGN §4). Throws EngineNotFoundError listing all probes.
99
+ // First hit wins (DESIGN §4, revised 0.3.1): explicit env override, then
100
+ // the app bundle (the canonical macOS location), then PATH/home probes —
101
+ // which now only accept a real zcode.cjs, never a same-named wrapper.
102
+ // Throws EngineNotFoundError listing all probes.
70
103
  function resolveEngine(env = process.env) {
71
104
  const probed = [];
72
105
  const candidates = [];
73
- if (env.ZAI_CODE_ENGINE) candidates.push(env.ZAI_CODE_ENGINE);
106
+ if (env.ZAI_CODE_ENGINE) candidates.push({ path: env.ZAI_CODE_ENGINE, strictFile: false });
107
+ candidates.push({ path: APP_BUNDLE_ENGINE });
74
108
  const onPath = whichOnPath('zcode', env.PATH);
75
- if (onPath) candidates.push(onPath);
76
- candidates.push(path.join(os.homedir(), '.local', 'bin', 'zcode'));
77
- candidates.push(path.join(os.homedir(), '.zcode', 'runtime', 'zcode.cjs'));
78
- candidates.push(APP_BUNDLE_ENGINE);
109
+ if (onPath) candidates.push({ path: onPath });
110
+ candidates.push({ path: path.join(os.homedir(), '.local', 'bin', 'zcode') });
111
+ candidates.push({ path: path.join(os.homedir(), '.zcode', 'runtime', 'zcode.cjs') });
79
112
  for (const candidate of candidates) {
80
- const resolved = resolveCandidate(candidate);
113
+ const resolved = resolveCandidate(candidate.path, {
114
+ strictFile: candidate.strictFile ?? true,
115
+ });
81
116
  if (resolved) return resolved;
82
- probed.push(candidate);
117
+ probed.push(candidate.path);
83
118
  }
84
119
  throw new EngineNotFoundError(probed);
85
120
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xgeorgemathew/zcode",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
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,