@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.
- package/dist/agent/reviewer-worker.d.ts +2 -1
- package/dist/agent/reviewer-worker.d.ts.map +1 -1
- package/dist/agent/worker.d.ts +2 -1
- package/dist/agent/worker.d.ts.map +1 -1
- package/dist/agent/worker.js +134 -208
- package/dist/ai/claude-runner.d.ts +0 -7
- package/dist/ai/claude-runner.d.ts.map +1 -1
- package/dist/ai/claude-stream-parser.d.ts +41 -0
- package/dist/ai/claude-stream-parser.d.ts.map +1 -0
- package/dist/ai/codex-runner.d.ts.map +1 -1
- package/dist/ai/factory.d.ts +11 -0
- package/dist/ai/factory.d.ts.map +1 -1
- package/dist/ai/index.d.ts +3 -1
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/discussion/discussion-facilitator.d.ts.map +1 -1
- package/dist/events.d.ts +0 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/index-node.d.ts +0 -1
- package/dist/index-node.d.ts.map +1 -1
- package/dist/index-node.js +146 -468
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -87
- package/dist/modules/workspaces.d.ts +0 -15
- package/dist/modules/workspaces.d.ts.map +1 -1
- package/dist/planning/planning-meeting.d.ts +2 -1
- package/dist/planning/planning-meeting.d.ts.map +1 -1
- package/dist/utils/resolve-bin.d.ts.map +1 -1
- package/package.json +5 -7
- package/dist/modules/instances.d.ts +0 -46
- package/dist/modules/instances.d.ts.map +0 -1
- package/dist/modules/suggestions.d.ts +0 -12
- package/dist/modules/suggestions.d.ts.map +0 -1
- package/dist/proposals/context-gatherer.d.ts +0 -32
- package/dist/proposals/context-gatherer.d.ts.map +0 -1
- package/dist/proposals/index.d.ts +0 -4
- package/dist/proposals/index.d.ts.map +0 -1
- package/dist/proposals/proposal-engine.d.ts +0 -21
- package/dist/proposals/proposal-engine.d.ts.map +0 -1
package/dist/index-node.js
CHANGED
|
@@ -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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 ??
|
|
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 ??
|
|
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();
|