@locusai/cli 0.21.0 → 0.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +190 -0
  2. package/bin/locus.js +18 -26
  3. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,190 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/asgarovf/locusai/master/assets/logo.png" alt="Locus" width="200" />
3
+ </p>
4
+
5
+ <h3 align="center">GitHub-native AI engineering CLI</h3>
6
+
7
+ <p align="center">
8
+ Turn GitHub issues into shipped code — plan sprints, execute tasks with AI agents, and iterate on feedback.
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://github.com/asgarovf/locusai/stargazers"><img src="https://img.shields.io/github/stars/asgarovf/locusai?style=flat&color=blue" alt="GitHub Stars" /></a>
13
+ <a href="https://www.npmjs.com/package/@locusai/cli"><img src="https://img.shields.io/npm/v/@locusai/cli?label=%40locusai%2Fcli&color=blue" alt="@locusai/cli" /></a>
14
+ <a href="https://github.com/asgarovf/locusai/blob/master/LICENSE"><img src="https://img.shields.io/github/license/asgarovf/locusai?style=flat&color=blue" alt="License" /></a>
15
+ <a href="https://docs.locusai.dev"><img src="https://img.shields.io/badge/docs-locusai.dev-blue" alt="Documentation" /></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="https://docs.locusai.dev">Documentation</a> &middot; <a href="https://docs.locusai.dev/getting-started/quickstart">Quick Start</a> &middot; <a href="https://github.com/asgarovf/locusai">GitHub</a> &middot; <a href="https://github.com/asgarovf/locusai/issues">Issues</a>
20
+ </p>
21
+
22
+ ---
23
+
24
+ > GitHub Issues are tasks. Milestones are sprints. Labels track status. Pull Requests are deliverables. **No servers. No database. No accounts.**
25
+
26
+ ## Prerequisites
27
+
28
+ - [Node.js](https://nodejs.org) 18+
29
+ - [GitHub CLI](https://cli.github.com) (`gh`) — authenticated via `gh auth login`
30
+ - An AI provider CLI: [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview) or [Codex](https://openai.com/index/introducing-codex/)
31
+ - [Docker Desktop](https://www.docker.com/products/docker-desktop/) 4.58+ for sandboxed execution (optional)
32
+
33
+ ## Install
34
+
35
+ ```bash
36
+ npm install -g @locusai/cli
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ```bash
42
+ # Initialize in your GitHub repo
43
+ locus init
44
+
45
+ # Plan a sprint from a goal
46
+ locus plan "Build user authentication with OAuth"
47
+
48
+ # Execute the sprint — agents write code, push commits, open PRs
49
+ locus run
50
+
51
+ # Review the PRs with AI
52
+ locus review
53
+
54
+ # Agents address feedback and update the PRs
55
+ locus iterate
56
+ ```
57
+
58
+ ## How It Works
59
+
60
+ ```
61
+ locus plan "your goal" → AI breaks the goal into GitHub Issues with execution order
62
+ locus run → Agents execute tasks sequentially, push code, create PRs
63
+ locus review → AI reviews PRs, posts inline comments on GitHub
64
+ locus iterate → Agents address review feedback until ready to merge
65
+ ```
66
+
67
+ **GitHub IS the backend:**
68
+
69
+ | Concept | GitHub Primitive |
70
+ |---------|-----------------|
71
+ | Task | Issue |
72
+ | Sprint | Milestone |
73
+ | Status | Labels (`locus:queued`, `locus:in-progress`, `locus:done`, `locus:failed`) |
74
+ | Priority | Labels (`p:critical`, `p:high`, `p:medium`, `p:low`) |
75
+ | Execution Order | Labels (`order:1`, `order:2`, ...) |
76
+ | Deliverable | Pull Request |
77
+
78
+ ## CLI Reference
79
+
80
+ ### Setup & Configuration
81
+
82
+ | Command | Description |
83
+ |---------|-------------|
84
+ | `locus init` | Initialize project with `.locus/` structure and GitHub labels |
85
+ | `locus config` | View and manage settings |
86
+ | `locus upgrade` | Self-upgrade to latest version |
87
+
88
+ ### Work Modeling
89
+
90
+ | Command | Alias | Description |
91
+ |---------|-------|-------------|
92
+ | `locus issue` | `locus i` | Create, list, show, label, and close GitHub issues |
93
+ | `locus sprint` | `locus s` | Create, list, show, activate, reorder, and close sprints |
94
+ | `locus plan` | | AI-powered sprint planning from a goal description |
95
+
96
+ ### Execution & Review
97
+
98
+ | Command | Alias | Description |
99
+ |---------|-------|-------------|
100
+ | `locus run` | | Execute sprint tasks or standalone issues with AI agents |
101
+ | `locus exec` | `locus e` | Interactive REPL or one-shot prompt execution |
102
+ | `locus review` | | AI code review on pull requests |
103
+ | `locus iterate` | | Re-execute tasks with PR feedback context |
104
+ | `locus discuss` | | AI-powered architectural discussions |
105
+
106
+ ### Visibility
107
+
108
+ | Command | Description |
109
+ |---------|-------------|
110
+ | `locus status` | Dashboard view of project state |
111
+ | `locus logs` | View, tail, and manage execution logs |
112
+ | `locus artifacts` | View and manage AI-generated artifacts |
113
+
114
+ ### Packages
115
+
116
+ | Command | Description |
117
+ |---------|-------------|
118
+ | `locus install` | Install a community package from npm |
119
+ | `locus uninstall` | Remove an installed package |
120
+ | `locus packages` | List installed packages |
121
+ | `locus pkg <name>` | Run a package-provided command |
122
+
123
+ ### Sandbox Management
124
+
125
+ | Command | Description |
126
+ |---------|-------------|
127
+ | `locus sandbox` | Create provider sandboxes and enable sandbox mode |
128
+ | `locus sandbox claude` | Authenticate Claude inside its sandbox |
129
+ | `locus sandbox codex` | Authenticate Codex inside its sandbox |
130
+ | `locus sandbox install <pkg>` | Install global npm package(s) in provider sandbox(s) |
131
+ | `locus sandbox shell <provider>` | Open an interactive shell in a provider sandbox |
132
+ | `locus sandbox logs <provider>` | Show provider sandbox logs |
133
+ | `locus sandbox rm` | Destroy provider sandboxes and disable sandbox mode |
134
+ | `locus sandbox status` | Show current sandbox state |
135
+
136
+ ## Workflows
137
+
138
+ ### Sprint: plan, execute, review, iterate
139
+
140
+ ```bash
141
+ locus plan "Add SSO login and role-based access"
142
+ locus run
143
+ locus review
144
+ locus iterate --sprint
145
+ ```
146
+
147
+ ### Parallel standalone issues
148
+
149
+ ```bash
150
+ # Run 3 independent issues concurrently
151
+ locus run 42 43 44
152
+ ```
153
+
154
+ ### Resume a failed run
155
+
156
+ ```bash
157
+ # Pick up where it left off — completed tasks are skipped
158
+ locus run --resume
159
+ ```
160
+
161
+ ### Interactive coding session
162
+
163
+ ```bash
164
+ # Start a REPL session
165
+ locus exec
166
+
167
+ # Or one-shot
168
+ locus exec "Refactor the auth middleware to use JWT"
169
+ ```
170
+
171
+ ## Key Flags
172
+
173
+ | Flag | Description |
174
+ |------|-------------|
175
+ | `-d, --debug` | Debug logging |
176
+ | `-h, --help` | Show help |
177
+ | `-V, --version` | Show version |
178
+ | `--dry-run` | Simulate without executing |
179
+ | `--model <name>` | Override AI model |
180
+ | `--resume` | Resume interrupted runs |
181
+ | `--no-sandbox` | Disable Docker isolation |
182
+ | `--sandbox=require` | Require Docker (fail if unavailable) |
183
+
184
+ ## Documentation
185
+
186
+ Full documentation is available at [docs.locusai.dev](https://docs.locusai.dev).
187
+
188
+ ## License
189
+
190
+ [MIT](https://github.com/asgarovf/locusai/blob/master/LICENSE)
package/bin/locus.js CHANGED
@@ -34,7 +34,7 @@ function inferProviderFromModel(model) {
34
34
  return "codex";
35
35
  return;
36
36
  }
37
- var CLAUDE_MODELS, CODEX_MODELS, CLAUDE_MODEL_SET, CODEX_MODEL_SET, ALL_MODEL_SET;
37
+ var CLAUDE_MODELS, CODEX_MODELS, CLAUDE_MODEL_SET, CODEX_MODEL_SET;
38
38
  var init_ai_models = __esm(() => {
39
39
  CLAUDE_MODELS = [
40
40
  "opus",
@@ -59,7 +59,6 @@ var init_ai_models = __esm(() => {
59
59
  ];
60
60
  CLAUDE_MODEL_SET = new Set(CLAUDE_MODELS);
61
61
  CODEX_MODEL_SET = new Set(CODEX_MODELS);
62
- ALL_MODEL_SET = new Set([...CLAUDE_MODELS, ...CODEX_MODELS]);
63
62
  });
64
63
 
65
64
  // src/core/config.ts
@@ -280,13 +279,12 @@ function drawBox(lines, options) {
280
279
  return parts.join(`
281
280
  `);
282
281
  }
283
- var cachedCapabilities = null, enabled = () => getCapabilities().colorBasic, bold, dim, italic, underline, strikethrough, red, green, yellow, blue, magenta, cyan, white, gray, redBright, greenBright, yellowBright, blueBright, magentaBright, cyanBright, bgRed, bgGreen, bgYellow, bgBlue, bgGray, box;
282
+ var cachedCapabilities = null, enabled = () => getCapabilities().colorBasic, bold, dim, italic, underline, red, green, yellow, blue, magenta, cyan, white, gray, box;
284
283
  var init_terminal = __esm(() => {
285
284
  bold = wrap("\x1B[1m", "\x1B[22m");
286
285
  dim = wrap("\x1B[2m", "\x1B[22m");
287
286
  italic = wrap("\x1B[3m", "\x1B[23m");
288
287
  underline = wrap("\x1B[4m", "\x1B[24m");
289
- strikethrough = wrap("\x1B[9m", "\x1B[29m");
290
288
  red = wrap("\x1B[31m", "\x1B[39m");
291
289
  green = wrap("\x1B[32m", "\x1B[39m");
292
290
  yellow = wrap("\x1B[33m", "\x1B[39m");
@@ -295,17 +293,6 @@ var init_terminal = __esm(() => {
295
293
  cyan = wrap("\x1B[36m", "\x1B[39m");
296
294
  white = wrap("\x1B[37m", "\x1B[39m");
297
295
  gray = wrap("\x1B[90m", "\x1B[39m");
298
- redBright = wrap("\x1B[91m", "\x1B[39m");
299
- greenBright = wrap("\x1B[92m", "\x1B[39m");
300
- yellowBright = wrap("\x1B[93m", "\x1B[39m");
301
- blueBright = wrap("\x1B[94m", "\x1B[39m");
302
- magentaBright = wrap("\x1B[95m", "\x1B[39m");
303
- cyanBright = wrap("\x1B[96m", "\x1B[39m");
304
- bgRed = wrap("\x1B[41m", "\x1B[49m");
305
- bgGreen = wrap("\x1B[42m", "\x1B[49m");
306
- bgYellow = wrap("\x1B[43m", "\x1B[49m");
307
- bgBlue = wrap("\x1B[44m", "\x1B[49m");
308
- bgGray = wrap("\x1B[100m", "\x1B[49m");
309
296
  box = {
310
297
  topLeft: "┌",
311
298
  topRight: "┐",
@@ -783,12 +770,17 @@ var exports_progress = {};
783
770
  __export(exports_progress, {
784
771
  renderTaskStatus: () => renderTaskStatus,
785
772
  progressBar: () => progressBar,
786
- formatDuration: () => formatDuration,
787
773
  createTimer: () => createTimer,
788
774
  Spinner: () => Spinner
789
775
  });
790
776
  function progressBar(current, total, options = {}) {
791
- const { width = 30, showPercent = true, showCount = true, label } = options;
777
+ const {
778
+ width = 30,
779
+ showPercent = true,
780
+ showCount = true,
781
+ brackets = true,
782
+ label
783
+ } = options;
792
784
  const percent = total > 0 ? current / total : 0;
793
785
  const filled = Math.round(width * percent);
794
786
  const empty = width - filled;
@@ -796,7 +788,7 @@ function progressBar(current, total, options = {}) {
796
788
  const parts = [];
797
789
  if (label)
798
790
  parts.push(label);
799
- parts.push(`[${bar}]`);
791
+ parts.push(brackets ? `[${bar}]` : bar);
800
792
  if (showPercent)
801
793
  parts.push(bold(`${Math.round(percent * 100)}%`));
802
794
  if (showCount)
@@ -6407,8 +6399,12 @@ async function sprintList(projectRoot, parsed) {
6407
6399
  const total = open + closed;
6408
6400
  if (total === 0)
6409
6401
  return dim("no issues");
6410
- const pct = Math.round(closed / total * 100);
6411
- const bar = progressBar2(pct, 10);
6402
+ const bar = progressBar(closed, total, {
6403
+ width: 10,
6404
+ brackets: false,
6405
+ showPercent: false,
6406
+ showCount: false
6407
+ });
6412
6408
  return `${bar} ${dim(`${closed}/${total}`)}`;
6413
6409
  }
6414
6410
  },
@@ -6501,7 +6497,7 @@ ${bold(`Sprint: ${milestone.title}`)} ${dim(`(${milestone.state})`)}
6501
6497
  const details = renderDetails([
6502
6498
  {
6503
6499
  label: "Progress",
6504
- value: `${progressBar2(pct, 20)} ${bold(`${pct}%`)} ${dim(`(${milestone.closedIssues}/${total} tasks)`)}`
6500
+ value: `${progressBar(milestone.closedIssues, total, { width: 20, brackets: false, showPercent: false, showCount: false })} ${bold(`${pct}%`)} ${dim(`(${milestone.closedIssues}/${total} tasks)`)}`
6505
6501
  },
6506
6502
  {
6507
6503
  label: "Due",
@@ -6847,11 +6843,6 @@ function formatStatus2(labels) {
6847
6843
  }
6848
6844
  return dim("—");
6849
6845
  }
6850
- function progressBar2(percent, width) {
6851
- const filled = Math.round(percent / 100 * width);
6852
- const empty = width - filled;
6853
- return green("█".repeat(filled)) + dim("░".repeat(empty));
6854
- }
6855
6846
  function printSprintHelp() {
6856
6847
  process.stderr.write(`
6857
6848
  ${bold("locus sprint")} — Manage sprints via GitHub Milestones
@@ -6889,6 +6880,7 @@ var init_sprint = __esm(() => {
6889
6880
  init_config();
6890
6881
  init_github();
6891
6882
  init_logger();
6883
+ init_progress();
6892
6884
  init_table();
6893
6885
  init_terminal();
6894
6886
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/cli",
3
- "version": "0.21.0",
3
+ "version": "0.21.2",
4
4
  "description": "GitHub-native AI engineering assistant",
5
5
  "type": "module",
6
6
  "bin": {