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