wave-agent-sdk 0.0.5 → 0.0.6

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 (140) hide show
  1. package/dist/agent.d.ts +3 -6
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +21 -21
  4. package/dist/index.d.ts +3 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +3 -3
  7. package/dist/managers/aiManager.d.ts +4 -2
  8. package/dist/managers/aiManager.d.ts.map +1 -1
  9. package/dist/managers/aiManager.js +84 -47
  10. package/dist/managers/backgroundBashManager.d.ts +1 -1
  11. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  12. package/dist/{hooks/manager.d.ts → managers/hookManager.d.ts} +26 -7
  13. package/dist/managers/hookManager.d.ts.map +1 -0
  14. package/dist/{hooks/manager.js → managers/hookManager.js} +107 -17
  15. package/dist/managers/mcpManager.d.ts +1 -1
  16. package/dist/managers/mcpManager.d.ts.map +1 -1
  17. package/dist/managers/messageManager.d.ts +17 -4
  18. package/dist/managers/messageManager.d.ts.map +1 -1
  19. package/dist/managers/messageManager.js +13 -5
  20. package/dist/managers/skillManager.d.ts +1 -1
  21. package/dist/managers/skillManager.d.ts.map +1 -1
  22. package/dist/managers/slashCommandManager.d.ts +1 -1
  23. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  24. package/dist/managers/subagentManager.d.ts +7 -12
  25. package/dist/managers/subagentManager.d.ts.map +1 -1
  26. package/dist/managers/subagentManager.js +39 -45
  27. package/dist/managers/toolManager.d.ts +1 -1
  28. package/dist/managers/toolManager.d.ts.map +1 -1
  29. package/dist/services/aiService.d.ts +1 -1
  30. package/dist/services/aiService.d.ts.map +1 -1
  31. package/dist/services/aiService.js +8 -1
  32. package/dist/services/hook.d.ts +56 -0
  33. package/dist/services/hook.d.ts.map +1 -0
  34. package/dist/services/hook.js +276 -0
  35. package/dist/services/session.d.ts +1 -1
  36. package/dist/services/session.d.ts.map +1 -1
  37. package/dist/services/session.js +5 -4
  38. package/dist/tools/taskTool.d.ts.map +1 -1
  39. package/dist/tools/taskTool.js +7 -3
  40. package/dist/types/commands.d.ts +24 -0
  41. package/dist/types/commands.d.ts.map +1 -0
  42. package/dist/types/commands.js +5 -0
  43. package/dist/types/config.d.ts +13 -0
  44. package/dist/types/config.d.ts.map +1 -0
  45. package/dist/types/config.js +5 -0
  46. package/dist/types/core.d.ts +38 -0
  47. package/dist/types/core.d.ts.map +1 -0
  48. package/dist/{types.js → types/core.js} +4 -13
  49. package/dist/{hooks/types.d.ts → types/hooks.d.ts} +2 -1
  50. package/dist/types/hooks.d.ts.map +1 -0
  51. package/dist/types/index.d.ts +20 -0
  52. package/dist/types/index.d.ts.map +1 -0
  53. package/dist/types/index.js +21 -0
  54. package/dist/types/mcp.d.ts +28 -0
  55. package/dist/types/mcp.d.ts.map +1 -0
  56. package/dist/types/mcp.js +5 -0
  57. package/dist/types/messaging.d.ts +80 -0
  58. package/dist/types/messaging.d.ts.map +1 -0
  59. package/dist/types/messaging.js +5 -0
  60. package/dist/types/processes.d.ts +17 -0
  61. package/dist/types/processes.d.ts.map +1 -0
  62. package/dist/types/processes.js +5 -0
  63. package/dist/types/skills.d.ts +78 -0
  64. package/dist/types/skills.d.ts.map +1 -0
  65. package/dist/types/skills.js +17 -0
  66. package/dist/utils/configResolver.d.ts +1 -1
  67. package/dist/utils/configResolver.d.ts.map +1 -1
  68. package/dist/utils/configResolver.js +1 -1
  69. package/dist/utils/configValidator.d.ts +1 -1
  70. package/dist/utils/configValidator.d.ts.map +1 -1
  71. package/dist/utils/configValidator.js +1 -1
  72. package/dist/utils/convertMessagesForAPI.d.ts +1 -1
  73. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
  74. package/dist/utils/customCommands.d.ts +1 -1
  75. package/dist/utils/customCommands.d.ts.map +1 -1
  76. package/dist/{hooks/matcher.d.ts → utils/hookMatcher.d.ts} +1 -1
  77. package/dist/utils/hookMatcher.d.ts.map +1 -0
  78. package/dist/utils/markdownParser.d.ts +1 -1
  79. package/dist/utils/markdownParser.d.ts.map +1 -1
  80. package/dist/utils/mcpUtils.d.ts +1 -1
  81. package/dist/utils/mcpUtils.d.ts.map +1 -1
  82. package/dist/utils/messageOperations.d.ts +6 -1
  83. package/dist/utils/messageOperations.d.ts.map +1 -1
  84. package/dist/utils/messageOperations.js +16 -0
  85. package/dist/utils/skillParser.d.ts +1 -1
  86. package/dist/utils/skillParser.d.ts.map +1 -1
  87. package/package.json +1 -1
  88. package/src/agent.ts +49 -43
  89. package/src/index.ts +3 -4
  90. package/src/managers/aiManager.ts +240 -158
  91. package/src/managers/backgroundBashManager.ts +1 -1
  92. package/src/{hooks/manager.ts → managers/hookManager.ts} +159 -26
  93. package/src/managers/mcpManager.ts +1 -1
  94. package/src/managers/messageManager.ts +36 -6
  95. package/src/managers/skillManager.ts +1 -1
  96. package/src/managers/slashCommandManager.ts +5 -1
  97. package/src/managers/subagentManager.ts +46 -53
  98. package/src/managers/toolManager.ts +1 -1
  99. package/src/services/aiService.ts +9 -2
  100. package/src/services/hook.ts +360 -0
  101. package/src/services/session.ts +6 -7
  102. package/src/tools/taskTool.ts +13 -5
  103. package/src/types/commands.ts +26 -0
  104. package/src/types/config.ts +14 -0
  105. package/src/types/core.ts +49 -0
  106. package/src/{hooks/types.ts → types/hooks.ts} +1 -0
  107. package/src/types/index.ts +23 -0
  108. package/src/types/mcp.ts +31 -0
  109. package/src/types/messaging.ts +103 -0
  110. package/src/types/processes.ts +18 -0
  111. package/src/types/skills.ts +91 -0
  112. package/src/utils/configResolver.ts +1 -1
  113. package/src/utils/configValidator.ts +5 -1
  114. package/src/utils/convertMessagesForAPI.ts +1 -1
  115. package/src/utils/customCommands.ts +1 -1
  116. package/src/utils/markdownParser.ts +1 -1
  117. package/src/utils/mcpUtils.ts +1 -1
  118. package/src/utils/messageOperations.ts +20 -1
  119. package/src/utils/skillParser.ts +1 -1
  120. package/dist/hooks/executor.d.ts +0 -56
  121. package/dist/hooks/executor.d.ts.map +0 -1
  122. package/dist/hooks/executor.js +0 -312
  123. package/dist/hooks/index.d.ts +0 -17
  124. package/dist/hooks/index.d.ts.map +0 -1
  125. package/dist/hooks/index.js +0 -14
  126. package/dist/hooks/manager.d.ts.map +0 -1
  127. package/dist/hooks/matcher.d.ts.map +0 -1
  128. package/dist/hooks/settings.d.ts +0 -46
  129. package/dist/hooks/settings.d.ts.map +0 -1
  130. package/dist/hooks/settings.js +0 -100
  131. package/dist/hooks/types.d.ts.map +0 -1
  132. package/dist/types.d.ts +0 -288
  133. package/dist/types.d.ts.map +0 -1
  134. package/src/hooks/executor.ts +0 -440
  135. package/src/hooks/index.ts +0 -52
  136. package/src/hooks/settings.ts +0 -129
  137. /package/dist/{hooks/types.js → types/hooks.js} +0 -0
  138. /package/dist/{hooks/matcher.js → utils/hookMatcher.js} +0 -0
  139. /package/src/{types.ts → types/index.ts.backup} +0 -0
  140. /package/src/{hooks/matcher.ts → utils/hookMatcher.ts} +0 -0
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Background process and shell management types
3
+ * Dependencies: None
4
+ */
5
+
6
+ import type { ChildProcess } from "child_process";
7
+
8
+ export interface BackgroundShell {
9
+ id: string;
10
+ process: ChildProcess;
11
+ command: string;
12
+ startTime: number;
13
+ status: "running" | "completed" | "killed";
14
+ stdout: string;
15
+ stderr: string;
16
+ exitCode?: number;
17
+ runtime?: number;
18
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Skill system types and constants
3
+ * Dependencies: Core (Logger)
4
+ */
5
+
6
+ import type { Logger } from "./core.js";
7
+
8
+ export interface SkillMetadata {
9
+ name: string;
10
+ description: string;
11
+ type: "personal" | "project";
12
+ skillPath: string;
13
+ }
14
+
15
+ export interface Skill extends SkillMetadata {
16
+ content: string;
17
+ frontmatter: SkillFrontmatter;
18
+ isValid: boolean;
19
+ errors: string[];
20
+ }
21
+
22
+ export interface SkillFrontmatter {
23
+ name: string;
24
+ description: string;
25
+ [key: string]: unknown;
26
+ }
27
+
28
+ export interface SkillCollection {
29
+ type: "personal" | "project";
30
+ basePath: string;
31
+ skills: Map<string, SkillMetadata>;
32
+ errors: SkillError[];
33
+ }
34
+
35
+ export interface SkillError {
36
+ skillPath: string;
37
+ message: string;
38
+ }
39
+
40
+ export interface SkillValidationResult {
41
+ isValid: boolean;
42
+ skill?: Skill;
43
+ errors: string[];
44
+ }
45
+
46
+ export interface SkillDiscoveryResult {
47
+ personalSkills: Map<string, SkillMetadata>;
48
+ projectSkills: Map<string, SkillMetadata>;
49
+ errors: SkillError[];
50
+ }
51
+
52
+ export interface SkillInvocationContext {
53
+ skillName: string;
54
+ }
55
+
56
+ export interface SkillToolArgs {
57
+ skill_name: string;
58
+ }
59
+
60
+ export interface SkillManagerOptions {
61
+ personalSkillsPath?: string;
62
+ scanTimeout?: number;
63
+ logger?: Logger;
64
+ }
65
+
66
+ export interface ParsedSkillFile {
67
+ frontmatter: SkillFrontmatter;
68
+ content: string;
69
+ skillMetadata: SkillMetadata;
70
+ validationErrors: string[];
71
+ isValid: boolean;
72
+ }
73
+
74
+ export interface SkillParseOptions {
75
+ validateMetadata?: boolean;
76
+ basePath?: string;
77
+ }
78
+
79
+ export const SKILL_DEFAULTS = {
80
+ PERSONAL_SKILLS_DIR: ".wave/skills",
81
+ PROJECT_SKILLS_DIR: ".wave/skills",
82
+ SKILL_FILE_NAME: "SKILL.md",
83
+ MAX_NAME_LENGTH: 64,
84
+ MAX_DESCRIPTION_LENGTH: 1024,
85
+ MIN_DESCRIPTION_LENGTH: 1,
86
+ NAME_PATTERN: /^[a-z0-9-]+$/,
87
+ MAX_METADATA_CACHE: 1000,
88
+ MAX_CONTENT_CACHE: 100,
89
+ SCAN_TIMEOUT: 5000,
90
+ LOAD_TIMEOUT: 2000,
91
+ } as const;
@@ -8,7 +8,7 @@ import {
8
8
  ModelConfig,
9
9
  ConfigurationError,
10
10
  CONFIG_ERRORS,
11
- } from "../types.js";
11
+ } from "../types/index.js";
12
12
 
