@locusai/sdk 0.15.5 → 0.16.2

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 (39) hide show
  1. package/dist/agent/reviewer-worker.d.ts +2 -1
  2. package/dist/agent/reviewer-worker.d.ts.map +1 -1
  3. package/dist/agent/worker.d.ts +2 -1
  4. package/dist/agent/worker.d.ts.map +1 -1
  5. package/dist/agent/worker.js +134 -208
  6. package/dist/ai/claude-runner.d.ts +0 -7
  7. package/dist/ai/claude-runner.d.ts.map +1 -1
  8. package/dist/ai/claude-stream-parser.d.ts +41 -0
  9. package/dist/ai/claude-stream-parser.d.ts.map +1 -0
  10. package/dist/ai/codex-runner.d.ts.map +1 -1
  11. package/dist/ai/factory.d.ts +11 -0
  12. package/dist/ai/factory.d.ts.map +1 -1
  13. package/dist/ai/index.d.ts +3 -1
  14. package/dist/ai/index.d.ts.map +1 -1
  15. package/dist/discussion/discussion-facilitator.d.ts.map +1 -1
  16. package/dist/events.d.ts +0 -2
  17. package/dist/events.d.ts.map +1 -1
  18. package/dist/index-node.d.ts +0 -1
  19. package/dist/index-node.d.ts.map +1 -1
  20. package/dist/index-node.js +146 -468
  21. package/dist/index.d.ts +0 -6
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +0 -87
  24. package/dist/modules/workspaces.d.ts +0 -15
  25. package/dist/modules/workspaces.d.ts.map +1 -1
  26. package/dist/planning/planning-meeting.d.ts +2 -1
  27. package/dist/planning/planning-meeting.d.ts.map +1 -1
  28. package/dist/utils/resolve-bin.d.ts.map +1 -1
  29. package/package.json +5 -7
  30. package/dist/modules/instances.d.ts +0 -46
  31. package/dist/modules/instances.d.ts.map +0 -1
  32. package/dist/modules/suggestions.d.ts +0 -12
  33. package/dist/modules/suggestions.d.ts.map +0 -1
  34. package/dist/proposals/context-gatherer.d.ts +0 -32
  35. package/dist/proposals/context-gatherer.d.ts.map +0 -1
  36. package/dist/proposals/index.d.ts +0 -4
  37. package/dist/proposals/index.d.ts.map +0 -1
  38. package/dist/proposals/proposal-engine.d.ts +0 -21
  39. package/dist/proposals/proposal-engine.d.ts.map +0 -1
@@ -156,49 +156,6 @@ var init_docs = __esm(() => {
156
156
  };
157
157
  });
158
158
 
159
- // src/modules/instances.ts
160
- var InstancesModule;
161
- var init_instances = __esm(() => {
162
- InstancesModule = class InstancesModule extends BaseModule {
163
- async list(workspaceId) {
164
- const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances`);
165
- return data.instances;
166
- }
167
- async get(workspaceId, instanceId) {
168
- const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances/${instanceId}`);
169
- return data.instance;
170
- }
171
- async provision(workspaceId, body) {
172
- const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances`, body);
173
- return data.instance;
174
- }
175
- async performAction(workspaceId, instanceId, action) {
176
- const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances/${instanceId}/actions`, { action });
177
- return data.instance;
178
- }
179
- async sync(workspaceId, instanceId) {
180
- const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances/${instanceId}/sync`);
181
- return data.instance;
182
- }
183
- async checkUpdates(workspaceId, instanceId) {
184
- const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances/${instanceId}/updates`);
185
- return data.update;
186
- }
187
- async applyUpdate(workspaceId, instanceId) {
188
- const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances/${instanceId}/updates`);
189
- return data.update;
190
- }
191
- async getSecurity(workspaceId, instanceId) {
192
- const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances/${instanceId}/security`);
193
- return data.rules;
194
- }
195
- async updateSecurity(workspaceId, instanceId, body) {
196
- const { data } = await this.api.put(`/workspaces/${workspaceId}/aws-instances/${instanceId}/security`, body);
197
- return data.rules;
198
- }
199
- };
200
- });
201
-
202
159
  // src/modules/invitations.ts
203
160
  var InvitationsModule;
