ast-mcp-server 0.11.2 → 0.12.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 +17 -2
- package/README.md +20 -2
- package/SECURITY.md +1 -1
- package/dist/batch/schema.js +7 -16
- package/dist/server.js +2 -32
- package/dist/services/agent-targets.js +2 -14
- package/dist/services/diagnostics.js +55 -0
- package/dist/tools/apply_operation.js +5 -2
- package/dist/tools/catalog.js +80 -0
- package/dist/tools/explore.js +5 -2
- package/dist/tools/find_references.js +5 -2
- package/dist/tools/find_test_candidates.js +5 -2
- package/dist/tools/get_diagnostics.js +36 -4
- package/dist/tools/get_file.js +5 -2
- package/dist/tools/get_impact.js +5 -2
- package/dist/tools/get_operation_preview.js +5 -2
- package/dist/tools/get_outline.js +5 -2
- package/dist/tools/get_project_status.js +5 -2
- package/dist/tools/get_symbol_source.js +5 -2
- package/dist/tools/list_files.js +5 -2
- package/dist/tools/rename_symbol.js +5 -2
- package/dist/tools/replace_symbol_body.js +5 -2
- package/dist/tools/scaffold_class.js +5 -2
- package/dist/tools/search_symbols.js +5 -2
- package/docs/support.md +6 -6
- package/package.json +2 -2
- package/skills/structural-code-editing/SKILL.md +14 -2
- package/skills/structural-code-editing/releases.json +17 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,22 @@ 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.12.0] — local release candidate, pending release (2026-08-27)
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Diagnostic pagination can now include opt-in bounded aggregates computed from the complete normalized snapshot, with code and file dimensions capped at 20 entries and explicit coverage metadata.
|
|
14
|
+
- Added an immutable tool capability catalog with MCP, batch, and agent projections derived from one source of truth, plus independent inventory, integration, canary, package, and documentation oracles.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Canary validation continues to enforce the established public runtime gate payload while capability metadata is checked independently, preventing an internal catalog change from widening the public canary schema.
|
|
19
|
+
|
|
20
|
+
### Release status
|
|
21
|
+
|
|
22
|
+
- Version `0.12.0` remains pending its exact-tree two-runtime matrix, CI, and separately authorized delivery sequence. It has not been published, assigned to an npm dist-tag, tagged in Git, or released on GitHub.
|
|
23
|
+
|
|
24
|
+
## [0.11.2] — published to `latest` and `next`, registry verified (2026-08-25)
|
|
10
25
|
|
|
11
26
|
### Added
|
|
12
27
|
|
|
@@ -22,7 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
22
37
|
|
|
23
38
|
### Release status
|
|
24
39
|
|
|
25
|
-
-
|
|
40
|
+
- npm published these immutable bytes under `next` with provenance and the expected Git commit. Public-registry consumer and release-preflight verification passed, `latest` and `next` both resolve to `0.11.2`, and the annotated `v0.11.2` tag plus GitHub Release resolve to the same release commit. This release supersedes immutable versions `0.11.0` and `0.11.1`, whose separate public-registry verification defects prevented promotion.
|
|
26
41
|
|
|
27
42
|
## [0.11.1] — published to `next`, verification failed, not promoted (2026-08-23)
|
|
28
43
|
|
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ The included batch benchmark records a 50% reduction in model round-trips and a
|
|
|
84
84
|
|
|
85
85
|
## Supported environment and trust boundary
|
|
86
86
|
|
|
87
|
-
The local `0.
|
|
87
|
+
The local `0.12.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.11.2 retains its immutable historical Node.js 22.13.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.
|
|
88
88
|
|
|
89
89
|
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.
|
|
90
90
|
|
|
@@ -100,7 +100,7 @@ The parent waits for child readiness before replaying bounded initialization sta
|
|
|
100
100
|
|
|
101
101
|
The scoped Linux canary passed on exact Node.js 22.13.0 and Node.js 24 with repeatable PSS reclamation, stable compiler fingerprints, unchanged SQLite reuse, bounded redacted diagnostics, and no orphan after parent death. This is one child per connection, not a shared daemon, pool, or new default. See [ADR 0014](docs/adr/0014-supervised-compiler-worker.md).
|
|
102
102
|
|
|
103
|
-
In published v0.
|
|
103
|
+
In published v0.11.2 and the local `0.12.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.
|
|
104
104
|
|
|
105
105
|
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:
|
|
106
106
|
|
|
@@ -345,6 +345,12 @@ Project-scoped tools accept `project_root`, either the project directory or an e
|
|
|
345
345
|
|
|
346
346
|
Read results use project-relative paths, deterministic ordering, structured MCP output, and pagination where result sets can grow with the project.
|
|
347
347
|
|
|
348
|
+
### Diagnostic aggregates
|
|
349
|
+
|
|
350
|
+
Set `include_aggregates: true` on `ast_get_diagnostics` to summarize the complete normalized diagnostic snapshot independently of the selected raw page. The option defaults to `false`; disabled responses omit `aggregates` and keep the existing shape.
|
|
351
|
+
|
|
352
|
+
Each code and file dimension returns at most 20 ranked groups. `groups.length + omitted_group_count = total_group_count`, and `sum(groups[*].count) = covered_diagnostic_count`. Code coverage plus `omitted_diagnostic_count` equals the diagnostic total; file coverage also adds `unfiled_diagnostic_count`. File groups contain normalized project-relative paths only, but may disclose a path that is absent from the selected raw page.
|
|
353
|
+
|
|
348
354
|
`ast_explore` supports query, exact file, and exact symbol routes. Its default `summary` profile returns bounded reusable selectors; `context` adds selected source and `full` adds compiler references. Whole symbol clusters are admitted under the caller's `max_bytes` ceiling, so source, reference records, and call paths are never sliced. `omissions` classifies withheld components as `budget`, `incomplete`, or `untrusted`, and any requested omission keeps completeness false.
|
|
349
355
|
|
|
350
356
|
Exact `file_path` plus `symbol_path` requests may opt into bounded static `call_spines`. Only fresh, exact, compiler-resolved invocation sites qualify; generic references, dynamic dispatch, and runtime behavior are not inferred. Absence of `call_spines` performs no call traversal. Every response still reports freshness, completeness, truncation, unresolved selectors, record limits, and canonical serialized-byte accounting. Use the primitive tools when a single exact operation is clearer or when preparing a mutation. See [ADR 0013](docs/adr/0013-ast-explore-presentation.md).
|
|
@@ -486,7 +492,19 @@ The server does **not** claim a filesystem-wide transaction:
|
|
|
486
492
|
|
|
487
493
|
## Development gates
|
|
488
494
|
|
|
495
|
+
### Add or change an MCP tool
|
|
496
|
+
|
|
497
|
+
Keep schemas, metadata, annotations, handlers, errors, and serialization in the tool module. Export
|
|
498
|
+
one frozen descriptor, add it to the intentional order in `src/tools/catalog.ts`, and declare only
|
|
499
|
+
static effect, batch, compatibility, and direct-format facts. Do not add request state, dynamic
|
|
500
|
+
discovery, invocation-by-name, or a generic executor to the catalog.
|
|
501
|
+
|
|
502
|
+
Update the independent `tools/list` inventories only after reviewing the complete wire metadata;
|
|
503
|
+
they must not import or derive expectations from the catalog. Then run the focused catalog and MCP
|
|
504
|
+
integration tests plus the runtime, package, and managed-skill gates below.
|
|
505
|
+
|
|
489
506
|
```bash
|
|
507
|
+
yarn vitest run test/tool-catalog.test.ts test/mcp.integration.test.ts
|
|
490
508
|
yarn format:check
|
|
491
509
|
yarn lint
|
|
492
510
|
yarn typecheck
|
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 local `0.
|
|
14
|
+
This project supports trusted single-user local stdio use; the supported operating-system and architecture boundary remains Linux x64 only. The local `0.12.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.11.2 retains its immutable Node.js 22.13.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/batch/schema.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { toolCatalog } from "../tools/catalog.js";
|
|
2
3
|
export const BATCH_SCHEMA_VERSION = 1;
|
|
3
4
|
export const MAX_BATCH_STEPS = 50;
|
|
4
5
|
export const MAX_BATCH_INVOCATIONS = 500;
|
|
@@ -8,22 +9,12 @@ export const MAX_BATCH_CONCURRENCY = 16;
|
|
|
8
9
|
export const MAX_BATCH_INPUT_BYTES = 1024 * 1024;
|
|
9
10
|
export const MAX_BATCH_OUTPUT_BYTES = 10 * 1024 * 1024;
|
|
10
11
|
export const MAX_BATCH_CONTEXT_BYTES = 50 * 1024 * 1024;
|
|
11
|
-
export const READ_BATCH_TOOLS =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"ast_find_test_candidates",
|
|
18
|
-
"ast_explore",
|
|
19
|
-
"ast_get_diagnostics",
|
|
20
|
-
];
|
|
21
|
-
export const PREPARE_BATCH_TOOLS = [
|
|
22
|
-
"ast_rename_symbol",
|
|
23
|
-
"ast_replace_symbol_body",
|
|
24
|
-
"ast_scaffold_class",
|
|
25
|
-
];
|
|
26
|
-
export const BATCH_TOOLS = [...READ_BATCH_TOOLS, ...PREPARE_BATCH_TOOLS];
|
|
12
|
+
export const READ_BATCH_TOOLS = toolCatalog.batch.read;
|
|
13
|
+
export const PREPARE_BATCH_TOOLS = toolCatalog.batch.prepare;
|
|
14
|
+
export const BATCH_TOOLS = Object.freeze([
|
|
15
|
+
...READ_BATCH_TOOLS,
|
|
16
|
+
...PREPARE_BATCH_TOOLS,
|
|
17
|
+
]);
|
|
27
18
|
const BatchToolSchema = z.enum(BATCH_TOOLS);
|
|
28
19
|
const BatchStepSchema = z
|
|
29
20
|
.object({
|
package/dist/server.js
CHANGED
|
@@ -1,22 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { McpServer, } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { PublicOperationalError } from "./services/public-errors.js";
|
|
4
|
-
import {
|
|
5
|
-
import { registerFindReferences } from "./tools/find_references.js";
|
|
6
|
-
import { registerFindTestCandidates } from "./tools/find_test_candidates.js";
|
|
7
|
-
import { registerGetDiagnostics } from "./tools/get_diagnostics.js";
|
|
8
|
-
import { registerGetFile } from "./tools/get_file.js";
|
|
9
|
-
import { registerGetImpact } from "./tools/get_impact.js";
|
|
10
|
-
import { registerGetOperationPreview } from "./tools/get_operation_preview.js";
|
|
11
|
-
import { registerGetOutline } from "./tools/get_outline.js";
|
|
12
|
-
import { registerGetProjectStatus } from "./tools/get_project_status.js";
|
|
13
|
-
import { registerGetSymbolSource } from "./tools/get_symbol_source.js";
|
|
14
|
-
import { registerListFiles } from "./tools/list_files.js";
|
|
15
|
-
import { registerRenameSymbol } from "./tools/rename_symbol.js";
|
|
16
|
-
import { registerReplaceSymbolBody } from "./tools/replace_symbol_body.js";
|
|
17
|
-
import { registerScaffoldClass } from "./tools/scaffold_class.js";
|
|
18
|
-
import { registerSearchSymbols } from "./tools/search_symbols.js";
|
|
19
|
-
import { registerExplore } from "./tools/explore.js";
|
|
4
|
+
import { toolCatalog } from "./tools/catalog.js";
|
|
20
5
|
import { createToolErrorContext, errorResult } from "./tools/result.js";
|
|
21
6
|
const packageMetadata = createRequire(import.meta.url)("../package.json");
|
|
22
7
|
export const PACKAGE_VERSION = packageMetadata.version;
|
|
@@ -40,21 +25,6 @@ export function createServer(options = {}) {
|
|
|
40
25
|
});
|
|
41
26
|
if (options.runtimeActivity)
|
|
42
27
|
installRuntimeActivityTracking(server, options.runtimeActivity);
|
|
43
|
-
|
|
44
|
-
registerGetProjectStatus(server);
|
|
45
|
-
registerExplore(server);
|
|
46
|
-
registerGetOutline(server);
|
|
47
|
-
registerGetSymbolSource(server);
|
|
48
|
-
registerSearchSymbols(server);
|
|
49
|
-
registerFindReferences(server);
|
|
50
|
-
registerGetImpact(server);
|
|
51
|
-
registerFindTestCandidates(server);
|
|
52
|
-
registerGetDiagnostics(server);
|
|
53
|
-
registerGetFile(server);
|
|
54
|
-
registerRenameSymbol(server);
|
|
55
|
-
registerReplaceSymbolBody(server);
|
|
56
|
-
registerScaffoldClass(server);
|
|
57
|
-
registerGetOperationPreview(server);
|
|
58
|
-
registerApplyOperation(server);
|
|
28
|
+
toolCatalog.registerAll(server);
|
|
59
29
|
return server;
|
|
60
30
|
}
|
|
@@ -1,18 +1,6 @@
|
|
|
1
|
+
import { toolCatalog } from "../tools/catalog.js";
|
|
1
2
|
export const MCP_SERVER_NAME = "ast";
|
|
2
|
-
const EXPECTED_TOOLS =
|
|
3
|
-
"ast_list_files",
|
|
4
|
-
"ast_get_outline",
|
|
5
|
-
"ast_get_symbol_source",
|
|
6
|
-
"ast_search_symbols",
|
|
7
|
-
"ast_find_references",
|
|
8
|
-
"ast_find_test_candidates",
|
|
9
|
-
"ast_get_diagnostics",
|
|
10
|
-
"ast_rename_symbol",
|
|
11
|
-
"ast_replace_symbol_body",
|
|
12
|
-
"ast_scaffold_class",
|
|
13
|
-
"ast_get_operation_preview",
|
|
14
|
-
"ast_apply_operation",
|
|
15
|
-
];
|
|
3
|
+
const EXPECTED_TOOLS = toolCatalog.compatibility.required;
|
|
16
4
|
function semver(value) {
|
|
17
5
|
const match = value.match(/(?:^|\s|v)(\d+)\.(\d+)\.(\d+)(?=\s|$|[-+()]|\.(?:\s|$))/);
|
|
18
6
|
return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : undefined;
|
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { DiagnosticCategory, ts } from "ts-morph";
|
|
3
3
|
import { NO_REQUEST_CONTEXT } from "./request-context.js";
|
|
4
|
+
export const DIAGNOSTIC_AGGREGATE_GROUP_LIMIT = 20;
|
|
5
|
+
function safeCount(value) {
|
|
6
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
7
|
+
throw new RangeError("Diagnostic aggregate count is outside the safe integer range.");
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
function increment(counts, key) {
|
|
12
|
+
counts.set(key, safeCount((counts.get(key) ?? 0) + 1));
|
|
13
|
+
}
|
|
14
|
+
function rankGroups(counts, createGroup, compareKey, groupedDiagnosticCount, requestContext) {
|
|
15
|
+
const groups = [];
|
|
16
|
+
for (const [key, count] of counts) {
|
|
17
|
+
requestContext.checkpoint();
|
|
18
|
+
groups.push(createGroup(key, safeCount(count)));
|
|
19
|
+
}
|
|
20
|
+
groups.sort((left, right) => {
|
|
21
|
+
requestContext.checkpoint();
|
|
22
|
+
return right.count - left.count || compareKey(left, right);
|
|
23
|
+
});
|
|
24
|
+
const selected = groups.slice(0, DIAGNOSTIC_AGGREGATE_GROUP_LIMIT);
|
|
25
|
+
const covered = safeCount(selected.reduce((total, group) => safeCount(total + group.count), 0));
|
|
26
|
+
const omittedGroups = safeCount(groups.length - selected.length);
|
|
27
|
+
return {
|
|
28
|
+
groups: selected,
|
|
29
|
+
total_group_count: safeCount(groups.length),
|
|
30
|
+
omitted_group_count: omittedGroups,
|
|
31
|
+
covered_diagnostic_count: covered,
|
|
32
|
+
omitted_diagnostic_count: safeCount(groupedDiagnosticCount - covered),
|
|
33
|
+
truncated: omittedGroups > 0,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function buildDiagnosticAggregates(diagnostics, requestContext = NO_REQUEST_CONTEXT) {
|
|
37
|
+
requestContext.checkpoint();
|
|
38
|
+
const codeCounts = new Map();
|
|
39
|
+
const fileCounts = new Map();
|
|
40
|
+
let unfiled = 0;
|
|
41
|
+
for (const diagnostic of diagnostics) {
|
|
42
|
+
requestContext.checkpoint();
|
|
43
|
+
increment(codeCounts, diagnostic.code);
|
|
44
|
+
if (diagnostic.file === null) {
|
|
45
|
+
unfiled = safeCount(unfiled + 1);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
increment(fileCounts, diagnostic.file);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const codes = rankGroups(codeCounts, (code, count) => ({ code, count }), (left, right) => left.code - right.code, safeCount(diagnostics.length), requestContext);
|
|
52
|
+
const files = rankGroups(fileCounts, (file, count) => ({ file, count }), (left, right) => (left.file < right.file ? -1 : left.file > right.file ? 1 : 0), safeCount(diagnostics.length - unfiled), requestContext);
|
|
53
|
+
return {
|
|
54
|
+
group_limit: DIAGNOSTIC_AGGREGATE_GROUP_LIMIT,
|
|
55
|
+
codes,
|
|
56
|
+
files: { ...files, unfiled_diagnostic_count: unfiled },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
4
59
|
export function normalizeDiagnostic(diagnostic, projectRoot, requestContext = NO_REQUEST_CONTEXT) {
|
|
5
60
|
requestContext.checkpoint();
|
|
6
61
|
const sourceFile = diagnostic.getSourceFile();
|
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { applyOperation } from "../services/operations.js";
|
|
3
3
|
import { createRequestContext } from "../services/request-context.js";
|
|
4
4
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
5
|
+
const TOOL_NAME = "ast_apply_operation";
|
|
5
6
|
const AstApplyOperationInputSchema = z.object({
|
|
6
7
|
operation_id: z.string().uuid().describe("Identifier returned by a prepare operation."),
|
|
7
8
|
plan_hash: z.string().length(64).describe("Plan hash returned by the same prepare operation."),
|
|
@@ -15,7 +16,7 @@ const AstApplyOperationOutputSchema = z.object({
|
|
|
15
16
|
idempotent_replay: z.boolean(),
|
|
16
17
|
});
|
|
17
18
|
export function registerApplyOperation(server) {
|
|
18
|
-
server.registerTool(
|
|
19
|
+
server.registerTool(TOOL_NAME, {
|
|
19
20
|
title: "Apply a prepared structural operation",
|
|
20
21
|
description: "Applies exactly the reviewed plan after verifying its plan hash and the complete TypeScript workspace fingerprint. Conflicts abort before writes; retries after success are idempotent.",
|
|
21
22
|
inputSchema: AstApplyOperationInputSchema,
|
|
@@ -34,7 +35,9 @@ export function registerApplyOperation(server) {
|
|
|
34
35
|
});
|
|
35
36
|
}
|
|
36
37
|
catch (error) {
|
|
37
|
-
return errorResult(error, createToolErrorContext(
|
|
38
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME));
|
|
38
39
|
}
|
|
39
40
|
});
|
|
40
41
|
}
|
|
42
|
+
// prettier-ignore
|
|
43
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerApplyOperation, compatibility: "required", effect: "apply", batch: "none", directOutputFormats: Object.freeze(["json"]) });
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { toolDescriptor as applyOperation } from "./apply_operation.js";
|
|
2
|
+
import { toolDescriptor as explore } from "./explore.js";
|
|
3
|
+
import { toolDescriptor as findReferences } from "./find_references.js";
|
|
4
|
+
import { toolDescriptor as findTestCandidates } from "./find_test_candidates.js";
|
|
5
|
+
import { toolDescriptor as getDiagnostics } from "./get_diagnostics.js";
|
|
6
|
+
import { toolDescriptor as getFile } from "./get_file.js";
|
|
7
|
+
import { toolDescriptor as getImpact } from "./get_impact.js";
|
|
8
|
+
import { toolDescriptor as getOperationPreview } from "./get_operation_preview.js";
|
|
9
|
+
import { toolDescriptor as getOutline } from "./get_outline.js";
|
|
10
|
+
import { toolDescriptor as getProjectStatus } from "./get_project_status.js";
|
|
11
|
+
import { toolDescriptor as getSymbolSource } from "./get_symbol_source.js";
|
|
12
|
+
import { toolDescriptor as listFiles } from "./list_files.js";
|
|
13
|
+
import { toolDescriptor as renameSymbol } from "./rename_symbol.js";
|
|
14
|
+
import { toolDescriptor as replaceSymbolBody } from "./replace_symbol_body.js";
|
|
15
|
+
import { toolDescriptor as scaffoldClass } from "./scaffold_class.js";
|
|
16
|
+
import { toolDescriptor as searchSymbols } from "./search_symbols.js";
|
|
17
|
+
function validateDescriptor(descriptor) {
|
|
18
|
+
const formats = descriptor.directOutputFormats.join(",");
|
|
19
|
+
const valid = (descriptor.effect === "read" &&
|
|
20
|
+
(descriptor.batch === "none" || descriptor.batch === "read") &&
|
|
21
|
+
(formats === "json" || formats === "json,toon")) ||
|
|
22
|
+
(descriptor.effect === "prepare" && descriptor.batch === "prepare" && formats === "json") ||
|
|
23
|
+
(descriptor.effect === "apply" && descriptor.batch === "none" && formats === "json");
|
|
24
|
+
if (!valid)
|
|
25
|
+
throw new Error(`Contradictory capability descriptor: ${descriptor.name}`);
|
|
26
|
+
}
|
|
27
|
+
export function defineToolCatalog(input) {
|
|
28
|
+
const seen = new Set();
|
|
29
|
+
for (const descriptor of input) {
|
|
30
|
+
if (seen.has(descriptor.name))
|
|
31
|
+
throw new Error(`Duplicate tool name: ${descriptor.name}`);
|
|
32
|
+
seen.add(descriptor.name);
|
|
33
|
+
validateDescriptor(descriptor);
|
|
34
|
+
}
|
|
35
|
+
const descriptors = Object.freeze(input.map((descriptor) => Object.freeze({
|
|
36
|
+
...descriptor,
|
|
37
|
+
directOutputFormats: Object.freeze([...descriptor.directOutputFormats]),
|
|
38
|
+
})));
|
|
39
|
+
const names = (predicate) => Object.freeze(descriptors.filter(predicate).map(({ name }) => name));
|
|
40
|
+
return Object.freeze({
|
|
41
|
+
descriptors,
|
|
42
|
+
batch: Object.freeze({
|
|
43
|
+
read: names((item) => item.batch === "read"),
|
|
44
|
+
prepare: names((item) => item.batch === "prepare"),
|
|
45
|
+
excluded: names((item) => item.batch === "none"),
|
|
46
|
+
}),
|
|
47
|
+
compatibility: Object.freeze({
|
|
48
|
+
required: names((item) => item.compatibility === "required"),
|
|
49
|
+
optional: names((item) => item.compatibility === "optional"),
|
|
50
|
+
}),
|
|
51
|
+
byEffect: Object.freeze({
|
|
52
|
+
read: names((item) => item.effect === "read"),
|
|
53
|
+
prepare: names((item) => item.effect === "prepare"),
|
|
54
|
+
apply: names((item) => item.effect === "apply"),
|
|
55
|
+
}),
|
|
56
|
+
directToon: names((item) => item.directOutputFormats.length === 2),
|
|
57
|
+
registerAll(server) {
|
|
58
|
+
for (const descriptor of descriptors)
|
|
59
|
+
descriptor.register(server);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export const toolCatalog = defineToolCatalog([
|
|
64
|
+
listFiles,
|
|
65
|
+
getProjectStatus,
|
|
66
|
+
explore,
|
|
67
|
+
getOutline,
|
|
68
|
+
getSymbolSource,
|
|
69
|
+
searchSymbols,
|
|
70
|
+
findReferences,
|
|
71
|
+
getImpact,
|
|
72
|
+
findTestCandidates,
|
|
73
|
+
getDiagnostics,
|
|
74
|
+
getFile,
|
|
75
|
+
renameSymbol,
|
|
76
|
+
replaceSymbolBody,
|
|
77
|
+
scaffoldClass,
|
|
78
|
+
getOperationPreview,
|
|
79
|
+
applyOperation,
|
|
80
|
+
]);
|
package/dist/tools/explore.js
CHANGED
|
@@ -8,6 +8,7 @@ import { createRequestContext } from "../services/request-context.js";
|
|
|
8
8
|
import { FRESHNESS_CAUSES, SNAPSHOT_STATES, TRUNCATION_REASONS, } from "../services/read-contracts.js";
|
|
9
9
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
10
10
|
import { RelationshipEndpointSchema } from "./relationship-schema.js";
|
|
11
|
+
const TOOL_NAME = "ast_explore";
|
|
11
12
|
const ExploreDetailSchema = z.enum(["selectors", "summary", "context", "full"]).default("summary");
|
|
12
13
|
const ReferenceDetailSchema = z.enum(["locations", "context"]).default("locations");
|
|
13
14
|
const CallSpinesInputSchema = z.object({
|
|
@@ -200,7 +201,7 @@ const ExploreOutputSchema = z.object({
|
|
|
200
201
|
}),
|
|
201
202
|
});
|
|
202
203
|
export function registerExplore(server) {
|
|
203
|
-
server.registerTool(
|
|
204
|
+
server.registerTool(TOOL_NAME, {
|
|
204
205
|
title: "Explore project context",
|
|
205
206
|
description: "Composes bounded structural search, exact selectors, source evidence and compiler references without weakening the primitive AST tools. Returns bounded session freshness metadata for fresh, pending, stale, rebuilding or degraded state.",
|
|
206
207
|
inputSchema: ExploreInputSchema,
|
|
@@ -241,7 +242,9 @@ export function registerExplore(server) {
|
|
|
241
242
|
return structuredResult(ExploreOutputSchema.parse(output));
|
|
242
243
|
}
|
|
243
244
|
catch (error) {
|
|
244
|
-
return errorResult(error, createToolErrorContext(
|
|
245
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
245
246
|
}
|
|
246
247
|
});
|
|
247
248
|
}
|
|
249
|
+
// prettier-ignore
|
|
250
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerExplore, compatibility: "optional", effect: "read", batch: "read", directOutputFormats: Object.freeze(["json"]) });
|
|
@@ -4,6 +4,7 @@ import { findDeclarationByName, getSourceFileOrThrow, withProject } from "../ser
|
|
|
4
4
|
import { collectSymbolReferences } from "../services/references.js";
|
|
5
5
|
import { createRequestContext } from "../services/request-context.js";
|
|
6
6
|
import { createToolErrorContext, errorResult, formattedResult, ToolOutputFormatInputSchema, } from "./result.js";
|
|
7
|
+
const TOOL_NAME = "ast_find_references";
|
|
7
8
|
const ReferenceDetailSchema = z.enum(["locations", "context"]).default("locations");
|
|
8
9
|
const AstFindReferencesInputSchema = z.object({
|
|
9
10
|
project_root: z
|
|
@@ -44,7 +45,7 @@ const ReferenceOutputSchemas = {
|
|
|
44
45
|
}),
|
|
45
46
|
};
|
|
46
47
|
export function registerFindReferences(server) {
|
|
47
|
-
server.registerTool(
|
|
48
|
+
server.registerTool(TOOL_NAME, {
|
|
48
49
|
title: "Find semantic symbol references",
|
|
49
50
|
description: "Finds type-resolved references and returns bounded project-relative locations, including declaration impact by default.",
|
|
50
51
|
inputSchema: AstFindReferencesInputSchema,
|
|
@@ -76,7 +77,9 @@ export function registerFindReferences(server) {
|
|
|
76
77
|
return formattedResult(outputSchema, structuredContent, output_format);
|
|
77
78
|
}
|
|
78
79
|
catch (error) {
|
|
79
|
-
return errorResult(error, createToolErrorContext(
|
|
80
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
80
81
|
}
|
|
81
82
|
});
|
|
82
83
|
}
|
|
84
|
+
// prettier-ignore
|
|
85
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerFindReferences, compatibility: "required", effect: "read", batch: "read", directOutputFormats: Object.freeze(["json", "toon"]) });
|
|
@@ -7,6 +7,7 @@ import { createRequestContext } from "../services/request-context.js";
|
|
|
7
7
|
import { findTestCandidates, MAX_TEST_CANDIDATE_CONVENTION_ITEMS, MAX_TEST_CANDIDATE_CONVENTION_LENGTH, TEST_CANDIDATE_CONFIDENCES, TEST_CANDIDATE_REASONS, } from "../services/test-candidates.js";
|
|
8
8
|
import { FreshnessSchema, RelationshipEdgeSchema, RelationshipEndpointSchema, } from "./relationship-schema.js";
|
|
9
9
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
10
|
+
const TOOL_NAME = "ast_find_test_candidates";
|
|
10
11
|
const ConventionSchema = z
|
|
11
12
|
.array(z.string().min(1).max(MAX_TEST_CANDIDATE_CONVENTION_LENGTH))
|
|
12
13
|
.max(MAX_TEST_CANDIDATE_CONVENTION_ITEMS)
|
|
@@ -59,7 +60,7 @@ const FindTestCandidatesOutputSchema = z.object({
|
|
|
59
60
|
}),
|
|
60
61
|
});
|
|
61
62
|
export function registerFindTestCandidates(server) {
|
|
62
|
-
server.registerTool(
|
|
63
|
+
server.registerTool(TOOL_NAME, {
|
|
63
64
|
title: "Find compiler-backed affected test candidates",
|
|
64
65
|
description: "Finds deterministic affected test candidates from fresh, complete incoming compiler relationships. Returns bounded whole-candidate proofs and never executes tests or prepares mutations.",
|
|
65
66
|
inputSchema: AstFindTestCandidatesInputSchema,
|
|
@@ -118,7 +119,9 @@ export function registerFindTestCandidates(server) {
|
|
|
118
119
|
return structuredResult(FindTestCandidatesOutputSchema.parse(result));
|
|
119
120
|
}
|
|
120
121
|
catch (error) {
|
|
121
|
-
return errorResult(error, createToolErrorContext(
|
|
122
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
122
123
|
}
|
|
123
124
|
});
|
|
124
125
|
}
|
|
126
|
+
// prettier-ignore
|
|
127
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerFindTestCandidates, compatibility: "required", effect: "read", batch: "read", directOutputFormats: Object.freeze(["json"]) });
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { normalizeDiagnostic } from "../services/diagnostics.js";
|
|
2
|
+
import { buildDiagnosticAggregates, DIAGNOSTIC_AGGREGATE_GROUP_LIMIT, normalizeDiagnostic, } from "../services/diagnostics.js";
|
|
3
3
|
import { PaginationInputSchema, PaginationOutputSchema, paginate } from "../services/pagination.js";
|
|
4
4
|
import { getSourceFileOrThrow, withProject } from "../services/project.js";
|
|
5
5
|
import { createRequestContext } from "../services/request-context.js";
|
|
6
6
|
import { createToolErrorContext, errorResult, formattedResult, ToolOutputFormatInputSchema, } from "./result.js";
|
|
7
|
+
const TOOL_NAME = "ast_get_diagnostics";
|
|
7
8
|
const DiagnosticSchema = z.object({
|
|
8
9
|
code: z.number().int(),
|
|
9
10
|
category: z.string(),
|
|
@@ -12,6 +13,29 @@ const DiagnosticSchema = z.object({
|
|
|
12
13
|
column: z.number().int().positive().nullable(),
|
|
13
14
|
message: z.string(),
|
|
14
15
|
});
|
|
16
|
+
const AggregateMetadataSchema = {
|
|
17
|
+
total_group_count: z.number().int().safe().min(0),
|
|
18
|
+
omitted_group_count: z.number().int().safe().min(0),
|
|
19
|
+
covered_diagnostic_count: z.number().int().safe().min(0),
|
|
20
|
+
omitted_diagnostic_count: z.number().int().safe().min(0),
|
|
21
|
+
truncated: z.boolean(),
|
|
22
|
+
};
|
|
23
|
+
const DiagnosticAggregatesSchema = z.object({
|
|
24
|
+
group_limit: z.literal(DIAGNOSTIC_AGGREGATE_GROUP_LIMIT),
|
|
25
|
+
codes: z.object({
|
|
26
|
+
groups: z
|
|
27
|
+
.array(z.object({ code: z.number().int().safe(), count: z.number().int().safe().positive() }))
|
|
28
|
+
.max(DIAGNOSTIC_AGGREGATE_GROUP_LIMIT),
|
|
29
|
+
...AggregateMetadataSchema,
|
|
30
|
+
}),
|
|
31
|
+
files: z.object({
|
|
32
|
+
groups: z
|
|
33
|
+
.array(z.object({ file: z.string(), count: z.number().int().safe().positive() }))
|
|
34
|
+
.max(DIAGNOSTIC_AGGREGATE_GROUP_LIMIT),
|
|
35
|
+
...AggregateMetadataSchema,
|
|
36
|
+
unfiled_diagnostic_count: z.number().int().safe().min(0),
|
|
37
|
+
}),
|
|
38
|
+
});
|
|
15
39
|
const AstGetDiagnosticsInputSchema = z.object({
|
|
16
40
|
project_root: z
|
|
17
41
|
.string()
|
|
@@ -20,6 +44,7 @@ const AstGetDiagnosticsInputSchema = z.object({
|
|
|
20
44
|
.string()
|
|
21
45
|
.optional()
|
|
22
46
|
.describe("Optional project-relative or absolute file path. Omit for project diagnostics."),
|
|
47
|
+
include_aggregates: z.boolean().optional().default(false),
|
|
23
48
|
...ToolOutputFormatInputSchema,
|
|
24
49
|
...PaginationInputSchema,
|
|
25
50
|
});
|
|
@@ -28,10 +53,11 @@ const AstGetDiagnosticsOutputSchema = z.object({
|
|
|
28
53
|
error_count: z.number().int().min(0),
|
|
29
54
|
warning_count: z.number().int().min(0),
|
|
30
55
|
duration_ms: z.number().min(0),
|
|
56
|
+
aggregates: DiagnosticAggregatesSchema.optional(),
|
|
31
57
|
...PaginationOutputSchema,
|
|
32
58
|
});
|
|
33
59
|
export function registerGetDiagnostics(server) {
|
|
34
|
-
server.registerTool(
|
|
60
|
+
server.registerTool(TOOL_NAME, {
|
|
35
61
|
title: "Get TypeScript diagnostics",
|
|
36
62
|
description: "Returns bounded normalized TypeScript diagnostics for a project or one source file. Existing errors are preserved as evidence for write-operation delta checks.",
|
|
37
63
|
inputSchema: AstGetDiagnosticsInputSchema,
|
|
@@ -41,7 +67,7 @@ export function registerGetDiagnostics(server) {
|
|
|
41
67
|
idempotentHint: true,
|
|
42
68
|
openWorldHint: false,
|
|
43
69
|
},
|
|
44
|
-
}, async ({ project_root, file_path, output_format, offset, limit }, extra) => {
|
|
70
|
+
}, async ({ project_root, file_path, include_aggregates, output_format, offset, limit }, extra) => {
|
|
45
71
|
const requestContext = createRequestContext(extra.signal);
|
|
46
72
|
try {
|
|
47
73
|
const structuredContent = await withProject(project_root, ({ project, projectRoot }, operationContext) => {
|
|
@@ -52,6 +78,9 @@ export function registerGetDiagnostics(server) {
|
|
|
52
78
|
const normalized = diagnostics
|
|
53
79
|
.map((diagnostic) => normalizeDiagnostic(diagnostic, projectRoot, operationContext))
|
|
54
80
|
.sort((left, right) => `${left.file ?? ""}:${left.line ?? 0}:${left.column ?? 0}:${left.code}`.localeCompare(`${right.file ?? ""}:${right.line ?? 0}:${right.column ?? 0}:${right.code}`));
|
|
81
|
+
const aggregates = include_aggregates
|
|
82
|
+
? buildDiagnosticAggregates(normalized, operationContext)
|
|
83
|
+
: undefined;
|
|
55
84
|
const page = paginate(normalized, offset, limit);
|
|
56
85
|
const { items, ...metadata } = page;
|
|
57
86
|
return {
|
|
@@ -61,13 +90,16 @@ export function registerGetDiagnostics(server) {
|
|
|
61
90
|
warning_count: normalized.filter((diagnostic) => diagnostic.category === "Warning")
|
|
62
91
|
.length,
|
|
63
92
|
duration_ms: performance.now() - startedAt,
|
|
93
|
+
...(aggregates ? { aggregates } : {}),
|
|
64
94
|
...metadata,
|
|
65
95
|
};
|
|
66
96
|
}, requestContext);
|
|
67
97
|
return formattedResult(AstGetDiagnosticsOutputSchema, structuredContent, output_format);
|
|
68
98
|
}
|
|
69
99
|
catch (error) {
|
|
70
|
-
return errorResult(error, createToolErrorContext(
|
|
100
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
71
101
|
}
|
|
72
102
|
});
|
|
73
103
|
}
|
|
104
|
+
// prettier-ignore
|
|
105
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerGetDiagnostics, compatibility: "required", effect: "read", batch: "read", directOutputFormats: Object.freeze(["json", "toon"]) });
|
package/dist/tools/get_file.js
CHANGED
|
@@ -5,6 +5,7 @@ import { getSourceFileOrThrow, withProject } from "../services/project.js";
|
|
|
5
5
|
import { createRequestContext } from "../services/request-context.js";
|
|
6
6
|
import { FRESHNESS_CAUSES, SNAPSHOT_STATES } from "../services/read-contracts.js";
|
|
7
7
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
8
|
+
const TOOL_NAME = "ast_get_file";
|
|
8
9
|
const AstGetFileInputSchema = z.object({
|
|
9
10
|
project_root: z
|
|
10
11
|
.string()
|
|
@@ -60,7 +61,7 @@ const AstGetFileOutputSchema = z.object({
|
|
|
60
61
|
symbols: z.array(OutlineSymbolSchema).optional(),
|
|
61
62
|
});
|
|
62
63
|
export function registerGetFile(server) {
|
|
63
|
-
server.registerTool(
|
|
64
|
+
server.registerTool(TOOL_NAME, {
|
|
64
65
|
title: "Get bounded source file",
|
|
65
66
|
description: "Returns exact bounded source lines for one TypeScript/JavaScript file, or body-free symbols when symbols_only is true. Read-only; file snapshot freshness and project freshness are reported separately from compiler diagnostics.",
|
|
66
67
|
inputSchema: AstGetFileInputSchema,
|
|
@@ -101,7 +102,9 @@ export function registerGetFile(server) {
|
|
|
101
102
|
return structuredResult(structuredContent);
|
|
102
103
|
}
|
|
103
104
|
catch (error) {
|
|
104
|
-
return errorResult(error, createToolErrorContext(
|
|
105
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
105
106
|
}
|
|
106
107
|
});
|
|
107
108
|
}
|
|
109
|
+
// prettier-ignore
|
|
110
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerGetFile, compatibility: "optional", effect: "read", batch: "none", directOutputFormats: Object.freeze(["json"]) });
|
package/dist/tools/get_impact.js
CHANGED
|
@@ -6,6 +6,7 @@ import { createRequestContext } from "../services/request-context.js";
|
|
|
6
6
|
import { RELATIONSHIP_EDGE_KINDS } from "../services/relationships.js";
|
|
7
7
|
import { FreshnessSchema, RelationshipEdgeSchema, RelationshipEndpointSchema, } from "./relationship-schema.js";
|
|
8
8
|
import { createToolErrorContext, errorResult, formattedResult, ToolOutputFormatInputSchema, } from "./result.js";
|
|
9
|
+
const TOOL_NAME = "ast_get_impact";
|
|
9
10
|
const AstGetImpactInputSchema = z.object({
|
|
10
11
|
project_root: z
|
|
11
12
|
.string()
|
|
@@ -68,7 +69,7 @@ const ImpactOutputSchema = z.object({
|
|
|
68
69
|
freshness: FreshnessSchema,
|
|
69
70
|
});
|
|
70
71
|
export function registerGetImpact(server) {
|
|
71
|
-
server.registerTool(
|
|
72
|
+
server.registerTool(TOOL_NAME, {
|
|
72
73
|
title: "Get bounded compiler-backed impact",
|
|
73
74
|
description: "Traverses exact compiler-backed relationships around a symbol with explicit direction, depth, node and edge budgets. Returns bounded session freshness metadata and fails closed when exact relationships are not fresh. Read-only evidence only; it never prepares or applies mutations.",
|
|
74
75
|
inputSchema: AstGetImpactInputSchema,
|
|
@@ -101,7 +102,9 @@ export function registerGetImpact(server) {
|
|
|
101
102
|
return formattedResult(ImpactOutputSchema, structuredContent, output_format);
|
|
102
103
|
}
|
|
103
104
|
catch (error) {
|
|
104
|
-
return errorResult(error, createToolErrorContext(
|
|
105
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
105
106
|
}
|
|
106
107
|
});
|
|
107
108
|
}
|
|
109
|
+
// prettier-ignore
|
|
110
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerGetImpact, compatibility: "optional", effect: "read", batch: "none", directOutputFormats: Object.freeze(["json", "toon"]) });
|
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { getOperationPreview } from "../services/operations.js";
|
|
3
3
|
import { createRequestContext } from "../services/request-context.js";
|
|
4
4
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
5
|
+
const TOOL_NAME = "ast_get_operation_preview";
|
|
5
6
|
const AstGetOperationPreviewInputSchema = z.object({
|
|
6
7
|
operation_id: z.string().uuid(),
|
|
7
8
|
file: z.string().optional().describe("Optional affected file path to retrieve only its diff."),
|
|
@@ -12,7 +13,7 @@ const AstGetOperationPreviewOutputSchema = z.object({
|
|
|
12
13
|
files: z.array(z.object({ file: z.string(), diff: z.string() })),
|
|
13
14
|
});
|
|
14
15
|
export function registerGetOperationPreview(server) {
|
|
15
|
-
server.registerTool(
|
|
16
|
+
server.registerTool(TOOL_NAME, {
|
|
16
17
|
title: "Get complete prepared-operation diff",
|
|
17
18
|
description: "Retrieves exact unified diffs retained for a prepared operation, optionally one affected file at a time.",
|
|
18
19
|
inputSchema: AstGetOperationPreviewInputSchema,
|
|
@@ -30,7 +31,9 @@ export function registerGetOperationPreview(server) {
|
|
|
30
31
|
return structuredResult(output);
|
|
31
32
|
}
|
|
32
33
|
catch (error) {
|
|
33
|
-
return errorResult(error, createToolErrorContext(
|
|
34
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME));
|
|
34
35
|
}
|
|
35
36
|
});
|
|
36
37
|
}
|
|
38
|
+
// prettier-ignore
|
|
39
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerGetOperationPreview, compatibility: "required", effect: "read", batch: "none", directOutputFormats: Object.freeze(["json"]) });
|
|
@@ -4,6 +4,7 @@ import { buildFileOutline } from "../services/outline.js";
|
|
|
4
4
|
import { getSourceFileOrThrow, withProject } from "../services/project.js";
|
|
5
5
|
import { createRequestContext } from "../services/request-context.js";
|
|
6
6
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
7
|
+
const TOOL_NAME = "ast_get_outline";
|
|
7
8
|
const AstGetOutlineInputSchema = z.object({
|
|
8
9
|
project_root: z
|
|
9
10
|
.string()
|
|
@@ -28,7 +29,7 @@ const AstGetOutlineOutputSchema = z.object({
|
|
|
28
29
|
symbols: z.array(OutlineSymbolSchema).optional(),
|
|
29
30
|
});
|
|
30
31
|
export function registerGetOutline(server) {
|
|
31
|
-
server.registerTool(
|
|
32
|
+
server.registerTool(TOOL_NAME, {
|
|
32
33
|
title: "Get compact file outline",
|
|
33
34
|
description: "Returns body-free declaration signatures for one TypeScript/JavaScript file. Detailed symbol metadata is opt-in because it duplicates signature text.",
|
|
34
35
|
inputSchema: AstGetOutlineInputSchema,
|
|
@@ -54,7 +55,9 @@ export function registerGetOutline(server) {
|
|
|
54
55
|
return structuredResult(structuredContent);
|
|
55
56
|
}
|
|
56
57
|
catch (error) {
|
|
57
|
-
return errorResult(error, createToolErrorContext(
|
|
58
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
58
59
|
}
|
|
59
60
|
});
|
|
60
61
|
}
|
|
62
|
+
// prettier-ignore
|
|
63
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerGetOutline, compatibility: "required", effect: "read", batch: "read", directOutputFormats: Object.freeze(["json"]) });
|
|
@@ -3,6 +3,7 @@ import { FRESHNESS_CAUSES, SNAPSHOT_STATES, TRUNCATION_REASONS, } from "../servi
|
|
|
3
3
|
import { getProjectStatus } from "../services/project.js";
|
|
4
4
|
import { createRequestContext } from "../services/request-context.js";
|
|
5
5
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
6
|
+
const TOOL_NAME = "ast_get_project_status";
|
|
6
7
|
const AstGetProjectStatusInputSchema = z.object({
|
|
7
8
|
project_root: z
|
|
8
9
|
.string()
|
|
@@ -113,7 +114,7 @@ const ProjectStatusOutputSchema = z.object({
|
|
|
113
114
|
index_observability: IndexObservabilitySchema,
|
|
114
115
|
});
|
|
115
116
|
export function registerGetProjectStatus(server) {
|
|
116
|
-
server.registerTool(
|
|
117
|
+
server.registerTool(TOOL_NAME, {
|
|
117
118
|
title: "Get project freshness status",
|
|
118
119
|
description: "Returns bounded, read-only compiler freshness and project status without exposing filesystem identities or credentials.",
|
|
119
120
|
inputSchema: AstGetProjectStatusInputSchema,
|
|
@@ -131,7 +132,9 @@ export function registerGetProjectStatus(server) {
|
|
|
131
132
|
return structuredResult({ ...output });
|
|
132
133
|
}
|
|
133
134
|
catch (error) {
|
|
134
|
-
return errorResult(error, createToolErrorContext(
|
|
135
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
135
136
|
}
|
|
136
137
|
});
|
|
137
138
|
}
|
|
139
|
+
// prettier-ignore
|
|
140
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerGetProjectStatus, compatibility: "optional", effect: "read", batch: "none", directOutputFormats: Object.freeze(["json"]) });
|
|
@@ -3,6 +3,7 @@ import { nodeSourceWithLocation } from "../services/outline.js";
|
|
|
3
3
|
import { findDeclarationByName, getSourceFileOrThrow, withProject } from "../services/project.js";
|
|
4
4
|
import { createRequestContext } from "../services/request-context.js";
|
|
5
5
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
6
|
+
const TOOL_NAME = "ast_get_symbol_source";
|
|
6
7
|
const AstGetSymbolSourceInputSchema = z.object({
|
|
7
8
|
project_root: z
|
|
8
9
|
.string()
|
|
@@ -17,7 +18,7 @@ const AstGetSymbolSourceOutputSchema = z.object({
|
|
|
17
18
|
text: z.string(),
|
|
18
19
|
});
|
|
19
20
|
export function registerGetSymbolSource(server) {
|
|
20
|
-
server.registerTool(
|
|
21
|
+
server.registerTool(TOOL_NAME, {
|
|
21
22
|
title: "Get one symbol implementation",
|
|
22
23
|
description: "Returns exactly one declaration or implementation with its project-relative location, not the complete file.",
|
|
23
24
|
inputSchema: AstGetSymbolSourceInputSchema,
|
|
@@ -39,7 +40,9 @@ export function registerGetSymbolSource(server) {
|
|
|
39
40
|
return structuredResult(structuredContent);
|
|
40
41
|
}
|
|
41
42
|
catch (error) {
|
|
42
|
-
return errorResult(error, createToolErrorContext(
|
|
43
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
43
44
|
}
|
|
44
45
|
});
|
|
45
46
|
}
|
|
47
|
+
// prettier-ignore
|
|
48
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerGetSymbolSource, compatibility: "required", effect: "read", batch: "read", directOutputFormats: Object.freeze(["json"]) });
|
package/dist/tools/list_files.js
CHANGED
|
@@ -4,6 +4,7 @@ import { PaginationInputSchema, PaginationOutputSchema, paginate } from "../serv
|
|
|
4
4
|
import { withProject } from "../services/project.js";
|
|
5
5
|
import { createRequestContext } from "../services/request-context.js";
|
|
6
6
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
7
|
+
const TOOL_NAME = "ast_list_files";
|
|
7
8
|
const AstListFilesInputSchema = z.object({
|
|
8
9
|
project_root: z
|
|
9
10
|
.string()
|
|
@@ -19,7 +20,7 @@ const AstListFilesOutputSchema = z.object({
|
|
|
19
20
|
...PaginationOutputSchema,
|
|
20
21
|
});
|
|
21
22
|
export function registerListFiles(server) {
|
|
22
|
-
server.registerTool(
|
|
23
|
+
server.registerTool(TOOL_NAME, {
|
|
23
24
|
title: "List TypeScript/JavaScript project files",
|
|
24
25
|
description: "Lists source files included by the project's tsconfig in deterministic, project-relative, paginated form.",
|
|
25
26
|
inputSchema: AstListFilesInputSchema,
|
|
@@ -50,7 +51,9 @@ export function registerListFiles(server) {
|
|
|
50
51
|
return structuredResult(output);
|
|
51
52
|
}
|
|
52
53
|
catch (error) {
|
|
53
|
-
return errorResult(error, createToolErrorContext(
|
|
54
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
54
55
|
}
|
|
55
56
|
});
|
|
56
57
|
}
|
|
58
|
+
// prettier-ignore
|
|
59
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerListFiles, compatibility: "required", effect: "read", batch: "read", directOutputFormats: Object.freeze(["json"]) });
|
|
@@ -3,6 +3,7 @@ import { prepareRename } from "../services/operations.js";
|
|
|
3
3
|
import { createRequestContext } from "../services/request-context.js";
|
|
4
4
|
import { PreparedOperationOutputSchema, serializePreparedOperation } from "./operation-schema.js";
|
|
5
5
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
6
|
+
const TOOL_NAME = "ast_rename_symbol";
|
|
6
7
|
const AstRenameSymbolInputSchema = z.object({
|
|
7
8
|
project_root: z.string(),
|
|
8
9
|
file_path: z.string(),
|
|
@@ -18,7 +19,7 @@ const AstRenameSymbolInputSchema = z.object({
|
|
|
18
19
|
.describe("Permit a plan with new TypeScript errors after explicit review."),
|
|
19
20
|
});
|
|
20
21
|
export function registerRenameSymbol(server) {
|
|
21
|
-
server.registerTool(
|
|
22
|
+
server.registerTool(TOOL_NAME, {
|
|
22
23
|
title: "Prepare a project-wide structural rename",
|
|
23
24
|
description: "Prepares an exact hash-bound rename plan without writing. Review the preview and apply its operation_id with ast_apply_operation.",
|
|
24
25
|
inputSchema: AstRenameSymbolInputSchema,
|
|
@@ -45,7 +46,9 @@ export function registerRenameSymbol(server) {
|
|
|
45
46
|
return structuredResult(serializePreparedOperation(operation));
|
|
46
47
|
}
|
|
47
48
|
catch (error) {
|
|
48
|
-
return errorResult(error, createToolErrorContext(
|
|
49
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
49
50
|
}
|
|
50
51
|
});
|
|
51
52
|
}
|
|
53
|
+
// prettier-ignore
|
|
54
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerRenameSymbol, compatibility: "required", effect: "prepare", batch: "prepare", directOutputFormats: Object.freeze(["json"]) });
|
|
@@ -3,6 +3,7 @@ import { prepareReplaceBody } from "../services/operations.js";
|
|
|
3
3
|
import { createRequestContext } from "../services/request-context.js";
|
|
4
4
|
import { PreparedOperationOutputSchema, serializePreparedOperation } from "./operation-schema.js";
|
|
5
5
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
6
|
+
const TOOL_NAME = "ast_replace_symbol_body";
|
|
6
7
|
const AstReplaceSymbolBodyInputSchema = z.object({
|
|
7
8
|
project_root: z.string(),
|
|
8
9
|
file_path: z.string(),
|
|
@@ -18,7 +19,7 @@ const AstReplaceSymbolBodyInputSchema = z.object({
|
|
|
18
19
|
.describe("Permit a plan with new TypeScript errors after explicit review."),
|
|
19
20
|
});
|
|
20
21
|
export function registerReplaceSymbolBody(server) {
|
|
21
|
-
server.registerTool(
|
|
22
|
+
server.registerTool(TOOL_NAME, {
|
|
22
23
|
title: "Prepare an exact function-body replacement",
|
|
23
24
|
description: "Prepares a hash-bound body replacement while preserving the signature. Supports declarations, methods, accessors and function-valued variables/properties.",
|
|
24
25
|
inputSchema: AstReplaceSymbolBodyInputSchema,
|
|
@@ -45,7 +46,9 @@ export function registerReplaceSymbolBody(server) {
|
|
|
45
46
|
return structuredResult(serializePreparedOperation(operation));
|
|
46
47
|
}
|
|
47
48
|
catch (error) {
|
|
48
|
-
return errorResult(error, createToolErrorContext(
|
|
49
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
49
50
|
}
|
|
50
51
|
});
|
|
51
52
|
}
|
|
53
|
+
// prettier-ignore
|
|
54
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerReplaceSymbolBody, compatibility: "required", effect: "prepare", batch: "prepare", directOutputFormats: Object.freeze(["json"]) });
|
|
@@ -3,6 +3,7 @@ import { prepareScaffoldClass } from "../services/operations.js";
|
|
|
3
3
|
import { createRequestContext } from "../services/request-context.js";
|
|
4
4
|
import { createToolErrorContext, errorResult, structuredResult } from "./result.js";
|
|
5
5
|
import { PreparedOperationOutputSchema, serializePreparedOperation } from "./operation-schema.js";
|
|
6
|
+
const TOOL_NAME = "ast_scaffold_class";
|
|
6
7
|
const IdentifierSchema = z.string().min(1).max(200);
|
|
7
8
|
const TypeTextSchema = z.string().min(1).max(10_000);
|
|
8
9
|
const AccessSchema = z.enum(["public", "protected", "private"]);
|
|
@@ -111,7 +112,7 @@ export function registerScaffoldClass(server) {
|
|
|
111
112
|
// The SDK compatibility overload exceeds TypeScript's instantiation depth for this schema.
|
|
112
113
|
// Keep the complete runtime schema and isolate only the registrar type.
|
|
113
114
|
const registerTool = server.registerTool.bind(server);
|
|
114
|
-
registerTool(
|
|
115
|
+
registerTool(TOOL_NAME, {
|
|
115
116
|
title: "Prepare Class Scaffold",
|
|
116
117
|
description: "Prepares a hash-bound new TypeScript class file without writing it. Each method body throws an explicit not-implemented error. Review the diff, then apply the returned operation_id and plan_hash with ast_apply_operation.",
|
|
117
118
|
inputSchema: ScaffoldClassInputSchema,
|
|
@@ -141,7 +142,9 @@ export function registerScaffoldClass(server) {
|
|
|
141
142
|
return structuredResult(structuredContent);
|
|
142
143
|
}
|
|
143
144
|
catch (error) {
|
|
144
|
-
return errorResult(error, createToolErrorContext(
|
|
145
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, args.project_root));
|
|
145
146
|
}
|
|
146
147
|
});
|
|
147
148
|
}
|
|
149
|
+
// prettier-ignore
|
|
150
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerScaffoldClass, compatibility: "required", effect: "prepare", batch: "prepare", directOutputFormats: Object.freeze(["json"]) });
|
|
@@ -4,6 +4,7 @@ import { withProject, reportSymbolIndexFailure } from "../services/project.js";
|
|
|
4
4
|
import { createRequestContext } from "../services/request-context.js";
|
|
5
5
|
import { searchProjectSymbolsPage, searchProjectSymbolsPageWithIndex, } from "../services/symbols.js";
|
|
6
6
|
import { createToolErrorContext, errorResult, formattedResult, ToolOutputFormatInputSchema, } from "./result.js";
|
|
7
|
+
const TOOL_NAME = "ast_search_symbols";
|
|
7
8
|
const SEARCH_DEFAULT_LIMIT = 20;
|
|
8
9
|
const SearchDetailSchema = z.enum(["selectors", "summary", "full"]).default("summary");
|
|
9
10
|
const AstSearchSymbolsInputSchema = z.object({
|
|
@@ -77,7 +78,7 @@ function projectSymbols(detail, symbols) {
|
|
|
77
78
|
return symbols.map(({ file, selector, kind }) => ({ file, selector, kind }));
|
|
78
79
|
}
|
|
79
80
|
export function registerSearchSymbols(server) {
|
|
80
|
-
server.registerTool(
|
|
81
|
+
server.registerTool(TOOL_NAME, {
|
|
81
82
|
title: "Search project symbols",
|
|
82
83
|
description: "Ranks structural declarations and returns exact file/symbol selectors for downstream AST tools.",
|
|
83
84
|
inputSchema: AstSearchSymbolsInputSchema,
|
|
@@ -108,7 +109,9 @@ export function registerSearchSymbols(server) {
|
|
|
108
109
|
return formattedResult(outputSchema, structuredContent, output_format);
|
|
109
110
|
}
|
|
110
111
|
catch (error) {
|
|
111
|
-
return errorResult(error, createToolErrorContext(
|
|
112
|
+
return errorResult(error, createToolErrorContext(TOOL_NAME, project_root));
|
|
112
113
|
}
|
|
113
114
|
});
|
|
114
115
|
}
|
|
116
|
+
// prettier-ignore
|
|
117
|
+
export const toolDescriptor = Object.freeze({ name: TOOL_NAME, register: registerSearchSymbols, compatibility: "required", effect: "read", batch: "read", directOutputFormats: Object.freeze(["json", "toon"]) });
|
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.11.2 and the local `0.12.0` release candidate.
|
|
4
4
|
|
|
5
5
|
## Supported release target
|
|
6
6
|
|
|
7
7
|
| Environment | Status | Contract |
|
|
8
8
|
| ----------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------- |
|
|
9
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.
|
|
11
|
-
| Linux x64 with required GNU coreutils and procfs, current Node.js 24 line | Supported | Published v0.
|
|
10
|
+
| Linux x64 with required GNU coreutils and procfs, exact Node.js 22.13.0 | Supported | Published v0.11.2 and local 0.12.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.11.2 and local 0.12.0 matrices, each bound to its own package and tree bytes. |
|
|
12
12
|
| Other Linux architectures or systems without the required filesystem features | Unverified | Not supported until equivalent architecture, mutation, and filesystem-publication gates pass. |
|
|
13
13
|
| macOS | Unverified | Not supported until equivalent filesystem, process, package, mutation, and canary gates pass. |
|
|
14
14
|
| Windows | Unverified | Not supported until equivalent filesystem, process, package, mutation, and canary gates pass. |
|
|
15
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.12.0` release 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.11.2 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
|
|
|
@@ -50,7 +50,7 @@ The scoped Linux evidence passed on exact Node.js 22.13.0 and the governed Node.
|
|
|
50
50
|
|
|
51
51
|
## Symbol-index persistence
|
|
52
52
|
|
|
53
|
-
Published v0.
|
|
53
|
+
Published v0.11.2 and the local `0.12.0` release candidate select native SQLite when the persistence setting is absent or explicitly `enabled`; operators requiring no persistent index state must set `disabled` explicitly:
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
56
|
AST_SYMBOL_INDEX_PERSISTENCE=disabled \
|
|
@@ -80,7 +80,7 @@ Both commands are bounded and path-free. Clear preflights the tree, refuses unsa
|
|
|
80
80
|
|
|
81
81
|
## Production-readiness acceptance
|
|
82
82
|
|
|
83
|
-
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, published-next v0.11.0 or v0.11.1, or the local v0.
|
|
83
|
+
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, published-next v0.11.0 or v0.11.1, published v0.11.2, or the local v0.12.0 release 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, the exact 0.10.0 matrix remains historical published-release evidence, the exact 0.11.0 and 0.11.1 matrices remain historical evidence for their immutable published-next bytes before public-registry verification exposed their distinct verifier defects, and the exact 0.11.2 matrix remains historical published-release evidence. A separate exact 0.12.0 release matrix is the release-candidate gate for current repository bytes under both supported runtime lines, including bounded diagnostic aggregates, catalog-derived tool capability projections, and their independent release oracles; none of these matrices rebinds the older retained reports. MCP-PROD-404 remains normative for admission:
|
|
84
84
|
|
|
85
85
|
- zero semantic mismatches across disabled, cold, warm, restart, and rollback reads;
|
|
86
86
|
- 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.12.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": "3991d0a74e672c6c4d3fbd1c8bbb1a60009515ec"
|
|
101
101
|
}
|
|
@@ -4,7 +4,7 @@ description: "Trigger: navegar, analizar o editar TypeScript/JavaScript con el c
|
|
|
4
4
|
license: "ISC"
|
|
5
5
|
metadata:
|
|
6
6
|
author: "yail"
|
|
7
|
-
version: "4.
|
|
7
|
+
version: "4.6.0"
|
|
8
8
|
hermes:
|
|
9
9
|
tags: ["typescript", "javascript", "ast", "refactoring", "mcp"]
|
|
10
10
|
homepage: "https://github.com/yailPeralta/ast-mcp-server"
|
|
@@ -18,7 +18,7 @@ Cargar este skill antes de navegar semánticamente, analizar impacto o referenci
|
|
|
18
18
|
|
|
19
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
20
|
|
|
21
|
-
The local 0.
|
|
21
|
+
The local 0.12.0 release candidate requires Node.js `>=22.13.0` and is verified with exact Node.js 22.13.0 plus the governed Node.js 24 line. Published v0.11.2 retains its immutable Node.js 22.13.0/24 release evidence.
|
|
22
22
|
|
|
23
23
|
## Hard Rules
|
|
24
24
|
|
|
@@ -29,6 +29,18 @@ The local 0.11.2 release candidate requires Node.js `>=22.13.0` and is verified
|
|
|
29
29
|
- Nunca reconstruir postimages desde un diff; después del apply, ejecutar el gate canónico del proyecto.
|
|
30
30
|
- Conservar `correlation_id` en errores públicos sin exponer source, paths absolutos, argumentos, environment, cache, stacks ni credenciales.
|
|
31
31
|
|
|
32
|
+
## Diagnostic aggregates
|
|
33
|
+
|
|
34
|
+
`ast_get_diagnostics` keeps its existing response shape unless `include_aggregates: true` is requested. Enabled summaries cover the complete normalized snapshot, not only the selected raw page, and cap both code and file groups at 20.
|
|
35
|
+
|
|
36
|
+
For each dimension, `groups.length + omitted_group_count = total_group_count` and group counts sum to `covered_diagnostic_count`. Code coverage plus omitted diagnostics equals the total; file coverage additionally includes `unfiled_diagnostic_count`. File groups expose normalized project-relative paths only and may include paths absent from the raw page.
|
|
37
|
+
|
|
38
|
+
## Contributor contract
|
|
39
|
+
|
|
40
|
+
Al agregar o modificar una tool, mantener schemas, metadata, annotations, handler, errores y serialización en su módulo. Exportar un descriptor congelado y ubicarlo deliberadamente en `src/tools/catalog.ts`; el catálogo solo admite hechos estáticos de efecto, batch, compatibilidad y formatos directos.
|
|
41
|
+
|
|
42
|
+
Las expectativas de `tools/list` deben seguir siendo independientes: revisar el inventario y metadata completos antes de actualizar sus hashes, sin importar ni derivar valores desde el catálogo.
|
|
43
|
+
|
|
32
44
|
## Decision Gates
|
|
33
45
|
|
|
34
46
|
| Situación | Acción |
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schema_version": 2,
|
|
3
3
|
"algorithm": "sha256",
|
|
4
4
|
"current": {
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.6.0",
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"path": "SKILL.md",
|
|
9
|
-
"sha256": "
|
|
9
|
+
"sha256": "d0048ffd9a585d00791540c6fa5e0bec91ff95b1448479678f85702e6b09be8a"
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"path": "references/operations.md",
|
|
@@ -79,6 +79,21 @@
|
|
|
79
79
|
"version": "4.4.0",
|
|
80
80
|
"sha256": "253b588c56d44c8f5565db3f33ce227d80c7c29aa6604d362844f44b1278385a",
|
|
81
81
|
"npm_versions": ["0.10.0"]
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"version": "4.5.0",
|
|
85
|
+
"sha256": "be757e8bd98733c7ee952d63a2805dcd9877becf651b4fcb6ab63d20f6546f21",
|
|
86
|
+
"npm_versions": ["0.11.0"]
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"version": "4.5.0",
|
|
90
|
+
"sha256": "2729b30ff6b7344e6680c7ee02ab540bc6db9774ad7111f091cd356f8cc9d4ce",
|
|
91
|
+
"npm_versions": ["0.11.1"]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"version": "4.5.0",
|
|
95
|
+
"sha256": "18132b4b747d135e4ccfbca9e2190a9afb41e144cc06c31c5e6bc0f1571e11da",
|
|
96
|
+
"npm_versions": ["0.11.2"]
|
|
82
97
|
}
|
|
83
98
|
]
|
|
84
99
|
}
|