zelari-code 1.8.2 → 1.9.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.
@@ -0,0 +1,281 @@
1
+ /**
2
+ * desktopConfig — non-interactive config dump/set for Zelari Desktop
3
+ * and scripts. Never prints API keys.
4
+ *
5
+ * Flags (handled in main.ts before TUI):
6
+ * --print-config
7
+ * --set-config [--provider] [--model] [--endpoint] [--endpoint-clear]
8
+ * --set-key --provider <id> --key <secret>
9
+ * --discover-models [--provider <id>]
10
+ */
11
+ import { PROVIDERS, resolveApiKey, getKeyStorePath, setApiKey, maskKey, } from './keyStore.js';
12
+ import { getProviderConfig, getProviderConfigPath, setActiveProviderId, setModelForProvider, setCustomEndpoint, clearCustomEndpoint, getCustomEndpoint, } from './providerConfig.js';
13
+ import { getCachedModels, discoverModelsForProvider, } from './modelDiscovery.js';
14
+ import { getCurrentVersion } from './updater.js';
15
+ /** True when argv requests --print-config. */
16
+ export function wantsPrintConfig(argv) {
17
+ return argv.includes('--print-config');
18
+ }
19
+ export function wantsSetKey(argv) {
20
+ return argv.includes('--set-key');
21
+ }
22
+ export function wantsDiscoverModels(argv) {
23
+ return argv.includes('--discover-models');
24
+ }
25
+ /**
26
+ * Parse --set-config [--provider id] [--model name] [--endpoint url] [--endpoint-clear].
27
+ */
28
+ export function parseSetConfigFlags(argv) {
29
+ if (!argv.includes('--set-config')) {
30
+ return { request: null };
31
+ }
32
+ let provider;
33
+ let model;
34
+ let endpoint;
35
+ let endpointClear = false;
36
+ for (let i = 0; i < argv.length; i++) {
37
+ const arg = argv[i];
38
+ if (arg === '--provider') {
39
+ provider = argv[i + 1];
40
+ i++;
41
+ }
42
+ else if (arg === '--model') {
43
+ model = argv[i + 1];
44
+ i++;
45
+ }
46
+ else if (arg === '--endpoint') {
47
+ endpoint = argv[i + 1];
48
+ i++;
49
+ }
50
+ else if (arg === '--endpoint-clear') {
51
+ endpointClear = true;
52
+ }
53
+ }
54
+ if (!provider && !model && !endpoint && !endpointClear) {
55
+ return {
56
+ request: null,
57
+ error: '--set-config requires --provider, --model, --endpoint, and/or --endpoint-clear',
58
+ };
59
+ }
60
+ if (provider !== undefined && provider.trim().length === 0) {
61
+ return { request: null, error: '--provider cannot be empty' };
62
+ }
63
+ if (model !== undefined && model.trim().length === 0) {
64
+ return { request: null, error: '--model cannot be empty' };
65
+ }
66
+ if (endpoint !== undefined && endpoint.trim().length === 0) {
67
+ return { request: null, error: '--endpoint cannot be empty' };
68
+ }
69
+ if (endpoint && endpointClear) {
70
+ return { request: null, error: '--endpoint and --endpoint-clear conflict' };
71
+ }
72
+ return {
73
+ request: {
74
+ provider: provider?.trim(),
75
+ model: model?.trim(),
76
+ endpoint: endpoint?.trim(),
77
+ endpointClear: endpointClear || undefined,
78
+ },
79
+ };
80
+ }
81
+ export function parseSetKeyFlags(argv) {
82
+ if (!argv.includes('--set-key')) {
83
+ return { request: null };
84
+ }
85
+ let provider;
86
+ let key;
87
+ for (let i = 0; i < argv.length; i++) {
88
+ const arg = argv[i];
89
+ if (arg === '--provider') {
90
+ provider = argv[i + 1];
91
+ i++;
92
+ }
93
+ else if (arg === '--key') {
94
+ key = argv[i + 1];
95
+ i++;
96
+ }
97
+ }
98
+ if (!provider || provider.trim().length === 0) {
99
+ return { request: null, error: '--set-key requires --provider <id>' };
100
+ }
101
+ if (!key || key.trim().length === 0) {
102
+ return { request: null, error: '--set-key requires --key <secret>' };
103
+ }
104
+ return {
105
+ request: {
106
+ provider: provider.trim(),
107
+ key: key.trim(),
108
+ },
109
+ };
110
+ }
111
+ export function parseDiscoverModelsFlags(argv) {
112
+ if (!argv.includes('--discover-models')) {
113
+ return { provider: null, present: false };
114
+ }
115
+ let provider;
116
+ for (let i = 0; i < argv.length; i++) {
117
+ if (argv[i] === '--provider') {
118
+ provider = argv[i + 1];
119
+ i++;
120
+ }
121
+ }
122
+ return {
123
+ present: true,
124
+ provider: provider?.trim() || null,
125
+ };
126
+ }
127
+ /** Build config snapshot for desktop/settings (no secrets). */
128
+ export function buildDesktopConfigSnapshot() {
129
+ const config = getProviderConfig();
130
+ const providers = PROVIDERS.map((p) => {
131
+ const cached = getCachedModels(p.id);
132
+ const models = cached?.models.map((m) => m.id) ?? [];
133
+ const defaultModel = config.modelByProvider[p.id] ?? '';
134
+ if (defaultModel && !models.includes(defaultModel)) {
135
+ models.unshift(defaultModel);
136
+ }
137
+ const custom = getCustomEndpoint(p.id);
138
+ const builtin = p.baseUrl ?? null;
139
+ return {
140
+ id: p.id,
141
+ displayName: p.displayName,
142
+ hasKey: !!resolveApiKey(p.id),
143
+ envVar: p.envVar,
144
+ models,
145
+ defaultModel,
146
+ endpoint: custom ?? null,
147
+ baseUrl: custom ?? builtin,
148
+ };
149
+ });
150
+ return {
151
+ activeProviderId: config.activeProviderId,
152
+ modelByProvider: { ...config.modelByProvider },
153
+ providers,
154
+ cliVersion: getCurrentVersion(),
155
+ configPaths: {
156
+ provider: getProviderConfigPath(),
157
+ keys: getKeyStorePath(),
158
+ },
159
+ };
160
+ }
161
+ /** Write one JSON object to stdout (pretty for humans, still single payload). */
162
+ export function printDesktopConfig() {
163
+ const snap = buildDesktopConfigSnapshot();
164
+ process.stdout.write(JSON.stringify(snap, null, 2) + '\n');
165
+ }
166
+ /**
167
+ * Persist provider, model, and/or custom endpoint.
168
+ */
169
+ export function applySetConfig(req) {
170
+ try {
171
+ const config = getProviderConfig();
172
+ let targetProvider = (req.provider ?? config.activeProviderId);
173
+ if (req.provider) {
174
+ const exists = PROVIDERS.some((p) => p.id === req.provider);
175
+ if (!exists) {
176
+ return {
177
+ ok: false,
178
+ error: `unknown provider '${req.provider}'. Available: ${PROVIDERS.map((p) => p.id).join(', ')}`,
179
+ };
180
+ }
181
+ setActiveProviderId(req.provider);
182
+ targetProvider = req.provider;
183
+ }
184
+ // Endpoint ops target explicit provider or active; for endpoint-only
185
+ // without --provider, prefer openai-compatible when clearing/setting
186
+ // and user is not targeting a specific provider... actually use targetProvider.
187
+ if (req.endpointClear) {
188
+ clearCustomEndpoint(targetProvider);
189
+ }
190
+ if (req.endpoint) {
191
+ setCustomEndpoint(targetProvider, req.endpoint);
192
+ }
193
+ if (req.model) {
194
+ setModelForProvider(targetProvider, req.model);
195
+ }
196
+ const after = getProviderConfig();
197
+ const ep = getCustomEndpoint(after.activeProviderId);
198
+ return {
199
+ ok: true,
200
+ message: `activeProvider=${after.activeProviderId} ` +
201
+ `model=${after.modelByProvider[after.activeProviderId]}` +
202
+ (ep ? ` endpoint=${ep}` : ''),
203
+ };
204
+ }
205
+ catch (err) {
206
+ return {
207
+ ok: false,
208
+ error: err instanceof Error ? err.message : String(err),
209
+ };
210
+ }
211
+ }
212
+ /** Store API key (never echoes the secret). */
213
+ export function applySetKey(req) {
214
+ try {
215
+ const exists = PROVIDERS.some((p) => p.id === req.provider);
216
+ if (!exists) {
217
+ return {
218
+ ok: false,
219
+ error: `unknown provider '${req.provider}'. Available: ${PROVIDERS.map((p) => p.id).join(', ')}`,
220
+ };
221
+ }
222
+ setApiKey(req.provider, req.key);
223
+ setActiveProviderId(req.provider);
224
+ return {
225
+ ok: true,
226
+ provider: req.provider,
227
+ masked: maskKey(req.key),
228
+ };
229
+ }
230
+ catch (err) {
231
+ return {
232
+ ok: false,
233
+ error: err instanceof Error ? err.message : String(err),
234
+ };
235
+ }
236
+ }
237
+ const DISCOVERABLE = [
238
+ 'grok',
239
+ 'glm',
240
+ 'minimax',
241
+ 'deepseek',
242
+ 'openai-compatible',
243
+ ];
244
+ /** Fetch and cache models; print JSON result. */
245
+ export async function runDiscoverModels(providerArg) {
246
+ const config = getProviderConfig();
247
+ const providerId = (providerArg ?? config.activeProviderId).trim();
248
+ if (!DISCOVERABLE.includes(providerId)) {
249
+ // custom may still work via openai-compatible discovery if mapped — try openai-compatible path
250
+ if (providerId === 'custom') {
251
+ // Fall through using openai-compatible discovery with custom endpoint if set
252
+ }
253
+ else {
254
+ return {
255
+ ok: false,
256
+ error: `provider '${providerId}' is not discoverable. Use: ${DISCOVERABLE.join(', ')}`,
257
+ };
258
+ }
259
+ }
260
+ const discoveryId = (providerId === 'custom' ? 'openai-compatible' : providerId);
261
+ try {
262
+ const entry = await discoverModelsForProvider(discoveryId);
263
+ return {
264
+ ok: true,
265
+ payload: {
266
+ ok: true,
267
+ provider: providerId,
268
+ models: entry.models.map((m) => m.id),
269
+ fetchedAt: entry.fetchedAt,
270
+ baseUrl: entry.baseUrl,
271
+ },
272
+ };
273
+ }
274
+ catch (err) {
275
+ return {
276
+ ok: false,
277
+ error: err instanceof Error ? err.message : String(err),
278
+ };
279
+ }
280
+ }
281
+ //# sourceMappingURL=desktopConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desktopConfig.js","sourceRoot":"","sources":["../../src/cli/desktopConfig.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * headless — non-interactive CLI mode for CI/CD and scripting.
2
+ * headless — non-interactive CLI mode for CI/CD, scripting, and Zelari Desktop.
3
3
  *
