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.
- package/LICENSE +21 -0
- package/dist/built-in/index.cjs +465 -42
- package/dist/built-in/index.cjs.map +1 -1
- package/dist/built-in/index.d.cts +1 -1
- package/dist/built-in/index.d.ts +1 -1
- package/dist/built-in/index.js +447 -26
- package/dist/built-in/index.js.map +1 -1
- package/dist/index-BkkQyz2L.d.cts +291 -0
- package/dist/index-BkkQyz2L.d.ts +291 -0
- package/dist/index.cjs +523 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -95
- package/dist/index.d.ts +12 -95
- package/dist/index.js +499 -37
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/dist/index-DDqISE31.d.cts +0 -120
- package/dist/index-DDqISE31.d.ts +0 -120
package/dist/built-in/index.cjs
CHANGED
|
@@ -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
|
|
280
|
-
var
|
|
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
|
|
313
|
-
|
|
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
|
|
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
|
|
408
|
-
- Bullets: use - ; merge related points; keep to one line when possible; 4
|
|
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
|
|
412
|
-
- Tone: collaborative, concise, factual; present tense, active voice; self
|
|
413
|
-
- Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short
|
|
414
|
-
- Adaptation: code explanations
|
|
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
|
|
419
|
-
* Optionally include line/column (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
|
-
|
|
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
|
|
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,
|
|
1191
|
+
if (!(0, import_fs4.existsSync)(filePath)) {
|
|
772
1192
|
throw new Error(`File does not exist: ${filePath}`);
|
|
773
1193
|
}
|
|
774
|
-
const stats = (0,
|
|
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,
|
|
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
|
|
807
|
-
var
|
|
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,
|
|
817
|
-
const dir = (0,
|
|
818
|
-
if (!(0,
|
|
819
|
-
(0,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
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:
|
|
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 (
|
|
944
|
-
if (!(0,
|
|
945
|
-
throw new Error(`Path does not exist: ${
|
|
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(
|
|
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
|
|
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:
|
|
1003
|
-
const files = (0,
|
|
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
|
|
1175
|
-
const files = await
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
});
|