@locusai/sdk 0.8.0 → 0.8.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.
@@ -1,5 +1,6 @@
1
1
  export { CodebaseIndexerService } from "./codebase-indexer-service.js";
2
2
  export { DocumentFetcher } from "./document-fetcher.js";
3
+ export { ReviewService, type ReviewServiceDeps } from "./review-service.js";
3
4
  export { TaskExecutor } from "./task-executor.js";
4
5
  export { AgentWorker, type WorkerConfig } from "./worker.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { Sprint } from "@locusai/shared";
2
+ import { LogFn } from "../ai/factory.js";
3
+ import type { AiRunner } from "../ai/runner.js";
4
+ export interface ReviewServiceDeps {
5
+ aiRunner: AiRunner;
6
+ projectPath: string;
7
+ log: LogFn;
8
+ }
9
+ /**
10
+ * Reviews staged git changes and produces a markdown report.
11
+ */
12
+ export declare class ReviewService {
13
+ private deps;
14
+ constructor(deps: ReviewServiceDeps);
15
+ /**
16
+ * Stages all changes and runs an AI review on the diff.
17
+ * Returns a markdown review report, or null if there are no changes.
18
+ */
19
+ reviewStagedChanges(sprint: Sprint | null): Promise<string | null>;
20
+ }
21
+ //# sourceMappingURL=review-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-service.d.ts","sourceRoot":"","sources":["../../src/agent/review-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,KAAK,CAAC;CACZ;AAED;;GAEG;AACH,qBAAa,aAAa;IACZ,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,iBAAiB;IAE3C;;;OAGG;IACG,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAkEzE"}
@@ -7,7 +7,7 @@ export interface TaskExecutorDeps {
7
7
  log: LogFn;
8
8
  }
9
9
  /**
10
- * Handles task execution with two-phase approach (planning + execution)
10
+ * Handles direct task execution (single-pass, no separate planning phase)
11
11
  */
