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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/cli/chat/models.ts"],"names":[],"mappings":"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","sourcesContent":["import { agentHome, hermesBinary, hermesEnvironment, setupAgent } from '../agent/config.js';\nimport { runProcess, terminalText } from '../agent/process.js';\n\nexport interface ModelProvider { id: string; name: string; models: string[] }\n// Use the installed Hermes catalog, credential resolver and persistence logic.\n// Only display fields cross this boundary; keys and endpoint credentials stay in Python.\nconst BRIDGE = String.raw`\nimport contextlib, io, json, sys\nrequest = json.load(sys.stdin)\nwith contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):\n from hermes_cli.config import load_config\n from hermes_cli.model_switch import switch_model, persist_model_selection\n from hermes_cli.model_switch_providers import list_picker_providers\n config = load_config()\n model = config.get('model') or {}\n if not isinstance(model, dict): model = {'default': str(model)}\n if request['action'] == 'catalog':\n import inspect\n kwargs = dict(current_provider=model.get('provider') or '', current_model=model.get('default') or '',\n current_base_url=model.get('base_url') or '', user_providers=config.get('providers'),\n custom_providers=config.get('custom_providers'), max_models=None, non_blocking_catalogs=True,\n probe_custom_providers=False, probe_current_custom_provider=False,\n excluded_providers=(config.get('model_catalog') or {}).get('excluded_providers'))\n accepted = inspect.signature(list_picker_providers).parameters\n rows = list_picker_providers(**{k: v for k, v in kwargs.items() if k in accepted})\n reply = {'providers': [{'id': str(p.get('slug') or ''), 'name': str(p.get('name') or p.get('slug') or ''),\n 'models': [m for m in p.get('models', []) if isinstance(m, str)]} for p in rows]}\n else:\n result = switch_model(request['model'], current_provider=model.get('provider') or '',\n current_model=model.get('default') or '', current_base_url=model.get('base_url') or '',\n current_api_key=model.get('api_key') or '', explicit_provider=request['provider'],\n user_providers=config.get('providers'), custom_providers=config.get('custom_providers'))\n if result.success: persist_model_selection(result)\n reply = {'success': bool(result.success), 'model': result.new_model if result.success else '',\n 'provider': result.target_provider if result.success else '',\n 'error': '' if result.success else 'Hermes could not activate this model. Configure its provider with /model configure.'}\nprint('ONBOARDER_MODEL_JSON:' + json.dumps(reply))\n`;\n\nexport class HermesModels {\n constructor(private home = agentHome(), private env: NodeJS.ProcessEnv = process.env, private execute = runProcess) {}\n private async request(request: Record<string, string>, signal: AbortSignal): Promise<any> {\n await setupAgent(this.home, this.env);\n const env = hermesEnvironment(this.home, this.env);\n // Hermes publishes its installation-bound Python/bootstrap argv. Retain that\n // bootstrap and replace only the verified entry point with our fixed bridge.\n const launch = await this.execute(hermesBinary(this.env), ['--print-runtime-command'], { env, signal, timeoutMs: 10000, maxBytes: 64000 });\n let command: unknown;\n try { command = JSON.parse(launch.stdout.trim()); } catch { throw new Error('Use /model configure with this Hermes installation.'); }\n if (launch.code || !Array.isArray(command) || command.length !== 4 || command.some(v => typeof v !== 'string') || command[1] !== '-I' || command[2] !== '-c') throw new Error('This Hermes launcher needs /model configure.');\n const entry = /runpy\\.run_module\\(['\"]hermes_cli\\.main['\"],\\s*run_name=['\"]__main__['\"],\\s*alter_sys=True\\)\\s*$/.exec(command[3]);\n if (!entry || !command[3].slice(0, entry.index).includes('import hermes_bootstrap;')) throw new Error('This Hermes launcher needs /model configure.');\n const bootstrap = command[3].slice(0, entry.index) + 'exec(sys.argv[1])';\n const response = await this.execute(command[0], ['-I', '-c', bootstrap, BRIDGE], { env, signal, input: JSON.stringify(request), timeoutMs: 30000, maxBytes: 2 * 1024 * 1024 });\n const line = response.stdout.split('\\n').find(s => s.startsWith('ONBOARDER_MODEL_JSON:'));\n if (response.code || !line) throw new Error('The model picker is unavailable. Choose Configure provider for the full Hermes setup.');\n return JSON.parse(line.slice('ONBOARDER_MODEL_JSON:'.length));\n }\n async catalog(signal: AbortSignal): Promise<ModelProvider[]> {\n const value = await this.request({ action: 'catalog' }, signal);\n if (!Array.isArray(value.providers)) throw new Error('Invalid Hermes model catalog.');\n return value.providers.slice(0, 200).filter((p: any) => typeof p.id === 'string' && p.id && typeof p.name === 'string' && Array.isArray(p.models))\n .map((p: any) => ({ id: terminalText(p.id).slice(0, 512), name: terminalText(p.name).slice(0, 512),\n models: [...new Set<string>(p.models.filter((m: unknown) => typeof m === 'string' && m.length > 0 && m.length <= 512).map((m: string) => terminalText(m)))].slice(0, 10000) }));\n }\n async select(model: string, provider: string, signal: AbortSignal): Promise<{ model: string; provider: string }> {\n if (!model || !provider || model.length > 512 || provider.length > 512) throw new Error('Choose a model and provider from the picker.');\n const result = await this.request({ action: 'select', model, provider }, signal);\n if (result.success !== true || typeof result.model !== 'string' || typeof result.provider !== 'string') throw new Error('Hermes could not activate this model. Use /model configure to check its credentials.');\n return { model: terminalText(result.model).slice(0, 512), provider: terminalText(result.provider).slice(0, 512) };\n }\n}\n"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { agentHome, runtimePaths } from '../agent/config.js';
|
|
4
|
+
import { terminalText } from '../agent/process.js';
|
|
5
|
+
function scalarValue(raw) {
|
|
6
|
+
raw = raw?.trim();
|
|
7
|
+
if (!raw || /^[!&*{\[]/.test(raw) || /^(?:null|~)$/i.test(raw))
|
|
8
|
+
return undefined;
|
|
9
|
+
if (raw.startsWith('"')) {
|
|
10
|
+
try {
|
|
11
|
+
const value = JSON.parse(raw);
|
|
12
|
+
return typeof value === 'string' ? value : undefined;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (raw.startsWith("'"))
|
|
19
|
+
return /^'([^']*(?:''[^']*)*)'\s*(?:#.*)?$/.exec(raw)?.[1]?.replace(/''/g, "'");
|
|
20
|
+
return raw.replace(/\s+#.*$/, '');
|
|
21
|
+
}
|
|
22
|
+
/** Hermes round-trip writes can retain a JSON-origin YAML flow mapping. */
|
|
23
|
+
function flowModel(source) {
|
|
24
|
+
const start = /(?:^|[{,\n])\s*(?:model|"model"|'model')\s*:\s*\{/m.exec(source);
|
|
25
|
+
if (!start)
|
|
26
|
+
return {};
|
|
27
|
+
let depth = 1, quote = '', piece = '', result = {};
|
|
28
|
+
const field = () => {
|
|
29
|
+
const match = /^\s*(?:"(default|provider)"|'(default|provider)'|(default|provider))\s*:\s*([\s\S]+)$/.exec(piece);
|
|
30
|
+
if (match)
|
|
31
|
+
result[match[1] || match[2] || match[3]] = scalarValue(match[4]);
|
|
32
|
+
piece = '';
|
|
33
|
+
};
|
|
34
|
+
for (let i = start.index + start[0].length; i < source.length; i++) {
|
|
35
|
+
const c = source[i];
|
|
36
|
+
if (quote) {
|
|
37
|
+
piece += c;
|
|
38
|
+
if (quote === '"' && c === '\\') {
|
|
39
|
+
piece += source[++i] || '';
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (c === quote) {
|
|
43
|
+
if (quote === "'" && source[i + 1] === "'") {
|
|
44
|
+
piece += source[++i];
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
quote = '';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (c === '"' || c === "'") {
|
|
51
|
+
quote = c;
|
|
52
|
+
piece += c;
|
|
53
|
+
}
|
|
54
|
+
else if (c === '{' || c === '[') {
|
|
55
|
+
depth++;
|
|
56
|
+
piece += c;
|
|
57
|
+
}
|
|
58
|
+
else if (c === '}' || c === ']') {
|
|
59
|
+
if (--depth === 0) {
|
|
60
|
+
field();
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
piece += c;
|
|
64
|
+
}
|
|
65
|
+
else if (c === ',' && depth === 1)
|
|
66
|
+
field();
|
|
67
|
+
else
|
|
68
|
+
piece += c;
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
/** Read only display fields; Hermes continues to own YAML parsing and credentials. */
|
|
73
|
+
export async function profileDisplay(home = agentHome(), env = process.env) {
|
|
74
|
+
const file = path.join(runtimePaths(home, env).profile, 'config.yaml');
|
|
75
|
+
try {
|
|
76
|
+
if ((await fs.stat(file)).size > 1024 * 1024)
|
|
77
|
+
return {};
|
|
78
|
+
const source = await fs.readFile(file, 'utf8');
|
|
79
|
+
let model, provider;
|
|
80
|
+
try {
|
|
81
|
+
const config = JSON.parse(source);
|
|
82
|
+
model = config.model?.default;
|
|
83
|
+
provider = config.model?.provider;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
const block = /^model:\s*\n((?:[ \t]+[^\n]*\n?|\s*\n)*)/m.exec(source)?.[1] || '';
|
|
87
|
+
const scalar = (key) => scalarValue(new RegExp('^ ' + key + ':\\s*([^\\n]+)', 'm').exec(block)?.[1]);
|
|
88
|
+
const flow = flowModel(source);
|
|
89
|
+
model = scalar('default') || flow.default;
|
|
90
|
+
provider = scalar('provider') || flow.provider;
|
|
91
|
+
}
|
|
92
|
+
return { ...(typeof model === 'string' ? { model: terminalText(model).slice(0, 512) } : {}), ...(typeof provider === 'string' ? { provider: terminalText(provider).slice(0, 512) } : {}) };
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return {};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/cli/chat/profile.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { agentHome, runtimePaths } from '../agent/config.js';\nimport { terminalText } from '../agent/process.js';\n\nfunction scalarValue(raw: string | undefined): string | undefined {\n raw = raw?.trim();\n if (!raw || /^[!&*{\\[]/.test(raw) || /^(?:null|~)$/i.test(raw)) return undefined;\n if (raw.startsWith('\"')) { try { const value = JSON.parse(raw); return typeof value === 'string' ? value : undefined; } catch { return undefined; } }\n if (raw.startsWith(\"'\")) return /^'([^']*(?:''[^']*)*)'\\s*(?:#.*)?$/.exec(raw)?.[1]?.replace(/''/g, \"'\");\n return raw.replace(/\\s+#.*$/, '');\n}\n/** Hermes round-trip writes can retain a JSON-origin YAML flow mapping. */\nfunction flowModel(source: string): Record<string, string | undefined> {\n const start = /(?:^|[{,\\n])\\s*(?:model|\"model\"|'model')\\s*:\\s*\\{/m.exec(source);\n if (!start) return {};\n let depth = 1, quote = '', piece = '', result: Record<string, string | undefined> = {};\n const field = () => {\n const match = /^\\s*(?:\"(default|provider)\"|'(default|provider)'|(default|provider))\\s*:\\s*([\\s\\S]+)$/.exec(piece);\n if (match) result[match[1] || match[2] || match[3]!] = scalarValue(match[4]);\n piece = '';\n };\n for (let i = start.index + start[0].length; i < source.length; i++) {\n const c = source[i]!;\n if (quote) {\n piece += c;\n if (quote === '\"' && c === '\\\\') { piece += source[++i] || ''; continue; }\n if (c === quote) {\n if (quote === \"'\" && source[i + 1] === \"'\") { piece += source[++i]; continue; }\n quote = '';\n }\n } else if (c === '\"' || c === \"'\") { quote = c; piece += c; }\n else if (c === '{' || c === '[') { depth++; piece += c; }\n else if (c === '}' || c === ']') { if (--depth === 0) { field(); break; } piece += c; }\n else if (c === ',' && depth === 1) field();\n else piece += c;\n }\n return result;\n}\n\n/** Read only display fields; Hermes continues to own YAML parsing and credentials. */\nexport async function profileDisplay(home = agentHome(), env: NodeJS.ProcessEnv = process.env): Promise<{ model?: string; provider?: string }> {\n const file = path.join(runtimePaths(home, env).profile, 'config.yaml');\n try {\n if ((await fs.stat(file)).size > 1024 * 1024) return {};\n const source = await fs.readFile(file, 'utf8');\n let model: string | undefined, provider: string | undefined;\n try { const config = JSON.parse(source); model = config.model?.default; provider = config.model?.provider; }\n catch {\n const block = /^model:\\s*\\n((?:[ \\t]+[^\\n]*\\n?|\\s*\\n)*)/m.exec(source)?.[1] || '';\n const scalar = (key: string) => scalarValue(new RegExp('^ ' + key + ':\\\\s*([^\\\\n]+)', 'm').exec(block)?.[1]);\n const flow = flowModel(source);\n model = scalar('default') || flow.default; provider = scalar('provider') || flow.provider;\n }\n return { ...(typeof model === 'string' ? { model: terminalText(model).slice(0, 512) } : {}), ...(typeof provider === 'string' ? { provider: terminalText(provider).slice(0, 512) } : {}) };\n } catch { return {}; }\n}\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ChatOutput } from './controller.js';
|
|
2
|
+
import type { ChatSettings } from './store.js';
|
|
3
|
+
export interface ChatTheme {
|
|
4
|
+
accent: (text: string) => string;
|
|
5
|
+
muted: (text: string) => string;
|
|
6
|
+
strong: (text: string) => string;
|
|
7
|
+
success: (text: string) => string;
|
|
8
|
+
error: (text: string) => string;
|
|
9
|
+
status?: (text: string) => string;
|
|
10
|
+
}
|
|
11
|
+
export declare const plainTheme: ChatTheme;
|
|
12
|
+
export interface BannerInfo {
|
|
13
|
+
model?: string;
|
|
14
|
+
provider?: string;
|
|
15
|
+
tools?: number;
|
|
16
|
+
session?: string;
|
|
17
|
+
rows?: number;
|
|
18
|
+
fullscreen?: boolean;
|
|
19
|
+
catalog?: {
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
}[];
|
|
23
|
+
}
|
|
24
|
+
export declare function chatBanner(settings: ChatSettings, columns?: number, theme?: ChatTheme, version?: string, info?: BannerInfo): string;
|
|
25
|
+
/** Writes only new output, leaving terminal scrollback and pasted code intact. */
|
|
26
|
+
export declare class ChatRenderer {
|
|
27
|
+
private write;
|
|
28
|
+
private theme;
|
|
29
|
+
private env;
|
|
30
|
+
private pending;
|
|
31
|
+
private segment;
|
|
32
|
+
private code;
|
|
33
|
+
private streamed;
|
|
34
|
+
constructor(write: (text: string) => void, theme?: ChatTheme, env?: NodeJS.ProcessEnv);
|
|
35
|
+
private safe;
|
|
36
|
+
private line;
|
|
37
|
+
private flush;
|
|
38
|
+
finish(): void;
|
|
39
|
+
handle(output: ChatOutput): void;
|
|
40
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { terminalText, redact } from '../agent/process.js';
|
|
2
|
+
import { cells, clip } from './text.js';
|
|
3
|
+
import { ONBOARDER_MARK, ONBOARDER_COMPACT_MARK } from './logo.js';
|
|
4
|
+
export const plainTheme = { accent: s => s, muted: s => s, strong: s => s, success: s => s, error: s => s };
|
|
5
|
+
const SIGIL = ONBOARDER_MARK;
|
|
6
|
+
const LETTERS = {
|
|
7
|
+
O: [' ███ ', '█ █', '█ █', '█ █', ' ███ '],
|
|
8
|
+
N: ['█ █', '██ █', '█ █ █', '█ ██', '█ █'],
|
|
9
|
+
B: ['████ ', '█ █', '████ ', '█ █', '████ '],
|
|
10
|
+
A: [' ███ ', '█ █', '█████', '█ █', '█ █'],
|
|
11
|
+
R: ['████ ', '█ █', '████ ', '█ █ ', '█ █'],
|
|
12
|
+
D: ['████ ', '█ █', '█ █', '█ █', '████ '],
|
|
13
|
+
E: ['█████', '█ ', '████ ', '█ ', '█████'],
|
|
14
|
+
};
|
|
15
|
+
export function chatBanner(settings, columns = 80, theme = plainTheme, version = '', info = {}) {
|
|
16
|
+
if (info.fullscreen)
|
|
17
|
+
return screenBanner(settings, columns, theme, version, info);
|
|
18
|
+
const room = Math.max(1, columns - 1), indent = room > 8 ? ' ' : '', width = Math.max(1, Math.min(room - indent.length, 144));
|
|
19
|
+
const line = (text) => indent + clip(text, width);
|
|
20
|
+
const output = [''];
|
|
21
|
+
if (width >= 55 && (!info.rows || info.rows >= 18))
|
|
22
|
+
for (let row = 0; row < 5; row++)
|
|
23
|
+
output.push(indent + theme.accent([...'ONBOARDER'].map(c => LETTERS[c][row]).join(' ')));
|
|
24
|
+
else
|
|
25
|
+
output.push(indent + theme.strong(clip('ONBOARDER', width)));
|
|
26
|
+
output.push(line(`v${version || 'dev'} · repository agent powered by Hermes`), '');
|
|
27
|
+
const details = [
|
|
28
|
+
'YOUR SESSION', settings.sourceUrl || settings.root,
|
|
29
|
+
'Model: ' + (settings.model || info.model || 'Choose with /model'),
|
|
30
|
+
'Provider: ' + (settings.provider || info.provider || 'Hermes profile'),
|
|
31
|
+
'Workflow: ' + settings.mode,
|
|
32
|
+
`Checks ${settings.checks ? 'on' : 'off'} · GitHub writes ${settings.github ? 'on' : 'off'}`,
|
|
33
|
+
'Session: ' + (info.session?.slice(0, 8) || 'new'),
|
|
34
|
+
];
|
|
35
|
+
const features = [
|
|
36
|
+
'AVAILABLE FEATURES',
|
|
37
|
+
'Repository: maps, source, search, dependencies',
|
|
38
|
+
'GitHub: PR reviews, issues, labels, CI, draft PRs',
|
|
39
|
+
'Code: isolated edits, diffs, optional checks',
|
|
40
|
+
'Explorer: diagrams, security, history, licenses',
|
|
41
|
+
'Chat: follow-ups, resume, export, multiline',
|
|
42
|
+
`${info.tools ?? 'Scoped'} tools · 6 workflow skills · /tools · /skills`,
|
|
43
|
+
];
|
|
44
|
+
const compact = !!info.rows && info.rows < 30;
|
|
45
|
+
const title = clip(` Onboarder v${version || 'dev'} · Hermes Agent `, Math.max(0, width - 6));
|
|
46
|
+
if (width >= 18)
|
|
47
|
+
output.push(indent + theme.accent('╭─' + title + '─'.repeat(width - 3 - cells(title)) + '╮'));
|
|
48
|
+
if (compact) {
|
|
49
|
+
const rows = [
|
|
50
|
+
settings.sourceUrl || settings.root,
|
|
51
|
+
'Model: ' + (settings.model || info.model || '/model — choose a provider'),
|
|
52
|
+
`${settings.mode} · checks ${settings.checks ? 'on' : 'off'} · GitHub writes ${settings.github ? 'on' : 'off'}`,
|
|
53
|
+
'Maps · code · GitHub · diagrams · history · security',
|
|
54
|
+
`${info.tools ?? 'Scoped'} tools · 6 workflows · session ${info.session?.slice(0, 8) || 'new'}`,
|
|
55
|
+
];
|
|
56
|
+
for (const text of rows) {
|
|
57
|
+
const content = clip(text, width >= 18 ? width - 4 : width);
|
|
58
|
+
output.push(indent + (width >= 18 ? theme.accent('│ ') : '') + content + (width >= 18 ? ' '.repeat(width - 4 - cells(content)) + theme.accent(' │') : ''));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (width >= 76) {
|
|
62
|
+
const left = Math.floor((width - 6) * 0.39), right = width - left - 6;
|
|
63
|
+
const tools = info.catalog || [];
|
|
64
|
+
const categories = [
|
|
65
|
+
['repository', tools.filter(t => t.name.startsWith('onboarder_agent_'))],
|
|
66
|
+
['analysis', tools.filter(t => !t.name.startsWith('onboarder_agent_') && !t.name.startsWith('github_'))],
|
|
67
|
+
['github', tools.filter(t => t.name.startsWith('github_'))],
|
|
68
|
+
];
|
|
69
|
+
const available = categories.flatMap(([label, list]) => list.length ? [label + ': ' + list.slice(0, 2).map(t => t.name.replace(/^onboarder_(?:agent_)?|^github_/, '')).join(', '), ` ${list.length} tools · /tools for details`] : []);
|
|
70
|
+
const rightRows = ['Available Tools', ...(available.length ? available : features.slice(1, 4)), '', 'Available Skills',
|
|
71
|
+
'repository: /ask — understand your code', 'review: /review — local changes and PRs', 'issues: /triage — investigate and prioritize',
|
|
72
|
+
'code: /implement — isolated workspaces', 'pull requests: /pr — prepare draft PRs', 'github: /github — issues, reviews, CI', '',
|
|
73
|
+
`${info.tools ?? 'Scoped'} tools · 6 skills · /help for commands`];
|
|
74
|
+
const leftRows = [...SIGIL, '', settings.model || info.model || '/model to choose a model', settings.provider || info.provider || 'Provider not configured',
|
|
75
|
+
settings.sourceUrl || settings.root, 'Session: ' + (info.session?.slice(0, 8) || 'new'),
|
|
76
|
+
`Checks ${settings.checks ? 'on' : 'off'} · GitHub ${settings.github ? 'on' : 'off'}`];
|
|
77
|
+
for (let i = 0; i < Math.max(leftRows.length, rightRows.length); i++) {
|
|
78
|
+
const a = clip(leftRows[i] || '', left), b = clip(rightRows[i] || '', right);
|
|
79
|
+
const heading = rightRows[i] === 'Available Tools' || rightRows[i] === 'Available Skills';
|
|
80
|
+
output.push(indent + theme.accent('│ ') + (i < SIGIL.length || i === SIGIL.length + 1 ? theme.accent(a) : theme.muted(a)) + ' '.repeat(left - cells(a)) + ' ' + (heading ? theme.accent(b) : b) + ' '.repeat(right - cells(b)) + theme.accent(' │'));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
for (const text of [...details, '', ...features]) {
|
|
85
|
+
const content = clip(text, width >= 18 ? width - 4 : width);
|
|
86
|
+
output.push(indent + (width >= 18 ? theme.accent('│ ') : '') + (text.endsWith('SESSION') || text.endsWith('FEATURES') ? theme.strong(content) : content) + (width >= 18 ? ' '.repeat(width - 4 - cells(content)) + theme.accent(' │') : ''));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (width >= 18)
|
|
90
|
+
output.push(indent + theme.accent('╰' + '─'.repeat(width - 2) + '╯'));
|
|
91
|
+
output.push('', line('Welcome. Ask a question or paste a GitHub URL to get started.'), line('Type / for live commands · ↑/↓ choose · Tab/Enter insert · Esc close'), '');
|
|
92
|
+
return output.join('\n');
|
|
93
|
+
}
|
|
94
|
+
/** A welcome screen fitted to the remaining viewport, rather than a fixed poster. */
|
|
95
|
+
function screenBanner(settings, columns, theme, version, info) {
|
|
96
|
+
const room = Math.max(1, columns - 1), height = Math.max(1, info.rows || 24);
|
|
97
|
+
const indent = room > 40 ? ' ' : '', width = Math.max(1, room - indent.length * 2);
|
|
98
|
+
const model = settings.model || info.model || '/model — choose a provider';
|
|
99
|
+
const details = [settings.sourceUrl || settings.root, 'Model: ' + model,
|
|
100
|
+
`${settings.mode} · checks ${settings.checks ? 'on' : 'off'} · GitHub writes ${settings.github ? 'on' : 'off'}`,
|
|
101
|
+
'Maps · code · GitHub · history · security', `${info.tools ?? 'Scoped'} tools · 6 skills · session ${info.session?.slice(0, 8) || 'new'}`];
|
|
102
|
+
if (height < 10 || width < 28)
|
|
103
|
+
return ['◈ ONBOARDER', ...details, 'Type / for commands'].slice(0, height).map(t => theme.accent(clip(t, room))).join('\n');
|
|
104
|
+
const output = [];
|
|
105
|
+
if (width >= 55 && height >= 18)
|
|
106
|
+
for (let r = 0; r < 5; r++)
|
|
107
|
+
output.push(indent + theme.accent([...'ONBOARDER'].map(c => LETTERS[c][r]).join(' ')));
|
|
108
|
+
else
|
|
109
|
+
output.push(indent + theme.accent('◈ ONBOARDER · code compass'));
|
|
110
|
+
if (height >= 14)
|
|
111
|
+
output.push(indent + theme.muted(clip('Understand the code. Find your direction.', width)), '');
|
|
112
|
+
const title = clip(` Onboarder v${version || 'dev'} · Hermes harness `, width - 6);
|
|
113
|
+
output.push(indent + theme.accent('╭─' + title + '─'.repeat(width - cells(title) - 3) + '╮'));
|
|
114
|
+
const pair = (a, b, left, right, accent = false) => {
|
|
115
|
+
const aa = clip(a, left), bb = clip(b, right);
|
|
116
|
+
return indent + theme.accent('│ ') + theme.accent(aa) + ' '.repeat(left - cells(aa)) + ' ' + (accent ? theme.accent(bb) : bb) + ' '.repeat(right - cells(bb)) + theme.accent(' │');
|
|
117
|
+
};
|
|
118
|
+
if (height >= 30 && width >= 76) {
|
|
119
|
+
const left = Math.floor((width - 6) * 0.39), right = width - left - 6, tools = info.catalog || [];
|
|
120
|
+
const groups = [['repository', tools.filter(t => t.name.startsWith('onboarder_agent_'))],
|
|
121
|
+
['analysis', tools.filter(t => !t.name.startsWith('onboarder_agent_') && !t.name.startsWith('github_'))],
|
|
122
|
+
['github', tools.filter(t => t.name.startsWith('github_'))]];
|
|
123
|
+
const available = groups.flatMap(([label, list]) => list.length ? [label + ': ' + list.slice(0, 2).map(t => t.name.replace(/^onboarder_(?:agent_)?|^github_/, '')).join(', '), ` ${list.length} tools · /tools for details`] : []);
|
|
124
|
+
const b = ['Available Tools', ...(available.length ? available : ['repository · analysis · github']), '', 'Available Skills',
|
|
125
|
+
'/ask — understand the repository', '/review — local changes and pull requests', '/triage — investigate issues',
|
|
126
|
+
'/implement — isolated code changes', '/pr — prepare draft pull requests', '/github — issues, reviews and CI', '', `${info.tools ?? 'Scoped'} tools · 6 skills · /help`];
|
|
127
|
+
const a = [...ONBOARDER_MARK, '', model, settings.provider || info.provider || 'Choose provider with /model',
|
|
128
|
+
settings.sourceUrl || settings.root, 'Session: ' + (info.session?.slice(0, 8) || 'new'),
|
|
129
|
+
`Checks ${settings.checks ? 'on' : 'off'} · GitHub ${settings.github ? 'on' : 'off'}`];
|
|
130
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++)
|
|
131
|
+
output.push(pair(a[i] || '', b[i] || '', left, right, b[i]?.startsWith('Available')));
|
|
132
|
+
}
|
|
133
|
+
else if (width >= 62) {
|
|
134
|
+
const left = 13, right = width - left - 6;
|
|
135
|
+
for (let i = 0; i < details.length; i++)
|
|
136
|
+
output.push(pair(ONBOARDER_COMPACT_MARK[i], details[i], left, right));
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
for (const detail of details) {
|
|
140
|
+
const text = clip(detail, width - 4);
|
|
141
|
+
output.push(indent + theme.accent('│ ') + text + ' '.repeat(width - 4 - cells(text)) + theme.accent(' │'));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
output.push(indent + theme.accent('╰' + '─'.repeat(width - 2) + '╯'));
|
|
145
|
+
if (height >= 14)
|
|
146
|
+
output.push('');
|
|
147
|
+
output.push(indent + theme.muted(clip('Ask a question or paste a GitHub URL. Type / for commands.', width)));
|
|
148
|
+
if (height >= 18)
|
|
149
|
+
output.push(indent + theme.muted(clip('↑/↓ select · Enter choose · PgUp/PgDn scroll · Esc close', width)));
|
|
150
|
+
return output.slice(0, height).join('\n');
|
|
151
|
+
}
|
|
152
|
+
/** Writes only new output, leaving terminal scrollback and pasted code intact. */
|
|
153
|
+
export class ChatRenderer {
|
|
154
|
+
write;
|
|
155
|
+
theme;
|
|
156
|
+
env;
|
|
157
|
+
pending = '';
|
|
158
|
+
segment = '';
|
|
159
|
+
code = false;
|
|
160
|
+
streamed = 0;
|
|
161
|
+
constructor(write, theme = plainTheme, env = process.env) {
|
|
162
|
+
this.write = write;
|
|
163
|
+
this.theme = theme;
|
|
164
|
+
this.env = env;
|
|
165
|
+
}
|
|
166
|
+
safe(text) { return terminalText(redact(text, this.env)); }
|
|
167
|
+
line(text) {
|
|
168
|
+
const safe = this.safe(text);
|
|
169
|
+
if (/^\s*```/.test(safe)) {
|
|
170
|
+
this.code = !this.code;
|
|
171
|
+
this.write(this.theme.muted(safe));
|
|
172
|
+
}
|
|
173
|
+
else if (this.code)
|
|
174
|
+
this.write(safe);
|
|
175
|
+
else if (/^#{1,4}\s/.test(safe))
|
|
176
|
+
this.write(this.theme.strong(safe.replace(/^#{1,4}\s*/, '')));
|
|
177
|
+
else
|
|
178
|
+
this.write(safe);
|
|
179
|
+
}
|
|
180
|
+
flush() { if (this.pending) {
|
|
181
|
+
this.line(this.pending);
|
|
182
|
+
this.pending = '';
|
|
183
|
+
} }
|
|
184
|
+
finish() { this.flush(); }
|
|
185
|
+
handle(output) {
|
|
186
|
+
if (output.type === 'start') {
|
|
187
|
+
this.pending = '';
|
|
188
|
+
this.segment = '';
|
|
189
|
+
this.code = false;
|
|
190
|
+
this.streamed = 0;
|
|
191
|
+
this.write('\n' + this.theme.accent('Hermes') + this.theme.muted(' · ' + output.mode));
|
|
192
|
+
if (['implement', 'pr'].includes(output.mode))
|
|
193
|
+
this.write(this.theme.muted('Edits use an isolated workspace at committed HEAD. Source checkout edits are excluded.'));
|
|
194
|
+
this.write(this.theme.muted('Working… /cancel or Ctrl-C to stop'));
|
|
195
|
+
}
|
|
196
|
+
else if (output.type === 'message') {
|
|
197
|
+
this.flush();
|
|
198
|
+
this.write(this.safe(output.text));
|
|
199
|
+
}
|
|
200
|
+
else if (output.type === 'event') {
|
|
201
|
+
const event = output.event;
|
|
202
|
+
if (event.type === 'text' && event.text) {
|
|
203
|
+
// Complete logical lines keep split credentials and escape sequences together.
|
|
204
|
+
// A bounded buffer also prevents an unbroken model response exhausting memory.
|
|
205
|
+
if (this.streamed >= 256000)
|
|
206
|
+
return;
|
|
207
|
+
const text = event.text.slice(0, 256000 - this.streamed);
|
|
208
|
+
this.streamed += text.length;
|
|
209
|
+
this.segment += text;
|
|
210
|
+
this.pending += text;
|
|
211
|
+
let end;
|
|
212
|
+
while ((end = this.pending.indexOf('\n')) >= 0) {
|
|
213
|
+
this.line(this.pending.slice(0, end));
|
|
214
|
+
this.pending = this.pending.slice(end + 1);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else if (event.type === 'tool_use') {
|
|
218
|
+
this.flush();
|
|
219
|
+
this.segment = '';
|
|
220
|
+
this.code = false;
|
|
221
|
+
const name = this.safe(event.name || 'repository tool').replace(/^mcp__onboarder__(?:onboarder_)?/, '').replace(/_/g, ' ');
|
|
222
|
+
this.write(this.theme.muted(' → ' + name));
|
|
223
|
+
}
|
|
224
|
+
else if (event.type === 'tool_result' && event.is_error) {
|
|
225
|
+
this.flush();
|
|
226
|
+
this.write(this.theme.error(' Tool reported an error; Hermes may retry or explain it.'));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else if (output.type === 'end') {
|
|
230
|
+
const answer = this.safe(output.result.answer), segment = this.safe(this.segment);
|
|
231
|
+
// Hermes emits intermediate narration as well as the final response. Only
|
|
232
|
+
// suppress a final response already emitted by this last assistant segment.
|
|
233
|
+
if (output.result.status === 'completed' && segment.trim() === answer.trim())
|
|
234
|
+
this.flush();
|
|
235
|
+
else if (output.result.status === 'completed' && answer.startsWith(segment) && segment) {
|
|
236
|
+
this.pending += answer.slice(segment.length);
|
|
237
|
+
this.flush();
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
this.flush();
|
|
241
|
+
if (answer)
|
|
242
|
+
this.write(answer.slice(0, 256000));
|
|
243
|
+
}
|
|
244
|
+
if (this.streamed >= 256000 || answer.length > 256000)
|
|
245
|
+
this.write(this.theme.muted('Display limited to 256000 characters. The full result is in agent show.'));
|
|
246
|
+
const style = output.result.status === 'completed' ? this.theme.success : this.theme.error;
|
|
247
|
+
this.write('\n' + style(output.result.status) + this.theme.muted(` · ${(output.elapsed / 1000).toFixed(1)}s · run ${output.result.id}`));
|
|
248
|
+
if (output.result.branch)
|
|
249
|
+
this.write(this.theme.muted('Workspace: ' + this.safe(output.result.workspace) + '\nBranch: ' + this.safe(output.result.branch)));
|
|
250
|
+
if (output.result.status === 'failed')
|
|
251
|
+
this.write(this.theme.muted('Use /doctor to check the runtime or /model configure to select a model.'));
|
|
252
|
+
this.write('');
|
|
253
|
+
this.pending = '';
|
|
254
|
+
this.segment = '';
|
|
255
|
+
this.code = false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/cli/chat/render.ts"],"names":[],"mappings":"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","sourcesContent":["import { terminalText, redact } from '../agent/process.js';\nimport type { ChatOutput } from './controller.js';\nimport type { ChatSettings } from './store.js';\nimport { cells, clip } from './text.js';\nimport { ONBOARDER_MARK, ONBOARDER_COMPACT_MARK } from './logo.js';\n\nexport interface ChatTheme {\n accent: (text: string) => string; muted: (text: string) => string;\n strong: (text: string) => string; success: (text: string) => string; error: (text: string) => string;\n status?: (text: string) => string;\n}\nexport const plainTheme: ChatTheme = { accent: s => s, muted: s => s, strong: s => s, success: s => s, error: s => s };\nexport interface BannerInfo { model?: string; provider?: string; tools?: number; session?: string; rows?: number; fullscreen?: boolean; catalog?: { name: string; description: string }[] }\nconst SIGIL = ONBOARDER_MARK;\nconst LETTERS: Record<string, string[]> = {\n O: [' ███ ', '█ █', '█ █', '█ █', ' ███ '],\n N: ['█ █', '██ █', '█ █ █', '█ ██', '█ █'],\n B: ['████ ', '█ █', '████ ', '█ █', '████ '],\n A: [' ███ ', '█ █', '█████', '█ █', '█ █'],\n R: ['████ ', '█ █', '████ ', '█ █ ', '█ █'],\n D: ['████ ', '█ █', '█ █', '█ █', '████ '],\n E: ['█████', '█ ', '████ ', '█ ', '█████'],\n};\nexport function chatBanner(settings: ChatSettings, columns = 80, theme = plainTheme, version = '', info: BannerInfo = {}): string {\n if (info.fullscreen) return screenBanner(settings, columns, theme, version, info);\n const room = Math.max(1, columns - 1), indent = room > 8 ? ' ' : '', width = Math.max(1, Math.min(room - indent.length, 144));\n const line = (text: string) => indent + clip(text, width);\n const output = [''];\n if (width >= 55 && (!info.rows || info.rows >= 18)) for (let row = 0; row < 5; row++) output.push(indent + theme.accent([... 'ONBOARDER'].map(c => LETTERS[c]![row]).join(' ')));\n else output.push(indent + theme.strong(clip('ONBOARDER', width)));\n output.push(line(`v${version || 'dev'} · repository agent powered by Hermes`), '');\n const details = [\n 'YOUR SESSION', settings.sourceUrl || settings.root,\n 'Model: ' + (settings.model || info.model || 'Choose with /model'),\n 'Provider: ' + (settings.provider || info.provider || 'Hermes profile'),\n 'Workflow: ' + settings.mode,\n `Checks ${settings.checks ? 'on' : 'off'} · GitHub writes ${settings.github ? 'on' : 'off'}`,\n 'Session: ' + (info.session?.slice(0, 8) || 'new'),\n ];\n const features = [\n 'AVAILABLE FEATURES',\n 'Repository: maps, source, search, dependencies',\n 'GitHub: PR reviews, issues, labels, CI, draft PRs',\n 'Code: isolated edits, diffs, optional checks',\n 'Explorer: diagrams, security, history, licenses',\n 'Chat: follow-ups, resume, export, multiline',\n `${info.tools ?? 'Scoped'} tools · 6 workflow skills · /tools · /skills`,\n ];\n const compact = !!info.rows && info.rows < 30;\n const title = clip(` Onboarder v${version || 'dev'} · Hermes Agent `, Math.max(0, width - 6));\n if (width >= 18) output.push(indent + theme.accent('╭─' + title + '─'.repeat(width - 3 - cells(title)) + '╮'));\n if (compact) {\n const rows = [\n settings.sourceUrl || settings.root,\n 'Model: ' + (settings.model || info.model || '/model — choose a provider'),\n `${settings.mode} · checks ${settings.checks ? 'on' : 'off'} · GitHub writes ${settings.github ? 'on' : 'off'}`,\n 'Maps · code · GitHub · diagrams · history · security',\n `${info.tools ?? 'Scoped'} tools · 6 workflows · session ${info.session?.slice(0, 8) || 'new'}`,\n ];\n for (const text of rows) {\n const content = clip(text, width >= 18 ? width - 4 : width);\n output.push(indent + (width >= 18 ? theme.accent('│ ') : '') + content + (width >= 18 ? ' '.repeat(width - 4 - cells(content)) + theme.accent(' │') : ''));\n }\n } else if (width >= 76) {\n const left = Math.floor((width - 6) * 0.39), right = width - left - 6;\n const tools = info.catalog || [];\n const categories = [\n ['repository', tools.filter(t => t.name.startsWith('onboarder_agent_'))],\n ['analysis', tools.filter(t => !t.name.startsWith('onboarder_agent_') && !t.name.startsWith('github_'))],\n ['github', tools.filter(t => t.name.startsWith('github_'))],\n ] as const;\n const available = categories.flatMap(([label, list]) => list.length ? [label + ': ' + list.slice(0, 2).map(t => t.name.replace(/^onboarder_(?:agent_)?|^github_/, '')).join(', '), ` ${list.length} tools · /tools for details`] : []);\n const rightRows = ['Available Tools', ...(available.length ? available : features.slice(1, 4)), '', 'Available Skills',\n 'repository: /ask — understand your code', 'review: /review — local changes and PRs', 'issues: /triage — investigate and prioritize',\n 'code: /implement — isolated workspaces', 'pull requests: /pr — prepare draft PRs', 'github: /github — issues, reviews, CI', '',\n `${info.tools ?? 'Scoped'} tools · 6 skills · /help for commands`];\n const leftRows = [...SIGIL, '', settings.model || info.model || '/model to choose a model', settings.provider || info.provider || 'Provider not configured',\n settings.sourceUrl || settings.root, 'Session: ' + (info.session?.slice(0, 8) || 'new'),\n `Checks ${settings.checks ? 'on' : 'off'} · GitHub ${settings.github ? 'on' : 'off'}`];\n for (let i = 0; i < Math.max(leftRows.length, rightRows.length); i++) {\n const a = clip(leftRows[i] || '', left), b = clip(rightRows[i] || '', right);\n const heading = rightRows[i] === 'Available Tools' || rightRows[i] === 'Available Skills';\n output.push(indent + theme.accent('│ ') + (i < SIGIL.length || i === SIGIL.length + 1 ? theme.accent(a) : theme.muted(a)) + ' '.repeat(left - cells(a)) + ' ' + (heading ? theme.accent(b) : b) + ' '.repeat(right - cells(b)) + theme.accent(' │'));\n }\n } else {\n for (const text of [...details, '', ...features]) {\n const content = clip(text, width >= 18 ? width - 4 : width);\n output.push(indent + (width >= 18 ? theme.accent('│ ') : '') + (text.endsWith('SESSION') || text.endsWith('FEATURES') ? theme.strong(content) : content) + (width >= 18 ? ' '.repeat(width - 4 - cells(content)) + theme.accent(' │') : ''));\n }\n }\n if (width >= 18) output.push(indent + theme.accent('╰' + '─'.repeat(width - 2) + '╯'));\n output.push('', line('Welcome. Ask a question or paste a GitHub URL to get started.'), line('Type / for live commands · ↑/↓ choose · Tab/Enter insert · Esc close'), '');\n return output.join('\\n');\n}\n\n/** A welcome screen fitted to the remaining viewport, rather than a fixed poster. */\nfunction screenBanner(settings: ChatSettings, columns: number, theme: ChatTheme, version: string, info: BannerInfo): string {\n const room = Math.max(1, columns - 1), height = Math.max(1, info.rows || 24);\n const indent = room > 40 ? ' ' : '', width = Math.max(1, room - indent.length * 2);\n const model = settings.model || info.model || '/model — choose a provider';\n const details = [settings.sourceUrl || settings.root, 'Model: ' + model,\n `${settings.mode} · checks ${settings.checks ? 'on' : 'off'} · GitHub writes ${settings.github ? 'on' : 'off'}`,\n 'Maps · code · GitHub · history · security', `${info.tools ?? 'Scoped'} tools · 6 skills · session ${info.session?.slice(0, 8) || 'new'}`];\n if (height < 10 || width < 28) return ['◈ ONBOARDER', ...details, 'Type / for commands'].slice(0, height).map(t => theme.accent(clip(t, room))).join('\\n');\n const output: string[] = [];\n if (width >= 55 && height >= 18) for (let r = 0; r < 5; r++) output.push(indent + theme.accent([... 'ONBOARDER'].map(c => LETTERS[c]![r]).join(' ')));\n else output.push(indent + theme.accent('◈ ONBOARDER · code compass'));\n if (height >= 14) output.push(indent + theme.muted(clip('Understand the code. Find your direction.', width)), '');\n const title = clip(` Onboarder v${version || 'dev'} · Hermes harness `, width - 6);\n output.push(indent + theme.accent('╭─' + title + '─'.repeat(width - cells(title) - 3) + '╮'));\n const pair = (a: string, b: string, left: number, right: number, accent = false) => {\n const aa = clip(a, left), bb = clip(b, right);\n return indent + theme.accent('│ ') + theme.accent(aa) + ' '.repeat(left - cells(aa)) + ' ' + (accent ? theme.accent(bb) : bb) + ' '.repeat(right - cells(bb)) + theme.accent(' │');\n };\n if (height >= 30 && width >= 76) {\n const left = Math.floor((width - 6) * 0.39), right = width - left - 6, tools = info.catalog || [];\n const groups = [['repository', tools.filter(t => t.name.startsWith('onboarder_agent_'))],\n ['analysis', tools.filter(t => !t.name.startsWith('onboarder_agent_') && !t.name.startsWith('github_'))],\n ['github', tools.filter(t => t.name.startsWith('github_'))]] as const;\n const available = groups.flatMap(([label, list]) => list.length ? [label + ': ' + list.slice(0, 2).map(t => t.name.replace(/^onboarder_(?:agent_)?|^github_/, '')).join(', '), ` ${list.length} tools · /tools for details`] : []);\n const b = ['Available Tools', ...(available.length ? available : ['repository · analysis · github']), '', 'Available Skills',\n '/ask — understand the repository', '/review — local changes and pull requests', '/triage — investigate issues',\n '/implement — isolated code changes', '/pr — prepare draft pull requests', '/github — issues, reviews and CI', '', `${info.tools ?? 'Scoped'} tools · 6 skills · /help`];\n const a = [...ONBOARDER_MARK, '', model, settings.provider || info.provider || 'Choose provider with /model',\n settings.sourceUrl || settings.root, 'Session: ' + (info.session?.slice(0, 8) || 'new'),\n `Checks ${settings.checks ? 'on' : 'off'} · GitHub ${settings.github ? 'on' : 'off'}`];\n for (let i = 0; i < Math.max(a.length, b.length); i++) output.push(pair(a[i] || '', b[i] || '', left, right, b[i]?.startsWith('Available')));\n } else if (width >= 62) {\n const left = 13, right = width - left - 6;\n for (let i = 0; i < details.length; i++) output.push(pair(ONBOARDER_COMPACT_MARK[i]!, details[i]!, left, right));\n } else {\n for (const detail of details) {\n const text = clip(detail, width - 4);\n output.push(indent + theme.accent('│ ') + text + ' '.repeat(width - 4 - cells(text)) + theme.accent(' │'));\n }\n }\n output.push(indent + theme.accent('╰' + '─'.repeat(width - 2) + '╯'));\n if (height >= 14) output.push('');\n output.push(indent + theme.muted(clip('Ask a question or paste a GitHub URL. Type / for commands.', width)));\n if (height >= 18) output.push(indent + theme.muted(clip('↑/↓ select · Enter choose · PgUp/PgDn scroll · Esc close', width)));\n return output.slice(0, height).join('\\n');\n}\n\n/** Writes only new output, leaving terminal scrollback and pasted code intact. */\nexport class ChatRenderer {\n private pending = '';\n private segment = '';\n private code = false;\n private streamed = 0;\n constructor(private write: (text: string) => void, private theme = plainTheme, private env: NodeJS.ProcessEnv = process.env) {}\n private safe(text: string) { return terminalText(redact(text, this.env)); }\n private line(text: string) {\n const safe = this.safe(text);\n if (/^\\s*```/.test(safe)) { this.code = !this.code; this.write(this.theme.muted(safe)); }\n else if (this.code) this.write(safe);\n else if (/^#{1,4}\\s/.test(safe)) this.write(this.theme.strong(safe.replace(/^#{1,4}\\s*/, '')));\n else this.write(safe);\n }\n private flush() { if (this.pending) { this.line(this.pending); this.pending = ''; } }\n finish() { this.flush(); }\n handle(output: ChatOutput) {\n if (output.type === 'start') {\n this.pending = ''; this.segment = ''; this.code = false; this.streamed = 0;\n this.write('\\n' + this.theme.accent('Hermes') + this.theme.muted(' · ' + output.mode));\n if (['implement', 'pr'].includes(output.mode)) this.write(this.theme.muted('Edits use an isolated workspace at committed HEAD. Source checkout edits are excluded.'));\n this.write(this.theme.muted('Working… /cancel or Ctrl-C to stop'));\n } else if (output.type === 'message') { this.flush(); this.write(this.safe(output.text)); }\n else if (output.type === 'event') {\n const event = output.event;\n if (event.type === 'text' && event.text) {\n // Complete logical lines keep split credentials and escape sequences together.\n // A bounded buffer also prevents an unbroken model response exhausting memory.\n if (this.streamed >= 256000) return;\n const text = event.text.slice(0, 256000 - this.streamed); this.streamed += text.length;\n this.segment += text; this.pending += text;\n let end: number;\n while ((end = this.pending.indexOf('\\n')) >= 0) { this.line(this.pending.slice(0, end)); this.pending = this.pending.slice(end + 1); }\n } else if (event.type === 'tool_use') {\n this.flush(); this.segment = ''; this.code = false;\n const name = this.safe(event.name || 'repository tool').replace(/^mcp__onboarder__(?:onboarder_)?/, '').replace(/_/g, ' ');\n this.write(this.theme.muted(' → ' + name));\n } else if (event.type === 'tool_result' && event.is_error) {\n this.flush(); this.write(this.theme.error(' Tool reported an error; Hermes may retry or explain it.'));\n }\n } else if (output.type === 'end') {\n const answer = this.safe(output.result.answer), segment = this.safe(this.segment);\n // Hermes emits intermediate narration as well as the final response. Only\n // suppress a final response already emitted by this last assistant segment.\n if (output.result.status === 'completed' && segment.trim() === answer.trim()) this.flush();\n else if (output.result.status === 'completed' && answer.startsWith(segment) && segment) {\n this.pending += answer.slice(segment.length); this.flush();\n } else { this.flush(); if (answer) this.write(answer.slice(0, 256000)); }\n if (this.streamed >= 256000 || answer.length > 256000) this.write(this.theme.muted('Display limited to 256000 characters. The full result is in agent show.'));\n const style = output.result.status === 'completed' ? this.theme.success : this.theme.error;\n this.write('\\n' + style(output.result.status) + this.theme.muted(` · ${(output.elapsed / 1000).toFixed(1)}s · run ${output.result.id}`));\n if (output.result.branch) this.write(this.theme.muted('Workspace: ' + this.safe(output.result.workspace) + '\\nBranch: ' + this.safe(output.result.branch)));\n if (output.result.status === 'failed') this.write(this.theme.muted('Use /doctor to check the runtime or /model configure to select a model.'));\n this.write(''); this.pending = ''; this.segment = ''; this.code = false;\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Keep only our text styling; wrap by terminal cells, including emoji and CJK. */
|
|
2
|
+
export declare function wrapScreenLine(text: string, columns: number): string[];
|
|
3
|
+
/** Alternate-screen ownership, bounded transcript and updates of changed rows only. */
|
|
4
|
+
export declare class TerminalScreen {
|
|
5
|
+
private output;
|
|
6
|
+
private lines;
|
|
7
|
+
private bytes;
|
|
8
|
+
private width;
|
|
9
|
+
private wrapped;
|
|
10
|
+
private dirty;
|
|
11
|
+
private offset;
|
|
12
|
+
private frame;
|
|
13
|
+
private columns;
|
|
14
|
+
private active;
|
|
15
|
+
private pendingRows;
|
|
16
|
+
constructor(output: NodeJS.WriteStream);
|
|
17
|
+
get scrolled(): boolean;
|
|
18
|
+
enter(): void;
|
|
19
|
+
leave(): void;
|
|
20
|
+
append(text: string): void;
|
|
21
|
+
clear(): void;
|
|
22
|
+
private reflow;
|
|
23
|
+
scroll(direction: number, columns: number, height: number): void;
|
|
24
|
+
view(columns: number, height: number, welcome: string): string[];
|
|
25
|
+
draw(rows: string[], columns: number, cursorRow: number, cursorColumn: number): void;
|
|
26
|
+
}
|