@polka-codes/cli 0.9.48 → 0.9.50

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 +1198 -545
  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.50";
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,89 @@ ${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
+ status: TodoStatus
48613
+ });
48614
+ var UpdateTodoItemInputSchema = exports_external.object({
48615
+ operation: exports_external.enum(["add", "update"]),
48616
+ id: exports_external.string().nullish(),
48617
+ parentId: exports_external.string().nullish(),
48618
+ title: exports_external.string().nullish(),
48619
+ description: exports_external.string().nullish(),
48620
+ status: TodoStatus.nullish()
48621
+ }).superRefine((data, ctx) => {
48622
+ if (data.operation === "add") {
48623
+ if (!data.title) {
48624
+ ctx.addIssue({
48625
+ code: "custom",
48626
+ message: 'Title is required for "add" operation',
48627
+ path: ["title"]
48628
+ });
48629
+ }
48630
+ } else if (data.operation === "update") {
48631
+ if (!data.id) {
48632
+ ctx.addIssue({
48633
+ code: "custom",
48634
+ message: 'ID is required for "update" operation',
48635
+ path: ["id"]
48636
+ });
48637
+ }
48638
+ }
48639
+ });
48640
+ var UpdateTodoItemOutputSchema = exports_external.object({
48641
+ id: exports_external.string()
48642
+ });
48643
+
48644
+ // ../core/src/tools/listTodoItems.ts
48645
+ var toolInfo7 = {
48646
+ name: "listTodoItems",
48647
+ 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.",
48648
+ parameters: exports_external.object({
48649
+ id: exports_external.string().nullish(),
48650
+ status: TodoStatus.nullish()
48651
+ })
48652
+ };
48653
+ var handler7 = async (provider, args) => {
48654
+ if (!provider.listTodoItems) {
48655
+ return {
48656
+ type: "Error" /* Error */,
48657
+ message: {
48658
+ type: "error-text",
48659
+ value: "Not possible to list to-do items."
48660
+ }
48661
+ };
48662
+ }
48663
+ const { id, status } = toolInfo7.parameters.parse(args);
48664
+ const items = await provider.listTodoItems(id, status);
48665
+ return {
48666
+ type: "Reply" /* Reply */,
48667
+ message: {
48668
+ type: "json",
48669
+ value: items
48670
+ }
48671
+ };
48672
+ };
48673
+ var listTodoItems_default = {
48674
+ ...toolInfo7,
48675
+ handler: handler7
48573
48676
  };
48574
48677
  // ../core/src/tools/readBinaryFile.ts
