ast-mcp-server 0.10.0 → 0.11.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/CHANGELOG.md +19 -2
- package/README.md +27 -2
- package/SECURITY.md +1 -1
- package/dist/cli.js +67 -1
- package/dist/services/agent-setup.js +11 -5
- package/dist/services/cli-project-discovery.js +97 -0
- package/dist/services/doctor-continuation.js +37 -0
- package/dist/services/doctor-model.js +77 -0
- package/dist/services/doctor.js +111 -0
- package/dist/services/managed-bundle.js +145 -0
- package/dist/services/managed-file.js +37 -0
- package/dist/services/project.js +98 -22
- package/dist/services/skill-installer.js +74 -56
- package/dist/services/upgrade-command.js +77 -0
- package/dist/services/upgrade-reconcile.js +41 -0
- package/dist/services/upgrade-runtime.js +157 -0
- package/dist/services/upgrade.js +232 -0
- package/docs/support.md +13 -13
- package/package.json +2 -2
- package/skills/structural-code-editing/SKILL.md +30 -160
- package/skills/structural-code-editing/references/operations.md +53 -0
- package/skills/structural-code-editing/releases.json +17 -3
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { chmod, copyFile, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rm, writeFile, } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
export class UpgradeCleanupError extends Error {
|
|
8
|
+
primaryCode;
|
|
9
|
+
code = "UPGRADE_CLEANUP_FAILED";
|
|
10
|
+
constructor(primaryCode) {
|
|
11
|
+
super("Upgrade temporary files could not be removed safely.");
|
|
12
|
+
this.primaryCode = primaryCode;
|
|
13
|
+
this.name = "UpgradeCleanupError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const executeFile = promisify(execFile);
|
|
17
|
+
async function npmCliFor(node, platform) {
|
|
18
|
+
const p = platform === "win32" ? path.win32 : path.posix;
|
|
19
|
+
const root = platform === "win32" ? p.dirname(node) : p.resolve(p.dirname(node), "..");
|
|
20
|
+
const candidates = platform === "win32"
|
|
21
|
+
? [p.join(root, "node_modules", "npm", "bin", "npm-cli.js")]
|
|
22
|
+
: [
|
|
23
|
+
p.join(p.dirname(node), "npm"),
|
|
24
|
+
p.join(root, "lib", "node_modules", "npm", "bin", "npm-cli.js"),
|
|
25
|
+
];
|
|
26
|
+
for (const candidate of candidates) {
|
|
27
|
+
try {
|
|
28
|
+
const resolved = await realpath(candidate);
|
|
29
|
+
if ((await lstat(resolved)).isFile())
|
|
30
|
+
return resolved;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Try the next layout owned by this Node installation.
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
async function copyUserConfig(environment, destination) {
|
|
39
|
+
const source = environment.npm_config_userconfig ??
|
|
40
|
+
environment.NPM_CONFIG_USERCONFIG ??
|
|
41
|
+
path.join(environment.HOME ?? os.homedir(), ".npmrc");
|
|
42
|
+
try {
|
|
43
|
+
await copyFile(source, destination);
|
|
44
|
+
await chmod(destination, 0o600);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
await writeFile(destination, "", { encoding: "utf8", mode: 0o600 });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function restoreOwnerAccess(value) {
|
|
51
|
+
const info = await lstat(value);
|
|
52
|
+
if (info.isSymbolicLink())
|
|
53
|
+
return;
|
|
54
|
+
await chmod(value, info.isDirectory() ? 0o700 : 0o600);
|
|
55
|
+
if (info.isDirectory())
|
|
56
|
+
for (const child of await readdir(value))
|
|
57
|
+
await restoreOwnerAccess(path.join(value, child));
|
|
58
|
+
}
|
|
59
|
+
async function cleanupBoundary(boundary, removeTree = (value) => rm(value, { recursive: true, force: true })) {
|
|
60
|
+
try {
|
|
61
|
+
await restoreOwnerAccess(boundary);
|
|
62
|
+
await removeTree(boundary);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
throw new UpgradeCleanupError();
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
await lstat(boundary);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (error.code === "ENOENT")
|
|
72
|
+
return;
|
|
73
|
+
throw new UpgradeCleanupError();
|
|
74
|
+
}
|
|
75
|
+
throw new UpgradeCleanupError();
|
|
76
|
+
}
|
|
77
|
+
export async function createUpgradeRuntime(executable, options = {}) {
|
|
78
|
+
const environment = options.environment ?? process.env;
|
|
79
|
+
const platform = options.platform ?? process.platform;
|
|
80
|
+
const nodeExecutable = options.nodeExecutable ?? process.execPath;
|
|
81
|
+
const execute = options.execute ?? executeFile;
|
|
82
|
+
const boundary = await mkdtemp(path.join(options.temporaryParent ?? os.tmpdir(), "ast-tool-upgrade-"));
|
|
83
|
+
try {
|
|
84
|
+
const cache = path.join(boundary, "cache");
|
|
85
|
+
const logs = path.join(boundary, "logs");
|
|
86
|
+
const userConfig = path.join(boundary, "npmrc");
|
|
87
|
+
await Promise.all([mkdir(cache), mkdir(logs), copyUserConfig(environment, userConfig)]);
|
|
88
|
+
const npmEnvironment = {
|
|
89
|
+
...environment,
|
|
90
|
+
npm_config_cache: cache,
|
|
91
|
+
npm_config_logs_dir: logs,
|
|
92
|
+
npm_config_userconfig: userConfig,
|
|
93
|
+
npm_config_update_notifier: "false",
|
|
94
|
+
npm_config_audit: "false",
|
|
95
|
+
npm_config_fund: "false",
|
|
96
|
+
};
|
|
97
|
+
const run = async (file, args) => (await execute(file, args, { encoding: "utf8", windowsHide: true, env: npmEnvironment }))
|
|
98
|
+
.stdout;
|
|
99
|
+
const cliExecutable = await realpath(executable);
|
|
100
|
+
const packageRoot = path.resolve(path.dirname(cliExecutable), "..");
|
|
101
|
+
const npmCliExecutable = await npmCliFor(nodeExecutable, platform);
|
|
102
|
+
const p = platform === "win32" ? path.win32 : path.posix;
|
|
103
|
+
const voltaExecutable = environment.VOLTA_HOME
|
|
104
|
+
? p.resolve(environment.VOLTA_HOME, "bin", platform === "win32" ? "volta.exe" : "volta")
|
|
105
|
+
: undefined;
|
|
106
|
+
const runtime = {
|
|
107
|
+
packageRoot,
|
|
108
|
+
cliExecutable,
|
|
109
|
+
nodeExecutable,
|
|
110
|
+
...(npmCliExecutable ? { npmCliExecutable } : {}),
|
|
111
|
+
...(voltaExecutable ? { voltaExecutable } : {}),
|
|
112
|
+
platform,
|
|
113
|
+
realpath,
|
|
114
|
+
directDirectory: async (value) => {
|
|
115
|
+
const info = await lstat(value).catch(() => undefined);
|
|
116
|
+
return info?.isDirectory() === true && info.isSymbolicLink() === false;
|
|
117
|
+
},
|
|
118
|
+
readPackage: async (root) => JSON.parse(await readFile(path.join(root, "package.json"), "utf8")),
|
|
119
|
+
latestVersion: async (provenance) => {
|
|
120
|
+
const stdout = provenance === "volta"
|
|
121
|
+
? await run(voltaExecutable, [
|
|
122
|
+
"run",
|
|
123
|
+
"npm",
|
|
124
|
+
"view",
|
|
125
|
+
"ast-mcp-server@latest",
|
|
126
|
+
"version",
|
|
127
|
+
"--json",
|
|
128
|
+
])
|
|
129
|
+
: await run(nodeExecutable, [
|
|
130
|
+
npmCliExecutable,
|
|
131
|
+
"view",
|
|
132
|
+
"ast-mcp-server@latest",
|
|
133
|
+
"version",
|
|
134
|
+
"--json",
|
|
135
|
+
]);
|
|
136
|
+
const value = JSON.parse(stdout);
|
|
137
|
+
if (typeof value !== "string")
|
|
138
|
+
throw new Error("invalid registry response");
|
|
139
|
+
return value;
|
|
140
|
+
},
|
|
141
|
+
run,
|
|
142
|
+
};
|
|
143
|
+
return {
|
|
144
|
+
runtime,
|
|
145
|
+
dispose: () => cleanupBoundary(boundary, options.removeTree),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
try {
|
|
150
|
+
await cleanupBoundary(boundary, options.removeTree);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
throw new UpgradeCleanupError("UPGRADE_RUNTIME_CREATION_FAILED");
|
|
154
|
+
}
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
const PACKAGE = "ast-mcp-server";
|
|
3
|
+
const CONTINUATION = "After reinstalling through its owning toolchain, run: ast-tool upgrade --check";
|
|
4
|
+
export class UpgradeError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
continuation;
|
|
7
|
+
constructor(code, message, continuation = CONTINUATION) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.continuation = continuation;
|
|
11
|
+
this.name = "UpgradeError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function fail(code, message) {
|
|
15
|
+
throw new UpgradeError(code, message);
|
|
16
|
+
}
|
|
17
|
+
function paths(platform) {
|
|
18
|
+
return platform === "win32" ? path.win32 : path.posix;
|
|
19
|
+
}
|
|
20
|
+
function same(a, b, platform) {
|
|
21
|
+
return platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
22
|
+
}
|
|
23
|
+
function inside(root, target, platform) {
|
|
24
|
+
const p = paths(platform);
|
|
25
|
+
const relative = p.relative(root, target);
|
|
26
|
+
return relative !== ".." && !relative.startsWith(`..${p.sep}`) && !p.isAbsolute(relative);
|
|
27
|
+
}
|
|
28
|
+
async function canonical(runtime, value) {
|
|
29
|
+
return runtime
|
|
30
|
+
.realpath(value)
|
|
31
|
+
.catch(() => fail("UPGRADE_PROVENANCE_UNSUPPORTED", "Package ownership could not be proven."));
|
|
32
|
+
}
|
|
33
|
+
function packageFields(record, platform) {
|
|
34
|
+
const bins = record.bin;
|
|
35
|
+
if (record.name !== PACKAGE ||
|
|
36
|
+
typeof record.version !== "string" ||
|
|
37
|
+
!record.version ||
|
|
38
|
+
!bins ||
|
|
39
|
+
typeof bins["ast-tool"] !== "string" ||
|
|
40
|
+
typeof bins["ast-mcp-server"] !== "string") {
|
|
41
|
+
fail("UPGRADE_PROVENANCE_UNSUPPORTED", "Package identity or bins are unsupported.");
|
|
42
|
+
}
|
|
43
|
+
const p = paths(platform);
|
|
44
|
+
for (const value of [bins["ast-tool"], bins["ast-mcp-server"]]) {
|
|
45
|
+
if (p.isAbsolute(value) || p.normalize(value).startsWith(`..${p.sep}`)) {
|
|
46
|
+
fail("UPGRADE_PROVENANCE_UNSUPPORTED", "Package executable location is unsafe.");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { version: record.version, cli: bins["ast-tool"], server: bins["ast-mcp-server"] };
|
|
50
|
+
}
|
|
51
|
+
async function readPackage(runtime, root) {
|
|
52
|
+
try {
|
|
53
|
+
return packageFields(await runtime.readPackage(root), runtime.platform);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof UpgradeError)
|
|
57
|
+
throw error;
|
|
58
|
+
fail("UPGRADE_PROVENANCE_UNSUPPORTED", "Package metadata could not be verified.");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function proveNpm(runtime, packageRoot) {
|
|
62
|
+
if (!runtime.npmCliExecutable)
|
|
63
|
+
return;
|
|
64
|
+
const p = paths(runtime.platform);
|
|
65
|
+
try {
|
|
66
|
+
const node = await canonical(runtime, runtime.nodeExecutable);
|
|
67
|
+
const npmCli = await canonical(runtime, runtime.npmCliExecutable);
|
|
68
|
+
const toolchainRoot = runtime.platform === "win32" ? p.dirname(node) : p.resolve(p.dirname(node), "..");
|
|
69
|
+
if (p.basename(npmCli).toLowerCase() !== "npm-cli.js" ||
|
|
70
|
+
!inside(toolchainRoot, npmCli, runtime.platform))
|
|
71
|
+
return;
|
|
72
|
+
const [rootText, prefixText] = await Promise.all([
|
|
73
|
+
runtime.run(runtime.nodeExecutable, [npmCli, "root", "--global"]),
|
|
74
|
+
runtime.run(runtime.nodeExecutable, [npmCli, "prefix", "--global"]),
|
|
75
|
+
]);
|
|
76
|
+
const lexicalRoot = p.resolve(rootText.trim());
|
|
77
|
+
const lexicalPackage = p.join(lexicalRoot, PACKAGE);
|
|
78
|
+
if (!p.isAbsolute(rootText.trim()) || !(await runtime.directDirectory(lexicalPackage)))
|
|
79
|
+
return;
|
|
80
|
+
const root = await canonical(runtime, lexicalRoot);
|
|
81
|
+
const prefix = await canonical(runtime, prefixText.trim());
|
|
82
|
+
const expectedRoot = await canonical(runtime, runtime.platform === "win32"
|
|
83
|
+
? p.join(prefix, "node_modules")
|
|
84
|
+
: p.join(prefix, "lib", "node_modules"));
|
|
85
|
+
const expectedPackage = await canonical(runtime, lexicalPackage);
|
|
86
|
+
if (!same(root, expectedRoot, runtime.platform) ||
|
|
87
|
+
!same(expectedPackage, packageRoot, runtime.platform))
|
|
88
|
+
return;
|
|
89
|
+
return {
|
|
90
|
+
kind: "npm",
|
|
91
|
+
executable: runtime.nodeExecutable,
|
|
92
|
+
args: [npmCli, "install", "--global", `${PACKAGE}@latest`, "--ignore-scripts"],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function proveVolta(runtime) {
|
|
100
|
+
if (!runtime.voltaExecutable)
|
|
101
|
+
return;
|
|
102
|
+
try {
|
|
103
|
+
const [tool, node] = await Promise.all([
|
|
104
|
+
runtime.run(runtime.voltaExecutable, ["which", "ast-tool"]),
|
|
105
|
+
runtime.run(runtime.voltaExecutable, ["which", "node"]),
|
|
106
|
+
]);
|
|
107
|
+
if (!same(await canonical(runtime, tool.trim()), await canonical(runtime, runtime.cliExecutable), runtime.platform) ||
|
|
108
|
+
!same(await canonical(runtime, node.trim()), await canonical(runtime, runtime.nodeExecutable), runtime.platform))
|
|
109
|
+
return;
|
|
110
|
+
return {
|
|
111
|
+
kind: "volta",
|
|
112
|
+
executable: runtime.voltaExecutable,
|
|
113
|
+
args: ["install", `${PACKAGE}@latest`],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function versionParts(value) {
|
|
121
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.exec(value);
|
|
122
|
+
return match ? [+match[1], +match[2], +match[3], match[4] ?? ""] : undefined;
|
|
123
|
+
}
|
|
124
|
+
function updateAvailable(current, latest) {
|
|
125
|
+
const left = versionParts(current);
|
|
126
|
+
const right = versionParts(latest);
|
|
127
|
+
if (!left || !right)
|
|
128
|
+
fail("UPGRADE_INSPECTION_FAILED", "Package version is invalid.");
|
|
129
|
+
for (let index = 0; index < 3; index++) {
|
|
130
|
+
if (left[index] !== right[index])
|
|
131
|
+
return left[index] < right[index];
|
|
132
|
+
}
|
|
133
|
+
if (!left[3] || !right[3])
|
|
134
|
+
return Boolean(left[3]);
|
|
135
|
+
return left[3].localeCompare(right[3], "en", { numeric: true }) < 0;
|
|
136
|
+
}
|
|
137
|
+
export async function planUpgrade(runtime) {
|
|
138
|
+
const p = paths(runtime.platform);
|
|
139
|
+
const root = await canonical(runtime, runtime.packageRoot);
|
|
140
|
+
const current = await readPackage(runtime, root);
|
|
141
|
+
const cli = await canonical(runtime, p.resolve(root, current.cli));
|
|
142
|
+
const server = await canonical(runtime, p.resolve(root, current.server));
|
|
143
|
+
if (!inside(root, cli, runtime.platform) ||
|
|
144
|
+
!inside(root, server, runtime.platform) ||
|
|
145
|
+
!same(cli, await canonical(runtime, runtime.cliExecutable), runtime.platform)) {
|
|
146
|
+
fail("UPGRADE_PROVENANCE_UNSUPPORTED", "The running CLI does not belong to this package.");
|
|
147
|
+
}
|
|
148
|
+
const proofs = (await Promise.all([proveNpm(runtime, root), proveVolta(runtime)])).filter((proof) => proof !== undefined);
|
|
149
|
+
if (proofs.length !== 1)
|
|
150
|
+
fail("UPGRADE_PROVENANCE_UNSUPPORTED", "Package ownership is ambiguous or unsupported.");
|
|
151
|
+
const proof = proofs[0];
|
|
152
|
+
let latest;
|
|
153
|
+
try {
|
|
154
|
+
latest = await runtime.latestVersion(proof.kind);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
fail("UPGRADE_INSPECTION_FAILED", "Latest package version could not be verified.");
|
|
158
|
+
}
|
|
159
|
+
const update = updateAvailable(current.version, latest);
|
|
160
|
+
return {
|
|
161
|
+
version: 1,
|
|
162
|
+
status: "ok",
|
|
163
|
+
current_version: current.version,
|
|
164
|
+
latest_version: latest,
|
|
165
|
+
provenance: proof.kind,
|
|
166
|
+
update_available: update,
|
|
167
|
+
action: "ast-tool upgrade",
|
|
168
|
+
restart_required: update,
|
|
169
|
+
package_root: root,
|
|
170
|
+
cli_executable: cli,
|
|
171
|
+
install_executable: proof.executable,
|
|
172
|
+
install_args: proof.args,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
export async function inspectUpgrade(runtime) {
|
|
176
|
+
const plan = await planUpgrade(runtime);
|
|
177
|
+
return {
|
|
178
|
+
version: plan.version,
|
|
179
|
+
status: plan.status,
|
|
180
|
+
current_version: plan.current_version,
|
|
181
|
+
latest_version: plan.latest_version,
|
|
182
|
+
provenance: plan.provenance,
|
|
183
|
+
update_available: plan.update_available,
|
|
184
|
+
action: plan.action,
|
|
185
|
+
restart_required: plan.restart_required,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
export async function performUpgrade(runtime) {
|
|
189
|
+
const planned = await planUpgrade(runtime);
|
|
190
|
+
if (!planned.update_available) {
|
|
191
|
+
return {
|
|
192
|
+
...inspectionFrom(planned),
|
|
193
|
+
status: "current",
|
|
194
|
+
installed_version: planned.current_version,
|
|
195
|
+
new_cli: planned.cli_executable,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
await runtime.run(planned.install_executable, planned.install_args);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
fail("UPGRADE_VERIFICATION_FAILED", "Package update command failed.");
|
|
203
|
+
}
|
|
204
|
+
let installed;
|
|
205
|
+
try {
|
|
206
|
+
installed = await planUpgrade(runtime);
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
fail("UPGRADE_VERIFICATION_FAILED", "Updated package verification failed.");
|
|
210
|
+
}
|
|
211
|
+
if (installed.current_version !== installed.latest_version || installed.update_available) {
|
|
212
|
+
fail("UPGRADE_VERIFICATION_FAILED", "Updated package does not match refreshed latest.");
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
...inspectionFrom(installed),
|
|
216
|
+
status: "updated",
|
|
217
|
+
restart_required: true,
|
|
218
|
+
installed_version: installed.current_version,
|
|
219
|
+
new_cli: installed.cli_executable,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function inspectionFrom(plan) {
|
|
223
|
+
return {
|
|
224
|
+
version: plan.version,
|
|
225
|
+
current_version: plan.current_version,
|
|
226
|
+
latest_version: plan.latest_version,
|
|
227
|
+
provenance: plan.provenance,
|
|
228
|
+
update_available: plan.update_available,
|
|
229
|
+
action: plan.action,
|
|
230
|
+
restart_required: plan.restart_required,
|
|
231
|
+
};
|
|
232
|
+
}
|
package/docs/support.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# Support policy
|
|
2
2
|
|
|
3
|
-
This document defines the supported platform, runtime, persistence, and operational boundary for published `ast-mcp-server` v0.
|
|
3
|
+
This document defines the supported platform, runtime, persistence, and operational boundary for published `ast-mcp-server` v0.10.0 and the local `0.11.0` release candidate.
|
|
4
4
|
|
|
5
5
|
## Supported release target
|
|
6
6
|
|
|
7
|
-
| Environment | Status | Contract
|
|
8
|
-
| ----------------------------------------------------------------------------- | ----------- |
|
|
9
|
-
| Linux x64 with required GNU coreutils and procfs, Node.js 22.5.0 |
|
|
10
|
-
| Linux x64 with required GNU coreutils and procfs, exact Node.js 22.13.0 | Supported |
|
|
11
|
-
| Linux x64 with required GNU coreutils and procfs, current Node.js 24 line | Supported | Published v0.
|
|
12
|
-
| Other Linux architectures or systems without the required filesystem features | Unverified | Not supported until equivalent architecture, mutation, and filesystem-publication gates pass.
|
|
13
|
-
| macOS | Unverified | Not supported until equivalent filesystem, process, package, mutation, and canary gates pass.
|
|
14
|
-
| Windows | Unverified | Not supported until equivalent filesystem, process, package, mutation, and canary gates pass.
|
|
15
|
-
| Remote, untrusted, or multi-tenant service use | Unsupported | No network authentication, sandbox, or tenant-isolation boundary is provided.
|
|
7
|
+
| Environment | Status | Contract |
|
|
8
|
+
| ----------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------- |
|
|
9
|
+
| Linux x64 with required GNU coreutils and procfs, Node.js 22.5.0 | Historical | Immutable v0.8.1 release evidence; not the runtime floor of the published or candidate lines. |
|
|
10
|
+
| Linux x64 with required GNU coreutils and procfs, exact Node.js 22.13.0 | Supported | Published v0.10.0 and local 0.11.0 matrices, each bound to its own package and tree bytes. |
|
|
11
|
+
| Linux x64 with required GNU coreutils and procfs, current Node.js 24 line | Supported | Published v0.10.0 and local 0.11.0 matrices, each bound to its own package and tree bytes. |
|
|
12
|
+
| Other Linux architectures or systems without the required filesystem features | Unverified | Not supported until equivalent architecture, mutation, and filesystem-publication gates pass. |
|
|
13
|
+
| macOS | Unverified | Not supported until equivalent filesystem, process, package, mutation, and canary gates pass. |
|
|
14
|
+
| Windows | Unverified | Not supported until equivalent filesystem, process, package, mutation, and canary gates pass. |
|
|
15
|
+
| Remote, untrusted, or multi-tenant service use | Unsupported | No network authentication, sandbox, or tenant-isolation boundary is provided. |
|
|
16
16
|
|
|
17
|
-
The local `0.
|
|
17
|
+
The local `0.11.0` candidate requires Node.js `>=22.13.0`; its matrix targets exact Node.js 22.13.0 and the governed Node.js 24 major. Published v0.10.0 retains its immutable `>=22.13.0` metadata and exact Node.js 22.13.0/24 release evidence. The earlier v0.8.1 Node.js 22.5.0/24 matrix remains historical evidence for those bytes only. A future runtime satisfying an engine range is not automatically a verified release target.
|
|
18
18
|
|
|
19
19
|
The checked-evidence freezer requires GNU coreutils 9.7 `mv` with `--update=none-fail`, `--no-copy`, and `--no-target-directory`. Managed setup-file mutation additionally requires that same `mv` with `--exchange`, GNU coreutils `ln -L -T`, procfs descriptor paths at `/proc/self/fd`, `O_DIRECTORY`, and `O_NOFOLLOW`. It fails closed when any verified Linux primitive is unavailable. Equivalent publication, exchange, descriptor-link, and descriptor-relative mutation semantics have not been verified on other operating systems or architectures.
|
|
20
20
|
|
|
@@ -34,7 +34,7 @@ Operation locks coordinate cooperating same-user processes. They do not stop edi
|
|
|
34
34
|
|
|
35
35
|
## Symbol-index persistence
|
|
36
36
|
|
|
37
|
-
Published v0.
|
|
37
|
+
Published v0.10.0 and the local `0.11.0` candidate select native SQLite when the persistence setting is absent or explicitly `enabled`; operators requiring no persistent index state must set `disabled` explicitly:
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
AST_SYMBOL_INDEX_PERSISTENCE=disabled \
|
|
@@ -64,7 +64,7 @@ Both commands are bounded and path-free. Clear preflights the tree, refuses unsa
|
|
|
64
64
|
|
|
65
65
|
## Production-readiness acceptance
|
|
66
66
|
|
|
67
|
-
The four retained Linux x64 production-readiness reports cover `ast-mcp-server` and `x-scraper` under Node.js 22.5.0 and Node.js 24 for package version 0.6.0, commit `2d0b21bbb80fae1acfca6a85d5891d87e68b59c1`, and tree `af931d49769fabdf06f623965a6cfe1f9afb8a81`. They are historical integration evidence only: they are not reattributed to v0.8.1, published-next v0.9.0 or v0.9.1,
|
|
67
|
+
The four retained Linux x64 production-readiness reports cover `ast-mcp-server` and `x-scraper` under Node.js 22.5.0 and Node.js 24 for package version 0.6.0, commit `2d0b21bbb80fae1acfca6a85d5891d87e68b59c1`, and tree `af931d49769fabdf06f623965a6cfe1f9afb8a81`. They are historical integration evidence only: they are not reattributed to v0.8.1, published-next v0.9.0 or v0.9.1, the local 0.9.2 candidate, published v0.10.0, or the local v0.11.0 candidate. The exact 0.9.0 and 0.9.1 release matrices remain historical evidence for their immutable published-next bytes, the exact 0.9.2 matrix remains historical local-candidate evidence, and the exact 0.10.0 matrix remains historical published-release evidence for its own bytes. A separate exact 0.11.0 release matrix is the candidate-specific gate for current repository bytes under both supported runtime lines, including managed setup; none of these matrices rebinds the older retained reports. MCP-PROD-404 remains normative for admission:
|
|
68
68
|
|
|
69
69
|
- zero semantic mismatches across disabled, cold, warm, restart, and rollback reads;
|
|
70
70
|
- byte-identical real-repository status and worktree trees;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ast-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Structural code MCP server and batch CLI for compact TypeScript/JavaScript reads and hash-bound AST edits.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -97,5 +97,5 @@
|
|
|
97
97
|
"typescript-eslint": "^8.65.0",
|
|
98
98
|
"vitest": "^4.1.10"
|
|
99
99
|
},
|
|
100
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "f0c8a66d72db71ffdf8ef0014f4b7b28f1d8852e"
|
|
101
101
|
}
|