@sickr/cli 0.9.12 → 0.9.14
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/dist/run.js +45 -2
- package/package.json +1 -1
package/dist/run.js
CHANGED
|
@@ -24,7 +24,7 @@ import { readFileSync, writeFileSync, appendFileSync, mkdirSync, existsSync, rea
|
|
|
24
24
|
import { homedir } from 'node:os';
|
|
25
25
|
import { join } from 'node:path';
|
|
26
26
|
import { randomUUID } from 'node:crypto';
|
|
27
|
-
import { execFileSync } from 'node:child_process';
|
|
27
|
+
import { execFileSync, spawn } from 'node:child_process';
|
|
28
28
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
29
29
|
import { readCredentials } from './auth.js';
|
|
30
30
|
import { runsDir } from './recorder.js';
|
|
@@ -143,6 +143,7 @@ export function stripAnsi(input) {
|
|
|
143
143
|
export function cleanPtyResponse(input, lastPrompt = '') {
|
|
144
144
|
const prompt = lastPrompt.trim();
|
|
145
145
|
return stripAnsi(input)
|
|
146
|
+
.replace(/[\u2800-\u28ff]/g, '')
|
|
146
147
|
.replace(/\r/g, '\n')
|
|
147
148
|
.split('\n')
|
|
148
149
|
.map((line) => line.replace(/^>+\s?/, '').trimEnd())
|
|
@@ -152,7 +153,7 @@ export function cleanPtyResponse(input, lastPrompt = '') {
|
|
|
152
153
|
return false;
|
|
153
154
|
if (prompt && trimmed === prompt)
|
|
154
155
|
return false;
|
|
155
|
-
if (trimmed
|
|
156
|
+
if (trimmed.includes('Send a message (/? for help)'))
|
|
156
157
|
return false;
|
|
157
158
|
return true;
|
|
158
159
|
})
|
|
@@ -166,6 +167,7 @@ export class HooklessPtyEventSynth {
|
|
|
166
167
|
inputBuffer = '';
|
|
167
168
|
outputBuffer = '';
|
|
168
169
|
lastPrompt = '';
|
|
170
|
+
awaitingResponse = false;
|
|
169
171
|
responseTimer = null;
|
|
170
172
|
constructor(identity, send, responseDelayMs = 700) {
|
|
171
173
|
this.identity = identity;
|
|
@@ -193,9 +195,13 @@ export class HooklessPtyEventSynth {
|
|
|
193
195
|
if (!prompt)
|
|
194
196
|
return;
|
|
195
197
|
this.lastPrompt = prompt;
|
|
198
|
+
this.outputBuffer = '';
|
|
199
|
+
this.awaitingResponse = true;
|
|
196
200
|
this.sendEvent('prompt', 'Prompt', prompt);
|
|
197
201
|
}
|
|
198
202
|
observeOutput(chunk) {
|
|
203
|
+
if (!this.awaitingResponse)
|
|
204
|
+
return;
|
|
199
205
|
this.outputBuffer += chunk;
|
|
200
206
|
if (this.responseTimer)
|
|
201
207
|
clearTimeout(this.responseTimer);
|
|
@@ -210,6 +216,7 @@ export class HooklessPtyEventSynth {
|
|
|
210
216
|
this.outputBuffer = '';
|
|
211
217
|
if (!detail)
|
|
212
218
|
return;
|
|
219
|
+
this.awaitingResponse = false;
|
|
213
220
|
this.sendEvent('response', this.identity.agent, detail);
|
|
214
221
|
}
|
|
215
222
|
sendEvent(kind, label, detail) {
|
|
@@ -396,6 +403,40 @@ export function providerArgsFor(agent, existingArgs) {
|
|
|
396
403
|
return ['run', model, ...existingArgs];
|
|
397
404
|
return existingArgs;
|
|
398
405
|
}
|
|
406
|
+
function ollamaHost() {
|
|
407
|
+
return process.env.OLLAMA_HOST || 'http://127.0.0.1:11434';
|
|
408
|
+
}
|
|
409
|
+
async function ollamaServerReady() {
|
|
410
|
+
try {
|
|
411
|
+
const res = await fetch(`${ollamaHost().replace(/\/$/, '')}/api/tags`, { signal: AbortSignal.timeout(1000) });
|
|
412
|
+
return res.ok;
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
export async function ensureOllamaServer(agentBin, opts = {}) {
|
|
419
|
+
if (await ollamaServerReady())
|
|
420
|
+
return;
|
|
421
|
+
const needsShell = process.platform === 'win32' && /\.(cmd|bat)$/i.test(agentBin);
|
|
422
|
+
const child = spawn(agentBin, ['serve'], {
|
|
423
|
+
cwd: process.cwd(),
|
|
424
|
+
env: process.env,
|
|
425
|
+
detached: true,
|
|
426
|
+
stdio: 'ignore',
|
|
427
|
+
windowsHide: true,
|
|
428
|
+
shell: needsShell,
|
|
429
|
+
});
|
|
430
|
+
child.unref();
|
|
431
|
+
const attempts = opts.attempts ?? 20;
|
|
432
|
+
const delayMs = opts.delayMs ?? 250;
|
|
433
|
+
for (let i = 0; i < attempts; i++) {
|
|
434
|
+
await sleep(delayMs);
|
|
435
|
+
if (await ollamaServerReady())
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
throw new Error('Ollama server did not start. Try running `ollama serve` in another terminal, then retry `sickr run ollama`.');
|
|
439
|
+
}
|
|
399
440
|
export async function startRun(opts) {
|
|
400
441
|
const creds = readCredentials();
|
|
401
442
|
if (!creds) {
|
|
@@ -417,6 +458,8 @@ export async function startRun(opts) {
|
|
|
417
458
|
ensureRecordingHooks(opts.agent);
|
|
418
459
|
const agentBin = resolveAgent(opts.agent);
|
|
419
460
|
const provider = providerForAgent(opts.agent);
|
|
461
|
+
if (provider === 'ollama')
|
|
462
|
+
await ensureOllamaServer(agentBin);
|
|
420
463
|
const agentLabel = provider ? PROVIDERS[provider].recordLabel : opts.agent;
|
|
421
464
|
const runnerId = randomUUID();
|
|
422
465
|
const runnerIdentity = { agent: agentLabel, runner: runnerId, sessions: new Set() };
|