@locusai/sdk 0.4.6 → 0.4.10

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.
Files changed (58) hide show
  1. package/dist/agent/worker.js +1271 -239
  2. package/dist/index-node.js +1601 -20
  3. package/dist/index.js +429 -121
  4. package/dist/orchestrator.d.ts.map +1 -1
  5. package/package.json +7 -19
  6. package/dist/agent/artifact-syncer.js +0 -77
  7. package/dist/agent/codebase-indexer-service.js +0 -55
  8. package/dist/agent/index.js +0 -5
  9. package/dist/agent/sprint-planner.js +0 -68
  10. package/dist/agent/task-executor.js +0 -60
  11. package/dist/ai/anthropic-client.js +0 -70
  12. package/dist/ai/claude-runner.js +0 -71
  13. package/dist/ai/index.js +0 -2
  14. package/dist/core/config.js +0 -15
  15. package/dist/core/index.js +0 -3
  16. package/dist/core/indexer.js +0 -113
  17. package/dist/core/prompt-builder.js +0 -83
  18. package/dist/events.js +0 -15
  19. package/dist/modules/auth.js +0 -23
  20. package/dist/modules/base.js +0 -8
  21. package/dist/modules/ci.js +0 -7
  22. package/dist/modules/docs.js +0 -38
  23. package/dist/modules/invitations.js +0 -22
  24. package/dist/modules/organizations.js +0 -39
  25. package/dist/modules/sprints.js +0 -34
  26. package/dist/modules/tasks.js +0 -56
  27. package/dist/modules/workspaces.js +0 -49
  28. package/dist/orchestrator.js +0 -356
  29. package/dist/utils/colors.js +0 -54
  30. package/dist/utils/retry.js +0 -37
  31. package/src/agent/artifact-syncer.ts +0 -111
  32. package/src/agent/codebase-indexer-service.ts +0 -71
  33. package/src/agent/index.ts +0 -5
  34. package/src/agent/sprint-planner.ts +0 -86
  35. package/src/agent/task-executor.ts +0 -85
  36. package/src/agent/worker.ts +0 -322
  37. package/src/ai/anthropic-client.ts +0 -93
  38. package/src/ai/claude-runner.ts +0 -86
  39. package/src/ai/index.ts +0 -2
  40. package/src/core/config.ts +0 -21
  41. package/src/core/index.ts +0 -3
  42. package/src/core/indexer.ts +0 -131
  43. package/src/core/prompt-builder.ts +0 -91
  44. package/src/events.ts +0 -35
  45. package/src/index-node.ts +0 -23
  46. package/src/index.ts +0 -159
  47. package/src/modules/auth.ts +0 -48
  48. package/src/modules/base.ts +0 -9
  49. package/src/modules/ci.ts +0 -12
  50. package/src/modules/docs.ts +0 -84
  51. package/src/modules/invitations.ts +0 -45
  52. package/src/modules/organizations.ts +0 -90
  53. package/src/modules/sprints.ts +0 -69
  54. package/src/modules/tasks.ts +0 -110
  55. package/src/modules/workspaces.ts +0 -94
  56. package/src/orchestrator.ts +0 -473
  57. package/src/utils/colors.ts +0 -63
  58. package/src/utils/retry.ts +0 -56
