ast-mcp-server 0.7.2 → 0.8.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 +33 -1
- package/README.md +36 -14
- package/SECURITY.md +8 -8
- package/dist/cli.js +18 -14
- package/dist/services/agent-setup.js +248 -27
- package/dist/services/agent-targets.js +209 -63
- package/dist/services/checkbox-state.js +31 -0
- package/dist/services/managed-file.js +709 -0
- package/dist/services/managed-guidance.js +229 -0
- package/dist/services/opencode-config.js +135 -0
- package/dist/services/raw-tty.js +75 -0
- package/dist/services/setup-wizard.js +45 -93
- package/dist/services/skill-installer.js +145 -84
- package/docs/support.md +13 -13
- package/package.json +6 -3
- package/skills/structural-code-editing/SKILL.md +9 -3
- package/skills/structural-code-editing/guidance.md +3 -0
- package/skills/structural-code-editing/releases.json +45 -0
|
@@ -1,127 +1,188 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { link, mkdir, readFile, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
1
|
+
import { readFile, realpath, stat } from "node:fs/promises";
|
|
3
2
|
import os from "node:os";
|
|
4
3
|
import path from "node:path";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { applyManagedFilePlan, canonicalizeFuturePath, captureManagedFileSnapshot, createManagedFileApplyContext, hashBytes, verifyManagedFilePostimage, } from "./managed-file.js";
|
|
5
6
|
const SKILL_NAME = "structural-code-editing";
|
|
7
|
+
const SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
8
|
+
const ReleaseRecordSchema = z
|
|
9
|
+
.object({
|
|
10
|
+
version: z.string().min(1),
|
|
11
|
+
sha256: z.string().regex(SHA256_PATTERN),
|
|
12
|
+
npm_versions: z.array(z.string().min(1)).min(1),
|
|
13
|
+
})
|
|
14
|
+
.strict();
|
|
15
|
+
const SkillReleaseManifestSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
schema_version: z.literal(1),
|
|
18
|
+
algorithm: z.literal("sha256"),
|
|
19
|
+
current: z
|
|
20
|
+
.object({
|
|
21
|
+
version: z.string().min(1),
|
|
22
|
+
sha256: z.string().regex(SHA256_PATTERN),
|
|
23
|
+
})
|
|
24
|
+
.strict(),
|
|
25
|
+
predecessors: z.array(ReleaseRecordSchema),
|
|
26
|
+
})
|
|
27
|
+
.strict();
|
|
6
28
|
export class SkillConflictError extends Error {
|
|
7
29
|
destination;
|
|
8
30
|
constructor(destination) {
|
|
9
31
|
super(`Skill already exists with different content at ${destination}; pass --force to replace it.`);
|
|
10
|
-
this.name = "SkillConflictError";
|
|
11
32
|
this.destination = destination;
|
|
33
|
+
this.name = "SkillConflictError";
|
|
12
34
|
}
|
|
13
35
|
}
|
|
36
|
+
export async function resolveBundledSkillAssets(executablePath) {
|
|
37
|
+
const root = path.resolve(path.dirname(await realpath(executablePath)), "..", "skills", SKILL_NAME);
|
|
38
|
+
const assets = {
|
|
39
|
+
skillPath: path.join(root, "SKILL.md"),
|
|
40
|
+
guidancePath: path.join(root, "guidance.md"),
|
|
41
|
+
releasesPath: path.join(root, "releases.json"),
|
|
42
|
+
};
|
|
43
|
+
for (const [label, filePath] of Object.entries(assets)) {
|
|
44
|
+
const info = await stat(filePath).catch(() => undefined);
|
|
45
|
+
if (!info?.isFile())
|
|
46
|
+
throw new Error(`Bundled ${label} is missing or not a regular file: ${filePath}`);
|
|
47
|
+
}
|
|
48
|
+
return assets;
|
|
49
|
+
}
|
|
14
50
|
export async function resolveBundledSkillPath(executablePath) {
|
|
15
|
-
|
|
16
|
-
return path.resolve(path.dirname(resolvedExecutable), "..", "skills", SKILL_NAME, "SKILL.md");
|
|
51
|
+
return (await resolveBundledSkillAssets(executablePath)).skillPath;
|
|
17
52
|
}
|
|
18
|
-
function
|
|
19
|
-
return path.resolve(
|
|
53
|
+
function configured(value, fallback, cwd) {
|
|
54
|
+
return path.resolve(cwd, value ?? fallback);
|
|
20
55
|
}
|
|
21
|
-
async function
|
|
22
|
-
|
|
56
|
+
async function destinations(options) {
|
|
57
|
+
const targets = options.target === "all"
|
|
58
|
+
? ["claude", "hermes"]
|
|
59
|
+
: Array.isArray(options.target)
|
|
60
|
+
? [...options.target]
|
|
61
|
+
: [options.target];
|
|
62
|
+
if (options.scope === "project" && targets.some((target) => target !== "claude"))
|
|
23
63
|
throw new Error("Project scope is supported only for Claude Code skills.");
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const environment = options.environment ?? process.env;
|
|
28
|
-
const targets = options.target === "all" ? ["claude", "hermes"] : [options.target];
|
|
64
|
+
const home = options.homeDirectory ?? os.homedir();
|
|
65
|
+
const cwd = options.workingDirectory ?? process.cwd();
|
|
66
|
+
const env = options.environment ?? process.env;
|
|
29
67
|
let projectRoot;
|
|
30
68
|
if (options.scope === "project") {
|
|
31
|
-
projectRoot = path.resolve(
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
throw error;
|
|
37
|
-
});
|
|
38
|
-
if (!projectStats.isDirectory()) {
|
|
39
|
-
throw new Error(`Project root is not a directory: ${projectRoot}`);
|
|
40
|
-
}
|
|
69
|
+
projectRoot = path.resolve(cwd, options.projectRoot ?? cwd);
|
|
70
|
+
const info = await stat(projectRoot).catch(() => undefined);
|
|
71
|
+
if (!info?.isDirectory())
|
|
72
|
+
throw new Error(`Project root does not exist or is not a directory: ${projectRoot}`);
|
|
41
73
|
}
|
|
42
|
-
|
|
74
|
+
const result = targets.map((target) => {
|
|
75
|
+
let destination;
|
|
43
76
|
if (target === "claude") {
|
|
44
77
|
const root = options.scope === "project"
|
|
45
78
|
? path.join(projectRoot, ".claude")
|
|
46
|
-
:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
79
|
+
: configured(env.CLAUDE_CONFIG_DIR, path.join(home, ".claude"), cwd);
|
|
80
|
+
destination = path.join(root, "skills", SKILL_NAME, "SKILL.md");
|
|
81
|
+
}
|
|
82
|
+
else if (target === "hermes") {
|
|
83
|
+
destination = path.join(configured(env.HERMES_HOME, path.join(home, ".hermes"), cwd), "skills", "software-development", SKILL_NAME, "SKILL.md");
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
destination = path.join(home, ".agents", "skills", SKILL_NAME, "SKILL.md");
|
|
52
87
|
}
|
|
53
|
-
const hermesHome = resolveConfiguredDirectory(environment.HERMES_HOME, path.join(homeDirectory, ".hermes"), workingDirectory);
|
|
54
88
|
return {
|
|
55
89
|
target,
|
|
56
|
-
scope: "user",
|
|
57
|
-
path:
|
|
90
|
+
scope: target === "claude" ? options.scope : "user",
|
|
91
|
+
path: destination,
|
|
58
92
|
};
|
|
59
93
|
});
|
|
94
|
+
return Promise.all(result.map(async (item) => ({ ...item, path: await canonicalizeFuturePath(item.path) })));
|
|
60
95
|
}
|
|
61
|
-
async function
|
|
96
|
+
async function readReleaseManifest(manifestPath) {
|
|
97
|
+
let parsed;
|
|
62
98
|
try {
|
|
63
|
-
|
|
64
|
-
if (existingContent === sourceContent)
|
|
65
|
-
return "unchanged";
|
|
66
|
-
if (!force) {
|
|
67
|
-
throw new SkillConflictError(destination);
|
|
68
|
-
}
|
|
69
|
-
return "updated";
|
|
99
|
+
parsed = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
70
100
|
}
|
|
71
101
|
catch (error) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
102
|
+
throw new Error(`Skill release manifest is unreadable or invalid JSON: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
103
|
+
}
|
|
104
|
+
const result = SkillReleaseManifestSchema.safeParse(parsed);
|
|
105
|
+
if (!result.success) {
|
|
106
|
+
throw new Error(`Skill release manifest is invalid: ${result.error.issues[0]?.message ?? "unknown error"}`);
|
|
107
|
+
}
|
|
108
|
+
const digests = [
|
|
109
|
+
result.data.current.sha256,
|
|
110
|
+
...result.data.predecessors.map((item) => item.sha256),
|
|
111
|
+
];
|
|
112
|
+
if (new Set(digests).size !== digests.length) {
|
|
113
|
+
throw new Error("Skill release manifest contains a duplicate digest.");
|
|
75
114
|
}
|
|
115
|
+
const predecessorVersions = result.data.predecessors.flatMap((item) => item.npm_versions);
|
|
116
|
+
if (new Set(predecessorVersions).size !== predecessorVersions.length) {
|
|
117
|
+
throw new Error("Skill release manifest contains a duplicate npm version provenance entry.");
|
|
118
|
+
}
|
|
119
|
+
return result.data;
|
|
76
120
|
}
|
|
77
|
-
async function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
flag: "wx",
|
|
86
|
-
mode: 0o644,
|
|
87
|
-
});
|
|
88
|
-
try {
|
|
89
|
-
if (status === "installed") {
|
|
90
|
-
await link(temporaryPath, destination).catch((error) => {
|
|
91
|
-
if (error.code === "EEXIST") {
|
|
92
|
-
throw new Error(`Skill appeared concurrently at ${destination}; no files were replaced.`);
|
|
93
|
-
}
|
|
94
|
-
throw error;
|
|
95
|
-
});
|
|
96
|
-
await rm(temporaryPath);
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
await rename(temporaryPath, destination);
|
|
121
|
+
export async function planBundledSkillInstallation(options) {
|
|
122
|
+
const sourcePath = path.resolve(options.sourceSkillPath);
|
|
123
|
+
const source = await readFile(sourcePath);
|
|
124
|
+
const sourceDigest = hashBytes(source);
|
|
125
|
+
const manifestPath = path.resolve(options.releaseManifestPath ?? path.join(path.dirname(sourcePath), "releases.json"));
|
|
126
|
+
const manifest = await readReleaseManifest(manifestPath);
|
|
127
|
+
if (sourceDigest !== manifest.current.sha256) {
|
|
128
|
+
throw new Error(`Skill release manifest current digest does not match source skill bytes: ${sourcePath}`);
|
|
100
129
|
}
|
|
101
|
-
|
|
102
|
-
|
|
130
|
+
const admittedPredecessors = new Set(manifest.predecessors.map((item) => item.sha256));
|
|
131
|
+
const logical = await destinations(options);
|
|
132
|
+
const filesByPath = new Map();
|
|
133
|
+
for (const item of logical) {
|
|
134
|
+
if (filesByPath.has(item.path))
|
|
135
|
+
continue;
|
|
136
|
+
const snapshot = await captureManagedFileSnapshot(item.path);
|
|
137
|
+
let status;
|
|
138
|
+
if (!snapshot.exists)
|
|
139
|
+
status = "installed";
|
|
140
|
+
else if (snapshot.sha256 === sourceDigest)
|
|
141
|
+
status = "unchanged";
|
|
142
|
+
else if (admittedPredecessors.has(snapshot.sha256) || options.force === true)
|
|
143
|
+
status = "updated";
|
|
144
|
+
else
|
|
145
|
+
throw new SkillConflictError(item.path);
|
|
146
|
+
filesByPath.set(item.path, {
|
|
147
|
+
path: item.path,
|
|
148
|
+
snapshot,
|
|
149
|
+
postimage: source,
|
|
150
|
+
postimageSha256: sourceDigest,
|
|
151
|
+
status,
|
|
152
|
+
});
|
|
103
153
|
}
|
|
154
|
+
return {
|
|
155
|
+
installations: logical.map((item) => ({
|
|
156
|
+
...item,
|
|
157
|
+
status: filesByPath.get(item.path).status,
|
|
158
|
+
})),
|
|
159
|
+
files: [...filesByPath.values()],
|
|
160
|
+
};
|
|
104
161
|
}
|
|
105
|
-
export async function
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
for (const destination of destinations) {
|
|
111
|
-
if (!statusByPath.has(destination.path)) {
|
|
112
|
-
statusByPath.set(destination.path, await classifyDestination(destination.path, sourceContent, force));
|
|
162
|
+
export async function applySkillInstallationPlan(plan, onApplied, context = createManagedFileApplyContext()) {
|
|
163
|
+
const authenticated = [];
|
|
164
|
+
for (const file of plan.files) {
|
|
165
|
+
for (const current of authenticated) {
|
|
166
|
+
await verifyManagedFilePostimage(current, context);
|
|
113
167
|
}
|
|
168
|
+
await applyManagedFilePlan(file, context);
|
|
169
|
+
authenticated.push(file);
|
|
170
|
+
await onApplied?.(file);
|
|
114
171
|
}
|
|
115
|
-
for (const
|
|
116
|
-
await
|
|
172
|
+
for (const current of authenticated) {
|
|
173
|
+
await verifyManagedFilePostimage(current, context);
|
|
117
174
|
}
|
|
175
|
+
}
|
|
176
|
+
export async function installBundledSkill(options) {
|
|
177
|
+
const plan = await planBundledSkillInstallation(options);
|
|
178
|
+
await applySkillInstallationPlan(plan);
|
|
118
179
|
return {
|
|
119
180
|
version: 1,
|
|
120
181
|
status: "ok",
|
|
121
182
|
skill: SKILL_NAME,
|
|
122
|
-
installations:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
183
|
+
installations: plan.installations,
|
|
184
|
+
physicalWrites: plan.files
|
|
185
|
+
.filter((file) => file.status !== "unchanged")
|
|
186
|
+
.map((file) => ({ path: file.path, status: file.status })),
|
|
126
187
|
};
|
|
127
188
|
}
|
package/docs/support.md
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
# Support policy
|
|
2
2
|
|
|
3
|
-
This document defines the supported platform, runtime, persistence, and operational boundary for `ast-mcp-server` v0.
|
|
3
|
+
This document defines the supported platform, runtime, persistence, and operational boundary for `ast-mcp-server` v0.8.0 and the current `Unreleased` development line.
|
|
4
4
|
|
|
5
5
|
## Supported release target
|
|
6
6
|
|
|
7
|
-
| Environment
|
|
8
|
-
|
|
|
9
|
-
| Linux x64 with required GNU coreutils, Node.js 22.5.0
|
|
10
|
-
| Linux x64 with required GNU coreutils, current Node.js 24 line
|
|
11
|
-
| Other Linux architectures or systems without required
|
|
12
|
-
| macOS
|
|
13
|
-
| Windows
|
|
14
|
-
| Remote, untrusted, or multi-tenant service use
|
|
7
|
+
| Environment | Status | Contract |
|
|
8
|
+
| ----------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------- |
|
|
9
|
+
| Linux x64 with required GNU coreutils and procfs, Node.js 22.5.0 | Supported | v0.8.0 exact release matrix for MCP/CLI/package, lifecycle, mutation, and managed setup. |
|
|
10
|
+
| Linux x64 with required GNU coreutils and procfs, current Node.js 24 line | Supported | v0.8.0 exact release matrix for MCP/CLI/package, lifecycle, mutation, and managed setup. |
|
|
11
|
+
| Other Linux architectures or systems without the required filesystem features | Unverified | Not supported until equivalent architecture, mutation, and filesystem-publication gates pass. |
|
|
12
|
+
| macOS | Unverified | Not supported until equivalent filesystem, process, package, mutation, and canary gates pass. |
|
|
13
|
+
| Windows | Unverified | Not supported until equivalent filesystem, process, package, mutation, and canary gates pass. |
|
|
14
|
+
| Remote, untrusted, or multi-tenant service use | Unsupported | No network authentication, sandbox, or tenant-isolation boundary is provided. |
|
|
15
15
|
|
|
16
|
-
The package engine floor is Node.js `>=22.5.0
|
|
16
|
+
The package engine floor is Node.js `>=22.5.0`. The v0.8.0 release matrix exercises exact Node.js 22.5.0 and the current Node.js 24 line on Linux, including managed setup-file publication; a future version satisfying the engine range is not automatically a verified release target.
|
|
17
17
|
|
|
18
|
-
The checked-evidence freezer requires GNU coreutils `mv` with `--update=none-fail`, `--no-copy`, and `--no-target-directory`. Equivalent publication semantics have not been verified on other operating systems or architectures.
|
|
18
|
+
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.
|
|
19
19
|
|
|
20
20
|
## Local stdio trust boundary
|
|
21
21
|
|
|
@@ -35,7 +35,7 @@ Operation locks coordinate cooperating same-user processes. They do not stop edi
|
|
|
35
35
|
|
|
36
36
|
The supported default is memory-only indexing. When `AST_SYMBOL_INDEX_PERSISTENCE` is absent, persistence remains disabled and no persistent cache is created.
|
|
37
37
|
|
|
38
|
-
The only candidate-authorized opt-in persistence policy is `canary`; it is not enabled by default in v0.
|
|
38
|
+
The only candidate-authorized opt-in persistence policy is `canary`; it is not enabled by default in v0.8.0:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
AST_SYMBOL_INDEX_PERSISTENCE=canary \
|
|
@@ -49,7 +49,7 @@ The cache root must be explicit and absolute. Use a dedicated local directory wi
|
|
|
49
49
|
|
|
50
50
|
## Production-readiness acceptance
|
|
51
51
|
|
|
52
|
-
The
|
|
52
|
+
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.0 and do not establish managed setup-file publication for that release. The separate exact v0.8.0 release matrix validates the current repository under both runtime lines, including managed setup-file publication. MCP-PROD-404 remains normative for the retained four-report cohort; all four reports must pass the following contract:
|
|
53
53
|
|
|
54
54
|
- zero semantic mismatches across disabled, cold, warm, restart, and rollback reads;
|
|
55
55
|
- 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.8.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",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"resolutions": {
|
|
46
46
|
"hono": "4.12.34",
|
|
47
|
-
"nanoid": "3.3.
|
|
47
|
+
"nanoid": "3.3.18"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "tsc",
|
|
@@ -56,6 +56,8 @@
|
|
|
56
56
|
"test:cli": "yarn build && node scripts/cli-smoke.mjs",
|
|
57
57
|
"test:errors": "yarn build && node scripts/public-error-smoke.mjs",
|
|
58
58
|
"test:package": "node scripts/package-smoke.mjs",
|
|
59
|
+
"test:installed-agents": "yarn build && node scripts/installed-agent-guidance-smoke.mjs",
|
|
60
|
+
"test:agent-fixtures": "node scripts/admit-agent-fixtures.mjs --check",
|
|
59
61
|
"test:release-candidate": "node scripts/release-candidate-matrix.mjs",
|
|
60
62
|
"benchmark": "yarn build && node scripts/benchmark.mjs",
|
|
61
63
|
"benchmark:corpus": "yarn build && node scripts/benchmark-corpus.mjs",
|
|
@@ -80,6 +82,7 @@
|
|
|
80
82
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
81
83
|
"@toon-format/toon": "4.1.0",
|
|
82
84
|
"diff": "^9.0.0",
|
|
85
|
+
"jsonc-parser": "^3.3.1",
|
|
83
86
|
"ts-morph": "24.0.0",
|
|
84
87
|
"zod": "^3.23.8"
|
|
85
88
|
},
|
|
@@ -93,5 +96,5 @@
|
|
|
93
96
|
"typescript-eslint": "^8.65.0",
|
|
94
97
|
"vitest": "^4.1.10"
|
|
95
98
|
},
|
|
96
|
-
"gitHead": "
|
|
99
|
+
"gitHead": "60825430f564e6978e4a21c14a371770bd585e51"
|
|
97
100
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: structural-code-editing
|
|
3
3
|
description: Leer, navegar y editar proyectos TypeScript/JavaScript mediante el resolver real del compilador y operaciones AST preparadas, revisadas y vinculadas por hash.
|
|
4
|
-
version: "4.
|
|
4
|
+
version: "4.2.0"
|
|
5
5
|
author: "yail"
|
|
6
6
|
license: "ISC"
|
|
7
7
|
metadata:
|
|
@@ -12,6 +12,12 @@ metadata:
|
|
|
12
12
|
|
|
13
13
|
# Edición estructural con el servidor MCP `ast`
|
|
14
14
|
|
|
15
|
+
## Contrato de activación
|
|
16
|
+
|
|
17
|
+
Cargar `structural-code-editing` antes de navegar semánticamente, analizar impacto o referencias, consultar diagnostics o preparar una mutación estructural en un proyecto TypeScript/JavaScript gobernado por el compilador. Preferir las tools compiler-backed del servidor `ast` para esas operaciones y revisar cualquier plan antes de aplicarlo.
|
|
18
|
+
|
|
19
|
+
No forzar un roundtrip AST para Markdown, configuración, comentarios ni una edición textual trivial en un archivo ya conocido. Si las tools `ast_*` no están disponibles, declarar el fallback y no presentar búsquedas textuales como evidencia compiler-backed.
|
|
20
|
+
|
|
15
21
|
## Cuándo usarlo
|
|
16
22
|
|
|
17
23
|
Usar las tools del servidor MCP `ast` en proyectos TypeScript/JavaScript con `tsconfig.json` cuando haya que:
|
|
@@ -40,13 +46,13 @@ El setup falla cerrado ante un registro `ast` conflictivo. No eliminar ni reempl
|
|
|
40
46
|
|
|
41
47
|
## Runtime, soporte y errores
|
|
42
48
|
|
|
43
|
-
El paquete requiere Node.js `>=22.5.0`.
|
|
49
|
+
El paquete requiere Node.js `>=22.5.0`. La matriz de release de v0.8.0 cubre Linux x64 con Node.js 22.5.0 y la línea actual de Node.js 24, incluida la publicación de archivos gestionados por setup. Esa mutación requiere además GNU coreutils 9.7 `mv` con `--update=none-fail`, `--exchange`, `--no-copy` y `--no-target-directory`, GNU coreutils `ln -L -T`, y procfs en `/proc/self/fd` con `O_DIRECTORY`/`O_NOFOLLOW`. Otras arquitecturas Linux, sistemas sin esos primitivos, macOS y Windows están sin verificar.
|
|
44
50
|
|
|
45
51
|
El transporte soportado es stdio local bajo los permisos filesystem del usuario que invoca el proceso. No asumir autenticación HTTP, sandbox, aislamiento entre tenants ni una frontera segura para clientes remotos o no confiables.
|
|
46
52
|
|
|
47
53
|
La persistencia del índice está deshabilitada por default. El modo `canary` requiere `AST_SYMBOL_INDEX_PERSISTENCE=canary` y un `AST_SYMBOL_INDEX_CACHE_ROOT` absoluto y aislado; `enabled` sigue sin publicarse y falla cerrado a memoria con `enabled_not_released`.
|
|
48
54
|
|
|
49
|
-
Los errores públicos usan un vocabulario cerrado dentro de `{ "error": { "code", "message", "correlation_id" } }`, con `isError: true`. Conservar el `correlation_id` al reportar un fallo; no pedir ni exponer stacks, paths absolutos, source, cache, argumentos crudos, environment ni credenciales para diagnosticarlo.
|
|
55
|
+
Los errores públicos de las tools MCP usan un vocabulario cerrado dentro de `{ "error": { "code", "message", "correlation_id" } }`, con `isError: true`. Conservar el `correlation_id` al reportar un fallo; no pedir ni exponer stacks, paths absolutos, source, cache, argumentos crudos, environment ni credenciales para diagnosticarlo. Los errores del comando local `setup` pueden incluir un path destino acotado para permitir inspeccionar una escritura incierta o pendiente, pero no argumentos, environment, credenciales ni output crudo del proveedor.
|
|
50
56
|
|
|
51
57
|
## Flujo compacto de lectura
|
|
52
58
|
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
Load the `structural-code-editing` skill before semantic TypeScript/JavaScript navigation, reference or impact analysis, compiler diagnostics, or structural mutation in a compiler-governed project. Prefer the compiler-backed `ast` MCP tools for symbols, references, impact, diagnostics, and reviewed structural mutations.
|
|
2
|
+
|
|
3
|
+
Use ordinary file tools for Markdown, configuration, comments, and trivial text edits in already known files. If the `ast` tools are unavailable, disclose the fallback and never describe textual search as compiler-backed evidence.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"algorithm": "sha256",
|
|
4
|
+
"current": {
|
|
5
|
+
"version": "4.2.0",
|
|
6
|
+
"sha256": "b072ccf68ebd50a825dc9fdbdaaf35cdbf7045ae5fb9a9d7a412dc7b702ee7a0"
|
|
7
|
+
},
|
|
8
|
+
"predecessors": [
|
|
9
|
+
{
|
|
10
|
+
"version": "3.3.0",
|
|
11
|
+
"sha256": "61251830f0a247d63873fbe6a912187a36ff99489241c24c5b2558563f79ab7f",
|
|
12
|
+
"npm_versions": ["0.3.0"]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "3.4.0",
|
|
16
|
+
"sha256": "b9f75a8cb4900f5c6ad652c106d373ea1e951c8757870b4424a59469dd3b0868",
|
|
17
|
+
"npm_versions": ["0.4.0"]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"version": "4.0.0",
|
|
21
|
+
"sha256": "fbc6a9eeb11d3e4ecb5a585283a49b0e4df102b413e7fd82316c2f6e44b2cd56",
|
|
22
|
+
"npm_versions": ["0.5.0", "0.5.1"]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"version": "4.0.0",
|
|
26
|
+
"sha256": "622ab59511396f4acf289bad39fb2a03114352f6dc8556f12b37bde98d67a6b3",
|
|
27
|
+
"npm_versions": ["0.6.0"]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"version": "4.1.0",
|
|
31
|
+
"sha256": "e10f89e8834c97fdb68157b7c5d97ebe59311fb8bbcca0f5f26fb47d684cbf52",
|
|
32
|
+
"npm_versions": ["0.7.0"]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"version": "4.1.0",
|
|
36
|
+
"sha256": "672307b01a93a16e395d40b0b58e06cfca34b54ffd05b697ef471633bc476ad1",
|
|
37
|
+
"npm_versions": ["0.7.1"]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"version": "4.1.0",
|
|
41
|
+
"sha256": "6284fbeaf054947d20693d317604ceabf5a53d32e3c836855a321e5e26766e29",
|
|
42
|
+
"npm_versions": ["0.7.2"]
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|