@locusai/cli 0.15.5 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/agent/worker.js +134 -359
- package/bin/locus.js +865 -1658
- package/package.json +4 -4
package/bin/locus.js
CHANGED
|
@@ -7055,7 +7055,6 @@ var init_resolve_bin = __esm(() => {
|
|
|
7055
7055
|
join4(homedir(), ".local", "bin"),
|
|
7056
7056
|
join4(homedir(), ".npm", "bin"),
|
|
7057
7057
|
join4(homedir(), ".npm-global", "bin"),
|
|
7058
|
-
join4(homedir(), ".npm-packages", "bin"),
|
|
7059
7058
|
join4(homedir(), ".yarn", "bin"),
|
|
7060
7059
|
join4(homedir(), ".bun", "bin"),
|
|
7061
7060
|
join4(homedir(), "Library", "pnpm"),
|
|
@@ -7066,6 +7065,112 @@ var init_resolve_bin = __esm(() => {
|
|
|
7066
7065
|
ENV_VARS_TO_STRIP = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"];
|
|
7067
7066
|
});
|
|
7068
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
|
+
|
|
7069
7174
|
// ../sdk/src/ai/claude-runner.ts
|
|
7070
7175
|
import { spawn } from "node:child_process";
|
|
7071
7176
|
import { resolve } from "node:path";
|
|
@@ -7076,7 +7181,6 @@ class ClaudeRunner {
|
|
|
7076
7181
|
projectPath;
|
|
7077
7182
|
eventEmitter;
|
|
7078
7183
|
currentToolName;
|
|
7079
|
-
activeTools = new Map;
|
|
7080
7184
|
activeProcess = null;
|
|
7081
7185
|
aborted = false;
|
|
7082
7186
|
timeoutMs;
|
|
@@ -7111,7 +7215,7 @@ class ClaudeRunner {
|
|
|
7111
7215
|
}
|
|
7112
7216
|
if (!isLastAttempt) {
|
|
7113
7217
|
const delay = Math.pow(2, attempt) * 1000;
|
|
7114
|
-
|
|
7218
|
+
this.log?.(`Claude CLI attempt ${attempt} failed: ${err.message}. Retrying in ${delay}ms...`, "warn");
|
|
7115
7219
|
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
7116
7220
|
}
|
|
7117
7221
|
}
|
|
@@ -7151,6 +7255,7 @@ class ClaudeRunner {
|
|
|
7151
7255
|
}
|
|
7152
7256
|
async* runStream(prompt) {
|
|
7153
7257
|
this.aborted = false;
|
|
7258
|
+
const parser = new ClaudeStreamParser;
|
|
7154
7259
|
const args = this.buildCliArgs();
|
|
7155
7260
|
const env = getAugmentedEnv({
|
|
7156
7261
|
FORCE_COLOR: "1",
|
|
@@ -7211,7 +7316,7 @@ class ClaudeRunner {
|
|
|
7211
7316
|
`);
|
|
7212
7317
|
buffer = lines.pop() || "";
|
|
7213
7318
|
for (const line of lines) {
|
|
7214
|
-
const chunk =
|
|
7319
|
+
const chunk = parser.parseLineToChunk(line);
|
|
7215
7320
|
if (chunk) {
|
|
7216
7321
|
if (chunk.type === "result") {
|
|
7217
7322
|
lastResultContent = chunk.content;
|
|
@@ -7320,77 +7425,9 @@ class ClaudeRunner {
|
|
|
7320
7425
|
break;
|
|
7321
7426
|
}
|
|
7322
7427
|
}
|
|
7323
|
-
parseStreamLineToChunk(line) {
|
|
7324
|
-
if (!line.trim())
|
|
7325
|
-
return null;
|
|
7326
|
-
try {
|
|
7327
|
-
const item = JSON.parse(line);
|
|
7328
|
-
return this.processStreamItemToChunk(item);
|
|
7329
|
-
} catch {
|
|
7330
|
-
return null;
|
|
7331
|
-
}
|
|
7332
|
-
}
|
|
7333
|
-
processStreamItemToChunk(item) {
|
|
7334
|
-
if (item.type === "result") {
|
|
7335
|
-
return { type: "result", content: item.result || "" };
|
|
7336
|
-
}
|
|
7337
|
-
if (item.type === "stream_event" && item.event) {
|
|
7338
|
-
return this.handleEventToChunk(item.event);
|
|
7339
|
-
}
|
|
7340
|
-
return null;
|
|
7341
|
-
}
|
|
7342
|
-
handleEventToChunk(event) {
|
|
7343
|
-
const { type, delta, content_block, index } = event;
|
|
7344
|
-
if (type === "content_block_delta" && delta?.type === "text_delta") {
|
|
7345
|
-
return { type: "text_delta", content: delta.text || "" };
|
|
7346
|
-
}
|
|
7347
|
-
if (type === "content_block_delta" && delta?.type === "input_json_delta" && delta.partial_json !== undefined && index !== undefined) {
|
|
7348
|
-
const activeTool = this.activeTools.get(index);
|
|
7349
|
-
if (activeTool) {
|
|
7350
|
-
activeTool.parameterJson += delta.partial_json;
|
|
7351
|
-
}
|
|
7352
|
-
return null;
|
|
7353
|
-
}
|
|
7354
|
-
if (type === "content_block_start" && content_block) {
|
|
7355
|
-
if (content_block.type === "tool_use" && content_block.name) {
|
|
7356
|
-
if (index !== undefined) {
|
|
7357
|
-
this.activeTools.set(index, {
|
|
7358
|
-
name: content_block.name,
|
|
7359
|
-
id: content_block.id,
|
|
7360
|
-
index,
|
|
7361
|
-
parameterJson: "",
|
|
7362
|
-
startTime: Date.now()
|
|
7363
|
-
});
|
|
7364
|
-
}
|
|
7365
|
-
return {
|
|
7366
|
-
type: "tool_use",
|
|
7367
|
-
tool: content_block.name,
|
|
7368
|
-
id: content_block.id
|
|
7369
|
-
};
|
|
7370
|
-
}
|
|
7371
|
-
if (content_block.type === "thinking") {
|
|
7372
|
-
return { type: "thinking" };
|
|
7373
|
-
}
|
|
7374
|
-
}
|
|
7375
|
-
if (type === "content_block_stop" && index !== undefined) {
|
|
7376
|
-
const activeTool = this.activeTools.get(index);
|
|
7377
|
-
if (activeTool?.parameterJson) {
|
|
7378
|
-
try {
|
|
7379
|
-
const parameters = JSON.parse(activeTool.parameterJson);
|
|
7380
|
-
return {
|
|
7381
|
-
type: "tool_parameters",
|
|
7382
|
-
tool: activeTool.name,
|
|
7383
|
-
id: activeTool.id,
|
|
7384
|
-
parameters
|
|
7385
|
-
};
|
|
7386
|
-
} catch {}
|
|
7387
|
-
}
|
|
7388
|
-
return null;
|
|
7389
|
-
}
|
|
7390
|
-
return null;
|
|
7391
|
-
}
|
|
7392
7428
|
executeRun(prompt) {
|
|
7393
7429
|
this.aborted = false;
|
|
7430
|
+
const parser = new ClaudeStreamParser;
|
|
7394
7431
|
return new Promise((resolve2, reject) => {
|
|
7395
7432
|
const args = this.buildCliArgs();
|
|
7396
7433
|
const env = getAugmentedEnv({
|
|
@@ -7413,7 +7450,7 @@ class ClaudeRunner {
|
|
|
7413
7450
|
`);
|
|
7414
7451
|
buffer = lines.pop() || "";
|
|
7415
7452
|
for (const line of lines) {
|
|
7416
|
-
const result =
|
|
7453
|
+
const result = parser.parseLine(line, this.log);
|
|
7417
7454
|
if (result)
|
|
7418
7455
|
finalResult = result;
|
|
7419
7456
|
}
|
|
@@ -7454,35 +7491,6 @@ class ClaudeRunner {
|
|
|
7454
7491
|
claude.stdin.end();
|
|
7455
7492
|
});
|
|
7456
7493
|
}
|
|
7457
|
-
handleStreamLine(line) {
|
|
7458
|
-
if (!line.trim())
|
|
7459
|
-
return null;
|
|
7460
|
-
try {
|
|
7461
|
-
const item = JSON.parse(line);
|
|
7462
|
-
return this.processStreamItem(item);
|
|
7463
|
-
} catch {
|
|
7464
|
-
return null;
|
|
7465
|
-
}
|
|
7466
|
-
}
|
|
7467
|
-
processStreamItem(item) {
|
|
7468
|
-
if (item.type === "result") {
|
|
7469
|
-
return item.result || "";
|
|
7470
|
-
}
|
|
7471
|
-
if (item.type === "stream_event" && item.event) {
|
|
7472
|
-
this.handleEvent(item.event);
|
|
7473
|
-
}
|
|
7474
|
-
return null;
|
|
7475
|
-
}
|
|
7476
|
-
handleEvent(event) {
|
|
7477
|
-
const { type, content_block } = event;
|
|
7478
|
-
if (type === "content_block_start" && content_block) {
|
|
7479
|
-
if (content_block.type === "tool_use" && content_block.name) {
|
|
7480
|
-
this.log?.(`
|
|
7481
|
-
${c.primary("[Claude]")} ${c.bold(`Running ${content_block.name}...`)}
|
|
7482
|
-
`, "info");
|
|
7483
|
-
}
|
|
7484
|
-
}
|
|
7485
|
-
}
|
|
7486
7494
|
shouldSuppressLine(line) {
|
|
7487
7495
|
const infoLogRegex = /^\[\d{2}:\d{2}:\d{2}\]\s\[.*?\]\sℹ\s*$/;
|
|
7488
7496
|
return infoLogRegex.test(line.trim());
|
|
@@ -7496,8 +7504,8 @@ ${c.primary("[Claude]")} ${c.bold(`Running ${content_block.name}...`)}
|
|
|
7496
7504
|
var DEFAULT_TIMEOUT_MS;
|
|
7497
7505
|
var init_claude_runner = __esm(() => {
|
|
7498
7506
|
init_config();
|
|
7499
|
-
init_colors();
|
|
7500
7507
|
init_resolve_bin();
|
|
7508
|
+
init_claude_stream_parser();
|
|
7501
7509
|
DEFAULT_TIMEOUT_MS = 60 * 60 * 1000;
|
|
7502
7510
|
});
|
|
7503
7511
|
|
|
@@ -7549,7 +7557,7 @@ class CodexRunner {
|
|
|
7549
7557
|
}
|
|
7550
7558
|
if (attempt < maxRetries) {
|
|
7551
7559
|
const delay = Math.pow(2, attempt) * 1000;
|
|
7552
|
-
|
|
7560
|
+
this.log?.(`Codex CLI attempt ${attempt} failed: ${lastError.message}. Retrying in ${delay}ms...`, "warn");
|
|
7553
7561
|
await this.sleep(delay);
|
|
7554
7562
|
}
|
|
7555
7563
|
}
|
|
@@ -7841,6 +7849,20 @@ var init_codex_runner = __esm(() => {
|
|
|
7841
7849
|
});
|
|
7842
7850
|
|
|
7843
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
|
+
}
|
|
7844
7866
|
function createAiRunner(provider, config) {
|
|
7845
7867
|
const resolvedProvider = provider ?? PROVIDER.CLAUDE;
|
|
7846
7868
|
const model = config.model ?? DEFAULT_MODEL[resolvedProvider];
|
|
@@ -7855,8 +7877,10 @@ function createAiRunner(provider, config) {
|
|
|
7855
7877
|
return new ClaudeRunner(config.projectPath, model, config.log, config.timeoutMs);
|
|
7856
7878
|
}
|
|
7857
7879
|
}
|
|
7880
|
+
var noopLogger = () => {};
|
|
7858
7881
|
var init_factory = __esm(() => {
|
|
7859
7882
|
init_config();
|
|
7883
|
+
init_colors();
|
|
7860
7884
|
init_claude_runner();
|
|
7861
7885
|
init_codex_runner();
|
|
7862
7886
|
});
|
|
@@ -23202,49 +23226,6 @@ var init_docs = __esm(() => {
|
|
|
23202
23226
|
};
|
|
23203
23227
|
});
|
|
23204
23228
|
|
|
23205
|
-
// ../sdk/src/modules/instances.ts
|
|
23206
|
-
var InstancesModule;
|
|
23207
|
-
var init_instances = __esm(() => {
|
|
23208
|
-
InstancesModule = class InstancesModule extends BaseModule {
|
|
23209
|
-
async list(workspaceId) {
|
|
23210
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances`);
|
|
23211
|
-
return data.instances;
|
|
23212
|
-
}
|
|
23213
|
-
async get(workspaceId, instanceId) {
|
|
23214
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances/${instanceId}`);
|
|
23215
|
-
return data.instance;
|
|
23216
|
-
}
|
|
23217
|
-
async provision(workspaceId, body) {
|
|
23218
|
-
const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances`, body);
|
|
23219
|
-
return data.instance;
|
|
23220
|
-
}
|
|
23221
|
-
async performAction(workspaceId, instanceId, action) {
|
|
23222
|
-
const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances/${instanceId}/actions`, { action });
|
|
23223
|
-
return data.instance;
|
|
23224
|
-
}
|
|
23225
|
-
async sync(workspaceId, instanceId) {
|
|
23226
|
-
const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances/${instanceId}/sync`);
|
|
23227
|
-
return data.instance;
|
|
23228
|
-
}
|
|
23229
|
-
async checkUpdates(workspaceId, instanceId) {
|
|
23230
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances/${instanceId}/updates`);
|
|
23231
|
-
return data.update;
|
|
23232
|
-
}
|
|
23233
|
-
async applyUpdate(workspaceId, instanceId) {
|
|
23234
|
-
const { data } = await this.api.post(`/workspaces/${workspaceId}/aws-instances/${instanceId}/updates`);
|
|
23235
|
-
return data.update;
|
|
23236
|
-
}
|
|
23237
|
-
async getSecurity(workspaceId, instanceId) {
|
|
23238
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-instances/${instanceId}/security`);
|
|
23239
|
-
return data.rules;
|
|
23240
|
-
}
|
|
23241
|
-
async updateSecurity(workspaceId, instanceId, body) {
|
|
23242
|
-
const { data } = await this.api.put(`/workspaces/${workspaceId}/aws-instances/${instanceId}/security`, body);
|
|
23243
|
-
return data.rules;
|
|
23244
|
-
}
|
|
23245
|
-
};
|
|
23246
|
-
});
|
|
23247
|
-
|
|
23248
23229
|
// ../sdk/src/modules/invitations.ts
|
|
23249
23230
|
var InvitationsModule;
|
|
23250
23231
|
var init_invitations = __esm(() => {
|
|
@@ -23353,29 +23334,6 @@ var init_sprints = __esm(() => {
|
|
|
23353
23334
|
};
|
|
23354
23335
|
});
|
|
23355
23336
|
|
|
23356
|
-
// ../sdk/src/modules/suggestions.ts
|
|
23357
|
-
var SuggestionsModule;
|
|
23358
|
-
var init_suggestions = __esm(() => {
|
|
23359
|
-
SuggestionsModule = class SuggestionsModule extends BaseModule {
|
|
23360
|
-
async create(workspaceId, data) {
|
|
23361
|
-
const { data: res } = await this.api.post(`/workspaces/${workspaceId}/suggestions`, data);
|
|
23362
|
-
return res.suggestion;
|
|
23363
|
-
}
|
|
23364
|
-
async list(workspaceId, params) {
|
|
23365
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/suggestions`, { params });
|
|
23366
|
-
return data.suggestions;
|
|
23367
|
-
}
|
|
23368
|
-
async get(workspaceId, id) {
|
|
23369
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/suggestions/${id}`);
|
|
23370
|
-
return data.suggestion;
|
|
23371
|
-
}
|
|
23372
|
-
async updateStatus(workspaceId, id, status) {
|
|
23373
|
-
const { data } = await this.api.patch(`/workspaces/${workspaceId}/suggestions/${id}/status`, status);
|
|
23374
|
-
return data.suggestion;
|
|
23375
|
-
}
|
|
23376
|
-
};
|
|
23377
|
-
});
|
|
23378
|
-
|
|
23379
23337
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/core.js
|
|
23380
23338
|
function $constructor(name, initializer, params) {
|
|
23381
23339
|
function init(inst, def) {
|
|
@@ -37297,7 +37255,7 @@ var init_constants = __esm(() => {
|
|
|
37297
37255
|
});
|
|
37298
37256
|
|
|
37299
37257
|
// ../shared/src/enums.ts
|
|
37300
|
-
var UserRole, MembershipRole, TaskStatus, TaskPriority, AssigneeRole, SprintStatus,
|
|
37258
|
+
var UserRole, MembershipRole, TaskStatus, TaskPriority, AssigneeRole, SprintStatus, EventType;
|
|
37301
37259
|
var init_enums = __esm(() => {
|
|
37302
37260
|
((UserRole2) => {
|
|
37303
37261
|
UserRole2["USER"] = "USER";
|
|
@@ -37334,16 +37292,6 @@ var init_enums = __esm(() => {
|
|
|
37334
37292
|
SprintStatus2["ACTIVE"] = "ACTIVE";
|
|
37335
37293
|
SprintStatus2["COMPLETED"] = "COMPLETED";
|
|
37336
37294
|
})(SprintStatus ||= {});
|
|
37337
|
-
((InstanceStatus2) => {
|
|
37338
|
-
InstanceStatus2["PROVISIONING"] = "PROVISIONING";
|
|
37339
|
-
InstanceStatus2["RUNNING"] = "RUNNING";
|
|
37340
|
-
InstanceStatus2["STOPPED"] = "STOPPED";
|
|
37341
|
-
InstanceStatus2["TERMINATED"] = "TERMINATED";
|
|
37342
|
-
InstanceStatus2["ERROR"] = "ERROR";
|
|
37343
|
-
})(InstanceStatus ||= {});
|
|
37344
|
-
((AwsRegion2) => {
|
|
37345
|
-
AwsRegion2["US_EAST_1"] = "us-east-1";
|
|
37346
|
-
})(AwsRegion ||= {});
|
|
37347
37295
|
((EventType2) => {
|
|
37348
37296
|
EventType2["TASK_CREATED"] = "TASK_CREATED";
|
|
37349
37297
|
EventType2["TASK_UPDATED"] = "TASK_UPDATED";
|
|
@@ -37691,145 +37639,6 @@ var init_auth2 = __esm(() => {
|
|
|
37691
37639
|
});
|
|
37692
37640
|
});
|
|
37693
37641
|
|
|
37694
|
-
// ../shared/src/models/autonomy.ts
|
|
37695
|
-
var RiskLevel, ChangeCategory, AutonomyRuleSchema, DEFAULT_AUTONOMY_RULES;
|
|
37696
|
-
var init_autonomy = __esm(() => {
|
|
37697
|
-
init_zod();
|
|
37698
|
-
((RiskLevel2) => {
|
|
37699
|
-
RiskLevel2["LOW"] = "LOW";
|
|
37700
|
-
RiskLevel2["HIGH"] = "HIGH";
|
|
37701
|
-
})(RiskLevel ||= {});
|
|
37702
|
-
((ChangeCategory2) => {
|
|
37703
|
-
ChangeCategory2["FIX"] = "FIX";
|
|
37704
|
-
ChangeCategory2["REFACTOR"] = "REFACTOR";
|
|
37705
|
-
ChangeCategory2["STYLE"] = "STYLE";
|
|
37706
|
-
ChangeCategory2["DEPENDENCY"] = "DEPENDENCY";
|
|
37707
|
-
ChangeCategory2["FEATURE"] = "FEATURE";
|
|
37708
|
-
ChangeCategory2["ARCHITECTURE"] = "ARCHITECTURE";
|
|
37709
|
-
ChangeCategory2["DATABASE"] = "DATABASE";
|
|
37710
|
-
ChangeCategory2["AUTH"] = "AUTH";
|
|
37711
|
-
ChangeCategory2["API"] = "API";
|
|
37712
|
-
})(ChangeCategory ||= {});
|
|
37713
|
-
AutonomyRuleSchema = exports_external.object({
|
|
37714
|
-
category: exports_external.enum(ChangeCategory),
|
|
37715
|
-
riskLevel: exports_external.enum(RiskLevel),
|
|
37716
|
-
autoExecute: exports_external.boolean()
|
|
37717
|
-
});
|
|
37718
|
-
DEFAULT_AUTONOMY_RULES = [
|
|
37719
|
-
{ category: "FIX" /* FIX */, riskLevel: "LOW" /* LOW */, autoExecute: true },
|
|
37720
|
-
{
|
|
37721
|
-
category: "REFACTOR" /* REFACTOR */,
|
|
37722
|
-
riskLevel: "LOW" /* LOW */,
|
|
37723
|
-
autoExecute: true
|
|
37724
|
-
},
|
|
37725
|
-
{
|
|
37726
|
-
category: "STYLE" /* STYLE */,
|
|
37727
|
-
riskLevel: "LOW" /* LOW */,
|
|
37728
|
-
autoExecute: true
|
|
37729
|
-
},
|
|
37730
|
-
{
|
|
37731
|
-
category: "DEPENDENCY" /* DEPENDENCY */,
|
|
37732
|
-
riskLevel: "LOW" /* LOW */,
|
|
37733
|
-
autoExecute: true
|
|
37734
|
-
},
|
|
37735
|
-
{
|
|
37736
|
-
category: "FEATURE" /* FEATURE */,
|
|
37737
|
-
riskLevel: "HIGH" /* HIGH */,
|
|
37738
|
-
autoExecute: false
|
|
37739
|
-
},
|
|
37740
|
-
{
|
|
37741
|
-
category: "ARCHITECTURE" /* ARCHITECTURE */,
|
|
37742
|
-
riskLevel: "HIGH" /* HIGH */,
|
|
37743
|
-
autoExecute: false
|
|
37744
|
-
},
|
|
37745
|
-
{
|
|
37746
|
-
category: "DATABASE" /* DATABASE */,
|
|
37747
|
-
riskLevel: "HIGH" /* HIGH */,
|
|
37748
|
-
autoExecute: false
|
|
37749
|
-
},
|
|
37750
|
-
{
|
|
37751
|
-
category: "AUTH" /* AUTH */,
|
|
37752
|
-
riskLevel: "HIGH" /* HIGH */,
|
|
37753
|
-
autoExecute: false
|
|
37754
|
-
},
|
|
37755
|
-
{
|
|
37756
|
-
category: "API" /* API */,
|
|
37757
|
-
riskLevel: "HIGH" /* HIGH */,
|
|
37758
|
-
autoExecute: false
|
|
37759
|
-
}
|
|
37760
|
-
];
|
|
37761
|
-
});
|
|
37762
|
-
|
|
37763
|
-
// ../shared/src/models/aws-instance.ts
|
|
37764
|
-
var InstanceAction, AwsCredentialsSchema, IntegrationSchema, AwsInstanceSchema, CreateAwsInstanceSchema, UpdateAwsInstanceSchema, SaveAwsCredentialsSchema, ProvisionAwsInstanceSchema, InstanceActionBodySchema, InstanceIdParamSchema, CIDR_REGEX, UpdateSecurityRulesSchema;
|
|
37765
|
-
var init_aws_instance = __esm(() => {
|
|
37766
|
-
init_zod();
|
|
37767
|
-
init_common();
|
|
37768
|
-
init_enums();
|
|
37769
|
-
((InstanceAction2) => {
|
|
37770
|
-
InstanceAction2["START"] = "START";
|
|
37771
|
-
InstanceAction2["STOP"] = "STOP";
|
|
37772
|
-
InstanceAction2["TERMINATE"] = "TERMINATE";
|
|
37773
|
-
})(InstanceAction ||= {});
|
|
37774
|
-
AwsCredentialsSchema = exports_external.object({
|
|
37775
|
-
accessKeyId: exports_external.string().min(1),
|
|
37776
|
-
secretAccessKey: exports_external.string().min(1),
|
|
37777
|
-
region: exports_external.enum(AwsRegion).default("us-east-1" /* US_EAST_1 */)
|
|
37778
|
-
});
|
|
37779
|
-
IntegrationSchema = exports_external.object({
|
|
37780
|
-
name: exports_external.string(),
|
|
37781
|
-
config: exports_external.record(exports_external.string(), exports_external.string())
|
|
37782
|
-
});
|
|
37783
|
-
AwsInstanceSchema = BaseEntitySchema.extend({
|
|
37784
|
-
workspaceId: exports_external.uuid(),
|
|
37785
|
-
instanceId: exports_external.string(),
|
|
37786
|
-
status: exports_external.enum(InstanceStatus),
|
|
37787
|
-
instanceType: exports_external.enum(["t3.micro", "t3.small", "t3.medium"]),
|
|
37788
|
-
region: exports_external.enum(AwsRegion).default("us-east-1" /* US_EAST_1 */),
|
|
37789
|
-
publicIp: exports_external.string().nullable().optional(),
|
|
37790
|
-
launchTime: exports_external.union([exports_external.date(), exports_external.number()]).nullable().optional(),
|
|
37791
|
-
repoUrl: exports_external.string().nullable().optional(),
|
|
37792
|
-
integrations: exports_external.array(IntegrationSchema).default([])
|
|
37793
|
-
});
|
|
37794
|
-
CreateAwsInstanceSchema = exports_external.object({
|
|
37795
|
-
workspaceId: exports_external.uuid(),
|
|
37796
|
-
instanceType: exports_external.enum(["t3.micro", "t3.small", "t3.medium"]).default("t3.micro"),
|
|
37797
|
-
region: exports_external.enum(AwsRegion).default("us-east-1" /* US_EAST_1 */),
|
|
37798
|
-
repoUrl: exports_external.string().optional(),
|
|
37799
|
-
integrations: exports_external.array(IntegrationSchema).optional().default([])
|
|
37800
|
-
});
|
|
37801
|
-
UpdateAwsInstanceSchema = exports_external.object({
|
|
37802
|
-
status: exports_external.enum(InstanceStatus).optional(),
|
|
37803
|
-
instanceType: exports_external.enum(["t3.micro", "t3.small", "t3.medium"]).optional(),
|
|
37804
|
-
publicIp: exports_external.string().nullable().optional(),
|
|
37805
|
-
launchTime: exports_external.union([exports_external.date(), exports_external.number()]).nullable().optional(),
|
|
37806
|
-
repoUrl: exports_external.string().nullable().optional(),
|
|
37807
|
-
integrations: exports_external.array(IntegrationSchema).optional()
|
|
37808
|
-
});
|
|
37809
|
-
SaveAwsCredentialsSchema = exports_external.object({
|
|
37810
|
-
accessKeyId: exports_external.string().min(16),
|
|
37811
|
-
secretAccessKey: exports_external.string().min(1),
|
|
37812
|
-
region: exports_external.string().default("us-east-1")
|
|
37813
|
-
});
|
|
37814
|
-
ProvisionAwsInstanceSchema = exports_external.object({
|
|
37815
|
-
repoUrl: exports_external.string().min(1),
|
|
37816
|
-
githubToken: exports_external.string().min(1),
|
|
37817
|
-
instanceType: exports_external.enum(["t3.micro", "t3.small", "t3.medium"]).default("t3.small"),
|
|
37818
|
-
integrations: exports_external.array(IntegrationSchema).optional().default([])
|
|
37819
|
-
});
|
|
37820
|
-
InstanceActionBodySchema = exports_external.object({
|
|
37821
|
-
action: exports_external.nativeEnum(InstanceAction)
|
|
37822
|
-
});
|
|
37823
|
-
InstanceIdParamSchema = exports_external.object({
|
|
37824
|
-
workspaceId: exports_external.string().uuid("Invalid Workspace ID"),
|
|
37825
|
-
instanceId: exports_external.string().uuid("Invalid Instance ID")
|
|
37826
|
-
});
|
|
37827
|
-
CIDR_REGEX = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}$/;
|
|
37828
|
-
UpdateSecurityRulesSchema = exports_external.object({
|
|
37829
|
-
allowedIps: exports_external.array(exports_external.string().regex(CIDR_REGEX, "Invalid CIDR format (e.g. 1.2.3.4/32)"))
|
|
37830
|
-
});
|
|
37831
|
-
});
|
|
37832
|
-
|
|
37833
37642
|
// ../shared/src/models/ci.ts
|
|
37834
37643
|
var RecordCiSchema;
|
|
37835
37644
|
var init_ci2 = __esm(() => {
|
|
@@ -38078,49 +37887,6 @@ var init_sprint = __esm(() => {
|
|
|
38078
37887
|
});
|
|
38079
37888
|
});
|
|
38080
37889
|
|
|
38081
|
-
// ../shared/src/models/suggestion.ts
|
|
38082
|
-
var SuggestionStatus, SuggestionType, SuggestionSchema, CreateSuggestionSchema, UpdateSuggestionStatusSchema;
|
|
38083
|
-
var init_suggestion = __esm(() => {
|
|
38084
|
-
init_zod();
|
|
38085
|
-
((SuggestionStatus2) => {
|
|
38086
|
-
SuggestionStatus2["NEW"] = "NEW";
|
|
38087
|
-
SuggestionStatus2["NOTIFIED"] = "NOTIFIED";
|
|
38088
|
-
SuggestionStatus2["ACTED_ON"] = "ACTED_ON";
|
|
38089
|
-
SuggestionStatus2["SKIPPED"] = "SKIPPED";
|
|
38090
|
-
SuggestionStatus2["EXPIRED"] = "EXPIRED";
|
|
38091
|
-
})(SuggestionStatus ||= {});
|
|
38092
|
-
((SuggestionType2) => {
|
|
38093
|
-
SuggestionType2["CODE_FIX"] = "CODE_FIX";
|
|
38094
|
-
SuggestionType2["DEPENDENCY_UPDATE"] = "DEPENDENCY_UPDATE";
|
|
38095
|
-
SuggestionType2["NEXT_STEP"] = "NEXT_STEP";
|
|
38096
|
-
SuggestionType2["REFACTOR"] = "REFACTOR";
|
|
38097
|
-
SuggestionType2["TEST_FIX"] = "TEST_FIX";
|
|
38098
|
-
})(SuggestionType ||= {});
|
|
38099
|
-
SuggestionSchema = exports_external.object({
|
|
38100
|
-
id: exports_external.string(),
|
|
38101
|
-
type: exports_external.enum(SuggestionType),
|
|
38102
|
-
status: exports_external.enum(SuggestionStatus),
|
|
38103
|
-
title: exports_external.string(),
|
|
38104
|
-
description: exports_external.string(),
|
|
38105
|
-
jobRunId: exports_external.string().optional(),
|
|
38106
|
-
workspaceId: exports_external.string(),
|
|
38107
|
-
createdAt: exports_external.string(),
|
|
38108
|
-
expiresAt: exports_external.string(),
|
|
38109
|
-
metadata: exports_external.record(exports_external.string(), exports_external.any()).optional()
|
|
38110
|
-
});
|
|
38111
|
-
CreateSuggestionSchema = exports_external.object({
|
|
38112
|
-
type: exports_external.enum(SuggestionType),
|
|
38113
|
-
title: exports_external.string().min(1, "Title is required"),
|
|
38114
|
-
description: exports_external.string().min(1, "Description is required"),
|
|
38115
|
-
jobRunId: exports_external.string().uuid().optional(),
|
|
38116
|
-
metadata: exports_external.record(exports_external.string(), exports_external.any()).optional(),
|
|
38117
|
-
expiresAt: exports_external.string().optional()
|
|
38118
|
-
});
|
|
38119
|
-
UpdateSuggestionStatusSchema = exports_external.object({
|
|
38120
|
-
status: exports_external.enum(SuggestionStatus)
|
|
38121
|
-
});
|
|
38122
|
-
});
|
|
38123
|
-
|
|
38124
37890
|
// ../shared/src/models/task.ts
|
|
38125
37891
|
var AcceptanceItemSchema, TaskSchema, CreateTaskSchema, UpdateTaskSchema, AddCommentSchema, DispatchTaskSchema, TaskIdParamSchema, TaskQuerySchema, TaskResponseSchema, TasksResponseSchema;
|
|
38126
37892
|
var init_task = __esm(() => {
|
|
@@ -38260,15 +38026,12 @@ var init_models = __esm(() => {
|
|
|
38260
38026
|
init_activity();
|
|
38261
38027
|
init_agent();
|
|
38262
38028
|
init_auth2();
|
|
38263
|
-
init_autonomy();
|
|
38264
|
-
init_aws_instance();
|
|
38265
38029
|
init_ci2();
|
|
38266
38030
|
init_doc();
|
|
38267
38031
|
init_doc_group();
|
|
38268
38032
|
init_invitation();
|
|
38269
38033
|
init_organization();
|
|
38270
38034
|
init_sprint();
|
|
38271
|
-
init_suggestion();
|
|
38272
38035
|
init_task();
|
|
38273
38036
|
init_user();
|
|
38274
38037
|
init_workspace();
|
|
@@ -38931,17 +38694,6 @@ var init_workspaces = __esm(() => {
|
|
|
38931
38694
|
async deleteApiKey(workspaceId, keyId) {
|
|
38932
38695
|
await this.api.delete(`/workspaces/${workspaceId}/api-keys/${keyId}`);
|
|
38933
38696
|
}
|
|
38934
|
-
async getAwsCredentials(workspaceId) {
|
|
38935
|
-
const { data } = await this.api.get(`/workspaces/${workspaceId}/aws-credentials`);
|
|
38936
|
-
return data.credential;
|
|
38937
|
-
}
|
|
38938
|
-
async saveAwsCredentials(workspaceId, body) {
|
|
38939
|
-
const { data } = await this.api.put(`/workspaces/${workspaceId}/aws-credentials`, body);
|
|
38940
|
-
return data.credential;
|
|
38941
|
-
}
|
|
38942
|
-
async deleteAwsCredentials(workspaceId) {
|
|
38943
|
-
await this.api.delete(`/workspaces/${workspaceId}/aws-credentials`);
|
|
38944
|
-
}
|
|
38945
38697
|
};
|
|
38946
38698
|
});
|
|
38947
38699
|
|
|
@@ -38990,8 +38742,6 @@ class LocusClient {
|
|
|
38990
38742
|
invitations;
|
|
38991
38743
|
docs;
|
|
38992
38744
|
ci;
|
|
38993
|
-
instances;
|
|
38994
|
-
suggestions;
|
|
38995
38745
|
constructor(config2) {
|
|
38996
38746
|
this.emitter = new LocusEmitter;
|
|
38997
38747
|
this.api = axios_default.create({
|
|
@@ -39011,8 +38761,6 @@ class LocusClient {
|
|
|
39011
38761
|
this.invitations = new InvitationsModule(this.api, this.emitter);
|
|
39012
38762
|
this.docs = new DocsModule(this.api, this.emitter);
|
|
39013
38763
|
this.ci = new CiModule(this.api, this.emitter);
|
|
39014
|
-
this.instances = new InstancesModule(this.api, this.emitter);
|
|
39015
|
-
this.suggestions = new SuggestionsModule(this.api, this.emitter);
|
|
39016
38764
|
if (config2.retryOptions) {
|
|
39017
38765
|
this.setupRetryInterceptor(config2.retryOptions);
|
|
39018
38766
|
}
|
|
@@ -39078,11 +38826,9 @@ var init_src2 = __esm(() => {
|
|
|
39078
38826
|
init_auth();
|
|
39079
38827
|
init_ci();
|
|
39080
38828
|
init_docs();
|
|
39081
|
-
init_instances();
|
|
39082
38829
|
init_invitations();
|
|
39083
38830
|
init_organizations();
|
|
39084
38831
|
init_sprints();
|
|
39085
|
-
init_suggestions();
|
|
39086
38832
|
init_tasks();
|
|
39087
38833
|
init_workspaces();
|
|
39088
38834
|
init_discussion_types();
|
|
@@ -39090,11 +38836,9 @@ var init_src2 = __esm(() => {
|
|
|
39090
38836
|
init_auth();
|
|
39091
38837
|
init_ci();
|
|
39092
38838
|
init_docs();
|
|
39093
|
-
init_instances();
|
|
39094
38839
|
init_invitations();
|
|
39095
38840
|
init_organizations();
|
|
39096
38841
|
init_sprints();
|
|
39097
|
-
init_suggestions();
|
|
39098
38842
|
init_tasks();
|
|
39099
38843
|
init_workspaces();
|
|
39100
38844
|
});
|
|
@@ -39117,9 +38861,11 @@ class ReviewerWorker {
|
|
|
39117
38861
|
currentTaskId = null;
|
|
39118
38862
|
maxReviews = 50;
|
|
39119
38863
|
reviewsCompleted = 0;
|
|
38864
|
+
log;
|
|
39120
38865
|
constructor(config2) {
|
|
39121
38866
|
this.config = config2;
|
|
39122
38867
|
const projectPath = config2.projectPath || process.cwd();
|
|
38868
|
+
this.log = createWorkerLogger(config2.agentId, "R");
|
|
39123
38869
|
this.client = new LocusClient({
|
|
39124
38870
|
baseUrl: config2.apiBase,
|
|
39125
38871
|
token: config2.apiKey,
|
|
@@ -39130,28 +38876,16 @@ class ReviewerWorker {
|
|
|
39130
38876
|
factor: 2
|
|
39131
38877
|
}
|
|
39132
38878
|
});
|
|
39133
|
-
const log = this.log.bind(this);
|
|
39134
38879
|
const provider = config2.provider ?? PROVIDER.CLAUDE;
|
|
39135
38880
|
this.aiRunner = createAiRunner(provider, {
|
|
39136
38881
|
projectPath,
|
|
39137
38882
|
model: config2.model,
|
|
39138
|
-
log
|
|
38883
|
+
log: this.log
|
|
39139
38884
|
});
|
|
39140
|
-
this.prService = new PrService(projectPath, log);
|
|
38885
|
+
this.prService = new PrService(projectPath, this.log);
|
|
39141
38886
|
const providerLabel = provider === "codex" ? "Codex" : "Claude";
|
|
39142
38887
|
this.log(`Reviewer agent using ${providerLabel} CLI`, "info");
|
|
39143
38888
|
}
|
|
39144
|
-
log(message, level = "info") {
|
|
39145
|
-
const timestamp = new Date().toISOString().split("T")[1]?.slice(0, 8) ?? "";
|
|
39146
|
-
const colorFn = {
|
|
39147
|
-
info: c.cyan,
|
|
39148
|
-
success: c.green,
|
|
39149
|
-
warn: c.yellow,
|
|
39150
|
-
error: c.red
|
|
39151
|
-
}[level];
|
|
39152
|
-
const prefix = { info: "ℹ", success: "✓", warn: "⚠", error: "✗" }[level];
|
|
39153
|
-
console.log(`${c.dim(`[${timestamp}]`)} ${c.bold(`[R:${this.config.agentId.slice(-8)}]`)} ${colorFn(`${prefix} ${message}`)}`);
|
|
39154
|
-
}
|
|
39155
38889
|
getNextUnreviewedPr() {
|
|
39156
38890
|
const prs = this.prService.listUnreviewedLocusPrs();
|
|
39157
38891
|
return prs.length > 0 ? prs[0] : null;
|
|
@@ -39271,7 +39005,6 @@ var init_reviewer_worker = __esm(() => {
|
|
|
39271
39005
|
init_git_utils();
|
|
39272
39006
|
init_pr_service();
|
|
39273
39007
|
init_src2();
|
|
39274
|
-
init_colors();
|
|
39275
39008
|
reviewerEntrypoint = process.argv[1]?.split(/[\\/]/).pop();
|
|
39276
39009
|
if (reviewerEntrypoint === "reviewer-worker.js" || reviewerEntrypoint === "reviewer-worker.ts") {
|
|
39277
39010
|
process.title = "locus-reviewer";
|
|
@@ -39900,9 +39633,11 @@ class AgentWorker {
|
|
|
39900
39633
|
currentTaskId = null;
|
|
39901
39634
|
completedTaskList = [];
|
|
39902
39635
|
taskSummaries = [];
|
|
39636
|
+
log;
|
|
39903
39637
|
constructor(config2) {
|
|
39904
39638
|
this.config = config2;
|
|
39905
39639
|
const projectPath = config2.projectPath || process.cwd();
|
|
39640
|
+
this.log = createWorkerLogger(config2.agentId);
|
|
39906
39641
|
this.client = new LocusClient({
|
|
39907
39642
|
baseUrl: config2.apiBase,
|
|
39908
39643
|
token: config2.apiKey,
|
|
@@ -39913,7 +39648,6 @@ class AgentWorker {
|
|
|
39913
39648
|
factor: 2
|
|
39914
39649
|
}
|
|
39915
39650
|
});
|
|
39916
|
-
const log = this.log.bind(this);
|
|
39917
39651
|
if (!isGitAvailable()) {
|
|
39918
39652
|
this.log("git is not installed — branch management will not work", "error");
|
|
39919
39653
|
}
|
|
@@ -39924,29 +39658,18 @@ class AgentWorker {
|
|
|
39924
39658
|
this.aiRunner = createAiRunner(provider, {
|
|
39925
39659
|
projectPath,
|
|
39926
39660
|
model: config2.model,
|
|
39927
|
-
log,
|
|
39661
|
+
log: this.log,
|
|
39928
39662
|
reasoningEffort: config2.reasoningEffort
|
|
39929
39663
|
});
|
|
39930
39664
|
this.taskExecutor = new TaskExecutor({
|
|
39931
39665
|
aiRunner: this.aiRunner,
|
|
39932
39666
|
projectPath,
|
|
39933
|
-
log
|
|
39667
|
+
log: this.log
|
|
39934
39668
|
});
|
|
39935
|
-
this.gitWorkflow = new GitWorkflow(config2, log);
|
|
39669
|
+
this.gitWorkflow = new GitWorkflow(config2, this.log);
|
|
39936
39670
|
const providerLabel = provider === "codex" ? "Codex" : "Claude";
|
|
39937
39671
|
this.log(`Using ${providerLabel} CLI for all phases`, "info");
|
|
39938
39672
|
}
|
|
39939
|
-
log(message, level = "info") {
|
|
39940
|
-
const timestamp = new Date().toISOString().split("T")[1]?.slice(0, 8) ?? "";
|
|
39941
|
-
const colorFn = {
|
|
39942
|
-
info: c.cyan,
|
|
39943
|
-
success: c.green,
|
|
39944
|
-
warn: c.yellow,
|
|
39945
|
-
error: c.red
|
|
39946
|
-
}[level];
|
|
39947
|
-
const prefix = { info: "ℹ", success: "✓", warn: "⚠", error: "✗" }[level];
|
|
39948
|
-
console.log(`${c.dim(`[${timestamp}]`)} ${c.bold(`[${this.config.agentId.slice(-8)}]`)} ${colorFn(`${prefix} ${message}`)}`);
|
|
39949
|
-
}
|
|
39950
39673
|
async getActiveSprint() {
|
|
39951
39674
|
try {
|
|
39952
39675
|
if (this.config.sprintId) {
|
|
@@ -40123,7 +39846,6 @@ var init_worker = __esm(() => {
|
|
|
40123
39846
|
init_config();
|
|
40124
39847
|
init_git_utils();
|
|
40125
39848
|
init_src2();
|
|
40126
|
-
init_colors();
|
|
40127
39849
|
init_git_workflow();
|
|
40128
39850
|
init_task_executor();
|
|
40129
39851
|
workerEntrypoint = process.argv[1]?.split(/[\\/]/).pop();
|
|
@@ -40154,6 +39876,7 @@ var init_agent2 = __esm(() => {
|
|
|
40154
39876
|
// ../sdk/src/ai/index.ts
|
|
40155
39877
|
var init_ai = __esm(() => {
|
|
40156
39878
|
init_claude_runner();
|
|
39879
|
+
init_claude_stream_parser();
|
|
40157
39880
|
init_codex_runner();
|
|
40158
39881
|
init_factory();
|
|
40159
39882
|
});
|
|
@@ -40325,9 +40048,7 @@ class DiscussionFacilitator {
|
|
|
40325
40048
|
this.projectPath = config2.projectPath;
|
|
40326
40049
|
this.aiRunner = config2.aiRunner;
|
|
40327
40050
|
this.discussionManager = config2.discussionManager;
|
|
40328
|
-
this.log = config2.log ??
|
|
40329
|
-
return;
|
|
40330
|
-
});
|
|
40051
|
+
this.log = config2.log ?? noopLogger;
|
|
40331
40052
|
this.provider = config2.provider;
|
|
40332
40053
|
this.model = config2.model;
|
|
40333
40054
|
}
|
|
@@ -40498,6 +40219,7 @@ If you need more information about the project strategies, plans, or architectur
|
|
|
40498
40219
|
}
|
|
40499
40220
|
}
|
|
40500
40221
|
var init_discussion_facilitator = __esm(() => {
|
|
40222
|
+
init_factory();
|
|
40501
40223
|
init_config();
|
|
40502
40224
|
});
|
|
40503
40225
|
|
|
@@ -41985,9 +41707,7 @@ class PlanningMeeting {
|
|
|
41985
41707
|
constructor(config2) {
|
|
41986
41708
|
this.projectPath = config2.projectPath;
|
|
41987
41709
|
this.aiRunner = config2.aiRunner;
|
|
41988
|
-
this.log = config2.log ??
|
|
41989
|
-
return;
|
|
41990
|
-
});
|
|
41710
|
+
this.log = config2.log ?? noopLogger;
|
|
41991
41711
|
}
|
|
41992
41712
|
async run(directive, feedback) {
|
|
41993
41713
|
this.log("Planning sprint...", "info");
|
|
@@ -42027,6 +41747,7 @@ class PlanningMeeting {
|
|
|
42027
41747
|
}
|
|
42028
41748
|
}
|
|
42029
41749
|
var init_planning_meeting = __esm(() => {
|
|
41750
|
+
init_factory();
|
|
42030
41751
|
init_config();
|
|
42031
41752
|
});
|
|
42032
41753
|
|
|
@@ -42037,22 +41758,6 @@ var init_planning = __esm(() => {
|
|
|
42037
41758
|
init_sprint_plan();
|
|
42038
41759
|
});
|
|
42039
41760
|
|
|
42040
|
-
// ../sdk/src/proposals/context-gatherer.ts
|
|
42041
|
-
var init_context_gatherer = () => {};
|
|
42042
|
-
|
|
42043
|
-
// ../sdk/src/proposals/proposal-engine.ts
|
|
42044
|
-
var init_proposal_engine = __esm(() => {
|
|
42045
|
-
init_src();
|
|
42046
|
-
init_factory();
|
|
42047
|
-
init_context_gatherer();
|
|
42048
|
-
});
|
|
42049
|
-
|
|
42050
|
-
// ../sdk/src/proposals/index.ts
|
|
42051
|
-
var init_proposals = __esm(() => {
|
|
42052
|
-
init_context_gatherer();
|
|
42053
|
-
init_proposal_engine();
|
|
42054
|
-
});
|
|
42055
|
-
|
|
42056
41761
|
// ../sdk/src/index-node.ts
|
|
42057
41762
|
var init_index_node = __esm(() => {
|
|
42058
41763
|
init_prompt_builder();
|
|
@@ -42067,27 +41772,315 @@ var init_index_node = __esm(() => {
|
|
|
42067
41772
|
init_git();
|
|
42068
41773
|
init_src2();
|
|
42069
41774
|
init_planning();
|
|
42070
|
-
|
|
41775
|
+
});
|
|
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();
|
|
42071
42064
|
});
|
|
42072
42065
|
|
|
42073
42066
|
// src/utils/version.ts
|
|
42074
|
-
import { existsSync as
|
|
42075
|
-
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";
|
|
42076
42069
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
42077
42070
|
function getVersion() {
|
|
42078
42071
|
try {
|
|
42079
42072
|
const __filename2 = fileURLToPath3(import.meta.url);
|
|
42080
42073
|
const __dirname2 = dirname3(__filename2);
|
|
42081
|
-
const bundledPath =
|
|
42082
|
-
const sourcePath =
|
|
42083
|
-
if (
|
|
42084
|
-
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"));
|
|
42085
42078
|
if (pkg.name === "@locusai/cli") {
|
|
42086
42079
|
return pkg.version || "0.0.0";
|
|
42087
42080
|
}
|
|
42088
42081
|
}
|
|
42089
|
-
if (
|
|
42090
|
-
const pkg = JSON.parse(
|
|
42082
|
+
if (existsSync15(sourcePath)) {
|
|
42083
|
+
const pkg = JSON.parse(readFileSync13(sourcePath, "utf-8"));
|
|
42091
42084
|
if (pkg.name === "@locusai/cli") {
|
|
42092
42085
|
return pkg.version || "0.0.0";
|
|
42093
42086
|
}
|
|
@@ -42116,13 +42109,6 @@ var init_banner = __esm(() => {
|
|
|
42116
42109
|
});
|
|
42117
42110
|
|
|
42118
42111
|
// src/utils/helpers.ts
|
|
42119
|
-
import { existsSync as existsSync13 } from "node:fs";
|
|
42120
|
-
import { join as join13 } from "node:path";
|
|
42121
|
-
function isProjectInitialized(projectPath) {
|
|
42122
|
-
const locusDir = join13(projectPath, LOCUS_CONFIG.dir);
|
|
42123
|
-
const configPath = join13(locusDir, LOCUS_CONFIG.configFile);
|
|
42124
|
-
return existsSync13(locusDir) && existsSync13(configPath);
|
|
42125
|
-
}
|
|
42126
42112
|
function requireInitialization(projectPath, command) {
|
|
42127
42113
|
if (!isProjectInitialized(projectPath)) {
|
|
42128
42114
|
console.error(`
|
|
@@ -42138,15 +42124,16 @@ function requireInitialization(projectPath, command) {
|
|
|
42138
42124
|
process.exit(1);
|
|
42139
42125
|
}
|
|
42140
42126
|
}
|
|
42141
|
-
function
|
|
42142
|
-
|
|
42143
|
-
return
|
|
42144
|
-
|
|
42145
|
-
|
|
42146
|
-
|
|
42147
|
-
|
|
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
|
+
}
|
|
42148
42134
|
}
|
|
42149
42135
|
var init_helpers2 = __esm(() => {
|
|
42136
|
+
init_src3();
|
|
42150
42137
|
init_index_node();
|
|
42151
42138
|
});
|
|
42152
42139
|
|
|
@@ -42157,17 +42144,107 @@ var init_utils3 = __esm(() => {
|
|
|
42157
42144
|
init_version();
|
|
42158
42145
|
});
|
|
42159
42146
|
|
|
42160
|
-
// 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
|
|
42161
42238
|
import { execSync as execSync2 } from "node:child_process";
|
|
42162
|
-
import { existsSync as
|
|
42163
|
-
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";
|
|
42164
42241
|
function updateGitignore(projectPath) {
|
|
42165
|
-
const gitignorePath =
|
|
42242
|
+
const gitignorePath = join16(projectPath, ".gitignore");
|
|
42166
42243
|
let content = "";
|
|
42167
42244
|
const locusBlock = LOCUS_GITIGNORE_PATTERNS.join(`
|
|
42168
42245
|
`);
|
|
42169
|
-
if (
|
|
42170
|
-
content =
|
|
42246
|
+
if (existsSync16(gitignorePath)) {
|
|
42247
|
+
content = readFileSync14(gitignorePath, "utf-8");
|
|
42171
42248
|
if (content.includes(LOCUS_GITIGNORE_MARKER)) {
|
|
42172
42249
|
const lines = content.split(`
|
|
42173
42250
|
`);
|
|
@@ -42184,7 +42261,7 @@ function updateGitignore(projectPath) {
|
|
|
42184
42261
|
const after = lines.slice(endIdx + 1);
|
|
42185
42262
|
content = [...before, locusBlock, ...after].join(`
|
|
42186
42263
|
`);
|
|
42187
|
-
|
|
42264
|
+
writeFileSync7(gitignorePath, content);
|
|
42188
42265
|
return;
|
|
42189
42266
|
}
|
|
42190
42267
|
if (content.length > 0 && !content.endsWith(`
|
|
@@ -42199,7 +42276,7 @@ function updateGitignore(projectPath) {
|
|
|
42199
42276
|
}
|
|
42200
42277
|
content += `${locusBlock}
|
|
42201
42278
|
`;
|
|
42202
|
-
|
|
42279
|
+
writeFileSync7(gitignorePath, content);
|
|
42203
42280
|
}
|
|
42204
42281
|
function ensureGitIdentity(projectPath) {
|
|
42205
42282
|
const hasName = (() => {
|
|
@@ -42239,6 +42316,13 @@ function ensureGitIdentity(projectPath) {
|
|
|
42239
42316
|
stdio: "ignore"
|
|
42240
42317
|
});
|
|
42241
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";
|
|
42242
42326
|
|
|
42243
42327
|
class ConfigManager {
|
|
42244
42328
|
projectPath;
|
|
@@ -42246,9 +42330,9 @@ class ConfigManager {
|
|
|
42246
42330
|
this.projectPath = projectPath;
|
|
42247
42331
|
}
|
|
42248
42332
|
async init(version2) {
|
|
42249
|
-
const locusConfigDir =
|
|
42333
|
+
const locusConfigDir = join17(this.projectPath, LOCUS_CONFIG.dir);
|
|
42250
42334
|
const locusConfigPath = getLocusPath(this.projectPath, "configFile");
|
|
42251
|
-
if (!
|
|
42335
|
+
if (!existsSync17(locusConfigDir)) {
|
|
42252
42336
|
mkdirSync7(locusConfigDir, { recursive: true });
|
|
42253
42337
|
}
|
|
42254
42338
|
const locusSubdirs = [
|
|
@@ -42260,35 +42344,35 @@ class ConfigManager {
|
|
|
42260
42344
|
LOCUS_CONFIG.discussionsDir
|
|
42261
42345
|
];
|
|
42262
42346
|
for (const subdir of locusSubdirs) {
|
|
42263
|
-
const subdirPath =
|
|
42264
|
-
if (!
|
|
42347
|
+
const subdirPath = join17(locusConfigDir, subdir);
|
|
42348
|
+
if (!existsSync17(subdirPath)) {
|
|
42265
42349
|
mkdirSync7(subdirPath, { recursive: true });
|
|
42266
42350
|
}
|
|
42267
42351
|
}
|
|
42268
42352
|
const locusMdPath = getLocusPath(this.projectPath, "contextFile");
|
|
42269
|
-
if (!
|
|
42270
|
-
|
|
42353
|
+
if (!existsSync17(locusMdPath)) {
|
|
42354
|
+
writeFileSync8(locusMdPath, LOCUS_MD_TEMPLATE);
|
|
42271
42355
|
}
|
|
42272
42356
|
const learningsMdPath = getLocusPath(this.projectPath, "learningsFile");
|
|
42273
|
-
if (!
|
|
42274
|
-
|
|
42357
|
+
if (!existsSync17(learningsMdPath)) {
|
|
42358
|
+
writeFileSync8(learningsMdPath, DEFAULT_LEARNINGS_MD);
|
|
42275
42359
|
}
|
|
42276
|
-
if (!
|
|
42360
|
+
if (!existsSync17(locusConfigPath)) {
|
|
42277
42361
|
const config2 = {
|
|
42278
42362
|
$schema: LOCUS_SCHEMAS.config,
|
|
42279
42363
|
version: version2,
|
|
42280
42364
|
createdAt: new Date().toISOString(),
|
|
42281
42365
|
projectPath: "."
|
|
42282
42366
|
};
|
|
42283
|
-
|
|
42367
|
+
writeFileSync8(locusConfigPath, JSON.stringify(config2, null, 2));
|
|
42284
42368
|
}
|
|
42285
42369
|
updateGitignore(this.projectPath);
|
|
42286
42370
|
ensureGitIdentity(this.projectPath);
|
|
42287
42371
|
}
|
|
42288
42372
|
loadConfig() {
|
|
42289
42373
|
const path2 = getLocusPath(this.projectPath, "configFile");
|
|
42290
|
-
if (
|
|
42291
|
-
return JSON.parse(
|
|
42374
|
+
if (existsSync17(path2)) {
|
|
42375
|
+
return JSON.parse(readFileSync15(path2, "utf-8"));
|
|
42292
42376
|
}
|
|
42293
42377
|
return null;
|
|
42294
42378
|
}
|
|
@@ -42318,19 +42402,19 @@ class ConfigManager {
|
|
|
42318
42402
|
this.saveConfig(config2);
|
|
42319
42403
|
}
|
|
42320
42404
|
}
|
|
42321
|
-
const settingsPath =
|
|
42322
|
-
if (
|
|
42323
|
-
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");
|
|
42324
42408
|
const settings = JSON.parse(raw);
|
|
42325
42409
|
if (settings.$schema !== LOCUS_SCHEMAS.settings) {
|
|
42326
42410
|
const { $schema: _2, ...rest } = settings;
|
|
42327
42411
|
const ordered = { $schema: LOCUS_SCHEMAS.settings, ...rest };
|
|
42328
|
-
|
|
42412
|
+
writeFileSync8(settingsPath, JSON.stringify(ordered, null, 2), "utf-8");
|
|
42329
42413
|
}
|
|
42330
42414
|
}
|
|
42331
42415
|
const locusMdPath = getLocusPath(this.projectPath, "contextFile");
|
|
42332
|
-
const locusMdExisted =
|
|
42333
|
-
|
|
42416
|
+
const locusMdExisted = existsSync17(locusMdPath);
|
|
42417
|
+
writeFileSync8(locusMdPath, LOCUS_MD_TEMPLATE);
|
|
42334
42418
|
if (!locusMdExisted) {
|
|
42335
42419
|
result.directoriesCreated.push(".locus/LOCUS.md");
|
|
42336
42420
|
}
|
|
@@ -42342,23 +42426,23 @@ class ConfigManager {
|
|
|
42342
42426
|
LOCUS_CONFIG.plansDir,
|
|
42343
42427
|
LOCUS_CONFIG.discussionsDir
|
|
42344
42428
|
];
|
|
42345
|
-
const locusConfigDir =
|
|
42429
|
+
const locusConfigDir = join17(this.projectPath, LOCUS_CONFIG.dir);
|
|
42346
42430
|
for (const subdir of locusSubdirs) {
|
|
42347
|
-
const subdirPath =
|
|
42348
|
-
if (!
|
|
42431
|
+
const subdirPath = join17(locusConfigDir, subdir);
|
|
42432
|
+
if (!existsSync17(subdirPath)) {
|
|
42349
42433
|
mkdirSync7(subdirPath, { recursive: true });
|
|
42350
42434
|
result.directoriesCreated.push(`.locus/${subdir}`);
|
|
42351
42435
|
}
|
|
42352
42436
|
}
|
|
42353
42437
|
const learningsMdPath = getLocusPath(this.projectPath, "learningsFile");
|
|
42354
|
-
if (!
|
|
42355
|
-
|
|
42438
|
+
if (!existsSync17(learningsMdPath)) {
|
|
42439
|
+
writeFileSync8(learningsMdPath, DEFAULT_LEARNINGS_MD);
|
|
42356
42440
|
result.directoriesCreated.push(".locus/LEARNINGS.md");
|
|
42357
42441
|
}
|
|
42358
|
-
const gitignorePath =
|
|
42359
|
-
const gitignoreBefore =
|
|
42442
|
+
const gitignorePath = join17(this.projectPath, ".gitignore");
|
|
42443
|
+
const gitignoreBefore = existsSync17(gitignorePath) ? readFileSync15(gitignorePath, "utf-8") : "";
|
|
42360
42444
|
updateGitignore(this.projectPath);
|
|
42361
|
-
const gitignoreAfter =
|
|
42445
|
+
const gitignoreAfter = readFileSync15(gitignorePath, "utf-8");
|
|
42362
42446
|
if (gitignoreBefore !== gitignoreAfter) {
|
|
42363
42447
|
result.gitignoreUpdated = true;
|
|
42364
42448
|
}
|
|
@@ -42369,190 +42453,12 @@ class ConfigManager {
|
|
|
42369
42453
|
const { $schema: _2, ...rest } = config2;
|
|
42370
42454
|
const ordered = { $schema: LOCUS_SCHEMAS.config, ...rest };
|
|
42371
42455
|
const path2 = getLocusPath(this.projectPath, "configFile");
|
|
42372
|
-
|
|
42456
|
+
writeFileSync8(path2, JSON.stringify(ordered, null, 2));
|
|
42373
42457
|
}
|
|
42374
42458
|
}
|
|
42375
|
-
var LOCUS_GITIGNORE_MARKER = "# Locus AI", LOCUS_MD_TEMPLATE = `## Planning First
|
|
42376
|
-
|
|
42377
|
-
Complex tasks must be planned before writing code. Create ".locus/plans/<task-name>.md" with:
|
|
42378
|
-
- **Goal**: What we're trying to achieve and why
|
|
42379
|
-
- **Approach**: Step-by-step strategy with technical decisions
|
|
42380
|
-
- **Affected files**: List of files to create/modify/delete
|
|
42381
|
-
- **Acceptance criteria**: Specific, testable conditions for completion
|
|
42382
|
-
- **Dependencies**: Required packages, APIs, or external services
|
|
42383
|
-
|
|
42384
|
-
Delete the planning .md files after successful execution.
|
|
42385
|
-
|
|
42386
|
-
## Code Quality
|
|
42387
|
-
|
|
42388
|
-
- **Follow existing patterns**: Run formatters and linters before finishing (check "package.json" scripts or project config)
|
|
42389
|
-
- **Minimize changes**: Keep modifications atomic. Separate refactors from behavioral changes into different tasks
|
|
42390
|
-
- **Never commit secrets**: No API keys, passwords, or credentials in code. Use environment variables or secret management
|
|
42391
|
-
- **Test as you go**: If tests exist, run relevant ones. If breaking changes occur, update tests accordingly
|
|
42392
|
-
- **Comment complex logic**: Explain *why*, not *what*. Focus on business logic and non-obvious decisions
|
|
42393
|
-
|
|
42394
|
-
## Artifacts
|
|
42395
|
-
|
|
42396
|
-
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":
|
|
42397
|
-
|
|
42398
|
-
**Always create artifacts for:**
|
|
42399
|
-
- Code quality audits, security reviews, vulnerability assessments
|
|
42400
|
-
- Architecture analyses, system design proposals, or recommendations
|
|
42401
|
-
- Dependency reports, performance profiling, benchmarking results
|
|
42402
|
-
- Research summaries, technology comparisons, or feasibility studies
|
|
42403
|
-
- Migration plans, deployment strategies, or rollback procedures
|
|
42404
|
-
- Post-mortems, incident analysis, or debugging investigations
|
|
42405
|
-
|
|
42406
|
-
**Artifact structure:**
|
|
42407
|
-
- Clear title and date
|
|
42408
|
-
- Executive summary (2-3 sentences)
|
|
42409
|
-
- Detailed findings/analysis
|
|
42410
|
-
- Actionable recommendations (if applicable)
|
|
42411
|
-
|
|
42412
|
-
## Git Operations
|
|
42413
|
-
|
|
42414
|
-
- **Do NOT run**: git add, git commit, git push, git checkout, git branch, or any git commands
|
|
42415
|
-
- **Why**: The Locus orchestrator handles all version control automatically after execution
|
|
42416
|
-
- **Your role**: Focus solely on making file changes. The system commits, pushes, and creates PRs
|
|
42417
|
-
|
|
42418
|
-
## Continuous Learning
|
|
42419
|
-
|
|
42420
|
-
Read ".locus/LEARNINGS.md" **before starting any task** to avoid repeating mistakes.
|
|
42421
|
-
|
|
42422
|
-
**When to update:**
|
|
42423
|
-
- User corrects your approach or provides guidance
|
|
42424
|
-
- You discover a better pattern while working
|
|
42425
|
-
- A decision prevents future confusion (e.g., "use X not Y because Z")
|
|
42426
|
-
- You encounter and solve a tricky problem
|
|
42427
|
-
|
|
42428
|
-
**What to record:**
|
|
42429
|
-
- Architectural decisions and their rationale
|
|
42430
|
-
- Preferred libraries, tools, or patterns for this project
|
|
42431
|
-
- Common pitfalls and how to avoid them
|
|
42432
|
-
- Project-specific conventions or user preferences
|
|
42433
|
-
- Solutions to non-obvious problems
|
|
42434
|
-
|
|
42435
|
-
**Format (append-only, never delete):**
|
|
42436
|
-
|
|
42437
|
-
"""
|
|
42438
|
-
- **[Category]**: Concise description (1-2 lines max). *Context if needed.*
|
|
42439
|
-
"""
|
|
42440
|
-
|
|
42441
|
-
**Categories:** Architecture, Dependencies, Patterns, Debugging, Performance, Security, DevOps, User Preferences
|
|
42442
|
-
|
|
42443
|
-
## Error Handling
|
|
42444
|
-
|
|
42445
|
-
- **Read error messages carefully**: Don't guess. Parse the actual error before proposing fixes
|
|
42446
|
-
- **Check dependencies first**: Missing packages, wrong versions, and environment issues are common
|
|
42447
|
-
- **Verify assumptions**: If something "should work," confirm it actually does in this environment
|
|
42448
|
-
- **Ask for context**: If you need environment details, configuration, or logs, request them explicitly
|
|
42449
|
-
|
|
42450
|
-
## Communication
|
|
42451
|
-
|
|
42452
|
-
- **Be precise**: When uncertain, state what you know and what you're assuming
|
|
42453
|
-
- **Show your work**: For complex changes, briefly explain the approach before executing
|
|
42454
|
-
- **Highlight trade-offs**: If multiple approaches exist, note why you chose one over others
|
|
42455
|
-
- **Request feedback**: For ambiguous requirements, propose an approach and ask for confirmation
|
|
42456
|
-
`, DEFAULT_LEARNINGS_MD = `# Learnings
|
|
42457
|
-
|
|
42458
|
-
This file captures important lessons, decisions, and corrections made during development.
|
|
42459
|
-
It is read by AI agents before every task to avoid repeating mistakes and to follow established patterns.
|
|
42460
|
-
|
|
42461
|
-
<!-- Add learnings below this line. Format: - **[Category]**: Description -->
|
|
42462
|
-
`;
|
|
42463
42459
|
var init_config_manager = __esm(() => {
|
|
42464
42460
|
init_index_node();
|
|
42465
|
-
|
|
42466
|
-
|
|
42467
|
-
// src/settings-manager.ts
|
|
42468
|
-
import { existsSync as existsSync15, readFileSync as readFileSync13, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
42469
|
-
import { join as join15 } from "node:path";
|
|
42470
|
-
function getSettingsPath(projectPath) {
|
|
42471
|
-
return join15(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG.settingsFile);
|
|
42472
|
-
}
|
|
42473
|
-
|
|
42474
|
-
class SettingsManager {
|
|
42475
|
-
projectPath;
|
|
42476
|
-
constructor(projectPath) {
|
|
42477
|
-
this.projectPath = projectPath;
|
|
42478
|
-
}
|
|
42479
|
-
load() {
|
|
42480
|
-
const settingsPath = getSettingsPath(this.projectPath);
|
|
42481
|
-
if (!existsSync15(settingsPath)) {
|
|
42482
|
-
return {};
|
|
42483
|
-
}
|
|
42484
|
-
return JSON.parse(readFileSync13(settingsPath, "utf-8"));
|
|
42485
|
-
}
|
|
42486
|
-
save(settings) {
|
|
42487
|
-
const { $schema: _2, ...rest } = settings;
|
|
42488
|
-
const ordered = { $schema: LOCUS_SCHEMAS.settings, ...rest };
|
|
42489
|
-
const settingsPath = getSettingsPath(this.projectPath);
|
|
42490
|
-
writeFileSync7(settingsPath, JSON.stringify(ordered, null, 2), "utf-8");
|
|
42491
|
-
}
|
|
42492
|
-
get(key) {
|
|
42493
|
-
return this.load()[key];
|
|
42494
|
-
}
|
|
42495
|
-
set(key, value) {
|
|
42496
|
-
const settings = this.load();
|
|
42497
|
-
settings[key] = value;
|
|
42498
|
-
this.save(settings);
|
|
42499
|
-
}
|
|
42500
|
-
remove() {
|
|
42501
|
-
const settingsPath = getSettingsPath(this.projectPath);
|
|
42502
|
-
if (existsSync15(settingsPath)) {
|
|
42503
|
-
unlinkSync4(settingsPath);
|
|
42504
|
-
}
|
|
42505
|
-
}
|
|
42506
|
-
exists() {
|
|
42507
|
-
return existsSync15(getSettingsPath(this.projectPath));
|
|
42508
|
-
}
|
|
42509
|
-
getAutonomyRules() {
|
|
42510
|
-
const settings = this.load();
|
|
42511
|
-
const userRules = settings.autonomy?.rules ?? [];
|
|
42512
|
-
if (userRules.length === 0) {
|
|
42513
|
-
return DEFAULT_AUTONOMY_RULES;
|
|
42514
|
-
}
|
|
42515
|
-
const ruleMap = new Map(DEFAULT_AUTONOMY_RULES.map((r) => [r.category, r]));
|
|
42516
|
-
for (const rule of userRules) {
|
|
42517
|
-
ruleMap.set(rule.category, rule);
|
|
42518
|
-
}
|
|
42519
|
-
return Array.from(ruleMap.values());
|
|
42520
|
-
}
|
|
42521
|
-
}
|
|
42522
|
-
var init_settings_manager = __esm(() => {
|
|
42523
|
-
init_index_node();
|
|
42524
|
-
init_src();
|
|
42525
|
-
});
|
|
42526
|
-
|
|
42527
|
-
// src/workspace-resolver.ts
|
|
42528
|
-
class WorkspaceResolver {
|
|
42529
|
-
options;
|
|
42530
|
-
constructor(options) {
|
|
42531
|
-
this.options = options;
|
|
42532
|
-
}
|
|
42533
|
-
async resolve() {
|
|
42534
|
-
if (this.options.workspaceId) {
|
|
42535
|
-
return this.options.workspaceId;
|
|
42536
|
-
}
|
|
42537
|
-
try {
|
|
42538
|
-
console.log(c.dim("ℹ Resolving workspace from API key..."));
|
|
42539
|
-
const client = new LocusClient({
|
|
42540
|
-
baseUrl: this.options.apiBase,
|
|
42541
|
-
token: this.options.apiKey
|
|
42542
|
-
});
|
|
42543
|
-
const info = await client.auth.getApiKeyInfo();
|
|
42544
|
-
if (info.workspaceId) {
|
|
42545
|
-
console.log(c.success(`✓ Resolved workspace: ${info.workspaceId}`));
|
|
42546
|
-
return info.workspaceId;
|
|
42547
|
-
}
|
|
42548
|
-
throw new Error("API key is not associated with a workspace. Please specify --workspace.");
|
|
42549
|
-
} catch (error48) {
|
|
42550
|
-
throw new Error(`Error resolving workspace: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
42551
|
-
}
|
|
42552
|
-
}
|
|
42553
|
-
}
|
|
42554
|
-
var init_workspace_resolver = __esm(() => {
|
|
42555
|
-
init_index_node();
|
|
42461
|
+
init_git_helpers();
|
|
42556
42462
|
});
|
|
42557
42463
|
|
|
42558
42464
|
// src/commands/plan.ts
|
|
@@ -42560,8 +42466,8 @@ var exports_plan = {};
|
|
|
42560
42466
|
__export(exports_plan, {
|
|
42561
42467
|
planCommand: () => planCommand
|
|
42562
42468
|
});
|
|
42563
|
-
import { existsSync as
|
|
42564
|
-
import { join as
|
|
42469
|
+
import { existsSync as existsSync18, unlinkSync as unlinkSync5 } from "node:fs";
|
|
42470
|
+
import { join as join18 } from "node:path";
|
|
42565
42471
|
import { parseArgs } from "node:util";
|
|
42566
42472
|
function normalizePlanIdArgs(args) {
|
|
42567
42473
|
const planIdFlags = new Set(["--approve", "--reject", "--cancel", "--show"]);
|
|
@@ -42605,13 +42511,34 @@ async function planCommand(args) {
|
|
|
42605
42511
|
requireInitialization(projectPath, "plan");
|
|
42606
42512
|
const planManager = new PlanManager(projectPath);
|
|
42607
42513
|
if (values.list) {
|
|
42608
|
-
return
|
|
42514
|
+
return renderPlanList(planManager);
|
|
42609
42515
|
}
|
|
42610
42516
|
if (values.show) {
|
|
42611
|
-
|
|
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;
|
|
42612
42528
|
}
|
|
42613
42529
|
if (values.cancel) {
|
|
42614
|
-
|
|
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;
|
|
42615
42542
|
}
|
|
42616
42543
|
if (values.reject) {
|
|
42617
42544
|
const feedback2 = values.feedback;
|
|
@@ -42623,30 +42550,59 @@ async function planCommand(args) {
|
|
|
42623
42550
|
`);
|
|
42624
42551
|
process.exit(1);
|
|
42625
42552
|
}
|
|
42626
|
-
|
|
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;
|
|
42627
42570
|
}
|
|
42628
42571
|
if (values.approve) {
|
|
42629
|
-
const
|
|
42630
|
-
|
|
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
|
+
}
|
|
42631
42588
|
}
|
|
42632
42589
|
const directive = positionals.join(" ").trim();
|
|
42633
42590
|
if (!directive) {
|
|
42634
42591
|
showPlanHelp();
|
|
42635
42592
|
return;
|
|
42636
42593
|
}
|
|
42637
|
-
const
|
|
42638
|
-
|
|
42639
|
-
|
|
42594
|
+
const { provider, model } = resolveAiSettings({
|
|
42595
|
+
projectPath,
|
|
42596
|
+
provider: values.provider,
|
|
42597
|
+
model: values.model
|
|
42598
|
+
});
|
|
42640
42599
|
const reasoningEffort = values["reasoning-effort"];
|
|
42641
42600
|
const aiRunner = createAiRunner(provider, {
|
|
42642
42601
|
projectPath,
|
|
42643
42602
|
model,
|
|
42644
42603
|
reasoningEffort
|
|
42645
42604
|
});
|
|
42646
|
-
const log = (
|
|
42647
|
-
const icon = level === "success" ? c.success("✔") : level === "error" ? c.error("✖") : level === "warn" ? c.warning("!") : c.info("●");
|
|
42648
|
-
console.log(` ${icon} ${message}`);
|
|
42649
|
-
};
|
|
42605
|
+
const log = createCliLogger();
|
|
42650
42606
|
console.log(`
|
|
42651
42607
|
${c.header(" PLANNING MEETING ")} ${c.bold("Starting async planning meeting...")}
|
|
42652
42608
|
`);
|
|
@@ -42668,8 +42624,8 @@ async function planCommand(args) {
|
|
|
42668
42624
|
try {
|
|
42669
42625
|
const result = await meeting.run(directive, feedback);
|
|
42670
42626
|
planManager.save(result.plan);
|
|
42671
|
-
const tempFile =
|
|
42672
|
-
if (
|
|
42627
|
+
const tempFile = join18(getLocusPath(projectPath, "plansDir"), `${result.plan.id}.json`);
|
|
42628
|
+
if (existsSync18(tempFile)) {
|
|
42673
42629
|
unlinkSync5(tempFile);
|
|
42674
42630
|
}
|
|
42675
42631
|
console.log(`
|
|
@@ -42690,8 +42646,8 @@ async function planCommand(args) {
|
|
|
42690
42646
|
process.exit(1);
|
|
42691
42647
|
}
|
|
42692
42648
|
}
|
|
42693
|
-
function
|
|
42694
|
-
const plans = planManager
|
|
42649
|
+
function renderPlanList(planManager) {
|
|
42650
|
+
const plans = listPlans(planManager);
|
|
42695
42651
|
if (plans.length === 0) {
|
|
42696
42652
|
console.log(`
|
|
42697
42653
|
${c.dim("No plans found.")}
|
|
@@ -42705,7 +42661,7 @@ function listPlans(planManager) {
|
|
|
42705
42661
|
`);
|
|
42706
42662
|
for (const plan of plans) {
|
|
42707
42663
|
const statusIcon = plan.status === "pending" ? c.warning("◯") : plan.status === "approved" ? c.success("✔") : plan.status === "rejected" ? c.error("✖") : c.dim("⊘");
|
|
42708
|
-
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`)}`);
|
|
42709
42665
|
console.log(` ${c.dim("ID:")} ${plan.id}`);
|
|
42710
42666
|
console.log(` ${c.dim("Created:")} ${plan.createdAt}`);
|
|
42711
42667
|
if (plan.feedback) {
|
|
@@ -42714,50 +42670,7 @@ function listPlans(planManager) {
|
|
|
42714
42670
|
console.log("");
|
|
42715
42671
|
}
|
|
42716
42672
|
}
|
|
42717
|
-
function
|
|
42718
|
-
const md = planManager.getMarkdown(idOrSlug);
|
|
42719
|
-
if (!md) {
|
|
42720
|
-
console.error(`
|
|
42721
|
-
${c.error("✖")} ${c.red(`Plan not found: ${idOrSlug}`)}
|
|
42722
|
-
`);
|
|
42723
|
-
process.exit(1);
|
|
42724
|
-
}
|
|
42725
|
-
console.log(`
|
|
42726
|
-
${md}
|
|
42727
|
-
`);
|
|
42728
|
-
}
|
|
42729
|
-
function cancelPlan(planManager, idOrSlug) {
|
|
42730
|
-
try {
|
|
42731
|
-
planManager.cancel(idOrSlug);
|
|
42732
|
-
console.log(`
|
|
42733
|
-
${c.success("✔")} ${c.dim("Plan cancelled.")}
|
|
42734
|
-
`);
|
|
42735
|
-
} catch (error48) {
|
|
42736
|
-
console.error(`
|
|
42737
|
-
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
42738
|
-
`);
|
|
42739
|
-
process.exit(1);
|
|
42740
|
-
}
|
|
42741
|
-
}
|
|
42742
|
-
function rejectPlan(planManager, idOrSlug, feedback) {
|
|
42743
|
-
try {
|
|
42744
|
-
const plan = planManager.reject(idOrSlug, feedback);
|
|
42745
|
-
console.log(`
|
|
42746
|
-
${c.warning("!")} ${c.bold("Plan rejected:")} ${plan.name}
|
|
42747
|
-
`);
|
|
42748
|
-
console.log(` ${c.dim("Feedback saved:")} ${feedback}
|
|
42749
|
-
`);
|
|
42750
|
-
console.log(` ${c.dim("Re-run the planning meeting with the same directive to incorporate feedback:")}`);
|
|
42751
|
-
console.log(` ${c.cyan(`locus plan "${plan.directive}"`)}
|
|
42752
|
-
`);
|
|
42753
|
-
} catch (error48) {
|
|
42754
|
-
console.error(`
|
|
42755
|
-
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
42756
|
-
`);
|
|
42757
|
-
process.exit(1);
|
|
42758
|
-
}
|
|
42759
|
-
}
|
|
42760
|
-
async function approvePlan(planManager, idOrSlug, client, workspaceId) {
|
|
42673
|
+
async function renderApprovePlan(planManager, idOrSlug, client, workspaceId) {
|
|
42761
42674
|
try {
|
|
42762
42675
|
console.log(`
|
|
42763
42676
|
${c.info("●")} ${c.bold("Approving plan and creating sprint...")}
|
|
@@ -42780,34 +42693,6 @@ async function approvePlan(planManager, idOrSlug, client, workspaceId) {
|
|
|
42780
42693
|
process.exit(1);
|
|
42781
42694
|
}
|
|
42782
42695
|
}
|
|
42783
|
-
async function resolveApiContext(projectPath, values) {
|
|
42784
|
-
const configManager = new ConfigManager(projectPath);
|
|
42785
|
-
configManager.updateVersion(VERSION2);
|
|
42786
|
-
const settingsManager = new SettingsManager(projectPath);
|
|
42787
|
-
const settings = settingsManager.load();
|
|
42788
|
-
const apiKey = values["api-key"] || settings.apiKey;
|
|
42789
|
-
if (!apiKey) {
|
|
42790
|
-
console.error(`
|
|
42791
|
-
${c.error("✖")} ${c.red("API key is required for this operation")}
|
|
42792
|
-
`);
|
|
42793
|
-
console.error(` ${c.dim(`Configure with: locus config setup --api-key <key>
|
|
42794
|
-
Or pass --api-key flag`)}
|
|
42795
|
-
`);
|
|
42796
|
-
process.exit(1);
|
|
42797
|
-
}
|
|
42798
|
-
const apiBase = values["api-url"] || settings.apiUrl || "https://api.locusai.dev/api";
|
|
42799
|
-
const resolver = new WorkspaceResolver({
|
|
42800
|
-
apiKey,
|
|
42801
|
-
apiBase,
|
|
42802
|
-
workspaceId: values.workspace
|
|
42803
|
-
});
|
|
42804
|
-
const workspaceId = await resolver.resolve();
|
|
42805
|
-
const client = new LocusClient({
|
|
42806
|
-
baseUrl: apiBase,
|
|
42807
|
-
token: apiKey
|
|
42808
|
-
});
|
|
42809
|
-
return { client, workspaceId };
|
|
42810
|
-
}
|
|
42811
42696
|
function printPlanSummary(plan) {
|
|
42812
42697
|
console.log(` ${c.bold("Sprint:")} ${plan.name}`);
|
|
42813
42698
|
console.log(` ${c.bold("Goal:")} ${plan.goal}`);
|
|
@@ -42865,11 +42750,10 @@ function showPlanHelp() {
|
|
|
42865
42750
|
`);
|
|
42866
42751
|
}
|
|
42867
42752
|
var init_plan = __esm(() => {
|
|
42753
|
+
init_src3();
|
|
42868
42754
|
init_index_node();
|
|
42869
42755
|
init_config_manager();
|
|
42870
|
-
init_settings_manager();
|
|
42871
42756
|
init_utils3();
|
|
42872
|
-
init_workspace_resolver();
|
|
42873
42757
|
});
|
|
42874
42758
|
|
|
42875
42759
|
// src/display/tool-display.ts
|
|
@@ -43126,19 +43010,31 @@ class ProgressRenderer {
|
|
|
43126
43010
|
toolDisplay = new ToolDisplay;
|
|
43127
43011
|
toolDisplayShown = false;
|
|
43128
43012
|
thinkingShown = false;
|
|
43013
|
+
animated;
|
|
43129
43014
|
spinnerInterval = null;
|
|
43130
43015
|
spinnerFrameIndex = 0;
|
|
43131
43016
|
thinkingStartTime = null;
|
|
43132
43017
|
isInTextBlock = false;
|
|
43133
43018
|
textBuffer = "";
|
|
43019
|
+
constructor(options = {}) {
|
|
43020
|
+
this.animated = options.animated ?? false;
|
|
43021
|
+
}
|
|
43134
43022
|
showThinkingStarted() {
|
|
43135
43023
|
if (this.isThinking)
|
|
43136
43024
|
return;
|
|
43137
43025
|
this.isThinking = true;
|
|
43138
43026
|
this.thinkingStartTime = Date.now();
|
|
43139
|
-
if (
|
|
43140
|
-
this.thinkingShown
|
|
43141
|
-
|
|
43027
|
+
if (this.animated) {
|
|
43028
|
+
if (!this.thinkingShown) {
|
|
43029
|
+
this.thinkingShown = true;
|
|
43030
|
+
this.startThinkingAnimation();
|
|
43031
|
+
}
|
|
43032
|
+
} else {
|
|
43033
|
+
if (!this.thinkingShown) {
|
|
43034
|
+
console.log(c.dim(`\uD83E\uDD14 Thinking...
|
|
43035
|
+
`));
|
|
43036
|
+
this.thinkingShown = true;
|
|
43037
|
+
}
|
|
43142
43038
|
}
|
|
43143
43039
|
}
|
|
43144
43040
|
showThinkingStopped() {
|
|
@@ -43169,7 +43065,7 @@ class ProgressRenderer {
|
|
|
43169
43065
|
clearInterval(this.spinnerInterval);
|
|
43170
43066
|
this.spinnerInterval = null;
|
|
43171
43067
|
}
|
|
43172
|
-
if (this.thinkingShown && this.isThinking) {
|
|
43068
|
+
if (this.animated && this.thinkingShown && this.isThinking) {
|
|
43173
43069
|
process.stdout.write(`${ANSI.MOVE_TO_START}${ANSI.CLEAR_LINE}
|
|
43174
43070
|
`);
|
|
43175
43071
|
}
|
|
@@ -43451,9 +43347,9 @@ var init_progress_renderer = __esm(() => {
|
|
|
43451
43347
|
});
|
|
43452
43348
|
|
|
43453
43349
|
// src/repl/image-detect.ts
|
|
43454
|
-
import { copyFileSync, existsSync as
|
|
43455
|
-
import { homedir as
|
|
43456
|
-
import { basename as basename2, join as
|
|
43350
|
+
import { copyFileSync, existsSync as existsSync19, mkdirSync as mkdirSync8 } from "node:fs";
|
|
43351
|
+
import { homedir as homedir2, tmpdir as tmpdir2 } from "node:os";
|
|
43352
|
+
import { basename as basename2, join as join19 } from "node:path";
|
|
43457
43353
|
function hasImageExtension(p) {
|
|
43458
43354
|
const dot = p.lastIndexOf(".");
|
|
43459
43355
|
if (dot === -1)
|
|
@@ -43466,16 +43362,16 @@ function resolvePath(raw) {
|
|
|
43466
43362
|
p = p.slice(1, -1);
|
|
43467
43363
|
}
|
|
43468
43364
|
if (p.startsWith("~/")) {
|
|
43469
|
-
p =
|
|
43365
|
+
p = homedir2() + p.slice(1);
|
|
43470
43366
|
}
|
|
43471
43367
|
return p;
|
|
43472
43368
|
}
|
|
43473
43369
|
function copyToStable(srcPath) {
|
|
43474
43370
|
try {
|
|
43475
|
-
|
|
43371
|
+
mkdirSync8(STABLE_IMAGE_DIR, { recursive: true });
|
|
43476
43372
|
const ts = Date.now();
|
|
43477
43373
|
const name = `${ts}-${basename2(srcPath)}`;
|
|
43478
|
-
const destPath =
|
|
43374
|
+
const destPath = join19(STABLE_IMAGE_DIR, name);
|
|
43479
43375
|
copyFileSync(srcPath, destPath);
|
|
43480
43376
|
return destPath;
|
|
43481
43377
|
} catch {
|
|
@@ -43495,7 +43391,7 @@ function detectImages(input) {
|
|
|
43495
43391
|
let exists = false;
|
|
43496
43392
|
let stablePath = normalized;
|
|
43497
43393
|
try {
|
|
43498
|
-
exists =
|
|
43394
|
+
exists = existsSync19(normalized);
|
|
43499
43395
|
} catch {}
|
|
43500
43396
|
if (exists) {
|
|
43501
43397
|
const copied = copyToStable(normalized);
|
|
@@ -43569,7 +43465,7 @@ var init_image_detect = __esm(() => {
|
|
|
43569
43465
|
".tif",
|
|
43570
43466
|
".tiff"
|
|
43571
43467
|
]);
|
|
43572
|
-
STABLE_IMAGE_DIR =
|
|
43468
|
+
STABLE_IMAGE_DIR = join19(tmpdir2(), "locus-images");
|
|
43573
43469
|
});
|
|
43574
43470
|
|
|
43575
43471
|
// src/repl/input-handler.ts
|
|
@@ -44112,7 +44008,7 @@ class InteractiveSession {
|
|
|
44112
44008
|
model: options.model
|
|
44113
44009
|
});
|
|
44114
44010
|
this.promptBuilder = new PromptBuilder(options.projectPath);
|
|
44115
|
-
this.renderer = new ProgressRenderer;
|
|
44011
|
+
this.renderer = new ProgressRenderer({ animated: true });
|
|
44116
44012
|
this.historyManager = new HistoryManager(options.projectPath);
|
|
44117
44013
|
this.projectPath = options.projectPath;
|
|
44118
44014
|
this.model = options.model;
|
|
@@ -44326,66 +44222,10 @@ var init_interactive_session = __esm(() => {
|
|
|
44326
44222
|
init_index_node();
|
|
44327
44223
|
|
|
44328
44224
|
// src/commands/artifacts.ts
|
|
44225
|
+
init_src3();
|
|
44329
44226
|
init_index_node();
|
|
44330
44227
|
init_utils3();
|
|
44331
|
-
import { existsSync as existsSync17, readdirSync as readdirSync5, readFileSync as readFileSync14, statSync } from "node:fs";
|
|
44332
|
-
import { join as join17 } from "node:path";
|
|
44333
44228
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
44334
|
-
function listArtifacts(projectPath) {
|
|
44335
|
-
const artifactsDir = getLocusPath(projectPath, "artifactsDir");
|
|
44336
|
-
if (!existsSync17(artifactsDir)) {
|
|
44337
|
-
return [];
|
|
44338
|
-
}
|
|
44339
|
-
const files = readdirSync5(artifactsDir).filter((f) => f.endsWith(".md"));
|
|
44340
|
-
return files.map((fileName) => {
|
|
44341
|
-
const filePath = join17(artifactsDir, fileName);
|
|
44342
|
-
const stat = statSync(filePath);
|
|
44343
|
-
const name = fileName.replace(/\.md$/, "");
|
|
44344
|
-
return {
|
|
44345
|
-
name,
|
|
44346
|
-
fileName,
|
|
44347
|
-
createdAt: stat.birthtime,
|
|
44348
|
-
size: stat.size
|
|
44349
|
-
};
|
|
44350
|
-
}).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
44351
|
-
}
|
|
44352
|
-
function readArtifact(projectPath, name) {
|
|
44353
|
-
const artifactsDir = getLocusPath(projectPath, "artifactsDir");
|
|
44354
|
-
const fileName = name.endsWith(".md") ? name : `${name}.md`;
|
|
44355
|
-
const filePath = join17(artifactsDir, fileName);
|
|
44356
|
-
if (!existsSync17(filePath)) {
|
|
44357
|
-
return null;
|
|
44358
|
-
}
|
|
44359
|
-
const stat = statSync(filePath);
|
|
44360
|
-
const content = readFileSync14(filePath, "utf-8");
|
|
44361
|
-
return {
|
|
44362
|
-
content,
|
|
44363
|
-
info: {
|
|
44364
|
-
name: fileName.replace(/\.md$/, ""),
|
|
44365
|
-
fileName,
|
|
44366
|
-
createdAt: stat.birthtime,
|
|
44367
|
-
size: stat.size
|
|
44368
|
-
}
|
|
44369
|
-
};
|
|
44370
|
-
}
|
|
44371
|
-
function formatSize(bytes) {
|
|
44372
|
-
if (bytes < 1024)
|
|
44373
|
-
return `${bytes}B`;
|
|
44374
|
-
const kb = bytes / 1024;
|
|
44375
|
-
if (kb < 1024)
|
|
44376
|
-
return `${kb.toFixed(1)}KB`;
|
|
44377
|
-
const mb = kb / 1024;
|
|
44378
|
-
return `${mb.toFixed(1)}MB`;
|
|
44379
|
-
}
|
|
44380
|
-
function formatDate(date5) {
|
|
44381
|
-
return date5.toLocaleDateString("en-US", {
|
|
44382
|
-
year: "numeric",
|
|
44383
|
-
month: "short",
|
|
44384
|
-
day: "numeric",
|
|
44385
|
-
hour: "2-digit",
|
|
44386
|
-
minute: "2-digit"
|
|
44387
|
-
});
|
|
44388
|
-
}
|
|
44389
44229
|
async function artifactsCommand(args) {
|
|
44390
44230
|
const { positionals } = parseArgs2({
|
|
44391
44231
|
args,
|
|
@@ -44456,27 +44296,8 @@ async function listArtifactsCommand(projectPath) {
|
|
|
44456
44296
|
`);
|
|
44457
44297
|
}
|
|
44458
44298
|
async function showArtifact(projectPath, name) {
|
|
44459
|
-
const result =
|
|
44299
|
+
const result = findArtifact(projectPath, name);
|
|
44460
44300
|
if (!result) {
|
|
44461
|
-
const artifacts = listArtifacts(projectPath);
|
|
44462
|
-
const matches = artifacts.filter((a) => a.name.toLowerCase().includes(name.toLowerCase()));
|
|
44463
|
-
if (matches.length === 1) {
|
|
44464
|
-
const match = readArtifact(projectPath, matches[0].name);
|
|
44465
|
-
if (match) {
|
|
44466
|
-
printArtifact(match.info, match.content);
|
|
44467
|
-
return;
|
|
44468
|
-
}
|
|
44469
|
-
}
|
|
44470
|
-
if (matches.length > 1) {
|
|
44471
|
-
console.error(`
|
|
44472
|
-
${c.error("Error:")} Multiple artifacts match "${name}":
|
|
44473
|
-
`);
|
|
44474
|
-
for (const m of matches) {
|
|
44475
|
-
console.log(` ${c.cyan(m.name)}`);
|
|
44476
|
-
}
|
|
44477
|
-
console.log();
|
|
44478
|
-
return;
|
|
44479
|
-
}
|
|
44480
44301
|
console.error(`
|
|
44481
44302
|
${c.error("Error:")} Artifact "${name}" not found
|
|
44482
44303
|
`);
|
|
@@ -44484,6 +44305,16 @@ async function showArtifact(projectPath, name) {
|
|
|
44484
44305
|
`);
|
|
44485
44306
|
return;
|
|
44486
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
|
+
}
|
|
44487
44318
|
printArtifact(result.info, result.content);
|
|
44488
44319
|
}
|
|
44489
44320
|
function printArtifact(info, content) {
|
|
@@ -44497,17 +44328,16 @@ function printArtifact(info, content) {
|
|
|
44497
44328
|
console.log(content);
|
|
44498
44329
|
}
|
|
44499
44330
|
async function convertToPlan(projectPath, name) {
|
|
44500
|
-
const result =
|
|
44331
|
+
const result = findArtifact(projectPath, name);
|
|
44501
44332
|
if (!result) {
|
|
44502
|
-
|
|
44503
|
-
|
|
44504
|
-
|
|
44505
|
-
|
|
44506
|
-
|
|
44507
|
-
|
|
44508
|
-
|
|
44509
|
-
|
|
44510
|
-
}
|
|
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) {
|
|
44511
44341
|
console.error(`
|
|
44512
44342
|
${c.error("Error:")} Artifact "${name}" not found
|
|
44513
44343
|
`);
|
|
@@ -44526,8 +44356,8 @@ async function runPlanConversion(artifactName) {
|
|
|
44526
44356
|
await planCommand2([directive]);
|
|
44527
44357
|
}
|
|
44528
44358
|
// src/commands/config.ts
|
|
44359
|
+
init_src3();
|
|
44529
44360
|
init_index_node();
|
|
44530
|
-
init_settings_manager();
|
|
44531
44361
|
import { createInterface } from "node:readline";
|
|
44532
44362
|
function ask(question) {
|
|
44533
44363
|
const rl = createInterface({
|
|
@@ -44554,11 +44384,6 @@ var TELEGRAM_KEYS = [
|
|
|
44554
44384
|
"telegram.testMode"
|
|
44555
44385
|
];
|
|
44556
44386
|
var ALL_KEYS = [...TOP_LEVEL_KEYS, ...TELEGRAM_KEYS];
|
|
44557
|
-
function maskSecret(value) {
|
|
44558
|
-
if (value.length <= 8)
|
|
44559
|
-
return "****";
|
|
44560
|
-
return `${value.slice(0, 4)}...${value.slice(-4)}`;
|
|
44561
|
-
}
|
|
44562
44387
|
function showConfigHelp() {
|
|
44563
44388
|
console.log(`
|
|
44564
44389
|
${c.header(" CONFIG ")}
|
|
@@ -44783,539 +44608,12 @@ async function configCommand(args) {
|
|
|
44783
44608
|
showConfigHelp();
|
|
44784
44609
|
}
|
|
44785
44610
|
}
|
|
44786
|
-
// src/commands/daemon.ts
|
|
44787
|
-
init_index_node();
|
|
44788
|
-
init_settings_manager();
|
|
44789
|
-
init_utils3();
|
|
44790
|
-
import { existsSync as existsSync19, mkdirSync as mkdirSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync8 } from "node:fs";
|
|
44791
|
-
import { homedir as homedir3 } from "node:os";
|
|
44792
|
-
import { join as join19 } from "node:path";
|
|
44793
|
-
|
|
44794
|
-
// src/utils/process.ts
|
|
44795
|
-
import { spawn as spawn4 } from "node:child_process";
|
|
44796
|
-
import { existsSync as existsSync18, readdirSync as readdirSync6, readFileSync as readFileSync15 } from "node:fs";
|
|
44797
|
-
import { homedir as homedir2 } from "node:os";
|
|
44798
|
-
import { dirname as dirname4, join as join18 } from "node:path";
|
|
44799
|
-
function runShell(cmd, args) {
|
|
44800
|
-
return new Promise((resolve2) => {
|
|
44801
|
-
const proc = spawn4(cmd, args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
44802
|
-
let stdout = "";
|
|
44803
|
-
let stderr = "";
|
|
44804
|
-
proc.stdout?.on("data", (d) => {
|
|
44805
|
-
stdout += d.toString();
|
|
44806
|
-
});
|
|
44807
|
-
proc.stderr?.on("data", (d) => {
|
|
44808
|
-
stderr += d.toString();
|
|
44809
|
-
});
|
|
44810
|
-
proc.on("close", (exitCode) => resolve2({ exitCode, stdout, stderr }));
|
|
44811
|
-
proc.on("error", (err) => resolve2({ exitCode: 1, stdout, stderr: err.message }));
|
|
44812
|
-
});
|
|
44813
|
-
}
|
|
44814
|
-
async function findTelegramBinary() {
|
|
44815
|
-
const result = await runShell("which", ["locus-telegram"]);
|
|
44816
|
-
const p = result.stdout.trim();
|
|
44817
|
-
return p?.startsWith?.("/") ? p : null;
|
|
44818
|
-
}
|
|
44819
|
-
async function findBinDir(binary) {
|
|
44820
|
-
const result = await runShell("which", [binary]);
|
|
44821
|
-
const p = result.stdout.trim();
|
|
44822
|
-
if (p?.startsWith?.("/"))
|
|
44823
|
-
return dirname4(p);
|
|
44824
|
-
return null;
|
|
44825
|
-
}
|
|
44826
|
-
function resolveNvmBinDir() {
|
|
44827
|
-
const nvmDir = process.env.NVM_DIR || join18(homedir2(), ".nvm");
|
|
44828
|
-
const versionsDir = join18(nvmDir, "versions", "node");
|
|
44829
|
-
if (!existsSync18(versionsDir))
|
|
44830
|
-
return null;
|
|
44831
|
-
let versions2;
|
|
44832
|
-
try {
|
|
44833
|
-
versions2 = readdirSync6(versionsDir).filter((d) => d.startsWith("v"));
|
|
44834
|
-
} catch {
|
|
44835
|
-
return null;
|
|
44836
|
-
}
|
|
44837
|
-
if (versions2.length === 0)
|
|
44838
|
-
return null;
|
|
44839
|
-
const currentNodeVersion = `v${process.versions.node}`;
|
|
44840
|
-
const currentBin = join18(versionsDir, currentNodeVersion, "bin");
|
|
44841
|
-
if (versions2.includes(currentNodeVersion) && existsSync18(currentBin)) {
|
|
44842
|
-
return currentBin;
|
|
44843
|
-
}
|
|
44844
|
-
const aliasPath = join18(nvmDir, "alias", "default");
|
|
44845
|
-
if (existsSync18(aliasPath)) {
|
|
44846
|
-
try {
|
|
44847
|
-
const alias = readFileSync15(aliasPath, "utf-8").trim();
|
|
44848
|
-
const match = versions2.find((v) => v === `v${alias}` || v.startsWith(`v${alias}.`));
|
|
44849
|
-
if (match) {
|
|
44850
|
-
const bin2 = join18(versionsDir, match, "bin");
|
|
44851
|
-
if (existsSync18(bin2))
|
|
44852
|
-
return bin2;
|
|
44853
|
-
}
|
|
44854
|
-
} catch {}
|
|
44855
|
-
}
|
|
44856
|
-
const sorted = versions2.sort((a, b) => {
|
|
44857
|
-
const pa = a.slice(1).split(".").map(Number);
|
|
44858
|
-
const pb = b.slice(1).split(".").map(Number);
|
|
44859
|
-
for (let i = 0;i < 3; i++) {
|
|
44860
|
-
if ((pa[i] || 0) !== (pb[i] || 0))
|
|
44861
|
-
return (pb[i] || 0) - (pa[i] || 0);
|
|
44862
|
-
}
|
|
44863
|
-
return 0;
|
|
44864
|
-
});
|
|
44865
|
-
const bin = join18(versionsDir, sorted[0], "bin");
|
|
44866
|
-
return existsSync18(bin) ? bin : null;
|
|
44867
|
-
}
|
|
44868
|
-
async function buildServicePath() {
|
|
44869
|
-
const home = homedir2();
|
|
44870
|
-
const dirs = new Set;
|
|
44871
|
-
dirs.add("/usr/local/bin");
|
|
44872
|
-
dirs.add("/usr/bin");
|
|
44873
|
-
dirs.add("/bin");
|
|
44874
|
-
const candidates = [
|
|
44875
|
-
join18(home, ".bun", "bin"),
|
|
44876
|
-
join18(home, ".local", "bin"),
|
|
44877
|
-
join18(home, ".npm", "bin"),
|
|
44878
|
-
join18(home, ".npm-global", "bin"),
|
|
44879
|
-
join18(home, ".yarn", "bin")
|
|
44880
|
-
];
|
|
44881
|
-
for (const d of candidates) {
|
|
44882
|
-
if (existsSync18(d))
|
|
44883
|
-
dirs.add(d);
|
|
44884
|
-
}
|
|
44885
|
-
const nvmBin = resolveNvmBinDir();
|
|
44886
|
-
if (nvmBin)
|
|
44887
|
-
dirs.add(nvmBin);
|
|
44888
|
-
const fnmCurrent = join18(home, ".fnm", "current", "bin");
|
|
44889
|
-
if (existsSync18(fnmCurrent))
|
|
44890
|
-
dirs.add(fnmCurrent);
|
|
44891
|
-
for (const bin of ["claude", "codex"]) {
|
|
44892
|
-
const dir = await findBinDir(bin);
|
|
44893
|
-
if (dir)
|
|
44894
|
-
dirs.add(dir);
|
|
44895
|
-
}
|
|
44896
|
-
return Array.from(dirs).join(":");
|
|
44897
|
-
}
|
|
44898
|
-
var SERVICE_NAME = "locus";
|
|
44899
|
-
var SYSTEMD_UNIT_PATH = `/etc/systemd/system/${SERVICE_NAME}.service`;
|
|
44900
|
-
var PLIST_LABEL = "com.locus.agent";
|
|
44901
|
-
function getPlistPath() {
|
|
44902
|
-
return join18(homedir2(), "Library/LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
44903
|
-
}
|
|
44904
|
-
function getPlatform() {
|
|
44905
|
-
if (process.platform === "linux")
|
|
44906
|
-
return "linux";
|
|
44907
|
-
if (process.platform === "darwin")
|
|
44908
|
-
return "darwin";
|
|
44909
|
-
return null;
|
|
44910
|
-
}
|
|
44911
|
-
async function killOrphanedProcesses() {
|
|
44912
|
-
const result = await runShell("pgrep", ["-f", "locus-telegram"]);
|
|
44913
|
-
const pids = result.stdout.trim().split(`
|
|
44914
|
-
`).filter((p) => p.length > 0);
|
|
44915
|
-
if (pids.length === 0)
|
|
44916
|
-
return;
|
|
44917
|
-
console.log(` Killing ${pids.length} orphaned locus-telegram process${pids.length > 1 ? "es" : ""}...`);
|
|
44918
|
-
await runShell("pkill", ["-f", "locus-telegram"]);
|
|
44919
|
-
await new Promise((resolve2) => setTimeout(resolve2, 2000));
|
|
44920
|
-
const check2 = await runShell("pgrep", ["-f", "locus-telegram"]);
|
|
44921
|
-
if (check2.stdout.trim().length > 0) {
|
|
44922
|
-
await runShell("pkill", ["-9", "-f", "locus-telegram"]);
|
|
44923
|
-
}
|
|
44924
|
-
}
|
|
44925
|
-
async function isDaemonRunning() {
|
|
44926
|
-
const platform = getPlatform();
|
|
44927
|
-
if (platform === "linux") {
|
|
44928
|
-
const result = await runShell("systemctl", ["is-active", SERVICE_NAME]);
|
|
44929
|
-
return result.stdout.trim() === "active";
|
|
44930
|
-
}
|
|
44931
|
-
if (platform === "darwin") {
|
|
44932
|
-
const plistPath = getPlistPath();
|
|
44933
|
-
if (!existsSync18(plistPath))
|
|
44934
|
-
return false;
|
|
44935
|
-
const result = await runShell("launchctl", ["list"]);
|
|
44936
|
-
const match = result.stdout.split(`
|
|
44937
|
-
`).find((l) => l.includes(PLIST_LABEL));
|
|
44938
|
-
if (!match)
|
|
44939
|
-
return false;
|
|
44940
|
-
const pid = match.trim().split(/\s+/)[0];
|
|
44941
|
-
return pid !== "-";
|
|
44942
|
-
}
|
|
44943
|
-
return false;
|
|
44944
|
-
}
|
|
44945
|
-
async function restartDaemonIfRunning() {
|
|
44946
|
-
const platform = getPlatform();
|
|
44947
|
-
if (!platform)
|
|
44948
|
-
return false;
|
|
44949
|
-
const running = await isDaemonRunning();
|
|
44950
|
-
if (!running)
|
|
44951
|
-
return false;
|
|
44952
|
-
if (platform === "linux") {
|
|
44953
|
-
const result = await runShell("systemctl", ["restart", SERVICE_NAME]);
|
|
44954
|
-
return result.exitCode === 0;
|
|
44955
|
-
}
|
|
44956
|
-
if (platform === "darwin") {
|
|
44957
|
-
const plistPath = getPlistPath();
|
|
44958
|
-
await runShell("launchctl", ["unload", plistPath]);
|
|
44959
|
-
const result = await runShell("launchctl", ["load", plistPath]);
|
|
44960
|
-
return result.exitCode === 0;
|
|
44961
|
-
}
|
|
44962
|
-
return false;
|
|
44963
|
-
}
|
|
44964
|
-
|
|
44965
|
-
// src/commands/daemon.ts
|
|
44966
|
-
function showDaemonHelp() {
|
|
44967
|
-
console.log(`
|
|
44968
|
-
${c.header(" DAEMON ")}
|
|
44969
|
-
${c.primary("locus daemon")} ${c.dim("<subcommand>")}
|
|
44970
|
-
|
|
44971
|
-
${c.header(" SUBCOMMANDS ")}
|
|
44972
|
-
${c.success("start")} Install and start Locus as a background service
|
|
44973
|
-
${c.dim("Sets up systemd (Linux) or launchd (macOS)")}
|
|
44974
|
-
${c.success("stop")} Stop and remove the background service
|
|
44975
|
-
${c.success("restart")} Restart the background service
|
|
44976
|
-
${c.success("status")} Check if the service is running
|
|
44977
|
-
|
|
44978
|
-
${c.header(" EXAMPLES ")}
|
|
44979
|
-
${c.dim("$")} ${c.primary("locus daemon start")}
|
|
44980
|
-
${c.dim("$")} ${c.primary("locus daemon status")}
|
|
44981
|
-
${c.dim("$")} ${c.primary("locus daemon restart")}
|
|
44982
|
-
${c.dim("$")} ${c.primary("locus daemon stop")}
|
|
44983
|
-
`);
|
|
44984
|
-
}
|
|
44985
|
-
async function resolveBinaries() {
|
|
44986
|
-
const binaryPath = await findTelegramBinary();
|
|
44987
|
-
if (!binaryPath) {
|
|
44988
|
-
console.error(`
|
|
44989
|
-
${c.error("✖")} ${c.bold("Could not find locus-telegram binary.")}
|
|
44990
|
-
` + ` Install with: ${c.primary("npm install -g @locusai/telegram")}
|
|
44991
|
-
`);
|
|
44992
|
-
process.exit(1);
|
|
44993
|
-
}
|
|
44994
|
-
for (const bin of ["claude", "codex"]) {
|
|
44995
|
-
if (!await findBinDir(bin)) {
|
|
44996
|
-
console.warn(`
|
|
44997
|
-
${c.secondary("⚠")} ${c.bold(`Could not find '${bin}' CLI in PATH.`)}
|
|
44998
|
-
` + ` The service may need it to execute tasks.
|
|
44999
|
-
`);
|
|
45000
|
-
}
|
|
45001
|
-
}
|
|
45002
|
-
const servicePath = await buildServicePath();
|
|
45003
|
-
return { binaryPath, servicePath };
|
|
45004
|
-
}
|
|
45005
|
-
function requirePlatform() {
|
|
45006
|
-
const platform = getPlatform();
|
|
45007
|
-
if (!platform) {
|
|
45008
|
-
console.error(`
|
|
45009
|
-
${c.error("✖")} ${c.bold(`Unsupported platform: ${process.platform}`)}
|
|
45010
|
-
` + ` Daemon management is supported on Linux (systemd) and macOS (launchd).
|
|
45011
|
-
`);
|
|
45012
|
-
process.exit(1);
|
|
45013
|
-
}
|
|
45014
|
-
return platform;
|
|
45015
|
-
}
|
|
45016
|
-
function validateConfig(projectPath) {
|
|
45017
|
-
const manager = new SettingsManager(projectPath);
|
|
45018
|
-
const settings = manager.load();
|
|
45019
|
-
if (!settings.telegram?.botToken || !settings.telegram?.chatId) {
|
|
45020
|
-
console.error(`
|
|
45021
|
-
${c.error("✖")} ${c.bold("Telegram is not configured.")}
|
|
45022
|
-
` + ` Run ${c.primary("locus telegram setup")} first.
|
|
45023
|
-
`);
|
|
45024
|
-
process.exit(1);
|
|
45025
|
-
}
|
|
45026
|
-
if (!settings.apiKey) {
|
|
45027
|
-
console.error(`
|
|
45028
|
-
${c.error("✖")} ${c.bold("API key is not configured.")}
|
|
45029
|
-
` + ` Run ${c.primary("locus config setup --api-key <key>")} first.
|
|
45030
|
-
`);
|
|
45031
|
-
process.exit(1);
|
|
45032
|
-
}
|
|
45033
|
-
}
|
|
45034
|
-
function generateSystemdUnit(projectPath, user2, bins) {
|
|
45035
|
-
return `[Unit]
|
|
45036
|
-
Description=Locus AI Agent (Telegram bot + proposal scheduler)
|
|
45037
|
-
After=network-online.target
|
|
45038
|
-
Wants=network-online.target
|
|
45039
|
-
|
|
45040
|
-
[Service]
|
|
45041
|
-
Type=simple
|
|
45042
|
-
User=${user2}
|
|
45043
|
-
WorkingDirectory=${projectPath}
|
|
45044
|
-
ExecStart=${bins.binaryPath}
|
|
45045
|
-
Restart=on-failure
|
|
45046
|
-
RestartSec=10
|
|
45047
|
-
Environment=PATH=${bins.servicePath}
|
|
45048
|
-
Environment=HOME=${homedir3()}
|
|
45049
|
-
|
|
45050
|
-
[Install]
|
|
45051
|
-
WantedBy=multi-user.target
|
|
45052
|
-
`;
|
|
45053
|
-
}
|
|
45054
|
-
async function startSystemd(projectPath, bins) {
|
|
45055
|
-
const user2 = process.env.USER || "root";
|
|
45056
|
-
const unit = generateSystemdUnit(projectPath, user2, bins);
|
|
45057
|
-
console.log(`
|
|
45058
|
-
${c.info("▶")} Writing systemd unit to ${c.dim(SYSTEMD_UNIT_PATH)}`);
|
|
45059
|
-
writeFileSync8(SYSTEMD_UNIT_PATH, unit, "utf-8");
|
|
45060
|
-
console.log(` ${c.info("▶")} Reloading systemd daemon...`);
|
|
45061
|
-
await runShell("systemctl", ["daemon-reload"]);
|
|
45062
|
-
console.log(` ${c.info("▶")} Enabling and starting ${SERVICE_NAME}...`);
|
|
45063
|
-
await runShell("systemctl", ["enable", SERVICE_NAME]);
|
|
45064
|
-
const result = await runShell("systemctl", ["start", SERVICE_NAME]);
|
|
45065
|
-
if (result.exitCode !== 0) {
|
|
45066
|
-
console.error(`
|
|
45067
|
-
${c.error("✖")} Failed to start service: ${result.stderr.trim()}`);
|
|
45068
|
-
console.error(` ${c.dim("Check logs with:")} ${c.primary(`journalctl -u ${SERVICE_NAME} -f`)}`);
|
|
45069
|
-
return;
|
|
45070
|
-
}
|
|
45071
|
-
console.log(`
|
|
45072
|
-
${c.success("✔")} ${c.bold("Locus daemon started!")}
|
|
45073
|
-
|
|
45074
|
-
${c.bold("Service:")} ${SERVICE_NAME}
|
|
45075
|
-
${c.bold("Unit file:")} ${SYSTEMD_UNIT_PATH}
|
|
45076
|
-
|
|
45077
|
-
${c.bold("Useful commands:")}
|
|
45078
|
-
${c.dim("$")} ${c.primary(`sudo systemctl status ${SERVICE_NAME}`)}
|
|
45079
|
-
${c.dim("$")} ${c.primary(`journalctl -u ${SERVICE_NAME} -f`)}
|
|
45080
|
-
`);
|
|
45081
|
-
}
|
|
45082
|
-
async function stopSystemd() {
|
|
45083
|
-
if (!existsSync19(SYSTEMD_UNIT_PATH)) {
|
|
45084
|
-
console.log(`
|
|
45085
|
-
${c.dim("No systemd service found. Nothing to stop.")}
|
|
45086
|
-
`);
|
|
45087
|
-
await killOrphanedProcesses();
|
|
45088
|
-
return;
|
|
45089
|
-
}
|
|
45090
|
-
console.log(` ${c.info("▶")} Stopping and disabling ${SERVICE_NAME}...`);
|
|
45091
|
-
await runShell("systemctl", ["stop", SERVICE_NAME]);
|
|
45092
|
-
await runShell("systemctl", ["disable", SERVICE_NAME]);
|
|
45093
|
-
unlinkSync6(SYSTEMD_UNIT_PATH);
|
|
45094
|
-
await runShell("systemctl", ["daemon-reload"]);
|
|
45095
|
-
await killOrphanedProcesses();
|
|
45096
|
-
console.log(`
|
|
45097
|
-
${c.success("✔")} ${c.bold("Locus daemon stopped.")}
|
|
45098
|
-
`);
|
|
45099
|
-
}
|
|
45100
|
-
async function restartSystemd() {
|
|
45101
|
-
if (!existsSync19(SYSTEMD_UNIT_PATH)) {
|
|
45102
|
-
console.log(`
|
|
45103
|
-
${c.dim("No systemd service found. Use")} ${c.primary("locus daemon start")} ${c.dim("first.")}
|
|
45104
|
-
`);
|
|
45105
|
-
return;
|
|
45106
|
-
}
|
|
45107
|
-
console.log(` ${c.info("▶")} Restarting ${SERVICE_NAME}...`);
|
|
45108
|
-
const result = await runShell("systemctl", ["restart", SERVICE_NAME]);
|
|
45109
|
-
if (result.exitCode !== 0) {
|
|
45110
|
-
console.error(`
|
|
45111
|
-
${c.error("✖")} Failed to restart: ${result.stderr.trim()}
|
|
45112
|
-
`);
|
|
45113
|
-
return;
|
|
45114
|
-
}
|
|
45115
|
-
console.log(`
|
|
45116
|
-
${c.success("✔")} ${c.bold("Locus daemon restarted.")}
|
|
45117
|
-
`);
|
|
45118
|
-
}
|
|
45119
|
-
async function statusSystemd() {
|
|
45120
|
-
const result = await runShell("systemctl", ["is-active", SERVICE_NAME]);
|
|
45121
|
-
const state = result.stdout.trim();
|
|
45122
|
-
if (state === "active") {
|
|
45123
|
-
console.log(`
|
|
45124
|
-
${c.success("●")} ${c.bold("Locus daemon is running")} ${c.dim("(systemd)")}
|
|
45125
|
-
`);
|
|
45126
|
-
} else if (existsSync19(SYSTEMD_UNIT_PATH)) {
|
|
45127
|
-
console.log(`
|
|
45128
|
-
${c.secondary("●")} ${c.bold(`Locus daemon is ${state}`)} ${c.dim("(systemd)")}
|
|
45129
|
-
`);
|
|
45130
|
-
console.log(` ${c.dim("Start with:")} ${c.primary("locus daemon start")}
|
|
45131
|
-
`);
|
|
45132
|
-
} else {
|
|
45133
|
-
console.log(`
|
|
45134
|
-
${c.secondary("●")} ${c.bold("Locus daemon is not installed")}
|
|
45135
|
-
`);
|
|
45136
|
-
console.log(` ${c.dim("Start with:")} ${c.primary("locus daemon start")}
|
|
45137
|
-
`);
|
|
45138
|
-
}
|
|
45139
|
-
}
|
|
45140
|
-
function generatePlist(projectPath, bins) {
|
|
45141
|
-
const logDir = join19(homedir3(), "Library/Logs/Locus");
|
|
45142
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
45143
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
45144
|
-
<plist version="1.0">
|
|
45145
|
-
<dict>
|
|
45146
|
-
<key>Label</key>
|
|
45147
|
-
<string>${PLIST_LABEL}</string>
|
|
45148
|
-
<key>ProgramArguments</key>
|
|
45149
|
-
<array>
|
|
45150
|
-
<string>${bins.binaryPath}</string>
|
|
45151
|
-
</array>
|
|
45152
|
-
<key>WorkingDirectory</key>
|
|
45153
|
-
<string>${projectPath}</string>
|
|
45154
|
-
<key>RunAtLoad</key>
|
|
45155
|
-
<true/>
|
|
45156
|
-
<key>KeepAlive</key>
|
|
45157
|
-
<true/>
|
|
45158
|
-
<key>StandardOutPath</key>
|
|
45159
|
-
<string>${join19(logDir, "locus.log")}</string>
|
|
45160
|
-
<key>StandardErrorPath</key>
|
|
45161
|
-
<string>${join19(logDir, "locus-error.log")}</string>
|
|
45162
|
-
<key>EnvironmentVariables</key>
|
|
45163
|
-
<dict>
|
|
45164
|
-
<key>PATH</key>
|
|
45165
|
-
<string>${bins.servicePath}</string>
|
|
45166
|
-
</dict>
|
|
45167
|
-
</dict>
|
|
45168
|
-
</plist>
|
|
45169
|
-
`;
|
|
45170
|
-
}
|
|
45171
|
-
async function startLaunchd(projectPath, bins) {
|
|
45172
|
-
const plistPath = getPlistPath();
|
|
45173
|
-
if (existsSync19(plistPath)) {
|
|
45174
|
-
await runShell("launchctl", ["unload", plistPath]);
|
|
45175
|
-
}
|
|
45176
|
-
const logDir = join19(homedir3(), "Library/Logs/Locus");
|
|
45177
|
-
mkdirSync8(logDir, { recursive: true });
|
|
45178
|
-
mkdirSync8(join19(homedir3(), "Library/LaunchAgents"), { recursive: true });
|
|
45179
|
-
const plist = generatePlist(projectPath, bins);
|
|
45180
|
-
console.log(`
|
|
45181
|
-
${c.info("▶")} Writing plist to ${c.dim(plistPath)}`);
|
|
45182
|
-
writeFileSync8(plistPath, plist, "utf-8");
|
|
45183
|
-
console.log(` ${c.info("▶")} Loading service...`);
|
|
45184
|
-
const result = await runShell("launchctl", ["load", plistPath]);
|
|
45185
|
-
if (result.exitCode !== 0) {
|
|
45186
|
-
console.error(`
|
|
45187
|
-
${c.error("✖")} Failed to load service: ${result.stderr.trim()}`);
|
|
45188
|
-
return;
|
|
45189
|
-
}
|
|
45190
|
-
const logPath = join19(logDir, "locus.log");
|
|
45191
|
-
console.log(`
|
|
45192
|
-
${c.success("✔")} ${c.bold("Locus daemon started!")}
|
|
45193
|
-
|
|
45194
|
-
${c.bold("Plist:")} ${plistPath}
|
|
45195
|
-
${c.bold("Logs:")} ${logPath}
|
|
45196
|
-
|
|
45197
|
-
${c.bold("Useful commands:")}
|
|
45198
|
-
${c.dim("$")} ${c.primary(`launchctl list | grep ${PLIST_LABEL}`)}
|
|
45199
|
-
${c.dim("$")} ${c.primary(`tail -f ${logPath}`)}
|
|
45200
|
-
`);
|
|
45201
|
-
}
|
|
45202
|
-
async function stopLaunchd() {
|
|
45203
|
-
const plistPath = getPlistPath();
|
|
45204
|
-
if (!existsSync19(plistPath)) {
|
|
45205
|
-
console.log(`
|
|
45206
|
-
${c.dim("No launchd service found. Nothing to stop.")}
|
|
45207
|
-
`);
|
|
45208
|
-
await killOrphanedProcesses();
|
|
45209
|
-
return;
|
|
45210
|
-
}
|
|
45211
|
-
console.log(` ${c.info("▶")} Unloading service...`);
|
|
45212
|
-
await runShell("launchctl", ["unload", plistPath]);
|
|
45213
|
-
unlinkSync6(plistPath);
|
|
45214
|
-
await killOrphanedProcesses();
|
|
45215
|
-
console.log(`
|
|
45216
|
-
${c.success("✔")} ${c.bold("Locus daemon stopped.")}
|
|
45217
|
-
`);
|
|
45218
|
-
}
|
|
45219
|
-
async function restartLaunchd() {
|
|
45220
|
-
const plistPath = getPlistPath();
|
|
45221
|
-
if (!existsSync19(plistPath)) {
|
|
45222
|
-
console.log(`
|
|
45223
|
-
${c.dim("No launchd service found. Use")} ${c.primary("locus daemon start")} ${c.dim("first.")}
|
|
45224
|
-
`);
|
|
45225
|
-
return;
|
|
45226
|
-
}
|
|
45227
|
-
console.log(` ${c.info("▶")} Restarting service...`);
|
|
45228
|
-
await runShell("launchctl", ["unload", plistPath]);
|
|
45229
|
-
const result = await runShell("launchctl", ["load", plistPath]);
|
|
45230
|
-
if (result.exitCode !== 0) {
|
|
45231
|
-
console.error(`
|
|
45232
|
-
${c.error("✖")} Failed to restart: ${result.stderr.trim()}
|
|
45233
|
-
`);
|
|
45234
|
-
return;
|
|
45235
|
-
}
|
|
45236
|
-
console.log(`
|
|
45237
|
-
${c.success("✔")} ${c.bold("Locus daemon restarted.")}
|
|
45238
|
-
`);
|
|
45239
|
-
}
|
|
45240
|
-
async function statusLaunchd() {
|
|
45241
|
-
const plistPath = getPlistPath();
|
|
45242
|
-
if (!existsSync19(plistPath)) {
|
|
45243
|
-
console.log(`
|
|
45244
|
-
${c.secondary("●")} ${c.bold("Locus daemon is not installed")}
|
|
45245
|
-
`);
|
|
45246
|
-
console.log(` ${c.dim("Start with:")} ${c.primary("locus daemon start")}
|
|
45247
|
-
`);
|
|
45248
|
-
return;
|
|
45249
|
-
}
|
|
45250
|
-
const result = await runShell("launchctl", ["list"]);
|
|
45251
|
-
const match = result.stdout.split(`
|
|
45252
|
-
`).find((l) => l.includes(PLIST_LABEL));
|
|
45253
|
-
if (match) {
|
|
45254
|
-
const parts = match.trim().split(/\s+/);
|
|
45255
|
-
const pid = parts[0] === "-" ? null : parts[0];
|
|
45256
|
-
if (pid) {
|
|
45257
|
-
console.log(`
|
|
45258
|
-
${c.success("●")} ${c.bold("Locus daemon is running")} ${c.dim(`(PID ${pid}, launchd)`)}
|
|
45259
|
-
`);
|
|
45260
|
-
} else {
|
|
45261
|
-
console.log(`
|
|
45262
|
-
${c.secondary("●")} ${c.bold("Locus daemon is stopped")} ${c.dim("(launchd)")}
|
|
45263
|
-
`);
|
|
45264
|
-
console.log(` ${c.dim("Start with:")} ${c.primary("locus daemon start")}
|
|
45265
|
-
`);
|
|
45266
|
-
}
|
|
45267
|
-
} else {
|
|
45268
|
-
console.log(`
|
|
45269
|
-
${c.secondary("●")} ${c.bold("Locus daemon is not loaded")} ${c.dim("(plist exists but not loaded)")}
|
|
45270
|
-
`);
|
|
45271
|
-
console.log(` ${c.dim("Start with:")} ${c.primary("locus daemon start")}
|
|
45272
|
-
`);
|
|
45273
|
-
}
|
|
45274
|
-
}
|
|
45275
|
-
async function daemonCommand(args) {
|
|
45276
|
-
const projectPath = process.cwd();
|
|
45277
|
-
requireInitialization(projectPath, "daemon");
|
|
45278
|
-
const subcommand = args[0];
|
|
45279
|
-
const platform = subcommand ? requirePlatform() : null;
|
|
45280
|
-
const isLinux = platform === "linux";
|
|
45281
|
-
switch (subcommand) {
|
|
45282
|
-
case "start": {
|
|
45283
|
-
validateConfig(projectPath);
|
|
45284
|
-
const bins = await resolveBinaries();
|
|
45285
|
-
if (isLinux)
|
|
45286
|
-
await startSystemd(projectPath, bins);
|
|
45287
|
-
else
|
|
45288
|
-
await startLaunchd(projectPath, bins);
|
|
45289
|
-
break;
|
|
45290
|
-
}
|
|
45291
|
-
case "stop":
|
|
45292
|
-
if (isLinux)
|
|
45293
|
-
await stopSystemd();
|
|
45294
|
-
else
|
|
45295
|
-
await stopLaunchd();
|
|
45296
|
-
break;
|
|
45297
|
-
case "restart":
|
|
45298
|
-
if (isLinux)
|
|
45299
|
-
await restartSystemd();
|
|
45300
|
-
else
|
|
45301
|
-
await restartLaunchd();
|
|
45302
|
-
break;
|
|
45303
|
-
case "status":
|
|
45304
|
-
if (isLinux)
|
|
45305
|
-
await statusSystemd();
|
|
45306
|
-
else
|
|
45307
|
-
await statusLaunchd();
|
|
45308
|
-
break;
|
|
45309
|
-
default:
|
|
45310
|
-
showDaemonHelp();
|
|
45311
|
-
}
|
|
45312
|
-
}
|
|
45313
44611
|
// src/commands/discuss.ts
|
|
44612
|
+
init_src3();
|
|
45314
44613
|
init_index_node();
|
|
45315
44614
|
init_progress_renderer();
|
|
45316
44615
|
init_image_detect();
|
|
45317
44616
|
init_input_handler();
|
|
45318
|
-
init_settings_manager();
|
|
45319
44617
|
init_utils3();
|
|
45320
44618
|
import { parseArgs as parseArgs3 } from "node:util";
|
|
45321
44619
|
async function discussCommand(args) {
|
|
@@ -45338,35 +44636,66 @@ async function discussCommand(args) {
|
|
|
45338
44636
|
requireInitialization(projectPath, "discuss");
|
|
45339
44637
|
const discussionManager = new DiscussionManager(projectPath);
|
|
45340
44638
|
if (values.list) {
|
|
45341
|
-
return
|
|
44639
|
+
return renderDiscussionList(discussionManager);
|
|
45342
44640
|
}
|
|
45343
44641
|
if (values.show) {
|
|
45344
|
-
|
|
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;
|
|
45345
44653
|
}
|
|
45346
44654
|
if (values.archive) {
|
|
45347
|
-
|
|
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;
|
|
45348
44667
|
}
|
|
45349
44668
|
if (values.delete) {
|
|
45350
|
-
|
|
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;
|
|
45351
44681
|
}
|
|
45352
44682
|
const topic = positionals.join(" ").trim();
|
|
45353
44683
|
if (!topic) {
|
|
45354
44684
|
showDiscussHelp();
|
|
45355
44685
|
return;
|
|
45356
44686
|
}
|
|
45357
|
-
const
|
|
45358
|
-
|
|
45359
|
-
|
|
44687
|
+
const { provider, model } = resolveAiSettings({
|
|
44688
|
+
projectPath,
|
|
44689
|
+
provider: values.provider,
|
|
44690
|
+
model: values.model
|
|
44691
|
+
});
|
|
45360
44692
|
const reasoningEffort = values["reasoning-effort"];
|
|
45361
44693
|
const aiRunner = createAiRunner(provider, {
|
|
45362
44694
|
projectPath,
|
|
45363
44695
|
model,
|
|
45364
44696
|
reasoningEffort
|
|
45365
44697
|
});
|
|
45366
|
-
const log = (
|
|
45367
|
-
const icon = level === "success" ? c.success("✔") : level === "error" ? c.error("✖") : level === "warn" ? c.warning("!") : c.info("●");
|
|
45368
|
-
console.log(` ${icon} ${message}`);
|
|
45369
|
-
};
|
|
44698
|
+
const log = createCliLogger();
|
|
45370
44699
|
const facilitator = new DiscussionFacilitator({
|
|
45371
44700
|
projectPath,
|
|
45372
44701
|
aiRunner,
|
|
@@ -45381,7 +44710,7 @@ async function discussCommand(args) {
|
|
|
45381
44710
|
console.log(` ${c.dim("Topic:")} ${c.bold(topic)}`);
|
|
45382
44711
|
console.log(` ${c.dim("Model:")} ${c.dim(`${model} (${provider})`)}
|
|
45383
44712
|
`);
|
|
45384
|
-
const renderer = new ProgressRenderer;
|
|
44713
|
+
const renderer = new ProgressRenderer({ animated: true });
|
|
45385
44714
|
let discussionId;
|
|
45386
44715
|
try {
|
|
45387
44716
|
renderer.showThinkingStarted();
|
|
@@ -45445,7 +44774,7 @@ async function discussCommand(args) {
|
|
|
45445
44774
|
}
|
|
45446
44775
|
if (lowerInput === "summary") {
|
|
45447
44776
|
isProcessing = true;
|
|
45448
|
-
const summaryRenderer = new ProgressRenderer;
|
|
44777
|
+
const summaryRenderer = new ProgressRenderer({ animated: true });
|
|
45449
44778
|
try {
|
|
45450
44779
|
summaryRenderer.showThinkingStarted();
|
|
45451
44780
|
const summary = await facilitator.summarizeDiscussion(discussionId);
|
|
@@ -45489,7 +44818,7 @@ async function discussCommand(args) {
|
|
|
45489
44818
|
const cleanedInput = stripImagePaths(trimmed, images);
|
|
45490
44819
|
const effectiveInput = cleanedInput + buildImageContext(images);
|
|
45491
44820
|
isProcessing = true;
|
|
45492
|
-
const chunkRenderer = new ProgressRenderer;
|
|
44821
|
+
const chunkRenderer = new ProgressRenderer({ animated: true });
|
|
45493
44822
|
try {
|
|
45494
44823
|
chunkRenderer.showThinkingStarted();
|
|
45495
44824
|
const stream4 = facilitator.continueDiscussionStream(discussionId, effectiveInput);
|
|
@@ -45552,8 +44881,8 @@ async function discussCommand(args) {
|
|
|
45552
44881
|
inputHandler.start();
|
|
45553
44882
|
inputHandler.showPrompt();
|
|
45554
44883
|
}
|
|
45555
|
-
function
|
|
45556
|
-
const discussions = discussionManager
|
|
44884
|
+
function renderDiscussionList(discussionManager) {
|
|
44885
|
+
const discussions = listDiscussions(discussionManager);
|
|
45557
44886
|
if (discussions.length === 0) {
|
|
45558
44887
|
console.log(`
|
|
45559
44888
|
${c.dim("No discussions found.")}
|
|
@@ -45567,50 +44896,12 @@ function listDiscussions(discussionManager) {
|
|
|
45567
44896
|
`);
|
|
45568
44897
|
for (const disc of discussions) {
|
|
45569
44898
|
const statusIcon = disc.status === "active" ? c.warning("◯") : disc.status === "completed" ? c.success("✔") : c.dim("⊘");
|
|
45570
|
-
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`)}`);
|
|
45571
44900
|
console.log(` ${c.dim("ID:")} ${disc.id}`);
|
|
45572
44901
|
console.log(` ${c.dim("Created:")} ${disc.createdAt}`);
|
|
45573
44902
|
console.log("");
|
|
45574
44903
|
}
|
|
45575
44904
|
}
|
|
45576
|
-
function showDiscussion(discussionManager, id) {
|
|
45577
|
-
const md = discussionManager.getMarkdown(id);
|
|
45578
|
-
if (!md) {
|
|
45579
|
-
console.error(`
|
|
45580
|
-
${c.error("✖")} ${c.red(`Discussion not found: ${id}`)}
|
|
45581
|
-
`);
|
|
45582
|
-
process.exit(1);
|
|
45583
|
-
}
|
|
45584
|
-
console.log(`
|
|
45585
|
-
${md}
|
|
45586
|
-
`);
|
|
45587
|
-
}
|
|
45588
|
-
function archiveDiscussion(discussionManager, id) {
|
|
45589
|
-
try {
|
|
45590
|
-
discussionManager.archive(id);
|
|
45591
|
-
console.log(`
|
|
45592
|
-
${c.success("✔")} ${c.dim("Discussion archived.")}
|
|
45593
|
-
`);
|
|
45594
|
-
} catch (error48) {
|
|
45595
|
-
console.error(`
|
|
45596
|
-
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
45597
|
-
`);
|
|
45598
|
-
process.exit(1);
|
|
45599
|
-
}
|
|
45600
|
-
}
|
|
45601
|
-
function deleteDiscussion(discussionManager, id) {
|
|
45602
|
-
try {
|
|
45603
|
-
discussionManager.delete(id);
|
|
45604
|
-
console.log(`
|
|
45605
|
-
${c.success("✔")} ${c.dim("Discussion deleted.")}
|
|
45606
|
-
`);
|
|
45607
|
-
} catch (error48) {
|
|
45608
|
-
console.error(`
|
|
45609
|
-
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
45610
|
-
`);
|
|
45611
|
-
process.exit(1);
|
|
45612
|
-
}
|
|
45613
|
-
}
|
|
45614
44905
|
function showCurrentInsights(discussionManager, discussionId) {
|
|
45615
44906
|
const discussion2 = discussionManager.load(discussionId);
|
|
45616
44907
|
if (!discussion2 || discussion2.insights.length === 0) {
|
|
@@ -45701,11 +44992,10 @@ function showDiscussHelp() {
|
|
|
45701
44992
|
`);
|
|
45702
44993
|
}
|
|
45703
44994
|
// src/commands/docs.ts
|
|
44995
|
+
init_src3();
|
|
45704
44996
|
init_index_node();
|
|
45705
44997
|
init_config_manager();
|
|
45706
|
-
init_settings_manager();
|
|
45707
44998
|
init_utils3();
|
|
45708
|
-
init_workspace_resolver();
|
|
45709
44999
|
import { parseArgs as parseArgs4 } from "node:util";
|
|
45710
45000
|
async function docsCommand(args) {
|
|
45711
45001
|
const subcommand = args[0];
|
|
@@ -45739,55 +45029,25 @@ async function docsSyncCommand(args) {
|
|
|
45739
45029
|
requireInitialization(projectPath, "docs sync");
|
|
45740
45030
|
const configManager = new ConfigManager(projectPath);
|
|
45741
45031
|
configManager.updateVersion(VERSION2);
|
|
45742
|
-
|
|
45743
|
-
const settings = settingsManager.load();
|
|
45744
|
-
const apiKey = values["api-key"] || settings.apiKey;
|
|
45745
|
-
if (!apiKey) {
|
|
45746
|
-
console.error(`
|
|
45747
|
-
${c.error("✖")} ${c.red("API key is required")}
|
|
45748
|
-
` + ` ${c.dim(`Configure with: locus config setup --api-key <key>
|
|
45749
|
-
Or pass --api-key flag`)}
|
|
45750
|
-
`);
|
|
45751
|
-
process.exit(1);
|
|
45752
|
-
}
|
|
45753
|
-
const apiBase = values["api-url"] || settings.apiUrl || "https://api.locusai.dev/api";
|
|
45754
|
-
const resolver = new WorkspaceResolver({
|
|
45755
|
-
apiKey,
|
|
45756
|
-
apiBase,
|
|
45757
|
-
workspaceId: values.workspace
|
|
45758
|
-
});
|
|
45759
|
-
let workspaceId;
|
|
45032
|
+
let apiContext;
|
|
45760
45033
|
try {
|
|
45761
|
-
|
|
45034
|
+
apiContext = await resolveApiContext({
|
|
45035
|
+
projectPath,
|
|
45036
|
+
apiKey: values["api-key"],
|
|
45037
|
+
apiUrl: values["api-url"],
|
|
45038
|
+
workspaceId: values.workspace
|
|
45039
|
+
});
|
|
45762
45040
|
} catch (error48) {
|
|
45763
45041
|
console.error(`
|
|
45764
45042
|
${c.error("✖")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}
|
|
45765
45043
|
`);
|
|
45766
45044
|
process.exit(1);
|
|
45767
45045
|
}
|
|
45768
|
-
const client = new LocusClient({
|
|
45769
|
-
baseUrl: apiBase,
|
|
45770
|
-
token: apiKey
|
|
45771
|
-
});
|
|
45772
45046
|
const fetcher = new DocumentFetcher({
|
|
45773
|
-
client,
|
|
45774
|
-
workspaceId,
|
|
45047
|
+
client: apiContext.client,
|
|
45048
|
+
workspaceId: apiContext.workspaceId,
|
|
45775
45049
|
projectPath,
|
|
45776
|
-
log: (
|
|
45777
|
-
if (level === "error") {
|
|
45778
|
-
console.log(` ${c.error("✖")} ${message}`);
|
|
45779
|
-
return;
|
|
45780
|
-
}
|
|
45781
|
-
if (level === "warn") {
|
|
45782
|
-
console.log(` ${c.warning("!")} ${message}`);
|
|
45783
|
-
return;
|
|
45784
|
-
}
|
|
45785
|
-
if (level === "success") {
|
|
45786
|
-
console.log(` ${c.success("✔")} ${message}`);
|
|
45787
|
-
return;
|
|
45788
|
-
}
|
|
45789
|
-
console.log(` ${c.info("●")} ${message}`);
|
|
45790
|
-
}
|
|
45050
|
+
log: createCliLogger()
|
|
45791
45051
|
});
|
|
45792
45052
|
console.log(`
|
|
45793
45053
|
${c.info("●")} ${c.bold("Syncing docs from API...")}
|
|
@@ -45966,7 +45226,11 @@ class JsonStreamRenderer {
|
|
|
45966
45226
|
|
|
45967
45227
|
// src/commands/exec.ts
|
|
45968
45228
|
init_progress_renderer();
|
|
45969
|
-
|
|
45229
|
+
|
|
45230
|
+
// src/settings-manager.ts
|
|
45231
|
+
init_src3();
|
|
45232
|
+
|
|
45233
|
+
// src/commands/exec.ts
|
|
45970
45234
|
init_utils3();
|
|
45971
45235
|
|
|
45972
45236
|
// src/commands/exec-sessions.ts
|
|
@@ -46178,7 +45442,7 @@ async function execCommand(args) {
|
|
|
46178
45442
|
}
|
|
46179
45443
|
}
|
|
46180
45444
|
const execSettings = new SettingsManager(projectPath).load();
|
|
46181
|
-
const provider =
|
|
45445
|
+
const provider = resolveProvider4(values.provider || execSettings.provider);
|
|
46182
45446
|
const model = values.model || execSettings.model || DEFAULT_MODEL[provider];
|
|
46183
45447
|
const isInteractive = values.interactive;
|
|
46184
45448
|
const sessionId = values.session;
|
|
@@ -46274,7 +45538,7 @@ async function execCommand(args) {
|
|
|
46274
45538
|
async function execJsonStream(values, positionals, projectPath) {
|
|
46275
45539
|
const sessionId = values["session-id"] ?? values.session ?? randomUUID2();
|
|
46276
45540
|
const execSettings = new SettingsManager(projectPath).load();
|
|
46277
|
-
const provider =
|
|
45541
|
+
const provider = resolveProvider4(values.provider || execSettings.provider);
|
|
46278
45542
|
const model = values.model || execSettings.model || DEFAULT_MODEL[provider];
|
|
46279
45543
|
const renderer = new JsonStreamRenderer({
|
|
46280
45544
|
sessionId,
|
|
@@ -46358,17 +45622,11 @@ function showHelp2() {
|
|
|
46358
45622
|
${c.dim("sync Sync docs from API to .locus/documents")}
|
|
46359
45623
|
${c.success("review")} Review open Locus PRs on GitHub with AI
|
|
46360
45624
|
${c.dim("local Review staged changes locally (no GitHub)")}
|
|
46361
|
-
${c.success("telegram")}
|
|
46362
|
-
${c.dim("start Start the Telegram bot")}
|
|
45625
|
+
${c.success("telegram")} Configure the Telegram bot
|
|
46363
45626
|
${c.dim("setup Interactive bot token and chat ID setup")}
|
|
46364
45627
|
${c.dim("config Show current configuration")}
|
|
46365
45628
|
${c.dim("set <k> <v> Update a config value")}
|
|
46366
45629
|
${c.dim("remove Remove Telegram configuration")}
|
|
46367
|
-
${c.success("daemon")} Manage the Locus background service
|
|
46368
|
-
${c.dim("start Install and start the daemon")}
|
|
46369
|
-
${c.dim("stop Stop and remove the daemon")}
|
|
46370
|
-
${c.dim("restart Restart the daemon")}
|
|
46371
|
-
${c.dim("status Check if the daemon is running")}
|
|
46372
45630
|
${c.success("exec")} Run a prompt with repository context
|
|
46373
45631
|
${c.dim("--interactive, -i Start interactive REPL mode")}
|
|
46374
45632
|
${c.dim("--session, -s <id> Resume a previous session")}
|
|
@@ -46391,19 +45649,17 @@ function showHelp2() {
|
|
|
46391
45649
|
${c.header(" GETTING STARTED ")}
|
|
46392
45650
|
${c.dim("$")} ${c.primary("locus init")}
|
|
46393
45651
|
${c.dim("$")} ${c.primary("locus config setup")}
|
|
46394
|
-
${c.dim("$")} ${c.primary("locus
|
|
46395
|
-
${c.dim("$")} ${c.primary("locus daemon start")}
|
|
45652
|
+
${c.dim("$")} ${c.primary("locus run")}
|
|
46396
45653
|
|
|
46397
45654
|
${c.header(" EXAMPLES ")}
|
|
46398
45655
|
${c.dim("$")} ${c.primary("locus run")}
|
|
46399
45656
|
${c.dim("$")} ${c.primary("locus docs sync")}
|
|
46400
45657
|
${c.dim("$")} ${c.primary("locus review")}
|
|
46401
45658
|
${c.dim("$")} ${c.primary("locus review local")}
|
|
46402
|
-
${c.dim("$")} ${c.primary("locus telegram
|
|
45659
|
+
${c.dim("$")} ${c.primary("locus telegram setup")}
|
|
46403
45660
|
${c.dim("$")} ${c.primary('locus discuss "how should we design the auth system?"')}
|
|
46404
45661
|
${c.dim("$")} ${c.primary("locus exec sessions list")}
|
|
46405
45662
|
${c.dim("$")} ${c.primary("locus artifacts")}
|
|
46406
|
-
${c.dim("$")} ${c.primary("locus daemon start")}
|
|
46407
45663
|
|
|
46408
45664
|
For more information, visit: ${c.underline("https://docs.locusai.dev")}
|
|
46409
45665
|
`);
|
|
@@ -46452,7 +45708,7 @@ async function indexCommand(args) {
|
|
|
46452
45708
|
const projectPath = values.dir || process.cwd();
|
|
46453
45709
|
requireInitialization(projectPath, "index");
|
|
46454
45710
|
new ConfigManager(projectPath).updateVersion(VERSION2);
|
|
46455
|
-
const provider =
|
|
45711
|
+
const provider = resolveProvider4(values.provider);
|
|
46456
45712
|
const model = values.model || DEFAULT_MODEL[provider];
|
|
46457
45713
|
const aiRunner = createAiRunner(provider, {
|
|
46458
45714
|
projectPath,
|
|
@@ -46543,13 +45799,12 @@ async function initCommand() {
|
|
|
46543
45799
|
init_plan();
|
|
46544
45800
|
|
|
46545
45801
|
// src/commands/review.ts
|
|
45802
|
+
init_src3();
|
|
46546
45803
|
init_index_node();
|
|
46547
45804
|
init_config_manager();
|
|
46548
|
-
init_settings_manager();
|
|
46549
45805
|
init_utils3();
|
|
46550
|
-
|
|
46551
|
-
import {
|
|
46552
|
-
import { join as join21 } 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";
|
|
46553
45808
|
import { parseArgs as parseArgs7 } from "node:util";
|
|
46554
45809
|
async function reviewCommand(args) {
|
|
46555
45810
|
const subcommand = args[0];
|
|
@@ -46575,41 +45830,25 @@ async function reviewPrsCommand(args) {
|
|
|
46575
45830
|
requireInitialization(projectPath, "review");
|
|
46576
45831
|
const configManager = new ConfigManager(projectPath);
|
|
46577
45832
|
configManager.updateVersion(VERSION2);
|
|
46578
|
-
|
|
46579
|
-
const settings = settingsManager.load();
|
|
46580
|
-
const apiKey = values["api-key"] || settings.apiKey;
|
|
46581
|
-
if (!apiKey) {
|
|
46582
|
-
console.error(c.error("Error: API key is required for PR review"));
|
|
46583
|
-
console.error(c.dim(`Configure with: locus config setup --api-key <key>
|
|
46584
|
-
Or pass --api-key flag`));
|
|
46585
|
-
console.error(c.dim("For local staged-changes review, use: locus review local"));
|
|
46586
|
-
process.exit(1);
|
|
46587
|
-
}
|
|
46588
|
-
const provider = resolveProvider3(values.provider || settings.provider);
|
|
46589
|
-
const model = values.model || settings.model || DEFAULT_MODEL[provider];
|
|
46590
|
-
const apiBase = values["api-url"] || settings.apiUrl || "https://api.locusai.dev/api";
|
|
46591
|
-
let workspaceId;
|
|
45833
|
+
let apiContext;
|
|
46592
45834
|
try {
|
|
46593
|
-
|
|
46594
|
-
|
|
46595
|
-
|
|
45835
|
+
apiContext = await resolveApiContext({
|
|
45836
|
+
projectPath,
|
|
45837
|
+
apiKey: values["api-key"],
|
|
45838
|
+
apiUrl: values["api-url"],
|
|
46596
45839
|
workspaceId: values.workspace
|
|
46597
45840
|
});
|
|
46598
|
-
workspaceId = await resolver.resolve();
|
|
46599
45841
|
} catch (error48) {
|
|
46600
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"));
|
|
46601
45844
|
process.exit(1);
|
|
46602
45845
|
}
|
|
46603
|
-
const
|
|
46604
|
-
|
|
46605
|
-
|
|
46606
|
-
|
|
46607
|
-
|
|
46608
|
-
|
|
46609
|
-
}[level];
|
|
46610
|
-
const prefix = { info: "ℹ", success: "✓", warn: "⚠", error: "✗" }[level];
|
|
46611
|
-
console.log(` ${colorFn(`${prefix} ${msg}`)}`);
|
|
46612
|
-
};
|
|
45846
|
+
const { provider, model } = resolveAiSettings({
|
|
45847
|
+
projectPath,
|
|
45848
|
+
provider: values.provider,
|
|
45849
|
+
model: values.model
|
|
45850
|
+
});
|
|
45851
|
+
const log = createCliLogger();
|
|
46613
45852
|
const prService = new PrService(projectPath, log);
|
|
46614
45853
|
const unreviewedPrs = prService.listUnreviewedLocusPrs();
|
|
46615
45854
|
if (unreviewedPrs.length === 0) {
|
|
@@ -46624,10 +45863,10 @@ async function reviewPrsCommand(args) {
|
|
|
46624
45863
|
const agentId = `reviewer-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
46625
45864
|
const reviewer = new ReviewerWorker({
|
|
46626
45865
|
agentId,
|
|
46627
|
-
workspaceId,
|
|
46628
|
-
apiBase,
|
|
45866
|
+
workspaceId: apiContext.workspaceId,
|
|
45867
|
+
apiBase: apiContext.apiBase,
|
|
46629
45868
|
projectPath,
|
|
46630
|
-
apiKey,
|
|
45869
|
+
apiKey: apiContext.apiKey,
|
|
46631
45870
|
model,
|
|
46632
45871
|
provider
|
|
46633
45872
|
});
|
|
@@ -46656,9 +45895,11 @@ async function reviewLocalCommand(args) {
|
|
|
46656
45895
|
});
|
|
46657
45896
|
const projectPath = values.dir || process.cwd();
|
|
46658
45897
|
requireInitialization(projectPath, "review local");
|
|
46659
|
-
const
|
|
46660
|
-
|
|
46661
|
-
|
|
45898
|
+
const { provider, model } = resolveAiSettings({
|
|
45899
|
+
projectPath,
|
|
45900
|
+
provider: values.provider,
|
|
45901
|
+
model: values.model
|
|
45902
|
+
});
|
|
46662
45903
|
const aiRunner = createAiRunner(provider, {
|
|
46663
45904
|
projectPath,
|
|
46664
45905
|
model
|
|
@@ -46666,18 +45907,7 @@ async function reviewLocalCommand(args) {
|
|
|
46666
45907
|
const reviewService = new ReviewService({
|
|
46667
45908
|
aiRunner,
|
|
46668
45909
|
projectPath,
|
|
46669
|
-
log: (
|
|
46670
|
-
switch (level) {
|
|
46671
|
-
case "error":
|
|
46672
|
-
console.log(` ${c.error("✖")} ${msg}`);
|
|
46673
|
-
break;
|
|
46674
|
-
case "success":
|
|
46675
|
-
console.log(` ${c.success("✔")} ${msg}`);
|
|
46676
|
-
break;
|
|
46677
|
-
default:
|
|
46678
|
-
console.log(` ${c.dim(msg)}`);
|
|
46679
|
-
}
|
|
46680
|
-
}
|
|
45910
|
+
log: createCliLogger()
|
|
46681
45911
|
});
|
|
46682
45912
|
console.log(`
|
|
46683
45913
|
${c.primary("\uD83D\uDD0D")} ${c.bold("Reviewing staged changes...")}
|
|
@@ -46688,12 +45918,12 @@ async function reviewLocalCommand(args) {
|
|
|
46688
45918
|
`);
|
|
46689
45919
|
return;
|
|
46690
45920
|
}
|
|
46691
|
-
const reviewsDir =
|
|
46692
|
-
if (!
|
|
46693
|
-
|
|
45921
|
+
const reviewsDir = join20(projectPath, LOCUS_CONFIG.dir, LOCUS_CONFIG.reviewsDir);
|
|
45922
|
+
if (!existsSync20(reviewsDir)) {
|
|
45923
|
+
mkdirSync9(reviewsDir, { recursive: true });
|
|
46694
45924
|
}
|
|
46695
45925
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
46696
|
-
const reportPath =
|
|
45926
|
+
const reportPath = join20(reviewsDir, `review-${timestamp}.md`);
|
|
46697
45927
|
writeFileSync9(reportPath, report, "utf-8");
|
|
46698
45928
|
console.log(`
|
|
46699
45929
|
${c.success("✔")} ${c.success("Review complete!")}`);
|
|
@@ -46703,10 +45933,23 @@ async function reviewLocalCommand(args) {
|
|
|
46703
45933
|
// src/commands/run.ts
|
|
46704
45934
|
init_index_node();
|
|
46705
45935
|
init_config_manager();
|
|
46706
|
-
init_settings_manager();
|
|
46707
|
-
init_utils3();
|
|
46708
|
-
init_workspace_resolver();
|
|
46709
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
|
|
46710
45953
|
async function runCommand(args) {
|
|
46711
45954
|
const { values } = parseArgs8({
|
|
46712
45955
|
args,
|
|
@@ -46737,11 +45980,11 @@ async function runCommand(args) {
|
|
|
46737
45980
|
process.exit(1);
|
|
46738
45981
|
}
|
|
46739
45982
|
let workspaceId = values.workspace;
|
|
46740
|
-
const provider =
|
|
45983
|
+
const provider = resolveProvider4(values.provider || settings.provider);
|
|
46741
45984
|
const model = values.model || settings.model || DEFAULT_MODEL[provider];
|
|
46742
45985
|
const apiBase = values["api-url"] || settings.apiUrl || "https://api.locusai.dev/api";
|
|
46743
45986
|
try {
|
|
46744
|
-
const resolver = new
|
|
45987
|
+
const resolver = new WorkspaceResolver2({
|
|
46745
45988
|
apiKey,
|
|
46746
45989
|
apiBase,
|
|
46747
45990
|
workspaceId: values.workspace
|
|
@@ -46787,30 +46030,11 @@ ${c.info(`Received ${signal}. Stopping agent and cleaning up...`)}`);
|
|
|
46787
46030
|
console.log(` ${c.dim("A PR will be opened when all tasks are done")}`);
|
|
46788
46031
|
await orchestrator.start();
|
|
46789
46032
|
}
|
|
46790
|
-
// src/commands/service.ts
|
|
46791
|
-
init_index_node();
|
|
46792
|
-
async function serviceCommand(args) {
|
|
46793
|
-
const subcommand = args[0];
|
|
46794
|
-
const mapping = {
|
|
46795
|
-
install: "start",
|
|
46796
|
-
uninstall: "stop",
|
|
46797
|
-
status: "status"
|
|
46798
|
-
};
|
|
46799
|
-
const mapped = subcommand ? mapping[subcommand] : undefined;
|
|
46800
|
-
if (mapped) {
|
|
46801
|
-
console.log(` ${c.dim(`Hint: 'locus service ${subcommand}' is now 'locus daemon ${mapped}'`)}
|
|
46802
|
-
`);
|
|
46803
|
-
await daemonCommand([mapped, ...args.slice(1)]);
|
|
46804
|
-
} else {
|
|
46805
|
-
await daemonCommand(args);
|
|
46806
|
-
}
|
|
46807
|
-
}
|
|
46808
46033
|
// src/commands/telegram.ts
|
|
46809
46034
|
init_index_node();
|
|
46810
|
-
|
|
46811
|
-
import {
|
|
46812
|
-
import {
|
|
46813
|
-
import { join as join22 } from "node:path";
|
|
46035
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
46036
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
46037
|
+
import { join as join21 } from "node:path";
|
|
46814
46038
|
import { createInterface as createInterface2 } from "node:readline";
|
|
46815
46039
|
function ask2(question) {
|
|
46816
46040
|
const rl = createInterface2({
|
|
@@ -46836,7 +46060,7 @@ function showTelegramHelp() {
|
|
|
46836
46060
|
${c.primary("locus telegram")} ${c.dim("<subcommand> [options]")}
|
|
46837
46061
|
|
|
46838
46062
|
${c.header(" SUBCOMMANDS ")}
|
|
46839
|
-
${c.success("
|
|
46063
|
+
${c.success("run")} Start the Telegram bot
|
|
46840
46064
|
${c.success("setup")} Interactive Telegram bot setup (or pass flags below)
|
|
46841
46065
|
${c.success("config")} Show current Telegram configuration
|
|
46842
46066
|
${c.success("set")} Set a config value
|
|
@@ -46845,7 +46069,7 @@ function showTelegramHelp() {
|
|
|
46845
46069
|
${c.success("remove")} Remove Telegram configuration
|
|
46846
46070
|
|
|
46847
46071
|
${c.header(" EXAMPLES ")}
|
|
46848
|
-
${c.dim("$")} ${c.primary("locus telegram
|
|
46072
|
+
${c.dim("$")} ${c.primary("locus telegram run")}
|
|
46849
46073
|
${c.dim("$")} ${c.primary('locus telegram setup --token "123:ABC" --chat-id 987654')}
|
|
46850
46074
|
${c.dim("$")} ${c.primary("locus telegram config")}
|
|
46851
46075
|
${c.dim("$")} ${c.primary("locus telegram remove")}
|
|
@@ -46856,7 +46080,7 @@ function showTelegramHelp() {
|
|
|
46856
46080
|
${c.primary("locus config set <key> <value>")}
|
|
46857
46081
|
`);
|
|
46858
46082
|
}
|
|
46859
|
-
async function
|
|
46083
|
+
async function setupCommand2(args, projectPath) {
|
|
46860
46084
|
let token;
|
|
46861
46085
|
let chatId;
|
|
46862
46086
|
for (let i = 0;i < args.length; i++) {
|
|
@@ -46928,11 +46152,10 @@ async function setup(args, projectPath) {
|
|
|
46928
46152
|
${c.primary("Chat ID:")} ${parsedChatId}
|
|
46929
46153
|
|
|
46930
46154
|
${c.bold("Next steps:")}
|
|
46931
|
-
Start
|
|
46932
|
-
Or run manually: ${c.primary("locus telegram start")}
|
|
46155
|
+
Start the bot with: ${c.primary("locus telegram run")}
|
|
46933
46156
|
`);
|
|
46934
46157
|
}
|
|
46935
|
-
function
|
|
46158
|
+
function configCommand2(projectPath) {
|
|
46936
46159
|
const manager = new SettingsManager(projectPath);
|
|
46937
46160
|
const settings = manager.load();
|
|
46938
46161
|
const tg = settings.telegram;
|
|
@@ -46948,28 +46171,36 @@ function showConfig(projectPath) {
|
|
|
46948
46171
|
console.log(` ${c.dim("File: .locus/settings.json (telegram section)")}
|
|
46949
46172
|
`);
|
|
46950
46173
|
const entries = [];
|
|
46951
|
-
if (tg.botToken)
|
|
46174
|
+
if (tg.botToken) {
|
|
46952
46175
|
entries.push(["botToken", maskToken(tg.botToken)]);
|
|
46953
|
-
|
|
46176
|
+
}
|
|
46177
|
+
if (tg.chatId) {
|
|
46954
46178
|
entries.push(["chatId", String(tg.chatId)]);
|
|
46955
|
-
|
|
46179
|
+
}
|
|
46180
|
+
if (tg.testMode !== undefined) {
|
|
46956
46181
|
entries.push(["testMode", String(tg.testMode)]);
|
|
46957
|
-
|
|
46182
|
+
}
|
|
46183
|
+
if (settings.apiKey) {
|
|
46958
46184
|
entries.push(["apiKey (shared)", maskToken(settings.apiKey)]);
|
|
46959
|
-
|
|
46185
|
+
}
|
|
46186
|
+
if (settings.apiUrl) {
|
|
46960
46187
|
entries.push(["apiUrl (shared)", settings.apiUrl]);
|
|
46961
|
-
|
|
46188
|
+
}
|
|
46189
|
+
if (settings.provider) {
|
|
46962
46190
|
entries.push(["provider (shared)", settings.provider]);
|
|
46963
|
-
|
|
46191
|
+
}
|
|
46192
|
+
if (settings.model) {
|
|
46964
46193
|
entries.push(["model (shared)", settings.model]);
|
|
46965
|
-
|
|
46194
|
+
}
|
|
46195
|
+
if (settings.workspaceId) {
|
|
46966
46196
|
entries.push(["workspaceId (shared)", settings.workspaceId]);
|
|
46197
|
+
}
|
|
46967
46198
|
for (const [key, value] of entries) {
|
|
46968
46199
|
console.log(` ${c.primary(`${key}:`)} ${value}`);
|
|
46969
46200
|
}
|
|
46970
46201
|
console.log("");
|
|
46971
46202
|
}
|
|
46972
|
-
function
|
|
46203
|
+
function setCommand2(args, projectPath) {
|
|
46973
46204
|
const key = args[0]?.trim();
|
|
46974
46205
|
const value = args.slice(1).join(" ").trim();
|
|
46975
46206
|
if (!key || !value) {
|
|
@@ -47012,7 +46243,7 @@ function setValue(args, projectPath) {
|
|
|
47012
46243
|
${c.success("✔")} Set ${c.primary(key)} = ${displayValue}
|
|
47013
46244
|
`);
|
|
47014
46245
|
}
|
|
47015
|
-
function
|
|
46246
|
+
function removeCommand2(projectPath) {
|
|
47016
46247
|
const manager = new SettingsManager(projectPath);
|
|
47017
46248
|
const settings = manager.load();
|
|
47018
46249
|
if (!settings.telegram) {
|
|
@@ -47027,7 +46258,7 @@ function removeConfig(projectPath) {
|
|
|
47027
46258
|
${c.success("✔")} ${c.bold("Telegram configuration removed.")}
|
|
47028
46259
|
`);
|
|
47029
46260
|
}
|
|
47030
|
-
function
|
|
46261
|
+
function runBotCommand(projectPath) {
|
|
47031
46262
|
const manager = new SettingsManager(projectPath);
|
|
47032
46263
|
const settings = manager.load();
|
|
47033
46264
|
if (!settings.telegram?.botToken || !settings.telegram?.chatId) {
|
|
@@ -47037,14 +46268,22 @@ function startBot(projectPath) {
|
|
|
47037
46268
|
`);
|
|
47038
46269
|
process.exit(1);
|
|
47039
46270
|
}
|
|
47040
|
-
const
|
|
47041
|
-
const isMonorepo =
|
|
47042
|
-
|
|
47043
|
-
|
|
47044
|
-
|
|
46271
|
+
const monorepoTelegramEntry = join21(projectPath, "packages/telegram/src/index.ts");
|
|
46272
|
+
const isMonorepo = existsSync21(monorepoTelegramEntry);
|
|
46273
|
+
let cmd;
|
|
46274
|
+
let args;
|
|
46275
|
+
if (isMonorepo) {
|
|
46276
|
+
cmd = "bun";
|
|
46277
|
+
args = ["run", monorepoTelegramEntry];
|
|
46278
|
+
} else {
|
|
46279
|
+
cmd = "locus-telegram";
|
|
46280
|
+
args = [];
|
|
46281
|
+
}
|
|
46282
|
+
const env = { ...process.env };
|
|
46283
|
+
const child = spawn4(cmd, args, {
|
|
47045
46284
|
cwd: projectPath,
|
|
47046
46285
|
stdio: "inherit",
|
|
47047
|
-
env
|
|
46286
|
+
env
|
|
47048
46287
|
});
|
|
47049
46288
|
child.on("error", (err) => {
|
|
47050
46289
|
if (err.code === "ENOENT" && !isMonorepo) {
|
|
@@ -47065,23 +46304,22 @@ function startBot(projectPath) {
|
|
|
47065
46304
|
}
|
|
47066
46305
|
async function telegramCommand(args) {
|
|
47067
46306
|
const projectPath = process.cwd();
|
|
47068
|
-
const
|
|
46307
|
+
const subcommand = args[0];
|
|
47069
46308
|
switch (subcommand) {
|
|
47070
|
-
case "start":
|
|
47071
46309
|
case "run":
|
|
47072
|
-
|
|
46310
|
+
runBotCommand(projectPath);
|
|
47073
46311
|
break;
|
|
47074
46312
|
case "setup":
|
|
47075
|
-
await
|
|
46313
|
+
await setupCommand2(args, projectPath);
|
|
47076
46314
|
break;
|
|
47077
46315
|
case "config":
|
|
47078
|
-
|
|
46316
|
+
configCommand2(projectPath);
|
|
47079
46317
|
break;
|
|
47080
46318
|
case "set":
|
|
47081
|
-
|
|
46319
|
+
setCommand2(args, projectPath);
|
|
47082
46320
|
break;
|
|
47083
46321
|
case "remove":
|
|
47084
|
-
|
|
46322
|
+
removeCommand2(projectPath);
|
|
47085
46323
|
break;
|
|
47086
46324
|
default:
|
|
47087
46325
|
showTelegramHelp();
|
|
@@ -47117,7 +46355,6 @@ async function upgradeCommand() {
|
|
|
47117
46355
|
console.log(`
|
|
47118
46356
|
${c.header(" UPGRADE ")}
|
|
47119
46357
|
`);
|
|
47120
|
-
const daemonWasRunning = await isDaemonRunning();
|
|
47121
46358
|
try {
|
|
47122
46359
|
console.log(` ${c.dim("◌")} Cleaning npm cache...`);
|
|
47123
46360
|
execSync3("npm cache clean --force", {
|
|
@@ -47129,7 +46366,6 @@ async function upgradeCommand() {
|
|
|
47129
46366
|
console.log(` ${c.dim("⚠")} Could not clean npm cache, continuing...
|
|
47130
46367
|
`);
|
|
47131
46368
|
}
|
|
47132
|
-
let anyUpdated = false;
|
|
47133
46369
|
for (const pkg of PACKAGES) {
|
|
47134
46370
|
const current = getInstalledVersion(pkg);
|
|
47135
46371
|
const latest = getLatestVersion(pkg);
|
|
@@ -47152,27 +46388,12 @@ async function upgradeCommand() {
|
|
|
47152
46388
|
});
|
|
47153
46389
|
console.log(` ${c.success("✔")} ${c.bold(pkg)} updated to ${c.primary(`v${latest}`)}
|
|
47154
46390
|
`);
|
|
47155
|
-
anyUpdated = true;
|
|
47156
46391
|
} catch {
|
|
47157
46392
|
console.error(` ${c.error("✖")} Failed to update ${c.bold(pkg)}. Try manually:
|
|
47158
46393
|
` + ` ${c.primary(`npm install -g ${pkg}@latest`)}
|
|
47159
46394
|
`);
|
|
47160
46395
|
}
|
|
47161
46396
|
}
|
|
47162
|
-
if (daemonWasRunning && anyUpdated) {
|
|
47163
|
-
console.log(` ${c.info("▶")} Restarting locus daemon...`);
|
|
47164
|
-
const restarted = await restartDaemonIfRunning();
|
|
47165
|
-
if (restarted) {
|
|
47166
|
-
console.log(` ${c.success("✔")} Locus daemon restarted
|
|
47167
|
-
`);
|
|
47168
|
-
} else {
|
|
47169
|
-
console.log(` ${c.dim("⚠")} Could not restart daemon (may need sudo)
|
|
47170
|
-
`);
|
|
47171
|
-
}
|
|
47172
|
-
} else if (daemonWasRunning && !anyUpdated) {
|
|
47173
|
-
console.log(` ${c.dim("No updates — daemon left running")}
|
|
47174
|
-
`);
|
|
47175
|
-
}
|
|
47176
46397
|
console.log("");
|
|
47177
46398
|
}
|
|
47178
46399
|
// src/commands/version.ts
|
|
@@ -47244,12 +46465,6 @@ async function main() {
|
|
|
47244
46465
|
case "config":
|
|
47245
46466
|
await configCommand(args);
|
|
47246
46467
|
break;
|
|
47247
|
-
case "daemon":
|
|
47248
|
-
await daemonCommand(args);
|
|
47249
|
-
break;
|
|
47250
|
-
case "service":
|
|
47251
|
-
await serviceCommand(args);
|
|
47252
|
-
break;
|
|
47253
46468
|
case "docs":
|
|
47254
46469
|
await docsCommand(args);
|
|
47255
46470
|
break;
|
|
@@ -47278,11 +46493,3 @@ main().catch((err) => {
|
|
|
47278
46493
|
${c.error("✖ Fatal Error")} ${c.red(err.message)}`);
|
|
47279
46494
|
process.exit(1);
|
|
47280
46495
|
});
|
|
47281
|
-
|
|
47282
|
-
// index.ts
|
|
47283
|
-
var _emit = process.emit;
|
|
47284
|
-
process.emit = function(name, data, ...args) {
|
|
47285
|
-
if (name === "warning" && data?.code === "DEP0040")
|
|
47286
|
-
return false;
|
|
47287
|
-
return _emit.apply(process, [name, data, ...args]);
|
|
47288
|
-
};
|