opencode-command-hooks 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.
Files changed (46) hide show
  1. package/README.md +796 -0
  2. package/dist/config/agent.d.ts +82 -0
  3. package/dist/config/agent.d.ts.map +1 -0
  4. package/dist/config/agent.js +145 -0
  5. package/dist/config/agent.js.map +1 -0
  6. package/dist/config/global.d.ts +36 -0
  7. package/dist/config/global.d.ts.map +1 -0
  8. package/dist/config/global.js +219 -0
  9. package/dist/config/global.js.map +1 -0
  10. package/dist/config/markdown.d.ts +119 -0
  11. package/dist/config/markdown.d.ts.map +1 -0
  12. package/dist/config/markdown.js +373 -0
  13. package/dist/config/markdown.js.map +1 -0
  14. package/dist/config/merge.d.ts +67 -0
  15. package/dist/config/merge.d.ts.map +1 -0
  16. package/dist/config/merge.js +192 -0
  17. package/dist/config/merge.js.map +1 -0
  18. package/dist/execution/shell.d.ts +55 -0
  19. package/dist/execution/shell.d.ts.map +1 -0
  20. package/dist/execution/shell.js +187 -0
  21. package/dist/execution/shell.js.map +1 -0
  22. package/dist/execution/template.d.ts +55 -0
  23. package/dist/execution/template.d.ts.map +1 -0
  24. package/dist/execution/template.js +106 -0
  25. package/dist/execution/template.js.map +1 -0
  26. package/dist/executor.d.ts +54 -0
  27. package/dist/executor.d.ts.map +1 -0
  28. package/dist/executor.js +314 -0
  29. package/dist/executor.js.map +1 -0
  30. package/dist/index.d.ts +22 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +359 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/logging.d.ts +24 -0
  35. package/dist/logging.d.ts.map +1 -0
  36. package/dist/logging.js +57 -0
  37. package/dist/logging.js.map +1 -0
  38. package/dist/schemas.d.ts +425 -0
  39. package/dist/schemas.d.ts.map +1 -0
  40. package/dist/schemas.js +150 -0
  41. package/dist/schemas.js.map +1 -0
  42. package/dist/types/hooks.d.ts +635 -0
  43. package/dist/types/hooks.d.ts.map +1 -0
  44. package/dist/types/hooks.js +12 -0
  45. package/dist/types/hooks.js.map +1 -0
  46. package/package.json +66 -0
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Agent configuration resolution and loading for command hooks
3
+ *
4
+ * Handles finding and parsing agent markdown files (.opencode/agent/*.md or
5
+ * ~/.config/opencode/agent/*.md) to extract command_hooks from YAML frontmatter.
6
+ * These hooks are applied when the specific subagent is invoked via the task tool.
7
+ */
8
+ import type { CommandHooksConfig } from "../types/hooks.js";
9
+ /**
10
+ * Resolve agent markdown file path by agent name
11
+ *
12
+ * Searches for agent markdown files in the following order:
13
+ * 1. Project-level: .opencode/agent/{name}.md
14
+ * 2. User-level: ~/.config/opencode/agent/{name}.md
15
+ *
16
+ * Returns the first existing path found, or null if no file exists.
17
+ *
18
+ * @param agentName - Name of the agent to resolve (without .md extension)
19
+ * @returns Promise resolving to absolute path of the agent markdown file, or null if not found
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const path = await resolveAgentPath("engineer");
24
+ * // Returns: "/Users/example/project/.opencode/agent/engineer.md" (if exists)
25
+ * // Or: "/Users/example/.config/opencode/agent/engineer.md" (if project path doesn't exist)
26
+ * // Or: null (if neither exists)
27
+ * ```
28
+ */
29
+ export declare function resolveAgentPath(agentName: string): Promise<string | null>;
30
+ /**
31
+ * Load command_hooks from an agent's markdown file
32
+ *
33
+ * Attempts to resolve the agent markdown file and extract command_hooks
34
+ * from its YAML frontmatter. Returns an empty config if the file doesn't
35
+ * exist or contains no valid hooks.
36
+ *
37
+ * **Caching:** This function uses the caching from loadMarkdownConfig() internally.
38
+ * Multiple calls for the same agent will only read the file once.
39
+ *
40
+ * Error handling:
41
+ * - If agent file doesn't exist: returns empty config
42
+ * - If file exists but has no frontmatter: returns empty config
43
+ * - If frontmatter is malformed: logs warning, returns empty config
44
+ * - If no command_hooks field: returns empty config
45
+ * - Never throws errors - always returns a valid config
46
+ *
47
+ * @param agentName - Name of the agent to load configuration for
48
+ * @returns Promise resolving to CommandHooksConfig (may be empty)
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const config = await loadAgentConfig("engineer");
53
+ * // Returns: { tool: [...], session: [...] } with agent-specific hooks
54
+ * // Or: { tool: [], session: [] } if no valid hooks found
55
+ * ```
56
+ */
57
+ export declare function loadAgentConfig(agentName: string): Promise<CommandHooksConfig>;
58
+ /**
59
+ * Load and merge agent-specific configuration with global configuration
60
+ *
61
+ * Combines global command hooks with agent-specific hooks, where agent hooks
62
+ * take precedence for the specific agent context. This is useful when you want
63
+ * to apply both global hooks and agent-specific hooks together.
64
+ *
65
+ * The merge follows the same precedence rules as mergeConfigs:
66
+ * - Agent hooks with the same ID replace global hooks
67
+ * - Agent hooks with unique IDs are added alongside global hooks
68
+ *
69
+ * @param agentName - Name of the agent to load configuration for
70
+ * @returns Promise resolving to merged CommandHooksConfig
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * const { config } = await loadAgentConfigWithGlobal("engineer");
75
+ * // Returns merged config with both global and engineer-specific hooks
76
+ * ```
77
+ */
78
+ export declare function loadAgentConfigWithGlobal(agentName: string): Promise<{
79
+ config: CommandHooksConfig;
80
+ agentPath: string | null;
81
+ }>;
82
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/config/agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAM5D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqChF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAqBpF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,MAAM,EAAE,kBAAkB,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAanE"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Agent configuration resolution and loading for command hooks
3
+ *
4
+ * Handles finding and parsing agent markdown files (.opencode/agent/*.md or
5
+ * ~/.config/opencode/agent/*.md) to extract command_hooks from YAML frontmatter.
6
+ * These hooks are applied when the specific subagent is invoked via the task tool.
7
+ */
8
+ import { join } from "path";
9
+ import { homedir } from "os";
10
+ import { loadMarkdownConfig } from "./markdown.js";
11
+ import { logger } from "../logging.js";
12
+ /**
13
+ * Resolve agent markdown file path by agent name
14
+ *
15
+ * Searches for agent markdown files in the following order:
16
+ * 1. Project-level: .opencode/agent/{name}.md
17
+ * 2. User-level: ~/.config/opencode/agent/{name}.md
18
+ *
19
+ * Returns the first existing path found, or null if no file exists.
20
+ *
21
+ * @param agentName - Name of the agent to resolve (without .md extension)
22
+ * @returns Promise resolving to absolute path of the agent markdown file, or null if not found
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const path = await resolveAgentPath("engineer");
27
+ * // Returns: "/Users/example/project/.opencode/agent/engineer.md" (if exists)
28
+ * // Or: "/Users/example/.config/opencode/agent/engineer.md" (if project path doesn't exist)
29
+ * // Or: null (if neither exists)
30
+ * ```
31
+ */
32
+ export async function resolveAgentPath(agentName) {
33
+ // Validate agent name to prevent directory traversal
34
+ if (!agentName || agentName.includes("/") || agentName.includes("..")) {
35
+ logger.debug(`Invalid agent name: ${agentName}`);
36
+ return null;
37
+ }
38
+ const agentFileName = `${agentName}.md`;
39
+ // Check project-level agent file
40
+ const projectAgentPath = join(process.cwd(), ".opencode", "agent", agentFileName);
41
+ try {
42
+ const projectFile = Bun.file(projectAgentPath);
43
+ if (await projectFile.exists()) {
44
+ logger.debug(`Found project agent file: ${projectAgentPath}`);
45
+ return projectAgentPath;
46
+ }
47
+ }
48
+ catch (error) {
49
+ const message = error instanceof Error ? error.message : String(error);
50
+ logger.debug(`Error checking project agent file ${projectAgentPath}: ${message}`);
51
+ }
52
+ // Check user-level agent file
53
+ const userAgentPath = join(homedir(), ".config", "opencode", "agent", agentFileName);
54
+ try {
55
+ const userFile = Bun.file(userAgentPath);
56
+ if (await userFile.exists()) {
57
+ logger.debug(`Found user agent file: ${userAgentPath}`);
58
+ return userAgentPath;
59
+ }
60
+ }
61
+ catch (error) {
62
+ const message = error instanceof Error ? error.message : String(error);
63
+ logger.debug(`Error checking user agent file ${userAgentPath}: ${message}`);
64
+ }
65
+ logger.debug(`No agent file found for: ${agentName}`);
66
+ return null;
67
+ }
68
+ /**
69
+ * Load command_hooks from an agent's markdown file
70
+ *
71
+ * Attempts to resolve the agent markdown file and extract command_hooks
72
+ * from its YAML frontmatter. Returns an empty config if the file doesn't
73
+ * exist or contains no valid hooks.
74
+ *
75
+ * **Caching:** This function uses the caching from loadMarkdownConfig() internally.
76
+ * Multiple calls for the same agent will only read the file once.
77
+ *
78
+ * Error handling:
79
+ * - If agent file doesn't exist: returns empty config
80
+ * - If file exists but has no frontmatter: returns empty config
81
+ * - If frontmatter is malformed: logs warning, returns empty config
82
+ * - If no command_hooks field: returns empty config
83
+ * - Never throws errors - always returns a valid config
84
+ *
85
+ * @param agentName - Name of the agent to load configuration for
86
+ * @returns Promise resolving to CommandHooksConfig (may be empty)
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * const config = await loadAgentConfig("engineer");
91
+ * // Returns: { tool: [...], session: [...] } with agent-specific hooks
92
+ * // Or: { tool: [], session: [] } if no valid hooks found
93
+ * ```
94
+ */
95
+ export async function loadAgentConfig(agentName) {
96
+ // Resolve the agent path
97
+ const agentPath = await resolveAgentPath(agentName);
98
+ if (!agentPath) {
99
+ logger.debug(`No agent file found for: ${agentName}, returning empty config`);
100
+ return { tool: [], session: [] };
101
+ }
102
+ // Load the markdown config using the existing function
103
+ const config = await loadMarkdownConfig(agentPath);
104
+ if (config.tool?.length === 0 && config.session?.length === 0) {
105
+ logger.debug(`Agent ${agentName} has no command_hooks in frontmatter`);
106
+ }
107
+ else {
108
+ logger.debug(`Loaded agent config for ${agentName}: ${config.tool?.length ?? 0} tool hooks, ${config.session?.length ?? 0} session hooks`);
109
+ }
110
+ return config;
111
+ }
112
+ /**
113
+ * Load and merge agent-specific configuration with global configuration
114
+ *
115
+ * Combines global command hooks with agent-specific hooks, where agent hooks
116
+ * take precedence for the specific agent context. This is useful when you want
117
+ * to apply both global hooks and agent-specific hooks together.
118
+ *
119
+ * The merge follows the same precedence rules as mergeConfigs:
120
+ * - Agent hooks with the same ID replace global hooks
121
+ * - Agent hooks with unique IDs are added alongside global hooks
122
+ *
123
+ * @param agentName - Name of the agent to load configuration for
124
+ * @returns Promise resolving to merged CommandHooksConfig
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * const { config } = await loadAgentConfigWithGlobal("engineer");
129
+ * // Returns merged config with both global and engineer-specific hooks
130
+ * ```
131
+ */
132
+ export async function loadAgentConfigWithGlobal(agentName) {
133
+ const [globalConfig, agentConfig] = await Promise.all([
134
+ import("./global.js").then((m) => m.loadGlobalConfig()),
135
+ loadAgentConfig(agentName),
136
+ ]);
137
+ return {
138
+ config: {
139
+ tool: [...(globalConfig.tool ?? []), ...(agentConfig.tool ?? [])],
140
+ session: [...(globalConfig.session ?? []), ...(agentConfig.session ?? [])],
141
+ },
142
+ agentPath: await resolveAgentPath(agentName),
143
+ };
144
+ }
145
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/config/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Global configuration parser for loading hooks from .opencode/command-hooks.jsonc
3
+ *
4
+ * Searches for .opencode/command-hooks.jsonc starting from the current working
5
+ * directory and walking up the directory tree. Parses JSONC format as CommandHooksConfig.
6
+ */
7
+ import type { CommandHooksConfig } from "../types/hooks.js";
8
+ /**
9
+ * Load and parse global command hooks configuration
10
+ *
11
+ * Searches for .opencode/command-hooks.jsonc starting from the current working
12
+ * directory and walking up. Parses the entire file as CommandHooksConfig.
13
+ *
14
+ * **Caching:** This function implements in-memory caching to avoid repeated file
15
+ * system reads on every tool call. The cache is checked first; if null, the config
16
+ * is loaded from disk and cached for subsequent calls.
17
+ *
18
+ * Error handling:
19
+ * - If no config file found: returns empty config (not an error)
20
+ * - If config file is malformed: logs warning, returns empty config
21
+ * - If file is not a valid CommandHooksConfig: logs warning, returns empty config
22
+ * - Never throws errors - always returns a valid config
23
+ *
24
+ * @returns Promise resolving to CommandHooksConfig (may be empty)
25
+ */
26
+ export declare function loadGlobalConfig(): Promise<CommandHooksConfig>;
27
+ /**
28
+ * Clear the global config cache
29
+ *
30
+ * Forces the next call to loadGlobalConfig() to reload from disk.
31
+ * Useful for testing or when config files may have changed.
32
+ *
33
+ * @internal For testing purposes
34
+ */
35
+ export declare function clearGlobalConfigCache(): void;
36
+ //# sourceMappingURL=global.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global.d.ts","sourceRoot":"","sources":["../../src/config/global.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AA0I5D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAmFpE;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C"}
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Global configuration parser for loading hooks from .opencode/command-hooks.jsonc
3
+ *
4
+ * Searches for .opencode/command-hooks.jsonc starting from the current working
5
+ * directory and walking up the directory tree. Parses JSONC format as CommandHooksConfig.
6
+ */
7
+ import { join, dirname } from "path";
8
+ import { logger } from "../logging.js";
9
+ /**
10
+ * In-memory cache for global configuration
11
+ * Stores the loaded config to avoid repeated file system reads on every tool call.
12
+ * Set to null to force a reload on the next loadGlobalConfig() call.
13
+ */
14
+ let cachedConfig = null;
15
+ /**
16
+ * Strip comments from JSONC content
17
+ * Handles both line comments and block comments
18
+ */
19
+ function stripJsoncComments(content) {
20
+ let result = "";
21
+ let i = 0;
22
+ while (i < content.length) {
23
+ // Check for line comment
24
+ if (content[i] === "/" && content[i + 1] === "/") {
25
+ // Skip until end of line
26
+ while (i < content.length && content[i] !== "\n") {
27
+ i++;
28
+ }
29
+ // Keep the newline
30
+ if (i < content.length) {
31
+ result += "\n";
32
+ i++;
33
+ }
34
+ continue;
35
+ }
36
+ // Check for block comment
37
+ if (content[i] === "/" && content[i + 1] === "*") {
38
+ // Skip until */
39
+ i += 2;
40
+ while (i < content.length - 1) {
41
+ if (content[i] === "*" && content[i + 1] === "/") {
42
+ i += 2;
43
+ break;
44
+ }
45
+ // Preserve newlines to maintain line numbers
46
+ if (content[i] === "\n") {
47
+ result += "\n";
48
+ }
49
+ i++;
50
+ }
51
+ continue;
52
+ }
53
+ // Regular character
54
+ result += content[i];
55
+ i++;
56
+ }
57
+ return result;
58
+ }
59
+ /**
60
+ * Parse JSON content, handling parse errors gracefully
61
+ */
62
+ function parseJson(content) {
63
+ try {
64
+ return JSON.parse(content);
65
+ }
66
+ catch (error) {
67
+ const message = error instanceof Error ? error.message : String(error);
68
+ throw new Error(`Failed to parse JSON: ${message}`);
69
+ }
70
+ }
71
+ /**
72
+ * Check if a value is a valid CommandHooksConfig object
73
+ */
74
+ function isValidCommandHooksConfig(value) {
75
+ if (typeof value !== "object" || value === null) {
76
+ return false;
77
+ }
78
+ const obj = value;
79
+ // Both tool and session are optional
80
+ if (obj.tool !== undefined && !Array.isArray(obj.tool)) {
81
+ return false;
82
+ }
83
+ if (obj.session !== undefined && !Array.isArray(obj.session)) {
84
+ return false;
85
+ }
86
+ return true;
87
+ }
88
+ /**
89
+ * Find command hooks config file by walking up directory tree
90
+ * Looks for .opencode/command-hooks.jsonc
91
+ */
92
+ async function findConfigFile(startDir) {
93
+ let currentDir = startDir;
94
+ // Limit search depth to avoid infinite loops
95
+ const maxDepth = 20;
96
+ let depth = 0;
97
+ while (depth < maxDepth) {
98
+ // Try .opencode/command-hooks.jsonc
99
+ const configPath = join(currentDir, ".opencode", "command-hooks.jsonc");
100
+ try {
101
+ const file = Bun.file(configPath);
102
+ if (await file.exists()) {
103
+ logger.debug(`Found config file: ${configPath}`);
104
+ return configPath;
105
+ }
106
+ }
107
+ catch {
108
+ // Continue searching
109
+ }
110
+ // Move up one directory
111
+ const parentDir = dirname(currentDir);
112
+ if (parentDir === currentDir) {
113
+ // Reached filesystem root
114
+ break;
115
+ }
116
+ currentDir = parentDir;
117
+ depth++;
118
+ }
119
+ logger.debug(`No config file found after searching ${depth} directories`);
120
+ return null;
121
+ }
122
+ /**
123
+ * Load and parse global command hooks configuration
124
+ *
125
+ * Searches for .opencode/command-hooks.jsonc starting from the current working
126
+ * directory and walking up. Parses the entire file as CommandHooksConfig.
127
+ *
128
+ * **Caching:** This function implements in-memory caching to avoid repeated file
129
+ * system reads on every tool call. The cache is checked first; if null, the config
130
+ * is loaded from disk and cached for subsequent calls.
131
+ *
132
+ * Error handling:
133
+ * - If no config file found: returns empty config (not an error)
134
+ * - If config file is malformed: logs warning, returns empty config
135
+ * - If file is not a valid CommandHooksConfig: logs warning, returns empty config
136
+ * - Never throws errors - always returns a valid config
137
+ *
138
+ * @returns Promise resolving to CommandHooksConfig (may be empty)
139
+ */
140
+ export async function loadGlobalConfig() {
141
+ // Check cache first
142
+ if (cachedConfig !== null) {
143
+ logger.debug(`Returning cached global config: ${cachedConfig.tool?.length ?? 0} tool hooks, ${cachedConfig.session?.length ?? 0} session hooks`);
144
+ return cachedConfig;
145
+ }
146
+ try {
147
+ // Find config file
148
+ const configPath = await findConfigFile(process.cwd());
149
+ if (!configPath) {
150
+ logger.debug(`No .opencode/command-hooks.jsonc file found, using empty config`);
151
+ const emptyConfig = { tool: [], session: [] };
152
+ cachedConfig = emptyConfig;
153
+ return emptyConfig;
154
+ }
155
+ // Read file
156
+ let content;
157
+ try {
158
+ const file = Bun.file(configPath);
159
+ content = await file.text();
160
+ }
161
+ catch (error) {
162
+ const message = error instanceof Error ? error.message : String(error);
163
+ logger.info(`Failed to read config file ${configPath}: ${message}`);
164
+ const emptyConfig = { tool: [], session: [] };
165
+ cachedConfig = emptyConfig;
166
+ return emptyConfig;
167
+ }
168
+ // Parse JSONC
169
+ let parsed;
170
+ try {
171
+ const stripped = stripJsoncComments(content);
172
+ parsed = parseJson(stripped);
173
+ }
174
+ catch (error) {
175
+ const message = error instanceof Error ? error.message : String(error);
176
+ logger.info(`Failed to parse config file ${configPath}: ${message}`);
177
+ const emptyConfig = { tool: [], session: [] };
178
+ cachedConfig = emptyConfig;
179
+ return emptyConfig;
180
+ }
181
+ // Validate entire file as CommandHooksConfig
182
+ if (!isValidCommandHooksConfig(parsed)) {
183
+ logger.info(`Config file is not a valid CommandHooksConfig (expected { tool?: [], session?: [] }), using empty config`);
184
+ const emptyConfig = { tool: [], session: [] };
185
+ cachedConfig = emptyConfig;
186
+ return emptyConfig;
187
+ }
188
+ // Return with defaults for missing arrays
189
+ const result = {
190
+ tool: parsed.tool ?? [],
191
+ session: parsed.session ?? [],
192
+ };
193
+ logger.debug(`Loaded global config: ${result.tool?.length ?? 0} tool hooks, ${result.session?.length ?? 0} session hooks`);
194
+ // Cache the result
195
+ cachedConfig = result;
196
+ return result;
197
+ }
198
+ catch (error) {
199
+ // Catch-all for unexpected errors
200
+ const message = error instanceof Error ? error.message : String(error);
201
+ logger.info(`Unexpected error loading global config: ${message}`);
202
+ const emptyConfig = { tool: [], session: [] };
203
+ cachedConfig = emptyConfig;
204
+ return emptyConfig;
205
+ }
206
+ }
207
+ /**
208
+ * Clear the global config cache
209
+ *
210
+ * Forces the next call to loadGlobalConfig() to reload from disk.
211
+ * Useful for testing or when config files may have changed.
212
+ *
213
+ * @internal For testing purposes
214
+ */
215
+ export function clearGlobalConfigCache() {
216
+ logger.debug("Clearing global config cache");
217
+ cachedConfig = null;
218
+ }
219
+ //# sourceMappingURL=global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global.js","sourceRoot":"","sources":["../../src/config/global.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Markdown configuration parser for loading hooks from agent and slash-command markdown files
3
+ *
4
+ * Parses YAML frontmatter from markdown files and extracts command_hooks configuration.
5
+ * Supports both agent markdown files (typically in .opencode/agents/) and slash-command
6
+ * markdown files (typically in .opencode/commands/).
7
+ */
8
+ import type { AgentHooks, CommandHooksConfig } from "../types/hooks.js";
9
+ /**
10
+ * Extract YAML frontmatter from markdown content
11
+ *
12
+ * Frontmatter is defined as content between the first `---` and second `---`
13
+ * at the start of the file. Returns the raw YAML string (without delimiters).
14
+ *
15
+ * @param content - Full markdown file content
16
+ * @returns Raw YAML string, or null if no frontmatter found
17
+ *
18
+ * @example
19
+ * ```
20
+ * ---
21
+ * name: my-agent
22
+ * command_hooks:
23
+ * tool: [...]
24
+ * ---
25
+ *
26
+ * # Agent content
27
+ * ```
28
+ * Returns the YAML between the delimiters
29
+ */
30
+ export declare function extractYamlFrontmatter(content: string): string | null;
31
+ /**
32
+ * Parse YAML content and return the parsed object
33
+ *
34
+ * Handles YAML parsing errors gracefully by returning null.
35
+ * Does not throw errors - callers should check for null return value.
36
+ *
37
+ * @param yamlContent - Raw YAML string to parse
38
+ * @returns Parsed YAML object, or null if parsing failed
39
+ */
40
+ export declare function parseYamlFrontmatter(content: string): unknown;
41
+ /**
42
+ * Parse simplified agent hooks from YAML frontmatter content
43
+ *
44
+ * Extracts and validates the new simplified `hooks` format from agent markdown
45
+ * frontmatter. Returns null if no hooks are present or if parsing fails.
46
+ *
47
+ * @param yamlContent - Raw YAML string from frontmatter
48
+ * @param agentName - Name of the agent (used for auto-generating hook IDs)
49
+ * @returns Parsed AgentHooks object, or null if no valid hooks found
50
+ *
51
+ * @example
52
+ * ```yaml
53
+ * hooks:
54
+ * before:
55
+ * - run: "echo starting"
56
+ * after:
57
+ * - run: ["npm run test"]
58
+ * inject: "Results:\n{stdout}"
59
+ * ```
60
+ */
61
+ export declare function parseAgentHooks(yamlContent: string): AgentHooks | null;
62
+ /**
63
+ * Convert simplified agent hooks to internal CommandHooksConfig format
64
+ *
65
+ * Takes the simplified AgentHooks format and converts it to the internal
66
+ * ToolHook[] format with auto-generated IDs and proper when clauses.
67
+ *
68
+ * @param agentHooks - Simplified agent hooks configuration
69
+ * @param agentName - Name of the agent (used for hook ID generation)
70
+ * @returns CommandHooksConfig with tool hooks converted to internal format
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * const simpleHooks: AgentHooks = {
75
+ * after: [{ run: "npm run test", inject: "Results: {stdout}" }]
76
+ * };
77
+ * const config = convertToCommandHooksConfig(simpleHooks, "engineer");
78
+ * // Results in: { tool: [{ id: "engineer-after-0", when: {...}, run: ..., inject: ... }] }
79
+ * ```
80
+ */
81
+ export declare function convertToCommandHooksConfig(agentHooks: AgentHooks, agentName: string): CommandHooksConfig;
82
+ /**
83
+ * Load and parse command hooks configuration from a markdown file
84
+ *
85
+ * Reads a markdown file, extracts YAML frontmatter, parses it, and extracts
86
+ * either the new simplified `hooks` format or the legacy `command_hooks` format.
87
+ *
88
+ * **Caching:** This function implements in-memory caching per file path to avoid
89
+ * repeated file reads. The cache is checked first; if not found, the file is read
90
+ * from disk and cached for subsequent calls.
91
+ *
92
+ * Error handling:
93
+ * - If file doesn't exist: returns empty config (not an error)
94
+ * - If no frontmatter found: returns empty config
95
+ * - If YAML is malformed: logs warning, returns empty config
96
+ * - If hooks format is invalid: logs warning, returns empty config
97
+ * - Never throws errors - always returns a valid config
98
+ *
99
+ * @param filePath - Absolute path to the markdown file
100
+ * @returns Promise resolving to CommandHooksConfig (may be empty)
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * const config = await loadMarkdownConfig("/path/to/agent.md");
105
+ * // Returns { tool: [...], session: [...] } or { tool: [], session: [] }
106
+ * ```
107
+ */
108
+ export declare function loadMarkdownConfig(filePath: string): Promise<CommandHooksConfig>;
109
+ /**
110
+ * Clear the markdown config cache for a specific file
111
+ *
112
+ * Forces the next call to loadMarkdownConfig() for this file to reload from disk.
113
+ * Useful for testing or when config files may have changed.
114
+ *
115
+ * @param filePath - Path to clear from cache, or undefined to clear all
116
+ * @internal For testing purposes
117
+ */
118
+ export declare function clearMarkdownConfigCache(filePath?: string): void;
119
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/config/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAkB,kBAAkB,EAAY,MAAM,mBAAmB,CAAC;AAWlG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAS7D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,GAClB,UAAU,GAAG,IAAI,CA8CnB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,GAChB,kBAAkB,CAqCpB;AA2ED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,kBAAkB,CACrC,QAAQ,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CA+H7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAQhE"}