wave-agent-sdk 0.0.17-alpha.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/agent.d.ts +2 -1
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +23 -2
  4. package/dist/constants/prompts.d.ts +1 -0
  5. package/dist/constants/prompts.d.ts.map +1 -1
  6. package/dist/constants/prompts.js +21 -0
  7. package/dist/managers/MemoryRuleManager.d.ts +31 -0
  8. package/dist/managers/MemoryRuleManager.d.ts.map +1 -0
  9. package/dist/managers/MemoryRuleManager.js +110 -0
  10. package/dist/managers/messageManager.d.ts +10 -0
  11. package/dist/managers/messageManager.d.ts.map +1 -1
  12. package/dist/managers/messageManager.js +61 -0
  13. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  14. package/dist/managers/slashCommandManager.js +16 -0
  15. package/dist/services/MemoryRuleService.d.ts +12 -0
  16. package/dist/services/MemoryRuleService.d.ts.map +1 -0
  17. package/dist/services/MemoryRuleService.js +44 -0
  18. package/dist/types/index.d.ts +1 -0
  19. package/dist/types/index.d.ts.map +1 -1
  20. package/dist/types/index.js +1 -0
  21. package/dist/types/memoryRule.d.ts +31 -0
  22. package/dist/types/memoryRule.d.ts.map +1 -0
  23. package/dist/types/memoryRule.js +1 -0
  24. package/dist/utils/constants.d.ts +1 -1
  25. package/dist/utils/constants.js +1 -1
  26. package/dist/utils/markdownParser.d.ts +7 -0
  27. package/dist/utils/markdownParser.d.ts.map +1 -1
  28. package/dist/utils/markdownParser.js +13 -3
  29. package/package.json +1 -1
  30. package/src/agent.ts +27 -2
  31. package/src/constants/prompts.ts +22 -0
  32. package/src/managers/MemoryRuleManager.ts +148 -0
  33. package/src/managers/messageManager.ts +67 -0
  34. package/src/managers/slashCommandManager.ts +19 -0
  35. package/src/services/MemoryRuleService.ts +59 -0
  36. package/src/types/index.ts +1 -0
  37. package/src/types/memoryRule.ts +31 -0
  38. package/src/utils/constants.ts +1 -1
  39. package/src/utils/markdownParser.ts +16 -3