13
13
  export class ConfigResolver {
14
14
  /**
@@ -3,7 +3,11 @@
3
3
  * Validates configuration values for correctness and security
4
4
  */
5
5
 
6
- import { GatewayConfig, ConfigurationError, CONFIG_ERRORS } from "../types.js";
6
+ import {
7
+ GatewayConfig,
8
+ ConfigurationError,
9
+ CONFIG_ERRORS,
10
+ } from "../types/index.js";
7
11
 
8
12
  export class ConfigValidator {
9
13
  /**
@@ -1,4 +1,4 @@
1
- import type { Message } from "../types.js";
1
+ import type { Message } from "../types/index.js";
2
2
  import { convertImageToBase64 } from "./messageOperations.js";
3
3
  import { ChatCompletionMessageToolCall } from "openai/resources";
4
4
  import { stripAnsiColors } from "./stringUtils.js";
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readdirSync } from "fs";
2
2
  import { join, extname, basename } from "path";
3
3
  import { homedir } from "os";
4
- import type { CustomSlashCommand } from "../types.js";
4
+ import type { CustomSlashCommand } from "../types/index.js";
5
5
  import { parseMarkdownFile } from "./markdownParser.js";
6
6
 
7
7
  /**
@@ -1,5 +1,5 @@
1
1
  import { readFileSync } from "fs";
2
- import type { CustomSlashCommandConfig } from "../types.js";
2
+ import type { CustomSlashCommandConfig } from "../types/index.js";
3
3
 
4
4
  interface ParsedMarkdownFile {
5
5
  content: string;
@@ -1,6 +1,6 @@
1
1
  import { ChatCompletionFunctionTool } from "openai/resources.js";
2
2
  import type { ToolPlugin, ToolResult, ToolContext } from "../tools/types.js";
3
- import type { McpTool, McpServerStatus } from "../types.js";
3
+ import type { McpTool, McpServerStatus } from "../types/index.js";
4
4
 
5
5
  /**
6
6
  * Convert MCP tool to OpenAI function tool format
@@ -1,4 +1,4 @@
1
- import type { Message, Usage } from "../types.js";
1
+ import type { Message, Usage } from "../types/index.js";
2
2
  import { readFileSync } from "fs";
3
3
  import { extname } from "path";
4
4
  import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
@@ -586,3 +586,22 @@ export const updateSubagentBlockInMessage = (
586
586
 
587
587
  return newMessages;
588
588
  };
589
+
590
+ /**
591
+ * Removes the last user message from the messages array
592
+ * Used for hook error handling when the user prompt needs to be erased
593
+ */
594
+ export const removeLastUserMessage = (messages: Message[]): Message[] => {
595
+ const newMessages = [...messages];
596
+
597
+ // Find the index of the last user message
598
+ for (let i = newMessages.length - 1; i >= 0; i--) {
599
+ if (newMessages[i].role === "user") {
600
+ // Remove the user message at index i
601
+ newMessages.splice(i, 1);
602
+ break;
603
+ }
604
+ }
605
+
606
+ return newMessages;
607
+ };
@@ -5,7 +5,7 @@ import type {
5
5
  SkillParseOptions,
6
6
  SkillFrontmatter,
7
7
  SkillMetadata,
8
- } from "../types.js";
8
+ } from "../types/index.js";
9
9
 
10
10
  /**
11
11
  * Parse a SKILL.md file and validate its contents
@@ -1,56 +0,0 @@
1
- /**
2
- * Hook Command Executor
3
- *
4
- * Handles the execution of hook commands in isolated processes with proper
5
- * timeout handling, environment variable injection, and cross-platform support.
6
- */
7
- import { type HookExecutionContext, type HookExecutionResult, type HookExecutionOptions, type ExtendedHookExecutionContext } from "./types.js";
8
- import type { Logger } from "../types.js";
9
- export interface IHookExecutor {
10
- executeCommand(command: string, context: HookExecutionContext | ExtendedHookExecutionContext, options?: HookExecutionOptions): Promise<HookExecutionResult>;
11
- executeCommands(commands: string[], context: HookExecutionContext | ExtendedHookExecutionContext, options?: HookExecutionOptions): Promise<HookExecutionResult[]>;
12
- isCommandSafe(command: string): boolean;
13
- }
14
- export declare class HookExecutor implements IHookExecutor {
15
- private readonly defaultTimeout;
16
- private readonly maxTimeout;
17
- private readonly logger?;
18
- private readonly skipExecution;
19
- constructor(logger?: Logger, options?: {
20
- skipExecution?: boolean;
21
- });
22
- /**
23
- * Execute a single hook command in an isolated process
24
- */
25
- executeCommand(command: string, context: HookExecutionContext | ExtendedHookExecutionContext, options?: HookExecutionOptions): Promise<HookExecutionResult>;
26
- /**
27
- * Execute multiple commands in sequence
28
- * Stops on first failure unless configured otherwise
29
- */
30
- executeCommands(commands: string[], context: HookExecutionContext | ExtendedHookExecutionContext, options?: HookExecutionOptions): Promise<HookExecutionResult[]>;
31
- /**
32
- * Validate command safety to prevent injection attacks
33
- */
34
- isCommandSafe(command: string): boolean;
35
- /**
36
- * Build environment variables for hook execution
37
- */
38
- private buildEnvironment;
39
- /**
40
- * Resolve environment variables in command string
41
- */
42
- private resolveEnvironmentVariables;
43
- /**
44
- * Get process statistics for monitoring
45
- */
46
- getExecutionStats(): {
47
- platform: NodeJS.Platform;
48
- defaultTimeout: number;
49
- maxTimeout: number;
50
- };
51
- /**
52
- * Test if the executor can run commands on this platform
53
- */
54
- isSupported(): boolean;
55
- }
56
- //# sourceMappingURL=executor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/hooks/executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EAGlC,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAyC1C,MAAM,WAAW,aAAa;IAE5B,cAAc,CACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,EAC5D,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAGhC,eAAe,CACb,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,EAC5D,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAGlC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACzC;AAED,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;gBAE5B,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE;IASlE;;OAEG;IACG,cAAc,CAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,EAC5D,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,mBAAmB,CAAC;IAmM/B;;;OAGG;IACG,eAAe,CACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,EAC5D,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAmDjC;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAwBvC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAqBnC;;OAEG;IACH,iBAAiB,IAAI;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;QAC1B,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;KACpB;IAQD;;OAEG;IACH,WAAW,IAAI,OAAO;CAQvB"}
@@ -1,312 +0,0 @@
1
- /**
2
- * Hook Command Executor
3
- *
4
- * Handles the execution of hook commands in isolated processes with proper
5
- * timeout handling, environment variable injection, and cross-platform support.
6
- */
7
- import { spawn } from "child_process";
8
- import { getSessionFilePath, } from "./types.js";
9
- /**
10
- * Build JSON input data for hook stdin
11
- */
12
- function buildHookJsonInput(context) {
13
- const jsonInput = {
14
- session_id: context.sessionId || "unknown",
15
- transcript_path: context.transcriptPath ||
16
- (context.sessionId ? getSessionFilePath(context.sessionId) : ""),
17
- cwd: context.cwd || context.projectDir,
18
- hook_event_name: context.event,
19
- };
20
- // Add optional fields based on event type
21
- if (context.event === "PreToolUse" || context.event === "PostToolUse") {
22
- if (context.toolName) {
23
- jsonInput.tool_name = context.toolName;
24
- }
25
- if (context.toolInput !== undefined) {
26
- jsonInput.tool_input = context.toolInput;
27
- }
28
- }
29
- if (context.event === "PostToolUse" && context.toolResponse !== undefined) {
30
- jsonInput.tool_response = context.toolResponse;
31
- }
32
- if (context.event === "UserPromptSubmit" &&
33
- context.userPrompt !== undefined) {
34
- jsonInput.user_prompt = context.userPrompt;
35
- }
36
- return jsonInput;
37
- }
38
- export class HookExecutor {
39
- constructor(logger, options) {
40
- this.defaultTimeout = 10000; // 10 seconds
41
- this.maxTimeout = 300000; // 5 minutes
42
- this.logger = logger;
43
- // Skip execution in test environment unless we're specifically testing the executor
44
- this.skipExecution =
45
- options?.skipExecution ??
46
- ((process.env.NODE_ENV === "test" || process.env.VITEST === "true") &&
47
- !process.env.WAVE_TEST_HOOKS_EXECUTION);
48
- }
49
- /**
50
- * Execute a single hook command in an isolated process
51
- */
52
- async executeCommand(command, context, options = {}) {
53
- const startTime = Date.now();
54
- const timeout = Math.min(options.timeout ?? this.defaultTimeout, this.maxTimeout);
55
- const cwd = options.cwd ?? context.projectDir;
56
- // Skip command execution in test environment (unless specifically testing hooks)
57
- if (this.skipExecution) {
58
- this.logger?.debug(`[Hook] Skipping command execution: ${command}`);
59
- return {
60
- success: true,
61
- exitCode: 0,
62
- stdout: "Test environment: command execution skipped",
63
- duration: Date.now() - startTime,
64
- timedOut: false,
65
- };
66
- }
67
- // Log hook execution start
68
- this.logger?.debug(`[Hook] Executing ${context.event} hook: ${command}`);
69
- this.logger?.debug(`[Hook] Context: event=${context.event}, tool=${context.toolName || "N/A"}, cwd=${cwd}`);
70
- // Validate command safety
71
- if (!this.isCommandSafe(command)) {
72
- const error = "Command contains potentially unsafe characters";
73
- this.logger?.warn(`[Hook] Command safety validation failed: ${error}`);
74
- return {
75
- success: false,
76
- exitCode: -1,
77
- stderr: error,
78
- duration: Date.now() - startTime,
79
- timedOut: false,
80
- };
81
- }
82
- // Prepare environment variables
83
- const env = this.buildEnvironment(context);
84
- // Resolve command with environment variables
85
- const resolvedCommand = this.resolveEnvironmentVariables(command, env);
86
- // Prepare JSON input for stdin (if extended context is provided)
87
- const isExtendedContext = "sessionId" in context ||
88
- "toolInput" in context ||
89
- "toolResponse" in context ||
90
- "userPrompt" in context;
91
- const jsonInput = isExtendedContext
92
- ? buildHookJsonInput(context)
93
- : null;
94
- this.logger?.debug(`[Hook] Resolved command: ${resolvedCommand}`);
95
- if (jsonInput) {
96
- this.logger?.debug(`[Hook] JSON input: ${JSON.stringify(jsonInput)}`);
97
- }
98
- return new Promise((resolve) => {
99
- let stdout = "";
100
- let stderr = "";
101
- let timedOut = false;
102
- let childProcess;
103
- // Setup timeout
104
- const timeoutId = setTimeout(() => {
105
- timedOut = true;
106
- this.logger?.warn(`[Hook] Command timed out after ${timeout}ms: ${resolvedCommand}`);
107
- if (childProcess && !childProcess.killed) {
108
- childProcess.kill("SIGTERM");
109
- // Force kill after 5 seconds if SIGTERM doesn't work
110
- setTimeout(() => {
111
- if (childProcess && !childProcess.killed) {
112
- this.logger?.warn(`[Hook] Force killing process: ${resolvedCommand}`);
113
- childProcess.kill("SIGKILL");
114
- }
115
- }, 5000);
116
- }
117
- }, timeout);
118
- try {
119
- // Execute command using shell for cross-platform compatibility
120
- const shell = process.platform === "win32" ? "cmd.exe" : "/bin/sh";
121
- const shellArgs = process.platform === "win32" ? ["/c"] : ["-c"];
122
- childProcess = spawn(shell, [...shellArgs, resolvedCommand], {
123
- cwd,
124
- env,
125
- stdio: "pipe",
126
- windowsHide: true, // Hide console window on Windows
127
- });
128
- this.logger?.debug(`[Hook] Process started (PID: ${childProcess.pid})`);
129
- // Write JSON input to stdin if available
130
- if (jsonInput && childProcess.stdin) {
131
- try {
132
- const jsonString = JSON.stringify(jsonInput, null, 2);
133
- childProcess.stdin.write(jsonString);
134
- childProcess.stdin.end();
135
- this.logger?.debug(`[Hook] JSON input written to stdin`);
136
- }
137
- catch (error) {
138
- this.logger?.warn(`[Hook] Failed to write JSON to stdin: ${error}`);
139
- }
140
- }
141
- // Collect stdout
142
- childProcess.stdout?.on("data", (data) => {
143
- stdout += data.toString();
144
- });
145
- // Collect stderr
146
- childProcess.stderr?.on("data", (data) => {
147
- stderr += data.toString();
148
- });
149
- // Handle process completion
150
- childProcess.on("close", (exitCode) => {
151
- clearTimeout(timeoutId);
152
- const duration = Date.now() - startTime;
153
- const success = !timedOut && exitCode === 0;
154
- // Log execution result
155
- if (success) {
156
- this.logger?.debug(`[Hook] Command completed successfully in ${duration}ms (exit code: ${exitCode})`);
157
- }
158
- else {
159
- this.logger?.warn(`[Hook] Command failed in ${duration}ms (exit code: ${exitCode}, timed out: ${timedOut})`);
160
- if (stderr) {
161
- this.logger?.warn(`[Hook] stderr: ${stderr.trim()}`);
162
- }
163
- }
164
- if (stdout && stdout.trim()) {
165
- this.logger?.debug(`[Hook] stdout: ${stdout.trim()}`);
166
- }
167
- resolve({
168
- success,
169
- exitCode: exitCode ?? undefined,
170
- stdout: stdout.trim() || undefined,
171
- stderr: stderr.trim() || undefined,
172
- duration,
173
- timedOut,
174
- });
175
- });
176
- // Handle process errors
177
- childProcess.on("error", (error) => {
178
- clearTimeout(timeoutId);
179
- const duration = Date.now() - startTime;
180
- this.logger?.error(`[Hook] Process error in ${duration}ms: ${error.message}`);
181
- resolve({
182
- success: false,
183
- stderr: error.message,
184
- duration,
185
- timedOut,
186
- });
187
- });
188
- }
189
- catch (error) {
190
- clearTimeout(timeoutId);
191
- const duration = Date.now() - startTime;
192
- const errorMessage = error instanceof Error ? error.message : "Unknown execution error";
193
- this.logger?.error(`[Hook] Execution error in ${duration}ms: ${errorMessage}`);
194
- resolve({
195
- success: false,
196
- stderr: errorMessage,
197
- duration,
198
- timedOut,
199
- });
200
- }
201
- });
202
- }
203
- /**
204
- * Execute multiple commands in sequence
205
- * Stops on first failure unless configured otherwise
206
- */
207
- async executeCommands(commands, context, options = {}) {
208
- const results = [];
209
- this.logger?.debug(`[Hook] Executing ${commands.length} commands in sequence for ${context.event} event`);
210
- for (let i = 0; i < commands.length; i++) {
211
- const command = commands[i];
212
- this.logger?.debug(`[Hook] Command ${i + 1}/${commands.length}: ${command}`);
213
- try {
214
- const result = await this.executeCommand(command, context, options);
215
- results.push(result);
216
- // Stop on first failure to prevent cascading issues
217
- if (!result.success) {
218
- this.logger?.warn(`[Hook] Stopping sequence at command ${i + 1} due to failure`);
219
- break;
220
- }
221
- }
222
- catch (error) {
223
- // This shouldn't happen as executeCommand handles all errors,
224
- // but include defensive handling
225
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
226
- this.logger?.error(`[Hook] Unexpected error in command ${i + 1}: ${errorMessage}`);
227
- results.push({
228
- success: false,
229
- stderr: errorMessage,
230
- duration: 0,
231
- timedOut: false,
232
- });
233
- break;
234
- }
235
- }
236
- const successCount = results.filter((r) => r.success).length;
237
- this.logger?.debug(`[Hook] Completed sequence: ${successCount}/${results.length} commands succeeded`);
238
- return results;
239
- }
240
- /**
241
- * Validate command safety to prevent injection attacks
242
- */
243
- isCommandSafe(command) {
244
- if (!command || typeof command !== "string")
245
- return false;
246
- // Command cannot be empty
247
- const trimmed = command.trim();
248
- if (trimmed.length === 0)
249
- return false;
250
- // Basic safety checks - these could be expanded based on security requirements
251
- const dangerousPatterns = [
252
- /\b(rm\s+-rf\s+\/|rm\s+-rf\s+~|rm\s+-rf\s+\*)/i, // Dangerous rm commands
253
- /\bdd\s+if=/i, // dd commands that could be destructive
254
- /:\(\)\{.*\}/, // Fork bomb patterns
255
- /\beval\s*[(\s]/i, // Code evaluation
256
- /\bexec\s+/i, // Process execution in shells
257
- ];
258
- // Check for obviously dangerous patterns
259
- if (dangerousPatterns.some((pattern) => pattern.test(trimmed))) {
260
- return false;
261
- }
262
- return true;
263
- }
264
- /**
265
- * Build environment variables for hook execution
266
- */
267
- buildEnvironment(context) {
268
- return {
269
- ...process.env, // Inherit parent environment
270
- WAVE_PROJECT_DIR: context.projectDir,
271
- };
272
- }
273
- /**
274
- * Resolve environment variables in command string
275
- */
276
- resolveEnvironmentVariables(command, env) {
277
- let resolved = command;
278
- // Replace $VAR and ${VAR} patterns
279
- Object.entries(env).forEach(([key, value]) => {
280
- if (value !== undefined) {
281
- // Handle both $VAR and ${VAR} syntax
282
- const dollarPattern = new RegExp(`\\$${key}\\b`, "g");
283
- const bracesPattern = new RegExp(`\\$\\{${key}\\}`, "g");
284
- resolved = resolved.replace(dollarPattern, value);
285
- resolved = resolved.replace(bracesPattern, value);
286
- }
287
- });
288
- return resolved;
289
- }
290
- /**
291
- * Get process statistics for monitoring
292
- */
293
- getExecutionStats() {
294
- return {
295
- platform: process.platform,
296
- defaultTimeout: this.defaultTimeout,
297
- maxTimeout: this.maxTimeout,
298
- };
299
- }
300
- /**
301
- * Test if the executor can run commands on this platform
302
- */
303
- isSupported() {
304
- try {
305
- // Try to detect shell availability - basic check could be enhanced with actual shell testing
306
- return true;
307
- }
308
- catch {
309
- return false;
310
- }
311
- }
312
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * Hooks System Entry Point
3
- *
4
- * Exports all public APIs for the Wave Code hooks system.
5
- * This module provides a clean interface for integrating hooks
6
- * into AI workflows and CLI applications.
7
- */
8
- export type { HookEvent, HookCommand, HookEventConfig, HookConfiguration, HookExecutionContext, HookExecutionResult, HookExecutionOptions, ValidationResult, HookEnvironment, } from "./types.js";
9
- export { isValidHookEvent, isValidHookCommand, isValidHookEventConfig, HookExecutionError, HookConfigurationError, } from "./types.js";
10
- export type { IHookMatcher } from "./matcher.js";
11
- export { HookMatcher } from "./matcher.js";
12
- export type { IHookExecutor } from "./executor.js";
13
- export { HookExecutor } from "./executor.js";
14
- export type { IHookManager } from "./manager.js";
15
- export { HookManager } from "./manager.js";
16
- export { getUserHooksConfigPath, getProjectHooksConfigPath, loadUserHooksConfig, loadProjectHooksConfig, loadMergedHooksConfig, hasHooksConfiguration, getHooksConfigurationInfo, } from "./settings.js";
17
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,YAAY,EACV,SAAS,EACT,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,GAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,eAAe,CAAC"}
@@ -1,14 +0,0 @@
1
- /**
2
- * Hooks System Entry Point
3
- *
4
- * Exports all public APIs for the Wave Code hooks system.
5
- * This module provides a clean interface for integrating hooks
6
- * into AI workflows and CLI applications.
7
- */
8
- // Type guards and utility functions
9
- export { isValidHookEvent, isValidHookCommand, isValidHookEventConfig, HookExecutionError, HookConfigurationError, } from "./types.js";
10
- export { HookMatcher } from "./matcher.js";
11
- export { HookExecutor } from "./executor.js";
12
- export { HookManager } from "./manager.js";
13
- // Settings and configuration loading
14
- export { getUserHooksConfigPath, getProjectHooksConfigPath, loadUserHooksConfig, loadProjectHooksConfig, loadMergedHooksConfig, hasHooksConfiguration, getHooksConfigurationInfo, } from "./settings.js";
@@ -1 +0,0 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/hooks/manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EAItB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,YAAY,EAAe,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,KAAK,aAAa,EAAgB,MAAM,eAAe,CAAC;AAEjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,YAAY;IAE3B,iBAAiB,CACf,SAAS,CAAC,EAAE,wBAAwB,EACpC,YAAY,CAAC,EAAE,wBAAwB,GACtC,IAAI,CAAC;IAGR,6BAA6B,IAAI,IAAI,CAAC;IAGtC,YAAY,CACV,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,GAC3D,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAGlC,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAGvD,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,gBAAgB,CAAC;IAGnE,gBAAgB,IAAI,wBAAwB,GAAG,SAAS,CAAC;CAC1D;AAED,qBAAa,WAAY,YAAW,YAAY;IAC9C,OAAO,CAAC,aAAa,CAAuC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAG/B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,YAAgC,EACzC,QAAQ,CAAC,EAAE,aAAa,EACxB,MAAM,CAAC,EAAE,MAAM;IAWjB;;;OAGG;IACH,iBAAiB,CACf,SAAS,CAAC,EAAE,wBAAwB,EACpC,YAAY,CAAC,EAAE,wBAAwB,GACtC,IAAI;IAyBP;;;OAGG;IACH,6BAA6B,IAAI,IAAI;IAmCrC;;OAEG;IACG,YAAY,CAChB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,GAC3D,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAwHjC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAWtD;;OAEG;IACH,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,gBAAgB;IA8ClE;;OAEG;IACH,OAAO,CAAC,4BAA4B;IAyCpC;;OAEG;IACH,gBAAgB,IAAI,wBAAwB,GAAG,SAAS;IAOxD;;OAEG;IACH,kBAAkB,IAAI,IAAI;IAI1B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAmDhC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA8BhC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAa/B;;OAEG;IACH,OAAO,CAAC,aAAa;IA4BrB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAqC3B;;OAEG;IACH,qBAAqB,IAAI;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;KAC3C;CA2CF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../../src/hooks/matcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,YAAY;IAE3B,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAGpD,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAGzC,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,cAAc,CAAC;CAC9E;AAED,qBAAa,WAAY,YAAW,YAAY;IAC9C;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAYnD;;OAEG;IACH,OAAO,CAAC,aAAa;IAmBrB;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAoBxC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAmB5B;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,cAAc;IA6B5E;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE;IAI1D;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO;CAkCxD"}