4
4
  * Bypasses Ink entirely. Reads `--task <prompt>`, runs the prompt
5
5
  * through the same dispatch path the TUI uses, and serializes the
@@ -17,11 +17,22 @@
17
17
  import { PROVIDERS, resolveApiKeyWithMeta } from './keyStore.js';
18
18
  import { getActiveProvider, getModelForProvider } from './providerConfig.js';
19
19
  import { openaiCompatibleProvider } from './provider/openai-compatible.js';
20
- const HELP_TEXT = `zelari-code --headless --task <prompt> [--output json|plain] [--council] [--provider <id>] [--model <name>]
20
+ import { parsePhase } from './phase.js';
21
+ import { parseMode } from './mode.js';
22
+ const HELP_TEXT = `zelari-code --headless --task <prompt> [options]
21
23
 
22
24
  Non-interactive mode. Streams BrainEvents as NDJSON to stdout (one JSON
23
25
  object per line) or as plain text (just the assistant message text).
24
26
 
27
+ Options:
28
+ --task <text> Task prompt (required)
29
+ --output json|plain Output format (default: json)
30
+ --mode agent|council|zelari Dispatch mode (default: agent)
31
+ --council Alias for --mode council
32
+ --phase plan|build Work phase (default: build)
33
+ --provider <id> Provider override (default: active)
34
+ --model <name> Model override (default: provider default)
35
+
25
36
  Exit codes:
