@howaboua/opencode-chat 0.1.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/LICENSE +21 -0
- package/README.md +116 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +65 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/script/download-model.d.ts +2 -0
- package/dist/script/download-model.d.ts.map +1 -0
- package/dist/script/download-model.js +39 -0
- package/dist/script/semantic-index.d.ts +2 -0
- package/dist/script/semantic-index.d.ts.map +1 -0
- package/dist/script/semantic-index.js +63 -0
- package/dist/semantic/chunker.d.ts +8 -0
- package/dist/semantic/chunker.d.ts.map +1 -0
- package/dist/semantic/chunker.js +163 -0
- package/dist/semantic/embedder.d.ts +12 -0
- package/dist/semantic/embedder.d.ts.map +1 -0
- package/dist/semantic/embedder.js +54 -0
- package/dist/semantic/index.d.ts +41 -0
- package/dist/semantic/index.d.ts.map +1 -0
- package/dist/semantic/index.js +178 -0
- package/dist/system.d.ts +5 -0
- package/dist/system.d.ts.map +1 -0
- package/dist/system.js +93 -0
- package/dist/tools/bash.d.ts +22 -0
- package/dist/tools/bash.d.ts.map +1 -0
- package/dist/tools/bash.js +59 -0
- package/dist/tools/batch.d.ts +25 -0
- package/dist/tools/batch.d.ts.map +1 -0
- package/dist/tools/batch.js +49 -0
- package/dist/tools/edit.d.ts +25 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +44 -0
- package/dist/tools/glob.d.ts +19 -0
- package/dist/tools/glob.d.ts.map +1 -0
- package/dist/tools/glob.js +54 -0
- package/dist/tools/grep.d.ts +22 -0
- package/dist/tools/grep.d.ts.map +1 -0
- package/dist/tools/grep.js +92 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +51 -0
- package/dist/tools/patch.d.ts +16 -0
- package/dist/tools/patch.d.ts.map +1 -0
- package/dist/tools/patch.js +87 -0
- package/dist/tools/read.d.ts +22 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +70 -0
- package/dist/tools/remember.d.ts +16 -0
- package/dist/tools/remember.d.ts.map +1 -0
- package/dist/tools/remember.js +58 -0
- package/dist/tools/semantic-search.d.ts +19 -0
- package/dist/tools/semantic-search.d.ts.map +1 -0
- package/dist/tools/semantic-search.js +54 -0
- package/dist/tools/skill.d.ts +17 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +106 -0
- package/dist/tools/todo.d.ts +62 -0
- package/dist/tools/todo.d.ts.map +1 -0
- package/dist/tools/todo.js +62 -0
- package/dist/tools/write.d.ts +19 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +37 -0
- package/dist/util/constants.d.ts +16 -0
- package/dist/util/constants.d.ts.map +1 -0
- package/dist/util/constants.js +39 -0
- package/dist/util/patch.d.ts +32 -0
- package/dist/util/patch.d.ts.map +1 -0
- package/dist/util/patch.js +240 -0
- package/dist/util/paths.d.ts +6 -0
- package/dist/util/paths.d.ts.map +1 -0
- package/dist/util/paths.js +76 -0
- package/dist/util/text.d.ts +4 -0
- package/dist/util/text.d.ts.map +1 -0
- package/dist/util/text.js +37 -0
- package/dist/util/todo.d.ts +5 -0
- package/dist/util/todo.d.ts.map +1 -0
- package/dist/util/todo.js +48 -0
- package/dist/util/types.d.ts +22 -0
- package/dist/util/types.d.ts.map +1 -0
- package/dist/util/types.js +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path and file-type helpers for chatified tools.
|
|
3
|
+
* Ensures paths remain within the working directory and flags unsafe targets.
|
|
4
|
+
* File-type checks mimic core tool behavior where possible.
|
|
5
|
+
*/
|
|
6
|
+
import path from "path";
|
|
7
|
+
export function resolvePath(baseDir, inputPath) {
|
|
8
|
+
const resolved = path.isAbsolute(inputPath) ? inputPath : path.resolve(baseDir, inputPath);
|
|
9
|
+
const rel = path.relative(baseDir, resolved);
|
|
10
|
+
if (rel.startsWith("..") || path.isAbsolute(rel)) {
|
|
11
|
+
throw new Error(`Path must stay within ${baseDir}: ${inputPath}`);
|
|
12
|
+
}
|
|
13
|
+
return resolved;
|
|
14
|
+
}
|
|
15
|
+
export function isBlockedEnvPath(filePath) {
|
|
16
|
+
if (filePath.endsWith(".env.sample") || filePath.endsWith(".env.example"))
|
|
17
|
+
return false;
|
|
18
|
+
return filePath.includes(".env");
|
|
19
|
+
}
|
|
20
|
+
export function isBinaryExtension(filePath) {
|
|
21
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
22
|
+
return new Set([
|
|
23
|
+
".zip",
|
|
24
|
+
".tar",
|
|
25
|
+
".gz",
|
|
26
|
+
".exe",
|
|
27
|
+
".dll",
|
|
28
|
+
".so",
|
|
29
|
+
".class",
|
|
30
|
+
".jar",
|
|
31
|
+
".war",
|
|
32
|
+
".7z",
|
|
33
|
+
".doc",
|
|
34
|
+
".docx",
|
|
35
|
+
".xls",
|
|
36
|
+
".xlsx",
|
|
37
|
+
".ppt",
|
|
38
|
+
".pptx",
|
|
39
|
+
".odt",
|
|
40
|
+
".ods",
|
|
41
|
+
".odp",
|
|
42
|
+
".bin",
|
|
43
|
+
".dat",
|
|
44
|
+
".obj",
|
|
45
|
+
".o",
|
|
46
|
+
".a",
|
|
47
|
+
".lib",
|
|
48
|
+
".wasm",
|
|
49
|
+
".pyc",
|
|
50
|
+
".pyo",
|
|
51
|
+
]).has(ext);
|
|
52
|
+
}
|
|
53
|
+
export function isImageExtension(filePath) {
|
|
54
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
55
|
+
return new Set([".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"]).has(ext);
|
|
56
|
+
}
|
|
57
|
+
export async function isBinaryFile(filePath) {
|
|
58
|
+
if (isBinaryExtension(filePath))
|
|
59
|
+
return true;
|
|
60
|
+
const file = Bun.file(filePath);
|
|
61
|
+
const buffer = await file.arrayBuffer().catch(() => undefined);
|
|
62
|
+
if (!buffer)
|
|
63
|
+
return false;
|
|
64
|
+
const bytes = new Uint8Array(buffer.slice(0, Math.min(4096, buffer.byteLength)));
|
|
65
|
+
if (bytes.length === 0)
|
|
66
|
+
return false;
|
|
67
|
+
let nonPrintable = 0;
|
|
68
|
+
for (const byte of bytes) {
|
|
69
|
+
if (byte === 0)
|
|
70
|
+
return true;
|
|
71
|
+
if (byte < 9 || (byte > 13 && byte < 32)) {
|
|
72
|
+
nonPrintable += 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return nonPrintable / bytes.length > 0.3;
|
|
76
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function trimLine(line: string): string;
|
|
2
|
+
export declare function replaceOnce(content: string, oldString: string, newString: string, replaceAll?: boolean): string;
|
|
3
|
+
export declare function stripHtml(html: string): string;
|
|
4
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../util/text.ts"],"names":[],"mappings":"AAOA,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,UAGpC;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,UAqBtG;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,UAKrC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text helpers used by multiple tools.
|
|
3
|
+
* Keeps formatting and replacement behavior consistent across modules.
|
|
4
|
+
* Focuses on predictable output instead of clever heuristics.
|
|
5
|
+
*/
|
|
6
|
+
import { MAX_LINE_LENGTH } from "./constants";
|
|
7
|
+
export function trimLine(line) {
|
|
8
|
+
if (line.length <= MAX_LINE_LENGTH)
|
|
9
|
+
return line;
|
|
10
|
+
return line.slice(0, MAX_LINE_LENGTH) + "...";
|
|
11
|
+
}
|
|
12
|
+
export function replaceOnce(content, oldString, newString, replaceAll) {
|
|
13
|
+
if (oldString === newString) {
|
|
14
|
+
throw new Error("oldString and newString must be different");
|
|
15
|
+
}
|
|
16
|
+
if (oldString === "") {
|
|
17
|
+
return newString;
|
|
18
|
+
}
|
|
19
|
+
const first = content.indexOf(oldString);
|
|
20
|
+
if (first === -1) {
|
|
21
|
+
throw new Error("oldString not found in content");
|
|
22
|
+
}
|
|
23
|
+
if (replaceAll) {
|
|
24
|
+
return content.split(oldString).join(newString);
|
|
25
|
+
}
|
|
26
|
+
const last = content.lastIndexOf(oldString);
|
|
27
|
+
if (first !== last) {
|
|
28
|
+
throw new Error("Found multiple matches for oldString. Provide more surrounding lines in oldString to identify the correct match.");
|
|
29
|
+
}
|
|
30
|
+
return content.slice(0, first) + newString + content.slice(first + oldString.length);
|
|
31
|
+
}
|
|
32
|
+
export function stripHtml(html) {
|
|
33
|
+
const withoutScripts = html.replace(/<script[\s\S]*?<\/script>/gi, "");
|
|
34
|
+
const withoutStyles = withoutScripts.replace(/<style[\s\S]*?<\/style>/gi, "");
|
|
35
|
+
const withoutTags = withoutStyles.replace(/<[^>]+>/g, " ");
|
|
36
|
+
return withoutTags.replace(/\s+/g, " ").trim();
|
|
37
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { TodoItem } from "./types";
|
|
2
|
+
export declare function formatTodoMarkdown(todos: TodoItem[]): string;
|
|
3
|
+
export declare function readTodoFile(todoPath: string): Promise<TodoItem[]>;
|
|
4
|
+
export declare function writeTodoFile(todoPath: string, todos: TodoItem[]): Promise<string>;
|
|
5
|
+
//# sourceMappingURL=todo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todo.d.ts","sourceRoot":"","sources":["../../util/todo.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAElC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,UAUnD;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAgBxE;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,mBAStE"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Todo file helpers for chat_todowrite and chat_todoread.
|
|
3
|
+
* Stores task lists in a repo-level todo.md with embedded JSON payload.
|
|
4
|
+
* Removes the file when all tasks are completed.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from "fs/promises";
|
|
7
|
+
export function formatTodoMarkdown(todos) {
|
|
8
|
+
const lines = ["# Todo", ""];
|
|
9
|
+
for (const todo of todos) {
|
|
10
|
+
const box = todo.status === "completed" ? "x" : " ";
|
|
11
|
+
lines.push(`- [${box}] ${todo.content} (priority: ${todo.priority}, id: ${todo.id}, status: ${todo.status})`);
|
|
12
|
+
}
|
|
13
|
+
lines.push("", "<!-- opencode-todo");
|
|
14
|
+
lines.push(JSON.stringify(todos, null, 2));
|
|
15
|
+
lines.push("-->");
|
|
16
|
+
return lines.join("\n");
|
|
17
|
+
}
|
|
18
|
+
export async function readTodoFile(todoPath) {
|
|
19
|
+
const exists = await fs
|
|
20
|
+
.stat(todoPath)
|
|
21
|
+
.then(() => true)
|
|
22
|
+
.catch(() => false);
|
|
23
|
+
if (!exists)
|
|
24
|
+
return [];
|
|
25
|
+
const content = await fs.readFile(todoPath, "utf-8");
|
|
26
|
+
const match = content.match(/<!-- opencode-todo\n([\s\S]*?)\n-->/);
|
|
27
|
+
if (!match)
|
|
28
|
+
return [];
|
|
29
|
+
try {
|
|
30
|
+
const parsed = JSON.parse(match[1]);
|
|
31
|
+
if (Array.isArray(parsed))
|
|
32
|
+
return parsed;
|
|
33
|
+
}
|
|
34
|
+
catch (_error) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
export async function writeTodoFile(todoPath, todos) {
|
|
40
|
+
const remaining = todos.filter((todo) => todo.status !== "completed");
|
|
41
|
+
if (remaining.length === 0) {
|
|
42
|
+
await fs.unlink(todoPath).catch(() => { });
|
|
43
|
+
return "All todos completed. Removed todo.md.";
|
|
44
|
+
}
|
|
45
|
+
const content = formatTodoMarkdown(todos);
|
|
46
|
+
await fs.writeFile(todoPath, content, "utf-8");
|
|
47
|
+
return `${remaining.length} todos remaining. Updated todo.md.`;
|
|
48
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions for chatifier tools.
|
|
3
|
+
* Keeps tool signatures consistent across modules and batch execution.
|
|
4
|
+
* Extend cautiously to avoid widening interfaces unnecessarily.
|
|
5
|
+
*/
|
|
6
|
+
export type TodoItem = {
|
|
7
|
+
content: string;
|
|
8
|
+
status: "pending" | "in_progress" | "completed" | "cancelled";
|
|
9
|
+
priority: "high" | "medium" | "low";
|
|
10
|
+
id: string;
|
|
11
|
+
};
|
|
12
|
+
export type ToolCall = {
|
|
13
|
+
tool: string;
|
|
14
|
+
parameters: Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
export type Match = {
|
|
17
|
+
path: string;
|
|
18
|
+
modTime: number;
|
|
19
|
+
lineNum: number;
|
|
20
|
+
lineText: string;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../util/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,WAAW,CAAA;IAC7D,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAA;IACnC,EAAE,EAAE,MAAM,CAAA;CACX,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@howaboua/opencode-chat",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Chatifier plugin for OpenCode - Adds chat-optimized tools and semantic search",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"opencode-chat-download-model": "dist/script/download-model.js",
|
|
10
|
+
"opencode-chat-semantic-index": "dist/script/semantic-index.js"
|
|
11
|
+
},
|
|
12
|
+
"author": "Igor Wiedler <igor@wiedler.ch>",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"scripts": {
|
|
15
|
+
"clean": "rm -rf dist",
|
|
16
|
+
"build": "npm run clean && tsc",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"download-model": "bun dist/script/download-model.js",
|
|
19
|
+
"semantic-index": "bun dist/script/semantic-index.js"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"fastembed": "latest"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@opencode-ai/plugin": "^1.0.201"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@opencode-ai/plugin": "^1.0.201",
|
|
29
|
+
"@types/node": "^20.0.0",
|
|
30
|
+
"bun-types": "latest",
|
|
31
|
+
"typescript": "^5.7.0"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
38
|
+
"keywords": [
|
|
39
|
+
"opencode",
|
|
40
|
+
"opencode-plugin",
|
|
41
|
+
"plugin",
|
|
42
|
+
"chat",
|
|
43
|
+
"semantic-search",
|
|
44
|
+
"agent"
|
|
45
|
+
],
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/IgorWarzocha/Opencode-Chatifier.git"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
}
|
|
53
|
+
}
|