mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-17 21:15:40 +02:00
85 lines
4.9 KiB
JavaScript
85 lines
4.9 KiB
JavaScript
const assert = require('assert');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { spawnSync } = require('child_process');
|
|
const { parseArgs, run } = require('../../skills/ito-market-intelligence/scripts/ito-market-intelligence');
|
|
|
|
const ROOT = path.join(__dirname, '..', '..');
|
|
const SKILL = path.join(ROOT, 'skills', 'ito-market-intelligence');
|
|
const CLIENT = path.join(SKILL, 'scripts', 'ito-market-intelligence.js');
|
|
|
|
function invoke(args, env = {}) {
|
|
return spawnSync(process.execPath, [CLIENT, '--json', ...args], {
|
|
encoding: 'utf8', env: { PATH: process.env.PATH, ...env }, timeout: 5000,
|
|
});
|
|
}
|
|
|
|
(async () => {
|
|
const skill = fs.readFileSync(path.join(SKILL, 'SKILL.md'), 'utf8');
|
|
assert.match(skill, /^---\nname: ito-market-intelligence\ndescription: [^\n]+\n---/);
|
|
assert.doesNotMatch(skill.split('---')[1], /\nmetadata:/);
|
|
for (const trigger of ['event discovery', 'venue comparison', 'basket theme', 'market brief']) assert.ok(skill.includes(trigger));
|
|
for (const contract of ['retrieved_at', 'source-provided timestamps', 'AUTH_REJECTED', 'RATE_LIMITED', 'TIMEOUT']) assert.ok(skill.includes(contract));
|
|
const agentMetadata = fs.readFileSync(path.join(SKILL, 'agents', 'openai.yaml'), 'utf8');
|
|
assert.match(agentMetadata, /display_name: "Itô Market Intelligence"/);
|
|
assert.match(agentMetadata, /default_prompt: "Use \$ito-market-intelligence /);
|
|
|
|
let result = invoke(['search-markets']);
|
|
assert.strictEqual(result.status, 1);
|
|
assert.strictEqual(JSON.parse(result.stderr).error.code, 'AUTH_MISSING');
|
|
|
|
result = invoke(['search-markets'], { ITO_API_KEY: 'secret', ITO_MARKET_API_URL: 'http://example.com/api/v1' });
|
|
assert.strictEqual(JSON.parse(result.stderr).error.code, 'CONFIG');
|
|
assert.ok(!result.stderr.includes('secret'));
|
|
|
|
const fetchSuccess = async (url, request) => {
|
|
assert.strictEqual(request.method, 'GET');
|
|
assert.strictEqual(request.headers.Authorization, 'Bearer test-key');
|
|
assert.match(url.toString(), /\/markets\/search\?platform=all&limit=1$/);
|
|
return new Response(JSON.stringify({ data: [{ market_id: 'm1', title: 'Example' }], meta: { updated_at: '2026-08-07T12:00:00Z' } }), { status: 200, headers: { 'x-ratelimit-limit': '120', 'x-ratelimit-remaining': '119', 'x-ratelimit-reset': '1786128733' } });
|
|
};
|
|
const payload = await run(parseArgs(['node', CLIENT, 'search-markets', '--platform', 'all', '--limit', '1']), { ITO_API_KEY: 'test-key' }, fetchSuccess);
|
|
assert.strictEqual(payload.ok, true);
|
|
assert.strictEqual(payload.source.provider, 'Itô Markets');
|
|
assert.strictEqual(payload.freshness.source_updated_at, '2026-08-07T12:00:00Z');
|
|
assert.deepStrictEqual(payload.rate_limit, { limit: 120, remaining: 119, reset_epoch: 1786128733 });
|
|
assert.deepStrictEqual(payload.data, [{ market_id: 'm1', title: 'Example' }]);
|
|
assert.ok(!JSON.stringify(payload).includes('test-key'));
|
|
|
|
const fetchPage = async url => {
|
|
assert.match(url.toString(), /\/baskets\?page=2&per_page=5$/);
|
|
return new Response(JSON.stringify({ data: [], meta: { page: 2, per_page: 5 } }), { status: 200 });
|
|
};
|
|
const pagePayload = await run(parseArgs(['node', CLIENT, 'list-baskets', '--page', '2', '--per-page', '5']), { ITO_API_KEY: 'test-key' }, fetchPage);
|
|
assert.strictEqual(pagePayload.meta.per_page, 5);
|
|
|
|
await assert.rejects(
|
|
run(parseArgs(['node', CLIENT, 'list-baskets']), { ITO_API_KEY: 'revoked' }, async () => new Response('{}', { status: 401 })),
|
|
error => error.code === 'AUTH_REJECTED' && !error.message.includes('revoked')
|
|
);
|
|
|
|
await assert.rejects(
|
|
run(parseArgs(['node', CLIENT, 'list-baskets']), { ITO_API_KEY: 'key' }, async () => new Response('{}', { status: 429, headers: { 'retry-after': '7' } })),
|
|
error => error.code === 'RATE_LIMITED' && error.details.retry_after_seconds === 7
|
|
);
|
|
|
|
await assert.rejects(
|
|
run(parseArgs(['node', CLIENT, '--timeout-ms', '100', 'list-baskets']), { ITO_API_KEY: 'key' }, async (_url, request) => new Promise((_resolve, reject) => {
|
|
request.signal.addEventListener('abort', () => reject(Object.assign(new Error('aborted'), { name: 'AbortError' })));
|
|
})),
|
|
error => error.code === 'TIMEOUT' && !error.message.includes('key')
|
|
);
|
|
|
|
await assert.rejects(
|
|
run(parseArgs(['node', CLIENT, 'list-baskets']), { ITO_API_KEY: 'key' }, async () => new Response('<html>bad gateway</html>', { status: 502 })),
|
|
error => error.code === 'INVALID_RESPONSE' && !error.message.includes('bad gateway')
|
|
);
|
|
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(ROOT, 'manifests', 'install-modules.json')));
|
|
assert.ok(manifest.modules.some(module => module.paths?.includes('skills/ito-market-intelligence')));
|
|
const packed = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'))).files;
|
|
assert.ok(packed.includes('skills/ito-market-intelligence/'));
|
|
fs.accessSync(CLIENT, fs.constants.R_OK);
|
|
console.log('PASS ito-market-intelligence skill contract');
|
|
})().catch(error => { console.error(error); process.exitCode = 1; });
|