26
37
  0 completed
27
38
  1 user error (bad flags, missing API key, ...)
@@ -38,7 +49,10 @@ export function parseHeadlessFlags(argv) {
38
49
  }
39
50
  let task;
40
51
  let output = 'json';
41
- let useCouncil = false;
52
+ let mode = 'agent';
53
+ let phase = 'build';
54
+ let modeExplicit = false;
55
+ let councilFlag = false;
42
56
  let provider;
43
57
  let model;
44
58
  for (let i = 0; i < argv.length; i++) {
@@ -63,7 +77,32 @@ export function parseHeadlessFlags(argv) {
63
77
  i++;
64
78
  }
65
79
  else if (arg === '--council') {
66
- useCouncil = true;
80
+ councilFlag = true;
81
+ }
82
+ else if (arg === '--mode') {
83
+ const next = argv[i + 1];
84
+ const parsed = next ? parseMode(next) : null;
85
+ if (!parsed) {
86
+ return {
87
+ options: null,
88
+ error: `--mode requires 'agent', 'council', or 'zelari', got '${next ?? '(missing)'}'`,
89
+ };
90
+ }
91
+ mode = parsed;
92
+ modeExplicit = true;
93
+ i++;
94
+ }
95
+ else if (arg === '--phase') {
96
+ const next = argv[i + 1];
97
+ const parsed = next ? parsePhase(next) : null;
98
+ if (!parsed) {
99
+ return {
100
+ options: null,
101
+ error: `--phase requires 'plan' or 'build', got '${next ?? '(missing)'}'`,
102
+ };
103
+ }
104
+ phase = parsed;
105
+ i++;
67
106
  }
68
107
  else if (arg === '--provider') {
69
108
  provider = argv[i + 1];
@@ -74,11 +113,29 @@ export function parseHeadlessFlags(argv) {
74
113
  i++;
75
114
  }
76
115
  }
116
+ // --council is an alias for --mode council when --mode was not set.
117
+ if (councilFlag && !modeExplicit) {
118
+ mode = 'council';
119
+ }
120
+ else if (councilFlag && modeExplicit && mode !== 'council') {
121
+ return {
122
+ options: null,
123
+ error: `--council conflicts with --mode ${mode}`,
124
+ };
125
+ }
77
126
  if (!task || task.trim().length === 0) {
78
127
  return { options: null, error: '--headless requires --task <prompt>' };
79
128
  }
80
129
  return {
81
- options: { task, output, useCouncil, provider, model },
130
+ options: {
131
+ task,
132
+ output,
133
+ mode,
134
+ phase,
135
+ useCouncil: mode === 'council',
136
+ provider,
137
+ model,
138
+ },
82
139
  };
83
140
  }
