@mootup/moot-cli 0.1.0-rc.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.
Files changed (46) hide show
  1. package/README.md +76 -0
  2. package/dist/bin.d.ts +3 -0
  3. package/dist/bin.d.ts.map +1 -0
  4. package/dist/bin.js +52 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/commands/attach.d.ts +8 -0
  7. package/dist/commands/attach.d.ts.map +1 -0
  8. package/dist/commands/attach.js +8 -0
  9. package/dist/commands/attach.js.map +1 -0
  10. package/dist/commands/compact.d.ts +8 -0
  11. package/dist/commands/compact.d.ts.map +1 -0
  12. package/dist/commands/compact.js +14 -0
  13. package/dist/commands/compact.js.map +1 -0
  14. package/dist/commands/down.d.ts +8 -0
  15. package/dist/commands/down.d.ts.map +1 -0
  16. package/dist/commands/down.js +12 -0
  17. package/dist/commands/down.js.map +1 -0
  18. package/dist/commands/init.d.ts +10 -0
  19. package/dist/commands/init.d.ts.map +1 -0
  20. package/dist/commands/init.js +194 -0
  21. package/dist/commands/init.js.map +1 -0
  22. package/dist/commands/login.d.ts +8 -0
  23. package/dist/commands/login.d.ts.map +1 -0
  24. package/dist/commands/login.js +44 -0
  25. package/dist/commands/login.js.map +1 -0
  26. package/dist/commands/status.d.ts +7 -0
  27. package/dist/commands/status.d.ts.map +1 -0
  28. package/dist/commands/status.js +11 -0
  29. package/dist/commands/status.js.map +1 -0
  30. package/dist/commands/up.d.ts +7 -0
  31. package/dist/commands/up.d.ts.map +1 -0
  32. package/dist/commands/up.js +14 -0
  33. package/dist/commands/up.js.map +1 -0
  34. package/dist/credential.d.ts +13 -0
  35. package/dist/credential.d.ts.map +1 -0
  36. package/dist/credential.js +56 -0
  37. package/dist/credential.js.map +1 -0
  38. package/dist/docker.d.ts +46 -0
  39. package/dist/docker.d.ts.map +1 -0
  40. package/dist/docker.js +99 -0
  41. package/dist/docker.js.map +1 -0
  42. package/dist/index.d.ts +10 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +10 -0
  45. package/dist/index.js.map +1 -0
  46. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # @mootup/moot-cli
