pulse-coder-engine 0.0.1-alpha.11 → 0.0.1-alpha.13

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/index.cjs CHANGED
@@ -43,12 +43,14 @@ __export(src_exports, {
43
43
  PluginManager: () => PluginManager,
44
44
  PulseAgent: () => Engine,
45
45
  ReadTool: () => ReadTool,
46
+ TaskListService: () => TaskListService,
46
47
  TavilyTool: () => TavilyTool,
47
48
  WriteTool: () => WriteTool,
48
49
  builtInMCPPlugin: () => builtInMCPPlugin,
49
50
  builtInPlanModePlugin: () => builtInPlanModePlugin,
50
51
  builtInPlugins: () => builtInPlugins,
51
52
  builtInSkillsPlugin: () => builtInSkillsPlugin,
53
+ builtInTaskTrackingPlugin: () => builtInTaskTrackingPlugin,
52
54
  getFinalToolsMap: () => getFinalToolsMap,
53
55
  loop: () => loop,
54
56
  maybeCompactContext: () => maybeCompactContext,
@@ -525,6 +527,9 @@ async function loop(context, options) {
525
527
  }
526
528
  }
527
529
  if (finishReason === "stop") {
530
+ if (!text) {
531
+ continue;
532
+ }
528
533
  return text || "Task completed.";
529
534
  }
530
535
  if (finishReason === "length") {
@@ -556,6 +561,9 @@ async function loop(context, options) {
556
561
  }
557
562
  continue;
558
563
  }
564
+ if (!text) {
565
+ continue;
566
+ }
559
567
  return text || "Task completed.";
560
568
  } catch (error) {
561
569
  if (options?.abortSignal?.aborted || error?.name === "AbortError") {
@@ -747,7 +755,7 @@ var GrepTool = {
747
755
  }),
748
756
  execute: async ({
749
757
  pattern,
750
- path: path5 = ".",
758
+ path: path6 = ".",
751
759
  glob: glob2,
752
760
  type,
753
761
  outputMode = "files_with_matches",
@@ -782,11 +790,11 @@ var GrepTool = {
782
790
  if (type) {
783
791
  args.push("--type", type);
784
792
  }
785
- if (path5 && path5 !== ".") {
786
- if (!(0, import_fs5.existsSync)(path5)) {
787
- throw new Error(`Path does not exist: ${path5}`);
793
+ if (path6 && path6 !== ".") {
794
+ if (!(0, import_fs5.existsSync)(path6)) {
795
+ throw new Error(`Path does not exist: ${path6}`);
788
796
  }
789
- args.push(path5);
797
+ args.push(path6);
790
798
  }
791
799
  let command = args.map((arg) => {
792
800
  if (arg.includes(" ") || arg.includes("$") || arg.includes("*")) {
@@ -841,8 +849,8 @@ var LsTool = {
841
849
  inputSchema: import_zod5.default.object({
842
850
  path: import_zod5.default.string().optional().describe("The path to list files from (defaults to current directory)")
843
851
  }),
844
- execute: async ({ path: path5 = "." }) => {
845
- const files = (0, import_fs6.readdirSync)(path5);
852
+ execute: async ({ path: path6 = "." }) => {
853
+ const files = (0, import_fs6.readdirSync)(path6);
846
854
  return { files };
847
855
  }
848
856
  };
@@ -1614,16 +1622,44 @@ var BuiltInSkillRegistry = class {
1614
1622
  return Array.from(this.skills.values());
1615
1623
  }
1616
1624
  /**
1617
- * 根据名称获取技能
1625
+ * 注册或更新一个技能(支持插件在运行期追加技能)
1626
+ */
1627
+ registerSkill(skill) {
1628
+ const name = skill.name?.trim();
1629
+ if (!name) {
1630
+ throw new Error("Skill name is required");
1631
+ }
1632
+ const existingKey = Array.from(this.skills.keys()).find((key) => key.toLowerCase() === name.toLowerCase());
1633
+ const replaced = existingKey !== void 0;
1634
+ if (existingKey && existingKey !== name) {
1635
+ this.skills.delete(existingKey);
1636
+ }
1637
+ this.skills.set(name, {
1638
+ ...skill,
1639
+ name
1640
+ });
1641
+ return {
1642
+ skillName: name,
1643
+ replaced,
1644
+ total: this.skills.size
1645
+ };
1646
+ }
1647
+ /**
1648
+ * 根据名称获取技能(大小写不敏感)
1618
1649
  */
1619
1650
  get(name) {
1620
- return this.skills.get(name);
1651
+ const exact = this.skills.get(name);
1652
+ if (exact) {
1653
+ return exact;
1654
+ }
1655
+ const target = name.toLowerCase();
1656
+ return this.getAll().find((skill) => skill.name.toLowerCase() === target);
1621
1657
  }
1622
1658
  /**
1623
1659
  * 检查技能是否存在
1624
1660
  */
1625
1661
  has(name) {
1626
- return this.skills.has(name);
1662
+ return !!this.get(name);
1627
1663
  }
1628
1664
  /**
1629
1665
  * 搜索技能(模糊匹配)
@@ -1638,7 +1674,7 @@ var BuiltInSkillRegistry = class {
1638
1674
  var skillToolSchema = import_zod10.z.object({
1639
1675
  name: import_zod10.z.string().describe("The name of the skill to execute")
1640
1676
  });
1641
- function generateSkillTool(skills) {
1677
+ function generateSkillTool(registry) {
1642
1678
  const getSkillsPrompt = (availableSkills) => {
1643
1679
  return [
1644
1680
  "If query matches an available skill's description or instruction [use skill], use the skill tool to get detailed instructions.",
@@ -1659,10 +1695,10 @@ function generateSkillTool(skills) {
1659
1695
  };
1660
1696
  return {
1661
1697
  name: "skill",
1662
- description: getSkillsPrompt(skills),
1698
+ description: getSkillsPrompt(registry.getAll()),
1663
1699
  inputSchema: skillToolSchema,
1664
1700
  execute: async ({ name }) => {
1665
- const skill = skills.find((skill2) => skill2.name === name);
1701
+ const skill = registry.get(name);
1666
1702
  if (!skill) {
1667
1703
  throw new Error(`Skill ${name} not found`);
1668
1704
  }
@@ -1676,14 +1712,21 @@ var builtInSkillsPlugin = {
1676
1712
  async initialize(context) {
1677
1713
  const registry = new BuiltInSkillRegistry();
1678
1714
  await registry.initialize(process.cwd());
1715
+ context.registerService("skillRegistry", registry);
1716
+ context.registerTool("skill", generateSkillTool(registry));
1717
+ context.registerHook("beforeRun", ({ tools }) => {
1718
+ return {
1719
+ tools: {
1720
+ ...tools,
1721
+ skill: generateSkillTool(registry)
1722
+ }
1723
+ };
1724
+ });
1679
1725
  const skills = registry.getAll();
1680
1726
  if (skills.length === 0) {
1681
1727
  console.log("[Skills] No skills found");
1682
1728
  return;
1683
1729
  }
1684
- const skillTool = generateSkillTool(skills);
1685
- context.registerTool("skill", skillTool);
1686
- context.registerService("skillRegistry", registry);
1687
1730
  console.log(`[Skills] Registered ${skills.length} skill(s)`);
1688
1731
  }
1689
1732
  };
@@ -1794,6 +1837,26 @@ var KNOWN_TOOL_META = {
1794
1837
  category: "other",
1795
1838
  risk: "low",
1796
1839
  description: "Ask the user a targeted clarification question."
1840
+ },
1841
+ task_create: {
1842
+ category: "other",
1843
+ risk: "low",
1844
+ description: "Create tracked task entries for planning and execution visibility."
1845
+ },
1846
+ task_get: {
1847
+ category: "other",
1848
+ risk: "low",
1849
+ description: "Inspect a task entry by ID."
1850
+ },
1851
+ task_list: {
1852
+ category: "other",
1853
+ risk: "low",
1854
+ description: "List task tracking entries and status summary."
1855
+ },
1856
+ task_update: {
1857
+ category: "other",
1858
+ risk: "low",
1859
+ description: "Update task tracking fields and status."
1797
1860
  }
1798
1861
  };
1799
1862
  var BuiltInPlanModeService = class {
@@ -2073,17 +2136,404 @@ var builtInPlanModePlugin = {
2073
2136
  }
2074
2137
  };
2075
2138
 
2076
- // src/built-in/sub-agent-plugin/index.ts
2077
- var import_zod11 = require("zod");
2139
+ // src/built-in/task-tracking-plugin/index.ts
2078
2140
  var import_fs10 = require("fs");
2079
2141
  var import_path4 = __toESM(require("path"), 1);
2142
+ var import_os2 = require("os");
2143
+ var import_crypto2 = require("crypto");
2144
+ var import_zod11 = require("zod");
2145
+ var TASK_STATUSES = ["pending", "in_progress", "completed", "blocked"];
2146
+ var CREATE_TASK_ITEM_SCHEMA = import_zod11.z.object({
2147
+ title: import_zod11.z.string().min(1).describe("Task title"),
2148
+ details: import_zod11.z.string().optional().describe("Task details / acceptance notes"),
2149
+ status: import_zod11.z.enum(TASK_STATUSES).optional().describe("Initial status; defaults to pending"),
2150
+ dependencies: import_zod11.z.array(import_zod11.z.string()).optional().describe("Task IDs that must be completed first"),
2151
+ blockedReason: import_zod11.z.string().optional().describe("Reason when status is blocked"),
2152
+ metadata: import_zod11.z.record(import_zod11.z.string(), import_zod11.z.any()).optional().describe("Additional machine-readable metadata")
2153
+ });
2154
+ var TASK_CREATE_INPUT_SCHEMA = import_zod11.z.object({
2155
+ title: import_zod11.z.string().min(1).optional().describe("Task title (single-task mode)"),
2156
+ details: import_zod11.z.string().optional().describe("Task details (single-task mode)"),
2157
+ status: import_zod11.z.enum(TASK_STATUSES).optional().describe("Initial status (single-task mode)"),
2158
+ dependencies: import_zod11.z.array(import_zod11.z.string()).optional().describe("Dependencies (single-task mode)"),
2159
+ blockedReason: import_zod11.z.string().optional().describe("Blocked reason (single-task mode)"),
2160
+ metadata: import_zod11.z.record(import_zod11.z.string(), import_zod11.z.any()).optional().describe("Metadata (single-task mode)"),
2161
+ tasks: import_zod11.z.array(CREATE_TASK_ITEM_SCHEMA).min(1).optional().describe("Batch create mode")
2162
+ }).refine((value) => !!value.tasks?.length || !!value.title, {
2163
+ message: "Either provide `tasks` or `title` for single-task mode."
2164
+ });
2165
+ var TASK_GET_INPUT_SCHEMA = import_zod11.z.object({
2166
+ id: import_zod11.z.string().min(1).describe("Task ID to retrieve")
2167
+ });
2168
+ var TASK_LIST_INPUT_SCHEMA = import_zod11.z.object({
2169
+ statuses: import_zod11.z.array(import_zod11.z.enum(TASK_STATUSES)).optional().describe("Filter by statuses"),
2170
+ includeCompleted: import_zod11.z.boolean().optional().describe("Set false to hide completed tasks"),
2171
+ limit: import_zod11.z.number().int().positive().max(500).optional().describe("Maximum tasks to return")
2172
+ });
2173
+ var TASK_TRACKING_SKILL = {
2174
+ name: "task-tracking-workflow",
2175
+ description: "Track complex execution with task tools and proceed directly without confirmation unless the user explicitly asks for confirmation.",
2176
+ location: "pulse-coder-engine/built-in/task-tracking-plugin",
2177
+ content: `# Task Tracking Workflow
2178
+
2179
+ ## When to use
2180
+ - The request has multiple phases or deliverables.
2181
+ - Work may span multiple tool calls or sessions.
2182
+ - You need explicit progress visibility and blocker management.
2183
+
2184
+ ## Execution autonomy
2185
+ - Default behavior: execute directly and call tools without asking for confirmation.
2186
+ - Only ask for confirmation when the user explicitly requires confirmation.
2187
+ - If critical information is missing, ask only the minimum clarifying question needed to continue.
2188
+
2189
+ ## Required flow
2190
+ 1. Start by reviewing existing tasks with \`task_list\`.
2191
+ 2. If no suitable tasks exist, create focused tasks with \`task_create\` (prefer batch mode).
2192
+ 3. Keep exactly one primary task in \`in_progress\` where possible.
2193
+ 4. Update status with \`task_update\` after meaningful progress.
2194
+ 5. Mark blockers with \`status=blocked\` and a concrete \`blockedReason\`.
2195
+ 6. Mark done tasks as \`completed\` and move to the next actionable item.
2196
+
2197
+ ## Quality rules
2198
+ - Keep tasks atomic and verifiable.
2199
+ - Avoid single oversized umbrella tasks.
2200
+ - Reuse existing in-progress tasks instead of duplicating.
2201
+ - Keep dependency links explicit when order matters.`
2202
+ };
2203
+ var TASK_UPDATE_INPUT_SCHEMA = import_zod11.z.object({
2204
+ id: import_zod11.z.string().min(1).describe("Task ID to update"),
2205
+ title: import_zod11.z.string().min(1).optional().describe("New title"),
2206
+ details: import_zod11.z.string().optional().describe("New details"),
2207
+ status: import_zod11.z.enum(TASK_STATUSES).optional().describe("New status"),
2208
+ dependencies: import_zod11.z.array(import_zod11.z.string()).optional().describe("Replace dependencies with this list"),
2209
+ blockedReason: import_zod11.z.string().optional().describe("Blocked reason, used with status=blocked"),
2210
+ metadata: import_zod11.z.record(import_zod11.z.string(), import_zod11.z.any()).optional().describe("Replace metadata object"),
2211
+ delete: import_zod11.z.boolean().optional().describe("Delete this task")
2212
+ });
2213
+ function normalizeTaskListId(raw) {
2214
+ const trimmed = raw.trim();
2215
+ if (!trimmed) {
2216
+ return "default";
2217
+ }
2218
+ return trimmed.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120) || "default";
2219
+ }
2220
+ function now() {
2221
+ return Date.now();
2222
+ }
2223
+ function dedupeStrings(values) {
2224
+ if (!values?.length) {
2225
+ return [];
2226
+ }
2227
+ return Array.from(new Set(values.map((value) => String(value).trim()).filter(Boolean)));
2228
+ }
2229
+ var TaskListService = class _TaskListService {
2230
+ taskListId;
2231
+ storagePath;
2232
+ storageDir;
2233
+ initialized = false;
2234
+ createdAt = now();
2235
+ updatedAt = now();
2236
+ tasks = /* @__PURE__ */ new Map();
2237
+ constructor(taskListId = _TaskListService.resolveTaskListId(), storageDir = _TaskListService.resolveStorageDir()) {
2238
+ const normalized = normalizeTaskListId(taskListId);
2239
+ this.storageDir = storageDir;
2240
+ this.taskListId = normalized;
2241
+ this.storagePath = import_path4.default.join(this.storageDir, `${normalized}.json`);
2242
+ }
2243
+ static resolveTaskListId() {
2244
+ return process.env.PULSE_CODER_TASK_LIST_ID || process.env.CLAUDE_CODE_TASK_LIST_ID || "default";
2245
+ }
2246
+ static resolveStorageDir() {
2247
+ return process.env.PULSE_CODER_TASKS_DIR || import_path4.default.join((0, import_os2.homedir)(), ".pulse-coder", "tasks");
2248
+ }
2249
+ async initialize() {
2250
+ if (this.initialized) {
2251
+ return;
2252
+ }
2253
+ await this.loadTaskList(this.taskListId);
2254
+ }
2255
+ async setTaskListId(taskListId) {
2256
+ await this.initialize();
2257
+ const normalized = normalizeTaskListId(taskListId);
2258
+ if (normalized === this.taskListId) {
2259
+ return {
2260
+ switched: false,
2261
+ taskListId: this.taskListId,
2262
+ storagePath: this.storagePath
2263
+ };
2264
+ }
2265
+ await this.loadTaskList(normalized);
2266
+ return {
2267
+ switched: true,
2268
+ taskListId: this.taskListId,
2269
+ storagePath: this.storagePath
2270
+ };
2271
+ }
2272
+ async createTask(input) {
2273
+ await this.initialize();
2274
+ const timestamp = now();
2275
+ const status = input.status ?? "pending";
2276
+ const task = {
2277
+ id: (0, import_crypto2.randomUUID)(),
2278
+ title: input.title.trim(),
2279
+ details: input.details,
2280
+ status,
2281
+ dependencies: dedupeStrings(input.dependencies),
2282
+ blockedReason: status === "blocked" ? input.blockedReason ?? "Blocked without reason" : void 0,
2283
+ metadata: input.metadata,
2284
+ createdAt: timestamp,
2285
+ updatedAt: timestamp,
2286
+ completedAt: status === "completed" ? timestamp : void 0
2287
+ };
2288
+ this.tasks.set(task.id, task);
2289
+ this.updatedAt = timestamp;
2290
+ await this.persist();
2291
+ return task;
2292
+ }
2293
+ async createTasks(inputs) {
2294
+ const created = [];
2295
+ for (const input of inputs) {
2296
+ created.push(await this.createTask(input));
2297
+ }
2298
+ return created;
2299
+ }
2300
+ async listTasks(options) {
2301
+ await this.initialize();
2302
+ const statuses = options?.statuses?.length ? new Set(options.statuses) : null;
2303
+ const includeCompleted = options?.includeCompleted ?? true;
2304
+ let tasks = Array.from(this.tasks.values()).filter((task) => {
2305
+ if (!includeCompleted && task.status === "completed") {
2306
+ return false;
2307
+ }
2308
+ if (statuses && !statuses.has(task.status)) {
2309
+ return false;
2310
+ }
2311
+ return true;
2312
+ });
2313
+ tasks = tasks.sort((a, b) => a.createdAt - b.createdAt);
2314
+ if (options?.limit && options.limit > 0) {
2315
+ tasks = tasks.slice(0, options.limit);
2316
+ }
2317
+ return tasks;
2318
+ }
2319
+ async getTask(id) {
2320
+ await this.initialize();
2321
+ return this.tasks.get(id) ?? null;
2322
+ }
2323
+ async updateTask(input) {
2324
+ await this.initialize();
2325
+ if (input.delete) {
2326
+ const deleted = this.tasks.delete(input.id);
2327
+ if (!deleted) {
2328
+ return null;
2329
+ }
2330
+ this.updatedAt = now();
2331
+ await this.persist();
2332
+ return null;
2333
+ }
2334
+ const existing = this.tasks.get(input.id);
2335
+ if (!existing) {
2336
+ return null;
2337
+ }
2338
+ const timestamp = now();
2339
+ const nextStatus = input.status ?? existing.status;
2340
+ const next = {
2341
+ ...existing,
2342
+ title: input.title !== void 0 ? input.title : existing.title,
2343
+ details: input.details !== void 0 ? input.details : existing.details,
2344
+ status: nextStatus,
2345
+ dependencies: input.dependencies !== void 0 ? dedupeStrings(input.dependencies) : existing.dependencies,
2346
+ metadata: input.metadata !== void 0 ? input.metadata : existing.metadata,
2347
+ blockedReason: this.resolveBlockedReason(nextStatus, input.blockedReason, existing.blockedReason),
2348
+ updatedAt: timestamp,
2349
+ completedAt: nextStatus === "completed" ? existing.completedAt ?? timestamp : void 0
2350
+ };
2351
+ this.tasks.set(input.id, next);
2352
+ this.updatedAt = timestamp;
2353
+ await this.persist();
2354
+ return next;
2355
+ }
2356
+ async snapshot(options) {
2357
+ const tasks = await this.listTasks(options);
2358
+ return {
2359
+ taskListId: this.taskListId,
2360
+ storagePath: this.storagePath,
2361
+ createdAt: this.createdAt,
2362
+ updatedAt: this.updatedAt,
2363
+ total: tasks.length,
2364
+ tasks
2365
+ };
2366
+ }
2367
+ resolveBlockedReason(status, blockedReasonInput, previous) {
2368
+ if (status !== "blocked") {
2369
+ return void 0;
2370
+ }
2371
+ if (blockedReasonInput !== void 0) {
2372
+ return blockedReasonInput || "Blocked without reason";
2373
+ }
2374
+ return previous ?? "Blocked without reason";
2375
+ }
2376
+ async loadTaskList(taskListId) {
2377
+ const normalized = normalizeTaskListId(taskListId);
2378
+ this.taskListId = normalized;
2379
+ this.storagePath = import_path4.default.join(this.storageDir, `${normalized}.json`);
2380
+ await import_fs10.promises.mkdir(this.storageDir, { recursive: true });
2381
+ try {
2382
+ const raw = await import_fs10.promises.readFile(this.storagePath, "utf-8");
2383
+ const parsed = JSON.parse(raw);
2384
+ const parsedTasks = Array.isArray(parsed.tasks) ? parsed.tasks : [];
2385
+ this.tasks = new Map(parsedTasks.filter((task) => !!task?.id).map((task) => [task.id, task]));
2386
+ this.createdAt = typeof parsed.createdAt === "number" ? parsed.createdAt : now();
2387
+ this.updatedAt = typeof parsed.updatedAt === "number" ? parsed.updatedAt : now();
2388
+ } catch (error) {
2389
+ if (error?.code !== "ENOENT") {
2390
+ throw error;
2391
+ }
2392
+ const timestamp = now();
2393
+ this.tasks = /* @__PURE__ */ new Map();
2394
+ this.createdAt = timestamp;
2395
+ this.updatedAt = timestamp;
2396
+ await this.persist();
2397
+ }
2398
+ this.initialized = true;
2399
+ }
2400
+ async persist() {
2401
+ const payload = {
2402
+ taskListId: this.taskListId,
2403
+ createdAt: this.createdAt,
2404
+ updatedAt: this.updatedAt,
2405
+ tasks: Array.from(this.tasks.values()).sort((a, b) => a.createdAt - b.createdAt)
2406
+ };
2407
+ await import_fs10.promises.writeFile(this.storagePath, JSON.stringify(payload, null, 2), "utf-8");
2408
+ }
2409
+ };
2410
+ function buildTaskCreateTool(service) {
2411
+ return {
2412
+ name: "task_create",
2413
+ description: "Create one or more tracked tasks for complex work. Use this when work has multiple steps, dependencies, or blockers.",
2414
+ inputSchema: TASK_CREATE_INPUT_SCHEMA,
2415
+ execute: async ({ tasks, title, details, status, dependencies, blockedReason, metadata }) => {
2416
+ const items = tasks?.length ? tasks : [{ title, details, status, dependencies, blockedReason, metadata }];
2417
+ const created = await service.createTasks(items);
2418
+ return {
2419
+ taskListId: service.taskListId,
2420
+ storagePath: service.storagePath,
2421
+ createdCount: created.length,
2422
+ tasks: created
2423
+ };
2424
+ }
2425
+ };
2426
+ }
2427
+ function buildTaskGetTool(service) {
2428
+ return {
2429
+ name: "task_get",
2430
+ description: "Get full details for a single task by task ID.",
2431
+ inputSchema: TASK_GET_INPUT_SCHEMA,
2432
+ execute: async ({ id }) => {
2433
+ const task = await service.getTask(id);
2434
+ if (!task) {
2435
+ throw new Error(`Task not found: ${id}`);
2436
+ }
2437
+ return {
2438
+ taskListId: service.taskListId,
2439
+ storagePath: service.storagePath,
2440
+ task
2441
+ };
2442
+ }
2443
+ };
2444
+ }
2445
+ function buildTaskListTool(service) {
2446
+ return {
2447
+ name: "task_list",
2448
+ description: "List tasks and their current status. Use this to check progress before and after major changes.",
2449
+ inputSchema: TASK_LIST_INPUT_SCHEMA,
2450
+ execute: async ({ statuses, includeCompleted, limit }) => {
2451
+ const snapshot = await service.snapshot({ statuses, includeCompleted, limit });
2452
+ const completed = snapshot.tasks.filter((task) => task.status === "completed").length;
2453
+ const inProgress = snapshot.tasks.filter((task) => task.status === "in_progress").length;
2454
+ const pending = snapshot.tasks.filter((task) => task.status === "pending").length;
2455
+ const blocked = snapshot.tasks.filter((task) => task.status === "blocked").length;
2456
+ return {
2457
+ ...snapshot,
2458
+ summary: {
2459
+ total: snapshot.total,
2460
+ completed,
2461
+ inProgress,
2462
+ pending,
2463
+ blocked
2464
+ }
2465
+ };
2466
+ }
2467
+ };
2468
+ }
2469
+ function buildTaskUpdateTool(service) {
2470
+ return {
2471
+ name: "task_update",
2472
+ description: "Update task fields, move status (pending/in_progress/completed/blocked), or delete tasks.",
2473
+ inputSchema: TASK_UPDATE_INPUT_SCHEMA,
2474
+ execute: async (input) => {
2475
+ const task = await service.updateTask(input);
2476
+ if (input.delete) {
2477
+ return {
2478
+ taskListId: service.taskListId,
2479
+ storagePath: service.storagePath,
2480
+ deleted: true,
2481
+ id: input.id
2482
+ };
2483
+ }
2484
+ if (!task) {
2485
+ throw new Error(`Task not found: ${input.id}`);
2486
+ }
2487
+ return {
2488
+ taskListId: service.taskListId,
2489
+ storagePath: service.storagePath,
2490
+ deleted: false,
2491
+ task
2492
+ };
2493
+ }
2494
+ };
2495
+ }
2496
+ var builtInTaskTrackingPlugin = {
2497
+ name: "pulse-coder-engine/built-in-task-tracking",
2498
+ version: "1.0.0",
2499
+ dependencies: ["pulse-coder-engine/built-in-skills"],
2500
+ async initialize(context) {
2501
+ const service = new TaskListService();
2502
+ await service.initialize();
2503
+ context.registerService("taskListService", service);
2504
+ context.registerService("taskTracking", service);
2505
+ const skillRegistry = context.getService("skillRegistry");
2506
+ if (skillRegistry) {
2507
+ const registration = skillRegistry.registerSkill(TASK_TRACKING_SKILL);
2508
+ context.logger.info("[TaskTracking] Registered built-in task tracking skill", registration);
2509
+ } else {
2510
+ context.logger.warn("[TaskTracking] skillRegistry service unavailable; skipped task tracking skill registration");
2511
+ }
2512
+ context.registerTools({
2513
+ task_create: buildTaskCreateTool(service),
2514
+ task_get: buildTaskGetTool(service),
2515
+ task_list: buildTaskListTool(service),
2516
+ task_update: buildTaskUpdateTool(service)
2517
+ });
2518
+ context.logger.info("[TaskTracking] Registered task tools", {
2519
+ taskListId: service.taskListId,
2520
+ storagePath: service.storagePath,
2521
+ skillRegistryAvailable: !!skillRegistry
2522
+ });
2523
+ }
2524
+ };
2525
+
2526
+ // src/built-in/sub-agent-plugin/index.ts
2527
+ var import_zod12 = require("zod");
2528
+ var import_fs11 = require("fs");
2529
+ var import_path5 = __toESM(require("path"), 1);
2080
2530
  var ConfigLoader = class {
2081
2531
  async getAgentFilesInfo(configDirs) {
2082
2532
  const fileInfos = [];
2083
2533
  for (let configDir of configDirs) {
2084
2534
  try {
2085
- await import_fs10.promises.access(configDir);
2086
- const files = await import_fs10.promises.readdir(configDir);
2535
+ await import_fs11.promises.access(configDir);
2536
+ const files = await import_fs11.promises.readdir(configDir);
2087
2537
  fileInfos.push({ files, configDir });
2088
2538
  } catch {
2089
2539
  continue;
@@ -2100,7 +2550,7 @@ var ConfigLoader = class {
2100
2550
  const files = fileInfo.files;
2101
2551
  for (const file of files) {
2102
2552
  if (file.endsWith(".md")) {
2103
- const config = await this.parseConfig(import_path4.default.join(fileInfo.configDir, file));
2553
+ const config = await this.parseConfig(import_path5.default.join(fileInfo.configDir, file));
2104
2554
  if (config) configs.push(config);
2105
2555
  }
2106
2556
  }
@@ -2112,7 +2562,7 @@ var ConfigLoader = class {
2112
2562
  }
2113
2563
  async parseConfig(filePath) {
2114
2564
  try {
2115
- const content = await import_fs10.promises.readFile(filePath, "utf-8");
2565
+ const content = await import_fs11.promises.readFile(filePath, "utf-8");
2116
2566
  const lines = content.split("\n");
2117
2567
  let name = "";
2118
2568
  let description = "";
@@ -2141,7 +2591,7 @@ var ConfigLoader = class {
2141
2591
  }
2142
2592
  }
2143
2593
  if (!name) {
2144
- name = import_path4.default.basename(filePath, ".md");
2594
+ name = import_path5.default.basename(filePath, ".md");
2145
2595
  }
2146
2596
  return {
2147
2597
  name: name.trim(),
@@ -2192,9 +2642,9 @@ var SubAgentPlugin = class {
2192
2642
  const toolName = `${config.name}_agent`;
2193
2643
  const tool2 = {
2194
2644
  description: config.description,
2195
- inputSchema: import_zod11.z.object({
2196
- task: import_zod11.z.string().describe("\u8981\u6267\u884C\u7684\u4EFB\u52A1\u63CF\u8FF0"),
2197
- context: import_zod11.z.any().optional().describe("\u4EFB\u52A1\u4E0A\u4E0B\u6587\u4FE1\u606F")
2645
+ inputSchema: import_zod12.z.object({
2646
+ task: import_zod12.z.string().describe("\u8981\u6267\u884C\u7684\u4EFB\u52A1\u63CF\u8FF0"),
2647
+ context: import_zod12.z.any().optional().describe("\u4EFB\u52A1\u4E0A\u4E0B\u6587\u4FE1\u606F")
2198
2648
  }),
2199
2649
  execute: async ({ task, context: taskContext }) => {
2200
2650
  const tools = { ...BuiltinToolsMap, ...context.getTools() };
@@ -2221,6 +2671,7 @@ var builtInPlugins = [
2221
2671
  builtInMCPPlugin,
2222
2672
  builtInSkillsPlugin,
2223
2673
  builtInPlanModePlugin,
2674
+ builtInTaskTrackingPlugin,
2224
2675
  new SubAgentPlugin()
2225
2676
  ];
2226
2677
 
@@ -2408,12 +2859,14 @@ var Engine = class {
2408
2859
  PluginManager,
2409
2860
  PulseAgent,
2410
2861
  ReadTool,
2862
+ TaskListService,
2411
2863
  TavilyTool,
2412
2864
  WriteTool,
2413
2865
  builtInMCPPlugin,
2414
2866
  builtInPlanModePlugin,
2415
2867
  builtInPlugins,
2416
2868
  builtInSkillsPlugin,
2869
+ builtInTaskTrackingPlugin,
2417
2870
  getFinalToolsMap,
2418
2871
  loop,
2419
2872
  maybeCompactContext,