@agentproto/harness 0.1.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/LICENSE +21 -0
- package/README.md +71 -0
- package/dist/index.d.ts +259 -0
- package/dist/index.mjs +322 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.mjs +3 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jeremy André and agentproto contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# @agentproto/harness
|
|
2
|
+
|
|
3
|
+
Typed presets for spinning up agentproto agent sessions in one call.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm add @agentproto/harness
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick-starts
|
|
12
|
+
|
|
13
|
+
### Coder (claude-code / opus)
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { connectHarness, createCoderHarness } from "@agentproto/harness"
|
|
17
|
+
|
|
18
|
+
const dx = await connectHarness()
|
|
19
|
+
const coder = await createCoderHarness(dx, {
|
|
20
|
+
workspace: "/path/to/repo",
|
|
21
|
+
context: { stack: "TypeScript, pnpm", gateCmds: ["pnpm check-types"] },
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const result = await coder.ask("Implement the Widget component")
|
|
25
|
+
console.log(result)
|
|
26
|
+
await coder.kill()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Coder (hermes + deepseek-v4-pro, cheaper)
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
const coder = await createCoderHarness(dx, {
|
|
33
|
+
workspace: "/path/to/repo",
|
|
34
|
+
engine: "hermes", // → deepseek/deepseek-v4-pro via OpenRouter
|
|
35
|
+
context: { gateCmds: ["pnpm test"] },
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Researcher (hermes + GLM-5.2, large context)
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { createResearcherHarness } from "@agentproto/harness"
|
|
43
|
+
|
|
44
|
+
const researcher = await createResearcherHarness(dx, {
|
|
45
|
+
// default model: z-ai/glm-5.2 via OpenRouter (1M+ context)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const report = await researcher.ask("Research the top 5 vector DB options in 2025")
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Supervisor (claude-code opus, orchestrates sub-agents)
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { createSupervisorHarness } from "@agentproto/harness"
|
|
55
|
+
|
|
56
|
+
const supervisor = await createSupervisorHarness(dx, {
|
|
57
|
+
workspace: "/path/to/repo",
|
|
58
|
+
workPackages: [
|
|
59
|
+
{ id: "WP1", title: "Add auth middleware", description: "...", gate: "pnpm test" },
|
|
60
|
+
{ id: "WP2", title: "Write tests", description: "...", gate: "pnpm test" },
|
|
61
|
+
],
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
await supervisor.waitForTurn({ timeoutMs: 120_000 })
|
|
65
|
+
const tree = await supervisor.subtree()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Prerequisites
|
|
69
|
+
|
|
70
|
+
- agentproto daemon running (`agentproto serve`) on port 18790
|
|
71
|
+
- For hermes models: `OPENROUTER_API_KEY` set in the daemon's environment
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { ConnectHarnessOptions, StartAgentArgs, SessionDescriptor, TurnEvent, TurnResult, AgentHandle, CoderContext, McpServerMount, OrchestratorOption } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @agentproto/harness — transport client (WP1).
|
|
5
|
+
*
|
|
6
|
+
* The single place that touches the MCP SDK + JSON-payload parsing. Connects to
|
|
7
|
+
* the daemon's `/mcp` endpoint over `StreamableHTTPClientTransport` and exposes
|
|
8
|
+
* typed wrappers over the session tools. Mirrors the proven pattern in
|
|
9
|
+
* `packages/cli/src/commands/mcp-bridge.ts:30-58`.
|
|
10
|
+
*
|
|
11
|
+
* Tool results come back as `content: [{ type: "text", text: <JSON> }]`; the
|
|
12
|
+
* `#call` helper unwraps + parses that text payload.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** Default daemon MCP endpoint (port 18790; `serve.ts:186,865`). */
|
|
16
|
+
declare const DEFAULT_MCP_URL = "http://127.0.0.1:18790/mcp";
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the daemon URL: explicit option → `AGENTPROTO_MCP_URL` → default.
|
|
19
|
+
*/
|
|
20
|
+
declare function resolveMcpUrl(opts?: ConnectHarnessOptions): string;
|
|
21
|
+
/**
|
|
22
|
+
* Thin typed facade over the daemon's session MCP tools. One instance is shared
|
|
23
|
+
* by all harnesses created against the same daemon.
|
|
24
|
+
*/
|
|
25
|
+
declare class HarnessClient {
|
|
26
|
+
#private;
|
|
27
|
+
readonly url: string;
|
|
28
|
+
private constructor();
|
|
29
|
+
/**
|
|
30
|
+
* Connect an MCP client over HTTP to the daemon's `/mcp` endpoint.
|
|
31
|
+
*/
|
|
32
|
+
static connect(opts?: ConnectHarnessOptions): Promise<HarnessClient>;
|
|
33
|
+
/** Spawn a session via `start_agent_session`. */
|
|
34
|
+
start(args: StartAgentArgs): Promise<SessionDescriptor>;
|
|
35
|
+
/** Send a follow-up turn via `prompt_agent_session` (fire-and-forget). */
|
|
36
|
+
prompt(sessionId: string, prompt: string): Promise<void>;
|
|
37
|
+
/** Tail the ring buffer via `get_agent_session_output`. */
|
|
38
|
+
output(sessionId: string, lastN?: number): Promise<string>;
|
|
39
|
+
/** SIGTERM via `kill_agent_session`. */
|
|
40
|
+
kill(sessionId: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Multiplexed long-poll via `wait_for_any`. `timeoutMs` is clamped to the
|
|
43
|
+
* tool's 1 000–49 000 window; a clean timeout surfaces as
|
|
44
|
+
* `{ event: "timeout" }`.
|
|
45
|
+
*/
|
|
46
|
+
waitForAny(sessionIds: string[], opts?: {
|
|
47
|
+
timeoutMs?: number;
|
|
48
|
+
event?: TurnEvent;
|
|
49
|
+
}): Promise<TurnResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Snapshot the session hierarchy via `session_tree`. When called from a
|
|
52
|
+
* scoped orchestrator token only the caller's subtree is returned.
|
|
53
|
+
*/
|
|
54
|
+
sessionTree(sessionId: string, onlyAlive?: boolean): Promise<unknown>;
|
|
55
|
+
/** Disconnect the underlying transport. */
|
|
56
|
+
close(): Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @agentproto/harness — AgentHandle factory (WP2, STUB).
|
|
61
|
+
*
|
|
62
|
+
* `makeHandle` adapts a `HarnessClient` + a live session into the uniform
|
|
63
|
+
* `AgentHandle` contract that every preset returns.
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
interface MakeHandleMeta {
|
|
67
|
+
sessionId: string;
|
|
68
|
+
adapter: string;
|
|
69
|
+
model?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Build an `AgentHandle` over a started session.
|
|
73
|
+
*
|
|
74
|
+
* WP2: implement `send` (→ client.prompt), `waitForTurn` (→ client.waitForAny
|
|
75
|
+
* with `event: "any"` to catch `turn-end`, `awaiting-input`, and `exited`),
|
|
76
|
+
* timeout → `{ event: "timeout" }`), `ask` (send + waitForTurn + output),
|
|
77
|
+
* `output` (→ client.output), `kill` (→ client.kill).
|
|
78
|
+
*/
|
|
79
|
+
declare function makeHandle(client: HarnessClient, meta: MakeHandleMeta): AgentHandle;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @agentproto/harness — coding context types + rendering.
|
|
83
|
+
*
|
|
84
|
+
* Extract of the coder preset's `CoderContext` shape and its prompt renderer,
|
|
85
|
+
* so both the harness and the supervisor can reference them without a circular
|
|
86
|
+
* import through the harness file.
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Renders a `CoderContext` into an agent-facing instruction block.
|
|
91
|
+
*
|
|
92
|
+
* Produces a short markdown block with stack, conventions, and gate commands
|
|
93
|
+
* the agent should verify before declaring a task done.
|
|
94
|
+
*/
|
|
95
|
+
declare function renderCoderPrompt(ctx: CoderContext): string;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @agentproto/harness — coder preset (WP3, STUB).
|
|
99
|
+
*
|
|
100
|
+
* Spawns a coding agent: `claude-code` (default) or `hermes` routed to a coding
|
|
101
|
+
* model via OpenRouter. Sets cwd to the workspace and injects a coding context
|
|
102
|
+
* (stack, conventions, gate commands) as the initial prompt.
|
|
103
|
+
*/
|
|
104
|
+
|
|
105
|
+
interface CoderHarnessOptions {
|
|
106
|
+
/** Absolute workspace path (wins over `workspaceSlug`). */
|
|
107
|
+
workspace?: string;
|
|
108
|
+
workspaceSlug?: string;
|
|
109
|
+
/** Engine selector. Default `claude-code`. */
|
|
110
|
+
engine?: "claude-code" | "hermes";
|
|
111
|
+
/** Model override. Defaults: claude-code → `claude-opus-4-8`;
|
|
112
|
+
* hermes → `deepseek/deepseek-v4-pro` (confirmed live, WP6). */
|
|
113
|
+
model?: string;
|
|
114
|
+
/** Reasoning effort. Default `high`. */
|
|
115
|
+
effort?: string;
|
|
116
|
+
/** Coding context rendered into the spawn prompt. */
|
|
117
|
+
context?: CoderContext;
|
|
118
|
+
label?: string;
|
|
119
|
+
mcpServers?: McpServerMount[];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Build the `start_agent_session` args for the coder preset. Exported so WP3's
|
|
123
|
+
* unit test can snapshot the args for both engines without a live daemon.
|
|
124
|
+
*
|
|
125
|
+
* For hermes: `model` and `effort` are NOT included — hermes does not declare
|
|
126
|
+
* them as manifest options so the daemon rejects them at compose time. Instead,
|
|
127
|
+
* `createCoderHarness` sends `/model <slug>` as a first prompt turn after spawn.
|
|
128
|
+
*/
|
|
129
|
+
declare function buildCoderArgs(opts: CoderHarnessOptions): StartAgentArgs;
|
|
130
|
+
/** Create a coder session and return its handle. */
|
|
131
|
+
declare function createCoderHarness(client: HarnessClient, opts?: CoderHarnessOptions): Promise<AgentHandle>;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @agentproto/harness — researcher preset (WP4).
|
|
135
|
+
*
|
|
136
|
+
* Spawns a big-context research agent: `hermes` routed to GLM-5.2 via
|
|
137
|
+
* OpenRouter. Mounts a web-search MCP server and injects a structured-output
|
|
138
|
+
* instruction so replies are parseable.
|
|
139
|
+
*/
|
|
140
|
+
|
|
141
|
+
interface ResearcherHarnessOptions {
|
|
142
|
+
/** Model override. Default `z-ai/glm-5.2` (big context, WP6). */
|
|
143
|
+
model?: string;
|
|
144
|
+
cwd?: string;
|
|
145
|
+
workspaceSlug?: string;
|
|
146
|
+
/** MCP server to mount for web search (e.g. a bureau/search MCP ref). */
|
|
147
|
+
searchMcp?: McpServerMount;
|
|
148
|
+
/** JSON schema hint injected into the spawn prompt for structured output. */
|
|
149
|
+
outputSchema?: Record<string, unknown>;
|
|
150
|
+
effort?: string;
|
|
151
|
+
label?: string;
|
|
152
|
+
mcpServers?: McpServerMount[];
|
|
153
|
+
}
|
|
154
|
+
/** Default output-schema hint the researcher is asked to return. */
|
|
155
|
+
declare const DEFAULT_RESEARCH_SCHEMA: {
|
|
156
|
+
readonly findings: "string[]";
|
|
157
|
+
readonly sources: "string[]";
|
|
158
|
+
readonly confidence: "low | medium | high";
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Render the researcher spawn prompt — an instruction block telling the agent:
|
|
162
|
+
* 1. It is a researcher agent.
|
|
163
|
+
* 2. It MUST structure its final answer as JSON matching the outputSchema.
|
|
164
|
+
* 3. Brief format hint: { findings: [...], sources: [...], confidence: "..." }
|
|
165
|
+
*
|
|
166
|
+
* Exported for unit tests.
|
|
167
|
+
*/
|
|
168
|
+
declare function renderResearcherPrompt(opts: ResearcherHarnessOptions): string;
|
|
169
|
+
/**
|
|
170
|
+
* Build the `start_agent_session` args for the researcher preset.
|
|
171
|
+
* Exported so WP4's unit test can assert `mcpServers` + schema are present.
|
|
172
|
+
*
|
|
173
|
+
* `model`, `effort`, and the system `prompt` are NOT included here —
|
|
174
|
+
* `createResearcherHarness` delivers them as controlled turns after spawn
|
|
175
|
+
* so each step has exactly one turn-end to drain:
|
|
176
|
+
* 1. `/model <slug>` → model switch turn-end (fast)
|
|
177
|
+
* 2. system prompt turn → LLM response turn-end (may be slow)
|
|
178
|
+
* This avoids the race where a spawn-time prompt fires a turn-end that
|
|
179
|
+
* interferes with the caller's first `ask()`.
|
|
180
|
+
*/
|
|
181
|
+
declare function buildResearcherArgs(opts: ResearcherHarnessOptions): StartAgentArgs;
|
|
182
|
+
/** Create a researcher session and return its handle. */
|
|
183
|
+
declare function createResearcherHarness(client: HarnessClient, opts?: ResearcherHarnessOptions): Promise<AgentHandle>;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* @agentproto/harness — WorkPackage type + supervisor prompt renderer (WP5).
|
|
187
|
+
*
|
|
188
|
+
* A WorkPackage describes a unit of work the supervisor assigns to a sub-agent.
|
|
189
|
+
* `renderSupervisorPrompt` turns a list into a markdown orchestration brief.
|
|
190
|
+
*/
|
|
191
|
+
/** A unit of work the supervisor harness assigns to a sub-agent. */
|
|
192
|
+
interface WorkPackage {
|
|
193
|
+
id: string;
|
|
194
|
+
title: string;
|
|
195
|
+
description: string;
|
|
196
|
+
files?: string[];
|
|
197
|
+
gate?: string;
|
|
198
|
+
}
|
|
199
|
+
/** Renders a WP list into a supervisor orchestration brief. */
|
|
200
|
+
declare function renderSupervisorPrompt(workPackages: WorkPackage[]): string;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @agentproto/harness — supervisor preset (WP5).
|
|
204
|
+
*
|
|
205
|
+
* Spawns a `claude-code` opus orchestrator with `orchestrator: true` so it can
|
|
206
|
+
* spawn + supervise its OWN sub-agents via the daemon's scoped sub-gateway.
|
|
207
|
+
* Accepts a Work-Package list and renders it into an orchestration brief, and
|
|
208
|
+
* adds fan-in helpers (`subtree`, `waitForAnyChild`) on top of `AgentHandle`.
|
|
209
|
+
*/
|
|
210
|
+
|
|
211
|
+
interface SupervisorHarnessOptions {
|
|
212
|
+
workspace?: string;
|
|
213
|
+
workspaceSlug?: string;
|
|
214
|
+
/** Model override. Default `claude-opus-4-8`. */
|
|
215
|
+
model?: string;
|
|
216
|
+
effort?: string;
|
|
217
|
+
/** Scoped-orchestrator config. Default `true` (curated subset). */
|
|
218
|
+
orchestrator?: OrchestratorOption;
|
|
219
|
+
/** Work packages to render into the orchestration brief. */
|
|
220
|
+
workPackages?: WorkPackage[];
|
|
221
|
+
label?: string;
|
|
222
|
+
}
|
|
223
|
+
/** Supervisor handle adds fan-in helpers over the base contract. */
|
|
224
|
+
interface SupervisorHandle extends AgentHandle {
|
|
225
|
+
/** Snapshot this session's child subtree (→ `session_tree`). */
|
|
226
|
+
subtree(): Promise<unknown>;
|
|
227
|
+
/** Block until ANY child session ends a turn (→ `wait_for_any`). */
|
|
228
|
+
waitForAnyChild(opts?: {
|
|
229
|
+
timeoutMs?: number;
|
|
230
|
+
}): Promise<TurnResult>;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Build the `start_agent_session` args for the supervisor preset. Exported so
|
|
234
|
+
* WP5's unit test can assert `orchestrator` + the rendered WP brief.
|
|
235
|
+
*/
|
|
236
|
+
declare function buildSupervisorArgs(opts: SupervisorHarnessOptions): StartAgentArgs;
|
|
237
|
+
/** Create a supervisor session and return its (extended) handle. */
|
|
238
|
+
declare function createSupervisorHarness(client: HarnessClient, opts?: SupervisorHarnessOptions): Promise<SupervisorHandle>;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* @agentproto/harness — public barrel.
|
|
242
|
+
*
|
|
243
|
+
* Typed, one-call agent-session presets over the agentproto daemon's session
|
|
244
|
+
* tools. Connect once, then spin up `coder` / `researcher` / `supervisor`
|
|
245
|
+
* sessions that all resolve to the uniform `AgentHandle` contract.
|
|
246
|
+
*
|
|
247
|
+
* import { connectHarness, createCoderHarness } from "@agentproto/harness"
|
|
248
|
+
* const dx = await connectHarness()
|
|
249
|
+
* const coder = await createCoderHarness(dx, { workspace: process.cwd() })
|
|
250
|
+
* const reply = await coder.ask("Add a health-check route")
|
|
251
|
+
*/
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Connect the shared transport to the daemon's `/mcp` endpoint. Returns a
|
|
255
|
+
* `HarnessClient` to hand to the `create*Harness` factories.
|
|
256
|
+
*/
|
|
257
|
+
declare function connectHarness(opts?: ConnectHarnessOptions): Promise<HarnessClient>;
|
|
258
|
+
|
|
259
|
+
export { AgentHandle, CoderContext, type CoderHarnessOptions, ConnectHarnessOptions, DEFAULT_MCP_URL, DEFAULT_RESEARCH_SCHEMA, HarnessClient, McpServerMount, OrchestratorOption, type ResearcherHarnessOptions, SessionDescriptor, StartAgentArgs, type SupervisorHandle, type SupervisorHarnessOptions, TurnEvent, TurnResult, type WorkPackage, buildCoderArgs, buildResearcherArgs, buildSupervisorArgs, connectHarness, createCoderHarness, createResearcherHarness, createSupervisorHarness, makeHandle, renderCoderPrompt, renderResearcherPrompt, renderSupervisorPrompt, resolveMcpUrl };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @agentproto/harness v0.1.0-alpha
|
|
6
|
+
* Typed one-call agent-session presets over the agentproto daemon.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
var DEFAULT_MCP_URL = "http://127.0.0.1:18790/mcp";
|
|
10
|
+
function resolveMcpUrl(opts) {
|
|
11
|
+
return opts?.url ?? process.env.AGENTPROTO_MCP_URL ?? DEFAULT_MCP_URL;
|
|
12
|
+
}
|
|
13
|
+
var HarnessClient = class _HarnessClient {
|
|
14
|
+
url;
|
|
15
|
+
#client;
|
|
16
|
+
constructor(url, client) {
|
|
17
|
+
this.url = url;
|
|
18
|
+
this.#client = client;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Connect an MCP client over HTTP to the daemon's `/mcp` endpoint.
|
|
22
|
+
*/
|
|
23
|
+
static async connect(opts) {
|
|
24
|
+
const url = resolveMcpUrl(opts);
|
|
25
|
+
const client = new Client(
|
|
26
|
+
{ name: "harness", version: "0.1.0" },
|
|
27
|
+
{ capabilities: {} }
|
|
28
|
+
);
|
|
29
|
+
const transport = new StreamableHTTPClientTransport(new URL(url));
|
|
30
|
+
await client.connect(transport);
|
|
31
|
+
return new _HarnessClient(url, client);
|
|
32
|
+
}
|
|
33
|
+
/** Spawn a session via `start_agent_session`. */
|
|
34
|
+
async start(args) {
|
|
35
|
+
return this.#call("start_agent_session", args);
|
|
36
|
+
}
|
|
37
|
+
/** Send a follow-up turn via `prompt_agent_session` (fire-and-forget). */
|
|
38
|
+
async prompt(sessionId, prompt) {
|
|
39
|
+
await this.#call("prompt_agent_session", { sessionId, prompt });
|
|
40
|
+
}
|
|
41
|
+
/** Tail the ring buffer via `get_agent_session_output`. */
|
|
42
|
+
async output(sessionId, lastN) {
|
|
43
|
+
const res = await this.#call(
|
|
44
|
+
"get_agent_session_output",
|
|
45
|
+
{ sessionId, lastN }
|
|
46
|
+
);
|
|
47
|
+
return (res.lines ?? []).join("\n");
|
|
48
|
+
}
|
|
49
|
+
/** SIGTERM via `kill_agent_session`. */
|
|
50
|
+
async kill(sessionId) {
|
|
51
|
+
await this.#call("kill_agent_session", { sessionId });
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Multiplexed long-poll via `wait_for_any`. `timeoutMs` is clamped to the
|
|
55
|
+
* tool's 1 000–49 000 window; a clean timeout surfaces as
|
|
56
|
+
* `{ event: "timeout" }`.
|
|
57
|
+
*/
|
|
58
|
+
async waitForAny(sessionIds, opts) {
|
|
59
|
+
return this.#call("wait_for_any", {
|
|
60
|
+
sessionIds,
|
|
61
|
+
...opts?.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
62
|
+
...opts?.event !== void 0 ? { event: opts.event } : {}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Snapshot the session hierarchy via `session_tree`. When called from a
|
|
67
|
+
* scoped orchestrator token only the caller's subtree is returned.
|
|
68
|
+
*/
|
|
69
|
+
async sessionTree(sessionId, onlyAlive) {
|
|
70
|
+
return this.#call("session_tree", {
|
|
71
|
+
sessionId,
|
|
72
|
+
...onlyAlive !== void 0 ? { onlyAlive } : {}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** Disconnect the underlying transport. */
|
|
76
|
+
async close() {
|
|
77
|
+
await this.#client.close();
|
|
78
|
+
}
|
|
79
|
+
// ── private helpers ────────────────────────────────────────────────
|
|
80
|
+
/** Call a daemon MCP tool and unwrap its JSON response. */
|
|
81
|
+
async #call(name, args) {
|
|
82
|
+
const res = await this.#client.callTool({ name, arguments: args });
|
|
83
|
+
const text = res.content[0]?.text;
|
|
84
|
+
if (!text) {
|
|
85
|
+
throw new Error(`No content from tool \`${name}\``);
|
|
86
|
+
}
|
|
87
|
+
if (res.isError) {
|
|
88
|
+
throw new Error(`Tool \`${name}\` returned error: ${text}`);
|
|
89
|
+
}
|
|
90
|
+
return JSON.parse(text);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// src/handle.ts
|
|
95
|
+
function makeHandle(client, meta) {
|
|
96
|
+
return {
|
|
97
|
+
sessionId: meta.sessionId,
|
|
98
|
+
adapter: meta.adapter,
|
|
99
|
+
model: meta.model,
|
|
100
|
+
async send(prompt) {
|
|
101
|
+
await client.prompt(meta.sessionId, prompt);
|
|
102
|
+
},
|
|
103
|
+
async waitForTurn(opts) {
|
|
104
|
+
return client.waitForAny([meta.sessionId], {
|
|
105
|
+
event: "any",
|
|
106
|
+
...opts?.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {}
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
async ask(prompt, opts) {
|
|
110
|
+
const waitPromise = client.waitForAny([meta.sessionId], {
|
|
111
|
+
event: "any",
|
|
112
|
+
timeoutMs: opts?.timeoutMs !== void 0 ? opts.timeoutMs : 45e3
|
|
113
|
+
});
|
|
114
|
+
await client.prompt(meta.sessionId, prompt);
|
|
115
|
+
const result = await waitPromise;
|
|
116
|
+
if (result.event === "timeout") return "[timeout]";
|
|
117
|
+
return client.output(meta.sessionId);
|
|
118
|
+
},
|
|
119
|
+
async output(opts) {
|
|
120
|
+
return client.output(meta.sessionId, opts?.lastN);
|
|
121
|
+
},
|
|
122
|
+
async kill() {
|
|
123
|
+
await client.kill(meta.sessionId);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/context.ts
|
|
129
|
+
function renderCoderPrompt(ctx) {
|
|
130
|
+
const parts = ["## Coding context"];
|
|
131
|
+
if (ctx.stack) parts.push(`**Stack:** ${ctx.stack}`);
|
|
132
|
+
if (ctx.conventions) parts.push(`**Conventions:** ${ctx.conventions}`);
|
|
133
|
+
if (ctx.gateCmds?.length) {
|
|
134
|
+
parts.push(
|
|
135
|
+
`**Gate:** ${ctx.gateCmds.map((c) => `\`${c}\``).join(" \xB7 ")}`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
if (ctx.extra) parts.push(ctx.extra);
|
|
139
|
+
return parts.join("\n");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/harnesses/coder.ts
|
|
143
|
+
var DEFAULTS = {
|
|
144
|
+
claudeCodeModel: "claude-opus-4-8",
|
|
145
|
+
hermesModel: "deepseek/deepseek-v4-pro",
|
|
146
|
+
effort: "high"
|
|
147
|
+
};
|
|
148
|
+
function buildCoderArgs(opts) {
|
|
149
|
+
const engine = opts.engine ?? "claude-code";
|
|
150
|
+
const isHermes = engine === "hermes";
|
|
151
|
+
const model = opts.model ?? (isHermes ? DEFAULTS.hermesModel : DEFAULTS.claudeCodeModel);
|
|
152
|
+
return {
|
|
153
|
+
adapter: engine,
|
|
154
|
+
...isHermes ? {} : { model, effort: opts.effort ?? DEFAULTS.effort },
|
|
155
|
+
...opts.workspace ? { cwd: opts.workspace } : {},
|
|
156
|
+
...opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {},
|
|
157
|
+
...opts.context ? { prompt: renderCoderPrompt(opts.context) } : {},
|
|
158
|
+
...opts.label ? { label: opts.label } : {},
|
|
159
|
+
...opts.mcpServers ? { mcpServers: opts.mcpServers } : {}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
async function createCoderHarness(client, opts = {}) {
|
|
163
|
+
const engine = opts.engine ?? "claude-code";
|
|
164
|
+
const isHermes = engine === "hermes";
|
|
165
|
+
const modelSlug = isHermes ? opts.model ?? DEFAULTS.hermesModel : opts.model ?? DEFAULTS.claudeCodeModel;
|
|
166
|
+
const args = buildCoderArgs(opts);
|
|
167
|
+
const desc = await client.start(args);
|
|
168
|
+
if (isHermes && modelSlug) {
|
|
169
|
+
await client.prompt(desc.id, `/model ${modelSlug}`);
|
|
170
|
+
await client.waitForAny([desc.id], { event: "turn-end", timeoutMs: 15e3 });
|
|
171
|
+
}
|
|
172
|
+
return makeHandle(client, {
|
|
173
|
+
sessionId: desc.id,
|
|
174
|
+
adapter: args.adapter,
|
|
175
|
+
model: modelSlug
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/harnesses/researcher.ts
|
|
180
|
+
var DEFAULTS2 = {
|
|
181
|
+
model: "z-ai/glm-5.2"
|
|
182
|
+
};
|
|
183
|
+
var DEFAULT_RESEARCH_SCHEMA = {
|
|
184
|
+
findings: "string[]",
|
|
185
|
+
sources: "string[]",
|
|
186
|
+
confidence: "low | medium | high"
|
|
187
|
+
};
|
|
188
|
+
function renderResearcherPrompt(opts) {
|
|
189
|
+
const schema = opts.outputSchema ?? DEFAULT_RESEARCH_SCHEMA;
|
|
190
|
+
return [
|
|
191
|
+
"You are a researcher agent. Use the available web-search tools to gather",
|
|
192
|
+
"evidence and synthesize findings.",
|
|
193
|
+
"Always reply in English regardless of the query language.",
|
|
194
|
+
"",
|
|
195
|
+
"You MUST structure your final answer as JSON matching this schema:",
|
|
196
|
+
JSON.stringify(schema, null, 2),
|
|
197
|
+
"",
|
|
198
|
+
"Format hint:",
|
|
199
|
+
" {",
|
|
200
|
+
' "findings": ["key finding 1", "key finding 2", ...],',
|
|
201
|
+
' "sources": ["url or citation", ...],',
|
|
202
|
+
' "confidence": "low | medium | high"',
|
|
203
|
+
" }"
|
|
204
|
+
].join("\n");
|
|
205
|
+
}
|
|
206
|
+
function buildResearcherArgs(opts) {
|
|
207
|
+
const mcpServers = [
|
|
208
|
+
...opts.mcpServers ?? [],
|
|
209
|
+
...opts.searchMcp ? [opts.searchMcp] : []
|
|
210
|
+
];
|
|
211
|
+
return {
|
|
212
|
+
adapter: "hermes",
|
|
213
|
+
...opts.cwd ? { cwd: opts.cwd } : {},
|
|
214
|
+
...opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {},
|
|
215
|
+
...mcpServers.length ? { mcpServers } : {},
|
|
216
|
+
...opts.label ? { label: opts.label } : {}
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
async function createResearcherHarness(client, opts = {}) {
|
|
220
|
+
const modelSlug = opts.model ?? DEFAULTS2.model;
|
|
221
|
+
const args = buildResearcherArgs(opts);
|
|
222
|
+
const desc = await client.start(args);
|
|
223
|
+
if (modelSlug) {
|
|
224
|
+
await client.prompt(desc.id, `/model ${modelSlug}`);
|
|
225
|
+
await client.waitForAny([desc.id], { event: "turn-end", timeoutMs: 15e3 });
|
|
226
|
+
}
|
|
227
|
+
await client.prompt(desc.id, renderResearcherPrompt(opts));
|
|
228
|
+
await client.waitForAny([desc.id], { event: "turn-end", timeoutMs: 3e4 });
|
|
229
|
+
return makeHandle(client, {
|
|
230
|
+
sessionId: desc.id,
|
|
231
|
+
adapter: args.adapter,
|
|
232
|
+
model: modelSlug
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// src/wp.ts
|
|
237
|
+
function renderSupervisorPrompt(workPackages) {
|
|
238
|
+
const header = "You are a supervisor agent. Execute the following work packages in order, assigning each to a sub-agent. Gate each WP before proceeding to the next.";
|
|
239
|
+
const body = workPackages.map((wp) => {
|
|
240
|
+
let s = `## ${wp.id} \u2014 ${wp.title}
|
|
241
|
+
${wp.description}`;
|
|
242
|
+
if (wp.files?.length) s += `
|
|
243
|
+
Files: ${wp.files.join(", ")}`;
|
|
244
|
+
if (wp.gate) s += `
|
|
245
|
+
Gate: ${wp.gate}`;
|
|
246
|
+
return s;
|
|
247
|
+
}).join("\n\n");
|
|
248
|
+
return `${header}
|
|
249
|
+
|
|
250
|
+
${body}`;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/harnesses/supervisor.ts
|
|
254
|
+
var DEFAULTS3 = {
|
|
255
|
+
model: "claude-opus-4-8",
|
|
256
|
+
effort: "high"
|
|
257
|
+
};
|
|
258
|
+
function buildSupervisorArgs(opts) {
|
|
259
|
+
return {
|
|
260
|
+
adapter: "claude-code",
|
|
261
|
+
model: opts.model ?? DEFAULTS3.model,
|
|
262
|
+
effort: opts.effort ?? DEFAULTS3.effort,
|
|
263
|
+
orchestrator: opts.orchestrator ?? true,
|
|
264
|
+
...opts.workspace ? { cwd: opts.workspace } : {},
|
|
265
|
+
...opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {},
|
|
266
|
+
...opts.workPackages?.length ? { prompt: renderSupervisorPrompt(opts.workPackages) } : {},
|
|
267
|
+
...opts.label ? { label: opts.label } : {}
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
async function createSupervisorHarness(client, opts = {}) {
|
|
271
|
+
const args = buildSupervisorArgs(opts);
|
|
272
|
+
const desc = await client.start(args);
|
|
273
|
+
const base = makeHandle(client, {
|
|
274
|
+
sessionId: desc.id,
|
|
275
|
+
adapter: args.adapter,
|
|
276
|
+
...args.model ? { model: args.model } : {}
|
|
277
|
+
});
|
|
278
|
+
return {
|
|
279
|
+
...base,
|
|
280
|
+
async subtree() {
|
|
281
|
+
return client.sessionTree(desc.id);
|
|
282
|
+
},
|
|
283
|
+
async waitForAnyChild(opts2) {
|
|
284
|
+
const data = await client.sessionTree(desc.id);
|
|
285
|
+
const childIds = collectChildIds(data.tree ?? []);
|
|
286
|
+
if (childIds.length === 0) {
|
|
287
|
+
return {
|
|
288
|
+
sessionId: desc.id,
|
|
289
|
+
event: "timeout"
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const CHUNK = 20;
|
|
293
|
+
if (childIds.length <= CHUNK) {
|
|
294
|
+
return client.waitForAny(childIds, opts2);
|
|
295
|
+
}
|
|
296
|
+
const chunks = [];
|
|
297
|
+
for (let i = 0; i < childIds.length; i += CHUNK) {
|
|
298
|
+
chunks.push(childIds.slice(i, i + CHUNK));
|
|
299
|
+
}
|
|
300
|
+
return Promise.race(chunks.map((chunk) => client.waitForAny(chunk, opts2)));
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function collectChildIds(nodes) {
|
|
305
|
+
const ids = [];
|
|
306
|
+
for (const node of nodes) {
|
|
307
|
+
ids.push(node.id);
|
|
308
|
+
if (node.children?.length) {
|
|
309
|
+
ids.push(...collectChildIds(node.children));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return ids;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// src/index.ts
|
|
316
|
+
async function connectHarness(opts) {
|
|
317
|
+
return HarnessClient.connect(opts);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export { DEFAULT_MCP_URL, DEFAULT_RESEARCH_SCHEMA, HarnessClient, buildCoderArgs, buildResearcherArgs, buildSupervisorArgs, connectHarness, createCoderHarness, createResearcherHarness, createSupervisorHarness, makeHandle, renderCoderPrompt, renderResearcherPrompt, renderSupervisorPrompt, resolveMcpUrl };
|
|
321
|
+
//# sourceMappingURL=index.mjs.map
|
|
322
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/handle.ts","../src/context.ts","../src/harnesses/coder.ts","../src/harnesses/researcher.ts","../src/wp.ts","../src/harnesses/supervisor.ts","../src/index.ts"],"names":["DEFAULTS","opts"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @agentproto/harness — transport client (WP1).\n *\n * The single place that touches the MCP SDK + JSON-payload parsing. Connects to\n * the daemon's `/mcp` endpoint over `StreamableHTTPClientTransport` and exposes\n * typed wrappers over the session tools. Mirrors the proven pattern in\n * `packages/cli/src/commands/mcp-bridge.ts:30-58`.\n *\n * Tool results come back as `content: [{ type: \"text\", text: <JSON> }]`; the\n * `#call` helper unwraps + parses that text payload.\n */\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\"\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\"\nimport type {\n ConnectHarnessOptions,\n SessionDescriptor,\n StartAgentArgs,\n TurnEvent,\n TurnResult,\n} from \"./types.js\"\n\n/** Default daemon MCP endpoint (port 18790; `serve.ts:186,865`). */\nexport const DEFAULT_MCP_URL = \"http://127.0.0.1:18790/mcp\"\n\n/**\n * Resolve the daemon URL: explicit option → `AGENTPROTO_MCP_URL` → default.\n */\nexport function resolveMcpUrl(opts?: ConnectHarnessOptions): string {\n return (\n opts?.url ?? process.env.AGENTPROTO_MCP_URL ?? DEFAULT_MCP_URL\n )\n}\n\n/**\n * Thin typed facade over the daemon's session MCP tools. One instance is shared\n * by all harnesses created against the same daemon.\n */\nexport class HarnessClient {\n readonly url: string\n #client: Client\n\n private constructor(url: string, client: Client) {\n this.url = url\n this.#client = client\n }\n\n /**\n * Connect an MCP client over HTTP to the daemon's `/mcp` endpoint.\n */\n static async connect(opts?: ConnectHarnessOptions): Promise<HarnessClient> {\n const url = resolveMcpUrl(opts)\n const client = new Client(\n { name: \"harness\", version: \"0.1.0\" },\n { capabilities: {} },\n )\n const transport = new StreamableHTTPClientTransport(new URL(url))\n await client.connect(transport)\n return new HarnessClient(url, client)\n }\n\n /** Spawn a session via `start_agent_session`. */\n async start(args: StartAgentArgs): Promise<SessionDescriptor> {\n return this.#call(\"start_agent_session\", args as unknown as Record<string, unknown>)\n }\n\n /** Send a follow-up turn via `prompt_agent_session` (fire-and-forget). */\n async prompt(sessionId: string, prompt: string): Promise<void> {\n await this.#call(\"prompt_agent_session\", { sessionId, prompt })\n }\n\n /** Tail the ring buffer via `get_agent_session_output`. */\n async output(sessionId: string, lastN?: number): Promise<string> {\n const res = await this.#call<{ lines?: string[] }>(\n \"get_agent_session_output\",\n { sessionId, lastN },\n )\n return (res.lines ?? []).join(\"\\n\")\n }\n\n /** SIGTERM via `kill_agent_session`. */\n async kill(sessionId: string): Promise<void> {\n await this.#call(\"kill_agent_session\", { sessionId })\n }\n\n /**\n * Multiplexed long-poll via `wait_for_any`. `timeoutMs` is clamped to the\n * tool's 1 000–49 000 window; a clean timeout surfaces as\n * `{ event: \"timeout\" }`.\n */\n async waitForAny(\n sessionIds: string[],\n opts?: { timeoutMs?: number; event?: TurnEvent },\n ): Promise<TurnResult> {\n return this.#call(\"wait_for_any\", {\n sessionIds,\n ...(opts?.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),\n ...(opts?.event !== undefined ? { event: opts.event } : {}),\n })\n }\n\n /**\n * Snapshot the session hierarchy via `session_tree`. When called from a\n * scoped orchestrator token only the caller's subtree is returned.\n */\n async sessionTree(sessionId: string, onlyAlive?: boolean): Promise<unknown> {\n return this.#call(\"session_tree\", {\n sessionId,\n ...(onlyAlive !== undefined ? { onlyAlive } : {}),\n })\n }\n\n /** Disconnect the underlying transport. */\n async close(): Promise<void> {\n await this.#client.close()\n }\n\n // ── private helpers ────────────────────────────────────────────────\n\n /** Call a daemon MCP tool and unwrap its JSON response. */\n async #call<T = unknown>(\n name: string,\n args: Record<string, unknown>,\n ): Promise<T> {\n const res = await this.#client.callTool({ name, arguments: args })\n const text = (\n res.content as Array<{ type: string; text?: string }>\n )[0]?.text\n if (!text) {\n throw new Error(`No content from tool \\`${name}\\``)\n }\n // TODO: remove cast once SDK types are stable — CallToolResult already\n // carries isError?: boolean in newer SDK versions.\n if ((res as { isError?: boolean }).isError) {\n throw new Error(`Tool \\`${name}\\` returned error: ${text}`)\n }\n return JSON.parse(text) as T\n }\n}\n","/**\n * @agentproto/harness — AgentHandle factory (WP2, STUB).\n *\n * `makeHandle` adapts a `HarnessClient` + a live session into the uniform\n * `AgentHandle` contract that every preset returns.\n */\n\nimport type { HarnessClient } from \"./client.js\"\nimport type { AgentHandle, TurnResult } from \"./types.js\"\n\nexport type { AgentHandle } from \"./types.js\"\n\nexport interface MakeHandleMeta {\n sessionId: string\n adapter: string\n model?: string\n}\n\n/**\n * Build an `AgentHandle` over a started session.\n *\n * WP2: implement `send` (→ client.prompt), `waitForTurn` (→ client.waitForAny\n * with `event: \"any\"` to catch `turn-end`, `awaiting-input`, and `exited`),\n * timeout → `{ event: \"timeout\" }`), `ask` (send + waitForTurn + output),\n * `output` (→ client.output), `kill` (→ client.kill).\n */\nexport function makeHandle(\n client: HarnessClient,\n meta: MakeHandleMeta,\n): AgentHandle {\n return {\n sessionId: meta.sessionId,\n adapter: meta.adapter,\n model: meta.model,\n\n async send(prompt: string): Promise<void> {\n await client.prompt(meta.sessionId, prompt)\n },\n\n async waitForTurn(opts?: { timeoutMs?: number }): Promise<TurnResult> {\n return client.waitForAny([meta.sessionId], {\n event: \"any\",\n ...(opts?.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),\n })\n },\n\n async ask(prompt: string, opts?: { timeoutMs?: number }): Promise<string> {\n // Start the wait BEFORE sending to avoid a race window: if the agent\n // turns around extremely fast the prompt could produce a turn-end before\n // waitForAny subscribes.\n const waitPromise = client.waitForAny([meta.sessionId], {\n event: \"any\",\n timeoutMs: opts?.timeoutMs !== undefined ? opts.timeoutMs : 45000,\n })\n await client.prompt(meta.sessionId, prompt)\n const result = await waitPromise\n if (result.event === \"timeout\") return \"[timeout]\"\n return client.output(meta.sessionId)\n },\n\n async output(opts?: { lastN?: number }): Promise<string> {\n return client.output(meta.sessionId, opts?.lastN)\n },\n\n async kill(): Promise<void> {\n await client.kill(meta.sessionId)\n },\n }\n}\n","/**\n * @agentproto/harness — coding context types + rendering.\n *\n * Extract of the coder preset's `CoderContext` shape and its prompt renderer,\n * so both the harness and the supervisor can reference them without a circular\n * import through the harness file.\n */\n\nimport type { CoderContext } from \"./types.js\"\n\nexport type { CoderContext }\n\n/**\n * Renders a `CoderContext` into an agent-facing instruction block.\n *\n * Produces a short markdown block with stack, conventions, and gate commands\n * the agent should verify before declaring a task done.\n */\nexport function renderCoderPrompt(ctx: CoderContext): string {\n const parts: string[] = [\"## Coding context\"]\n if (ctx.stack) parts.push(`**Stack:** ${ctx.stack}`)\n if (ctx.conventions) parts.push(`**Conventions:** ${ctx.conventions}`)\n if (ctx.gateCmds?.length) {\n parts.push(\n `**Gate:** ${ctx.gateCmds.map((c) => `\\`${c}\\``).join(\" · \")}`,\n )\n }\n if (ctx.extra) parts.push(ctx.extra)\n return parts.join(\"\\n\")\n}","/**\n * @agentproto/harness — coder preset (WP3, STUB).\n *\n * Spawns a coding agent: `claude-code` (default) or `hermes` routed to a coding\n * model via OpenRouter. Sets cwd to the workspace and injects a coding context\n * (stack, conventions, gate commands) as the initial prompt.\n */\n\nimport type { HarnessClient } from \"../client.js\"\nimport { renderCoderPrompt } from \"../context.js\"\nexport { renderCoderPrompt }\nimport type { CoderContext } from \"../context.js\"\nimport { makeHandle } from \"../handle.js\"\nimport type {\n AgentHandle,\n McpServerMount,\n StartAgentArgs,\n} from \"../types.js\"\n\nexport interface CoderHarnessOptions {\n /** Absolute workspace path (wins over `workspaceSlug`). */\n workspace?: string\n workspaceSlug?: string\n /** Engine selector. Default `claude-code`. */\n engine?: \"claude-code\" | \"hermes\"\n /** Model override. Defaults: claude-code → `claude-opus-4-8`;\n * hermes → `deepseek/deepseek-v4-pro` (confirmed live, WP6). */\n model?: string\n /** Reasoning effort. Default `high`. */\n effort?: string\n /** Coding context rendered into the spawn prompt. */\n context?: CoderContext\n label?: string\n mcpServers?: McpServerMount[]\n}\n\nconst DEFAULTS = {\n claudeCodeModel: \"claude-opus-4-8\",\n hermesModel: \"deepseek/deepseek-v4-pro\",\n effort: \"high\",\n} as const\n\n/**\n * Build the `start_agent_session` args for the coder preset. Exported so WP3's\n * unit test can snapshot the args for both engines without a live daemon.\n *\n * For hermes: `model` and `effort` are NOT included — hermes does not declare\n * them as manifest options so the daemon rejects them at compose time. Instead,\n * `createCoderHarness` sends `/model <slug>` as a first prompt turn after spawn.\n */\nexport function buildCoderArgs(opts: CoderHarnessOptions): StartAgentArgs {\n const engine = opts.engine ?? \"claude-code\"\n const isHermes = engine === \"hermes\"\n const model =\n opts.model ??\n (isHermes ? DEFAULTS.hermesModel : DEFAULTS.claudeCodeModel)\n return {\n adapter: engine,\n ...(isHermes ? {} : { model, effort: opts.effort ?? DEFAULTS.effort }),\n ...(opts.workspace ? { cwd: opts.workspace } : {}),\n ...(opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {}),\n ...(opts.context ? { prompt: renderCoderPrompt(opts.context) } : {}),\n ...(opts.label ? { label: opts.label } : {}),\n ...(opts.mcpServers ? { mcpServers: opts.mcpServers } : {}),\n }\n}\n\n/** Create a coder session and return its handle. */\nexport async function createCoderHarness(\n client: HarnessClient,\n opts: CoderHarnessOptions = {},\n): Promise<AgentHandle> {\n const engine = opts.engine ?? \"claude-code\"\n const isHermes = engine === \"hermes\"\n const modelSlug = isHermes\n ? (opts.model ?? DEFAULTS.hermesModel)\n : (opts.model ?? DEFAULTS.claudeCodeModel)\n const args = buildCoderArgs(opts)\n const desc = await client.start(args)\n if (isHermes && modelSlug) {\n await client.prompt(desc.id, `/model ${modelSlug}`)\n // wait for the model-switch turn to complete before caller uses the handle,\n // otherwise waitForTurn() on the first ask() triggers on this event instead\n await client.waitForAny([desc.id], { event: \"turn-end\", timeoutMs: 15_000 })\n }\n return makeHandle(client, {\n sessionId: desc.id,\n adapter: args.adapter,\n model: modelSlug,\n })\n}\n","/**\n * @agentproto/harness — researcher preset (WP4).\n *\n * Spawns a big-context research agent: `hermes` routed to GLM-5.2 via\n * OpenRouter. Mounts a web-search MCP server and injects a structured-output\n * instruction so replies are parseable.\n */\n\nimport type { HarnessClient } from \"../client.js\"\nimport { makeHandle } from \"../handle.js\"\nimport type {\n AgentHandle,\n McpServerMount,\n StartAgentArgs,\n} from \"../types.js\"\n\nexport interface ResearcherHarnessOptions {\n /** Model override. Default `z-ai/glm-5.2` (big context, WP6). */\n model?: string\n cwd?: string\n workspaceSlug?: string\n /** MCP server to mount for web search (e.g. a bureau/search MCP ref). */\n searchMcp?: McpServerMount\n /** JSON schema hint injected into the spawn prompt for structured output. */\n outputSchema?: Record<string, unknown>\n effort?: string\n label?: string\n mcpServers?: McpServerMount[]\n}\n\nconst DEFAULTS = {\n model: \"z-ai/glm-5.2\",\n} as const\n\n/** Default output-schema hint the researcher is asked to return. */\nexport const DEFAULT_RESEARCH_SCHEMA = {\n findings: \"string[]\",\n sources: \"string[]\",\n confidence: \"low | medium | high\",\n} as const\n\n/**\n * Render the researcher spawn prompt — an instruction block telling the agent:\n * 1. It is a researcher agent.\n * 2. It MUST structure its final answer as JSON matching the outputSchema.\n * 3. Brief format hint: { findings: [...], sources: [...], confidence: \"...\" }\n *\n * Exported for unit tests.\n */\nexport function renderResearcherPrompt(\n opts: ResearcherHarnessOptions,\n): string {\n const schema = opts.outputSchema ?? DEFAULT_RESEARCH_SCHEMA\n return [\n \"You are a researcher agent. Use the available web-search tools to gather\",\n \"evidence and synthesize findings.\",\n \"Always reply in English regardless of the query language.\",\n \"\",\n \"You MUST structure your final answer as JSON matching this schema:\",\n JSON.stringify(schema, null, 2),\n \"\",\n \"Format hint:\",\n \" {\",\n ' \"findings\": [\"key finding 1\", \"key finding 2\", ...],',\n ' \"sources\": [\"url or citation\", ...],',\n ' \"confidence\": \"low | medium | high\"',\n \" }\",\n ].join(\"\\n\")\n}\n\n/**\n * Build the `start_agent_session` args for the researcher preset.\n * Exported so WP4's unit test can assert `mcpServers` + schema are present.\n *\n * `model`, `effort`, and the system `prompt` are NOT included here —\n * `createResearcherHarness` delivers them as controlled turns after spawn\n * so each step has exactly one turn-end to drain:\n * 1. `/model <slug>` → model switch turn-end (fast)\n * 2. system prompt turn → LLM response turn-end (may be slow)\n * This avoids the race where a spawn-time prompt fires a turn-end that\n * interferes with the caller's first `ask()`.\n */\nexport function buildResearcherArgs(\n opts: ResearcherHarnessOptions,\n): StartAgentArgs {\n // effort is not supported for hermes engine (not declared as a manifest option)\n const mcpServers: McpServerMount[] = [\n ...(opts.mcpServers ?? []),\n ...(opts.searchMcp ? [opts.searchMcp] : []),\n ]\n return {\n adapter: \"hermes\",\n ...(opts.cwd ? { cwd: opts.cwd } : {}),\n ...(opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {}),\n ...(mcpServers.length ? { mcpServers } : {}),\n ...(opts.label ? { label: opts.label } : {}),\n }\n}\n\n/** Create a researcher session and return its handle. */\nexport async function createResearcherHarness(\n client: HarnessClient,\n opts: ResearcherHarnessOptions = {},\n): Promise<AgentHandle> {\n const modelSlug = opts.model ?? DEFAULTS.model\n const args = buildResearcherArgs(opts)\n const desc = await client.start(args)\n if (modelSlug) {\n // Step 1: switch model, drain its fast turn-end\n await client.prompt(desc.id, `/model ${modelSlug}`)\n await client.waitForAny([desc.id], { event: \"turn-end\", timeoutMs: 15_000 })\n }\n // Step 2: inject system prompt as an explicit turn, drain LLM response\n await client.prompt(desc.id, renderResearcherPrompt(opts))\n await client.waitForAny([desc.id], { event: \"turn-end\", timeoutMs: 30_000 })\n return makeHandle(client, {\n sessionId: desc.id,\n adapter: args.adapter,\n model: modelSlug,\n })\n}","/**\n * @agentproto/harness — WorkPackage type + supervisor prompt renderer (WP5).\n *\n * A WorkPackage describes a unit of work the supervisor assigns to a sub-agent.\n * `renderSupervisorPrompt` turns a list into a markdown orchestration brief.\n */\n\n/** A unit of work the supervisor harness assigns to a sub-agent. */\nexport interface WorkPackage {\n id: string // e.g. \"WP1\"\n title: string\n description: string\n files?: string[] // file scope\n gate?: string // gate command\n}\n\n/** Renders a WP list into a supervisor orchestration brief. */\nexport function renderSupervisorPrompt(workPackages: WorkPackage[]): string {\n const header =\n \"You are a supervisor agent. Execute the following work packages in order, \" +\n \"assigning each to a sub-agent. Gate each WP before proceeding to the next.\"\n\n const body = workPackages\n .map(wp => {\n let s = `## ${wp.id} — ${wp.title}\\n${wp.description}`\n if (wp.files?.length) s += `\\nFiles: ${wp.files.join(\", \")}`\n if (wp.gate) s += `\\nGate: ${wp.gate}`\n return s\n })\n .join(\"\\n\\n\")\n\n return `${header}\\n\\n${body}`\n}","/**\n * @agentproto/harness — supervisor preset (WP5).\n *\n * Spawns a `claude-code` opus orchestrator with `orchestrator: true` so it can\n * spawn + supervise its OWN sub-agents via the daemon's scoped sub-gateway.\n * Accepts a Work-Package list and renders it into an orchestration brief, and\n * adds fan-in helpers (`subtree`, `waitForAnyChild`) on top of `AgentHandle`.\n */\n\nimport type { HarnessClient } from \"../client.js\"\nimport { makeHandle } from \"../handle.js\"\nimport type {\n AgentHandle,\n OrchestratorOption,\n StartAgentArgs,\n TurnResult,\n} from \"../types.js\"\nimport type { WorkPackage } from \"../wp.js\"\nimport { renderSupervisorPrompt } from \"../wp.js\"\nexport { renderSupervisorPrompt }\n\nexport interface SupervisorHarnessOptions {\n workspace?: string\n workspaceSlug?: string\n /** Model override. Default `claude-opus-4-8`. */\n model?: string\n effort?: string\n /** Scoped-orchestrator config. Default `true` (curated subset). */\n orchestrator?: OrchestratorOption\n /** Work packages to render into the orchestration brief. */\n workPackages?: WorkPackage[]\n label?: string\n}\n\n/** Supervisor handle adds fan-in helpers over the base contract. */\nexport interface SupervisorHandle extends AgentHandle {\n /** Snapshot this session's child subtree (→ `session_tree`). */\n subtree(): Promise<unknown>\n /** Block until ANY child session ends a turn (→ `wait_for_any`). */\n waitForAnyChild(opts?: { timeoutMs?: number }): Promise<TurnResult>\n}\n\nconst DEFAULTS = {\n model: \"claude-opus-4-8\",\n effort: \"high\",\n} as const\n\n/**\n * Build the `start_agent_session` args for the supervisor preset. Exported so\n * WP5's unit test can assert `orchestrator` + the rendered WP brief.\n */\nexport function buildSupervisorArgs(\n opts: SupervisorHarnessOptions,\n): StartAgentArgs {\n return {\n adapter: \"claude-code\",\n model: opts.model ?? DEFAULTS.model,\n effort: opts.effort ?? DEFAULTS.effort,\n orchestrator: opts.orchestrator ?? true,\n ...(opts.workspace ? { cwd: opts.workspace } : {}),\n ...(opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {}),\n ...(opts.workPackages?.length\n ? { prompt: renderSupervisorPrompt(opts.workPackages!) }\n : {}),\n ...(opts.label ? { label: opts.label } : {}),\n }\n}\n\n/** Create a supervisor session and return its (extended) handle. */\nexport async function createSupervisorHarness(\n client: HarnessClient,\n opts: SupervisorHarnessOptions = {},\n): Promise<SupervisorHandle> {\n const args = buildSupervisorArgs(opts)\n const desc = await client.start(args)\n const base = makeHandle(client, {\n sessionId: desc.id,\n adapter: args.adapter,\n ...(args.model ? { model: args.model } : {}),\n })\n return {\n ...base,\n async subtree(): Promise<unknown> {\n return client.sessionTree(desc.id)\n },\n async waitForAnyChild(opts?: { timeoutMs?: number }): Promise<TurnResult> {\n const data = (await client.sessionTree(desc.id)) as {\n tree?: TreeNode[]\n }\n const childIds = collectChildIds(data.tree ?? [])\n if (childIds.length === 0) {\n return {\n sessionId: desc.id,\n event: \"timeout\",\n }\n }\n // wait_for_any accepts max 20 session IDs — chunk & race\n const CHUNK = 20\n if (childIds.length <= CHUNK) {\n return client.waitForAny(childIds, opts)\n }\n const chunks: string[][] = []\n for (let i = 0; i < childIds.length; i += CHUNK) {\n chunks.push(childIds.slice(i, i + CHUNK))\n }\n // NOTE: losing chunks are not cancellable — they poll until their own timeoutMs\n // expires. This is a known limitation of the wait_for_any tool (no cancel API).\n // Impact: at most (Math.ceil(n/20) - 1) extra open long-polls until timeout.\n return Promise.race(chunks.map((chunk) => client.waitForAny(chunk, opts)))\n },\n }\n}\n\n/** Recursively collect all child session ids from a session_tree result. */\nfunction collectChildIds(nodes: readonly TreeNode[]): string[] {\n const ids: string[] = []\n for (const node of nodes) {\n ids.push(node.id)\n if (node.children?.length) {\n ids.push(...collectChildIds(node.children as TreeNode[]))\n }\n }\n return ids\n}\n\ninterface TreeNode {\n id: string\n children?: unknown[]\n}","/**\n * @agentproto/harness — public barrel.\n *\n * Typed, one-call agent-session presets over the agentproto daemon's session\n * tools. Connect once, then spin up `coder` / `researcher` / `supervisor`\n * sessions that all resolve to the uniform `AgentHandle` contract.\n *\n * import { connectHarness, createCoderHarness } from \"@agentproto/harness\"\n * const dx = await connectHarness()\n * const coder = await createCoderHarness(dx, { workspace: process.cwd() })\n * const reply = await coder.ask(\"Add a health-check route\")\n */\n\nimport { HarnessClient } from \"./client.js\"\nimport type { ConnectHarnessOptions } from \"./types.js\"\n\n/**\n * Connect the shared transport to the daemon's `/mcp` endpoint. Returns a\n * `HarnessClient` to hand to the `create*Harness` factories.\n */\nexport async function connectHarness(\n opts?: ConnectHarnessOptions,\n): Promise<HarnessClient> {\n return HarnessClient.connect(opts)\n}\n\nexport { HarnessClient, DEFAULT_MCP_URL, resolveMcpUrl } from \"./client.js\"\nexport { makeHandle } from \"./handle.js\"\n\nexport {\n createCoderHarness,\n buildCoderArgs,\n renderCoderPrompt,\n type CoderHarnessOptions,\n} from \"./harnesses/coder.js\"\nexport {\n createResearcherHarness,\n buildResearcherArgs,\n renderResearcherPrompt,\n DEFAULT_RESEARCH_SCHEMA,\n type ResearcherHarnessOptions,\n} from \"./harnesses/researcher.js\"\nexport {\n createSupervisorHarness,\n buildSupervisorArgs,\n renderSupervisorPrompt,\n type SupervisorHarnessOptions,\n type SupervisorHandle,\n} from \"./harnesses/supervisor.js\"\n\nexport type {\n AgentHandle,\n TurnResult,\n TurnEvent,\n McpServerMount,\n OrchestratorOption,\n StartAgentArgs,\n SessionDescriptor,\n ConnectHarnessOptions,\n CoderContext,\n} from \"./types.js\"\nexport type { WorkPackage } from \"./wp.js\"\n"]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agentproto/harness — shared types.
|
|
3
|
+
*
|
|
4
|
+
* The harness wraps the daemon's session tools (`start_agent_session`,
|
|
5
|
+
* `prompt_agent_session`, `get_agent_session_output`, `kill_agent_session`,
|
|
6
|
+
* `wait_for_any`) exposed over the `/mcp` endpoint. These types describe the
|
|
7
|
+
* client-side contract; the wire shapes mirror the tool schemas in
|
|
8
|
+
* `@agentproto/runtime` (`session-tools.ts`, `orchestration-tools.ts`).
|
|
9
|
+
*/
|
|
10
|
+
/** Lifecycle event a turn can settle on. `timeout` is harness-side only. */
|
|
11
|
+
type TurnEvent = "turn-end" | "awaiting-input" | "exited" | "any" | "timeout";
|
|
12
|
+
/** Result of `AgentHandle.waitForTurn` / `wait_for_any`. */
|
|
13
|
+
interface TurnResult {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
event: TurnEvent;
|
|
16
|
+
status?: string;
|
|
17
|
+
awaitingInput?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* MCP-server mount forwarded verbatim to `start_agent_session.mcpServers`
|
|
21
|
+
* (→ `session/new.mcpServers` on the ACP arm).
|
|
22
|
+
*/
|
|
23
|
+
interface McpServerMount {
|
|
24
|
+
name: string;
|
|
25
|
+
transport: "stdio" | "http" | "sse";
|
|
26
|
+
ref?: string;
|
|
27
|
+
[k: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Scoped-orchestrator request — forwarded to `start_agent_session.orchestrator`.
|
|
31
|
+
* `true` = the default curated subset; the object form narrows it.
|
|
32
|
+
*/
|
|
33
|
+
type OrchestratorOption = boolean | {
|
|
34
|
+
tools?: string[];
|
|
35
|
+
maxDepth?: number;
|
|
36
|
+
maxChildren?: number;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Args handed to `start_agent_session`. 1:1 with the tool schema
|
|
40
|
+
* (`session-tools.ts:241-374`).
|
|
41
|
+
*/
|
|
42
|
+
interface StartAgentArgs {
|
|
43
|
+
adapter: string;
|
|
44
|
+
cwd?: string;
|
|
45
|
+
workspaceSlug?: string;
|
|
46
|
+
prompt?: string;
|
|
47
|
+
label?: string;
|
|
48
|
+
model?: string;
|
|
49
|
+
effort?: string;
|
|
50
|
+
mcpServers?: McpServerMount[];
|
|
51
|
+
orchestrator?: OrchestratorOption;
|
|
52
|
+
notifyUrl?: string;
|
|
53
|
+
}
|
|
54
|
+
/** Session descriptor as returned by `start_agent_session` (subset). */
|
|
55
|
+
interface SessionDescriptor {
|
|
56
|
+
id: string;
|
|
57
|
+
label?: string;
|
|
58
|
+
status: string;
|
|
59
|
+
adapterSlug?: string;
|
|
60
|
+
cwd?: string;
|
|
61
|
+
parentSessionId?: string;
|
|
62
|
+
depth?: number;
|
|
63
|
+
startedAt: string;
|
|
64
|
+
}
|
|
65
|
+
/** Connection options for the shared MCP transport. */
|
|
66
|
+
interface ConnectHarnessOptions {
|
|
67
|
+
/** Daemon MCP endpoint. Default `http://127.0.0.1:18790/mcp`
|
|
68
|
+
* (or `AGENTPROTO_MCP_URL`). */
|
|
69
|
+
url?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The uniform contract every harness resolves to. A typed wrapper over a
|
|
73
|
+
* single live daemon session.
|
|
74
|
+
*/
|
|
75
|
+
interface AgentHandle {
|
|
76
|
+
readonly sessionId: string;
|
|
77
|
+
readonly adapter: string;
|
|
78
|
+
readonly model?: string;
|
|
79
|
+
/** Send a follow-up turn (fire-and-forget at the daemon). */
|
|
80
|
+
send(prompt: string): Promise<void>;
|
|
81
|
+
/** Block until this session ends its current turn (`wait_for_any`). */
|
|
82
|
+
waitForTurn(opts?: {
|
|
83
|
+
timeoutMs?: number;
|
|
84
|
+
}): Promise<TurnResult>;
|
|
85
|
+
/** Convenience: `send` + `waitForTurn` + return the new output tail. */
|
|
86
|
+
ask(prompt: string, opts?: {
|
|
87
|
+
timeoutMs?: number;
|
|
88
|
+
}): Promise<string>;
|
|
89
|
+
/** Tail the ring buffer (`get_agent_session_output`). */
|
|
90
|
+
output(opts?: {
|
|
91
|
+
lastN?: number;
|
|
92
|
+
}): Promise<string>;
|
|
93
|
+
/** SIGTERM the session (`kill_agent_session`). */
|
|
94
|
+
kill(): Promise<void>;
|
|
95
|
+
}
|
|
96
|
+
/** Coding context injected by the coder harness into its spawn prompt. */
|
|
97
|
+
interface CoderContext {
|
|
98
|
+
/** Short stack description, e.g. "TypeScript monorepo, pnpm, tsup" */
|
|
99
|
+
stack?: string;
|
|
100
|
+
/** Coding conventions, e.g. "ESM-only, no default exports except React" */
|
|
101
|
+
conventions?: string;
|
|
102
|
+
/** Gate commands that must stay green before declaring done. */
|
|
103
|
+
gateCmds?: string[];
|
|
104
|
+
/** Extra context injected verbatim. */
|
|
105
|
+
extra?: string;
|
|
106
|
+
}
|
|
107
|
+
/** Alias for the spec-facing name. */
|
|
108
|
+
type StartArgs = StartAgentArgs;
|
|
109
|
+
|
|
110
|
+
export type { AgentHandle, CoderContext, ConnectHarnessOptions, McpServerMount, OrchestratorOption, SessionDescriptor, StartAgentArgs, StartArgs, TurnEvent, TurnResult };
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"types.mjs"}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentproto/harness",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "@agentproto/harness — typed, one-call agent-session presets (coder, researcher, supervisor) over the agentproto daemon's start/prompt/output session tools. A client-side recipe layer; adds no new daemon surface.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agentproto",
|
|
7
|
+
"harness",
|
|
8
|
+
"agent",
|
|
9
|
+
"session",
|
|
10
|
+
"orchestration",
|
|
11
|
+
"mcp",
|
|
12
|
+
"preset"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://agentproto.sh",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/agentproto/ts",
|
|
18
|
+
"directory": "packages/harness"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/agentproto/ts/issues"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "dist/index.mjs",
|
|
26
|
+
"module": "dist/index.mjs",
|
|
27
|
+
"types": "dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.mjs",
|
|
32
|
+
"default": "./dist/index.mjs"
|
|
33
|
+
},
|
|
34
|
+
"./types": {
|
|
35
|
+
"types": "./dist/types.d.ts",
|
|
36
|
+
"import": "./dist/types.mjs",
|
|
37
|
+
"default": "./dist/types.mjs"
|
|
38
|
+
},
|
|
39
|
+
"./package.json": "./package.json"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"README.md",
|
|
44
|
+
"LICENSE"
|
|
45
|
+
],
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@modelcontextprotocol/sdk": ">=1.0.0",
|
|
51
|
+
"zod": ">=3.0.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
55
|
+
"@types/node": "^25.6.2",
|
|
56
|
+
"tsup": "^8.5.1",
|
|
57
|
+
"typescript": "^5.9.3",
|
|
58
|
+
"vitest": "^3.2.4",
|
|
59
|
+
"zod": "^4.4.3",
|
|
60
|
+
"@agentproto/tooling": "0.1.0-alpha.0"
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=20.9.0"
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"dev": "tsup --watch",
|
|
67
|
+
"build": "tsup",
|
|
68
|
+
"clean": "rm -rf dist",
|
|
69
|
+
"check-types": "tsc --noEmit",
|
|
70
|
+
"test": "vitest run --passWithNoTests",
|
|
71
|
+
"test:watch": "vitest"
|
|
72
|
+
}
|
|
73
|
+
}
|