12
12
  export declare class TaskExecutor {
13
13
  private deps;
@@ -1 +1 @@
1
- {"version":3,"file":"task-executor.d.ts","sourceRoot":"","sources":["../../src/agent/task-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGhD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,KAAK,CAAC;CACZ;AAED;;GAEG;AACH,qBAAa,YAAY;IAGX,OAAO,CAAC,IAAI;IAFxB,OAAO,CAAC,aAAa,CAAgB;gBAEjB,IAAI,EAAE,gBAAgB;IAIpC,OAAO,CACX,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CA2ClD"}
1
+ {"version":3,"file":"task-executor.d.ts","sourceRoot":"","sources":["../../src/agent/task-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGhD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,KAAK,CAAC;CACZ;AAED;;GAEG;AACH,qBAAa,YAAY;IAGX,OAAO,CAAC,IAAI;IAFxB,OAAO,CAAC,aAAa,CAAgB;gBAEjB,IAAI,EAAE,gBAAgB;IAIpC,OAAO,CACX,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAyBlD"}
@@ -20,16 +20,15 @@ export declare class AgentWorker {
20
20
  private indexerService;
21
21
  private documentFetcher;
22
22
  private taskExecutor;
23
- private consecutiveEmpty;
24
- private maxEmpty;
23
+ private reviewService;
25
24
  private maxTasks;
26
25
  private tasksCompleted;
27
- private pollInterval;
28
26
  constructor(config: WorkerConfig);
29
27
  log(message: string, level?: "info" | "success" | "warn" | "error"): void;
30
28
  private getActiveSprint;
31
29
  private getNextTask;
32
30
  private executeTask;
31
+ private runStagedChangesReview;
33
32
  run(): Promise<void>;
34
33
  }
35
34
  //# sourceMappingURL=worker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/agent/worker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,iBAAiB,CAAC;AAsB5D,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,UAAU,CAAC;CACvB;AAED;;;GAGG;AACH,qBAAa,WAAW;IAgBV,OAAO,CAAC,MAAM;IAf1B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAW;IAG3B,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,YAAY,CAAe;IAGnC,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,YAAY,CAAU;gBAEV,MAAM,EAAE,YAAY;IAiDxC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAgB;YAe5D,eAAe;YAcf,WAAW;YAiBX,WAAW;IA6BnB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAqF3B"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/agent/worker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,iBAAiB,CAAC;AAuB5D,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,UAAU,CAAC;CACvB;AAED;;;GAGG;AACH,qBAAa,WAAW;IAcV,OAAO,CAAC,MAAM;IAb1B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAW;IAG3B,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,aAAa,CAAgB;IAGrC,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,cAAc,CAAK;gBAEP,MAAM,EAAE,YAAY;IAuDxC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAgB;YAe5D,eAAe;YAcf,WAAW;YAiBX,WAAW;YA6BX,sBAAsB;IAoC9B,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA2D3B"}
@@ -512,6 +512,8 @@ __export(exports_worker, {
512
512
  AgentWorker: () => AgentWorker
513
513
  });
514
514
  module.exports = __toCommonJS(exports_worker);
515
+ var import_node_fs5 = require("node:fs");
516
+ var import_node_path7 = require("node:path");
515
517
 
516
518
  // src/core/config.ts
517
519
  var import_node_path = require("node:path");
@@ -531,14 +533,22 @@ var LOCUS_CONFIG = {
531
533
  artifactsDir: "artifacts",
532
534
  documentsDir: "documents",
533
535
  agentSkillsDir: ".agent/skills",
534
- sessionsDir: "sessions"
536
+ sessionsDir: "sessions",
537
+ reviewsDir: "reviews",
538
+ plansDir: "plans"
535
539
  };
536
540
  var LOCUS_GITIGNORE_PATTERNS = [
537
541
  "# Locus AI - Session data (user-specific, can grow large)",
538
542
  ".locus/sessions/",
539
543
  "",
540
544
  "# Locus AI - Artifacts (local-only, user-specific)",
541
- ".locus/artifacts/"
545
+ ".locus/artifacts/",
546
+ "",
547
+ "# Locus AI - Review reports (generated per sprint)",
548
+ ".locus/reviews/",
549
+ "",
550
+ "# Locus AI - Plans (generated per task)",
551
+ ".locus/plans/"
542
552
  ];
543
553
  function getLocusPath(projectPath, fileName) {
544
554
  if (fileName === "contextFile") {
@@ -633,7 +643,7 @@ class ClaudeRunner {
633
643
  setEventEmitter(emitter) {
634
644
  this.eventEmitter = emitter;
635
645
  }
636
- async run(prompt, _isPlanning = false) {
646
+ async run(prompt) {
637
647
  const maxRetries = 3;
638
648
  let lastError = null;
639
649
  for (let attempt = 1;attempt <= maxRetries; attempt++) {
@@ -1479,7 +1489,7 @@ File tree:
1479
1489
  ${tree}
1480
1490
 
1481
1491
  Return ONLY valid JSON, no markdown formatting.`;
1482
- const response = await this.deps.aiRunner.run(prompt, true);
1492
+ const response = await this.deps.aiRunner.run(prompt);
1483
1493
  const jsonMatch = response.match(/\{[\s\S]*\}/);
1484
1494
  if (jsonMatch) {
1485
1495
  return JSON.parse(jsonMatch[0]);
@@ -1542,6 +1552,66 @@ class DocumentFetcher {
1542
1552
  }
1543
1553
  }
1544
1554
 
1555
+ // src/agent/review-service.ts
1556
+ var import_node_child_process3 = require("node:child_process");
1557
+
1558
+ class ReviewService {
1559
+ deps;
1560
+ constructor(deps) {
1561
+ this.deps = deps;
1562
+ }
1563
+ async reviewStagedChanges(sprint) {
1564
+ const { projectPath, log } = this.deps;
1565
+ try {
1566
+ import_node_child_process3.execSync("git add -A", { cwd: projectPath, stdio: "pipe" });
1567
+ log("Staged all changes for review.", "info");
1568
+ } catch (err) {
1569
+ log(`Failed to stage changes: ${err instanceof Error ? err.message : String(err)}`, "error");
1570
+ return null;
1571
+ }
1572
+ let diff;
1573
+ try {
1574
+ diff = import_node_child_process3.execSync("git diff --cached --stat && echo '---' && git diff --cached", {
1575
+ cwd: projectPath,
1576
+ maxBuffer: 10 * 1024 * 1024
1577
+ }).toString();
1578
+ } catch (err) {
1579
+ log(`Failed to get staged diff: ${err instanceof Error ? err.message : String(err)}`, "error");
1580
+ return null;
1581
+ }
1582
+ if (!diff.trim()) {
1583
+ return null;
1584
+ }
1585
+ const sprintInfo = sprint ? `Sprint: ${sprint.name} (${sprint.id})` : "No active sprint";
1586
+ const reviewPrompt = `# Code Review Request
1587
+
1588
+ ## Context
1589
+ ${sprintInfo}
1590
+ Date: ${new Date().toISOString()}
1591
+
1592
+ ## Staged Changes (git diff)
1593
+ \`\`\`diff
1594
+ ${diff}
1595
+ \`\`\`
1596
+
1597
+ ## Instructions
1598
+ You are reviewing the staged changes at the end of a sprint. Produce a thorough markdown review report with the following sections:
1599
+
1600
+ 1. **Summary** — Brief overview of what changed and why.
1601
+ 2. **Files Changed** — List each file with a short description of changes.
1602
+ 3. **Code Quality** — Note any code quality concerns (naming, structure, complexity).
1603
+ 4. **Potential Issues** — Identify bugs, security issues, edge cases, or regressions.
1604
+ 5. **Recommendations** — Actionable suggestions for improvement.
1605
+ 6. **Overall Assessment** — A short verdict (e.g., "Looks good", "Needs attention", "Critical issues found").
1606
+
1607
+ Keep the review concise but thorough. Focus on substance over style.
1608
+ Do NOT output <promise>COMPLETE</promise> — just output the review report as markdown.`;
1609
+ log("Running AI review on staged changes...", "info");
1610
+ const report = await this.deps.aiRunner.run(reviewPrompt);
1611
+ return report;
1612
+ }
1613
+ }
1614
+
1545
1615
  // src/core/prompt-builder.ts
1546
1616
  var import_node_fs4 = require("node:fs");
1547
1617
  var import_node_os2 = require("node:os");
@@ -1907,29 +1977,8 @@ class TaskExecutor {
1907
1977
  taskContext: context
1908
1978
  });
1909
1979
  try {
1910
- let plan = null;
1911
- this.deps.log("Phase 1: Planning (CLI)...", "info");
1912
- const planningPrompt = `${basePrompt}
1913
-
1914
- ## Phase 1: Planning
1915
- Analyze and create a detailed plan for THIS SPECIFIC TASK. Do NOT execute changes yet.`;
1916
- plan = await this.deps.aiRunner.run(planningPrompt, true);
1917
1980
  this.deps.log("Starting Execution...", "info");
1918
- let executionPrompt = basePrompt;
1919
- if (plan != null) {
1920
- executionPrompt += `
1921
-
1922
- ## Phase 2: Execution
1923
- Based on the plan, execute the task:
1924
-
1925
- ${plan}`;
1926
- } else {
1927
- executionPrompt += `
1928
-
1929
- ## Execution
1930
- Execute the task directly.`;
1931
- }
1932
- executionPrompt += `
1981
+ const executionPrompt = `${basePrompt}
1933
1982
 
1934
1983
  When finished, output: <promise>COMPLETE</promise>`;
1935
1984
  const output = await this.deps.aiRunner.run(executionPrompt);
@@ -1963,11 +2012,9 @@ class AgentWorker {
1963
2012
  indexerService;
1964
2013
  documentFetcher;
1965
2014
  taskExecutor;
1966
- consecutiveEmpty = 0;
1967
- maxEmpty = 60;
2015
+ reviewService;
1968
2016
  maxTasks = 50;
1969
2017
  tasksCompleted = 0;
1970
- pollInterval = 1e4;
1971
2018
  constructor(config) {
1972
2019
  this.config = config;
1973
2020
  const projectPath = config.projectPath || process.cwd();
@@ -2004,6 +2051,11 @@ class AgentWorker {
2004
2051
  projectPath,
2005
2052
  log
2006
2053
  });
2054
+ this.reviewService = new ReviewService({
2055
+ aiRunner: this.aiRunner,
2056
+ projectPath,
2057
+ log
2058
+ });
2007
2059
  const providerLabel = provider === "codex" ? "Codex" : "Claude";
2008
2060
  this.log(`Using ${providerLabel} CLI for all phases`, "info");
2009
2061
  }
@@ -2049,33 +2101,42 @@ class AgentWorker {
2049
2101
  await this.indexerService.reindex();
2050
2102
  return result;
2051
2103
  }
2104
+ async runStagedChangesReview(sprint) {
2105
+ try {
2106
+ const report = await this.reviewService.reviewStagedChanges(sprint);
2107
+ if (report) {
2108
+ const reviewsDir = import_node_path7.join(this.config.projectPath, LOCUS_CONFIG.dir, "reviews");
2109
+ if (!import_node_fs5.existsSync(reviewsDir)) {
2110
+ import_node_fs5.mkdirSync(reviewsDir, { recursive: true });
2111
+ }
2112
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
2113
+ const sprintSlug = sprint?.name ? sprint.name.toLowerCase().replace(/\s+/g, "-").slice(0, 40) : "no-sprint";
2114
+ const fileName = `review-${sprintSlug}-${timestamp}.md`;
2115
+ const filePath = import_node_path7.join(reviewsDir, fileName);
2116
+ import_node_fs5.writeFileSync(filePath, report);
2117
+ this.log(`Review report saved to .locus/reviews/${fileName}`, "success");
2118
+ } else {
2119
+ this.log("No staged changes to review.", "info");
2120
+ }
2121
+ } catch (err) {
2122
+ this.log(`Review failed: ${err instanceof Error ? err.message : String(err)}`, "error");
2123
+ }
2124
+ }
2052
2125
  async run() {
2053
2126
  this.log(`Agent started in ${this.config.projectPath || process.cwd()}`, "success");
2054
2127
  const sprint = await this.getActiveSprint();
2055
2128
  if (sprint) {
2056
- this.log(`Active sprint found: ${sprint.name}. Ensuring plan is up to date...`, "info");
2057
- try {
2058
- await this.client.sprints.triggerAIPlanning(sprint.id, this.config.workspaceId);
2059
- this.log(`Sprint plan sync checked on server.`, "success");
2060
- } catch (err) {
2061
- this.log(`Sprint planning sync failed (non-critical): ${err instanceof Error ? err.message : String(err)}`, "warn");
2062
- }
2129
+ this.log(`Active sprint found: ${sprint.name}`, "info");
2063
2130
  } else {
2064
- this.log("No active sprint found for planning.", "warn");
2131
+ this.log("No active sprint found.", "warn");
2065
2132
  }
2066
- while (this.tasksCompleted < this.maxTasks && this.consecutiveEmpty < this.maxEmpty) {
2133
+ while (this.tasksCompleted < this.maxTasks) {
2067
2134
  const task = await this.getNextTask();
2068
2135
  if (!task) {
2069
- if (this.consecutiveEmpty === 0) {
2070
- this.log("Queue empty, waiting for tasks...", "info");
2071
- }
2072
- this.consecutiveEmpty++;
2073
- if (this.consecutiveEmpty >= this.maxEmpty)
2074
- break;
2075
- await new Promise((r) => setTimeout(r, this.pollInterval));
2076
- continue;
2136
+ this.log("No tasks remaining. Running review on staged changes...", "info");
2137
+ await this.runStagedChangesReview(sprint);
2138
+ break;
2077
2139
  }
2078
- this.consecutiveEmpty = 0;
2079
2140
  this.log(`Claimed: ${task.title}`, "success");
2080
2141
  const result = await this.executeTask(task);
2081
2142
  try {
@@ -14,7 +14,7 @@ export declare class ClaudeRunner implements AiRunner {
14
14
  * Set an event emitter to receive execution events.
15
15
  */
16
16
  setEventEmitter(emitter: ExecEventEmitter): void;
17
- run(prompt: string, _isPlanning?: boolean): Promise<string>;
17
+ run(prompt: string): Promise<string>;
18
18
  runStream(prompt: string): AsyncGenerator<StreamChunk, void, unknown>;
19
19
  /**
20
20
  * Emit an event corresponding to a stream chunk.
@@ -1 +1 @@
1
- {"version":3,"file":"claude-runner.d.ts","sourceRoot":"","sources":["../../src/ai/claude-runner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAEhE,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAgC5C,qBAAa,YAAa,YAAW,QAAQ;IAQzC,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,GAAG,CAAC;IARd,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAC,CAAmB;IACxC,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,WAAW,CAA+C;gBAGhE,WAAW,EAAE,MAAM,EACX,KAAK,GAAE,MAAuC,EAC9C,GAAG,CAAC,EAAE,KAAK,YAAA;IAKrB;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAI1C,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAyBxD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC;IAqK5E;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiCzB,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,kBAAkB;IAwE1B,OAAO,CAAC,UAAU;IAkFlB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,oBAAoB;CAO7B"}
1
+ {"version":3,"file":"claude-runner.d.ts","sourceRoot":"","sources":["../../src/ai/claude-runner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAEhE,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAgC5C,qBAAa,YAAa,YAAW,QAAQ;IAQzC,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,GAAG,CAAC;IARd,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAC,CAAmB;IACxC,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,WAAW,CAA+C;gBAGhE,WAAW,EAAE,MAAM,EACX,KAAK,GAAE,MAAuC,EAC9C,GAAG,CAAC,EAAE,KAAK,YAAA;IAKrB;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAI1C,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyBnC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC;IAqK5E;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiCzB,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,kBAAkB;IAwE1B,OAAO,CAAC,UAAU;IAkFlB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,oBAAoB;CAO7B"}
@@ -2,7 +2,7 @@ import type { Provider } from "../core/config.js";
2
2
  import type { ExecEventEmitter } from "../exec/event-emitter.js";
3
3
  import type { StreamChunk } from "../exec/types.js";
4
4
  export interface AiRunner {
5
- run(prompt: string, isPlanning?: boolean): Promise<string>;
5
+ run(prompt: string): Promise<string>;
6
6
  runStream(prompt: string): AsyncGenerator<StreamChunk, void, unknown>;
7
7
  /**
8
8
  * Set an event emitter to receive execution events.
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/ai/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACtE;;OAEG;IACH,eAAe,CAAC,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACnD;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/ai/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACtE;;OAEG;IACH,eAAe,CAAC,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACnD;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC"}
@@ -13,8 +13,10 @@ export declare const LOCUS_CONFIG: {
13
13
  documentsDir: string;
14
14
  agentSkillsDir: string;
15
15
  sessionsDir: string;
16
+ reviewsDir: string;
17
+ plansDir: string;
16
18
  };
17
- export declare const LOCUS_GITIGNORE_PATTERNS: readonly ["# Locus AI - Session data (user-specific, can grow large)", ".locus/sessions/", "", "# Locus AI - Artifacts (local-only, user-specific)", ".locus/artifacts/"];
19
+ export declare const LOCUS_GITIGNORE_PATTERNS: readonly ["# Locus AI - Session data (user-specific, can grow large)", ".locus/sessions/", "", "# Locus AI - Artifacts (local-only, user-specific)", ".locus/artifacts/", "", "# Locus AI - Review reports (generated per sprint)", ".locus/reviews/", "", "# Locus AI - Plans (generated per task)", ".locus/plans/"];
18
20
  export declare function getLocusPath(projectPath: string, fileName: keyof typeof LOCUS_CONFIG): string;
19
21
  /**
20
22
  * Gets the artifacts directory path for a specific agent.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ;;;CAGX,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC;AAEhE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAGlD,CAAC;AAEF,eAAO,MAAM,YAAY;;;;;;;;;CASxB,CAAC;AAIF,eAAO,MAAM,wBAAwB,2KAM3B,CAAC;AAEX,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,OAAO,YAAY,GAClC,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,MAAM,CASR"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ;;;CAGX,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC;AAEhE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAGlD,CAAC;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;CAWxB,CAAC;AAIF,eAAO,MAAM,wBAAwB,wTAY3B,CAAC;AAEX,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,OAAO,YAAY,GAClC,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,MAAM,CASR"}
@@ -512,6 +512,8 @@ __export(exports_worker, {
512
512
  AgentWorker: () => AgentWorker
513
513
  });
514
514
  module.exports = __toCommonJS(exports_worker);
515
+ var import_node_fs5 = require("node:fs");
516
+ var import_node_path7 = require("node:path");
515
517
 
516
518
  // src/core/config.ts
517
519
  var import_node_path = require("node:path");
@@ -531,14 +533,22 @@ var LOCUS_CONFIG = {
531
533
  artifactsDir: "artifacts",
532
534
  documentsDir: "documents",
533
535
  agentSkillsDir: ".agent/skills",
534
- sessionsDir: "sessions"
536
+ sessionsDir: "sessions",
537
+ reviewsDir: "reviews",
538
+ plansDir: "plans"
535
539
  };
536
540
  var LOCUS_GITIGNORE_PATTERNS = [
537
541
  "# Locus AI - Session data (user-specific, can grow large)",
538
542
  ".locus/sessions/",
539
543
  "",
540
544
  "# Locus AI - Artifacts (local-only, user-specific)",
541
- ".locus/artifacts/"
545
+ ".locus/artifacts/",
546
+ "",
547
+ "# Locus AI - Review reports (generated per sprint)",
548
+ ".locus/reviews/",
549
+ "",
550
+ "# Locus AI - Plans (generated per task)",
551
+ ".locus/plans/"
542
552
  ];
543
553
  function getLocusPath(projectPath, fileName) {
544
554
  if (fileName === "contextFile") {
@@ -633,7 +643,7 @@ class ClaudeRunner {
633
643
  setEventEmitter(emitter) {
634
644
  this.eventEmitter = emitter;
635
645
  }
636
- async run(prompt, _isPlanning = false) {
646
+ async run(prompt) {
637
647
  const maxRetries = 3;
638
648
  let lastError = null;
639
649
  for (let attempt = 1;attempt <= maxRetries; attempt++) {
@@ -1479,7 +1489,7 @@ File tree:
1479
1489
  ${tree}
1480
1490
 
1481
1491
  Return ONLY valid JSON, no markdown formatting.`;
1482
- const response = await this.deps.aiRunner.run(prompt, true);
1492
+ const response = await this.deps.aiRunner.run(prompt);
1483
1493
  const jsonMatch = response.match(/\{[\s\S]*\}/);
1484
1494
  if (jsonMatch) {
1485
1495
  return JSON.parse(jsonMatch[0]);
@@ -1542,6 +1552,66 @@ class DocumentFetcher {
1542
1552
  }
1543
1553
  }
1544
1554
 
1555
+ // src/agent/review-service.ts
1556
+ var import_node_child_process3 = require("node:child_process");
1557
+
1558
+ class ReviewService {
1559
+ deps;
1560
+ constructor(deps) {
1561
+ this.deps = deps;
1562
+ }
1563
+ async reviewStagedChanges(sprint) {
1564
+ const { projectPath, log } = this.deps;
1565
+ try {
1566
+ import_node_child_process3.execSync("git add -A", { cwd: projectPath, stdio: "pipe" });
1567
+ log("Staged all changes for review.", "info");
1568
+ } catch (err) {
1569
+ log(`Failed to stage changes: ${err instanceof Error ? err.message : String(err)}`, "error");
1570
+ return null;
1571
+ }
1572
+ let diff;
1573
+ try {
1574
+ diff = import_node_child_process3.execSync("git diff --cached --stat && echo '---' && git diff --cached", {
1575
+ cwd: projectPath,
1576
+ maxBuffer: 10 * 1024 * 1024
1577
+ }).toString();
1578
+ } catch (err) {
1579
+ log(`Failed to get staged diff: ${err instanceof Error ? err.message : String(err)}`, "error");
1580
+ return null;
1581
+ }
1582
+ if (!diff.trim()) {
1583
+ return null;
1584
+ }
1585
+ const sprintInfo = sprint ? `Sprint: ${sprint.name} (${sprint.id})` : "No active sprint";
1586
+ const reviewPrompt = `# Code Review Request
1587
+
1588
+ ## Context
1589
+ ${sprintInfo}
1590
+ Date: ${new Date().toISOString()}
1591
+
1592
+ ## Staged Changes (git diff)
1593
+ \`\`\`diff
1594
+ ${diff}
1595
+ \`\`\`
1596
+
1597
+ ## Instructions
1598
+ You are reviewing the staged changes at the end of a sprint. Produce a thorough markdown review report with the following sections:
1599
+
1600
+ 1. **Summary** — Brief overview of what changed and why.
1601
+ 2. **Files Changed** — List each file with a short description of changes.
1602
+ 3. **Code Quality** — Note any code quality concerns (naming, structure, complexity).
1603
+ 4. **Potential Issues** — Identify bugs, security issues, edge cases, or regressions.
1604
+ 5. **Recommendations** — Actionable suggestions for improvement.
1605
+ 6. **Overall Assessment** — A short verdict (e.g., "Looks good", "Needs attention", "Critical issues found").
1606
+
1607
+ Keep the review concise but thorough. Focus on substance over style.
1608
+ Do NOT output <promise>COMPLETE</promise> — just output the review report as markdown.`;
1609
+ log("Running AI review on staged changes...", "info");
1610
+ const report = await this.deps.aiRunner.run(reviewPrompt);
1611
+ return report;
1612
+ }
1613
+ }
1614
+
1545
1615
  // src/core/prompt-builder.ts
1546
1616
  var import_node_fs4 = require("node:fs");
1547
1617
  var import_node_os2 = require("node:os");
@@ -1907,29 +1977,8 @@ class TaskExecutor {
1907
1977
  taskContext: context
1908
1978
  });
1909
1979
  try {
1910
- let plan = null;
1911
- this.deps.log("Phase 1: Planning (CLI)...", "info");
1912
- const planningPrompt = `${basePrompt}
1913
-
1914
- ## Phase 1: Planning
1915
- Analyze and create a detailed plan for THIS SPECIFIC TASK. Do NOT execute changes yet.`;
1916
- plan = await this.deps.aiRunner.run(planningPrompt, true);
1917
1980
  this.deps.log("Starting Execution...", "info");
1918
- let executionPrompt = basePrompt;
1919
- if (plan != null) {
1920
- executionPrompt += `
1921
-
1922
- ## Phase 2: Execution
1923
- Based on the plan, execute the task:
1924
-
1925
- ${plan}`;
1926
- } else {
1927
- executionPrompt += `
1928
-
1929
- ## Execution
1930
- Execute the task directly.`;
1931
- }
1932
- executionPrompt += `
1981
+ const executionPrompt = `${basePrompt}
1933
1982
 
1934
1983
  When finished, output: <promise>COMPLETE</promise>`;
1935
1984
  const output = await this.deps.aiRunner.run(executionPrompt);
@@ -1963,11 +2012,9 @@ class AgentWorker {
1963
2012
  indexerService;
1964
2013
  documentFetcher;
1965
2014
  taskExecutor;
1966
- consecutiveEmpty = 0;
1967
- maxEmpty = 60;
2015
+ reviewService;
1968
2016
  maxTasks = 50;
1969
2017
  tasksCompleted = 0;
1970
- pollInterval = 1e4;
1971
2018
  constructor(config) {
1972
2019
  this.config = config;
1973
2020
  const projectPath = config.projectPath || process.cwd();
@@ -2004,6 +2051,11 @@ class AgentWorker {
2004
2051
  projectPath,
2005
2052
  log
2006
2053
  });
2054
+ this.reviewService = new ReviewService({
2055
+ aiRunner: this.aiRunner,
2056
+ projectPath,
2057
+ log
2058
+ });
2007
2059
  const providerLabel = provider === "codex" ? "Codex" : "Claude";
2008
2060
  this.log(`Using ${providerLabel} CLI for all phases`, "info");
2009
2061
  }
@@ -2049,33 +2101,42 @@ class AgentWorker {
2049
2101
  await this.indexerService.reindex();
2050
2102
  return result;
2051
2103
  }
2104
+ async runStagedChangesReview(sprint) {
2105
+ try {
2106
+ const report = await this.reviewService.reviewStagedChanges(sprint);
2107
+ if (report) {
2108
+ const reviewsDir = import_node_path7.join(this.config.projectPath, LOCUS_CONFIG.dir, "reviews");
2109
+ if (!import_node_fs5.existsSync(reviewsDir)) {
2110
+ import_node_fs5.mkdirSync(reviewsDir, { recursive: true });
2111
+ }
2112
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
2113
+ const sprintSlug = sprint?.name ? sprint.name.toLowerCase().replace(/\s+/g, "-").slice(0, 40) : "no-sprint";
2114
+ const fileName = `review-${sprintSlug}-${timestamp}.md`;
2115
+ const filePath = import_node_path7.join(reviewsDir, fileName);
2116
+ import_node_fs5.writeFileSync(filePath, report);
2117
+ this.log(`Review report saved to .locus/reviews/${fileName}`, "success");
2118
+ } else {
2119
+ this.log("No staged changes to review.", "info");
2120
+ }
2121
+ } catch (err) {
2122
+ this.log(`Review failed: ${err instanceof Error ? err.message : String(err)}`, "error");
2123
+ }
2124
+ }
2052
2125
  async run() {
2053
2126
  this.log(`Agent started in ${this.config.projectPath || process.cwd()}`, "success");
2054
2127
  const sprint = await this.getActiveSprint();
2055
2128
  if (sprint) {
2056
- this.log(`Active sprint found: ${sprint.name}. Ensuring plan is up to date...`, "info");
2057
- try {
2058
- await this.client.sprints.triggerAIPlanning(sprint.id, this.config.workspaceId);
2059
- this.log(`Sprint plan sync checked on server.`, "success");
2060
- } catch (err) {
2061
- this.log(`Sprint planning sync failed (non-critical): ${err instanceof Error ? err.message : String(err)}`, "warn");
2062
- }
2129
+ this.log(`Active sprint found: ${sprint.name}`, "info");
2063
2130
  } else {
2064
- this.log("No active sprint found for planning.", "warn");
2131
+ this.log("No active sprint found.", "warn");
2065
2132
  }
2066
- while (this.tasksCompleted < this.maxTasks && this.consecutiveEmpty < this.maxEmpty) {
2133
+ while (this.tasksCompleted < this.maxTasks) {
2067
2134
  const task = await this.getNextTask();
2068
2135
  if (!task) {
2069
- if (this.consecutiveEmpty === 0) {
2070
- this.log("Queue empty, waiting for tasks...", "info");
2071
- }
2072
- this.consecutiveEmpty++;
2073
- if (this.consecutiveEmpty >= this.maxEmpty)
2074
- break;
2075
- await new Promise((r) => setTimeout(r, this.pollInterval));
2076
- continue;
2136
+ this.log("No tasks remaining. Running review on staged changes...", "info");
2137
+ await this.runStagedChangesReview(sprint);
2138
+ break;
2077
2139
  }
2078
- this.consecutiveEmpty = 0;
2079
2140
  this.log(`Claimed: ${task.title}`, "success");
2080
2141
  const result = await this.executeTask(task);
2081
2142
  try {
@@ -2157,6 +2218,7 @@ __export(exports_index_node, {
2157
2218
  TasksModule: () => TasksModule,
2158
2219
  TaskExecutor: () => TaskExecutor,
2159
2220
  SprintsModule: () => SprintsModule,
2221
+ ReviewService: () => ReviewService,
2160
2222
  PromptBuilder: () => PromptBuilder,
2161
2223
  PROVIDER: () => PROVIDER,
2162
2224
  OrganizationsModule: () => OrganizationsModule,
@@ -2598,8 +2660,8 @@ class ExecEventEmitter {
2598
2660
  }
2599
2661
  }
2600
2662
  // src/exec/history-manager.ts
2601
- var import_node_fs5 = require("node:fs");
2602
- var import_node_path7 = require("node:path");
2663
+ var import_node_fs6 = require("node:fs");
2664
+ var import_node_path8 = require("node:path");
2603
2665
  var DEFAULT_MAX_SESSIONS = 30;
2604
2666
  function generateSessionId2() {
2605
2667
  const timestamp = Date.now().toString(36);
@@ -2611,30 +2673,30 @@ class HistoryManager {
2611
2673
  historyDir;
2612
2674
  maxSessions;
2613
2675
  constructor(projectPath, options) {
2614
- this.historyDir = options?.historyDir ?? import_node_path7.join(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG.sessionsDir);
2676
+ this.historyDir = options?.historyDir ?? import_node_path8.join(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG.sessionsDir);
2615
2677
  this.maxSessions = options?.maxSessions ?? DEFAULT_MAX_SESSIONS;
2616
2678
  this.ensureHistoryDir();
2617
2679
  }
2618
2680
  ensureHistoryDir() {
2619
- if (!import_node_fs5.existsSync(this.historyDir)) {
2620
- import_node_fs5.mkdirSync(this.historyDir, { recursive: true });
2681
+ if (!import_node_fs6.existsSync(this.historyDir)) {
2682
+ import_node_fs6.mkdirSync(this.historyDir, { recursive: true });
2621
2683
  }
2622
2684
  }
2623
2685
  getSessionPath(sessionId) {
2624
- return import_node_path7.join(this.historyDir, `${sessionId}.json`);
2686
+ return import_node_path8.join(this.historyDir, `${sessionId}.json`);
2625
2687
  }
2626
2688
  saveSession(session) {
2627
2689
  const filePath = this.getSessionPath(session.id);
2628
2690
  session.updatedAt = Date.now();
2629
- import_node_fs5.writeFileSync(filePath, JSON.stringify(session, null, 2), "utf-8");
2691
+ import_node_fs6.writeFileSync(filePath, JSON.stringify(session, null, 2), "utf-8");
2630
2692
  }
2631
2693
  loadSession(sessionId) {
2632
2694
  const filePath = this.getSessionPath(sessionId);
2633
- if (!import_node_fs5.existsSync(filePath)) {
2695
+ if (!import_node_fs6.existsSync(filePath)) {
2634
2696
  return null;
2635
2697
  }
2636
2698
  try {
2637
- const content = import_node_fs5.readFileSync(filePath, "utf-8");
2699
+ const content = import_node_fs6.readFileSync(filePath, "utf-8");
2638
2700
  return JSON.parse(content);
2639
2701
  } catch {
2640
2702
  return null;
@@ -2642,18 +2704,18 @@ class HistoryManager {
2642
2704
  }
2643
2705
  deleteSession(sessionId) {
2644
2706
  const filePath = this.getSessionPath(sessionId);
2645
- if (!import_node_fs5.existsSync(filePath)) {
2707
+ if (!import_node_fs6.existsSync(filePath)) {
2646
2708
  return false;
2647
2709
  }
2648
2710
  try {
2649
- import_node_fs5.rmSync(filePath);
2711
+ import_node_fs6.rmSync(filePath);
2650
2712
  return true;
2651
2713
  } catch {
2652
2714
  return false;
2653
2715
  }
2654
2716
  }
2655
2717
  listSessions(options) {
2656
- const files = import_node_fs5.readdirSync(this.historyDir);
2718
+ const files = import_node_fs6.readdirSync(this.historyDir);
2657
2719
  let sessions = [];
2658
2720
  for (const file of files) {
2659
2721
  if (file.endsWith(".json")) {
@@ -2726,11 +2788,11 @@ class HistoryManager {
2726
2788
  return deleted;
2727
2789
  }
2728
2790
  getSessionCount() {
2729
- const files = import_node_fs5.readdirSync(this.historyDir);
2791
+ const files = import_node_fs6.readdirSync(this.historyDir);
2730
2792
  return files.filter((f) => f.endsWith(".json")).length;
2731
2793
  }
2732
2794
  sessionExists(sessionId) {
2733
- return import_node_fs5.existsSync(this.getSessionPath(sessionId));
2795
+ return import_node_fs6.existsSync(this.getSessionPath(sessionId));
2734
2796
  }
2735
2797
  findSessionByPartialId(partialId) {
2736
2798
  const sessions = this.listSessions();
@@ -2744,12 +2806,12 @@ class HistoryManager {
2744
2806
  return this.historyDir;
2745
2807
  }
2746
2808
  clearAllSessions() {
2747
- const files = import_node_fs5.readdirSync(this.historyDir);
2809
+ const files = import_node_fs6.readdirSync(this.historyDir);
2748
2810
  let deleted = 0;
2749
2811
  for (const file of files) {
2750
2812
  if (file.endsWith(".json")) {
2751
2813
  try {
2752
- import_node_fs5.rmSync(import_node_path7.join(this.historyDir, file));
2814
+ import_node_fs6.rmSync(import_node_path8.join(this.historyDir, file));
2753
2815
  deleted++;
2754
2816
  } catch {}
2755
2817
  }
@@ -3014,9 +3076,9 @@ ${currentPrompt}`);
3014
3076
  }
3015
3077
  }
3016
3078
  // src/orchestrator.ts
3017
- var import_node_child_process3 = require("node:child_process");
3018
- var import_node_fs6 = require("node:fs");
3019
- var import_node_path8 = require("node:path");
3079
+ var import_node_child_process4 = require("node:child_process");
3080
+ var import_node_fs7 = require("node:fs");
3081
+ var import_node_path9 = require("node:path");
3020
3082
  var import_node_url = require("node:url");
3021
3083
  var import_shared3 = require("@locusai/shared");
3022
3084
  var import_events4 = require("events");
@@ -3112,9 +3174,9 @@ ${c.success("✅ Orchestrator finished")}`);
3112
3174
  `);
3113
3175
  const potentialPaths = [];
3114
3176
  const currentModulePath = import_node_url.fileURLToPath("file:///home/runner/work/locusai/locusai/packages/sdk/src/orchestrator.ts");
3115
- const currentModuleDir = import_node_path8.dirname(currentModulePath);
3116
- potentialPaths.push(import_node_path8.join(currentModuleDir, "agent", "worker.js"), import_node_path8.join(currentModuleDir, "worker.js"), import_node_path8.join(currentModuleDir, "agent", "worker.ts"));
3117
- const workerPath = potentialPaths.find((p) => import_node_fs6.existsSync(p));
3177
+ const currentModuleDir = import_node_path9.dirname(currentModulePath);
3178
+ potentialPaths.push(import_node_path9.join(currentModuleDir, "agent", "worker.js"), import_node_path9.join(currentModuleDir, "worker.js"), import_node_path9.join(currentModuleDir, "agent", "worker.ts"));
3179
+ const workerPath = potentialPaths.find((p) => import_node_fs7.existsSync(p));
3118
3180
  if (!workerPath) {
3119
3181
  throw new Error(`Worker file not found. Checked: ${potentialPaths.join(", ")}. ` + `Make sure the SDK is properly built and installed.`);
3120
3182
  }
@@ -3139,7 +3201,7 @@ ${c.success("✅ Orchestrator finished")}`);
3139
3201
  if (this.resolvedSprintId) {
3140
3202
  workerArgs.push("--sprint-id", this.resolvedSprintId);
3141
3203
  }
3142
- const agentProcess = import_node_child_process3.spawn(process.execPath, [workerPath, ...workerArgs], {
3204
+ const agentProcess = import_node_child_process4.spawn(process.execPath, [workerPath, ...workerArgs], {
3143
3205
  stdio: ["pipe", "pipe", "pipe"],
3144
3206
  env: {
3145
3207
  ...process.env,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/sdk",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -30,7 +30,7 @@
30
30
  "clean": "rm -rf node_modules"
31
31
  },
32
32
  "dependencies": {
33
- "@locusai/shared": "^0.8.0",
33
+ "@locusai/shared": "^0.8.1",
34
34
  "axios": "^1.13.2",
35
35
  "events": "^3.3.0",
36
36
  "globby": "^14.0.2"