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.
Files changed (139) hide show
  1. package/README.md +140 -12
  2. package/bin/onboarder.js +0 -0
  3. package/cli/agent/command.d.ts +71 -0
  4. package/cli/agent/command.js +177 -0
  5. package/cli/agent/command.js.map +1 -0
  6. package/cli/agent/config.d.ts +31 -0
  7. package/cli/agent/config.js +98 -0
  8. package/cli/agent/config.js.map +1 -0
  9. package/cli/agent/contracts.d.ts +77 -0
  10. package/cli/agent/contracts.js +2 -0
  11. package/cli/agent/contracts.js.map +1 -0
  12. package/cli/agent/files.d.ts +19 -0
  13. package/cli/agent/files.js +109 -0
  14. package/cli/agent/files.js.map +1 -0
  15. package/cli/agent/gitSource.d.ts +18 -0
  16. package/cli/agent/gitSource.js +69 -0
  17. package/cli/agent/gitSource.js.map +1 -0
  18. package/cli/agent/github.d.ts +21 -0
  19. package/cli/agent/github.js +94 -0
  20. package/cli/agent/github.js.map +1 -0
  21. package/cli/agent/mcp.d.ts +15 -0
  22. package/cli/agent/mcp.js +78 -0
  23. package/cli/agent/mcp.js.map +1 -0
  24. package/cli/agent/process.d.ts +18 -0
  25. package/cli/agent/process.js +118 -0
  26. package/cli/agent/process.js.map +1 -0
  27. package/cli/agent/protocol.d.ts +3 -0
  28. package/cli/agent/protocol.js +26 -0
  29. package/cli/agent/protocol.js.map +1 -0
  30. package/cli/agent/runner.d.ts +34 -0
  31. package/cli/agent/runner.js +152 -0
  32. package/cli/agent/runner.js.map +1 -0
  33. package/cli/agent/stdio.d.ts +1 -0
  34. package/cli/agent/stdio.js +62 -0
  35. package/cli/agent/stdio.js.map +1 -0
  36. package/cli/agent/tools.d.ts +7 -0
  37. package/cli/agent/tools.js +225 -0
  38. package/cli/agent/tools.js.map +1 -0
  39. package/cli/chat/analysis.d.ts +26 -0
  40. package/cli/chat/analysis.js +188 -0
  41. package/cli/chat/analysis.js.map +1 -0
  42. package/cli/chat/app.d.ts +16 -0
  43. package/cli/chat/app.js +363 -0
  44. package/cli/chat/app.js.map +1 -0
  45. package/cli/chat/commands.d.ts +11 -0
  46. package/cli/chat/commands.js +122 -0
  47. package/cli/chat/commands.js.map +1 -0
  48. package/cli/chat/composer.d.ts +75 -0
  49. package/cli/chat/composer.js +467 -0
  50. package/cli/chat/composer.js.map +1 -0
  51. package/cli/chat/controller.d.ts +64 -0
  52. package/cli/chat/controller.js +402 -0
  53. package/cli/chat/controller.js.map +1 -0
  54. package/cli/chat/logo.d.ts +3 -0
  55. package/cli/chat/logo.js +14 -0
  56. package/cli/chat/logo.js.map +1 -0
  57. package/cli/chat/models.d.ts +18 -0
  58. package/cli/chat/models.js +88 -0
  59. package/cli/chat/models.js.map +1 -0
  60. package/cli/chat/profile.d.ts +5 -0
  61. package/cli/chat/profile.js +98 -0
  62. package/cli/chat/profile.js.map +1 -0
  63. package/cli/chat/render.d.ts +40 -0
  64. package/cli/chat/render.js +259 -0
  65. package/cli/chat/render.js.map +1 -0
  66. package/cli/chat/screen.d.ts +26 -0
  67. package/cli/chat/screen.js +117 -0
  68. package/cli/chat/screen.js.map +1 -0
  69. package/cli/chat/source.d.ts +29 -0
  70. package/cli/chat/source.js +116 -0
  71. package/cli/chat/source.js.map +1 -0
  72. package/cli/chat/store.d.ts +43 -0
  73. package/cli/chat/store.js +94 -0
  74. package/cli/chat/store.js.map +1 -0
  75. package/cli/chat/text.d.ts +4 -0
  76. package/cli/chat/text.js +27 -0
  77. package/cli/chat/text.js.map +1 -0
  78. package/cli/explorer/app.d.ts +1 -0
  79. package/cli/explorer/app.js +20 -1
  80. package/cli/explorer/app.js.map +1 -1
  81. package/cli/explorer/commands.js +5 -0
  82. package/cli/explorer/commands.js.map +1 -1
  83. package/cli/explorer/featureViews.d.ts +1 -0
  84. package/cli/explorer/featureViews.js +4 -0
  85. package/cli/explorer/featureViews.js.map +1 -1
  86. package/cli/main.js +47 -13
  87. package/cli/main.js.map +1 -1
  88. package/docs/HERMES_RESEARCH.md +51 -0
  89. package/package.json +2 -1
  90. package/public/app.js +98 -24
  91. package/public/app.js.map +1 -1
  92. package/public/assets/onboarder-mark.svg +11 -0
  93. package/public/browser.d.ts +3 -0
  94. package/public/browser.js.map +1 -1
  95. package/public/index.html +24 -7
  96. package/public/js/about.js +2 -2
  97. package/public/js/about.js.map +1 -1
  98. package/public/js/aiDraft.d.ts +1 -0
  99. package/public/js/aiDraft.js +66 -17
  100. package/public/js/aiDraft.js.map +1 -1
  101. package/public/js/api.d.ts +8 -5
  102. package/public/js/api.js +45 -22
  103. package/public/js/api.js.map +1 -1
  104. package/public/js/deepAnalysisView.js +2 -2
  105. package/public/js/deepAnalysisView.js.map +1 -1
  106. package/public/js/diagramPane.d.ts +1 -0
  107. package/public/js/diagramPane.js +5 -0
  108. package/public/js/diagramPane.js.map +1 -1
  109. package/public/js/docsView.js +6 -6
  110. package/public/js/docsView.js.map +1 -1
  111. package/public/js/dom.d.ts +8 -0
  112. package/public/js/dom.js.map +1 -1
  113. package/public/js/llm.d.ts +3 -1
  114. package/public/js/llm.js +15 -8
  115. package/public/js/llm.js.map +1 -1
  116. package/public/js/repoFiles.js +1 -1
  117. package/public/js/repoFiles.js.map +1 -1
  118. package/public/js/reviewView.js +1 -1
  119. package/public/js/reviewView.js.map +1 -1
  120. package/public/styles.css +25 -0
  121. package/server/gitDiff.d.ts +1 -1
  122. package/server/hermesChat.d.ts +13 -0
  123. package/server/hermesChat.js +145 -0
  124. package/server/hermesChat.js.map +1 -0
  125. package/server/http.d.ts +5 -4
  126. package/server/http.js +0 -4
  127. package/server/http.js.map +1 -1
  128. package/server/mcp/server.d.ts +1 -1
  129. package/server/mcp/server.js +2 -2
  130. package/server/mcp/server.js.map +1 -1
  131. package/server/router.js +7 -3
  132. package/server/router.js.map +1 -1
  133. package/server/tools/scan.js +16 -2
  134. package/server/tools/scan.js.map +1 -1
  135. package/server/tools.d.ts +1 -0
  136. package/server/tools.js +46 -6
  137. package/server/tools.js.map +1 -1
  138. package/shared/diagram/aiMermaid.js +16 -13
  139. package/shared/diagram/aiMermaid.js.map +1 -1
