codebase-onboarder 0.7.0 → 1.0.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 +115 -12
- package/bin/onboarder.js +0 -0
- package/cli/agent/command.d.ts +71 -0
- package/cli/agent/command.js +177 -0
- package/cli/agent/command.js.map +1 -0
- package/cli/agent/config.d.ts +31 -0
- package/cli/agent/config.js +98 -0
- package/cli/agent/config.js.map +1 -0
- package/cli/agent/contracts.d.ts +77 -0
- package/cli/agent/contracts.js +2 -0
- package/cli/agent/contracts.js.map +1 -0
- package/cli/agent/files.d.ts +19 -0
- package/cli/agent/files.js +109 -0
- package/cli/agent/files.js.map +1 -0
- package/cli/agent/gitSource.d.ts +18 -0
- package/cli/agent/gitSource.js +69 -0
- package/cli/agent/gitSource.js.map +1 -0
- package/cli/agent/github.d.ts +21 -0
- package/cli/agent/github.js +94 -0
- package/cli/agent/github.js.map +1 -0
- package/cli/agent/mcp.d.ts +15 -0
- package/cli/agent/mcp.js +78 -0
- package/cli/agent/mcp.js.map +1 -0
- package/cli/agent/process.d.ts +18 -0
- package/cli/agent/process.js +118 -0
- package/cli/agent/process.js.map +1 -0
- package/cli/agent/protocol.d.ts +3 -0
- package/cli/agent/protocol.js +26 -0
- package/cli/agent/protocol.js.map +1 -0
- package/cli/agent/runner.d.ts +34 -0
- package/cli/agent/runner.js +152 -0
- package/cli/agent/runner.js.map +1 -0
- package/cli/agent/stdio.d.ts +1 -0
- package/cli/agent/stdio.js +62 -0
- package/cli/agent/stdio.js.map +1 -0
- package/cli/agent/tools.d.ts +7 -0
- package/cli/agent/tools.js +201 -0
- package/cli/agent/tools.js.map +1 -0
- package/cli/chat/app.d.ts +16 -0
- package/cli/chat/app.js +345 -0
- package/cli/chat/app.js.map +1 -0
- package/cli/chat/commands.d.ts +11 -0
- package/cli/chat/commands.js +120 -0
- package/cli/chat/commands.js.map +1 -0
- package/cli/chat/composer.d.ts +75 -0
- package/cli/chat/composer.js +467 -0
- package/cli/chat/composer.js.map +1 -0
- package/cli/chat/controller.d.ts +60 -0
- package/cli/chat/controller.js +393 -0
- package/cli/chat/controller.js.map +1 -0
- package/cli/chat/logo.d.ts +3 -0
- package/cli/chat/logo.js +14 -0
- package/cli/chat/logo.js.map +1 -0
- package/cli/chat/models.d.ts +18 -0
- package/cli/chat/models.js +88 -0
- package/cli/chat/models.js.map +1 -0
- package/cli/chat/profile.d.ts +5 -0
- package/cli/chat/profile.js +98 -0
- package/cli/chat/profile.js.map +1 -0
- package/cli/chat/render.d.ts +40 -0
- package/cli/chat/render.js +259 -0
- package/cli/chat/render.js.map +1 -0
- package/cli/chat/screen.d.ts +26 -0
- package/cli/chat/screen.js +117 -0
- package/cli/chat/screen.js.map +1 -0
- package/cli/chat/source.d.ts +29 -0
- package/cli/chat/source.js +116 -0
- package/cli/chat/source.js.map +1 -0
- package/cli/chat/store.d.ts +43 -0
- package/cli/chat/store.js +94 -0
- package/cli/chat/store.js.map +1 -0
- package/cli/chat/text.d.ts +4 -0
- package/cli/chat/text.js +27 -0
- package/cli/chat/text.js.map +1 -0
- package/cli/explorer/app.d.ts +1 -0
- package/cli/explorer/app.js +20 -1
- package/cli/explorer/app.js.map +1 -1
- package/cli/explorer/commands.js +5 -0
- package/cli/explorer/commands.js.map +1 -1
- package/cli/main.js +47 -13
- package/cli/main.js.map +1 -1
- package/docs/HERMES_RESEARCH.md +51 -0
- package/package.json +2 -1
- package/public/app.js +98 -24
- package/public/app.js.map +1 -1
- package/public/assets/onboarder-mark.svg +11 -0
- package/public/browser.d.ts +3 -0
- package/public/browser.js.map +1 -1
- package/public/index.html +24 -7
- package/public/js/about.js +2 -2
- package/public/js/about.js.map +1 -1
- package/public/js/aiDraft.d.ts +1 -0
- package/public/js/aiDraft.js +66 -17
- package/public/js/aiDraft.js.map +1 -1
- package/public/js/api.d.ts +8 -5
- package/public/js/api.js +45 -22
- package/public/js/api.js.map +1 -1
- package/public/js/deepAnalysisView.js +2 -2
- package/public/js/deepAnalysisView.js.map +1 -1
- package/public/js/diagramPane.d.ts +1 -0
- package/public/js/diagramPane.js +5 -0
- package/public/js/diagramPane.js.map +1 -1
- package/public/js/docsView.js +6 -6
- package/public/js/docsView.js.map +1 -1
- package/public/js/dom.d.ts +8 -0
- package/public/js/dom.js.map +1 -1
- package/public/js/llm.d.ts +3 -1
- package/public/js/llm.js +15 -8
- package/public/js/llm.js.map +1 -1
- package/public/js/repoFiles.js +1 -1
- package/public/js/repoFiles.js.map +1 -1
- package/public/js/reviewView.js +1 -1
- package/public/js/reviewView.js.map +1 -1
- package/public/styles.css +25 -0
- package/server/gitDiff.d.ts +1 -1
- package/server/hermesChat.d.ts +13 -0
- package/server/hermesChat.js +145 -0
- package/server/hermesChat.js.map +1 -0
- package/server/http.d.ts +5 -4
- package/server/http.js +0 -4
- package/server/http.js.map +1 -1
- package/server/mcp/server.d.ts +1 -1
- package/server/mcp/server.js +2 -2
- package/server/mcp/server.js.map +1 -1
- package/server/router.js +7 -3
- package/server/router.js.map +1 -1
- package/shared/diagram/aiMermaid.js +16 -13
- package/shared/diagram/aiMermaid.js.map +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
Onboarder reads a software repository the way a senior engineer would: starting at the front door, tracing import graphs, mapping architectural layers, computing risk/health metrics, discovering dead exports and dependency drift, and charting Git hotspots — rendering everything as interactive, zoomable diagrams.
|
|
14
14
|
|
|
15
|
-
**
|
|
15
|
+
**Local analysis**: Repository maps and the offline explorer run on your machine without an account. Optional AI chat sends task context and requested source to your configured model provider.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -22,9 +22,12 @@ Onboarder reads a software repository the way a senior engineer would: starting
|
|
|
22
22
|
# Install from npm (Node 20+, zero runtime dependencies)
|
|
23
23
|
npm install -g codebase-onboarder
|
|
24
24
|
|
|
25
|
-
#
|
|
25
|
+
# Open the repository chat harness in your terminal
|
|
26
26
|
onboarder
|
|
27
27
|
|
|
28
|
+
# Browse offline, including folders and Git URLs
|
|
29
|
+
onboarder explore
|
|
30
|
+
|
|
28
31
|
# …or start the web UI instead
|
|
29
32
|
onboarder start
|
|
30
33
|
```
|
|
@@ -40,7 +43,7 @@ npm start
|
|
|
40
43
|
|
|
41
44
|
Open **http://localhost:4310** in your browser (the CLI opens it for you).
|
|
42
45
|
|
|
43
|
-
- **
|
|
46
|
+
- **Chat, explorer, and web UI.** `onboarder` opens the Hermes chat harness; `onboarder explore` opens offline browsing; `onboarder start` opens the web UI. Repository analysis uses the same engine in all three.
|
|
44
47
|
- **Ready to run from npm**: Compiled JavaScript is included in the package. Application source lives in `src/` as TypeScript. Run `npm run build` after editing it, or use `npm run dev` for automatic rebuilds and server restarts.
|
|
45
48
|
- **Zero runtime dependencies**: Powered by Node.js built-ins (`node:http`, `node:fs`, `node:crypto`).
|
|
46
49
|
- **Offline ready**: Vendored Mermaid.js and Monaco Editor builds are included in `public/vendor/`.
|
|
@@ -49,18 +52,71 @@ Open **http://localhost:4310** in your browser (the CLI opens it for you).
|
|
|
49
52
|
|
|
50
53
|
## 🖥️ The terminal app
|
|
51
54
|
|
|
52
|
-
Type `onboarder` to
|
|
55
|
+
Type `onboarder` to open the Hermes-powered chat interface for the current repository, or `onboarder chat ~/work/some-repo` to open another local checkout. An amber welcome screen shows the actual configured model, repository, permissions, six workflow skills, and 37 registered tools. The composer has a session status bar with recorded token usage, elapsed run time, and live tool activity. It keeps terminal scrollback and loads the browsing engine only when requested.
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
onboarder chat
|
|
59
|
+
onboarder chat ~/work/some-repo --mode review
|
|
60
|
+
onboarder chat https://github.com/owner/repo
|
|
61
|
+
onboarder chat --resume <conversation-id>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Inside the chat:
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
codebase ask › /model configure
|
|
68
|
+
codebase ask › /repo https://github.com/owner/repo
|
|
69
|
+
codebase ask › Explain how authentication works
|
|
70
|
+
codebase ask › Where are those permissions checked?
|
|
71
|
+
codebase ask › /review 42 Focus on correctness and security
|
|
72
|
+
codebase review › /triage 12
|
|
73
|
+
codebase triage › /permissions checks on
|
|
74
|
+
codebase triage › /implement Fix the bug described in issue 12
|
|
75
|
+
codebase implement › /diff
|
|
76
|
+
codebase implement › Add a regression test for that fix
|
|
77
|
+
codebase implement › /history
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
| Commands | Purpose |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| `/ask`, `/review`, `/triage`, `/implement`, `/pr`, `/github` | Start a workflow; following messages continue it |
|
|
83
|
+
| `/mode`, `/model`, `/permissions`, `/limits` | Control the workflow, provider, allowed actions, timeout, and turn budget |
|
|
84
|
+
| `/map`, `/tree`, `/find`, `/show`, `/diff`, `/health`, `/rescan` | Browse and analyze offline; inspect the active implementation workspace |
|
|
85
|
+
| `/tour`, `/explain`, `/deps`, `/inspect`, `/graph`, `/blast`, `/symbols` | Follow the reading order, inspect modules, and trace dependencies |
|
|
86
|
+
| `/hubs`, `/layers`, `/patterns`, `/stats`, `/security`, `/stack`, `/entry`, `/externals`, `/coupling`, `/clusters`, `/risks` | Explore repository structure, health, and risks |
|
|
87
|
+
| `/log`, `/hotspots`, `/blame`, `/diagram`, `/layers-diagram`, `/atlas`, `/docs`, `/workflows`, `/sbom` | Inspect Git history, diagrams, documentation, CI, and licenses |
|
|
88
|
+
| `/engines`, `/deep`, `/web`, `/about` | Discover and run optional analyzers, start the web interface, and inspect repository details |
|
|
89
|
+
| `/new`, `/history`, `/resume`, `/repo`, `/status` | Manage saved conversations, repository context, and workspaces |
|
|
90
|
+
| `/clone <GitHub URL>`, `/pull` | Clone a GitHub repository and refresh a clean saved checkout |
|
|
91
|
+
| `/paste`, `/send`, `/discard` | Compose or discard multiline prompts and code |
|
|
92
|
+
| `/setup`, `/doctor`, `/help`, `/clear`, `/cancel`, `/exit` | Set up Hermes, check readiness, and control the terminal session |
|
|
93
|
+
| `/tools`, `/skills`, `/runs`, `/run`, `/export` | Inspect actual capabilities, saved runs, and export this chat as Markdown |
|
|
94
|
+
|
|
95
|
+
Typing `/` immediately opens a searchable command menu with descriptions. Keep typing to filter, use ↑/↓ to choose, and press Tab or Enter to fill the command without starting a task. A fully typed command executes on Enter. Esc dismisses the menu and restores normal history navigation. Tab also completes settings and indexed file paths. Alt-Enter adds a newline; bracketed paste keeps multiline code together and waits for Enter before sending. Ctrl-A/E move to the start/end, Ctrl-U clears the draft, and Ctrl-C cancels an active task. Ctrl-D cancels, saves, and exits when the draft is empty.
|
|
96
|
+
|
|
97
|
+
Chat opens in a **full-screen terminal interface** with the composer pinned to the bottom. The welcome, conversation and menus automatically reflow when the terminal window changes size. **Page Up / Page Down** scroll the conversation without editing your draft; new output preserves your reading position until you return to the latest messages. Narrow or short windows use compact layouts, and the original Onboarder **code-compass** logo appears in full or compact terminal art. Its reusable vector image is [public/assets/onboarder-mark.svg](public/assets/onboarder-mark.svg).
|
|
98
|
+
|
|
99
|
+
The screen paints only changed rows and batches streamed output. Drafts survive resizes and model-wizard handoffs, and leaving chat restores the original shell screen. The in-memory viewport retains up to 4,000 logical lines or 2 MiB; conversation storage and `/export` remain available separately. Follow-ups reuse the saved Hermes session and its isolated implementation workspace. Changing the workflow, PR/issue target, model, or permissions starts a new session. `/clear` clears the screen while keeping context; `/new` resets the conversation. Checks and GitHub writes default to off. `/deep` requires checks permission. `/pr` prepares changes locally unless GitHub writes are enabled; publishing must also be requested in the task. `/export` saves a private Markdown transcript under the agent home's `exports` folder.
|
|
100
|
+
|
|
101
|
+
`/model` opens a Hermes-style provider/model picker below the input. Type to filter, use ↑/↓ to select, and press Enter to choose. Available providers and models come from the installed Hermes catalog; selection uses Hermes' own credential resolution and saves the model to the dedicated Onboarder profile. Escape keeps your current model and conversation. Choose **Configure provider / authentication**, or run `/model configure`, for the full official Hermes configuration, including custom endpoints and provider login. Older Hermes installations can use this full wizard when the quick picker is unavailable. No model names or provider credentials are hardcoded into the picker.
|
|
102
|
+
|
|
103
|
+
At startup, an unconfigured profile offers **Choose a provider and model** or **Continue offline**. Configured profiles start directly in chat. Hermes must be installed separately for AI tasks; offline commands work without it. Conversation summaries are stored privately in `~/.config/onboarder/agent/chats`, alongside agent runs, and known environment credentials are redacted. `/resume` requires a conversation for the current repository and preserves your current permission choices. `onboarder chat --resume` takes a **conversation ID**; `onboarder agent … --resume` takes an **agent run ID**.
|
|
104
|
+
|
|
105
|
+
To ask about a GitHub repository, launch `onboarder chat https://github.com/owner/repo`, use `/repo <URL>` or `/clone <URL>`, or simply paste the URL into chat. You can also paste `<URL> Explain this repository` to clone and ask in one message. HTTPS and GitHub SSH URLs work; private repositories use your existing Git credentials. Cloning shows progress and can be cancelled with Ctrl-C.
|
|
106
|
+
|
|
107
|
+
Chat checkouts are saved under `~/.config/onboarder/agent/repositories` and remain after exit, so conversations and isolated implementation workspaces can resume. Reopening the same URL reuses its checkout. `/pull` fetches current changes with a fast-forward-only pull and refuses local changes; use `/new` first if an implementation workspace is active. A successful pull resets AI context so the next question reads the updated source. To resume later, reopen the same URL and use `/history`, then `/resume <conversation-id>`.
|
|
108
|
+
|
|
109
|
+
The original explorer remains available for its full browsing, source picker, diagrams, and optional analyzer commands:
|
|
53
110
|
|
|
54
111
|
```bash
|
|
55
|
-
onboarder
|
|
112
|
+
onboarder explore # choose a source; Enter uses the current directory
|
|
56
113
|
onboarder explore ~/work/some-repo
|
|
57
114
|
onboarder report . # one-shot summary, no interactive terminal needed
|
|
58
115
|
onboarder report . --json # stable JSON for scripts and CI
|
|
59
|
-
onboarder
|
|
60
|
-
onboarder --server # force the web UI (what bare `onboarder` used to do)
|
|
116
|
+
onboarder --server # force the web UI
|
|
61
117
|
```
|
|
62
118
|
|
|
63
|
-
|
|
119
|
+
The explorer lands on a `map` of the repo, then waits:
|
|
64
120
|
|
|
65
121
|
```
|
|
66
122
|
codebase > tour
|
|
@@ -136,12 +192,55 @@ The HTTP equivalent is `{ "path": "/repo", "options": { "maxFiles": 10000,
|
|
|
136
192
|
and 32 reads. Scan cache keys include every file and its imports, exports, and
|
|
137
193
|
findings, so changes beyond the first hundred files also invalidate the cache.
|
|
138
194
|
|
|
139
|
-
`ask` is optional. Set `ONBOARDER_AI_BASE_URL` and `ONBOARDER_AI_MODEL`, plus
|
|
195
|
+
The explorer's `ask` command is optional. Set `ONBOARDER_AI_BASE_URL` and `ONBOARDER_AI_MODEL`, plus
|
|
140
196
|
`ONBOARDER_AI_API_KEY` when the endpoint requires a key. The CLI also accepts
|
|
141
197
|
`OPENAI_BASE_URL`, `OPENAI_MODEL`, and `OPENAI_API_KEY`. It sends the question
|
|
142
198
|
and a limited scan summary only when you run `ask`; the key stays in the
|
|
143
199
|
process environment and is not saved in Onboarder's config.
|
|
144
200
|
|
|
201
|
+
### Hermes repository and GitHub agent
|
|
202
|
+
|
|
203
|
+
`onboarder agent` adds multi-step repository work through [Nous Research's Hermes Agent](https://github.com/NousResearch/hermes-agent). Hermes is an optional, separately installed Python runtime; Onboarder's npm package still has no runtime dependencies. The TypeScript harness supplies **37 scoped MCP tools** built around Onboarder's existing analysis and GitHub's API.
|
|
204
|
+
|
|
205
|
+
```sh
|
|
206
|
+
onboarder agent setup
|
|
207
|
+
onboarder agent model # choose a provider/model in the dedicated profile
|
|
208
|
+
onboarder agent doctor
|
|
209
|
+
onboarder agent ask . --task "Explain the authentication flow"
|
|
210
|
+
onboarder agent review . --pr 42 --task "Review correctness and security"
|
|
211
|
+
onboarder agent triage . --issue 12 --task "Investigate the cause and propose labels"
|
|
212
|
+
onboarder agent implement . --issue 12 --task "Fix this issue" --allow-checks
|
|
213
|
+
onboarder agent pr . --task "Implement the fix and open a draft PR" --allow-checks --allow-github-writes
|
|
214
|
+
onboarder agent github . --task "Explain why the latest CI run failed"
|
|
215
|
+
onboarder agent runs
|
|
216
|
+
onboarder agent show <run-id>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The same commands work inside the explorer: `agent review --pr 42` uses the loaded repository. Implementation and PR work require a persistent local checkout; the explorer's temporary URL clones are removed on exit. `agent help` lists setup and workflow options. Use `--dry-run --json` to inspect a plan without creating a workspace or calling a model. Use `--json` for one machine-readable result; progress stays on stderr.
|
|
220
|
+
|
|
221
|
+
| Workflow | Result |
|
|
222
|
+
| --- | --- |
|
|
223
|
+
| `ask` | Repository Q&A grounded in scan, architecture, search and source tools |
|
|
224
|
+
| `review` | Local-change or GitHub PR findings, patch coverage, discussion and checks at the PR head SHA |
|
|
225
|
+
| `triage` | Issue investigation, duplicate candidates, priority, labels and a proposed implementation plan |
|
|
226
|
+
| `implement` | Edits in a separate Git worktree, diff inspection and optional npm checks |
|
|
227
|
+
| `pr` | Implementation plus a proposed PR; publishes a **draft** when GitHub writes are enabled |
|
|
228
|
+
| `github` | Repository, issues, PR discussions, labels, CI runs/jobs, comments and review tasks |
|
|
229
|
+
|
|
230
|
+
GitHub access uses the local checkout's **github.com `origin`** and `GITHUB_TOKEN` or `GH_TOKEN`. Public reads can work without a token; private reads and writes need a token with access to the requested resources. Git transport uses your existing Git credentials. Publishing a review requires the freshly read PR head SHA and refuses a changed head.
|
|
231
|
+
|
|
232
|
+
Source editing is available only in `implement`/`pr` worktrees created at **committed HEAD** on a `codex/agent-…` branch. Uncommitted changes in your source checkout are excluded. File tools refuse symlinks, credential files, traversal and files larger than 128 KiB; edits require the hash of a fresh read. Workspaces remain available after completion or failure for inspection. Publishing commits workspace changes, pushes that task branch and creates a draft PR; it does not merge. The PR target defaults to the cached `origin/HEAD` branch, falling back to the current branch; choose another with `--base`. Repeated identical successful writes are deduplicated within one running tool server.
|
|
233
|
+
|
|
234
|
+
`--allow-checks` allows lockfile dependency installation with lifecycle scripts disabled, plus `npm test`, `npm run typecheck` and `npm run build`. Test/build scripts can execute repository code and may write files. `--allow-github-writes` enables issue updates, comments, PR reviews and draft PR publishing. Both permissions are enforced by the tools and default to off. Onboarder supplies only its dedicated MCP toolset to Hermes.
|
|
235
|
+
|
|
236
|
+
Runs have a default 24-turn, 300-second limit; adjust with `--max-turns` and `--timeout`. Ctrl-C cancels an active agent in both the CLI and explorer. `--resume <run-id>` continues a saved Hermes session in its original workspace; repeat any enabled permission flags. Resume cannot expand the original permissions. Timeouts, missing completion frames and nonzero process exits are recorded as failures.
|
|
237
|
+
|
|
238
|
+
Run metadata, final answers and operation audits live under `~/.config/onboarder/agent` (override with `ONBOARDER_AGENT_HOME`). Hermes configuration and transcripts use a dedicated named profile under the installation's `profiles` folder; `agent setup` prints its path. Audit records contain operation names, outcome and timing; Hermes session transcripts can contain prompts and source. Repository/tool content is sent to the configured model during agent tasks. Known environment credentials are redacted from Onboarder diagnostics and final answers. API keys supplied through the environment are not written by Onboarder.
|
|
239
|
+
|
|
240
|
+
For an existing compatible endpoint, set `ONBOARDER_AI_BASE_URL`, `ONBOARDER_AI_MODEL` and optionally `ONBOARDER_AI_API_KEY` **before the first `agent setup`**. Standard `OPENAI_BASE_URL`, `OPENAI_MODEL`, `OPENAI_API_KEY` aliases also work. Later, `agent model` updates the dedicated profile without changing your normal Hermes profile. Use `ONBOARDER_HERMES_BIN` to select a Hermes executable. For a nonstandard source installation, preserve its `HERMES_HOME`/`HERMES_RUNTIME_DIR` environment so the harness can locate its shared Python packages.
|
|
241
|
+
|
|
242
|
+
`onboarder agent source` fetches the official MIT-licensed source at the researched revision into the agent source cache. This does not install Python dependencies or vendor Hermes into the npm package. The source review and integration decisions are documented in [Hermes research](docs/HERMES_RESEARCH.md). Developers can run `node scripts/hermes-smoke.mjs` after building to verify a real installed Hermes runtime against a local model fixture, without external inference or GitHub writes.
|
|
243
|
+
|
|
145
244
|
**It also takes a GitHub URL, the way the site does.** Point it at one and it clones, scans and opens that repo:
|
|
146
245
|
|
|
147
246
|
```
|
|
@@ -305,8 +404,8 @@ Next to **Explorer** in the top nav. One page with everything:
|
|
|
305
404
|
- **What this means** — the AI reads the report: *"Explain this analysis"* for a
|
|
306
405
|
prioritised read, or ask about a specific finding (*"is the eval finding
|
|
307
406
|
reachable?"*). It is told which engines did **not** run, so it will not claim
|
|
308
|
-
coverage it does not have. Needs an
|
|
309
|
-
report is still fully readable and the button offers the
|
|
407
|
+
coverage it does not have. Needs a Hermes connection or an AI endpoint; without one the
|
|
408
|
+
report is still fully readable and the button offers the AI connection drawer.
|
|
310
409
|
|
|
311
410
|
Rules that keep this safe to self-host:
|
|
312
411
|
|
|
@@ -340,8 +439,12 @@ Rules that keep this safe to self-host:
|
|
|
340
439
|
|
|
341
440
|
### 5. AI Notes & Explainers (Optional)
|
|
342
441
|
- Works 100% offline out-of-the-box.
|
|
442
|
+
- In **AI connection**, choose **Hermes · use my configured login** to reuse the Onboarder CLI's Hermes provider and model. No API key is needed in the browser. The drawer shows the current model/provider; use **Test connection**, then **Save**. Install Hermes on the computer running the server and run `onboarder agent model` to sign in or change models, then refresh the configuration in the drawer.
|
|
343
443
|
- Connect any OpenAI-compatible LLM endpoint (OpenAI, Azure OpenAI, Groq, OpenRouter, Ollama, LM Studio) to generate streaming explanations and repository documentation.
|
|
344
|
-
-
|
|
444
|
+
- Hermes powers questions, explanations, diagrams, documentation, analysis summaries and review briefs using their supplied repository context. Web explanations have no machine tools. Each request starts a fresh conversation, with a two-minute runtime budget and at most two concurrent requests; closing or cancelling an answer stops its Hermes process. Runtime startup can add a few seconds to the first response.
|
|
445
|
+
- **AI sketch** draws the current map, folder, file or architecture view using that connection. Sketches are checked with Mermaid before they are cached and displayed. **Static** returns to the original map; **AI sketch ✓** restores the cached sketch. Generated diagrams support **Copy Mermaid**, **Save SVG**, pan/zoom and file links. **Cancel sketch**, changing views, or opening another repository cancels an unfinished request. Hermes diagram requests use low reasoning without changing the saved chat configuration.
|
|
446
|
+
- Hermes owns its login and may save prompts/source in its session transcripts. Context is sent to the configured provider under its normal account usage limits. Existing API endpoint settings still work; API-mode keys are saved in browser `localStorage` and never logged or written to the server's disk. Hermes requests do not forward these browser keys.
|
|
447
|
+
- Developers can run `node scripts/hermes-web-smoke.mjs` after building to verify the HTTP integration against a real installed Hermes runtime and a local model fixture without external inference.
|
|
345
448
|
|
|
346
449
|
### 6. MCP Server — let any AI agent onboard itself
|
|
347
450
|
|
package/bin/onboarder.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export declare const AGENT_HELP = "\n Onboarder agent \u2014 Hermes with repository and GitHub tools\n\n onboarder agent setup Create a dedicated Hermes profile\n onboarder chat [folder] Open the conversational harness with / commands\n onboarder agent model Configure its model/provider interactively\n onboarder agent doctor Check runtime and integration compatibility\n onboarder agent source Fetch the researched official Hermes source\n onboarder agent runs List saved runs\n onboarder agent show <run-id> Inspect a saved result and workspace\n onboarder agent <workflow> [folder] --task \"...\"\n\n Workflows: ask, review, triage, implement, pr, github\n --pr <number> Review/inspect a GitHub pull request\n --issue <number> Work from an issue\n --base <branch> PR target (default: origin HEAD, or current branch)\n --allow-checks Allow npm install/test/typecheck/build (repository code)\n --allow-github-writes Allow issue/review/comment updates and draft PR publishing\n --max-turns <1\u2013100> Agent turn limit (default: 24)\n --timeout <seconds> Run limit, 15\u20133600 (default: 300)\n --model <name> --provider <name> Override the dedicated Hermes model\n --resume <run-id> Continue a session; repeat allowed permission flags\n --dry-run Print the plan without a model call or worktree\n --json One JSON result; progress goes to stderr\n\n implement/pr use a new Git worktree at committed HEAD. Uncommitted source\n changes are excluded. Without --allow-github-writes, pr prepares a draft locally.\n GitHub uses the checkout's github.com origin and GITHUB_TOKEN or GH_TOKEN.\n Hermes is an optional separate Python runtime: https://github.com/NousResearch/hermes-agent\n Profile/history: ONBOARDER_AGENT_HOME (default: ~/.config/onboarder/agent).\n\n onboarder agent ask . --task \"Explain the authentication flow\"\n onboarder agent review . --pr 42 --task \"Find correctness and security issues\"\n onboarder agent triage . --issue 12 --task \"Investigate and propose a fix\"\n onboarder agent implement . --task \"Fix issue 12\" --issue 12 --allow-checks\n onboarder agent pr . --task \"Fix issue 12 and open a draft PR\" --issue 12 --allow-checks --allow-github-writes\n";
|
|
2
|
+
export declare const AGENT_OPTIONS: {
|
|
3
|
+
task: {
|
|
4
|
+
type: 'string';
|
|
5
|
+
};
|
|
6
|
+
pr: {
|
|
7
|
+
type: 'string';
|
|
8
|
+
};
|
|
9
|
+
issue: {
|
|
10
|
+
type: 'string';
|
|
11
|
+
};
|
|
12
|
+
'max-turns': {
|
|
13
|
+
type: 'string';
|
|
14
|
+
};
|
|
15
|
+
timeout: {
|
|
16
|
+
type: 'string';
|
|
17
|
+
};
|
|
18
|
+
resume: {
|
|
19
|
+
type: 'string';
|
|
20
|
+
};
|
|
21
|
+
'allow-checks': {
|
|
22
|
+
type: 'boolean';
|
|
23
|
+
};
|
|
24
|
+
'allow-github-writes': {
|
|
25
|
+
type: 'boolean';
|
|
26
|
+
};
|
|
27
|
+
'dry-run': {
|
|
28
|
+
type: 'boolean';
|
|
29
|
+
};
|
|
30
|
+
model: {
|
|
31
|
+
type: 'string';
|
|
32
|
+
};
|
|
33
|
+
provider: {
|
|
34
|
+
type: 'string';
|
|
35
|
+
};
|
|
36
|
+
json: {
|
|
37
|
+
type: 'boolean';
|
|
38
|
+
};
|
|
39
|
+
help: {
|
|
40
|
+
type: 'boolean';
|
|
41
|
+
short: string;
|
|
42
|
+
};
|
|
43
|
+
base: {
|
|
44
|
+
type: 'string';
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export declare function agentDoctor(home?: string, env?: NodeJS.ProcessEnv): Promise<{
|
|
48
|
+
runtime: boolean;
|
|
49
|
+
compatible: boolean;
|
|
50
|
+
server: boolean;
|
|
51
|
+
profile: boolean;
|
|
52
|
+
githubToken: boolean;
|
|
53
|
+
home: string;
|
|
54
|
+
ready: boolean;
|
|
55
|
+
detail: string;
|
|
56
|
+
next: string;
|
|
57
|
+
}>;
|
|
58
|
+
export declare function fetchHermesSource(home?: string, signal?: AbortSignal): Promise<{
|
|
59
|
+
source: string;
|
|
60
|
+
revision: string;
|
|
61
|
+
directory: string;
|
|
62
|
+
license: string;
|
|
63
|
+
installed: boolean;
|
|
64
|
+
}>;
|
|
65
|
+
export declare function agentCommand(sub?: string, positionals?: string[], flags?: Record<string, any>, options?: {
|
|
66
|
+
root?: string;
|
|
67
|
+
signal?: AbortSignal;
|
|
68
|
+
out?: (text: string) => void;
|
|
69
|
+
err?: (text: string) => void;
|
|
70
|
+
}): Promise<number>;
|
|
71
|
+
export declare function explorerAgent(args: string[], root: string, signal: AbortSignal, out: (text: string) => void, err: (text: string) => void): Promise<string>;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { parseArgs } from 'node:util';
|
|
6
|
+
import { AGENT_MODES } from './contracts.js';
|
|
7
|
+
import { agentHome, setupAgent, prepareAgentProfile, runtimePaths, hermesBinary, hermesEnvironment, HERMES_SOURCE, HERMES_REVISION } from './config.js';
|
|
8
|
+
import { runAgent, savedRun } from './runner.js';
|
|
9
|
+
import { runProcess, terminalText, redact } from './process.js';
|
|
10
|
+
import { githubToken } from './github.js';
|
|
11
|
+
export const AGENT_HELP = `
|
|
12
|
+
Onboarder agent — Hermes with repository and GitHub tools
|
|
13
|
+
|
|
14
|
+
onboarder agent setup Create a dedicated Hermes profile
|
|
15
|
+
onboarder chat [folder] Open the conversational harness with / commands
|
|
16
|
+
onboarder agent model Configure its model/provider interactively
|
|
17
|
+
onboarder agent doctor Check runtime and integration compatibility
|
|
18
|
+
onboarder agent source Fetch the researched official Hermes source
|
|
19
|
+
onboarder agent runs List saved runs
|
|
20
|
+
onboarder agent show <run-id> Inspect a saved result and workspace
|
|
21
|
+
onboarder agent <workflow> [folder] --task "..."
|
|
22
|
+
|
|
23
|
+
Workflows: ask, review, triage, implement, pr, github
|
|
24
|
+
--pr <number> Review/inspect a GitHub pull request
|
|
25
|
+
--issue <number> Work from an issue
|
|
26
|
+
--base <branch> PR target (default: origin HEAD, or current branch)
|
|
27
|
+
--allow-checks Allow npm install/test/typecheck/build (repository code)
|
|
28
|
+
--allow-github-writes Allow issue/review/comment updates and draft PR publishing
|
|
29
|
+
--max-turns <1–100> Agent turn limit (default: 24)
|
|
30
|
+
--timeout <seconds> Run limit, 15–3600 (default: 300)
|
|
31
|
+
--model <name> --provider <name> Override the dedicated Hermes model
|
|
32
|
+
--resume <run-id> Continue a session; repeat allowed permission flags
|
|
33
|
+
--dry-run Print the plan without a model call or worktree
|
|
34
|
+
--json One JSON result; progress goes to stderr
|
|
35
|
+
|
|
36
|
+
implement/pr use a new Git worktree at committed HEAD. Uncommitted source
|
|
37
|
+
changes are excluded. Without --allow-github-writes, pr prepares a draft locally.
|
|
38
|
+
GitHub uses the checkout's github.com origin and GITHUB_TOKEN or GH_TOKEN.
|
|
39
|
+
Hermes is an optional separate Python runtime: https://github.com/NousResearch/hermes-agent
|
|
40
|
+
Profile/history: ONBOARDER_AGENT_HOME (default: ~/.config/onboarder/agent).
|
|
41
|
+
|
|
42
|
+
onboarder agent ask . --task "Explain the authentication flow"
|
|
43
|
+
onboarder agent review . --pr 42 --task "Find correctness and security issues"
|
|
44
|
+
onboarder agent triage . --issue 12 --task "Investigate and propose a fix"
|
|
45
|
+
onboarder agent implement . --task "Fix issue 12" --issue 12 --allow-checks
|
|
46
|
+
onboarder agent pr . --task "Fix issue 12 and open a draft PR" --issue 12 --allow-checks --allow-github-writes
|
|
47
|
+
`;
|
|
48
|
+
export const AGENT_OPTIONS = {
|
|
49
|
+
task: { type: 'string' }, pr: { type: 'string' }, issue: { type: 'string' },
|
|
50
|
+
'max-turns': { type: 'string' }, timeout: { type: 'string' }, resume: { type: 'string' },
|
|
51
|
+
'allow-checks': { type: 'boolean' }, 'allow-github-writes': { type: 'boolean' }, 'dry-run': { type: 'boolean' },
|
|
52
|
+
model: { type: 'string' }, provider: { type: 'string' }, json: { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
|
|
53
|
+
base: { type: 'string' },
|
|
54
|
+
};
|
|
55
|
+
export async function agentDoctor(home = agentHome(), env = process.env) {
|
|
56
|
+
const paths = runtimePaths(home, env);
|
|
57
|
+
let runtime = false, compatible = false, detail = '';
|
|
58
|
+
try {
|
|
59
|
+
const result = await runProcess(hermesBinary(env), ['chat', '--help'], { env: hermesEnvironment(home, env), timeoutMs: 30_000, maxBytes: 128000 });
|
|
60
|
+
runtime = result.code === 0;
|
|
61
|
+
compatible = runtime && ['--query-file', 'stream-json', '--toolsets', '--run-budget', '--ignore-rules', '--no-restore-cwd'].every(s => result.stdout.includes(s));
|
|
62
|
+
if (!compatible)
|
|
63
|
+
detail = result.code ? result.stderr.slice(-2000) || 'Hermes could not start.' : 'Update Hermes to a runtime supporting structured one-shot chat and MCP selection.';
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
detail = redact(e instanceof Error ? e.message : String(e), env);
|
|
67
|
+
}
|
|
68
|
+
const server = await fs.access(paths.server).then(() => true).catch(() => false);
|
|
69
|
+
const profile = await fs.access(path.join(paths.profile, 'config.yaml')).then(() => true).catch(() => false);
|
|
70
|
+
return { runtime, compatible, server, profile, githubToken: Boolean(githubToken(env)), home, ready: runtime && compatible && server && profile, detail,
|
|
71
|
+
next: !runtime ? 'Install Hermes from its official repository, then agent setup and agent model.' : !profile ? 'Run onboarder agent setup, then onboarder agent model.' : 'Model credentials are checked by Hermes when a task runs; use agent model to configure them.' };
|
|
72
|
+
}
|
|
73
|
+
export async function fetchHermesSource(home = agentHome(), signal) {
|
|
74
|
+
const target = path.join(home, 'upstream', 'hermes-agent');
|
|
75
|
+
await fs.mkdir(path.dirname(target), { recursive: true, mode: 0o700 });
|
|
76
|
+
const git = async (args) => {
|
|
77
|
+
const output = await runProcess('git', ['-c', 'http.version=HTTP/1.1', ...args], { signal, timeoutMs: 120_000, maxBytes: 2 * 1024 * 1024 });
|
|
78
|
+
if (output.code)
|
|
79
|
+
throw new Error(`Hermes source fetch failed: ${output.stderr.slice(-1500)}`);
|
|
80
|
+
return output.stdout.trim();
|
|
81
|
+
};
|
|
82
|
+
if (!await fs.access(target).then(() => true).catch(() => false)) {
|
|
83
|
+
const staging = target + '-' + randomUUID();
|
|
84
|
+
try {
|
|
85
|
+
await git(['clone', '--depth', '1', '--no-checkout', '--', HERMES_SOURCE, staging]);
|
|
86
|
+
await fs.rename(staging, target);
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
await fs.rm(staging, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (await git(['-C', target, 'remote', 'get-url', 'origin']) !== HERMES_SOURCE)
|
|
93
|
+
throw new Error('The source cache origin is not the official Hermes repository.');
|
|
94
|
+
if (await git(['-C', target, 'status', '--porcelain']) && await fs.access(path.join(target, 'LICENSE')).then(() => true).catch(() => false))
|
|
95
|
+
throw new Error('The source cache contains edits. Preserve them before updating it.');
|
|
96
|
+
await git(['-C', target, 'fetch', '--depth', '1', 'origin', HERMES_REVISION]);
|
|
97
|
+
await git(['-C', target, '-c', 'core.hooksPath=' + path.join(home, 'empty-hooks'), 'checkout', '--detach', HERMES_REVISION]);
|
|
98
|
+
return { source: HERMES_SOURCE, revision: HERMES_REVISION, directory: target, license: 'MIT', installed: false };
|
|
99
|
+
}
|
|
100
|
+
export async function agentCommand(sub = 'help', positionals = [], flags = {}, options = {}) {
|
|
101
|
+
const out = options.out || console.log, err = options.err || console.error, home = agentHome();
|
|
102
|
+
const print = (value) => out(typeof value === 'string' ? value : JSON.stringify(value, null, 2));
|
|
103
|
+
if (flags.help || sub === 'help') {
|
|
104
|
+
out(AGENT_HELP);
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
if (sub === 'setup') {
|
|
108
|
+
const result = await prepareAgentProfile(home, process.env, options.signal);
|
|
109
|
+
print(flags.json ? result : `Dedicated Hermes profile: ${result.profile}\n${result.created ? 'Created.' : 'Existing model settings preserved.'} Run onboarder agent model to configure its provider.\nRun onboarder agent doctor to check the integration.`);
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
if (sub === 'doctor') {
|
|
113
|
+
const report = await agentDoctor(home);
|
|
114
|
+
print(report);
|
|
115
|
+
return report.ready ? 0 : 1;
|
|
116
|
+
}
|
|
117
|
+
if (sub === 'source') {
|
|
118
|
+
print(await fetchHermesSource(home, options.signal));
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
if (sub === 'model') {
|
|
122
|
+
if (!process.stdin.isTTY)
|
|
123
|
+
throw new Error('Run onboarder agent model in an interactive terminal.');
|
|
124
|
+
await setupAgent(home);
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
const child = spawn(hermesBinary(), ['model'], { env: hermesEnvironment(home), stdio: 'inherit', shell: false, signal: options.signal });
|
|
127
|
+
child.on('error', reject);
|
|
128
|
+
child.on('close', code => resolve(code ?? 1));
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (sub === 'runs') {
|
|
132
|
+
const names = await fs.readdir(runtimePaths(home).runs).catch(e => { if (e.code !== 'ENOENT')
|
|
133
|
+
throw e; return []; });
|
|
134
|
+
const runs = (await Promise.all(names.filter(n => /^[a-f\d-]{36}$/.test(n)).map(async (id) => {
|
|
135
|
+
try {
|
|
136
|
+
const { manifest, result } = await savedRun(id, home);
|
|
137
|
+
return { id, mode: manifest.mode, status: result?.status || 'unfinished', startedAt: manifest.startedAt, workspace: manifest.root, repository: manifest.repository };
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return { id, status: 'unreadable' };
|
|
141
|
+
}
|
|
142
|
+
}))).sort((a, b) => (b.startedAt || '').localeCompare(a.startedAt || ''));
|
|
143
|
+
print(runs);
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
if (sub === 'show') {
|
|
147
|
+
print(await savedRun(positionals[0] || '', home));
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
if (!AGENT_MODES.includes(sub))
|
|
151
|
+
throw new Error('Unknown agent workflow. Run onboarder agent --help.');
|
|
152
|
+
if (positionals.length > 1)
|
|
153
|
+
throw new Error('Use one repository folder and --task "your task".');
|
|
154
|
+
const task = flags.task || (sub === 'review' ? `Review ${flags.pr ? 'pull request ' + flags.pr : 'local changes'} for actionable correctness and security issues.` : sub === 'triage' ? `Investigate ${flags.issue ? 'issue ' + flags.issue : 'open issues'} and propose a prioritized plan.` : '');
|
|
155
|
+
const result = await runAgent({ mode: sub, root: positionals[0] || options.root || '.', task,
|
|
156
|
+
pr: flags.pr === undefined ? undefined : Number(flags.pr), issue: flags.issue === undefined ? undefined : Number(flags.issue),
|
|
157
|
+
maxTurns: flags.maxTurns === undefined ? flags['max-turns'] : flags.maxTurns, timeoutSeconds: flags.timeout,
|
|
158
|
+
allowChecks: flags.allowChecks || flags['allow-checks'], allowGithubWrites: flags.allowGithubWrites || flags['allow-github-writes'], dryRun: flags.dryRun || flags['dry-run'],
|
|
159
|
+
model: flags.model, provider: flags.provider, resume: flags.resume, base: flags.base }, { signal: options.signal,
|
|
160
|
+
onEvent: event => {
|
|
161
|
+
if (event.type === 'tool_use')
|
|
162
|
+
err(` ${terminalText(event.name || 'Tool')}…`);
|
|
163
|
+
if (event.type === 'tool_result' && event.is_error)
|
|
164
|
+
err(` ${terminalText(event.name || 'Tool')} reported an error.`);
|
|
165
|
+
} });
|
|
166
|
+
if ('dryRun' in result || flags.json)
|
|
167
|
+
print(result);
|
|
168
|
+
else
|
|
169
|
+
out(`${terminalText(result.answer)}\n\nRun: ${result.id} (${result.status})\nWorkspace: ${result.workspace}${result.branch ? '\nBranch: ' + result.branch : ''}`);
|
|
170
|
+
return 'dryRun' in result || result.status === 'completed' ? 0 : result.status === 'cancelled' ? 130 : 1;
|
|
171
|
+
}
|
|
172
|
+
export async function explorerAgent(args, root, signal, out, err) {
|
|
173
|
+
const parsed = parseArgs({ args, options: AGENT_OPTIONS, allowPositionals: true });
|
|
174
|
+
await agentCommand(parsed.positionals[0], parsed.positionals.slice(1), parsed.values, { root, signal, out, err });
|
|
175
|
+
return '';
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/cli/agent/command.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { spawn } from 'node:child_process';\nimport { parseArgs } from 'node:util';\nimport { AGENT_MODES, type AgentMode } from './contracts.js';\nimport { agentHome, setupAgent, prepareAgentProfile, runtimePaths, hermesBinary, hermesEnvironment, HERMES_SOURCE, HERMES_REVISION } from './config.js';\nimport { runAgent, savedRun } from './runner.js';\nimport { runProcess, terminalText, redact } from './process.js';\nimport { githubToken } from './github.js';\n\nexport const AGENT_HELP = `\n Onboarder agent — Hermes with repository and GitHub tools\n\n onboarder agent setup Create a dedicated Hermes profile\n onboarder chat [folder] Open the conversational harness with / commands\n onboarder agent model Configure its model/provider interactively\n onboarder agent doctor Check runtime and integration compatibility\n onboarder agent source Fetch the researched official Hermes source\n onboarder agent runs List saved runs\n onboarder agent show <run-id> Inspect a saved result and workspace\n onboarder agent <workflow> [folder] --task \"...\"\n\n Workflows: ask, review, triage, implement, pr, github\n --pr <number> Review/inspect a GitHub pull request\n --issue <number> Work from an issue\n --base <branch> PR target (default: origin HEAD, or current branch)\n --allow-checks Allow npm install/test/typecheck/build (repository code)\n --allow-github-writes Allow issue/review/comment updates and draft PR publishing\n --max-turns <1–100> Agent turn limit (default: 24)\n --timeout <seconds> Run limit, 15–3600 (default: 300)\n --model <name> --provider <name> Override the dedicated Hermes model\n --resume <run-id> Continue a session; repeat allowed permission flags\n --dry-run Print the plan without a model call or worktree\n --json One JSON result; progress goes to stderr\n\n implement/pr use a new Git worktree at committed HEAD. Uncommitted source\n changes are excluded. Without --allow-github-writes, pr prepares a draft locally.\n GitHub uses the checkout's github.com origin and GITHUB_TOKEN or GH_TOKEN.\n Hermes is an optional separate Python runtime: https://github.com/NousResearch/hermes-agent\n Profile/history: ONBOARDER_AGENT_HOME (default: ~/.config/onboarder/agent).\n\n onboarder agent ask . --task \"Explain the authentication flow\"\n onboarder agent review . --pr 42 --task \"Find correctness and security issues\"\n onboarder agent triage . --issue 12 --task \"Investigate and propose a fix\"\n onboarder agent implement . --task \"Fix issue 12\" --issue 12 --allow-checks\n onboarder agent pr . --task \"Fix issue 12 and open a draft PR\" --issue 12 --allow-checks --allow-github-writes\n`;\nexport const AGENT_OPTIONS = {\n task: { type: 'string' as const }, pr: { type: 'string' as const }, issue: { type: 'string' as const },\n 'max-turns': { type: 'string' as const }, timeout: { type: 'string' as const }, resume: { type: 'string' as const },\n 'allow-checks': { type: 'boolean' as const }, 'allow-github-writes': { type: 'boolean' as const }, 'dry-run': { type: 'boolean' as const },\n model: { type: 'string' as const }, provider: { type: 'string' as const }, json: { type: 'boolean' as const }, help: { type: 'boolean' as const, short: 'h' },\n base: { type: 'string' as const },\n};\nexport async function agentDoctor(home = agentHome(), env: NodeJS.ProcessEnv = process.env) {\n const paths = runtimePaths(home, env);\n let runtime = false, compatible = false, detail = '';\n try {\n const result = await runProcess(hermesBinary(env), ['chat', '--help'], { env: hermesEnvironment(home, env), timeoutMs: 30_000, maxBytes: 128000 });\n runtime = result.code === 0;\n compatible = runtime && ['--query-file', 'stream-json', '--toolsets', '--run-budget', '--ignore-rules', '--no-restore-cwd'].every(s => result.stdout.includes(s));\n if (!compatible) detail = result.code ? result.stderr.slice(-2000) || 'Hermes could not start.' : 'Update Hermes to a runtime supporting structured one-shot chat and MCP selection.';\n } catch (e) { detail = redact(e instanceof Error ? e.message : String(e), env); }\n const server = await fs.access(paths.server).then(() => true).catch(() => false);\n const profile = await fs.access(path.join(paths.profile, 'config.yaml')).then(() => true).catch(() => false);\n return { runtime, compatible, server, profile, githubToken: Boolean(githubToken(env)), home, ready: runtime && compatible && server && profile, detail,\n next: !runtime ? 'Install Hermes from its official repository, then agent setup and agent model.' : !profile ? 'Run onboarder agent setup, then onboarder agent model.' : 'Model credentials are checked by Hermes when a task runs; use agent model to configure them.' };\n}\nexport async function fetchHermesSource(home = agentHome(), signal?: AbortSignal) {\n const target = path.join(home, 'upstream', 'hermes-agent');\n await fs.mkdir(path.dirname(target), { recursive: true, mode: 0o700 });\n const git = async (args: string[]) => {\n const output = await runProcess('git', ['-c', 'http.version=HTTP/1.1', ...args], { signal, timeoutMs: 120_000, maxBytes: 2 * 1024 * 1024 });\n if (output.code) throw new Error(`Hermes source fetch failed: ${output.stderr.slice(-1500)}`);\n return output.stdout.trim();\n };\n if (!await fs.access(target).then(() => true).catch(() => false)) {\n const staging = target + '-' + randomUUID();\n try { await git(['clone', '--depth', '1', '--no-checkout', '--', HERMES_SOURCE, staging]); await fs.rename(staging, target); }\n finally { await fs.rm(staging, { recursive: true, force: true }); }\n }\n if (await git(['-C', target, 'remote', 'get-url', 'origin']) !== HERMES_SOURCE) throw new Error('The source cache origin is not the official Hermes repository.');\n if (await git(['-C', target, 'status', '--porcelain']) && await fs.access(path.join(target, 'LICENSE')).then(() => true).catch(() => false)) throw new Error('The source cache contains edits. Preserve them before updating it.');\n await git(['-C', target, 'fetch', '--depth', '1', 'origin', HERMES_REVISION]);\n await git(['-C', target, '-c', 'core.hooksPath=' + path.join(home, 'empty-hooks'), 'checkout', '--detach', HERMES_REVISION]);\n return { source: HERMES_SOURCE, revision: HERMES_REVISION, directory: target, license: 'MIT', installed: false };\n}\n\nexport async function agentCommand(sub = 'help', positionals: string[] = [], flags: Record<string, any> = {}, options: { root?: string; signal?: AbortSignal; out?: (text: string) => void; err?: (text: string) => void } = {}) {\n const out = options.out || console.log, err = options.err || console.error, home = agentHome();\n const print = (value: unknown) => out(typeof value === 'string' ? value : JSON.stringify(value, null, 2));\n if (flags.help || sub === 'help') { out(AGENT_HELP); return 0; }\n if (sub === 'setup') {\n const result = await prepareAgentProfile(home, process.env, options.signal);\n print(flags.json ? result : `Dedicated Hermes profile: ${result.profile}\\n${result.created ? 'Created.' : 'Existing model settings preserved.'} Run onboarder agent model to configure its provider.\\nRun onboarder agent doctor to check the integration.`); return 0;\n }\n if (sub === 'doctor') { const report = await agentDoctor(home); print(report); return report.ready ? 0 : 1; }\n if (sub === 'source') { print(await fetchHermesSource(home, options.signal)); return 0; }\n if (sub === 'model') {\n if (!process.stdin.isTTY) throw new Error('Run onboarder agent model in an interactive terminal.');\n await setupAgent(home);\n return new Promise<number>((resolve, reject) => {\n const child = spawn(hermesBinary(), ['model'], { env: hermesEnvironment(home), stdio: 'inherit', shell: false, signal: options.signal });\n child.on('error', reject); child.on('close', code => resolve(code ?? 1));\n });\n }\n if (sub === 'runs') {\n const names = await fs.readdir(runtimePaths(home).runs).catch(e => { if (e.code !== 'ENOENT') throw e; return []; });\n const runs = (await Promise.all(names.filter(n => /^[a-f\\d-]{36}$/.test(n)).map(async id => {\n try { const { manifest, result } = await savedRun(id, home); return { id, mode: manifest.mode, status: result?.status || 'unfinished', startedAt: manifest.startedAt, workspace: manifest.root, repository: manifest.repository }; }\n catch { return { id, status: 'unreadable' }; }\n }))).sort((a, b) => (b.startedAt || '').localeCompare(a.startedAt || ''));\n print(runs); return 0;\n }\n if (sub === 'show') { print(await savedRun(positionals[0] || '', home)); return 0; }\n if (!AGENT_MODES.includes(sub as AgentMode)) throw new Error('Unknown agent workflow. Run onboarder agent --help.');\n if (positionals.length > 1) throw new Error('Use one repository folder and --task \"your task\".');\n const task = flags.task || (sub === 'review' ? `Review ${flags.pr ? 'pull request ' + flags.pr : 'local changes'} for actionable correctness and security issues.` : sub === 'triage' ? `Investigate ${flags.issue ? 'issue ' + flags.issue : 'open issues'} and propose a prioritized plan.` : '');\n const result = await runAgent({ mode: sub as AgentMode, root: positionals[0] || options.root || '.', task,\n pr: flags.pr === undefined ? undefined : Number(flags.pr), issue: flags.issue === undefined ? undefined : Number(flags.issue),\n maxTurns: flags.maxTurns === undefined ? flags['max-turns'] : flags.maxTurns, timeoutSeconds: flags.timeout,\n allowChecks: flags.allowChecks || flags['allow-checks'], allowGithubWrites: flags.allowGithubWrites || flags['allow-github-writes'], dryRun: flags.dryRun || flags['dry-run'],\n model: flags.model, provider: flags.provider, resume: flags.resume, base: flags.base }, { signal: options.signal,\n onEvent: event => {\n if (event.type === 'tool_use') err(` ${terminalText(event.name || 'Tool')}…`);\n if (event.type === 'tool_result' && event.is_error) err(` ${terminalText(event.name || 'Tool')} reported an error.`);\n } });\n if ('dryRun' in result || flags.json) print(result);\n else out(`${terminalText(result.answer)}\\n\\nRun: ${result.id} (${result.status})\\nWorkspace: ${result.workspace}${result.branch ? '\\nBranch: ' + result.branch : ''}`);\n return 'dryRun' in result || result.status === 'completed' ? 0 : result.status === 'cancelled' ? 130 : 1;\n}\n\nexport async function explorerAgent(args: string[], root: string, signal: AbortSignal, out: (text: string) => void, err: (text: string) => void) {\n const parsed = parseArgs({ args, options: AGENT_OPTIONS, allowPositionals: true });\n await agentCommand(parsed.positionals[0], parsed.positionals.slice(1), parsed.values, { root, signal, out, err });\n return '';\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const HERMES_SOURCE = "https://github.com/NousResearch/hermes-agent.git";
|
|
2
|
+
export declare const HERMES_REVISION = "eb7e8620324b32424c06218f6a28094df2e921f8";
|
|
3
|
+
export declare function agentHome(env?: NodeJS.ProcessEnv): string;
|
|
4
|
+
export declare function hermesBinary(env?: NodeJS.ProcessEnv): string;
|
|
5
|
+
export declare function runtimePaths(home?: string, env?: NodeJS.ProcessEnv): {
|
|
6
|
+
home: string;
|
|
7
|
+
profile: string;
|
|
8
|
+
runs: string;
|
|
9
|
+
workspaces: string;
|
|
10
|
+
server: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function hermesEnvironment(home?: string, env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
13
|
+
export declare function setupAgent(home?: string, env?: NodeJS.ProcessEnv): Promise<{
|
|
14
|
+
home: string;
|
|
15
|
+
profile: string;
|
|
16
|
+
runs: string;
|
|
17
|
+
workspaces: string;
|
|
18
|
+
server: string;
|
|
19
|
+
configFile: string;
|
|
20
|
+
created: boolean;
|
|
21
|
+
}>;
|
|
22
|
+
/** Refresh only harness-owned settings; retain the model wizard's provider/auth choices. */
|
|
23
|
+
export declare function prepareAgentProfile(home?: string, env?: NodeJS.ProcessEnv, signal?: AbortSignal): Promise<{
|
|
24
|
+
home: string;
|
|
25
|
+
profile: string;
|
|
26
|
+
runs: string;
|
|
27
|
+
workspaces: string;
|
|
28
|
+
server: string;
|
|
29
|
+
configFile: string;
|
|
30
|
+
created: boolean;
|
|
31
|
+
}>;
|