wave-agent-sdk 0.7.1 → 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
@@ -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
  /**
5
6
  * Check if a directory is a git repository
@@ -22,3 +23,77 @@ export function isGitRepository(dirPath: string): string {
22
23
  return "No";
23
24
  }
24
25
  }
26
+
27
+ /**
28
+ * Get the root directory of the git repository
29
+ * @param cwd Working directory
30
+ * @returns Repository root path
31
+ */
32
+ export function getGitRepoRoot(cwd: string): string {
33
+ try {
34
+ return execSync("git rev-parse --show-toplevel", {
35
+ cwd,
36
+ encoding: "utf8",
37
+ stdio: ["ignore", "pipe", "ignore"],
38
+ }).trim();
39
+ } catch {
40
+ return cwd;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Get the default remote branch (e.g., origin/main)
46
+ * @param cwd Working directory
47
+ * @returns Default remote branch name
48
+ */
49
+ export function getDefaultRemoteBranch(cwd: string): string {
50
+ try {
51
+ const head = execSync("git symbolic-ref refs/remotes/origin/HEAD", {
52
+ cwd,
53
+ encoding: "utf8",
54
+ stdio: ["ignore", "pipe", "ignore"],
55
+ }).trim();
56
+ return head.replace("refs/remotes/", "");
57
+ } catch {
58
+ // Fallback to origin/main if origin/HEAD is not set
59
+ return "origin/main";
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Check if there are uncommitted changes in the working directory
65
+ * @param cwd Working directory
66
+ * @returns True if there are uncommitted changes
67
+ */
68
+ export function hasUncommittedChanges(cwd: string): boolean {
69
+ try {
70
+ const status = execSync("git status --porcelain", {
71
+ cwd,
72
+ encoding: "utf8",
73
+ stdio: ["ignore", "pipe", "ignore"],
74
+ }).trim();
75
+ return status.length > 0;
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Check if there are new commits in the current branch that are not in the base branch
83
+ * @param cwd Working directory
84
+ * @param baseBranch Base branch name (e.g., origin/main)
85
+ * @returns True if there are new commits
86
+ */
87
+ export function hasNewCommits(cwd: string, baseBranch?: string): boolean {
88
+ try {
89
+ const range = baseBranch ? `${baseBranch}..HEAD` : "@{u}..HEAD";
90
+ const log = execSync(`git log ${range} --oneline`, {
91
+ cwd,
92
+ encoding: "utf8",
93
+ stdio: ["ignore", "pipe", "ignore"],
94
+ }).trim();
95
+ return log.length > 0;
96
+ } catch {
97
+ return false;
98
+ }
99
+ }
@@ -1,6 +1,10 @@
1
1
  import { readFileSync } from "fs";
2
+ import { exec } from "child_process";
3
+ import { promisify } from "util";
2
4
  import type { CustomSlashCommandConfig } from "../types/index.js";
3
5
 
6
+ const execAsync = promisify(exec);
7
+
4
8
  interface ParsedMarkdownFile {
5
9
  content: string;
6
10
  config?: CustomSlashCommandConfig;
@@ -176,3 +180,46 @@ export function replaceBashCommandsWithOutput(
176
180
 
177
181
  return processedContent;
178
182
  }
183
+
184
+ /**
185
+ * Execute bash commands and return results
186
+ */
187
+ export async function executeBashCommands(
188
+ commands: string[],
189
+ workdir: string,
190
+ timeout: number = 30000,
191
+ ): Promise<BashCommandResult[]> {
192
+ const results: BashCommandResult[] = [];
193
+
194
+ for (const command of commands) {
195
+ try {
196
+ const { stdout, stderr } = await execAsync(command, {
197
+ cwd: workdir,
198
+ timeout,
199
+ });
200
+ results.push({
201
+ command,
202
+ output: (stdout + (stderr || "")).trim(),
203
+ exitCode: 0,
204
+ });
205
+ } catch (error: unknown) {
206
+ const execError = error as {
207
+ stdout?: string;
208
+ stderr?: string;
209
+ message?: string;
210
+ code?: number;
211
+ };
212
+ results.push({
213
+ command,
214
+ output: (
215
+ (execError.stdout || "") +
216
+ (execError.stderr || "") +
217
+ (execError.message || "")
218
+ ).trim(),
219
+ exitCode: execError.code || 1,
220
+ });
221
+ }
222
+ }
223
+
224
+ return results;
225
+ }
@@ -53,21 +53,22 @@ export interface AddErrorBlockParams {
53
53
  error: string;
54
54
  }
55
55
 
56
- export interface AddCommandOutputParams {
56
+ export interface AddBangParams {
57
57
  messages: Message[];
58
58
  command: string;
59
59
  }
60
60
 
61
- export interface UpdateCommandOutputParams {
61
+ export interface UpdateBangParams {
62
62
  messages: Message[];
63
63
  command: string;
64
64
  output: string;
65
65
  }
66
66
 
67
- export interface CompleteCommandParams {
67
+ export interface CompleteBangParams {
68
68
  messages: Message[];
69
69
  command: string;
70
70
  exitCode: number;
71
+ output?: string;
71
72
  }
72
73
 
73
74
  /**
@@ -295,16 +296,16 @@ export const addErrorBlockToMessage = ({
295
296
  return newMessages;
296
297
  };
297
298
 
298
- // Add command output block to message list
299
- export const addCommandOutputMessage = ({
299
+ // Add bang block to message list
300
+ export const addBangMessage = ({
300
301
  messages,
301
302
  command,
302
- }: AddCommandOutputParams): Message[] => {
303
+ }: AddBangParams): Message[] => {
303
304
  const outputMessage: Message = {
304
305
  role: "user",
305
306
  blocks: [
306
307
  {
307
- type: "command_output",
308
+ type: "bang",
308
309
  command,
309
310
  output: "",
310
311
  isRunning: true,
@@ -316,24 +317,22 @@ export const addCommandOutputMessage = ({
316
317
  return [...messages, outputMessage];
317
318
  };
318
319
 
319
- // Update output content of command output block
320
- export const updateCommandOutputInMessage = ({
320
+ // Update output content of bang block
321
+ export const updateBangInMessage = ({
321
322
  messages,
322
323
  command,
323
324
  output,
324
- }: UpdateCommandOutputParams): Message[] => {
325
+ }: UpdateBangParams): Message[] => {
325
326
  const newMessages = [...messages];
326
- // Find the last user message with a command_output block for this command
327
+ // Find the last user message with a bang block for this command
327
328
  for (let i = newMessages.length - 1; i >= 0; i--) {
328
329
  const msg = newMessages[i];
329
330
  if (msg.role === "user") {
330
331
  const commandBlock = msg.blocks.find(
331
332
  (block) =>
332
- block.type === "command_output" &&
333
- block.command === command &&
334
- block.isRunning,
333
+ block.type === "bang" && block.command === command && block.isRunning,
335
334
  );
336
- if (commandBlock && commandBlock.type === "command_output") {
335
+ if (commandBlock && commandBlock.type === "bang") {
337
336
  commandBlock.output = output.trim();
338
337
  break;
339
338
  }
@@ -342,26 +341,28 @@ export const updateCommandOutputInMessage = ({
342
341
  return newMessages;
343
342
  };
344
343
 
345
- // Complete command execution, update exit status
346
- export const completeCommandInMessage = ({
344
+ // Complete bang execution, update exit status
345
+ export const completeBangInMessage = ({
347
346
  messages,
348
347
  command,
349
348
  exitCode,
350
- }: CompleteCommandParams): Message[] => {
349
+ output,
350
+ }: CompleteBangParams): Message[] => {
351
351
  const newMessages = [...messages];
352
- // Find the last user message with a command_output block for this command
352
+ // Find the last user message with a bang block for this command
353
353
  for (let i = newMessages.length - 1; i >= 0; i--) {
354
354
  const msg = newMessages[i];
355
355
  if (msg.role === "user") {
356
356
  const commandBlock = msg.blocks.find(
357
357
  (block) =>
358
- block.type === "command_output" &&
359
- block.command === command &&
360
- block.isRunning,
358
+ block.type === "bang" && block.command === command && block.isRunning,
361
359
  );
362
- if (commandBlock && commandBlock.type === "command_output") {
360
+ if (commandBlock && commandBlock.type === "bang") {
363
361
  commandBlock.isRunning = false;
364
362
  commandBlock.exitCode = exitCode;
363
+ if (output !== undefined) {
364
+ commandBlock.output = output.trim();
365
+ }
365
366
  break;
366
367
  }
367
368
  }
@@ -370,20 +371,49 @@ export const completeCommandInMessage = ({
370
371
  };
371
372
 
372
373
  /**
373
- * Removes the last user message from the messages array
374
+ * Helper to count tool blocks in messages
375
+ */
376
+ export function countToolBlocks(messages: Message[]): number {
377
+ let toolCount = 0;
378
+ messages.forEach((msg) => {
379
+ msg.blocks.forEach((block) => {
380
+ if (block.type === "tool") {
381
+ toolCount++;
382
+ }
383
+ });
384
+ });
385
+ return toolCount;
386
+ }
387
+
388
+ /**
389
+ * Remove the last user message from the conversation
374
390
  * Used for hook error handling when the user prompt needs to be erased
375
391
  */
376
392
  export const removeLastUserMessage = (messages: Message[]): Message[] => {
377
393
  const newMessages = [...messages];
378
-
379
- // Find the index of the last user message
380
394
  for (let i = newMessages.length - 1; i >= 0; i--) {
381
395
  if (newMessages[i].role === "user") {
382
- // Remove the user message at index i
383
396
  newMessages.splice(i, 1);
384
397
  break;
385
398
  }
386
399
  }
387
-
388
400
  return newMessages;
389
401
  };
402
+
403
+ /**
404
+ * Helper to format tool and token summary
405
+ */
406
+ export function formatToolTokenSummary(
407
+ toolCount: number,
408
+ tokens: number,
409
+ ): string {
410
+ if (toolCount === 0) {
411
+ return "";
412
+ }
413
+ let summary = `(${toolCount} tools`;
414
+ if (tokens > 0) {
415
+ summary += ` | ${tokens.toLocaleString()} tokens`;
416
+ }
417
+ summary += ")";
418
+ return summary;
419
+ }
@@ -69,10 +69,11 @@ const nouns = [
69
69
  ];
70
70
 
71
71
  /**
72
- * Generates a random English name (adjective-noun)
72
+ * Generates a random English name (adjective-adjective-noun)
73
73
  */
74
74
  export function generateRandomName(seed?: string): string {
75
- let adjIndex: number;
75
+ let adj1Index: number;
76
+ let adj2Index: number;
76
77
  let nounIndex: number;
77
78
 
78
79
  if (seed) {
@@ -82,14 +83,17 @@ export function generateRandomName(seed?: string): string {
82
83
  hash = (hash << 5) - hash + seed.charCodeAt(i);
83
84
  hash |= 0; // Convert to 32bit integer
84
85
  }
85
- adjIndex = Math.abs(hash) % adjectives.length;
86
+ adj1Index = Math.abs(hash) % adjectives.length;
87
+ adj2Index = Math.abs(hash >> 4) % adjectives.length;
86
88
  nounIndex = Math.abs(hash >> 8) % nouns.length;
87
89
  } else {
88
- adjIndex = Math.floor(Math.random() * adjectives.length);
90
+ adj1Index = Math.floor(Math.random() * adjectives.length);
91
+ adj2Index = Math.floor(Math.random() * adjectives.length);
89
92
  nounIndex = Math.floor(Math.random() * nouns.length);
90
93
  }
91
94
 
92
- const adj = adjectives[adjIndex];
95
+ const adj1 = adjectives[adj1Index];
96
+ const adj2 = adjectives[adj2Index];
93
97
  const noun = nouns[nounIndex];
94
- return `${adj}-${noun}`;
98
+ return `${adj1}-${adj2}-${noun}`;
95
99
  }
@@ -57,11 +57,40 @@ export function parseSkillFile(
57
57
  ? "project"
58
58
  : "personal";
59
59
 
60
+ // Extract allowed tools
61
+ let allowedTools: string[] | undefined;
62
+ const rawAllowedTools = result.frontmatter["allowed-tools"];
63
+ if (Array.isArray(rawAllowedTools)) {
64
+ allowedTools = rawAllowedTools.map((t) => String(t).trim());
65
+ } else if (typeof rawAllowedTools === "string") {
66
+ allowedTools = rawAllowedTools
67
+ .split(",")
68
+ .map((t) => t.trim())
69
+ .filter((t) => t.length > 0);
70
+ }
71
+
72
+ // Extract disable-model-invocation
73
+ const disableModelInvocation =
74
+ result.frontmatter["disable-model-invocation"] === true ||
75
+ result.frontmatter["disable-model-invocation"] === "true";
76
+
77
+ // Extract user-invocable (default to true)
78
+ const userInvocable =
79
+ result.frontmatter["user-invocable"] === undefined ||
80
+ result.frontmatter["user-invocable"] === true ||
81
+ result.frontmatter["user-invocable"] === "true";
82
+
60
83
  result.skillMetadata = {
61
84
  name: result.frontmatter.name,
62
85
  description: result.frontmatter.description,
63
86
  type: skillType,
64
87
  skillPath,
88
+ allowedTools,
89
+ context: result.frontmatter.context,
90
+ agent: result.frontmatter.agent,
91
+ model: result.frontmatter.model as string | undefined,
92
+ disableModelInvocation,
93
+ userInvocable,
65
94
  };
66
95
 
67
96
  // Validate metadata if requested
@@ -88,10 +117,29 @@ function parseYamlFrontmatter(yamlContent: string): SkillFrontmatter {
88
117
 
89
118
  try {
90
119
  const lines = yamlContent.split("\n");
120
+ let currentKey: string | null = null;
121
+
91
122
  for (const line of lines) {
92
123
  const trimmed = line.trim();
93
124
  if (!trimmed || trimmed.startsWith("#")) continue;
94
125
 
126
+ // Check for list item
127
+ if (trimmed.startsWith("-") && currentKey) {
128
+ const value = trimmed
129
+ .substring(1)
130
+ .trim()
131
+ .replace(/^["']|["']$/g, "");
132
+ if (value) {
133
+ const existing = frontmatter[currentKey];
134
+ if (Array.isArray(existing)) {
135
+ (existing as string[]).push(value);
136
+ } else {
137
+ frontmatter[currentKey] = [value];
138
+ }
139
+ }
140
+ continue;
141
+ }
142
+
95
143
  const colonIndex = trimmed.indexOf(":");
96
144
  if (colonIndex === -1) continue;
97
145
 
@@ -101,8 +149,12 @@ function parseYamlFrontmatter(yamlContent: string): SkillFrontmatter {
101
149
  .trim()
102
150
  .replace(/^["']|["']$/g, "");
103
151
 
152
+ currentKey = key;
104
153
  if (key && value) {
105
154
  frontmatter[key] = value;
155
+ } else if (key) {
156
+ // Key with no value on the same line, might be a list
157
+ frontmatter[key] = [];
106
158
  }
107
159
  }
108
160
  } catch {
@@ -1,27 +0,0 @@
1
- import type { BackgroundShell } from "../types/index.js";
2
- export interface BackgroundBashManagerCallbacks {
3
- onShellsChange?: (shells: BackgroundShell[]) => void;
4
- }
5
- export interface BackgroundBashManagerOptions {
6
- callbacks?: BackgroundBashManagerCallbacks;
7
- workdir: string;
8
- }
9
- export declare class BackgroundBashManager {
10
- private shells;
11
- private nextId;
12
- private callbacks;
13
- private workdir;
14
- constructor(options: BackgroundBashManagerOptions);
15
- private notifyShellsChange;
16
- startShell(command: string, timeout?: number): string;
17
- getShell(id: string): BackgroundShell | undefined;
18
- getAllShells(): BackgroundShell[];
19
- getOutput(id: string, filter?: string): {
20
- stdout: string;
21
- stderr: string;
22
- status: string;
23
- } | null;
24
- killShell(id: string): boolean;
25
- cleanup(): void;
26
- }
27
- //# sourceMappingURL=backgroundBashManager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"backgroundBashManager.d.ts","sourceRoot":"","sources":["../../src/managers/backgroundBashManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,8BAA8B;IAC7C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,8BAA8B,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,4BAA4B;IAKjD,OAAO,CAAC,kBAAkB;IAInB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM;IAuErD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIjD,YAAY,IAAI,eAAe,EAAE;IAIjC,SAAS,CACd,EAAE,EAAE,MAAM,EACV,MAAM,CAAC,EAAE,MAAM,GACd;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAiCrD,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAmD9B,OAAO,IAAI,IAAI;CAUvB"}
@@ -1,169 +0,0 @@
1
- import { spawn } from "child_process";
2
- import { logger } from "../utils/globalLogger.js";
3
- import { stripAnsiColors } from "../utils/stringUtils.js";
4
- export class BackgroundBashManager {
5
- constructor(options) {
6
- this.shells = new Map();
7
- this.nextId = 1;
8
- this.callbacks = options.callbacks || {};
9
- this.workdir = options.workdir;
10
- }
11
- notifyShellsChange() {
12
- this.callbacks.onShellsChange?.(Array.from(this.shells.values()));
13
- }
14
- startShell(command, timeout) {
15
- const id = `bash_${this.nextId++}`;
16
- const startTime = Date.now();
17
- const child = spawn(command, {
18
- shell: true,
19
- stdio: "pipe",
20
- cwd: this.workdir,
21
- env: {
22
- ...process.env,
23
- },
24
- });
25
- const shell = {
26
- id,
27
- type: "shell",
28
- process: child,
29
- command,
30
- startTime,
31
- status: "running",
32
- stdout: "",
33
- stderr: "",
34
- };
35
- this.shells.set(id, shell);
36
- this.notifyShellsChange();
37
- // Set up timeout if specified
38
- let timeoutHandle;
39
- if (timeout && timeout > 0) {
40
- timeoutHandle = setTimeout(() => {
41
- if (shell.status === "running") {
42
- this.killShell(id);
43
- }
44
- }, timeout);
45
- }
46
- child.stdout?.on("data", (data) => {
47
- shell.stdout += stripAnsiColors(data.toString());
48
- this.notifyShellsChange();
49
- });
50
- child.stderr?.on("data", (data) => {
51
- shell.stderr += stripAnsiColors(data.toString());
52
- this.notifyShellsChange();
53
- });
54
- child.on("exit", (code) => {
55
- if (timeoutHandle) {
56
- clearTimeout(timeoutHandle);
57
- }
58
- shell.status = "completed";
59
- shell.exitCode = code ?? 0;
60
- shell.runtime = Date.now() - startTime;
61
- this.notifyShellsChange();
62
- });
63
- child.on("error", (error) => {
64
- if (timeoutHandle) {
65
- clearTimeout(timeoutHandle);
66
- }
67
- shell.status = "completed";
68
- shell.stderr += `\nProcess error: ${stripAnsiColors(error.message)}`;
69
- shell.exitCode = 1;
70
- shell.runtime = Date.now() - startTime;
71
- this.notifyShellsChange();
72
- });
73
- return id;
74
- }
75
- getShell(id) {
76
- return this.shells.get(id);
77
- }
78
- getAllShells() {
79
- return Array.from(this.shells.values());
80
- }
81
- getOutput(id, filter) {
82
- const shell = this.shells.get(id);
83
- if (!shell) {
84
- return null;
85
- }
86
- let stdout = shell.stdout;
87
- let stderr = shell.stderr;
88
- // Apply regex filter if provided
89
- if (filter) {
90
- try {
91
- const regex = new RegExp(filter);
92
- stdout = stdout
93
- .split("\n")
94
- .filter((line) => regex.test(line))
95
- .join("\n");
96
- stderr = stderr
97
- .split("\n")
98
- .filter((line) => regex.test(line))
99
- .join("\n");
100
- }
101
- catch (error) {
102
- logger.warn(`Invalid filter regex: ${filter}`, error);
103
- }
104
- }
105
- return {
106
- stdout,
107
- stderr,
108
- status: shell.status,
109
- };
110
- }
111
- killShell(id) {
112
- const shell = this.shells.get(id);
113
- if (!shell || shell.status !== "running") {
114
- return false;
115
- }
116
- try {
117
- // Try to kill process group first
118
- if (shell.process.pid) {
119
- process.kill(-shell.process.pid, "SIGTERM");
120
- // Force kill after timeout
121
- setTimeout(() => {
122
- if (shell.status === "running" &&
123
- shell.process.pid &&
124
- !shell.process.killed) {
125
- try {
126
- process.kill(-shell.process.pid, "SIGKILL");
127
- }
128
- catch (error) {
129
- logger.error("Failed to force kill process:", error);
130
- }
131
- }
132
- }, 1000);
133
- }
134
- shell.status = "killed";
135
- shell.runtime = Date.now() - shell.startTime;
136
- this.notifyShellsChange();
137
- return true;
138
- }
139
- catch {
140
- // Fallback to direct process kill
141
- try {
142
- shell.process.kill("SIGTERM");
143
- setTimeout(() => {
144
- if (!shell.process.killed) {
145
- shell.process.kill("SIGKILL");
146
- }
147
- }, 1000);
148
- shell.status = "killed";
149
- shell.runtime = Date.now() - shell.startTime;
150
- this.notifyShellsChange();
151
- return true;
152
- }
153
- catch (directKillError) {
154
- logger.error("Failed to kill child process:", directKillError);
155
- return false;
156
- }
157
- }
158
- }
159
- cleanup() {
160
- // Kill all running shells
161
- for (const [id, shell] of this.shells) {
162
- if (shell.status === "running") {
163
- this.killShell(id);
164
- }
165
- }
166
- this.shells.clear();
167
- this.notifyShellsChange();
168
- }
169
- }