48575
- var toolInfo6 = {
48678
+ var toolInfo8 = {
48576
48679
  name: "readBinaryFile",
48577
48680
  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
48681
  parameters: exports_external.object({
48579
48682
  url: exports_external.string().describe("The URL or local path of the file to read.")
48580
48683
  })
48581
48684
  };
48582
- var handler6 = async (provider, args) => {
48685
+ var handler8 = async (provider, args) => {
48583
48686
  if (!provider.readBinaryFile) {
48584
48687
  return {
48585
48688
  type: "Error" /* Error */,
@@ -48589,7 +48692,7 @@ var handler6 = async (provider, args) => {
48589
48692
  }
48590
48693
  };
48591
48694
  }
48592
- const { url: url2 } = toolInfo6.parameters.parse(args);
48695
+ const { url: url2 } = toolInfo8.parameters.parse(args);
48593
48696
  try {
48594
48697
  const filePart = await provider.readBinaryFile(url2);
48595
48698
  return {
@@ -48618,11 +48721,11 @@ var handler6 = async (provider, args) => {
48618
48721
  }
48619
48722
  };
48620
48723
  var readBinaryFile_default = {
48621
- ...toolInfo6,
48622
- handler: handler6
48724
+ ...toolInfo8,
48725
+ handler: handler8
48623
48726
  };
48624
48727
  // ../core/src/tools/readFile.ts
48625
- var toolInfo7 = {
48728
+ var toolInfo9 = {
48626
48729
  name: "readFile",
48627
48730
  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
48731
  parameters: exports_external.object({
@@ -48659,7 +48762,7 @@ var toolInfo7 = {
48659
48762
  ]
48660
48763
  })
48661
48764
  };
48662
- var handler7 = async (provider, args) => {
48765
+ var handler9 = async (provider, args) => {
48663
48766
  if (!provider.readFile) {
48664
48767
  return {
48665
48768
  type: "Error" /* Error */,
@@ -48669,7 +48772,7 @@ var handler7 = async (provider, args) => {
48669
48772
  }
48670
48773
  };
48671
48774
  }
48672
- const { path: paths, includeIgnored } = toolInfo7.parameters.parse(args);
48775
+ const { path: paths, includeIgnored } = toolInfo9.parameters.parse(args);
48673
48776
  const resp = [];
48674
48777
  for (const path of paths) {
48675
48778
  const fileContent = await provider.readFile(path, includeIgnored);
@@ -48694,19 +48797,19 @@ var handler7 = async (provider, args) => {
48694
48797
  };
48695
48798
  };
48696
48799
  var readFile_default = {
48697
- ...toolInfo7,
48698
- handler: handler7
48800
+ ...toolInfo9,
48801
+ handler: handler9
48699
48802
  };
48700
48803
  // ../core/src/tools/readMemory.ts
48701
- var toolInfo8 = {
48804
+ var toolInfo10 = {
48702
48805
  name: "readMemory",
48703
- description: "Reads content from a memory topic.",
48806
+ 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
48807
  parameters: exports_external.object({
48705
48808
  topic: exports_external.string().optional().describe('The topic to read from memory. Defaults to ":default:".')
48706
48809
  })
48707
48810
  };
48708
- var handler8 = async (provider, args) => {
48709
- const { topic } = toolInfo8.parameters.parse(args);
48811
+ var handler10 = async (provider, args) => {
48812
+ const { topic } = toolInfo10.parameters.parse(args);
48710
48813
  const content = await provider.readMemory(topic);
48711
48814
  if (content) {
48712
48815
  return {
@@ -48728,11 +48831,11 @@ ${content}
48728
48831
  };
48729
48832
  };
48730
48833
  var readMemory_default = {
48731
- ...toolInfo8,
48732
- handler: handler8
48834
+ ...toolInfo10,
48835
+ handler: handler10
48733
48836
  };
48734
48837
  // ../core/src/tools/removeFile.ts
48735
- var toolInfo9 = {
48838
+ var toolInfo11 = {
48736
48839
  name: "removeFile",
48737
48840
  description: "Request to remove a file at the specified path.",
48738
48841
  parameters: exports_external.object({
@@ -48748,7 +48851,7 @@ var toolInfo9 = {
48748
48851
  ]
48749
48852
  })
48750
48853
  };
48751
- var handler9 = async (provider, args) => {
48854
+ var handler11 = async (provider, args) => {
48752
48855
  if (!provider.removeFile) {
48753
48856
  return {
48754
48857
  type: "Error" /* Error */,
@@ -48758,7 +48861,7 @@ var handler9 = async (provider, args) => {
48758
48861
  }
48759
48862
  };
48760
48863
  }
48761
- const parsed = toolInfo9.parameters.safeParse(args);
48864
+ const parsed = toolInfo11.parameters.safeParse(args);
48762
48865
  if (!parsed.success) {
48763
48866
  return {
48764
48867
  type: "Error" /* Error */,
@@ -48779,11 +48882,11 @@ var handler9 = async (provider, args) => {
48779
48882
  };
48780
48883
  };
48781
48884
  var removeFile_default = {
48782
- ...toolInfo9,
48783
- handler: handler9
48885
+ ...toolInfo11,
48886
+ handler: handler11
48784
48887
  };
48785
48888
  // ../core/src/tools/renameFile.ts
48786
- var toolInfo10 = {
48889
+ var toolInfo12 = {
48787
48890
  name: "renameFile",
48788
48891
  description: "Request to rename a file from source path to target path.",
48789
48892
  parameters: exports_external.object({
@@ -48801,7 +48904,7 @@ var toolInfo10 = {
48801
48904
  ]
48802
48905
  })
48803
48906
  };
48804
- var handler10 = async (provider, args) => {
48907
+ var handler12 = async (provider, args) => {
48805
48908
  if (!provider.renameFile) {
48806
48909
  return {
48807
48910
  type: "Error" /* Error */,
@@ -48811,7 +48914,7 @@ var handler10 = async (provider, args) => {
48811
48914
  }
48812
48915
  };
48813
48916
  }
48814
- const { source_path, target_path } = toolInfo10.parameters.parse(args);
48917
+ const { source_path, target_path } = toolInfo12.parameters.parse(args);
48815
48918
  await provider.renameFile(source_path, target_path);
48816
48919
  return {
48817
48920
  type: "Reply" /* Reply */,
@@ -48822,12 +48925,12 @@ var handler10 = async (provider, args) => {
48822
48925
  };
48823
48926
  };
48824
48927
  var renameFile_default = {
48825
- ...toolInfo10,
48826
- handler: handler10
48928
+ ...toolInfo12,
48929
+ handler: handler12
48827
48930
  };
48828
48931
  // ../core/src/tools/utils/replaceInFile.ts
48829
48932
  var replaceInFile = (fileContent, diff) => {
48830
- const blockPattern = /<<<<<+ SEARCH>?\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
48933
+ const blockPattern = /^\s*<<<<<+\s*SEARCH>?\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+\s*REPLACE\s*$/gm;
48831
48934
  const blocks = [];
48832
48935
  for (let match = blockPattern.exec(diff);match !== null; match = blockPattern.exec(diff)) {
48833
48936
  blocks.push({ search: match[1], replace: match[2] });
@@ -48900,7 +49003,7 @@ var replaceInFile = (fileContent, diff) => {
48900
49003
  };
48901
49004
 
48902
49005
  // ../core/src/tools/replaceInFile.ts
48903
- var toolInfo11 = {
49006
+ var toolInfo13 = {
48904
49007
  name: "replaceInFile",
48905
49008
  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
49009
  parameters: exports_external.object({
@@ -49010,7 +49113,7 @@ function oldFeature() {
49010
49113
  ]
49011
49114
  })
49012
49115
  };
49013
- var handler11 = async (provider, args) => {
49116
+ var handler13 = async (provider, args) => {
49014
49117
  if (!provider.readFile || !provider.writeFile) {
49015
49118
  return {
49016
49119
  type: "Error" /* Error */,
@@ -49020,7 +49123,7 @@ var handler11 = async (provider, args) => {
49020
49123
  }
49021
49124
  };
49022
49125
  }
49023
- const parsed = toolInfo11.parameters.safeParse(args);
49126
+ const parsed = toolInfo13.parameters.safeParse(args);
49024
49127
  if (!parsed.success) {
49025
49128
  return {
49026
49129
  type: "Error" /* Error */,
@@ -49084,11 +49187,11 @@ var handler11 = async (provider, args) => {
49084
49187
  }
49085
49188
  };
49086
49189
  var replaceInFile_default = {
49087
- ...toolInfo11,
49088
- handler: handler11
49190
+ ...toolInfo13,
49191
+ handler: handler13
49089
49192
  };
49090
49193
  // ../core/src/tools/searchFiles.ts
49091
- var toolInfo12 = {
49194
+ var toolInfo14 = {
49092
49195
  name: "searchFiles",
49093
49196
  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
49197
  parameters: exports_external.object({
@@ -49112,7 +49215,7 @@ var toolInfo12 = {
49112
49215
  ]
49113
49216
  })
49114
49217
  };
49115
- var handler12 = async (provider, args) => {
49218
+ var handler14 = async (provider, args) => {
49116
49219
  if (!provider.searchFiles) {
49117
49220
  return {
49118
49221
  type: "Error" /* Error */,
@@ -49122,7 +49225,7 @@ var handler12 = async (provider, args) => {
49122
49225
  }
49123
49226
  };
49124
49227
  }
49125
- const parsed = toolInfo12.parameters.safeParse(args);
49228
+ const parsed = toolInfo14.parameters.safeParse(args);
49126
49229
  if (!parsed.success) {
49127
49230
  return {
49128
49231
  type: "Error" /* Error */,
@@ -49160,13 +49263,13 @@ ${files.join(`
49160
49263
  }
49161
49264
  };
49162
49265
  var searchFiles_default = {
49163
- ...toolInfo12,
49164
- handler: handler12
49266
+ ...toolInfo14,
49267
+ handler: handler14
49165
49268
  };
49166
49269
  // ../core/src/tools/updateMemory.ts
49167
- var toolInfo13 = {
49270
+ var toolInfo15 = {
49168
49271
  name: "updateMemory",
49169
- description: "Appends, replaces, or removes content from a memory topic.",
49272
+ 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
49273
  parameters: exports_external.object({
49171
49274
  operation: exports_external.enum(["append", "replace", "remove"]).describe("The operation to perform."),
49172
49275
  topic: exports_external.string().nullish().describe('The topic to update in memory. Defaults to ":default:".'),
@@ -49191,7 +49294,7 @@ var toolInfo13 = {
49191
49294
  }
49192
49295
  })
49193
49296
  };
49194
- var handler13 = async (provider, args) => {
49297
+ var handler15 = async (provider, args) => {
49195
49298
  if (!provider.updateMemory) {
49196
49299
  return {
49197
49300
  type: "Error" /* Error */,
@@ -49201,7 +49304,7 @@ var handler13 = async (provider, args) => {
49201
49304
  }
49202
49305
  };
49203
49306
  }
49204
- const params = toolInfo13.parameters.parse(args);
49307
+ const params = toolInfo15.parameters.parse(args);
49205
49308
  await provider.updateMemory(params.operation, params.topic ?? undefined, "content" in params ? params.content : undefined);
49206
49309
  switch (params.operation) {
49207
49310
  case "append":
@@ -49231,11 +49334,41 @@ var handler13 = async (provider, args) => {
49231
49334
  }
49232
49335
  };
49233
49336
  var updateMemory_default = {
49234
- ...toolInfo13,
49235
- handler: handler13
49337
+ ...toolInfo15,
49338
+ handler: handler15
49339
+ };
49340
+ // ../core/src/tools/updateTodoItem.ts
49341
+ var toolInfo16 = {
49342
+ name: "updateTodoItem",
49343
+ description: "Add or update a to-do item.",
49344
+ parameters: UpdateTodoItemInputSchema
49345
+ };
49346
+ var handler16 = async (provider, args) => {
49347
+ if (!provider.updateTodoItem) {
49348
+ return {
49349
+ type: "Error" /* Error */,
49350
+ message: {
49351
+ type: "error-text",
49352
+ value: "Not possible to update a to-do item."
49353
+ }
49354
+ };
49355
+ }
49356
+ const input = toolInfo16.parameters.parse(args);
49357
+ const result = await provider.updateTodoItem(input);
49358
+ return {
49359
+ type: "Reply" /* Reply */,
49360
+ message: {
49361
+ type: "json",
49362
+ value: result
49363
+ }
49364
+ };
49365
+ };
49366
+ var updateTodoItem_default = {
49367
+ ...toolInfo16,
49368
+ handler: handler16
49236
49369
  };
49237
49370
  // ../core/src/tools/writeToFile.ts
49238
- var toolInfo14 = {
49371
+ var toolInfo17 = {
49239
49372
  name: "writeToFile",
49240
49373
  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
49374
  parameters: exports_external.object({
@@ -49264,7 +49397,7 @@ export default App;
49264
49397
  ]
49265
49398
  })
49266
49399
  };
49267
- var handler14 = async (provider, args) => {
49400
+ var handler17 = async (provider, args) => {
49268
49401
  if (!provider.writeFile) {
49269
49402
  return {
49270
49403
  type: "Error" /* Error */,
@@ -49274,7 +49407,7 @@ var handler14 = async (provider, args) => {
49274
49407
  }
49275
49408
  };
49276
49409
  }
49277
- const parsed = toolInfo14.parameters.safeParse(args);
49410
+ const parsed = toolInfo17.parameters.safeParse(args);
49278
49411
  if (!parsed.success) {
49279
49412
  return {
49280
49413
  type: "Error" /* Error */,
@@ -49298,8 +49431,8 @@ var handler14 = async (provider, args) => {
49298
49431
  };
49299
49432
  };
49300
49433
  var writeToFile_default = {
49301
- ...toolInfo14,
49302
- handler: handler14
49434
+ ...toolInfo17,
49435
+ handler: handler17
49303
49436
  };
49304
49437
  // ../core/src/UsageMeter.ts
49305
49438
  class UsageMeter {
@@ -51340,15 +51473,15 @@ function useKeypress(userHandler) {
51340
51473
  signal.current = userHandler;
51341
51474
  useEffect((rl) => {
51342
51475
  let ignore = false;
51343
- const handler15 = withUpdates((_input, event) => {
51476
+ const handler18 = withUpdates((_input, event) => {
51344
51477
  if (ignore)
51345
51478
  return;
51346
51479
  signal.current(event, rl);
51347
51480
  });
51348
- rl.input.on("keypress", handler15);
51481
+ rl.input.on("keypress", handler18);
51349
51482
  return () => {
51350
51483
  ignore = true;
51351
- rl.input.removeListener("keypress", handler15);
51484
+ rl.input.removeListener("keypress", handler18);
51352
51485
  };
51353
51486
  }, []);
51354
51487
  }
@@ -51507,16 +51640,16 @@ class Emitter {
51507
51640
 
51508
51641
  class SignalExitBase {
51509
51642
  }
51510
- var signalExitWrap = (handler15) => {
51643
+ var signalExitWrap = (handler18) => {
51511
51644
  return {
51512
51645
  onExit(cb, opts) {
51513
- return handler15.onExit(cb, opts);
51646
+ return handler18.onExit(cb, opts);
51514
51647
  },
51515
51648
  load() {
51516
- return handler15.load();
51649
+ return handler18.load();
51517
51650
  },
51518
51651
  unload() {
51519
- return handler15.unload();
51652
+ return handler18.unload();
51520
51653
  }
51521
51654
  };
51522
51655
  };
@@ -52337,36 +52470,147 @@ async function searchFiles(path, regex, filePattern, cwd, excludeFiles) {
52337
52470
  }
52338
52471
 
52339
52472
  // ../cli-shared/src/provider.ts
52473
+ class InMemoryStore {
52474
+ #data;
52475
+ async read() {
52476
+ return this.#data;
52477
+ }
52478
+ async write(data) {
52479
+ this.#data = data;
52480
+ }
52481
+ }
52340
52482
  var getProvider = (options = {}) => {
52341
52483
  const ig = import_ignore2.default().add(options.excludeFiles ?? []);
52342
- const memoryStore = {};
52484
+ const memoryStore = options.memoryStore ?? new InMemoryStore;
52485
+ const todoItemStore = options.todoItemStore ?? new InMemoryStore;
52343
52486
  const defaultMemoryTopic = ":default:";
52344
52487
  const provider2 = {
52488
+ listTodoItems: async (id, status) => {
52489
+ const todoItems = await todoItemStore.read() ?? [];
52490
+ let items;
52491
+ if (!id) {
52492
+ items = todoItems.filter((i) => !i.id.includes("."));
52493
+ } else {
52494
+ const parent = todoItems.find((i) => i.id === id);
52495
+ if (!parent) {
52496
+ throw new Error(`To-do item with id ${id} not found`);
52497
+ }
52498
+ items = todoItems.filter((i) => i.id.startsWith(`${id}.`) && i.id.split(".").length === id.split(".").length + 1);
52499
+ }
52500
+ if (status) {
52501
+ items = items.filter((item) => item.status === status);
52502
+ }
52503
+ items.sort((a, b) => {
52504
+ const aParts = a.id.split(".");
52505
+ const bParts = b.id.split(".");
52506
+ const len = Math.min(aParts.length, bParts.length);
52507
+ for (let i = 0;i < len; i++) {
52508
+ const comparison = aParts[i].localeCompare(bParts[i], undefined, { numeric: true });
52509
+ if (comparison !== 0) {
52510
+ return comparison;
52511
+ }
52512
+ }
52513
+ return aParts.length - bParts.length;
52514
+ });
52515
+ return items;
52516
+ },
52517
+ getTodoItem: async (id) => {
52518
+ const todoItems = await todoItemStore.read() ?? [];
52519
+ const item = todoItems.find((i) => i.id === id);
52520
+ if (!item) {
52521
+ throw new Error(`To-do item with id ${id} not found`);
52522
+ }
52523
+ const subItems = todoItems.filter((i) => i.id.startsWith(`${id}.`) && i.id.split(".").length === id.split(".").length + 1).map(({ id: id2, title }) => ({ id: id2, title }));
52524
+ return { ...item, subItems };
52525
+ },
52526
+ updateTodoItem: async (input) => {
52527
+ const todoItems = await todoItemStore.read() ?? [];
52528
+ if (input.operation === "add") {
52529
+ const { parentId, title, description, status } = input;
52530
+ if (!title) {
52531
+ throw new Error("Title is required for add operation");
52532
+ }
52533
+ let newId;
52534
+ if (parentId) {
52535
+ const parent = todoItems.find((i) => i.id === parentId);
52536
+ if (!parent) {
52537
+ throw new Error(`Parent to-do item with id ${parentId} not found`);
52538
+ }
52539
+ const childItems = todoItems.filter((i) => i.id.startsWith(`${parentId}.`) && i.id.split(".").length === parentId.split(".").length + 1);
52540
+ const maxId = childItems.reduce((max, item) => {
52541
+ const parts = item.id.split(".");
52542
+ const lastPart = parseInt(parts[parts.length - 1], 10);
52543
+ return Math.max(max, lastPart);
52544
+ }, 0);
52545
+ newId = `${parentId}.${maxId + 1}`;
52546
+ } else {
52547
+ const rootItems = todoItems.filter((i) => !i.id.includes("."));
52548
+ const maxId = rootItems.reduce((max, item) => {
52549
+ const idNum = parseInt(item.id, 10);
52550
+ return Math.max(max, idNum);
52551
+ }, 0);
52552
+ newId = `${maxId + 1}`;
52553
+ }
52554
+ const newItem = {
52555
+ id: newId,
52556
+ title,
52557
+ description: description ?? "",
52558
+ status: status ?? "open"
52559
+ };
52560
+ await todoItemStore.write([...todoItems, newItem]);
52561
+ return { id: newId };
52562
+ } else {
52563
+ const { id } = input;
52564
+ if (!id) {
52565
+ throw new Error("ID is required for update operation");
52566
+ }
52567
+ const item = todoItems.find((i) => i.id === id);
52568
+ if (!item) {
52569
+ throw new Error(`To-do item with id ${id} not found`);
52570
+ }
52571
+ if (input.title != null) {
52572
+ item.title = input.title;
52573
+ }
52574
+ if (input.description != null) {
52575
+ item.description = input.description ?? "";
52576
+ }
52577
+ if (input.status != null) {
52578
+ item.status = input.status;
52579
+ }
52580
+ await todoItemStore.write(todoItems);
52581
+ return { id };
52582
+ }
52583
+ },
52345
52584
  listMemoryTopics: async () => {
52346
- return Object.keys(memoryStore);
52585
+ const memory = await memoryStore.read() ?? {};
52586
+ return Object.keys(memory);
52347
52587
  },
52348
52588
  readMemory: async (topic = defaultMemoryTopic) => {
52349
- return memoryStore[topic];
52589
+ const memory = await memoryStore.read() ?? {};
52590
+ return memory[topic];
52350
52591
  },
52351
52592
  updateMemory: async (operation, topic, content) => {
52352
52593
  const memoryTopic = topic ?? defaultMemoryTopic;
52594
+ const memory = await memoryStore.read() ?? {};
52353
52595
  switch (operation) {
52354
52596
  case "append":
52355
52597
  if (content === undefined) {
52356
52598
  throw new Error("Content is required for append operation.");
52357
52599
  }
52358
- memoryStore[memoryTopic] = (memoryStore[memoryTopic] || "") + content;
52600
+ memory[memoryTopic] = `${memory[memoryTopic] || ""}
52601
+ ${content}`;
52359
52602
  break;
52360
52603
  case "replace":
52361
52604
  if (content === undefined) {
52362
52605
  throw new Error("Content is required for replace operation.");
52363
52606
  }
52364
- memoryStore[memoryTopic] = content;
52607
+ memory[memoryTopic] = content;
52365
52608
  break;
52366
52609
  case "remove":
52367
- delete memoryStore[memoryTopic];
52610
+ delete memory[memoryTopic];
52368
52611
  break;
52369
52612
  }
52613
+ await memoryStore.write(memory);
52370
52614
  },
52371
52615
  readFile: async (path, includeIgnored) => {
52372
52616
  if (!includeIgnored && ig.ignores(path)) {
@@ -64126,16 +64370,12 @@ var uiMessagesSchema = lazyValidator(() => zodSchema(exports_external.array(expo
64126
64370
 
64127
64371
  // ../workflow/src/agent.workflow.ts
64128
64372
  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;
64373
+ const event = (name17, event2) => step(name17, () => tools2.taskEvent(event2));
64374
+ const { tools: toolInfo18, maxToolRoundTrips = 200 } = input;
64135
64375
  const messages = "systemPrompt" in input ? [{ role: "system", content: input.systemPrompt }] : input.messages;
64136
64376
  await event("start-task", { kind: "StartTask" /* StartTask */, systemPrompt: "systemPrompt" in input ? input.systemPrompt : "" });
64137
64377
  const toolSet = {};
64138
- for (const tool3 of toolInfo15) {
64378
+ for (const tool3 of toolInfo18) {
64139
64379
  toolSet[tool3.name] = {
64140
64380
  description: tool3.description,
64141
64381
  inputSchema: jsonSchema(toJSONSchema(tool3.parameters))
@@ -64183,7 +64423,9 @@ var agentWorkflow = async (input, { step, tools: tools2 }) => {
64183
64423
  await event(`end-round-${i}`, { kind: "EndRequest" /* EndRequest */, message: textContent });
64184
64424
  if (toolCalls.length === 0) {
64185
64425
  if (!input.outputSchema) {
64186
- return { type: "Exit" /* Exit */, message: textContent };
64426
+ const exitReason2 = { type: "Exit" /* Exit */, message: textContent };
64427
+ await event("end-task", { kind: "EndTask" /* EndTask */, exitReason: exitReason2 });
64428
+ return exitReason2;
64187
64429
  }
64188
64430
  const parsed = parseJsonFromMarkdown(textContent);
64189
64431
  if (!parsed.success) {
@@ -64197,7 +64439,9 @@ var agentWorkflow = async (input, { step, tools: tools2 }) => {
64197
64439
  nextMessage = [{ role: "user", content: errorMessage }];
64198
64440
  continue;
64199
64441
  }
64200
- return { type: "Exit" /* Exit */, message: textContent, object: validated.data };
64442
+ const exitReason = { type: "Exit" /* Exit */, message: textContent, object: validated.data };
64443
+ await event("end-task", { kind: "EndTask" /* EndTask */, exitReason });
64444
+ return exitReason;
64201
64445
  }
64202
64446
  const toolResults = [];
64203
64447
  for (const toolCall of toolCalls) {
@@ -64266,6 +64510,7 @@ var agentWorkflow = async (input, { step, tools: tools2 }) => {
64266
64510
  }
64267
64511
  ];
64268
64512
  }
64513
+ await event("end-task", { kind: "EndTask" /* EndTask */, exitReason: { type: "UsageExceeded" } });
64269
64514
  throw new Error("Maximum number of tool round trips reached.");
64270
64515
  };
64271
64516
  // ../workflow/src/json-ai-types.ts
@@ -64835,6 +65080,53 @@ var chalk = createChalk();
64835
65080
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
64836
65081
  var source_default = chalk;
64837
65082
 
65083
+ // ../cli-shared/src/utils/parameterSimplifier.ts
65084
+ function replaceInFileSimplifier(params) {
65085
+ return { path: params.path };
65086
+ }
65087
+ function writeToFileSimplifier(params) {
65088
+ return { path: params.path };
65089
+ }
65090
+ function readFileSimplifier(params) {
65091
+ return { path: params.path, includeIgnored: params.includeIgnored };
65092
+ }
65093
+ function listFilesSimplifier(params) {
65094
+ const maxCount = params.maxCount;
65095
+ return {
65096
+ path: params.path,
65097
+ recursive: params.recursive,
65098
+ ...maxCount !== 2000 && { maxCount }
65099
+ };
65100
+ }
65101
+ function searchFilesSimplifier(params) {
65102
+ return { ...params };
65103
+ }
65104
+ function executeCommandSimplifier(params) {
65105
+ return { command: params.command, requiresApproval: params.requiresApproval };
65106
+ }
65107
+ function updateMemorySimplifier(params) {
65108
+ return { operation: params.operation, topic: params.topic };
65109
+ }
65110
+ var SIMPLIFIERS = {
65111
+ replaceInFile: replaceInFileSimplifier,
65112
+ writeToFile: writeToFileSimplifier,
65113
+ readFile: readFileSimplifier,
65114
+ listFiles: listFilesSimplifier,
65115
+ searchFiles: searchFilesSimplifier,
65116
+ executeCommand: executeCommandSimplifier,
65117
+ updateMemory: updateMemorySimplifier
65118
+ };
65119
+ function simplifyToolParameters(toolName, params) {
65120
+ if (params === undefined || params === null) {
65121
+ return {};
65122
+ }
65123
+ const simplifier = SIMPLIFIERS[toolName];
65124
+ if (simplifier) {
65125
+ return simplifier(params);
65126
+ }
65127
+ return { ...params };
65128
+ }
65129
+
64838
65130
  // ../cli-shared/src/utils/eventHandler.ts
64839
65131
  var taskToolCallStats = new Map;
64840
65132
  var globalToolCallStats = new Map;
@@ -64859,8 +65151,26 @@ function logToolCallStats(stream, statsMap, title) {
64859
65151
  customConsole.log("No tools were called.");
64860
65152
  }
64861
65153
  }
65154
+ var mergeToolCallStats = (a, b) => {
65155
+ const merged = new Map;
65156
+ for (const [tool3, stat] of a) {
65157
+ merged.set(tool3, { ...stat });
65158
+ }
65159
+ for (const [tool3, stat] of b) {
65160
+ const existing = merged.get(tool3);
65161
+ if (existing) {
65162
+ existing.calls += stat.calls;
65163
+ existing.success += stat.success;
65164
+ existing.errors += stat.errors;
65165
+ } else {
65166
+ merged.set(tool3, { ...stat });
65167
+ }
65168
+ }
65169
+ return merged;
65170
+ };
64862
65171
  function logGlobalToolCallStats(stream) {
64863
- logToolCallStats(stream, globalToolCallStats, "Global Tool Call Stats");
65172
+ const merged = mergeToolCallStats(globalToolCallStats, taskToolCallStats);
65173
+ logToolCallStats(stream, merged, "Global Tool Call Stats");
64864
65174
  }
64865
65175
  var printEvent = (verbose, usageMeter, stream = process.stdout) => {
64866
65176
  if (verbose < 0) {
@@ -64868,6 +65178,7 @@ var printEvent = (verbose, usageMeter, stream = process.stdout) => {
64868
65178
  }
64869
65179
  const customConsole = new Console(stream, stream);
64870
65180
  let hadReasoning = false;
65181
+ let hasText = false;
64871
65182
  const write = stream.write.bind(stream);
64872
65183
  return (event) => {
64873
65184
  switch (event.kind) {
@@ -64884,6 +65195,7 @@ ${event.systemPrompt}`);
64884
65195
  }
64885
65196
  break;
64886
65197
  case "StartRequest" /* StartRequest */:
65198
+ hasText = false;
64887
65199
  if (verbose > 0) {
64888
65200
  customConsole.log(`
64889
65201
 
@@ -64937,6 +65249,11 @@ ${event.systemPrompt}`);
64937
65249
  customConsole.log(`
64938
65250
 
64939
65251
  ======== Request Ended ========
65252
+ `);
65253
+ }
65254
+ if (verbose === 0 && hasText) {
65255
+ write(`
65256
+
64940
65257
  `);
64941
65258
  }
64942
65259
  if (verbose > 1) {
@@ -64950,6 +65267,9 @@ ${event.systemPrompt}`);
64950
65267
  `);
64951
65268
  hadReasoning = false;
64952
65269
  }
65270
+ if (event.newText.trim().length > 0) {
65271
+ hasText = true;
65272
+ }
64953
65273
  write(event.newText);
64954
65274
  break;
64955
65275
  }
@@ -64962,9 +65282,10 @@ ${event.systemPrompt}`);
64962
65282
  }
64963
65283
  case "ToolUse" /* ToolUse */: {
64964
65284
  if (verbose > 0) {
65285
+ const params = verbose > 1 ? event.params : simplifyToolParameters(event.tool, event.params);
64965
65286
  customConsole.log(source_default.yellow(`
64966
65287
 
64967
- Tool use:`, event.tool), event.params);
65288
+ Tool use:`, event.tool), params);
64968
65289
  }
64969
65290
  const stats = taskToolCallStats.get(event.tool) ?? { calls: 0, success: 0, errors: 0 };
64970
65291
  stats.calls++;
@@ -65000,18 +65321,28 @@ Tool error:`, event.tool));
65000
65321
  `);
65001
65322
  customConsole.log("Reason:", event.exitReason.type);
65002
65323
  switch (event.exitReason.type) {
65324
+ case "Error": {
65325
+ const { error: error46 } = event.exitReason;
65326
+ customConsole.error(source_default.red(`Workflow failed: ${error46.message}`));
65327
+ if (verbose > 0 && error46.stack) {
65328
+ customConsole.error(source_default.red(error46.stack));
65329
+ }
65330
+ break;
65331
+ }
65003
65332
  case "Exit" /* Exit */:
65004
- customConsole.log("Exit Message:", event.exitReason.message);
65333
+ if (verbose > 0) {
65334
+ customConsole.log("Exit Message:", event.exitReason.message);
65335
+ }
65005
65336
  break;
65006
65337
  }
65338
+ for (const [tool3, taskStats] of taskToolCallStats.entries()) {
65339
+ const globalStats = globalToolCallStats.get(tool3) ?? { calls: 0, success: 0, errors: 0 };
65340
+ globalStats.calls += taskStats.calls;
65341
+ globalStats.success += taskStats.success;
65342
+ globalStats.errors += taskStats.errors;
65343
+ globalToolCallStats.set(tool3, globalStats);
65344
+ }
65007
65345
  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
65346
  logToolCallStats(stream, taskToolCallStats, "Task Tool Call Stats");
65016
65347
  }
65017
65348
  break;
@@ -77501,7 +77832,7 @@ function annotateDiffWithLineNumbers(diff) {
77501
77832
  }
77502
77833
 
77503
77834
  // src/tools/gitDiff.ts
77504
- var toolInfo15 = {
77835
+ var toolInfo18 = {
77505
77836
  name: "git_diff",
77506
77837
  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
77838
  parameters: exports_external.object({
@@ -77530,7 +77861,7 @@ var toolInfo15 = {
77530
77861
  }, exports_external.boolean().optional().default(false)).describe("Annotate the diff with line numbers for additions and deletions.")
77531
77862
  })
77532
77863
  };
77533
- var handler15 = async (provider3, args) => {
77864
+ var handler18 = async (provider3, args) => {
77534
77865
  if (!provider3.executeCommand) {
77535
77866
  return {
77536
77867
  type: "Error" /* Error */,
@@ -77540,7 +77871,7 @@ var handler15 = async (provider3, args) => {
77540
77871
  }
77541
77872
  };
77542
77873
  }
77543
- const { staged, file: file2, commitRange, contextLines, includeLineNumbers } = toolInfo15.parameters.parse(args);
77874
+ const { staged, file: file2, commitRange, contextLines, includeLineNumbers } = toolInfo18.parameters.parse(args);
77544
77875
  const commandParts = ["git", "diff", "--no-color", `-U${contextLines}`];
77545
77876
  if (staged) {
77546
77877
  commandParts.push("--staged");
@@ -77597,8 +77928,8 @@ ${result.stderr}`
77597
77928
  }
77598
77929
  };
77599
77930
  var gitDiff_default = {
77600
- ...toolInfo15,
77601
- handler: handler15
77931
+ ...toolInfo18,
77932
+ handler: handler18
77602
77933
  };
77603
77934
  // src/utils/cacheControl.ts
77604
77935
  var CACHEABLE_MODELS = ["sonnet", "opus", "haiku", "gemini"];
@@ -77929,7 +78260,10 @@ var allTools = [
77929
78260
  replaceInFile_default,
77930
78261
  searchFiles_default,
77931
78262
  writeToFile_default,
77932
- gitDiff_default
78263
+ gitDiff_default,
78264
+ getTodoItem_default,
78265
+ listTodoItems_default,
78266
+ updateTodoItem_default
77933
78267
  ];
77934
78268
  var toolHandlers = new Map(allTools.map((t) => [t.name, t]));
77935
78269
  async function createPullRequest(input, _context) {
@@ -77974,6 +78308,7 @@ async function confirm(input, context) {
77974
78308
  }
77975
78309
  await new Promise((resolve4) => setTimeout(resolve4, 50));
77976
78310
  try {
78311
+ process.stderr.write("\x07");
77977
78312
  const result = await esm_default2({ message: input.message });
77978
78313
  return result;
77979
78314
  } catch (_e) {
@@ -77985,6 +78320,7 @@ async function input(input2, context) {
77985
78320
  return input2.default ?? "";
77986
78321
  }
77987
78322
  await new Promise((resolve4) => setTimeout(resolve4, 50));
78323
+ process.stderr.write("\x07");
77988
78324
  const result = await getUserInput(input2.message, {
77989
78325
  default: input2.default
77990
78326
  });
@@ -77999,6 +78335,7 @@ async function select(input2, context) {
77999
78335
  }
78000
78336
  await new Promise((resolve4) => setTimeout(resolve4, 50));
78001
78337
  try {
78338
+ process.stderr.write("\x07");
78002
78339
  const result = await esm_default5({ message: input2.message, choices: input2.choices });
78003
78340
  return result;
78004
78341
  } catch (_e) {
@@ -78188,11 +78525,31 @@ ${defaultContent}
78188
78525
  return contextParts.join(`
78189
78526
  `);
78190
78527
  }
78528
+ async function readMemory(input2, context) {
78529
+ const provider3 = context.toolProvider;
78530
+ return await provider3.readMemory(input2.topic) ?? "";
78531
+ }
78532
+ async function listMemoryTopics(_input, context) {
78533
+ const provider3 = context.toolProvider;
78534
+ return provider3.listMemoryTopics();
78535
+ }
78191
78536
  async function updateMemory(input2, context) {
78192
78537
  const provider3 = context.toolProvider;
78193
78538
  const content = "content" in input2 ? input2.content : undefined;
78194
78539
  return provider3.updateMemory(input2.operation, input2.topic, content);
78195
78540
  }
78541
+ async function listTodoItems(input2, context) {
78542
+ const provider3 = context.toolProvider;
78543
+ return provider3.listTodoItems(input2.id, input2.status);
78544
+ }
78545
+ async function getTodoItem(input2, context) {
78546
+ const provider3 = context.toolProvider;
78547
+ return provider3.getTodoItem(input2.id);
78548
+ }
78549
+ async function updateTodoItem(input2, context) {
78550
+ const provider3 = context.toolProvider;
78551
+ return provider3.updateTodoItem(input2);
78552
+ }
78196
78553
  var localToolHandlers = {
78197
78554
  createPullRequest,
78198
78555
  createCommit,
@@ -78207,12 +78564,17 @@ var localToolHandlers = {
78207
78564
  invokeTool,
78208
78565
  taskEvent,
78209
78566
  getMemoryContext,
78210
- updateMemory
78567
+ readMemory,
78568
+ listMemoryTopics,
78569
+ updateMemory,
78570
+ listTodoItems,
78571
+ getTodoItem,
78572
+ updateTodoItem
78211
78573
  };
78212
78574
  async function toolCall(toolCall2, context) {
78213
- const handler16 = localToolHandlers[toolCall2.tool];
78214
- if (handler16) {
78215
- return handler16(toolCall2.input, context);
78575
+ const handler19 = localToolHandlers[toolCall2.tool];
78576
+ if (handler19) {
78577
+ return handler19(toolCall2.input, context);
78216
78578
  }
78217
78579
  throw new Error(`Unknown tool: ${toolCall2.tool}`);
78218
78580
  }
@@ -78236,7 +78598,7 @@ async function runWorkflow(workflow2, workflowInput, options) {
78236
78598
  maxCost: config4.budget
78237
78599
  });
78238
78600
  const onEvent = printEvent(verbose, usage, process.stderr);
78239
- const toolProvider = getProvider({ excludeFiles: config4.excludeFiles });
78601
+ const toolProvider = (options.getProvider ?? getProvider)({ excludeFiles: config4.excludeFiles });
78240
78602
  const commandConfig = providerConfig.getConfigForCommand(commandName);
78241
78603
  if (!commandConfig) {
78242
78604
  throw new Error(`No provider configured for command: ${commandName}`);
@@ -78284,11 +78646,15 @@ Workflow completed successfully.`);
78284
78646
  return output;
78285
78647
  } catch (e) {
78286
78648
  const error46 = e;
78649
+ onEvent({
78650
+ kind: "EndTask" /* EndTask */,
78651
+ exitReason: {
78652
+ type: "Error",
78653
+ error: { message: error46.message, stack: error46.stack }
78654
+ }
78655
+ });
78287
78656
  if (error46 instanceof UserCancelledError) {
78288
78657
  logger.warn("Workflow cancelled by user.");
78289
- } else {
78290
- logger.error(`Workflow failed: ${error46.message}`);
78291
- logger.error(error46);
78292
78658
  }
78293
78659
  logger.info(usage.getUsageText());
78294
78660
  return;
@@ -78305,14 +78671,33 @@ ${JSON.stringify(schema, null, 2)}
78305
78671
  \`\`\`
78306
78672
  `;
78307
78673
  }
78674
+ var TOOL_USAGE_INSTRUCTION = `
78675
+ ## Action Line
78676
+
78677
+ Before any tool call, emit a single high-level action line.
78678
+
78679
+ You MUST follow these style constraints for the action line:
78680
+ - NO filler or preambles.
78681
+ - DO NOT use "ok", "okay", "alright".
78682
+ - DO NOT use first person ("I", "I'm", "I will", "I'll", etc.).
78683
+ - NO apologies, hedging, or promises about later work.
78684
+ `;
78308
78685
  var MEMORY_USAGE_SECTION = `## Memory Usage
78309
78686
 
78310
78687
  You have access to a memory feature to store and retrieve information across tool calls.
78311
78688
 
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.
78689
+ ### Topic Organization
78690
+
78691
+ Memory is organized using topics, which are like named containers for different types of information:
78692
+ - **Default topic** (\`:default:\`): Used when no topic is specified. Good for general context.
78693
+ - **Named topics**: Create meaningful topic names to organize different types of information
78694
+
78695
+ ### Best Practices
78696
+
78697
+ - Store decisions and context that inform subsequent steps
78698
+ - Use named topics to organize different types of information
78699
+ - Use the default topic for simple, single-context scenarios
78700
+ - Memory persists across all tool calls within the current workflow
78316
78701
  `;
78317
78702
  var PLANNER_SYSTEM_PROMPT = `Role: Expert software architect and planner.
78318
78703
  Goal: Analyze user requests and create detailed, actionable implementation plans for software development tasks.
@@ -78321,6 +78706,8 @@ You are an expert software architect and planner with deep experience in breakin
78321
78706
 
78322
78707
  ${MEMORY_USAGE_SECTION}
78323
78708
 
78709
+ ${TOOL_USAGE_INSTRUCTION}
78710
+
78324
78711
  ## Your Role
78325
78712
 
78326
78713
  As a planner, your expertise lies in:
@@ -78506,6 +78893,8 @@ You are an expert software architect specializing in creating high-level plans f
78506
78893
 
78507
78894
  ${MEMORY_USAGE_SECTION}
78508
78895
 
78896
+ ${TOOL_USAGE_INSTRUCTION}
78897
+
78509
78898
  ## Your Role
78510
78899
 
78511
78900
  As a high-level planner for epics, your expertise lies in:
@@ -78528,15 +78917,21 @@ Effective planning requires understanding before action:
78528
78917
  - File system exploration (\`listFiles\`, \`searchFiles\`) reveals structure and patterns.
78529
78918
  - Reading existing files (\`readFile\`) shows coding style and conventions.
78530
78919
 
78531
- 3. **High-Level, Not Granular**
78532
- - Your plan should focus on the "what" and "why" at a strategic level.
78533
- - Avoid getting bogged down in implementation minutiae. For example, instead of "add a 20px margin to the button", say "Update the component styling to align with the design system".
78534
- - The output should be a roadmap, not a turn-by-turn navigation.
78920
+ 3. **High-Level Strategy with Detailed Tasks**
78921
+ - "High-level" refers to strategic phases and architectural decisions, not individual implementation steps.
78922
+ - While the plan structure should be strategic (phases, components), each task item must contain detailed implementation guidance.
78923
+ - Each task should include specific file paths, function names, implementation patterns, and technical details.
78924
+ - The plan should be detailed enough that task creation does not require additional codebase exploration.
78925
+ - Example of appropriate detail level:
78926
+ * ❌ Too vague: "Add authentication"
78927
+ * ❌ Too granular: "Add a 20px margin to the button on line 45"
78928
+ * ✅ Appropriate: "Implement authentication endpoints in \`src/api/auth.ts\` with \`POST /api/auth/login\` that validates credentials using bcrypt and returns JWT tokens"
78535
78929
 
78536
78930
  4. **Clarity for AI Implementation**
78537
- - The plan must be clear enough for AI agents to implement directly.
78538
- - Each task should be a concrete, implementable piece of work.
78539
- - Focus on what needs to be built and how.
78931
+ - The plan must be clear enough for AI agents to implement directly without further exploration.
78932
+ - Each task should be a concrete, implementable piece of work with all necessary details.
78933
+ - Include specific technical information: file paths, function signatures, dependencies, patterns to follow.
78934
+ - The task creation agent should be able to parse the plan and create todo items without exploring the codebase.
78540
78935
 
78541
78936
  ## Your Approach
78542
78937
 
@@ -78557,33 +78952,61 @@ For epic-scale work, **checkboxes are RECOMMENDED** to help track progress throu
78557
78952
 
78558
78953
  **Recommended Checklist Format**:
78559
78954
  - Use markdown checkboxes (\`- [ ] item\`) for major components and tasks
78955
+ - Create nested task breakdowns with 3-4 levels of detail
78560
78956
  - Each checkbox represents a distinct, trackable piece of work
78561
- - Each checkbox item should be specific and implementable independently
78562
- - Group related checkboxes under numbered sections or phases when appropriate
78957
+ - Each checkbox item must include detailed implementation guidance
78958
+ - Group related checkboxes under numbered sections or phases
78563
78959
  - Items will be implemented one at a time iteratively
78564
78960
  - After each implementation, the completed item will be marked with \`- [x]\` when the plan is updated
78565
78961
 
78566
- **Example checklist format**:
78962
+ **Implementation Details Requirements**:
78963
+
78964
+ Each task item must specify:
78965
+ - **Exact file paths** for new files or modifications (e.g., \`src/api/auth.ts\`)
78966
+ - **Function signatures and class names** to implement (e.g., \`async function authenticateUser(email: string, password: string)\`)
78967
+ - **Specific patterns from the codebase** to follow (e.g., "Follow the middleware pattern used in \`src/middleware/logger.ts\`")
78968
+ - **Required imports and dependencies** (e.g., "Import \`bcrypt\` for password hashing, use \`jsonwebtoken\` for JWT generation")
78969
+ - **Error handling approach** (e.g., "Use \`ApiError\` class from \`src/errors.ts\`")
78970
+ - **Integration points** with existing code (e.g., "Register middleware in \`src/app.ts\` before route handlers")
78971
+ - **Testing requirements** if applicable (e.g., "Add unit tests in \`src/api/__tests__/auth.test.ts\`")
78972
+
78973
+ **Example checklist format with proper detail**:
78567
78974
  \`\`\`
78568
78975
  1. Phase 1: Backend API Development
78569
- - [ ] Design and implement user authentication endpoints
78976
+ - [ ] Design and implement user authentication endpoints in \`src/api/auth.ts\`
78977
+ - [ ] Create \`POST /api/auth/login\` endpoint that accepts email/password in request body, validates using bcrypt, returns JWT token using \`jsonwebtoken\` library with 24h expiration
78978
+ - [ ] Create \`POST /api/auth/register\` endpoint that validates input with zod schema (\`email\`, \`password\` min 8 chars), hashes password with bcrypt (10 rounds), stores in database using Prisma ORM
78979
+ - [ ] Add authentication middleware in \`src/middleware/auth.ts\` that verifies JWT tokens from Authorization header and attaches user object to \`req.user\`
78570
78980
  - [ ] Create database schema and migrations
78571
- - [ ] Implement data validation middleware
78981
+ - [ ] Define User model in \`prisma/schema.prisma\` with fields: id (UUID), email (unique string), passwordHash (string), createdAt (DateTime), updatedAt (DateTime)
78982
+ - [ ] Generate migration with \`npx prisma migrate dev --name add-user-auth\`
78983
+ - [ ] Update \`src/db/client.ts\` to export Prisma client instance
78984
+ - [ ] Implement data validation middleware in \`src/middleware/validation.ts\`
78985
+ - [ ] Create \`validateRequest\` function that accepts zod schema and returns Express middleware
78986
+ - [ ] Add error handling that returns 400 status with validation errors in response body
78987
+ - [ ] Follow error format used in \`src/middleware/errorHandler.ts\`
78572
78988
 
78573
78989
  2. Phase 2: Frontend Integration
78574
- - [ ] Build authentication UI components
78575
- - [ ] Integrate with backend API
78990
+ - [ ] Build authentication UI components in \`src/components/auth/\`
78991
+ - [ ] Create \`LoginForm.tsx\` component with email/password fields using React Hook Form, submit handler calls \`/api/auth/login\`
78992
+ - [ ] Create \`RegisterForm.tsx\` component with email/password/confirmPassword fields, client-side validation matches backend rules
78993
+ - [ ] Add \`AuthContext.tsx\` using React Context API to manage auth state (user object, isAuthenticated boolean, login/logout functions)
78994
+ - [ ] Integrate with backend API using \`src/lib/api.ts\`
78995
+ - [ ] Add \`login(email, password)\` function that calls \`POST /api/auth/login\`, stores JWT in localStorage, returns user object
78996
+ - [ ] Add \`register(email, password)\` function that calls \`POST /api/auth/register\`
78997
+ - [ ] Add \`logout()\` function that removes JWT from localStorage and clears auth state
78576
78998
  - [ ] Add error handling and loading states
78999
+ - [ ] Display API errors in form using \`ErrorMessage\` component from \`src/components/ui/ErrorMessage.tsx\`
79000
+ - [ ] Show loading spinner during API calls using \`LoadingSpinner\` component from \`src/components/ui/LoadingSpinner.tsx\`
79001
+ - [ ] Add toast notifications for success/error using \`react-hot-toast\` library
78577
79002
  \`\`\`
78578
79003
 
78579
- **Alternative Format**:
78580
- You may also use numbered lists if checkboxes don't fit the task structure. However, each item should still be clear, actionable, and implementable independently.
78581
-
78582
79004
  **What to Include**:
78583
- - Actionable implementation steps
78584
- - Technical requirements and specifications
78585
- - Specific files, functions, or components to create/modify
78586
- - Context needed for implementation
79005
+ - Actionable implementation steps with complete technical specifications
79006
+ - Exact file paths, function names, and implementation patterns
79007
+ - All dependencies, imports, and integration points
79008
+ - Specific technical constraints and requirements
79009
+ - Testing approach if applicable
78587
79010
 
78588
79011
  **What NOT to Include**:
78589
79012
  - Future enhancements or scope outside the current task
@@ -78602,9 +79025,11 @@ Branch names should:
78602
79025
 
78603
79026
  1. Analyze the task and the existing plan (if any).
78604
79027
  2. If the requirements are clear and you can generate or update the plan:
78605
- a. Provide the plan in the "plan" field using the checklist format described above
78606
- b. Propose a suitable git branch name in the "branchName" field.
78607
- c. Include relevant file paths in the "files" array if applicable
79028
+ a. **Explore the codebase first** to understand patterns, conventions, and existing implementations
79029
+ b. Provide the plan in the "plan" field using the checklist format with detailed implementation guidance
79030
+ c. Ensure the plan is detailed enough that task creation does not require additional codebase exploration
79031
+ d. Each task item must include specific file paths, function names, implementation patterns, and technical details
79032
+ e. Propose a suitable git branch name in the "branchName" field
78608
79033
  3. If the requirements are not clear:
78609
79034
  a. Ask a clarifying question in the "question" field
78610
79035
  4. If the task is already implemented or no action is needed:
@@ -78623,9 +79048,12 @@ ${createJsonResponseInstruction({
78623
79048
  reason: "If no plan is needed, provide a reason here."
78624
79049
  })}
78625
79050
  `;
79051
+ var BRANCH_NAME_PATTERN = /^[a-zA-Z0-9/_-]+$/;
78626
79052
  var EpicPlanSchema = exports_external.object({
78627
79053
  plan: exports_external.string().nullish(),
78628
- branchName: exports_external.string(),
79054
+ 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), {
79055
+ message: "Invalid branch name format. Branch names should contain only letters, numbers, hyphens, underscores, and forward slashes."
79056
+ }),
78629
79057
  question: exports_external.object({
78630
79058
  question: exports_external.string(),
78631
79059
  defaultAnswer: exports_external.string().nullish()
@@ -78647,57 +79075,92 @@ ${task}
78647
79075
  </task>
78648
79076
  ${planSection}`;
78649
79077
  }
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
79078
+ var EPIC_ADD_TODO_ITEMS_SYSTEM_PROMPT = `Role: Task creation agent
79079
+ Goal: Parse a detailed epic plan and create todo items from the provided task breakdowns.
78652
79080
 
78653
- You are a plan update agent responsible for tracking progress on an epic by updating the plan.
79081
+ ${TOOL_USAGE_INSTRUCTION}
78654
79082
 
78655
- ${MEMORY_USAGE_SECTION}
79083
+ You are a task creation agent responsible for parsing a detailed epic plan and creating todo items that can be executed autonomously by an AI coding agent.
78656
79084
 
78657
- ## Your Task
79085
+ ## Your Responsibility
78658
79086
 
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
79087
+ Your goal is to create todo items that are:
79088
+ - **Specific and actionable**: Each item should be clear enough for an AI agent to implement without human intervention
79089
+ - **Well-documented**: Include detailed implementation guidance extracted from the plan
79090
+ - **Context-rich**: Specify relevant files that will be modified or created (as provided in the plan)
79091
+ - **Self-contained**: Each item should be implementable independently with the context from the plan
78663
79092
 
78664
- ## Process
79093
+ ## Plan Structure Expectations
78665
79094
 
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
79095
+ The plan you receive contains all necessary implementation details. You should NOT need to explore the codebase because:
79096
+ - Each task in the plan already includes specific file paths
79097
+ - Function and class names are specified in the plan
79098
+ - Implementation patterns and approaches are provided
79099
+ - Dependencies and imports are listed
79100
+ - Technical specifications are included
79101
+ - Integration points are documented
78673
79102
 
78674
- ## Output Requirements
79103
+ Your job is to extract these details from the plan and create todo items, not to research or discover them.
78675
79104
 
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
79105
+ ## Todo Item Requirements
78680
79106
 
78681
- ## Important Notes
79107
+ For each task in the plan, create a todo item using the \`updateTodoItem\` tool with:
78682
79108
 
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
79109
+ ### 1. **title** (required)
79110
+ A concise, action-oriented task name that clearly states what needs to be done.
78687
79111
 
78688
- ## Response Format
79112
+ **Examples:**
79113
+ - ✅ "Implement user authentication with JWT tokens"
79114
+ - ✅ "Add validation middleware for API endpoints"
79115
+ - ❌ "Authentication" (too vague)
79116
+
79117
+ ### 2. **description** (required)
79118
+ Detailed implementation instructions extracted from the plan. Include:
79119
+
79120
+ **Must extract from the plan:**
79121
+ - **Specific files to create or modify** with exact paths (as specified in the plan)
79122
+ - **Function/class names** to implement or modify (as specified in the plan)
79123
+ - **Implementation patterns** to follow (as referenced in the plan)
79124
+ - **Technical requirements** and constraints (as documented in the plan)
79125
+ - **Dependencies** and imports needed (as listed in the plan)
79126
+ - **Integration points** with existing code (as described in the plan)
79127
+
79128
+ **Example of extracting from a detailed plan task:**
79129
+
79130
+ Plan task:
79131
+ \`\`\`
79132
+ - [ ] Add authentication middleware in \`src/middleware/auth.ts\` that verifies JWT tokens from Authorization header and attaches user object to \`req.user\`
79133
+ \`\`\`
79134
+
79135
+ Todo item description:
79136
+ \`\`\`
79137
+ Create a new authentication middleware in \`src/middleware/auth.ts\`:
79138
+
79139
+ 1. Implement \`authenticateJWT\` function that:
79140
+ - Extracts JWT token from Authorization header
79141
+ - Verifies token (implementation details from plan)
79142
+ - Attaches user object to \`req.user\`
79143
+ - Returns 401 error for invalid/missing tokens
79144
+
79145
+ 2. Export the middleware for use in route definitions
79146
+ \`\`\`
79147
+
79148
+ **Note:** All implementation details should come from the plan. Do not add information not present in the plan.
79149
+
79150
+ ## Process
79151
+
79152
+ 1. **Read and parse the plan** provided in the user message to identify individual tasks
79153
+ 2. **Parse the plan structure** to understand the task hierarchy and details
79154
+ 3. **For each task in the plan:**
79155
+ a. Extract the specific files mentioned in the task
79156
+ b. Extract implementation patterns specified in the plan
79157
+ c. Create a detailed description using the plan's guidance
79158
+ d. Identify all relevant files from the plan
79159
+ e. Call \`updateTodoItem\` with operation='add', title and description
79160
+
79161
+ **Important:** Do NOT explore the codebase. All necessary information is already in the plan.
78689
79162
 
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
- })}
78695
79163
  `;
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
79164
  var CODER_SYSTEM_PROMPT = `Role: AI developer.
78702
79165
  Goal: Implement the provided plan by writing and modifying code.
78703
79166
 
@@ -78705,6 +79168,8 @@ Your task is to implement the plan created and approved in Phase 1.
78705
79168
 
78706
79169
  ${MEMORY_USAGE_SECTION}
78707
79170
 
79171
+ ${TOOL_USAGE_INSTRUCTION}
79172
+
78708
79173
  ## Implementation Guidelines
78709
79174
 
78710
79175
  ### 1. Plan Analysis
@@ -78778,6 +79243,8 @@ You are an expert software developer. Your task is to fix a project that is fail
78778
79243
 
78779
79244
  ${MEMORY_USAGE_SECTION}
78780
79245
 
79246
+ ${TOOL_USAGE_INSTRUCTION}
79247
+
78781
79248
  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
79249
 
78783
79250
  Example for successful fix:
@@ -78815,6 +79282,8 @@ ${stderr || "(empty)"}
78815
79282
  var CODE_REVIEW_SYSTEM_PROMPT = `Role: Senior software engineer.
78816
79283
  Goal: Review code changes and provide specific, actionable feedback on any issues found.
78817
79284
 
79285
+ ${TOOL_USAGE_INSTRUCTION}
79286
+
78818
79287
  # Code Review Prompt
78819
79288
 
78820
79289
  You are a senior software engineer reviewing code changes.
@@ -78929,6 +79398,8 @@ ${instructions}
78929
79398
  var COMMIT_MESSAGE_SYSTEM_PROMPT = `Role: Expert git user.
78930
79399
  Goal: Generate a concise and descriptive commit message in conventional commit format based on staged changes.
78931
79400
 
79401
+ ${TOOL_USAGE_INSTRUCTION}
79402
+
78932
79403
  You are an expert at writing git commit messages.
78933
79404
  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
79405
 
@@ -78941,6 +79412,8 @@ ${createJsonResponseInstruction({
78941
79412
  var GET_PR_DETAILS_SYSTEM_PROMPT = `Role: Expert developer.
78942
79413
  Goal: Generate a pull request title and description based on the branch name, commits, and diff.
78943
79414
 
79415
+ ${TOOL_USAGE_INSTRUCTION}
79416
+
78944
79417
  You are an expert at creating pull requests.
78945
79418
  Based on the provided branch name, commit messages, and diff, generate a title and description for the pull request.
78946
79419
 
@@ -78953,6 +79426,8 @@ var INIT_WORKFLOW_ANALYZE_SYSTEM_PROMPT = `
78953
79426
  Role: Analyzer agent
78954
79427
  Goal: Produce a valid polkacodes YAML configuration for the project.
78955
79428
 
79429
+ ${TOOL_USAGE_INSTRUCTION}
79430
+
78956
79431
  Workflow
78957
79432
  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
79433
  - Package/build tool (npm, bun, pnpm, etc.)
@@ -79364,10 +79839,10 @@ var ImplementOutputSchema = exports_external.object({
79364
79839
  });
79365
79840
  var codeWorkflow = async (input2, context) => {
79366
79841
  const { logger, step, tools: tools2 } = context;
79367
- const { task, files, mode = "interactive" } = input2;
79842
+ const { task, files, mode = "interactive", additionalTools, additionalInstructions } = input2;
79368
79843
  const summaries = [];
79369
79844
  logger.info(`
79370
- \uD83D\uDCCB Phase 1: Creating implementation plan...
79845
+ Phase 1: Creating implementation plan...
79371
79846
  `);
79372
79847
  const planResult = await step("plan", async () => {
79373
79848
  return await planWorkflow({ task, files, mode: mode === "interactive" ? "confirm" : "noninteractive" }, context);
@@ -79378,7 +79853,7 @@ var codeWorkflow = async (input2, context) => {
79378
79853
  }
79379
79854
  const { plan, files: planFiles } = planResult;
79380
79855
  logger.info(`
79381
- ⚙️ Phase 2: Implementing the plan...
79856
+ Phase 2: Implementing the plan...
79382
79857
  `);
79383
79858
  let implementPrompt = getImplementPrompt(plan);
79384
79859
  if (planFiles && planFiles.length > 0) {
@@ -79426,6 +79901,9 @@ ${fileContentString}`;
79426
79901
  if (mode === "interactive") {
79427
79902
  agentTools.push(askFollowupQuestion_default);
79428
79903
  }
79904
+ if (additionalTools) {
79905
+ agentTools.push(...additionalTools);
79906
+ }
79429
79907
  const res = await step("implement", async () => {
79430
79908
  const defaultContext = await getDefaultContext();
79431
79909
  const memoryContext = await tools2.getMemoryContext();
@@ -79442,8 +79920,11 @@ ${memoryContext}`;
79442
79920
  ${memoryContext}`
79443
79921
  });
79444
79922
  }
79923
+ const systemPrompt = additionalInstructions ? `${CODER_SYSTEM_PROMPT}
79924
+
79925
+ ${additionalInstructions}` : CODER_SYSTEM_PROMPT;
79445
79926
  return await agentWorkflow({
79446
- systemPrompt: CODER_SYSTEM_PROMPT,
79927
+ systemPrompt,
79447
79928
  userMessage: [{ role: "user", content: userContent }],
79448
79929
  tools: agentTools,
79449
79930
  outputSchema: ImplementOutputSchema
@@ -79453,13 +79934,13 @@ ${memoryContext}`
79453
79934
  const { summary, bailReason } = res.object;
79454
79935
  if (bailReason) {
79455
79936
  logger.error(`
79456
- Implementation failed: ${bailReason}
79937
+ Implementation failed: ${bailReason}
79457
79938
  `);
79458
79939
  return { success: false, reason: bailReason, summaries };
79459
79940
  }
79460
79941
  if (summary) {
79461
79942
  logger.info(`
79462
- Implementation complete!
79943
+ Implementation complete!
79463
79944
  `);
79464
79945
  summaries.push(summary);
79465
79946
  logger.info(`Summary: ${summary}`);
@@ -79472,20 +79953,20 @@ ${memoryContext}`
79472
79953
  });
79473
79954
  } else {
79474
79955
  logger.info(`
79475
- Implementation complete!
79956
+ Implementation complete!
79476
79957
  `);
79477
79958
  }
79478
79959
  } else if (res.type === "Exit" /* Exit */) {
79479
79960
  logger.info(`
79480
- Implementation complete!
79961
+ Implementation complete!
79481
79962
  `);
79482
79963
  } else {
79483
79964
  logger.warn(`
79484
- ⚠️ Implementation failed. Please check the output for errors.
79965
+ Warning: Implementation failed. Please check the output for errors.
79485
79966
  `, res);
79486
79967
  }
79487
79968
  logger.info(`
79488
- \uD83D\uDD27 Phase 3: Checking for errors...
79969
+ Phase 3: Checking for errors...
79489
79970
  `);
79490
79971
  const fixResult = await step("fix", async () => {
79491
79972
  return await fixWorkflow({ interactive: false, task: input2.task }, context);
@@ -79895,98 +80376,67 @@ ${provider3.toUpperCase()}_API_KEY=${providerConfig.apiKey}`;
79895
80376
  });
79896
80377
  return { configPath };
79897
80378
  };
79898
- // src/workflows/epic.workflow.ts
79899
- 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
- };
80379
+ // src/workflows/epic-context.ts
80380
+ import { promises as fs3 } from "node:fs";
80381
+ var EPIC_CONTEXT_FILE = ".epic.yml";
80382
+ var EpicContextSchema = exports_external.object({
80383
+ task: exports_external.string().nullish(),
80384
+ plan: exports_external.string().nullish(),
80385
+ branchName: exports_external.string().nullish(),
80386
+ todos: exports_external.array(TodoItemSchema).nullish(),
80387
+ memory: exports_external.record(exports_external.string(), exports_external.string()).nullish()
80388
+ });
80389
+ var saveEpicContext = async (context) => {
80390
+ const yamlString = $stringify(context);
80391
+ await fs3.writeFile(EPIC_CONTEXT_FILE, yamlString, "utf-8");
80392
+ };
80393
+ var loadEpicContext = async () => {
80394
+ let fileContent;
80395
+ try {
80396
+ fileContent = await fs3.readFile(EPIC_CONTEXT_FILE, "utf-8");
80397
+ } catch {
80398
+ return {};
79907
80399
  }
79908
- if (name18.length > 255) {
79909
- return { valid: false, error: "Branch name is too long (max 255 characters)." };
80400
+ try {
80401
+ const loaded = $parse(fileContent);
80402
+ return EpicContextSchema.parse(loaded);
80403
+ } catch (error46) {
80404
+ console.error("Error parsing epic context file:", EPIC_CONTEXT_FILE, error46);
80405
+ return {};
79910
80406
  }
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>
80407
+ };
79970
80408
 
79971
- After an initial implementation, a review found the following issues. Please fix them:
80409
+ class EpicMemoryStore {
80410
+ #context;
80411
+ constructor(context) {
80412
+ this.#context = context;
80413
+ }
80414
+ async read() {
80415
+ return this.#context.memory ?? {};
80416
+ }
80417
+ async write(data) {
80418
+ this.#context.memory = data;
80419
+ await saveEpicContext(this.#context);
80420
+ }
80421
+ }
79972
80422
 
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
- }
80423
+ class EpicTodoItemStore {
80424
+ #context;
80425
+ constructor(context) {
80426
+ this.#context = context;
80427
+ }
80428
+ async read() {
80429
+ return this.#context.todos ?? [];
80430
+ }
80431
+ async write(data) {
80432
+ this.#context.todos = data;
80433
+ await saveEpicContext(this.#context);
79987
80434
  }
79988
- return { passed: false };
79989
80435
  }
80436
+
80437
+ // src/workflows/epic.workflow.ts
80438
+ var MAX_REVIEW_RETRIES = 5;
80439
+ var TODO_HANDLING_INSTRUCTIONS = `If you discover that a task is larger than you thought, or that a new task is required, you can add a // TODO comment in the code and create a todo item for it. This will allow you to continue with the current task and address the larger issue later.`;
79990
80440
  async function createPlan2(input2, context) {
79991
80441
  const { task, plan, files, feedback } = input2;
79992
80442
  const content = [{ type: "text", text: getPlanPrompt(task, plan) }];
@@ -80036,316 +80486,517 @@ ${feedback}`
80036
80486
  }
80037
80487
  return { plan: "", reason: "Usage limit exceeded.", type: "Exit" /* Exit */, branchName: "" };
80038
80488
  }
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");
80489
+ async function createAndApprovePlan(task, context) {
80490
+ const { logger, step, tools: tools2 } = context;
80491
+ logger.info(`Phase 2: Creating high-level plan...
80492
+ `);
80493
+ let feedback;
80494
+ let highLevelPlan;
80495
+ let branchName;
80496
+ let planAttempt = 1;
80497
+ try {
80498
+ while (true) {
80499
+ const result = await step(`plan-${planAttempt}`, () => createPlan2({ task, feedback }, context));
80500
+ planAttempt++;
80501
+ if (result.question) {
80502
+ const answer = await tools2.input({
80503
+ message: result.question.question,
80504
+ default: result.question.defaultAnswer || undefined
80505
+ });
80506
+ feedback = `The user answered the question "${result.question.question}" with: "${answer}"`;
80507
+ continue;
80508
+ }
80509
+ if (!result.plan) {
80510
+ if (result.reason) {
80511
+ logger.info(`No plan created. Reason: ${result.reason}`);
80512
+ } else {
80513
+ logger.info("No plan created.");
80514
+ }
80515
+ return null;
80516
+ }
80517
+ logger.info(`Plan:
80518
+ ${result.plan}`);
80519
+ if (result.branchName) {
80520
+ logger.info(`Suggested branch name: ${result.branchName}`);
80521
+ }
80522
+ feedback = await tools2.input({ message: "Press Enter to approve the plan, or provide feedback to refine it." });
80523
+ if (feedback.trim() === "") {
80524
+ highLevelPlan = result.plan;
80525
+ branchName = result.branchName;
80526
+ break;
80527
+ }
80528
+ }
80529
+ } catch (e) {
80530
+ if (e instanceof UserCancelledError) {
80531
+ logger.info("Plan creation cancelled by user.");
80532
+ return null;
80533
+ }
80534
+ throw e;
80063
80535
  }
80064
- const updateResult = result.object;
80065
- return {
80066
- updatedPlan: updateResult.updatedPlan,
80067
- isComplete: updateResult.isComplete,
80068
- nextTask: updateResult.nextTask || null
80069
- };
80536
+ if (!highLevelPlan) {
80537
+ logger.info("Plan not approved. Exiting.");
80538
+ return null;
80539
+ }
80540
+ if (!branchName) {
80541
+ logger.error("Error: No branch name was generated from the plan. Exiting.");
80542
+ return null;
80543
+ }
80544
+ logger.info(`High-level plan approved.
80545
+ `);
80546
+ return { plan: highLevelPlan, branchName };
80547
+ }
80548
+ async function createFeatureBranch(branchName, context) {
80549
+ const { logger, step, tools: tools2 } = context;
80550
+ logger.info(`Phase 3: Creating/switching to feature branch...
80551
+ `);
80552
+ const branchExistsResult = await step("checkBranchExists", async () => await tools2.executeCommand({ command: "git", args: ["rev-parse", "--verify", branchName] }));
80553
+ if (branchExistsResult.exitCode === 0) {
80554
+ const currentBranchResult = await step("getCurrentBranch", async () => tools2.executeCommand({ command: "git", args: ["rev-parse", "--abbrev-ref", "HEAD"] }));
80555
+ const currentBranch = currentBranchResult.stdout.trim();
80556
+ if (currentBranch !== branchName) {
80557
+ logger.info(`Branch '${branchName}' already exists. Switching to it...`);
80558
+ const checkoutResult = await step("checkoutBranch", async () => await tools2.executeCommand({ command: "git", args: ["checkout", branchName] }));
80559
+ if (checkoutResult.exitCode !== 0) {
80560
+ logger.error(`Error: Failed to switch to branch '${branchName}'. Git command failed.`);
80561
+ return { success: false, branchName: null };
80562
+ }
80563
+ } else {
80564
+ logger.info(`Already on branch '${branchName}'.`);
80565
+ }
80566
+ } else {
80567
+ logger.info(`Creating new branch '${branchName}'...`);
80568
+ const createBranchResult = await step("createBranch", async () => await tools2.executeCommand({ command: "git", args: ["checkout", "-b", branchName] }));
80569
+ if (createBranchResult.exitCode !== 0) {
80570
+ logger.error(`Error: Failed to create branch '${branchName}'. Git command failed.`);
80571
+ return { success: false, branchName: null };
80572
+ }
80573
+ }
80574
+ logger.info(`Successfully on branch '${branchName}'.
80575
+ `);
80576
+ return { success: true, branchName };
80070
80577
  }
80071
- async function runPreflightChecks(context) {
80578
+ async function addTodoItemsFromPlan(plan, context) {
80072
80579
  const { logger, step, tools: tools2 } = context;
80073
- logger.info(`\uD83D\uDCCB Phase 1: Running pre-flight checks...
80580
+ logger.info(`Phase 4: Creating todo items from plan...
80581
+ `);
80582
+ await step("add-todo-items", async () => {
80583
+ await agentWorkflow({
80584
+ systemPrompt: EPIC_ADD_TODO_ITEMS_SYSTEM_PROMPT,
80585
+ userMessage: [{ role: "user", content: `Please create the todo items based on the plan
80586
+ <plan>
80587
+ ${plan}</plan>` }],
80588
+ tools: [readFile_default, searchFiles_default, listFiles_default, readMemory_default, getTodoItem_default, listTodoItems_default, updateTodoItem_default, updateMemory_default, listMemoryTopics_default]
80589
+ }, context);
80590
+ });
80591
+ const todos = await tools2.listTodoItems({});
80592
+ logger.info(`Created ${todos.length} todo items.
80593
+ `);
80594
+ }
80595
+ async function runPreflightChecks(epicContext, context) {
80596
+ const { logger, step, tools: tools2 } = context;
80597
+ logger.info(`Phase 1: Running pre-flight checks...
80074
80598
  `);
80075
80599
  const gitCheckResult = await step("gitCheck", async () => tools2.executeCommand({ command: "git", args: ["rev-parse", "--git-dir"] }));
80076
80600
  if (gitCheckResult.exitCode !== 0) {
80077
- logger.error("Error: Git is not initialized in this directory. Please run `git init` first.");
80078
- logger.info("\uD83D\uDCA1 Suggestion: Run `git init` to initialize a git repository.\n");
80079
- return { success: false };
80601
+ logger.error("Error: Git is not initialized in this directory. Please run `git init` first.");
80602
+ logger.info("Suggestion: Run `git init` to initialize a git repository.\n");
80603
+ return false;
80604
+ }
80605
+ if (epicContext.plan) {
80606
+ logger.info("Found an existing `.epic.yml` file.");
80607
+ if (epicContext.branchName) {
80608
+ const currentBranchResult = await step("getCurrentBranch", async () => tools2.executeCommand({ command: "git", args: ["rev-parse", "--abbrev-ref", "HEAD"] }));
80609
+ const currentBranch = currentBranchResult.stdout.trim();
80610
+ if (currentBranch !== epicContext.branchName) {
80611
+ throw new Error(`You are on branch '${currentBranch}' but the epic was started on branch '${epicContext.branchName}'. Please switch to the correct branch to resume.`);
80612
+ }
80613
+ }
80614
+ logger.info("Resuming previous epic session.");
80615
+ return true;
80080
80616
  }
80081
80617
  const gitStatusResult = await step("gitStatus", async () => tools2.executeCommand({ command: "git status --porcelain", shell: true }));
80082
80618
  if (gitStatusResult.stdout.trim() !== "") {
80083
- logger.error("Error: Your working directory is not clean. Please stash or commit your changes before running the epic workflow.");
80084
- logger.info("\uD83D\uDCA1 Suggestion: Run `git add .` and `git commit` to clean your working directory, or `git stash` to temporarily save changes.\n");
80085
- return { success: false };
80619
+ logger.error("Error: Your working directory is not clean. Please stash or commit your changes before running the epic workflow.");
80620
+ logger.info("Suggestion: Run `git add .` and `git commit` to clean your working directory, or `git stash` to temporarily save changes.\n");
80621
+ return false;
80086
80622
  }
80087
- logger.info(`✅ Pre-flight checks passed.
80623
+ logger.info(`Pre-flight checks passed.
80088
80624
  `);
80089
- return { success: true };
80625
+ return true;
80090
80626
  }
80091
- var epicWorkflow = async (input2, context) => {
80627
+ async function performReviewAndFixCycle(iterationCount, taskItem, highLevelPlan, context) {
80092
80628
  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...
80629
+ for (let i = 0;i < MAX_REVIEW_RETRIES; i++) {
80630
+ const diffResult = await tools2.executeCommand({ command: "git", args: ["diff", "--name-status", "HEAD~1", "HEAD"] });
80631
+ const changedFiles = parseGitDiffNameStatus(diffResult.stdout);
80632
+ if (changedFiles.length === 0) {
80633
+ logger.info(`No files were changed. Skipping review.
80107
80634
  `);
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;
80635
+ return { passed: true };
80154
80636
  }
80155
- if (!branchName2) {
80156
- logger2.error("❌ Error: No branch name was generated from the plan. Exiting.");
80157
- return null;
80637
+ logger.info(`
80638
+ Review iteration ${i + 1}/${MAX_REVIEW_RETRIES}`);
80639
+ logger.info(` Changed files: ${changedFiles.length}`);
80640
+ const changeInfo = {
80641
+ commitRange: "HEAD~1...HEAD",
80642
+ changedFiles
80643
+ };
80644
+ const reviewAgentResult = await step(`review-${iterationCount}-${i}`, async () => {
80645
+ const defaultContext = await getDefaultContext();
80646
+ const memoryContext = await tools2.getMemoryContext();
80647
+ const userMessage = `${defaultContext}
80648
+ ${memoryContext}
80649
+
80650
+ ${formatReviewToolInput(changeInfo)}`;
80651
+ return await agentWorkflow({
80652
+ systemPrompt: CODE_REVIEW_SYSTEM_PROMPT,
80653
+ userMessage: [{ role: "user", content: userMessage }],
80654
+ tools: [readFile_default, readBinaryFile_default, searchFiles_default, listFiles_default, gitDiff_default, readMemory_default, updateMemory_default, listMemoryTopics_default],
80655
+ outputSchema: reviewOutputSchema
80656
+ }, context);
80657
+ });
80658
+ if (reviewAgentResult.type !== "Exit" /* Exit */) {
80659
+ logger.error(`Review agent failed with status: ${reviewAgentResult.type}.`);
80660
+ break;
80158
80661
  }
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...
80662
+ const reviewResult = reviewAgentResult.object;
80663
+ if (!reviewResult || !reviewResult.specificReviews || reviewResult.specificReviews.length === 0) {
80664
+ logger.info(`Review passed. No issues found.
80172
80665
  `);
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
- }
80666
+ return { passed: true };
80197
80667
  }
80198
- if (finalBranchName !== branchName2) {
80199
- logger2.info(`Branch name '${branchName2}' was taken. Using '${finalBranchName}' instead.`);
80668
+ logger.warn(`Warning: Review found ${reviewResult.specificReviews.length} issue(s). Attempting to fix...
80669
+ `);
80670
+ for (const [idx, review] of reviewResult.specificReviews.entries()) {
80671
+ logger.warn(` ${idx + 1}. ${review.file}:${review.lines}`);
80200
80672
  }
80201
- await step2("createBranch", async () => await tools3.executeCommand({ command: "git", args: ["checkout", "-b", finalBranchName] }));
80202
- logger2.info(`✅ Branch '${finalBranchName}' created.
80673
+ logger.warn("");
80674
+ const reviewSummary = reviewResult.specificReviews.map((r) => `File: ${r.file} (lines: ${r.lines})
80675
+ Review: ${r.review}`).join(`
80676
+
80203
80677
  `);
80204
- await tools3.updateMemory({
80205
- operation: "append",
80206
- topic: "epic-context",
80207
- content: `Epic: ${task2}
80208
- Branch: ${finalBranchName}
80209
- Started: ${new Date().toISOString()}`
80678
+ const fixTask = `You are working on an epic. The original task was: "${taskItem}".
80679
+
80680
+ Here is the full plan for context:
80681
+ <plan>
80682
+ ${highLevelPlan}
80683
+ </plan>
80684
+
80685
+ After an initial implementation, a review found the following issues. Please fix them:
80686
+
80687
+ ${reviewSummary}`;
80688
+ await step(`fix-${iterationCount}-${i}`, async () => {
80689
+ await codeWorkflow({
80690
+ task: fixTask,
80691
+ mode: "noninteractive",
80692
+ additionalInstructions: TODO_HANDLING_INSTRUCTIONS,
80693
+ additionalTools: [getTodoItem_default, listTodoItems_default, updateTodoItem_default]
80694
+ }, context);
80210
80695
  });
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;
80696
+ await step(`commit-fix-${iterationCount}-${i}`, async () => {
80697
+ await tools2.executeCommand({ command: "git", args: ["add", "."] });
80698
+ await tools2.executeCommand({ command: "git", args: ["commit", "--amend", "--no-edit"] });
80699
+ });
80700
+ if (i === MAX_REVIEW_RETRIES - 1) {
80701
+ logger.error(`
80702
+ Max retries (${MAX_REVIEW_RETRIES}) reached. Moving to the next task, but issues might remain.
80703
+ `);
80704
+ return { passed: false };
80705
+ }
80217
80706
  }
80218
- branchName = branchResult.branchName;
80219
- logger.info(`\uD83D\uDE80 Phase 4: Iterative Implementation Loop...
80707
+ return { passed: false };
80708
+ }
80709
+ async function runImplementationLoop(context, highLevelPlan) {
80710
+ const { logger, step, tools: tools2 } = context;
80711
+ const commitMessages = [];
80712
+ logger.info(`Phase 5: Iterative Implementation Loop...
80220
80713
  `);
80221
80714
  logger.info(`${"=".repeat(80)}
80222
80715
  `);
80223
- let currentPlan = highLevelPlan;
80224
80716
  let iterationCount = 0;
80225
80717
  let isComplete = false;
80226
80718
  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(`
80238
- ${"━".repeat(80)}`);
80239
- logger.info(`\uD83D\uDCCC Iteration ${iterationCount}`);
80240
- logger.info(`${"━".repeat(80)}`);
80241
- logger.info(`${nextTask}
80719
+ let nextTaskId = null;
80720
+ const initialTasks = await step("get-initial-tasks", async () => {
80721
+ return await tools2.listTodoItems({ status: "open" });
80722
+ });
80723
+ if (initialTasks.length > 0) {
80724
+ const firstTask = initialTasks[0];
80725
+ nextTask = firstTask.title;
80726
+ nextTaskId = firstTask.id;
80727
+ } else {
80728
+ isComplete = true;
80729
+ }
80730
+ while (!isComplete && nextTask && nextTaskId) {
80731
+ iterationCount++;
80732
+ const taskStartTime = Date.now();
80733
+ logger.info(`
80734
+ ${"-".repeat(80)}`);
80735
+ logger.info(`Iteration ${iterationCount}`);
80736
+ logger.info(`${"-".repeat(80)}`);
80737
+ logger.info(`${nextTask}
80242
80738
  `);
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:
80739
+ await step(`task-${iterationCount}`, async () => {
80740
+ const taskWithContext = `You are working on an epic. Here is the full plan:
80246
80741
 
80247
80742
  <plan>
80248
- ${currentPlan}
80743
+ ${highLevelPlan}
80249
80744
  </plan>
80250
80745
 
80251
80746
  Your current task is to implement this specific item:
80252
80747
  ${nextTask}
80253
80748
 
80254
80749
  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`;
80294
- }
80295
- logger.info(`
80296
- \uD83D\uDCCA Progress: ${progressMessage}`);
80297
- if (isComplete) {
80298
- logger.info(`✅ All tasks complete!
80299
- `);
80300
- break;
80750
+ return await codeWorkflow({
80751
+ task: taskWithContext,
80752
+ mode: "noninteractive",
80753
+ additionalInstructions: TODO_HANDLING_INSTRUCTIONS,
80754
+ additionalTools: [getTodoItem_default, listTodoItems_default, updateTodoItem_default]
80755
+ }, context);
80756
+ });
80757
+ const commitMessage = `feat: ${nextTask}`;
80758
+ await step(`commit-initial-${iterationCount}`, async () => {
80759
+ await tools2.executeCommand({ command: "git", args: ["add", "."] });
80760
+ await tools2.executeCommand({ command: "git", args: ["commit", "-m", commitMessage] });
80761
+ });
80762
+ commitMessages.push(commitMessage);
80763
+ const { passed: reviewPassed } = await performReviewAndFixCycle(iterationCount, nextTask, highLevelPlan, context);
80764
+ const taskElapsed = Date.now() - taskStartTime;
80765
+ const taskElapsedTime = formatElapsedTime(taskElapsed);
80766
+ if (reviewPassed) {
80767
+ logger.info(`Iteration ${iterationCount} completed successfully (${taskElapsedTime})`);
80768
+ } else {
80769
+ logger.warn(`Warning: Iteration ${iterationCount} completed with potential issues (${taskElapsedTime})`);
80770
+ }
80771
+ await step(`update-task-status-${iterationCount}`, async () => {
80772
+ if (!nextTaskId) {
80773
+ throw new Error("Invariant violation: nextTaskId is null inside the implementation loop.");
80301
80774
  }
80302
- if (nextTask) {
80303
- logger.info(`\uD83D\uDCCC Next task: ${nextTask}
80775
+ await tools2.updateTodoItem({ operation: "update", id: nextTaskId, status: "completed" });
80776
+ });
80777
+ const openTasks = await step(`get-next-task-${iterationCount}`, async () => {
80778
+ return await tools2.listTodoItems({ status: "open" });
80779
+ });
80780
+ if (openTasks.length > 0) {
80781
+ const nextTodo = openTasks[0];
80782
+ nextTask = nextTodo.title;
80783
+ nextTaskId = nextTodo.id;
80784
+ isComplete = false;
80785
+ } else {
80786
+ nextTask = null;
80787
+ nextTaskId = null;
80788
+ isComplete = true;
80789
+ }
80790
+ const allTodos = await tools2.listTodoItems({});
80791
+ const completedTodos = allTodos.filter((t) => t.status === "completed").length;
80792
+ const totalTodos = allTodos.length;
80793
+ let progressMessage = "";
80794
+ if (totalTodos > 0) {
80795
+ progressMessage = `${completedTodos}/${totalTodos} items completed`;
80796
+ } else {
80797
+ progressMessage = `Iteration ${iterationCount} completed`;
80798
+ }
80799
+ logger.info(`
80800
+ Progress: ${progressMessage}`);
80801
+ if (isComplete) {
80802
+ logger.info(`All tasks complete!
80304
80803
  `);
80305
- }
80306
- logger.info(`${"━".repeat(80)}
80804
+ break;
80805
+ }
80806
+ if (nextTask) {
80807
+ logger.info(`Next task: ${nextTask}
80307
80808
  `);
80308
80809
  }
80309
- } catch (error46) {
80310
- logger.error(`
80311
- ❌ Epic workflow failed: ${error46 instanceof Error ? error46.message : String(error46)}`);
80312
- logger.info(`
80313
- Branch '${branchName}' was created but work is incomplete.`);
80314
- logger.info(`To cleanup: git checkout <previous-branch> && git branch -D ${branchName}
80810
+ logger.info(`${"-".repeat(80)}
80315
80811
  `);
80316
- await tools2.updateMemory({ operation: "remove", topic: "epic-context" });
80317
- await tools2.updateMemory({ operation: "remove", topic: "epic-plan" });
80318
- throw error46;
80319
80812
  }
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)}`);
80813
+ return commitMessages;
80814
+ }
80815
+ async function performFinalReviewAndFix(context, highLevelPlan) {
80816
+ const { logger, step, tools: tools2 } = context;
80327
80817
  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}
80818
+ Phase 6: Final Review and Fixup...
80334
80819
  `);
80335
- logger.info("\uD83D\uDCDD Commits created:");
80336
- commitMessages.forEach((msg, idx) => {
80337
- logger.info(` ${idx + 1}. ${msg}`);
80820
+ const ghCheckResult = await tools2.executeCommand({ command: "gh", args: ["--version"] });
80821
+ if (ghCheckResult.exitCode !== 0) {
80822
+ logger.warn("Warning: GitHub CLI (gh) is not installed. Skipping final review step. Please install it from https://cli.github.com/ to enable final reviews.");
80823
+ return { passed: true };
80824
+ }
80825
+ const defaultBranchResult = await tools2.executeCommand({
80826
+ command: "gh",
80827
+ args: ["repo", "view", "--json", "defaultBranchRef", "--jq", ".defaultBranchRef.name"]
80338
80828
  });
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
80829
+ const defaultBranch = defaultBranchResult.stdout.trim();
80830
+ const currentBranchResult = await tools2.executeCommand({ command: "git", args: ["rev-parse", "--abbrev-ref", "HEAD"] });
80831
+ const currentBranch = currentBranchResult.stdout.trim();
80832
+ if (currentBranch === defaultBranch) {
80833
+ logger.info(`You are on the default branch ('${defaultBranch}'). No final review needed.`);
80834
+ return { passed: true };
80835
+ }
80836
+ const commitRange = `${defaultBranch}...${currentBranch}`;
80837
+ for (let i = 0;i < MAX_REVIEW_RETRIES; i++) {
80838
+ const diffResult = await tools2.executeCommand({ command: "git", args: ["diff", "--name-status", commitRange] });
80839
+ const changedFiles = parseGitDiffNameStatus(diffResult.stdout);
80840
+ if (changedFiles.length === 0) {
80841
+ logger.info(`No files have been changed in this branch. Skipping final review.
80344
80842
  `);
80345
- logger.info(`${"=".repeat(80)}
80843
+ return { passed: true };
80844
+ }
80845
+ logger.info(`
80846
+ Final review iteration ${i + 1}/${MAX_REVIEW_RETRIES}`);
80847
+ logger.info(` Changed files: ${changedFiles.length}`);
80848
+ const changeInfo = {
80849
+ commitRange,
80850
+ changedFiles
80851
+ };
80852
+ const reviewAgentResult = await step(`final-review-${i}`, async () => {
80853
+ const defaultContext = await getDefaultContext();
80854
+ const memoryContext = await tools2.getMemoryContext();
80855
+ const userMessage = `${defaultContext}
80856
+ ${memoryContext}
80857
+
80858
+ ${formatReviewToolInput(changeInfo)}`;
80859
+ return await agentWorkflow({
80860
+ systemPrompt: CODE_REVIEW_SYSTEM_PROMPT,
80861
+ userMessage: [{ role: "user", content: userMessage }],
80862
+ tools: [readFile_default, readBinaryFile_default, searchFiles_default, listFiles_default, gitDiff_default, readMemory_default, updateMemory_default, listMemoryTopics_default],
80863
+ outputSchema: reviewOutputSchema
80864
+ }, context);
80865
+ });
80866
+ if (reviewAgentResult.type !== "Exit" /* Exit */) {
80867
+ logger.error(`Review agent failed with status: ${reviewAgentResult.type}.`);
80868
+ break;
80869
+ }
80870
+ const reviewResult = reviewAgentResult.object;
80871
+ if (!reviewResult || !reviewResult.specificReviews || reviewResult.specificReviews.length === 0) {
80872
+ logger.info(`Final review passed. No issues found.
80873
+ `);
80874
+ return { passed: true };
80875
+ }
80876
+ logger.warn(`Warning: Final review found ${reviewResult.specificReviews.length} issue(s). Attempting to fix...
80877
+ `);
80878
+ for (const [idx, review] of reviewResult.specificReviews.entries()) {
80879
+ logger.warn(` ${idx + 1}. ${review.file}:${review.lines}`);
80880
+ }
80881
+ logger.warn("");
80882
+ const reviewSummary = reviewResult.specificReviews.map((r) => `File: ${r.file} (lines: ${r.lines})
80883
+ Review: ${r.review}`).join(`
80884
+
80346
80885
  `);
80347
- await tools2.updateMemory({ operation: "remove", topic: "epic-context" });
80348
- await tools2.updateMemory({ operation: "remove", topic: "epic-plan" });
80886
+ const fixTask = `You are working on an epic. The original task was to implement a feature based on this plan:
80887
+
80888
+ <plan>
80889
+ ${highLevelPlan}
80890
+ </plan>
80891
+
80892
+ A final review of all the changes in the branch found the following issues. Please fix them:
80893
+
80894
+ ${reviewSummary}`;
80895
+ await step(`final-fix-${i}`, async () => {
80896
+ await codeWorkflow({
80897
+ task: fixTask,
80898
+ mode: "noninteractive",
80899
+ additionalInstructions: TODO_HANDLING_INSTRUCTIONS,
80900
+ additionalTools: [getTodoItem_default, listTodoItems_default, updateTodoItem_default]
80901
+ }, context);
80902
+ });
80903
+ await step(`commit-final-fix-${i}`, async () => {
80904
+ await tools2.executeCommand({ command: "git", args: ["add", "."] });
80905
+ await tools2.executeCommand({ command: "git", args: ["commit", "-m", "chore: apply automated review feedback"] });
80906
+ });
80907
+ if (i === MAX_REVIEW_RETRIES - 1) {
80908
+ logger.error(`
80909
+ Max retries (${MAX_REVIEW_RETRIES}) reached for final review. Issues might remain.
80910
+ `);
80911
+ return { passed: false };
80912
+ }
80913
+ }
80914
+ return { passed: false };
80915
+ }
80916
+ var epicWorkflow = async (input2, context) => {
80917
+ const { logger, tools: tools2 } = context;
80918
+ const { task, epicContext = {} } = input2;
80919
+ const workflowStartTime = Date.now();
80920
+ if (!task || task.trim() === "") {
80921
+ logger.error("Error: Task cannot be empty. Please provide a valid task description.");
80922
+ return;
80923
+ }
80924
+ if (!epicContext.task) {
80925
+ epicContext.task = task;
80926
+ }
80927
+ try {
80928
+ const preflightResult = await runPreflightChecks(epicContext, context);
80929
+ if (!preflightResult) {
80930
+ return;
80931
+ }
80932
+ if (!epicContext.plan) {
80933
+ if (!epicContext.task) {
80934
+ logger.error("Error: Task is missing in epic context. Exiting.");
80935
+ return;
80936
+ }
80937
+ const planResult = await createAndApprovePlan(epicContext.task, context);
80938
+ if (!planResult)
80939
+ return;
80940
+ epicContext.plan = planResult.plan;
80941
+ epicContext.branchName = planResult.branchName;
80942
+ await saveEpicContext(epicContext);
80943
+ }
80944
+ if (!epicContext.plan) {
80945
+ logger.error("Error: Plan is missing after planning phase. Exiting.");
80946
+ return;
80947
+ }
80948
+ if (!epicContext.branchName) {
80949
+ logger.error("Error: Branch name is missing after planning phase. Exiting.");
80950
+ return;
80951
+ }
80952
+ const branchResult = await createFeatureBranch(epicContext.branchName, context);
80953
+ if (!branchResult.success || !branchResult.branchName)
80954
+ return;
80955
+ if (epicContext.branchName !== branchResult.branchName) {
80956
+ epicContext.branchName = branchResult.branchName;
80957
+ await saveEpicContext(epicContext);
80958
+ }
80959
+ const todos = await tools2.listTodoItems({});
80960
+ if (todos.length === 0) {
80961
+ await addTodoItemsFromPlan(epicContext.plan, context);
80962
+ }
80963
+ const commitMessages = await runImplementationLoop(context, epicContext.plan);
80964
+ await performFinalReviewAndFix(context, epicContext.plan);
80965
+ await tools2.executeCommand({ command: "git", args: ["rm", "-f", ".epic.yml"] });
80966
+ const statusResult = await tools2.executeCommand({
80967
+ command: "git",
80968
+ args: ["status", "--porcelain", "--", ".epic.yml"]
80969
+ });
80970
+ if (statusResult.stdout.trim() !== "") {
80971
+ await tools2.executeCommand({ command: "git", args: ["commit", "-m", "chore: remove .epic.yml", "--", ".epic.yml"] });
80972
+ logger.info("Cleaned up .epic.yml file.");
80973
+ }
80974
+ const totalElapsed = Date.now() - workflowStartTime;
80975
+ const totalElapsedTime = formatElapsedTime(totalElapsed);
80976
+ logger.info(`
80977
+ ${"=".repeat(80)}`);
80978
+ logger.info("Epic Workflow Complete!");
80979
+ logger.info(`${"=".repeat(80)}`);
80980
+ logger.info(`
80981
+ Summary:`);
80982
+ logger.info(` Branch: ${epicContext.branchName}`);
80983
+ logger.info(` Total time: ${totalElapsedTime}`);
80984
+ logger.info(` Total commits: ${commitMessages.length}`);
80985
+ logger.info("Commits created:");
80986
+ for (const [idx, msg] of commitMessages.entries()) {
80987
+ logger.info(` ${idx + 1}. ${msg}`);
80988
+ }
80989
+ } catch (error46) {
80990
+ logger.error(`
80991
+ Epic workflow failed: ${error46 instanceof Error ? error46.message : String(error46)}`);
80992
+ if (epicContext?.branchName) {
80993
+ logger.info(`
80994
+ Branch '${epicContext.branchName}' was created but work is incomplete.`);
80995
+ logger.info(`To cleanup: git checkout <previous-branch> && git branch -D ${epicContext.branchName}
80996
+ `);
80997
+ }
80998
+ throw error46;
80999
+ }
80349
81000
  };
80350
81001
 
80351
81002
  // src/workflows/task.workflow.ts
@@ -80356,7 +81007,7 @@ var taskWorkflow = async (input2, context) => {
80356
81007
  const { logger, step } = context;
80357
81008
  const { task } = input2;
80358
81009
  logger.info(`
80359
- \uD83E\uDD16 Running generic agent...
81010
+ Running generic agent...
80360
81011
  `);
80361
81012
  await step("agent", async () => {
80362
81013
  const defaultContext = await getDefaultContext();
@@ -80381,7 +81032,7 @@ ${defaultContext}`;
80381
81032
  }, context);
80382
81033
  });
80383
81034
  logger.info(`
80384
- Agent finished!
81035
+ Agent finished!
80385
81036
  `);
80386
81037
  return { success: true };
80387
81038
  };
@@ -80394,7 +81045,7 @@ var metaWorkflow = async (input2, context) => {
80394
81045
  const { task } = input2;
80395
81046
  const { logger } = context;
80396
81047
  logger.info(`
80397
- \uD83E\uDD14 Deciding which workflow to use for task...
81048
+ Deciding which workflow to use for task...
80398
81049
  `);
80399
81050
  const result = await agentWorkflow({
80400
81051
  systemPrompt: META_SYSTEM_PROMPT,
@@ -80415,7 +81066,7 @@ var metaWorkflow = async (input2, context) => {
80415
81066
  throw new Error("Could not decide which workflow to run.");
80416
81067
  }
80417
81068
  logger.info(`
80418
- Decision: Using '${decision.workflow}' workflow.`);
81069
+ Decision: Using '${decision.workflow}' workflow.`);
80419
81070
  switch (decision.workflow) {
80420
81071
  case "code":
80421
81072
  await codeWorkflow({ task }, context);
@@ -80635,30 +81286,32 @@ var commitCommand = new Command("commit").description("Create a commit with AI-g
80635
81286
  async function runEpic(task2, _options, command) {
80636
81287
  let taskInput = task2;
80637
81288
  if (!taskInput) {
80638
- try {
80639
- taskInput = await esm_default3({
80640
- message: "What epic or large feature do you want to implement?"
80641
- });
80642
- } catch (error46) {
80643
- if (error46 instanceof Error && error46.name === "ExitPromptError") {
80644
- return;
80645
- }
80646
- throw error46;
81289
+ taskInput = await getUserInput("What epic or large feature do you want to implement?");
81290
+ if (!taskInput) {
81291
+ return;
80647
81292
  }
80648
81293
  }
80649
81294
  if (!taskInput) {
80650
81295
  console.error("No task provided. Aborting.");
80651
81296
  return;
80652
81297
  }
81298
+ const ctx = await loadEpicContext();
80653
81299
  const workflowInput = {
80654
- task: taskInput
81300
+ task: taskInput,
81301
+ epicContext: ctx
80655
81302
  };
80656
81303
  const globalOpts = (command.parent ?? command).opts();
80657
81304
  const { verbose, yes } = globalOpts;
80658
81305
  const logger = createLogger({
80659
81306
  verbose
80660
81307
  });
80661
- await runWorkflow(epicWorkflow, workflowInput, { commandName: "epic", command, logger, yes });
81308
+ await runWorkflow(epicWorkflow, workflowInput, {
81309
+ commandName: "epic",
81310
+ command,
81311
+ logger,
81312
+ yes,
81313
+ getProvider: (opt) => getProvider({ ...opt, todoItemStore: new EpicTodoItemStore(ctx), memoryStore: new EpicMemoryStore(ctx) })
81314
+ });
80662
81315
  }
80663
81316
  var epicCommand = new Command("epic").description("Orchestrates a large feature or epic, breaking it down into smaller tasks.").argument("[task]", "The epic to plan and implement.").action(runEpic);
80664
81317