@ahpd/agent-claude 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luiz Fernando Softov <lfs@softov.dev>
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,56 @@
1
+ # @ahpd/agent-claude
2
+
3
+ The Claude backend for [`@ahpd/server`](https://www.npmjs.com/package/@ahpd/server).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @ahpd/agent-claude @ahpd/server @microsoft/agent-host-protocol
9
+ ```
10
+
11
+ ## Use
12
+
13
+ ```ts
14
+ import { createHost, listen } from '@ahpd/server';
15
+ import { claude } from '@ahpd/agent-claude';
16
+
17
+ const path = process.cwd();
18
+ const host = createHost({ path, agents: [claude({ paths: [path] })] });
19
+ await listen({ port: 9187 }, (peer) => host.accept(peer));
20
+ ```
21
+
22
+ `createHost` takes a list of agents, so this can run alongside other backends.
23
+
24
+ ## What it does
25
+
26
+ It starts the [Claude agent SDK](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk), converts its message stream into AHP state actions, and reads Claude's transcript files.
27
+
28
+ | export | |
29
+ | --- | --- |
30
+ | `claude(options)` | the `Agent` to pass to `createHost` |
31
+ | `createSession(options)` | one live session |
32
+ | `catalogue(dir)` | Claude's sessions in a directory, as rows a host can list |
33
+ | `turnsOf(sessionId, dir)` | a past session read from its transcript, as turns |
34
+ | `probe(options)` | runs a CLI at startup to read the available models and commands |
35
+
36
+ ## Supported
37
+
38
+ Turns and streaming, tool calls and approvals, questions from the agent, model and effort selection, permission modes, MCP servers and OAuth sign-in, skills and slash commands, multiple chats per session, forking a chat from a turn, truncating a chat back to a turn, session titles, token usage, and context compaction.
39
+
40
+ Sessions the host is not running are read from Claude's transcripts, so clients can browse and read them without starting a process. The agent starts when a turn is sent.
41
+
42
+ ## Credentials
43
+
44
+ Sessions use whatever the Claude CLI is signed in with. A client can push a token instead. Pushed tokens are held per connection and are not used for other clients' sessions.
45
+
46
+ ## Documentation
47
+
48
+ | | |
49
+ | --- | --- |
50
+ | [AGENT.md](https://github.com/softov/ahpd/blob/main/docs/AGENT.md) | The `Agent` and `Session` contracts this implements |
51
+ | [AHP.md](https://github.com/softov/ahpd/blob/main/docs/AHP.md) | Which actions are served, which are refused, and why |
52
+
53
+ ## License
54
+
55
+ MIT © Softov
56
+
@@ -0,0 +1,19 @@
1
+ import type { Listed } from '@ahpd/server';
2
+ /**
3
+ * Claude's own sessions, as rows a host can list.
4
+ *
5
+ * Renames the SDK's session listing into `Listed`. The SDK is the authority on
6
+ * which sessions exist; this module only maps the fields - which is why it is
7
+ * here and not beside the URI helpers in `@ahpd/server`: a host serving some
8
+ * other harness has a different answer to the same question, and no reason to
9
+ * load this one to find that out.
10
+ */
11
+ /**
12
+ * What this backend is a catalogue *of*.
13
+ *
14
+ * `dir`, not `cwd` - the option that scopes a listing to one project is spelled
15
+ * `dir`, and an unrecognised key is ignored rather than refused, so the wrong
16
+ * spelling answers with every session on the machine and looks like it worked.
17
+ */
18
+ export declare function catalogue(dir: string): Promise<Listed[]>;
19
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C;;;;;;;;GAQG;AACH;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAS9D"}
@@ -0,0 +1,28 @@
1
+ import { listSessions } from '@anthropic-ai/claude-agent-sdk';
2
+ /**
3
+ * Claude's own sessions, as rows a host can list.
4
+ *
5
+ * Renames the SDK's session listing into `Listed`. The SDK is the authority on
6
+ * which sessions exist; this module only maps the fields - which is why it is
7
+ * here and not beside the URI helpers in `@ahpd/server`: a host serving some
8
+ * other harness has a different answer to the same question, and no reason to
9
+ * load this one to find that out.
10
+ */
11
+ /**
12
+ * What this backend is a catalogue *of*.
13
+ *
14
+ * `dir`, not `cwd` - the option that scopes a listing to one project is spelled
15
+ * `dir`, and an unrecognised key is ignored rather than refused, so the wrong
16
+ * spelling answers with every session on the machine and looks like it worked.
17
+ */
18
+ export async function catalogue(dir) {
19
+ const found = await listSessions({ dir });
20
+ return found.map((info) => ({
21
+ id: info.sessionId,
22
+ title: info.customTitle ?? info.summary ?? info.firstPrompt ?? 'Session',
23
+ createdAt: new Date(info.createdAt ?? info.lastModified).toISOString(),
24
+ modifiedAt: new Date(info.lastModified).toISOString(),
25
+ workingDirectories: [`file://${info.cwd ?? dir}`],
26
+ }));
27
+ }
28
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAG9D;;;;;;;;GAQG;AACH;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1C,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1B,EAAE,EAAE,IAAI,CAAC,SAAS;QAClB,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,WAAW,IAAI,SAAS;QACxE,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;QACtE,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;QACrD,kBAAkB,EAAE,CAAC,UAAU,IAAI,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC;KAClD,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { Agent } from '@ahpd/server';
2
+ /**
3
+ * Claude Code, as an agent backend.
4
+ *
5
+ * Everything the host would otherwise have to know about one particular
6
+ * harness: which settings it takes, where its past sessions are kept, and how
7
+ * to start one. The host asks through `Agent` and imports none of this.
8
+ */
9
+ /** How to build the Claude backend. */
10
+ export interface ClaudeOptions {
11
+ /**
12
+ * The directories it will work in, and the ones it lists.
13
+ *
14
+ * The first is where a session goes when the client names none. A client
15
+ * may name any of the others and nothing else: a host that ran the agent
16
+ * wherever it was told is one anybody who can reach the port can point at
17
+ * any directory on the machine.
18
+ *
19
+ * This is also the catalogue's scope, so a directory left out is one whose
20
+ * sessions are neither listed nor openable.
21
+ */
22
+ paths: string[];
23
+ /** The id clients name. `claude` unless something else already is. */
24
+ provider?: string;
25
+ }
26
+ /** Claude Code on one or more directories, ready to be handed to `createHost`. */
27
+ export declare function claude(options: ClaudeOptions): Agent;
28
+ //# sourceMappingURL=claude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,KAAK,EAAc,MAAM,cAAc,CAAC;AAYtD;;;;;;GAMG;AAEH,uCAAuC;AACvC,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;;OAUG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,kFAAkF;AAClF,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,KAAK,CAmTpD"}
package/dist/claude.js ADDED
@@ -0,0 +1,311 @@
1
+ import { probe } from './probe.js';
2
+ import { serversFor } from './mcp.js';
3
+ import { createSession, EFFORT_LABELS, EFFORTS } from './session.js';
4
+ import { turnsOf } from './transcript.js';
5
+ import { catalogue } from './catalog.js';
6
+ import { within } from '@ahpd/server';
7
+ /**
8
+ * The resource a token for this backend is for.
9
+ *
10
+ * Named once, because it is the identifier a client must send back verbatim:
11
+ * the protocol says `authenticate`'s `resource` MUST match one the server
12
+ * advertised, so this string appearing twice with a typo between them is a
13
+ * token nothing will accept.
14
+ */
15
+ const ANTHROPIC = 'https://api.anthropic.com';
16
+ /** Claude Code on one or more directories, ready to be handed to `createHost`. */
17
+ export function claude(options) {
18
+ const dirs = options.paths;
19
+ const dir = dirs[0];
20
+ if (dir === undefined)
21
+ throw new Error('claude() needs at least one directory to work in.');
22
+ /**
23
+ * Which directory a session goes in.
24
+ *
25
+ * Named, or the first. Anything else is refused rather than quietly
26
+ * replaced - a directory accepted and then ignored is a session running
27
+ * somewhere nobody asked for, with nothing on screen to say so.
28
+ */
29
+ const workingDirectory = (asked) => {
30
+ if (asked === undefined)
31
+ return dir;
32
+ /*
33
+ * Under a served directory, not equal to one.
34
+ *
35
+ * This compared for equality, so a host told to serve `/home/you` served
36
+ * that one directory and refused every project inside it - which is the
37
+ * only kind of directory anybody opens. An editor asks for its workspace
38
+ * folder, and that is never the path somebody passed to `--path`.
39
+ */
40
+ if (!dirs.some((served) => within(served, asked))) {
41
+ throw new Error(`This host does not serve ${asked}. It serves ${dirs.join(', ')}.`);
42
+ }
43
+ // What was asked for, not the root it sits under: the session runs where
44
+ // the client said.
45
+ return asked;
46
+ };
47
+ /*
48
+ * What the probe learned about output styles.
49
+ *
50
+ * The schema is otherwise fixed, but this one property's choices belong to
51
+ * the harness rather than to the protocol - a person's own styles live in
52
+ * their settings - so it is learned once at startup, the way models are,
53
+ * and the control is simply absent until it is known.
54
+ */
55
+ let styles = [];
56
+ /**
57
+ * Whether the models this harness offers carry effort controls of their own.
58
+ *
59
+ * A model's `configSchema` and the session-wide `effortLevel` reach the same
60
+ * setting, and a client draws both - so a person is shown two effort
61
+ * controls, on two different values, for one thing. The model's is the
62
+ * truthful one: it lists what that model actually supports, where the
63
+ * session-wide key lists all five whatever is chosen. So this backend offers
64
+ * the session key only while there is nothing better.
65
+ */
66
+ let perModelEffort = false;
67
+ let style;
68
+ /**
69
+ * What a session can be told to do differently.
70
+ *
71
+ * One schema, used by `resolveSessionConfig` (before a session exists) and
72
+ * by every session's own state (after one does). Two copies would drift, and
73
+ * the composer would offer one set of controls on the new-session screen and
74
+ * a different set the moment a session opened.
75
+ *
76
+ * `sessionMutable` is what each row turns on: the permission mode, the model
77
+ * and the effort level are things the CLI takes on a *running* session.
78
+ * `thinking` is fixed when the query is built, so offering it live would be
79
+ * a switch that flips back.
80
+ */
81
+ const schema = () => ({
82
+ // A JSON Schema object, and it has to say so: `type` is required, and a
83
+ // schema without it matches nothing a client validates.
84
+ type: 'object',
85
+ properties: {
86
+ /*
87
+ * One axis, and the CLI's own five values.
88
+ *
89
+ * The protocol's config schema is generic and a backend advertises what
90
+ * it has - VS Code's own hosts advertise different properties for
91
+ * Copilot and for Claude, and a client draws whatever it is given. Its
92
+ * Claude host says why in as many words: it collapses the platform's
93
+ * `autoApprove` x `mode` two-axis surface onto one `permissionMode`
94
+ * matching the SDK's enum, and *omits* `autoApprove`, `mode`,
95
+ * `isolation` and `branch` deliberately, because the pickers key off
96
+ * property names and omitting them suppresses a mode and branch UI that
97
+ * would not mean anything here.
98
+ *
99
+ * The wording is that host's too, so one session reads the same however
100
+ * it is opened. `auto` was missing here and is a real mode the CLI
101
+ * takes: the agent deciding, per call, whether it needs to ask.
102
+ */
103
+ permissionMode: {
104
+ scope: 'session',
105
+ type: 'string',
106
+ title: 'Approvals',
107
+ description: 'How the agent handles tool approvals.',
108
+ enum: ['default', 'acceptEdits', 'plan', 'auto', 'bypassPermissions'],
109
+ enumLabels: [
110
+ 'Ask Before Edits',
111
+ 'Edit Automatically',
112
+ 'Plan Mode',
113
+ 'Auto Mode',
114
+ 'Bypass Permissions',
115
+ ],
116
+ enumDescriptions: [
117
+ 'Asks before editing files.',
118
+ 'Edits files without asking, and asks before using other tools.',
119
+ 'Creates a plan before making changes.',
120
+ 'Decides whether to ask for each tool operation.',
121
+ 'Runs all tools without asking.',
122
+ ],
123
+ default: 'default',
124
+ sessionMutable: true,
125
+ },
126
+ /*
127
+ * The model is not a config property.
128
+ *
129
+ * A session has no model; each message has one. The choices are carried
130
+ * on the agent (`RootState.agents[].models`) and the choice on the turn.
131
+ * `session/configChanged` with a `model` key is still honoured, but the
132
+ * model is not advertised here as a control of its own.
133
+ */
134
+ ...(perModelEffort ? {} : {
135
+ effortLevel: {
136
+ scope: 'chat',
137
+ type: 'string',
138
+ title: 'Effort',
139
+ description: 'How hard it thinks before answering.',
140
+ enum: [...EFFORTS],
141
+ enumLabels: EFFORTS.map((one) => EFFORT_LABELS[one]),
142
+ default: 'high',
143
+ sessionMutable: true,
144
+ },
145
+ }),
146
+ // Learned, so absent until the probe has answered and absent for good
147
+ // on a harness that has no styles.
148
+ ...(styles.length > 0
149
+ ? {
150
+ outputStyle: {
151
+ scope: 'session',
152
+ type: 'string',
153
+ title: 'Output style',
154
+ description: 'The voice it answers in.',
155
+ enum: styles,
156
+ enumLabels: styles.map((name) => name.charAt(0).toUpperCase() + name.slice(1)),
157
+ ...(style !== undefined ? { default: style } : {}),
158
+ sessionMutable: true,
159
+ },
160
+ }
161
+ : {}),
162
+ thinking: {
163
+ type: 'string',
164
+ title: 'Thinking',
165
+ description: 'Fixed when the session is created.',
166
+ enum: ['adaptive', 'disabled'],
167
+ enumLabels: ['Adaptive', 'Off'],
168
+ enumDescriptions: ['The agent decides when to think', 'No extended thinking'],
169
+ default: 'adaptive',
170
+ sessionMutable: false,
171
+ },
172
+ /*
173
+ * Per-tool allow and deny, which is the slope the mode above is a cliff.
174
+ *
175
+ * A platform key rather than one of this backend's invention: it is what
176
+ * the reference client's permission picker writes when somebody approves
177
+ * a tool "in this session", and its own Claude host advertises it
178
+ * unchanged because the SDK takes `allowedTools` / `disallowedTools`
179
+ * natively. Without it the only way to stop being asked about the one
180
+ * command you trust is `bypassPermissions`, which stops asking about
181
+ * everything.
182
+ *
183
+ * An object, and the first config value here that is not a string. The
184
+ * protocol declares the bag `Record<string, unknown>`; this host used to
185
+ * declare it `Record<string, string>`, which is why nothing of this
186
+ * shape could be carried at all.
187
+ */
188
+ permissions: {
189
+ scope: 'session',
190
+ type: 'object',
191
+ title: 'Permissions',
192
+ description: 'Per-tool session permissions. Updated when a tool is approved for this session.',
193
+ properties: {
194
+ allow: { type: 'array', title: 'Allowed tools', items: { type: 'string', title: 'Tool name' } },
195
+ deny: { type: 'array', title: 'Denied tools', items: { type: 'string', title: 'Tool name' } },
196
+ },
197
+ default: { allow: [], deny: [] },
198
+ // Unlike `thinking`, this one really can move on a running session:
199
+ // the SDK takes the lists when the query is built, and `canUseTool`
200
+ // is where this host already sits between the agent and the person.
201
+ sessionMutable: true,
202
+ },
203
+ },
204
+ });
205
+ const defaults = () => ({
206
+ permissionMode: 'default',
207
+ // Beside its schema or not at all: a value with no property to draw it is
208
+ // a control a client cannot show and cannot change.
209
+ ...(perModelEffort ? {} : { effortLevel: 'high' }),
210
+ thinking: 'adaptive',
211
+ permissions: { allow: [], deny: [] },
212
+ ...(style !== undefined ? { outputStyle: style } : {}),
213
+ });
214
+ return {
215
+ provider: options.provider ?? 'claude',
216
+ displayName: 'Claude Code',
217
+ // Both, because the SDK resumes at a named prompt: `resumeSessionAt` with
218
+ // `forkSession` continues from a turn under a new id, and a side chat is
219
+ // an unresumed session handed what that turn said.
220
+ chats: { fork: true, sideChat: true },
221
+ // The SDK takes `additionalDirectories` at startup, so a session works in
222
+ // as many as it was given; the first is the process root and is fixed.
223
+ multipleDirectories: true,
224
+ description: `The Claude Agent SDK, on ${dirs.join(', ')}`,
225
+ schema,
226
+ defaults,
227
+ directories: () => [...dirs],
228
+ // The styles are kept as well as handed on: `schema()` is asked before any
229
+ // session exists, and it can only offer what has already been learned.
230
+ probe: async () => {
231
+ const offered = await probe(dir);
232
+ styles = offered.outputStyles ?? [];
233
+ style = offered.outputStyle;
234
+ perModelEffort = offered.models.some((model) => model.configSchema !== undefined);
235
+ return offered;
236
+ },
237
+ // Every directory it serves, as one list. A session is listed by the
238
+ // catalogue of the directory it ran in, and a host serving several has
239
+ // one catalogue.
240
+ list: async () => (await Promise.all(dirs.map((served) => catalogue(served)))).flat(),
241
+ // Whichever directory holds it. The transcript reader wants the one the
242
+ // session ran in, and only its own catalogue knows which that was.
243
+ transcript: async (id) => {
244
+ for (const served of dirs) {
245
+ const rows = await catalogue(served).catch(() => []);
246
+ if (rows.some((row) => row.id === id))
247
+ return turnsOf(id, served);
248
+ }
249
+ return undefined;
250
+ },
251
+ /*
252
+ * The one resource this backend can be given a token for.
253
+ *
254
+ * `required: false`, and that is the honest declaration rather than the
255
+ * lenient one: this daemon runs as whoever started it and inherits their
256
+ * `claude login` or `ANTHROPIC_API_KEY`, so it works with nothing pushed
257
+ * at all. Saying `required: true` would refuse clients that would
258
+ * otherwise be perfectly able to open a session.
259
+ */
260
+ protectedResources: [{
261
+ resource: ANTHROPIC,
262
+ resource_name: 'Anthropic API',
263
+ authorization_servers: ['https://console.anthropic.com'],
264
+ required: false,
265
+ }],
266
+ create: (start) => createSession({
267
+ uri: start.uri,
268
+ chatUri: start.chatUri,
269
+ cwd: workingDirectory(start.workingDirectory),
270
+ /*
271
+ * The MCP servers, declared by this host rather than found by the CLI.
272
+ *
273
+ * The same files the CLI reads - `.mcp.json` beside the project and
274
+ * `mcpServers` in `~/.claude.json` - handed to the SDK so they are
275
+ * *its* servers. That is what makes a token a client signed in with
276
+ * applicable: `setMcpServers` re-declares only what the SDK was given.
277
+ */
278
+ mcpServers: serversFor([workingDirectory(start.workingDirectory), ...(start.additional ?? [])]),
279
+ // Each one checked the way the first is: a directory this host does not
280
+ // serve is not one an agent may be pointed at, however it arrived.
281
+ ...(start.additional && start.additional.length > 0
282
+ ? { additional: start.additional.map((one) => workingDirectory(one)) }
283
+ : {}),
284
+ // The host's own tools, offered to the model beside this backend's.
285
+ ...(start.tools && start.tools.length > 0 ? { tools: start.tools } : {}),
286
+ settings: start.settings,
287
+ schema: start.schema,
288
+ emit: start.emit,
289
+ ...(start.seedCustomizations ? { seedCustomizations: start.seedCustomizations } : {}),
290
+ ...(start.resume !== undefined ? { resume: start.resume } : {}),
291
+ ...(start.forkAt !== undefined ? { forkAt: start.forkAt } : {}),
292
+ ...(start.rewindAt !== undefined ? { rewindAt: start.rewindAt } : {}),
293
+ ...(start.context !== undefined ? { context: start.context } : {}),
294
+ ...(start.seed ? { seed: start.seed } : {}),
295
+ ...(start.onFileEdit ? { onFileEdit: start.onFileEdit } : {}),
296
+ ...(start.onHandshake ? { onHandshake: start.onHandshake } : {}),
297
+ /*
298
+ * A pushed token, as the variable the CLI reads.
299
+ *
300
+ * Which variable that is, is this file's business and not the host's:
301
+ * the host knows a token belongs to `https://api.anthropic.com` and
302
+ * stops there, which is what keeps `createHost` the protocol and
303
+ * nothing else.
304
+ */
305
+ ...(start.credentials?.[ANTHROPIC]
306
+ ? { env: { ANTHROPIC_API_KEY: start.credentials[ANTHROPIC] } }
307
+ : {}),
308
+ }),
309
+ };
310
+ }
311
+ //# sourceMappingURL=claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The Claude backend, as an `Agent` this host can be handed.
3
+ *
4
+ * One implementation of the contract `@ahpd/server` declares, and the only
5
+ * thing in either package that knows what the Claude harness is: it starts the
6
+ * agent SDK, translates its message stream into the state actions the protocol
7
+ * describes, and reads a transcript somebody else's session left on disk.
8
+ *
9
+ * A host that wants a different harness registers a different `Agent` and
10
+ * never loads this. A host that wants both registers both - `createHost` takes
11
+ * a list, and cannot tell one from another.
12
+ */
13
+ export { catalogue } from './catalog.js';
14
+ export { claude } from './claude.js';
15
+ export type { ClaudeOptions } from './claude.js';
16
+ export { createSession, EFFORTS, EFFORT_LABELS } from './session.js';
17
+ export type { Published } from './session.js';
18
+ export { probe } from './probe.js';
19
+ export { turnsOf } from './transcript.js';
20
+ export { protectedResource, urlOf } from './mcp.js';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACrE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The Claude backend, as an `Agent` this host can be handed.
3
+ *
4
+ * One implementation of the contract `@ahpd/server` declares, and the only
5
+ * thing in either package that knows what the Claude harness is: it starts the
6
+ * agent SDK, translates its message stream into the state actions the protocol
7
+ * describes, and reads a transcript somebody else's session left on disk.
8
+ *
9
+ * A host that wants a different harness registers a different `Agent` and
10
+ * never loads this. A host that wants both registers both - `createHost` takes
11
+ * a list, and cannot tell one from another.
12
+ */
13
+ export { catalogue } from './catalog.js';
14
+ export { claude } from './claude.js';
15
+ export { createSession, EFFORTS, EFFORT_LABELS } from './session.js';
16
+ export { probe } from './probe.js';
17
+ export { turnsOf } from './transcript.js';
18
+ export { protectedResource, urlOf } from './mcp.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAErE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC"}
package/dist/mcp.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ /** The MCP servers a session runs with, read from the files the CLI reads. */
2
+ import type { Bag } from '@ahpd/server';
3
+ /**
4
+ * Every MCP server configured for a directory, by name.
5
+ *
6
+ * The CLI finds these itself and this host normally leaves it to. It reads
7
+ * them here for one reason: a server the *SDK* was given is one
8
+ * `setMcpServers` can re-declare, and a server that came from a settings file
9
+ * is not - so a token a client signs in with has nowhere to go unless this
10
+ * host owns the declaration. The files are the CLI's own: `.mcp.json` beside
11
+ * the project, and `mcpServers` in `~/.claude.json`.
12
+ *
13
+ * A file that is missing, unreadable or not JSON contributes nothing. This is
14
+ * a best effort by design: the CLI still reads the same files, and a server
15
+ * this misses is a server that works exactly as it did before.
16
+ */
17
+ export declare function serversFor(directories: string[]): Record<string, Bag>;
18
+ /** The URL an http or sse server lives at, or nothing for a stdio one. */
19
+ export declare const urlOf: (config: unknown) => string | undefined;
20
+ /**
21
+ * What an MCP server says about signing into it, per RFC 9728.
22
+ *
23
+ * `<url>/.well-known/oauth-protected-resource`, which is where an OAuth
24
+ * protected resource publishes its metadata and where a client looks to find
25
+ * the authorization server. Answers the discovered document, or a bare one
26
+ * naming the server itself: the URL *is* the canonical resource identifier,
27
+ * so an incomplete answer is still a true one - what a client loses is the
28
+ * one-click sign-in, not the knowledge that it needs to sign in.
29
+ */
30
+ export declare function protectedResource(url: string, name: string, ms?: number): Promise<Bag>;
31
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAK9E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAExC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAsBrE;AAED,0EAA0E;AAC1E,eAAO,MAAM,KAAK,GAAI,QAAQ,OAAO,KAAG,MAAM,GAAG,SAMhD,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAU5F"}