@polka-codes/cli 0.9.47 → 0.9.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1035 -615
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -35579,7 +35579,7 @@ var {
35579
35579
  Help
35580
35580
  } = import__.default;
35581
35581
  // package.json
35582
- var version = "0.9.47";
35582
+ var version = "0.9.49";
35583
35583
 
35584
35584
  // src/commands/code.ts
35585
35585
  import { readFile as readFile3 } from "node:fs/promises";
@@ -48216,36 +48216,12 @@ var configSchema = exports_external.object({
48216
48216
  rules: exports_external.array(exports_external.string()).optional().or(exports_external.string()).optional(),
48217
48217
  excludeFiles: exports_external.array(exports_external.string()).optional()
48218
48218
  }).strict();
48219
- // ../core/src/tools/appendMemory.ts
48220
- var toolInfo = {
48221
- name: "appendMemory",
48222
- description: "Appends content to a memory topic.",
48223
- parameters: exports_external.object({
48224
- topic: exports_external.string().nullish().describe('The topic to append to in memory. Defaults to ":default:".'),
48225
- content: exports_external.string().describe("The content to append.")
48226
- })
48227
- };
48228
- var handler = async (provider, args) => {
48229
- const { topic, content } = toolInfo.parameters.parse(args);
48230
- await provider.appendMemory(topic ?? undefined, content);
48231
- return {
48232
- type: "Reply" /* Reply */,
48233
- message: {
48234
- type: "text",
48235
- value: `Content appended to memory topic '${topic || ""}'.`
48236
- }
48237
- };
48238
- };
48239
- var appendMemory_default = {
48240
- ...toolInfo,
48241
- handler
48242
- };
48243
48219
  // ../core/src/tools/askFollowupQuestion.ts
48244
48220
  var questionObject = exports_external.object({
48245
48221
  prompt: exports_external.string().describe("The text of the question.").meta({ usageValue: "question text here" }),
48246
48222
  options: exports_external.array(exports_external.string()).default([]).describe("Ordered list of suggested answers (omit if none).").meta({ usageValue: "suggested answer here" })
48247
48223
  });