@@ -0,0 +1,402 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { AGENT_MODES } from '../agent/contracts.js';
3
+ import { runAgent, savedRun } from '../agent/runner.js';
4
+ import { agentHome } from '../agent/config.js';
5
+ import { redact, terminalText } from '../agent/process.js';
6
+ import { ChatStore, newChat, historySummary } from './store.js';
7
+ import { slashInput, chatHelp, BROWSE_COMMANDS } from './commands.js';
8
+ import { ChatSources, isRemoteSource } from './source.js';
9
+ export class ChatController {
10
+ ports;
11
+ record;
12
+ lastResult = null;
13
+ busy = false;
14
+ closed = false;
15
+ abort = null;
16
+ paste = null;
17
+ store;
18
+ sources;
19
+ constructor(settings, ports) {
20
+ this.ports = ports;
21
+ this.record = newChat(settings);
22
+ this.store = ports.store || new ChatStore(ports.runner?.home || agentHome(ports.runner?.env), ports.runner?.env);
23
+ this.sources = ports.sources || new ChatSources(this.store.home, { env: ports.runner?.env });
24
+ }
25
+ get settings() { return this.record.settings; }
26
+ get pasting() { return this.paste !== null; }
27
+ get workspace() { return this.lastResult?.workspace || this.settings.root; }
28
+ say(text) { this.ports.output({ type: 'message', text: terminalText(redact(text, this.ports.runner?.env)) }); }
29
+ cancel() { this.abort?.abort(); }
30
+ close() { this.closed = true; this.cancel(); this.paste = null; this.ports.output({ type: 'exit' }); }
31
+ async persist() {
32
+ this.record.updatedAt = new Date().toISOString();
33
+ try {
34
+ await this.store.save(this.record);
35
+ return true;
36
+ }
37
+ catch (e) {
38
+ this.say(`Could not save this conversation: ${e instanceof Error ? e.message : e}. The agent run remains in agent runs.`);
39
+ return false;
40
+ }
41
+ }
42
+ async save() { return this.persist(); }
43
+ resetContext() { this.record.lastRun = null; this.lastResult = null; }
44
+ status() {
45
+ const s = this.settings;
46
+ return [...(s.sourceUrl ? [`GitHub: ${s.sourceUrl}`] : []), `Repository: ${s.root}`, `Workflow: ${s.mode}${s.pr ? ' · PR #' + s.pr : ''}${s.issue ? ' · issue #' + s.issue : ''}`,
47
+ `Model: ${s.model || 'Hermes profile default'}${s.provider ? ' (' + s.provider + ')' : ''}`,
48
+ `Permissions: files ${['implement', 'pr'].includes(s.mode) ? 'isolated workspace' : 'read only'} · checks ${s.checks ? 'on' : 'off'} · GitHub writes ${s.github ? 'on' : 'off'}`,
49
+ `Limits: ${s.timeout}s · ${s.maxTurns} agent turns`, `Conversation: ${this.record.id}`, `Session run: ${this.record.lastRun || 'new'}`,
50
+ `Workspace: ${this.workspace}`, ...(this.lastResult?.branch ? [`Branch: ${this.lastResult.branch}`] : [])].join('\n');
51
+ }
52
+ async accept(input) {
53
+ if (this.closed)
54
+ return;
55
+ const trimmed = input.trim(), command = slashInput(trimmed);
56
+ if (command?.name === 'exit' || command?.name === 'quit') {
57
+ this.close();
58
+ return;
59
+ }
60
+ if (command?.name === 'cancel') {
61
+ if (this.busy) {
62
+ this.cancel();
63
+ this.say('Cancelling…');
64
+ }
65
+ else
66
+ this.say('No active task.');
67
+ return;
68
+ }
69
+ if (this.busy) {
70
+ this.say('A task is running. Use /cancel or Ctrl-C before starting another.');
71
+ return;
72
+ }
73
+ if (this.paste !== null) {
74
+ if (trimmed === '/discard') {
75
+ this.paste = null;
76
+ this.say('Multiline message discarded.');
77
+ return;
78
+ }
79
+ if (trimmed === '/send') {
80
+ const body = this.paste.join('\n');
81
+ this.paste = null;
82
+ if (body.trim())
83
+ await this.submit(body);
84
+ return;
85
+ }
86
+ if (this.paste.join('\n').length + input.length + 1 > 16000) {
87
+ this.say('Message limit is 16000 characters. /send or /discard this message.');
88
+ return;
89
+ }
90
+ this.paste.push(input);
91
+ return;
92
+ }
93
+ if (!trimmed)
94
+ return;
95
+ this.busy = true;
96
+ this.abort = new AbortController();
97
+ try {
98
+ if (!command) {
99
+ if (trimmed.startsWith('/'))
100
+ throw new Error('Invalid slash command. Use /help.');
101
+ const first = trimmed.split(/\s+/)[0];
102
+ if (isRemoteSource(first)) {
103
+ await this.openSource(first);
104
+ const question = trimmed.slice(first.length).trim();
105
+ if (question)
106
+ await this.run(question);
107
+ return;
108
+ }
109
+ await this.run(trimmed);
110
+ return;
111
+ }
112
+ const { name, args, body } = command;
113
+ if (!name || name === 'help') {
114
+ this.say(chatHelp(args[0]));
115
+ return;
116
+ }
117
+ if (name === 'status') {
118
+ this.say(this.status());
119
+ return;
120
+ }
121
+ if (name === 'skills') {
122
+ this.say('Built-in workflow skills\n' + ['ask — repository Q&A', 'review — local and PR review', 'triage — investigate issues', 'implement — isolated code changes', 'pr — prepare or publish a draft PR', 'github — issues, discussions, labels, and CI'].map(s => ' /' + s).join('\n'));
123
+ return;
124
+ }
125
+ if (name === 'tools' || name === 'runs') {
126
+ this.say(await this.utility(name));
127
+ return;
128
+ }
129
+ if (name === 'run') {
130
+ const saved = await savedRun(args[0] || '', this.store.home);
131
+ if (saved.manifest.sourceRoot !== this.settings.root)
132
+ throw new Error('This run belongs to another repository. Switch with /repo first.');
133
+ this.say(`Run: ${saved.manifest.id} · ${saved.result?.status || 'unfinished'}\nWorkspace: ${saved.manifest.root}\n\n${saved.result?.answer || 'No saved final answer.'}`);
134
+ return;
135
+ }
136
+ if (name === 'export') {
137
+ this.say('Conversation exported: ' + await this.store.export(this.record));
138
+ return;
139
+ }
140
+ if (name === 'send' || name === 'discard') {
141
+ this.say('Use /paste first to compose a multiline message.');
142
+ return;
143
+ }
144
+ if (name === 'clear') {
145
+ this.ports.output({ type: 'clear' });
146
+ return;
147
+ }
148
+ if (name === 'paste') {
149
+ this.paste = [];
150
+ this.say('Multiline input. /send submits; /discard cancels.');
151
+ return;
152
+ }
153
+ if (name === 'new') {
154
+ this.record = newChat({ ...this.settings, pr: undefined, issue: undefined });
155
+ this.lastResult = null;
156
+ this.say('New conversation. ' + this.record.id);
157
+ await this.persist();
158
+ return;
159
+ }
160
+ if (name === 'history') {
161
+ this.say(historySummary(await this.store.list(this.settings.root)));
162
+ return;
163
+ }
164
+ if (name === 'resume') {
165
+ await this.resume(args[0] || '');
166
+ return;
167
+ }
168
+ if (name === 'repo' || name === 'clone') {
169
+ if (!body) {
170
+ this.say(name === 'clone' ? 'Usage: /clone <GitHub URL>' : (this.settings.sourceUrl || this.settings.root));
171
+ return;
172
+ }
173
+ if (name === 'clone' && (args.length !== 1 || !isRemoteSource(args[0])))
174
+ throw new Error('Usage: /clone <GitHub URL>');
175
+ await this.openSource(args.join(' '));
176
+ return;
177
+ }
178
+ if (name === 'pull') {
179
+ if (body)
180
+ throw new Error('Usage: /pull');
181
+ if (this.lastResult?.branch)
182
+ throw new Error('Use /new before pulling the source checkout. Your implementation workspace remains saved in agent runs.');
183
+ this.say(await this.sources.pull(this.settings.root, this.abort.signal, text => this.say(text)));
184
+ this.resetContext();
185
+ await this.persist();
186
+ this.say('Source refreshed. The next question starts a new agent session.');
187
+ return;
188
+ }
189
+ if (name === 'mode') {
190
+ if (!body) {
191
+ this.say(`Workflow: ${this.settings.mode}. Choose ${AGENT_MODES.join(', ')}.`);
192
+ return;
193
+ }
194
+ if (!AGENT_MODES.includes(body))
195
+ throw new Error('Usage: /mode ' + AGENT_MODES.join('|'));
196
+ if (body !== this.settings.mode) {
197
+ this.settings.mode = body;
198
+ this.settings.pr = undefined;
199
+ this.settings.issue = undefined;
200
+ this.resetContext();
201
+ }
202
+ this.say('Workflow: ' + body + '. Following messages use this workflow.');
203
+ await this.persist();
204
+ return;
205
+ }
206
+ if (name === 'permissions') {
207
+ if (!body) {
208
+ this.say(`Checks: ${this.settings.checks ? 'on' : 'off'} · GitHub writes: ${this.settings.github ? 'on' : 'off'}\n/permissions checks on|off · /permissions github on|off`);
209
+ return;
210
+ }
211
+ if (args.length !== 2 || !['checks', 'github'].includes(args[0]) || !['on', 'off'].includes(args[1]))
212
+ throw new Error('Usage: /permissions checks|github on|off');
213
+ const key = args[0], value = args[1] === 'on';
214
+ if (this.settings[key] !== value) {
215
+ this.settings[key] = value;
216
+ this.resetContext();
217
+ }
218
+ this.say(`${key === 'checks' ? 'Repository test execution' : 'GitHub writes'} ${value ? 'enabled' : 'disabled'}.`);
219
+ await this.persist();
220
+ return;
221
+ }
222
+ if (name === 'model') {
223
+ if (args.length > 2 || args.some(arg => arg.length > 512))
224
+ throw new Error('Usage: /model <name> [provider] (maximum 512 characters each)');
225
+ if (!body || body === 'configure') {
226
+ const changed = this.ports.chooseModel ? await this.ports.chooseModel(body === 'configure', this.abort.signal) : (this.say(await this.utility('model')), true);
227
+ if (!changed) {
228
+ this.say('Model selection closed. Current settings kept.');
229
+ return;
230
+ }
231
+ this.settings.model = undefined;
232
+ this.settings.provider = undefined;
233
+ }
234
+ else {
235
+ this.settings.model = args[0] === 'default' ? undefined : args[0];
236
+ this.settings.provider = args[0] === 'default' ? undefined : args[1];
237
+ }
238
+ this.resetContext();
239
+ this.say('Model: ' + (this.settings.model || 'Hermes profile default'));
240
+ await this.persist();
241
+ return;
242
+ }
243
+ if (name === 'limits') {
244
+ if (!body) {
245
+ this.say(`${this.settings.timeout}s · ${this.settings.maxTurns} agent turns`);
246
+ return;
247
+ }
248
+ const seconds = Number(args[0]), turns = args[1] === undefined ? this.settings.maxTurns : Number(args[1]);
249
+ if (args.length > 2 || !Number.isInteger(seconds) || seconds < 15 || seconds > 3600 || !Number.isInteger(turns) || turns < 1 || turns > 100)
250
+ throw new Error('Usage: /limits <15–3600 seconds> [1–100 turns]');
251
+ this.settings.timeout = seconds;
252
+ this.settings.maxTurns = turns;
253
+ await this.persist();
254
+ this.say(`${seconds}s · ${turns} agent turns`);
255
+ return;
256
+ }
257
+ if (name === 'setup' || name === 'doctor') {
258
+ this.say(await this.utility(name));
259
+ return;
260
+ }
261
+ if ((name === 'deep' || name === 'engines') && this.ports.analysis) {
262
+ const result = await this.ports.analysis(name, args, this.workspace, this.abort.signal, this.settings.checks);
263
+ this.abort.signal.throwIfAborted();
264
+ if (result.explain)
265
+ await this.run(result.explain, result.text);
266
+ else
267
+ this.say(result.text);
268
+ return;
269
+ }
270
+ if (BROWSE_COMMANDS.includes(name)) {
271
+ if (name === 'deep' && !this.settings.checks)
272
+ throw new Error('Enable /permissions checks on before running an external analyzer.');
273
+ if (!this.ports.browse)
274
+ throw new Error('Repository browsing is unavailable.');
275
+ this.say(await this.ports.browse(name, args, this.workspace, this.abort.signal));
276
+ return;
277
+ }
278
+ if (AGENT_MODES.includes(name)) {
279
+ const mode = name;
280
+ let task = body, pr, issue;
281
+ if (['review', 'triage'].includes(mode) && /^\d+(?:\s|$)/.test(body)) {
282
+ const match = /^(\d+)(?:\s+([\s\S]*))?$/.exec(body);
283
+ const id = Number(match[1]);
284
+ if (!Number.isSafeInteger(id) || id < 1)
285
+ throw new Error('Use a positive PR or issue number.');
286
+ if (mode === 'review')
287
+ pr = id;
288
+ else
289
+ issue = id;
290
+ task = match[2] || '';
291
+ }
292
+ task ||= mode === 'review' ? `Review ${pr ? 'PR #' + pr : 'local changes'} for actionable correctness and security issues.` : mode === 'triage' ? `Investigate ${issue ? 'issue #' + issue : 'open issues'} and propose a prioritized plan.` : '';
293
+ if (!task)
294
+ throw new Error(`Usage: /${mode} <task>`);
295
+ if (mode !== this.settings.mode || pr !== this.settings.pr || issue !== this.settings.issue)
296
+ this.resetContext();
297
+ Object.assign(this.settings, { mode, pr, issue });
298
+ await this.run(task);
299
+ return;
300
+ }
301
+ throw new Error(`Unknown command /${name}. Use /help; Tab completes commands.`);
302
+ }
303
+ catch (e) {
304
+ this.say(this.abort?.signal.aborted ? 'Task cancelled.' : e instanceof Error ? e.message : String(e));
305
+ }
306
+ finally {
307
+ this.busy = false;
308
+ this.abort = null;
309
+ }
310
+ }
311
+ async submit(task) {
312
+ this.busy = true;
313
+ this.abort = new AbortController();
314
+ try {
315
+ await this.run(task);
316
+ }
317
+ catch (e) {
318
+ this.say(e instanceof Error ? e.message : String(e));
319
+ }
320
+ finally {
321
+ this.busy = false;
322
+ this.abort = null;
323
+ }
324
+ }
325
+ async utility(name) {
326
+ if (!this.ports.utility)
327
+ throw new Error(`Use onboarder agent ${name} in a terminal.`);
328
+ return this.ports.utility(name, this.abort.signal);
329
+ }
330
+ async openSource(target) {
331
+ const source = await this.sources.open(target, this.settings.root, this.abort.signal, text => this.say(text));
332
+ this.abort.signal.throwIfAborted();
333
+ await this.persist();
334
+ this.abort.signal.throwIfAborted();
335
+ this.record = newChat({ ...this.settings, root: source.root, sourceUrl: source.sourceUrl, pr: undefined, issue: undefined });
336
+ this.lastResult = null;
337
+ this.say(`Repository: ${source.sourceUrl || source.root}\nNew conversation. Type your question.`);
338
+ await this.persist();
339
+ }
340
+ async resume(id) {
341
+ const record = await this.store.load(id);
342
+ if (record.settings.root !== this.settings.root)
343
+ throw new Error('This conversation belongs to another repository. Switch with /repo first.');
344
+ let result = null;
345
+ if (record.lastRun) {
346
+ const saved = await savedRun(record.lastRun, this.store.home);
347
+ if (saved.manifest.sourceRoot !== this.settings.root || saved.manifest.mode !== record.settings.mode || !saved.result?.sessionId)
348
+ throw new Error('This conversation has no resumable Hermes session. Use /new.');
349
+ await fs.access(saved.manifest.root);
350
+ if (this.settings.checks && !saved.manifest.permissions.checks || this.settings.github && !saved.manifest.permissions.github)
351
+ throw new Error('Resume cannot expand permissions. Turn them off first or use /new.');
352
+ result = saved.result;
353
+ }
354
+ // Restore the model and task target, while retaining the permissions chosen in this application.
355
+ const changed = record.settings.checks !== this.settings.checks || record.settings.github !== this.settings.github;
356
+ record.settings.checks = this.settings.checks;
357
+ record.settings.github = this.settings.github;
358
+ if (changed)
359
+ record.lastRun = null;
360
+ this.record = record;
361
+ this.lastResult = changed ? null : result;
362
+ this.say(`Resumed conversation ${id}.\n${this.status()}${changed ? '\nPermissions changed; the next task starts a new Hermes session.' : ''}`);
363
+ const last = record.turns.at(-1);
364
+ if (last)
365
+ this.say('Last answer\n' + last.answer);
366
+ }
367
+ async run(task, displayPrompt = task) {
368
+ if (!task.trim() || task.length > 16000)
369
+ throw new Error('Messages must contain 1–16000 characters.');
370
+ const s = this.settings, start = Date.now();
371
+ const request = { root: s.root, mode: s.mode, task, model: s.model, provider: s.provider, pr: s.pr, issue: s.issue,
372
+ base: s.base, allowChecks: s.checks, allowGithubWrites: s.github, timeoutSeconds: s.timeout, maxTurns: s.maxTurns,
373
+ ...(this.record.lastRun ? { resume: this.record.lastRun } : {}) };
374
+ this.ports.output({ type: 'start', prompt: terminalText(redact(displayPrompt, this.ports.runner?.env)), mode: s.mode });
375
+ let result, sessionStarted = false;
376
+ try {
377
+ result = await (this.ports.run || runAgent)(request, { ...this.ports.runner, signal: this.abort.signal,
378
+ onEvent: event => {
379
+ if (['text', 'tool_use', 'tool_result'].includes(event.type))
380
+ sessionStarted = true;
381
+ this.ports.output({ type: 'event', event });
382
+ } });
383
+ }
384
+ catch (e) {
385
+ // Validation can reject before a run exists. Finish the UI without inventing a saved run.
386
+ this.say('Task could not start: ' + (e instanceof Error ? e.message : String(e)));
387
+ return;
388
+ }
389
+ if ('dryRun' in result)
390
+ throw new Error('Chat requires a live agent result.');
391
+ this.lastResult = result;
392
+ // Failed startup can emit an ID without creating a usable Hermes session.
393
+ // Keep the previous working session on failure; new failures start fresh.
394
+ if (result.sessionId && (result.status === 'completed' || result.status === 'cancelled' && sessionStarted))
395
+ this.record.lastRun = result.id;
396
+ this.record.turns.push({ at: new Date().toISOString(), prompt: displayPrompt, answer: result.answer, run: result.id, status: result.status });
397
+ this.record.turns = this.record.turns.slice(-100);
398
+ this.ports.output({ type: 'end', result, elapsed: Date.now() - start });
399
+ await this.persist();
400
+ }
401
+ }
402
+ //# sourceMappingURL=controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../src/cli/chat/controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport { AGENT_MODES, type AgentMode, type AgentRequest, type AgentEvent, type AgentResult } from '../agent/contracts.js';\nimport { runAgent, savedRun, type RunnerOptions } from '../agent/runner.js';\nimport { agentHome } from '../agent/config.js';\nimport { redact, terminalText } from '../agent/process.js';\nimport { ChatStore, newChat, historySummary, type ChatRecord, type ChatSettings } from './store.js';\nimport { slashInput, chatHelp, BROWSE_COMMANDS } from './commands.js';\nimport { ChatSources, isRemoteSource } from './source.js';\n\nexport type ChatOutput =\n | { type: 'message'; text: string }\n | { type: 'start'; prompt: string; mode: AgentMode }\n | { type: 'event'; event: AgentEvent }\n | { type: 'end'; result: AgentResult; elapsed: number }\n | { type: 'clear' | 'exit' };\nexport interface ChatPorts {\n output: (event: ChatOutput) => void;\n run?: typeof runAgent;\n browse?: (name: string, args: string[], root: string, signal: AbortSignal) => Promise<string>;\n utility?: (name: ChatUtility, signal: AbortSignal) => Promise<string>;\n chooseModel?: (configure: boolean, signal: AbortSignal) => Promise<boolean>;\n analysis?: (name: string, args: string[], root: string, signal: AbortSignal, checks: boolean) => Promise<{ text: string; explain?: string }>;\n store?: ChatStore; runner?: Omit<RunnerOptions, 'onEvent' | 'signal'>;\n sources?: ChatSources;\n}\nexport type ChatUtility = 'doctor' | 'setup' | 'model' | 'tools' | 'runs';\nexport class ChatController {\n record: ChatRecord;\n lastResult: AgentResult | null = null;\n busy = false;\n closed = false;\n private abort: AbortController | null = null;\n private paste: string[] | null = null;\n private store: ChatStore;\n private sources: ChatSources;\n constructor(settings: ChatSettings, private ports: ChatPorts) {\n this.record = newChat(settings);\n this.store = ports.store || new ChatStore(ports.runner?.home || agentHome(ports.runner?.env), ports.runner?.env);\n this.sources = ports.sources || new ChatSources(this.store.home, { env: ports.runner?.env });\n }\n get settings() { return this.record.settings; }\n get pasting() { return this.paste !== null; }\n get workspace() { return this.lastResult?.workspace || this.settings.root; }\n private say(text: string) { this.ports.output({ type: 'message', text: terminalText(redact(text, this.ports.runner?.env)) }); }\n cancel() { this.abort?.abort(); }\n close() { this.closed = true; this.cancel(); this.paste = null; this.ports.output({ type: 'exit' }); }\n private async persist() {\n this.record.updatedAt = new Date().toISOString();\n try { await this.store.save(this.record); return true; }\n catch (e) { this.say(`Could not save this conversation: ${e instanceof Error ? e.message : e}. The agent run remains in agent runs.`); return false; }\n }\n async save() { return this.persist(); }\n private resetContext() { this.record.lastRun = null; this.lastResult = null; }\n status(): string {\n const s = this.settings;\n return [...(s.sourceUrl ? [`GitHub: ${s.sourceUrl}`] : []), `Repository: ${s.root}`, `Workflow: ${s.mode}${s.pr ? ' · PR #' + s.pr : ''}${s.issue ? ' · issue #' + s.issue : ''}`,\n `Model: ${s.model || 'Hermes profile default'}${s.provider ? ' (' + s.provider + ')' : ''}`,\n `Permissions: files ${['implement', 'pr'].includes(s.mode) ? 'isolated workspace' : 'read only'} · checks ${s.checks ? 'on' : 'off'} · GitHub writes ${s.github ? 'on' : 'off'}`,\n `Limits: ${s.timeout}s · ${s.maxTurns} agent turns`, `Conversation: ${this.record.id}`, `Session run: ${this.record.lastRun || 'new'}`,\n `Workspace: ${this.workspace}`, ...(this.lastResult?.branch ? [`Branch: ${this.lastResult.branch}`] : [])].join('\\n');\n }\n async accept(input: string): Promise<void> {\n if (this.closed) return;\n const trimmed = input.trim(), command = slashInput(trimmed);\n if (command?.name === 'exit' || command?.name === 'quit') { this.close(); return; }\n if (command?.name === 'cancel') { if (this.busy) { this.cancel(); this.say('Cancelling…'); } else this.say('No active task.'); return; }\n if (this.busy) { this.say('A task is running. Use /cancel or Ctrl-C before starting another.'); return; }\n if (this.paste !== null) {\n if (trimmed === '/discard') { this.paste = null; this.say('Multiline message discarded.'); return; }\n if (trimmed === '/send') { const body = this.paste.join('\\n'); this.paste = null; if (body.trim()) await this.submit(body); return; }\n if (this.paste.join('\\n').length + input.length + 1 > 16000) { this.say('Message limit is 16000 characters. /send or /discard this message.'); return; }\n this.paste.push(input); return;\n }\n if (!trimmed) return;\n this.busy = true; this.abort = new AbortController();\n try {\n if (!command) {\n if (trimmed.startsWith('/')) throw new Error('Invalid slash command. Use /help.');\n const first = trimmed.split(/\\s+/)[0]!;\n if (isRemoteSource(first)) {\n await this.openSource(first);\n const question = trimmed.slice(first.length).trim(); if (question) await this.run(question);\n return;\n }\n await this.run(trimmed); return;\n }\n const { name, args, body } = command;\n if (!name || name === 'help') { this.say(chatHelp(args[0])); return; }\n if (name === 'status') { this.say(this.status()); return; }\n if (name === 'skills') { this.say('Built-in workflow skills\\n' + ['ask — repository Q&A', 'review — local and PR review', 'triage — investigate issues', 'implement — isolated code changes', 'pr — prepare or publish a draft PR', 'github — issues, discussions, labels, and CI'].map(s => ' /' + s).join('\\n')); return; }\n if (name === 'tools' || name === 'runs') { this.say(await this.utility(name)); return; }\n if (name === 'run') {\n const saved = await savedRun(args[0] || '', this.store.home);\n if (saved.manifest.sourceRoot !== this.settings.root) throw new Error('This run belongs to another repository. Switch with /repo first.');\n this.say(`Run: ${saved.manifest.id} · ${saved.result?.status || 'unfinished'}\\nWorkspace: ${saved.manifest.root}\\n\\n${saved.result?.answer || 'No saved final answer.'}`); return;\n }\n if (name === 'export') { this.say('Conversation exported: ' + await this.store.export(this.record)); return; }\n if (name === 'send' || name === 'discard') { this.say('Use /paste first to compose a multiline message.'); return; }\n if (name === 'clear') { this.ports.output({ type: 'clear' }); return; }\n if (name === 'paste') { this.paste = []; this.say('Multiline input. /send submits; /discard cancels.'); return; }\n if (name === 'new') { this.record = newChat({ ...this.settings, pr: undefined, issue: undefined }); this.lastResult = null; this.say('New conversation. ' + this.record.id); await this.persist(); return; }\n if (name === 'history') { this.say(historySummary(await this.store.list(this.settings.root))); return; }\n if (name === 'resume') { await this.resume(args[0] || ''); return; }\n if (name === 'repo' || name === 'clone') {\n if (!body) { this.say(name === 'clone' ? 'Usage: /clone <GitHub URL>' : (this.settings.sourceUrl || this.settings.root)); return; }\n if (name === 'clone' && (args.length !== 1 || !isRemoteSource(args[0]!))) throw new Error('Usage: /clone <GitHub URL>');\n await this.openSource(args.join(' ')); return;\n }\n if (name === 'pull') {\n if (body) throw new Error('Usage: /pull');\n if (this.lastResult?.branch) throw new Error('Use /new before pulling the source checkout. Your implementation workspace remains saved in agent runs.');\n this.say(await this.sources.pull(this.settings.root, this.abort.signal, text => this.say(text)));\n this.resetContext(); await this.persist(); this.say('Source refreshed. The next question starts a new agent session.'); return;\n }\n if (name === 'mode') {\n if (!body) { this.say(`Workflow: ${this.settings.mode}. Choose ${AGENT_MODES.join(', ')}.`); return; }\n if (!AGENT_MODES.includes(body as AgentMode)) throw new Error('Usage: /mode ' + AGENT_MODES.join('|'));\n if (body !== this.settings.mode) { this.settings.mode = body as AgentMode; this.settings.pr = undefined; this.settings.issue = undefined; this.resetContext(); }\n this.say('Workflow: ' + body + '. Following messages use this workflow.'); await this.persist(); return;\n }\n if (name === 'permissions') {\n if (!body) { this.say(`Checks: ${this.settings.checks ? 'on' : 'off'} · GitHub writes: ${this.settings.github ? 'on' : 'off'}\\n/permissions checks on|off · /permissions github on|off`); return; }\n if (args.length !== 2 || !['checks', 'github'].includes(args[0]!) || !['on', 'off'].includes(args[1]!)) throw new Error('Usage: /permissions checks|github on|off');\n const key = args[0] as 'checks' | 'github', value = args[1] === 'on';\n if (this.settings[key] !== value) { this.settings[key] = value; this.resetContext(); }\n this.say(`${key === 'checks' ? 'Repository test execution' : 'GitHub writes'} ${value ? 'enabled' : 'disabled'}.`); await this.persist(); return;\n }\n if (name === 'model') {\n if (args.length > 2 || args.some(arg => arg.length > 512)) throw new Error('Usage: /model <name> [provider] (maximum 512 characters each)');\n if (!body || body === 'configure') {\n const changed = this.ports.chooseModel ? await this.ports.chooseModel(body === 'configure', this.abort.signal) : (this.say(await this.utility('model')), true);\n if (!changed) { this.say('Model selection closed. Current settings kept.'); return; }\n this.settings.model = undefined; this.settings.provider = undefined;\n }\n else { this.settings.model = args[0] === 'default' ? undefined : args[0]; this.settings.provider = args[0] === 'default' ? undefined : args[1]; }\n this.resetContext(); this.say('Model: ' + (this.settings.model || 'Hermes profile default')); await this.persist(); return;\n }\n if (name === 'limits') {\n if (!body) { this.say(`${this.settings.timeout}s · ${this.settings.maxTurns} agent turns`); return; }\n const seconds = Number(args[0]), turns = args[1] === undefined ? this.settings.maxTurns : Number(args[1]);\n if (args.length > 2 || !Number.isInteger(seconds) || seconds < 15 || seconds > 3600 || !Number.isInteger(turns) || turns < 1 || turns > 100) throw new Error('Usage: /limits <15–3600 seconds> [1–100 turns]');\n this.settings.timeout = seconds; this.settings.maxTurns = turns; await this.persist(); this.say(`${seconds}s · ${turns} agent turns`); return;\n }\n if (name === 'setup' || name === 'doctor') { this.say(await this.utility(name)); return; }\n if ((name === 'deep' || name === 'engines') && this.ports.analysis) {\n const result = await this.ports.analysis(name, args, this.workspace, this.abort.signal, this.settings.checks);\n this.abort.signal.throwIfAborted();\n if (result.explain) await this.run(result.explain, result.text); else this.say(result.text);\n return;\n }\n if (BROWSE_COMMANDS.includes(name as typeof BROWSE_COMMANDS[number])) {\n if (name === 'deep' && !this.settings.checks) throw new Error('Enable /permissions checks on before running an external analyzer.');\n if (!this.ports.browse) throw new Error('Repository browsing is unavailable.');\n this.say(await this.ports.browse(name, args, this.workspace, this.abort.signal)); return;\n }\n if (AGENT_MODES.includes(name as AgentMode)) {\n const mode = name as AgentMode;\n let task = body, pr: number | undefined, issue: number | undefined;\n if (['review', 'triage'].includes(mode) && /^\\d+(?:\\s|$)/.test(body)) {\n const match = /^(\\d+)(?:\\s+([\\s\\S]*))?$/.exec(body)!;\n const id = Number(match[1]); if (!Number.isSafeInteger(id) || id < 1) throw new Error('Use a positive PR or issue number.');\n if (mode === 'review') pr = id; else issue = id;\n task = match[2] || '';\n }\n task ||= mode === 'review' ? `Review ${pr ? 'PR #' + pr : 'local changes'} for actionable correctness and security issues.` : mode === 'triage' ? `Investigate ${issue ? 'issue #' + issue : 'open issues'} and propose a prioritized plan.` : '';\n if (!task) throw new Error(`Usage: /${mode} <task>`);\n if (mode !== this.settings.mode || pr !== this.settings.pr || issue !== this.settings.issue) this.resetContext();\n Object.assign(this.settings, { mode, pr, issue }); await this.run(task); return;\n }\n throw new Error(`Unknown command /${name}. Use /help; Tab completes commands.`);\n } catch (e) { this.say(this.abort?.signal.aborted ? 'Task cancelled.' : e instanceof Error ? e.message : String(e)); }\n finally { this.busy = false; this.abort = null; }\n }\n private async submit(task: string) {\n this.busy = true; this.abort = new AbortController();\n try { await this.run(task); } catch (e) { this.say(e instanceof Error ? e.message : String(e)); }\n finally { this.busy = false; this.abort = null; }\n }\n private async utility(name: ChatUtility) {\n if (!this.ports.utility) throw new Error(`Use onboarder agent ${name} in a terminal.`);\n return this.ports.utility(name, this.abort!.signal);\n }\n private async openSource(target: string) {\n const source = await this.sources.open(target, this.settings.root, this.abort!.signal, text => this.say(text));\n this.abort!.signal.throwIfAborted();\n await this.persist();\n this.abort!.signal.throwIfAborted();\n this.record = newChat({ ...this.settings, root: source.root, sourceUrl: source.sourceUrl, pr: undefined, issue: undefined });\n this.lastResult = null;\n this.say(`Repository: ${source.sourceUrl || source.root}\\nNew conversation. Type your question.`);\n await this.persist();\n }\n async resume(id: string) {\n const record = await this.store.load(id);\n if (record.settings.root !== this.settings.root) throw new Error('This conversation belongs to another repository. Switch with /repo first.');\n let result: AgentResult | null = null;\n if (record.lastRun) {\n const saved = await savedRun(record.lastRun, this.store.home);\n if (saved.manifest.sourceRoot !== this.settings.root || saved.manifest.mode !== record.settings.mode || !saved.result?.sessionId) throw new Error('This conversation has no resumable Hermes session. Use /new.');\n await fs.access(saved.manifest.root);\n if (this.settings.checks && !saved.manifest.permissions.checks || this.settings.github && !saved.manifest.permissions.github) throw new Error('Resume cannot expand permissions. Turn them off first or use /new.');\n result = saved.result;\n }\n // Restore the model and task target, while retaining the permissions chosen in this application.\n const changed = record.settings.checks !== this.settings.checks || record.settings.github !== this.settings.github;\n record.settings.checks = this.settings.checks; record.settings.github = this.settings.github;\n if (changed) record.lastRun = null;\n this.record = record; this.lastResult = changed ? null : result;\n this.say(`Resumed conversation ${id}.\\n${this.status()}${changed ? '\\nPermissions changed; the next task starts a new Hermes session.' : ''}`);\n const last = record.turns.at(-1); if (last) this.say('Last answer\\n' + last.answer);\n }\n private async run(task: string, displayPrompt = task) {\n if (!task.trim() || task.length > 16000) throw new Error('Messages must contain 1–16000 characters.');\n const s = this.settings, start = Date.now();\n const request: AgentRequest = { root: s.root, mode: s.mode, task, model: s.model, provider: s.provider, pr: s.pr, issue: s.issue,\n base: s.base, allowChecks: s.checks, allowGithubWrites: s.github, timeoutSeconds: s.timeout, maxTurns: s.maxTurns,\n ...(this.record.lastRun ? { resume: this.record.lastRun } : {}) };\n this.ports.output({ type: 'start', prompt: terminalText(redact(displayPrompt, this.ports.runner?.env)), mode: s.mode });\n let result: Awaited<ReturnType<typeof runAgent>>, sessionStarted = false;\n try {\n result = await (this.ports.run || runAgent)(request, { ...this.ports.runner, signal: this.abort!.signal,\n onEvent: event => {\n if (['text', 'tool_use', 'tool_result'].includes(event.type)) sessionStarted = true;\n this.ports.output({ type: 'event', event });\n } });\n } catch (e) {\n // Validation can reject before a run exists. Finish the UI without inventing a saved run.\n this.say('Task could not start: ' + (e instanceof Error ? e.message : String(e))); return;\n }\n if ('dryRun' in result) throw new Error('Chat requires a live agent result.');\n this.lastResult = result;\n // Failed startup can emit an ID without creating a usable Hermes session.\n // Keep the previous working session on failure; new failures start fresh.\n if (result.sessionId && (result.status === 'completed' || result.status === 'cancelled' && sessionStarted)) this.record.lastRun = result.id;\n this.record.turns.push({ at: new Date().toISOString(), prompt: displayPrompt, answer: result.answer, run: result.id, status: result.status });\n this.record.turns = this.record.turns.slice(-100);\n this.ports.output({ type: 'end', result, elapsed: Date.now() - start });\n await this.persist();\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ /** Original Onboarder mark: a compass inside an O, with a repository branch. */
2
+ export declare const ONBOARDER_MARK: string[];
3
+ export declare const ONBOARDER_COMPACT_MARK: string[];
@@ -0,0 +1,14 @@
1
+ /** Original Onboarder mark: a compass inside an O, with a repository branch. */
2
+ export const ONBOARDER_MARK = [
3
+ ' ▄██████▄',
4
+ ' ▄██▀ ▀██▄',
5
+ ' ▄██ ▲ ██▄',
6
+ ' ██ │ ██',
7
+ ' ██ ●───┼───● ██',
8
+ ' ██ │ ██',
9
+ ' ▀██ ● ██▀',
10
+ ' ▀██▄ ▄██▀',
11
+ ' ▀██████▀',
12
+ ];
13
+ export const ONBOARDER_COMPACT_MARK = [' ╭─────╮', ' │ ▲ │', ' │ ●┼● │', ' │ ● │', ' ╰─────╯'];
14
+ //# sourceMappingURL=logo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logo.js","sourceRoot":"","sources":["../../src/cli/chat/logo.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,mBAAmB;IACnB,sBAAsB;IACtB,wBAAwB;IACxB,wBAAwB;IACxB,wBAAwB;IACxB,wBAAwB;IACxB,wBAAwB;IACxB,sBAAsB;IACtB,mBAAmB;CACpB,CAAC;AACF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC","sourcesContent":["/** Original Onboarder mark: a compass inside an O, with a repository branch. */\nexport const ONBOARDER_MARK = [\n ' ▄██████▄',\n ' ▄██▀ ▀██▄',\n ' ▄██ ▲ ██▄',\n ' ██ │ ██',\n ' ██ ●───┼───● ██',\n ' ██ │ ██',\n ' ▀██ ● ██▀',\n ' ▀██▄ ▄██▀',\n ' ▀██████▀',\n];\nexport const ONBOARDER_COMPACT_MARK = [' ╭─────╮', ' │ ▲ │', ' │ ●┼● │', ' │ ● │', ' ╰─────╯'];\n"]}
@@ -0,0 +1,18 @@
1
+ import { runProcess } from '../agent/process.js';
2
+ export interface ModelProvider {
3
+ id: string;
4
+ name: string;
5
+ models: string[];
6
+ }
7
+ export declare class HermesModels {
8
+ private home;
9
+ private env;
10
+ private execute;
11
+ constructor(home?: string, env?: NodeJS.ProcessEnv, execute?: typeof runProcess);
12
+ private request;
13
+ catalog(signal: AbortSignal): Promise<ModelProvider[]>;
14
+ select(model: string, provider: string, signal: AbortSignal): Promise<{
15
+ model: string;
16
+ provider: string;
17
+ }>;
18
+ }
@@ -0,0 +1,88 @@
1
+ import { agentHome, hermesBinary, hermesEnvironment, setupAgent } from '../agent/config.js';
2
+ import { runProcess, terminalText } from '../agent/process.js';
3
+ // Use the installed Hermes catalog, credential resolver and persistence logic.
4
+ // Only display fields cross this boundary; keys and endpoint credentials stay in Python.
5
+ const BRIDGE = String.raw `
6
+ import contextlib, io, json, sys
7
+ request = json.load(sys.stdin)
8
+ with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
9
+ from hermes_cli.config import load_config
10
+ from hermes_cli.model_switch import switch_model, persist_model_selection
11
+ from hermes_cli.model_switch_providers import list_picker_providers
12
+ config = load_config()
13
+ model = config.get('model') or {}
14
+ if not isinstance(model, dict): model = {'default': str(model)}
15
+ if request['action'] == 'catalog':
16
+ import inspect
17
+ kwargs = dict(current_provider=model.get('provider') or '', current_model=model.get('default') or '',
18
+ current_base_url=model.get('base_url') or '', user_providers=config.get('providers'),
19
+ custom_providers=config.get('custom_providers'), max_models=None, non_blocking_catalogs=True,
20
+ probe_custom_providers=False, probe_current_custom_provider=False,
21
+ excluded_providers=(config.get('model_catalog') or {}).get('excluded_providers'))
22
+ accepted = inspect.signature(list_picker_providers).parameters
23
+ rows = list_picker_providers(**{k: v for k, v in kwargs.items() if k in accepted})
24
+ reply = {'providers': [{'id': str(p.get('slug') or ''), 'name': str(p.get('name') or p.get('slug') or ''),
25
+ 'models': [m for m in p.get('models', []) if isinstance(m, str)]} for p in rows]}
26
+ else:
27
+ result = switch_model(request['model'], current_provider=model.get('provider') or '',
28
+ current_model=model.get('default') or '', current_base_url=model.get('base_url') or '',
29
+ current_api_key=model.get('api_key') or '', explicit_provider=request['provider'],
30
+ user_providers=config.get('providers'), custom_providers=config.get('custom_providers'))
31
+ if result.success: persist_model_selection(result)
32
+ reply = {'success': bool(result.success), 'model': result.new_model if result.success else '',
33
+ 'provider': result.target_provider if result.success else '',
34
+ 'error': '' if result.success else 'Hermes could not activate this model. Configure its provider with /model configure.'}
35
+ print('ONBOARDER_MODEL_JSON:' + json.dumps(reply))
36
+ `;
37
+ export class HermesModels {
38
+ home;
39
+ env;
40
+ execute;
41
+ constructor(home = agentHome(), env = process.env, execute = runProcess) {
42
+ this.home = home;
43
+ this.env = env;
44
+ this.execute = execute;
45
+ }
46
+ async request(request, signal) {
47
+ await setupAgent(this.home, this.env);
48
+ const env = hermesEnvironment(this.home, this.env);
49
+ // Hermes publishes its installation-bound Python/bootstrap argv. Retain that
50
+ // bootstrap and replace only the verified entry point with our fixed bridge.
51
+ const launch = await this.execute(hermesBinary(this.env), ['--print-runtime-command'], { env, signal, timeoutMs: 10000, maxBytes: 64000 });
52
+ let command;
53
+ try {
54
+ command = JSON.parse(launch.stdout.trim());
55
+ }
56
+ catch {
57
+ throw new Error('Use /model configure with this Hermes installation.');
58
+ }
59
+ if (launch.code || !Array.isArray(command) || command.length !== 4 || command.some(v => typeof v !== 'string') || command[1] !== '-I' || command[2] !== '-c')
60
+ throw new Error('This Hermes launcher needs /model configure.');
61
+ const entry = /runpy\.run_module\(['"]hermes_cli\.main['"],\s*run_name=['"]__main__['"],\s*alter_sys=True\)\s*$/.exec(command[3]);
62
+ if (!entry || !command[3].slice(0, entry.index).includes('import hermes_bootstrap;'))
63
+ throw new Error('This Hermes launcher needs /model configure.');
64
+ const bootstrap = command[3].slice(0, entry.index) + 'exec(sys.argv[1])';
65
+ const response = await this.execute(command[0], ['-I', '-c', bootstrap, BRIDGE], { env, signal, input: JSON.stringify(request), timeoutMs: 30000, maxBytes: 2 * 1024 * 1024 });
66
+ const line = response.stdout.split('\n').find(s => s.startsWith('ONBOARDER_MODEL_JSON:'));
67
+ if (response.code || !line)
68
+ throw new Error('The model picker is unavailable. Choose Configure provider for the full Hermes setup.');
69
+ return JSON.parse(line.slice('ONBOARDER_MODEL_JSON:'.length));
70
+ }
71
+ async catalog(signal) {
72
+ const value = await this.request({ action: 'catalog' }, signal);
73
+ if (!Array.isArray(value.providers))
74
+ throw new Error('Invalid Hermes model catalog.');
75
+ return value.providers.slice(0, 200).filter((p) => typeof p.id === 'string' && p.id && typeof p.name === 'string' && Array.isArray(p.models))
76
+ .map((p) => ({ id: terminalText(p.id).slice(0, 512), name: terminalText(p.name).slice(0, 512),
77
+ models: [...new Set(p.models.filter((m) => typeof m === 'string' && m.length > 0 && m.length <= 512).map((m) => terminalText(m)))].slice(0, 10000) }));
78
+ }
79
+ async select(model, provider, signal) {
80
+ if (!model || !provider || model.length > 512 || provider.length > 512)
81
+ throw new Error('Choose a model and provider from the picker.');
82
+ const result = await this.request({ action: 'select', model, provider }, signal);
83
+ if (result.success !== true || typeof result.model !== 'string' || typeof result.provider !== 'string')
84
+ throw new Error('Hermes could not activate this model. Use /model configure to check its credentials.');
85
+ return { model: terminalText(result.model).slice(0, 512), provider: terminalText(result.provider).slice(0, 512) };
86
+ }
87
+ }
88
+ //# sourceMappingURL=models.js.map