@locusai/cli 0.21.0 → 0.21.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.
- package/README.md +194 -0
- package/bin/locus.js +18 -26
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
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> · <a href="https://docs.locusai.dev/getting-started/quickstart">Quick Start</a> · <a href="https://github.com/asgarovf/locusai">GitHub</a> · <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
|
+
## VS Code Extension
|
|
185
|
+
|
|
186
|
+
Locus includes a [VS Code extension](https://marketplace.visualstudio.com/items?itemName=locusai.locus) with an integrated chat interface for running tasks directly from your editor.
|
|
187
|
+
|
|
188
|
+
## Documentation
|
|
189
|
+
|
|
190
|
+
Full documentation is available at [docs.locusai.dev](https://docs.locusai.dev).
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
[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
|
|
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,
|
|
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 {
|
|
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
|
|
6411
|
-
|
|
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: `${
|
|
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
|
});
|