zam-core 0.10.7 → 0.10.9
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/app.js +1362 -1136
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/commands/mcp.js +551 -325
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/copilot-extension/host.bundle.js +1 -1
- package/dist/copilot-extension/manifest.json +1 -1
- package/dist/copilot-extension/mcp-client.bundle.mjs +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/ui/recall-panel.html +1 -1
- package/dist/ui/studio-panel.html +1 -1
- package/dist/vscode-extension/{ZAM_Companion_0.10.7.vsix → ZAM_Companion_0.10.9.vsix} +0 -0
- package/dist/vscode-extension/manifest.json +2 -2
- package/package.json +1 -1
package/dist/cli/commands/mcp.js
CHANGED
|
@@ -6122,6 +6122,14 @@ function setAgentConnectAutoDone(done, path = defaultConfigPath()) {
|
|
|
6122
6122
|
}
|
|
6123
6123
|
saveInstallConfig(config, path);
|
|
6124
6124
|
}
|
|
6125
|
+
function getLastRepairedVersion(path = defaultConfigPath()) {
|
|
6126
|
+
return loadInstallConfig(path).lastRepairedVersion;
|
|
6127
|
+
}
|
|
6128
|
+
function setLastRepairedVersion(version, path = defaultConfigPath()) {
|
|
6129
|
+
const config = loadInstallConfig(path);
|
|
6130
|
+
config.lastRepairedVersion = version;
|
|
6131
|
+
saveInstallConfig(config, path);
|
|
6132
|
+
}
|
|
6125
6133
|
function getConfiguredWorkspaces(path = defaultConfigPath()) {
|
|
6126
6134
|
return loadInstallConfig(path).workspaces ?? [];
|
|
6127
6135
|
}
|
|
@@ -6844,6 +6852,7 @@ __export(kernel_exports, {
|
|
|
6844
6852
|
getInstallMode: () => getInstallMode,
|
|
6845
6853
|
getKnowledgeContextById: () => getKnowledgeContextById,
|
|
6846
6854
|
getKnowledgeContextByName: () => getKnowledgeContextByName,
|
|
6855
|
+
getLastRepairedVersion: () => getLastRepairedVersion,
|
|
6847
6856
|
getMachineAiConfig: () => getMachineAiConfig,
|
|
6848
6857
|
getMachineAiModels: () => getMachineAiModels,
|
|
6849
6858
|
getMonitorDir: () => getMonitorDir,
|
|
@@ -6939,6 +6948,7 @@ __export(kernel_exports, {
|
|
|
6939
6948
|
setAgentConnectAutoDone: () => setAgentConnectAutoDone,
|
|
6940
6949
|
setInstallChannel: () => setInstallChannel,
|
|
6941
6950
|
setInstallMode: () => setInstallMode,
|
|
6951
|
+
setLastRepairedVersion: () => setLastRepairedVersion,
|
|
6942
6952
|
setProviderApiKey: () => setProviderApiKey,
|
|
6943
6953
|
setSetting: () => setSetting,
|
|
6944
6954
|
setTursoCredentials: () => setTursoCredentials,
|
|
@@ -7016,8 +7026,8 @@ var init_kernel = __esm({
|
|
|
7016
7026
|
|
|
7017
7027
|
// src/cli/commands/mcp.ts
|
|
7018
7028
|
init_kernel();
|
|
7019
|
-
import { existsSync as
|
|
7020
|
-
import { dirname as dirname11, join as
|
|
7029
|
+
import { existsSync as existsSync21, readFileSync as readFileSync18 } from "fs";
|
|
7030
|
+
import { dirname as dirname11, join as join24 } from "path";
|
|
7021
7031
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
7022
7032
|
import {
|
|
7023
7033
|
RESOURCE_MIME_TYPE,
|
|
@@ -8132,7 +8142,7 @@ async function prepareRecallChain(db, opts) {
|
|
|
8132
8142
|
} else {
|
|
8133
8143
|
spawnLocalRunner(endpoint.url, endpoint.model, endpoint.runner);
|
|
8134
8144
|
while (Date.now() < deadline) {
|
|
8135
|
-
await new Promise((
|
|
8145
|
+
await new Promise((resolve7) => setTimeout(resolve7, 1e3));
|
|
8136
8146
|
if (await isLlmOnline(endpoint.url)) {
|
|
8137
8147
|
online = true;
|
|
8138
8148
|
break;
|
|
@@ -8425,7 +8435,7 @@ async function startLocalRunner(url, model, locale, hint) {
|
|
|
8425
8435
|
let attempts = 0;
|
|
8426
8436
|
const dotsPerLine = 30;
|
|
8427
8437
|
while (true) {
|
|
8428
|
-
await new Promise((
|
|
8438
|
+
await new Promise((resolve7) => setTimeout(resolve7, 500));
|
|
8429
8439
|
if (await isLlmOnline(url)) {
|
|
8430
8440
|
if (attempts > 0) process.stdout.write("\n");
|
|
8431
8441
|
return true;
|
|
@@ -8485,8 +8495,8 @@ async function fetchWithInteractiveTimeout(url, options = {}) {
|
|
|
8485
8495
|
const dotsPerLine = 30;
|
|
8486
8496
|
while (true) {
|
|
8487
8497
|
let timeoutId;
|
|
8488
|
-
const timeoutPromise = new Promise((
|
|
8489
|
-
timeoutId = setTimeout(() =>
|
|
8498
|
+
const timeoutPromise = new Promise((resolve7) => {
|
|
8499
|
+
timeoutId = setTimeout(() => resolve7("timeout"), timeoutMs);
|
|
8490
8500
|
});
|
|
8491
8501
|
const dotsInterval = setInterval(() => {
|
|
8492
8502
|
process.stdout.write(".");
|
|
@@ -9830,11 +9840,11 @@ async function publishUiIntent(app, input = {}, opts = {}) {
|
|
|
9830
9840
|
|
|
9831
9841
|
// src/cli/commands/bridge.ts
|
|
9832
9842
|
init_kernel();
|
|
9833
|
-
import { execFileSync as
|
|
9843
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
9834
9844
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
9835
|
-
import { existsSync as
|
|
9836
|
-
import { homedir as
|
|
9837
|
-
import { join as
|
|
9845
|
+
import { existsSync as existsSync20, readdirSync as readdirSync2, readFileSync as readFileSync17, rmSync as rmSync3 } from "fs";
|
|
9846
|
+
import { homedir as homedir15, tmpdir as tmpdir3 } from "os";
|
|
9847
|
+
import { join as join23, resolve as resolve6 } from "path";
|
|
9838
9848
|
import { Command } from "commander";
|
|
9839
9849
|
import { ulid as ulid11 } from "ulid";
|
|
9840
9850
|
|
|
@@ -9913,7 +9923,7 @@ async function readWebLink(url) {
|
|
|
9913
9923
|
redirect: "manual",
|
|
9914
9924
|
signal: controller.signal,
|
|
9915
9925
|
headers: {
|
|
9916
|
-
"User-Agent": "ZAM-Content-Studio/0.10.
|
|
9926
|
+
"User-Agent": "ZAM-Content-Studio/0.10.9"
|
|
9917
9927
|
}
|
|
9918
9928
|
});
|
|
9919
9929
|
if (res.status >= 300 && res.status < 400) {
|
|
@@ -10373,6 +10383,7 @@ function detectInstalledConnectHarnesses(options = {}) {
|
|
|
10373
10383
|
return detected;
|
|
10374
10384
|
}
|
|
10375
10385
|
function parseMcpJsonConfig(path, content) {
|
|
10386
|
+
if (content.trim() === "") return {};
|
|
10376
10387
|
let parsed;
|
|
10377
10388
|
try {
|
|
10378
10389
|
parsed = JSON.parse(content);
|
|
@@ -10418,17 +10429,21 @@ function connectHarnessMcp(harnessId, opts) {
|
|
|
10418
10429
|
if (!existing.mcpServers) {
|
|
10419
10430
|
existing.mcpServers = {};
|
|
10420
10431
|
}
|
|
10421
|
-
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
|
|
10425
|
-
|
|
10426
|
-
|
|
10427
|
-
|
|
10428
|
-
|
|
10429
|
-
|
|
10430
|
-
|
|
10432
|
+
const expected = opts.zamPath.endsWith(".js") ? {
|
|
10433
|
+
command: process.execPath,
|
|
10434
|
+
args: [opts.zamPath, "mcp"]
|
|
10435
|
+
} : {
|
|
10436
|
+
command: opts.zamPath,
|
|
10437
|
+
args: ["mcp"]
|
|
10438
|
+
};
|
|
10439
|
+
const current = existing.mcpServers.zam;
|
|
10440
|
+
if (typeof current === "object" && current !== null && !Array.isArray(current)) {
|
|
10441
|
+
const c = current;
|
|
10442
|
+
if (c.command === expected.command && JSON.stringify(c.args) === JSON.stringify(expected.args)) {
|
|
10443
|
+
alreadyConfigured = true;
|
|
10444
|
+
}
|
|
10431
10445
|
}
|
|
10446
|
+
existing.mcpServers.zam = expected;
|
|
10432
10447
|
return JSON.stringify(existing, null, 2);
|
|
10433
10448
|
};
|
|
10434
10449
|
if (harnessId === "claude-code") {
|
|
@@ -10455,25 +10470,7 @@ function connectHarnessMcp(harnessId, opts) {
|
|
|
10455
10470
|
} else if (harnessId === "antigravity") {
|
|
10456
10471
|
targetPath = join16(opts.home, ".gemini", "config", "mcp_config.json");
|
|
10457
10472
|
hint = "Shared config read by Antigravity CLI and IDE (2.0+); older IDE builds read ~/.gemini/antigravity/mcp_config.json instead. Refresh Installed MCP Servers; the first tool call may still require approval.";
|
|
10458
|
-
|
|
10459
|
-
if (exists(targetPath)) {
|
|
10460
|
-
existing = parseMcpJsonConfig(targetPath, read(targetPath));
|
|
10461
|
-
}
|
|
10462
|
-
if (!existing.mcpServers) {
|
|
10463
|
-
existing.mcpServers = {};
|
|
10464
|
-
}
|
|
10465
|
-
if (opts.zamPath.endsWith(".js")) {
|
|
10466
|
-
existing.mcpServers.zam = {
|
|
10467
|
-
command: process.execPath,
|
|
10468
|
-
args: [opts.zamPath, "mcp"]
|
|
10469
|
-
};
|
|
10470
|
-
} else {
|
|
10471
|
-
existing.mcpServers.zam = {
|
|
10472
|
-
command: opts.zamPath,
|
|
10473
|
-
args: ["mcp"]
|
|
10474
|
-
};
|
|
10475
|
-
}
|
|
10476
|
-
content = JSON.stringify(existing, null, 2);
|
|
10473
|
+
content = mergeMcpServersJson(targetPath);
|
|
10477
10474
|
} else if (harnessId === "opencode") {
|
|
10478
10475
|
targetPath = join16(opts.home, ".config", "opencode", "opencode.json");
|
|
10479
10476
|
hint = "OpenCode will load the enabled 'zam' MCP server on next launch.";
|
|
@@ -10487,11 +10484,19 @@ function connectHarnessMcp(harnessId, opts) {
|
|
|
10487
10484
|
}
|
|
10488
10485
|
const servers = mcp ?? {};
|
|
10489
10486
|
const cmd = opts.zamPath.endsWith(".js") ? [process.execPath, opts.zamPath, "mcp"] : [opts.zamPath, "mcp"];
|
|
10490
|
-
|
|
10487
|
+
const expected = {
|
|
10491
10488
|
type: "local",
|
|
10492
10489
|
command: cmd,
|
|
10493
10490
|
enabled: true
|
|
10494
10491
|
};
|
|
10492
|
+
const current = servers.zam;
|
|
10493
|
+
if (typeof current === "object" && current !== null && !Array.isArray(current)) {
|
|
10494
|
+
const c = current;
|
|
10495
|
+
if (c.type === expected.type && c.enabled === expected.enabled && JSON.stringify(c.command) === JSON.stringify(expected.command)) {
|
|
10496
|
+
alreadyConfigured = true;
|
|
10497
|
+
}
|
|
10498
|
+
}
|
|
10499
|
+
servers.zam = expected;
|
|
10495
10500
|
existing.mcp = servers;
|
|
10496
10501
|
content = JSON.stringify(existing, null, 2);
|
|
10497
10502
|
} else if (harnessId === "codex") {
|
|
@@ -10602,21 +10607,25 @@ ${zamExtension}
|
|
|
10602
10607
|
if (!existing.mcpServers) {
|
|
10603
10608
|
existing.mcpServers = {};
|
|
10604
10609
|
}
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10610
|
+
const expected = opts.zamPath.endsWith(".js") ? {
|
|
10611
|
+
type: "local",
|
|
10612
|
+
command: process.execPath,
|
|
10613
|
+
args: [opts.zamPath, "mcp"],
|
|
10614
|
+
tools: ["*"]
|
|
10615
|
+
} : {
|
|
10616
|
+
type: "local",
|
|
10617
|
+
command: opts.zamPath,
|
|
10618
|
+
args: ["mcp"],
|
|
10619
|
+
tools: ["*"]
|
|
10620
|
+
};
|
|
10621
|
+
const current = existing.mcpServers.zam;
|
|
10622
|
+
if (typeof current === "object" && current !== null && !Array.isArray(current)) {
|
|
10623
|
+
const c = current;
|
|
10624
|
+
if (c.type === expected.type && c.command === expected.command && JSON.stringify(c.args) === JSON.stringify(expected.args) && JSON.stringify(c.tools) === JSON.stringify(expected.tools)) {
|
|
10625
|
+
alreadyConfigured = true;
|
|
10626
|
+
}
|
|
10619
10627
|
}
|
|
10628
|
+
existing.mcpServers.zam = expected;
|
|
10620
10629
|
content = JSON.stringify(existing, null, 2);
|
|
10621
10630
|
}
|
|
10622
10631
|
return {
|
|
@@ -11043,6 +11052,127 @@ function inspectConnectHarnesses(deps = {}) {
|
|
|
11043
11052
|
return { zamOnPath: Boolean(foundZam), harnesses };
|
|
11044
11053
|
}
|
|
11045
11054
|
|
|
11055
|
+
// src/cli/cli-install.ts
|
|
11056
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
11057
|
+
import {
|
|
11058
|
+
chmodSync as chmodSync2,
|
|
11059
|
+
existsSync as existsSync17,
|
|
11060
|
+
mkdirSync as mkdirSync13,
|
|
11061
|
+
readFileSync as readFileSync14,
|
|
11062
|
+
writeFileSync as writeFileSync11
|
|
11063
|
+
} from "fs";
|
|
11064
|
+
import { homedir as homedir14 } from "os";
|
|
11065
|
+
import { delimiter as delimiter2, join as join19, resolve as resolve5 } from "path";
|
|
11066
|
+
var BUILT_CLI_PATTERN = /[\\/]dist[\\/]cli[\\/]index\.js$/;
|
|
11067
|
+
function normalizeForCompare(path, platform) {
|
|
11068
|
+
const resolved = resolve5(path);
|
|
11069
|
+
return platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
11070
|
+
}
|
|
11071
|
+
function windowsShimContent(nodePath, cliPath) {
|
|
11072
|
+
return `@echo off\r
|
|
11073
|
+
"${nodePath}" "${cliPath}" %*\r
|
|
11074
|
+
`;
|
|
11075
|
+
}
|
|
11076
|
+
function unixShimContent(nodePath, cliPath) {
|
|
11077
|
+
return `#!/bin/sh
|
|
11078
|
+
exec "${nodePath}" "${cliPath}" "$@"
|
|
11079
|
+
`;
|
|
11080
|
+
}
|
|
11081
|
+
function psQuote(value) {
|
|
11082
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
11083
|
+
}
|
|
11084
|
+
function ensureWindowsUserPath(binDir) {
|
|
11085
|
+
const script = [
|
|
11086
|
+
"$ErrorActionPreference = 'Stop'",
|
|
11087
|
+
"$key = [Microsoft.Win32.Registry]::CurrentUser.CreateSubKey('Environment', $true)",
|
|
11088
|
+
"$old = [string]$key.GetValue('Path', '', [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)",
|
|
11089
|
+
`$target = ${psQuote(binDir)}`,
|
|
11090
|
+
"$expanded = ($old -split ';') | Where-Object { $_ -ne '' } | ForEach-Object { [Environment]::ExpandEnvironmentVariables($_).TrimEnd('\\') }",
|
|
11091
|
+
"if ($expanded -contains $target.TrimEnd('\\')) { 'present'; exit 0 }",
|
|
11092
|
+
"$new = if ($old -and -not $old.EndsWith(';')) { $old + ';' + $target } else { $old + $target }",
|
|
11093
|
+
"$key.SetValue('Path', $new, [Microsoft.Win32.RegistryValueKind]::ExpandString)",
|
|
11094
|
+
`$sig = '[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);'`,
|
|
11095
|
+
"$type = Add-Type -MemberDefinition $sig -Name 'ZamEnvBroadcast' -Namespace 'ZamInstall' -PassThru",
|
|
11096
|
+
"[UIntPtr]$result = [UIntPtr]::Zero",
|
|
11097
|
+
"$null = $type::SendMessageTimeout([IntPtr]0xffff, 0x001A, [UIntPtr]::Zero, 'Environment', 2, 5000, [ref]$result)",
|
|
11098
|
+
"'updated'"
|
|
11099
|
+
].join("; ");
|
|
11100
|
+
const output = execFileSync4(
|
|
11101
|
+
"powershell.exe",
|
|
11102
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
11103
|
+
{ stdio: ["ignore", "pipe", "pipe"], windowsHide: true }
|
|
11104
|
+
).toString().trim();
|
|
11105
|
+
return output.endsWith("updated");
|
|
11106
|
+
}
|
|
11107
|
+
function ensureUnixUserPath(home, platform) {
|
|
11108
|
+
const profile = join19(home, platform === "darwin" ? ".zprofile" : ".profile");
|
|
11109
|
+
const existing = existsSync17(profile) ? readFileSync14(profile, "utf8") : "";
|
|
11110
|
+
if (existing.includes(".zam/bin")) return false;
|
|
11111
|
+
const block = `
|
|
11112
|
+
# Added by ZAM: keep the zam CLI on PATH
|
|
11113
|
+
export PATH="$HOME/.zam/bin:$PATH"
|
|
11114
|
+
`;
|
|
11115
|
+
writeFileSync11(profile, existing + block, "utf8");
|
|
11116
|
+
return true;
|
|
11117
|
+
}
|
|
11118
|
+
function installCliShim(options = {}) {
|
|
11119
|
+
const home = options.home ?? homedir14();
|
|
11120
|
+
const platform = options.platform ?? process.platform;
|
|
11121
|
+
const env = options.env ?? process.env;
|
|
11122
|
+
const find = options.find ?? findExecutable;
|
|
11123
|
+
const nodePath = resolve5(options.nodePath ?? process.execPath);
|
|
11124
|
+
const cliPath = resolve5(options.cliPath ?? process.argv[1] ?? "");
|
|
11125
|
+
const binDir = join19(home, ".zam", "bin");
|
|
11126
|
+
const shimPath = join19(binDir, platform === "win32" ? "zam.cmd" : "zam");
|
|
11127
|
+
const report = {
|
|
11128
|
+
status: "ok",
|
|
11129
|
+
binDir,
|
|
11130
|
+
shimPath,
|
|
11131
|
+
nodePath,
|
|
11132
|
+
cliPath,
|
|
11133
|
+
onPath: false,
|
|
11134
|
+
pathUpdated: false,
|
|
11135
|
+
needsNewTerminal: false
|
|
11136
|
+
};
|
|
11137
|
+
if (!BUILT_CLI_PATTERN.test(cliPath) || !existsSync17(cliPath)) {
|
|
11138
|
+
report.status = "skipped";
|
|
11139
|
+
report.detail = `Not running from a built CLI entry (${cliPath}); nothing to link.`;
|
|
11140
|
+
return report;
|
|
11141
|
+
}
|
|
11142
|
+
try {
|
|
11143
|
+
const existing = find("zam");
|
|
11144
|
+
if (existing && normalizeForCompare(existing, platform) !== normalizeForCompare(shimPath, platform)) {
|
|
11145
|
+
report.status = "external";
|
|
11146
|
+
report.onPath = true;
|
|
11147
|
+
report.detail = existing;
|
|
11148
|
+
return report;
|
|
11149
|
+
}
|
|
11150
|
+
const content = platform === "win32" ? windowsShimContent(nodePath, cliPath) : unixShimContent(nodePath, cliPath);
|
|
11151
|
+
const existed = existsSync17(shimPath);
|
|
11152
|
+
const changed = !existed || readFileSync14(shimPath, "utf8") !== content;
|
|
11153
|
+
if (changed) {
|
|
11154
|
+
mkdirSync13(binDir, { recursive: true });
|
|
11155
|
+
writeFileSync11(shimPath, content, "utf8");
|
|
11156
|
+
if (platform !== "win32") chmodSync2(shimPath, 493);
|
|
11157
|
+
}
|
|
11158
|
+
report.status = !existed ? "installed" : changed ? "refreshed" : "ok";
|
|
11159
|
+
const processPathHasBin = (env.PATH ?? "").split(delimiter2).map((entry) => normalizeForCompare(entry.trim() || ".", platform)).includes(normalizeForCompare(binDir, platform));
|
|
11160
|
+
if (processPathHasBin) {
|
|
11161
|
+
report.onPath = true;
|
|
11162
|
+
return report;
|
|
11163
|
+
}
|
|
11164
|
+
const ensureUserPath = options.ensureUserPath ?? (platform === "win32" ? ensureWindowsUserPath : () => ensureUnixUserPath(home, platform));
|
|
11165
|
+
report.pathUpdated = ensureUserPath(binDir);
|
|
11166
|
+
report.onPath = true;
|
|
11167
|
+
report.needsNewTerminal = true;
|
|
11168
|
+
return report;
|
|
11169
|
+
} catch (error) {
|
|
11170
|
+
report.status = "error";
|
|
11171
|
+
report.detail = error instanceof Error ? error.message : String(error);
|
|
11172
|
+
return report;
|
|
11173
|
+
}
|
|
11174
|
+
}
|
|
11175
|
+
|
|
11046
11176
|
// src/cli/curriculum/breadcrumb.ts
|
|
11047
11177
|
init_kernel();
|
|
11048
11178
|
var LAST_SELECTION_KEY = "curriculum.lastSelection";
|
|
@@ -27729,6 +27859,297 @@ function getCurriculumProvider(id) {
|
|
|
27729
27859
|
return CURRICULUM_PROVIDERS.find((provider) => provider.id === id);
|
|
27730
27860
|
}
|
|
27731
27861
|
|
|
27862
|
+
// src/cli/install-repair.ts
|
|
27863
|
+
init_kernel();
|
|
27864
|
+
import { existsSync as existsSync19 } from "fs";
|
|
27865
|
+
|
|
27866
|
+
// src/cli/provisioning/index.ts
|
|
27867
|
+
import {
|
|
27868
|
+
existsSync as existsSync18,
|
|
27869
|
+
lstatSync as lstatSync2,
|
|
27870
|
+
mkdirSync as mkdirSync14,
|
|
27871
|
+
readFileSync as readFileSync15,
|
|
27872
|
+
realpathSync,
|
|
27873
|
+
rmSync as rmSync2,
|
|
27874
|
+
symlinkSync,
|
|
27875
|
+
writeFileSync as writeFileSync12
|
|
27876
|
+
} from "fs";
|
|
27877
|
+
import { basename as basename4, dirname as dirname10, join as join20 } from "path";
|
|
27878
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
27879
|
+
var packageRoot3 = [
|
|
27880
|
+
fileURLToPath5(new URL("../..", import.meta.url)),
|
|
27881
|
+
fileURLToPath5(new URL("../../..", import.meta.url))
|
|
27882
|
+
].find((candidate) => existsSync18(join20(candidate, "package.json"))) ?? fileURLToPath5(new URL("../..", import.meta.url));
|
|
27883
|
+
var ALL_SETUP_AGENTS = ["claude", "copilot", "codex", "agent"];
|
|
27884
|
+
var SKILL_PAIRS = [
|
|
27885
|
+
{
|
|
27886
|
+
from: join20(packageRoot3, ".claude", "skills", "zam", "SKILL.md"),
|
|
27887
|
+
to: join20(".claude", "skills", "zam", "SKILL.md"),
|
|
27888
|
+
agents: ["claude", "copilot"]
|
|
27889
|
+
},
|
|
27890
|
+
{
|
|
27891
|
+
from: join20(packageRoot3, ".agent", "skills", "zam", "SKILL.md"),
|
|
27892
|
+
to: join20(".agent", "skills", "zam", "SKILL.md"),
|
|
27893
|
+
agents: ["agent"]
|
|
27894
|
+
},
|
|
27895
|
+
{
|
|
27896
|
+
from: join20(packageRoot3, ".agents", "skills", "zam", "SKILL.md"),
|
|
27897
|
+
to: join20(".agents", "skills", "zam", "SKILL.md"),
|
|
27898
|
+
agents: ["codex"]
|
|
27899
|
+
}
|
|
27900
|
+
];
|
|
27901
|
+
function parseSetupAgents(value) {
|
|
27902
|
+
if (!value || value.trim().toLowerCase() === "all") {
|
|
27903
|
+
return new Set(ALL_SETUP_AGENTS);
|
|
27904
|
+
}
|
|
27905
|
+
const aliases = {
|
|
27906
|
+
claude: ["claude"],
|
|
27907
|
+
copilot: ["copilot"],
|
|
27908
|
+
codex: ["codex"],
|
|
27909
|
+
agent: ["agent"],
|
|
27910
|
+
opencode: ["agent"]
|
|
27911
|
+
};
|
|
27912
|
+
const selected = /* @__PURE__ */ new Set();
|
|
27913
|
+
for (const raw of value.split(",")) {
|
|
27914
|
+
const key = raw.trim().toLowerCase();
|
|
27915
|
+
const mapped = aliases[key];
|
|
27916
|
+
if (!mapped) {
|
|
27917
|
+
throw new Error(
|
|
27918
|
+
`Unknown agent "${raw}". Use: all, claude, copilot, codex, agent.`
|
|
27919
|
+
);
|
|
27920
|
+
}
|
|
27921
|
+
for (const item of mapped) selected.add(item);
|
|
27922
|
+
}
|
|
27923
|
+
return selected;
|
|
27924
|
+
}
|
|
27925
|
+
function pathExists(path) {
|
|
27926
|
+
try {
|
|
27927
|
+
lstatSync2(path);
|
|
27928
|
+
return true;
|
|
27929
|
+
} catch {
|
|
27930
|
+
return false;
|
|
27931
|
+
}
|
|
27932
|
+
}
|
|
27933
|
+
function isSymbolicLink(path) {
|
|
27934
|
+
try {
|
|
27935
|
+
return lstatSync2(path).isSymbolicLink();
|
|
27936
|
+
} catch {
|
|
27937
|
+
return false;
|
|
27938
|
+
}
|
|
27939
|
+
}
|
|
27940
|
+
function comparableRealPath(path) {
|
|
27941
|
+
const real = realpathSync(path);
|
|
27942
|
+
return process.platform === "win32" ? real.toLowerCase() : real;
|
|
27943
|
+
}
|
|
27944
|
+
function pathsResolveToSameDirectory(sourceDir, destinationDir) {
|
|
27945
|
+
try {
|
|
27946
|
+
return comparableRealPath(destinationDir) === comparableRealPath(sourceDir);
|
|
27947
|
+
} catch {
|
|
27948
|
+
return false;
|
|
27949
|
+
}
|
|
27950
|
+
}
|
|
27951
|
+
function linkPointsTo(sourceDir, destinationDir) {
|
|
27952
|
+
return isSymbolicLink(destinationDir) && pathsResolveToSameDirectory(sourceDir, destinationDir);
|
|
27953
|
+
}
|
|
27954
|
+
function isZamSkillCopy(destinationDir) {
|
|
27955
|
+
try {
|
|
27956
|
+
if (!lstatSync2(destinationDir).isDirectory()) return false;
|
|
27957
|
+
const skillFile = join20(destinationDir, "SKILL.md");
|
|
27958
|
+
if (!existsSync18(skillFile)) return false;
|
|
27959
|
+
return /^name:\s*zam\s*$/m.test(readFileSync15(skillFile, "utf8"));
|
|
27960
|
+
} catch {
|
|
27961
|
+
return false;
|
|
27962
|
+
}
|
|
27963
|
+
}
|
|
27964
|
+
function classifySkillDestination(sourceDir, destinationDir) {
|
|
27965
|
+
if (!existsSync18(sourceDir)) return "source-missing";
|
|
27966
|
+
if (!isSymbolicLink(destinationDir) && pathsResolveToSameDirectory(sourceDir, destinationDir)) {
|
|
27967
|
+
return "source-directory";
|
|
27968
|
+
}
|
|
27969
|
+
if (linkPointsTo(sourceDir, destinationDir)) return "linked";
|
|
27970
|
+
if (!pathExists(destinationDir)) return "missing";
|
|
27971
|
+
if (isSymbolicLink(destinationDir)) return "broken";
|
|
27972
|
+
if (isZamSkillCopy(destinationDir)) return "stale-copy";
|
|
27973
|
+
return "unmanaged";
|
|
27974
|
+
}
|
|
27975
|
+
function wireSkills(cwd = process.cwd(), agents = parseSetupAgents(), opts = {}) {
|
|
27976
|
+
const results = [];
|
|
27977
|
+
const log = (message) => {
|
|
27978
|
+
if (!opts.quiet) console.log(message);
|
|
27979
|
+
};
|
|
27980
|
+
for (const { from, to, agents: pairAgents } of SKILL_PAIRS) {
|
|
27981
|
+
if (!pairAgents.some((agent) => agents.has(agent))) continue;
|
|
27982
|
+
const sourceDir = dirname10(from);
|
|
27983
|
+
const destinationDir = dirname10(join20(cwd, to));
|
|
27984
|
+
const label = dirname10(to);
|
|
27985
|
+
const state = classifySkillDestination(sourceDir, destinationDir);
|
|
27986
|
+
if (state === "source-missing") {
|
|
27987
|
+
if (!opts.quiet) {
|
|
27988
|
+
console.warn(` warn source not found, skipping: ${sourceDir}`);
|
|
27989
|
+
}
|
|
27990
|
+
results.push({
|
|
27991
|
+
source: sourceDir,
|
|
27992
|
+
destination: destinationDir,
|
|
27993
|
+
action: "skipped",
|
|
27994
|
+
reason: "source-not-found"
|
|
27995
|
+
});
|
|
27996
|
+
continue;
|
|
27997
|
+
}
|
|
27998
|
+
if (state === "source-directory") {
|
|
27999
|
+
log(` skip ${label} (package source)`);
|
|
28000
|
+
results.push({
|
|
28001
|
+
source: sourceDir,
|
|
28002
|
+
destination: destinationDir,
|
|
28003
|
+
action: "skipped",
|
|
28004
|
+
reason: "source-directory"
|
|
28005
|
+
});
|
|
28006
|
+
continue;
|
|
28007
|
+
}
|
|
28008
|
+
if (state === "linked") {
|
|
28009
|
+
log(` skip ${label} (already linked)`);
|
|
28010
|
+
results.push({
|
|
28011
|
+
source: sourceDir,
|
|
28012
|
+
destination: destinationDir,
|
|
28013
|
+
action: "skipped",
|
|
28014
|
+
reason: "already-linked"
|
|
28015
|
+
});
|
|
28016
|
+
continue;
|
|
28017
|
+
}
|
|
28018
|
+
const destinationExists = state !== "missing";
|
|
28019
|
+
const replaceExisting = destinationExists && (Boolean(opts.force) || state === "broken" || state === "stale-copy");
|
|
28020
|
+
if (destinationExists && !replaceExisting) {
|
|
28021
|
+
if (!opts.quiet) {
|
|
28022
|
+
console.warn(
|
|
28023
|
+
` warn ${label} already exists and is not managed by ZAM; use --force to replace it`
|
|
28024
|
+
);
|
|
28025
|
+
}
|
|
28026
|
+
results.push({
|
|
28027
|
+
source: sourceDir,
|
|
28028
|
+
destination: destinationDir,
|
|
28029
|
+
action: "skipped",
|
|
28030
|
+
reason: "unmanaged-destination"
|
|
28031
|
+
});
|
|
28032
|
+
continue;
|
|
28033
|
+
}
|
|
28034
|
+
const action = destinationExists ? "relinked" : "linked";
|
|
28035
|
+
if (opts.dryRun) {
|
|
28036
|
+
log(` would ${action === "linked" ? "link" : "relink"} ${label}`);
|
|
28037
|
+
} else {
|
|
28038
|
+
if (destinationExists) {
|
|
28039
|
+
rmSync2(destinationDir, { recursive: true, force: true });
|
|
28040
|
+
}
|
|
28041
|
+
mkdirSync14(dirname10(destinationDir), { recursive: true });
|
|
28042
|
+
symlinkSync(
|
|
28043
|
+
sourceDir,
|
|
28044
|
+
destinationDir,
|
|
28045
|
+
process.platform === "win32" ? "junction" : "dir"
|
|
28046
|
+
);
|
|
28047
|
+
log(` ${action === "linked" ? "link" : "relink"} ${label}`);
|
|
28048
|
+
}
|
|
28049
|
+
results.push({ source: sourceDir, destination: destinationDir, action });
|
|
28050
|
+
}
|
|
28051
|
+
return results;
|
|
28052
|
+
}
|
|
28053
|
+
function inspectSkillLinks(cwd = process.cwd(), agents = parseSetupAgents()) {
|
|
28054
|
+
const results = [];
|
|
28055
|
+
for (const { from, to, agents: pairAgents } of SKILL_PAIRS) {
|
|
28056
|
+
if (!pairAgents.some((agent) => agents.has(agent))) continue;
|
|
28057
|
+
const sourceDir = dirname10(from);
|
|
28058
|
+
const destinationDir = dirname10(join20(cwd, to));
|
|
28059
|
+
results.push({
|
|
28060
|
+
agents: pairAgents,
|
|
28061
|
+
source: sourceDir,
|
|
28062
|
+
destination: destinationDir,
|
|
28063
|
+
state: classifySkillDestination(sourceDir, destinationDir)
|
|
28064
|
+
});
|
|
28065
|
+
}
|
|
28066
|
+
return results;
|
|
28067
|
+
}
|
|
28068
|
+
function summarizeSkillLinkHealth(inspections) {
|
|
28069
|
+
if (inspections.some((item) => item.state === "unmanaged")) {
|
|
28070
|
+
return "unmanaged";
|
|
28071
|
+
}
|
|
28072
|
+
const repairable = ["missing", "broken", "stale-copy"];
|
|
28073
|
+
if (inspections.some((item) => repairable.includes(item.state))) {
|
|
28074
|
+
return "needs-repair";
|
|
28075
|
+
}
|
|
28076
|
+
return "healthy";
|
|
28077
|
+
}
|
|
28078
|
+
|
|
28079
|
+
// src/cli/install-repair.ts
|
|
28080
|
+
function defaultRepairWorkspaces() {
|
|
28081
|
+
const summary = {
|
|
28082
|
+
provisioned: 0,
|
|
28083
|
+
missing: 0,
|
|
28084
|
+
relinked: 0
|
|
28085
|
+
};
|
|
28086
|
+
try {
|
|
28087
|
+
const agents = parseSetupAgents();
|
|
28088
|
+
for (const workspace of getConfiguredWorkspaces()) {
|
|
28089
|
+
if (!existsSync19(workspace.path)) {
|
|
28090
|
+
summary.missing += 1;
|
|
28091
|
+
continue;
|
|
28092
|
+
}
|
|
28093
|
+
const results = wireSkills(workspace.path, agents, { quiet: true });
|
|
28094
|
+
summary.provisioned += 1;
|
|
28095
|
+
summary.relinked += results.filter(
|
|
28096
|
+
(result) => result.action === "linked" || result.action === "relinked"
|
|
28097
|
+
).length;
|
|
28098
|
+
}
|
|
28099
|
+
} catch (error) {
|
|
28100
|
+
summary.error = error instanceof Error ? error.message : String(error);
|
|
28101
|
+
}
|
|
28102
|
+
return summary;
|
|
28103
|
+
}
|
|
28104
|
+
function defaultConnectAgents(deps) {
|
|
28105
|
+
const report = performAgentConnect({}, deps);
|
|
28106
|
+
const companion = report.results.find((result) => result.extension?.kind === "vscode")?.extension?.action ?? null;
|
|
28107
|
+
return {
|
|
28108
|
+
success: report.success,
|
|
28109
|
+
detected: report.detected,
|
|
28110
|
+
connected: report.results.filter(
|
|
28111
|
+
(result) => !result.error && (result.alreadyConfigured || result.wrote)
|
|
28112
|
+
).length,
|
|
28113
|
+
companion,
|
|
28114
|
+
errors: report.results.flatMap(
|
|
28115
|
+
(result) => result.error ? [`${result.label}: ${result.error}`] : []
|
|
28116
|
+
)
|
|
28117
|
+
};
|
|
28118
|
+
}
|
|
28119
|
+
function performInstallRepair(opts = {}, deps = {}) {
|
|
28120
|
+
const version = (deps.version ?? currentVersion)();
|
|
28121
|
+
const getLastRepaired = deps.getLastRepaired ?? getLastRepairedVersion;
|
|
28122
|
+
if (opts.ifVersionChanged && getLastRepaired() === version) {
|
|
28123
|
+
return {
|
|
28124
|
+
version,
|
|
28125
|
+
skipped: true,
|
|
28126
|
+
cli: null,
|
|
28127
|
+
workspaces: null,
|
|
28128
|
+
agents: null
|
|
28129
|
+
};
|
|
28130
|
+
}
|
|
28131
|
+
const cli = (deps.installCli ?? installCliShim)();
|
|
28132
|
+
const workspaces = (deps.repairWorkspaces ?? defaultRepairWorkspaces)();
|
|
28133
|
+
const agentDeps = {};
|
|
28134
|
+
if (cli.status === "installed" || cli.status === "refreshed" || cli.status === "ok") {
|
|
28135
|
+
agentDeps.findZam = () => cli.shimPath;
|
|
28136
|
+
}
|
|
28137
|
+
let agents;
|
|
28138
|
+
try {
|
|
28139
|
+
agents = (deps.connectAgents ?? defaultConnectAgents)(agentDeps);
|
|
28140
|
+
} catch (error) {
|
|
28141
|
+
agents = {
|
|
28142
|
+
success: false,
|
|
28143
|
+
detected: [],
|
|
28144
|
+
connected: 0,
|
|
28145
|
+
companion: null,
|
|
28146
|
+
errors: [error instanceof Error ? error.message : String(error)]
|
|
28147
|
+
};
|
|
28148
|
+
}
|
|
28149
|
+
(deps.setLastRepaired ?? setLastRepairedVersion)(version);
|
|
28150
|
+
return { version, skipped: false, cli, workspaces, agents };
|
|
28151
|
+
}
|
|
28152
|
+
|
|
27732
28153
|
// src/cli/llm/capability-probe.ts
|
|
27733
28154
|
init_kernel();
|
|
27734
28155
|
var EMBEDDING_MODEL_HINTS = [
|
|
@@ -27853,9 +28274,9 @@ function validateModelSave(entry, probe, now = () => (/* @__PURE__ */ new Date()
|
|
|
27853
28274
|
// src/cli/llm/vision.ts
|
|
27854
28275
|
init_kernel();
|
|
27855
28276
|
import { randomBytes } from "crypto";
|
|
27856
|
-
import { readFileSync as
|
|
28277
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
27857
28278
|
import { tmpdir as tmpdir2 } from "os";
|
|
27858
|
-
import { basename as
|
|
28279
|
+
import { basename as basename5, join as join21 } from "path";
|
|
27859
28280
|
var LANGUAGE_NAMES2 = {
|
|
27860
28281
|
en: "English",
|
|
27861
28282
|
de: "German",
|
|
@@ -27891,13 +28312,13 @@ async function observeUiSnapshotViaLLM(db, input) {
|
|
|
27891
28312
|
const imageUrls = [];
|
|
27892
28313
|
const isVideo = /\.(mp4|mov|m4v|avi|mkv|webm)$/i.test(input.imagePath);
|
|
27893
28314
|
if (isVideo) {
|
|
27894
|
-
const { mkdirSync:
|
|
28315
|
+
const { mkdirSync: mkdirSync16, readdirSync: readdirSync3, rmSync: rmSync4 } = await import("fs");
|
|
27895
28316
|
const { execSync: execSync5 } = await import("child_process");
|
|
27896
|
-
const tempDir =
|
|
28317
|
+
const tempDir = join21(
|
|
27897
28318
|
tmpdir2(),
|
|
27898
28319
|
`zam-frames-${randomBytes(4).toString("hex")}`
|
|
27899
28320
|
);
|
|
27900
|
-
|
|
28321
|
+
mkdirSync16(tempDir, { recursive: true });
|
|
27901
28322
|
try {
|
|
27902
28323
|
execSync5(
|
|
27903
28324
|
`ffmpeg -i "${input.imagePath}" -vf "fps=1/3,scale=1280:-1" -vsync vfr "${tempDir}/frame_%03d.png"`,
|
|
@@ -27926,7 +28347,7 @@ async function observeUiSnapshotViaLLM(db, input) {
|
|
|
27926
28347
|
}
|
|
27927
28348
|
}
|
|
27928
28349
|
for (const file of sampledFiles) {
|
|
27929
|
-
const bytes =
|
|
28350
|
+
const bytes = readFileSync16(join21(tempDir, file));
|
|
27930
28351
|
imageUrls.push(`data:image/png;base64,${bytes.toString("base64")}`);
|
|
27931
28352
|
}
|
|
27932
28353
|
} finally {
|
|
@@ -27936,7 +28357,7 @@ async function observeUiSnapshotViaLLM(db, input) {
|
|
|
27936
28357
|
}
|
|
27937
28358
|
}
|
|
27938
28359
|
} else {
|
|
27939
|
-
const imageBytes =
|
|
28360
|
+
const imageBytes = readFileSync16(input.imagePath);
|
|
27940
28361
|
const ext = input.imagePath.split(".").pop()?.toLowerCase();
|
|
27941
28362
|
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : "image/png";
|
|
27942
28363
|
imageUrls.push(`data:${mime};base64,${imageBytes.toString("base64")}`);
|
|
@@ -28174,7 +28595,7 @@ function buildReport(input, draft) {
|
|
|
28174
28595
|
evidence: [
|
|
28175
28596
|
{
|
|
28176
28597
|
type: "keyframe",
|
|
28177
|
-
ref: input.evidenceRef ??
|
|
28598
|
+
ref: input.evidenceRef ?? basename5(input.imagePath),
|
|
28178
28599
|
redacted: input.redacted ?? false
|
|
28179
28600
|
}
|
|
28180
28601
|
],
|
|
@@ -28196,7 +28617,7 @@ function uncertainReport(input, summary) {
|
|
|
28196
28617
|
evidence: [
|
|
28197
28618
|
{
|
|
28198
28619
|
type: "keyframe",
|
|
28199
|
-
ref: input.evidenceRef ??
|
|
28620
|
+
ref: input.evidenceRef ?? basename5(input.imagePath),
|
|
28200
28621
|
redacted: input.redacted ?? false
|
|
28201
28622
|
}
|
|
28202
28623
|
],
|
|
@@ -28406,219 +28827,6 @@ async function withProviderScope(machine, action) {
|
|
|
28406
28827
|
await withDb(action);
|
|
28407
28828
|
}
|
|
28408
28829
|
|
|
28409
|
-
// src/cli/provisioning/index.ts
|
|
28410
|
-
import {
|
|
28411
|
-
existsSync as existsSync17,
|
|
28412
|
-
lstatSync as lstatSync2,
|
|
28413
|
-
mkdirSync as mkdirSync13,
|
|
28414
|
-
readFileSync as readFileSync15,
|
|
28415
|
-
realpathSync,
|
|
28416
|
-
rmSync as rmSync2,
|
|
28417
|
-
symlinkSync,
|
|
28418
|
-
writeFileSync as writeFileSync11
|
|
28419
|
-
} from "fs";
|
|
28420
|
-
import { basename as basename5, dirname as dirname10, join as join20 } from "path";
|
|
28421
|
-
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
28422
|
-
var packageRoot3 = [
|
|
28423
|
-
fileURLToPath5(new URL("../..", import.meta.url)),
|
|
28424
|
-
fileURLToPath5(new URL("../../..", import.meta.url))
|
|
28425
|
-
].find((candidate) => existsSync17(join20(candidate, "package.json"))) ?? fileURLToPath5(new URL("../..", import.meta.url));
|
|
28426
|
-
var ALL_SETUP_AGENTS = ["claude", "copilot", "codex", "agent"];
|
|
28427
|
-
var SKILL_PAIRS = [
|
|
28428
|
-
{
|
|
28429
|
-
from: join20(packageRoot3, ".claude", "skills", "zam", "SKILL.md"),
|
|
28430
|
-
to: join20(".claude", "skills", "zam", "SKILL.md"),
|
|
28431
|
-
agents: ["claude", "copilot"]
|
|
28432
|
-
},
|
|
28433
|
-
{
|
|
28434
|
-
from: join20(packageRoot3, ".agent", "skills", "zam", "SKILL.md"),
|
|
28435
|
-
to: join20(".agent", "skills", "zam", "SKILL.md"),
|
|
28436
|
-
agents: ["agent"]
|
|
28437
|
-
},
|
|
28438
|
-
{
|
|
28439
|
-
from: join20(packageRoot3, ".agents", "skills", "zam", "SKILL.md"),
|
|
28440
|
-
to: join20(".agents", "skills", "zam", "SKILL.md"),
|
|
28441
|
-
agents: ["codex"]
|
|
28442
|
-
}
|
|
28443
|
-
];
|
|
28444
|
-
function parseSetupAgents(value) {
|
|
28445
|
-
if (!value || value.trim().toLowerCase() === "all") {
|
|
28446
|
-
return new Set(ALL_SETUP_AGENTS);
|
|
28447
|
-
}
|
|
28448
|
-
const aliases = {
|
|
28449
|
-
claude: ["claude"],
|
|
28450
|
-
copilot: ["copilot"],
|
|
28451
|
-
codex: ["codex"],
|
|
28452
|
-
agent: ["agent"],
|
|
28453
|
-
opencode: ["agent"]
|
|
28454
|
-
};
|
|
28455
|
-
const selected = /* @__PURE__ */ new Set();
|
|
28456
|
-
for (const raw of value.split(",")) {
|
|
28457
|
-
const key = raw.trim().toLowerCase();
|
|
28458
|
-
const mapped = aliases[key];
|
|
28459
|
-
if (!mapped) {
|
|
28460
|
-
throw new Error(
|
|
28461
|
-
`Unknown agent "${raw}". Use: all, claude, copilot, codex, agent.`
|
|
28462
|
-
);
|
|
28463
|
-
}
|
|
28464
|
-
for (const item of mapped) selected.add(item);
|
|
28465
|
-
}
|
|
28466
|
-
return selected;
|
|
28467
|
-
}
|
|
28468
|
-
function pathExists(path) {
|
|
28469
|
-
try {
|
|
28470
|
-
lstatSync2(path);
|
|
28471
|
-
return true;
|
|
28472
|
-
} catch {
|
|
28473
|
-
return false;
|
|
28474
|
-
}
|
|
28475
|
-
}
|
|
28476
|
-
function isSymbolicLink(path) {
|
|
28477
|
-
try {
|
|
28478
|
-
return lstatSync2(path).isSymbolicLink();
|
|
28479
|
-
} catch {
|
|
28480
|
-
return false;
|
|
28481
|
-
}
|
|
28482
|
-
}
|
|
28483
|
-
function comparableRealPath(path) {
|
|
28484
|
-
const real = realpathSync(path);
|
|
28485
|
-
return process.platform === "win32" ? real.toLowerCase() : real;
|
|
28486
|
-
}
|
|
28487
|
-
function pathsResolveToSameDirectory(sourceDir, destinationDir) {
|
|
28488
|
-
try {
|
|
28489
|
-
return comparableRealPath(destinationDir) === comparableRealPath(sourceDir);
|
|
28490
|
-
} catch {
|
|
28491
|
-
return false;
|
|
28492
|
-
}
|
|
28493
|
-
}
|
|
28494
|
-
function linkPointsTo(sourceDir, destinationDir) {
|
|
28495
|
-
return isSymbolicLink(destinationDir) && pathsResolveToSameDirectory(sourceDir, destinationDir);
|
|
28496
|
-
}
|
|
28497
|
-
function isZamSkillCopy(destinationDir) {
|
|
28498
|
-
try {
|
|
28499
|
-
if (!lstatSync2(destinationDir).isDirectory()) return false;
|
|
28500
|
-
const skillFile = join20(destinationDir, "SKILL.md");
|
|
28501
|
-
if (!existsSync17(skillFile)) return false;
|
|
28502
|
-
return /^name:\s*zam\s*$/m.test(readFileSync15(skillFile, "utf8"));
|
|
28503
|
-
} catch {
|
|
28504
|
-
return false;
|
|
28505
|
-
}
|
|
28506
|
-
}
|
|
28507
|
-
function classifySkillDestination(sourceDir, destinationDir) {
|
|
28508
|
-
if (!existsSync17(sourceDir)) return "source-missing";
|
|
28509
|
-
if (!isSymbolicLink(destinationDir) && pathsResolveToSameDirectory(sourceDir, destinationDir)) {
|
|
28510
|
-
return "source-directory";
|
|
28511
|
-
}
|
|
28512
|
-
if (linkPointsTo(sourceDir, destinationDir)) return "linked";
|
|
28513
|
-
if (!pathExists(destinationDir)) return "missing";
|
|
28514
|
-
if (isSymbolicLink(destinationDir)) return "broken";
|
|
28515
|
-
if (isZamSkillCopy(destinationDir)) return "stale-copy";
|
|
28516
|
-
return "unmanaged";
|
|
28517
|
-
}
|
|
28518
|
-
function wireSkills(cwd = process.cwd(), agents = parseSetupAgents(), opts = {}) {
|
|
28519
|
-
const results = [];
|
|
28520
|
-
const log = (message) => {
|
|
28521
|
-
if (!opts.quiet) console.log(message);
|
|
28522
|
-
};
|
|
28523
|
-
for (const { from, to, agents: pairAgents } of SKILL_PAIRS) {
|
|
28524
|
-
if (!pairAgents.some((agent) => agents.has(agent))) continue;
|
|
28525
|
-
const sourceDir = dirname10(from);
|
|
28526
|
-
const destinationDir = dirname10(join20(cwd, to));
|
|
28527
|
-
const label = dirname10(to);
|
|
28528
|
-
const state = classifySkillDestination(sourceDir, destinationDir);
|
|
28529
|
-
if (state === "source-missing") {
|
|
28530
|
-
if (!opts.quiet) {
|
|
28531
|
-
console.warn(` warn source not found, skipping: ${sourceDir}`);
|
|
28532
|
-
}
|
|
28533
|
-
results.push({
|
|
28534
|
-
source: sourceDir,
|
|
28535
|
-
destination: destinationDir,
|
|
28536
|
-
action: "skipped",
|
|
28537
|
-
reason: "source-not-found"
|
|
28538
|
-
});
|
|
28539
|
-
continue;
|
|
28540
|
-
}
|
|
28541
|
-
if (state === "source-directory") {
|
|
28542
|
-
log(` skip ${label} (package source)`);
|
|
28543
|
-
results.push({
|
|
28544
|
-
source: sourceDir,
|
|
28545
|
-
destination: destinationDir,
|
|
28546
|
-
action: "skipped",
|
|
28547
|
-
reason: "source-directory"
|
|
28548
|
-
});
|
|
28549
|
-
continue;
|
|
28550
|
-
}
|
|
28551
|
-
if (state === "linked") {
|
|
28552
|
-
log(` skip ${label} (already linked)`);
|
|
28553
|
-
results.push({
|
|
28554
|
-
source: sourceDir,
|
|
28555
|
-
destination: destinationDir,
|
|
28556
|
-
action: "skipped",
|
|
28557
|
-
reason: "already-linked"
|
|
28558
|
-
});
|
|
28559
|
-
continue;
|
|
28560
|
-
}
|
|
28561
|
-
const destinationExists = state !== "missing";
|
|
28562
|
-
const replaceExisting = destinationExists && (Boolean(opts.force) || state === "broken" || state === "stale-copy");
|
|
28563
|
-
if (destinationExists && !replaceExisting) {
|
|
28564
|
-
if (!opts.quiet) {
|
|
28565
|
-
console.warn(
|
|
28566
|
-
` warn ${label} already exists and is not managed by ZAM; use --force to replace it`
|
|
28567
|
-
);
|
|
28568
|
-
}
|
|
28569
|
-
results.push({
|
|
28570
|
-
source: sourceDir,
|
|
28571
|
-
destination: destinationDir,
|
|
28572
|
-
action: "skipped",
|
|
28573
|
-
reason: "unmanaged-destination"
|
|
28574
|
-
});
|
|
28575
|
-
continue;
|
|
28576
|
-
}
|
|
28577
|
-
const action = destinationExists ? "relinked" : "linked";
|
|
28578
|
-
if (opts.dryRun) {
|
|
28579
|
-
log(` would ${action === "linked" ? "link" : "relink"} ${label}`);
|
|
28580
|
-
} else {
|
|
28581
|
-
if (destinationExists) {
|
|
28582
|
-
rmSync2(destinationDir, { recursive: true, force: true });
|
|
28583
|
-
}
|
|
28584
|
-
mkdirSync13(dirname10(destinationDir), { recursive: true });
|
|
28585
|
-
symlinkSync(
|
|
28586
|
-
sourceDir,
|
|
28587
|
-
destinationDir,
|
|
28588
|
-
process.platform === "win32" ? "junction" : "dir"
|
|
28589
|
-
);
|
|
28590
|
-
log(` ${action === "linked" ? "link" : "relink"} ${label}`);
|
|
28591
|
-
}
|
|
28592
|
-
results.push({ source: sourceDir, destination: destinationDir, action });
|
|
28593
|
-
}
|
|
28594
|
-
return results;
|
|
28595
|
-
}
|
|
28596
|
-
function inspectSkillLinks(cwd = process.cwd(), agents = parseSetupAgents()) {
|
|
28597
|
-
const results = [];
|
|
28598
|
-
for (const { from, to, agents: pairAgents } of SKILL_PAIRS) {
|
|
28599
|
-
if (!pairAgents.some((agent) => agents.has(agent))) continue;
|
|
28600
|
-
const sourceDir = dirname10(from);
|
|
28601
|
-
const destinationDir = dirname10(join20(cwd, to));
|
|
28602
|
-
results.push({
|
|
28603
|
-
agents: pairAgents,
|
|
28604
|
-
source: sourceDir,
|
|
28605
|
-
destination: destinationDir,
|
|
28606
|
-
state: classifySkillDestination(sourceDir, destinationDir)
|
|
28607
|
-
});
|
|
28608
|
-
}
|
|
28609
|
-
return results;
|
|
28610
|
-
}
|
|
28611
|
-
function summarizeSkillLinkHealth(inspections) {
|
|
28612
|
-
if (inspections.some((item) => item.state === "unmanaged")) {
|
|
28613
|
-
return "unmanaged";
|
|
28614
|
-
}
|
|
28615
|
-
const repairable = ["missing", "broken", "stale-copy"];
|
|
28616
|
-
if (inspections.some((item) => repairable.includes(item.state))) {
|
|
28617
|
-
return "needs-repair";
|
|
28618
|
-
}
|
|
28619
|
-
return "healthy";
|
|
28620
|
-
}
|
|
28621
|
-
|
|
28622
28830
|
// src/cli/users/identity.ts
|
|
28623
28831
|
init_kernel();
|
|
28624
28832
|
async function ensureDefaultUser(db, preferredUserId) {
|
|
@@ -28642,13 +28850,13 @@ async function resolveUser(opts, db, resolveOpts) {
|
|
|
28642
28850
|
}
|
|
28643
28851
|
|
|
28644
28852
|
// src/cli/workspaces/backup.ts
|
|
28645
|
-
import { mkdirSync as
|
|
28646
|
-
import { join as
|
|
28853
|
+
import { mkdirSync as mkdirSync15 } from "fs";
|
|
28854
|
+
import { join as join22 } from "path";
|
|
28647
28855
|
async function backupDatabaseTo(db, targetDir) {
|
|
28648
|
-
const backupDir =
|
|
28649
|
-
|
|
28856
|
+
const backupDir = join22(targetDir, "zam-backups");
|
|
28857
|
+
mkdirSync15(backupDir, { recursive: true });
|
|
28650
28858
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
28651
|
-
const dest =
|
|
28859
|
+
const dest = join22(backupDir, `zam-${stamp}.db`);
|
|
28652
28860
|
await db.exec(`VACUUM INTO '${dest.replace(/'/g, "''")}'`);
|
|
28653
28861
|
return dest;
|
|
28654
28862
|
}
|
|
@@ -28779,20 +28987,20 @@ bridgeCommand.command("workspace-info").description("Report the workspace dir, i
|
|
|
28779
28987
|
activeWorkspace,
|
|
28780
28988
|
workspaceDir: activeWorkspace.path,
|
|
28781
28989
|
defaultWorkspaceDir: defaultWorkspaceDir(),
|
|
28782
|
-
dataDir:
|
|
28990
|
+
dataDir: join23(homedir15(), ".zam")
|
|
28783
28991
|
});
|
|
28784
28992
|
});
|
|
28785
28993
|
});
|
|
28786
28994
|
function provisionConfiguredWorkspaces() {
|
|
28787
28995
|
return getConfiguredWorkspaces().flatMap(
|
|
28788
|
-
(workspace) =>
|
|
28996
|
+
(workspace) => existsSync20(workspace.path) ? wireSkills(workspace.path, parseSetupAgents(), { quiet: true }) : []
|
|
28789
28997
|
);
|
|
28790
28998
|
}
|
|
28791
28999
|
function buildWorkspaceLinkHealth(workspaces) {
|
|
28792
29000
|
const agents = parseSetupAgents();
|
|
28793
29001
|
const map = {};
|
|
28794
29002
|
for (const workspace of workspaces) {
|
|
28795
|
-
if (!
|
|
29003
|
+
if (!existsSync20(workspace.path)) continue;
|
|
28796
29004
|
const links = inspectSkillLinks(workspace.path, agents);
|
|
28797
29005
|
map[workspace.id] = {
|
|
28798
29006
|
health: summarizeSkillLinkHealth(links),
|
|
@@ -28822,7 +29030,7 @@ bridgeCommand.command("workspace-list").description("List configured ZAM workspa
|
|
|
28822
29030
|
activeWorkspace,
|
|
28823
29031
|
workspaceDir: activeWorkspace.path,
|
|
28824
29032
|
defaultWorkspaceDir: defaultWorkspaceDir(),
|
|
28825
|
-
dataDir:
|
|
29033
|
+
dataDir: join23(homedir15(), ".zam"),
|
|
28826
29034
|
linkHealth: buildWorkspaceLinkHealth(workspaces)
|
|
28827
29035
|
});
|
|
28828
29036
|
});
|
|
@@ -28837,7 +29045,7 @@ bridgeCommand.command("workspace-repair-links").description(
|
|
|
28837
29045
|
if (!id) jsonError("A non-empty --id is required");
|
|
28838
29046
|
const workspace = getConfiguredWorkspaces().find((item) => item.id === id);
|
|
28839
29047
|
if (!workspace) jsonError(`Workspace "${id}" is not configured`);
|
|
28840
|
-
if (!
|
|
29048
|
+
if (!existsSync20(workspace.path)) {
|
|
28841
29049
|
jsonError(`Workspace path does not exist: ${workspace.path}`);
|
|
28842
29050
|
}
|
|
28843
29051
|
const agents = parseSetupAgents(opts.agents);
|
|
@@ -28868,8 +29076,8 @@ function parseBridgeWorkspaceKind(value) {
|
|
|
28868
29076
|
bridgeCommand.command("workspace-add").description("Register an existing directory as a ZAM workspace (JSON)").requiredOption("--path <dir>", "Existing workspace/repository directory").option("--id <id>", "Workspace id").option("--label <label>", "Human-readable label").option("--kind <kind>", "Workspace kind", "custom").action(async (opts) => {
|
|
28869
29077
|
const raw = String(opts.path ?? "").trim();
|
|
28870
29078
|
if (!raw) jsonError("A non-empty --path is required");
|
|
28871
|
-
const path =
|
|
28872
|
-
if (!
|
|
29079
|
+
const path = resolve6(raw);
|
|
29080
|
+
if (!existsSync20(path)) jsonError(`Workspace path does not exist: ${path}`);
|
|
28873
29081
|
const id = opts.id ? String(opts.id).trim() : void 0;
|
|
28874
29082
|
if (opts.id && !id) jsonError("A non-empty --id is required");
|
|
28875
29083
|
const kind = parseBridgeWorkspaceKind(opts.kind);
|
|
@@ -28913,8 +29121,8 @@ bridgeCommand.command("workspace-remove").description("Unregister a ZAM workspac
|
|
|
28913
29121
|
bridgeCommand.command("set-workspace-dir").description("Set the personal workspace directory (JSON)").requiredOption("--dir <path>", "Path to the workspace directory").action(async (opts) => {
|
|
28914
29122
|
const raw = String(opts.dir ?? "").trim();
|
|
28915
29123
|
if (!raw) jsonError("A non-empty --dir is required");
|
|
28916
|
-
const dir =
|
|
28917
|
-
if (!
|
|
29124
|
+
const dir = resolve6(raw);
|
|
29125
|
+
if (!existsSync20(dir)) jsonError(`Workspace path does not exist: ${dir}`);
|
|
28918
29126
|
const skillLinks = wireSkills(dir, parseSetupAgents(), { quiet: true });
|
|
28919
29127
|
await withDb2(async (db) => {
|
|
28920
29128
|
const workspace = await activateWorkspacePath(db, dir);
|
|
@@ -28977,7 +29185,7 @@ bridgeCommand.command("agent-open").description("Launch an agent harness in the
|
|
|
28977
29185
|
jsonError(`Workspace is not configured: ${opts.workspace}`);
|
|
28978
29186
|
}
|
|
28979
29187
|
const activeWorkspace = await ensureActiveWorkspace(db);
|
|
28980
|
-
const workspace = opts.dir ?
|
|
29188
|
+
const workspace = opts.dir ? existsSync20(opts.dir) ? opts.dir : homedir15() : existingWorkspaceDirOrHome(configuredWorkspace ?? activeWorkspace);
|
|
28981
29189
|
launchHarness(harness, {
|
|
28982
29190
|
executable,
|
|
28983
29191
|
workspace,
|
|
@@ -29349,7 +29557,7 @@ bridgeCommand.command("discover-skills").description(
|
|
|
29349
29557
|
"20"
|
|
29350
29558
|
).action(async (opts) => {
|
|
29351
29559
|
try {
|
|
29352
|
-
const monitorDir =
|
|
29560
|
+
const monitorDir = join23(homedir15(), ".zam", "monitor");
|
|
29353
29561
|
let files;
|
|
29354
29562
|
try {
|
|
29355
29563
|
files = readdirSync2(monitorDir).filter((f) => f.endsWith(".jsonl"));
|
|
@@ -29362,7 +29570,7 @@ bridgeCommand.command("discover-skills").description(
|
|
|
29362
29570
|
return;
|
|
29363
29571
|
}
|
|
29364
29572
|
const limit = Number(opts.limit);
|
|
29365
|
-
const sorted = files.map((f) => ({ name: f, path:
|
|
29573
|
+
const sorted = files.map((f) => ({ name: f, path: join23(monitorDir, f) })).sort((a, b) => b.name.localeCompare(a.name)).slice(0, limit);
|
|
29366
29574
|
const sessionCommands = /* @__PURE__ */ new Map();
|
|
29367
29575
|
for (const file of sorted) {
|
|
29368
29576
|
const sessionId = file.name.replace(".jsonl", "");
|
|
@@ -29474,7 +29682,7 @@ bridgeCommand.command("observe-ui-snapshot").description(
|
|
|
29474
29682
|
});
|
|
29475
29683
|
function resolveWindowsPowerShell() {
|
|
29476
29684
|
try {
|
|
29477
|
-
|
|
29685
|
+
execFileSync5("where.exe", ["pwsh.exe"], { stdio: "ignore" });
|
|
29478
29686
|
return "pwsh";
|
|
29479
29687
|
} catch {
|
|
29480
29688
|
return "powershell";
|
|
@@ -29489,7 +29697,7 @@ function captureScreenshot(outputPath, hwnd, processName) {
|
|
|
29489
29697
|
throw new Error(`Invalid process name format: ${processName}`);
|
|
29490
29698
|
}
|
|
29491
29699
|
if (platform === "win32") {
|
|
29492
|
-
const stdout =
|
|
29700
|
+
const stdout = execFileSync5(
|
|
29493
29701
|
resolveWindowsPowerShell(),
|
|
29494
29702
|
[
|
|
29495
29703
|
"-NoProfile",
|
|
@@ -29802,13 +30010,13 @@ Write-CaptureResult "fullscreen" $hwndVal $matchedBy
|
|
|
29802
30010
|
} else if (platform === "darwin") {
|
|
29803
30011
|
if (hwnd) {
|
|
29804
30012
|
const parsedHwnd = hwnd.startsWith("0x") ? parseInt(hwnd, 16) : parseInt(hwnd, 10);
|
|
29805
|
-
|
|
30013
|
+
execFileSync5("screencapture", ["-l", String(parsedHwnd), outputPath], {
|
|
29806
30014
|
stdio: "pipe"
|
|
29807
30015
|
});
|
|
29808
30016
|
return { method: "screencapture-window", target: null };
|
|
29809
30017
|
} else if (processName) {
|
|
29810
30018
|
try {
|
|
29811
|
-
const windowId =
|
|
30019
|
+
const windowId = execFileSync5(
|
|
29812
30020
|
"osascript",
|
|
29813
30021
|
[
|
|
29814
30022
|
"-e",
|
|
@@ -29817,17 +30025,17 @@ Write-CaptureResult "fullscreen" $hwndVal $matchedBy
|
|
|
29817
30025
|
{ encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] }
|
|
29818
30026
|
).trim();
|
|
29819
30027
|
if (windowId && /^\d+$/.test(windowId)) {
|
|
29820
|
-
|
|
30028
|
+
execFileSync5("screencapture", ["-l", windowId, outputPath], {
|
|
29821
30029
|
stdio: "pipe"
|
|
29822
30030
|
});
|
|
29823
30031
|
return { method: "screencapture-window", target: null };
|
|
29824
30032
|
}
|
|
29825
30033
|
} catch {
|
|
29826
30034
|
}
|
|
29827
|
-
|
|
30035
|
+
execFileSync5("screencapture", ["-x", outputPath], { stdio: "pipe" });
|
|
29828
30036
|
return { method: "screencapture-full", target: null };
|
|
29829
30037
|
} else {
|
|
29830
|
-
|
|
30038
|
+
execFileSync5("screencapture", ["-x", outputPath], { stdio: "pipe" });
|
|
29831
30039
|
return { method: "screencapture-full", target: null };
|
|
29832
30040
|
}
|
|
29833
30041
|
} else {
|
|
@@ -29864,7 +30072,7 @@ bridgeCommand.command("capture-ui").description("Capture a screenshot for agent-
|
|
|
29864
30072
|
return;
|
|
29865
30073
|
}
|
|
29866
30074
|
}
|
|
29867
|
-
const outputPath = opts.image ?? opts.output ??
|
|
30075
|
+
const outputPath = opts.image ?? opts.output ?? join23(tmpdir3(), `zam-capture-${randomBytes2(4).toString("hex")}.png`);
|
|
29868
30076
|
const captureResult = isProvided ? { method: "provided", target: null } : captureScreenshot(outputPath, opts.hwnd, opts.processName);
|
|
29869
30077
|
if (!isProvided) {
|
|
29870
30078
|
const post = decidePostCapture(policy, {
|
|
@@ -29892,7 +30100,7 @@ bridgeCommand.command("capture-ui").description("Capture a screenshot for agent-
|
|
|
29892
30100
|
return;
|
|
29893
30101
|
}
|
|
29894
30102
|
}
|
|
29895
|
-
const imageBytes =
|
|
30103
|
+
const imageBytes = readFileSync17(outputPath);
|
|
29896
30104
|
const base64 = imageBytes.toString("base64");
|
|
29897
30105
|
jsonOut({
|
|
29898
30106
|
sessionId: opts.session ?? null,
|
|
@@ -29919,11 +30127,11 @@ bridgeCommand.command("start-recording").description("Start screen recording in
|
|
|
29919
30127
|
return;
|
|
29920
30128
|
}
|
|
29921
30129
|
const sessionId = opts.session;
|
|
29922
|
-
const statePath =
|
|
30130
|
+
const statePath = join23(tmpdir3(), `zam-recording-${sessionId}.json`);
|
|
29923
30131
|
const defaultExt = platform === "win32" ? ".mkv" : ".mov";
|
|
29924
|
-
const outputPath = opts.output ??
|
|
29925
|
-
const { existsSync:
|
|
29926
|
-
if (
|
|
30132
|
+
const outputPath = opts.output ?? join23(tmpdir3(), `zam-recording-${sessionId}${defaultExt}`);
|
|
30133
|
+
const { existsSync: existsSync22, writeFileSync: writeFileSync13, openSync, closeSync } = await import("fs");
|
|
30134
|
+
if (existsSync22(statePath)) {
|
|
29927
30135
|
jsonOut({
|
|
29928
30136
|
sessionId,
|
|
29929
30137
|
started: false,
|
|
@@ -29931,7 +30139,7 @@ bridgeCommand.command("start-recording").description("Start screen recording in
|
|
|
29931
30139
|
});
|
|
29932
30140
|
return;
|
|
29933
30141
|
}
|
|
29934
|
-
const logPath =
|
|
30142
|
+
const logPath = join23(tmpdir3(), `zam-recording-${sessionId}.log`);
|
|
29935
30143
|
let logFd;
|
|
29936
30144
|
try {
|
|
29937
30145
|
logFd = openSync(logPath, "w");
|
|
@@ -29977,7 +30185,7 @@ bridgeCommand.command("start-recording").description("Start screen recording in
|
|
|
29977
30185
|
}
|
|
29978
30186
|
child.unref();
|
|
29979
30187
|
if (child.pid) {
|
|
29980
|
-
|
|
30188
|
+
writeFileSync13(
|
|
29981
30189
|
statePath,
|
|
29982
30190
|
JSON.stringify({
|
|
29983
30191
|
pid: child.pid,
|
|
@@ -30013,9 +30221,9 @@ bridgeCommand.command("stop-recording").description(
|
|
|
30013
30221
|
return;
|
|
30014
30222
|
}
|
|
30015
30223
|
const sessionId = opts.session;
|
|
30016
|
-
const statePath =
|
|
30017
|
-
const { existsSync:
|
|
30018
|
-
if (!
|
|
30224
|
+
const statePath = join23(tmpdir3(), `zam-recording-${sessionId}.json`);
|
|
30225
|
+
const { existsSync: existsSync22, readFileSync: readFileSync19, rmSync: rmSync4 } = await import("fs");
|
|
30226
|
+
if (!existsSync22(statePath)) {
|
|
30019
30227
|
jsonOut({
|
|
30020
30228
|
sessionId,
|
|
30021
30229
|
stopped: false,
|
|
@@ -30023,7 +30231,7 @@ bridgeCommand.command("stop-recording").description(
|
|
|
30023
30231
|
});
|
|
30024
30232
|
return;
|
|
30025
30233
|
}
|
|
30026
|
-
const state = JSON.parse(
|
|
30234
|
+
const state = JSON.parse(readFileSync19(statePath, "utf8"));
|
|
30027
30235
|
const { pid, outputPath } = state;
|
|
30028
30236
|
try {
|
|
30029
30237
|
process.kill(pid, "SIGINT");
|
|
@@ -30039,7 +30247,7 @@ bridgeCommand.command("stop-recording").description(
|
|
|
30039
30247
|
};
|
|
30040
30248
|
let attempts = 0;
|
|
30041
30249
|
while (isProcessRunning(pid) && attempts < 20) {
|
|
30042
|
-
await new Promise((
|
|
30250
|
+
await new Promise((resolve7) => setTimeout(resolve7, 250));
|
|
30043
30251
|
attempts++;
|
|
30044
30252
|
}
|
|
30045
30253
|
if (isProcessRunning(pid)) {
|
|
@@ -30052,7 +30260,7 @@ bridgeCommand.command("stop-recording").description(
|
|
|
30052
30260
|
rmSync4(statePath, { force: true });
|
|
30053
30261
|
} catch {
|
|
30054
30262
|
}
|
|
30055
|
-
if (!
|
|
30263
|
+
if (!existsSync22(outputPath)) {
|
|
30056
30264
|
jsonOut({
|
|
30057
30265
|
sessionId,
|
|
30058
30266
|
stopped: false,
|
|
@@ -30482,7 +30690,7 @@ bridgeCommand.command("cloud-model-hint").description("Suggest a cloud model for
|
|
|
30482
30690
|
});
|
|
30483
30691
|
bridgeCommand.command("local-llm-hints").description("Detect installed local LLM servers and suggest defaults (JSON)").action(() => {
|
|
30484
30692
|
const profile = getSystemProfile();
|
|
30485
|
-
const flmInstalled = hasCommand("flm") ||
|
|
30693
|
+
const flmInstalled = hasCommand("flm") || existsSync20("C:\\Program Files\\flm\\flm.exe");
|
|
30486
30694
|
const ollamaInstalled = isOllamaInstalled();
|
|
30487
30695
|
const runners = [
|
|
30488
30696
|
{ id: "flm", label: "FastFlowLM", installed: flmInstalled },
|
|
@@ -30714,13 +30922,15 @@ bridgeCommand.command("desktop-bootstrap").description("Initialize first-run des
|
|
|
30714
30922
|
const userId = await ensureDefaultUser(db, opts.user);
|
|
30715
30923
|
const { enabled, url, model, locale } = await getLlmConfig(db);
|
|
30716
30924
|
const { workspaceDir, activeWorkspaceId, skillLinks } = await ensureDesktopWorkspace(db);
|
|
30925
|
+
const cli = installCliShim();
|
|
30717
30926
|
jsonOut({
|
|
30718
30927
|
userId,
|
|
30719
30928
|
locale,
|
|
30720
30929
|
llm: { enabled, url, model },
|
|
30721
30930
|
activeWorkspaceId,
|
|
30722
30931
|
workspaceDir,
|
|
30723
|
-
skillLinks
|
|
30932
|
+
skillLinks,
|
|
30933
|
+
cli
|
|
30724
30934
|
});
|
|
30725
30935
|
});
|
|
30726
30936
|
});
|
|
@@ -30737,6 +30947,22 @@ bridgeCommand.command("get-settings").description("Get active ZAM settings (JSON
|
|
|
30737
30947
|
});
|
|
30738
30948
|
});
|
|
30739
30949
|
});
|
|
30950
|
+
bridgeCommand.command("install-repair").description(
|
|
30951
|
+
"Verify and repair this machine's ZAM installation: CLI shim + PATH, workspace skill links, agent configs and companion extensions (JSON)"
|
|
30952
|
+
).option(
|
|
30953
|
+
"--if-version-changed",
|
|
30954
|
+
"Only run when the app version differs from the last repaired one; reports skipped:true otherwise"
|
|
30955
|
+
).action((opts) => {
|
|
30956
|
+
try {
|
|
30957
|
+
jsonOut(
|
|
30958
|
+
performInstallRepair({
|
|
30959
|
+
ifVersionChanged: Boolean(opts.ifVersionChanged)
|
|
30960
|
+
})
|
|
30961
|
+
);
|
|
30962
|
+
} catch (err) {
|
|
30963
|
+
jsonError(err.message);
|
|
30964
|
+
}
|
|
30965
|
+
});
|
|
30740
30966
|
bridgeCommand.command("agent-harness-status").description(
|
|
30741
30967
|
"Detect installed agent harnesses and their ZAM MCP configuration state (JSON)"
|
|
30742
30968
|
).action(() => {
|
|
@@ -32393,11 +32619,11 @@ bridgeCommand.command("serve").description("Start the persistent JSON-RPC stdin/
|
|
|
32393
32619
|
|
|
32394
32620
|
// src/cli/commands/mcp.ts
|
|
32395
32621
|
var __dirname = dirname11(fileURLToPath6(import.meta.url));
|
|
32396
|
-
var pkgPath =
|
|
32397
|
-
if (!
|
|
32398
|
-
pkgPath =
|
|
32622
|
+
var pkgPath = join24(__dirname, "..", "..", "package.json");
|
|
32623
|
+
if (!existsSync21(pkgPath)) {
|
|
32624
|
+
pkgPath = join24(__dirname, "..", "..", "..", "package.json");
|
|
32399
32625
|
}
|
|
32400
|
-
var pkg = JSON.parse(
|
|
32626
|
+
var pkg = JSON.parse(readFileSync18(pkgPath, "utf-8"));
|
|
32401
32627
|
var STUDIO_RESOURCE_URI = "ui://zam/studio";
|
|
32402
32628
|
var RECALL_RESOURCE_URI = "ui://zam/recall";
|
|
32403
32629
|
var GRAPH_RESOURCE_URI = "ui://zam/graph";
|
|
@@ -32422,13 +32648,13 @@ var STUDIO_BRIDGE_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
32422
32648
|
function loadPanelHtml(fileName, placeholderTitle) {
|
|
32423
32649
|
const candidates = [
|
|
32424
32650
|
// dist/cli/commands/mcp.js → dist/ui/
|
|
32425
|
-
|
|
32651
|
+
join24(__dirname, "..", "..", "ui", fileName),
|
|
32426
32652
|
// src/cli/commands/mcp.ts via tsx → <repo>/dist/ui/
|
|
32427
|
-
|
|
32653
|
+
join24(__dirname, "..", "..", "..", "dist", "ui", fileName)
|
|
32428
32654
|
];
|
|
32429
32655
|
for (const candidate of candidates) {
|
|
32430
|
-
if (
|
|
32431
|
-
return
|
|
32656
|
+
if (existsSync21(candidate)) {
|
|
32657
|
+
return readFileSync18(candidate, "utf-8");
|
|
32432
32658
|
}
|
|
32433
32659
|
}
|
|
32434
32660
|
return `<!doctype html>
|