48248
- var toolInfo2 = {
48224
+ var toolInfo = {
48249
48225
  name: "askFollowupQuestion",
48250
48226
  description: "Call this when vital details are missing. Pose each follow-up as one direct, unambiguous question. If it speeds the reply, add up to five short, mutually-exclusive answer options. Group any related questions in the same call to avoid a back-and-forth chain.",
48251
48227
  parameters: exports_external.object({
@@ -48295,7 +48271,7 @@ var toolInfo2 = {
48295
48271
  ]
48296
48272
  })
48297
48273
  };
48298
- var handler2 = async (provider, args) => {
48274
+ var handler = async (provider, args) => {
48299
48275
  if (!provider.askFollowupQuestion) {
48300
48276
  return {
48301
48277
  type: "Error" /* Error */,
@@ -48305,7 +48281,7 @@ var handler2 = async (provider, args) => {
48305
48281
  }
48306
48282
  };
48307
48283
  }
48308
- const { questions } = toolInfo2.parameters.parse(args);
48284
+ const { questions } = toolInfo.parameters.parse(args);
48309
48285
  if (questions.length === 0) {
48310
48286
  return {
48311
48287
  type: "Error" /* Error */,
@@ -48333,11 +48309,11 @@ ${answer}
48333
48309
  };
48334
48310
  };
48335
48311
  var askFollowupQuestion_default = {
48336
- ...toolInfo2,
48337
- handler: handler2
48312
+ ...toolInfo,
48313
+ handler
48338
48314
  };
48339
48315
  // ../core/src/tools/executeCommand.ts
48340
- var toolInfo3 = {
48316
+ var toolInfo2 = {
48341
48317
  name: "executeCommand",
48342
48318
  description: "Run a single CLI command. The command is always executed in the project-root working directory (regardless of earlier commands). Prefer one-off shell commands over wrapper scripts for flexibility. **IMPORTANT**: After an `execute_command` call, you MUST stop and NOT allowed to make further tool calls in the same message.",
48343
48319
  parameters: exports_external.object({
@@ -48364,7 +48340,7 @@ var toolInfo3 = {
48364
48340
  ]
48365
48341
  })
48366
48342
  };
48367
- var handler3 = async (provider, args) => {
48343
+ var handler2 = async (provider, args) => {
48368
48344
  if (!provider.executeCommand) {
48369
48345
  return {
48370
48346
  type: "Error" /* Error */,
@@ -48374,7 +48350,7 @@ var handler3 = async (provider, args) => {
48374
48350
  }
48375
48351
  };
48376
48352
  }
48377
- const { command, requiresApproval } = toolInfo3.parameters.parse(args);
48353
+ const { command, requiresApproval } = toolInfo2.parameters.parse(args);
48378
48354
  try {
48379
48355
  const result = await provider.executeCommand(command, requiresApproval);
48380
48356
  let message = `<command>${command}</command>
@@ -48421,11 +48397,11 @@ ${result.stderr}
48421
48397
  }
48422
48398
  };
48423
48399
  var executeCommand_default = {
48424
- ...toolInfo3,
48425
- handler: handler3
48400
+ ...toolInfo2,
48401
+ handler: handler2
48426
48402
  };
48427
48403
  // ../core/src/tools/fetchUrl.ts
48428
- var toolInfo4 = {
48404
+ var toolInfo3 = {
48429
48405
  name: "fetchUrl",
48430
48406
  description: "Fetch the content located at one or more HTTP(S) URLs and return it in Markdown format. This works for standard web pages as well as raw files (e.g. README.md, source code) hosted on platforms like GitHub.",
48431
48407
  parameters: exports_external.object({
@@ -48458,7 +48434,7 @@ var toolInfo4 = {
48458
48434
  ]
48459
48435
  })
48460
48436
  };
48461
- var handler4 = async (provider, args) => {
48437
+ var handler3 = async (provider, args) => {
48462
48438
  if (!provider.fetchUrl) {
48463
48439
  return {
48464
48440
  type: "Error" /* Error */,
@@ -48468,7 +48444,7 @@ var handler4 = async (provider, args) => {
48468
48444
  }
48469
48445
  };
48470
48446
  }
48471
- const { url: urls } = toolInfo4.parameters.parse(args);
48447
+ const { url: urls } = toolInfo3.parameters.parse(args);
48472
48448
  if (urls.length === 0) {
48473
48449
  return {
48474
48450
  type: "Error" /* Error */,
@@ -48499,6 +48475,38 @@ var handler4 = async (provider, args) => {
48499
48475
  };
48500
48476
  };
48501
48477
  var fetchUrl_default = {
48478
+ ...toolInfo3,
48479
+ handler: handler3
48480
+ };
48481
+ // ../core/src/tools/getTodoItem.ts
48482
+ var toolInfo4 = {
48483
+ name: "getTodoItem",
48484
+ description: "Get a to-do item by its ID.",
48485
+ parameters: exports_external.object({
48486
+ id: exports_external.string().describe("The ID of the to-do item.")
48487
+ })
48488
+ };
48489
+ var handler4 = async (provider, args) => {
48490
+ if (!provider.getTodoItem) {
48491
+ return {
48492
+ type: "Error" /* Error */,
48493
+ message: {
48494
+ type: "error-text",
48495
+ value: "Not possible to get a to-do item."
48496
+ }
48497
+ };
48498
+ }
48499
+ const { id } = toolInfo4.parameters.parse(args);
48500
+ const item = await provider.getTodoItem(id);
48501
+ return {
48502
+ type: "Reply" /* Reply */,
48503
+ message: {
48504
+ type: "json",
48505
+ value: item ?? null
48506
+ }
48507
+ };
48508
+ };
48509
+ var getTodoItem_default = {
48502
48510
  ...toolInfo4,
48503
48511
  handler: handler4
48504
48512
  };
@@ -48573,7 +48581,7 @@ var listFiles_default = {
48573
48581
  // ../core/src/tools/listMemoryTopics.ts
48574
48582
  var toolInfo6 = {
48575
48583
  name: "listMemoryTopics",
48576
- description: "Lists all topics in memory.",
48584
+ description: "Lists all topics in memory. Use this to see what information has been stored and which topics are available to read from.",
48577
48585
  parameters: exports_external.object({})
48578
48586
  };
48579
48587
  var handler6 = async (provider, _args) => {
@@ -48595,15 +48603,88 @@ var listMemoryTopics_default = {
48595
48603
  ...toolInfo6,
48596
48604
  handler: handler6
48597
48605
  };
48598
- // ../core/src/tools/readBinaryFile.ts
48606
+ // ../core/src/tools/todo.ts
48607
+ var TodoStatus = exports_external.enum(["open", "completed", "closed"]);
48608
+ var TodoItemSchema = exports_external.object({
48609
+ id: exports_external.string(),
48610
+ title: exports_external.string(),
48611
+ description: exports_external.string(),
48612
+ relevantFileList: exports_external.array(exports_external.string()),
48613
+ status: TodoStatus
48614
+ });
48615
+ var UpdateTodoItemInputSchema = exports_external.object({
48616
+ operation: exports_external.enum(["add", "update"]),
48617
+ id: exports_external.string().nullish(),
48618
+ parentId: exports_external.string().nullish(),
48619
+ title: exports_external.string().nullish(),
48620
+ description: exports_external.string().nullish(),
48621
+ relevantFileList: exports_external.array(exports_external.string()).nullish(),
48622
+ status: TodoStatus.nullish()
48623
+ }).superRefine((data, ctx) => {
48624
+ if (data.operation === "add") {
48625
+ if (!data.title) {
48626
+ ctx.addIssue({
48627
+ code: "custom",
48628
+ message: 'Title is required for "add" operation',
48629
+ path: ["title"]
48630
+ });
48631
+ }
48632
+ } else if (data.operation === "update") {
48633
+ if (!data.id) {
48634
+ ctx.addIssue({
48635
+ code: "custom",
48636
+ message: 'ID is required for "update" operation',
48637
+ path: ["id"]
48638
+ });
48639
+ }
48640
+ }
48641
+ });
48642
+ var UpdateTodoItemOutputSchema = exports_external.object({
48643
+ id: exports_external.string()
48644
+ });
48645
+
48646
+ // ../core/src/tools/listTodoItems.ts
48599
48647
  var toolInfo7 = {
48648
+ name: "listTodoItems",
48649
+ description: "List all to-do items, sorted by id. If an id is provided, it lists all sub-items for that id. Can be filtered by status.",
48650
+ parameters: exports_external.object({
48651
+ id: exports_external.string().nullish(),
48652
+ status: TodoStatus.nullish()
48653
+ })
48654
+ };
48655
+ var handler7 = async (provider, args) => {
48656
+ if (!provider.listTodoItems) {
48657
+ return {
48658
+ type: "Error" /* Error */,
48659
+ message: {
48660
+ type: "error-text",
48661
+ value: "Not possible to list to-do items."
48662
+ }
48663
+ };
48664
+ }
48665
+ const { id, status } = toolInfo7.parameters.parse(args);
48666
+ const items = await provider.listTodoItems(id, status);
48667
+ return {
48668
+ type: "Reply" /* Reply */,
48669
+ message: {
48670
+ type: "json",
48671
+ value: items
48672
+ }
48673
+ };
48674
+ };
48675
+ var listTodoItems_default = {
48676
+ ...toolInfo7,
48677
+ handler: handler7
48678
+ };
48679
+ // ../core/src/tools/readBinaryFile.ts
48680
+ var toolInfo8 = {
48600
48681
  name: "readBinaryFile",
48601
48682
  description: "Read a binary file from a URL or local path. Use file:// prefix to access local files. This can be used to access non-text files such as PDFs or images.",
48602
48683
  parameters: exports_external.object({
48603
48684
  url: exports_external.string().describe("The URL or local path of the file to read.")
48604
48685
  })
48605
48686
  };
48606
- var handler7 = async (provider, args) => {
48687
+ var handler8 = async (provider, args) => {
48607
48688
  if (!provider.readBinaryFile) {
48608
48689
  return {
48609
48690
  type: "Error" /* Error */,
@@ -48613,7 +48694,7 @@ var handler7 = async (provider, args) => {
48613
48694
  }
48614
48695
  };
48615
48696
  }
48616
- const { url: url2 } = toolInfo7.parameters.parse(args);
48697
+ const { url: url2 } = toolInfo8.parameters.parse(args);
48617
48698
  try {
48618
48699
  const filePart = await provider.readBinaryFile(url2);
48619
48700
  return {
@@ -48642,11 +48723,11 @@ var handler7 = async (provider, args) => {
48642
48723
  }
48643
48724
  };
48644
48725
  var readBinaryFile_default = {
48645
- ...toolInfo7,
48646
- handler: handler7
48726
+ ...toolInfo8,
48727
+ handler: handler8
48647
48728
  };
48648
48729
  // ../core/src/tools/readFile.ts
48649
- var toolInfo8 = {
48730
+ var toolInfo9 = {
48650
48731
  name: "readFile",
48651
48732
  description: "Request to read the contents of one or multiple files at the specified paths. Use comma separated paths to read multiple files. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. May not be suitable for other types of binary files, as it returns the raw content as a string. Try to list all the potential files are relevent to the task, and then use this tool to read all the relevant files.",
48652
48733
  parameters: exports_external.object({
@@ -48683,7 +48764,7 @@ var toolInfo8 = {
48683
48764
  ]
48684
48765
  })
48685
48766
  };
48686
- var handler8 = async (provider, args) => {
48767
+ var handler9 = async (provider, args) => {
48687
48768
  if (!provider.readFile) {
48688
48769
  return {
48689
48770
  type: "Error" /* Error */,
@@ -48693,7 +48774,7 @@ var handler8 = async (provider, args) => {
48693
48774
  }
48694
48775
  };
48695
48776
  }
48696
- const { path: paths, includeIgnored } = toolInfo8.parameters.parse(args);
48777
+ const { path: paths, includeIgnored } = toolInfo9.parameters.parse(args);
48697
48778
  const resp = [];
48698
48779
  for (const path of paths) {
48699
48780
  const fileContent = await provider.readFile(path, includeIgnored);
@@ -48718,19 +48799,19 @@ var handler8 = async (provider, args) => {
48718
48799
  };
48719
48800
  };
48720
48801
  var readFile_default = {
48721
- ...toolInfo8,
48722
- handler: handler8
48802
+ ...toolInfo9,
48803
+ handler: handler9
48723
48804
  };
48724
48805
  // ../core/src/tools/readMemory.ts
48725
- var toolInfo9 = {
48806
+ var toolInfo10 = {
48726
48807
  name: "readMemory",
48727
- description: "Reads content from a memory topic.",
48808
+ description: "Reads content from a memory topic. Use this to retrieve information stored in previous steps. If no topic is specified, reads from the default topic.",
48728
48809
  parameters: exports_external.object({
48729
48810
  topic: exports_external.string().optional().describe('The topic to read from memory. Defaults to ":default:".')
48730
48811
  })
48731
48812
  };
48732
- var handler9 = async (provider, args) => {
48733
- const { topic } = toolInfo9.parameters.parse(args);
48813
+ var handler10 = async (provider, args) => {
48814
+ const { topic } = toolInfo10.parameters.parse(args);
48734
48815
  const content = await provider.readMemory(topic);
48735
48816
  if (content) {
48736
48817
  return {
@@ -48752,11 +48833,11 @@ ${content}
48752
48833
  };
48753
48834
  };
48754
48835
  var readMemory_default = {
48755
- ...toolInfo9,
48756
- handler: handler9
48836
+ ...toolInfo10,
48837
+ handler: handler10
48757
48838
  };
48758
48839
  // ../core/src/tools/removeFile.ts
48759
- var toolInfo10 = {
48840
+ var toolInfo11 = {
48760
48841
  name: "removeFile",
48761
48842
  description: "Request to remove a file at the specified path.",
48762
48843
  parameters: exports_external.object({
@@ -48772,7 +48853,7 @@ var toolInfo10 = {
48772
48853
  ]
48773
48854
  })
48774
48855
  };
48775
- var handler10 = async (provider, args) => {
48856
+ var handler11 = async (provider, args) => {
48776
48857
  if (!provider.removeFile) {
48777
48858
  return {
48778
48859
  type: "Error" /* Error */,
@@ -48782,7 +48863,7 @@ var handler10 = async (provider, args) => {
48782
48863
  }
48783
48864
  };
48784
48865
  }
48785
- const parsed = toolInfo10.parameters.safeParse(args);
48866
+ const parsed = toolInfo11.parameters.safeParse(args);
48786
48867
  if (!parsed.success) {
48787
48868
  return {
48788
48869
  type: "Error" /* Error */,
@@ -48803,29 +48884,6 @@ var handler10 = async (provider, args) => {
48803
48884
  };
48804
48885
  };
48805
48886
  var removeFile_default = {
48806
- ...toolInfo10,
48807
- handler: handler10
48808
- };
48809
- // ../core/src/tools/removeMemory.ts
48810
- var toolInfo11 = {
48811
- name: "removeMemory",
48812
- description: "Removes a topic from memory.",
48813
- parameters: exports_external.object({
48814
- topic: exports_external.string().optional().describe('The topic to remove from memory. Defaults to ":default:".')
48815
- })
48816
- };
48817
- var handler11 = async (provider, args) => {
48818
- const { topic } = toolInfo11.parameters.parse(args);
48819
- await provider.removeMemory(topic);
48820
- return {
48821
- type: "Reply" /* Reply */,
48822
- message: {
48823
- type: "text",
48824
- value: `Memory topic '${topic || ""}' removed.`
48825
- }
48826
- };
48827
- };
48828
- var removeMemory_default = {
48829
48887
  ...toolInfo11,
48830
48888
  handler: handler11
48831
48889
  };
@@ -48874,7 +48932,7 @@ var renameFile_default = {
48874
48932
  };
48875
48933
  // ../core/src/tools/utils/replaceInFile.ts
48876
48934
  var replaceInFile = (fileContent, diff) => {
48877
- const blockPattern = /<<<<<+ SEARCH>?\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
48935
+ const blockPattern = /^\s*<<<<<+\s*SEARCH>?\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+\s*REPLACE\s*$/gm;
48878
48936
  const blocks = [];
48879
48937
  for (let match = blockPattern.exec(diff);match !== null; match = blockPattern.exec(diff)) {
48880
48938
  blocks.push({ search: match[1], replace: match[2] });
@@ -49134,32 +49192,8 @@ var replaceInFile_default = {
49134
49192
  ...toolInfo13,
49135
49193
  handler: handler13
49136
49194
  };
49137
- // ../core/src/tools/replaceMemory.ts
49138
- var toolInfo14 = {
49139
- name: "replaceMemory",
49140
- description: "Replaces content of a memory topic.",
49141
- parameters: exports_external.object({
49142
- topic: exports_external.string().optional().describe('The topic to replace in memory. Defaults to ":default:".'),
49143
- content: exports_external.string().describe("The new content.")
49144
- })
49145
- };
49146
- var handler14 = async (provider, args) => {
49147
- const { topic, content } = toolInfo14.parameters.parse(args);
49148
- await provider.replaceMemory(topic, content);
49149
- return {
49150
- type: "Reply" /* Reply */,
49151
- message: {
49152
- type: "text",
49153
- value: `Memory topic '${topic || ""}' replaced.`
49154
- }
49155
- };
49156
- };
49157
- var replaceMemory_default = {
49158
- ...toolInfo14,
49159
- handler: handler14
49160
- };
49161
49195
  // ../core/src/tools/searchFiles.ts
49162
- var toolInfo15 = {
49196
+ var toolInfo14 = {
49163
49197
  name: "searchFiles",
49164
49198
  description: "Request to perform a regex search across files in a specified directory, outputting context-rich results that include surrounding lines. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context.",
49165
49199
  parameters: exports_external.object({
@@ -49183,7 +49217,7 @@ var toolInfo15 = {
49183
49217
  ]
49184
49218
  })
49185
49219
  };
49186
- var handler15 = async (provider, args) => {
49220
+ var handler14 = async (provider, args) => {
49187
49221
  if (!provider.searchFiles) {
49188
49222
  return {
49189
49223
  type: "Error" /* Error */,
@@ -49193,7 +49227,7 @@ var handler15 = async (provider, args) => {
49193
49227
  }
49194
49228
  };
49195
49229
  }
49196
- const parsed = toolInfo15.parameters.safeParse(args);
49230
+ const parsed = toolInfo14.parameters.safeParse(args);
49197
49231
  if (!parsed.success) {
49198
49232
  return {
49199
49233
  type: "Error" /* Error */,
@@ -49231,11 +49265,112 @@ ${files.join(`
49231
49265
  }
49232
49266
  };
49233
49267
  var searchFiles_default = {
49268
+ ...toolInfo14,
49269
+ handler: handler14
49270
+ };
49271
+ // ../core/src/tools/updateMemory.ts
49272
+ var toolInfo15 = {
49273
+ name: "updateMemory",
49274
+ description: 'Appends, replaces, or removes content from a memory topic. Use "append" to add to existing content, "replace" to overwrite entirely, or "remove" to delete a topic. Memory persists across tool calls within a workflow.',
49275
+ parameters: exports_external.object({
49276
+ operation: exports_external.enum(["append", "replace", "remove"]).describe("The operation to perform."),
49277
+ topic: exports_external.string().nullish().describe('The topic to update in memory. Defaults to ":default:".'),
49278
+ content: exports_external.string().optional().describe("The content for append or replace operations. Must be omitted for remove operation.")
49279
+ }).superRefine((data, ctx) => {
49280
+ if (data.operation === "append" || data.operation === "replace") {
49281
+ if (data.content === undefined) {
49282
+ ctx.addIssue({
49283
+ code: "custom",
49284
+ message: 'Content is required for "append" and "replace" operations.',
49285
+ path: ["content"]
49286
+ });
49287
+ }
49288
+ } else if (data.operation === "remove") {
49289
+ if (data.content !== undefined) {
49290
+ ctx.addIssue({
49291
+ code: "custom",
49292
+ message: 'Content must not be provided for "remove" operation.',
49293
+ path: ["content"]
49294
+ });
49295
+ }
49296
+ }
49297
+ })
49298
+ };
49299
+ var handler15 = async (provider, args) => {
49300
+ if (!provider.updateMemory) {
49301
+ return {
49302
+ type: "Error" /* Error */,
49303
+ message: {
49304
+ type: "error-text",
49305
+ value: "Memory operations are not supported by the current provider."
49306
+ }
49307
+ };
49308
+ }
49309
+ const params = toolInfo15.parameters.parse(args);
49310
+ await provider.updateMemory(params.operation, params.topic ?? undefined, "content" in params ? params.content : undefined);
49311
+ switch (params.operation) {
49312
+ case "append":
49313
+ return {
49314
+ type: "Reply" /* Reply */,
49315
+ message: {
49316
+ type: "text",
49317
+ value: `Content appended to memory topic '${params.topic || ":default:"}'.`
49318
+ }
49319
+ };
49320
+ case "replace":
49321
+ return {
49322
+ type: "Reply" /* Reply */,
49323
+ message: {
49324
+ type: "text",
49325
+ value: `Memory topic '${params.topic || ":default:"}' replaced.`
49326
+ }
49327
+ };
49328
+ case "remove":
49329
+ return {
49330
+ type: "Reply" /* Reply */,
49331
+ message: {
49332
+ type: "text",
49333
+ value: `Memory topic '${params.topic || ":default:"}' removed.`
49334
+ }
49335
+ };
49336
+ }
49337
+ };
49338
+ var updateMemory_default = {
49234
49339
  ...toolInfo15,
49235
49340
  handler: handler15
49236
49341
  };
49237
- // ../core/src/tools/writeToFile.ts
49342
+ // ../core/src/tools/updateTodoItem.ts
49238
49343
  var toolInfo16 = {
49344
+ name: "updateTodoItem",
49345
+ description: "Add or update a to-do item.",
49346
+ parameters: UpdateTodoItemInputSchema
49347
+ };
49348
+ var handler16 = async (provider, args) => {
49349
+ if (!provider.updateTodoItem) {
49350
+ return {
49351
+ type: "Error" /* Error */,
49352
+ message: {
49353
+ type: "error-text",
49354
+ value: "Not possible to update a to-do item."
49355
+ }
49356
+ };
49357
+ }
49358
+ const input = toolInfo16.parameters.parse(args);
49359
+ const result = await provider.updateTodoItem(input);
49360
+ return {
49361
+ type: "Reply" /* Reply */,
49362
+ message: {
49363
+ type: "json",
49364
+ value: result
49365
+ }
49366
+ };
49367
+ };
49368
+ var updateTodoItem_default = {
49369
+ ...toolInfo16,
49370
+ handler: handler16
49371
+ };
49372
+ // ../core/src/tools/writeToFile.ts
49373
+ var toolInfo17 = {
49239
49374
  name: "writeToFile",
49240
49375
  description: "Request to write content to a file at the specified path. If the file exists, it will be overwritten with the provided content. If the file doesn't exist, it will be created. This tool will automatically create any directories needed to write the file. Ensure that the output content does not include incorrect escaped character patterns such as `&lt;`, `&gt;`, or `&amp;`. Also ensure there is no unwanted CDATA tags in the content.",
49241
49376
  parameters: exports_external.object({
@@ -49264,7 +49399,7 @@ export default App;
49264
49399
  ]
49265
49400
  })
49266
49401
  };
49267
- var handler16 = async (provider, args) => {
49402
+ var handler17 = async (provider, args) => {
49268
49403
  if (!provider.writeFile) {
49269
49404
  return {
49270
49405
  type: "Error" /* Error */,
@@ -49274,7 +49409,7 @@ var handler16 = async (provider, args) => {
49274
49409
  }
49275
49410
  };
49276
49411
  }
49277
- const parsed = toolInfo16.parameters.safeParse(args);
49412
+ const parsed = toolInfo17.parameters.safeParse(args);
49278
49413
  if (!parsed.success) {
49279
49414
  return {
49280
49415
  type: "Error" /* Error */,
@@ -49298,8 +49433,8 @@ var handler16 = async (provider, args) => {
49298
49433
  };
49299
49434
  };
49300
49435
  var writeToFile_default = {
49301
- ...toolInfo16,
49302
- handler: handler16
49436
+ ...toolInfo17,
49437
+ handler: handler17
49303
49438
  };
49304
49439
  // ../core/src/UsageMeter.ts
49305
49440
  class UsageMeter {
@@ -51340,15 +51475,15 @@ function useKeypress(userHandler) {
51340
51475
  signal.current = userHandler;
51341
51476
  useEffect((rl) => {
51342
51477
  let ignore = false;
51343
- const handler17 = withUpdates((_input, event) => {
51478
+ const handler18 = withUpdates((_input, event) => {
51344
51479
  if (ignore)
51345
51480
  return;
51346
51481
  signal.current(event, rl);
51347
51482
  });
51348
- rl.input.on("keypress", handler17);
51483
+ rl.input.on("keypress", handler18);
51349
51484
  return () => {
51350
51485
  ignore = true;
51351
- rl.input.removeListener("keypress", handler17);
51486
+ rl.input.removeListener("keypress", handler18);
51352
51487
  };
51353
51488
  }, []);
51354
51489
  }
@@ -51507,16 +51642,16 @@ class Emitter {
51507
51642
 
51508
51643
  class SignalExitBase {
51509
51644
  }
51510
- var signalExitWrap = (handler17) => {
51645
+ var signalExitWrap = (handler18) => {
51511
51646
  return {
51512
51647
  onExit(cb, opts) {
51513
- return handler17.onExit(cb, opts);
51648
+ return handler18.onExit(cb, opts);
51514
51649
  },
51515
51650
  load() {
51516
- return handler17.load();
51651
+ return handler18.load();
51517
51652
  },
51518
51653
  unload() {
51519
- return handler17.unload();
51654
+ return handler18.unload();
51520
51655
  }
51521
51656
  };
51522
51657
  };
@@ -52340,27 +52475,122 @@ async function searchFiles(path, regex, filePattern, cwd, excludeFiles) {
52340
52475
  var getProvider = (options = {}) => {
52341
52476
  const ig = import_ignore2.default().add(options.excludeFiles ?? []);
52342
52477
  const memoryStore = {};
52478
+ const todoItems = [];
52343
52479
  const defaultMemoryTopic = ":default:";
52344
52480
  const provider2 = {
52481
+ listTodoItems: async (id, status) => {
52482
+ let items;
52483
+ if (!id) {
52484
+ items = todoItems.filter((i) => !i.id.includes("."));
52485
+ } else {
52486
+ const parent = todoItems.find((i) => i.id === id);
52487
+ if (!parent) {
52488
+ throw new Error(`To-do item with id ${id} not found`);
52489
+ }
52490
+ items = todoItems.filter((i) => i.id.startsWith(`${id}.`) && i.id.split(".").length === id.split(".").length + 1);
52491
+ }
52492
+ if (status) {
52493
+ items = items.filter((item) => item.status === status);
52494
+ }
52495
+ items.sort((a, b) => {
52496
+ const aParts = a.id.split(".");
52497
+ const bParts = b.id.split(".");
52498
+ const len = Math.min(aParts.length, bParts.length);
52499
+ for (let i = 0;i < len; i++) {
52500
+ const comparison = aParts[i].localeCompare(bParts[i], undefined, { numeric: true });
52501
+ if (comparison !== 0) {
52502
+ return comparison;
52503
+ }
52504
+ }
52505
+ return aParts.length - bParts.length;
52506
+ });
52507
+ return items;
52508
+ },
52509
+ getTodoItem: async (id) => {
52510
+ const item = todoItems.find((i) => i.id === id);
52511
+ if (!item) {
52512
+ throw new Error(`To-do item with id ${id} not found`);
52513
+ }
52514
+ const subItems = todoItems.filter((i) => i.id.startsWith(`${id}.`) && i.id.split(".").length === id.split(".").length + 1).map(({ id: id2, title }) => ({ id: id2, title }));
52515
+ return { ...item, subItems };
52516
+ },
52517
+ updateTodoItem: async (input) => {
52518
+ if (input.operation === "add") {
52519
+ const { parentId, title, description, relevantFileList } = input;
52520
+ if (!title) {
52521
+ throw new Error("Title is required for add operation");
52522
+ }
52523
+ let newId;
52524
+ if (parentId) {
52525
+ const parent = todoItems.find((i) => i.id === parentId);
52526
+ if (!parent) {
52527
+ throw new Error(`Parent to-do item with id ${parentId} not found`);
52528
+ }
52529
+ const childItems = todoItems.filter((i) => i.id.startsWith(`${parentId}.`) && i.id.split(".").length === parentId.split(".").length + 1);
52530
+ newId = `${parentId}.${childItems.length + 1}`;
52531
+ } else {
52532
+ const rootItems = todoItems.filter((i) => !i.id.includes("."));
52533
+ newId = `${rootItems.length + 1}`;
52534
+ }
52535
+ const newItem = {
52536
+ id: newId,
52537
+ title,
52538
+ description: description ?? "",
52539
+ relevantFileList: relevantFileList ?? [],
52540
+ status: "open"
52541
+ };
52542
+ todoItems.push(newItem);
52543
+ return { id: newId };
52544
+ } else {
52545
+ const { id } = input;
52546
+ if (!id) {
52547
+ throw new Error("ID is required for update operation");
52548
+ }
52549
+ const item = todoItems.find((i) => i.id === id);
52550
+ if (!item) {
52551
+ throw new Error(`To-do item with id ${id} not found`);
52552
+ }
52553
+ if (input.title != null) {
52554
+ item.title = input.title;
52555
+ }
52556
+ if (input.description != null) {
52557
+ item.description = input.description ?? "";
52558
+ }
52559
+ if (input.relevantFileList != null) {
52560
+ item.relevantFileList = input.relevantFileList;
52561
+ }
52562
+ if (input.status != null) {
52563
+ item.status = input.status;
52564
+ }
52565
+ return { id };
52566
+ }
52567
+ },
52345
52568
  listMemoryTopics: async () => {
52346
52569
  return Object.keys(memoryStore);
52347
52570
  },
52348
52571
  readMemory: async (topic = defaultMemoryTopic) => {
52349
52572
  return memoryStore[topic];
52350
52573
  },
52351
- appendMemory: async (topic = defaultMemoryTopic, content) => {
52352
- if (memoryStore[topic]) {
52353
- memoryStore[topic] += content;
52354
- } else {
52355
- memoryStore[topic] = content;
52574
+ updateMemory: async (operation, topic, content) => {
52575
+ const memoryTopic = topic ?? defaultMemoryTopic;
52576
+ switch (operation) {
52577
+ case "append":
52578
+ if (content === undefined) {
52579
+ throw new Error("Content is required for append operation.");
52580
+ }
52581
+ memoryStore[memoryTopic] = (memoryStore[memoryTopic] || "") + content;
52582
+ break;
52583
+ case "replace":
52584
+ if (content === undefined) {
52585
+ throw new Error("Content is required for replace operation.");
52586
+ }
52587
+ memoryStore[memoryTopic] = content;
52588
+ break;
52589
+ case "remove":
52590
+ delete memoryStore[memoryTopic];
52591
+ break;
52356
52592
  }
52357
52593
  },
52358
- replaceMemory: async (topic = defaultMemoryTopic, content) => {
52359
- memoryStore[topic] = content;
52360
- },
52361
- removeMemory: async (topic = defaultMemoryTopic) => {
52362
- delete memoryStore[topic];
52363
- },
52364
52594
  readFile: async (path, includeIgnored) => {
52365
52595
  if (!includeIgnored && ig.ignores(path)) {
52366
52596
  throw new Error(`Not allow to access file ${path}`);
@@ -64119,16 +64349,12 @@ var uiMessagesSchema = lazyValidator(() => zodSchema(exports_external.array(expo
64119
64349
 
64120
64350
  // ../workflow/src/agent.workflow.ts
64121
64351
  var agentWorkflow = async (input, { step, tools: tools2 }) => {
64122
- const event = async (name17, event2) => {
64123
- await step(name17, async () => {
64124
- await tools2.taskEvent(event2);
64125
- });
64126
- };
64127
- const { tools: toolInfo17, maxToolRoundTrips = 200 } = input;
64352
+ const event = (name17, event2) => step(name17, () => tools2.taskEvent(event2));
64353
+ const { tools: toolInfo18, maxToolRoundTrips = 200 } = input;
64128
64354
  const messages = "systemPrompt" in input ? [{ role: "system", content: input.systemPrompt }] : input.messages;
64129
64355
  await event("start-task", { kind: "StartTask" /* StartTask */, systemPrompt: "systemPrompt" in input ? input.systemPrompt : "" });
64130
64356
  const toolSet = {};
64131
- for (const tool3 of toolInfo17) {
64357
+ for (const tool3 of toolInfo18) {
64132
64358
  toolSet[tool3.name] = {
64133
64359
  description: tool3.description,
64134
64360
  inputSchema: jsonSchema(toJSONSchema(tool3.parameters))
@@ -64176,7 +64402,9 @@ var agentWorkflow = async (input, { step, tools: tools2 }) => {
64176
64402
  await event(`end-round-${i}`, { kind: "EndRequest" /* EndRequest */, message: textContent });
64177
64403
  if (toolCalls.length === 0) {
64178
64404
  if (!input.outputSchema) {
64179
- return { type: "Exit" /* Exit */, message: textContent };
64405
+ const exitReason2 = { type: "Exit" /* Exit */, message: textContent };
64406
+ await event("end-task", { kind: "EndTask" /* EndTask */, exitReason: exitReason2 });
64407
+ return exitReason2;
64180
64408
  }
64181
64409
  const parsed = parseJsonFromMarkdown(textContent);
64182
64410
  if (!parsed.success) {
@@ -64190,7 +64418,9 @@ var agentWorkflow = async (input, { step, tools: tools2 }) => {
64190
64418
  nextMessage = [{ role: "user", content: errorMessage }];
64191
64419
  continue;
64192
64420
  }
64193
- return { type: "Exit" /* Exit */, message: textContent, object: validated.data };
64421
+ const exitReason = { type: "Exit" /* Exit */, message: textContent, object: validated.data };
64422
+ await event("end-task", { kind: "EndTask" /* EndTask */, exitReason });
64423
+ return exitReason;
64194
64424
  }
64195
64425
  const toolResults = [];
64196
64426
  for (const toolCall of toolCalls) {
@@ -64259,6 +64489,7 @@ var agentWorkflow = async (input, { step, tools: tools2 }) => {
64259
64489
  }
64260
64490
  ];
64261
64491
  }
64492
+ await event("end-task", { kind: "EndTask" /* EndTask */, exitReason: { type: "UsageExceeded" } });
64262
64493
  throw new Error("Maximum number of tool round trips reached.");
64263
64494
  };
64264
64495
  // ../workflow/src/json-ai-types.ts
@@ -64828,19 +65059,110 @@ var chalk = createChalk();
64828
65059
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
64829
65060
  var source_default = chalk;
64830
65061
 
65062
+ // ../cli-shared/src/utils/parameterSimplifier.ts
65063
+ function replaceInFileSimplifier(params) {
65064
+ return { path: params.path };
65065
+ }
65066
+ function writeToFileSimplifier(params) {
65067
+ return { path: params.path };
65068
+ }
65069
+ function readFileSimplifier(params) {
65070
+ return { path: params.path, includeIgnored: params.includeIgnored };
65071
+ }
65072
+ function listFilesSimplifier(params) {
65073
+ const maxCount = params.maxCount;
65074
+ return {
65075
+ path: params.path,
65076
+ recursive: params.recursive,
65077
+ ...maxCount !== 2000 && { maxCount }
65078
+ };
65079
+ }
65080
+ function searchFilesSimplifier(params) {
65081
+ return { ...params };
65082
+ }
65083
+ function executeCommandSimplifier(params) {
65084
+ return { command: params.command, requiresApproval: params.requiresApproval };
65085
+ }
65086
+ function updateMemorySimplifier(params) {
65087
+ return { operation: params.operation, topic: params.topic };
65088
+ }
65089
+ var SIMPLIFIERS = {
65090
+ replaceInFile: replaceInFileSimplifier,
65091
+ writeToFile: writeToFileSimplifier,
65092
+ readFile: readFileSimplifier,
65093
+ listFiles: listFilesSimplifier,
65094
+ searchFiles: searchFilesSimplifier,
65095
+ executeCommand: executeCommandSimplifier,
65096
+ updateMemory: updateMemorySimplifier
65097
+ };
65098
+ function simplifyToolParameters(toolName, params) {
65099
+ if (params === undefined || params === null) {
65100
+ return {};
65101
+ }
65102
+ const simplifier = SIMPLIFIERS[toolName];
65103
+ if (simplifier) {
65104
+ return simplifier(params);
65105
+ }
65106
+ return { ...params };
65107
+ }
65108
+
64831
65109
  // ../cli-shared/src/utils/eventHandler.ts
64832
- var toolCallStats = new Map;
65110
+ var taskToolCallStats = new Map;
65111
+ var globalToolCallStats = new Map;
65112
+ function logToolCallStats(stream, statsMap, title) {
65113
+ const customConsole = new Console(stream, stream);
65114
+ customConsole.log(`
65115
+
65116
+ ======== ${title} ========`);
65117
+ if (statsMap.size > 0) {
65118
+ const tableData = [...statsMap.entries()].map(([tool3, stats]) => {
65119
+ const successRate = stats.calls > 0 ? stats.success / stats.calls * 100 : 0;
65120
+ return {
65121
+ "Tool Name": tool3,
65122
+ Calls: stats.calls,
65123
+ Success: stats.success,
65124
+ Errors: stats.errors,
65125
+ "Success Rate": `${successRate.toFixed(2)}%`
65126
+ };
65127
+ });
65128
+ customConsole.table(tableData);
65129
+ } else {
65130
+ customConsole.log("No tools were called.");
65131
+ }
65132
+ }
65133
+ var mergeToolCallStats = (a, b) => {
65134
+ const merged = new Map;
65135
+ for (const [tool3, stat] of a) {
65136
+ merged.set(tool3, { ...stat });
65137
+ }
65138
+ for (const [tool3, stat] of b) {
65139
+ const existing = merged.get(tool3);
65140
+ if (existing) {
65141
+ existing.calls += stat.calls;
65142
+ existing.success += stat.success;
65143
+ existing.errors += stat.errors;
65144
+ } else {
65145
+ merged.set(tool3, { ...stat });
65146
+ }
65147
+ }
65148
+ return merged;
65149
+ };
65150
+ function logGlobalToolCallStats(stream) {
65151
+ const merged = mergeToolCallStats(globalToolCallStats, taskToolCallStats);
65152
+ logToolCallStats(stream, merged, "Global Tool Call Stats");
65153
+ }
64833
65154
  var printEvent = (verbose, usageMeter, stream = process.stdout) => {
64834
65155
  if (verbose < 0) {
64835
65156
  return () => {};
64836
65157
  }
64837
65158
  const customConsole = new Console(stream, stream);
64838
65159
  let hadReasoning = false;
65160
+ let hasText = false;
64839
65161
  const write = stream.write.bind(stream);
64840
65162
  return (event) => {
64841
65163
  switch (event.kind) {
64842
65164
  case "StartTask" /* StartTask */:
64843
- toolCallStats.clear();
65165
+ taskToolCallStats.clear();
64844
65166
  if (verbose > 2) {
64845
65167
  customConsole.log(`
64846
65168
  ====== System Prompt ======
@@ -64852,10 +65174,13 @@ ${event.systemPrompt}`);
64852
65174
  }
64853
65175
  break;
64854
65176
  case "StartRequest" /* StartRequest */:
64855
- customConsole.log(`
65177
+ hasText = false;
65178
+ if (verbose > 0) {
65179
+ customConsole.log(`
64856
65180
 
64857
65181
  ======== New Request ========
64858
65182
  `);
65183
+ }
64859
65184
  if (verbose > 1) {
64860
65185
  for (const message of event.userMessage) {
64861
65186
  const userMessage = message.content;
@@ -64899,10 +65224,17 @@ ${event.systemPrompt}`);
64899
65224
  }
64900
65225
  break;
64901
65226
  case "EndRequest" /* EndRequest */:
64902
- customConsole.log(`
65227
+ if (verbose > 0) {
65228
+ customConsole.log(`
64903
65229
 
64904
65230
  ======== Request Ended ========
64905
65231
  `);
65232
+ }
65233
+ if (verbose === 0 && hasText) {
65234
+ write(`
65235
+
65236
+ `);
65237
+ }
64906
65238
  if (verbose > 1) {
64907
65239
  customConsole.log(usageMeter.getUsageText());
64908
65240
  }
@@ -64914,27 +65246,34 @@ ${event.systemPrompt}`);
64914
65246
  `);
64915
65247
  hadReasoning = false;
64916
65248
  }
65249
+ if (event.newText.trim().length > 0) {
65250
+ hasText = true;
65251
+ }
64917
65252
  write(event.newText);
64918
65253
  break;
64919
65254
  }
64920
65255
  case "Reasoning" /* Reasoning */: {
64921
- write(source_default.dim(event.newText));
64922
- hadReasoning = true;
65256
+ if (verbose > 0) {
65257
+ write(source_default.dim(event.newText));
65258
+ hadReasoning = true;
65259
+ }
64923
65260
  break;
64924
65261
  }
64925
65262
  case "ToolUse" /* ToolUse */: {
64926
- customConsole.log(source_default.yellow(`
65263
+ if (verbose > 0) {
65264
+ customConsole.log(source_default.yellow(`
64927
65265
 
64928
- Tool use:`, event.tool), event.params);
64929
- const stats = toolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
65266
+ Tool use:`, event.tool), simplifyToolParameters(event.tool, event.params));
65267
+ }
65268
+ const stats = taskToolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
64930
65269
  stats.calls++;
64931
- toolCallStats.set(event.tool, stats);
65270
+ taskToolCallStats.set(event.tool, stats);
64932
65271
  break;
64933
65272
  }
64934
65273
  case "ToolReply" /* ToolReply */: {
64935
- const stats = toolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
65274
+ const stats = taskToolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
64936
65275
  stats.success++;
64937
- toolCallStats.set(event.tool, stats);
65276
+ taskToolCallStats.set(event.tool, stats);
64938
65277
  break;
64939
65278
  }
64940
65279
  case "ToolError" /* ToolError */: {
@@ -64942,9 +65281,9 @@ Tool use:`, event.tool), event.params);
64942
65281
 
64943
65282
  Tool error:`, event.tool));
64944
65283
  customConsole.error(event.error);
64945
- const stats = toolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
65284
+ const stats = taskToolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
64946
65285
  stats.errors++;
64947
- toolCallStats.set(event.tool, stats);
65286
+ taskToolCallStats.set(event.tool, stats);
64948
65287
  break;
64949
65288
  }
64950
65289
  case "UsageExceeded" /* UsageExceeded */:
@@ -64960,27 +65299,27 @@ Tool error:`, event.tool));
64960
65299
  `);
64961
65300
  customConsole.log("Reason:", event.exitReason.type);
64962
65301
  switch (event.exitReason.type) {
65302
+ case "Error": {
65303
+ const { error: error46 } = event.exitReason;
65304
+ customConsole.error(source_default.red(`Workflow failed: ${error46.message}`));
65305
+ if (verbose > 0 && error46.stack) {
65306
+ customConsole.error(source_default.red(error46.stack));
65307
+ }
65308
+ break;
65309
+ }
64963
65310
  case "Exit" /* Exit */:
64964
65311
  customConsole.log("Exit Message:", event.exitReason.message);
64965
65312
  break;
64966
65313
  }
64967
- customConsole.log(`
64968
-
64969
- ======== Tool Call Stats ========`);
64970
- if (toolCallStats.size > 0) {
64971
- const tableData = [...toolCallStats.entries()].map(([tool3, stats]) => {
64972
- const successRate = stats.calls > 0 ? stats.success / stats.calls * 100 : 0;
64973
- return {
64974
- "Tool Name": tool3,
64975
- Calls: stats.calls,
64976
- Success: stats.success,
64977
- Errors: stats.errors,
64978
- "Success Rate": `${successRate.toFixed(2)}%`
64979
- };
64980
- });
64981
- customConsole.table(tableData);
64982
- } else {
64983
- customConsole.log("No tools were called.");
65314
+ for (const [tool3, taskStats] of taskToolCallStats.entries()) {
65315
+ const globalStats = globalToolCallStats.get(tool3) ?? { calls: 0, success: 0, errors: 0 };
65316
+ globalStats.calls += taskStats.calls;
65317
+ globalStats.success += taskStats.success;
65318
+ globalStats.errors += taskStats.errors;
65319
+ globalToolCallStats.set(tool3, globalStats);
65320
+ }
65321
+ if (verbose > 0) {
65322
+ logToolCallStats(stream, taskToolCallStats, "Task Tool Call Stats");
64984
65323
  }
64985
65324
  break;
64986
65325
  }
@@ -77469,7 +77808,7 @@ function annotateDiffWithLineNumbers(diff) {
77469
77808
  }
77470
77809
 
77471
77810
  // src/tools/gitDiff.ts
77472
- var toolInfo17 = {
77811
+ var toolInfo18 = {
77473
77812
  name: "git_diff",
77474
77813
  description: "Get the git diff for the current repository. Can be used to get staged changes, unstaged changes, or changes between commits. By default, it returns unstaged changes.",
77475
77814
  parameters: exports_external.object({
@@ -77498,7 +77837,7 @@ var toolInfo17 = {
77498
77837
  }, exports_external.boolean().optional().default(false)).describe("Annotate the diff with line numbers for additions and deletions.")
77499
77838
  })
77500
77839
  };
77501
- var handler17 = async (provider3, args) => {
77840
+ var handler18 = async (provider3, args) => {
77502
77841
  if (!provider3.executeCommand) {
77503
77842
  return {
77504
77843
  type: "Error" /* Error */,
@@ -77508,7 +77847,7 @@ var handler17 = async (provider3, args) => {
77508
77847
  }
77509
77848
  };
77510
77849
  }
77511
- const { staged, file: file2, commitRange, contextLines, includeLineNumbers } = toolInfo17.parameters.parse(args);
77850
+ const { staged, file: file2, commitRange, contextLines, includeLineNumbers } = toolInfo18.parameters.parse(args);
77512
77851
  const commandParts = ["git", "diff", "--no-color", `-U${contextLines}`];
77513
77852
  if (staged) {
77514
77853
  commandParts.push("--staged");
@@ -77565,8 +77904,8 @@ ${result.stderr}`
77565
77904
  }
77566
77905
  };
77567
77906
  var gitDiff_default = {
77568
- ...toolInfo17,
77569
- handler: handler17
77907
+ ...toolInfo18,
77908
+ handler: handler18
77570
77909
  };
77571
77910
  // src/utils/cacheControl.ts
77572
77911
  var CACHEABLE_MODELS = ["sonnet", "opus", "haiku", "gemini"];
@@ -77889,17 +78228,18 @@ var allTools = [
77889
78228
  listFiles_default,
77890
78229
  readBinaryFile_default,
77891
78230
  readFile_default,
77892
- appendMemory_default,
77893
78231
  readMemory_default,
77894
- replaceMemory_default,
77895
- removeMemory_default,
77896
78232
  listMemoryTopics_default,
78233
+ updateMemory_default,
77897
78234
  removeFile_default,
77898
78235
  renameFile_default,
77899
78236
  replaceInFile_default,
77900
78237
  searchFiles_default,
77901
78238
  writeToFile_default,
77902
- gitDiff_default
78239
+ gitDiff_default,
78240
+ getTodoItem_default,
78241
+ listTodoItems_default,
78242
+ updateTodoItem_default
77903
78243
  ];
77904
78244
  var toolHandlers = new Map(allTools.map((t) => [t.name, t]));
77905
78245
  async function createPullRequest(input, _context) {
@@ -77944,6 +78284,7 @@ async function confirm(input, context) {
77944
78284
  }
77945
78285
  await new Promise((resolve4) => setTimeout(resolve4, 50));
77946
78286
  try {
78287
+ process.stderr.write("\x07");
77947
78288
  const result = await esm_default2({ message: input.message });
77948
78289
  return result;
77949
78290
  } catch (_e) {
@@ -77955,6 +78296,7 @@ async function input(input2, context) {
77955
78296
  return input2.default ?? "";
77956
78297
  }
77957
78298
  await new Promise((resolve4) => setTimeout(resolve4, 50));
78299
+ process.stderr.write("\x07");
77958
78300
  const result = await getUserInput(input2.message, {
77959
78301
  default: input2.default
77960
78302
  });
@@ -77969,6 +78311,7 @@ async function select(input2, context) {
77969
78311
  }
77970
78312
  await new Promise((resolve4) => setTimeout(resolve4, 50));
77971
78313
  try {
78314
+ process.stderr.write("\x07");
77972
78315
  const result = await esm_default5({ message: input2.message, choices: input2.choices });
77973
78316
  return result;
77974
78317
  } catch (_e) {
@@ -78158,17 +78501,22 @@ ${defaultContent}
78158
78501
  return contextParts.join(`
78159
78502
  `);
78160
78503
  }
78161
- async function appendMemory(input2, context) {
78504
+ async function updateMemory(input2, context) {
78162
78505
  const provider3 = context.toolProvider;
78163
- await provider3.appendMemory(input2.topic, input2.content);
78506
+ const content = "content" in input2 ? input2.content : undefined;
78507
+ return provider3.updateMemory(input2.operation, input2.topic, content);
78164
78508
  }
78165
- async function replaceMemory(input2, context) {
78509
+ async function listTodoItems(input2, context) {
78166
78510
  const provider3 = context.toolProvider;
78167
- await provider3.replaceMemory(input2.topic, input2.content);
78511
+ return provider3.listTodoItems(input2.id, input2.status);
78168
78512
  }
78169
- async function removeMemory(input2, context) {
78513
+ async function getTodoItem(input2, context) {
78170
78514
  const provider3 = context.toolProvider;
78171
- await provider3.removeMemory(input2.topic);
78515
+ return provider3.getTodoItem(input2.id);
78516
+ }
78517
+ async function updateTodoItem(input2, context) {
78518
+ const provider3 = context.toolProvider;
78519
+ return provider3.updateTodoItem(input2);
78172
78520
  }
78173
78521
  var localToolHandlers = {
78174
78522
  createPullRequest,
@@ -78184,14 +78532,15 @@ var localToolHandlers = {
78184
78532
  invokeTool,
78185
78533
  taskEvent,
78186
78534
  getMemoryContext,
78187
- appendMemory,
78188
- replaceMemory,
78189
- removeMemory
78535
+ updateMemory,
78536
+ listTodoItems,
78537
+ getTodoItem,
78538
+ updateTodoItem
78190
78539
  };
78191
78540
  async function toolCall(toolCall2, context) {
78192
- const handler18 = localToolHandlers[toolCall2.tool];
78193
- if (handler18) {
78194
- return handler18(toolCall2.input, context);
78541
+ const handler19 = localToolHandlers[toolCall2.tool];
78542
+ if (handler19) {
78543
+ return handler19(toolCall2.input, context);
78195
78544
  }
78196
78545
  throw new Error(`Unknown tool: ${toolCall2.tool}`);
78197
78546
  }
@@ -78256,19 +78605,27 @@ async function runWorkflow(workflow2, workflowInput, options) {
78256
78605
  try {
78257
78606
  logger.info("Running workflow...");
78258
78607
  const output = await workflow2(workflowInput, context);
78259
- logger.info("Workflow completed successfully.");
78608
+ logger.info(`
78609
+
78610
+ Workflow completed successfully.`);
78260
78611
  logger.info(usage.getUsageText());
78261
78612
  return output;
78262
78613
  } catch (e) {
78263
78614
  const error46 = e;
78615
+ onEvent({
78616
+ kind: "EndTask" /* EndTask */,
78617
+ exitReason: {
78618
+ type: "Error",
78619
+ error: { message: error46.message, stack: error46.stack }
78620
+ }
78621
+ });
78264
78622
  if (error46 instanceof UserCancelledError) {
78265
78623
  logger.warn("Workflow cancelled by user.");
78266
- } else {
78267
- logger.error(`Workflow failed: ${error46.message}`);
78268
- logger.error(error46);
78269
78624
  }
78270
78625
  logger.info(usage.getUsageText());
78271
78626
  return;
78627
+ } finally {
78628
+ logGlobalToolCallStats(process.stderr);
78272
78629
  }
78273
78630
  }
78274
78631
 
@@ -78280,14 +78637,23 @@ ${JSON.stringify(schema, null, 2)}
78280
78637
  \`\`\`
78281
78638
  `;
78282
78639
  }
78640
+ var TOOL_USAGE_INSTRUCTION = `When you use a tool, you MUST first provide a short summary of what you are doing and why you are using that tool. This summary will be shown to the user to explain your actions.`;
78283
78641
  var MEMORY_USAGE_SECTION = `## Memory Usage
78284
78642
 
78285
78643
  You have access to a memory feature to store and retrieve information across tool calls.
78286
78644
 
78287
- Use memory to:
78288
- - Store context between steps.
78289
- - Keep track of important information like file paths or decisions made.
78290
- - Avoid re-running expensive discovery tools.
78645
+ ### Topic Organization
78646
+
78647
+ Memory is organized using topics, which are like named containers for different types of information:
78648
+ - **Default topic** (\`:default:\`): Used when no topic is specified. Good for general context.
78649
+ - **Named topics**: Create meaningful topic names to organize different types of information
78650
+
78651
+ ### Best Practices
78652
+
78653
+ - Store decisions and context that inform subsequent steps
78654
+ - Use named topics to organize different types of information
78655
+ - Use the default topic for simple, single-context scenarios
78656
+ - Memory persists across all tool calls within the current workflow
78291
78657
  `;
78292
78658
  var PLANNER_SYSTEM_PROMPT = `Role: Expert software architect and planner.
78293
78659
  Goal: Analyze user requests and create detailed, actionable implementation plans for software development tasks.
@@ -78296,6 +78662,8 @@ You are an expert software architect and planner with deep experience in breakin
78296
78662
 
78297
78663
  ${MEMORY_USAGE_SECTION}
78298
78664
 
78665
+ ${TOOL_USAGE_INSTRUCTION}
78666
+
78299
78667
  ## Your Role
78300
78668
 
78301
78669
  As a planner, your expertise lies in:
@@ -78303,7 +78671,8 @@ As a planner, your expertise lies in:
78303
78671
  - Exploring codebases to identify patterns, conventions, and integration points
78304
78672
  - Breaking down complex tasks into clear, logical sequences of steps
78305
78673
  - Anticipating dependencies, edge cases, and potential challenges
78306
- - Creating plans that are specific, actionable, and implementable by other developers or AI agents
78674
+ - Creating plans that can be executed autonomously by an AI coding agent
78675
+ - Providing technical specificity required for autonomous implementation
78307
78676
 
78308
78677
  ## Planning Philosophy
78309
78678
 
@@ -78322,16 +78691,39 @@ Effective planning requires understanding before action:
78322
78691
  - Understanding context prevents suggesting solutions that don't fit the project
78323
78692
 
78324
78693
  3. **Specificity Over Generality**
78325
- - Vague plans lead to implementation confusion
78694
+ - Vague plans lead to implementation confusion and prevent autonomous execution
78326
78695
  - Instead of "implement the feature," specify which files to modify, what functions to add, and what logic to implement
78327
78696
  - Name specific components, modules, or files when possible
78328
78697
  - Describe what needs to change and why
78329
-
78330
- 4. **Clarity for AI and Human Implementers**
78331
- - Plans should be understandable and actionable by someone else
78332
- - Each step should have a clear deliverable
78333
- - Break complex tasks into smaller, logical units
78698
+ - Examples:
78699
+ * Vague: "Implement the feature"
78700
+ * Specific: "Create \`src/components/LoginForm.tsx\` with a React component that includes email and password fields, using the existing \`useAuth\` hook from \`src/hooks/useAuth.ts\`"
78701
+ * Vague: "Add error handling"
78702
+ * ✅ Specific: "In \`src/api/client.ts\`, wrap the fetch call in a try-catch block and throw custom errors using the \`ApiError\` class from \`src/errors.ts\`"
78703
+
78704
+ 4. **Clarity for AI Coding Agents**
78705
+ - Plans will be executed autonomously by an AI coding agent without human intervention
78706
+ - Break complex tasks into smaller, logical units that can be completed independently
78334
78707
  - Use clear structure (numbered lists, narrative text, or combined formats) to organize steps
78708
+ - Include exact file paths, function names, and implementation patterns
78709
+
78710
+ ## Planning for AI Implementation
78711
+
78712
+ Plans will be executed by an AI coding agent that operates autonomously with the following capabilities:
78713
+
78714
+ **Planning Requirements:**
78715
+ Plans should include specific technical details to enable autonomous implementation:
78716
+ - **Function/class names**: Name specific functions, classes, or components to implement
78717
+ - **Implementation patterns**: Reference existing patterns or provide clear guidance on approach
78718
+ - **Import statements**: Specify required dependencies and where to import them from
78719
+ - **Technical constraints**: Note any architectural decisions, performance requirements, or compatibility concerns
78720
+
78721
+ **What Makes a Good AI-Actionable Plan:**
78722
+ - Each step can be completed using the available tools
78723
+ - File paths and code structures are explicitly named
78724
+ - Dependencies between steps are clear
78725
+ - Implementation approach follows existing codebase patterns
78726
+ - Technical requirements are specific, not general
78335
78727
 
78336
78728
  ## Your Approach
78337
78729
 
@@ -78408,9 +78800,11 @@ When generating your plan, follow these formatting guidelines:
78408
78800
  2. Implement feature B
78409
78801
  3. Write tests
78410
78802
 
78411
- 5. Only include relevant details for AI Agents:
78412
- a. Avoid unnecessary technical jargon or implementation details
78413
- b. Avoid steps that require human intervention or cannot be done by an AI agent
78803
+ 5. Include implementation-ready details for AI agents:
78804
+ a. Provide specific technical details the coding agent needs (file paths, function signatures, etc.)
78805
+ b. Avoid steps that require human intervention or manual processes
78806
+ c. Each step should be implementable using the AI agent's available tools
78807
+ d. Reference existing code patterns and conventions from the codebase
78414
78808
 
78415
78809
  **Note**: Plans should use flexible formats such as numbered lists or narrative text. Checklist formats (markdown checkboxes) are NOT required and should only be used when specifically appropriate for tracking independent action items.
78416
78810
 
@@ -78455,6 +78849,8 @@ You are an expert software architect specializing in creating high-level plans f
78455
78849
 
78456
78850
  ${MEMORY_USAGE_SECTION}
78457
78851
 
78852
+ ${TOOL_USAGE_INSTRUCTION}
78853
+
78458
78854
  ## Your Role
78459
78855
 
78460
78856
  As a high-level planner for epics, your expertise lies in:
@@ -78572,9 +78968,12 @@ ${createJsonResponseInstruction({
78572
78968
  reason: "If no plan is needed, provide a reason here."
78573
78969
  })}
78574
78970
  `;
78971
+ var BRANCH_NAME_PATTERN = /^[a-zA-Z0-9/_-]+$/;
78575
78972
  var EpicPlanSchema = exports_external.object({
78576
78973
  plan: exports_external.string().nullish(),
78577
- branchName: exports_external.string(),
78974
+ branchName: exports_external.string().refine((name18) => name18.length >= 3, { message: "Branch name is too short (min 3 characters)." }).refine((name18) => name18.length <= 255, { message: "Branch name is too long (max 255 characters)." }).refine((name18) => BRANCH_NAME_PATTERN.test(name18), {
78975
+ message: "Invalid branch name format. Branch names should contain only letters, numbers, hyphens, underscores, and forward slashes."
78976
+ }),
78578
78977
  question: exports_external.object({
78579
78978
  question: exports_external.string(),
78580
78979
  defaultAnswer: exports_external.string().nullish()
@@ -78596,57 +78995,23 @@ ${task}
78596
78995
  </task>
78597
78996
  ${planSection}`;
78598
78997
  }
78599
- var EPIC_PLAN_UPDATE_SYSTEM_PROMPT = `Role: Plan update agent
78600
- Goal: Update the epic plan by marking the completed item and determining if work is complete
78998
+ var EPIC_ADD_TODO_ITEMS_SYSTEM_PROMPT = `Role: Task creation agent
78999
+ Goal: Read a high-level plan and create corresponding todo items.
78601
79000
 
78602
- You are a plan update agent responsible for tracking progress on an epic by updating the plan.
79001
+ ${TOOL_USAGE_INSTRUCTION}
78603
79002
 
78604
- ${MEMORY_USAGE_SECTION}
79003
+ You are a task creation agent. Your responsibility is to read a high-level plan for an epic and create a todo item for each task in the plan.
78605
79004
 
78606
79005
  ## Your Task
78607
79006
 
78608
- You will receive:
78609
- - **Current plan** (may use checkboxes \`- [ ]\`/\`- [x]\`, numbered lists, or other formats)
78610
- - **Implementation summary** describing what was just completed
78611
- - **The specific task** that was just implemented
79007
+ You will have access to the high-level plan stored in memory under the topic 'epic-plan'.
79008
+ Read the plan and for each task item in the plan, use the 'updateTodoItem' tool to create a new todo item.
78612
79009
 
78613
79010
  ## Process
78614
79011
 
78615
- 1. **Find the completed item**: Locate the item in the plan that matches the completed task
78616
- 2. **Mark it as complete**:
78617
- - If using checkboxes: Change \`- [ ]\` to \`- [x]\`
78618
- - If using numbered lists: Add a ✅ prefix (e.g., "1. Task" → "✅ 1. Task")
78619
- - If using narrative: Mark completion in context-appropriate way
78620
- 3. **Scan for next task**: Find the next incomplete item
78621
- 4. **Determine completion status**: Check if all items are complete
78622
-
78623
- ## Output Requirements
78624
-
78625
- Return:
78626
- - **updatedPlan**: The full plan text with the completed item marked
78627
- - **isComplete**: boolean - true if all items are done, false if incomplete items remain
78628
- - **nextTask**: The text of the next incomplete item, or null if all items are complete
78629
-
78630
- ## Important Notes
78631
-
78632
- - Keep the plan structure and formatting intact
78633
- - Adapt completion marking to match the plan's format
78634
- - Extract the next task text without format prefixes (e.g., without "- [ ]" or "1.")
78635
- - If multiple incomplete items remain, return the first one in document order
78636
-
78637
- ## Response Format
78638
-
78639
- ${createJsonResponseInstruction({
78640
- updatedPlan: "The full plan with completed item marked",
78641
- isComplete: false,
78642
- nextTask: "The text of the next incomplete item (or null if complete)"
78643
- })}
79012
+ 1. Parse the plan to identify individual tasks.
79013
+ 2. For each task, call 'updateTodoItem' with the task description as the 'title'.
78644
79014
  `;
78645
- var UpdatedPlanSchema = exports_external.object({
78646
- updatedPlan: exports_external.string().describe("The updated plan with completed item marked as [x]"),
78647
- isComplete: exports_external.boolean().describe("True if all checklist items are completed, false if incomplete items remain"),
78648
- nextTask: exports_external.string().nullish().describe("The next incomplete checklist item to implement, or null if complete")
78649
- });
78650
79015
  var CODER_SYSTEM_PROMPT = `Role: AI developer.
78651
79016
  Goal: Implement the provided plan by writing and modifying code.
78652
79017
 
@@ -78654,6 +79019,8 @@ Your task is to implement the plan created and approved in Phase 1.
78654
79019
 
78655
79020
  ${MEMORY_USAGE_SECTION}
78656
79021
 
79022
+ ${TOOL_USAGE_INSTRUCTION}
79023
+
78657
79024
  ## Implementation Guidelines
78658
79025
 
78659
79026
  ### 1. Plan Analysis
@@ -78727,6 +79094,8 @@ You are an expert software developer. Your task is to fix a project that is fail
78727
79094
 
78728
79095
  ${MEMORY_USAGE_SECTION}
78729
79096
 
79097
+ ${TOOL_USAGE_INSTRUCTION}
79098
+
78730
79099
  After making changes, you MUST return a JSON object in a markdown block with either a summary of the changes OR a bailReason if you cannot complete the task.
78731
79100
 
78732
79101
  Example for successful fix:
@@ -78764,6 +79133,8 @@ ${stderr || "(empty)"}
78764
79133
  var CODE_REVIEW_SYSTEM_PROMPT = `Role: Senior software engineer.
78765
79134
  Goal: Review code changes and provide specific, actionable feedback on any issues found.
78766
79135
 
79136
+ ${TOOL_USAGE_INSTRUCTION}
79137
+
78767
79138
  # Code Review Prompt
78768
79139
 
78769
79140
  You are a senior software engineer reviewing code changes.
@@ -78878,6 +79249,8 @@ ${instructions}
78878
79249
  var COMMIT_MESSAGE_SYSTEM_PROMPT = `Role: Expert git user.
78879
79250
  Goal: Generate a concise and descriptive commit message in conventional commit format based on staged changes.
78880
79251
 
79252
+ ${TOOL_USAGE_INSTRUCTION}
79253
+
78881
79254
  You are an expert at writing git commit messages.
78882
79255
  Based on the provided list of staged files in <file_status>, the diff in <diff> and optional user context in <tool_input_context>, generate a concise and descriptive commit message.
78883
79256
 
@@ -78890,6 +79263,8 @@ ${createJsonResponseInstruction({
78890
79263
  var GET_PR_DETAILS_SYSTEM_PROMPT = `Role: Expert developer.
78891
79264
  Goal: Generate a pull request title and description based on the branch name, commits, and diff.
78892
79265
 
79266
+ ${TOOL_USAGE_INSTRUCTION}
79267
+
78893
79268
  You are an expert at creating pull requests.
78894
79269
  Based on the provided branch name, commit messages, and diff, generate a title and description for the pull request.
78895
79270
 
@@ -78902,6 +79277,8 @@ var INIT_WORKFLOW_ANALYZE_SYSTEM_PROMPT = `
78902
79277
  Role: Analyzer agent
78903
79278
  Goal: Produce a valid polkacodes YAML configuration for the project.
78904
79279
 
79280
+ ${TOOL_USAGE_INSTRUCTION}
79281
+
78905
79282
  Workflow
78906
79283
  1. Scan project files to identify the project's characteristics. Start using the "readFile" tool to understand the project's dependencies, scripts, and basic configuration.
78907
79284
  - Package/build tool (npm, bun, pnpm, etc.)
@@ -79060,9 +79437,7 @@ ${memoryContext}`
79060
79437
  removeFile_default,
79061
79438
  renameFile_default,
79062
79439
  readMemory_default,
79063
- appendMemory_default,
79064
- replaceMemory_default,
79065
- removeMemory_default,
79440
+ updateMemory_default,
79066
79441
  listMemoryTopics_default
79067
79442
  ],
79068
79443
  outputSchema: FixIterationSummarySchema
@@ -79077,7 +79452,7 @@ ${memoryContext}`
79077
79452
  }
79078
79453
  if (summary) {
79079
79454
  summaries.push(summary);
79080
- await tools2.appendMemory({ content: `Summary of changes for fix attempt ${i + 1}: ${summary}` });
79455
+ await tools2.updateMemory({ operation: "append", content: `Summary of changes for fix attempt ${i + 1}: ${summary}` });
79081
79456
  logger.info(`Summary of changes: ${summary}`);
79082
79457
  }
79083
79458
  }
@@ -79130,9 +79505,7 @@ ${defaultContext}`;
79130
79505
  fetchUrl_default,
79131
79506
  listMemoryTopics_default,
79132
79507
  readMemory_default,
79133
- appendMemory_default,
79134
- replaceMemory_default,
79135
- removeMemory_default
79508
+ updateMemory_default
79136
79509
  ];
79137
79510
  if (interactive) {
79138
79511
  agentTools.push(askFollowupQuestion_default);
@@ -79373,9 +79746,7 @@ ${fileContentString}`;
79373
79746
  removeFile_default,
79374
79747
  renameFile_default,
79375
79748
  readMemory_default,
79376
- appendMemory_default,
79377
- replaceMemory_default,
79378
- removeMemory_default,
79749
+ updateMemory_default,
79379
79750
  listMemoryTopics_default
79380
79751
  ];
79381
79752
  if (mode === "interactive") {
@@ -79419,7 +79790,8 @@ ${memoryContext}`
79419
79790
  summaries.push(summary);
79420
79791
  logger.info(`Summary: ${summary}`);
79421
79792
  await step("summarize-implementation", async () => {
79422
- await tools2.appendMemory({
79793
+ await tools2.updateMemory({
79794
+ operation: "append",
79423
79795
  topic: "implementation-summary",
79424
79796
  content: summary
79425
79797
  });
@@ -79851,107 +80223,6 @@ ${provider3.toUpperCase()}_API_KEY=${providerConfig.apiKey}`;
79851
80223
  };
79852
80224
  // src/workflows/epic.workflow.ts
79853
80225
  var MAX_REVIEW_RETRIES = 5;
79854
- var BRANCH_NAME_PATTERN = /^[a-zA-Z0-9/_-]+$/;
79855
- function validateBranchName(name18) {
79856
- if (!BRANCH_NAME_PATTERN.test(name18)) {
79857
- return {
79858
- valid: false,
79859
- error: `Invalid branch name format: "${name18}". Branch names should contain only letters, numbers, hyphens, underscores, and forward slashes.`
79860
- };
79861
- }
79862
- if (name18.length > 255) {
79863
- return { valid: false, error: "Branch name is too long (max 255 characters)." };
79864
- }
79865
- return { valid: true };
79866
- }
79867
- async function performReviewAndFixCycle(iterationCount, taskItem, currentPlan, context) {
79868
- const { logger, step, tools: tools2 } = context;
79869
- for (let i = 0;i < MAX_REVIEW_RETRIES; i++) {
79870
- const diffResult = await tools2.executeCommand({ command: "git", args: ["diff", "--name-status", "HEAD~1", "HEAD"] });
79871
- const changedFiles = parseGitDiffNameStatus(diffResult.stdout);
79872
- if (changedFiles.length === 0) {
79873
- logger.info(`ℹ️ No files were changed. Skipping review.
79874
- `);
79875
- return { passed: true };
79876
- }
79877
- logger.info(`
79878
- \uD83D\uDD0E Review iteration ${i + 1}/${MAX_REVIEW_RETRIES}`);
79879
- logger.info(` Changed files: ${changedFiles.length}`);
79880
- const changeInfo = {
79881
- commitRange: "HEAD~1...HEAD",
79882
- changedFiles
79883
- };
79884
- const reviewAgentResult = await step(`review-${iterationCount}-${i}`, async () => {
79885
- const defaultContext = await getDefaultContext();
79886
- const memoryContext = await tools2.getMemoryContext();
79887
- const userMessage = `${defaultContext}
79888
- ${memoryContext}
79889
-
79890
- ${formatReviewToolInput(changeInfo)}`;
79891
- return await agentWorkflow({
79892
- systemPrompt: CODE_REVIEW_SYSTEM_PROMPT,
79893
- userMessage: [{ role: "user", content: userMessage }],
79894
- tools: [
79895
- readFile_default,
79896
- readBinaryFile_default,
79897
- searchFiles_default,
79898
- listFiles_default,
79899
- gitDiff_default,
79900
- readMemory_default,
79901
- appendMemory_default,
79902
- replaceMemory_default,
79903
- removeMemory_default,
79904
- listMemoryTopics_default
79905
- ],
79906
- outputSchema: reviewOutputSchema
79907
- }, context);
79908
- });
79909
- if (reviewAgentResult.type !== "Exit" /* Exit */) {
79910
- logger.error(`\uD83D\uDEAB Review agent failed with status: ${reviewAgentResult.type}.`);
79911
- break;
79912
- }
79913
- const reviewResult = reviewAgentResult.object;
79914
- if (!reviewResult || !reviewResult.specificReviews || reviewResult.specificReviews.length === 0) {
79915
- logger.info(`✅ Review passed. No issues found.
79916
- `);
79917
- return { passed: true };
79918
- }
79919
- logger.warn(`⚠️ Review found ${reviewResult.specificReviews.length} issue(s). Attempting to fix...
79920
- `);
79921
- reviewResult.specificReviews.forEach((review, idx) => {
79922
- logger.warn(` ${idx + 1}. ${review.file}:${review.lines}`);
79923
- });
79924
- logger.warn("");
79925
- const reviewSummary = reviewResult.specificReviews.map((r) => `File: ${r.file} (lines: ${r.lines})
79926
- Review: ${r.review}`).join(`
79927
-
79928
- `);
79929
- const fixTask = `You are working on an epic. The original task was: "${taskItem}".
79930
-
79931
- Here is the full plan for context:
79932
- <plan>
79933
- ${currentPlan}
79934
- </plan>
79935
-
79936
- After an initial implementation, a review found the following issues. Please fix them:
79937
-
79938
- ${reviewSummary}`;
79939
- await step(`fix-${iterationCount}-${i}`, async () => {
79940
- await codeWorkflow({ task: fixTask, mode: "noninteractive" }, context);
79941
- });
79942
- await step(`commit-fix-${iterationCount}-${i}`, async () => {
79943
- await tools2.executeCommand({ command: "git", args: ["add", "."] });
79944
- await tools2.executeCommand({ command: "git", args: ["commit", "--amend", "--no-edit"] });
79945
- });
79946
- if (i === MAX_REVIEW_RETRIES - 1) {
79947
- logger.error(`
79948
- \uD83D\uDEAB Max retries (${MAX_REVIEW_RETRIES}) reached. Moving to the next task, but issues might remain.
79949
- `);
79950
- return { passed: false };
79951
- }
79952
- }
79953
- return { passed: false };
79954
- }
79955
80226
  async function createPlan2(input2, context) {
79956
80227
  const { task, plan, files, feedback } = input2;
79957
80228
  const content = [{ type: "text", text: getPlanPrompt(task, plan) }];
@@ -79991,9 +80262,7 @@ ${feedback}`
79991
80262
  readBinaryFile_default,
79992
80263
  searchFiles_default,
79993
80264
  readMemory_default,
79994
- appendMemory_default,
79995
- replaceMemory_default,
79996
- removeMemory_default,
80265
+ updateMemory_default,
79997
80266
  listMemoryTopics_default
79998
80267
  ],
79999
80268
  outputSchema: EpicPlanSchema
@@ -80003,37 +80272,113 @@ ${feedback}`
80003
80272
  }
80004
80273
  return { plan: "", reason: "Usage limit exceeded.", type: "Exit" /* Exit */, branchName: "" };
80005
80274
  }
80006
- async function updatePlanAgent(currentPlan, implementationSummary, completedTask, context) {
80007
- const userMessage = `# Current Plan
80008
-
80009
- <plan>
80010
- ${currentPlan}
80011
- </plan>
80012
-
80013
- # Implementation Summary
80014
-
80015
- ${implementationSummary}
80016
-
80017
- # Completed Task
80018
-
80019
- ${completedTask}
80020
-
80021
- Please update the plan by marking the completed task as [x] and identify the next incomplete task.`;
80022
- const result = await agentWorkflow({
80023
- systemPrompt: EPIC_PLAN_UPDATE_SYSTEM_PROMPT,
80024
- userMessage: [{ role: "user", content: userMessage }],
80025
- tools: [],
80026
- outputSchema: UpdatedPlanSchema
80027
- }, context);
80028
- if (result.type !== "Exit" /* Exit */ || !result.object) {
80029
- throw new Error("Plan update agent failed");
80275
+ async function createAndApprovePlan(task, context) {
80276
+ const { logger, step, tools: tools2 } = context;
80277
+ logger.info(`\uD83D\uDCDD Phase 2: Creating high-level plan...
80278
+ `);
80279
+ let feedback;
80280
+ let highLevelPlan;
80281
+ let branchName;
80282
+ let planAttempt = 1;
80283
+ try {
80284
+ while (true) {
80285
+ const result = await step(`plan-${planAttempt}`, () => createPlan2({ task, feedback }, context));
80286
+ planAttempt++;
80287
+ if (result.question) {
80288
+ const answer = await tools2.input({
80289
+ message: result.question.question,
80290
+ default: result.question.defaultAnswer || undefined
80291
+ });
80292
+ feedback = `The user answered the question "${result.question.question}" with: "${answer}"`;
80293
+ continue;
80294
+ }
80295
+ if (!result.plan) {
80296
+ if (result.reason) {
80297
+ logger.info(`No plan created. Reason: ${result.reason}`);
80298
+ } else {
80299
+ logger.info("No plan created.");
80300
+ }
80301
+ return null;
80302
+ }
80303
+ logger.info(`\uD83D\uDCDD Plan:
80304
+ ${result.plan}`);
80305
+ if (result.branchName) {
80306
+ logger.info(`\uD83C\uDF3F Suggested branch name: ${result.branchName}`);
80307
+ }
80308
+ feedback = await tools2.input({ message: "Press Enter to approve the plan, or provide feedback to refine it." });
80309
+ if (feedback.trim() === "") {
80310
+ highLevelPlan = result.plan;
80311
+ branchName = result.branchName;
80312
+ break;
80313
+ }
80314
+ }
80315
+ } catch (e) {
80316
+ if (e instanceof UserCancelledError) {
80317
+ logger.info("Plan creation cancelled by user.");
80318
+ return null;
80319
+ }
80320
+ throw e;
80030
80321
  }
80031
- const updateResult = result.object;
80032
- return {
80033
- updatedPlan: updateResult.updatedPlan,
80034
- isComplete: updateResult.isComplete,
80035
- nextTask: updateResult.nextTask || null
80036
- };
80322
+ if (!highLevelPlan) {
80323
+ logger.info("Plan not approved. Exiting.");
80324
+ return null;
80325
+ }
80326
+ if (!branchName) {
80327
+ logger.error("❌ Error: No branch name was generated from the plan. Exiting.");
80328
+ return null;
80329
+ }
80330
+ logger.info(`✅ High-level plan approved.
80331
+ `);
80332
+ return { plan: highLevelPlan, branchName };
80333
+ }
80334
+ async function createFeatureBranch(branchName, context) {
80335
+ const { logger, step, tools: tools2 } = context;
80336
+ logger.info(`\uD83C\uDF3F Phase 3: Creating feature branch...
80337
+ `);
80338
+ let finalBranchName = branchName;
80339
+ const initialCheckResult = await step("checkBranch-initial", async () => await tools2.executeCommand({ command: "git", args: ["rev-parse", "--verify", finalBranchName] }));
80340
+ if (initialCheckResult.exitCode === 0) {
80341
+ logger.warn(`⚠️ Branch '${finalBranchName}' already exists. Trying to find an available name...`);
80342
+ const suffixMatch = branchName.match(/-(\d+)$/);
80343
+ let baseName = branchName;
80344
+ let counter = 2;
80345
+ if (suffixMatch) {
80346
+ baseName = branchName.substring(0, suffixMatch.index);
80347
+ counter = parseInt(suffixMatch[1], 10) + 1;
80348
+ }
80349
+ while (true) {
80350
+ finalBranchName = `${baseName}-${counter}`;
80351
+ const branchCheckResult = await step(`checkBranch-${counter}`, async () => await tools2.executeCommand({ command: "git", args: ["rev-parse", "--verify", finalBranchName] }));
80352
+ if (branchCheckResult.exitCode !== 0) {
80353
+ break;
80354
+ }
80355
+ counter++;
80356
+ }
80357
+ }
80358
+ if (finalBranchName !== branchName) {
80359
+ logger.info(`Branch name '${branchName}' was taken. Using '${finalBranchName}' instead.`);
80360
+ }
80361
+ await step("createBranch", async () => await tools2.executeCommand({ command: "git", args: ["checkout", "-b", finalBranchName] }));
80362
+ logger.info(`✅ Branch '${finalBranchName}' created.
80363
+ `);
80364
+ return { success: true, branchName: finalBranchName };
80365
+ }
80366
+ async function addTodoItemsFromPlan(plan, context) {
80367
+ const { logger, step, tools: tools2 } = context;
80368
+ logger.info(`\uD83D\uDCDD Phase 4: Creating todo items from plan...
80369
+ `);
80370
+ await step("add-todo-items", async () => {
80371
+ await agentWorkflow({
80372
+ systemPrompt: EPIC_ADD_TODO_ITEMS_SYSTEM_PROMPT,
80373
+ userMessage: [{ role: "user", content: `Please create the todo items based on the plan
80374
+ <plan>
80375
+ ${plan}</plan>` }],
80376
+ tools: [readFile_default, searchFiles_default, listFiles_default, readMemory_default, getTodoItem_default, listTodoItems_default, updateTodoItem_default, updateMemory_default, listMemoryTopics_default]
80377
+ }, context);
80378
+ });
80379
+ const todos = await tools2.listTodoItems({});
80380
+ logger.info(`✅ Created ${todos.length} todo items.
80381
+ `);
80037
80382
  }
80038
80383
  async function runPreflightChecks(context) {
80039
80384
  const { logger, step, tools: tools2 } = context;
@@ -80055,261 +80400,336 @@ async function runPreflightChecks(context) {
80055
80400
  `);
80056
80401
  return { success: true };
80057
80402
  }
80058
- var epicWorkflow = async (input2, context) => {
80403
+ async function performReviewAndFixCycle(iterationCount, taskItem, highLevelPlan, context) {
80059
80404
  const { logger, step, tools: tools2 } = context;
80060
- const { task } = input2;
80061
- const workflowStartTime = Date.now();
80062
- const commitMessages = [];
80063
- if (!task || task.trim() === "") {
80064
- logger.error("❌ Error: Task cannot be empty. Please provide a valid task description.");
80065
- return;
80066
- }
80067
- const preflightResult = await runPreflightChecks(context);
80068
- if (!preflightResult.success) {
80069
- return;
80070
- }
80071
- async function createAndApprovePlan(task2, context2) {
80072
- const { logger: logger2, step: step2, tools: tools3 } = context2;
80073
- logger2.info(`\uD83D\uDCDD Phase 2: Creating high-level plan...
80405
+ for (let i = 0;i < MAX_REVIEW_RETRIES; i++) {
80406
+ const diffResult = await tools2.executeCommand({ command: "git", args: ["diff", "--name-status", "HEAD~1", "HEAD"] });
80407
+ const changedFiles = parseGitDiffNameStatus(diffResult.stdout);
80408
+ if (changedFiles.length === 0) {
80409
+ logger.info(`ℹ️ No files were changed. Skipping review.
80074
80410
  `);
80075
- let feedback;
80076
- let highLevelPlan2;
80077
- let branchName2;
80078
- try {
80079
- while (true) {
80080
- const result = await step2("plan", () => createPlan2({ task: task2, feedback }, context2));
80081
- if (result.question) {
80082
- const answer = await tools3.input({
80083
- message: result.question.question,
80084
- default: result.question.defaultAnswer || undefined
80085
- });
80086
- feedback = `The user answered the question "${result.question.question}" with: "${answer}"`;
80087
- continue;
80088
- }
80089
- if (!result.plan) {
80090
- if (result.reason) {
80091
- logger2.info(`No plan created. Reason: ${result.reason}`);
80092
- } else {
80093
- logger2.info("No plan created.");
80094
- }
80095
- return null;
80096
- }
80097
- logger2.info(`\uD83D\uDCDD Plan:
80098
- ${result.plan}`);
80099
- if (result.branchName) {
80100
- logger2.info(`\uD83C\uDF3F Suggested branch name: ${result.branchName}`);
80101
- }
80102
- feedback = await tools3.input({ message: "Press Enter to approve the plan, or provide feedback to refine it." });
80103
- if (feedback.trim() === "") {
80104
- highLevelPlan2 = result.plan;
80105
- branchName2 = result.branchName;
80106
- break;
80107
- }
80108
- }
80109
- } catch (e) {
80110
- if (e instanceof UserCancelledError) {
80111
- logger2.info("Plan creation cancelled by user.");
80112
- return null;
80113
- }
80114
- throw e;
80115
- }
80116
- if (!highLevelPlan2) {
80117
- logger2.info("Plan not approved. Exiting.");
80118
- return null;
80411
+ return { passed: true };
80119
80412
  }
80120
- if (!branchName2) {
80121
- logger2.error("❌ Error: No branch name was generated from the plan. Exiting.");
80122
- return null;
80413
+ logger.info(`
80414
+ \uD83D\uDD0E Review iteration ${i + 1}/${MAX_REVIEW_RETRIES}`);
80415
+ logger.info(` Changed files: ${changedFiles.length}`);
80416
+ const changeInfo = {
80417
+ commitRange: "HEAD~1...HEAD",
80418
+ changedFiles
80419
+ };
80420
+ const reviewAgentResult = await step(`review-${iterationCount}-${i}`, async () => {
80421
+ const defaultContext = await getDefaultContext();
80422
+ const memoryContext = await tools2.getMemoryContext();
80423
+ const userMessage = `${defaultContext}
80424
+ ${memoryContext}
80425
+
80426
+ ${formatReviewToolInput(changeInfo)}`;
80427
+ return await agentWorkflow({
80428
+ systemPrompt: CODE_REVIEW_SYSTEM_PROMPT,
80429
+ userMessage: [{ role: "user", content: userMessage }],
80430
+ tools: [readFile_default, readBinaryFile_default, searchFiles_default, listFiles_default, gitDiff_default, readMemory_default, updateMemory_default, listMemoryTopics_default],
80431
+ outputSchema: reviewOutputSchema
80432
+ }, context);
80433
+ });
80434
+ if (reviewAgentResult.type !== "Exit" /* Exit */) {
80435
+ logger.error(`\uD83D\uDEAB Review agent failed with status: ${reviewAgentResult.type}.`);
80436
+ break;
80123
80437
  }
80124
- logger2.info(`✅ High-level plan approved.
80125
- `);
80126
- return { plan: highLevelPlan2, branchName: branchName2 };
80127
- }
80128
- const planResult = await createAndApprovePlan(task, context);
80129
- if (!planResult) {
80130
- return;
80131
- }
80132
- const highLevelPlan = planResult.plan;
80133
- let branchName = planResult.branchName;
80134
- async function createFeatureBranch(branchName2, task2, plan, context2) {
80135
- const { logger: logger2, step: step2, tools: tools3 } = context2;
80136
- logger2.info(`\uD83C\uDF3F Phase 3: Creating feature branch...
80438
+ const reviewResult = reviewAgentResult.object;
80439
+ if (!reviewResult || !reviewResult.specificReviews || reviewResult.specificReviews.length === 0) {
80440
+ logger.info(`✅ Review passed. No issues found.
80137
80441
  `);
80138
- const branchValidation = validateBranchName(branchName2);
80139
- if (!branchValidation.valid) {
80140
- logger2.error(`❌ Error: ${branchValidation.error}`);
80141
- return { success: false, branchName: null };
80142
- }
80143
- let finalBranchName = branchName2;
80144
- const initialCheckResult = await step2("checkBranch-initial", async () => tools3.executeCommand({ command: "git", args: ["rev-parse", "--verify", finalBranchName] }));
80145
- if (initialCheckResult.exitCode === 0) {
80146
- logger2.warn(`⚠️ Branch '${finalBranchName}' already exists. Trying to find an available name...`);
80147
- const suffixMatch = branchName2.match(/-(\d+)$/);
80148
- let baseName = branchName2;
80149
- let counter = 2;
80150
- if (suffixMatch) {
80151
- baseName = branchName2.substring(0, suffixMatch.index);
80152
- counter = parseInt(suffixMatch[1], 10) + 1;
80153
- }
80154
- while (true) {
80155
- finalBranchName = `${baseName}-${counter}`;
80156
- const branchCheckResult = await step2(`checkBranch-${counter}`, async () => tools3.executeCommand({ command: "git", args: ["rev-parse", "--verify", finalBranchName] }));
80157
- if (branchCheckResult.exitCode !== 0) {
80158
- break;
80159
- }
80160
- counter++;
80161
- }
80442
+ return { passed: true };
80162
80443
  }
80163
- if (finalBranchName !== branchName2) {
80164
- logger2.info(`Branch name '${branchName2}' was taken. Using '${finalBranchName}' instead.`);
80444
+ logger.warn(`⚠️ Review found ${reviewResult.specificReviews.length} issue(s). Attempting to fix...
80445
+ `);
80446
+ for (const [idx, review] of reviewResult.specificReviews.entries()) {
80447
+ logger.warn(` ${idx + 1}. ${review.file}:${review.lines}`);
80165
80448
  }
80166
- await step2("createBranch", async () => await tools3.executeCommand({ command: "git", args: ["checkout", "-b", finalBranchName] }));
80167
- logger2.info(`✅ Branch '${finalBranchName}' created.
80449
+ logger.warn("");
80450
+ const reviewSummary = reviewResult.specificReviews.map((r) => `File: ${r.file} (lines: ${r.lines})
80451
+ Review: ${r.review}`).join(`
80452
+
80168
80453
  `);
80169
- await tools3.appendMemory({
80170
- topic: "epic-context",
80171
- content: `Epic: ${task2}
80172
- Branch: ${finalBranchName}
80173
- Started: ${new Date().toISOString()}`
80454
+ const fixTask = `You are working on an epic. The original task was: "${taskItem}".
80455
+
80456
+ Here is the full plan for context:
80457
+ <plan>
80458
+ ${highLevelPlan}
80459
+ </plan>
80460
+
80461
+ After an initial implementation, a review found the following issues. Please fix them:
80462
+
80463
+ ${reviewSummary}`;
80464
+ await step(`fix-${iterationCount}-${i}`, async () => {
80465
+ await codeWorkflow({ task: fixTask, mode: "noninteractive" }, context);
80174
80466
  });
80175
- await tools3.appendMemory({ topic: "epic-plan", content: plan });
80176
- return { success: true, branchName: finalBranchName };
80177
- }
80178
- const branchResult = await createFeatureBranch(branchName, task, highLevelPlan, context);
80179
- if (!branchResult.success || !branchResult.branchName) {
80180
- return;
80467
+ await step(`commit-fix-${iterationCount}-${i}`, async () => {
80468
+ await tools2.executeCommand({ command: "git", args: ["add", "."] });
80469
+ await tools2.executeCommand({ command: "git", args: ["commit", "--amend", "--no-edit"] });
80470
+ });
80471
+ if (i === MAX_REVIEW_RETRIES - 1) {
80472
+ logger.error(`
80473
+ \uD83D\uDEAB Max retries (${MAX_REVIEW_RETRIES}) reached. Moving to the next task, but issues might remain.
80474
+ `);
80475
+ return { passed: false };
80476
+ }
80181
80477
  }
80182
- branchName = branchResult.branchName;
80183
- logger.info(`\uD83D\uDE80 Phase 4: Iterative Implementation Loop...
80478
+ return { passed: false };
80479
+ }
80480
+ async function runImplementationLoop(context, highLevelPlan) {
80481
+ const { logger, step, tools: tools2 } = context;
80482
+ const commitMessages = [];
80483
+ logger.info(`\uD83D\uDE80 Phase 5: Iterative Implementation Loop...
80184
80484
  `);
80185
80485
  logger.info(`${"=".repeat(80)}
80186
80486
  `);
80187
- let currentPlan = highLevelPlan;
80188
80487
  let iterationCount = 0;
80189
80488
  let isComplete = false;
80190
80489
  let nextTask = null;
80191
- try {
80192
- const firstTaskResult = await step("extract-first-task", async () => {
80193
- return await updatePlanAgent(currentPlan, "", "", context);
80194
- });
80195
- currentPlan = firstTaskResult.updatedPlan;
80196
- nextTask = firstTaskResult.nextTask;
80197
- isComplete = firstTaskResult.isComplete;
80198
- while (!isComplete && nextTask) {
80199
- iterationCount++;
80200
- const taskStartTime = Date.now();
80201
- logger.info(`
80490
+ let nextTaskId = null;
80491
+ const initialTasks = await step("get-initial-tasks", async () => {
80492
+ return await tools2.listTodoItems({ status: "open" });
80493
+ });
80494
+ if (initialTasks.length > 0) {
80495
+ const firstTask = initialTasks[0];
80496
+ nextTask = firstTask.title;
80497
+ nextTaskId = firstTask.id;
80498
+ } else {
80499
+ isComplete = true;
80500
+ }
80501
+ while (!isComplete && nextTask && nextTaskId) {
80502
+ iterationCount++;
80503
+ const taskStartTime = Date.now();
80504
+ logger.info(`
80202
80505
  ${"━".repeat(80)}`);
80203
- logger.info(`\uD83D\uDCCC Iteration ${iterationCount}`);
80204
- logger.info(`${"━".repeat(80)}`);
80205
- logger.info(`${nextTask}
80506
+ logger.info(`\uD83D\uDCCC Iteration ${iterationCount}`);
80507
+ logger.info(`${"━".repeat(80)}`);
80508
+ logger.info(`${nextTask}
80206
80509
  `);
80207
- let implementationSummary = "";
80208
- const codeResult = await step(`task-${iterationCount}`, async () => {
80209
- const taskWithContext = `You are working on an epic. Here is the full plan:
80510
+ await step(`task-${iterationCount}`, async () => {
80511
+ const taskWithContext = `You are working on an epic. Here is the full plan:
80210
80512
 
80211
80513
  <plan>
80212
- ${currentPlan}
80514
+ ${highLevelPlan}
80213
80515
  </plan>
80214
80516
 
80215
80517
  Your current task is to implement this specific item:
80216
80518
  ${nextTask}
80217
80519
 
80218
80520
  Focus only on this item, but use the plan for context.`;
80219
- return await codeWorkflow({ task: taskWithContext, mode: "noninteractive" }, context);
80220
- });
80221
- if (codeResult && "summaries" in codeResult && codeResult.summaries.length > 0) {
80222
- implementationSummary = codeResult.summaries.join(`
80223
- `);
80224
- } else {
80225
- implementationSummary = nextTask;
80226
- }
80227
- const commitMessage = `feat: ${nextTask}`;
80228
- await step(`commit-initial-${iterationCount}`, async () => {
80229
- await tools2.executeCommand({ command: "git", args: ["add", "."] });
80230
- await tools2.executeCommand({ command: "git", args: ["commit", "-m", commitMessage] });
80231
- });
80232
- commitMessages.push(commitMessage);
80233
- const { passed: reviewPassed } = await performReviewAndFixCycle(iterationCount, nextTask, currentPlan, context);
80234
- const taskElapsed = Date.now() - taskStartTime;
80235
- const taskElapsedTime = formatElapsedTime(taskElapsed);
80236
- if (reviewPassed) {
80237
- logger.info(`✅ Iteration ${iterationCount} completed successfully (${taskElapsedTime})`);
80238
- } else {
80239
- logger.warn(`⚠️ Iteration ${iterationCount} completed with potential issues (${taskElapsedTime})`);
80240
- }
80241
- const updateResult = await step(`update-plan-${iterationCount}`, async () => {
80242
- return await updatePlanAgent(currentPlan, implementationSummary, nextTask ?? "", context);
80243
- });
80244
- currentPlan = updateResult.updatedPlan;
80245
- isComplete = updateResult.isComplete;
80246
- nextTask = updateResult.nextTask;
80247
- await tools2.replaceMemory({ topic: "epic-plan", content: currentPlan });
80248
- const checkboxCompleted = (currentPlan.match(/- \[x\]/g) || []).length;
80249
- const checkboxTotal = (currentPlan.match(/- \[[x ]\]/g) || []).length;
80250
- const checkmarkCompleted = (currentPlan.match(/^✅/gm) || []).length;
80251
- let progressMessage = "";
80252
- if (checkboxTotal > 0) {
80253
- progressMessage = `${checkboxCompleted}/${checkboxTotal} items completed`;
80254
- } else if (checkmarkCompleted > 0) {
80255
- progressMessage = `${checkmarkCompleted} items completed`;
80256
- } else {
80257
- progressMessage = `Iteration ${iterationCount} completed`;
80521
+ return await codeWorkflow({ task: taskWithContext, mode: "noninteractive" }, context);
80522
+ });
80523
+ const commitMessage = `feat: ${nextTask}`;
80524
+ await step(`commit-initial-${iterationCount}`, async () => {
80525
+ await tools2.executeCommand({ command: "git", args: ["add", "."] });
80526
+ await tools2.executeCommand({ command: "git", args: ["commit", "-m", commitMessage] });
80527
+ });
80528
+ commitMessages.push(commitMessage);
80529
+ const { passed: reviewPassed } = await performReviewAndFixCycle(iterationCount, nextTask, highLevelPlan, context);
80530
+ const taskElapsed = Date.now() - taskStartTime;
80531
+ const taskElapsedTime = formatElapsedTime(taskElapsed);
80532
+ if (reviewPassed) {
80533
+ logger.info(`✅ Iteration ${iterationCount} completed successfully (${taskElapsedTime})`);
80534
+ } else {
80535
+ logger.warn(`⚠️ Iteration ${iterationCount} completed with potential issues (${taskElapsedTime})`);
80536
+ }
80537
+ await step(`update-task-status-${iterationCount}`, async () => {
80538
+ if (!nextTaskId) {
80539
+ throw new Error("Invariant violation: nextTaskId is null inside the implementation loop.");
80258
80540
  }
80259
- logger.info(`
80541
+ await tools2.updateTodoItem({ operation: "update", id: nextTaskId, status: "completed" });
80542
+ });
80543
+ const openTasks = await step(`get-next-task-${iterationCount}`, async () => {
80544
+ return await tools2.listTodoItems({ status: "open" });
80545
+ });
80546
+ if (openTasks.length > 0) {
80547
+ const nextTodo = openTasks[0];
80548
+ nextTask = nextTodo.title;
80549
+ nextTaskId = nextTodo.id;
80550
+ isComplete = false;
80551
+ } else {
80552
+ nextTask = null;
80553
+ nextTaskId = null;
80554
+ isComplete = true;
80555
+ }
80556
+ const allTodos = await tools2.listTodoItems({});
80557
+ const completedTodos = allTodos.filter((t) => t.status === "completed").length;
80558
+ const totalTodos = allTodos.length;
80559
+ let progressMessage = "";
80560
+ if (totalTodos > 0) {
80561
+ progressMessage = `${completedTodos}/${totalTodos} items completed`;
80562
+ } else {
80563
+ progressMessage = `Iteration ${iterationCount} completed`;
80564
+ }
80565
+ logger.info(`
80260
80566
  \uD83D\uDCCA Progress: ${progressMessage}`);
80261
- if (isComplete) {
80262
- logger.info(`✅ All tasks complete!
80567
+ if (isComplete) {
80568
+ logger.info(`✅ All tasks complete!
80263
80569
  `);
80264
- break;
80265
- }
80266
- if (nextTask) {
80267
- logger.info(`\uD83D\uDCCC Next task: ${nextTask}
80570
+ break;
80571
+ }
80572
+ if (nextTask) {
80573
+ logger.info(`\uD83D\uDCCC Next task: ${nextTask}
80268
80574
  `);
80269
- }
80270
- logger.info(`${"━".repeat(80)}
80575
+ }
80576
+ logger.info(`${"━".repeat(80)}
80577
+ `);
80578
+ }
80579
+ return commitMessages;
80580
+ }
80581
+ async function performFinalReviewAndFix(context, highLevelPlan) {
80582
+ const { logger, step, tools: tools2 } = context;
80583
+ logger.info(`
80584
+ Phase 6: Final Review and Fixup...
80585
+ `);
80586
+ const ghCheckResult = await tools2.executeCommand({ command: "gh", args: ["--version"] });
80587
+ if (ghCheckResult.exitCode !== 0) {
80588
+ logger.warn("⚠️ GitHub CLI (gh) is not installed. Skipping final review step. Please install it from https://cli.github.com/ to enable final reviews.");
80589
+ return { passed: true };
80590
+ }
80591
+ const defaultBranchResult = await tools2.executeCommand({
80592
+ command: "gh",
80593
+ args: ["repo", "view", "--json", "defaultBranchRef", "--jq", ".defaultBranchRef.name"]
80594
+ });
80595
+ const defaultBranch = defaultBranchResult.stdout.trim();
80596
+ const currentBranchResult = await tools2.executeCommand({ command: "git", args: ["rev-parse", "--abbrev-ref", "HEAD"] });
80597
+ const currentBranch = currentBranchResult.stdout.trim();
80598
+ if (currentBranch === defaultBranch) {
80599
+ logger.info(`✅ You are on the default branch ('${defaultBranch}'). No final review needed.`);
80600
+ return { passed: true };
80601
+ }
80602
+ const commitRange = `${defaultBranch}...${currentBranch}`;
80603
+ for (let i = 0;i < MAX_REVIEW_RETRIES; i++) {
80604
+ const diffResult = await tools2.executeCommand({ command: "git", args: ["diff", "--name-status", commitRange] });
80605
+ const changedFiles = parseGitDiffNameStatus(diffResult.stdout);
80606
+ if (changedFiles.length === 0) {
80607
+ logger.info(`ℹ️ No files have been changed in this branch. Skipping final review.
80608
+ `);
80609
+ return { passed: true };
80610
+ }
80611
+ logger.info(`
80612
+ \uD83D\uDD0E Final review iteration ${i + 1}/${MAX_REVIEW_RETRIES}`);
80613
+ logger.info(` Changed files: ${changedFiles.length}`);
80614
+ const changeInfo = {
80615
+ commitRange,
80616
+ changedFiles
80617
+ };
80618
+ const reviewAgentResult = await step(`final-review-${i}`, async () => {
80619
+ const defaultContext = await getDefaultContext();
80620
+ const memoryContext = await tools2.getMemoryContext();
80621
+ const userMessage = `${defaultContext}
80622
+ ${memoryContext}
80623
+
80624
+ ${formatReviewToolInput(changeInfo)}`;
80625
+ return await agentWorkflow({
80626
+ systemPrompt: CODE_REVIEW_SYSTEM_PROMPT,
80627
+ userMessage: [{ role: "user", content: userMessage }],
80628
+ tools: [readFile_default, readBinaryFile_default, searchFiles_default, listFiles_default, gitDiff_default, readMemory_default, updateMemory_default, listMemoryTopics_default],
80629
+ outputSchema: reviewOutputSchema
80630
+ }, context);
80631
+ });
80632
+ if (reviewAgentResult.type !== "Exit" /* Exit */) {
80633
+ logger.error(`\uD83D\uDEAB Review agent failed with status: ${reviewAgentResult.type}.`);
80634
+ break;
80635
+ }
80636
+ const reviewResult = reviewAgentResult.object;
80637
+ if (!reviewResult || !reviewResult.specificReviews || reviewResult.specificReviews.length === 0) {
80638
+ logger.info(`✅ Final review passed. No issues found.
80639
+ `);
80640
+ return { passed: true };
80641
+ }
80642
+ logger.warn(`⚠️ Final review found ${reviewResult.specificReviews.length} issue(s). Attempting to fix...
80643
+ `);
80644
+ for (const [idx, review] of reviewResult.specificReviews.entries()) {
80645
+ logger.warn(` ${idx + 1}. ${review.file}:${review.lines}`);
80646
+ }
80647
+ logger.warn("");
80648
+ const reviewSummary = reviewResult.specificReviews.map((r) => `File: ${r.file} (lines: ${r.lines})
80649
+ Review: ${r.review}`).join(`
80650
+
80651
+ `);
80652
+ const fixTask = `You are working on an epic. The original task was to implement a feature based on this plan:
80653
+
80654
+ <plan>
80655
+ ${highLevelPlan}
80656
+ </plan>
80657
+
80658
+ A final review of all the changes in the branch found the following issues. Please fix them:
80659
+
80660
+ ${reviewSummary}`;
80661
+ await step(`final-fix-${i}`, async () => {
80662
+ await codeWorkflow({ task: fixTask, mode: "noninteractive" }, context);
80663
+ });
80664
+ await step(`commit-final-fix-${i}`, async () => {
80665
+ await tools2.executeCommand({ command: "git", args: ["add", "."] });
80666
+ await tools2.executeCommand({ command: "git", args: ["commit", "-m", "chore: apply automated review feedback"] });
80667
+ });
80668
+ if (i === MAX_REVIEW_RETRIES - 1) {
80669
+ logger.error(`
80670
+ \uD83D\uDEAB Max retries (${MAX_REVIEW_RETRIES}) reached for final review. Issues might remain.
80271
80671
  `);
80672
+ return { passed: false };
80673
+ }
80674
+ }
80675
+ return { passed: false };
80676
+ }
80677
+ var epicWorkflow = async (input2, context) => {
80678
+ const { logger } = context;
80679
+ const { task } = input2;
80680
+ const workflowStartTime = Date.now();
80681
+ let branchName = "";
80682
+ if (!task || task.trim() === "") {
80683
+ logger.error("❌ Error: Task cannot be empty. Please provide a valid task description.");
80684
+ return;
80685
+ }
80686
+ try {
80687
+ const preflightResult = await runPreflightChecks(context);
80688
+ if (!preflightResult.success) {
80689
+ return;
80690
+ }
80691
+ const planResult = await createAndApprovePlan(task, context);
80692
+ if (!planResult) {
80693
+ return;
80694
+ }
80695
+ const { plan: highLevelPlan } = planResult;
80696
+ branchName = planResult.branchName;
80697
+ const branchResult = await createFeatureBranch(branchName, context);
80698
+ if (!branchResult.success || !branchResult.branchName) {
80699
+ return;
80700
+ }
80701
+ branchName = branchResult.branchName;
80702
+ await addTodoItemsFromPlan(highLevelPlan, context);
80703
+ const commitMessages = await runImplementationLoop(context, highLevelPlan);
80704
+ await performFinalReviewAndFix(context, highLevelPlan);
80705
+ const totalElapsed = Date.now() - workflowStartTime;
80706
+ const totalElapsedTime = formatElapsedTime(totalElapsed);
80707
+ const iterationCount = commitMessages.length;
80708
+ logger.info(`
80709
+ ${"=".repeat(80)}`);
80710
+ logger.info("\uD83C\uDF89 Epic Workflow Complete!");
80711
+ logger.info(`${"=".repeat(80)}`);
80712
+ logger.info(`
80713
+ \uD83D\uDCCA Summary:`);
80714
+ logger.info(` Total iterations: ${iterationCount}`);
80715
+ logger.info(` Total commits: ${commitMessages.length}`);
80716
+ logger.info(` Branch: ${branchName}`);
80717
+ logger.info(` Total time: ${totalElapsedTime}`);
80718
+ logger.info("\uD83D\uDCDD Commits created:");
80719
+ for (const [idx, msg] of commitMessages.entries()) {
80720
+ logger.info(` ${idx + 1}. ${msg}`);
80272
80721
  }
80273
80722
  } catch (error46) {
80274
80723
  logger.error(`
80275
80724
  ❌ Epic workflow failed: ${error46 instanceof Error ? error46.message : String(error46)}`);
80276
- logger.info(`
80725
+ if (branchName) {
80726
+ logger.info(`
80277
80727
  Branch '${branchName}' was created but work is incomplete.`);
80278
- logger.info(`To cleanup: git checkout <previous-branch> && git branch -D ${branchName}
80728
+ logger.info(`To cleanup: git checkout <previous-branch> && git branch -D ${branchName}
80279
80729
  `);
80280
- await tools2.removeMemory({ topic: "epic-context" });
80281
- await tools2.removeMemory({ topic: "epic-plan" });
80730
+ }
80282
80731
  throw error46;
80283
80732
  }
80284
- const totalElapsed = Date.now() - workflowStartTime;
80285
- const totalElapsedTime = formatElapsedTime(totalElapsed);
80286
- const avgTimePerIteration = iterationCount > 0 ? formatElapsedTime(totalElapsed / iterationCount) : "N/A";
80287
- logger.info(`
80288
- ${"=".repeat(80)}`);
80289
- logger.info("\uD83C\uDF89 Epic Workflow Complete!");
80290
- logger.info(`${"=".repeat(80)}`);
80291
- logger.info(`
80292
- \uD83D\uDCCA Summary:`);
80293
- logger.info(` Total iterations: ${iterationCount}`);
80294
- logger.info(` Total commits: ${commitMessages.length}`);
80295
- logger.info(` Branch: ${branchName}`);
80296
- logger.info(` Total time: ${totalElapsedTime}`);
80297
- logger.info(` Average per iteration: ${avgTimePerIteration}
80298
- `);
80299
- logger.info("\uD83D\uDCDD Commits created:");
80300
- commitMessages.forEach((msg, idx) => {
80301
- logger.info(` ${idx + 1}. ${msg}`);
80302
- });
80303
- logger.info(`
80304
- \uD83D\uDCA1 Next steps:`);
80305
- logger.info(` • Review your changes: git log`);
80306
- logger.info(` • Push to remote: git push origin ${branchName}`);
80307
- logger.info(` • Create a pull request on your Git platform
80308
- `);
80309
- logger.info(`${"=".repeat(80)}
80310
- `);
80311
- await tools2.removeMemory({ topic: "epic-context" });
80312
- await tools2.removeMemory({ topic: "epic-plan" });
80313
80733
  };
80314
80734
 
80315
80735
  // src/workflows/task.workflow.ts