@jongleberry/atel 0.0.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.
Files changed (64) hide show
  1. package/README.md +168 -0
  2. package/dist/cli/append.d.mts +3 -0
  3. package/dist/cli/append.mjs +38 -0
  4. package/dist/cli/args.d.mts +14 -0
  5. package/dist/cli/args.mjs +49 -0
  6. package/dist/cli/context.d.mts +15 -0
  7. package/dist/cli/context.mjs +1 -0
  8. package/dist/cli/credentials.d.mts +6 -0
  9. package/dist/cli/credentials.mjs +45 -0
  10. package/dist/cli/env.d.mts +5 -0
  11. package/dist/cli/env.mjs +21 -0
  12. package/dist/cli/errors.d.mts +3 -0
  13. package/dist/cli/errors.mjs +3 -0
  14. package/dist/cli/get.d.mts +9 -0
  15. package/dist/cli/get.mjs +55 -0
  16. package/dist/cli/index.d.mts +18 -0
  17. package/dist/cli/index.mjs +69 -0
  18. package/dist/cli/output.d.mts +4 -0
  19. package/dist/cli/output.mjs +4 -0
  20. package/dist/cli/patch.d.mts +7 -0
  21. package/dist/cli/patch.mjs +57 -0
  22. package/dist/cli/usage.d.mts +1 -0
  23. package/dist/cli/usage.mjs +21 -0
  24. package/dist/client/append.d.mts +5 -0
  25. package/dist/client/append.mjs +18 -0
  26. package/dist/client/auth.d.mts +26 -0
  27. package/dist/client/auth.mjs +23 -0
  28. package/dist/client/credentials.d.mts +13 -0
  29. package/dist/client/credentials.mjs +19 -0
  30. package/dist/client/errors.d.mts +8 -0
  31. package/dist/client/errors.mjs +13 -0
  32. package/dist/client/http.d.mts +22 -0
  33. package/dist/client/http.mjs +66 -0
  34. package/dist/client/journal.d.mts +24 -0
  35. package/dist/client/journal.mjs +35 -0
  36. package/dist/client/journals.d.mts +18 -0
  37. package/dist/client/journals.mjs +28 -0
  38. package/dist/client/patch.d.mts +6 -0
  39. package/dist/client/patch.mjs +12 -0
  40. package/dist/client/stream.d.mts +30 -0
  41. package/dist/client/stream.mjs +90 -0
  42. package/dist/client/types.d.mts +65 -0
  43. package/dist/client/types.mjs +8 -0
  44. package/dist/format-error.d.mts +6 -0
  45. package/dist/format-error.mjs +15 -0
  46. package/dist/index.d.mts +20 -0
  47. package/dist/index.mjs +16 -0
  48. package/dist/mcp/dispatch.d.mts +3 -0
  49. package/dist/mcp/dispatch.mjs +16 -0
  50. package/dist/mcp/schemas.d.mts +2 -0
  51. package/dist/mcp/schemas.mjs +69 -0
  52. package/dist/mcp/server.d.mts +10 -0
  53. package/dist/mcp/server.mjs +35 -0
  54. package/dist/mcp/tool-append.d.mts +3 -0
  55. package/dist/mcp/tool-append.mjs +17 -0
  56. package/dist/mcp/tool-get.d.mts +13 -0
  57. package/dist/mcp/tool-get.mjs +30 -0
  58. package/dist/mcp/tool-patch.d.mts +5 -0
  59. package/dist/mcp/tool-patch.mjs +22 -0
  60. package/dist/mcp/validate.d.mts +6 -0
  61. package/dist/mcp/validate.mjs +28 -0
  62. package/dist/session.d.mts +24 -0
  63. package/dist/session.mjs +68 -0
  64. package/package.json +45 -0
