zam-core 0.10.8 → 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 +1318 -1090
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/commands/mcp.js +509 -281
- 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.8.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);
|
|
@@ -11041,6 +11052,127 @@ function inspectConnectHarnesses(deps = {}) {
|
|
|
11041
11052
|
return { zamOnPath: Boolean(foundZam), harnesses };
|
|
11042
11053
|
}
|
|
11043
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
|
+
|
|
11044
11176
|
// src/cli/curriculum/breadcrumb.ts
|
|
11045
11177
|
init_kernel();
|
|
11046
11178
|
var LAST_SELECTION_KEY = "curriculum.lastSelection";
|
|
@@ -27727,6 +27859,297 @@ function getCurriculumProvider(id) {
|
|
|
27727
27859
|
return CURRICULUM_PROVIDERS.find((provider) => provider.id === id);
|
|
27728
27860
|
}
|
|
27729
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
|
+
|
|
27730
28153
|
// src/cli/llm/capability-probe.ts
|
|
27731
28154
|
init_kernel();
|
|
27732
28155
|
var EMBEDDING_MODEL_HINTS = [
|
|
@@ -27851,9 +28274,9 @@ function validateModelSave(entry, probe, now = () => (/* @__PURE__ */ new Date()
|
|
|
27851
28274
|
// src/cli/llm/vision.ts
|
|
27852
28275
|
init_kernel();
|
|
27853
28276
|
import { randomBytes } from "crypto";
|
|
27854
|
-
import { readFileSync as
|
|
28277
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
27855
28278
|
import { tmpdir as tmpdir2 } from "os";
|
|
27856
|
-
import { basename as
|
|
28279
|
+
import { basename as basename5, join as join21 } from "path";
|
|
27857
28280
|
var LANGUAGE_NAMES2 = {
|
|
27858
28281
|
en: "English",
|
|
27859
28282
|
de: "German",
|
|
@@ -27889,13 +28312,13 @@ async function observeUiSnapshotViaLLM(db, input) {
|
|
|
27889
28312
|
const imageUrls = [];
|
|
27890
28313
|
const isVideo = /\.(mp4|mov|m4v|avi|mkv|webm)$/i.test(input.imagePath);
|
|
27891
28314
|
if (isVideo) {
|
|
27892
|
-
const { mkdirSync:
|
|
28315
|
+
const { mkdirSync: mkdirSync16, readdirSync: readdirSync3, rmSync: rmSync4 } = await import("fs");
|
|
27893
28316
|
const { execSync: execSync5 } = await import("child_process");
|
|
27894
|
-
const tempDir =
|
|
28317
|
+
const tempDir = join21(
|
|
27895
28318
|
tmpdir2(),
|
|
27896
28319
|
`zam-frames-${randomBytes(4).toString("hex")}`
|
|
27897
28320
|
);
|
|
27898
|
-
|
|
28321
|
+
mkdirSync16(tempDir, { recursive: true });
|
|
27899
28322
|
try {
|
|
27900
28323
|
execSync5(
|
|
27901
28324
|
`ffmpeg -i "${input.imagePath}" -vf "fps=1/3,scale=1280:-1" -vsync vfr "${tempDir}/frame_%03d.png"`,
|
|
@@ -27924,7 +28347,7 @@ async function observeUiSnapshotViaLLM(db, input) {
|
|
|
27924
28347
|
}
|
|
27925
28348
|
}
|
|
27926
28349
|
for (const file of sampledFiles) {
|
|
27927
|
-
const bytes =
|
|
28350
|
+
const bytes = readFileSync16(join21(tempDir, file));
|
|
27928
28351
|
imageUrls.push(`data:image/png;base64,${bytes.toString("base64")}`);
|
|
27929
28352
|
}
|
|
27930
28353
|
} finally {
|
|
@@ -27934,7 +28357,7 @@ async function observeUiSnapshotViaLLM(db, input) {
|
|
|
27934
28357
|
}
|
|
27935
28358
|
}
|
|
27936
28359
|
} else {
|
|
27937
|
-
const imageBytes =
|
|
28360
|
+
const imageBytes = readFileSync16(input.imagePath);
|
|
27938
28361
|
const ext = input.imagePath.split(".").pop()?.toLowerCase();
|
|
27939
28362
|
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : "image/png";
|
|
27940
28363
|
imageUrls.push(`data:${mime};base64,${imageBytes.toString("base64")}`);
|
|
@@ -28172,7 +28595,7 @@ function buildReport(input, draft) {
|
|
|
28172
28595
|
evidence: [
|
|
28173
28596
|
{
|
|
28174
28597
|
type: "keyframe",
|
|
28175
|
-
ref: input.evidenceRef ??
|
|
28598
|
+
ref: input.evidenceRef ?? basename5(input.imagePath),
|
|
28176
28599
|
redacted: input.redacted ?? false
|
|
28177
28600
|
}
|
|
28178
28601
|
],
|
|
@@ -28194,7 +28617,7 @@ function uncertainReport(input, summary) {
|
|
|
28194
28617
|
evidence: [
|
|
28195
28618
|
{
|
|
28196
28619
|
type: "keyframe",
|
|
28197
|
-
ref: input.evidenceRef ??
|
|
28620
|
+
ref: input.evidenceRef ?? basename5(input.imagePath),
|
|
28198
28621
|
redacted: input.redacted ?? false
|
|
28199
28622
|
}
|
|
28200
28623
|
],
|
|
@@ -28404,219 +28827,6 @@ async function withProviderScope(machine, action) {
|
|
|
28404
28827
|
await withDb(action);
|
|
28405
28828
|
}
|
|
28406
28829
|
|
|
28407
|
-
// src/cli/provisioning/index.ts
|
|
28408
|
-
import {
|
|
28409
|
-
existsSync as existsSync17,
|
|
28410
|
-
lstatSync as lstatSync2,
|
|
28411
|
-
mkdirSync as mkdirSync13,
|
|
28412
|
-
readFileSync as readFileSync15,
|
|
28413
|
-
realpathSync,
|
|
28414
|
-
rmSync as rmSync2,
|
|
28415
|
-
symlinkSync,
|
|
28416
|
-
writeFileSync as writeFileSync11
|
|
28417
|
-
} from "fs";
|
|
28418
|
-
import { basename as basename5, dirname as dirname10, join as join20 } from "path";
|
|
28419
|
-
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
28420
|
-
var packageRoot3 = [
|
|
28421
|
-
fileURLToPath5(new URL("../..", import.meta.url)),
|
|
28422
|
-
fileURLToPath5(new URL("../../..", import.meta.url))
|
|
28423
|
-
].find((candidate) => existsSync17(join20(candidate, "package.json"))) ?? fileURLToPath5(new URL("../..", import.meta.url));
|
|
28424
|
-
var ALL_SETUP_AGENTS = ["claude", "copilot", "codex", "agent"];
|
|
28425
|
-
var SKILL_PAIRS = [
|
|
28426
|
-
{
|
|
28427
|
-
from: join20(packageRoot3, ".claude", "skills", "zam", "SKILL.md"),
|
|
28428
|
-
to: join20(".claude", "skills", "zam", "SKILL.md"),
|
|
28429
|
-
agents: ["claude", "copilot"]
|
|
28430
|
-
},
|
|
28431
|
-
{
|
|
28432
|
-
from: join20(packageRoot3, ".agent", "skills", "zam", "SKILL.md"),
|
|
28433
|
-
to: join20(".agent", "skills", "zam", "SKILL.md"),
|
|
28434
|
-
agents: ["agent"]
|
|
28435
|
-
},
|
|
28436
|
-
{
|
|
28437
|
-
from: join20(packageRoot3, ".agents", "skills", "zam", "SKILL.md"),
|
|
28438
|
-
to: join20(".agents", "skills", "zam", "SKILL.md"),
|
|
28439
|
-
agents: ["codex"]
|
|
28440
|
-
}
|
|
28441
|
-
];
|
|
28442
|
-
function parseSetupAgents(value) {
|
|
28443
|
-
if (!value || value.trim().toLowerCase() === "all") {
|
|
28444
|
-
return new Set(ALL_SETUP_AGENTS);
|
|
28445
|
-
}
|
|
28446
|
-
const aliases = {
|
|
28447
|
-
claude: ["claude"],
|
|
28448
|
-
copilot: ["copilot"],
|
|
28449
|
-
codex: ["codex"],
|
|
28450
|
-
agent: ["agent"],
|
|
28451
|
-
opencode: ["agent"]
|
|
28452
|
-
};
|
|
28453
|
-
const selected = /* @__PURE__ */ new Set();
|
|
28454
|
-
for (const raw of value.split(",")) {
|
|
28455
|
-
const key = raw.trim().toLowerCase();
|
|
28456
|
-
const mapped = aliases[key];
|
|
28457
|
-
if (!mapped) {
|
|
28458
|
-
throw new Error(
|
|
28459
|
-
`Unknown agent "${raw}". Use: all, claude, copilot, codex, agent.`
|
|
28460
|
-
);
|
|
28461
|
-
}
|
|
28462
|
-
for (const item of mapped) selected.add(item);
|
|
28463
|
-
}
|
|
28464
|
-
return selected;
|
|
28465
|
-
}
|
|
28466
|
-
function pathExists(path) {
|
|
28467
|
-
try {
|
|
28468
|
-
lstatSync2(path);
|
|
28469
|
-
return true;
|
|
28470
|
-
} catch {
|
|
28471
|
-
return false;
|
|
28472
|
-
}
|
|
28473
|
-
}
|
|
28474
|
-
function isSymbolicLink(path) {
|
|
28475
|
-
try {
|
|
28476
|
-
return lstatSync2(path).isSymbolicLink();
|
|
28477
|
-
} catch {
|
|
28478
|
-
return false;
|
|
28479
|
-
}
|
|
28480
|
-
}
|
|
28481
|
-
function comparableRealPath(path) {
|
|
28482
|
-
const real = realpathSync(path);
|
|
28483
|
-
return process.platform === "win32" ? real.toLowerCase() : real;
|
|
28484
|
-
}
|
|
28485
|
-
function pathsResolveToSameDirectory(sourceDir, destinationDir) {
|
|
28486
|
-
try {
|
|
28487
|
-
return comparableRealPath(destinationDir) === comparableRealPath(sourceDir);
|
|
28488
|
-
} catch {
|
|
28489
|
-
return false;
|
|
28490
|
-
}
|
|
28491
|
-
}
|
|
28492
|
-
function linkPointsTo(sourceDir, destinationDir) {
|
|
28493
|
-
return isSymbolicLink(destinationDir) && pathsResolveToSameDirectory(sourceDir, destinationDir);
|
|
28494
|
-
}
|
|
28495
|
-
function isZamSkillCopy(destinationDir) {
|
|
28496
|
-
try {
|
|
28497
|
-
if (!lstatSync2(destinationDir).isDirectory()) return false;
|
|
28498
|
-
const skillFile = join20(destinationDir, "SKILL.md");
|
|
28499
|
-
if (!existsSync17(skillFile)) return false;
|
|
28500
|
-
return /^name:\s*zam\s*$/m.test(readFileSync15(skillFile, "utf8"));
|
|
28501
|
-
} catch {
|
|
28502
|
-
return false;
|
|
28503
|
-
}
|
|
28504
|
-
}
|
|
28505
|
-
function classifySkillDestination(sourceDir, destinationDir) {
|
|
28506
|
-
if (!existsSync17(sourceDir)) return "source-missing";
|
|
28507
|
-
if (!isSymbolicLink(destinationDir) && pathsResolveToSameDirectory(sourceDir, destinationDir)) {
|
|
28508
|
-
return "source-directory";
|
|
28509
|
-
}
|
|
28510
|
-
if (linkPointsTo(sourceDir, destinationDir)) return "linked";
|
|
28511
|
-
if (!pathExists(destinationDir)) return "missing";
|
|
28512
|
-
if (isSymbolicLink(destinationDir)) return "broken";
|
|
28513
|
-
if (isZamSkillCopy(destinationDir)) return "stale-copy";
|
|
28514
|
-
return "unmanaged";
|
|
28515
|
-
}
|
|
28516
|
-
function wireSkills(cwd = process.cwd(), agents = parseSetupAgents(), opts = {}) {
|
|
28517
|
-
const results = [];
|
|
28518
|
-
const log = (message) => {
|
|
28519
|
-
if (!opts.quiet) console.log(message);
|
|
28520
|
-
};
|
|
28521
|
-
for (const { from, to, agents: pairAgents } of SKILL_PAIRS) {
|
|
28522
|
-
if (!pairAgents.some((agent) => agents.has(agent))) continue;
|
|
28523
|
-
const sourceDir = dirname10(from);
|
|
28524
|
-
const destinationDir = dirname10(join20(cwd, to));
|
|
28525
|
-
const label = dirname10(to);
|
|
28526
|
-
const state = classifySkillDestination(sourceDir, destinationDir);
|
|
28527
|
-
if (state === "source-missing") {
|
|
28528
|
-
if (!opts.quiet) {
|
|
28529
|
-
console.warn(` warn source not found, skipping: ${sourceDir}`);
|
|
28530
|
-
}
|
|
28531
|
-
results.push({
|
|
28532
|
-
source: sourceDir,
|
|
28533
|
-
destination: destinationDir,
|
|
28534
|
-
action: "skipped",
|
|
28535
|
-
reason: "source-not-found"
|
|
28536
|
-
});
|
|
28537
|
-
continue;
|
|
28538
|
-
}
|
|
28539
|
-
if (state === "source-directory") {
|
|
28540
|
-
log(` skip ${label} (package source)`);
|
|
28541
|
-
results.push({
|
|
28542
|
-
source: sourceDir,
|
|
28543
|
-
destination: destinationDir,
|
|
28544
|
-
action: "skipped",
|
|
28545
|
-
reason: "source-directory"
|
|
28546
|
-
});
|
|
28547
|
-
continue;
|
|
28548
|
-
}
|
|
28549
|
-
if (state === "linked") {
|
|
28550
|
-
log(` skip ${label} (already linked)`);
|
|
28551
|
-
results.push({
|
|
28552
|
-
source: sourceDir,
|
|
28553
|
-
destination: destinationDir,
|
|
28554
|
-
action: "skipped",
|
|
28555
|
-
reason: "already-linked"
|
|
28556
|
-
});
|
|
28557
|
-
continue;
|
|
28558
|
-
}
|
|
28559
|
-
const destinationExists = state !== "missing";
|
|
28560
|
-
const replaceExisting = destinationExists && (Boolean(opts.force) || state === "broken" || state === "stale-copy");
|
|
28561
|
-
if (destinationExists && !replaceExisting) {
|
|
28562
|
-
if (!opts.quiet) {
|
|
28563
|
-
console.warn(
|
|
28564
|
-
` warn ${label} already exists and is not managed by ZAM; use --force to replace it`
|
|
28565
|
-
);
|
|
28566
|
-
}
|
|
28567
|
-
results.push({
|
|
28568
|
-
source: sourceDir,
|
|
28569
|
-
destination: destinationDir,
|
|
28570
|
-
action: "skipped",
|
|
28571
|
-
reason: "unmanaged-destination"
|
|
28572
|
-
});
|
|
28573
|
-
continue;
|
|
28574
|
-
}
|
|
28575
|
-
const action = destinationExists ? "relinked" : "linked";
|
|
28576
|
-
if (opts.dryRun) {
|
|
28577
|
-
log(` would ${action === "linked" ? "link" : "relink"} ${label}`);
|
|
28578
|
-
} else {
|
|
28579
|
-
if (destinationExists) {
|
|
28580
|
-
rmSync2(destinationDir, { recursive: true, force: true });
|
|
28581
|
-
}
|
|
28582
|
-
mkdirSync13(dirname10(destinationDir), { recursive: true });
|
|
28583
|
-
symlinkSync(
|
|
28584
|
-
sourceDir,
|
|
28585
|
-
destinationDir,
|
|
28586
|
-
process.platform === "win32" ? "junction" : "dir"
|
|
28587
|
-
);
|
|
28588
|
-
log(` ${action === "linked" ? "link" : "relink"} ${label}`);
|
|
28589
|
-
}
|
|
28590
|
-
results.push({ source: sourceDir, destination: destinationDir, action });
|
|
28591
|
-
}
|
|
28592
|
-
return results;
|
|
28593
|
-
}
|
|
28594
|
-
function inspectSkillLinks(cwd = process.cwd(), agents = parseSetupAgents()) {
|
|
28595
|
-
const results = [];
|
|
28596
|
-
for (const { from, to, agents: pairAgents } of SKILL_PAIRS) {
|
|
28597
|
-
if (!pairAgents.some((agent) => agents.has(agent))) continue;
|
|
28598
|
-
const sourceDir = dirname10(from);
|
|
28599
|
-
const destinationDir = dirname10(join20(cwd, to));
|
|
28600
|
-
results.push({
|
|
28601
|
-
agents: pairAgents,
|
|
28602
|
-
source: sourceDir,
|
|
28603
|
-
destination: destinationDir,
|
|
28604
|
-
state: classifySkillDestination(sourceDir, destinationDir)
|
|
28605
|
-
});
|
|
28606
|
-
}
|
|
28607
|
-
return results;
|
|
28608
|
-
}
|
|
28609
|
-
function summarizeSkillLinkHealth(inspections) {
|
|
28610
|
-
if (inspections.some((item) => item.state === "unmanaged")) {
|
|
28611
|
-
return "unmanaged";
|
|
28612
|
-
}
|
|
28613
|
-
const repairable = ["missing", "broken", "stale-copy"];
|
|
28614
|
-
if (inspections.some((item) => repairable.includes(item.state))) {
|
|
28615
|
-
return "needs-repair";
|
|
28616
|
-
}
|
|
28617
|
-
return "healthy";
|
|
28618
|
-
}
|
|
28619
|
-
|
|
28620
28830
|
// src/cli/users/identity.ts
|
|
28621
28831
|
init_kernel();
|
|
28622
28832
|
async function ensureDefaultUser(db, preferredUserId) {
|
|
@@ -28640,13 +28850,13 @@ async function resolveUser(opts, db, resolveOpts) {
|
|
|
28640
28850
|
}
|
|
28641
28851
|
|
|
28642
28852
|
// src/cli/workspaces/backup.ts
|
|
28643
|
-
import { mkdirSync as
|
|
28644
|
-
import { join as
|
|
28853
|
+
import { mkdirSync as mkdirSync15 } from "fs";
|
|
28854
|
+
import { join as join22 } from "path";
|
|
28645
28855
|
async function backupDatabaseTo(db, targetDir) {
|
|
28646
|
-
const backupDir =
|
|
28647
|
-
|
|
28856
|
+
const backupDir = join22(targetDir, "zam-backups");
|
|
28857
|
+
mkdirSync15(backupDir, { recursive: true });
|
|
28648
28858
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
28649
|
-
const dest =
|
|
28859
|
+
const dest = join22(backupDir, `zam-${stamp}.db`);
|
|
28650
28860
|
await db.exec(`VACUUM INTO '${dest.replace(/'/g, "''")}'`);
|
|
28651
28861
|
return dest;
|
|
28652
28862
|
}
|
|
@@ -28777,20 +28987,20 @@ bridgeCommand.command("workspace-info").description("Report the workspace dir, i
|
|
|
28777
28987
|
activeWorkspace,
|
|
28778
28988
|
workspaceDir: activeWorkspace.path,
|
|
28779
28989
|
defaultWorkspaceDir: defaultWorkspaceDir(),
|
|
28780
|
-
dataDir:
|
|
28990
|
+
dataDir: join23(homedir15(), ".zam")
|
|
28781
28991
|
});
|
|
28782
28992
|
});
|
|
28783
28993
|
});
|
|
28784
28994
|
function provisionConfiguredWorkspaces() {
|
|
28785
28995
|
return getConfiguredWorkspaces().flatMap(
|
|
28786
|
-
(workspace) =>
|
|
28996
|
+
(workspace) => existsSync20(workspace.path) ? wireSkills(workspace.path, parseSetupAgents(), { quiet: true }) : []
|
|
28787
28997
|
);
|
|
28788
28998
|
}
|
|
28789
28999
|
function buildWorkspaceLinkHealth(workspaces) {
|
|
28790
29000
|
const agents = parseSetupAgents();
|
|
28791
29001
|
const map = {};
|
|
28792
29002
|
for (const workspace of workspaces) {
|
|
28793
|
-
if (!
|
|
29003
|
+
if (!existsSync20(workspace.path)) continue;
|
|
28794
29004
|
const links = inspectSkillLinks(workspace.path, agents);
|
|
28795
29005
|
map[workspace.id] = {
|
|
28796
29006
|
health: summarizeSkillLinkHealth(links),
|
|
@@ -28820,7 +29030,7 @@ bridgeCommand.command("workspace-list").description("List configured ZAM workspa
|
|
|
28820
29030
|
activeWorkspace,
|
|
28821
29031
|
workspaceDir: activeWorkspace.path,
|
|
28822
29032
|
defaultWorkspaceDir: defaultWorkspaceDir(),
|
|
28823
|
-
dataDir:
|
|
29033
|
+
dataDir: join23(homedir15(), ".zam"),
|
|
28824
29034
|
linkHealth: buildWorkspaceLinkHealth(workspaces)
|
|
28825
29035
|
});
|
|
28826
29036
|
});
|
|
@@ -28835,7 +29045,7 @@ bridgeCommand.command("workspace-repair-links").description(
|
|
|
28835
29045
|
if (!id) jsonError("A non-empty --id is required");
|
|
28836
29046
|
const workspace = getConfiguredWorkspaces().find((item) => item.id === id);
|
|
28837
29047
|
if (!workspace) jsonError(`Workspace "${id}" is not configured`);
|
|
28838
|
-
if (!
|
|
29048
|
+
if (!existsSync20(workspace.path)) {
|
|
28839
29049
|
jsonError(`Workspace path does not exist: ${workspace.path}`);
|
|
28840
29050
|
}
|
|
28841
29051
|
const agents = parseSetupAgents(opts.agents);
|
|
@@ -28866,8 +29076,8 @@ function parseBridgeWorkspaceKind(value) {
|
|
|
28866
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) => {
|
|
28867
29077
|
const raw = String(opts.path ?? "").trim();
|
|
28868
29078
|
if (!raw) jsonError("A non-empty --path is required");
|
|
28869
|
-
const path =
|
|
28870
|
-
if (!
|
|
29079
|
+
const path = resolve6(raw);
|
|
29080
|
+
if (!existsSync20(path)) jsonError(`Workspace path does not exist: ${path}`);
|
|
28871
29081
|
const id = opts.id ? String(opts.id).trim() : void 0;
|
|
28872
29082
|
if (opts.id && !id) jsonError("A non-empty --id is required");
|
|
28873
29083
|
const kind = parseBridgeWorkspaceKind(opts.kind);
|
|
@@ -28911,8 +29121,8 @@ bridgeCommand.command("workspace-remove").description("Unregister a ZAM workspac
|
|
|
28911
29121
|
bridgeCommand.command("set-workspace-dir").description("Set the personal workspace directory (JSON)").requiredOption("--dir <path>", "Path to the workspace directory").action(async (opts) => {
|
|
28912
29122
|
const raw = String(opts.dir ?? "").trim();
|
|
28913
29123
|
if (!raw) jsonError("A non-empty --dir is required");
|
|
28914
|
-
const dir =
|
|
28915
|
-
if (!
|
|
29124
|
+
const dir = resolve6(raw);
|
|
29125
|
+
if (!existsSync20(dir)) jsonError(`Workspace path does not exist: ${dir}`);
|
|
28916
29126
|
const skillLinks = wireSkills(dir, parseSetupAgents(), { quiet: true });
|
|
28917
29127
|
await withDb2(async (db) => {
|
|
28918
29128
|
const workspace = await activateWorkspacePath(db, dir);
|
|
@@ -28975,7 +29185,7 @@ bridgeCommand.command("agent-open").description("Launch an agent harness in the
|
|
|
28975
29185
|
jsonError(`Workspace is not configured: ${opts.workspace}`);
|
|
28976
29186
|
}
|
|
28977
29187
|
const activeWorkspace = await ensureActiveWorkspace(db);
|
|
28978
|
-
const workspace = opts.dir ?
|
|
29188
|
+
const workspace = opts.dir ? existsSync20(opts.dir) ? opts.dir : homedir15() : existingWorkspaceDirOrHome(configuredWorkspace ?? activeWorkspace);
|
|
28979
29189
|
launchHarness(harness, {
|
|
28980
29190
|
executable,
|
|
28981
29191
|
workspace,
|
|
@@ -29347,7 +29557,7 @@ bridgeCommand.command("discover-skills").description(
|
|
|
29347
29557
|
"20"
|
|
29348
29558
|
).action(async (opts) => {
|
|
29349
29559
|
try {
|
|
29350
|
-
const monitorDir =
|
|
29560
|
+
const monitorDir = join23(homedir15(), ".zam", "monitor");
|
|
29351
29561
|
let files;
|
|
29352
29562
|
try {
|
|
29353
29563
|
files = readdirSync2(monitorDir).filter((f) => f.endsWith(".jsonl"));
|
|
@@ -29360,7 +29570,7 @@ bridgeCommand.command("discover-skills").description(
|
|
|
29360
29570
|
return;
|
|
29361
29571
|
}
|
|
29362
29572
|
const limit = Number(opts.limit);
|
|
29363
|
-
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);
|
|
29364
29574
|
const sessionCommands = /* @__PURE__ */ new Map();
|
|
29365
29575
|
for (const file of sorted) {
|
|
29366
29576
|
const sessionId = file.name.replace(".jsonl", "");
|
|
@@ -29472,7 +29682,7 @@ bridgeCommand.command("observe-ui-snapshot").description(
|
|
|
29472
29682
|
});
|
|
29473
29683
|
function resolveWindowsPowerShell() {
|
|
29474
29684
|
try {
|
|
29475
|
-
|
|
29685
|
+
execFileSync5("where.exe", ["pwsh.exe"], { stdio: "ignore" });
|
|
29476
29686
|
return "pwsh";
|
|
29477
29687
|
} catch {
|
|
29478
29688
|
return "powershell";
|
|
@@ -29487,7 +29697,7 @@ function captureScreenshot(outputPath, hwnd, processName) {
|
|
|
29487
29697
|
throw new Error(`Invalid process name format: ${processName}`);
|
|
29488
29698
|
}
|
|
29489
29699
|
if (platform === "win32") {
|
|
29490
|
-
const stdout =
|
|
29700
|
+
const stdout = execFileSync5(
|
|
29491
29701
|
resolveWindowsPowerShell(),
|
|
29492
29702
|
[
|
|
29493
29703
|
"-NoProfile",
|
|
@@ -29800,13 +30010,13 @@ Write-CaptureResult "fullscreen" $hwndVal $matchedBy
|
|
|
29800
30010
|
} else if (platform === "darwin") {
|
|
29801
30011
|
if (hwnd) {
|
|
29802
30012
|
const parsedHwnd = hwnd.startsWith("0x") ? parseInt(hwnd, 16) : parseInt(hwnd, 10);
|
|
29803
|
-
|
|
30013
|
+
execFileSync5("screencapture", ["-l", String(parsedHwnd), outputPath], {
|
|
29804
30014
|
stdio: "pipe"
|
|
29805
30015
|
});
|
|
29806
30016
|
return { method: "screencapture-window", target: null };
|
|
29807
30017
|
} else if (processName) {
|
|
29808
30018
|
try {
|
|
29809
|
-
const windowId =
|
|
30019
|
+
const windowId = execFileSync5(
|
|
29810
30020
|
"osascript",
|
|
29811
30021
|
[
|
|
29812
30022
|
"-e",
|
|
@@ -29815,17 +30025,17 @@ Write-CaptureResult "fullscreen" $hwndVal $matchedBy
|
|
|
29815
30025
|
{ encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] }
|
|
29816
30026
|
).trim();
|
|
29817
30027
|
if (windowId && /^\d+$/.test(windowId)) {
|
|
29818
|
-
|
|
30028
|
+
execFileSync5("screencapture", ["-l", windowId, outputPath], {
|
|
29819
30029
|
stdio: "pipe"
|
|
29820
30030
|
});
|
|
29821
30031
|
return { method: "screencapture-window", target: null };
|
|
29822
30032
|
}
|
|
29823
30033
|
} catch {
|
|
29824
30034
|
}
|
|
29825
|
-
|
|
30035
|
+
execFileSync5("screencapture", ["-x", outputPath], { stdio: "pipe" });
|
|
29826
30036
|
return { method: "screencapture-full", target: null };
|
|
29827
30037
|
} else {
|
|
29828
|
-
|
|
30038
|
+
execFileSync5("screencapture", ["-x", outputPath], { stdio: "pipe" });
|
|
29829
30039
|
return { method: "screencapture-full", target: null };
|
|
29830
30040
|
}
|
|
29831
30041
|
} else {
|
|
@@ -29862,7 +30072,7 @@ bridgeCommand.command("capture-ui").description("Capture a screenshot for agent-
|
|
|
29862
30072
|
return;
|
|
29863
30073
|
}
|
|
29864
30074
|
}
|
|
29865
|
-
const outputPath = opts.image ?? opts.output ??
|
|
30075
|
+
const outputPath = opts.image ?? opts.output ?? join23(tmpdir3(), `zam-capture-${randomBytes2(4).toString("hex")}.png`);
|
|
29866
30076
|
const captureResult = isProvided ? { method: "provided", target: null } : captureScreenshot(outputPath, opts.hwnd, opts.processName);
|
|
29867
30077
|
if (!isProvided) {
|
|
29868
30078
|
const post = decidePostCapture(policy, {
|
|
@@ -29890,7 +30100,7 @@ bridgeCommand.command("capture-ui").description("Capture a screenshot for agent-
|
|
|
29890
30100
|
return;
|
|
29891
30101
|
}
|
|
29892
30102
|
}
|
|
29893
|
-
const imageBytes =
|
|
30103
|
+
const imageBytes = readFileSync17(outputPath);
|
|
29894
30104
|
const base64 = imageBytes.toString("base64");
|
|
29895
30105
|
jsonOut({
|
|
29896
30106
|
sessionId: opts.session ?? null,
|
|
@@ -29917,11 +30127,11 @@ bridgeCommand.command("start-recording").description("Start screen recording in
|
|
|
29917
30127
|
return;
|
|
29918
30128
|
}
|
|
29919
30129
|
const sessionId = opts.session;
|
|
29920
|
-
const statePath =
|
|
30130
|
+
const statePath = join23(tmpdir3(), `zam-recording-${sessionId}.json`);
|
|
29921
30131
|
const defaultExt = platform === "win32" ? ".mkv" : ".mov";
|
|
29922
|
-
const outputPath = opts.output ??
|
|
29923
|
-
const { existsSync:
|
|
29924
|
-
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)) {
|
|
29925
30135
|
jsonOut({
|
|
29926
30136
|
sessionId,
|
|
29927
30137
|
started: false,
|
|
@@ -29929,7 +30139,7 @@ bridgeCommand.command("start-recording").description("Start screen recording in
|
|
|
29929
30139
|
});
|
|
29930
30140
|
return;
|
|
29931
30141
|
}
|
|
29932
|
-
const logPath =
|
|
30142
|
+
const logPath = join23(tmpdir3(), `zam-recording-${sessionId}.log`);
|
|
29933
30143
|
let logFd;
|
|
29934
30144
|
try {
|
|
29935
30145
|
logFd = openSync(logPath, "w");
|
|
@@ -29975,7 +30185,7 @@ bridgeCommand.command("start-recording").description("Start screen recording in
|
|
|
29975
30185
|
}
|
|
29976
30186
|
child.unref();
|
|
29977
30187
|
if (child.pid) {
|
|
29978
|
-
|
|
30188
|
+
writeFileSync13(
|
|
29979
30189
|
statePath,
|
|
29980
30190
|
JSON.stringify({
|
|
29981
30191
|
pid: child.pid,
|
|
@@ -30011,9 +30221,9 @@ bridgeCommand.command("stop-recording").description(
|
|
|
30011
30221
|
return;
|
|
30012
30222
|
}
|
|
30013
30223
|
const sessionId = opts.session;
|
|
30014
|
-
const statePath =
|
|
30015
|
-
const { existsSync:
|
|
30016
|
-
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)) {
|
|
30017
30227
|
jsonOut({
|
|
30018
30228
|
sessionId,
|
|
30019
30229
|
stopped: false,
|
|
@@ -30021,7 +30231,7 @@ bridgeCommand.command("stop-recording").description(
|
|
|
30021
30231
|
});
|
|
30022
30232
|
return;
|
|
30023
30233
|
}
|
|
30024
|
-
const state = JSON.parse(
|
|
30234
|
+
const state = JSON.parse(readFileSync19(statePath, "utf8"));
|
|
30025
30235
|
const { pid, outputPath } = state;
|
|
30026
30236
|
try {
|
|
30027
30237
|
process.kill(pid, "SIGINT");
|
|
@@ -30037,7 +30247,7 @@ bridgeCommand.command("stop-recording").description(
|
|
|
30037
30247
|
};
|
|
30038
30248
|
let attempts = 0;
|
|
30039
30249
|
while (isProcessRunning(pid) && attempts < 20) {
|
|
30040
|
-
await new Promise((
|
|
30250
|
+
await new Promise((resolve7) => setTimeout(resolve7, 250));
|
|
30041
30251
|
attempts++;
|
|
30042
30252
|
}
|
|
30043
30253
|
if (isProcessRunning(pid)) {
|
|
@@ -30050,7 +30260,7 @@ bridgeCommand.command("stop-recording").description(
|
|
|
30050
30260
|
rmSync4(statePath, { force: true });
|
|
30051
30261
|
} catch {
|
|
30052
30262
|
}
|
|
30053
|
-
if (!
|
|
30263
|
+
if (!existsSync22(outputPath)) {
|
|
30054
30264
|
jsonOut({
|
|
30055
30265
|
sessionId,
|
|
30056
30266
|
stopped: false,
|
|
@@ -30480,7 +30690,7 @@ bridgeCommand.command("cloud-model-hint").description("Suggest a cloud model for
|
|
|
30480
30690
|
});
|
|
30481
30691
|
bridgeCommand.command("local-llm-hints").description("Detect installed local LLM servers and suggest defaults (JSON)").action(() => {
|
|
30482
30692
|
const profile = getSystemProfile();
|
|
30483
|
-
const flmInstalled = hasCommand("flm") ||
|
|
30693
|
+
const flmInstalled = hasCommand("flm") || existsSync20("C:\\Program Files\\flm\\flm.exe");
|
|
30484
30694
|
const ollamaInstalled = isOllamaInstalled();
|
|
30485
30695
|
const runners = [
|
|
30486
30696
|
{ id: "flm", label: "FastFlowLM", installed: flmInstalled },
|
|
@@ -30712,13 +30922,15 @@ bridgeCommand.command("desktop-bootstrap").description("Initialize first-run des
|
|
|
30712
30922
|
const userId = await ensureDefaultUser(db, opts.user);
|
|
30713
30923
|
const { enabled, url, model, locale } = await getLlmConfig(db);
|
|
30714
30924
|
const { workspaceDir, activeWorkspaceId, skillLinks } = await ensureDesktopWorkspace(db);
|
|
30925
|
+
const cli = installCliShim();
|
|
30715
30926
|
jsonOut({
|
|
30716
30927
|
userId,
|
|
30717
30928
|
locale,
|
|
30718
30929
|
llm: { enabled, url, model },
|
|
30719
30930
|
activeWorkspaceId,
|
|
30720
30931
|
workspaceDir,
|
|
30721
|
-
skillLinks
|
|
30932
|
+
skillLinks,
|
|
30933
|
+
cli
|
|
30722
30934
|
});
|
|
30723
30935
|
});
|
|
30724
30936
|
});
|
|
@@ -30735,6 +30947,22 @@ bridgeCommand.command("get-settings").description("Get active ZAM settings (JSON
|
|
|
30735
30947
|
});
|
|
30736
30948
|
});
|
|
30737
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
|
+
});
|
|
30738
30966
|
bridgeCommand.command("agent-harness-status").description(
|
|
30739
30967
|
"Detect installed agent harnesses and their ZAM MCP configuration state (JSON)"
|
|
30740
30968
|
).action(() => {
|
|
@@ -32391,11 +32619,11 @@ bridgeCommand.command("serve").description("Start the persistent JSON-RPC stdin/
|
|
|
32391
32619
|
|
|
32392
32620
|
// src/cli/commands/mcp.ts
|
|
32393
32621
|
var __dirname = dirname11(fileURLToPath6(import.meta.url));
|
|
32394
|
-
var pkgPath =
|
|
32395
|
-
if (!
|
|
32396
|
-
pkgPath =
|
|
32622
|
+
var pkgPath = join24(__dirname, "..", "..", "package.json");
|
|
32623
|
+
if (!existsSync21(pkgPath)) {
|
|
32624
|
+
pkgPath = join24(__dirname, "..", "..", "..", "package.json");
|
|
32397
32625
|
}
|
|
32398
|
-
var pkg = JSON.parse(
|
|
32626
|
+
var pkg = JSON.parse(readFileSync18(pkgPath, "utf-8"));
|
|
32399
32627
|
var STUDIO_RESOURCE_URI = "ui://zam/studio";
|
|
32400
32628
|
var RECALL_RESOURCE_URI = "ui://zam/recall";
|
|
32401
32629
|
var GRAPH_RESOURCE_URI = "ui://zam/graph";
|
|
@@ -32420,13 +32648,13 @@ var STUDIO_BRIDGE_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
32420
32648
|
function loadPanelHtml(fileName, placeholderTitle) {
|
|
32421
32649
|
const candidates = [
|
|
32422
32650
|
// dist/cli/commands/mcp.js → dist/ui/
|
|
32423
|
-
|
|
32651
|
+
join24(__dirname, "..", "..", "ui", fileName),
|
|
32424
32652
|
// src/cli/commands/mcp.ts via tsx → <repo>/dist/ui/
|
|
32425
|
-
|
|
32653
|
+
join24(__dirname, "..", "..", "..", "dist", "ui", fileName)
|
|
32426
32654
|
];
|
|
32427
32655
|
for (const candidate of candidates) {
|
|
32428
|
-
if (
|
|
32429
|
-
return
|
|
32656
|
+
if (existsSync21(candidate)) {
|
|
32657
|
+
return readFileSync18(candidate, "utf-8");
|
|
32430
32658
|
}
|
|
32431
32659
|
}
|
|
32432
32660
|
return `<!doctype html>
|