zam-core 0.12.0 → 0.13.0
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 +1 -1
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/commands/mcp.js +198 -24
- 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/ui/okf-panel.html +787 -0
- package/dist/vscode-extension/{ZAM_Companion_0.12.0.vsix → ZAM_Companion_0.13.0.vsix} +0 -0
- package/dist/vscode-extension/manifest.json +2 -2
- package/package.json +2 -2
package/dist/cli/commands/mcp.js
CHANGED
|
@@ -9165,12 +9165,21 @@ var init_bundle = __esm({
|
|
|
9165
9165
|
var io_exports = {};
|
|
9166
9166
|
__export(io_exports, {
|
|
9167
9167
|
DEFAULT_BUNDLE_DIR: () => DEFAULT_BUNDLE_DIR,
|
|
9168
|
+
findRepoRoot: () => findRepoRoot,
|
|
9168
9169
|
loadBundle: () => loadBundle,
|
|
9169
9170
|
resolveArticlePath: () => resolveArticlePath,
|
|
9171
|
+
resolveCitationPath: () => resolveCitationPath,
|
|
9170
9172
|
upsertArticle: () => upsertArticle
|
|
9171
9173
|
});
|
|
9172
|
-
import {
|
|
9173
|
-
|
|
9174
|
+
import {
|
|
9175
|
+
existsSync as existsSync21,
|
|
9176
|
+
mkdirSync as mkdirSync16,
|
|
9177
|
+
readdirSync as readdirSync3,
|
|
9178
|
+
readFileSync as readFileSync18,
|
|
9179
|
+
realpathSync as realpathSync2,
|
|
9180
|
+
writeFileSync as writeFileSync13
|
|
9181
|
+
} from "fs";
|
|
9182
|
+
import { dirname as dirname11, isAbsolute as isAbsolute2, join as join24, relative, resolve as resolve7, sep } from "path";
|
|
9174
9183
|
function resolveArticlePath(dir, file) {
|
|
9175
9184
|
if (file.includes("/") || file.includes("\\") || file.includes("..")) {
|
|
9176
9185
|
throw new Error(`invalid article file name: ${file}`);
|
|
@@ -9180,6 +9189,42 @@ function resolveArticlePath(dir, file) {
|
|
|
9180
9189
|
}
|
|
9181
9190
|
return join24(resolve7(dir), file);
|
|
9182
9191
|
}
|
|
9192
|
+
function findRepoRoot(startDir) {
|
|
9193
|
+
let dir = resolve7(startDir);
|
|
9194
|
+
for (; ; ) {
|
|
9195
|
+
if (existsSync21(join24(dir, ".git"))) return dir;
|
|
9196
|
+
const parent = dirname11(dir);
|
|
9197
|
+
if (parent === dir) return resolve7(startDir, "..");
|
|
9198
|
+
dir = parent;
|
|
9199
|
+
}
|
|
9200
|
+
}
|
|
9201
|
+
function resolveCitationPath(bundleDir, target) {
|
|
9202
|
+
if (isAbsolute2(target)) {
|
|
9203
|
+
throw new Error(
|
|
9204
|
+
`invalid citation target: absolute paths are not allowed (${target})`
|
|
9205
|
+
);
|
|
9206
|
+
}
|
|
9207
|
+
if (!target.endsWith(".md")) {
|
|
9208
|
+
throw new Error(
|
|
9209
|
+
`invalid citation target: only .md files are readable (${target})`
|
|
9210
|
+
);
|
|
9211
|
+
}
|
|
9212
|
+
const root = findRepoRoot(bundleDir);
|
|
9213
|
+
const resolved = resolve7(bundleDir, target);
|
|
9214
|
+
assertContained(root, resolved, target);
|
|
9215
|
+
if (existsSync21(resolved)) {
|
|
9216
|
+
assertContained(realpathSync2(root), realpathSync2(resolved), target);
|
|
9217
|
+
}
|
|
9218
|
+
return resolved;
|
|
9219
|
+
}
|
|
9220
|
+
function assertContained(root, candidate, target) {
|
|
9221
|
+
const rel = relative(root, candidate);
|
|
9222
|
+
if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute2(rel)) {
|
|
9223
|
+
throw new Error(
|
|
9224
|
+
`invalid citation target: resolves outside the repository root (${target})`
|
|
9225
|
+
);
|
|
9226
|
+
}
|
|
9227
|
+
}
|
|
9183
9228
|
function loadBundle(dir) {
|
|
9184
9229
|
const root = resolve7(dir);
|
|
9185
9230
|
let entries;
|
|
@@ -9253,8 +9298,8 @@ var init_io = __esm({
|
|
|
9253
9298
|
|
|
9254
9299
|
// src/cli/commands/mcp.ts
|
|
9255
9300
|
init_kernel();
|
|
9256
|
-
import { existsSync as
|
|
9257
|
-
import { dirname as
|
|
9301
|
+
import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
|
|
9302
|
+
import { dirname as dirname12, join as join25 } from "path";
|
|
9258
9303
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
9259
9304
|
import {
|
|
9260
9305
|
RESOURCE_MIME_TYPE,
|
|
@@ -9347,7 +9392,8 @@ var COMPANION_SURFACES = [
|
|
|
9347
9392
|
"recall",
|
|
9348
9393
|
"graph",
|
|
9349
9394
|
"settings",
|
|
9350
|
-
"studio"
|
|
9395
|
+
"studio",
|
|
9396
|
+
"okf"
|
|
9351
9397
|
];
|
|
9352
9398
|
function isCompanionSurface(value) {
|
|
9353
9399
|
return typeof value === "string" && COMPANION_SURFACES.includes(value);
|
|
@@ -11898,7 +11944,7 @@ async function readWebLink(url) {
|
|
|
11898
11944
|
redirect: "manual",
|
|
11899
11945
|
signal: controller.signal,
|
|
11900
11946
|
headers: {
|
|
11901
|
-
"User-Agent": "ZAM-Content-Studio/0.
|
|
11947
|
+
"User-Agent": "ZAM-Content-Studio/0.13.0"
|
|
11902
11948
|
}
|
|
11903
11949
|
});
|
|
11904
11950
|
if (res.status >= 300 && res.status < 400) {
|
|
@@ -31063,8 +31109,8 @@ bridgeCommand.command("start-recording").description("Start screen recording in
|
|
|
31063
31109
|
const statePath = join22(tmpdir3(), `zam-recording-${sessionId}.json`);
|
|
31064
31110
|
const defaultExt = platform === "win32" ? ".mkv" : ".mov";
|
|
31065
31111
|
const outputPath = opts.output ?? join22(tmpdir3(), `zam-recording-${sessionId}${defaultExt}`);
|
|
31066
|
-
const { existsSync:
|
|
31067
|
-
if (
|
|
31112
|
+
const { existsSync: existsSync23, writeFileSync: writeFileSync14, openSync, closeSync } = await import("fs");
|
|
31113
|
+
if (existsSync23(statePath)) {
|
|
31068
31114
|
jsonOut({
|
|
31069
31115
|
sessionId,
|
|
31070
31116
|
started: false,
|
|
@@ -31155,8 +31201,8 @@ bridgeCommand.command("stop-recording").description(
|
|
|
31155
31201
|
}
|
|
31156
31202
|
const sessionId = opts.session;
|
|
31157
31203
|
const statePath = join22(tmpdir3(), `zam-recording-${sessionId}.json`);
|
|
31158
|
-
const { existsSync:
|
|
31159
|
-
if (!
|
|
31204
|
+
const { existsSync: existsSync23, readFileSync: readFileSync20, rmSync: rmSync4 } = await import("fs");
|
|
31205
|
+
if (!existsSync23(statePath)) {
|
|
31160
31206
|
jsonOut({
|
|
31161
31207
|
sessionId,
|
|
31162
31208
|
stopped: false,
|
|
@@ -31193,7 +31239,7 @@ bridgeCommand.command("stop-recording").description(
|
|
|
31193
31239
|
rmSync4(statePath, { force: true });
|
|
31194
31240
|
} catch {
|
|
31195
31241
|
}
|
|
31196
|
-
if (!
|
|
31242
|
+
if (!existsSync23(outputPath)) {
|
|
31197
31243
|
jsonOut({
|
|
31198
31244
|
sessionId,
|
|
31199
31245
|
stopped: false,
|
|
@@ -33817,9 +33863,9 @@ async function publishUiIntent(app, input = {}, opts = {}) {
|
|
|
33817
33863
|
}
|
|
33818
33864
|
|
|
33819
33865
|
// src/cli/commands/mcp.ts
|
|
33820
|
-
var __dirname =
|
|
33866
|
+
var __dirname = dirname12(fileURLToPath6(import.meta.url));
|
|
33821
33867
|
var pkgPath = join25(__dirname, "..", "..", "package.json");
|
|
33822
|
-
if (!
|
|
33868
|
+
if (!existsSync22(pkgPath)) {
|
|
33823
33869
|
pkgPath = join25(__dirname, "..", "..", "..", "package.json");
|
|
33824
33870
|
}
|
|
33825
33871
|
var pkg = JSON.parse(readFileSync19(pkgPath, "utf-8"));
|
|
@@ -33827,6 +33873,7 @@ var STUDIO_RESOURCE_URI = "ui://zam/studio";
|
|
|
33827
33873
|
var RECALL_RESOURCE_URI = "ui://zam/recall";
|
|
33828
33874
|
var GRAPH_RESOURCE_URI = "ui://zam/graph";
|
|
33829
33875
|
var SETTINGS_RESOURCE_URI = "ui://zam/settings";
|
|
33876
|
+
var OKF_RESOURCE_URI = "ui://zam/okf";
|
|
33830
33877
|
var STUDIO_BRIDGE_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
33831
33878
|
"list-tokens",
|
|
33832
33879
|
"personal-card-list",
|
|
@@ -33854,7 +33901,7 @@ function loadPanelHtml(fileName, placeholderTitle) {
|
|
|
33854
33901
|
join25(__dirname, "..", "..", "..", "dist", "ui", fileName)
|
|
33855
33902
|
];
|
|
33856
33903
|
for (const candidate of candidates) {
|
|
33857
|
-
if (
|
|
33904
|
+
if (existsSync22(candidate)) {
|
|
33858
33905
|
return readFileSync19(candidate, "utf-8");
|
|
33859
33906
|
}
|
|
33860
33907
|
}
|
|
@@ -34626,22 +34673,37 @@ function createMcpServer(db) {
|
|
|
34626
34673
|
{
|
|
34627
34674
|
description: "List the OKF knowledge-base articles (type, title, description, tags, resource URL) plus conformance problems, if any",
|
|
34628
34675
|
inputSchema: {
|
|
34629
|
-
bundle_dir: okfBundleDirSchema
|
|
34676
|
+
bundle_dir: okfBundleDirSchema,
|
|
34677
|
+
include_log: z.boolean().optional().describe(
|
|
34678
|
+
"Also return the raw log.md text (empty string if missing)"
|
|
34679
|
+
)
|
|
34630
34680
|
},
|
|
34631
34681
|
annotations: {
|
|
34632
34682
|
...commonAnnotations,
|
|
34633
34683
|
readOnlyHint: true
|
|
34634
34684
|
}
|
|
34635
34685
|
},
|
|
34636
|
-
wrapHandler(
|
|
34637
|
-
|
|
34638
|
-
|
|
34639
|
-
|
|
34640
|
-
|
|
34641
|
-
|
|
34642
|
-
|
|
34643
|
-
|
|
34644
|
-
|
|
34686
|
+
wrapHandler(
|
|
34687
|
+
async (params) => {
|
|
34688
|
+
const { DEFAULT_BUNDLE_DIR: DEFAULT_BUNDLE_DIR2, loadBundle: loadBundle2 } = await Promise.resolve().then(() => (init_io(), io_exports));
|
|
34689
|
+
const bundle = loadBundle2(params.bundle_dir ?? DEFAULT_BUNDLE_DIR2);
|
|
34690
|
+
let log;
|
|
34691
|
+
if (params.include_log) {
|
|
34692
|
+
const { readFileSync: readFileSync20 } = await import("fs");
|
|
34693
|
+
try {
|
|
34694
|
+
log = readFileSync20(join25(bundle.dir, "log.md"), "utf8");
|
|
34695
|
+
} catch {
|
|
34696
|
+
log = "";
|
|
34697
|
+
}
|
|
34698
|
+
}
|
|
34699
|
+
return {
|
|
34700
|
+
dir: bundle.dir,
|
|
34701
|
+
articles: bundle.catalog,
|
|
34702
|
+
problems: bundle.problems,
|
|
34703
|
+
...params.include_log ? { log } : {}
|
|
34704
|
+
};
|
|
34705
|
+
}
|
|
34706
|
+
)
|
|
34645
34707
|
);
|
|
34646
34708
|
server.registerTool(
|
|
34647
34709
|
"zam_okf_read",
|
|
@@ -34701,6 +34763,118 @@ function createMcpServer(db) {
|
|
|
34701
34763
|
}
|
|
34702
34764
|
)
|
|
34703
34765
|
);
|
|
34766
|
+
server.registerTool(
|
|
34767
|
+
"zam_okf_read_citation",
|
|
34768
|
+
{
|
|
34769
|
+
description: "Read a citation target referenced by an OKF article (e.g. an ADR): read-only, restricted to .md files that resolve inside the repository root \u2014 the target may be outside the bundle but never outside the repo",
|
|
34770
|
+
inputSchema: {
|
|
34771
|
+
bundle_dir: okfBundleDirSchema,
|
|
34772
|
+
target: z.string().describe(
|
|
34773
|
+
"Path to the citation target relative to bundle_dir, e.g. ../adr/2026-07-17-x.md"
|
|
34774
|
+
)
|
|
34775
|
+
},
|
|
34776
|
+
annotations: {
|
|
34777
|
+
...commonAnnotations,
|
|
34778
|
+
readOnlyHint: true
|
|
34779
|
+
}
|
|
34780
|
+
},
|
|
34781
|
+
wrapHandler(async (params) => {
|
|
34782
|
+
const { readFileSync: readFileSync20 } = await import("fs");
|
|
34783
|
+
const { relative: relative2, sep: sep2 } = await import("path");
|
|
34784
|
+
const { DEFAULT_BUNDLE_DIR: DEFAULT_BUNDLE_DIR2, findRepoRoot: findRepoRoot2, resolveCitationPath: resolveCitationPath2 } = await Promise.resolve().then(() => (init_io(), io_exports));
|
|
34785
|
+
const bundleDir = params.bundle_dir ?? DEFAULT_BUNDLE_DIR2;
|
|
34786
|
+
const path = resolveCitationPath2(bundleDir, params.target);
|
|
34787
|
+
const content = readFileSync20(path, "utf8");
|
|
34788
|
+
const root = findRepoRoot2(bundleDir);
|
|
34789
|
+
const repoRelativePath = relative2(root, path).split(sep2).join("/");
|
|
34790
|
+
return { target: params.target, path: repoRelativePath, content };
|
|
34791
|
+
})
|
|
34792
|
+
);
|
|
34793
|
+
registerAppTool(
|
|
34794
|
+
server,
|
|
34795
|
+
"zam_okf_visualize",
|
|
34796
|
+
{
|
|
34797
|
+
title: "Open ZAM OKF visualizer",
|
|
34798
|
+
description: "Open the ZAM OKF knowledge-base visualizer: articles by type with search, a markdown reader with inline-expandable cited ADRs, a link graph, and the log. Pass `bundle_dir` to browse a bundle other than the default (docs/okf under the server cwd).",
|
|
34799
|
+
inputSchema: {
|
|
34800
|
+
bundle_dir: okfBundleDirSchema
|
|
34801
|
+
},
|
|
34802
|
+
annotations: {
|
|
34803
|
+
...commonAnnotations,
|
|
34804
|
+
readOnlyHint: true
|
|
34805
|
+
},
|
|
34806
|
+
_meta: {
|
|
34807
|
+
ui: { resourceUri: OKF_RESOURCE_URI }
|
|
34808
|
+
}
|
|
34809
|
+
},
|
|
34810
|
+
wrapHandler(async ({ bundle_dir }) => {
|
|
34811
|
+
const opening = await resolveOpeningCompanionContextSafely(
|
|
34812
|
+
db,
|
|
34813
|
+
"okf",
|
|
34814
|
+
void 0,
|
|
34815
|
+
getNativeClientInfo(),
|
|
34816
|
+
{ clientSamplingCapable: getClientSamplingCapable() }
|
|
34817
|
+
);
|
|
34818
|
+
await publishUiIntent("okf", { bundle_dir });
|
|
34819
|
+
const { DEFAULT_BUNDLE_DIR: DEFAULT_BUNDLE_DIR2, loadBundle: loadBundle2 } = await Promise.resolve().then(() => (init_io(), io_exports));
|
|
34820
|
+
const { resolve: resolve8 } = await import("path");
|
|
34821
|
+
const requestedDir = bundle_dir ?? DEFAULT_BUNDLE_DIR2;
|
|
34822
|
+
let resolvedBundleDir = resolve8(requestedDir);
|
|
34823
|
+
let catalog = [];
|
|
34824
|
+
let problems = [];
|
|
34825
|
+
let log = "";
|
|
34826
|
+
let okfVersion = null;
|
|
34827
|
+
try {
|
|
34828
|
+
const bundle = loadBundle2(requestedDir);
|
|
34829
|
+
resolvedBundleDir = bundle.dir;
|
|
34830
|
+
catalog = bundle.catalog;
|
|
34831
|
+
problems = bundle.problems;
|
|
34832
|
+
const { readFileSync: readFileSync20 } = await import("fs");
|
|
34833
|
+
try {
|
|
34834
|
+
log = readFileSync20(join25(bundle.dir, "log.md"), "utf8");
|
|
34835
|
+
} catch {
|
|
34836
|
+
log = "";
|
|
34837
|
+
}
|
|
34838
|
+
try {
|
|
34839
|
+
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_bundle(), bundle_exports));
|
|
34840
|
+
const indexRaw = readFileSync20(join25(bundle.dir, "index.md"), "utf8");
|
|
34841
|
+
const { fields } = parseFrontmatter2(indexRaw);
|
|
34842
|
+
okfVersion = typeof fields.okf_version === "string" ? fields.okf_version : null;
|
|
34843
|
+
} catch {
|
|
34844
|
+
okfVersion = null;
|
|
34845
|
+
}
|
|
34846
|
+
} catch (error) {
|
|
34847
|
+
problems = [error instanceof Error ? error.message : String(error)];
|
|
34848
|
+
}
|
|
34849
|
+
return {
|
|
34850
|
+
okf: "zam",
|
|
34851
|
+
version: pkg.version,
|
|
34852
|
+
user: opening.context.user.currentId ?? null,
|
|
34853
|
+
bundleDir: resolvedBundleDir,
|
|
34854
|
+
okfVersion,
|
|
34855
|
+
catalog,
|
|
34856
|
+
problems,
|
|
34857
|
+
log,
|
|
34858
|
+
companionContext: opening.context,
|
|
34859
|
+
...opening.degraded ? { companionContextDegraded: true } : {}
|
|
34860
|
+
};
|
|
34861
|
+
})
|
|
34862
|
+
);
|
|
34863
|
+
registerAppResource(
|
|
34864
|
+
server,
|
|
34865
|
+
"zam-okf",
|
|
34866
|
+
OKF_RESOURCE_URI,
|
|
34867
|
+
{ mimeType: RESOURCE_MIME_TYPE },
|
|
34868
|
+
async () => ({
|
|
34869
|
+
contents: [
|
|
34870
|
+
{
|
|
34871
|
+
uri: OKF_RESOURCE_URI,
|
|
34872
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
34873
|
+
text: loadPanelHtml("okf-panel.html", "ZAM OKF")
|
|
34874
|
+
}
|
|
34875
|
+
]
|
|
34876
|
+
})
|
|
34877
|
+
);
|
|
34704
34878
|
return server;
|
|
34705
34879
|
}
|
|
34706
34880
|
async function runMcpServer() {
|