204
161
  var init_invitations = __esm(() => {
@@ -307,29 +264,6 @@ var init_sprints = __esm(() => {
307
264
  };
308
265
  });
309
266
 
310
- // src/modules/suggestions.ts
311
- var SuggestionsModule;
312
- var init_suggestions = __esm(() => {
313
- SuggestionsModule = class SuggestionsModule extends BaseModule {
314
- async create(workspaceId, data) {
315
- const { data: res } = await this.api.post(`/workspaces/${workspaceId}/suggestions`, data);
316
- return res.suggestion;
317
- }
318
- async list(workspaceId, params) {
319
- const { data } = await this.api.get(`/workspaces/${workspaceId}/suggestions`, { params });
320
- return data.suggestions;
321
- }
322
- async get(workspaceId, id) {
323
- const { data } = await this.api.get(`/workspaces/${workspaceId}/suggestions/${id}`);
324
- return data.suggestion;
325
- }
326
- async updateStatus(workspaceId, id, status) {
327
- const { data } = await this.api.patch(`/workspaces/${workspaceId}/suggestions/${id}/status`, status);
328
- return data.suggestion;
329
- }
330
- };
331
- });
332
-
333
267
  // src/modules/tasks.ts
334
268
  var import_shared, TasksModule;
335
269
  var init_tasks = __esm(() => {
@@ -454,17 +388,6 @@ var init_workspaces = __esm(() => {
454
388
  async deleteApiKey(workspaceId, keyId) {
455
389
  await this.api.delete(`/workspaces/${workspaceId}/api-keys/${keyId}`);
456
390
  }
457
- async getAwsCredentials(workspaceId) {
458
- const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-credentials`);
459
- return data.credential;
460
- }
461
- async saveAwsCredentials(workspaceId, body) {
462
- const { data } = await this.api.put(`/workspaces/${workspaceId}/aws-credentials`, body);
463
- return data.credential;
464
- }
465
- async deleteAwsCredentials(workspaceId) {
466
- await this.api.delete(`/workspaces/${workspaceId}/aws-credentials`);
467
- }
468
391
  };
469
392
  });
470
393
 
@@ -506,14 +429,12 @@ var exports_src = {};
506
429
  __export(exports_src, {
507
430
  WorkspacesModule: () => WorkspacesModule,
508
431
  TasksModule: () => TasksModule,
509
- SuggestionsModule: () => SuggestionsModule,
510
432
  SprintsModule: () => SprintsModule,
511
433
  OrganizationsModule: () => OrganizationsModule,
512
434
  LocusEvent: () => LocusEvent,
513
435
  LocusEmitter: () => LocusEmitter,
514
436
  LocusClient: () => LocusClient,
515
437
  InvitationsModule: () => InvitationsModule,
516
- InstancesModule: () => InstancesModule,
517
438
  DocsModule: () => DocsModule,
518
439
  DiscussionSchema: () => DiscussionSchema,
519
440
  DiscussionMessageSchema: () => DiscussionMessageSchema,
@@ -534,8 +455,6 @@ class LocusClient {
534
455
  invitations;
535
456
  docs;
536
457
  ci;
537
- instances;
538
- suggestions;
539
458
  constructor(config) {
540
459
  this.emitter = new LocusEmitter;
541
460
  this.api = import_axios.default.create({
@@ -555,8 +474,6 @@ class LocusClient {
555
474
  this.invitations = new InvitationsModule(this.api, this.emitter);
556
475
  this.docs = new DocsModule(this.api, this.emitter);
557
476
  this.ci = new CiModule(this.api, this.emitter);
558
- this.instances = new InstancesModule(this.api, this.emitter);
559
- this.suggestions = new SuggestionsModule(this.api, this.emitter);
560
477
  if (config.retryOptions) {
561
478
  this.setupRetryInterceptor(config.retryOptions);
562
479
  }
@@ -622,11 +539,9 @@ var init_src = __esm(() => {
622
539
  init_auth();
623
540
  init_ci();
624
541
  init_docs();
625
- init_instances();
626
542
  init_invitations();
627
543
  init_organizations();
628
544
  init_sprints();
629
- init_suggestions();
630
545
  init_tasks();
631
546
  init_workspaces();
632
547
  init_discussion_types();
@@ -635,11 +550,9 @@ var init_src = __esm(() => {
635
550
  init_auth();
636
551
  init_ci();
637
552
  init_docs();
638
- init_instances();
639
553
  init_invitations();
640
554
  init_organizations();
641
555
  init_sprints();
642
- init_suggestions();
643
556
  init_tasks();
644
557
  init_workspaces();
645
558
  });
@@ -892,7 +805,6 @@ var init_resolve_bin = __esm(() => {
892
805
  import_node_path2.join(import_node_os.homedir(), ".local", "bin"),
893
806
  import_node_path2.join(import_node_os.homedir(), ".npm", "bin"),
894
807
  import_node_path2.join(import_node_os.homedir(), ".npm-global", "bin"),
895
- import_node_path2.join(import_node_os.homedir(), ".npm-packages", "bin"),
896
808
  import_node_path2.join(import_node_os.homedir(), ".yarn", "bin"),
897
809
  import_node_path2.join(import_node_os.homedir(), ".bun", "bin"),
898
810
  import_node_path2.join(import_node_os.homedir(), "Library", "pnpm"),
@@ -903,6 +815,112 @@ var init_resolve_bin = __esm(() => {
903
815
  ENV_VARS_TO_STRIP = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"];
904
816
  });
905
817
 
818
+ // src/ai/claude-stream-parser.ts
819
+ class ClaudeStreamParser {
820
+ activeTools = new Map;
821
+ parseLineToChunk(line) {
822
+ if (!line.trim())
823
+ return null;
824
+ try {
825
+ const item = JSON.parse(line);
826
+ return this.processItemToChunk(item);
827
+ } catch {
828
+ return null;
829
+ }
830
+ }
831
+ parseLine(line, log) {
832
+ if (!line.trim())
833
+ return null;
834
+ try {
835
+ const item = JSON.parse(line);
836
+ return this.processItem(item, log);
837
+ } catch {
838
+ return null;
839
+ }
840
+ }
841
+ processItemToChunk(item) {
842
+ if (item.type === "result") {
843
+ return { type: "result", content: item.result || "" };
844
+ }
845
+ if (item.type === "stream_event" && item.event) {
846
+ return this.handleEventToChunk(item.event);
847
+ }
848
+ return null;
849
+ }
850
+ handleEventToChunk(event) {
851
+ const { type, delta, content_block, index } = event;
852
+ if (type === "content_block_delta" && delta?.type === "text_delta") {
853
+ return { type: "text_delta", content: delta.text || "" };
854
+ }
855
+ if (type === "content_block_delta" && delta?.type === "input_json_delta" && delta.partial_json !== undefined && index !== undefined) {
856
+ const activeTool = this.activeTools.get(index);
857
+ if (activeTool) {
858
+ activeTool.parameterJson += delta.partial_json;
859
+ }
860
+ return null;
861
+ }
862
+ if (type === "content_block_start" && content_block) {
863
+ if (content_block.type === "tool_use" && content_block.name) {
864
+ if (index !== undefined) {
865
+ this.activeTools.set(index, {
866
+ name: content_block.name,
867
+ id: content_block.id,
868
+ index,
869
+ parameterJson: "",
870
+ startTime: Date.now()
871
+ });
872
+ }
873
+ return {
874
+ type: "tool_use",
875
+ tool: content_block.name,
876
+ id: content_block.id
877
+ };
878
+ }
879
+ if (content_block.type === "thinking") {
880
+ return { type: "thinking" };
881
+ }
882
+ }
883
+ if (type === "content_block_stop" && index !== undefined) {
884
+ const activeTool = this.activeTools.get(index);
885
+ if (activeTool?.parameterJson) {
886
+ try {
887
+ const parameters = JSON.parse(activeTool.parameterJson);
888
+ return {
889
+ type: "tool_parameters",
890
+ tool: activeTool.name,
891
+ id: activeTool.id,
892
+ parameters
893
+ };
894
+ } catch {}
895
+ }
896
+ return null;
897
+ }
898
+ return null;
899
+ }
900
+ processItem(item, log) {
901
+ if (item.type === "result") {
902
+ return item.result || "";
903
+ }
904
+ if (item.type === "stream_event" && item.event) {
905
+ this.handleEvent(item.event, log);
906
+ }
907
+ return null;
908
+ }
909
+ handleEvent(event, log) {
910
+ const { type, content_block } = event;
911
+ if (type === "content_block_start" && content_block) {
912
+ if (content_block.type === "tool_use" && content_block.name) {
913
+ log?.(`
914
+ ${c.primary("[Claude]")} ${c.bold(`Running ${content_block.name}...`)}
915
+ `, "info");
916
+ }
917
+ }
918
+ }
919
+ }
920
+ var init_claude_stream_parser = __esm(() => {
921
+ init_colors();
922
+ });
923
+
906
924
  // src/ai/claude-runner.ts
907
925
  class ClaudeRunner {
908
926
  model;
@@ -910,7 +928,6 @@ class ClaudeRunner {
910
928
  projectPath;
911
929
  eventEmitter;
912
930
  currentToolName;
913
- activeTools = new Map;
914
931
  activeProcess = null;
915
932
  aborted = false;
916
933
  timeoutMs;
@@ -945,7 +962,7 @@ class ClaudeRunner {
945
962
  }
946
963
  if (!isLastAttempt) {
947
964
  const delay = Math.pow(2, attempt) * 1000;
948
- console.warn(`Claude CLI attempt ${attempt} failed: ${err.message}. Retrying in ${delay}ms...`);
965
+ this.log?.(`Claude CLI attempt ${attempt} failed: ${err.message}. Retrying in ${delay}ms...`, "warn");
949
966
  await new Promise((resolve2) => setTimeout(resolve2, delay));
950
967
  }
951
968
  }
@@ -985,6 +1002,7 @@ class ClaudeRunner {
985
1002
  }
986
1003
  async* runStream(prompt) {
987
1004
  this.aborted = false;
1005
+ const parser = new ClaudeStreamParser;
988
1006
  const args = this.buildCliArgs();
989
1007
  const env = getAugmentedEnv({
990
1008
  FORCE_COLOR: "1",
@@ -1045,7 +1063,7 @@ class ClaudeRunner {
1045
1063
  `);
1046
1064
  buffer = lines.pop() || "";
1047
1065
  for (const line of lines) {
1048
- const chunk = this.parseStreamLineToChunk(line);
1066
+ const chunk = parser.parseLineToChunk(line);
1049
1067
  if (chunk) {
1050
1068
  if (chunk.type === "result") {
1051
1069
  lastResultContent = chunk.content;
@@ -1154,77 +1172,9 @@ class ClaudeRunner {
1154
1172
  break;
1155
1173
  }
1156
1174
  }
1157
- parseStreamLineToChunk(line) {
1158
- if (!line.trim())
1159
- return null;
1160
- try {
1161
- const item = JSON.parse(line);
1162
- return this.processStreamItemToChunk(item);
1163
- } catch {
1164
- return null;
1165
- }
1166
- }
1167
- processStreamItemToChunk(item) {
1168
- if (item.type === "result") {
1169
- return { type: "result", content: item.result || "" };
1170
- }
1171
- if (item.type === "stream_event" && item.event) {
1172
- return this.handleEventToChunk(item.event);
1173
- }
1174
- return null;
1175
- }
1176
- handleEventToChunk(event) {
1177
- const { type, delta, content_block, index } = event;
1178
- if (type === "content_block_delta" && delta?.type === "text_delta") {
1179
- return { type: "text_delta", content: delta.text || "" };
1180
- }
1181
- if (type === "content_block_delta" && delta?.type === "input_json_delta" && delta.partial_json !== undefined && index !== undefined) {
1182
- const activeTool = this.activeTools.get(index);
1183
- if (activeTool) {
1184
- activeTool.parameterJson += delta.partial_json;
1185
- }
1186
- return null;
1187
- }
1188
- if (type === "content_block_start" && content_block) {
1189
- if (content_block.type === "tool_use" && content_block.name) {
1190
- if (index !== undefined) {
1191
- this.activeTools.set(index, {
1192
- name: content_block.name,
1193
- id: content_block.id,
1194
- index,
1195
- parameterJson: "",
1196
- startTime: Date.now()
1197
- });
1198
- }
1199
- return {
1200
- type: "tool_use",
1201
- tool: content_block.name,
1202
- id: content_block.id
1203
- };
1204
- }
1205
- if (content_block.type === "thinking") {
1206
- return { type: "thinking" };
1207
- }
1208
- }
1209
- if (type === "content_block_stop" && index !== undefined) {
1210
- const activeTool = this.activeTools.get(index);
1211
- if (activeTool?.parameterJson) {
1212
- try {
1213
- const parameters = JSON.parse(activeTool.parameterJson);
1214
- return {
1215
- type: "tool_parameters",
1216
- tool: activeTool.name,
1217
- id: activeTool.id,
1218
- parameters
1219
- };
1220
- } catch {}
1221
- }
1222
- return null;
1223
- }
1224
- return null;
1225
- }
1226
1175
  executeRun(prompt) {
1227
1176
  this.aborted = false;
1177
+ const parser = new ClaudeStreamParser;
1228
1178
  return new Promise((resolve2, reject) => {
1229
1179
  const args = this.buildCliArgs();
1230
1180
  const env = getAugmentedEnv({
@@ -1247,7 +1197,7 @@ class ClaudeRunner {
1247
1197
  `);
1248
1198
  buffer = lines.pop() || "";
1249
1199
  for (const line of lines) {
1250
- const result = this.handleStreamLine(line);
1200
+ const result = parser.parseLine(line, this.log);
1251
1201
  if (result)
1252
1202
  finalResult = result;
1253
1203
  }
@@ -1288,35 +1238,6 @@ class ClaudeRunner {
1288
1238
  claude.stdin.end();
1289
1239
  });
1290
1240
  }
1291
- handleStreamLine(line) {
1292
- if (!line.trim())
1293
- return null;
1294
- try {
1295
- const item = JSON.parse(line);
1296
- return this.processStreamItem(item);
1297
- } catch {
1298
- return null;
1299
- }
1300
- }
1301
- processStreamItem(item) {
1302
- if (item.type === "result") {
1303
- return item.result || "";
1304
- }
1305
- if (item.type === "stream_event" && item.event) {
1306
- this.handleEvent(item.event);
1307
- }
1308
- return null;
1309
- }
1310
- handleEvent(event) {
1311
- const { type, content_block } = event;
1312
- if (type === "content_block_start" && content_block) {
1313
- if (content_block.type === "tool_use" && content_block.name) {
1314
- this.log?.(`
1315
- ${c.primary("[Claude]")} ${c.bold(`Running ${content_block.name}...`)}
1316
- `, "info");
1317
- }
1318
- }
1319
- }
1320
1241
  shouldSuppressLine(line) {
1321
1242
  const infoLogRegex = /^\[\d{2}:\d{2}:\d{2}\]\s\[.*?\]\sℹ\s*$/;
1322
1243
  return infoLogRegex.test(line.trim());
@@ -1330,8 +1251,8 @@ ${c.primary("[Claude]")} ${c.bold(`Running ${content_block.name}...`)}
1330
1251
  var import_node_child_process, import_node_path3, DEFAULT_TIMEOUT_MS;
1331
1252
  var init_claude_runner = __esm(() => {
1332
1253
  init_config();
1333
- init_colors();
1334
1254
  init_resolve_bin();
1255
+ init_claude_stream_parser();
1335
1256
  import_node_child_process = require("node:child_process");
1336
1257
  import_node_path3 = require("node:path");
1337
1258
  DEFAULT_TIMEOUT_MS = 60 * 60 * 1000;
@@ -1379,7 +1300,7 @@ class CodexRunner {
1379
1300
  }
1380
1301
  if (attempt < maxRetries) {
1381
1302
  const delay = Math.pow(2, attempt) * 1000;
1382
- console.warn(`Codex CLI attempt ${attempt} failed: ${lastError.message}. Retrying in ${delay}ms...`);
1303
+ this.log?.(`Codex CLI attempt ${attempt} failed: ${lastError.message}. Retrying in ${delay}ms...`, "warn");
1383
1304
  await this.sleep(delay);
1384
1305
  }
1385
1306
  }
@@ -1676,6 +1597,20 @@ var init_codex_runner = __esm(() => {
1676
1597
  });
1677
1598
 
1678
1599
  // src/ai/factory.ts
1600
+ function createWorkerLogger(agentId, prefix) {
1601
+ const tag = prefix ? `${prefix}:${agentId.slice(-8)}` : agentId.slice(-8);
1602
+ return (message, level = "info") => {
1603
+ const timestamp = new Date().toISOString().split("T")[1]?.slice(0, 8) ?? "";
1604
+ const colorFn = {
1605
+ info: c.cyan,
1606
+ success: c.green,
1607
+ warn: c.yellow,
1608
+ error: c.red
1609
+ }[level];
1610
+ const icon = { info: "ℹ", success: "✓", warn: "⚠", error: "✗" }[level];
1611
+ console.log(`${c.dim(`[${timestamp}]`)} ${c.bold(`[${tag}]`)} ${colorFn(`${icon} ${message}`)}`);
1612
+ };
1613
+ }
1679
1614
  function createAiRunner(provider, config) {
1680
1615
  const resolvedProvider = provider ?? PROVIDER.CLAUDE;
1681
1616
  const model = config.model ?? DEFAULT_MODEL[resolvedProvider];
@@ -1690,8 +1625,10 @@ function createAiRunner(provider, config) {
1690
1625
  return new ClaudeRunner(config.projectPath, model, config.log, config.timeoutMs);
1691
1626
  }
1692
1627
  }
1628
+ var noopLogger = () => {};
1693
1629
  var init_factory = __esm(() => {
1694
1630
  init_config();
1631
+ init_colors();
1695
1632
  init_claude_runner();
1696
1633
  init_codex_runner();
1697
1634
  });
@@ -2624,9 +2561,11 @@ class AgentWorker {
2624
2561
  currentTaskId = null;
2625
2562
  completedTaskList = [];
2626
2563
  taskSummaries = [];
2564
+ log;
2627
2565
  constructor(config) {
2628
2566
  this.config = config;
2629
2567
  const projectPath = config.projectPath || process.cwd();
2568
+ this.log = createWorkerLogger(config.agentId);
2630
2569
  this.client = new LocusClient({
2631
2570
  baseUrl: config.apiBase,
2632
2571
  token: config.apiKey,
@@ -2637,7 +2576,6 @@ class AgentWorker {
2637
2576
  factor: 2
2638
2577
  }
2639
2578
  });
2640
- const log = this.log.bind(this);
2641
2579
  if (!isGitAvailable()) {
2642
2580
  this.log("git is not installed — branch management will not work", "error");
2643
2581
  }
@@ -2648,29 +2586,18 @@ class AgentWorker {
2648
2586
  this.aiRunner = createAiRunner(provider, {
2649
2587
  projectPath,
2650
2588
  model: config.model,
2651
- log,
2589
+ log: this.log,
2652
2590
  reasoningEffort: config.reasoningEffort
2653
2591
  });
2654
2592
  this.taskExecutor = new TaskExecutor({
2655
2593
  aiRunner: this.aiRunner,
2656
2594
  projectPath,
2657
- log
2595
+ log: this.log
2658
2596
  });
2659
- this.gitWorkflow = new GitWorkflow(config, log);
2597
+ this.gitWorkflow = new GitWorkflow(config, this.log);
2660
2598
  const providerLabel = provider === "codex" ? "Codex" : "Claude";
2661
2599
  this.log(`Using ${providerLabel} CLI for all phases`, "info");
2662
2600
  }
2663
- log(message, level = "info") {
2664
- const timestamp = new Date().toISOString().split("T")[1]?.slice(0, 8) ?? "";
2665
- const colorFn = {
2666
- info: c.cyan,
2667
- success: c.green,
2668
- warn: c.yellow,
2669
- error: c.red
2670
- }[level];
2671
- const prefix = { info: "ℹ", success: "✓", warn: "⚠", error: "✗" }[level];
2672
- console.log(`${c.dim(`[${timestamp}]`)} ${c.bold(`[${this.config.agentId.slice(-8)}]`)} ${colorFn(`${prefix} ${message}`)}`);
2673
- }
2674
2601
  async getActiveSprint() {
2675
2602
  try {
2676
2603
  if (this.config.sprintId) {
@@ -2846,7 +2773,6 @@ var init_worker = __esm(() => {
2846
2773
  init_config();
2847
2774
  init_git_utils();
2848
2775
  init_src();
2849
- init_colors();
2850
2776
  init_git_workflow();
2851
2777
  init_task_executor();
2852
2778
  import_shared3 = require("@locusai/shared");
@@ -2871,6 +2797,7 @@ __export(exports_index_node, {
2871
2797
  plannedTasksToCreatePayloads: () => plannedTasksToCreatePayloads,
2872
2798
  parseSprintPlanFromAI: () => parseSprintPlanFromAI,
2873
2799
  parseJsonWithSchema: () => parseJsonWithSchema,
2800
+ noopLogger: () => noopLogger,
2874
2801
  isValidModelForProvider: () => isValidModelForProvider,
2875
2802
  getRemoteUrl: () => getRemoteUrl,
2876
2803
  getModelsForProvider: () => getModelsForProvider,
@@ -2880,6 +2807,7 @@ __export(exports_index_node, {
2880
2807
  getAgentArtifactsPath: () => getAgentArtifactsPath,
2881
2808
  extractJsonFromLLMOutput: () => extractJsonFromLLMOutput,
2882
2809
  detectRemoteProvider: () => detectRemoteProvider,
2810
+ createWorkerLogger: () => createWorkerLogger,
2883
2811
  createAiRunner: () => createAiRunner,
2884
2812
  c: () => c,
2885
2813
  buildSummaryPrompt: () => buildSummaryPrompt,
@@ -2887,11 +2815,9 @@ __export(exports_index_node, {
2887
2815
  WorkspacesModule: () => WorkspacesModule,
2888
2816
  TasksModule: () => TasksModule,
2889
2817
  TaskExecutor: () => TaskExecutor,
2890
- SuggestionsModule: () => SuggestionsModule,
2891
2818
  SprintsModule: () => SprintsModule,
2892
2819
  ReviewerWorker: () => ReviewerWorker,
2893
2820
  ReviewService: () => ReviewService,
2894
- ProposalEngine: () => ProposalEngine,
2895
2821
  PromptBuilder: () => PromptBuilder,
2896
2822
  PrService: () => PrService,
2897
2823
  PlanningMeeting: () => PlanningMeeting,
@@ -2907,7 +2833,6 @@ __export(exports_index_node, {
2907
2833
  LOCUS_GITIGNORE_PATTERNS: () => LOCUS_GITIGNORE_PATTERNS,
2908
2834
  LOCUS_CONFIG: () => LOCUS_CONFIG,
2909
2835
  InvitationsModule: () => InvitationsModule,
2910
- InstancesModule: () => InstancesModule,
2911
2836
  HistoryManager: () => HistoryManager,
2912
2837
  GitWorkflow: () => GitWorkflow,
2913
2838
  ExecSession: () => ExecSession,
@@ -2922,10 +2847,10 @@ __export(exports_index_node, {
2922
2847
  DiscussionFacilitator: () => DiscussionFacilitator,
2923
2848
  DEFAULT_MODEL: () => DEFAULT_MODEL,
2924
2849
  ContextTracker: () => ContextTracker,
2925
- ContextGatherer: () => ContextGatherer,
2926
2850
  CodexRunner: () => CodexRunner,
2927
2851
  CodebaseIndexerService: () => CodebaseIndexerService,
2928
2852
  CodebaseIndexer: () => CodebaseIndexer,
2853
+ ClaudeStreamParser: () => ClaudeStreamParser,
2929
2854
  ClaudeRunner: () => ClaudeRunner,
2930
2855
  CiModule: () => CiModule,
2931
2856
  CODEX_MODELS: () => CODEX_MODELS,
@@ -3596,7 +3521,6 @@ class PrService {
3596
3521
 
3597
3522
  // src/agent/reviewer-worker.ts
3598
3523
  init_src();
3599
- init_colors();
3600
3524
  function resolveProvider2(value) {
3601
3525
  if (!value || value.startsWith("--"))
3602
3526
  return PROVIDER.CLAUDE;
@@ -3614,9 +3538,11 @@ class ReviewerWorker {
3614
3538
  currentTaskId = null;
3615
3539
  maxReviews = 50;
3616
3540
  reviewsCompleted = 0;
3541
+ log;
3617
3542
  constructor(config) {
3618
3543
  this.config = config;
3619
3544
  const projectPath = config.projectPath || process.cwd();
3545
+ this.log = createWorkerLogger(config.agentId, "R");
3620
3546
  this.client = new LocusClient({
3621
3547
  baseUrl: config.apiBase,
3622
3548
  token: config.apiKey,
@@ -3627,28 +3553,16 @@ class ReviewerWorker {
3627
3553
  factor: 2
3628
3554
  }
3629
3555
  });
3630
- const log = this.log.bind(this);
3631
3556
  const provider = config.provider ?? PROVIDER.CLAUDE;
3632
3557
  this.aiRunner = createAiRunner(provider, {
3633
3558
  projectPath,
3634
3559
  model: config.model,
3635
- log
3560
+ log: this.log
3636
3561
  });
3637
- this.prService = new PrService(projectPath, log);
3562
+ this.prService = new PrService(projectPath, this.log);
3638
3563
  const providerLabel = provider === "codex" ? "Codex" : "Claude";
3639
3564
  this.log(`Reviewer agent using ${providerLabel} CLI`, "info");
3640
3565
  }
3641
- log(message, level = "info") {
3642
- const timestamp = new Date().toISOString().split("T")[1]?.slice(0, 8) ?? "";
3643
- const colorFn = {
3644
- info: c.cyan,
3645
- success: c.green,
3646
- warn: c.yellow,
3647
- error: c.red
3648
- }[level];
3649
- const prefix = { info: "ℹ", success: "✓", warn: "⚠", error: "✗" }[level];
3650
- console.log(`${c.dim(`[${timestamp}]`)} ${c.bold(`[R:${this.config.agentId.slice(-8)}]`)} ${colorFn(`${prefix} ${message}`)}`);
3651
- }
3652
3566
  getNextUnreviewedPr() {
3653
3567
  const prs = this.prService.listUnreviewedLocusPrs();
3654
3568
  return prs.length > 0 ? prs[0] : null;
@@ -3805,6 +3719,7 @@ init_task_executor();
3805
3719
  init_worker();
3806
3720
  // src/ai/index.ts
3807
3721
  init_claude_runner();
3722
+ init_claude_stream_parser();
3808
3723
  init_codex_runner();
3809
3724
  init_factory();
3810
3725
  // src/core/index.ts
@@ -3960,6 +3875,7 @@ ${insightsText.trimEnd()}
3960
3875
  </discussion_summary>`;
3961
3876
  }
3962
3877
  // src/discussion/discussion-facilitator.ts
3878
+ init_factory();
3963
3879
  init_config();
3964
3880
  var import_node_fs7 = require("node:fs");
3965
3881
  class DiscussionFacilitator {
@@ -3973,9 +3889,7 @@ class DiscussionFacilitator {
3973
3889
  this.projectPath = config.projectPath;
3974
3890
  this.aiRunner = config.aiRunner;
3975
3891
  this.discussionManager = config.discussionManager;
3976
- this.log = config.log ?? ((_msg) => {
3977
- return;
3978
- });
3892
+ this.log = config.log ?? noopLogger;
3979
3893
  this.provider = config.provider;
3980
3894
  this.model = config.model;
3981
3895
  }
@@ -5568,6 +5482,7 @@ class PlanManager {
5568
5482
  }
5569
5483
  }
5570
5484
  // src/planning/planning-meeting.ts
5485
+ init_factory();
5571
5486
  init_config();
5572
5487
  var import_node_fs11 = require("node:fs");
5573
5488
  var import_node_path12 = require("node:path");
@@ -5649,9 +5564,7 @@ class PlanningMeeting {
5649
5564
  constructor(config) {
5650
5565
  this.projectPath = config.projectPath;
5651
5566
  this.aiRunner = config.aiRunner;
5652
- this.log = config.log ?? ((_msg) => {
5653
- return;
5654
- });
5567
+ this.log = config.log ?? noopLogger;
5655
5568
  }
5656
5569
  async run(directive, feedback) {
5657
5570
  this.log("Planning sprint...", "info");
@@ -5690,240 +5603,5 @@ class PlanningMeeting {
5690
5603
  };
5691
5604
  }
5692
5605
  }
5693
- // src/proposals/context-gatherer.ts
5694
- var import_node_child_process8 = require("node:child_process");
5695
- var import_node_fs12 = require("node:fs");
5696
- var import_node_path13 = require("node:path");
5697
-
5698
- class ContextGatherer {
5699
- async gather(projectPath, client, workspaceId) {
5700
- const [activeSprint, allTasks, skippedSuggestions] = await Promise.all([
5701
- this.fetchActiveSprint(client, workspaceId),
5702
- this.fetchTasks(client, workspaceId),
5703
- this.fetchSkippedSuggestions(client, workspaceId)
5704
- ]);
5705
- const sprintTasks = activeSprint ? allTasks.filter((t) => t.sprintId === activeSprint.id) : [];
5706
- const backlogTasks = allTasks.filter((t) => !t.sprintId);
5707
- const gitLog = this.readGitLog(projectPath);
5708
- const artifactContents = this.readArtifacts(projectPath);
5709
- const locusInstructions = this.readLocusInstructions(projectPath);
5710
- return {
5711
- activeSprint,
5712
- sprintTasks,
5713
- backlogTasks,
5714
- gitLog,
5715
- artifactContents,
5716
- locusInstructions,
5717
- skippedSuggestions
5718
- };
5719
- }
5720
- async fetchActiveSprint(client, workspaceId) {
5721
- try {
5722
- return await client.sprints.getActive(workspaceId);
5723
- } catch {
5724
- return null;
5725
- }
5726
- }
5727
- async fetchTasks(client, workspaceId) {
5728
- try {
5729
- return await client.tasks.list(workspaceId);
5730
- } catch {
5731
- return [];
5732
- }
5733
- }
5734
- async fetchSkippedSuggestions(client, workspaceId) {
5735
- try {
5736
- return await client.suggestions.list(workspaceId, { status: "SKIPPED" });
5737
- } catch {
5738
- return [];
5739
- }
5740
- }
5741
- readGitLog(projectPath) {
5742
- try {
5743
- return import_node_child_process8.execFileSync("git", ["log", "--oneline", "--no-decorate", "-n", "20"], {
5744
- cwd: projectPath,
5745
- encoding: "utf-8",
5746
- timeout: 1e4,
5747
- stdio: ["pipe", "pipe", "pipe"]
5748
- }).trim();
5749
- } catch {
5750
- return "";
5751
- }
5752
- }
5753
- readArtifacts(projectPath) {
5754
- const artifactsDir = import_node_path13.join(projectPath, ".locus", "artifacts");
5755
- if (!import_node_fs12.existsSync(artifactsDir))
5756
- return [];
5757
- try {
5758
- const files = import_node_fs12.readdirSync(artifactsDir).filter((f) => f.endsWith(".md"));
5759
- return files.slice(0, 10).map((name) => ({
5760
- name,
5761
- content: import_node_fs12.readFileSync(import_node_path13.join(artifactsDir, name), "utf-8").slice(0, 2000)
5762
- }));
5763
- } catch {
5764
- return [];
5765
- }
5766
- }
5767
- readLocusInstructions(projectPath) {
5768
- const locusPath = import_node_path13.join(projectPath, ".locus", "LOCUS.md");
5769
- if (!import_node_fs12.existsSync(locusPath))
5770
- return null;
5771
- try {
5772
- return import_node_fs12.readFileSync(locusPath, "utf-8").slice(0, 3000);
5773
- } catch {
5774
- return null;
5775
- }
5776
- }
5777
- }
5778
- // src/proposals/proposal-engine.ts
5779
- init_factory();
5780
- var import_shared6 = require("@locusai/shared");
5781
- class ProposalEngine {
5782
- contextGatherer;
5783
- constructor(contextGatherer) {
5784
- this.contextGatherer = contextGatherer ?? new ContextGatherer;
5785
- }
5786
- async runProposalCycle(projectPath, client, workspaceId) {
5787
- const context = await this.contextGatherer.gather(projectPath, client, workspaceId);
5788
- return this.generateProposals(context, projectPath, client, workspaceId);
5789
- }
5790
- async generateProposals(context, projectPath, client, workspaceId) {
5791
- const prompt = this.buildPrompt(context);
5792
- const runner = createAiRunner(undefined, {
5793
- projectPath,
5794
- timeoutMs: 5 * 60 * 1000,
5795
- maxTurns: 1
5796
- });
5797
- let aiResponse;
5798
- try {
5799
- aiResponse = await runner.run(prompt);
5800
- } catch {
5801
- return [];
5802
- }
5803
- const proposals = this.parseResponse(aiResponse);
5804
- const created = [];
5805
- for (const proposal of proposals) {
5806
- if (this.isDuplicate(proposal.title, context.skippedSuggestions)) {
5807
- continue;
5808
- }
5809
- try {
5810
- const suggestion = await client.suggestions.create(workspaceId, {
5811
- type: import_shared6.SuggestionType.NEXT_STEP,
5812
- title: proposal.title,
5813
- description: proposal.description,
5814
- metadata: {
5815
- complexity: proposal.complexity,
5816
- relatedBacklogItem: proposal.relatedBacklogItem,
5817
- source: "proposal-engine"
5818
- }
5819
- });
5820
- created.push(suggestion);
5821
- } catch {}
5822
- }
5823
- return created;
5824
- }
5825
- buildPrompt(context) {
5826
- const sections = [];
5827
- sections.push("You are a proactive software engineering advisor. Based on the project context below, propose 1-3 high-value next steps the team should take. Focus on actionable, impactful work.");
5828
- if (context.activeSprint) {
5829
- const sprintInfo = `Sprint: ${context.activeSprint.name} (${context.activeSprint.status})`;
5830
- const tasksByStatus = this.groupTasksByStatus(context.sprintTasks);
5831
- sections.push(`## Current Sprint
5832
- ${sprintInfo}
5833
- ${tasksByStatus}`);
5834
- }
5835
- if (context.backlogTasks.length > 0) {
5836
- const backlogList = context.backlogTasks.slice(0, 15).map((t) => `- [${t.priority}] ${t.title}${t.description ? `: ${t.description.slice(0, 100)}` : ""}`).join(`
5837
- `);
5838
- sections.push(`## Backlog Items
5839
- ${backlogList}`);
5840
- }
5841
- if (context.gitLog) {
5842
- sections.push(`## Recent Commits (last 20)
5843
- ${context.gitLog}`);
5844
- }
5845
- if (context.artifactContents.length > 0) {
5846
- const artifacts = context.artifactContents.map((a) => `### ${a.name}
5847
- ${a.content}`).join(`
5848
-
5849
- `);
5850
- sections.push(`## Product Context
5851
- ${artifacts}`);
5852
- }
5853
- if (context.locusInstructions) {
5854
- sections.push(`## Project Instructions
5855
- ${context.locusInstructions}`);
5856
- }
5857
- if (context.skippedSuggestions.length > 0) {
5858
- const skipped = context.skippedSuggestions.map((s) => `- ${s.title}`).join(`
5859
- `);
5860
- sections.push(`## Previously Skipped Proposals (do NOT re-propose these)
5861
- ${skipped}`);
5862
- }
5863
- sections.push(`## Instructions
5864
- Propose 1-3 high-value next steps. For each, respond with exactly this format:
5865
-
5866
- PROPOSAL_START
5867
- Title: <clear, concise title>
5868
- Description: <what to do and why, 2-4 sentences>
5869
- Complexity: <low|medium|high>
5870
- Related Backlog: <title of related backlog item, or "none">
5871
- PROPOSAL_END
5872
-
5873
- Rules:
5874
- - Focus on what would deliver the most value right now
5875
- - Align with the current sprint goals when possible
5876
- - Don't propose things that are already in progress
5877
- - Don't re-propose previously skipped suggestions
5878
- - Keep proposals specific and actionable`);
5879
- return sections.join(`
5880
-
5881
- `);
5882
- }
5883
- parseResponse(response) {
5884
- const proposals = [];
5885
- const blocks = response.split("PROPOSAL_START");
5886
- for (const block of blocks) {
5887
- const endIdx = block.indexOf("PROPOSAL_END");
5888
- if (endIdx === -1)
5889
- continue;
5890
- const content = block.slice(0, endIdx).trim();
5891
- const title = this.extractField(content, "Title");
5892
- const description = this.extractField(content, "Description");
5893
- const complexity = this.extractField(content, "Complexity") ?? "medium";
5894
- const relatedRaw = this.extractField(content, "Related Backlog");
5895
- const relatedBacklogItem = relatedRaw && relatedRaw.toLowerCase() !== "none" ? relatedRaw : null;
5896
- if (title && description) {
5897
- proposals.push({
5898
- title: title.slice(0, 200),
5899
- description: description.slice(0, 2000),
5900
- complexity: complexity.toLowerCase(),
5901
- relatedBacklogItem
5902
- });
5903
- }
5904
- }
5905
- return proposals.slice(0, 3);
5906
- }
5907
- extractField(content, field) {
5908
- const regex = new RegExp(`^${field}:\\s*(.+)`, "im");
5909
- const match = content.match(regex);
5910
- return match ? match[1].trim() : null;
5911
- }
5912
- isDuplicate(title, skipped) {
5913
- const normalized = title.toLowerCase().trim();
5914
- return skipped.some((s) => {
5915
- const skippedNorm = s.title.toLowerCase().trim();
5916
- return skippedNorm === normalized || skippedNorm.includes(normalized) || normalized.includes(skippedNorm);
5917
- });
5918
- }
5919
- groupTasksByStatus(tasks2) {
5920
- const groups = {};
5921
- for (const t of tasks2) {
5922
- groups[t.status] = (groups[t.status] ?? 0) + 1;
5923
- }
5924
- return Object.entries(groups).map(([status, count]) => `- ${status}: ${count} task(s)`).join(`
5925
- `);
5926
- }
5927
- }
5928
5606
  // src/index-node.ts
5929
5607
  init_colors();