2
+
3
+ Host-side operator CLI for the Moot agent team workflow. Bin name: `mootup`.
4
+
5
+ ## Install
6
+
7
+ One-off via `npx`:
8
+
9
+ npx @mootup/moot-cli login
10
+ npx @mootup/moot-cli init
11
+
12
+ Or global install:
13
+
14
+ npm i -g @mootup/moot-cli
15
+ mootup login
16
+ mootup init
17
+
18
+ Requires Node ≥ 20, Docker, and [`@devcontainers/cli`](https://github.com/devcontainers/cli) on `PATH`:
19
+
20
+ npm i -g @devcontainers/cli
21
+
22
+ ## First-use flow
23
+
24
+ ```bash
25
+ # 1. Create a personal access token at https://mootup.io/settings/api-keys
26
+ # 2. Authenticate (stored under ~/.mootup/credentials.json, mode 0600):
27
+ mootup login
28
+
29
+ # 3. Provision actors and install .devcontainer/ in your repo:
30
+ cd my-project
31
+ mootup init
32
+
33
+ # 4. Bring the devcontainer up and start the agent team:
34
+ mootup up
35
+
36
+ # 5. Inspect, attach, compact as needed:
37
+ mootup status
38
+ mootup attach leader
39
+ mootup compact spec
40
+
41
+ # 6. Stop everything:
42
+ mootup down
43
+ ```
44
+
45
+ ## Command reference
46
+
47
+ | Command | Runs | Delegates to |
48
+ |---|---|---|
49
+ | `mootup login [--token <pat>] [--api-url <url>]` | host | writes `~/.mootup/credentials.json` |
50
+ | `mootup init [--force] [--yes] [--api-url <url>]` | host | rotates actor keys, writes `.moot/actors.json`, copies `.devcontainer/` |
51
+ | `mootup up` | host → container | `devcontainer up` + `docker exec <cid> moot up` |
52
+ | `mootup down [role]` | container | `docker exec <cid> moot down [role]` |
53
+ | `mootup status` | container | `docker exec <cid> moot status` |
54
+ | `mootup attach <role>` | container | `docker exec -it <cid> moot attach <role>` |
55
+ | `mootup compact [role]` | container | `docker exec <cid> moot compact [role]` |
56
+
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 `mootup up`.
58
+
59
+ ## Scope vs the Python CLI
60
+
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). `mootup init` in v0.1.0-rc.0 installs `.moot/actors.json` + `.devcontainer/` only; skill / CLAUDE.md / hook bundle installation is tracked as a follow-up run (v0.2.0).
62
+
63
+ ## Manual smoke test (operator)
64
+
65
+ Run from a fresh test directory after logging in:
66
+
67
+ mkdir /tmp/mootup-smoke && cd /tmp/mootup-smoke
68
+ git init
69
+ mootup init
70
+ test -f .moot/actors.json && echo "actors.json ✓"
71
+ test -d .devcontainer && echo "devcontainer ✓"
72
+ mootup up
73
+ mootup status
74
+ mootup down
75
+
76
+ `mootup 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.
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { cmdLogin } from './commands/login.js';
4
+ import { cmdInit } from './commands/init.js';
5
+ import { cmdUp } from './commands/up.js';
6
+ import { cmdDown } from './commands/down.js';
7
+ import { cmdStatus } from './commands/status.js';
8
+ import { cmdAttach } from './commands/attach.js';
9
+ import { cmdCompact } from './commands/compact.js';
10
+ const program = new Command();
11
+ program
12
+ .name('mootup')
13
+ .description('Host-side operator CLI for the Moot agent team workflow')
14
+ .version('0.1.0-rc.0');
15
+ program
16
+ .command('login')
17
+ .description('Authenticate against mootup.io and store credential')
18
+ .option('--token <pat>', 'Personal access token (prompts if omitted)')
19
+ .option('--api-url <url>', 'Moot API URL', 'https://mootup.io')
20
+ .action((opts) => cmdLogin(opts));
21
+ program
22
+ .command('init')
23
+ .description('Rotate actor keys, write .moot/actors.json, install .devcontainer/')
24
+ .option('--force', 'Rotate keys for already-keyed agents (destructive)', false)
25
+ .option('--yes', 'Skip all confirmation prompts', false)
26
+ .option('--api-url <url>', 'Moot API URL (overrides stored credential)')
27
+ .action((opts) => cmdInit(opts));
28
+ program
29
+ .command('up')
30
+ .description('Bring the devcontainer up and start the agent team')
31
+ .action(() => cmdUp({}));
32
+ program
33
+ .command('down [role]')
34
+ .description('Stop agents (optionally a specific role)')
35
+ .action((role) => cmdDown({ role }));
36
+ program
37
+ .command('status')
38
+ .description('Show running agents')
39
+ .action(() => cmdStatus({}));
40
+ program
41
+ .command('attach <role>')
42
+ .description('Attach to a role\'s tmux session')
43
+ .action((role) => cmdAttach({ role }));
44
+ program
45
+ .command('compact [role]')
46
+ .description('Compact a role\'s context (all roles if omitted)')
47
+ .action((role) => cmdCompact({ role }));
48
+ program.parseAsync(process.argv).catch((err) => {
49
+ console.error(err instanceof Error ? err.message : String(err));
50
+ process.exit(1);
51
+ });
52
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,yDAAyD,CAAC;KACtE,OAAO,CAAC,YAAY,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,qDAAqD,CAAC;KAClE,MAAM,CAAC,eAAe,EAAE,4CAA4C,CAAC;KACrE,MAAM,CAAC,iBAAiB,EAAE,cAAc,EAAE,mBAAmB,CAAC;KAC9D,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAEpC,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,oEAAoE,CAAC;KACjF,MAAM,CAAC,SAAS,EAAE,oDAAoD,EAAE,KAAK,CAAC;KAC9E,MAAM,CAAC,OAAO,EAAE,+BAA+B,EAAE,KAAK,CAAC;KACvD,MAAM,CAAC,iBAAiB,EAAE,4CAA4C,CAAC;KACvE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAEnC,OAAO;KACJ,OAAO,CAAC,IAAI,CAAC;KACb,WAAW,CAAC,oDAAoD,CAAC;KACjE,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AAE3B,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAEvC,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,qBAAqB,CAAC;KAClC,MAAM,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;AAE/B,OAAO;KACJ,OAAO,CAAC,eAAe,CAAC;KACxB,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAEzC,OAAO;KACJ,OAAO,CAAC,gBAAgB,CAAC;KACzB,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAE1C,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC7C,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type DockerDeps } from '../docker.js';
2
+ export interface AttachOptions {
3
+ role: string;
4
+ cwd?: string;
5
+ docker?: DockerDeps;
6
+ }
7
+ export declare function cmdAttach(opts: AttachOptions): Promise<void>;
8
+ //# sourceMappingURL=attach.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attach.d.ts","sourceRoot":"","sources":["../../src/commands/attach.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAUlE"}
@@ -0,0 +1,8 @@
1
+ import { requireContainerId, execInContainer, } from '../docker.js';
2
+ export async function cmdAttach(opts) {
3
+ const cwd = opts.cwd ?? process.cwd();
4
+ const docker = opts.docker ?? {};
5
+ const cid = requireContainerId(cwd, docker);
6
+ await execInContainer(cid, ['moot', 'attach', opts.role], { interactive: true }, docker);
7
+ }
8
+ //# sourceMappingURL=attach.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attach.js","sourceRoot":"","sources":["../../src/commands/attach.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,eAAe,GAEhB,MAAM,cAAc,CAAC;AAQtB,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAmB;IACjD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,eAAe,CACnB,GAAG,EACH,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,EAC7B,EAAE,WAAW,EAAE,IAAI,EAAE,EACrB,MAAM,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type DockerDeps } from '../docker.js';
2
+ export interface CompactOptions {
3
+ role?: string;
4
+ cwd?: string;
5
+ docker?: DockerDeps;
6
+ }
7
+ export declare function cmdCompact(opts: CompactOptions): Promise<void>;
8
+ //# sourceMappingURL=compact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact.d.ts","sourceRoot":"","sources":["../../src/commands/compact.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAWpE"}
@@ -0,0 +1,14 @@
1
+ import { requireContainerId, execInContainer, } from '../docker.js';
2
+ export async function cmdCompact(opts) {
3
+ const cwd = opts.cwd ?? process.cwd();
4
+ const docker = opts.docker ?? {};
5
+ const cid = requireContainerId(cwd, docker);
6
+ const args = opts.role
7
+ ? ['moot', 'compact', opts.role]
8
+ : ['moot', 'compact'];
9
+ const code = await execInContainer(cid, args, {}, docker);
10
+ if (code !== 0) {
11
+ throw new Error(`moot compact failed (exit code ${code})`);
12
+ }
13
+ }
14
+ //# sourceMappingURL=compact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact.js","sourceRoot":"","sources":["../../src/commands/compact.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,eAAe,GAEhB,MAAM,cAAc,CAAC;AAQtB,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAoB;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI;QACpB,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC;QAChC,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxB,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IAC1D,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,GAAG,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type DockerDeps } from '../docker.js';
2
+ export interface DownOptions {
3
+ role?: string;
4
+ cwd?: string;
5
+ docker?: DockerDeps;
6
+ }
7
+ export declare function cmdDown(opts: DownOptions): Promise<void>;
8
+ //# sourceMappingURL=down.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"down.d.ts","sourceRoot":"","sources":["../../src/commands/down.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAS9D"}
@@ -0,0 +1,12 @@
1
+ import { requireContainerId, execInContainer, } from '../docker.js';
2
+ export async function cmdDown(opts) {
3
+ const cwd = opts.cwd ?? process.cwd();
4
+ const docker = opts.docker ?? {};
5
+ const cid = requireContainerId(cwd, docker);
6
+ const args = opts.role ? ['moot', 'down', opts.role] : ['moot', 'down'];
7
+ const code = await execInContainer(cid, args, {}, docker);
8
+ if (code !== 0) {
9
+ throw new Error(`moot down failed (exit code ${code})`);
10
+ }
11
+ }
12
+ //# sourceMappingURL=down.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"down.js","sourceRoot":"","sources":["../../src/commands/down.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,eAAe,GAEhB,MAAM,cAAc,CAAC;AAQtB,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAiB;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IAC1D,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,GAAG,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface InitOptions {
2
+ force?: boolean;
3
+ yes?: boolean;
4
+ apiUrl?: string;
5
+ cwd?: string;
6
+ fetch?: typeof globalThis.fetch;
7
+ confirm?: (prompt: string) => Promise<boolean>;
8
+ }
9
+ export declare function cmdInit(opts: InitOptions): Promise<void>;
10
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAChD;AAiBD,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA0F9D"}
@@ -0,0 +1,194 @@
1
+ import { mkdirSync, existsSync, writeFileSync, chmodSync, copyFileSync, readdirSync, statSync, } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { createMootupClient } from '@mootup/moot-sdk';
4
+ import { getTemplatesDir } from '@mootup/moot-templates';
5
+ import { loadCredential } from '../credential.js';
6
+ async function defaultConfirm(prompt) {
7
+ const { createInterface } = await import('node:readline/promises');
8
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
9
+ const answer = (await rl.question(prompt)).trim().toLowerCase();
10
+ rl.close();
11
+ return answer === 'y' || answer === 'yes';
12
+ }
13
+ export async function cmdInit(opts) {
14
+ const cwd = opts.cwd ?? process.cwd();
15
+ const force = opts.force ?? false;
16
+ const yes = opts.yes ?? false;
17
+ const confirm = opts.confirm ?? defaultConfirm;
18
+ if (!existsSync(join(cwd, '.git'))) {
19
+ console.warn("Warning: this doesn't look like a git repository; " +
20
+ '.moot/ entries will not be versioned.');
21
+ }
22
+ const actorsPath = join(cwd, '.moot', 'actors.json');
23
+ if (existsSync(actorsPath) && !force) {
24
+ console.error(`Error: ${actorsPath} already exists.\n` +
25
+ `Use 'mootup init --force' to rotate keys (invalidates the current set).`);
26
+ throw new Error('actors.json already exists (use --force)');
27
+ }
28
+ const cred = loadCredential();
29
+ if (!cred) {
30
+ console.error("Error: not logged in. Run 'mootup login' first.");
31
+ throw new Error('not logged in');
32
+ }
33
+ const apiUrl = opts.apiUrl ?? cred.api_url;
34
+ const token = cred.token;
35
+ const client = createMootupClient({
36
+ baseUrl: apiUrl,
37
+ apiKey: token,
38
+ ...(opts.fetch ? { fetch: opts.fetch } : {}),
39
+ });
40
+ console.log(`Using profile default (authenticated on ${apiUrl})`);
41
+ const { spaceId } = await fetchActorAndSpace(client);
42
+ const spaceName = spaceId;
43
+ console.log(`Fetched your default space: ${spaceId}`);
44
+ const keyless = await fetchKeylessAgents(client, force);
45
+ if (keyless.length === 0) {
46
+ if (force) {
47
+ console.error('Error: no agents found in your default space to adopt.');
48
+ }
49
+ else {
50
+ console.error('Error: no keyless agents found in your default space.\n' +
51
+ "If you've run 'mootup init' before on this space, use " +
52
+ "'mootup init --force' to rotate the existing keys.");
53
+ }
54
+ throw new Error('no agents to adopt');
55
+ }
56
+ console.log(`Found ${keyless.length} ${force ? 'agents' : 'keyless agents'} in default space:`);
57
+ for (const a of keyless) {
58
+ console.log(` - ${a.display_name.padEnd(16)} (${a.actor_id})`);
59
+ }
60
+ if (force && !yes) {
61
+ const ok = await confirm(`This will rotate keys for ${keyless.length} agents. ` +
62
+ `Currently-connected agents will disconnect. Continue? [y/N] `);
63
+ if (!ok) {
64
+ console.log('Aborted.');
65
+ return;
66
+ }
67
+ }
68
+ console.log('\nRotating keys for keyless agents...');
69
+ const adopted = await rotateKeys(client, keyless, force);
70
+ writeActorsJson({
71
+ cwd,
72
+ spaceId,
73
+ spaceName,
74
+ apiUrl,
75
+ adopted,
76
+ });
77
+ console.log(`Wrote .moot/actors.json (${Object.keys(adopted).length} agents, chmod 600)`);
78
+ installDevcontainer({ cwd, overwrite: false });
79
+ console.log("\nDone. Run 'mootup up' to bring your team online.");
80
+ }
81
+ async function fetchActorAndSpace(client) {
82
+ const { data, response } = await client.GET('/api/actors/me');
83
+ if (response.status !== 200) {
84
+ throw new Error(`Could not fetch your account (${response.status}). ` +
85
+ `Your credential may have expired — run 'mootup login' again.`);
86
+ }
87
+ const actor = data;
88
+ const spaceId = actor?.default_space_id;
89
+ if (typeof spaceId !== 'string') {
90
+ throw new Error('Your account has no default space. Contact support.');
91
+ }
92
+ return { actor: actor ?? {}, spaceId };
93
+ }
94
+ async function fetchKeylessAgents(client, force) {
95
+ const { data, response } = await client.GET('/api/actors/me/agents');
96
+ if (response.status !== 200) {
97
+ throw new Error(`Could not list agents (${response.status})`);
98
+ }
99
+ const agents = data ?? [];
100
+ const out = [];
101
+ for (const a of agents) {
102
+ if (!a || typeof a !== 'object')
103
+ continue;
104
+ const r = a;
105
+ if (typeof r.actor_id !== 'string' ||
106
+ typeof r.display_name !== 'string' ||
107
+ r.actor_type !== 'agent')
108
+ continue;
109
+ const keyed = typeof r.api_key_prefix === 'string' && r.api_key_prefix.length > 0;
110
+ if (!force && keyed)
111
+ continue;
112
+ out.push({
113
+ actor_id: r.actor_id,
114
+ display_name: r.display_name,
115
+ actor_type: 'agent',
116
+ api_key_prefix: keyed ? r.api_key_prefix : null,
117
+ });
118
+ }
119
+ return out;
120
+ }
121
+ async function rotateKeys(client, agents, force) {
122
+ const adopted = {};
123
+ for (const agent of agents) {
124
+ const roleKey = agent.display_name.toLowerCase().replace(/ /g, '_');
125
+ const { data, response } = await client.POST('/api/actors/{actor_id}/rotate-key', {
126
+ params: { path: { actor_id: agent.actor_id } },
127
+ ...(force ? { headers: { 'X-Force-Rotate': 'true' } } : {}),
128
+ });
129
+ if (response.status !== 200 && response.status !== 201) {
130
+ throw new Error(`rotate-key failed for ${agent.display_name} (${response.status})`);
131
+ }
132
+ const body = data ?? {};
133
+ const apiKey = typeof body.api_key === 'string' ? body.api_key : '';
134
+ adopted[roleKey] = {
135
+ actor_id: agent.actor_id,
136
+ api_key: apiKey,
137
+ display_name: agent.display_name,
138
+ };
139
+ console.log(` ${agent.display_name.padEnd(16)} ✓`);
140
+ }
141
+ return adopted;
142
+ }
143
+ function writeActorsJson(args) {
144
+ const mootDir = join(args.cwd, '.moot');
145
+ if (!existsSync(mootDir)) {
146
+ mkdirSync(mootDir, { recursive: true, mode: 0o700 });
147
+ }
148
+ else {
149
+ chmodSync(mootDir, 0o700);
150
+ }
151
+ const content = {
152
+ space_id: args.spaceId,
153
+ space_name: args.spaceName,
154
+ api_url: args.apiUrl,
155
+ actors: args.adopted,
156
+ };
157
+ const actorsPath = join(mootDir, 'actors.json');
158
+ writeFileSync(actorsPath, JSON.stringify(content, null, 2) + '\n');
159
+ chmodSync(actorsPath, 0o600);
160
+ }
161
+ function installDevcontainer(args) {
162
+ const src = join(getTemplatesDir(), 'devcontainer');
163
+ const target = join(args.cwd, '.devcontainer');
164
+ const staged = join(args.cwd, '.moot', 'suggested-devcontainer');
165
+ const targetExists = existsSync(target);
166
+ if (targetExists && !args.overwrite) {
167
+ copyDirRecursive(src, staged);
168
+ console.log(`.devcontainer/ already exists — staged at .moot/suggested-devcontainer/`);
169
+ return;
170
+ }
171
+ copyDirRecursive(src, target);
172
+ const fileCount = readdirSync(target).length;
173
+ console.log(`Installed .devcontainer/ (${fileCount} files)`);
174
+ }
175
+ function copyDirRecursive(src, dest) {
176
+ if (!existsSync(dest)) {
177
+ mkdirSync(dest, { recursive: true });
178
+ }
179
+ for (const entry of readdirSync(src)) {
180
+ const s = join(src, entry);
181
+ const d = join(dest, entry);
182
+ const stats = statSync(s);
183
+ if (stats.isDirectory()) {
184
+ copyDirRecursive(s, d);
185
+ }
186
+ else {
187
+ copyFileSync(s, d);
188
+ if (entry.endsWith('.sh')) {
189
+ chmodSync(d, 0o755);
190
+ }
191
+ }
192
+ }
193
+ }
194
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface LoginOptions {
2
+ token?: string;
3
+ apiUrl?: string;
4
+ fetch?: typeof globalThis.fetch;
5
+ readToken?: () => Promise<string>;
6
+ }
7
+ export declare function cmdLogin(opts: LoginOptions): Promise<void>;
8
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACnC;AAeD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAoChE"}
@@ -0,0 +1,44 @@
1
+ import { createInterface } from 'node:readline/promises';
2
+ import { createMootupClient } from '@mootup/moot-sdk';
3
+ import { storeCredential, PAT_PREFIX, DEFAULT_API_URL, } from '../credential.js';
4
+ async function defaultReadToken() {
5
+ console.log('Create a personal access token at https://mootup.io/settings/api-keys');
6
+ const rl = createInterface({
7
+ input: process.stdin,
8
+ output: process.stdout,
9
+ });
10
+ const answer = await rl.question('Paste your token: ');
11
+ rl.close();
12
+ return answer.trim();
13
+ }
14
+ export async function cmdLogin(opts) {
15
+ const apiUrl = opts.apiUrl ?? DEFAULT_API_URL;
16
+ const token = opts.token ?? (await (opts.readToken ?? defaultReadToken)());
17
+ if (!token.startsWith(PAT_PREFIX)) {
18
+ console.error("That doesn't look like a Moot personal access token.\n" +
19
+ "Tokens start with 'mootup_pat_' — did you paste an agent " +
20
+ "API key (convo_key_...) by mistake?");
21
+ throw new Error('invalid PAT prefix');
22
+ }
23
+ const client = createMootupClient({
24
+ baseUrl: apiUrl,
25
+ apiKey: token,
26
+ ...(opts.fetch ? { fetch: opts.fetch } : {}),
27
+ });
28
+ const { data, response } = await client.GET('/api/actors/me');
29
+ if (response.status !== 200) {
30
+ console.error(`Error: authentication failed (${response.status})`);
31
+ throw new Error(`authentication failed (${response.status})`);
32
+ }
33
+ const actor = data;
34
+ if (!actor || typeof actor.actor_id !== 'string' || typeof actor.display_name !== 'string') {
35
+ throw new Error('unexpected /api/actors/me response shape');
36
+ }
37
+ storeCredential({
38
+ api_url: apiUrl,
39
+ token,
40
+ user_id: actor.actor_id,
41
+ });
42
+ console.log(`Authenticated as ${actor.display_name} (${actor.actor_id}) on ${apiUrl}`);
43
+ }
44
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EACL,eAAe,EACf,UAAU,EACV,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAS1B,KAAK,UAAU,gBAAgB;IAC7B,OAAO,CAAC,GAAG,CACT,uEAAuE,CACxE,CAAC;IACF,MAAM,EAAE,GAAG,eAAe,CAAC;QACzB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IACvD,EAAE,CAAC,KAAK,EAAE,CAAC;IACX,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAkB;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,eAAe,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAE3E,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CACX,wDAAwD;YACxD,2DAA2D;YAC3D,qCAAqC,CACtC,CAAC;QACF,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,MAAM,GAAG,kBAAkB,CAAC;QAChC,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,KAAK;QACb,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC,CAAC;IACH,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC9D,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,iCAAiC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,KAAK,GAAG,IAAgE,CAAC;IAC/E,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC3F,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IAED,eAAe,CAAC;QACd,OAAO,EAAE,MAAM;QACf,KAAK;QACL,OAAO,EAAE,KAAK,CAAC,QAAQ;KACxB,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CACT,oBAAoB,KAAK,CAAC,YAAY,KAAK,KAAK,CAAC,QAAQ,QAAQ,MAAM,EAAE,CAC1E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type DockerDeps } from '../docker.js';
2
+ export interface StatusOptions {
3
+ cwd?: string;
4
+ docker?: DockerDeps;
5
+ }
6
+ export declare function cmdStatus(opts: StatusOptions): Promise<void>;
7
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAQlE"}
@@ -0,0 +1,11 @@
1
+ import { requireContainerId, execInContainer, } from '../docker.js';
2
+ export async function cmdStatus(opts) {
3
+ const cwd = opts.cwd ?? process.cwd();
4
+ const docker = opts.docker ?? {};
5
+ const cid = requireContainerId(cwd, docker);
6
+ const code = await execInContainer(cid, ['moot', 'status'], {}, docker);
7
+ if (code !== 0) {
8
+ throw new Error(`moot status failed (exit code ${code})`);
9
+ }
10
+ }
11
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,eAAe,GAEhB,MAAM,cAAc,CAAC;AAOtB,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAmB;IACjD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IACxE,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,GAAG,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type DockerDeps } from '../docker.js';
2
+ export interface UpOptions {
3
+ cwd?: string;
4
+ docker?: DockerDeps;
5
+ }
6
+ export declare function cmdUp(opts: UpOptions): Promise<void>;
7
+ //# sourceMappingURL=up.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"up.d.ts","sourceRoot":"","sources":["../../src/commands/up.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,wBAAsB,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAW1D"}
@@ -0,0 +1,14 @@
1
+ import { containerIdOrNone, devcontainerUp, execInContainer, } from '../docker.js';
2
+ export async function cmdUp(opts) {
3
+ const cwd = opts.cwd ?? process.cwd();
4
+ const docker = opts.docker ?? {};
5
+ let cid = containerIdOrNone(cwd, docker);
6
+ if (!cid) {
7
+ cid = await devcontainerUp(cwd, docker);
8
+ }
9
+ const code = await execInContainer(cid, ['moot', 'up'], {}, docker);
10
+ if (code !== 0) {
11
+ throw new Error(`moot up failed (exit code ${code})`);
12
+ }
13
+ }
14
+ //# sourceMappingURL=up.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"up.js","sourceRoot":"","sources":["../../src/commands/up.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,eAAe,GAEhB,MAAM,cAAc,CAAC;AAOtB,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAe;IACzC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IACjC,IAAI,GAAG,GAAG,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACzC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IACpE,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,GAAG,CAAC,CAAC;IACxD,CAAC;AACH,CAAC"}
@@ -0,0 +1,13 @@
1
+ export declare const CRED_DIR: string;
2
+ export declare const CRED_FILE: string;
3
+ export declare const PAT_PREFIX = "mootup_pat_";
4
+ export declare const DEFAULT_API_URL = "https://mootup.io";
5
+ export interface Credential {
6
+ api_url: string;
7
+ token: string;
8
+ user_id: string;
9
+ }
10
+ export type CredentialsFile = Record<string, Credential>;
11
+ export declare function loadCredential(profile?: string): Credential | null;
12
+ export declare function storeCredential(cred: Credential, profile?: string): void;
13
+ //# sourceMappingURL=credential.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.d.ts","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,QAAQ,QAA6B,CAAC;AACnD,eAAO,MAAM,SAAS,QAAqC,CAAC;AAC5D,eAAO,MAAM,UAAU,gBAAgB,CAAC;AACxC,eAAO,MAAM,eAAe,sBAAsB,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAEzD,wBAAgB,cAAc,CAAC,OAAO,SAAY,GAAG,UAAU,GAAG,IAAI,CAqBrE;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,OAAO,SAAY,GAClB,IAAI,CAqBN"}
@@ -0,0 +1,56 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ export const CRED_DIR = join(homedir(), '.mootup');
5
+ export const CRED_FILE = join(CRED_DIR, 'credentials.json');
6
+ export const PAT_PREFIX = 'mootup_pat_';
7
+ export const DEFAULT_API_URL = 'https://mootup.io';
8
+ export function loadCredential(profile = 'default') {
9
+ if (!existsSync(CRED_FILE))
10
+ return null;
11
+ const raw = readFileSync(CRED_FILE, 'utf8');
12
+ let parsed;
13
+ try {
14
+ parsed = JSON.parse(raw);
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ if (!parsed || typeof parsed !== 'object')
20
+ return null;
21
+ const cred = parsed[profile];
22
+ if (!cred || typeof cred !== 'object')
23
+ return null;
24
+ const c = cred;
25
+ if (typeof c.api_url !== 'string' ||
26
+ typeof c.token !== 'string' ||
27
+ typeof c.user_id !== 'string') {
28
+ return null;
29
+ }
30
+ return { api_url: c.api_url, token: c.token, user_id: c.user_id };
31
+ }
32
+ export function storeCredential(cred, profile = 'default') {
33
+ if (!existsSync(CRED_DIR)) {
34
+ mkdirSync(CRED_DIR, { recursive: true, mode: 0o700 });
35
+ }
36
+ else {
37
+ chmodSync(CRED_DIR, 0o700);
38
+ }
39
+ let existing = {};
40
+ if (existsSync(CRED_FILE)) {
41
+ try {
42
+ const raw = readFileSync(CRED_FILE, 'utf8');
43
+ const parsed = JSON.parse(raw);
44
+ if (parsed && typeof parsed === 'object') {
45
+ existing = parsed;
46
+ }
47
+ }
48
+ catch {
49
+ existing = {};
50
+ }
51
+ }
52
+ existing[profile] = cred;
53
+ writeFileSync(CRED_FILE, JSON.stringify(existing, null, 2) + '\n');
54
+ chmodSync(CRED_FILE, 0o600);
55
+ }
56
+ //# sourceMappingURL=credential.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.js","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AACnD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;AAC5D,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC;AACxC,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAUnD,MAAM,UAAU,cAAc,CAAC,OAAO,GAAG,SAAS;IAChD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC5C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACvD,MAAM,IAAI,GAAI,MAAkC,CAAC,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,IACE,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ;QAC7B,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAC3B,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,EAC7B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,IAAgB,EAChB,OAAO,GAAG,SAAS;IAEnB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,CAAC;SAAM,CAAC;QACN,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,QAAQ,GAAoB,EAAE,CAAC;IACnC,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;YAC1C,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACzC,QAAQ,GAAG,MAAyB,CAAC;YACvC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IACD,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IACzB,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACnE,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { type SpawnOptions } from 'node:child_process';
2
+ export interface SpawnResult {
3
+ status: number | null;
4
+ stdout: string;
5
+ stderr: string;
6
+ }
7
+ export type SpawnFn = (cmd: string, args: readonly string[], options?: SpawnOptions) => SpawnResult;
8
+ export type ExecFn = (cmd: string, args: readonly string[], options?: {
9
+ stdio?: 'inherit' | 'pipe';
10
+ env?: Record<string, string>;
11
+ }) => Promise<number>;
12
+ export declare const defaultSpawnSync: SpawnFn;
13
+ export declare const defaultSpawnAsync: ExecFn;
14
+ export interface DockerDeps {
15
+ spawnSyncFn?: SpawnFn;
16
+ spawnAsyncFn?: ExecFn;
17
+ }
18
+ /**
19
+ * Return the running container id for `workspace`, or null if not running.
20
+ * Mirrors Python moot-cli's container_id_or_none: filters docker ps by the
21
+ * `devcontainer.local_folder` label that @devcontainers/cli stamps on every
22
+ * container it creates.
23
+ */
24
+ export declare function containerIdOrNone(workspace: string, deps?: DockerDeps): string | null;
25
+ /**
26
+ * Run `devcontainer up --workspace-folder <workspace>`. Streams stdout/stderr
27
+ * to the user's terminal. Returns the container id after up; throws if no
28
+ * container is running after up exits 0.
29
+ */
30
+ export declare function devcontainerUp(workspace: string, deps?: DockerDeps): Promise<string>;
31
+ /**
32
+ * Run `docker exec --user node [-it] <cid> <args...>`. Streams output via
33
+ * stdio: 'inherit'. Returns exit code. Interactive mode adds TERM + LANG
34
+ * env vars so tmux attach works across host terminals (mirrors Python's
35
+ * exec_interactive behavior).
36
+ */
37
+ export declare function execInContainer(cid: string, args: readonly string[], options?: {
38
+ interactive?: boolean;
39
+ }, deps?: DockerDeps): Promise<number>;
40
+ /**
41
+ * Helper: look up cid for cwd or throw the standard "no container" error.
42
+ * Used by every delegated command (down/status/attach/compact) and by up's
43
+ * post-devcontainer-up re-lookup.
44
+ */
45
+ export declare function requireContainerId(workspace: string, deps?: DockerDeps): string;
46
+ //# sourceMappingURL=docker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../src/docker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGzE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,OAAO,GAAG,CACpB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE,YAAY,KACnB,WAAW,CAAC;AAEjB,MAAM,MAAM,MAAM,GAAG,CACnB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,KACnE,OAAO,CAAC,MAAM,CAAC,CAAC;AAErB,eAAO,MAAM,gBAAgB,EAAE,OAU9B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,MAQ5B,CAAC;AAEL,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,UAAe,GACpB,MAAM,GAAG,IAAI,CAUf;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,UAAe,GACpB,OAAO,CAAC,MAAM,CAAC,CAsBjB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,EACvC,IAAI,GAAE,UAAe,GACpB,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,UAAe,GACpB,MAAM,CASR"}
package/dist/docker.js ADDED
@@ -0,0 +1,99 @@
1
+ import { spawn, spawnSync } from 'node:child_process';
2
+ import { resolve } from 'node:path';
3
+ export const defaultSpawnSync = (cmd, args, options) => {
4
+ const proc = spawnSync(cmd, [...args], {
5
+ encoding: 'utf8',
6
+ ...(options ?? {}),
7
+ });
8
+ return {
9
+ status: proc.status,
10
+ stdout: typeof proc.stdout === 'string' ? proc.stdout : '',
11
+ stderr: typeof proc.stderr === 'string' ? proc.stderr : '',
12
+ };
13
+ };
14
+ export const defaultSpawnAsync = (cmd, args, options) => new Promise((resolveP, reject) => {
15
+ const proc = spawn(cmd, [...args], {
16
+ stdio: options?.stdio ?? 'inherit',
17
+ env: { ...process.env, ...(options?.env ?? {}) },
18
+ });
19
+ proc.on('error', reject);
20
+ proc.on('exit', (code) => resolveP(code ?? 1));
21
+ });
22
+ /**
23
+ * Return the running container id for `workspace`, or null if not running.
24
+ * Mirrors Python moot-cli's container_id_or_none: filters docker ps by the
25
+ * `devcontainer.local_folder` label that @devcontainers/cli stamps on every
26
+ * container it creates.
27
+ */
28
+ export function containerIdOrNone(workspace, deps = {}) {
29
+ const spawnFn = deps.spawnSyncFn ?? defaultSpawnSync;
30
+ const absPath = resolve(workspace);
31
+ const result = spawnFn('docker', [
32
+ 'ps', '-q',
33
+ '--filter', `label=devcontainer.local_folder=${absPath}`,
34
+ ]);
35
+ if (result.status !== 0)
36
+ return null;
37
+ const ids = result.stdout.trim().split('\n').filter(Boolean);
38
+ return ids.length > 0 ? ids[0] ?? null : null;
39
+ }
40
+ /**
41
+ * Run `devcontainer up --workspace-folder <workspace>`. Streams stdout/stderr
42
+ * to the user's terminal. Returns the container id after up; throws if no
43
+ * container is running after up exits 0.
44
+ */
45
+ export async function devcontainerUp(workspace, deps = {}) {
46
+ const spawnFn = deps.spawnAsyncFn ?? defaultSpawnAsync;
47
+ const alreadyRunning = containerIdOrNone(workspace, deps) !== null;
48
+ if (!alreadyRunning) {
49
+ console.log(`Building devcontainer in ${workspace} ` +
50
+ `(first launch can take 1-3 minutes)...`);
51
+ }
52
+ const code = await spawnFn('devcontainer', [
53
+ 'up', '--workspace-folder', workspace,
54
+ ]);
55
+ if (code !== 0) {
56
+ throw new Error(`devcontainer up failed (exit code ${code})`);
57
+ }
58
+ const cid = containerIdOrNone(workspace, deps);
59
+ if (!cid) {
60
+ throw new Error(`devcontainer up exited 0 but no running container was found for ${workspace}`);
61
+ }
62
+ return cid;
63
+ }
64
+ /**
65
+ * Run `docker exec --user node [-it] <cid> <args...>`. Streams output via
66
+ * stdio: 'inherit'. Returns exit code. Interactive mode adds TERM + LANG
67
+ * env vars so tmux attach works across host terminals (mirrors Python's
68
+ * exec_interactive behavior).
69
+ */
70
+ export async function execInContainer(cid, args, options = {}, deps = {}) {
71
+ const spawnFn = deps.spawnAsyncFn ?? defaultSpawnAsync;
72
+ const dockerArgs = ['exec'];
73
+ if (options.interactive) {
74
+ dockerArgs.push('-it');
75
+ }
76
+ dockerArgs.push('--user', 'node');
77
+ if (options.interactive) {
78
+ dockerArgs.push('-e', 'TERM=xterm-256color', '-e', 'LANG=C.UTF-8');
79
+ const colorterm = process.env.COLORTERM;
80
+ if (colorterm)
81
+ dockerArgs.push('-e', `COLORTERM=${colorterm}`);
82
+ }
83
+ dockerArgs.push(cid, ...args);
84
+ return spawnFn('docker', dockerArgs, { stdio: 'inherit' });
85
+ }
86
+ /**
87
+ * Helper: look up cid for cwd or throw the standard "no container" error.
88
+ * Used by every delegated command (down/status/attach/compact) and by up's
89
+ * post-devcontainer-up re-lookup.
90
+ */
91
+ export function requireContainerId(workspace, deps = {}) {
92
+ const cid = containerIdOrNone(workspace, deps);
93
+ if (!cid) {
94
+ throw new Error(`No running devcontainer found for ${resolve(workspace)}.\n` +
95
+ `Run 'mootup up' first.`);
96
+ }
97
+ return cid;
98
+ }
99
+ //# sourceMappingURL=docker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.js","sourceRoot":"","sources":["../src/docker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export { cmdLogin } from './commands/login.js';
2
+ export { cmdInit } from './commands/init.js';
3
+ export { cmdUp } from './commands/up.js';
4
+ export { cmdDown } from './commands/down.js';
5
+ export { cmdStatus } from './commands/status.js';
6
+ export { cmdAttach } from './commands/attach.js';
7
+ export { cmdCompact } from './commands/compact.js';
8
+ export { containerIdOrNone, execInContainer, devcontainerUp, type ExecFn, type SpawnFn, } from './docker.js';
9
+ export { loadCredential, storeCredential, CRED_DIR, CRED_FILE, type Credential, } from './credential.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,KAAK,MAAM,EACX,KAAK,OAAO,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,cAAc,EACd,eAAe,EACf,QAAQ,EACR,SAAS,EACT,KAAK,UAAU,GAChB,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export { cmdLogin } from './commands/login.js';
2
+ export { cmdInit } from './commands/init.js';
3
+ export { cmdUp } from './commands/up.js';
4
+ export { cmdDown } from './commands/down.js';
5
+ export { cmdStatus } from './commands/status.js';
6
+ export { cmdAttach } from './commands/attach.js';
7
+ export { cmdCompact } from './commands/compact.js';
8
+ export { containerIdOrNone, execInContainer, devcontainerUp, } from './docker.js';
9
+ export { loadCredential, storeCredential, CRED_DIR, CRED_FILE, } from './credential.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,cAAc,GAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,cAAc,EACd,eAAe,EACf,QAAQ,EACR,SAAS,GAEV,MAAM,iBAAiB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@mootup/moot-cli",
3
+ "version": "0.1.0-rc.0",
4
+ "description": "Host-side operator CLI for the Moot agent team workflow. Wraps devcontainer launch and delegates in-container work to the Python moot CLI via docker exec.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "mootup": "./dist/bin.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md"
21
+ ],
22
+ "engines": {
23
+ "node": ">=20.0.0"
24
+ },
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.build.json && chmod +x dist/bin.js",
27
+ "test": "vitest run",
28
+ "test:watch": "vitest",
29
+ "lint": "tsc --noEmit",
30
+ "prepublishOnly": "npm run build && npm test"
31
+ },
32
+ "dependencies": {
33
+ "@mootup/moot-sdk": "*",
34
+ "@mootup/moot-templates": "*",
35
+ "commander": "^12.1.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.14.0",
39
+ "msw": "^2.4.0",
40
+ "typescript": "^5.5.0",
41
+ "vitest": "^2.1.0"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ }
46
+ }