dsh-hashline-edit 0.1.0 → 0.2.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/README.md +72 -70
- package/cordis.patch.yml +1 -1
- package/lib/index.js +4494 -4813
- package/lib/types/dsh/contracts.d.ts +69 -6
- package/lib/types/dsh/fs.d.ts +38 -3
- package/lib/types/dsh/guidance.d.ts +5 -5
- package/lib/types/dsh/hide.d.ts +78 -0
- package/lib/types/dsh/host-compat.d.ts +7 -78
- package/lib/types/dsh/index.d.ts +17 -7
- package/lib/types/dsh/metrics/events.d.ts +8 -1
- package/lib/types/dsh/metrics/instrument.d.ts +20 -14
- package/lib/types/dsh/metrics/observer.d.ts +28 -0
- package/lib/types/dsh/sandbox.d.ts +2 -2
- package/lib/types/dsh/shell-hook.d.ts +17 -8
- package/lib/types/dsh/shell-view.d.ts +65 -3
- package/lib/types/dsh/tools/apply-patch.d.ts +38 -0
- package/lib/types/dsh/tools/context.d.ts +19 -1
- package/lib/types/dsh/tools/output.d.ts +32 -4
- package/lib/types/dsh/tools/read.d.ts +12 -15
- package/lib/types/dsh/tools/undo.d.ts +5 -0
- package/lib/types/dsh/write-hook.d.ts +8 -22
- package/lib/types/src/apply-patch/commit.d.ts +49 -0
- package/lib/types/src/apply-patch/grammar.d.ts +29 -0
- package/lib/types/src/apply-patch/lifecycle.d.ts +32 -0
- package/lib/types/src/apply-patch/plan.d.ts +50 -0
- package/lib/types/src/apply-patch/render.d.ts +51 -0
- package/lib/types/src/apply-patch/resolve.d.ts +129 -0
- package/lib/types/src/apply-patch/tool.d.ts +54 -0
- package/lib/types/src/apply-patch/types.d.ts +362 -0
- package/lib/types/src/bash-view-banner.d.ts +20 -0
- package/lib/types/src/domain-errors.d.ts +16 -2
- package/lib/types/src/edit-undo.d.ts +11 -2
- package/lib/types/src/file-content/detection.d.ts +17 -0
- package/lib/types/src/file-content/index.d.ts +2 -2
- package/lib/types/src/file-content/preview.d.ts +1 -1
- package/lib/types/src/fs-lifecycle.d.ts +44 -0
- package/lib/types/src/hashline/resolve.d.ts +6 -0
- package/lib/types/src/host-utils.d.ts +63 -0
- package/lib/types/src/mutation-engine/batch-span-gate.d.ts +6 -0
- package/lib/types/src/mutation-engine/edit-request.d.ts +34 -0
- package/lib/types/src/mutation-engine/pipeline.d.ts +18 -3
- package/lib/types/src/mutation-engine/types.d.ts +50 -58
- package/lib/types/src/read-expansion/grammar-manifest.d.ts +4 -2
- package/lib/types/src/read-expansion/java-decoration.d.ts +21 -0
- package/lib/types/src/read-expansion/span-expansion.d.ts +6 -2
- package/lib/types/src/read-expansion/span-kind.d.ts +3 -2
- package/lib/types/src/read-expansion/vue-decoration.d.ts +14 -0
- package/lib/types/src/served-session/serve-render.d.ts +9 -3
- package/lib/types/src/undo-store.d.ts +17 -1
- package/package.json +10 -22
- package/prompts/apply-patch-guidelines.md +10 -0
- package/prompts/apply-patch.md +1 -0
- package/prompts/read-guidelines.md +5 -5
- package/prompts/read.md +1 -1
- package/prompts/undo-last-edit-guidelines.md +2 -2
- package/prompts/undo-last-edit-snippet.md +1 -1
- package/prompts/undo-last-edit.md +1 -1
- package/src/apply-patch/commit.ts +190 -0
- package/src/apply-patch/grammar.ts +620 -0
- package/src/apply-patch/index.ts +17 -0
- package/src/apply-patch/lifecycle.ts +195 -0
- package/src/apply-patch/plan.ts +800 -0
- package/src/apply-patch/render.ts +137 -0
- package/src/apply-patch/resolve.ts +470 -0
- package/src/apply-patch/tool.ts +257 -0
- package/src/apply-patch/types.ts +387 -0
- package/src/cut-repair.ts +77 -11
- package/src/domain-errors.ts +58 -10
- package/src/edit-undo.ts +379 -25
- package/src/file-content/detection.ts +34 -0
- package/src/file-content/index.ts +2 -2
- package/src/file-content/preview.ts +1 -1
- package/src/file-content/served-header.ts +1 -1
- package/src/fs-lifecycle.ts +201 -0
- package/src/hash-store.ts +18 -1
- package/src/hashline/lease-resolve.ts +14 -8
- package/src/hashline/resolve.ts +30 -27
- package/src/host-utils.ts +224 -0
- package/src/mutation-engine/batch-span-gate.ts +17 -4
- package/src/mutation-engine/edit-request.ts +39 -0
- package/src/mutation-engine/pipeline.ts +535 -63
- package/src/mutation-engine/types.ts +49 -65
- package/src/mutation-queue.ts +1 -1
- package/src/prompts.ts +0 -28
- package/src/read-expansion/ast-provider.ts +4 -0
- package/src/read-expansion/grammar-manifest.ts +21 -2
- package/src/read-expansion/java-decoration.ts +34 -0
- package/src/read-expansion/span-expansion.ts +6 -2
- package/src/read-expansion/span-kind.ts +3 -1
- package/src/read-expansion/vue-decoration.ts +43 -0
- package/src/served-session/serve-render.ts +5 -5
- package/src/undo-store.ts +74 -5
- package/lib/types/dsh/encoding-bridge.d.ts +0 -25
- package/lib/types/dsh/encoding.d.ts +0 -144
- package/lib/types/dsh/tools/edit.d.ts +0 -10
- package/lib/types/src/edit-tool.d.ts +0 -41
- package/lib/types/src/mutation-engine/engine.d.ts +0 -31
- package/lib/types/src/payload-contract.d.ts +0 -124
- package/prompts/edit-guidelines.md +0 -10
- package/prompts/edit-snippet.md +0 -1
- package/prompts/edit.md +0 -1
- package/src/bash-classifier.ts +0 -1626
- package/src/bash-conversion/decide.ts +0 -812
- package/src/bash-display-transform.ts +0 -50
- package/src/bash-multifile-config.ts +0 -239
- package/src/bash-view-config.ts +0 -158
- package/src/edit-normalize.ts +0 -8
- package/src/edit-render.ts +0 -161
- package/src/edit-tool.ts +0 -116
- package/src/edit.ts +0 -136
- package/src/integrations/pi-lens/command.ts +0 -712
- package/src/integrations/pi-lens/config.ts +0 -148
- package/src/integrations/pi-lens/io-bridge-adapter.ts +0 -234
- package/src/integrations/pi-lens/io-bridge.ts +0 -112
- package/src/integrations/pi-lens/settings-overlay.ts +0 -272
- package/src/lifecycle-hooks/index.ts +0 -1992
- package/src/lifecycle-hooks/types.ts +0 -64
- package/src/mutated-files.ts +0 -75
- package/src/mutation-engine/engine.ts +0 -173
- package/src/mutation-engine/index.ts +0 -17
- package/src/payload-contract.ts +0 -637
- package/src/preview-controller.ts +0 -84
- package/src/read.ts +0 -865
- package/src/search-hook.ts +0 -41
- package/src/store-config.ts +0 -73
- package/src/store-janitor-warning.ts +0 -169
- package/src/store-janitor.ts +0 -539
- package/src/store-kernel/settings.ts +0 -233
- package/src/store.ts +0 -154
- package/src/tui-presenter.ts +0 -134
- package/src/write-hook.ts +0 -130
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { ServedRow } from "../served-session/serve-render.js";
|
|
2
|
-
import type { EditDetails } from "../edit-response.js";
|
|
3
|
-
import type { NormFile, ReadNormOptions } from "../file-reader.js";
|
|
4
|
-
import type { LFile, LoadFileOptions } from "../file-kind.js";
|
|
5
|
-
import type { Hasher } from "../hashline/hasher.js";
|
|
6
|
-
import type { TruncationResult } from "@earendil-works/pi-coding-agent";
|
|
7
|
-
|
|
8
|
-
import type { DisplayTransform } from "../bash-classifier.js";
|
|
9
|
-
|
|
10
|
-
export type ToolResultEvent = {
|
|
11
|
-
toolName: string;
|
|
12
|
-
isError: boolean;
|
|
13
|
-
input?: Record<string, unknown>;
|
|
14
|
-
content?: Array<{ type: string; text: string }>;
|
|
15
|
-
details?: EditDetails;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export type ToolContext = {
|
|
19
|
-
cwd: string;
|
|
20
|
-
sessionManager?: { getSessionId(): string };
|
|
21
|
-
ui: { notify: (msg: string, level: string) => void };
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export type LifecycleDeps = {
|
|
25
|
-
initHasher: () => Promise<Hasher>;
|
|
26
|
-
pruneMissingAll: () => Promise<void>;
|
|
27
|
-
clearUndo: (path: string) => Promise<void>;
|
|
28
|
-
resolveTarget: (path: string) => Promise<string>;
|
|
29
|
-
toCwd: (path: string, cwd: string) => string;
|
|
30
|
-
valAccess: (resolved: string, display: string) => Promise<void>;
|
|
31
|
-
loadFileKindAndText: (path: string, opts?: LoadFileOptions) => Promise<LFile>;
|
|
32
|
-
readNormFile: (displayPath: string, cwd: string, opts?: ReadNormOptions) => Promise<NormFile>;
|
|
33
|
-
fmtReadPreview: (
|
|
34
|
-
normalized: string,
|
|
35
|
-
opts: {
|
|
36
|
-
offset?: number;
|
|
37
|
-
limit?: number;
|
|
38
|
-
sectionHeader?: (startLine: number, endLine: number, totalLines: number) => string;
|
|
39
|
-
windows?: Array<{ offset: number; limit: number }>;
|
|
40
|
-
},
|
|
41
|
-
fileHashes: string[],
|
|
42
|
-
absolutePath: string,
|
|
43
|
-
maxBytes: number,
|
|
44
|
-
maxLines: number,
|
|
45
|
-
) => Promise<{ text: string; truncation?: TruncationResult; served: ServedRow[] }>;
|
|
46
|
-
recordDiffServes: (input: {
|
|
47
|
-
sessionKey: string;
|
|
48
|
-
path: string;
|
|
49
|
-
servedRows: ServedRow[];
|
|
50
|
-
/** Committed `file_snapshots.snapshot_hash` of the content served; binds the leases granted. */
|
|
51
|
-
contentHash: string;
|
|
52
|
-
resultLineCount?: number;
|
|
53
|
-
firstChangedLine?: number;
|
|
54
|
-
lastChangedLine?: number;
|
|
55
|
-
}) => Promise<void>;
|
|
56
|
-
sessionKeyFor: (ctx?: { sessionManager?: { getSessionId(): string } }) => string;
|
|
57
|
-
finalizeToolResult: (details: EditDetails) => {
|
|
58
|
-
content: Array<{ type: string; text: string }>;
|
|
59
|
-
servedRows?: ServedRow[];
|
|
60
|
-
};
|
|
61
|
-
visLines: (s: string) => string[];
|
|
62
|
-
/** (ADR-0048 D2) re-run the terminal display transform on the exact raw head bytes. */
|
|
63
|
-
runDisplayTransform: (transform: DisplayTransform, input: string) => Promise<string | undefined>;
|
|
64
|
-
};
|
package/src/mutated-files.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mutated-file observer seam — the domain-neutral notification of which file this tool just
|
|
3
|
-
* changed, and which of its lines moved. Producers (edit, undo-last-edit, write) hand over the
|
|
4
|
-
* 1-indexed changed ranges; this module fans them out to registered observers.
|
|
5
|
-
*
|
|
6
|
-
* WHY a seam: the mutated set is known deep in the mutation paths, while the consumer is an
|
|
7
|
-
* optional outer integration that may be absent entirely (the mutation bridge). Inverting
|
|
8
|
-
* the dependency here keeps every producer free of integration imports, and with no observer
|
|
9
|
-
* registered the behavior of the tool is unchanged.
|
|
10
|
-
*
|
|
11
|
-
* Invariant: an empty `ranges` list means the WHOLE file changed (whole-file authorship, an undo
|
|
12
|
-
* that re-serves the file, a producer that knows no line detail) — it is never "nothing happened",
|
|
13
|
-
* so every notification is delivered. `src/served-spans.ts` makes the opposite choice for the same
|
|
14
|
-
* word: an empty `spans` list there means nothing was served and is dropped. The two payloads read
|
|
15
|
-
* alike but mean opposites, which is why the two seams stay separate modules.
|
|
16
|
-
*
|
|
17
|
-
* Invariant: no path handling lives here — `filePath` is the absolute normalized path the caller
|
|
18
|
-
* already holds. Ranges are 1-indexed and expected ascending, non-overlapping, non-adjacent.
|
|
19
|
-
*/
|
|
20
|
-
import type { ServedSpan } from "./served-spans.js";
|
|
21
|
-
|
|
22
|
-
/** One file this tool changed, and the lines it changed. */
|
|
23
|
-
export interface MutatedFileNotification {
|
|
24
|
-
/** Absolute normalized path supplied by the caller; never resolved or rewritten here. */
|
|
25
|
-
filePath: string;
|
|
26
|
-
/** `edit` is a partial change carrying `ranges`; `write` is whole-file authorship. */
|
|
27
|
-
kind: "edit" | "write";
|
|
28
|
-
/** 1-indexed changed ranges; EMPTY means the whole file changed. */
|
|
29
|
-
ranges: ServedSpan[];
|
|
30
|
-
/** Which tool produced the mutation, for consumers that attribute the write. */
|
|
31
|
-
sourceTool: "edit" | "undo_last_edit" | "write";
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export type MutatedFileObserver = (notification: MutatedFileNotification) => void;
|
|
35
|
-
|
|
36
|
-
let observers: MutatedFileObserver[] = [];
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Register an observer. The returned unsubscribe is idempotent and removes exactly this
|
|
40
|
-
* registration, so registering the same function twice yields two independent subscriptions.
|
|
41
|
-
*/
|
|
42
|
-
export function addMutatedFileObserver(observer: MutatedFileObserver): () => void {
|
|
43
|
-
observers.push(observer);
|
|
44
|
-
return () => {
|
|
45
|
-
const index = observers.indexOf(observer);
|
|
46
|
-
if (index >= 0) observers.splice(index, 1);
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Fan out to a snapshot of the observers, in registration order.
|
|
52
|
-
*
|
|
53
|
-
* WHY the two deliberate choices: every notification is delivered — including one whose `ranges`
|
|
54
|
-
* are empty, because empty means whole-file rather than nothing — and one throwing observer must
|
|
55
|
-
* not starve the others. That failure belongs to the observer, never to the tool call whose write
|
|
56
|
-
* already landed.
|
|
57
|
-
*/
|
|
58
|
-
export function notifyMutatedFile(notification: MutatedFileNotification): void {
|
|
59
|
-
// WHY: a snapshot keeps this pass stable — an observer that subscribes or unsubscribes during
|
|
60
|
-
// WHY: fan-out must not change the recipient set mid-iteration.
|
|
61
|
-
const snapshot = observers.slice();
|
|
62
|
-
for (const observer of snapshot) {
|
|
63
|
-
try {
|
|
64
|
-
observer(notification);
|
|
65
|
-
} catch {
|
|
66
|
-
// SAFETY: observer isolation — a broken integration sink must never fail the edit or write
|
|
67
|
-
// SAFETY: that already landed, nor silence the remaining observers.
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Test helper: drop every registration so observer state cannot leak between tests. */
|
|
73
|
-
export function clearMutatedFileObserversForTests(): void {
|
|
74
|
-
observers = [];
|
|
75
|
-
}
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SAFETY: MutationEngine — deep module behind the mutation seam.
|
|
3
|
-
*
|
|
4
|
-
* Small interface: `execute` + `preview`. Deep implementation: load → parse
|
|
5
|
-
* → mutate → finalize → drift → persist → serve hidden inside the pipeline.
|
|
6
|
-
* Internal seams (validate, verify, mutate, guard, persist, record) stay
|
|
7
|
-
* private — not exported. The interface is the test surface.
|
|
8
|
-
*
|
|
9
|
-
* Typed boundaries: validate once at admission (edit.ts via payload-contract),
|
|
10
|
-
* trust inside. Errors fail loud with typed `MutationFailure`.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { apply as pipelineApply, previewEdits as pipelinePreview } from "./pipeline.js";
|
|
14
|
-
import { genDiff } from "../edit-diff.js";
|
|
15
|
-
import { DIFF_PREVIEW_CONTEXT } from "../constants.js";
|
|
16
|
-
import type { PipelineOptions } from "./types.js";
|
|
17
|
-
import type { MutationResult } from "./types.js";
|
|
18
|
-
import type { NormalizedEditRequest } from "../payload-contract.js";
|
|
19
|
-
import { DomainError, badPayloadMessageOf, type DomainErrorCode } from "../domain-errors.js";
|
|
20
|
-
import { readEnvelope, type ErrorEnvelope } from "../error-envelope.js";
|
|
21
|
-
|
|
22
|
-
function failureFromEnvelope(args: {
|
|
23
|
-
code: DomainErrorCode;
|
|
24
|
-
message: string;
|
|
25
|
-
env: ErrorEnvelope;
|
|
26
|
-
payloadMessage?: string;
|
|
27
|
-
}): MutationResult {
|
|
28
|
-
const { code, message, env, payloadMessage } = args;
|
|
29
|
-
return {
|
|
30
|
-
ok: false,
|
|
31
|
-
code,
|
|
32
|
-
message,
|
|
33
|
-
...(payloadMessage !== undefined ? { payloadMessage } : {}),
|
|
34
|
-
...(env.servedRows !== undefined && env.servedRows.length > 0
|
|
35
|
-
? { servedRows: env.servedRows }
|
|
36
|
-
: {}),
|
|
37
|
-
...(env.servedBlock !== undefined ? { servedBlock: env.servedBlock } : {}),
|
|
38
|
-
...(env.cause !== undefined ? { cause: env.cause, details: { code, cause: env.cause } } : {}),
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function toFailure(error: unknown): MutationResult {
|
|
43
|
-
// WHY: registry errors carry their code, rows, block, and diagnosis as typed
|
|
44
|
-
// WHY: fields — the code is read, never scraped from the message, so a
|
|
45
|
-
// WHY: `[MODEL]`-only message can never surface as `code: "MODEL"`.
|
|
46
|
-
if (error instanceof DomainError) {
|
|
47
|
-
// WHY: a rendered refusal cannot be re-attributed at the tool seam.
|
|
48
|
-
// WHY: The RAW payload message travels beside it, undefined for every other code.
|
|
49
|
-
const payloadMessage = badPayloadMessageOf(error);
|
|
50
|
-
return failureFromEnvelope({
|
|
51
|
-
code: error.code,
|
|
52
|
-
message: error.message,
|
|
53
|
-
env: readEnvelope(error) ?? {},
|
|
54
|
-
...(payloadMessage !== undefined ? { payloadMessage } : {}),
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
58
|
-
// WHY: the batch-abort wrapper preserves the failing item's own code as a
|
|
59
|
-
// WHY: plain field — a registry member routes the typed path, while
|
|
60
|
-
// WHY: errno-style codes (ENOENT) and unexpected throws fall through to
|
|
61
|
-
// WHY: `E_UNKNOWN` instead of leaking a scraped token as the code. The
|
|
62
|
-
// WHY: envelope reader owns that validation: a non-registry code reads back
|
|
63
|
-
// WHY: as no code at all, which is exactly the fall-through condition.
|
|
64
|
-
const env = readEnvelope(error);
|
|
65
|
-
if (env !== undefined && env.code !== undefined) {
|
|
66
|
-
return failureFromEnvelope({ code: env.code, message, env });
|
|
67
|
-
}
|
|
68
|
-
// WHY: unexpected errors emit `E_UNKNOWN` through the registry: the first
|
|
69
|
-
// WHY: message line only, never the verbatim `String(error)` dump.
|
|
70
|
-
const unknown = new DomainError("E_UNKNOWN", {
|
|
71
|
-
errorName: error instanceof Error ? error.name : typeof error,
|
|
72
|
-
message,
|
|
73
|
-
});
|
|
74
|
-
return failureFromEnvelope({
|
|
75
|
-
code: unknown.code,
|
|
76
|
-
message: unknown.message,
|
|
77
|
-
env: readEnvelope(unknown) ?? {},
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* SAFETY: Execute a mutation against the file system (persist + undo + serve).
|
|
83
|
-
* Returns discriminated `MutationResult` — callers must switch on `ok`.
|
|
84
|
-
*
|
|
85
|
-
* No `any` threading: input is `NormalizedEditRequest` (validated at
|
|
86
|
-
* admission), output is typed. Failures are `ok:false` with `code`, not
|
|
87
|
-
* loose `isError` flags.
|
|
88
|
-
*/
|
|
89
|
-
export async function execute(
|
|
90
|
-
request: NormalizedEditRequest,
|
|
91
|
-
cwd: string,
|
|
92
|
-
options?: PipelineOptions,
|
|
93
|
-
): Promise<MutationResult> {
|
|
94
|
-
try {
|
|
95
|
-
const { result, diff, drift, metrics, raw, toolResult } = await pipelineApply(
|
|
96
|
-
request,
|
|
97
|
-
cwd,
|
|
98
|
-
options,
|
|
99
|
-
);
|
|
100
|
-
if (!metrics) throw new Error("missing metrics from pipeline — invariant violation");
|
|
101
|
-
return {
|
|
102
|
-
ok: true,
|
|
103
|
-
result,
|
|
104
|
-
diff,
|
|
105
|
-
drift,
|
|
106
|
-
metrics,
|
|
107
|
-
raw,
|
|
108
|
-
toolResult,
|
|
109
|
-
};
|
|
110
|
-
} catch (error) {
|
|
111
|
-
return toFailure(error);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* SAFETY: Preview a mutation without persisting (noPersist). Same seam as `execute`,
|
|
117
|
-
* same `MutationResult` — one interface, N call sites (preview + apply share
|
|
118
|
-
* the internal path via `runMutations` with `noPersist:true`).
|
|
119
|
-
*/
|
|
120
|
-
export async function preview(
|
|
121
|
-
request: NormalizedEditRequest,
|
|
122
|
-
cwd: string,
|
|
123
|
-
options?: Omit<PipelineOptions, "noPersist">,
|
|
124
|
-
): Promise<MutationResult> {
|
|
125
|
-
try {
|
|
126
|
-
// WHY: pipelinePreview does not persist and does not write undo — but still
|
|
127
|
-
// WHY: runs the full mutate→finalize→drift path.
|
|
128
|
-
const file = await pipelinePreview(request, cwd, options);
|
|
129
|
-
// WHY: #174 single-projection contract — the preview diff IS the `genDiff` projection,
|
|
130
|
-
// WHY: produced here at the same seam that returns execute's projected `diff`, with the
|
|
131
|
-
// WHY: preview pane's context (`DIFF_PREVIEW_CONTEXT`). The display path (`edit-tool
|
|
132
|
-
// WHY: preview` → preview-controller → edit-render) consumes this text and never
|
|
133
|
-
// WHY: re-projects; `file` already carries everything `genDiff` needs, so no side
|
|
134
|
-
// WHY: decision of an empty diff is synthesized here.
|
|
135
|
-
const diff = genDiff(
|
|
136
|
-
file.originalNormalized,
|
|
137
|
-
file.result,
|
|
138
|
-
DIFF_PREVIEW_CONTEXT,
|
|
139
|
-
file.resultHashes,
|
|
140
|
-
file.originalHashes,
|
|
141
|
-
).diff;
|
|
142
|
-
const metrics: import("../edit-response.js").RMetrics = {
|
|
143
|
-
classification: (file.appliedCount > 0 ? "applied" : "noop") as "applied" | "noop",
|
|
144
|
-
edits_attempted: file.appliedCount + file.noopCount,
|
|
145
|
-
edits_noop: file.noopCount,
|
|
146
|
-
warnings: file.warnings.length,
|
|
147
|
-
added_lines: file.totalAddedLines,
|
|
148
|
-
removed_lines: file.totalRemovedLines,
|
|
149
|
-
...(file.literalDeclarations > 0 ? { literalDeclarations: file.literalDeclarations } : {}),
|
|
150
|
-
};
|
|
151
|
-
const details: import("../edit-response.js").EditDetails = {
|
|
152
|
-
diff,
|
|
153
|
-
...(file.warnings.length > 0 ? { warnings: file.warnings } : {}),
|
|
154
|
-
...(file.driftNotice !== undefined ? { driftNotice: file.driftNotice } : {}),
|
|
155
|
-
metrics,
|
|
156
|
-
servedRows: [],
|
|
157
|
-
};
|
|
158
|
-
return {
|
|
159
|
-
ok: true,
|
|
160
|
-
result: file.result,
|
|
161
|
-
diff,
|
|
162
|
-
drift: file.driftNotice,
|
|
163
|
-
metrics,
|
|
164
|
-
raw: file,
|
|
165
|
-
toolResult: { content: [{ type: "text", text: diff }], details },
|
|
166
|
-
};
|
|
167
|
-
} catch (error) {
|
|
168
|
-
return toFailure(error);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// WHY: Re-export for callers that need the throw-based legacy path.
|
|
173
|
-
export { toFailure };
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SAFETY: MutationEngine — public interface for the deep mutation seam.
|
|
3
|
-
*
|
|
4
|
-
* One seam, small interface, deep implementation. Internal pipeline phases
|
|
5
|
-
* (load, parse, mutate, finalize, drift, persist, serve) stay private.
|
|
6
|
-
* Two adapters justify the seam: SQLiteSnapshotStore (prod) vs
|
|
7
|
-
* MemorySnapshotStore (tests) — local-substitutable.
|
|
8
|
-
*
|
|
9
|
-
* Callers cross this seam via `execute` / `preview` and switch on the
|
|
10
|
-
* discriminated `MutationResult` (`ok:true` vs `ok:false`). No `any`,
|
|
11
|
-
* no `isError` flag checks, no threading of `sessionKey`/`store` details.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export { isMutationSuccess, isMutationFailure } from "./types.js";
|
|
15
|
-
|
|
16
|
-
// WHY: Deep seam — small interface.
|
|
17
|
-
export { execute, preview } from "./engine.js";
|