lalph 0.3.61 → 0.3.62
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/cli.mjs +85 -25
- package/package.json +4 -4
- package/src/Agents/researcher.ts +31 -0
- package/src/Agents/worker.ts +19 -2
- package/src/Clanka.ts +5 -3
- package/src/Projects.ts +6 -0
- package/src/PromptGen.ts +19 -0
- package/src/commands/projects/ls.ts +3 -0
- package/src/commands/root.ts +16 -6
- package/src/domain/Project.ts +1 -0
package/dist/cli.mjs
CHANGED
|
@@ -87793,6 +87793,7 @@ var Project$2 = class extends Class$1("lalph/Project")({
|
|
|
87793
87793
|
targetBranch: Option(String$1),
|
|
87794
87794
|
concurrency: Int.check(isGreaterThanOrEqualTo(1)),
|
|
87795
87795
|
gitFlow: Literals(["pr", "commit"]),
|
|
87796
|
+
researchAgent: Boolean$2.pipe(withDecodingDefault(() => false)),
|
|
87796
87797
|
reviewAgent: Boolean$2
|
|
87797
87798
|
}) {};
|
|
87798
87799
|
//#endregion
|
|
@@ -177948,7 +177949,7 @@ var ji = Bt, Ii = Object.assign(Qe, { sync: Bt }), zi = Ut, Bi = Object.assign(e
|
|
|
177948
177949
|
});
|
|
177949
177950
|
Ze.glob = Ze;
|
|
177950
177951
|
//#endregion
|
|
177951
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
177952
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/ApplyPatch.js
|
|
177952
177953
|
/**
|
|
177953
177954
|
* @since 1.0.0
|
|
177954
177955
|
*/
|
|
@@ -192821,7 +192822,7 @@ var StreamableHTTPClientTransport = class {
|
|
|
192821
192822
|
}
|
|
192822
192823
|
};
|
|
192823
192824
|
//#endregion
|
|
192824
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
192825
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/McpClient.js
|
|
192825
192826
|
/**
|
|
192826
192827
|
* @since 1.0.0
|
|
192827
192828
|
*/
|
|
@@ -192866,7 +192867,7 @@ const layer$7 = effect$1(McpClient, gen(function* () {
|
|
|
192866
192867
|
});
|
|
192867
192868
|
}));
|
|
192868
192869
|
//#endregion
|
|
192869
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
192870
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/ExaSearch.js
|
|
192870
192871
|
/**
|
|
192871
192872
|
* @since 1.0.0
|
|
192872
192873
|
*/
|
|
@@ -207816,7 +207817,7 @@ var require_lib = /* @__PURE__ */ __commonJSMin$1(((exports) => {
|
|
|
207816
207817
|
exports.impl = impl;
|
|
207817
207818
|
}));
|
|
207818
207819
|
//#endregion
|
|
207819
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
207820
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/WebToMarkdown.js
|
|
207820
207821
|
/**
|
|
207821
207822
|
* @since 1.0.0
|
|
207822
207823
|
*/
|
|
@@ -210898,7 +210899,7 @@ const unsafeSecureJsonParse = (text) => {
|
|
|
210898
210899
|
}
|
|
210899
210900
|
};
|
|
210900
210901
|
//#endregion
|
|
210901
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
210902
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/AgentTools.js
|
|
210902
210903
|
/**
|
|
210903
210904
|
* @since 1.0.0
|
|
210904
210905
|
*/
|
|
@@ -211248,7 +211249,7 @@ const AgentToolHandlers = AgentToolHandlersNoDeps.pipe(provide$3([layer$6, layer
|
|
|
211248
211249
|
AgentToolHandlersNoDeps.pipe(provide$3([mock(ExaSearch)({}), mock(WebToMarkdown)({})]));
|
|
211249
211250
|
var ApplyPatchError = class extends TaggedClass$1("ApplyPatchError") {};
|
|
211250
211251
|
//#endregion
|
|
211251
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
211252
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/TypeBuilder.js
|
|
211252
211253
|
const resolveDocumentation = resolveAt("documentation");
|
|
211253
211254
|
const identifierPattern = /^[$A-Z_a-z][$0-9A-Z_a-z]*$/u;
|
|
211254
211255
|
const Precedence = {
|
|
@@ -211521,7 +211522,7 @@ const render = (schema, options) => {
|
|
|
211521
211522
|
return printNode({ text: documentation === void 0 ? rendered.text : `${renderJsDoc(documentation, 0, printerOptions)}${printerOptions.newLine}${rendered.text}` }, printerOptions);
|
|
211522
211523
|
};
|
|
211523
211524
|
//#endregion
|
|
211524
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
211525
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/ToolkitRenderer.js
|
|
211525
211526
|
/**
|
|
211526
211527
|
* @since 1.0.0
|
|
211527
211528
|
*/
|
|
@@ -211543,7 +211544,7 @@ declare function ${name}(${params}): Promise<${render(tool.successSchema)}>`);
|
|
|
211543
211544
|
}) });
|
|
211544
211545
|
};
|
|
211545
211546
|
//#endregion
|
|
211546
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
211547
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/AgentExecutor.js
|
|
211547
211548
|
/**
|
|
211548
211549
|
* @since 1.0.0
|
|
211549
211550
|
*/
|
|
@@ -211697,7 +211698,7 @@ var QueueWriteStream = class extends Writable {
|
|
|
211697
211698
|
}
|
|
211698
211699
|
};
|
|
211699
211700
|
//#endregion
|
|
211700
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
211701
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/ScriptExtraction.js
|
|
211701
211702
|
const stripWrappingCodeFence = (script) => {
|
|
211702
211703
|
const lines = script.split(/\r?\n/);
|
|
211703
211704
|
if (lines.length < 2) return script;
|
|
@@ -213080,7 +213081,7 @@ const applySpanTransformer = (transformer, response, options) => {
|
|
|
213080
213081
|
});
|
|
213081
213082
|
};
|
|
213082
213083
|
//#endregion
|
|
213083
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
213084
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/Agent.js
|
|
213084
213085
|
/**
|
|
213085
213086
|
* @since 1.0.0
|
|
213086
213087
|
*/
|
|
@@ -213230,7 +213231,7 @@ ${content}
|
|
|
213230
213231
|
const result = yield* executeScript(currentScript);
|
|
213231
213232
|
update(prompt, concat([{
|
|
213232
213233
|
role: modelConfig.supportsAssistantPrefill ? "assistant" : "user",
|
|
213233
|
-
content: `
|
|
213234
|
+
content: `Console output from executing javascript code:\n\n${result}`
|
|
213234
213235
|
}]));
|
|
213235
213236
|
currentScript = "";
|
|
213236
213237
|
}
|
|
@@ -213409,7 +213410,8 @@ ${options.agentsMd}
|
|
|
213409
213410
|
const generateSystemTools = (toolsDts, multi) => {
|
|
213410
213411
|
return `${multi ? generateSystemMulti(toolsDts) : generateSystemSingle(toolsDts)}
|
|
213411
213412
|
|
|
213412
|
-
|
|
213413
|
+
For example, here is how you would read a file. First you would respond with
|
|
213414
|
+
javascript code that uses the "readFile" function:
|
|
213413
213415
|
|
|
213414
213416
|
\`\`\`
|
|
213415
213417
|
const content = await readFile({
|
|
@@ -213420,10 +213422,10 @@ const content = await readFile({
|
|
|
213420
213422
|
console.log(JSON.parse(content))
|
|
213421
213423
|
\`\`\`
|
|
213422
213424
|
|
|
213423
|
-
And
|
|
213425
|
+
And then you will revieve back the console output:
|
|
213424
213426
|
|
|
213425
213427
|
\`\`\`
|
|
213426
|
-
|
|
213428
|
+
Console output from executing javascript code:
|
|
213427
213429
|
|
|
213428
213430
|
[22:44:53.054] INFO (#47): Calling "readFile" { path: 'package.json' }
|
|
213429
213431
|
{
|
|
@@ -213446,10 +213448,12 @@ const systemToolsCommon = (toolsDts) => `- Use \`console.log\` to print any outp
|
|
|
213446
213448
|
- Top level await is supported.
|
|
213447
213449
|
- AVOID passing scripts into the "bash" function, and instead write javascript.
|
|
213448
213450
|
- PREFER the "search" function over "rg" for finding information or code
|
|
213451
|
+
- Do as much work as possible in a single script, using \`Promise.all\` to run multiple functions in parallel.
|
|
213449
213452
|
- Variables **are not shared** between executions, so you must include all necessary code in each script you execute.
|
|
213450
213453
|
- Make use of the "delegate" tool to delegate exploration and small research tasks. You can delegate multiple tasks in parallel with Promise.all
|
|
213451
213454
|
|
|
213452
213455
|
**When you have fully completed your task**, call the "taskComplete" function with the final output.
|
|
213456
|
+
DO NOT output the final result without wrapping it with "taskComplete".
|
|
213453
213457
|
Make sure every detail of the task is done before calling "taskComplete".
|
|
213454
213458
|
|
|
213455
213459
|
You have the following functions available to you:
|
|
@@ -224220,7 +224224,7 @@ const transformToolCallParams = /* @__PURE__ */ fnUntraced(function* (tools, too
|
|
|
224220
224224
|
})));
|
|
224221
224225
|
});
|
|
224222
224226
|
//#endregion
|
|
224223
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
224227
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/CodexAuth.js
|
|
224224
224228
|
/**
|
|
224225
224229
|
* @since 1.0.0
|
|
224226
224230
|
*/
|
|
@@ -224440,7 +224444,7 @@ var CodexAuth = class CodexAuth extends Service$1()("clanka/CodexAuth") {
|
|
|
224440
224444
|
static layerClient = this.layerClientNoDeps.pipe(provide$3(CodexAuth.layer));
|
|
224441
224445
|
};
|
|
224442
224446
|
//#endregion
|
|
224443
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
224447
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/Codex.js
|
|
224444
224448
|
/**
|
|
224445
224449
|
* @since 1.0.0
|
|
224446
224450
|
*/
|
|
@@ -225759,7 +225763,7 @@ const getUsageDetailNumber = (details, field) => {
|
|
|
225759
225763
|
return typeof value === "number" ? value : void 0;
|
|
225760
225764
|
};
|
|
225761
225765
|
//#endregion
|
|
225762
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
225766
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/CopilotAuth.js
|
|
225763
225767
|
/**
|
|
225764
225768
|
* @since 1.0.0
|
|
225765
225769
|
*/
|
|
@@ -225950,7 +225954,7 @@ var GithubCopilotAuth = class GithubCopilotAuth extends Service$1()("clanka/Gith
|
|
|
225950
225954
|
static layerClient = this.layerClientNoDeps.pipe(provide$3(GithubCopilotAuth.layer));
|
|
225951
225955
|
};
|
|
225952
225956
|
//#endregion
|
|
225953
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
225957
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/Copilot.js
|
|
225954
225958
|
/**
|
|
225955
225959
|
* @since 1.0.0
|
|
225956
225960
|
*/
|
|
@@ -226373,7 +226377,7 @@ Object.defineProperties(createChalk.prototype, styles);
|
|
|
226373
226377
|
const chalk = createChalk();
|
|
226374
226378
|
createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
226375
226379
|
//#endregion
|
|
226376
|
-
//#region node_modules/.pnpm/clanka@0.1.
|
|
226380
|
+
//#region node_modules/.pnpm/clanka@0.1.10_@effect+ai-openai-compat@4.0.0-beta.31_effect@4.0.0-beta.31__@effect+ai-o_9214219cb2db90147f00f2a3436d6c48/node_modules/clanka/dist/OutputFormatter.js
|
|
226377
226381
|
/**
|
|
226378
226382
|
* @since 1.0.0
|
|
226379
226383
|
*/
|
|
@@ -234123,6 +234127,21 @@ All steps must be done before the task can be considered complete.${options.task
|
|
|
234123
234127
|
5. **After ${options.gitFlow.requiresGithubPr ? "pushing" : "committing"}** your changes, update current task to reflect any changes in the task state.
|
|
234124
234128
|
- Rewrite the notes in the description to include only the key discoveries and information that could speed up future work on other tasks. Make sure to preserve important information such as specification file references.
|
|
234125
234129
|
- If you believe the task is complete, update the \`state\` to "in-review".`;
|
|
234130
|
+
const promptResearch = (options) => `Your job is to gather all the necessary information and details to complete the task described below. Do not make any code changes yet, your job is just to research and gather information.
|
|
234131
|
+
|
|
234132
|
+
In the final report:
|
|
234133
|
+
|
|
234134
|
+
- Include key file names, line numbers, and code snippets that are relevant to the task.
|
|
234135
|
+
- Any key discoveries that will help with implementing the task.
|
|
234136
|
+
- Any other information that will help speed up the implementation of the task.
|
|
234137
|
+
- You DO NOT need to add your report to the task description, just include it in your final output.
|
|
234138
|
+
|
|
234139
|
+
# Task details
|
|
234140
|
+
|
|
234141
|
+
ID: ${options.task.id}
|
|
234142
|
+
Title: ${options.task.title}
|
|
234143
|
+
|
|
234144
|
+
${options.task.description}`;
|
|
234126
234145
|
const promptReview = (options) => `A previous engineer has completed a task from the instructions below.
|
|
234127
234146
|
|
|
234128
234147
|
You job is to meticulously review their work to ensure it meets the task requirements,
|
|
@@ -234268,6 +234287,7 @@ Make sure to setup dependencies between the tasks using the \`blockedBy\` field.
|
|
|
234268
234287
|
promptChooseClanka,
|
|
234269
234288
|
prompt,
|
|
234270
234289
|
promptClanka,
|
|
234290
|
+
promptResearch,
|
|
234271
234291
|
promptReview,
|
|
234272
234292
|
promptReviewCustom,
|
|
234273
234293
|
promptTimeout,
|
|
@@ -234437,6 +234457,10 @@ const addOrUpdateProject = fnUntraced(function* (existing) {
|
|
|
234437
234457
|
selected: existing ? existing.gitFlow === "commit" : false
|
|
234438
234458
|
}]
|
|
234439
234459
|
});
|
|
234460
|
+
const researchAgent = yield* toggle({
|
|
234461
|
+
message: "Enable research agent?",
|
|
234462
|
+
initial: existing ? existing.researchAgent : true
|
|
234463
|
+
});
|
|
234440
234464
|
const reviewAgent = yield* toggle({
|
|
234441
234465
|
message: "Enable review agent?",
|
|
234442
234466
|
initial: existing ? existing.reviewAgent : true
|
|
@@ -234447,6 +234471,7 @@ const addOrUpdateProject = fnUntraced(function* (existing) {
|
|
|
234447
234471
|
concurrency,
|
|
234448
234472
|
targetBranch,
|
|
234449
234473
|
gitFlow,
|
|
234474
|
+
researchAgent,
|
|
234450
234475
|
reviewAgent
|
|
234451
234476
|
});
|
|
234452
234477
|
yield* Settings.set(allProjects, some$2(existing ? projects.map((p) => p.id === project.id ? project : p) : [...projects, project]));
|
|
@@ -234900,7 +234925,7 @@ const runClanka = fnUntraced(function* (options) {
|
|
|
234900
234925
|
yield* log$1(`Received steer message: ${message}`);
|
|
234901
234926
|
yield* agent.steer(message);
|
|
234902
234927
|
}, fromEffectDrain)), runDrain, forkScoped);
|
|
234903
|
-
yield* stream.pipe(runDrain, catchTag$1("AgentFinished", () =>
|
|
234928
|
+
return yield* stream.pipe(runDrain, as$1(""), catchTag$1("AgentFinished", (e) => succeed$3(e.summary)));
|
|
234904
234929
|
}, scoped$1, (effect, options) => provide$1(effect, layerLocal({
|
|
234905
234930
|
directory: options.directory,
|
|
234906
234931
|
tools: options.withChoose ? TaskChooseTools : TaskTools
|
|
@@ -234915,7 +234940,18 @@ const agentWorker = fnUntraced(function* (options) {
|
|
|
234915
234940
|
directory: worktree.directory,
|
|
234916
234941
|
model: options.preset.extraArgs.join(" "),
|
|
234917
234942
|
system: options.system,
|
|
234918
|
-
prompt: options.
|
|
234943
|
+
prompt: match$8(options.research, {
|
|
234944
|
+
onNone: () => options.prompt,
|
|
234945
|
+
onSome: (research) => make$7([{
|
|
234946
|
+
role: "user",
|
|
234947
|
+
content: options.prompt
|
|
234948
|
+
}, {
|
|
234949
|
+
role: "assistant",
|
|
234950
|
+
content: `Another software engineer has done some prior research for this task, and found the following information:
|
|
234951
|
+
|
|
234952
|
+
${research}`
|
|
234953
|
+
}])
|
|
234954
|
+
}),
|
|
234919
234955
|
stallTimeout: options.stallTimeout,
|
|
234920
234956
|
steer: options.steer
|
|
234921
234957
|
});
|
|
@@ -235160,6 +235196,20 @@ const agentTimeout = fnUntraced(function* (options) {
|
|
|
235160
235196
|
}));
|
|
235161
235197
|
});
|
|
235162
235198
|
//#endregion
|
|
235199
|
+
//#region src/Agents/researcher.ts
|
|
235200
|
+
const agentResearcher = fnUntraced(function* (options) {
|
|
235201
|
+
const worktree = yield* Worktree;
|
|
235202
|
+
const promptGen = yield* PromptGen;
|
|
235203
|
+
if (options.preset.cliAgent.command) return none$4();
|
|
235204
|
+
return yield* runClanka({
|
|
235205
|
+
directory: worktree.directory,
|
|
235206
|
+
model: options.preset.extraArgs.join(" "),
|
|
235207
|
+
system: promptGen.systemClanka(options),
|
|
235208
|
+
prompt: promptGen.promptResearch({ task: options.task }),
|
|
235209
|
+
stallTimeout: options.stallTimeout
|
|
235210
|
+
}).pipe(asSome);
|
|
235211
|
+
});
|
|
235212
|
+
//#endregion
|
|
235163
235213
|
//#region src/commands/root.ts
|
|
235164
235214
|
const run = fnUntraced(function* (options) {
|
|
235165
235215
|
const projectId = yield* CurrentProjectId;
|
|
@@ -235223,6 +235273,13 @@ const run = fnUntraced(function* (options) {
|
|
|
235223
235273
|
}));
|
|
235224
235274
|
if (yield* gen(function* () {
|
|
235225
235275
|
registry.update(currentWorker.state, (s) => s.transitionTo(WorkerStatus.Working({ issueId: taskId })));
|
|
235276
|
+
let researchResult = none$4();
|
|
235277
|
+
if (options.research) researchResult = yield* agentResearcher({
|
|
235278
|
+
task: chosenTask.prd,
|
|
235279
|
+
specsDirectory: options.specsDirectory,
|
|
235280
|
+
stallTimeout: options.stallTimeout,
|
|
235281
|
+
preset: taskPreset
|
|
235282
|
+
});
|
|
235226
235283
|
const promptGen = yield* PromptGen;
|
|
235227
235284
|
const instructions = taskPreset.cliAgent.command ? promptGen.prompt({
|
|
235228
235285
|
specsDirectory: options.specsDirectory,
|
|
@@ -235246,6 +235303,7 @@ const run = fnUntraced(function* (options) {
|
|
|
235246
235303
|
stallTimeout: options.stallTimeout,
|
|
235247
235304
|
preset: taskPreset,
|
|
235248
235305
|
prompt: instructions,
|
|
235306
|
+
research: researchResult,
|
|
235249
235307
|
steer
|
|
235250
235308
|
}).pipe(provideService$2(CurrentTaskRef, issueRef), catchStallInReview, withSpan("Main.agentWorker"))}`);
|
|
235251
235309
|
if (options.review) {
|
|
@@ -235297,7 +235355,8 @@ const runProject = fnUntraced(function* (options) {
|
|
|
235297
235355
|
specsDirectory: options.specsDirectory,
|
|
235298
235356
|
stallTimeout: options.stallTimeout,
|
|
235299
235357
|
runTimeout: options.runTimeout,
|
|
235300
|
-
review: options.project.reviewAgent
|
|
235358
|
+
review: options.project.reviewAgent,
|
|
235359
|
+
research: options.project.researchAgent
|
|
235301
235360
|
}).pipe(provide$1(options.project.gitFlow === "commit" ? GitFlowCommit : GitFlowPR, { local: true }), withWorkerState(options.project.id))), catchTags$1({
|
|
235302
235361
|
NoMoreWork(_error) {
|
|
235303
235362
|
if (isFinite) {
|
|
@@ -235359,10 +235418,10 @@ const commandRoot = make$49("lalph", {
|
|
|
235359
235418
|
const watchTaskState = fnUntraced(function* (options) {
|
|
235360
235419
|
return yield* toStreamResult(yield* AtomRegistry, currentIssuesAtom(yield* CurrentProjectId)).pipe(retry$1(forever$1), orDie, debounce(seconds(10)), runForEach((issues) => {
|
|
235361
235420
|
const issue = issues.find((entry) => entry.id === options.issueId);
|
|
235362
|
-
if (
|
|
235421
|
+
if (issue?.state === "in-progress" || issue?.state === "in-review") return void_$1;
|
|
235363
235422
|
return fail$6(new TaskStateChanged({
|
|
235364
235423
|
issueId: options.issueId,
|
|
235365
|
-
state: issue
|
|
235424
|
+
state: issue?.state ?? "missing"
|
|
235366
235425
|
}));
|
|
235367
235426
|
}), withSpan("Main.watchTaskState"));
|
|
235368
235427
|
});
|
|
@@ -235650,7 +235709,7 @@ const commandEdit = make$49("edit").pipe(withDescription("Open the selected proj
|
|
|
235650
235709
|
const commandSource = make$49("source").pipe(withDescription("Select the issue source to use (e.g. GitHub Issues or Linear). This applies to all projects."), withHandler(() => selectIssueSource), provide(Settings.layer));
|
|
235651
235710
|
//#endregion
|
|
235652
235711
|
//#region package.json
|
|
235653
|
-
var version = "0.3.
|
|
235712
|
+
var version = "0.3.62";
|
|
235654
235713
|
//#endregion
|
|
235655
235714
|
//#region src/commands/projects/ls.ts
|
|
235656
235715
|
const commandProjectsLs = make$49("ls").pipe(withDescription("List configured projects and how they run (enabled state, concurrency, branch, git flow, review agent)."), withHandler(fnUntraced(function* () {
|
|
@@ -235670,6 +235729,7 @@ const commandProjectsLs = make$49("ls").pipe(withDescription("List configured pr
|
|
|
235670
235729
|
console.log(` Concurrency: ${project.concurrency}`);
|
|
235671
235730
|
if (isSome(project.targetBranch)) console.log(` Target Branch: ${project.targetBranch.value}`);
|
|
235672
235731
|
console.log(` Git flow: ${project.gitFlow === "pr" ? "Pull Request" : "Commit"}`);
|
|
235732
|
+
console.log(` Research agent: ${project.researchAgent ? "Enabled" : "Disabled"}`);
|
|
235673
235733
|
console.log(` Review agent: ${project.reviewAgent ? "Enabled" : "Disabled"}`);
|
|
235674
235734
|
console.log("");
|
|
235675
235735
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lalph",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.62",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"@linear/sdk": "^77.0.0",
|
|
30
30
|
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
|
|
31
31
|
"@octokit/types": "^16.0.0",
|
|
32
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
33
|
-
"clanka": "^0.1.
|
|
32
|
+
"@typescript/native-preview": "7.0.0-dev.20260314.1",
|
|
33
|
+
"clanka": "^0.1.10",
|
|
34
34
|
"concurrently": "^9.2.1",
|
|
35
35
|
"effect": "4.0.0-beta.31",
|
|
36
36
|
"husky": "^9.1.7",
|
|
37
|
-
"lint-staged": "^16.3.
|
|
37
|
+
"lint-staged": "^16.3.4",
|
|
38
38
|
"octokit": "^5.0.5",
|
|
39
39
|
"oxlint": "^1.55.0",
|
|
40
40
|
"prettier": "^3.8.1",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Duration, Effect, Option } from "effect"
|
|
2
|
+
import { PromptGen } from "../PromptGen.ts"
|
|
3
|
+
import { Worktree } from "../Worktree.ts"
|
|
4
|
+
import type { CliAgentPreset } from "../domain/CliAgentPreset.ts"
|
|
5
|
+
import { runClanka } from "../Clanka.ts"
|
|
6
|
+
import type { PrdIssue } from "../domain/PrdIssue.ts"
|
|
7
|
+
|
|
8
|
+
export const agentResearcher = Effect.fnUntraced(function* (options: {
|
|
9
|
+
readonly task: PrdIssue
|
|
10
|
+
readonly specsDirectory: string
|
|
11
|
+
readonly stallTimeout: Duration.Duration
|
|
12
|
+
readonly preset: CliAgentPreset
|
|
13
|
+
}) {
|
|
14
|
+
const worktree = yield* Worktree
|
|
15
|
+
const promptGen = yield* PromptGen
|
|
16
|
+
|
|
17
|
+
// use clanka
|
|
18
|
+
if (options.preset.cliAgent.command) {
|
|
19
|
+
return Option.none<string>()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return yield* runClanka({
|
|
23
|
+
directory: worktree.directory,
|
|
24
|
+
model: options.preset.extraArgs.join(" "),
|
|
25
|
+
system: promptGen.systemClanka(options),
|
|
26
|
+
prompt: promptGen.promptResearch({
|
|
27
|
+
task: options.task,
|
|
28
|
+
}),
|
|
29
|
+
stallTimeout: options.stallTimeout,
|
|
30
|
+
}).pipe(Effect.asSome)
|
|
31
|
+
})
|
package/src/Agents/worker.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { Duration, Effect, Path, pipe, Stream } from "effect"
|
|
1
|
+
import { Duration, Effect, Option, Path, pipe, Stream } from "effect"
|
|
2
2
|
import { ChildProcess } from "effect/unstable/process"
|
|
3
3
|
import { Worktree } from "../Worktree.ts"
|
|
4
4
|
import type { CliAgentPreset } from "../domain/CliAgentPreset.ts"
|
|
5
5
|
import { runClanka } from "../Clanka.ts"
|
|
6
6
|
import { ExitCode } from "effect/unstable/process/ChildProcessSpawner"
|
|
7
|
+
import { Prompt } from "effect/unstable/ai"
|
|
7
8
|
|
|
8
9
|
export const agentWorker = Effect.fnUntraced(function* (options: {
|
|
9
10
|
readonly stallTimeout: Duration.Duration
|
|
10
11
|
readonly preset: CliAgentPreset
|
|
11
12
|
readonly system?: string
|
|
12
13
|
readonly prompt: string
|
|
14
|
+
readonly research: Option.Option<string>
|
|
13
15
|
readonly steer?: Stream.Stream<string>
|
|
14
16
|
}) {
|
|
15
17
|
const pathService = yield* Path.Path
|
|
@@ -21,7 +23,22 @@ export const agentWorker = Effect.fnUntraced(function* (options: {
|
|
|
21
23
|
directory: worktree.directory,
|
|
22
24
|
model: options.preset.extraArgs.join(" "),
|
|
23
25
|
system: options.system,
|
|
24
|
-
prompt: options.
|
|
26
|
+
prompt: Option.match(options.research, {
|
|
27
|
+
onNone: () => options.prompt,
|
|
28
|
+
onSome: (research) =>
|
|
29
|
+
Prompt.make([
|
|
30
|
+
{
|
|
31
|
+
role: "user",
|
|
32
|
+
content: options.prompt,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
role: "assistant",
|
|
36
|
+
content: `Another software engineer has done some prior research for this task, and found the following information:
|
|
37
|
+
|
|
38
|
+
${research}`,
|
|
39
|
+
},
|
|
40
|
+
]),
|
|
41
|
+
}),
|
|
25
42
|
stallTimeout: options.stallTimeout,
|
|
26
43
|
steer: options.steer,
|
|
27
44
|
})
|
package/src/Clanka.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { TaskChooseTools, TaskTools, TaskToolsHandlers } from "./TaskTools.ts"
|
|
|
4
4
|
import { ClankaModels } from "./ClankaModels.ts"
|
|
5
5
|
import { withStallTimeout } from "./shared/stream.ts"
|
|
6
6
|
import { NodeHttpClient } from "@effect/platform-node"
|
|
7
|
+
import type { Prompt } from "effect/unstable/ai"
|
|
7
8
|
|
|
8
9
|
export const ClankaMuxerLayer = Layer.effectDiscard(
|
|
9
10
|
Effect.gen(function* () {
|
|
@@ -17,7 +18,7 @@ export const runClanka = Effect.fnUntraced(
|
|
|
17
18
|
function* (options: {
|
|
18
19
|
readonly directory: string
|
|
19
20
|
readonly model: string
|
|
20
|
-
readonly prompt:
|
|
21
|
+
readonly prompt: Prompt.RawInput
|
|
21
22
|
readonly system?: string | undefined
|
|
22
23
|
readonly stallTimeout?: Duration.Input | undefined
|
|
23
24
|
readonly steer?: Stream.Stream<string> | undefined
|
|
@@ -54,9 +55,10 @@ export const runClanka = Effect.fnUntraced(
|
|
|
54
55
|
)
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
yield* stream.pipe(
|
|
58
|
+
return yield* stream.pipe(
|
|
58
59
|
Stream.runDrain,
|
|
59
|
-
Effect.
|
|
60
|
+
Effect.as(""),
|
|
61
|
+
Effect.catchTag("AgentFinished", (e) => Effect.succeed(e.summary)),
|
|
60
62
|
)
|
|
61
63
|
},
|
|
62
64
|
Effect.scoped,
|
package/src/Projects.ts
CHANGED
|
@@ -123,6 +123,11 @@ export const addOrUpdateProject = Effect.fnUntraced(function* (
|
|
|
123
123
|
},
|
|
124
124
|
] as const,
|
|
125
125
|
})
|
|
126
|
+
|
|
127
|
+
const researchAgent = yield* Prompt.toggle({
|
|
128
|
+
message: "Enable research agent?",
|
|
129
|
+
initial: existing ? existing.researchAgent : true,
|
|
130
|
+
})
|
|
126
131
|
const reviewAgent = yield* Prompt.toggle({
|
|
127
132
|
message: "Enable review agent?",
|
|
128
133
|
initial: existing ? existing.reviewAgent : true,
|
|
@@ -134,6 +139,7 @@ export const addOrUpdateProject = Effect.fnUntraced(function* (
|
|
|
134
139
|
concurrency,
|
|
135
140
|
targetBranch,
|
|
136
141
|
gitFlow,
|
|
142
|
+
researchAgent,
|
|
137
143
|
reviewAgent,
|
|
138
144
|
})
|
|
139
145
|
yield* Settings.set(
|
package/src/PromptGen.ts
CHANGED
|
@@ -254,6 +254,24 @@ All steps must be done before the task can be considered complete.${
|
|
|
254
254
|
- Rewrite the notes in the description to include only the key discoveries and information that could speed up future work on other tasks. Make sure to preserve important information such as specification file references.
|
|
255
255
|
- If you believe the task is complete, update the \`state\` to "in-review".`
|
|
256
256
|
|
|
257
|
+
const promptResearch = (options: {
|
|
258
|
+
readonly task: PrdIssue
|
|
259
|
+
}) => `Your job is to gather all the necessary information and details to complete the task described below. Do not make any code changes yet, your job is just to research and gather information.
|
|
260
|
+
|
|
261
|
+
In the final report:
|
|
262
|
+
|
|
263
|
+
- Include key file names, line numbers, and code snippets that are relevant to the task.
|
|
264
|
+
- Any key discoveries that will help with implementing the task.
|
|
265
|
+
- Any other information that will help speed up the implementation of the task.
|
|
266
|
+
- You DO NOT need to add your report to the task description, just include it in your final output.
|
|
267
|
+
|
|
268
|
+
# Task details
|
|
269
|
+
|
|
270
|
+
ID: ${options.task.id}
|
|
271
|
+
Title: ${options.task.title}
|
|
272
|
+
|
|
273
|
+
${options.task.description}`
|
|
274
|
+
|
|
257
275
|
const promptReview = (options: {
|
|
258
276
|
readonly prompt: string
|
|
259
277
|
readonly gitFlow: GitFlow["Service"]
|
|
@@ -431,6 +449,7 @@ Make sure to setup dependencies between the tasks using the \`blockedBy\` field.
|
|
|
431
449
|
promptChooseClanka,
|
|
432
450
|
prompt,
|
|
433
451
|
promptClanka,
|
|
452
|
+
promptResearch,
|
|
434
453
|
promptReview,
|
|
435
454
|
promptReviewCustom,
|
|
436
455
|
promptTimeout,
|
|
@@ -35,6 +35,9 @@ export const commandProjectsLs = Command.make("ls").pipe(
|
|
|
35
35
|
console.log(
|
|
36
36
|
` Git flow: ${project.gitFlow === "pr" ? "Pull Request" : "Commit"}`,
|
|
37
37
|
)
|
|
38
|
+
console.log(
|
|
39
|
+
` Research agent: ${project.researchAgent ? "Enabled" : "Disabled"}`,
|
|
40
|
+
)
|
|
38
41
|
console.log(
|
|
39
42
|
` Review agent: ${project.reviewAgent ? "Enabled" : "Disabled"}`,
|
|
40
43
|
)
|
package/src/commands/root.ts
CHANGED
|
@@ -55,6 +55,7 @@ import type { PrdIssue } from "../domain/PrdIssue.ts"
|
|
|
55
55
|
import { CurrentTaskRef } from "../TaskTools.ts"
|
|
56
56
|
import type { OutputFormatter } from "clanka"
|
|
57
57
|
import { ClankaMuxerLayer } from "../Clanka.ts"
|
|
58
|
+
import { agentResearcher } from "../Agents/researcher.ts"
|
|
58
59
|
|
|
59
60
|
// Main iteration run logic
|
|
60
61
|
|
|
@@ -65,6 +66,7 @@ const run = Effect.fnUntraced(
|
|
|
65
66
|
readonly specsDirectory: string
|
|
66
67
|
readonly stallTimeout: Duration.Duration
|
|
67
68
|
readonly runTimeout: Duration.Duration
|
|
69
|
+
readonly research: boolean
|
|
68
70
|
readonly review: boolean
|
|
69
71
|
}): Effect.fn.Return<
|
|
70
72
|
void,
|
|
@@ -212,6 +214,16 @@ const run = Effect.fnUntraced(
|
|
|
212
214
|
s.transitionTo(WorkerStatus.Working({ issueId: taskId })),
|
|
213
215
|
)
|
|
214
216
|
|
|
217
|
+
let researchResult = Option.none<string>()
|
|
218
|
+
if (options.research) {
|
|
219
|
+
researchResult = yield* agentResearcher({
|
|
220
|
+
task: chosenTask.prd,
|
|
221
|
+
specsDirectory: options.specsDirectory,
|
|
222
|
+
stallTimeout: options.stallTimeout,
|
|
223
|
+
preset: taskPreset,
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
|
|
215
227
|
const promptGen = yield* PromptGen
|
|
216
228
|
const instructions = taskPreset.cliAgent.command
|
|
217
229
|
? promptGen.prompt({
|
|
@@ -243,6 +255,7 @@ const run = Effect.fnUntraced(
|
|
|
243
255
|
stallTimeout: options.stallTimeout,
|
|
244
256
|
preset: taskPreset,
|
|
245
257
|
prompt: instructions,
|
|
258
|
+
research: researchResult,
|
|
246
259
|
steer,
|
|
247
260
|
}).pipe(
|
|
248
261
|
Effect.provideService(CurrentTaskRef, issueRef),
|
|
@@ -352,6 +365,7 @@ const runProject = Effect.fnUntraced(
|
|
|
352
365
|
stallTimeout: options.stallTimeout,
|
|
353
366
|
runTimeout: options.runTimeout,
|
|
354
367
|
review: options.project.reviewAgent,
|
|
368
|
+
research: options.project.researchAgent,
|
|
355
369
|
}).pipe(
|
|
356
370
|
Effect.provide(
|
|
357
371
|
options.project.gitFlow === "commit" ? GitFlowCommit : GitFlowPR,
|
|
@@ -522,17 +536,13 @@ const watchTaskState = Effect.fnUntraced(function* (options: {
|
|
|
522
536
|
Stream.debounce(Duration.seconds(10)),
|
|
523
537
|
Stream.runForEach((issues) => {
|
|
524
538
|
const issue = issues.find((entry) => entry.id === options.issueId)
|
|
525
|
-
if (
|
|
526
|
-
!issue ||
|
|
527
|
-
issue.state === "in-progress" ||
|
|
528
|
-
issue.state === "in-review"
|
|
529
|
-
) {
|
|
539
|
+
if (issue?.state === "in-progress" || issue?.state === "in-review") {
|
|
530
540
|
return Effect.void
|
|
531
541
|
}
|
|
532
542
|
return Effect.fail(
|
|
533
543
|
new TaskStateChanged({
|
|
534
544
|
issueId: options.issueId,
|
|
535
|
-
state: issue
|
|
545
|
+
state: issue?.state ?? "missing",
|
|
536
546
|
}),
|
|
537
547
|
)
|
|
538
548
|
}),
|
package/src/domain/Project.ts
CHANGED
|
@@ -9,5 +9,6 @@ export class Project extends Schema.Class<Project>("lalph/Project")({
|
|
|
9
9
|
targetBranch: Schema.Option(Schema.String),
|
|
10
10
|
concurrency: Schema.Int.check(Schema.isGreaterThanOrEqualTo(1)),
|
|
11
11
|
gitFlow: Schema.Literals(["pr", "commit"]),
|
|
12
|
+
researchAgent: Schema.Boolean.pipe(Schema.withDecodingDefault(() => false)),
|
|
12
13
|
reviewAgent: Schema.Boolean,
|
|
13
14
|
}) {}
|