@sixseven-ai/cli 0.1.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 +143 -0
- package/USAGE.md +94 -0
- package/dist/api.js +181 -0
- package/dist/api.js.map +1 -0
- package/dist/bin.js +86 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/doctor.js +90 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.js +97 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.js +42 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/setup.js +185 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/status.js +36 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/config.js +125 -0
- package/dist/config.js.map +1 -0
- package/dist/mcp/server.js +561 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/source-reader.js +200 -0
- package/dist/source-reader.js.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# @sixseven-ai/cli
|
|
2
|
+
|
|
3
|
+
One install, two roles:
|
|
4
|
+
|
|
5
|
+
- **You** use `sixseven` from the terminal to log in and bind a repo to a SixSeven project.
|
|
6
|
+
- **Claude Code (or Cursor / Claude Desktop)** uses `sixseven mcp` behind the scenes to read your source code, author whitebox testcases, run them, and read evidence — all without leaving the repo.
|
|
7
|
+
|
|
8
|
+
Same binary, same token, same project binding.
|
|
9
|
+
|
|
10
|
+
## Quick start
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Install
|
|
14
|
+
npm i -g @sixseven-ai/cli # once published
|
|
15
|
+
# or, in this workspace:
|
|
16
|
+
pnpm -C packages/cli install && pnpm -C packages/cli build
|
|
17
|
+
|
|
18
|
+
# Get a CI token from the SixSeven UI:
|
|
19
|
+
# project → CI Tokens → Create (token starts with 67ci_)
|
|
20
|
+
|
|
21
|
+
# Then, from your app's repo:
|
|
22
|
+
cd /path/to/your/app
|
|
23
|
+
sixseven setup
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`sixseven setup` is a 3-step wizard that:
|
|
27
|
+
|
|
28
|
+
1. **Logs you in** — prompts for SixSeven base URL + CI token, verifies it, saves to `~/.sixseven/credentials` (mode `0600`). Skips this step if a valid token is already saved.
|
|
29
|
+
2. **Binds the repo** — lists your projects, pick one, writes `.sixseven/config.json`. Skips if a binding already exists (asks before re-binding).
|
|
30
|
+
3. **Registers the MCP server** — if the `claude` CLI is on your PATH, runs `claude mcp add sixseven -- sixseven mcp` for you. Otherwise prints copy-paste JSON for Cursor (`.cursor/mcp.json`) or Claude Desktop.
|
|
31
|
+
|
|
32
|
+
That's it. Open Claude Code and ask *"list sixseven features"* to confirm.
|
|
33
|
+
|
|
34
|
+
> **Workspace dev?** If you haven't installed globally, the wizard auto-detects and uses the absolute path (`node /abs/path/dist/bin.js mcp`) so the MCP registration still works.
|
|
35
|
+
|
|
36
|
+
## Commands
|
|
37
|
+
|
|
38
|
+
| Command | What |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `sixseven setup` | **Guided wizard — start here.** Login → bind project → register MCP. |
|
|
41
|
+
| `sixseven login` | Just the login step (saves token to `~/.sixseven/credentials`) |
|
|
42
|
+
| `sixseven init` | Just the bind step (writes `.sixseven/config.json`) |
|
|
43
|
+
| `sixseven status` | Show binding + token validity + feature/testcase counts |
|
|
44
|
+
| `sixseven doctor` | Diagnose config, token, backend reachability, project access |
|
|
45
|
+
| `sixseven mcp` | Start MCP server on stdio (spawned by Claude Code; you don't run this directly) |
|
|
46
|
+
|
|
47
|
+
### Advanced: manual MCP registration
|
|
48
|
+
|
|
49
|
+
If you skipped the wizard's MCP step:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Claude Code
|
|
53
|
+
claude mcp add sixseven -- sixseven mcp
|
|
54
|
+
|
|
55
|
+
# Cursor — add to .cursor/mcp.json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"sixseven": { "command": "sixseven", "args": ["mcp"] }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## MCP tools exposed
|
|
64
|
+
|
|
65
|
+
**Whitebox (source code)**
|
|
66
|
+
|
|
67
|
+
| Tool | Purpose |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `sixseven.read_code` | Read a text file inside configured `codeRoots` |
|
|
70
|
+
| `sixseven.list_dir` | List a directory inside the repo |
|
|
71
|
+
| `sixseven.search_code` | Substring/regex search across `codeRoots` (≤200 hits) |
|
|
72
|
+
|
|
73
|
+
**Features & testcases**
|
|
74
|
+
|
|
75
|
+
| Tool | Purpose |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `sixseven.list_features` | List features of the bound SixSeven project |
|
|
78
|
+
| `sixseven.create_feature` | Create a feature (group of testcases) |
|
|
79
|
+
| `sixseven.list_testcases` | List testcases (optionally per platform) |
|
|
80
|
+
| `sixseven.get_testcase` | Fetch a testcase by id |
|
|
81
|
+
| `sixseven.create_testcase` | Push a new testcase to a feature |
|
|
82
|
+
| `sixseven.update_testcase` | Patch an existing testcase |
|
|
83
|
+
|
|
84
|
+
**Runs, execution, and evidence**
|
|
85
|
+
|
|
86
|
+
| Tool | Purpose |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `sixseven.list_runs` | List recent runs for the bound project |
|
|
89
|
+
| `sixseven.create_run` | Create a run for one or more testcases |
|
|
90
|
+
| `sixseven.execute_run` | Trigger execution (fire-and-forget, 202) |
|
|
91
|
+
| `sixseven.get_run` | Get current run state (status, reportUrl, timestamps) |
|
|
92
|
+
| `sixseven.cancel_run` | Cancel an in-flight run |
|
|
93
|
+
| `sixseven.wait_for_run` | Poll until terminal status (or timeout). Returns summary + final run |
|
|
94
|
+
| `sixseven.list_run_testcases` | List testcases attached to a specific run |
|
|
95
|
+
| `sixseven.get_evidence` | Aggregate per-case attempts + step events + failed-step screenshots |
|
|
96
|
+
|
|
97
|
+
**Auto-explore (blackbox)**
|
|
98
|
+
|
|
99
|
+
| Tool | Purpose |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `sixseven.start_exploration` | Kick off SixSeven's BFS crawler on seed URLs (server-side Puppeteer) |
|
|
102
|
+
| `sixseven.get_exploration` | Read the latest exploration snapshot (status + counts) |
|
|
103
|
+
|
|
104
|
+
**Bug filing**
|
|
105
|
+
|
|
106
|
+
| Tool | Purpose |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `sixseven.file_bug` | Open an issue report against the bound project (after auto-fix loop confirms a real defect) |
|
|
109
|
+
| `sixseven.list_bugs` | List issue reports for the project |
|
|
110
|
+
| `sixseven.get_bug` | Fetch a single issue report by id |
|
|
111
|
+
|
|
112
|
+
**Context**
|
|
113
|
+
|
|
114
|
+
| Tool | Purpose |
|
|
115
|
+
|---|---|
|
|
116
|
+
| `sixseven.whoami` | Echo current user + project context |
|
|
117
|
+
|
|
118
|
+
## Security & telemetry
|
|
119
|
+
|
|
120
|
+
- **No telemetry.** The CLI makes no outbound calls except to the SixSeven backend you configured in `.sixseven/config.json`. There is no analytics, no crash reporter, no usage ping.
|
|
121
|
+
- **Source code stays local.** The CLI never auto-uploads files. Source content only leaves the machine if the developer (or Claude Code, on the developer's instruction) explicitly bakes it into a testcase payload.
|
|
122
|
+
- **File reads are sandboxed.** Reads are constrained to configured `codeRoots`, paths in `exclude` are refused, and path-traversal attempts (`../`, absolute paths) are rejected.
|
|
123
|
+
- **Stdout in `sixseven mcp` is strict JSON-RPC.** Human-readable logs go to stderr. Set `SIXSEVEN_DEBUG=1` to include stack traces on errors.
|
|
124
|
+
- **Credentials.** Tokens are saved to `~/.sixseven/credentials` with mode `0600`. The directory is created with mode `0700`. Tokens are never logged.
|
|
125
|
+
|
|
126
|
+
## Walk-through
|
|
127
|
+
|
|
128
|
+
See [`USAGE.md`](./USAGE.md) for end-to-end prompt examples that drive Claude Code through generate → run → evidence → auto-fix → file-bug loops.
|
|
129
|
+
|
|
130
|
+
## Config shape
|
|
131
|
+
|
|
132
|
+
`.sixseven/config.json`:
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"baseUrl": "https://sixseven.sprout.co.id",
|
|
137
|
+
"projectId": "uuid-of-project",
|
|
138
|
+
"defaultFeatureId": null,
|
|
139
|
+
"codeRoots": ["src", "apps"],
|
|
140
|
+
"exclude": ["node_modules", "dist", ".git", ".next"],
|
|
141
|
+
"platform": "web"
|
|
142
|
+
}
|
|
143
|
+
```
|
package/USAGE.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @sixseven-ai/cli — Claude Code usage guide
|
|
2
|
+
|
|
3
|
+
Once `sixseven login` + `sixseven init` are done and the MCP server is registered (`claude mcp add sixseven -- node /abs/path/dist/bin.js mcp`), you can prompt Claude Code in plain language and it will pick the right `sixseven.*` tools on its own.
|
|
4
|
+
|
|
5
|
+
Below are real prompt patterns you can paste into Claude Code.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. First sanity check
|
|
10
|
+
|
|
11
|
+
> Use `sixseven.whoami`. Then list features and tell me which one to use for login flow tests.
|
|
12
|
+
|
|
13
|
+
This confirms binding works and surfaces the feature you'll attach testcases to.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. Whitebox testcase from source code
|
|
18
|
+
|
|
19
|
+
> I want a happy-path login testcase. Read `src/pages/Login.tsx` and the form schema next to it. Use the feature named "Auth". Create the testcase and run it on web. When the run finishes, tell me pass/fail and the report URL.
|
|
20
|
+
|
|
21
|
+
What Claude will do under the hood:
|
|
22
|
+
|
|
23
|
+
1. `sixseven.search_code` for `Login.tsx` and schema files.
|
|
24
|
+
2. `sixseven.read_code` on the matches.
|
|
25
|
+
3. `sixseven.list_features` → pick "Auth" id.
|
|
26
|
+
4. `sixseven.create_testcase` with Midscene steps inferred from the form fields.
|
|
27
|
+
5. `sixseven.create_run({ testCaseIds:[id], platform:"web" })`.
|
|
28
|
+
6. `sixseven.execute_run`.
|
|
29
|
+
7. `sixseven.wait_for_run` (defaults: 300 s timeout, 3 s poll).
|
|
30
|
+
8. Reports back the result and report URL.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 3. Auto-fix loop (testcase or app bug?)
|
|
35
|
+
|
|
36
|
+
> Run testcase `tc_abc123`. If it fails, fetch evidence and decide: is the testcase brittle (fix it and re-run), or is the app broken (file a bug with the screenshot, severity high)?
|
|
37
|
+
|
|
38
|
+
Claude will iterate via:
|
|
39
|
+
|
|
40
|
+
- `sixseven.create_run` → `execute_run` → `wait_for_run`.
|
|
41
|
+
- On fail: `sixseven.get_evidence({ runId })` → reads `failedSteps[].error` + `screenshotUrl`.
|
|
42
|
+
- Decides: `sixseven.update_testcase` (selector / step wording was off) **or** `sixseven.list_bugs` then `sixseven.file_bug({ title, severity:"high", evidences:[screenshotUrl] })`.
|
|
43
|
+
- Re-runs on update; stops after filing a bug.
|
|
44
|
+
|
|
45
|
+
You can cap iterations explicitly:
|
|
46
|
+
|
|
47
|
+
> Iterate at most 3 times.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 4. Blackbox sweep before whitebox
|
|
52
|
+
|
|
53
|
+
> Start exploration on `https://staging.example.com/`. Wait until done. Then for every route that has a form or a primary CTA, propose a testcase in the "Smoke" feature and run them in parallel.
|
|
54
|
+
|
|
55
|
+
Claude will use:
|
|
56
|
+
|
|
57
|
+
- `sixseven.start_exploration({ seedUrls:[…], maxDepth:3 })`.
|
|
58
|
+
- Polls `sixseven.get_exploration` until `status === "completed"`.
|
|
59
|
+
- Cross-references discovered routes with `sixseven.search_code` (whitebox) to enrich each testcase.
|
|
60
|
+
- Bulk-creates testcases, bulk-creates one run with all of them, executes, waits.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 5. Pre-flight every commit (CI prompt)
|
|
65
|
+
|
|
66
|
+
> For each changed file in this commit that lives in `src/pages/**`, find the testcase tagged with the route, run it on web, and exit non-zero if any fail. Print the SixSeven report URLs.
|
|
67
|
+
|
|
68
|
+
Best paired with `--allowedTools` in a CI Claude Code invocation so only `sixseven.*` and `git` are available.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Tool reference (when Claude asks "what can I do?")
|
|
73
|
+
|
|
74
|
+
Whitebox: `read_code`, `list_dir`, `search_code`.
|
|
75
|
+
|
|
76
|
+
Features/testcases: `list_features`, `create_feature`, `list_testcases`, `get_testcase`, `create_testcase`, `update_testcase`.
|
|
77
|
+
|
|
78
|
+
Runs: `list_runs`, `create_run`, `execute_run`, `get_run`, `cancel_run`, `wait_for_run`, `list_run_testcases`, `get_evidence`.
|
|
79
|
+
|
|
80
|
+
Exploration: `start_exploration`, `get_exploration`.
|
|
81
|
+
|
|
82
|
+
Bugs: `file_bug`, `list_bugs`, `get_bug`.
|
|
83
|
+
|
|
84
|
+
Context: `whoami`.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Tips for better Claude prompts
|
|
89
|
+
|
|
90
|
+
- Tell it the **feature name** rather than the id — it can resolve via `list_features`.
|
|
91
|
+
- Be explicit about **platform** (`web` / `android` / `ios`) when it differs from `.sixseven/config.json`.
|
|
92
|
+
- For iteration loops, set a **hard cap** ("at most 3 attempts") so Claude doesn't spin.
|
|
93
|
+
- If a step screenshot URL is a presigned S3 link, it expires (~1 h). Have Claude file the bug in the same session, not the next day.
|
|
94
|
+
- Set `SIXSEVEN_DEBUG=1` before `sixseven mcp` to see stack traces on stderr; Claude won't see them.
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { Agent, fetch } from 'undici';
|
|
2
|
+
import { normalizeBaseUrl } from './config.js';
|
|
3
|
+
export class ApiError extends Error {
|
|
4
|
+
status;
|
|
5
|
+
bodyText;
|
|
6
|
+
constructor(status, bodyText, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.bodyText = bodyText;
|
|
10
|
+
this.name = 'ApiError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class SixSevenApi {
|
|
14
|
+
baseUrl;
|
|
15
|
+
token;
|
|
16
|
+
timeoutMs;
|
|
17
|
+
agent;
|
|
18
|
+
constructor(opts) {
|
|
19
|
+
this.baseUrl = normalizeBaseUrl(opts.baseUrl);
|
|
20
|
+
this.token = opts.token;
|
|
21
|
+
this.timeoutMs = opts.timeoutMs ?? 30_000;
|
|
22
|
+
this.agent =
|
|
23
|
+
opts.dispatcher ??
|
|
24
|
+
new Agent({
|
|
25
|
+
connect: { timeout: 10_000 },
|
|
26
|
+
headersTimeout: this.timeoutMs,
|
|
27
|
+
bodyTimeout: this.timeoutMs,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async request(method, path, body) {
|
|
31
|
+
const url = `${this.baseUrl}${path}`;
|
|
32
|
+
const headers = {
|
|
33
|
+
Authorization: `Bearer ${this.token}`,
|
|
34
|
+
Accept: 'application/json',
|
|
35
|
+
};
|
|
36
|
+
let payload;
|
|
37
|
+
if (body !== undefined) {
|
|
38
|
+
headers['Content-Type'] = 'application/json';
|
|
39
|
+
payload = JSON.stringify(body);
|
|
40
|
+
}
|
|
41
|
+
let res;
|
|
42
|
+
try {
|
|
43
|
+
res = await fetch(url, {
|
|
44
|
+
method,
|
|
45
|
+
headers,
|
|
46
|
+
body: payload,
|
|
47
|
+
dispatcher: this.agent,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
throw new ApiError(0, '', `Network error calling ${url}: ${err.message}`);
|
|
52
|
+
}
|
|
53
|
+
const text = await res.text();
|
|
54
|
+
if (!res.ok) {
|
|
55
|
+
let msg = `${method} ${path} -> ${res.status}`;
|
|
56
|
+
try {
|
|
57
|
+
const parsed = JSON.parse(text);
|
|
58
|
+
if (parsed?.error)
|
|
59
|
+
msg += `: ${parsed.error}`;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
if (text)
|
|
63
|
+
msg += `: ${text.slice(0, 200)}`;
|
|
64
|
+
}
|
|
65
|
+
throw new ApiError(res.status, text, msg);
|
|
66
|
+
}
|
|
67
|
+
if (!text)
|
|
68
|
+
return undefined;
|
|
69
|
+
try {
|
|
70
|
+
return JSON.parse(text);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return text;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// --- Auth ---
|
|
77
|
+
async me() {
|
|
78
|
+
return this.request('GET', '/api/auth/me');
|
|
79
|
+
}
|
|
80
|
+
// --- Projects ---
|
|
81
|
+
async listProjects() {
|
|
82
|
+
return this.request('GET', '/api/projects');
|
|
83
|
+
}
|
|
84
|
+
async getProject(projectId) {
|
|
85
|
+
return this.request('GET', `/api/projects/${projectId}`);
|
|
86
|
+
}
|
|
87
|
+
// --- Features ---
|
|
88
|
+
async listFeatures(projectId) {
|
|
89
|
+
return this.request('GET', `/api/projects/${projectId}/features`);
|
|
90
|
+
}
|
|
91
|
+
async createFeature(projectId, input) {
|
|
92
|
+
return this.request('POST', `/api/projects/${projectId}/features`, input);
|
|
93
|
+
}
|
|
94
|
+
// --- Test cases ---
|
|
95
|
+
async listTestCasesByProject(projectId, platform) {
|
|
96
|
+
const qs = platform ? `?platform=${encodeURIComponent(platform)}` : '';
|
|
97
|
+
return this.request('GET', `/api/projects/${projectId}/test-cases${qs}`);
|
|
98
|
+
}
|
|
99
|
+
async listTestCasesByFeature(featureId) {
|
|
100
|
+
return this.request('GET', `/api/features/${featureId}/test-cases`);
|
|
101
|
+
}
|
|
102
|
+
async createTestCase(featureId, input) {
|
|
103
|
+
return this.request('POST', `/api/features/${featureId}/test-cases`, input);
|
|
104
|
+
}
|
|
105
|
+
async getTestCase(id) {
|
|
106
|
+
return this.request('GET', `/api/test-cases/${id}`);
|
|
107
|
+
}
|
|
108
|
+
async updateTestCase(id, patch) {
|
|
109
|
+
return this.request('PATCH', `/api/test-cases/${id}`, patch);
|
|
110
|
+
}
|
|
111
|
+
// --- Runs ---
|
|
112
|
+
async listRuns(projectId, platform) {
|
|
113
|
+
const qs = platform ? `?platform=${encodeURIComponent(platform)}` : '';
|
|
114
|
+
return this.request('GET', `/api/projects/${projectId}/runs${qs}`);
|
|
115
|
+
}
|
|
116
|
+
async createRun(projectId, input) {
|
|
117
|
+
return this.request('POST', `/api/projects/${projectId}/runs`, input);
|
|
118
|
+
}
|
|
119
|
+
async getRun(runId) {
|
|
120
|
+
return this.request('GET', `/api/runs/${runId}`);
|
|
121
|
+
}
|
|
122
|
+
async executeRun(runId, body = {}) {
|
|
123
|
+
return this.request('POST', `/api/runs/${runId}/execute`, body);
|
|
124
|
+
}
|
|
125
|
+
async cancelRun(runId) {
|
|
126
|
+
return this.request('POST', `/api/runs/${runId}/cancel`, {});
|
|
127
|
+
}
|
|
128
|
+
async listRunTestCases(runId) {
|
|
129
|
+
return this.request('GET', `/api/runs/${runId}/test-cases`);
|
|
130
|
+
}
|
|
131
|
+
async listRunCaseAttempts(runId) {
|
|
132
|
+
return this.request('GET', `/api/runs/${runId}/case-attempts`);
|
|
133
|
+
}
|
|
134
|
+
async listRunStepEvents(runId, testCaseId) {
|
|
135
|
+
const qs = testCaseId
|
|
136
|
+
? `?testCaseId=${encodeURIComponent(testCaseId)}`
|
|
137
|
+
: '';
|
|
138
|
+
return this.request('GET', `/api/runs/${runId}/events${qs}`);
|
|
139
|
+
}
|
|
140
|
+
// --- Issue reports (bugs) ---
|
|
141
|
+
async createIssueReport(input) {
|
|
142
|
+
return this.request('POST', '/api/issue-reports', input);
|
|
143
|
+
}
|
|
144
|
+
async listIssueReports(projectId) {
|
|
145
|
+
const qs = projectId ? `?projectId=${encodeURIComponent(projectId)}` : '';
|
|
146
|
+
const resp = await this.request('GET', `/api/issue-reports${qs}`);
|
|
147
|
+
if (Array.isArray(resp))
|
|
148
|
+
return resp;
|
|
149
|
+
return resp.reports ?? [];
|
|
150
|
+
}
|
|
151
|
+
async getIssueReport(id) {
|
|
152
|
+
return this.request('GET', `/api/issue-reports/${id}`);
|
|
153
|
+
}
|
|
154
|
+
// --- Exploration ---
|
|
155
|
+
async startExploration(projectId, input) {
|
|
156
|
+
return this.request('POST', `/api/projects/${projectId}/explore`, input);
|
|
157
|
+
}
|
|
158
|
+
async getExploration(projectId) {
|
|
159
|
+
return this.request('GET', `/api/projects/${projectId}/explore`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// --- Run / step event types ---
|
|
163
|
+
export const TERMINAL_RUN_STATUSES = new Set([
|
|
164
|
+
'passed',
|
|
165
|
+
'failed',
|
|
166
|
+
'cancelled',
|
|
167
|
+
'error',
|
|
168
|
+
]);
|
|
169
|
+
export async function pingBaseUrl(baseUrl) {
|
|
170
|
+
try {
|
|
171
|
+
const res = await fetch(`${normalizeBaseUrl(baseUrl)}/api/auth/me`, {
|
|
172
|
+
method: 'GET',
|
|
173
|
+
});
|
|
174
|
+
// 401 means server reachable but unauthenticated, which is fine
|
|
175
|
+
return res.status >= 200 && res.status < 500;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import { doctorCommand } from './commands/doctor.js';
|
|
5
|
+
import { initCommand } from './commands/init.js';
|
|
6
|
+
import { loginCommand } from './commands/login.js';
|
|
7
|
+
import { setupCommand } from './commands/setup.js';
|
|
8
|
+
import { statusCommand } from './commands/status.js';
|
|
9
|
+
import { runMcpServer } from './mcp/server.js';
|
|
10
|
+
async function main() {
|
|
11
|
+
const program = new Command();
|
|
12
|
+
program
|
|
13
|
+
.name('sixseven')
|
|
14
|
+
.description('SixSeven CLI — login, init repo, and run an MCP server so Claude Code can author whitebox testcases against your app.')
|
|
15
|
+
.version('0.1.1');
|
|
16
|
+
program
|
|
17
|
+
.command('setup')
|
|
18
|
+
.description('Guided wizard: login → bind project → register MCP with Claude Code in one go')
|
|
19
|
+
.option('--base-url <url>', 'SixSeven base URL')
|
|
20
|
+
.option('--token <token>', 'CI token starting with 67ci_')
|
|
21
|
+
.option('--project-id <id>', 'SixSeven project id')
|
|
22
|
+
.option('--skip-mcp', 'do not register the MCP server')
|
|
23
|
+
.option('--non-interactive', 'fail instead of prompting')
|
|
24
|
+
.action(async (opts) => {
|
|
25
|
+
await setupCommand({
|
|
26
|
+
baseUrl: opts.baseUrl,
|
|
27
|
+
token: opts.token,
|
|
28
|
+
projectId: opts.projectId,
|
|
29
|
+
skipMcp: !!opts.skipMcp,
|
|
30
|
+
nonInteractive: !!opts.nonInteractive,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
program
|
|
34
|
+
.command('login')
|
|
35
|
+
.description('Authenticate against a SixSeven backend with a CI token')
|
|
36
|
+
.option('--base-url <url>', 'SixSeven base URL (e.g. http://localhost:3067)')
|
|
37
|
+
.option('--token <token>', 'CI token starting with 67ci_')
|
|
38
|
+
.option('--non-interactive', 'fail instead of prompting')
|
|
39
|
+
.action(async (opts) => {
|
|
40
|
+
await loginCommand({
|
|
41
|
+
baseUrl: opts.baseUrl,
|
|
42
|
+
token: opts.token,
|
|
43
|
+
nonInteractive: !!opts.nonInteractive,
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
program
|
|
47
|
+
.command('init')
|
|
48
|
+
.description('Create .sixseven/config.json bound to a SixSeven project')
|
|
49
|
+
.option('--base-url <url>', 'SixSeven base URL')
|
|
50
|
+
.option('--project-id <id>', 'SixSeven project id')
|
|
51
|
+
.option('--non-interactive', 'fail instead of prompting')
|
|
52
|
+
.action(async (opts) => {
|
|
53
|
+
await initCommand({
|
|
54
|
+
baseUrl: opts.baseUrl,
|
|
55
|
+
projectId: opts.projectId,
|
|
56
|
+
nonInteractive: !!opts.nonInteractive,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
program
|
|
60
|
+
.command('status')
|
|
61
|
+
.description('Show current binding, token validity, and project counts')
|
|
62
|
+
.action(async () => {
|
|
63
|
+
await statusCommand();
|
|
64
|
+
});
|
|
65
|
+
program
|
|
66
|
+
.command('doctor')
|
|
67
|
+
.description('Run diagnostics: config, token, backend reachability, project access')
|
|
68
|
+
.action(async () => {
|
|
69
|
+
await doctorCommand();
|
|
70
|
+
});
|
|
71
|
+
program
|
|
72
|
+
.command('mcp')
|
|
73
|
+
.description('Start the SixSeven MCP server on stdio (spawned by Claude Code)')
|
|
74
|
+
.action(async () => {
|
|
75
|
+
await runMcpServer();
|
|
76
|
+
});
|
|
77
|
+
await program.parseAsync(process.argv);
|
|
78
|
+
}
|
|
79
|
+
main().catch((err) => {
|
|
80
|
+
process.stderr.write(pc.red(`\nerror: ${err?.message ?? err}\n`));
|
|
81
|
+
if (process.env.SIXSEVEN_DEBUG) {
|
|
82
|
+
process.stderr.write(`${String(err?.stack ?? '')}\n`);
|
|
83
|
+
}
|
|
84
|
+
process.exit(1);
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
import { fetch } from 'undici';
|
|
3
|
+
import { SixSevenApi } from '../api.js';
|
|
4
|
+
import { findRepoRoot, getToken, readProjectConfig } from '../config.js';
|
|
5
|
+
function ok(msg) {
|
|
6
|
+
process.stdout.write(pc.green(` ✓ ${msg}\n`));
|
|
7
|
+
}
|
|
8
|
+
function bad(msg) {
|
|
9
|
+
process.stdout.write(pc.red(` ✗ ${msg}\n`));
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
}
|
|
12
|
+
function warn(msg) {
|
|
13
|
+
process.stdout.write(pc.yellow(` ! ${msg}\n`));
|
|
14
|
+
}
|
|
15
|
+
export async function doctorCommand() {
|
|
16
|
+
process.stdout.write(pc.bold('SixSeven CLI doctor\n'));
|
|
17
|
+
const repoRoot = await findRepoRoot(process.cwd());
|
|
18
|
+
if (!repoRoot) {
|
|
19
|
+
bad('No .sixseven/config.json found. Run `sixseven init`.');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
ok(`repo root: ${repoRoot}`);
|
|
23
|
+
let cfg;
|
|
24
|
+
try {
|
|
25
|
+
cfg = await readProjectConfig(repoRoot);
|
|
26
|
+
ok(`config parsed: projectId=${cfg.projectId} platform=${cfg.platform}`);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
bad(`config invalid: ${err.message}`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const token = await getToken(cfg.baseUrl);
|
|
33
|
+
if (!token) {
|
|
34
|
+
bad(`no saved token for ${cfg.baseUrl}. Run \`sixseven login\`.`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
ok(`token present for ${cfg.baseUrl}`);
|
|
38
|
+
try {
|
|
39
|
+
const r = await fetch(`${cfg.baseUrl}/api/auth/me`);
|
|
40
|
+
if (r.status >= 200 && r.status < 600)
|
|
41
|
+
ok(`backend reachable (${r.status})`);
|
|
42
|
+
else
|
|
43
|
+
warn(`backend status ${r.status}`);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
bad(`backend unreachable: ${err.message}`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const api = new SixSevenApi({ baseUrl: cfg.baseUrl, token });
|
|
50
|
+
try {
|
|
51
|
+
const user = await api.me();
|
|
52
|
+
ok(`token valid: ${user.email} (${user.role})`);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
bad(`token invalid: ${err.message}`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
let features = [];
|
|
59
|
+
try {
|
|
60
|
+
features = (await api.listFeatures(cfg.projectId));
|
|
61
|
+
ok(`project ${cfg.projectId} accessible, ${features.length} feature(s)`);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
bad(`project access failed: ${err.message}`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const project = await api.getProject(cfg.projectId);
|
|
69
|
+
const supported = project.platforms ?? [];
|
|
70
|
+
if (supported.length && !supported.includes(cfg.platform)) {
|
|
71
|
+
warn(`default platform "${cfg.platform}" is NOT in project.platforms [${supported.join(', ')}] — sixseven.create_run will fail until you fix .sixseven/config.json`);
|
|
72
|
+
}
|
|
73
|
+
else if (supported.length) {
|
|
74
|
+
ok(`platform "${cfg.platform}" is supported by project`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
warn('could not verify project platforms (non-fatal)');
|
|
79
|
+
}
|
|
80
|
+
if (cfg.defaultFeatureId) {
|
|
81
|
+
const exists = features.some((f) => f.id === cfg.defaultFeatureId);
|
|
82
|
+
if (!exists) {
|
|
83
|
+
warn(`defaultFeatureId ${cfg.defaultFeatureId} not found in project — clear it from .sixseven/config.json or pick a real feature id`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
ok('defaultFeatureId resolves to a real feature');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|