@flyingrobots/graft 0.7.0 → 0.7.1
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 +13 -0
- package/README.md +0 -1
- package/bin/graft.js +26 -26
- package/dist/cli/init-client-config.d.ts.map +1 -1
- package/dist/cli/init-client-config.js +40 -4
- package/dist/cli/init-client-config.js.map +1 -1
- package/dist/cli/init-model.js +2 -2
- package/dist/cli/init-model.js.map +1 -1
- package/dist/cli/json-document.d.ts +1 -0
- package/dist/cli/json-document.d.ts.map +1 -1
- package/dist/cli/json-document.js +3 -0
- package/dist/cli/json-document.js.map +1 -1
- package/dist/hooks/posttooluse-read.js +1 -1
- package/dist/hooks/posttooluse-read.js.map +1 -1
- package/dist/hooks/pretooluse-read.js +1 -1
- package/dist/hooks/pretooluse-read.js.map +1 -1
- package/dist/mcp/daemon-worker-child-pool.d.ts +2 -0
- package/dist/mcp/daemon-worker-child-pool.d.ts.map +1 -1
- package/dist/mcp/daemon-worker-child-pool.js +10 -3
- package/dist/mcp/daemon-worker-child-pool.js.map +1 -1
- package/dist/mcp/daemon-worker-pool.d.ts +1 -1
- package/dist/mcp/daemon-worker-pool.d.ts.map +1 -1
- package/dist/mcp/daemon-worker-pool.js +1 -1
- package/dist/mcp/daemon-worker-pool.js.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +3 -1
- package/dist/version.js.map +1 -1
- package/docs/SETUP.md +11 -7
- package/package.json +9 -4
- package/src/adapters/canonical-json.ts +0 -56
- package/src/adapters/json-text-decoder.ts +0 -11
- package/src/adapters/node-fs.ts +0 -43
- package/src/adapters/node-git.ts +0 -47
- package/src/adapters/node-paths.ts +0 -35
- package/src/adapters/node-process-runner.ts +0 -27
- package/src/adapters/repo-paths.ts +0 -63
- package/src/adapters/rotating-ndjson-log.ts +0 -66
- package/src/api/index.ts +0 -107
- package/src/api/repo-local-graft.ts +0 -21
- package/src/api/repo-workspace.ts +0 -34
- package/src/api/tool-bridge.ts +0 -22
- package/src/cli/activity-render.ts +0 -112
- package/src/cli/cli-error.ts +0 -192
- package/src/cli/command-parser.ts +0 -484
- package/src/cli/daemon-status-model.ts +0 -238
- package/src/cli/daemon-status-render.ts +0 -102
- package/src/cli/daemon-status.ts +0 -100
- package/src/cli/entrypoint.ts +0 -18
- package/src/cli/git-graft-enhance-model.ts +0 -131
- package/src/cli/git-graft-enhance-render.ts +0 -33
- package/src/cli/git-graft-enhance.ts +0 -54
- package/src/cli/index-cmd.ts +0 -90
- package/src/cli/index-model.ts +0 -75
- package/src/cli/init-bootstrap.ts +0 -47
- package/src/cli/init-client-config.ts +0 -428
- package/src/cli/init-model.ts +0 -284
- package/src/cli/init-render.ts +0 -54
- package/src/cli/init-target-hooks.ts +0 -93
- package/src/cli/init.ts +0 -124
- package/src/cli/json-document.ts +0 -155
- package/src/cli/local-history-dag-model.ts +0 -437
- package/src/cli/local-history-dag-render.ts +0 -133
- package/src/cli/local-history-dag.ts +0 -103
- package/src/cli/main.ts +0 -197
- package/src/cli/migrate-local-history.ts +0 -119
- package/src/cli/peer-command.ts +0 -60
- package/src/contracts/capabilities.ts +0 -540
- package/src/contracts/causal-ontology.ts +0 -627
- package/src/contracts/causal-surface-next-action.ts +0 -18
- package/src/contracts/json-object.ts +0 -18
- package/src/contracts/mcp-runtime.ts +0 -16
- package/src/contracts/output-schema-cli.ts +0 -103
- package/src/contracts/output-schema-fragments.ts +0 -881
- package/src/contracts/output-schema-mcp.ts +0 -501
- package/src/contracts/output-schema-meta.ts +0 -119
- package/src/contracts/output-schemas.ts +0 -1524
- package/src/git/diff.ts +0 -161
- package/src/git/target-git-hook-bootstrap.ts +0 -56
- package/src/guards/stream-boundary.ts +0 -110
- package/src/hooks/posttooluse-read.ts +0 -54
- package/src/hooks/pretooluse-read.ts +0 -52
- package/src/hooks/read-governor.ts +0 -95
- package/src/hooks/read-messages.ts +0 -53
- package/src/hooks/shared.ts +0 -168
- package/src/index.ts +0 -1
- package/src/mcp/burden.ts +0 -132
- package/src/mcp/cache.ts +0 -7
- package/src/mcp/cached-file.ts +0 -1
- package/src/mcp/context.ts +0 -150
- package/src/mcp/control-plane/authz-storage.ts +0 -129
- package/src/mcp/control-plane/session-registry.ts +0 -115
- package/src/mcp/control-plane/status-projection.ts +0 -76
- package/src/mcp/control-plane/types.ts +0 -144
- package/src/mcp/daemon-bootstrap.ts +0 -100
- package/src/mcp/daemon-control-plane.ts +0 -310
- package/src/mcp/daemon-job-scheduler.ts +0 -279
- package/src/mcp/daemon-repos.ts +0 -99
- package/src/mcp/daemon-server.ts +0 -172
- package/src/mcp/daemon-session-host.ts +0 -234
- package/src/mcp/daemon-stdio-bridge.ts +0 -262
- package/src/mcp/daemon-worker-child-pool.ts +0 -213
- package/src/mcp/daemon-worker-inline-pool.ts +0 -46
- package/src/mcp/daemon-worker-pool.ts +0 -7
- package/src/mcp/daemon-worker-process.ts +0 -52
- package/src/mcp/daemon-worker-types.ts +0 -66
- package/src/mcp/metrics.ts +0 -176
- package/src/mcp/monitor-health.ts +0 -83
- package/src/mcp/monitor-persistence.ts +0 -54
- package/src/mcp/monitor-tick-job.ts +0 -153
- package/src/mcp/monitor-types.ts +0 -103
- package/src/mcp/persisted-local-history-graph.ts +0 -592
- package/src/mcp/persisted-local-history-policy.ts +0 -501
- package/src/mcp/persisted-local-history-views.ts +0 -250
- package/src/mcp/persisted-local-history.ts +0 -1621
- package/src/mcp/persistent-monitor-runtime.ts +0 -482
- package/src/mcp/policy.ts +0 -75
- package/src/mcp/receipt.ts +0 -201
- package/src/mcp/repo-concurrency.ts +0 -392
- package/src/mcp/repo-overview/filter.ts +0 -44
- package/src/mcp/repo-overview/types.ts +0 -63
- package/src/mcp/repo-overview/view-projection.ts +0 -90
- package/src/mcp/repo-state-git.ts +0 -247
- package/src/mcp/repo-state-observation.ts +0 -203
- package/src/mcp/repo-state-transition.ts +0 -151
- package/src/mcp/repo-state-types.ts +0 -107
- package/src/mcp/repo-state.ts +0 -146
- package/src/mcp/repo-tool-job.ts +0 -102
- package/src/mcp/repo-tool-worker-context.ts +0 -215
- package/src/mcp/repo-workspace.ts +0 -21
- package/src/mcp/run-capture-config.ts +0 -33
- package/src/mcp/runtime-causal-context.ts +0 -72
- package/src/mcp/runtime-observability.ts +0 -217
- package/src/mcp/runtime-staged-target.ts +0 -161
- package/src/mcp/runtime-workspace-overlay.ts +0 -255
- package/src/mcp/secret-scrub.ts +0 -89
- package/src/mcp/semantic-transition-guidance.ts +0 -60
- package/src/mcp/semantic-transition-summary.ts +0 -130
- package/src/mcp/server-context.ts +0 -236
- package/src/mcp/server-invocation.ts +0 -388
- package/src/mcp/server-tool-access.ts +0 -148
- package/src/mcp/server.ts +0 -270
- package/src/mcp/stdio-server.ts +0 -26
- package/src/mcp/stdio.ts +0 -3
- package/src/mcp/tool-registry.ts +0 -98
- package/src/mcp/tools/activity-view.ts +0 -325
- package/src/mcp/tools/budget.ts +0 -23
- package/src/mcp/tools/causal-attach.ts +0 -67
- package/src/mcp/tools/causal-status.ts +0 -58
- package/src/mcp/tools/changed-since.ts +0 -71
- package/src/mcp/tools/code-find.ts +0 -192
- package/src/mcp/tools/code-refs.ts +0 -470
- package/src/mcp/tools/code-show.ts +0 -289
- package/src/mcp/tools/daemon-monitors.ts +0 -14
- package/src/mcp/tools/daemon-repos.ts +0 -22
- package/src/mcp/tools/daemon-sessions.ts +0 -14
- package/src/mcp/tools/daemon-status.ts +0 -12
- package/src/mcp/tools/diagnostic-models.ts +0 -97
- package/src/mcp/tools/doctor.ts +0 -83
- package/src/mcp/tools/explain.ts +0 -84
- package/src/mcp/tools/export-surface-diff.ts +0 -26
- package/src/mcp/tools/file-outline.ts +0 -67
- package/src/mcp/tools/git-files.ts +0 -73
- package/src/mcp/tools/graft-diff.ts +0 -35
- package/src/mcp/tools/graft-edit.ts +0 -276
- package/src/mcp/tools/knowledge-map.ts +0 -34
- package/src/mcp/tools/map-collector.ts +0 -338
- package/src/mcp/tools/map.ts +0 -185
- package/src/mcp/tools/monitor-nudge.ts +0 -19
- package/src/mcp/tools/monitor-pause.ts +0 -18
- package/src/mcp/tools/monitor-resume.ts +0 -18
- package/src/mcp/tools/monitor-start.ts +0 -20
- package/src/mcp/tools/monitor-stop.ts +0 -18
- package/src/mcp/tools/precision-live.ts +0 -158
- package/src/mcp/tools/precision-match.ts +0 -54
- package/src/mcp/tools/precision-paths.ts +0 -59
- package/src/mcp/tools/precision-query.ts +0 -127
- package/src/mcp/tools/precision-show.ts +0 -86
- package/src/mcp/tools/precision-visibility.ts +0 -44
- package/src/mcp/tools/precision-warp.ts +0 -101
- package/src/mcp/tools/precision.ts +0 -21
- package/src/mcp/tools/read-range.ts +0 -28
- package/src/mcp/tools/refactor-difficulty.ts +0 -42
- package/src/mcp/tools/run-capture.ts +0 -149
- package/src/mcp/tools/safe-read.ts +0 -148
- package/src/mcp/tools/since.ts +0 -53
- package/src/mcp/tools/state.ts +0 -39
- package/src/mcp/tools/stats.ts +0 -24
- package/src/mcp/tools/structural-blame.ts +0 -55
- package/src/mcp/tools/structural-churn.ts +0 -28
- package/src/mcp/tools/structural-log.ts +0 -41
- package/src/mcp/tools/structural-review.ts +0 -63
- package/src/mcp/tools/workspace-authorizations.ts +0 -14
- package/src/mcp/tools/workspace-authorize.ts +0 -20
- package/src/mcp/tools/workspace-bind.ts +0 -25
- package/src/mcp/tools/workspace-rebind.ts +0 -25
- package/src/mcp/tools/workspace-revoke.ts +0 -18
- package/src/mcp/tools/workspace-status.ts +0 -12
- package/src/mcp/warp-pool.ts +0 -36
- package/src/mcp/workspace-read-observation-model.ts +0 -48
- package/src/mcp/workspace-read-observation.ts +0 -103
- package/src/mcp/workspace-router-capability.ts +0 -32
- package/src/mcp/workspace-router-history.ts +0 -233
- package/src/mcp/workspace-router-model.ts +0 -131
- package/src/mcp/workspace-router-resolution.ts +0 -71
- package/src/mcp/workspace-router-runtime.ts +0 -246
- package/src/mcp/workspace-router.ts +0 -688
- package/src/metrics/logger.ts +0 -40
- package/src/metrics/types.ts +0 -40
- package/src/operations/adaptive-projection.ts +0 -54
- package/src/operations/agent-handoff.ts +0 -59
- package/src/operations/cached-file.ts +0 -40
- package/src/operations/capture-range.ts +0 -64
- package/src/operations/conversation-primer.ts +0 -82
- package/src/operations/cross-session-resume.ts +0 -104
- package/src/operations/deterministic-replay.ts +0 -143
- package/src/operations/diff-identity.ts +0 -127
- package/src/operations/export-surface-diff.ts +0 -355
- package/src/operations/file-outline.ts +0 -48
- package/src/operations/footprint-parallelism.ts +0 -98
- package/src/operations/graft-diff.ts +0 -169
- package/src/operations/horizon-of-readability.ts +0 -60
- package/src/operations/import-reference-impact.ts +0 -143
- package/src/operations/knowledge-map.ts +0 -96
- package/src/operations/observation-cache.ts +0 -165
- package/src/operations/projection-safety.ts +0 -111
- package/src/operations/read-range.ts +0 -64
- package/src/operations/repo-workspace.ts +0 -339
- package/src/operations/result-dto.ts +0 -23
- package/src/operations/safe-read.ts +0 -118
- package/src/operations/semantic-drift.ts +0 -70
- package/src/operations/session-filtration.ts +0 -76
- package/src/operations/session-replay.ts +0 -73
- package/src/operations/sludge-detector.ts +0 -356
- package/src/operations/state.ts +0 -66
- package/src/operations/structural-blame.ts +0 -197
- package/src/operations/structural-review.ts +0 -317
- package/src/operations/structured-buffer-compare.ts +0 -429
- package/src/operations/structured-buffer-model.ts +0 -456
- package/src/operations/structured-buffer-query.ts +0 -794
- package/src/operations/structured-buffer.ts +0 -181
- package/src/operations/teaching-hints.ts +0 -52
- package/src/parser/diff.ts +0 -320
- package/src/parser/lang.ts +0 -71
- package/src/parser/markdown.ts +0 -197
- package/src/parser/outline.ts +0 -316
- package/src/parser/runtime.ts +0 -71
- package/src/parser/types.ts +0 -75
- package/src/policy/evaluate.ts +0 -178
- package/src/policy/graftignore.ts +0 -6
- package/src/policy/types.ts +0 -87
- package/src/ports/codec.ts +0 -13
- package/src/ports/filesystem.ts +0 -18
- package/src/ports/git.ts +0 -16
- package/src/ports/guards.ts +0 -68
- package/src/ports/paths.ts +0 -22
- package/src/ports/process-runner.ts +0 -22
- package/src/release/security-gate.ts +0 -102
- package/src/session/tracker.ts +0 -145
- package/src/session/types.ts +0 -23
- package/src/version.ts +0 -3
- package/src/warp/ast-emitter.ts +0 -133
- package/src/warp/ast-import-resolver.ts +0 -333
- package/src/warp/commit-meta.ts +0 -19
- package/src/warp/context.ts +0 -48
- package/src/warp/dead-symbols.ts +0 -174
- package/src/warp/drift-sentinel.ts +0 -101
- package/src/warp/index-head.ts +0 -348
- package/src/warp/observers.ts +0 -101
- package/src/warp/open.ts +0 -67
- package/src/warp/outline-diff-trailer.ts +0 -100
- package/src/warp/plumbing.d.ts +0 -24
- package/src/warp/refactor-difficulty.ts +0 -257
- package/src/warp/references.ts +0 -77
- package/src/warp/stale-docs.ts +0 -210
- package/src/warp/structural-drift-detection.ts +0 -97
- package/src/warp/structural-queries.ts +0 -258
- package/src/warp/symbol-timeline.ts +0 -209
- package/src/warp/traverse-hydrate.ts +0 -61
- package/src/warp/warp-reference-count.ts +0 -47
- package/src/warp/warp-structural-blame.ts +0 -65
- package/src/warp/warp-structural-churn.ts +0 -309
- package/src/warp/warp-structural-log.ts +0 -149
- package/src/warp/writer-id.ts +0 -30
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { fileOutline } from "../../operations/file-outline.js";
|
|
3
|
-
import { detectStructuredFormat } from "../../parser/lang.js";
|
|
4
|
-
import { hashContent } from "../cache.js";
|
|
5
|
-
import type { ToolDefinition, ToolHandler } from "../context.js";
|
|
6
|
-
import { toJsonObject } from "../../operations/result-dto.js";
|
|
7
|
-
|
|
8
|
-
export const fileOutlineTool: ToolDefinition = {
|
|
9
|
-
name: "file_outline",
|
|
10
|
-
description:
|
|
11
|
-
"Structural skeleton of a file \u2014 function signatures, class shapes, " +
|
|
12
|
-
"exports. Includes a jump table mapping each symbol to its line range " +
|
|
13
|
-
"for targeted read_range follow-ups.",
|
|
14
|
-
schema: { path: z.string() },
|
|
15
|
-
policyCheck: true,
|
|
16
|
-
createHandler(): ToolHandler {
|
|
17
|
-
return async (args, ctx) => {
|
|
18
|
-
const filePath = ctx.resolvePath(args["path"] as string);
|
|
19
|
-
ctx.recordFootprint({ paths: [filePath] });
|
|
20
|
-
|
|
21
|
-
// Check cache
|
|
22
|
-
let rawContent: string | null = null;
|
|
23
|
-
try {
|
|
24
|
-
rawContent = await ctx.fs.readFile(filePath, "utf-8");
|
|
25
|
-
} catch {
|
|
26
|
-
// proceed to fileOutline for error handling
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const outlineSupported = detectStructuredFormat(filePath) !== null;
|
|
30
|
-
|
|
31
|
-
if (rawContent !== null && outlineSupported) {
|
|
32
|
-
const cacheResult = ctx.cache.check(filePath, rawContent);
|
|
33
|
-
if (cacheResult.hit) {
|
|
34
|
-
cacheResult.obs.touch(ctx.cache.now());
|
|
35
|
-
ctx.metrics.recordCacheHit(cacheResult.obs.actual.bytes);
|
|
36
|
-
ctx.recordFootprint({
|
|
37
|
-
symbols: cacheResult.obs.outline.map((e) => e.name),
|
|
38
|
-
});
|
|
39
|
-
return ctx.respond("file_outline", {
|
|
40
|
-
path: filePath,
|
|
41
|
-
outline: cacheResult.obs.outline,
|
|
42
|
-
jumpTable: cacheResult.obs.jumpTable,
|
|
43
|
-
cacheHit: true,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
// If stale, fall through to fresh parse (no diff for file_outline)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const result = await fileOutline(filePath, { fs: ctx.fs });
|
|
50
|
-
ctx.metrics.recordOutline();
|
|
51
|
-
ctx.recordFootprint({ symbols: result.outline.map((e) => e.name) });
|
|
52
|
-
|
|
53
|
-
// Record observation
|
|
54
|
-
if (rawContent !== null && outlineSupported && result.reason !== "UNSUPPORTED_LANGUAGE") {
|
|
55
|
-
ctx.cache.record(
|
|
56
|
-
filePath,
|
|
57
|
-
hashContent(rawContent),
|
|
58
|
-
result.outline,
|
|
59
|
-
result.jumpTable,
|
|
60
|
-
{ lines: rawContent.split("\n").length, bytes: Buffer.byteLength(rawContent) },
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return ctx.respond("file_outline", toJsonObject(result));
|
|
65
|
-
};
|
|
66
|
-
},
|
|
67
|
-
};
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import type { GitClient } from "../../ports/git.js";
|
|
2
|
-
|
|
3
|
-
type GitFileListMode = "tracked" | "project";
|
|
4
|
-
|
|
5
|
-
export class GitFileQuery {
|
|
6
|
-
readonly cwd: string;
|
|
7
|
-
readonly dirPath: string;
|
|
8
|
-
readonly mode: GitFileListMode;
|
|
9
|
-
|
|
10
|
-
constructor(opts: {
|
|
11
|
-
cwd: string;
|
|
12
|
-
dirPath: string;
|
|
13
|
-
mode: GitFileListMode;
|
|
14
|
-
}) {
|
|
15
|
-
if (opts.cwd.trim().length === 0) {
|
|
16
|
-
throw new Error("GitFileQuery: cwd must be non-empty");
|
|
17
|
-
}
|
|
18
|
-
this.cwd = opts.cwd;
|
|
19
|
-
this.dirPath = opts.dirPath.trim();
|
|
20
|
-
this.mode = opts.mode;
|
|
21
|
-
Object.freeze(this);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static tracked(cwd: string, dirPath: string): GitFileQuery {
|
|
25
|
-
return new GitFileQuery({ cwd, dirPath, mode: "tracked" });
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static project(cwd: string, dirPath: string): GitFileQuery {
|
|
29
|
-
return new GitFileQuery({ cwd, dirPath, mode: "project" });
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
toArgs(): string[] {
|
|
33
|
-
if (this.mode === "tracked") {
|
|
34
|
-
return this.dirPath.length > 0 ? ["ls-files", "--", this.dirPath] : ["ls-files"];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return this.dirPath.length > 0
|
|
38
|
-
? ["ls-files", "--cached", "--others", "--exclude-standard", "--", this.dirPath]
|
|
39
|
-
: ["ls-files", "--cached", "--others", "--exclude-standard"];
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export class GitFileList {
|
|
44
|
-
readonly paths: readonly string[];
|
|
45
|
-
|
|
46
|
-
constructor(paths: readonly string[]) {
|
|
47
|
-
this.paths = Object.freeze([...paths]);
|
|
48
|
-
Object.freeze(this);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export async function listGitFiles(query: GitFileQuery, git: GitClient): Promise<GitFileList> {
|
|
53
|
-
try {
|
|
54
|
-
const result = await git.run({ args: query.toArgs(), cwd: query.cwd });
|
|
55
|
-
if (result.error !== undefined || result.status !== 0) {
|
|
56
|
-
throw result.error ?? new Error(result.stderr.trim() || `git exited with status ${String(result.status)}`);
|
|
57
|
-
}
|
|
58
|
-
const output = result.stdout.trim();
|
|
59
|
-
const paths = output.length === 0 ? [] : output.split("\n");
|
|
60
|
-
return new GitFileList(paths);
|
|
61
|
-
} catch (err: unknown) {
|
|
62
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
63
|
-
throw new Error(`git file listing failed: ${message}`, { cause: err });
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export async function listTrackedFiles(dirPath: string, cwd: string, git: GitClient): Promise<string[]> {
|
|
68
|
-
return [...(await listGitFiles(GitFileQuery.tracked(cwd, dirPath), git)).paths];
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export async function listProjectFiles(dirPath: string, cwd: string, git: GitClient): Promise<string[]> {
|
|
72
|
-
return [...(await listGitFiles(GitFileQuery.project(cwd, dirPath), git)).paths];
|
|
73
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { graftDiff } from "../../operations/graft-diff.js";
|
|
3
|
-
import type { ToolDefinition, ToolHandler } from "../context.js";
|
|
4
|
-
import { evaluateMcpRefusal } from "../policy.js";
|
|
5
|
-
|
|
6
|
-
export const graftDiffTool: ToolDefinition = {
|
|
7
|
-
name: "graft_diff",
|
|
8
|
-
description:
|
|
9
|
-
"Structural diff between two git refs. Shows added, removed, and " +
|
|
10
|
-
"changed symbols per file \u2014 not line hunks. Defaults to working " +
|
|
11
|
-
"tree vs HEAD.",
|
|
12
|
-
schema: { base: z.string().optional(), head: z.string().optional(), path: z.string().optional() },
|
|
13
|
-
createHandler(): ToolHandler {
|
|
14
|
-
return async (args, ctx) => {
|
|
15
|
-
const head = args["head"] as string | undefined;
|
|
16
|
-
const result = await graftDiff({
|
|
17
|
-
cwd: ctx.projectRoot,
|
|
18
|
-
fs: ctx.fs,
|
|
19
|
-
git: ctx.git,
|
|
20
|
-
resolveWorkingTreePath: (filePath) => ctx.resolvePath(filePath),
|
|
21
|
-
base: args["base"] as string | undefined,
|
|
22
|
-
head,
|
|
23
|
-
path: args["path"] as string | undefined,
|
|
24
|
-
refusalCheck: (filePath, actual) => evaluateMcpRefusal(ctx, filePath, actual),
|
|
25
|
-
});
|
|
26
|
-
ctx.recordFootprint({
|
|
27
|
-
paths: (result.files as readonly { path: string }[]).map((f) => f.path),
|
|
28
|
-
});
|
|
29
|
-
return ctx.respond("graft_diff", {
|
|
30
|
-
...result,
|
|
31
|
-
layer: head === undefined ? "workspace_overlay" : "ref_view",
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
},
|
|
35
|
-
};
|
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { evaluateMcpPolicy } from "../policy.js";
|
|
3
|
-
import { RefusedResult } from "../../policy/types.js";
|
|
4
|
-
import type { ToolDefinition, ToolHandler } from "../context.js";
|
|
5
|
-
|
|
6
|
-
type GraftEditReason =
|
|
7
|
-
| "NOT_FOUND"
|
|
8
|
-
| "OLD_STRING_NOT_FOUND"
|
|
9
|
-
| "OLD_STRING_AMBIGUOUS"
|
|
10
|
-
| RefusedResult["reason"];
|
|
11
|
-
|
|
12
|
-
type DriftPattern = "jsdoc_typedef";
|
|
13
|
-
type DriftDirection = "removed" | "added";
|
|
14
|
-
|
|
15
|
-
interface GraftEditDriftObservation {
|
|
16
|
-
readonly pattern: DriftPattern;
|
|
17
|
-
readonly path: string;
|
|
18
|
-
readonly direction: DriftDirection;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface GraftEditDriftWarning {
|
|
22
|
-
readonly kind: "structural_pattern_reintroduced";
|
|
23
|
-
readonly severity: "advisory";
|
|
24
|
-
readonly pattern: DriftPattern;
|
|
25
|
-
readonly basis: "session_local_graft_edit";
|
|
26
|
-
readonly message: string;
|
|
27
|
-
readonly current: {
|
|
28
|
-
readonly path: string;
|
|
29
|
-
readonly direction: "added";
|
|
30
|
-
};
|
|
31
|
-
readonly previous: {
|
|
32
|
-
readonly path: string;
|
|
33
|
-
readonly direction: "removed";
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
interface GraftEditResponse {
|
|
38
|
-
readonly path: string;
|
|
39
|
-
readonly operation: "replace";
|
|
40
|
-
readonly projection: "edited" | "refused";
|
|
41
|
-
readonly status: "edited" | "refused";
|
|
42
|
-
readonly changed: boolean;
|
|
43
|
-
readonly matches: number;
|
|
44
|
-
readonly replacements: number;
|
|
45
|
-
readonly reason?: GraftEditReason;
|
|
46
|
-
readonly reasonDetail?: string;
|
|
47
|
-
readonly next?: readonly string[];
|
|
48
|
-
readonly actual?: {
|
|
49
|
-
readonly lines: number;
|
|
50
|
-
readonly bytes: number;
|
|
51
|
-
};
|
|
52
|
-
readonly driftWarnings?: readonly GraftEditDriftWarning[];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function countOccurrences(content: string, needle: string): number {
|
|
56
|
-
if (needle.length === 0) {
|
|
57
|
-
return content.length + 1;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let count = 0;
|
|
61
|
-
let offset = 0;
|
|
62
|
-
while (offset <= content.length) {
|
|
63
|
-
const index = content.indexOf(needle, offset);
|
|
64
|
-
if (index === -1) {
|
|
65
|
-
return count;
|
|
66
|
-
}
|
|
67
|
-
count += 1;
|
|
68
|
-
offset = index + needle.length;
|
|
69
|
-
}
|
|
70
|
-
return count;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async function actualForFile(
|
|
74
|
-
content: string,
|
|
75
|
-
stat: () => Promise<{ size: number }>,
|
|
76
|
-
): Promise<{ lines: number; bytes: number }> {
|
|
77
|
-
const fileStat = await stat();
|
|
78
|
-
return {
|
|
79
|
-
lines: content.split("\n").length,
|
|
80
|
-
bytes: fileStat.size,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function refused(input: {
|
|
85
|
-
readonly path: string;
|
|
86
|
-
readonly reason: GraftEditReason;
|
|
87
|
-
readonly reasonDetail?: string;
|
|
88
|
-
readonly next?: readonly string[];
|
|
89
|
-
readonly actual?: { readonly lines: number; readonly bytes: number };
|
|
90
|
-
readonly matches?: number;
|
|
91
|
-
}): GraftEditResponse {
|
|
92
|
-
return {
|
|
93
|
-
path: input.path,
|
|
94
|
-
operation: "replace",
|
|
95
|
-
projection: "refused",
|
|
96
|
-
status: "refused",
|
|
97
|
-
changed: false,
|
|
98
|
-
matches: input.matches ?? 0,
|
|
99
|
-
replacements: 0,
|
|
100
|
-
reason: input.reason,
|
|
101
|
-
...(input.reasonDetail !== undefined ? { reasonDetail: input.reasonDetail } : {}),
|
|
102
|
-
...(input.next !== undefined ? { next: [...input.next] } : {}),
|
|
103
|
-
...(input.actual !== undefined ? { actual: input.actual } : {}),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function containsJsdocTypedef(content: string): boolean {
|
|
108
|
-
return content
|
|
109
|
-
.split(/\r?\n/u)
|
|
110
|
-
.some((line) => line.trimStart().startsWith("* @typedef "));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function classifyStructuralEdit(input: {
|
|
114
|
-
readonly path: string;
|
|
115
|
-
readonly oldString: string;
|
|
116
|
-
readonly newString: string;
|
|
117
|
-
}): GraftEditDriftObservation | null {
|
|
118
|
-
const oldHasTypedef = containsJsdocTypedef(input.oldString);
|
|
119
|
-
const newHasTypedef = containsJsdocTypedef(input.newString);
|
|
120
|
-
if (oldHasTypedef === newHasTypedef) {
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
path: input.path,
|
|
125
|
-
pattern: "jsdoc_typedef",
|
|
126
|
-
direction: oldHasTypedef ? "removed" : "added",
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function buildDriftWarnings(
|
|
131
|
-
observation: GraftEditDriftObservation | null,
|
|
132
|
-
priorObservations: readonly GraftEditDriftObservation[],
|
|
133
|
-
): GraftEditDriftWarning[] {
|
|
134
|
-
if (observation?.direction !== "added") {
|
|
135
|
-
return [];
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
let previous: GraftEditDriftObservation | undefined;
|
|
139
|
-
for (let i = priorObservations.length - 1; i >= 0; i--) {
|
|
140
|
-
const candidate = priorObservations[i];
|
|
141
|
-
if (candidate?.pattern === observation.pattern && candidate.direction === "removed") {
|
|
142
|
-
previous = candidate;
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
if (previous === undefined) {
|
|
147
|
-
return [];
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return [{
|
|
151
|
-
kind: "structural_pattern_reintroduced",
|
|
152
|
-
severity: "advisory",
|
|
153
|
-
pattern: observation.pattern,
|
|
154
|
-
basis: "session_local_graft_edit",
|
|
155
|
-
message: "You are adding a typedef in a session that has been removing typedefs.",
|
|
156
|
-
current: {
|
|
157
|
-
path: observation.path,
|
|
158
|
-
direction: "added",
|
|
159
|
-
},
|
|
160
|
-
previous: {
|
|
161
|
-
path: previous.path,
|
|
162
|
-
direction: "removed",
|
|
163
|
-
},
|
|
164
|
-
}];
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export const graftEditTool: ToolDefinition = {
|
|
168
|
-
name: "graft_edit",
|
|
169
|
-
description:
|
|
170
|
-
"Perform one governed exact string replacement in a repo file. " +
|
|
171
|
-
"Requires path, old_string, and new_string. Refuses missing or " +
|
|
172
|
-
"ambiguous old_string matches and policy-denied paths.",
|
|
173
|
-
schema: {
|
|
174
|
-
path: z.string(),
|
|
175
|
-
old_string: z.string(),
|
|
176
|
-
new_string: z.string(),
|
|
177
|
-
},
|
|
178
|
-
createHandler(): ToolHandler {
|
|
179
|
-
const structuralEditObservations: GraftEditDriftObservation[] = [];
|
|
180
|
-
|
|
181
|
-
return async (args, ctx) => {
|
|
182
|
-
const filePath = ctx.resolvePath(args["path"] as string);
|
|
183
|
-
const oldString = args["old_string"] as string;
|
|
184
|
-
const newString = args["new_string"] as string;
|
|
185
|
-
ctx.recordFootprint({ paths: [filePath] });
|
|
186
|
-
|
|
187
|
-
let content: string;
|
|
188
|
-
try {
|
|
189
|
-
content = await ctx.fs.readFile(filePath, "utf-8");
|
|
190
|
-
} catch {
|
|
191
|
-
ctx.metrics.recordRefusal();
|
|
192
|
-
return ctx.respond("graft_edit", {
|
|
193
|
-
...refused({
|
|
194
|
-
path: filePath,
|
|
195
|
-
reason: "NOT_FOUND",
|
|
196
|
-
reasonDetail: "File does not exist or cannot be read",
|
|
197
|
-
next: ["Choose an existing file; graft_edit does not create files"],
|
|
198
|
-
}),
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const actual = await actualForFile(content, () => ctx.fs.stat(filePath));
|
|
203
|
-
const policy = evaluateMcpPolicy(ctx, filePath, actual);
|
|
204
|
-
if (policy instanceof RefusedResult) {
|
|
205
|
-
ctx.metrics.recordRefusal();
|
|
206
|
-
return ctx.respond("graft_edit", {
|
|
207
|
-
...refused({
|
|
208
|
-
path: filePath,
|
|
209
|
-
reason: policy.reason,
|
|
210
|
-
reasonDetail: policy.reasonDetail,
|
|
211
|
-
next: policy.next,
|
|
212
|
-
actual,
|
|
213
|
-
}),
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const matches = countOccurrences(content, oldString);
|
|
218
|
-
if (matches === 0) {
|
|
219
|
-
ctx.metrics.recordRefusal();
|
|
220
|
-
return ctx.respond("graft_edit", {
|
|
221
|
-
...refused({
|
|
222
|
-
path: filePath,
|
|
223
|
-
reason: "OLD_STRING_NOT_FOUND",
|
|
224
|
-
reasonDetail: "old_string does not occur in the target file",
|
|
225
|
-
next: ["Inspect the current file content and provide an exact old_string"],
|
|
226
|
-
actual,
|
|
227
|
-
matches,
|
|
228
|
-
}),
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (matches !== 1) {
|
|
233
|
-
ctx.metrics.recordRefusal();
|
|
234
|
-
return ctx.respond("graft_edit", {
|
|
235
|
-
...refused({
|
|
236
|
-
path: filePath,
|
|
237
|
-
reason: "OLD_STRING_AMBIGUOUS",
|
|
238
|
-
reasonDetail: "old_string must occur exactly once",
|
|
239
|
-
next: ["Provide a longer old_string that uniquely identifies the edit site"],
|
|
240
|
-
actual,
|
|
241
|
-
matches,
|
|
242
|
-
}),
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const nextContent = content.replace(oldString, newString);
|
|
247
|
-
const changed = nextContent !== content;
|
|
248
|
-
if (changed) {
|
|
249
|
-
await ctx.fs.writeFile(filePath, nextContent, "utf-8");
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const observation = classifyStructuralEdit({
|
|
253
|
-
path: filePath,
|
|
254
|
-
oldString,
|
|
255
|
-
newString,
|
|
256
|
-
});
|
|
257
|
-
const driftWarnings = buildDriftWarnings(observation, structuralEditObservations);
|
|
258
|
-
if (observation !== null) {
|
|
259
|
-
structuralEditObservations.push(observation);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const response: GraftEditResponse = {
|
|
263
|
-
path: filePath,
|
|
264
|
-
operation: "replace",
|
|
265
|
-
projection: "edited",
|
|
266
|
-
status: "edited",
|
|
267
|
-
changed,
|
|
268
|
-
matches,
|
|
269
|
-
replacements: 1,
|
|
270
|
-
actual,
|
|
271
|
-
...(driftWarnings.length > 0 ? { driftWarnings } : {}),
|
|
272
|
-
};
|
|
273
|
-
return ctx.respond("graft_edit", { ...response });
|
|
274
|
-
};
|
|
275
|
-
},
|
|
276
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { buildKnowledgeMap } from "../../operations/knowledge-map.js";
|
|
2
|
-
import type { ToolDefinition, ToolHandler } from "../context.js";
|
|
3
|
-
|
|
4
|
-
export const knowledgeMapTool: ToolDefinition = {
|
|
5
|
-
name: "knowledge_map",
|
|
6
|
-
description:
|
|
7
|
-
"Session knowledge map — answers \"what do I already know?\" " +
|
|
8
|
-
"Lists all files and symbols observed this session, flags stale " +
|
|
9
|
-
"files (changed since last read), and shows directory coverage. " +
|
|
10
|
-
"Use before reading more files to avoid redundant context consumption.",
|
|
11
|
-
createHandler(): ToolHandler {
|
|
12
|
-
return async (_args, ctx) => {
|
|
13
|
-
const result = await buildKnowledgeMap({
|
|
14
|
-
cache: ctx.cache,
|
|
15
|
-
fs: ctx.fs,
|
|
16
|
-
projectRoot: ctx.projectRoot,
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
return ctx.respond("knowledge_map", {
|
|
20
|
-
totalFiles: result.totalFiles,
|
|
21
|
-
totalSymbols: result.totalSymbols,
|
|
22
|
-
files: result.files.map((f) => ({
|
|
23
|
-
path: f.path,
|
|
24
|
-
symbols: [...f.symbols],
|
|
25
|
-
readCount: f.readCount,
|
|
26
|
-
lastReadAt: f.lastReadAt,
|
|
27
|
-
stale: f.stale,
|
|
28
|
-
})),
|
|
29
|
-
staleFiles: [...result.staleFiles],
|
|
30
|
-
directoryCoverage: result.directoryCoverage,
|
|
31
|
-
});
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
};
|