diff --git a/README.md b/README.md index a53afeb..8580354 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,15 @@ Inspect a node: npx kalaris-myriad show MYR-D051-T041 ``` +Route a natural-language request to one bounded task without claiming scientific completion: + +```bash +node examples/task-router.js "variant-aware off-target assessment" +``` + +The example returns the selected node's objective, required evidence, and qualified-review +boundary as structured JSON. + Export a domain: ```bash diff --git a/examples/task-router.js b/examples/task-router.js new file mode 100644 index 0000000..8f45e89 --- /dev/null +++ b/examples/task-router.js @@ -0,0 +1,46 @@ +#!/usr/bin/env node +import { execFileSync } from 'node:child_process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const cli = path.join(root, 'bin', 'kalaris-myriad.js'); +function main() { + const request = process.argv.slice(2).join(' ').trim(); + + if (!request) { + console.error('Usage: node examples/task-router.js '); + process.exitCode = 1; + return; + } + + const candidates = JSON.parse(execFileSync(process.execPath, [ + cli, 'search', request, '--limit', '1', '--json' + ], { cwd: root, encoding: 'utf8' })); + + if (candidates.length === 0) { + console.log(JSON.stringify({ status: 'no-route', request, task: null }, null, 2)); + process.exitCode = 0; + return; + } + + const task = candidates[0]; + console.log(JSON.stringify({ + status: 'routed', + request, + task: { + id: task.id, + routing_name: task.routing.name, + objective: task.objective, + expected_evidence: task.execution_contract.required_completion_evidence, + review_boundary: { + mode: task.execution_contract.mode, + human_review_required: task.execution_contract.human_review_required, + no_call_when: task.execution_contract.no_call_when, + scientific_validation_claim: task.maturity.scientific_validation_claim + } + } + }, null, 2)); +} + +main(); diff --git a/package.json b/package.json index 4b9157c..965d1ff 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "schemas/", "docs/", "explorer/", + "examples/", "README.md", "CREDITS.md", "NOTICE.md", diff --git a/tests/cli.test.js b/tests/cli.test.js index b2d9802..7f6451c 100644 --- a/tests/cli.test.js +++ b/tests/cli.test.js @@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const cli = path.join(root, 'bin', 'kalaris-myriad.js'); +const router = path.join(root, 'examples', 'task-router.js'); function run(args) { const r = spawnSync(process.execPath, [cli, ...args], { cwd: root, encoding: 'utf8' }); assert.equal(r.status, 0, r.stderr || r.stdout); @@ -37,3 +38,33 @@ test('CLI validator passes', () => { assert.equal(data.status, 'PASS'); assert.equal(data.task_count, 10000); }); + +test('task router returns a bounded route without claiming completion', () => { + const result = spawnSync(process.execPath, [router, 'variant', 'off-target'], { + cwd: root, + encoding: 'utf8' + }); + assert.equal(result.status, 0, result.stderr || result.stdout); + const data = JSON.parse(result.stdout); + assert.equal(data.status, 'routed'); + assert.match(data.task.id, /^MYR-/); + assert.equal(data.task.review_boundary.mode, 'computational-advisory'); + assert.equal(data.task.review_boundary.human_review_required, true); + assert.equal(data.task.review_boundary.scientific_validation_claim, 'none'); + assert.ok(data.task.expected_evidence.length > 0); + assert.equal('completed' in data, false); +}); + +test('task router emits complete JSON when no route matches', () => { + const request = 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'; + const result = spawnSync(process.execPath, [router, request], { + cwd: root, + encoding: 'utf8' + }); + assert.equal(result.status, 0, result.stderr || result.stdout); + assert.deepEqual(JSON.parse(result.stdout), { + status: 'no-route', + request, + task: null + }); +});