ast-mcp-server 0.8.0 → 0.9.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 +39 -4
- package/README.md +13 -4
- package/SECURITY.md +1 -1
- package/dist/cli.js +21 -0
- package/dist/services/opencode-config.js +15 -2
- package/dist/services/project.js +12 -2
- package/dist/services/symbol-index-cache.js +847 -0
- package/dist/services/symbol-index-policy.js +48 -15
- package/dist/services/symbol-index-sqlite.js +266 -7
- package/docs/support.md +31 -16
- package/package.json +4 -3
- package/skills/structural-code-editing/SKILL.md +3 -3
- package/skills/structural-code-editing/releases.json +12 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,42 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
-
## [0.
|
|
9
|
+
## [0.9.0] — local release candidate, pending release (2026-08-16)
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added bounded `ast-tool cache inspect` and confirmation-gated `ast-tool cache clear --yes`; both avoid host paths, reject unsafe trees, preserve unknown files, and perform no automatic garbage collection.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Native SQLite is now the requested symbol-index backend when `AST_SYMBOL_INDEX_PERSISTENCE` is absent or `enabled`; explicit `disabled` remains the immediate memory-only rollback, and `canary` still requires an explicit safe root.
|
|
18
|
+
- The current development-line engine floor and lower evidence lane are Node.js `>=22.13.0` and exact `v22.13.0` respectively; Node.js 24 remains governed by major, and active harnesses no longer use `--experimental-sqlite`.
|
|
19
|
+
- Default persistence resolves through an explicit override, XDG cache home, then HOME, while invalid explicit overrides fail closed instead of being hidden by another root.
|
|
20
|
+
- Integration, package, CLI and consumer harnesses now exercise default SQLite, restart reuse, explicit rollback, mutation-only cache isolation and private artifacts.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Promotion now tolerates bounded npm dist-tag propagation lag while revalidating package version, `gitHead`, integrity, provenance, and the complete `next`/`latest` state on every readback.
|
|
25
|
+
|
|
26
|
+
### Security
|
|
27
|
+
|
|
28
|
+
- Package-created cache directories use `0700`; SQLite main, WAL, SHM and quarantine artifacts use `0600` on supported Linux, with no-follow, ownership, link-count and device/inode validation around database open, quarantine and cleanup.
|
|
29
|
+
|
|
30
|
+
### Release status
|
|
31
|
+
|
|
32
|
+
- This local candidate is pending exact-tree CI and the repository's separately authorized delivery sequence. It has not been published to npm, assigned to `next` or `latest`, tagged in Git, or released on GitHub; registry and GitHub readbacks remain authoritative.
|
|
33
|
+
|
|
34
|
+
## [0.8.1] — published to `latest` and `next`, registry verified (2026-08-14)
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- Public-registry verification now prepares the pinned GNU coreutils 9.7 `mv` primitive before running the managed-setup consumer smoke, and workflow policy rejects removal or reordering of that prerequisite.
|
|
39
|
+
|
|
40
|
+
### Release status
|
|
41
|
+
|
|
42
|
+
- npm published these immutable bytes under `next` with provenance and the expected Git commit. Public-consumer verification passed, `latest` and `next` both resolve to `0.8.1`, and the annotated `v0.8.1` tag plus GitHub Release resolve to the same release commit.
|
|
43
|
+
|
|
44
|
+
## [0.8.0] — published to `next`, verification failed, not promoted (2026-08-14)
|
|
10
45
|
|
|
11
46
|
### Fixed
|
|
12
47
|
|
|
@@ -25,9 +60,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
25
60
|
|
|
26
61
|
### Release status
|
|
27
62
|
|
|
28
|
-
-
|
|
63
|
+
- npm published these immutable bytes under `next` with provenance and the expected Git commit. Public-consumer verification stopped during managed setup because the verification workflow had not prepared its required GNU coreutils 9.7 `mv`; the package was never promoted to `latest`, tagged, or released on GitHub. Version `0.8.1` superseded it after verified publication.
|
|
29
64
|
|
|
30
|
-
## [0.7.2] — published to `latest
|
|
65
|
+
## [0.7.2] — published to `latest`, registry verified (2026-08-13)
|
|
31
66
|
|
|
32
67
|
### Fixed
|
|
33
68
|
|
|
@@ -41,7 +76,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
41
76
|
|
|
42
77
|
### Release status
|
|
43
78
|
|
|
44
|
-
- npm
|
|
79
|
+
- npm promoted the immutable `0.7.2` bytes to `latest`. Later `next` assignments do not alter those bytes, and the `0.8.x` sections above describe distinct package versions that cannot be attributed to `0.7.2`.
|
|
45
80
|
|
|
46
81
|
## [0.7.1] — published to `next`, verified, not promoted (2026-08-12)
|
|
47
82
|
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[](https://github.com/yailPeralta/ast-mcp-server/actions/workflows/ci.yml)
|
|
8
8
|
[](https://www.npmjs.com/package/ast-mcp-server)
|
|
9
|
-
[](https://nodejs.org/)
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
|
|
12
12
|
`ast-mcp-server` gives coding agents compact, type-aware access to TypeScript and JavaScript projects. It uses the real compiler project model through `ts-morph`, so declarations, references, rename locations, and diagnostics come from the AST instead of text-search guesses.
|
|
@@ -76,17 +76,26 @@ The included batch benchmark records a 50% reduction in model round-trips and a
|
|
|
76
76
|
|
|
77
77
|
## Requirements
|
|
78
78
|
|
|
79
|
-
- Node.js 22.
|
|
79
|
+
- Node.js 22.13.0 or newer
|
|
80
80
|
- Corepack with Yarn 4.15.0 (pinned by `packageManager`)
|
|
81
81
|
- A target project with a `tsconfig.json`
|
|
82
82
|
|
|
83
83
|
## Supported environment and trust boundary
|
|
84
84
|
|
|
85
|
-
The
|
|
85
|
+
The local `0.9.0` release candidate requires Node.js `>=22.13.0`; its evidence matrix targets exact Node.js 22.13.0 and the current Node.js 24 line. Published v0.8.1 retains its immutable historical Node.js 22.5.0/24 evidence. Managed setup-file publication additionally requires GNU coreutils 9.7 `mv` supporting `--update=none-fail`, `--exchange`, `--no-copy`, and `--no-target-directory`, GNU coreutils `ln -L -T`, procfs descriptor paths at `/proc/self/fd`, and `O_DIRECTORY`/`O_NOFOLLOW`. Other Linux architectures or systems without those filesystem primitives, macOS, and Windows remain unverified.
|
|
86
86
|
|
|
87
87
|
This is a local stdio server. It runs with the invoking user's filesystem permissions, and clients may request any `project_root` that user can access. It does not provide HTTP authentication, sandboxing, tenant isolation, or a remote-service security boundary. Remote, untrusted, and multi-tenant operation is unsupported.
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
In the local `0.9.0` release candidate, an absent `AST_SYMBOL_INDEX_PERSISTENCE` or explicit `enabled` selects the private SQLite symbol-index cache. `disabled` is the immediate memory-only rollback. `canary` requires an explicit absolute normalized `AST_SYMBOL_INDEX_CACHE_ROOT`. Invalid policy or storage fails closed to compiler-authoritative memory reads with bounded path-free status.
|
|
90
|
+
|
|
91
|
+
The default cache root is selected from `AST_SYMBOL_INDEX_CACHE_ROOT`, then `XDG_CACHE_HOME`, then `HOME`. Inspect or clear only derived cache artifacts through the bounded CLI:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
ast-tool cache inspect
|
|
95
|
+
ast-tool cache clear --yes
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Clear requires exact confirmation, refuses unsafe or active SQLite artifacts, and preserves unknown regular files. No automatic cache GC is enabled.
|
|
90
99
|
|
|
91
100
|
See [Support policy](docs/support.md) for the complete platform, runtime, persistence, and operational contract. Report security issues through [SECURITY.md](SECURITY.md).
|
|
92
101
|
|
package/SECURITY.md
CHANGED
|
@@ -11,7 +11,7 @@ Security fixes are provided for the exact version currently identified by the np
|
|
|
11
11
|
| Earlier npm versions | No |
|
|
12
12
|
| Unpublished release candidates | No |
|
|
13
13
|
|
|
14
|
-
This project supports trusted single-user local stdio use; the supported operating-system and architecture boundary remains Linux x64 only. The
|
|
14
|
+
This project supports trusted single-user local stdio use; the supported operating-system and architecture boundary remains Linux x64 only. The local `0.9.0` release candidate requires Node.js `>=22.13.0`, with evidence targeted at exact Node.js 22.13.0 and the governed Node.js 24 major. Published v0.8.1 retains its immutable Node.js 22.5.0/24 release matrix. Managed setup mutation requires GNU coreutils 9.7 `mv --update=none-fail --exchange --no-copy --no-target-directory`, GNU coreutils `ln -L -T`, and procfs descriptor-relative paths at `/proc/self/fd` with `O_DIRECTORY`/`O_NOFOLLOW`. The candidate's default SQLite cache also relies on Linux ownership, mode, no-follow, link-count and inode-identity checks; it does not defend against a malicious same-UID process. Other Linux architectures and systems without those primitives are unverified, as are macOS and Windows. Remote, untrusted, and multi-tenant use is outside the supported security boundary.
|
|
15
15
|
|
|
16
16
|
## Reporting a vulnerability
|
|
17
17
|
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import { BatchExecutionError, parseBatchDocument, runBatchDocument } from "./bat
|
|
|
6
6
|
import { MAX_BATCH_INPUT_BYTES, isPrepareBatchTool } from "./batch/schema.js";
|
|
7
7
|
import { CliOutputError, serializeCliSuccess } from "./cli-output.js";
|
|
8
8
|
import { applyPersistedOperation, persistOperationPlan } from "./services/operation-plan-file.js";
|
|
9
|
+
import { clearSymbolIndexCache, inspectSymbolIndexCache, SymbolIndexCacheError, } from "./services/symbol-index-cache.js";
|
|
9
10
|
import { AgentSetupError, detectInstalledAgents, resolveServerEntryPath, runAgentSetup, } from "./services/agent-setup.js";
|
|
10
11
|
import { installBundledSkill, resolveBundledSkillAssets, } from "./services/skill-installer.js";
|
|
11
12
|
import { parseAgentsArgument, promptForAgentSelection, resolveAgentSelection, } from "./services/setup-wizard.js";
|
|
@@ -31,6 +32,8 @@ function usage() {
|
|
|
31
32
|
" ast-tool run <pipeline.json|-> [--output-format json|toon]",
|
|
32
33
|
" ast-tool validate <pipeline.json|->",
|
|
33
34
|
" ast-tool apply <plan.astplan> --plan-hash <sha256>",
|
|
35
|
+
" ast-tool cache inspect",
|
|
36
|
+
" ast-tool cache clear --yes",
|
|
34
37
|
" ast-tool install-skill [claude|hermes|all] [--scope user|project] [--project-root <path>] [--force]",
|
|
35
38
|
" ast-tool setup [--agents claude,hermes|all --yes] [--force-skill]",
|
|
36
39
|
].join("\n");
|
|
@@ -227,6 +230,24 @@ export async function runCli(args) {
|
|
|
227
230
|
throw new CliError(error instanceof Error ? error.message : String(error), "EXECUTION_ERROR", 1, command, undefined, { cause: error });
|
|
228
231
|
}
|
|
229
232
|
}
|
|
233
|
+
if (command === "cache") {
|
|
234
|
+
const [subcommand, ...cacheArgs] = commandArgs;
|
|
235
|
+
const cacheCommand = subcommand ? `cache ${subcommand}` : "cache";
|
|
236
|
+
const inspectRequested = subcommand === "inspect" && cacheArgs.length === 0;
|
|
237
|
+
const clearRequested = subcommand === "clear" && cacheArgs.length === 1 && cacheArgs[0] === "--yes";
|
|
238
|
+
if (!inspectRequested && !clearRequested) {
|
|
239
|
+
throw new CliError(usage(), "USAGE", 2, cacheCommand);
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
return inspectRequested ? await inspectSymbolIndexCache() : await clearSymbolIndexCache();
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
if (error instanceof SymbolIndexCacheError) {
|
|
246
|
+
throw new CliError(error.message, error.code, 1, cacheCommand, undefined, { cause: error }, error.details);
|
|
247
|
+
}
|
|
248
|
+
throw new CliError("Cache command failed without exposing host details.", "CACHE_ERROR", 1, cacheCommand, undefined, { cause: error });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
230
251
|
if (command === "apply") {
|
|
231
252
|
const { planFile, planHash } = parseApplyArgs(commandArgs);
|
|
232
253
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { link, mkdir, mkdtemp, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { link, mkdir, mkdtemp, open, readFile, rename, rm, stat, writeFile, } from "node:fs/promises";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { applyEdits, modify, parse } from "jsonc-parser";
|
|
@@ -120,8 +120,21 @@ export async function applyOpenCodeConfigPlan(plan) {
|
|
|
120
120
|
const directory = path.dirname(plan.filePath);
|
|
121
121
|
await mkdir(directory, { recursive: true });
|
|
122
122
|
const temporary = path.join(directory, `.${path.basename(plan.filePath)}.${randomUUID()}.tmp`);
|
|
123
|
-
await writeFile(temporary, plan.content, { encoding: "utf8", flag: "wx", mode: plan.mode });
|
|
124
123
|
try {
|
|
124
|
+
let handle;
|
|
125
|
+
try {
|
|
126
|
+
handle = await open(temporary, "wx", plan.mode);
|
|
127
|
+
await handle.writeFile(plan.content, { encoding: "utf8" });
|
|
128
|
+
await handle.chmod(plan.mode);
|
|
129
|
+
await handle.sync();
|
|
130
|
+
const staged = await handle.stat();
|
|
131
|
+
if ((staged.mode & 0o777) !== plan.mode) {
|
|
132
|
+
throw new Error("OpenCode configuration mode could not be preserved.");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
await handle?.close();
|
|
137
|
+
}
|
|
125
138
|
if (!plan.beforeExists) {
|
|
126
139
|
await link(temporary, plan.filePath);
|
|
127
140
|
await rm(temporary);
|
package/dist/services/project.js
CHANGED
|
@@ -32,8 +32,14 @@ function getProjectRuntimePolicy() {
|
|
|
32
32
|
return projectRuntimePolicy;
|
|
33
33
|
}
|
|
34
34
|
function closePersistentSymbolIndex(session) {
|
|
35
|
-
session.persistentSymbolIndex
|
|
35
|
+
const persistentSymbolIndex = session.persistentSymbolIndex;
|
|
36
36
|
session.persistentSymbolIndex = undefined;
|
|
37
|
+
try {
|
|
38
|
+
persistentSymbolIndex?.close();
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Detachment is authoritative; a stale SQLite store must not survive cleanup failure.
|
|
42
|
+
}
|
|
37
43
|
}
|
|
38
44
|
function symbolIndexFailureOperation(reason) {
|
|
39
45
|
if (reason === "corrupt_storage")
|
|
@@ -118,8 +124,12 @@ async function ensureSessionSymbolIndex(session, requestContext) {
|
|
|
118
124
|
symbolIndexObservability: createInitialSymbolIndexRuntimeObservability(policy),
|
|
119
125
|
};
|
|
120
126
|
}
|
|
121
|
-
if (policy.backend === "memory")
|
|
127
|
+
if (policy.backend === "memory") {
|
|
128
|
+
if (policy.mode === "enabled" || policy.mode === "canary") {
|
|
129
|
+
fallbackToMemory(session, policy.reason);
|
|
130
|
+
}
|
|
122
131
|
return;
|
|
132
|
+
}
|
|
123
133
|
if (session.persistentSymbolIndex)
|
|
124
134
|
return;
|
|
125
135
|
const cachePath = symbolIndexCachePath(policy, session.context.status.project);
|