@polka-codes/cli 0.9.48 → 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 +867 -483
  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.48";
35582
+ var version = "0.9.49";
35583
35583
 
35584
35584
  // src/commands/code.ts
35585
35585
  import { readFile as readFile3 } from "node:fs/promises";
@@ -48478,8 +48478,40 @@ var fetchUrl_default = {
48478
48478
  ...toolInfo3,
48479
48479
  handler: handler3
48480
48480
  };
48481
- // ../core/src/tools/listFiles.ts
48481
+ // ../core/src/tools/getTodoItem.ts
48482
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 = {
48510
+ ...toolInfo4,
48511
+ handler: handler4
48512
+ };
48513
+ // ../core/src/tools/listFiles.ts
48514
+ var toolInfo5 = {
48483
48515
  name: "listFiles",
48484
48516
  description: "Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.",
48485
48517
  parameters: exports_external.object({
@@ -48517,7 +48549,7 @@ var toolInfo4 = {
48517
48549
  ]
48518
48550
  })
48519
48551
  };
48520
- var handler4 = async (provider, args) => {
48552
+ var handler5 = async (provider, args) => {
48521
48553
  if (!provider.listFiles) {
48522
48554
  return {
48523
48555
  type: "Error" /* Error */,
@@ -48527,7 +48559,7 @@ var handler4 = async (provider, args) => {
48527
48559
  }
48528
48560
  };
48529
48561
  }
48530
- const { path, maxCount, recursive, includeIgnored } = toolInfo4.parameters.parse(args);
48562
+ const { path, maxCount, recursive, includeIgnored } = toolInfo5.parameters.parse(args);
48531
48563
  const [files, limitReached] = await provider.listFiles(path, recursive, maxCount, includeIgnored);
48532
48564
  return {
48533
48565
  type: "Reply" /* Reply */,
@@ -48543,16 +48575,16 @@ ${files.join(`
48543
48575
  };
48544
48576
  };
48545
48577
  var listFiles_default = {
48546
- ...toolInfo4,
48547
- handler: handler4
48578
+ ...toolInfo5,
48579
+ handler: handler5
48548
48580
  };
48549
48581
  // ../core/src/tools/listMemoryTopics.ts
48550
- var toolInfo5 = {
48582
+ var toolInfo6 = {
48551
48583
  name: "listMemoryTopics",
48552
- 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.",
48553
48585
  parameters: exports_external.object({})
48554
48586
  };
48555
- var handler5 = async (provider, _args) => {
48587
+ var handler6 = async (provider, _args) => {
48556
48588
  const topics = await provider.listMemoryTopics();
48557
48589
  if (!topics.length) {
48558
48590
  return { type: "Reply" /* Reply */, message: { type: "text", value: "No topics found." } };
@@ -48568,18 +48600,91 @@ ${topics.join(`
48568
48600
  };
48569
48601
  };
48570
48602
  var listMemoryTopics_default = {
48571
- ...toolInfo5,
48572
- handler: handler5
48603
+ ...toolInfo6,
48604
+ handler: handler6
48605
+ };
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
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
48573
48678
  };
48574
48679
  // ../core/src/tools/readBinaryFile.ts
48575
- var toolInfo6 = {
48680
+ var toolInfo8 = {
48576
48681
  name: "readBinaryFile",
48577
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.",
48578
48683
  parameters: exports_external.object({
48579
48684
  url: exports_external.string().describe("The URL or local path of the file to read.")
48580
48685
  })
48581
48686
  };
48582
- var handler6 = async (provider, args) => {
48687
+ var handler8 = async (provider, args) => {
48583
48688
  if (!provider.readBinaryFile) {
48584
48689
  return {
48585
48690
  type: "Error" /* Error */,
@@ -48589,7 +48694,7 @@ var handler6 = async (provider, args) => {
48589
48694
  }
48590
48695
  };
48591
48696
  }
48592
- const { url: url2 } = toolInfo6.parameters.parse(args);
48697
+ const { url: url2 } = toolInfo8.parameters.parse(args);
48593
48698
  try {
48594
48699
  const filePart = await provider.readBinaryFile(url2);
48595
48700
  return {
@@ -48618,11 +48723,11 @@ var handler6 = async (provider, args) => {
48618
48723
  }
48619
48724
  };
48620
48725
  var readBinaryFile_default = {
48621
- ...toolInfo6,
48622
- handler: handler6
48726
+ ...toolInfo8,
48727
+ handler: handler8
48623
48728
  };
48624
48729
  // ../core/src/tools/readFile.ts
48625
- var toolInfo7 = {
48730
+ var toolInfo9 = {
48626
48731
  name: "readFile",
48627
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.",
48628
48733
  parameters: exports_external.object({
@@ -48659,7 +48764,7 @@ var toolInfo7 = {
48659
48764
  ]
48660
48765
  })
48661
48766
  };
48662
- var handler7 = async (provider, args) => {
48767
+ var handler9 = async (provider, args) => {
48663
48768
  if (!provider.readFile) {
48664
48769
  return {
48665
48770
  type: "Error" /* Error */,
@@ -48669,7 +48774,7 @@ var handler7 = async (provider, args) => {
48669
48774
  }
48670
48775
  };
48671
48776
  }
48672
- const { path: paths, includeIgnored } = toolInfo7.parameters.parse(args);
48777
+ const { path: paths, includeIgnored } = toolInfo9.parameters.parse(args);
48673
48778
  const resp = [];
48674
48779
  for (const path of paths) {
48675
48780
  const fileContent = await provider.readFile(path, includeIgnored);
@@ -48694,19 +48799,19 @@ var handler7 = async (provider, args) => {
48694
48799
  };
48695
48800
  };
48696
48801
  var readFile_default = {
48697
- ...toolInfo7,
48698
- handler: handler7
48802
+ ...toolInfo9,
48803
+ handler: handler9
48699
48804
  };
48700
48805
  // ../core/src/tools/readMemory.ts
48701
- var toolInfo8 = {
48806
+ var toolInfo10 = {
48702
48807
  name: "readMemory",
48703
- 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.",
48704
48809
  parameters: exports_external.object({
48705
48810
  topic: exports_external.string().optional().describe('The topic to read from memory. Defaults to ":default:".')
48706
48811
  })
48707
48812
  };
48708
- var handler8 = async (provider, args) => {
48709
- const { topic } = toolInfo8.parameters.parse(args);
48813
+ var handler10 = async (provider, args) => {
48814
+ const { topic } = toolInfo10.parameters.parse(args);
48710
48815
  const content = await provider.readMemory(topic);
48711
48816
  if (content) {
48712
48817
  return {
@@ -48728,11 +48833,11 @@ ${content}
48728
48833
  };
48729
48834
  };
48730
48835
  var readMemory_default = {
48731
- ...toolInfo8,
48732
- handler: handler8
48836
+ ...toolInfo10,
48837
+ handler: handler10
48733
48838
  };
48734
48839
  // ../core/src/tools/removeFile.ts
48735
- var toolInfo9 = {
48840
+ var toolInfo11 = {
48736
48841
  name: "removeFile",
48737
48842
  description: "Request to remove a file at the specified path.",
48738
48843
  parameters: exports_external.object({
@@ -48748,7 +48853,7 @@ var toolInfo9 = {
48748
48853
  ]
48749
48854
  })
48750
48855
  };
48751
- var handler9 = async (provider, args) => {
48856
+ var handler11 = async (provider, args) => {
48752
48857
  if (!provider.removeFile) {
48753
48858
  return {
48754
48859
  type: "Error" /* Error */,
@@ -48758,7 +48863,7 @@ var handler9 = async (provider, args) => {
48758
48863
  }
48759
48864
  };
48760
48865
  }
48761
- const parsed = toolInfo9.parameters.safeParse(args);
48866
+ const parsed = toolInfo11.parameters.safeParse(args);
48762
48867
  if (!parsed.success) {
48763
48868
  return {
48764
48869
  type: "Error" /* Error */,
@@ -48779,11 +48884,11 @@ var handler9 = async (provider, args) => {
48779
48884
  };
48780
48885
  };
48781
48886
  var removeFile_default = {
48782
- ...toolInfo9,
48783
- handler: handler9
48887
+ ...toolInfo11,
48888
+ handler: handler11
48784
48889
  };
48785
48890
  // ../core/src/tools/renameFile.ts
48786
- var toolInfo10 = {
48891
+ var toolInfo12 = {
48787
48892
  name: "renameFile",
48788
48893
  description: "Request to rename a file from source path to target path.",
48789
48894
  parameters: exports_external.object({
@@ -48801,7 +48906,7 @@ var toolInfo10 = {
48801
48906
  ]
48802
48907
  })
48803
48908
  };
48804
- var handler10 = async (provider, args) => {
48909
+ var handler12 = async (provider, args) => {
48805
48910
  if (!provider.renameFile) {
48806
48911
  return {
48807
48912
  type: "Error" /* Error */,
@@ -48811,7 +48916,7 @@ var handler10 = async (provider, args) => {
48811
48916
  }
48812
48917
  };
48813
48918
  }
48814
- const { source_path, target_path } = toolInfo10.parameters.parse(args);
48919
+ const { source_path, target_path } = toolInfo12.parameters.parse(args);
48815
48920
  await provider.renameFile(source_path, target_path);
48816
48921
  return {
48817
48922
  type: "Reply" /* Reply */,
@@ -48822,12 +48927,12 @@ var handler10 = async (provider, args) => {
48822
48927
  };
48823
48928
  };
48824
48929
  var renameFile_default = {
48825
- ...toolInfo10,
48826
- handler: handler10
48930
+ ...toolInfo12,
48931
+ handler: handler12
48827
48932
  };
48828
48933
  // ../core/src/tools/utils/replaceInFile.ts
48829
48934
  var replaceInFile = (fileContent, diff) => {
48830
- 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;
48831
48936
  const blocks = [];
48832
48937
  for (let match = blockPattern.exec(diff);match !== null; match = blockPattern.exec(diff)) {
48833
48938
  blocks.push({ search: match[1], replace: match[2] });
@@ -48900,7 +49005,7 @@ var replaceInFile = (fileContent, diff) => {
48900
49005
  };
48901
49006
 
48902
49007
  // ../core/src/tools/replaceInFile.ts
48903
- var toolInfo11 = {
49008
+ var toolInfo13 = {
48904
49009
  name: "replaceInFile",
48905
49010
  description: "Request to replace sections of content in an existing file using SEARCH/REPLACE blocks that define exact changes to specific parts of the file. This tool should be used when you need to make targeted changes to specific parts of a file.",
48906
49011
  parameters: exports_external.object({
@@ -49010,7 +49115,7 @@ function oldFeature() {
49010
49115
  ]
49011
49116
  })
49012
49117
  };
49013
- var handler11 = async (provider, args) => {
49118
+ var handler13 = async (provider, args) => {
49014
49119
  if (!provider.readFile || !provider.writeFile) {
49015
49120
  return {
49016
49121
  type: "Error" /* Error */,
@@ -49020,7 +49125,7 @@ var handler11 = async (provider, args) => {
49020
49125
  }
49021
49126
  };
49022
49127
  }
49023
- const parsed = toolInfo11.parameters.safeParse(args);
49128
+ const parsed = toolInfo13.parameters.safeParse(args);
49024
49129
  if (!parsed.success) {
49025
49130
  return {
49026
49131
  type: "Error" /* Error */,
@@ -49084,11 +49189,11 @@ var handler11 = async (provider, args) => {
49084
49189
  }
49085
49190
  };
49086
49191
  var replaceInFile_default = {
49087
- ...toolInfo11,
49088
- handler: handler11
49192
+ ...toolInfo13,
49193
+ handler: handler13
49089
49194
  };
49090
49195
  // ../core/src/tools/searchFiles.ts
49091
- var toolInfo12 = {
49196
+ var toolInfo14 = {
49092
49197
  name: "searchFiles",
49093
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.",
49094
49199
  parameters: exports_external.object({
@@ -49112,7 +49217,7 @@ var toolInfo12 = {
49112
49217
  ]
49113
49218
  })
49114
49219
  };
49115
- var handler12 = async (provider, args) => {
49220
+ var handler14 = async (provider, args) => {
49116
49221
  if (!provider.searchFiles) {
49117
49222
  return {
49118
49223
  type: "Error" /* Error */,
@@ -49122,7 +49227,7 @@ var handler12 = async (provider, args) => {
49122
49227
  }
49123
49228
  };
49124
49229
  }
49125
- const parsed = toolInfo12.parameters.safeParse(args);
49230
+ const parsed = toolInfo14.parameters.safeParse(args);
49126
49231
  if (!parsed.success) {
49127
49232
  return {
49128
49233
  type: "Error" /* Error */,
@@ -49160,13 +49265,13 @@ ${files.join(`
49160
49265
  }
49161
49266
  };
49162
49267
  var searchFiles_default = {
49163
- ...toolInfo12,
49164
- handler: handler12
49268
+ ...toolInfo14,
49269
+ handler: handler14
49165
49270
  };
49166
49271
  // ../core/src/tools/updateMemory.ts
49167
- var toolInfo13 = {
49272
+ var toolInfo15 = {
49168
49273
  name: "updateMemory",
49169
- description: "Appends, replaces, or removes content from a memory topic.",
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.',
49170
49275
  parameters: exports_external.object({
49171
49276
  operation: exports_external.enum(["append", "replace", "remove"]).describe("The operation to perform."),
49172
49277
  topic: exports_external.string().nullish().describe('The topic to update in memory. Defaults to ":default:".'),
@@ -49191,7 +49296,7 @@ var toolInfo13 = {
49191
49296
  }
49192
49297
  })
49193
49298
  };
49194
- var handler13 = async (provider, args) => {
49299
+ var handler15 = async (provider, args) => {
49195
49300
  if (!provider.updateMemory) {
49196
49301
  return {
49197
49302
  type: "Error" /* Error */,
@@ -49201,7 +49306,7 @@ var handler13 = async (provider, args) => {
49201
49306
  }
49202
49307
  };
49203
49308
  }
49204
- const params = toolInfo13.parameters.parse(args);
49309
+ const params = toolInfo15.parameters.parse(args);
49205
49310
  await provider.updateMemory(params.operation, params.topic ?? undefined, "content" in params ? params.content : undefined);
49206
49311
  switch (params.operation) {
49207
49312
  case "append":
@@ -49231,11 +49336,41 @@ var handler13 = async (provider, args) => {
49231
49336
  }
49232
49337
  };
49233
49338
  var updateMemory_default = {
49234
- ...toolInfo13,
49235
- handler: handler13
49339
+ ...toolInfo15,
49340
+ handler: handler15
49341
+ };
49342
+ // ../core/src/tools/updateTodoItem.ts
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
49236
49371
  };
49237
49372
  // ../core/src/tools/writeToFile.ts
49238
- var toolInfo14 = {
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 handler14 = 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 handler14 = async (provider, args) => {
49274
49409
  }
49275
49410
  };
49276
49411
  }
49277
- const parsed = toolInfo14.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 handler14 = async (provider, args) => {
49298
49433
  };
49299
49434
  };
49300
49435
  var writeToFile_default = {
49301
- ...toolInfo14,
49302
- handler: handler14
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 handler15 = 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", handler15);
51483
+ rl.input.on("keypress", handler18);
51349
51484
  return () => {
51350
51485
  ignore = true;
51351
- rl.input.removeListener("keypress", handler15);
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 = (handler15) => {
51645
+ var signalExitWrap = (handler18) => {
51511
51646
  return {
51512
51647
  onExit(cb, opts) {
51513
- return handler15.onExit(cb, opts);
51648
+ return handler18.onExit(cb, opts);
51514
51649
  },
51515
51650
  load() {
51516
- return handler15.load();
51651
+ return handler18.load();
51517
51652
  },
51518
51653
  unload() {
51519
- return handler15.unload();
51654
+ return handler18.unload();
51520
51655
  }
51521
51656
  };
51522
51657
  };
@@ -52340,8 +52475,96 @@ 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
  },
@@ -64126,16 +64349,12 @@ var uiMessagesSchema = lazyValidator(() => zodSchema(exports_external.array(expo
64126
64349
 
64127
64350
  // ../workflow/src/agent.workflow.ts
64128
64351
  var agentWorkflow = async (input, { step, tools: tools2 }) => {
64129
- const event = async (name17, event2) => {
64130
- await step(name17, async () => {
64131
- await tools2.taskEvent(event2);
64132
- });
64133
- };
64134
- const { tools: toolInfo15, maxToolRoundTrips = 200 } = input;
64352
+ const event = (name17, event2) => step(name17, () => tools2.taskEvent(event2));
64353
+ const { tools: toolInfo18, maxToolRoundTrips = 200 } = input;
64135
64354
  const messages = "systemPrompt" in input ? [{ role: "system", content: input.systemPrompt }] : input.messages;
64136
64355
  await event("start-task", { kind: "StartTask" /* StartTask */, systemPrompt: "systemPrompt" in input ? input.systemPrompt : "" });
64137
64356
  const toolSet = {};
64138
- for (const tool3 of toolInfo15) {
64357
+ for (const tool3 of toolInfo18) {
64139
64358
  toolSet[tool3.name] = {
64140
64359
  description: tool3.description,
64141
64360
  inputSchema: jsonSchema(toJSONSchema(tool3.parameters))
@@ -64183,7 +64402,9 @@ var agentWorkflow = async (input, { step, tools: tools2 }) => {
64183
64402
  await event(`end-round-${i}`, { kind: "EndRequest" /* EndRequest */, message: textContent });
64184
64403
  if (toolCalls.length === 0) {
64185
64404
  if (!input.outputSchema) {
64186
- 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;
64187
64408
  }
64188
64409
  const parsed = parseJsonFromMarkdown(textContent);
64189
64410
  if (!parsed.success) {
@@ -64197,7 +64418,9 @@ var agentWorkflow = async (input, { step, tools: tools2 }) => {
64197
64418
  nextMessage = [{ role: "user", content: errorMessage }];
64198
64419
  continue;
64199
64420
  }
64200
- 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;
64201
64424
  }
64202
64425
  const toolResults = [];
64203
64426
  for (const toolCall of toolCalls) {
@@ -64266,6 +64489,7 @@ var agentWorkflow = async (input, { step, tools: tools2 }) => {
64266
64489
  }
64267
64490
  ];
64268
64491
  }
64492
+ await event("end-task", { kind: "EndTask" /* EndTask */, exitReason: { type: "UsageExceeded" } });
64269
64493
  throw new Error("Maximum number of tool round trips reached.");
64270
64494
  };
64271
64495
  // ../workflow/src/json-ai-types.ts
@@ -64835,6 +65059,53 @@ var chalk = createChalk();
64835
65059
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
64836
65060
  var source_default = chalk;
64837
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
+
64838
65109
  // ../cli-shared/src/utils/eventHandler.ts
64839
65110
  var taskToolCallStats = new Map;
64840
65111
  var globalToolCallStats = new Map;
@@ -64859,8 +65130,26 @@ function logToolCallStats(stream, statsMap, title) {
64859
65130
  customConsole.log("No tools were called.");
64860
65131
  }
64861
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
+ };
64862
65150
  function logGlobalToolCallStats(stream) {
64863
- logToolCallStats(stream, globalToolCallStats, "Global Tool Call Stats");
65151
+ const merged = mergeToolCallStats(globalToolCallStats, taskToolCallStats);
65152
+ logToolCallStats(stream, merged, "Global Tool Call Stats");
64864
65153
  }
64865
65154
  var printEvent = (verbose, usageMeter, stream = process.stdout) => {
64866
65155
  if (verbose < 0) {
@@ -64868,6 +65157,7 @@ var printEvent = (verbose, usageMeter, stream = process.stdout) => {
64868
65157
  }
64869
65158
  const customConsole = new Console(stream, stream);
64870
65159
  let hadReasoning = false;
65160
+ let hasText = false;
64871
65161
  const write = stream.write.bind(stream);
64872
65162
  return (event) => {
64873
65163
  switch (event.kind) {
@@ -64884,6 +65174,7 @@ ${event.systemPrompt}`);
64884
65174
  }
64885
65175
  break;
64886
65176
  case "StartRequest" /* StartRequest */:
65177
+ hasText = false;
64887
65178
  if (verbose > 0) {
64888
65179
  customConsole.log(`
64889
65180
 
@@ -64937,6 +65228,11 @@ ${event.systemPrompt}`);
64937
65228
  customConsole.log(`
64938
65229
 
64939
65230
  ======== Request Ended ========
65231
+ `);
65232
+ }
65233
+ if (verbose === 0 && hasText) {
65234
+ write(`
65235
+
64940
65236
  `);
64941
65237
  }
64942
65238
  if (verbose > 1) {
@@ -64950,6 +65246,9 @@ ${event.systemPrompt}`);
64950
65246
  `);
64951
65247
  hadReasoning = false;
64952
65248
  }
65249
+ if (event.newText.trim().length > 0) {
65250
+ hasText = true;
65251
+ }
64953
65252
  write(event.newText);
64954
65253
  break;
64955
65254
  }
@@ -64964,7 +65263,7 @@ ${event.systemPrompt}`);
64964
65263
  if (verbose > 0) {
64965
65264
  customConsole.log(source_default.yellow(`
64966
65265
 
64967
- Tool use:`, event.tool), event.params);
65266
+ Tool use:`, event.tool), simplifyToolParameters(event.tool, event.params));
64968
65267
  }
64969
65268
  const stats = taskToolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
64970
65269
  stats.calls++;
@@ -65000,18 +65299,26 @@ Tool error:`, event.tool));
65000
65299
  `);
65001
65300
  customConsole.log("Reason:", event.exitReason.type);
65002
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
+ }
65003
65310
  case "Exit" /* Exit */:
65004
65311
  customConsole.log("Exit Message:", event.exitReason.message);
65005
65312
  break;
65006
65313
  }
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
+ }
65007
65321
  if (verbose > 0) {
65008
- for (const [tool3, taskStats] of taskToolCallStats.entries()) {
65009
- const globalStats = globalToolCallStats.get(tool3) ?? { calls: 0, success: 0, errors: 0 };
65010
- globalStats.calls += taskStats.calls;
65011
- globalStats.success += taskStats.success;
65012
- globalStats.errors += taskStats.errors;
65013
- globalToolCallStats.set(tool3, globalStats);
65014
- }
65015
65322
  logToolCallStats(stream, taskToolCallStats, "Task Tool Call Stats");
65016
65323
  }
65017
65324
  break;
@@ -77501,7 +77808,7 @@ function annotateDiffWithLineNumbers(diff) {
77501
77808
  }
77502
77809
 
77503
77810
  // src/tools/gitDiff.ts
77504
- var toolInfo15 = {
77811
+ var toolInfo18 = {
77505
77812
  name: "git_diff",
77506
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.",
77507
77814
  parameters: exports_external.object({
@@ -77530,7 +77837,7 @@ var toolInfo15 = {
77530
77837
  }, exports_external.boolean().optional().default(false)).describe("Annotate the diff with line numbers for additions and deletions.")
77531
77838
  })
77532
77839
  };
77533
- var handler15 = async (provider3, args) => {
77840
+ var handler18 = async (provider3, args) => {
77534
77841
  if (!provider3.executeCommand) {
77535
77842
  return {
77536
77843
  type: "Error" /* Error */,
@@ -77540,7 +77847,7 @@ var handler15 = async (provider3, args) => {
77540
77847
  }
77541
77848
  };
77542
77849
  }
77543
- const { staged, file: file2, commitRange, contextLines, includeLineNumbers } = toolInfo15.parameters.parse(args);
77850
+ const { staged, file: file2, commitRange, contextLines, includeLineNumbers } = toolInfo18.parameters.parse(args);
77544
77851
  const commandParts = ["git", "diff", "--no-color", `-U${contextLines}`];
77545
77852
  if (staged) {
77546
77853
  commandParts.push("--staged");
@@ -77597,8 +77904,8 @@ ${result.stderr}`
77597
77904
  }
77598
77905
  };
77599
77906
  var gitDiff_default = {
77600
- ...toolInfo15,
77601
- handler: handler15
77907
+ ...toolInfo18,
77908
+ handler: handler18
77602
77909
  };
77603
77910
  // src/utils/cacheControl.ts
77604
77911
  var CACHEABLE_MODELS = ["sonnet", "opus", "haiku", "gemini"];
@@ -77929,7 +78236,10 @@ var allTools = [
77929
78236
  replaceInFile_default,
77930
78237
  searchFiles_default,
77931
78238
  writeToFile_default,
77932
- gitDiff_default
78239
+ gitDiff_default,
78240
+ getTodoItem_default,
78241
+ listTodoItems_default,
78242
+ updateTodoItem_default
77933
78243
  ];
77934
78244
  var toolHandlers = new Map(allTools.map((t) => [t.name, t]));
77935
78245
  async function createPullRequest(input, _context) {
@@ -77974,6 +78284,7 @@ async function confirm(input, context) {
77974
78284
  }
77975
78285
  await new Promise((resolve4) => setTimeout(resolve4, 50));
77976
78286
  try {
78287
+ process.stderr.write("\x07");
77977
78288
  const result = await esm_default2({ message: input.message });
77978
78289
  return result;
77979
78290
  } catch (_e) {
@@ -77985,6 +78296,7 @@ async function input(input2, context) {
77985
78296
  return input2.default ?? "";
77986
78297
  }
77987
78298
  await new Promise((resolve4) => setTimeout(resolve4, 50));
78299
+ process.stderr.write("\x07");
77988
78300
  const result = await getUserInput(input2.message, {
77989
78301
  default: input2.default
77990
78302
  });
@@ -77999,6 +78311,7 @@ async function select(input2, context) {
77999
78311
  }
78000
78312
  await new Promise((resolve4) => setTimeout(resolve4, 50));
78001
78313
  try {
78314
+ process.stderr.write("\x07");
78002
78315
  const result = await esm_default5({ message: input2.message, choices: input2.choices });
78003
78316
  return result;
78004
78317
  } catch (_e) {
@@ -78193,6 +78506,18 @@ async function updateMemory(input2, context) {
78193
78506
  const content = "content" in input2 ? input2.content : undefined;
78194
78507
  return provider3.updateMemory(input2.operation, input2.topic, content);
78195
78508
  }
78509
+ async function listTodoItems(input2, context) {
78510
+ const provider3 = context.toolProvider;
78511
+ return provider3.listTodoItems(input2.id, input2.status);
78512
+ }
78513
+ async function getTodoItem(input2, context) {
78514
+ const provider3 = context.toolProvider;
78515
+ return provider3.getTodoItem(input2.id);
78516
+ }
78517
+ async function updateTodoItem(input2, context) {
78518
+ const provider3 = context.toolProvider;
78519
+ return provider3.updateTodoItem(input2);
78520
+ }
78196
78521
  var localToolHandlers = {
78197
78522
  createPullRequest,
78198
78523
  createCommit,
@@ -78207,12 +78532,15 @@ var localToolHandlers = {
78207
78532
  invokeTool,
78208
78533
  taskEvent,
78209
78534
  getMemoryContext,
78210
- updateMemory
78535
+ updateMemory,
78536
+ listTodoItems,
78537
+ getTodoItem,
78538
+ updateTodoItem
78211
78539
  };
78212
78540
  async function toolCall(toolCall2, context) {
78213
- const handler16 = localToolHandlers[toolCall2.tool];
78214
- if (handler16) {
78215
- return handler16(toolCall2.input, context);
78541
+ const handler19 = localToolHandlers[toolCall2.tool];
78542
+ if (handler19) {
78543
+ return handler19(toolCall2.input, context);
78216
78544
  }
78217
78545
  throw new Error(`Unknown tool: ${toolCall2.tool}`);
78218
78546
  }
@@ -78284,11 +78612,15 @@ Workflow completed successfully.`);
78284
78612
  return output;
78285
78613
  } catch (e) {
78286
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
+ });
78287
78622
  if (error46 instanceof UserCancelledError) {
78288
78623
  logger.warn("Workflow cancelled by user.");
78289
- } else {
78290
- logger.error(`Workflow failed: ${error46.message}`);
78291
- logger.error(error46);
78292
78624
  }
78293
78625
  logger.info(usage.getUsageText());
78294
78626
  return;
@@ -78305,14 +78637,23 @@ ${JSON.stringify(schema, null, 2)}
78305
78637
  \`\`\`
78306
78638
  `;
78307
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.`;
78308
78641
  var MEMORY_USAGE_SECTION = `## Memory Usage
78309
78642
 
78310
78643
  You have access to a memory feature to store and retrieve information across tool calls.
78311
78644
 
78312
- Use memory to:
78313
- - Store context between steps.
78314
- - Keep track of important information like file paths or decisions made.
78315
- - 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
78316
78657
  `;
78317
78658
  var PLANNER_SYSTEM_PROMPT = `Role: Expert software architect and planner.
78318
78659
  Goal: Analyze user requests and create detailed, actionable implementation plans for software development tasks.
@@ -78321,6 +78662,8 @@ You are an expert software architect and planner with deep experience in breakin
78321
78662
 
78322
78663
  ${MEMORY_USAGE_SECTION}
78323
78664
 
78665
+ ${TOOL_USAGE_INSTRUCTION}
78666
+
78324
78667
  ## Your Role
78325
78668
 
78326
78669
  As a planner, your expertise lies in:
@@ -78506,6 +78849,8 @@ You are an expert software architect specializing in creating high-level plans f
78506
78849
 
78507
78850
  ${MEMORY_USAGE_SECTION}
78508
78851
 
78852
+ ${TOOL_USAGE_INSTRUCTION}
78853
+
78509
78854
  ## Your Role
78510
78855
 
78511
78856
  As a high-level planner for epics, your expertise lies in:
@@ -78623,9 +78968,12 @@ ${createJsonResponseInstruction({
78623
78968
  reason: "If no plan is needed, provide a reason here."
78624
78969
  })}
78625
78970
  `;
78971
+ var BRANCH_NAME_PATTERN = /^[a-zA-Z0-9/_-]+$/;
78626
78972
  var EpicPlanSchema = exports_external.object({
78627
78973
  plan: exports_external.string().nullish(),
78628
- 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
+ }),
78629
78977
  question: exports_external.object({
78630
78978
  question: exports_external.string(),
78631
78979
  defaultAnswer: exports_external.string().nullish()
@@ -78647,57 +78995,23 @@ ${task}
78647
78995
  </task>
78648
78996
  ${planSection}`;
78649
78997
  }
78650
- var EPIC_PLAN_UPDATE_SYSTEM_PROMPT = `Role: Plan update agent
78651
- 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.
78652
79000
 
78653
- You are a plan update agent responsible for tracking progress on an epic by updating the plan.
79001
+ ${TOOL_USAGE_INSTRUCTION}
78654
79002
 
78655
- ${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.
78656
79004
 
78657
79005
  ## Your Task
78658
79006
 
78659
- You will receive:
78660
- - **Current plan** (may use checkboxes \`- [ ]\`/\`- [x]\`, numbered lists, or other formats)
78661
- - **Implementation summary** describing what was just completed
78662
- - **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.
78663
79009
 
78664
79010
  ## Process
78665
79011
 
78666
- 1. **Find the completed item**: Locate the item in the plan that matches the completed task
78667
- 2. **Mark it as complete**:
78668
- - If using checkboxes: Change \`- [ ]\` to \`- [x]\`
78669
- - If using numbered lists: Add a ✅ prefix (e.g., "1. Task" → "✅ 1. Task")
78670
- - If using narrative: Mark completion in context-appropriate way
78671
- 3. **Scan for next task**: Find the next incomplete item
78672
- 4. **Determine completion status**: Check if all items are complete
78673
-
78674
- ## Output Requirements
78675
-
78676
- Return:
78677
- - **updatedPlan**: The full plan text with the completed item marked
78678
- - **isComplete**: boolean - true if all items are done, false if incomplete items remain
78679
- - **nextTask**: The text of the next incomplete item, or null if all items are complete
78680
-
78681
- ## Important Notes
78682
-
78683
- - Keep the plan structure and formatting intact
78684
- - Adapt completion marking to match the plan's format
78685
- - Extract the next task text without format prefixes (e.g., without "- [ ]" or "1.")
78686
- - If multiple incomplete items remain, return the first one in document order
78687
-
78688
- ## Response Format
78689
-
78690
- ${createJsonResponseInstruction({
78691
- updatedPlan: "The full plan with completed item marked",
78692
- isComplete: false,
78693
- nextTask: "The text of the next incomplete item (or null if complete)"
78694
- })}
79012
+ 1. Parse the plan to identify individual tasks.
79013
+ 2. For each task, call 'updateTodoItem' with the task description as the 'title'.
78695
79014
  `;
78696
- var UpdatedPlanSchema = exports_external.object({
78697
- updatedPlan: exports_external.string().describe("The updated plan with completed item marked as [x]"),
78698
- isComplete: exports_external.boolean().describe("True if all checklist items are completed, false if incomplete items remain"),
78699
- nextTask: exports_external.string().nullish().describe("The next incomplete checklist item to implement, or null if complete")
78700
- });
78701
79015
  var CODER_SYSTEM_PROMPT = `Role: AI developer.
78702
79016
  Goal: Implement the provided plan by writing and modifying code.
78703
79017
 
@@ -78705,6 +79019,8 @@ Your task is to implement the plan created and approved in Phase 1.
78705
79019
 
78706
79020
  ${MEMORY_USAGE_SECTION}
78707
79021
 
79022
+ ${TOOL_USAGE_INSTRUCTION}
79023
+
78708
79024
  ## Implementation Guidelines
78709
79025
 
78710
79026
  ### 1. Plan Analysis
@@ -78778,6 +79094,8 @@ You are an expert software developer. Your task is to fix a project that is fail
78778
79094
 
78779
79095
  ${MEMORY_USAGE_SECTION}
78780
79096
 
79097
+ ${TOOL_USAGE_INSTRUCTION}
79098
+
78781
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.
78782
79100
 
78783
79101
  Example for successful fix:
@@ -78815,6 +79133,8 @@ ${stderr || "(empty)"}
78815
79133
  var CODE_REVIEW_SYSTEM_PROMPT = `Role: Senior software engineer.
78816
79134
  Goal: Review code changes and provide specific, actionable feedback on any issues found.
78817
79135
 
79136
+ ${TOOL_USAGE_INSTRUCTION}
79137
+
78818
79138
  # Code Review Prompt
78819
79139
 
78820
79140
  You are a senior software engineer reviewing code changes.
@@ -78929,6 +79249,8 @@ ${instructions}
78929
79249
  var COMMIT_MESSAGE_SYSTEM_PROMPT = `Role: Expert git user.
78930
79250
  Goal: Generate a concise and descriptive commit message in conventional commit format based on staged changes.
78931
79251
 
79252
+ ${TOOL_USAGE_INSTRUCTION}
79253
+
78932
79254
  You are an expert at writing git commit messages.
78933
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.
78934
79256
 
@@ -78941,6 +79263,8 @@ ${createJsonResponseInstruction({
78941
79263
  var GET_PR_DETAILS_SYSTEM_PROMPT = `Role: Expert developer.
78942
79264
  Goal: Generate a pull request title and description based on the branch name, commits, and diff.
78943
79265
 
79266
+ ${TOOL_USAGE_INSTRUCTION}
79267
+
78944
79268
  You are an expert at creating pull requests.
78945
79269
  Based on the provided branch name, commit messages, and diff, generate a title and description for the pull request.
78946
79270
 
@@ -78953,6 +79277,8 @@ var INIT_WORKFLOW_ANALYZE_SYSTEM_PROMPT = `
78953
79277
  Role: Analyzer agent
78954
79278
  Goal: Produce a valid polkacodes YAML configuration for the project.
78955
79279
 
79280
+ ${TOOL_USAGE_INSTRUCTION}
79281
+
78956
79282
  Workflow
78957
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.
78958
79284
  - Package/build tool (npm, bun, pnpm, etc.)
@@ -79897,96 +80223,6 @@ ${provider3.toUpperCase()}_API_KEY=${providerConfig.apiKey}`;
79897
80223
  };
79898
80224
  // src/workflows/epic.workflow.ts
79899
80225
  var MAX_REVIEW_RETRIES = 5;
79900
- var BRANCH_NAME_PATTERN = /^[a-zA-Z0-9/_-]+$/;
79901
- function validateBranchName(name18) {
79902
- if (!BRANCH_NAME_PATTERN.test(name18)) {
79903
- return {
79904
- valid: false,
79905
- error: `Invalid branch name format: "${name18}". Branch names should contain only letters, numbers, hyphens, underscores, and forward slashes.`
79906
- };
79907
- }
79908
- if (name18.length > 255) {
79909
- return { valid: false, error: "Branch name is too long (max 255 characters)." };
79910
- }
79911
- return { valid: true };
79912
- }
79913
- async function performReviewAndFixCycle(iterationCount, taskItem, currentPlan, context) {
79914
- const { logger, step, tools: tools2 } = context;
79915
- for (let i = 0;i < MAX_REVIEW_RETRIES; i++) {
79916
- const diffResult = await tools2.executeCommand({ command: "git", args: ["diff", "--name-status", "HEAD~1", "HEAD"] });
79917
- const changedFiles = parseGitDiffNameStatus(diffResult.stdout);
79918
- if (changedFiles.length === 0) {
79919
- logger.info(`ℹ️ No files were changed. Skipping review.
79920
- `);
79921
- return { passed: true };
79922
- }
79923
- logger.info(`
79924
- \uD83D\uDD0E Review iteration ${i + 1}/${MAX_REVIEW_RETRIES}`);
79925
- logger.info(` Changed files: ${changedFiles.length}`);
79926
- const changeInfo = {
79927
- commitRange: "HEAD~1...HEAD",
79928
- changedFiles
79929
- };
79930
- const reviewAgentResult = await step(`review-${iterationCount}-${i}`, async () => {
79931
- const defaultContext = await getDefaultContext();
79932
- const memoryContext = await tools2.getMemoryContext();
79933
- const userMessage = `${defaultContext}
79934
- ${memoryContext}
79935
-
79936
- ${formatReviewToolInput(changeInfo)}`;
79937
- return await agentWorkflow({
79938
- systemPrompt: CODE_REVIEW_SYSTEM_PROMPT,
79939
- userMessage: [{ role: "user", content: userMessage }],
79940
- tools: [readFile_default, readBinaryFile_default, searchFiles_default, listFiles_default, gitDiff_default, readMemory_default, updateMemory_default, listMemoryTopics_default],
79941
- outputSchema: reviewOutputSchema
79942
- }, context);
79943
- });
79944
- if (reviewAgentResult.type !== "Exit" /* Exit */) {
79945
- logger.error(`\uD83D\uDEAB Review agent failed with status: ${reviewAgentResult.type}.`);
79946
- break;
79947
- }
79948
- const reviewResult = reviewAgentResult.object;
79949
- if (!reviewResult || !reviewResult.specificReviews || reviewResult.specificReviews.length === 0) {
79950
- logger.info(`✅ Review passed. No issues found.
79951
- `);
79952
- return { passed: true };
79953
- }
79954
- logger.warn(`⚠️ Review found ${reviewResult.specificReviews.length} issue(s). Attempting to fix...
79955
- `);
79956
- reviewResult.specificReviews.forEach((review, idx) => {
79957
- logger.warn(` ${idx + 1}. ${review.file}:${review.lines}`);
79958
- });
79959
- logger.warn("");
79960
- const reviewSummary = reviewResult.specificReviews.map((r) => `File: ${r.file} (lines: ${r.lines})
79961
- Review: ${r.review}`).join(`
79962
-
79963
- `);
79964
- const fixTask = `You are working on an epic. The original task was: "${taskItem}".
79965
-
79966
- Here is the full plan for context:
79967
- <plan>
79968
- ${currentPlan}
79969
- </plan>
79970
-
79971
- After an initial implementation, a review found the following issues. Please fix them:
79972
-
79973
- ${reviewSummary}`;
79974
- await step(`fix-${iterationCount}-${i}`, async () => {
79975
- await codeWorkflow({ task: fixTask, mode: "noninteractive" }, context);
79976
- });
79977
- await step(`commit-fix-${iterationCount}-${i}`, async () => {
79978
- await tools2.executeCommand({ command: "git", args: ["add", "."] });
79979
- await tools2.executeCommand({ command: "git", args: ["commit", "--amend", "--no-edit"] });
79980
- });
79981
- if (i === MAX_REVIEW_RETRIES - 1) {
79982
- logger.error(`
79983
- \uD83D\uDEAB Max retries (${MAX_REVIEW_RETRIES}) reached. Moving to the next task, but issues might remain.
79984
- `);
79985
- return { passed: false };
79986
- }
79987
- }
79988
- return { passed: false };
79989
- }
79990
80226
  async function createPlan2(input2, context) {
79991
80227
  const { task, plan, files, feedback } = input2;
79992
80228
  const content = [{ type: "text", text: getPlanPrompt(task, plan) }];
@@ -80036,37 +80272,113 @@ ${feedback}`
80036
80272
  }
80037
80273
  return { plan: "", reason: "Usage limit exceeded.", type: "Exit" /* Exit */, branchName: "" };
80038
80274
  }
80039
- async function updatePlanAgent(currentPlan, implementationSummary, completedTask, context) {
80040
- const userMessage = `# Current Plan
80041
-
80042
- <plan>
80043
- ${currentPlan}
80044
- </plan>
80045
-
80046
- # Implementation Summary
80047
-
80048
- ${implementationSummary}
80049
-
80050
- # Completed Task
80051
-
80052
- ${completedTask}
80053
-
80054
- Please update the plan by marking the completed task as [x] and identify the next incomplete task.`;
80055
- const result = await agentWorkflow({
80056
- systemPrompt: EPIC_PLAN_UPDATE_SYSTEM_PROMPT,
80057
- userMessage: [{ role: "user", content: userMessage }],
80058
- tools: [],
80059
- outputSchema: UpdatedPlanSchema
80060
- }, context);
80061
- if (result.type !== "Exit" /* Exit */ || !result.object) {
80062
- 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;
80063
80321
  }
80064
- const updateResult = result.object;
80065
- return {
80066
- updatedPlan: updateResult.updatedPlan,
80067
- isComplete: updateResult.isComplete,
80068
- nextTask: updateResult.nextTask || null
80069
- };
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
+ `);
80070
80382
  }
80071
80383
  async function runPreflightChecks(context) {
80072
80384
  const { logger, step, tools: tools2 } = context;
@@ -80088,264 +80400,336 @@ async function runPreflightChecks(context) {
80088
80400
  `);
80089
80401
  return { success: true };
80090
80402
  }
80091
- var epicWorkflow = async (input2, context) => {
80403
+ async function performReviewAndFixCycle(iterationCount, taskItem, highLevelPlan, context) {
80092
80404
  const { logger, step, tools: tools2 } = context;
80093
- const { task } = input2;
80094
- const workflowStartTime = Date.now();
80095
- const commitMessages = [];
80096
- if (!task || task.trim() === "") {
80097
- logger.error("❌ Error: Task cannot be empty. Please provide a valid task description.");
80098
- return;
80099
- }
80100
- const preflightResult = await runPreflightChecks(context);
80101
- if (!preflightResult.success) {
80102
- return;
80103
- }
80104
- async function createAndApprovePlan(task2, context2) {
80105
- const { logger: logger2, step: step2, tools: tools3 } = context2;
80106
- 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.
80107
80410
  `);
80108
- let feedback;
80109
- let highLevelPlan2;
80110
- let branchName2;
80111
- let planAttempt = 1;
80112
- try {
80113
- while (true) {
80114
- const result = await step2(`plan-${planAttempt}`, () => createPlan2({ task: task2, feedback }, context2));
80115
- planAttempt++;
80116
- if (result.question) {
80117
- const answer = await tools3.input({
80118
- message: result.question.question,
80119
- default: result.question.defaultAnswer || undefined
80120
- });
80121
- feedback = `The user answered the question "${result.question.question}" with: "${answer}"`;
80122
- continue;
80123
- }
80124
- if (!result.plan) {
80125
- if (result.reason) {
80126
- logger2.info(`No plan created. Reason: ${result.reason}`);
80127
- } else {
80128
- logger2.info("No plan created.");
80129
- }
80130
- return null;
80131
- }
80132
- logger2.info(`\uD83D\uDCDD Plan:
80133
- ${result.plan}`);
80134
- if (result.branchName) {
80135
- logger2.info(`\uD83C\uDF3F Suggested branch name: ${result.branchName}`);
80136
- }
80137
- feedback = await tools3.input({ message: "Press Enter to approve the plan, or provide feedback to refine it." });
80138
- if (feedback.trim() === "") {
80139
- highLevelPlan2 = result.plan;
80140
- branchName2 = result.branchName;
80141
- break;
80142
- }
80143
- }
80144
- } catch (e) {
80145
- if (e instanceof UserCancelledError) {
80146
- logger2.info("Plan creation cancelled by user.");
80147
- return null;
80148
- }
80149
- throw e;
80150
- }
80151
- if (!highLevelPlan2) {
80152
- logger2.info("Plan not approved. Exiting.");
80153
- return null;
80411
+ return { passed: true };
80154
80412
  }
80155
- if (!branchName2) {
80156
- logger2.error("❌ Error: No branch name was generated from the plan. Exiting.");
80157
- 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;
80158
80437
  }
80159
- logger2.info(`✅ High-level plan approved.
80160
- `);
80161
- return { plan: highLevelPlan2, branchName: branchName2 };
80162
- }
80163
- const planResult = await createAndApprovePlan(task, context);
80164
- if (!planResult) {
80165
- return;
80166
- }
80167
- const highLevelPlan = planResult.plan;
80168
- let branchName = planResult.branchName;
80169
- async function createFeatureBranch(branchName2, task2, plan, context2) {
80170
- const { logger: logger2, step: step2, tools: tools3 } = context2;
80171
- 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.
80172
80441
  `);
80173
- const branchValidation = validateBranchName(branchName2);
80174
- if (!branchValidation.valid) {
80175
- logger2.error(`❌ Error: ${branchValidation.error}`);
80176
- return { success: false, branchName: null };
80177
- }
80178
- let finalBranchName = branchName2;
80179
- const initialCheckResult = await step2("checkBranch-initial", async () => tools3.executeCommand({ command: "git", args: ["rev-parse", "--verify", finalBranchName] }));
80180
- if (initialCheckResult.exitCode === 0) {
80181
- logger2.warn(`⚠️ Branch '${finalBranchName}' already exists. Trying to find an available name...`);
80182
- const suffixMatch = branchName2.match(/-(\d+)$/);
80183
- let baseName = branchName2;
80184
- let counter = 2;
80185
- if (suffixMatch) {
80186
- baseName = branchName2.substring(0, suffixMatch.index);
80187
- counter = parseInt(suffixMatch[1], 10) + 1;
80188
- }
80189
- while (true) {
80190
- finalBranchName = `${baseName}-${counter}`;
80191
- const branchCheckResult = await step2(`checkBranch-${counter}`, async () => tools3.executeCommand({ command: "git", args: ["rev-parse", "--verify", finalBranchName] }));
80192
- if (branchCheckResult.exitCode !== 0) {
80193
- break;
80194
- }
80195
- counter++;
80196
- }
80442
+ return { passed: true };
80197
80443
  }
80198
- if (finalBranchName !== branchName2) {
80199
- 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}`);
80200
80448
  }
80201
- await step2("createBranch", async () => await tools3.executeCommand({ command: "git", args: ["checkout", "-b", finalBranchName] }));
80202
- 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
+
80203
80453
  `);
80204
- await tools3.updateMemory({
80205
- operation: "append",
80206
- topic: "epic-context",
80207
- content: `Epic: ${task2}
80208
- Branch: ${finalBranchName}
80209
- 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);
80210
80466
  });
80211
- await tools3.updateMemory({ operation: "append", topic: "epic-plan", content: plan });
80212
- return { success: true, branchName: finalBranchName };
80213
- }
80214
- const branchResult = await createFeatureBranch(branchName, task, highLevelPlan, context);
80215
- if (!branchResult.success || !branchResult.branchName) {
80216
- 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
+ }
80217
80477
  }
80218
- branchName = branchResult.branchName;
80219
- 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...
80220
80484
  `);
80221
80485
  logger.info(`${"=".repeat(80)}
80222
80486
  `);
80223
- let currentPlan = highLevelPlan;
80224
80487
  let iterationCount = 0;
80225
80488
  let isComplete = false;
80226
80489
  let nextTask = null;
80227
- try {
80228
- const firstTaskResult = await step("extract-first-task", async () => {
80229
- return await updatePlanAgent(currentPlan, "", "", context);
80230
- });
80231
- currentPlan = firstTaskResult.updatedPlan;
80232
- nextTask = firstTaskResult.nextTask;
80233
- isComplete = firstTaskResult.isComplete;
80234
- while (!isComplete && nextTask) {
80235
- iterationCount++;
80236
- const taskStartTime = Date.now();
80237
- 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(`
80238
80505
  ${"━".repeat(80)}`);
80239
- logger.info(`\uD83D\uDCCC Iteration ${iterationCount}`);
80240
- logger.info(`${"━".repeat(80)}`);
80241
- logger.info(`${nextTask}
80506
+ logger.info(`\uD83D\uDCCC Iteration ${iterationCount}`);
80507
+ logger.info(`${"━".repeat(80)}`);
80508
+ logger.info(`${nextTask}
80242
80509
  `);
80243
- let implementationSummary = "";
80244
- const codeResult = await step(`task-${iterationCount}`, async () => {
80245
- 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:
80246
80512
 
80247
80513
  <plan>
80248
- ${currentPlan}
80514
+ ${highLevelPlan}
80249
80515
  </plan>
80250
80516
 
80251
80517
  Your current task is to implement this specific item:
80252
80518
  ${nextTask}
80253
80519
 
80254
80520
  Focus only on this item, but use the plan for context.`;
80255
- return await codeWorkflow({ task: taskWithContext, mode: "noninteractive" }, context);
80256
- });
80257
- if (codeResult && "summaries" in codeResult && codeResult.summaries.length > 0) {
80258
- implementationSummary = codeResult.summaries.join(`
80259
- `);
80260
- } else {
80261
- implementationSummary = nextTask;
80262
- }
80263
- const commitMessage = `feat: ${nextTask}`;
80264
- await step(`commit-initial-${iterationCount}`, async () => {
80265
- await tools2.executeCommand({ command: "git", args: ["add", "."] });
80266
- await tools2.executeCommand({ command: "git", args: ["commit", "-m", commitMessage] });
80267
- });
80268
- commitMessages.push(commitMessage);
80269
- const { passed: reviewPassed } = await performReviewAndFixCycle(iterationCount, nextTask, currentPlan, context);
80270
- const taskElapsed = Date.now() - taskStartTime;
80271
- const taskElapsedTime = formatElapsedTime(taskElapsed);
80272
- if (reviewPassed) {
80273
- logger.info(`✅ Iteration ${iterationCount} completed successfully (${taskElapsedTime})`);
80274
- } else {
80275
- logger.warn(`⚠️ Iteration ${iterationCount} completed with potential issues (${taskElapsedTime})`);
80276
- }
80277
- const updateResult = await step(`update-plan-${iterationCount}`, async () => {
80278
- return await updatePlanAgent(currentPlan, implementationSummary, nextTask ?? "", context);
80279
- });
80280
- currentPlan = updateResult.updatedPlan;
80281
- isComplete = updateResult.isComplete;
80282
- nextTask = updateResult.nextTask;
80283
- await tools2.updateMemory({ operation: "replace", topic: "epic-plan", content: currentPlan });
80284
- const checkboxCompleted = (currentPlan.match(/- \[x\]/g) || []).length;
80285
- const checkboxTotal = (currentPlan.match(/- \[[x ]\]/g) || []).length;
80286
- const checkmarkCompleted = (currentPlan.match(/^✅/gm) || []).length;
80287
- let progressMessage = "";
80288
- if (checkboxTotal > 0) {
80289
- progressMessage = `${checkboxCompleted}/${checkboxTotal} items completed`;
80290
- } else if (checkmarkCompleted > 0) {
80291
- progressMessage = `${checkmarkCompleted} items completed`;
80292
- } else {
80293
- 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.");
80294
80540
  }
80295
- 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(`
80296
80566
  \uD83D\uDCCA Progress: ${progressMessage}`);
80297
- if (isComplete) {
80298
- logger.info(`✅ All tasks complete!
80567
+ if (isComplete) {
80568
+ logger.info(`✅ All tasks complete!
80299
80569
  `);
80300
- break;
80301
- }
80302
- if (nextTask) {
80303
- logger.info(`\uD83D\uDCCC Next task: ${nextTask}
80570
+ break;
80571
+ }
80572
+ if (nextTask) {
80573
+ logger.info(`\uD83D\uDCCC Next task: ${nextTask}
80304
80574
  `);
80305
- }
80306
- 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.
80307
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}`);
80308
80721
  }
80309
80722
  } catch (error46) {
80310
80723
  logger.error(`
80311
80724
  ❌ Epic workflow failed: ${error46 instanceof Error ? error46.message : String(error46)}`);
80312
- logger.info(`
80725
+ if (branchName) {
80726
+ logger.info(`
80313
80727
  Branch '${branchName}' was created but work is incomplete.`);
80314
- 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}
80315
80729
  `);
80316
- await tools2.updateMemory({ operation: "remove", topic: "epic-context" });
80317
- await tools2.updateMemory({ operation: "remove", topic: "epic-plan" });
80730
+ }
80318
80731
  throw error46;
80319
80732
  }
80320
- const totalElapsed = Date.now() - workflowStartTime;
80321
- const totalElapsedTime = formatElapsedTime(totalElapsed);
80322
- const avgTimePerIteration = iterationCount > 0 ? formatElapsedTime(totalElapsed / iterationCount) : "N/A";
80323
- logger.info(`
80324
- ${"=".repeat(80)}`);
80325
- logger.info("\uD83C\uDF89 Epic Workflow Complete!");
80326
- logger.info(`${"=".repeat(80)}`);
80327
- logger.info(`
80328
- \uD83D\uDCCA Summary:`);
80329
- logger.info(` Total iterations: ${iterationCount}`);
80330
- logger.info(` Total commits: ${commitMessages.length}`);
80331
- logger.info(` Branch: ${branchName}`);
80332
- logger.info(` Total time: ${totalElapsedTime}`);
80333
- logger.info(` Average per iteration: ${avgTimePerIteration}
80334
- `);
80335
- logger.info("\uD83D\uDCDD Commits created:");
80336
- commitMessages.forEach((msg, idx) => {
80337
- logger.info(` ${idx + 1}. ${msg}`);
80338
- });
80339
- logger.info(`
80340
- \uD83D\uDCA1 Next steps:`);
80341
- logger.info(` • Review your changes: git log`);
80342
- logger.info(` • Push to remote: git push origin ${branchName}`);
80343
- logger.info(` • Create a pull request on your Git platform
80344
- `);
80345
- logger.info(`${"=".repeat(80)}
80346
- `);
80347
- await tools2.updateMemory({ operation: "remove", topic: "epic-context" });
80348
- await tools2.updateMemory({ operation: "remove", topic: "epic-plan" });
80349
80733
  };
80350
80734
 
80351
80735
  // src/workflows/task.workflow.ts