pulse-coder-engine 0.0.1-alpha.4 → 0.0.1-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,9 +30,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/built-in/index.ts
31
31
  var built_in_exports = {};
32
32
  __export(built_in_exports, {
33
+ BuiltInPlanModeService: () => BuiltInPlanModeService,
33
34
  BuiltInSkillRegistry: () => BuiltInSkillRegistry,
34
35
  SubAgentPlugin: () => SubAgentPlugin,
35
36
  builtInMCPPlugin: () => builtInMCPPlugin,
37
+ builtInPlanModePlugin: () => builtInPlanModePlugin,
36
38
  builtInPlugins: () => builtInPlugins,
37
39
  builtInSkillsPlugin: () => builtInSkillsPlugin,
38
40
  default: () => built_in_default
@@ -274,10 +276,410 @@ var builtInSkillsPlugin = {
274
276
  }
275
277
  };
276
278
 
279
+ // src/built-in/plan-mode-plugin/index.ts
280
+ var PLANNING_POLICY = {
281
+ mode: "planning",
282
+ allowedCategories: ["read", "search", "other"],
283
+ disallowedCategories: ["write", "execute"],
284
+ notes: "Planning mode is prompt-constrained only. Disallowed tool attempts are observed and logged, not hard-blocked."
285
+ };
286
+ var EXECUTING_POLICY = {
287
+ mode: "executing",
288
+ allowedCategories: ["read", "search", "write", "execute", "other"],
289
+ disallowedCategories: []
290
+ };
291
+ var EXECUTE_PATTERNS = [
292
+ /开始执行/i,
293
+ /按这个计划做/i,
294
+ /可以改代码了/i,
295
+ /直接实现/i,
296
+ /go\s+ahead/i,
297
+ /proceed/i,
298
+ /implement\s+it/i,
299
+ /start\s+implement/i,
300
+ /start\s+coding/i
301
+ ];
302
+ var NEGATIVE_PATTERNS = [
303
+ /先不(要)?执行/i,
304
+ /先别执行/i,
305
+ /不要执行/i,
306
+ /暂时不要执行/i,
307
+ /先别改代码/i,
308
+ /先不要改代码/i,
309
+ /先不要实现/i,
310
+ /not\s+now/i,
311
+ /hold\s+off/i,
312
+ /do\s+not\s+(start|execute|implement|proceed)/i,
313
+ /don't\s+(start|execute|implement|proceed)/i
314
+ ];
315
+ var PLAN_PATTERNS = [/先计划/i, /先分析/i, /先出方案/i, /plan\s+first/i, /analysis\s+first/i];
316
+ function appendSystemPrompt(base, append) {
317
+ if (!append.trim()) {
318
+ return base ?? { append: "" };
319
+ }
320
+ if (!base) {
321
+ return { append };
322
+ }
323
+ if (typeof base === "string") {
324
+ return `${base}
325
+
326
+ ${append}`;
327
+ }
328
+ if (typeof base === "function") {
329
+ return () => `${base()}
330
+
331
+ ${append}`;
332
+ }
333
+ const currentAppend = base.append.trim();
334
+ return {
335
+ append: currentAppend ? `${currentAppend}
336
+
337
+ ${append}` : append
338
+ };
339
+ }
340
+ var KNOWN_TOOL_META = {
341
+ read: {
342
+ category: "read",
343
+ risk: "low",
344
+ description: "Read file contents from the workspace."
345
+ },
346
+ ls: {
347
+ category: "read",
348
+ risk: "low",
349
+ description: "List files and directories."
350
+ },
351
+ grep: {
352
+ category: "search",
353
+ risk: "low",
354
+ description: "Search text content across files."
355
+ },
356
+ tavily: {
357
+ category: "search",
358
+ risk: "low",
359
+ description: "Search web results from external sources."
360
+ },
361
+ skill: {
362
+ category: "search",
363
+ risk: "low",
364
+ description: "Load procedural guidance from installed skills."
365
+ },
366
+ write: {
367
+ category: "write",
368
+ risk: "high",
369
+ description: "Create or overwrite file content."
370
+ },
371
+ edit: {
372
+ category: "write",
373
+ risk: "high",
374
+ description: "Modify existing files using exact replacements."
375
+ },
376
+ bash: {
377
+ category: "execute",
378
+ risk: "high",
379
+ description: "Execute shell commands."
380
+ },
381
+ clarify: {
382
+ category: "other",
383
+ risk: "low",
384
+ description: "Ask the user a targeted clarification question."
385
+ }
386
+ };
387
+ var BuiltInPlanModeService = class {
388
+ constructor(logger, eventEmitter, initialMode = "executing") {
389
+ this.logger = logger;
390
+ this.eventEmitter = eventEmitter;
391
+ this.mode = initialMode;
392
+ this.emitEvent("mode_entered", { reason: "initialize" });
393
+ }
394
+ mode;
395
+ events = [];
396
+ getMode() {
397
+ return this.mode;
398
+ }
399
+ setMode(mode, reason = "manual") {
400
+ if (this.mode === mode) {
401
+ return;
402
+ }
403
+ this.mode = mode;
404
+ this.emitEvent("mode_entered", { reason });
405
+ }
406
+ detectIntent(input) {
407
+ const text = input.trim();
408
+ if (!text) {
409
+ return "UNCLEAR";
410
+ }
411
+ if (NEGATIVE_PATTERNS.some((pattern) => pattern.test(text))) {
412
+ return "PLAN_ONLY";
413
+ }
414
+ if (EXECUTE_PATTERNS.some((pattern) => pattern.test(text))) {
415
+ return "EXECUTE_NOW";
416
+ }
417
+ if (PLAN_PATTERNS.some((pattern) => pattern.test(text))) {
418
+ return "PLAN_ONLY";
419
+ }
420
+ return "UNCLEAR";
421
+ }
422
+ processContextMessages(messages) {
423
+ const userInput = this.getLatestUserText(messages);
424
+ const modeBefore = this.mode;
425
+ if (!userInput) {
426
+ return {
427
+ modeBefore,
428
+ modeAfter: this.mode,
429
+ switched: false,
430
+ intent: "UNCLEAR",
431
+ userInput: ""
432
+ };
433
+ }
434
+ const intent = this.detectIntent(userInput);
435
+ if (intent === "EXECUTE_NOW") {
436
+ this.emitEvent("execution_intent_detected", { intent, userInput });
437
+ if (this.mode === "planning") {
438
+ this.mode = "executing";
439
+ this.emitEvent("mode_switched_by_intent", {
440
+ from: "planning",
441
+ to: "executing",
442
+ userInput
443
+ });
444
+ this.emitEvent("mode_entered", {
445
+ reason: "intent",
446
+ from: "planning"
447
+ });
448
+ }
449
+ }
450
+ return {
451
+ modeBefore,
452
+ modeAfter: this.mode,
453
+ switched: modeBefore !== this.mode,
454
+ intent,
455
+ userInput
456
+ };
457
+ }
458
+ getModePolicy(mode = this.mode) {
459
+ return mode === "planning" ? PLANNING_POLICY : EXECUTING_POLICY;
460
+ }
461
+ getToolMetadata(toolNames) {
462
+ return Array.from(new Set(toolNames)).sort().map((name) => this.inferToolMeta(name));
463
+ }
464
+ buildPromptAppend(toolNames, transition) {
465
+ const mode = this.mode;
466
+ const policy = this.getModePolicy(mode);
467
+ const toolMeta = this.getToolMetadata(toolNames);
468
+ const shownTools = toolMeta.slice(0, 40);
469
+ const omittedCount = toolMeta.length - shownTools.length;
470
+ const lines = [
471
+ "## Plan Mode Policy (Built-in Plugin)",
472
+ `Current mode: ${mode.toUpperCase()}`,
473
+ `Allowed tool categories: ${policy.allowedCategories.join(", ")}`,
474
+ `Disallowed tool categories: ${policy.disallowedCategories.join(", ") || "none"}`,
475
+ policy.notes ? `Policy notes: ${policy.notes}` : ""
476
+ ].filter(Boolean);
477
+ if (mode === "planning") {
478
+ lines.push(
479
+ "Planning objective: prioritize reading, analysis, and plan generation.",
480
+ "In planning mode, do not intentionally perform write/edit/execute actions.",
481
+ "If implementation is requested but intent is not explicit, ask for execution authorization.",
482
+ "Before each tool call in planning mode, self-check category compliance.",
483
+ "Plan format must include: goals, assumptions, steps, risks, validation approach."
484
+ );
485
+ } else {
486
+ lines.push(
487
+ "Executing objective: follow the agreed plan before broad exploration.",
488
+ "Make targeted edits and keep changes scoped.",
489
+ "Report what changed and how it was validated."
490
+ );
491
+ }
492
+ if (transition?.switched && transition.modeAfter === "executing") {
493
+ lines.push(
494
+ "Mode transition: the latest user message explicitly authorized execution.",
495
+ "In your next reply, acknowledge switching to EXECUTING mode before implementation details."
496
+ );
497
+ }
498
+ lines.push("Tool metadata (prompt-level policy reference):");
499
+ for (const meta of shownTools) {
500
+ lines.push(`- ${meta.name}: category=${meta.category}, risk=${meta.risk}, ${meta.description}`);
501
+ }
502
+ if (omittedCount > 0) {
503
+ lines.push(`- ... ${omittedCount} additional tool(s) omitted for brevity.`);
504
+ }
505
+ return lines.join("\n");
506
+ }
507
+ applyHooks(baseHooks) {
508
+ return {
509
+ onBeforeToolCall: async (name, input) => {
510
+ this.observePotentialPolicyViolation(name, input);
511
+ if (baseHooks?.onBeforeToolCall) {
512
+ const nextInput = await baseHooks.onBeforeToolCall(name, input);
513
+ return nextInput ?? input;
514
+ }
515
+ return input;
516
+ },
517
+ onAfterToolCall: async (name, input, output) => {
518
+ if (baseHooks?.onAfterToolCall) {
519
+ const nextOutput = await baseHooks.onAfterToolCall(name, input, output);
520
+ return nextOutput ?? output;
521
+ }
522
+ return output;
523
+ }
524
+ };
525
+ }
526
+ getEvents(limit = 50) {
527
+ return this.events.slice(-Math.max(0, limit));
528
+ }
529
+ observePotentialPolicyViolation(toolName, input) {
530
+ if (this.mode !== "planning") {
531
+ return;
532
+ }
533
+ const meta = this.inferToolMeta(toolName);
534
+ const policy = this.getModePolicy("planning");
535
+ if (!policy.disallowedCategories.includes(meta.category)) {
536
+ return;
537
+ }
538
+ this.emitEvent("disallowed_tool_attempt_in_planning", {
539
+ toolName,
540
+ category: meta.category,
541
+ risk: meta.risk,
542
+ input
543
+ });
544
+ }
545
+ inferToolMeta(name) {
546
+ const knownMeta = KNOWN_TOOL_META[name];
547
+ if (knownMeta) {
548
+ return {
549
+ name,
550
+ ...knownMeta
551
+ };
552
+ }
553
+ if (name.startsWith("mcp_")) {
554
+ return {
555
+ name,
556
+ category: "execute",
557
+ risk: "medium",
558
+ description: "MCP external tool invocation."
559
+ };
560
+ }
561
+ if (name.endsWith("_agent")) {
562
+ return {
563
+ name,
564
+ category: "execute",
565
+ risk: "high",
566
+ description: "Sub-agent task execution tool."
567
+ };
568
+ }
569
+ if (/read|list|cat/i.test(name)) {
570
+ return {
571
+ name,
572
+ category: "read",
573
+ risk: "low",
574
+ description: "Likely a read-only inspection tool inferred by name."
575
+ };
576
+ }
577
+ if (/search|find|query|grep/i.test(name)) {
578
+ return {
579
+ name,
580
+ category: "search",
581
+ risk: "low",
582
+ description: "Likely a search tool inferred by name."
583
+ };
584
+ }
585
+ if (/write|edit|patch|update|create|delete|remove/i.test(name)) {
586
+ return {
587
+ name,
588
+ category: "write",
589
+ risk: "high",
590
+ description: "Likely a file-modifying tool inferred by name."
591
+ };
592
+ }
593
+ if (/bash|exec|run|shell|deploy|build|test/i.test(name)) {
594
+ return {
595
+ name,
596
+ category: "execute",
597
+ risk: "high",
598
+ description: "Likely a command execution tool inferred by name."
599
+ };
600
+ }
601
+ return {
602
+ name,
603
+ category: "other",
604
+ risk: "low",
605
+ description: "Tool category could not be inferred with high confidence."
606
+ };
607
+ }
608
+ getLatestUserText(messages) {
609
+ for (let i = messages.length - 1; i >= 0; i -= 1) {
610
+ const message = messages[i];
611
+ if (message.role !== "user") {
612
+ continue;
613
+ }
614
+ return this.messageContentToText(message.content);
615
+ }
616
+ return "";
617
+ }
618
+ messageContentToText(content) {
619
+ if (typeof content === "string") {
620
+ return content;
621
+ }
622
+ if (!Array.isArray(content)) {
623
+ return "";
624
+ }
625
+ const textParts = [];
626
+ for (const part of content) {
627
+ if (typeof part === "string") {
628
+ textParts.push(part);
629
+ continue;
630
+ }
631
+ if (part && typeof part === "object" && "text" in part && typeof part.text === "string") {
632
+ textParts.push(part.text);
633
+ }
634
+ }
635
+ return textParts.join("\n");
636
+ }
637
+ emitEvent(name, payload) {
638
+ const event = {
639
+ name,
640
+ mode: this.mode,
641
+ timestamp: Date.now(),
642
+ payload
643
+ };
644
+ this.events.push(event);
645
+ if (this.events.length > 500) {
646
+ this.events.shift();
647
+ }
648
+ this.eventEmitter.emit(name, event);
649
+ this.eventEmitter.emit("plan_mode_event", event);
650
+ if (name === "disallowed_tool_attempt_in_planning") {
651
+ this.logger.warn("[PlanMode] Soft violation detected in planning mode", payload);
652
+ return;
653
+ }
654
+ this.logger.info(`[PlanMode] ${name}`, payload);
655
+ }
656
+ };
657
+ var builtInPlanModePlugin = {
658
+ name: "pulse-coder-engine/built-in-plan-mode",
659
+ version: "1.0.0",
660
+ async initialize(context) {
661
+ const service = new BuiltInPlanModeService(context.logger, context.events, "executing");
662
+ context.registerRunHook("plan-mode", ({ context: runContext, tools, systemPrompt, hooks }) => {
663
+ const transition = service.processContextMessages(runContext.messages);
664
+ const append = service.buildPromptAppend(Object.keys(tools), transition);
665
+ const finalSystemPrompt = appendSystemPrompt(systemPrompt, append);
666
+ return {
667
+ systemPrompt: finalSystemPrompt,
668
+ hooks: service.applyHooks(hooks)
669
+ };
670
+ });
671
+ context.registerService("planMode", service);
672
+ context.registerService("planModeService", service);
673
+ context.logger.info("[PlanMode] Built-in plan mode plugin initialized", {
674
+ mode: service.getMode()
675
+ });
676
+ }
677
+ };
678
+
277
679
  // src/built-in/sub-agent-plugin/index.ts
278
680
  var import_zod10 = require("zod");
279
- var import_fs8 = require("fs");
280
- var import_path2 = __toESM(require("path"), 1);
681
+ var import_fs9 = require("fs");
682
+ var import_path3 = __toESM(require("path"), 1);
281
683
 
282
684
  // src/ai/index.ts
283
685
  var import_ai = require("ai");
@@ -309,8 +711,9 @@ var CLARIFICATION_TIMEOUT = Number(process.env.CLARIFICATION_TIMEOUT ?? 3e5);
309
711
  var CLARIFICATION_ENABLED = process.env.CLARIFICATION_ENABLED !== "false";
310
712
 
311
713
  // src/prompt/system.ts
312
- var generateSystemPrompt = () => {
313
- const basePrompt = `
714
+ var import_fs3 = __toESM(require("fs"), 1);
715
+ var import_path = __toESM(require("path"), 1);
716
+ var DEFAULT_PROMPT = `
314
717
  You are Pulse Coder, the best coding agent on the planet.
315
718
 
316
719
  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.
@@ -390,7 +793,7 @@ Use the 'clarify' tool when you genuinely need information from the user to proc
390
793
  - Explain briefly what would change based on the answer
391
794
 
392
795
  Example usage: Call clarify with a question, optional context, and optional default answer. The tool will pause and wait for the user's response.
393
- - For substantial work, summarize clearly; follow final\u2011answer formatting.
796
+ - For substantial work, summarize clearly; follow final-answer formatting.
394
797
  - Skip heavy formatting for simple confirmations.
395
798
  - Don't dump large files you've written; reference paths only.
396
799
  - No "save/copy this file" - User is on the same machine.
@@ -404,19 +807,19 @@ Example usage: Call clarify with a question, optional context, and optional defa
404
807
  ## Final answer structure and style guidelines
405
808
 
406
809
  - Plain text; CLI handles styling. Use structure only when it helps scanability.
407
- - Headers: optional; short Title Case (1-3 words) wrapped in **\u2026**; no blank line before the first bullet; add only if they truly help.
408
- - Bullets: use - ; merge related points; keep to one line when possible; 4\u20136 per list ordered by importance; keep phrasing consistent.
810
+ - Headers: optional; short Title Case (1-3 words) wrapped in **...**; no blank line before the first bullet; add only if they truly help.
811
+ - Bullets: use - ; merge related points; keep to one line when possible; 4-6 per list ordered by importance; keep phrasing consistent.
409
812
  - Monospace: backticks for commands/paths/env vars/code ids and inline examples; use for literal keyword bullets; never combine with **.
410
813
  - Code samples or multi-line snippets should be wrapped in fenced code blocks; include an info string as often as possible.
411
- - Structure: group related bullets; order sections general \u2192 specific \u2192 supporting; for subsections, start with a bolded keyword bullet, then items; match complexity to the task.
412
- - Tone: collaborative, concise, factual; present tense, active voice; self\u2011contained; no "above/below"; parallel wording.
413
- - Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short\u2014wrap/reformat if long; avoid naming formatting styles in answers.
414
- - Adaptation: code explanations \u2192 precise, structured with code refs; simple tasks \u2192 lead with outcome; big changes \u2192 logical walkthrough + rationale + next actions; casual one-offs \u2192 plain sentences, no headers/bullets.
814
+ - Structure: group related bullets; order sections general -> specific -> supporting; for subsections, start with a bolded keyword bullet, then items; match complexity to the task.
815
+ - Tone: collaborative, concise, factual; present tense, active voice; self-contained; no "above/below"; parallel wording.
816
+ - Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short-wrap/reformat if long; avoid naming formatting styles in answers.
817
+ - Adaptation: code explanations -> precise, structured with code refs; simple tasks -> lead with outcome; big changes -> logical walkthrough + rationale + next actions; casual one-offs -> plain sentences, no headers/bullets.
415
818
  - File References: When referencing files in your response follow the below rules:
416
819
  * Use inline code to make file paths clickable.
417
820
  * Each reference should have a stand alone path. Even if it's the same file.
418
- * Accepted: absolute, workspace\u2011relative, a/ or b/ diff prefixes, or bare filename/suffix.
419
- * Optionally include line/column (1\u2011based): :line[:column] or #Lline[Ccolumn] (column defaults to 1).
821
+ * Accepted: absolute, workspace-relative, a/ or b/ diff prefixes, or bare filename/suffix.
822
+ * Optionally include line/column (1-based): :line[:column] or #Lline[Ccolumn] (column defaults to 1).
420
823
  * Do not use URIs like file://, vscode://, or https://.
421
824
  * Do not provide range of lines
422
825
  * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\repoprojectmain.rs:12:5
@@ -430,7 +833,24 @@ Here is some useful information about the environment you are running in:
430
833
  <files>
431
834
 
432
835
  </files>`;
433
- return basePrompt;
836
+ var AGENTS_FILE_REGEX = /^agents\.md$/i;
837
+ var loadAgentsPrompt = () => {
838
+ try {
839
+ const cwd = process.cwd();
840
+ const entries = import_fs3.default.readdirSync(cwd, { withFileTypes: true });
841
+ const target = entries.find((entry) => entry.isFile() && AGENTS_FILE_REGEX.test(entry.name));
842
+ if (!target) {
843
+ return null;
844
+ }
845
+ const filePath = import_path.default.join(cwd, target.name);
846
+ const content = import_fs3.default.readFileSync(filePath, "utf8").trim();
847
+ return content.length > 0 ? content : null;
848
+ } catch {
849
+ return null;
850
+ }
851
+ };
852
+ var generateSystemPrompt = () => {
853
+ return loadAgentsPrompt() ?? DEFAULT_PROMPT;
434
854
  };
435
855
 
436
856
  // src/ai/index.ts
@@ -742,7 +1162,7 @@ function sleep(ms) {
742
1162
 
743
1163
  // src/tools/read.ts
744
1164
  var import_zod2 = __toESM(require("zod"), 1);
745
- var import_fs3 = require("fs");
1165
+ var import_fs4 = require("fs");
746
1166
 
747
1167
  // src/tools/utils.ts
748
1168
  var truncateOutput = (output) => {
@@ -768,14 +1188,14 @@ var ReadTool = {
768
1188
  limit: import_zod2.default.number().optional().describe("The number of lines to read. Only provide if the file is too large to read at once.")
769
1189
  }),
770
1190
  execute: async ({ filePath, offset, limit }) => {
771
- if (!(0, import_fs3.existsSync)(filePath)) {
1191
+ if (!(0, import_fs4.existsSync)(filePath)) {
772
1192
  throw new Error(`File does not exist: ${filePath}`);
773
1193
  }
774
- const stats = (0, import_fs3.statSync)(filePath);
1194
+ const stats = (0, import_fs4.statSync)(filePath);
775
1195
  if (stats.isDirectory()) {
776
1196
  throw new Error(`Cannot read directory: ${filePath}. Use 'ls' tool to list directory contents.`);
777
1197
  }
778
- const content = (0, import_fs3.readFileSync)(filePath, "utf-8");
1198
+ const content = (0, import_fs4.readFileSync)(filePath, "utf-8");
779
1199
  const lines = content.split("\n");
780
1200
  const totalLines = lines.length;
781
1201
  if (offset === void 0 && limit === void 0) {
@@ -803,8 +1223,8 @@ var ReadTool = {
803
1223
 
804
1224
  // src/tools/write.ts
805
1225
  var import_zod3 = __toESM(require("zod"), 1);
806
- var import_fs4 = require("fs");
807
- var import_path = require("path");
1226
+ var import_fs5 = require("fs");
1227
+ var import_path2 = require("path");
808
1228
  var WriteTool = {
809
1229
  name: "write",
810
1230
  description: "Write contents to a file. Automatically creates parent directories if they do not exist. Will overwrite existing files.",
@@ -813,12 +1233,12 @@ var WriteTool = {
813
1233
  content: import_zod3.default.string().describe("The content to write to the file")
814
1234
  }),
815
1235
  execute: async ({ filePath, content }) => {
816
- const fileExists = (0, import_fs4.existsSync)(filePath);
817
- const dir = (0, import_path.dirname)(filePath);
818
- if (!(0, import_fs4.existsSync)(dir)) {
819
- (0, import_fs4.mkdirSync)(dir, { recursive: true });
1236
+ const fileExists = (0, import_fs5.existsSync)(filePath);
1237
+ const dir = (0, import_path2.dirname)(filePath);
1238
+ if (!(0, import_fs5.existsSync)(dir)) {
1239
+ (0, import_fs5.mkdirSync)(dir, { recursive: true });
820
1240
  }
821
- (0, import_fs4.writeFileSync)(filePath, content, "utf-8");
1241
+ (0, import_fs5.writeFileSync)(filePath, content, "utf-8");
822
1242
  const bytes = Buffer.byteLength(content, "utf-8");
823
1243
  return {
824
1244
  success: true,
@@ -830,7 +1250,7 @@ var WriteTool = {
830
1250
 
831
1251
  // src/tools/edit.ts
832
1252
  var import_zod4 = __toESM(require("zod"), 1);
833
- var import_fs5 = require("fs");
1253
+ var import_fs6 = require("fs");
834
1254
  var EditTool = {
835
1255
  name: "edit",
836
1256
  description: "Performs exact string replacements in files. Use this to edit existing files by replacing old_string with new_string.",
@@ -844,7 +1264,7 @@ var EditTool = {
844
1264
  if (oldString === newString) {
845
1265
  throw new Error("old_string and new_string must be different");
846
1266
  }
847
- const content = (0, import_fs5.readFileSync)(filePath, "utf-8");
1267
+ const content = (0, import_fs6.readFileSync)(filePath, "utf-8");
848
1268
  if (!content.includes(oldString)) {
849
1269
  throw new Error(`old_string not found in file: ${filePath}`);
850
1270
  }
@@ -868,7 +1288,7 @@ var EditTool = {
868
1288
  newContent = content.slice(0, index) + newString + content.slice(index + oldString.length);
869
1289
  replacements = 1;
870
1290
  }
871
- (0, import_fs5.writeFileSync)(filePath, newContent, "utf-8");
1291
+ (0, import_fs6.writeFileSync)(filePath, newContent, "utf-8");
872
1292
  const changedIndex = newContent.indexOf(newString);
873
1293
  const contextLength = 200;
874
1294
  const start = Math.max(0, changedIndex - contextLength);
@@ -887,7 +1307,7 @@ var EditTool = {
887
1307
  // src/tools/grep.ts
888
1308
  var import_zod5 = __toESM(require("zod"), 1);
889
1309
  var import_child_process = require("child_process");
890
- var import_fs6 = require("fs");
1310
+ var import_fs7 = require("fs");
891
1311
  var GrepTool = {
892
1312
  name: "grep",
893
1313
  description: "A powerful search tool built on ripgrep. Supports regex patterns, file filtering, and multiple output modes.",
@@ -905,7 +1325,7 @@ var GrepTool = {
905
1325
  }),
906
1326
  execute: async ({
907
1327
  pattern,
908
- path: path3 = ".",
1328
+ path: path4 = ".",
909
1329
  glob,
910
1330
  type,
911
1331
  outputMode = "files_with_matches",
@@ -940,11 +1360,11 @@ var GrepTool = {
940
1360
  if (type) {
941
1361
  args.push("--type", type);
942
1362
  }
943
- if (path3 && path3 !== ".") {
944
- if (!(0, import_fs6.existsSync)(path3)) {
945
- throw new Error(`Path does not exist: ${path3}`);
1363
+ if (path4 && path4 !== ".") {
1364
+ if (!(0, import_fs7.existsSync)(path4)) {
1365
+ throw new Error(`Path does not exist: ${path4}`);
946
1366
  }
947
- args.push(path3);
1367
+ args.push(path4);
948
1368
  }
949
1369
  let command = args.map((arg) => {
950
1370
  if (arg.includes(" ") || arg.includes("$") || arg.includes("*")) {
@@ -992,15 +1412,15 @@ Command: ${command}`
992
1412
 
993
1413
  // src/tools/ls.ts
994
1414
  var import_zod6 = __toESM(require("zod"), 1);
995
- var import_fs7 = require("fs");
1415
+ var import_fs8 = require("fs");
996
1416
  var LsTool = {
997
1417
  name: "ls",
998
1418
  description: "List files and directories in a given path",
999
1419
  inputSchema: import_zod6.default.object({
1000
1420
  path: import_zod6.default.string().optional().describe("The path to list files from (defaults to current directory)")
1001
1421
  }),
1002
- execute: async ({ path: path3 = "." }) => {
1003
- const files = (0, import_fs7.readdirSync)(path3);
1422
+ execute: async ({ path: path4 = "." }) => {
1423
+ const files = (0, import_fs8.readdirSync)(path4);
1004
1424
  return { files };
1005
1425
  }
1006
1426
  };
@@ -1171,8 +1591,8 @@ var ConfigLoader = class {
1171
1591
  const fileInfos = [];
1172
1592
  for (let configDir of configDirs) {
1173
1593
  try {
1174
- await import_fs8.promises.access(configDir);
1175
- const files = await import_fs8.promises.readdir(configDir);
1594
+ await import_fs9.promises.access(configDir);
1595
+ const files = await import_fs9.promises.readdir(configDir);
1176
1596
  fileInfos.push({ files, configDir });
1177
1597
  } catch {
1178
1598
  continue;
@@ -1189,7 +1609,7 @@ var ConfigLoader = class {
1189
1609
  const files = fileInfo.files;
1190
1610
  for (const file of files) {
1191
1611
  if (file.endsWith(".md")) {
1192
- const config = await this.parseConfig(import_path2.default.join(fileInfo.configDir, file));
1612
+ const config = await this.parseConfig(import_path3.default.join(fileInfo.configDir, file));
1193
1613
  if (config) configs.push(config);
1194
1614
  }
1195
1615
  }
@@ -1201,7 +1621,7 @@ var ConfigLoader = class {
1201
1621
  }
1202
1622
  async parseConfig(filePath) {
1203
1623
  try {
1204
- const content = await import_fs8.promises.readFile(filePath, "utf-8");
1624
+ const content = await import_fs9.promises.readFile(filePath, "utf-8");
1205
1625
  const lines = content.split("\n");
1206
1626
  let name = "";
1207
1627
  let description = "";
@@ -1230,7 +1650,7 @@ var ConfigLoader = class {
1230
1650
  }
1231
1651
  }
1232
1652
  if (!name) {
1233
- name = import_path2.default.basename(filePath, ".md");
1653
+ name = import_path3.default.basename(filePath, ".md");
1234
1654
  }
1235
1655
  return {
1236
1656
  name: name.trim(),
@@ -1313,14 +1733,17 @@ var SubAgentPlugin = class {
1313
1733
  var builtInPlugins = [
1314
1734
  builtInMCPPlugin,
1315
1735
  builtInSkillsPlugin,
1736
+ builtInPlanModePlugin,
1316
1737
  new SubAgentPlugin()
1317
1738
  ];
1318
1739
  var built_in_default = builtInPlugins;
1319
1740
  // Annotate the CommonJS export names for ESM import in node:
1320
1741
  0 && (module.exports = {
1742
+ BuiltInPlanModeService,
1321
1743
  BuiltInSkillRegistry,
1322
1744
  SubAgentPlugin,
1323
1745
  builtInMCPPlugin,
1746
+ builtInPlanModePlugin,
1324
1747
  builtInPlugins,
1325
1748
  builtInSkillsPlugin
1326
1749
  });