wave-agent-sdk 0.2.1 → 0.5.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 (194) hide show
  1. package/dist/agent.d.ts +66 -20
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +156 -83
  4. package/dist/constants/prompts.d.ts +7 -2
  5. package/dist/constants/prompts.d.ts.map +1 -1
  6. package/dist/constants/prompts.js +41 -5
  7. package/dist/constants/tools.d.ts +2 -2
  8. package/dist/constants/tools.js +2 -2
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/managers/MemoryRuleManager.d.ts.map +1 -1
  13. package/dist/managers/MemoryRuleManager.js +16 -2
  14. package/dist/managers/aiManager.d.ts +14 -4
  15. package/dist/managers/aiManager.d.ts.map +1 -1
  16. package/dist/managers/aiManager.js +61 -9
  17. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  18. package/dist/managers/backgroundBashManager.js +1 -0
  19. package/dist/managers/backgroundTaskManager.d.ts +35 -0
  20. package/dist/managers/backgroundTaskManager.d.ts.map +1 -0
  21. package/dist/managers/backgroundTaskManager.js +249 -0
  22. package/dist/managers/bashManager.d.ts.map +1 -1
  23. package/dist/managers/bashManager.js +0 -3
  24. package/dist/managers/foregroundTaskManager.d.ts +9 -0
  25. package/dist/managers/foregroundTaskManager.d.ts.map +1 -0
  26. package/dist/managers/foregroundTaskManager.js +20 -0
  27. package/dist/managers/liveConfigManager.d.ts +1 -1
  28. package/dist/managers/liveConfigManager.d.ts.map +1 -1
  29. package/dist/managers/lspManager.d.ts.map +1 -1
  30. package/dist/managers/lspManager.js +3 -1
  31. package/dist/managers/messageManager.d.ts +34 -4
  32. package/dist/managers/messageManager.d.ts.map +1 -1
  33. package/dist/managers/messageManager.js +104 -13
  34. package/dist/managers/permissionManager.d.ts.map +1 -1
  35. package/dist/managers/permissionManager.js +11 -13
  36. package/dist/managers/pluginManager.d.ts.map +1 -1
  37. package/dist/managers/pluginManager.js +3 -2
  38. package/dist/managers/pluginScopeManager.d.ts +13 -2
  39. package/dist/managers/pluginScopeManager.d.ts.map +1 -1
  40. package/dist/managers/pluginScopeManager.js +38 -0
  41. package/dist/managers/reversionManager.d.ts +39 -0
  42. package/dist/managers/reversionManager.d.ts.map +1 -0
  43. package/dist/managers/reversionManager.js +118 -0
  44. package/dist/managers/slashCommandManager.d.ts +4 -1
  45. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  46. package/dist/managers/slashCommandManager.js +16 -6
  47. package/dist/managers/subagentManager.d.ts +13 -2
  48. package/dist/managers/subagentManager.d.ts.map +1 -1
  49. package/dist/managers/subagentManager.js +144 -35
  50. package/dist/managers/toolManager.d.ts +11 -1
  51. package/dist/managers/toolManager.d.ts.map +1 -1
  52. package/dist/managers/toolManager.js +11 -3
  53. package/dist/services/GitService.d.ts.map +1 -1
  54. package/dist/services/GitService.js +6 -2
  55. package/dist/services/MarketplaceService.d.ts +14 -1
  56. package/dist/services/MarketplaceService.d.ts.map +1 -1
  57. package/dist/services/MarketplaceService.js +72 -4
  58. package/dist/services/MemoryRuleService.d.ts +1 -1
  59. package/dist/services/MemoryRuleService.d.ts.map +1 -1
  60. package/dist/services/MemoryRuleService.js +13 -2
  61. package/dist/services/aiService.js +1 -1
  62. package/dist/services/configurationService.d.ts +18 -2
  63. package/dist/services/configurationService.d.ts.map +1 -1
  64. package/dist/services/configurationService.js +62 -0
  65. package/dist/services/fileWatcher.d.ts +0 -5
  66. package/dist/services/fileWatcher.d.ts.map +1 -1
  67. package/dist/services/fileWatcher.js +0 -11
  68. package/dist/services/memory.js +1 -1
  69. package/dist/services/pluginLoader.d.ts.map +1 -1
  70. package/dist/services/pluginLoader.js +6 -1
  71. package/dist/services/reversionService.d.ts +24 -0
  72. package/dist/services/reversionService.d.ts.map +1 -0
  73. package/dist/services/reversionService.js +76 -0
  74. package/dist/services/session.d.ts +7 -0
  75. package/dist/services/session.d.ts.map +1 -1
  76. package/dist/services/session.js +126 -3
  77. package/dist/tools/bashTool.d.ts +0 -8
  78. package/dist/tools/bashTool.d.ts.map +1 -1
  79. package/dist/tools/bashTool.js +52 -174
  80. package/dist/tools/deleteFileTool.d.ts.map +1 -1
  81. package/dist/tools/deleteFileTool.js +9 -0
  82. package/dist/tools/editTool.d.ts.map +1 -1
  83. package/dist/tools/editTool.js +15 -4
  84. package/dist/tools/multiEditTool.d.ts.map +1 -1
  85. package/dist/tools/multiEditTool.js +16 -5
  86. package/dist/tools/taskOutputTool.d.ts +3 -0
  87. package/dist/tools/taskOutputTool.d.ts.map +1 -0
  88. package/dist/tools/taskOutputTool.js +149 -0
  89. package/dist/tools/taskStopTool.d.ts +3 -0
  90. package/dist/tools/taskStopTool.d.ts.map +1 -0
  91. package/dist/tools/taskStopTool.js +65 -0
  92. package/dist/tools/taskTool.d.ts.map +1 -1
  93. package/dist/tools/taskTool.js +105 -63
  94. package/dist/tools/types.d.ts +7 -0
  95. package/dist/tools/types.d.ts.map +1 -1
  96. package/dist/tools/writeTool.d.ts.map +1 -1
  97. package/dist/tools/writeTool.js +9 -0
  98. package/dist/types/commands.d.ts +1 -0
  99. package/dist/types/commands.d.ts.map +1 -1
  100. package/dist/types/configuration.d.ts +3 -0
  101. package/dist/types/configuration.d.ts.map +1 -1
  102. package/dist/types/environment.d.ts +2 -1
  103. package/dist/types/environment.d.ts.map +1 -1
  104. package/dist/types/environment.js +0 -6
  105. package/dist/types/history.d.ts +5 -0
  106. package/dist/types/history.d.ts.map +1 -0
  107. package/dist/types/history.js +1 -0
  108. package/dist/types/index.d.ts +1 -0
  109. package/dist/types/index.d.ts.map +1 -1
  110. package/dist/types/index.js +1 -0
  111. package/dist/types/marketplace.d.ts +4 -0
  112. package/dist/types/marketplace.d.ts.map +1 -1
  113. package/dist/types/messaging.d.ts +7 -1
  114. package/dist/types/messaging.d.ts.map +1 -1
  115. package/dist/types/processes.d.ts +24 -4
  116. package/dist/types/processes.d.ts.map +1 -1
  117. package/dist/types/reversion.d.ts +29 -0
  118. package/dist/types/reversion.d.ts.map +1 -0
  119. package/dist/types/reversion.js +1 -0
  120. package/dist/utils/builtinSubagents.d.ts.map +1 -1
  121. package/dist/utils/builtinSubagents.js +16 -0
  122. package/dist/utils/constants.d.ts +2 -2
  123. package/dist/utils/constants.d.ts.map +1 -1
  124. package/dist/utils/constants.js +2 -2
  125. package/dist/utils/editUtils.d.ts +4 -9
  126. package/dist/utils/editUtils.d.ts.map +1 -1
  127. package/dist/utils/editUtils.js +54 -55
  128. package/dist/utils/messageOperations.d.ts +3 -1
  129. package/dist/utils/messageOperations.d.ts.map +1 -1
  130. package/dist/utils/messageOperations.js +8 -1
  131. package/dist/utils/openaiClient.d.ts.map +1 -1
  132. package/dist/utils/openaiClient.js +56 -26
  133. package/dist/utils/promptHistory.d.ts +20 -0
  134. package/dist/utils/promptHistory.d.ts.map +1 -0
  135. package/dist/utils/promptHistory.js +117 -0
  136. package/package.json +5 -3
  137. package/src/agent.ts +193 -109
  138. package/src/constants/prompts.ts +45 -5
  139. package/src/constants/tools.ts +2 -2
  140. package/src/index.ts +1 -1
  141. package/src/managers/MemoryRuleManager.ts +18 -2
  142. package/src/managers/aiManager.ts +87 -18
  143. package/src/managers/backgroundBashManager.ts +1 -0
  144. package/src/managers/backgroundTaskManager.ts +306 -0
  145. package/src/managers/bashManager.ts +0 -4
  146. package/src/managers/foregroundTaskManager.ts +26 -0
  147. package/src/managers/liveConfigManager.ts +2 -1
  148. package/src/managers/lspManager.ts +3 -1
  149. package/src/managers/messageManager.ts +136 -18
  150. package/src/managers/permissionManager.ts +11 -13
  151. package/src/managers/pluginManager.ts +4 -3
  152. package/src/managers/pluginScopeManager.ts +57 -8
  153. package/src/managers/reversionManager.ts +152 -0
  154. package/src/managers/slashCommandManager.ts +30 -7
  155. package/src/managers/subagentManager.ts +176 -31
  156. package/src/managers/toolManager.ts +23 -4
  157. package/src/services/GitService.ts +6 -2
  158. package/src/services/MarketplaceService.ts +100 -4
  159. package/src/services/MemoryRuleService.ts +18 -6
  160. package/src/services/aiService.ts +1 -1
  161. package/src/services/configurationService.ts +79 -1
  162. package/src/services/fileWatcher.ts +0 -13
  163. package/src/services/memory.ts +1 -1
  164. package/src/services/pluginLoader.ts +7 -1
  165. package/src/services/reversionService.ts +94 -0
  166. package/src/services/session.ts +161 -3
  167. package/src/tools/bashTool.ts +73 -200
  168. package/src/tools/deleteFileTool.ts +15 -0
  169. package/src/tools/editTool.ts +20 -10
  170. package/src/tools/multiEditTool.ts +21 -11
  171. package/src/tools/taskOutputTool.ts +174 -0
  172. package/src/tools/taskStopTool.ts +72 -0
  173. package/src/tools/taskTool.ts +130 -74
  174. package/src/tools/types.ts +7 -0
  175. package/src/tools/writeTool.ts +14 -0
  176. package/src/types/commands.ts +3 -0
  177. package/src/types/configuration.ts +4 -0
  178. package/src/types/environment.ts +3 -1
  179. package/src/types/history.ts +4 -0
  180. package/src/types/index.ts +1 -0
  181. package/src/types/marketplace.ts +5 -0
  182. package/src/types/messaging.ts +9 -1
  183. package/src/types/processes.ts +33 -4
  184. package/src/types/reversion.ts +29 -0
  185. package/src/utils/builtinSubagents.ts +18 -0
  186. package/src/utils/constants.ts +2 -2
  187. package/src/utils/editUtils.ts +66 -58
  188. package/src/utils/messageOperations.ts +10 -0
  189. package/src/utils/openaiClient.ts +69 -35
  190. package/src/utils/promptHistory.ts +133 -0
  191. package/dist/utils/bashHistory.d.ts +0 -50
  192. package/dist/utils/bashHistory.d.ts.map +0 -1
  193. package/dist/utils/bashHistory.js +0 -256
  194. package/src/utils/bashHistory.ts +0 -320