package/dist/agent.d.ts CHANGED
@@ -61,6 +61,7 @@ export declare class Agent {
61
61
  private pluginManager;
62
62
  private skillManager;
63
63
  private hookManager;
64
+ private memoryRuleManager;
64
65
  private liveConfigManager;
65
66
  private configurationService;
66
67
  private workdir;
@@ -116,7 +117,7 @@ export declare class Agent {
116
117
  get projectMemory(): string;
117
118
  /** Get user memory content */
118
119
  get userMemory(): string;
119
- /** Get combined memory content (project + user) */
120
+ /** Get combined memory content (project + user + modular rules) */
120
121
  get combinedMemory(): string;
121
122
  /** Get AI loading status */
122
123
  get isLoading(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
package/dist/agent.js CHANGED
@@ -9,9 +9,10 @@ import { BashManager } from "./managers/bashManager.js";
9
9
  import { BackgroundBashManager, } from "./managers/backgroundBashManager.js";
10
10
  import { SlashCommandManager } from "./managers/slashCommandManager.js";
11
11
  import { PluginManager } from "./managers/pluginManager.js";
12
+ import { HookManager } from "./managers/hookManager.js";
12
13
  import { PermissionManager } from "./managers/permissionManager.js";
13
14
  import { PlanManager } from "./managers/planManager.js";
14
- import { HookManager } from "./managers/hookManager.js";
15
+ import { MemoryRuleManager } from "./managers/MemoryRuleManager.js";
15
16
  import { LiveConfigManager } from "./managers/liveConfigManager.js";
16
17
  import { configValidator } from "./utils/configValidator.js";
17
18
  import { SkillManager } from "./managers/skillManager.js";
@@ -118,6 +119,10 @@ export class Agent {
118
119
  workdir: this.workdir,
119
120
  logger: this.logger,
120
121
  });
122
+ // Initialize memory rule manager
123
+ this.memoryRuleManager = new MemoryRuleManager({
124
+ workdir: this.workdir,
125
+ });
121
126
  // Create a wrapper for canUseTool that triggers notification hooks
122
127
  const canUseToolWithNotification = options.canUseTool
123
128
  ? async (context) => {
@@ -295,7 +300,7 @@ export class Agent {
295
300
  get userMemory() {
296
301
  return this._userMemoryContent;
297
302
  }
298
- /** Get combined memory content (project + user) */
303
+ /** Get combined memory content (project + user + modular rules) */
299
304
  get combinedMemory() {
300
305
  let combined = "";
301
306
  if (this._projectMemoryContent.trim()) {
@@ -307,6 +312,15 @@ export class Agent {
307
312
  }
308
313
  combined += this._userMemoryContent;
309
314
  }
315
+ // Add modular memory rules
316
+ const filesInContext = this.messageManager.getFilesInContext();
317
+ const activeRules = this.memoryRuleManager.getActiveRules(filesInContext);
318
+ if (activeRules.length > 0) {
319
+ if (combined) {
320
+ combined += "\n\n";
321
+ }
322
+ combined += activeRules.map((r) => r.content).join("\n\n");
323
+ }
310
324
  return combined;
311
325
  }
312
326
  /** Get AI loading status */
@@ -443,6 +457,13 @@ export class Agent {
443
457
  }
444
458
  // Resolve and validate configuration after loading settings.json
445
459
  this.resolveAndValidateConfig();
460
+ // Discover modular memory rules
461
+ try {
462
+ await this.memoryRuleManager.discoverRules();
463
+ }
464
+ catch (error) {
465
+ this.logger?.error("Failed to discover memory rules:", error);
466
+ }
446
467
  // Set global logger for SDK-wide access after validation
447
468
  setGlobalLogger(this.logger || null);
448
469
  // Initialize live configuration reload
@@ -5,6 +5,7 @@ export declare const SUBAGENT_POLICY = "\n- When doing file search, prefer to us
5
5
  export declare const FILE_TOOL_POLICY = "\n- Use specialized tools instead of bash commands when possible, as this provides a better user experience. For file operations, use dedicated tools: Read for reading files instead of cat/head/tail, Edit/MultiEdit for editing instead of sed/awk, Write for creating files instead of cat with heredoc or echo redirection, and LS/Glob/Grep for searching and listing files instead of find/ls/grep.";
6
6
  export declare const BASH_POLICY = "\n- Reserve bash tools exclusively for actual system commands and terminal operations that require shell execution. NEVER use bash echo or other command-line tools to communicate thoughts, explanations, or instructions to the user. Output all communication directly in your response text instead.\n- When making multiple bash tool calls, you MUST send a single message with multiple tools calls to run the calls in parallel. For example, if you need to run \"git status\" and \"git diff\", send a single message with two tool calls to run the calls in parallel.";
7
7
  export declare const DEFAULT_SYSTEM_PROMPT = "You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.\n\n# Doing tasks\nThe user will primarily request you perform software engineering tasks. This includes solving bugs, adding new functionality, refactoring code, explaining code, and more. For these tasks the following steps are recommended:\n- NEVER propose changes to code you haven't read. If a user asks about or wants you to modify a file, read it first. Understand existing code before suggesting modifications.\n- Be careful not to introduce security vulnerabilities such as command injection, XSS, SQL injection, and other OWASP top 10 vulnerabilities. If you notice that you wrote insecure code, immediately fix it.\n- Avoid over-engineering. Only make changes that are directly requested or clearly necessary. Keep solutions simple and focused.\n - Don't add features, refactor code, or make \"improvements\" beyond what was asked. A bug fix doesn't need surrounding code cleaned up. A simple feature doesn't need extra configurability. Don't add docstrings, comments, or type annotations to code you didn't change. Only add comments where the logic isn't self-evident.\n - Don't add error handling, fallbacks, or validation for scenarios that can't happen. Trust internal code and framework guarantees. Only validate at system boundaries (user input, external APIs). Don't use feature flags or backwards-compatibility shims when you can just change the code.\n - Don't create helpers, utilities, or abstractions for one-time operations. Don't design for hypothetical future requirements. The right amount of complexity is the minimum needed for the current task\u2014three similar lines of code is better than a premature abstraction.\n- Avoid backwards-compatibility hacks like renaming unused `_vars`, re-exporting types, adding `// removed` comments for removed code, etc. If something is unused, delete it completely.\n\n# Tool usage policy\n- You can call multiple tools in a single response. If you intend to call multiple tools and there are no dependencies between them, make all independent tool calls in parallel. Maximize use of parallel tool calls where possible to increase efficiency.\n- However, if some tool calls depend on previous calls to inform dependent values, do NOT call these tools in parallel and instead call them sequentially. For instance, if one operation must complete before another starts, run these operations sequentially instead. Never use placeholders or guess missing parameters in tool calls.\n- If the user specifies that they want you to run tools \"in parallel\", you MUST send a single message with multiple tool use content blocks.";
8
+ export declare const INIT_PROMPT = "Please analyze this codebase and create a AGENTS.md file, which will be given to future instances of Wave Code to operate in this repository.\n\nWhat to add:\n1. Commands that will be commonly used, such as how to build, lint, and run tests. Include the necessary commands to develop in this codebase, such as how to run a single test.\n2. High-level code architecture and structure so that future instances can be productive more quickly. Focus on the \"big picture\" architecture that requires reading multiple files to understand.\n\nUsage notes:\n- If there's already a AGENTS.md, suggest improvements to it.\n- When you make the initial AGENTS.md, do not repeat yourself and do not include obvious instructions like \"Provide helpful error messages to users\", \"Write unit tests for all new utilities\", \"Never include sensitive information (API keys, tokens) in code or commits\".\n- Avoid listing every component or file structure that can be easily discovered.\n- Don't include generic development practices.\n- If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include the important parts.\n- If there is a README.md, make sure to include the important parts.\n- Do not make up information such as \"Common Development Tasks\", \"Tips for Development\", \"Support and Documentation\" unless this is expressly included in other files that you read.\n- Be sure to prefix the file with the following text:\n\n```\n# AGENTS.md\n\nThis file provides guidance to Wave Code when working with code in this repository.\n```";
8
9
  export declare function buildSystemPrompt(basePrompt: string, tools: {
9
10
  name?: string;
10
11
  function?: {
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/constants/prompts.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,kBAAkB,ksFAe8G,CAAC;AAE9I,eAAO,MAAM,sBAAsB,+lBAImH,CAAC;AAEvJ,eAAO,MAAM,eAAe,mVAEgS,CAAC;AAE7T,eAAO,MAAM,eAAe,meAG0P,CAAC;AAEvR,eAAO,MAAM,gBAAgB,+YACwc,CAAC;AAEte,eAAO,MAAM,WAAW,sjBAE4O,CAAC;AAErQ,eAAO,MAAM,qBAAqB,ksFAAqB,CAAC;AAExD,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAAE,GACtD,MAAM,CAkCR"}
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/constants/prompts.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,kBAAkB,ksFAe8G,CAAC;AAE9I,eAAO,MAAM,sBAAsB,+lBAImH,CAAC;AAEvJ,eAAO,MAAM,eAAe,mVAEgS,CAAC;AAE7T,eAAO,MAAM,eAAe,meAG0P,CAAC;AAEvR,eAAO,MAAM,gBAAgB,+YACwc,CAAC;AAEte,eAAO,MAAM,WAAW,sjBAE4O,CAAC;AAErQ,eAAO,MAAM,qBAAqB,ksFAAqB,CAAC;AAExD,eAAO,MAAM,WAAW,0kDAoBjB,CAAC;AAER,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAAE,GACtD,MAAM,CAkCR"}
@@ -33,6 +33,27 @@ export const BASH_POLICY = `
33
33
  - Reserve bash tools exclusively for actual system commands and terminal operations that require shell execution. NEVER use bash echo or other command-line tools to communicate thoughts, explanations, or instructions to the user. Output all communication directly in your response text instead.
34
34
  - When making multiple bash tool calls, you MUST send a single message with multiple tools calls to run the calls in parallel. For example, if you need to run "git status" and "git diff", send a single message with two tool calls to run the calls in parallel.`;
35
35
  export const DEFAULT_SYSTEM_PROMPT = BASE_SYSTEM_PROMPT;
36
+ export const INIT_PROMPT = `Please analyze this codebase and create a AGENTS.md file, which will be given to future instances of Wave Code to operate in this repository.
37
+
38
+ What to add:
39
+ 1. Commands that will be commonly used, such as how to build, lint, and run tests. Include the necessary commands to develop in this codebase, such as how to run a single test.
40
+ 2. High-level code architecture and structure so that future instances can be productive more quickly. Focus on the "big picture" architecture that requires reading multiple files to understand.
41
+
42
+ Usage notes:
43
+ - If there's already a AGENTS.md, suggest improvements to it.
44
+ - When you make the initial AGENTS.md, do not repeat yourself and do not include obvious instructions like "Provide helpful error messages to users", "Write unit tests for all new utilities", "Never include sensitive information (API keys, tokens) in code or commits".
45
+ - Avoid listing every component or file structure that can be easily discovered.
46
+ - Don't include generic development practices.
47
+ - If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include the important parts.
48
+ - If there is a README.md, make sure to include the important parts.
49
+ - Do not make up information such as "Common Development Tasks", "Tips for Development", "Support and Documentation" unless this is expressly included in other files that you read.
50
+ - Be sure to prefix the file with the following text:
51
+
52
+ \`\`\`
53
+ # AGENTS.md
54
+
55
+ This file provides guidance to Wave Code when working with code in this repository.
56
+ \`\`\``;
36
57
  export function buildSystemPrompt(basePrompt, tools) {
37
58
  let prompt = basePrompt;
38
59
  const toolNames = new Set(tools.map((t) => t.function?.name || t.name).filter(Boolean));
@@ -0,0 +1,31 @@
1
+ import type { MemoryRule } from "../types/memoryRule.js";
2
+ export interface MemoryRuleRegistryState {
3
+ /** All discovered rules, indexed by ID */
4
+ rules: Record<string, MemoryRule>;
5
+ /** Set of active rule IDs based on the current context */
6
+ activeRuleIds: Set<string>;
7
+ }
8
+ export interface MemoryRuleManagerOptions {
9
+ workdir: string;
10
+ }
11
+ export declare class MemoryRuleManager {
12
+ private state;
13
+ private workdir;
14
+ private service;
15
+ constructor(options: MemoryRuleManagerOptions);
16
+ /**
17
+ * Scans .wave/rules and ~/.wave/rules for memory rule files.
18
+ */
19
+ discoverRules(): Promise<void>;
20
+ private scanDirectory;
21
+ private loadRuleFile;
22
+ /**
23
+ * Returns the union of all active memory rules based on the provided file paths.
24
+ */
25
+ getActiveRules(filesInContext: string[]): MemoryRule[];
26
+ /**
27
+ * Reloads rules from disk.
28
+ */
29
+ reload(): Promise<void>;
30
+ }
31
+ //# sourceMappingURL=MemoryRuleManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryRuleManager.d.ts","sourceRoot":"","sources":["../../src/managers/MemoryRuleManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAOzD,MAAM,WAAW,uBAAuB;IACtC,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,0DAA0D;IAC1D,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAGX;IAEF,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAoB;gBAEvB,OAAO,EAAE,wBAAwB;IAK7C;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;YAetB,aAAa;YAyDb,YAAY;IAqB1B;;OAEG;IACH,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE;IAUtD;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAG9B"}
@@ -0,0 +1,110 @@
1
+ import { MemoryRuleService } from "../services/MemoryRuleService.js";
2
+ import * as fs from "node:fs/promises";
3
+ import * as path from "node:path";
4
+ import * as os from "node:os";
5
+ import { logger } from "../utils/globalLogger.js";
6
+ export class MemoryRuleManager {
7
+ constructor(options) {
8
+ this.state = {
9
+ rules: {},
10
+ activeRuleIds: new Set(),
11
+ };
12
+ this.workdir = options.workdir;
13
+ this.service = new MemoryRuleService();
14
+ }
15
+ /**
16
+ * Scans .wave/rules and ~/.wave/rules for memory rule files.
17
+ */
18
+ async discoverRules() {
19
+ const projectRulesDir = path.join(this.workdir, ".wave", "rules");
20
+ const userRulesDir = path.join(os.homedir(), ".wave", "rules");
21
+ const newRules = {};
22
+ // Discover user rules first, then project rules so project rules can override if needed
23
+ // (though IDs are based on file path, so they shouldn't collide unless same path)
24
+ await this.scanDirectory(userRulesDir, "user", newRules);
25
+ await this.scanDirectory(projectRulesDir, "project", newRules);
26
+ this.state.rules = newRules;
27
+ logger.debug(`Discovered ${Object.keys(newRules).length} memory rules`);
28
+ }
29
+ async scanDirectory(dir, source, registry, visited = new Set()) {
30
+ const realDir = await fs.realpath(dir).catch(() => dir);
31
+ if (visited.has(realDir)) {
32
+ logger.warn(`Circular symlink detected or directory already visited: ${dir}`);
33
+ return;
34
+ }
35
+ visited.add(realDir);
36
+ try {
37
+ const entries = await fs.readdir(dir, { withFileTypes: true });
38
+ for (const entry of entries) {
39
+ const fullPath = path.join(dir, entry.name);
40
+ const isDirectory = typeof entry.isDirectory === "function" ? entry.isDirectory() : false;
41
+ const isSymbolicLink = typeof entry.isSymbolicLink === "function"
42
+ ? entry.isSymbolicLink()
43
+ : false;
44
+ const isFile = typeof entry.isFile === "function" ? entry.isFile() : false;
45
+ if (isDirectory) {
46
+ await this.scanDirectory(fullPath, source, registry, visited);
47
+ }
48
+ else if (isSymbolicLink) {
49
+ const stats = await fs.stat(fullPath);
50
+ if (stats.isDirectory()) {
51
+ await this.scanDirectory(fullPath, source, registry, visited);
52
+ }
53
+ else if (stats.isFile() && entry.name.endsWith(".md")) {
54
+ await this.loadRuleFile(fullPath, source, registry);
55
+ }
56
+ }
57
+ else if (isFile && entry.name.endsWith(".md")) {
58
+ await this.loadRuleFile(fullPath, source, registry);
59
+ }
60
+ else if (!isDirectory &&
61
+ !isSymbolicLink &&
62
+ !isFile &&
63
+ entry.name.endsWith(".md")) {
64
+ // Fallback for simple string arrays or incomplete mocks
65
+ await this.loadRuleFile(fullPath, source, registry);
66
+ }
67
+ }
68
+ }
69
+ catch (error) {
70
+ // Ignore if directory doesn't exist
71
+ if (error.code !== "ENOENT") {
72
+ logger.error(`Error scanning memory rules directory ${dir}:`, error);
73
+ }
74
+ }
75
+ }
76
+ async loadRuleFile(filePath, source, registry) {
77
+ try {
78
+ const content = await fs.readFile(filePath, "utf-8");
79
+ const rule = this.service.parseRule(content, filePath, source);
80
+ // Use relative path from rules root as ID to allow project rules to override user rules
81
+ const rulesRoot = source === "project"
82
+ ? path.join(this.workdir, ".wave", "rules")
83
+ : path.join(os.homedir(), ".wave", "rules");
84
+ const relativeId = path.relative(rulesRoot, filePath);
85
+ rule.id = relativeId;
86
+ registry[rule.id] = rule;
87
+ }
88
+ catch (error) {
89
+ logger.error(`Failed to parse memory rule at ${filePath}:`, error);
90
+ }
91
+ }
92
+ /**
93
+ * Returns the union of all active memory rules based on the provided file paths.
94
+ */
95
+ getActiveRules(filesInContext) {
96
+ const activeRules = [];
97
+ for (const rule of Object.values(this.state.rules)) {
98
+ if (this.service.isRuleActive(rule, filesInContext)) {
99
+ activeRules.push(rule);
100
+ }
101
+ }
102
+ return activeRules;
103
+ }
104
+ /**
105
+ * Reloads rules from disk.
106
+ */
107
+ async reload() {
108
+ await this.discoverRules();
109
+ }
110
+ }
@@ -46,6 +46,7 @@ export declare class MessageManager {
46
46
  private callbacks;
47
47
  private transcriptPath;
48
48
  private savedMessageCount;
49
+ private filesInContext;
49
50
  private sessionType;
50
51
  private subagentType?;
51
52
  constructor(options: MessageManagerOptions);
@@ -54,6 +55,10 @@ export declare class MessageManager {
54
55
  getlatestTotalTokens(): number;
55
56
  getUserInputHistory(): string[];
56
57
  getWorkdir(): string;
58
+ /**
59
+ * Returns all files mentioned in the current conversation context.
60
+ */
61
+ getFilesInContext(): string[];
57
62
  getSessionDir(): string;
58
63
  getTranscriptPath(): string;
59
64
  /**
@@ -122,5 +127,10 @@ export declare class MessageManager {
122
127
  * Used for hook error handling when the user prompt needs to be erased
123
128
  */
124
129
  removeLastUserMessage(): void;
130
+ /**
131
+ * Updates the set of files mentioned in the conversation.
132
+ */
133
+ private updateFilesInContext;
134
+ private extractPathsFromParams;
125
135
  }
126
136
  //# sourceMappingURL=messageManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messageManager.d.ts","sourceRoot":"","sources":["../../src/managers/messageManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messageManager.d.ts","sourceRoot":"","sources":["../../src/managers/messageManager.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ import { appendMessages, createSession, generateSessionId, SESSION_DIR, } from "
4
4
  import { pathEncoder } from "../utils/pathEncoder.js";
5
5
  export class MessageManager {
6
6
  constructor(options) {
7
+ this.filesInContext = new Set(); // Track files mentioned in the conversation
7
8
  this.sessionId = generateSessionId();
8
9
  this.messages = [];
9
10
  this.latestTotalTokens = 0;
@@ -34,6 +35,12 @@ export class MessageManager {
34
35
  getWorkdir() {
35
36
  return this.workdir;
36
37
  }
38
+ /**
39
+ * Returns all files mentioned in the current conversation context.
40
+ */
41
+ getFilesInContext() {
42
+ return Array.from(this.filesInContext);
43
+ }
37
44
  getSessionDir() {
38
45
  return SESSION_DIR;
39
46
  }
@@ -74,6 +81,7 @@ export class MessageManager {
74
81
  }
75
82
  setMessages(messages) {
76
83
  this.messages = [...messages];
84
+ this.updateFilesInContext(messages);
77
85
  this.callbacks.onMessagesChange?.([...messages]);
78
86
  }
79
87
  /**
@@ -126,6 +134,7 @@ export class MessageManager {
126
134
  initializeFromSession(sessionData) {
127
135
  this.setSessionId(sessionData.id);
128
136
  this.setMessages([...sessionData.messages]);
137
+ this.updateFilesInContext(sessionData.messages);
129
138
  this.setlatestTotalTokens(sessionData.metadata.latestTotalTokens);
130
139
  // Extract user input history from session messages
131
140
  this.setUserInputHistory(extractUserInputHistory(sessionData.messages));
@@ -404,4 +413,56 @@ export class MessageManager {
404
413
  const newMessages = removeLastUserMessage(this.messages);
405
414
  this.setMessages(newMessages);
406
415
  }
416
+ /**
417
+ * Updates the set of files mentioned in the conversation.
418
+ */
419
+ updateFilesInContext(messages) {
420
+ this.filesInContext.clear();
421
+ for (const message of messages) {
422
+ for (const block of message.blocks) {
423
+ if (block.type === "tool") {
424
+ // Extract file paths from common tool parameters
425
+ if (block.parameters) {
426
+ try {
427
+ const params = JSON.parse(block.parameters);
428
+ const paths = this.extractPathsFromParams(params);
429
+ for (const p of paths) {
430
+ this.filesInContext.add(p);
431
+ }
432
+ }
433
+ catch {
434
+ // Ignore parse errors
435
+ }
436
+ }
437
+ }
438
+ }
439
+ }
440
+ }
441
+ extractPathsFromParams(params) {
442
+ const paths = [];
443
+ if (typeof params !== "object" || params === null)
444
+ return paths;
445
+ // Common parameter names for file paths
446
+ const pathKeys = [
447
+ "path",
448
+ "filePath",
449
+ "file_path",
450
+ "target_file",
451
+ "targetFile",
452
+ ];
453
+ for (const key of pathKeys) {
454
+ if (typeof params[key] === "string") {
455
+ paths.push(params[key]);
456
+ }
457
+ }
458
+ // Handle arrays of paths (e.g. in Glob or Grep results if we ever track those,
459
+ // but here we track inputs to tools)
460
+ if (Array.isArray(params.files)) {
461
+ for (const f of params.files) {
462
+ if (typeof f === "string")
463
+ paths.push(f);
464
+ }
465
+ }
466
+ return paths;
467
+ }
407
468
  }
@@ -1 +1 @@
1
- {"version":3,"file":"slashCommandManager.d.ts","sourceRoot":"","sources":["../../src/managers/slashCommandManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,MAAM,EACP,MAAM,mBAAmB,CAAC;AAkB3B,MAAM,WAAW,0BAA0B;IACzC,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,OAAO,EAAE,0BAA0B;IAU/C,OAAO,CAAC,yBAAyB;IAejC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAgD1B;;OAEG;IACI,sBAAsB,CAC3B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,kBAAkB,EAAE,GAC7B,IAAI;IA+CP;;OAEG;IACI,oBAAoB,IAAI,IAAI;IAWnC;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACI,WAAW,IAAI,YAAY,EAAE;IAIpC;;OAEG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI9D;;OAEG;IACU,cAAc,CACzB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC;IAenB;;;OAGG;IACI,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG;QAClD,OAAO,EAAE,OAAO,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;IAeD;;OAEG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI7C;;OAEG;IACI,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI1E;;OAEG;IACI,iBAAiB,IAAI,kBAAkB,EAAE;IAIhD;;OAEG;YACW,+BAA+B;IA0E7C;;OAEG;IACI,mBAAmB,IAAI,IAAI;CAInC"}
1
+ {"version":3,"file":"slashCommandManager.d.ts","sourceRoot":"","sources":["../../src/managers/slashCommandManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,MAAM,EACP,MAAM,mBAAmB,CAAC;AAmB3B,MAAM,WAAW,0BAA0B;IACzC,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,OAAO,EAAE,0BAA0B;IAU/C,OAAO,CAAC,yBAAyB;IAiCjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAgD1B;;OAEG;IACI,sBAAsB,CAC3B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,kBAAkB,EAAE,GAC7B,IAAI;IA+CP;;OAEG;IACI,oBAAoB,IAAI,IAAI;IAWnC;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACI,WAAW,IAAI,YAAY,EAAE;IAIpC;;OAEG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI9D;;OAEG;IACU,cAAc,CACzB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC;IAenB;;;OAGG;IACI,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG;QAClD,OAAO,EAAE,OAAO,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;IAeD;;OAEG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI7C;;OAEG;IACI,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI1E;;OAEG;IACI,iBAAiB,IAAI,kBAAkB,EAAE;IAIhD;;OAEG;YACW,+BAA+B;IA0E7C;;OAEG;IACI,mBAAmB,IAAI,IAAI;CAInC"}
@@ -3,6 +3,7 @@ import { substituteCommandParameters, parseSlashCommandInput, hasParameterPlaceh
3
3
  import { parseBashCommands, replaceBashCommandsWithOutput, } from "../utils/markdownParser.js";
4
4
  import { exec } from "child_process";
5
5
  import { promisify } from "util";
6
+ import { INIT_PROMPT } from "../constants/prompts.js";
6
7
  const execAsync = promisify(exec);
7
8
  export class SlashCommandManager {
8
9
  constructor(options) {
@@ -28,6 +29,21 @@ export class SlashCommandManager {
28
29
  process.stdout.write("\x1Bc");
29
30
  },
30
31
  });
32
+ // Register built-in init command
33
+ this.registerCommand({
34
+ id: "init",
35
+ name: "init",
36
+ description: "Initialize repository for AI agents by generating AGENTS.md",
37
+ handler: async () => {
38
+ // Add custom command message to show the command being executed
39
+ this.messageManager.addUserMessage({
40
+ content: "/init",
41
+ customCommandContent: INIT_PROMPT,
42
+ });
43
+ // Execute the AI conversation with the init prompt
44
+ await this.aiManager.sendAIMessage();
45
+ },
46
+ });
31
47
  }
32
48
  /**
33
49
  * Load custom commands from filesystem
@@ -0,0 +1,12 @@
1
+ import type { MemoryRule } from "../types/memoryRule.js";
2
+ export declare class MemoryRuleService {
3
+ /**
4
+ * Parses a markdown file into a MemoryRule object.
5
+ */
6
+ parseRule(content: string, filePath: string, source: "project" | "user"): MemoryRule;
7
+ /**
8
+ * Determines if a rule matches any of the given file paths using minimatch.
9
+ */
10
+ isRuleActive(rule: MemoryRule, filesInContext: string[]): boolean;
11
+ }
12
+ //# sourceMappingURL=MemoryRuleService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryRuleService.d.ts","sourceRoot":"","sources":["../../src/services/MemoryRuleService.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAsB,MAAM,wBAAwB,CAAC;AAE7E,qBAAa,iBAAiB;IAC5B;;OAEG;IACH,SAAS,CACP,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,GAAG,MAAM,GACzB,UAAU;IAgCb;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO;CAWlE"}
@@ -0,0 +1,44 @@
1
+ import { minimatch } from "minimatch";
2
+ import { parseFrontmatter } from "../utils/markdownParser.js";
3
+ export class MemoryRuleService {
4
+ /**
5
+ * Parses a markdown file into a MemoryRule object.
6
+ */
7
+ parseRule(content, filePath, source) {
8
+ const { frontmatter, content: bodyContent } = parseFrontmatter(content);
9
+ const metadata = {};
10
+ if (frontmatter) {
11
+ if (Array.isArray(frontmatter.paths)) {
12
+ metadata.paths = frontmatter.paths.filter((p) => typeof p === "string");
13
+ }
14
+ else if (typeof frontmatter.paths === "string") {
15
+ metadata.paths = [frontmatter.paths];
16
+ }
17
+ if (typeof frontmatter.priority === "number") {
18
+ metadata.priority = frontmatter.priority;
19
+ }
20
+ else if (typeof frontmatter.priority === "string") {
21
+ const parsed = parseInt(frontmatter.priority, 10);
22
+ if (!isNaN(parsed)) {
23
+ metadata.priority = parsed;
24
+ }
25
+ }
26
+ }
27
+ return {
28
+ id: filePath, // Use absolute path as ID for now
29
+ content: bodyContent.trim(),
30
+ metadata,
31
+ source,
32
+ filePath,
33
+ };
34
+ }
35
+ /**
36
+ * Determines if a rule matches any of the given file paths using minimatch.
37
+ */
38
+ isRuleActive(rule, filesInContext) {
39
+ if (!rule.metadata.paths || rule.metadata.paths.length === 0) {
40
+ return true;
41
+ }
42
+ return filesInContext.some((filePath) => rule.metadata.paths.some((pattern) => minimatch(filePath, pattern, { dot: true })));
43
+ }
44
+ }
@@ -27,4 +27,5 @@ export * from "./fileSearch.js";
27
27
  export * from "./lsp.js";
28
28
  export * from "./plugins.js";
29
29
  export * from "./marketplace.js";
30
+ export * from "./memoryRule.js";
30
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,cAAc,WAAW,CAAC;AAG1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,cAAc,WAAW,CAAC;AAG1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC"}
@@ -29,3 +29,4 @@ export * from "./fileSearch.js"; // File search types
29
29
  export * from "./lsp.js";
30
30
  export * from "./plugins.js";
31
31
  export * from "./marketplace.js";
32
+ export * from "./memoryRule.js";
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Metadata extracted from the YAML frontmatter of a memory rule file.
3
+ */
4
+ export interface MemoryRuleMetadata {
5
+ /**
6
+ * Glob patterns that determine when this rule is active.
7
+ * If undefined or empty, the rule is always active.
8
+ */
9
+ paths?: string[];
10
+ /**
11
+ * Optional priority override.
12
+ * Higher numbers take precedence if there are conflicting instructions.
13
+ */
14
+ priority?: number;
15
+ }
16
+ /**
17
+ * Represents a single memory rule discovered from the filesystem.
18
+ */
19
+ export interface MemoryRule {
20
+ /** Unique identifier, typically the relative path from the rules root */
21
+ id: string;
22
+ /** The raw content of the markdown file (excluding frontmatter) */
23
+ content: string;
24
+ /** Metadata parsed from YAML frontmatter */
25
+ metadata: MemoryRuleMetadata;
26
+ /** Source of the rule (project-level or user-level) */
27
+ source: "project" | "user";
28
+ /** Absolute path to the file on disk */
29
+ filePath: string;
30
+ }
31
+ //# sourceMappingURL=memoryRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryRule.d.ts","sourceRoot":"","sources":["../../src/types/memoryRule.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,yEAAyE;IACzE,EAAE,EAAE,MAAM,CAAC;IACX,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,uDAAuD;IACvD,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;CAClB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -22,7 +22,7 @@ export declare const USER_MEMORY_FILE: string;
22
22
  * AI related constants
23
23
  */
24
24
  export declare const DEFAULT_WAVE_MAX_INPUT_TOKENS = 96000;
25
- export declare const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 4096;
25
+ export declare const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 8192;
26
26
  /**
27
27
  * Default number of messages to keep uncompressed
28
28
  */
@@ -24,7 +24,7 @@ export const USER_MEMORY_FILE = path.join(DATA_DIRECTORY, "AGENTS.md");
24
24
  * AI related constants
25
25
  */
26
26
  export const DEFAULT_WAVE_MAX_INPUT_TOKENS = 96000; // Default token limit
27
- export const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 4096; // Default output token limit
27
+ export const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 8192; // Default output token limit
28
28
  /**
29
29
  * Default number of messages to keep uncompressed
30
30
  */
@@ -3,6 +3,13 @@ interface ParsedMarkdownFile {
3
3
  content: string;
4
4
  config?: CustomSlashCommandConfig;
5
5
  }
6
+ /**
7
+ * Parse YAML frontmatter from markdown content
8
+ */
9
+ export declare function parseFrontmatter(content: string): {
10
+ frontmatter?: Record<string, unknown>;
11
+ content: string;
12
+ };
6
13
  /**
7
14
  * Parse markdown file and extract config and content
8
15
  */
@@ -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;AA2DD;;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":"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"}
@@ -2,7 +2,7 @@ import { readFileSync } from "fs";
2
2
  /**
3
3
  * Parse YAML frontmatter from markdown content
4
4
  */
5
- function parseFrontmatter(content) {
5
+ export function parseFrontmatter(content) {
6
6
  const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
7
7
  const match = content.match(frontmatterRegex);
8
8
  if (!match) {
@@ -20,8 +20,13 @@ function parseFrontmatter(content) {
20
20
  continue;
21
21
  // Check if it's a list item
22
22
  if (trimmedLine.startsWith("-") && currentKey) {
23
- const value = trimmedLine.slice(1).trim();
23
+ let value = trimmedLine.slice(1).trim();
24
24
  if (value) {
25
+ // Remove surrounding quotes if present
26
+ if ((value.startsWith('"') && value.endsWith('"')) ||
27
+ (value.startsWith("'") && value.endsWith("'"))) {
28
+ value = value.slice(1, -1);
29
+ }
25
30
  if (!Array.isArray(frontmatter[currentKey])) {
26
31
  frontmatter[currentKey] = [];
27
32
  }
@@ -36,7 +41,12 @@ function parseFrontmatter(content) {
36
41
  const value = trimmedLine.slice(colonIndex + 1).trim();
37
42
  currentKey = key;
38
43
  if (value) {
39
- frontmatter[key] = value;
44
+ // Remove surrounding quotes if present
45
+ const unquotedValue = (value.startsWith('"') && value.endsWith('"')) ||
46
+ (value.startsWith("'") && value.endsWith("'"))
47
+ ? value.slice(1, -1)
48
+ : value;
49
+ frontmatter[key] = unquotedValue;
40
50
  }
41
51
  }
42
52
  return { frontmatter, content: bodyContent };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-agent-sdk",
3
- "version": "0.0.17-alpha.0",
3
+ "version": "0.1.0",
4
4
  "description": "SDK for building AI-powered development tools and agents",
5
5
  "keywords": [
6
6
  "ai",
package/src/agent.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  } from "./managers/backgroundBashManager.js";
19
19
  import { SlashCommandManager } from "./managers/slashCommandManager.js";
20
20
  import { PluginManager } from "./managers/pluginManager.js";
21
+ import { HookManager } from "./managers/hookManager.js";
21
22
  import { PermissionManager } from "./managers/permissionManager.js";
22
23
  import { PlanManager } from "./managers/planManager.js";
23
24
  import type {
@@ -36,7 +37,7 @@ import type {
36
37
  PermissionMode,
37
38
  PermissionCallback,
38
39
  } from "./types/index.js";
39
- import { HookManager } from "./managers/hookManager.js";
40
+ import { MemoryRuleManager } from "./managers/MemoryRuleManager.js";
40
41
  import { LiveConfigManager } from "./managers/liveConfigManager.js";
41
42
  import { configValidator } from "./utils/configValidator.js";
42
43
  import { SkillManager } from "./managers/skillManager.js";
@@ -118,6 +119,7 @@ export class Agent {
118
119
  private pluginManager: PluginManager; // Add plugin manager instance
119
120
  private skillManager: SkillManager; // Add skill manager instance
120
121
  private hookManager: HookManager; // Add hooks manager instance
122
+ private memoryRuleManager: MemoryRuleManager; // Add memory rule manager instance
121
123
  private liveConfigManager: LiveConfigManager; // Add live configuration manager
122
124
  private configurationService: ConfigurationService; // Add configuration service
123
125
  private workdir: string; // Working directory
@@ -266,6 +268,11 @@ export class Agent {
266
268
  logger: this.logger,
267
269
  });
268
270
 
271
+ // Initialize memory rule manager
272
+ this.memoryRuleManager = new MemoryRuleManager({
273
+ workdir: this.workdir,
274
+ });
275
+
269
276
  // Create a wrapper for canUseTool that triggers notification hooks
270
277
  const canUseToolWithNotification: PermissionCallback | undefined =
271
278
  options.canUseTool
@@ -470,7 +477,7 @@ export class Agent {
470
477
  return this._userMemoryContent;
471
478
  }
472
479
 
473
- /** Get combined memory content (project + user) */
480
+ /** Get combined memory content (project + user + modular rules) */
474
481
  public get combinedMemory(): string {
475
482
  let combined = "";
476
483
  if (this._projectMemoryContent.trim()) {
@@ -482,6 +489,17 @@ export class Agent {
482
489
  }
483
490
  combined += this._userMemoryContent;
484
491
  }
492
+
493
+ // Add modular memory rules
494
+ const filesInContext = this.messageManager.getFilesInContext();
495
+ const activeRules = this.memoryRuleManager.getActiveRules(filesInContext);
496
+ if (activeRules.length > 0) {
497
+ if (combined) {
498
+ combined += "\n\n";
499
+ }
500
+ combined += activeRules.map((r) => r.content).join("\n\n");
501
+ }
502
+
485
503
  return combined;
486
504
  }
487
505
 
@@ -649,6 +667,13 @@ export class Agent {
649
667
  // Resolve and validate configuration after loading settings.json
650
668
  this.resolveAndValidateConfig();
651
669
 
670
+ // Discover modular memory rules
671
+ try {
672
+ await this.memoryRuleManager.discoverRules();
673
+ } catch (error) {
674
+ this.logger?.error("Failed to discover memory rules:", error);
675
+ }
676
+
652
677
  // Set global logger for SDK-wide access after validation
653
678
  setGlobalLogger(this.logger || null);
654
679
 
@@ -53,6 +53,28 @@ export const BASH_POLICY = `
53
53
 
54
54
  export const DEFAULT_SYSTEM_PROMPT = BASE_SYSTEM_PROMPT;
55
55
 
56
+ export const INIT_PROMPT = `Please analyze this codebase and create a AGENTS.md file, which will be given to future instances of Wave Code to operate in this repository.
57
+
58
+ What to add:
59
+ 1. Commands that will be commonly used, such as how to build, lint, and run tests. Include the necessary commands to develop in this codebase, such as how to run a single test.
60
+ 2. High-level code architecture and structure so that future instances can be productive more quickly. Focus on the "big picture" architecture that requires reading multiple files to understand.
61
+
62
+ Usage notes:
63
+ - If there's already a AGENTS.md, suggest improvements to it.
64
+ - When you make the initial AGENTS.md, do not repeat yourself and do not include obvious instructions like "Provide helpful error messages to users", "Write unit tests for all new utilities", "Never include sensitive information (API keys, tokens) in code or commits".
65
+ - Avoid listing every component or file structure that can be easily discovered.
66
+ - Don't include generic development practices.
67
+ - If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include the important parts.
68
+ - If there is a README.md, make sure to include the important parts.
69
+ - Do not make up information such as "Common Development Tasks", "Tips for Development", "Support and Documentation" unless this is expressly included in other files that you read.
70
+ - Be sure to prefix the file with the following text:
71
+
72
+ \`\`\`
73
+ # AGENTS.md
74
+
75
+ This file provides guidance to Wave Code when working with code in this repository.
76
+ \`\`\``;
77
+
56
78
  export function buildSystemPrompt(
57
79
  basePrompt: string,
58
80
  tools: { name?: string; function?: { name: string } }[],
@@ -0,0 +1,148 @@
1
+ import type { MemoryRule } from "../types/memoryRule.js";
2
+ import { MemoryRuleService } from "../services/MemoryRuleService.js";
3
+ import * as fs from "node:fs/promises";
4
+ import * as path from "node:path";
5
+ import * as os from "node:os";
6
+ import { logger } from "../utils/globalLogger.js";
7
+
8
+ export interface MemoryRuleRegistryState {
9
+ /** All discovered rules, indexed by ID */
10
+ rules: Record<string, MemoryRule>;
11
+ /** Set of active rule IDs based on the current context */
12
+ activeRuleIds: Set<string>;
13
+ }
14
+
15
+ export interface MemoryRuleManagerOptions {
16
+ workdir: string;
17
+ }
18
+
19
+ export class MemoryRuleManager {
20
+ private state: MemoryRuleRegistryState = {
21
+ rules: {},
22
+ activeRuleIds: new Set(),
23
+ };
24
+
25
+ private workdir: string;
26
+ private service: MemoryRuleService;
27
+
28
+ constructor(options: MemoryRuleManagerOptions) {
29
+ this.workdir = options.workdir;
30
+ this.service = new MemoryRuleService();
31
+ }
32
+
33
+ /**
34
+ * Scans .wave/rules and ~/.wave/rules for memory rule files.
35
+ */
36
+ async discoverRules(): Promise<void> {
37
+ const projectRulesDir = path.join(this.workdir, ".wave", "rules");
38
+ const userRulesDir = path.join(os.homedir(), ".wave", "rules");
39
+
40
+ const newRules: Record<string, MemoryRule> = {};
41
+
42
+ // Discover user rules first, then project rules so project rules can override if needed
43
+ // (though IDs are based on file path, so they shouldn't collide unless same path)
44
+ await this.scanDirectory(userRulesDir, "user", newRules);
45
+ await this.scanDirectory(projectRulesDir, "project", newRules);
46
+
47
+ this.state.rules = newRules;
48
+ logger.debug(`Discovered ${Object.keys(newRules).length} memory rules`);
49
+ }
50
+
51
+ private async scanDirectory(
52
+ dir: string,
53
+ source: "project" | "user",
54
+ registry: Record<string, MemoryRule>,
55
+ visited: Set<string> = new Set(),
56
+ ): Promise<void> {
57
+ const realDir = await fs.realpath(dir).catch(() => dir);
58
+ if (visited.has(realDir)) {
59
+ logger.warn(
60
+ `Circular symlink detected or directory already visited: ${dir}`,
61
+ );
62
+ return;
63
+ }
64
+ visited.add(realDir);
65
+
66
+ try {
67
+ const entries = await fs.readdir(dir, { withFileTypes: true });
68
+ for (const entry of entries) {
69
+ const fullPath = path.join(dir, entry.name);
70
+ const isDirectory =
71
+ typeof entry.isDirectory === "function" ? entry.isDirectory() : false;
72
+ const isSymbolicLink =
73
+ typeof entry.isSymbolicLink === "function"
74
+ ? entry.isSymbolicLink()
75
+ : false;
76
+ const isFile =
77
+ typeof entry.isFile === "function" ? entry.isFile() : false;
78
+
79
+ if (isDirectory) {
80
+ await this.scanDirectory(fullPath, source, registry, visited);
81
+ } else if (isSymbolicLink) {
82
+ const stats = await fs.stat(fullPath);
83
+ if (stats.isDirectory()) {
84
+ await this.scanDirectory(fullPath, source, registry, visited);
85
+ } else if (stats.isFile() && entry.name.endsWith(".md")) {
86
+ await this.loadRuleFile(fullPath, source, registry);
87
+ }
88
+ } else if (isFile && entry.name.endsWith(".md")) {
89
+ await this.loadRuleFile(fullPath, source, registry);
90
+ } else if (
91
+ !isDirectory &&
92
+ !isSymbolicLink &&
93
+ !isFile &&
94
+ entry.name.endsWith(".md")
95
+ ) {
96
+ // Fallback for simple string arrays or incomplete mocks
97
+ await this.loadRuleFile(fullPath, source, registry);
98
+ }
99
+ }
100
+ } catch (error) {
101
+ // Ignore if directory doesn't exist
102
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
103
+ logger.error(`Error scanning memory rules directory ${dir}:`, error);
104
+ }
105
+ }
106
+ }
107
+
108
+ private async loadRuleFile(
109
+ filePath: string,
110
+ source: "project" | "user",
111
+ registry: Record<string, MemoryRule>,
112
+ ): Promise<void> {
113
+ try {
114
+ const content = await fs.readFile(filePath, "utf-8");
115
+ const rule = this.service.parseRule(content, filePath, source);
116
+ // Use relative path from rules root as ID to allow project rules to override user rules
117
+ const rulesRoot =
118
+ source === "project"
119
+ ? path.join(this.workdir, ".wave", "rules")
120
+ : path.join(os.homedir(), ".wave", "rules");
121
+ const relativeId = path.relative(rulesRoot, filePath);
122
+ rule.id = relativeId;
123
+ registry[rule.id] = rule;
124
+ } catch (error) {
125
+ logger.error(`Failed to parse memory rule at ${filePath}:`, error);
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Returns the union of all active memory rules based on the provided file paths.
131
+ */
132
+ getActiveRules(filesInContext: string[]): MemoryRule[] {
133
+ const activeRules: MemoryRule[] = [];
134
+ for (const rule of Object.values(this.state.rules)) {
135
+ if (this.service.isRuleActive(rule, filesInContext)) {
136
+ activeRules.push(rule);
137
+ }
138
+ }
139
+ return activeRules;
140
+ }
141
+
142
+ /**
143
+ * Reloads rules from disk.
144
+ */
145
+ async reload(): Promise<void> {
146
+ await this.discoverRules();
147
+ }
148
+ }
@@ -92,6 +92,7 @@ export class MessageManager {
92
92
  private callbacks: MessageManagerCallbacks;
93
93
  private transcriptPath: string; // Cached transcript path
94
94
  private savedMessageCount: number; // Track how many messages have been saved to prevent duplication
95
+ private filesInContext: Set<string> = new Set(); // Track files mentioned in the conversation
95
96
  private sessionType: "main" | "subagent";
96
97
  private subagentType?: string;
97
98
 
@@ -133,6 +134,13 @@ export class MessageManager {
133
134
  return this.workdir;
134
135
  }
135
136
 
137
+ /**
138
+ * Returns all files mentioned in the current conversation context.
139
+ */
140
+ public getFilesInContext(): string[] {
141
+ return Array.from(this.filesInContext);
142
+ }
143
+
136
144
  public getSessionDir(): string {
137
145
  return SESSION_DIR;
138
146
  }
@@ -179,6 +187,7 @@ export class MessageManager {
179
187
 
180
188
  public setMessages(messages: Message[]): void {
181
189
  this.messages = [...messages];
190
+ this.updateFilesInContext(messages);
182
191
  this.callbacks.onMessagesChange?.([...messages]);
183
192
  }
184
193
 
@@ -244,6 +253,7 @@ export class MessageManager {
244
253
  public initializeFromSession(sessionData: SessionData): void {
245
254
  this.setSessionId(sessionData.id);
246
255
  this.setMessages([...sessionData.messages]);
256
+ this.updateFilesInContext(sessionData.messages);
247
257
  this.setlatestTotalTokens(sessionData.metadata.latestTotalTokens);
248
258
 
249
259
  // Extract user input history from session messages
@@ -632,4 +642,61 @@ export class MessageManager {
632
642
  const newMessages = removeLastUserMessage(this.messages);
633
643
  this.setMessages(newMessages);
634
644
  }
645
+
646
+ /**
647
+ * Updates the set of files mentioned in the conversation.
648
+ */
649
+ private updateFilesInContext(messages: Message[]): void {
650
+ this.filesInContext.clear();
651
+ for (const message of messages) {
652
+ for (const block of message.blocks) {
653
+ if (block.type === "tool") {
654
+ // Extract file paths from common tool parameters
655
+ if (block.parameters) {
656
+ try {
657
+ const params = JSON.parse(block.parameters) as Record<
658
+ string,
659
+ unknown
660
+ >;
661
+ const paths = this.extractPathsFromParams(params);
662
+ for (const p of paths) {
663
+ this.filesInContext.add(p);
664
+ }
665
+ } catch {
666
+ // Ignore parse errors
667
+ }
668
+ }
669
+ }
670
+ }
671
+ }
672
+ }
673
+
674
+ private extractPathsFromParams(params: Record<string, unknown>): string[] {
675
+ const paths: string[] = [];
676
+ if (typeof params !== "object" || params === null) return paths;
677
+
678
+ // Common parameter names for file paths
679
+ const pathKeys = [
680
+ "path",
681
+ "filePath",
682
+ "file_path",
683
+ "target_file",
684
+ "targetFile",
685
+ ];
686
+ for (const key of pathKeys) {
687
+ if (typeof params[key] === "string") {
688
+ paths.push(params[key]);
689
+ }
690
+ }
691
+
692
+ // Handle arrays of paths (e.g. in Glob or Grep results if we ever track those,
693
+ // but here we track inputs to tools)
694
+ if (Array.isArray(params.files)) {
695
+ for (const f of params.files) {
696
+ if (typeof f === "string") paths.push(f);
697
+ }
698
+ }
699
+
700
+ return paths;
701
+ }
635
702
  }
@@ -19,6 +19,7 @@ import {
19
19
  } from "../utils/markdownParser.js";
20
20
  import { exec } from "child_process";
21
21
  import { promisify } from "util";
22
+ import { INIT_PROMPT } from "../constants/prompts.js";
22
23
 
23
24
  const execAsync = promisify(exec);
24
25
 
@@ -60,6 +61,24 @@ export class SlashCommandManager {
60
61
  process.stdout.write("\x1Bc");
61
62
  },
62
63
  });
64
+
65
+ // Register built-in init command
66
+ this.registerCommand({
67
+ id: "init",
68
+ name: "init",
69
+ description:
70
+ "Initialize repository for AI agents by generating AGENTS.md",
71
+ handler: async () => {
72
+ // Add custom command message to show the command being executed
73
+ this.messageManager.addUserMessage({
74
+ content: "/init",
75
+ customCommandContent: INIT_PROMPT,
76
+ });
77
+
78
+ // Execute the AI conversation with the init prompt
79
+ await this.aiManager.sendAIMessage();
80
+ },
81
+ });
63
82
  }
64
83
 
65
84
  /**
@@ -0,0 +1,59 @@
1
+ import { minimatch } from "minimatch";
2
+ import { parseFrontmatter } from "../utils/markdownParser.js";
3
+ import type { MemoryRule, MemoryRuleMetadata } from "../types/memoryRule.js";
4
+
5
+ export class MemoryRuleService {
6
+ /**
7
+ * Parses a markdown file into a MemoryRule object.
8
+ */
9
+ parseRule(
10
+ content: string,
11
+ filePath: string,
12
+ source: "project" | "user",
13
+ ): MemoryRule {
14
+ const { frontmatter, content: bodyContent } = parseFrontmatter(content);
15
+
16
+ const metadata: MemoryRuleMetadata = {};
17
+ if (frontmatter) {
18
+ if (Array.isArray(frontmatter.paths)) {
19
+ metadata.paths = frontmatter.paths.filter(
20
+ (p): p is string => typeof p === "string",
21
+ );
22
+ } else if (typeof frontmatter.paths === "string") {
23
+ metadata.paths = [frontmatter.paths];
24
+ }
25
+
26
+ if (typeof frontmatter.priority === "number") {
27
+ metadata.priority = frontmatter.priority;
28
+ } else if (typeof frontmatter.priority === "string") {
29
+ const parsed = parseInt(frontmatter.priority, 10);
30
+ if (!isNaN(parsed)) {
31
+ metadata.priority = parsed;
32
+ }
33
+ }
34
+ }
35
+
36
+ return {
37
+ id: filePath, // Use absolute path as ID for now
38
+ content: bodyContent.trim(),
39
+ metadata,
40
+ source,
41
+ filePath,
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Determines if a rule matches any of the given file paths using minimatch.
47
+ */
48
+ isRuleActive(rule: MemoryRule, filesInContext: string[]): boolean {
49
+ if (!rule.metadata.paths || rule.metadata.paths.length === 0) {
50
+ return true;
51
+ }
52
+
53
+ return filesInContext.some((filePath) =>
54
+ rule.metadata.paths!.some((pattern) =>
55
+ minimatch(filePath, pattern, { dot: true }),
56
+ ),
57
+ );
58
+ }
59
+ }
@@ -31,3 +31,4 @@ export * from "./fileSearch.js"; // File search types
31
31
  export * from "./lsp.js";
32
32
  export * from "./plugins.js";
33
33
  export * from "./marketplace.js";
34
+ export * from "./memoryRule.js";
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Metadata extracted from the YAML frontmatter of a memory rule file.
3
+ */
4
+ export interface MemoryRuleMetadata {
5
+ /**
6
+ * Glob patterns that determine when this rule is active.
7
+ * If undefined or empty, the rule is always active.
8
+ */
9
+ paths?: string[];
10
+ /**
11
+ * Optional priority override.
12
+ * Higher numbers take precedence if there are conflicting instructions.
13
+ */
14
+ priority?: number;
15
+ }
16
+
17
+ /**
18
+ * Represents a single memory rule discovered from the filesystem.
19
+ */
20
+ export interface MemoryRule {
21
+ /** Unique identifier, typically the relative path from the rules root */
22
+ id: string;
23
+ /** The raw content of the markdown file (excluding frontmatter) */
24
+ content: string;
25
+ /** Metadata parsed from YAML frontmatter */
26
+ metadata: MemoryRuleMetadata;
27
+ /** Source of the rule (project-level or user-level) */
28
+ source: "project" | "user";
29
+ /** Absolute path to the file on disk */
30
+ filePath: string;
31
+ }
@@ -30,7 +30,7 @@ export const USER_MEMORY_FILE = path.join(DATA_DIRECTORY, "AGENTS.md");
30
30
  * AI related constants
31
31
  */
32
32
  export const DEFAULT_WAVE_MAX_INPUT_TOKENS = 96000; // Default token limit
33
- export const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 4096; // Default output token limit
33
+ export const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 8192; // Default output token limit
34
34
 
35
35
  /**
36
36
  * Default number of messages to keep uncompressed
@@ -9,7 +9,7 @@ interface ParsedMarkdownFile {
9
9
  /**
10
10
  * Parse YAML frontmatter from markdown content
11
11
  */
12
- function parseFrontmatter(content: string): {
12
+ export function parseFrontmatter(content: string): {
13
13
  frontmatter?: Record<string, unknown>;
14
14
  content: string;
15
15
  } {
@@ -34,8 +34,15 @@ function parseFrontmatter(content: string): {
34
34
 
35
35
  // Check if it's a list item
36
36
  if (trimmedLine.startsWith("-") && currentKey) {
37
- const value = trimmedLine.slice(1).trim();
37
+ let value = trimmedLine.slice(1).trim();
38
38
  if (value) {
39
+ // Remove surrounding quotes if present
40
+ if (
41
+ (value.startsWith('"') && value.endsWith('"')) ||
42
+ (value.startsWith("'") && value.endsWith("'"))
43
+ ) {
44
+ value = value.slice(1, -1);
45
+ }
39
46
  if (!Array.isArray(frontmatter[currentKey])) {
40
47
  frontmatter[currentKey] = [];
41
48
  }
@@ -52,7 +59,13 @@ function parseFrontmatter(content: string): {
52
59
 
53
60
  currentKey = key;
54
61
  if (value) {
55
- frontmatter[key] = value;
62
+ // Remove surrounding quotes if present
63
+ const unquotedValue =
64
+ (value.startsWith('"') && value.endsWith('"')) ||
65
+ (value.startsWith("'") && value.endsWith("'"))
66
+ ? value.slice(1, -1)
67
+ : value;
68
+ frontmatter[key] = unquotedValue;
56
69
  }
57
70
  }
58
71