84
141
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"headless.js","sourceRoot":"","sources":["../../src/cli/headless.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"headless.js","sourceRoot":"","sources":["../../src/cli/headless.ts"],"names":[],"mappings":"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"}
@@ -23,10 +23,17 @@ export function computeSessionStatsDelta(realUsage, userText, assistantContent,
23
23
  // char/4 fallback can't distinguish them, so assume 0 there.
24
24
  const cachedPromptTokens = realUsage?.cachedPromptTokens ?? 0;
25
25
  const turnCost = calculateCost(model, promptTokens, completionTokens, cachedPromptTokens);
26
+ // Context meter = this turn's prompt+completion (provider context window
27
+ // occupancy proxy), NOT the session cumulative total (which always grows
28
+ // and produced absurd "474k/200k" displays).
29
+ const contextTokens = realUsage
30
+ ? realUsage.totalTokens || promptTokens + completionTokens
31
+ : promptTokens + completionTokens;
26
32
  return {
27
33
  totalTokens: prev.totalTokens + promptTokens + completionTokens,
28
34
  totalCostUsd: prev.totalCostUsd + turnCost,
29
35
  cachedTokens: (prev.cachedTokens ?? 0) + cachedPromptTokens,
36
+ contextTokens,
30
37
  };
31
38
  }
32
39
  //# sourceMappingURL=chatStats.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chatStats.js","sourceRoot":"","sources":["../../../src/cli/hooks/chatStats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CACtC,SAKQ,EACR,QAAgB,EAChB,gBAAwB,EACxB,KAAa,EACb,IAA0E;IAE1E,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzF,MAAM,gBAAgB,GAAG,SAAS;QAChC,CAAC,CAAC,SAAS,CAAC,gBAAgB;QAC5B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3C,oEAAoE;IACpE,6DAA6D;IAC7D,MAAM,kBAAkB,GAAG,SAAS,EAAE,kBAAkB,IAAI,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;IAC1F,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,WAAW,GAAG,YAAY,GAAG,gBAAgB;QAC/D,YAAY,EAAE,IAAI,CAAC,YAAY,GAAG,QAAQ;QAC1C,YAAY,EAAE,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,kBAAkB;KAC5D,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"chatStats.js","sourceRoot":"","sources":["../../../src/cli/hooks/chatStats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CACtC,SAKQ,EACR,QAAgB,EAChB,gBAAwB,EACxB,KAAa,EACb,IAMC;IAOD,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzF,MAAM,gBAAgB,GAAG,SAAS;QAChC,CAAC,CAAC,SAAS,CAAC,gBAAgB;QAC5B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3C,oEAAoE;IACpE,6DAA6D;IAC7D,MAAM,kBAAkB,GAAG,SAAS,EAAE,kBAAkB,IAAI,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;IAC1F,yEAAyE;IACzE,yEAAyE;IACzE,6CAA6C;IAC7C,MAAM,aAAa,GAAG,SAAS;QAC7B,CAAC,CAAC,SAAS,CAAC,WAAW,IAAI,YAAY,GAAG,gBAAgB;QAC1D,CAAC,CAAC,YAAY,GAAG,gBAAgB,CAAC;IACpC,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,WAAW,GAAG,YAAY,GAAG,gBAAgB;QAC/D,YAAY,EAAE,IAAI,CAAC,YAAY,GAAG,QAAQ;QAC1C,YAAY,EAAE,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,kBAAkB;QAC3D,aAAa;KACd,CAAC;AACJ,CAAC"}
@@ -311,9 +311,13 @@ export function useChatTurn(params) {
311
311
  default: 25,
312
312
  min: 1,
313
313
  });