@@ -379,6 +379,23 @@ export class ConfigurationService {
379
379
  // Use default
380
380
  return DEFAULT_WAVE_MAX_INPUT_TOKENS;
381
381
  }
382
+ /**
383
+ * Resolves preferred language with fallbacks
384
+ * Resolution priority: options > settings.json > undefined
385
+ * @param constructorLanguage - Language from constructor (optional)
386
+ * @returns Resolved language or undefined
387
+ */
388
+ resolveLanguage(constructorLanguage) {
389
+ // 1. Constructor options (highest priority)
390
+ if (constructorLanguage !== undefined) {
391
+ return constructorLanguage;
392
+ }
393
+ // 2. settings.json (merged)
394
+ if (this.currentConfiguration?.language) {
395
+ return this.currentConfiguration.language;
396
+ }
397
+ return undefined;
398
+ }
382
399
  /**
383
400
  * Resolves max output tokens with fallbacks
384
401
  * Resolution priority: options > env (from settings.json) > process.env > default
@@ -483,6 +500,38 @@ export class ConfigurationService {
483
500
  config.enabledPlugins[pluginId] = enabled;
484
501
  await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
485
502
  }
503
+ /**
504
+ * Remove a plugin from the enabled plugins in the specified scope
505
+ */
506
+ async removeEnabledPlugin(workdir, scope, pluginId) {
507
+ if (scope !== "user" && !existsSync(workdir)) {
508
+ throw new Error(`Working directory does not exist: ${workdir}`);
509
+ }
510
+ let configPath;
511
+ if (scope === "user") {
512
+ configPath = getUserConfigPaths()[1]; // settings.json
513
+ }
514
+ else if (scope === "project") {
515
+ configPath = getProjectConfigPaths(workdir)[1]; // settings.json
516
+ }
517
+ else {
518
+ configPath = getProjectConfigPaths(workdir)[0]; // settings.local.json
519
+ }
520
+ if (!existsSync(configPath)) {
521
+ return; // Nothing to remove
522
+ }
523
+ try {
524
+ const content = await fs.readFile(configPath, "utf-8");
525
+ const config = JSON.parse(content);
526
+ if (config.enabledPlugins && pluginId in config.enabledPlugins) {
527
+ delete config.enabledPlugins[pluginId];
528
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
529
+ }
530
+ }
531
+ catch {
532
+ // Ignore errors for corrupted or non-existent files
533
+ }
534
+ }
486
535
  /**
487
536
  * Get merged enabled plugins from all scopes
488
537
  */
