dsh-hashline-edit 0.2.2 → 0.2.3

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.
Files changed (108) hide show
  1. package/README.md +57 -45
  2. package/cordis.patch.yml +3 -3
  3. package/lib/index.js +3175 -3943
  4. package/lib/types/dsh/contracts.d.ts +12 -3
  5. package/lib/types/dsh/fs.d.ts +3 -0
  6. package/lib/types/dsh/guidance.d.ts +5 -5
  7. package/lib/types/dsh/hide.d.ts +79 -0
  8. package/lib/types/dsh/host-compat.d.ts +7 -78
  9. package/lib/types/dsh/index.d.ts +21 -9
  10. package/lib/types/dsh/metrics/events.d.ts +1 -1
  11. package/lib/types/dsh/metrics/observer.d.ts +1 -1
  12. package/lib/types/dsh/sandbox.d.ts +2 -2
  13. package/lib/types/dsh/shell-hook.d.ts +1 -1
  14. package/lib/types/dsh/tools/apply-patch.d.ts +38 -0
  15. package/lib/types/dsh/tools/read.d.ts +3 -3
  16. package/lib/types/src/apply-patch/commit.d.ts +49 -0
  17. package/lib/types/src/apply-patch/grammar.d.ts +29 -0
  18. package/lib/types/src/apply-patch/lifecycle.d.ts +32 -0
  19. package/lib/types/src/apply-patch/plan.d.ts +50 -0
  20. package/lib/types/src/apply-patch/render.d.ts +51 -0
  21. package/lib/types/src/apply-patch/resolve.d.ts +129 -0
  22. package/lib/types/src/apply-patch/tool.d.ts +54 -0
  23. package/lib/types/src/apply-patch/types.d.ts +362 -0
  24. package/lib/types/src/domain-errors.d.ts +16 -2
  25. package/lib/types/src/edit-undo.d.ts +11 -2
  26. package/lib/types/src/file-content/index.d.ts +1 -1
  27. package/lib/types/src/file-content/preview.d.ts +1 -1
  28. package/lib/types/src/fs-lifecycle.d.ts +44 -0
  29. package/lib/types/src/hashline/alphabet.d.ts +4 -3
  30. package/lib/types/src/hashline/hash-identity.d.ts +12 -7
  31. package/lib/types/src/host-utils.d.ts +63 -0
  32. package/lib/types/src/mutation-engine/edit-request.d.ts +34 -0
  33. package/lib/types/src/mutation-engine/pipeline.d.ts +8 -1
  34. package/lib/types/src/mutation-engine/types.d.ts +40 -50
  35. package/lib/types/src/served-session/serve-render.d.ts +6 -0
  36. package/lib/types/src/undo-store.d.ts +17 -1
  37. package/package.json +18 -21
  38. package/prompts/apply-patch-guidelines.md +10 -0
  39. package/prompts/apply-patch.md +1 -0
  40. package/prompts/read-guidelines.md +4 -4
  41. package/prompts/read.md +1 -1
  42. package/prompts/undo-last-edit-guidelines.md +2 -2
  43. package/prompts/undo-last-edit-snippet.md +1 -1
  44. package/prompts/undo-last-edit.md +1 -1
  45. package/src/apply-patch/commit.ts +190 -0
  46. package/src/apply-patch/grammar.ts +620 -0
  47. package/src/apply-patch/index.ts +17 -0
  48. package/src/apply-patch/lifecycle.ts +195 -0
  49. package/src/apply-patch/plan.ts +800 -0
  50. package/src/apply-patch/render.ts +137 -0
  51. package/src/apply-patch/resolve.ts +470 -0
  52. package/src/apply-patch/tool.ts +257 -0
  53. package/src/apply-patch/types.ts +387 -0
  54. package/src/cut-repair.ts +77 -11
  55. package/src/domain-errors.ts +35 -3
  56. package/src/edit-undo.ts +379 -25
  57. package/src/file-content/index.ts +1 -1
  58. package/src/file-content/preview.ts +1 -1
  59. package/src/file-content/served-header.ts +1 -1
  60. package/src/fs-lifecycle.ts +201 -0
  61. package/src/hash-store.ts +18 -1
  62. package/src/hashline/alphabet.ts +7 -7
  63. package/src/hashline/hash-identity.ts +12 -7
  64. package/src/host-utils.ts +224 -0
  65. package/src/mutation-engine/edit-request.ts +39 -0
  66. package/src/mutation-engine/pipeline.ts +198 -27
  67. package/src/mutation-engine/types.ts +39 -57
  68. package/src/mutation-queue.ts +1 -1
  69. package/src/prompts.ts +3 -30
  70. package/src/served-session/serve-render.ts +2 -2
  71. package/src/undo-store.ts +74 -5
  72. package/lib/types/dsh/tools/edit.d.ts +0 -10
  73. package/lib/types/src/edit-tool.d.ts +0 -41
  74. package/lib/types/src/mutation-engine/engine.d.ts +0 -31
  75. package/lib/types/src/payload-contract.d.ts +0 -135
  76. package/prompts/edit-guidelines.md +0 -10
  77. package/prompts/edit-snippet.md +0 -1
  78. package/prompts/edit.md +0 -1
  79. package/src/bash-classifier.ts +0 -1626
  80. package/src/bash-conversion/decide.ts +0 -812
  81. package/src/bash-display-transform.ts +0 -50
  82. package/src/bash-multifile-config.ts +0 -239
  83. package/src/bash-view-config.ts +0 -158
  84. package/src/edit-normalize.ts +0 -8
  85. package/src/edit-render.ts +0 -161
  86. package/src/edit-tool.ts +0 -118
  87. package/src/edit.ts +0 -136
  88. package/src/integrations/pi-lens/command.ts +0 -712
  89. package/src/integrations/pi-lens/config.ts +0 -148
  90. package/src/integrations/pi-lens/io-bridge-adapter.ts +0 -234
  91. package/src/integrations/pi-lens/io-bridge.ts +0 -112
  92. package/src/integrations/pi-lens/settings-overlay.ts +0 -272
  93. package/src/lifecycle-hooks/index.ts +0 -1992
  94. package/src/lifecycle-hooks/types.ts +0 -64
  95. package/src/mutated-files.ts +0 -75
  96. package/src/mutation-engine/engine.ts +0 -239
  97. package/src/mutation-engine/index.ts +0 -17
  98. package/src/payload-contract.ts +0 -685
  99. package/src/preview-controller.ts +0 -84
  100. package/src/read.ts +0 -865
  101. package/src/search-hook.ts +0 -41
  102. package/src/store-config.ts +0 -73
  103. package/src/store-janitor-warning.ts +0 -169
  104. package/src/store-janitor.ts +0 -539
  105. package/src/store-kernel/settings.ts +0 -233
  106. package/src/store.ts +0 -154
  107. package/src/tui-presenter.ts +0 -134
  108. package/src/write-hook.ts +0 -130
