claude-maestro 0.1.16
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 +130 -0
- package/bin/maestro.mjs +45 -0
- package/out/main/index.js +5293 -0
- package/out/preload/index.js +130 -0
- package/out/renderer/assets/apl-fqmucPXA.js +140 -0
- package/out/renderer/assets/asciiarmor-DucZyvP0.js +56 -0
- package/out/renderer/assets/asn1-BnOEsgAm.js +144 -0
- package/out/renderer/assets/asterisk-QAlztEwS.js +345 -0
- package/out/renderer/assets/brainfuck-DZVCuF_t.js +53 -0
- package/out/renderer/assets/clike-xqXYL6ge.js +805 -0
- package/out/renderer/assets/clojure-BhXMqnxz.js +849 -0
- package/out/renderer/assets/cmake-BGaNd9E7.js +71 -0
- package/out/renderer/assets/cobol-4yqQntpt.js +120 -0
- package/out/renderer/assets/coffeescript-D2dXvhEc.js +308 -0
- package/out/renderer/assets/commonlisp-CF_VNHQR.js +130 -0
- package/out/renderer/assets/crystal-DyuLTqLs.js +398 -0
- package/out/renderer/assets/css-c-jst79C.js +1783 -0
- package/out/renderer/assets/cypher-Dlu_3r4V.js +121 -0
- package/out/renderer/assets/d-UURgV0Ux.js +179 -0
- package/out/renderer/assets/diff-B_Bi2Crb.js +25 -0
- package/out/renderer/assets/dockerfile-Bvk733Ga.js +201 -0
- package/out/renderer/assets/dtd-Dy74G54E.js +114 -0
- package/out/renderer/assets/dylan-TSb-Nfix.js +314 -0
- package/out/renderer/assets/ebnf-4fKAGW3a.js +140 -0
- package/out/renderer/assets/ecl-B59qGGVg.js +178 -0
- package/out/renderer/assets/eiffel-Dze7nlu3.js +134 -0
- package/out/renderer/assets/elm-DG7jkhNZ.js +176 -0
- package/out/renderer/assets/erlang-BO6gOnGA.js +674 -0
- package/out/renderer/assets/factor-CMxFHDqz.js +65 -0
- package/out/renderer/assets/fcl-CDDUNjTj.js +141 -0
- package/out/renderer/assets/forth-B9D2JCeE.js +116 -0
- package/out/renderer/assets/fortran-CAG2BFbe.js +467 -0
- package/out/renderer/assets/gas-d3KEcW3x.js +294 -0
- package/out/renderer/assets/gherkin-DhZlEZiy.js +115 -0
- package/out/renderer/assets/groovy-CpwJiBl7.js +223 -0
- package/out/renderer/assets/haskell-ySd-OUo8.js +459 -0
- package/out/renderer/assets/haxe-7MlzfeYV.js +514 -0
- package/out/renderer/assets/http-BqypyemW.js +79 -0
- package/out/renderer/assets/idl-4HIGJlDI.js +985 -0
- package/out/renderer/assets/index-2SQReYbL.js +117 -0
- package/out/renderer/assets/index-B4G_DF7l.js +178 -0
- package/out/renderer/assets/index-BJ7HHtlW.css +4015 -0
- package/out/renderer/assets/index-BLk1t3tc.js +151 -0
- package/out/renderer/assets/index-BLtm0KYA.js +157 -0
- package/out/renderer/assets/index-BPgGZ4iY.js +82 -0
- package/out/renderer/assets/index-BQE9vCdv.js +332 -0
- package/out/renderer/assets/index-BYr39Do3.js +61 -0
- package/out/renderer/assets/index-Ba0sUbhl.js +47177 -0
- package/out/renderer/assets/index-BewSkGJT.js +1041 -0
- package/out/renderer/assets/index-BnId7J8H.js +1021 -0
- package/out/renderer/assets/index-Btn996gP.js +406 -0
- package/out/renderer/assets/index-C7i4WyfA.js +311 -0
- package/out/renderer/assets/index-CW9SAu99.js +385 -0
- package/out/renderer/assets/index-CXmk7jHk.js +291 -0
- package/out/renderer/assets/index-CyQp9UDR.js +82 -0
- package/out/renderer/assets/index-Da2gJ_Wd.js +704 -0
- package/out/renderer/assets/index-DkFO-IXC.js +2488 -0
- package/out/renderer/assets/index-DqrDpNqn.js +689 -0
- package/out/renderer/assets/index-Dw7p19YD.js +327 -0
- package/out/renderer/assets/index-QPm3UFYR.js +97 -0
- package/out/renderer/assets/index-RGiHNShF.js +1768 -0
- package/out/renderer/assets/index-RgZE5T_I.js +642 -0
- package/out/renderer/assets/index-t8kJBumF.js +312 -0
- package/out/renderer/assets/javascript-C_OHM9hj.js +994 -0
- package/out/renderer/assets/julia-Bs6JJhYG.js +407 -0
- package/out/renderer/assets/livescript-DmzgM3Yt.js +296 -0
- package/out/renderer/assets/lua-Cvg8VrAA.js +256 -0
- package/out/renderer/assets/mathematica-DNLOL9PQ.js +110 -0
- package/out/renderer/assets/mbox-Ga7d4MMN.js +117 -0
- package/out/renderer/assets/mirc-Dma3B8rS.js +107 -0
- package/out/renderer/assets/mllike-DHn7xckP.js +334 -0
- package/out/renderer/assets/modelica-0d55jYY0.js +147 -0
- package/out/renderer/assets/mscgen-DdqZYINH.js +135 -0
- package/out/renderer/assets/mumps-Btr8VblO.js +93 -0
- package/out/renderer/assets/nginx-DTDtBDVN.js +141 -0
- package/out/renderer/assets/nsis-3zG7tgur.js +62 -0
- package/out/renderer/assets/ntriples-CvgOYMpL.js +153 -0
- package/out/renderer/assets/octave-DYBj3-tl.js +200 -0
- package/out/renderer/assets/oz-R_e8WMIi.js +231 -0
- package/out/renderer/assets/pascal-GD8iposT.js +105 -0
- package/out/renderer/assets/perl-DL9mHpoi.js +1105 -0
- package/out/renderer/assets/pig-C_4T4YIV.js +101 -0
- package/out/renderer/assets/powershell-B0suO7Vd.js +328 -0
- package/out/renderer/assets/properties-BR-vP1aU.js +58 -0
- package/out/renderer/assets/protobuf-BxgpyhoW.js +77 -0
- package/out/renderer/assets/pug-CTXt1f8z.js +405 -0
- package/out/renderer/assets/puppet-Bdao66PW.js +137 -0
- package/out/renderer/assets/python-CvWbmiX4.js +427 -0
- package/out/renderer/assets/q-CrbCVq4a.js +131 -0
- package/out/renderer/assets/r-V7nswm59.js +170 -0
- package/out/renderer/assets/rpm-C-DLY-If.js +109 -0
- package/out/renderer/assets/ruby-JDKLJNK0.js +330 -0
- package/out/renderer/assets/sas-D2UG-yhZ.js +207 -0
- package/out/renderer/assets/scheme-BKzrkGJD.js +222 -0
- package/out/renderer/assets/shell-BlsXDxCn.js +222 -0
- package/out/renderer/assets/sieve-CjwBwOY5.js +135 -0
- package/out/renderer/assets/simple-mode-DMneyfDu.js +130 -0
- package/out/renderer/assets/smalltalk-BOIGQuhN.js +121 -0
- package/out/renderer/assets/solr-CwD7U71z.js +69 -0
- package/out/renderer/assets/sparql-DYskk2vE.js +249 -0
- package/out/renderer/assets/spreadsheet-Bgtt3oLP.js +87 -0
- package/out/renderer/assets/sql-BSrOzCRI.js +354 -0
- package/out/renderer/assets/stex-B6LNC55o.js +231 -0
- package/out/renderer/assets/stylus-BkS-boTH.js +565 -0
- package/out/renderer/assets/swift-FRZi1uvB.js +291 -0
- package/out/renderer/assets/tcl-CUcaCdmq.js +114 -0
- package/out/renderer/assets/textile-BnFpjsrl.js +414 -0
- package/out/renderer/assets/tiddlywiki-CjprD-Qp.js +218 -0
- package/out/renderer/assets/tiki-DK9DOeWn.js +268 -0
- package/out/renderer/assets/toml-BOuWGMcf.js +76 -0
- package/out/renderer/assets/troff-E1bJ0PPL.js +61 -0
- package/out/renderer/assets/ttcn-cfg-Dc39-fIP.js +133 -0
- package/out/renderer/assets/ttcn-tKd4HLu4.js +192 -0
- package/out/renderer/assets/turtle-Dq7-1WAf.js +124 -0
- package/out/renderer/assets/vb-Dp90gtsv.js +196 -0
- package/out/renderer/assets/vbscript-CI6_mxxU.js +479 -0
- package/out/renderer/assets/velocity-BwIZK1TH.js +149 -0
- package/out/renderer/assets/verilog-DDCYnHN8.js +430 -0
- package/out/renderer/assets/vhdl-DCkMIyT9.js +158 -0
- package/out/renderer/assets/webidl-BTLTThCm.js +204 -0
- package/out/renderer/assets/xquery-BrBUuxMR.js +525 -0
- package/out/renderer/assets/yacas-b5lAVEIl.js +130 -0
- package/out/renderer/assets/z80-BZV19vqv.js +93 -0
- package/out/renderer/index.html +16 -0
- package/package.json +109 -0
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Maestro
|
|
2
|
+
|
|
3
|
+
> ⚠️ **Disclaimer: this is a vibe-coded app.** Maestro was built almost entirely by Claude Code
|
|
4
|
+
> (including by Maestro driving itself), with light human steering. Treat it as an experiment —
|
|
5
|
+
> expect rough edges, review before relying on it, and use at your own risk.
|
|
6
|
+
|
|
7
|
+
One window to run and **conduct** multiple Claude Code CLI sessions, each in its own repo, with a
|
|
8
|
+
live file explorer per session and git-worktree parallel tasks. See [PLAN.md](./PLAN.md) and
|
|
9
|
+
[SPECS.md](./SPECS.md).
|
|
10
|
+
|
|
11
|
+
Each session embeds the **real, unmodified `claude` CLI** in a real pseudo-terminal (ConPTY on
|
|
12
|
+
Windows, forkpty on macOS) — all CLI features (permission prompts, slash commands, `!` shell,
|
|
13
|
+
paste, vim mode) work exactly as in a normal terminal. The app adds the frame: session registry,
|
|
14
|
+
switching, status badges, file tree, viewer, parallel tasks, and restore-on-restart.
|
|
15
|
+
|
|
16
|
+
Requires the `claude` CLI on PATH (`npm i -g @anthropic-ai/claude-code`).
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
**Windows** — grab either from the [latest release](https://github.com/pedroferreira1142/maestro/releases/latest):
|
|
21
|
+
|
|
22
|
+
- `Maestro-<version>-portable.exe` — single file, run from anywhere, **no install, no admin rights**
|
|
23
|
+
- `Maestro-Setup-<version>.exe` — per-user installer (Start menu + uninstaller, no admin rights)
|
|
24
|
+
|
|
25
|
+
**macOS** — from the same release page:
|
|
26
|
+
|
|
27
|
+
- `Maestro-<version>-arm64.dmg` (Apple Silicon) or `Maestro-<version>-x64.dmg` (Intel)
|
|
28
|
+
- The app is unsigned: on first launch, right-click the app → **Open** (or
|
|
29
|
+
`xattr -d com.apple.quarantine /Applications/Maestro.app`).
|
|
30
|
+
|
|
31
|
+
**npx / npm** (any OS with Node 20+; downloads Electron on first run):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx claude-maestro
|
|
35
|
+
# or install the command globally:
|
|
36
|
+
npm i -g claude-maestro && claude-maestro
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
(Published to npm as [`claude-maestro`](https://www.npmjs.com/package/claude-maestro). You can also
|
|
40
|
+
run the unpublished tip with `npx github:pedroferreira1142/maestro`.)
|
|
41
|
+
|
|
42
|
+
## Develop
|
|
43
|
+
|
|
44
|
+
```powershell
|
|
45
|
+
npm install
|
|
46
|
+
npm run dev # development with HMR
|
|
47
|
+
npm run build # production bundles into out/
|
|
48
|
+
npm run package # build installers/portables into release/
|
|
49
|
+
node bin/maestro.mjs # run the built app
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Cutting a release: see [RELEASING.md](RELEASING.md) for the SemVer policy and the
|
|
53
|
+
`npm run release:patch|minor|major` scripts.
|
|
54
|
+
|
|
55
|
+
## Use
|
|
56
|
+
|
|
57
|
+
On macOS, `Cmd` works wherever `Ctrl` is listed (except `Ctrl+Tab`, which stays `Ctrl`).
|
|
58
|
+
|
|
59
|
+
| Action | How |
|
|
60
|
+
|---|---|
|
|
61
|
+
| New session | `+` in the sidebar, or `Ctrl+Shift+N` → pick a repo folder |
|
|
62
|
+
| **New parallel task (worktree)** | `⑂` on a session, or `Ctrl+Shift+T` |
|
|
63
|
+
| New terminal in session | `+▾` in the tab strip, or `Ctrl+T` |
|
|
64
|
+
| Switch session | Click in sidebar, `Ctrl+Tab` / `Ctrl+Shift+Tab`, or `Ctrl+1…9` |
|
|
65
|
+
| Close session | ✕ on hover, or `Ctrl+Shift+W` |
|
|
66
|
+
| Rename session | Double-click its name |
|
|
67
|
+
| Toggle file explorer | `Ctrl+B` |
|
|
68
|
+
| View a file | Single-click in the tree (read-only viewer tab) |
|
|
69
|
+
| Open in editor | Double-click in the tree (default: VS Code) |
|
|
70
|
+
| Context menu | Right-click a file/folder: open, reveal, copy path |
|
|
71
|
+
| Terminal search | `Ctrl+F` in the terminal |
|
|
72
|
+
| Copy / paste in terminal | `Ctrl+Shift+C` / `Ctrl+Shift+V`, right-click toggles copy/paste, `Ctrl+C` with selection copies |
|
|
73
|
+
|
|
74
|
+
Sessions keep running in the background when not visible; scrollback is preserved. Status
|
|
75
|
+
glyphs in the sidebar: `⟳` working · `●` needs your input · `○` idle · `✕` exited (with
|
|
76
|
+
restart-resume buttons in the pane).
|
|
77
|
+
|
|
78
|
+
On app restart, all sessions are restored and conversations resumed via `claude --continue`.
|
|
79
|
+
|
|
80
|
+
## Parallel tasks (git worktrees)
|
|
81
|
+
|
|
82
|
+
While Claude works on task A in a repo, spin off task B **on the same repo** without waiting:
|
|
83
|
+
|
|
84
|
+
1. Click `⑂` on the session (or `Ctrl+Shift+T`). Name the task and pick its type — a branch
|
|
85
|
+
(`parallel/<slug>`, `feature/<slug>` or `bug/<slug>`) and a worktree folder
|
|
86
|
+
(`<repo>.worktrees/<slug>`, sibling of the repo) are created.
|
|
87
|
+
2. A linked session appears indented under the parent, running its own `claude` in the
|
|
88
|
+
worktree — optionally pre-typed with your first prompt (you press Enter to send).
|
|
89
|
+
3. When the task is done, click **Merge** on the task entry: the branch is merged
|
|
90
|
+
(`--no-ff`) into the base branch. Clean merge → offers to remove the worktree and
|
|
91
|
+
branch. Conflicts → you land in the terminal to resolve them like a normal merge.
|
|
92
|
+
|
|
93
|
+
Any number of tasks can run side by side; each is isolated in its own working tree.
|
|
94
|
+
|
|
95
|
+
### Reliable "needs input" detection
|
|
96
|
+
|
|
97
|
+
Claude Code rings the terminal bell on prompts when configured to:
|
|
98
|
+
|
|
99
|
+
```powershell
|
|
100
|
+
claude config set --global preferredNotifChannel terminal_bell
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
With that set, background sessions flag themselves (badge + OS notification + taskbar flash)
|
|
104
|
+
the moment Claude asks for permission or input. Without it, detection falls back to output
|
|
105
|
+
heuristics.
|
|
106
|
+
|
|
107
|
+
## State
|
|
108
|
+
|
|
109
|
+
Session list, window bounds, and settings persist in `sessions.json` under the app's user-data
|
|
110
|
+
dir (`%APPDATA%\maestro` on Windows, `~/Library/Application Support/maestro` on macOS). The tail
|
|
111
|
+
of each terminal's output (~200 KB) is persisted under `scrollback/` in the same dir and replayed
|
|
112
|
+
on restart above a dim `── restored from previous session ──` divider, while Claude's own
|
|
113
|
+
`--continue` restores the conversation itself.
|
|
114
|
+
|
|
115
|
+
## Architecture (short)
|
|
116
|
+
|
|
117
|
+
- **Main process** (`src/main/`): `SessionManager` owns one `PtySession` (node-pty ConPTY
|
|
118
|
+
running `claude`) per session — PTYs live in main, so a renderer reload never kills sessions.
|
|
119
|
+
`StatusDetector` classifies the output stream; `FsService` does bounded chokidar watching
|
|
120
|
+
(root + expanded dirs, ignore-list at watcher level) and path-validated file reads.
|
|
121
|
+
- **Preload** (`src/preload/`): typed `window.api` bridge, contextIsolation on.
|
|
122
|
+
- **Renderer** (`src/renderer/`): React + zustand. One persistent xterm.js instance per
|
|
123
|
+
session (hidden, never unmounted ⇒ instant switching), lazy file tree with live updates and
|
|
124
|
+
changed-file flashes, CodeMirror 6 read-only viewer with auto language detection.
|
|
125
|
+
|
|
126
|
+
## Acknowledgements
|
|
127
|
+
|
|
128
|
+
This wouldn't have been possible without the help of
|
|
129
|
+
[Tim Pieters](https://www.linkedin.com/in/tim-pieters/) and
|
|
130
|
+
[Sven De Pickere](https://www.linkedin.com/in/svendepickere/).
|
package/bin/maestro.mjs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* npx/CLI launcher for Maestro.
|
|
4
|
+
*
|
|
5
|
+
* Resolves the electron binary and boots the built app (out/ + package.json
|
|
6
|
+
* `main`). When the package was installed without electron (it's a devDep so
|
|
7
|
+
* electron-builder accepts it), falls back to running electron via npx, which
|
|
8
|
+
* downloads it into the npx cache on first use — no admin rights needed.
|
|
9
|
+
*/
|
|
10
|
+
import { spawn } from 'node:child_process'
|
|
11
|
+
import { existsSync } from 'node:fs'
|
|
12
|
+
import { createRequire } from 'node:module'
|
|
13
|
+
import { dirname, join } from 'node:path'
|
|
14
|
+
import { fileURLToPath } from 'node:url'
|
|
15
|
+
|
|
16
|
+
const appDir = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
17
|
+
|
|
18
|
+
if (!existsSync(join(appDir, 'out', 'main', 'index.js'))) {
|
|
19
|
+
console.error('Maestro: built app not found (out/main/index.js missing). Run "npm run build" first.')
|
|
20
|
+
process.exit(1)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const require = createRequire(import.meta.url)
|
|
24
|
+
let electronPath = null
|
|
25
|
+
try {
|
|
26
|
+
// In plain Node, require('electron') resolves to the binary's path.
|
|
27
|
+
const resolved = require('electron')
|
|
28
|
+
if (typeof resolved === 'string') electronPath = resolved
|
|
29
|
+
} catch {
|
|
30
|
+
// electron not installed alongside the package — use the npx fallback below
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Windows needs shell:true to run npx.cmd; pass one pre-quoted string there
|
|
34
|
+
// (args arrays + shell:true are deprecated, DEP0190).
|
|
35
|
+
const child = electronPath
|
|
36
|
+
? spawn(electronPath, [appDir], { stdio: 'inherit' })
|
|
37
|
+
: process.platform === 'win32'
|
|
38
|
+
? spawn(`npx -y "electron@^33.3.0" "${appDir}"`, { stdio: 'inherit', shell: true })
|
|
39
|
+
: spawn('npx', ['-y', 'electron@^33.3.0', appDir], { stdio: 'inherit' })
|
|
40
|
+
|
|
41
|
+
child.on('error', (err) => {
|
|
42
|
+
console.error('Maestro: failed to launch electron:', err.message)
|
|
43
|
+
process.exit(1)
|
|
44
|
+
})
|
|
45
|
+
child.on('close', (code) => process.exit(code ?? 0))
|