@@ -0,0 +1,18 @@
1
+ import { requestJson } from './http.mjs';
2
+ const JSON_HEADERS = { 'content-type': 'application/json' };
3
+ /** Posts a single telemetry entry. `POST /telemetry` echoes back the created entry. */
4
+ export async function appendEntry(config, input) {
5
+ return requestJson(config, '/telemetry', {
6
+ method: 'POST',
7
+ headers: JSON_HEADERS,
8
+ body: JSON.stringify(input),
9
+ });
10
+ }
11
+ /** Posts a batch of telemetry entries. `POST /telemetry` echoes back the created entries. */
12
+ export async function appendEntriesBatch(config, inputs) {
13
+ return requestJson(config, '/telemetry', {
14
+ method: 'POST',
15
+ headers: JSON_HEADERS,
16
+ body: JSON.stringify(inputs),
17
+ });
18
+ }
@@ -0,0 +1,26 @@
1
+ import type { CredentialCreated, CredentialSummary } from './types.mjs';
2
+ export interface AuthOptions {
3
+ baseUrl: string;
4
+ /** Admin token (`atl_admin_<name>_<secret>`) — never a telemetry token. */
5
+ adminToken: string;
6
+ }
7
+ /**
8
+ * Credential (tenant) management — admin-only. Never used by the MCP
9
+ * server; wired up for the CLI's `credentials` subcommands only.
10
+ */
11
+ export declare class Auth {
12
+ #private;
13
+ constructor(options: AuthOptions);
14
+ /** Creates a new telemetry credential. The token is returned once. */
15
+ createCredentials(input: {
16
+ name: string;
17
+ }): Promise<CredentialCreated>;
18
+ /** Lists known credentials (never includes tokens). */
19
+ listCredentials(): Promise<CredentialSummary[]>;
20
+ /** Deletes a credential by id or by name. */
21
+ deleteCredentials(selector: {
22
+ id: string;
23
+ } | {
24
+ name: string;
25
+ }): Promise<void>;
26
+ }
@@ -0,0 +1,23 @@
1
+ import { createCredential, deleteCredential, listCredentials } from './credentials.mjs';
2
+ /**
3
+ * Credential (tenant) management — admin-only. Never used by the MCP
4
+ * server; wired up for the CLI's `credentials` subcommands only.
5
+ */
6
+ export class Auth {
7
+ #config;
8
+ constructor(options) {
9
+ this.#config = { baseUrl: options.baseUrl, token: options.adminToken };
10
+ }
11
+ /** Creates a new telemetry credential. The token is returned once. */
12
+ async createCredentials(input) {
13
+ return createCredential(this.#config, input);
14
+ }
15
+ /** Lists known credentials (never includes tokens). */
16
+ async listCredentials() {
17
+ return listCredentials(this.#config);
18
+ }
19
+ /** Deletes a credential by id or by name. */
20
+ async deleteCredentials(selector) {
21
+ return deleteCredential(this.#config, selector);
22
+ }
23
+ }
@@ -0,0 +1,13 @@
1
+ import type { ClientConfig, CredentialCreated, CredentialSummary } from './types.mjs';
2
+ /** `POST /credentials` (admin-only) — creates a telemetry credential. The token is shown once. */
3
+ export declare function createCredential(config: ClientConfig, input: {
4
+ name: string;
5
+ }): Promise<CredentialCreated>;
6
+ /** `GET /credentials` (admin-only) — lists credentials; never includes tokens. */
7
+ export declare function listCredentials(config: ClientConfig): Promise<CredentialSummary[]>;
8
+ /** `DELETE /credentials?id=` or `?name=` (admin-only). */
9
+ export declare function deleteCredential(config: ClientConfig, selector: {
10
+ id: string;
11
+ } | {
12
+ name: string;
13
+ }): Promise<void>;
@@ -0,0 +1,19 @@
1
+ import { rawRequest, requestJson } from './http.mjs';
2
+ /** `POST /credentials` (admin-only) — creates a telemetry credential. The token is shown once. */
3
+ export async function createCredential(config, input) {
4
+ return requestJson(config, '/credentials', {
5
+ method: 'POST',
6
+ headers: { 'content-type': 'application/json' },
7
+ body: JSON.stringify(input),
8
+ });
9
+ }
10
+ /** `GET /credentials` (admin-only) — lists credentials; never includes tokens. */
11
+ export async function listCredentials(config) {
12
+ return requestJson(config, '/credentials', { method: 'GET' });
13
+ }
14
+ /** `DELETE /credentials?id=` or `?name=` (admin-only). */
15
+ export async function deleteCredential(config, selector) {
16
+ const query = 'id' in selector ? { id: selector.id } : { name: selector.name };
17
+ const response = await rawRequest(config, '/credentials', { method: 'DELETE', query });
18
+ await response.text();
19
+ }
@@ -0,0 +1,8 @@
1
+ /** Thrown for any non-2xx response from the atel HTTP API. */
2
+ export declare class AtelError extends Error {
3
+ /** HTTP status code of the failed response. */
4
+ readonly status: number;
5
+ /** Parsed error body — JSON if the response was JSON, raw text otherwise. */
6
+ readonly body: unknown;
7
+ constructor(message: string, status: number, body: unknown);
8
+ }
@@ -0,0 +1,13 @@
1
+ /** Thrown for any non-2xx response from the atel HTTP API. */
2
+ export class AtelError extends Error {
3
+ /** HTTP status code of the failed response. */
4
+ status;
5
+ /** Parsed error body — JSON if the response was JSON, raw text otherwise. */
6
+ body;
7
+ constructor(message, status, body) {
8
+ super(message);
9
+ this.name = 'AtelError';
10
+ this.status = status;
11
+ this.body = body;
12
+ }
13
+ }
@@ -0,0 +1,22 @@
1
+ import type { ClientConfig, GetRawQuery, TelemetryWireFormat } from './types.mjs';
2
+ /** Query params as they go on the wire — every value is a string. */
3
+ type WireQuery = Record<string, string>;
4
+ /** Converts a typed `GET /telemetry` query into wire-format string params. */
5
+ export declare function buildTelemetriesQuery(query: GetRawQuery): WireQuery;
6
+ /** The `Accept` header that matches a given wire format. */
7
+ export declare function acceptHeaderFor(format: TelemetryWireFormat): string;
8
+ interface RequestOptions {
9
+ method: string;
10
+ headers?: Record<string, string>;
11
+ body?: string;
12
+ query?: WireQuery;
13
+ }
14
+ /**
15
+ * Issues an authenticated HTTP request and returns the raw `Response`,
16
+ * throwing `AtelError` on any non-2xx status. Callers that need the
17
+ * body streamed (not buffered) should read `response.body` directly.
18
+ */
19
+ export declare function rawRequest(config: ClientConfig, path: string, options: RequestOptions): Promise<Response>;
20
+ /** Issues an authenticated HTTP request and parses the response body as JSON. */
21
+ export declare function requestJson<T>(config: ClientConfig, path: string, options: RequestOptions): Promise<T>;
22
+ export {};
@@ -0,0 +1,66 @@
1
+ import { AtelError } from './errors.mjs';
2
+ /** Converts a typed `GET /telemetry` query into wire-format string params. */
3
+ export function buildTelemetriesQuery(query) {
4
+ const wire = {};
5
+ if (query.sessionId !== undefined)
6
+ wire.sessionId = query.sessionId;
7
+ if (query.agent !== undefined)
8
+ wire.agent = query.agent;
9
+ if (query.archived !== undefined)
10
+ wire.archived = String(query.archived);
11
+ if (query.format !== undefined)
12
+ wire.format = query.format;
13
+ return wire;
14
+ }
15
+ const ACCEPT_HEADERS = {
16
+ json: 'application/json',
17
+ jsonl: 'application/x-ndjson',
18
+ markdown: 'text/markdown',
19
+ };
20
+ /** The `Accept` header that matches a given wire format. */
21
+ export function acceptHeaderFor(format) {
22
+ return ACCEPT_HEADERS[format];
23
+ }
24
+ function buildUrl(baseUrl, path, query) {
25
+ const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
26
+ const url = new URL(path.replace(/^\//, ''), base);
27
+ for (const [key, value] of Object.entries(query)) {
28
+ url.searchParams.set(key, value);
29
+ }
30
+ return url;
31
+ }
32
+ async function parseErrorBody(response) {
33
+ const text = await response.text();
34
+ if (!text)
35
+ return undefined;
36
+ try {
37
+ return JSON.parse(text);
38
+ }
39
+ catch {
40
+ return text;
41
+ }
42
+ }
43
+ /**
44
+ * Issues an authenticated HTTP request and returns the raw `Response`,
45
+ * throwing `AtelError` on any non-2xx status. Callers that need the
46
+ * body streamed (not buffered) should read `response.body` directly.
47
+ */
48
+ export async function rawRequest(config, path, options) {
49
+ const url = buildUrl(config.baseUrl, path, options.query ?? {});
50
+ const headers = new Headers(options.headers);
51
+ headers.set('authorization', `Bearer ${config.token}`);
52
+ const init = { method: options.method, headers };
53
+ if (options.body !== undefined)
54
+ init.body = options.body;
55
+ const response = await fetch(url, init);
56
+ if (!response.ok) {
57
+ const body = await parseErrorBody(response);
58
+ throw new AtelError(`atel request failed: ${options.method} ${path} -> ${response.status}`, response.status, body);
59
+ }
60
+ return response;
61
+ }
62
+ /** Issues an authenticated HTTP request and parses the response body as JSON. */
63
+ export async function requestJson(config, path, options) {
64
+ const response = await rawRequest(config, path, options);
65
+ return (await response.json());
66
+ }
@@ -0,0 +1,24 @@
1
+ import type { GetEntriesQuery, TelemetryEntry } from './types.mjs';
2
+ export interface TelemetryOptions {
3
+ baseUrl: string;
4
+ token: string;
5
+ /** Explicit session id; falls back through `resolveSessionId` if omitted. */
6
+ sessionId?: string;
7
+ /** Agent identifier attached to every entry. Defaults to `'claude-code'`. */
8
+ agent?: string;
9
+ }
10
+ export type TelemetryGetOptions = Omit<GetEntriesQuery, 'sessionId' | 'agent'>;
11
+ /**
12
+ * A telemetry stream bound to one session + agent — the ergonomic entry
13
+ * point for "record what I'm doing, then read it back later."
14
+ */
15
+ export declare class Telemetry {
16
+ #private;
17
+ readonly sessionId: string;
18
+ readonly agent: string;
19
+ constructor(options: TelemetryOptions);
20
+ /** Appends one unstructured entry to this session's telemetry stream. */
21
+ append(data: Record<string, unknown>): Promise<TelemetryEntry>;
22
+ /** Reads this session's telemetry back, streaming entries as they arrive. */
23
+ get(options?: TelemetryGetOptions): AsyncIterable<TelemetryEntry>;
24
+ }
@@ -0,0 +1,35 @@
1
+ import { appendEntry } from './append.mjs';
2
+ import { streamEntries } from './stream.mjs';
3
+ import { resolveSessionId } from '../session.mjs';
4
+ const DEFAULT_AGENT = 'claude-code';
5
+ /**
6
+ * A telemetry stream bound to one session + agent — the ergonomic entry
7
+ * point for "record what I'm doing, then read it back later."
8
+ */
9
+ export class Telemetry {
10
+ sessionId;
11
+ agent;
12
+ #config;
13
+ constructor(options) {
14
+ this.#config = { baseUrl: options.baseUrl, token: options.token };
15
+ this.sessionId = resolveSessionId(options.sessionId);
16
+ this.agent = options.agent ?? DEFAULT_AGENT;
17
+ }
18
+ /** Appends one unstructured entry to this session's telemetry stream. */
19
+ async append(data) {
20
+ return appendEntry(this.#config, {
21
+ sessionId: this.sessionId,
22
+ agent: this.agent,
23
+ data,
24
+ });
25
+ }
26
+ /** Reads this session's telemetry back, streaming entries as they arrive. */
27
+ get(options = {}) {
28
+ const query = { sessionId: this.sessionId, agent: this.agent };
29
+ if (options.archived !== undefined)
30
+ query.archived = options.archived;
31
+ if (options.format !== undefined)
32
+ query.format = options.format;
33
+ return streamEntries(this.#config, query);
34
+ }
35
+ }
@@ -0,0 +1,18 @@
1
+ import type { AppendInput, ClientConfig, GetEntriesQuery, PatchOp, TelemetryEntry } from './types.mjs';
2
+ /**
3
+ * Cross-session telemetry operations — batch append, filtered reads across
4
+ * sessions/agents, and archive/data patches. Use this instead of
5
+ * `Telemetry` when you're not bound to one session (e.g. a distill pass
6
+ * over a credential's whole history).
7
+ */
8
+ export declare class Telemetries {
9
+ #private;
10
+ constructor(options: ClientConfig);
11
+ /** Appends one entry, or a batch — mirrors what `POST /telemetry` accepts. */
12
+ append(input: AppendInput): Promise<TelemetryEntry>;
13
+ append(input: AppendInput[]): Promise<TelemetryEntry[]>;
14
+ /** Reads entries across sessions/agents, streaming as they arrive. */
15
+ get(query?: GetEntriesQuery): AsyncIterable<TelemetryEntry>;
16
+ /** Batch-patches entries by id; `data` is a shallow merge, not a replace. */
17
+ patch(patches: PatchOp[]): Promise<TelemetryEntry[]>;
18
+ }
@@ -0,0 +1,28 @@
1
+ import { appendEntry, appendEntriesBatch } from './append.mjs';
2
+ import { patchEntries } from './patch.mjs';
3
+ import { streamEntries } from './stream.mjs';
4
+ /**
5
+ * Cross-session telemetry operations — batch append, filtered reads across
6
+ * sessions/agents, and archive/data patches. Use this instead of
7
+ * `Telemetry` when you're not bound to one session (e.g. a distill pass
8
+ * over a credential's whole history).
9
+ */
10
+ export class Telemetries {
11
+ #config;
12
+ constructor(options) {
13
+ this.#config = options;
14
+ }
15
+ append(input) {
16
+ return Array.isArray(input)
17
+ ? appendEntriesBatch(this.#config, input)
18
+ : appendEntry(this.#config, input);
19
+ }
20
+ /** Reads entries across sessions/agents, streaming as they arrive. */
21
+ get(query = {}) {
22
+ return streamEntries(this.#config, query);
23
+ }
24
+ /** Batch-patches entries by id; `data` is a shallow merge, not a replace. */
25
+ async patch(patches) {
26
+ return patchEntries(this.#config, patches);
27
+ }
28
+ }
@@ -0,0 +1,6 @@
1
+ import type { ClientConfig, PatchOp, TelemetryEntry } from './types.mjs';
2
+ /**
3
+ * Batch-patches telemetry entries. `data` is a shallow merge into each
4
+ * entry's existing `data` blob, not a replace.
5
+ */
6
+ export declare function patchEntries(config: ClientConfig, patches: PatchOp[]): Promise<TelemetryEntry[]>;
@@ -0,0 +1,12 @@
1
+ import { requestJson } from './http.mjs';
2
+ /**
3
+ * Batch-patches telemetry entries. `data` is a shallow merge into each
4
+ * entry's existing `data` blob, not a replace.
5
+ */
6
+ export async function patchEntries(config, patches) {
7
+ return requestJson(config, '/telemetry', {
8
+ method: 'PATCH',
9
+ headers: { 'content-type': 'application/json' },
10
+ body: JSON.stringify(patches),
11
+ });
12
+ }
@@ -0,0 +1,30 @@
1
+ import type { ClientConfig, GetEntriesQuery, GetRawQuery, TelemetryEntry } from './types.mjs';
2
+ /**
3
+ * Issues `GET /telemetry` and returns the raw `Response`, without reading
4
+ * the body. Used both for parsed-entry reads (below) and for the CLI's raw
5
+ * passthrough of whatever wire format the user asked for.
6
+ */
7
+ export declare function fetchTelemetriesRaw(config: ClientConfig, query: GetRawQuery): Promise<Response>;
8
+ /**
9
+ * Parses a `GET /telemetry` response body as newline-delimited JSON,
10
+ * genuinely incrementally: each line is parsed and yielded as soon as it
11
+ * has fully arrived, via the underlying `ReadableStream` reader — not after
12
+ * buffering the whole response.
13
+ */
14
+ export declare function parseNdjsonStream(response: Response): AsyncGenerator<TelemetryEntry>;
15
+ /**
16
+ * Parses a `GET /telemetry` response body as a single JSON array. This
17
+ * cannot be genuinely incremental — a JSON array isn't a valid JSON
18
+ * document until its closing `]` arrives, so this buffers the full body
19
+ * before yielding anything. Prefer `format: 'jsonl'` (the default) for real
20
+ * incremental delivery; this path exists for parity with the server's
21
+ * default wire format.
22
+ */
23
+ export declare function parseJsonArrayBuffered(response: Response): AsyncGenerator<TelemetryEntry>;
24
+ /**
25
+ * Reads `GET /telemetry` as parsed, structured entries. Always requests
26
+ * `jsonl` on the wire by default (true incremental parsing); pass
27
+ * `format: 'json'` to match the server's default array format instead, at
28
+ * the cost of buffering the full response (see `parseJsonArrayBuffered`).
29
+ */
30
+ export declare function streamEntries(config: ClientConfig, query?: GetEntriesQuery): AsyncGenerator<TelemetryEntry>;
@@ -0,0 +1,90 @@
1
+ import { acceptHeaderFor, buildTelemetriesQuery, rawRequest } from './http.mjs';
2
+ /**
3
+ * Issues `GET /telemetry` and returns the raw `Response`, without reading
4
+ * the body. Used both for parsed-entry reads (below) and for the CLI's raw
5
+ * passthrough of whatever wire format the user asked for.
6
+ */
7
+ export async function fetchTelemetriesRaw(config, query) {
8
+ const format = query.format ?? 'json';
9
+ return rawRequest(config, '/telemetry', {
10
+ method: 'GET',
11
+ headers: { accept: acceptHeaderFor(format) },
12
+ query: buildTelemetriesQuery(query),
13
+ });
14
+ }
15
+ /**
16
+ * Parses a `GET /telemetry` response body as newline-delimited JSON,
17
+ * genuinely incrementally: each line is parsed and yielded as soon as it
18
+ * has fully arrived, via the underlying `ReadableStream` reader — not after
19
+ * buffering the whole response.
20
+ */
21
+ export async function* parseNdjsonStream(response) {
22
+ if (!response.body)
23
+ return;
24
+ const reader = response.body.getReader();
25
+ const decoder = new TextDecoder();
26
+ let buffer = '';
27
+ try {
28
+ for (;;) {
29
+ const { done, value } = await reader.read();
30
+ if (value) {
31
+ buffer += decoder.decode(value, { stream: true });
32
+ let newlineIndex = buffer.indexOf('\n');
33
+ while (newlineIndex !== -1) {
34
+ const line = buffer.slice(0, newlineIndex).trim();
35
+ buffer = buffer.slice(newlineIndex + 1);
36
+ if (line.length > 0)
37
+ yield JSON.parse(line);
38
+ newlineIndex = buffer.indexOf('\n');
39
+ }
40
+ }
41
+ if (done)
42
+ break;
43
+ }
44
+ const trailing = buffer.trim();
45
+ if (trailing.length > 0)
46
+ yield JSON.parse(trailing);
47
+ }
48
+ finally {
49
+ reader.releaseLock();
50
+ }
51
+ }
52
+ /**
53
+ * Parses a `GET /telemetry` response body as a single JSON array. This
54
+ * cannot be genuinely incremental — a JSON array isn't a valid JSON
55
+ * document until its closing `]` arrives, so this buffers the full body
56
+ * before yielding anything. Prefer `format: 'jsonl'` (the default) for real
57
+ * incremental delivery; this path exists for parity with the server's
58
+ * default wire format.
59
+ */
60
+ export async function* parseJsonArrayBuffered(response) {
61
+ const text = (await response.text()).trim();
62
+ if (text.length === 0)
63
+ return;
64
+ const entries = JSON.parse(text);
65
+ for (const entry of entries)
66
+ yield entry;
67
+ }
68
+ /**
69
+ * Reads `GET /telemetry` as parsed, structured entries. Always requests
70
+ * `jsonl` on the wire by default (true incremental parsing); pass
71
+ * `format: 'json'` to match the server's default array format instead, at
72
+ * the cost of buffering the full response (see `parseJsonArrayBuffered`).
73
+ */
74
+ export async function* streamEntries(config, query = {}) {
75
+ const format = query.format ?? 'jsonl';
76
+ const wireQuery = { format };
77
+ if (query.sessionId !== undefined)
78
+ wireQuery.sessionId = query.sessionId;
79
+ if (query.agent !== undefined)
80
+ wireQuery.agent = query.agent;
81
+ if (query.archived !== undefined)
82
+ wireQuery.archived = query.archived;
83
+ const response = await fetchTelemetriesRaw(config, wireQuery);
84
+ if (format === 'jsonl') {
85
+ yield* parseNdjsonStream(response);
86
+ }
87
+ else {
88
+ yield* parseJsonArrayBuffered(response);
89
+ }
90
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Shared wire types for the atel HTTP client.
3
+ *
4
+ * These mirror the server's documented contract (see the plan doc / server
5
+ * `packages/server/src/core/handle-request.mts`) but are intentionally
6
+ * decoupled from it — this package must never import from `packages/server`.
7
+ */
8
+ /** Config needed to reach the server: a base URL and a bearer token. */
9
+ export interface ClientConfig {
10
+ baseUrl: string;
11
+ token: string;
12
+ }
13
+ /** A single telemetry entry as returned by the server. */
14
+ export interface TelemetryEntry {
15
+ id: string;
16
+ sessionId: string;
17
+ agent: string;
18
+ createdAt: string;
19
+ archived: boolean;
20
+ data: Record<string, unknown>;
21
+ }
22
+ /** Body accepted by `POST /telemetry` for a single entry. */
23
+ export interface AppendInput {
24
+ sessionId: string;
25
+ agent: string;
26
+ data: Record<string, unknown>;
27
+ }
28
+ /**
29
+ * Wire format for `GET /telemetry`. `'markdown'` is only meaningful for raw
30
+ * (unparsed) reads — see `client/stream.mts` for why entry-returning reads
31
+ * are restricted to `'json' | 'jsonl'`.
32
+ */
33
+ export type TelemetryWireFormat = 'json' | 'jsonl' | 'markdown';
34
+ /** Format restricted to values that parse into structured entries. */
35
+ export type TelemetryEntryFormat = Extract<TelemetryWireFormat, 'json' | 'jsonl'>;
36
+ /** Query params accepted by `GET /telemetry` when reading parsed entries. */
37
+ export interface GetEntriesQuery {
38
+ sessionId?: string;
39
+ agent?: string;
40
+ archived?: boolean;
41
+ format?: TelemetryEntryFormat;
42
+ }
43
+ /** Query params accepted by `GET /telemetry` for a raw (unparsed) read. */
44
+ export interface GetRawQuery {
45
+ sessionId?: string;
46
+ agent?: string;
47
+ archived?: boolean;
48
+ format?: TelemetryWireFormat;
49
+ }
50
+ /** One patch operation accepted by `PATCH /telemetry`. `data` is a shallow merge. */
51
+ export interface PatchOp {
52
+ id: string;
53
+ archived?: boolean;
54
+ data?: Record<string, unknown>;
55
+ }
56
+ /** A telemetry or admin credential, as listed by `GET /credentials`. */
57
+ export interface CredentialSummary {
58
+ id: string;
59
+ name: string;
60
+ createdAt: string;
61
+ }
62
+ /** The one-time response from `POST /credentials`, including the secret token. */
63
+ export interface CredentialCreated extends CredentialSummary {
64
+ token: string;
65
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Shared wire types for the atel HTTP client.
3
+ *
4
+ * These mirror the server's documented contract (see the plan doc / server
5
+ * `packages/server/src/core/handle-request.mts`) but are intentionally
6
+ * decoupled from it — this package must never import from `packages/server`.
7
+ */
8
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Formats any thrown value as a single-line, human-readable message — never
3
+ * a raw stack trace. Shared by the CLI (stderr) and the MCP server (tool
4
+ * error content), since a caller can throw anything in JS, not just `Error`.
5
+ */
6
+ export declare function formatError(err: unknown): string;
@@ -0,0 +1,15 @@
1
+ import { AtelError } from './client/errors.mjs';
2
+ /**
3
+ * Formats any thrown value as a single-line, human-readable message — never
4
+ * a raw stack trace. Shared by the CLI (stderr) and the MCP server (tool
5
+ * error content), since a caller can throw anything in JS, not just `Error`.
6
+ */
7
+ export function formatError(err) {
8
+ if (err instanceof AtelError) {
9
+ const bodyText = err.body === undefined ? '' : ` ${JSON.stringify(err.body)}`;
10
+ return `${err.message}${bodyText}`;
11
+ }
12
+ if (err instanceof Error)
13
+ return err.message;
14
+ return String(err);
15
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Public API of `@jongleberry/atel`: a thin `fetch`-based client for the
3
+ * atel HTTP service.
4
+ *
5
+ * - `Telemetry` — append + read, bound to one session + agent.
6
+ * - `Telemetries` — batch append/read/patch across sessions.
7
+ * - `Auth` — admin-only credential management.
8
+ *
9
+ * This module must never import `@aws-sdk/*` or anything from
10
+ * `packages/server` (enforced by `.dependency-cruiser.cjs`).
11
+ */
12
+ export { Auth } from './client/auth.mjs';
13
+ export type { AuthOptions } from './client/auth.mjs';
14
+ export { AtelError } from './client/errors.mjs';
15
+ export { Telemetry } from './client/journal.mjs';
16
+ export type { TelemetryGetOptions, TelemetryOptions } from './client/journal.mjs';
17
+ export { Telemetries } from './client/journals.mjs';
18
+ export type { AppendInput, ClientConfig, CredentialCreated, CredentialSummary, GetEntriesQuery, GetRawQuery, PatchOp, TelemetryEntry, TelemetryEntryFormat, TelemetryWireFormat, } from './client/types.mjs';
19
+ export { resolveSessionId } from './session.mjs';
20
+ export type { ResolveSessionIdOptions } from './session.mjs';
package/dist/index.mjs ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Public API of `@jongleberry/atel`: a thin `fetch`-based client for the
3
+ * atel HTTP service.
4
+ *
5
+ * - `Telemetry` — append + read, bound to one session + agent.
6
+ * - `Telemetries` — batch append/read/patch across sessions.
7
+ * - `Auth` — admin-only credential management.
8
+ *
9
+ * This module must never import `@aws-sdk/*` or anything from
10
+ * `packages/server` (enforced by `.dependency-cruiser.cjs`).
11
+ */
12
+ export { Auth } from './client/auth.mjs';
13
+ export { AtelError } from './client/errors.mjs';
14
+ export { Telemetry } from './client/journal.mjs';
15
+ export { Telemetries } from './client/journals.mjs';
16
+ export { resolveSessionId } from './session.mjs';
@@ -0,0 +1,3 @@
1
+ import type { ClientConfig } from '../client/types.mjs';
2
+ /** Routes a `tools/call` request to the matching handler by tool name. */
3
+ export declare function dispatchTool(name: string, args: Record<string, unknown>, config: ClientConfig): Promise<unknown>;
@@ -0,0 +1,16 @@
1
+ import { handleTelemetryAppend } from './tool-append.mjs';
2
+ import { handleTelemetryGet } from './tool-get.mjs';
3
+ import { handleTelemetryPatch } from './tool-patch.mjs';
4
+ /** Routes a `tools/call` request to the matching handler by tool name. */
5
+ export async function dispatchTool(name, args, config) {
6
+ switch (name) {
7
+ case 'telemetry_append':
8
+ return handleTelemetryAppend(args, config);
9
+ case 'telemetry_get':
10
+ return handleTelemetryGet(args, config);
11
+ case 'telemetry_patch':
12
+ return handleTelemetryPatch(args, config);
13
+ default:
14
+ throw new Error(`Unknown tool: ${name}`);
15
+ }
16
+ }
@@ -0,0 +1,2 @@
1
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ export declare const TELEMETRY_TOOLS: Tool[];