wave-agent-sdk 0.7.2 → 0.8.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 (168) hide show
  1. package/dist/agent.d.ts +9 -79
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +85 -302
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -1
  7. package/dist/managers/aiManager.d.ts.map +1 -1
  8. package/dist/managers/aiManager.js +20 -13
  9. package/dist/managers/backgroundTaskManager.d.ts +1 -1
  10. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundTaskManager.js +1 -1
  12. package/dist/managers/{bashManager.d.ts → bangManager.d.ts} +4 -4
  13. package/dist/managers/{bashManager.d.ts.map → bangManager.d.ts.map} +1 -1
  14. package/dist/managers/{bashManager.js → bangManager.js} +5 -6
  15. package/dist/managers/hookManager.d.ts.map +1 -1
  16. package/dist/managers/hookManager.js +12 -3
  17. package/dist/managers/messageManager.d.ts +18 -6
  18. package/dist/managers/messageManager.d.ts.map +1 -1
  19. package/dist/managers/messageManager.js +42 -20
  20. package/dist/managers/permissionManager.d.ts +22 -1
  21. package/dist/managers/permissionManager.d.ts.map +1 -1
  22. package/dist/managers/permissionManager.js +106 -85
  23. package/dist/managers/planManager.d.ts +6 -0
  24. package/dist/managers/planManager.d.ts.map +1 -1
  25. package/dist/managers/planManager.js +21 -0
  26. package/dist/managers/skillManager.d.ts +7 -2
  27. package/dist/managers/skillManager.d.ts.map +1 -1
  28. package/dist/managers/skillManager.js +30 -10
  29. package/dist/managers/slashCommandManager.d.ts +7 -0
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +57 -45
  32. package/dist/managers/subagentManager.d.ts +4 -0
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +47 -13
  35. package/dist/managers/toolManager.d.ts +7 -1
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +15 -2
  38. package/dist/prompts/index.d.ts +0 -4
  39. package/dist/prompts/index.d.ts.map +1 -1
  40. package/dist/prompts/index.js +0 -9
  41. package/dist/services/aiService.d.ts.map +1 -1
  42. package/dist/services/aiService.js +6 -6
  43. package/dist/services/configurationService.d.ts +2 -2
  44. package/dist/services/configurationService.d.ts.map +1 -1
  45. package/dist/services/configurationService.js +4 -4
  46. package/dist/services/hook.d.ts.map +1 -1
  47. package/dist/services/hook.js +6 -0
  48. package/dist/services/initializationService.d.ts +44 -0
  49. package/dist/services/initializationService.d.ts.map +1 -0
  50. package/dist/services/initializationService.js +170 -0
  51. package/dist/services/interactionService.d.ts +29 -0
  52. package/dist/services/interactionService.d.ts.map +1 -0
  53. package/dist/services/interactionService.js +97 -0
  54. package/dist/services/session.js +1 -1
  55. package/dist/services/taskManager.d.ts +5 -0
  56. package/dist/services/taskManager.d.ts.map +1 -1
  57. package/dist/services/taskManager.js +16 -2
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +7 -18
  60. package/dist/tools/editTool.js +1 -1
  61. package/dist/tools/exitPlanMode.js +1 -1
  62. package/dist/tools/lspTool.d.ts +2 -0
  63. package/dist/tools/lspTool.d.ts.map +1 -1
  64. package/dist/tools/lspTool.js +144 -52
  65. package/dist/tools/skillTool.d.ts.map +1 -1
  66. package/dist/tools/skillTool.js +97 -2
  67. package/dist/tools/taskManagementTools.d.ts.map +1 -1
  68. package/dist/tools/taskManagementTools.js +23 -2
  69. package/dist/tools/taskTool.d.ts.map +1 -1
  70. package/dist/tools/taskTool.js +9 -15
  71. package/dist/tools/types.d.ts +1 -2
  72. package/dist/tools/types.d.ts.map +1 -1
  73. package/dist/tools/writeTool.js +1 -1
  74. package/dist/types/agent.d.ts +64 -0
  75. package/dist/types/agent.d.ts.map +1 -0
  76. package/dist/types/agent.js +1 -0
  77. package/dist/types/commands.d.ts +0 -4
  78. package/dist/types/commands.d.ts.map +1 -1
  79. package/dist/types/config.d.ts +1 -1
  80. package/dist/types/config.d.ts.map +1 -1
  81. package/dist/types/hooks.d.ts +3 -1
  82. package/dist/types/hooks.d.ts.map +1 -1
  83. package/dist/types/hooks.js +1 -0
  84. package/dist/types/index.d.ts +1 -0
  85. package/dist/types/index.d.ts.map +1 -1
  86. package/dist/types/index.js +1 -0
  87. package/dist/types/messaging.d.ts +3 -3
  88. package/dist/types/messaging.d.ts.map +1 -1
  89. package/dist/types/skills.d.ts +13 -0
  90. package/dist/types/skills.d.ts.map +1 -1
  91. package/dist/utils/commandPathResolver.d.ts +3 -36
  92. package/dist/utils/commandPathResolver.d.ts.map +1 -1
  93. package/dist/utils/commandPathResolver.js +16 -93
  94. package/dist/utils/configValidator.d.ts +2 -2
  95. package/dist/utils/configValidator.d.ts.map +1 -1
  96. package/dist/utils/configValidator.js +4 -6
  97. package/dist/utils/containerSetup.d.ts +3 -4
  98. package/dist/utils/containerSetup.d.ts.map +1 -1
  99. package/dist/utils/containerSetup.js +14 -9
  100. package/dist/utils/customCommands.d.ts +2 -3
  101. package/dist/utils/customCommands.d.ts.map +1 -1
  102. package/dist/utils/customCommands.js +20 -60
  103. package/dist/utils/gitUtils.d.ts +25 -0
  104. package/dist/utils/gitUtils.d.ts.map +1 -1
  105. package/dist/utils/gitUtils.js +75 -0
  106. package/dist/utils/markdownParser.d.ts +4 -0
  107. package/dist/utils/markdownParser.d.ts.map +1 -1
  108. package/dist/utils/markdownParser.js +33 -0
  109. package/dist/utils/messageOperations.d.ts +16 -7
  110. package/dist/utils/messageOperations.d.ts.map +1 -1
  111. package/dist/utils/messageOperations.js +45 -20
  112. package/dist/utils/nameGenerator.d.ts +1 -1
  113. package/dist/utils/nameGenerator.d.ts.map +1 -1
  114. package/dist/utils/nameGenerator.js +10 -6
  115. package/dist/utils/skillParser.d.ts.map +1 -1
  116. package/dist/utils/skillParser.js +48 -0
  117. package/package.json +1 -1
  118. package/src/agent.ts +103 -458
  119. package/src/index.ts +2 -2
  120. package/src/managers/aiManager.ts +23 -17
  121. package/src/managers/backgroundTaskManager.ts +2 -2
  122. package/src/managers/{bashManager.ts → bangManager.ts} +11 -8
  123. package/src/managers/hookManager.ts +13 -3
  124. package/src/managers/messageManager.ts +55 -26
  125. package/src/managers/permissionManager.ts +121 -98
  126. package/src/managers/planManager.ts +26 -0
  127. package/src/managers/skillManager.ts +51 -14
  128. package/src/managers/slashCommandManager.ts +75 -55
  129. package/src/managers/subagentManager.ts +57 -13
  130. package/src/managers/toolManager.ts +22 -2
  131. package/src/prompts/index.ts +0 -15
  132. package/src/services/aiService.ts +9 -12
  133. package/src/services/configurationService.ts +4 -4
  134. package/src/services/hook.ts +7 -0
  135. package/src/services/initializationService.ts +291 -0
  136. package/src/services/interactionService.ts +171 -0
  137. package/src/services/session.ts +1 -1
  138. package/src/services/taskManager.ts +18 -2
  139. package/src/tools/bashTool.ts +8 -18
  140. package/src/tools/editTool.ts +1 -1
  141. package/src/tools/exitPlanMode.ts +1 -1
  142. package/src/tools/lsTool.ts +1 -1
  143. package/src/tools/lspTool.ts +184 -52
  144. package/src/tools/skillTool.ts +127 -2
  145. package/src/tools/taskManagementTools.ts +32 -2
  146. package/src/tools/taskTool.ts +13 -15
  147. package/src/tools/types.ts +1 -2
  148. package/src/tools/writeTool.ts +1 -1
  149. package/src/types/agent.ts +83 -0
  150. package/src/types/commands.ts +0 -6
  151. package/src/types/config.ts +1 -1
  152. package/src/types/hooks.ts +5 -1
  153. package/src/types/index.ts +1 -0
  154. package/src/types/messaging.ts +3 -3
  155. package/src/types/skills.ts +13 -0
  156. package/src/utils/commandPathResolver.ts +14 -117
  157. package/src/utils/configValidator.ts +5 -9
  158. package/src/utils/containerSetup.ts +17 -14
  159. package/src/utils/customCommands.ts +20 -83
  160. package/src/utils/gitUtils.ts +75 -0
  161. package/src/utils/markdownParser.ts +47 -0
  162. package/src/utils/messageOperations.ts +58 -28
  163. package/src/utils/nameGenerator.ts +10 -6
  164. package/src/utils/skillParser.ts +52 -0
  165. package/dist/managers/backgroundBashManager.d.ts +0 -27
  166. package/dist/managers/backgroundBashManager.d.ts.map +0 -1
  167. package/dist/managers/backgroundBashManager.js +0 -169
  168. package/src/managers/backgroundBashManager.ts +0 -206
