#!/usr/bin/env node /** * Run all local Goose v1.49 smoke checks in sequence. */ import { spawnSync } from 'node:child_process'; import { checkPassed, classifyCheckResult } from './goose-v149-check-result.mjs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { prepareGooseV149CheckEnv } from './goose-v149-canary.mjs'; import { enforceRealLlmGate } from './goose-v149-real-llm-gate.mjs'; import { gooseV149PortalAgentEnv, waitForAgentRunWorkerIdle, } from './goose-v149-worker-idle.mjs'; const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); enforceRealLlmGate('check-goosed-v149-all.mjs'); const checkEnv = prepareGooseV149CheckEnv({ ...process.env }, root); const checks = [ { name: 'memory-policy', script: 'check-goosed-v149-memory-policy.mjs', required: true }, { name: 'local', script: 'check-goosed-v149-local.mjs', required: true }, { name: 'agent-start', script: 'check-goosed-v149-agent-start.mjs', required: true }, { name: 'harness', script: 'check-goosed-v149-harness.mjs', required: true }, { name: 'session-reconcile', script: 'check-goosed-v149-session-reconcile.mjs', required: true }, { name: 'config-read', script: 'check-goosed-v149-config-read.mjs', required: true }, { name: 'web-smoke', script: 'check-goosed-v149-web-smoke.mjs', required: true }, { name: 'skills-smoke', script: 'check-goosed-v149-skills-smoke.mjs', required: true }, { name: 'deepseek-tools', script: 'check-goosed-v149-deepseek-tools.mjs', required: true, }, { name: 'thinking-preservation', script: 'check-goosed-v149-thinking-preservation.mjs', required: true, }, { name: 'message-sanitize', script: 'compare-goose-v149-message-sanitize.mjs', required: true, }, { name: 'reply-smoke', script: 'check-goosed-v149-reply-smoke.mjs', required: true }, { name: 'multiturn-provider', script: 'check-goosed-v149-multiturn-provider.mjs', required: true, }, { name: 'resume', script: 'check-goosed-v149-resume.mjs', required: true }, { name: 'sandbox-fs', script: 'check-goosed-v149-sandbox-fs.mjs', required: true }, { name: 'sandbox-page', script: 'check-goosed-v149-sandbox-page.mjs', required: true }, { name: 'executors', script: 'check-goosed-v149-executors.mjs', required: true }, { name: 'memory-loop', script: 'check-goosed-v149-memory-loop.mjs', required: true }, { name: 'portal-smoke', script: 'check-goosed-v149-portal-smoke.mjs', required: true }, { name: 'portal-resume', script: 'check-goosed-v149-portal-resume.mjs', required: true, extraEnv: gooseV149PortalAgentEnv, waitForWorkerIdle: true, }, { name: 'page-e2e', script: 'check-goosed-v149-page-e2e.mjs', required: true, extraEnv: gooseV149PortalAgentEnv, waitForWorkerIdle: true, }, { name: 'memory-chat', script: 'check-goosed-v149-memory-chat.mjs', required: true }, { name: 'missing-evidence', script: 'run-goosed-v149-missing-evidence.mjs', required: true, }, { name: 'provider', script: 'check-goosed-v149-provider.mjs', required: true, }, ]; function runCheck(check) { const scriptPath = path.join(root, 'scripts', check.script); const result = spawnSync(process.execPath, [scriptPath], { cwd: root, env: { ...checkEnv, ...(check.extraEnv ?? {}) }, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], }); return { ...check, ok: checkPassed(result), outcome: classifyCheckResult(result), status: result.status, stdout: result.stdout?.trim() ?? '', stderr: result.stderr?.trim() ?? '', }; } async function runAllChecks() { const results = []; for (const check of checks) { if (check.waitForWorkerIdle) { await waitForAgentRunWorkerIdle(root, checkEnv, { logPrefix: '[goose-v149-all]', }); } results.push(runCheck(check)); } return results; } const results = await runAllChecks(); function refreshMemoryBaselineAfterSmoke() { if (process.env.GOOSE_V149_MEMORY_DRIFT_REFRESH_AFTER_SMOKE === '0') return; const memorySmokeNames = new Set([ 'memory-loop', 'memory-chat', 'missing-evidence', ]); const ranMemorySmoke = results.some((item) => memorySmokeNames.has(item.name) && item.ok); if (!ranMemorySmoke) return; const baselinePath = path.join(root, 'docs', 'baselines', 'goose-v149-memory-latest.json'); const exportResult = spawnSync( process.execPath, [ path.join(root, 'scripts', 'export-goose-v149-memory-manifest.mjs'), '--output', baselinePath, ], { cwd: root, env: checkEnv, encoding: 'utf8' }, ); if (exportResult.status !== 0) { console.warn( '[goose-v149-all] memory baseline refresh failed:', (exportResult.stderr || exportResult.stdout || '').trim().slice(0, 300), ); return; } console.log(`[goose-v149-all] memory baseline refreshed: ${baselinePath}`); } refreshMemoryBaselineAfterSmoke(); const failedRequired = results.filter((item) => item.required && !item.ok); const failedOptional = results.filter((item) => !item.required && !item.ok); for (const item of results) { const label = item.required ? 'required' : 'optional'; console.log(`[goose-v149-all] ${item.outcome} (${label}) ${item.name}`); if (item.stdout) console.log(item.stdout); if (!item.ok && item.stderr) console.error(item.stderr); } if (failedRequired.length) { console.error( `GOOSE_V149_ALL_FAIL: ${failedRequired.map((item) => item.name).join(', ')}`, ); process.exit(1); } if (failedOptional.length) { console.log( `GOOSE_V149_ALL_OK_WITH_SKIPS: optional skipped/failed: ${failedOptional.map((item) => item.name).join(', ')}`, ); } else { console.log('GOOSE_V149_ALL_OK'); }