pi-hashline-edit-pro 6.1.0 → 6.1.1
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 +6 -4
- package/index.ts +6 -1
- package/package.json +1 -1
- package/src/config-ui.ts +3 -2
- package/src/config.ts +7 -2
package/README.md
CHANGED
|
@@ -346,7 +346,7 @@ The setting lives in `/hashline-config` as Auto-read all and in `config.json` as
|
|
|
346
346
|
|
|
347
347
|
| Command | Description |
|
|
348
348
|
| --- | --- |
|
|
349
|
-
| `/hashline-config` | Open the settings window: auto-read anchors, auto-read all mode, ignore folders/files, disable on models, diff context lines, `anchor_grep` tool, copy/move tools, replace_match tool, required `path`, and strict input. Persists across sessions. |
|
|
349
|
+
| `/hashline-config` | Open the settings window: auto-read anchors, auto-read all mode, ignore folders/files, disable on models, disable read on models, diff context lines, `anchor_grep` tool, copy/move tools, replace_match tool, required `path`, and strict input. Persists across sessions. |
|
|
350
350
|
| `/clear-anchors` | Clear the session's anchor claims. Anchors are re-claimed on the next `read`. |
|
|
351
351
|
|
|
352
352
|
Settings live in `~/.config/pi-hashline-edit-pro/config.json`, created when a setting is first changed in `/hashline-config`:
|
|
@@ -362,7 +362,8 @@ Settings live in `~/.config/pi-hashline-edit-pro/config.json`, created when a se
|
|
|
362
362
|
"requirePath": false,
|
|
363
363
|
"strictInput": false,
|
|
364
364
|
"diffContextLines": 1,
|
|
365
|
-
"disableOnModels": []
|
|
365
|
+
"disableOnModels": [],
|
|
366
|
+
"disableReadOnModels": true
|
|
366
367
|
}
|
|
367
368
|
```
|
|
368
369
|
|
|
@@ -377,9 +378,10 @@ Settings live in `~/.config/pi-hashline-edit-pro/config.json`, created when a se
|
|
|
377
378
|
| `requirePath` | Require path | `false` | `replace`, `replace_match`, `insert`, `copy`, and `move` require a `path` argument that must match anchor ownership. |
|
|
378
379
|
| `strictInput` | Strict input | `false` | Reject auto-fixable slips (`[W_BAD_SHAPE]`, `[W_BAD_REF]`, `[W_INVALID_PATCH]`, `[W_BARE_HASH_PREFIX]`) with `[E_BAD_SHAPE]` instead of applying them with a warning. |
|
|
379
380
|
| `diffContextLines` | Diff context | `1` | Surrounding lines in post-edit diffs, 0-10 (needs Auto-read). |
|
|
380
|
-
| `disableOnModels` | Disable on models | `[]` | Model globs matched case-insensitively against `provider/id`, the bare `id`, and `api`, with `*` and `?` wildcards. A matching model gets no
|
|
381
|
+
| `disableOnModels` | Disable on models | `[]` | Model globs matched case-insensitively against `provider/id`, the bare `id`, and `api`, with `*` and `?` wildcards. A matching model gets no anchored edit tools, no auto-read, and no write-echo refusal; `read` is only removed while Disable read on models is on. |
|
|
382
|
+
| `disableReadOnModels` | Disable read on models | `true` | Also remove `read` from the active tools for a model matched by `disableOnModels`. Turn it off to keep `read` active on those models. |
|
|
381
383
|
|
|
382
|
-
`disableOnModels` turns off the whole anchored surface for the models you name, so another edit tool (`apply_patch`, a shell read) can own the session without competing instructions. A match removes `
|
|
384
|
+
`disableOnModels` turns off the whole anchored surface for the models you name, so another edit tool (`apply_patch`, a shell read) can own the session without competing instructions. A match removes `replace`, `replace_match`, `insert`, `copy`, `move`, `anchor_grep`, and `undo_last_change` from the active tools, and also `read` while Disable read on models is on (the default), restoring the built-in `grep` when it was active, and it also skips the auto-read-all injection, the auto-read block after `write`, the post-edit diff substitution, and the `write` hook that refuses a `write` echoing a served anchor. Because the extension's `read` replaces the built-in one, a matched model has no `read` at all unless another extension provides one, so turn Disable read on models off to keep the anchored `read` active on those models. The list is checked on `session_start`, on `model_select`, and again on `before_agent_start`, so a model change inside a session switches the surface immediately and another extension cannot re-add the tools mid-session. The default `[]` leaves every model unchanged.
|
|
383
385
|
|
|
384
386
|
When `PI_HASHLINE_DIR` is unset or empty, non-Windows platforms honor `XDG_CONFIG_HOME` when set (falling back to `~/.config`); on Windows the directory always uses `~/.config`, where `~` is `%USERPROFILE%`. To move the directory explicitly, see [Isolated state](#isolated-state).
|
|
385
387
|
|
package/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
toggleAnchorGrep,
|
|
26
26
|
toggleCopyMove,
|
|
27
27
|
toggleReplaceMatch,
|
|
28
|
+
toggleDisableReadOnModels,
|
|
28
29
|
toggleRequirePath,
|
|
29
30
|
toggleStrictInput,
|
|
30
31
|
adjustDiffContextLines,
|
|
@@ -61,6 +62,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
61
62
|
let autoReadAll: AutoReadAllMode = "off";
|
|
62
63
|
let autoReadAllIgnore: string[] = [];
|
|
63
64
|
let disableOnModels: string[] = [];
|
|
65
|
+
let disableReadOnModels = true;
|
|
64
66
|
let autoReadAllInjected = false;
|
|
65
67
|
let grepWasActive = false;
|
|
66
68
|
const baseAnchorTools = new Set<string>();
|
|
@@ -85,7 +87,8 @@ export default function (pi: ExtensionAPI): void {
|
|
|
85
87
|
async function syncModelGate(model: ModelLike | undefined): Promise<void> {
|
|
86
88
|
if (disableOnModels.length > 0 && modelDisabled(model, disableOnModels)) {
|
|
87
89
|
const active = pi.getActiveTools();
|
|
88
|
-
const
|
|
90
|
+
const gated = disableReadOnModels ? ANCHOR_TOOL_NAMES : ANCHOR_TOOL_NAMES.filter((tool) => tool !== "read");
|
|
91
|
+
const next = active.filter((tool) => !gated.includes(tool));
|
|
89
92
|
if (grepWasActive && !next.includes("grep")) next.push("grep");
|
|
90
93
|
pi.setActiveTools(next);
|
|
91
94
|
gateApplied = true;
|
|
@@ -133,6 +136,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
133
136
|
autoReadAll = config.autoReadAll ?? "off";
|
|
134
137
|
autoReadAllIgnore = config.autoReadAllIgnore ?? [];
|
|
135
138
|
disableOnModels = config.disableOnModels ?? [];
|
|
139
|
+
disableReadOnModels = config.disableReadOnModels !== false;
|
|
136
140
|
const sessionBranch = (ctx as { sessionManager?: { getBranch?: () => Array<{ type?: string; customType?: string }> } }).sessionManager?.getBranch?.() ?? [];
|
|
137
141
|
autoReadAllInjected = sessionBranch.some((entry) => entry.type === "custom_message" && entry.customType === AUTO_READ_ALL_CUSTOM_TYPE);
|
|
138
142
|
await refreshEditTools();
|
|
@@ -197,6 +201,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
197
201
|
else if (key === "autoReadAll") { autoReadAll = await cycleAutoReadAllMode(); autoReadAllInjected = false; }
|
|
198
202
|
else if (key === "autoReadAllIgnore") autoReadAllIgnore = await setAutoReadAllIgnoreFromText(value ?? "");
|
|
199
203
|
else if (key === "disableOnModels") disableOnModels = await setDisableOnModelsFromText(value ?? "");
|
|
204
|
+
else if (key === "disableReadOnModels") disableReadOnModels = await toggleDisableReadOnModels();
|
|
200
205
|
else if (key === "diffContextLines") await adjustDiffContextLines(delta ?? 1);
|
|
201
206
|
else if (key === "anchorGrepEnabled") {
|
|
202
207
|
const enabled = await toggleAnchorGrep();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-hashline-edit-pro",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Hash-anchored read/replace/insert/grep tools for pi-coding-agent. Every line gets a unique 4-char tokenizer-friendly anchor that stays stable across edits; stale or ambiguous anchors are rejected, never fuzzy-matched. Undo persists across restarts.",
|
|
6
6
|
"main": "index.ts",
|
package/src/config-ui.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Key, matchesKey, visibleWidth } from "@earendil-works/pi-tui";
|
|
|
2
2
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { readConfig, type Config } from "./config";
|
|
4
4
|
|
|
5
|
-
export type ConfigToggleKey = "autoRead" | "autoReadAll" | "autoReadAllIgnore" | "anchorGrepEnabled" | "copyMoveEnabled" | "replaceMatchEnabled" | "requirePath" | "strictInput" | "diffContextLines" | "disableOnModels";
|
|
5
|
+
export type ConfigToggleKey = "autoRead" | "autoReadAll" | "autoReadAllIgnore" | "anchorGrepEnabled" | "copyMoveEnabled" | "replaceMatchEnabled" | "requirePath" | "strictInput" | "diffContextLines" | "disableOnModels" | "disableReadOnModels";
|
|
6
6
|
|
|
7
7
|
export interface ConfigRow {
|
|
8
8
|
key: ConfigToggleKey;
|
|
@@ -27,7 +27,8 @@ export function configRows(config: Config): ConfigRow[] {
|
|
|
27
27
|
{ key: "requirePath", label: "Require path", hint: "replace, insert, copy, move need path (RPC visibility)", enabled: config.requirePath === true },
|
|
28
28
|
{ key: "strictInput", label: "Strict input", hint: "Reject auto-fixable slips instead of warnings", enabled: config.strictInput === true },
|
|
29
29
|
{ key: "replaceMatchEnabled", label: "Replace match", hint: "replace_match tool (off while disabled)", enabled: config.replaceMatchEnabled !== false },
|
|
30
|
-
{ key: "disableOnModels", label: "Disable on models", hint: "Model globs (provider/id, model id, or api) that turn off
|
|
30
|
+
{ key: "disableOnModels", label: "Disable on models", hint: "Model globs (provider/id, model id, or api) that turn off the anchored edit tools (comma-separated)", enabled: (config.disableOnModels ?? []).length > 0, entries: config.disableOnModels ?? [] },
|
|
31
|
+
{ key: "disableReadOnModels", label: "Disable read on models", hint: "Also turn off read for models matched by Disable on models (off keeps read active)", enabled: config.disableReadOnModels !== false },
|
|
31
32
|
];
|
|
32
33
|
}
|
|
33
34
|
|
package/src/config.ts
CHANGED
|
@@ -21,6 +21,7 @@ export interface Config {
|
|
|
21
21
|
strictInput?: boolean;
|
|
22
22
|
diffContextLines?: number;
|
|
23
23
|
disableOnModels?: string[];
|
|
24
|
+
disableReadOnModels?: boolean;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
const DEFAULT_CONFIG: Config = {
|
|
@@ -33,7 +34,8 @@ const DEFAULT_CONFIG: Config = {
|
|
|
33
34
|
requirePath: false,
|
|
34
35
|
strictInput: false,
|
|
35
36
|
diffContextLines: DEFAULT_DIFF_CONTEXT_LINES,
|
|
36
|
-
disableOnModels: []
|
|
37
|
+
disableOnModels: [],
|
|
38
|
+
disableReadOnModels: true,
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
function parseAutoReadAllMode(value: unknown): AutoReadAllMode {
|
|
@@ -94,6 +96,7 @@ function parseConfig(content: string): Config {
|
|
|
94
96
|
const diffContextLines = parsed.diffContextLines;
|
|
95
97
|
const autoReadAllIgnore = parsed.autoReadAllIgnore;
|
|
96
98
|
const disableOnModels = parsed.disableOnModels;
|
|
99
|
+
const disableReadOnModels = parsed.disableReadOnModels;
|
|
97
100
|
return {
|
|
98
101
|
autoRead: typeof autoRead === "boolean" ? autoRead : DEFAULT_CONFIG.autoRead,
|
|
99
102
|
anchorGrepEnabled: typeof anchorGrepEnabled === "boolean" ? anchorGrepEnabled : DEFAULT_CONFIG.anchorGrepEnabled,
|
|
@@ -105,6 +108,7 @@ function parseConfig(content: string): Config {
|
|
|
105
108
|
diffContextLines: normalizeDiffContextLines(diffContextLines),
|
|
106
109
|
autoReadAllIgnore: parseAutoReadAllIgnore(autoReadAllIgnore),
|
|
107
110
|
disableOnModels: parseDisableOnModels(disableOnModels),
|
|
111
|
+
disableReadOnModels: typeof disableReadOnModels === "boolean" ? disableReadOnModels : DEFAULT_CONFIG.disableReadOnModels,
|
|
108
112
|
};
|
|
109
113
|
}
|
|
110
114
|
|
|
@@ -212,7 +216,7 @@ export async function writeConfig(config: Config): Promise<void> {
|
|
|
212
216
|
}
|
|
213
217
|
|
|
214
218
|
|
|
215
|
-
type ToggleKey = "autoRead" | "anchorGrepEnabled" | "copyMoveEnabled" | "replaceMatchEnabled" | "requirePath" | "strictInput";
|
|
219
|
+
type ToggleKey = "autoRead" | "anchorGrepEnabled" | "copyMoveEnabled" | "replaceMatchEnabled" | "requirePath" | "strictInput" | "disableReadOnModels";
|
|
216
220
|
|
|
217
221
|
async function toggleFlag(key: ToggleKey): Promise<boolean> {
|
|
218
222
|
const config = await updateConfig((c) => { c[key] = !(c[key] === true); });
|
|
@@ -222,6 +226,7 @@ export const toggleAutoRead = (): Promise<boolean> => toggleFlag("autoRead");
|
|
|
222
226
|
export const toggleAnchorGrep = (): Promise<boolean> => toggleFlag("anchorGrepEnabled");
|
|
223
227
|
export const toggleCopyMove = (): Promise<boolean> => toggleFlag("copyMoveEnabled");
|
|
224
228
|
export const toggleReplaceMatch = (): Promise<boolean> => toggleFlag("replaceMatchEnabled");
|
|
229
|
+
export const toggleDisableReadOnModels = (): Promise<boolean> => toggleFlag("disableReadOnModels");
|
|
225
230
|
export async function cycleAutoReadAllMode(): Promise<AutoReadAllMode> {
|
|
226
231
|
let next: AutoReadAllMode = "off";
|
|
227
232
|
await updateConfig((c) => {
|