@locusai/cli 0.11.8 → 0.12.1
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/bin/agent/worker.js +135 -348
- package/bin/locus.js +458 -904
- package/package.json +2 -2
package/bin/agent/worker.js
CHANGED
|
@@ -15249,9 +15249,6 @@ var init_src = __esm(() => {
|
|
|
15249
15249
|
// ../sdk/src/core/config.ts
|
|
15250
15250
|
import { join } from "node:path";
|
|
15251
15251
|
function getLocusPath(projectPath, fileName) {
|
|
15252
|
-
if (fileName === "projectContextFile" || fileName === "projectProgressFile") {
|
|
15253
|
-
return join(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG.projectDir, LOCUS_CONFIG[fileName]);
|
|
15254
|
-
}
|
|
15255
15252
|
return join(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG[fileName]);
|
|
15256
15253
|
}
|
|
15257
15254
|
var PROVIDER, DEFAULT_MODEL, LOCUS_SCHEMA_BASE_URL = "https://locusai.dev/schemas", LOCUS_SCHEMAS, LOCUS_CONFIG;
|
|
@@ -15274,14 +15271,12 @@ var init_config = __esm(() => {
|
|
|
15274
15271
|
settingsFile: "settings.json",
|
|
15275
15272
|
indexFile: "codebase-index.json",
|
|
15276
15273
|
contextFile: "LOCUS.md",
|
|
15274
|
+
learningsFile: "LEARNINGS.md",
|
|
15277
15275
|
artifactsDir: "artifacts",
|
|
15278
15276
|
documentsDir: "documents",
|
|
15279
15277
|
sessionsDir: "sessions",
|
|
15280
15278
|
reviewsDir: "reviews",
|
|
15281
|
-
plansDir: "plans"
|
|
15282
|
-
projectDir: "project",
|
|
15283
|
-
projectContextFile: "context.md",
|
|
15284
|
-
projectProgressFile: "progress.md"
|
|
15279
|
+
plansDir: "plans"
|
|
15285
15280
|
};
|
|
15286
15281
|
});
|
|
15287
15282
|
|
|
@@ -15523,17 +15518,22 @@ class ClaudeRunner {
|
|
|
15523
15518
|
});
|
|
15524
15519
|
});
|
|
15525
15520
|
}
|
|
15526
|
-
|
|
15521
|
+
buildCliArgs() {
|
|
15527
15522
|
const args = [
|
|
15528
|
-
"--dangerously-skip-permissions",
|
|
15529
15523
|
"--print",
|
|
15530
|
-
"--verbose",
|
|
15531
15524
|
"--output-format",
|
|
15532
15525
|
"stream-json",
|
|
15526
|
+
"--verbose",
|
|
15527
|
+
"--dangerously-skip-permissions",
|
|
15528
|
+
"--no-session-persistence",
|
|
15533
15529
|
"--include-partial-messages",
|
|
15534
15530
|
"--model",
|
|
15535
15531
|
this.model
|
|
15536
15532
|
];
|
|
15533
|
+
return args;
|
|
15534
|
+
}
|
|
15535
|
+
async* runStream(prompt) {
|
|
15536
|
+
const args = this.buildCliArgs();
|
|
15537
15537
|
const env = getAugmentedEnv({
|
|
15538
15538
|
FORCE_COLOR: "1",
|
|
15539
15539
|
TERM: "xterm-256color"
|
|
@@ -15773,16 +15773,7 @@ class ClaudeRunner {
|
|
|
15773
15773
|
}
|
|
15774
15774
|
executeRun(prompt) {
|
|
15775
15775
|
return new Promise((resolve2, reject) => {
|
|
15776
|
-
const args =
|
|
15777
|
-
"--dangerously-skip-permissions",
|
|
15778
|
-
"--print",
|
|
15779
|
-
"--verbose",
|
|
15780
|
-
"--output-format",
|
|
15781
|
-
"stream-json",
|
|
15782
|
-
"--include-partial-messages",
|
|
15783
|
-
"--model",
|
|
15784
|
-
this.model
|
|
15785
|
-
];
|
|
15776
|
+
const args = this.buildCliArgs();
|
|
15786
15777
|
const env = getAugmentedEnv({
|
|
15787
15778
|
FORCE_COLOR: "1",
|
|
15788
15779
|
TERM: "xterm-256color"
|
|
@@ -15907,7 +15898,7 @@ class CodexRunner {
|
|
|
15907
15898
|
eventEmitter;
|
|
15908
15899
|
currentToolName;
|
|
15909
15900
|
timeoutMs;
|
|
15910
|
-
constructor(projectPath, model = DEFAULT_MODEL[PROVIDER.CODEX], log,
|
|
15901
|
+
constructor(projectPath, model = DEFAULT_MODEL[PROVIDER.CODEX], log, reasoningEffort, timeoutMs) {
|
|
15911
15902
|
this.projectPath = projectPath;
|
|
15912
15903
|
this.model = model;
|
|
15913
15904
|
this.log = log;
|
|
@@ -16233,7 +16224,7 @@ function createAiRunner(provider, config2) {
|
|
|
16233
16224
|
const model = config2.model ?? DEFAULT_MODEL[resolvedProvider];
|
|
16234
16225
|
switch (resolvedProvider) {
|
|
16235
16226
|
case PROVIDER.CODEX:
|
|
16236
|
-
return new CodexRunner(config2.projectPath, model, config2.log, config2.
|
|
16227
|
+
return new CodexRunner(config2.projectPath, model, config2.log, config2.reasoningEffort ?? "high", config2.timeoutMs);
|
|
16237
16228
|
default:
|
|
16238
16229
|
return new ClaudeRunner(config2.projectPath, model, config2.log, config2.timeoutMs);
|
|
16239
16230
|
}
|
|
@@ -31771,106 +31762,6 @@ var init_src2 = __esm(() => {
|
|
|
31771
31762
|
init_workspaces();
|
|
31772
31763
|
});
|
|
31773
31764
|
|
|
31774
|
-
// ../sdk/src/project/knowledge-base.ts
|
|
31775
|
-
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "node:fs";
|
|
31776
|
-
import { dirname } from "node:path";
|
|
31777
|
-
|
|
31778
|
-
class KnowledgeBase {
|
|
31779
|
-
contextPath;
|
|
31780
|
-
progressPath;
|
|
31781
|
-
constructor(projectPath) {
|
|
31782
|
-
this.contextPath = getLocusPath(projectPath, "projectContextFile");
|
|
31783
|
-
this.progressPath = getLocusPath(projectPath, "projectProgressFile");
|
|
31784
|
-
}
|
|
31785
|
-
readContext() {
|
|
31786
|
-
if (!existsSync3(this.contextPath)) {
|
|
31787
|
-
return "";
|
|
31788
|
-
}
|
|
31789
|
-
return readFileSync3(this.contextPath, "utf-8");
|
|
31790
|
-
}
|
|
31791
|
-
readProgress() {
|
|
31792
|
-
if (!existsSync3(this.progressPath)) {
|
|
31793
|
-
return "";
|
|
31794
|
-
}
|
|
31795
|
-
return readFileSync3(this.progressPath, "utf-8");
|
|
31796
|
-
}
|
|
31797
|
-
updateContext(content) {
|
|
31798
|
-
this.ensureDir(this.contextPath);
|
|
31799
|
-
writeFileSync(this.contextPath, content);
|
|
31800
|
-
}
|
|
31801
|
-
updateProgress(entry) {
|
|
31802
|
-
this.ensureDir(this.progressPath);
|
|
31803
|
-
const existing = this.readProgress();
|
|
31804
|
-
const timestamp = (entry.timestamp ?? new Date).toISOString();
|
|
31805
|
-
const label = entry.role === "user" ? "User" : "Assistant";
|
|
31806
|
-
const line = `**${label}** (${timestamp}):
|
|
31807
|
-
${entry.content}`;
|
|
31808
|
-
const updated = existing ? `${existing}
|
|
31809
|
-
|
|
31810
|
-
---
|
|
31811
|
-
|
|
31812
|
-
${line}` : `# Conversation History
|
|
31813
|
-
|
|
31814
|
-
${line}`;
|
|
31815
|
-
writeFileSync(this.progressPath, updated);
|
|
31816
|
-
}
|
|
31817
|
-
getFullContext() {
|
|
31818
|
-
const context2 = this.readContext();
|
|
31819
|
-
const progress = this.readProgress();
|
|
31820
|
-
const parts = [];
|
|
31821
|
-
if (context2.trim()) {
|
|
31822
|
-
parts.push(context2.trim());
|
|
31823
|
-
}
|
|
31824
|
-
if (progress.trim()) {
|
|
31825
|
-
parts.push(progress.trim());
|
|
31826
|
-
}
|
|
31827
|
-
return parts.join(`
|
|
31828
|
-
|
|
31829
|
-
---
|
|
31830
|
-
|
|
31831
|
-
`);
|
|
31832
|
-
}
|
|
31833
|
-
initialize(info) {
|
|
31834
|
-
this.ensureDir(this.contextPath);
|
|
31835
|
-
this.ensureDir(this.progressPath);
|
|
31836
|
-
const techStackList = info.techStack.map((t) => `- ${t}`).join(`
|
|
31837
|
-
`);
|
|
31838
|
-
const contextContent = `# Project: ${info.name}
|
|
31839
|
-
|
|
31840
|
-
## Mission
|
|
31841
|
-
${info.mission}
|
|
31842
|
-
|
|
31843
|
-
## Tech Stack
|
|
31844
|
-
${techStackList}
|
|
31845
|
-
|
|
31846
|
-
## Architecture
|
|
31847
|
-
<!-- Describe your high-level architecture here -->
|
|
31848
|
-
|
|
31849
|
-
## Key Decisions
|
|
31850
|
-
<!-- Document important technical decisions and their rationale -->
|
|
31851
|
-
|
|
31852
|
-
## Feature Areas
|
|
31853
|
-
<!-- List your main feature areas and their status -->
|
|
31854
|
-
`;
|
|
31855
|
-
const progressContent = `# Conversation History
|
|
31856
|
-
`;
|
|
31857
|
-
writeFileSync(this.contextPath, contextContent);
|
|
31858
|
-
writeFileSync(this.progressPath, progressContent);
|
|
31859
|
-
}
|
|
31860
|
-
get exists() {
|
|
31861
|
-
return existsSync3(this.contextPath) || existsSync3(this.progressPath);
|
|
31862
|
-
}
|
|
31863
|
-
ensureDir(filePath) {
|
|
31864
|
-
const dir = dirname(filePath);
|
|
31865
|
-
if (!existsSync3(dir)) {
|
|
31866
|
-
mkdirSync(dir, { recursive: true });
|
|
31867
|
-
}
|
|
31868
|
-
}
|
|
31869
|
-
}
|
|
31870
|
-
var init_knowledge_base = __esm(() => {
|
|
31871
|
-
init_config();
|
|
31872
|
-
});
|
|
31873
|
-
|
|
31874
31765
|
// ../sdk/src/agent/git-workflow.ts
|
|
31875
31766
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
31876
31767
|
|
|
@@ -32117,7 +32008,7 @@ var init_git_workflow = __esm(() => {
|
|
|
32117
32008
|
});
|
|
32118
32009
|
|
|
32119
32010
|
// ../sdk/src/core/prompt-builder.ts
|
|
32120
|
-
import { existsSync as
|
|
32011
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
32121
32012
|
import { join as join4 } from "node:path";
|
|
32122
32013
|
|
|
32123
32014
|
class PromptBuilder {
|
|
@@ -32125,239 +32016,157 @@ class PromptBuilder {
|
|
|
32125
32016
|
constructor(projectPath) {
|
|
32126
32017
|
this.projectPath = projectPath;
|
|
32127
32018
|
}
|
|
32128
|
-
async build(task2
|
|
32129
|
-
let prompt = `# Task: ${task2.title}
|
|
32130
|
-
|
|
32131
|
-
`;
|
|
32019
|
+
async build(task2) {
|
|
32132
32020
|
const roleText = this.roleToText(task2.assigneeRole);
|
|
32021
|
+
const description = task2.description || "No description provided.";
|
|
32022
|
+
const context2 = this.getProjectContext();
|
|
32023
|
+
const learnings = this.getLearningsContent();
|
|
32024
|
+
const knowledgeBase = this.getKnowledgeBaseSection();
|
|
32025
|
+
let sections = "";
|
|
32133
32026
|
if (roleText) {
|
|
32134
|
-
|
|
32027
|
+
sections += `
|
|
32028
|
+
<role>
|
|
32135
32029
|
You are acting as a ${roleText}.
|
|
32136
|
-
|
|
32030
|
+
</role>
|
|
32137
32031
|
`;
|
|
32138
32032
|
}
|
|
32139
|
-
|
|
32140
|
-
|
|
32141
|
-
|
|
32142
|
-
`;
|
|
32143
|
-
const projectConfig = this.getProjectConfig();
|
|
32144
|
-
if (projectConfig) {
|
|
32145
|
-
prompt += `## Project Metadata
|
|
32146
|
-
`;
|
|
32147
|
-
prompt += `- Version: ${projectConfig.version || "Unknown"}
|
|
32148
|
-
`;
|
|
32149
|
-
prompt += `- Created At: ${projectConfig.createdAt || "Unknown"}
|
|
32150
|
-
|
|
32151
|
-
`;
|
|
32152
|
-
}
|
|
32153
|
-
let serverContext = null;
|
|
32154
|
-
if (options.taskContext) {
|
|
32155
|
-
try {
|
|
32156
|
-
serverContext = JSON.parse(options.taskContext);
|
|
32157
|
-
} catch {
|
|
32158
|
-
serverContext = { context: options.taskContext };
|
|
32159
|
-
}
|
|
32160
|
-
}
|
|
32161
|
-
const contextPath = getLocusPath(this.projectPath, "contextFile");
|
|
32162
|
-
let hasLocalContext = false;
|
|
32163
|
-
if (existsSync4(contextPath)) {
|
|
32164
|
-
try {
|
|
32165
|
-
const context2 = readFileSync4(contextPath, "utf-8");
|
|
32166
|
-
if (context2.trim().length > 20) {
|
|
32167
|
-
prompt += `## Project Context (Local)
|
|
32033
|
+
if (context2) {
|
|
32034
|
+
sections += `
|
|
32035
|
+
<project_context>
|
|
32168
32036
|
${context2}
|
|
32169
|
-
|
|
32170
|
-
`;
|
|
32171
|
-
hasLocalContext = true;
|
|
32172
|
-
}
|
|
32173
|
-
} catch (err) {
|
|
32174
|
-
console.warn(`Warning: Could not read context file: ${err}`);
|
|
32175
|
-
}
|
|
32176
|
-
}
|
|
32177
|
-
if (!hasLocalContext) {
|
|
32178
|
-
const fallback = this.getFallbackContext();
|
|
32179
|
-
if (fallback) {
|
|
32180
|
-
prompt += `## Project Context (README Fallback)
|
|
32181
|
-
${fallback}
|
|
32182
|
-
|
|
32183
|
-
`;
|
|
32184
|
-
}
|
|
32185
|
-
}
|
|
32186
|
-
if (serverContext) {
|
|
32187
|
-
prompt += `## Project Context (Server)
|
|
32188
|
-
`;
|
|
32189
|
-
const project = serverContext.project;
|
|
32190
|
-
if (project) {
|
|
32191
|
-
prompt += `- Project: ${project.name || "Unknown"}
|
|
32192
|
-
`;
|
|
32193
|
-
if (!hasLocalContext && project.techStack?.length) {
|
|
32194
|
-
prompt += `- Tech Stack: ${project.techStack.join(", ")}
|
|
32195
|
-
`;
|
|
32196
|
-
}
|
|
32197
|
-
}
|
|
32198
|
-
if (serverContext.context) {
|
|
32199
|
-
prompt += `
|
|
32200
|
-
${serverContext.context}
|
|
32201
|
-
`;
|
|
32202
|
-
}
|
|
32203
|
-
prompt += `
|
|
32037
|
+
</project_context>
|
|
32204
32038
|
`;
|
|
32205
32039
|
}
|
|
32206
|
-
|
|
32207
|
-
|
|
32208
|
-
|
|
32209
|
-
|
|
32210
|
-
`;
|
|
32211
|
-
prompt += `- Artifacts: \`.locus/artifacts\`
|
|
32040
|
+
sections += `
|
|
32041
|
+
<knowledge_base>
|
|
32042
|
+
${knowledgeBase}
|
|
32043
|
+
</knowledge_base>
|
|
32212
32044
|
`;
|
|
32213
|
-
|
|
32214
|
-
|
|
32215
|
-
|
|
32216
|
-
|
|
32217
|
-
|
|
32218
|
-
|
|
32219
|
-
if (existsSync4(indexPath)) {
|
|
32220
|
-
prompt += `## Codebase Overview
|
|
32221
|
-
There is an index file in the .locus/codebase-index.json and if you need you can check it.
|
|
32222
|
-
|
|
32045
|
+
if (learnings) {
|
|
32046
|
+
sections += `
|
|
32047
|
+
<learnings>
|
|
32048
|
+
These are accumulated lessons from past tasks. Follow them to avoid repeating mistakes:
|
|
32049
|
+
${learnings}
|
|
32050
|
+
</learnings>
|
|
32223
32051
|
`;
|
|
32224
32052
|
}
|
|
32225
32053
|
if (task2.docs && task2.docs.length > 0) {
|
|
32226
|
-
|
|
32227
|
-
`;
|
|
32228
|
-
prompt += `> Full content available on server. Rely on Task Description for specific requirements.
|
|
32229
|
-
|
|
32230
|
-
`;
|
|
32054
|
+
let docsContent = "";
|
|
32231
32055
|
for (const doc3 of task2.docs) {
|
|
32232
32056
|
const content = doc3.content || "";
|
|
32233
32057
|
const limit = 800;
|
|
32234
32058
|
const preview = content.slice(0, limit);
|
|
32235
32059
|
const isTruncated = content.length > limit;
|
|
32236
|
-
|
|
32060
|
+
docsContent += `### ${doc3.title}
|
|
32237
32061
|
${preview}${isTruncated ? `
|
|
32238
32062
|
...(truncated)...` : ""}
|
|
32239
32063
|
|
|
32240
32064
|
`;
|
|
32241
32065
|
}
|
|
32066
|
+
sections += `
|
|
32067
|
+
<documents>
|
|
32068
|
+
${docsContent.trimEnd()}
|
|
32069
|
+
</documents>
|
|
32070
|
+
`;
|
|
32242
32071
|
}
|
|
32243
32072
|
if (task2.acceptanceChecklist && task2.acceptanceChecklist.length > 0) {
|
|
32244
|
-
|
|
32245
|
-
`;
|
|
32073
|
+
let criteria = "";
|
|
32246
32074
|
for (const item of task2.acceptanceChecklist) {
|
|
32247
|
-
|
|
32075
|
+
criteria += `- ${item.done ? "[x]" : "[ ]"} ${item.text}
|
|
32248
32076
|
`;
|
|
32249
32077
|
}
|
|
32250
|
-
|
|
32078
|
+
sections += `
|
|
32079
|
+
<acceptance_criteria>
|
|
32080
|
+
${criteria.trimEnd()}
|
|
32081
|
+
</acceptance_criteria>
|
|
32251
32082
|
`;
|
|
32252
32083
|
}
|
|
32253
32084
|
if (task2.comments && task2.comments.length > 0) {
|
|
32254
|
-
const
|
|
32255
|
-
|
|
32256
|
-
|
|
32257
|
-
|
|
32258
|
-
|
|
32085
|
+
const filteredComments = task2.comments.filter((comment) => comment.author !== "system");
|
|
32086
|
+
const comments = filteredComments.slice(0, 3);
|
|
32087
|
+
if (comments.length > 0) {
|
|
32088
|
+
let commentsContent = "";
|
|
32089
|
+
for (const comment of comments) {
|
|
32090
|
+
const date5 = new Date(comment.createdAt).toLocaleString();
|
|
32091
|
+
commentsContent += `- ${comment.author} (${date5}): ${comment.text}
|
|
32259
32092
|
`;
|
|
32260
|
-
|
|
32261
|
-
|
|
32262
|
-
|
|
32263
|
-
${
|
|
32264
|
-
|
|
32093
|
+
}
|
|
32094
|
+
sections += `
|
|
32095
|
+
<feedback>
|
|
32096
|
+
${commentsContent.trimEnd()}
|
|
32097
|
+
</feedback>
|
|
32265
32098
|
`;
|
|
32266
32099
|
}
|
|
32267
32100
|
}
|
|
32268
|
-
|
|
32269
|
-
|
|
32270
|
-
|
|
32271
|
-
|
|
32272
|
-
|
|
32273
|
-
|
|
32274
|
-
|
|
32101
|
+
return `<task_execution>
|
|
32102
|
+
Complete this task: ${task2.title}
|
|
32103
|
+
|
|
32104
|
+
<description>
|
|
32105
|
+
${description}
|
|
32106
|
+
</description>
|
|
32107
|
+
${sections}
|
|
32108
|
+
<rules>
|
|
32109
|
+
- Complete the task as described
|
|
32110
|
+
- Save any high-level documentation (PRDs, technical drafts, architecture docs) in \`.locus/artifacts/\`
|
|
32111
|
+
- Use relative paths from the project root at all times — no absolute local paths
|
|
32112
|
+
- Do NOT run \`git add\`, \`git commit\`, \`git push\`, or create branches — Locus handles git automatically
|
|
32113
|
+
</rules>
|
|
32114
|
+
</task_execution>`;
|
|
32275
32115
|
}
|
|
32276
32116
|
async buildGenericPrompt(query) {
|
|
32277
|
-
|
|
32278
|
-
|
|
32279
|
-
|
|
32280
|
-
|
|
32281
|
-
|
|
32282
|
-
|
|
32283
|
-
|
|
32284
|
-
|
|
32285
|
-
|
|
32286
|
-
prompt += `## Project Metadata
|
|
32117
|
+
const context2 = this.getProjectContext();
|
|
32118
|
+
const learnings = this.getLearningsContent();
|
|
32119
|
+
const knowledgeBase = this.getKnowledgeBaseSection();
|
|
32120
|
+
let sections = "";
|
|
32121
|
+
if (context2) {
|
|
32122
|
+
sections += `
|
|
32123
|
+
<project_context>
|
|
32124
|
+
${context2}
|
|
32125
|
+
</project_context>
|
|
32287
32126
|
`;
|
|
32288
|
-
|
|
32127
|
+
}
|
|
32128
|
+
sections += `
|
|
32129
|
+
<knowledge_base>
|
|
32130
|
+
${knowledgeBase}
|
|
32131
|
+
</knowledge_base>
|
|
32289
32132
|
`;
|
|
32290
|
-
|
|
32291
|
-
|
|
32133
|
+
if (learnings) {
|
|
32134
|
+
sections += `
|
|
32135
|
+
<learnings>
|
|
32136
|
+
These are accumulated lessons from past tasks. Follow them to avoid repeating mistakes:
|
|
32137
|
+
${learnings}
|
|
32138
|
+
</learnings>
|
|
32292
32139
|
`;
|
|
32293
32140
|
}
|
|
32141
|
+
return `<direct_execution>
|
|
32142
|
+
Execute this prompt: ${query}
|
|
32143
|
+
${sections}
|
|
32144
|
+
<rules>
|
|
32145
|
+
- Execute the prompt based on the provided project context
|
|
32146
|
+
- Use relative paths from the project root at all times — no absolute local paths
|
|
32147
|
+
- Do NOT run \`git add\`, \`git commit\`, \`git push\`, or create branches — Locus handles git automatically
|
|
32148
|
+
</rules>
|
|
32149
|
+
</direct_execution>`;
|
|
32150
|
+
}
|
|
32151
|
+
getProjectContext() {
|
|
32294
32152
|
const contextPath = getLocusPath(this.projectPath, "contextFile");
|
|
32295
|
-
|
|
32296
|
-
if (existsSync4(contextPath)) {
|
|
32153
|
+
if (existsSync3(contextPath)) {
|
|
32297
32154
|
try {
|
|
32298
|
-
const context2 =
|
|
32155
|
+
const context2 = readFileSync3(contextPath, "utf-8");
|
|
32299
32156
|
if (context2.trim().length > 20) {
|
|
32300
|
-
|
|
32301
|
-
${context2}
|
|
32302
|
-
|
|
32303
|
-
`;
|
|
32304
|
-
hasLocalContext = true;
|
|
32157
|
+
return context2;
|
|
32305
32158
|
}
|
|
32306
32159
|
} catch (err) {
|
|
32307
32160
|
console.warn(`Warning: Could not read context file: ${err}`);
|
|
32308
32161
|
}
|
|
32309
32162
|
}
|
|
32310
|
-
|
|
32311
|
-
const fallback = this.getFallbackContext();
|
|
32312
|
-
if (fallback) {
|
|
32313
|
-
prompt += `## Project Context (README Fallback)
|
|
32314
|
-
${fallback}
|
|
32315
|
-
|
|
32316
|
-
`;
|
|
32317
|
-
}
|
|
32318
|
-
}
|
|
32319
|
-
prompt += this.getProjectStructure();
|
|
32320
|
-
prompt += `## Project Knowledge Base
|
|
32321
|
-
`;
|
|
32322
|
-
prompt += `You have access to the following documentation directories for context:
|
|
32323
|
-
`;
|
|
32324
|
-
prompt += `- Artifacts: \`.locus/artifacts\` (local-only, not synced to cloud)
|
|
32325
|
-
`;
|
|
32326
|
-
prompt += `- Documents: \`.locus/documents\` (synced from cloud)
|
|
32327
|
-
`;
|
|
32328
|
-
prompt += `If you need more information about the project strategies, plans, or architecture, please read files in these directories.
|
|
32329
|
-
|
|
32330
|
-
`;
|
|
32331
|
-
const indexPath = getLocusPath(this.projectPath, "indexFile");
|
|
32332
|
-
if (existsSync4(indexPath)) {
|
|
32333
|
-
prompt += `## Codebase Overview
|
|
32334
|
-
There is an index file in the .locus/codebase-index.json and if you need you can check it.
|
|
32335
|
-
|
|
32336
|
-
`;
|
|
32337
|
-
}
|
|
32338
|
-
prompt += `## Instructions
|
|
32339
|
-
1. Execute the prompt based on the provided project context.
|
|
32340
|
-
2. **Paths**: Use relative paths from the project root at all times. Do NOT use absolute local paths (e.g., /Users/...).
|
|
32341
|
-
3. **Git**: Do NOT run \`git add\`, \`git commit\`, \`git push\`, or create branches. The Locus system handles all git operations automatically after your execution completes.
|
|
32342
|
-
4. **Progress**: Do NOT modify \`.locus/project/progress.md\`. The system updates it automatically.`;
|
|
32343
|
-
return prompt;
|
|
32344
|
-
}
|
|
32345
|
-
getProjectConfig() {
|
|
32346
|
-
const configPath = getLocusPath(this.projectPath, "configFile");
|
|
32347
|
-
if (existsSync4(configPath)) {
|
|
32348
|
-
try {
|
|
32349
|
-
return JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
32350
|
-
} catch {
|
|
32351
|
-
return null;
|
|
32352
|
-
}
|
|
32353
|
-
}
|
|
32354
|
-
return null;
|
|
32163
|
+
return this.getFallbackContext() || null;
|
|
32355
32164
|
}
|
|
32356
32165
|
getFallbackContext() {
|
|
32357
32166
|
const readmePath = join4(this.projectPath, "README.md");
|
|
32358
|
-
if (
|
|
32167
|
+
if (existsSync3(readmePath)) {
|
|
32359
32168
|
try {
|
|
32360
|
-
const content =
|
|
32169
|
+
const content = readFileSync3(readmePath, "utf-8");
|
|
32361
32170
|
const limit = 1000;
|
|
32362
32171
|
return content.slice(0, limit) + (content.length > limit ? `
|
|
32363
32172
|
...(truncated)...` : "");
|
|
@@ -32367,32 +32176,28 @@ There is an index file in the .locus/codebase-index.json and if you need you can
|
|
|
32367
32176
|
}
|
|
32368
32177
|
return "";
|
|
32369
32178
|
}
|
|
32370
|
-
|
|
32179
|
+
getKnowledgeBaseSection() {
|
|
32180
|
+
return `You have access to the following documentation directories for context:
|
|
32181
|
+
- Artifacts: \`.locus/artifacts\` (local-only, not synced to cloud)
|
|
32182
|
+
- Documents: \`.locus/documents\` (synced from cloud)
|
|
32183
|
+
If you need more information about the project strategies, plans, or architecture, read files in these directories.`;
|
|
32184
|
+
}
|
|
32185
|
+
getLearningsContent() {
|
|
32186
|
+
const learningsPath = getLocusPath(this.projectPath, "learningsFile");
|
|
32187
|
+
if (!existsSync3(learningsPath)) {
|
|
32188
|
+
return null;
|
|
32189
|
+
}
|
|
32371
32190
|
try {
|
|
32372
|
-
const
|
|
32373
|
-
const
|
|
32374
|
-
|
|
32375
|
-
|
|
32376
|
-
|
|
32377
|
-
return statSync(join4(this.projectPath, e)).isDirectory();
|
|
32378
|
-
} catch {
|
|
32379
|
-
return false;
|
|
32380
|
-
}
|
|
32381
|
-
});
|
|
32382
|
-
if (folders.length === 0)
|
|
32383
|
-
return "";
|
|
32384
|
-
let structure = `## Project Structure
|
|
32385
|
-
`;
|
|
32386
|
-
structure += `Key directories in this project:
|
|
32387
|
-
`;
|
|
32388
|
-
for (const folder of folders) {
|
|
32389
|
-
structure += `- \`${folder}/\`
|
|
32390
|
-
`;
|
|
32191
|
+
const content = readFileSync3(learningsPath, "utf-8");
|
|
32192
|
+
const lines = content.split(`
|
|
32193
|
+
`).filter((l) => l.startsWith("- "));
|
|
32194
|
+
if (lines.length === 0) {
|
|
32195
|
+
return null;
|
|
32391
32196
|
}
|
|
32392
|
-
return
|
|
32393
|
-
|
|
32197
|
+
return lines.join(`
|
|
32198
|
+
`);
|
|
32394
32199
|
} catch {
|
|
32395
|
-
return
|
|
32200
|
+
return null;
|
|
32396
32201
|
}
|
|
32397
32202
|
}
|
|
32398
32203
|
roleToText(role) {
|
|
@@ -32528,7 +32333,6 @@ class AgentWorker {
|
|
|
32528
32333
|
client;
|
|
32529
32334
|
aiRunner;
|
|
32530
32335
|
taskExecutor;
|
|
32531
|
-
knowledgeBase;
|
|
32532
32336
|
gitWorkflow;
|
|
32533
32337
|
maxTasks = 50;
|
|
32534
32338
|
tasksCompleted = 0;
|
|
@@ -32568,7 +32372,6 @@ class AgentWorker {
|
|
|
32568
32372
|
projectPath,
|
|
32569
32373
|
log
|
|
32570
32374
|
});
|
|
32571
|
-
this.knowledgeBase = new KnowledgeBase(projectPath);
|
|
32572
32375
|
this.gitWorkflow = new GitWorkflow(config2, log);
|
|
32573
32376
|
const providerLabel = provider === "codex" ? "Codex" : "Claude";
|
|
32574
32377
|
this.log(`Using ${providerLabel} CLI for all phases`, "info");
|
|
@@ -32642,20 +32445,6 @@ class AgentWorker {
|
|
|
32642
32445
|
};
|
|
32643
32446
|
}
|
|
32644
32447
|
}
|
|
32645
|
-
updateProgress(task2, summary) {
|
|
32646
|
-
try {
|
|
32647
|
-
this.knowledgeBase.updateProgress({
|
|
32648
|
-
role: "user",
|
|
32649
|
-
content: task2.title
|
|
32650
|
-
});
|
|
32651
|
-
this.knowledgeBase.updateProgress({
|
|
32652
|
-
role: "assistant",
|
|
32653
|
-
content: summary
|
|
32654
|
-
});
|
|
32655
|
-
} catch (err) {
|
|
32656
|
-
this.log(`Failed to update progress: ${err instanceof Error ? err.message : String(err)}`, "warn");
|
|
32657
|
-
}
|
|
32658
|
-
}
|
|
32659
32448
|
startHeartbeat() {
|
|
32660
32449
|
this.sendHeartbeat();
|
|
32661
32450
|
this.heartbeatInterval = setInterval(() => this.sendHeartbeat(), 60000);
|
|
@@ -32709,7 +32498,7 @@ class AgentWorker {
|
|
|
32709
32498
|
assignedTo: null
|
|
32710
32499
|
});
|
|
32711
32500
|
await this.client.tasks.addComment(task2.id, this.config.workspaceId, {
|
|
32712
|
-
author:
|
|
32501
|
+
author: "system",
|
|
32713
32502
|
text: `⚠️ Agent execution finished with no file changes, so no commit was created.
|
|
32714
32503
|
|
|
32715
32504
|
${result.summary}`
|
|
@@ -32724,13 +32513,12 @@ ${result.summary}`
|
|
|
32724
32513
|
|
|
32725
32514
|
Branch: \`${result.branch}\`` : "";
|
|
32726
32515
|
await this.client.tasks.addComment(task2.id, this.config.workspaceId, {
|
|
32727
|
-
author:
|
|
32516
|
+
author: "system",
|
|
32728
32517
|
text: `✅ ${result.summary}${branchInfo}`
|
|
32729
32518
|
});
|
|
32730
32519
|
this.tasksCompleted++;
|
|
32731
32520
|
this.completedTaskList.push({ title: task2.title, id: task2.id });
|
|
32732
32521
|
this.taskSummaries.push(result.summary);
|
|
32733
|
-
this.updateProgress(task2, result.summary);
|
|
32734
32522
|
}
|
|
32735
32523
|
} else {
|
|
32736
32524
|
this.log(`Failed: ${task2.title} - ${result.summary}`, "error");
|
|
@@ -32739,7 +32527,7 @@ Branch: \`${result.branch}\`` : "";
|
|
|
32739
32527
|
assignedTo: null
|
|
32740
32528
|
});
|
|
32741
32529
|
await this.client.tasks.addComment(task2.id, this.config.workspaceId, {
|
|
32742
|
-
author:
|
|
32530
|
+
author: "system",
|
|
32743
32531
|
text: `❌ ${result.summary}`
|
|
32744
32532
|
});
|
|
32745
32533
|
}
|
|
@@ -32776,7 +32564,6 @@ var init_worker = __esm(() => {
|
|
|
32776
32564
|
init_config();
|
|
32777
32565
|
init_git_utils();
|
|
32778
32566
|
init_src2();
|
|
32779
|
-
init_knowledge_base();
|
|
32780
32567
|
init_colors();
|
|
32781
32568
|
init_git_workflow();
|
|
32782
32569
|
init_task_executor();
|