// Node 20.19+. No packages. Secrets and access tokens remain in memory. // Preview by default. Explicit --run executes ready, free child tools only. // client.mjs reads TASKVEGAS_URL, TASKVEGAS_CLIENT_ID and TASKVEGAS_CLIENT_SECRET. import { randomUUID } from 'node:crypto'; import { fileURLToPath } from 'node:url'; import { resolve } from 'node:path'; import { TaskVegasClient } from './client.mjs'; const TOOL_IDS = new Set(['taskvegas_plan_task', 'taskvegas_run_plan', 'taskvegas_get_plan_status', 'taskvegas_get_intelligence_usage']); class IntelligenceError extends Error {} async function readJson(response) { if (!/^application\/json(?:\s*;|$)/i.test(response.headers.get('content-type') || '')) { await response.body?.cancel(); throw new IntelligenceError('TaskVegas returned an unexpected response type.'); } const chunks = []; let size = 0; for await (const chunk of response.body) { size += chunk.length; if (size > 262144) { await response.body.cancel().catch(() => {}); throw new IntelligenceError('TaskVegas response exceeded the client size limit.'); } chunks.push(Buffer.from(chunk)); } try { return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(Buffer.concat(chunks))); } catch { throw new IntelligenceError('TaskVegas returned invalid JSON.'); } } export class TaskVegasIntelligenceClient extends TaskVegasClient { async execute(toolId, input, idempotencyKey = randomUUID()) { if (!TOOL_IDS.has(toolId)) throw new IntelligenceError('This example only supports its fixed Intelligence tools.'); const response = await fetch(`${this.config.origin}/api/v1/tools/${toolId}/execute`, { method: 'POST', redirect: 'error', signal: AbortSignal.timeout(toolId === 'taskvegas_run_plan' ? 50000 : 20000), headers: { Accept: 'application/json', 'Content-Type': 'application/json', Authorization: `Bearer ${await this.token()}` }, body: JSON.stringify({ input, idempotencyKey }), }); if (!response.ok) { await response.body?.cancel(); throw new IntelligenceError(`TaskVegas request failed (HTTP ${response.status}). Check exact grants, pilot consent, setup, credits, and plan status. Execution was not retried.`); } const value = await readJson(response); if (!value || !Object.hasOwn(value, 'result')) throw new IntelligenceError('TaskVegas returned an incomplete execution response.'); return value.result; } async preview(task = 'Find reviewed design guidance for an issue-triage dashboard with keyboard access and readable status labels.') { if (typeof task !== 'string' || !task.trim() || task.length > 500) throw new IntelligenceError('Use an approved task summary of 1–500 characters without secrets or private records.'); const discovery = await this.request('/api/v1/tools'); if (discovery.resource !== this.resource || !Array.isArray(discovery.tools) || !discovery.tools.some(tool => tool.name === 'taskvegas_plan_task')) throw new IntelligenceError('Grant taskvegas_plan_task and explicitly authorize Intelligence before using this example.'); return this.execute('taskvegas_plan_task', { task: task.trim(), context: { source: 'user-approved-summary' }, approvedBrief: true }); } async runFreePlan(plan) { if (!plan || plan.status !== 'ready' || typeof plan.envelope !== 'string' || !plan.envelope || !Array.isArray(plan.steps) || plan.steps.length < 1 || plan.steps.length > 5 || !Number.isFinite(Date.parse(plan.expiresAt)) || Date.parse(plan.expiresAt) <= Date.now()) throw new IntelligenceError('Only a ready, unexpired, reviewed plan can run.'); if (plan.steps.some(step => step.paid !== false)) throw new IntelligenceError('This example runs only explicitly free child tools. Review provider charges separately.'); const discovery = await this.request('/api/v1/tools'); if (discovery.resource !== this.resource || !Array.isArray(discovery.tools) || plan.steps.some(step => !discovery.tools.some(tool => tool.name === step.toolId && tool.readOnly === true && tool.paid === false && tool.agentAllowed === true))) throw new IntelligenceError('Every child tool needs a current exact grant for a free read. Reconnect and preview a new plan.'); return this.execute('taskvegas_run_plan', { envelope: plan.envelope }); } } if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) { try { if (process.argv.slice(2).some(value => value !== '--run')) throw new IntelligenceError('Use no argument to preview, or --run to approve a ready free plan.'); const client = new TaskVegasIntelligenceClient(); const value = await client.preview(); const plan = value?.plan; if (!plan || !Array.isArray(plan.steps)) throw new IntelligenceError('No complete plan was returned. No child tools were run.'); console.log(`Plan preview: ${['ready', 'needs-setup', 'clarification', 'recommendation', 'host-action'].includes(plan.status) ? plan.status : 'review required'}; ${plan.steps.length} step(s).`); if (process.argv.includes('--run')) { const result = await client.runFreePlan(plan); console.log(`Execution response: ${['completed', 'partial', 'stopped', 'failed', 'running', 'unknown'].includes(result?.status) ? result.status : 'check plan status'}.`); } } catch (error) { console.error(error instanceof IntelligenceError ? error.message : 'Intelligence client failed. Check configuration and service status. No execution was retried.'); process.exitCode = 1; } }