@@ -490,6 +539,13 @@ export class ConfigurationService {
490
539
  const mergedConfig = loadMergedWaveConfig(workdir);
491
540
  return mergedConfig?.enabledPlugins || {};
492
541
  }
542
+ /**
543
+ * Load Wave configuration from a JSON file
544
+ * Supports both hooks and environment variables with proper validation
545
+ */
546
+ loadWaveConfigFromFile(filePath) {
547
+ return loadWaveConfigFromFile(filePath);
548
+ }
493
549
  }
494
550
  // =============================================================================
495
551
  // Extracted Configuration Functions
@@ -604,6 +660,7 @@ export function loadWaveConfigFromFile(filePath) {
604
660
  env: config.env || undefined,
605
661
  permissions: config.permissions || undefined,
606
662
  enabledPlugins: config.enabledPlugins || undefined,
663
+ language: config.language || undefined,
607
664
  };
608
665
  }
609
666
  catch (error) {
@@ -735,6 +792,10 @@ export function loadMergedWaveConfig(workdir) {
735
792
  mergedConfig.enabledPlugins = {};
736
793
  Object.assign(mergedConfig.enabledPlugins, config.enabledPlugins);
737
794
  }
795
+ // Merge language (last one wins)
796
+ if (config.language !== undefined) {
797
+ mergedConfig.language = config.language;
798
+ }
738
799
  }
