dsh-hashline-edit 0.2.2 → 0.3.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.
Files changed (118) hide show
  1. package/README.md +57 -45
  2. package/cordis.patch.yml +9 -3
  3. package/lib/client.js +231 -0
  4. package/lib/index.js +3298 -3957
  5. package/lib/types/dsh/contracts.d.ts +12 -3
  6. package/lib/types/dsh/fs.d.ts +3 -0
  7. package/lib/types/dsh/guidance.d.ts +12 -6
  8. package/lib/types/dsh/hide.d.ts +79 -0
  9. package/lib/types/dsh/host-compat.d.ts +7 -78
  10. package/lib/types/dsh/index.d.ts +53 -10
  11. package/lib/types/dsh/metrics/events.d.ts +1 -1
  12. package/lib/types/dsh/metrics/observer.d.ts +1 -1
  13. package/lib/types/dsh/sandbox.d.ts +2 -2
  14. package/lib/types/dsh/shell-hook.d.ts +1 -1
  15. package/lib/types/dsh/tools/apply-patch.d.ts +38 -0
  16. package/lib/types/dsh/tools/read.d.ts +3 -3
  17. package/lib/types/src/apply-patch/commit.d.ts +49 -0
  18. package/lib/types/src/apply-patch/grammar.d.ts +29 -0
  19. package/lib/types/src/apply-patch/lifecycle.d.ts +32 -0
  20. package/lib/types/src/apply-patch/plan.d.ts +50 -0
  21. package/lib/types/src/apply-patch/render.d.ts +51 -0
  22. package/lib/types/src/apply-patch/resolve.d.ts +129 -0
  23. package/lib/types/src/apply-patch/tool.d.ts +54 -0
  24. package/lib/types/src/apply-patch/types.d.ts +362 -0
  25. package/lib/types/src/domain-errors.d.ts +16 -2
  26. package/lib/types/src/edit-undo.d.ts +11 -2
  27. package/lib/types/src/file-content/index.d.ts +1 -1
  28. package/lib/types/src/file-content/preview.d.ts +1 -1
  29. package/lib/types/src/fs-lifecycle.d.ts +44 -0
  30. package/lib/types/src/hashline/alphabet.d.ts +4 -3
  31. package/lib/types/src/hashline/hash-identity.d.ts +12 -7
  32. package/lib/types/src/host-utils.d.ts +63 -0
  33. package/lib/types/src/mutation-engine/edit-request.d.ts +34 -0
  34. package/lib/types/src/mutation-engine/pipeline.d.ts +8 -1
  35. package/lib/types/src/mutation-engine/types.d.ts +40 -50
  36. package/lib/types/src/served-session/serve-render.d.ts +6 -0
  37. package/lib/types/src/undo-store.d.ts +17 -1
  38. package/package.json +37 -21
  39. package/prompts/apply-patch-guidelines.md +4 -0
  40. package/prompts/apply-patch.md +1 -0
  41. package/prompts/read-guidelines.md +6 -6
  42. package/prompts/read.md +1 -1
  43. package/prompts/undo-last-edit-guidelines.md +2 -2
  44. package/prompts/undo-last-edit-snippet.md +1 -1
  45. package/prompts/undo-last-edit.md +1 -1
  46. package/prompts/zh/apply-patch-guidelines.md +4 -0
  47. package/prompts/zh/apply-patch.md +1 -0
  48. package/prompts/zh/read-guidelines.md +6 -0
  49. package/prompts/zh/read-snippet.md +1 -0
  50. package/prompts/zh/read.md +1 -0
  51. package/prompts/zh/undo-last-edit-guidelines.md +2 -0
  52. package/prompts/zh/undo-last-edit-snippet.md +1 -0
  53. package/prompts/zh/undo-last-edit.md +1 -0
  54. package/src/apply-patch/commit.ts +190 -0
  55. package/src/apply-patch/grammar.ts +620 -0
  56. package/src/apply-patch/index.ts +17 -0
  57. package/src/apply-patch/lifecycle.ts +195 -0
  58. package/src/apply-patch/plan.ts +800 -0
  59. package/src/apply-patch/render.ts +137 -0
  60. package/src/apply-patch/resolve.ts +470 -0
  61. package/src/apply-patch/tool.ts +257 -0
  62. package/src/apply-patch/types.ts +387 -0
  63. package/src/cut-repair.ts +77 -11
  64. package/src/domain-errors.ts +35 -3
  65. package/src/edit-undo.ts +379 -25
  66. package/src/file-content/index.ts +1 -1
  67. package/src/file-content/preview.ts +1 -1
  68. package/src/file-content/served-header.ts +1 -1
  69. package/src/fs-lifecycle.ts +201 -0
  70. package/src/hash-store.ts +18 -1
  71. package/src/hashline/alphabet.ts +7 -7
  72. package/src/hashline/hash-identity.ts +12 -7
  73. package/src/host-utils.ts +224 -0
  74. package/src/mutation-engine/edit-request.ts +39 -0
  75. package/src/mutation-engine/pipeline.ts +198 -27
  76. package/src/mutation-engine/types.ts +39 -57
  77. package/src/mutation-queue.ts +1 -1
  78. package/src/prompts.ts +3 -30
  79. package/src/served-session/serve-render.ts +2 -2
  80. package/src/undo-store.ts +74 -5
  81. package/lib/types/dsh/tools/edit.d.ts +0 -10
  82. package/lib/types/src/edit-tool.d.ts +0 -41
  83. package/lib/types/src/mutation-engine/engine.d.ts +0 -31
  84. package/lib/types/src/payload-contract.d.ts +0 -135
  85. package/prompts/edit-guidelines.md +0 -10
  86. package/prompts/edit-snippet.md +0 -1
  87. package/prompts/edit.md +0 -1
  88. package/prompts/read-snippet.md +0 -1
  89. package/src/bash-classifier.ts +0 -1626
  90. package/src/bash-conversion/decide.ts +0 -812
  91. package/src/bash-display-transform.ts +0 -50
  92. package/src/bash-multifile-config.ts +0 -239
  93. package/src/bash-view-config.ts +0 -158
  94. package/src/edit-normalize.ts +0 -8
  95. package/src/edit-render.ts +0 -161
  96. package/src/edit-tool.ts +0 -118
  97. package/src/edit.ts +0 -136
  98. package/src/integrations/pi-lens/command.ts +0 -712
  99. package/src/integrations/pi-lens/config.ts +0 -148
  100. package/src/integrations/pi-lens/io-bridge-adapter.ts +0 -234
  101. package/src/integrations/pi-lens/io-bridge.ts +0 -112
  102. package/src/integrations/pi-lens/settings-overlay.ts +0 -272
  103. package/src/lifecycle-hooks/index.ts +0 -1992
  104. package/src/lifecycle-hooks/types.ts +0 -64
  105. package/src/mutated-files.ts +0 -75
  106. package/src/mutation-engine/engine.ts +0 -239
  107. package/src/mutation-engine/index.ts +0 -17
  108. package/src/payload-contract.ts +0 -685
  109. package/src/preview-controller.ts +0 -84
  110. package/src/read.ts +0 -865
  111. package/src/search-hook.ts +0 -41
  112. package/src/store-config.ts +0 -73
  113. package/src/store-janitor-warning.ts +0 -169
  114. package/src/store-janitor.ts +0 -539
  115. package/src/store-kernel/settings.ts +0 -233
  116. package/src/store.ts +0 -154
  117. package/src/tui-presenter.ts +0 -134
  118. package/src/write-hook.ts +0 -130
