Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions harness/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@
"dev:provider-openai": "tsx src/provider-openai/main.ts",
"dev:provider-kimi": "tsx src/provider-kimi/main.ts",
"dev:provider-lmstudio": "tsx src/provider-lmstudio/main.ts",
"dev:provider-llamacpp": "tsx src/provider-llamacpp/main.ts",
"dev:context-compaction": "tsx src/context-compaction/main.ts",
"dev:provider-config": "tsx src/provider-config/main.ts"
"dev:provider-config": "tsx src/provider-config/main.ts",
"dev:web": "tsx src/web/main.ts"
},
"bin": {
"harness": "./dist/index.js",
Expand All @@ -50,8 +52,10 @@
"iii-provider-openai": "./dist/provider-openai/main.js",
"iii-provider-kimi": "./dist/provider-kimi/main.js",
"iii-provider-lmstudio": "./dist/provider-lmstudio/main.js",
"iii-provider-llamacpp": "./dist/provider-llamacpp/main.js",
"iii-context-compaction": "./dist/context-compaction/main.js",
"iii-provider-config": "./dist/provider-config/main.js"
"iii-provider-config": "./dist/provider-config/main.js",
"iii-web": "./dist/web/main.js"
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
Expand Down
6 changes: 6 additions & 0 deletions harness/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
} from './runtime/worker.js';
import { register as registerSession } from './session/register.js';
import { register as registerTurnOrchestrator } from './turn-orchestrator/register.js';
import { register as registerWeb } from './web/register.js';

const WORKERS: readonly WorkerDefinition[] = [
{
Expand Down Expand Up @@ -125,6 +126,11 @@ const WORKERS: readonly WorkerDefinition[] = [
'Out-of-band session-history compactor. Subscribes to agent::events::TurnEnd and writes a session-tree Compaction entry when the running token count crosses the configured threshold.',
register: (iii) => registerContextCompaction(iii),
},
{
name: 'web',
description: 'Outbound HTTP client on the iii bus (web::fetch).',
register: (iii, ctx) => registerWeb(iii, ctx),
},
];

async function main(): Promise<void> {
Expand Down
52 changes: 52 additions & 0 deletions harness/tests/composite-manifest.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { execFileSync } from 'node:child_process';
import { existsSync, readFileSync, readdirSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';

const here = dirname(fileURLToPath(import.meta.url));
const repoRoot = join(here, '..');
const srcDir = join(repoRoot, 'src');
const indexEntry = join(srcDir, 'index.ts');
const tsxBin = join(repoRoot, 'node_modules', '.bin', 'tsx');

const pkg = JSON.parse(readFileSync(join(repoRoot, 'package.json'), 'utf8')) as {
scripts: Record<string, string>;
bin: Record<string, string>;
};

/**
* Every folder under `src/` that ships a `main.ts` is a worker meant to run
* standalone. The composite entry-point (`src/index.ts`, what `dev:all` and
* `start:all` run) must register every one of them — otherwise a worker
* silently never starts in the all-in-one process. Regression guard for #202,
* where the `web` worker was added but never wired into `index.ts`.
*/
function runnableWorkerFolders(): string[] {
return readdirSync(srcDir, { withFileTypes: true })
.filter((e) => e.isDirectory() && existsSync(join(srcDir, e.name, 'main.ts')))
.map((e) => e.name)
.sort();
}

function compositeManifestNames(): string[] {
const out = execFileSync(tsxBin, [indexEntry, '--manifest'], { encoding: 'utf8' });
const manifest = JSON.parse(out) as Array<{ name: string }>;
return manifest.map((w) => w.name).sort();
}

describe('composite entry-point worker registration', () => {
it('registers every runnable worker folder in the WORKERS array', () => {
expect(compositeManifestNames()).toEqual(runnableWorkerFolders());
});

it('exposes a dev:<name> script for every runnable worker', () => {
const missing = runnableWorkerFolders().filter((name) => !pkg.scripts[`dev:${name}`]);
expect(missing).toEqual([]);
});

it('exposes an iii-<name> bin for every runnable worker', () => {
const missing = runnableWorkerFolders().filter((name) => !pkg.bin[`iii-${name}`]);
expect(missing).toEqual([]);
});
});
Loading