oorja-harness-host 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -2
- package/dist/database/index.d.ts +6 -0
- package/dist/database/index.js +29 -0
- package/dist/harnesses/claudeCode/index.d.ts +8 -0
- package/dist/harnesses/claudeCode/index.js +16 -0
- package/dist/harnesses/codex/index.d.ts +8 -0
- package/dist/harnesses/codex/index.js +16 -0
- package/dist/harnesses/doctor.d.ts +2 -0
- package/dist/harnesses/doctor.js +52 -0
- package/dist/harnesses/index.d.ts +8 -0
- package/dist/harnesses/index.js +42 -0
- package/dist/harnesses/openCode/index.d.ts +8 -0
- package/dist/harnesses/openCode/index.js +17 -0
- package/dist/harnesses/prepare.d.ts +2 -0
- package/dist/harnesses/prepare.js +11 -0
- package/dist/harnesses/runtime.d.ts +8 -0
- package/dist/harnesses/runtime.js +47 -0
- package/dist/harnesses/types.d.ts +21 -0
- package/dist/harnesses/types.js +1 -0
- package/dist/host/Future.d.ts +7 -0
- package/dist/host/Future.js +15 -0
- package/dist/host/HarnessHost.d.ts +39 -0
- package/dist/host/HarnessHost.js +369 -0
- package/dist/host/activity.d.ts +25 -0
- package/dist/host/activity.js +71 -0
- package/dist/host/models.d.ts +2 -0
- package/dist/host/models.js +16 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -0
- package/dist/messages.d.ts +150 -0
- package/dist/messages.js +37 -0
- package/dist/repo/HarnessRepo.d.ts +21 -0
- package/dist/repo/HarnessRepo.js +76 -0
- package/dist/repo/index.d.ts +2 -0
- package/dist/repo/index.js +2 -0
- package/dist/repo/migrations/001-initial.d.ts +2 -0
- package/dist/repo/migrations/001-initial.js +26 -0
- package/dist/repo/migrations/index.d.ts +2 -0
- package/dist/repo/migrations/index.js +2 -0
- package/dist/runtime.d.ts +13 -0
- package/dist/runtime.js +1 -0
- package/dist/sandbox/local.d.ts +15 -0
- package/dist/sandbox/local.js +126 -0
- package/package.json +36 -4
package/README.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Harness Host
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Runtime support for hosting AI coding harness sessions on a computer connected
|
|
4
|
+
to a Supakit room.
|
|
5
|
+
|
|
6
|
+
The package owns live harness sessions, adapters, preparation, resume state,
|
|
7
|
+
and the shared message contract. Applications own channel connections, routing,
|
|
8
|
+
machine identity, and command-line presentation.
|
|
9
|
+
|
|
10
|
+
Turn output remains buffered in memory until the client confirms that it has
|
|
11
|
+
saved it. On graceful shutdown, the host saves the opaque AI SDK resume state
|
|
12
|
+
provided by each harness session so the next process can resume it.
|
|
13
|
+
|
|
14
|
+
Harness state is stored in one SQLite database. The host keeps exclusive access
|
|
15
|
+
to that database while it is running; `stop()` saves the sessions and closes
|
|
16
|
+
the database.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
const host = await HarnessHost.start({
|
|
20
|
+
// ...
|
|
21
|
+
stateFile: '/path/to/harness-host.sqlite',
|
|
22
|
+
})
|
|
23
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { mkdirSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
export const openDatabase = (file, migrations) => {
|
|
5
|
+
mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
6
|
+
const database = new DatabaseSync(file, { timeout: 0 });
|
|
7
|
+
try {
|
|
8
|
+
database.exec('PRAGMA locking_mode = EXCLUSIVE');
|
|
9
|
+
database.exec('PRAGMA journal_mode = DELETE');
|
|
10
|
+
database.exec('BEGIN EXCLUSIVE');
|
|
11
|
+
const { user_version: currentVersion } = database
|
|
12
|
+
.prepare('PRAGMA user_version')
|
|
13
|
+
.get();
|
|
14
|
+
for (const migration of migrations) {
|
|
15
|
+
if (migration.version <= currentVersion)
|
|
16
|
+
continue;
|
|
17
|
+
migration.apply(database);
|
|
18
|
+
database.exec(`PRAGMA user_version = ${migration.version}`);
|
|
19
|
+
}
|
|
20
|
+
database.exec('COMMIT');
|
|
21
|
+
return database;
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (database.isTransaction)
|
|
25
|
+
database.exec('ROLLBACK');
|
|
26
|
+
database.close();
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createClaudeCode } from '@ai-sdk/harness-claude-code';
|
|
2
|
+
export type ClaudeCodeConfig = NonNullable<Parameters<typeof createClaudeCode>[0]>;
|
|
3
|
+
export declare const createClaudeCodeRuntime: ({ cwd, config }: {
|
|
4
|
+
cwd: string;
|
|
5
|
+
config?: ClaudeCodeConfig;
|
|
6
|
+
}) => import("../../index.js").HarnessRuntime;
|
|
7
|
+
export declare const prepareClaudeCode: (cwd: string) => Promise<string>;
|
|
8
|
+
export declare const runClaudeCodeDoctor: (cwd: string) => Promise<import("../types.js").HarnessDoctorCheck[]>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createClaudeCode } from '@ai-sdk/harness-claude-code';
|
|
2
|
+
import { HarnessId } from '../../messages.js';
|
|
3
|
+
import { runHarnessDoctor } from '../doctor.js';
|
|
4
|
+
import { prepareHarness } from '../prepare.js';
|
|
5
|
+
import { createHarnessRuntime } from '../runtime.js';
|
|
6
|
+
export const createClaudeCodeRuntime = ({ cwd, config }) => createHarnessRuntime({
|
|
7
|
+
harnessId: HarnessId.CLAUDE_CODE,
|
|
8
|
+
cwd,
|
|
9
|
+
createHarness: (port) => createClaudeCode({
|
|
10
|
+
...config,
|
|
11
|
+
port,
|
|
12
|
+
portEndpoint: { url: `ws://127.0.0.1:${port}` },
|
|
13
|
+
}),
|
|
14
|
+
});
|
|
15
|
+
export const prepareClaudeCode = (cwd) => prepareHarness(cwd, createClaudeCode());
|
|
16
|
+
export const runClaudeCodeDoctor = (cwd) => runHarnessDoctor(cwd, 'Claude Code');
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createCodex } from '@ai-sdk/harness-codex';
|
|
2
|
+
export type CodexConfig = NonNullable<Parameters<typeof createCodex>[0]>;
|
|
3
|
+
export declare const createCodexRuntime: ({ cwd, config }: {
|
|
4
|
+
cwd: string;
|
|
5
|
+
config?: CodexConfig;
|
|
6
|
+
}) => import("../../index.js").HarnessRuntime;
|
|
7
|
+
export declare const prepareCodex: (cwd: string) => Promise<string>;
|
|
8
|
+
export declare const runCodexDoctor: (cwd: string) => Promise<import("../types.js").HarnessDoctorCheck[]>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createCodex } from '@ai-sdk/harness-codex';
|
|
2
|
+
import { HarnessId } from '../../messages.js';
|
|
3
|
+
import { runHarnessDoctor } from '../doctor.js';
|
|
4
|
+
import { prepareHarness } from '../prepare.js';
|
|
5
|
+
import { createHarnessRuntime } from '../runtime.js';
|
|
6
|
+
export const createCodexRuntime = ({ cwd, config }) => createHarnessRuntime({
|
|
7
|
+
harnessId: HarnessId.CODEX,
|
|
8
|
+
cwd,
|
|
9
|
+
createHarness: (port) => createCodex({
|
|
10
|
+
...config,
|
|
11
|
+
port,
|
|
12
|
+
portEndpoint: { url: `ws://127.0.0.1:${port}` },
|
|
13
|
+
}),
|
|
14
|
+
});
|
|
15
|
+
export const prepareCodex = (cwd) => prepareHarness(cwd, createCodex());
|
|
16
|
+
export const runCodexDoctor = (cwd) => runHarnessDoctor(cwd, 'Codex');
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { constants } from 'node:fs';
|
|
2
|
+
import { access } from 'node:fs/promises';
|
|
3
|
+
import { createServer } from 'node:net';
|
|
4
|
+
import { LocalSandboxSession } from '../sandbox/local.js';
|
|
5
|
+
export const runHarnessDoctor = async (cwd, harnessName) => {
|
|
6
|
+
const sandbox = new LocalSandboxSession(cwd);
|
|
7
|
+
const home = process.env.HOME;
|
|
8
|
+
const [pnpm, homeIsWritable, loopbackIsAvailable] = await Promise.all([
|
|
9
|
+
Promise.resolve(sandbox.run({ command: 'pnpm --version' })).catch(() => undefined),
|
|
10
|
+
home ? canAccess(home, constants.R_OK | constants.W_OK) : false,
|
|
11
|
+
checkLoopbackPort().then(() => true, () => false),
|
|
12
|
+
]);
|
|
13
|
+
const nodeMajor = Number(process.versions.node.split('.')[0]);
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
name: 'node',
|
|
17
|
+
ok: nodeMajor >= 22,
|
|
18
|
+
detail: `Node ${process.versions.node}; requires Node 22 or newer`,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'pnpm',
|
|
22
|
+
ok: pnpm?.exitCode === 0,
|
|
23
|
+
detail: pnpm?.exitCode === 0 ? `pnpm ${pnpm.stdout.trim()}` : `pnpm is required for ${harnessName} bootstrap`,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'home',
|
|
27
|
+
ok: homeIsWritable,
|
|
28
|
+
detail: home ? `${home} must be readable and writable` : 'HOME is not set',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'loopback-port',
|
|
32
|
+
ok: loopbackIsAvailable,
|
|
33
|
+
detail: loopbackIsAvailable
|
|
34
|
+
? 'Can bind an ephemeral port on 127.0.0.1'
|
|
35
|
+
: 'Could not bind an ephemeral port on 127.0.0.1',
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
};
|
|
39
|
+
const checkLoopbackPort = () => new Promise((resolve, reject) => {
|
|
40
|
+
const server = createServer();
|
|
41
|
+
server.once('error', reject);
|
|
42
|
+
server.listen(0, '127.0.0.1', () => server.close((error) => (error ? reject(error) : resolve())));
|
|
43
|
+
});
|
|
44
|
+
const canAccess = async (target, mode) => {
|
|
45
|
+
try {
|
|
46
|
+
await access(target, mode);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { HarnessId } from '../messages.js';
|
|
2
|
+
import type { HarnessRuntime } from '../runtime.js';
|
|
3
|
+
import type { HarnessDoctorResult, HarnessPrepareResult } from './types.js';
|
|
4
|
+
export declare const ALL_HARNESSES: "all";
|
|
5
|
+
export type HarnessSelection = HarnessId | typeof ALL_HARNESSES;
|
|
6
|
+
export declare const doctorHarnessHost: (cwd: string) => Promise<HarnessDoctorResult[]>;
|
|
7
|
+
export declare const prepareHarnessHost: (cwd: string, selections?: readonly HarnessSelection[]) => Promise<HarnessPrepareResult[]>;
|
|
8
|
+
export declare const createHarnessRuntimes: (cwd: string) => HarnessRuntime[];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createClaudeCodeRuntime, prepareClaudeCode, runClaudeCodeDoctor, } from './claudeCode/index.js';
|
|
2
|
+
import { createCodexRuntime, prepareCodex, runCodexDoctor } from './codex/index.js';
|
|
3
|
+
import { createOpenCodeRuntime, prepareOpenCode, runOpenCodeDoctor } from './openCode/index.js';
|
|
4
|
+
import { HarnessId } from '../messages.js';
|
|
5
|
+
export const ALL_HARNESSES = 'all';
|
|
6
|
+
export const doctorHarnessHost = async (cwd) => Promise.all(harnesses.map(async ({ harnessId, doctor }) => ({
|
|
7
|
+
harnessId,
|
|
8
|
+
checks: await doctor(cwd),
|
|
9
|
+
})));
|
|
10
|
+
export const prepareHarnessHost = async (cwd, selections = [ALL_HARNESSES]) => {
|
|
11
|
+
const results = [];
|
|
12
|
+
for (const harness of selectHarnesses(selections)) {
|
|
13
|
+
results.push({ harnessId: harness.harnessId, detail: await harness.prepare(cwd) });
|
|
14
|
+
}
|
|
15
|
+
return results;
|
|
16
|
+
};
|
|
17
|
+
export const createHarnessRuntimes = (cwd) => harnesses.map(({ createRuntime }) => createRuntime(cwd));
|
|
18
|
+
const codex = {
|
|
19
|
+
harnessId: HarnessId.CODEX,
|
|
20
|
+
createRuntime: (cwd) => createCodexRuntime({ cwd }),
|
|
21
|
+
doctor: runCodexDoctor,
|
|
22
|
+
prepare: prepareCodex,
|
|
23
|
+
};
|
|
24
|
+
const claudeCode = {
|
|
25
|
+
harnessId: HarnessId.CLAUDE_CODE,
|
|
26
|
+
createRuntime: (cwd) => createClaudeCodeRuntime({ cwd }),
|
|
27
|
+
doctor: runClaudeCodeDoctor,
|
|
28
|
+
prepare: prepareClaudeCode,
|
|
29
|
+
};
|
|
30
|
+
const openCode = {
|
|
31
|
+
harnessId: HarnessId.OPENCODE,
|
|
32
|
+
createRuntime: (cwd) => createOpenCodeRuntime({ cwd }),
|
|
33
|
+
doctor: runOpenCodeDoctor,
|
|
34
|
+
prepare: prepareOpenCode,
|
|
35
|
+
};
|
|
36
|
+
const harnesses = [codex, claudeCode, openCode];
|
|
37
|
+
const selectHarnesses = (selections) => {
|
|
38
|
+
if (selections.includes(ALL_HARNESSES))
|
|
39
|
+
return harnesses;
|
|
40
|
+
const selected = new Set(selections);
|
|
41
|
+
return harnesses.filter(({ harnessId }) => selected.has(harnessId));
|
|
42
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createOpenCode } from '@ai-sdk/harness-opencode';
|
|
2
|
+
export type OpenCodeConfig = NonNullable<Parameters<typeof createOpenCode>[0]>;
|
|
3
|
+
export declare const createOpenCodeRuntime: ({ cwd, config }: {
|
|
4
|
+
cwd: string;
|
|
5
|
+
config?: OpenCodeConfig;
|
|
6
|
+
}) => import("../../index.js").HarnessRuntime;
|
|
7
|
+
export declare const prepareOpenCode: (cwd: string) => Promise<string>;
|
|
8
|
+
export declare const runOpenCodeDoctor: (cwd: string) => Promise<import("../types.js").HarnessDoctorCheck[]>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createOpenCode } from '@ai-sdk/harness-opencode';
|
|
2
|
+
import { HarnessId } from '../../messages.js';
|
|
3
|
+
import { runHarnessDoctor } from '../doctor.js';
|
|
4
|
+
import { prepareHarness } from '../prepare.js';
|
|
5
|
+
import { createHarnessRuntime } from '../runtime.js';
|
|
6
|
+
export const createOpenCodeRuntime = ({ cwd, config }) => createHarnessRuntime({
|
|
7
|
+
harnessId: HarnessId.OPENCODE,
|
|
8
|
+
cwd,
|
|
9
|
+
createHarness: (port) => createOpenCode({
|
|
10
|
+
...config,
|
|
11
|
+
provider: config?.provider ?? 'opencode',
|
|
12
|
+
port,
|
|
13
|
+
portEndpoint: { url: `ws://127.0.0.1:${port}` },
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
export const prepareOpenCode = (cwd) => prepareHarness(cwd, createOpenCode());
|
|
17
|
+
export const runOpenCodeDoctor = (cwd) => runHarnessDoctor(cwd, 'OpenCode');
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createHarnessSandboxTemplate } from '@ai-sdk/harness/agent';
|
|
2
|
+
import { LocalSandboxSession } from '../sandbox/local.js';
|
|
3
|
+
export const prepareHarness = async (cwd, harness) => {
|
|
4
|
+
const template = await createHarnessSandboxTemplate({
|
|
5
|
+
harnesses: [harness],
|
|
6
|
+
sandboxConfig: { workDir: '.' },
|
|
7
|
+
});
|
|
8
|
+
if (template)
|
|
9
|
+
await template.prepare({ session: new LocalSandboxSession(cwd) });
|
|
10
|
+
return 'Installed locally and ready to use.';
|
|
11
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type HarnessAgentAdapter } from '@ai-sdk/harness/agent';
|
|
2
|
+
import { HarnessId } from '../messages.js';
|
|
3
|
+
import type { HarnessRuntime } from '../runtime.js';
|
|
4
|
+
export declare const createHarnessRuntime: ({ harnessId, cwd, createHarness, }: {
|
|
5
|
+
harnessId: HarnessId;
|
|
6
|
+
cwd: string;
|
|
7
|
+
createHarness: (port: number) => HarnessAgentAdapter;
|
|
8
|
+
}) => HarnessRuntime;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createServer } from 'node:net';
|
|
2
|
+
import { HarnessAgent } from '@ai-sdk/harness/agent';
|
|
3
|
+
import { jsonSchema } from 'ai';
|
|
4
|
+
import { HARNESS_MODELS } from '../host/models.js';
|
|
5
|
+
import { LocalSandboxSession } from '../sandbox/local.js';
|
|
6
|
+
export const createHarnessRuntime = ({ harnessId, cwd, createHarness, }) => ({
|
|
7
|
+
harnessId,
|
|
8
|
+
createSession: async (sessionId, resumeFrom) => {
|
|
9
|
+
const port = await allocateLoopbackPort();
|
|
10
|
+
const agent = new HarnessAgent({
|
|
11
|
+
model: HARNESS_MODELS[harnessId].defaultModel,
|
|
12
|
+
harness: createHarness(port),
|
|
13
|
+
permissionMode: 'allow-all',
|
|
14
|
+
sandboxConfig: { workDir: '.' },
|
|
15
|
+
callOptionsSchema: jsonSchema({
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: { model: { type: 'string' } },
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
}),
|
|
20
|
+
prepareCall: ({ options, ...call }) => ({ ...call, model: options.model ?? call.model }),
|
|
21
|
+
});
|
|
22
|
+
const session = await agent.createSession({
|
|
23
|
+
sessionId,
|
|
24
|
+
resumeFrom,
|
|
25
|
+
sandboxSession: new LocalSandboxSession(cwd),
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
stream: async (prompt, abortSignal, model) => (await agent.stream({ session, prompt, abortSignal, options: { model } })).fullStream,
|
|
29
|
+
steer: (text) => agent.experimental_steer({ session, text }),
|
|
30
|
+
stop: () => session.stop(),
|
|
31
|
+
destroy: () => session.destroy(),
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
const allocateLoopbackPort = () => new Promise((resolve, reject) => {
|
|
36
|
+
const server = createServer();
|
|
37
|
+
server.once('error', reject);
|
|
38
|
+
server.listen(0, '127.0.0.1', () => {
|
|
39
|
+
const address = server.address();
|
|
40
|
+
if (address === null || typeof address === 'string') {
|
|
41
|
+
server.close();
|
|
42
|
+
reject(new Error('Unable to allocate a loopback port'));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
server.close((error) => (error ? reject(error) : resolve(address.port)));
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { HarnessId } from '../messages.js';
|
|
2
|
+
import type { HarnessRuntime } from '../runtime.js';
|
|
3
|
+
export type HarnessDoctorCheck = {
|
|
4
|
+
name: string;
|
|
5
|
+
ok: boolean;
|
|
6
|
+
detail: string;
|
|
7
|
+
};
|
|
8
|
+
export type HarnessDoctorResult = {
|
|
9
|
+
harnessId: HarnessId;
|
|
10
|
+
checks: HarnessDoctorCheck[];
|
|
11
|
+
};
|
|
12
|
+
export type HarnessPrepareResult = {
|
|
13
|
+
harnessId: HarnessId;
|
|
14
|
+
detail: string;
|
|
15
|
+
};
|
|
16
|
+
export type HarnessImplementation = {
|
|
17
|
+
harnessId: HarnessId;
|
|
18
|
+
createRuntime: (cwd: string) => HarnessRuntime;
|
|
19
|
+
doctor: (cwd: string) => Promise<HarnessDoctorCheck[]>;
|
|
20
|
+
prepare: (cwd: string) => Promise<string>;
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare class Future<T> {
|
|
2
|
+
readonly promise: Promise<T>;
|
|
3
|
+
resolve?: (arg: T) => void;
|
|
4
|
+
reject?: (error: unknown) => void;
|
|
5
|
+
onFinally?: () => void;
|
|
6
|
+
constructor(futureBase?: (resolve: (arg: T) => void, reject: (error: unknown) => void) => void, onFinally?: () => void);
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export class Future {
|
|
2
|
+
promise;
|
|
3
|
+
resolve;
|
|
4
|
+
reject;
|
|
5
|
+
onFinally;
|
|
6
|
+
constructor(futureBase, onFinally) {
|
|
7
|
+
this.onFinally = onFinally;
|
|
8
|
+
this.promise = new Promise(async (resolve, reject) => {
|
|
9
|
+
this.resolve = resolve;
|
|
10
|
+
this.reject = reject;
|
|
11
|
+
if (futureBase)
|
|
12
|
+
await futureBase(resolve, reject);
|
|
13
|
+
}).finally(() => this.onFinally?.());
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type HarnessCommand, type HarnessEvent, type HostState } from '../messages.js';
|
|
2
|
+
import type { HarnessRuntime } from '../runtime.js';
|
|
3
|
+
export type HarnessHostOptions = {
|
|
4
|
+
hostId: string;
|
|
5
|
+
hostname: string;
|
|
6
|
+
stateFile: string;
|
|
7
|
+
runtimes: HarnessRuntime[];
|
|
8
|
+
emit: (event: HarnessEvent) => void;
|
|
9
|
+
onError: (error: unknown) => void;
|
|
10
|
+
};
|
|
11
|
+
export declare class HarnessHost {
|
|
12
|
+
private readonly options;
|
|
13
|
+
private readonly database;
|
|
14
|
+
private readonly repo;
|
|
15
|
+
private readonly runtimes;
|
|
16
|
+
private readonly sessions;
|
|
17
|
+
private readonly openingSessions;
|
|
18
|
+
private stopping;
|
|
19
|
+
private constructor();
|
|
20
|
+
static start: (options: HarnessHostOptions) => Promise<HarnessHost>;
|
|
21
|
+
getState: () => HostState;
|
|
22
|
+
handleCommand: (command: HarnessCommand) => Promise<void>;
|
|
23
|
+
stop: () => Promise<void>;
|
|
24
|
+
private submitMessage;
|
|
25
|
+
private steer;
|
|
26
|
+
private runTurn;
|
|
27
|
+
private abortTurn;
|
|
28
|
+
private sendTurnSnapshot;
|
|
29
|
+
private handleTurnSaved;
|
|
30
|
+
private destroySession;
|
|
31
|
+
private setSessionModel;
|
|
32
|
+
private setModel;
|
|
33
|
+
private getSession;
|
|
34
|
+
private openSession;
|
|
35
|
+
private publishTurnPart;
|
|
36
|
+
private emitActivity;
|
|
37
|
+
private saveSession;
|
|
38
|
+
private emitState;
|
|
39
|
+
}
|