zelari-code 1.17.1 → 1.18.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/dist/cli/browser/driver.js +133 -3
- package/dist/cli/browser/driver.js.map +1 -1
- package/dist/cli/browser/tools.js +60 -11
- package/dist/cli/browser/tools.js.map +1 -1
- package/dist/cli/main.bundled.js +487 -19
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +13 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/plugins/cliFlags.js +91 -0
- package/dist/cli/plugins/cliFlags.js.map +1 -0
- package/dist/cli/plugins/installer.js +73 -11
- package/dist/cli/plugins/installer.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -18415,6 +18415,7 @@ Earlier members' outputs are shared context. Build on them; do not re-derive or
|
|
|
18415
18415
|
- Pass complete, valid arguments. Required parameters must be present.
|
|
18416
18416
|
- Prefer tools over asking the user to paste file contents.
|
|
18417
18417
|
- After durable changes, briefly name what you created or modified.
|
|
18418
|
+
- **Act, don't narrate**: if you will edit/fix files, call the tools in this turn. Do not restate the same diagnosis or "I will fix\u2026" plan on a loop without tool calls.
|
|
18418
18419
|
- Text-only tool blocks (\`---TOOLS---\` JSON) are a legacy fallback \u2014 use them only if the runtime has no native tool channel.`
|
|
18419
18420
|
};
|
|
18420
18421
|
CODING_PRACTICES_MODULE = {
|
|
@@ -18429,7 +18430,9 @@ Earlier members' outputs are shared context. Build on them; do not re-derive or
|
|
|
18429
18430
|
- **Don't invent**: no fake APIs, deps, or config keys \u2014 discover from the tree or package manifests.
|
|
18430
18431
|
- **Verify**: after non-trivial edits, run the project's tests/typecheck/build when available; fix failures you introduced.
|
|
18431
18432
|
- **Use project scripts**: prefer package.json / Makefile / existing tooling over ad-hoc commands.
|
|
18432
|
-
- **Finish**: list the paths you wrote/edited and how to verify. If you wrote nothing, say so honestly \u2014 do not invent a done report
|
|
18433
|
+
- **Finish**: list the paths you wrote/edited and how to verify. If you wrote nothing, say so honestly \u2014 do not invent a done report.
|
|
18434
|
+
- **No spam**: never repeat the same paragraph or status line. One diagnosis, then tools (or one short final answer).
|
|
18435
|
+
- **Browser smoke honesty**: with \`browser_check\`, prefer \`waitForSelector\` / \`waitForText\` / \`evaluate\` on DOM (or explicit test hooks). Do not claim a logic fix is verified from \u201Cno console errors after N seconds\u201D alone (\`smokeStrength: weak\`). ES modules keep symbols off \`window\` \u2014 do not loop on exposing globals; assert visible UI or inject \`evaluate\` on \`document\`.`
|
|
18433
18436
|
};
|
|
18434
18437
|
CLARIFICATION_PROTOCOL_MODULE = {
|
|
18435
18438
|
type: "custom",
|
|
@@ -19124,6 +19127,159 @@ var init_events = __esm({
|
|
|
19124
19127
|
}
|
|
19125
19128
|
});
|
|
19126
19129
|
|
|
19130
|
+
// packages/core/dist/core/textLoopDetect.js
|
|
19131
|
+
function normalizeLoopUnit(s) {
|
|
19132
|
+
return s.replace(/<\/?small>/gi, "").replace(/<\/?(?:p|div|span|b|i|em|strong|br)\b[^>]*>/gi, "").replace(/\s+/g, " ").trim();
|
|
19133
|
+
}
|
|
19134
|
+
function detectChunkSequenceLoop(chunks, kind) {
|
|
19135
|
+
if (chunks.length < MIN_REPEATS)
|
|
19136
|
+
return { looping: false };
|
|
19137
|
+
const maxK = Math.min(12, Math.floor(chunks.length / MIN_REPEATS));
|
|
19138
|
+
for (let k = 1; k <= maxK; k++) {
|
|
19139
|
+
const unitParts = chunks.slice(chunks.length - k);
|
|
19140
|
+
const unitKey = unitParts.join("\n");
|
|
19141
|
+
if (normalizeLoopUnit(unitKey).length < MIN_UNIT)
|
|
19142
|
+
continue;
|
|
19143
|
+
let count = 1;
|
|
19144
|
+
let pos = chunks.length - k;
|
|
19145
|
+
while (pos - k >= 0) {
|
|
19146
|
+
const prev2 = chunks.slice(pos - k, pos);
|
|
19147
|
+
let same = true;
|
|
19148
|
+
for (let i = 0; i < k; i++) {
|
|
19149
|
+
if (prev2[i] !== unitParts[i]) {
|
|
19150
|
+
same = false;
|
|
19151
|
+
break;
|
|
19152
|
+
}
|
|
19153
|
+
}
|
|
19154
|
+
if (!same)
|
|
19155
|
+
break;
|
|
19156
|
+
count++;
|
|
19157
|
+
pos -= k;
|
|
19158
|
+
}
|
|
19159
|
+
if (count >= MIN_REPEATS) {
|
|
19160
|
+
return {
|
|
19161
|
+
looping: true,
|
|
19162
|
+
unit: unitKey,
|
|
19163
|
+
count,
|
|
19164
|
+
kind
|
|
19165
|
+
};
|
|
19166
|
+
}
|
|
19167
|
+
}
|
|
19168
|
+
return { looping: false };
|
|
19169
|
+
}
|
|
19170
|
+
function detectSuffixPeriod(text) {
|
|
19171
|
+
const compact = text.replace(/\s+/g, " ").trim();
|
|
19172
|
+
if (compact.length < MIN_UNIT * MIN_REPEATS)
|
|
19173
|
+
return { looping: false };
|
|
19174
|
+
const tail = compact.slice(-Math.min(compact.length, MAX_TAIL));
|
|
19175
|
+
const maxP = Math.min(MAX_PERIOD, Math.floor(tail.length / MIN_REPEATS));
|
|
19176
|
+
for (let period = MIN_UNIT; period <= maxP; period++) {
|
|
19177
|
+
const need = period * MIN_REPEATS;
|
|
19178
|
+
if (tail.length < need)
|
|
19179
|
+
continue;
|
|
19180
|
+
const unit = tail.slice(tail.length - period);
|
|
19181
|
+
if (normalizeLoopUnit(unit).length < MIN_UNIT * 0.55)
|
|
19182
|
+
continue;
|
|
19183
|
+
let ok = true;
|
|
19184
|
+
for (let r = 1; r < MIN_REPEATS; r++) {
|
|
19185
|
+
const start = tail.length - period * (r + 1);
|
|
19186
|
+
if (tail.slice(start, start + period) !== unit) {
|
|
19187
|
+
ok = false;
|
|
19188
|
+
break;
|
|
19189
|
+
}
|
|
19190
|
+
}
|
|
19191
|
+
if (!ok)
|
|
19192
|
+
continue;
|
|
19193
|
+
let count = MIN_REPEATS;
|
|
19194
|
+
let end = tail.length - period * MIN_REPEATS;
|
|
19195
|
+
while (end >= period && tail.slice(end - period, end) === unit) {
|
|
19196
|
+
count++;
|
|
19197
|
+
end -= period;
|
|
19198
|
+
}
|
|
19199
|
+
return {
|
|
19200
|
+
looping: true,
|
|
19201
|
+
unit,
|
|
19202
|
+
count,
|
|
19203
|
+
kind: "suffix"
|
|
19204
|
+
};
|
|
19205
|
+
}
|
|
19206
|
+
return { looping: false };
|
|
19207
|
+
}
|
|
19208
|
+
function detectAssistantTextLoop(text) {
|
|
19209
|
+
if (!text || text.length < MIN_UNIT * MIN_REPEATS) {
|
|
19210
|
+
return { looping: false };
|
|
19211
|
+
}
|
|
19212
|
+
const nl = text.replace(/\r\n/g, "\n");
|
|
19213
|
+
const paragraphs = nl.split(/\n\s*\n+/).map((p3) => normalizeLoopUnit(p3)).filter((p3) => p3.length > 0);
|
|
19214
|
+
const paraHit = detectChunkSequenceLoop(paragraphs, "paragraph");
|
|
19215
|
+
if (paraHit.looping)
|
|
19216
|
+
return paraHit;
|
|
19217
|
+
const lines = nl.split("\n").map((l) => normalizeLoopUnit(l)).filter((l) => l.length > 0);
|
|
19218
|
+
const lineHit = detectChunkSequenceLoop(lines, "line");
|
|
19219
|
+
if (lineHit.looping)
|
|
19220
|
+
return lineHit;
|
|
19221
|
+
return detectSuffixPeriod(nl);
|
|
19222
|
+
}
|
|
19223
|
+
function collapseLoopedAssistantText(text) {
|
|
19224
|
+
const hit = detectAssistantTextLoop(text);
|
|
19225
|
+
if (!hit.looping)
|
|
19226
|
+
return text;
|
|
19227
|
+
const note = `
|
|
19228
|
+
|
|
19229
|
+
[system: stopped repeating the same text \xD7${hit.count}; call tools or finish.]`;
|
|
19230
|
+
if (hit.kind === "paragraph" || hit.kind === "line") {
|
|
19231
|
+
const joinSep = hit.kind === "paragraph" ? "\n\n" : "\n";
|
|
19232
|
+
const unitParts = hit.unit.split("\n").map((p3) => normalizeLoopUnit(p3));
|
|
19233
|
+
const k = unitParts.length;
|
|
19234
|
+
if (k === 0)
|
|
19235
|
+
return text + note;
|
|
19236
|
+
const rawParts = text.replace(/\r\n/g, "\n").split(hit.kind === "paragraph" ? /\n\s*\n+/ : /\n/).filter((p3) => normalizeLoopUnit(p3).length > 0);
|
|
19237
|
+
if (rawParts.length < k * MIN_REPEATS) {
|
|
19238
|
+
return collapseByCharBudget(text, hit.unit, hit.count) + note;
|
|
19239
|
+
}
|
|
19240
|
+
let trailBlocks = 0;
|
|
19241
|
+
let pos = rawParts.length;
|
|
19242
|
+
while (pos >= k) {
|
|
19243
|
+
let same = true;
|
|
19244
|
+
for (let i = 0; i < k; i++) {
|
|
19245
|
+
if (normalizeLoopUnit(rawParts[pos - k + i]) !== unitParts[i]) {
|
|
19246
|
+
same = false;
|
|
19247
|
+
break;
|
|
19248
|
+
}
|
|
19249
|
+
}
|
|
19250
|
+
if (!same)
|
|
19251
|
+
break;
|
|
19252
|
+
trailBlocks++;
|
|
19253
|
+
pos -= k;
|
|
19254
|
+
}
|
|
19255
|
+
if (trailBlocks < MIN_REPEATS) {
|
|
19256
|
+
return collapseByCharBudget(text, hit.unit, hit.count) + note;
|
|
19257
|
+
}
|
|
19258
|
+
const keepBlocks = 2;
|
|
19259
|
+
const keepParts = rawParts.slice(0, rawParts.length - k * (trailBlocks - keepBlocks));
|
|
19260
|
+
return keepParts.join(joinSep).trimEnd() + note;
|
|
19261
|
+
}
|
|
19262
|
+
return collapseByCharBudget(text, hit.unit, hit.count) + note;
|
|
19263
|
+
}
|
|
19264
|
+
function collapseByCharBudget(text, unit, count) {
|
|
19265
|
+
const unitLen = Math.max(unit.length, MIN_UNIT);
|
|
19266
|
+
if (count < MIN_REPEATS)
|
|
19267
|
+
return text;
|
|
19268
|
+
const drop = unitLen * (count - 2);
|
|
19269
|
+
const cut = Math.max(0, text.length - drop);
|
|
19270
|
+
return text.slice(0, cut).trimEnd();
|
|
19271
|
+
}
|
|
19272
|
+
var MIN_UNIT, MIN_REPEATS, MAX_TAIL, MAX_PERIOD;
|
|
19273
|
+
var init_textLoopDetect = __esm({
|
|
19274
|
+
"packages/core/dist/core/textLoopDetect.js"() {
|
|
19275
|
+
"use strict";
|
|
19276
|
+
MIN_UNIT = 48;
|
|
19277
|
+
MIN_REPEATS = 3;
|
|
19278
|
+
MAX_TAIL = 6e3;
|
|
19279
|
+
MAX_PERIOD = 600;
|
|
19280
|
+
}
|
|
19281
|
+
});
|
|
19282
|
+
|
|
19127
19283
|
// packages/core/dist/core/AgentHarness.js
|
|
19128
19284
|
function hashToolCall(toolName, args) {
|
|
19129
19285
|
const canonical = stableStringify(args);
|
|
@@ -19362,6 +19518,8 @@ var init_AgentHarness = __esm({
|
|
|
19362
19518
|
"packages/core/dist/core/AgentHarness.js"() {
|
|
19363
19519
|
"use strict";
|
|
19364
19520
|
init_events();
|
|
19521
|
+
init_textLoopDetect();
|
|
19522
|
+
init_textLoopDetect();
|
|
19365
19523
|
AgentHarness = class {
|
|
19366
19524
|
config;
|
|
19367
19525
|
eventBus;
|
|
@@ -19811,6 +19969,7 @@ ${shared2.content}`,
|
|
|
19811
19969
|
const turnToolCalls = [];
|
|
19812
19970
|
const turnToolResults = [];
|
|
19813
19971
|
const pendingNativeTools = [];
|
|
19972
|
+
let lastLoopCheckLen = 0;
|
|
19814
19973
|
for await (const delta of stream) {
|
|
19815
19974
|
if (this.cancelled) {
|
|
19816
19975
|
const cancelEvent = createBrainEvent("error", this.sessionId, {
|
|
@@ -19827,6 +19986,29 @@ ${shared2.content}`,
|
|
|
19827
19986
|
const deltaEvent = createBrainEvent("message_delta", this.sessionId, { messageId, delta: delta.delta, ...this.memberFields() });
|
|
19828
19987
|
this.emit(deltaEvent);
|
|
19829
19988
|
yield deltaEvent;
|
|
19989
|
+
if (turnText.length >= 48 * 3 && turnText.length - lastLoopCheckLen >= 48) {
|
|
19990
|
+
lastLoopCheckLen = turnText.length;
|
|
19991
|
+
const loopHit = detectAssistantTextLoop(turnText);
|
|
19992
|
+
if (loopHit.looping) {
|
|
19993
|
+
const loopErr = createBrainEvent("error", this.sessionId, {
|
|
19994
|
+
severity: "recoverable",
|
|
19995
|
+
message: `Assistant text loop detected (same block \xD7${loopHit.count}). Stopped generation \u2014 model was repeating instead of calling tools or finishing. Retry or ask it to apply changes with tools.`,
|
|
19996
|
+
code: "assistant_text_loop"
|
|
19997
|
+
});
|
|
19998
|
+
this.emit(loopErr);
|
|
19999
|
+
yield loopErr;
|
|
20000
|
+
finishRef.value = "stop";
|
|
20001
|
+
const sealed = collapseLoopedAssistantText(turnText);
|
|
20002
|
+
if (sealed.length > 0 || turnReasoning.length > 0) {
|
|
20003
|
+
this.config.messages.push({
|
|
20004
|
+
role: "assistant",
|
|
20005
|
+
content: sealed,
|
|
20006
|
+
...turnReasoning.length > 0 ? { reasoningContent: turnReasoning } : {}
|
|
20007
|
+
});
|
|
20008
|
+
}
|
|
20009
|
+
break;
|
|
20010
|
+
}
|
|
20011
|
+
}
|
|
19830
20012
|
} else if (delta.kind === "thinking") {
|
|
19831
20013
|
turnReasoning += delta.delta;
|
|
19832
20014
|
const thinkEvent = createBrainEvent("thinking_delta", this.sessionId, {
|
|
@@ -20247,7 +20429,10 @@ var harness_exports = {};
|
|
|
20247
20429
|
__export(harness_exports, {
|
|
20248
20430
|
AgentHarness: () => AgentHarness,
|
|
20249
20431
|
SessionJsonlWriter: () => SessionJsonlWriter,
|
|
20432
|
+
collapseLoopedAssistantText: () => collapseLoopedAssistantText,
|
|
20433
|
+
detectAssistantTextLoop: () => detectAssistantTextLoop,
|
|
20250
20434
|
hashToolCall: () => hashToolCall,
|
|
20435
|
+
normalizeLoopUnit: () => normalizeLoopUnit,
|
|
20251
20436
|
normalizeTextToolArgs: () => normalizeTextToolArgs,
|
|
20252
20437
|
parseMinimaxStyleToolCalls: () => parseMinimaxStyleToolCalls,
|
|
20253
20438
|
parseTextToolCalls: () => parseTextToolCalls,
|
|
@@ -22439,21 +22624,53 @@ async function loadPlaywright(cwd) {
|
|
|
22439
22624
|
return null;
|
|
22440
22625
|
}
|
|
22441
22626
|
}
|
|
22627
|
+
function serializeEvaluateValue(value) {
|
|
22628
|
+
try {
|
|
22629
|
+
const json2 = JSON.stringify(value, (_k, v) => {
|
|
22630
|
+
if (typeof v === "function") return "[Function]";
|
|
22631
|
+
if (typeof v === "bigint") return v.toString();
|
|
22632
|
+
if (v instanceof Error) return { name: v.name, message: v.message };
|
|
22633
|
+
return v;
|
|
22634
|
+
});
|
|
22635
|
+
if (json2 === void 0) return null;
|
|
22636
|
+
if (json2.length > MAX_EVAL_RESULT) {
|
|
22637
|
+
return {
|
|
22638
|
+
truncated: true,
|
|
22639
|
+
preview: json2.slice(0, MAX_EVAL_RESULT)
|
|
22640
|
+
};
|
|
22641
|
+
}
|
|
22642
|
+
return JSON.parse(json2);
|
|
22643
|
+
} catch (err) {
|
|
22644
|
+
return {
|
|
22645
|
+
error: `non-serializable: ${err instanceof Error ? err.message : String(err)}`
|
|
22646
|
+
};
|
|
22647
|
+
}
|
|
22648
|
+
}
|
|
22649
|
+
function wrapEvaluateExpression(expression) {
|
|
22650
|
+
const expr = expression.trim();
|
|
22651
|
+
if (!expr) return "return undefined";
|
|
22652
|
+
if (/\breturn\b/.test(expr) || expr.includes("\n")) {
|
|
22653
|
+
return expr;
|
|
22654
|
+
}
|
|
22655
|
+
return `return (${expr})`;
|
|
22656
|
+
}
|
|
22442
22657
|
async function runBrowserCheck(options, loader) {
|
|
22443
22658
|
const consoleErrors = [];
|
|
22444
22659
|
const pageErrors = [];
|
|
22445
22660
|
const failedRequests = [];
|
|
22661
|
+
const evaluateResults = [];
|
|
22446
22662
|
const base = { ok: false, consoleErrors, pageErrors, failedRequests };
|
|
22447
22663
|
const resolve = loader ?? (() => loadPlaywright(options.cwd ?? process.cwd()));
|
|
22448
22664
|
const pw = await resolve();
|
|
22449
22665
|
if (!pw) {
|
|
22450
22666
|
return {
|
|
22451
22667
|
...base,
|
|
22452
|
-
error: "browser automation unavailable \u2014 install
|
|
22668
|
+
error: "browser automation unavailable \u2014 Playwright is not installed in this workspace. Install it with: `zelari-code --plugins-install playwright --cwd .` (or Desktop banner \u201CInstall\u201D, or CLI `/plugins install playwright`, or `npm i -D playwright && npx playwright install chromium`). Then re-run browser_check."
|
|
22453
22669
|
};
|
|
22454
22670
|
}
|
|
22455
22671
|
const timeout = options.timeoutMs ?? 15e3;
|
|
22456
22672
|
let browser;
|
|
22673
|
+
let textFound;
|
|
22457
22674
|
try {
|
|
22458
22675
|
browser = await pw.chromium.launch({ headless: true });
|
|
22459
22676
|
const page = await browser.newPage();
|
|
@@ -22480,6 +22697,63 @@ async function runBrowserCheck(options, loader) {
|
|
|
22480
22697
|
case "wait":
|
|
22481
22698
|
await page.waitForTimeout(action.ms);
|
|
22482
22699
|
break;
|
|
22700
|
+
case "press": {
|
|
22701
|
+
const key = action.key.trim();
|
|
22702
|
+
if (!key) break;
|
|
22703
|
+
if (page.keyboard && typeof page.keyboard.press === "function") {
|
|
22704
|
+
await page.keyboard.press(key, { timeout });
|
|
22705
|
+
} else {
|
|
22706
|
+
await page.evaluate(
|
|
22707
|
+
wrapEvaluateExpression(
|
|
22708
|
+
`document.dispatchEvent(new KeyboardEvent('keydown',{key:${JSON.stringify(key)},bubbles:true})); true`
|
|
22709
|
+
)
|
|
22710
|
+
);
|
|
22711
|
+
}
|
|
22712
|
+
break;
|
|
22713
|
+
}
|
|
22714
|
+
case "waitForText": {
|
|
22715
|
+
const needle = action.text;
|
|
22716
|
+
const t = action.timeoutMs ?? timeout;
|
|
22717
|
+
try {
|
|
22718
|
+
await page.waitForFunction(
|
|
22719
|
+
`return (document.body && (document.body.innerText || document.body.textContent || '')).includes(arguments[0])`,
|
|
22720
|
+
needle,
|
|
22721
|
+
{ timeout: t }
|
|
22722
|
+
);
|
|
22723
|
+
textFound = textFound === false ? false : true;
|
|
22724
|
+
} catch {
|
|
22725
|
+
textFound = false;
|
|
22726
|
+
}
|
|
22727
|
+
break;
|
|
22728
|
+
}
|
|
22729
|
+
case "evaluate": {
|
|
22730
|
+
const raw = action.expression ?? "";
|
|
22731
|
+
if (raw.length > MAX_EVAL_EXPR) {
|
|
22732
|
+
evaluateResults.push({
|
|
22733
|
+
expression: raw.slice(0, 120) + "\u2026",
|
|
22734
|
+
error: `expression too long (max ${MAX_EVAL_EXPR} chars)`
|
|
22735
|
+
});
|
|
22736
|
+
break;
|
|
22737
|
+
}
|
|
22738
|
+
if (!raw.trim()) {
|
|
22739
|
+
evaluateResults.push({ expression: raw, error: "empty expression" });
|
|
22740
|
+
break;
|
|
22741
|
+
}
|
|
22742
|
+
try {
|
|
22743
|
+
const wrapped = wrapEvaluateExpression(raw);
|
|
22744
|
+
const value = await page.evaluate(wrapped);
|
|
22745
|
+
evaluateResults.push({
|
|
22746
|
+
expression: raw.length > 200 ? raw.slice(0, 200) + "\u2026" : raw,
|
|
22747
|
+
value: serializeEvaluateValue(value)
|
|
22748
|
+
});
|
|
22749
|
+
} catch (err) {
|
|
22750
|
+
evaluateResults.push({
|
|
22751
|
+
expression: raw.length > 200 ? raw.slice(0, 200) + "\u2026" : raw,
|
|
22752
|
+
error: err instanceof Error ? err.message : String(err)
|
|
22753
|
+
});
|
|
22754
|
+
}
|
|
22755
|
+
break;
|
|
22756
|
+
}
|
|
22483
22757
|
default:
|
|
22484
22758
|
break;
|
|
22485
22759
|
}
|
|
@@ -22493,6 +22767,20 @@ async function runBrowserCheck(options, loader) {
|
|
|
22493
22767
|
selectorFound = false;
|
|
22494
22768
|
}
|
|
22495
22769
|
}
|
|
22770
|
+
let bodyTextSnippet;
|
|
22771
|
+
if (options.textSample) {
|
|
22772
|
+
try {
|
|
22773
|
+
const text = await page.evaluate(
|
|
22774
|
+
wrapEvaluateExpression(
|
|
22775
|
+
`(document.body?.innerText || document.body?.textContent || '').trim()`
|
|
22776
|
+
)
|
|
22777
|
+
);
|
|
22778
|
+
if (typeof text === "string" && text.length > 0) {
|
|
22779
|
+
bodyTextSnippet = text.length > MAX_BODY_SNIPPET ? text.slice(0, MAX_BODY_SNIPPET) + "\u2026" : text;
|
|
22780
|
+
}
|
|
22781
|
+
} catch {
|
|
22782
|
+
}
|
|
22783
|
+
}
|
|
22496
22784
|
let screenshotPath;
|
|
22497
22785
|
if (options.screenshotPath) {
|
|
22498
22786
|
try {
|
|
@@ -22510,6 +22798,9 @@ async function runBrowserCheck(options, loader) {
|
|
|
22510
22798
|
url: page.url(),
|
|
22511
22799
|
...title !== void 0 ? { title } : {},
|
|
22512
22800
|
...selectorFound !== void 0 ? { selectorFound } : {},
|
|
22801
|
+
...evaluateResults.length > 0 ? { evaluateResults } : {},
|
|
22802
|
+
...textFound !== void 0 ? { textFound } : {},
|
|
22803
|
+
...bodyTextSnippet !== void 0 ? { bodyTextSnippet } : {},
|
|
22513
22804
|
...screenshotPath ? { screenshotPath } : {}
|
|
22514
22805
|
};
|
|
22515
22806
|
} catch (err) {
|
|
@@ -22521,9 +22812,13 @@ async function runBrowserCheck(options, loader) {
|
|
|
22521
22812
|
}
|
|
22522
22813
|
}
|
|
22523
22814
|
}
|
|
22815
|
+
var MAX_EVAL_EXPR, MAX_EVAL_RESULT, MAX_BODY_SNIPPET;
|
|
22524
22816
|
var init_driver = __esm({
|
|
22525
22817
|
"src/cli/browser/driver.ts"() {
|
|
22526
22818
|
"use strict";
|
|
22819
|
+
MAX_EVAL_EXPR = 4e3;
|
|
22820
|
+
MAX_EVAL_RESULT = 8e3;
|
|
22821
|
+
MAX_BODY_SNIPPET = 2e3;
|
|
22527
22822
|
}
|
|
22528
22823
|
});
|
|
22529
22824
|
|
|
@@ -22533,15 +22828,16 @@ import os7 from "node:os";
|
|
|
22533
22828
|
function createBrowserTool(deps = {}) {
|
|
22534
22829
|
return {
|
|
22535
22830
|
name: "browser_check",
|
|
22536
|
-
description:
|
|
22831
|
+
description: "Open a URL in a headless browser to VERIFY a web change: optionally run click/fill/goto/wait/press/waitForText/evaluate actions, then report console errors, uncaught page exceptions, failed network requests, final title/URL, selector/text presence, evaluate results, and a screenshot path. Prefer DOM assertions (waitForSelector, waitForText, evaluate on document.querySelector) over window.* globals \u2014 ES modules and const keep symbols off window. Absence of console errors after a short wait is WEAK smoke only; assert UI state when claiming a fix is verified. Requires Playwright (optional dependency).",
|
|
22537
22832
|
permissions: ["network"],
|
|
22538
22833
|
// A browser launch + navigation can take a while.
|
|
22539
22834
|
timeoutMs: 6e4,
|
|
22540
22835
|
inputSchema: external_exports.object({
|
|
22541
22836
|
url: external_exports.string().min(1).describe("URL to open (e.g. http://localhost:3000)."),
|
|
22542
|
-
actions: external_exports.array(ActionSchema).optional().describe("Optional sequence of interactions before checking."),
|
|
22837
|
+
actions: external_exports.array(ActionSchema).optional().describe("Optional sequence of interactions / probes before checking."),
|
|
22543
22838
|
waitForSelector: external_exports.string().optional().describe("Assert this CSS selector is present after actions."),
|
|
22544
|
-
screenshot: external_exports.boolean().optional().describe("Save a screenshot (default true).")
|
|
22839
|
+
screenshot: external_exports.boolean().optional().describe("Save a screenshot (default true)."),
|
|
22840
|
+
textSample: external_exports.boolean().optional().describe("Include a short body.innerText snippet (HUD / Game Over text).")
|
|
22545
22841
|
}),
|
|
22546
22842
|
execute: async (args, ctx) => {
|
|
22547
22843
|
const a = args;
|
|
@@ -22553,14 +22849,17 @@ function createBrowserTool(deps = {}) {
|
|
|
22553
22849
|
cwd: ctx.cwd,
|
|
22554
22850
|
...a.actions ? { actions: a.actions } : {},
|
|
22555
22851
|
...a.waitForSelector ? { waitForSelector: a.waitForSelector } : {},
|
|
22556
|
-
...screenshotPath ? { screenshotPath } : {}
|
|
22852
|
+
...screenshotPath ? { screenshotPath } : {},
|
|
22853
|
+
...a.textSample ? { textSample: true } : {}
|
|
22557
22854
|
},
|
|
22558
22855
|
deps.loader
|
|
22559
22856
|
);
|
|
22560
22857
|
if (!result.ok) {
|
|
22561
22858
|
return typedOk({ ok: false, note: result.error ?? "browser check failed" });
|
|
22562
22859
|
}
|
|
22563
|
-
const clean = result.consoleErrors.length === 0 && result.pageErrors.length === 0 && result.failedRequests.length === 0 && result.selectorFound !== false;
|
|
22860
|
+
const clean = result.consoleErrors.length === 0 && result.pageErrors.length === 0 && result.failedRequests.length === 0 && result.selectorFound !== false && result.textFound !== false;
|
|
22861
|
+
const hadDomAssertion = result.selectorFound !== void 0 || result.textFound !== void 0 || result.evaluateResults !== void 0 && result.evaluateResults.length > 0 || !!result.bodyTextSnippet;
|
|
22862
|
+
const onlyWeakSmoke = clean && !hadDomAssertion;
|
|
22564
22863
|
return typedOk({
|
|
22565
22864
|
ok: true,
|
|
22566
22865
|
clean,
|
|
@@ -22570,7 +22869,14 @@ function createBrowserTool(deps = {}) {
|
|
|
22570
22869
|
pageErrors: result.pageErrors,
|
|
22571
22870
|
failedRequests: result.failedRequests,
|
|
22572
22871
|
...result.selectorFound !== void 0 ? { selectorFound: result.selectorFound } : {},
|
|
22573
|
-
...result.
|
|
22872
|
+
...result.evaluateResults ? { evaluateResults: result.evaluateResults } : {},
|
|
22873
|
+
...result.textFound !== void 0 ? { textFound: result.textFound } : {},
|
|
22874
|
+
...result.bodyTextSnippet ? { bodyTextSnippet: result.bodyTextSnippet } : {},
|
|
22875
|
+
...result.screenshotPath ? { screenshotPath: result.screenshotPath } : {},
|
|
22876
|
+
...onlyWeakSmoke ? {
|
|
22877
|
+
note: "Weak smoke only: no selector/text/evaluate assertions. No console/page errors is necessary but not sufficient to claim a logic fix. Add waitForSelector, waitForText, or evaluate (DOM/read hooks) for stronger evidence.",
|
|
22878
|
+
smokeStrength: "weak"
|
|
22879
|
+
} : { smokeStrength: "asserted" }
|
|
22574
22880
|
});
|
|
22575
22881
|
}
|
|
22576
22882
|
};
|
|
@@ -22586,7 +22892,22 @@ var init_tools5 = __esm({
|
|
|
22586
22892
|
external_exports.object({ type: external_exports.literal("click"), selector: external_exports.string().min(1) }),
|
|
22587
22893
|
external_exports.object({ type: external_exports.literal("fill"), selector: external_exports.string().min(1), value: external_exports.string() }),
|
|
22588
22894
|
external_exports.object({ type: external_exports.literal("wait"), ms: external_exports.number().int().positive().max(3e4) }),
|
|
22589
|
-
external_exports.object({ type: external_exports.literal("goto"), url: external_exports.string().min(1) })
|
|
22895
|
+
external_exports.object({ type: external_exports.literal("goto"), url: external_exports.string().min(1) }),
|
|
22896
|
+
external_exports.object({
|
|
22897
|
+
type: external_exports.literal("evaluate"),
|
|
22898
|
+
expression: external_exports.string().min(1).max(4e3).describe(
|
|
22899
|
+
"JS expression or statements run in the page (page.evaluate). Prefer DOM reads (document.querySelector\u2026), not assuming window.game exists. Return JSON-safe values."
|
|
22900
|
+
)
|
|
22901
|
+
}),
|
|
22902
|
+
external_exports.object({
|
|
22903
|
+
type: external_exports.literal("press"),
|
|
22904
|
+
key: external_exports.string().min(1).describe('Playwright key name, e.g. "Space", "KeyW", "ArrowLeft", "Enter".')
|
|
22905
|
+
}),
|
|
22906
|
+
external_exports.object({
|
|
22907
|
+
type: external_exports.literal("waitForText"),
|
|
22908
|
+
text: external_exports.string().min(1).describe("Substring that must appear in document body text."),
|
|
22909
|
+
timeoutMs: external_exports.number().int().positive().max(6e4).optional()
|
|
22910
|
+
})
|
|
22590
22911
|
]);
|
|
22591
22912
|
}
|
|
22592
22913
|
});
|
|
@@ -39277,18 +39598,65 @@ import { spawn as spawn10 } from "node:child_process";
|
|
|
39277
39598
|
async function installPlugin(spec, cwd, executor = spawn10) {
|
|
39278
39599
|
const scopeFlag = spec.installScope === "global" ? "-g" : "-D";
|
|
39279
39600
|
const args = ["install", scopeFlag, spec.npmPackage];
|
|
39280
|
-
|
|
39281
|
-
if (
|
|
39282
|
-
|
|
39283
|
-
|
|
39284
|
-
|
|
39285
|
-
|
|
39286
|
-
|
|
39287
|
-
|
|
39601
|
+
let result = await runNpm2(executor, args, cwd, "shim");
|
|
39602
|
+
if (!result.ok) {
|
|
39603
|
+
const npmCli = resolveBundledNpmCli();
|
|
39604
|
+
if (npmCli && looksLikeBrokenShim(result.exitCode, result.output)) {
|
|
39605
|
+
const fallback = await runNpm2(executor, args, cwd, "bundled", npmCli);
|
|
39606
|
+
result = {
|
|
39607
|
+
...fallback,
|
|
39608
|
+
output: `[plugins] npm shim failed (${result.error ?? "exit " + result.exitCode}); retried via bundled npm (${npmCli}).
|
|
39288
39609
|
${fallback.output}`
|
|
39610
|
+
};
|
|
39611
|
+
}
|
|
39612
|
+
}
|
|
39613
|
+
if (!result.ok) return result;
|
|
39614
|
+
if (spec.id === "playwright") {
|
|
39615
|
+
const browsers = await runPlaywrightInstallChromium(cwd, executor);
|
|
39616
|
+
result = {
|
|
39617
|
+
...result,
|
|
39618
|
+
ok: browsers.ok ? true : result.ok,
|
|
39619
|
+
// Prefer package success even if browser download fails — surface both.
|
|
39620
|
+
output: (result.output ? result.output + "\n" : "") + (browsers.output ? `[playwright browsers]
|
|
39621
|
+
${browsers.output}` : "") + (browsers.ok ? "" : `
|
|
39622
|
+
[playwright] Chromium install failed: ${browsers.error ?? "unknown"}. Run: npx playwright install chromium`),
|
|
39623
|
+
error: browsers.ok ? result.error : result.error ?? `playwright package installed but Chromium download failed: ${browsers.error ?? "unknown"}`
|
|
39289
39624
|
};
|
|
39625
|
+
result = { ...result, ok: true };
|
|
39290
39626
|
}
|
|
39291
|
-
return
|
|
39627
|
+
return result;
|
|
39628
|
+
}
|
|
39629
|
+
function runPlaywrightInstallChromium(cwd, executor) {
|
|
39630
|
+
return new Promise((resolve) => {
|
|
39631
|
+
let stdout = "";
|
|
39632
|
+
let stderr = "";
|
|
39633
|
+
const stdio = ["ignore", "pipe", "pipe"];
|
|
39634
|
+
const args = ["playwright", "install", "chromium"];
|
|
39635
|
+
const child = process.platform === "win32" ? executor(buildCmdLine("npx", args), { stdio, shell: true, cwd }) : executor("npx", args, { stdio, cwd });
|
|
39636
|
+
child.stdout?.on("data", (chunk) => {
|
|
39637
|
+
stdout += chunk.toString();
|
|
39638
|
+
});
|
|
39639
|
+
child.stderr?.on("data", (chunk) => {
|
|
39640
|
+
stderr += chunk.toString();
|
|
39641
|
+
});
|
|
39642
|
+
child.on("error", (err) => {
|
|
39643
|
+
resolve({
|
|
39644
|
+
ok: false,
|
|
39645
|
+
output: stdout + stderr,
|
|
39646
|
+
error: err.message,
|
|
39647
|
+
exitCode: null
|
|
39648
|
+
});
|
|
39649
|
+
});
|
|
39650
|
+
child.on("close", (code) => {
|
|
39651
|
+
const ok = code === 0;
|
|
39652
|
+
resolve({
|
|
39653
|
+
ok,
|
|
39654
|
+
output: stdout + stderr,
|
|
39655
|
+
exitCode: code,
|
|
39656
|
+
error: ok ? void 0 : `npx playwright install chromium exited ${code}`
|
|
39657
|
+
});
|
|
39658
|
+
});
|
|
39659
|
+
});
|
|
39292
39660
|
}
|
|
39293
39661
|
function runNpm2(executor, args, cwd, mode, npmCliPath) {
|
|
39294
39662
|
return new Promise((resolve) => {
|
|
@@ -42750,6 +43118,98 @@ async function runDiscoverModels(providerArg) {
|
|
|
42750
43118
|
}
|
|
42751
43119
|
}
|
|
42752
43120
|
|
|
43121
|
+
// src/cli/plugins/cliFlags.ts
|
|
43122
|
+
init_registry2();
|
|
43123
|
+
function getArg(argv, flag) {
|
|
43124
|
+
const i = argv.indexOf(flag);
|
|
43125
|
+
if (i < 0) return void 0;
|
|
43126
|
+
return argv[i + 1];
|
|
43127
|
+
}
|
|
43128
|
+
function resolveCwd(argv) {
|
|
43129
|
+
return getArg(argv, "--cwd") ?? process.cwd();
|
|
43130
|
+
}
|
|
43131
|
+
function wantsPluginsStatus(argv) {
|
|
43132
|
+
return argv.includes("--plugins-status");
|
|
43133
|
+
}
|
|
43134
|
+
function wantsPluginsInstall(argv) {
|
|
43135
|
+
return argv.includes("--plugins-install");
|
|
43136
|
+
}
|
|
43137
|
+
async function runPluginsStatus(argv) {
|
|
43138
|
+
const cwd = resolveCwd(argv);
|
|
43139
|
+
const plugins = [];
|
|
43140
|
+
for (const spec of PLUGINS) {
|
|
43141
|
+
let present = false;
|
|
43142
|
+
try {
|
|
43143
|
+
present = await spec.detect(cwd);
|
|
43144
|
+
} catch {
|
|
43145
|
+
present = false;
|
|
43146
|
+
}
|
|
43147
|
+
plugins.push({
|
|
43148
|
+
id: spec.id,
|
|
43149
|
+
label: spec.label,
|
|
43150
|
+
present,
|
|
43151
|
+
description: spec.description,
|
|
43152
|
+
postInstallHint: spec.postInstallHint ?? null,
|
|
43153
|
+
npmPackage: spec.npmPackage,
|
|
43154
|
+
installScope: spec.installScope
|
|
43155
|
+
});
|
|
43156
|
+
}
|
|
43157
|
+
process.stdout.write(JSON.stringify({ cwd, plugins }, null, 2) + "\n");
|
|
43158
|
+
return 0;
|
|
43159
|
+
}
|
|
43160
|
+
async function runPluginsInstall(argv) {
|
|
43161
|
+
const cwd = resolveCwd(argv);
|
|
43162
|
+
const id = getArg(argv, "--plugins-install");
|
|
43163
|
+
if (!id) {
|
|
43164
|
+
process.stderr.write(
|
|
43165
|
+
"[plugins] usage: zelari-code --plugins-install <id> [--cwd <path>]\n"
|
|
43166
|
+
);
|
|
43167
|
+
process.stdout.write(
|
|
43168
|
+
JSON.stringify({
|
|
43169
|
+
ok: false,
|
|
43170
|
+
id: "",
|
|
43171
|
+
message: "missing plugin id"
|
|
43172
|
+
}) + "\n"
|
|
43173
|
+
);
|
|
43174
|
+
return 1;
|
|
43175
|
+
}
|
|
43176
|
+
const spec = findPlugin(id);
|
|
43177
|
+
if (!spec) {
|
|
43178
|
+
const msg = `unknown plugin id: ${id}. Available: ${PLUGINS.map((p3) => p3.id).join(", ")}`;
|
|
43179
|
+
process.stderr.write(`[plugins] ${msg}
|
|
43180
|
+
`);
|
|
43181
|
+
process.stdout.write(
|
|
43182
|
+
JSON.stringify({ ok: false, id, message: msg }) + "\n"
|
|
43183
|
+
);
|
|
43184
|
+
return 1;
|
|
43185
|
+
}
|
|
43186
|
+
process.stderr.write(
|
|
43187
|
+
`[plugins] installing ${spec.label} into ${cwd}\u2026
|
|
43188
|
+
`
|
|
43189
|
+
);
|
|
43190
|
+
const result = await installPlugin(spec, cwd);
|
|
43191
|
+
const payload = {
|
|
43192
|
+
ok: result.ok,
|
|
43193
|
+
id: spec.id,
|
|
43194
|
+
message: result.ok ? `Installed ${spec.label}` : result.error ?? `Install failed for ${spec.label}`,
|
|
43195
|
+
output: result.output?.slice(-4e3),
|
|
43196
|
+
postInstallHint: spec.postInstallHint ?? null
|
|
43197
|
+
};
|
|
43198
|
+
process.stdout.write(JSON.stringify(payload, null, 2) + "\n");
|
|
43199
|
+
if (!result.ok) {
|
|
43200
|
+
process.stderr.write(`[plugins] \u2717 ${payload.message}
|
|
43201
|
+
`);
|
|
43202
|
+
return 1;
|
|
43203
|
+
}
|
|
43204
|
+
process.stderr.write(`[plugins] \u2713 ${payload.message}
|
|
43205
|
+
`);
|
|
43206
|
+
if (spec.postInstallHint) {
|
|
43207
|
+
process.stderr.write(`[plugins] \u2192 ${spec.postInstallHint}
|
|
43208
|
+
`);
|
|
43209
|
+
}
|
|
43210
|
+
return 0;
|
|
43211
|
+
}
|
|
43212
|
+
|
|
42753
43213
|
// src/cli/skillsMd.ts
|
|
42754
43214
|
init_skills2();
|
|
42755
43215
|
import { existsSync as existsSync36, readdirSync as readdirSync5, readFileSync as readFileSync30 } from "node:fs";
|
|
@@ -42934,6 +43394,14 @@ function pickRootComponent() {
|
|
|
42934
43394
|
console.log(`zelari-code v${VERSION}`);
|
|
42935
43395
|
process.exit(0);
|
|
42936
43396
|
}
|
|
43397
|
+
if (wantsPluginsStatus(argv)) {
|
|
43398
|
+
void runPluginsStatus(argv).then((code) => process.exit(code));
|
|
43399
|
+
return { kind: "done" };
|
|
43400
|
+
}
|
|
43401
|
+
if (wantsPluginsInstall(argv)) {
|
|
43402
|
+
void runPluginsInstall(argv).then((code) => process.exit(code));
|
|
43403
|
+
return { kind: "done" };
|
|
43404
|
+
}
|
|
42937
43405
|
if (argv.includes("--doctor") || argv.includes("doctor")) {
|
|
42938
43406
|
const { runDoctor: runDoctor2 } = (init_doctor(), __toCommonJS(doctor_exports));
|
|
42939
43407
|
void runDoctor2().then((healthy) => process.exit(healthy ? 0 : 1));
|
|
@@ -42963,7 +43431,7 @@ function pickRootComponent() {
|
|
|
42963
43431
|
}
|
|
42964
43432
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
42965
43433
|
console.log(
|
|
42966
|
-
"zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode agent|council|zelari Dispatch mode (default: agent)\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --print-config Print provider/model config as JSON (no secrets)\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable (required)\n --args <json> JSON array of args (optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
|
|
43434
|
+
"zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode agent|council|zelari Dispatch mode (default: agent)\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --print-config Print provider/model config as JSON (no secrets)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable (required)\n --args <json> JSON array of args (optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
|
|
42967
43435
|
);
|
|
42968
43436
|
process.exit(0);
|
|
42969
43437
|
}
|