739
800
  return {
740
801
  hooks: mergedConfig.hooks && Object.keys(mergedConfig.hooks).length > 0
@@ -751,5 +812,6 @@ export function loadMergedWaveConfig(workdir) {
751
812
  Object.keys(mergedConfig.enabledPlugins).length > 0
752
813
  ? mergedConfig.enabledPlugins
753
814
  : undefined,
815
+ language: mergedConfig.language,
754
816
  };
755
817
  }
@@ -53,11 +53,6 @@ export declare class FileWatcherService extends EventEmitter {
53
53
  * For monitoring and debugging
54
54
  */
55
55
  getAllWatcherStatuses(): FileWatcherStatus[];
56
- /**
57
- * Configure watcher behavior
58
- * Runtime configuration updates
59
- */
60
- updateConfig(config: Partial<FileWatcherConfig>): void;
61
56
  /**
62
57
  * Cleanup all watchers
63
58
  */
@@ -1 +1 @@
1
- {"version":3,"file":"fileWatcher.d.ts","sourceRoot":"","sources":["../../src/services/fileWatcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B;AAaD,qBAAa,kBAAmB,SAAQ,YAAY;IAClD,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAahE;;;OAGG;IACG,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GACxC,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;OAGG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB9C;;;OAGG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IA0BxD;;;OAGG;IACH,qBAAqB,IAAI,iBAAiB,EAAE;IAM5C;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI;IAStD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAUhB,iBAAiB;IAkD/B,OAAO,CAAC,wBAAwB;IA4BhC,OAAO,CAAC,eAAe;CA8BxB"}
1
+ {"version":3,"file":"fileWatcher.d.ts","sourceRoot":"","sources":["../../src/services/fileWatcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B;AAaD,qBAAa,kBAAmB,SAAQ,YAAY;IAClD,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAahE;;;OAGG;IACG,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GACxC,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;OAGG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB9C;;;OAGG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IA0BxD;;;OAGG;IACH,qBAAqB,IAAI,iBAAiB,EAAE;IAM5C;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAUhB,iBAAiB;IAkD/B,OAAO,CAAC,wBAAwB;IA4BhC,OAAO,CAAC,eAAe;CA8BxB"}
@@ -107,17 +107,6 @@ export class FileWatcherService extends EventEmitter {
107
107
  .map((path) => this.getWatcherStatus(path))
108
108
  .filter((status) => status !== null);
109
109
  }
110
- /**
111
- * Configure watcher behavior
112
- * Runtime configuration updates
113
- */
114
- updateConfig(config) {
115
- this.defaultConfig = { ...this.defaultConfig, ...config };
116
- // Update existing watchers with new config
117
- for (const entry of this.watchers.values()) {
118
- entry.config = { ...entry.config, ...config };
119
- }
120
- }
121
110
  /**
122
111
  * Cleanup all watchers
123
112
  */
@@ -126,7 +126,7 @@ export const readMemoryFile = async (workdir) => {
126
126
  return "";
127
127
  }
128
128
  logger.error("Failed to read memory file", { memoryFilePath, error });
129
- throw error;
129
+ return "";
130
130
  }
131
131
  };
132
132
  // Get merged memory content (project memory + user memory)
@@ -1 +1 @@
1
- {"version":3,"file":"pluginLoader.d.ts","sourceRoot":"","sources":["../../src/services/pluginLoader.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,EACL,SAAS,EACT,SAAS,EACT,wBAAwB,EACzB,MAAM,mBAAmB,CAAC;AAI3B,qBAAa,YAAY;IACvB;;;OAGG;WACU,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA6CtE;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAK7D;;;OAGG;WACU,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAwC7D;;OAEG;WACU,aAAa,CACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAUjC;;OAEG;WACU,aAAa,CACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAUjC;;OAEG;WACU,eAAe,CAC1B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC;IAUhD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;CAgBhC"}
1
+ {"version":3,"file":"pluginLoader.d.ts","sourceRoot":"","sources":["../../src/services/pluginLoader.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,EACL,SAAS,EACT,SAAS,EACT,wBAAwB,EACzB,MAAM,mBAAmB,CAAC;AAI3B,qBAAa,YAAY;IACvB;;;OAGG;WACU,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA6CtE;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAW7D;;;OAGG;WACU,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAwC7D;;OAEG;WACU,aAAa,CACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAUjC;;OAEG;WACU,aAAa,CACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAUjC;;OAEG;WACU,eAAe,CAC1B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC;IAUhD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;CAgBhC"}
@@ -45,7 +45,12 @@ export class PluginLoader {
45
45
  */
46
46
  static loadCommands(pluginPath) {
47
47
  const commandsPath = path.join(pluginPath, "commands");
48
- return scanCommandsDirectory(commandsPath);
48
+ const commands = scanCommandsDirectory(commandsPath);
49
+ // Attach plugin path to each command for WAVE_PLUGIN_ROOT support
50
+ return commands.map((command) => ({
51
+ ...command,
52
+ pluginPath,
53
+ }));
49
54
  }
50
55
  /**
51
56
  * Load skills from a plugin's skills directory
@@ -0,0 +1,24 @@
1
+ import { FileSnapshot } from "../types/reversion.js";
2
+ export declare class ReversionService {
3
+ private historyBaseDir;
4
+ private sessionId;
5
+ constructor(sessionId: string);
6
+ private getFilePathHash;
7
+ private getNextVersion;
8
+ private updateVersionsFile;
9
+ /**
10
+ * Saves a single snapshot to the file history directory.
11
+ * Returns the snapshot path.
12
+ */
13
+ saveSnapshot(snapshot: FileSnapshot): Promise<string>;
14
+ /**
15
+ * Reads snapshot content from the given path.
16
+ */
17
+ readSnapshotContent(snapshotPath: string): Promise<string | null>;
18
+ /**
19
+ * Deletes all snapshots for this session.
20
+ */
21
+ deleteSessionHistory(): Promise<void>;
22
+ private ensureDirectory;
23
+ }
24
+ //# sourceMappingURL=reversionService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversionService.d.ts","sourceRoot":"","sources":["../../src/services/reversionService.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,EAAE,MAAM;IAK7B,OAAO,CAAC,eAAe;YAIT,cAAc;YAad,kBAAkB;IAOhC;;;OAGG;IACG,YAAY,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAuB3D;;OAEG;IACG,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAWvE;;OAEG;IACG,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;YAI7B,eAAe;CAG9B"}
@@ -0,0 +1,76 @@
1
+ import { readFile, writeFile, mkdir, rm } from "fs/promises";
2
+ import { join } from "path";
3
+ import { homedir } from "os";
4
+ import { createHash } from "crypto";
5
+ export class ReversionService {
6
+ constructor(sessionId) {
7
+ this.sessionId = sessionId;
8
+ this.historyBaseDir = join(homedir(), ".wave", "file-history", sessionId);
9
+ }
10
+ getFilePathHash(filePath) {
11
+ return createHash("md5").update(filePath).digest("hex");
12
+ }
13
+ async getNextVersion(fileHashDir) {
14
+ try {
15
+ const files = await readFile(join(fileHashDir, "versions"), "utf-8");
16
+ const versions = files
17
+ .split("\n")
18
+ .map((v) => parseInt(v, 10))
19
+ .filter((v) => !isNaN(v));
20
+ return versions.length > 0 ? Math.max(...versions) + 1 : 1;
21
+ }
22
+ catch {
23
+ return 1;
24
+ }
25
+ }
26
+ async updateVersionsFile(fileHashDir, version) {
27
+ await appendFile(join(fileHashDir, "versions"), `${version}\n`, "utf-8");
28
+ }
29
+ /**
30
+ * Saves a single snapshot to the file history directory.
31
+ * Returns the snapshot path.
32
+ */
33
+ async saveSnapshot(snapshot) {
34
+ const fileHash = this.getFilePathHash(snapshot.filePath);
35
+ const fileHashDir = join(this.historyBaseDir, fileHash);
36
+ await this.ensureDirectory(fileHashDir);
37
+ const version = await this.getNextVersion(fileHashDir);
38
+ const snapshotPath = join(fileHashDir, `v${version}`);
39
+ const snapshotWithContent = snapshot;
40
+ if (snapshotWithContent.content !== null) {
41
+ await writeFile(snapshotPath, snapshotWithContent.content, "utf-8");
42
+ }
43
+ else {
44
+ // For 'create' operation, the file didn't exist, so we don't write a content file.
45
+ // The absence of the file at snapshotPath will indicate it should be deleted on reversion.
46
+ return ""; // Return empty string to indicate no snapshot file
47
+ }
48
+ await this.updateVersionsFile(fileHashDir, version);
49
+ return snapshotPath;
50
+ }
51
+ /**
52
+ * Reads snapshot content from the given path.
53
+ */
54
+ async readSnapshotContent(snapshotPath) {
55
+ try {
56
+ return await readFile(snapshotPath, "utf-8");
57
+ }
58
+ catch (error) {
59
+ if (error.code === "ENOENT") {
60
+ return null;
61
+ }
62
+ throw error;
63
+ }
64
+ }
65
+ /**
66
+ * Deletes all snapshots for this session.
67
+ */
68
+ async deleteSessionHistory() {
69
+ await rm(this.historyBaseDir, { recursive: true, force: true });
70
+ }
71
+ async ensureDirectory(dirPath) {
72
+ await mkdir(dirPath, { recursive: true });
73
+ }
74
+ }
75
+ // Helper to avoid appendFile import error if not imported
76
+ import { appendFile } from "fs/promises";
@@ -31,6 +31,13 @@ export interface SessionMetadata {
31
31
  workdir: string;
32
32
  lastActiveAt: Date;
33
33
  latestTotalTokens: number;
34
+ firstMessage?: string;
35
+ }
36
+ export interface SessionIndex {
37
+ sessions: Record<string, Omit<SessionMetadata, "id" | "lastActiveAt"> & {
38
+ lastActiveAt: string;
39
+ }>;
40
+ lastUpdated: string;
34
41
  }
35
42
  /**
36
43
  * Generate a new session ID using Node.js native crypto.randomUUID()
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/services/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/services/session.ts"],"names":[],"mappings":"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"}
@@ -40,6 +40,32 @@ export function generateSubagentFilename(sessionId) {
40
40
  // Constants
41
41
  export const SESSION_DIR = join(homedir(), ".wave", "projects");
42
42
  const MAX_SESSION_AGE_DAYS = 14;
43
+ const SESSION_INDEX_FILENAME = "sessions-index.json";
44
+ /**
45
+ * Update the session index for a project directory
46
+ */
47
+ async function updateSessionIndex(projectDirPath, metadata) {
48
+ const indexPath = join(projectDirPath, SESSION_INDEX_FILENAME);
49
+ let index = {
50
+ sessions: {},
51
+ lastUpdated: new Date().toISOString(),
52
+ };
53
+ try {
54
+ const content = await fs.readFile(indexPath, "utf8");
55
+ index = JSON.parse(content);
56
+ }
57
+ catch {
58
+ // Index doesn't exist or is invalid, start fresh
59
+ }
60
+ const { id, ...rest } = metadata;
61
+ index.sessions[id] = {
62
+ ...rest,
63
+ lastActiveAt: metadata.lastActiveAt.toISOString(),
64
+ firstMessage: metadata.firstMessage || index.sessions[id]?.firstMessage,
65
+ };
66
+ index.lastUpdated = new Date().toISOString();
67
+ await fs.writeFile(indexPath, JSON.stringify(index, null, 2), "utf8");
68
+ }
43
69
  /**
44
70
  * Ensure session directory exists
45
71
  */
@@ -126,6 +152,36 @@ export async function appendMessages(sessionId, newMessages, workdir, sessionTyp
126
152
  await jsonlHandler.append(filePath, messagesWithTimestamp, {
127
153
  atomic: false,
128
154
  });
155
+ // Update index
156
+ const encoder = new PathEncoder();
157
+ const projectDir = await encoder.getProjectDirectory(workdir, SESSION_DIR);
158
+ const lastMessage = messagesWithTimestamp[messagesWithTimestamp.length - 1];
159
+ // Get first message content if it's a new session or we don't have it
160
+ let firstMessage;
161
+ try {
162
+ const indexPath = join(projectDir.encodedPath, SESSION_INDEX_FILENAME);
163
+ const content = await fs.readFile(indexPath, "utf8");
164
+ const index = JSON.parse(content);
165
+ if (!index.sessions[sessionId]?.firstMessage) {
166
+ firstMessage =
167
+ (await getFirstMessageContent(sessionId, workdir)) || undefined;
168
+ }
169
+ }
170
+ catch {
171
+ // If index doesn't exist, this might be the first message
172
+ firstMessage =
173
+ (await getFirstMessageContent(sessionId, workdir)) || undefined;
174
+ }
175
+ await updateSessionIndex(projectDir.encodedPath, {
176
+ id: sessionId,
177
+ sessionType,
178
+ workdir,
179
+ lastActiveAt: new Date(lastMessage.timestamp),
180
+ latestTotalTokens: lastMessage.usage
181
+ ? extractLatestTotalTokens([lastMessage])
182
+ : 0,
183
+ firstMessage,
184
+ });
129
185
  }
130
186
  /**
131
187
  * Load session data from JSONL file (new approach)
@@ -224,6 +280,23 @@ export async function listSessionsFromJsonl(workdir) {
224
280
  const encoder = new PathEncoder();
225
281
  const baseDir = SESSION_DIR;
226
282
  const projectDir = await encoder.getProjectDirectory(workdir, baseDir);
283
+ // Try to read from index first
284
+ const indexPath = join(projectDir.encodedPath, SESSION_INDEX_FILENAME);
285
+ try {
286
+ const indexContent = await fs.readFile(indexPath, "utf8");
287
+ const index = JSON.parse(indexContent);
288
+ const sessions = Object.entries(index.sessions)
289
+ .filter(([, meta]) => meta.sessionType === "main")
290
+ .map(([id, meta]) => ({
291
+ id,
292
+ ...meta,
293
+ lastActiveAt: new Date(meta.lastActiveAt),
294
+ }));
295
+ return sessions.sort((a, b) => b.lastActiveAt.getTime() - a.lastActiveAt.getTime());
296
+ }
297
+ catch {
298
+ // Fallback to manual listing if index fails
299
+ }
227
300
  let files;
228
301
  try {
229
302
  files = await fs.readdir(projectDir.encodedPath);
@@ -266,7 +339,7 @@ export async function listSessionsFromJsonl(workdir) {
266
339
  lastActiveAt = stats.mtime;
267
340
  }
268
341
  // Return inline object for performance (no interface instantiation overhead)
269
- sessions.push({
342
+ const sessionMeta = {
270
343
  id: sessionId,
271
344
  sessionType: "main",
272
345
  subagentType: undefined, // No longer stored in metadata
@@ -275,7 +348,18 @@ export async function listSessionsFromJsonl(workdir) {
275
348
  latestTotalTokens: lastMessage?.usage
276
349
  ? extractLatestTotalTokens([lastMessage])
277
350
  : 0,
278
- });
351
+ };
352
+ // Try to get first message content for the fallback/rebuild case
353
+ try {
354
+ const firstContent = await getFirstMessageContent(sessionId, workdir);
355
+ if (firstContent) {
356
+ sessionMeta.firstMessage = firstContent;
357
+ }
358
+ }
359
+ catch {
360
+ // Ignore errors getting first message
361
+ }
362
+ sessions.push(sessionMeta);
279
363
  }
280
364
  catch {
281
365
  // Skip corrupted session files
@@ -283,7 +367,26 @@ export async function listSessionsFromJsonl(workdir) {
283
367
  }
284
368
  }
285
369
  // Sort by last active time (most recently active first)
286
- return sessions.sort((a, b) => b.lastActiveAt.getTime() - a.lastActiveAt.getTime());
370
+ const sortedSessions = sessions.sort((a, b) => b.lastActiveAt.getTime() - a.lastActiveAt.getTime());
371
+ // Rebuild index if we had to fall back
372
+ try {
373
+ const index = {
374
+ sessions: {},
375
+ lastUpdated: new Date().toISOString(),
376
+ };
377
+ for (const session of sessions) {
378
+ const { id, ...rest } = session;
379
+ index.sessions[id] = {
380
+ ...rest,
381
+ lastActiveAt: session.lastActiveAt.toISOString(),
382
+ };
383
+ }
384
+ await fs.writeFile(indexPath, JSON.stringify(index, null, 2), "utf8");
385
+ }
386
+ catch (error) {
387
+ logger.warn(`Failed to rebuild session index for ${workdir}:`, error);
388
+ }
389
+ return sortedSessions;
287
390
  }
288
391
  catch (error) {
289
392
  throw new Error(`Failed to list sessions: ${error}`);
@@ -318,6 +421,26 @@ export async function cleanupExpiredSessionsFromJsonl(workdir) {
318
421
  if (fileAge > maxAge) {
319
422
  await fs.unlink(filePath);
320
423
  deletedCount++;
424
+ // Remove from index if it exists
425
+ try {
426
+ const indexPath = join(projectDir.encodedPath, SESSION_INDEX_FILENAME);
427
+ const indexContent = await fs.readFile(indexPath, "utf8");
428
+ const index = JSON.parse(indexContent);
429
+ const uuidMatch = file.match(/^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/);
430
+ const subagentMatch = file.match(/^subagent-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/);
431
+ const sessionId = uuidMatch
432
+ ? uuidMatch[1]
433
+ : subagentMatch
434
+ ? subagentMatch[1]
435
+ : null;
436
+ if (sessionId && index.sessions[sessionId]) {
437
+ delete index.sessions[sessionId];
438
+ await fs.writeFile(indexPath, JSON.stringify(index, null, 2), "utf8");
439
+ }
440
+ }
441
+ catch {
442
+ // Ignore index update errors during cleanup
443
+ }
321
444
  }
322
445
  }
323
446
  catch {
@@ -3,12 +3,4 @@ import type { ToolPlugin } from "./types.js";
3
3
  * Bash command execution tool - supports both foreground and background execution
4
4
  */
5
5
  export declare const bashTool: ToolPlugin;
6
- /**
7
- * BashOutput tool - retrieves output from background bash shells
8
- */
9
- export declare const bashOutputTool: ToolPlugin;
10
- /**
11
- * KillBash tool - kills a running background bash shell
12
- */
13
- export declare const killBashTool: ToolPlugin;
14
6
  //# sourceMappingURL=bashTool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bashTool.d.ts","sourceRoot":"","sources":["../../src/tools/bashTool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAetE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UA0TtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,UA+F5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,UA8E1B,CAAC"}
1
+ {"version":3,"file":"bashTool.d.ts","sourceRoot":"","sources":["../../src/tools/bashTool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AActE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UAmXtB,CAAC"}