#!/usr/bin/env node /** * Capture Goose v1.49 local baseline samples (status, sessions, optional SSE reply). */ import fs from 'node:fs/promises'; import path from 'node:path'; import { execFileSync } from 'node:child_process'; import { randomUUID } from 'node:crypto'; import { Readable } from 'node:stream'; import { Agent, fetch } from 'undici'; const port = process.env.GOOSE_V149_PORT || '18049'; const host = process.env.GOOSE_V149_HOST || '127.0.0.1'; const secret = process.env.GOOSE_SERVER__SECRET_KEY || 'local-v149-dev-secret'; const base = `https://${host}:${port}`; const blockedHosts = ['58.38.22.103', '120.26.184.105']; function usage() { return [ 'Usage: node scripts/capture-goose-v149-baseline.mjs [--output ] [--skip-reply]', '', 'Captures /status, /sessions, and optional reply SSE terminal event for Phase 0 baseline.', ].join('\n'); } function parseArgs(argv) { const args = { output: '', skipReply: false }; for (let i = 2; i < argv.length; i += 1) { const arg = argv[i]; if (arg === '--output' && argv[i + 1]) args.output = argv[++i]; else if (arg === '--skip-reply') args.skipReply = true; else if (arg === '--help' || arg === '-h') { console.log(usage()); process.exit(0); } else { console.error(`Unknown argument: ${arg}`); console.error(usage()); process.exit(2); } } return args; } if (blockedHosts.includes(host)) { console.error(`GOOSE_V149_BASELINE_FAIL: refusing production host ${host}`); process.exit(1); } const dispatcher = new Agent({ connect: { rejectUnauthorized: false } }); async function apiFetch(pathname, init = {}) { const headers = { ...(init.headers ?? {}), 'X-Secret-Key': secret }; if (init.body && !headers['Content-Type']) headers['Content-Type'] = 'application/json'; return fetch(`${base}${pathname}`, { ...init, headers, dispatcher }); } async function curlJson(url) { const body = execFileSync('curl', ['-sk', '--connect-timeout', '5', url], { encoding: 'utf8' }).trim(); return body === 'ok' ? { status: 'ok' } : JSON.parse(body); } async function captureReplySample(sessionId) { const requestId = randomUUID(); const events = []; const eventsResponse = await apiFetch(`/sessions/${sessionId}/events`, { method: 'GET', headers: { Accept: 'text/event-stream' }, }); if (!eventsResponse.ok || !eventsResponse.body) { throw new Error(`events ${eventsResponse.status}`); } const replyResponse = await apiFetch(`/sessions/${sessionId}/reply`, { method: 'POST', body: JSON.stringify({ request_id: requestId, user_message: { role: 'user', created: Date.now(), content: [{ type: 'text', text: 'baseline ping' }], metadata: { userVisible: true, agentVisible: true, displayText: 'baseline ping' }, }, }), }); replyResponse.body?.cancel?.(); const reader = Readable.fromWeb(eventsResponse.body); const decoder = new TextDecoder(); let buffer = ''; const deadline = Date.now() + Number(process.env.GOOSE_V149_BASELINE_REPLY_TIMEOUT_MS || 30_000); for await (const chunk of reader) { if (Date.now() > deadline) break; buffer += decoder.decode(chunk, { stream: true }); const frames = buffer.split('\n\n'); buffer = frames.pop() ?? ''; for (const frame of frames) { let data = ''; for (const line of frame.split('\n')) { if (line.startsWith('data:')) data += line.slice(5).trim(); } if (!data) continue; let event; try { event = JSON.parse(data); } catch { continue; } events.push(event); const routingId = event.chat_request_id ?? event.request_id; if (routingId && routingId !== requestId) continue; if (event.type === 'Finish' || event.type === 'Error') { return { requestId, outcome: event.type.toLowerCase(), events }; } } } return { requestId, outcome: 'timeout', events }; } async function main() { const args = parseArgs(process.argv); const capturedAt = new Date().toISOString(); const status = await curlJson(`${base}/status`); const sessions = await curlJson(`${base}/sessions`); const baseline = { schemaVersion: 'goose-v149-baseline-v1', capturedAt, target: base, status, sessionsSummary: { count: Array.isArray(sessions?.sessions) ? sessions.sessions.length : null, sample: Array.isArray(sessions?.sessions) ? sessions.sessions.slice(0, 3) : sessions, }, reply: null, }; if (!args.skipReply) { const startResponse = await apiFetch('/agent/start', { method: 'POST', body: JSON.stringify({ working_dir: process.cwd() }), }); const startBody = await startResponse.json(); if (startResponse.ok && startBody?.id) { baseline.reply = await captureReplySample(startBody.id); baseline.reply.sessionId = startBody.id; } else { baseline.reply = { error: 'agent/start failed', status: startResponse.status, body: startBody }; } } const outputDir = args.output ? path.resolve(args.output) : path.join(process.cwd(), 'docs', 'baselines'); await fs.mkdir(outputDir, { recursive: true }); const outputPath = path.join( outputDir, `goose-v149-runtime-baseline-${capturedAt.replace(/[:.]/g, '-')}.json`, ); await fs.writeFile(outputPath, `${JSON.stringify(baseline, null, 2)}\n`, 'utf8'); console.log(`GOOSE_V149_BASELINE_OK: ${outputPath}`); } main().catch((error) => { console.error(`GOOSE_V149_BASELINE_FAIL: ${error.message}`); process.exit(1); });