codebase-onboarder 0.6.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 +284 -53
- package/bin/build-if-source.js +23 -0
- 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/commands.d.ts +26 -0
- package/cli/commands.js +836 -811
- package/cli/commands.js.map +1 -0
- package/cli/explorer/advanced.d.ts +14 -0
- package/cli/explorer/advanced.js +321 -329
- package/cli/explorer/advanced.js.map +1 -0
- package/cli/explorer/app.d.ts +2 -0
- package/cli/explorer/app.js +404 -314
- package/cli/explorer/app.js.map +1 -0
- package/cli/explorer/assistant.d.ts +9 -0
- package/cli/explorer/assistant.js +58 -0
- package/cli/explorer/assistant.js.map +1 -0
- package/cli/explorer/commands.d.ts +17 -0
- package/cli/explorer/commands.js +373 -302
- package/cli/explorer/commands.js.map +1 -0
- package/cli/explorer/featureViews.d.ts +124 -0
- package/cli/explorer/featureViews.js +179 -0
- package/cli/explorer/featureViews.js.map +1 -0
- package/cli/explorer/github.d.ts +21 -0
- package/cli/explorer/github.js +42 -44
- package/cli/explorer/github.js.map +1 -0
- package/cli/explorer/graphs.d.ts +7 -0
- package/cli/explorer/graphs.js +90 -95
- package/cli/explorer/graphs.js.map +1 -0
- package/cli/explorer/picker.d.ts +22 -0
- package/cli/explorer/picker.js +150 -0
- package/cli/explorer/picker.js.map +1 -0
- package/cli/explorer/report.d.ts +85 -0
- package/cli/explorer/report.js +60 -0
- package/cli/explorer/report.js.map +1 -0
- package/cli/explorer/session.d.ts +449 -0
- package/cli/explorer/session.js +143 -144
- package/cli/explorer/session.js.map +1 -0
- package/cli/explorer/views.d.ts +19 -0
- package/cli/explorer/views.js +465 -482
- package/cli/explorer/views.js.map +1 -0
- package/cli/explorer/wrap.d.ts +1 -0
- package/cli/explorer/wrap.js +28 -44
- package/cli/explorer/wrap.js.map +1 -0
- package/cli/main.d.ts +1 -0
- package/cli/main.js +251 -164
- package/cli/main.js.map +1 -0
- package/cli/prompt.d.ts +5 -0
- package/cli/prompt.js +84 -80
- package/cli/prompt.js.map +1 -0
- package/cli/scanOptions.d.ts +2 -0
- package/cli/scanOptions.js +11 -0
- package/cli/scanOptions.js.map +1 -0
- package/cli/ui.d.ts +33 -0
- package/cli/ui.js +35 -44
- package/cli/ui.js.map +1 -0
- package/cli/wizard.d.ts +187 -0
- package/cli/wizard.js +304 -284
- package/cli/wizard.js.map +1 -0
- package/docs/HERMES_RESEARCH.md +51 -0
- package/package.json +16 -4
- package/public/app.d.ts +1 -0
- package/public/app.js +1133 -1011
- package/public/app.js.map +1 -0
- package/public/assets/onboarder-mark.svg +11 -0
- package/public/browser.d.ts +71 -0
- package/public/browser.js +2 -0
- package/public/browser.js.map +1 -0
- package/public/index.html +54 -20
- package/public/js/about.d.ts +6 -0
- package/public/js/about.js +152 -172
- package/public/js/about.js.map +1 -0
- package/public/js/aiDraft.d.ts +4 -0
- package/public/js/aiDraft.js +166 -125
- package/public/js/aiDraft.js.map +1 -0
- package/public/js/analysisPanel.d.ts +7 -0
- package/public/js/analysisPanel.js +166 -166
- package/public/js/analysisPanel.js.map +1 -0
- package/public/js/analysisReport.d.ts +38 -0
- package/public/js/analysisReport.js +105 -110
- package/public/js/analysisReport.js.map +1 -0
- package/public/js/api.d.ts +29 -0
- package/public/js/api.js +198 -166
- package/public/js/api.js.map +1 -0
- package/public/js/atlas.d.ts +6 -0
- package/public/js/atlas.js +50 -58
- package/public/js/atlas.js.map +1 -0
- package/public/js/blameView.d.ts +2 -0
- package/public/js/blameView.js +36 -37
- package/public/js/blameView.js.map +1 -0
- package/public/js/codeTab.d.ts +3 -0
- package/public/js/codeTab.js +175 -180
- package/public/js/codeTab.js.map +1 -0
- package/public/js/codeViewer.d.ts +5 -0
- package/public/js/codeViewer.js +162 -150
- package/public/js/codeViewer.js.map +1 -0
- package/public/js/components/FileChip.d.ts +9 -0
- package/public/js/components/FileChip.js +45 -49
- package/public/js/components/FileChip.js.map +1 -0
- package/public/js/components/MetricSparkline.d.ts +7 -0
- package/public/js/components/MetricSparkline.js +35 -44
- package/public/js/components/MetricSparkline.js.map +1 -0
- package/public/js/components/RiskBadge.d.ts +9 -0
- package/public/js/components/RiskBadge.js +55 -63
- package/public/js/components/RiskBadge.js.map +1 -0
- package/public/js/deepAnalysisView.d.ts +99 -0
- package/public/js/deepAnalysisView.js +282 -302
- package/public/js/deepAnalysisView.js.map +1 -0
- package/public/js/diagramPane.d.ts +9 -0
- package/public/js/diagramPane.js +138 -135
- package/public/js/diagramPane.js.map +1 -0
- package/public/js/diffView.d.ts +6 -0
- package/public/js/diffView.js +222 -209
- package/public/js/diffView.js.map +1 -0
- package/public/js/docsView.d.ts +2 -0
- package/public/js/docsView.js +441 -442
- package/public/js/docsView.js.map +1 -0
- package/public/js/dom.d.ts +197 -0
- package/public/js/dom.js +5 -0
- package/public/js/dom.js.map +1 -0
- package/public/js/fileSourceBrowser.d.ts +5 -0
- package/public/js/fileSourceBrowser.js +33 -41
- package/public/js/fileSourceBrowser.js.map +1 -0
- package/public/js/flameGraph.d.ts +5 -0
- package/public/js/flameGraph.js +62 -72
- package/public/js/flameGraph.js.map +1 -0
- package/public/js/forceGraph.d.ts +10 -0
- package/public/js/forceGraph.js +581 -556
- package/public/js/forceGraph.js.map +1 -0
- package/public/js/heatmap.d.ts +4 -0
- package/public/js/heatmap.js +142 -164
- package/public/js/heatmap.js.map +1 -0
- package/public/js/highlight.d.ts +2 -0
- package/public/js/highlight.js +116 -107
- package/public/js/highlight.js.map +1 -0
- package/public/js/html.d.ts +2 -0
- package/public/js/html.js +14 -44
- package/public/js/html.js.map +1 -0
- package/public/js/insightsView.d.ts +5 -0
- package/public/js/insightsView.js +93 -111
- package/public/js/insightsView.js.map +1 -0
- package/public/js/inspector.d.ts +37 -0
- package/public/js/inspector.js +416 -445
- package/public/js/inspector.js.map +1 -0
- package/public/js/llm.d.ts +115 -0
- package/public/js/llm.js +246 -278
- package/public/js/llm.js.map +1 -0
- package/public/js/mapView.d.ts +3 -0
- package/public/js/mapView.js +121 -120
- package/public/js/mapView.js.map +1 -0
- package/public/js/markdown.d.ts +3 -0
- package/public/js/markdown.js +84 -91
- package/public/js/markdown.js.map +1 -0
- package/public/js/mindmap.d.ts +32 -0
- package/public/js/mindmap.js +244 -259
- package/public/js/mindmap.js.map +1 -0
- package/public/js/mobilePanels.d.ts +5 -0
- package/public/js/mobilePanels.js +50 -0
- package/public/js/mobilePanels.js.map +1 -0
- package/public/js/repoFiles.d.ts +12 -0
- package/public/js/repoFiles.js +29 -28
- package/public/js/repoFiles.js.map +1 -0
- package/public/js/reviewView.d.ts +28 -0
- package/public/js/reviewView.js +256 -0
- package/public/js/reviewView.js.map +1 -0
- package/public/js/sbomView.d.ts +3 -0
- package/public/js/sbomView.js +59 -67
- package/public/js/sbomView.js.map +1 -0
- package/public/js/scanCache.d.ts +16 -0
- package/public/js/scanCache.js +67 -65
- package/public/js/scanCache.js.map +1 -0
- package/public/js/search.d.ts +7 -0
- package/public/js/search.js +868 -800
- package/public/js/search.js.map +1 -0
- package/public/js/searchLocal.d.ts +42 -0
- package/public/js/searchLocal.js +87 -0
- package/public/js/searchLocal.js.map +1 -0
- package/public/js/serverSettings.d.ts +5 -0
- package/public/js/serverSettings.js +153 -164
- package/public/js/serverSettings.js.map +1 -0
- package/public/js/state.d.ts +798 -0
- package/public/js/state.js +114 -122
- package/public/js/state.js.map +1 -0
- package/public/js/tour.d.ts +6 -0
- package/public/js/tour.js +5 -7
- package/public/js/tour.js.map +1 -0
- package/public/js/transitions.d.ts +2 -0
- package/public/js/transitions.js +9 -10
- package/public/js/transitions.js.map +1 -0
- package/public/js/tree.d.ts +12 -0
- package/public/js/tree.js +157 -154
- package/public/js/tree.js.map +1 -0
- package/public/js/workflowsView.d.ts +3 -0
- package/public/js/workflowsView.js +15 -22
- package/public/js/workflowsView.js.map +1 -0
- package/public/search.css +495 -0
- package/public/styles.css +188 -346
- package/public/workbench.css +166 -0
- package/server/apiAuth.d.ts +3 -0
- package/server/apiAuth.js +18 -20
- package/server/apiAuth.js.map +1 -0
- package/server/apiDiff.d.ts +2 -0
- package/server/apiDiff.js +20 -18
- package/server/apiDiff.js.map +1 -0
- package/server/apiDocs.d.ts +2 -0
- package/server/apiDocs.js +38 -40
- package/server/apiDocs.js.map +1 -0
- package/server/apiFile.d.ts +1 -0
- package/server/apiFile.js +14 -17
- package/server/apiFile.js.map +1 -0
- package/server/apiGitBlame.d.ts +2 -0
- package/server/apiGitBlame.js +50 -51
- package/server/apiGitBlame.js.map +1 -0
- package/server/apiMcp.d.ts +4 -0
- package/server/apiMcp.js +64 -66
- package/server/apiMcp.js.map +1 -0
- package/server/apiReview.d.ts +2 -0
- package/server/apiReview.js +45 -0
- package/server/apiReview.js.map +1 -0
- package/server/apiScan.d.ts +5 -0
- package/server/apiScan.js +90 -71
- package/server/apiScan.js.map +1 -0
- package/server/apiSearch.d.ts +33 -0
- package/server/apiSearch.js +184 -200
- package/server/apiSearch.js.map +1 -0
- package/server/apiSettings.d.ts +4 -0
- package/server/apiSettings.js +84 -85
- package/server/apiSettings.js.map +1 -0
- package/server/apiTools.d.ts +3 -0
- package/server/apiTools.js +55 -56
- package/server/apiTools.js.map +1 -0
- package/server/auth.d.ts +5 -0
- package/server/auth.js +54 -51
- package/server/auth.js.map +1 -0
- package/server/config.d.ts +42 -0
- package/server/config.js +189 -194
- package/server/config.js.map +1 -0
- package/server/daemon.d.ts +12 -0
- package/server/daemon.js +124 -114
- package/server/daemon.js.map +1 -0
- package/server/fileSourceNode.d.ts +2 -0
- package/server/fileSourceNode.js +34 -36
- package/server/fileSourceNode.js.map +1 -0
- package/server/gitClone.d.ts +9 -0
- package/server/gitClone.js +59 -61
- package/server/gitClone.js.map +1 -0
- package/server/gitDiff.d.ts +36 -0
- package/server/gitDiff.js +271 -169
- package/server/gitDiff.js.map +1 -0
- package/server/gitHistory.d.ts +12 -0
- package/server/gitHistory.js +80 -80
- package/server/gitHistory.js.map +1 -0
- package/server/gitRemote.d.ts +12 -0
- package/server/gitRemote.js +37 -38
- package/server/gitRemote.js.map +1 -0
- package/server/hermesChat.d.ts +13 -0
- package/server/hermesChat.js +145 -0
- package/server/hermesChat.js.map +1 -0
- package/server/htmlText.d.ts +4 -0
- package/server/htmlText.js +16 -23
- package/server/htmlText.js.map +1 -0
- package/server/http.d.ts +6 -0
- package/server/http.js +27 -34
- package/server/http.js.map +1 -0
- package/server/httpGuards.d.ts +2 -0
- package/server/httpGuards.js +47 -43
- package/server/httpGuards.js.map +1 -0
- package/server/https.d.ts +34 -0
- package/server/https.js +121 -111
- package/server/https.js.map +1 -0
- package/server/index.d.ts +40 -0
- package/server/index.js +139 -147
- package/server/index.js.map +1 -0
- package/server/layout.d.ts +26 -0
- package/server/layout.js +59 -64
- package/server/layout.js.map +1 -0
- package/server/llmProxy.d.ts +3 -0
- package/server/llmProxy.js +137 -135
- package/server/llmProxy.js.map +1 -0
- package/server/logger.d.ts +38 -0
- package/server/logger.js +198 -211
- package/server/logger.js.map +1 -0
- package/server/mcp/analysis.d.ts +29 -0
- package/server/mcp/analysis.js +99 -120
- package/server/mcp/analysis.js.map +1 -0
- package/server/mcp/http.d.ts +9 -0
- package/server/mcp/http.js +128 -137
- package/server/mcp/http.js.map +1 -0
- package/server/mcp/runner.d.ts +68 -0
- package/server/mcp/runner.js +208 -218
- package/server/mcp/runner.js.map +1 -0
- package/server/mcp/server.d.ts +29 -0
- package/server/mcp/server.js +167 -180
- package/server/mcp/server.js.map +1 -0
- package/server/mcp/standalone.d.ts +1 -0
- package/server/mcp/standalone.js +8 -10
- package/server/mcp/standalone.js.map +1 -0
- package/server/mcp/tools.d.ts +2020 -0
- package/server/mcp/tools.js +523 -574
- package/server/mcp/tools.js.map +1 -0
- package/server/paths.d.ts +3 -0
- package/server/paths.js +17 -15
- package/server/paths.js.map +1 -0
- package/server/pidfile.d.ts +9 -0
- package/server/pidfile.js +43 -45
- package/server/pidfile.js.map +1 -0
- package/server/review.d.ts +5 -0
- package/server/review.js +35 -0
- package/server/review.js.map +1 -0
- package/server/router.d.ts +33 -0
- package/server/router.js +195 -197
- package/server/router.js.map +1 -0
- package/server/scanRequest.d.ts +3 -0
- package/server/scanRequest.js +36 -0
- package/server/scanRequest.js.map +1 -0
- package/server/searchIndex.d.ts +17 -0
- package/server/searchIndex.js +83 -80
- package/server/searchIndex.js.map +1 -0
- package/server/sessions.d.ts +14 -0
- package/server/sessions.js +62 -70
- package/server/sessions.js.map +1 -0
- package/server/startup.d.ts +118 -0
- package/server/startup.js +143 -148
- package/server/startup.js.map +1 -0
- package/server/static.d.ts +6 -0
- package/server/static.js +28 -31
- package/server/static.js.map +1 -0
- package/server/tools/install.d.ts +4 -0
- package/server/tools/install.js +176 -185
- package/server/tools/install.js.map +1 -0
- package/server/tools/parse.d.ts +8 -0
- package/server/tools/parse.js +112 -114
- package/server/tools/parse.js.map +1 -0
- package/server/tools/platform.d.ts +9 -0
- package/server/tools/platform.js +49 -47
- package/server/tools/platform.js.map +1 -0
- package/server/tools/registry.d.ts +137 -0
- package/server/tools/registry.js +173 -172
- package/server/tools/registry.js.map +1 -0
- package/server/tools/scan.d.ts +34 -0
- package/server/tools/scan.js +89 -98
- package/server/tools/scan.js.map +1 -0
- package/server/tools.d.ts +34 -0
- package/server/tools.js +94 -107
- package/server/tools.js.map +1 -0
- package/server/tunnel.d.ts +29 -0
- package/server/tunnel.js +61 -66
- package/server/tunnel.js.map +1 -0
- package/shared/analyzer/docs.d.ts +16 -0
- package/shared/analyzer/docs.js +99 -93
- package/shared/analyzer/docs.js.map +1 -0
- package/shared/analyzer/explainLocal.d.ts +4 -0
- package/shared/analyzer/explainLocal.js +122 -142
- package/shared/analyzer/explainLocal.js.map +1 -0
- package/shared/analyzer/github.d.ts +37 -0
- package/shared/analyzer/github.js +41 -43
- package/shared/analyzer/github.js.map +1 -0
- package/shared/analyzer/graph.d.ts +41 -0
- package/shared/analyzer/graph.js +393 -400
- package/shared/analyzer/graph.js.map +1 -0
- package/shared/analyzer/health.d.ts +33 -0
- package/shared/analyzer/health.js +197 -193
- package/shared/analyzer/health.js.map +1 -0
- package/shared/analyzer/history.d.ts +29 -0
- package/shared/analyzer/history.js +110 -111
- package/shared/analyzer/history.js.map +1 -0
- package/shared/analyzer/jsonConfig.d.ts +2 -0
- package/shared/analyzer/jsonConfig.js +61 -0
- package/shared/analyzer/jsonConfig.js.map +1 -0
- package/shared/analyzer/languages/csharp.d.ts +26 -0
- package/shared/analyzer/languages/csharp.js +83 -88
- package/shared/analyzer/languages/csharp.js.map +1 -0
- package/shared/analyzer/languages/generic.d.ts +23 -0
- package/shared/analyzer/languages/generic.js +94 -105
- package/shared/analyzer/languages/generic.js.map +1 -0
- package/shared/analyzer/languages/go.d.ts +24 -0
- package/shared/analyzer/languages/go.js +45 -54
- package/shared/analyzer/languages/go.js.map +1 -0
- package/shared/analyzer/languages/index.d.ts +6 -0
- package/shared/analyzer/languages/index.js +19 -20
- package/shared/analyzer/languages/index.js.map +1 -0
- package/shared/analyzer/languages/java.d.ts +20 -0
- package/shared/analyzer/languages/java.js +73 -78
- package/shared/analyzer/languages/java.js.map +1 -0
- package/shared/analyzer/languages/javascript.d.ts +12 -0
- package/shared/analyzer/languages/javascript.js +258 -209
- package/shared/analyzer/languages/javascript.js.map +1 -0
- package/shared/analyzer/languages/python.d.ts +23 -0
- package/shared/analyzer/languages/python.js +92 -100
- package/shared/analyzer/languages/python.js.map +1 -0
- package/shared/analyzer/languages/rust.d.ts +17 -0
- package/shared/analyzer/languages/rust.js +96 -98
- package/shared/analyzer/languages/rust.js.map +1 -0
- package/shared/analyzer/languages/typescript.d.ts +11 -0
- package/shared/analyzer/languages/typescript.js +117 -116
- package/shared/analyzer/languages/typescript.js.map +1 -0
- package/shared/analyzer/licenses.d.ts +18 -0
- package/shared/analyzer/licenses.js +130 -133
- package/shared/analyzer/licenses.js.map +1 -0
- package/shared/analyzer/metrics.d.ts +20 -0
- package/shared/analyzer/metrics.js +112 -104
- package/shared/analyzer/metrics.js.map +1 -0
- package/shared/analyzer/pathUtil.d.ts +10 -0
- package/shared/analyzer/pathUtil.js +29 -35
- package/shared/analyzer/pathUtil.js.map +1 -0
- package/shared/analyzer/patterns.d.ts +11 -0
- package/shared/analyzer/patterns.js +231 -253
- package/shared/analyzer/patterns.js.map +1 -0
- package/shared/analyzer/scan.d.ts +62 -0
- package/shared/analyzer/scan.js +451 -442
- package/shared/analyzer/scan.js.map +1 -0
- package/shared/analyzer/scanControl.d.ts +11 -0
- package/shared/analyzer/scanControl.js +62 -0
- package/shared/analyzer/scanControl.js.map +1 -0
- package/shared/analyzer/security.d.ts +18 -0
- package/shared/analyzer/security.js +159 -159
- package/shared/analyzer/security.js.map +1 -0
- package/shared/analyzer/services.d.ts +5 -0
- package/shared/analyzer/services.js +141 -138
- package/shared/analyzer/services.js.map +1 -0
- package/shared/analyzer/stack.d.ts +6 -0
- package/shared/analyzer/stack.js +134 -141
- package/shared/analyzer/stack.js.map +1 -0
- package/shared/analyzer/tour.d.ts +2 -0
- package/shared/analyzer/tour.js +45 -53
- package/shared/analyzer/tour.js.map +1 -0
- package/shared/analyzer/util.d.ts +8 -0
- package/shared/analyzer/util.js +130 -76
- package/shared/analyzer/util.js.map +1 -0
- package/shared/analyzer/workflows.d.ts +8 -0
- package/shared/analyzer/workflows.js +139 -134
- package/shared/analyzer/workflows.js.map +1 -0
- package/shared/contracts.d.ts +250 -0
- package/shared/contracts.js +2 -0
- package/shared/contracts.js.map +1 -0
- package/shared/diagram/aiFacts.d.ts +35 -0
- package/shared/diagram/aiFacts.js +102 -105
- package/shared/diagram/aiFacts.js.map +1 -0
- package/shared/diagram/aiMermaid.d.ts +5 -0
- package/shared/diagram/aiMermaid.js +50 -46
- package/shared/diagram/aiMermaid.js.map +1 -0
- package/shared/diagram/atlas.d.ts +16 -0
- package/shared/diagram/atlas.js +51 -60
- package/shared/diagram/atlas.js.map +1 -0
- package/shared/diagram/mermaid.d.ts +43 -0
- package/shared/diagram/mermaid.js +348 -370
- package/shared/diagram/mermaid.js.map +1 -0
- package/shared/review/contracts.d.ts +95 -0
- package/shared/review/contracts.js +2 -0
- package/shared/review/contracts.js.map +1 -0
- package/shared/review/review.d.ts +10 -0
- package/shared/review/review.js +184 -0
- package/shared/review/review.js.map +1 -0
- package/shared/search/query.d.ts +32 -0
- package/shared/search/query.js +395 -388
- package/shared/search/query.js.map +1 -0
|
@@ -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
|
+
}>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
7
|
+
import { runProcess } from './process.js';
|
|
8
|
+
export const HERMES_SOURCE = 'https://github.com/NousResearch/hermes-agent.git';
|
|
9
|
+
export const HERMES_REVISION = 'eb7e8620324b32424c06218f6a28094df2e921f8';
|
|
10
|
+
export function agentHome(env = process.env) {
|
|
11
|
+
return path.resolve(env.ONBOARDER_AGENT_HOME || path.join(env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'onboarder', 'agent'));
|
|
12
|
+
}
|
|
13
|
+
export function hermesBinary(env = process.env) {
|
|
14
|
+
return env.ONBOARDER_HERMES_BIN || 'hermes';
|
|
15
|
+
}
|
|
16
|
+
export function runtimePaths(home = agentHome(), env = process.env) {
|
|
17
|
+
const native = process.platform === 'win32' ? path.join(env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), 'hermes') : path.join(os.homedir(), '.hermes');
|
|
18
|
+
const configured = env.HERMES_HOME ? (path.basename(path.dirname(env.HERMES_HOME)) === 'profiles' ? path.dirname(path.dirname(env.HERMES_HOME)) : env.HERMES_HOME) : native;
|
|
19
|
+
// Named profiles share the installation's Python store, but not its config,
|
|
20
|
+
// credentials, sessions, memory, or MCP server selection.
|
|
21
|
+
const name = 'onboarder-' + createHash('sha256').update(path.resolve(home)).digest('hex').slice(0, 12);
|
|
22
|
+
return { home, profile: path.join(configured, 'profiles', name), runs: path.join(home, 'runs'), workspaces: path.join(home, 'workspaces'), server: fileURLToPath(new URL('./stdio.js', import.meta.url)) };
|
|
23
|
+
}
|
|
24
|
+
export function hermesEnvironment(home = agentHome(), env = process.env) {
|
|
25
|
+
return { ...env, HERMES_HOME: runtimePaths(home, env).profile, OPENAI_API_KEY: env.ONBOARDER_AI_API_KEY || env.OPENAI_API_KEY,
|
|
26
|
+
PATH: [path.join(os.homedir(), '.local', 'bin'), env.PATH || ''].join(path.delimiter) };
|
|
27
|
+
}
|
|
28
|
+
export async function setupAgent(home = agentHome(), env = process.env) {
|
|
29
|
+
const paths = runtimePaths(home, env);
|
|
30
|
+
for (const dir of [paths.profile, paths.runs, paths.workspaces])
|
|
31
|
+
await fs.mkdir(dir, { recursive: true, mode: 0o700 });
|
|
32
|
+
const file = path.join(paths.profile, 'config.yaml');
|
|
33
|
+
const base = env.ONBOARDER_AI_BASE_URL || env.OPENAI_BASE_URL;
|
|
34
|
+
const model = env.ONBOARDER_AI_MODEL || env.OPENAI_MODEL;
|
|
35
|
+
// JSON is a YAML subset. Hermes can subsequently maintain this file with its own model wizard.
|
|
36
|
+
const config = {
|
|
37
|
+
...(base && model ? { model: { provider: 'custom', base_url: base, default: model } } : {}),
|
|
38
|
+
agent: { max_turns: 24 }, memory: { memory_enabled: false, user_profile_enabled: false },
|
|
39
|
+
tools: { tool_search: { enabled: 'off' } },
|
|
40
|
+
mcp_servers: { onboarder: { command: process.execPath, args: [paths.server],
|
|
41
|
+
env: { ONBOARDER_AGENT_RUN: '${ONBOARDER_AGENT_RUN}', GITHUB_TOKEN: '${GITHUB_TOKEN}', GH_TOKEN: '${GH_TOKEN}' },
|
|
42
|
+
tools: { prompts: false, resources: false }, connect_timeout: 30, timeout: 150 } },
|
|
43
|
+
};
|
|
44
|
+
let created = false;
|
|
45
|
+
try {
|
|
46
|
+
await fs.writeFile(file, JSON.stringify(config, null, 2) + '\n', { mode: 0o600, flag: 'wx' });
|
|
47
|
+
created = true;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (error.code !== 'EEXIST')
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
return { ...paths, configFile: file, created };
|
|
54
|
+
}
|
|
55
|
+
/** Refresh only harness-owned settings; retain the model wizard's provider/auth choices. */
|
|
56
|
+
export async function prepareAgentProfile(home = agentHome(), env = process.env, signal) {
|
|
57
|
+
const setup = await setupAgent(home, env);
|
|
58
|
+
if (setup.created)
|
|
59
|
+
return setup;
|
|
60
|
+
const server = { command: process.execPath, args: [setup.server],
|
|
61
|
+
env: { ONBOARDER_AGENT_RUN: '${ONBOARDER_AGENT_RUN}', GITHUB_TOKEN: '${GITHUB_TOKEN}', GH_TOKEN: '${GH_TOKEN}' },
|
|
62
|
+
tools: { prompts: false, resources: false }, connect_timeout: 30, timeout: 150 };
|
|
63
|
+
const source = await fs.readFile(setup.configFile, 'utf8');
|
|
64
|
+
let config = null;
|
|
65
|
+
try {
|
|
66
|
+
const value = JSON.parse(source);
|
|
67
|
+
if (value && typeof value === 'object' && !Array.isArray(value))
|
|
68
|
+
config = value;
|
|
69
|
+
}
|
|
70
|
+
catch { /* Hermes' model wizard writes native YAML. */ }
|
|
71
|
+
if (config) {
|
|
72
|
+
config.mcp_servers = { ...(config.mcp_servers || {}), onboarder: server };
|
|
73
|
+
config.tools = { ...(config.tools || {}), tool_search: { ...(config.tools?.tool_search || {}), enabled: 'off' } };
|
|
74
|
+
config.memory = { ...(config.memory || {}), memory_enabled: false, user_profile_enabled: false };
|
|
75
|
+
const next = JSON.stringify(config, null, 2) + '\n';
|
|
76
|
+
if (source !== next) {
|
|
77
|
+
const temporary = setup.configFile + '-' + randomUUID();
|
|
78
|
+
try {
|
|
79
|
+
await fs.writeFile(temporary, next, { flag: 'wx', mode: 0o600 });
|
|
80
|
+
await fs.rename(temporary, setup.configFile);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
await fs.rm(temporary, { force: true });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Let Hermes parse/preserve its own YAML rather than adding a Node dependency
|
|
89
|
+
// or hand-editing the model wizard's configuration.
|
|
90
|
+
for (const [key, value] of [['mcp_servers.onboarder', JSON.stringify(server)], ['tools.tool_search.enabled', 'off'], ['memory.memory_enabled', 'false'], ['memory.user_profile_enabled', 'false']]) {
|
|
91
|
+
const result = await runProcess(hermesBinary(env), ['config', 'set', key, value], { env: hermesEnvironment(home, env), signal, timeoutMs: 30_000, maxBytes: 128000 });
|
|
92
|
+
if (result.code)
|
|
93
|
+
throw new Error(`Could not refresh the dedicated Hermes profile: ${result.stderr.slice(-1500) || result.stdout.slice(-1500)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return setup;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/cli/agent/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { fileURLToPath } from 'node:url';\nimport { randomUUID } from 'node:crypto';\nimport { runProcess } from './process.js';\n\nexport const HERMES_SOURCE = 'https://github.com/NousResearch/hermes-agent.git';\nexport const HERMES_REVISION = 'eb7e8620324b32424c06218f6a28094df2e921f8';\nexport function agentHome(env: NodeJS.ProcessEnv = process.env): string {\n return path.resolve(env.ONBOARDER_AGENT_HOME || path.join(env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'onboarder', 'agent'));\n}\nexport function hermesBinary(env: NodeJS.ProcessEnv = process.env): string {\n return env.ONBOARDER_HERMES_BIN || 'hermes';\n}\nexport function runtimePaths(home = agentHome(), env: NodeJS.ProcessEnv = process.env) {\n const native = process.platform === 'win32' ? path.join(env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), 'hermes') : path.join(os.homedir(), '.hermes');\n const configured = env.HERMES_HOME ? (path.basename(path.dirname(env.HERMES_HOME)) === 'profiles' ? path.dirname(path.dirname(env.HERMES_HOME)) : env.HERMES_HOME) : native;\n // Named profiles share the installation's Python store, but not its config,\n // credentials, sessions, memory, or MCP server selection.\n const name = 'onboarder-' + createHash('sha256').update(path.resolve(home)).digest('hex').slice(0, 12);\n return { home, profile: path.join(configured, 'profiles', name), runs: path.join(home, 'runs'), workspaces: path.join(home, 'workspaces'), server: fileURLToPath(new URL('./stdio.js', import.meta.url)) };\n}\nexport function hermesEnvironment(home = agentHome(), env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {\n return { ...env, HERMES_HOME: runtimePaths(home, env).profile, OPENAI_API_KEY: env.ONBOARDER_AI_API_KEY || env.OPENAI_API_KEY,\n PATH: [path.join(os.homedir(), '.local', 'bin'), env.PATH || ''].join(path.delimiter) };\n}\nexport async function setupAgent(home = agentHome(), env: NodeJS.ProcessEnv = process.env) {\n const paths = runtimePaths(home, env);\n for (const dir of [paths.profile, paths.runs, paths.workspaces]) await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n const file = path.join(paths.profile, 'config.yaml');\n const base = env.ONBOARDER_AI_BASE_URL || env.OPENAI_BASE_URL;\n const model = env.ONBOARDER_AI_MODEL || env.OPENAI_MODEL;\n // JSON is a YAML subset. Hermes can subsequently maintain this file with its own model wizard.\n const config = {\n ...(base && model ? { model: { provider: 'custom', base_url: base, default: model } } : {}),\n agent: { max_turns: 24 }, memory: { memory_enabled: false, user_profile_enabled: false },\n tools: { tool_search: { enabled: 'off' } },\n mcp_servers: { onboarder: { command: process.execPath, args: [paths.server],\n env: { ONBOARDER_AGENT_RUN: '${ONBOARDER_AGENT_RUN}', GITHUB_TOKEN: '${GITHUB_TOKEN}', GH_TOKEN: '${GH_TOKEN}' },\n tools: { prompts: false, resources: false }, connect_timeout: 30, timeout: 150 } },\n };\n let created = false;\n try { await fs.writeFile(file, JSON.stringify(config, null, 2) + '\\n', { mode: 0o600, flag: 'wx' }); created = true; }\n catch (error) { if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error; }\n return { ...paths, configFile: file, created };\n}\n\n/** Refresh only harness-owned settings; retain the model wizard's provider/auth choices. */\nexport async function prepareAgentProfile(home = agentHome(), env: NodeJS.ProcessEnv = process.env, signal?: AbortSignal) {\n const setup = await setupAgent(home, env);\n if (setup.created) return setup;\n const server = { command: process.execPath, args: [setup.server],\n env: { ONBOARDER_AGENT_RUN: '${ONBOARDER_AGENT_RUN}', GITHUB_TOKEN: '${GITHUB_TOKEN}', GH_TOKEN: '${GH_TOKEN}' },\n tools: { prompts: false, resources: false }, connect_timeout: 30, timeout: 150 };\n const source = await fs.readFile(setup.configFile, 'utf8');\n let config: Record<string, any> | null = null;\n try { const value = JSON.parse(source); if (value && typeof value === 'object' && !Array.isArray(value)) config = value; } catch { /* Hermes' model wizard writes native YAML. */ }\n if (config) {\n config.mcp_servers = { ...(config.mcp_servers || {}), onboarder: server };\n config.tools = { ...(config.tools || {}), tool_search: { ...(config.tools?.tool_search || {}), enabled: 'off' } };\n config.memory = { ...(config.memory || {}), memory_enabled: false, user_profile_enabled: false };\n const next = JSON.stringify(config, null, 2) + '\\n';\n if (source !== next) {\n const temporary = setup.configFile + '-' + randomUUID();\n try { await fs.writeFile(temporary, next, { flag: 'wx', mode: 0o600 }); await fs.rename(temporary, setup.configFile); }\n finally { await fs.rm(temporary, { force: true }); }\n }\n } else {\n // Let Hermes parse/preserve its own YAML rather than adding a Node dependency\n // or hand-editing the model wizard's configuration.\n for (const [key, value] of [['mcp_servers.onboarder', JSON.stringify(server)], ['tools.tool_search.enabled', 'off'], ['memory.memory_enabled', 'false'], ['memory.user_profile_enabled', 'false']]) {\n const result = await runProcess(hermesBinary(env), ['config', 'set', key, value], { env: hermesEnvironment(home, env), signal, timeoutMs: 30_000, maxBytes: 128000 });\n if (result.code) throw new Error(`Could not refresh the dedicated Hermes profile: ${result.stderr.slice(-1500) || result.stdout.slice(-1500)}`);\n }\n }\n return setup;\n}\n"]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export declare const AGENT_MODES: readonly ['ask', 'review', 'triage', 'implement', 'pr', 'github'];
|
|
2
|
+
export type AgentMode = typeof AGENT_MODES[number];
|
|
3
|
+
export interface AgentRequest {
|
|
4
|
+
mode: AgentMode;
|
|
5
|
+
root: string;
|
|
6
|
+
task: string;
|
|
7
|
+
pr?: number;
|
|
8
|
+
issue?: number;
|
|
9
|
+
maxTurns?: number;
|
|
10
|
+
timeoutSeconds?: number;
|
|
11
|
+
allowChecks?: boolean;
|
|
12
|
+
allowGithubWrites?: boolean;
|
|
13
|
+
dryRun?: boolean;
|
|
14
|
+
model?: string;
|
|
15
|
+
provider?: string;
|
|
16
|
+
resume?: string;
|
|
17
|
+
base?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface RunManifest {
|
|
20
|
+
schemaVersion: 1;
|
|
21
|
+
id: string;
|
|
22
|
+
mode: AgentMode;
|
|
23
|
+
sourceRoot: string;
|
|
24
|
+
root: string;
|
|
25
|
+
repository: string | null;
|
|
26
|
+
remote: string | null;
|
|
27
|
+
branch: string | null;
|
|
28
|
+
baseBranch: string | null;
|
|
29
|
+
task: string;
|
|
30
|
+
pr?: number;
|
|
31
|
+
issue?: number;
|
|
32
|
+
permissions: {
|
|
33
|
+
files: boolean;
|
|
34
|
+
checks: boolean;
|
|
35
|
+
github: boolean;
|
|
36
|
+
};
|
|
37
|
+
startedAt: string;
|
|
38
|
+
timeoutSeconds: number;
|
|
39
|
+
maxTurns: number;
|
|
40
|
+
auditFile: string;
|
|
41
|
+
}
|
|
42
|
+
export interface AgentEvent {
|
|
43
|
+
type: 'system' | 'text' | 'tool_use' | 'tool_result' | 'result';
|
|
44
|
+
subtype?: string;
|
|
45
|
+
name?: string;
|
|
46
|
+
text?: string;
|
|
47
|
+
session_id?: string;
|
|
48
|
+
exit_code?: number;
|
|
49
|
+
error?: string;
|
|
50
|
+
is_error?: boolean;
|
|
51
|
+
tokens?: Record<string, number>;
|
|
52
|
+
duration_ms?: number;
|
|
53
|
+
}
|
|
54
|
+
export interface AgentResult {
|
|
55
|
+
id: string;
|
|
56
|
+
status: 'completed' | 'failed' | 'cancelled';
|
|
57
|
+
mode: AgentMode;
|
|
58
|
+
answer: string;
|
|
59
|
+
sessionId: string | null;
|
|
60
|
+
workspace: string;
|
|
61
|
+
branch: string | null;
|
|
62
|
+
repository: string | null;
|
|
63
|
+
auditFile: string;
|
|
64
|
+
completedAt: string;
|
|
65
|
+
tokens?: Record<string, number>;
|
|
66
|
+
}
|
|
67
|
+
export interface AgentTool {
|
|
68
|
+
name: string;
|
|
69
|
+
description: string;
|
|
70
|
+
inputSchema: {
|
|
71
|
+
type: 'object';
|
|
72
|
+
properties: Record<string, unknown>;
|
|
73
|
+
required?: string[];
|
|
74
|
+
additionalProperties?: boolean;
|
|
75
|
+
};
|
|
76
|
+
run: (args: Record<string, unknown>) => Promise<unknown>;
|
|
77
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../src/cli/agent/contracts.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,CAAU,CAAC","sourcesContent":["export const AGENT_MODES = ['ask', 'review', 'triage', 'implement', 'pr', 'github'] as const;\nexport type AgentMode = typeof AGENT_MODES[number];\nexport interface AgentRequest {\n mode: AgentMode;\n root: string;\n task: string;\n pr?: number;\n issue?: number;\n maxTurns?: number;\n timeoutSeconds?: number;\n allowChecks?: boolean;\n allowGithubWrites?: boolean;\n dryRun?: boolean;\n model?: string;\n provider?: string;\n resume?: string;\n base?: string;\n}\nexport interface RunManifest {\n schemaVersion: 1;\n id: string;\n mode: AgentMode;\n sourceRoot: string;\n root: string;\n repository: string | null;\n remote: string | null;\n branch: string | null;\n baseBranch: string | null;\n task: string;\n pr?: number;\n issue?: number;\n permissions: { files: boolean; checks: boolean; github: boolean };\n startedAt: string;\n timeoutSeconds: number;\n maxTurns: number;\n auditFile: string;\n}\nexport interface AgentEvent {\n type: 'system' | 'text' | 'tool_use' | 'tool_result' | 'result';\n subtype?: string;\n name?: string;\n text?: string;\n session_id?: string;\n exit_code?: number;\n error?: string;\n is_error?: boolean;\n tokens?: Record<string, number>;\n duration_ms?: number;\n}\nexport interface AgentResult {\n id: string;\n status: 'completed' | 'failed' | 'cancelled';\n mode: AgentMode;\n answer: string;\n sessionId: string | null;\n workspace: string;\n branch: string | null;\n repository: string | null;\n auditFile: string;\n completedAt: string;\n tokens?: Record<string, number>;\n}\nexport interface AgentTool {\n name: string;\n description: string;\n inputSchema: { type: 'object'; properties: Record<string, unknown>; required?: string[]; additionalProperties?: boolean };\n run: (args: Record<string, unknown>) => Promise<unknown>;\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const FILE_LIMIT: number;
|
|
2
|
+
export declare const hashText: (text: string) => string;
|
|
3
|
+
export declare function safeRelative(file: string): string;
|
|
4
|
+
export declare function scopedFile(root: string, file: string, createParents?: boolean): Promise<string>;
|
|
5
|
+
export declare function readAgentFile(root: string, file: string): Promise<{
|
|
6
|
+
file: string;
|
|
7
|
+
content: string;
|
|
8
|
+
sha256: string;
|
|
9
|
+
lines: number;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function writeAgentFile(root: string, file: string, content: string, expected: string): Promise<{
|
|
12
|
+
file: string;
|
|
13
|
+
sha256: string;
|
|
14
|
+
bytes: number;
|
|
15
|
+
}>;
|
|
16
|
+
export declare function deleteAgentFile(root: string, file: string, expected: string): Promise<{
|
|
17
|
+
file: string;
|
|
18
|
+
deleted: boolean;
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { promises as fs, constants } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
4
|
+
export const FILE_LIMIT = 128 * 1024;
|
|
5
|
+
export const hashText = (text) => createHash('sha256').update(text).digest('hex');
|
|
6
|
+
export function safeRelative(file) {
|
|
7
|
+
if (!file || file.length > 500 || path.isAbsolute(file) || file.includes('\\') || /[\x00-\x1f]/.test(file))
|
|
8
|
+
throw new Error('Use a relative repository file path.');
|
|
9
|
+
const parts = file.split('/');
|
|
10
|
+
if (parts.some(p => !p || p === '..' || p === '.' || ['.git', 'node_modules', '.ssh', '.aws', '.npmrc', '.pypirc', '.netrc', '.git-credentials'].includes(p) || /^\.env(?:\.|$)/.test(p) || /^(?:id_rsa|id_ed25519)$|\.(?:pem|key)$/i.test(p)))
|
|
11
|
+
throw new Error('This path is outside the agent source-file scope.');
|
|
12
|
+
return file;
|
|
13
|
+
}
|
|
14
|
+
export async function scopedFile(root, file, createParents = false) {
|
|
15
|
+
safeRelative(file);
|
|
16
|
+
const canonical = await fs.realpath(root);
|
|
17
|
+
const parts = file.split('/');
|
|
18
|
+
let current = canonical;
|
|
19
|
+
for (let i = 0; i < parts.length; i++) {
|
|
20
|
+
current = path.join(current, parts[i]);
|
|
21
|
+
let stat;
|
|
22
|
+
try {
|
|
23
|
+
stat = await fs.lstat(current);
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
if (e.code !== 'ENOENT')
|
|
27
|
+
throw e;
|
|
28
|
+
if (createParents && i < parts.length - 1)
|
|
29
|
+
await fs.mkdir(current);
|
|
30
|
+
else if (i < parts.length - 1)
|
|
31
|
+
throw new Error('The parent directory does not exist.');
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (stat.isSymbolicLink())
|
|
35
|
+
throw new Error('Agent file tools do not follow symbolic links.');
|
|
36
|
+
if (i < parts.length - 1 && !stat.isDirectory())
|
|
37
|
+
throw new Error('The parent path is not a directory.');
|
|
38
|
+
if (i === parts.length - 1 && !stat.isFile())
|
|
39
|
+
throw new Error('The path is not a regular file.');
|
|
40
|
+
}
|
|
41
|
+
return current;
|
|
42
|
+
}
|
|
43
|
+
async function readBounded(file) {
|
|
44
|
+
const handle = await fs.open(file, constants.O_RDONLY | (constants.O_NOFOLLOW || 0));
|
|
45
|
+
try {
|
|
46
|
+
const stat = await handle.stat();
|
|
47
|
+
if (!stat.isFile() || stat.size > FILE_LIMIT)
|
|
48
|
+
throw new Error(`File must be text and at most ${FILE_LIMIT} bytes.`);
|
|
49
|
+
const buffer = Buffer.alloc(FILE_LIMIT + 1);
|
|
50
|
+
let bytesRead = 0;
|
|
51
|
+
while (bytesRead < buffer.length) {
|
|
52
|
+
const read = await handle.read(buffer, bytesRead, buffer.length - bytesRead, bytesRead);
|
|
53
|
+
if (!read.bytesRead)
|
|
54
|
+
break;
|
|
55
|
+
bytesRead += read.bytesRead;
|
|
56
|
+
}
|
|
57
|
+
if (bytesRead > FILE_LIMIT || buffer.subarray(0, bytesRead).includes(0))
|
|
58
|
+
throw new Error('File exceeds the text-file limit or contains binary data.');
|
|
59
|
+
return buffer.subarray(0, bytesRead).toString('utf8');
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
await handle.close();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export async function readAgentFile(root, file) {
|
|
66
|
+
const content = await readBounded(await scopedFile(root, file));
|
|
67
|
+
return { file, content, sha256: hashText(content), lines: content.split('\n').length };
|
|
68
|
+
}
|
|
69
|
+
export async function writeAgentFile(root, file, content, expected) {
|
|
70
|
+
if (Buffer.byteLength(content) > FILE_LIMIT || content.includes('\0'))
|
|
71
|
+
throw new Error('New content exceeds the text-file limit.');
|
|
72
|
+
const target = await scopedFile(root, file, true);
|
|
73
|
+
const check = async () => {
|
|
74
|
+
try {
|
|
75
|
+
const current = await readBounded(target);
|
|
76
|
+
if (expected === 'new' || hashText(current) !== expected)
|
|
77
|
+
throw new Error('The file changed. Read it again before writing.');
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
if (e.code === 'ENOENT' && expected === 'new')
|
|
81
|
+
return;
|
|
82
|
+
throw e;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
await check();
|
|
86
|
+
const mode = await fs.stat(target).then(s => s.mode & 0o777).catch(() => 0o644);
|
|
87
|
+
const temporary = path.join(path.dirname(target), `.onboarder-${randomUUID()}.tmp`);
|
|
88
|
+
try {
|
|
89
|
+
await fs.writeFile(temporary, content, { mode, flag: 'wx' });
|
|
90
|
+
await check();
|
|
91
|
+
if (expected === 'new')
|
|
92
|
+
await fs.link(temporary, target);
|
|
93
|
+
else
|
|
94
|
+
await fs.rename(temporary, target);
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
await fs.unlink(temporary).catch(() => { });
|
|
98
|
+
}
|
|
99
|
+
return { file, sha256: hashText(content), bytes: Buffer.byteLength(content) };
|
|
100
|
+
}
|
|
101
|
+
export async function deleteAgentFile(root, file, expected) {
|
|
102
|
+
const target = await scopedFile(root, file);
|
|
103
|
+
const current = await readBounded(target);
|
|
104
|
+
if (hashText(current) !== expected)
|
|
105
|
+
throw new Error('The file changed. Read it again before deleting.');
|
|
106
|
+
await fs.unlink(target);
|
|
107
|
+
return { file, deleted: true };
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/cli/agent/files.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs, constants } from 'node:fs';\nimport path from 'node:path';\nimport { createHash, randomUUID } from 'node:crypto';\n\nexport const FILE_LIMIT = 128 * 1024;\nexport const hashText = (text: string) => createHash('sha256').update(text).digest('hex');\nexport function safeRelative(file: string): string {\n if (!file || file.length > 500 || path.isAbsolute(file) || file.includes('\\\\') || /[\\x00-\\x1f]/.test(file)) throw new Error('Use a relative repository file path.');\n const parts = file.split('/');\n if (parts.some(p => !p || p === '..' || p === '.' || ['.git', 'node_modules', '.ssh', '.aws', '.npmrc', '.pypirc', '.netrc', '.git-credentials'].includes(p) || /^\\.env(?:\\.|$)/.test(p) || /^(?:id_rsa|id_ed25519)$|\\.(?:pem|key)$/i.test(p))) throw new Error('This path is outside the agent source-file scope.');\n return file;\n}\nexport async function scopedFile(root: string, file: string, createParents = false): Promise<string> {\n safeRelative(file);\n const canonical = await fs.realpath(root);\n const parts = file.split('/');\n let current = canonical;\n for (let i = 0; i < parts.length; i++) {\n current = path.join(current, parts[i]);\n let stat;\n try { stat = await fs.lstat(current); }\n catch (e) {\n if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e;\n if (createParents && i < parts.length - 1) await fs.mkdir(current);\n else if (i < parts.length - 1) throw new Error('The parent directory does not exist.');\n continue;\n }\n if (stat.isSymbolicLink()) throw new Error('Agent file tools do not follow symbolic links.');\n if (i < parts.length - 1 && !stat.isDirectory()) throw new Error('The parent path is not a directory.');\n if (i === parts.length - 1 && !stat.isFile()) throw new Error('The path is not a regular file.');\n }\n return current;\n}\nasync function readBounded(file: string): Promise<string> {\n const handle = await fs.open(file, constants.O_RDONLY | (constants.O_NOFOLLOW || 0));\n try {\n const stat = await handle.stat();\n if (!stat.isFile() || stat.size > FILE_LIMIT) throw new Error(`File must be text and at most ${FILE_LIMIT} bytes.`);\n const buffer = Buffer.alloc(FILE_LIMIT + 1);\n let bytesRead = 0;\n while (bytesRead < buffer.length) {\n const read = await handle.read(buffer, bytesRead, buffer.length - bytesRead, bytesRead);\n if (!read.bytesRead) break;\n bytesRead += read.bytesRead;\n }\n if (bytesRead > FILE_LIMIT || buffer.subarray(0, bytesRead).includes(0)) throw new Error('File exceeds the text-file limit or contains binary data.');\n return buffer.subarray(0, bytesRead).toString('utf8');\n } finally { await handle.close(); }\n}\nexport async function readAgentFile(root: string, file: string) {\n const content = await readBounded(await scopedFile(root, file));\n return { file, content, sha256: hashText(content), lines: content.split('\\n').length };\n}\nexport async function writeAgentFile(root: string, file: string, content: string, expected: string) {\n if (Buffer.byteLength(content) > FILE_LIMIT || content.includes('\\0')) throw new Error('New content exceeds the text-file limit.');\n const target = await scopedFile(root, file, true);\n const check = async () => {\n try {\n const current = await readBounded(target);\n if (expected === 'new' || hashText(current) !== expected) throw new Error('The file changed. Read it again before writing.');\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === 'ENOENT' && expected === 'new') return;\n throw e;\n }\n };\n await check();\n const mode = await fs.stat(target).then(s => s.mode & 0o777).catch(() => 0o644);\n const temporary = path.join(path.dirname(target), `.onboarder-${randomUUID()}.tmp`);\n try {\n await fs.writeFile(temporary, content, { mode, flag: 'wx' });\n await check();\n if (expected === 'new') await fs.link(temporary, target);\n else await fs.rename(temporary, target);\n } finally { await fs.unlink(temporary).catch(() => {}); }\n return { file, sha256: hashText(content), bytes: Buffer.byteLength(content) };\n}\nexport async function deleteAgentFile(root: string, file: string, expected: string) {\n const target = await scopedFile(root, file);\n const current = await readBounded(target);\n if (hashText(current) !== expected) throw new Error('The file changed. Read it again before deleting.');\n await fs.unlink(target);\n return { file, deleted: true };\n}\n"]}
|