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 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 import_tool = require("@opencode-ai/plugin/tool");
634
+ var import_zod = require("zod");
635
635
  init_hashline();
636
636
  function createHashlineEditTool(config, cache) {
637
- return (0, import_tool.tool)({
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: import_tool.tool.schema.string().describe("Path to the file (absolute or relative to project directory)"),
641
- operation: import_tool.tool.schema.enum(["replace", "delete", "insert_before", "insert_after"]).describe("Edit operation"),
642
- startRef: import_tool.tool.schema.string().describe('Start hash reference, e.g. "5:a3f" or "#HL 5:a3f|const x = 1;"'),
643
- endRef: import_tool.tool.schema.string().optional().describe("End hash reference for range operations. Defaults to startRef when omitted."),
644
- replacement: import_tool.tool.schema.string().optional().describe("Replacement/inserted content. Required for replace/insert operations.")
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 absPath = (0, import_path2.isAbsolute)(args.path) ? args.path : (0, import_path2.resolve)(context.directory, args.path);
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: "${args.path}" resolves outside the project directory`);
652
+ throw new Error(`Access denied: "${path}" resolves outside the project directory`);
652
653
  }
653
- const displayPath = (0, import_path2.relative)(context.worktree, absPath) || args.path;
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: args.operation,
668
- startRef: args.startRef,
669
- endRef: args.endRef,
670
- replacement: args.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 (args.path !== absPath) cache.invalidate(args.path);
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: ${args.operation} ${displayPath}`,
696
+ title: `hashline_edit: ${operation} ${displayPath}`,
696
697
  metadata: {
697
698
  path: displayPath,
698
- operation: args.operation,
699
+ operation,
699
700
  startLine,
700
701
  endLine
701
702
  }
702
703
  });
703
704
  return [
704
- `Applied ${args.operation} to ${displayPath}.`,
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 { tool } from "@opencode-ai/plugin/tool";
21
+ import { z } from "zod";
22
22
  function createHashlineEditTool(config, cache) {
23
- return tool({
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: tool.schema.string().describe("Path to the file (absolute or relative to project directory)"),
27
- operation: tool.schema.enum(["replace", "delete", "insert_before", "insert_after"]).describe("Edit operation"),
28
- startRef: tool.schema.string().describe('Start hash reference, e.g. "5:a3f" or "#HL 5:a3f|const x = 1;"'),
29
- endRef: tool.schema.string().optional().describe("End hash reference for range operations. Defaults to startRef when omitted."),
30
- replacement: tool.schema.string().optional().describe("Replacement/inserted content. Required for replace/insert operations.")
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 absPath = isAbsolute(args.path) ? args.path : resolve(context.directory, args.path);
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: "${args.path}" resolves outside the project directory`);
38
+ throw new Error(`Access denied: "${path}" resolves outside the project directory`);
38
39
  }
39
- const displayPath = relative(context.worktree, absPath) || args.path;
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: args.operation,
54
- startRef: args.startRef,
55
- endRef: args.endRef,
56
- replacement: args.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 (args.path !== absPath) cache.invalidate(args.path);
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: ${args.operation} ${displayPath}`,
82
+ title: `hashline_edit: ${operation} ${displayPath}`,
82
83
  metadata: {
83
84
  path: displayPath,
84
- operation: args.operation,
85
+ operation,
85
86
  startLine,
86
87
  endLine
87
88
  }
88
89
  });
89
90
  return [
90
- `Applied ${args.operation} to ${displayPath}.`,
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.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"