@@ -1,37 +0,0 @@
1
- import { isAxiosError } from "axios";
2
- export const DEFAULT_RETRY_OPTIONS = {
3
- maxRetries: 3,
4
- initialDelay: 1000,
5
- maxDelay: 5000,
6
- factor: 2,
7
- retryCondition: (error) => {
8
- // Retry on network errors or 5xx server errors
9
- if (isAxiosError(error)) {
10
- if (!error.response)
11
- return true; // Network error
12
- return error.response.status >= 500;
13
- }
14
- return true; // Retry on other unknown errors
15
- },
16
- };
17
- /**
18
- * Retries an async function with exponential backoff
19
- */
20
- export async function withRetry(fn, options = {}) {
21
- const config = { ...DEFAULT_RETRY_OPTIONS, ...options };
22
- let lastError;
23
- for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
24
- try {
25
- return await fn();
26
- }
27
- catch (error) {
28
- lastError = error;
29
- if (attempt === config.maxRetries || !config.retryCondition(error)) {
30
- throw error;
31
- }
32
- const delay = Math.min(config.initialDelay * Math.pow(config.factor, attempt), config.maxDelay);
33
- await new Promise((resolve) => setTimeout(resolve, delay));
34
- }
35
- }
36
- throw lastError;
37
- }
@@ -1,111 +0,0 @@
1
- import {
2
- existsSync,
3
- mkdirSync,
4
- readdirSync,
5
- readFileSync,
6
- statSync,
7
- } from "node:fs";
8
- import { join } from "node:path";
9
- import { getLocusPath } from "../core/config.js";
10
- import type { LocusClient } from "../index.js";
11
-
12
- export interface ArtifactSyncerDeps {
13
- client: LocusClient;
14
- workspaceId: string;
15
- projectPath: string;
16
- log: (message: string, level?: "info" | "success" | "warn" | "error") => void;
17
- }
18
-
19
- /**
20
- * Handles syncing local artifacts to the platform
21
- */
22
- export class ArtifactSyncer {
23
- constructor(private deps: ArtifactSyncerDeps) {}
24
-
25
- private async getOrCreateArtifactsGroup(): Promise<string> {
26
- try {
27
- const groups = await this.deps.client.docs.listGroups(
28
- this.deps.workspaceId
29
- );
30
- const artifactsGroup = groups.find((g) => g.name === "Artifacts");
31
-
32
- if (artifactsGroup) {
33
- return artifactsGroup.id;
34
- }
35
-
36
- // Create the Artifacts group
37
- const newGroup = await this.deps.client.docs.createGroup(
38
- this.deps.workspaceId,
39
- {
40
- name: "Artifacts",
41
- order: 999, // Place at the end
42
- }
43
- );
44
- this.deps.log(
45
- "Created 'Artifacts' group for agent-generated docs",
46
- "info"
47
- );
48
- return newGroup.id;
49
- } catch (error) {
50
- this.deps.log(`Failed to get/create Artifacts group: ${error}`, "error");
51
- throw error;
52
- }
53
- }
54
-
55
- async sync(): Promise<void> {
56
- const artifactsDir = getLocusPath(this.deps.projectPath, "artifactsDir");
57
- if (!existsSync(artifactsDir)) {
58
- mkdirSync(artifactsDir, { recursive: true });
59
- return;
60
- }
61
-
62
- try {
63
- const files = readdirSync(artifactsDir);
64
- if (files.length === 0) return;
65
-
66
- this.deps.log(`Syncing ${files.length} artifacts to server...`, "info");
67
-
68
- // Get or create the Artifacts group
69
- const artifactsGroupId = await this.getOrCreateArtifactsGroup();
70
-
71
- // Get existing docs to check for updates
72
- const existingDocs = await this.deps.client.docs.list(
73
- this.deps.workspaceId
74
- );
75
-
76
- for (const file of files) {
77
- const filePath = join(artifactsDir, file);
78
- if (statSync(filePath).isFile()) {
79
- const content = readFileSync(filePath, "utf-8");
80
- const title = file.replace(/\.md$/, "").trim();
81
- if (!title) continue;
82
-
83
- const existing = existingDocs.find((d) => d.title === title);
84
-
85
- if (existing) {
86
- if (
87
- existing.content !== content ||
88
- existing.groupId !== artifactsGroupId
89
- ) {
90
- await this.deps.client.docs.update(
91
- existing.id,
92
- this.deps.workspaceId,
93
- { content, groupId: artifactsGroupId }
94
- );
95
- this.deps.log(`Updated artifact: ${file}`, "success");
96
- }
97
- } else {
98
- await this.deps.client.docs.create(this.deps.workspaceId, {
99
- title,
100
- content,
101
- groupId: artifactsGroupId,
102
- });
103
- this.deps.log(`Created artifact: ${file}`, "success");
104
- }
105
- }
106
- }
107
- } catch (error) {
108
- this.deps.log(`Failed to sync artifacts: ${error}`, "error");
109
- }
110
- }
111
- }
@@ -1,71 +0,0 @@
1
- import type { AnthropicClient } from "../ai/anthropic-client.js";
2
- import type { ClaudeRunner } from "../ai/claude-runner.js";
3
- import { CodebaseIndexer } from "../core/indexer.js";
4
-
5
- export interface CodebaseIndexerServiceDeps {
6
- anthropicClient: AnthropicClient | null;
7
- claudeRunner: ClaudeRunner;
8
- projectPath: string;
9
- log: (message: string, level?: "info" | "success" | "warn" | "error") => void;
10
- }
11
-
12
- /**
13
- * Handles codebase indexing with AI analysis
14
- */
15
- export class CodebaseIndexerService {
16
- private indexer: CodebaseIndexer;
17
-
18
- constructor(private deps: CodebaseIndexerServiceDeps) {
19
- this.indexer = new CodebaseIndexer(deps.projectPath);
20
- }
21
-
22
- async reindex(): Promise<void> {
23
- try {
24
- this.deps.log("Reindexing codebase...", "info");
25
-
26
- const index = await this.indexer.index(
27
- (msg) => this.deps.log(msg, "info"),
28
- async (tree: string) => {
29
- const prompt = `You are a codebase analysis expert. Analyze the file tree and extract:
30
- 1. Key symbols (classes, functions, types) and their locations
31
- 2. Responsibilities of each directory/file
32
- 3. Overall project structure
33
-
34
- Analyze this file tree and provide a JSON response with:
35
- - "symbols": object mapping symbol names to file paths (array)
36
- - "responsibilities": object mapping paths to brief descriptions
37
-
38
- File tree:
39
- ${tree}
40
-
41
- Return ONLY valid JSON, no markdown formatting.`;
42
-
43
- let response: string;
44
-
45
- if (this.deps.anthropicClient) {
46
- // Use Anthropic SDK with caching for faster indexing
47
- response = await this.deps.anthropicClient.run({
48
- systemPrompt:
49
- "You are a codebase analysis expert specialized in extracting structure and symbols from file trees.",
50
- userPrompt: prompt,
51
- });
52
- } else {
53
- // Fallback to Claude CLI
54
- response = await this.deps.claudeRunner.run(prompt, true);
55
- }
56
-
57
- // Extract JSON from response (handle markdown code blocks)
58
- const jsonMatch = response.match(/\{[\s\S]*\}/);
59
- if (jsonMatch) {
60
- return JSON.parse(jsonMatch[0]);
61
- }
62
- return { symbols: {}, responsibilities: {}, lastIndexed: "" };
63
- }
64
- );
65
- this.indexer.saveIndex(index);
66
- this.deps.log("Codebase reindexed successfully", "success");
67
- } catch (error) {
68
- this.deps.log(`Failed to reindex codebase: ${error}`, "error");
69
- }
70
- }
71
- }
@@ -1,5 +0,0 @@
1
- export { ArtifactSyncer } from "./artifact-syncer.js";
2
- export { CodebaseIndexerService } from "./codebase-indexer-service.js";
3
- export { SprintPlanner } from "./sprint-planner.js";
4
- export { TaskExecutor } from "./task-executor.js";
5
- export { AgentWorker, type WorkerConfig } from "./worker.js";
@@ -1,86 +0,0 @@
1
- import type { Sprint, Task } from "@locusai/shared";
2
- import type { AnthropicClient } from "../ai/anthropic-client.js";
3
- import type { ClaudeRunner } from "../ai/claude-runner.js";
4
-
5
- export interface SprintPlannerDeps {
6
- anthropicClient: AnthropicClient | null;
7
- claudeRunner: ClaudeRunner;
8
- log: (message: string, level?: "info" | "success" | "warn" | "error") => void;
9
- }
10
-
11
- /**
12
- * Handles sprint planning and mindmap generation
13
- */
14
- export class SprintPlanner {
15
- constructor(private deps: SprintPlannerDeps) {}
16
-
17
- async planSprint(sprint: Sprint, tasks: Task[]): Promise<string> {
18
- this.deps.log(`Planning sprint: ${sprint.name}`, "info");
19
-
20
- try {
21
- const taskList = tasks
22
- .map(
23
- (t) => `- [${t.id}] ${t.title}: ${t.description || "No description"}`
24
- )
25
- .join("\n");
26
-
27
- let plan: string;
28
-
29
- if (this.deps.anthropicClient) {
30
- // Use Anthropic SDK with caching for faster planning
31
- const systemPrompt = `You are an expert project manager and lead engineer specialized in sprint planning and task prioritization.`;
32
-
33
- const userPrompt = `# Sprint Planning: ${sprint.name}
34
-
35
- ## Tasks
36
- ${taskList}
37
-
38
- ## Instructions
39
- 1. Analyze dependencies between these tasks.
40
- 2. Prioritize them for the most efficient execution.
41
- 3. Create a mindmap (in Markdown or Mermaid format) that visualizes the sprint structure.
42
- 4. Output your final plan. The plan should clearly state the order of execution.
43
-
44
- **IMPORTANT**:
45
- - Do NOT create any files on the filesystem during this planning phase.
46
- - Avoid using absolute local paths (e.g., /Users/...) in your output. Use relative paths starting from the project root if necessary.
47
- - Your output will be saved as the official sprint mindmap on the server.`;
48
-
49
- plan = await this.deps.anthropicClient.run({
50
- systemPrompt,
51
- userPrompt,
52
- });
53
- } else {
54
- // Fallback to Claude CLI
55
- const planningPrompt = `# Sprint Planning: ${sprint.name}
56
-
57
- You are an expert project manager and lead engineer. You need to create a mindmap and execution plan for the following tasks in this sprint.
58
-
59
- ## Tasks
60
- ${taskList}
61
-
62
- ## Instructions
63
- 1. Analyze dependencies between these tasks.
64
- 2. Prioritize them for the most efficient execution.
65
- 3. Create a mindmap (in Markdown or Mermaid format) that visualizes the sprint structure.
66
- 4. Output your final plan. The plan should clearly state the order of execution.
67
-
68
- **IMPORTANT**:
69
- - Do NOT create any files on the filesystem during this planning phase.
70
- - Avoid using absolute local paths (e.g., /Users/...) in your output. Use relative paths starting from the project root if necessary.
71
- - Your output will be saved as the official sprint mindmap on the server.`;
72
-
73
- plan = await this.deps.claudeRunner.run(planningPrompt, true);
74
- }
75
-
76
- this.deps.log(
77
- "Sprint mindmap generated and posted to server.",
78
- "success"
79
- );
80
- return plan;
81
- } catch (error) {
82
- this.deps.log(`Sprint planning failed: ${error}`, "error");
83
- return sprint.mindmap || "";
84
- }
85
- }
86
- }
@@ -1,85 +0,0 @@
1
- import type { Task } from "@locusai/shared";
2
- import type { AnthropicClient } from "../ai/anthropic-client.js";
3
- import type { ClaudeRunner } from "../ai/claude-runner.js";
4
- import { PromptBuilder } from "../core/prompt-builder.js";
5
-
6
- export interface TaskExecutorDeps {
7
- anthropicClient: AnthropicClient | null;
8
- claudeRunner: ClaudeRunner;
9
- projectPath: string;
10
- sprintPlan: string | null;
11
- log: (message: string, level?: "info" | "success" | "warn" | "error") => void;
12
- }
13
-
14
- /**
15
- * Handles task execution with two-phase approach (planning + execution)
16
- */
17
- export class TaskExecutor {
18
- private promptBuilder: PromptBuilder;
19
-
20
- constructor(private deps: TaskExecutorDeps) {
21
- this.promptBuilder = new PromptBuilder(deps.projectPath);
22
- }
23
-
24
- updateSprintPlan(sprintPlan: string | null) {
25
- this.deps.sprintPlan = sprintPlan;
26
- }
27
-
28
- async execute(task: Task): Promise<{ success: boolean; summary: string }> {
29
- this.deps.log(`Executing: ${task.title}`, "info");
30
- let basePrompt = await this.promptBuilder.build(task);
31
-
32
- if (this.deps.sprintPlan) {
33
- basePrompt = `## Sprint Context\n${this.deps.sprintPlan}\n\n${basePrompt}`;
34
- }
35
-
36
- try {
37
- let plan: string = "";
38
-
39
- if (this.deps.anthropicClient) {
40
- // Phase 1: Planning (using Anthropic SDK with caching)
41
- this.deps.log("Phase 1: Planning (Anthropic SDK)...", "info");
42
-
43
- // Build cacheable context blocks
44
- const cacheableContext: string[] = [basePrompt];
45
-
46
- plan = await this.deps.anthropicClient.run({
47
- systemPrompt:
48
- "You are an expert software engineer. Analyze the task carefully and create a detailed implementation plan.",
49
- cacheableContext,
50
- userPrompt:
51
- "## Phase 1: Planning\nAnalyze and create a detailed plan for THIS SPECIFIC TASK. Do NOT execute changes yet.",
52
- });
53
- } else {
54
- this.deps.log(
55
- "Skipping Phase 1: Planning (No Anthropic API Key)...",
56
- "info"
57
- );
58
- }
59
-
60
- // Phase 2: Execution (always using Claude CLI for agentic tools)
61
- this.deps.log("Starting Execution...", "info");
62
-
63
- let executionPrompt = basePrompt;
64
- if (plan) {
65
- executionPrompt += `\n\n## Phase 2: Execution\nBased on the plan, execute the task:\n\n${plan}`;
66
- } else {
67
- executionPrompt += `\n\n## Execution\nExecute the task directly.`;
68
- }
69
-
70
- executionPrompt += `\n\nWhen finished, output: <promise>COMPLETE</promise>`;
71
- const output = await this.deps.claudeRunner.run(executionPrompt);
72
-
73
- const success = output.includes("<promise>COMPLETE</promise>");
74
-
75
- return {
76
- success,
77
- summary: success
78
- ? "Task completed by Claude"
79
- : "Claude did not signal completion",
80
- };
81
- } catch (error) {
82
- return { success: false, summary: `Error: ${error}` };
83
- }
84
- }
85
- }