@locusai/sdk 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/dist/agent/codebase-indexer-service.d.ts.map +1 -1
- package/dist/agent/reviewer-worker.d.ts +0 -1
- package/dist/agent/reviewer-worker.d.ts.map +1 -1
- package/dist/agent/worker.d.ts +0 -2
- package/dist/agent/worker.d.ts.map +1 -1
- package/dist/agent/worker.js +140 -356
- package/dist/ai/claude-runner.d.ts +1 -0
- package/dist/ai/claude-runner.d.ts.map +1 -1
- package/dist/ai/codex-runner.d.ts +1 -1
- package/dist/ai/codex-runner.d.ts.map +1 -1
- package/dist/ai/factory.d.ts +2 -0
- package/dist/ai/factory.d.ts.map +1 -1
- package/dist/core/config.d.ts +2 -4
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/prompt-builder.d.ts +4 -5
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/index-node.d.ts +1 -1
- package/dist/index-node.d.ts.map +1 -1
- package/dist/index-node.js +400 -776
- package/dist/planning/agents/cross-task-reviewer.d.ts +0 -14
- package/dist/planning/agents/cross-task-reviewer.d.ts.map +1 -1
- package/dist/planning/agents/planner.d.ts +11 -6
- package/dist/planning/agents/planner.d.ts.map +1 -1
- package/dist/planning/index.d.ts +1 -1
- package/dist/planning/index.d.ts.map +1 -1
- package/dist/planning/plan-manager.d.ts +0 -1
- package/dist/planning/plan-manager.d.ts.map +1 -1
- package/dist/planning/planning-meeting.d.ts +11 -13
- package/dist/planning/planning-meeting.d.ts.map +1 -1
- package/dist/planning/sprint-plan.d.ts +7 -3
- package/dist/planning/sprint-plan.d.ts.map +1 -1
- package/dist/utils/json-extractor.d.ts +6 -2
- package/dist/utils/json-extractor.d.ts.map +1 -1
- package/dist/utils/structured-output.d.ts +14 -0
- package/dist/utils/structured-output.d.ts.map +1 -0
- package/package.json +5 -4
- package/dist/project/knowledge-base.d.ts +0 -24
- package/dist/project/knowledge-base.d.ts.map +0 -1
- package/dist/worktree/index.d.ts +0 -2
- package/dist/worktree/index.d.ts.map +0 -1
- package/dist/worktree/worktree-config.d.ts +0 -2
- package/dist/worktree/worktree-config.d.ts.map +0 -1
- package/dist/worktree/worktree-manager.d.ts +0 -2
- package/dist/worktree/worktree-manager.d.ts.map +0 -1
package/dist/agent/worker.js
CHANGED
|
@@ -522,9 +522,6 @@ var init_src = __esm(() => {
|
|
|
522
522
|
|
|
523
523
|
// src/core/config.ts
|
|
524
524
|
function getLocusPath(projectPath, fileName) {
|
|
525
|
-
if (fileName === "projectContextFile" || fileName === "projectProgressFile") {
|
|
526
|
-
return import_node_path.join(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG.projectDir, LOCUS_CONFIG[fileName]);
|
|
527
|
-
}
|
|
528
525
|
return import_node_path.join(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG[fileName]);
|
|
529
526
|
}
|
|
530
527
|
function getAgentArtifactsPath(projectPath, agentId) {
|
|
@@ -552,14 +549,12 @@ var init_config = __esm(() => {
|
|
|
552
549
|
settingsFile: "settings.json",
|
|
553
550
|
indexFile: "codebase-index.json",
|
|
554
551
|
contextFile: "LOCUS.md",
|
|
552
|
+
learningsFile: "LEARNINGS.md",
|
|
555
553
|
artifactsDir: "artifacts",
|
|
556
554
|
documentsDir: "documents",
|
|
557
555
|
sessionsDir: "sessions",
|
|
558
556
|
reviewsDir: "reviews",
|
|
559
|
-
plansDir: "plans"
|
|
560
|
-
projectDir: "project",
|
|
561
|
-
projectContextFile: "context.md",
|
|
562
|
-
projectProgressFile: "progress.md"
|
|
557
|
+
plansDir: "plans"
|
|
563
558
|
};
|
|
564
559
|
LOCUS_GITIGNORE_PATTERNS = [
|
|
565
560
|
"# Locus AI - Session data (user-specific, can grow large)",
|
|
@@ -577,11 +572,8 @@ var init_config = __esm(() => {
|
|
|
577
572
|
"# Locus AI - Settings (contains API key, telegram config, etc.)",
|
|
578
573
|
".locus/settings.json",
|
|
579
574
|
"",
|
|
580
|
-
"# Locus AI - Configuration (contains project context,
|
|
581
|
-
".locus/config.json"
|
|
582
|
-
"",
|
|
583
|
-
"# Locus AI - Project progress (contains project progress, etc.)",
|
|
584
|
-
".locus/project/progress.md"
|
|
575
|
+
"# Locus AI - Configuration (contains project context, etc.)",
|
|
576
|
+
".locus/config.json"
|
|
585
577
|
];
|
|
586
578
|
});
|
|
587
579
|
|
|
@@ -820,17 +812,22 @@ class ClaudeRunner {
|
|
|
820
812
|
});
|
|
821
813
|
});
|
|
822
814
|
}
|
|
823
|
-
|
|
815
|
+
buildCliArgs() {
|
|
824
816
|
const args = [
|
|
825
|
-
"--dangerously-skip-permissions",
|
|
826
817
|
"--print",
|
|
827
|
-
"--verbose",
|
|
828
818
|
"--output-format",
|
|
829
819
|
"stream-json",
|
|
820
|
+
"--verbose",
|
|
821
|
+
"--dangerously-skip-permissions",
|
|
822
|
+
"--no-session-persistence",
|
|
830
823
|
"--include-partial-messages",
|
|
831
824
|
"--model",
|
|
832
825
|
this.model
|
|
833
826
|
];
|
|
827
|
+
return args;
|
|
828
|
+
}
|
|
829
|
+
async* runStream(prompt) {
|
|
830
|
+
const args = this.buildCliArgs();
|
|
834
831
|
const env = getAugmentedEnv({
|
|
835
832
|
FORCE_COLOR: "1",
|
|
836
833
|
TERM: "xterm-256color"
|
|
@@ -1070,16 +1067,7 @@ class ClaudeRunner {
|
|
|
1070
1067
|
}
|
|
1071
1068
|
executeRun(prompt) {
|
|
1072
1069
|
return new Promise((resolve2, reject) => {
|
|
1073
|
-
const args =
|
|
1074
|
-
"--dangerously-skip-permissions",
|
|
1075
|
-
"--print",
|
|
1076
|
-
"--verbose",
|
|
1077
|
-
"--output-format",
|
|
1078
|
-
"stream-json",
|
|
1079
|
-
"--include-partial-messages",
|
|
1080
|
-
"--model",
|
|
1081
|
-
this.model
|
|
1082
|
-
];
|
|
1070
|
+
const args = this.buildCliArgs();
|
|
1083
1071
|
const env = getAugmentedEnv({
|
|
1084
1072
|
FORCE_COLOR: "1",
|
|
1085
1073
|
TERM: "xterm-256color"
|
|
@@ -1200,7 +1188,7 @@ class CodexRunner {
|
|
|
1200
1188
|
eventEmitter;
|
|
1201
1189
|
currentToolName;
|
|
1202
1190
|
timeoutMs;
|
|
1203
|
-
constructor(projectPath, model = DEFAULT_MODEL[PROVIDER.CODEX], log,
|
|
1191
|
+
constructor(projectPath, model = DEFAULT_MODEL[PROVIDER.CODEX], log, reasoningEffort, timeoutMs) {
|
|
1204
1192
|
this.projectPath = projectPath;
|
|
1205
1193
|
this.model = model;
|
|
1206
1194
|
this.log = log;
|
|
@@ -1531,7 +1519,7 @@ function createAiRunner(provider, config) {
|
|
|
1531
1519
|
const model = config.model ?? DEFAULT_MODEL[resolvedProvider];
|
|
1532
1520
|
switch (resolvedProvider) {
|
|
1533
1521
|
case PROVIDER.CODEX:
|
|
1534
|
-
return new CodexRunner(config.projectPath, model, config.log, config.
|
|
1522
|
+
return new CodexRunner(config.projectPath, model, config.log, config.reasoningEffort ?? "high", config.timeoutMs);
|
|
1535
1523
|
default:
|
|
1536
1524
|
return new ClaudeRunner(config.projectPath, model, config.log, config.timeoutMs);
|
|
1537
1525
|
}
|
|
@@ -1638,106 +1626,6 @@ var init_git_utils = __esm(() => {
|
|
|
1638
1626
|
import_node_child_process3 = require("node:child_process");
|
|
1639
1627
|
});
|
|
1640
1628
|
|
|
1641
|
-
// src/project/knowledge-base.ts
|
|
1642
|
-
class KnowledgeBase {
|
|
1643
|
-
contextPath;
|
|
1644
|
-
progressPath;
|
|
1645
|
-
constructor(projectPath) {
|
|
1646
|
-
this.contextPath = getLocusPath(projectPath, "projectContextFile");
|
|
1647
|
-
this.progressPath = getLocusPath(projectPath, "projectProgressFile");
|
|
1648
|
-
}
|
|
1649
|
-
readContext() {
|
|
1650
|
-
if (!import_node_fs3.existsSync(this.contextPath)) {
|
|
1651
|
-
return "";
|
|
1652
|
-
}
|
|
1653
|
-
return import_node_fs3.readFileSync(this.contextPath, "utf-8");
|
|
1654
|
-
}
|
|
1655
|
-
readProgress() {
|
|
1656
|
-
if (!import_node_fs3.existsSync(this.progressPath)) {
|
|
1657
|
-
return "";
|
|
1658
|
-
}
|
|
1659
|
-
return import_node_fs3.readFileSync(this.progressPath, "utf-8");
|
|
1660
|
-
}
|
|
1661
|
-
updateContext(content) {
|
|
1662
|
-
this.ensureDir(this.contextPath);
|
|
1663
|
-
import_node_fs3.writeFileSync(this.contextPath, content);
|
|
1664
|
-
}
|
|
1665
|
-
updateProgress(entry) {
|
|
1666
|
-
this.ensureDir(this.progressPath);
|
|
1667
|
-
const existing = this.readProgress();
|
|
1668
|
-
const timestamp = (entry.timestamp ?? new Date).toISOString();
|
|
1669
|
-
const label = entry.role === "user" ? "User" : "Assistant";
|
|
1670
|
-
const line = `**${label}** (${timestamp}):
|
|
1671
|
-
${entry.content}`;
|
|
1672
|
-
const updated = existing ? `${existing}
|
|
1673
|
-
|
|
1674
|
-
---
|
|
1675
|
-
|
|
1676
|
-
${line}` : `# Conversation History
|
|
1677
|
-
|
|
1678
|
-
${line}`;
|
|
1679
|
-
import_node_fs3.writeFileSync(this.progressPath, updated);
|
|
1680
|
-
}
|
|
1681
|
-
getFullContext() {
|
|
1682
|
-
const context = this.readContext();
|
|
1683
|
-
const progress = this.readProgress();
|
|
1684
|
-
const parts = [];
|
|
1685
|
-
if (context.trim()) {
|
|
1686
|
-
parts.push(context.trim());
|
|
1687
|
-
}
|
|
1688
|
-
if (progress.trim()) {
|
|
1689
|
-
parts.push(progress.trim());
|
|
1690
|
-
}
|
|
1691
|
-
return parts.join(`
|
|
1692
|
-
|
|
1693
|
-
---
|
|
1694
|
-
|
|
1695
|
-
`);
|
|
1696
|
-
}
|
|
1697
|
-
initialize(info) {
|
|
1698
|
-
this.ensureDir(this.contextPath);
|
|
1699
|
-
this.ensureDir(this.progressPath);
|
|
1700
|
-
const techStackList = info.techStack.map((t) => `- ${t}`).join(`
|
|
1701
|
-
`);
|
|
1702
|
-
const contextContent = `# Project: ${info.name}
|
|
1703
|
-
|
|
1704
|
-
## Mission
|
|
1705
|
-
${info.mission}
|
|
1706
|
-
|
|
1707
|
-
## Tech Stack
|
|
1708
|
-
${techStackList}
|
|
1709
|
-
|
|
1710
|
-
## Architecture
|
|
1711
|
-
<!-- Describe your high-level architecture here -->
|
|
1712
|
-
|
|
1713
|
-
## Key Decisions
|
|
1714
|
-
<!-- Document important technical decisions and their rationale -->
|
|
1715
|
-
|
|
1716
|
-
## Feature Areas
|
|
1717
|
-
<!-- List your main feature areas and their status -->
|
|
1718
|
-
`;
|
|
1719
|
-
const progressContent = `# Conversation History
|
|
1720
|
-
`;
|
|
1721
|
-
import_node_fs3.writeFileSync(this.contextPath, contextContent);
|
|
1722
|
-
import_node_fs3.writeFileSync(this.progressPath, progressContent);
|
|
1723
|
-
}
|
|
1724
|
-
get exists() {
|
|
1725
|
-
return import_node_fs3.existsSync(this.contextPath) || import_node_fs3.existsSync(this.progressPath);
|
|
1726
|
-
}
|
|
1727
|
-
ensureDir(filePath) {
|
|
1728
|
-
const dir = import_node_path5.dirname(filePath);
|
|
1729
|
-
if (!import_node_fs3.existsSync(dir)) {
|
|
1730
|
-
import_node_fs3.mkdirSync(dir, { recursive: true });
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
}
|
|
1734
|
-
var import_node_fs3, import_node_path5;
|
|
1735
|
-
var init_knowledge_base = __esm(() => {
|
|
1736
|
-
init_config();
|
|
1737
|
-
import_node_fs3 = require("node:fs");
|
|
1738
|
-
import_node_path5 = require("node:path");
|
|
1739
|
-
});
|
|
1740
|
-
|
|
1741
1629
|
// src/agent/git-workflow.ts
|
|
1742
1630
|
class GitWorkflow {
|
|
1743
1631
|
config;
|
|
@@ -1989,239 +1877,157 @@ class PromptBuilder {
|
|
|
1989
1877
|
constructor(projectPath) {
|
|
1990
1878
|
this.projectPath = projectPath;
|
|
1991
1879
|
}
|
|
1992
|
-
async build(task
|
|
1993
|
-
let prompt = `# Task: ${task.title}
|
|
1994
|
-
|
|
1995
|
-
`;
|
|
1880
|
+
async build(task) {
|
|
1996
1881
|
const roleText = this.roleToText(task.assigneeRole);
|
|
1882
|
+
const description = task.description || "No description provided.";
|
|
1883
|
+
const context = this.getProjectContext();
|
|
1884
|
+
const learnings = this.getLearningsContent();
|
|
1885
|
+
const knowledgeBase = this.getKnowledgeBaseSection();
|
|
1886
|
+
let sections = "";
|
|
1997
1887
|
if (roleText) {
|
|
1998
|
-
|
|
1888
|
+
sections += `
|
|
1889
|
+
<role>
|
|
1999
1890
|
You are acting as a ${roleText}.
|
|
2000
|
-
|
|
1891
|
+
</role>
|
|
2001
1892
|
`;
|
|
2002
1893
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
`;
|
|
2007
|
-
const projectConfig = this.getProjectConfig();
|
|
2008
|
-
if (projectConfig) {
|
|
2009
|
-
prompt += `## Project Metadata
|
|
2010
|
-
`;
|
|
2011
|
-
prompt += `- Version: ${projectConfig.version || "Unknown"}
|
|
2012
|
-
`;
|
|
2013
|
-
prompt += `- Created At: ${projectConfig.createdAt || "Unknown"}
|
|
2014
|
-
|
|
2015
|
-
`;
|
|
2016
|
-
}
|
|
2017
|
-
let serverContext = null;
|
|
2018
|
-
if (options.taskContext) {
|
|
2019
|
-
try {
|
|
2020
|
-
serverContext = JSON.parse(options.taskContext);
|
|
2021
|
-
} catch {
|
|
2022
|
-
serverContext = { context: options.taskContext };
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
const contextPath = getLocusPath(this.projectPath, "contextFile");
|
|
2026
|
-
let hasLocalContext = false;
|
|
2027
|
-
if (import_node_fs4.existsSync(contextPath)) {
|
|
2028
|
-
try {
|
|
2029
|
-
const context = import_node_fs4.readFileSync(contextPath, "utf-8");
|
|
2030
|
-
if (context.trim().length > 20) {
|
|
2031
|
-
prompt += `## Project Context (Local)
|
|
1894
|
+
if (context) {
|
|
1895
|
+
sections += `
|
|
1896
|
+
<project_context>
|
|
2032
1897
|
${context}
|
|
2033
|
-
|
|
2034
|
-
`;
|
|
2035
|
-
hasLocalContext = true;
|
|
2036
|
-
}
|
|
2037
|
-
} catch (err) {
|
|
2038
|
-
console.warn(`Warning: Could not read context file: ${err}`);
|
|
2039
|
-
}
|
|
2040
|
-
}
|
|
2041
|
-
if (!hasLocalContext) {
|
|
2042
|
-
const fallback = this.getFallbackContext();
|
|
2043
|
-
if (fallback) {
|
|
2044
|
-
prompt += `## Project Context (README Fallback)
|
|
2045
|
-
${fallback}
|
|
2046
|
-
|
|
1898
|
+
</project_context>
|
|
2047
1899
|
`;
|
|
2048
|
-
}
|
|
2049
1900
|
}
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
if (project) {
|
|
2055
|
-
prompt += `- Project: ${project.name || "Unknown"}
|
|
1901
|
+
sections += `
|
|
1902
|
+
<knowledge_base>
|
|
1903
|
+
${knowledgeBase}
|
|
1904
|
+
</knowledge_base>
|
|
2056
1905
|
`;
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
prompt += `
|
|
2064
|
-
${serverContext.context}
|
|
2065
|
-
`;
|
|
2066
|
-
}
|
|
2067
|
-
prompt += `
|
|
2068
|
-
`;
|
|
2069
|
-
}
|
|
2070
|
-
prompt += this.getProjectStructure();
|
|
2071
|
-
prompt += `## Project Knowledge Base
|
|
2072
|
-
`;
|
|
2073
|
-
prompt += `You have access to the following documentation directories for context:
|
|
2074
|
-
`;
|
|
2075
|
-
prompt += `- Artifacts: \`.locus/artifacts\`
|
|
2076
|
-
`;
|
|
2077
|
-
prompt += `- Documents: \`.locus/documents\`
|
|
2078
|
-
`;
|
|
2079
|
-
prompt += `If you need more information about the project strategies, plans, or architecture, please read files in these directories.
|
|
2080
|
-
|
|
2081
|
-
`;
|
|
2082
|
-
const indexPath = getLocusPath(this.projectPath, "indexFile");
|
|
2083
|
-
if (import_node_fs4.existsSync(indexPath)) {
|
|
2084
|
-
prompt += `## Codebase Overview
|
|
2085
|
-
There is an index file in the .locus/codebase-index.json and if you need you can check it.
|
|
2086
|
-
|
|
1906
|
+
if (learnings) {
|
|
1907
|
+
sections += `
|
|
1908
|
+
<learnings>
|
|
1909
|
+
These are accumulated lessons from past tasks. Follow them to avoid repeating mistakes:
|
|
1910
|
+
${learnings}
|
|
1911
|
+
</learnings>
|
|
2087
1912
|
`;
|
|
2088
1913
|
}
|
|
2089
1914
|
if (task.docs && task.docs.length > 0) {
|
|
2090
|
-
|
|
2091
|
-
`;
|
|
2092
|
-
prompt += `> Full content available on server. Rely on Task Description for specific requirements.
|
|
2093
|
-
|
|
2094
|
-
`;
|
|
1915
|
+
let docsContent = "";
|
|
2095
1916
|
for (const doc of task.docs) {
|
|
2096
1917
|
const content = doc.content || "";
|
|
2097
1918
|
const limit = 800;
|
|
2098
1919
|
const preview = content.slice(0, limit);
|
|
2099
1920
|
const isTruncated = content.length > limit;
|
|
2100
|
-
|
|
1921
|
+
docsContent += `### ${doc.title}
|
|
2101
1922
|
${preview}${isTruncated ? `
|
|
2102
1923
|
...(truncated)...` : ""}
|
|
2103
1924
|
|
|
2104
1925
|
`;
|
|
2105
1926
|
}
|
|
1927
|
+
sections += `
|
|
1928
|
+
<documents>
|
|
1929
|
+
${docsContent.trimEnd()}
|
|
1930
|
+
</documents>
|
|
1931
|
+
`;
|
|
2106
1932
|
}
|
|
2107
1933
|
if (task.acceptanceChecklist && task.acceptanceChecklist.length > 0) {
|
|
2108
|
-
|
|
2109
|
-
`;
|
|
1934
|
+
let criteria = "";
|
|
2110
1935
|
for (const item of task.acceptanceChecklist) {
|
|
2111
|
-
|
|
1936
|
+
criteria += `- ${item.done ? "[x]" : "[ ]"} ${item.text}
|
|
2112
1937
|
`;
|
|
2113
1938
|
}
|
|
2114
|
-
|
|
1939
|
+
sections += `
|
|
1940
|
+
<acceptance_criteria>
|
|
1941
|
+
${criteria.trimEnd()}
|
|
1942
|
+
</acceptance_criteria>
|
|
2115
1943
|
`;
|
|
2116
1944
|
}
|
|
2117
1945
|
if (task.comments && task.comments.length > 0) {
|
|
2118
|
-
const
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
1946
|
+
const filteredComments = task.comments.filter((comment) => comment.author !== "system");
|
|
1947
|
+
const comments = filteredComments.slice(0, 3);
|
|
1948
|
+
if (comments.length > 0) {
|
|
1949
|
+
let commentsContent = "";
|
|
1950
|
+
for (const comment of comments) {
|
|
1951
|
+
const date = new Date(comment.createdAt).toLocaleString();
|
|
1952
|
+
commentsContent += `- ${comment.author} (${date}): ${comment.text}
|
|
2123
1953
|
`;
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
${
|
|
2128
|
-
|
|
1954
|
+
}
|
|
1955
|
+
sections += `
|
|
1956
|
+
<feedback>
|
|
1957
|
+
${commentsContent.trimEnd()}
|
|
1958
|
+
</feedback>
|
|
2129
1959
|
`;
|
|
2130
1960
|
}
|
|
2131
1961
|
}
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
1962
|
+
return `<task_execution>
|
|
1963
|
+
Complete this task: ${task.title}
|
|
1964
|
+
|
|
1965
|
+
<description>
|
|
1966
|
+
${description}
|
|
1967
|
+
</description>
|
|
1968
|
+
${sections}
|
|
1969
|
+
<rules>
|
|
1970
|
+
- Complete the task as described
|
|
1971
|
+
- Save any high-level documentation (PRDs, technical drafts, architecture docs) in \`.locus/artifacts/\`
|
|
1972
|
+
- Use relative paths from the project root at all times — no absolute local paths
|
|
1973
|
+
- Do NOT run \`git add\`, \`git commit\`, \`git push\`, or create branches — Locus handles git automatically
|
|
1974
|
+
</rules>
|
|
1975
|
+
</task_execution>`;
|
|
2139
1976
|
}
|
|
2140
1977
|
async buildGenericPrompt(query) {
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
prompt += `## Project Metadata
|
|
1978
|
+
const context = this.getProjectContext();
|
|
1979
|
+
const learnings = this.getLearningsContent();
|
|
1980
|
+
const knowledgeBase = this.getKnowledgeBaseSection();
|
|
1981
|
+
let sections = "";
|
|
1982
|
+
if (context) {
|
|
1983
|
+
sections += `
|
|
1984
|
+
<project_context>
|
|
1985
|
+
${context}
|
|
1986
|
+
</project_context>
|
|
2151
1987
|
`;
|
|
2152
|
-
|
|
1988
|
+
}
|
|
1989
|
+
sections += `
|
|
1990
|
+
<knowledge_base>
|
|
1991
|
+
${knowledgeBase}
|
|
1992
|
+
</knowledge_base>
|
|
2153
1993
|
`;
|
|
2154
|
-
|
|
2155
|
-
|
|
1994
|
+
if (learnings) {
|
|
1995
|
+
sections += `
|
|
1996
|
+
<learnings>
|
|
1997
|
+
These are accumulated lessons from past tasks. Follow them to avoid repeating mistakes:
|
|
1998
|
+
${learnings}
|
|
1999
|
+
</learnings>
|
|
2156
2000
|
`;
|
|
2157
2001
|
}
|
|
2002
|
+
return `<direct_execution>
|
|
2003
|
+
Execute this prompt: ${query}
|
|
2004
|
+
${sections}
|
|
2005
|
+
<rules>
|
|
2006
|
+
- Execute the prompt based on the provided project context
|
|
2007
|
+
- Use relative paths from the project root at all times — no absolute local paths
|
|
2008
|
+
- Do NOT run \`git add\`, \`git commit\`, \`git push\`, or create branches — Locus handles git automatically
|
|
2009
|
+
</rules>
|
|
2010
|
+
</direct_execution>`;
|
|
2011
|
+
}
|
|
2012
|
+
getProjectContext() {
|
|
2158
2013
|
const contextPath = getLocusPath(this.projectPath, "contextFile");
|
|
2159
|
-
|
|
2160
|
-
if (import_node_fs4.existsSync(contextPath)) {
|
|
2014
|
+
if (import_node_fs3.existsSync(contextPath)) {
|
|
2161
2015
|
try {
|
|
2162
|
-
const context =
|
|
2016
|
+
const context = import_node_fs3.readFileSync(contextPath, "utf-8");
|
|
2163
2017
|
if (context.trim().length > 20) {
|
|
2164
|
-
|
|
2165
|
-
${context}
|
|
2166
|
-
|
|
2167
|
-
`;
|
|
2168
|
-
hasLocalContext = true;
|
|
2018
|
+
return context;
|
|
2169
2019
|
}
|
|
2170
2020
|
} catch (err) {
|
|
2171
2021
|
console.warn(`Warning: Could not read context file: ${err}`);
|
|
2172
2022
|
}
|
|
2173
2023
|
}
|
|
2174
|
-
|
|
2175
|
-
const fallback = this.getFallbackContext();
|
|
2176
|
-
if (fallback) {
|
|
2177
|
-
prompt += `## Project Context (README Fallback)
|
|
2178
|
-
${fallback}
|
|
2179
|
-
|
|
2180
|
-
`;
|
|
2181
|
-
}
|
|
2182
|
-
}
|
|
2183
|
-
prompt += this.getProjectStructure();
|
|
2184
|
-
prompt += `## Project Knowledge Base
|
|
2185
|
-
`;
|
|
2186
|
-
prompt += `You have access to the following documentation directories for context:
|
|
2187
|
-
`;
|
|
2188
|
-
prompt += `- Artifacts: \`.locus/artifacts\` (local-only, not synced to cloud)
|
|
2189
|
-
`;
|
|
2190
|
-
prompt += `- Documents: \`.locus/documents\` (synced from cloud)
|
|
2191
|
-
`;
|
|
2192
|
-
prompt += `If you need more information about the project strategies, plans, or architecture, please read files in these directories.
|
|
2193
|
-
|
|
2194
|
-
`;
|
|
2195
|
-
const indexPath = getLocusPath(this.projectPath, "indexFile");
|
|
2196
|
-
if (import_node_fs4.existsSync(indexPath)) {
|
|
2197
|
-
prompt += `## Codebase Overview
|
|
2198
|
-
There is an index file in the .locus/codebase-index.json and if you need you can check it.
|
|
2199
|
-
|
|
2200
|
-
`;
|
|
2201
|
-
}
|
|
2202
|
-
prompt += `## Instructions
|
|
2203
|
-
1. Execute the prompt based on the provided project context.
|
|
2204
|
-
2. **Paths**: Use relative paths from the project root at all times. Do NOT use absolute local paths (e.g., /Users/...).
|
|
2205
|
-
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.
|
|
2206
|
-
4. **Progress**: Do NOT modify \`.locus/project/progress.md\`. The system updates it automatically.`;
|
|
2207
|
-
return prompt;
|
|
2208
|
-
}
|
|
2209
|
-
getProjectConfig() {
|
|
2210
|
-
const configPath = getLocusPath(this.projectPath, "configFile");
|
|
2211
|
-
if (import_node_fs4.existsSync(configPath)) {
|
|
2212
|
-
try {
|
|
2213
|
-
return JSON.parse(import_node_fs4.readFileSync(configPath, "utf-8"));
|
|
2214
|
-
} catch {
|
|
2215
|
-
return null;
|
|
2216
|
-
}
|
|
2217
|
-
}
|
|
2218
|
-
return null;
|
|
2024
|
+
return this.getFallbackContext() || null;
|
|
2219
2025
|
}
|
|
2220
2026
|
getFallbackContext() {
|
|
2221
|
-
const readmePath =
|
|
2222
|
-
if (
|
|
2027
|
+
const readmePath = import_node_path5.join(this.projectPath, "README.md");
|
|
2028
|
+
if (import_node_fs3.existsSync(readmePath)) {
|
|
2223
2029
|
try {
|
|
2224
|
-
const content =
|
|
2030
|
+
const content = import_node_fs3.readFileSync(readmePath, "utf-8");
|
|
2225
2031
|
const limit = 1000;
|
|
2226
2032
|
return content.slice(0, limit) + (content.length > limit ? `
|
|
2227
2033
|
...(truncated)...` : "");
|
|
@@ -2231,32 +2037,28 @@ There is an index file in the .locus/codebase-index.json and if you need you can
|
|
|
2231
2037
|
}
|
|
2232
2038
|
return "";
|
|
2233
2039
|
}
|
|
2234
|
-
|
|
2040
|
+
getKnowledgeBaseSection() {
|
|
2041
|
+
return `You have access to the following documentation directories for context:
|
|
2042
|
+
- Artifacts: \`.locus/artifacts\` (local-only, not synced to cloud)
|
|
2043
|
+
- Documents: \`.locus/documents\` (synced from cloud)
|
|
2044
|
+
If you need more information about the project strategies, plans, or architecture, read files in these directories.`;
|
|
2045
|
+
}
|
|
2046
|
+
getLearningsContent() {
|
|
2047
|
+
const learningsPath = getLocusPath(this.projectPath, "learningsFile");
|
|
2048
|
+
if (!import_node_fs3.existsSync(learningsPath)) {
|
|
2049
|
+
return null;
|
|
2050
|
+
}
|
|
2235
2051
|
try {
|
|
2236
|
-
const
|
|
2237
|
-
const
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
return import_node_fs4.statSync(import_node_path6.join(this.projectPath, e)).isDirectory();
|
|
2242
|
-
} catch {
|
|
2243
|
-
return false;
|
|
2244
|
-
}
|
|
2245
|
-
});
|
|
2246
|
-
if (folders.length === 0)
|
|
2247
|
-
return "";
|
|
2248
|
-
let structure = `## Project Structure
|
|
2249
|
-
`;
|
|
2250
|
-
structure += `Key directories in this project:
|
|
2251
|
-
`;
|
|
2252
|
-
for (const folder of folders) {
|
|
2253
|
-
structure += `- \`${folder}/\`
|
|
2254
|
-
`;
|
|
2052
|
+
const content = import_node_fs3.readFileSync(learningsPath, "utf-8");
|
|
2053
|
+
const lines = content.split(`
|
|
2054
|
+
`).filter((l) => l.startsWith("- "));
|
|
2055
|
+
if (lines.length === 0) {
|
|
2056
|
+
return null;
|
|
2255
2057
|
}
|
|
2256
|
-
return
|
|
2257
|
-
|
|
2058
|
+
return lines.join(`
|
|
2059
|
+
`);
|
|
2258
2060
|
} catch {
|
|
2259
|
-
return
|
|
2061
|
+
return null;
|
|
2260
2062
|
}
|
|
2261
2063
|
}
|
|
2262
2064
|
roleToText(role) {
|
|
@@ -2279,11 +2081,11 @@ There is an index file in the .locus/codebase-index.json and if you need you can
|
|
|
2279
2081
|
}
|
|
2280
2082
|
}
|
|
2281
2083
|
}
|
|
2282
|
-
var
|
|
2084
|
+
var import_node_fs3, import_node_path5, import_shared2;
|
|
2283
2085
|
var init_prompt_builder = __esm(() => {
|
|
2284
2086
|
init_config();
|
|
2285
|
-
|
|
2286
|
-
|
|
2087
|
+
import_node_fs3 = require("node:fs");
|
|
2088
|
+
import_node_path5 = require("node:path");
|
|
2287
2089
|
import_shared2 = require("@locusai/shared");
|
|
2288
2090
|
});
|
|
2289
2091
|
|
|
@@ -2401,7 +2203,6 @@ class AgentWorker {
|
|
|
2401
2203
|
client;
|
|
2402
2204
|
aiRunner;
|
|
2403
2205
|
taskExecutor;
|
|
2404
|
-
knowledgeBase;
|
|
2405
2206
|
gitWorkflow;
|
|
2406
2207
|
maxTasks = 50;
|
|
2407
2208
|
tasksCompleted = 0;
|
|
@@ -2441,7 +2242,6 @@ class AgentWorker {
|
|
|
2441
2242
|
projectPath,
|
|
2442
2243
|
log
|
|
2443
2244
|
});
|
|
2444
|
-
this.knowledgeBase = new KnowledgeBase(projectPath);
|
|
2445
2245
|
this.gitWorkflow = new GitWorkflow(config, log);
|
|
2446
2246
|
const providerLabel = provider === "codex" ? "Codex" : "Claude";
|
|
2447
2247
|
this.log(`Using ${providerLabel} CLI for all phases`, "info");
|
|
@@ -2515,20 +2315,6 @@ class AgentWorker {
|
|
|
2515
2315
|
};
|
|
2516
2316
|
}
|
|
2517
2317
|
}
|
|
2518
|
-
updateProgress(task, summary) {
|
|
2519
|
-
try {
|
|
2520
|
-
this.knowledgeBase.updateProgress({
|
|
2521
|
-
role: "user",
|
|
2522
|
-
content: task.title
|
|
2523
|
-
});
|
|
2524
|
-
this.knowledgeBase.updateProgress({
|
|
2525
|
-
role: "assistant",
|
|
2526
|
-
content: summary
|
|
2527
|
-
});
|
|
2528
|
-
} catch (err) {
|
|
2529
|
-
this.log(`Failed to update progress: ${err instanceof Error ? err.message : String(err)}`, "warn");
|
|
2530
|
-
}
|
|
2531
|
-
}
|
|
2532
2318
|
startHeartbeat() {
|
|
2533
2319
|
this.sendHeartbeat();
|
|
2534
2320
|
this.heartbeatInterval = setInterval(() => this.sendHeartbeat(), 60000);
|
|
@@ -2582,7 +2368,7 @@ class AgentWorker {
|
|
|
2582
2368
|
assignedTo: null
|
|
2583
2369
|
});
|
|
2584
2370
|
await this.client.tasks.addComment(task.id, this.config.workspaceId, {
|
|
2585
|
-
author:
|
|
2371
|
+
author: "system",
|
|
2586
2372
|
text: `⚠️ Agent execution finished with no file changes, so no commit was created.
|
|
2587
2373
|
|
|
2588
2374
|
${result.summary}`
|
|
@@ -2597,13 +2383,12 @@ ${result.summary}`
|
|
|
2597
2383
|
|
|
2598
2384
|
Branch: \`${result.branch}\`` : "";
|
|
2599
2385
|
await this.client.tasks.addComment(task.id, this.config.workspaceId, {
|
|
2600
|
-
author:
|
|
2386
|
+
author: "system",
|
|
2601
2387
|
text: `✅ ${result.summary}${branchInfo}`
|
|
2602
2388
|
});
|
|
2603
2389
|
this.tasksCompleted++;
|
|
2604
2390
|
this.completedTaskList.push({ title: task.title, id: task.id });
|
|
2605
2391
|
this.taskSummaries.push(result.summary);
|
|
2606
|
-
this.updateProgress(task, result.summary);
|
|
2607
2392
|
}
|
|
2608
2393
|
} else {
|
|
2609
2394
|
this.log(`Failed: ${task.title} - ${result.summary}`, "error");
|
|
@@ -2612,7 +2397,7 @@ Branch: \`${result.branch}\`` : "";
|
|
|
2612
2397
|
assignedTo: null
|
|
2613
2398
|
});
|
|
2614
2399
|
await this.client.tasks.addComment(task.id, this.config.workspaceId, {
|
|
2615
|
-
author:
|
|
2400
|
+
author: "system",
|
|
2616
2401
|
text: `❌ ${result.summary}`
|
|
2617
2402
|
});
|
|
2618
2403
|
}
|
|
@@ -2648,7 +2433,6 @@ var init_worker = __esm(() => {
|
|
|
2648
2433
|
init_config();
|
|
2649
2434
|
init_git_utils();
|
|
2650
2435
|
init_src();
|
|
2651
|
-
init_knowledge_base();
|
|
2652
2436
|
init_colors();
|
|
2653
2437
|
init_git_workflow();
|
|
2654
2438
|
init_task_executor();
|
|
@@ -22,6 +22,7 @@ export declare class ClaudeRunner implements AiRunner {
|
|
|
22
22
|
abort(): void;
|
|
23
23
|
run(prompt: string): Promise<string>;
|
|
24
24
|
private withTimeout;
|
|
25
|
+
private buildCliArgs;
|
|
25
26
|
runStream(prompt: string): AsyncGenerator<StreamChunk, void, unknown>;
|
|
26
27
|
/**
|
|
27
28
|
* Emit an event corresponding to a stream chunk.
|