@locusai/cli 0.16.1 → 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/bin/agent/worker.js +134 -260
- package/bin/locus.js +796 -859
- package/package.json +4 -3
package/bin/locus.js
CHANGED
|
@@ -7065,6 +7065,112 @@ var init_resolve_bin = __esm(() => {
|
|
|
7065
7065
|
ENV_VARS_TO_STRIP = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"];
|
|
7066
7066
|
});
|
|
7067
7067
|
|
|
7068
|
+
// ../sdk/src/ai/claude-stream-parser.ts
|
|
7069
|
+
class ClaudeStreamParser {
|
|
7070
|
+
activeTools = new Map;
|
|
7071
|
+
parseLineToChunk(line) {
|
|
7072
|
+
if (!line.trim())
|
|
7073
|
+
return null;
|
|
7074
|
+
try {
|
|
7075
|
+
const item = JSON.parse(line);
|
|
7076
|
+
return this.processItemToChunk(item);
|
|
7077
|
+
} catch {
|
|
7078
|
+
return null;
|
|
7079
|
+
}
|
|
7080
|
+
}
|
|
7081
|
+
parseLine(line, log) {
|
|
7082
|
+
if (!line.trim())
|
|
7083
|
+
return null;
|
|
7084
|
+
try {
|
|
7085
|
+
const item = JSON.parse(line);
|
|
7086
|
+
return this.processItem(item, log);
|
|
7087
|
+
} catch {
|
|
7088
|
+
return null;
|
|
7089
|
+
}
|
|
7090
|
+
}
|
|
7091
|
+
processItemToChunk(item) {
|
|
7092
|
+
if (item.type === "result") {
|
|
7093
|
+
return { type: "result", content: item.result || "" };
|
|
7094
|
+
}
|
|
7095
|
+
if (item.type === "stream_event" && item.event) {
|
|
7096
|
+
return this.handleEventToChunk(item.event);
|
|
7097
|
+
}
|
|
7098
|
+
return null;
|
|
7099
|
+
}
|
|
7100
|
+
handleEventToChunk(event) {
|
|
7101
|
+
const { type, delta, content_block, index } = event;
|
|
7102
|
+
if (type === "content_block_delta" && delta?.type === "text_delta") {
|
|
7103
|
+
return { type: "text_delta", content: delta.text || "" };
|
|
7104
|
+
}
|
|
7105
|
+
if (type === "content_block_delta" && delta?.type === "input_json_delta" && delta.partial_json !== undefined && index !== undefined) {
|
|
7106
|
+
const activeTool = this.activeTools.get(index);
|
|
7107
|
+
if (activeTool) {
|
|
7108
|
+
activeTool.parameterJson += delta.partial_json;
|
|
7109
|
+
}
|
|
7110
|
+
return null;
|
|
7111
|
+
}
|
|
7112
|
+
if (type === "content_block_start" && content_block) {
|
|
7113
|
+
if (content_block.type === "tool_use" && content_block.name) {
|
|
7114
|
+
if (index !== undefined) {
|
|
7115
|
+
this.activeTools.set(index, {
|
|
7116
|
+
name: content_block.name,
|
|
7117
|
+
id: content_block.id,
|
|
7118
|
+
index,
|
|
7119
|
+
parameterJson: "",
|
|
7120
|
+
startTime: Date.now()
|
|
7121
|
+
});
|
|
7122
|
+
}
|
|
7123
|
+
return {
|
|
7124
|
+
type: "tool_use",
|
|
7125
|
+
tool: content_block.name,
|
|
7126
|
+
id: content_block.id
|
|
7127
|
+
};
|
|
7128
|
+
}
|
|
7129
|
+
if (content_block.type === "thinking") {
|
|
7130
|
+
return { type: "thinking" };
|
|
7131
|
+
}
|
|
7132
|
+
}
|
|
7133
|
+
if (type === "content_block_stop" && index !== undefined) {
|
|
7134
|
+
const activeTool = this.activeTools.get(index);
|
|
7135
|
+
if (activeTool?.parameterJson) {
|
|
7136
|
+
try {
|
|
7137
|
+
const parameters = JSON.parse(activeTool.parameterJson);
|
|
7138
|
+
return {
|
|
7139
|
+
type: "tool_parameters",
|
|
7140
|
+
tool: activeTool.name,
|
|
7141
|
+
id: activeTool.id,
|
|
7142
|
+
parameters
|
|
7143
|
+
};
|
|
7144
|
+
} catch {}
|
|
7145
|
+
}
|
|
7146
|
+
return null;
|
|
7147
|
+
}
|
|
7148
|
+
return null;
|
|
7149
|
+
}
|
|
7150
|
+
processItem(item, log) {
|
|
7151
|
+
if (item.type === "result") {
|
|
7152
|
+
return item.result || "";
|
|
7153
|
+
}
|
|
7154
|
+
if (item.type === "stream_event" && item.event) {
|
|
7155
|
+
this.handleEvent(item.event, log);
|
|
7156
|
+
}
|
|
7157
|
+
return null;
|
|
7158
|
+
}
|
|
7159
|
+
handleEvent(event, log) {
|
|
7160
|
+
const { type, content_block } = event;
|
|
7161
|
+
if (type === "content_block_start" && content_block) {
|
|
7162
|
+
if (content_block.type === "tool_use" && content_block.name) {
|
|
7163
|
+
log?.(`
|
|
7164
|
+
${c.primary("[Claude]")} ${c.bold(`Running ${content_block.name}...`)}
|
|
7165
|
+
`, "info");
|
|
7166
|
+
}
|
|
7167
|
+
}
|
|
7168
|
+
}
|
|
7169
|
+
}
|
|
7170
|
+
var init_claude_stream_parser = __esm(() => {
|
|
7171
|
+
init_colors();
|
|
7172
|
+
});
|
|
7173
|
+
|
|
7068
7174
|
// ../sdk/src/ai/claude-runner.ts
|
|
7069
7175
|
import { spawn } from "node:child_process";
|
|
7070
7176
|
import { resolve } from "node:path";
|
|
@@ -7075,7 +7181,6 @@ class ClaudeRunner {
|
|
|
7075
7181
|
projectPath;
|
|
7076
7182
|
eventEmitter;
|
|
7077
7183
|
currentToolName;
|
|
7078
|
-
activeTools = new Map;
|
|
7079
7184
|
activeProcess = null;
|
|
7080
7185
|
aborted = false;
|
|
7081
7186
|
timeoutMs;
|
|
@@ -7110,7 +7215,7 @@ class ClaudeRunner {
|
|
|
7110
7215
|
}
|
|
7111
7216
|
if (!isLastAttempt) {
|
|
7112
7217
|
const delay = Math.pow(2, attempt) * 1000;
|
|
7113
|
-
|
|
7218
|
+
this.log?.(`Claude CLI attempt ${attempt} failed: ${err.message}. Retrying in ${delay}ms...`, "warn");
|
|
7114
7219
|
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
7115
7220
|
}
|
|
7116
7221
|
}
|
|
@@ -7150,6 +7255,7 @@ class ClaudeRunner {
|
|
|
7150
7255
|
}
|
|
7151
7256
|
async* runStream(prompt) {
|
|
7152
7257
|
this.aborted = false;
|
|
7258
|
+
const parser = new ClaudeStreamParser;
|
|
7153
7259
|
const args = this.buildCliArgs();
|
|
7154
7260
|
const env = getAugmentedEnv({
|
|
7155
7261
|
FORCE_COLOR: "1",
|
|
@@ -7210,7 +7316,7 @@ class ClaudeRunner {
|
|
|
7210
7316
|
`);
|
|
7211
7317
|
buffer = lines.pop() || "";
|
|
7212
7318
|
for (const line of lines) {
|
|
7213
|
-
const chunk =
|
|
7319
|
+
const chunk = parser.parseLineToChunk(line);
|
|
7214
7320
|
if (chunk) {
|
|
7215
7321
|
if (chunk.type === "result") {
|
|
7216
7322
|
lastResultContent = chunk.content;
|
|
@@ -7319,77 +7425,9 @@ class ClaudeRunner {
|
|
|
7319
7425
|
break;
|
|
7320
7426
|
}
|
|
7321
7427
|
}
|
|
7322
|
-
parseStreamLineToChunk(line) {
|
|
7323
|
-
if (!line.trim())
|
|
7324
|
-
return null;
|
|
7325
|
-
try {
|
|
7326
|
-
const item = JSON.parse(line);
|
|
7327
|
-
return this.processStreamItemToChunk(item);
|
|
7328
|
-
} catch {
|
|
7329
|
-
return null;
|
|
7330
|
-
}
|
|
7331
|
-
}
|
|
7332
|
-
processStreamItemToChunk(item) {
|
|
7333
|
-
if (item.type === "result") {
|
|
7334
|
-
return { type: "result", content: item.result || "" };
|
|
7335
|
-
}
|
|
7336
|
-
if (item.type === "stream_event" && item.event) {
|
|
7337
|
-
return this.handleEventToChunk(item.event);
|
|
7338
|
-
}
|
|
7339
|
-
return null;
|
|
7340
|
-
}
|
|
7341
|
-
handleEventToChunk(event) {
|
|
7342
|
-
const { type, delta, content_block, index } = event;
|
|
7343
|
-
if (type === "content_block_delta" && delta?.type === "text_delta") {
|
|
7344
|
-
return { type: "text_delta", content: delta.text || "" };
|
|
7345
|
-
}
|
|
7346
|
-
if (type === "content_block_delta" && delta?.type === "input_json_delta" && delta.partial_json !== undefined && index !== undefined) {
|
|
7347
|
-
const activeTool = this.activeTools.get(index);
|
|
7348
|
-
if (activeTool) {
|
|
7349
|
-
activeTool.parameterJson += delta.partial_json;
|
|
7350
|
-
}
|
|
7351
|
-
return null;
|
|
7352
|
-
}
|
|
7353
|
-
if (type === "content_block_start" && content_block) {
|
|
7354
|
-
if (content_block.type === "tool_use" && content_block.name) {
|
|
7355
|
-
if (index !== undefined) {
|
|
7356
|
-
this.activeTools.set(index, {
|
|
7357
|
-
name: content_block.name,
|
|
7358
|
-
id: content_block.id,
|
|
7359
|
-
index,
|
|
7360
|
-
parameterJson: "",
|
|
7361
|
-
startTime: Date.now()
|
|
7362
|
-
});
|
|
7363
|
-
}
|
|
7364
|
-
return {
|
|
7365
|
-
type: "tool_use",
|
|
7366
|
-
tool: content_block.name,
|
|
7367
|
-
id: content_block.id
|
|
7368
|
-
};
|
|
7369
|
-
}
|
|
7370
|
-
if (content_block.type === "thinking") {
|
|
7371
|
-
return { type: "thinking" };
|
|
7372
|
-
}
|
|
7373
|
-
}
|
|
7374
|
-
if (type === "content_block_stop" && index !== undefined) {
|
|
7375
|
-
const activeTool = this.activeTools.get(index);
|
|
7376
|
-
if (activeTool?.parameterJson) {
|
|
7377
|
-
try {
|
|
7378
|
-
const parameters = JSON.parse(activeTool.parameterJson);
|
|
7379
|
-
return {
|
|
7380
|
-
type: "tool_parameters",
|
|
7381
|
-
tool: activeTool.name,
|
|
7382
|
-
id: activeTool.id,
|
|
7383
|
-
parameters
|
|
7384
|
-
};
|
|
7385
|
-
} catch {}
|
|
7386
|
-
}
|
|
7387
|
-
return null;
|
|
7388
|
-
}
|
|
7389
|
-
return null;
|
|
7390
|
-
}
|
|
7391
7428
|
executeRun(prompt) {
|
|
7392
7429
|
this.aborted = false;
|
|
7430
|
+
const parser = new ClaudeStreamParser;
|
|
7393
7431
|
return new Promise((resolve2, reject) => {
|
|
7394
7432
|
const args = this.buildCliArgs();
|
|
7395
7433
|
const env = getAugmentedEnv({
|
|
@@ -7412,7 +7450,7 @@ class ClaudeRunner {
|
|
|
7412
7450
|
`);
|
|
7413
7451
|
buffer = lines.pop() || "";
|
|
7414
7452
|
for (const line of lines) {
|
|
7415
|
-
const result =
|
|
7453
|
+
const result = parser.parseLine(line, this.log);
|
|
7416
7454
|
if (result)
|
|
7417
7455
|
finalResult = result;
|
|
7418
7456
|
}
|
|
@@ -7453,35 +7491,6 @@ class ClaudeRunner {
|
|
|
7453
7491
|
claude.stdin.end();
|
|
7454
7492
|
});
|
|
7455
7493
|
}
|
|
7456
|
-
handleStreamLine(line) {
|
|
7457
|
-
if (!line.trim())
|
|
7458
|
-
return null;
|
|
7459
|
-
try {
|
|
7460
|
-
const item = JSON.parse(line);
|
|
7461
|
-
return this.processStreamItem(item);
|
|
7462
|
-
} catch {
|
|
7463
|
-
return null;
|
|
7464
|
-
}
|
|
7465
|
-
}
|
|
7466
|
-
processStreamItem(item) {
|
|
7467
|
-
if (item.type === "result") {
|
|
7468
|
-
return item.result || "";
|
|
7469
|
-
}
|
|
7470
|
-
if (item.type === "stream_event" && item.event) {
|
|
7471
|
-
this.handleEvent(item.event);
|
|
7472
|
-
}
|
|
7473
|
-
return null;
|
|
7474
|
-
}
|
|
7475
|
-
handleEvent(event) {
|
|
7476
|
-
const { type, content_block } = event;
|
|
7477
|
-
if (type === "content_block_start" && content_block) {
|
|
7478
|
-
if (content_block.type === "tool_use" && content_block.name) {
|
|
7479
|
-
this.log?.(`
|
|
7480
|
-
${c.primary("[Claude]")} ${c.bold(`Running ${content_block.name}...`)}
|
|
7481
|
-
`, "info");
|
|
7482
|
-
}
|
|
7483
|
-
}
|
|
7484
|
-
}
|
|
7485
7494
|
shouldSuppressLine(line) {
|
|
7486
7495
|
const infoLogRegex = /^\[\d{2}:\d{2}:\d{2}\]\s\[.*?\]\sℹ\s*$/;
|
|
7487
7496
|
return infoLogRegex.test(line.trim());
|
|
@@ -7495,8 +7504,8 @@ ${c.primary("[Claude]")} ${c.bold(`Running ${content_block.name}...`)}
|
|
|
7495
7504
|
var DEFAULT_TIMEOUT_MS;
|
|
7496
7505
|
var init_claude_runner = __esm(() => {
|
|
7497
7506
|
init_config();
|
|
7498
|
-
init_colors();
|
|
7499
7507
|
init_resolve_bin();
|
|
7508
|
+
init_claude_stream_parser();
|
|
7500
7509
|
DEFAULT_TIMEOUT_MS = 60 * 60 * 1000;
|
|
7501
7510
|
});
|
|
7502
7511
|
|
|
@@ -7548,7 +7557,7 @@ class CodexRunner {
|
|
|
7548
7557
|
}
|
|
7549
7558
|
if (attempt < maxRetries) {
|
|
7550
7559
|
const delay = Math.pow(2, attempt) * 1000;
|
|
7551
|
-
|
|
7560
|
+
this.log?.(`Codex CLI attempt ${attempt} failed: ${lastError.message}. Retrying in ${delay}ms...`, "warn");
|
|
7552
7561
|
await this.sleep(delay);
|
|
7553
7562
|
}
|
|
7554
7563
|
}
|
|
@@ -7840,6 +7849,20 @@ var init_codex_runner = __esm(() => {
|
|
|
7840
7849
|
});
|
|
7841
7850
|
|
|
7842
7851
|
// ../sdk/src/ai/factory.ts
|
|
7852
|
+
function createWorkerLogger(agentId, prefix) {
|
|
7853
|
+
const tag = prefix ? `${prefix}:${agentId.slice(-8)}` : agentId.slice(-8);
|
|
7854
|
+
return (message, level = "info") => {
|
|
7855
|
+
const timestamp = new Date().toISOString().split("T")[1]?.slice(0, 8) ?? "";
|
|
7856
|
+
const colorFn = {
|
|
7857
|
+
info: c.cyan,
|
|
7858
|
+
success: c.green,
|
|
7859
|
+
warn: c.yellow,
|
|
7860
|
+
error: c.red
|
|
7861
|
+
}[level];
|
|
7862
|
+
const icon = { info: "ℹ", success: "✓", warn: "⚠", error: "✗" }[level];
|
|
7863
|
+
console.log(`${c.dim(`[${timestamp}]`)} ${c.bold(`[${tag}]`)} ${colorFn(`${icon} ${message}`)}`);
|
|
7864
|
+
};
|
|
7865
|
+
}
|
|
7843
7866
|
function createAiRunner(provider, config) {
|
|
7844
7867
|
const resolvedProvider = provider ?? PROVIDER.CLAUDE;
|
|
7845
7868
|
const model = config.model ?? DEFAULT_MODEL[resolvedProvider];
|
|
@@ -7854,8 +7877,10 @@ function createAiRunner(provider, config) {
|
|
|
7854
7877
|
return new ClaudeRunner(config.projectPath, model, config.log, config.timeoutMs);
|
|
7855
7878
|
}
|
|
7856
7879
|
}
|
|
7880
|
+
var noopLogger = () => {};
|
|
7857
7881
|
var init_factory = __esm(() => {
|
|
7858
7882
|
init_config();
|
|
7883
|
+
init_colors();
|
|
7859
7884
|
init_claude_runner();
|
|
7860
7885
|
init_codex_runner();
|
|
7861
7886
|
});
|
|
@@ -23201,49 +23226,6 @@ var init_docs = __esm(() => {
|
|
|
23201
23226
|
};
|
|
23202
23227
|
});
|
|
23203
23228
|
|
|
23204
|
-
// ../sdk/src/modules/instances.ts
|
|
23205
|
-
var InstancesModule;
|
|
23206
|
-
var init_instances = __esm(() => {
|
|
23207
|
-
InstancesModule = class InstancesModule extends BaseModule {
|
|
23208
|
-
async list(workspaceId) {
|
|
23209
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances`);
|
|
23210
|
-
return data.instances;
|
|
23211
|
-
}
|
|
23212
|
-
async get(workspaceId, instanceId) {
|
|
23213
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances/${instanceId}`);
|
|
23214
|
-
return data.instance;
|
|
23215
|
-
}
|
|
23216
|
-
async provision(workspaceId, body) {
|
|
23217
|
-
const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances`, body);
|
|
23218
|
-
return data.instance;
|
|
23219
|
-
}
|
|
23220
|
-
async performAction(workspaceId, instanceId, action) {
|
|
23221
|
-
const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances/${instanceId}/actions`, { action });
|
|
23222
|
-
return data.instance;
|
|
23223
|
-
}
|
|
23224
|
-
async sync(workspaceId, instanceId) {
|
|
23225
|
-
const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances/${instanceId}/sync`);
|
|
23226
|
-
return data.instance;
|
|
23227
|
-
}
|
|
23228
|
-
async checkUpdates(workspaceId, instanceId) {
|
|
23229
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances/${instanceId}/updates`);
|
|
23230
|
-
return data.update;
|
|
23231
|
-
}
|
|
23232
|
-
async applyUpdate(workspaceId, instanceId) {
|
|
23233
|
-
const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances/${instanceId}/updates`);
|
|
23234
|
-
return data.update;
|
|
23235
|
-
}
|
|
23236
|
-
async getSecurity(workspaceId, instanceId) {
|
|
23237
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances/${instanceId}/security`);
|
|
23238
|
-
return data.rules;
|
|
23239
|
-
}
|
|
23240
|
-
async updateSecurity(workspaceId, instanceId, body) {
|
|
23241
|
-
const { data } = await this.api.put(`/workspaces/${workspaceId}/aws-instances/${instanceId}/security`, body);
|
|
23242
|
-
return data.rules;
|
|
23243
|
-
}
|
|
23244
|
-
};
|
|
23245
|
-
});
|
|
23246
|
-
|
|
23247
23229
|
// ../sdk/src/modules/invitations.ts
|
|
23248
23230
|
var InvitationsModule;
|
|
23249
23231
|
var init_invitations = __esm(() => {
|
|
@@ -37273,7 +37255,7 @@ var init_constants = __esm(() => {
|
|
|
37273
37255
|
});
|
|
37274
37256
|
|
|
37275
37257
|
// ../shared/src/enums.ts
|
|
37276
|
-
var UserRole, MembershipRole, TaskStatus, TaskPriority, AssigneeRole, SprintStatus,
|
|
37258
|
+
var UserRole, MembershipRole, TaskStatus, TaskPriority, AssigneeRole, SprintStatus, EventType;
|
|
37277
37259
|
var init_enums = __esm(() => {
|
|
37278
37260
|
((UserRole2) => {
|
|
37279
37261
|
UserRole2["USER"] = "USER";
|
|
@@ -37310,16 +37292,6 @@ var init_enums = __esm(() => {
|
|
|
37310
37292
|
SprintStatus2["ACTIVE"] = "ACTIVE";
|
|
37311
37293
|
SprintStatus2["COMPLETED"] = "COMPLETED";
|
|
37312
37294
|
})(SprintStatus ||= {});
|
|
37313
|
-
((InstanceStatus2) => {
|
|
37314
|
-
InstanceStatus2["PROVISIONING"] = "PROVISIONING";
|
|
37315
|
-
InstanceStatus2["RUNNING"] = "RUNNING";
|
|
37316
|
-
InstanceStatus2["STOPPED"] = "STOPPED";
|
|
37317
|
-
InstanceStatus2["TERMINATED"] = "TERMINATED";
|
|
37318
|
-
InstanceStatus2["ERROR"] = "ERROR";
|
|
37319
|
-
})(InstanceStatus ||= {});
|
|
37320
|
-
((AwsRegion2) => {
|
|
37321
|
-
AwsRegion2["US_EAST_1"] = "us-east-1";
|
|
37322
|
-
})(AwsRegion ||= {});
|
|
37323
37295
|
((EventType2) => {
|
|
37324
37296
|
EventType2["TASK_CREATED"] = "TASK_CREATED";
|
|
37325
37297
|
EventType2["TASK_UPDATED"] = "TASK_UPDATED";
|
|
@@ -37667,76 +37639,6 @@ var init_auth2 = __esm(() => {
|
|
|
37667
37639
|
});
|
|
37668
37640
|
});
|
|
37669
37641
|
|
|
37670
|
-
// ../shared/src/models/aws-instance.ts
|
|
37671
|
-
var InstanceAction, AwsCredentialsSchema, IntegrationSchema, AwsInstanceSchema, CreateAwsInstanceSchema, UpdateAwsInstanceSchema, SaveAwsCredentialsSchema, ProvisionAwsInstanceSchema, InstanceActionBodySchema, InstanceIdParamSchema, CIDR_REGEX, UpdateSecurityRulesSchema;
|
|
37672
|
-
var init_aws_instance = __esm(() => {
|
|
37673
|
-
init_zod();
|
|
37674
|
-
init_common();
|
|
37675
|
-
init_enums();
|
|
37676
|
-
((InstanceAction2) => {
|
|
37677
|
-
InstanceAction2["START"] = "START";
|
|
37678
|
-
InstanceAction2["STOP"] = "STOP";
|
|
37679
|
-
InstanceAction2["TERMINATE"] = "TERMINATE";
|
|
37680
|
-
})(InstanceAction ||= {});
|
|
37681
|
-
AwsCredentialsSchema = exports_external.object({
|
|
37682
|
-
accessKeyId: exports_external.string().min(1),
|
|
37683
|
-
secretAccessKey: exports_external.string().min(1),
|
|
37684
|
-
region: exports_external.enum(AwsRegion).default("us-east-1" /* US_EAST_1 */)
|
|
37685
|
-
});
|
|
37686
|
-
IntegrationSchema = exports_external.object({
|
|
37687
|
-
name: exports_external.string(),
|
|
37688
|
-
config: exports_external.record(exports_external.string(), exports_external.string())
|
|
37689
|
-
});
|
|
37690
|
-
AwsInstanceSchema = BaseEntitySchema.extend({
|
|
37691
|
-
workspaceId: exports_external.uuid(),
|
|
37692
|
-
instanceId: exports_external.string(),
|
|
37693
|
-
status: exports_external.enum(InstanceStatus),
|
|
37694
|
-
instanceType: exports_external.enum(["t3.micro", "t3.small", "t3.medium"]),
|
|
37695
|
-
region: exports_external.enum(AwsRegion).default("us-east-1" /* US_EAST_1 */),
|
|
37696
|
-
publicIp: exports_external.string().nullable().optional(),
|
|
37697
|
-
launchTime: exports_external.union([exports_external.date(), exports_external.number()]).nullable().optional(),
|
|
37698
|
-
repoUrl: exports_external.string().nullable().optional(),
|
|
37699
|
-
integrations: exports_external.array(IntegrationSchema).default([])
|
|
37700
|
-
});
|
|
37701
|
-
CreateAwsInstanceSchema = exports_external.object({
|
|
37702
|
-
workspaceId: exports_external.uuid(),
|
|
37703
|
-
instanceType: exports_external.enum(["t3.micro", "t3.small", "t3.medium"]).default("t3.micro"),
|
|
37704
|
-
region: exports_external.enum(AwsRegion).default("us-east-1" /* US_EAST_1 */),
|
|
37705
|
-
repoUrl: exports_external.string().optional(),
|
|
37706
|
-
integrations: exports_external.array(IntegrationSchema).optional().default([])
|
|
37707
|
-
});
|
|
37708
|
-
UpdateAwsInstanceSchema = exports_external.object({
|
|
37709
|
-
status: exports_external.enum(InstanceStatus).optional(),
|
|
37710
|
-
instanceType: exports_external.enum(["t3.micro", "t3.small", "t3.medium"]).optional(),
|
|
37711
|
-
publicIp: exports_external.string().nullable().optional(),
|
|
37712
|
-
launchTime: exports_external.union([exports_external.date(), exports_external.number()]).nullable().optional(),
|
|
37713
|
-
repoUrl: exports_external.string().nullable().optional(),
|
|
37714
|
-
integrations: exports_external.array(IntegrationSchema).optional()
|
|
37715
|
-
});
|
|
37716
|
-
SaveAwsCredentialsSchema = exports_external.object({
|
|
37717
|
-
accessKeyId: exports_external.string().min(16),
|
|
37718
|
-
secretAccessKey: exports_external.string().min(1),
|
|
37719
|
-
region: exports_external.string().default("us-east-1")
|
|
37720
|
-
});
|
|
37721
|
-
ProvisionAwsInstanceSchema = exports_external.object({
|
|
37722
|
-
repoUrl: exports_external.string().min(1),
|
|
37723
|
-
githubToken: exports_external.string().min(1),
|
|
37724
|
-
instanceType: exports_external.enum(["t3.micro", "t3.small", "t3.medium"]).default("t3.small"),
|
|
37725
|
-
integrations: exports_external.array(IntegrationSchema).optional().default([])
|
|
37726
|
-
});
|
|
37727
|
-
InstanceActionBodySchema = exports_external.object({
|
|
37728
|
-
action: exports_external.nativeEnum(InstanceAction)
|
|
37729
|
-
});
|
|
37730
|
-
InstanceIdParamSchema = exports_external.object({
|
|
37731
|
-
workspaceId: exports_external.string().uuid("Invalid Workspace ID"),
|
|
37732
|
-
instanceId: exports_external.string().uuid("Invalid Instance ID")
|
|
37733
|
-
});
|
|
37734
|
-
CIDR_REGEX = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}$/;
|
|
37735
|
-
UpdateSecurityRulesSchema = exports_external.object({
|
|
37736
|
-
allowedIps: exports_external.array(exports_external.string().regex(CIDR_REGEX, "Invalid CIDR format (e.g. 1.2.3.4/32)"))
|
|
37737
|
-
});
|
|
37738
|
-
});
|
|
37739
|
-
|
|
37740
37642
|
// ../shared/src/models/ci.ts
|
|
37741
37643
|
var RecordCiSchema;
|
|
37742
37644
|
var init_ci2 = __esm(() => {
|
|
@@ -38124,7 +38026,6 @@ var init_models = __esm(() => {
|
|
|
38124
38026
|
init_activity();
|
|
38125
38027
|
init_agent();
|
|
38126
38028
|
init_auth2();
|
|
38127
|
-
init_aws_instance();
|
|
38128
38029
|
init_ci2();
|
|
38129
38030
|
init_doc();
|
|
38130
38031
|
init_doc_group();
|
|
@@ -38793,17 +38694,6 @@ var init_workspaces = __esm(() => {
|
|
|
38793
38694
|
async deleteApiKey(workspaceId, keyId) {
|
|
38794
38695
|
await this.api.delete(`/workspaces/${workspaceId}/api-keys/${keyId}`);
|
|
38795
38696
|
}
|
|
38796
|
-
async getAwsCredentials(workspaceId) {
|
|
38797
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-credentials`);
|
|
38798
|
-
return data.credential;
|
|
38799
|
-
}
|
|
38800
|
-
async saveAwsCredentials(workspaceId, body) {
|
|
38801
|
-
const { data } = await this.api.put(`/workspaces/${workspaceId}/aws-credentials`, body);
|
|
38802
|
-
return data.credential;
|
|
38803
|
-
}
|
|
38804
|
-
async deleteAwsCredentials(workspaceId) {
|
|
38805
|
-
await this.api.delete(`/workspaces/${workspaceId}/aws-credentials`);
|
|
38806
|
-
}
|
|
38807
38697
|
};
|
|
38808
38698
|
});
|
|
38809
38699
|
|
|
@@ -38852,7 +38742,6 @@ class LocusClient {
|
|
|
38852
38742
|
invitations;
|
|
38853
38743
|
docs;
|
|
38854
38744
|
ci;
|
|
38855
|
-
instances;
|
|
38856
38745
|
constructor(config2) {
|
|
38857
38746
|
this.emitter = new LocusEmitter;
|
|
38858
38747
|
this.api = axios_default.create({
|
|
@@ -38872,7 +38761,6 @@ class LocusClient {
|
|
|
38872
38761
|
this.invitations = new InvitationsModule(this.api, this.emitter);
|
|
38873
38762
|
this.docs = new DocsModule(this.api, this.emitter);
|
|
38874
38763
|
this.ci = new CiModule(this.api, this.emitter);
|
|
38875
|
-
this.instances = new InstancesModule(this.api, this.emitter);
|
|
38876
38764
|
if (config2.retryOptions) {
|
|
38877
38765
|
this.setupRetryInterceptor(config2.retryOptions);
|
|
38878
38766
|
}
|
|
@@ -38938,7 +38826,6 @@ var init_src2 = __esm(() => {
|
|
|
38938
38826
|
init_auth();
|
|
38939
38827
|
init_ci();
|
|
38940
38828
|
init_docs();
|
|
38941
|
-
init_instances();
|
|
38942
38829
|
init_invitations();
|
|
38943
38830
|
init_organizations();
|
|
38944
38831
|
init_sprints();
|
|
@@ -38949,7 +38836,6 @@ var init_src2 = __esm(() => {
|
|
|
38949
38836
|
init_auth();
|
|
38950
38837
|
init_ci();
|
|
38951
38838
|
init_docs();
|
|
38952
|
-
init_instances();
|
|
38953
38839
|
init_invitations();
|
|
38954
38840
|
init_organizations();
|
|
38955
38841
|
init_sprints();
|
|
@@ -38975,9 +38861,11 @@ class ReviewerWorker {
|
|
|
38975
38861
|
currentTaskId = null;
|
|
38976
38862
|
maxReviews = 50;
|
|
38977
38863
|
reviewsCompleted = 0;
|
|
38864
|
+
log;
|
|
38978
38865
|
constructor(config2) {
|
|
38979
38866
|
this.config = config2;
|
|
38980
38867
|
const projectPath = config2.projectPath || process.cwd();
|
|
38868
|
+
this.log = createWorkerLogger(config2.agentId, "R");
|
|
38981
38869
|
this.client = new LocusClient({
|
|
38982
38870
|
baseUrl: config2.apiBase,
|
|
38983
38871
|
token: config2.apiKey,
|
|
@@ -38988,28 +38876,16 @@ class ReviewerWorker {
|
|
|
38988
38876
|
factor: 2
|
|
38989
38877
|
}
|
|
38990
38878
|
});
|
|
38991
|
-
const log = this.log.bind(this);
|
|
38992
38879
|
const provider = config2.provider ?? PROVIDER.CLAUDE;
|
|
38993
38880
|
this.aiRunner = createAiRunner(provider, {
|
|
38994
38881
|
projectPath,
|
|
38995
38882
|
model: config2.model,
|
|
38996
|
-
log
|
|
38883
|
+
log: this.log
|
|
38997
38884
|
});
|
|
38998
|
-
this.prService = new PrService(projectPath, log);
|
|
38885
|
+
this.prService = new PrService(projectPath, this.log);
|
|
38999
38886
|
const providerLabel = provider === "codex" ? "Codex" : "Claude";
|
|
39000
38887
|
this.log(`Reviewer agent using ${providerLabel} CLI`, "info");
|
|
39001
38888
|
}
|
|
39002
|
-
log(message, level = "info") {
|
|
39003
|
-
const timestamp = new Date().toISOString().split("T")[1]?.slice(0, 8) ?? "";
|
|
39004
|
-
const colorFn = {
|
|
39005
|
-
info: c.cyan,
|
|
39006
|
-
success: c.green,
|
|
39007
|
-
warn: c.yellow,
|
|
39008
|
-
error: c.red
|
|
39009
|
-
}[level];
|
|
39010
|
-
const prefix = { info: "ℹ", success: "✓", warn: "⚠", error: "✗" }[level];
|
|
39011
|
-
console.log(`${c.dim(`[${timestamp}]`)} ${c.bold(`[R:${this.config.agentId.slice(-8)}]`)} ${colorFn(`${prefix} ${message}`)}`);
|
|
39012
|
-
}
|
|
39013
38889
|
getNextUnreviewedPr() {
|
|
39014
38890
|
const prs = this.prService.listUnreviewedLocusPrs();
|
|
39015
38891
|
return prs.length > 0 ? prs[0] : null;
|
|
@@ -39129,7 +39005,6 @@ var init_reviewer_worker = __esm(() => {
|
|
|
39129
39005
|
init_git_utils();
|
|
39130
39006
|
init_pr_service();
|
|
39131
39007
|
init_src2();
|
|
39132
|
-
init_colors();
|
|
39133
39008
|
reviewerEntrypoint = process.argv[1]?.split(/[\\/]/).pop();
|
|
39134
39009
|
if (reviewerEntrypoint === "reviewer-worker.js" || reviewerEntrypoint === "reviewer-worker.ts") {
|
|
39135
39010
|
process.title = "locus-reviewer";
|
|
@@ -39758,9 +39633,11 @@ class AgentWorker {
|
|
|
39758
39633
|
currentTaskId = null;
|
|
39759
39634
|
completedTaskList = [];
|
|
39760
39635
|
taskSummaries = [];
|
|
39636
|
+
log;
|
|
39761
39637
|
constructor(config2) {
|
|
39762
39638
|
this.config = config2;
|
|
39763
39639
|
const projectPath = config2.projectPath || process.cwd();
|
|
39640
|
+
this.log = createWorkerLogger(config2.agentId);
|
|
39764
39641
|
this.client = new LocusClient({
|
|
39765
39642
|
baseUrl: config2.apiBase,
|
|
39766
39643
|
token: config2.apiKey,
|
|
@@ -39771,7 +39648,6 @@ class AgentWorker {
|
|
|
39771
39648
|
factor: 2
|
|
39772
39649
|
}
|
|
39773
39650
|
});
|
|
39774
|
-
const log = this.log.bind(this);
|
|
39775
39651
|
if (!isGitAvailable()) {
|
|
39776
39652
|
this.log("git is not installed — branch management will not work", "error");
|
|
39777
39653
|
}
|
|
@@ -39782,29 +39658,18 @@ class AgentWorker {
|
|
|
39782
39658
|
this.aiRunner = createAiRunner(provider, {
|
|
39783
39659
|
projectPath,
|
|
39784
39660
|
model: config2.model,
|
|
39785
|
-
log,
|
|
39661
|
+
log: this.log,
|
|
39786
39662
|
reasoningEffort: config2.reasoningEffort
|
|
39787
39663
|
});
|
|
39788
39664
|
this.taskExecutor = new TaskExecutor({
|
|
39789
39665
|
aiRunner: this.aiRunner,
|
|
39790
39666
|
projectPath,
|
|
39791
|
-
log
|
|
39667
|
+
log: this.log
|
|
39792
39668
|
});
|
|
39793
|
-
this.gitWorkflow = new GitWorkflow(config2, log);
|
|
39669
|
+
this.gitWorkflow = new GitWorkflow(config2, this.log);
|
|
39794
39670
|
const providerLabel = provider === "codex" ? "Codex" : "Claude";
|
|
39795
39671
|
this.log(`Using ${providerLabel} CLI for all phases`, "info");
|
|
39796
39672
|
}
|
|
39797
|
-
log(message, level = "info") {
|
|
39798
|
-
const timestamp = new Date().toISOString().split("T")[1]?.slice(0, 8) ?? "";
|
|
39799
|
-
const colorFn = {
|
|
39800
|
-
info: c.cyan,
|
|
39801
|
-
success: c.green,
|
|
39802
|
-
warn: c.yellow,
|
|
39803
|
-
error: c.red
|
|
39804
|
-
}[level];
|
|
39805
|
-
const prefix = { info: "ℹ", success: "✓", warn: "⚠", error: "✗" }[level];
|
|
39806
|
-
console.log(`${c.dim(`[${timestamp}]`)} ${c.bold(`[${this.config.agentId.slice(-8)}]`)} ${colorFn(`${prefix} ${message}`)}`);
|
|
39807
|
-
}
|
|
39808
39673
|
async getActiveSprint() {
|
|
39809
39674
|
try {
|
|
39810
39675
|
if (this.config.sprintId) {
|
|
@@ -39981,7 +39846,6 @@ var init_worker = __esm(() => {
|
|
|
39981
39846
|
init_config();
|
|
39982
39847
|
init_git_utils();
|
|
39983
39848
|
init_src2();
|
|
39984
|
-
init_colors();
|
|
39985
39849
|
init_git_workflow();
|
|
39986
39850
|
init_task_executor();
|
|
39987
39851
|
workerEntrypoint = process.argv[1]?.split(/[\\/]/).pop();
|
|
@@ -40012,6 +39876,7 @@ var init_agent2 = __esm(() => {
|
|
|
40012
39876
|
// ../sdk/src/ai/index.ts
|
|
40013
39877
|
var init_ai = __esm(() => {
|
|
40014
39878
|
init_claude_runner();
|
|
39879
|
+
init_claude_stream_parser();
|
|
40015
39880
|
init_codex_runner();
|
|
40016
39881
|
init_factory();
|
|
40017
39882
|
});
|
|
@@ -40183,9 +40048,7 @@ class DiscussionFacilitator {
|
|
|
40183
40048
|
this.projectPath = config2.projectPath;
|
|
40184
40049
|
this.aiRunner = config2.aiRunner;
|
|
40185
40050
|
this.discussionManager = config2.discussionManager;
|
|
40186
|
-
this.log = config2.log ??
|
|
40187
|
-
return;
|
|
40188
|
-
});
|
|
40051
|
+
this.log = config2.log ?? noopLogger;
|
|
40189
40052
|
this.provider = config2.provider;
|
|
40190
40053
|
this.model = config2.model;
|
|
40191
40054
|
}
|
|
@@ -40356,6 +40219,7 @@ If you need more information about the project strategies, plans, or architectur
|
|
|
40356
40219
|
}
|
|
40357
40220
|
}
|
|
40358
40221
|
var init_discussion_facilitator = __esm(() => {
|
|
40222
|
+
init_factory();
|
|
40359
40223
|
init_config();
|
|
40360
40224
|
});
|
|
40361
40225
|
|
|
@@ -41843,9 +41707,7 @@ class PlanningMeeting {
|
|
|
41843
41707
|
constructor(config2) {
|
|
41844
41708
|
this.projectPath = config2.projectPath;
|
|
41845
41709
|
this.aiRunner = config2.aiRunner;
|
|
41846
|
-
this.log = config2.log ??
|
|
41847
|
-
return;
|
|
41848
|
-
});
|
|
41710
|
+
this.log = config2.log ?? noopLogger;
|
|
41849
41711
|
}
|
|
41850
41712
|
async run(directive, feedback) {
|
|
41851
41713
|
this.log("Planning sprint...", "info");
|
|
@@ -41885,6 +41747,7 @@ class PlanningMeeting {
|
|
|
41885
41747
|
}
|
|
41886
41748
|
}
|
|
41887
41749
|
var init_planning_meeting = __esm(() => {
|
|
41750
|
+
init_factory();
|
|
41888
41751
|
init_config();
|
|
41889
41752
|
});
|
|
41890
41753
|
|
|
@@ -41911,24 +41774,313 @@ var init_index_node = __esm(() => {
|
|
|
41911
41774
|
init_planning();
|
|
41912
41775
|
});
|
|
41913
41776
|
|
|
41777
|
+
// ../commands/src/config.ts
|
|
41778
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
41779
|
+
import { join as join12 } from "node:path";
|
|
41780
|
+
function isProjectInitialized(projectPath) {
|
|
41781
|
+
const locusDir = join12(projectPath, LOCUS_CONFIG.dir);
|
|
41782
|
+
const configPath = join12(locusDir, LOCUS_CONFIG.configFile);
|
|
41783
|
+
return existsSync12(locusDir) && existsSync12(configPath);
|
|
41784
|
+
}
|
|
41785
|
+
function resolveProvider3(input) {
|
|
41786
|
+
if (!input)
|
|
41787
|
+
return PROVIDER.CLAUDE;
|
|
41788
|
+
if (input === PROVIDER.CLAUDE || input === PROVIDER.CODEX)
|
|
41789
|
+
return input;
|
|
41790
|
+
throw new Error(`Invalid provider '${input}'. Must be 'claude' or 'codex'.`);
|
|
41791
|
+
}
|
|
41792
|
+
function maskSecret(value) {
|
|
41793
|
+
if (value.length <= 8)
|
|
41794
|
+
return "****";
|
|
41795
|
+
return `${value.slice(0, 4)}...${value.slice(-4)}`;
|
|
41796
|
+
}
|
|
41797
|
+
var init_config2 = __esm(() => {
|
|
41798
|
+
init_index_node();
|
|
41799
|
+
});
|
|
41800
|
+
|
|
41801
|
+
// ../commands/src/settings.ts
|
|
41802
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "node:fs";
|
|
41803
|
+
import { join as join13 } from "node:path";
|
|
41804
|
+
function getSettingsPath(projectPath) {
|
|
41805
|
+
return join13(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG.settingsFile);
|
|
41806
|
+
}
|
|
41807
|
+
|
|
41808
|
+
class SettingsManager {
|
|
41809
|
+
projectPath;
|
|
41810
|
+
constructor(projectPath) {
|
|
41811
|
+
this.projectPath = projectPath;
|
|
41812
|
+
}
|
|
41813
|
+
load() {
|
|
41814
|
+
const settingsPath = getSettingsPath(this.projectPath);
|
|
41815
|
+
if (!existsSync13(settingsPath)) {
|
|
41816
|
+
return {};
|
|
41817
|
+
}
|
|
41818
|
+
return JSON.parse(readFileSync11(settingsPath, "utf-8"));
|
|
41819
|
+
}
|
|
41820
|
+
save(settings) {
|
|
41821
|
+
const { $schema: _2, ...rest } = settings;
|
|
41822
|
+
const ordered = { $schema: LOCUS_SCHEMAS.settings, ...rest };
|
|
41823
|
+
const settingsPath = getSettingsPath(this.projectPath);
|
|
41824
|
+
writeFileSync6(settingsPath, JSON.stringify(ordered, null, 2), "utf-8");
|
|
41825
|
+
}
|
|
41826
|
+
get(key) {
|
|
41827
|
+
return this.load()[key];
|
|
41828
|
+
}
|
|
41829
|
+
set(key, value) {
|
|
41830
|
+
const settings = this.load();
|
|
41831
|
+
settings[key] = value;
|
|
41832
|
+
this.save(settings);
|
|
41833
|
+
}
|
|
41834
|
+
remove() {
|
|
41835
|
+
const settingsPath = getSettingsPath(this.projectPath);
|
|
41836
|
+
if (existsSync13(settingsPath)) {
|
|
41837
|
+
unlinkSync4(settingsPath);
|
|
41838
|
+
}
|
|
41839
|
+
}
|
|
41840
|
+
exists() {
|
|
41841
|
+
return existsSync13(getSettingsPath(this.projectPath));
|
|
41842
|
+
}
|
|
41843
|
+
}
|
|
41844
|
+
var init_settings = __esm(() => {
|
|
41845
|
+
init_index_node();
|
|
41846
|
+
});
|
|
41847
|
+
|
|
41848
|
+
// ../commands/src/logger.ts
|
|
41849
|
+
function createCliLogger() {
|
|
41850
|
+
return (message, level) => {
|
|
41851
|
+
const icon = level === "success" ? c.success("✔") : level === "error" ? c.error("✖") : level === "warn" ? c.warning("!") : c.info("●");
|
|
41852
|
+
console.log(` ${icon} ${message}`);
|
|
41853
|
+
};
|
|
41854
|
+
}
|
|
41855
|
+
var init_logger = __esm(() => {
|
|
41856
|
+
init_index_node();
|
|
41857
|
+
init_index_node();
|
|
41858
|
+
});
|
|
41859
|
+
|
|
41860
|
+
// ../commands/src/workspace.ts
|
|
41861
|
+
class WorkspaceResolver {
|
|
41862
|
+
options;
|
|
41863
|
+
constructor(options) {
|
|
41864
|
+
this.options = options;
|
|
41865
|
+
}
|
|
41866
|
+
async resolve() {
|
|
41867
|
+
if (this.options.workspaceId) {
|
|
41868
|
+
return this.options.workspaceId;
|
|
41869
|
+
}
|
|
41870
|
+
const log = this.options.log ?? noopLogger;
|
|
41871
|
+
try {
|
|
41872
|
+
log("Resolving workspace from API key...");
|
|
41873
|
+
const client = new LocusClient({
|
|
41874
|
+
baseUrl: this.options.apiBase,
|
|
41875
|
+
token: this.options.apiKey
|
|
41876
|
+
});
|
|
41877
|
+
const info = await client.auth.getApiKeyInfo();
|
|
41878
|
+
if (info.workspaceId) {
|
|
41879
|
+
log(`Resolved workspace: ${info.workspaceId}`);
|
|
41880
|
+
return info.workspaceId;
|
|
41881
|
+
}
|
|
41882
|
+
throw new Error("API key is not associated with a workspace. Please specify a workspace ID.");
|
|
41883
|
+
} catch (error48) {
|
|
41884
|
+
if (error48 instanceof Error && error48.message.includes("API key is not")) {
|
|
41885
|
+
throw error48;
|
|
41886
|
+
}
|
|
41887
|
+
throw new Error(`Error resolving workspace: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
41888
|
+
}
|
|
41889
|
+
}
|
|
41890
|
+
}
|
|
41891
|
+
var init_workspace2 = __esm(() => {
|
|
41892
|
+
init_src2();
|
|
41893
|
+
init_logger();
|
|
41894
|
+
});
|
|
41895
|
+
|
|
41896
|
+
// ../commands/src/api-context.ts
|
|
41897
|
+
async function resolveApiContext(options) {
|
|
41898
|
+
const settings = new SettingsManager(options.projectPath).load();
|
|
41899
|
+
const apiKey = options.apiKey || settings.apiKey;
|
|
41900
|
+
if (!apiKey) {
|
|
41901
|
+
throw new Error("API key is required. Configure with: locus config setup --api-key <key>");
|
|
41902
|
+
}
|
|
41903
|
+
const apiBase = options.apiUrl || settings.apiUrl || DEFAULT_API_BASE;
|
|
41904
|
+
const resolver = new WorkspaceResolver({
|
|
41905
|
+
apiKey,
|
|
41906
|
+
apiBase,
|
|
41907
|
+
workspaceId: options.workspaceId
|
|
41908
|
+
});
|
|
41909
|
+
const workspaceId = await resolver.resolve();
|
|
41910
|
+
const client = new LocusClient({
|
|
41911
|
+
baseUrl: apiBase,
|
|
41912
|
+
token: apiKey
|
|
41913
|
+
});
|
|
41914
|
+
return { client, workspaceId, apiKey, apiBase };
|
|
41915
|
+
}
|
|
41916
|
+
function resolveAiSettings(options) {
|
|
41917
|
+
const settings = new SettingsManager(options.projectPath).load();
|
|
41918
|
+
const provider = resolveProvider3(options.provider || settings.provider);
|
|
41919
|
+
const model = options.model || settings.model || DEFAULT_MODEL[provider];
|
|
41920
|
+
return { provider, model };
|
|
41921
|
+
}
|
|
41922
|
+
var DEFAULT_API_BASE = "https://api.locusai.dev/api";
|
|
41923
|
+
var init_api_context = __esm(() => {
|
|
41924
|
+
init_src2();
|
|
41925
|
+
init_index_node();
|
|
41926
|
+
init_config2();
|
|
41927
|
+
init_settings();
|
|
41928
|
+
init_workspace2();
|
|
41929
|
+
});
|
|
41930
|
+
|
|
41931
|
+
// ../commands/src/artifacts.ts
|
|
41932
|
+
import { existsSync as existsSync14, readdirSync as readdirSync5, readFileSync as readFileSync12, statSync } from "node:fs";
|
|
41933
|
+
import { join as join14 } from "node:path";
|
|
41934
|
+
function listArtifacts(projectPath) {
|
|
41935
|
+
const artifactsDir = getLocusPath(projectPath, "artifactsDir");
|
|
41936
|
+
if (!existsSync14(artifactsDir)) {
|
|
41937
|
+
return [];
|
|
41938
|
+
}
|
|
41939
|
+
const files = readdirSync5(artifactsDir).filter((f) => f.endsWith(".md"));
|
|
41940
|
+
return files.map((fileName) => {
|
|
41941
|
+
const filePath = join14(artifactsDir, fileName);
|
|
41942
|
+
const stat = statSync(filePath);
|
|
41943
|
+
const name = fileName.replace(/\.md$/, "");
|
|
41944
|
+
return {
|
|
41945
|
+
name,
|
|
41946
|
+
fileName,
|
|
41947
|
+
createdAt: stat.birthtime,
|
|
41948
|
+
size: stat.size
|
|
41949
|
+
};
|
|
41950
|
+
}).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
41951
|
+
}
|
|
41952
|
+
function readArtifact(projectPath, name) {
|
|
41953
|
+
const artifactsDir = getLocusPath(projectPath, "artifactsDir");
|
|
41954
|
+
const fileName = name.endsWith(".md") ? name : `${name}.md`;
|
|
41955
|
+
const filePath = join14(artifactsDir, fileName);
|
|
41956
|
+
if (!existsSync14(filePath)) {
|
|
41957
|
+
return null;
|
|
41958
|
+
}
|
|
41959
|
+
const stat = statSync(filePath);
|
|
41960
|
+
const content = readFileSync12(filePath, "utf-8");
|
|
41961
|
+
return {
|
|
41962
|
+
content,
|
|
41963
|
+
info: {
|
|
41964
|
+
name: fileName.replace(/\.md$/, ""),
|
|
41965
|
+
fileName,
|
|
41966
|
+
createdAt: stat.birthtime,
|
|
41967
|
+
size: stat.size
|
|
41968
|
+
}
|
|
41969
|
+
};
|
|
41970
|
+
}
|
|
41971
|
+
function findArtifact(projectPath, name) {
|
|
41972
|
+
const exact = readArtifact(projectPath, name);
|
|
41973
|
+
if (exact) {
|
|
41974
|
+
return { match: true, content: exact.content, info: exact.info };
|
|
41975
|
+
}
|
|
41976
|
+
const artifacts = listArtifacts(projectPath);
|
|
41977
|
+
const matches = artifacts.filter((a) => a.name.toLowerCase().includes(name.toLowerCase()));
|
|
41978
|
+
if (matches.length === 1) {
|
|
41979
|
+
const result = readArtifact(projectPath, matches[0].name);
|
|
41980
|
+
if (result) {
|
|
41981
|
+
return { match: true, content: result.content, info: result.info };
|
|
41982
|
+
}
|
|
41983
|
+
}
|
|
41984
|
+
if (matches.length > 1) {
|
|
41985
|
+
return { match: false, ambiguous: matches };
|
|
41986
|
+
}
|
|
41987
|
+
return null;
|
|
41988
|
+
}
|
|
41989
|
+
function formatSize(bytes) {
|
|
41990
|
+
if (bytes < 1024)
|
|
41991
|
+
return `${bytes}B`;
|
|
41992
|
+
const kb = bytes / 1024;
|
|
41993
|
+
if (kb < 1024)
|
|
41994
|
+
return `${kb.toFixed(1)}KB`;
|
|
41995
|
+
const mb = kb / 1024;
|
|
41996
|
+
return `${mb.toFixed(1)}MB`;
|
|
41997
|
+
}
|
|
41998
|
+
function formatDate(date5) {
|
|
41999
|
+
return date5.toLocaleDateString("en-US", {
|
|
42000
|
+
year: "numeric",
|
|
42001
|
+
month: "short",
|
|
42002
|
+
day: "numeric",
|
|
42003
|
+
hour: "2-digit",
|
|
42004
|
+
minute: "2-digit"
|
|
42005
|
+
});
|
|
42006
|
+
}
|
|
42007
|
+
var init_artifacts = __esm(() => {
|
|
42008
|
+
init_index_node();
|
|
42009
|
+
});
|
|
42010
|
+
|
|
42011
|
+
// ../commands/src/discussions.ts
|
|
42012
|
+
function listDiscussions(manager) {
|
|
42013
|
+
const discussions = manager.list();
|
|
42014
|
+
return discussions.map((d) => ({
|
|
42015
|
+
id: d.id,
|
|
42016
|
+
title: d.title,
|
|
42017
|
+
status: d.status,
|
|
42018
|
+
messageCount: d.messages.length,
|
|
42019
|
+
insightCount: d.insights.length,
|
|
42020
|
+
createdAt: d.createdAt
|
|
42021
|
+
}));
|
|
42022
|
+
}
|
|
42023
|
+
function showDiscussion(manager, id) {
|
|
42024
|
+
return manager.getMarkdown(id);
|
|
42025
|
+
}
|
|
42026
|
+
function archiveDiscussion(manager, id) {
|
|
42027
|
+
manager.archive(id);
|
|
42028
|
+
}
|
|
42029
|
+
function deleteDiscussion(manager, id) {
|
|
42030
|
+
manager.delete(id);
|
|
42031
|
+
}
|
|
42032
|
+
|
|
42033
|
+
// ../commands/src/plans.ts
|
|
42034
|
+
function listPlans(manager, status) {
|
|
42035
|
+
const plans = manager.list(status);
|
|
42036
|
+
return plans.map((p) => ({
|
|
42037
|
+
id: p.id,
|
|
42038
|
+
name: p.name,
|
|
42039
|
+
status: p.status,
|
|
42040
|
+
taskCount: p.tasks.length,
|
|
42041
|
+
directive: p.directive,
|
|
42042
|
+
createdAt: p.createdAt,
|
|
42043
|
+
feedback: p.feedback
|
|
42044
|
+
}));
|
|
42045
|
+
}
|
|
42046
|
+
function showPlan(manager, idOrSlug) {
|
|
42047
|
+
return manager.getMarkdown(idOrSlug);
|
|
42048
|
+
}
|
|
42049
|
+
function cancelPlan(manager, idOrSlug) {
|
|
42050
|
+
manager.cancel(idOrSlug);
|
|
42051
|
+
}
|
|
42052
|
+
function rejectPlan(manager, idOrSlug, feedback) {
|
|
42053
|
+
return manager.reject(idOrSlug, feedback);
|
|
42054
|
+
}
|
|
42055
|
+
|
|
42056
|
+
// ../commands/src/index.ts
|
|
42057
|
+
var init_src3 = __esm(() => {
|
|
42058
|
+
init_api_context();
|
|
42059
|
+
init_artifacts();
|
|
42060
|
+
init_config2();
|
|
42061
|
+
init_logger();
|
|
42062
|
+
init_settings();
|
|
42063
|
+
init_workspace2();
|
|
42064
|
+
});
|
|
42065
|
+
|
|
41914
42066
|
// src/utils/version.ts
|
|
41915
|
-
import { existsSync as
|
|
41916
|
-
import { dirname as dirname3, join as
|
|
42067
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "node:fs";
|
|
42068
|
+
import { dirname as dirname3, join as join15 } from "node:path";
|
|
41917
42069
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
41918
42070
|
function getVersion() {
|
|
41919
42071
|
try {
|
|
41920
42072
|
const __filename2 = fileURLToPath3(import.meta.url);
|
|
41921
42073
|
const __dirname2 = dirname3(__filename2);
|
|
41922
|
-
const bundledPath =
|
|
41923
|
-
const sourcePath =
|
|
41924
|
-
if (
|
|
41925
|
-
const pkg = JSON.parse(
|
|
42074
|
+
const bundledPath = join15(__dirname2, "..", "package.json");
|
|
42075
|
+
const sourcePath = join15(__dirname2, "..", "..", "package.json");
|
|
42076
|
+
if (existsSync15(bundledPath)) {
|
|
42077
|
+
const pkg = JSON.parse(readFileSync13(bundledPath, "utf-8"));
|
|
41926
42078
|
if (pkg.name === "@locusai/cli") {
|
|
41927
42079
|
return pkg.version || "0.0.0";
|
|
41928
42080
|
}
|
|
41929
42081
|
}
|
|
41930
|
-
if (
|
|
41931
|
-
const pkg = JSON.parse(
|
|
42082
|
+
if (existsSync15(sourcePath)) {
|
|
42083
|
+
const pkg = JSON.parse(readFileSync13(sourcePath, "utf-8"));
|
|
41932
42084
|
if (pkg.name === "@locusai/cli") {
|
|
41933
42085
|
return pkg.version || "0.0.0";
|
|
41934
42086
|
}
|
|
@@ -41957,13 +42109,6 @@ var init_banner = __esm(() => {
|
|
|
41957
42109
|
});
|
|
41958
42110
|
|
|
41959
42111
|
// src/utils/helpers.ts
|
|
41960
|
-
import { existsSync as existsSync13 } from "node:fs";
|
|
41961
|
-
import { join as join13 } from "node:path";
|
|
41962
|
-
function isProjectInitialized(projectPath) {
|
|
41963
|
-
const locusDir = join13(projectPath, LOCUS_CONFIG.dir);
|
|
41964
|
-
const configPath = join13(locusDir, LOCUS_CONFIG.configFile);
|
|
41965
|
-
return existsSync13(locusDir) && existsSync13(configPath);
|
|
41966
|
-
}
|
|
41967
42112
|
function requireInitialization(projectPath, command) {
|
|
41968
42113
|
if (!isProjectInitialized(projectPath)) {
|
|
41969
42114
|
console.error(`
|
|
@@ -41979,15 +42124,16 @@ function requireInitialization(projectPath, command) {
|
|
|
41979
42124
|
process.exit(1);
|
|
41980
42125
|
}
|
|
41981
42126
|
}
|
|
41982
|
-
function
|
|
41983
|
-
|
|
41984
|
-
return
|
|
41985
|
-
|
|
41986
|
-
|
|
41987
|
-
|
|
41988
|
-
|
|
42127
|
+
function resolveProvider4(input) {
|
|
42128
|
+
try {
|
|
42129
|
+
return resolveProvider3(input);
|
|
42130
|
+
} catch {
|
|
42131
|
+
console.error(c.error(`Error: invalid provider '${input}'. Use 'claude' or 'codex'.`));
|
|
42132
|
+
process.exit(1);
|
|
42133
|
+
}
|
|
41989
42134
|
}
|
|
41990
42135
|
var init_helpers2 = __esm(() => {
|
|
42136
|
+
init_src3();
|
|
41991
42137
|
init_index_node();
|
|
41992
42138
|
});
|
|
41993
42139
|
|
|
@@ -41998,17 +42144,107 @@ var init_utils3 = __esm(() => {
|
|
|
41998
42144
|
init_version();
|
|
41999
42145
|
});
|
|
42000
42146
|
|
|
42001
|
-
// src/
|
|
42147
|
+
// src/templates.ts
|
|
42148
|
+
var LOCUS_GITIGNORE_MARKER = "# Locus AI", LOCUS_MD_TEMPLATE = `## Planning First
|
|
42149
|
+
|
|
42150
|
+
Complex tasks must be planned before writing code. Create ".locus/plans/<task-name>.md" with:
|
|
42151
|
+
- **Goal**: What we're trying to achieve and why
|
|
42152
|
+
- **Approach**: Step-by-step strategy with technical decisions
|
|
42153
|
+
- **Affected files**: List of files to create/modify/delete
|
|
42154
|
+
- **Acceptance criteria**: Specific, testable conditions for completion
|
|
42155
|
+
- **Dependencies**: Required packages, APIs, or external services
|
|
42156
|
+
|
|
42157
|
+
Delete the planning .md files after successful execution.
|
|
42158
|
+
|
|
42159
|
+
## Code Quality
|
|
42160
|
+
|
|
42161
|
+
- **Follow existing patterns**: Run formatters and linters before finishing (check "package.json" scripts or project config)
|
|
42162
|
+
- **Minimize changes**: Keep modifications atomic. Separate refactors from behavioral changes into different tasks
|
|
42163
|
+
- **Never commit secrets**: No API keys, passwords, or credentials in code. Use environment variables or secret management
|
|
42164
|
+
- **Test as you go**: If tests exist, run relevant ones. If breaking changes occur, update tests accordingly
|
|
42165
|
+
- **Comment complex logic**: Explain *why*, not *what*. Focus on business logic and non-obvious decisions
|
|
42166
|
+
|
|
42167
|
+
## Artifacts
|
|
42168
|
+
|
|
42169
|
+
When a task produces knowledge, analysis, or research output rather than (or in addition to) code changes, you **must** save results as Markdown in ".locus/artifacts/<descriptive-name>.md":
|
|
42170
|
+
|
|
42171
|
+
**Always create artifacts for:**
|
|
42172
|
+
- Code quality audits, security reviews, vulnerability assessments
|
|
42173
|
+
- Architecture analyses, system design proposals, or recommendations
|
|
42174
|
+
- Dependency reports, performance profiling, benchmarking results
|
|
42175
|
+
- Research summaries, technology comparisons, or feasibility studies
|
|
42176
|
+
- Migration plans, deployment strategies, or rollback procedures
|
|
42177
|
+
- Post-mortems, incident analysis, or debugging investigations
|
|
42178
|
+
|
|
42179
|
+
**Artifact structure:**
|
|
42180
|
+
- Clear title and date
|
|
42181
|
+
- Executive summary (2-3 sentences)
|
|
42182
|
+
- Detailed findings/analysis
|
|
42183
|
+
- Actionable recommendations (if applicable)
|
|
42184
|
+
|
|
42185
|
+
## Git Operations
|
|
42186
|
+
|
|
42187
|
+
- **Do NOT run**: git add, git commit, git push, git checkout, git branch, or any git commands
|
|
42188
|
+
- **Why**: The Locus orchestrator handles all version control automatically after execution
|
|
42189
|
+
- **Your role**: Focus solely on making file changes. The system commits, pushes, and creates PRs
|
|
42190
|
+
|
|
42191
|
+
## Continuous Learning
|
|
42192
|
+
|
|
42193
|
+
Read ".locus/LEARNINGS.md" **before starting any task** to avoid repeating mistakes.
|
|
42194
|
+
|
|
42195
|
+
**When to update:**
|
|
42196
|
+
- User corrects your approach or provides guidance
|
|
42197
|
+
- You discover a better pattern while working
|
|
42198
|
+
- A decision prevents future confusion (e.g., "use X not Y because Z")
|
|
42199
|
+
- You encounter and solve a tricky problem
|
|
42200
|
+
|
|
42201
|
+
**What to record:**
|
|
42202
|
+
- Architectural decisions and their rationale
|
|
42203
|
+
- Preferred libraries, tools, or patterns for this project
|
|
42204
|
+
- Common pitfalls and how to avoid them
|
|
42205
|
+
- Project-specific conventions or user preferences
|
|
42206
|
+
- Solutions to non-obvious problems
|
|
42207
|
+
|
|
42208
|
+
**Format (append-only, never delete):**
|
|
42209
|
+
|
|
42210
|
+
"""
|
|
42211
|
+
- **[Category]**: Concise description (1-2 lines max). *Context if needed.*
|
|
42212
|
+
"""
|
|
42213
|
+
|
|
42214
|
+
**Categories:** Architecture, Dependencies, Patterns, Debugging, Performance, Security, DevOps, User Preferences
|
|
42215
|
+
|
|
42216
|
+
## Error Handling
|
|
42217
|
+
|
|
42218
|
+
- **Read error messages carefully**: Don't guess. Parse the actual error before proposing fixes
|
|
42219
|
+
- **Check dependencies first**: Missing packages, wrong versions, and environment issues are common
|
|
42220
|
+
- **Verify assumptions**: If something "should work," confirm it actually does in this environment
|
|
42221
|
+
- **Ask for context**: If you need environment details, configuration, or logs, request them explicitly
|
|
42222
|
+
|
|
42223
|
+
## Communication
|
|
42224
|
+
|
|
42225
|
+
- **Be precise**: When uncertain, state what you know and what you're assuming
|
|
42226
|
+
- **Show your work**: For complex changes, briefly explain the approach before executing
|
|
42227
|
+
- **Highlight trade-offs**: If multiple approaches exist, note why you chose one over others
|
|
42228
|
+
- **Request feedback**: For ambiguous requirements, propose an approach and ask for confirmation
|
|
42229
|
+
`, DEFAULT_LEARNINGS_MD = `# Learnings
|
|
42230
|
+
|
|
42231
|
+
This file captures important lessons, decisions, and corrections made during development.
|
|
42232
|
+
It is read by AI agents before every task to avoid repeating mistakes and to follow established patterns.
|
|
42233
|
+
|
|
42234
|
+
<!-- Add learnings below this line. Format: - **[Category]**: Description -->
|
|
42235
|
+
`;
|
|
42236
|
+
|
|
42237
|
+
// src/git-helpers.ts
|
|
42002
42238
|
import { execSync as execSync2 } from "node:child_process";
|
|
42003
|
-
import { existsSync as
|
|
42004
|
-
import { join as
|
|
42239
|
+
import { existsSync as existsSync16, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "node:fs";
|
|
42240
|
+
import { join as join16 } from "node:path";
|
|
42005
42241
|
function updateGitignore(projectPath) {
|
|
42006
|
-
const gitignorePath =
|
|
42242
|
+
const gitignorePath = join16(projectPath, ".gitignore");
|
|
42007
42243
|
let content = "";
|
|
42008
42244
|
const locusBlock = LOCUS_GITIGNORE_PATTERNS.join(`
|
|
42009
42245
|
`);
|
|
42010
|
-
if (
|
|
42011
|
-
content =
|
|
42246
|
+
if (existsSync16(gitignorePath)) {
|
|
42247
|
+
content = readFileSync14(gitignorePath, "utf-8");
|
|
42012
42248
|
if (content.includes(LOCUS_GITIGNORE_MARKER)) {
|
|
42013
42249
|
const lines = content.split(`
|
|
42014
42250
|
`);
|
|
@@ -42025,7 +42261,7 @@ function updateGitignore(projectPath) {
|
|
|
42025
42261
|
const after = lines.slice(endIdx + 1);
|
|
42026
42262
|
content = [...before, locusBlock, ...after].join(`
|
|
42027
42263
|
`);
|
|
42028
|
-
|
|
42264
|
+
writeFileSync7(gitignorePath, content);
|
|
42029
42265
|
return;
|
|
42030
42266
|
}
|
|
42031
42267
|
if (content.length > 0 && !content.endsWith(`
|
|
@@ -42040,7 +42276,7 @@ function updateGitignore(projectPath) {
|
|
|
42040
42276
|
}
|
|
42041
42277
|
content += `${locusBlock}
|
|
42042
42278
|
`;
|
|
42043
|
-
|
|
42279
|
+
writeFileSync7(gitignorePath, content);
|
|
42044
42280
|
}
|
|
42045
42281
|
function ensureGitIdentity(projectPath) {
|
|
42046
42282
|
const hasName = (() => {
|
|
@@ -42080,6 +42316,13 @@ function ensureGitIdentity(projectPath) {
|
|
|
42080
42316
|
stdio: "ignore"
|
|
42081
42317
|
});
|
|
42082
42318
|
}
|
|
42319
|
+
var init_git_helpers = __esm(() => {
|
|
42320
|
+
init_index_node();
|
|
42321
|
+
});
|
|
42322
|
+
|
|
42323
|
+
// src/config-manager.ts
|
|
42324
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
|
|
42325
|
+
import { join as join17 } from "node:path";
|
|
42083
42326
|
|
|
42084
42327
|
class ConfigManager {
|
|
42085
42328
|
projectPath;
|
|
@@ -42087,9 +42330,9 @@ class ConfigManager {
|
|
|
42087
42330
|
this.projectPath = projectPath;
|
|
42088
42331
|
}
|
|
42089
42332
|
async init(version2) {
|
|
42090
|
-
const locusConfigDir =
|
|
42333
|
+
const locusConfigDir = join17(this.projectPath, LOCUS_CONFIG.dir);
|
|
42091
42334
|
const locusConfigPath = getLocusPath(this.projectPath, "configFile");
|
|
42092
|
-
if (!
|
|
42335
|
+
if (!existsSync17(locusConfigDir)) {
|
|
42093
42336
|
mkdirSync7(locusConfigDir, { recursive: true });
|
|
42094
42337
|
}
|
|
42095
42338
|
const locusSubdirs = [
|
|
@@ -42101,35 +42344,35 @@ class ConfigManager {
|
|
|
42101
42344
|
LOCUS_CONFIG.discussionsDir
|
|
42102
42345
|
];
|
|
42103
42346
|
for (const subdir of locusSubdirs) {
|
|
42104
|
-
const subdirPath =
|
|
42105
|
-
if (!
|
|
42347
|
+
const subdirPath = join17(locusConfigDir, subdir);
|
|
42348
|
+
if (!existsSync17(subdirPath)) {
|
|
42106
42349
|
mkdirSync7(subdirPath, { recursive: true });
|
|
42107
42350
|
}
|
|
42108
42351
|
}
|
|
42109
42352
|
const locusMdPath = getLocusPath(this.projectPath, "contextFile");
|
|
42110
|
-
if (!
|
|
42111
|
-
|
|
42353
|
+
if (!existsSync17(locusMdPath)) {
|
|
42354
|
+
writeFileSync8(locusMdPath, LOCUS_MD_TEMPLATE);
|
|
42112
42355
|
}
|
|
42113
42356
|
const learningsMdPath = getLocusPath(this.projectPath, "learningsFile");
|
|
42114
|
-
if (!
|
|
42115
|
-
|
|
42357
|
+
if (!existsSync17(learningsMdPath)) {
|
|
42358
|
+
writeFileSync8(learningsMdPath, DEFAULT_LEARNINGS_MD);
|
|
42116
42359
|
}
|
|
42117
|
-
if (!
|
|
42360
|
+
if (!existsSync17(locusConfigPath)) {
|
|
42118
42361
|
const config2 = {
|
|
42119
42362
|
$schema: LOCUS_SCHEMAS.config,
|
|
42120
42363
|
version: version2,
|
|
42121
42364
|
createdAt: new Date().toISOString(),
|
|
42122
42365
|
projectPath: "."
|
|
42123
42366
|
};
|
|
42124
|
-
|
|
42367
|
+
writeFileSync8(locusConfigPath, JSON.stringify(config2, null, 2));
|
|
42125
42368
|
}
|
|
42126
42369
|
updateGitignore(this.projectPath);
|
|
42127
42370
|
ensureGitIdentity(this.projectPath);
|
|
42128
42371
|
}
|
|
42129
42372
|
loadConfig() {
|
|
42130
42373
|
const path2 = getLocusPath(this.projectPath, "configFile");
|
|
42131
|
-
if (
|
|
42132
|
-
return JSON.parse(
|
|
42374
|
+
if (existsSync17(path2)) {
|
|
42375
|
+
return JSON.parse(readFileSync15(path2, "utf-8"));
|
|
42133
42376
|
}
|
|
42134
42377
|
return null;
|
|
42135
42378
|
}
|
|
@@ -42159,19 +42402,19 @@ class ConfigManager {
|
|
|
42159
42402
|
this.saveConfig(config2);
|
|
42160
42403
|
}
|
|
42161
42404
|
}
|
|
42162
|
-
const settingsPath =
|
|
42163
|
-
if (
|
|
42164
|
-
const raw =
|
|
42405
|
+
const settingsPath = join17(this.projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG.settingsFile);
|
|
42406
|
+
if (existsSync17(settingsPath)) {
|
|
42407
|
+
const raw = readFileSync15(settingsPath, "utf-8");
|
|
42165
42408
|
const settings = JSON.parse(raw);
|
|
42166
42409
|
if (settings.$schema !== LOCUS_SCHEMAS.settings) {
|
|
42167
42410
|
const { $schema: _2, ...rest } = settings;
|
|
42168
42411
|
const ordered = { $schema: LOCUS_SCHEMAS.settings, ...rest };
|
|
42169
|
-
|
|
42412
|
+
writeFileSync8(settingsPath, JSON.stringify(ordered, null, 2), "utf-8");
|
|
42170
42413
|
}
|
|
42171
42414
|
}
|
|
42172
42415
|
const locusMdPath = getLocusPath(this.projectPath, "contextFile");
|
|
42173
|
-
const locusMdExisted =
|
|
42174
|
-
|
|
42416
|
+
const locusMdExisted = existsSync17(locusMdPath);
|
|
42417
|
+
writeFileSync8(locusMdPath, LOCUS_MD_TEMPLATE);
|
|
42175
42418
|
if (!locusMdExisted) {
|
|
42176
42419
|
result.directoriesCreated.push(".locus/LOCUS.md");
|
|
42177
42420
|
}
|
|
@@ -42183,23 +42426,23 @@ class ConfigManager {
|
|
|
42183
42426
|
LOCUS_CONFIG.plansDir,
|
|
42184
42427
|
LOCUS_CONFIG.discussionsDir
|
|
42185
42428
|
];
|
|
42186
|
-
const locusConfigDir =
|
|
42429
|
+
const locusConfigDir = join17(this.projectPath, LOCUS_CONFIG.dir);
|
|
42187
42430
|
for (const subdir of locusSubdirs) {
|
|
42188
|
-
const subdirPath =
|
|
42189
|
-
if (!
|
|
42431
|
+
const subdirPath = join17(locusConfigDir, subdir);
|
|
42432
|
+
if (!existsSync17(subdirPath)) {
|
|
42190
42433
|
mkdirSync7(subdirPath, { recursive: true });
|
|
42191
42434
|
result.directoriesCreated.push(`.locus/${subdir}`);
|
|
42192
42435
|
}
|
|
42193
42436
|
}
|
|
42194
42437
|
const learningsMdPath = getLocusPath(this.projectPath, "learningsFile");
|
|
42195
|
-
if (!
|
|
42196
|
-
|
|
42438
|
+
if (!existsSync17(learningsMdPath)) {
|
|
42439
|
+
writeFileSync8(learningsMdPath, DEFAULT_LEARNINGS_MD);
|
|
42197
42440
|
result.directoriesCreated.push(".locus/LEARNINGS.md");
|
|
42198
42441
|
}
|
|
42199
|
-
const gitignorePath =
|
|
42200
|
-
const gitignoreBefore =
|
|
42442
|
+
const gitignorePath = join17(this.projectPath, ".gitignore");
|
|
42443
|
+
const gitignoreBefore = existsSync17(gitignorePath) ? readFileSync15(gitignorePath, "utf-8") : "";
|
|
42201
42444
|
updateGitignore(this.projectPath);
|
|
42202
|
-
const gitignoreAfter =
|
|
42445
|
+
const gitignoreAfter = readFileSync15(gitignorePath, "utf-8");
|
|
42203
42446
|
if (gitignoreBefore !== gitignoreAfter) {
|
|
42204
42447
|
result.gitignoreUpdated = true;
|
|
42205
42448
|
}
|
|
@@ -42210,177 +42453,12 @@ class ConfigManager {
|
|
|
42210
42453
|
const { $schema: _2, ...rest } = config2;
|
|
42211
42454
|
const ordered = { $schema: LOCUS_SCHEMAS.config, ...rest };
|
|
42212
42455
|
const path2 = getLocusPath(this.projectPath, "configFile");
|
|
42213
|
-
|
|
42456
|
+
writeFileSync8(path2, JSON.stringify(ordered, null, 2));
|
|
42214
42457
|
}
|
|
42215
42458
|
}
|
|
42216
|
-
var LOCUS_GITIGNORE_MARKER = "# Locus AI", LOCUS_MD_TEMPLATE = `## Planning First
|
|
42217
|
-
|
|
42218
|
-
Complex tasks must be planned before writing code. Create ".locus/plans/<task-name>.md" with:
|
|
42219
|
-
- **Goal**: What we're trying to achieve and why
|
|
42220
|
-
- **Approach**: Step-by-step strategy with technical decisions
|
|
42221
|
-
- **Affected files**: List of files to create/modify/delete
|
|
42222
|
-
- **Acceptance criteria**: Specific, testable conditions for completion
|
|
42223
|
-
- **Dependencies**: Required packages, APIs, or external services
|
|
42224
|
-
|
|
42225
|
-
Delete the planning .md files after successful execution.
|
|
42226
|
-
|
|
42227
|
-
## Code Quality
|
|
42228
|
-
|
|
42229
|
-
- **Follow existing patterns**: Run formatters and linters before finishing (check "package.json" scripts or project config)
|
|
42230
|
-
- **Minimize changes**: Keep modifications atomic. Separate refactors from behavioral changes into different tasks
|
|
42231
|
-
- **Never commit secrets**: No API keys, passwords, or credentials in code. Use environment variables or secret management
|
|
42232
|
-
- **Test as you go**: If tests exist, run relevant ones. If breaking changes occur, update tests accordingly
|
|
42233
|
-
- **Comment complex logic**: Explain *why*, not *what*. Focus on business logic and non-obvious decisions
|
|
42234
|
-
|
|
42235
|
-
## Artifacts
|
|
42236
|
-
|
|
42237
|
-
When a task produces knowledge, analysis, or research output rather than (or in addition to) code changes, you **must** save results as Markdown in ".locus/artifacts/<descriptive-name>.md":
|
|
42238
|
-
|
|
42239
|
-
**Always create artifacts for:**
|
|
42240
|
-
- Code quality audits, security reviews, vulnerability assessments
|
|
42241
|
-
- Architecture analyses, system design proposals, or recommendations
|
|
42242
|
-
- Dependency reports, performance profiling, benchmarking results
|
|
42243
|
-
- Research summaries, technology comparisons, or feasibility studies
|
|
42244
|
-
- Migration plans, deployment strategies, or rollback procedures
|
|
42245
|
-
- Post-mortems, incident analysis, or debugging investigations
|
|
42246
|
-
|
|
42247
|
-
**Artifact structure:**
|
|
42248
|
-
- Clear title and date
|
|
42249
|
-
- Executive summary (2-3 sentences)
|
|
42250
|
-
- Detailed findings/analysis
|
|
42251
|
-
- Actionable recommendations (if applicable)
|
|
42252
|
-
|
|
42253
|
-
## Git Operations
|
|
42254
|
-
|
|
42255
|
-
- **Do NOT run**: git add, git commit, git push, git checkout, git branch, or any git commands
|
|
42256
|
-
- **Why**: The Locus orchestrator handles all version control automatically after execution
|
|
42257
|
-
- **Your role**: Focus solely on making file changes. The system commits, pushes, and creates PRs
|
|
42258
|
-
|
|
42259
|
-
## Continuous Learning
|
|
42260
|
-
|
|
42261
|
-
Read ".locus/LEARNINGS.md" **before starting any task** to avoid repeating mistakes.
|
|
42262
|
-
|
|
42263
|
-
**When to update:**
|
|
42264
|
-
- User corrects your approach or provides guidance
|
|
42265
|
-
- You discover a better pattern while working
|
|
42266
|
-
- A decision prevents future confusion (e.g., "use X not Y because Z")
|
|
42267
|
-
- You encounter and solve a tricky problem
|
|
42268
|
-
|
|
42269
|
-
**What to record:**
|
|
42270
|
-
- Architectural decisions and their rationale
|
|
42271
|
-
- Preferred libraries, tools, or patterns for this project
|
|
42272
|
-
- Common pitfalls and how to avoid them
|
|
42273
|
-
- Project-specific conventions or user preferences
|
|
42274
|
-
- Solutions to non-obvious problems
|
|
42275
|
-
|
|
42276
|
-
**Format (append-only, never delete):**
|
|
42277
|
-
|
|
42278
|
-
"""
|
|
42279
|
-
- **[Category]**: Concise description (1-2 lines max). *Context if needed.*
|
|
42280
|
-
"""
|
|
42281
|
-
|
|
42282
|
-
**Categories:** Architecture, Dependencies, Patterns, Debugging, Performance, Security, DevOps, User Preferences
|
|
42283
|
-
|
|
42284
|
-
## Error Handling
|
|
42285
|
-
|
|
42286
|
-
- **Read error messages carefully**: Don't guess. Parse the actual error before proposing fixes
|
|
42287
|
-
- **Check dependencies first**: Missing packages, wrong versions, and environment issues are common
|
|
42288
|
-
- **Verify assumptions**: If something "should work," confirm it actually does in this environment
|
|
42289
|
-
- **Ask for context**: If you need environment details, configuration, or logs, request them explicitly
|
|
42290
|
-
|
|
42291
|
-
## Communication
|
|
42292
|
-
|
|
42293
|
-
- **Be precise**: When uncertain, state what you know and what you're assuming
|
|
42294
|
-
- **Show your work**: For complex changes, briefly explain the approach before executing
|
|
42295
|
-
- **Highlight trade-offs**: If multiple approaches exist, note why you chose one over others
|
|
42296
|
-
- **Request feedback**: For ambiguous requirements, propose an approach and ask for confirmation
|
|
42297
|
-
`, DEFAULT_LEARNINGS_MD = `# Learnings
|
|
42298
|
-
|
|
42299
|
-
This file captures important lessons, decisions, and corrections made during development.
|
|
42300
|
-
It is read by AI agents before every task to avoid repeating mistakes and to follow established patterns.
|
|
42301
|
-
|
|
42302
|
-
<!-- Add learnings below this line. Format: - **[Category]**: Description -->
|
|
42303
|
-
`;
|
|
42304
42459
|
var init_config_manager = __esm(() => {
|
|
42305
42460
|
init_index_node();
|
|
42306
|
-
|
|
42307
|
-
|
|
42308
|
-
// src/settings-manager.ts
|
|
42309
|
-
import { existsSync as existsSync15, readFileSync as readFileSync13, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
42310
|
-
import { join as join15 } from "node:path";
|
|
42311
|
-
function getSettingsPath(projectPath) {
|
|
42312
|
-
return join15(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG.settingsFile);
|
|
42313
|
-
}
|
|
42314
|
-
|
|
42315
|
-
class SettingsManager {
|
|
42316
|
-
projectPath;
|
|
42317
|
-
constructor(projectPath) {
|
|
42318
|
-
this.projectPath = projectPath;
|
|
42319
|
-
}
|
|
42320
|
-
load() {
|
|
42321
|
-
const settingsPath = getSettingsPath(this.projectPath);
|
|
42322
|
-
if (!existsSync15(settingsPath)) {
|
|
42323
|
-
return {};
|
|
42324
|
-
}
|
|
42325
|
-
return JSON.parse(readFileSync13(settingsPath, "utf-8"));
|
|
42326
|
-
}
|
|
42327
|
-
save(settings) {
|
|
42328
|
-
const { $schema: _2, ...rest } = settings;
|
|
42329
|
-
const ordered = { $schema: LOCUS_SCHEMAS.settings, ...rest };
|
|
42330
|
-
const settingsPath = getSettingsPath(this.projectPath);
|
|
42331
|
-
writeFileSync7(settingsPath, JSON.stringify(ordered, null, 2), "utf-8");
|
|
42332
|
-
}
|
|
42333
|
-
get(key) {
|
|
42334
|
-
return this.load()[key];
|
|
42335
|
-
}
|
|
42336
|
-
set(key, value) {
|
|
42337
|
-
const settings = this.load();
|
|
42338
|
-
settings[key] = value;
|
|
42339
|
-
this.save(settings);
|
|
42340
|
-
}
|
|
42341
|
-
remove() {
|
|
42342
|
-
const settingsPath = getSettingsPath(this.projectPath);
|
|
42343
|
-
if (existsSync15(settingsPath)) {
|
|
42344
|
-
unlinkSync4(settingsPath);
|
|
42345
|
-
}
|
|
42346
|
-
}
|
|
42347
|
-
exists() {
|
|
42348
|
-
return existsSync15(getSettingsPath(this.projectPath));
|
|
42349
|
-
}
|
|
42350
|
-
}
|
|
42351
|
-
var init_settings_manager = __esm(() => {
|
|
42352
|
-
init_index_node();
|
|
42353
|
-
});
|
|
42354
|
-
|
|
42355
|
-
// src/workspace-resolver.ts
|
|
42356
|
-
class WorkspaceResolver {
|
|
42357
|
-
options;
|
|
42358
|
-
constructor(options) {
|
|
42359
|
-
this.options = options;
|
|
42360
|
-
}
|
|
42361
|
-
async resolve() {
|
|
42362
|
-
if (this.options.workspaceId) {
|
|
42363
|
-
return this.options.workspaceId;
|
|
42364
|
-
}
|
|
42365
|
-
try {
|
|
42366
|
-
console.log(c.dim("ℹ Resolving workspace from API key..."));
|
|
42367
|
-
const client = new LocusClient({
|
|
42368
|
-
baseUrl: this.options.apiBase,
|
|
42369
|
-
token: this.options.apiKey
|
|
42370
|
-
});
|
|
42371
|
-
const info = await client.auth.getApiKeyInfo();
|
|
42372
|
-
if (info.workspaceId) {
|
|
42373
|
-
console.log(c.success(`✓ Resolved workspace: ${info.workspaceId}`));
|
|
42374
|
-
return info.workspaceId;
|
|
42375
|
-
}
|
|
42376
|
-
throw new Error("API key is not associated with a workspace. Please specify --workspace.");
|
|
42377
|
-
} catch (error48) {
|
|
42378
|
-
throw new Error(`Error resolving workspace: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
42379
|
-
}
|
|
42380
|
-
}
|
|
42381
|
-
}
|
|
42382
|
-
var init_workspace_resolver = __esm(() => {
|
|
42383
|
-
init_index_node();
|
|
42461
|
+
init_git_helpers();
|
|
42384
42462
|
});
|
|
42385
42463
|
|
|
42386
42464
|
// src/commands/plan.ts
|
|
@@ -42388,8 +42466,8 @@ var exports_plan = {};
|
|
|
42388
42466
|
__export(exports_plan, {
|
|
42389
42467
|
planCommand: () => planCommand
|
|
42390
42468
|
});
|
|
42391
|
-
import { existsSync as
|
|
42392
|
-
import { join as
|
|
42469
|
+
import { existsSync as existsSync18, unlinkSync as unlinkSync5 } from "node:fs";
|
|
42470
|
+
import { join as join18 } from "node:path";
|
|
42393
42471
|
import { parseArgs } from "node:util";
|
|
42394
42472
|
function normalizePlanIdArgs(args) {
|
|
42395
42473
|
const planIdFlags = new Set(["--approve", "--reject", "--cancel", "--show"]);
|
|
@@ -42433,13 +42511,34 @@ async function planCommand(args) {
|
|
|
42433
42511
|
requireInitialization(projectPath, "plan");
|
|
42434
42512
|
const planManager = new PlanManager(projectPath);
|
|
42435
42513
|
if (values.list) {
|
|
42436
|
-
return
|
|
42514
|
+
return renderPlanList(planManager);
|
|
42437
42515
|
}
|
|
42438
42516
|
if (values.show) {
|
|
42439
|
-
|
|
42517
|
+
const md = showPlan(planManager, values.show);
|
|
42518
|
+
if (!md) {
|
|
42519
|
+
console.error(`
|
|
42520
|
+
${c.error("✖")} ${c.red(`Plan not found: ${values.show}`)}
|
|
42521
|
+
`);
|
|
42522
|
+
process.exit(1);
|
|
42523
|
+
}
|
|
42524
|
+
console.log(`
|
|
42525
|
+
${md}
|
|
42526
|
+
`);
|
|
42527
|
+
return;
|
|
42440
42528
|
}
|
|
42441
42529
|
if (values.cancel) {
|
|
42442
|
-
|
|
42530
|
+
try {
|
|
42531
|
+
cancelPlan(planManager, values.cancel);
|
|
42532
|
+
console.log(`
|
|
42533
|
+
${c.success("✔")} ${c.dim("Plan cancelled.")}
|
|
42534
|
+
`);
|
|
42535
|
+
} catch (error48) {
|
|
42536
|
+
console.error(`
|
|
42537
|
+
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
42538
|
+
`);
|
|
42539
|
+
process.exit(1);
|
|
42540
|
+
}
|
|
42541
|
+
return;
|
|
42443
42542
|
}
|
|
42444
42543
|
if (values.reject) {
|
|
42445
42544
|
const feedback2 = values.feedback;
|
|
@@ -42451,30 +42550,59 @@ async function planCommand(args) {
|
|
|
42451
42550
|
`);
|
|
42452
42551
|
process.exit(1);
|
|
42453
42552
|
}
|
|
42454
|
-
|
|
42553
|
+
try {
|
|
42554
|
+
const plan = rejectPlan(planManager, values.reject, feedback2);
|
|
42555
|
+
console.log(`
|
|
42556
|
+
${c.warning("!")} ${c.bold("Plan rejected:")} ${plan.name}
|
|
42557
|
+
`);
|
|
42558
|
+
console.log(` ${c.dim("Feedback saved:")} ${feedback2}
|
|
42559
|
+
`);
|
|
42560
|
+
console.log(` ${c.dim("Re-run the planning meeting with the same directive to incorporate feedback:")}`);
|
|
42561
|
+
console.log(` ${c.cyan(`locus plan "${plan.directive}"`)}
|
|
42562
|
+
`);
|
|
42563
|
+
} catch (error48) {
|
|
42564
|
+
console.error(`
|
|
42565
|
+
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
42566
|
+
`);
|
|
42567
|
+
process.exit(1);
|
|
42568
|
+
}
|
|
42569
|
+
return;
|
|
42455
42570
|
}
|
|
42456
42571
|
if (values.approve) {
|
|
42457
|
-
const
|
|
42458
|
-
|
|
42572
|
+
const configManager = new ConfigManager(projectPath);
|
|
42573
|
+
configManager.updateVersion(VERSION2);
|
|
42574
|
+
try {
|
|
42575
|
+
const { client, workspaceId } = await resolveApiContext({
|
|
42576
|
+
projectPath,
|
|
42577
|
+
apiKey: values["api-key"],
|
|
42578
|
+
apiUrl: values["api-url"],
|
|
42579
|
+
workspaceId: values.workspace
|
|
42580
|
+
});
|
|
42581
|
+
return await renderApprovePlan(planManager, values.approve, client, workspaceId);
|
|
42582
|
+
} catch (error48) {
|
|
42583
|
+
console.error(`
|
|
42584
|
+
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
42585
|
+
`);
|
|
42586
|
+
process.exit(1);
|
|
42587
|
+
}
|
|
42459
42588
|
}
|
|
42460
42589
|
const directive = positionals.join(" ").trim();
|
|
42461
42590
|
if (!directive) {
|
|
42462
42591
|
showPlanHelp();
|
|
42463
42592
|
return;
|
|
42464
42593
|
}
|
|
42465
|
-
const
|
|
42466
|
-
|
|
42467
|
-
|
|
42594
|
+
const { provider, model } = resolveAiSettings({
|
|
42595
|
+
projectPath,
|
|
42596
|
+
provider: values.provider,
|
|
42597
|
+
model: values.model
|
|
42598
|
+
});
|
|
42468
42599
|
const reasoningEffort = values["reasoning-effort"];
|
|
42469
42600
|
const aiRunner = createAiRunner(provider, {
|
|
42470
42601
|
projectPath,
|
|
42471
42602
|
model,
|
|
42472
42603
|
reasoningEffort
|
|
42473
42604
|
});
|
|
42474
|
-
const log = (
|
|
42475
|
-
const icon = level === "success" ? c.success("✔") : level === "error" ? c.error("✖") : level === "warn" ? c.warning("!") : c.info("●");
|
|
42476
|
-
console.log(` ${icon} ${message}`);
|
|
42477
|
-
};
|
|
42605
|
+
const log = createCliLogger();
|
|
42478
42606
|
console.log(`
|
|
42479
42607
|
${c.header(" PLANNING MEETING ")} ${c.bold("Starting async planning meeting...")}
|
|
42480
42608
|
`);
|
|
@@ -42496,8 +42624,8 @@ async function planCommand(args) {
|
|
|
42496
42624
|
try {
|
|
42497
42625
|
const result = await meeting.run(directive, feedback);
|
|
42498
42626
|
planManager.save(result.plan);
|
|
42499
|
-
const tempFile =
|
|
42500
|
-
if (
|
|
42627
|
+
const tempFile = join18(getLocusPath(projectPath, "plansDir"), `${result.plan.id}.json`);
|
|
42628
|
+
if (existsSync18(tempFile)) {
|
|
42501
42629
|
unlinkSync5(tempFile);
|
|
42502
42630
|
}
|
|
42503
42631
|
console.log(`
|
|
@@ -42518,8 +42646,8 @@ async function planCommand(args) {
|
|
|
42518
42646
|
process.exit(1);
|
|
42519
42647
|
}
|
|
42520
42648
|
}
|
|
42521
|
-
function
|
|
42522
|
-
const plans = planManager
|
|
42649
|
+
function renderPlanList(planManager) {
|
|
42650
|
+
const plans = listPlans(planManager);
|
|
42523
42651
|
if (plans.length === 0) {
|
|
42524
42652
|
console.log(`
|
|
42525
42653
|
${c.dim("No plans found.")}
|
|
@@ -42533,7 +42661,7 @@ function listPlans(planManager) {
|
|
|
42533
42661
|
`);
|
|
42534
42662
|
for (const plan of plans) {
|
|
42535
42663
|
const statusIcon = plan.status === "pending" ? c.warning("◯") : plan.status === "approved" ? c.success("✔") : plan.status === "rejected" ? c.error("✖") : c.dim("⊘");
|
|
42536
|
-
console.log(` ${statusIcon} ${c.bold(plan.name)} ${c.dim(`[${plan.status}]`)} ${c.dim(`— ${plan.
|
|
42664
|
+
console.log(` ${statusIcon} ${c.bold(plan.name)} ${c.dim(`[${plan.status}]`)} ${c.dim(`— ${plan.taskCount} tasks`)}`);
|
|
42537
42665
|
console.log(` ${c.dim("ID:")} ${plan.id}`);
|
|
42538
42666
|
console.log(` ${c.dim("Created:")} ${plan.createdAt}`);
|
|
42539
42667
|
if (plan.feedback) {
|
|
@@ -42542,50 +42670,7 @@ function listPlans(planManager) {
|
|
|
42542
42670
|
console.log("");
|
|
42543
42671
|
}
|
|
42544
42672
|
}
|
|
42545
|
-
function
|
|
42546
|
-
const md = planManager.getMarkdown(idOrSlug);
|
|
42547
|
-
if (!md) {
|
|
42548
|
-
console.error(`
|
|
42549
|
-
${c.error("✖")} ${c.red(`Plan not found: ${idOrSlug}`)}
|
|
42550
|
-
`);
|
|
42551
|
-
process.exit(1);
|
|
42552
|
-
}
|
|
42553
|
-
console.log(`
|
|
42554
|
-
${md}
|
|
42555
|
-
`);
|
|
42556
|
-
}
|
|
42557
|
-
function cancelPlan(planManager, idOrSlug) {
|
|
42558
|
-
try {
|
|
42559
|
-
planManager.cancel(idOrSlug);
|
|
42560
|
-
console.log(`
|
|
42561
|
-
${c.success("✔")} ${c.dim("Plan cancelled.")}
|
|
42562
|
-
`);
|
|
42563
|
-
} catch (error48) {
|
|
42564
|
-
console.error(`
|
|
42565
|
-
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
42566
|
-
`);
|
|
42567
|
-
process.exit(1);
|
|
42568
|
-
}
|
|
42569
|
-
}
|
|
42570
|
-
function rejectPlan(planManager, idOrSlug, feedback) {
|
|
42571
|
-
try {
|
|
42572
|
-
const plan = planManager.reject(idOrSlug, feedback);
|
|
42573
|
-
console.log(`
|
|
42574
|
-
${c.warning("!")} ${c.bold("Plan rejected:")} ${plan.name}
|
|
42575
|
-
`);
|
|
42576
|
-
console.log(` ${c.dim("Feedback saved:")} ${feedback}
|
|
42577
|
-
`);
|
|
42578
|
-
console.log(` ${c.dim("Re-run the planning meeting with the same directive to incorporate feedback:")}`);
|
|
42579
|
-
console.log(` ${c.cyan(`locus plan "${plan.directive}"`)}
|
|
42580
|
-
`);
|
|
42581
|
-
} catch (error48) {
|
|
42582
|
-
console.error(`
|
|
42583
|
-
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
42584
|
-
`);
|
|
42585
|
-
process.exit(1);
|
|
42586
|
-
}
|
|
42587
|
-
}
|
|
42588
|
-
async function approvePlan(planManager, idOrSlug, client, workspaceId) {
|
|
42673
|
+
async function renderApprovePlan(planManager, idOrSlug, client, workspaceId) {
|
|
42589
42674
|
try {
|
|
42590
42675
|
console.log(`
|
|
42591
42676
|
${c.info("●")} ${c.bold("Approving plan and creating sprint...")}
|
|
@@ -42608,34 +42693,6 @@ async function approvePlan(planManager, idOrSlug, client, workspaceId) {
|
|
|
42608
42693
|
process.exit(1);
|
|
42609
42694
|
}
|
|
42610
42695
|
}
|
|
42611
|
-
async function resolveApiContext(projectPath, values) {
|
|
42612
|
-
const configManager = new ConfigManager(projectPath);
|
|
42613
|
-
configManager.updateVersion(VERSION2);
|
|
42614
|
-
const settingsManager = new SettingsManager(projectPath);
|
|
42615
|
-
const settings = settingsManager.load();
|
|
42616
|
-
const apiKey = values["api-key"] || settings.apiKey;
|
|
42617
|
-
if (!apiKey) {
|
|
42618
|
-
console.error(`
|
|
42619
|
-
${c.error("✖")} ${c.red("API key is required for this operation")}
|
|
42620
|
-
`);
|
|
42621
|
-
console.error(` ${c.dim(`Configure with: locus config setup --api-key <key>
|
|
42622
|
-
Or pass --api-key flag`)}
|
|
42623
|
-
`);
|
|
42624
|
-
process.exit(1);
|
|
42625
|
-
}
|
|
42626
|
-
const apiBase = values["api-url"] || settings.apiUrl || "https://api.locusai.dev/api";
|
|
42627
|
-
const resolver = new WorkspaceResolver({
|
|
42628
|
-
apiKey,
|
|
42629
|
-
apiBase,
|
|
42630
|
-
workspaceId: values.workspace
|
|
42631
|
-
});
|
|
42632
|
-
const workspaceId = await resolver.resolve();
|
|
42633
|
-
const client = new LocusClient({
|
|
42634
|
-
baseUrl: apiBase,
|
|
42635
|
-
token: apiKey
|
|
42636
|
-
});
|
|
42637
|
-
return { client, workspaceId };
|
|
42638
|
-
}
|
|
42639
42696
|
function printPlanSummary(plan) {
|
|
42640
42697
|
console.log(` ${c.bold("Sprint:")} ${plan.name}`);
|
|
42641
42698
|
console.log(` ${c.bold("Goal:")} ${plan.goal}`);
|
|
@@ -42693,11 +42750,10 @@ function showPlanHelp() {
|
|
|
42693
42750
|
`);
|
|
42694
42751
|
}
|
|
42695
42752
|
var init_plan = __esm(() => {
|
|
42753
|
+
init_src3();
|
|
42696
42754
|
init_index_node();
|
|
42697
42755
|
init_config_manager();
|
|
42698
|
-
init_settings_manager();
|
|
42699
42756
|
init_utils3();
|
|
42700
|
-
init_workspace_resolver();
|
|
42701
42757
|
});
|
|
42702
42758
|
|
|
42703
42759
|
// src/display/tool-display.ts
|
|
@@ -43291,9 +43347,9 @@ var init_progress_renderer = __esm(() => {
|
|
|
43291
43347
|
});
|
|
43292
43348
|
|
|
43293
43349
|
// src/repl/image-detect.ts
|
|
43294
|
-
import { copyFileSync, existsSync as
|
|
43350
|
+
import { copyFileSync, existsSync as existsSync19, mkdirSync as mkdirSync8 } from "node:fs";
|
|
43295
43351
|
import { homedir as homedir2, tmpdir as tmpdir2 } from "node:os";
|
|
43296
|
-
import { basename as basename2, join as
|
|
43352
|
+
import { basename as basename2, join as join19 } from "node:path";
|
|
43297
43353
|
function hasImageExtension(p) {
|
|
43298
43354
|
const dot = p.lastIndexOf(".");
|
|
43299
43355
|
if (dot === -1)
|
|
@@ -43315,7 +43371,7 @@ function copyToStable(srcPath) {
|
|
|
43315
43371
|
mkdirSync8(STABLE_IMAGE_DIR, { recursive: true });
|
|
43316
43372
|
const ts = Date.now();
|
|
43317
43373
|
const name = `${ts}-${basename2(srcPath)}`;
|
|
43318
|
-
const destPath =
|
|
43374
|
+
const destPath = join19(STABLE_IMAGE_DIR, name);
|
|
43319
43375
|
copyFileSync(srcPath, destPath);
|
|
43320
43376
|
return destPath;
|
|
43321
43377
|
} catch {
|
|
@@ -43335,7 +43391,7 @@ function detectImages(input) {
|
|
|
43335
43391
|
let exists = false;
|
|
43336
43392
|
let stablePath = normalized;
|
|
43337
43393
|
try {
|
|
43338
|
-
exists =
|
|
43394
|
+
exists = existsSync19(normalized);
|
|
43339
43395
|
} catch {}
|
|
43340
43396
|
if (exists) {
|
|
43341
43397
|
const copied = copyToStable(normalized);
|
|
@@ -43409,7 +43465,7 @@ var init_image_detect = __esm(() => {
|
|
|
43409
43465
|
".tif",
|
|
43410
43466
|
".tiff"
|
|
43411
43467
|
]);
|
|
43412
|
-
STABLE_IMAGE_DIR =
|
|
43468
|
+
STABLE_IMAGE_DIR = join19(tmpdir2(), "locus-images");
|
|
43413
43469
|
});
|
|
43414
43470
|
|
|
43415
43471
|
// src/repl/input-handler.ts
|
|
@@ -44166,66 +44222,10 @@ var init_interactive_session = __esm(() => {
|
|
|
44166
44222
|
init_index_node();
|
|
44167
44223
|
|
|
44168
44224
|
// src/commands/artifacts.ts
|
|
44225
|
+
init_src3();
|
|
44169
44226
|
init_index_node();
|
|
44170
44227
|
init_utils3();
|
|
44171
|
-
import { existsSync as existsSync17, readdirSync as readdirSync5, readFileSync as readFileSync14, statSync } from "node:fs";
|
|
44172
|
-
import { join as join17 } from "node:path";
|
|
44173
44228
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
44174
|
-
function listArtifacts(projectPath) {
|
|
44175
|
-
const artifactsDir = getLocusPath(projectPath, "artifactsDir");
|
|
44176
|
-
if (!existsSync17(artifactsDir)) {
|
|
44177
|
-
return [];
|
|
44178
|
-
}
|
|
44179
|
-
const files = readdirSync5(artifactsDir).filter((f) => f.endsWith(".md"));
|
|
44180
|
-
return files.map((fileName) => {
|
|
44181
|
-
const filePath = join17(artifactsDir, fileName);
|
|
44182
|
-
const stat = statSync(filePath);
|
|
44183
|
-
const name = fileName.replace(/\.md$/, "");
|
|
44184
|
-
return {
|
|
44185
|
-
name,
|
|
44186
|
-
fileName,
|
|
44187
|
-
createdAt: stat.birthtime,
|
|
44188
|
-
size: stat.size
|
|
44189
|
-
};
|
|
44190
|
-
}).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
44191
|
-
}
|
|
44192
|
-
function readArtifact(projectPath, name) {
|
|
44193
|
-
const artifactsDir = getLocusPath(projectPath, "artifactsDir");
|
|
44194
|
-
const fileName = name.endsWith(".md") ? name : `${name}.md`;
|
|
44195
|
-
const filePath = join17(artifactsDir, fileName);
|
|
44196
|
-
if (!existsSync17(filePath)) {
|
|
44197
|
-
return null;
|
|
44198
|
-
}
|
|
44199
|
-
const stat = statSync(filePath);
|
|
44200
|
-
const content = readFileSync14(filePath, "utf-8");
|
|
44201
|
-
return {
|
|
44202
|
-
content,
|
|
44203
|
-
info: {
|
|
44204
|
-
name: fileName.replace(/\.md$/, ""),
|
|
44205
|
-
fileName,
|
|
44206
|
-
createdAt: stat.birthtime,
|
|
44207
|
-
size: stat.size
|
|
44208
|
-
}
|
|
44209
|
-
};
|
|
44210
|
-
}
|
|
44211
|
-
function formatSize(bytes) {
|
|
44212
|
-
if (bytes < 1024)
|
|
44213
|
-
return `${bytes}B`;
|
|
44214
|
-
const kb = bytes / 1024;
|
|
44215
|
-
if (kb < 1024)
|
|
44216
|
-
return `${kb.toFixed(1)}KB`;
|
|
44217
|
-
const mb = kb / 1024;
|
|
44218
|
-
return `${mb.toFixed(1)}MB`;
|
|
44219
|
-
}
|
|
44220
|
-
function formatDate(date5) {
|
|
44221
|
-
return date5.toLocaleDateString("en-US", {
|
|
44222
|
-
year: "numeric",
|
|
44223
|
-
month: "short",
|
|
44224
|
-
day: "numeric",
|
|
44225
|
-
hour: "2-digit",
|
|
44226
|
-
minute: "2-digit"
|
|
44227
|
-
});
|
|
44228
|
-
}
|
|
44229
44229
|
async function artifactsCommand(args) {
|
|
44230
44230
|
const { positionals } = parseArgs2({
|
|
44231
44231
|
args,
|
|
@@ -44296,27 +44296,8 @@ async function listArtifactsCommand(projectPath) {
|
|
|
44296
44296
|
`);
|
|
44297
44297
|
}
|
|
44298
44298
|
async function showArtifact(projectPath, name) {
|
|
44299
|
-
const result =
|
|
44299
|
+
const result = findArtifact(projectPath, name);
|
|
44300
44300
|
if (!result) {
|
|
44301
|
-
const artifacts = listArtifacts(projectPath);
|
|
44302
|
-
const matches = artifacts.filter((a) => a.name.toLowerCase().includes(name.toLowerCase()));
|
|
44303
|
-
if (matches.length === 1) {
|
|
44304
|
-
const match = readArtifact(projectPath, matches[0].name);
|
|
44305
|
-
if (match) {
|
|
44306
|
-
printArtifact(match.info, match.content);
|
|
44307
|
-
return;
|
|
44308
|
-
}
|
|
44309
|
-
}
|
|
44310
|
-
if (matches.length > 1) {
|
|
44311
|
-
console.error(`
|
|
44312
|
-
${c.error("Error:")} Multiple artifacts match "${name}":
|
|
44313
|
-
`);
|
|
44314
|
-
for (const m of matches) {
|
|
44315
|
-
console.log(` ${c.cyan(m.name)}`);
|
|
44316
|
-
}
|
|
44317
|
-
console.log();
|
|
44318
|
-
return;
|
|
44319
|
-
}
|
|
44320
44301
|
console.error(`
|
|
44321
44302
|
${c.error("Error:")} Artifact "${name}" not found
|
|
44322
44303
|
`);
|
|
@@ -44324,6 +44305,16 @@ async function showArtifact(projectPath, name) {
|
|
|
44324
44305
|
`);
|
|
44325
44306
|
return;
|
|
44326
44307
|
}
|
|
44308
|
+
if (!result.match) {
|
|
44309
|
+
console.error(`
|
|
44310
|
+
${c.error("Error:")} Multiple artifacts match "${name}":
|
|
44311
|
+
`);
|
|
44312
|
+
for (const m of result.ambiguous) {
|
|
44313
|
+
console.log(` ${c.cyan(m.name)}`);
|
|
44314
|
+
}
|
|
44315
|
+
console.log();
|
|
44316
|
+
return;
|
|
44317
|
+
}
|
|
44327
44318
|
printArtifact(result.info, result.content);
|
|
44328
44319
|
}
|
|
44329
44320
|
function printArtifact(info, content) {
|
|
@@ -44337,17 +44328,16 @@ function printArtifact(info, content) {
|
|
|
44337
44328
|
console.log(content);
|
|
44338
44329
|
}
|
|
44339
44330
|
async function convertToPlan(projectPath, name) {
|
|
44340
|
-
const result =
|
|
44331
|
+
const result = findArtifact(projectPath, name);
|
|
44341
44332
|
if (!result) {
|
|
44342
|
-
|
|
44343
|
-
|
|
44344
|
-
|
|
44345
|
-
|
|
44346
|
-
|
|
44347
|
-
|
|
44348
|
-
|
|
44349
|
-
|
|
44350
|
-
}
|
|
44333
|
+
console.error(`
|
|
44334
|
+
${c.error("Error:")} Artifact "${name}" not found
|
|
44335
|
+
`);
|
|
44336
|
+
console.log(` ${c.dim("Use 'locus artifacts' to see available artifacts")}
|
|
44337
|
+
`);
|
|
44338
|
+
return;
|
|
44339
|
+
}
|
|
44340
|
+
if (!result.match) {
|
|
44351
44341
|
console.error(`
|
|
44352
44342
|
${c.error("Error:")} Artifact "${name}" not found
|
|
44353
44343
|
`);
|
|
@@ -44366,8 +44356,8 @@ async function runPlanConversion(artifactName) {
|
|
|
44366
44356
|
await planCommand2([directive]);
|
|
44367
44357
|
}
|
|
44368
44358
|
// src/commands/config.ts
|
|
44359
|
+
init_src3();
|
|
44369
44360
|
init_index_node();
|
|
44370
|
-
init_settings_manager();
|
|
44371
44361
|
import { createInterface } from "node:readline";
|
|
44372
44362
|
function ask(question) {
|
|
44373
44363
|
const rl = createInterface({
|
|
@@ -44394,11 +44384,6 @@ var TELEGRAM_KEYS = [
|
|
|
44394
44384
|
"telegram.testMode"
|
|
44395
44385
|
];
|
|
44396
44386
|
var ALL_KEYS = [...TOP_LEVEL_KEYS, ...TELEGRAM_KEYS];
|
|
44397
|
-
function maskSecret(value) {
|
|
44398
|
-
if (value.length <= 8)
|
|
44399
|
-
return "****";
|
|
44400
|
-
return `${value.slice(0, 4)}...${value.slice(-4)}`;
|
|
44401
|
-
}
|
|
44402
44387
|
function showConfigHelp() {
|
|
44403
44388
|
console.log(`
|
|
44404
44389
|
${c.header(" CONFIG ")}
|
|
@@ -44624,11 +44609,11 @@ async function configCommand(args) {
|
|
|
44624
44609
|
}
|
|
44625
44610
|
}
|
|
44626
44611
|
// src/commands/discuss.ts
|
|
44612
|
+
init_src3();
|
|
44627
44613
|
init_index_node();
|
|
44628
44614
|
init_progress_renderer();
|
|
44629
44615
|
init_image_detect();
|
|
44630
44616
|
init_input_handler();
|
|
44631
|
-
init_settings_manager();
|
|
44632
44617
|
init_utils3();
|
|
44633
44618
|
import { parseArgs as parseArgs3 } from "node:util";
|
|
44634
44619
|
async function discussCommand(args) {
|
|
@@ -44651,35 +44636,66 @@ async function discussCommand(args) {
|
|
|
44651
44636
|
requireInitialization(projectPath, "discuss");
|
|
44652
44637
|
const discussionManager = new DiscussionManager(projectPath);
|
|
44653
44638
|
if (values.list) {
|
|
44654
|
-
return
|
|
44639
|
+
return renderDiscussionList(discussionManager);
|
|
44655
44640
|
}
|
|
44656
44641
|
if (values.show) {
|
|
44657
|
-
|
|
44642
|
+
const md = showDiscussion(discussionManager, values.show);
|
|
44643
|
+
if (!md) {
|
|
44644
|
+
console.error(`
|
|
44645
|
+
${c.error("✖")} ${c.red(`Discussion not found: ${values.show}`)}
|
|
44646
|
+
`);
|
|
44647
|
+
process.exit(1);
|
|
44648
|
+
}
|
|
44649
|
+
console.log(`
|
|
44650
|
+
${md}
|
|
44651
|
+
`);
|
|
44652
|
+
return;
|
|
44658
44653
|
}
|
|
44659
44654
|
if (values.archive) {
|
|
44660
|
-
|
|
44655
|
+
try {
|
|
44656
|
+
archiveDiscussion(discussionManager, values.archive);
|
|
44657
|
+
console.log(`
|
|
44658
|
+
${c.success("✔")} ${c.dim("Discussion archived.")}
|
|
44659
|
+
`);
|
|
44660
|
+
} catch (error48) {
|
|
44661
|
+
console.error(`
|
|
44662
|
+
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
44663
|
+
`);
|
|
44664
|
+
process.exit(1);
|
|
44665
|
+
}
|
|
44666
|
+
return;
|
|
44661
44667
|
}
|
|
44662
44668
|
if (values.delete) {
|
|
44663
|
-
|
|
44669
|
+
try {
|
|
44670
|
+
deleteDiscussion(discussionManager, values.delete);
|
|
44671
|
+
console.log(`
|
|
44672
|
+
${c.success("✔")} ${c.dim("Discussion deleted.")}
|
|
44673
|
+
`);
|
|
44674
|
+
} catch (error48) {
|
|
44675
|
+
console.error(`
|
|
44676
|
+
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
44677
|
+
`);
|
|
44678
|
+
process.exit(1);
|
|
44679
|
+
}
|
|
44680
|
+
return;
|
|
44664
44681
|
}
|
|
44665
44682
|
const topic = positionals.join(" ").trim();
|
|
44666
44683
|
if (!topic) {
|
|
44667
44684
|
showDiscussHelp();
|
|
44668
44685
|
return;
|
|
44669
44686
|
}
|
|
44670
|
-
const
|
|
44671
|
-
|
|
44672
|
-
|
|
44687
|
+
const { provider, model } = resolveAiSettings({
|
|
44688
|
+
projectPath,
|
|
44689
|
+
provider: values.provider,
|
|
44690
|
+
model: values.model
|
|
44691
|
+
});
|
|
44673
44692
|
const reasoningEffort = values["reasoning-effort"];
|
|
44674
44693
|
const aiRunner = createAiRunner(provider, {
|
|
44675
44694
|
projectPath,
|
|
44676
44695
|
model,
|
|
44677
44696
|
reasoningEffort
|
|
44678
44697
|
});
|
|
44679
|
-
const log = (
|
|
44680
|
-
const icon = level === "success" ? c.success("✔") : level === "error" ? c.error("✖") : level === "warn" ? c.warning("!") : c.info("●");
|
|
44681
|
-
console.log(` ${icon} ${message}`);
|
|
44682
|
-
};
|
|
44698
|
+
const log = createCliLogger();
|
|
44683
44699
|
const facilitator = new DiscussionFacilitator({
|
|
44684
44700
|
projectPath,
|
|
44685
44701
|
aiRunner,
|
|
@@ -44865,8 +44881,8 @@ async function discussCommand(args) {
|
|
|
44865
44881
|
inputHandler.start();
|
|
44866
44882
|
inputHandler.showPrompt();
|
|
44867
44883
|
}
|
|
44868
|
-
function
|
|
44869
|
-
const discussions = discussionManager
|
|
44884
|
+
function renderDiscussionList(discussionManager) {
|
|
44885
|
+
const discussions = listDiscussions(discussionManager);
|
|
44870
44886
|
if (discussions.length === 0) {
|
|
44871
44887
|
console.log(`
|
|
44872
44888
|
${c.dim("No discussions found.")}
|
|
@@ -44880,50 +44896,12 @@ function listDiscussions(discussionManager) {
|
|
|
44880
44896
|
`);
|
|
44881
44897
|
for (const disc of discussions) {
|
|
44882
44898
|
const statusIcon = disc.status === "active" ? c.warning("◯") : disc.status === "completed" ? c.success("✔") : c.dim("⊘");
|
|
44883
|
-
console.log(` ${statusIcon} ${c.bold(disc.title)} ${c.dim(`[${disc.status}]`)} ${c.dim(`— ${disc.
|
|
44899
|
+
console.log(` ${statusIcon} ${c.bold(disc.title)} ${c.dim(`[${disc.status}]`)} ${c.dim(`— ${disc.messageCount} messages, ${disc.insightCount} insights`)}`);
|
|
44884
44900
|
console.log(` ${c.dim("ID:")} ${disc.id}`);
|
|
44885
44901
|
console.log(` ${c.dim("Created:")} ${disc.createdAt}`);
|
|
44886
44902
|
console.log("");
|
|
44887
44903
|
}
|
|
44888
44904
|
}
|
|
44889
|
-
function showDiscussion(discussionManager, id) {
|
|
44890
|
-
const md = discussionManager.getMarkdown(id);
|
|
44891
|
-
if (!md) {
|
|
44892
|
-
console.error(`
|
|
44893
|
-
${c.error("✖")} ${c.red(`Discussion not found: ${id}`)}
|
|
44894
|
-
`);
|
|
44895
|
-
process.exit(1);
|
|
44896
|
-
}
|
|
44897
|
-
console.log(`
|
|
44898
|
-
${md}
|
|
44899
|
-
`);
|
|
44900
|
-
}
|
|
44901
|
-
function archiveDiscussion(discussionManager, id) {
|
|
44902
|
-
try {
|
|
44903
|
-
discussionManager.archive(id);
|
|
44904
|
-
console.log(`
|
|
44905
|
-
${c.success("✔")} ${c.dim("Discussion archived.")}
|
|
44906
|
-
`);
|
|
44907
|
-
} catch (error48) {
|
|
44908
|
-
console.error(`
|
|
44909
|
-
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
44910
|
-
`);
|
|
44911
|
-
process.exit(1);
|
|
44912
|
-
}
|
|
44913
|
-
}
|
|
44914
|
-
function deleteDiscussion(discussionManager, id) {
|
|
44915
|
-
try {
|
|
44916
|
-
discussionManager.delete(id);
|
|
44917
|
-
console.log(`
|
|
44918
|
-
${c.success("✔")} ${c.dim("Discussion deleted.")}
|
|
44919
|
-
`);
|
|
44920
|
-
} catch (error48) {
|
|
44921
|
-
console.error(`
|
|
44922
|
-
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
44923
|
-
`);
|
|
44924
|
-
process.exit(1);
|
|
44925
|
-
}
|
|
44926
|
-
}
|
|
44927
44905
|
function showCurrentInsights(discussionManager, discussionId) {
|
|
44928
44906
|
const discussion2 = discussionManager.load(discussionId);
|
|
44929
44907
|
if (!discussion2 || discussion2.insights.length === 0) {
|
|
@@ -45014,11 +44992,10 @@ function showDiscussHelp() {
|
|
|
45014
44992
|
`);
|
|
45015
44993
|
}
|
|
45016
44994
|
// src/commands/docs.ts
|
|
44995
|
+
init_src3();
|
|
45017
44996
|
init_index_node();
|
|
45018
44997
|
init_config_manager();
|
|
45019
|
-
init_settings_manager();
|
|
45020
44998
|
init_utils3();
|
|
45021
|
-
init_workspace_resolver();
|
|
45022
44999
|
import { parseArgs as parseArgs4 } from "node:util";
|
|
45023
45000
|
async function docsCommand(args) {
|
|
45024
45001
|
const subcommand = args[0];
|
|
@@ -45052,55 +45029,25 @@ async function docsSyncCommand(args) {
|
|
|
45052
45029
|
requireInitialization(projectPath, "docs sync");
|
|
45053
45030
|
const configManager = new ConfigManager(projectPath);
|
|
45054
45031
|
configManager.updateVersion(VERSION2);
|
|
45055
|
-
|
|
45056
|
-
const settings = settingsManager.load();
|
|
45057
|
-
const apiKey = values["api-key"] || settings.apiKey;
|
|
45058
|
-
if (!apiKey) {
|
|
45059
|
-
console.error(`
|
|
45060
|
-
${c.error("✖")} ${c.red("API key is required")}
|
|
45061
|
-
` + ` ${c.dim(`Configure with: locus config setup --api-key <key>
|
|
45062
|
-
Or pass --api-key flag`)}
|
|
45063
|
-
`);
|
|
45064
|
-
process.exit(1);
|
|
45065
|
-
}
|
|
45066
|
-
const apiBase = values["api-url"] || settings.apiUrl || "https://api.locusai.dev/api";
|
|
45067
|
-
const resolver = new WorkspaceResolver({
|
|
45068
|
-
apiKey,
|
|
45069
|
-
apiBase,
|
|
45070
|
-
workspaceId: values.workspace
|
|
45071
|
-
});
|
|
45072
|
-
let workspaceId;
|
|
45032
|
+
let apiContext;
|
|
45073
45033
|
try {
|
|
45074
|
-
|
|
45034
|
+
apiContext = await resolveApiContext({
|
|
45035
|
+
projectPath,
|
|
45036
|
+
apiKey: values["api-key"],
|
|
45037
|
+
apiUrl: values["api-url"],
|
|
45038
|
+
workspaceId: values.workspace
|
|
45039
|
+
});
|
|
45075
45040
|
} catch (error48) {
|
|
45076
45041
|
console.error(`
|
|
45077
45042
|
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
45078
45043
|
`);
|
|
45079
45044
|
process.exit(1);
|
|
45080
45045
|
}
|
|
45081
|
-
const client = new LocusClient({
|
|
45082
|
-
baseUrl: apiBase,
|
|
45083
|
-
token: apiKey
|
|
45084
|
-
});
|
|
45085
45046
|
const fetcher = new DocumentFetcher({
|
|
45086
|
-
client,
|
|
45087
|
-
workspaceId,
|
|
45047
|
+
client: apiContext.client,
|
|
45048
|
+
workspaceId: apiContext.workspaceId,
|
|
45088
45049
|
projectPath,
|
|
45089
|
-
log: (
|
|
45090
|
-
if (level === "error") {
|
|
45091
|
-
console.log(` ${c.error("✖")} ${message}`);
|
|
45092
|
-
return;
|
|
45093
|
-
}
|
|
45094
|
-
if (level === "warn") {
|
|
45095
|
-
console.log(` ${c.warning("!")} ${message}`);
|
|
45096
|
-
return;
|
|
45097
|
-
}
|
|
45098
|
-
if (level === "success") {
|
|
45099
|
-
console.log(` ${c.success("✔")} ${message}`);
|
|
45100
|
-
return;
|
|
45101
|
-
}
|
|
45102
|
-
console.log(` ${c.info("●")} ${message}`);
|
|
45103
|
-
}
|
|
45050
|
+
log: createCliLogger()
|
|
45104
45051
|
});
|
|
45105
45052
|
console.log(`
|
|
45106
45053
|
${c.info("●")} ${c.bold("Syncing docs from API...")}
|
|
@@ -45279,7 +45226,11 @@ class JsonStreamRenderer {
|
|
|
45279
45226
|
|
|
45280
45227
|
// src/commands/exec.ts
|
|
45281
45228
|
init_progress_renderer();
|
|
45282
|
-
|
|
45229
|
+
|
|
45230
|
+
// src/settings-manager.ts
|
|
45231
|
+
init_src3();
|
|
45232
|
+
|
|
45233
|
+
// src/commands/exec.ts
|
|
45283
45234
|
init_utils3();
|
|
45284
45235
|
|
|
45285
45236
|
// src/commands/exec-sessions.ts
|
|
@@ -45491,7 +45442,7 @@ async function execCommand(args) {
|
|
|
45491
45442
|
}
|
|
45492
45443
|
}
|
|
45493
45444
|
const execSettings = new SettingsManager(projectPath).load();
|
|
45494
|
-
const provider =
|
|
45445
|
+
const provider = resolveProvider4(values.provider || execSettings.provider);
|
|
45495
45446
|
const model = values.model || execSettings.model || DEFAULT_MODEL[provider];
|
|
45496
45447
|
const isInteractive = values.interactive;
|
|
45497
45448
|
const sessionId = values.session;
|
|
@@ -45587,7 +45538,7 @@ async function execCommand(args) {
|
|
|
45587
45538
|
async function execJsonStream(values, positionals, projectPath) {
|
|
45588
45539
|
const sessionId = values["session-id"] ?? values.session ?? randomUUID2();
|
|
45589
45540
|
const execSettings = new SettingsManager(projectPath).load();
|
|
45590
|
-
const provider =
|
|
45541
|
+
const provider = resolveProvider4(values.provider || execSettings.provider);
|
|
45591
45542
|
const model = values.model || execSettings.model || DEFAULT_MODEL[provider];
|
|
45592
45543
|
const renderer = new JsonStreamRenderer({
|
|
45593
45544
|
sessionId,
|
|
@@ -45757,7 +45708,7 @@ async function indexCommand(args) {
|
|
|
45757
45708
|
const projectPath = values.dir || process.cwd();
|
|
45758
45709
|
requireInitialization(projectPath, "index");
|
|
45759
45710
|
new ConfigManager(projectPath).updateVersion(VERSION2);
|
|
45760
|
-
const provider =
|
|
45711
|
+
const provider = resolveProvider4(values.provider);
|
|
45761
45712
|
const model = values.model || DEFAULT_MODEL[provider];
|
|
45762
45713
|
const aiRunner = createAiRunner(provider, {
|
|
45763
45714
|
projectPath,
|
|
@@ -45848,13 +45799,12 @@ async function initCommand() {
|
|
|
45848
45799
|
init_plan();
|
|
45849
45800
|
|
|
45850
45801
|
// src/commands/review.ts
|
|
45802
|
+
init_src3();
|
|
45851
45803
|
init_index_node();
|
|
45852
45804
|
init_config_manager();
|
|
45853
|
-
init_settings_manager();
|
|
45854
45805
|
init_utils3();
|
|
45855
|
-
|
|
45856
|
-
import {
|
|
45857
|
-
import { join as join19 } from "node:path";
|
|
45806
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "node:fs";
|
|
45807
|
+
import { join as join20 } from "node:path";
|
|
45858
45808
|
import { parseArgs as parseArgs7 } from "node:util";
|
|
45859
45809
|
async function reviewCommand(args) {
|
|
45860
45810
|
const subcommand = args[0];
|
|
@@ -45880,41 +45830,25 @@ async function reviewPrsCommand(args) {
|
|
|
45880
45830
|
requireInitialization(projectPath, "review");
|
|
45881
45831
|
const configManager = new ConfigManager(projectPath);
|
|
45882
45832
|
configManager.updateVersion(VERSION2);
|
|
45883
|
-
|
|
45884
|
-
const settings = settingsManager.load();
|
|
45885
|
-
const apiKey = values["api-key"] || settings.apiKey;
|
|
45886
|
-
if (!apiKey) {
|
|
45887
|
-
console.error(c.error("Error: API key is required for PR review"));
|
|
45888
|
-
console.error(c.dim(`Configure with: locus config setup --api-key <key>
|
|
45889
|
-
Or pass --api-key flag`));
|
|
45890
|
-
console.error(c.dim("For local staged-changes review, use: locus review local"));
|
|
45891
|
-
process.exit(1);
|
|
45892
|
-
}
|
|
45893
|
-
const provider = resolveProvider3(values.provider || settings.provider);
|
|
45894
|
-
const model = values.model || settings.model || DEFAULT_MODEL[provider];
|
|
45895
|
-
const apiBase = values["api-url"] || settings.apiUrl || "https://api.locusai.dev/api";
|
|
45896
|
-
let workspaceId;
|
|
45833
|
+
let apiContext;
|
|
45897
45834
|
try {
|
|
45898
|
-
|
|
45899
|
-
|
|
45900
|
-
|
|
45835
|
+
apiContext = await resolveApiContext({
|
|
45836
|
+
projectPath,
|
|
45837
|
+
apiKey: values["api-key"],
|
|
45838
|
+
apiUrl: values["api-url"],
|
|
45901
45839
|
workspaceId: values.workspace
|
|
45902
45840
|
});
|
|
45903
|
-
workspaceId = await resolver.resolve();
|
|
45904
45841
|
} catch (error48) {
|
|
45905
45842
|
console.error(c.error(error48 instanceof Error ? error48.message : String(error48)));
|
|
45843
|
+
console.error(c.dim("For local staged-changes review, use: locus review local"));
|
|
45906
45844
|
process.exit(1);
|
|
45907
45845
|
}
|
|
45908
|
-
const
|
|
45909
|
-
|
|
45910
|
-
|
|
45911
|
-
|
|
45912
|
-
|
|
45913
|
-
|
|
45914
|
-
}[level];
|
|
45915
|
-
const prefix = { info: "ℹ", success: "✓", warn: "⚠", error: "✗" }[level];
|
|
45916
|
-
console.log(` ${colorFn(`${prefix} ${msg}`)}`);
|
|
45917
|
-
};
|
|
45846
|
+
const { provider, model } = resolveAiSettings({
|
|
45847
|
+
projectPath,
|
|
45848
|
+
provider: values.provider,
|
|
45849
|
+
model: values.model
|
|
45850
|
+
});
|
|
45851
|
+
const log = createCliLogger();
|
|
45918
45852
|
const prService = new PrService(projectPath, log);
|
|
45919
45853
|
const unreviewedPrs = prService.listUnreviewedLocusPrs();
|
|
45920
45854
|
if (unreviewedPrs.length === 0) {
|
|
@@ -45929,10 +45863,10 @@ async function reviewPrsCommand(args) {
|
|
|
45929
45863
|
const agentId = `reviewer-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
45930
45864
|
const reviewer = new ReviewerWorker({
|
|
45931
45865
|
agentId,
|
|
45932
|
-
workspaceId,
|
|
45933
|
-
apiBase,
|
|
45866
|
+
workspaceId: apiContext.workspaceId,
|
|
45867
|
+
apiBase: apiContext.apiBase,
|
|
45934
45868
|
projectPath,
|
|
45935
|
-
apiKey,
|
|
45869
|
+
apiKey: apiContext.apiKey,
|
|
45936
45870
|
model,
|
|
45937
45871
|
provider
|
|
45938
45872
|
});
|
|
@@ -45961,9 +45895,11 @@ async function reviewLocalCommand(args) {
|
|
|
45961
45895
|
});
|
|
45962
45896
|
const projectPath = values.dir || process.cwd();
|
|
45963
45897
|
requireInitialization(projectPath, "review local");
|
|
45964
|
-
const
|
|
45965
|
-
|
|
45966
|
-
|
|
45898
|
+
const { provider, model } = resolveAiSettings({
|
|
45899
|
+
projectPath,
|
|
45900
|
+
provider: values.provider,
|
|
45901
|
+
model: values.model
|
|
45902
|
+
});
|
|
45967
45903
|
const aiRunner = createAiRunner(provider, {
|
|
45968
45904
|
projectPath,
|
|
45969
45905
|
model
|
|
@@ -45971,18 +45907,7 @@ async function reviewLocalCommand(args) {
|
|
|
45971
45907
|
const reviewService = new ReviewService({
|
|
45972
45908
|
aiRunner,
|
|
45973
45909
|
projectPath,
|
|
45974
|
-
log: (
|
|
45975
|
-
switch (level) {
|
|
45976
|
-
case "error":
|
|
45977
|
-
console.log(` ${c.error("✖")} ${msg}`);
|
|
45978
|
-
break;
|
|
45979
|
-
case "success":
|
|
45980
|
-
console.log(` ${c.success("✔")} ${msg}`);
|
|
45981
|
-
break;
|
|
45982
|
-
default:
|
|
45983
|
-
console.log(` ${c.dim(msg)}`);
|
|
45984
|
-
}
|
|
45985
|
-
}
|
|
45910
|
+
log: createCliLogger()
|
|
45986
45911
|
});
|
|
45987
45912
|
console.log(`
|
|
45988
45913
|
${c.primary("\uD83D\uDD0D")} ${c.bold("Reviewing staged changes...")}
|
|
@@ -45993,13 +45918,13 @@ async function reviewLocalCommand(args) {
|
|
|
45993
45918
|
`);
|
|
45994
45919
|
return;
|
|
45995
45920
|
}
|
|
45996
|
-
const reviewsDir =
|
|
45997
|
-
if (!
|
|
45921
|
+
const reviewsDir = join20(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG.reviewsDir);
|
|
45922
|
+
if (!existsSync20(reviewsDir)) {
|
|
45998
45923
|
mkdirSync9(reviewsDir, { recursive: true });
|
|
45999
45924
|
}
|
|
46000
45925
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
46001
|
-
const reportPath =
|
|
46002
|
-
|
|
45926
|
+
const reportPath = join20(reviewsDir, `review-${timestamp}.md`);
|
|
45927
|
+
writeFileSync9(reportPath, report, "utf-8");
|
|
46003
45928
|
console.log(`
|
|
46004
45929
|
${c.success("✔")} ${c.success("Review complete!")}`);
|
|
46005
45930
|
console.log(` ${c.dim("Report saved to:")} ${c.primary(reportPath)}
|
|
@@ -46008,10 +45933,23 @@ async function reviewLocalCommand(args) {
|
|
|
46008
45933
|
// src/commands/run.ts
|
|
46009
45934
|
init_index_node();
|
|
46010
45935
|
init_config_manager();
|
|
46011
|
-
init_settings_manager();
|
|
46012
|
-
init_utils3();
|
|
46013
|
-
init_workspace_resolver();
|
|
46014
45936
|
import { parseArgs as parseArgs8 } from "node:util";
|
|
45937
|
+
init_utils3();
|
|
45938
|
+
|
|
45939
|
+
// src/workspace-resolver.ts
|
|
45940
|
+
init_src3();
|
|
45941
|
+
init_index_node();
|
|
45942
|
+
|
|
45943
|
+
class WorkspaceResolver2 extends WorkspaceResolver {
|
|
45944
|
+
constructor(options) {
|
|
45945
|
+
super({
|
|
45946
|
+
...options,
|
|
45947
|
+
log: (msg) => console.log(c.dim(`ℹ ${msg}`))
|
|
45948
|
+
});
|
|
45949
|
+
}
|
|
45950
|
+
}
|
|
45951
|
+
|
|
45952
|
+
// src/commands/run.ts
|
|
46015
45953
|
async function runCommand(args) {
|
|
46016
45954
|
const { values } = parseArgs8({
|
|
46017
45955
|
args,
|
|
@@ -46042,11 +45980,11 @@ async function runCommand(args) {
|
|
|
46042
45980
|
process.exit(1);
|
|
46043
45981
|
}
|
|
46044
45982
|
let workspaceId = values.workspace;
|
|
46045
|
-
const provider =
|
|
45983
|
+
const provider = resolveProvider4(values.provider || settings.provider);
|
|
46046
45984
|
const model = values.model || settings.model || DEFAULT_MODEL[provider];
|
|
46047
45985
|
const apiBase = values["api-url"] || settings.apiUrl || "https://api.locusai.dev/api";
|
|
46048
45986
|
try {
|
|
46049
|
-
const resolver = new
|
|
45987
|
+
const resolver = new WorkspaceResolver2({
|
|
46050
45988
|
apiKey,
|
|
46051
45989
|
apiBase,
|
|
46052
45990
|
workspaceId: values.workspace
|
|
@@ -46094,10 +46032,9 @@ ${c.info(`Received ${signal}. Stopping agent and cleaning up...`)}`);
|
|
|
46094
46032
|
}
|
|
46095
46033
|
// src/commands/telegram.ts
|
|
46096
46034
|
init_index_node();
|
|
46097
|
-
init_settings_manager();
|
|
46098
46035
|
import { spawn as spawn4 } from "node:child_process";
|
|
46099
|
-
import { existsSync as
|
|
46100
|
-
import { join as
|
|
46036
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
46037
|
+
import { join as join21 } from "node:path";
|
|
46101
46038
|
import { createInterface as createInterface2 } from "node:readline";
|
|
46102
46039
|
function ask2(question) {
|
|
46103
46040
|
const rl = createInterface2({
|
|
@@ -46331,8 +46268,8 @@ function runBotCommand(projectPath) {
|
|
|
46331
46268
|
`);
|
|
46332
46269
|
process.exit(1);
|
|
46333
46270
|
}
|
|
46334
|
-
const monorepoTelegramEntry =
|
|
46335
|
-
const isMonorepo =
|
|
46271
|
+
const monorepoTelegramEntry = join21(projectPath, "packages/telegram/src/index.ts");
|
|
46272
|
+
const isMonorepo = existsSync21(monorepoTelegramEntry);
|
|
46336
46273
|
let cmd;
|
|
46337
46274
|
let args;
|
|
46338
46275
|
if (isMonorepo) {
|