package/src/edit-tool.ts DELETED
@@ -1,118 +0,0 @@
1
- /** SAFETY: EditTool — deep module owning the edit Use Case seam.
2
- *
3
- * Graded surface: one narrow interface `EditTool { execute, preview }`
4
- * hides pipeline delegation, warnings/drift stitching.
5
- * Frameworks (pi TUI) never cross this seam — that lives in TuiPresenter.
6
- * Clean Architecture: Use Cases depend inward only (mutation-engine),
7
- * never outward to Frameworks.
8
- *
9
- * Typed boundaries: validate once at admission (payload-contract via normReq/assertReq),
10
- * trust inside. Immutable state: never mutates caller-owned request.
11
- */
12
-
13
- import { constants } from "node:fs";
14
- import { sessionKeyFor } from "./served-session/session.js";
15
- import { normReq, assertReq, type NormalizedEditRequest } from "./payload-contract.js";
16
- import { execute as engineExecute, preview as enginePreview } from "./mutation-engine/engine.js";
17
- import { isMutationSuccess } from "./mutation-engine/types.js";
18
- import { attachEnvelope } from "./error-envelope.js";
19
-
20
- type EditToolContext = {
21
- cwd: string;
22
- sessionManager?: { getSessionId(): string };
23
- };
24
-
25
- export type PreviewContext = {
26
- sessionManager?: { getSessionId(): string };
27
- };
28
-
29
- type PreviewResult = { diff: string } | { error: string };
30
-
31
- export interface EditTool {
32
- /** SAFETY: Execute a validated edit; returns pi tool_result or throws on failure. Admission: params validated by normReq/assertReq. */
33
- execute(
34
- params: unknown,
35
- signal: AbortSignal | undefined,
36
- ctx: EditToolContext,
37
- ): Promise<{
38
- content: Array<{ type: "text"; text: string }>;
39
- details: unknown;
40
- }>;
41
- /** SAFETY: Preview without persisting — mirrors pi's compPreview(request, cwd, ctx). The ctx must carry the session whose serves the anchors came from (#165). */
42
- preview(request: unknown, cwd: string, ctx: PreviewContext): Promise<PreviewResult>;
43
- }
44
-
45
- export function createEditTool(): EditTool {
46
- return {
47
- async execute(params, signal, ctx) {
48
- const canonical = normReq(params);
49
- assertReq(canonical);
50
- // SAFETY: ctx is untyped at pi boundary — cast validated by pi's runtime context shape (cwd + sessionManager)
51
- const sessionKey = sessionKeyFor(
52
- ctx as unknown as { sessionManager?: { getSessionId(): string } },
53
- );
54
- // SAFETY: canonical is validated NormalizedEditRequest after assertReq — trusted inside boundary
55
- const result = await engineExecute(canonical as NormalizedEditRequest, ctx.cwd, {
56
- accessMode: constants.R_OK | constants.W_OK,
57
- // SAFETY: signal is AbortSignal | undefined at pi boundary — runtime check via engine's abortIf
58
- ...(signal !== undefined ? { signal } : {}),
59
- sessionKey,
60
- });
61
- if (isMutationSuccess(result)) {
62
- // SAFETY: toolResult is validated by isMutationSuccess discriminated union guard
63
- return result.toolResult as {
64
- content: Array<{ type: "text"; text: string }>;
65
- details: unknown;
66
- };
67
- }
68
- // WHY: every range-family producer emits `details.cause` (user-facing diagnosis) —
69
- // WHY: carry it on the thrown error so callers catching the message still see the cause.
70
- // WHY: the whole failure envelope (code, diagnosis, rows, block) is stamped through the
71
- // WHY: envelope assembler (src/error-envelope.ts) — this seam never hand-copies fields.
72
- const failure = new Error(result.message);
73
- attachEnvelope(failure, {
74
- code: result.code,
75
- ...(result.cause !== undefined ? { cause: result.cause } : {}),
76
- // WHY: the raw payload message rides the envelope so the adapter can name the tool.
77
- // WHY: The rendered message alone cannot say which call raised the refusal.
78
- ...(result.payloadMessage !== undefined ? { payloadMessage: result.payloadMessage } : {}),
79
- servedRows: result.servedRows ?? [],
80
- servedBlock: result.servedBlock ?? "",
81
- });
82
- throw failure;
83
- },
84
- async preview(request, cwd, ctx) {
85
- try {
86
- const normalized = normReq(request);
87
- assertReq(normalized);
88
- // SAFETY: normalized is validated NormalizedEditRequest after assertReq
89
- // WHY: (#165) preview verifies against the SAME session the anchors were served to —
90
- // WHY: without a session, sessionKeyFor fails loud here instead of minting a key whose
91
- // WHY: lease lookups all miss as a misleading E_UNKNOWN_ANCHOR.
92
- const result = await enginePreview(normalized as NormalizedEditRequest, cwd, {
93
- accessMode: constants.R_OK,
94
- sessionKey: sessionKeyFor(ctx),
95
- });
96
- if (!isMutationSuccess(result)) {
97
- return { error: result.message };
98
- }
99
- const file = result.raw;
100
- // WHY: the call's own classification, not the primary file's bytes: a multi-file edit may
101
- // WHY: change another file while the primary stands still, and that IS a change to preview.
102
- if (result.metrics.classification === "noop") {
103
- return {
104
- error: `No changes made to ${file.path}. The edit produced identical content.`,
105
- };
106
- }
107
- return {
108
- // WHY: #174 single projection — the engine's `preview` seam already produced the
109
- // WHY: `genDiff` text with the pane's context; this display path renders it and
110
- // WHY: never re-projects.
111
- diff: result.diff,
112
- };
113
- } catch (error: unknown) {
114
- return { error: error instanceof Error ? error.message : String(error) };
115
- }
116
- },
117
- };
118
- }
package/src/edit.ts DELETED
@@ -1,136 +0,0 @@
1
- /** SAFETY: Edit tool — thin adapter over deep EditTool + TuiPresenter.
2
- *
3
- * Clean Architecture: this module is the Interface Adapter seam.
4
- * It owns the pi ToolDefinition wiring only; Use Case lives in EditTool,
5
- * Framework (pi TUI) lives in TuiPresenter.
6
- */
7
-
8
- import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
9
- import type { TSchema } from "typebox";
10
- import {
11
- prepareEditArguments,
12
- EDIT_DESCRIPTION,
13
- type NormalizedEditRequest,
14
- type EditItem,
15
- editToolSchema,
16
- editItemSchema,
17
- anchorFromSchema,
18
- anchorToSchema,
19
- editFileSchema,
20
- editModeSchema,
21
- assertReq,
22
- } from "./payload-contract.js";
23
- import { withPayloadSubject } from "./domain-errors.js";
24
- import { attributePayloadSubject } from "./error-envelope.js";
25
- import { createEditTool, type PreviewContext } from "./edit-tool.js";
26
- import { createTuiPresenter } from "./tui-presenter.js";
27
- import { loadP, loadGuide } from "./prompts.js";
28
- import type { EditDetails } from "./edit-response.js";
29
- import type { RPreview, RRState } from "./edit-render.js";
30
-
31
- void EDIT_DESCRIPTION;
32
- /** SAFETY: @deprecated Import from "./payload-contract.js" — single source per ADR-0007 */
33
- export { assertReq };
34
- /** SAFETY: @deprecated Import from "./payload-contract.js" — single source per ADR-0007. Re-exports retained for compatibility until next MAJOR. `replaceWithSchema` is REMOVED: the ticket-04 wire has no `replace_with` fold. */
35
- export {
36
- editToolSchema,
37
- editItemSchema,
38
- anchorFromSchema,
39
- anchorToSchema,
40
- editFileSchema,
41
- editModeSchema,
42
- };
43
- export { reuseText, reuseMarkdown } from "./tui-presenter.js";
44
-
45
- /** The wire item (ticket-04): exactly one payload — `text` or `text_ref` — plus optional `at`. */
46
- export type EditParams = EditItem;
47
-
48
- export type EditRequest = NormalizedEditRequest;
49
-
50
- export async function compPreview(
51
- request: unknown,
52
- cwd: string,
53
- ctx: PreviewContext,
54
- ): Promise<RPreview> {
55
- const tool = createEditTool();
56
- return tool.preview(request, cwd, ctx);
57
- }
58
-
59
- type ToolDef = ToolDefinition<TSchema, EditDetails, RRState> & {
60
- renderShell?: "default" | "self";
61
- };
62
-
63
- export function buildToolDef(
64
- getSessionManager?: () => { getSessionId(): string } | undefined,
65
- ): ToolDef {
66
- const E_DESC = loadP("../prompts/edit.md");
67
- const E_SNIPPET = loadP("../prompts/edit-snippet.md");
68
- const E_GUIDE = loadGuide("../prompts/edit-guidelines.md");
69
- const parameters = editToolSchema;
70
- const tool = createEditTool();
71
- const presenter = createTuiPresenter(
72
- // SAFETY: fire-time read is paired with the arm-time getSessionId below; DebouncedPreview
73
- // SAFETY: drops the compute if the serving session changed between arming and firing.
74
- (req, cwd) => {
75
- // SAFETY: the fire-time read stays inside the call so the ctx names the session serving anchors now.
76
- const sessionManager = getSessionManager?.();
77
- return tool.preview(req, cwd, sessionManager === undefined ? {} : { sessionManager });
78
- },
79
- () => getSessionManager?.()?.getSessionId(),
80
- );
81
- return {
82
- name: "edit",
83
- label: "Edit",
84
- description: E_DESC,
85
- parameters,
86
- promptSnippet: E_SNIPPET,
87
- promptGuidelines: E_GUIDE,
88
- // WHY: an admission refusal raised here carries no subject, so it must name the edit tool.
89
- // WHY: Without the stamp the model reads the neutral wording — the analyzer names no caller.
90
- prepareArguments: (args: unknown) => {
91
- try {
92
- return prepareEditArguments(args);
93
- } catch (error) {
94
- throw withPayloadSubject(error, "edit");
95
- }
96
- },
97
- renderShell: "default",
98
- // SAFETY: presenter owns TUI casts — asToolDef returns ToolDefinition-typed renders, edit.ts has zero direct TUI casts
99
- ...presenter.asToolDef(),
100
- async execute(_toolCallId, params, signal, _onUpdate, ctx) {
101
- // SAFETY: pi execute boundary is untyped — ctx narrowed via sessionKeyFor, signal is AbortSignal validated by engine
102
- try {
103
- const res = await tool.execute(
104
- params,
105
- signal as AbortSignal | undefined,
106
- // SAFETY: ctx is untyped at the pi boundary — cast validated by pi's runtime shape
107
- ctx as unknown as {
108
- cwd: string;
109
- sessionManager?: { getSessionId(): string };
110
- },
111
- );
112
- // SAFETY: res is validated tool result after tool.execute — cast to pi ToolDef return type for registration
113
- return res as unknown as ReturnType<ToolDef["execute"]> extends Promise<infer R>
114
- ? R
115
- : never;
116
- } catch (error) {
117
- throw attributePayloadSubject(error, "edit");
118
- }
119
- },
120
- };
121
- }
122
-
123
- export function regEdit(pi: ExtensionAPI): void {
124
- // WHY: (#165) pi's ToolRenderContext carries no session, so the preview pane's session is
125
- // WHY: captured from the session_start ctx — the same session reads serve anchors to.
126
- // WHY: session_start fires for startup/reload/new/resume/fork, so the capture tracks switches.
127
- // WHY: (#168-class) tracking a switch is only safe if the *pending* compute re-checks it:
128
- // WHY: buildToolDef below exposes getSessionId so DebouncedPreview binds the serving session
129
- // WHY: at arm time and drops (cancels) a compute whose session changed before the timer fires,
130
- // WHY: instead of verifying anchors against a session that never served them.
131
- let sessionManager: { getSessionId(): string } | undefined;
132
- pi.on("session_start", (_event, ctx) => {
133
- sessionManager = ctx.sessionManager;
134
- });
135
- pi.registerTool(buildToolDef(() => sessionManager));
136
- }