opencode-snippets 1.4.2 → 1.4.3

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.
Files changed (56) hide show
  1. package/dist/index.d.ts +11 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +72 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/src/arg-parser.d.ts +16 -0
  6. package/dist/src/arg-parser.d.ts.map +1 -0
  7. package/dist/src/arg-parser.js +94 -0
  8. package/dist/src/arg-parser.js.map +1 -0
  9. package/dist/src/commands.d.ts +30 -0
  10. package/dist/src/commands.d.ts.map +1 -0
  11. package/dist/src/commands.js +315 -0
  12. package/dist/src/commands.js.map +1 -0
  13. package/dist/src/constants.d.ts +26 -0
  14. package/dist/src/constants.d.ts.map +1 -0
  15. package/dist/src/constants.js +28 -0
  16. package/dist/src/constants.js.map +1 -0
  17. package/dist/src/expander.d.ts +36 -0
  18. package/dist/src/expander.d.ts.map +1 -0
  19. package/dist/src/expander.js +187 -0
  20. package/dist/src/expander.js.map +1 -0
  21. package/dist/src/loader.d.ts +46 -0
  22. package/dist/src/loader.d.ts.map +1 -0
  23. package/dist/src/loader.js +223 -0
  24. package/dist/src/loader.js.map +1 -0
  25. package/dist/src/logger.d.ts +15 -0
  26. package/dist/src/logger.d.ts.map +1 -0
  27. package/dist/src/logger.js +107 -0
  28. package/dist/src/logger.js.map +1 -0
  29. package/dist/src/notification.d.ts +11 -0
  30. package/dist/src/notification.d.ts.map +1 -0
  31. package/dist/src/notification.js +26 -0
  32. package/dist/src/notification.js.map +1 -0
  33. package/dist/src/shell.d.ts +18 -0
  34. package/dist/src/shell.d.ts.map +1 -0
  35. package/dist/src/shell.js +30 -0
  36. package/dist/src/shell.js.map +1 -0
  37. package/dist/src/types.d.ts +65 -0
  38. package/dist/src/types.d.ts.map +1 -0
  39. package/dist/src/types.js +2 -0
  40. package/dist/src/types.js.map +1 -0
  41. package/package.json +8 -5
  42. package/index.ts +0 -81
  43. package/src/arg-parser.test.ts +0 -177
  44. package/src/arg-parser.ts +0 -87
  45. package/src/commands.test.ts +0 -188
  46. package/src/commands.ts +0 -414
  47. package/src/constants.ts +0 -32
  48. package/src/expander.test.ts +0 -846
  49. package/src/expander.ts +0 -225
  50. package/src/loader.test.ts +0 -352
  51. package/src/loader.ts +0 -268
  52. package/src/logger.test.ts +0 -136
  53. package/src/logger.ts +0 -121
  54. package/src/notification.ts +0 -30
  55. package/src/shell.ts +0 -50
  56. package/src/types.ts +0 -71
