@mootup/moot-cli 0.1.0-rc.0 → 0.2.0
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 +37 -30
- package/dist/auth/archetypes.d.ts +10 -0
- package/dist/auth/archetypes.d.ts.map +1 -0
- package/dist/auth/archetypes.js +39 -0
- package/dist/auth/archetypes.js.map +1 -0
- package/dist/auth/credentials.d.ts +21 -0
- package/dist/auth/credentials.d.ts.map +1 -0
- package/dist/auth/credentials.js +97 -0
- package/dist/auth/credentials.js.map +1 -0
- package/dist/auth/oauth.d.ts +42 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +200 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/profile.d.ts +3 -0
- package/dist/auth/profile.d.ts.map +1 -0
- package/dist/auth/profile.js +7 -0
- package/dist/auth/profile.js.map +1 -0
- package/dist/bin.js +21 -3
- package/dist/bin.js.map +1 -1
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +261 -69
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +5 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +7 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +42 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/refresh.d.ts +6 -0
- package/dist/commands/refresh.d.ts.map +1 -0
- package/dist/commands/refresh.js +53 -0
- package/dist/commands/refresh.js.map +1 -0
- package/dist/credential.d.ts +6 -0
- package/dist/credential.d.ts.map +1 -1
- package/dist/credential.js +30 -1
- package/dist/credential.js.map +1 -1
- package/dist/docker.js +1 -1
- package/dist/docker.js.map +1 -1
- package/dist/harness/claude-code.d.ts +37 -0
- package/dist/harness/claude-code.d.ts.map +1 -0
- package/dist/harness/claude-code.js +66 -0
- package/dist/harness/claude-code.js.map +1 -0
- package/dist/harness/cursor-agent.d.ts +3 -0
- package/dist/harness/cursor-agent.d.ts.map +1 -0
- package/dist/harness/cursor-agent.js +17 -0
- package/dist/harness/cursor-agent.js.map +1 -0
- package/dist/harness/cursor-ide.d.ts +10 -0
- package/dist/harness/cursor-ide.d.ts.map +1 -0
- package/dist/harness/cursor-ide.js +65 -0
- package/dist/harness/cursor-ide.js.map +1 -0
- package/dist/harness/index.d.ts +16 -0
- package/dist/harness/index.d.ts.map +1 -0
- package/dist/harness/index.js +65 -0
- package/dist/harness/index.js.map +1 -0
- package/dist/harness/sdk.d.ts +7 -0
- package/dist/harness/sdk.d.ts.map +1 -0
- package/dist/harness/sdk.js +18 -0
- package/dist/harness/sdk.js.map +1 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
# @mootup/moot-cli
|
|
2
2
|
|
|
3
|
-
Host-side operator CLI for the Moot agent team workflow. Bin name: `
|
|
3
|
+
Host-side operator CLI for the Moot agent team workflow. Bin name: `moot`.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### Recommended: user-local install (no sudo)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
npm i -g --prefix ~/.local @mootup/moot-cli
|
|
10
|
+
moot --version
|
|
11
|
+
|
|
12
|
+
Most Ubuntu/Debian systems already have `~/.local/bin` in PATH. If `moot --version` is not found after install, add the export to `~/.bashrc`:
|
|
13
|
+
|
|
14
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
### Alternative: system-wide install (requires sudo)
|
|
13
17
|
|
|
14
|
-
npm i -g @mootup/moot-cli
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
sudo npm i -g @mootup/moot-cli
|
|
19
|
+
moot --version
|
|
20
|
+
|
|
21
|
+
### Ephemeral: npx (no install)
|
|
22
|
+
|
|
23
|
+
npx @mootup/moot-cli login
|
|
17
24
|
|
|
18
|
-
Requires Node ≥
|
|
25
|
+
Requires Node ≥ 18, Docker, and [`@devcontainers/cli`](https://github.com/devcontainers/cli) on PATH:
|
|
19
26
|
|
|
20
27
|
npm i -g @devcontainers/cli
|
|
21
28
|
|
|
@@ -24,41 +31,41 @@ Requires Node ≥ 20, Docker, and [`@devcontainers/cli`](https://github.com/devc
|
|
|
24
31
|
```bash
|
|
25
32
|
# 1. Create a personal access token at https://mootup.io/settings/api-keys
|
|
26
33
|
# 2. Authenticate (stored under ~/.mootup/credentials.json, mode 0600):
|
|
27
|
-
|
|
34
|
+
moot login
|
|
28
35
|
|
|
29
36
|
# 3. Provision actors and install .devcontainer/ in your repo:
|
|
30
37
|
cd my-project
|
|
31
|
-
|
|
38
|
+
moot init
|
|
32
39
|
|
|
33
40
|
# 4. Bring the devcontainer up and start the agent team:
|
|
34
|
-
|
|
41
|
+
moot up
|
|
35
42
|
|
|
36
43
|
# 5. Inspect, attach, compact as needed:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
moot status
|
|
45
|
+
moot attach leader
|
|
46
|
+
moot compact spec
|
|
40
47
|
|
|
41
48
|
# 6. Stop everything:
|
|
42
|
-
|
|
49
|
+
moot down
|
|
43
50
|
```
|
|
44
51
|
|
|
45
52
|
## Command reference
|
|
46
53
|
|
|
47
54
|
| Command | Runs | Delegates to |
|
|
48
55
|
|---|---|---|
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
54
|
-
| `
|
|
55
|
-
| `
|
|
56
|
+
| `moot login [--token <pat>] [--api-url <url>]` | host | writes `~/.mootup/credentials.json` |
|
|
57
|
+
| `moot init [--force] [--yes] [--api-url <url>]` | host | rotates actor keys, writes `.moot/actors.json`, copies `.devcontainer/` |
|
|
58
|
+
| `moot up` | host → container | `devcontainer up` + `docker exec <cid> moot up` |
|
|
59
|
+
| `moot down [role]` | container | `docker exec <cid> moot down [role]` |
|
|
60
|
+
| `moot status` | container | `docker exec <cid> moot status` |
|
|
61
|
+
| `moot attach <role>` | container | `docker exec -it <cid> moot attach <role>` |
|
|
62
|
+
| `moot compact [role]` | container | `docker exec <cid> moot compact [role]` |
|
|
56
63
|
|
|
57
|
-
The `up`, `down`, `status`, `attach`, and `compact` commands look up the running container by the `devcontainer.local_folder` label the devcontainer CLI stamps on each container; no container → clear error prompting `
|
|
64
|
+
The `up`, `down`, `status`, `attach`, and `compact` commands look up the running container by the `devcontainer.local_folder` label the devcontainer CLI stamps on each container; no container → clear error prompting `moot up`.
|
|
58
65
|
|
|
59
66
|
## Scope vs the Python CLI
|
|
60
67
|
|
|
61
|
-
`@mootup/moot-cli` covers only the host-side operator surface. The Python `moot` CLI inside the devcontainer remains canonical for in-container orchestration (tmux, MCP adapter, channel adapter, hooks, team profile). `
|
|
68
|
+
`@mootup/moot-cli` covers only the host-side operator surface. The Python `moot` CLI inside the devcontainer remains canonical for in-container orchestration (tmux, MCP adapter, channel adapter, hooks, team profile). `moot init` in v0.1.0 installs `.moot/actors.json` + `.devcontainer/` only; skill / CLAUDE.md / hook bundle installation is tracked as a follow-up run.
|
|
62
69
|
|
|
63
70
|
## Manual smoke test (operator)
|
|
64
71
|
|
|
@@ -66,11 +73,11 @@ Run from a fresh test directory after logging in:
|
|
|
66
73
|
|
|
67
74
|
mkdir /tmp/mootup-smoke && cd /tmp/mootup-smoke
|
|
68
75
|
git init
|
|
69
|
-
|
|
76
|
+
moot init
|
|
70
77
|
test -f .moot/actors.json && echo "actors.json ✓"
|
|
71
78
|
test -d .devcontainer && echo "devcontainer ✓"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
moot up
|
|
80
|
+
moot status
|
|
81
|
+
moot down
|
|
75
82
|
|
|
76
|
-
`
|
|
83
|
+
`moot init` hits the authenticated `/api/actors/me`, `/api/actors/me/agents`, `/api/actors/{id}/rotate-key` endpoints against the API URL stored at login time. A reachable backend is required.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface ArchetypeEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
version: string;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const ARCHETYPE_CATALOG: readonly ArchetypeEntry[];
|
|
7
|
+
export declare const DEFAULT_ARCHETYPE = "mootup/loop-6";
|
|
8
|
+
export declare function findArchetype(id: string): ArchetypeEntry | null;
|
|
9
|
+
export declare function promptArchetype(prompt?: (q: string) => Promise<string>): Promise<ArchetypeEntry>;
|
|
10
|
+
//# sourceMappingURL=archetypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archetypes.d.ts","sourceRoot":"","sources":["../../src/auth/archetypes.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAO7C,CAAC;AAEX,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAE/D;AAED,wBAAsB,eAAe,CACnC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GACtC,OAAO,CAAC,cAAc,CAAC,CAkBzB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline/promises';
|
|
2
|
+
export const ARCHETYPE_CATALOG = [
|
|
3
|
+
{ id: 'mootup/loop-6', version: '1.0', description: 'Full pipeline (product/leader/spec/impl/qa/librarian)' },
|
|
4
|
+
{ id: 'mootup/loop-4', version: '1.0', description: 'Core pipeline (product/spec/impl/qa)' },
|
|
5
|
+
{ id: 'mootup/loop-4-observer', version: '1.0', description: 'Core + librarian' },
|
|
6
|
+
{ id: 'mootup/loop-4-parallel', version: '1.0', description: 'Core + parallel impl-a/impl-b' },
|
|
7
|
+
{ id: 'mootup/loop-4-split-leader', version: '1.0', description: 'Core + dedicated leader' },
|
|
8
|
+
{ id: 'mootup/loop-3', version: '1.0', description: 'Minimal (leader/impl/qa)' },
|
|
9
|
+
];
|
|
10
|
+
export const DEFAULT_ARCHETYPE = 'mootup/loop-6';
|
|
11
|
+
export function findArchetype(id) {
|
|
12
|
+
return ARCHETYPE_CATALOG.find((a) => a.id === id) ?? null;
|
|
13
|
+
}
|
|
14
|
+
export async function promptArchetype(prompt) {
|
|
15
|
+
const ask = prompt ?? defaultPrompt;
|
|
16
|
+
console.log('Available team archetypes:');
|
|
17
|
+
ARCHETYPE_CATALOG.forEach((a, i) => {
|
|
18
|
+
const marker = a.id === DEFAULT_ARCHETYPE ? ' (default)' : '';
|
|
19
|
+
console.log(` ${i + 1}. ${a.id}${marker} — ${a.description}`);
|
|
20
|
+
});
|
|
21
|
+
const answer = (await ask(`Select archetype [1-${ARCHETYPE_CATALOG.length}, default=${DEFAULT_ARCHETYPE}]: `)).trim();
|
|
22
|
+
if (!answer)
|
|
23
|
+
return findArchetype(DEFAULT_ARCHETYPE);
|
|
24
|
+
const idx = Number.parseInt(answer, 10);
|
|
25
|
+
if (Number.isFinite(idx) && idx >= 1 && idx <= ARCHETYPE_CATALOG.length) {
|
|
26
|
+
return ARCHETYPE_CATALOG[idx - 1];
|
|
27
|
+
}
|
|
28
|
+
const byId = findArchetype(answer);
|
|
29
|
+
if (byId)
|
|
30
|
+
return byId;
|
|
31
|
+
throw new Error(`Unknown archetype: ${answer}`);
|
|
32
|
+
}
|
|
33
|
+
async function defaultPrompt(q) {
|
|
34
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
35
|
+
const answer = await rl.question(q);
|
|
36
|
+
rl.close();
|
|
37
|
+
return answer;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=archetypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archetypes.js","sourceRoot":"","sources":["../../src/auth/archetypes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAQzD,MAAM,CAAC,MAAM,iBAAiB,GAA8B;IAC1D,EAAE,EAAE,EAAE,eAAe,EAAe,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,uDAAuD,EAAE;IAC1H,EAAE,EAAE,EAAE,eAAe,EAAe,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,sCAAsC,EAAE;IACzG,EAAE,EAAE,EAAE,wBAAwB,EAAM,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE;IACrF,EAAE,EAAE,EAAE,wBAAwB,EAAM,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,+BAA+B,EAAE;IAClG,EAAE,EAAE,EAAE,4BAA4B,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,yBAAyB,EAAE;IAC5F,EAAE,EAAE,EAAE,eAAe,EAAe,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,0BAA0B,EAAE;CACrF,CAAC;AAEX,MAAM,CAAC,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEjD,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC;AAC5D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAuC;IAEvC,MAAM,GAAG,GAAG,MAAM,IAAI,aAAa,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC1C,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,iBAAiB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,MAAM,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,CACb,MAAM,GAAG,CAAC,uBAAuB,iBAAiB,CAAC,MAAM,aAAa,iBAAiB,KAAK,CAAC,CAC9F,CAAC,IAAI,EAAE,CAAC;IACT,IAAI,CAAC,MAAM;QAAE,OAAO,aAAa,CAAC,iBAAiB,CAAE,CAAC;IACtD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxC,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,iBAAiB,CAAC,MAAM,EAAE,CAAC;QACxE,OAAO,iBAAiB,CAAC,GAAG,GAAG,CAAC,CAAE,CAAC;IACrC,CAAC;IACD,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,CAAS;IACpC,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpC,EAAE,CAAC,KAAK,EAAE,CAAC;IACX,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const KEYTAR_SERVICE = "mootup-cli";
|
|
2
|
+
export interface OAuthCredentialBundle {
|
|
3
|
+
api_url: string;
|
|
4
|
+
user_id: string;
|
|
5
|
+
access_token: string;
|
|
6
|
+
refresh_token: string;
|
|
7
|
+
access_token_expires_at: number;
|
|
8
|
+
installation_id?: string;
|
|
9
|
+
}
|
|
10
|
+
type KeytarLike = {
|
|
11
|
+
setPassword: (service: string, account: string, password: string) => Promise<void>;
|
|
12
|
+
getPassword: (service: string, account: string) => Promise<string | null>;
|
|
13
|
+
deletePassword: (service: string, account: string) => Promise<boolean>;
|
|
14
|
+
};
|
|
15
|
+
export declare function __setKeytarForTest(k: KeytarLike | null): void;
|
|
16
|
+
export declare function storeOAuthCredential(profile: string, creds: OAuthCredentialBundle): Promise<void>;
|
|
17
|
+
export declare function loadRefreshToken(profile: string): Promise<string | null>;
|
|
18
|
+
export declare function deleteOAuthCredential(profile: string): Promise<void>;
|
|
19
|
+
export declare function __clearSessionMemoryForTest(): void;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/auth/credentials.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID,KAAK,UAAU,GAAG;IAChB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnF,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1E,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxE,CAAC;AAIF,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAE7D;AAoBD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAYD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAY9E;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc1E;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { loadCredential, storeCredential, deleteCredential, } from '../credential.js';
|
|
2
|
+
export const KEYTAR_SERVICE = 'mootup-cli';
|
|
3
|
+
const sessionRefreshTokenMemory = new Map();
|
|
4
|
+
let keytarOverride = null;
|
|
5
|
+
export function __setKeytarForTest(k) {
|
|
6
|
+
keytarOverride = k;
|
|
7
|
+
}
|
|
8
|
+
async function loadKeytar() {
|
|
9
|
+
if (keytarOverride)
|
|
10
|
+
return keytarOverride;
|
|
11
|
+
try {
|
|
12
|
+
// keytar is an optionalDependency; dynamic import keeps it optional at build time.
|
|
13
|
+
const modName = 'keytar';
|
|
14
|
+
const mod = (await import(/* @vite-ignore */ modName));
|
|
15
|
+
return mod.default ?? mod;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function keychainRef(profile) {
|
|
22
|
+
return `${KEYTAR_SERVICE}:${profile}:refresh`;
|
|
23
|
+
}
|
|
24
|
+
export async function storeOAuthCredential(profile, creds) {
|
|
25
|
+
const keytar = await loadKeytar();
|
|
26
|
+
let refresh_token_ref;
|
|
27
|
+
if (keytar) {
|
|
28
|
+
const ref = keychainRef(profile);
|
|
29
|
+
try {
|
|
30
|
+
await keytar.setPassword(KEYTAR_SERVICE, ref, creds.refresh_token);
|
|
31
|
+
refresh_token_ref = ref;
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
printKeychainFallback(err);
|
|
35
|
+
sessionRefreshTokenMemory.set(profile, creds.refresh_token);
|
|
36
|
+
refresh_token_ref = undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
printKeychainFallback(new Error('keytar module not installed'));
|
|
41
|
+
sessionRefreshTokenMemory.set(profile, creds.refresh_token);
|
|
42
|
+
}
|
|
43
|
+
const cred = {
|
|
44
|
+
api_url: creds.api_url,
|
|
45
|
+
token: creds.access_token,
|
|
46
|
+
user_id: creds.user_id,
|
|
47
|
+
credential_type: 'oauth',
|
|
48
|
+
access_token_expires_at: creds.access_token_expires_at,
|
|
49
|
+
};
|
|
50
|
+
if (refresh_token_ref !== undefined)
|
|
51
|
+
cred.refresh_token_ref = refresh_token_ref;
|
|
52
|
+
if (creds.installation_id !== undefined)
|
|
53
|
+
cred.installation_id = creds.installation_id;
|
|
54
|
+
storeCredential(cred, profile);
|
|
55
|
+
}
|
|
56
|
+
function printKeychainFallback(err) {
|
|
57
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
58
|
+
const filePath = `${process.env.HOME ?? '~'}/.mootup/credentials.json`;
|
|
59
|
+
console.error(`note: keychain unavailable (${msg}); refresh-token lives in memory ` +
|
|
60
|
+
`for this session only. Re-authenticate on next session. ` +
|
|
61
|
+
`(using file-based storage at ${filePath} for non-secret fields only)`);
|
|
62
|
+
}
|
|
63
|
+
export async function loadRefreshToken(profile) {
|
|
64
|
+
const cred = loadCredential(profile);
|
|
65
|
+
if (!cred || cred.credential_type !== 'oauth' || !cred.refresh_token_ref) {
|
|
66
|
+
return sessionRefreshTokenMemory.get(profile) ?? null;
|
|
67
|
+
}
|
|
68
|
+
const keytar = await loadKeytar();
|
|
69
|
+
if (!keytar)
|
|
70
|
+
return sessionRefreshTokenMemory.get(profile) ?? null;
|
|
71
|
+
try {
|
|
72
|
+
return await keytar.getPassword(KEYTAR_SERVICE, cred.refresh_token_ref);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export async function deleteOAuthCredential(profile) {
|
|
79
|
+
const cred = loadCredential(profile);
|
|
80
|
+
if (cred?.refresh_token_ref) {
|
|
81
|
+
const keytar = await loadKeytar();
|
|
82
|
+
if (keytar) {
|
|
83
|
+
try {
|
|
84
|
+
await keytar.deletePassword(KEYTAR_SERVICE, cred.refresh_token_ref);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// best-effort
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
sessionRefreshTokenMemory.delete(profile);
|
|
92
|
+
deleteCredential(profile);
|
|
93
|
+
}
|
|
94
|
+
export function __clearSessionMemoryForTest() {
|
|
95
|
+
sessionRefreshTokenMemory.clear();
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/auth/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface OAuthBrowserFlowOptions {
|
|
2
|
+
apiUrl: string;
|
|
3
|
+
clientId?: string;
|
|
4
|
+
scope?: string;
|
|
5
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
6
|
+
openImpl?: (url: string) => Promise<void>;
|
|
7
|
+
waitForCallbackImpl?: (expectedState: string) => Promise<string>;
|
|
8
|
+
}
|
|
9
|
+
export interface OAuthTokenResponse {
|
|
10
|
+
access_token: string;
|
|
11
|
+
refresh_token: string;
|
|
12
|
+
expires_in: number;
|
|
13
|
+
token_type: string;
|
|
14
|
+
}
|
|
15
|
+
export interface BrowserFlowResult {
|
|
16
|
+
access_token: string;
|
|
17
|
+
refresh_token: string;
|
|
18
|
+
access_token_expires_at: number;
|
|
19
|
+
token_type: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function shouldUseBrowser(): boolean;
|
|
22
|
+
export declare function base64UrlEncode(buf: Buffer): string;
|
|
23
|
+
export declare function mintPkcePair(): {
|
|
24
|
+
verifier: string;
|
|
25
|
+
challenge: string;
|
|
26
|
+
};
|
|
27
|
+
export declare function mintState(): string;
|
|
28
|
+
export declare function generateIdempotencyKey(): string;
|
|
29
|
+
export declare function runBrowserFlow(opts: OAuthBrowserFlowOptions): Promise<BrowserFlowResult>;
|
|
30
|
+
export declare function refreshAccessToken(opts: {
|
|
31
|
+
apiUrl: string;
|
|
32
|
+
refreshToken: string;
|
|
33
|
+
clientId?: string;
|
|
34
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
35
|
+
}): Promise<BrowserFlowResult>;
|
|
36
|
+
export declare function revokeRefreshToken(opts: {
|
|
37
|
+
apiUrl: string;
|
|
38
|
+
refreshToken: string;
|
|
39
|
+
clientId?: string;
|
|
40
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/auth/oauth.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,mBAAmB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAI1C;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,YAAY,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAItE;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CA+D5B;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuB7B;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhB"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { createHash, randomBytes, randomUUID } from 'node:crypto';
|
|
2
|
+
import { createServer } from 'node:net';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
export function shouldUseBrowser() {
|
|
5
|
+
if (process.env.MOOTUP_FORCE_DEVICE_CODE === '1')
|
|
6
|
+
return false;
|
|
7
|
+
if (process.platform === 'darwin' || process.platform === 'win32')
|
|
8
|
+
return true;
|
|
9
|
+
return Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
|
|
10
|
+
}
|
|
11
|
+
export function base64UrlEncode(buf) {
|
|
12
|
+
return buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
13
|
+
}
|
|
14
|
+
export function mintPkcePair() {
|
|
15
|
+
const verifier = base64UrlEncode(randomBytes(32));
|
|
16
|
+
const challenge = base64UrlEncode(createHash('sha256').update(verifier).digest());
|
|
17
|
+
return { verifier, challenge };
|
|
18
|
+
}
|
|
19
|
+
export function mintState() {
|
|
20
|
+
return randomBytes(16).toString('hex');
|
|
21
|
+
}
|
|
22
|
+
export function generateIdempotencyKey() {
|
|
23
|
+
return randomUUID();
|
|
24
|
+
}
|
|
25
|
+
export async function runBrowserFlow(opts) {
|
|
26
|
+
const clientId = opts.clientId ?? 'mootup-cli';
|
|
27
|
+
const scope = opts.scope ?? 'team:install';
|
|
28
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
29
|
+
const openFn = opts.openImpl ?? openBrowser;
|
|
30
|
+
const { verifier, challenge } = mintPkcePair();
|
|
31
|
+
const state = mintState();
|
|
32
|
+
let port;
|
|
33
|
+
let waitForCallback;
|
|
34
|
+
if (opts.waitForCallbackImpl) {
|
|
35
|
+
port = 0;
|
|
36
|
+
waitForCallback = opts.waitForCallbackImpl;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const listener = await startCallbackListener(state);
|
|
40
|
+
port = listener.port;
|
|
41
|
+
waitForCallback = listener.wait;
|
|
42
|
+
}
|
|
43
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
44
|
+
const authorizeUrl = `${opts.apiUrl}/oauth/authorize?response_type=code&client_id=${encodeURIComponent(clientId)}` +
|
|
45
|
+
`&redirect_uri=${encodeURIComponent(redirectUri)}&scope=${encodeURIComponent(scope)}` +
|
|
46
|
+
`&state=${state}&code_challenge=${challenge}&code_challenge_method=S256`;
|
|
47
|
+
console.log(`Opening browser for authorization: ${authorizeUrl}`);
|
|
48
|
+
try {
|
|
49
|
+
await openFn(authorizeUrl);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
53
|
+
console.error(`Could not launch browser (${msg}). Open the URL above manually.`);
|
|
54
|
+
}
|
|
55
|
+
const code = await waitForCallback(state);
|
|
56
|
+
const tokenRes = await fetchImpl(`${opts.apiUrl}/oauth/token`, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
59
|
+
body: new URLSearchParams({
|
|
60
|
+
grant_type: 'authorization_code',
|
|
61
|
+
code,
|
|
62
|
+
code_verifier: verifier,
|
|
63
|
+
redirect_uri: redirectUri,
|
|
64
|
+
client_id: clientId,
|
|
65
|
+
}).toString(),
|
|
66
|
+
});
|
|
67
|
+
if (tokenRes.status !== 200) {
|
|
68
|
+
const body = await tokenRes.text();
|
|
69
|
+
throw new Error(`/oauth/token exchange failed (${tokenRes.status}): ${body}`);
|
|
70
|
+
}
|
|
71
|
+
const body = (await tokenRes.json());
|
|
72
|
+
if (!body.access_token || !body.refresh_token) {
|
|
73
|
+
throw new Error('/oauth/token response missing access_token or refresh_token');
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
access_token: body.access_token,
|
|
77
|
+
refresh_token: body.refresh_token,
|
|
78
|
+
access_token_expires_at: Math.floor(Date.now() / 1000) + (body.expires_in ?? 0),
|
|
79
|
+
token_type: body.token_type ?? 'Bearer',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export async function refreshAccessToken(opts) {
|
|
83
|
+
const clientId = opts.clientId ?? 'mootup-cli';
|
|
84
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
85
|
+
const res = await fetchImpl(`${opts.apiUrl}/oauth/token`, {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
88
|
+
body: new URLSearchParams({
|
|
89
|
+
grant_type: 'refresh_token',
|
|
90
|
+
refresh_token: opts.refreshToken,
|
|
91
|
+
client_id: clientId,
|
|
92
|
+
}).toString(),
|
|
93
|
+
});
|
|
94
|
+
if (res.status !== 200) {
|
|
95
|
+
const body = await res.text();
|
|
96
|
+
throw new Error(`/oauth/token refresh failed (${res.status}): ${body}`);
|
|
97
|
+
}
|
|
98
|
+
const body = (await res.json());
|
|
99
|
+
return {
|
|
100
|
+
access_token: body.access_token,
|
|
101
|
+
refresh_token: body.refresh_token,
|
|
102
|
+
access_token_expires_at: Math.floor(Date.now() / 1000) + (body.expires_in ?? 0),
|
|
103
|
+
token_type: body.token_type ?? 'Bearer',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export async function revokeRefreshToken(opts) {
|
|
107
|
+
const clientId = opts.clientId ?? 'mootup-cli';
|
|
108
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
109
|
+
await fetchImpl(`${opts.apiUrl}/oauth/revoke`, {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
112
|
+
body: new URLSearchParams({
|
|
113
|
+
token: opts.refreshToken,
|
|
114
|
+
client_id: clientId,
|
|
115
|
+
}).toString(),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async function openBrowser(url) {
|
|
119
|
+
const cmd = process.platform === 'darwin'
|
|
120
|
+
? 'open'
|
|
121
|
+
: process.platform === 'win32'
|
|
122
|
+
? 'start'
|
|
123
|
+
: 'xdg-open';
|
|
124
|
+
const child = spawn(cmd, [url], { stdio: 'ignore', detached: true, shell: process.platform === 'win32' });
|
|
125
|
+
child.unref();
|
|
126
|
+
}
|
|
127
|
+
async function startCallbackListener(expectedState) {
|
|
128
|
+
let server;
|
|
129
|
+
let resolveWait;
|
|
130
|
+
let rejectWait;
|
|
131
|
+
const waitPromise = new Promise((resolve, reject) => {
|
|
132
|
+
resolveWait = resolve;
|
|
133
|
+
rejectWait = reject;
|
|
134
|
+
});
|
|
135
|
+
server = createServer((socket) => {
|
|
136
|
+
let buf = '';
|
|
137
|
+
socket.on('data', (chunk) => {
|
|
138
|
+
buf += chunk.toString('utf8');
|
|
139
|
+
const headerEnd = buf.indexOf('\r\n\r\n');
|
|
140
|
+
if (headerEnd === -1)
|
|
141
|
+
return;
|
|
142
|
+
const firstLine = buf.slice(0, buf.indexOf('\r\n'));
|
|
143
|
+
const match = firstLine.match(/^GET\s+(\S+)\s+HTTP/);
|
|
144
|
+
if (!match) {
|
|
145
|
+
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const pathAndQuery = match[1];
|
|
149
|
+
const url = new URL(pathAndQuery, 'http://localhost');
|
|
150
|
+
const gotState = url.searchParams.get('state');
|
|
151
|
+
const gotCode = url.searchParams.get('code');
|
|
152
|
+
const gotError = url.searchParams.get('error');
|
|
153
|
+
if (gotError) {
|
|
154
|
+
sendResponse(socket, 400, `OAuth error: ${gotError}. You can close this window.`);
|
|
155
|
+
rejectWait(new Error(`OAuth error: ${gotError}`));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (!gotState || !gotCode || gotState !== expectedState) {
|
|
159
|
+
sendResponse(socket, 400, 'OAuth state mismatch. You can close this window.');
|
|
160
|
+
rejectWait(new Error('OAuth state mismatch'));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
sendResponse(socket, 200, 'Authorization received. You can close this window.');
|
|
164
|
+
resolveWait(gotCode);
|
|
165
|
+
});
|
|
166
|
+
socket.on('error', () => {
|
|
167
|
+
// ignore
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
await new Promise((resolve, reject) => {
|
|
171
|
+
server.once('error', reject);
|
|
172
|
+
server.listen(0, '127.0.0.1', resolve);
|
|
173
|
+
});
|
|
174
|
+
const address = server.address();
|
|
175
|
+
const port = typeof address === 'object' && address ? address.port : 0;
|
|
176
|
+
return {
|
|
177
|
+
port,
|
|
178
|
+
wait: async (expected) => {
|
|
179
|
+
try {
|
|
180
|
+
const code = await waitPromise;
|
|
181
|
+
return code;
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
server.close();
|
|
185
|
+
}
|
|
186
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
187
|
+
void expected;
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function sendResponse(socket, status, body) {
|
|
192
|
+
const reason = status === 200 ? 'OK' : 'Bad Request';
|
|
193
|
+
socket.end(`HTTP/1.1 ${status} ${reason}\r\n` +
|
|
194
|
+
'Content-Type: text/plain; charset=utf-8\r\n' +
|
|
195
|
+
`Content-Length: ${Buffer.byteLength(body)}\r\n` +
|
|
196
|
+
'Connection: close\r\n' +
|
|
197
|
+
'\r\n' +
|
|
198
|
+
body);
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/auth/oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../src/auth/profile.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,QAAkB,CAAC;AAE1C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMrD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/auth/profile.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,eAAe,CAAC;AAE1C,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,yBAAyB,OAAO,iBAAiB,UAAU,GAAG,CAC/D,CAAC;IACJ,CAAC;AACH,CAAC"}
|
package/dist/bin.js
CHANGED
|
@@ -7,24 +7,42 @@ import { cmdDown } from './commands/down.js';
|
|
|
7
7
|
import { cmdStatus } from './commands/status.js';
|
|
8
8
|
import { cmdAttach } from './commands/attach.js';
|
|
9
9
|
import { cmdCompact } from './commands/compact.js';
|
|
10
|
+
import { cmdLogout } from './commands/logout.js';
|
|
11
|
+
import { cmdRefresh } from './commands/refresh.js';
|
|
10
12
|
const program = new Command();
|
|
11
13
|
program
|
|
12
|
-
.name('
|
|
14
|
+
.name('moot')
|
|
13
15
|
.description('Host-side operator CLI for the Moot agent team workflow')
|
|
14
|
-
.version('0.1.0
|
|
16
|
+
.version('0.1.0');
|
|
15
17
|
program
|
|
16
18
|
.command('login')
|
|
17
19
|
.description('Authenticate against mootup.io and store credential')
|
|
18
20
|
.option('--token <pat>', 'Personal access token (prompts if omitted)')
|
|
19
21
|
.option('--api-url <url>', 'Moot API URL', 'https://mootup.io')
|
|
22
|
+
.option('--profile <name>', 'Named profile (default "default")')
|
|
20
23
|
.action((opts) => cmdLogin(opts));
|
|
21
24
|
program
|
|
22
25
|
.command('init')
|
|
23
|
-
.description('
|
|
26
|
+
.description('Authenticate (OAuth), select harness + archetype, install team, write .moot/actors.json')
|
|
24
27
|
.option('--force', 'Rotate keys for already-keyed agents (destructive)', false)
|
|
25
28
|
.option('--yes', 'Skip all confirmation prompts', false)
|
|
26
29
|
.option('--api-url <url>', 'Moot API URL (overrides stored credential)')
|
|
30
|
+
.option('--profile <name>', 'Named profile (default "default")')
|
|
31
|
+
.option('--archetype <id>', 'Archetype to install (skips prompt)')
|
|
32
|
+
.option('--harness <name>', 'Harness integration (claude-code, cursor-agent, cursor-ide, sdk)', 'claude-code')
|
|
33
|
+
.option('--show-token', 'For --harness sdk, print the full PAT plaintext', false)
|
|
27
34
|
.action((opts) => cmdInit(opts));
|
|
35
|
+
program
|
|
36
|
+
.command('logout')
|
|
37
|
+
.description('Revoke OAuth installation and clear local credential')
|
|
38
|
+
.option('--profile <name>', 'Named profile (default "default")')
|
|
39
|
+
.option('--all', 'Revoke all installations (alias for logout; multi-install deferred)', false)
|
|
40
|
+
.action((opts) => cmdLogout(opts));
|
|
41
|
+
program
|
|
42
|
+
.command('refresh')
|
|
43
|
+
.description('Refresh the stored OAuth access token')
|
|
44
|
+
.option('--profile <name>', 'Named profile (default "default")')
|
|
45
|
+
.action((opts) => cmdRefresh(opts));
|
|
28
46
|
program
|
|
29
47
|
.command('up')
|
|
30
48
|
.description('Bring the devcontainer up and start the agent team')
|