pulse-coder-engine 0.0.1-alpha.10 → 0.0.1-alpha.12
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/dist/built-in/index.cjs +591 -131
- package/dist/built-in/index.cjs.map +1 -1
- package/dist/built-in/index.d.cts +2 -2
- package/dist/built-in/index.d.ts +2 -2
- package/dist/built-in/index.js +578 -120
- package/dist/built-in/index.js.map +1 -1
- package/dist/{index-C7fdydbL.d.cts → index-CPgs_IXY.d.cts} +143 -30
- package/dist/{index-C7fdydbL.d.ts → index-CPgs_IXY.d.ts} +143 -30
- package/dist/index.cjs +586 -111
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -18
- package/dist/index.d.ts +32 -18
- package/dist/index.js +584 -111
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/built-in/index.cjs
CHANGED
|
@@ -33,10 +33,12 @@ __export(built_in_exports, {
|
|
|
33
33
|
BuiltInPlanModeService: () => BuiltInPlanModeService,
|
|
34
34
|
BuiltInSkillRegistry: () => BuiltInSkillRegistry,
|
|
35
35
|
SubAgentPlugin: () => SubAgentPlugin,
|
|
36
|
+
TaskListService: () => TaskListService,
|
|
36
37
|
builtInMCPPlugin: () => builtInMCPPlugin,
|
|
37
38
|
builtInPlanModePlugin: () => builtInPlanModePlugin,
|
|
38
39
|
builtInPlugins: () => builtInPlugins,
|
|
39
40
|
builtInSkillsPlugin: () => builtInSkillsPlugin,
|
|
41
|
+
builtInTaskTrackingPlugin: () => builtInTaskTrackingPlugin,
|
|
40
42
|
default: () => built_in_default
|
|
41
43
|
});
|
|
42
44
|
module.exports = __toCommonJS(built_in_exports);
|
|
@@ -202,16 +204,44 @@ var BuiltInSkillRegistry = class {
|
|
|
202
204
|
return Array.from(this.skills.values());
|
|
203
205
|
}
|
|
204
206
|
/**
|
|
205
|
-
*
|
|
207
|
+
* 注册或更新一个技能(支持插件在运行期追加技能)
|
|
208
|
+
*/
|
|
209
|
+
registerSkill(skill) {
|
|
210
|
+
const name = skill.name?.trim();
|
|
211
|
+
if (!name) {
|
|
212
|
+
throw new Error("Skill name is required");
|
|
213
|
+
}
|
|
214
|
+
const existingKey = Array.from(this.skills.keys()).find((key) => key.toLowerCase() === name.toLowerCase());
|
|
215
|
+
const replaced = existingKey !== void 0;
|
|
216
|
+
if (existingKey && existingKey !== name) {
|
|
217
|
+
this.skills.delete(existingKey);
|
|
218
|
+
}
|
|
219
|
+
this.skills.set(name, {
|
|
220
|
+
...skill,
|
|
221
|
+
name
|
|
222
|
+
});
|
|
223
|
+
return {
|
|
224
|
+
skillName: name,
|
|
225
|
+
replaced,
|
|
226
|
+
total: this.skills.size
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* 根据名称获取技能(大小写不敏感)
|
|
206
231
|
*/
|
|
207
232
|
get(name) {
|
|
208
|
-
|
|
233
|
+
const exact = this.skills.get(name);
|
|
234
|
+
if (exact) {
|
|
235
|
+
return exact;
|
|
236
|
+
}
|
|
237
|
+
const target = name.toLowerCase();
|
|
238
|
+
return this.getAll().find((skill) => skill.name.toLowerCase() === target);
|
|
209
239
|
}
|
|
210
240
|
/**
|
|
211
241
|
* 检查技能是否存在
|
|
212
242
|
*/
|
|
213
243
|
has(name) {
|
|
214
|
-
return this.
|
|
244
|
+
return !!this.get(name);
|
|
215
245
|
}
|
|
216
246
|
/**
|
|
217
247
|
* 搜索技能(模糊匹配)
|
|
@@ -226,7 +256,7 @@ var BuiltInSkillRegistry = class {
|
|
|
226
256
|
var skillToolSchema = import_zod.z.object({
|
|
227
257
|
name: import_zod.z.string().describe("The name of the skill to execute")
|
|
228
258
|
});
|
|
229
|
-
function generateSkillTool(
|
|
259
|
+
function generateSkillTool(registry) {
|
|
230
260
|
const getSkillsPrompt = (availableSkills) => {
|
|
231
261
|
return [
|
|
232
262
|
"If query matches an available skill's description or instruction [use skill], use the skill tool to get detailed instructions.",
|
|
@@ -247,10 +277,10 @@ function generateSkillTool(skills) {
|
|
|
247
277
|
};
|
|
248
278
|
return {
|
|
249
279
|
name: "skill",
|
|
250
|
-
description: getSkillsPrompt(
|
|
280
|
+
description: getSkillsPrompt(registry.getAll()),
|
|
251
281
|
inputSchema: skillToolSchema,
|
|
252
282
|
execute: async ({ name }) => {
|
|
253
|
-
const skill =
|
|
283
|
+
const skill = registry.get(name);
|
|
254
284
|
if (!skill) {
|
|
255
285
|
throw new Error(`Skill ${name} not found`);
|
|
256
286
|
}
|
|
@@ -264,14 +294,21 @@ var builtInSkillsPlugin = {
|
|
|
264
294
|
async initialize(context) {
|
|
265
295
|
const registry = new BuiltInSkillRegistry();
|
|
266
296
|
await registry.initialize(process.cwd());
|
|
297
|
+
context.registerService("skillRegistry", registry);
|
|
298
|
+
context.registerTool("skill", generateSkillTool(registry));
|
|
299
|
+
context.registerHook("beforeRun", ({ tools }) => {
|
|
300
|
+
return {
|
|
301
|
+
tools: {
|
|
302
|
+
...tools,
|
|
303
|
+
skill: generateSkillTool(registry)
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
});
|
|
267
307
|
const skills = registry.getAll();
|
|
268
308
|
if (skills.length === 0) {
|
|
269
309
|
console.log("[Skills] No skills found");
|
|
270
310
|
return;
|
|
271
311
|
}
|
|
272
|
-
const skillTool = generateSkillTool(skills);
|
|
273
|
-
context.registerTool("skill", skillTool);
|
|
274
|
-
context.registerService("skillRegistry", registry);
|
|
275
312
|
console.log(`[Skills] Registered ${skills.length} skill(s)`);
|
|
276
313
|
}
|
|
277
314
|
};
|
|
@@ -382,6 +419,26 @@ var KNOWN_TOOL_META = {
|
|
|
382
419
|
category: "other",
|
|
383
420
|
risk: "low",
|
|
384
421
|
description: "Ask the user a targeted clarification question."
|
|
422
|
+
},
|
|
423
|
+
task_create: {
|
|
424
|
+
category: "other",
|
|
425
|
+
risk: "low",
|
|
426
|
+
description: "Create tracked task entries for planning and execution visibility."
|
|
427
|
+
},
|
|
428
|
+
task_get: {
|
|
429
|
+
category: "other",
|
|
430
|
+
risk: "low",
|
|
431
|
+
description: "Inspect a task entry by ID."
|
|
432
|
+
},
|
|
433
|
+
task_list: {
|
|
434
|
+
category: "other",
|
|
435
|
+
risk: "low",
|
|
436
|
+
description: "List task tracking entries and status summary."
|
|
437
|
+
},
|
|
438
|
+
task_update: {
|
|
439
|
+
category: "other",
|
|
440
|
+
risk: "low",
|
|
441
|
+
description: "Update task tracking fields and status."
|
|
385
442
|
}
|
|
386
443
|
};
|
|
387
444
|
var BuiltInPlanModeService = class {
|
|
@@ -504,25 +561,6 @@ var BuiltInPlanModeService = class {
|
|
|
504
561
|
}
|
|
505
562
|
return lines.join("\n");
|
|
506
563
|
}
|
|
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
564
|
getEvents(limit = 50) {
|
|
527
565
|
return this.events.slice(-Math.max(0, limit));
|
|
528
566
|
}
|
|
@@ -659,21 +697,18 @@ var builtInPlanModePlugin = {
|
|
|
659
697
|
version: "1.0.0",
|
|
660
698
|
async initialize(context) {
|
|
661
699
|
const service = new BuiltInPlanModeService(context.logger, context.events, "executing");
|
|
662
|
-
context.
|
|
700
|
+
context.registerHook("beforeLLMCall", ({ context: runContext, tools, systemPrompt }) => {
|
|
663
701
|
const mode = service.getMode();
|
|
664
702
|
if (mode === "executing") {
|
|
665
|
-
return
|
|
666
|
-
systemPrompt,
|
|
667
|
-
hooks
|
|
668
|
-
};
|
|
703
|
+
return;
|
|
669
704
|
}
|
|
670
705
|
const transition = service.processContextMessages(runContext.messages);
|
|
671
706
|
const append = service.buildPromptAppend(Object.keys(tools), transition);
|
|
672
707
|
const finalSystemPrompt = appendSystemPrompt(systemPrompt, append);
|
|
673
|
-
return {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
708
|
+
return { systemPrompt: finalSystemPrompt };
|
|
709
|
+
});
|
|
710
|
+
context.registerHook("beforeToolCall", ({ name, input }) => {
|
|
711
|
+
service.observePotentialPolicyViolation(name, input);
|
|
677
712
|
});
|
|
678
713
|
context.registerService("planMode", service);
|
|
679
714
|
context.registerService("planModeService", service);
|
|
@@ -683,10 +718,397 @@ var builtInPlanModePlugin = {
|
|
|
683
718
|
}
|
|
684
719
|
};
|
|
685
720
|
|
|
721
|
+
// src/built-in/task-tracking-plugin/index.ts
|
|
722
|
+
var import_fs3 = require("fs");
|
|
723
|
+
var import_path = __toESM(require("path"), 1);
|
|
724
|
+
var import_os2 = require("os");
|
|
725
|
+
var import_crypto = require("crypto");
|
|
726
|
+
var import_zod2 = require("zod");
|
|
727
|
+
var TASK_STATUSES = ["pending", "in_progress", "completed", "blocked"];
|
|
728
|
+
var CREATE_TASK_ITEM_SCHEMA = import_zod2.z.object({
|
|
729
|
+
title: import_zod2.z.string().min(1).describe("Task title"),
|
|
730
|
+
details: import_zod2.z.string().optional().describe("Task details / acceptance notes"),
|
|
731
|
+
status: import_zod2.z.enum(TASK_STATUSES).optional().describe("Initial status; defaults to pending"),
|
|
732
|
+
dependencies: import_zod2.z.array(import_zod2.z.string()).optional().describe("Task IDs that must be completed first"),
|
|
733
|
+
blockedReason: import_zod2.z.string().optional().describe("Reason when status is blocked"),
|
|
734
|
+
metadata: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.any()).optional().describe("Additional machine-readable metadata")
|
|
735
|
+
});
|
|
736
|
+
var TASK_CREATE_INPUT_SCHEMA = import_zod2.z.object({
|
|
737
|
+
title: import_zod2.z.string().min(1).optional().describe("Task title (single-task mode)"),
|
|
738
|
+
details: import_zod2.z.string().optional().describe("Task details (single-task mode)"),
|
|
739
|
+
status: import_zod2.z.enum(TASK_STATUSES).optional().describe("Initial status (single-task mode)"),
|
|
740
|
+
dependencies: import_zod2.z.array(import_zod2.z.string()).optional().describe("Dependencies (single-task mode)"),
|
|
741
|
+
blockedReason: import_zod2.z.string().optional().describe("Blocked reason (single-task mode)"),
|
|
742
|
+
metadata: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.any()).optional().describe("Metadata (single-task mode)"),
|
|
743
|
+
tasks: import_zod2.z.array(CREATE_TASK_ITEM_SCHEMA).min(1).optional().describe("Batch create mode")
|
|
744
|
+
}).refine((value) => !!value.tasks?.length || !!value.title, {
|
|
745
|
+
message: "Either provide `tasks` or `title` for single-task mode."
|
|
746
|
+
});
|
|
747
|
+
var TASK_GET_INPUT_SCHEMA = import_zod2.z.object({
|
|
748
|
+
id: import_zod2.z.string().min(1).describe("Task ID to retrieve")
|
|
749
|
+
});
|
|
750
|
+
var TASK_LIST_INPUT_SCHEMA = import_zod2.z.object({
|
|
751
|
+
statuses: import_zod2.z.array(import_zod2.z.enum(TASK_STATUSES)).optional().describe("Filter by statuses"),
|
|
752
|
+
includeCompleted: import_zod2.z.boolean().optional().describe("Set false to hide completed tasks"),
|
|
753
|
+
limit: import_zod2.z.number().int().positive().max(500).optional().describe("Maximum tasks to return")
|
|
754
|
+
});
|
|
755
|
+
var TASK_TRACKING_SKILL = {
|
|
756
|
+
name: "task-tracking-workflow",
|
|
757
|
+
description: "Track complex execution with task tools and proceed directly without confirmation unless the user explicitly asks for confirmation.",
|
|
758
|
+
location: "pulse-coder-engine/built-in/task-tracking-plugin",
|
|
759
|
+
content: `# Task Tracking Workflow
|
|
760
|
+
|
|
761
|
+
## When to use
|
|
762
|
+
- The request has multiple phases or deliverables.
|
|
763
|
+
- Work may span multiple tool calls or sessions.
|
|
764
|
+
- You need explicit progress visibility and blocker management.
|
|
765
|
+
|
|
766
|
+
## Execution autonomy
|
|
767
|
+
- Default behavior: execute directly and call tools without asking for confirmation.
|
|
768
|
+
- Only ask for confirmation when the user explicitly requires confirmation.
|
|
769
|
+
- If critical information is missing, ask only the minimum clarifying question needed to continue.
|
|
770
|
+
|
|
771
|
+
## Required flow
|
|
772
|
+
1. Start by reviewing existing tasks with \`task_list\`.
|
|
773
|
+
2. If no suitable tasks exist, create focused tasks with \`task_create\` (prefer batch mode).
|
|
774
|
+
3. Keep exactly one primary task in \`in_progress\` where possible.
|
|
775
|
+
4. Update status with \`task_update\` after meaningful progress.
|
|
776
|
+
5. Mark blockers with \`status=blocked\` and a concrete \`blockedReason\`.
|
|
777
|
+
6. Mark done tasks as \`completed\` and move to the next actionable item.
|
|
778
|
+
|
|
779
|
+
## Quality rules
|
|
780
|
+
- Keep tasks atomic and verifiable.
|
|
781
|
+
- Avoid single oversized umbrella tasks.
|
|
782
|
+
- Reuse existing in-progress tasks instead of duplicating.
|
|
783
|
+
- Keep dependency links explicit when order matters.`
|
|
784
|
+
};
|
|
785
|
+
var TASK_UPDATE_INPUT_SCHEMA = import_zod2.z.object({
|
|
786
|
+
id: import_zod2.z.string().min(1).describe("Task ID to update"),
|
|
787
|
+
title: import_zod2.z.string().min(1).optional().describe("New title"),
|
|
788
|
+
details: import_zod2.z.string().optional().describe("New details"),
|
|
789
|
+
status: import_zod2.z.enum(TASK_STATUSES).optional().describe("New status"),
|
|
790
|
+
dependencies: import_zod2.z.array(import_zod2.z.string()).optional().describe("Replace dependencies with this list"),
|
|
791
|
+
blockedReason: import_zod2.z.string().optional().describe("Blocked reason, used with status=blocked"),
|
|
792
|
+
metadata: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.any()).optional().describe("Replace metadata object"),
|
|
793
|
+
delete: import_zod2.z.boolean().optional().describe("Delete this task")
|
|
794
|
+
});
|
|
795
|
+
function normalizeTaskListId(raw) {
|
|
796
|
+
const trimmed = raw.trim();
|
|
797
|
+
if (!trimmed) {
|
|
798
|
+
return "default";
|
|
799
|
+
}
|
|
800
|
+
return trimmed.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120) || "default";
|
|
801
|
+
}
|
|
802
|
+
function now() {
|
|
803
|
+
return Date.now();
|
|
804
|
+
}
|
|
805
|
+
function dedupeStrings(values) {
|
|
806
|
+
if (!values?.length) {
|
|
807
|
+
return [];
|
|
808
|
+
}
|
|
809
|
+
return Array.from(new Set(values.map((value) => String(value).trim()).filter(Boolean)));
|
|
810
|
+
}
|
|
811
|
+
var TaskListService = class _TaskListService {
|
|
812
|
+
taskListId;
|
|
813
|
+
storagePath;
|
|
814
|
+
storageDir;
|
|
815
|
+
initialized = false;
|
|
816
|
+
createdAt = now();
|
|
817
|
+
updatedAt = now();
|
|
818
|
+
tasks = /* @__PURE__ */ new Map();
|
|
819
|
+
constructor(taskListId = _TaskListService.resolveTaskListId(), storageDir = _TaskListService.resolveStorageDir()) {
|
|
820
|
+
const normalized = normalizeTaskListId(taskListId);
|
|
821
|
+
this.storageDir = storageDir;
|
|
822
|
+
this.taskListId = normalized;
|
|
823
|
+
this.storagePath = import_path.default.join(this.storageDir, `${normalized}.json`);
|
|
824
|
+
}
|
|
825
|
+
static resolveTaskListId() {
|
|
826
|
+
return process.env.PULSE_CODER_TASK_LIST_ID || process.env.CLAUDE_CODE_TASK_LIST_ID || "default";
|
|
827
|
+
}
|
|
828
|
+
static resolveStorageDir() {
|
|
829
|
+
return process.env.PULSE_CODER_TASKS_DIR || import_path.default.join((0, import_os2.homedir)(), ".pulse-coder", "tasks");
|
|
830
|
+
}
|
|
831
|
+
async initialize() {
|
|
832
|
+
if (this.initialized) {
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
await this.loadTaskList(this.taskListId);
|
|
836
|
+
}
|
|
837
|
+
async setTaskListId(taskListId) {
|
|
838
|
+
await this.initialize();
|
|
839
|
+
const normalized = normalizeTaskListId(taskListId);
|
|
840
|
+
if (normalized === this.taskListId) {
|
|
841
|
+
return {
|
|
842
|
+
switched: false,
|
|
843
|
+
taskListId: this.taskListId,
|
|
844
|
+
storagePath: this.storagePath
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
await this.loadTaskList(normalized);
|
|
848
|
+
return {
|
|
849
|
+
switched: true,
|
|
850
|
+
taskListId: this.taskListId,
|
|
851
|
+
storagePath: this.storagePath
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
async createTask(input) {
|
|
855
|
+
await this.initialize();
|
|
856
|
+
const timestamp = now();
|
|
857
|
+
const status = input.status ?? "pending";
|
|
858
|
+
const task = {
|
|
859
|
+
id: (0, import_crypto.randomUUID)(),
|
|
860
|
+
title: input.title.trim(),
|
|
861
|
+
details: input.details,
|
|
862
|
+
status,
|
|
863
|
+
dependencies: dedupeStrings(input.dependencies),
|
|
864
|
+
blockedReason: status === "blocked" ? input.blockedReason ?? "Blocked without reason" : void 0,
|
|
865
|
+
metadata: input.metadata,
|
|
866
|
+
createdAt: timestamp,
|
|
867
|
+
updatedAt: timestamp,
|
|
868
|
+
completedAt: status === "completed" ? timestamp : void 0
|
|
869
|
+
};
|
|
870
|
+
this.tasks.set(task.id, task);
|
|
871
|
+
this.updatedAt = timestamp;
|
|
872
|
+
await this.persist();
|
|
873
|
+
return task;
|
|
874
|
+
}
|
|
875
|
+
async createTasks(inputs) {
|
|
876
|
+
const created = [];
|
|
877
|
+
for (const input of inputs) {
|
|
878
|
+
created.push(await this.createTask(input));
|
|
879
|
+
}
|
|
880
|
+
return created;
|
|
881
|
+
}
|
|
882
|
+
async listTasks(options) {
|
|
883
|
+
await this.initialize();
|
|
884
|
+
const statuses = options?.statuses?.length ? new Set(options.statuses) : null;
|
|
885
|
+
const includeCompleted = options?.includeCompleted ?? true;
|
|
886
|
+
let tasks = Array.from(this.tasks.values()).filter((task) => {
|
|
887
|
+
if (!includeCompleted && task.status === "completed") {
|
|
888
|
+
return false;
|
|
889
|
+
}
|
|
890
|
+
if (statuses && !statuses.has(task.status)) {
|
|
891
|
+
return false;
|
|
892
|
+
}
|
|
893
|
+
return true;
|
|
894
|
+
});
|
|
895
|
+
tasks = tasks.sort((a, b) => a.createdAt - b.createdAt);
|
|
896
|
+
if (options?.limit && options.limit > 0) {
|
|
897
|
+
tasks = tasks.slice(0, options.limit);
|
|
898
|
+
}
|
|
899
|
+
return tasks;
|
|
900
|
+
}
|
|
901
|
+
async getTask(id) {
|
|
902
|
+
await this.initialize();
|
|
903
|
+
return this.tasks.get(id) ?? null;
|
|
904
|
+
}
|
|
905
|
+
async updateTask(input) {
|
|
906
|
+
await this.initialize();
|
|
907
|
+
if (input.delete) {
|
|
908
|
+
const deleted = this.tasks.delete(input.id);
|
|
909
|
+
if (!deleted) {
|
|
910
|
+
return null;
|
|
911
|
+
}
|
|
912
|
+
this.updatedAt = now();
|
|
913
|
+
await this.persist();
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
916
|
+
const existing = this.tasks.get(input.id);
|
|
917
|
+
if (!existing) {
|
|
918
|
+
return null;
|
|
919
|
+
}
|
|
920
|
+
const timestamp = now();
|
|
921
|
+
const nextStatus = input.status ?? existing.status;
|
|
922
|
+
const next = {
|
|
923
|
+
...existing,
|
|
924
|
+
title: input.title !== void 0 ? input.title : existing.title,
|
|
925
|
+
details: input.details !== void 0 ? input.details : existing.details,
|
|
926
|
+
status: nextStatus,
|
|
927
|
+
dependencies: input.dependencies !== void 0 ? dedupeStrings(input.dependencies) : existing.dependencies,
|
|
928
|
+
metadata: input.metadata !== void 0 ? input.metadata : existing.metadata,
|
|
929
|
+
blockedReason: this.resolveBlockedReason(nextStatus, input.blockedReason, existing.blockedReason),
|
|
930
|
+
updatedAt: timestamp,
|
|
931
|
+
completedAt: nextStatus === "completed" ? existing.completedAt ?? timestamp : void 0
|
|
932
|
+
};
|
|
933
|
+
this.tasks.set(input.id, next);
|
|
934
|
+
this.updatedAt = timestamp;
|
|
935
|
+
await this.persist();
|
|
936
|
+
return next;
|
|
937
|
+
}
|
|
938
|
+
async snapshot(options) {
|
|
939
|
+
const tasks = await this.listTasks(options);
|
|
940
|
+
return {
|
|
941
|
+
taskListId: this.taskListId,
|
|
942
|
+
storagePath: this.storagePath,
|
|
943
|
+
createdAt: this.createdAt,
|
|
944
|
+
updatedAt: this.updatedAt,
|
|
945
|
+
total: tasks.length,
|
|
946
|
+
tasks
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
resolveBlockedReason(status, blockedReasonInput, previous) {
|
|
950
|
+
if (status !== "blocked") {
|
|
951
|
+
return void 0;
|
|
952
|
+
}
|
|
953
|
+
if (blockedReasonInput !== void 0) {
|
|
954
|
+
return blockedReasonInput || "Blocked without reason";
|
|
955
|
+
}
|
|
956
|
+
return previous ?? "Blocked without reason";
|
|
957
|
+
}
|
|
958
|
+
async loadTaskList(taskListId) {
|
|
959
|
+
const normalized = normalizeTaskListId(taskListId);
|
|
960
|
+
this.taskListId = normalized;
|
|
961
|
+
this.storagePath = import_path.default.join(this.storageDir, `${normalized}.json`);
|
|
962
|
+
await import_fs3.promises.mkdir(this.storageDir, { recursive: true });
|
|
963
|
+
try {
|
|
964
|
+
const raw = await import_fs3.promises.readFile(this.storagePath, "utf-8");
|
|
965
|
+
const parsed = JSON.parse(raw);
|
|
966
|
+
const parsedTasks = Array.isArray(parsed.tasks) ? parsed.tasks : [];
|
|
967
|
+
this.tasks = new Map(parsedTasks.filter((task) => !!task?.id).map((task) => [task.id, task]));
|
|
968
|
+
this.createdAt = typeof parsed.createdAt === "number" ? parsed.createdAt : now();
|
|
969
|
+
this.updatedAt = typeof parsed.updatedAt === "number" ? parsed.updatedAt : now();
|
|
970
|
+
} catch (error) {
|
|
971
|
+
if (error?.code !== "ENOENT") {
|
|
972
|
+
throw error;
|
|
973
|
+
}
|
|
974
|
+
const timestamp = now();
|
|
975
|
+
this.tasks = /* @__PURE__ */ new Map();
|
|
976
|
+
this.createdAt = timestamp;
|
|
977
|
+
this.updatedAt = timestamp;
|
|
978
|
+
await this.persist();
|
|
979
|
+
}
|
|
980
|
+
this.initialized = true;
|
|
981
|
+
}
|
|
982
|
+
async persist() {
|
|
983
|
+
const payload = {
|
|
984
|
+
taskListId: this.taskListId,
|
|
985
|
+
createdAt: this.createdAt,
|
|
986
|
+
updatedAt: this.updatedAt,
|
|
987
|
+
tasks: Array.from(this.tasks.values()).sort((a, b) => a.createdAt - b.createdAt)
|
|
988
|
+
};
|
|
989
|
+
await import_fs3.promises.writeFile(this.storagePath, JSON.stringify(payload, null, 2), "utf-8");
|
|
990
|
+
}
|
|
991
|
+
};
|
|
992
|
+
function buildTaskCreateTool(service) {
|
|
993
|
+
return {
|
|
994
|
+
name: "task_create",
|
|
995
|
+
description: "Create one or more tracked tasks for complex work. Use this when work has multiple steps, dependencies, or blockers.",
|
|
996
|
+
inputSchema: TASK_CREATE_INPUT_SCHEMA,
|
|
997
|
+
execute: async ({ tasks, title, details, status, dependencies, blockedReason, metadata }) => {
|
|
998
|
+
const items = tasks?.length ? tasks : [{ title, details, status, dependencies, blockedReason, metadata }];
|
|
999
|
+
const created = await service.createTasks(items);
|
|
1000
|
+
return {
|
|
1001
|
+
taskListId: service.taskListId,
|
|
1002
|
+
storagePath: service.storagePath,
|
|
1003
|
+
createdCount: created.length,
|
|
1004
|
+
tasks: created
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
}
|
|
1009
|
+
function buildTaskGetTool(service) {
|
|
1010
|
+
return {
|
|
1011
|
+
name: "task_get",
|
|
1012
|
+
description: "Get full details for a single task by task ID.",
|
|
1013
|
+
inputSchema: TASK_GET_INPUT_SCHEMA,
|
|
1014
|
+
execute: async ({ id }) => {
|
|
1015
|
+
const task = await service.getTask(id);
|
|
1016
|
+
if (!task) {
|
|
1017
|
+
throw new Error(`Task not found: ${id}`);
|
|
1018
|
+
}
|
|
1019
|
+
return {
|
|
1020
|
+
taskListId: service.taskListId,
|
|
1021
|
+
storagePath: service.storagePath,
|
|
1022
|
+
task
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
function buildTaskListTool(service) {
|
|
1028
|
+
return {
|
|
1029
|
+
name: "task_list",
|
|
1030
|
+
description: "List tasks and their current status. Use this to check progress before and after major changes.",
|
|
1031
|
+
inputSchema: TASK_LIST_INPUT_SCHEMA,
|
|
1032
|
+
execute: async ({ statuses, includeCompleted, limit }) => {
|
|
1033
|
+
const snapshot = await service.snapshot({ statuses, includeCompleted, limit });
|
|
1034
|
+
const completed = snapshot.tasks.filter((task) => task.status === "completed").length;
|
|
1035
|
+
const inProgress = snapshot.tasks.filter((task) => task.status === "in_progress").length;
|
|
1036
|
+
const pending = snapshot.tasks.filter((task) => task.status === "pending").length;
|
|
1037
|
+
const blocked = snapshot.tasks.filter((task) => task.status === "blocked").length;
|
|
1038
|
+
return {
|
|
1039
|
+
...snapshot,
|
|
1040
|
+
summary: {
|
|
1041
|
+
total: snapshot.total,
|
|
1042
|
+
completed,
|
|
1043
|
+
inProgress,
|
|
1044
|
+
pending,
|
|
1045
|
+
blocked
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
function buildTaskUpdateTool(service) {
|
|
1052
|
+
return {
|
|
1053
|
+
name: "task_update",
|
|
1054
|
+
description: "Update task fields, move status (pending/in_progress/completed/blocked), or delete tasks.",
|
|
1055
|
+
inputSchema: TASK_UPDATE_INPUT_SCHEMA,
|
|
1056
|
+
execute: async (input) => {
|
|
1057
|
+
const task = await service.updateTask(input);
|
|
1058
|
+
if (input.delete) {
|
|
1059
|
+
return {
|
|
1060
|
+
taskListId: service.taskListId,
|
|
1061
|
+
storagePath: service.storagePath,
|
|
1062
|
+
deleted: true,
|
|
1063
|
+
id: input.id
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
if (!task) {
|
|
1067
|
+
throw new Error(`Task not found: ${input.id}`);
|
|
1068
|
+
}
|
|
1069
|
+
return {
|
|
1070
|
+
taskListId: service.taskListId,
|
|
1071
|
+
storagePath: service.storagePath,
|
|
1072
|
+
deleted: false,
|
|
1073
|
+
task
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
var builtInTaskTrackingPlugin = {
|
|
1079
|
+
name: "pulse-coder-engine/built-in-task-tracking",
|
|
1080
|
+
version: "1.0.0",
|
|
1081
|
+
dependencies: ["pulse-coder-engine/built-in-skills"],
|
|
1082
|
+
async initialize(context) {
|
|
1083
|
+
const service = new TaskListService();
|
|
1084
|
+
await service.initialize();
|
|
1085
|
+
context.registerService("taskListService", service);
|
|
1086
|
+
context.registerService("taskTracking", service);
|
|
1087
|
+
const skillRegistry = context.getService("skillRegistry");
|
|
1088
|
+
if (skillRegistry) {
|
|
1089
|
+
const registration = skillRegistry.registerSkill(TASK_TRACKING_SKILL);
|
|
1090
|
+
context.logger.info("[TaskTracking] Registered built-in task tracking skill", registration);
|
|
1091
|
+
} else {
|
|
1092
|
+
context.logger.warn("[TaskTracking] skillRegistry service unavailable; skipped task tracking skill registration");
|
|
1093
|
+
}
|
|
1094
|
+
context.registerTools({
|
|
1095
|
+
task_create: buildTaskCreateTool(service),
|
|
1096
|
+
task_get: buildTaskGetTool(service),
|
|
1097
|
+
task_list: buildTaskListTool(service),
|
|
1098
|
+
task_update: buildTaskUpdateTool(service)
|
|
1099
|
+
});
|
|
1100
|
+
context.logger.info("[TaskTracking] Registered task tools", {
|
|
1101
|
+
taskListId: service.taskListId,
|
|
1102
|
+
storagePath: service.storagePath,
|
|
1103
|
+
skillRegistryAvailable: !!skillRegistry
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
};
|
|
1107
|
+
|
|
686
1108
|
// src/built-in/sub-agent-plugin/index.ts
|
|
687
|
-
var
|
|
688
|
-
var
|
|
689
|
-
var
|
|
1109
|
+
var import_zod11 = require("zod");
|
|
1110
|
+
var import_fs10 = require("fs");
|
|
1111
|
+
var import_path4 = __toESM(require("path"), 1);
|
|
690
1112
|
|
|
691
1113
|
// src/ai/index.ts
|
|
692
1114
|
var import_ai = require("ai");
|
|
@@ -718,8 +1140,8 @@ var CLARIFICATION_TIMEOUT = Number(process.env.CLARIFICATION_TIMEOUT ?? 3e5);
|
|
|
718
1140
|
var CLARIFICATION_ENABLED = process.env.CLARIFICATION_ENABLED !== "false";
|
|
719
1141
|
|
|
720
1142
|
// src/prompt/system.ts
|
|
721
|
-
var
|
|
722
|
-
var
|
|
1143
|
+
var import_fs4 = __toESM(require("fs"), 1);
|
|
1144
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
723
1145
|
var DEFAULT_PROMPT = `
|
|
724
1146
|
You are Pulse Coder, the best coding agent on the planet.
|
|
725
1147
|
|
|
@@ -855,13 +1277,13 @@ var AGENTS_FILE_REGEX = /^agents\.md$/i;
|
|
|
855
1277
|
var loadAgentsPrompt = () => {
|
|
856
1278
|
try {
|
|
857
1279
|
const cwd = process.cwd();
|
|
858
|
-
const entries =
|
|
1280
|
+
const entries = import_fs4.default.readdirSync(cwd, { withFileTypes: true });
|
|
859
1281
|
const target = entries.find((entry) => entry.isFile() && AGENTS_FILE_REGEX.test(entry.name));
|
|
860
1282
|
if (!target) {
|
|
861
1283
|
return null;
|
|
862
1284
|
}
|
|
863
|
-
const filePath =
|
|
864
|
-
const content =
|
|
1285
|
+
const filePath = import_path2.default.join(cwd, target.name);
|
|
1286
|
+
const content = import_fs4.default.readFileSync(filePath, "utf8").trim();
|
|
865
1287
|
return content.length > 0 ? content : null;
|
|
866
1288
|
} catch {
|
|
867
1289
|
return null;
|
|
@@ -1047,15 +1469,28 @@ var maybeCompactContext = async (context, options) => {
|
|
|
1047
1469
|
};
|
|
1048
1470
|
|
|
1049
1471
|
// src/core/loop.ts
|
|
1050
|
-
function
|
|
1472
|
+
function wrapToolsWithHooks(tools, beforeHooks, afterHooks) {
|
|
1051
1473
|
const wrapped = {};
|
|
1052
1474
|
for (const [name, t] of Object.entries(tools)) {
|
|
1053
1475
|
wrapped[name] = {
|
|
1054
1476
|
...t,
|
|
1055
1477
|
execute: async (input, ctx) => {
|
|
1056
|
-
|
|
1478
|
+
let finalInput = input;
|
|
1479
|
+
for (const hook of beforeHooks) {
|
|
1480
|
+
const result = await hook({ name, input: finalInput });
|
|
1481
|
+
if (result && "input" in result) {
|
|
1482
|
+
finalInput = result.input;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1057
1485
|
const output = await t.execute(finalInput, ctx);
|
|
1058
|
-
|
|
1486
|
+
let finalOutput = output;
|
|
1487
|
+
for (const hook of afterHooks) {
|
|
1488
|
+
const result = await hook({ name, input: finalInput, output: finalOutput });
|
|
1489
|
+
if (result && "output" in result) {
|
|
1490
|
+
finalOutput = result.output;
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
return finalOutput;
|
|
1059
1494
|
}
|
|
1060
1495
|
};
|
|
1061
1496
|
}
|
|
@@ -1065,6 +1500,7 @@ async function loop(context, options) {
|
|
|
1065
1500
|
let errorCount = 0;
|
|
1066
1501
|
let totalSteps = 0;
|
|
1067
1502
|
let compactionAttempts = 0;
|
|
1503
|
+
const loopHooks = options?.hooks ?? {};
|
|
1068
1504
|
while (true) {
|
|
1069
1505
|
try {
|
|
1070
1506
|
if (compactionAttempts < MAX_COMPACTION_ATTEMPTS) {
|
|
@@ -1081,8 +1517,24 @@ async function loop(context, options) {
|
|
|
1081
1517
|
}
|
|
1082
1518
|
}
|
|
1083
1519
|
let tools = options?.tools || {};
|
|
1084
|
-
|
|
1085
|
-
|
|
1520
|
+
let systemPrompt = options?.systemPrompt;
|
|
1521
|
+
if (loopHooks.beforeLLMCall?.length) {
|
|
1522
|
+
for (const hook of loopHooks.beforeLLMCall) {
|
|
1523
|
+
const result2 = await hook({ context, systemPrompt, tools });
|
|
1524
|
+
if (result2) {
|
|
1525
|
+
if ("systemPrompt" in result2 && result2.systemPrompt !== void 0) {
|
|
1526
|
+
systemPrompt = result2.systemPrompt;
|
|
1527
|
+
}
|
|
1528
|
+
if ("tools" in result2 && result2.tools !== void 0) {
|
|
1529
|
+
tools = result2.tools;
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
const beforeToolHooks = loopHooks.beforeToolCall ?? [];
|
|
1535
|
+
const afterToolHooks = loopHooks.afterToolCall ?? [];
|
|
1536
|
+
if (beforeToolHooks.length || afterToolHooks.length) {
|
|
1537
|
+
tools = wrapToolsWithHooks(tools, beforeToolHooks, afterToolHooks);
|
|
1086
1538
|
}
|
|
1087
1539
|
const toolExecutionContext = {
|
|
1088
1540
|
onClarificationRequest: options?.onClarificationRequest,
|
|
@@ -1093,7 +1545,7 @@ async function loop(context, options) {
|
|
|
1093
1545
|
toolExecutionContext,
|
|
1094
1546
|
provider: options?.provider,
|
|
1095
1547
|
model: options?.model,
|
|
1096
|
-
systemPrompt
|
|
1548
|
+
systemPrompt,
|
|
1097
1549
|
onStepFinish: (step) => {
|
|
1098
1550
|
options?.onStepFinish?.(step);
|
|
1099
1551
|
},
|
|
@@ -1121,6 +1573,11 @@ async function loop(context, options) {
|
|
|
1121
1573
|
options?.onResponse?.(messages);
|
|
1122
1574
|
}
|
|
1123
1575
|
}
|
|
1576
|
+
if (loopHooks.afterLLMCall?.length) {
|
|
1577
|
+
for (const hook of loopHooks.afterLLMCall) {
|
|
1578
|
+
await hook({ context, finishReason, text });
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1124
1581
|
if (finishReason === "stop") {
|
|
1125
1582
|
return text || "Task completed.";
|
|
1126
1583
|
}
|
|
@@ -1180,8 +1637,8 @@ function sleep(ms) {
|
|
|
1180
1637
|
}
|
|
1181
1638
|
|
|
1182
1639
|
// src/tools/read.ts
|
|
1183
|
-
var
|
|
1184
|
-
var
|
|
1640
|
+
var import_zod3 = __toESM(require("zod"), 1);
|
|
1641
|
+
var import_fs5 = require("fs");
|
|
1185
1642
|
|
|
1186
1643
|
// src/tools/utils.ts
|
|
1187
1644
|
var truncateOutput = (output) => {
|
|
@@ -1201,20 +1658,20 @@ var truncateOutput = (output) => {
|
|
|
1201
1658
|
var ReadTool = {
|
|
1202
1659
|
name: "read",
|
|
1203
1660
|
description: "Read the contents of a file. Supports reading specific line ranges with offset and limit.",
|
|
1204
|
-
inputSchema:
|
|
1205
|
-
filePath:
|
|
1206
|
-
offset:
|
|
1207
|
-
limit:
|
|
1661
|
+
inputSchema: import_zod3.default.object({
|
|
1662
|
+
filePath: import_zod3.default.string().describe("The absolute path to the file to read"),
|
|
1663
|
+
offset: import_zod3.default.number().optional().describe("The line number to start reading from (0-based). Only provide if the file is too large to read at once."),
|
|
1664
|
+
limit: import_zod3.default.number().optional().describe("The number of lines to read. Only provide if the file is too large to read at once.")
|
|
1208
1665
|
}),
|
|
1209
1666
|
execute: async ({ filePath, offset, limit }) => {
|
|
1210
|
-
if (!(0,
|
|
1667
|
+
if (!(0, import_fs5.existsSync)(filePath)) {
|
|
1211
1668
|
throw new Error(`File does not exist: ${filePath}`);
|
|
1212
1669
|
}
|
|
1213
|
-
const stats = (0,
|
|
1670
|
+
const stats = (0, import_fs5.statSync)(filePath);
|
|
1214
1671
|
if (stats.isDirectory()) {
|
|
1215
1672
|
throw new Error(`Cannot read directory: ${filePath}. Use 'ls' tool to list directory contents.`);
|
|
1216
1673
|
}
|
|
1217
|
-
const content = (0,
|
|
1674
|
+
const content = (0, import_fs5.readFileSync)(filePath, "utf-8");
|
|
1218
1675
|
const lines = content.split("\n");
|
|
1219
1676
|
const totalLines = lines.length;
|
|
1220
1677
|
if (offset === void 0 && limit === void 0) {
|
|
@@ -1241,23 +1698,23 @@ var ReadTool = {
|
|
|
1241
1698
|
};
|
|
1242
1699
|
|
|
1243
1700
|
// src/tools/write.ts
|
|
1244
|
-
var
|
|
1245
|
-
var
|
|
1246
|
-
var
|
|
1701
|
+
var import_zod4 = __toESM(require("zod"), 1);
|
|
1702
|
+
var import_fs6 = require("fs");
|
|
1703
|
+
var import_path3 = require("path");
|
|
1247
1704
|
var WriteTool = {
|
|
1248
1705
|
name: "write",
|
|
1249
1706
|
description: "Write contents to a file. Automatically creates parent directories if they do not exist. Will overwrite existing files.",
|
|
1250
|
-
inputSchema:
|
|
1251
|
-
filePath:
|
|
1252
|
-
content:
|
|
1707
|
+
inputSchema: import_zod4.default.object({
|
|
1708
|
+
filePath: import_zod4.default.string().describe("The absolute path to the file to write (must be absolute, not relative)"),
|
|
1709
|
+
content: import_zod4.default.string().describe("The content to write to the file")
|
|
1253
1710
|
}),
|
|
1254
1711
|
execute: async ({ filePath, content }) => {
|
|
1255
|
-
const fileExists = (0,
|
|
1256
|
-
const dir = (0,
|
|
1257
|
-
if (!(0,
|
|
1258
|
-
(0,
|
|
1712
|
+
const fileExists = (0, import_fs6.existsSync)(filePath);
|
|
1713
|
+
const dir = (0, import_path3.dirname)(filePath);
|
|
1714
|
+
if (!(0, import_fs6.existsSync)(dir)) {
|
|
1715
|
+
(0, import_fs6.mkdirSync)(dir, { recursive: true });
|
|
1259
1716
|
}
|
|
1260
|
-
(0,
|
|
1717
|
+
(0, import_fs6.writeFileSync)(filePath, content, "utf-8");
|
|
1261
1718
|
const bytes = Buffer.byteLength(content, "utf-8");
|
|
1262
1719
|
return {
|
|
1263
1720
|
success: true,
|
|
@@ -1268,22 +1725,22 @@ var WriteTool = {
|
|
|
1268
1725
|
};
|
|
1269
1726
|
|
|
1270
1727
|
// src/tools/edit.ts
|
|
1271
|
-
var
|
|
1272
|
-
var
|
|
1728
|
+
var import_zod5 = __toESM(require("zod"), 1);
|
|
1729
|
+
var import_fs7 = require("fs");
|
|
1273
1730
|
var EditTool = {
|
|
1274
1731
|
name: "edit",
|
|
1275
1732
|
description: "Performs exact string replacements in files. Use this to edit existing files by replacing old_string with new_string.",
|
|
1276
|
-
inputSchema:
|
|
1277
|
-
filePath:
|
|
1278
|
-
oldString:
|
|
1279
|
-
newString:
|
|
1280
|
-
replaceAll:
|
|
1733
|
+
inputSchema: import_zod5.default.object({
|
|
1734
|
+
filePath: import_zod5.default.string().describe("The absolute path to the file to modify"),
|
|
1735
|
+
oldString: import_zod5.default.string().describe("The exact text to replace (must match exactly)"),
|
|
1736
|
+
newString: import_zod5.default.string().describe("The text to replace it with (must be different from old_string)"),
|
|
1737
|
+
replaceAll: import_zod5.default.boolean().optional().default(false).describe("Replace all occurrences of old_string (default false)")
|
|
1281
1738
|
}),
|
|
1282
1739
|
execute: async ({ filePath, oldString, newString, replaceAll = false }) => {
|
|
1283
1740
|
if (oldString === newString) {
|
|
1284
1741
|
throw new Error("old_string and new_string must be different");
|
|
1285
1742
|
}
|
|
1286
|
-
const content = (0,
|
|
1743
|
+
const content = (0, import_fs7.readFileSync)(filePath, "utf-8");
|
|
1287
1744
|
if (!content.includes(oldString)) {
|
|
1288
1745
|
throw new Error(`old_string not found in file: ${filePath}`);
|
|
1289
1746
|
}
|
|
@@ -1307,7 +1764,7 @@ var EditTool = {
|
|
|
1307
1764
|
newContent = content.slice(0, index) + newString + content.slice(index + oldString.length);
|
|
1308
1765
|
replacements = 1;
|
|
1309
1766
|
}
|
|
1310
|
-
(0,
|
|
1767
|
+
(0, import_fs7.writeFileSync)(filePath, newContent, "utf-8");
|
|
1311
1768
|
const changedIndex = newContent.indexOf(newString);
|
|
1312
1769
|
const contextLength = 200;
|
|
1313
1770
|
const start = Math.max(0, changedIndex - contextLength);
|
|
@@ -1324,27 +1781,27 @@ var EditTool = {
|
|
|
1324
1781
|
};
|
|
1325
1782
|
|
|
1326
1783
|
// src/tools/grep.ts
|
|
1327
|
-
var
|
|
1784
|
+
var import_zod6 = __toESM(require("zod"), 1);
|
|
1328
1785
|
var import_child_process = require("child_process");
|
|
1329
|
-
var
|
|
1786
|
+
var import_fs8 = require("fs");
|
|
1330
1787
|
var GrepTool = {
|
|
1331
1788
|
name: "grep",
|
|
1332
1789
|
description: "A powerful search tool built on ripgrep. Supports regex patterns, file filtering, and multiple output modes.",
|
|
1333
|
-
inputSchema:
|
|
1334
|
-
pattern:
|
|
1335
|
-
path:
|
|
1336
|
-
glob:
|
|
1337
|
-
type:
|
|
1338
|
-
outputMode:
|
|
1339
|
-
context:
|
|
1340
|
-
caseInsensitive:
|
|
1341
|
-
headLimit:
|
|
1342
|
-
offset:
|
|
1343
|
-
multiline:
|
|
1790
|
+
inputSchema: import_zod6.default.object({
|
|
1791
|
+
pattern: import_zod6.default.string().describe("The regular expression pattern to search for in file contents"),
|
|
1792
|
+
path: import_zod6.default.string().optional().describe("File or directory to search in. Defaults to current working directory."),
|
|
1793
|
+
glob: import_zod6.default.string().optional().describe('Glob pattern to filter files (e.g. "*.js", "*.{ts,tsx}")'),
|
|
1794
|
+
type: import_zod6.default.string().optional().describe("File type to search (e.g., js, py, rust, go, java, ts, tsx, json, md)"),
|
|
1795
|
+
outputMode: import_zod6.default.enum(["content", "files_with_matches", "count"]).optional().default("files_with_matches").describe('Output mode: "content" shows matching lines, "files_with_matches" shows file paths, "count" shows match counts'),
|
|
1796
|
+
context: import_zod6.default.number().optional().describe('Number of lines to show before and after each match (only with output_mode: "content")'),
|
|
1797
|
+
caseInsensitive: import_zod6.default.boolean().optional().default(false).describe("Case insensitive search"),
|
|
1798
|
+
headLimit: import_zod6.default.number().optional().default(0).describe("Limit output to first N lines/entries. 0 means unlimited."),
|
|
1799
|
+
offset: import_zod6.default.number().optional().default(0).describe("Skip first N lines/entries before applying head_limit"),
|
|
1800
|
+
multiline: import_zod6.default.boolean().optional().default(false).describe("Enable multiline mode where patterns can span lines")
|
|
1344
1801
|
}),
|
|
1345
1802
|
execute: async ({
|
|
1346
1803
|
pattern,
|
|
1347
|
-
path:
|
|
1804
|
+
path: path5 = ".",
|
|
1348
1805
|
glob,
|
|
1349
1806
|
type,
|
|
1350
1807
|
outputMode = "files_with_matches",
|
|
@@ -1379,11 +1836,11 @@ var GrepTool = {
|
|
|
1379
1836
|
if (type) {
|
|
1380
1837
|
args.push("--type", type);
|
|
1381
1838
|
}
|
|
1382
|
-
if (
|
|
1383
|
-
if (!(0,
|
|
1384
|
-
throw new Error(`Path does not exist: ${
|
|
1839
|
+
if (path5 && path5 !== ".") {
|
|
1840
|
+
if (!(0, import_fs8.existsSync)(path5)) {
|
|
1841
|
+
throw new Error(`Path does not exist: ${path5}`);
|
|
1385
1842
|
}
|
|
1386
|
-
args.push(
|
|
1843
|
+
args.push(path5);
|
|
1387
1844
|
}
|
|
1388
1845
|
let command = args.map((arg) => {
|
|
1389
1846
|
if (arg.includes(" ") || arg.includes("$") || arg.includes("*")) {
|
|
@@ -1430,31 +1887,31 @@ Command: ${command}`
|
|
|
1430
1887
|
};
|
|
1431
1888
|
|
|
1432
1889
|
// src/tools/ls.ts
|
|
1433
|
-
var
|
|
1434
|
-
var
|
|
1890
|
+
var import_zod7 = __toESM(require("zod"), 1);
|
|
1891
|
+
var import_fs9 = require("fs");
|
|
1435
1892
|
var LsTool = {
|
|
1436
1893
|
name: "ls",
|
|
1437
1894
|
description: "List files and directories in a given path",
|
|
1438
|
-
inputSchema:
|
|
1439
|
-
path:
|
|
1895
|
+
inputSchema: import_zod7.default.object({
|
|
1896
|
+
path: import_zod7.default.string().optional().describe("The path to list files from (defaults to current directory)")
|
|
1440
1897
|
}),
|
|
1441
|
-
execute: async ({ path:
|
|
1442
|
-
const files = (0,
|
|
1898
|
+
execute: async ({ path: path5 = "." }) => {
|
|
1899
|
+
const files = (0, import_fs9.readdirSync)(path5);
|
|
1443
1900
|
return { files };
|
|
1444
1901
|
}
|
|
1445
1902
|
};
|
|
1446
1903
|
|
|
1447
1904
|
// src/tools/bash.ts
|
|
1448
|
-
var
|
|
1905
|
+
var import_zod8 = __toESM(require("zod"), 1);
|
|
1449
1906
|
var import_child_process2 = require("child_process");
|
|
1450
1907
|
var BashTool = {
|
|
1451
1908
|
name: "bash",
|
|
1452
1909
|
description: "Execute a bash command and return the output. Supports timeout and working directory configuration.",
|
|
1453
|
-
inputSchema:
|
|
1454
|
-
command:
|
|
1455
|
-
timeout:
|
|
1456
|
-
cwd:
|
|
1457
|
-
description:
|
|
1910
|
+
inputSchema: import_zod8.default.object({
|
|
1911
|
+
command: import_zod8.default.string().describe("The bash command to execute"),
|
|
1912
|
+
timeout: import_zod8.default.number().optional().describe("Optional timeout in milliseconds (max 600000ms / 10 minutes). Defaults to 120000ms (2 minutes)."),
|
|
1913
|
+
cwd: import_zod8.default.string().optional().describe("Optional working directory for command execution. Defaults to current directory."),
|
|
1914
|
+
description: import_zod8.default.string().optional().describe("Optional description of what this command does (for logging/debugging)")
|
|
1458
1915
|
}),
|
|
1459
1916
|
execute: async ({ command, timeout = 12e4, cwd, description }) => {
|
|
1460
1917
|
if (timeout && (timeout < 0 || timeout > 6e5)) {
|
|
@@ -1495,13 +1952,13 @@ ${stderr}`),
|
|
|
1495
1952
|
};
|
|
1496
1953
|
|
|
1497
1954
|
// src/tools/tavily.ts
|
|
1498
|
-
var
|
|
1955
|
+
var import_zod9 = __toESM(require("zod"), 1);
|
|
1499
1956
|
var TavilyTool = {
|
|
1500
1957
|
name: "tavily",
|
|
1501
1958
|
description: "Search the web using Tavily API",
|
|
1502
|
-
inputSchema:
|
|
1503
|
-
query:
|
|
1504
|
-
maxResults:
|
|
1959
|
+
inputSchema: import_zod9.default.object({
|
|
1960
|
+
query: import_zod9.default.string().describe("The search query"),
|
|
1961
|
+
maxResults: import_zod9.default.number().optional().default(5).describe("Maximum number of results to return")
|
|
1505
1962
|
}),
|
|
1506
1963
|
execute: async ({ query, maxResults = 5 }) => {
|
|
1507
1964
|
const apiKey = process.env.TAVILY_API_KEY;
|
|
@@ -1539,23 +1996,23 @@ var TavilyTool = {
|
|
|
1539
1996
|
};
|
|
1540
1997
|
|
|
1541
1998
|
// src/tools/clarify.ts
|
|
1542
|
-
var
|
|
1543
|
-
var
|
|
1999
|
+
var import_zod10 = __toESM(require("zod"), 1);
|
|
2000
|
+
var import_crypto2 = require("crypto");
|
|
1544
2001
|
var ClarifyTool = {
|
|
1545
2002
|
name: "clarify",
|
|
1546
2003
|
description: "Ask the user a clarifying question and wait for their response. Use this when you need information from the user to proceed with the task.",
|
|
1547
|
-
inputSchema:
|
|
1548
|
-
question:
|
|
1549
|
-
context:
|
|
1550
|
-
defaultAnswer:
|
|
1551
|
-
timeout:
|
|
2004
|
+
inputSchema: import_zod10.default.object({
|
|
2005
|
+
question: import_zod10.default.string().describe("The question to ask the user"),
|
|
2006
|
+
context: import_zod10.default.string().optional().describe("Additional context to help the user answer"),
|
|
2007
|
+
defaultAnswer: import_zod10.default.string().optional().describe("Default answer if user does not respond within timeout"),
|
|
2008
|
+
timeout: import_zod10.default.number().optional().describe("Timeout in milliseconds (default: 5 minutes)")
|
|
1552
2009
|
}),
|
|
1553
2010
|
execute: async (input, toolContext) => {
|
|
1554
2011
|
if (!toolContext?.onClarificationRequest) {
|
|
1555
2012
|
throw new Error("Clarification is not supported in this context. The clarify tool requires a CLI interface with user interaction.");
|
|
1556
2013
|
}
|
|
1557
2014
|
const timeout = input.timeout ?? CLARIFICATION_TIMEOUT;
|
|
1558
|
-
const requestId = (0,
|
|
2015
|
+
const requestId = (0, import_crypto2.randomUUID)();
|
|
1559
2016
|
try {
|
|
1560
2017
|
const timeoutPromise = new Promise((_, reject) => {
|
|
1561
2018
|
setTimeout(() => {
|
|
@@ -1610,8 +2067,8 @@ var ConfigLoader = class {
|
|
|
1610
2067
|
const fileInfos = [];
|
|
1611
2068
|
for (let configDir of configDirs) {
|
|
1612
2069
|
try {
|
|
1613
|
-
await
|
|
1614
|
-
const files = await
|
|
2070
|
+
await import_fs10.promises.access(configDir);
|
|
2071
|
+
const files = await import_fs10.promises.readdir(configDir);
|
|
1615
2072
|
fileInfos.push({ files, configDir });
|
|
1616
2073
|
} catch {
|
|
1617
2074
|
continue;
|
|
@@ -1628,7 +2085,7 @@ var ConfigLoader = class {
|
|
|
1628
2085
|
const files = fileInfo.files;
|
|
1629
2086
|
for (const file of files) {
|
|
1630
2087
|
if (file.endsWith(".md")) {
|
|
1631
|
-
const config = await this.parseConfig(
|
|
2088
|
+
const config = await this.parseConfig(import_path4.default.join(fileInfo.configDir, file));
|
|
1632
2089
|
if (config) configs.push(config);
|
|
1633
2090
|
}
|
|
1634
2091
|
}
|
|
@@ -1640,7 +2097,7 @@ var ConfigLoader = class {
|
|
|
1640
2097
|
}
|
|
1641
2098
|
async parseConfig(filePath) {
|
|
1642
2099
|
try {
|
|
1643
|
-
const content = await
|
|
2100
|
+
const content = await import_fs10.promises.readFile(filePath, "utf-8");
|
|
1644
2101
|
const lines = content.split("\n");
|
|
1645
2102
|
let name = "";
|
|
1646
2103
|
let description = "";
|
|
@@ -1669,7 +2126,7 @@ var ConfigLoader = class {
|
|
|
1669
2126
|
}
|
|
1670
2127
|
}
|
|
1671
2128
|
if (!name) {
|
|
1672
|
-
name =
|
|
2129
|
+
name = import_path4.default.basename(filePath, ".md");
|
|
1673
2130
|
}
|
|
1674
2131
|
return {
|
|
1675
2132
|
name: name.trim(),
|
|
@@ -1720,9 +2177,9 @@ var SubAgentPlugin = class {
|
|
|
1720
2177
|
const toolName = `${config.name}_agent`;
|
|
1721
2178
|
const tool2 = {
|
|
1722
2179
|
description: config.description,
|
|
1723
|
-
inputSchema:
|
|
1724
|
-
task:
|
|
1725
|
-
context:
|
|
2180
|
+
inputSchema: import_zod11.z.object({
|
|
2181
|
+
task: import_zod11.z.string().describe("\u8981\u6267\u884C\u7684\u4EFB\u52A1\u63CF\u8FF0"),
|
|
2182
|
+
context: import_zod11.z.any().optional().describe("\u4EFB\u52A1\u4E0A\u4E0B\u6587\u4FE1\u606F")
|
|
1726
2183
|
}),
|
|
1727
2184
|
execute: async ({ task, context: taskContext }) => {
|
|
1728
2185
|
const tools = { ...BuiltinToolsMap, ...context.getTools() };
|
|
@@ -1749,6 +2206,7 @@ var builtInPlugins = [
|
|
|
1749
2206
|
builtInMCPPlugin,
|
|
1750
2207
|
builtInSkillsPlugin,
|
|
1751
2208
|
builtInPlanModePlugin,
|
|
2209
|
+
builtInTaskTrackingPlugin,
|
|
1752
2210
|
new SubAgentPlugin()
|
|
1753
2211
|
];
|
|
1754
2212
|
var built_in_default = builtInPlugins;
|
|
@@ -1757,9 +2215,11 @@ var built_in_default = builtInPlugins;
|
|
|
1757
2215
|
BuiltInPlanModeService,
|
|
1758
2216
|
BuiltInSkillRegistry,
|
|
1759
2217
|
SubAgentPlugin,
|
|
2218
|
+
TaskListService,
|
|
1760
2219
|
builtInMCPPlugin,
|
|
1761
2220
|
builtInPlanModePlugin,
|
|
1762
2221
|
builtInPlugins,
|
|
1763
|
-
builtInSkillsPlugin
|
|
2222
|
+
builtInSkillsPlugin,
|
|
2223
|
+
builtInTaskTrackingPlugin
|
|
1764
2224
|
});
|
|
1765
2225
|
//# sourceMappingURL=index.cjs.map
|