@@ -0,0 +1,11 @@
1
+ import type { Plugin } from "@opencode-ai/plugin";
2
+ /**
3
+ * Snippets Plugin for OpenCode
4
+ *
5
+ * Expands hashtag-based shortcuts in user messages into predefined text snippets.
6
+ * Also provides /snippet command for managing snippets.
7
+ *
8
+ * @see https://github.com/JosXa/opencode-snippets for full documentation
9
+ */
10
+ export declare const SnippetsPlugin: Plugin;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAOlD;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,EAAE,MAiE5B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,72 @@
1
+ import { createCommandExecuteHandler } from "./src/commands.js";
2
+ import { assembleMessage, expandHashtags } from "./src/expander.js";
3
+ import { loadSnippets } from "./src/loader.js";
4
+ import { logger } from "./src/logger.js";
5
+ import { executeShellCommands } from "./src/shell.js";
6
+ /**
7
+ * Snippets Plugin for OpenCode
8
+ *
9
+ * Expands hashtag-based shortcuts in user messages into predefined text snippets.
10
+ * Also provides /snippet command for managing snippets.
11
+ *
12
+ * @see https://github.com/JosXa/opencode-snippets for full documentation
13
+ */
14
+ export const SnippetsPlugin = async (ctx) => {
15
+ // Load all snippets at startup (global + project directory)
16
+ const startupStart = performance.now();
17
+ const snippets = await loadSnippets(ctx.directory);
18
+ const startupTime = performance.now() - startupStart;
19
+ logger.debug("Plugin startup complete", {
20
+ startupTimeMs: startupTime.toFixed(2),
21
+ snippetCount: snippets.size,
22
+ });
23
+ // Create command handler
24
+ const commandHandler = createCommandExecuteHandler(ctx.client, snippets, ctx.directory);
25
+ return {
26
+ // Register /snippet command
27
+ config: async (opencodeConfig) => {
28
+ opencodeConfig.command ??= {};
29
+ opencodeConfig.command.snippet = {
30
+ template: "",
31
+ description: "Manage text snippets (add, delete, list, help)",
32
+ };
33
+ },
34
+ // Handle /snippet command execution
35
+ "command.execute.before": commandHandler,
36
+ "chat.message": async (_input, output) => {
37
+ // Only process user messages, never assistant messages
38
+ if (output.message.role !== "user")
39
+ return;
40
+ const messageStart = performance.now();
41
+ let expandTimeTotal = 0;
42
+ let shellTimeTotal = 0;
43
+ let processedParts = 0;
44
+ for (const part of output.parts) {
45
+ if (part.type === "text" && part.text) {
46
+ // 1. Expand hashtags recursively with loop detection
47
+ const expandStart = performance.now();
48
+ const expansionResult = expandHashtags(part.text, snippets);
49
+ part.text = assembleMessage(expansionResult);
50
+ const expandTime = performance.now() - expandStart;
51
+ expandTimeTotal += expandTime;
52
+ // 2. Execute shell commands: !`command`
53
+ const shellStart = performance.now();
54
+ part.text = await executeShellCommands(part.text, ctx);
55
+ const shellTime = performance.now() - shellStart;
56
+ shellTimeTotal += shellTime;
57
+ processedParts += 1;
58
+ }
59
+ }
60
+ const totalTime = performance.now() - messageStart;
61
+ if (processedParts > 0) {
62
+ logger.debug("Message processing complete", {
63
+ totalTimeMs: totalTime.toFixed(2),
64
+ snippetExpandTimeMs: expandTimeTotal.toFixed(2),
65
+ shellTimeMs: shellTimeTotal.toFixed(2),
66
+ processedParts,
67
+ });
68
+ }
69
+ },
70
+ };
71
+ };
72
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Shell-like argument parser that handles quoted strings correctly.
3
+ *
4
+ * Supports:
5
+ * - Space-separated arguments
6
+ * - Double-quoted strings (preserves spaces, allows single quotes inside)
7
+ * - Single-quoted strings (preserves spaces, allows double quotes inside)
8
+ * - --key=value syntax with quoted values
9
+ * - Multiline content inside quotes
10
+ * - Backslash escapes for quotes inside quoted strings
11
+ *
12
+ * @param input - The raw argument string to parse
13
+ * @returns Array of parsed arguments with quotes stripped
14
+ */
15
+ export declare function parseCommandArgs(input: string): string[];
16
+ //# sourceMappingURL=arg-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arg-parser.d.ts","sourceRoot":"","sources":["../../src/arg-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAwExD"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Shell-like argument parser that handles quoted strings correctly.
3
+ *
4
+ * Supports:
5
+ * - Space-separated arguments
6
+ * - Double-quoted strings (preserves spaces, allows single quotes inside)
7
+ * - Single-quoted strings (preserves spaces, allows double quotes inside)
8
+ * - --key=value syntax with quoted values
9
+ * - Multiline content inside quotes
10
+ * - Backslash escapes for quotes inside quoted strings
11
+ *
12
+ * @param input - The raw argument string to parse
13
+ * @returns Array of parsed arguments with quotes stripped
14
+ */
15
+ export function parseCommandArgs(input) {
16
+ const args = [];
17
+ let current = "";
18
+ let state = "normal";
19
+ let hasQuotedContent = false; // Track if we've entered a quoted section
20
+ let i = 0;
21
+ while (i < input.length) {
22
+ const char = input[i];
23
+ if (state === "normal") {
24
+ if (char === " " || char === "\t") {
25
+ // Whitespace in normal mode: finish current token
26
+ if (current.length > 0 || hasQuotedContent) {
27
+ args.push(current);
28
+ current = "";
29
+ hasQuotedContent = false;
30
+ }
31
+ }
32
+ else if (char === '"') {
33
+ // Enter double-quote mode
34
+ state = "double";
35
+ hasQuotedContent = true;
36
+ }
37
+ else if (char === "'") {
38
+ // Enter single-quote mode
39
+ state = "single";
40
+ hasQuotedContent = true;
41
+ }
42
+ else {
43
+ current += char;
44
+ }
45
+ }
46
+ else if (state === "double") {
47
+ if (char === "\\") {
48
+ // Check for escape sequences
49
+ const next = input[i + 1];
50
+ if (next === '"' || next === "\\") {
51
+ current += next;
52
+ i++; // Skip the escaped character
53
+ }
54
+ else {
55
+ current += char;
56
+ }
57
+ }
58
+ else if (char === '"') {
59
+ // Exit double-quote mode
60
+ state = "normal";
61
+ }
62
+ else {
63
+ current += char;
64
+ }
65
+ }
66
+ else if (state === "single") {
67
+ if (char === "\\") {
68
+ // Check for escape sequences
69
+ const next = input[i + 1];
70
+ if (next === "'" || next === "\\") {
71
+ current += next;
72
+ i++; // Skip the escaped character
73
+ }
74
+ else {
75
+ current += char;
76
+ }
77
+ }
78
+ else if (char === "'") {
79
+ // Exit single-quote mode
80
+ state = "normal";
81
+ }
82
+ else {
83
+ current += char;
84
+ }
85
+ }
86
+ i++;
87
+ }
88
+ // Handle any remaining content (including unclosed quotes or empty quoted strings)
89
+ if (current.length > 0 || hasQuotedContent) {
90
+ args.push(current);
91
+ }
92
+ return args;
93
+ }
94
+ //# sourceMappingURL=arg-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arg-parser.js","sourceRoot":"","sources":["../../src/arg-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { OpencodeClient, SnippetRegistry } from "./types.js";
2
+ /**
3
+ * Parsed options from the add command arguments
4
+ */
5
+ export interface AddOptions {
6
+ aliases: string[];
7
+ description: string | undefined;
8
+ isProject: boolean;
9
+ }
10
+ /**
11
+ * Parses option arguments for the add command.
12
+ *
13
+ * Supports all variations per PR #13 requirements:
14
+ * - --alias=a,b, --alias a,b, --aliases=a,b, --aliases a,b
15
+ * - --desc=x, --desc x, --description=x, --description x
16
+ * - --project flag
17
+ *
18
+ * @param args - Array of parsed arguments (after name and content extraction)
19
+ * @returns Parsed options object
20
+ */
21
+ export declare function parseAddOptions(args: string[]): AddOptions;
22
+ /**
23
+ * Creates the command execute handler for the snippets command
24
+ */
25
+ export declare function createCommandExecuteHandler(client: OpencodeClient, snippets: SnippetRegistry, projectDir?: string): (input: {
26
+ command: string;
27
+ sessionID: string;
28
+ arguments: string;
29
+ }) => Promise<void>;
30
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/commands.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAclE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA8D1D;AAYD;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,eAAe,EACzB,UAAU,CAAC,EAAE,MAAM,IAEL,OAAO;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,mBAsD/E"}
@@ -0,0 +1,315 @@
1
+ import { parseCommandArgs } from "./arg-parser.js";
2
+ import { PATHS } from "./constants.js";
3
+ import { createSnippet, deleteSnippet, listSnippets, reloadSnippets } from "./loader.js";
4
+ import { logger } from "./logger.js";
5
+ import { sendIgnoredMessage } from "./notification.js";
6
+ /** Marker error to indicate command was handled */
7
+ const COMMAND_HANDLED_MARKER = "__SNIPPETS_COMMAND_HANDLED__";
8
+ /**
9
+ * Parses option arguments for the add command.
10
+ *
11
+ * Supports all variations per PR #13 requirements:
12
+ * - --alias=a,b, --alias a,b, --aliases=a,b, --aliases a,b
13
+ * - --desc=x, --desc x, --description=x, --description x
14
+ * - --project flag
15
+ *
16
+ * @param args - Array of parsed arguments (after name and content extraction)
17
+ * @returns Parsed options object
18
+ */
19
+ export function parseAddOptions(args) {
20
+ const result = {
21
+ aliases: [],
22
+ description: undefined,
23
+ isProject: false,
24
+ };
25
+ for (let i = 0; i < args.length; i++) {
26
+ const arg = args[i];
27
+ // Skip non-option arguments
28
+ if (!arg.startsWith("--")) {
29
+ continue;
30
+ }
31
+ // Handle --project flag
32
+ if (arg === "--project") {
33
+ result.isProject = true;
34
+ continue;
35
+ }
36
+ // Check for --alias or --aliases
37
+ if (arg === "--alias" || arg === "--aliases") {
38
+ // Space-separated: --alias a,b
39
+ const nextArg = args[i + 1];
40
+ if (nextArg && !nextArg.startsWith("--")) {
41
+ result.aliases = parseAliasValue(nextArg);
42
+ i++; // Skip the value arg
43
+ }
44
+ continue;
45
+ }
46
+ if (arg.startsWith("--alias=") || arg.startsWith("--aliases=")) {
47
+ // Equals syntax: --alias=a,b
48
+ const value = arg.includes("--aliases=")
49
+ ? arg.slice("--aliases=".length)
50
+ : arg.slice("--alias=".length);
51
+ result.aliases = parseAliasValue(value);
52
+ continue;
53
+ }
54
+ // Check for --desc or --description
55
+ if (arg === "--desc" || arg === "--description") {
56
+ // Space-separated: --desc value
57
+ const nextArg = args[i + 1];
58
+ if (nextArg && !nextArg.startsWith("--")) {
59
+ result.description = nextArg;
60
+ i++; // Skip the value arg
61
+ }
62
+ continue;
63
+ }
64
+ if (arg.startsWith("--desc=") || arg.startsWith("--description=")) {
65
+ // Equals syntax: --desc=value
66
+ const value = arg.startsWith("--description=")
67
+ ? arg.slice("--description=".length)
68
+ : arg.slice("--desc=".length);
69
+ result.description = value;
70
+ }
71
+ }
72
+ return result;
73
+ }
74
+ /**
75
+ * Parse comma-separated alias values, trimming whitespace
76
+ */
77
+ function parseAliasValue(value) {
78
+ return value
79
+ .split(",")
80
+ .map((s) => s.trim())
81
+ .filter(Boolean);
82
+ }
83
+ /**
84
+ * Creates the command execute handler for the snippets command
85
+ */
86
+ export function createCommandExecuteHandler(client, snippets, projectDir) {
87
+ return async (input) => {
88
+ if (input.command !== "snippet")
89
+ return;
90
+ // Use shell-like argument parsing to handle quoted strings correctly
91
+ const args = parseCommandArgs(input.arguments);
92
+ const subcommand = args[0]?.toLowerCase() || "help";
93
+ const ctx = {
94
+ client,
95
+ sessionId: input.sessionID,
96
+ args: args.slice(1),
97
+ rawArguments: input.arguments,
98
+ snippets,
99
+ projectDir,
100
+ };
101
+ try {
102
+ switch (subcommand) {
103
+ case "add":
104
+ case "create":
105
+ case "new":
106
+ await handleAddCommand(ctx);
107
+ break;
108
+ case "delete":
109
+ case "remove":
110
+ case "rm":
111
+ await handleDeleteCommand(ctx);
112
+ break;
113
+ case "list":
114
+ case "ls":
115
+ await handleListCommand(ctx);
116
+ break;
117
+ default:
118
+ await handleHelpCommand(ctx);
119
+ break;
120
+ }
121
+ }
122
+ catch (error) {
123
+ if (error instanceof Error && error.message === COMMAND_HANDLED_MARKER) {
124
+ throw error;
125
+ }
126
+ logger.error("Command execution failed", {
127
+ subcommand,
128
+ error: error instanceof Error ? error.message : String(error),
129
+ });
130
+ await sendIgnoredMessage(ctx.client, ctx.sessionId, `Error: ${error instanceof Error ? error.message : String(error)}`);
131
+ }
132
+ // Signal that command was handled
133
+ throw new Error(COMMAND_HANDLED_MARKER);
134
+ };
135
+ }
136
+ /**
137
+ * Handle /snippet add <name> ["content"] [--project] [--alias=<alias>] [--desc=<description>]
138
+ */
139
+ async function handleAddCommand(ctx) {
140
+ const { client, sessionId, args, snippets, projectDir } = ctx;
141
+ if (args.length === 0) {
142
+ await sendIgnoredMessage(client, sessionId, 'Usage: /snippet add <name> ["content"] [options]\n\n' +
143
+ "Adds a new snippet. Defaults to global directory.\n\n" +
144
+ "Examples:\n" +
145
+ " /snippet add greeting\n" +
146
+ ' /snippet add bye "see you later"\n' +
147
+ ' /snippet add hi "hello there" --aliases hello,hey\n' +
148
+ ' /snippet add fix "fix imports" --project\n\n' +
149
+ "Options:\n" +
150
+ " --project Add to project directory (.opencode/snippet/)\n" +
151
+ " --aliases X,Y,Z Add aliases (comma-separated)\n" +
152
+ ' --desc "..." Add a description');
153
+ return;
154
+ }
155
+ const name = args[0];
156
+ // Extract content: second argument if it doesn't start with --
157
+ // The arg-parser already handles quoted strings, so content is clean
158
+ let content = "";
159
+ let optionArgs = args.slice(1);
160
+ if (args[1] && !args[1].startsWith("--")) {
161
+ content = args[1];
162
+ optionArgs = args.slice(2);
163
+ }
164
+ // Parse all options using the new parser
165
+ const options = parseAddOptions(optionArgs);
166
+ // Default to global, --project puts it in project directory
167
+ const targetDir = options.isProject ? projectDir : undefined;
168
+ const location = options.isProject && projectDir ? "project" : "global";
169
+ try {
170
+ const filePath = await createSnippet(name, content, { aliases: options.aliases, description: options.description }, targetDir);
171
+ // Reload snippets
172
+ await reloadSnippets(snippets, projectDir);
173
+ let message = `Added ${location} snippet: ${name}\nFile: ${filePath}`;
174
+ if (content) {
175
+ message += `\nContent: "${truncate(content, 50)}"`;
176
+ }
177
+ else {
178
+ message += "\n\nEdit the file to add your snippet content.";
179
+ }
180
+ if (options.aliases.length > 0) {
181
+ message += `\nAliases: ${options.aliases.join(", ")}`;
182
+ }
183
+ await sendIgnoredMessage(client, sessionId, message);
184
+ }
185
+ catch (error) {
186
+ await sendIgnoredMessage(client, sessionId, `Failed to add snippet: ${error instanceof Error ? error.message : String(error)}`);
187
+ }
188
+ }
189
+ /**
190
+ * Handle /snippet delete <name>
191
+ */
192
+ async function handleDeleteCommand(ctx) {
193
+ const { client, sessionId, args, snippets, projectDir } = ctx;
194
+ if (args.length === 0) {
195
+ await sendIgnoredMessage(client, sessionId, "Usage: /snippet delete <name>\n\nDeletes a snippet by name. " +
196
+ "Project snippets are checked first, then global.");
197
+ return;
198
+ }
199
+ const name = args[0];
200
+ const deletedPath = await deleteSnippet(name, projectDir);
201
+ if (deletedPath) {
202
+ // Reload snippets
203
+ await reloadSnippets(snippets, projectDir);
204
+ await sendIgnoredMessage(client, sessionId, `Deleted snippet: #${name}\nRemoved: ${deletedPath}`);
205
+ }
206
+ else {
207
+ await sendIgnoredMessage(client, sessionId, `Snippet not found: #${name}\n\nUse /snippet list to see available snippets.`);
208
+ }
209
+ }
210
+ /** Maximum characters for snippet content preview */
211
+ const MAX_CONTENT_PREVIEW_LENGTH = 200;
212
+ /** Maximum characters for aliases display */
213
+ const MAX_ALIASES_LENGTH = 50;
214
+ /** Divider line */
215
+ const DIVIDER = "────────────────────────────────────────────────";
216
+ /**
217
+ * Truncate text with ellipsis if it exceeds maxLength
218
+ */
219
+ function truncate(text, maxLength) {
220
+ if (text.length <= maxLength)
221
+ return text;
222
+ return `${text.slice(0, maxLength - 3)}...`;
223
+ }
224
+ /**
225
+ * Format aliases for display, truncating if needed
226
+ */
227
+ function formatAliases(aliases) {
228
+ if (aliases.length === 0)
229
+ return "";
230
+ const joined = aliases.join(", ");
231
+ if (joined.length <= MAX_ALIASES_LENGTH) {
232
+ return ` (aliases: ${joined})`;
233
+ }
234
+ // Truncate and show count
235
+ const truncated = truncate(joined, MAX_ALIASES_LENGTH - 10);
236
+ return ` (aliases: ${truncated} +${aliases.length})`;
237
+ }
238
+ /**
239
+ * Format a single snippet for display
240
+ */
241
+ function formatSnippetEntry(s) {
242
+ const header = `${s.name}${formatAliases(s.aliases)}`;
243
+ const content = truncate(s.content.trim(), MAX_CONTENT_PREVIEW_LENGTH);
244
+ return `${header}\n${DIVIDER}\n${content || "(empty)"}`;
245
+ }
246
+ /**
247
+ * Handle /snippet list
248
+ */
249
+ async function handleListCommand(ctx) {
250
+ const { client, sessionId, snippets, projectDir } = ctx;
251
+ const snippetList = listSnippets(snippets);
252
+ if (snippetList.length === 0) {
253
+ await sendIgnoredMessage(client, sessionId, "No snippets found.\n\n" +
254
+ `Global snippets: ${PATHS.SNIPPETS_DIR}\n` +
255
+ (projectDir
256
+ ? `Project snippets: ${projectDir}/.opencode/snippet/`
257
+ : "No project directory detected.") +
258
+ "\n\nUse /snippet add <name> to add a new snippet.");
259
+ return;
260
+ }
261
+ const lines = [];
262
+ // Group by source
263
+ const globalSnippets = snippetList.filter((s) => s.source === "global");
264
+ const projectSnippets = snippetList.filter((s) => s.source === "project");
265
+ if (globalSnippets.length > 0) {
266
+ lines.push(`── Global (${PATHS.SNIPPETS_DIR}) ──`, "");
267
+ for (const s of globalSnippets) {
268
+ lines.push(formatSnippetEntry(s), "");
269
+ }
270
+ }
271
+ if (projectSnippets.length > 0) {
272
+ lines.push(`── Project (${projectDir}/.opencode/snippet/) ──`, "");
273
+ for (const s of projectSnippets) {
274
+ lines.push(formatSnippetEntry(s), "");
275
+ }
276
+ }
277
+ await sendIgnoredMessage(client, sessionId, lines.join("\n").trimEnd());
278
+ }
279
+ /**
280
+ * Handle /snippet help
281
+ */
282
+ async function handleHelpCommand(ctx) {
283
+ const { client, sessionId } = ctx;
284
+ const helpText = `Snippets Command - Manage text snippets
285
+
286
+ Usage: /snippet <command> [options]
287
+
288
+ Commands:
289
+ add <name> ["content"] [options]
290
+ --project Add to project directory (default: global)
291
+ --aliases X,Y,Z Add aliases (comma-separated)
292
+ --desc "..." Add a description
293
+
294
+ delete <name> Delete a snippet
295
+ list List all available snippets
296
+ help Show this help message
297
+
298
+ Snippet Locations:
299
+ Global: ~/.config/opencode/snippet/
300
+ Project: <project>/.opencode/snippet/
301
+
302
+ Usage in messages:
303
+ Type #snippet-name to expand a snippet inline.
304
+ Snippets can reference other snippets recursively.
305
+
306
+ Examples:
307
+ /snippet add greeting
308
+ /snippet add bye "see you later"
309
+ /snippet add hi "hello there" --aliases hello,hey
310
+ /snippet add fix "fix imports" --project
311
+ /snippet delete old-snippet
312
+ /snippet list`;
313
+ await sendIgnoredMessage(client, sessionId, helpText);
314
+ }
315
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Regular expression patterns used throughout the plugin
3
+ */
4
+ export declare const PATTERNS: {
5
+ /** Matches hashtags like #snippet-name */
6
+ readonly HASHTAG: RegExp;
7
+ /** Matches shell commands like !`command` */
8
+ readonly SHELL_COMMAND: RegExp;
9
+ };
10
+ /**
11
+ * File system paths
12
+ */
13
+ export declare const PATHS: {
14
+ /** OpenCode configuration directory */
15
+ readonly CONFIG_DIR: string;
16
+ /** Snippets directory */
17
+ readonly SNIPPETS_DIR: string;
18
+ };
19
+ /**
20
+ * Plugin configuration
21
+ */
22
+ export declare const CONFIG: {
23
+ /** File extension for snippet files */
24
+ readonly SNIPPET_EXTENSION: ".md";
25
+ };
26
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,QAAQ;IACnB,0CAA0C;;IAG1C,6CAA6C;;CAErC,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,KAAK;IAChB,uCAAuC;;IAGvC,yBAAyB;;CAEjB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,MAAM;IACjB,uCAAuC;;CAE/B,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ /**
4
+ * Regular expression patterns used throughout the plugin
5
+ */
6
+ export const PATTERNS = {
7
+ /** Matches hashtags like #snippet-name */
8
+ HASHTAG: /#([a-z0-9\-_]+)/gi,
9
+ /** Matches shell commands like !`command` */
10
+ SHELL_COMMAND: /!`([^`]+)`/g,
11
+ };
12
+ /**
13
+ * File system paths
14
+ */
15
+ export const PATHS = {
16
+ /** OpenCode configuration directory */
17
+ CONFIG_DIR: join(homedir(), ".config", "opencode"),
18
+ /** Snippets directory */
19
+ SNIPPETS_DIR: join(join(homedir(), ".config", "opencode"), "snippet"),
20
+ };
21
+ /**
22
+ * Plugin configuration
23
+ */
24
+ export const CONFIG = {
25
+ /** File extension for snippet files */
26
+ SNIPPET_EXTENSION: ".md",
27
+ };
28
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,0CAA0C;IAC1C,OAAO,EAAE,mBAAmB;IAE5B,6CAA6C;IAC7C,aAAa,EAAE,aAAa;CACpB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,uCAAuC;IACvC,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC;IAElD,yBAAyB;IACzB,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,SAAS,CAAC;CAC7D,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,uCAAuC;IACvC,iBAAiB,EAAE,KAAK;CAChB,CAAC"}