@locusai/cli 0.9.16 → 0.9.18

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.
@@ -24976,7 +24976,8 @@ var ApiResponseSchema = exports_external.object({
24976
24976
  meta: exports_external.object({
24977
24977
  pagination: PaginationMetaSchema.optional(),
24978
24978
  timestamp: exports_external.string(),
24979
- path: exports_external.string()
24979
+ path: exports_external.string(),
24980
+ requestId: exports_external.string().optional()
24980
24981
  }).optional()
24981
24982
  });
24982
24983
  var SuccessResponseSchema = exports_external.object({
package/bin/locus.js CHANGED
@@ -6317,6 +6317,51 @@ var init_indexer = __esm(() => {
6317
6317
  init_globby();
6318
6318
  });
6319
6319
 
6320
+ // ../sdk/src/utils/json-extractor.ts
6321
+ function extractJsonFromLLMOutput(raw) {
6322
+ const trimmed = raw.trim();
6323
+ const codeBlockMatch = trimmed.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
6324
+ if (codeBlockMatch) {
6325
+ return codeBlockMatch[1]?.trim() || "";
6326
+ }
6327
+ if (trimmed.startsWith("{")) {
6328
+ return trimmed;
6329
+ }
6330
+ const startIdx = trimmed.indexOf("{");
6331
+ if (startIdx === -1) {
6332
+ return trimmed;
6333
+ }
6334
+ let depth = 0;
6335
+ let inString = false;
6336
+ let escaped = false;
6337
+ for (let i = startIdx;i < trimmed.length; i++) {
6338
+ const ch = trimmed[i];
6339
+ if (escaped) {
6340
+ escaped = false;
6341
+ continue;
6342
+ }
6343
+ if (ch === "\\") {
6344
+ escaped = true;
6345
+ continue;
6346
+ }
6347
+ if (ch === '"') {
6348
+ inString = !inString;
6349
+ continue;
6350
+ }
6351
+ if (inString)
6352
+ continue;
6353
+ if (ch === "{")
6354
+ depth++;
6355
+ else if (ch === "}") {
6356
+ depth--;
6357
+ if (depth === 0) {
6358
+ return trimmed.slice(startIdx, i + 1);
6359
+ }
6360
+ }
6361
+ }
6362
+ return trimmed.slice(startIdx);
6363
+ }
6364
+
6320
6365
  // ../sdk/src/agent/codebase-indexer-service.ts
6321
6366
  var init_codebase_indexer_service = __esm(() => {
6322
6367
  init_indexer();
@@ -36693,7 +36738,8 @@ var init_common = __esm(() => {
36693
36738
  meta: exports_external.object({
36694
36739
  pagination: PaginationMetaSchema.optional(),
36695
36740
  timestamp: exports_external.string(),
36696
- path: exports_external.string()
36741
+ path: exports_external.string(),
36742
+ requestId: exports_external.string().optional()
36697
36743
  }).optional()
36698
36744
  });
36699
36745
  SuccessResponseSchema = exports_external.object({
@@ -40583,12 +40629,11 @@ function plannedTasksToCreatePayloads(plan, sprintId) {
40583
40629
  }));
40584
40630
  }
40585
40631
  function parseSprintPlanFromAI(raw, directive) {
40586
- let jsonStr = raw.trim();
40587
- const jsonMatch = jsonStr.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
40588
- if (jsonMatch) {
40589
- jsonStr = jsonMatch[1]?.trim() || "";
40632
+ const jsonStr = extractJsonFromLLMOutput(raw);
40633
+ let parsed = JSON.parse(jsonStr);
40634
+ if (parsed.revisedPlan) {
40635
+ parsed = parsed.revisedPlan;
40590
40636
  }
40591
- const parsed = JSON.parse(jsonStr);
40592
40637
  const now = new Date().toISOString();
40593
40638
  const id = `plan-${Date.now()}`;
40594
40639
  const tasks2 = (parsed.tasks || []).map((t, i) => ({
@@ -40801,14 +40846,29 @@ Review and refine the Tech Lead's breakdown:
40801
40846
 
40802
40847
  1. **Ordering** — Order tasks so that foundational work comes first. Tasks that produce outputs consumed by later tasks must appear earlier in the list. Foundation tasks (schemas, config, shared code) must be listed before tasks that build on them. The array index IS the execution order.
40803
40848
  2. **Risk Assessment** — Flag tasks that are risky, underestimated, or have unknowns.
40804
- 3. **Task Splitting** — If a task is too large (would take more than a day), split it.
40805
- 4. **Task Merging** — If two tasks are trivially small and related, merge them.
40806
- 5. **Complexity Scoring** — Rate each task 1-5 (1=trivial, 5=very complex).
40807
- 6. **Missing Tasks** — Add any tasks the Tech Lead missed (database migrations, configuration, testing, etc.).
40849
+ 3. **Task Merging** — If two tasks are trivially small and related, merge them.
40850
+ 4. **Complexity Scoring** — Rate each task 1-5 (1=trivial, 5=very complex).
40851
+ 5. **Missing Tasks** — Add any tasks the Tech Lead missed (database migrations, configuration, testing, etc.).
40852
+
40853
+ ## CRITICAL: Task Isolation & Overlap Detection
40854
+
40855
+ Tasks are executed by INDEPENDENT agents on SEPARATE git branches that get merged together. Each agent has NO knowledge of what other agents are doing. You MUST enforce these rules:
40856
+
40857
+ 1. **Detect overlapping file modifications.** For each task, mentally list the files it will touch. If two tasks modify the same file (especially config files like app.module.ts, configuration.ts, package.json, or shared modules), they WILL cause merge conflicts. You must either:
40858
+ - **Merge them** into a single task, OR
40859
+ - **Move the shared file changes** into one foundational task that runs and merges first
40860
+
40861
+ 2. **Detect duplicated work.** If two tasks both introduce the same environment variable, config field, dependency, helper function, or module registration — that is duplicated work. Consolidate it into ONE task.
40862
+
40863
+ 3. **Do NOT split tasks that share code changes.** Even if a task is large, do NOT split it if the subtasks would both need to modify the same files. A single larger self-contained task is far better than two smaller conflicting tasks. Only split tasks when the parts are truly independent (touch completely different files and modules).
40864
+
40865
+ 4. **Validate self-containment.** Each task must include ALL changes it needs to function: config, schema, module registration, implementation, and tests. A task must NOT assume another concurrent task will provide something it needs.
40866
+
40867
+ 5. **Flag high-conflict zones.** In your risk assessment, specifically call out any remaining cases where tasks might touch the same files, and explain why it's unavoidable and how merge conflicts can be minimized.
40808
40868
 
40809
40869
  ## Output Format
40810
40870
 
40811
- Respond with ONLY a JSON object (no markdown code blocks, no explanation):
40871
+ Your entire response must be a single JSON object no text before it, no text after it, no markdown code blocks, no explanation. Start your response with the "{" character:
40812
40872
 
40813
40873
  {
40814
40874
  "tasks": [
@@ -40834,6 +40894,116 @@ Respond with ONLY a JSON object (no markdown code blocks, no explanation):
40834
40894
  return prompt;
40835
40895
  }
40836
40896
 
40897
+ // ../sdk/src/planning/agents/cross-task-reviewer.ts
40898
+ function buildCrossTaskReviewerPrompt(input) {
40899
+ let prompt = `# Role: Cross-Task Reviewer (Architect + Engineer + Planner)
40900
+
40901
+ You are a combined Architect, Senior Engineer, and Sprint Planner performing a FINAL review of a sprint plan. Your sole focus is ensuring that tasks are fully isolated and will not conflict when executed by independent agents on separate git branches.
40902
+
40903
+ ## Context
40904
+
40905
+ In this system, each task is executed by an independent AI agent that:
40906
+ - Works on its own git branch (worktree)
40907
+ - Has NO knowledge of what other agents are working on
40908
+ - Cannot see changes made by other concurrent agents
40909
+ - Its branch will be merged into main after completion
40910
+
40911
+ This means that if two tasks modify the same file, add the same dependency, or introduce the same config variable — they WILL cause merge conflicts and duplicated code.
40912
+
40913
+ ## CEO Directive
40914
+ > ${input.directive}
40915
+ `;
40916
+ if (input.feedback) {
40917
+ prompt += `
40918
+ ## CEO Feedback on Previous Plan
40919
+ > ${input.feedback}
40920
+
40921
+ IMPORTANT: Ensure the reviewed plan still addresses this feedback.
40922
+ `;
40923
+ }
40924
+ prompt += `
40925
+ ## Project Context
40926
+ ${input.projectContext || "No project context available."}
40927
+
40928
+ ## Sprint Plan to Review
40929
+ ${input.sprintOrganizerOutput}
40930
+
40931
+ ## Your Review Checklist
40932
+
40933
+ Go through EACH pair of tasks and check for:
40934
+
40935
+ ### 1. File Overlap Analysis
40936
+ For each task, list the files it will likely modify. Then check:
40937
+ - Do any two tasks modify the same file? (e.g., app.module.ts, configuration.ts, package.json, shared DTOs)
40938
+ - If yes: MERGE those tasks or move shared changes to a foundational task
40939
+
40940
+ ### 2. Duplicated Work Detection
40941
+ Check if multiple tasks:
40942
+ - Add the same environment variable or config field
40943
+ - Install or configure the same dependency
40944
+ - Register the same module or provider
40945
+ - Create the same helper function, guard, interceptor, or middleware
40946
+ - Add the same import to a shared file
40947
+ If yes: consolidate into ONE task
40948
+
40949
+ ### 3. Self-Containment Validation
40950
+ For each task, verify:
40951
+ - Does it include ALL config/env changes it needs?
40952
+ - Does it include ALL module registrations it needs?
40953
+ - Does it include ALL dependency installations it needs?
40954
+ - Can it be completed without ANY output from concurrent tasks?
40955
+
40956
+ ### 4. Merge Conflict Risk Zones
40957
+ Identify the highest-risk files (files that multiple tasks might touch) and ensure only ONE task modifies each.
40958
+
40959
+ ## Output Format
40960
+
40961
+ Your entire response must be a single JSON object — no text before it, no text after it, no markdown code blocks, no explanation. Start your response with the "{" character:
40962
+
40963
+ {
40964
+ "hasIssues": true | false,
40965
+ "issues": [
40966
+ {
40967
+ "type": "file_overlap" | "duplicated_work" | "not_self_contained" | "merge_conflict_risk",
40968
+ "description": "string describing the specific issue",
40969
+ "affectedTasks": ["Task Title 1", "Task Title 2"],
40970
+ "resolution": "string describing how to fix it (merge, move, consolidate)"
40971
+ }
40972
+ ],
40973
+ "revisedPlan": {
40974
+ "name": "string (2-4 words)",
40975
+ "goal": "string (1 paragraph)",
40976
+ "estimatedDays": 3,
40977
+ "tasks": [
40978
+ {
40979
+ "title": "string",
40980
+ "description": "string",
40981
+ "assigneeRole": "BACKEND | FRONTEND | QA | PM | DESIGN",
40982
+ "priority": "CRITICAL | HIGH | MEDIUM | LOW",
40983
+ "labels": ["string"],
40984
+ "acceptanceCriteria": ["string"],
40985
+ "complexity": 3
40986
+ }
40987
+ ],
40988
+ "risks": [
40989
+ {
40990
+ "description": "string",
40991
+ "mitigation": "string",
40992
+ "severity": "low | medium | high"
40993
+ }
40994
+ ]
40995
+ }
40996
+ }
40997
+
40998
+ IMPORTANT:
40999
+ - If hasIssues is true, the revisedPlan MUST contain the corrected task list with issues resolved (tasks merged, duplicated work consolidated, etc.)
41000
+ - If hasIssues is false, the revisedPlan should be identical to the input plan (no changes needed)
41001
+ - The revisedPlan is ALWAYS required — it becomes the final plan
41002
+ - When merging tasks, combine their acceptance criteria and update descriptions to cover all consolidated work
41003
+ - Prefer fewer, larger, self-contained tasks over many small conflicting ones`;
41004
+ return prompt;
41005
+ }
41006
+
40837
41007
  // ../sdk/src/planning/agents/sprint-organizer.ts
40838
41008
  function buildSprintOrganizerPrompt(input) {
40839
41009
  let prompt = `# Role: Sprint Organizer
@@ -40872,9 +41042,18 @@ Guidelines:
40872
41042
  - Ensure acceptance criteria are specific and testable
40873
41043
  - Keep the sprint focused — if it's too large (>12 tasks), consider reducing scope
40874
41044
 
41045
+ ## CRITICAL: Task Isolation Validation
41046
+
41047
+ Before finalizing, validate that EVERY task is fully self-contained and conflict-free:
41048
+
41049
+ 1. **No two tasks should modify the same file.** If they do, merge them or restructure so shared changes live in one foundational task.
41050
+ 2. **No duplicated work.** Each env var, config field, dependency, module import, or helper function must be introduced by exactly ONE task.
41051
+ 3. **Each task is independently executable.** An agent working on task N must be able to complete it without knowing what tasks N-1 or N+1 are doing. The only exception is foundational tasks that are merged BEFORE dependent tasks start.
41052
+ 4. **Prefer fewer, larger self-contained tasks over many small overlapping ones.** Do not split a task if the parts would conflict with each other.
41053
+
40875
41054
  ## Output Format
40876
41055
 
40877
- Respond with ONLY a JSON object (no markdown code blocks, no explanation):
41056
+ Your entire response must be a single JSON object no text before it, no text after it, no markdown code blocks, no explanation. Start your response with the "{" character:
40878
41057
 
40879
41058
  {
40880
41059
  "name": "string (2-4 words)",
@@ -40943,9 +41122,19 @@ Think about:
40943
41122
  - What the right granularity is (not too big, not too small)
40944
41123
  - What risks or unknowns exist
40945
41124
 
41125
+ ## CRITICAL: Task Isolation Rules
41126
+
41127
+ Tasks will be executed by INDEPENDENT agents on SEPARATE git branches that get merged together. Each agent has NO knowledge of what other agents are doing. Therefore:
41128
+
41129
+ 1. **No shared work across tasks.** If two tasks both need the same config variable, helper function, database migration, or module setup, that shared work MUST be consolidated into ONE task (or placed into a dedicated foundational task that runs first and is merged before others start).
41130
+ 2. **Each task must be fully self-contained.** A task must include ALL the code changes it needs to work — from config to implementation to tests. It should NOT assume that another task in the same sprint will create something it depends on.
41131
+ 3. **Do NOT split tasks if they share code changes.** If implementing feature A and feature B both require modifying the same file or adding the same dependency/config, they should be ONE task — even if that makes the task larger. A bigger self-contained task is better than two smaller conflicting tasks.
41132
+ 4. **Think about file-level conflicts.** Two tasks modifying the same file (e.g., app.module.ts, configuration.ts, package.json) will cause git merge conflicts. Minimize this by bundling related changes together.
41133
+ 5. **Environment variables, configs, and shared modules are high-conflict zones.** If a task introduces a new env var, config schema field, or module import, NO other task should touch that same file unless absolutely necessary.
41134
+
40946
41135
  ## Output Format
40947
41136
 
40948
- Respond with ONLY a JSON object (no markdown code blocks, no explanation):
41137
+ Your entire response must be a single JSON object no text before it, no text after it, no markdown code blocks, no explanation. Start your response with the "{" character:
40949
41138
 
40950
41139
  {
40951
41140
  "tasks": [
@@ -40980,7 +41169,7 @@ class PlanningMeeting {
40980
41169
  async run(directive, feedback) {
40981
41170
  const projectContext = this.getProjectContext();
40982
41171
  const codebaseIndex = this.getCodebaseIndex();
40983
- this.log("Phase 1/3: Tech Lead analyzing directive...", "info");
41172
+ this.log("Phase 1/4: Tech Lead analyzing directive...", "info");
40984
41173
  const techLeadPrompt = buildTechLeadPrompt({
40985
41174
  directive,
40986
41175
  projectContext,
@@ -40989,7 +41178,7 @@ class PlanningMeeting {
40989
41178
  });
40990
41179
  const techLeadOutput = await this.aiRunner.run(techLeadPrompt);
40991
41180
  this.log("Tech Lead phase complete.", "success");
40992
- this.log("Phase 2/3: Architect refining task breakdown...", "info");
41181
+ this.log("Phase 2/4: Architect refining task breakdown...", "info");
40993
41182
  const architectPrompt = buildArchitectPrompt({
40994
41183
  directive,
40995
41184
  projectContext,
@@ -40998,7 +41187,7 @@ class PlanningMeeting {
40998
41187
  });
40999
41188
  const architectOutput = await this.aiRunner.run(architectPrompt);
41000
41189
  this.log("Architect phase complete.", "success");
41001
- this.log("Phase 3/3: Sprint Organizer finalizing plan...", "info");
41190
+ this.log("Phase 3/4: Sprint Organizer finalizing plan...", "info");
41002
41191
  const sprintOrganizerPrompt = buildSprintOrganizerPrompt({
41003
41192
  directive,
41004
41193
  architectOutput,
@@ -41006,7 +41195,16 @@ class PlanningMeeting {
41006
41195
  });
41007
41196
  const sprintOrganizerOutput = await this.aiRunner.run(sprintOrganizerPrompt);
41008
41197
  this.log("Sprint Organizer phase complete.", "success");
41009
- const plan = parseSprintPlanFromAI(sprintOrganizerOutput, directive);
41198
+ this.log("Phase 4/4: Cross-Task Review checking for conflicts and overlaps...", "info");
41199
+ const crossTaskReviewerPrompt = buildCrossTaskReviewerPrompt({
41200
+ directive,
41201
+ projectContext,
41202
+ sprintOrganizerOutput,
41203
+ feedback
41204
+ });
41205
+ const crossTaskReviewOutput = await this.aiRunner.run(crossTaskReviewerPrompt);
41206
+ this.log("Cross-Task Review phase complete.", "success");
41207
+ const plan = parseSprintPlanFromAI(crossTaskReviewOutput, directive);
41010
41208
  if (feedback) {
41011
41209
  plan.feedback = feedback;
41012
41210
  }
@@ -41015,7 +41213,8 @@ class PlanningMeeting {
41015
41213
  phaseOutputs: {
41016
41214
  techLead: techLeadOutput,
41017
41215
  architect: architectOutput,
41018
- sprintOrganizer: sprintOrganizerOutput
41216
+ sprintOrganizer: sprintOrganizerOutput,
41217
+ crossTaskReview: crossTaskReviewOutput
41019
41218
  }
41020
41219
  };
41021
41220
  }
@@ -43490,6 +43689,8 @@ init_index_node();
43490
43689
  import { parseArgs as parseArgs4 } from "node:util";
43491
43690
 
43492
43691
  // src/tree-summarizer.ts
43692
+ init_index_node();
43693
+
43493
43694
  class TreeSummarizer {
43494
43695
  aiRunner;
43495
43696
  constructor(aiRunner) {
@@ -43506,10 +43707,8 @@ Return ONLY a JSON object with this structure:
43506
43707
  File Tree:
43507
43708
  ${tree}`;
43508
43709
  const output = await this.aiRunner.run(prompt);
43509
- const jsonMatch = output.match(/\{[\s\S]*\}/);
43510
- if (jsonMatch)
43511
- return JSON.parse(jsonMatch[0]);
43512
- throw new Error("Could not find JSON in AI output");
43710
+ const jsonStr = extractJsonFromLLMOutput(output);
43711
+ return JSON.parse(jsonStr);
43513
43712
  }
43514
43713
  }
43515
43714
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/cli",
3
- "version": "0.9.16",
3
+ "version": "0.9.18",
4
4
  "description": "CLI for Locus - AI-native project management platform",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,7 +32,7 @@
32
32
  "author": "",
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
- "@locusai/sdk": "^0.9.16"
35
+ "@locusai/sdk": "^0.9.18"
36
36
  },
37
37
  "devDependencies": {}
38
38
  }