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
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Shared host contracts for the dsh adapter.
|
|
3
3
|
*
|
|
4
4
|
* The `dsh/` tree is the DeepSeek Harness host layer over the host-agnostic
|
|
5
|
-
* hashline core in `src/`. Every lane (host, read,
|
|
5
|
+
* hashline core in `src/`. Every lane (host, read, apply-patch, platform) compiles
|
|
6
6
|
* against this file; renaming or reshaping an export here is a cross-lane
|
|
7
7
|
* breaking change.
|
|
8
8
|
*
|
|
@@ -52,10 +52,11 @@ export interface FileStat {
|
|
|
52
52
|
*
|
|
53
53
|
* Paths crossing this interface are absolute and already validated by
|
|
54
54
|
* `dsh/fs.ts`: implementations may assume no null byte and no relative path.
|
|
55
|
-
* Reads return raw bytes so
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
55
|
+
* Reads return raw bytes so a byte-level refusal stays possible without a second
|
|
56
|
+
* decode step; callers that want text decode the bytes through
|
|
57
|
+
* `src/file-content/detection.ts`'s `decodeUtf8Strict` (the host's one admission:
|
|
58
|
+
* strict UTF-8, BOM stripped) or, for the anchor pipeline, through `decodeNormText`
|
|
59
|
+
* (which is node:fs-bound today and therefore takes a path, not this interface).
|
|
59
60
|
*/
|
|
60
61
|
export interface FileIO {
|
|
61
62
|
/** Read a whole regular file as raw bytes. */
|
|
@@ -66,6 +67,15 @@ export interface FileIO {
|
|
|
66
67
|
stat(path: string, signal?: AbortSignal): Promise<FileStat | undefined>;
|
|
67
68
|
/** Direct child names of a directory, sorted lexicographically. */
|
|
68
69
|
readdir(path: string, signal?: AbortSignal): Promise<string[]>;
|
|
70
|
+
/**
|
|
71
|
+
* Delete one regular file. A lifecycle delete targets a file; a directory at the same path is
|
|
72
|
+
* a caller bug that must surface (never a recursive removal).
|
|
73
|
+
*/
|
|
74
|
+
remove?(path: string, signal?: AbortSignal): Promise<void>;
|
|
75
|
+
/** Rename one regular file. The destination must not exist and its parent is created first. */
|
|
76
|
+
rename?(from: string, to: string, signal?: AbortSignal): Promise<void>;
|
|
77
|
+
/** Create one directory and missing parents. */
|
|
78
|
+
mkdir?(path: string, signal?: AbortSignal): Promise<void>;
|
|
69
79
|
}
|
|
70
80
|
/** The two sandbox-escalation arguments a mutating tool may carry. */
|
|
71
81
|
export interface SandboxArgs {
|
|
@@ -118,6 +128,54 @@ export interface SandboxController {
|
|
|
118
128
|
*/
|
|
119
129
|
mapError(error: unknown, decision: SandboxDecision): unknown;
|
|
120
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* The host observation channel one agent install publishes through.
|
|
133
|
+
*
|
|
134
|
+
* The host's observation policy fills its per-session state exclusively from
|
|
135
|
+
* `fs/observed`, and that state is what lets a built-in `write` replace an
|
|
136
|
+
* existing file. Shadowed `read`/`apply_patch` calls never touch the provider's own
|
|
137
|
+
* write path, so without this channel a file this plugin served stays
|
|
138
|
+
* "unobserved" and the built-in overwrite is refused forever.
|
|
139
|
+
*
|
|
140
|
+
* A mounted `ctx.fs` supplies the channel. Without one (`dsh/fs.ts`'s local
|
|
141
|
+
* `node:fs` fallback, and every test double that drives the tools directly)
|
|
142
|
+
* there is no channel at all: `FsTarget` and `FsVersion` are provider-owned
|
|
143
|
+
* values a consumer must never manufacture, so a local-only composition
|
|
144
|
+
* publishes nothing instead of publishing a fabricated identity.
|
|
145
|
+
*/
|
|
146
|
+
export interface FsObservationChannel {
|
|
147
|
+
/**
|
|
148
|
+
* Publish what a successful call observed or produced for one file.
|
|
149
|
+
*
|
|
150
|
+
* Reuses the version an in-flight `stat` already reported unless
|
|
151
|
+
* {@link FsObserveOptions.fresh} is set, which re-stats; a write must pass
|
|
152
|
+
* `fresh` because the pre-write version is stale by then. A target the
|
|
153
|
+
* provider confirms missing is published as `{ kind: "absent" }`.
|
|
154
|
+
*
|
|
155
|
+
* Never throws and never fails the tool call: a provider round-trip or
|
|
156
|
+
* listener failure is reported through the channel's diagnostic sink.
|
|
157
|
+
* At most one observation per call and file is published.
|
|
158
|
+
*/
|
|
159
|
+
publish(absolutePath: string, exec?: object, options?: FsObserveOptions): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Dispatch `fs/write-intent` for a file this plugin is about to write, so
|
|
162
|
+
* host listeners still see the change this plugin is making.
|
|
163
|
+
*
|
|
164
|
+
* The returned intent is deliberately not enforced: this plugin's mutations
|
|
165
|
+
* go straight to `node:fs`, so the provider's guarded-write semantics (which
|
|
166
|
+
* is where an intent is applied) do not run for them. A listener failure is
|
|
167
|
+
* reported and the write proceeds — this dispatch is bookkeeping, not a
|
|
168
|
+
* guard this plugin owns.
|
|
169
|
+
*/
|
|
170
|
+
announceWrite(absolutePath: string, exec?: object, signal?: AbortSignal): Promise<void>;
|
|
171
|
+
}
|
|
172
|
+
/** Knobs for one {@link FsObservationChannel.publish} call. */
|
|
173
|
+
export interface FsObserveOptions {
|
|
174
|
+
/** Re-stat through the provider instead of reusing the version this call already saw. */
|
|
175
|
+
readonly fresh?: boolean | undefined;
|
|
176
|
+
/** Caller cancellation, forwarded into the provider round-trip. */
|
|
177
|
+
readonly signal?: AbortSignal | undefined;
|
|
178
|
+
}
|
|
121
179
|
/** Host services one tool factory receives at agent-install time. */
|
|
122
180
|
export interface ToolDependencies {
|
|
123
181
|
/** Local filesystem seam; M1 is `dsh/fs.ts`'s node:fs implementation. */
|
|
@@ -126,6 +184,11 @@ export interface ToolDependencies {
|
|
|
126
184
|
readonly sandbox: SandboxController;
|
|
127
185
|
/** Read-only IO bridge; absent keeps the legacy node:fs read path. */
|
|
128
186
|
readonly coreIo?: CoreReadIo;
|
|
187
|
+
/**
|
|
188
|
+
* Host observation channel; absent without a mounted `ctx.fs`, where a
|
|
189
|
+
* provider-owned target and version cannot be manufactured.
|
|
190
|
+
*/
|
|
191
|
+
readonly observations?: FsObservationChannel;
|
|
129
192
|
/** Optional telemetry recorder; undefined keeps the tool path emission-free. */
|
|
130
193
|
readonly metrics?: ToolMetrics;
|
|
131
194
|
}
|
|
@@ -136,7 +199,7 @@ export interface ToolDependencies {
|
|
|
136
199
|
* factories at registration time. The fixed names are part of the lane
|
|
137
200
|
* contract:
|
|
138
201
|
* - `dsh/tools/read.ts` → `buildReadTool` (tool name `read`)
|
|
139
|
-
* - `dsh/tools/
|
|
202
|
+
* - `dsh/tools/apply-patch.ts` → `buildApplyPatchTool` (tool name `apply_patch`)
|
|
140
203
|
* - `dsh/tools/undo.ts` → `buildUndoTool` (tool name `undo_last_edit`)
|
|
141
204
|
*/
|
|
142
205
|
export type ToolDefinitionFactory = (deps: ToolDependencies) => ToolDefinition;
|
package/lib/types/dsh/fs.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { FileIO, FileStat } from "./contracts.js";
|
|
2
|
-
import {
|
|
1
|
+
import type { FileIO, FileStat, FsObservationChannel } from "./contracts.js";
|
|
2
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
import { type FileSystem, type FsTarget, type FsVersion } from "@deepseek-ai/dsh-fs";
|
|
3
4
|
import type { CoreReadIo } from "../src/io-port.js";
|
|
4
5
|
/** Stable codes for request-shape failures raised before any OS call. */
|
|
5
6
|
export type FileValidationCode = "E_PATH_EMPTY" | "E_PATH_NULL_BYTE" | "E_PATH_NOT_ABSOLUTE" | "E_ACCESS_MODE";
|
|
@@ -40,6 +41,9 @@ export declare class LocalFileIO implements FileIO {
|
|
|
40
41
|
write(path: string, data: Uint8Array | string, signal?: AbortSignal): Promise<void>;
|
|
41
42
|
stat(path: string, signal?: AbortSignal): Promise<FileStat | undefined>;
|
|
42
43
|
readdir(path: string, signal?: AbortSignal): Promise<string[]>;
|
|
44
|
+
remove(path: string, signal?: AbortSignal): Promise<void>;
|
|
45
|
+
rename(from: string, to: string, signal?: AbortSignal): Promise<void>;
|
|
46
|
+
mkdir(path: string, signal?: AbortSignal): Promise<void>;
|
|
43
47
|
}
|
|
44
48
|
/** Create the M1 local filesystem seam. */
|
|
45
49
|
export declare function createLocalFileIO(): FileIO;
|
|
@@ -48,6 +52,11 @@ export declare function createLocalFileIO(): FileIO;
|
|
|
48
52
|
* fallback when no `ctx.fs` service is mounted; it reads through `node:fs`.
|
|
49
53
|
*/
|
|
50
54
|
export declare function createCoreReadIo(io: FileIO): CoreReadIo;
|
|
55
|
+
/**
|
|
56
|
+
* One successful `stat` through the `ctx.fs` bridge: the target it settled on
|
|
57
|
+
* and the provider's opaque version token for it.
|
|
58
|
+
*/
|
|
59
|
+
export type CtxFsStatObserver = (target: FsTarget, version: FsVersion) => void;
|
|
51
60
|
/**
|
|
52
61
|
* Adapt a mounted `ctx.fs` provider to the core read port. Targets are cached
|
|
53
62
|
* by path and opaque `targetKey`; `resolve` returns the backend's absolute
|
|
@@ -56,5 +65,31 @@ export declare function createCoreReadIo(io: FileIO): CoreReadIo;
|
|
|
56
65
|
* path round-trip. `FsInfo.version` stays opaque and is deliberately not turned
|
|
57
66
|
* into a fake inode identity: ADR-0043 adoption is skipped for such targets and
|
|
58
67
|
* the read path falls back to content hashing.
|
|
68
|
+
* @param fs - the mounted provider.
|
|
69
|
+
* @param onStat - receives the target and provider version of every successful
|
|
70
|
+
* `stat`. `CoreFileStat` has no field for the version, so without this hook the
|
|
71
|
+
* freshness token the observation channel needs would be dropped.
|
|
72
|
+
* @returns the read port the core consumes.
|
|
73
|
+
*/
|
|
74
|
+
export declare function createCtxFsCoreReadIo(fs: FileSystem, onStat?: CtxFsStatObserver): CoreReadIo;
|
|
75
|
+
/** The read bridge plus the observation channel for one mounted `ctx.fs`. */
|
|
76
|
+
export interface CtxFsBridge {
|
|
77
|
+
/** The read port the core consumes. */
|
|
78
|
+
readonly io: CoreReadIo;
|
|
79
|
+
/** The channel that publishes `fs/observed` and dispatches `fs/write-intent`. */
|
|
80
|
+
readonly observations: FsObservationChannel;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Build the read bridge and the observation channel over one `ctx.fs` provider.
|
|
84
|
+
*
|
|
85
|
+
* Both share one resolved-target cache, and the bridge reports every `stat` it
|
|
86
|
+
* performs, so a successful read publishes the exact version it saw instead of
|
|
87
|
+
* paying for a second provider round-trip.
|
|
88
|
+
*
|
|
89
|
+
* @param ctx - the context that owns the observed tool calls. Publishing from
|
|
90
|
+
* the agent's own scope keeps a scope-filtered host listener on that agent.
|
|
91
|
+
* @param fs - the mounted provider.
|
|
92
|
+
* @param warn - host diagnostic sink for a publication that could not complete.
|
|
93
|
+
* @returns the bridge and its channel.
|
|
59
94
|
*/
|
|
60
|
-
export declare function
|
|
95
|
+
export declare function createCtxFsBridge(ctx: Context, fs: FileSystem, warn: (message: string) => void): CtxFsBridge;
|
|
@@ -26,20 +26,20 @@ export declare function parseSectionFile(content: string): ParsedSection;
|
|
|
26
26
|
export declare function isBlankOverride(content: string): boolean;
|
|
27
27
|
/** One overridable tool section. */
|
|
28
28
|
export interface GuidanceSection {
|
|
29
|
-
/** Registry section name, e.g. `tool:
|
|
29
|
+
/** Registry section name, e.g. `tool:apply_patch`. */
|
|
30
30
|
readonly name: string;
|
|
31
|
-
/** Override file name inside a preset directory, e.g. `
|
|
31
|
+
/** Override file name inside a preset directory, e.g. `apply-patch.md`. */
|
|
32
32
|
readonly file: string;
|
|
33
33
|
/** Order used when the harness registry names no slot for this section. */
|
|
34
34
|
readonly defaultOrder: number;
|
|
35
35
|
/** The `systemPrompt.getSectionOrder` slot this section shadows, when one exists. */
|
|
36
|
-
readonly orderName?: "TOOL_READ" | "TOOL_EDIT";
|
|
36
|
+
readonly orderName?: "TOOL_READ" | "TOOL_EDIT" | "TOOL_APPLY_PATCH";
|
|
37
37
|
/** The compiled default text. */
|
|
38
38
|
renderDefault(): string;
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
* The three sections, in default-order sequence.
|
|
42
|
-
*
|
|
41
|
+
* The three sections, in default-order sequence. Read and undo reuse the pi
|
|
42
|
+
* host's prompt sources; apply_patch owns the v4 mutation guidance.
|
|
43
43
|
*/
|
|
44
44
|
export declare const GUIDANCE_SECTIONS: readonly GuidanceSection[];
|
|
45
45
|
/** Render the compiled default text for one section. */
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hide the native edit-class tools so every precise text change goes through
|
|
3
|
+
* `apply_patch` — the one mutation entry point of the v4 surface.
|
|
4
|
+
*
|
|
5
|
+
* DSH 0.2.2-alpha.3 owns tool declarations in the tool registry, not in the
|
|
6
|
+
* `system-prompt/assemble` waterfall: the waterfall receives sections, contexts
|
|
7
|
+
* and variables only. The authoritative schema filter is therefore the
|
|
8
|
+
* per-agent registry restriction (`tools.restrict({ deny })`), which removes a
|
|
9
|
+
* global tool from both the native schema list and the PTC `tools:sdk` section
|
|
10
|
+
* because both are rendered from `tools.definitions(scope, toolSet)`.
|
|
11
|
+
*
|
|
12
|
+
* Three seams still back that up, because a restriction only governs the
|
|
13
|
+
* registry view and a stale session or a hand-rolled section could carry a
|
|
14
|
+
* residual binding:
|
|
15
|
+
*
|
|
16
|
+
* 1. `tools.restrict({ deny })` drops the hidden schemas for this agent;
|
|
17
|
+
* 2. `system-prompt/assemble` empties the `tool:edit` guidance section (its
|
|
18
|
+
* text is prose, never a tool mention) and deletes the hidden tools' member
|
|
19
|
+
* blocks from any rendered PTC `tools:sdk` section;
|
|
20
|
+
* 3. `tools.guard` is the monotonic execution backstop for a stale schema or
|
|
21
|
+
* any residual binding.
|
|
22
|
+
*
|
|
23
|
+
* `write` stays visible on purpose: whole-file replacement has no operation in
|
|
24
|
+
* `apply_patch` (`*** Add File:` refuses to overwrite), so hiding it would leave
|
|
25
|
+
* a rewrite with nowhere to go. Callers that want it gone can list it in
|
|
26
|
+
* `hiddenToolNames`.
|
|
27
|
+
*
|
|
28
|
+
* The layer is installed only when `apply_patch` actually registered: hiding
|
|
29
|
+
* the native editors while owning no replacement would leave the profile with
|
|
30
|
+
* no way to change a file.
|
|
31
|
+
*
|
|
32
|
+
* @module dsh-hashline-edit/hide
|
|
33
|
+
*/
|
|
34
|
+
/** A boolean config value, or a live getter (used when a host exposes volatile config). */
|
|
35
|
+
type BooleanSource = boolean | (() => boolean);
|
|
36
|
+
/** The hide-layer configuration after the plugin-level defaults are applied. */
|
|
37
|
+
export interface NativeHideConfig {
|
|
38
|
+
/** The registered replacement tool name, protected from `hiddenToolNames`. */
|
|
39
|
+
readonly toolName: string;
|
|
40
|
+
/** Hide `edit`/`str_replace_editor`; defaults to true. */
|
|
41
|
+
readonly hideNativeWriteTools?: BooleanSource;
|
|
42
|
+
/** Extra global tool names to hide alongside the native set. */
|
|
43
|
+
readonly hiddenToolNames?: readonly string[];
|
|
44
|
+
/** The Agent scope key used for the agent-view probe; absent keeps the global probe. */
|
|
45
|
+
readonly scope?: unknown;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Delete the hidden tools' member blocks from one rendered `tools:sdk` text.
|
|
49
|
+
*
|
|
50
|
+
* Structural, renderer-specific parsing — never a mention match:
|
|
51
|
+
* - TypeScript: a member starts at ` name: type` (2-space indent) inside
|
|
52
|
+
* `ToolArgsMap`/`ToolOutputMap`, may open braces on the same line, and ends
|
|
53
|
+
* at the first line that closes every opened brace and ends with `;`. Its
|
|
54
|
+
* optional single-line JSDoc comment directly above goes with it.
|
|
55
|
+
* - Python: a `Tools` protocol member starts at an indented `async def` line
|
|
56
|
+
* and spans until the next line at that member indent or shallower.
|
|
57
|
+
* @param text - the rendered SDK section text.
|
|
58
|
+
* @param hidden - the tool names to remove.
|
|
59
|
+
* @returns the text with every hidden member block removed.
|
|
60
|
+
*/
|
|
61
|
+
export declare function stripSdkMembers(text: string, hidden: ReadonlySet<string>): string;
|
|
62
|
+
interface LoggerLike {
|
|
63
|
+
warn?(message: string): void;
|
|
64
|
+
}
|
|
65
|
+
declare function warn(rootCtx: {
|
|
66
|
+
logger?: LoggerLike;
|
|
67
|
+
}, message: string): void;
|
|
68
|
+
/**
|
|
69
|
+
* Install the hide layer for one agent. Only call this after `apply_patch`
|
|
70
|
+
* registered successfully.
|
|
71
|
+
*
|
|
72
|
+
* @param rootCtx - the plugin/root scope, used for the global-name probe and warnings.
|
|
73
|
+
* @param agentCtx - the agent scope whose tool view is restricted.
|
|
74
|
+
* @param config - the resolved hide configuration.
|
|
75
|
+
* @returns the exact disposer; disposing lifts the restriction and every listener.
|
|
76
|
+
*/
|
|
77
|
+
export declare function registerNativeToolHiding(rootCtx: Parameters<typeof warn>[0], agentCtx: unknown, config: NativeHideConfig): () => void;
|
|
78
|
+
export {};
|
|
@@ -1,82 +1,11 @@
|
|
|
1
|
-
/** Retained line budget, matching pi's `DEFAULT_MAX_LINES`. */
|
|
2
|
-
export declare const DEFAULT_MAX_LINES = 2000;
|
|
3
|
-
/** Retained byte budget, matching pi's `DEFAULT_MAX_BYTES` (50KB). */
|
|
4
|
-
export declare const DEFAULT_MAX_BYTES: number;
|
|
5
|
-
/** The truncation report the core's read page renders. */
|
|
6
|
-
export interface TruncationResult {
|
|
7
|
-
/** The truncated content. */
|
|
8
|
-
content: string;
|
|
9
|
-
/** Whether truncation occurred. */
|
|
10
|
-
truncated: boolean;
|
|
11
|
-
/** Which limit was hit: `"lines"`, `"bytes"`, or `null` when nothing was cut. */
|
|
12
|
-
truncatedBy: "lines" | "bytes" | null;
|
|
13
|
-
/** Total number of lines in the original content. */
|
|
14
|
-
totalLines: number;
|
|
15
|
-
/** Total number of bytes in the original content. */
|
|
16
|
-
totalBytes: number;
|
|
17
|
-
/** Number of complete lines in the truncated output. */
|
|
18
|
-
outputLines: number;
|
|
19
|
-
/** Number of bytes in the truncated output. */
|
|
20
|
-
outputBytes: number;
|
|
21
|
-
/** Whether the last line was partially truncated (tail truncation only). */
|
|
22
|
-
lastLinePartial: boolean;
|
|
23
|
-
/** Whether the first line exceeded the byte limit (head truncation only). */
|
|
24
|
-
firstLineExceedsLimit: boolean;
|
|
25
|
-
/** The line limit that was applied. */
|
|
26
|
-
maxLines: number;
|
|
27
|
-
/** The byte limit that was applied. */
|
|
28
|
-
maxBytes: number;
|
|
29
|
-
}
|
|
30
|
-
/** The two independent limits a truncation call applies. */
|
|
31
|
-
export interface TruncationOptions {
|
|
32
|
-
/** Maximum number of lines; defaults to {@link DEFAULT_MAX_LINES}. */
|
|
33
|
-
maxLines?: number;
|
|
34
|
-
/** Maximum number of bytes; defaults to {@link DEFAULT_MAX_BYTES}. */
|
|
35
|
-
maxBytes?: number;
|
|
36
|
-
}
|
|
37
1
|
/**
|
|
38
|
-
*
|
|
2
|
+
* dsh host shim for the host-neutral utilities the core uses.
|
|
39
3
|
*
|
|
40
|
-
* WHY:
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*/
|
|
45
|
-
export interface ExtensionAPI {
|
|
46
|
-
/**
|
|
47
|
-
* Register one pi tool definition. The argument is intentionally structural and loose: the dsh
|
|
48
|
-
* program only needs the registration to compile, never to execute, and the loose `execute`
|
|
49
|
-
* signature keeps the pi adapter's untyped callback out of the dsh build's implicit-any checks.
|
|
50
|
-
*/
|
|
51
|
-
registerTool(definition: {
|
|
52
|
-
execute: (...args: any[]) => unknown;
|
|
53
|
-
[key: string]: unknown;
|
|
54
|
-
}): void;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Format bytes as a human-readable size (`512B`, `1.5KB`, `2.0MB`).
|
|
58
|
-
* @param bytes - the byte count to render.
|
|
59
|
-
* @returns the pi-compatible size label.
|
|
60
|
-
*/
|
|
61
|
-
export declare function formatSize(bytes: number): string;
|
|
62
|
-
/**
|
|
63
|
-
* Truncate content from the head (keep the first N lines / bytes).
|
|
4
|
+
* WHY: the dsh bundle must not ship the pi agent package. The core's utility
|
|
5
|
+
* surface lives in `src/host-utils.ts`; this module keeps the historical
|
|
6
|
+
* `dsh/host-compat` import path (and the `@earendil-works/pi-coding-agent`
|
|
7
|
+
* esbuild/tsconfig alias) working for the dsh build.
|
|
64
8
|
*
|
|
65
|
-
*
|
|
66
|
-
* implementation the rest of the contract was written against, so this is a
|
|
67
|
-
* faithful port including its two edge rules: complete lines only, and an
|
|
68
|
-
* over-long first line yields empty content with `firstLineExceedsLimit`.
|
|
69
|
-
* @param content - the text to truncate.
|
|
70
|
-
* @param options - the line and byte limits.
|
|
71
|
-
* @returns the truncation report.
|
|
72
|
-
*/
|
|
73
|
-
export declare function truncateHead(content: string, options?: TruncationOptions): TruncationResult;
|
|
74
|
-
/**
|
|
75
|
-
* Serialize file mutation operations that target the same file; different files still run
|
|
76
|
-
* in parallel. A faithful port of pi's queue so the core's cut transaction keeps its
|
|
77
|
-
* lock ordering guarantees under the dsh host.
|
|
78
|
-
* @param filePath - the file the mutation targets.
|
|
79
|
-
* @param run - the critical section to run once the path is free.
|
|
80
|
-
* @returns the critical section's result.
|
|
9
|
+
* @module dsh-hashline-edit/host-compat
|
|
81
10
|
*/
|
|
82
|
-
export
|
|
11
|
+
export * from "../src/host-utils.js";
|
package/lib/types/dsh/index.d.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dsh-hashline-edit host plugin entry.
|
|
3
3
|
*
|
|
4
|
-
* On every `agent/created`, install the
|
|
5
|
-
* own scope layer so they shadow the preset's built-in `read
|
|
4
|
+
* On every `agent/created`, install the hashline tools on the AGENT's
|
|
5
|
+
* own scope layer so they shadow the preset's built-in `read` for that
|
|
6
6
|
* agent (nearest layer wins in dsh's tool registry) and unwind automatically
|
|
7
7
|
* when the agent is disposed. The built-in `write` stays in place; the
|
|
8
8
|
* platform lane's write hook integrates with it.
|
|
9
9
|
*
|
|
10
|
-
* `inject` deliberately lists only `tools` and `systemPrompt`: M1 has no
|
|
11
10
|
* `inject` deliberately lists only `tools` and `systemPrompt`: the read-path
|
|
12
11
|
* `ctx.fs` bridge is optional and resolved with `ctx.get`, so a minimal
|
|
13
|
-
* composition still loads with the local `node:fs` fallback.
|
|
14
|
-
* local-only (the M5 bridge covers reads; M6 owns mutation).
|
|
12
|
+
* composition still loads with the local `node:fs` fallback. apply_patch and
|
|
13
|
+
* undo stay local-only (the M5 bridge covers reads; M6 owns mutation).
|
|
15
14
|
* @module dsh-hashline-edit
|
|
16
15
|
*/
|
|
17
16
|
import type { Context } from "@deepseek-ai/cordis";
|
|
@@ -24,6 +23,17 @@ export declare const name = "dsh-hashline-edit";
|
|
|
24
23
|
* services are resolved with `ctx.get` inside `dsh/sandbox.ts` instead.
|
|
25
24
|
*/
|
|
26
25
|
export declare const inject: string[];
|
|
26
|
+
/** The plugin configuration the loader passes as the second `apply` argument. */
|
|
27
|
+
export interface PluginConfig {
|
|
28
|
+
/**
|
|
29
|
+
* Hide the native `edit`/`str_replace_editor` tools so every precise text
|
|
30
|
+
* change goes through `apply_patch`. Defaults to true. `write` is not in
|
|
31
|
+
* that set on purpose: whole-file replacement has no apply_patch operation.
|
|
32
|
+
*/
|
|
33
|
+
hideNativeWriteTools?: boolean;
|
|
34
|
+
/** Extra global tool names to hide alongside the native write set. */
|
|
35
|
+
hiddenToolNames?: readonly string[];
|
|
36
|
+
}
|
|
27
37
|
/**
|
|
28
38
|
* Install the hashline toolset for one agent inside its own effect, so the
|
|
29
39
|
* registrations are disposed in reverse order when the agent scope unwinds.
|
|
@@ -31,6 +41,6 @@ export declare const inject: string[];
|
|
|
31
41
|
* Exported separately from {@link apply} so the host test can drive one fake
|
|
32
42
|
* agent directly and integration probes can reuse the exact install path.
|
|
33
43
|
*/
|
|
34
|
-
export declare function installAgentTools(rootCtx: Context, agent: Agent, metrics?: ToolMetrics): void;
|
|
44
|
+
export declare function installAgentTools(rootCtx: Context, agent: Agent, metrics?: ToolMetrics, config?: PluginConfig): void;
|
|
35
45
|
/** Mount the plugin: install the hashline toolset on every new agent. */
|
|
36
|
-
export declare function apply(rootCtx: Context): void;
|
|
46
|
+
export declare function apply(rootCtx: Context, config?: PluginConfig): void;
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Every tool name this telemetry can carry.
|
|
3
|
+
*
|
|
4
|
+
* The named members are the tools this plugin measures itself; the open member
|
|
5
|
+
* lets the global observer record any other host tool — the built-in `write`,
|
|
6
|
+
* `pwsh`, `grep`, … — without widening this union once per tool.
|
|
7
|
+
*/
|
|
8
|
+
type ToolName = "read" | "apply_patch" | "undo_last_edit" | "write" | "shell_view" | (string & {});
|
|
2
9
|
/** One tool call, as written to the JSONL file. Character counts are exact; the
|
|
3
10
|
* token estimate belongs to the summarizer so the ratio stays a reporting
|
|
4
11
|
* choice instead of being frozen into the event stream. */
|
|
@@ -1,19 +1,18 @@
|
|
|
1
|
+
import type { MetricSink, ToolMetric } from "./events.js";
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* The tools and the shell hook call {@link createToolMetrics} at their boundary
|
|
5
|
-
* with whatever counts they already hold; every extraction here is cheap
|
|
6
|
-
* (string lengths, array lengths, one JSON stringify of the request). The
|
|
7
|
-
* sink is optional: when no `DSH_HASHLINE_METRICS` file is configured the
|
|
8
|
-
* callers skip the timer and this module is never reached, so the tool path
|
|
9
|
-
* pays no allocation.
|
|
3
|
+
* The execution facts one measured call carries.
|
|
10
4
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
5
|
+
* Structural on purpose: a tool boundary hands over a `ToolRunContext` while the
|
|
6
|
+
* global observer sees the `tools/execute` view of the same call, and both expose
|
|
7
|
+
* the caller agent. Only the agent's id is read (the session key the event
|
|
8
|
+
* names), so neither caller has to manufacture a full `ToolExecution`.
|
|
14
9
|
*/
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
interface MetricExecution {
|
|
11
|
+
/** The agent on whose behalf the call ran. */
|
|
12
|
+
readonly agent?: {
|
|
13
|
+
readonly id?: unknown;
|
|
14
|
+
} | undefined;
|
|
15
|
+
}
|
|
17
16
|
/** One event's facts, as the tool boundary knows them. */
|
|
18
17
|
interface MetricRecord {
|
|
19
18
|
/** The metric tool key; `shell_view` is emitted only when the hook rewrites a result. */
|
|
@@ -23,7 +22,7 @@ interface MetricRecord {
|
|
|
23
22
|
/** Wall time of the tool call (or of the shell hook's rewrite). */
|
|
24
23
|
readonly durationMs: number;
|
|
25
24
|
/** The dsh execution; supplies the session id. */
|
|
26
|
-
readonly exec:
|
|
25
|
+
readonly exec: MetricExecution;
|
|
27
26
|
/** The accepted tool arguments, used for the exact request-payload character count. */
|
|
28
27
|
readonly args?: unknown;
|
|
29
28
|
/** Explicit request character count; when omitted, `JSON.stringify(args).length`. */
|
|
@@ -32,6 +31,11 @@ interface MetricRecord {
|
|
|
32
31
|
readonly charsOut: number;
|
|
33
32
|
/** The request path, when the call names one. */
|
|
34
33
|
readonly path?: string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Retry-chain discriminator for a call that names no path: a shell call's
|
|
36
|
+
* command, so re-running the same command is one chain.
|
|
37
|
+
*/
|
|
38
|
+
readonly chain?: string | undefined;
|
|
35
39
|
/** First `E_*`/`W_*` code on a refusal or a warning. */
|
|
36
40
|
readonly code?: string | undefined;
|
|
37
41
|
/** Final file line count, when the tool already computed it. */
|
|
@@ -45,6 +49,8 @@ interface MetricRecord {
|
|
|
45
49
|
export declare function pathOf(args: unknown): string | undefined;
|
|
46
50
|
/** The first `W_*` code among the supplied warning strings, if any. */
|
|
47
51
|
export declare function warningCodeOf(values: readonly (string | undefined)[]): string | undefined;
|
|
52
|
+
/** The first `E_*`/`W_*` code carried by a settled result's content blocks. */
|
|
53
|
+
export declare function resultCodeOf(result: unknown): string | undefined;
|
|
48
54
|
/** The registry code carried by a caught failure, if it carries one. */
|
|
49
55
|
export declare function errorCodeOf(error: unknown): string | undefined;
|
|
50
56
|
/** Exact text length of `{ content: [{text}], … }` tool envelopes (edit/undo). */
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global tool-call telemetry for the dsh host layer.
|
|
3
|
+
*
|
|
4
|
+
* Before this observer the adapter measured only its own surface: `read`,
|
|
5
|
+
* `apply_patch` and `undo_last_edit` from the tool boundaries, plus `shell_view` from
|
|
6
|
+
* the shell hook when it rewrites a result. Every other call the host
|
|
7
|
+
* dispatched — the built-in `write` that sits next to this plugin's shadowed
|
|
8
|
+
* tools, `pwsh`, `grep`, … — left no event at all, so no baseline could say
|
|
9
|
+
* what those calls cost or how often they were retried. This listener closes
|
|
10
|
+
* that hole with the tool's own name as the event's `tool`.
|
|
11
|
+
*
|
|
12
|
+
* It hangs off `tools/execute`, the host's around-dispatch waterfall (the one
|
|
13
|
+
* the host documents for metrics), on the agent's own scope, so a
|
|
14
|
+
* scope-filtered dispatch sends it that agent's calls only. It is installed
|
|
15
|
+
* only when a sink exists: the unmeasured composition pays no listener and no
|
|
16
|
+
* allocation.
|
|
17
|
+
*
|
|
18
|
+
* @module dsh-hashline-edit/metrics/observer
|
|
19
|
+
*/
|
|
20
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
21
|
+
import { type ToolMetrics } from "./instrument.js";
|
|
22
|
+
/**
|
|
23
|
+
* Install the global observer for one agent.
|
|
24
|
+
* @param agentCtx - the agent's scoped context; the listener sees only its calls.
|
|
25
|
+
* @param metrics - the shared recorder; `undefined` installs nothing at all.
|
|
26
|
+
* @returns the exact disposer that unregisters the listener.
|
|
27
|
+
*/
|
|
28
|
+
export declare function registerToolObserver(agentCtx: Context, metrics: ToolMetrics | undefined): () => void;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Mirrors the built-in `@deepseek-ai/dsh-tool-fs` controller (same
|
|
5
5
|
* vocabulary, same fail-closed approval sequence, shared
|
|
6
|
-
* `@deepseek-ai/dsh-sandbox` pieces) so `
|
|
6
|
+
* `@deepseek-ai/dsh-sandbox` pieces) so `apply_patch`/`undo_last_edit` ask for wider
|
|
7
7
|
* access exactly like the built-in `write`/`edit`. The differences are
|
|
8
8
|
* deliberate M1 facts:
|
|
9
9
|
*
|
|
@@ -21,7 +21,7 @@ import type { ToolExecution } from "@deepseek-ai/dsh-tools";
|
|
|
21
21
|
import type { SandboxMode } from "@deepseek-ai/dsh-sandbox";
|
|
22
22
|
import type { SandboxArgs, SandboxController, SandboxDecision } from "./contracts.js";
|
|
23
23
|
/**
|
|
24
|
-
* The filesystem escalation controller shared by `
|
|
24
|
+
* The filesystem escalation controller shared by `apply_patch` and `undo_last_edit`
|
|
25
25
|
* for one agent install.
|
|
26
26
|
*/
|
|
27
27
|
export declare class FsSandboxController implements SandboxController {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* foreground stdout channel, or a shell view that refuses (not whitelisted /
|
|
8
8
|
* ambiguous alignment) all pass the decision through untouched. Only a
|
|
9
9
|
* successful, uniquely aligned view is rewritten, and its rows are served
|
|
10
|
-
* through the read tool's seam so a following `
|
|
10
|
+
* through the read tool's seam so a following `apply_patch` hunk resolves the anchors.
|
|
11
11
|
*
|
|
12
12
|
* Both foreground value shapes the host may project are understood:
|
|
13
13
|
* `{ kind: "foreground", stdout: { text, truncated } }` (the canonical
|
|
@@ -19,13 +19,20 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import type { Context } from "@deepseek-ai/cordis";
|
|
21
21
|
import type { PostToolDecision, ToolExecution, ToolExecutionResult } from "@deepseek-ai/dsh-tools";
|
|
22
|
-
import type { ToolDependencies } from "./contracts.js";
|
|
22
|
+
import type { FsObservationChannel, ToolDependencies } from "./contracts.js";
|
|
23
23
|
import type { ToolMetrics } from "./metrics/instrument.js";
|
|
24
|
-
import { type ShellViewPlan, type ShellViewRequest } from "./shell-view.js";
|
|
24
|
+
import { type GrepViewPlan, type GrepViewRequest, type ShellViewPlan, type ShellViewRequest } from "./shell-view.js";
|
|
25
25
|
/** Host seams one shell hook needs; a product of `ctx`/`deps` at apply time. */
|
|
26
26
|
export interface ShellHookDeps {
|
|
27
27
|
/** Plan anchored rows for a whitelisted command; `undefined` means pass through. */
|
|
28
28
|
plan(request: ShellViewRequest): Promise<ShellViewPlan | undefined>;
|
|
29
|
+
/** Plan anchored rows for a built-in `grep` result; `undefined` means pass through. */
|
|
30
|
+
planGrep(request: GrepViewRequest): Promise<GrepViewPlan | undefined>;
|
|
31
|
+
/**
|
|
32
|
+
* Optional host observation channel: a granted view is a read of that file, so
|
|
33
|
+
* the host's read-before-write guard must see it.
|
|
34
|
+
*/
|
|
35
|
+
readonly observations?: FsObservationChannel;
|
|
29
36
|
/** Host diagnostic sink; the hook must never throw through this. */
|
|
30
37
|
warn(message: string): void;
|
|
31
38
|
/** Optional telemetry recorder; emits `shell_view` only when a result is rewritten. */
|
|
@@ -36,18 +43,20 @@ export interface ShellHooks {
|
|
|
36
43
|
postExecute(exec: ToolExecution, result: Readonly<ToolExecutionResult>, next: () => Promise<PostToolDecision>): Promise<PostToolDecision>;
|
|
37
44
|
}
|
|
38
45
|
/**
|
|
39
|
-
* Compose the shell
|
|
40
|
-
* the
|
|
46
|
+
* Compose the shell and built-in-grep hooks around one dependency set. Both listen on
|
|
47
|
+
* `tools/post-execute` and share the serve/lease seam; this single entry point keeps the
|
|
48
|
+
* registration one listener. The returned function is the test surface;
|
|
49
|
+
* {@link registerShellHook} is a thin `agentCtx.on` binding.
|
|
41
50
|
*/
|
|
42
51
|
export declare function createShellHooks(deps: ShellHookDeps): ShellHooks;
|
|
43
52
|
/** The production dependency set: the shell-view planner plus the host diagnostic sink. */
|
|
44
53
|
export declare function defaultShellHookDeps(deps: ToolDependencies, warn: (message: string) => void): ShellHookDeps;
|
|
45
54
|
/**
|
|
46
|
-
* Register the shell
|
|
55
|
+
* Register the shell and built-in-grep integrations for one agent on its own scope layer.
|
|
47
56
|
*
|
|
48
57
|
* @param rootCtx - host context, used only for diagnostics.
|
|
49
|
-
* @param agentCtx - the agent's scoped context; the listener sees only that agent's
|
|
50
|
-
* @param deps - the host seams the shell view
|
|
58
|
+
* @param agentCtx - the agent's scoped context; the listener sees only that agent's calls.
|
|
59
|
+
* @param deps - the host seams the shell view and the grep view plan and serve through.
|
|
51
60
|
* @returns the exact disposer that unregisters the listener.
|
|
52
61
|
*/
|
|
53
62
|
export declare function registerShellHook(rootCtx: Context, agentCtx: Context, deps: ToolDependencies): () => void;
|