opencode-hashline 1.0.0 → 1.0.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/dist/index.cjs +20 -19
- package/dist/index.js +20 -19
- package/package.json +5 -3
package/dist/index.cjs
CHANGED
|
@@ -631,26 +631,27 @@ init_hashline();
|
|
|
631
631
|
// src/hashline-tool.ts
|
|
632
632
|
var import_fs2 = require("fs");
|
|
633
633
|
var import_path2 = require("path");
|
|
634
|
-
var
|
|
634
|
+
var import_zod = require("zod");
|
|
635
635
|
init_hashline();
|
|
636
636
|
function createHashlineEditTool(config, cache) {
|
|
637
|
-
return
|
|
637
|
+
return {
|
|
638
638
|
description: "Edit files using hashline references. Resolves refs like 5:a3f or '#HL 5:a3f|...' and applies replace/delete/insert without old_string matching.",
|
|
639
639
|
args: {
|
|
640
|
-
path:
|
|
641
|
-
operation:
|
|
642
|
-
startRef:
|
|
643
|
-
endRef:
|
|
644
|
-
replacement:
|
|
640
|
+
path: import_zod.z.string().describe("Path to the file (absolute or relative to project directory)"),
|
|
641
|
+
operation: import_zod.z.enum(["replace", "delete", "insert_before", "insert_after"]).describe("Edit operation"),
|
|
642
|
+
startRef: import_zod.z.string().describe('Start hash reference, e.g. "5:a3f" or "#HL 5:a3f|const x = 1;"'),
|
|
643
|
+
endRef: import_zod.z.string().optional().describe("End hash reference for range operations. Defaults to startRef when omitted."),
|
|
644
|
+
replacement: import_zod.z.string().optional().describe("Replacement/inserted content. Required for replace/insert operations.")
|
|
645
645
|
},
|
|
646
646
|
async execute(args, context) {
|
|
647
|
-
const
|
|
647
|
+
const { path, operation, startRef, endRef, replacement } = args;
|
|
648
|
+
const absPath = (0, import_path2.isAbsolute)(path) ? path : (0, import_path2.resolve)(context.directory, path);
|
|
648
649
|
const normalizedAbs = (0, import_path2.resolve)(absPath);
|
|
649
650
|
const normalizedWorktree = (0, import_path2.resolve)(context.worktree);
|
|
650
651
|
if (normalizedAbs !== normalizedWorktree && !normalizedAbs.startsWith(normalizedWorktree + import_path2.sep)) {
|
|
651
|
-
throw new Error(`Access denied: "${
|
|
652
|
+
throw new Error(`Access denied: "${path}" resolves outside the project directory`);
|
|
652
653
|
}
|
|
653
|
-
const displayPath = (0, import_path2.relative)(context.worktree, absPath) ||
|
|
654
|
+
const displayPath = (0, import_path2.relative)(context.worktree, absPath) || path;
|
|
654
655
|
let current;
|
|
655
656
|
try {
|
|
656
657
|
current = (0, import_fs2.readFileSync)(absPath, "utf-8");
|
|
@@ -664,10 +665,10 @@ function createHashlineEditTool(config, cache) {
|
|
|
664
665
|
try {
|
|
665
666
|
const result = applyHashEdit(
|
|
666
667
|
{
|
|
667
|
-
operation
|
|
668
|
-
startRef
|
|
669
|
-
endRef
|
|
670
|
-
replacement
|
|
668
|
+
operation,
|
|
669
|
+
startRef,
|
|
670
|
+
endRef,
|
|
671
|
+
replacement
|
|
671
672
|
},
|
|
672
673
|
current,
|
|
673
674
|
config.hashLength || void 0
|
|
@@ -688,25 +689,25 @@ function createHashlineEditTool(config, cache) {
|
|
|
688
689
|
if (cache) {
|
|
689
690
|
cache.invalidate(absPath);
|
|
690
691
|
cache.invalidate(normalizedAbs);
|
|
691
|
-
if (
|
|
692
|
+
if (path !== absPath) cache.invalidate(path);
|
|
692
693
|
if (displayPath !== absPath) cache.invalidate(displayPath);
|
|
693
694
|
}
|
|
694
695
|
context.metadata({
|
|
695
|
-
title: `hashline_edit: ${
|
|
696
|
+
title: `hashline_edit: ${operation} ${displayPath}`,
|
|
696
697
|
metadata: {
|
|
697
698
|
path: displayPath,
|
|
698
|
-
operation
|
|
699
|
+
operation,
|
|
699
700
|
startLine,
|
|
700
701
|
endLine
|
|
701
702
|
}
|
|
702
703
|
});
|
|
703
704
|
return [
|
|
704
|
-
`Applied ${
|
|
705
|
+
`Applied ${operation} to ${displayPath}.`,
|
|
705
706
|
`Resolved range: ${startLine}-${endLine}.`,
|
|
706
707
|
"Re-read the file to get fresh hash references before the next edit."
|
|
707
708
|
].join("\n");
|
|
708
709
|
}
|
|
709
|
-
}
|
|
710
|
+
};
|
|
710
711
|
}
|
|
711
712
|
|
|
712
713
|
// src/index.ts
|
package/dist/index.js
CHANGED
|
@@ -18,25 +18,26 @@ import { fileURLToPath } from "url";
|
|
|
18
18
|
// src/hashline-tool.ts
|
|
19
19
|
import { readFileSync, writeFileSync } from "fs";
|
|
20
20
|
import { isAbsolute, relative, resolve, sep } from "path";
|
|
21
|
-
import {
|
|
21
|
+
import { z } from "zod";
|
|
22
22
|
function createHashlineEditTool(config, cache) {
|
|
23
|
-
return
|
|
23
|
+
return {
|
|
24
24
|
description: "Edit files using hashline references. Resolves refs like 5:a3f or '#HL 5:a3f|...' and applies replace/delete/insert without old_string matching.",
|
|
25
25
|
args: {
|
|
26
|
-
path:
|
|
27
|
-
operation:
|
|
28
|
-
startRef:
|
|
29
|
-
endRef:
|
|
30
|
-
replacement:
|
|
26
|
+
path: z.string().describe("Path to the file (absolute or relative to project directory)"),
|
|
27
|
+
operation: z.enum(["replace", "delete", "insert_before", "insert_after"]).describe("Edit operation"),
|
|
28
|
+
startRef: z.string().describe('Start hash reference, e.g. "5:a3f" or "#HL 5:a3f|const x = 1;"'),
|
|
29
|
+
endRef: z.string().optional().describe("End hash reference for range operations. Defaults to startRef when omitted."),
|
|
30
|
+
replacement: z.string().optional().describe("Replacement/inserted content. Required for replace/insert operations.")
|
|
31
31
|
},
|
|
32
32
|
async execute(args, context) {
|
|
33
|
-
const
|
|
33
|
+
const { path, operation, startRef, endRef, replacement } = args;
|
|
34
|
+
const absPath = isAbsolute(path) ? path : resolve(context.directory, path);
|
|
34
35
|
const normalizedAbs = resolve(absPath);
|
|
35
36
|
const normalizedWorktree = resolve(context.worktree);
|
|
36
37
|
if (normalizedAbs !== normalizedWorktree && !normalizedAbs.startsWith(normalizedWorktree + sep)) {
|
|
37
|
-
throw new Error(`Access denied: "${
|
|
38
|
+
throw new Error(`Access denied: "${path}" resolves outside the project directory`);
|
|
38
39
|
}
|
|
39
|
-
const displayPath = relative(context.worktree, absPath) ||
|
|
40
|
+
const displayPath = relative(context.worktree, absPath) || path;
|
|
40
41
|
let current;
|
|
41
42
|
try {
|
|
42
43
|
current = readFileSync(absPath, "utf-8");
|
|
@@ -50,10 +51,10 @@ function createHashlineEditTool(config, cache) {
|
|
|
50
51
|
try {
|
|
51
52
|
const result = applyHashEdit(
|
|
52
53
|
{
|
|
53
|
-
operation
|
|
54
|
-
startRef
|
|
55
|
-
endRef
|
|
56
|
-
replacement
|
|
54
|
+
operation,
|
|
55
|
+
startRef,
|
|
56
|
+
endRef,
|
|
57
|
+
replacement
|
|
57
58
|
},
|
|
58
59
|
current,
|
|
59
60
|
config.hashLength || void 0
|
|
@@ -74,25 +75,25 @@ function createHashlineEditTool(config, cache) {
|
|
|
74
75
|
if (cache) {
|
|
75
76
|
cache.invalidate(absPath);
|
|
76
77
|
cache.invalidate(normalizedAbs);
|
|
77
|
-
if (
|
|
78
|
+
if (path !== absPath) cache.invalidate(path);
|
|
78
79
|
if (displayPath !== absPath) cache.invalidate(displayPath);
|
|
79
80
|
}
|
|
80
81
|
context.metadata({
|
|
81
|
-
title: `hashline_edit: ${
|
|
82
|
+
title: `hashline_edit: ${operation} ${displayPath}`,
|
|
82
83
|
metadata: {
|
|
83
84
|
path: displayPath,
|
|
84
|
-
operation
|
|
85
|
+
operation,
|
|
85
86
|
startLine,
|
|
86
87
|
endLine
|
|
87
88
|
}
|
|
88
89
|
});
|
|
89
90
|
return [
|
|
90
|
-
`Applied ${
|
|
91
|
+
`Applied ${operation} to ${displayPath}.`,
|
|
91
92
|
`Resolved range: ${startLine}-${endLine}.`,
|
|
92
93
|
"Re-read the file to get fresh hash references before the next edit."
|
|
93
94
|
].join("\n");
|
|
94
95
|
}
|
|
95
|
-
}
|
|
96
|
+
};
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
// src/index.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-hashline",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Hashline plugin for OpenCode — content-addressable line hashing for precise AI code editing",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
],
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@opencode-ai/plugin": "^1.2.2"
|
|
43
|
+
"@opencode-ai/plugin": "^1.2.2",
|
|
44
|
+
"zod": "^3.0.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@opencode-ai/plugin": "^1.2.2",
|
|
@@ -48,7 +49,8 @@
|
|
|
48
49
|
"@types/picomatch": "^4.0.2",
|
|
49
50
|
"tsup": "^8.5.1",
|
|
50
51
|
"typescript": "^5.9.3",
|
|
51
|
-
"vitest": "^4.0.18"
|
|
52
|
+
"vitest": "^4.0.18",
|
|
53
|
+
"zod": "^4.1.8"
|
|
52
54
|
},
|
|
53
55
|
"dependencies": {
|
|
54
56
|
"picomatch": "^4.0.3"
|