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 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.8.0] — release candidate (unreleased, 2026-08-14)
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
- - This version is bound to exact-SHA CI and the repository's staged `next` publication, public-registry verification, `latest` promotion, annotated-tag, and hosted-release sequence. npm registry and GitHub readbacks remain authoritative for those external transitions.
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` and `next`, registry verified (2026-08-13)
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 exposes the immutable published `0.7.2` bytes under both `latest` and `next`. The `0.8.0` section above describes distinct release bytes and cannot be attributed to that package version.
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
  [![CI](https://github.com/yailPeralta/ast-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/yailPeralta/ast-mcp-server/actions/workflows/ci.yml)
8
8
  [![npm version](https://img.shields.io/npm/v/ast-mcp-server.svg)](https://www.npmjs.com/package/ast-mcp-server)
9
- [![Node.js 22.5+](https://img.shields.io/badge/Node.js-22.5%2B-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
9
+ [![Node.js 22.13+](https://img.shields.io/badge/Node.js-22.13%2B-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
10
10
  [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](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.5.0 or newer
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 package engine floor remains Node.js `>=22.5.0`. The v0.8.0 release matrix covers Linux x64 under exact Node.js 22.5.0 and the current Node.js 24 line, including managed setup-file publication. That mutation 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 until equivalent exact-tree gates pass.
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
- Symbol-index persistence remains disabled by default. `AST_SYMBOL_INDEX_PERSISTENCE=canary` additionally requires an explicit absolute `AST_SYMBOL_INDEX_CACHE_ROOT`; the reserved `enabled` mode fails closed to memory-only with `enabled_not_released`.
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 package engine floor is Node.js `>=22.5.0`, and the v0.8.0 release matrix covers Linux x64 under exact Node.js 22.5.0 and the current Node.js 24 line, including managed setup-file publication. That 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`. 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.
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);
@@ -32,8 +32,14 @@ function getProjectRuntimePolicy() {
32
32
  return projectRuntimePolicy;
33
33
  }
34
34
  function closePersistentSymbolIndex(session) {
35
- session.persistentSymbolIndex?.close();
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);