codebase-onboarder 0.7.0 → 1.0.1
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 +140 -12
- package/bin/onboarder.js +0 -0
- package/cli/agent/command.d.ts +71 -0
- package/cli/agent/command.js +177 -0
- package/cli/agent/command.js.map +1 -0
- package/cli/agent/config.d.ts +31 -0
- package/cli/agent/config.js +98 -0
- package/cli/agent/config.js.map +1 -0
- package/cli/agent/contracts.d.ts +77 -0
- package/cli/agent/contracts.js +2 -0
- package/cli/agent/contracts.js.map +1 -0
- package/cli/agent/files.d.ts +19 -0
- package/cli/agent/files.js +109 -0
- package/cli/agent/files.js.map +1 -0
- package/cli/agent/gitSource.d.ts +18 -0
- package/cli/agent/gitSource.js +69 -0
- package/cli/agent/gitSource.js.map +1 -0
- package/cli/agent/github.d.ts +21 -0
- package/cli/agent/github.js +94 -0
- package/cli/agent/github.js.map +1 -0
- package/cli/agent/mcp.d.ts +15 -0
- package/cli/agent/mcp.js +78 -0
- package/cli/agent/mcp.js.map +1 -0
- package/cli/agent/process.d.ts +18 -0
- package/cli/agent/process.js +118 -0
- package/cli/agent/process.js.map +1 -0
- package/cli/agent/protocol.d.ts +3 -0
- package/cli/agent/protocol.js +26 -0
- package/cli/agent/protocol.js.map +1 -0
- package/cli/agent/runner.d.ts +34 -0
- package/cli/agent/runner.js +152 -0
- package/cli/agent/runner.js.map +1 -0
- package/cli/agent/stdio.d.ts +1 -0
- package/cli/agent/stdio.js +62 -0
- package/cli/agent/stdio.js.map +1 -0
- package/cli/agent/tools.d.ts +7 -0
- package/cli/agent/tools.js +225 -0
- package/cli/agent/tools.js.map +1 -0
- package/cli/chat/analysis.d.ts +26 -0
- package/cli/chat/analysis.js +188 -0
- package/cli/chat/analysis.js.map +1 -0
- package/cli/chat/app.d.ts +16 -0
- package/cli/chat/app.js +363 -0
- package/cli/chat/app.js.map +1 -0
- package/cli/chat/commands.d.ts +11 -0
- package/cli/chat/commands.js +122 -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 +64 -0
- package/cli/chat/controller.js +402 -0
- package/cli/chat/controller.js.map +1 -0
- package/cli/chat/logo.d.ts +3 -0
- package/cli/chat/logo.js +14 -0
- package/cli/chat/logo.js.map +1 -0
- package/cli/chat/models.d.ts +18 -0
- package/cli/chat/models.js +88 -0
- package/cli/chat/models.js.map +1 -0
- package/cli/chat/profile.d.ts +5 -0
- package/cli/chat/profile.js +98 -0
- package/cli/chat/profile.js.map +1 -0
- package/cli/chat/render.d.ts +40 -0
- package/cli/chat/render.js +259 -0
- package/cli/chat/render.js.map +1 -0
- package/cli/chat/screen.d.ts +26 -0
- package/cli/chat/screen.js +117 -0
- package/cli/chat/screen.js.map +1 -0
- package/cli/chat/source.d.ts +29 -0
- package/cli/chat/source.js +116 -0
- package/cli/chat/source.js.map +1 -0
- package/cli/chat/store.d.ts +43 -0
- package/cli/chat/store.js +94 -0
- package/cli/chat/store.js.map +1 -0
- package/cli/chat/text.d.ts +4 -0
- package/cli/chat/text.js +27 -0
- package/cli/chat/text.js.map +1 -0
- package/cli/explorer/app.d.ts +1 -0
- package/cli/explorer/app.js +20 -1
- package/cli/explorer/app.js.map +1 -1
- package/cli/explorer/commands.js +5 -0
- package/cli/explorer/commands.js.map +1 -1
- package/cli/explorer/featureViews.d.ts +1 -0
- package/cli/explorer/featureViews.js +4 -0
- package/cli/explorer/featureViews.js.map +1 -1
- package/cli/main.js +47 -13
- package/cli/main.js.map +1 -1
- package/docs/HERMES_RESEARCH.md +51 -0
- package/package.json +2 -1
- package/public/app.js +98 -24
- package/public/app.js.map +1 -1
- package/public/assets/onboarder-mark.svg +11 -0
- package/public/browser.d.ts +3 -0
- package/public/browser.js.map +1 -1
- package/public/index.html +24 -7
- package/public/js/about.js +2 -2
- package/public/js/about.js.map +1 -1
- package/public/js/aiDraft.d.ts +1 -0
- package/public/js/aiDraft.js +66 -17
- package/public/js/aiDraft.js.map +1 -1
- package/public/js/api.d.ts +8 -5
- package/public/js/api.js +45 -22
- package/public/js/api.js.map +1 -1
- package/public/js/deepAnalysisView.js +2 -2
- package/public/js/deepAnalysisView.js.map +1 -1
- package/public/js/diagramPane.d.ts +1 -0
- package/public/js/diagramPane.js +5 -0
- package/public/js/diagramPane.js.map +1 -1
- package/public/js/docsView.js +6 -6
- package/public/js/docsView.js.map +1 -1
- package/public/js/dom.d.ts +8 -0
- package/public/js/dom.js.map +1 -1
- package/public/js/llm.d.ts +3 -1
- package/public/js/llm.js +15 -8
- package/public/js/llm.js.map +1 -1
- package/public/js/repoFiles.js +1 -1
- package/public/js/repoFiles.js.map +1 -1
- package/public/js/reviewView.js +1 -1
- package/public/js/reviewView.js.map +1 -1
- package/public/styles.css +25 -0
- package/server/gitDiff.d.ts +1 -1
- package/server/hermesChat.d.ts +13 -0
- package/server/hermesChat.js +145 -0
- package/server/hermesChat.js.map +1 -0
- package/server/http.d.ts +5 -4
- package/server/http.js +0 -4
- package/server/http.js.map +1 -1
- package/server/mcp/server.d.ts +1 -1
- package/server/mcp/server.js +2 -2
- package/server/mcp/server.js.map +1 -1
- package/server/router.js +7 -3
- package/server/router.js.map +1 -1
- package/server/tools/scan.js +16 -2
- package/server/tools/scan.js.map +1 -1
- package/server/tools.d.ts +1 -0
- package/server/tools.js +46 -6
- package/server/tools.js.map +1 -1
- package/shared/diagram/aiMermaid.js +16 -13
- package/shared/diagram/aiMermaid.js.map +1 -1
package/public/js/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/public/js/api.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ScanRequest } from '../../shared/contracts.js';\n// Server round-trips. Thin and honest: JSON in, JSON (or an SSE stream) out,\n// server error messages surfaced untouched.\n\n// Browser access is an HttpOnly session cookie set by the themed self-hosted\n// login page. Same-origin fetches include it automatically, and JavaScript never\n// reads or stores the access key. API clients can still use `Authorization:\n// Bearer …`; local mode needs no credential at all.\n\n// 0.3.0 briefly stored a raw self-hosted key here. Remove that legacy value on\n// first load so upgrading also removes the old secret rather than merely ignoring it.\ntry { localStorage.removeItem('onboarder.accessKey'); } catch { /* storage may be unavailable */ }\n\nasync function postJSON(url: string, body: unknown, options: { signal?: AbortSignal } = {}) {\n const res = await fetch(url, {\n method: 'POST',\n signal: options.signal,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n });\n let data = null;\n try {\n data = await res.json();\n } catch {\n /* error path handled below with a generic message */\n }\n if (!res.ok) {\n throw new Error(data?.error || `The server said ${res.status}.`);\n }\n return data;\n}\n\nexport function scanOnServer(payload: ScanRequest, options: { signal?: AbortSignal } = {}) {\n return postJSON('/api/scan', payload, options);\n}\n\nexport async function cleanupClone(cloneId) {\n try {\n await fetch('/api/scan/' + encodeURIComponent(cloneId), { method: 'DELETE' });\n } catch {\n /* best-effort: the temp dir expires on its own eventually */\n }\n}\n\nexport async function fetchFileText(scanId, path) {\n const res = await fetch('/api/file?scan=' + encodeURIComponent(scanId) + '&path=' + encodeURIComponent(path));\n if (!res.ok) throw new Error('Could not read that file from the server.');\n return res.text();\n}\n\n// Which deep analyzers this machine can run, and how. Server-side scans only —\n// a browser-picked folder has no scan id and no server-visible root to point a\n// tool at, and this returns that honestly instead of pretending.\nexport async function fetchToolsStatus() {\n try {\n const res = await fetch('/api/tools');\n if (!res.ok) return null;\n const data = await res.json();\n return data && data.tools ? data.tools : null;\n } catch {\n return null; // an unreachable server is just \"no deep analysis here\"\n }\n}\n\n// Run the available analyzers against a live scan. `kinds`/`tools` narrow which\n// engines run; `options` carries the per-engine GUI settings, validated against\n// the registry schema on the server. The report normalizes every finding into\n// the shape the security view already draws, plus a per-engine pass list so\n// the UI can say which tool answered and which are missing.\nexport function runAnalysisTools(scanId, options: Record<string, any> = {}) {\n return postJSON('/api/tools/run', {\n scanId,\n kinds: options.kinds || undefined,\n tools: options.tools || undefined,\n options: options.options || undefined,\n });\n}\n\n// Install a missing engine, streaming progress events. The server emits SSE\n// frames shaped like the explain stream, minus the OpenAI envelope:\n// { type: 'log', line } / { type: 'plan', label } / { type: 'done', ok, … }\n// `onEvent` gets each one as it arrives; the promise resolves with the final\n// `done` event (or throws if the request itself failed).\nexport async function streamToolInstall(tool, onEvent) {\n const emit = typeof onEvent === 'function' ? onEvent : (..._args: unknown[]) => {};\n const res = await fetch('/api/tools/install', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tool }),\n });\n if (!res.ok || !res.body) {\n let detail = '';\n try { detail = (await res.json()).error || ''; } catch { /* generic below */ }\n throw new Error(detail || `The server said ${res.status}.`);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let done = null;\n while (true) {\n const { done: ended, value } = await reader.read();\n if (ended) break;\n buffer += decoder.decode(value, { stream: true });\n const frames = buffer.split('\\n\\n');\n buffer = frames.pop();\n for (const frame of frames) {\n for (const line of frame.split('\\n')) {\n if (!line.startsWith('data:')) continue;\n try {\n const event = JSON.parse(line.slice(5).trim());\n emit(event);\n if (event.type === 'done') done = event;\n } catch { /* a partial frame — the next chunk completes it */ }\n }\n }\n }\n return done || { type: 'done', ok: false, error: 'The install stream ended without a verdict.' };\n}\n\n// The MCP button's three round-trips. The status one is a plain GET like\n// `/api/tools`; start and stop are POSTs because each one changes a process on\n// this machine, which is exactly the side effect `postJSON` is here for.\nexport async function fetchMcpStatus() {\n try {\n const res = await fetch('/api/mcp');\n if (!res.ok) return null;\n return await res.json();\n } catch {\n return null; // no server means no button state, not an error to shout about\n }\n}\n\nexport function startMcpServer() {\n return postJSON('/api/mcp/start', {});\n}\n\nexport function stopMcpServer() {\n return postJSON('/api/mcp/stop', {});\n}\n\n// The command an agent harness is configured with. Kept separate from the status\n// fetch because it never changes, so it is read once when the panel opens rather\n// than on every poll.\nexport async function fetchMcpCommand() {\n try {\n const res = await fetch('/api/mcp/command');\n if (!res.ok) return null;\n return await res.json();\n } catch {\n return null;\n }\n}\n\n// Streams an OpenAI-compatible chat completion through the local proxy.\n// Yields text deltas as they arrive; throws with the provider's message on\n// a non-200 from upstream.\nexport async function* streamExplain({ baseUrl, apiKey, model, messages, maxTokens = 1200, providerOptions = {}, signal = undefined as AbortSignal | undefined }) {\n const res = await fetch('/api/explain', {\n signal,\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ baseUrl, apiKey, model, messages, stream: true, max_tokens: maxTokens, ...providerOptions }),\n });\n\n if (!res.ok) {\n let detail = '';\n try {\n const data = await res.json();\n detail = data.detail || data.error || '';\n } catch {\n /* keep the generic line */\n }\n throw new Error(detail || `The provider said ${res.status}.`);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const frames = buffer.split('\\n\\n');\n buffer = frames.pop();\n for (const frame of frames) {\n for (const line of frame.split('\\n')) {\n if (!line.startsWith('data:')) continue;\n const payload = line.slice(5).trim();\n if (payload === '[DONE]') return;\n try {\n const json = JSON.parse(payload);\n const delta = json.choices?.[0]?.delta?.content;\n if (delta) yield delta;\n } catch {\n /* a partial JSON frame — the next chunk completes it */\n }\n }\n }\n }\n}\n\n// The Server drawer's three round-trips. The read is a GET that comes back\n// with the secret masked; writes go through PUT with only the changed keys;\n// rotation is a POST because it mints a new key on the server — the one and\n// only time a key ever crosses the wire in the clear.\nexport async function fetchServerSettings() {\n const res = await fetch('/api/settings');\n const data = await res.json().catch(() => null);\n if (!res.ok) throw new Error(data?.error || `The server said ${res.status}.`);\n return data;\n}\n\nexport async function updateServerSettings(patch) {\n const res = await fetch('/api/settings', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(patch),\n });\n const data = await res.json().catch(() => null);\n if (!res.ok) throw new Error(data?.error || `The server said ${res.status}.`);\n return data;\n}\n\nexport function rotateServerAccessKey() {\n return postJSON('/api/settings/access-key', {});\n}\n\nexport function logoutRemoteSession() {\n return postJSON('/api/auth/logout', {});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/public/js/api.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ScanRequest } from '../../shared/contracts.js';\n// Server round-trips. Thin and honest: JSON in, JSON (or an SSE stream) out,\n// server error messages surfaced untouched.\n\n// Browser access is an HttpOnly session cookie set by the themed self-hosted\n// login page. Same-origin fetches include it automatically, and JavaScript never\n// reads or stores the access key. API clients can still use `Authorization:\n// Bearer …`; local mode needs no credential at all.\n\n// 0.3.0 briefly stored a raw self-hosted key here. Remove that legacy value on\n// first load so upgrading also removes the old secret rather than merely ignoring it.\ntry { localStorage.removeItem('onboarder.accessKey'); } catch { /* storage may be unavailable */ }\n\nasync function postJSON(url: string, body: unknown, options: { signal?: AbortSignal } = {}) {\n const res = await fetch(url, {\n method: 'POST',\n signal: options.signal,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n });\n let data = null;\n try {\n data = await res.json();\n } catch {\n /* error path handled below with a generic message */\n }\n if (!res.ok) {\n throw new Error(data?.error || `The server said ${res.status}.`);\n }\n return data;\n}\n\nexport function scanOnServer(payload: ScanRequest, options: { signal?: AbortSignal } = {}) {\n return postJSON('/api/scan', payload, options);\n}\n\nexport async function cleanupClone(cloneId) {\n try {\n await fetch('/api/scan/' + encodeURIComponent(cloneId), { method: 'DELETE' });\n } catch {\n /* best-effort: the temp dir expires on its own eventually */\n }\n}\n\nexport async function fetchFileText(scanId, path) {\n const res = await fetch('/api/file?scan=' + encodeURIComponent(scanId) + '&path=' + encodeURIComponent(path));\n if (!res.ok) throw new Error('Could not read that file from the server.');\n return res.text();\n}\n\n// Which deep analyzers this machine can run, and how. Server-side scans only —\n// a browser-picked folder has no scan id and no server-visible root to point a\n// tool at, and this returns that honestly instead of pretending.\nexport async function fetchToolsStatus() {\n try {\n const res = await fetch('/api/tools');\n if (!res.ok) return null;\n const data = await res.json();\n return data && data.tools ? data.tools : null;\n } catch {\n return null; // an unreachable server is just \"no deep analysis here\"\n }\n}\n\n// Run the available analyzers against a live scan. `kinds`/`tools` narrow which\n// engines run; `options` carries the per-engine GUI settings, validated against\n// the registry schema on the server. The report normalizes every finding into\n// the shape the security view already draws, plus a per-engine pass list so\n// the UI can say which tool answered and which are missing.\nexport function runAnalysisTools(scanId, options: Record<string, any> = {}) {\n return postJSON('/api/tools/run', {\n scanId,\n kinds: options.kinds || undefined,\n tools: options.tools || undefined,\n options: options.options || undefined,\n });\n}\n\n// Install a missing engine, streaming progress events. The server emits SSE\n// frames shaped like the explain stream, minus the OpenAI envelope:\n// { type: 'log', line } / { type: 'plan', label } / { type: 'done', ok, … }\n// `onEvent` gets each one as it arrives; the promise resolves with the final\n// `done` event (or throws if the request itself failed).\nexport async function streamToolInstall(tool, onEvent) {\n const emit = typeof onEvent === 'function' ? onEvent : (..._args: unknown[]) => {};\n const res = await fetch('/api/tools/install', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tool }),\n });\n if (!res.ok || !res.body) {\n let detail = '';\n try { detail = (await res.json()).error || ''; } catch { /* generic below */ }\n throw new Error(detail || `The server said ${res.status}.`);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let done = null;\n while (true) {\n const { done: ended, value } = await reader.read();\n if (ended) break;\n buffer += decoder.decode(value, { stream: true });\n const frames = buffer.split('\\n\\n');\n buffer = frames.pop();\n for (const frame of frames) {\n for (const line of frame.split('\\n')) {\n if (!line.startsWith('data:')) continue;\n try {\n const event = JSON.parse(line.slice(5).trim());\n emit(event);\n if (event.type === 'done') done = event;\n } catch { /* a partial frame — the next chunk completes it */ }\n }\n }\n }\n return done || { type: 'done', ok: false, error: 'The install stream ended without a verdict.' };\n}\n\n// The MCP button's three round-trips. The status one is a plain GET like\n// `/api/tools`; start and stop are POSTs because each one changes a process on\n// this machine, which is exactly the side effect `postJSON` is here for.\nexport async function fetchMcpStatus() {\n try {\n const res = await fetch('/api/mcp');\n if (!res.ok) return null;\n return await res.json();\n } catch {\n return null; // no server means no button state, not an error to shout about\n }\n}\n\nexport function startMcpServer() {\n return postJSON('/api/mcp/start', {});\n}\n\nexport function stopMcpServer() {\n return postJSON('/api/mcp/stop', {});\n}\n\n// The command an agent harness is configured with. Kept separate from the status\n// fetch because it never changes, so it is read once when the panel opens rather\n// than on every poll.\nexport async function fetchMcpCommand() {\n try {\n const res = await fetch('/api/mcp/command');\n if (!res.ok) return null;\n return await res.json();\n } catch {\n return null;\n }\n}\n\n// Streams an OpenAI-compatible chat completion through the local proxy.\n// Yields text deltas as they arrive; throws with the provider's message on\n// a non-200 from upstream.\nexport async function* streamExplain({ connection = 'api', baseUrl = '', apiKey = '', model = '', messages, maxTokens = 1200, providerOptions = {}, purpose = '', signal = undefined as AbortSignal | undefined }) {\n const res = await fetch('/api/explain', {\n signal,\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(connection === 'hermes' ? { connection, messages, stream: true, ...(purpose === 'diagram' ? { purpose } : {}) }\n : { baseUrl, apiKey, model, messages, stream: true, max_tokens: maxTokens, ...providerOptions }),\n });\n\n if (!res.ok) {\n let detail = '';\n try {\n const data = await res.json();\n detail = data.detail || data.error || '';\n } catch {\n /* keep the generic line */\n }\n throw new Error(detail || `The provider said ${res.status}.`);\n }\n\n if (!res.body) throw new Error('The connection returned no answer stream.');\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n try { while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer = (buffer + decoder.decode(value, { stream: true })).replace(/\\r\\n/g, '\\n');\n if (buffer.length > 2 * 1024 * 1024) throw new Error('The answer exceeded the stream limit.');\n const frames = buffer.split('\\n\\n');\n buffer = frames.pop();\n for (const frame of frames) {\n for (const line of frame.split('\\n')) {\n if (!line.startsWith('data:')) continue;\n const payload = line.slice(5).trim();\n if (payload === '[DONE]') return;\n let json;\n try { json = JSON.parse(payload); } catch { continue; }\n if (json.error) throw new Error(typeof json.error === 'string' ? json.error : json.error.message || 'The assistant could not finish its answer.');\n const delta = json.choices?.[0]?.delta?.content;\n if (typeof delta === 'string' && delta) yield delta;\n }\n }\n }\n if (connection === 'hermes') throw new Error('Hermes disconnected before finishing its answer. Try again.');\n } finally { await reader.cancel().catch(() => {}); reader.releaseLock(); }\n}\n\nexport async function fetchHermesStatus(signal?: AbortSignal) {\n const res = await fetch('/api/hermes', { signal });\n const data = await res.json();\n if (!res.ok) throw new Error(data.error || 'Could not check Hermes.');\n return data;\n}\n\n// The Server drawer's three round-trips. The read is a GET that comes back\n// with the secret masked; writes go through PUT with only the changed keys;\n// rotation is a POST because it mints a new key on the server — the one and\n// only time a key ever crosses the wire in the clear.\nexport async function fetchServerSettings() {\n const res = await fetch('/api/settings');\n const data = await res.json().catch(() => null);\n if (!res.ok) throw new Error(data?.error || `The server said ${res.status}.`);\n return data;\n}\n\nexport async function updateServerSettings(patch) {\n const res = await fetch('/api/settings', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(patch),\n });\n const data = await res.json().catch(() => null);\n if (!res.ok) throw new Error(data?.error || `The server said ${res.status}.`);\n return data;\n}\n\nexport function rotateServerAccessKey() {\n return postJSON('/api/settings/access-key', {});\n}\n\nexport function logoutRemoteSession() {\n return postJSON('/api/auth/logout', {});\n}\n"]}
|
|
@@ -152,7 +152,7 @@ async function explainWithAI(question) {
|
|
|
152
152
|
return;
|
|
153
153
|
if (!llm.isConfigured()) {
|
|
154
154
|
hooks.onOpenSettings();
|
|
155
|
-
hooks.onToast('
|
|
155
|
+
hooks.onToast('Choose Hermes or an endpoint in AI connection — the report is still readable without one.');
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
158
|
const rows = findingsFromSecurity(state.security);
|
|
@@ -372,7 +372,7 @@ function renderAIBlock() {
|
|
|
372
372
|
const ask = escapeHtml(state.analysis.ai.question || '');
|
|
373
373
|
const settingsBtn = configured
|
|
374
374
|
? ''
|
|
375
|
-
: '<button class="btn btn-ghost btn-sm" data-open-settings>
|
|
375
|
+
: '<button class="btn btn-ghost btn-sm" data-open-settings>AI connection…</button>';
|
|
376
376
|
return `<section class="analysis-block">
|
|
377
377
|
<h2 class="analysis-h">What this means <span class="analysis-h-sub">ask the AI</span></h2>
|
|
378
378
|
<div class="analysis-ai">
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepAnalysisView.js","sourceRoot":"","sources":["../../src/public/js/deepAnalysisView.ts"],"names":[],"mappings":"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","sourcesContent":["// The Deep Analysis view: the whole report, in one place, with every finding a\n// click away from its line.\n//\n// The Security panel in the inspector is a summary — engines, a run button, a\n// verdict. This is the other half: a full-page report you can read, filter, and\n// ask about. It shares the run itself with the panel through the store in\n// `analysisPanel.js`, so both surfaces always show the same report and the same\n// grade; only the presentation differs.\n//\n// Three blocks, top to bottom:\n//\n// 1. **Engines** — what is installed, what ran, what it cost, and what it\n// found. An engine that could not run says so here, with the reason, which\n// is the difference between \"clean\" and \"unchecked\".\n// 2. **What this means** — the AI. One button explains the report; the box\n// answers a specific question about it. Works offline: with no endpoint\n// configured it offers the drawer instead of failing silently.\n// 3. **Findings** — every finding from every engine, merged, worst first,\n// each row linking to `file:line` in the Code tab.\n//\n// The filters (severity, engine, text) live on `state.analysis` so they survive\n// switching tabs within a repo, and reset with the repo.\n\nimport { escapeHtml } from './html.js';\nimport { mdInline } from './markdown.js';\nimport { streamExplain } from './api.js';\nimport * as llm from './llm.js';\nimport { state } from './state.js';\nimport {\n filterFindings, findingsFromSecurity, tabulate, engineRows, engineSummary,\n SEV_ORDER, BUILTIN_TOOL,\n} from './analysisReport.js';\nimport {\n ensureToolsStatus, installEngine, runDeepAnalysis, runOutcomeMessage, subscribeAnalysis,\n} from './analysisPanel.js';\n\nlet host = null;\nlet hooks = {\n onToast: (..._args: unknown[]) => {},\n onOpenFile: (..._args: unknown[]) => {},\n onOpenSettings: (..._args: unknown[]) => {},\n repoOverview: () => '',\n};\n\nexport function initDeepAnalysis(options) {\n host = options.host;\n hooks = { ...hooks, ...options };\n\n host.addEventListener('click', (event) => {\n const kind = event.target.closest('[data-run-kind]');\n if (kind) return void doRun({ kinds: [kind.dataset.runKind] });\n\n if (event.target.closest('[data-run-all]')) return void doRun({});\n\n const engineRun = event.target.closest('[data-engine-run]');\n if (engineRun) return void doRun({ tools: [engineRun.dataset.engineRun] });\n\n const engineInstall = event.target.closest('[data-engine-install]');\n if (engineInstall) {\n const id = engineInstall.dataset.engineInstall;\n return void installEngine(id).then((done) => {\n if (done && done.ok) hooks.onToast(`${id} installed — press Run to use it.`);\n else if (done && done.error) hooks.onToast(done.error);\n });\n }\n\n if (event.target.closest('[data-sev]')) {\n state.analysis.severity = event.target.closest('[data-sev]').dataset.sev;\n return renderDeepAnalysis(host, state);\n }\n if (event.target.closest('[data-tool-filter]')) {\n state.analysis.tool = event.target.closest('[data-tool-filter]').dataset.toolFilter;\n return renderDeepAnalysis(host, state);\n }\n if (event.target.closest('[data-open-settings]')) {\n hooks.onOpenSettings();\n return undefined;\n }\n if (event.target.closest('[data-ai-explain]')) return void explainWithAI('');\n\n const fileLink = event.target.closest('[data-goto]');\n if (fileLink) {\n hooks.onOpenFile(fileLink.dataset.goto, Number(fileLink.dataset.gotoLine) || 0);\n }\n return undefined;\n });\n\n host.addEventListener('input', (event) => {\n if (event.target.matches('[data-finding-search]')) {\n const caret = event.target.selectionStart;\n state.analysis.q = event.target.value;\n renderDeepAnalysis(host, state);\n // Re-focus and restore the caret: a full repaint replaces the input, and\n // typing into a box that loses focus on every keystroke is unusable.\n const next = host.querySelector('[data-finding-search]');\n if (next) {\n next.focus();\n next.setSelectionRange(caret, caret);\n }\n return;\n }\n if (event.target.matches('[data-ai-question]')) {\n state.analysis.ai.question = event.target.value;\n }\n });\n\n host.addEventListener('keydown', (event) => {\n if (event.key === 'Enter' && event.target.matches('[data-ai-question]')) {\n event.preventDefault();\n explainWithAI(event.target.value);\n }\n });\n\n // The Configure forms. `change` — not `input` — so a repaint never fights a\n // half-typed number; the store keeps the values and the next run picks them\n // up. No repaint on change either: the control itself already shows the new\n // value, and redrawing would close the <details> the person just opened.\n host.addEventListener('change', (event) => {\n const control = event.target.closest('[data-opt]');\n if (!control) return;\n const { engine, key } = control.dataset;\n const slot = state.tools.options[engine] || (state.tools.options[engine] = {});\n if (control.type === 'checkbox') {\n if (control.dataset.optValue) {\n // one value of a multi-select\n const list = Array.isArray(slot[key]) ? [...slot[key]] : [];\n const at = list.indexOf(control.dataset.optValue);\n if (control.checked && at === -1) list.push(control.dataset.optValue);\n if (!control.checked && at !== -1) list.splice(at, 1);\n slot[key] = list;\n } else {\n slot[key] = control.checked;\n }\n } else if (control.type === 'number') {\n slot[key] = control.value === '' ? undefined : Number(control.value);\n } else {\n slot[key] = control.value;\n }\n });\n\n // A run started from the inspector panel repaints this view too.\n subscribeAnalysis(() => {\n if (state.view === 'analysis') renderDeepAnalysis(host, state);\n });\n}\n\nasync function doRun(options) {\n const report = await runDeepAnalysis(options);\n hooks.onToast(runOutcomeMessage(report));\n}\n\n// ---- the AI pass ------------------------------------------------------------\n\n// Explains the report, or answers `question` about it. Streams into\n// `state.analysis.ai.text` and repaints the note in place — a full page repaint\n// mid-stream would throw away every character already received.\nasync function explainWithAI(question) {\n const ai = state.analysis.ai;\n if (ai.running) return;\n\n if (!llm.isConfigured()) {\n hooks.onOpenSettings();\n hooks.onToast('Add an endpoint and model first — the report is still readable without one.');\n return;\n }\n\n const rows = findingsFromSecurity(state.security);\n const counts = tabulate(rows);\n const engines = engineRows(state.tools.status, state.tools.report);\n const messages = llm.analysisMessages({\n repoName: state.scan.name,\n grade: state.security?.grade,\n score: state.security?.score,\n counts,\n engines,\n findings: rows,\n question: (question || '').trim(),\n });\n\n const settings = llm.getSettings();\n ai.running = true;\n ai.text = '';\n ai.error = '';\n paintAI();\n\n try {\n const providerOptions = llm.isAzureHost(settings.baseUrl) ? {} : { reasoning: { exclude: true } };\n for await (const delta of streamExplain({ ...settings, messages, maxTokens: 900, providerOptions })) {\n ai.text += delta;\n paintAI();\n }\n } catch (err) {\n ai.error = err.message;\n } finally {\n ai.running = false;\n paintAI();\n }\n}\n\n// Repaint just the AI note, so streaming never fights the rest of the page.\nfunction paintAI() {\n if (!host) return;\n const note = host.querySelector('[data-ai-note]');\n if (!note) return;\n const ai = state.analysis.ai;\n note.innerHTML = renderAINote(ai);\n}\n\n// ---- painting ---------------------------------------------------------------\n\nexport function renderDeepAnalysis(container, appState = state) {\n if (!container) return;\n host = container;\n const { analysis } = appState;\n\n // A browser-picked folder has no server-side root, so there is nothing for an\n // engine to read. Say that once, plainly, rather than showing an empty table\n // that looks like a clean bill of health.\n if (!appState.scanId) {\n container.innerHTML = `<div class=\"analysis-layout\">\n <header class=\"analysis-head\">\n <h1 class=\"analysis-title\">Deep analysis</h1>\n <p class=\"analysis-sub\">External engines — Semgrep, Gitleaks, Knip, Vulture, Depcheck.</p>\n </header>\n <div class=\"analysis-empty\">This repo was picked in the browser, so its files never reached the server. An external engine needs a directory on the server to read, so deep analysis is available for folders scanned by path and for git clones. The built-in scan — every finding on the <b>Security</b> tab — still applies.</div>\n </div>`;\n return;\n }\n\n const engines = engineRows(appState.tools.status, appState.tools.report);\n const all = findingsFromSecurity(appState.security);\n const counts = tabulate(all);\n const visible = filterFindings(all, analysis);\n const summary = engineSummary(appState.tools.report, engines);\n const running = appState.tools.running;\n\n container.innerHTML = `<div class=\"analysis-layout\">\n ${renderHead(counts, running)}\n ${renderEngineBlock(engines, summary, running, appState.tools)}\n ${renderAIBlock()}\n ${renderFindingsBlock(visible, counts, analysis)}\n </div>`;\n\n // The engines panel may still be loading; ask once and let the store notify.\n if (!appState.tools.status && !appState.tools.loading) void ensureToolsStatus();\n}\n\nfunction renderHead(counts, running) {\n const chip = (label, value, cls = '') => `<span class=\"analysis-chip ${cls}\"><b>${value}</b> ${label}</span>`;\n return `<header class=\"analysis-head\">\n <div class=\"analysis-head-text\">\n <h1 class=\"analysis-title\">Deep analysis</h1>\n <p class=\"analysis-sub\">Every engine this machine has, plus the built-in scanner — merged into one list. Click any file to open it at the line.</p>\n </div>\n <div class=\"analysis-actions\">\n <button class=\"btn btn-ink\" data-run-all ${running ? 'disabled' : ''}>${running ? 'Running…' : 'Run all engines'}</button>\n <button class=\"btn btn-ghost\" data-run-kind=\"security\" ${running ? 'disabled' : ''}>Security only</button>\n <button class=\"btn btn-ghost\" data-run-kind=\"dead-code\" ${running ? 'disabled' : ''}>Dead code only</button>\n </div>\n </header>\n <div class=\"analysis-stats\">\n ${chip('findings', counts.total)}\n ${counts.critical ? chip('critical', counts.critical, 'is-critical') : ''}\n ${counts.high ? chip('high', counts.high, 'is-high') : ''}\n ${chip('from engines', counts.external, counts.external ? 'is-external' : '')}\n ${chip('from built-in', counts.builtin)}\n </div>`;\n}\n\nfunction renderEngineBlock(engines, summary, running, tools) {\n const rows = engines.length ? engines.map((e) => renderEngineRow(e, running)).join('') : '';\n const empty = tools.loading\n ? '<div class=\"analysis-empty\">Checking which engines are installed…</div>'\n : (engines.length ? '' : '<div class=\"analysis-empty\">No engine table — the server did not answer.</div>');\n\n return `<section class=\"analysis-block\">\n <h2 class=\"analysis-h\">Engines <span class=\"analysis-h-sub\">what this machine can run</span></h2>\n <div class=\"analysis-engines\">${rows}${empty}</div>\n <div class=\"analysis-verdict is-${escapeHtml(summary.tone)}\">${escapeHtml(summary.text)}</div>\n </section>`;\n}\n\nfunction renderEngineRow(engine, running) {\n const installing = state.tools.install[engine.id];\n let badge;\n if (installing && installing.running) badge = '<span class=\"tools-badge is-running\">installing…</span>';\n else if (!engine.available) badge = '<span class=\"tools-badge is-missing\">not installed</span>';\n else if (running) badge = '<span class=\"tools-badge is-running\">running…</span>';\n else if (engine.ran) badge = `<span class=\"tools-badge is-ran\">${engine.findings} · ${engine.ms}ms</span>`;\n else if (engine.failed) badge = '<span class=\"tools-badge is-failed\">failed</span>';\n else badge = `<span class=\"tools-badge is-ready\">ready${engine.how ? ' · ' + escapeHtml(engine.how) : ''}</span>`;\n\n const note = !engine.available && engine.reason\n ? `<span class=\"tools-reason\">${escapeHtml(engine.reason)}</span>`\n : (engine.failure ? `<span class=\"tools-reason\">${escapeHtml(engine.failure)}</span>` : '');\n\n const runBtn = engine.available\n ? `<button class=\"btn btn-ghost btn-sm\" data-engine-run=\"${escapeHtml(engine.id)}\" ${running ? 'disabled' : ''}>Run</button>`\n : '';\n const installBtn = !engine.available && engine.installable\n ? `<button class=\"btn btn-ink btn-sm\" data-engine-install=\"${escapeHtml(engine.id)}\" ${installing && installing.running ? 'disabled' : ''}>${installing && installing.running ? 'Installing…' : 'Install'}</button>`\n : '';\n\n return `<div class=\"analysis-engine${engine.available ? '' : ' is-missing'}\">\n <div class=\"analysis-engine-top\">\n <span class=\"tools-name\">${escapeHtml(engine.label)}</span>\n ${badge}\n <span class=\"analysis-engine-kind\">${escapeHtml(engine.kind)}</span>\n ${installBtn}\n ${runBtn}\n </div>\n <div class=\"tools-purpose\">${escapeHtml(engine.purpose)}</div>\n ${note}\n ${renderEngineOptions(engine)}\n ${renderInstallConsole(installing)}\n </div>`;\n}\n\n// The Configure panel: a <details> with one control per schema entry, so the\n// useful surface of each engine — semgrep's rule sets, gitleaks' history\n// scan, vulture's confidence floor — is a form, not a command line. Values\n// live in `state.tools.options` and ride along with the next run; the server\n// validates them against the same schema before they touch an argv.\nfunction renderEngineOptions(engine) {\n if (!engine.options.length) return '';\n const values = state.tools.options[engine.id] || {};\n\n const field = (opt) => {\n const current = values[opt.key] !== undefined ? values[opt.key] : engine.defaults[opt.key];\n let control;\n if (opt.type === 'boolean') {\n control = `<label class=\"analysis-opt-check\">\n <input type=\"checkbox\" data-opt data-engine=\"${escapeHtml(engine.id)}\" data-key=\"${escapeHtml(opt.key)}\" ${current ? 'checked' : ''}>\n <span>${escapeHtml(opt.label)}</span>\n </label>`;\n } else if (opt.type === 'enum') {\n const options = opt.values.map((v) =>\n `<option value=\"${escapeHtml(v)}\" ${v === current ? 'selected' : ''}>${escapeHtml(v)}</option>`).join('');\n control = `<label class=\"analysis-opt-field\"><span>${escapeHtml(opt.label)}</span>\n <select class=\"text-input\" data-opt data-engine=\"${escapeHtml(engine.id)}\" data-key=\"${escapeHtml(opt.key)}\">${options}</select>\n </label>`;\n } else if (opt.type === 'multi') {\n const chosen = Array.isArray(current) ? current : [];\n control = `<div class=\"analysis-opt-field\"><span>${escapeHtml(opt.label)}</span>\n <div class=\"analysis-opt-multi\">${opt.values.map((v) => `\n <label class=\"analysis-opt-check\">\n <input type=\"checkbox\" data-opt data-engine=\"${escapeHtml(engine.id)}\" data-key=\"${escapeHtml(opt.key)}\"\n data-opt-value=\"${escapeHtml(v)}\" ${chosen.includes(v) ? 'checked' : ''}>\n <span>${escapeHtml(v)}</span>\n </label>`).join('')}\n </div>\n </div>`;\n } else { // number\n control = `<label class=\"analysis-opt-field\"><span>${escapeHtml(opt.label)}</span>\n <input type=\"number\" class=\"text-input\" data-opt data-engine=\"${escapeHtml(engine.id)}\" data-key=\"${escapeHtml(opt.key)}\"\n min=\"${opt.min}\" max=\"${opt.max}\" value=\"${escapeHtml(String(current ?? opt.default))}\">\n </label>`;\n }\n const hint = opt.hint ? `<span class=\"analysis-opt-hint\">${escapeHtml(opt.hint)}</span>` : '';\n return `<div class=\"analysis-opt\">${control}${hint}</div>`;\n };\n\n return `<details class=\"analysis-config\">\n <summary>Configure</summary>\n <div class=\"analysis-config-body\">${engine.options.map(field).join('')}</div>\n </details>`;\n}\n\n// The install log, live while an install runs and kept afterwards so a failed\n// install leaves its reason on screen instead of in a toast that faded.\nfunction renderInstallConsole(installing) {\n if (!installing || (!installing.log.length && !installing.running && !installing.error)) return '';\n const verdict = installing.running\n ? ''\n : installing.ok\n ? '<div class=\"analysis-console-verdict is-ok\">Installed — the engine is ready.</div>'\n : `<div class=\"analysis-console-verdict is-err\">${escapeHtml(installing.error || 'The install failed.')}</div>`;\n return `<div class=\"analysis-console-wrap\">\n <pre class=\"analysis-console\">${escapeHtml(installing.log.join('\\n'))}${installing.running ? ' ▍' : ''}</pre>\n ${verdict}\n </div>`;\n}\n\n\nfunction renderAIBlock() {\n const configured = llm.isConfigured();\n const ask = escapeHtml(state.analysis.ai.question || '');\n const settingsBtn = configured\n ? ''\n : '<button class=\"btn btn-ghost btn-sm\" data-open-settings>API key…</button>';\n return `<section class=\"analysis-block\">\n <h2 class=\"analysis-h\">What this means <span class=\"analysis-h-sub\">ask the AI</span></h2>\n <div class=\"analysis-ai\">\n <div class=\"analysis-ai-bar\">\n <button class=\"btn btn-ink btn-sm\" data-ai-explain>${configured ? 'Explain this analysis' : 'Explain (needs an endpoint)'}</button>\n ${settingsBtn}\n <span class=\"analysis-ai-hint\">Uses the report above — engines, severities, files. Nothing is sent anywhere but your own endpoint.</span>\n </div>\n <div class=\"analysis-ai-note\" data-ai-note>${renderAINote(state.analysis.ai)}</div>\n <div class=\"analysis-ai-ask\">\n <input type=\"text\" class=\"text-input\" data-ai-question placeholder=\"Ask about this report — e.g. “is the eval finding reachable?”\" value=\"${ask}\" spellcheck=\"false\" autocomplete=\"off\">\n <button class=\"btn btn-ghost btn-sm\" data-ai-explain>Ask</button>\n </div>\n </div>\n </section>`;\n}\n\n// The note is plain text from the model. It goes through `mdInline`, the same\n// boundary helper the inspector uses: escape first, then bold and inline code.\n// The prompt asks for prose, but models reach for `**bold**` and backticks\n// anyway, and half-rendered asterisks look like a bug.\nexport function renderAINote(ai) {\n if (ai.running && !ai.text) {\n return '<span class=\"analysis-ai-waiting\"><span class=\"search-spinner\"></span> Reading the report…</span>';\n }\n if (ai.error) return `<span class=\"analysis-ai-error\">${escapeHtml(ai.error)}</span>`;\n if (!ai.text) {\n return '<span class=\"analysis-ai-idle\">Press <b>Explain this analysis</b> for a prioritised read of the findings above, or ask a question about any of them.</span>';\n }\n const html = ai.text\n .split(/\\n{2,}/)\n .map((para) => `<p>${mdInline(para).replace(/\\n/g, '<br>')}</p>`)\n .join('');\n const cursor = ai.running ? '<span class=\"analysis-ai-cursor\">▍</span>' : '';\n return html + cursor;\n}\n\nfunction renderFindingsBlock(visible, counts, analysis) {\n const sevChips = ['all', ...SEV_ORDER].map((sev) => {\n const n = sev === 'all' ? counts.total : (counts.bySeverity[sev] || 0);\n if (sev !== 'all' && !n) return '';\n const active = analysis.severity === sev ? ' is-active' : '';\n return `<button class=\"btn btn-ghost btn-sm${active}\" data-sev=\"${sev}\">${sev} (${n})</button>`;\n }).join('');\n\n const tools = Object.keys(counts.byTool).sort((a, b) => counts.byTool[b] - counts.byTool[a]);\n const toolChips = tools.length > 1\n ? ['all', ...tools].map((tool) => {\n const n = tool === 'all' ? counts.total : counts.byTool[tool];\n const label = tool === BUILTIN_TOOL ? 'built-in scanner' : tool;\n const active = analysis.tool === tool ? ' is-active' : '';\n return `<button class=\"btn btn-ghost btn-sm${active}\" data-tool-filter=\"${escapeHtml(tool)}\">${escapeHtml(label)} (${n})</button>`;\n }).join('')\n : '';\n\n const body = visible.length\n ? visible.map(renderFindingRow).join('')\n : `<tr><td colspan=\"5\" class=\"analysis-no-rows\">Nothing matches those filters.</td></tr>`;\n\n return `<section class=\"analysis-block\">\n <h2 class=\"analysis-h\">Findings <span class=\"analysis-h-sub\">${visible.length} of ${counts.total} shown</span></h2>\n <div class=\"analysis-filterbar\">\n <div class=\"analysis-filter-group\">${sevChips}</div>\n ${toolChips ? `<div class=\"analysis-filter-group\">${toolChips}</div>` : ''}\n <input type=\"text\" class=\"text-input analysis-search\" data-finding-search\n placeholder=\"Filter by file, rule or message…\" value=\"${escapeHtml(analysis.q || '')}\" spellcheck=\"false\">\n </div>\n <div class=\"analysis-table-wrap\">\n <table class=\"analysis-table\">\n <thead><tr>\n <th class=\"col-sev\">Severity</th>\n <th class=\"col-file\">File</th>\n <th class=\"col-rule\">Rule</th>\n <th class=\"col-tool\">Engine</th>\n <th>Finding</th>\n </tr></thead>\n <tbody>${body}</tbody>\n </table>\n </div>\n </section>`;\n}\n\n// One finding. The file cell is the point of the whole view: it carries the\n// path, the line, and the click that opens the Code tab there.\nfunction renderFindingRow(row) {\n return `<tr class=\"analysis-row is-${escapeHtml(row.severity)}\">\n <td class=\"col-sev\"><span class=\"sev-pill is-${escapeHtml(row.severity)}\">${escapeHtml(row.severity)}</span></td>\n <td class=\"col-file\">\n <button class=\"analysis-file\" data-goto=\"${escapeHtml(row.path)}\" data-goto-line=\"${row.line}\"\n title=\"Open ${escapeHtml(row.path)} at line ${row.line}\">\n <span class=\"analysis-file-name\">${escapeHtml(row.name)}</span>\n <span class=\"analysis-file-line\">L${row.line}</span>\n </button>\n <span class=\"analysis-file-dir\">${escapeHtml(dirOf(row.path))}</span>\n </td>\n <td class=\"col-rule\"><code>${escapeHtml(row.rule)}</code></td>\n <td class=\"col-tool\"><span class=\"analysis-tool is-${escapeHtml(row.tool === BUILTIN_TOOL ? 'builtin' : 'external')}\">${escapeHtml(row.tool === BUILTIN_TOOL ? 'built-in' : row.tool)}</span></td>\n <td class=\"analysis-msg\">${escapeHtml(row.message)}</td>\n </tr>`;\n}\n\nfunction dirOf(path) {\n const at = String(path || '').lastIndexOf('/');\n return at === -1 ? '' : path.slice(0, at);\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"deepAnalysisView.js","sourceRoot":"","sources":["../../src/public/js/deepAnalysisView.ts"],"names":[],"mappings":"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","sourcesContent":["// The Deep Analysis view: the whole report, in one place, with every finding a\n// click away from its line.\n//\n// The Security panel in the inspector is a summary — engines, a run button, a\n// verdict. This is the other half: a full-page report you can read, filter, and\n// ask about. It shares the run itself with the panel through the store in\n// `analysisPanel.js`, so both surfaces always show the same report and the same\n// grade; only the presentation differs.\n//\n// Three blocks, top to bottom:\n//\n// 1. **Engines** — what is installed, what ran, what it cost, and what it\n// found. An engine that could not run says so here, with the reason, which\n// is the difference between \"clean\" and \"unchecked\".\n// 2. **What this means** — the AI. One button explains the report; the box\n// answers a specific question about it. Works offline: with no endpoint\n// configured it offers the drawer instead of failing silently.\n// 3. **Findings** — every finding from every engine, merged, worst first,\n// each row linking to `file:line` in the Code tab.\n//\n// The filters (severity, engine, text) live on `state.analysis` so they survive\n// switching tabs within a repo, and reset with the repo.\n\nimport { escapeHtml } from './html.js';\nimport { mdInline } from './markdown.js';\nimport { streamExplain } from './api.js';\nimport * as llm from './llm.js';\nimport { state } from './state.js';\nimport {\n filterFindings, findingsFromSecurity, tabulate, engineRows, engineSummary,\n SEV_ORDER, BUILTIN_TOOL,\n} from './analysisReport.js';\nimport {\n ensureToolsStatus, installEngine, runDeepAnalysis, runOutcomeMessage, subscribeAnalysis,\n} from './analysisPanel.js';\n\nlet host = null;\nlet hooks = {\n onToast: (..._args: unknown[]) => {},\n onOpenFile: (..._args: unknown[]) => {},\n onOpenSettings: (..._args: unknown[]) => {},\n repoOverview: () => '',\n};\n\nexport function initDeepAnalysis(options) {\n host = options.host;\n hooks = { ...hooks, ...options };\n\n host.addEventListener('click', (event) => {\n const kind = event.target.closest('[data-run-kind]');\n if (kind) return void doRun({ kinds: [kind.dataset.runKind] });\n\n if (event.target.closest('[data-run-all]')) return void doRun({});\n\n const engineRun = event.target.closest('[data-engine-run]');\n if (engineRun) return void doRun({ tools: [engineRun.dataset.engineRun] });\n\n const engineInstall = event.target.closest('[data-engine-install]');\n if (engineInstall) {\n const id = engineInstall.dataset.engineInstall;\n return void installEngine(id).then((done) => {\n if (done && done.ok) hooks.onToast(`${id} installed — press Run to use it.`);\n else if (done && done.error) hooks.onToast(done.error);\n });\n }\n\n if (event.target.closest('[data-sev]')) {\n state.analysis.severity = event.target.closest('[data-sev]').dataset.sev;\n return renderDeepAnalysis(host, state);\n }\n if (event.target.closest('[data-tool-filter]')) {\n state.analysis.tool = event.target.closest('[data-tool-filter]').dataset.toolFilter;\n return renderDeepAnalysis(host, state);\n }\n if (event.target.closest('[data-open-settings]')) {\n hooks.onOpenSettings();\n return undefined;\n }\n if (event.target.closest('[data-ai-explain]')) return void explainWithAI('');\n\n const fileLink = event.target.closest('[data-goto]');\n if (fileLink) {\n hooks.onOpenFile(fileLink.dataset.goto, Number(fileLink.dataset.gotoLine) || 0);\n }\n return undefined;\n });\n\n host.addEventListener('input', (event) => {\n if (event.target.matches('[data-finding-search]')) {\n const caret = event.target.selectionStart;\n state.analysis.q = event.target.value;\n renderDeepAnalysis(host, state);\n // Re-focus and restore the caret: a full repaint replaces the input, and\n // typing into a box that loses focus on every keystroke is unusable.\n const next = host.querySelector('[data-finding-search]');\n if (next) {\n next.focus();\n next.setSelectionRange(caret, caret);\n }\n return;\n }\n if (event.target.matches('[data-ai-question]')) {\n state.analysis.ai.question = event.target.value;\n }\n });\n\n host.addEventListener('keydown', (event) => {\n if (event.key === 'Enter' && event.target.matches('[data-ai-question]')) {\n event.preventDefault();\n explainWithAI(event.target.value);\n }\n });\n\n // The Configure forms. `change` — not `input` — so a repaint never fights a\n // half-typed number; the store keeps the values and the next run picks them\n // up. No repaint on change either: the control itself already shows the new\n // value, and redrawing would close the <details> the person just opened.\n host.addEventListener('change', (event) => {\n const control = event.target.closest('[data-opt]');\n if (!control) return;\n const { engine, key } = control.dataset;\n const slot = state.tools.options[engine] || (state.tools.options[engine] = {});\n if (control.type === 'checkbox') {\n if (control.dataset.optValue) {\n // one value of a multi-select\n const list = Array.isArray(slot[key]) ? [...slot[key]] : [];\n const at = list.indexOf(control.dataset.optValue);\n if (control.checked && at === -1) list.push(control.dataset.optValue);\n if (!control.checked && at !== -1) list.splice(at, 1);\n slot[key] = list;\n } else {\n slot[key] = control.checked;\n }\n } else if (control.type === 'number') {\n slot[key] = control.value === '' ? undefined : Number(control.value);\n } else {\n slot[key] = control.value;\n }\n });\n\n // A run started from the inspector panel repaints this view too.\n subscribeAnalysis(() => {\n if (state.view === 'analysis') renderDeepAnalysis(host, state);\n });\n}\n\nasync function doRun(options) {\n const report = await runDeepAnalysis(options);\n hooks.onToast(runOutcomeMessage(report));\n}\n\n// ---- the AI pass ------------------------------------------------------------\n\n// Explains the report, or answers `question` about it. Streams into\n// `state.analysis.ai.text` and repaints the note in place — a full page repaint\n// mid-stream would throw away every character already received.\nasync function explainWithAI(question) {\n const ai = state.analysis.ai;\n if (ai.running) return;\n\n if (!llm.isConfigured()) {\n hooks.onOpenSettings();\n hooks.onToast('Choose Hermes or an endpoint in AI connection — the report is still readable without one.');\n return;\n }\n\n const rows = findingsFromSecurity(state.security);\n const counts = tabulate(rows);\n const engines = engineRows(state.tools.status, state.tools.report);\n const messages = llm.analysisMessages({\n repoName: state.scan.name,\n grade: state.security?.grade,\n score: state.security?.score,\n counts,\n engines,\n findings: rows,\n question: (question || '').trim(),\n });\n\n const settings = llm.getSettings();\n ai.running = true;\n ai.text = '';\n ai.error = '';\n paintAI();\n\n try {\n const providerOptions = llm.isAzureHost(settings.baseUrl) ? {} : { reasoning: { exclude: true } };\n for await (const delta of streamExplain({ ...settings, messages, maxTokens: 900, providerOptions })) {\n ai.text += delta;\n paintAI();\n }\n } catch (err) {\n ai.error = err.message;\n } finally {\n ai.running = false;\n paintAI();\n }\n}\n\n// Repaint just the AI note, so streaming never fights the rest of the page.\nfunction paintAI() {\n if (!host) return;\n const note = host.querySelector('[data-ai-note]');\n if (!note) return;\n const ai = state.analysis.ai;\n note.innerHTML = renderAINote(ai);\n}\n\n// ---- painting ---------------------------------------------------------------\n\nexport function renderDeepAnalysis(container, appState = state) {\n if (!container) return;\n host = container;\n const { analysis } = appState;\n\n // A browser-picked folder has no server-side root, so there is nothing for an\n // engine to read. Say that once, plainly, rather than showing an empty table\n // that looks like a clean bill of health.\n if (!appState.scanId) {\n container.innerHTML = `<div class=\"analysis-layout\">\n <header class=\"analysis-head\">\n <h1 class=\"analysis-title\">Deep analysis</h1>\n <p class=\"analysis-sub\">External engines — Semgrep, Gitleaks, Knip, Vulture, Depcheck.</p>\n </header>\n <div class=\"analysis-empty\">This repo was picked in the browser, so its files never reached the server. An external engine needs a directory on the server to read, so deep analysis is available for folders scanned by path and for git clones. The built-in scan — every finding on the <b>Security</b> tab — still applies.</div>\n </div>`;\n return;\n }\n\n const engines = engineRows(appState.tools.status, appState.tools.report);\n const all = findingsFromSecurity(appState.security);\n const counts = tabulate(all);\n const visible = filterFindings(all, analysis);\n const summary = engineSummary(appState.tools.report, engines);\n const running = appState.tools.running;\n\n container.innerHTML = `<div class=\"analysis-layout\">\n ${renderHead(counts, running)}\n ${renderEngineBlock(engines, summary, running, appState.tools)}\n ${renderAIBlock()}\n ${renderFindingsBlock(visible, counts, analysis)}\n </div>`;\n\n // The engines panel may still be loading; ask once and let the store notify.\n if (!appState.tools.status && !appState.tools.loading) void ensureToolsStatus();\n}\n\nfunction renderHead(counts, running) {\n const chip = (label, value, cls = '') => `<span class=\"analysis-chip ${cls}\"><b>${value}</b> ${label}</span>`;\n return `<header class=\"analysis-head\">\n <div class=\"analysis-head-text\">\n <h1 class=\"analysis-title\">Deep analysis</h1>\n <p class=\"analysis-sub\">Every engine this machine has, plus the built-in scanner — merged into one list. Click any file to open it at the line.</p>\n </div>\n <div class=\"analysis-actions\">\n <button class=\"btn btn-ink\" data-run-all ${running ? 'disabled' : ''}>${running ? 'Running…' : 'Run all engines'}</button>\n <button class=\"btn btn-ghost\" data-run-kind=\"security\" ${running ? 'disabled' : ''}>Security only</button>\n <button class=\"btn btn-ghost\" data-run-kind=\"dead-code\" ${running ? 'disabled' : ''}>Dead code only</button>\n </div>\n </header>\n <div class=\"analysis-stats\">\n ${chip('findings', counts.total)}\n ${counts.critical ? chip('critical', counts.critical, 'is-critical') : ''}\n ${counts.high ? chip('high', counts.high, 'is-high') : ''}\n ${chip('from engines', counts.external, counts.external ? 'is-external' : '')}\n ${chip('from built-in', counts.builtin)}\n </div>`;\n}\n\nfunction renderEngineBlock(engines, summary, running, tools) {\n const rows = engines.length ? engines.map((e) => renderEngineRow(e, running)).join('') : '';\n const empty = tools.loading\n ? '<div class=\"analysis-empty\">Checking which engines are installed…</div>'\n : (engines.length ? '' : '<div class=\"analysis-empty\">No engine table — the server did not answer.</div>');\n\n return `<section class=\"analysis-block\">\n <h2 class=\"analysis-h\">Engines <span class=\"analysis-h-sub\">what this machine can run</span></h2>\n <div class=\"analysis-engines\">${rows}${empty}</div>\n <div class=\"analysis-verdict is-${escapeHtml(summary.tone)}\">${escapeHtml(summary.text)}</div>\n </section>`;\n}\n\nfunction renderEngineRow(engine, running) {\n const installing = state.tools.install[engine.id];\n let badge;\n if (installing && installing.running) badge = '<span class=\"tools-badge is-running\">installing…</span>';\n else if (!engine.available) badge = '<span class=\"tools-badge is-missing\">not installed</span>';\n else if (running) badge = '<span class=\"tools-badge is-running\">running…</span>';\n else if (engine.ran) badge = `<span class=\"tools-badge is-ran\">${engine.findings} · ${engine.ms}ms</span>`;\n else if (engine.failed) badge = '<span class=\"tools-badge is-failed\">failed</span>';\n else badge = `<span class=\"tools-badge is-ready\">ready${engine.how ? ' · ' + escapeHtml(engine.how) : ''}</span>`;\n\n const note = !engine.available && engine.reason\n ? `<span class=\"tools-reason\">${escapeHtml(engine.reason)}</span>`\n : (engine.failure ? `<span class=\"tools-reason\">${escapeHtml(engine.failure)}</span>` : '');\n\n const runBtn = engine.available\n ? `<button class=\"btn btn-ghost btn-sm\" data-engine-run=\"${escapeHtml(engine.id)}\" ${running ? 'disabled' : ''}>Run</button>`\n : '';\n const installBtn = !engine.available && engine.installable\n ? `<button class=\"btn btn-ink btn-sm\" data-engine-install=\"${escapeHtml(engine.id)}\" ${installing && installing.running ? 'disabled' : ''}>${installing && installing.running ? 'Installing…' : 'Install'}</button>`\n : '';\n\n return `<div class=\"analysis-engine${engine.available ? '' : ' is-missing'}\">\n <div class=\"analysis-engine-top\">\n <span class=\"tools-name\">${escapeHtml(engine.label)}</span>\n ${badge}\n <span class=\"analysis-engine-kind\">${escapeHtml(engine.kind)}</span>\n ${installBtn}\n ${runBtn}\n </div>\n <div class=\"tools-purpose\">${escapeHtml(engine.purpose)}</div>\n ${note}\n ${renderEngineOptions(engine)}\n ${renderInstallConsole(installing)}\n </div>`;\n}\n\n// The Configure panel: a <details> with one control per schema entry, so the\n// useful surface of each engine — semgrep's rule sets, gitleaks' history\n// scan, vulture's confidence floor — is a form, not a command line. Values\n// live in `state.tools.options` and ride along with the next run; the server\n// validates them against the same schema before they touch an argv.\nfunction renderEngineOptions(engine) {\n if (!engine.options.length) return '';\n const values = state.tools.options[engine.id] || {};\n\n const field = (opt) => {\n const current = values[opt.key] !== undefined ? values[opt.key] : engine.defaults[opt.key];\n let control;\n if (opt.type === 'boolean') {\n control = `<label class=\"analysis-opt-check\">\n <input type=\"checkbox\" data-opt data-engine=\"${escapeHtml(engine.id)}\" data-key=\"${escapeHtml(opt.key)}\" ${current ? 'checked' : ''}>\n <span>${escapeHtml(opt.label)}</span>\n </label>`;\n } else if (opt.type === 'enum') {\n const options = opt.values.map((v) =>\n `<option value=\"${escapeHtml(v)}\" ${v === current ? 'selected' : ''}>${escapeHtml(v)}</option>`).join('');\n control = `<label class=\"analysis-opt-field\"><span>${escapeHtml(opt.label)}</span>\n <select class=\"text-input\" data-opt data-engine=\"${escapeHtml(engine.id)}\" data-key=\"${escapeHtml(opt.key)}\">${options}</select>\n </label>`;\n } else if (opt.type === 'multi') {\n const chosen = Array.isArray(current) ? current : [];\n control = `<div class=\"analysis-opt-field\"><span>${escapeHtml(opt.label)}</span>\n <div class=\"analysis-opt-multi\">${opt.values.map((v) => `\n <label class=\"analysis-opt-check\">\n <input type=\"checkbox\" data-opt data-engine=\"${escapeHtml(engine.id)}\" data-key=\"${escapeHtml(opt.key)}\"\n data-opt-value=\"${escapeHtml(v)}\" ${chosen.includes(v) ? 'checked' : ''}>\n <span>${escapeHtml(v)}</span>\n </label>`).join('')}\n </div>\n </div>`;\n } else { // number\n control = `<label class=\"analysis-opt-field\"><span>${escapeHtml(opt.label)}</span>\n <input type=\"number\" class=\"text-input\" data-opt data-engine=\"${escapeHtml(engine.id)}\" data-key=\"${escapeHtml(opt.key)}\"\n min=\"${opt.min}\" max=\"${opt.max}\" value=\"${escapeHtml(String(current ?? opt.default))}\">\n </label>`;\n }\n const hint = opt.hint ? `<span class=\"analysis-opt-hint\">${escapeHtml(opt.hint)}</span>` : '';\n return `<div class=\"analysis-opt\">${control}${hint}</div>`;\n };\n\n return `<details class=\"analysis-config\">\n <summary>Configure</summary>\n <div class=\"analysis-config-body\">${engine.options.map(field).join('')}</div>\n </details>`;\n}\n\n// The install log, live while an install runs and kept afterwards so a failed\n// install leaves its reason on screen instead of in a toast that faded.\nfunction renderInstallConsole(installing) {\n if (!installing || (!installing.log.length && !installing.running && !installing.error)) return '';\n const verdict = installing.running\n ? ''\n : installing.ok\n ? '<div class=\"analysis-console-verdict is-ok\">Installed — the engine is ready.</div>'\n : `<div class=\"analysis-console-verdict is-err\">${escapeHtml(installing.error || 'The install failed.')}</div>`;\n return `<div class=\"analysis-console-wrap\">\n <pre class=\"analysis-console\">${escapeHtml(installing.log.join('\\n'))}${installing.running ? ' ▍' : ''}</pre>\n ${verdict}\n </div>`;\n}\n\n\nfunction renderAIBlock() {\n const configured = llm.isConfigured();\n const ask = escapeHtml(state.analysis.ai.question || '');\n const settingsBtn = configured\n ? ''\n : '<button class=\"btn btn-ghost btn-sm\" data-open-settings>AI connection…</button>';\n return `<section class=\"analysis-block\">\n <h2 class=\"analysis-h\">What this means <span class=\"analysis-h-sub\">ask the AI</span></h2>\n <div class=\"analysis-ai\">\n <div class=\"analysis-ai-bar\">\n <button class=\"btn btn-ink btn-sm\" data-ai-explain>${configured ? 'Explain this analysis' : 'Explain (needs an endpoint)'}</button>\n ${settingsBtn}\n <span class=\"analysis-ai-hint\">Uses the report above — engines, severities, files. Nothing is sent anywhere but your own endpoint.</span>\n </div>\n <div class=\"analysis-ai-note\" data-ai-note>${renderAINote(state.analysis.ai)}</div>\n <div class=\"analysis-ai-ask\">\n <input type=\"text\" class=\"text-input\" data-ai-question placeholder=\"Ask about this report — e.g. “is the eval finding reachable?”\" value=\"${ask}\" spellcheck=\"false\" autocomplete=\"off\">\n <button class=\"btn btn-ghost btn-sm\" data-ai-explain>Ask</button>\n </div>\n </div>\n </section>`;\n}\n\n// The note is plain text from the model. It goes through `mdInline`, the same\n// boundary helper the inspector uses: escape first, then bold and inline code.\n// The prompt asks for prose, but models reach for `**bold**` and backticks\n// anyway, and half-rendered asterisks look like a bug.\nexport function renderAINote(ai) {\n if (ai.running && !ai.text) {\n return '<span class=\"analysis-ai-waiting\"><span class=\"search-spinner\"></span> Reading the report…</span>';\n }\n if (ai.error) return `<span class=\"analysis-ai-error\">${escapeHtml(ai.error)}</span>`;\n if (!ai.text) {\n return '<span class=\"analysis-ai-idle\">Press <b>Explain this analysis</b> for a prioritised read of the findings above, or ask a question about any of them.</span>';\n }\n const html = ai.text\n .split(/\\n{2,}/)\n .map((para) => `<p>${mdInline(para).replace(/\\n/g, '<br>')}</p>`)\n .join('');\n const cursor = ai.running ? '<span class=\"analysis-ai-cursor\">▍</span>' : '';\n return html + cursor;\n}\n\nfunction renderFindingsBlock(visible, counts, analysis) {\n const sevChips = ['all', ...SEV_ORDER].map((sev) => {\n const n = sev === 'all' ? counts.total : (counts.bySeverity[sev] || 0);\n if (sev !== 'all' && !n) return '';\n const active = analysis.severity === sev ? ' is-active' : '';\n return `<button class=\"btn btn-ghost btn-sm${active}\" data-sev=\"${sev}\">${sev} (${n})</button>`;\n }).join('');\n\n const tools = Object.keys(counts.byTool).sort((a, b) => counts.byTool[b] - counts.byTool[a]);\n const toolChips = tools.length > 1\n ? ['all', ...tools].map((tool) => {\n const n = tool === 'all' ? counts.total : counts.byTool[tool];\n const label = tool === BUILTIN_TOOL ? 'built-in scanner' : tool;\n const active = analysis.tool === tool ? ' is-active' : '';\n return `<button class=\"btn btn-ghost btn-sm${active}\" data-tool-filter=\"${escapeHtml(tool)}\">${escapeHtml(label)} (${n})</button>`;\n }).join('')\n : '';\n\n const body = visible.length\n ? visible.map(renderFindingRow).join('')\n : `<tr><td colspan=\"5\" class=\"analysis-no-rows\">Nothing matches those filters.</td></tr>`;\n\n return `<section class=\"analysis-block\">\n <h2 class=\"analysis-h\">Findings <span class=\"analysis-h-sub\">${visible.length} of ${counts.total} shown</span></h2>\n <div class=\"analysis-filterbar\">\n <div class=\"analysis-filter-group\">${sevChips}</div>\n ${toolChips ? `<div class=\"analysis-filter-group\">${toolChips}</div>` : ''}\n <input type=\"text\" class=\"text-input analysis-search\" data-finding-search\n placeholder=\"Filter by file, rule or message…\" value=\"${escapeHtml(analysis.q || '')}\" spellcheck=\"false\">\n </div>\n <div class=\"analysis-table-wrap\">\n <table class=\"analysis-table\">\n <thead><tr>\n <th class=\"col-sev\">Severity</th>\n <th class=\"col-file\">File</th>\n <th class=\"col-rule\">Rule</th>\n <th class=\"col-tool\">Engine</th>\n <th>Finding</th>\n </tr></thead>\n <tbody>${body}</tbody>\n </table>\n </div>\n </section>`;\n}\n\n// One finding. The file cell is the point of the whole view: it carries the\n// path, the line, and the click that opens the Code tab there.\nfunction renderFindingRow(row) {\n return `<tr class=\"analysis-row is-${escapeHtml(row.severity)}\">\n <td class=\"col-sev\"><span class=\"sev-pill is-${escapeHtml(row.severity)}\">${escapeHtml(row.severity)}</span></td>\n <td class=\"col-file\">\n <button class=\"analysis-file\" data-goto=\"${escapeHtml(row.path)}\" data-goto-line=\"${row.line}\"\n title=\"Open ${escapeHtml(row.path)} at line ${row.line}\">\n <span class=\"analysis-file-name\">${escapeHtml(row.name)}</span>\n <span class=\"analysis-file-line\">L${row.line}</span>\n </button>\n <span class=\"analysis-file-dir\">${escapeHtml(dirOf(row.path))}</span>\n </td>\n <td class=\"col-rule\"><code>${escapeHtml(row.rule)}</code></td>\n <td class=\"col-tool\"><span class=\"analysis-tool is-${escapeHtml(row.tool === BUILTIN_TOOL ? 'builtin' : 'external')}\">${escapeHtml(row.tool === BUILTIN_TOOL ? 'built-in' : row.tool)}</span></td>\n <td class=\"analysis-msg\">${escapeHtml(row.message)}</td>\n </tr>`;\n}\n\nfunction dirOf(path) {\n const at = String(path || '').lastIndexOf('/');\n return at === -1 ? '' : path.slice(0, at);\n}\n\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare function renderInto(contentEl: any, source: any): Promise<any>;
|
|
2
|
+
export declare function validateDiagram(source: string): Promise<void>;
|
|
2
3
|
export declare function wireNodeClicks(contentEl: any, nodes: any, onClick: any): void;
|
|
3
4
|
export declare function makePanzoom(canvas: any, content: any): {
|
|
4
5
|
fit: () => void;
|
package/public/js/diagramPane.js
CHANGED
|
@@ -31,6 +31,11 @@ export async function renderInto(contentEl, source) {
|
|
|
31
31
|
}
|
|
32
32
|
return el;
|
|
33
33
|
}
|
|
34
|
+
export async function validateDiagram(source) {
|
|
35
|
+
ensureMermaid();
|
|
36
|
+
if (!await window.mermaid.parse(source))
|
|
37
|
+
throw new Error('The diagram could not be parsed.');
|
|
38
|
+
}
|
|
34
39
|
// Mermaid gives every node a DOM id like "flowchart-f3-87"; the middle part
|
|
35
40
|
// is the id our diagram builders assigned, and `nodes` maps it back to a
|
|
36
41
|
// file or folder payload.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagramPane.js","sourceRoot":"","sources":["../../src/public/js/diagramPane.ts"],"names":[],"mappings":"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","sourcesContent":["// Mermaid rendering plus the canvas furniture: click wiring, pan & zoom,\n// fit-to-view, SVG export. Mermaid comes from the vendored UMD build and\n// stays a global; everything interactive happens here.\n\nlet initialized = false;\nlet renderSeq = 0;\n\nfunction ensureMermaid() {\n if (initialized) return;\n window.mermaid.initialize({\n startOnLoad: false,\n securityLevel: 'loose', // labels are escaped upstream; local tool, local data\n flowchart: { htmlLabels: false },\n });\n initialized = true;\n}\n\nexport async function renderInto(contentEl, source) {\n ensureMermaid();\n const { svg } = await window.mermaid.render('obd' + ++renderSeq, source);\n contentEl.innerHTML = svg;\n const el = contentEl.querySelector('svg');\n // Mermaid emits `max-width` + fluid sizing, so the CSS box rarely matches\n // the viewBox units — and our pan/zoom math assumes 1 unit = 1 px. Pin the\n // box to the viewBox, or fit() sizes and centers against a phantom.\n if (el && el.viewBox && el.viewBox.baseVal && el.viewBox.baseVal.width) {\n const vb = el.viewBox.baseVal;\n el.setAttribute('width', String(vb.width));\n el.setAttribute('height', String(vb.height));\n el.style.maxWidth = 'none';\n el.style.width = `${vb.width}px`;\n el.style.height = `${vb.height}px`;\n }\n return el;\n}\n\n// Mermaid gives every node a DOM id like \"flowchart-f3-87\"; the middle part\n// is the id our diagram builders assigned, and `nodes` maps it back to a\n// file or folder payload.\nexport function wireNodeClicks(contentEl, nodes, onClick) {\n for (const g of contentEl.querySelectorAll('g.node')) {\n const m = (g.id || '').match(/^flowchart-([A-Za-z0-9]+)-\\d+$/);\n if (!m || !nodes[m[1]]) continue;\n g.style.cursor = 'pointer';\n g.addEventListener('click', (event) => {\n event.stopPropagation();\n onClick(nodes[m[1]]);\n });\n }\n}\n\nexport function makePanzoom(canvas, content) {\n let scale = 1;\n let tx = 0;\n let ty = 0;\n let dragging = false;\n let lastX = 0;\n let lastY = 0;\n\n const apply = () => {\n content.style.transform = `translate(${tx}px, ${ty}px) scale(${scale})`;\n };\n\n canvas.addEventListener('pointerdown', (event) => {\n if (content.classList.contains('atlas-mode')) return; // the atlas list takes its own clicks\n dragging = true;\n lastX = event.clientX;\n lastY = event.clientY;\n canvas.classList.add('is-dragging');\n canvas.setPointerCapture(event.pointerId);\n });\n canvas.addEventListener('pointermove', (event) => {\n if (!dragging) return;\n tx += event.clientX - lastX;\n ty += event.clientY - lastY;\n lastX = event.clientX;\n lastY = event.clientY;\n apply();\n });\n const stop = () => {\n dragging = false;\n canvas.classList.remove('is-dragging');\n };\n canvas.addEventListener('pointerup', stop);\n canvas.addEventListener('pointercancel', stop);\n\n canvas.addEventListener('wheel', (event) => {\n if (content.classList.contains('atlas-mode')) return; // the atlas list scrolls\n event.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const cx = event.clientX - rect.left;\n const cy = event.clientY - rect.top;\n const factor = event.deltaY < 0 ? 1.12 : 1 / 1.12;\n const next = Math.min(4, Math.max(0.12, scale * factor));\n tx = cx - ((cx - tx) * next) / scale;\n ty = cy - ((cy - ty) * next) / scale;\n scale = next;\n apply();\n }, { passive: false });\n\n canvas.addEventListener('dblclick', () => fit());\n\n function fit() {\n const first = content.firstElementChild;\n if (!first) return;\n let w = 0;\n let h = 0;\n if (first instanceof SVGElement) {\n try {\n const box = (first as SVGGraphicsElement).getBBox();\n w = box.width;\n h = box.height;\n } catch {\n return;\n }\n } else {\n // HTML content (the tree map): offset sizes ignore the transform.\n w = first.offsetWidth;\n h = first.offsetHeight;\n }\n if (!w || !h) return;\n const cw = canvas.clientWidth - 48;\n const ch = canvas.clientHeight - 48;\n scale = Math.min(cw / w, ch / h, 1.15);\n tx = (canvas.clientWidth - w * scale) / 2;\n ty = (canvas.clientHeight - h * scale) / 2;\n apply();\n }\n\n // Back to the un-zoomed, un-panned resting position (the atlas list wants\n // this — it is a document, not a diagram).\n function home() {\n scale = 1;\n tx = 0;\n ty = 0;\n apply();\n }\n\n return { fit, reset: fit, home };\n}\n\nexport function downloadSvg(contentEl, name) {\n const svg = contentEl.querySelector('svg');\n if (!svg) return false;\n const clone = svg.cloneNode(true);\n clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n const blob = new Blob(['<?xml version=\"1.0\"?>\\n' + clone.outerHTML], { type: 'image/svg+xml' });\n const a = document.createElement('a');\n a.href = URL.createObjectURL(blob);\n a.download = name;\n a.click();\n URL.revokeObjectURL(a.href);\n return true;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"diagramPane.js","sourceRoot":"","sources":["../../src/public/js/diagramPane.ts"],"names":[],"mappings":"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","sourcesContent":["// Mermaid rendering plus the canvas furniture: click wiring, pan & zoom,\n// fit-to-view, SVG export. Mermaid comes from the vendored UMD build and\n// stays a global; everything interactive happens here.\n\nlet initialized = false;\nlet renderSeq = 0;\n\nfunction ensureMermaid() {\n if (initialized) return;\n window.mermaid.initialize({\n startOnLoad: false,\n securityLevel: 'loose', // labels are escaped upstream; local tool, local data\n flowchart: { htmlLabels: false },\n });\n initialized = true;\n}\n\nexport async function renderInto(contentEl, source) {\n ensureMermaid();\n const { svg } = await window.mermaid.render('obd' + ++renderSeq, source);\n contentEl.innerHTML = svg;\n const el = contentEl.querySelector('svg');\n // Mermaid emits `max-width` + fluid sizing, so the CSS box rarely matches\n // the viewBox units — and our pan/zoom math assumes 1 unit = 1 px. Pin the\n // box to the viewBox, or fit() sizes and centers against a phantom.\n if (el && el.viewBox && el.viewBox.baseVal && el.viewBox.baseVal.width) {\n const vb = el.viewBox.baseVal;\n el.setAttribute('width', String(vb.width));\n el.setAttribute('height', String(vb.height));\n el.style.maxWidth = 'none';\n el.style.width = `${vb.width}px`;\n el.style.height = `${vb.height}px`;\n }\n return el;\n}\n\nexport async function validateDiagram(source: string): Promise<void> {\n ensureMermaid();\n if (!await window.mermaid.parse(source)) throw new Error('The diagram could not be parsed.');\n}\n\n// Mermaid gives every node a DOM id like \"flowchart-f3-87\"; the middle part\n// is the id our diagram builders assigned, and `nodes` maps it back to a\n// file or folder payload.\nexport function wireNodeClicks(contentEl, nodes, onClick) {\n for (const g of contentEl.querySelectorAll('g.node')) {\n const m = (g.id || '').match(/^flowchart-([A-Za-z0-9]+)-\\d+$/);\n if (!m || !nodes[m[1]]) continue;\n g.style.cursor = 'pointer';\n g.addEventListener('click', (event) => {\n event.stopPropagation();\n onClick(nodes[m[1]]);\n });\n }\n}\n\nexport function makePanzoom(canvas, content) {\n let scale = 1;\n let tx = 0;\n let ty = 0;\n let dragging = false;\n let lastX = 0;\n let lastY = 0;\n\n const apply = () => {\n content.style.transform = `translate(${tx}px, ${ty}px) scale(${scale})`;\n };\n\n canvas.addEventListener('pointerdown', (event) => {\n if (content.classList.contains('atlas-mode')) return; // the atlas list takes its own clicks\n dragging = true;\n lastX = event.clientX;\n lastY = event.clientY;\n canvas.classList.add('is-dragging');\n canvas.setPointerCapture(event.pointerId);\n });\n canvas.addEventListener('pointermove', (event) => {\n if (!dragging) return;\n tx += event.clientX - lastX;\n ty += event.clientY - lastY;\n lastX = event.clientX;\n lastY = event.clientY;\n apply();\n });\n const stop = () => {\n dragging = false;\n canvas.classList.remove('is-dragging');\n };\n canvas.addEventListener('pointerup', stop);\n canvas.addEventListener('pointercancel', stop);\n\n canvas.addEventListener('wheel', (event) => {\n if (content.classList.contains('atlas-mode')) return; // the atlas list scrolls\n event.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const cx = event.clientX - rect.left;\n const cy = event.clientY - rect.top;\n const factor = event.deltaY < 0 ? 1.12 : 1 / 1.12;\n const next = Math.min(4, Math.max(0.12, scale * factor));\n tx = cx - ((cx - tx) * next) / scale;\n ty = cy - ((cy - ty) * next) / scale;\n scale = next;\n apply();\n }, { passive: false });\n\n canvas.addEventListener('dblclick', () => fit());\n\n function fit() {\n const first = content.firstElementChild;\n if (!first) return;\n let w = 0;\n let h = 0;\n if (first instanceof SVGElement) {\n try {\n const box = (first as SVGGraphicsElement).getBBox();\n w = box.width;\n h = box.height;\n } catch {\n return;\n }\n } else {\n // HTML content (the tree map): offset sizes ignore the transform.\n w = first.offsetWidth;\n h = first.offsetHeight;\n }\n if (!w || !h) return;\n const cw = canvas.clientWidth - 48;\n const ch = canvas.clientHeight - 48;\n scale = Math.min(cw / w, ch / h, 1.15);\n tx = (canvas.clientWidth - w * scale) / 2;\n ty = (canvas.clientHeight - h * scale) / 2;\n apply();\n }\n\n // Back to the un-zoomed, un-panned resting position (the atlas list wants\n // this — it is a document, not a diagram).\n function home() {\n scale = 1;\n tx = 0;\n ty = 0;\n apply();\n }\n\n return { fit, reset: fit, home };\n}\n\nexport function downloadSvg(contentEl, name) {\n const svg = contentEl.querySelector('svg');\n if (!svg) return false;\n const clone = svg.cloneNode(true);\n clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n const blob = new Blob(['<?xml version=\"1.0\"?>\\n' + clone.outerHTML], { type: 'image/svg+xml' });\n const a = document.createElement('a');\n a.href = URL.createObjectURL(blob);\n a.download = name;\n a.click();\n URL.revokeObjectURL(a.href);\n return true;\n}\n"]}
|
package/public/js/docsView.js
CHANGED
|
@@ -193,7 +193,7 @@ async function askAboutRepo() {
|
|
|
193
193
|
return hooks.onToast('Type a question first.');
|
|
194
194
|
if (!llm.isConfigured()) {
|
|
195
195
|
hooks.onOpenSettings();
|
|
196
|
-
hooks.onToast('
|
|
196
|
+
hooks.onToast('Choose Hermes or an endpoint in AI connection first.');
|
|
197
197
|
return;
|
|
198
198
|
}
|
|
199
199
|
input.value = '';
|
|
@@ -239,11 +239,11 @@ async function askAboutRepo() {
|
|
|
239
239
|
card.querySelector('.doc-qa-a').innerHTML = mdLite(text) + '<span class="caret"></span>';
|
|
240
240
|
}
|
|
241
241
|
card.querySelector('.doc-qa-a').innerHTML =
|
|
242
|
-
mdLite(text) + `<p class="explain-src">Answered by ${settings.model}, looking at ${escapeHtml(scope)}.</p>`;
|
|
242
|
+
mdLite(text) + `<p class="explain-src">Answered by ${escapeHtml(settings.model)}, looking at ${escapeHtml(scope)}.</p>`;
|
|
243
243
|
}
|
|
244
244
|
catch (err) {
|
|
245
245
|
card.querySelector('.doc-qa-a').innerHTML =
|
|
246
|
-
`<p style="color:var(--warn)">${escapeHtml(err.message)} — check the
|
|
246
|
+
`<p style="color:var(--warn)">${escapeHtml(err.message)} — check the AI connection drawer, top right.</p>`;
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
// ---- doc tabs: detailed AI documents per file/folder -----------------------
|
|
@@ -380,7 +380,7 @@ function scheduleDocPaneRefresh(entry) {
|
|
|
380
380
|
async function generateDocTab(entry) {
|
|
381
381
|
if (!llm.isConfigured()) {
|
|
382
382
|
entry.status = 'error';
|
|
383
|
-
entry.error = 'No
|
|
383
|
+
entry.error = 'No AI connection configured — open the AI connection drawer, top right.';
|
|
384
384
|
showActiveDoc();
|
|
385
385
|
renderDocStrip();
|
|
386
386
|
hooks.onOpenSettings();
|
|
@@ -453,7 +453,7 @@ async function writeDocsWithAI() {
|
|
|
453
453
|
return;
|
|
454
454
|
if (!llm.isConfigured()) {
|
|
455
455
|
hooks.onOpenSettings();
|
|
456
|
-
hooks.onToast('
|
|
456
|
+
hooks.onToast('Choose Hermes or an endpoint in AI connection first.');
|
|
457
457
|
return;
|
|
458
458
|
}
|
|
459
459
|
const settings = llm.getSettings();
|
|
@@ -544,7 +544,7 @@ async function writeDocsWithAI() {
|
|
|
544
544
|
}
|
|
545
545
|
}
|
|
546
546
|
if (note)
|
|
547
|
-
note.textContent = `Written by ${settings.model} from the real import graph. Press “Regenerate documentation” for a fresh take.`;
|
|
547
|
+
note.textContent = `Written by ${escapeHtml(settings.model)} from the real import graph. Press “Regenerate documentation” for a fresh take.`;
|
|
548
548
|
if (btn)
|
|
549
549
|
btn.textContent = 'Regenerate documentation';
|
|
550
550
|
}
|