@@ -2,7 +2,7 @@ import { existsSync, readdirSync, statSync } from "fs";
2
2
  import { join, extname, basename } from "path";
3
3
  import { homedir } from "os";
4
4
  import { parseMarkdownFile } from "./markdownParser.js";
5
- import { generateCommandId, getCommandSegments, getNamespace, getDepth, } from "./commandPathResolver.js";
5
+ import { generateCommandId } from "./commandPathResolver.js";
6
6
  import { logger } from "./globalLogger.js";
7
7
  /**
8
8
  * Get the project-specific commands directory
@@ -17,82 +17,42 @@ export function getUserCommandsDir() {
17
17
  return join(homedir(), ".wave", "commands");
18
18
  }
19
19
  /**
20
- * Scan a directory for markdown command files with nested directory support
20
+ * Scan a directory for markdown command files (flat structure only)
21
21
  * @param dirPath - Root commands directory path
22
- * @param maxDepth - Maximum nesting depth to scan (default: 1)
23
22
  */
24
- export function scanCommandsDirectory(dirPath, maxDepth = 1) {
23
+ export function scanCommandsDirectory(dirPath) {
25
24
  if (!existsSync(dirPath)) {
26
25
  return [];
27
26
  }
28
- return scanCommandsDirectoryRecursive(dirPath, dirPath, 0, maxDepth);
29
- }
30
- /**
31
- * Recursively scan directory for commands with depth control
32
- * @param currentPath - Current directory being scanned
33
- * @param rootPath - Root commands directory (for relative path calculation)
34
- * @param currentDepth - Current nesting depth
35
- * @param maxDepth - Maximum allowed depth
36
- */
37
- function scanCommandsDirectoryRecursive(currentPath, rootPath, currentDepth, maxDepth) {
38
27
  const commands = [];
39
28
  try {
40
- const entries = readdirSync(currentPath);
29
+ const entries = readdirSync(dirPath);
41
30
  for (const entryName of entries) {
42
- const fullPath = join(currentPath, entryName);
43
- let isDirectory = false;
44
- let isFile = false;
31
+ const fullPath = join(dirPath, entryName);
45
32
  try {
46
33
  const stats = statSync(fullPath);
47
- isDirectory = stats.isDirectory();
48
- isFile = stats.isFile();
49
- }
50
- catch (error) {
51
- // Skip entries that cannot be stat'd
52
- logger.warn(`Cannot access ${fullPath}:`, error);
53
- continue;
54
- }
55
- if (isDirectory) {
56
- // Skip subdirectories if we're at max depth
57
- if (currentDepth >= maxDepth) {
58
- logger.warn(`Skipping directory ${fullPath}: exceeds maximum nesting depth of ${maxDepth}`);
34
+ if (!stats.isFile() || extname(entryName) !== ".md") {
59
35
  continue;
60
36
  }
61
- // Recursively scan subdirectory
62
- const nestedCommands = scanCommandsDirectoryRecursive(fullPath, rootPath, currentDepth + 1, maxDepth);
63
- commands.push(...nestedCommands);
64
- }
65
- else if (isFile && extname(entryName) === ".md") {
66
37
  // Process markdown file
67
- try {
68
- const commandId = generateCommandId(fullPath, rootPath);
69
- const segments = getCommandSegments(fullPath, rootPath);
70
- const namespace = getNamespace(segments);
71
- const depth = getDepth(segments);
72
- const { content, config } = parseMarkdownFile(fullPath);
73
- commands.push({
74
- id: commandId,
75
- name: basename(entryName, ".md"),
76
- description: config?.description,
77
- filePath: fullPath,
78
- content,
79
- config,
80
- // Nested command metadata
81
- namespace,
82
- isNested: depth > 0,
83
- depth,
84
- segments,
85
- });
86
- }
87
- catch (error) {
88
- logger.warn(`Failed to load custom command from ${fullPath}:`, error);
89
- }
38
+ const commandId = generateCommandId(fullPath, dirPath);
39
+ const { content, config } = parseMarkdownFile(fullPath);
40
+ commands.push({
41
+ id: commandId,
42
+ name: basename(entryName, ".md"),
43
+ description: config?.description,
44
+ filePath: fullPath,
45
+ content,
46
+ config,
47
+ });
48
+ }
49
+ catch (error) {
50
+ logger.warn(`Failed to load custom command from ${fullPath}:`, error);
90
51
  }
91
- // Skip non-markdown files silently
92
52
  }
93
53
  }
94
54
  catch (error) {
95
- logger.warn(`Failed to scan commands directory ${currentPath}:`, error);
55
+ logger.warn(`Failed to scan commands directory ${dirPath}:`, error);
96
56
  }
97
57
  return commands;
98
58
  }
@@ -4,4 +4,29 @@
4
4
  * @returns "Yes" if it's a git repository, "No" otherwise
5
5
  */
6
6
  export declare function isGitRepository(dirPath: string): string;
7
+ /**
8
+ * Get the root directory of the git repository
9
+ * @param cwd Working directory
10
+ * @returns Repository root path
11
+ */
12
+ export declare function getGitRepoRoot(cwd: string): string;
13
+ /**
14
+ * Get the default remote branch (e.g., origin/main)
15
+ * @param cwd Working directory
16
+ * @returns Default remote branch name
17
+ */
18
+ export declare function getDefaultRemoteBranch(cwd: string): string;
19
+ /**
20
+ * Check if there are uncommitted changes in the working directory
21
+ * @param cwd Working directory
22
+ * @returns True if there are uncommitted changes
23
+ */
24
+ export declare function hasUncommittedChanges(cwd: string): boolean;
25
+ /**
26
+ * Check if there are new commits in the current branch that are not in the base branch
27
+ * @param cwd Working directory
28
+ * @param baseBranch Base branch name (e.g., origin/main)
29
+ * @returns True if there are new commits
30
+ */
31
+ export declare function hasNewCommits(cwd: string, baseBranch?: string): boolean;
7
32
  //# sourceMappingURL=gitUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gitUtils.d.ts","sourceRoot":"","sources":["../../src/utils/gitUtils.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAevD"}
1
+ {"version":3,"file":"gitUtils.d.ts","sourceRoot":"","sources":["../../src/utils/gitUtils.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAevD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAY1D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAW1D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAYvE"}
@@ -1,5 +1,6 @@
1
1
  import * as path from "node:path";
2
2
  import * as fsSync from "node:fs";
3
+ import { execSync } from "node:child_process";
3
4
  /**
4
5
  * Check if a directory is a git repository
5
6
  * @param dirPath Directory path
@@ -22,3 +23,77 @@ export function isGitRepository(dirPath) {
22
23
  return "No";
23
24
  }
24
25
  }
26
+ /**
27
+ * Get the root directory of the git repository
28
+ * @param cwd Working directory
29
+ * @returns Repository root path
30
+ */
31
+ export function getGitRepoRoot(cwd) {
32
+ try {
33
+ return execSync("git rev-parse --show-toplevel", {
34
+ cwd,
35
+ encoding: "utf8",
36
+ stdio: ["ignore", "pipe", "ignore"],
37
+ }).trim();
38
+ }
39
+ catch {
40
+ return cwd;
41
+ }
42
+ }
43
+ /**
44
+ * Get the default remote branch (e.g., origin/main)
45
+ * @param cwd Working directory
46
+ * @returns Default remote branch name
47
+ */
48
+ export function getDefaultRemoteBranch(cwd) {
49
+ try {
50
+ const head = execSync("git symbolic-ref refs/remotes/origin/HEAD", {
51
+ cwd,
52
+ encoding: "utf8",
53
+ stdio: ["ignore", "pipe", "ignore"],
54
+ }).trim();
55
+ return head.replace("refs/remotes/", "");
56
+ }
57
+ catch {
58
+ // Fallback to origin/main if origin/HEAD is not set
59
+ return "origin/main";
60
+ }
61
+ }
62
+ /**
63
+ * Check if there are uncommitted changes in the working directory
64
+ * @param cwd Working directory
65
+ * @returns True if there are uncommitted changes
66
+ */
67
+ export function hasUncommittedChanges(cwd) {
68
+ try {
69
+ const status = execSync("git status --porcelain", {
70
+ cwd,
71
+ encoding: "utf8",
72
+ stdio: ["ignore", "pipe", "ignore"],
73
+ }).trim();
74
+ return status.length > 0;
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ /**
81
+ * Check if there are new commits in the current branch that are not in the base branch
82
+ * @param cwd Working directory
83
+ * @param baseBranch Base branch name (e.g., origin/main)
84
+ * @returns True if there are new commits
85
+ */
86
+ export function hasNewCommits(cwd, baseBranch) {
87
+ try {
88
+ const range = baseBranch ? `${baseBranch}..HEAD` : "@{u}..HEAD";
89
+ const log = execSync(`git log ${range} --oneline`, {
90
+ cwd,
91
+ encoding: "utf8",
92
+ stdio: ["ignore", "pipe", "ignore"],
93
+ }).trim();
94
+ return log.length > 0;
95
+ }
96
+ catch {
97
+ return false;
98
+ }
99
+ }
@@ -30,5 +30,9 @@ export declare function parseBashCommands(content: string): {
30
30
  * Replace bash command placeholders with their outputs
31
31
  */
32
32
  export declare function replaceBashCommandsWithOutput(content: string, results: BashCommandResult[]): string;
33
+ /**
34
+ * Execute bash commands and return results
35
+ */
36
+ export declare function executeBashCommands(commands: string[], workdir: string, timeout?: number): Promise<BashCommandResult[]>;
33
37
  export {};
34
38
  //# sourceMappingURL=markdownParser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdownParser.d.ts","sourceRoot":"","sources":["../../src/utils/markdownParser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAElE,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,wBAAwB,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB,CA8DA;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CA4CtE;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAClD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAgBA;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,EAAE,GAC3B,MAAM,CAcR"}
1
+ {"version":3,"file":"markdownParser.d.ts","sourceRoot":"","sources":["../../src/utils/markdownParser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAIlE,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,wBAAwB,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB,CA8DA;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CA4CtE;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAClD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAgBA;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,EAAE,GAC3B,MAAM,CAcR;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAc,GACtB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAkC9B"}
@@ -1,4 +1,7 @@
1
1
  import { readFileSync } from "fs";
2
+ import { exec } from "child_process";
3
+ import { promisify } from "util";
4
+ const execAsync = promisify(exec);
2
5
  /**
3
6
  * Parse YAML frontmatter from markdown content
4
7
  */
@@ -125,3 +128,33 @@ export function replaceBashCommandsWithOutput(content, results) {
125
128
  });
126
129
  return processedContent;
127
130
  }
131
+ /**
132
+ * Execute bash commands and return results
133
+ */
134
+ export async function executeBashCommands(commands, workdir, timeout = 30000) {
135
+ const results = [];
136
+ for (const command of commands) {
137
+ try {
138
+ const { stdout, stderr } = await execAsync(command, {
139
+ cwd: workdir,
140
+ timeout,
141
+ });
142
+ results.push({
143
+ command,
144
+ output: (stdout + (stderr || "")).trim(),
145
+ exitCode: 0,
146
+ });
147
+ }
148
+ catch (error) {
149
+ const execError = error;
150
+ results.push({
151
+ command,
152
+ output: ((execError.stdout || "") +
153
+ (execError.stderr || "") +
154
+ (execError.message || "")).trim(),
155
+ exitCode: execError.code || 1,
156
+ });
157
+ }
158
+ }
159
+ return results;
160
+ }
@@ -44,19 +44,20 @@ export interface AddErrorBlockParams {
44
44
  messages: Message[];
45
45
  error: string;
46
46
  }
47
- export interface AddCommandOutputParams {
47
+ export interface AddBangParams {
48
48
  messages: Message[];
49
49
  command: string;
50
50
  }
51
- export interface UpdateCommandOutputParams {
51
+ export interface UpdateBangParams {
52
52
  messages: Message[];
53
53
  command: string;
54
54
  output: string;
55
55
  }
56
- export interface CompleteCommandParams {
56
+ export interface CompleteBangParams {
57
57
  messages: Message[];
58
58
  command: string;
59
59
  exitCode: number;
60
+ output?: string;
60
61
  }
61
62
  /**
62
63
  * Convert image file path to base64 format
@@ -68,12 +69,20 @@ export declare const addUserMessageToMessages: ({ messages, content, images, cus
68
69
  export declare const addAssistantMessageToMessages: (messages: Message[], content?: string, toolCalls?: ChatCompletionMessageFunctionToolCall[], usage?: Usage, additionalFields?: Record<string, unknown>) => Message[];
69
70
  export declare const updateToolBlockInMessage: ({ messages, id, parameters, result, success, error, stage, name, shortResult, startLineNumber, images, compactParams, parametersChunk, isManuallyBackgrounded, }: UpdateToolBlockParams) => Message[];
70
71
  export declare const addErrorBlockToMessage: ({ messages, error, }: AddErrorBlockParams) => Message[];
71
- export declare const addCommandOutputMessage: ({ messages, command, }: AddCommandOutputParams) => Message[];
72
- export declare const updateCommandOutputInMessage: ({ messages, command, output, }: UpdateCommandOutputParams) => Message[];
73
- export declare const completeCommandInMessage: ({ messages, command, exitCode, }: CompleteCommandParams) => Message[];
72
+ export declare const addBangMessage: ({ messages, command, }: AddBangParams) => Message[];
73
+ export declare const updateBangInMessage: ({ messages, command, output, }: UpdateBangParams) => Message[];
74
+ export declare const completeBangInMessage: ({ messages, command, exitCode, output, }: CompleteBangParams) => Message[];
74
75
  /**
75
- * Removes the last user message from the messages array
76
+ * Helper to count tool blocks in messages
77
+ */
78
+ export declare function countToolBlocks(messages: Message[]): number;
79
+ /**
80
+ * Remove the last user message from the conversation
76
81
  * Used for hook error handling when the user prompt needs to be erased
77
82
  */
78
83
  export declare const removeLastUserMessage: (messages: Message[]) => Message[];
84
+ /**
85
+ * Helper to format tool and token summary
86
+ */
87
+ export declare function formatToolTokenSummary(toolCount: number, tokens: number): string;
79
88
  //# sourceMappingURL=messageOperations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messageOperations.d.ts","sourceRoot":"","sources":["../../src/utils/messageOperations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messageOperations.d.ts","sourceRoot":"","sources":["../../src/utils/messageOperations.ts"],"names":[],"mappings":"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"}
@@ -185,13 +185,13 @@ export const addErrorBlockToMessage = ({ messages, error, }) => {
185
185
  }
186
186
  return newMessages;
187
187
  };
188
- // Add command output block to message list
189
- export const addCommandOutputMessage = ({ messages, command, }) => {
188
+ // Add bang block to message list
189
+ export const addBangMessage = ({ messages, command, }) => {
190
190
  const outputMessage = {
191
191
  role: "user",
192
192
  blocks: [
193
193
  {
194
- type: "command_output",
194
+ type: "bang",
195
195
  command,
196
196
  output: "",
197
197
  isRunning: true,
@@ -201,17 +201,15 @@ export const addCommandOutputMessage = ({ messages, command, }) => {
201
201
  };
202
202
  return [...messages, outputMessage];
203
203
  };
204
- // Update output content of command output block
205
- export const updateCommandOutputInMessage = ({ messages, command, output, }) => {
204
+ // Update output content of bang block
205
+ export const updateBangInMessage = ({ messages, command, output, }) => {
206
206
  const newMessages = [...messages];
207
- // Find the last user message with a command_output block for this command
207
+ // Find the last user message with a bang block for this command
208
208
  for (let i = newMessages.length - 1; i >= 0; i--) {
209
209
  const msg = newMessages[i];
210
210
  if (msg.role === "user") {
211
- const commandBlock = msg.blocks.find((block) => block.type === "command_output" &&
212
- block.command === command &&
213
- block.isRunning);
214
- if (commandBlock && commandBlock.type === "command_output") {
211
+ const commandBlock = msg.blocks.find((block) => block.type === "bang" && block.command === command && block.isRunning);
212
+ if (commandBlock && commandBlock.type === "bang") {
215
213
  commandBlock.output = output.trim();
216
214
  break;
217
215
  }
@@ -219,19 +217,20 @@ export const updateCommandOutputInMessage = ({ messages, command, output, }) =>
219
217
  }
220
218
  return newMessages;
221
219
  };
222
- // Complete command execution, update exit status
223
- export const completeCommandInMessage = ({ messages, command, exitCode, }) => {
220
+ // Complete bang execution, update exit status
221
+ export const completeBangInMessage = ({ messages, command, exitCode, output, }) => {
224
222
  const newMessages = [...messages];
225
- // Find the last user message with a command_output block for this command
223
+ // Find the last user message with a bang block for this command
226
224
  for (let i = newMessages.length - 1; i >= 0; i--) {
227
225
  const msg = newMessages[i];
228
226
  if (msg.role === "user") {
229
- const commandBlock = msg.blocks.find((block) => block.type === "command_output" &&
230
- block.command === command &&
231
- block.isRunning);
232
- if (commandBlock && commandBlock.type === "command_output") {
227
+ const commandBlock = msg.blocks.find((block) => block.type === "bang" && block.command === command && block.isRunning);
228
+ if (commandBlock && commandBlock.type === "bang") {
233
229
  commandBlock.isRunning = false;
234
230
  commandBlock.exitCode = exitCode;
231
+ if (output !== undefined) {
232
+ commandBlock.output = output.trim();
233
+ }
235
234
  break;
236
235
  }
237
236
  }
@@ -239,18 +238,44 @@ export const completeCommandInMessage = ({ messages, command, exitCode, }) => {
239
238
  return newMessages;
240
239
  };
241
240
  /**
242
- * Removes the last user message from the messages array
241
+ * Helper to count tool blocks in messages
242
+ */
243
+ export function countToolBlocks(messages) {
244
+ let toolCount = 0;
245
+ messages.forEach((msg) => {
246
+ msg.blocks.forEach((block) => {
247
+ if (block.type === "tool") {
248
+ toolCount++;
249
+ }
250
+ });
251
+ });
252
+ return toolCount;
253
+ }
254
+ /**
255
+ * Remove the last user message from the conversation
243
256
  * Used for hook error handling when the user prompt needs to be erased
244
257
  */
245
258
  export const removeLastUserMessage = (messages) => {
246
259
  const newMessages = [...messages];
247
- // Find the index of the last user message
248
260
  for (let i = newMessages.length - 1; i >= 0; i--) {
249
261
  if (newMessages[i].role === "user") {
250
- // Remove the user message at index i
251
262
  newMessages.splice(i, 1);
252
263
  break;
253
264
  }
254
265
  }
255
266
  return newMessages;
256
267
  };
268
+ /**
269
+ * Helper to format tool and token summary
270
+ */
271
+ export function formatToolTokenSummary(toolCount, tokens) {
272
+ if (toolCount === 0) {
273
+ return "";
274
+ }
275
+ let summary = `(${toolCount} tools`;
276
+ if (tokens > 0) {
277
+ summary += ` | ${tokens.toLocaleString()} tokens`;
278
+ }
279
+ summary += ")";
280
+ return summary;
281
+ }
@@ -2,7 +2,7 @@
2
2
  * Random name generator for plan files
3
3
  */
4
4
  /**
5
- * Generates a random English name (adjective-noun)
5
+ * Generates a random English name (adjective-adjective-noun)
6
6
  */
7
7
  export declare function generateRandomName(seed?: string): string;
8
8
  //# sourceMappingURL=nameGenerator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nameGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/nameGenerator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoEH;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAqBxD"}
1
+ {"version":3,"file":"nameGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/nameGenerator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoEH;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAyBxD"}
@@ -66,10 +66,11 @@ const nouns = [
66
66
  "elk",
67
67
  ];
68
68
  /**
69
- * Generates a random English name (adjective-noun)
69
+ * Generates a random English name (adjective-adjective-noun)
70
70
  */
71
71
  export function generateRandomName(seed) {
72
- let adjIndex;
72
+ let adj1Index;
73
+ let adj2Index;
73
74
  let nounIndex;
74
75
  if (seed) {
75
76
  // Simple hash function to derive indices from seed
@@ -78,14 +79,17 @@ export function generateRandomName(seed) {
78
79
  hash = (hash << 5) - hash + seed.charCodeAt(i);
79
80
  hash |= 0; // Convert to 32bit integer
80
81
  }
81
- adjIndex = Math.abs(hash) % adjectives.length;
82
+ adj1Index = Math.abs(hash) % adjectives.length;
83
+ adj2Index = Math.abs(hash >> 4) % adjectives.length;
82
84
  nounIndex = Math.abs(hash >> 8) % nouns.length;
83
85
  }
84
86
  else {
85
- adjIndex = Math.floor(Math.random() * adjectives.length);
87
+ adj1Index = Math.floor(Math.random() * adjectives.length);
88
+ adj2Index = Math.floor(Math.random() * adjectives.length);
86
89
  nounIndex = Math.floor(Math.random() * nouns.length);
87
90
  }
88
- const adj = adjectives[adjIndex];
91
+ const adj1 = adjectives[adj1Index];
92
+ const adj2 = adjectives[adj2Index];
89
93
  const noun = nouns[nounIndex];
90
- return `${adj}-${noun}`;
94
+ return `${adj1}-${adj2}-${noun}`;
91
95
  }
@@ -1 +1 @@
1
- {"version":3,"file":"skillParser.d.ts","sourceRoot":"","sources":["../../src/utils/skillParser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EAEjB,aAAa,EACd,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,iBAAsB,GAC9B,eAAe,CAiEjB;AAkCD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAwCvE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAa5E"}
1
+ {"version":3,"file":"skillParser.d.ts","sourceRoot":"","sources":["../../src/utils/skillParser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EAEjB,aAAa,EACd,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,iBAAsB,GAC9B,eAAe,CA8FjB;AAyDD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAwCvE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAa5E"}
@@ -38,11 +38,36 @@ export function parseSkillFile(filePath, options = {}) {
38
38
  const skillType = skillPath.includes("/.wave/skills")
39
39
  ? "project"
40
40
  : "personal";
41
+ // Extract allowed tools
42
+ let allowedTools;
43
+ const rawAllowedTools = result.frontmatter["allowed-tools"];
44
+ if (Array.isArray(rawAllowedTools)) {
45
+ allowedTools = rawAllowedTools.map((t) => String(t).trim());
46
+ }
47
+ else if (typeof rawAllowedTools === "string") {
48
+ allowedTools = rawAllowedTools
49
+ .split(",")
50
+ .map((t) => t.trim())
51
+ .filter((t) => t.length > 0);
52
+ }
53
+ // Extract disable-model-invocation
54
+ const disableModelInvocation = result.frontmatter["disable-model-invocation"] === true ||
55
+ result.frontmatter["disable-model-invocation"] === "true";
56
+ // Extract user-invocable (default to true)
57
+ const userInvocable = result.frontmatter["user-invocable"] === undefined ||
58
+ result.frontmatter["user-invocable"] === true ||
59
+ result.frontmatter["user-invocable"] === "true";
41
60
  result.skillMetadata = {
42
61
  name: result.frontmatter.name,
43
62
  description: result.frontmatter.description,
44
63
  type: skillType,
45
64
  skillPath,
65
+ allowedTools,
66
+ context: result.frontmatter.context,
67
+ agent: result.frontmatter.agent,
68
+ model: result.frontmatter.model,
69
+ disableModelInvocation,
70
+ userInvocable,
46
71
  };
47
72
  // Validate metadata if requested
48
73
  if (validateMetadata) {
@@ -64,10 +89,28 @@ function parseYamlFrontmatter(yamlContent) {
64
89
  const frontmatter = { name: "", description: "" };
65
90
  try {
66
91
  const lines = yamlContent.split("\n");
92
+ let currentKey = null;
67
93
  for (const line of lines) {
68
94
  const trimmed = line.trim();
69
95
  if (!trimmed || trimmed.startsWith("#"))
70
96
  continue;
97
+ // Check for list item
98
+ if (trimmed.startsWith("-") && currentKey) {
99
+ const value = trimmed
100
+ .substring(1)
101
+ .trim()
102
+ .replace(/^["']|["']$/g, "");
103
+ if (value) {
104
+ const existing = frontmatter[currentKey];
105
+ if (Array.isArray(existing)) {
106
+ existing.push(value);
107
+ }
108
+ else {
109
+ frontmatter[currentKey] = [value];
110
+ }
111
+ }
112
+ continue;
113
+ }
71
114
  const colonIndex = trimmed.indexOf(":");
72
115
  if (colonIndex === -1)
73
116
  continue;
@@ -76,9 +119,14 @@ function parseYamlFrontmatter(yamlContent) {
76
119
  .substring(colonIndex + 1)
77
120
  .trim()
78
121
  .replace(/^["']|["']$/g, "");
122
+ currentKey = key;
79
123
  if (key && value) {
80
124
  frontmatter[key] = value;
81
125
  }
126
+ else if (key) {
127
+ // Key with no value on the same line, might be a list
128
+ frontmatter[key] = [];
129
+ }
82
130
  }
83
131
  }
84
132
  catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-agent-sdk",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "SDK for building AI-powered development tools and agents",
5
5
  "keywords": [
6
6
  "ai",