@@ -0,0 +1,195 @@
1
+ import { splitLines } from "../utils.js";
2
+ import { lineHashes } from "../hashline/hash-identity.js";
3
+ import { snapshotIOFor } from "../snapshot-store";
4
+ import { loadHashStore, type HashStore } from "../hash-store.js";
5
+ import type { ProcessedEditFile, MemberLifecycle } from "../mutation-engine/types.js";
6
+ import type { FileBaseline, PatchPath, PlannedFile, PlannedMutation } from "./types.js";
7
+ import { applyPlannedMutations, mutationDelta } from "./plan.js";
8
+
9
+ /**
10
+ * apply_patch lifecycle materialization — the plan-to-engine adapter.
11
+ *
12
+ * The planner resolves every mutation against a pre-call baseline; this module turns that plan
13
+ * into the mutation engine's `ProcessedEditFile` member shape (plus the engine-local lifecycle
14
+ * action). It never writes: the correlated transaction in `mutation-engine/pipeline.ts` owns the
15
+ * one commit path. Pure text application (splice at baseline coordinates) is the only work here,
16
+ * and the resulting anchors are always derived under the member's COMMITTED path.
17
+ *
18
+ * @module dsh-hashline-edit/apply-patch/lifecycle
19
+ */
20
+
21
+ /** One materialized member: the plan facts plus the engine member the commit consumes. */
22
+ export interface MaterializedMember {
23
+ readonly planned: PlannedFile;
24
+ readonly member: ProcessedEditFile;
25
+ readonly status: "A" | "M" | "R" | "D";
26
+ /** The committed display path (destination for a move; the pre path otherwise). */
27
+ readonly committedPath: PatchPath;
28
+ /** The pre-transaction display path (move only). */
29
+ readonly fromPath?: PatchPath;
30
+ }
31
+
32
+ /** The union of baseline anchors whose lines this file's mutations retire. */
33
+ function removedHashesOf(
34
+ baseline: FileBaseline,
35
+ mutations: readonly PlannedMutation[],
36
+ ): Set<string> {
37
+ const removed = new Set<string>();
38
+ for (const mutation of mutations) {
39
+ if (mutation.range.startLine > mutation.range.endLine) continue;
40
+ for (let line = mutation.range.startLine; line <= mutation.range.endLine; line++) {
41
+ const hash = baseline.hashes[line - 1];
42
+ if (hash !== undefined) removed.add(hash);
43
+ }
44
+ }
45
+ return removed;
46
+ }
47
+
48
+ /** Sum the semantic line counts one materialized member reports (context lines excluded). */
49
+ function countMutationLines(
50
+ baselineLines: readonly string[],
51
+ mutations: readonly PlannedMutation[],
52
+ ): {
53
+ added: number;
54
+ removed: number;
55
+ } {
56
+ let added = 0;
57
+ let removed = 0;
58
+ for (const mutation of mutations) {
59
+ const delta = mutationDelta(baselineLines, mutation);
60
+ added += delta.added;
61
+ removed += delta.removed;
62
+ }
63
+ return { added, removed };
64
+ }
65
+
66
+ /** The engine lifecycle action for one planned file. */
67
+ function lifecycleOf(planned: PlannedFile): MemberLifecycle {
68
+ switch (planned.lifecycle.kind) {
69
+ case "keep":
70
+ return { kind: "keep" };
71
+ case "add":
72
+ return { kind: "add", createdDirs: [] };
73
+ case "delete":
74
+ return { kind: "delete" };
75
+ case "move":
76
+ return {
77
+ kind: "move",
78
+ fromAbsolutePath: planned.absolutePath,
79
+ toAbsolutePath: planned.lifecycle.toAbsolutePath,
80
+ createdDirs: [],
81
+ };
82
+ }
83
+ }
84
+
85
+ /** The absolute path a member commits to (a move commits at its destination). */
86
+ function committedAbsolutePath(planned: PlannedFile): string {
87
+ return planned.lifecycle.kind === "move"
88
+ ? planned.lifecycle.toAbsolutePath
89
+ : planned.absolutePath;
90
+ }
91
+
92
+ /** The display path a member commits to. */
93
+ function committedDisplayPath(planned: PlannedFile): PatchPath {
94
+ return planned.lifecycle.kind === "move" ? planned.lifecycle.to : planned.path;
95
+ }
96
+
97
+ /**
98
+ * Derive the member's result anchors under its COMMITTED path.
99
+ *
100
+ * Anchors are file-scoped (the path seeds the derivation), so a move must re-derive at the
101
+ * destination instead of carrying the source's anchors across. An in-place edit keeps the
102
+ * baseline's surviving anchors through the engine's prior-identity seam.
103
+ */
104
+ async function resultHashesFor(
105
+ planned: PlannedFile,
106
+ result: string,
107
+ store?: HashStore,
108
+ ): Promise<string[]> {
109
+ if (planned.lifecycle.kind === "delete") return [];
110
+ const resolvedStore = store ?? (await loadHashStore());
111
+ const path = committedAbsolutePath(planned);
112
+ const previous =
113
+ planned.lifecycle.kind === "keep"
114
+ ? {
115
+ content: planned.baseline.text,
116
+ hashes: [...planned.baseline.hashes],
117
+ removedHashes: removedHashesOf(planned.baseline, planned.mutations),
118
+ }
119
+ : undefined;
120
+ return lineHashes(result, path, previous, snapshotIOFor(resolvedStore), false);
121
+ }
122
+
123
+ /** The status letter one member reports in the success summary. */
124
+ function statusOf(planned: PlannedFile): "A" | "M" | "R" | "D" {
125
+ switch (planned.lifecycle.kind) {
126
+ case "add":
127
+ return "A";
128
+ case "delete":
129
+ return "D";
130
+ case "move":
131
+ return "R";
132
+ case "keep":
133
+ return "M";
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Materialize one planned file into the engine's member shape.
139
+ *
140
+ * The result text is produced by applying the plan's baseline-coordinate mutations; the anchors
141
+ * are then derived under the committed path. No file is read or written here — the plan already
142
+ * carries every baseline byte the commit needs.
143
+ */
144
+ export async function materializeMember(
145
+ planned: PlannedFile,
146
+ store?: HashStore,
147
+ ): Promise<MaterializedMember> {
148
+ const lifecycle = planned.lifecycle;
149
+ const isDelete = lifecycle.kind === "delete";
150
+ const isEmptyBaseline = planned.baseline.text === "" && planned.baseline.hashes.length === 0;
151
+ const baselineLines = isEmptyBaseline ? [] : splitLines(planned.baseline.text);
152
+ const resultLines = isDelete ? [] : applyPlannedMutations(baselineLines, planned.mutations);
153
+ const result = isDelete
154
+ ? ""
155
+ : isEmptyBaseline
156
+ ? resultLines.length === 0
157
+ ? ""
158
+ : resultLines.join("\n") + "\n"
159
+ : resultLines.join("\n") + (planned.baseline.text.endsWith("\n") ? "\n" : "");
160
+ const resultHashes = isDelete ? [] : await resultHashesFor(planned, result, store);
161
+ const { added, removed } = isDelete
162
+ ? { added: 0, removed: baselineLines.length }
163
+ : countMutationLines(baselineLines, planned.mutations);
164
+ const member: ProcessedEditFile = {
165
+ path: planned.path,
166
+ absolutePath: committedAbsolutePath(planned),
167
+ originalNormalized: lifecycle.kind === "add" ? "" : planned.baseline.text,
168
+ result,
169
+ bom: planned.baseline.bom,
170
+ originalEnding: planned.baseline.ending,
171
+ warnings: [],
172
+ originalHashes: [...planned.baseline.hashes],
173
+ resultHashes,
174
+ resultLineIds: [],
175
+ removedHashes: removedHashesOf(planned.baseline, planned.mutations),
176
+ appliedCount: 1,
177
+ noopCount: 0,
178
+ totalAddedLines: added,
179
+ totalRemovedLines: removed,
180
+ driftNotice: undefined,
181
+ range: { startLine: 1, endLine: 1, startHash: "", endHash: "", delta: 0 },
182
+ editedIntervals: [],
183
+ literalDeclarations: 0,
184
+ foreignCuts: [],
185
+ lifecycle: lifecycleOf(planned),
186
+ };
187
+ const fromPath = lifecycle.kind === "move" ? planned.path : undefined;
188
+ return {
189
+ planned,
190
+ member,
191
+ status: statusOf(planned),
192
+ committedPath: committedDisplayPath(planned),
193
+ ...(fromPath !== undefined ? { fromPath } : {}),
194
+ };
195
+ }