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,116 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
5
|
+
import { agentHome } from '../agent/config.js';
|
|
6
|
+
import { repositoryFromRemote } from '../agent/github.js';
|
|
7
|
+
import { runProcess } from '../agent/process.js';
|
|
8
|
+
export function isRemoteSource(value) { return /^(?:https?:\/\/|ssh:\/\/|git@)/i.test(value); }
|
|
9
|
+
export function githubSource(value) {
|
|
10
|
+
const raw = value.trim(), repository = repositoryFromRemote(raw);
|
|
11
|
+
if (!repository)
|
|
12
|
+
throw new Error('Enter a GitHub repository URL: https://github.com/owner/repo or git@github.com:owner/repo.git.');
|
|
13
|
+
const url = `https://github.com/${repository}`;
|
|
14
|
+
const gitUrl = /^https:/i.test(raw) ? url + '.git' : `git@github.com:${repository}.git`;
|
|
15
|
+
return { repository, url, gitUrl };
|
|
16
|
+
}
|
|
17
|
+
/** Persistent checkouts keep conversations and agent worktrees usable after exit. */
|
|
18
|
+
export class ChatSources {
|
|
19
|
+
home;
|
|
20
|
+
options;
|
|
21
|
+
constructor(home = agentHome(), options = {}) {
|
|
22
|
+
this.home = home;
|
|
23
|
+
this.options = options;
|
|
24
|
+
}
|
|
25
|
+
get directory() { return path.join(this.home, 'repositories'); }
|
|
26
|
+
target(repository) {
|
|
27
|
+
const key = repository.toLowerCase();
|
|
28
|
+
return path.join(this.directory, key.split('/')[1].slice(0, 40) + '-' + createHash('sha256').update(key).digest('hex').slice(0, 16));
|
|
29
|
+
}
|
|
30
|
+
async git(args, signal, hooks) {
|
|
31
|
+
const env = this.options.env || process.env;
|
|
32
|
+
const result = await (this.options.execute || runProcess)('git', [
|
|
33
|
+
...(hooks ? ['-c', `core.hooksPath=${hooks}`] : []), '-c', 'submodule.recurse=false', ...args,
|
|
34
|
+
], { env: { ...env, GIT_TERMINAL_PROMPT: '0', GIT_SSH_COMMAND: env.GIT_SSH_COMMAND || 'ssh -oBatchMode=yes' }, signal, timeoutMs: 180000, maxBytes: 1024 * 1024 });
|
|
35
|
+
if (result.code !== 0)
|
|
36
|
+
throw new Error(`Could not open/update the repository. ${result.stderr.trim().slice(-1200) || 'Git exited with ' + result.code}. Private repositories require your existing Git credentials.`);
|
|
37
|
+
return result.stdout.trim();
|
|
38
|
+
}
|
|
39
|
+
async verify(target, repository, signal) {
|
|
40
|
+
const stat = await fs.lstat(target);
|
|
41
|
+
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
42
|
+
throw new Error('The saved repository path is not a regular directory.');
|
|
43
|
+
const root = await fs.realpath(target);
|
|
44
|
+
if (await fs.realpath(await this.git(['-C', root, 'rev-parse', '--show-toplevel'], signal)) !== root)
|
|
45
|
+
throw new Error('The saved checkout does not belong to this repository.');
|
|
46
|
+
const origin = await this.git(['-C', root, 'remote', 'get-url', 'origin'], signal);
|
|
47
|
+
if (repositoryFromRemote(origin)?.toLowerCase() !== repository.toLowerCase())
|
|
48
|
+
throw new Error('The saved checkout origin changed. Its files were preserved.');
|
|
49
|
+
return root;
|
|
50
|
+
}
|
|
51
|
+
async open(target, from = process.cwd(), signal, progress = () => { }) {
|
|
52
|
+
signal?.throwIfAborted();
|
|
53
|
+
if (!isRemoteSource(target)) {
|
|
54
|
+
const folder = target.replace(/^~(?=\/|$)/, os.homedir());
|
|
55
|
+
const root = await fs.realpath(path.resolve(from, folder));
|
|
56
|
+
if (!(await fs.stat(root)).isDirectory())
|
|
57
|
+
throw new Error('Choose a repository folder or GitHub URL.');
|
|
58
|
+
signal?.throwIfAborted();
|
|
59
|
+
return { root, reused: false };
|
|
60
|
+
}
|
|
61
|
+
const source = githubSource(target), destination = this.target(source.repository);
|
|
62
|
+
const existing = await fs.lstat(destination).then(() => true).catch(e => { if (e.code !== 'ENOENT')
|
|
63
|
+
throw e; return false; });
|
|
64
|
+
if (existing) {
|
|
65
|
+
const root = await this.verify(destination, source.repository, signal);
|
|
66
|
+
progress(`Using saved checkout of ${source.repository}. Use /pull to fetch the latest changes.`);
|
|
67
|
+
return { root, sourceUrl: source.url, reused: true };
|
|
68
|
+
}
|
|
69
|
+
await fs.mkdir(this.directory, { recursive: true, mode: 0o700 });
|
|
70
|
+
const staging = await fs.mkdtemp(path.join(this.directory, '.clone-'));
|
|
71
|
+
const hooks = path.join(staging, 'empty-hooks'), checkout = path.join(staging, 'checkout');
|
|
72
|
+
await fs.mkdir(hooks, { mode: 0o700 });
|
|
73
|
+
try {
|
|
74
|
+
progress(`Cloning ${source.repository}… Ctrl-C to stop.`);
|
|
75
|
+
await this.git(['clone', '--filter=blob:none', '--single-branch', '--', source.gitUrl, checkout], signal, hooks);
|
|
76
|
+
signal?.throwIfAborted();
|
|
77
|
+
await this.verify(checkout, source.repository, signal);
|
|
78
|
+
await fs.chmod(checkout, 0o700);
|
|
79
|
+
try {
|
|
80
|
+
await fs.rename(checkout, destination);
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
// Two chats may clone the same URL concurrently. Reuse the complete
|
|
84
|
+
// winner, preserving it rather than replacing its existing contents.
|
|
85
|
+
if (!['EEXIST', 'ENOTEMPTY'].includes(e.code || ''))
|
|
86
|
+
throw e;
|
|
87
|
+
}
|
|
88
|
+
const root = await this.verify(destination, source.repository, signal);
|
|
89
|
+
progress(`Ready: ${source.repository}\nSaved checkout: ${root}\nAsk a question, or use /map to explore.`);
|
|
90
|
+
return { root, sourceUrl: source.url, reused: false };
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
await fs.rm(staging, { recursive: true, force: true });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async pull(root, signal, progress = () => { }) {
|
|
97
|
+
const origin = await this.git(['-C', root, 'remote', 'get-url', 'origin'], signal);
|
|
98
|
+
const repository = repositoryFromRemote(origin);
|
|
99
|
+
if (!repository || await fs.realpath(this.target(repository)).catch(() => null) !== root)
|
|
100
|
+
throw new Error('/pull updates a saved GitHub checkout. Open one with /repo <GitHub URL> first.');
|
|
101
|
+
await this.verify(root, repository, signal);
|
|
102
|
+
if (await this.git(['-C', root, 'status', '--porcelain', '--untracked-files=all'], signal))
|
|
103
|
+
throw new Error('The checkout has local changes. Preserve or commit them before /pull.');
|
|
104
|
+
const hooks = path.join(this.directory, '.pull-hooks-' + randomUUID());
|
|
105
|
+
await fs.mkdir(hooks, { mode: 0o700 });
|
|
106
|
+
try {
|
|
107
|
+
progress(`Pulling latest changes for ${repository}…`);
|
|
108
|
+
const result = await this.git(['-C', root, 'pull', '--ff-only', '--no-rebase'], signal, hooks);
|
|
109
|
+
return result || 'Repository is up to date.';
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
await fs.rm(hooks, { recursive: true, force: true });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/cli/chat/source.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { createHash, randomUUID } from 'node:crypto';\nimport { agentHome } from '../agent/config.js';\nimport { repositoryFromRemote } from '../agent/github.js';\nimport { runProcess } from '../agent/process.js';\n\nexport interface ChatSource { root: string; sourceUrl?: string; reused: boolean }\ninterface SourceOptions { env?: NodeJS.ProcessEnv; execute?: typeof runProcess }\nexport function isRemoteSource(value: string): boolean { return /^(?:https?:\\/\\/|ssh:\\/\\/|git@)/i.test(value); }\nexport function githubSource(value: string): { repository: string; url: string; gitUrl: string } {\n const raw = value.trim(), repository = repositoryFromRemote(raw);\n if (!repository) throw new Error('Enter a GitHub repository URL: https://github.com/owner/repo or git@github.com:owner/repo.git.');\n const url = `https://github.com/${repository}`;\n const gitUrl = /^https:/i.test(raw) ? url + '.git' : `git@github.com:${repository}.git`;\n return { repository, url, gitUrl };\n}\n\n/** Persistent checkouts keep conversations and agent worktrees usable after exit. */\nexport class ChatSources {\n constructor(readonly home = agentHome(), private options: SourceOptions = {}) {}\n get directory() { return path.join(this.home, 'repositories'); }\n private target(repository: string) {\n const key = repository.toLowerCase();\n return path.join(this.directory, key.split('/')[1]!.slice(0, 40) + '-' + createHash('sha256').update(key).digest('hex').slice(0, 16));\n }\n private async git(args: string[], signal?: AbortSignal, hooks?: string) {\n const env = this.options.env || process.env;\n const result = await (this.options.execute || runProcess)('git', [\n ...(hooks ? ['-c', `core.hooksPath=${hooks}`] : []), '-c', 'submodule.recurse=false', ...args,\n ], { env: { ...env, GIT_TERMINAL_PROMPT: '0', GIT_SSH_COMMAND: env.GIT_SSH_COMMAND || 'ssh -oBatchMode=yes' }, signal, timeoutMs: 180000, maxBytes: 1024 * 1024 });\n if (result.code !== 0) throw new Error(`Could not open/update the repository. ${result.stderr.trim().slice(-1200) || 'Git exited with ' + result.code}. Private repositories require your existing Git credentials.`);\n return result.stdout.trim();\n }\n private async verify(target: string, repository: string, signal?: AbortSignal) {\n const stat = await fs.lstat(target);\n if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error('The saved repository path is not a regular directory.');\n const root = await fs.realpath(target);\n if (await fs.realpath(await this.git(['-C', root, 'rev-parse', '--show-toplevel'], signal)) !== root) throw new Error('The saved checkout does not belong to this repository.');\n const origin = await this.git(['-C', root, 'remote', 'get-url', 'origin'], signal);\n if (repositoryFromRemote(origin)?.toLowerCase() !== repository.toLowerCase()) throw new Error('The saved checkout origin changed. Its files were preserved.');\n return root;\n }\n async open(target: string, from = process.cwd(), signal?: AbortSignal, progress: (text: string) => void = () => {}): Promise<ChatSource> {\n signal?.throwIfAborted();\n if (!isRemoteSource(target)) {\n const folder = target.replace(/^~(?=\\/|$)/, os.homedir());\n const root = await fs.realpath(path.resolve(from, folder));\n if (!(await fs.stat(root)).isDirectory()) throw new Error('Choose a repository folder or GitHub URL.');\n signal?.throwIfAborted();\n return { root, reused: false };\n }\n const source = githubSource(target), destination = this.target(source.repository);\n const existing = await fs.lstat(destination).then(() => true).catch(e => { if (e.code !== 'ENOENT') throw e; return false; });\n if (existing) {\n const root = await this.verify(destination, source.repository, signal);\n progress(`Using saved checkout of ${source.repository}. Use /pull to fetch the latest changes.`);\n return { root, sourceUrl: source.url, reused: true };\n }\n await fs.mkdir(this.directory, { recursive: true, mode: 0o700 });\n const staging = await fs.mkdtemp(path.join(this.directory, '.clone-'));\n const hooks = path.join(staging, 'empty-hooks'), checkout = path.join(staging, 'checkout');\n await fs.mkdir(hooks, { mode: 0o700 });\n try {\n progress(`Cloning ${source.repository}… Ctrl-C to stop.`);\n await this.git(['clone', '--filter=blob:none', '--single-branch', '--', source.gitUrl, checkout], signal, hooks);\n signal?.throwIfAborted();\n await this.verify(checkout, source.repository, signal);\n await fs.chmod(checkout, 0o700);\n try { await fs.rename(checkout, destination); }\n catch (e) {\n // Two chats may clone the same URL concurrently. Reuse the complete\n // winner, preserving it rather than replacing its existing contents.\n if (!['EEXIST', 'ENOTEMPTY'].includes((e as NodeJS.ErrnoException).code || '')) throw e;\n }\n const root = await this.verify(destination, source.repository, signal);\n progress(`Ready: ${source.repository}\\nSaved checkout: ${root}\\nAsk a question, or use /map to explore.`);\n return { root, sourceUrl: source.url, reused: false };\n } finally { await fs.rm(staging, { recursive: true, force: true }); }\n }\n async pull(root: string, signal?: AbortSignal, progress: (text: string) => void = () => {}) {\n const origin = await this.git(['-C', root, 'remote', 'get-url', 'origin'], signal);\n const repository = repositoryFromRemote(origin);\n if (!repository || await fs.realpath(this.target(repository)).catch(() => null) !== root) throw new Error('/pull updates a saved GitHub checkout. Open one with /repo <GitHub URL> first.');\n await this.verify(root, repository, signal);\n if (await this.git(['-C', root, 'status', '--porcelain', '--untracked-files=all'], signal)) throw new Error('The checkout has local changes. Preserve or commit them before /pull.');\n const hooks = path.join(this.directory, '.pull-hooks-' + randomUUID());\n await fs.mkdir(hooks, { mode: 0o700 });\n try {\n progress(`Pulling latest changes for ${repository}…`);\n const result = await this.git(['-C', root, 'pull', '--ff-only', '--no-rebase'], signal, hooks);\n return result || 'Repository is up to date.';\n } finally { await fs.rm(hooks, { recursive: true, force: true }); }\n }\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type AgentMode, type AgentResult } from '../agent/contracts.js';
|
|
2
|
+
export interface ChatSettings {
|
|
3
|
+
root: string;
|
|
4
|
+
sourceUrl?: string;
|
|
5
|
+
mode: AgentMode;
|
|
6
|
+
model?: string;
|
|
7
|
+
provider?: string;
|
|
8
|
+
checks: boolean;
|
|
9
|
+
github: boolean;
|
|
10
|
+
timeout: number;
|
|
11
|
+
maxTurns: number;
|
|
12
|
+
pr?: number;
|
|
13
|
+
issue?: number;
|
|
14
|
+
base?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ChatTurn {
|
|
17
|
+
at: string;
|
|
18
|
+
prompt: string;
|
|
19
|
+
answer: string;
|
|
20
|
+
run: string;
|
|
21
|
+
status: AgentResult['status'];
|
|
22
|
+
}
|
|
23
|
+
export interface ChatRecord {
|
|
24
|
+
schemaVersion: 1;
|
|
25
|
+
id: string;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
updatedAt: string;
|
|
28
|
+
settings: ChatSettings;
|
|
29
|
+
lastRun: string | null;
|
|
30
|
+
turns: ChatTurn[];
|
|
31
|
+
}
|
|
32
|
+
export declare function newChat(settings: ChatSettings): ChatRecord;
|
|
33
|
+
export declare class ChatStore {
|
|
34
|
+
readonly home: string;
|
|
35
|
+
private env;
|
|
36
|
+
constructor(home?: string, env?: NodeJS.ProcessEnv);
|
|
37
|
+
get directory(): string;
|
|
38
|
+
save(record: ChatRecord): Promise<void>;
|
|
39
|
+
load(id: string): Promise<ChatRecord>;
|
|
40
|
+
list(root: string): Promise<ChatRecord[]>;
|
|
41
|
+
export(record: ChatRecord): Promise<string>;
|
|
42
|
+
}
|
|
43
|
+
export declare function historySummary(records: ChatRecord[]): string;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { AGENT_MODES } from '../agent/contracts.js';
|
|
5
|
+
import { agentHome } from '../agent/config.js';
|
|
6
|
+
import { runId } from '../agent/runner.js';
|
|
7
|
+
import { redact, terminalText } from '../agent/process.js';
|
|
8
|
+
import { repositoryFromRemote } from '../agent/github.js';
|
|
9
|
+
export function newChat(settings) {
|
|
10
|
+
const now = new Date().toISOString();
|
|
11
|
+
return { schemaVersion: 1, id: randomUUID(), createdAt: now, updatedAt: now, settings: { ...settings }, lastRun: null, turns: [] };
|
|
12
|
+
}
|
|
13
|
+
function validSettings(s) {
|
|
14
|
+
return !!s && typeof s.root === 'string' && path.isAbsolute(s.root) && AGENT_MODES.includes(s.mode) &&
|
|
15
|
+
typeof s.checks === 'boolean' && typeof s.github === 'boolean' && Number.isInteger(s.timeout) && s.timeout >= 15 && s.timeout <= 3600 &&
|
|
16
|
+
Number.isInteger(s.maxTurns) && s.maxTurns >= 1 && s.maxTurns <= 100 &&
|
|
17
|
+
[s.model, s.provider, s.base].every(v => v === undefined || typeof v === 'string' && v.length <= 512) &&
|
|
18
|
+
[s.pr, s.issue].every(v => v === undefined || Number.isSafeInteger(v) && v > 0) &&
|
|
19
|
+
(s.sourceUrl === undefined || typeof s.sourceUrl === 'string' && repositoryFromRemote(s.sourceUrl) !== null);
|
|
20
|
+
}
|
|
21
|
+
export class ChatStore {
|
|
22
|
+
home;
|
|
23
|
+
env;
|
|
24
|
+
constructor(home = agentHome(), env = process.env) {
|
|
25
|
+
this.home = home;
|
|
26
|
+
this.env = env;
|
|
27
|
+
}
|
|
28
|
+
get directory() { return path.join(this.home, 'chats'); }
|
|
29
|
+
async save(record) {
|
|
30
|
+
await fs.mkdir(this.directory, { recursive: true, mode: 0o700 });
|
|
31
|
+
const target = path.join(this.directory, runId(record.id) + '.json'), temp = target + '.' + randomUUID() + '.tmp';
|
|
32
|
+
const safe = { ...record, turns: record.turns.slice(-100).map(t => ({ ...t, prompt: redact(t.prompt, this.env), answer: redact(t.answer, this.env).slice(0, 32000) })) };
|
|
33
|
+
let encoded = JSON.stringify(safe, null, 2) + '\n';
|
|
34
|
+
// UTF-8 transcripts can use several bytes per character. Bound the stored
|
|
35
|
+
// bytes, rather than producing a conversation our own loader cannot read.
|
|
36
|
+
while (Buffer.byteLength(encoded) > 5 * 1024 * 1024 && safe.turns.length > 1) {
|
|
37
|
+
safe.turns.shift();
|
|
38
|
+
encoded = JSON.stringify(safe, null, 2) + '\n';
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
await fs.writeFile(temp, encoded, { mode: 0o600, flag: 'wx' });
|
|
42
|
+
await fs.rename(temp, target);
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
await fs.rm(temp, { force: true });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async load(id) {
|
|
49
|
+
const file = path.join(this.directory, runId(id) + '.json');
|
|
50
|
+
if ((await fs.stat(file)).size > 6 * 1024 * 1024)
|
|
51
|
+
throw new Error('The saved conversation exceeds the size limit.');
|
|
52
|
+
const record = JSON.parse(await fs.readFile(file, 'utf8'));
|
|
53
|
+
if (record.schemaVersion !== 1 || record.id !== id || !validSettings(record.settings) ||
|
|
54
|
+
typeof record.createdAt !== 'string' || typeof record.updatedAt !== 'string' || !Array.isArray(record.turns) || record.turns.length > 100 ||
|
|
55
|
+
!(record.lastRun === null || typeof record.lastRun === 'string') || record.turns.some(t => !t || typeof t.at !== 'string' ||
|
|
56
|
+
typeof t.prompt !== 'string' || t.prompt.length > 16000 || typeof t.answer !== 'string' || t.answer.length > 32000 ||
|
|
57
|
+
typeof t.run !== 'string' || !['completed', 'failed', 'cancelled'].includes(t.status)))
|
|
58
|
+
throw new Error('The saved conversation is invalid.');
|
|
59
|
+
if (record.lastRun)
|
|
60
|
+
runId(record.lastRun);
|
|
61
|
+
for (const turn of record.turns)
|
|
62
|
+
runId(turn.run);
|
|
63
|
+
return record;
|
|
64
|
+
}
|
|
65
|
+
async list(root) {
|
|
66
|
+
const entries = await fs.readdir(this.directory, { withFileTypes: true }).catch(e => { if (e.code !== 'ENOENT')
|
|
67
|
+
throw e; return []; });
|
|
68
|
+
const records = [];
|
|
69
|
+
for (const entry of entries) {
|
|
70
|
+
if (!entry.isFile() || !/^[a-f\d-]{36}\.json$/i.test(entry.name))
|
|
71
|
+
continue;
|
|
72
|
+
try {
|
|
73
|
+
const record = await this.load(entry.name.slice(0, -5));
|
|
74
|
+
if (record.settings.root === root)
|
|
75
|
+
records.push(record);
|
|
76
|
+
}
|
|
77
|
+
catch { /* A damaged entry must not hide the others. */ }
|
|
78
|
+
}
|
|
79
|
+
return records.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)).slice(0, 30);
|
|
80
|
+
}
|
|
81
|
+
async export(record) {
|
|
82
|
+
const directory = path.join(this.home, 'exports');
|
|
83
|
+
await fs.mkdir(directory, { recursive: true, mode: 0o700 });
|
|
84
|
+
const file = path.join(directory, record.id + '-' + randomUUID().slice(0, 8) + '.md');
|
|
85
|
+
const text = ['# Onboarder conversation', '', `Repository: ${record.settings.sourceUrl || record.settings.root}`, `Conversation: ${record.id}`, '',
|
|
86
|
+
...record.turns.flatMap(turn => ['## You', '', turn.prompt, '', `## Hermes (${turn.status})`, '', turn.answer, '', `Run: ${turn.run}`, ''])].join('\n');
|
|
87
|
+
await fs.writeFile(file, redact(text, this.env), { flag: 'wx', mode: 0o600 });
|
|
88
|
+
return file;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function historySummary(records) {
|
|
92
|
+
return records.length ? records.map(r => `${r.id} ${r.settings.mode} ${r.turns.length} turns\n ${r.updatedAt} ${terminalText(r.turns[0]?.prompt || 'Empty conversation').replace(/\s+/g, ' ').slice(0, 100)}`).join('\n\n') : 'No saved conversations for this repository yet.';
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/cli/chat/store.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 { AGENT_MODES, type AgentMode, type AgentResult } from '../agent/contracts.js';\nimport { agentHome } from '../agent/config.js';\nimport { runId } from '../agent/runner.js';\nimport { redact, terminalText } from '../agent/process.js';\nimport { repositoryFromRemote } from '../agent/github.js';\n\nexport interface ChatSettings {\n root: string; sourceUrl?: string; mode: AgentMode; model?: string; provider?: string;\n checks: boolean; github: boolean; timeout: number; maxTurns: number; pr?: number; issue?: number; base?: string;\n}\nexport interface ChatTurn { at: string; prompt: string; answer: string; run: string; status: AgentResult['status'] }\nexport interface ChatRecord {\n schemaVersion: 1; id: string; createdAt: string; updatedAt: string;\n settings: ChatSettings; lastRun: string | null; turns: ChatTurn[];\n}\nexport function newChat(settings: ChatSettings): ChatRecord {\n const now = new Date().toISOString();\n return { schemaVersion: 1, id: randomUUID(), createdAt: now, updatedAt: now, settings: { ...settings }, lastRun: null, turns: [] };\n}\nfunction validSettings(s: ChatSettings): boolean {\n return !!s && typeof s.root === 'string' && path.isAbsolute(s.root) && AGENT_MODES.includes(s.mode) &&\n typeof s.checks === 'boolean' && typeof s.github === 'boolean' && Number.isInteger(s.timeout) && s.timeout >= 15 && s.timeout <= 3600 &&\n Number.isInteger(s.maxTurns) && s.maxTurns >= 1 && s.maxTurns <= 100 &&\n [s.model, s.provider, s.base].every(v => v === undefined || typeof v === 'string' && v.length <= 512) &&\n [s.pr, s.issue].every(v => v === undefined || Number.isSafeInteger(v) && v > 0) &&\n (s.sourceUrl === undefined || typeof s.sourceUrl === 'string' && repositoryFromRemote(s.sourceUrl) !== null);\n}\nexport class ChatStore {\n constructor(readonly home = agentHome(), private env: NodeJS.ProcessEnv = process.env) {}\n get directory() { return path.join(this.home, 'chats'); }\n async save(record: ChatRecord) {\n await fs.mkdir(this.directory, { recursive: true, mode: 0o700 });\n const target = path.join(this.directory, runId(record.id) + '.json'), temp = target + '.' + randomUUID() + '.tmp';\n const safe = { ...record, turns: record.turns.slice(-100).map(t => ({ ...t, prompt: redact(t.prompt, this.env), answer: redact(t.answer, this.env).slice(0, 32000) })) };\n let encoded = JSON.stringify(safe, null, 2) + '\\n';\n // UTF-8 transcripts can use several bytes per character. Bound the stored\n // bytes, rather than producing a conversation our own loader cannot read.\n while (Buffer.byteLength(encoded) > 5 * 1024 * 1024 && safe.turns.length > 1) {\n safe.turns.shift(); encoded = JSON.stringify(safe, null, 2) + '\\n';\n }\n try { await fs.writeFile(temp, encoded, { mode: 0o600, flag: 'wx' }); await fs.rename(temp, target); }\n finally { await fs.rm(temp, { force: true }); }\n }\n async load(id: string): Promise<ChatRecord> {\n const file = path.join(this.directory, runId(id) + '.json');\n if ((await fs.stat(file)).size > 6 * 1024 * 1024) throw new Error('The saved conversation exceeds the size limit.');\n const record = JSON.parse(await fs.readFile(file, 'utf8')) as ChatRecord;\n if (record.schemaVersion !== 1 || record.id !== id || !validSettings(record.settings) ||\n typeof record.createdAt !== 'string' || typeof record.updatedAt !== 'string' || !Array.isArray(record.turns) || record.turns.length > 100 ||\n !(record.lastRun === null || typeof record.lastRun === 'string') || record.turns.some(t => !t || typeof t.at !== 'string' ||\n typeof t.prompt !== 'string' || t.prompt.length > 16000 || typeof t.answer !== 'string' || t.answer.length > 32000 ||\n typeof t.run !== 'string' || !['completed', 'failed', 'cancelled'].includes(t.status))) throw new Error('The saved conversation is invalid.');\n if (record.lastRun) runId(record.lastRun);\n for (const turn of record.turns) runId(turn.run);\n return record;\n }\n async list(root: string): Promise<ChatRecord[]> {\n const entries = await fs.readdir(this.directory, { withFileTypes: true }).catch(e => { if (e.code !== 'ENOENT') throw e; return []; });\n const records: ChatRecord[] = [];\n for (const entry of entries) {\n if (!entry.isFile() || !/^[a-f\\d-]{36}\\.json$/i.test(entry.name)) continue;\n try { const record = await this.load(entry.name.slice(0, -5)); if (record.settings.root === root) records.push(record); } catch { /* A damaged entry must not hide the others. */ }\n }\n return records.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)).slice(0, 30);\n }\n async export(record: ChatRecord): Promise<string> {\n const directory = path.join(this.home, 'exports'); await fs.mkdir(directory, { recursive: true, mode: 0o700 });\n const file = path.join(directory, record.id + '-' + randomUUID().slice(0, 8) + '.md');\n const text = ['# Onboarder conversation', '', `Repository: ${record.settings.sourceUrl || record.settings.root}`, `Conversation: ${record.id}`, '',\n ...record.turns.flatMap(turn => ['## You', '', turn.prompt, '', `## Hermes (${turn.status})`, '', turn.answer, '', `Run: ${turn.run}`, ''])].join('\\n');\n await fs.writeFile(file, redact(text, this.env), { flag: 'wx', mode: 0o600 }); return file;\n }\n}\nexport function historySummary(records: ChatRecord[]): string {\n return records.length ? records.map(r => `${r.id} ${r.settings.mode} ${r.turns.length} turns\\n ${r.updatedAt} ${terminalText(r.turns[0]?.prompt || 'Empty conversation').replace(/\\s+/g, ' ').slice(0, 100)}`).join('\\n\\n') : 'No saved conversations for this repository yet.';\n}\n"]}
|
package/cli/chat/text.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { terminalText } from '../agent/process.js';
|
|
2
|
+
const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
|
|
3
|
+
export function graphemes(value) { return [...segmenter.segment(value)].map(s => s.segment); }
|
|
4
|
+
export function clusterCells(cluster) {
|
|
5
|
+
if (/^[\p{Mark}\u200d\ufe0f]+$/u.test(cluster))
|
|
6
|
+
return 0;
|
|
7
|
+
return /\p{Extended_Pictographic}|[\u1100-\u115f\u2329\u232a\u2e80-\ua4cf\uac00-\ud7a3\uf900-\ufaff\ufe10-\ufe19\ufe30-\ufe6f\uff01-\uff60\uffe0-\uffe6\u{1f1e6}-\u{1f1ff}]/u.test(cluster) ? 2 : 1;
|
|
8
|
+
}
|
|
9
|
+
export function cells(value) {
|
|
10
|
+
return graphemes(terminalText(value)).reduce((total, cluster) => total + clusterCells(cluster), 0);
|
|
11
|
+
}
|
|
12
|
+
export function clip(value, room, ellipsis = true) {
|
|
13
|
+
const safe = terminalText(value).replace(/[\r\n\t]/g, ' ');
|
|
14
|
+
if (cells(safe) <= room)
|
|
15
|
+
return safe;
|
|
16
|
+
const limit = Math.max(0, room - (ellipsis && room > 0 ? 1 : 0));
|
|
17
|
+
let result = '', used = 0;
|
|
18
|
+
for (const g of graphemes(safe)) {
|
|
19
|
+
const size = clusterCells(g);
|
|
20
|
+
if (used + size > limit)
|
|
21
|
+
break;
|
|
22
|
+
result += g;
|
|
23
|
+
used += size;
|
|
24
|
+
}
|
|
25
|
+
return result + (ellipsis && room > 0 ? '…' : '');
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/cli/chat/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;AAC7E,MAAM,UAAU,SAAS,CAAC,KAAa,IAAc,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,IAAI,4BAA4B,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,CAAC,CAAC;IACzD,OAAO,sKAAsK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtM,CAAC;AACD,MAAM,UAAU,KAAK,CAAC,KAAa;IACjC,OAAO,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACrG,CAAC;AACD,MAAM,UAAU,IAAI,CAAC,KAAa,EAAE,IAAY,EAAE,QAAQ,GAAG,IAAI;IAC/D,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IAC3D,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,QAAQ,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,IAAI,MAAM,GAAG,EAAE,EAAE,IAAI,GAAG,CAAC,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QAAC,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAAC,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;YAAE,MAAM;QAAC,MAAM,IAAI,CAAC,CAAC;QAAC,IAAI,IAAI,IAAI,CAAC;IAAC,CAAC;IAC7H,OAAO,MAAM,GAAG,CAAC,QAAQ,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACpD,CAAC","sourcesContent":["import { terminalText } from '../agent/process.js';\n\nconst segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });\nexport function graphemes(value: string): string[] { return [...segmenter.segment(value)].map(s => s.segment); }\nexport function clusterCells(cluster: string): number {\n if (/^[\\p{Mark}\\u200d\\ufe0f]+$/u.test(cluster)) return 0;\n return /\\p{Extended_Pictographic}|[\\u1100-\\u115f\\u2329\\u232a\\u2e80-\\ua4cf\\uac00-\\ud7a3\\uf900-\\ufaff\\ufe10-\\ufe19\\ufe30-\\ufe6f\\uff01-\\uff60\\uffe0-\\uffe6\\u{1f1e6}-\\u{1f1ff}]/u.test(cluster) ? 2 : 1;\n}\nexport function cells(value: string): number {\n return graphemes(terminalText(value)).reduce((total, cluster) => total + clusterCells(cluster), 0);\n}\nexport function clip(value: string, room: number, ellipsis = true): string {\n const safe = terminalText(value).replace(/[\\r\\n\\t]/g, ' ');\n if (cells(safe) <= room) return safe;\n const limit = Math.max(0, room - (ellipsis && room > 0 ? 1 : 0));\n let result = '', used = 0;\n for (const g of graphemes(safe)) { const size = clusterCells(g); if (used + size > limit) break; result += g; used += size; }\n return result + (ellipsis && room > 0 ? '…' : '');\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare function runSetup({ flags, out, err, version }?: Record<string, any>): any;
|
|
2
|
+
export declare function serverDetails(started: any, { configFile, pid, mode, logFile }?: Record<string, any>): {
|
|
3
|
+
rows: {
|
|
4
|
+
label: string;
|
|
5
|
+
value: string;
|
|
6
|
+
}[];
|
|
7
|
+
urls: import("../shared/contracts.js").ServerUrls;
|
|
8
|
+
mode: any;
|
|
9
|
+
};
|
|
10
|
+
export declare function watchResize(render: any, stream?: NodeJS.WriteStream & {
|
|
11
|
+
fd: 1;
|
|
12
|
+
}): (..._args: unknown[]) => void;
|
|
13
|
+
export declare function runStart({ flags, out, err }?: Record<string, any>): any;
|
|
14
|
+
export declare function runStartBackground({ flags, out, err }?: Record<string, any>): any;
|
|
15
|
+
export declare function runStatus({ flags, out }?: Record<string, any>): Promise<number>;
|
|
16
|
+
export declare function humanDuration(ms: any): string;
|
|
17
|
+
export declare function runStop({ flags, out, err }?: Record<string, any>): Promise<0 | 1>;
|
|
18
|
+
export declare function runRestart(options?: Record<string, any>): Promise<any>;
|
|
19
|
+
export declare function runLogs({ flags, out, err }?: Record<string, any>): Promise<0 | 1 | 2>;
|
|
20
|
+
export declare function runStartup(action?: string, { flags, out, err }?: Record<string, any>): Promise<0 | 1>;
|
|
21
|
+
export declare function runConfig(sub: any, args: any, { flags, out }?: Record<string, any>): Promise<number>;
|
|
22
|
+
export declare function runConfigKey(action: any, args: any, { flags, out, err }?: Record<string, any>): Promise<number>;
|
|
23
|
+
export declare function runConfigReset({ flags, out, err }?: Record<string, any>): Promise<0 | 1>;
|
|
24
|
+
export declare function runDoctor({ flags, out }?: Record<string, any>): Promise<0 | 1>;
|
|
25
|
+
export declare function runHttps(action?: string, { flags, out, err }?: Record<string, any>): Promise<0 | 1>;
|
|
26
|
+
export declare function runTunnel(kind: any, { flags, out, err }?: Record<string, any>): Promise<unknown>;
|