@locusai/cli 0.6.0 → 0.7.1

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.
@@ -17065,7 +17065,15 @@ var colors = {
17065
17065
  brightBlue: `${ESC}94m`,
17066
17066
  brightMagenta: `${ESC}95m`,
17067
17067
  brightCyan: `${ESC}96m`,
17068
- brightWhite: `${ESC}97m`
17068
+ brightWhite: `${ESC}97m`,
17069
+ bgBlack: `${ESC}40m`,
17070
+ bgRed: `${ESC}41m`,
17071
+ bgGreen: `${ESC}42m`,
17072
+ bgYellow: `${ESC}43m`,
17073
+ bgBlue: `${ESC}44m`,
17074
+ bgMagenta: `${ESC}45m`,
17075
+ bgCyan: `${ESC}46m`,
17076
+ bgWhite: `${ESC}47m`
17069
17077
  };
17070
17078
  var c = {
17071
17079
  text: (text, ...colorNames) => {
@@ -17081,11 +17089,17 @@ var c = {
17081
17089
  magenta: (t) => c.text(t, "magenta"),
17082
17090
  cyan: (t) => c.text(t, "cyan"),
17083
17091
  gray: (t) => c.text(t, "gray"),
17092
+ white: (t) => c.text(t, "white"),
17093
+ brightBlue: (t) => c.text(t, "brightBlue"),
17094
+ bgBlue: (t) => c.text(t, "bgBlue", "white", "bold"),
17084
17095
  success: (t) => c.text(t, "green", "bold"),
17085
17096
  error: (t) => c.text(t, "red", "bold"),
17086
17097
  warning: (t) => c.text(t, "yellow", "bold"),
17087
17098
  info: (t) => c.text(t, "cyan", "bold"),
17088
17099
  primary: (t) => c.text(t, "blue", "bold"),
17100
+ secondary: (t) => c.text(t, "magenta", "bold"),
17101
+ header: (t) => c.text(` ${t} `, "bgBlue", "white", "bold"),
17102
+ step: (t) => c.text(` ${t} `, "bgCyan", "black", "bold"),
17089
17103
  underline: (t) => c.text(t, "underline")
17090
17104
  };
17091
17105
 
@@ -17143,6 +17157,7 @@ class ClaudeRunner {
17143
17157
  let finalResult = "";
17144
17158
  let errorOutput = "";
17145
17159
  let buffer = "";
17160
+ let stderrBuffer = "";
17146
17161
  claude.stdout.on("data", (data) => {
17147
17162
  buffer += data.toString();
17148
17163
  const lines = buffer.split(`
@@ -17155,14 +17170,27 @@ class ClaudeRunner {
17155
17170
  }
17156
17171
  });
17157
17172
  claude.stderr.on("data", (data) => {
17158
- const msg = data.toString();
17159
- errorOutput += msg;
17160
- process.stderr.write(msg);
17173
+ const chunk = data.toString();
17174
+ errorOutput += chunk;
17175
+ stderrBuffer += chunk;
17176
+ const lines = stderrBuffer.split(`
17177
+ `);
17178
+ stderrBuffer = lines.pop() || "";
17179
+ for (const line of lines) {
17180
+ if (!this.shouldSuppressLine(line)) {
17181
+ process.stderr.write(`${line}
17182
+ `);
17183
+ }
17184
+ }
17161
17185
  });
17162
17186
  claude.on("error", (err) => {
17163
17187
  reject(new Error(`Failed to start Claude CLI: ${err.message}. Please ensure the 'claude' command is available in your PATH.`));
17164
17188
  });
17165
17189
  claude.on("close", (code) => {
17190
+ if (stderrBuffer && !this.shouldSuppressLine(stderrBuffer)) {
17191
+ process.stderr.write(`${stderrBuffer}
17192
+ `);
17193
+ }
17166
17194
  process.stdout.write(`
17167
17195
  `);
17168
17196
  if (code === 0) {
@@ -17205,6 +17233,10 @@ ${c.primary("[Claude]")} ${c.bold(`Running ${content_block.name}...`)}
17205
17233
  }
17206
17234
  }
17207
17235
  }
17236
+ shouldSuppressLine(line) {
17237
+ const infoLogRegex = /^\[\d{2}:\d{2}:\d{2}\]\s\[.*?\]\sℹ\s*$/;
17238
+ return infoLogRegex.test(line.trim());
17239
+ }
17208
17240
  createExecutionError(code, detail) {
17209
17241
  const errorMsg = detail.trim();
17210
17242
  const message = errorMsg ? `Claude CLI error (exit code ${code}): ${errorMsg}` : `Claude CLI exited with code ${code}. Please ensure the Claude CLI is installed and you are logged in.`;
@@ -20771,7 +20803,15 @@ class BaseModule {
20771
20803
  // ../sdk/src/modules/ai.ts
20772
20804
  class AIModule extends BaseModule {
20773
20805
  async chat(workspaceId, body) {
20774
- const { data } = await this.api.post(`/ai/${workspaceId}/chat`, body);
20806
+ const { data } = await this.api.post(`/ai/${workspaceId}/chat`, body, { timeout: 300000 });
20807
+ return data;
20808
+ }
20809
+ async detectIntent(workspaceId, body) {
20810
+ const { data } = await this.api.post(`/ai/${workspaceId}/chat/intent`, body, { timeout: 300000 });
20811
+ return data;
20812
+ }
20813
+ async executeIntent(workspaceId, body) {
20814
+ const { data } = await this.api.post(`/ai/${workspaceId}/chat/execute`, body, { timeout: 300000 });
20775
20815
  return data;
20776
20816
  }
20777
20817
  async listSessions(workspaceId) {
@@ -20788,14 +20828,25 @@ class AIModule extends BaseModule {
20788
20828
  async deleteSession(workspaceId, sessionId) {
20789
20829
  await this.api.delete(`/ai/${workspaceId}/session/${sessionId}`);
20790
20830
  }
20831
+ async shareSession(workspaceId, sessionId, body) {
20832
+ await this.api.post(`/ai/${workspaceId}/session/${sessionId}/share`, body);
20833
+ }
20834
+ async getSharedSession(sessionId) {
20835
+ const { data } = await this.api.get(`/ai/shared/${sessionId}`);
20836
+ return data;
20837
+ }
20791
20838
  }
20792
20839
 
20793
20840
  // ../sdk/src/modules/auth.ts
20794
20841
  class AuthModule extends BaseModule {
20795
- async getMe() {
20842
+ async getProfile() {
20796
20843
  const { data } = await this.api.get("/auth/me");
20797
20844
  return data;
20798
20845
  }
20846
+ async getApiKeyInfo() {
20847
+ const { data } = await this.api.get("/auth/api-key");
20848
+ return data;
20849
+ }
20799
20850
  async requestRegisterOtp(email) {
20800
20851
  const { data } = await this.api.post("/auth/register-otp", { email });
20801
20852
  return data;
@@ -34804,6 +34855,9 @@ var ChatResponseSchema = exports_external.object({
34804
34855
  sessionId: exports_external.string(),
34805
34856
  history: exports_external.array(AIMessageSchema).optional()
34806
34857
  });
34858
+ var ShareChatRequestSchema = exports_external.object({
34859
+ isShared: exports_external.boolean()
34860
+ });
34807
34861
  // ../shared/src/models/user.ts
34808
34862
  var UserSchema = BaseEntitySchema.extend({
34809
34863
  email: exports_external.string().email(),
@@ -34841,9 +34895,10 @@ var JwtAuthUserSchema = exports_external.object({
34841
34895
  });
34842
34896
  var ApiKeyAuthUserSchema = exports_external.object({
34843
34897
  authType: exports_external.literal("api_key"),
34844
- apiKeyId: exports_external.uuid(),
34898
+ apiKeyId: exports_external.string(),
34845
34899
  apiKeyName: exports_external.string(),
34846
- orgId: exports_external.uuid()
34900
+ orgId: exports_external.string().optional(),
34901
+ workspaceId: exports_external.string().optional()
34847
34902
  });
34848
34903
  var AuthenticatedUserSchema = exports_external.discriminatedUnion("authType", [
34849
34904
  JwtAuthUserSchema,
@@ -35344,6 +35399,17 @@ class WorkspacesModule extends BaseModule {
35344
35399
  const { data } = await this.api.post(`/workspaces/${id}/dispatch`, { workerId, sprintId });
35345
35400
  return data.task;
35346
35401
  }
35402
+ async listApiKeys(workspaceId) {
35403
+ const { data } = await this.api.get(`/workspaces/${workspaceId}/api-keys`);
35404
+ return data.apiKeys;
35405
+ }
35406
+ async createApiKey(workspaceId, name) {
35407
+ const { data } = await this.api.post(`/workspaces/${workspaceId}/api-keys`, { name });
35408
+ return data.apiKey;
35409
+ }
35410
+ async deleteApiKey(workspaceId, keyId) {
35411
+ await this.api.delete(`/workspaces/${workspaceId}/api-keys/${keyId}`);
35412
+ }
35347
35413
  }
35348
35414
 
35349
35415
  // ../sdk/src/index.ts
@@ -36068,13 +36134,10 @@ class CodebaseIndexer {
36068
36134
  `);
36069
36135
  const newTreeHash = this.hashTree(treeString);
36070
36136
  const existingIndex = this.loadIndex();
36071
- if (!force && existingIndex?.treeHash === newTreeHash) {
36072
- onProgress?.("No file changes detected, skipping reindex");
36073
- return null;
36074
- }
36075
36137
  const currentHashes = this.computeFileHashes(currentFiles);
36076
36138
  const existingHashes = existingIndex?.fileHashes;
36077
- const canIncremental = !force && existingIndex && existingHashes;
36139
+ const hasExistingContent = existingIndex && (Object.keys(existingIndex.symbols).length > 0 || Object.keys(existingIndex.responsibilities).length > 0);
36140
+ const canIncremental = !force && existingIndex && existingHashes && hasExistingContent;
36078
36141
  if (canIncremental) {
36079
36142
  onProgress?.("Performing incremental update");
36080
36143
  const { added, deleted, modified } = this.diffFiles(currentHashes, existingHashes);
@@ -36107,8 +36170,12 @@ class CodebaseIndexer {
36107
36170
  }
36108
36171
  }
36109
36172
  onProgress?.("AI is analyzing codebase structure...");
36110
- const index = await treeSummarizer(treeString);
36111
- return this.applyIndexMetadata(index, currentHashes, newTreeHash);
36173
+ try {
36174
+ const index = await treeSummarizer(treeString);
36175
+ return this.applyIndexMetadata(index, currentHashes, newTreeHash);
36176
+ } catch (error48) {
36177
+ throw new Error(`AI analysis failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
36178
+ }
36112
36179
  }
36113
36180
  async getFileTree() {
36114
36181
  const gitmodulesPath = join4(this.projectPath, ".gitmodules");
@@ -36600,16 +36667,12 @@ class TaskExecutor {
36600
36667
  });
36601
36668
  try {
36602
36669
  let plan = null;
36603
- if (this.deps.skipPlanning) {
36604
- this.deps.log("Skipping Phase 1: Planning (CLI)...", "info");
36605
- } else {
36606
- this.deps.log("Phase 1: Planning (CLI)...", "info");
36607
- const planningPrompt = `${basePrompt}
36670
+ this.deps.log("Phase 1: Planning (CLI)...", "info");
36671
+ const planningPrompt = `${basePrompt}
36608
36672
 
36609
36673
  ## Phase 1: Planning
36610
36674
  Analyze and create a detailed plan for THIS SPECIFIC TASK. Do NOT execute changes yet.`;
36611
- plan = await this.deps.aiRunner.run(planningPrompt, true);
36612
- }
36675
+ plan = await this.deps.aiRunner.run(planningPrompt, true);
36613
36676
  this.deps.log("Starting Execution...", "info");
36614
36677
  let executionPrompt = basePrompt;
36615
36678
  if (plan != null) {
@@ -36698,7 +36761,6 @@ class AgentWorker {
36698
36761
  this.taskExecutor = new TaskExecutor({
36699
36762
  aiRunner: this.aiRunner,
36700
36763
  projectPath,
36701
- skipPlanning: config2.skipPlanning,
36702
36764
  log
36703
36765
  });
36704
36766
  const providerLabel = provider === "codex" ? "Codex" : "Claude";
@@ -36829,8 +36891,7 @@ if (process.argv[1]?.includes("agent-worker") || process.argv[1]?.includes("work
36829
36891
  if (value && !value.startsWith("--"))
36830
36892
  i++;
36831
36893
  config2.provider = resolveProvider(value);
36832
- } else if (arg === "--skip-planning")
36833
- config2.skipPlanning = true;
36894
+ }
36834
36895
  }
36835
36896
  if (!config2.agentId || !config2.workspaceId || !config2.apiBase || !config2.apiKey || !config2.projectPath) {
36836
36897
  console.error("Missing required arguments");
package/bin/locus.js CHANGED
@@ -30874,6 +30874,9 @@ var ChatResponseSchema = exports_external.object({
30874
30874
  sessionId: exports_external.string(),
30875
30875
  history: exports_external.array(AIMessageSchema).optional()
30876
30876
  });
30877
+ var ShareChatRequestSchema = exports_external.object({
30878
+ isShared: exports_external.boolean()
30879
+ });
30877
30880
  // ../shared/src/models/user.ts
30878
30881
  var UserSchema = BaseEntitySchema.extend({
30879
30882
  email: exports_external.string().email(),
@@ -30911,9 +30914,10 @@ var JwtAuthUserSchema = exports_external.object({
30911
30914
  });
30912
30915
  var ApiKeyAuthUserSchema = exports_external.object({
30913
30916
  authType: exports_external.literal("api_key"),
30914
- apiKeyId: exports_external.uuid(),
30917
+ apiKeyId: exports_external.string(),
30915
30918
  apiKeyName: exports_external.string(),
30916
- orgId: exports_external.uuid()
30919
+ orgId: exports_external.string().optional(),
30920
+ workspaceId: exports_external.string().optional()
30917
30921
  });
30918
30922
  var AuthenticatedUserSchema = exports_external.discriminatedUnion("authType", [
30919
30923
  JwtAuthUserSchema,
@@ -31960,13 +31964,10 @@ class CodebaseIndexer {
31960
31964
  `);
31961
31965
  const newTreeHash = this.hashTree(treeString);
31962
31966
  const existingIndex = this.loadIndex();
31963
- if (!force && existingIndex?.treeHash === newTreeHash) {
31964
- onProgress?.("No file changes detected, skipping reindex");
31965
- return null;
31966
- }
31967
31967
  const currentHashes = this.computeFileHashes(currentFiles);
31968
31968
  const existingHashes = existingIndex?.fileHashes;
31969
- const canIncremental = !force && existingIndex && existingHashes;
31969
+ const hasExistingContent = existingIndex && (Object.keys(existingIndex.symbols).length > 0 || Object.keys(existingIndex.responsibilities).length > 0);
31970
+ const canIncremental = !force && existingIndex && existingHashes && hasExistingContent;
31970
31971
  if (canIncremental) {
31971
31972
  onProgress?.("Performing incremental update");
31972
31973
  const { added, deleted, modified } = this.diffFiles(currentHashes, existingHashes);
@@ -31999,8 +32000,12 @@ class CodebaseIndexer {
31999
32000
  }
32000
32001
  }
32001
32002
  onProgress?.("AI is analyzing codebase structure...");
32002
- const index = await treeSummarizer(treeString);
32003
- return this.applyIndexMetadata(index, currentHashes, newTreeHash);
32003
+ try {
32004
+ const index = await treeSummarizer(treeString);
32005
+ return this.applyIndexMetadata(index, currentHashes, newTreeHash);
32006
+ } catch (error48) {
32007
+ throw new Error(`AI analysis failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
32008
+ }
32004
32009
  }
32005
32010
  async getFileTree() {
32006
32011
  const gitmodulesPath = join3(this.projectPath, ".gitmodules");
@@ -32491,16 +32496,12 @@ class TaskExecutor {
32491
32496
  });
32492
32497
  try {
32493
32498
  let plan = null;
32494
- if (this.deps.skipPlanning) {
32495
- this.deps.log("Skipping Phase 1: Planning (CLI)...", "info");
32496
- } else {
32497
- this.deps.log("Phase 1: Planning (CLI)...", "info");
32498
- const planningPrompt = `${basePrompt}
32499
+ this.deps.log("Phase 1: Planning (CLI)...", "info");
32500
+ const planningPrompt = `${basePrompt}
32499
32501
 
32500
32502
  ## Phase 1: Planning
32501
32503
  Analyze and create a detailed plan for THIS SPECIFIC TASK. Do NOT execute changes yet.`;
32502
- plan = await this.deps.aiRunner.run(planningPrompt, true);
32503
- }
32504
+ plan = await this.deps.aiRunner.run(planningPrompt, true);
32504
32505
  this.deps.log("Starting Execution...", "info");
32505
32506
  let executionPrompt = basePrompt;
32506
32507
  if (plan != null) {
@@ -32558,7 +32559,15 @@ var colors = {
32558
32559
  brightBlue: `${ESC}94m`,
32559
32560
  brightMagenta: `${ESC}95m`,
32560
32561
  brightCyan: `${ESC}96m`,
32561
- brightWhite: `${ESC}97m`
32562
+ brightWhite: `${ESC}97m`,
32563
+ bgBlack: `${ESC}40m`,
32564
+ bgRed: `${ESC}41m`,
32565
+ bgGreen: `${ESC}42m`,
32566
+ bgYellow: `${ESC}43m`,
32567
+ bgBlue: `${ESC}44m`,
32568
+ bgMagenta: `${ESC}45m`,
32569
+ bgCyan: `${ESC}46m`,
32570
+ bgWhite: `${ESC}47m`
32562
32571
  };
32563
32572
  var c = {
32564
32573
  text: (text, ...colorNames) => {
@@ -32574,11 +32583,17 @@ var c = {
32574
32583
  magenta: (t) => c.text(t, "magenta"),
32575
32584
  cyan: (t) => c.text(t, "cyan"),
32576
32585
  gray: (t) => c.text(t, "gray"),
32586
+ white: (t) => c.text(t, "white"),
32587
+ brightBlue: (t) => c.text(t, "brightBlue"),
32588
+ bgBlue: (t) => c.text(t, "bgBlue", "white", "bold"),
32577
32589
  success: (t) => c.text(t, "green", "bold"),
32578
32590
  error: (t) => c.text(t, "red", "bold"),
32579
32591
  warning: (t) => c.text(t, "yellow", "bold"),
32580
32592
  info: (t) => c.text(t, "cyan", "bold"),
32581
32593
  primary: (t) => c.text(t, "blue", "bold"),
32594
+ secondary: (t) => c.text(t, "magenta", "bold"),
32595
+ header: (t) => c.text(` ${t} `, "bgBlue", "white", "bold"),
32596
+ step: (t) => c.text(` ${t} `, "bgCyan", "black", "bold"),
32582
32597
  underline: (t) => c.text(t, "underline")
32583
32598
  };
32584
32599
 
@@ -32636,6 +32651,7 @@ class ClaudeRunner {
32636
32651
  let finalResult = "";
32637
32652
  let errorOutput = "";
32638
32653
  let buffer = "";
32654
+ let stderrBuffer = "";
32639
32655
  claude.stdout.on("data", (data) => {
32640
32656
  buffer += data.toString();
32641
32657
  const lines = buffer.split(`
@@ -32648,14 +32664,27 @@ class ClaudeRunner {
32648
32664
  }
32649
32665
  });
32650
32666
  claude.stderr.on("data", (data) => {
32651
- const msg = data.toString();
32652
- errorOutput += msg;
32653
- process.stderr.write(msg);
32667
+ const chunk = data.toString();
32668
+ errorOutput += chunk;
32669
+ stderrBuffer += chunk;
32670
+ const lines = stderrBuffer.split(`
32671
+ `);
32672
+ stderrBuffer = lines.pop() || "";
32673
+ for (const line of lines) {
32674
+ if (!this.shouldSuppressLine(line)) {
32675
+ process.stderr.write(`${line}
32676
+ `);
32677
+ }
32678
+ }
32654
32679
  });
32655
32680
  claude.on("error", (err) => {
32656
32681
  reject(new Error(`Failed to start Claude CLI: ${err.message}. Please ensure the 'claude' command is available in your PATH.`));
32657
32682
  });
32658
32683
  claude.on("close", (code) => {
32684
+ if (stderrBuffer && !this.shouldSuppressLine(stderrBuffer)) {
32685
+ process.stderr.write(`${stderrBuffer}
32686
+ `);
32687
+ }
32659
32688
  process.stdout.write(`
32660
32689
  `);
32661
32690
  if (code === 0) {
@@ -32698,6 +32727,10 @@ ${c.primary("[Claude]")} ${c.bold(`Running ${content_block.name}...`)}
32698
32727
  }
32699
32728
  }
32700
32729
  }
32730
+ shouldSuppressLine(line) {
32731
+ const infoLogRegex = /^\[\d{2}:\d{2}:\d{2}\]\s\[.*?\]\sℹ\s*$/;
32732
+ return infoLogRegex.test(line.trim());
32733
+ }
32701
32734
  createExecutionError(code, detail) {
32702
32735
  const errorMsg = detail.trim();
32703
32736
  const message = errorMsg ? `Claude CLI error (exit code ${code}): ${errorMsg}` : `Claude CLI exited with code ${code}. Please ensure the Claude CLI is installed and you are logged in.`;
@@ -36264,7 +36297,15 @@ class BaseModule {
36264
36297
  // ../sdk/src/modules/ai.ts
36265
36298
  class AIModule extends BaseModule {
36266
36299
  async chat(workspaceId, body) {
36267
- const { data } = await this.api.post(`/ai/${workspaceId}/chat`, body);
36300
+ const { data } = await this.api.post(`/ai/${workspaceId}/chat`, body, { timeout: 300000 });
36301
+ return data;
36302
+ }
36303
+ async detectIntent(workspaceId, body) {
36304
+ const { data } = await this.api.post(`/ai/${workspaceId}/chat/intent`, body, { timeout: 300000 });
36305
+ return data;
36306
+ }
36307
+ async executeIntent(workspaceId, body) {
36308
+ const { data } = await this.api.post(`/ai/${workspaceId}/chat/execute`, body, { timeout: 300000 });
36268
36309
  return data;
36269
36310
  }
36270
36311
  async listSessions(workspaceId) {
@@ -36281,14 +36322,25 @@ class AIModule extends BaseModule {
36281
36322
  async deleteSession(workspaceId, sessionId) {
36282
36323
  await this.api.delete(`/ai/${workspaceId}/session/${sessionId}`);
36283
36324
  }
36325
+ async shareSession(workspaceId, sessionId, body) {
36326
+ await this.api.post(`/ai/${workspaceId}/session/${sessionId}/share`, body);
36327
+ }
36328
+ async getSharedSession(sessionId) {
36329
+ const { data } = await this.api.get(`/ai/shared/${sessionId}`);
36330
+ return data;
36331
+ }
36284
36332
  }
36285
36333
 
36286
36334
  // ../sdk/src/modules/auth.ts
36287
36335
  class AuthModule extends BaseModule {
36288
- async getMe() {
36336
+ async getProfile() {
36289
36337
  const { data } = await this.api.get("/auth/me");
36290
36338
  return data;
36291
36339
  }
36340
+ async getApiKeyInfo() {
36341
+ const { data } = await this.api.get("/auth/api-key");
36342
+ return data;
36343
+ }
36292
36344
  async requestRegisterOtp(email3) {
36293
36345
  const { data } = await this.api.post("/auth/register-otp", { email: email3 });
36294
36346
  return data;
@@ -36551,6 +36603,17 @@ class WorkspacesModule extends BaseModule {
36551
36603
  const { data } = await this.api.post(`/workspaces/${id}/dispatch`, { workerId, sprintId });
36552
36604
  return data.task;
36553
36605
  }
36606
+ async listApiKeys(workspaceId) {
36607
+ const { data } = await this.api.get(`/workspaces/${workspaceId}/api-keys`);
36608
+ return data.apiKeys;
36609
+ }
36610
+ async createApiKey(workspaceId, name) {
36611
+ const { data } = await this.api.post(`/workspaces/${workspaceId}/api-keys`, { name });
36612
+ return data.apiKey;
36613
+ }
36614
+ async deleteApiKey(workspaceId, keyId) {
36615
+ await this.api.delete(`/workspaces/${workspaceId}/api-keys/${keyId}`);
36616
+ }
36554
36617
  }
36555
36618
 
36556
36619
  // ../sdk/src/index.ts
@@ -36704,7 +36767,6 @@ class AgentWorker {
36704
36767
  this.taskExecutor = new TaskExecutor({
36705
36768
  aiRunner: this.aiRunner,
36706
36769
  projectPath,
36707
- skipPlanning: config2.skipPlanning,
36708
36770
  log
36709
36771
  });
36710
36772
  const providerLabel = provider === "codex" ? "Codex" : "Claude";
@@ -36835,8 +36897,7 @@ if (process.argv[1]?.includes("agent-worker") || process.argv[1]?.includes("work
36835
36897
  if (value && !value.startsWith("--"))
36836
36898
  i++;
36837
36899
  config2.provider = resolveProvider(value);
36838
- } else if (arg === "--skip-planning")
36839
- config2.skipPlanning = true;
36900
+ }
36840
36901
  }
36841
36902
  if (!config2.agentId || !config2.workspaceId || !config2.apiBase || !config2.apiKey || !config2.projectPath) {
36842
36903
  console.error("Missing required arguments");
@@ -36970,9 +37031,6 @@ ${c.success("✅ Orchestrator finished")}`);
36970
37031
  if (this.config.provider) {
36971
37032
  workerArgs.push("--provider", this.config.provider);
36972
37033
  }
36973
- if (this.config.skipPlanning) {
36974
- workerArgs.push("--skip-planning");
36975
- }
36976
37034
  if (this.resolvedSprintId) {
36977
37035
  workerArgs.push("--sprint-id", this.resolvedSprintId);
36978
37036
  }
@@ -37477,10 +37535,23 @@ class ConfigManager {
37477
37535
  const config2 = this.loadConfig();
37478
37536
  if (config2 && config2.version !== version2) {
37479
37537
  config2.version = version2;
37480
- const path2 = getLocusPath(this.projectPath, "configFile");
37481
- writeFileSync3(path2, JSON.stringify(config2, null, 2));
37538
+ this.saveConfig(config2);
37482
37539
  }
37483
37540
  }
37541
+ getWorkspaceId() {
37542
+ return this.loadConfig()?.workspaceId;
37543
+ }
37544
+ setWorkspaceId(workspaceId) {
37545
+ const config2 = this.loadConfig();
37546
+ if (config2) {
37547
+ config2.workspaceId = workspaceId;
37548
+ this.saveConfig(config2);
37549
+ }
37550
+ }
37551
+ saveConfig(config2) {
37552
+ const path2 = getLocusPath(this.projectPath, "configFile");
37553
+ writeFileSync3(path2, JSON.stringify(config2, null, 2));
37554
+ }
37484
37555
  }
37485
37556
 
37486
37557
  // src/tree-summarizer.ts
@@ -37507,6 +37578,41 @@ ${tree}`;
37507
37578
  }
37508
37579
  }
37509
37580
 
37581
+ // src/workspace-resolver.ts
37582
+ class WorkspaceResolver {
37583
+ configManager;
37584
+ options;
37585
+ constructor(configManager, options) {
37586
+ this.configManager = configManager;
37587
+ this.options = options;
37588
+ }
37589
+ async resolve() {
37590
+ if (this.options.workspaceId) {
37591
+ return this.options.workspaceId;
37592
+ }
37593
+ const persistedId = this.configManager.getWorkspaceId();
37594
+ if (persistedId) {
37595
+ return persistedId;
37596
+ }
37597
+ try {
37598
+ console.log(c.dim("ℹ Resolving workspace from API key..."));
37599
+ const client = new LocusClient({
37600
+ baseUrl: this.options.apiBase,
37601
+ token: this.options.apiKey
37602
+ });
37603
+ const info = await client.auth.getApiKeyInfo();
37604
+ if (info.workspaceId) {
37605
+ this.configManager.setWorkspaceId(info.workspaceId);
37606
+ console.log(c.success(`✓ Resolved workspace: ${info.workspaceId}`));
37607
+ return info.workspaceId;
37608
+ }
37609
+ throw new Error("API key is not associated with a workspace. Please specify --workspace.");
37610
+ } catch (error48) {
37611
+ throw new Error(`Error resolving workspace: ${error48 instanceof Error ? error48.message : String(error48)}`);
37612
+ }
37613
+ }
37614
+ }
37615
+
37510
37616
  // src/cli.ts
37511
37617
  function getVersion() {
37512
37618
  try {
@@ -37523,12 +37629,12 @@ function getVersion() {
37523
37629
  var VERSION2 = getVersion();
37524
37630
  function printBanner() {
37525
37631
  console.log(c.primary(`
37526
- ## ###### ###### ## ## ######
37527
- ## ## ## ## ## ## ##
37528
- ## ## ## ## ## ## ######
37529
- ## ## ## ## ## ## ##
37530
- ####### ###### ###### ###### ###### v${VERSION2}
37531
- `));
37632
+ _ ____ ____ _ _ ____
37633
+ | | / __ \\ / ___| | | |/ ___|
37634
+ | | | | | | | | | | |\\___ \\
37635
+ | |___| |__| | |___| |_| |___) |
37636
+ |_____|\\____/ \\____|\\___/|____/ ${c.dim(`v${VERSION2}`)}
37637
+ `));
37532
37638
  }
37533
37639
  function isProjectInitialized(projectPath) {
37534
37640
  const locusDir = join8(projectPath, LOCUS_CONFIG.dir);
@@ -37538,14 +37644,14 @@ function isProjectInitialized(projectPath) {
37538
37644
  function requireInitialization(projectPath, command) {
37539
37645
  if (!isProjectInitialized(projectPath)) {
37540
37646
  console.error(`
37541
- ${c.error(" Error: Locus is not initialized in this directory.")}
37647
+ ${c.error(" Error")} ${c.red(`Locus is not initialized in this directory.`)}
37542
37648
 
37543
- The '${c.bold(command)}' command requires a Locus project to be initialized.
37649
+ The '${c.bold(command)}' command requires a Locus project to be initialized.
37544
37650
 
37545
- To initialize Locus in this directory, run:
37546
- ${c.primary("locus init")}
37651
+ To initialize Locus in this directory, run:
37652
+ ${c.primary("locus init")}
37547
37653
 
37548
- This will create a .locus directory with the necessary configuration.
37654
+ This will create a ${c.dim(".locus")} directory with the necessary configuration.
37549
37655
  `);
37550
37656
  process.exit(1);
37551
37657
  }
@@ -37575,13 +37681,27 @@ async function runCommand(args) {
37575
37681
  });
37576
37682
  const projectPath = values.dir || process.cwd();
37577
37683
  requireInitialization(projectPath, "run");
37578
- new ConfigManager(projectPath).updateVersion(VERSION2);
37684
+ const configManager = new ConfigManager(projectPath);
37685
+ configManager.updateVersion(VERSION2);
37579
37686
  const apiKey = values["api-key"];
37580
- const workspaceId = values.workspace;
37687
+ let workspaceId = values.workspace;
37581
37688
  const provider = resolveProvider2(values.provider);
37582
37689
  const model = values.model || DEFAULT_MODEL[provider];
37583
- if (!apiKey || !workspaceId) {
37584
- console.error(c.error("Error: --api-key and --workspace are required"));
37690
+ const apiBase = values["api-url"] || "https://api.locusai.dev/api";
37691
+ if (!apiKey) {
37692
+ console.error(c.error("Error: --api-key is required"));
37693
+ console.error(c.dim("You can create an API key in Workspace Settings > API Keys"));
37694
+ process.exit(1);
37695
+ }
37696
+ try {
37697
+ const resolver = new WorkspaceResolver(configManager, {
37698
+ apiKey,
37699
+ apiBase,
37700
+ workspaceId: values.workspace
37701
+ });
37702
+ workspaceId = await resolver.resolve();
37703
+ } catch (error48) {
37704
+ console.error(c.error(error48 instanceof Error ? error48.message : String(error48)));
37585
37705
  process.exit(1);
37586
37706
  }
37587
37707
  const orchestrator = new AgentOrchestrator({
@@ -37589,15 +37709,14 @@ async function runCommand(args) {
37589
37709
  sprintId: values.sprint || "",
37590
37710
  model,
37591
37711
  provider,
37592
- apiBase: values["api-url"] || "https://api.locusai.dev/api",
37712
+ apiBase,
37593
37713
  maxIterations: 100,
37594
37714
  projectPath,
37595
- apiKey,
37596
- skipPlanning: Boolean(values["skip-planning"])
37715
+ apiKey
37597
37716
  });
37598
- orchestrator.on("task:assigned", (data) => console.log(`ℹ [CLAIMED] ${data.title}`));
37599
- orchestrator.on("task:completed", (data) => console.log(`✓ [COMPLETED] ${data.taskId}`));
37600
- orchestrator.on("task:failed", (data) => console.log(`✗ [FAILED] ${data.taskId}: ${data.error}`));
37717
+ orchestrator.on("task:assigned", (data) => console.log(` ${c.info("●")} ${c.bold("Claimed:")} ${data.title}`));
37718
+ orchestrator.on("task:completed", (data) => console.log(` ${c.success("✔")} ${c.success("Completed:")} ${c.dim(data.taskId)}`));
37719
+ orchestrator.on("task:failed", (data) => console.log(` ${c.error("✖")} ${c.error("Failed:")} ${c.bold(data.taskId)}: ${data.error}`));
37601
37720
  const handleSignal = async (signal) => {
37602
37721
  console.log(`
37603
37722
  ${c.info(`Received ${signal}. Stopping agents...`)}`);
@@ -37606,7 +37725,8 @@ ${c.info(`Received ${signal}. Stopping agents...`)}`);
37606
37725
  };
37607
37726
  process.on("SIGINT", () => handleSignal("SIGINT"));
37608
37727
  process.on("SIGTERM", () => handleSignal("SIGTERM"));
37609
- console.log(`${c.primary("\uD83D\uDE80 Starting agent in")} ${c.bold(projectPath)}...`);
37728
+ console.log(`
37729
+ ${c.primary("\uD83D\uDE80")} ${c.bold("Starting Locus agent in")} ${c.primary(projectPath)}...`);
37610
37730
  await orchestrator.start();
37611
37731
  }
37612
37732
  async function indexCommand(args) {
@@ -37630,12 +37750,22 @@ async function indexCommand(args) {
37630
37750
  });
37631
37751
  const summarizer = new TreeSummarizer(aiRunner);
37632
37752
  const indexer = new CodebaseIndexer(projectPath);
37633
- console.log(`${c.primary("\uD83D\uDD0D Indexing codebase in")} ${c.bold(projectPath)}...`);
37634
- const index = await indexer.index((msg) => console.log(` ${c.dim(msg)}`), (tree) => summarizer.summarize(tree));
37635
- if (index) {
37636
- indexer.saveIndex(index);
37753
+ console.log(`
37754
+ ${c.step(" INDEX ")} ${c.primary("Analyzing codebase in")} ${c.bold(projectPath)}...`);
37755
+ try {
37756
+ const index = await indexer.index((msg) => console.log(` ${c.dim(msg)}`), (tree) => summarizer.summarize(tree));
37757
+ if (index) {
37758
+ indexer.saveIndex(index);
37759
+ }
37760
+ } catch (error48) {
37761
+ console.error(`
37762
+ ${c.error("✖")} ${c.error("Indexing failed:")} ${c.red(error48 instanceof Error ? error48.message : String(error48))}`);
37763
+ console.error(c.dim(` The agent might have limited context until indexing succeeds.
37764
+ `));
37637
37765
  }
37638
- console.log(c.success("✅ Indexing complete!"));
37766
+ console.log(`
37767
+ ${c.success("✔")} ${c.success("Indexing complete!")}
37768
+ `);
37639
37769
  }
37640
37770
  async function initCommand() {
37641
37771
  const projectPath = process.cwd();
@@ -37651,19 +37781,19 @@ If you want to reinitialize, please remove the .locus directory first.
37651
37781
  }
37652
37782
  await new ConfigManager(projectPath).init(VERSION2);
37653
37783
  console.log(`
37654
- ${c.success("✨ Locus initialized successfully!")}
37784
+ ${c.success("✨ Locus initialized successfully!")}
37655
37785
 
37656
- Created:
37657
- \uD83D\uDCC1 ${c.dim(".locus/")} - Locus configuration directory
37658
- \uD83D\uDCC4 ${c.dim(".locus/config.json")} - Project configuration
37659
- \uD83D\uDCDD ${c.dim("CLAUDE.md")} - AI context file
37660
- \uD83D\uDCC1 ${c.dim(".agent/skills/")} - Agent skills (Frontend, Backend, DevOps, etc.)
37786
+ ${c.bold("Created:")}
37787
+ ${c.primary("\uD83D\uDCC1")} ${c.bold(".locus/")} ${c.dim("Configuration directory")}
37788
+ ${c.primary("\uD83D\uDCC4")} ${c.bold(".locus/config.json")} ${c.dim("Project settings")}
37789
+ ${c.primary("\uD83D\uDCDD")} ${c.bold("CLAUDE.md")} ${c.dim("AI instructions & context")}
37790
+ ${c.primary("\uD83D\uDCC1")} ${c.bold(".agent/skills/")} ${c.dim("Domain-specific agent skills")}
37661
37791
 
37662
- Next steps:
37663
- 1. Run '${c.primary("locus index")}' to index your codebase
37664
- 2. Run '${c.primary("locus run")}' to start an agent (requires --api-key and --workspace)
37792
+ ${c.bold("Next steps:")}
37793
+ 1. Run '${c.primary("locus index")}' to index your codebase
37794
+ 2. Run '${c.primary("locus run")}' to start an agent (requires --api-key)
37665
37795
 
37666
- For more information, visit: ${c.underline("https://locusai.dev/docs")}
37796
+ For more information, visit: ${c.underline("https://locusai.dev/docs")}
37667
37797
  `);
37668
37798
  }
37669
37799
  async function main() {
@@ -37682,28 +37812,29 @@ async function main() {
37682
37812
  break;
37683
37813
  default:
37684
37814
  console.log(`
37685
- Usage: locus <command>
37815
+ ${c.header(" USAGE ")}
37816
+ ${c.primary("locus")} ${c.dim("<command> [options]")}
37686
37817
 
37687
- Commands:
37688
- init Initialize Locus in the current directory
37689
- index Index the codebase for AI context
37690
- run Start an agent to work on tasks
37818
+ ${c.header(" COMMANDS ")}
37819
+ ${c.success("init")} Initialize Locus in the current directory
37820
+ ${c.success("index")} Index the codebase for AI context
37821
+ ${c.success("run")} Start an agent to work on tasks
37691
37822
 
37692
- Options:
37693
- --help Show this help message
37694
- --provider <name> AI provider: claude or codex (default: claude)
37695
- --skip-planning Skip the planning phase (CLI planning)
37823
+ ${c.header(" OPTIONS ")}
37824
+ ${c.secondary("--help")} Show this help message
37825
+ ${c.secondary("--provider")} <name> AI provider: ${c.dim("claude")} or ${c.dim("codex")} (default: ${c.dim("claude")})
37696
37826
 
37697
- Examples:
37698
- locus init
37699
- locus index
37700
- locus run --api-key YOUR_KEY --workspace WORKSPACE_ID
37827
+ ${c.header(" EXAMPLES ")}
37828
+ ${c.dim("$")} ${c.primary("locus init")}
37829
+ ${c.dim("$")} ${c.primary("locus index")}
37830
+ ${c.dim("$")} ${c.primary("locus run --api-key YOUR_KEY")}
37701
37831
 
37702
- For more information, visit: https://locusai.dev/docs
37832
+ For more information, visit: ${c.underline("https://locusai.dev/docs")}
37703
37833
  `);
37704
37834
  }
37705
37835
  }
37706
37836
  main().catch((err) => {
37707
- console.error(`Fatal error: ${err.message}`);
37837
+ console.error(`
37838
+ ${c.error("✖ Fatal Error")} ${c.red(err.message)}`);
37708
37839
  process.exit(1);
37709
37840
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/cli",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "CLI for Locus - AI-native project management platform",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,7 +32,7 @@
32
32
  "author": "",
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
- "@locusai/sdk": "^0.6.0"
35
+ "@locusai/sdk": "^0.7.1"
36
36
  },
37
37
  "devDependencies": {}
38
38
  }