314
- // v1.5.2 / v1.8.0: tool-loop cap budget policy may lower under
315
- // context pressure; env still wins as the ceiling via applyBudgetPolicy.
314
+ // v1.5.2 / v1.8.0 / v1.8.3: soft tool-loop + optional hard ceiling.
315
+ // Soft can auto-extend until hard so multi-step work finishes.
316
316
  const maxToolLoopIterations = budget.maxToolLoopIterations;
317
+ const maxToolLoopHardCap = envNumber(process.env.ZELARI_MAX_TOOL_LOOP_HARD, {
318
+ default: 0, // 0 → harness default (soft×3, min soft+60)
319
+ min: 0,
320
+ });
317
321
  const harness = new AgentHarness({
318
322
  model: envConfig.model,
319
323
  provider: "openai-compatible",
@@ -335,6 +339,7 @@ export function useChatTurn(params) {
335
339
  cwd,
336
340
  maxToolCallsPerTurn,
337
341
  maxToolLoopIterations,
342
+ ...(maxToolLoopHardCap > 0 ? { maxToolLoopHardCap } : {}),
338
343
  });
339
344
  harnessRef.current = harness;
340
345
  setQueueCount(harness.queueLength);
@@ -429,7 +434,13 @@ export function useChatTurn(params) {
429
434
  }
430
435
  else if (event.type === "error") {
431
436
  flushStreaming();
432
- appendSystem(setMessages, `[error] ${event.message}`, Date.now());
437
+ // Budget extension is informational, not a hard error.
438
+ if (event.code === "tool_budget_extended") {
439
+ appendSystem(setMessages, `[budget] ${event.message}`, Date.now());
440
+ }
441
+ else {
442
+ appendSystem(setMessages, `[error] ${event.message}`, Date.now());
443
+ }
433
444
  }
434
445
  else if (event.type === "tool_execution_start") {
435
446
  toolNameById.set(event.toolCallId, event.toolName);