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,190 @@
1
+ /**
2
+ * apply_patch v4 — commit seam.
3
+ *
4
+ * Commits a `PatchPlan` as ONE correlated transaction through the existing hashline machinery:
5
+ *
6
+ * - pre-mirror every written member (durable pre-images),
7
+ * - one undo row per member carrying the shared transaction id,
8
+ * - the durable intent record,
9
+ * - deterministic member order (primary first), lifecycle actions included,
10
+ * - best-effort rollback of every member on failure,
11
+ * - the per-file store commit and the new-anchor served rows.
12
+ *
13
+ * This module is deliberately thin: it maps `PlannedFile` onto the engine's
14
+ * `ProcessedEditFile`/`commitTransaction` skeleton and never re-implements hashing, leasing,
15
+ * snapshots or undo storage.
16
+ *
17
+ * @module dsh-hashline-edit/apply-patch/commit
18
+ */
19
+ import { SERVED_ROWS_CAP } from "../constants.js";
20
+ import { DomainError } from "../domain-errors.js";
21
+ import { genDiff } from "../edit-diff.js";
22
+ import type { HashStore } from "../hash-store.js";
23
+ import { commitTransaction } from "../mutation-engine/pipeline.js";
24
+ import type { ProcessedEditFile, TransactionRecoveryReport } from "../mutation-engine/types.js";
25
+ import { fmtServedRows, paginationHint } from "../served-session/serve-render.js";
26
+ import { visLines } from "../utils.js";
27
+ import { materializeMember, type MaterializedMember } from "./lifecycle.js";
28
+ import type { ApplyPatchFailure, PatchProblem, PatchPlan, ServedFileBlock } from "./types.js";
29
+
30
+ /** Options for {@link commitPlan}. */
31
+ export interface CommitPlanOptions {
32
+ readonly cwd: string;
33
+ readonly sessionKey: string;
34
+ readonly signal?: AbortSignal;
35
+ readonly store?: HashStore;
36
+ /** POSIX access-mode bitmask; defaults to read+write. */
37
+ readonly accessMode?: number;
38
+ /** TEST-ONLY: fires before the first rename, while the pre-images/undo rows are durable. */
39
+ readonly onBeforeFirstWrite?: () => void | Promise<void>;
40
+ /** TEST-ONLY: fires between two member renames, after the earlier one is durable. */
41
+ readonly onBetweenWrites?: (committedAbsolutePath: string) => void | Promise<void>;
42
+ /** TEST-ONLY: fires after a move rename and before the destination rewrite (mid-member failure). */
43
+ readonly onAfterMoveRename?: (toAbsolutePath: string) => void | Promise<void>;
44
+ }
45
+
46
+ /** One committed file's lifecycle status and line accounting. */
47
+ export interface CommittedFile {
48
+ readonly path: string;
49
+ readonly status: "A" | "M" | "R" | "D";
50
+ /** Original path for a rename (`R` only). */
51
+ readonly fromPath?: string;
52
+ readonly addedLines: number;
53
+ readonly removedLines: number;
54
+ /** New anchors for the changed lines; absent when the member wrote no content. */
55
+ readonly served?: ServedFileBlock;
56
+ }
57
+
58
+ /** Commit outcome: the per-file facts on success, the whole failure on rejection. */
59
+ export type CommitPlanResult =
60
+ | {
61
+ readonly ok: true;
62
+ readonly files: readonly CommittedFile[];
63
+ readonly diff: string;
64
+ readonly warnings: readonly string[];
65
+ }
66
+ | { readonly ok: false; readonly failure: ApplyPatchFailure };
67
+
68
+ /** Build the served block one committed member owes the model: only its actually changed lines. */
69
+ function servedBlockFor(member: ProcessedEditFile, path: string): ServedFileBlock | undefined {
70
+ if (member.resultHashes.length === 0) return undefined;
71
+ // WHY: a success result returns anchors for the changed lines only (§7); the whole-file projection
72
+ // WHY: made a one-line edit dump every unchanged line back at the model.
73
+ const diff = genDiff(
74
+ member.originalNormalized,
75
+ member.result,
76
+ 0,
77
+ member.resultHashes,
78
+ member.originalHashes,
79
+ );
80
+ let rows = diff.servedRows;
81
+ if (rows.length === 0) return undefined;
82
+ let text: string;
83
+ if (rows.length > SERVED_ROWS_CAP) {
84
+ const next = rows[SERVED_ROWS_CAP]!;
85
+ text =
86
+ fmtServedRows(rows.slice(0, SERVED_ROWS_CAP), visLines(member.result)) +
87
+ "\n" +
88
+ paginationHint(next.position + 1, rows.length - SERVED_ROWS_CAP);
89
+ rows = rows.slice(0, SERVED_ROWS_CAP);
90
+ } else {
91
+ text = fmtServedRows(rows, visLines(member.result));
92
+ }
93
+ return { path, rows, text };
94
+ }
95
+
96
+ /** Map a commit-stage thrown value onto the apply-patch failure shape. */
97
+ function failureOf(
98
+ error: unknown,
99
+ plan: PatchPlan,
100
+ recovery: TransactionRecoveryReport | undefined,
101
+ ): ApplyPatchFailure {
102
+ const code = error instanceof DomainError ? error.code : "E_UNKNOWN";
103
+ const baseMessage = error instanceof Error ? error.message : String(error);
104
+ const patchLine = plan.files[0]?.mutations[0]?.patchLine ?? 1;
105
+ const recoveryText =
106
+ recovery === undefined
107
+ ? ""
108
+ : "\nRecovery: restored [" +
109
+ recovery.restored.join(", ") +
110
+ "], remaining [" +
111
+ recovery.remaining.join(", ") +
112
+ "], uncertain [" +
113
+ recovery.uncertain.join(", ") +
114
+ "].";
115
+ const problem: PatchProblem = { code, patchLine, message: baseMessage + recoveryText };
116
+ return {
117
+ ok: false,
118
+ code,
119
+ message: "apply_patch commit failed: " + baseMessage + recoveryText,
120
+ problems: [problem],
121
+ served: [],
122
+ changedNothing: recovery === undefined || recovery.remaining.length === 0,
123
+ ...(recovery !== undefined ? { recovery } : {}),
124
+ };
125
+ }
126
+
127
+ /**
128
+ * Commit one plan atomically (one correlated transaction, one undo record set).
129
+ *
130
+ * The implementation reuses `commitTransaction` — the existing correlated skeleton — and extends
131
+ * its member shape with the plan's lifecycle action; the undo schema gains the matching action.
132
+ *
133
+ * @param plan - the fully resolved plan.
134
+ * @param options - cwd/session/store, cancellation and the test fault seams.
135
+ * @returns the committed facts, or a failure whose `changedNothing` reflects the rollback.
136
+ */
137
+ export async function commitPlan(
138
+ plan: PatchPlan,
139
+ options: CommitPlanOptions,
140
+ ): Promise<CommitPlanResult> {
141
+ const entries: MaterializedMember[] = [];
142
+ for (const planned of plan.files) {
143
+ if (planned.writes) entries.push(await materializeMember(planned, options.store));
144
+ }
145
+ if (entries.length === 0) return { ok: true, files: [], diff: "", warnings: [] };
146
+ const members = entries.map((entry) => entry.member);
147
+ try {
148
+ const outcome = await commitTransaction(
149
+ members,
150
+ members,
151
+ {
152
+ sessionKey: options.sessionKey,
153
+ workspaceRoot: options.cwd,
154
+ ...(options.signal !== undefined ? { signal: options.signal } : {}),
155
+ ...(options.store !== undefined ? { store: options.store } : {}),
156
+ ...(options.accessMode !== undefined ? { accessMode: options.accessMode } : {}),
157
+ ...(options.onBeforeFirstWrite !== undefined
158
+ ? { onBeforeFirstCutWrite: options.onBeforeFirstWrite }
159
+ : {}),
160
+ ...(options.onBetweenWrites !== undefined
161
+ ? { onCutBetweenWrites: options.onBetweenWrites }
162
+ : {}),
163
+ ...(options.onAfterMoveRename !== undefined
164
+ ? { onAfterMoveRename: options.onAfterMoveRename }
165
+ : {}),
166
+ },
167
+ options.sessionKey,
168
+ );
169
+ const files: CommittedFile[] = entries.map((entry) => {
170
+ const served = servedBlockFor(entry.member, entry.committedPath);
171
+ return {
172
+ path: entry.committedPath,
173
+ status: entry.status,
174
+ ...(entry.fromPath !== undefined ? { fromPath: entry.fromPath } : {}),
175
+ addedLines: entry.member.totalAddedLines,
176
+ removedLines: entry.member.totalRemovedLines,
177
+ ...(served !== undefined ? { served } : {}),
178
+ };
179
+ });
180
+ return {
181
+ ok: true,
182
+ files,
183
+ diff: outcome.toolResult.details.diff ?? "",
184
+ warnings: outcome.toolResult.details.warnings ?? [],
185
+ };
186
+ } catch (error) {
187
+ const recovery = (error as Error & { recovery?: TransactionRecoveryReport }).recovery;
188
+ return { ok: false, failure: failureOf(error, plan, recovery) };
189
+ }
190
+ }